- Add ws/ directory: server setup, auth, router, connections map - WebSocket auth rejects upgrade with 401 if no Better Auth session - Router parses WsClientMessageSchema, dispatches to handlers, two-layer error handling (AppError -> WsErrorSchema, unknown -> 500) - connections.ts: in-memory Map<lobbyId, Map<userId, WebSocket>> with addConnection, removeConnection, broadcastToLobby - LobbyGameStore interface + InMemoryLobbyGameStore implementation following existing GameSessionStore pattern - multiplayerGameService: generateMultiplayerQuestions() decoupled from single-player flow, hardcoded defaults en->it nouns easy 3 rounds - handleLobbyJoin and handleLobbyLeave implemented - WsErrorSchema added to shared schemas - server.ts switched to createServer + setupWebSocket
32 lines
896 B
TypeScript
32 lines
896 B
TypeScript
import type { IncomingMessage } from "http";
|
|
import type { Duplex } from "stream";
|
|
import type { WebSocketServer, WebSocket } from "ws";
|
|
import { fromNodeHeaders } from "better-auth/node";
|
|
import { auth } from "../lib/auth.js";
|
|
|
|
export const handleUpgrade = async (
|
|
request: IncomingMessage,
|
|
socket: Duplex,
|
|
head: Buffer,
|
|
wss: WebSocketServer,
|
|
): Promise<void> => {
|
|
try {
|
|
const session = await auth.api.getSession({
|
|
headers: fromNodeHeaders(request.headers),
|
|
});
|
|
|
|
if (!session) {
|
|
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
|
|
socket.destroy();
|
|
return;
|
|
}
|
|
|
|
wss.handleUpgrade(request, socket, head, (ws: WebSocket) => {
|
|
wss.emit("connection", ws, request, session);
|
|
});
|
|
} catch (err) {
|
|
console.error("WebSocket auth error:", err);
|
|
socket.write("HTTP/1.1 500 Internal Server Error\r\n\r\n");
|
|
socket.destroy();
|
|
}
|
|
};
|