@aws-amplify/analytics 6.1.2-unstable.ffe65ea.1 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,24 +1,24 @@
1
1
  // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
 
4
+ import { Cache } from '@aws-amplify/cache';
4
5
  import {
5
6
  ConsoleLogger as Logger,
6
7
  ClientDevice,
7
8
  Credentials,
8
9
  Signer,
9
10
  Hub,
10
- getAmplifyUserAgent,
11
11
  transferKeyToLowerCase,
12
12
  transferKeyToUpperCase,
13
13
  } from '@aws-amplify/core';
14
14
  import {
15
- EventsBatch,
16
- PinpointClient,
17
- PutEventsCommand,
18
- PutEventsCommandInput,
19
- UpdateEndpointCommand,
20
- } from '@aws-sdk/client-pinpoint';
21
- import { Cache } from '@aws-amplify/cache';
15
+ putEvents,
16
+ PutEventsInput,
17
+ PutEventsOutput,
18
+ updateEndpoint,
19
+ UpdateEndpointInput,
20
+ UpdateEndpointOutput,
21
+ } from '@aws-amplify/core/internals/aws-clients/pinpoint';
22
22
 
23
23
  import {
24
24
  AnalyticsProvider,
@@ -29,7 +29,7 @@ import {
29
29
  EndpointFailureData,
30
30
  } from '../types';
31
31
  import { v1 as uuid } from 'uuid';
32
- import EventsBuffer from './EventBuffer';
32
+ import EventBuffer from './EventBuffer';
33
33
 
34
34
  const AMPLIFY_SYMBOL = (
35
35
  typeof Symbol !== 'undefined' && typeof Symbol.for === 'function'
@@ -68,10 +68,9 @@ export class AWSPinpointProvider implements AnalyticsProvider {
68
68
  static providerName = 'AWSPinpoint';
69
69
 
70
70
  private _config;
71
- private pinpointClient;
72
71
  private _sessionId;
73
72
  private _sessionStartTimestamp;
74
- private _buffer: EventsBuffer;
73
+ private _buffer: EventBuffer | null;
75
74
  private _endpointBuffer: EndpointBuffer;
76
75
  private _clientInfo;
77
76
  private _endpointGenerating = true;
@@ -152,7 +151,7 @@ export class AWSPinpointProvider implements AnalyticsProvider {
152
151
  );
153
152
  }
154
153
 
155
- this._initClients(credentials);
154
+ this._init(credentials);
156
155
 
157
156
  const timestamp = new Date().getTime();
158
157
  // attach the session and eventId
@@ -194,7 +193,7 @@ export class AWSPinpointProvider implements AnalyticsProvider {
194
193
  return;
195
194
  }
196
195
 
197
- this._buffer && this._buffer.push({ params, handlers });
196
+ this._buffer?.push({ params, handlers });
198
197
  }
199
198
 
200
199
  private _generateSession(params) {
@@ -249,34 +248,31 @@ export class AWSPinpointProvider implements AnalyticsProvider {
249
248
  }
250
249
  }
251
250
 
252
- private _generateBatchItemContext(params) {
251
+ private _generateBatchItemContext(params): PutEventsInput {
253
252
  const { event, timestamp, config } = params;
254
253
  const { name, attributes, metrics, eventId, session } = event;
255
254
  const { appId, endpointId } = config;
256
-
257
255
  const endpointContext = {};
258
256
 
259
- const eventParams: PutEventsCommandInput = {
257
+ return {
260
258
  ApplicationId: appId,
261
259
  EventsRequest: {
262
- BatchItem: {},
263
- },
264
- };
265
-
266
- const endpointObj: EventsBatch = {} as EventsBatch;
267
- endpointObj.Endpoint = endpointContext;
268
- endpointObj.Events = {
269
- [eventId]: {
270
- EventType: name,
271
- Timestamp: new Date(timestamp).toISOString(),
272
- Attributes: attributes,
273
- Metrics: metrics,
274
- Session: session,
260
+ BatchItem: {
261
+ [endpointId]: {
262
+ Endpoint: endpointContext,
263
+ Events: {
264
+ [eventId]: {
265
+ EventType: name,
266
+ Timestamp: new Date(timestamp).toISOString(),
267
+ Attributes: attributes,
268
+ Metrics: metrics,
269
+ Session: session,
270
+ },
271
+ },
272
+ },
273
+ },
275
274
  },
276
275
  };
277
- eventParams.EventsRequest.BatchItem[endpointId] = endpointObj;
278
-
279
- return eventParams;
280
276
  }
281
277
 
282
278
  private async _pinpointPutEvents(params, handlers) {
@@ -285,33 +281,30 @@ export class AWSPinpointProvider implements AnalyticsProvider {
285
281
  config: { endpointId },
286
282
  } = params;
287
283
  const eventParams = this._generateBatchItemContext(params);
288
- const command: PutEventsCommand = new PutEventsCommand(eventParams);
289
284
 
290
285
  try {
291
- const data = await this.pinpointClient.send(command);
292
- const {
293
- EventsResponse: {
294
- Results: {
295
- [endpointId]: {
296
- EventsItemResponse: {
297
- [eventId]: { StatusCode, Message },
298
- },
299
- },
300
- },
301
- },
302
- } = data;
303
- if (ACCEPTED_CODES.includes(StatusCode)) {
286
+ const { credentials, region } = this._config;
287
+ const data: PutEventsOutput = await putEvents(
288
+ { credentials, region },
289
+ eventParams
290
+ );
291
+
292
+ const { StatusCode, Message } =
293
+ data.EventsResponse?.Results?.[endpointId]?.EventsItemResponse?.[
294
+ eventId
295
+ ] ?? {};
296
+
297
+ if (StatusCode && ACCEPTED_CODES.includes(StatusCode)) {
304
298
  logger.debug('record event success. ', data);
305
299
  return handlers.resolve(data);
300
+ } else if (StatusCode && RETRYABLE_CODES.includes(StatusCode)) {
301
+ // TODO: v6 integrate retry to the service handler retryDecider
302
+ this._retry(params, handlers);
306
303
  } else {
307
- if (RETRYABLE_CODES.includes(StatusCode)) {
308
- this._retry(params, handlers);
309
- } else {
310
- logger.error(
311
- `Event ${eventId} is not accepted, the error is ${Message}`
312
- );
313
- return handlers.reject(data);
314
- }
304
+ logger.error(
305
+ `Event ${eventId} is not accepted, the error is ${Message}`
306
+ );
307
+ return handlers.reject(data);
315
308
  }
316
309
  } catch (err) {
317
310
  this._eventError(err);
@@ -319,7 +312,7 @@ export class AWSPinpointProvider implements AnalyticsProvider {
319
312
  }
320
313
  }
321
314
 
322
- private _pinpointSendStopSession(params, handlers): Promise<string> {
315
+ private _pinpointSendStopSession(params, handlers): Promise<string> | void {
323
316
  if (!BEACON_SUPPORTED) {
324
317
  this._pinpointPutEvents(params, handlers);
325
318
  return;
@@ -348,12 +341,7 @@ export class AWSPinpointProvider implements AnalyticsProvider {
348
341
 
349
342
  const serviceInfo = { region, service: MOBILE_SERVICE_NAME };
350
343
 
351
- const requestUrl: string = Signer.signUrl(
352
- request,
353
- accessInfo,
354
- serviceInfo,
355
- null
356
- );
344
+ const requestUrl: string = Signer.signUrl(request, accessInfo, serviceInfo);
357
345
 
358
346
  const success: boolean = navigator.sendBeacon(requestUrl, body);
359
347
 
@@ -393,18 +381,18 @@ export class AWSPinpointProvider implements AnalyticsProvider {
393
381
  ['attributes', 'userAttributes', 'Attributes', 'UserAttributes']
394
382
  )
395
383
  );
396
- const update_params = {
384
+ const update_params: UpdateEndpointInput = {
397
385
  ApplicationId: appId,
398
386
  EndpointId: endpointId,
399
387
  EndpointRequest: request,
400
388
  };
401
389
 
402
390
  try {
403
- const command: UpdateEndpointCommand = new UpdateEndpointCommand(
391
+ const { credentials, region } = this._config;
392
+ const data: UpdateEndpointOutput = await updateEndpoint(
393
+ { credentials, region },
404
394
  update_params
405
395
  );
406
- const data = await this.pinpointClient.send(command);
407
-
408
396
  logger.debug('updateEndpoint success', data);
409
397
  this._endpointGenerating = false;
410
398
  this._resumeBuffer();
@@ -492,13 +480,12 @@ export class AWSPinpointProvider implements AnalyticsProvider {
492
480
  /**
493
481
  * @private
494
482
  * @param config
495
- * Init the clients
483
+ * Configure credentials and init buffer
496
484
  */
497
- private async _initClients(credentials) {
498
- logger.debug('init clients');
485
+ private async _init(credentials) {
486
+ logger.debug('init provider');
499
487
 
500
488
  if (
501
- this.pinpointClient &&
502
489
  this._config.credentials &&
503
490
  this._config.credentials.sessionToken === credentials.sessionToken &&
504
491
  this._config.credentials.identityId === credentials.identityId
@@ -512,43 +499,17 @@ export class AWSPinpointProvider implements AnalyticsProvider {
512
499
  : null;
513
500
 
514
501
  this._config.credentials = credentials;
515
- const { region } = this._config;
516
- logger.debug('init clients with credentials', credentials);
517
- this.pinpointClient = new PinpointClient({
518
- region,
519
- credentials,
520
- customUserAgent: getAmplifyUserAgent(),
521
- });
522
-
523
- // TODO: remove this middleware once a long term fix is implemented by aws-sdk-js team.
524
- this.pinpointClient.middlewareStack.addRelativeTo(
525
- next => args => {
526
- delete args.request.headers['amz-sdk-invocation-id'];
527
- delete args.request.headers['amz-sdk-request'];
528
- return next(args);
529
- },
530
- {
531
- step: 'finalizeRequest',
532
- relation: 'after',
533
- toMiddleware: 'retryMiddleware',
534
- }
535
- );
536
502
 
537
- if (this._bufferExists() && identityId === credentials.identityId) {
538
- // if the identity has remained the same, pass the updated client to the buffer
539
- this._updateBufferClient();
540
- } else {
541
- // otherwise flush the buffer and instantiate a new one
503
+ if (!this._bufferExists() || identityId !== credentials.identityId) {
504
+ // if the identity has changed, flush the buffer and instantiate a new one
542
505
  // this will cause the old buffer to send any remaining events
543
506
  // with the old credentials and then stop looping and shortly thereafter get picked up by GC
544
507
  this._initBuffer();
545
508
  }
546
-
547
- this._customizePinpointClientReq();
548
509
  }
549
510
 
550
511
  private _bufferExists() {
551
- return this._buffer && this._buffer instanceof EventsBuffer;
512
+ return this._buffer && this._buffer instanceof EventBuffer;
552
513
  }
553
514
 
554
515
  private _initBuffer() {
@@ -556,7 +517,7 @@ export class AWSPinpointProvider implements AnalyticsProvider {
556
517
  this._flushBuffer();
557
518
  }
558
519
 
559
- this._buffer = new EventsBuffer(this.pinpointClient, this._config);
520
+ this._buffer = new EventBuffer(this._config);
560
521
 
561
522
  // if the first endpoint update hasn't yet resolved pause the buffer to
562
523
  // prevent race conditions. It will be resumed as soon as that request succeeds
@@ -565,36 +526,19 @@ export class AWSPinpointProvider implements AnalyticsProvider {
565
526
  }
566
527
  }
567
528
 
568
- private _updateBufferClient() {
569
- if (this._bufferExists()) {
570
- this._buffer.updateClient(this.pinpointClient);
571
- }
572
- }
573
-
574
529
  private _flushBuffer() {
575
530
  if (this._bufferExists()) {
576
- this._buffer.flush();
531
+ this._buffer?.flush();
577
532
  this._buffer = null;
578
533
  }
579
534
  }
580
535
 
581
536
  private _resumeBuffer() {
582
537
  if (this._bufferExists()) {
583
- this._buffer.resume();
538
+ this._buffer?.resume();
584
539
  }
585
540
  }
586
541
 
587
- private _customizePinpointClientReq() {
588
- // TODO FIXME: Find a middleware to do this with AWS V3 SDK
589
- // if (Platform.isReactNative) {
590
- // this.pinpointClient.customizeRequests(request => {
591
- // request.on('build', req => {
592
- // req.httpRequest.headers['user-agent'] = Platform.userAgent;
593
- // });
594
- // });
595
- // }
596
- }
597
-
598
542
  private async _getEndpointId(cacheKey) {
599
543
  // try to get from cache
600
544
  let endpointId = await Cache.getItem(cacheKey);
@@ -1,15 +1,10 @@
1
1
  import { ConsoleLogger as Logger } from '@aws-amplify/core';
2
-
3
- import {
4
- PutEventsResponse,
5
- EventBuffer,
6
- EventObject,
7
- EventMap,
8
- } from '../types';
9
2
  import {
10
- PutEventsCommand,
11
- PutEventsCommandOutput,
12
- } from '@aws-sdk/client-pinpoint';
3
+ putEvents,
4
+ PutEventsInput,
5
+ PutEventsOutput,
6
+ } from '@aws-amplify/core/internals/aws-clients/pinpoint';
7
+ import { EventBuffer, EventObject, EventMap } from '../types';
13
8
  import { isAppInForeground } from '../utils/AppUtils';
14
9
 
15
10
  const logger = new Logger('EventsBuffer');
@@ -25,16 +20,14 @@ type EventsBufferConfig = {
25
20
 
26
21
  export default class EventsBuffer {
27
22
  private _config;
28
- private _client;
29
23
  private _interval;
30
24
  private _buffer: EventBuffer;
31
25
  private _pause = false;
32
26
  private _flush = false;
33
27
 
34
- constructor(client, config: EventsBufferConfig) {
28
+ constructor(config: EventsBufferConfig) {
35
29
  logger.debug('Instantiating buffer with config:', config);
36
30
  this._buffer = [];
37
- this._client = client;
38
31
  this._config = config;
39
32
 
40
33
  this._sendBatch = this._sendBatch.bind(this);
@@ -64,10 +57,6 @@ export default class EventsBuffer {
64
57
  this._pause = false;
65
58
  }
66
59
 
67
- public updateClient(client) {
68
- this._client = client;
69
- }
70
-
71
60
  public flush() {
72
61
  this._flush = true;
73
62
  }
@@ -110,15 +99,18 @@ export default class EventsBuffer {
110
99
  const batchEventParams = this._generateBatchEventParams(eventMap);
111
100
 
112
101
  try {
113
- const command: PutEventsCommand = new PutEventsCommand(batchEventParams);
114
- const data: PutEventsCommandOutput = await this._client.send(command);
102
+ const { credentials, region } = this._config;
103
+ const data: PutEventsOutput = await putEvents(
104
+ { credentials, region },
105
+ batchEventParams
106
+ );
115
107
  this._processPutEventsSuccessResponse(data, eventMap);
116
108
  } catch (err) {
117
109
  return this._handlePutEventsFailure(err, eventMap);
118
110
  }
119
111
  }
120
112
 
121
- private _generateBatchEventParams(eventMap: EventMap) {
113
+ private _generateBatchEventParams(eventMap: EventMap): PutEventsInput {
122
114
  const batchEventParams = {
123
115
  ApplicationId: '',
124
116
  EventsRequest: {
@@ -167,50 +159,53 @@ export default class EventsBuffer {
167
159
  }
168
160
 
169
161
  private _processPutEventsSuccessResponse(
170
- data: PutEventsResponse,
162
+ data: PutEventsOutput,
171
163
  eventMap: EventMap
172
164
  ) {
173
- const { Results } = data.EventsResponse;
165
+ const { Results = {} } = data.EventsResponse ?? {};
174
166
  const retryableEvents: EventObject[] = [];
175
167
 
176
168
  Object.entries(Results).forEach(([endpointId, endpointValues]) => {
177
- const responses = endpointValues.EventsItemResponse;
178
-
179
- Object.entries(responses).forEach(
180
- ([eventId, { StatusCode, Message }]) => {
181
- const eventObject = eventMap[eventId];
182
-
183
- // manually crafting handlers response to keep API consistant
184
- const response = {
185
- EventsResponse: {
186
- Results: {
187
- [endpointId]: {
188
- EventsItemResponse: {
189
- [eventId]: { StatusCode, Message },
190
- },
169
+ const responses = endpointValues.EventsItemResponse ?? {};
170
+
171
+ Object.entries(responses).forEach(([eventId, eventValues]) => {
172
+ const eventObject = eventMap[eventId];
173
+ if (!eventObject) {
174
+ return;
175
+ }
176
+
177
+ const { StatusCode, Message } = eventValues ?? {};
178
+
179
+ // manually crafting handlers response to keep API consistant
180
+ const response = {
181
+ EventsResponse: {
182
+ Results: {
183
+ [endpointId]: {
184
+ EventsItemResponse: {
185
+ [eventId]: { StatusCode, Message },
191
186
  },
192
187
  },
193
188
  },
194
- };
189
+ },
190
+ };
195
191
 
196
- if (ACCEPTED_CODES.includes(StatusCode)) {
197
- eventObject.handlers.resolve(response);
198
- return;
199
- }
192
+ if (StatusCode && ACCEPTED_CODES.includes(StatusCode)) {
193
+ eventObject.handlers.resolve(response);
194
+ return;
195
+ }
200
196
 
201
- if (RETRYABLE_CODES.includes(StatusCode)) {
202
- retryableEvents.push(eventObject);
203
- return;
204
- }
197
+ if (StatusCode && RETRYABLE_CODES.includes(StatusCode)) {
198
+ retryableEvents.push(eventObject);
199
+ return;
200
+ }
205
201
 
206
- const { name } = eventObject.params.event;
202
+ const { name } = eventObject.params.event;
207
203
 
208
- logger.error(
209
- `event ${eventId} : ${name} failed with error: ${Message}`
210
- );
211
- return eventObject.handlers.reject(response);
212
- }
213
- );
204
+ logger.error(
205
+ `event ${eventId} : ${name} failed with error: ${Message}`
206
+ );
207
+ return eventObject.handlers.reject(response);
208
+ });
214
209
  });
215
210
 
216
211
  if (retryableEvents.length) {