chore: pin Node 20 (LTS) and pnpm 10.34.3

Unpinned `pnpm@latest` in the Dockerfile made fresh builds non-reproducible:
`latest` now resolves to pnpm 11, but the committed lockfile targets pnpm 10, so
`pnpm install --frozen-lockfile` fails with ERR_PNPM_LOCKFILE_CONFIG_MISMATCH on
a clean host. Pin pnpm to 10.34.3 across the Dockerfile, the `packageManager`
field, and the release workflow; pin Node to 20 (LTS) via `.nvmrc` and `engines`
so Docker, CI, and from-source builds all use the same tested toolchain.

Also corrects the docs: the lockfile is v9.0 (requires pnpm 10, not "pnpm 8+"),
and "Node 20+" implied untested newer majors were supported.
This commit is contained in:
Jannis Braun
2026-07-06 01:04:59 +02:00
parent ef020601eb
commit 9d3f72be75
6 changed files with 16 additions and 9 deletions
+1 -1
View File
@@ -67,7 +67,7 @@ jobs:
- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10
version: 10.34.3
- name: Setup Node.js
uses: actions/setup-node@v4
+1
View File
@@ -0,0 +1 @@
20
+3 -1
View File
@@ -40,7 +40,9 @@ Signing is automatic and takes one comment:
## Development setup
Requirements: **Node.js 20+** and **pnpm 8+**.
Requirements: **Node.js 20 (LTS)** and **pnpm 10**. Run `nvm use` (reads
`.nvmrc`); Corepack activates the pinned pnpm from the `packageManager` field
automatically — don't install pnpm globally.
```bash
pnpm install # install all workspace dependencies
+2 -2
View File
@@ -5,7 +5,7 @@
# Stage 1: Install dependencies and build frontend
FROM node:20-slim AS builder
RUN corepack enable && corepack prepare pnpm@latest --activate
RUN corepack enable && corepack prepare pnpm@10.34.3 --activate
WORKDIR /app
@@ -36,7 +36,7 @@ RUN pnpm --filter @backspace/web build
# Stage 2: Production runtime
FROM node:20-slim AS runtime
RUN corepack enable && corepack prepare pnpm@latest --activate
RUN corepack enable && corepack prepare pnpm@10.34.3 --activate
# Install build dependencies for better-sqlite3 native module
RUN apt-get update && \
+6 -3
View File
@@ -8,7 +8,7 @@
[![License: AGPL-3.0](https://img.shields.io/badge/license-AGPL--3.0-3da639.svg)](LICENSE)
[![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6.svg)](https://www.typescriptlang.org/)
[![Node.js](https://img.shields.io/badge/node-%E2%89%A520-339933.svg)](https://nodejs.org/)
[![Node.js](https://img.shields.io/badge/node-20_LTS-339933.svg)](https://nodejs.org/)
[![Version](https://img.shields.io/badge/version-1.0.0-16a34a.svg)](#project-status)
</div>
@@ -257,7 +257,10 @@ The stack runs three services via Docker Compose:
## Development
Requirements: **Node.js 20+** and **pnpm 8+**.
Requirements: **Node.js 20 (LTS)** and **pnpm 10** — both are pinned (`.nvmrc` +
the `packageManager` field), so `nvm use` and Corepack select the right versions
automatically. Newer Node majors are untested; the Docker image always builds on
Node 20 regardless of your host.
```bash
pnpm install
@@ -382,7 +385,7 @@ packages/
| Layer | Technology |
|--------------|------------|
| Server | Node.js 20+, Fastify 4, TypeScript (strict) |
| Server | Node.js 20 (LTS), Fastify 4, TypeScript (strict) |
| Database | SQLite (better-sqlite3) + Drizzle ORM |
| Auth | JWT + bcrypt |
| Frontend | React 18, Vite 6, Tailwind CSS 3, Zustand 5 |
+3 -2
View File
@@ -38,8 +38,9 @@
"uiohook-napi@1.5.5": "patches/uiohook-napi@1.5.5.patch"
}
},
"packageManager": "pnpm@10.34.3",
"engines": {
"node": ">=20.0.0",
"pnpm": ">=8.0.0"
"node": ">=20.0.0 <21.0.0",
"pnpm": ">=10.0.0"
}
}