/**
 * Strategy for calculating retry delays.
 */ export interface RetryDelayStrategy { param error param failedAttempts returns nextDelay ( error ? , failedAttempts ? ) : number ; /** Implementation should reset its state, this is mandatory to call upon success.  */ success ( ) : void ; } /**
 * Interface for errors to inform that an associated operation can be retried.
 */ export interface RetriableDecision { /**
     * Informs whether this can be retried.
     */ canRetry ( ) : boolean ; returns retryAfter ( ) : number ; } const retriableStatusCodes = [ 404 , 408 , 425 , 429 , 500 , 502 , 503 , 504 ] ; /** isStatusCodeRetriable checks whether the supplied HTTP status code is retriable. */ export function isStatusCodeRetriable ( statusCode ) { return retriableStatusCodes . includes ( statusCode ) ; } /** IllegalArgumentError is thrown when illegal argument is supplied. */ export class IllegalArgumentError extends Error { constructor ( message ) { super ( message ) ; this . name = 'IllegalArgumentError' ; Object . setPrototypeOf ( this , IllegalArgumentError . prototype ) ; } } /**
 * A general HTTP error.
 */ export class HttpError extends Error implements RetriableDecision { private _retryAfter : number ; /** application error code, when available */ public code : string | undefined ; /** json error response */ public json : any ; constructor ( readonly statusCode , readonly statusMessage , readonly body ? , retryAfter ? , readonly contentType ? , message ? ) { super ( ) ; Object . setPrototypeOf ( this , HttpError . prototype ) ; if ( message ) { this . message = message ; } else if ( body ) { if ( contentType ?. startsWith ( 'application/json' ) ) { try { this . json = JSON . parse ( body ) ; this . message = this . json . message ; this . code = this . json . code ; } catch ( e ) { } } if ( ! this . message ) { this . message = `${ statusCode } ${ statusMessage } : ${ body }` ; } } else { this . message = `${ statusCode } ${ statusMessage }` ; } this . name = 'HttpError' ; this . setRetryAfter ( retryAfter ) ; } private setRetryAfter ( retryAfter ? ) { if ( typeof retryAfter === 'string' ) { if ( /^[0-9]+$/ . test ( retryAfter ) ) { this . _retryAfter = parseInt ( retryAfter ) ; } else { this . _retryAfter = 0 ; } } else { this . _retryAfter = 0 ; } } canRetry ( ) { return isStatusCodeRetriable ( this . statusCode ) ; } retryAfter ( ) { return this . _retryAfter ; } } const RETRY_CODES = [ 'ECONNRESET' , 'ENOTFOUND' , 'ESOCKETTIMEDOUT' , 'ETIMEDOUT' , 'ECONNREFUSED' , 'EHOSTUNREACH' , 'EPIPE' , ] ; param error returns export function canRetryHttpCall ( error ) { if ( ! error ) { return false ; } else if ( typeof ( error as any ) . canRetry === 'function' ) { return ! ! ( ( error as any ) . canRetry as ( ) => boolean ) ( ) ; } else if ( ( error as any ) . code && RETRY_CODES . includes ( ( error as any ) . code ) ) { return true ; } return false ; } /**
 * Gets retry delay from the supplied error, possibly using random number up to retryJitter.
 */ export function getRetryDelay ( error ? , retryJitter ? ) { if ( ! error ) { return 0 ; } else { let retVal ; if ( typeof ( error as any ) . retryAfter === 'function' ) { return ( ( error as any ) . retryAfter as ( ) => number ) ( ) ; } else { retVal = 0 ; } if ( retryJitter && retryJitter > 0 ) { return retVal + Math . round ( Math . random ( ) * retryJitter ) ; } else { return retVal ; } } } /** RequestTimedOutError indicates request timeout in the communication with the server */ export class RequestTimedOutError extends Error implements RetriableDecision { constructor ( ) { super ( ) ; Object . setPrototypeOf ( this , RequestTimedOutError . prototype ) ; this . name = 'RequestTimedOutError' ; this . message = 'Request timed out' ; } canRetry ( ) { return true ; } retryAfter ( ) { return 0 ; } } /** AbortError indicates that the communication with the server was aborted */ export class AbortError extends Error implements RetriableDecision { constructor ( ) { super ( ) ; this . name = 'AbortError' ; Object . setPrototypeOf ( this , AbortError . prototype ) ; this . message = 'Response aborted' ; } canRetry ( ) { return true ; } retryAfter ( ) { return 0 ; } }