add nix flake with devShell and native package build
Some checks failed
Docker image / build-and-push-image (push) Has been cancelled

devShell: nodejs_20, pnpm_8, prisma + prisma-engines, sqlite, openssl,
plus the env wiring so prisma uses nix-provided engines instead of
fetching from binaries.prisma.sh.

packages.default: full native build via pnpm_8.fetchDeps + configHook.
Patches the workspace:* ndk spec to the lockfile-resolved ^2.8.1 so
--frozen-lockfile accepts it, then re-runs install with scripts to
trigger bcrypt's node-pre-gyp fallback-to-build (uses python311 since
node-gyp 9.4.1 bundled with pnpm 8 still imports distutils).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-05-25 23:59:31 +02:00
commit 711a017e8c
3 changed files with 201 additions and 0 deletions

27
flake.lock generated Normal file
View file

@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1767313136,
"narHash": "sha256-16KkgfdYqjaeRGBaYsNrhPRRENs0qzkQVUooNHtoy2w=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "ac62194c3917d5f474c1a844b6fd6da2db95077d",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-25.05",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

51
flake.nix Normal file
View file

@ -0,0 +1,51 @@
{
description = "nsecbunkerd Nostr remote signing daemon (NIP-46)";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
outputs = { self, nixpkgs }:
let
systems = [ "x86_64-linux" "aarch64-linux" ];
forAllSystems = nixpkgs.lib.genAttrs systems;
pkgsFor = system: import nixpkgs { inherit system; };
in
{
packages = forAllSystems (system:
let pkgs = pkgsFor system; in
rec {
default = nsecbunkerd;
nsecbunkerd = pkgs.callPackage ./package.nix { };
}
);
devShells = forAllSystems (system:
let pkgs = pkgsFor system; in
{
default = pkgs.mkShell {
packages = with pkgs; [
nodejs_20
pnpm_8
prisma
prisma-engines
python3
gcc
pkg-config
openssl
sqlite
];
shellHook = ''
# Point prisma at the nix-provided engines so it doesn't try to
# download them from binaries.prisma.sh on every install.
export PRISMA_QUERY_ENGINE_BINARY=${pkgs.prisma-engines}/bin/query-engine
export PRISMA_QUERY_ENGINE_LIBRARY=${pkgs.prisma-engines}/lib/libquery_engine.node
export PRISMA_SCHEMA_ENGINE_BINARY=${pkgs.prisma-engines}/bin/schema-engine
export PRISMA_FMT_BINARY=${pkgs.prisma-engines}/bin/prisma-fmt
export PRISMA_INTROSPECTION_ENGINE_BINARY=${pkgs.prisma-engines}/bin/introspection-engine
export PRISMA_CLIENT_ENGINE_TYPE=binary
'';
};
}
);
};
}

123
package.nix Normal file
View file

@ -0,0 +1,123 @@
{
lib,
stdenv,
pnpm_8,
nodejs_20,
makeWrapper,
prisma-engines,
openssl,
sqlite,
python311,
pkg-config,
node-gyp,
}:
let
# package.json pins `@nostr-dev-kit/ndk: "workspace:*"` but the lockfile
# resolves `^2.8.1`. With --frozen-lockfile pnpm refuses the mismatch,
# so rewrite the spec to match the lockfile.
patchNdk = ''
substituteInPlace package.json \
--replace-fail '"@nostr-dev-kit/ndk": "workspace:*"' \
'"@nostr-dev-kit/ndk": "^2.8.1"'
'';
prismaEnv = {
PRISMA_SCHEMA_ENGINE_BINARY = lib.getExe' prisma-engines "schema-engine";
PRISMA_QUERY_ENGINE_BINARY = lib.getExe' prisma-engines "query-engine";
PRISMA_QUERY_ENGINE_LIBRARY = "${prisma-engines}/lib/libquery_engine.node";
PRISMA_INTROSPECTION_ENGINE_BINARY = lib.getExe' prisma-engines "introspection-engine";
PRISMA_FMT_BINARY = lib.getExe' prisma-engines "prisma-fmt";
PRISMA_CLIENT_ENGINE_TYPE = "binary";
};
in
stdenv.mkDerivation (finalAttrs: {
pname = "nsecbunkerd";
version = "0.10.5";
src = ./.;
pnpmDeps = pnpm_8.fetchDeps {
inherit (finalAttrs) pname version src;
fetcherVersion = 2;
prePnpmInstall = patchNdk;
hash = "sha256-dQ+TX5jf1ZQKGoPCZgWaFwpAC3uP6iL1ZSxS0mFNdP8=";
};
postPatch = patchNdk;
nativeBuildInputs = [
pnpm_8.configHook
pnpm_8
nodejs_20
makeWrapper
node-gyp
python311
pkg-config
];
buildInputs = [
openssl
sqlite
];
env = prismaEnv;
buildPhase = ''
runHook preBuild
export npm_config_nodedir=${nodejs_20}
pnpm config set nodedir ${nodejs_20}
# configHook ran with --ignore-scripts; re-run install to trigger
# native-module postinstall (bcrypt). --offline keeps it inside the
# store seeded by configHook.
pnpm install --force --offline --frozen-lockfile --reporter=append-only
pnpm prisma generate
pnpm build
pnpm prune --prod --ignore-scripts
find node_modules -xtype l -delete
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p $out/{bin,share/nsecbunkerd}
cp -r dist node_modules prisma templates package.json \
$out/share/nsecbunkerd/
makeWrapper ${lib.getExe nodejs_20} $out/bin/nsecbunkerd \
--chdir $out/share/nsecbunkerd \
--add-flags $out/share/nsecbunkerd/dist/index.js \
--set NODE_ENV production \
--prefix PATH : ${lib.makeBinPath [ openssl ]} \
${
lib.concatStringsSep " \\\n " (
lib.mapAttrsToList (n: v: "--set ${n} ${lib.escapeShellArg v}") prismaEnv
)
}
makeWrapper ${lib.getExe nodejs_20} $out/bin/nsecbunker-client \
--chdir $out/share/nsecbunkerd \
--add-flags $out/share/nsecbunkerd/dist/client/client.js \
--set NODE_ENV production
runHook postInstall
'';
passthru = {
inherit prisma-engines;
};
meta = {
description = "Nostr remote signing daemon (NIP-46)";
homepage = "https://github.com/kind-0/nsecbunkerd";
license = lib.licenses.mit;
mainProgram = "nsecbunkerd";
platforms = lib.platforms.linux;
};
})