screentinker/server
ScreenTinker 8ad2258e7c feat: app-ending signal (exit-signal contract v1) — server + APK + .wgt + /player
Best-effort "last gasp" so Offline is annotated with WHY it went away — completing the liveness story.
Categories: crashed (client uncaught-exception), clean_exit (client confident lifecycle-end, best-effort),
silent (SERVER-inferred by absence — the honest catch-all for violent/external death incl. force-stop/MDM).

SERVER:
- device:exit socket handler + token-authed beacon POST /api/device/exit (reliable-on-unload). Both gated
  by liveness.sanitizeExitReason (honesty: only crashed/clean_exit accepted; 'silent'/unknown rejected).
- offline_reason/offline_reason_at/offline_detail columns (additive migration). Clear-on-online (a reason
  is always THIS session's); offline transition COALESCEs to 'silent'. Pure annotation — offline detection
  and #148/liveness are untouched. Offline dashboard emits carry offline_reason + client_type.
CLIENTS (canonical {reason,detail} shape):
- /player: window error/unhandledrejection + pagehide(persisted=false) -> sendBeacon.
- .wgt: same + BACK-key exit -> socket.emit + sendBeacon.
- APK: global UncaughtExceptionHandler -> crashed (blocking beacon, chains to default); Service.onDestroy
  -> clean_exit (socket + bounded beacon). New ExitSignal.kt. onStop/onPause NOT wired (background != exit).
Proven (Phase 3): per-category classification, nothing misclassified, external kill -> silent (never
clean_exit), backgrounding emits no false exit, #148/reconnect-vs-exit intact. 382/382 suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 15:32:40 -05:00
..
config PiP overlay MVP: push image/web overlays to a device or group (#109) (#127) 2026-06-18 14:54:44 -05:00
db feat: app-ending signal (exit-signal contract v1) — server + APK + .wgt + /player 2026-07-08 15:32:40 -05:00
lib feat: app-ending signal (exit-signal contract v1) — server + APK + .wgt + /player 2026-07-08 15:32:40 -05:00
middleware feat(#146): billing:read scoped token — dual-path auth for the Usage Report (Option C) 2026-07-01 21:16:21 -05:00
player feat: app-ending signal (exit-signal contract v1) — server + APK + .wgt + /player 2026-07-08 15:32:40 -05:00
routes feat(#150): preserve per-device settings across delete+re-pair (fingerprint-keyed) 2026-07-07 12:40:47 -05:00
scripts feat(scheduling): per-item schedule blocks (#74 dayparting, #75 auto-expire) 2026-06-11 15:46:41 -05:00
services feat: app-ending signal (exit-signal contract v1) — server + APK + .wgt + /player 2026-07-08 15:32:40 -05:00
test feat: app-ending signal (exit-signal contract v1) — server + APK + .wgt + /player 2026-07-08 15:32:40 -05:00
ws feat: app-ending signal (exit-signal contract v1) — server + APK + .wgt + /player 2026-07-08 15:32:40 -05:00
.gitignore feat(email): Microsoft Graph send + alert spam protection + preferences UI 2026-05-12 18:16:40 -05:00
config.js fix(db): WAL checkpointer worker-death handling (respawn + inline-autocheckpoint fallback) 2026-07-06 23:50:18 -05:00
package-lock.json chore(release): v1.9.2-patch3 2026-07-06 23:51:44 -05:00
package.json chore(release): v1.9.2-patch3 2026-07-06 23:51:44 -05:00
server.js feat: app-ending signal (exit-signal contract v1) — server + APK + .wgt + /player 2026-07-08 15:32:40 -05:00
version.js chore(version): single-source VERSION, env-configurable data paths, bump tooling 2026-06-10 12:56:03 -05:00