import { createServer } from "http"; import { Server as SocketIOServer } from "socket.io"; import type { IncomingMessage, ServerResponse } from "http"; import app, { sessionMiddleware } from "./app"; import { logger } from "./lib/logger"; const rawPort = process.env["PORT"]; if (!rawPort) { throw new Error( "PORT environment variable is required but was not provided.", ); } const port = Number(rawPort); if (Number.isNaN(port) || port <= 0) { throw new Error(`Invalid PORT value: "${rawPort}"`); } const httpServer = createServer(app); export const io = new SocketIOServer(httpServer, { path: "/api/socket.io", cors: { origin: process.env.ALLOWED_ORIGINS ? process.env.ALLOWED_ORIGINS.split(",").map((o) => o.trim()) : true, methods: ["GET", "POST"], credentials: true, }, }); io.engine.use( (req: IncomingMessage, res: ServerResponse, next: (err?: unknown) => void) => { sessionMiddleware(req as Parameters[0], res as Parameters[1], next); }, ); io.use((socket, next) => { const req = socket.request as IncomingMessage & { session?: { userId?: number } }; const userId = req.session?.userId; if (!userId) { return next(new Error("Unauthorized: no session")); } socket.data.userId = userId; next(); }); io.on("connection", (socket) => { const userId = socket.data.userId as number; logger.info({ socketId: socket.id, userId }, "Socket connected"); socket.join(`user:${userId}`); socket.on("disconnect", () => { logger.info({ socketId: socket.id }, "Socket disconnected"); }); }); httpServer.listen(port, () => { logger.info({ port }, "Server listening"); });