@@ -28,6 +28,7 @@ declare class XMLHttpRequest {
2828 setRequestHeader ( header : string , value : string ) : void ;
2929 getResponseHeader ( name : string ) : string | null ;
3030 getAllResponseHeaders ( ) : string ;
31+ addEventListener ( type : string , listener : ( this : XMLHttpRequest , ev : any ) => any ) : void ;
3132}
3233
3334// Callback types use 'any' to match React Native's XHRInterceptor API
@@ -85,6 +86,12 @@ function enableInterception(): void {
8586 username ?: string | null ,
8687 password ?: string | null
8788 ) : void {
89+ const xhr = this as any ;
90+ xhr . _interception = {
91+ method,
92+ url : url . toString ( ) ,
93+ } ;
94+
8895 openCallback ( method , url . toString ( ) , this ) ;
8996
9097 return originalXHROpen ! . call (
@@ -113,12 +120,14 @@ function enableInterception(): void {
113120 const dataString = body === null || body === undefined ? '' : String ( body ) ;
114121 sendCallback ( dataString , xhr ) ;
115122
116- // Listen for state changes to capture headers and response
117- const originalOnReadyStateChange = this . onreadystatechange ;
118- this . onreadystatechange = function ( event : any ) {
123+ // Use addEventListener which is more reliable than overriding onreadystatechange
124+ // This works even when handlers are set after send() is called
125+ this . addEventListener ( 'readystatechange' , function ( ) {
119126 if ( this . readyState === XMLHttpRequest . HEADERS_RECEIVED ) {
120- if ( ! xhr . _hasCalledHeaderReceived ) {
121- xhr . _hasCalledHeaderReceived = true ;
127+ if ( ! xhr . _interception ?. hasCalledHeaderReceived ) {
128+ if ( xhr . _interception ) {
129+ xhr . _interception . hasCalledHeaderReceived = true ;
130+ }
122131 const contentType = this . getResponseHeader ( 'content-type' ) || '' ;
123132 const contentLength = this . getResponseHeader ( 'content-length' ) ;
124133 const responseSize = contentLength ? parseInt ( contentLength , 10 ) : 0 ;
@@ -134,33 +143,34 @@ function enableInterception(): void {
134143 }
135144
136145 if ( this . readyState === XMLHttpRequest . DONE ) {
137- let responseData = '' ;
138- if ( this . responseType === '' || this . responseType === 'text' ) {
139- responseData = this . responseText || '' ;
140- } else if ( this . responseType === 'json' && this . response ) {
141- try {
142- responseData = JSON . stringify ( this . response ) ;
143- } catch {
144- responseData = '[Unable to stringify response]' ;
146+ if ( ! xhr . _interception ?. hasCalledResponse ) {
147+ if ( xhr . _interception ) {
148+ xhr . _interception . hasCalledResponse = true ;
149+ }
150+ let responseData = '' ;
151+ if ( this . responseType === '' || this . responseType === 'text' ) {
152+ responseData = this . responseText || '' ;
153+ } else if ( this . responseType === 'json' && this . response ) {
154+ try {
155+ responseData = JSON . stringify ( this . response ) ;
156+ } catch {
157+ responseData = '[Unable to stringify response]' ;
158+ }
159+ } else if ( this . response ) {
160+ responseData = '[Non-text response]' ;
145161 }
146- } else if ( this . response ) {
147- responseData = '[Non-text response]' ;
148- }
149-
150- responseCallback (
151- this . status ,
152- this . timeout ,
153- responseData ,
154- this . responseURL ,
155- this . responseType ,
156- xhr
157- ) ;
158- }
159162
160- if ( originalOnReadyStateChange ) {
161- originalOnReadyStateChange . call ( this , event ) ;
163+ responseCallback (
164+ this . status ,
165+ this . timeout ,
166+ responseData ,
167+ this . responseURL ,
168+ this . responseType ,
169+ xhr
170+ ) ;
171+ }
162172 }
163- } ;
173+ } ) ;
164174
165175 return originalXHRSend ! . call ( this , body ) ;
166176 } ;
0 commit comments