diff --git a/README.md b/README.md index 15ea0a3..d29ba58 100644 --- a/README.md +++ b/README.md @@ -71,12 +71,10 @@ nix multi user, multi system, configuration with `sops` secret management, `home - [ ] monitor configuration in `~/.config/monitors.xml` should be sym linked to `/run/gdm/.config/monitors.xml` (https://www.reddit.com/r/NixOS/comments/u09cz9/home_manager_create_my_own_symlinks_automatically/) - [ ] migrate away from flakes and move to npins - [ ] `host.users` should be redone so that we just extend the base `users.users` object. Right now we cant quite do this because we have weird circular dependencies with disko/impermanence (not sure which one) and home manger enabling/disabling users per devices -- [ ] Home manager impermanence is preventing updates to the latest version of the module ## Broken things - [ ] figure out steam vr things? - [ ] whisper was having issues -- [ ] auto loading of ssh agent keys that we auto generate per system ## Data Integrity - [ ] zfs email after scrubbing # TODO: test this @@ -104,9 +102,7 @@ nix multi user, multi system, configuration with `sops` secret management, `home - [ ] Penpot services (need to make this custom) - [ ] minecraft server with old world file - [ ] storj server -- [ ] XMR miner used to heat home based on smart thermostat - [ ] Create Tor guard/relay server -- [ ] Create i2P node - [ ] screeps server - [ ] mastodon instance diff --git a/configurations/home-manager/default.nix b/configurations/home-manager/default.nix index a7fa478..3f88481 100644 --- a/configurations/home-manager/default.nix +++ b/configurations/home-manager/default.nix @@ -8,5 +8,6 @@ in { leyla = lib.mkIf users.leyla.isNormalUser (import ./leyla); eve = lib.mkIf users.eve.isNormalUser (import ./eve); + ivy = lib.mkIf users.ivy.isNormalUser (import ./ivy); git = lib.mkIf (osConfig.services.forgejo.enable or false) (import ./git); } diff --git a/configurations/home-manager/eve/packages.nix b/configurations/home-manager/eve/packages.nix index c87f786..6b3c2e2 100644 --- a/configurations/home-manager/eve/packages.nix +++ b/configurations/home-manager/eve/packages.nix @@ -60,7 +60,7 @@ in { bitwarden.enable = true; discord.enable = true; makemkv.enable = true; - signal-desktop.enable = true; + signal-desktop-bin.enable = true; steam.enable = true; piper.enable = hardware.piperMouse.enable; krita.enable = true; @@ -75,9 +75,7 @@ in { libreoffice.enable = true; noita-entangled-worlds.enable = true; - opencode.enable = osConfig.host.ai.enable; - - e621-downloader.enable = true; + claude-code.enable = osConfig.host.ai.enable; # Windows applications that we need to figure out how to install guild-wars-2.enable = false; diff --git a/configurations/home-manager/ivy/default.nix b/configurations/home-manager/ivy/default.nix new file mode 100644 index 0000000..48a3cae --- /dev/null +++ b/configurations/home-manager/ivy/default.nix @@ -0,0 +1,55 @@ +{osConfig, ...}: let + userConfig = osConfig.host.users.ivy; +in { + imports = [ + ./packages.nix + ]; + + home = { + username = userConfig.name; + homeDirectory = osConfig.users.users.ivy.home; + + # This value determines the Home Manager release that your configuration is + # compatible with. This helps avoid breakage when a new Home Manager release + # introduces backwards incompatible changes. + # + # You should not change this value, even if you update Home Manager. If you do + # want to update the value, then make sure to first check the Home Manager + # release notes. + stateVersion = "23.11"; # Please read the comment before changing. + + # Home Manager is pretty good at managing dotfiles. The primary way to manage + # plain files is through 'home.file'. + file = { + # # Building this configuration will create a copy of 'dotfiles/screenrc' in + # # the Nix store. Activating the configuration will then make '~/.screenrc' a + # # symlink to the Nix store copy. + # ".screenrc".source = dotfiles/screenrc; + + # # You can also set the file content immediately. + # ".gradle/gradle.properties".text = '' + # org.gradle.console=verbose + # org.gradle.daemon.idletimeout=3600000 + # ''; + }; + + # Home Manager can also manage your environment variables through + # 'home.sessionVariables'. If you don't want to manage your shell through Home + # Manager then you have to manually source 'hm-session-vars.sh' located at + # either + # + # ~/.nix-profile/etc/profile.d/hm-session-vars.sh + # + # or + # + # ~/.local/state/nix/profiles/profile/etc/profile.d/hm-session-vars.sh + # + # or + # + # /etc/profiles/per-user/ivy/etc/profile.d/hm-session-vars.sh + # + sessionVariables = { + # EDITOR = "emacs"; + }; + }; +} diff --git a/configurations/home-manager/ivy/packages.nix b/configurations/home-manager/ivy/packages.nix new file mode 100644 index 0000000..3c2a3d9 --- /dev/null +++ b/configurations/home-manager/ivy/packages.nix @@ -0,0 +1,73 @@ +{ + lib, + pkgs, + config, + osConfig, + ... +}: { + config = { + nixpkgs.config = { + allowUnfree = true; + }; + + # Programs that need to be installed with some extra configuration + programs = lib.mkMerge [ + { + # Let Home Manager install and manage itself. + home-manager.enable = true; + } + (lib.mkIf (config.user.isDesktopUser || config.user.isTerminalUser) { + # git = { + # enable = true; + # userName = "Ivy"; + # userEmail = "ivy@example.com"; # Update this with actual email + # extraConfig.init.defaultBranch = "main"; + # }; + + openssh = { + enable = true; + hostKeys = [ + { + type = "ed25519"; + path = "${config.home.username}_${osConfig.networking.hostName}_ed25519"; + } + ]; + }; + }) + (lib.mkIf config.user.isDesktopUser { + vscode = { + enable = true; + package = pkgs.vscodium; + mutableExtensionsDir = false; + + profiles.default = { + enableUpdateCheck = false; + enableExtensionUpdateCheck = false; + + extraExtensions = { + # Cline extension (Claude AI assistant) + claudeDev.enable = true; + # Auto Rename Tag + autoRenameTag.enable = true; + # Live Server + liveServer.enable = true; + }; + + extensions = let + extension-pkgs = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version; + in ( + with extension-pkgs.open-vsx; [ + streetsidesoftware.code-spell-checker + ] + ); + }; + }; + + firefox.enable = true; + discord.enable = true; + signal-desktop-bin.enable = true; + claude-code.enable = true; + }) + ]; + }; +} diff --git a/configurations/home-manager/leyla/default.nix b/configurations/home-manager/leyla/default.nix index 20b04c7..8a37754 100644 --- a/configurations/home-manager/leyla/default.nix +++ b/configurations/home-manager/leyla/default.nix @@ -12,7 +12,7 @@ ]; config = { - impermanence.enable = osConfig.storage.impermanence.enable; + impermanence.enable = osConfig.host.impermanence.enable; # Home Manager needs a bit of information about you and the paths it should # manage. diff --git a/configurations/home-manager/leyla/impermanence.nix b/configurations/home-manager/leyla/impermanence.nix index 8fbff41..ce81c81 100644 --- a/configurations/home-manager/leyla/impermanence.nix +++ b/configurations/home-manager/leyla/impermanence.nix @@ -4,7 +4,7 @@ ... }: { config = lib.mkIf (config.impermanence.enable) { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist/home/leyla" = { directories = [ "desktop" "downloads" @@ -14,6 +14,7 @@ ".bash_history" # keep shell history around "${config.xdg.dataHome}/recently-used.xbel" # gnome recently viewed files ]; + allowOther = true; }; }; } diff --git a/configurations/home-manager/leyla/packages/default.nix b/configurations/home-manager/leyla/packages/default.nix index 5f64742..bc41350 100644 --- a/configurations/home-manager/leyla/packages/default.nix +++ b/configurations/home-manager/leyla/packages/default.nix @@ -41,19 +41,17 @@ in { openrgb.enable = hardware.openRGB.enable; via.enable = hardware.viaKeyboard.enable; claude-code.enable = osConfig.host.ai.enable; - opencode.enable = osConfig.host.ai.enable; davinci-resolve.enable = hardware.graphicsAcceleration.enable; mfoc.enable = true; }) (lib.mkIf (hardware.directAccess.enable && config.user.isDesktopUser) { anki.enable = true; - android-studio.enable = true; makemkv.enable = true; discord.enable = true; - signal-desktop.enable = true; + signal-desktop-bin.enable = true; calibre.enable = true; obsidian.enable = true; - jetbrains.idea-oss.enable = true; + jetbrains.idea-community.enable = true; vscode.enable = true; firefox.enable = true; steam.enable = true; @@ -73,10 +71,6 @@ in { noita-entangled-worlds.enable = true; tor-browser.enable = true; gdx-liftoff.enable = true; - proton-mail-pwa.enable = true; - proton-calendar-pwa.enable = true; - matrix-cyberia-pwa.enable = true; - kicad.enable = true; }) ]; } diff --git a/configurations/home-manager/leyla/packages/firefox/bookmarks.nix b/configurations/home-manager/leyla/packages/firefox/bookmarks.nix index bd172e7..4210d1e 100644 --- a/configurations/home-manager/leyla/packages/firefox/bookmarks.nix +++ b/configurations/home-manager/leyla/packages/firefox/bookmarks.nix @@ -141,12 +141,6 @@ keyword = ""; tags = [""]; } - { - name = "Cyberia Git"; - url = "https://git.cyberia.club"; - keyword = ""; - tags = [""]; - } # Template # { # name = ""; diff --git a/configurations/home-manager/leyla/packages/vscode/default.nix b/configurations/home-manager/leyla/packages/vscode/default.nix index e0b2d98..36168b2 100644 --- a/configurations/home-manager/leyla/packages/vscode/default.nix +++ b/configurations/home-manager/leyla/packages/vscode/default.nix @@ -58,9 +58,6 @@ in { nearley.enable = true; - # graphql - graphql.enable = true; - # astro development vscodeMdx.enable = true; astroVscode.enable = true; @@ -75,12 +72,9 @@ in { # rust development rustAnalyzer.enable = true; - # arduino development - platformIO.enable = false; - # claude development claudeDev = lib.mkIf ai-tooling-enabled { - enable = false; + enable = true; mcp = { nixos = { enable = true; diff --git a/configurations/home-manager/leyla/packages/vscode/user-words.nix b/configurations/home-manager/leyla/packages/vscode/user-words.nix index 112269e..bb99bbc 100644 --- a/configurations/home-manager/leyla/packages/vscode/user-words.nix +++ b/configurations/home-manager/leyla/packages/vscode/user-words.nix @@ -6,7 +6,6 @@ config.programs.vscode.profiles.default.userSettings = { "cSpell.userWords" = [ "leyla" - "Cyberia" ]; "cSpell.languageSettings" = [ diff --git a/configurations/nixos/defiant/configuration.nix b/configurations/nixos/defiant/configuration.nix index 40adbd5..e2f9401 100644 --- a/configurations/nixos/defiant/configuration.nix +++ b/configurations/nixos/defiant/configuration.nix @@ -33,6 +33,44 @@ isPrincipleUser = true; }; }; + impermanence.enable = true; + storage = { + enable = true; + encryption = true; + notifications = { + enable = true; + host = "smtp.protonmail.ch"; + port = 587; + to = "leyla@jan-leila.com"; + user = "noreply@jan-leila.com"; + tokenFile = config.sops.secrets."services/zfs_smtp_token".path; + }; + pool = { + # We are having to boot off of the nvm cache drive because I cant figure out how to boot via the HBA + bootDrives = ["nvme-Samsung_SSD_990_PRO_4TB_S7KGNU0X907881F"]; + vdevs = [ + [ + "ata-ST18000NE000-3G6101_ZVTCXVEB" + "ata-ST18000NE000-3G6101_ZVTCXWSC" + "ata-ST18000NE000-3G6101_ZVTD10EH" + "ata-ST18000NT001-3NF101_ZVTE0S3Q" + "ata-ST18000NT001-3NF101_ZVTEF27J" + "ata-ST18000NE000-3G6101_ZVTJ7359" + ] + [ + "ata-ST4000NE001-2MA101_WS2275P3" + "ata-ST4000NE001-2MA101_WS227B9F" + "ata-ST4000NE001-2MA101_WS227CEW" + "ata-ST4000NE001-2MA101_WS227CYN" + "ata-ST4000NE001-2MA101_WS23TBWV" + "ata-ST4000NE001-2MA101_WS23TC5F" + ] + ]; + cache = [ + "nvme-Samsung_SSD_990_PRO_4TB_S7KGNU0X907881F" + ]; + }; + }; network_storage = { enable = true; directories = [ @@ -66,53 +104,6 @@ }; }; - storage = { - zfs = { - enable = true; - notifications = { - enable = true; - host = "smtp.protonmail.ch"; - port = 587; - to = "leyla@jan-leila.com"; - user = "noreply@jan-leila.com"; - tokenFile = config.sops.secrets."services/zfs_smtp_token".path; - }; - pool = { - encryption = { - enable = true; - }; - vdevs = [ - [ - "ata-ST18000NE000-3G6101_ZVTCXVEB" - "ata-ST18000NE000-3G6101_ZVTCXWSC" - "ata-ST18000NE000-3G6101_ZVTD10EH" - "ata-ST18000NT001-3NF101_ZVTE0S3Q" - "ata-ST18000NT001-3NF101_ZVTEF27J" - "ata-ST18000NE000-3G6101_ZVTJ7359" - ] - [ - "ata-ST4000NE001-2MA101_WS2275P3" - "ata-ST4000NE001-2MA101_WS227B9F" - "ata-ST4000NE001-2MA101_WS227CEW" - "ata-ST4000NE001-2MA101_WS227CYN" - "ata-ST4000NE001-2MA101_WS23TBWV" - "ata-ST4000NE001-2MA101_WS23TC5F" - ] - ]; - # We are having to boot off of the nvm cache drive because I cant figure out how to boot via the HBA - cache = [ - { - device = "nvme-Samsung_SSD_990_PRO_4TB_S7KGNU0X907881F"; - boot = true; - } - ]; - }; - }; - impermanence = { - enable = true; - }; - }; - systemd.network = { enable = true; @@ -143,7 +134,6 @@ Endpoint = "185.230.126.146:51820"; # Allow all traffic but use policy routing to prevent system-wide VPN AllowedIPs = ["0.0.0.0/0"]; - PersistentKeepalive = 25; } ]; }; @@ -227,7 +217,6 @@ postgresql = { enable = true; adminUsers = ["leyla"]; - impermanence.enable = false; }; # temp enable desktop environment for setup @@ -246,7 +235,6 @@ reverseProxy = { enable = true; openFirewall = true; - impermanence.enable = false; acme = { enable = true; email = "jan-leila@protonmail.com"; @@ -256,7 +244,8 @@ ollama = { enable = true; exposePort = true; - impermanence.enable = false; + + acceleration = false; environmentVariables = { OLLAMA_KEEP_ALIVE = "24h"; @@ -291,7 +280,6 @@ enable = true; authKeyFile = config.sops.secrets."vpn-keys/tailscale-authkey/defiant".path; useRoutingFeatures = "server"; - impermanence.enable = false; extraUpFlags = [ "--advertise-exit-node" "--advertise-routes=192.168.0.0/24" @@ -304,33 +292,24 @@ ]; }; - syncthing = { - enable = true; - impermanence.enable = false; - }; + syncthing.enable = true; - fail2ban = { - enable = true; - impermanence.enable = false; - }; + fail2ban.enable = true; jellyfin = { enable = true; domain = "media.jan-leila.com"; extraDomains = ["jellyfin.jan-leila.com"]; - impermanence.enable = false; }; immich = { enable = true; domain = "photos.jan-leila.com"; - impermanence.enable = false; }; forgejo = { enable = true; reverseProxy.domain = "git.jan-leila.com"; - impermanence.enable = false; }; searx = { @@ -339,9 +318,8 @@ }; actual = { - enable = false; + enable = true; domain = "budget.jan-leila.com"; - impermanence.enable = false; }; home-assistant = { @@ -349,7 +327,6 @@ domain = "home.jan-leila.com"; openFirewall = true; postgres.enable = true; - impermanence.enable = false; extensions = { sonos.enable = true; @@ -362,13 +339,11 @@ enable = true; domain = "documents.jan-leila.com"; passwordFile = config.sops.secrets."services/paperless_password".path; - impermanence.enable = false; }; panoramax = { enable = false; openFirewall = true; - impermanence.enable = false; }; crab-hole = { @@ -376,7 +351,6 @@ port = 8085; openFirewall = true; show_doc = true; - impermanence.enable = false; downstreams = { host = { enable = true; @@ -392,38 +366,31 @@ mediaDir = "/srv/qbittorent"; openFirewall = true; webuiPort = 8084; - impermanence.enable = false; }; sonarr = { enable = true; openFirewall = true; - impermanence.enable = false; }; radarr = { enable = true; openFirewall = true; - impermanence.enable = false; }; bazarr = { enable = true; openFirewall = true; - impermanence.enable = false; }; lidarr = { enable = true; openFirewall = true; - impermanence.enable = false; }; jackett = { enable = true; openFirewall = true; - impermanence.enable = false; }; flaresolverr = { enable = true; openFirewall = true; - impermanence.enable = false; }; }; diff --git a/configurations/nixos/defiant/default.nix b/configurations/nixos/defiant/default.nix index dd2383f..3013946 100644 --- a/configurations/nixos/defiant/default.nix +++ b/configurations/nixos/defiant/default.nix @@ -4,7 +4,5 @@ ./hardware-configuration.nix ./configuration.nix ./packages.nix - ./legacy-storage.nix - ./legacy-impermanence.nix ]; } diff --git a/configurations/nixos/defiant/legacy-impermanence.nix b/configurations/nixos/defiant/legacy-impermanence.nix deleted file mode 100644 index 4cfe18b..0000000 --- a/configurations/nixos/defiant/legacy-impermanence.nix +++ /dev/null @@ -1,296 +0,0 @@ -# Legacy impermanence module for defiant -# See legacy-storage.nix for the full incremental migration plan. -# -# This file is consumed in two phases: -# -# Phase 3 (after generateBase is enabled): -# Remove the SYSTEM-LEVEL entries marked [PHASE 3] below. These will be -# handled automatically by storage.nix, ssh.nix, and the impermanence module: -# - var-lib-private-permissions activation script -# - /etc/machine-id -# - SSH host keys -# - /var/lib/nixos -# - /var/lib/systemd/coredump -# - /persist/system/var/log persistence block -# -# Phase 4 (migrate services one at a time, any order): -# For each service: -# 1. Remove the service's section marked [PHASE 4] from this file -# 2. Remove `impermanence.enable = false` for that service in configuration.nix -# For jellyfin/qbittorrent, also remove the separate media persistence blocks. -# -# Phase 5: Delete this file once empty. -{ - config, - lib, - ... -}: { - config = lib.mkIf config.storage.impermanence.enable { - # [PHASE 3] Remove this activation script after enabling generateBase - system.activationScripts = { - "var-lib-private-permissions" = { - deps = ["specialfs"]; - text = '' - mkdir -p /persist/system/root/var/lib/private - chmod 0700 /persist/system/root/var/lib/private - ''; - }; - }; - - environment.persistence."/persist/system/root" = { - enable = true; - hideMounts = true; - # [PHASE 3] Remove this files block after enabling generateBase - files = lib.mkMerge [ - ["/etc/machine-id"] - # SSH host keys - (lib.mkIf config.services.openssh.enable ( - lib.lists.flatten ( - builtins.map (hostKey: [ - hostKey.path - "${hostKey.path}.pub" - ]) - config.services.openssh.hostKeys - ) - )) - ]; - directories = lib.mkMerge [ - # [PHASE 3] Remove these system directories after enabling generateBase - [ - "/var/lib/nixos" - "/var/lib/systemd/coredump" - ] - - # [PHASE 4] PostgreSQL - (lib.mkIf config.services.postgresql.enable [ - { - directory = "/var/lib/postgresql/16"; - user = "postgres"; - group = "postgres"; - } - ]) - - # [PHASE 4] Reverse Proxy (ACME) - (lib.mkIf config.services.reverseProxy.enable [ - { - directory = "/var/lib/acme"; - user = "acme"; - group = "acme"; - } - ]) - - # [PHASE 4] Ollama - (lib.mkIf config.services.ollama.enable [ - { - directory = "/var/lib/private/ollama"; - user = config.services.ollama.user; - group = config.services.ollama.group; - mode = "0700"; - } - ]) - - # [PHASE 4] Tailscale - (lib.mkIf config.services.tailscale.enable [ - { - directory = "/var/lib/tailscale"; - user = "root"; - group = "root"; - } - ]) - - # [PHASE 4] Syncthing - (lib.mkIf config.services.syncthing.enable [ - { - directory = "/mnt/sync"; - user = "syncthing"; - group = "syncthing"; - } - { - directory = "/etc/syncthing"; - user = "syncthing"; - group = "syncthing"; - } - ]) - - # [PHASE 4] Fail2ban - (lib.mkIf config.services.fail2ban.enable [ - { - directory = "/var/lib/fail2ban"; - user = "fail2ban"; - group = "fail2ban"; - } - ]) - - # [PHASE 4] Jellyfin (data/cache only - media is on separate dataset) - (lib.mkIf config.services.jellyfin.enable [ - { - directory = "/var/lib/jellyfin"; - user = "jellyfin"; - group = "jellyfin"; - } - { - directory = "/var/cache/jellyfin"; - user = "jellyfin"; - group = "jellyfin"; - } - ]) - - # [PHASE 4] Immich - (lib.mkIf config.services.immich.enable [ - { - directory = "/var/lib/immich"; - user = "immich"; - group = "immich"; - } - ]) - - # [PHASE 4] Forgejo - (lib.mkIf config.services.forgejo.enable [ - { - directory = "/var/lib/forgejo"; - user = "forgejo"; - group = "forgejo"; - } - ]) - - # [PHASE 4] Actual - (lib.mkIf config.services.actual.enable [ - { - directory = "/var/lib/private/actual"; - user = "actual"; - group = "actual"; - } - ]) - - # [PHASE 4] Home Assistant - (lib.mkIf config.services.home-assistant.enable [ - { - directory = "/var/lib/hass"; - user = "hass"; - group = "hass"; - } - ]) - - # [PHASE 4] Paperless - (lib.mkIf config.services.paperless.enable [ - { - directory = "/var/lib/paperless"; - user = "paperless"; - group = "paperless"; - } - ]) - - # [PHASE 4] Crab-hole - (lib.mkIf config.services.crab-hole.enable [ - { - directory = "/var/lib/private/crab-hole"; - user = "crab-hole"; - group = "crab-hole"; - } - ]) - - # [PHASE 4] qBittorrent (config only - media is on separate dataset) - (lib.mkIf config.services.qbittorrent.enable [ - { - directory = "/var/lib/qBittorrent/"; - user = "qbittorrent"; - group = "qbittorrent"; - } - ]) - - # [PHASE 4] Sonarr - (lib.mkIf config.services.sonarr.enable [ - { - directory = "/var/lib/sonarr/.config/NzbDrone"; - user = "sonarr"; - group = "sonarr"; - } - ]) - - # [PHASE 4] Radarr - (lib.mkIf config.services.radarr.enable [ - { - directory = "/var/lib/radarr/.config/Radarr"; - user = "radarr"; - group = "radarr"; - } - ]) - - # [PHASE 4] Bazarr - (lib.mkIf config.services.bazarr.enable [ - { - directory = "/var/lib/bazarr"; - user = "bazarr"; - group = "bazarr"; - } - ]) - - # [PHASE 4] Lidarr - (lib.mkIf config.services.lidarr.enable [ - { - directory = "/var/lib/lidarr/.config/Lidarr"; - user = "lidarr"; - group = "lidarr"; - } - ]) - - # [PHASE 4] Jackett - (lib.mkIf config.services.jackett.enable [ - { - directory = "/var/lib/jackett/.config/Jackett"; - user = "jackett"; - group = "jackett"; - } - ]) - - # [PHASE 4] FlareSolverr - (lib.mkIf config.services.flaresolverr.enable [ - { - directory = "/var/lib/flaresolverr"; - user = "flaresolverr"; - group = "flaresolverr"; - } - ]) - ]; - }; - - # [PHASE 4 - LAST] Jellyfin media on separate dataset - # Requires Phase 2 media dataset merge before migrating (several days of data copy) - environment.persistence."/persist/system/jellyfin" = lib.mkIf config.services.jellyfin.enable { - enable = true; - hideMounts = true; - directories = [ - { - directory = config.services.jellyfin.media_directory; - user = "jellyfin"; - group = "jellyfin_media"; - mode = "1770"; - } - ]; - }; - - # [PHASE 4 - LAST] qBittorrent media on separate dataset - # Requires Phase 2 media dataset merge before migrating (several days of data copy) - environment.persistence."/persist/system/qbittorrent" = lib.mkIf config.services.qbittorrent.enable { - enable = true; - hideMounts = true; - directories = [ - { - directory = config.services.qbittorrent.mediaDir; - user = "qbittorrent"; - group = "qbittorrent"; - mode = "1775"; - } - ]; - }; - - # [PHASE 3] /var/log persistence - handled by storage.nix after generateBase - environment.persistence."/persist/system/var/log" = { - enable = true; - hideMounts = true; - directories = [ - "/var/log" - ]; - }; - }; -} diff --git a/configurations/nixos/defiant/legacy-storage.nix b/configurations/nixos/defiant/legacy-storage.nix deleted file mode 100644 index 9ab79a6..0000000 --- a/configurations/nixos/defiant/legacy-storage.nix +++ /dev/null @@ -1,218 +0,0 @@ -# Legacy storage configuration for defiant -# This file manually defines ZFS datasets matching the existing on-disk layout -# to allow incremental migration to the new storage module (generateBase = true). -# -# ============================================================================ -# INCREMENTAL MIGRATION PLAN -# ============================================================================ -# -# Current disk usage (for reference): -# rpool/local/system/nix ~26G (renamed in place, no copy) -# rpool/local/system/sops ~328K (renamed in place, no copy) -# rpool/persist/system/jellyfin ~32T (renamed in place, no copy) -# rpool/persist/system/qbittorrent ~6.5T (copied into media dataset, ~6.5T temp) -# rpool free space ~30T -# -# Phase 1: Migrate base datasets on disk (boot from live USB or rescue) -# All operations in this phase are instant renames -- no data is copied. -# -# Unlock the pool: -# zfs load-key -a -# -# Step 1a: Move nix and sops out of local/ (they go to persist/local/) -# The -p flag auto-creates the parent datasets. -# -# zfs rename -p rpool/local/system/nix rpool/persist/local/nix -# zfs rename -p rpool/local/system/sops rpool/persist/local/system/sops -# -# Step 1b: Rename local/ -> ephemeral/ (takes remaining children with it) -# zfs rename rpool/local rpool/ephemeral -# # This moves: local/system/root -> ephemeral/system/root -# # local/home/leyla -> ephemeral/home/leyla -# -# Step 1c: Recreate blank snapshots on ephemeral datasets -# zfs destroy rpool/ephemeral/system/root@blank -# zfs snapshot rpool/ephemeral/system/root@blank -# zfs destroy rpool/ephemeral/home/leyla@blank -# zfs snapshot rpool/ephemeral/home/leyla@blank -# -# Step 1d: Move persist/ children under persist/replicate/ -# zfs create -o canmount=off rpool/persist/replicate -# zfs create -o canmount=off rpool/persist/replicate/system -# zfs rename rpool/persist/system/root rpool/persist/replicate/system/root -# zfs rename rpool/persist/system/var rpool/persist/replicate/system/var -# zfs rename rpool/persist/home/leyla rpool/persist/replicate/home -# # Clean up the now-empty home parent -# zfs destroy rpool/persist/home -# # NOTE: Do NOT destroy rpool/persist/system -- it still contains -# # persist/system/jellyfin and persist/system/qbittorrent which are -# # migrated in Phase 2. -# -# Verify the new layout: -# zfs list -r rpool -o name,used,mountpoint -# -# Phase 2: Merge media into a single dataset (do this last) -# Strategy: Rename the jellyfin dataset to become the shared media dataset -# (zero copy, instant), then copy qbittorrent data into it (~6.5T copy). -# This avoids duplicating the 32T jellyfin dataset. -# -# Step 2a: Rename jellyfin dataset to the shared media name -# zfs rename rpool/persist/system/jellyfin rpool/persist/replicate/system/media -# -# Step 2b: Copy qbittorrent data into the media dataset -# This copies ~6.5T and may take several hours/days depending on disk speed. -# The qbittorrent data is not critical to back up so no snapshot needed. -# -# systemctl stop qbittorrent -# rsync -avPHAX /persist/system/qbittorrent/ /persist/replicate/system/media/ -# -# Step 2c: Verify the data and clean up -# ls -la /persist/replicate/system/media/ -# zfs destroy rpool/persist/system/qbittorrent -# # persist/system should now be empty, clean it up: -# zfs destroy rpool/persist/system -# -# Phase 3: Enable generateBase -# In the nix config: -# - Delete this file (legacy-storage.nix) and remove its import from default.nix -# - Remove [PHASE 3] entries from legacy-impermanence.nix: -# - var-lib-private-permissions activation script -# - /etc/machine-id, SSH host keys (files block) -# - /var/lib/nixos, /var/lib/systemd/coredump (directories) -# - /persist/system/var/log persistence block -# These are now handled automatically by storage.nix and ssh.nix. -# Rebuild and verify: -# sudo nixos-rebuild switch --flake .#defiant -# # Verify mounts: findmnt -t fuse.bindfs,fuse -# # Verify persist: ls /persist/replicate/system/root/var/lib/nixos -# # Verify boot: reboot and confirm system comes up cleanly -# -# Phase 4: Migrate services (one at a time, any order) -# For each service (except jellyfin/qbittorrent): -# 1. Remove the service's [PHASE 4] section from legacy-impermanence.nix -# 2. Remove `impermanence.enable = false` for that service in configuration.nix -# 3. Rebuild: sudo nixos-rebuild switch --flake .#defiant -# 4. Verify: systemctl status , check the service's data is intact -# No data migration is needed -- the data already lives on the renamed -# dataset at the new path. -# -# Migrate jellyfin and qbittorrent LAST (after Phase 2 media merge): -# 1. Remove [PHASE 4 - LAST] jellyfin entries from legacy-impermanence.nix -# 2. Remove [PHASE 4 - LAST] qbittorrent entries from legacy-impermanence.nix -# 3. Remove `impermanence.enable = false` for both in configuration.nix -# 4. Rebuild: sudo nixos-rebuild switch --flake .#defiant -# 5. Verify: systemctl status jellyfin qbittorrent -# -# Phase 5: Cleanup -# Once all services are migrated and legacy-impermanence.nix is empty: -# - Delete legacy-impermanence.nix and remove its import from default.nix -# - Rebuild: sudo nixos-rebuild switch --flake .#defiant -# -# ============================================================================ -# -# Current on-disk dataset layout: -# rpool/local/ - ephemeral parent -# rpool/local/home/leyla - ephemeral user home (rolled back on boot) -# rpool/local/system/nix - nix store -# rpool/local/system/root - root filesystem (rolled back on boot) -# rpool/local/system/sops - sops age key -# rpool/persist/ - persistent parent -# rpool/persist/home/leyla - persistent user home -# rpool/persist/system/jellyfin - jellyfin media -# rpool/persist/system/qbittorrent - qbittorrent media -# rpool/persist/system/root - persistent root data -# rpool/persist/system/var/log - log persistence -{lib, ...}: { - # Disable automatic base dataset generation so we can define them manually - storage.generateBase = false; - - # Manually define ZFS datasets matching main's structure - storage.zfs.datasets = { - # Ephemeral datasets (local/) - "local" = { - type = "zfs_fs"; - mount = null; - }; - "local/home/leyla" = { - type = "zfs_fs"; - mount = "/home/leyla"; - snapshot = { - blankSnapshot = true; - }; - }; - "local/system/nix" = { - type = "zfs_fs"; - mount = "/nix"; - atime = "off"; - relatime = "off"; - snapshot = { - autoSnapshot = false; - }; - }; - "local/system/root" = { - type = "zfs_fs"; - mount = "/"; - snapshot = { - blankSnapshot = true; - }; - }; - "local/system/sops" = { - type = "zfs_fs"; - mount = "/var/lib/sops-nix"; - }; - - # Persistent datasets (persist/) - "persist" = { - type = "zfs_fs"; - mount = null; - }; - "persist/home/leyla" = { - type = "zfs_fs"; - mount = "/persist/home/leyla"; - snapshot = { - autoSnapshot = true; - }; - }; - "persist/system/jellyfin" = { - type = "zfs_fs"; - mount = "/persist/system/jellyfin"; - atime = "off"; - relatime = "off"; - }; - "persist/system/qbittorrent" = { - type = "zfs_fs"; - mount = "/persist/system/qbittorrent"; - atime = "off"; - relatime = "off"; - }; - "persist/system/root" = { - type = "zfs_fs"; - mount = "/persist/system/root"; - snapshot = { - autoSnapshot = true; - }; - }; - "persist/system/var/log" = { - type = "zfs_fs"; - mount = "/persist/system/var/log"; - }; - }; - - # Boot commands to rollback ephemeral root and user homes on boot - boot.initrd.postResumeCommands = lib.mkAfter '' - zfs rollback -r rpool/local/system/root@blank - zfs rollback -r rpool/local/home/leyla@blank - ''; - - # FileSystems needed for boot - fileSystems = { - "/".neededForBoot = true; - "/persist/system/root".neededForBoot = true; - "/persist/system/var/log".neededForBoot = true; - "/persist/system/jellyfin".neededForBoot = true; - "/persist/system/qbittorrent".neededForBoot = true; - "/var/lib/sops-nix".neededForBoot = true; - "/persist/home/leyla".neededForBoot = true; - "/home/leyla".neededForBoot = true; - }; -} diff --git a/configurations/nixos/emergent/configuration.nix b/configurations/nixos/emergent/configuration.nix index 35ef445..bf6c553 100644 --- a/configurations/nixos/emergent/configuration.nix +++ b/configurations/nixos/emergent/configuration.nix @@ -59,22 +59,12 @@ hardware = { piperMouse.enable = true; }; - }; - storage = { - zfs = { + storage = { enable = true; pool = { - mode = "stripe"; - vdevs = [ - [ - { - device = "wwn-0x5000039fd0cf05eb"; - boot = true; - } - ] - ]; - cache = []; + mode = ""; + drives = ["wwn-0x5000039fd0cf05eb"]; }; }; }; @@ -82,7 +72,7 @@ virtualisation.libvirtd.enable = true; users.users.eve = { - extraGroups = ["libvirtd"]; + extraGroups = [ "libvirtd" ]; }; services.tailscale.enable = true; diff --git a/configurations/nixos/emergent/default.nix b/configurations/nixos/emergent/default.nix index 3acaeda..452334a 100644 --- a/configurations/nixos/emergent/default.nix +++ b/configurations/nixos/emergent/default.nix @@ -3,6 +3,5 @@ imports = [ ./configuration.nix ./hardware-configuration.nix - ./legacy-storage.nix ]; } diff --git a/configurations/nixos/emergent/legacy-storage.nix b/configurations/nixos/emergent/legacy-storage.nix deleted file mode 100644 index 2b24729..0000000 --- a/configurations/nixos/emergent/legacy-storage.nix +++ /dev/null @@ -1,51 +0,0 @@ -# Legacy storage configuration for emergent -# This file manually defines ZFS datasets matching the existing on-disk layout -# to allow incremental migration to the new storage module (generateBase = true). -# -# Current on-disk dataset layout: -# rpool/local/ - parent (canmount=off) -# rpool/local/system/nix - nix store -# rpool/local/system/root - root filesystem -# -# Migration plan: -# Phase 1: Rename datasets on disk (boot from live USB) -# zfs rename -p rpool/local/system/nix rpool/persist/local/nix -# zfs rename rpool/local rpool/persist/local -# # This moves: local/system/root -> persist/local/root (need to rename after) -# # Actually, since local/system/root needs to become persist/local/root: -# zfs rename rpool/persist/local/system/root rpool/persist/local/root -# zfs destroy rpool/persist/local/system # now empty -# # Recreate blank snapshot: -# zfs destroy rpool/persist/local/root@blank -# zfs snapshot rpool/persist/local/root@blank -# -# Phase 2: Delete this file, remove its import from default.nix, rebuild. -{...}: { - # Disable automatic base dataset generation so we can define them manually - storage.generateBase = false; - - # Manually define ZFS datasets matching the existing on-disk layout - storage.zfs.datasets = { - "local" = { - type = "zfs_fs"; - mount = null; - }; - "local/system/nix" = { - type = "zfs_fs"; - mount = "/nix"; - atime = "off"; - relatime = "off"; - snapshot = { - autoSnapshot = false; - }; - }; - "local/system/root" = { - type = "zfs_fs"; - mount = "/"; - snapshot = { - blankSnapshot = true; - autoSnapshot = true; - }; - }; - }; -} diff --git a/configurations/nixos/emergent/nvidia-drivers.nix b/configurations/nixos/emergent/nvidia-drivers.nix index 05b7205..0fc51ac 100644 --- a/configurations/nixos/emergent/nvidia-drivers.nix +++ b/configurations/nixos/emergent/nvidia-drivers.nix @@ -1,4 +1,9 @@ -{config, ...}: { +{ + config, + lib, + pkgs, + ... +}: { # Enable OpenGL hardware.graphics = { enable = true; diff --git a/configurations/nixos/horizon/configuration.nix b/configurations/nixos/horizon/configuration.nix index b81a895..0e86fe7 100644 --- a/configurations/nixos/horizon/configuration.nix +++ b/configurations/nixos/horizon/configuration.nix @@ -32,6 +32,7 @@ isPrincipleUser = true; }; eve.isDesktopUser = true; + ivy.isDesktopUser = true; }; hardware = { @@ -84,15 +85,16 @@ }; }; - virtualisation.docker.enable = true; - environment.systemPackages = with pkgs; [ cachefilesd webtoon-dl - android-tools ]; services.cachefilesd.enable = true; + programs = { + adb.enable = true; + }; + networking = { networkmanager.enable = true; hostName = "horizon"; # Define your hostname. diff --git a/configurations/nixos/twilight/configuration.nix b/configurations/nixos/twilight/configuration.nix index d02af0a..477c517 100644 --- a/configurations/nixos/twilight/configuration.nix +++ b/configurations/nixos/twilight/configuration.nix @@ -4,6 +4,10 @@ pkgs, ... }: { + imports = [ + ./monitors.nix + ]; + nixpkgs.config.allowUnfree = true; boot.initrd.availableKernelModules = ["usb_storage"]; diff --git a/configurations/nixos/twilight/hardware-configuration.nix b/configurations/nixos/twilight/hardware-configuration.nix index 1288343..94c83d6 100644 --- a/configurations/nixos/twilight/hardware-configuration.nix +++ b/configurations/nixos/twilight/hardware-configuration.nix @@ -18,12 +18,12 @@ fileSystems = { "/" = { - device = "/dev/disk/by-id/nvme-Samsung_SSD_980_500GB_S64ENJ0RA06463Z-part2"; + device = "/dev/disk/by-id/ata-TOSHIBA_DT01ACA100_77D21HVNS-part2"; fsType = "ext4"; }; "/boot" = { - device = "/dev/disk/by-id/nvme-Samsung_SSD_980_500GB_S64ENJ0RA06463Z-part1"; + device = "/dev/disk/by-id/ata-TOSHIBA_DT01ACA100_77D21HVNS-part1"; fsType = "vfat"; options = ["fmask=0022" "dmask=0022"]; }; diff --git a/configurations/nixos/twilight/monitors.nix b/configurations/nixos/twilight/monitors.nix new file mode 100644 index 0000000..1308f50 --- /dev/null +++ b/configurations/nixos/twilight/monitors.nix @@ -0,0 +1,199 @@ +{pkgs, ...}: { + systemd.tmpfiles.rules = [ + "L+ /run/gdm/.config/monitors.xml - - - - ${pkgs.writeText "gdm-monitors.xml" '' + + + + 0 + 156 + 1 + + + DP-4 + DEL + DELL U2719D + 8RGXNS2 + + + 2560 + 1440 + 59.951 + + + + + 2560 + 324 + 1 + yes + + + DP-2 + GSM + LG ULTRAGEAR + 0x00068c96 + + + 1920 + 1080 + 240.001 + + + + + 4480 + 0 + 1 + + left + no + + + + HDMI-0 + HWP + HP w2207 + CND7332S88 + + + 1600 + 1000 + 59.999 + + + + + + + 0 + 0 + 1 + yes + + + DP-1 + DEL + DELL U2719D + 8RGXNS2 + + + 2560 + 1440 + 59.951 + + + + + 4480 + 226 + 1 + + left + no + + + + HDMI-1 + HWP + HP w2207 + CND7332S88 + + + 1680 + 1050 + 59.954 + + + + + 2560 + 226 + 1 + + + DP-2 + GSM + LG ULTRAGEAR + 0x00068c96 + + + 1920 + 1080 + 240.001 + + + + + + + 2560 + 228 + 1 + yes + + + DP-2 + GSM + LG ULTRAGEAR + 0x00068c96 + + + 1920 + 1080 + 240.001 + + + + + 4480 + 69 + 1 + + left + no + + + + HDMI-1 + HWP + HP w2207 + CND7332S88 + + + 1680 + 1050 + 59.954 + + + + + 0 + 0 + 1 + + + DP-3 + DEL + DELL U2719D + 8RGXNS2 + + + 2560 + 1440 + 59.951 + + + + + + None-1 + unknown + unknown + unknown + + + + + ''}" + ]; +} diff --git a/configurations/nixos/twilight/nvidia-drivers.nix b/configurations/nixos/twilight/nvidia-drivers.nix index 2842d0a..d875e37 100644 --- a/configurations/nixos/twilight/nvidia-drivers.nix +++ b/configurations/nixos/twilight/nvidia-drivers.nix @@ -4,9 +4,8 @@ # Load nvidia driver for Xorg and Wayland videoDrivers = ["nvidia"]; }; - # Temporarily enable wayland to fix boot issue - # TODO: Investigate proper X11 session generation for gaming - displayManager.gdm.wayland = true; + # Use X instead of wayland for gaming reasons + displayManager.gdm.wayland = false; }; hardware = { diff --git a/flake.lock b/flake.lock index 14c8561..a3c552f 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,23 @@ { "nodes": { + "devshell": { + "inputs": { + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1741473158, + "narHash": "sha256-kWNaq6wQUbUMlPgw8Y+9/9wP0F8SHkjy24/mN3UAppg=", + "owner": "numtide", + "repo": "devshell", + "rev": "7c9e793ebe66bcba8292989a68c0419b737a22a0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "devshell", + "type": "github" + } + }, "disko": { "inputs": { "nixpkgs": [ @@ -7,11 +25,11 @@ ] }, "locked": { - "lastModified": 1772867152, - "narHash": "sha256-RIFgZ4O6Eg+5ysZ8Tqb3YvcqiRaNy440GEY22ltjRrs=", + "lastModified": 1763651264, + "narHash": "sha256-8vvwZbw0s7YvBMJeyPVpWke6lg6ROgtts5N2/SMCcv4=", "owner": "nix-community", "repo": "disko", - "rev": "eaafb89b56e948661d618eefd4757d9ea8d77514", + "rev": "e86a89079587497174ccab6d0d142a65811a4fd9", "type": "github" }, "original": { @@ -28,11 +46,11 @@ }, "locked": { "dir": "pkgs/firefox-addons", - "lastModified": 1772856163, - "narHash": "sha256-xD+d1+FVhKJ+oFYMTWOdVSBoXS4yeMyVZyDjMXqWEJE=", + "lastModified": 1763697825, + "narHash": "sha256-AgCCcVPOi1tuzuW5/StlwqBjRWSX62oL97qWuxrq5UA=", "owner": "rycee", "repo": "nur-expressions", - "rev": "d358a550c7beac5f04fbc5a786e14af079606689", + "rev": "cefce78793603231be226fa77e7ad58e0e4899b8", "type": "gitlab" }, "original": { @@ -44,11 +62,11 @@ }, "flake-compat": { "locked": { - "lastModified": 1767039857, - "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "lastModified": 1761588595, + "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", "owner": "edolstra", "repo": "flake-compat", - "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", "type": "github" }, "original": { @@ -57,24 +75,6 @@ "type": "github" } }, - "flake-parts": { - "inputs": { - "nixpkgs-lib": "nixpkgs-lib" - }, - "locked": { - "lastModified": 1767609335, - "narHash": "sha256-feveD98mQpptwrAEggBQKJTYbvwwglSbOv53uCfH9PY=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "250481aafeb741edfe23d29195671c19b36b6dca", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "flake-parts", - "type": "github" - } - }, "flake-utils": { "inputs": { "systems": "systems" @@ -93,6 +93,24 @@ "type": "github" } }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, "flakey-profile": { "locked": { "lastModified": 1712898590, @@ -115,11 +133,11 @@ ] }, "locked": { - "lastModified": 1772845525, - "narHash": "sha256-Dp5Ir2u4jJDGCgeMRviHvEQDe+U37hMxp6RSNOoMMPc=", + "lastModified": 1763748372, + "narHash": "sha256-AUc78Qv3sWir0hvbmfXoZ7Jzq9VVL97l+sP9Jgms+JU=", "owner": "nix-community", "repo": "home-manager", - "rev": "27b93804fbef1544cb07718d3f0a451f4c4cd6c0", + "rev": "d10a9b16b2a3ee28433f3d1c603f4e9f1fecb8e1", "type": "github" }, "original": { @@ -129,20 +147,12 @@ } }, "impermanence": { - "inputs": { - "home-manager": [ - "home-manager" - ], - "nixpkgs": [ - "nixpkgs" - ] - }, "locked": { - "lastModified": 1769548169, - "narHash": "sha256-03+JxvzmfwRu+5JafM0DLbxgHttOQZkUtDWBmeUkN8Y=", + "lastModified": 1737831083, + "narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=", "owner": "nix-community", "repo": "impermanence", - "rev": "7b1d382faf603b6d264f58627330f9faa5cba149", + "rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170", "type": "github" }, "original": { @@ -175,11 +185,11 @@ ] }, "locked": { - "lastModified": 1767364176, - "narHash": "sha256-l6YdEBYQxXjD8ujqvc0tKdwWc3K8UQOi+E4Y3DKQ318=", + "lastModified": 1763435414, + "narHash": "sha256-i2467FddWfd19q5Qoj+1/BAeg6LZmM5m4mYGRSQn/as=", "ref": "refs/heads/main", - "rev": "1688100bba140492658d597f6b307c327f35c780", - "revCount": 179, + "rev": "192c92b603731fbc1bade6c1b18c8d8a0086f703", + "revCount": 169, "type": "git", "url": "https://git.lix.systems/lix-project/nixos-module.git" }, @@ -190,15 +200,18 @@ }, "mcp-nixos": { "inputs": { - "flake-parts": "flake-parts", - "nixpkgs": "nixpkgs" + "devshell": "devshell", + "flake-utils": "flake-utils_2", + "nixpkgs": [ + "nixpkgs" + ] }, "locked": { - "lastModified": 1772769318, - "narHash": "sha256-RAyOW5JMXRhiREqxFPOzw80fVsYVBnOPFgBSjnJ6gbY=", + "lastModified": 1760821194, + "narHash": "sha256-UCsJ8eDuHL14u2GFIYEY/drtZ6jht5zN/G/6QNlEy2g=", "owner": "utensils", "repo": "mcp-nixos", - "rev": "60c1efbba0de1268b42f1144c904e6c8a9627dde", + "rev": "0ae453f38d0f088c31d4678da3a12b183165986f", "type": "github" }, "original": { @@ -214,11 +227,11 @@ ] }, "locked": { - "lastModified": 1772379624, - "narHash": "sha256-NG9LLTWlz4YiaTAiRGChbrzbVxBfX+Auq4Ab/SWmk4A=", + "lastModified": 1763505477, + "narHash": "sha256-nJRd4LY2kT3OELfHqdgWjvToNZ4w+zKCMzS2R6z4sXE=", "owner": "LnL7", "repo": "nix-darwin", - "rev": "52d061516108769656a8bd9c6e811c677ec5b462", + "rev": "3bda9f6b14161becbd07b3c56411f1670e19b9b5", "type": "github" }, "original": { @@ -255,11 +268,11 @@ ] }, "locked": { - "lastModified": 1772850876, - "narHash": "sha256-Ga19zlfMpakCY4GMwBSOljNLOF0nEYrYBXv0hP/d4rw=", + "lastModified": 1763690163, + "narHash": "sha256-MMl9P8f17unCvlk2IAinnMq/P72f51UUHVRIYnojT7w=", "owner": "nix-community", "repo": "nix-vscode-extensions", - "rev": "22f084d4c280dfc8a9d764f7b85af38e5d69c3dc", + "rev": "590349d9faeb398a037205c2927ffbaede980539", "type": "github" }, "original": { @@ -270,11 +283,11 @@ }, "nixos-hardware": { "locked": { - "lastModified": 1771969195, - "narHash": "sha256-qwcDBtrRvJbrrnv1lf/pREQi8t2hWZxVAyeMo7/E9sw=", + "lastModified": 1762847253, + "narHash": "sha256-BWWnUUT01lPwCWUvS0p6Px5UOBFeXJ8jR+ZdLX8IbrU=", "owner": "NixOS", "repo": "nixos-hardware", - "rev": "41c6b421bdc301b2624486e11905c9af7b8ec68e", + "rev": "899dc449bc6428b9ee6b3b8f771ca2b0ef945ab9", "type": "github" }, "original": { @@ -286,42 +299,27 @@ }, "nixpkgs": { "locked": { - "lastModified": 1767640445, - "narHash": "sha256-UWYqmD7JFBEDBHWYcqE6s6c77pWdcU/i+bwD6XxMb8A=", + "lastModified": 1722073938, + "narHash": "sha256-OpX0StkL8vpXyWOGUD6G+MA26wAXK6SpT94kLJXo6B4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "9f0c42f8bc7151b8e7e5840fb3bd454ad850d8c5", + "rev": "e36e9f57337d0ff0cf77aceb58af4c805472bfae", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-unstable", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-lib": { - "locked": { - "lastModified": 1765674936, - "narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=", - "owner": "nix-community", - "repo": "nixpkgs.lib", - "rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixpkgs.lib", - "type": "github" - } - }, "nixpkgs_2": { "locked": { - "lastModified": 1772773019, - "narHash": "sha256-E1bxHxNKfDoQUuvriG71+f+s/NT0qWkImXsYZNFFfCs=", + "lastModified": 1763421233, + "narHash": "sha256-Stk9ZYRkGrnnpyJ4eqt9eQtdFWRRIvMxpNRf4sIegnw=", "owner": "nixos", "repo": "nixpkgs", - "rev": "aca4d95fce4914b3892661bcb80b8087293536c6", + "rev": "89c2b2330e733d6cdb5eae7b899326930c2c0648", "type": "github" }, "original": { @@ -351,14 +349,14 @@ "inputs": { "nixpkgs": "nixpkgs_3", "rust-overlay": "rust-overlay", - "systems": "systems_2" + "systems": "systems_3" }, "locked": { - "lastModified": 1771445312, - "narHash": "sha256-8uOcu+ZurGx0LmGFCf87Zbj4ikhVPQtP+PuBscEBCv0=", + "lastModified": 1764204484, + "narHash": "sha256-S45ghD/YjcKDy8Mz3DYklLMaA/z6f6mTbx0i7pAktYk=", "owner": "IntQuant", "repo": "noita_entangled_worlds", - "rev": "4a842f29d0e5fb8dc6df73d87f7bb8d2a16f0fc8", + "rev": "ab2c2162157140ab519fa19f6737c044e1ed0e3b", "type": "github" }, "original": { @@ -411,11 +409,11 @@ "secrets": { "flake": false, "locked": { - "lastModified": 1768867162, - "narHash": "sha256-NiW2gUcdhnUbYQw476HzgBz+uVjyLnz151hzCQbWBX8=", + "lastModified": 1759945215, + "narHash": "sha256-xmUzOuhJl6FtTjR5++OQvSoAnXe7/VA5QFCZDyFwBXo=", "ref": "refs/heads/main", - "rev": "22be81505a49cd205e9b5c91f51af69c0b885ed3", - "revCount": 23, + "rev": "444229a105445339fb028d15a8d866063c5f8141", + "revCount": 21, "type": "git", "url": "ssh://git@git.jan-leila.com/jan-leila/nix-config-secrets.git" }, @@ -431,11 +429,11 @@ ] }, "locked": { - "lastModified": 1772495394, - "narHash": "sha256-hmIvE/slLKEFKNEJz27IZ8BKlAaZDcjIHmkZ7GCEjfw=", + "lastModified": 1763607916, + "narHash": "sha256-VefBA1JWRXM929mBAFohFUtQJLUnEwZ2vmYUNkFnSjE=", "owner": "Mic92", "repo": "sops-nix", - "rev": "1d9b98a29a45abe9c4d3174bd36de9f28755e3ff", + "rev": "877bb495a6f8faf0d89fc10bd142c4b7ed2bcc0b", "type": "github" }, "original": { @@ -460,6 +458,21 @@ } }, "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { "flake": false, "locked": { "lastModified": 1681028828, diff --git a/flake.nix b/flake.nix index df5f6e9..e935688 100644 --- a/flake.nix +++ b/flake.nix @@ -37,8 +37,6 @@ # delete your darlings impermanence = { url = "github:nix-community/impermanence"; - inputs.nixpkgs.follows = "nixpkgs"; - inputs.home-manager.follows = "home-manager"; }; nix-darwin = { @@ -77,7 +75,7 @@ # MCP NixOS server for Claude Dev mcp-nixos = { url = "github:utensils/mcp-nixos"; - # Not following nixpkgs because aws-sam-translator doesn't support Python 3.14 yet + inputs.nixpkgs.follows = "nixpkgs"; }; # Noita Entangled Worlds package diff --git a/modules/common-modules/pkgs/cline/cline-package-lock.json b/modules/common-modules/pkgs/cline/cline-package-lock.json deleted file mode 100644 index b8d0d6e..0000000 --- a/modules/common-modules/pkgs/cline/cline-package-lock.json +++ /dev/null @@ -1,4102 +0,0 @@ -{ - "name": "cline", - "version": "2.4.2", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "cline", - "version": "2.4.2", - "cpu": [ - "x64", - "arm64" - ], - "license": "Apache-2.0", - "os": [ - "darwin", - "linux", - "win32" - ], - "dependencies": { - "@agentclientprotocol/sdk": "^0.13.1", - "aws4fetch": "^1.0.20", - "chalk": "^5.3.0", - "commander": "^12.1.0", - "ink": "npm:@jrichman/ink@6.4.7", - "ink-picture": "^1.3.3", - "ink-spinner": "^5.0.0", - "nanoid": "^5.1.6", - "ora": "^8.0.1", - "pino": "^10.0.0", - "pino-roll": "^4.0.0", - "prompts": "^2.4.2", - "react": "^19.2.3" - }, - "bin": { - "cline": "dist/cli.mjs" - }, - "devDependencies": { - "@types/node": "20.x", - "@types/prompts": "^2.4.9", - "@types/react": "^19.2.9", - "dotenv": "^16.4.5", - "esbuild": "^0.25.0", - "ink-testing-library": "^4.0.0", - "rimraf": "^6.0.1", - "typescript": "^5.4.5", - "vitest": "^4.0.17" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@agentclientprotocol/sdk": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/@agentclientprotocol/sdk/-/sdk-0.13.1.tgz", - "integrity": "sha512-6byvu+F/xc96GBkdAx4hq6/tB3vT63DSBO4i3gYCz8nuyZMerVFna2Gkhm8EHNpZX0J9DjUxzZCW+rnHXUg0FA==", - "license": "Apache-2.0", - "peerDependencies": { - "zod": "^3.25.0 || ^4.0.0" - } - }, - "node_modules/@alcalzone/ansi-tokenize": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@alcalzone/ansi-tokenize/-/ansi-tokenize-0.2.5.tgz", - "integrity": "sha512-3NX/MpTdroi0aKz134A6RC2Gb2iXVECN4QaAXnvCIxxIm3C3AVB1mkUe8NaaiyvOpDfsrqWhYtj+Q6a62RrTsw==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", - "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@img/colour": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", - "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", - "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", - "cpu": [ - "ppc64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", - "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", - "cpu": [ - "riscv64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", - "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", - "cpu": [ - "s390x" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", - "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", - "cpu": [ - "ppc64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-riscv64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", - "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", - "cpu": [ - "riscv64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", - "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", - "cpu": [ - "s390x" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", - "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", - "cpu": [ - "wasm32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.7.0" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", - "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@pinojs/redact": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", - "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.58.0.tgz", - "integrity": "sha512-mr0tmS/4FoVk1cnaeN244A/wjvGDNItZKR8hRhnmCzygyRXYtKF5jVDSIILR1U97CTzAYmbgIj/Dukg62ggG5w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.58.0.tgz", - "integrity": "sha512-+s++dbp+/RTte62mQD9wLSbiMTV+xr/PeRJEc/sFZFSBRlHPNPVaf5FXlzAL77Mr8FtSfQqCN+I598M8U41ccQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.58.0.tgz", - "integrity": "sha512-MFWBwTcYs0jZbINQBXHfSrpSQJq3IUOakcKPzfeSznONop14Pxuqa0Kg19GD0rNBMPQI2tFtu3UzapZpH0Uc1Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.58.0.tgz", - "integrity": "sha512-yiKJY7pj9c9JwzuKYLFaDZw5gma3fI9bkPEIyofvVfsPqjCWPglSHdpdwXpKGvDeYDms3Qal8qGMEHZ1M/4Udg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.58.0.tgz", - "integrity": "sha512-x97kCoBh5MOevpn/CNK9W1x8BEzO238541BGWBc315uOlN0AD/ifZ1msg+ZQB05Ux+VF6EcYqpiagfLJ8U3LvQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.58.0.tgz", - "integrity": "sha512-Aa8jPoZ6IQAG2eIrcXPpjRcMjROMFxCt1UYPZZtCxRV68WkuSigYtQ/7Zwrcr2IvtNJo7T2JfDXyMLxq5L4Jlg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.58.0.tgz", - "integrity": "sha512-Ob8YgT5kD/lSIYW2Rcngs5kNB/44Q2RzBSPz9brf2WEtcGR7/f/E9HeHn1wYaAwKBni+bdXEwgHvUd0x12lQSA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.58.0.tgz", - "integrity": "sha512-K+RI5oP1ceqoadvNt1FecL17Qtw/n9BgRSzxif3rTL2QlIu88ccvY+Y9nnHe/cmT5zbH9+bpiJuG1mGHRVwF4Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.58.0.tgz", - "integrity": "sha512-T+17JAsCKUjmbopcKepJjHWHXSjeW7O5PL7lEFaeQmiVyw4kkc5/lyYKzrv6ElWRX/MrEWfPiJWqbTvfIvjM1Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.58.0.tgz", - "integrity": "sha512-cCePktb9+6R9itIJdeCFF9txPU7pQeEHB5AbHu/MKsfH/k70ZtOeq1k4YAtBv9Z7mmKI5/wOLYjQ+B9QdxR6LA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.58.0.tgz", - "integrity": "sha512-iekUaLkfliAsDl4/xSdoCJ1gnnIXvoNz85C8U8+ZxknM5pBStfZjeXgB8lXobDQvvPRCN8FPmmuTtH+z95HTmg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.58.0.tgz", - "integrity": "sha512-68ofRgJNl/jYJbxFjCKE7IwhbfxOl1muPN4KbIqAIe32lm22KmU7E8OPvyy68HTNkI2iV/c8y2kSPSm2mW/Q9Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.58.0.tgz", - "integrity": "sha512-dpz8vT0i+JqUKuSNPCP5SYyIV2Lh0sNL1+FhM7eLC457d5B9/BC3kDPp5BBftMmTNsBarcPcoz5UGSsnCiw4XQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.58.0.tgz", - "integrity": "sha512-4gdkkf9UJ7tafnweBCR/mk4jf3Jfl0cKX9Np80t5i78kjIH0ZdezUv/JDI2VtruE5lunfACqftJ8dIMGN4oHew==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.58.0.tgz", - "integrity": "sha512-YFS4vPnOkDTD/JriUeeZurFYoJhPf9GQQEF/v4lltp3mVcBmnsAdjEWhr2cjUCZzZNzxCG0HZOvJU44UGHSdzw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.58.0.tgz", - "integrity": "sha512-x2xgZlFne+QVNKV8b4wwaCS8pwq3y14zedZ5DqLzjdRITvreBk//4Knbcvm7+lWmms9V9qFp60MtUd0/t/PXPw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.58.0.tgz", - "integrity": "sha512-jIhrujyn4UnWF8S+DHSkAkDEO3hLX0cjzxJZPLF80xFyzyUIYgSMRcYQ3+uqEoyDD2beGq7Dj7edi8OnJcS/hg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.58.0.tgz", - "integrity": "sha512-+410Srdoh78MKSJxTQ+hZ/Mx+ajd6RjjPwBPNd0R3J9FtL6ZA0GqiiyNjCO9In0IzZkCNrpGymSfn+kgyPQocg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.58.0.tgz", - "integrity": "sha512-ZjMyby5SICi227y1MTR3VYBpFTdZs823Rs/hpakufleBoufoOIB6jtm9FEoxn/cgO7l6PM2rCEl5Kre5vX0QrQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.58.0.tgz", - "integrity": "sha512-ds4iwfYkSQ0k1nb8LTcyXw//ToHOnNTJtceySpL3fa7tc/AsE+UpUFphW126A6fKBGJD5dhRvg8zw1rvoGFxmw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.58.0.tgz", - "integrity": "sha512-fd/zpJniln4ICdPkjWFhZYeY/bpnaN9pGa6ko+5WD38I0tTqk9lXMgXZg09MNdhpARngmxiCg0B0XUamNw/5BQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.58.0.tgz", - "integrity": "sha512-YpG8dUOip7DCz3nr/JUfPbIUo+2d/dy++5bFzgi4ugOGBIox+qMbbqt/JoORwvI/C9Kn2tz6+Bieoqd5+B1CjA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.58.0.tgz", - "integrity": "sha512-b9DI8jpFQVh4hIXFr0/+N/TzLdpBIoPzjt0Rt4xJbW3mzguV3mduR9cNgiuFcuL/TeORejJhCWiAXe3E/6PxWA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.58.0.tgz", - "integrity": "sha512-CSrVpmoRJFN06LL9xhkitkwUcTZtIotYAF5p6XOR2zW0Zz5mzb3IPpcoPhB02frzMHFNo1reQ9xSF5fFm3hUsQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.58.0.tgz", - "integrity": "sha512-QFsBgQNTnh5K0t/sBsjJLq24YVqEIVkGpfN2VHsnN90soZyhaiA9UUHufcctVNL4ypJY0wrwad0wslx2KJQ1/w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "20.19.33", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.33.tgz", - "integrity": "sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/prompts": { - "version": "2.4.9", - "resolved": "https://registry.npmjs.org/@types/prompts/-/prompts-2.4.9.tgz", - "integrity": "sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "kleur": "^3.0.3" - } - }, - "node_modules/@types/react": { - "version": "19.2.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", - "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", - "devOptional": true, - "license": "MIT", - "peer": true, - "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@vitest/expect": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", - "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "chai": "^6.2.1", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/mocker": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", - "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.0.18", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", - "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", - "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.0.18", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", - "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.18", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", - "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", - "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.18", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@xmldom/xmldom": { - "version": "0.8.11", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", - "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/ansi-escapes": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", - "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", - "license": "MIT", - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/app-path": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/app-path/-/app-path-4.0.0.tgz", - "integrity": "sha512-mgBO9PZJ3MpbKbwFTljTi36ZKBvG5X/fkVR1F85ANsVcVllEb+C0LGNdJfGUm84GpC4xxgN6HFkmkMU8VEO4mA==", - "license": "MIT", - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/atomic-sleep": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", - "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/auto-bind": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-5.0.1.tgz", - "integrity": "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/aws4fetch": { - "version": "1.0.20", - "resolved": "https://registry.npmjs.org/aws4fetch/-/aws4fetch-1.0.20.tgz", - "integrity": "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g==", - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.3.tgz", - "integrity": "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz", - "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/cli-boxes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", - "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", - "license": "MIT", - "dependencies": { - "restore-cursor": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", - "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", - "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", - "license": "MIT", - "dependencies": { - "slice-ansi": "^5.0.0", - "string-width": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/node_modules/is-fullwidth-code-point": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", - "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate/node_modules/slice-ansi": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", - "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.0.0", - "is-fullwidth-code-point": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/code-excerpt": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/code-excerpt/-/code-excerpt-4.0.0.tgz", - "integrity": "sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==", - "license": "MIT", - "dependencies": { - "convert-to-spaces": "^2.0.1" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/convert-to-spaces": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/convert-to-spaces/-/convert-to-spaces-2.0.1.tgz", - "integrity": "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/date-fns": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", - "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/kossnocorp" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/dotenv": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", - "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "license": "MIT" - }, - "node_modules/environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/es-toolkit": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.44.0.tgz", - "integrity": "sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==", - "license": "MIT", - "workspaces": [ - "docs", - "benchmarks" - ] - }, - "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" - } - }, - "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "license": "MIT", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", - "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/indent-string": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ink": { - "name": "@jrichman/ink", - "version": "6.4.7", - "resolved": "https://registry.npmjs.org/@jrichman/ink/-/ink-6.4.7.tgz", - "integrity": "sha512-QHyxhNF5VonF5cRmdAJD/UPucB9nRx3FozWMjQrDGfBxfAL9lpyu72/MlFPgloS1TMTGsOt7YN6dTPPA6mh0Aw==", - "license": "MIT", - "peer": true, - "dependencies": { - "@alcalzone/ansi-tokenize": "^0.2.1", - "ansi-escapes": "^7.0.0", - "ansi-styles": "^6.2.1", - "auto-bind": "^5.0.1", - "chalk": "^5.6.0", - "cli-boxes": "^3.0.0", - "cli-cursor": "^4.0.0", - "cli-truncate": "^4.0.0", - "code-excerpt": "^4.0.0", - "es-toolkit": "^1.39.10", - "indent-string": "^5.0.0", - "is-in-ci": "^2.0.0", - "mnemonist": "^0.40.3", - "patch-console": "^2.0.0", - "react-reconciler": "^0.32.0", - "signal-exit": "^3.0.7", - "slice-ansi": "^7.1.0", - "stack-utils": "^2.0.6", - "string-width": "^8.1.0", - "type-fest": "^4.27.0", - "wrap-ansi": "^9.0.0", - "ws": "^8.18.0", - "yoga-layout": "~3.2.1" - }, - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "@types/react": ">=19.0.0", - "react": ">=19.0.0", - "react-devtools-core": "^6.1.2" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "react-devtools-core": { - "optional": true - } - } - }, - "node_modules/ink-picture": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/ink-picture/-/ink-picture-1.3.3.tgz", - "integrity": "sha512-kFDZaiqnvbM2cU46ptIHFeh4RJkfsZfQUh657JmbOmD/swANdCkUvcb8c3Qv6270qFWKwRehf04fghMwtHwEGw==", - "license": "MIT", - "dependencies": { - "chalk": "^5.6.0", - "is-unicode-supported": "^2.1.0", - "iterm2-version": "^5.0.0", - "node-fetch": "^3.3.2", - "sharp": "^0.34.3", - "sixel": "^0.16.0", - "supports-color": "^10.2.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "ink": ">=5", - "react": ">=18" - } - }, - "node_modules/ink-spinner": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ink-spinner/-/ink-spinner-5.0.0.tgz", - "integrity": "sha512-EYEasbEjkqLGyPOUc8hBJZNuC5GvXGMLu0w5gdTNskPc7Izc5vO3tdQEYnzvshucyGCBXc86ig0ujXPMWaQCdA==", - "license": "MIT", - "dependencies": { - "cli-spinners": "^2.7.0" - }, - "engines": { - "node": ">=14.16" - }, - "peerDependencies": { - "ink": ">=4.0.0", - "react": ">=18.0.0" - } - }, - "node_modules/ink-testing-library": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ink-testing-library/-/ink-testing-library-4.0.0.tgz", - "integrity": "sha512-yF92kj3pmBvk7oKbSq5vEALO//o7Z9Ck/OaLNlkzXNeYdwfpxMQkSowGTFUCS5MSu9bWfSZMewGpp7bFc66D7Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/react": ">=18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-in-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-in-ci/-/is-in-ci-2.0.0.tgz", - "integrity": "sha512-cFeerHriAnhrQSbpAxL37W1wcJKUUX07HyLWZCW1URJT/ra3GyUTzBgUnh24TMVfNTV2Hij2HLxkPHFZfOZy5w==", - "license": "MIT", - "bin": { - "is-in-ci": "cli.js" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-interactive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", - "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/iterm2-version": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/iterm2-version/-/iterm2-version-5.0.0.tgz", - "integrity": "sha512-WdLXcMYvN3SXT6vEtuW78vnZs4pVWm2nBnb4VKjOPPXmdlR1xTHmBgqKacOzAe4RXOiY/V+0u/0zsU3LoGQoBg==", - "license": "MIT", - "dependencies": { - "app-path": "^4.0.0", - "plist": "^3.0.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/log-symbols": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", - "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", - "license": "MIT", - "dependencies": { - "chalk": "^5.3.0", - "is-unicode-supported": "^1.3.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-symbols/node_modules/is-unicode-supported": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", - "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT" - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", - "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/mnemonist": { - "version": "0.40.3", - "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.40.3.tgz", - "integrity": "sha512-Vjyr90sJ23CKKH/qPAgUKicw/v6pRoamxIEDFOF8uSgFME7DqPRpHgRTejWVjkdGg5dXj0/NyxZHZ9bcjH+2uQ==", - "license": "MIT", - "dependencies": { - "obliterator": "^2.0.4" - } - }, - "node_modules/nanoid": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", - "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.js" - }, - "engines": { - "node": "^18 || >=20" - } - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "license": "MIT", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/obliterator": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", - "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", - "license": "MIT" - }, - "node_modules/obug": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT" - }, - "node_modules/on-exit-leak-free": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", - "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", - "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", - "license": "MIT", - "dependencies": { - "chalk": "^5.3.0", - "cli-cursor": "^5.0.0", - "cli-spinners": "^2.9.2", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.0.0", - "log-symbols": "^6.0.0", - "stdin-discarder": "^0.2.2", - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/ora/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/patch-console": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/patch-console/-/patch-console-2.0.0.tgz", - "integrity": "sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA==", - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pino": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", - "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", - "license": "MIT", - "dependencies": { - "@pinojs/redact": "^0.4.0", - "atomic-sleep": "^1.0.0", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^3.0.0", - "pino-std-serializers": "^7.0.0", - "process-warning": "^5.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.2.0", - "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^4.0.1", - "thread-stream": "^4.0.0" - }, - "bin": { - "pino": "bin.js" - } - }, - "node_modules/pino-abstract-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", - "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", - "license": "MIT", - "dependencies": { - "split2": "^4.0.0" - } - }, - "node_modules/pino-roll": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/pino-roll/-/pino-roll-4.0.0.tgz", - "integrity": "sha512-axI1aQaIxXdw1F4OFFli1EDxIrdYNGLowkw/ZoZogX8oCSLHUghzwVVXUS8U+xD/Savwa5IXpiXmsSGKFX/7Sg==", - "license": "MIT", - "dependencies": { - "date-fns": "^4.1.0", - "sonic-boom": "^4.0.1" - } - }, - "node_modules/pino-std-serializers": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", - "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", - "license": "MIT" - }, - "node_modules/plist": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", - "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", - "license": "MIT", - "dependencies": { - "@xmldom/xmldom": "^0.8.8", - "base64-js": "^1.5.1", - "xmlbuilder": "^15.1.1" - }, - "engines": { - "node": ">=10.4.0" - } - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/process-warning": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", - "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT" - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/quick-format-unescaped": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", - "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", - "license": "MIT" - }, - "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-reconciler": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.32.0.tgz", - "integrity": "sha512-2NPMOzgTlG0ZWdIf3qG+dcbLSoAc/uLfOwckc3ofy5sSK0pLJqnQLpUFxvGcN2rlXSjnVtGeeFLNimCQEj5gOQ==", - "license": "MIT", - "dependencies": { - "scheduler": "^0.26.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "peerDependencies": { - "react": "^19.1.0" - } - }, - "node_modules/real-require": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", - "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", - "license": "MIT", - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/restore-cursor": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", - "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", - "license": "MIT", - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/rimraf": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", - "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "glob": "^13.0.3", - "package-json-from-dist": "^1.0.1" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.58.0.tgz", - "integrity": "sha512-wbT0mBmWbIvvq8NeEYWWvevvxnOyhKChir47S66WCxw1SXqhw7ssIYejnQEVt7XYQpsj2y8F9PM+Cr3SNEa0gw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.58.0", - "@rollup/rollup-android-arm64": "4.58.0", - "@rollup/rollup-darwin-arm64": "4.58.0", - "@rollup/rollup-darwin-x64": "4.58.0", - "@rollup/rollup-freebsd-arm64": "4.58.0", - "@rollup/rollup-freebsd-x64": "4.58.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.58.0", - "@rollup/rollup-linux-arm-musleabihf": "4.58.0", - "@rollup/rollup-linux-arm64-gnu": "4.58.0", - "@rollup/rollup-linux-arm64-musl": "4.58.0", - "@rollup/rollup-linux-loong64-gnu": "4.58.0", - "@rollup/rollup-linux-loong64-musl": "4.58.0", - "@rollup/rollup-linux-ppc64-gnu": "4.58.0", - "@rollup/rollup-linux-ppc64-musl": "4.58.0", - "@rollup/rollup-linux-riscv64-gnu": "4.58.0", - "@rollup/rollup-linux-riscv64-musl": "4.58.0", - "@rollup/rollup-linux-s390x-gnu": "4.58.0", - "@rollup/rollup-linux-x64-gnu": "4.58.0", - "@rollup/rollup-linux-x64-musl": "4.58.0", - "@rollup/rollup-openbsd-x64": "4.58.0", - "@rollup/rollup-openharmony-arm64": "4.58.0", - "@rollup/rollup-win32-arm64-msvc": "4.58.0", - "@rollup/rollup-win32-ia32-msvc": "4.58.0", - "@rollup/rollup-win32-x64-gnu": "4.58.0", - "@rollup/rollup-win32-x64-msvc": "4.58.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/safe-stable-stringify": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/scheduler": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", - "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/sharp": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", - "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@img/colour": "^1.0.0", - "detect-libc": "^2.1.2", - "semver": "^7.7.3" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.5", - "@img/sharp-darwin-x64": "0.34.5", - "@img/sharp-libvips-darwin-arm64": "1.2.4", - "@img/sharp-libvips-darwin-x64": "1.2.4", - "@img/sharp-libvips-linux-arm": "1.2.4", - "@img/sharp-libvips-linux-arm64": "1.2.4", - "@img/sharp-libvips-linux-ppc64": "1.2.4", - "@img/sharp-libvips-linux-riscv64": "1.2.4", - "@img/sharp-libvips-linux-s390x": "1.2.4", - "@img/sharp-libvips-linux-x64": "1.2.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", - "@img/sharp-libvips-linuxmusl-x64": "1.2.4", - "@img/sharp-linux-arm": "0.34.5", - "@img/sharp-linux-arm64": "0.34.5", - "@img/sharp-linux-ppc64": "0.34.5", - "@img/sharp-linux-riscv64": "0.34.5", - "@img/sharp-linux-s390x": "0.34.5", - "@img/sharp-linux-x64": "0.34.5", - "@img/sharp-linuxmusl-arm64": "0.34.5", - "@img/sharp-linuxmusl-x64": "0.34.5", - "@img/sharp-wasm32": "0.34.5", - "@img/sharp-win32-arm64": "0.34.5", - "@img/sharp-win32-ia32": "0.34.5", - "@img/sharp-win32-x64": "0.34.5" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "license": "MIT" - }, - "node_modules/sixel": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/sixel/-/sixel-0.16.0.tgz", - "integrity": "sha512-xicu6Y6Cyhmv5rjyHxq2r5RnKerlL/nyZEGjOU5bLCshXkZryc9JFJThTCKPOAtWXCfeWquEKFVFfMPcTD25PA==", - "license": "MIT" - }, - "node_modules/slice-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/sonic-boom": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", - "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", - "license": "MIT", - "dependencies": { - "atomic-sleep": "^1.0.0" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "dev": true, - "license": "MIT" - }, - "node_modules/stdin-discarder": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", - "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", - "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.5.0", - "strip-ansi": "^7.1.2" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/supports-color": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", - "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/thread-stream": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", - "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", - "license": "MIT", - "dependencies": { - "real-require": "^0.2.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyrainbow": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "optional": true - }, - "node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - } - }, - "node_modules/vitest": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", - "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.0.18", - "@vitest/mocker": "4.0.18", - "@vitest/pretty-format": "4.0.18", - "@vitest/runner": "4.0.18", - "@vitest/snapshot": "4.0.18", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "es-module-lexer": "^1.7.0", - "expect-type": "^1.2.2", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^3.10.0", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3", - "vite": "^6.0.0 || ^7.0.0", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.0.18", - "@vitest/browser-preview": "4.0.18", - "@vitest/browser-webdriverio": "4.0.18", - "@vitest/ui": "4.0.18", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xmlbuilder": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", - "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", - "license": "MIT", - "engines": { - "node": ">=8.0" - } - }, - "node_modules/yoga-layout": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz", - "integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==", - "license": "MIT" - }, - "node_modules/zod": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", - "license": "MIT", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/modules/common-modules/pkgs/cline/default.nix b/modules/common-modules/pkgs/cline/default.nix deleted file mode 100644 index 05dbf48..0000000 --- a/modules/common-modules/pkgs/cline/default.nix +++ /dev/null @@ -1,53 +0,0 @@ -{ - lib, - buildNpmPackage, - fetchurl, - ripgrep, - makeWrapper, - jq, - ... -}: -buildNpmPackage rec { - pname = "cline"; - version = "2.4.2"; - - src = fetchurl { - url = "https://registry.npmjs.org/cline/-/cline-${version}.tgz"; - hash = "sha256-2utOBC0vhoj5fR+cG+Vdo3N6+i/pNW1E4mESF/dZS/c="; - }; - - sourceRoot = "package"; - - postPatch = '' - cp ${./cline-package-lock.json} package-lock.json - - # Remove @vscode/ripgrep from package.json since it tries to download - # a binary from GitHub during install, which fails in the nix sandbox. - # We provide ripgrep from nixpkgs instead via PATH wrapping. - # Also remove the man field since the man page is not included in the npm tarball. - ${jq}/bin/jq 'del(.dependencies["@vscode/ripgrep"]) | del(.man)' package.json > package.json.tmp - mv package.json.tmp package.json - ''; - - npmDepsHash = "sha256-oHo60ghR7A4SUT0cLmIe7glPDYBK3twJ0F71RKVrxQc="; - - dontNpmBuild = true; - - # Skip post-install scripts to be safe - npmFlags = ["--ignore-scripts"]; - - nativeBuildInputs = [makeWrapper jq]; - - # Provide ripgrep from nixpkgs since @vscode/ripgrep was removed - postInstall = '' - wrapProgram $out/bin/cline \ - --prefix PATH : ${lib.makeBinPath [ripgrep]} - ''; - - meta = with lib; { - description = "Autonomous coding agent CLI - capable of creating/editing files, running commands, using the browser, and more"; - homepage = "https://cline.bot"; - license = licenses.asl20; - mainProgram = "cline"; - }; -} diff --git a/modules/common-modules/pkgs/default.nix b/modules/common-modules/pkgs/default.nix index c1e5e80..2afc9f2 100644 --- a/modules/common-modules/pkgs/default.nix +++ b/modules/common-modules/pkgs/default.nix @@ -44,11 +44,5 @@ # Override h3 C library to version 4.3.0 h3 = pkgs.callPackage ./h3-c-lib.nix {}; }) - (final: prev: { - cline = pkgs.callPackage ./cline/default.nix {}; - }) - (final: prev: { - e621-downloader = pkgs.callPackage ./e621-downloader.nix {}; - }) ]; } diff --git a/modules/common-modules/pkgs/e621-downloader.nix b/modules/common-modules/pkgs/e621-downloader.nix deleted file mode 100644 index 3e7c546..0000000 --- a/modules/common-modules/pkgs/e621-downloader.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ - lib, - rustPlatform, - fetchFromGitHub, - pkg-config, - openssl, - ... -}: -rustPlatform.buildRustPackage rec { - pname = "e621-downloader"; - version = "1.7.2"; - - src = fetchFromGitHub { - owner = "McSib"; - repo = "e621_downloader"; - rev = version; - hash = "sha256-4z+PrCv8Mlp0VOJ5Akv1TXrJir1Ws/+45a6VCZGuCtk="; - }; - - cargoHash = "sha256-/yqNYjP7BuFQWilL2Ty+E5rd8qXj30twteptHx7cLRo="; - - nativeBuildInputs = [ - pkg-config - ]; - - buildInputs = [ - openssl - ]; - - meta = with lib; { - description = "E621 and E926 downloader made in Rust"; - homepage = "https://github.com/McSib/e621_downloader"; - license = licenses.asl20; - mainProgram = "e621_downloader"; - }; -} diff --git a/modules/common-modules/pkgs/gdx-liftoff.nix b/modules/common-modules/pkgs/gdx-liftoff.nix index da7d51f..d2e9424 100644 --- a/modules/common-modules/pkgs/gdx-liftoff.nix +++ b/modules/common-modules/pkgs/gdx-liftoff.nix @@ -4,12 +4,8 @@ makeWrapper, jdk, lib, + xorg, libGL, - libx11, - libxcursor, - libxext, - libxrandr, - libxxf86vm, ... }: stdenv.mkDerivation rec { @@ -28,11 +24,11 @@ stdenv.mkDerivation rec { runtimeDependencies = lib.makeLibraryPath [ # glfw libGL - libx11 - libxcursor - libxext - libxrandr - libxxf86vm + xorg.libX11 + xorg.libXcursor + xorg.libXext + xorg.libXrandr + xorg.libXxf86vm ]; installPhase = '' diff --git a/modules/home-manager-modules/impermanence.nix b/modules/home-manager-modules/impermanence.nix index e8b3ec4..6c75edd 100644 --- a/modules/home-manager-modules/impermanence.nix +++ b/modules/home-manager-modules/impermanence.nix @@ -12,29 +12,21 @@ in { type = lib.types.bool; default = true; }; - persistencePath = lib.mkOption { - type = lib.types.str; - default = - if osConfig.storage.generateBase - then "/persist/replicate/home" - else "/persist"; - description = "The base path for user home persistence. The impermanence module will automatically append the user's home directory path. Automatically adapts based on whether the system uses the new dataset layout or the legacy one."; - }; }; config = lib.mkMerge [ (lib.mkIf config.impermanence.enable { assertions = [ { - assertion = osConfig.storage.impermanence.enable; + assertion = osConfig.host.impermanence.enable; message = "impermanence can not be enabled for a user when it is not enabled for the system"; } ]; }) # If impermanence is not enabled for this user but system impermanence is enabled, # persist the entire home directory as fallback - (lib.mkIf (osConfig.storage.impermanence.enable && !cfg.enable && cfg.fallbackPersistence.enable) { - home.persistence."${cfg.persistencePath}" = { + (lib.mkIf (osConfig.host.impermanence.enable && !cfg.enable && cfg.fallbackPersistence.enable) { + home.persistence."/persist/home/${config.home.username}" = { directories = ["."]; allowOther = true; }; diff --git a/modules/home-manager-modules/openssh.nix b/modules/home-manager-modules/openssh.nix index 2f44957..afc98dd 100644 --- a/modules/home-manager-modules/openssh.nix +++ b/modules/home-manager-modules/openssh.nix @@ -52,9 +52,9 @@ addKeysToAgent = "confirm"; }; }; - # extraConfig = lib.strings.concatLines ( - # builtins.map (hostKey: "IdentityFile ~/.ssh/${hostKey.path}") config.programs.openssh.hostKeys - # ); + extraConfig = lib.strings.concatLines ( + builtins.map (hostKey: "IdentityFile ~/.ssh/${hostKey.path}") config.programs.openssh.hostKeys + ); }; systemd.user.services = builtins.listToAttrs ( @@ -96,7 +96,7 @@ } ) (lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { files = lib.lists.flatten ( builtins.map (hostKey: [".ssh/${hostKey.path}" ".ssh/${hostKey.path}.pub"]) config.programs.openssh.hostKeys ); diff --git a/modules/home-manager-modules/programs/android-studio.nix b/modules/home-manager-modules/programs/android-studio.nix deleted file mode 100644 index 8d1e28c..0000000 --- a/modules/home-manager-modules/programs/android-studio.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: { - options.programs.android-studio = { - enable = lib.mkEnableOption "enable android-studio"; - }; - - config = lib.mkIf config.programs.android-studio.enable (lib.mkMerge [ - { - home.packages = with pkgs; [ - android-studio - ]; - } - ( - lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { - directories = [ - "${config.xdg.configHome}/Google/AndroidStudio" - ".android" - ".gradle" - "${config.xdg.cacheHome}/Google/AndroidStudio" - ]; - }; - } - ) - ]); -} diff --git a/modules/home-manager-modules/programs/anki.nix b/modules/home-manager-modules/programs/anki.nix index dcabce8..c2f93ea 100644 --- a/modules/home-manager-modules/programs/anki.nix +++ b/modules/home-manager-modules/programs/anki.nix @@ -1,13 +1,15 @@ { lib, config, + osConfig, ... }: { - config = lib.mkIf (config.programs.anki.enable && config.impermanence.enable) { - home.persistence."${config.impermanence.persistencePath}" = { + config = lib.mkIf (config.programs.anki.enable && osConfig.host.impermanence.enable) { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ - ".local/share/Anki2" + "${config.xdg.dataHome}/Anki2/" ]; + allowOther = true; }; }; } diff --git a/modules/home-manager-modules/programs/bitwarden.nix b/modules/home-manager-modules/programs/bitwarden.nix index bbd2086..e305b6c 100644 --- a/modules/home-manager-modules/programs/bitwarden.nix +++ b/modules/home-manager-modules/programs/bitwarden.nix @@ -16,10 +16,11 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/Bitwarden" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/bruno.nix b/modules/home-manager-modules/programs/bruno.nix index 7bc64b6..8ad5e63 100644 --- a/modules/home-manager-modules/programs/bruno.nix +++ b/modules/home-manager-modules/programs/bruno.nix @@ -16,10 +16,11 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/bruno/" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/calibre.nix b/modules/home-manager-modules/programs/calibre.nix index 7174b43..dbe6e2b 100644 --- a/modules/home-manager-modules/programs/calibre.nix +++ b/modules/home-manager-modules/programs/calibre.nix @@ -4,6 +4,10 @@ config, ... }: { + options.programs.calibre = { + enable = lib.mkEnableOption "enable calibre"; + }; + config = lib.mkIf config.programs.calibre.enable (lib.mkMerge [ { home.packages = with pkgs; [ @@ -12,10 +16,11 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/calibre" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/davinci-resolve.nix b/modules/home-manager-modules/programs/davinci-resolve.nix index 5956578..6c4526f 100644 --- a/modules/home-manager-modules/programs/davinci-resolve.nix +++ b/modules/home-manager-modules/programs/davinci-resolve.nix @@ -16,11 +16,12 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.dataHome}/DaVinciResolve" "${config.xdg.configHome}/blackmagic" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/dbeaver.nix b/modules/home-manager-modules/programs/dbeaver.nix index 1595a02..8b6c41a 100644 --- a/modules/home-manager-modules/programs/dbeaver.nix +++ b/modules/home-manager-modules/programs/dbeaver.nix @@ -16,10 +16,11 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.dataHome}/DBeaverData/" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/default.nix b/modules/home-manager-modules/programs/default.nix index 044d076..e70cfc8 100644 --- a/modules/home-manager-modules/programs/default.nix +++ b/modules/home-manager-modules/programs/default.nix @@ -1,6 +1,5 @@ {...}: { imports = [ - ./android-studio.nix ./firefox.nix ./signal.nix ./bitwarden.nix @@ -14,7 +13,6 @@ ./prostudiomasters.nix ./idea.nix ./kdenlive.nix - ./kicad.nix ./krita.nix ./protonvpn.nix ./calibre.nix @@ -47,9 +45,5 @@ ./gdx-liftoff.nix ./tor-browser.nix ./vmware-workstation.nix - ./proton-mail-pwa.nix - ./proton-calendar-pwa.nix - ./matrix-cyberia-pwa.nix - ./e621-downloader.nix ]; } diff --git a/modules/home-manager-modules/programs/discord.nix b/modules/home-manager-modules/programs/discord.nix index e42367b..71b09b2 100644 --- a/modules/home-manager-modules/programs/discord.nix +++ b/modules/home-manager-modules/programs/discord.nix @@ -6,10 +6,11 @@ config = lib.mkIf config.programs.discord.enable (lib.mkMerge [ ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/discord/" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/e621-downloader.nix b/modules/home-manager-modules/programs/e621-downloader.nix deleted file mode 100644 index 2cb32a9..0000000 --- a/modules/home-manager-modules/programs/e621-downloader.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: { - options.programs.e621-downloader = { - enable = lib.mkEnableOption "enable e621-downloader"; - }; - - config = lib.mkIf config.programs.e621-downloader.enable { - home.packages = with pkgs; [ - e621-downloader - ]; - }; -} diff --git a/modules/home-manager-modules/programs/firefox.nix b/modules/home-manager-modules/programs/firefox.nix index 2756e31..8841887 100644 --- a/modules/home-manager-modules/programs/firefox.nix +++ b/modules/home-manager-modules/programs/firefox.nix @@ -22,10 +22,11 @@ # Extension configuration ".mozilla/firefox/${profile}/extension-settings.json" ]; + allowOther = true; }; in { config = lib.mkIf (config.programs.firefox.enable && config.impermanence.enable) { - home.persistence."${config.impermanence.persistencePath}" = lib.mkMerge ( + home.persistence."/persist${config.home.homeDirectory}" = lib.mkMerge ( ( lib.attrsets.mapAttrsToList (profile: _: buildProfilePersistence profile) diff --git a/modules/home-manager-modules/programs/freecad.nix b/modules/home-manager-modules/programs/freecad.nix index 50600db..89668de 100644 --- a/modules/home-manager-modules/programs/freecad.nix +++ b/modules/home-manager-modules/programs/freecad.nix @@ -16,10 +16,11 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/FreeCAD" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/gimp.nix b/modules/home-manager-modules/programs/gimp.nix index 95c87e6..925a2d9 100644 --- a/modules/home-manager-modules/programs/gimp.nix +++ b/modules/home-manager-modules/programs/gimp.nix @@ -16,10 +16,11 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/GIMP" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/idea.nix b/modules/home-manager-modules/programs/idea.nix index a1aebda..e59e7b2 100644 --- a/modules/home-manager-modules/programs/idea.nix +++ b/modules/home-manager-modules/programs/idea.nix @@ -4,19 +4,19 @@ config, ... }: { - options.programs.jetbrains.idea-oss = { - enable = lib.mkEnableOption "enable idea-oss"; + options.programs.jetbrains.idea-community = { + enable = lib.mkEnableOption "enable idea-community"; }; - config = lib.mkIf config.programs.jetbrains.idea-oss.enable (lib.mkMerge [ + config = lib.mkIf config.programs.jetbrains.idea-community.enable (lib.mkMerge [ { home.packages = with pkgs; [ - jetbrains.idea-oss + jetbrains.idea-community ]; } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ # configuration "${config.xdg.configHome}/JetBrains/" diff --git a/modules/home-manager-modules/programs/inkscape.nix b/modules/home-manager-modules/programs/inkscape.nix index 28eb334..a26ddec 100644 --- a/modules/home-manager-modules/programs/inkscape.nix +++ b/modules/home-manager-modules/programs/inkscape.nix @@ -16,10 +16,11 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/inkscape" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/kdenlive.nix b/modules/home-manager-modules/programs/kdenlive.nix index 2c4bac8..05327d1 100644 --- a/modules/home-manager-modules/programs/kdenlive.nix +++ b/modules/home-manager-modules/programs/kdenlive.nix @@ -23,11 +23,12 @@ in { } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/kdenliverc" "${config.xdg.dataHome}/kdenlive" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/kicad.nix b/modules/home-manager-modules/programs/kicad.nix deleted file mode 100644 index c2414c1..0000000 --- a/modules/home-manager-modules/programs/kicad.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: { - options.programs.kicad = { - enable = lib.mkEnableOption "enable kicad"; - }; - - config = lib.mkIf config.programs.kicad.enable (lib.mkMerge [ - { - home.packages = with pkgs; [ - kicad - ]; - } - ( - lib.mkIf config.impermanence.enable { - # TODO: - } - ) - ]); -} diff --git a/modules/home-manager-modules/programs/krita.nix b/modules/home-manager-modules/programs/krita.nix index dd7bb12..3ba5560 100644 --- a/modules/home-manager-modules/programs/krita.nix +++ b/modules/home-manager-modules/programs/krita.nix @@ -16,11 +16,12 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/kritarc" "${config.xdg.dataHome}/krita" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/libreoffice.nix b/modules/home-manager-modules/programs/libreoffice.nix index 283c8db..93163e7 100644 --- a/modules/home-manager-modules/programs/libreoffice.nix +++ b/modules/home-manager-modules/programs/libreoffice.nix @@ -16,10 +16,11 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/libreoffice" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/makemkv.nix b/modules/home-manager-modules/programs/makemkv.nix index f748f68..e92c3d3 100644 --- a/modules/home-manager-modules/programs/makemkv.nix +++ b/modules/home-manager-modules/programs/makemkv.nix @@ -30,7 +30,7 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ ".MakeMKV" ]; diff --git a/modules/home-manager-modules/programs/mapillary-uploader.nix b/modules/home-manager-modules/programs/mapillary-uploader.nix index 0d9ad5f..df1f093 100644 --- a/modules/home-manager-modules/programs/mapillary-uploader.nix +++ b/modules/home-manager-modules/programs/mapillary-uploader.nix @@ -17,11 +17,12 @@ in { } ( mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/mapillary-uploader" "${config.xdg.dataHome}/mapillary-uploader" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/matrix-cyberia-pwa.nix b/modules/home-manager-modules/programs/matrix-cyberia-pwa.nix deleted file mode 100644 index 644df92..0000000 --- a/modules/home-manager-modules/programs/matrix-cyberia-pwa.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: let - cfg = config.programs.matrix-cyberia-pwa; - isChromium = cfg.package == pkgs.chromium; - isBrowserImpermanenceSupported = cfg.package == pkgs.chromium; -in { - options.programs.matrix-cyberia-pwa = { - enable = lib.mkEnableOption "enable Matrix Cyberia PWA"; - package = lib.mkOption { - type = lib.types.package; - default = pkgs.chromium; - description = "Browser package to use for the PWA"; - }; - impermanence = { - enable = lib.mkOption { - type = lib.types.bool; - default = isBrowserImpermanenceSupported; - description = "Enable impermanence configuration for the PWA. Only automatically enabled when using chromium."; - }; - }; - }; - - config = lib.mkIf cfg.enable (lib.mkMerge [ - { - warnings = - lib.optional (config.impermanence.enable && !isBrowserImpermanenceSupported) - "matrix-cyberia-pwa: Using unsupported package. You will need to manually configure pwa for ${cfg.package.pname}. Supported package(s) ${pkgs.chromium.pname}"; - } - ( - lib.mkIf isChromium { - xdg.desktopEntries.matrix-cyberia-pwa = { - name = "Matrix (Cyberia)"; - type = "Application"; - exec = "${cfg.package}/bin/${cfg.package.pname} --app=https://chat.cyberia.club/"; - icon = "matrix"; - terminal = false; - categories = ["Network" "InstantMessaging"]; - }; - } - ) - ( - lib.mkIf (config.impermanence.enable && cfg.impermanence.enable && isChromium) { - home.persistence."/persist${config.home.homeDirectory}" = { - directories = [ - "${config.xdg.configHome}/chromium" - ]; - allowOther = true; - }; - } - ) - ]); -} diff --git a/modules/home-manager-modules/programs/obs.nix b/modules/home-manager-modules/programs/obs.nix index 0a4caf7..bfdba90 100644 --- a/modules/home-manager-modules/programs/obs.nix +++ b/modules/home-manager-modules/programs/obs.nix @@ -6,10 +6,11 @@ config = lib.mkIf config.programs.obs-studio.enable (lib.mkMerge [ ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/obs-studio" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/obsidian.nix b/modules/home-manager-modules/programs/obsidian.nix index 6676ecd..824563d 100644 --- a/modules/home-manager-modules/programs/obsidian.nix +++ b/modules/home-manager-modules/programs/obsidian.nix @@ -6,7 +6,7 @@ config = lib.mkIf config.programs.obsidian.enable (lib.mkMerge [ ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/obsidian" ]; diff --git a/modules/home-manager-modules/programs/olympus.nix b/modules/home-manager-modules/programs/olympus.nix index 2d5adb6..0e38eec 100644 --- a/modules/home-manager-modules/programs/olympus.nix +++ b/modules/home-manager-modules/programs/olympus.nix @@ -23,11 +23,12 @@ in { } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/olympus" "${config.xdg.dataHome}/olympus" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/openrgb.nix b/modules/home-manager-modules/programs/openrgb.nix index c350b1e..c9d5e14 100644 --- a/modules/home-manager-modules/programs/openrgb.nix +++ b/modules/home-manager-modules/programs/openrgb.nix @@ -16,10 +16,11 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/OpenRGB" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/picard.nix b/modules/home-manager-modules/programs/picard.nix index ffc4289..bc37b86 100644 --- a/modules/home-manager-modules/programs/picard.nix +++ b/modules/home-manager-modules/programs/picard.nix @@ -16,10 +16,11 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/MusicBrainz" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/prostudiomasters.nix b/modules/home-manager-modules/programs/prostudiomasters.nix index d61b7e5..5345169 100644 --- a/modules/home-manager-modules/programs/prostudiomasters.nix +++ b/modules/home-manager-modules/programs/prostudiomasters.nix @@ -16,7 +16,7 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/ProStudioMasters" ]; diff --git a/modules/home-manager-modules/programs/proton-calendar-pwa.nix b/modules/home-manager-modules/programs/proton-calendar-pwa.nix deleted file mode 100644 index 33796e2..0000000 --- a/modules/home-manager-modules/programs/proton-calendar-pwa.nix +++ /dev/null @@ -1,55 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: let - cfg = config.programs.proton-calendar-pwa; - isChromium = cfg.package == pkgs.chromium; - isBrowserImpermanenceSupported = cfg.package == pkgs.chromium; -in { - options.programs.proton-calendar-pwa = { - enable = lib.mkEnableOption "enable Proton Calendar PWA"; - package = lib.mkOption { - type = lib.types.package; - default = pkgs.chromium; - description = "Browser package to use for the PWA"; - }; - impermanence = { - enable = lib.mkOption { - type = lib.types.bool; - default = isBrowserImpermanenceSupported; - description = "Enable impermanence configuration for the PWA. Only automatically enabled when using chromium."; - }; - }; - }; - - config = lib.mkIf cfg.enable (lib.mkMerge [ - { - warnings = - lib.optional (config.impermanence.enable && !isBrowserImpermanenceSupported) - "proton-calendar-pwa: Using unsupported package. You will need to manually configure pwa for ${cfg.package.pname}. Supported package(s) ${pkgs.chromium.pname}"; - } - ( - lib.mkIf isChromium { - xdg.desktopEntries.proton-calendar-pwa = { - name = "Proton Calendar"; - type = "Application"; - exec = "${cfg.package}/bin/${cfg.package.pname} --app=https://calendar.proton.me"; - icon = "chrome-ojibjkjikcpjonjjngfkegflhmffeemk-Default"; - terminal = false; - }; - } - ) - ( - lib.mkIf (config.impermanence.enable && cfg.impermanence.enable && isChromium) { - home.persistence."/persist${config.home.homeDirectory}" = { - directories = [ - "${config.xdg.configHome}/chromium" - ]; - allowOther = true; - }; - } - ) - ]); -} diff --git a/modules/home-manager-modules/programs/proton-mail-pwa.nix b/modules/home-manager-modules/programs/proton-mail-pwa.nix deleted file mode 100644 index 3a3fe89..0000000 --- a/modules/home-manager-modules/programs/proton-mail-pwa.nix +++ /dev/null @@ -1,55 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: let - cfg = config.programs.proton-mail-pwa; - isChromium = cfg.package == pkgs.chromium; - isBrowserImpermanenceSupported = cfg.package == pkgs.chromium; -in { - options.programs.proton-mail-pwa = { - enable = lib.mkEnableOption "enable Proton Mail PWA"; - package = lib.mkOption { - type = lib.types.package; - default = pkgs.chromium; - description = "Browser package to use for the PWA"; - }; - impermanence = { - enable = lib.mkOption { - type = lib.types.bool; - default = isBrowserImpermanenceSupported; - description = "Enable impermanence configuration for the PWA. Only automatically enabled when using chromium."; - }; - }; - }; - - config = lib.mkIf cfg.enable (lib.mkMerge [ - { - warnings = - lib.optional (config.impermanence.enable && !isBrowserImpermanenceSupported) - "proton-mail-pwa: Using unsupported package. You will need to manually configure pwa for ${cfg.package.pname}. Supported package(s) ${pkgs.chromium.pname}"; - } - ( - lib.mkIf isChromium { - xdg.desktopEntries.proton-mail-pwa = { - name = "Proton Mail"; - type = "Application"; - exec = "${cfg.package}/bin/${cfg.package.pname} --app=https://mail.proton.me"; - icon = "chrome-jnpecgipniidlgicjocehkhajgdnjekh-Default"; - terminal = false; - }; - } - ) - ( - lib.mkIf (config.impermanence.enable && cfg.impermanence.enable && isChromium) { - home.persistence."/persist${config.home.homeDirectory}" = { - directories = [ - "${config.xdg.configHome}/chromium" - ]; - allowOther = true; - }; - } - ) - ]); -} diff --git a/modules/home-manager-modules/programs/protonvpn.nix b/modules/home-manager-modules/programs/protonvpn.nix index 5742948..513a610 100644 --- a/modules/home-manager-modules/programs/protonvpn.nix +++ b/modules/home-manager-modules/programs/protonvpn.nix @@ -16,7 +16,7 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/protonvpn" "${config.xdg.configHome}/Proton" diff --git a/modules/home-manager-modules/programs/qbittorrent.nix b/modules/home-manager-modules/programs/qbittorrent.nix index b2e0f50..61d13c0 100644 --- a/modules/home-manager-modules/programs/qbittorrent.nix +++ b/modules/home-manager-modules/programs/qbittorrent.nix @@ -16,7 +16,7 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/qBittorrent" ]; diff --git a/modules/home-manager-modules/programs/qflipper.nix b/modules/home-manager-modules/programs/qflipper.nix index bb141a4..8b42766 100644 --- a/modules/home-manager-modules/programs/qflipper.nix +++ b/modules/home-manager-modules/programs/qflipper.nix @@ -16,10 +16,11 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/qFlipper" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/signal.nix b/modules/home-manager-modules/programs/signal.nix index a50a49e..7db23a7 100644 --- a/modules/home-manager-modules/programs/signal.nix +++ b/modules/home-manager-modules/programs/signal.nix @@ -4,19 +4,19 @@ config, ... }: { - options.programs.signal-desktop = { + options.programs.signal-desktop-bin = { enable = lib.mkEnableOption "enable signal"; }; - config = lib.mkIf config.programs.signal-desktop.enable (lib.mkMerge [ + config = lib.mkIf config.programs.signal-desktop-bin.enable (lib.mkMerge [ { home.packages = with pkgs; [ - signal-desktop + signal-desktop-bin ]; } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/Signal" ]; diff --git a/modules/home-manager-modules/programs/steam.nix b/modules/home-manager-modules/programs/steam.nix index 4e0644e..fd98cb6 100644 --- a/modules/home-manager-modules/programs/steam.nix +++ b/modules/home-manager-modules/programs/steam.nix @@ -18,13 +18,14 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ { directory = "${config.xdg.dataHome}/Steam"; method = "symlink"; } ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/tor-browser.nix b/modules/home-manager-modules/programs/tor-browser.nix index c108805..c3b085d 100644 --- a/modules/home-manager-modules/programs/tor-browser.nix +++ b/modules/home-manager-modules/programs/tor-browser.nix @@ -16,10 +16,11 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.dataHome}/torbrowser" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/ungoogled-chromium.nix b/modules/home-manager-modules/programs/ungoogled-chromium.nix index 32f4b40..ef6a881 100644 --- a/modules/home-manager-modules/programs/ungoogled-chromium.nix +++ b/modules/home-manager-modules/programs/ungoogled-chromium.nix @@ -16,10 +16,11 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/chromium" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/via.nix b/modules/home-manager-modules/programs/via.nix index ad6f45a..0aa58e4 100644 --- a/modules/home-manager-modules/programs/via.nix +++ b/modules/home-manager-modules/programs/via.nix @@ -16,11 +16,12 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ "${config.xdg.configHome}/via" "${config.xdg.dataHome}/via" ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/vmware-workstation.nix b/modules/home-manager-modules/programs/vmware-workstation.nix index 76f260b..8e9d406 100644 --- a/modules/home-manager-modules/programs/vmware-workstation.nix +++ b/modules/home-manager-modules/programs/vmware-workstation.nix @@ -17,7 +17,7 @@ } ( lib.mkIf config.impermanence.enable { - home.persistence."${config.impermanence.persistencePath}" = { + home.persistence."/persist${config.home.homeDirectory}" = { directories = [ { directory = ".vmware"; @@ -28,6 +28,7 @@ method = "symlink"; } ]; + allowOther = true; }; } ) diff --git a/modules/home-manager-modules/programs/vscode/claudeDev.nix b/modules/home-manager-modules/programs/vscode/claudeDev.nix index c4d2dd7..ffeaff3 100644 --- a/modules/home-manager-modules/programs/vscode/claudeDev.nix +++ b/modules/home-manager-modules/programs/vscode/claudeDev.nix @@ -10,19 +10,6 @@ mcp-nixos = inputs.mcp-nixos.packages.${pkgs.stdenv.hostPlatform.system}.default; - anyProfileHasInstallTool = lib.any ( - profile: - profile.extraExtensions.claudeDev.enable - && profile.extraExtensions.claudeDev.installTool - ) (lib.attrValues config.programs.vscode.profiles); - - getInstallToolPackage = lib.findFirst (package: package != null) pkgs.cline (map ( - profile: - if profile.extraExtensions.claudeDev.enable && profile.extraExtensions.claudeDev.installTool - then profile.extraExtensions.claudeDev.package - else null - ) (lib.attrValues config.programs.vscode.profiles)); - anyProfileHasMcpNixos = lib.any ( profile: profile.extraExtensions.claudeDev.enable @@ -82,17 +69,6 @@ in { default = ["saoudrizwan" "claude-dev"]; }; - installTool = lib.mkOption { - type = lib.types.bool; - default = true; - description = "Whether to install the cline CLI tool for subagent support when the extension is enabled"; - }; - package = lib.mkOption { - type = lib.types.package; - default = pkgs.cline; - description = "The package to install for the cline CLI tool"; - }; - mcp = { nixos = { enable = lib.mkEnableOption "enable NixOS MCP server for Claude Dev"; @@ -169,12 +145,6 @@ in { }; config = lib.mkMerge [ - (lib.mkIf anyProfileHasInstallTool { - home.packages = [ - getInstallToolPackage - ]; - }) - (lib.mkIf anyProfileHasMcpNixos { home.packages = [ mcp-nixos diff --git a/modules/home-manager-modules/programs/vscode/default.nix b/modules/home-manager-modules/programs/vscode/default.nix index 6b7fbb9..f9d83dc 100644 --- a/modules/home-manager-modules/programs/vscode/default.nix +++ b/modules/home-manager-modules/programs/vscode/default.nix @@ -16,7 +16,6 @@ ./go.nix ./evenBetterToml.nix ./openRemoteSsh.nix - ./platformIO.nix ./rustAnalyzer.nix ./astroVscode.nix ./vscodeMdx.nix @@ -26,6 +25,5 @@ ./direnv.nix ./conventionalCommits.nix ./openDyslexicFont.nix - ./graphql.nix ]; } diff --git a/modules/home-manager-modules/programs/vscode/go.nix b/modules/home-manager-modules/programs/vscode/go.nix index bd9b771..02ffe5d 100644 --- a/modules/home-manager-modules/programs/vscode/go.nix +++ b/modules/home-manager-modules/programs/vscode/go.nix @@ -21,13 +21,6 @@ in { extensions = [ config.extraExtensions.go.extension ]; - userSettings = { - "go.alternateTools" = { - "gopls" = "gopls"; - }; - "go.toolsManagement.autoUpdate" = false; - "go.useLanguageServer" = true; - }; }; })); }; diff --git a/modules/home-manager-modules/programs/vscode/graphql.nix b/modules/home-manager-modules/programs/vscode/graphql.nix deleted file mode 100644 index fde08f3..0000000 --- a/modules/home-manager-modules/programs/vscode/graphql.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: let - pkgsRepositories = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version; - pkgsRepository = pkgsRepositories.open-vsx; -in { - options.programs.vscode.profiles = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule ({config, ...}: { - options = { - extraExtensions.graphql = { - enable = lib.mkEnableOption "should the graphql highlighting extension for vscode be enabled"; - extension = lib.mkPackageOption pkgsRepository "vscode-graphql" { - default = ["graphql" "vscode-graphql-syntax"]; - }; - }; - }; - config = lib.mkIf config.extraExtensions.graphql.enable { - extensions = [ - config.extraExtensions.graphql.extension - ]; - }; - })); - }; -} diff --git a/modules/home-manager-modules/programs/vscode/platformIO.nix b/modules/home-manager-modules/programs/vscode/platformIO.nix deleted file mode 100644 index ace83b7..0000000 --- a/modules/home-manager-modules/programs/vscode/platformIO.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ - lib, - pkgs, - config, - ... -}: let - pkgsRepositories = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version; - pkgsRepository = pkgsRepositories.open-vsx; -in { - options.programs.vscode.profiles = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule ({config, ...}: { - options = { - extraExtensions.platformIO = { - enable = lib.mkEnableOption "should the platformIO extension for vscode be enabled"; - extension = lib.mkPackageOption pkgsRepository "platformIO" { - default = ["pioarduino" "pioarduino-ide"]; - }; - }; - }; - config = lib.mkIf config.extraExtensions.platformIO.enable { - extensions = [ - config.extraExtensions.platformIO.extension - ]; - userSettings = { - "platformio-ide.useBuiltinPIOCore" = false; - }; - }; - })); - }; -} diff --git a/modules/nixos-modules/default.nix b/modules/nixos-modules/default.nix index 34e041e..2ba1a58 100644 --- a/modules/nixos-modules/default.nix +++ b/modules/nixos-modules/default.nix @@ -8,13 +8,14 @@ ./desktop.nix ./ssh.nix ./i18n.nix - ./sync - ./ollama + ./sync.nix + ./impermanence.nix + ./disko.nix + ./ollama.nix ./ai.nix - ./tailscale + ./tailscale.nix ./steam.nix ./server - ./storage ]; nixpkgs.config.permittedInsecurePackages = [ diff --git a/modules/nixos-modules/desktop.nix b/modules/nixos-modules/desktop.nix index 66a2433..6686ee3 100644 --- a/modules/nixos-modules/desktop.nix +++ b/modules/nixos-modules/desktop.nix @@ -47,9 +47,6 @@ # Get rid of xTerm desktopManager.xterm.enable = false; - excludePackages = with pkgs; [ - xterm - ]; }; # Enable the GNOME Desktop Environment. diff --git a/modules/nixos-modules/disko.nix b/modules/nixos-modules/disko.nix new file mode 100644 index 0000000..a962689 --- /dev/null +++ b/modules/nixos-modules/disko.nix @@ -0,0 +1,267 @@ +{ + lib, + pkgs, + config, + inputs, + ... +}: let + # there currently is a bug with disko that causes long disk names to be generated improperly this hash function should alleviate it when used for disk names instead of what we are defaulting to + # max gpt length is 36 and disk adds formats it like disk-xxxx-zfs which means we need to be 9 characters under that + hashDisk = drive: (builtins.substring 0 27 (builtins.hashString "sha256" drive)); + + vdevs = + builtins.map ( + disks: + builtins.map (disk: lib.attrsets.nameValuePair (hashDisk disk) disk) disks + ) + config.host.storage.pool.vdevs; + cache = + builtins.map ( + disk: lib.attrsets.nameValuePair (hashDisk disk) disk + ) + config.host.storage.pool.cache; + + datasets = config.host.storage.pool.datasets // config.host.storage.pool.extraDatasets; +in { + options.host.storage = { + enable = lib.mkEnableOption "are we going create zfs disks with disko on this device"; + encryption = lib.mkEnableOption "is the vdev going to be encrypted"; + notifications = { + enable = lib.mkEnableOption "are notifications enabled"; + host = lib.mkOption { + type = lib.types.str; + description = "what is the host that we are going to send the email to"; + }; + port = lib.mkOption { + type = lib.types.port; + description = "what port is the host using to receive mail on"; + }; + to = lib.mkOption { + type = lib.types.str; + description = "what account is the email going to be sent to"; + }; + user = lib.mkOption { + type = lib.types.str; + description = "what user is the email going to be set from"; + }; + tokenFile = lib.mkOption { + type = lib.types.str; + description = "file containing the password to be used by msmtp for notifications"; + }; + }; + pool = { + mode = lib.mkOption { + type = lib.types.str; + default = "raidz2"; + description = "what level of redundancy should this pool have"; + }; + # list of drives in pool that will have a boot partition put onto them + bootDrives = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "list of disks that are going to have a boot partition installed on them"; + default = lib.lists.flatten config.host.storage.pool.vdevs; + }; + # shorthand for vdevs if you only have 1 vdev + drives = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "list of drives that are going to be in the vdev"; + default = []; + }; + # list of all drives in each vdev + vdevs = lib.mkOption { + type = lib.types.listOf (lib.types.listOf lib.types.str); + description = "list of disks that are going to be in"; + default = [config.host.storage.pool.drives]; + }; + # list of cache drives for pool + cache = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "list of drives that are going to be used as cache"; + default = []; + }; + # Default datasets that are needed to make a functioning system + datasets = lib.mkOption { + type = lib.types.attrsOf (inputs.disko.lib.subType { + types = {inherit (inputs.disko.lib.types) zfs_fs zfs_volume;}; + }); + default = { + "local" = { + type = "zfs_fs"; + options.canmount = "off"; + }; + # nix directory needs to be available pre persist and doesn't need to be snapshotted or backed up + "local/system/nix" = { + type = "zfs_fs"; + mountpoint = "/nix"; + options = { + atime = "off"; + relatime = "off"; + canmount = "on"; + }; + }; + # dataset for root that gets rolled back on every boot + "local/system/root" = { + type = "zfs_fs"; + mountpoint = "/"; + options = { + canmount = "on"; + }; + postCreateHook = '' + zfs snapshot rpool/local/system/root@blank + ''; + }; + }; + }; + extraDatasets = lib.mkOption { + type = lib.types.attrsOf (inputs.disko.lib.subType { + types = {inherit (inputs.disko.lib.types) zfs_fs zfs_volume;}; + }); + description = "List of datasets to define"; + default = {}; + }; + }; + }; + + config = lib.mkIf config.host.storage.enable { + programs.msmtp = lib.mkIf config.host.storage.notifications.enable { + enable = true; + setSendmail = true; + defaults = { + aliases = "/etc/aliases"; + port = config.host.storage.notifications.port; + tls_trust_file = "/etc/ssl/certs/ca-certificates.crt"; + tls = "on"; + auth = "login"; + tls_starttls = "off"; + }; + accounts = { + zfs_notifications = { + auth = true; + tls = true; + host = config.host.storage.notifications.host; + passwordeval = "cat ${config.host.storage.notifications.tokenFile}"; + user = config.host.storage.notifications.user; + from = config.host.storage.notifications.user; + }; + }; + }; + + services.zfs = { + autoScrub.enable = true; + autoSnapshot.enable = true; + + zed = lib.mkIf config.host.storage.notifications.enable { + enableMail = true; + + settings = { + ZED_DEBUG_LOG = "/tmp/zed.debug.log"; + ZED_EMAIL_ADDR = [config.host.storage.notifications.to]; + ZED_EMAIL_PROG = "${pkgs.msmtp}/bin/msmtp"; + ZED_EMAIL_OPTS = "-a zfs_notifications @ADDRESS@"; + + ZED_NOTIFY_INTERVAL_SECS = 3600; + ZED_NOTIFY_VERBOSE = true; + + ZED_USE_ENCLOSURE_LEDS = true; + ZED_SCRUB_AFTER_RESILVER = true; + }; + }; + }; + + disko.devices = { + disk = ( + builtins.listToAttrs ( + builtins.map + (drive: + lib.attrsets.nameValuePair (drive.name) { + type = "disk"; + device = "/dev/disk/by-id/${drive.value}"; + content = { + type = "gpt"; + partitions = { + ESP = lib.mkIf (builtins.elem drive.value config.host.storage.pool.bootDrives) { + # The 2GB here for the boot partition might be a bit overkill we probably only need like 1/4th of that but storage is cheap + size = "2G"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = ["umask=0077"]; + }; + }; + zfs = { + size = "100%"; + content = { + type = "zfs"; + pool = "rpool"; + }; + }; + }; + }; + }) + ( + (lib.lists.flatten vdevs) ++ cache + ) + ) + ); + zpool = { + rpool = { + type = "zpool"; + mode = { + topology = { + type = "topology"; + vdev = ( + builtins.map (disks: { + mode = config.host.storage.pool.mode; + members = + builtins.map (disk: disk.name) disks; + }) + vdevs + ); + cache = builtins.map (disk: disk.name) cache; + }; + }; + + options = { + ashift = "12"; + autotrim = "on"; + }; + + rootFsOptions = + { + canmount = "off"; + mountpoint = "none"; + + xattr = "sa"; + acltype = "posixacl"; + relatime = "on"; + + compression = "lz4"; + + "com.sun:auto-snapshot" = "false"; + } + // ( + lib.attrsets.optionalAttrs config.host.storage.encryption { + encryption = "on"; + keyformat = "hex"; + keylocation = "prompt"; + } + ); + + datasets = lib.mkMerge [ + ( + lib.attrsets.mapAttrs (name: value: { + type = value.type; + options = value.options; + mountpoint = value.mountpoint; + postCreateHook = value.postCreateHook; + }) + datasets + ) + ]; + }; + }; + }; + }; +} diff --git a/modules/nixos-modules/impermanence.nix b/modules/nixos-modules/impermanence.nix new file mode 100644 index 0000000..60011cb --- /dev/null +++ b/modules/nixos-modules/impermanence.nix @@ -0,0 +1,134 @@ +{ + config, + lib, + ... +}: { + # options.storage = { + # zfs = { + # # TODO: enable option + # # when this option is enabled we need to configure and enable disko things + + # # TODO: we need some way of managing notifications + + # # TODO: we need options to configure zfs pools + # # we should have warnings when the configured pool is missing drives + + # # TODO: dataset option that is a submodule that adds datasets to the system + # # warnings for when a dataset was created in the past on a system but it is now missing some of the options defined for it + + # # TODO: pools and datasets need to be passed to disko + # }; + + # impermanence = { + # # TODO: enable option + + # # TODO: datasets option that is a submodule that will be used to define what datasets to add to the storage system + # # We should by default create the `local`, `local/system/nix`, `local/system/root`, `persist` `persist/system/root`, and `persist/system/var/log` datasets + # # Then we should make a dataset for user folders local and persist + # # We should also create datasets for systemd modules that have have impermanence enabled for them + # # we need to figure out what options a dataset can have in zfs + # }; + + # # TODO: we should have an impermanence module for home manager that proxies its values namespaced to the user down here that matches the same interface + + # # TODO: we should have a way of enabling impermanence for a systemd config + # # these should have an option to put their folder into their own dataset (this needs to support private vs non private) + # # options for features that can be added to the dataset + # }; + + options.host.impermanence.enable = lib.mkEnableOption "are we going to use impermanence on this device"; + + config = lib.mkMerge [ + { + assertions = [ + { + assertion = !(config.host.impermanence.enable && !config.host.storage.enable); + message = '' + Disko storage must be enabled to use impermanence. + ''; + } + ]; + } + ( + lib.mkIf config.host.impermanence.enable { + assertions = [ + { + assertion = config.host.impermanence.enable && config.host.storage.enable; + message = "Impermanence can not be used without managed host storage."; + } + ]; + + # fixes issues with /var/lib/private not having the correct permissions https://github.com/nix-community/impermanence/issues/254 + system.activationScripts."createPersistentStorageDirs".deps = ["var-lib-private-permissions" "users" "groups"]; + system.activationScripts = { + "var-lib-private-permissions" = { + deps = ["specialfs"]; + text = '' + mkdir -p /persist/system/root/var/lib/private + chmod 0700 /persist/system/root/var/lib/private + ''; + }; + }; + + programs.fuse.userAllowOther = true; + + boot.initrd.postResumeCommands = lib.mkAfter '' + zfs rollback -r rpool/local/system/root@blank + ''; + + fileSystems = { + "/".neededForBoot = true; + "/persist/system/root".neededForBoot = true; + "/persist/system/var/log".neededForBoot = true; + }; + + host.storage.pool.extraDatasets = { + # persist datasets are datasets that contain information that we would like to keep around + "persist" = { + type = "zfs_fs"; + options.canmount = "off"; + options = { + "com.sun:auto-snapshot" = "true"; + }; + }; + # this is where root data actually lives + "persist/system/root" = { + type = "zfs_fs"; + mountpoint = "/persist/system/root"; + }; + "persist/system/var/log" = { + type = "zfs_fs"; + mountpoint = "/persist/system/var/log"; + # logs should be append only so we shouldn't need to snapshot them + options = { + "com.sun:auto-snapshot" = "false"; + }; + }; + }; + + environment.persistence."/persist/system/var/log" = { + enable = true; + hideMounts = true; + directories = [ + "/var/log" + ]; + }; + + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + "/var/lib/nixos" + "/var/lib/systemd/coredump" + ]; + files = [ + "/etc/machine-id" + ]; + }; + + # TODO: this should live in leylas home manager configuration + security.sudo.extraConfig = "Defaults lecture=never"; + } + ) + ]; +} diff --git a/modules/nixos-modules/ollama/ollama.nix b/modules/nixos-modules/ollama.nix similarity index 63% rename from modules/nixos-modules/ollama/ollama.nix rename to modules/nixos-modules/ollama.nix index dc7cdd9..99819bf 100644 --- a/modules/nixos-modules/ollama/ollama.nix +++ b/modules/nixos-modules/ollama.nix @@ -27,6 +27,20 @@ allowedUDPPorts = ports; }; })) + (lib.mkIf config.host.impermanence.enable { + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = "/var/lib/private/ollama"; + user = config.services.ollama.user; + group = config.services.ollama.group; + mode = "0700"; + } + ]; + }; + }) ] ); } diff --git a/modules/nixos-modules/ollama/default.nix b/modules/nixos-modules/ollama/default.nix deleted file mode 100644 index 896526a..0000000 --- a/modules/nixos-modules/ollama/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -{...}: { - imports = [ - ./ollama.nix - ./storage.nix - ]; -} diff --git a/modules/nixos-modules/ollama/storage.nix b/modules/nixos-modules/ollama/storage.nix deleted file mode 100644 index 6ab0fc8..0000000 --- a/modules/nixos-modules/ollama/storage.nix +++ /dev/null @@ -1,37 +0,0 @@ -{ - config, - lib, - ... -}: { - options = { - services.ollama.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.ollama.enable && config.storage.impermanence.enable; - }; - }; - - config = lib.mkIf (config.services.ollama.enable) { - storage.datasets.replicate."system/root" = { - directories."/var/lib/private/ollama" = lib.mkIf config.services.ollama.impermanence.enable { - enable = true; - owner.name = config.services.ollama.user; - group.name = config.services.ollama.group; - owner.permissions = { - read = true; - write = true; - execute = false; - }; - group.permissions = { - read = false; - write = false; - execute = false; - }; - other.permissions = { - read = false; - write = false; - execute = false; - }; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/actual/default.nix b/modules/nixos-modules/server/actual/default.nix index 99778af..b59517b 100644 --- a/modules/nixos-modules/server/actual/default.nix +++ b/modules/nixos-modules/server/actual/default.nix @@ -3,6 +3,6 @@ ./actual.nix ./proxy.nix ./fail2ban.nix - ./storage.nix + ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/actual/impermanence.nix b/modules/nixos-modules/server/actual/impermanence.nix new file mode 100644 index 0000000..d870789 --- /dev/null +++ b/modules/nixos-modules/server/actual/impermanence.nix @@ -0,0 +1,37 @@ +{ + lib, + config, + ... +}: let + const = import ./const.nix; + dataDirectory = const.dataDirectory; +in { + options.services.actual = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.actual.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.actual.impermanence.enable { + assertions = [ + { + assertion = config.services.actual.settings.dataDir == dataDirectory; + message = "actual data location does not match persistence\nconfig directory: ${config.services.actual.settings.dataDir}\npersistence directory: ${dataDirectory}"; + } + { + assertion = config.systemd.services.actual.serviceConfig.DynamicUser or false; + message = "actual systemd service must have DynamicUser enabled to use private directory"; + } + ]; + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = dataDirectory; + user = "actual"; + group = "actual"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/actual/storage.nix b/modules/nixos-modules/server/actual/storage.nix deleted file mode 100644 index d6b904e..0000000 --- a/modules/nixos-modules/server/actual/storage.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ - lib, - config, - ... -}: let - const = import ./const.nix; - dataDirectory = const.dataDirectory; -in { - options.services.actual.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.actual.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.actual.enable { - storage.datasets.replicate."system/root" = { - directories."${dataDirectory}" = lib.mkIf config.services.actual.impermanence.enable { - owner.name = "actual"; - group.name = "actual"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/bazarr/default.nix b/modules/nixos-modules/server/bazarr/default.nix index cb2a5f0..86dbb4b 100644 --- a/modules/nixos-modules/server/bazarr/default.nix +++ b/modules/nixos-modules/server/bazarr/default.nix @@ -1,5 +1,5 @@ {...}: { imports = [ - ./storage.nix + ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/bazarr/impermanence.nix b/modules/nixos-modules/server/bazarr/impermanence.nix new file mode 100644 index 0000000..70a45d1 --- /dev/null +++ b/modules/nixos-modules/server/bazarr/impermanence.nix @@ -0,0 +1,33 @@ +{ + lib, + config, + ... +}: let + bazarr_data_directory = "/var/lib/bazarr"; +in { + options.services.bazarr = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.bazarr.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.bazarr.impermanence.enable { + assertions = [ + { + assertion = config.services.bazarr.dataDir == bazarr_data_directory; + message = "bazarr data directory does not match persistence"; + } + ]; + + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = bazarr_data_directory; + user = "bazarr"; + group = "bazarr"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/bazarr/storage.nix b/modules/nixos-modules/server/bazarr/storage.nix deleted file mode 100644 index a243d4c..0000000 --- a/modules/nixos-modules/server/bazarr/storage.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - lib, - config, - ... -}: let - bazarr_data_directory = "/var/lib/bazarr"; -in { - options.services.bazarr.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.bazarr.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.bazarr.enable { - storage.datasets.replicate."system/root" = { - directories."${bazarr_data_directory}" = lib.mkIf config.services.bazarr.impermanence.enable { - owner.name = "bazarr"; - group.name = "bazarr"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/crab-hole/default.nix b/modules/nixos-modules/server/crab-hole/default.nix index 9f990c5..158a851 100644 --- a/modules/nixos-modules/server/crab-hole/default.nix +++ b/modules/nixos-modules/server/crab-hole/default.nix @@ -1,6 +1,6 @@ {...}: { imports = [ ./crab-hole.nix - ./storage.nix + ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/crab-hole/impermanence.nix b/modules/nixos-modules/server/crab-hole/impermanence.nix new file mode 100644 index 0000000..51efc0c --- /dev/null +++ b/modules/nixos-modules/server/crab-hole/impermanence.nix @@ -0,0 +1,33 @@ +{ + lib, + config, + ... +}: let + workingDirectory = "/var/lib/private/crab-hole"; +in { + options.services.crab-hole = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.crab-hole.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.crab-hole.impermanence.enable { + assertions = [ + { + assertion = + config.systemd.services.crab-hole.serviceConfig.WorkingDirectory == (builtins.replaceStrings ["/private"] [""] workingDirectory); + message = "crab-hole working directory does not match persistence"; + } + ]; + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = workingDirectory; + user = "crab-hole"; + group = "crab-hole"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/crab-hole/storage.nix b/modules/nixos-modules/server/crab-hole/storage.nix deleted file mode 100644 index 827fb25..0000000 --- a/modules/nixos-modules/server/crab-hole/storage.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - lib, - config, - ... -}: let - workingDirectory = "/var/lib/private/crab-hole"; -in { - options.services.crab-hole.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.crab-hole.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.crab-hole.enable { - storage.datasets.replicate."system/root" = { - directories."${workingDirectory}" = lib.mkIf config.services.crab-hole.impermanence.enable { - owner.name = "crab-hole"; - group.name = "crab-hole"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/fail2ban/default.nix b/modules/nixos-modules/server/fail2ban/default.nix index 84a46d4..30fca99 100644 --- a/modules/nixos-modules/server/fail2ban/default.nix +++ b/modules/nixos-modules/server/fail2ban/default.nix @@ -1,6 +1,6 @@ {...}: { imports = [ ./fail2ban.nix - ./storage.nix + ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/fail2ban/impermanence.nix b/modules/nixos-modules/server/fail2ban/impermanence.nix new file mode 100644 index 0000000..6e214b3 --- /dev/null +++ b/modules/nixos-modules/server/fail2ban/impermanence.nix @@ -0,0 +1,34 @@ +{ + lib, + config, + ... +}: let + dataFolder = "/var/lib/fail2ban"; + dataFile = "fail2ban.sqlite3"; +in { + options.services.fail2ban = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.fail2ban.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.fail2ban.impermanence.enable { + assertions = [ + { + assertion = config.services.fail2ban.daemonSettings.Definition.dbfile == "${dataFolder}/${dataFile}"; + message = "fail2ban data file does not match persistence"; + } + ]; + + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = dataFolder; + user = "fail2ban"; + group = "fail2ban"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/fail2ban/storage.nix b/modules/nixos-modules/server/fail2ban/storage.nix deleted file mode 100644 index 1ef02c7..0000000 --- a/modules/nixos-modules/server/fail2ban/storage.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ - lib, - config, - ... -}: let - dataFolder = "/var/lib/fail2ban"; - dataFile = "fail2ban.sqlite3"; -in { - options.services.fail2ban.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.fail2ban.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.fail2ban.enable { - storage.datasets.replicate."system/root" = { - directories."${dataFolder}" = lib.mkIf config.services.fail2ban.impermanence.enable { - owner.name = "fail2ban"; - group.name = "fail2ban"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/flaresolverr/default.nix b/modules/nixos-modules/server/flaresolverr/default.nix index cb2a5f0..86dbb4b 100644 --- a/modules/nixos-modules/server/flaresolverr/default.nix +++ b/modules/nixos-modules/server/flaresolverr/default.nix @@ -1,5 +1,5 @@ {...}: { imports = [ - ./storage.nix + ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/flaresolverr/impermanence.nix b/modules/nixos-modules/server/flaresolverr/impermanence.nix new file mode 100644 index 0000000..4544e75 --- /dev/null +++ b/modules/nixos-modules/server/flaresolverr/impermanence.nix @@ -0,0 +1,26 @@ +{ + lib, + config, + ... +}: { + options.services.flaresolverr = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.flaresolverr.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.flaresolverr.impermanence.enable { + # FlareSolverr typically doesn't need persistent storage as it's a proxy service + # but we'll add basic structure in case it's needed for logs or configuration + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = "/var/lib/flaresolverr"; + user = "flaresolverr"; + group = "flaresolverr"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/flaresolverr/storage.nix b/modules/nixos-modules/server/flaresolverr/storage.nix deleted file mode 100644 index 919318c..0000000 --- a/modules/nixos-modules/server/flaresolverr/storage.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - lib, - config, - ... -}: { - options.services.flaresolverr.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.flaresolverr.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.flaresolverr.enable { - storage.datasets.replicate."system/root" = { - directories."/var/lib/flaresolverr" = lib.mkIf config.services.flaresolverr.impermanence.enable { - owner.name = "flaresolverr"; - group.name = "flaresolverr"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/forgejo/default.nix b/modules/nixos-modules/server/forgejo/default.nix index c990e57..4333f69 100644 --- a/modules/nixos-modules/server/forgejo/default.nix +++ b/modules/nixos-modules/server/forgejo/default.nix @@ -4,6 +4,6 @@ ./proxy.nix ./database.nix ./fail2ban.nix - ./storage.nix + ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/forgejo/impermanence.nix b/modules/nixos-modules/server/forgejo/impermanence.nix new file mode 100644 index 0000000..6fe3de8 --- /dev/null +++ b/modules/nixos-modules/server/forgejo/impermanence.nix @@ -0,0 +1,35 @@ +{ + lib, + config, + ... +}: let + stateDir = "/var/lib/forgejo"; +in { + options.services.forgejo = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.forgejo.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.forgejo.impermanence.enable { + assertions = [ + { + assertion = config.services.forgejo.stateDir == stateDir; + message = "forgejo state directory does not match persistence"; + } + ]; + + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = stateDir; + user = "forgejo"; + group = "forgejo"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/forgejo/storage.nix b/modules/nixos-modules/server/forgejo/storage.nix deleted file mode 100644 index da30ed9..0000000 --- a/modules/nixos-modules/server/forgejo/storage.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - lib, - config, - ... -}: let - stateDir = "/var/lib/forgejo"; -in { - options.services.forgejo.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.forgejo.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.forgejo.enable { - storage.datasets.replicate."system/root" = { - directories."${stateDir}" = lib.mkIf config.services.forgejo.impermanence.enable { - owner.name = "forgejo"; - group.name = "forgejo"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/home-assistant/default.nix b/modules/nixos-modules/server/home-assistant/default.nix index d213964..b6f9356 100644 --- a/modules/nixos-modules/server/home-assistant/default.nix +++ b/modules/nixos-modules/server/home-assistant/default.nix @@ -4,7 +4,7 @@ ./proxy.nix ./database.nix ./fail2ban.nix - ./storage.nix + ./impermanence.nix ./extensions ]; } diff --git a/modules/nixos-modules/server/home-assistant/impermanence.nix b/modules/nixos-modules/server/home-assistant/impermanence.nix new file mode 100644 index 0000000..8c056a1 --- /dev/null +++ b/modules/nixos-modules/server/home-assistant/impermanence.nix @@ -0,0 +1,26 @@ +{ + lib, + config, + ... +}: let + configDir = "/var/lib/hass"; +in + lib.mkIf (config.host.impermanence.enable && config.services.home-assistant.enable) { + assertions = [ + { + assertion = config.services.home-assistant.configDir == configDir; + message = "home assistant config directory does not match persistence"; + } + ]; + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = configDir; + user = "hass"; + group = "hass"; + } + ]; + }; + } diff --git a/modules/nixos-modules/server/home-assistant/storage.nix b/modules/nixos-modules/server/home-assistant/storage.nix deleted file mode 100644 index 60e5085..0000000 --- a/modules/nixos-modules/server/home-assistant/storage.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - lib, - config, - ... -}: let - configDir = "/var/lib/hass"; -in { - options.services.home-assistant.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.home-assistant.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.home-assistant.enable { - storage.datasets.replicate."system/root" = { - directories."${configDir}" = lib.mkIf config.services.home-assistant.impermanence.enable { - owner.name = "hass"; - group.name = "hass"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/immich/default.nix b/modules/nixos-modules/server/immich/default.nix index 75ae2fd..4d93c0b 100644 --- a/modules/nixos-modules/server/immich/default.nix +++ b/modules/nixos-modules/server/immich/default.nix @@ -3,7 +3,7 @@ ./proxy.nix ./database.nix ./fail2ban.nix - ./storage.nix + ./impermanence.nix ]; # NOTE: This shouldn't be needed now that we are out of testing diff --git a/modules/nixos-modules/server/immich/impermanence.nix b/modules/nixos-modules/server/immich/impermanence.nix new file mode 100644 index 0000000..56e51d0 --- /dev/null +++ b/modules/nixos-modules/server/immich/impermanence.nix @@ -0,0 +1,32 @@ +{ + lib, + config, + ... +}: let + mediaLocation = "/var/lib/immich"; +in { + options.services.immich = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.immich.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.immich.impermanence.enable { + assertions = [ + { + assertion = config.services.immich.mediaLocation == mediaLocation; + message = "immich media location does not match persistence"; + } + ]; + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = mediaLocation; + user = "immich"; + group = "immich"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/immich/storage.nix b/modules/nixos-modules/server/immich/storage.nix deleted file mode 100644 index de24329..0000000 --- a/modules/nixos-modules/server/immich/storage.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - lib, - config, - ... -}: let - mediaLocation = "/var/lib/immich"; -in { - options.services.immich.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.immich.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.immich.enable { - storage.datasets.replicate."system/root" = { - directories."${mediaLocation}" = lib.mkIf config.services.immich.impermanence.enable { - owner.name = "immich"; - group.name = "immich"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/jackett/default.nix b/modules/nixos-modules/server/jackett/default.nix index 5043814..86dbb4b 100644 --- a/modules/nixos-modules/server/jackett/default.nix +++ b/modules/nixos-modules/server/jackett/default.nix @@ -1,17 +1,5 @@ {...}: { imports = [ - ./storage.nix + ./impermanence.nix ]; - - config = { - nixpkgs.overlays = [ - # Disable jackett tests due to date-related test failures - # (ParseDateTimeGoLangTest expects 2024-09-14 but gets 2025-09-14 due to year rollover logic) - (final: prev: { - jackett = prev.jackett.overrideAttrs (oldAttrs: { - doCheck = false; - }); - }) - ]; - }; } diff --git a/modules/nixos-modules/server/jackett/impermanence.nix b/modules/nixos-modules/server/jackett/impermanence.nix new file mode 100644 index 0000000..24fc5e6 --- /dev/null +++ b/modules/nixos-modules/server/jackett/impermanence.nix @@ -0,0 +1,33 @@ +{ + lib, + config, + ... +}: let + jackett_data_directory = "/var/lib/jackett/.config/Jackett"; +in { + options.services.jackett = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.jackett.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.jackett.impermanence.enable { + assertions = [ + { + assertion = config.services.jackett.dataDir == jackett_data_directory; + message = "jackett data directory does not match persistence"; + } + ]; + + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = jackett_data_directory; + user = "jackett"; + group = "jackett"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/jackett/storage.nix b/modules/nixos-modules/server/jackett/storage.nix deleted file mode 100644 index 5f202e6..0000000 --- a/modules/nixos-modules/server/jackett/storage.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - lib, - config, - ... -}: let - jackett_data_directory = "/var/lib/jackett/.config/Jackett"; -in { - options.services.jackett.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.jackett.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.jackett.enable { - storage.datasets.replicate."system/root" = { - directories."${jackett_data_directory}" = lib.mkIf config.services.jackett.impermanence.enable { - owner.name = "jackett"; - group.name = "jackett"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/jellyfin/default.nix b/modules/nixos-modules/server/jellyfin/default.nix index 4770ae1..2dbdcfd 100644 --- a/modules/nixos-modules/server/jellyfin/default.nix +++ b/modules/nixos-modules/server/jellyfin/default.nix @@ -3,6 +3,6 @@ ./jellyfin.nix ./proxy.nix ./fail2ban.nix - ./storage.nix + ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/jellyfin/impermanence.nix b/modules/nixos-modules/server/jellyfin/impermanence.nix new file mode 100644 index 0000000..cbcb54f --- /dev/null +++ b/modules/nixos-modules/server/jellyfin/impermanence.nix @@ -0,0 +1,73 @@ +{ + lib, + config, + ... +}: let + jellyfin_data_directory = "/var/lib/jellyfin"; + jellyfin_cache_directory = "/var/cache/jellyfin"; +in { + options.services.jellyfin = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.jellyfin.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.jellyfin.impermanence.enable { + fileSystems."/persist/system/jellyfin".neededForBoot = true; + + host.storage.pool.extraDatasets = { + # sops age key needs to be available to pre persist for user generation + "persist/system/jellyfin" = { + type = "zfs_fs"; + mountpoint = "/persist/system/jellyfin"; + options = { + atime = "off"; + relatime = "off"; + canmount = "on"; + }; + }; + }; + + assertions = [ + { + assertion = config.services.jellyfin.dataDir == jellyfin_data_directory; + message = "jellyfin data directory does not match persistence"; + } + { + assertion = config.services.jellyfin.cacheDir == jellyfin_cache_directory; + message = "jellyfin cache directory does not match persistence"; + } + ]; + + environment.persistence = { + "/persist/system/root" = { + directories = [ + { + directory = jellyfin_data_directory; + user = "jellyfin"; + group = "jellyfin"; + } + { + directory = jellyfin_cache_directory; + user = "jellyfin"; + group = "jellyfin"; + } + ]; + }; + + "/persist/system/jellyfin" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = config.services.jellyfin.media_directory; + user = "jellyfin"; + group = "jellyfin_media"; + mode = "1770"; + } + ]; + }; + }; + }; +} diff --git a/modules/nixos-modules/server/jellyfin/storage.nix b/modules/nixos-modules/server/jellyfin/storage.nix deleted file mode 100644 index 5cff3e8..0000000 --- a/modules/nixos-modules/server/jellyfin/storage.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ - lib, - config, - ... -}: let - jellyfin_data_directory = "/var/lib/jellyfin"; - jellyfin_cache_directory = "/var/cache/jellyfin"; -in { - options.services.jellyfin.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.jellyfin.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.jellyfin.enable { - storage.datasets.replicate = { - "system/root" = { - directories = { - "${jellyfin_data_directory}" = lib.mkIf config.services.jellyfin.impermanence.enable { - enable = true; - owner.name = "jellyfin"; - group.name = "jellyfin"; - }; - "${jellyfin_cache_directory}" = lib.mkIf config.services.jellyfin.impermanence.enable { - enable = true; - owner.name = "jellyfin"; - group.name = "jellyfin"; - }; - }; - }; - "system/media" = { - mount = "/persist/replicate/system/media"; - - directories."${config.services.jellyfin.media_directory}" = lib.mkIf config.services.jellyfin.impermanence.enable { - enable = true; - owner.name = "jellyfin"; - group.name = "jellyfin_media"; - owner.permissions = { - read = true; - write = true; - execute = true; - }; - group.permissions = { - read = true; - write = true; - execute = true; - }; - other.permissions = { - read = false; - write = false; - execute = false; - }; - }; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/lidarr/default.nix b/modules/nixos-modules/server/lidarr/default.nix index cb2a5f0..86dbb4b 100644 --- a/modules/nixos-modules/server/lidarr/default.nix +++ b/modules/nixos-modules/server/lidarr/default.nix @@ -1,5 +1,5 @@ {...}: { imports = [ - ./storage.nix + ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/lidarr/impermanence.nix b/modules/nixos-modules/server/lidarr/impermanence.nix new file mode 100644 index 0000000..5d3aa3f --- /dev/null +++ b/modules/nixos-modules/server/lidarr/impermanence.nix @@ -0,0 +1,33 @@ +{ + lib, + config, + ... +}: let + lidarr_data_directory = "/var/lib/lidarr/.config/Lidarr"; +in { + options.services.lidarr = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.lidarr.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.lidarr.impermanence.enable { + assertions = [ + { + assertion = config.services.lidarr.dataDir == lidarr_data_directory; + message = "lidarr data directory does not match persistence"; + } + ]; + + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = lidarr_data_directory; + user = "lidarr"; + group = "lidarr"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/lidarr/storage.nix b/modules/nixos-modules/server/lidarr/storage.nix deleted file mode 100644 index c4c020e..0000000 --- a/modules/nixos-modules/server/lidarr/storage.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - lib, - config, - ... -}: let - lidarr_data_directory = "/var/lib/lidarr/.config/Lidarr"; -in { - options.services.lidarr.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.lidarr.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.lidarr.enable { - storage.datasets.replicate."system/root" = { - directories."${lidarr_data_directory}" = lib.mkIf config.services.lidarr.impermanence.enable { - owner.name = "lidarr"; - group.name = "lidarr"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/network_storage/network_storage.nix b/modules/nixos-modules/server/network_storage/network_storage.nix index b9d0446..ebc3bee 100644 --- a/modules/nixos-modules/server/network_storage/network_storage.nix +++ b/modules/nixos-modules/server/network_storage/network_storage.nix @@ -74,7 +74,7 @@ in { ); } # (lib.mkIf config.host.impermanence.enable { - # environment.persistence."/persist/replicate/system/root" = { + # environment.persistence."/persist/system/root" = { # enable = true; # hideMounts = true; # directories = [ diff --git a/modules/nixos-modules/server/panoramax/default.nix b/modules/nixos-modules/server/panoramax/default.nix index f5a514f..4c6b9ea 100644 --- a/modules/nixos-modules/server/panoramax/default.nix +++ b/modules/nixos-modules/server/panoramax/default.nix @@ -2,7 +2,7 @@ imports = [ ./proxy.nix ./fail2ban.nix - ./storage.nix + ./impermanence.nix ./panoramax.nix ./database.nix ]; diff --git a/modules/nixos-modules/server/panoramax/impermanence.nix b/modules/nixos-modules/server/panoramax/impermanence.nix new file mode 100644 index 0000000..e25ef92 --- /dev/null +++ b/modules/nixos-modules/server/panoramax/impermanence.nix @@ -0,0 +1,20 @@ +{ + lib, + config, + ... +}: { + options.services.panoramax = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.panoramax.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.panoramax.impermanence.enable { + # TODO: configure impermanence for panoramax data + # This would typically include directories like: + # - /var/lib/panoramax + # - panoramax storage directories + # - any cache or temporary directories that need to persist + }; +} diff --git a/modules/nixos-modules/server/panoramax/storage.nix b/modules/nixos-modules/server/panoramax/storage.nix deleted file mode 100644 index b36e087..0000000 --- a/modules/nixos-modules/server/panoramax/storage.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - lib, - config, - ... -}: { - options.services.panoramax.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.panoramax.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.panoramax.enable { - storage.datasets.replicate."system/root" = { - directories."/var/lib/panoramax" = lib.mkIf config.services.panoramax.impermanence.enable { - owner.name = "panoramax"; - group.name = "panoramax"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/paperless/default.nix b/modules/nixos-modules/server/paperless/default.nix index f7a5aa7..7e5e16b 100644 --- a/modules/nixos-modules/server/paperless/default.nix +++ b/modules/nixos-modules/server/paperless/default.nix @@ -4,6 +4,6 @@ ./proxy.nix ./database.nix ./fail2ban.nix - ./storage.nix + ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/paperless/impermanence.nix b/modules/nixos-modules/server/paperless/impermanence.nix new file mode 100644 index 0000000..fc87ea7 --- /dev/null +++ b/modules/nixos-modules/server/paperless/impermanence.nix @@ -0,0 +1,32 @@ +{ + config, + lib, + ... +}: let + dataDir = "/var/lib/paperless"; +in { + options.services.paperless = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.paperless.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.paperless.impermanence.enable { + assertions = [ + { + assertion = config.services.paperless.dataDir == dataDir; + message = "paperless data location does not match persistence"; + } + ]; + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = dataDir; + user = "paperless"; + group = "paperless"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/paperless/storage.nix b/modules/nixos-modules/server/paperless/storage.nix deleted file mode 100644 index 6e17bc2..0000000 --- a/modules/nixos-modules/server/paperless/storage.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - config, - lib, - ... -}: let - dataDir = "/var/lib/paperless"; -in { - options.services.paperless.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.paperless.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.paperless.enable { - storage.datasets.replicate."system/root" = { - directories."${dataDir}" = lib.mkIf config.services.paperless.impermanence.enable { - owner.name = "paperless"; - group.name = "paperless"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/postgres/default.nix b/modules/nixos-modules/server/postgres/default.nix index 50d90d4..abf4ade 100644 --- a/modules/nixos-modules/server/postgres/default.nix +++ b/modules/nixos-modules/server/postgres/default.nix @@ -1,6 +1,6 @@ {...}: { imports = [ ./postgres.nix - ./storage.nix + ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/postgres/impermanence.nix b/modules/nixos-modules/server/postgres/impermanence.nix new file mode 100644 index 0000000..a67fb1a --- /dev/null +++ b/modules/nixos-modules/server/postgres/impermanence.nix @@ -0,0 +1,27 @@ +{ + config, + lib, + ... +}: let + dataDir = "/var/lib/postgresql/16"; +in { + config = lib.mkIf (config.services.postgresql.enable && config.host.impermanence.enable) { + assertions = [ + { + assertion = config.services.postgresql.dataDir == dataDir; + message = "postgres data directory does not match persistence"; + } + ]; + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = dataDir; + user = "postgres"; + group = "postgres"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/postgres/storage.nix b/modules/nixos-modules/server/postgres/storage.nix deleted file mode 100644 index 58a84a6..0000000 --- a/modules/nixos-modules/server/postgres/storage.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - config, - lib, - ... -}: let - dataDir = "/var/lib/postgresql/16"; -in { - options.services.postgresql.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.postgresql.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.postgresql.enable { - storage.datasets.replicate."system/root" = { - directories."${dataDir}" = lib.mkIf config.services.postgresql.impermanence.enable { - owner.name = "postgres"; - group.name = "postgres"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/qbittorent/default.nix b/modules/nixos-modules/server/qbittorent/default.nix index 11cc449..f7511e6 100644 --- a/modules/nixos-modules/server/qbittorent/default.nix +++ b/modules/nixos-modules/server/qbittorent/default.nix @@ -1,6 +1,6 @@ {...}: { imports = [ ./qbittorent.nix - ./storage.nix + ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/qbittorent/impermanence.nix b/modules/nixos-modules/server/qbittorent/impermanence.nix new file mode 100644 index 0000000..1489e7d --- /dev/null +++ b/modules/nixos-modules/server/qbittorent/impermanence.nix @@ -0,0 +1,61 @@ +{ + lib, + config, + ... +}: let + qbittorent_profile_directory = "/var/lib/qBittorrent/"; +in { + options.services.qbittorrent = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.qbittorrent.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.qbittorrent.impermanence.enable { + fileSystems."/persist/system/qbittorrent".neededForBoot = true; + + host.storage.pool.extraDatasets = { + # sops age key needs to be available to pre persist for user generation + "persist/system/qbittorrent" = { + type = "zfs_fs"; + mountpoint = "/persist/system/qbittorrent"; + options = { + canmount = "on"; + }; + }; + }; + + assertions = [ + { + assertion = config.services.qbittorrent.profileDir == qbittorent_profile_directory; + message = "qbittorrent data directory does not match persistence"; + } + ]; + + environment.persistence = { + "/persist/system/root" = { + directories = [ + { + directory = qbittorent_profile_directory; + user = "qbittorrent"; + group = "qbittorrent"; + } + ]; + }; + + "/persist/system/qbittorrent" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = config.services.qbittorrent.mediaDir; + user = "qbittorrent"; + group = "qbittorrent"; + mode = "1775"; + } + ]; + }; + }; + }; +} diff --git a/modules/nixos-modules/server/qbittorent/storage.nix b/modules/nixos-modules/server/qbittorent/storage.nix deleted file mode 100644 index da82bcc..0000000 --- a/modules/nixos-modules/server/qbittorent/storage.nix +++ /dev/null @@ -1,46 +0,0 @@ -{ - lib, - config, - ... -}: let - qbittorent_profile_directory = "/var/lib/qBittorrent/"; -in { - options.services.qbittorrent.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.qbittorrent.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.qbittorrent.enable { - storage.datasets.replicate = { - "system/root" = { - directories."${qbittorent_profile_directory}" = lib.mkIf config.services.qbittorrent.impermanence.enable { - owner.name = "qbittorrent"; - group.name = "qbittorrent"; - }; - }; - "system/media" = { - mount = "/persist/replicate/system/media"; - - directories."${config.services.qbittorrent.mediaDir}" = lib.mkIf config.services.qbittorrent.impermanence.enable { - owner.name = "qbittorrent"; - group.name = "qbittorrent"; - owner.permissions = { - read = true; - write = true; - execute = true; - }; - group.permissions = { - read = true; - write = true; - execute = true; - }; - other.permissions = { - read = true; - write = false; - execute = true; - }; - }; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/radarr/default.nix b/modules/nixos-modules/server/radarr/default.nix index cb2a5f0..86dbb4b 100644 --- a/modules/nixos-modules/server/radarr/default.nix +++ b/modules/nixos-modules/server/radarr/default.nix @@ -1,5 +1,5 @@ {...}: { imports = [ - ./storage.nix + ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/radarr/impermanence.nix b/modules/nixos-modules/server/radarr/impermanence.nix new file mode 100644 index 0000000..c948e3a --- /dev/null +++ b/modules/nixos-modules/server/radarr/impermanence.nix @@ -0,0 +1,33 @@ +{ + lib, + config, + ... +}: let + radarr_data_directory = "/var/lib/radarr/.config/Radarr"; +in { + options.services.radarr = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.radarr.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.radarr.impermanence.enable { + assertions = [ + { + assertion = config.services.radarr.dataDir == radarr_data_directory; + message = "radarr data directory does not match persistence"; + } + ]; + + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = radarr_data_directory; + user = "radarr"; + group = "radarr"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/radarr/storage.nix b/modules/nixos-modules/server/radarr/storage.nix deleted file mode 100644 index 8f991c0..0000000 --- a/modules/nixos-modules/server/radarr/storage.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - lib, - config, - ... -}: let - radarr_data_directory = "/var/lib/radarr/.config/Radarr"; -in { - options.services.radarr.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.radarr.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.radarr.enable { - storage.datasets.replicate."system/root" = { - directories."${radarr_data_directory}" = lib.mkIf config.services.radarr.impermanence.enable { - owner.name = "radarr"; - group.name = "radarr"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/reverseProxy/default.nix b/modules/nixos-modules/server/reverseProxy/default.nix index 336e28b..5d57175 100644 --- a/modules/nixos-modules/server/reverseProxy/default.nix +++ b/modules/nixos-modules/server/reverseProxy/default.nix @@ -1,6 +1,6 @@ {...}: { imports = [ ./reverseProxy.nix - ./storage.nix + ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/reverseProxy/impermanence.nix b/modules/nixos-modules/server/reverseProxy/impermanence.nix new file mode 100644 index 0000000..7af55df --- /dev/null +++ b/modules/nixos-modules/server/reverseProxy/impermanence.nix @@ -0,0 +1,21 @@ +{ + lib, + config, + ... +}: let + dataDir = "/var/lib/acme"; +in { + config = lib.mkIf (config.host.impermanence.enable && config.services.reverseProxy.enable) { + environment.persistence."/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = dataDir; + user = "acme"; + group = "acme"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/reverseProxy/storage.nix b/modules/nixos-modules/server/reverseProxy/storage.nix deleted file mode 100644 index 62b5451..0000000 --- a/modules/nixos-modules/server/reverseProxy/storage.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - lib, - config, - ... -}: let - dataDir = "/var/lib/acme"; -in { - options.services.reverseProxy.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.reverseProxy.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.reverseProxy.enable { - storage.datasets.replicate."system/root" = { - directories."${dataDir}" = lib.mkIf config.services.reverseProxy.impermanence.enable { - owner.name = "acme"; - group.name = "acme"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/sonarr/default.nix b/modules/nixos-modules/server/sonarr/default.nix index cb2a5f0..86dbb4b 100644 --- a/modules/nixos-modules/server/sonarr/default.nix +++ b/modules/nixos-modules/server/sonarr/default.nix @@ -1,5 +1,5 @@ {...}: { imports = [ - ./storage.nix + ./impermanence.nix ]; } diff --git a/modules/nixos-modules/server/sonarr/impermanence.nix b/modules/nixos-modules/server/sonarr/impermanence.nix new file mode 100644 index 0000000..5b90ee9 --- /dev/null +++ b/modules/nixos-modules/server/sonarr/impermanence.nix @@ -0,0 +1,33 @@ +{ + lib, + config, + ... +}: let + sonarr_data_directory = "/var/lib/sonarr/.config/NzbDrone"; +in { + options.services.sonarr = { + impermanence.enable = lib.mkOption { + type = lib.types.bool; + default = config.services.sonarr.enable && config.host.impermanence.enable; + }; + }; + + config = lib.mkIf config.services.sonarr.impermanence.enable { + assertions = [ + { + assertion = config.services.sonarr.dataDir == sonarr_data_directory; + message = "sonarr data directory does not match persistence"; + } + ]; + + environment.persistence."/persist/system/root" = { + directories = [ + { + directory = sonarr_data_directory; + user = "sonarr"; + group = "sonarr"; + } + ]; + }; + }; +} diff --git a/modules/nixos-modules/server/sonarr/storage.nix b/modules/nixos-modules/server/sonarr/storage.nix deleted file mode 100644 index 8587751..0000000 --- a/modules/nixos-modules/server/sonarr/storage.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ - lib, - config, - ... -}: let - sonarr_data_directory = "/var/lib/sonarr/.config/NzbDrone"; -in { - options.services.sonarr.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.sonarr.enable && config.storage.impermanence.enable; - }; - - config = lib.mkIf config.services.sonarr.enable { - storage.datasets.replicate."system/root" = { - directories."${sonarr_data_directory}" = lib.mkIf config.services.sonarr.impermanence.enable { - owner.name = "sonarr"; - group.name = "sonarr"; - }; - }; - }; -} diff --git a/modules/nixos-modules/server/wyoming.nix b/modules/nixos-modules/server/wyoming.nix index 1df6877..c9a1474 100644 --- a/modules/nixos-modules/server/wyoming.nix +++ b/modules/nixos-modules/server/wyoming.nix @@ -48,7 +48,7 @@ systemd.services."wyoming-faster-whisper-en".serviceConfig.ProcSubset = lib.mkForce "all"; } (lib.mkIf config.host.impermanence.enable { - environment.persistence."/persist/replicate/system/root" = { + environment.persistence."/persist/system/root" = { enable = true; hideMounts = true; directories = [ diff --git a/modules/nixos-modules/ssh.nix b/modules/nixos-modules/ssh.nix index 6fe8e5c..0a82116 100644 --- a/modules/nixos-modules/ssh.nix +++ b/modules/nixos-modules/ssh.nix @@ -3,42 +3,28 @@ config, ... }: { - options = { - services.openssh.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.openssh.enable && config.storage.impermanence.enable; - }; - }; - - config = { - services = { - openssh = { - enable = true; - ports = [22]; - settings = { - PasswordAuthentication = false; - UseDns = true; - X11Forwarding = false; + config = lib.mkMerge [ + { + services = { + openssh = { + enable = true; + ports = [22]; + settings = { + PasswordAuthentication = false; + UseDns = true; + X11Forwarding = false; + }; }; }; - }; - storage.datasets.replicate."system/root" = { - files = lib.mkIf config.services.openssh.impermanence.enable (builtins.listToAttrs ( - lib.lists.flatten ( - builtins.map (hostKey: [ - { - name = hostKey.path; - value = {enable = true;}; - } - { - name = "${hostKey.path}.pub"; - value = {enable = true;}; - } - ]) - config.services.openssh.hostKeys - ) - )); - }; - }; + programs.ssh.kexAlgorithms = config.services.openssh.settings.KexAlgorithms; + } + (lib.mkIf config.host.impermanence.enable { + environment.persistence."/persist/system/root" = { + files = lib.lists.flatten ( + builtins.map (hostKey: [hostKey.path "${hostKey.path}.pub"]) config.services.openssh.hostKeys + ); + }; + }) + ]; } diff --git a/modules/nixos-modules/storage/default.nix b/modules/nixos-modules/storage/default.nix deleted file mode 100644 index ebf990a..0000000 --- a/modules/nixos-modules/storage/default.nix +++ /dev/null @@ -1,13 +0,0 @@ -{...}: { - # TODO: we should have an impermanence module for home manager that proxies its values namespaced to the user down here that matches the same interface - - # TODO: we should have a way of enabling impermanence for a systemd config - # these should have an option to put their folder into their own dataset (this needs to support private vs non private) - # options for features that can be added to the dataset - - imports = [ - ./impermanence.nix - ./zfs.nix - ./storage.nix - ]; -} diff --git a/modules/nixos-modules/storage/impermanence.nix b/modules/nixos-modules/storage/impermanence.nix deleted file mode 100644 index 4fdf803..0000000 --- a/modules/nixos-modules/storage/impermanence.nix +++ /dev/null @@ -1,142 +0,0 @@ -args @ { - lib, - config, - ... -}: let - datasetSubmodules = (import ./submodules/dataset.nix) args; - impermanenceDatasetSubmodule = (import ./submodules/impermanenceDataset.nix) args; - - permissionsToMode = permissions: let - permSetToDigit = permSet: - ( - if permSet.read - then 4 - else 0 - ) - + ( - if permSet.write - then 2 - else 0 - ) - + ( - if permSet.execute - then 1 - else 0 - ); - - ownerDigit = permSetToDigit permissions.owner.permissions; - groupDigit = permSetToDigit permissions.group.permissions; - otherDigit = permSetToDigit permissions.other.permissions; - in - toString ownerDigit + toString groupDigit + toString otherDigit; - - # Get the option names from both submodules to automatically determine which are impermanence-specific - regularDatasetEval = lib.evalModules { - modules = [datasetSubmodules]; - specialArgs = args; - }; - impermanenceDatasetEval = lib.evalModules { - modules = [impermanenceDatasetSubmodule]; - specialArgs = args; - }; - - regularDatasetOptions = builtins.attrNames regularDatasetEval.options; - impermanenceDatasetOptions = builtins.attrNames impermanenceDatasetEval.options; - - # Find options that are only in impermanence datasets (not in regular ZFS datasets) - impermanenceOnlyOptions = lib.lists.subtractLists regularDatasetOptions impermanenceDatasetOptions; -in { - options.storage = { - impermanence = { - enable = lib.mkEnableOption "should impermanence be enabled for this system"; - - datasets = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule impermanenceDatasetSubmodule); - default = {}; - }; - }; - }; - - config = lib.mkIf config.storage.impermanence.enable (lib.mkMerge [ - { - assertions = [ - { - assertion = config.storage.zfs.enable; - message = "storage.impermanence can not be used without storage.zfs."; - } - ]; - - system.activationScripts = { - # fixes issues with /var/lib/private not having the correct permissions https://github.com/nix-community/impermanence/issues/254 - "createPersistentStorageDirs".deps = ["var-lib-private-permissions" "users" "groups"]; - - "var-lib-private-permissions" = lib.mkIf config.storage.generateBase { - deps = ["specialfs"]; - text = '' - mkdir -p /persist/replicate/system/root/var/lib/private - chmod 0700 /persist/replicate/system/root/var/lib/private - ''; - }; - }; - - programs.fuse.userAllowOther = true; - - # Suppress sudo lecture on every boot since impermanence wipes the lecture status file - security.sudo.extraConfig = "Defaults lecture=never"; - - fileSystems = - lib.mapAttrs' ( - datasetName: dataset: - lib.nameValuePair "/${datasetName}" { - device = "rpool/${datasetName}"; - fsType = "zfs"; - neededForBoot = true; - } - ) - (lib.filterAttrs ( - datasetName: dataset: dataset.impermanence.enable - ) - config.storage.impermanence.datasets); - - environment.persistence = - lib.mapAttrs (datasetName: dataset: { - enable = true; - hideMounts = true; - persistentStoragePath = "/${datasetName}"; - directories = lib.mapAttrsToList (path: dirConfig: { - directory = path; - user = dirConfig.owner.name; - group = dirConfig.group.name; - mode = permissionsToMode dirConfig; - }) (lib.filterAttrs (_: dirConfig: dirConfig.enable) dataset.directories); - files = lib.mapAttrsToList (path: fileConfig: { - file = path; - parentDirectory = { - user = fileConfig.owner.name; - group = fileConfig.group.name; - mode = permissionsToMode fileConfig; - }; - }) (lib.filterAttrs (_: fileConfig: fileConfig.enable) dataset.files); - }) - (lib.filterAttrs ( - datasetName: dataset: let - enabledDirectories = lib.filterAttrs (_: dirConfig: dirConfig.enable) dataset.directories; - enabledFiles = lib.filterAttrs (_: fileConfig: fileConfig.enable) dataset.files; - in - (enabledDirectories != {}) || (enabledFiles != {}) - ) - (lib.filterAttrs ( - datasetName: dataset: dataset.impermanence.enable - ) - config.storage.impermanence.datasets)); - } - (lib.mkIf config.storage.zfs.enable { - storage.zfs.datasets = - lib.mapAttrs ( - datasetName: dataset: - builtins.removeAttrs dataset impermanenceOnlyOptions - ) - config.storage.impermanence.datasets; - }) - ]); -} diff --git a/modules/nixos-modules/storage/storage.nix b/modules/nixos-modules/storage/storage.nix deleted file mode 100644 index 771d661..0000000 --- a/modules/nixos-modules/storage/storage.nix +++ /dev/null @@ -1,216 +0,0 @@ -args @ { - lib, - config, - ... -}: let - datasetSubmodule = (import ./submodules/dataset.nix) args; - impermanenceDatasetSubmodule = (import ./submodules/impermanenceDataset.nix) args; - - # Get the option names from both submodules to automatically determine which are impermanence-specific - regularDatasetEval = lib.evalModules { - modules = [datasetSubmodule]; - specialArgs = args; - }; - impermanenceDatasetEval = lib.evalModules { - modules = [impermanenceDatasetSubmodule]; - specialArgs = args; - }; - - regularDatasetOptions = builtins.attrNames regularDatasetEval.options; - impermanenceDatasetOptions = builtins.attrNames impermanenceDatasetEval.options; - - # Find options that are only in impermanence datasets (not in regular ZFS datasets) - impermanenceOnlyOptions = lib.lists.subtractLists regularDatasetOptions impermanenceDatasetOptions; -in { - options.storage = { - generateBase = lib.mkOption { - type = lib.types.bool; - default = true; - description = '' - When enabled, enables automatic generation of base datasets (ephemeral, local, replicate roots). - This allows manual definition of datasets matching an existing system layout for migration purposes. - ''; - }; - datasets = { - ephemeral = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule datasetSubmodule); - default = {}; - }; - local = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule impermanenceDatasetSubmodule); - default = {}; - }; - replicate = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule impermanenceDatasetSubmodule); - default = {}; - }; - }; - }; - - config = lib.mkMerge [ - (lib.mkIf (config.storage.zfs.enable && config.storage.generateBase) { - # Create ZFS datasets based on storage.datasets configuration - storage.datasets = { - local = { - "nix" = { - impermanence.enable = false; - type = "zfs_fs"; - mount = "/nix"; - snapshot = { - autoSnapshot = false; - }; - atime = "off"; - relatime = "off"; - }; - }; - }; - }) - (lib.mkIf (config.storage.zfs.enable && config.storage.impermanence.enable && config.storage.generateBase) { - storage.datasets = { - ephemeral = { - "" = { - type = "zfs_fs"; - mount = null; - }; - "system/root" = { - type = "zfs_fs"; - mount = "/"; - snapshot = { - blankSnapshot = true; - }; - }; - }; - # TODO: can we auto set the mount points on these to just be `"/persist/local/${name}"` - local = { - "" = { - mount = "/persist/local"; - }; - }; - # TODO: can we auto set the mount points on these to just be `"/persist/replicate/${name}"` - replicate = { - "" = { - mount = "/persist/replicate"; - }; - "system/root" = { - mount = "/persist/replicate/system/root"; - snapshot = { - autoSnapshot = true; - }; - directories = { - "/var/lib/nixos".enable = true; - "/var/lib/systemd/coredump".enable = true; - }; - files = { - "/etc/machine-id".enable = true; - }; - }; - "home" = { - mount = "/persist/replicate/home"; - snapshot = { - autoSnapshot = true; - }; - }; - "system/var/log" = { - type = "zfs_fs"; - directories = { - "/var/log".enable = true; - }; - }; - }; - }; - - storage.zfs.datasets = lib.mkMerge [ - (lib.mapAttrs' (name: dataset: { - name = - if name == "" - then "ephemeral" - else "ephemeral/${name}"; - value = dataset; - }) - config.storage.datasets.ephemeral) - ]; - - boot.initrd.postResumeCommands = lib.mkAfter '' - zfs rollback -r rpool/ephemeral/system/root@blank - ''; - - storage.impermanence.datasets = lib.mkMerge [ - (lib.mapAttrs' (name: dataset: { - name = - if name == "" - then "persist/local" - else "persist/local/${name}"; - value = dataset; - }) - config.storage.datasets.local) - (lib.mapAttrs' (name: dataset: { - name = - if name == "" - then "persist/replicate" - else "persist/replicate/${name}"; - value = dataset; - }) - config.storage.datasets.replicate) - ]; - }) - (lib.mkIf (config.storage.zfs.enable && !config.storage.impermanence.enable && config.storage.generateBase) { - storage.datasets = { - # Base organizational datasets (only needed when impermanence is disabled) - local = { - "" = { - type = "zfs_fs"; - mount = null; - }; - "root" = { - type = "zfs_fs"; - mount = "/"; - compression = "lz4"; - acltype = "posixacl"; - relatime = "on"; - xattr = "sa"; - snapshot = { - autoSnapshot = true; - blankSnapshot = true; - }; - }; - }; - replicate = { - "" = { - type = "zfs_fs"; - mount = null; - }; - "system/var/log" = { - type = "zfs_fs"; - mount = "/var/log"; - }; - }; - }; - - storage.zfs.datasets = lib.mkMerge [ - (lib.mapAttrs' (name: dataset: { - name = - if name == "" - then "persist/local" - else "persist/local/${name}"; - value = builtins.removeAttrs dataset impermanenceOnlyOptions; - }) - config.storage.datasets.local) - (lib.mapAttrs' (name: dataset: { - name = - if name == "" - then "persist/replicate" - else "persist/replicate/${name}"; - value = builtins.removeAttrs dataset impermanenceOnlyOptions; - }) - config.storage.datasets.replicate) - ]; - }) - ]; - - # TODO: set up datasets for systemd services that want a dataset created - # TODO: home-manager.users..storage.impermanence.enable - # is false then persist the entire directory of the user - # if true persist home-manager.users..storage.impermanence.datasets - # TODO: systemd.services..storage.datasets persists - # TODO: configure other needed storage modes here -} diff --git a/modules/nixos-modules/storage/submodules/dataset.nix b/modules/nixos-modules/storage/submodules/dataset.nix deleted file mode 100644 index 2a45552..0000000 --- a/modules/nixos-modules/storage/submodules/dataset.nix +++ /dev/null @@ -1,86 +0,0 @@ -{lib, ...}: {name, ...}: { - options = { - type = lib.mkOption { - type = lib.types.enum ["zfs_fs" "zfs_volume"]; - default = "zfs_fs"; - description = "Type of ZFS dataset (filesystem or volume)"; - }; - - acltype = lib.mkOption { - type = lib.types.nullOr (lib.types.enum ["off" "nfsv4" "posixacl"]); - default = null; - description = "Access control list type"; - }; - - relatime = lib.mkOption { - type = lib.types.nullOr (lib.types.enum ["on" "off"]); - default = null; - description = "Controls when access time is updated"; - }; - - atime = lib.mkOption { - type = lib.types.nullOr (lib.types.enum ["on" "off"]); - default = null; - description = "Controls whether access time is updated"; - }; - - xattr = lib.mkOption { - type = lib.types.nullOr (lib.types.enum ["on" "off" "sa" "dir"]); - default = null; - description = "Extended attribute storage method"; - }; - - compression = lib.mkOption { - type = lib.types.nullOr (lib.types.enum ["on" "off" "lz4" "gzip" "zstd" "lzjb" "zle"]); - default = null; - description = "Compression algorithm to use"; - }; - - sync = lib.mkOption { - type = lib.types.nullOr (lib.types.enum ["standard" "always" "disabled"]); - default = null; - description = "Synchronous write behavior"; - }; - - mount = lib.mkOption { - type = lib.types.nullOr lib.types.str; - description = "Controls the mount point used for this file system"; - default = null; - }; - - encryption = { - enable = lib.mkEnableOption "should encryption be enabled"; - type = lib.mkOption { - type = lib.types.enum ["aes-128-ccm" "aes-192-ccm" "aes-256-ccm" "aes-128-gcm" "aes-192-gcm" "aes-256-gcm"]; - description = "What encryption type to use"; - }; - keyformat = lib.mkOption { - type = lib.types.enum ["raw" "hex" "passphrase"]; - description = "Format of the encryption key"; - }; - keylocation = lib.mkOption { - type = lib.types.str; - description = "Location of the encryption key"; - }; - }; - - snapshot = { - # This option should set this option flag - autoSnapshot = lib.mkEnableOption "Enable automatic snapshots for this dataset"; - # Creates a blank snapshot in the post create hook for rollback purposes - blankSnapshot = lib.mkEnableOption "Should a blank snapshot be auto created in the post create hook"; - }; - - recordSize = lib.mkOption { - type = lib.types.nullOr lib.types.str; - default = null; - description = "Suggested block size for files in the file system"; - }; - - postCreateHook = lib.mkOption { - type = lib.types.str; - default = ""; - description = "Script to run after dataset creation"; - }; - }; -} diff --git a/modules/nixos-modules/storage/submodules/impermanenceDataset.nix b/modules/nixos-modules/storage/submodules/impermanenceDataset.nix deleted file mode 100644 index e4d3584..0000000 --- a/modules/nixos-modules/storage/submodules/impermanenceDataset.nix +++ /dev/null @@ -1,56 +0,0 @@ -args @ {lib, ...}: {name, ...}: let - datasetSubmodule = (import ./dataset.nix) args; - pathPermissions = { - read = lib.mkEnableOption "should the path have read permissions"; - write = lib.mkEnableOption "should the path have read permissions"; - execute = lib.mkEnableOption "should the path have read permissions"; - }; - pathTypeSubmodule = {name, ...}: { - options = { - enable = lib.mkOption { - type = lib.types.bool; - default = true; - }; - owner = { - name = lib.mkOption { - type = lib.types.str; - default = "root"; - }; - permissions = pathPermissions; - }; - group = { - name = lib.mkOption { - type = lib.types.str; - default = "root"; - }; - permissions = pathPermissions; - }; - other = { - permissions = pathPermissions; - }; - }; - }; -in { - imports = [ - datasetSubmodule - ]; - - options = { - files = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule pathTypeSubmodule); - default = {}; - }; - directories = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule pathTypeSubmodule); - default = {}; - }; - impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = true; - }; - }; - - config = { - mount = lib.mkDefault "/${name}"; - }; -} diff --git a/modules/nixos-modules/storage/zfs.nix b/modules/nixos-modules/storage/zfs.nix deleted file mode 100644 index 2fc6cb4..0000000 --- a/modules/nixos-modules/storage/zfs.nix +++ /dev/null @@ -1,347 +0,0 @@ -args @ { - lib, - pkgs, - config, - ... -}: let - datasetSubmodule = (import ./submodules/dataset.nix) args; - - # Hash function for disk names (max 27 chars to fit GPT limitations) - hashDisk = drive: (builtins.substring 0 27 (builtins.hashString "sha256" drive)); - - # Map "stripe" to "" for disko compatibility (disko uses "" for stripe mode) - diskoPoolMode = - if config.storage.zfs.pool.mode == "stripe" - then "" - else config.storage.zfs.pool.mode; - - # Helper to flatten vdevs into list of devices with names - allVdevDevices = lib.lists.flatten (builtins.map ( - vdev: - builtins.map ( - device: - lib.attrsets.nameValuePair (hashDisk device.device) device - ) - vdev - ) - config.storage.zfs.pool.vdevs); - - # Cache devices with names - allCacheDevices = builtins.map ( - device: - lib.attrsets.nameValuePair (hashDisk device.device) device - ) (config.storage.zfs.pool.cache); - - # All devices (vdevs + cache) - allDevices = allVdevDevices ++ allCacheDevices; - - # Boot devices - filter devices that have boot = true - bootDevices = builtins.filter (device: device.value.boot) allDevices; - - # Helper function to convert dataset options to ZFS properties - datasetToZfsOptions = dataset: let - baseOptions = - (lib.attrsets.optionalAttrs (dataset.acltype != null) {acltype = dataset.acltype;}) - // (lib.attrsets.optionalAttrs (dataset.relatime != null) {relatime = dataset.relatime;}) - // (lib.attrsets.optionalAttrs (dataset.atime != null) {atime = dataset.atime;}) - // (lib.attrsets.optionalAttrs (dataset.xattr != null) {xattr = dataset.xattr;}) - // (lib.attrsets.optionalAttrs (dataset.compression != null) {compression = dataset.compression;}) - // (lib.attrsets.optionalAttrs (dataset.sync != null) {sync = dataset.sync;}) - // (lib.attrsets.optionalAttrs (dataset.recordSize != null) {recordSize = dataset.recordSize;}); - - encryptionOptions = lib.attrsets.optionalAttrs (dataset.encryption.enable) ( - (lib.attrsets.optionalAttrs (dataset.encryption ? type) {encryption = dataset.encryption.type;}) - // (lib.attrsets.optionalAttrs (dataset.encryption ? keyformat) {keyformat = dataset.encryption.keyformat;}) - // (lib.attrsets.optionalAttrs (dataset.encryption ? keylocation) {keylocation = dataset.encryption.keylocation;}) - ); - - mountOptions = lib.attrsets.optionalAttrs (dataset ? mount && dataset.mount ? enable) ( - if builtins.isBool dataset.mount.enable - then { - canmount = - if dataset.mount.enable - then "on" - else "off"; - } - else {canmount = dataset.mount.enable;} - ); - - snapshotOptions = lib.attrsets.optionalAttrs (dataset ? snapshot && dataset.snapshot ? autoSnapshot) { - "com.sun:auto-snapshot" = - if dataset.snapshot.autoSnapshot - then "true" - else "false"; - }; - in - baseOptions // encryptionOptions // mountOptions // snapshotOptions; - - # Helper to generate post create hooks - generatePostCreateHook = name: dataset: - dataset.postCreateHook - + (lib.optionalString dataset.snapshot.blankSnapshot '' - zfs snapshot rpool/${name}@blank - ''); - - # Convert datasets to disko format - convertedDatasets = builtins.listToAttrs ( - (lib.attrsets.mapAttrsToList ( - name: dataset: - lib.attrsets.nameValuePair name { - type = dataset.type; - options = datasetToZfsOptions dataset; - mountpoint = dataset.mount or null; - postCreateHook = generatePostCreateHook name dataset; - } - ) - config.storage.zfs.datasets) - ++ (lib.optional (config.storage.zfs.rootDataset != null) ( - lib.attrsets.nameValuePair "" { - type = config.storage.zfs.rootDataset.type; - options = datasetToZfsOptions config.storage.zfs.rootDataset; - mountpoint = config.storage.zfs.rootDataset.mount or null; - postCreateHook = generatePostCreateHook "" config.storage.zfs.rootDataset; - } - )) - ); -in { - options.storage = { - zfs = { - enable = lib.mkEnableOption "Should zfs be enabled on this system."; - - notifications = { - enable = lib.mkEnableOption "are notifications enabled"; - host = lib.mkOption { - type = lib.types.str; - description = "what is the host that we are going to send the email to"; - }; - port = lib.mkOption { - type = lib.types.port; - description = "what port is the host using to receive mail on"; - }; - to = lib.mkOption { - type = lib.types.str; - description = "what account is the email going to be sent to"; - }; - user = lib.mkOption { - type = lib.types.str; - description = "what user is the email going to be set from"; - }; - tokenFile = lib.mkOption { - type = lib.types.str; - description = "file containing the password to be used by msmtp for notifications"; - }; - }; - - pool = let - deviceType = - lib.types.coercedTo lib.types.str (device: { - device = device; - boot = false; - }) (lib.types.submodule { - options = { - device = lib.mkOption { - type = lib.types.str; - }; - boot = lib.mkEnableOption "should this device be a boot device"; - }; - }); - in { - encryption = { - enable = lib.mkEnableOption "Should encryption be enabled on this pool."; - keyformat = lib.mkOption { - type = lib.types.enum ["raw" "hex" "passphrase"]; - default = "hex"; - description = "Format of the encryption key"; - }; - keylocation = lib.mkOption { - type = lib.types.str; - default = "prompt"; - description = "Location of the encryption key"; - }; - }; - mode = lib.mkOption { - type = lib.types.enum ["stripe" "mirror" "raidz1" "raidz2" "raidz3"]; - default = "raidz2"; - description = "ZFS redundancy mode for the pool"; - }; - bootPartitionSize = lib.mkOption { - type = lib.types.str; - default = "2G"; - description = "Size of the boot partition on boot drives"; - }; - vdevs = lib.mkOption { - type = lib.types.listOf (lib.types.listOf deviceType); - default = []; - description = "List of vdevs, where each vdev is a list of devices"; - }; - cache = lib.mkOption { - type = lib.types.listOf deviceType; - default = []; - }; - }; - - rootDataset = lib.mkOption { - type = lib.types.nullOr (lib.types.submodule datasetSubmodule); - description = "Root ZFS dataset to create"; - default = null; - }; - - datasets = lib.mkOption { - type = lib.types.attrsOf (lib.types.submodule datasetSubmodule); - description = "Additional ZFS datasets to create"; - default = {}; - }; - }; - }; - - config = lib.mkIf config.storage.zfs.enable (lib.mkMerge [ - { - # Assertion that we have at least one boot device - assertions = [ - { - assertion = (builtins.length bootDevices) > 0; - message = "ZFS configuration requires at least one boot device. Set boot = true for at least one device in your vdevs or cache."; - } - ]; - - # # Warning about disk/dataset mismatches - these would be runtime checks - # warnings = let - # configuredDisks = builtins.map (device: device.device) (builtins.map (dev: dev.value) allDevices); - # diskWarnings = - # lib.optional (config.storage.zfs.enable) - # "ZFS: Please ensure the following disks are available on your system: ${builtins.concatStringsSep ", " configuredDisks}"; - - # configuredDatasets = builtins.attrNames config.storage.zfs.datasets; - # datasetWarnings = - # lib.optional (config.storage.zfs.enable && (builtins.length configuredDatasets) > 0) - # "ZFS: Configured datasets: ${builtins.concatStringsSep ", " configuredDatasets}. Ensure these match your intended ZFS layout."; - # in - # diskWarnings ++ datasetWarnings; - - services.zfs = { - autoScrub.enable = true; - autoSnapshot.enable = true; - }; - - # # Configure disko for ZFS setup - disko.devices = { - disk = builtins.listToAttrs ( - builtins.map ( - drive: - lib.attrsets.nameValuePair (drive.name) { - type = "disk"; - device = "/dev/disk/by-id/${drive.value.device}"; - content = { - type = "gpt"; - partitions = { - ESP = lib.mkIf drive.value.boot { - size = config.storage.zfs.pool.bootPartitionSize; - type = "EF00"; - content = { - type = "filesystem"; - format = "vfat"; - mountpoint = "/boot"; - mountOptions = ["umask=0077"]; - }; - }; - zfs = { - size = "100%"; - content = { - type = "zfs"; - pool = "rpool"; - }; - }; - }; - }; - } - ) - allDevices - ); - - zpool = { - rpool = { - type = "zpool"; - mode = { - topology = { - type = "topology"; - vdev = - builtins.map (vdev: { - mode = diskoPoolMode; - members = builtins.map (device: hashDisk device.device) vdev; - }) - config.storage.zfs.pool.vdevs; - cache = builtins.map (device: hashDisk device.device) config.storage.zfs.pool.cache; - }; - }; - - options = { - ashift = "12"; - autotrim = "on"; - }; - - rootFsOptions = - { - canmount = "off"; - mountpoint = "none"; - xattr = "sa"; - acltype = "posixacl"; - relatime = "on"; - compression = "lz4"; - "com.sun:auto-snapshot" = "false"; - } - // (lib.attrsets.optionalAttrs config.storage.zfs.pool.encryption.enable { - encryption = "on"; - keyformat = config.storage.zfs.pool.encryption.keyformat; - keylocation = config.storage.zfs.pool.encryption.keylocation; - }); - - datasets = convertedDatasets; - }; - }; - }; - } - (lib.mkIf config.storage.zfs.notifications.enable { - programs.msmtp = { - enable = true; - setSendmail = true; - defaults = { - aliases = "/etc/aliases"; - port = config.storage.zfs.notifications.port; - tls_trust_file = "/etc/ssl/certs/ca-certificates.crt"; - tls = "on"; - auth = "login"; - tls_starttls = "off"; - }; - accounts = { - zfs_notifications = { - auth = true; - tls = true; - host = config.storage.zfs.notifications.host; - passwordeval = "cat ${config.storage.zfs.notifications.tokenFile}"; - user = config.storage.zfs.notifications.user; - from = config.storage.zfs.notifications.user; - }; - }; - }; - - services.zfs = { - zed = { - enableMail = true; - - settings = { - ZED_DEBUG_LOG = "/tmp/zed.debug.log"; - ZED_EMAIL_ADDR = [config.storage.zfs.notifications.to]; - ZED_EMAIL_PROG = "${pkgs.msmtp}/bin/msmtp"; - ZED_EMAIL_OPTS = "-a zfs_notifications @ADDRESS@"; - - ZED_NOTIFY_INTERVAL_SECS = 3600; - ZED_NOTIFY_VERBOSE = true; - - ZED_USE_ENCLOSURE_LEDS = true; - ZED_SCRUB_AFTER_RESILVER = true; - }; - }; - }; - }) - ]); -} diff --git a/modules/nixos-modules/sync.nix b/modules/nixos-modules/sync.nix new file mode 100644 index 0000000..96f54d5 --- /dev/null +++ b/modules/nixos-modules/sync.nix @@ -0,0 +1,69 @@ +{ + config, + lib, + syncthingConfiguration, + ... +}: let + mountDir = "/mnt/sync"; + configDir = "/etc/syncthing"; +in { + config = lib.mkMerge [ + { + systemd = lib.mkIf config.services.syncthing.enable { + tmpfiles.rules = [ + "A ${mountDir} - - - - u:syncthing:rwX,g:syncthing:rwX,o::-" + "d ${mountDir} 2755 syncthing syncthing -" + "d ${config.services.syncthing.dataDir} 775 syncthing syncthing -" + "d ${config.services.syncthing.configDir} 755 syncthing syncthing -" + ]; + }; + } + (lib.mkIf config.services.syncthing.enable (lib.mkMerge [ + { + services.syncthing = { + user = "syncthing"; + group = "syncthing"; + dataDir = "${mountDir}/default"; + configDir = configDir; + overrideDevices = true; + overrideFolders = true; + configuration = syncthingConfiguration; + deviceName = config.networking.hostName; + }; + } + + (lib.mkIf config.host.impermanence.enable { + assertions = + [ + { + assertion = config.services.syncthing.configDir == configDir; + message = "syncthing config dir does not match persistence"; + } + ] + ++ lib.attrsets.mapAttrsToList (_: folder: { + assertion = lib.strings.hasPrefix mountDir folder.path; + message = "syncthing folder ${folder.label} is stored at ${folder.path} which not under the persisted path of ${mountDir}"; + }) + config.services.syncthing.settings.folders; + environment.persistence = { + "/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = mountDir; + user = "syncthing"; + group = "syncthing"; + } + { + directory = configDir; + user = "syncthing"; + group = "syncthing"; + } + ]; + }; + }; + }) + ])) + ]; +} diff --git a/modules/nixos-modules/sync/default.nix b/modules/nixos-modules/sync/default.nix deleted file mode 100644 index 5640417..0000000 --- a/modules/nixos-modules/sync/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -{...}: { - imports = [ - ./sync.nix - ./storage.nix - ]; -} diff --git a/modules/nixos-modules/sync/storage.nix b/modules/nixos-modules/sync/storage.nix deleted file mode 100644 index 61bf855..0000000 --- a/modules/nixos-modules/sync/storage.nix +++ /dev/null @@ -1,32 +0,0 @@ -{ - config, - lib, - ... -}: let - mountDir = "/mnt/sync"; - configDir = "/etc/syncthing"; -in { - options = { - services.syncthing.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.syncthing.enable && config.storage.impermanence.enable; - }; - }; - - config = lib.mkIf config.services.syncthing.enable { - storage.datasets.replicate."system/root" = { - directories = { - "${mountDir}" = lib.mkIf config.services.syncthing.impermanence.enable { - enable = true; - owner.name = "syncthing"; - group.name = "syncthing"; - }; - "${configDir}" = lib.mkIf config.services.syncthing.impermanence.enable { - enable = true; - owner.name = "syncthing"; - group.name = "syncthing"; - }; - }; - }; - }; -} diff --git a/modules/nixos-modules/sync/sync.nix b/modules/nixos-modules/sync/sync.nix deleted file mode 100644 index 28b6e38..0000000 --- a/modules/nixos-modules/sync/sync.nix +++ /dev/null @@ -1,36 +0,0 @@ -{ - config, - lib, - syncthingConfiguration, - ... -}: let - mountDir = "/mnt/sync"; - configDir = "/etc/syncthing"; -in { - config = lib.mkMerge [ - { - systemd = lib.mkIf config.services.syncthing.enable { - tmpfiles.rules = [ - "A ${mountDir} - - - - u:syncthing:rwX,g:syncthing:rwX,o::-" - "d ${mountDir} 2755 syncthing syncthing -" - "d ${config.services.syncthing.dataDir} 775 syncthing syncthing -" - "d ${config.services.syncthing.configDir} 755 syncthing syncthing -" - ]; - }; - } - (lib.mkIf config.services.syncthing.enable (lib.mkMerge [ - { - services.syncthing = { - user = "syncthing"; - group = "syncthing"; - dataDir = "${mountDir}/default"; - configDir = configDir; - overrideDevices = true; - overrideFolders = true; - configuration = syncthingConfiguration; - deviceName = config.networking.hostName; - }; - } - ])) - ]; -} diff --git a/modules/nixos-modules/tailscale.nix b/modules/nixos-modules/tailscale.nix new file mode 100644 index 0000000..db664e8 --- /dev/null +++ b/modules/nixos-modules/tailscale.nix @@ -0,0 +1,34 @@ +{ + config, + lib, + ... +}: let + tailscale_data_directory = "/var/lib/tailscale"; +in { + options.host.tailscale = { + enable = lib.mkEnableOption "should tailscale be enabled on this computer"; + }; + + config = lib.mkIf config.services.tailscale.enable ( + lib.mkMerge [ + { + # any configs we want shared between all machines + } + (lib.mkIf config.host.impermanence.enable { + environment.persistence = { + "/persist/system/root" = { + enable = true; + hideMounts = true; + directories = [ + { + directory = tailscale_data_directory; + user = "root"; + group = "root"; + } + ]; + }; + }; + }) + ] + ); +} diff --git a/modules/nixos-modules/tailscale/default.nix b/modules/nixos-modules/tailscale/default.nix deleted file mode 100644 index 7a283e8..0000000 --- a/modules/nixos-modules/tailscale/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -{...}: { - imports = [ - ./tailscale.nix - ./storage.nix - ]; -} diff --git a/modules/nixos-modules/tailscale/storage.nix b/modules/nixos-modules/tailscale/storage.nix deleted file mode 100644 index 7ac7e9a..0000000 --- a/modules/nixos-modules/tailscale/storage.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ - config, - lib, - ... -}: let - tailscale_data_directory = "/var/lib/tailscale"; -in { - options = { - services.tailscale.impermanence.enable = lib.mkOption { - type = lib.types.bool; - default = config.services.tailscale.enable && config.storage.impermanence.enable; - }; - }; - - config = lib.mkIf config.services.tailscale.enable { - storage.datasets.replicate."system/root" = { - directories."${tailscale_data_directory}" = lib.mkIf config.services.tailscale.impermanence.enable { - enable = true; - owner.name = "root"; - group.name = "root"; - }; - }; - }; -} diff --git a/modules/nixos-modules/tailscale/tailscale.nix b/modules/nixos-modules/tailscale/tailscale.nix deleted file mode 100644 index 06899b1..0000000 --- a/modules/nixos-modules/tailscale/tailscale.nix +++ /dev/null @@ -1,19 +0,0 @@ -{ - config, - lib, - ... -}: { - options = { - host.tailscale = { - enable = lib.mkEnableOption "should tailscale be enabled on this computer"; - }; - }; - - config = lib.mkIf config.services.tailscale.enable ( - lib.mkMerge [ - { - # any configs we want shared between all machines - } - ] - ); -} diff --git a/modules/nixos-modules/users.nix b/modules/nixos-modules/users.nix index 9cef952..987e080 100644 --- a/modules/nixos-modules/users.nix +++ b/modules/nixos-modules/users.nix @@ -15,8 +15,7 @@ uids = { leyla = 1000; eve = 1002; - # ester = 1003; - # ivy = 1004; + ivy = 1004; jellyfin = 2000; forgejo = 2002; hass = 2004; @@ -37,8 +36,7 @@ gids = { leyla = 1000; eve = 1002; - # ester = 1003 - # ivy = 1004; + ivy = 1004; users = 100; jellyfin_media = 2001; jellyfin = 2000; @@ -61,6 +59,7 @@ users = config.users.users; leyla = users.leyla.name; eve = users.eve.name; + ivy = users.ivy.name; in { config = lib.mkMerge [ { @@ -98,6 +97,10 @@ in { neededForUsers = true; sopsFile = "${inputs.secrets}/user-passwords.yaml"; }; + "passwords/ivy" = { + neededForUsers = true; + sopsFile = "${inputs.secrets}/user-passwords.yaml"; + }; }; }; @@ -110,7 +113,7 @@ in { description = "Leyla"; extraGroups = (lib.lists.optionals host.users.leyla.isNormalUser ["networkmanager"]) - ++ (lib.lists.optionals host.users.leyla.isPrincipleUser ["wheel" "dialout" "docker"]) + ++ (lib.lists.optionals host.users.leyla.isPrincipleUser ["wheel" "dialout"]) ++ (lib.lists.optionals host.users.leyla.isDesktopUser ["adbusers"]); hashedPasswordFile = config.sops.secrets."passwords/leyla".path; isNormalUser = host.users.leyla.isNormalUser; @@ -131,6 +134,19 @@ in { group = config.users.users.eve.name; }; + ivy = { + uid = lib.mkForce uids.ivy; + name = lib.mkForce host.users.ivy.name; + description = "Ivy"; + extraGroups = + lib.optionals host.users.ivy.isNormalUser ["networkmanager"] + ++ (lib.lists.optionals host.users.ivy.isPrincipleUser ["wheel"]); + hashedPasswordFile = config.sops.secrets."passwords/ivy".path; + isNormalUser = host.users.ivy.isNormalUser; + isSystemUser = !host.users.ivy.isNormalUser; + group = config.users.users.ivy.name; + }; + jellyfin = { uid = lib.mkForce uids.jellyfin; isSystemUser = true; @@ -238,11 +254,19 @@ in { ]; }; + ivy = { + gid = lib.mkForce gids.ivy; + members = [ + ivy + ]; + }; + users = { gid = lib.mkForce gids.users; members = [ leyla eve + ivy ]; }; @@ -256,6 +280,7 @@ in { users.lidarr.name leyla eve + ivy ]; }; @@ -289,6 +314,7 @@ in { users.syncthing.name leyla eve + ivy ]; }; @@ -373,60 +399,79 @@ in { }; }; } - (lib.mkIf config.storage.zfs.enable (lib.mkMerge [ - { - # sops age key needs to be available to pre persist for user generation - storage.datasets.local."system/sops" = { - type = "zfs_fs"; - mount = SOPS_AGE_KEY_DIRECTORY; - atime = "off"; - relatime = "off"; - impermanence.enable = false; - }; - } - (lib.mkIf (!config.storage.impermanence.enable) { - storage.datasets.replicate = lib.mkMerge ( - builtins.map (user: { - "home/${user.name}" = { + (lib.mkIf config.host.impermanence.enable { + boot.initrd.postResumeCommands = lib.mkAfter ( + lib.strings.concatLines (builtins.map (user: "zfs rollback -r rpool/local/home/${user.name}@blank") + normalUsers) + ); + + systemd = { + tmpfiles.rules = + builtins.map ( + user: "d /persist/home/${user.name} 700 ${user.name} ${user.name} -" + ) + normalUsers; + }; + + fileSystems = lib.mkMerge [ + { + ${SOPS_AGE_KEY_DIRECTORY}.neededForBoot = true; + } + ( + builtins.listToAttrs ( + builtins.map (user: + lib.attrsets.nameValuePair "/persist/home/${user.name}" { + neededForBoot = true; + }) + normalUsers + ) + ) + ( + builtins.listToAttrs ( + builtins.map (user: + lib.attrsets.nameValuePair "/home/${user.name}" { + neededForBoot = true; + }) + normalUsers + ) + ) + ]; + + host.storage.pool.extraDatasets = lib.mkMerge ( + [ + { + # sops age key needs to be available to pre persist for user generation + "local/system/sops" = { type = "zfs_fs"; - mount = "/home/${user.name}"; - snapshot.autoSnapshot = true; + mountpoint = SOPS_AGE_KEY_DIRECTORY; + options = { + atime = "off"; + relatime = "off"; + canmount = "on"; + }; + }; + } + ] + ++ ( + builtins.map (user: { + "local/home/${user.name}" = { + type = "zfs_fs"; + mountpoint = "/home/${user.name}"; + options = { + canmount = "on"; + }; + postCreateHook = '' + zfs snapshot rpool/local/home/${user.name}@blank + ''; + }; + "persist/home/${user.name}" = { + type = "zfs_fs"; + mountpoint = "/persist/home/${user.name}"; }; }) normalUsers - ); - }) - (lib.mkIf config.storage.impermanence.enable { - storage.datasets.ephemeral = lib.mkMerge ( - builtins.map (user: { - "home/${user.name}" = { - type = "zfs_fs"; - mount = "/home/${user.name}"; - snapshot.blankSnapshot = true; - }; - }) - normalUsers - ); - - # Post resume commands to rollback user home datasets to blank snapshots - # Only add these when generateBase is true -- when false, the legacy - # storage config is responsible for providing rollback commands with - # the correct (old) dataset paths. - boot.initrd.postResumeCommands = lib.mkIf config.storage.generateBase (lib.mkAfter ( - lib.strings.concatLines (builtins.map (user: "zfs rollback -r rpool/ephemeral/home/${user.name}@blank") - normalUsers) - )); - - # TODO: I don't think we need this anymore but I have not tested it - # Create persist home directories with proper permissions - # systemd = { - # tmpfiles.rules = - # builtins.map ( - # user: "d /persist/replicate/home/${user.name} 700 ${user.name} ${user.name} -" - # ) - # normalUsers; - # }; - }) - ])) + ) + ); + }) ]; } diff --git a/modules/system-modules/users.nix b/modules/system-modules/users.nix index cd9c900..dda9ed3 100644 --- a/modules/system-modules/users.nix +++ b/modules/system-modules/users.nix @@ -89,6 +89,11 @@ in { isDesktopUser = lib.mkDefault false; isTerminalUser = lib.mkDefault false; }; + ivy = { + isPrincipleUser = lib.mkDefault false; + isDesktopUser = lib.mkDefault false; + isTerminalUser = lib.mkDefault false; + }; }; assertions = diff --git a/nix-config-secrets b/nix-config-secrets index 22be815..444229a 160000 --- a/nix-config-secrets +++ b/nix-config-secrets @@ -1 +1 @@ -Subproject commit 22be81505a49cd205e9b5c91f51af69c0b885ed3 +Subproject commit 444229a105445339fb028d15a8d866063c5f8141 diff --git a/util/default.nix b/util/default.nix index d72d00d..66e300b 100644 --- a/util/default.nix +++ b/util/default.nix @@ -10,7 +10,7 @@ nix-syncthing = inputs.nix-syncthing; disko = inputs.disko; impermanence = inputs.impermanence; - # lix-module = inputs.lix-module; + lix-module = inputs.lix-module; systems = [ "aarch64-darwin" @@ -29,6 +29,7 @@ common-modules ++ [ sops-nix.homeManagerModules.sops + impermanence.homeManagerModules.impermanence ../modules/home-manager-modules ];