Adding vitest (#124) updated pnpm-lock.yaml (pulled in @standard-schema/spec
and other vitest deps) but the fixed-output pnpmDeps.hash in mkWebapp was
not regenerated, so the build reused the stale offline store and failed
with ERR_PNPM_NO_OFFLINE_TARBALL during `pnpm install --offline`. Rehash
so the deps FOD is refetched from the current lockfile.
Verified: `nix build .#chat` succeeds.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
NixOS consumers (webapp-module's hub build, server-deploy's
standalones module) bake VITE_* env vars into the bundle at build
time: VITE_BASE_PATH for path-mounted standalones,
VITE_LNBITS_BASE_URL / VITE_NOSTR_RELAYS / VITE_LIGHTNING_DOMAIN /
etc. for per-deployment service URLs.
extraEnv is merged on top of the brand kit + sandbox defaults
(BRAND_DIR, BRAND_APP, CI). Brand-controlled vars (VITE_APP_NAME via
brand.name) stay strict — the vite configs internally set
process.env.VITE_APP_NAME from brand.json after the derivation
starts, so an extraEnv attempt at VITE_APP_NAME is a no-op (by
design, per #99 strict-from-the-start). Per-host name customization
flows through per-host brandDir, not env vars.
Verified VITE_BASE_PATH=/events/ via extraEnv emits hrefs prefixed
with /events/ in the built events.html.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mkWebapp was passing the consumer's `pkgs.pnpm_10` into fetchPnpmDeps,
which means the pnpmDeps snapshot is byte-for-byte different across
consumers using different nixpkgs minor versions (flake's
nixos-unstable has pnpm_10@10.34.0, server-deploy's nixpkgs may have
a different 10.x). The pinned hash matches one snapshot exactly, so
the wrong consumer gets:
ERR_PNPM_NO_OFFLINE_TARBALL @vite-pwa/assets-generator-1.0.2.tgz
at deploy time.
Fix: derive a `flakePkgs` from THIS flake's pinned nixpkgs (via
`flakePkgsFor`) and source pnpm, pnpmConfigHook, fetchPnpmDeps,
nodejs, autoPatchelfHook, stdenv, and stdc++ from it. The consumer's
`pkgs` argument is now used only for its system attribute.
Net effect: the pnpmDeps snapshot is now reproducible regardless of
who's calling mkWebapp. The pinned hash
sha256-FUN2lMHsaBTkk1tljDysYZAoQD+5MIBIEvGnRUWiF4s= remains valid (it
was computed against the flake's own nixpkgs originally).
Verified:
- `nix build .#main` — produces same dist/ as before (uses flake pkgs
internally either way)
- `nix build --impure --expr '...lib.mkWebapp { pkgs = <system>; ... }'`
— now succeeds with the system's nixpkgs, where it would fail
before with NO_OFFLINE_TARBALL on @vite-pwa/assets-generator
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two issues found when calling lib.mkWebapp from an external nixpkgs
(server-deploy's scenario):
- pnpm 10 in the sandbox aborts with
ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY when it sees a
modules-purge prompt without a TTY. CI=true is pnpm's documented
bypass; harmless on builds that don't need it.
- Pinning pkgs.pnpm leaves it floating with the consumer's nixpkgs
(flake's nixos-unstable has pnpm 11.5.1, system nixpkgs has 10.33,
etc.). pnpmDeps hash is per-pnpm-version so a floating pnpm means
consumers hit hash mismatches. Pinning pkgs.pnpm_10 locks to the
same major series that produced the lockfile (package.json's
packageManager: pnpm@10.33.0) while still allowing minor drift
inside major-10.
New pnpmDeps hash reflects pnpm_10's snapshot format.
Verified end-to-end: `nix build --impure --expr '...lib.mkWebapp {
brandDir = /tmp/fixture; app = "events"; }'` with an external pkgs
produces a Sortir-branded dist-events (manifest name "Sortir", theme
#dc2626, bg #fff5f5, HTML title "Sortir").
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Establishes the nix build path so deploy/server-deploy can call
inputs.webapp.lib.mkWebapp { brandDir, app } per-host instead of
running its own derivation.
lib.mkWebapp { pkgs, brandDir ? ./branding/default, app ? "main" }
returns a stdenv.mkDerivation that:
- Uses pnpmConfigHook + fetchPnpmDeps (fetcherVersion = 3) to install
node_modules from a hash-pinned snapshot, offline.
- Wires brandDir into the BRAND_DIR env var so vite-branding.ts and
pwa-assets.config.ts resolve the right brand.
- Sets BRAND_APP from `app` so per-standalone overrides
(branding/<dep>/icons/<app>/logo.*) work.
- autoPatchelfHook + stdenv.cc.cc.lib patch the prebuilt
@img/sharp-libvips-linux-x64 binaries to run under the nix sandbox.
- Runs `pnpm run build` for the hub or `pnpm run build:<app>` for a
standalone, then copies the resulting dist/ or dist-<app>/ into $out.
Per-system exposure:
- packages.<app> for each of main/events/wallet/chat/market/forum/
tasks/restaurant/libra — exercises the builder under CI.
- packages.default = packages.main.
Closesaiolabs/webapp#97. Server-deploy hosts can now migrate via
aiolabs/server-deploy#8.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>