Public: anyone can read this; the crew can change it.
forked from trevato/cs · proposes
Not found is a page, not a fragment: the 404 and the 500 are served through the shell, and a favicon is not a miss #184
Check · Review · Land · Live done — Landed and live in production.
`GET /nope` used to answer 433 bytes of unstyled markup and `error()` one bare `<h1>`; both are now whole documents served through `src/pages/shell.ts`, with the same head, header nav, environment pill, commit and footer every game page has.
shipped production is serving it deploy ae07c2d
Sign in to join this conversation.
new above
offline
GET /nopeused to answer 433 bytes of unstyled markup anderror()one bare<h1>; both are now whole documents served throughsrc/pages/shell.ts, with the same head, header nav, environment pill, commit and footer every game page has.What changed:
PageOptions.scriptis optional and the shell emits no<script>element when it is absent. The existing "the only script is the bundle" test still passes and has a sibling that a scriptless page has no<script>anywhere; the per-game tests asserting exactly one script on/,/rangeand/exampleare untouched and are the guard against a game shipping without its bundle.src/pages/miss.ts— the pages that are not a game. The 404 is a heading, the sentence andlistHtml()from./games.ts, with each link given the nav's 44px through the page's ownextraStyle; the 500 says something went wrong and nothing else — it is never handed the error, so there is no path, stack, runtime or version to leak.listHtml()gained aclass="games"so the miss page can size those links.src/server.tsrenders both once at start-up, like the old fragment, and/nopeanswers in about 0.5 ms at 7 kB. Status codes,text/html; charset=utf-8and the whole security floor are unchanged, the 500 stillconsole.errors the error, and the 404 now goes throughwithoutBodyIfHeadso HEAD on a miss is the status and headers with nothing to read on both call paths (it was already that over HTTP; it is now that when the handler is called directly too).<link rel="icon" href="data:image/svg+xml,…">— a crosshair on the page's background, under 400 bytes — so no browser goes looking for/favicon.ico. No file understatic/, no route, no second request;img-src 'self' data:was already in the CSP.Worth a look:
src/pages/miss.test.ts(both pages checked as documents, and the 500 checked for the markers it must not carry) and the newonErrorexport insrc/server.ts, which is how the 500 is tested — called as a function with an error carrying a path and a stack, rather than leaving a broken route behind. I chose not to add a/favicon.icoroute: a link in the document means the request is never made, and a route would be a second way to serve the same picture.bun testpasses: 814 tests, 0 failures.🤖 Generated with Claude Code
Closes #115