diff --git a/server/lib/preflight-deps.js b/server/lib/preflight-deps.js index 9be7249..e65cf26 100644 --- a/server/lib/preflight-deps.js +++ b/server/lib/preflight-deps.js @@ -14,6 +14,18 @@ * NODE UPGRADE better-sqlite3 is a native module compiled against one ABI. Upgrading Node makes * every boot fail with NODE_MODULE_VERSION mismatch, which reads like database * corruption and is not. + * + * ⚠️ better-sqlite3 is pinned to EXACTLY 12.9.0, not a caret range, and the reason + * is invisible from package.json: 12.10.0 DROPPED the prebuilt binary for Node 20 + * (ABI 115) while still advertising `"node": "20.x || ..."` in engines. So a caret + * resolves to 12.11.x, finds no prebuild on Node 20, and silently falls through to + * `node-gyp rebuild` — a from-source compile during install, and during the repair + * below. That matters here: this file rebuilds synchronously BEFORE the server + * listens, and prod's systemd unit has TimeoutStartSec=90 with Restart=always, so a + * slow or failing compile is a boot loop rather than a self-heal. 12.9.0 is the last + * version shipping prebuilds for BOTH Node 20 (115) and Node 22 (127), which is what + * lets the runtime move without the module having to compile at all. + * Re-check the release assets before widening the pin. * HAND EDITS a `git checkout`, a partly-copied tree, an interrupted install. * * All three present as a server that will not start, with an error that names a file rather than diff --git a/server/package-lock.json b/server/package-lock.json index ff95a92..e2c9469 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -13,7 +13,7 @@ "@jsquash/webp": "^1.5.0", "archiver": "^7.0.1", "bcryptjs": "^3.0.3", - "better-sqlite3": "^9.4.3", + "better-sqlite3": "12.9.0", "cors": "^2.8.5", "express": "^4.18.2", "express-rate-limit": "^8.3.1", @@ -24,7 +24,6 @@ "nodemailer": "^6.9.16", "otplib": "^12.0.1", "qrcode": "^1.5.4", - "sharp": "^0.35.3", "socket.io": "^4.7.2", "stripe": "^20.4.1", "unzipper": "^0.12.3", @@ -33,6 +32,7 @@ "devDependencies": { "js-yaml": "^4.2.0", "puppeteer-core": "^24.43.1", + "sharp": "^0.35.3", "socket.io-client": "^4.8.3" } }, @@ -72,6 +72,7 @@ "version": "1.11.3", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -82,6 +83,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -94,6 +96,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -116,6 +119,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -135,6 +139,7 @@ "version": "0.35.3", "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -157,6 +162,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -173,6 +179,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -189,6 +196,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -205,6 +213,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -221,6 +230,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -237,6 +247,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -253,6 +264,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -269,6 +281,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -285,6 +298,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -301,6 +315,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -317,6 +332,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -339,6 +355,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -361,6 +378,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -383,6 +401,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -405,6 +424,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -427,6 +447,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -449,6 +470,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -471,6 +493,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0", "optional": true, "os": [ @@ -490,6 +513,7 @@ "version": "0.35.3", "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, "dependencies": { @@ -509,6 +533,7 @@ "cpu": [ "wasm32" ], + "dev": true, "license": "Apache-2.0", "optional": true, "dependencies": { @@ -528,6 +553,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -547,6 +573,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -566,6 +593,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ @@ -1829,14 +1857,17 @@ } }, "node_modules/better-sqlite3": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-9.6.0.tgz", - "integrity": "sha512-yR5HATnqeYNVnkaUTf4bOP2dJSnyhP4puJN/QPRyx4YkBEEUxib422n2XzPqDEHjQQqazoYoADdAm5vE15+dAQ==", + "version": "12.9.0", + "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.9.0.tgz", + "integrity": "sha512-wqUv4Gm3toFpHDQmaKD4QhZm3g1DjUBI0yzS4UBl6lElUmXFYdTQmmEDpAFa5o8FiFiymURypEnfVHzILKaxqQ==", "hasInstallScript": true, "license": "MIT", "dependencies": { "bindings": "^1.5.0", "prebuild-install": "^7.1.1" + }, + "engines": { + "node": "20.x || 22.x || 23.x || 24.x || 25.x" } }, "node_modules/bindings": { @@ -4591,6 +4622,7 @@ "version": "0.35.3", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.3.tgz", "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@img/colour": "^1.1.0", @@ -5309,7 +5341,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "devOptional": true, + "dev": true, "license": "0BSD" }, "node_modules/tunnel-agent": { diff --git a/server/package.json b/server/package.json index 3d96a68..2a5cfc5 100644 --- a/server/package.json +++ b/server/package.json @@ -15,7 +15,7 @@ "@jsquash/webp": "^1.5.0", "archiver": "^7.0.1", "bcryptjs": "^3.0.3", - "better-sqlite3": "^9.4.3", + "better-sqlite3": "12.9.0", "cors": "^2.8.5", "express": "^4.18.2", "express-rate-limit": "^8.3.1",