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
31 lines
870 B
TypeScript
31 lines
870 B
TypeScript
import { defineConfig } from "vite";
|
|
import react from "@vitejs/plugin-react";
|
|
import { tanstackRouter } from "@tanstack/router-plugin/vite";
|
|
import tailwindcss from "@tailwindcss/vite";
|
|
|
|
// https://vite.dev/config/
|
|
export default defineConfig({
|
|
plugins: [
|
|
tanstackRouter({ target: "react", autoCodeSplitting: true }),
|
|
react(),
|
|
tailwindcss(),
|
|
],
|
|
server: {
|
|
proxy: {
|
|
"/ws": {
|
|
target: "http://localhost:3000",
|
|
ws: true,
|
|
rewriteWsOrigin: true,
|
|
configure: (proxy) => {
|
|
proxy.on("error", (err) => {
|
|
console.log("[ws proxy error]", err.message);
|
|
});
|
|
proxy.on("proxyReqWs", (_proxyReq, req) => {
|
|
console.log("[ws proxy] forwarding", req.url);
|
|
});
|
|
},
|
|
},
|
|
"/api": { target: "http://localhost:3000", changeOrigin: true },
|
|
},
|
|
},
|
|
});
|