@@ -38,6 +38,98 @@ export function initBrowserEcho(opts: InitBrowserEchoOptions = {}) {
3838 ORIGINAL [ 'info' ] ?.( `${ tag } forwarding console logs to ${ route } (session ${ session } )` ) ;
3939 } catch { }
4040
41+ // Network interception (fetch/XHR)
42+ try {
43+ const net = opts . network || { } ;
44+ const enableNetwork = typeof net . enabled === 'boolean' ? net . enabled : true ;
45+ if ( enableNetwork ) {
46+ // Intercept fetch
47+ try {
48+ const captureFetch = typeof net . captureFetch === 'boolean' ? net . captureFetch : true ;
49+ if ( captureFetch && typeof ( w . fetch ) === 'function' ) {
50+ const originalFetch = w . fetch . bind ( w ) ;
51+ w . fetch = ( async ( ...args : any [ ] ) => {
52+ let method = 'GET' ;
53+ let url = '' ;
54+ try {
55+ const input = args [ 0 ] ;
56+ const init = args [ 1 ] || { } ;
57+ if ( typeof input === 'string' ) url = input ;
58+ else if ( input && typeof input . url === 'string' ) url = input . url ;
59+ if ( init && init . method ) method = String ( init . method ) . toUpperCase ( ) ;
60+ else if ( input && input . method ) method = String ( input . method ) . toUpperCase ( ) ;
61+ } catch { }
62+ const started = ( typeof performance !== 'undefined' && performance . now ) ? performance . now ( ) : Date . now ( ) ;
63+ try {
64+ const res = await originalFetch ( ...( args as any ) ) ;
65+ const finished = ( typeof performance !== 'undefined' && performance . now ) ? performance . now ( ) : Date . now ( ) ;
66+ const data = {
67+ kind : 'network' ,
68+ transport : 'fetch' ,
69+ method,
70+ url,
71+ status : ( res && typeof res . status === 'number' ) ? res . status : 0 ,
72+ ok : ! ! ( res && ( res as any ) . ok ) ,
73+ ms : Math . round ( finished - started )
74+ } as const ;
75+ enqueue ( { level : 'info' , text : `NET ${ JSON . stringify ( data ) } ` , time : Date . now ( ) , stack : '' , source : url } ) ;
76+ return res ;
77+ } catch ( err ) {
78+ const finished = ( typeof performance !== 'undefined' && performance . now ) ? performance . now ( ) : Date . now ( ) ;
79+ const data = { kind : 'network' , transport : 'fetch' , method, url, error : safeFormat ( err ) , ms : Math . round ( finished - started ) } as const ;
80+ enqueue ( { level : 'error' , text : `NET ${ JSON . stringify ( data ) } ` , time : Date . now ( ) , stack : '' , source : url } ) ;
81+ throw err ;
82+ }
83+ } ) as typeof w . fetch ;
84+ }
85+ } catch { }
86+
87+ // Intercept XMLHttpRequest
88+ try {
89+ const captureXHR = typeof net . captureXmlHttpRequest === 'boolean' ? net . captureXmlHttpRequest : true ;
90+ if ( captureXHR && typeof ( w . XMLHttpRequest ) !== 'undefined' ) {
91+ const OrigXHR = w . XMLHttpRequest as any ;
92+ function WrappedXHR ( this : any ) {
93+ const xhr = new OrigXHR ( ) ;
94+ let method = 'GET' ;
95+ let url = '' ;
96+ let start = 0 ;
97+ const origOpen = xhr . open ;
98+ xhr . open = function ( m : string , u : string , ...rest : any [ ] ) {
99+ try { method = ( m || 'GET' ) . toUpperCase ( ) ; url = u || '' ; } catch { }
100+ return origOpen . call ( xhr , m , u , ...rest ) ;
101+ } ;
102+ const origSend = xhr . send ;
103+ xhr . send = function ( ...sendArgs : any [ ] ) {
104+ start = ( typeof performance !== 'undefined' && performance . now ) ? performance . now ( ) : Date . now ( ) ;
105+ try {
106+ // loadend fires for success and error
107+ xhr . addEventListener ( 'loadend' , function ( ) {
108+ try {
109+ const end = ( typeof performance !== 'undefined' && performance . now ) ? performance . now ( ) : Date . now ( ) ;
110+ const status = Number ( xhr . status || 0 ) ;
111+ const ok = status >= 200 && status < 400 ;
112+ const data = { kind : 'network' , transport : 'xhr' , method, url, status, ok, ms : Math . round ( end - start ) } as const ;
113+ enqueue ( { level : ok ? 'info' : 'error' , text : `NET ${ JSON . stringify ( data ) } ` , time : Date . now ( ) , stack : '' , source : url } ) ;
114+ } catch { }
115+ } , { once : true } ) ;
116+ } catch { }
117+ try { return origSend . apply ( xhr , sendArgs as any ) ; }
118+ catch ( err ) {
119+ const end = ( typeof performance !== 'undefined' && performance . now ) ? performance . now ( ) : Date . now ( ) ;
120+ const data = { kind : 'network' , transport : 'xhr' , method, url, error : safeFormat ( err ) , ms : Math . round ( end - start ) } as const ;
121+ enqueue ( { level : 'error' , text : `NET ${ JSON . stringify ( data ) } ` , time : Date . now ( ) , stack : '' , source : url } ) ;
122+ throw err ;
123+ }
124+ } ;
125+ return xhr ;
126+ }
127+ ( w as any ) . XMLHttpRequest = WrappedXHR ;
128+ }
129+ } catch { }
130+ }
131+ } catch { }
132+
41133 function enqueue ( entry : any ) {
42134 queue . push ( entry ) ;
43135 if ( queue . length >= batchSize ) flush ( ) ;
0 commit comments