Packaging papra, a pnpm application

Hello, I am trying to package GitHub - papra-hq/papra: The minimalistic document archiving platform. but I am having issues.
This is my latest attempt:

{
  makeBinaryWrapper,
  nodejs,
  fetchPnpmDeps,
  fetchFromGitHub,
  pnpm_10,
  pnpmConfigHook,
  stdenv,
  breakpointHook,
  lib,
  ...
}:
let
  pnpm = pnpm_10;
in
stdenv.mkDerivation (finalAttrs: {
  pname = "papra";
  version = "26.1.0";
  src = fetchFromGitHub {
    owner = "papra-hq";
    repo = "papra";
    rev = "@papra/app@${finalAttrs.version}";
    hash = "sha256-erFJoOv/e46juheFaiNaVb8PhW778vUgcA3a8moeS+k=";
  };

  nativeBuildInputs = [
    makeBinaryWrapper
    nodejs
    pnpmConfigHook
    pnpm
    # breakpointHook
  ];

  buildPhase = ''
    runHook preBuild

    pnpm --filter "@papra/app-client..." run build
    pnpm --filter "@papra/app-server..." run build

    runHook postBuild
  '';

  installPhase = ''
    runHook preInstall

    mkdir -p $out/bin
    mkdir -p $out/lib

    pnpm deploy --filter=@papra/app-server --legacy --prod $out/lib/

    mkdir -p $out/lib/public
    cp -r apps/papra-client/dist/* $out/lib/public/

    # chmod +x $out/share/index.js
    makeWrapper "${lib.getExe nodejs}" $out/bin/papra \
      --add-flags "$out/lib/index.js"

    runHook postInstall
  '';

  pnpmDeps = fetchPnpmDeps {
    inherit (finalAttrs) pname version src;
    pnpm = pnpm;
    fetcherVersion = 3;
    hash = "sha256-Rs9b30v+WUCZ/6zeavEDw9xVuSff+QcCsWLvnPvi4RY=";
    pnpmWorkspaces = [
      "@papra/app-client..."
      "@papra/app-server..."
    ];
  };
})

The build step succeeds but the install step fails with:

Running phase: installPhase
@nix { "action": "setPhase", "phase": "installPhase" }
e[43me[30m WARN e[39me[49m Shared workspace lockfile detected but configuration forces legacy deploy implementation.
.                                        | e[43me[30m WARN e[39me[49m A pnpm-lock.yaml file exists. The current configuration prohibits to read or write a lockfile
Packages are copied from the content-addressable store to the virtual store.
  Content-addressable store is at: /build/tmp.nMdaQ5ffV4/v10
  Virtual store is at:             ../../nix/store/mbiakp9qa218yz423p0xqfz9xbz1h91q-papra-26.1.0/lib/node_modules/.pnpm
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@aws-sdk%2Fclient-s3 error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@aws-sdk%2Flib-storage error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@azure%2Fstorage-blob error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@cadence-mq%2Fcore error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@cadence-mq%2Fdriver-libsql error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@cadence-mq%2Fdriver-memory error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@corentinth%2Ffriendly-ids error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@crowlog%2Fasync-context-plugin error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@crowlog%2Flogger error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@hono%2Fnode-server error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@libsql%2Fclient error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@owlrelay%2Fapi-sdk error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@owlrelay%2Fwebhook error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@paralleldrive%2Fcuid2 error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@better-auth%2Fexpo error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@corentinth%2Fchisels error (EAI_AGAIN). Will retry in 10 seconds. 2 retries left.
Progress: resolved e[96m1e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1AProgress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@aws-sdk%2Fclient-s3 error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@aws-sdk%2Flib-storage error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@azure%2Fstorage-blob error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@cadence-mq%2Fcore error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@cadence-mq%2Fdriver-libsql error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@cadence-mq%2Fdriver-memory error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@corentinth%2Ffriendly-ids error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@crowlog%2Fasync-context-plugin error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@crowlog%2Flogger error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@hono%2Fnode-server error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@libsql%2Fclient error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@owlrelay%2Fapi-sdk error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@owlrelay%2Fwebhook error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@paralleldrive%2Fcuid2 error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@better-auth%2Fexpo error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1Ae[43me[30m WARN e[39me[49m GET https://registry.npmjs.org/@corentinth%2Fchisels error (EAI_AGAIN). Will retry in 1 minute. 1 retries left.
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m
e[1A/build/source/apps/papra-server:e[0K
e[41me[30m ERR_PNPM_META_FETCH_FAIL e[39me[49m e[31mGET https://registry.npmjs.org/@aws-sdk%2Fclient-s3: request to https://registry.npmjs.org/@aws-sdk%2Fclient-s3 failed, reason: getaddrinfo EAI_AGAIN registry.npmjs.orge[39m

This error happened while installing a direct dependency of /build/source/apps/papra-server
Progress: resolved e[96m3e[39m, reused e[96m0e[39m, downloaded e[96m0e[39m, added e[96m0e[39m

I am replicating the commands the project uses in its Dockerfile but it sounds like pnpm deploy --filter=@papra/app-server --legacy --prod $out/lib/ doesn’t play nicely with Nix.

Does anyone have any advice on how I could make some progress?

Add the following after runHook preBuild:

    pnpm config set inject-workspace-packages true

    pushd node_modules/sharp
    pnpm run install
    popd

Add node-gyp, python3, pkg-config, and vips to the nativeBuildInputs, remove --legacy from pnpm deploy, and add --set "NODE_PATH" $out/lib/node_modules the wrapProgram call. Add the following before buildPhase to get the web ui to work:

  postPatch = ''
    substituteInPlace apps/papra-server/src/modules/app/static-assets/static-assets.routes.ts \
      --replace-fail "./public" "$out/lib/public"
    substituteInPlace apps/papra-server/src/modules/app/static-assets/static-assets.routes.ts \
      --replace-fail "public/index.html" "$out/lib/public/index.html"
  '';
Final nix package, not well organized
{
  makeBinaryWrapper,
  nodejs,
  node-gyp,
  fetchPnpmDeps,
  fetchFromGitHub,
  pnpm_10,
  pnpmConfigHook,
  stdenv,
  breakpointHookCntr,
  lib,
  vips,
  pkg-config,
  python3,
  ...
}:
let
  pnpm = pnpm_10;
in
stdenv.mkDerivation (finalAttrs: {
  pname = "papra";
  version = "26.1.0";
  src = fetchFromGitHub {
    owner = "papra-hq";
    repo = "papra";
    rev = "@papra/app@${finalAttrs.version}";
    hash = "sha256-erFJoOv/e46juheFaiNaVb8PhW778vUgcA3a8moeS+k=";
  };

  nativeBuildInputs = [
    makeBinaryWrapper
    nodejs
    node-gyp
    pkg-config
    pnpmConfigHook
    pnpm
    vips
    python3
  ];

  env.SHARP_FORCE_GLOBAL_LIBVIPS = 1;
  env.npm_config_nodedir = nodejs;

  postPatch = ''
    substituteInPlace apps/papra-server/src/modules/app/static-assets/static-assets.routes.ts \
      --replace-fail "./public" "$out/lib/public"
    substituteInPlace apps/papra-server/src/modules/app/static-assets/static-assets.routes.ts \
      --replace-fail "public/index.html" "$out/lib/public/index.html"
  '';

  buildPhase = ''
    runHook preBuild

    pnpm config set inject-workspace-packages true

    pushd node_modules/sharp
    pnpm run install
    popd

    pnpm --filter "@papra/app-client..." run build
    pnpm --filter "@papra/app-server..." run build

    runHook postBuild
  '';

  installPhase = ''
    runHook preInstall

    mkdir -p $out/bin
    mkdir -p $out/lib

    pnpm deploy --filter=@papra/app-server --prod $out/lib/

    mkdir -p $out/lib/public
    cp -r apps/papra-client/dist/* $out/lib/public/

    # chmod +x $out/share/index.js
    makeWrapper "${lib.getExe nodejs}" $out/bin/papra \
      --add-flags "$out/lib/dist/index.js" \
      --set "NODE_PATH" $out/lib/node_modules

    runHook postInstall
  '';

  pnpmDeps = fetchPnpmDeps {
    inherit (finalAttrs) pname version src;
    pnpm = pnpm;
    fetcherVersion = 3;
    hash = "sha256-Rs9b30v+WUCZ/6zeavEDw9xVuSff+QcCsWLvnPvi4RY=";
    pnpmWorkspaces = [
      "@papra/app-client..."
      "@papra/app-server..."
    ];
  };
})

Thank you, this is very helpful!

1 Like

After you helped me to get the package building (thanks again!) I also created a module and opened a nixpkgs PR papra: init at 26.1.0, nixos/papra: init by wariuccio · Pull Request #485134 · NixOS/nixpkgs · GitHub to upstream both.

I’ll be happy to add you as a co-author if you would like it. And of course any feedback to the PR is welcome, but don’t feel obliged to review

Yes, I would like to be added as co-author. You’re welcome!