From a95d8624463a3cd1fc9b547cbd9498c0bb89be84 Mon Sep 17 00:00:00 2001 From: basmith7 Date: Sun, 1 Nov 2026 11:08:22 -0700 Subject: [PATCH 1/2] Run on Node 24 and drop the temporary CA workaround Both image stages move to node:24-alpine; nodejs/node#66871 shipped, so the OS-store CA block goes. engines, @types/node and the esbuild targets follow the runtime. Co-Authored-By: Claude Opus 5.5 --- Dockerfile | 7 ++----- package-lock.json | 18 +++++++++--------- package.json | 2 +- packages/server-node/package.json | 4 ++-- packages/server-node/test/thinker.test.ts | 2 +- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/Dockerfile b/Dockerfile index d163069..8f67a87 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Multi-stage: build the site and bundle the server, then ship only the runtime pieces. -FROM node:22-alpine AS build +FROM node:24-alpine AS build WORKDIR /app COPY package.json package-lock.json ./ COPY packages/engine/package.json packages/engine/ @@ -11,11 +11,8 @@ COPY . . # build:site sets VITE_MULTIPLAYER_URL to "" = same origin (apps/web/src/multiplayer/config.ts). RUN npm run build:site && npm run build --workspace @arcs/server-node -FROM node:22-alpine AS runner +FROM node:24-alpine AS runner WORKDIR /app -# TEMP: revert when nodejs/node#66871 ships (eMudhra CA: use the patched OS store, not Node's roots) -RUN apk upgrade --no-cache ca-certificates-bundle -ENV NODE_OPTIONS=--use-openssl-ca ENV NODE_ENV=production \ PORT=3070 \ DATABASE_PATH=/data/arcs.db \ diff --git a/package-lock.json b/package-lock.json index 982069a..59b3858 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,7 @@ "vitest": "^2.1.0" }, "engines": { - "node": ">=22" + "node": ">=24" } }, "apps/web": { @@ -1955,13 +1955,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.20.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz", - "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==", + "version": "24.19.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.19.2.tgz", + "integrity": "sha512-93d49wCWJkCyN87MxLpNN6KXPCwFw7bVUg79mGUV1OS40JGWwVCr8n61DXCSqz7CV6/VfPkb7xec7uP2M+QHWQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": ">=7.24.0 <7.24.7" } }, "node_modules/@types/prop-types": { @@ -3418,9 +3418,9 @@ } }, "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "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==", "dev": true, "license": "MIT" }, @@ -4201,7 +4201,7 @@ "ws": "^8.18.0" }, "devDependencies": { - "@types/node": "^22.10.0", + "@types/node": "^24", "@types/ws": "^8.5.13", "esbuild": "^0.24.0", "tsx": "^4.19.0" diff --git a/package.json b/package.json index 7d2fd2f..ad248cf 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,6 @@ "vitest": "^2.1.0" }, "engines": { - "node": ">=22" + "node": ">=24" } } diff --git a/packages/server-node/package.json b/packages/server-node/package.json index 3156e4c..9ff7ade 100644 --- a/packages/server-node/package.json +++ b/packages/server-node/package.json @@ -7,7 +7,7 @@ "scripts": { "typecheck": "tsc --noEmit", "dev": "tsx watch --no-warnings=ExperimentalWarning src/main.ts", - "build": "esbuild src/main.ts src/bot-worker.ts --bundle --platform=node --format=esm --target=node22 --external:ws --outdir=dist", + "build": "esbuild src/main.ts src/bot-worker.ts --bundle --platform=node --format=esm --target=node24 --external:ws --outdir=dist", "start": "node --no-warnings=ExperimentalWarning dist/main.js" }, "dependencies": { @@ -16,7 +16,7 @@ "ws": "^8.18.0" }, "devDependencies": { - "@types/node": "^22.10.0", + "@types/node": "^24", "@types/ws": "^8.5.13", "esbuild": "^0.24.0", "tsx": "^4.19.0" diff --git a/packages/server-node/test/thinker.test.ts b/packages/server-node/test/thinker.test.ts index fa90c92..6e73e9a 100644 --- a/packages/server-node/test/thinker.test.ts +++ b/packages/server-node/test/thinker.test.ts @@ -34,7 +34,7 @@ beforeAll(async () => { bundle: true, platform: 'node', format: 'esm', - target: 'node22', + target: 'node24', outfile: join(dir, 'bot-worker.js'), logLevel: 'silent', }) From 095bc439553b45df4dac055130f73e2e909d4882 Mon Sep 17 00:00:00 2001 From: basmith7 Date: Sun, 1 Nov 2026 11:08:37 -0700 Subject: [PATCH 2/2] v0.18.2: changelog entry for Node 24 Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cb3867..c16e1b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Moved from AGENTS.md on 2026-10-08. Newest first. +- **v0.18.2** no app change: the image runs on Node 24 (`node:24-alpine`), and the v0.16.3 CA workaround is gone now that nodejs/node#66871 shipped; `engines`, `@types/node` and the esbuild targets follow - **v0.18.1** no app change: the image is built by the shared `basmith7/workflows` build (`.github/workflows/build.yml`), so it carries its commit and version labels (`deploy-app status arcs` shows them), and it deploys with tower-deploy's `deploy-now` (`.tower-deploy`), which also syncs `docker-compose.prod.yml` to Tower. `scripts/deploy-now.sh` is gone - **v0.18.0** **End turn** sends itself after two minutes (the countdown is on the button) or when you leave the page, and its panel shows which of your moves Start over takes back and which are locked in behind a roll, draw or peek. A move that can't be undone (a card draw, a look at a hand) now asks **Go ahead** first; the battle window's Roll and Reroll say "Can't be undone" on the button instead of asking. The setting is now Settings > Board > Confirm moves (`confirmMoves`; a stored `confirmEndTurn` is ignored, so it reads On again) - **v0.17.0** online, the move that ends your turn waits on your device for **End turn**, with **Undo last move** and **Start over** (back through your own moves this turn, stopping at a dice roll, draw or peek, by the same `takeBackBlock` rule as Undo; Settings > Board > Confirm end of turn, on by default). Private per-seat **Notes** under the log, saved on the server (`seat_note`, `GET`/`POST /games/:id/note`) so a plan follows you between devices. On desktop the log is always a column (the pin toggle and `logPinned` setting are gone, and so is the desktop's turn feed over the map)