houserules/packages/server/src
Joey Yakimowich-Payne 174cad6ae7
feat(server): layout-aware room.create + resolved layout echoes (Phase C)
Extends the WebSocket protocol so clients can request a specific
starting layout when creating a room, and receive the resolved
layout echoed back on room.created / room.joined.

Protocol additions (Zod):
- room.create.payload.layout: optional discriminated union of
  { kind: "premade", id } | { kind: "fen", fen, name? }
                           | { kind: "custom", pieces, name? }
- room.created / room.joined: new optional 'layout' field with
  resolved { id, name, pieces } — present on new servers, absent
  on legacy ones (backward compat).
- LAYOUT_INVALID error code for validation failures.
- PiecePlacement + ResolvedLayout schemas.

Server implementation:
- New layouts.ts: resolveLayoutRequest() handles premade lookup,
  FEN parse, custom pieces. Chess960 picks a random seed server-
  side (the ultimate authority on 'which position'). Always runs
  validateLayout — invalid input returns LAYOUT_INVALID, never
  mutates room state.
- rooms.ts: Room.layout field + RoomRegistry.createRoom/joinRoom
  accept/return resolved layouts. Default is CLASSIC_LAYOUT.
- game-session.ts: GameSession + GameSessionRegistry.create
  accept StartingLayout; constructs ChessEngine({ layout }).
- broadcast.ts: handleRoomCreate resolves+validates first, rejects
  with LAYOUT_INVALID toast, otherwise threads layout into the
  room + session + response. handleRoomJoin echoes the room's
  stored layout to the joiner.

Chess package:
- packages/chess/src/index.ts exports LAYOUT_REGISTRY, all premade
  layouts, buildChess960Layout, toFen/fromFen, validateLayout,
  and the related types — so server can pull them without
  importing internal module paths.

Tests: 20 new tests (11 in protocol.test.ts for the layout union,
12 in layouts.test.ts for server-side resolution).

1011 tests passing; bun run check clean.

PROTOCOL.md updated with examples of all three layout kinds.
2026-04-18 20:01:01 -06:00
..
broadcast.test.ts feat(server): add reconnection with 60s grace + snapshot resume (P4.7) 2026-04-16 17:38:26 -06:00
broadcast.ts feat(server): layout-aware room.create + resolved layout echoes (Phase C) 2026-04-18 20:01:01 -06:00
game-session.test.ts feat(server): add authoritative game session per room (P4.5) 2026-04-16 17:17:42 -06:00
game-session.ts feat(server): layout-aware room.create + resolved layout echoes (Phase C) 2026-04-18 20:01:01 -06:00
index.ts feat(server): add reconnection with 60s grace + snapshot resume (P4.7) 2026-04-16 17:38:26 -06:00
layouts.test.ts feat(server): layout-aware room.create + resolved layout echoes (Phase C) 2026-04-18 20:01:01 -06:00
layouts.ts feat(server): layout-aware room.create + resolved layout echoes (Phase C) 2026-04-18 20:01:01 -06:00
logger.ts feat(server): scaffold Bun HTTP+WS server with health + logging (P4.1) 2026-04-16 17:03:42 -06:00
logging.test.ts feat(server): add reconnection with 60s grace + snapshot resume (P4.7) 2026-04-16 17:38:26 -06:00
logging.ts feat(server): add reconnection with 60s grace + snapshot resume (P4.7) 2026-04-16 17:38:26 -06:00
middleware.test.ts feat(server): add rate-limit, origin allow-list, message-size cap (P4.4) 2026-04-16 17:11:40 -06:00
middleware.ts feat(server): add rate-limit, origin allow-list, message-size cap (P4.4) 2026-04-16 17:11:40 -06:00
protocol.test.ts feat(server): layout-aware room.create + resolved layout echoes (Phase C) 2026-04-18 20:01:01 -06:00
protocol.ts feat(server): layout-aware room.create + resolved layout echoes (Phase C) 2026-04-18 20:01:01 -06:00
reconnect.test.ts feat(server): add reconnection with 60s grace + snapshot resume (P4.7) 2026-04-16 17:38:26 -06:00
reconnect.ts feat(server): add reconnection with 60s grace + snapshot resume (P4.7) 2026-04-16 17:38:26 -06:00
rooms.test.ts feat(server): add room registry with codes + tokens (P4.3) 2026-04-16 17:09:43 -06:00
rooms.ts feat(server): layout-aware room.create + resolved layout echoes (Phase C) 2026-04-18 20:01:01 -06:00