import { sleep } from './utils' ; const DEFAULT_MAX_RETRIES = 30 ; const DEFAULT_INITIAL_DELAY_MS = 1000 ; const DEFAULT_RETRY_INTERVAL_MS = 2000 ; /** Action is an interface that has a sys.status to be checked against */ interface Action extends Record < string , any > { sys : { status : string ; type : string ; } ; } export class AsyncActionProcessingError extends Error { public action ? : Action ; constructor ( message , action ? ) { super ( message ) ; this . action = action ; this . name = this . constructor . name ; } } export class AsyncActionFailedError extends AsyncActionProcessingError { } export type AsyncActionProcessingOptions = { default retryCount ? : number ; default retryIntervalMs ? : number ; default initialDelayMs ? : number ; default throwOnFailedExecution ? : boolean ; } ; description param { Function } actionFunction throws throws export async function pollAsyncActionStatus < T extends Action = any > ( actionFunction , options ? ) { let retryCount = 0 ; let done = false ; let action ; const maxRetries = options ?. retryCount ?? DEFAULT_MAX_RETRIES ; const retryIntervalMs = options ?. retryIntervalMs ?? DEFAULT_RETRY_INTERVAL_MS ; const initialDelayMs = options ?. initialDelayMs ?? DEFAULT_INITIAL_DELAY_MS ; const throwOnFailedExecution = options ?. throwOnFailedExecution ?? true ; await sleep ( initialDelayMs ) ; while ( retryCount < maxRetries && ! done ) { action = await actionFunction ( ) ; if ( action && [ 'succeeded' , 'failed' ] . includes ( action . sys . status ) ) { done = true ; if ( action . sys . status === 'failed' && throwOnFailedExecution ) { throw new AsyncActionFailedError ( `${ action . sys . type } failed to execute.` , action ) ; } return action ; } await sleep ( retryIntervalMs ) ; retryCount += 1 ; } throw new AsyncActionProcessingError ( `${ action ?. sys . type } didn't finish processing within the expected timeframe.` , action ) ; }