@@ -52,7 +52,7 @@ const defaultConfig = {
5252 * @returns {Object } ConcurrencyQueue instance with request/response interceptors attached to Axios.
5353 * @throws {Error } If axios instance is not provided or configuration is invalid.
5454 */
55- export function ConcurrencyQueue ( { axios, config } ) {
55+ export function ConcurrencyQueue ( { axios, config, plugins = [ ] } ) {
5656 if ( ! axios ) {
5757 throw Error ( ERROR_MESSAGES . AXIOS_INSTANCE_MISSING )
5858 }
@@ -436,6 +436,30 @@ export function ConcurrencyQueue ({ axios, config }) {
436436 return response
437437 }
438438
439+ // Run plugin onResponse hooks for errors so plugins see every error (including
440+ // those that are rejected without going through the plugin response interceptor).
441+ const runPluginOnResponseForError = ( error ) => {
442+ if ( ! plugins || ! plugins . length ) return error
443+ let currentError = error
444+ for ( const plugin of plugins ) {
445+ try {
446+ if ( typeof plugin . onResponse === 'function' ) {
447+ const result = plugin . onResponse ( currentError )
448+ if ( result !== undefined ) currentError = result
449+ }
450+ } catch ( e ) {
451+ if ( this . config . logHandler ) {
452+ this . config . logHandler ( 'error' , {
453+ name : 'PluginError' ,
454+ message : `Error in plugin onResponse (error handler): ${ e . message } ` ,
455+ error : e
456+ } )
457+ }
458+ }
459+ }
460+ return currentError
461+ }
462+
439463 const responseErrorHandler = error => {
440464 let networkError = error . config . retryCount
441465 let retryErrorType = null
@@ -449,7 +473,8 @@ export function ConcurrencyQueue ({ axios, config }) {
449473
450474 // Original retry logic for non-network errors
451475 if ( ! this . config . retryOnError || networkError > this . config . retryLimit ) {
452- return Promise . reject ( responseHandler ( error ) )
476+ const err = runPluginOnResponseForError ( error )
477+ return Promise . reject ( responseHandler ( err ) )
453478 }
454479
455480 // Check rate limit remaining header before retrying
@@ -465,14 +490,23 @@ export function ConcurrencyQueue ({ axios, config }) {
465490 }
466491 response = error . response
467492 } else {
468- return Promise . reject ( responseHandler ( error ) )
493+ const err = runPluginOnResponseForError ( error )
494+ return Promise . reject ( responseHandler ( err ) )
469495 }
470496 } else if ( ( response . status === 401 && this . config . refreshToken ) ) {
497+ // If error_code is 294 (2FA required), don't retry/refresh - pass through the error as-is
498+ const apiErrorCode = response . data ?. error_code
499+ if ( apiErrorCode === 294 ) {
500+ const err = runPluginOnResponseForError ( error )
501+ return Promise . reject ( responseHandler ( err ) )
502+ }
503+
471504 retryErrorType = `Error with status: ${ response . status } `
472505 networkError ++
473506
474507 if ( networkError > this . config . retryLimit ) {
475- return Promise . reject ( responseHandler ( error ) )
508+ const err = runPluginOnResponseForError ( error )
509+ return Promise . reject ( responseHandler ( err ) )
476510 }
477511 this . running . shift ( )
478512 // Cool down the running requests
@@ -486,19 +520,22 @@ export function ConcurrencyQueue ({ axios, config }) {
486520 networkError ++
487521 return this . retry ( error , retryErrorType , networkError , wait )
488522 }
489- return Promise . reject ( responseHandler ( error ) )
523+ const err = runPluginOnResponseForError ( error )
524+ return Promise . reject ( responseHandler ( err ) )
490525 }
491526
492527 this . retry = ( error , retryErrorType , retryCount , waittime ) => {
493528 let delaytime = waittime
494529 if ( retryCount > this . config . retryLimit ) {
495- return Promise . reject ( responseHandler ( error ) )
530+ const err = runPluginOnResponseForError ( error )
531+ return Promise . reject ( responseHandler ( err ) )
496532 }
497533 if ( this . config . retryDelayOptions ) {
498534 if ( this . config . retryDelayOptions . customBackoff ) {
499535 delaytime = this . config . retryDelayOptions . customBackoff ( retryCount , error )
500536 if ( delaytime && delaytime <= 0 ) {
501- return Promise . reject ( responseHandler ( error ) )
537+ const err = runPluginOnResponseForError ( error )
538+ return Promise . reject ( responseHandler ( err ) )
502539 }
503540 } else if ( this . config . retryDelayOptions . base ) {
504541 delaytime = this . config . retryDelayOptions . base * retryCount
0 commit comments