Public: anyone can read this; the crew can change it.
forked from trevato/cs
The room's two doors are tested where they are opened: POST /api/room and the socket upgrade answer to src/server.test.ts #352
Check · Review · Land · Live done — Landed and live in production.
`src/server.test.ts` grows a section at the end, "the room's two doors", and `src/server.ts` exports one thing it did not before — the hub — so a test can hand a room back; no behaviour changed.
shipped production is serving it deploy ae07c2d
Sign in to join this conversation.
new above
offline
src/server.test.tsgrows a section at the end, "the room's two doors", andsrc/server.tsexports one thing it did not before — the hub — so a test can hand a room back; no behaviour changed.POST /api/roomis now tested at the door: it answers a code asno-storeapplication/jsonwith the whole security floor and the session cookie it arrived with; an unknown map isde_forgeand only the exact wordlongis the long match (the room the hub holds is checked too, rules and all); a cross-origin POST, a GET, a HEAD,{, and a body past the kilobyte cap are all refused and leave no world behind; one caller gets three rooms then a 429 withretry-after: 20; and pastROOM_CAPthe answer is a 503 whose sentence names the cap. The upgrade: noroomis 400 "not a room code", a well-formed code for no room is 404 with its sentence, another site is 403 before the room is even looked up, and a plainGET /ws— with a real code, lower-cased, so it is the upgrade that failed and not the lookup — is the app's own 404 document. The 101 is read off a raw socket inhandshake, because aWebSockethands a page the socket and never the response, and it carries the session cookie and the four floor headers. Then a real client:helloparsed byreadDownand a snapshot applied byapplySnapshotagainst a world carved from the seed it was handed; a name of ten control codes and twenty-six letters comes back as fourteen, which is the door's cut at 24 and not the room's at 20; a text frame of exactlyINPUT_BYTESis dropped while the binary frame behind it drives the seat; and a frame pastMESSAGE_MAXcloses the connection with a code that is the runtime's and never the hub's own 4001.Worth a look: each test takes a session cookie nobody else uses, so
ROOM_LIMIT— three per caller, keyed by address and session — imposes no order on the file and the flood test sits in the middle rather than last. TheROOM_CAPtest fills nineteen rooms through the hub and opens only the twentieth through the route; nineteen POSTs would want seven callers, and nineteen rooms cost 6.5 ms measured, so the limiter picked that and not the clock. Every test closes its sockets and deletes its room, and the last test readshub.roomsandhub.members()to prove it. Ten mutations ofsrc/server.tswere run against the new tests — the cut at 24, the cookie on the 101, the 404 on an unknown code,maxPayloadLength, the upgrade's same-origin check, the room limiter, the map fallback, the length,no-store, the text-frame guard — and each was caught by the test that claims it.Wall time:
bun test src/server.test.tswas 1.10 s for 73 tests and is 1.17 s for 88; the whole suite is 23–25 s before and after, which is its own run-to-run noise. The section lives in this 1,764-line file rather than in a sibling becausebun testuses one process and one module registry: a second file importing./server.tswould share this file's server and, running first, would setFORGE_APP_DATAafter the bundles were built somewhere else — the docstring says so. One thing I did not fix:src/range/boot.test.tsfails about once in twenty-five runs on its own, because the range seeds its targets fromDate.now()(src/range/main.ts:73); that is #351, and it is not this pull's file.🤖 Generated with Claude Code
Closes #335