import { Event , Options , Payload , Status , Response } from '@amplitude/types' ; import { AsyncQueue , collectInvalidEventIndices } from '@amplitude/utils' ; import { BaseRetryHandler } from './baseRetry' ; /**
 * A retry handler made specifically to handle a strategy where
 * the server network connection is not always available. (e.g. executing node code on a client device).
 * Instead of retrying events on a loop, this will save untried events
 */ export class OfflineRetryHandler extends BaseRetryHandler { private _eventsToRetry : Event [ ] = [ ] ; private readonly _requestQueue : AsyncQueue = new AsyncQueue ( ) ; public constructor ( apiKey , options = { } ) { super ( apiKey , options ) ; } inheritDoc public async sendEventsWithRetry ( events ) { return await this . _requestQueue . addToQueue ( async ( ) => { let response = { status : Status . Unknown , statusCode : 0 } ; const payload = this . _getPayload ( events ) ; try { response = await this . _transport . sendPayload ( payload ) ; if ( response . status !== Status . Success ) { throw new Error ( response . status ) ; } else { this . _onSendSuccess ( ) ; } } catch { this . _onSendError ( payload . events , response ) ; } return response ; } ) ; } protected _getPayload ( events ) { return { api_key : this . _apiKey , events : this . _eventsToRetry . concat ( events ) , ... this . _getPayloadOptions ( ) , } ; } private _onSendSuccess ( ) { this . _eventsToRetry = [ ] ; } private _onSendError ( events , response ) { let newEventsToRetry = Array . from ( events ) ; if ( response . status === Status . Invalid ) { if ( typeof response . body ?. missingField === 'string' || events . length === 1 ) { newEventsToRetry = [ ] ; } else if ( response . body !== undefined ) { const invalidEventIndices = new Set < number > ( collectInvalidEventIndices ( response ) ) ; newEventsToRetry = events . filter ( ( _ , index ) => ! invalidEventIndices . has ( index ) ) ; } } else if ( response . status === Status . Success ) { newEventsToRetry = [ ] ; } this . _eventsToRetry = newEventsToRetry ; if ( this . _eventsToRetry . length > this . _options . maxCachedEvents ) { const numExceededEvents = this . _eventsToRetry . length - this . _options . maxCachedEvents ; this . _eventsToRetry . splice ( 0 , numExceededEvents ) ; } } }