/** * WebSocket upgrade routing. * * Routes incoming HTTP Upgrade requests to the appropriate WebSocket handler * based on the request path and session/topic. Non-matching paths are * destroyed immediately. * * Current routes (all LEGACY — browser HTML client): * /ws → legacy browser client WebSocket endpoint * * Future routes (T-1.5): * /sessions/:id/stream → binary ANSI stream per tmux session * * T-1.5 will extend createUpgradeHandler to accept a session registry and * dispatch to per-session stream handlers. */ import type { IncomingMessage } from "node:http"; import type { Socket } from "node:net"; import type { WsClient, WsServer } from "./types.js"; /** * Create the HTTP `upgrade` event handler. * * @param wss - WebSocket server instance. * @param isAuthenticated - Predicate that checks token/session on the request. * @returns A handler suitable for `httpServer.on("upgrade", handler)`. */ export function createUpgradeHandler( wss: WsServer, isAuthenticated: (req: IncomingMessage) => boolean, ): (request: IncomingMessage, socket: Socket, head: Buffer) => void { return (request: IncomingMessage, socket: Socket, head: Buffer): void => { const url = new URL(request.url ?? "/", "http://localhost"); if (url.pathname === "/ws") { // LEGACY: browser HTML client WebSocket endpoint — auth guard if (!isAuthenticated(request)) { socket.write("HTTP/1.1 403 Forbidden\r\n\r\n"); socket.destroy(); return; } wss.handleUpgrade(request, socket, head, (ws: WsClient) => { wss.emit("connection", ws, request); }); return; } // Unknown upgrade path — reject socket.destroy(); }; }