import { ComponentClient , ComponentClientOptions } from '@layr/component-client' ; import fetch from 'cross-fetch' ; import { sleep } from '@layr/utilities' ; import type { PlainObject } from 'core-helpers' ; const DEFAULT_MAXIMUM_REQUEST_RETRIES = 10 ; const DEFAULT_MINIMUM_TIME_BETWEEN_REQUEST_RETRIES = 3000 ; export type ComponentHTTPClientOptions = ComponentClientOptions & { retryFailedRequests ? : RetryFailedRequests ; maximumRequestRetries ? : number ; minimumTimeBetweenRequestRetries ? : number ; } ; export type RetryFailedRequests = boolean | ( ( { error , numberOfRetries } : { error : Error ; numberOfRetries : number ; } ) => Promise < boolean > ) ; expose attribute expose method expose attribute expose method export class ComponentHTTPClient extends ComponentClient { param url param options . version param options . mixins param options . retryFailedRequests param options . maximumRequestRetries param options . minimumTimeBetweenRequestRetries returns category constructor ( url , options = { } ) { const { retryFailedRequests = false , maximumRequestRetries = DEFAULT_MAXIMUM_REQUEST_RETRIES , minimumTimeBetweenRequestRetries = DEFAULT_MINIMUM_TIME_BETWEEN_REQUEST_RETRIES , ... componentClientOptions } = options ; const componentServer = createComponentServer ( url , { retryFailedRequests , maximumRequestRetries , minimumTimeBetweenRequestRetries } ) ; super ( componentServer , { ... componentClientOptions , batchable : true } ) ; } } function createComponentServer ( url , { retryFailedRequests , maximumRequestRetries , minimumTimeBetweenRequestRetries } ) { return { async receive ( request ) { const { query , components , version } = request ; const jsonRequest = { query , components , version } ; let numberOfRetries = 0 ; while ( true ) { let fetchResponse ; let jsonResponse ; try { fetchResponse = await fetch ( url , { method : 'POST' , headers : { 'Content-Type' : 'application/json' } , body : JSON . stringify ( jsonRequest ) } ) ; jsonResponse = await fetchResponse . json ( ) ; } catch ( error ) { if ( numberOfRetries < maximumRequestRetries ) { const startTime = Date . now ( ) ; const shouldRetry = typeof retryFailedRequests === 'function' ? await retryFailedRequests ( { error , numberOfRetries } ) : retryFailedRequests ; if ( shouldRetry ) { const elapsedTime = Date . now ( ) - startTime ; if ( elapsedTime < minimumTimeBetweenRequestRetries ) { await sleep ( minimumTimeBetweenRequestRetries - elapsedTime ) ; } numberOfRetries ++ ; continue ; } } throw error ; } if ( fetchResponse . status !== 200 ) { const { message = 'An error occurred while sending query to remote components' , ... attributes } = jsonResponse ?? { } ; throw Object . assign ( new Error ( message ) , attributes ) ; } return jsonResponse ; } } } ; }