diff --git a/packages/analytics/__tests__/providers/pinpoint/apis/flushEvents.test.ts b/packages/analytics/__tests__/providers/pinpoint/apis/flushEvents.test.ts index ace1313da1a..c89a31694f8 100644 --- a/packages/analytics/__tests__/providers/pinpoint/apis/flushEvents.test.ts +++ b/packages/analytics/__tests__/providers/pinpoint/apis/flushEvents.test.ts @@ -6,7 +6,7 @@ import { resolveCredentials, } from '../../../../src/providers/pinpoint/utils'; import { config, credentials, identityId } from './testUtils/data'; -import { flushEvents } from '../../../../src/providers/pinpoint'; +import { flushEvents } from '../../../../src'; import { flushEvents as pinpointFlushEvents } from '@aws-amplify/core/internals/providers/pinpoint'; import { AnalyticsAction } from '@aws-amplify/core/internals/utils'; import { ConsoleLogger } from '@aws-amplify/core'; @@ -44,13 +44,12 @@ describe('Pinpoint API: flushEvents', () => { expect(mockResolveCredentials).toBeCalledTimes(1); await new Promise(process.nextTick); - expect(mockPinpointFlushEvents).toBeCalledWith( - config.appId, - config.region, + expect(mockPinpointFlushEvents).toBeCalledWith({ + ...config, credentials, identityId, - getAnalyticsUserAgentString(AnalyticsAction.Record) - ); + userAgentValue: getAnalyticsUserAgentString(AnalyticsAction.Record), + }); }); it('logs an error when credentials can not be fetched', async () => { diff --git a/packages/analytics/__tests__/providers/pinpoint/utils/resolveConfig.test.ts b/packages/analytics/__tests__/providers/pinpoint/utils/resolveConfig.test.ts index 5672b1c3c79..84e9ff30d06 100644 --- a/packages/analytics/__tests__/providers/pinpoint/utils/resolveConfig.test.ts +++ b/packages/analytics/__tests__/providers/pinpoint/utils/resolveConfig.test.ts @@ -8,6 +8,10 @@ describe('Analytics Pinpoint Provider Util: resolveConfig', () => { const pinpointConfig = { appId: 'app-id', region: 'region', + bufferSize: 100, + flushSize: 10, + flushInterval: 50, + resendLimit: 3, }; // create spies const getConfigSpy = jest.spyOn(Amplify, 'getConfig'); diff --git a/packages/analytics/src/providers/pinpoint/apis/flushEvents.ts b/packages/analytics/src/providers/pinpoint/apis/flushEvents.ts index ac41ee5fe95..4dc6425b77b 100644 --- a/packages/analytics/src/providers/pinpoint/apis/flushEvents.ts +++ b/packages/analytics/src/providers/pinpoint/apis/flushEvents.ts @@ -17,16 +17,21 @@ const logger = new ConsoleLogger('Analytics'); * this API may not be included in the flush. */ export const flushEvents = () => { - const { appId, region } = resolveConfig(); + const { appId, region, bufferSize, flushSize, flushInterval, resendLimit } = + resolveConfig(); resolveCredentials() .then(({ credentials, identityId }) => - flushEventsCore( + flushEventsCore({ appId, region, credentials, identityId, - getAnalyticsUserAgentString(AnalyticsAction.Record) - ) + bufferSize, + flushSize, + flushInterval, + resendLimit, + userAgentValue: getAnalyticsUserAgentString(AnalyticsAction.Record), + }) ) .catch(e => logger.warn('Failed to flush events', e)); }; diff --git a/packages/analytics/src/providers/pinpoint/apis/record.ts b/packages/analytics/src/providers/pinpoint/apis/record.ts index 8422d0ffb20..c9de36b02ee 100644 --- a/packages/analytics/src/providers/pinpoint/apis/record.ts +++ b/packages/analytics/src/providers/pinpoint/apis/record.ts @@ -49,7 +49,8 @@ const logger = new ConsoleLogger('Analytics'); * ``` */ export const record = (input: RecordInput): void => { - const { appId, region } = resolveConfig(); + const { appId, region, bufferSize, flushSize, flushInterval, resendLimit } = + resolveConfig(); if (!isAnalyticsEnabled()) { logger.debug('Analytics is disabled, event will not be recorded.'); @@ -74,6 +75,10 @@ export const record = (input: RecordInput): void => { identityId, region, userAgentValue: getAnalyticsUserAgentString(AnalyticsAction.Record), + bufferSize, + flushSize, + flushInterval, + resendLimit, }); }) .catch(e => { diff --git a/packages/analytics/src/providers/pinpoint/utils/resolveConfig.ts b/packages/analytics/src/providers/pinpoint/utils/resolveConfig.ts index e5b16a8641d..28d60e258cf 100644 --- a/packages/analytics/src/providers/pinpoint/utils/resolveConfig.ts +++ b/packages/analytics/src/providers/pinpoint/utils/resolveConfig.ts @@ -11,8 +11,10 @@ import { * @internal */ export const resolveConfig = () => { - const { appId, region } = Amplify.getConfig().Analytics?.Pinpoint ?? {}; + const { appId, region, bufferSize, flushSize, flushInterval, resendLimit } = + Amplify.getConfig().Analytics?.Pinpoint ?? {}; assertValidationError(!!appId, AnalyticsValidationErrorCode.NoAppId); assertValidationError(!!region, AnalyticsValidationErrorCode.NoRegion); - return { appId, region }; + + return { appId, region, bufferSize, flushSize, flushInterval, resendLimit }; }; diff --git a/packages/core/__tests__/providers/pinpoint/apis/flushEvents.test.ts b/packages/core/__tests__/providers/pinpoint/apis/flushEvents.test.ts index 9f0549684c8..f324bc7054f 100644 --- a/packages/core/__tests__/providers/pinpoint/apis/flushEvents.test.ts +++ b/packages/core/__tests__/providers/pinpoint/apis/flushEvents.test.ts @@ -4,6 +4,12 @@ import { getEventBuffer } from '../../../../src/providers/pinpoint/utils/getEventBuffer'; import { flushEvents } from '../../../../src/providers/pinpoint'; import { appId, region, credentials, identityId } from '../testUtils/data'; +import { + BUFFER_SIZE, + FLUSH_INTERVAL, + FLUSH_SIZE, + RESEND_LIMIT, +} from '../../../../src/providers/pinpoint/utils/constants'; jest.mock('../../../../src/providers/pinpoint/utils/getEventBuffer'); @@ -22,15 +28,17 @@ describe('Pinpoint Provider API: flushEvents', () => { }); it('invokes flushAll on pinpoint buffer', () => { - flushEvents(appId, region, credentials, identityId); - expect(mockGetEventBuffer).toBeCalledWith( - expect.objectContaining({ - appId, - region, - credentials, - identityId, - }) - ); + flushEvents({ appId, region, credentials, identityId }); + expect(mockGetEventBuffer).toBeCalledWith({ + appId, + region, + credentials, + identityId, + bufferSize: BUFFER_SIZE, + flushInterval: FLUSH_INTERVAL, + flushSize: FLUSH_SIZE, + resendLimit: RESEND_LIMIT, + }); expect(mockFlushAll).toBeCalledTimes(1); }); }); diff --git a/packages/core/src/ServiceWorker/ServiceWorker.ts b/packages/core/src/ServiceWorker/ServiceWorker.ts index 12cc7b5e4fc..d7abfede978 100644 --- a/packages/core/src/ServiceWorker/ServiceWorker.ts +++ b/packages/core/src/ServiceWorker/ServiceWorker.ts @@ -211,7 +211,14 @@ export class ServiceWorkerClass { const currentState = this.serviceWorker.state; this._logger.debug(`ServiceWorker statechange: ${currentState}`); - const { appId, region } = Amplify.getConfig().Analytics?.Pinpoint ?? {}; + const { + appId, + region, + bufferSize, + flushInterval, + flushSize, + resendLimit, + } = Amplify.getConfig().Analytics?.Pinpoint ?? {}; const { credentials } = await fetchAuthSession(); if (appId && region && credentials) { @@ -221,6 +228,10 @@ export class ServiceWorkerClass { region, category: 'Core', credentials, + bufferSize, + flushInterval, + flushSize, + resendLimit, event: { name: 'ServiceWorker', attributes: { diff --git a/packages/core/src/providers/pinpoint/apis/flushEvents.ts b/packages/core/src/providers/pinpoint/apis/flushEvents.ts index 8d07b0591e9..95c8281771a 100644 --- a/packages/core/src/providers/pinpoint/apis/flushEvents.ts +++ b/packages/core/src/providers/pinpoint/apis/flushEvents.ts @@ -1,8 +1,9 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { AWSCredentials } from '../../../libraryUtils'; import { getEventBuffer } from '../utils/getEventBuffer'; +import { EventBufferConfig } from '../types/buffer'; +import { AuthSession } from '../../../singleton/Auth/types'; import { BUFFER_SIZE, FLUSH_INTERVAL, @@ -10,22 +11,34 @@ import { RESEND_LIMIT, } from '../utils/constants'; -export const flushEvents = ( - appId: string, - region: string, - credentials: AWSCredentials, - identityId?: string, - userAgentValue?: string -) => { +export type PinpointFlushEventsInput = Partial & { + appId: string; + region: string; + credentials: Required['credentials']; + identityId?: AuthSession['identityId']; + userAgentValue?: string; +}; + +export const flushEvents = ({ + appId, + region, + credentials, + bufferSize, + flushInterval, + flushSize, + resendLimit, + identityId, + userAgentValue, +}: PinpointFlushEventsInput) => { getEventBuffer({ appId, - bufferSize: BUFFER_SIZE, + region, credentials, - flushInterval: FLUSH_INTERVAL, - flushSize: FLUSH_SIZE, + bufferSize: bufferSize ?? BUFFER_SIZE, + flushInterval: flushInterval ?? FLUSH_INTERVAL, + flushSize: flushSize ?? FLUSH_SIZE, + resendLimit: resendLimit ?? RESEND_LIMIT, identityId, - region, - resendLimit: RESEND_LIMIT, userAgentValue, }).flushAll(); }; diff --git a/packages/core/src/providers/pinpoint/apis/record.ts b/packages/core/src/providers/pinpoint/apis/record.ts index caaca4e9ccb..10784514254 100644 --- a/packages/core/src/providers/pinpoint/apis/record.ts +++ b/packages/core/src/providers/pinpoint/apis/record.ts @@ -30,6 +30,10 @@ export const record = async ({ identityId, region, userAgentValue, + bufferSize, + flushInterval, + flushSize, + resendLimit, }: PinpointRecordInput): Promise => { let eventSession = session; const currentTime = new Date(); @@ -39,13 +43,13 @@ export const record = async ({ // Prepare event buffer if required const buffer = getEventBuffer({ appId, - bufferSize: BUFFER_SIZE, + region, credentials, - flushInterval: FLUSH_INTERVAL, - flushSize: FLUSH_SIZE, + bufferSize: bufferSize ?? BUFFER_SIZE, + flushInterval: flushInterval ?? FLUSH_INTERVAL, + flushSize: flushSize ?? FLUSH_SIZE, + resendLimit: resendLimit ?? RESEND_LIMIT, identityId, - region, - resendLimit: RESEND_LIMIT, userAgentValue, }); @@ -88,6 +92,6 @@ export const record = async ({ event, session: eventSession!, timestamp: timestampISOString, - resendLimit: RESEND_LIMIT, + resendLimit: resendLimit ?? RESEND_LIMIT, }); }; diff --git a/packages/core/src/providers/pinpoint/types/buffer.ts b/packages/core/src/providers/pinpoint/types/buffer.ts index 6652d4db3bb..28fd0582c44 100644 --- a/packages/core/src/providers/pinpoint/types/buffer.ts +++ b/packages/core/src/providers/pinpoint/types/buffer.ts @@ -5,14 +5,17 @@ import { AuthSession } from '../../../singleton/Auth/types'; import { PinpointAnalyticsEvent, PinpointSession } from './pinpoint'; export type EventBufferConfig = { - appId: string; bufferSize: number; - credentials: Required['credentials']; - identityId: AuthSession['identityId']; flushInterval: number; flushSize: number; - region: string; resendLimit: number; +}; + +export type PinpointEventBufferConfig = EventBufferConfig & { + appId: string; + region: string; + credentials: Required['credentials']; + identityId: AuthSession['identityId']; userAgentValue?: string; }; diff --git a/packages/core/src/providers/pinpoint/types/index.ts b/packages/core/src/providers/pinpoint/types/index.ts index 36f1992aecd..e8c2749ee66 100644 --- a/packages/core/src/providers/pinpoint/types/index.ts +++ b/packages/core/src/providers/pinpoint/types/index.ts @@ -2,4 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 export { UpdateEndpointException } from './errors'; -export * from './pinpoint'; +export { + PinpointUpdateEndpointInput, + PinpointRecordInput, + SupportedCategory, + PinpointProviderConfig, + PinpointSession, + PinpointServiceOptions, + PinpointAnalyticsEvent, +} from './pinpoint'; diff --git a/packages/core/src/providers/pinpoint/types/pinpoint.ts b/packages/core/src/providers/pinpoint/types/pinpoint.ts index 16210807554..91d97aaf273 100644 --- a/packages/core/src/providers/pinpoint/types/pinpoint.ts +++ b/packages/core/src/providers/pinpoint/types/pinpoint.ts @@ -3,6 +3,7 @@ import { AuthSession } from '../../../singleton/Auth/types'; import { UserProfile } from '../../../types'; +import { EventBufferConfig } from './buffer'; export type SupportedCategory = | 'Analytics' @@ -13,7 +14,7 @@ export type SupportedCategory = type SupportedChannelType = 'APNS' | 'APNS_SANDBOX' | 'GCM' | 'IN_APP'; export type PinpointProviderConfig = { - Pinpoint: { + Pinpoint: Partial & { appId: string; region: string; }; @@ -55,6 +56,7 @@ export type PinpointUpdateEndpointInput = PinpointCommonParameters & userProfile?: UserProfile; }; -export type PinpointRecordInput = PinpointCommonParameters & { - event: PinpointAnalyticsEvent; -}; +export type PinpointRecordInput = Partial & + PinpointCommonParameters & { + event: PinpointAnalyticsEvent; + }; diff --git a/packages/core/src/providers/pinpoint/utils/PinpointEventBuffer.ts b/packages/core/src/providers/pinpoint/utils/PinpointEventBuffer.ts index 616e0ca2767..55e7ce02be7 100644 --- a/packages/core/src/providers/pinpoint/utils/PinpointEventBuffer.ts +++ b/packages/core/src/providers/pinpoint/utils/PinpointEventBuffer.ts @@ -9,7 +9,7 @@ import { PutEventsOutput, } from '../../../awsClients/pinpoint'; import { - EventBufferConfig, + PinpointEventBufferConfig, BufferedEvent, BufferedEventMap, EventBuffer, @@ -22,13 +22,13 @@ const RETRYABLE_CODES = [429, 500]; const ACCEPTED_CODES = [202]; export class PinpointEventBuffer { - private _config: EventBufferConfig; + private _config: PinpointEventBufferConfig; private _interval: ReturnType | undefined = undefined; private _buffer: EventBuffer; private _pause = false; private _flush = false; - constructor(config: EventBufferConfig) { + constructor(config: PinpointEventBufferConfig) { this._buffer = []; this._config = config; diff --git a/packages/core/src/providers/pinpoint/utils/getEventBuffer.ts b/packages/core/src/providers/pinpoint/utils/getEventBuffer.ts index c2778359361..0f737391915 100644 --- a/packages/core/src/providers/pinpoint/utils/getEventBuffer.ts +++ b/packages/core/src/providers/pinpoint/utils/getEventBuffer.ts @@ -3,32 +3,40 @@ import { EventBufferConfig } from '../types/buffer'; import { PinpointEventBuffer } from './PinpointEventBuffer'; -import { BUFFER_SIZE, FLUSH_INTERVAL, FLUSH_SIZE, RESEND_LIMIT } from './constants'; +import { AuthSession } from '../../../singleton/Auth/types'; // Map of buffers by region -> appId const eventBufferMap: Record> = {}; +export type GetEventBufferInput = EventBufferConfig & { + appId: string; + region: string; + credentials: Required['credentials']; + identityId?: AuthSession['identityId']; + userAgentValue?: string; +}; + /** * Returns a PinpointEventBuffer instance for the specified region & app ID, creating one if it does not yet exist. - * + * * @internal */ export const getEventBuffer = ({ appId, - bufferSize = BUFFER_SIZE, + region, credentials, - flushInterval = FLUSH_INTERVAL, - flushSize = FLUSH_SIZE, + bufferSize, + flushInterval, + flushSize, + resendLimit, identityId, - region, - resendLimit = RESEND_LIMIT, - userAgentValue -}: EventBufferConfig): PinpointEventBuffer => { + userAgentValue, +}: GetEventBufferInput): PinpointEventBuffer => { if (eventBufferMap[region]?.[appId]) { const buffer = eventBufferMap[region][appId]; /* - If the identity has changed flush out the buffer and create a new instance. The old instance will be garbage + If the identity has changed flush out the buffer and create a new instance. The old instance will be garbage collected. */ if (buffer.identityHasChanged(identityId)) { @@ -47,7 +55,7 @@ export const getEventBuffer = ({ identityId, region, resendLimit, - userAgentValue + userAgentValue, }); if (!eventBufferMap[region]) {