{ self }: { config, lib, pkgs, ... }: let inherit (lib) mkEnableOption mkIf mkOption types ; cfg = config.services.vibe-proxy; statePath = "/var/lib/${cfg.stateDirectory}"; yaml = pkgs.formats.yaml { }; generatedSettings = lib.recursiveUpdate ( { host = cfg.host; port = cfg.port; auth-dir = "${statePath}/auths"; } // cfg.settings ) { host = cfg.host; port = cfg.port; }; generatedConfig = yaml.generate "vibe-proxy.yaml" generatedSettings; runtimeConfig = if cfg.configFile == null then "${statePath}/config.yaml" else toString cfg.configFile; in { options.services.vibe-proxy = { enable = mkEnableOption "Vibe Proxy"; package = mkOption { type = types.package; default = self.packages.${pkgs.stdenv.hostPlatform.system}.default; defaultText = lib.literalExpression "inputs.vibe-proxy.packages.${pkgs.stdenv.hostPlatform.system}.default"; description = "Vibe Proxy package to run."; }; user = mkOption { type = types.str; default = "vibe-proxy"; description = "User account under which the service runs."; }; group = mkOption { type = types.str; default = "vibe-proxy"; description = "Group under which the service runs."; }; stateDirectory = mkOption { type = types.str; default = "vibe-proxy"; description = "Directory below /var/lib used for writable service state."; }; host = mkOption { type = types.str; default = "127.0.0.1"; description = "Address on which the API listens."; }; port = mkOption { type = types.port; default = 8317; description = "TCP port on which the API listens."; }; openFirewall = mkOption { type = types.bool; default = false; description = "Whether to open the main API port in the firewall."; }; configFile = mkOption { type = types.nullOr types.str; default = null; description = "Writable external configuration file. When null, settings generate the configuration on every service start."; }; settings = mkOption { type = yaml.type; default = { }; description = "Declarative YAML configuration. Secrets in this option are written to the Nix store; use environmentFiles for secrets."; }; environment = mkOption { type = types.attrsOf types.str; default = { }; description = "Non-secret environment variables for the service."; }; environmentFiles = mkOption { type = types.listOf types.path; default = [ ]; description = "Environment files containing secrets such as MANAGEMENT_PASSWORD."; }; }; config = mkIf cfg.enable { users.groups = mkIf (cfg.group == "vibe-proxy") { vibe-proxy = { }; }; users.users = mkIf (cfg.user == "vibe-proxy") { vibe-proxy = { isSystemUser = true; inherit (cfg) group; home = statePath; }; }; networking.firewall.allowedTCPPorts = lib.optional cfg.openFirewall cfg.port; systemd.services.vibe-proxy = { description = "Vibe Proxy API"; wantedBy = [ "multi-user.target" ]; after = [ "network-online.target" ]; wants = [ "network-online.target" ]; environment = { HOME = statePath; WRITABLE_PATH = statePath; } // cfg.environment; preStart = '' ln -sfn ${cfg.package}/share/vibe-proxy/config.example.yaml ${statePath}/config.example.yaml '' + lib.optionalString (cfg.configFile == null) '' install -m 0600 ${generatedConfig} ${runtimeConfig} ''; serviceConfig = { User = cfg.user; Group = cfg.group; StateDirectory = cfg.stateDirectory; StateDirectoryMode = "0700"; WorkingDirectory = statePath; EnvironmentFile = cfg.environmentFiles; ExecStart = "${lib.getExe cfg.package} --config ${lib.escapeShellArg runtimeConfig}"; Restart = "on-failure"; RestartSec = "5s"; UMask = "0077"; NoNewPrivileges = true; PrivateTmp = true; ProtectSystem = "strict"; ProtectHome = true; ReadWritePaths = [ statePath ] ++ lib.optional (cfg.configFile != null) (builtins.dirOf cfg.configFile); }; }; }; }