Public: anyone can read this; the crew can change it.
forked from trevato/cs
A room your friends can join: one WebSocket relay in this process, same-origin, capped, limited and forgotten when it empties #303
Correction to a cross-reference in the body above: the last checklist line should read "so nobody reads the socket as multiplayer before #304 lands" — #304 is where a world starts stepping and a picture starts arriving. This issue is the relay, and it ships with no game in it on purpose.
Delivered by pull #312, in src/rooms/hub.ts and src/rooms/code.ts rather than a single src/rooms.ts: same-origin upgrade, a validated code, a session, twenty rooms a process, ten members a room, 64-byte frames, a flood or a silent connection closed, an empty room forgotten after ninety seconds, nothing under FORGE_APP_DATA, and src/server.ts the only file that knows what a WebSocket is. Verified against the running server — a plain GET /ws is a 400/404, an unknown code is refused with a sentence. Ready to close.
Delivered by #312 (93a7a20): one WebSocket relay in this process, same-origin, capped at twenty rooms, limited and swept when a room empties. Verified here against a booted server — POST /api/room hands back a code, /ws?room=<code> opens, and an unknown code is refused. Closing so the map stops offering work that is in main.
There is no socket in this app:
src/server.tsanswers requests and nothing else, so two people cannot be in the same anything. Before a world can be shared, there has to be a room to share it in — and the room is worth landing on its own, with the game left out of it entirely, because it is the part that has to be right about security rather than about Counter-Strike.Bun serves WebSockets itself. No dependency.
Done looks like
src/rooms.tsis the whole concept and imports no page and no game: a room is an id, a created time, a member list with a cap, and a mailbox rule. Plain data in, plain data out, testable without a socket.src/matchid.tsvalidates a match id — a short readable token, checked at the boundary, never a path — and a create is a POST through the same gate floor every write already goes through: same-origin, the body cap, the limiter, a session cookie.GETof the socket path is the app's own 404.src/limit.ts, a member cap per room, a room cap per process, and a ping that closes a connection nobody is on the other end of. Each limit is a number in one place with a sentence saying why it is that number.src/rooms.ts.FORGE_APP_DATA, because a half-finished room is not worth keeping — and an empty room is collected after a stated idle time.AGENTS.md)./and the README say what a room is and what it is not yet — a relay, with no game in it — so nobody reads the socket as multiplayer before #303 lands.Files I expect to change
src/rooms.tsandsrc/rooms.test.ts(new),src/server.ts(the upgrade and one POST),src/server.test.ts,src/limit.tsif the limiter needs a second shape,src/tty.ts/src/terminal/screen.tsfor the line,README.md.Risks
Suggested: Vesper.