Commit graph

3 commits

Author SHA1 Message Date
lila
8aaafea3fc feat: multiplayer slice — end to end working
WebSocket server:
- WS auth via Better Auth session on upgrade request
- Router with discriminated union dispatch and two-layer error handling
- In-memory connections map with broadcastToLobby
- Lobby handlers: join, leave, start
- Game handlers: answer, resolve round, end game, game:ready for state sync
- Shared game state store (LobbyGameStore interface + InMemory impl)
- Timer map separate from store for Valkey-readiness

REST API:
- POST /api/v1/lobbies — create lobby + add host as first player
- POST /api/v1/lobbies/:code/join — atomic join with capacity/status checks
- getLobbyWithPlayers added to model for id-based lookup

Frontend:
- WsClient class with typed on/off, connect/disconnect, isConnected
- WsProvider owns connection lifecycle (connect/disconnect/isConnected state)
- WsConnector component triggers connection at multiplayer layout mount
- Lobby waiting room: live player list, copyable code, host Start button
- Game view: reuses QuestionCard, game:ready on mount, round results
- MultiplayerScoreScreen: sorted scores, winner highlight, tie handling
- Vite proxy: /ws and /api proxied to localhost:3000 for dev cookie fix

Tests:
- lobbyService.test.ts: create, join, retry, idempotency, full lobby
- auth.test.ts: 401 reject, upgrade success, 500 on error
- router.test.ts: dispatch all message types, error handling
- vitest.config.ts: exclude dist folder

Fixes:
- server.ts: server.listen() instead of app.listen() for WS support
- StrictMode removed from main.tsx (incompatible with WS lifecycle)
- getLobbyWithPlayers(id) added for handleLobbyStart lookup
2026-04-18 23:32:21 +02:00
lila
f2eb6ce17f feat(web): add multiplayer lobby, game, and score screen routes
- lobby.$code.tsx: waiting room with live player list via lobby:state,
  copyable lobby code, host Start Game button (disabled until 2+ players),
  sends lobby:join on connect, lobby:leave on unmount
- game.$code.tsx: in-game view, sends game:ready on mount to get current
  question, handles game:question/answer_result/finished messages,
  reuses QuestionCard component, shows round results after each answer
- MultiplayerScoreScreen: final score screen sorted by score, highlights
  winner(s) with crown, handles ties via winnerIds array, Play Again
  navigates back to lobby, Leave goes to multiplayer landing
- GameRouteSearchSchema added to shared for typed lobbyId search param
  without requiring Zod in apps/web
2026-04-18 10:33:48 +02:00
lila
4d4715b4ee feat(web): add multiplayer layout route and landing page
- multiplayer.tsx: layout route wrapping all multiplayer children
  with WsProvider, auth guard via beforeLoad
- multiplayer/index.tsx: create/join landing page
  - POST /api/v1/lobbies to create, navigates to lobby waiting room
  - POST /api/v1/lobbies/:code/join to join, normalizes code to
    uppercase before sending
  - loading states per action, error display, Enter key on join input
  - imports Lobby type from @lila/shared (single source of truth)
2026-04-17 21:33:40 +02:00