diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e294d99238..ea611ba434 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v6 with: - node-version: 22 + node-version-file: ".nvmrc" cache: npm - name: Install dependencies diff --git a/.node-version b/.node-version index 2bd5a0a98a..a45fd52cc5 100644 --- a/.node-version +++ b/.node-version @@ -1 +1 @@ -22 +24 diff --git a/.nvmrc b/.nvmrc index 2bd5a0a98a..a45fd52cc5 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -22 +24 diff --git a/README.md b/README.md index badd54324c..9d654017dd 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ questions with source citations that link back to the original PDF/document. ## Setup -1. Use Node.js 22.x. CI runs on Node 22, and `.nvmrc` / `.node-version` +1. Use Node.js 24.x. CI runs on Node 24, and `.nvmrc` / `.node-version` pin the same runtime for local version managers. 2. Copy `.env.example` to `.env.local` and fill in Supabase and OpenAI values. 3. Confirm the Supabase target: diff --git a/docs/process-hardening.md b/docs/process-hardening.md index e9814878ee..b1ee87cb46 100644 --- a/docs/process-hardening.md +++ b/docs/process-hardening.md @@ -33,8 +33,8 @@ This document turns the current process review into phased, durable repo practic ## Phase 4 - Release maturity -- `npm run check:runtime` is the strict release runtime gate and is now part of `npm run verify:release`; it fails outside Node 22.x. -- CI runs `npm run check:runtime` after dependency install so branch verification cannot silently drift to Node 24+. +- `npm run check:runtime` is the strict release runtime gate and is now part of `npm run verify:release`; it fails outside Node 24.x. +- CI runs `npm run check:runtime` after dependency install so branch verification cannot silently drift to Node 25+. - Decide whether CI should run all Playwright browser projects on protected branches, release branches, or a scheduled workflow instead of every push. - Add explicit review ownership for clinical source governance, outdated-source handling, incident review, and decommission decisions. - Record production-readiness outcomes in release notes whenever clinical workflow, source governance, privacy, or deployment assumptions change. diff --git a/docs/production-readiness-checklist.md b/docs/production-readiness-checklist.md index 53093d8b82..dc9cda3583 100644 --- a/docs/production-readiness-checklist.md +++ b/docs/production-readiness-checklist.md @@ -3,7 +3,7 @@ This is the runbook to make the app publishable in one focused pass. - Branch: `codex/premium-redesign` (do not touch `.env` / secrets directly). -- Runtime target: Next.js 16.2.7, Node 22.x, npm >= 10. +- Runtime target: Next.js 16.2.7, Node 24.x, npm >= 11. - Supabase target: `sjrfecxgysukkwxsowpy` (`Clinical KB Database`). ## Immediate completion targets @@ -21,7 +21,7 @@ This is the runbook to make the app publishable in one focused pass. - used in CI and non-blocking on local-only secret absence. - [x] Added strict runtime release gate: - `npm run check:runtime` - - enforces Node 22.x before `npm run verify:release`. + - enforces Node 24.x before `npm run verify:release`. ## Remaining high-priority publish items (same day) diff --git a/docs/project-alignment-cleanup.md b/docs/project-alignment-cleanup.md index d408efab55..03581db57c 100644 --- a/docs/project-alignment-cleanup.md +++ b/docs/project-alignment-cleanup.md @@ -10,15 +10,15 @@ ## Dependency verification note - `npm ci` and `npm audit --json` are the release gates for dependency install and security status. -- On Windows with npm 10, `npm ls --depth=0` can report bundled optional wasm/native packages as extraneous immediately after `npm ci`: `@emnapi/core`, `@emnapi/runtime`, `@emnapi/wasi-threads`, `@napi-rs/wasm-runtime`, and `@tybys/wasm-util`. +- On Windows with npm 11, `npm ls --depth=0` can report bundled optional wasm/native packages as extraneous immediately after `npm ci`: `@emnapi/core`, `@emnapi/runtime`, `@emnapi/wasi-threads`, `@napi-rs/wasm-runtime`, and `@tybys/wasm-util`. - `npm explain` traces these packages to optional wasm/native dependency paths from `@tailwindcss/oxide-wasm32-wasi`, `@rolldown/binding-wasm32-wasi`, and `@unrs/resolver-binding-wasm32-wasi`; the lockfile contains those paths and `npm audit --json` reports zero vulnerabilities. - Do not treat this specific `npm ls --depth=0` extraneous output as a hard release blocker unless audit fails, install fails, package versions drift from `package-lock.json`, or a future npm/package update stops reproducing the optional-dependency reporting issue. ## Runtime policy -- CI verifies the project on Node.js 22, so local development should also use Node.js 22.x. -- `.nvmrc`, `.node-version`, and `package.json` `engines` all declare the Node 22 runtime expectation. -- New cleanup or dependency work should be verified on Node 22 before release, even when local shells happen to use newer Node versions. +- CI verifies the project on Node.js 24, so local development should also use Node.js 24.x. +- `.nvmrc`, `.node-version`, and `package.json` `engines` all declare the Node 24 runtime expectation. +- New cleanup or dependency work should be verified on Node 24 before release, even when local shells happen to use newer Node versions. ## Stale branch audit diff --git a/package-lock.json b/package-lock.json index dc0cb812d4..8598c33290 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ }, "devDependencies": { "@tailwindcss/postcss": "^4.3.0", - "@types/node": "^25.9.2", + "@types/node": "^24", "@types/pdf-parse": "^1.1.5", "@types/pdfkit": "^0.17.6", "@types/react": "^19.2.17", @@ -45,8 +45,8 @@ "vitest": "^4.1.8" }, "engines": { - "node": "22.x", - "npm": "10.x" + "node": "24.x", + "npm": "11.x" } }, "node_modules/@alloc/quick-lru": { @@ -2776,13 +2776,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.9.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.2.tgz", - "integrity": "sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw==", + "version": "24.13.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.2.tgz", + "integrity": "sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" + "undici-types": "~7.18.0" } }, "node_modules/@types/pdf-parse": { @@ -9512,9 +9512,9 @@ "license": "MIT" }, "node_modules/undici-types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", - "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index 398e7abbb0..1174650946 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "private": true, "packageManager": "npm@10.9.8", "engines": { - "node": "22.x", - "npm": "10.x" + "node": "24.x", + "npm": "11.x" }, "scripts": { "dev": "node scripts/dev-free-port.mjs", @@ -98,7 +98,7 @@ }, "devDependencies": { "@tailwindcss/postcss": "^4.3.0", - "@types/node": "^25.9.2", + "@types/node": "^24", "@types/pdf-parse": "^1.1.5", "@types/pdfkit": "^0.17.6", "@types/react": "^19.2.17", diff --git a/scripts/check-node-engine.cjs b/scripts/check-node-engine.cjs index 0ea27aa961..fe8ea79538 100644 --- a/scripts/check-node-engine.cjs +++ b/scripts/check-node-engine.cjs @@ -3,12 +3,12 @@ const npmUserAgent = process.env.npm_config_user_agent ?? ""; const npmVersion = npmUserAgent.match(/\bnpm\/(\d+\.\d+\.\d+)/)?.[1] ?? ""; const npmMajor = Number(npmVersion.split(".")[0]); -if (major !== 22) { - console.error(`This project must be installed with Node 22.x. Current runtime: ${process.versions.node}.`); +if (major !== 24) { + console.error(`This project must be installed with Node 24.x. Current runtime: ${process.versions.node}.`); process.exit(1); } -if (npmVersion && npmMajor !== 10) { - console.error(`This project must be installed with npm 10.x. Current npm runtime: ${npmVersion}.`); +if (npmVersion && npmMajor !== 11) { + console.error(`This project must be installed with npm 11.x. Current npm runtime: ${npmVersion}.`); process.exit(1); } diff --git a/scripts/check-runtime.ts b/scripts/check-runtime.ts index f2d81496bd..aab5c30bd3 100644 --- a/scripts/check-runtime.ts +++ b/scripts/check-runtime.ts @@ -43,11 +43,11 @@ function runtimeResult(runtimeName: string, version: string, expectedMajor: numb }; } -export function checkNodeRuntime(version: string, expectedMajor = 22): RuntimeCheckResult { +export function checkNodeRuntime(version: string, expectedMajor = 24): RuntimeCheckResult { return runtimeResult("Node", version, expectedMajor); } -export function checkNpmRuntime(userAgent = process.env.npm_config_user_agent ?? "", expectedMajor = 10): RuntimeCheckResult { +export function checkNpmRuntime(userAgent = process.env.npm_config_user_agent ?? "", expectedMajor = 11): RuntimeCheckResult { if (!userAgent) { return { ok: true, diff --git a/scripts/dev-free-port.mjs b/scripts/dev-free-port.mjs index f2da35facf..ee86c98020 100644 --- a/scripts/dev-free-port.mjs +++ b/scripts/dev-free-port.mjs @@ -5,8 +5,8 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; import { appName, stableProjectPort } from "./local-server-utils.mjs"; -if (Number(process.versions.node.split(".")[0]) !== 22) { - console.error(`Clinical KB local server requires Node 22.x. Current runtime: ${process.versions.node}.`); +if (Number(process.versions.node.split(".")[0]) !== 24) { + console.error(`Clinical KB local server requires Node 24.x. Current runtime: ${process.versions.node}.`); process.exit(1); } diff --git a/scripts/ensure-local-server.mjs b/scripts/ensure-local-server.mjs index cf2a0bb3f9..3d9ffbbb0b 100644 --- a/scripts/ensure-local-server.mjs +++ b/scripts/ensure-local-server.mjs @@ -7,8 +7,8 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; import { appName, localProjectId, projectPortEnd, stableProjectPort } from "./local-server-utils.mjs"; -if (Number(process.versions.node.split(".")[0]) !== 22) { - console.error(`Clinical KB local server requires Node 22.x. Current runtime: ${process.versions.node}.`); +if (Number(process.versions.node.split(".")[0]) !== 24) { + console.error(`Clinical KB local server requires Node 24.x. Current runtime: ${process.versions.node}.`); process.exit(1); } diff --git a/tests/check-runtime.test.ts b/tests/check-runtime.test.ts index 2e2c706d24..f44bc445ea 100644 --- a/tests/check-runtime.test.ts +++ b/tests/check-runtime.test.ts @@ -3,30 +3,30 @@ import { describe, expect, it } from "vitest"; import { checkNodeRuntime, checkNpmRuntime } from "../scripts/check-runtime"; describe("runtime release gate", () => { - it("accepts the Node 22 release target", () => { - expect(checkNodeRuntime("22.22.3")).toMatchObject({ + it("accepts the Node 24 release target", () => { + expect(checkNodeRuntime("24.15.0")).toMatchObject({ ok: true, - expectedMajor: 22, + expectedMajor: 24, }); }); it("rejects older and newer major runtimes", () => { - expect(checkNodeRuntime("21.7.0")).toMatchObject({ ok: false }); - expect(checkNodeRuntime("24.15.0")).toMatchObject({ ok: false }); + expect(checkNodeRuntime("23.11.0")).toMatchObject({ ok: false }); + expect(checkNodeRuntime("25.0.0")).toMatchObject({ ok: false }); }); it("reports unparsable runtime versions as failures", () => { expect(checkNodeRuntime("not-a-version")).toMatchObject({ ok: false }); }); - it("accepts the npm 10 release package manager", () => { - expect(checkNpmRuntime("npm/10.9.8 node/v22.22.3 win32 x64")).toMatchObject({ + it("accepts the npm 11 release package manager", () => { + expect(checkNpmRuntime("npm/11.12.1 node/v24.15.0 win32 x64")).toMatchObject({ ok: true, - expectedMajor: 10, + expectedMajor: 11, }); }); it("rejects newer npm majors for release verification", () => { - expect(checkNpmRuntime("npm/11.17.0 node/v22.22.3 win32 x64")).toMatchObject({ ok: false }); + expect(checkNpmRuntime("npm/12.0.0 node/v24.15.0 win32 x64")).toMatchObject({ ok: false }); }); });