From 540155788aaa0053527f6929b2e010ad888a8045 Mon Sep 17 00:00:00 2001 From: lila Date: Sat, 18 Apr 2026 21:57:58 +0200 Subject: [PATCH] fix(api): use server.listen instead of app.listen for WebSocket support - server.ts: switch from app.listen() to server.listen() so WebSocket upgrade handler is on the same server as HTTP requests - lobbyService: add host as first player on lobby creation - ws-client: guard against reconnect when already connecting - ws-provider: skip connect if already connected --- apps/api/src/server.ts | 2 +- apps/api/src/services/lobbyService.ts | 4 +++- apps/web/src/lib/ws-client.ts | 8 ++++++++ apps/web/src/lib/ws-provider.tsx | 2 ++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/api/src/server.ts b/apps/api/src/server.ts index c2b6d34..2cdeb0e 100644 --- a/apps/api/src/server.ts +++ b/apps/api/src/server.ts @@ -9,6 +9,6 @@ const server = createServer(app); setupWebSocket(server); -app.listen(PORT, () => { +server.listen(PORT, () => { console.log(`Server listening on port ${PORT}`); }); diff --git a/apps/api/src/services/lobbyService.ts b/apps/api/src/services/lobbyService.ts index 3e307ef..985b776 100644 --- a/apps/api/src/services/lobbyService.ts +++ b/apps/api/src/services/lobbyService.ts @@ -28,7 +28,9 @@ export const createLobby = async (hostUserId: string): Promise => { for (let i = 0; i < MAX_CODE_ATTEMPTS; i++) { const code = generateLobbyCode(); try { - return await createLobbyModel(code, hostUserId); + const lobby = await createLobbyModel(code, hostUserId); + await addPlayer(lobby.id, hostUserId, MAX_LOBBY_PLAYERS); + return lobby; } catch (err) { if (isUniqueViolation(err)) continue; throw err; diff --git a/apps/web/src/lib/ws-client.ts b/apps/web/src/lib/ws-client.ts index f1da6cc..2925a58 100644 --- a/apps/web/src/lib/ws-client.ts +++ b/apps/web/src/lib/ws-client.ts @@ -25,6 +25,14 @@ export class WsClient { public onClose: ((event: CloseEvent) => void) | null = null; connect(apiUrl: string): Promise { + // If already connected or connecting, resolve immediately + if ( + this.ws && + (this.ws.readyState === WebSocket.OPEN || + this.ws.readyState === WebSocket.CONNECTING) + ) { + return Promise.resolve(); + } return new Promise((resolve, reject) => { if (this.ws) { this.ws.close(); diff --git a/apps/web/src/lib/ws-provider.tsx b/apps/web/src/lib/ws-provider.tsx index 1b34bd6..b4a56d3 100644 --- a/apps/web/src/lib/ws-provider.tsx +++ b/apps/web/src/lib/ws-provider.tsx @@ -9,6 +9,8 @@ export const WsProvider = ({ children }: { children: ReactNode }) => { const [isConnected, setIsConnected] = useState(false); const connect = useCallback(async (url: string): Promise => { + if (wsClient.isConnected()) return; + wsClient.onClose = () => setIsConnected(false); wsClient.onError = () => setIsConnected(false); try {