screentinker/server/package.json
screentinker c436a44c89
Pin better-sqlite3 to 12.9.0 (was ^9.4.3) (#264)
Prepares for the Node 22 move by decoupling it from the database driver, so the
two upgrades land as independently reversible steps rather than one flag day.

9.6.0 cannot work on Node 22. It uses the raw V8 API (220 v8:: references, zero
napi_), so it is ABI-locked per Node major, and its GitHub release assets carry
prebuilds for ABI 108/115/120 only — nothing for Node 22's 127. Its install script
is `prebuild-install || node-gyp rebuild --release`, so on Node 22 it silently
falls through to compiling raw-V8 code against Node 22 headers. That is not just
slow: lib/preflight-deps.js rebuilds synchronously before the server listens, and
prod's systemd unit is TimeoutStartSec=90 with Restart=always, so a slow or failing
compile is an unbootable loop rather than the intended self-heal.

12.9.0 ships prebuilds for BOTH Node 20 (ABI 115) and Node 22 (127), so neither the
current runtime nor the target has to compile anything.

THE PIN IS EXACT ON PURPOSE — ^12.9.0 would defeat it. 12.10.0 dropped the Node 20
prebuild while still advertising "20.x" in engines, so a caret resolves to 12.11.x
and reintroduces the from-source compile on today's runtime. Verified against the
release assets per version:
    12.0.0 / 12.2.0 / 12.4.5 / 12.6.2 / 12.9.0   ABIs 115,127,...
    12.10.0 / 12.10.1 / 12.11.1                  ABIs 127,137,141,147 — no 115
The reasoning is recorded in preflight-deps.js, which is where anyone hitting the
matching failure will already be reading.

13.x was considered and rejected FOR NOW: it is the first N-API release, which ends
the per-major ABI problem for good (8 prebuilds keyed by platform, not ABI) and is
where we should eventually land — but engines is ">=22", so it cannot be adopted
while prod, alpha and CI all run Node 20. It is also three weeks old with three
patch releases, which is young for the one component that owns all the data.

No API changes to absorb: every major from 10 to 13 bumped only for dropping EOL
Node/Electron versions, so the ~1486 .prepare(), 46 .transaction() and 59 .pragma()
call sites are untouched.

Verified on Node 20: installed from a PREBUILT binary (no obj.target, so no
compilation), opens a real database, and the WAL path the #149 checkpointer depends
on still works — journal_mode=WAL engages on a file DB, pragma(...,{simple:false})
returns the expected shape, and a second connection from another handle reads and
runs wal_checkpoint(TRUNCATE). 1649/1649 tests pass.
2026-08-13 12:18:47 -05:00

41 lines
1.1 KiB
JSON

{
"name": "screentinker",
"version": "1.9.34-alpha6",
"description": "ScreenTinker - Digital Signage Management Server",
"main": "server.js",
"scripts": {
"start": "node --env-file-if-exists=.env server.js",
"dev": "node --watch --env-file-if-exists=.env server.js",
"test": "node --test --test-concurrency=2",
"smoke": "node smoke-ui.js"
},
"dependencies": {
"@azure/msal-node": "^5.2.1",
"@jsquash/avif": "^1.3.0",
"@jsquash/webp": "^1.5.0",
"archiver": "^7.0.1",
"bcryptjs": "^3.0.3",
"better-sqlite3": "12.9.0",
"cors": "^2.8.5",
"express": "^4.18.2",
"express-rate-limit": "^8.3.1",
"helmet": "^8.1.0",
"jimp": "^1.6.1",
"jsonwebtoken": "^9.0.3",
"multer": "^1.4.5-lts.1",
"nodemailer": "^6.9.16",
"otplib": "^12.0.1",
"qrcode": "^1.5.4",
"socket.io": "^4.7.2",
"stripe": "^20.4.1",
"unzipper": "^0.12.3",
"uuid": "^14.0.0"
},
"devDependencies": {
"js-yaml": "^4.2.0",
"puppeteer-core": "^24.43.1",
"sharp": "^0.35.3",
"socket.io-client": "^4.8.3"
}
}