import axios , { AxiosRequestConfig , CancelToken , AxiosError } from 'axios' ; import { isDebugEnabled } from './debug' ; import { fetchCachedResponse , saveCacheResponse , findAndDeleteExpiredCachedItems , CacheConfig , removeCacheableRequestsInProgress , } from './cacheHandlers' ; const DEFAULT_RETRY_DELAY = 3000 ; const DEFAULT_MAX_RETRIES = 2 ; declare module 'axios' { export interface AxiosRequestConfig { retries ? : number ; cancelToken ? : CancelToken ; cacheKey ? : string ; cache ? : CacheConfig ; rewriteUrlFunc ? : ( url : string ) => string ; setCancelTokenCacheKey ? : ( cacheKey : string ) => void ; } } export const registerInitialAxiosInterceptors = ( ) : any => { findAndDeleteExpiredCachedItems ( ) ; axios . interceptors . request . use ( logCurl , error => Promise . reject ( error ) ) ; axios . interceptors . request . use ( fetchCachedResponse , error => Promise . reject ( error ) ) ; axios . interceptors . request . use ( rewriteUrl , error => Promise . reject ( error ) ) ; axios . interceptors . response . use ( saveCacheResponse , error => retryRequests ( error ) ) ; } ; const rewriteUrl = async ( config ) : Promise < any > => { if ( config . rewriteUrlFunc ) { config . url = config . rewriteUrlFunc ( config . url ) ; } return config ; } ; const logCurl = async ( config ) : Promise < any > => { if ( isDebugEnabled ( ) ) { let headers = { ... config . headers . common , ... config . headers [ config . method ] , } ; const addedHeadersKeys = Object . keys ( config . headers ) . filter ( k => typeof config . headers [ k ] === 'string' ) ; addedHeadersKeys . forEach ( k => ( headers [ k ] = config . headers [ k ] ) ) ; if ( typeof config . data !== 'string' ) { headers [ 'Content-Type' ] = 'application/json' ; } let lowercaseHeaders = { } ; for ( let k in headers ) { lowercaseHeaders [ k . toLowerCase ( ) ] = headers [ k ] ; } console . debug ( `${ '*' . repeat ( 30 ) }\n${ curlify ( config . url , config . method . toUpperCase ( ) , config . data , lowercaseHeaders ) }\n\n` ) ; } return config ; } ; function curlify ( url , method , payload = null , headers = { } ) { let curl = `curl -X ${ method } '${ url }'` ; for ( let h in headers ) { curl += ` -H '${ h }: ${ headers [ h ] }'` ; } if ( payload ) { curl += ` -d '${ typeof payload === 'string' ? payload : JSON . stringify ( payload ) }'` ; } return curl ; } const retryRequests = ( err ) : any => { if ( ! err . config ) { return Promise . reject ( err ) ; } if ( err . config . cacheKey ) { removeCacheableRequestsInProgress ( err . config . cacheKey ) ; } if ( shouldRetry ( err ) ) { err . config . retriesCount = err . config . retriesCount | 0 ; const maxRetries = err . config . retries === undefined || err . config . retries === null ? DEFAULT_MAX_RETRIES : err . config . retries ; const shouldRetry = err . config . retriesCount < maxRetries ; if ( shouldRetry ) { err . config . retriesCount += 1 ; return new Promise ( resolve => setTimeout ( ( ) => resolve ( axios ( err . config ) ) , DEFAULT_RETRY_DELAY ) ) ; } } return Promise . reject ( err ) ; } ; const shouldRetry = ( error ) : boolean => { if ( ! error . response || ! error . response . status ) { return false ; } return error . response . status == 429 || ( error . response . status >= 500 && error . response . status <= 599 ) ; } ;