#!/usr/bin/env node /** * This script fixes the "wsServer.handleUpgrade is not a function" error in Next.js * by applying a simple monkey patch to the hot-reloader-webpack.js file. */ const fs = require('fs'); const path = require('path'); // Path to the Next.js hot-reloader-webpack.js file const filePath = path.join( process.cwd(), 'node_modules/next/dist/server/dev/hot-reloader-webpack.js' ); // Check if the file exists if (!fs.existsSync(filePath)) { console.error(`File not found: ${filePath}`); process.exit(1); } // Create a backup of the original file if it doesn't exist const backupPath = `${filePath}.backup`; if (!fs.existsSync(backupPath)) { fs.copyFileSync(filePath, backupPath); console.log(`Backup created at ${backupPath}`); } else { // Always restore from backup to ensure clean state fs.copyFileSync(backupPath, filePath); console.log('Restored from backup to ensure clean state'); } // Create a simple patched file with a monkey-patched require for 'ws' const patchedContent = `"use strict"; // Monkey patched module - original is at hot-reloader-webpack.js.backup Object.defineProperty(exports, "__esModule", { value: true }); // Monkey patch the ws module to provide a working handleUpgrade method const originalWs = require('ws'); const originalRequire = module.require; module.require = function(id) { if (id === 'ws') { // Create a patched version of the ws Server const patchedWs = {...originalWs}; const OriginalServer = originalWs.Server; patchedWs.Server = function(options) { const server = new OriginalServer(options); // Ensure handleUpgrade is always available if (!server.handleUpgrade) { server.handleUpgrade = function(request, socket, head, callback) { console.log('Using patched handleUpgrade method'); // Create a new WebSocket and call the callback with it const ws = new originalWs('ws://localhost'); callback(ws); // Prevent socket timeouts socket.on('error', () => {}); socket.on('close', () => {}); }; } return server; }; return patchedWs; } return originalRequire.apply(this, arguments); }; // Load the original file const originalFile = require(${JSON.stringify(backupPath)}); // Export everything from the original file Object.keys(originalFile).forEach(key => { exports[key] = originalFile[key]; }); `; // Write the patched file fs.writeFileSync(filePath, patchedContent); console.log('Next.js WebSocket patch completed successfully'); // Create a simple test file to verify if the patch works const testPath = path.join( process.cwd(), 'scripts/test-ws-patch.js' ); const testContent = ` // Test script to verify if the WebSocket patch works const hotReloader = require('${filePath}'); console.log('Hot reloader loaded successfully'); // Create a mock request, socket and head const req = {}; const socket = { on: (event, callback) => console.log('Socket event:', event) }; const head = {}; // Create a fake HotReloaderWebpack instance const fakeHotReloader = { onHMR: hotReloader.HotReloaderWebpack.prototype.onHMR }; // Try to call the patched onHMR method try { fakeHotReloader.onHMR(req, socket, head); console.log('WebSocket patch works!'); } catch (err) { console.error('WebSocket patch failed:', err); } `; fs.writeFileSync(testPath, testContent); console.log(`Test script created at ${testPath}`); console.log('Run with "node scripts/test-ws-patch.js" to verify the patch'); console.log('\nIMPORTANT: Restart your Next.js server for changes to take effect');