1+ import type { Buffer } from 'node:buffer'
12import type { IncomingMessage , ServerResponse } from 'node:http'
23import type { ViteDevServer } from 'vite'
34
45const SSE_PATH = '/__hmr_sse'
56const SEND_PATH = '/__hmr_send'
7+ const MAX_POST_BODY = 64 * 1024 // 64KB limit for client messages
68
79export function setupHmrSseBridge ( server : ViteDevServer ) : void {
810 const sseClients = new Set < ServerResponse > ( )
@@ -24,9 +26,14 @@ export function setupHmrSseBridge(server: ViteDevServer): void {
2426 payload = JSON . stringify ( args [ 0 ] )
2527 }
2628
27- // Push to all SSE clients
29+ // Push to all SSE clients (skip errored ones)
2830 for ( const res of sseClients ) {
29- res . write ( `data: ${ payload } \n\n` )
31+ try {
32+ res . write ( `data: ${ payload } \n\n` )
33+ }
34+ catch {
35+ sseClients . delete ( res )
36+ }
3037 }
3138 }
3239
@@ -57,7 +64,6 @@ function handleSseConnection(
5764 'Content-Type' : 'text/event-stream' ,
5865 'Cache-Control' : 'no-cache' ,
5966 'Connection' : 'keep-alive' ,
60- 'Access-Control-Allow-Origin' : '*' ,
6167 } )
6268
6369 // Send initial connected message (same as Vite's WebSocket)
@@ -67,13 +73,19 @@ function handleSseConnection(
6773
6874 // Keep-alive ping every 30s
6975 const keepAlive = setInterval ( ( ) => {
70- res . write ( ': ping\n\n' )
76+ try {
77+ res . write ( ': ping\n\n' )
78+ }
79+ catch { cleanup ( ) }
7180 } , 30000 )
7281
73- res . on ( 'close' , ( ) => {
82+ function cleanup ( ) : void {
7483 clearInterval ( keepAlive )
7584 sseClients . delete ( res )
76- } )
85+ }
86+
87+ res . on ( 'close' , cleanup )
88+ res . on ( 'error' , cleanup )
7789}
7890
7991function handleClientMessage (
@@ -82,10 +94,20 @@ function handleClientMessage(
8294 server : ViteDevServer ,
8395) : void {
8496 let body = ''
97+ let overflow = false
8598 req . on ( 'data' , ( chunk : Buffer ) => {
8699 body += chunk . toString ( )
100+ if ( body . length > MAX_POST_BODY ) {
101+ overflow = true
102+ req . destroy ( )
103+ }
87104 } )
88105 req . on ( 'end' , ( ) => {
106+ if ( overflow ) {
107+ res . writeHead ( 413 )
108+ res . end ( '{"ok":false}' )
109+ return
110+ }
89111 try {
90112 const data = JSON . parse ( body )
91113 // Forward custom events to Vite's HMR server
@@ -102,7 +124,6 @@ function handleClientMessage(
102124 }
103125 res . writeHead ( 200 , {
104126 'Content-Type' : 'application/json' ,
105- 'Access-Control-Allow-Origin' : '*' ,
106127 } )
107128 res . end ( '{"ok":true}' )
108129 }
@@ -237,7 +258,8 @@ export const hmrSseBridgeClientScript = `
237258 PatchedWebSocket.OPEN = 1;
238259 PatchedWebSocket.CLOSING = 2;
239260 PatchedWebSocket.CLOSED = 3;
240- PatchedWebSocket.prototype = OriginalWebSocket.prototype;
261+ PatchedWebSocket.prototype = Object.create(OriginalWebSocket.prototype);
262+ PatchedWebSocket.prototype.constructor = PatchedWebSocket;
241263
242264 window.WebSocket = PatchedWebSocket;
243265})();
0 commit comments