screentinker/server/lib
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
..
agency-layouts.js feat: agency zone-grant issuance UI + reactive placement card (#73) 2026-06-14 15:12:55 -05:00
agency-targets.js feat(agency): per-token upload folder — auto-created, subtree-confined (#158) (#171) 2026-07-12 21:23:25 -05:00
apk-cache.js Serve a beta APK alongside the stable one, and let a display move between them 2026-07-30 19:12:46 -05:00
apk-signature.js feat(device-owner): tier foundation + QR provisioning + content-expiry & device enhancements (#168) 2026-07-12 19:41:07 -05:00
app-settings.js feat(#146): always-on devices_connected + admin-toggleable /api/status debug block 2026-07-01 18:45:40 -05:00
billing-token.js feat(#146): owner-only CLI to mint billing:read tokens (scripts/mint-billing-token.js) 2026-07-01 21:31:11 -05:00
billing.js feat(#146): usage metering + admin-gated Billable Screens report (contract system-of-record) 2026-07-01 20:45:27 -05:00
bounded-snapshot-store.js fix(widgets): bound the unauthenticated telemetry store, and stop it writing rows 2026-07-26 10:36:09 -05:00
branding.js fix(security): patch quick-win findings from the codebase review 2026-06-08 19:02:19 -05:00
brightsign-package.js autorun.zip must be STORED and opened with roBrightPackage 2026-08-05 11:36:18 -05:00
brightsign-snapshot-queue.js Let a BrightSign host COLLECT its capture request over HTTP 2026-08-07 14:15:06 -05:00
brightsign-update.js Remote screenshots use the framebuffer, and an opted-in tester can move forward 2026-08-05 12:33:34 -05:00
chunked-prune.js fix(#146) A: non-blocking maintenance — chunked+yield+band-gate all sweeps 2026-06-30 20:55:05 -05:00
command-queue.js feat(socket): delivery queue for offline-device emits 2026-05-14 13:06:43 -05:00
content-ack-limiter.js fix(#146) E: log/write self-protection — coalesced logs, batched telemetry, bounded maps 2026-06-30 21:34:01 -05:00
content-ingest.js Drop sharp: pure-JS image ops on a worker thread (#263) 2026-08-13 11:40:13 -05:00
device-identity.js fix(#146) P1.1: resolveIdentity short-circuits on device_id (zero-lookup hot path) 2026-06-30 21:57:55 -05:00
device-sanitize.js Scope device serialization to what each endpoint actually needs 2026-07-27 20:40:40 -05:00
device-settings.js Apply a saved device snapshot only inside the workspace it was taken in 2026-07-30 20:56:59 -05:00
device-timezone.js Store a schedule in the timezone its screen runs in 2026-07-28 09:43:46 -05:00
domain-verify.js SSO: refuse delegated proof names, release lapsed and deleted claims 2026-08-10 21:01:26 -05:00
emailVerify.js feat(auth,tizen): TOTP 2FA UI, email verification on signup, Tizen SSSP install 2026-07-22 21:08:50 -05:00
flap-limiter.js fix(#148) Item 1: exempt paired+authenticated devices from the flap-limiter quarantine 2026-07-02 14:59:25 -05:00
ghcr-check.js feat(dashboard): version indicator + GHCR update check (#165) 2026-07-10 22:40:06 -05:00
image-gen.js feat(ai): generate background + foreground images for signs (#41 Phase 2) 2026-06-09 13:40:14 -05:00
image-ops-core.js Drop sharp: pure-JS image ops on a worker thread (#263) 2026-08-13 11:40:13 -05:00
image-ops-worker.js Drop sharp: pure-JS image ops on a worker thread (#263) 2026-08-13 11:40:13 -05:00
image-ops.js Drop sharp: pure-JS image ops on a worker thread (#263) 2026-08-13 11:40:13 -05:00
incident-classify.js feat(diagnostics): device incident log — offline cause, network-vs-reboot, display-sleep (#175) 2026-07-13 11:26:04 -05:00
item-duration.js Default a video playlist item to the clip's own length (#237) 2026-08-06 09:36:53 -05:00
limiter-telemetry.js Record auth rate-limit rejections so they can be measured 2026-07-28 14:01:00 -05:00
liveness.js QA: close four ways a control or an asset lied about itself 2026-08-06 16:12:29 -05:00
log-coalescer.js fix(#146) P3.7: coalescer carries the PEAK numeric over the window 2026-06-30 22:10:45 -05:00
login-lockout.js feat(auth): bound password login per account, not only per IP 2026-07-26 14:07:16 -05:00
media-mute.js Mute reaches YouTube items — it never did, and failed opposite ways per player 2026-08-05 10:50:59 -05:00
media-orientation.js fix(content+android): rotation-aware media — portrait upright on dashboard AND player (#170) (#172) 2026-07-12 22:05:11 -05:00
media-tools.js Backfill missing thumbnails at boot, and say when ffmpeg is absent 2026-08-07 09:30:32 +01:00
numeric-code.js fix(devices): generate access-gating six-digit codes with a CSPRNG 2026-07-26 14:24:03 -05:00
oidc-providers.js Customer Entra tenants: verify the domain, then be believed 2026-08-11 23:05:25 -05:00
oidc.js SSO: refuse delegated proof names, release lapsed and deleted claims 2026-08-10 21:01:26 -05:00
orientation-style.js Preview a rotated display the way people see it, not the way its framebuffer is 2026-08-06 09:38:31 -05:00
ota-breaker.js Serve a beta APK alongside the stable one, and let a display move between them 2026-07-30 19:12:46 -05:00
ota-download-guard.js feat(#146): /api/status.debug throughput counters (gauges -> gauges + work done) 2026-06-30 23:24:32 -05:00
pair-lockout.js fix(pairing): expire a pairing code on device liveness, not row age 2026-07-27 10:59:38 -05:00
parse-size.js Parse MAX_FILE_SIZE, and document what else caps an upload 2026-07-28 20:40:14 -05:00
passwordReset.js feat(auth): self-service password reset 2026-07-27 11:19:39 -05:00
permissions.js feat(roles): add cross-org platform_operator staff role (#13) 2026-06-05 10:30:21 -05:00
player-cache-policy.js Offline media on every player, and a revision so the cache can still be updated 2026-08-05 15:27:36 -05:00
player-capabilities.js A baseline moves when the fix reaches SCREENS, which is not one rule 2026-08-06 22:54:45 -05:00
player-media-health.js Export shared modules to the browser even when Node is in the page 2026-08-07 10:36:50 -05:00
preflight-deps.js Pin better-sqlite3 to 12.9.0 (was ^9.4.3) (#264) 2026-08-13 12:18:47 -05:00
public-email-domains.js SSO: fix an account takeover, a remote crash, and login CSRF found in review 2026-08-10 18:12:07 -05:00
reconnect-throttle.js fix(#146): reconnect/heartbeat storm containment (beta5) 2026-06-29 22:12:13 -05:00
recovery-grant.js fix(auth): back break-glass recovery with a revocable, auditable grant 2026-07-26 14:49:03 -05:00
rolling-counter.js feat(#146): /api/status.debug throughput counters (gauges -> gauges + work done) 2026-06-30 23:24:32 -05:00
safe-socket.js fix(#146): crash-hardening — one device's handler throw can't take down the fleet 2026-06-29 23:38:11 -05:00
schedule-eval.js Export shared modules to the browser even when Node is in the page 2026-08-07 10:36:50 -05:00
schema-check.js fix(db): observable migrations + fail-fast schema verification (#37) 2026-06-09 09:31:52 -05:00
secretbox.js feat(ai): AI content design in the Designer, BYO endpoint (#41 Phase 1) 2026-06-09 12:23:55 -05:00
session-settle.js fix(#148) patch2: per-device session-settle debounce — absorb duplicate-socket storms 2026-07-02 19:12:46 -05:00
settings-pin.js The settings PIN can be rotated and set from the dashboard 2026-08-05 13:44:15 -05:00
socket-rooms.js feat(socket): Phase 2.3 workspace-scoped dashboard socket rooms + per-command permission gates. Dashboard namespace was previously a flat broadcast - every connected dashboard received every device's status/screenshot/playback events platform-wide (foreign device names + IPs included). Inbound socket commands gated by a legacy admin/superadmin role check that was dead code post-Phase-1 rename. 2026-05-12 11:34:24 -05:00
ssrf-guard.js feat: transition engine — GL wipes across web, Tizen & Android (+ image↔video) (#204) 2026-07-20 16:45:32 -05:00
status-log-writer.js feat(diagnostics): device incident log — offline cause, network-vs-reboot, display-sleep (#175) 2026-07-13 11:26:04 -05:00
sync-backend.js Drop the user-agent fallback — it could never fire 2026-08-05 10:30:10 -05:00
tcp-keepalive.js fix(#148) Items 2-4: mark-offline closes the socket + tighten ping + TCP keepalive 2026-07-02 14:59:25 -05:00
tenancy.js refactor(auth): drop the unused optionalAuth middleware 2026-07-24 21:03:25 -05:00
tenant-cascade-migration.js fix(db): cascade tenant resources on workspace/org delete (#18 follow-up) 2026-06-08 16:01:52 -05:00
thumbnail-backfill.js Backfill missing thumbnails at boot, and say when ffmpeg is absent 2026-08-07 09:30:32 +01:00
totp-lockout.js feat(server): TOTP primitives - encrypted secret, hashed recovery codes, verify lockout (#100) 2026-06-13 20:48:55 -05:00
totp.js feat(auth,tizen): TOTP 2FA UI, email verification on signup, Tizen SSSP install 2026-07-22 21:08:50 -05:00
transition-bundle.js feat: transition engine — GL wipes across web, Tizen & Android (+ image↔video) (#204) 2026-07-20 16:45:32 -05:00
transition-config.js feat: transition engine — GL wipes across web, Tizen & Android (+ image↔video) (#204) 2026-07-20 16:45:32 -05:00
upload-sniff.js fix(uploads): derive stored type from file content, and never serve uploads as documents 2026-07-25 11:47:09 -05:00
user-deletion.js feat(#150): preserve per-device settings across delete+re-pair (fingerprint-keyed) 2026-07-07 12:40:47 -05:00
wall-geometry.js Describe a portrait video wall as portrait, and stop a wall hiding its screens 2026-08-06 09:46:31 -05:00
wgt-cache.js feat(auth,tizen): TOTP 2FA UI, email verification on signup, Tizen SSSP install 2026-07-22 21:08:50 -05:00
zone-validate.js fix: per-item mute round-trip + multi-zone orphan-zone fallback & warnings 2026-06-22 23:16:29 -05:00