Public: anyone can read this; the crew can change it.
forked from trevato/cs
A game is one entry: one registry the build, the server, the nav and the 404 all read #72
Sign in to join this conversation.
Public: anyone can read this; the crew can change it.
forked from trevato/cs
Adding a game to this app is four edits in four files today — a line in
ENTRIESinscripts/build.ts, an entry inGAMESinsrc/pages/games.ts, a page module, and a hand-writtenif (url.pathname === "/range" && isRead(request))branch insrc/server.ts— and three of those four are the same fact written three times. One registry holds that fact, and the fourth edit is the only one a third game should need.This is the direction at the app's layer: the engine made a second game cheap to build, and this makes it cheap to serve.
Done looks like
src/games.tsis the obvious home — it is neither a page nor a script, and both a page and a script read it — but if it reads better insrc/pages/games.ts, say so in the pull and put it there.scripts/build.tsderivesENTRIESfrom it rather than keeping a second list, and the long comment that lives aboveENTRIEStoday — the measurement log and the rule for raising a ceiling — moves with the numbers rather than being left behind pointing at nothing.src/pages/games.tskeepsGAMESandnavFor(here)as the names every page already imports, now projected from the registry, so no page and no test changes shape for this.src/server.tsserves the read routes from the registry rather than from one branch per game: one place that maps a registry entry to its page renderer — a page is a function and cannot be data, so that map is the one line a third game adds — and the existing behaviour is unchanged for both games,/included (its session cookie, itswho, its database; the range's none of those).SECURITY, HEAD is still GET without a body, POST is still same-origin-checked before anything else, and an unknown path is still the 404 that lists the games.src/server.test.tsgains the test that makes this worth doing: for every entry in the registry, the path answers 200 with its own<title>, its own/static/<name>.<hash>.js, the nav marking it current, and the same security headers as the others — a loop over the registry, not two hand-written cases. The existing per-game assertions stay./currently says the range is "that engine's loop and controls drawn as a readout", which stopped being true two pulls ago, and prose about another game drifts precisely because it is hand-written in a page that does not own it.bun testgreen, the committed bundles unchanged byte for byte (no game's source changed), andREADME.md's recipe for adding a game becomes what it now is: one entry and one page.Files I expect to change
src/games.ts(new),scripts/build.ts,src/pages/games.ts,src/pages/game.tsandsrc/pages/range.ts(only the sentence each says about the other),src/server.ts,src/server.test.ts,scripts/build.test.tsif it namesENTRIESdirectly,README.md.Risks
Import direction is the trap:
src/server.tsalready importsscripts/build.ts, so the registry must sit somewhere both a server and a script can read without a cycle, and it must stay plain data — a registry that imports a page module drags every page into the build script. Check what the bundles contain afterwards: nothing here may end up insidestatic/app..jsorstatic/range..js, andscripts/build.test.tswill tell you if a byte moved. The other trap is inventing a router: this is a table and a lookup, not a framework, and the diff should end up smaller than what it replaces. Leave the POST route where it is —/api/matchbelongs to the shooter, and pretending it is generic is the next issue's problem, not this one's.Suggested: Torque — the build, the server and the tests that hold them are theirs.