@@ -191,6 +191,62 @@ function emitWebSocketClosed(ws) {
191191 ws [ _inspectorRequestId ] = undefined ;
192192}
193193
194+ // Opcodes per RFC 6455 / CDP `WebSocketFrame.opcode`:
195+ // 1 = text, 2 = binary. Per RFC 6455 client-to-server frames are masked,
196+ // server-to-client are not - so the `mask` flag depends on direction and
197+ // role: a CLIENT socket masks what it sends, a SERVER socket sees masked
198+ // frames coming in.
199+ function emitWebSocketFrame ( ws , eventName , opcode , payloadData ) {
200+ const ins = getInspectorNetwork ( ) ;
201+ const requestId = ws [ _inspectorRequestId ] ;
202+ if ( ins === null || requestId === undefined ) return ;
203+ const sent = eventName === "frameSent" ;
204+ const mask = ws [ _role ] === SERVER ? ! sent : sent ;
205+ try {
206+ const params = {
207+ requestId,
208+ timestamp : DateNow ( ) / 1000 ,
209+ response : { opcode, mask, payloadData } ,
210+ } ;
211+ if ( sent ) ins . webSocketFrameSent ( params ) ;
212+ else ins . webSocketFrameReceived ( params ) ;
213+ } catch {
214+ // never let inspector instrumentation break a real WebSocket
215+ }
216+ }
217+
218+ // Called by ext/http's `upgradeWebSocket` after a successful handshake, so
219+ // server-accepted sockets show up in the inspector's Network panel and
220+ // the frame emitters in `_eventLoop` / `send` start firing for them.
221+ // Handshake events (`willSendHandshakeRequest`, `handshakeResponseReceived`)
222+ // are intentionally skipped here - those are client-side concepts.
223+ function installServerInspector ( ws , url ) {
224+ const ins = getInspectorNetwork ( ) ;
225+ if ( ins === null ) return ;
226+ const requestId = ins . nextRequestId ( ) ;
227+ ws [ _inspectorRequestId ] = requestId ;
228+ try {
229+ ins . webSocketCreated ( { requestId, url } ) ;
230+ } catch {
231+ // never let inspector instrumentation break a real WebSocket
232+ }
233+ }
234+
235+ function emitWebSocketFrameError ( ws , errorMessage ) {
236+ const ins = getInspectorNetwork ( ) ;
237+ const requestId = ws [ _inspectorRequestId ] ;
238+ if ( ins === null || requestId === undefined ) return ;
239+ try {
240+ ins . webSocketFrameError ( {
241+ requestId,
242+ timestamp : DateNow ( ) / 1000 ,
243+ errorMessage,
244+ } ) ;
245+ } catch {
246+ // never let inspector instrumentation break a real WebSocket
247+ }
248+ }
249+
194250class WebSocket extends EventTarget {
195251 constructor ( url , initOrProtocols ) {
196252 super ( ) ;
@@ -573,8 +629,10 @@ class WebSocket extends EventTarget {
573629 // data is being sent.
574630 if ( ArrayBufferIsView ( data ) ) {
575631 op_ws_send_binary ( this [ _rid ] , data ) ;
632+ emitWebSocketFrame ( this , "frameSent" , 2 , data ) ;
576633 } else if ( isArrayBuffer ( data ) ) {
577634 op_ws_send_binary_ab ( this [ _rid ] , data ) ;
635+ emitWebSocketFrame ( this , "frameSent" , 2 , data ) ;
578636 } else if ( ObjectPrototypeIsPrototypeOf ( BlobPrototype , data ) ) {
579637 this [ _queueSend ] ( data ) ;
580638 } else {
@@ -583,6 +641,7 @@ class WebSocket extends EventTarget {
583641 this [ _rid ] ,
584642 string ,
585643 ) ;
644+ emitWebSocketFrame ( this , "frameSent" , 1 , string ) ;
586645 }
587646 } else {
588647 // Slower path if the send queue is not empty, for example when sending
@@ -690,6 +749,7 @@ class WebSocket extends EventTarget {
690749 }
691750
692751 this [ _serverHandleIdleTimeout ] ( ) ;
752+ emitWebSocketFrame ( this , "frameReceived" , 1 , data ) ;
693753 const event = new MessageEvent ( "message" , {
694754 data,
695755 origin : this [ _url ] ,
@@ -708,6 +768,7 @@ class WebSocket extends EventTarget {
708768 this [ _serverHandleIdleTimeout ] ( ) ;
709769 // deno-lint-ignore prefer-primordials
710770 const buffer = d . buffer ;
771+ emitWebSocketFrame ( this , "frameReceived" , 2 , buffer ) ;
711772 let data ;
712773 if ( this . binaryType === "blob" ) {
713774 data = new Blob ( [ buffer ] ) ;
@@ -733,6 +794,7 @@ class WebSocket extends EventTarget {
733794 this [ _readyState ] = CLOSED ;
734795
735796 const message = op_ws_get_error ( rid ) ;
797+ emitWebSocketFrameError ( this , message ) ;
736798 const error = new Error ( message ) ;
737799 const errorEv = new ErrorEvent ( "error" , {
738800 error,
@@ -797,18 +859,22 @@ class WebSocket extends EventTarget {
797859 const data = queue [ 0 ] ;
798860 if ( ArrayBufferIsView ( data ) ) {
799861 op_ws_send_binary ( this [ _rid ] , data ) ;
862+ emitWebSocketFrame ( this , "frameSent" , 2 , data ) ;
800863 } else if ( isArrayBuffer ( data ) ) {
801864 op_ws_send_binary_ab ( this [ _rid ] , data ) ;
865+ emitWebSocketFrame ( this , "frameSent" , 2 , data ) ;
802866 } else if ( ObjectPrototypeIsPrototypeOf ( BlobPrototype , data ) ) {
803867 // deno-lint-ignore prefer-primordials
804868 const ab = await data . slice ( ) . arrayBuffer ( ) ;
805869 op_ws_send_binary_ab ( this [ _rid ] , ab ) ;
870+ emitWebSocketFrame ( this , "frameSent" , 2 , ab ) ;
806871 } else {
807872 const string = String ( data ) ;
808873 op_ws_send_text (
809874 this [ _rid ] ,
810875 string ,
811876 ) ;
877+ emitWebSocketFrame ( this , "frameSent" , 1 , string ) ;
812878 }
813879 ArrayPrototypeShift ( queue ) ;
814880 }
@@ -947,6 +1013,8 @@ export {
9471013 _serverHandleIdleTimeout ,
9481014 CLIENT ,
9491015 createWebSocketBranded ,
1016+ emitWebSocketClosed ,
1017+ installServerInspector ,
9501018 SERVER ,
9511019 WebSocket ,
9521020} ;
0 commit comments