diff --git a/server.js b/server.js index 37b546b..4f89231 100644 --- a/server.js +++ b/server.js @@ -79,16 +79,27 @@ class ScriptExecutionHandler { * @param {import('http').Server} server */ constructor(server) { - // Create WebSocketServer attached to server with path filter - // The path option should ensure it only handles /ws/script-execution + // Create WebSocketServer without attaching to server + // We'll handle upgrades manually to avoid interfering with Next.js HMR this.wss = new WebSocketServer({ - server, - path: '/ws/script-execution' + noServer: true }); this.activeExecutions = new Map(); this.db = getDatabase(); this.setupWebSocket(); } + + /** + * Handle WebSocket upgrade for our endpoint + * @param {import('http').IncomingMessage} request + * @param {import('net').Socket} socket + * @param {Buffer} head + */ + handleUpgrade(request, socket, head) { + this.wss.handleUpgrade(request, socket, head, (ws) => { + this.wss.emit('connection', ws, request); + }); + } /** * Parse Container ID from terminal output @@ -1187,6 +1198,33 @@ app.prepare().then(() => { // Create WebSocket handlers const scriptHandler = new ScriptExecutionHandler(httpServer); + + // Handle WebSocket upgrades manually to avoid interfering with Next.js HMR + // We need to preserve Next.js's upgrade handlers and call them for non-matching paths + // Save any existing upgrade listeners (Next.js might have set them up) + const existingUpgradeListeners = httpServer.listeners('upgrade').slice(); + httpServer.removeAllListeners('upgrade'); + + // Add our upgrade handler that routes based on path + httpServer.on('upgrade', (request, socket, head) => { + const parsedUrl = parse(request.url || '', true); + const { pathname } = parsedUrl; + + if (pathname === '/ws/script-execution') { + // Handle our custom WebSocket endpoint + scriptHandler.handleUpgrade(request, socket, head); + } else { + // For all other paths (including Next.js HMR), call existing listeners + // This allows Next.js to handle its own WebSocket upgrades + for (const listener of existingUpgradeListeners) { + try { + listener.call(httpServer, request, socket, head); + } catch (err) { + console.error('Error in upgrade listener:', err); + } + } + } + }); // Note: TerminalHandler removed as it's not being used by the current application httpServer