(deps: SocketServerDeps)
| 46 | } |
| 47 | |
| 48 | export function createSocketServer(deps: SocketServerDeps): { |
| 49 | io: SocketServer |
| 50 | engine: Engine |
| 51 | rpcRegistry: RpcRegistry |
| 52 | } { |
| 53 | const configuration = getConfiguration() |
| 54 | const corsOrigins = deps.corsOrigins ?? configuration.corsOrigins |
| 55 | const allowAllOrigins = corsOrigins.includes('*') |
| 56 | const corsOriginOption = allowAllOrigins ? '*' : corsOrigins |
| 57 | const corsOptions = { |
| 58 | origin: corsOriginOption, |
| 59 | methods: ['GET', 'POST'], |
| 60 | credentials: false |
| 61 | } |
| 62 | |
| 63 | const io = new Server<DefaultEventsMap, DefaultEventsMap, DefaultEventsMap, SocketData>({ |
| 64 | cors: corsOptions |
| 65 | }) |
| 66 | |
| 67 | const engine = new Engine({ |
| 68 | path: '/socket.io/', |
| 69 | cors: corsOptions, |
| 70 | allowRequest: async (req) => { |
| 71 | const origin = req.headers.get('origin') |
| 72 | if (!origin || allowAllOrigins || corsOrigins.includes(origin)) { |
| 73 | return |
| 74 | } |
| 75 | throw 'Origin not allowed' |
| 76 | } |
| 77 | }) |
| 78 | io.bind(engine) |
| 79 | |
| 80 | const rpcRegistry = new RpcRegistry() |
| 81 | const idleTimeoutMs = resolveEnvNumber('HAPI_TERMINAL_IDLE_TIMEOUT_MS', DEFAULT_IDLE_TIMEOUT_MS) |
| 82 | const maxTerminals = resolveEnvNumber('HAPI_TERMINAL_MAX_TERMINALS', DEFAULT_MAX_TERMINALS) |
| 83 | const maxTerminalsPerSocket = maxTerminals |
| 84 | const maxTerminalsPerSession = maxTerminals |
| 85 | const cliNs = io.of('/cli') |
| 86 | const terminalNs = io.of('/terminal') |
| 87 | const terminalRegistry = new TerminalRegistry({ |
| 88 | idleTimeoutMs, |
| 89 | onIdle: (entry) => { |
| 90 | const terminalSocket = terminalNs.sockets.get(entry.socketId) |
| 91 | terminalSocket?.emit('terminal:error', { |
| 92 | terminalId: entry.terminalId, |
| 93 | message: 'Terminal closed due to inactivity.' |
| 94 | }) |
| 95 | const cliSocket = cliNs.sockets.get(entry.cliSocketId) |
| 96 | cliSocket?.emit('terminal:close', { |
| 97 | sessionId: entry.sessionId, |
| 98 | terminalId: entry.terminalId |
| 99 | }) |
| 100 | } |
| 101 | }) |
| 102 | |
| 103 | cliNs.use((socket, next) => { |
| 104 | const auth = socket.handshake.auth as Record<string, unknown> | undefined |
| 105 | const token = typeof auth?.token === 'string' ? auth.token : null |
no test coverage detected