#!/usr/bin/env node /** * Patch the OpenNext worker to add WebSocket handling * Intercepts WebSocket requests before they reach Next.js */ const fs = require('fs') const path = require('path') console.log('🔨 Patching worker to add WebSocket handler...') const workerPath = path.join(__dirname, '../.open-next/worker.js') if (!fs.existsSync(workerPath)) { console.error('❌ Worker file not found at:', workerPath) process.exit(1) } // Read worker file let workerContent = fs.readFileSync(workerPath, 'utf-8') // Check if already patched if (workerContent.includes('// WebSocket Intercept Handler')) { console.log('✅ Worker already patched, skipping') process.exit(0) } // Create WebSocket intercept handler const wsInterceptCode = ` // WebSocket Intercept Handler function handleWebSocketUpgrade(request, env) { const url = new URL(request.url); const upgradeHeader = request.headers.get('Upgrade'); // Check if this is a WebSocket upgrade for agent endpoints if (upgradeHeader === 'websocket' && url.pathname.includes('/api/agent/') && url.pathname.endsWith('/ws')) { // Extract runId from path: /api/agent/{runId}/ws const pathParts = url.pathname.split('/'); const runIdIndex = pathParts.indexOf('agent') + 1; const runId = pathParts[runIdIndex]; if (runId && env.BANDIT_AGENT) { // Forward directly to Durable Object const id = env.BANDIT_AGENT.idFromName(runId); const stub = env.BANDIT_AGENT.get(id); return stub.fetch(request); } } return null; // Not a WebSocket request, continue normal handling } `; // Find where to inject the WebSocket intercept const fetchFunctionStart = workerContent.indexOf('export default {'); if (fetchFunctionStart === -1) { console.error('❌ Could not find export default in worker.js'); process.exit(1); } // Find the async fetch function const asyncFetchStart = workerContent.indexOf('async fetch(request, env, ctx) {', fetchFunctionStart); if (asyncFetchStart === -1) { console.error('❌ Could not find async fetch function in worker.js'); process.exit(1); } // Find the opening brace of the fetch function const fetchBodyStart = workerContent.indexOf('{', asyncFetchStart) + 1; // Find the first return statement in the fetch body const returnStatement = workerContent.indexOf('return', fetchBodyStart); // Insert WebSocket intercept at the beginning of fetch, before the return const patchedContent = workerContent.slice(0, fetchBodyStart) + wsInterceptCode + ` // Check for WebSocket upgrades first (before Next.js) const wsResponse = handleWebSocketUpgrade(request, env); if (wsResponse) { return wsResponse; } ` + workerContent.slice(fetchBodyStart); // Write back fs.writeFileSync(workerPath, patchedContent, 'utf-8'); console.log('✅ Worker patched successfully - WebSocket handler added'); console.log('📝 Note: WebSocket requests now bypass Next.js and go directly to DO');