From d0d9bbdf41e59f5e96a19ca1a0e3aff2fa5b5e91 Mon Sep 17 00:00:00 2001 From: Rinse Date: Thu, 3 Sep 2026 02:52:52 +0000 Subject: [PATCH] ci: pin npm 11 so dep bumps stop desyncing the lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Node 22 bundles npm 10.9.x, but this repo is developed on npm 11, and the two disagree on lockfile shape: npm 11 prunes entries (utf-8-validate@5.0.10 and friends) that npm 10 then reports as `Missing from lock file` and refuses to `npm ci`. Every dependency bump therefore had to have its lockfile regenerated with `npx npm@10` or CI failed — 5b1728b did exactly that for the 0.0.92 bump, and #46 hit it again for 0.0.94. Pin npm 11.13.0 in both jobs, declare it via packageManager + engines, and regenerate package-lock.json with npm 11 so the committed lockfile is the shape CI actually installs. Same fix this library's consumers already carry: pubsub-voting-testing-on-real-website dfc1b7f (packageManager + engines + Netlify NPM_VERSION) and pkc-js 516431d98 (the release job). release.yml is pinned too, not just ci.yml: release-it's before:git:release hook runs `npm i --package-lock-only`, so the release bot rewrites the lockfile with whatever npm it has. Pinning only CI would mean every release re-broke master. Verified locally on npm 11.13.0: npm ci, typecheck, typecheck:examples, typecheck:tests, build, 509 unit tests, 12 integration tests — all pass. And `npx npm@10 ci --dry-run` now fails with the EUSAGE/Missing error, confirming the pin is load-bearing rather than decorative. --- .github/workflows/ci.yml | 5 +++ .github/workflows/release.yml | 6 ++++ package-lock.json | 63 ++--------------------------------- package.json | 4 +++ 4 files changed, 18 insertions(+), 60 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d4a2f7f..b3e4cb5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,11 @@ jobs: with: node-version: 22 cache: "npm" + # Node 22 bundles npm 10.9.x, which writes and requires a different lockfile shape + # than the npm 11 used locally (packageManager pins it) — npm 10 demands entries npm + # 11 prunes, so a lockfile regenerated on a dev machine failed `npm ci` here. Pin the + # same npm the repo declares, so CI and local agree. Keep in sync with release.yml. + - run: npm i -g npm@11.13.0 - run: npm ci - run: npm run typecheck - run: npm run typecheck:examples diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 46ecd69..db60a6f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,6 +23,12 @@ jobs: node-version: 22 cache: "npm" + # release-it's version bump rewrites package-lock.json with whatever npm this job + # has (see the before:git:release hook in config/.release-it.json), so it must match + # the npm CI uses or every release desyncs the lockfile and breaks `npm ci` on + # master. Keep in sync with ci.yml. + - run: npm i -g npm@11.13.0 + - run: npm ci - run: npm run build diff --git a/package-lock.json b/package-lock.json index b2876cd..e8a7f26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,6 +44,9 @@ "strip-json-comments": "5.0.3", "typescript": "5.9.3", "vitest": "4.1.11" + }, + "engines": { + "npm": ">=11" } }, "node_modules/@achingbrain/http-parser-js": { @@ -3978,21 +3981,6 @@ "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/@react-native/dev-middleware/node_modules/utf-8-validate": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", - "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, "node_modules/@react-native/dev-middleware/node_modules/ws": { "version": "7.5.11", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", @@ -11479,21 +11467,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/metro/node_modules/utf-8-validate": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", - "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, "node_modules/metro/node_modules/ws": { "version": "7.5.11", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", @@ -13428,21 +13401,6 @@ "ws": "^7" } }, - "node_modules/react-devtools-core/node_modules/utf-8-validate": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", - "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, "node_modules/react-devtools-core/node_modules/ws": { "version": "7.5.11", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", @@ -13581,21 +13539,6 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "license": "MIT" }, - "node_modules/react-native/node_modules/utf-8-validate": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", - "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, "node_modules/react-native/node_modules/ws": { "version": "7.5.11", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", diff --git a/package.json b/package.json index 9f69b4d..cc35a2e 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,10 @@ "description": "Trustless pubsub voting over a shared libp2p/Helia node.", "type": "module", "license": "GPL-3.0-or-later", + "packageManager": "npm@11.13.0", + "engines": { + "npm": ">=11" + }, "repository": { "type": "git", "url": "git+https://github.com/bitsocialnet/pubsub-voting.git"