The seats route closes its block and the carried copies of the template's helpers are gone: the server builds again

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCLa2PaEeCj8njQZSWGqHx
This commit is contained in:
Eric WagonerandClaude Fable 5.1 committed 2026-11-10 21:40:14 -05:00
1 parent 29a68f4d9d
commit 8e9f5fb8ce
3 files changed
+3 -63

No files matched your search

+1 -61
View File
@@ -231,67 +231,6 @@ function provenBank(req: IncomingMessage, claimed: unknown, forget: unknown): {
return proven;
}
function send(res: ServerResponse, status: number, body: unknown): void {
res.writeHead(status, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' });
res.end(status === 204 ? undefined : JSON.stringify(body));
}
function readBytes(req: IncomingMessage, limit: number, tooBig: string): Promise<Buffer> {
return new Promise((resolve, reject) => {
const declared = Number(req.headers['content-length'] ?? 0);
if (declared > limit) {
reject(new RoomError(tooBig, 413));
req.destroy();
return;
}
let size = 0;
const chunks: Buffer[] = [];
req.on('data', (chunk: Buffer) => {
size += chunk.length;
if (size > limit) {
reject(new RoomError(tooBig, 413));
req.destroy();
return;
}
chunks.push(chunk);
});
req.on('end', () => resolve(Buffer.concat(chunks)));
req.on('error', reject);
});
}
async function readBody(req: IncomingMessage): Promise<Record<string, unknown>> {
const bytes = await readBytes(req, BODY_LIMIT, 'That is more than a move needs.');
if (bytes.length === 0) return {};
try {
return JSON.parse(bytes.toString('utf8')) as Record<string, unknown>;
} catch {
throw new RoomError('The request was not JSON.');
}
}
/** A report, an answer, or a call to the table is worth waking the keeper for; the desk's own replies are not. */
function ringBell(title: string, detail: { fingerprint: string[]; tags: Record<string, string>; extra: Record<string, unknown> }): void {
Sentry.captureMessage(title, { level: 'error', ...detail });
}
/** The seats a browser claims, kept to the ones its tokens prove. */
function provenSeats(raw: unknown): { roomId: string; seat: string }[] {
const claims = Array.isArray(raw) ? raw.slice(0, 50) : [];
const proven: { roomId: string; seat: string }[] = [];
for (const claim of claims) {
if (typeof claim !== 'object' || claim === null) continue;
const c = claim as Record<string, unknown>;
try {
const room = rooms.get(String(c.roomId ?? ''));
proven.push({ roomId: room.id, seat: rooms.seatOf(room, typeof c.token === 'string' ? c.token : undefined).id });
} catch {
// A seat this browser cannot prove is not its business.
}
}
return proven;
}
/** The seats a browser claims, kept to the ones its tokens prove. */
function provenSeats(raw: unknown): { roomId: string; seat: string }[] {
const claims = Array.isArray(raw) ? raw.slice(0, 50) : [];
@@ -427,6 +366,7 @@ async function handle(req: IncomingMessage, res: ServerResponse): Promise<void>
return send(res, 200, found);
}
throw new RoomError('Not here.', 404);
}
if (parts[0] !== 'api' || parts[1] !== 'rooms') throw new RoomError('Not here.', 404);
if (parts.length === 2 && req.method === 'POST') {
+1 -1
View File
@@ -168,7 +168,7 @@ describe('a seat a browser lost', () => {
rooms.seen(other.room, other.token, 'home');
expect(rooms.findSeats('Bo', 'home', other.room.id).seated.map((s) => s.roomId)).toEqual([other.room.id]);
expect(rooms.findSeats('Bo', 'home').seated.map((s) => s.roomId).sort()).toEqual([other.room.id, room.id].sort());
room.over = true;
room.state!.over = { winner: 'A', reason: 'the test says so' };
expect(rooms.findSeats('Bo', 'home').seated.map((s) => s.roomId)).toEqual([other.room.id]);
});
});
+1 -1
View File
@@ -318,7 +318,7 @@ export class Rooms {
} catch {
continue;
}
if (room.over) continue;
if (room.state?.over) continue;
const seat = room.seats.find((s) => (!s.bot || s.standIn) && s.name.toLowerCase() === wanted);
if (seat) found.push({ room, seat });
}