{ description = "Nostr relay Prometheus exporter"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11"; }; outputs = { self, nixpkgs }: let inherit (nixpkgs.lib) genAttrs; systems = [ "x86_64-linux" "aarch64-linux" ]; forAllSystems = genAttrs systems; mkPackage = pkgs: let pname = "relay-exporter"; version = "0.1.0"; src = pkgs.lib.cleanSourceWith { src = ./.; filter = path: type: !(pkgs.lib.hasInfix "/.git/" path) && !(pkgs.lib.hasInfix "/node_modules/" path) && !(pkgs.lib.hasInfix "/dist/" path); }; in pkgs.stdenv.mkDerivation { inherit pname version; inherit src; nativeBuildInputs = [ pkgs.nodejs_22 pkgs.pnpm.configHook pkgs.makeWrapper ]; pnpmDeps = pkgs.pnpm.fetchDeps { inherit pname version src; fetcherVersion = 1; hash = "sha256-rZhEXQcRPS5pHdXNfrYeTI3zxkqtJjcyaGgrmzwFaHA="; }; buildPhase = '' runHook preBuild pnpm run build runHook postBuild ''; installPhase = '' runHook preInstall mkdir -p $out/app $out/bin cp -r dist package.json node_modules $out/app/ makeWrapper ${pkgs.nodejs_22}/bin/node $out/bin/relay-exporter \ --set NODE_ENV production \ --add-flags "$out/app/dist/index.js" runHook postInstall ''; meta = { description = "Prometheus exporter for Nostr relay health checks"; mainProgram = "relay-exporter"; license = pkgs.lib.licenses.mit; platforms = pkgs.lib.platforms.linux; }; }; in rec { packages = forAllSystems (system: let pkgs = import nixpkgs { inherit system; }; pkg = mkPackage pkgs; in { relay-exporter = pkg; default = pkg; }); devShells = forAllSystems (system: let pkgs = import nixpkgs { inherit system; }; in { default = pkgs.mkShell { packages = [ pkgs.nodejs_22 pkgs.pnpm_10 ]; }; }); overlays.default = final: prev: { relay-exporter = self.packages.${prev.stdenv.hostPlatform.system}.relay-exporter; }; nixosModules.default = { config, lib, pkgs, ... }: let inherit (lib) mkEnableOption mkIf mkOption types; cfg = config.services.relay-exporter; system = pkgs.stdenv.hostPlatform.system; defaultPackage = self.packages.${system}.relay-exporter; in { options.services.relay-exporter = { enable = mkEnableOption "relay-exporter service"; package = mkOption { type = types.package; default = defaultPackage; defaultText = "self.packages.${system}.relay-exporter"; description = "Derivation that provides relay-exporter."; }; port = mkOption { type = types.port; default = 9464; description = "HTTP listen port for relay-exporter."; }; listenAddr = mkOption { type = types.str; default = "0.0.0.0"; description = "Listen address for relay-exporter."; }; stateDirectory = mkOption { type = types.str; default = "relay-exporter"; description = "Name of the state directory managed by systemd."; }; environment = mkOption { type = types.attrsOf types.str; default = { }; description = "Additional environment variables for relay-exporter."; }; environmentFile = mkOption { type = types.nullOr types.path; default = null; description = "Optional environment file consumed by systemd."; }; }; config = mkIf cfg.enable { systemd.services.relay-exporter = { description = "Nostr relay Prometheus exporter"; wantedBy = [ "multi-user.target" ]; after = [ "network-online.target" ]; wants = [ "network-online.target" ]; environment = { NODE_ENV = "production"; PORT = builtins.toString cfg.port; LISTEN_ADDR = cfg.listenAddr; } // cfg.environment; serviceConfig = { Type = "simple"; ExecStart = "${cfg.package}/bin/relay-exporter"; DynamicUser = true; StateDirectory = cfg.stateDirectory; WorkingDirectory = "/var/lib/${cfg.stateDirectory}"; Restart = "on-failure"; RestartSec = 3; } // lib.optionalAttrs (cfg.environmentFile != null) { EnvironmentFile = cfg.environmentFile; }; }; }; }; }; }