screentinker/server
ScreenTinker e812f35b6b Fail loudly on a missing asset, and stop an empty playlist wiping the cache
Two faults that are live on 1.9.29, both silent, both ending in a dark screen.

A missing upload answered 200 OK with Content-Type: text/html and 15KB of the
dashboard, under the immutable/30-day header the mount sets before it knows
whether the file exists. Every downloader here treats 200 as success, so a panel
stores the page AS the video and caches it for a month; Android validates the
byte count, not the type, so a correctly-sized page passes integrity and is
promoted as a valid asset. Reachable exactly when it hurts — a replace writes a
new random filename and unlinks the old one. Now a 404, with the cache header
removed.

And the service worker treated an empty playlist as "keep nothing". But
`assignments: []` is what the server sends for a device between playlists, for a
playlist never published, and from the catch when a snapshot fails to parse — so
a message that means nothing of the sort deleted every byte of media the panel
held. Only survivable while the uplink is up, i.e. exactly when the cache is
worthless.

Both regression tests drive the whole server or the real worker, because both
bugs live in the relationship between two pieces that are individually correct:
the order of two mounts, and the difference between "needs nothing" and "did not
arrive".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL
2026-08-06 16:31:53 -05:00
..
config fix(logging): gate CF-Connecting-IP on a Cloudflare peer, not any trusted proxy 2026-07-26 10:23:04 -05:00
db Offline media on every player, and a revision so the cache can still be updated 2026-08-05 15:27:36 -05:00
lib Offline media on every player, and a revision so the cache can still be updated 2026-08-05 15:27:36 -05:00
middleware Merge branch 'fix/recovery-grants' into release/auth-campaign 2026-07-26 16:22:59 -05:00
player Fail loudly on a missing asset, and stop an empty playlist wiping the cache 2026-08-06 16:31:53 -05:00
routes Offline media on every player, and a revision so the cache can still be updated 2026-08-05 15:27:36 -05:00
scripts fix(content+android): rotation-aware media — portrait upright on dashboard AND player (#170) (#172) 2026-07-12 22:05:11 -05:00
services Show only the controls a display can actually honour 2026-08-05 14:24:52 -05:00
test Fail loudly on a missing asset, and stop an empty playlist wiping the cache 2026-08-06 16:31:53 -05:00
ws Offline media on every player, and a revision so the cache can still be updated 2026-08-05 15:27:36 -05:00
.gitignore feat(email): Microsoft Graph send + alert spam protection + preferences UI 2026-05-12 18:16:40 -05:00
config.js Add an operator override for self-update on MDM-managed panels 2026-07-28 23:07:30 -05:00
package-lock.json chore(release): v1.9.29 2026-08-06 08:39:26 -05:00
package.json chore(release): v1.9.29 2026-08-06 08:39:26 -05:00
server.js Fail loudly on a missing asset, and stop an empty playlist wiping the cache 2026-08-06 16:31:53 -05:00
smoke-ui.js Keep the smoke test out of npm test, and update the lockfile 2026-07-28 20:34:34 -05:00
version.js chore(version): single-source VERSION, env-configurable data paths, bump tooling 2026-06-10 12:56:03 -05:00