# Changelog ## 1.9.29-rc2 Fixes for three things rc1 only revealed once it was deployed and pointed at real hardware. ### Fixed - **The player assets 404'd in a container.** `/player/st-bridge.js` and `/player/st-sync.js` are served from `../brightsign` so the copy the player loads can never drift from the copy on the player's own storage — but the Dockerfile never copied that directory into the image, so both routes worked from a dev checkout and failed in Docker. Note how this fails when the route is absent entirely: the SPA fallback answers **200 with `text/html`**, so the browser gets a page where it expected JavaScript and the bridge silently never exists. - **A BrightSign kept re-pairing on every boot.** The bridge persisted `device_id` but not `device_token`. The server authenticates a claim to an existing display with the token, so an id presented without one reads as a brand-new player and gets a fresh device row. - **A BrightSign was labelled "Web Player".** It runs the same web player, so `client_type` is `player` and the device view fell through to a hardcoded label — indistinguishable from a browser tab, for a dedicated signage appliance. ### Added - **`autorun.zip` — a single-file player installer**, attached to every release and built by `scripts/build-autorun-zip.sh`. Drop it on the root of a player's storage and power-cycle. - **Booting from internal flash.** A player runs `FLASH:/autorun.brs` with no card present at all, so a failed card slot no longer ends a player's life. Confirmed on an XT245 with a physically dead microSD interface. ## 1.9.29-rc1 **BrightSign port.** The player on BrightSign is the ordinary web player running in an `roHtmlWidget` — that part already worked. This release adds the host around it, which covers what a page cannot do for itself, and a per-group choice of synchronisation protocol. Release candidate: cut for testing on alpha, not for production fleets. ### Added - **`brightsign/autorun.brs` — a supervised host, not a URL wrapper.** It owns the widget lifecycle, because a page-initiated `location.reload()` does not reliably bring an `roHtmlWidget` back: a deploy on 2026-07-28 reloaded every connected player and the BrightSign was the only one that never returned. The page now posts `{type:"restart"}` and the host rebuilds the widget. It also retries `load-error` with backoff, falls back to a local page, and runs a heartbeat watchdog that catches a page which loaded fine and then wedged — the case `load-error` never reports. - **`brightsign/st-bridge.js` — the page's half of that contract**, over `@brightsign/messageport`. Registry-backed identity (the registry outlives `localStorage` on this platform), restart-instead-of-reload, heartbeat, and sync-backend reporting. Every method degrades to a no-op off-platform, so it is served to every player rather than gated on a user agent. - **`brightsign/st-sync.js` — native SyncManager support.** Frame-accurate video sync between BrightSign players via `setSyncParams` on the standard `