The nameless viewer may watch the whole tale too

Whole-game share links minted fine and then 404ed: the share page
rebuilds through catchUpSteps, whose seat check never learned the
SPECTATOR exemption momentSteps got — the anonymous viewer held no
seat, so the rebuild refused and the page said "no such replay". The
spectator is now admitted to finished games' full replays, public
knowledge only, same as single turns.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-23 20:57:55 -04:00
co-authored by Claude Fable 5
parent 4ee2a3e5d3
commit c4337e3a7b
+4 -1
View File
@@ -384,7 +384,10 @@ export interface CatchUpStep {
*/
export function catchUpSteps(room: Room, playerId: PlayerId, sinceSeq: number, full = false): CatchUpStep[] | { error: string } {
if (!room.state) return { error: "game not started" };
if (!room.players.includes(playerId)) return { error: "you hold no seat in this room" };
// The SPECTATOR builds whole-game share pages: public knowledge, no seat.
if (playerId !== SPECTATOR && !room.players.includes(playerId)) {
return { error: "you hold no seat in this room" };
}
if (full && room.state.phase !== "finished") return { error: "full replays wait for the game to finish" };
const MAX_STEPS = 200;
const from = full ? 0 : Math.max(sinceSeq, room.log.length - MAX_STEPS);