Skip to content

Rebuild @screenly/edge-apps with failure-mode algorithm and single-file deploy - #5

Open
Sir-Monke wants to merge 3 commits into
masterfrom
rebuild-on-library
Open

Rebuild @screenly/edge-apps with failure-mode algorithm and single-file deploy#5
Sir-Monke wants to merge 3 commits into
masterfrom
rebuild-on-library

Conversation

@Sir-Monke

Copy link
Copy Markdown
Contributor

Description of Changes

Rebuilt on @screenly/edge-apps, scaffolded with the official create command. TypeScript in src/, Bun and Vite, release plumbing per the Edge Apps development doc. index.html is now generated rather than hand-written; the design is unchanged, pixel for pixel.

The failure-mode algorithm. There are no credentials here — the USGS feed is public — so the credential half of the diagram does not apply. What is left:

Feed display_errors Result
OK Cache the ten nearest, draw the closest
Failed on Show the error, draw nothing
Failed off, cache present Draw the last reading received
Failed off, no cache Say it is unavailable

display_errors follows the library exactly: same key, same false default, same panic-overlay, and the same signal-on-error, so a crash cannot stall a playlist. The last row is the diagram's Abort terminal — screenly.signalAbort() does not exist yet (T10903), so for now it states the problem and signals ready anyway, because an app that never signals holds the playlist for sixty seconds and is then dropped with PlaybackReason::LoadTimeout.

Only the ten nearest quakes are cached, trimmed to the five fields drawn — 491 bytes rather than the feed's few megabytes, and a cached render is identical to a live one.

Timings. One clock: an 8s feed timeout. The screenshotter allows 10s for the page to go quiet and 10s more for the ready signal, so timing out early leaves room to fall back to cache, draw and signal. Measured at 8,089 ms to signal on a hung feed.

Single-use values moved into the functions that use them — compass into heading(), the 1500/12000 clamps into widthToFitKept(), the feed URL into load(), units into away().

Release plumbing. CHANGELOG.md, CI and deploy workflows, user_version in the manifest. Drops .ignore — deploying from dist/ makes it unnecessary — and five workflows for Rust, Python and SQL, none of which this repo has ever contained.

  • Are these changes breaking any existing functionality? No. Same design, same behaviour, plus failure handling that was not there before.
  • Have tests been added/updated to cover the changes? e2e/failure-modes.mjs, 24 checks, one per branch of the diagram. bun run verify.

Checklist

  • I have performed a self-review of my own code
  • I have commented on my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Additional Notes/Comments

Two library bugs found on the way, both worth their own issues.

The default build output does not deploy. edge-apps-scripts build emits index.html plus js/ and css/ subdirectories. Deployed as-is, the player sticks in a "downloading content" loop and api/v3/assets/<id>/capture/ returns 500 — with a completely clean browser console, because nothing of the app ever executes. The same app as one file renders on both. Proven across three revisions: 49 (three files) broken, 50 (old single file) fine, 51 (rebuilt, inlined) fine. Root cause not isolated — either the player cannot serve nested asset paths, or type="module" crossorigin fails on it. scripts/inline-bundle.mjs sidesteps both by folding the CSS and JS back into index.html after Vite runs. If this reproduces generally, every app scaffolded today has it.

edge-apps-scripts does not run on Windows. lint, type-check, build, dev and build:dev all fail with "The system cannot find the path specified". resolveBin() returns node_modules/.bin/<tool> with no .cmd or .exe, and execSync/execFileSync route that through cmd.exe, which cannot execute it. CI is unaffected. The README documents the direct-invocation workaround.

Three things must be in place before either workflow can fire, none of which I can do:

  1. master renamed to main — both workflows trigger on main and development per the doc, so while this PR targets master no checks will run on it.
  2. A development branch, for the stage environment.
  3. A SCREENLY_API_TOKEN repo secret.

Two conventions deliberately not adopted, both commented in place with the reason:

  • The library stylesheet is not imported. It inlines three Inter faces as base64 — 444 KB of the 458 KB it emits — and this app is designed on system-ui on purpose. Skipping it takes the CSS from 458 KB to 3.4 KB.
  • <auto-scaler> is not used. It scales a fixed 1920x1080 design, which would letterbox a portrait screen; the map window is fitted to the screen's real aspect ratio instead.

Happy to change either if you would rather have consistency than the behaviour.

- Scaffolded with the official create command: TypeScript in src/, Bun and Vite
  building to dist/, so a deploy uploads three files and nothing else.
- Implements the approved failure-mode diagram. There are no credentials here,
  the USGS feed is public, so only the data half applies: cache on success,
  display_errors on failure, last-known-good otherwise, and an explicit
  unavailable state when there is no cache.
- display_errors follows the library: same key, same false default, same
  panic-overlay, and the same signal-on-error so a crash cannot stall a playlist.
- 8s fetch timeout to fit the screenshotter budget. Measured: signals at 8.1s
  on a hung feed, inside the 10s ready-signal window.
- Single-use values moved into the functions that use them.
- Release plumbing: CHANGELOG.md, CI and deploy workflows, user_version.
- Drops .ignore, since deploying from dist/ makes it unnecessary, and five
  workflows for languages this repo has never contained.

The library stylesheet and auto-scaler are deliberately not used. Both are
commented in place with the reason.

24 failure-mode checks in e2e/failure-modes.mjs, all passing.
Deploying index.html plus ./js and ./css subdirectories does not work: the
player sat in a downloading-content loop and the screenshotter returned 500 on
the asset capture. The same app as one file renders on both. Measured against
revisions 49, 50 and 51.

- scripts/inline-bundle.mjs folds the CSS and JS back into index.html after
  Vite runs, wired as postbuild. It also drops type=module and crossorigin,
  which the IIFE bundle does not need, so there is no subresource fetch and no
  CORS for a player to get wrong.
- stage, map and world were resolved at module top level. As a deferred module
  that happened after parsing and worked by accident; inlined as a classic
  script it runs before <body> exists and all three were null. They are
  resolved in start() instead.

Verified: revision 51 deploys at 1/1 file and renders through Screenly's own
capture endpoint. 24/24 failure-mode checks still pass.
@Sir-Monke
Sir-Monke requested a review from a team as a code owner August 23, 2026 20:23
…heir functions

- jsdom, @types/jsdom, bun-types and @types/bun are scaffold defaults that
  nothing imports. tsconfig's types list is [vite/client, node], so the bun
  types were never loaded either.
- playwright is now an explicit devDependency. e2e/failure-modes.mjs imports it
  by name and was resolving it transitively through @playwright/test, which
  works until that tree changes.
- FETCH_TIMEOUT_MS, REFRESH_MS and KEPT had one use each. Moved into load(),
  start() and nearestKept(), same as compass and the map clamps.

build:prod, build:dev and test:unit are duplicate aliases with no caller here,
but the Edge Apps doc calls for a shared workflow template across repos and it
may invoke them. Left in place deliberately.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant