@aws-amplify/pubsub 4.2.10-cloud-logging.7 → 4.2.10-cloud-logging.8

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +24 -49
  2. package/dist/aws-amplify-pubsub.js +238 -202
  3. package/dist/aws-amplify-pubsub.js.map +1 -1
  4. package/dist/aws-amplify-pubsub.min.js +2 -2
  5. package/dist/aws-amplify-pubsub.min.js.map +1 -1
  6. package/lib/Providers/AWSAppSyncProvider.d.ts +3 -0
  7. package/lib/Providers/AWSAppSyncProvider.js +3 -0
  8. package/lib/Providers/AWSAppSyncProvider.js.map +1 -1
  9. package/lib/Providers/AWSAppSyncRealTimeProvider.d.ts +19 -4
  10. package/lib/Providers/AWSAppSyncRealTimeProvider.js +174 -154
  11. package/lib/Providers/AWSAppSyncRealTimeProvider.js.map +1 -1
  12. package/lib/Providers/AWSIotProvider.d.ts +6 -1
  13. package/lib/Providers/AWSIotProvider.js +3 -2
  14. package/lib/Providers/AWSIotProvider.js.map +1 -1
  15. package/lib/Providers/MqttOverWSProvider.d.ts +14 -11
  16. package/lib/Providers/MqttOverWSProvider.js +17 -10
  17. package/lib/Providers/MqttOverWSProvider.js.map +1 -1
  18. package/lib/Providers/PubSubProvider.d.ts +7 -7
  19. package/lib/Providers/PubSubProvider.js.map +1 -1
  20. package/lib/PubSub.d.ts +6 -6
  21. package/lib/PubSub.js +2 -2
  22. package/lib/PubSub.js.map +1 -1
  23. package/lib/types/Provider.d.ts +3 -3
  24. package/lib/types/PubSub.d.ts +5 -1
  25. package/lib-esm/Providers/AWSAppSyncProvider.d.ts +3 -0
  26. package/lib-esm/Providers/AWSAppSyncProvider.js +3 -0
  27. package/lib-esm/Providers/AWSAppSyncProvider.js.map +1 -1
  28. package/lib-esm/Providers/AWSAppSyncRealTimeProvider.d.ts +19 -4
  29. package/lib-esm/Providers/AWSAppSyncRealTimeProvider.js +174 -154
  30. package/lib-esm/Providers/AWSAppSyncRealTimeProvider.js.map +1 -1
  31. package/lib-esm/Providers/AWSIotProvider.d.ts +6 -1
  32. package/lib-esm/Providers/AWSIotProvider.js +3 -2
  33. package/lib-esm/Providers/AWSIotProvider.js.map +1 -1
  34. package/lib-esm/Providers/MqttOverWSProvider.d.ts +14 -11
  35. package/lib-esm/Providers/MqttOverWSProvider.js +17 -10
  36. package/lib-esm/Providers/MqttOverWSProvider.js.map +1 -1
  37. package/lib-esm/Providers/PubSubProvider.d.ts +7 -7
  38. package/lib-esm/Providers/PubSubProvider.js.map +1 -1
  39. package/lib-esm/PubSub.d.ts +6 -6
  40. package/lib-esm/PubSub.js +2 -2
  41. package/lib-esm/PubSub.js.map +1 -1
  42. package/lib-esm/types/Provider.d.ts +3 -3
  43. package/lib-esm/types/PubSub.d.ts +5 -1
  44. package/package.json +5 -5
  45. package/src/Providers/AWSAppSyncProvider.ts +27 -26
  46. package/src/Providers/AWSAppSyncRealTimeProvider.ts +247 -191
  47. package/src/Providers/AWSIotProvider.ts +10 -1
  48. package/src/Providers/MqttOverWSProvider.ts +52 -33
  49. package/src/Providers/PubSubProvider.ts +8 -8
  50. package/src/PubSub.ts +10 -10
  51. package/src/types/Provider.ts +3 -7
  52. package/src/types/PubSub.ts +6 -1
@@ -15,7 +15,7 @@ import { GraphQLError } from 'graphql';
15
15
  import * as url from 'url';
16
16
  import { v4 as uuid } from 'uuid';
17
17
  import { Buffer } from 'buffer';
18
- import { ProvidertOptions } from '../types';
18
+ import { ProviderOptions } from '../types';
19
19
  import {
20
20
  Logger,
21
21
  Credentials,
@@ -25,9 +25,10 @@ import {
25
25
  USER_AGENT_HEADER,
26
26
  jitteredExponentialRetry,
27
27
  NonRetryableError,
28
+ ICredentials,
28
29
  } from '@aws-amplify/core';
29
30
  import Cache from '@aws-amplify/cache';
30
- import Auth from '@aws-amplify/auth';
31
+ import Auth, { GRAPHQL_AUTH_MODE } from '@aws-amplify/auth';
31
32
  import { AbstractPubSubProvider } from './PubSubProvider';
32
33
  import { CONTROL_MSG } from '../index';
33
34
 
@@ -54,7 +55,7 @@ type ObserverQuery = {
54
55
  subscriptionState: SUBSCRIPTION_STATUS;
55
56
  subscriptionReadyCallback?: Function;
56
57
  subscriptionFailedCallback?: Function;
57
- startAckTimeoutId?;
58
+ startAckTimeoutId?: ReturnType<typeof setTimeout>;
58
59
  };
59
60
 
60
61
  enum MESSAGE_TYPES {
@@ -148,10 +149,29 @@ const standardDomainPattern =
148
149
 
149
150
  const customDomainPath = '/realtime';
150
151
 
152
+ type GraphqlAuthModes = keyof typeof GRAPHQL_AUTH_MODE;
153
+
154
+ export interface AWSAppSyncRealTimeProviderOptions extends ProviderOptions {
155
+ appSyncGraphqlEndpoint?: string;
156
+ authenticationType?: GraphqlAuthModes;
157
+ query?: string;
158
+ variables?: object;
159
+ apiKey?: string;
160
+ region?: string;
161
+ graphql_headers?: () => {} | (() => Promise<{}>);
162
+ additionalHeaders?: { [key: string]: string };
163
+ }
164
+
165
+ type AWSAppSyncRealTimeAuthInput =
166
+ Partial<AWSAppSyncRealTimeProviderOptions> & {
167
+ canonicalUri: string;
168
+ payload: string;
169
+ };
170
+
151
171
  export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
152
- private awsRealTimeSocket: WebSocket;
172
+ private awsRealTimeSocket?: WebSocket;
153
173
  private socketStatus: SOCKET_STATUS = SOCKET_STATUS.CLOSED;
154
- private keepAliveTimeoutId;
174
+ private keepAliveTimeoutId?: ReturnType<typeof setTimeout>;
155
175
  private keepAliveTimeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
156
176
  private subscriptionObserverMap: Map<string, ObserverQuery> = new Map();
157
177
  private promiseArray: Array<{ res: Function; rej: Function }> = [];
@@ -175,12 +195,12 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
175
195
 
176
196
  subscribe(
177
197
  _topics: string[] | string,
178
- options?: ProvidertOptions
198
+ options?: AWSAppSyncRealTimeProviderOptions
179
199
  ): Observable<any> {
180
- const { appSyncGraphqlEndpoint } = options;
200
+ const appSyncGraphqlEndpoint = options?.appSyncGraphqlEndpoint;
181
201
 
182
202
  return new Observable(observer => {
183
- if (!appSyncGraphqlEndpoint) {
203
+ if (!options || !appSyncGraphqlEndpoint) {
184
204
  observer.error({
185
205
  errors: [
186
206
  {
@@ -197,7 +217,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
197
217
  options,
198
218
  observer,
199
219
  subscriptionId,
200
- }).catch(err => {
220
+ }).catch<any>(err => {
201
221
  observer.error({
202
222
  errors: [
203
223
  {
@@ -243,10 +263,15 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
243
263
  return !this.options
244
264
  .aws_appsync_dangerously_connect_to_http_endpoint_for_testing;
245
265
  }
266
+
246
267
  private async _startSubscriptionWithAWSAppSyncRealTime({
247
268
  options,
248
269
  observer,
249
270
  subscriptionId,
271
+ }: {
272
+ options: AWSAppSyncRealTimeProviderOptions;
273
+ observer: ZenObservable.SubscriptionObserver<any>;
274
+ subscriptionId: string;
250
275
  }) {
251
276
  const {
252
277
  appSyncGraphqlEndpoint,
@@ -267,10 +292,10 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
267
292
  // Having a subscription id map will make it simple to forward messages received
268
293
  this.subscriptionObserverMap.set(subscriptionId, {
269
294
  observer,
270
- query,
271
- variables,
295
+ query: query ?? '',
296
+ variables: variables ?? {},
272
297
  subscriptionState,
273
- startAckTimeoutId: null,
298
+ startAckTimeoutId: undefined,
274
299
  });
275
300
 
276
301
  // Preparing payload for subscription message
@@ -316,7 +341,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
316
341
  });
317
342
  } catch (err) {
318
343
  logger.debug({ err });
319
- const { message = '' } = err;
344
+ const message = err['message'] ?? '';
320
345
  observer.error({
321
346
  errors: [
322
347
  {
@@ -325,7 +350,6 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
325
350
  ],
326
351
  });
327
352
  observer.complete();
328
-
329
353
  const { subscriptionFailedCallback } =
330
354
  this.subscriptionObserverMap.get(subscriptionId) || {};
331
355
 
@@ -341,14 +365,14 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
341
365
  // Both subscriptionFailedCallback and subscriptionReadyCallback are used to synchronized this.
342
366
 
343
367
  const { subscriptionFailedCallback, subscriptionReadyCallback } =
344
- this.subscriptionObserverMap.get(subscriptionId);
368
+ this.subscriptionObserverMap.get(subscriptionId) ?? {};
345
369
 
346
370
  // This must be done before sending the message in order to be listening immediately
347
371
  this.subscriptionObserverMap.set(subscriptionId, {
348
372
  observer,
349
373
  subscriptionState,
350
- variables,
351
- query,
374
+ query: query ?? '',
375
+ variables: variables ?? {},
352
376
  subscriptionReadyCallback,
353
377
  subscriptionFailedCallback,
354
378
  startAckTimeoutId: setTimeout(() => {
@@ -361,27 +385,30 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
361
385
  }
362
386
 
363
387
  // Waiting that subscription has been connected before trying to unsubscribe
364
- private async _waitForSubscriptionToBeConnected(subscriptionId) {
365
- const { subscriptionState } =
388
+ private async _waitForSubscriptionToBeConnected(subscriptionId: string) {
389
+ const subscriptionObserver =
366
390
  this.subscriptionObserverMap.get(subscriptionId);
367
- // This in case unsubscribe is invoked before sending start subscription message
368
- if (subscriptionState === SUBSCRIPTION_STATUS.PENDING) {
369
- return new Promise((res, rej) => {
370
- const { observer, subscriptionState, variables, query } =
371
- this.subscriptionObserverMap.get(subscriptionId);
372
- this.subscriptionObserverMap.set(subscriptionId, {
373
- observer,
374
- subscriptionState,
375
- variables,
376
- query,
377
- subscriptionReadyCallback: res,
378
- subscriptionFailedCallback: rej,
391
+ if (subscriptionObserver) {
392
+ const { subscriptionState } = subscriptionObserver;
393
+ // This in case unsubscribe is invoked before sending start subscription message
394
+ if (subscriptionState === SUBSCRIPTION_STATUS.PENDING) {
395
+ return new Promise((res, rej) => {
396
+ const { observer, subscriptionState, variables, query } =
397
+ subscriptionObserver;
398
+ this.subscriptionObserverMap.set(subscriptionId, {
399
+ observer,
400
+ subscriptionState,
401
+ variables,
402
+ query,
403
+ subscriptionReadyCallback: res,
404
+ subscriptionFailedCallback: rej,
405
+ });
379
406
  });
380
- });
407
+ }
381
408
  }
382
409
  }
383
410
 
384
- private _sendUnsubscriptionMessage(subscriptionId) {
411
+ private _sendUnsubscriptionMessage(subscriptionId: string) {
385
412
  try {
386
413
  if (
387
414
  this.awsRealTimeSocket &&
@@ -402,7 +429,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
402
429
  }
403
430
  }
404
431
 
405
- private _removeSubscriptionObserver(subscriptionId) {
432
+ private _removeSubscriptionObserver(subscriptionId: string) {
406
433
  this.subscriptionObserverMap.delete(subscriptionId);
407
434
 
408
435
  // Verifying 1000ms after removing subscription in case there are new subscription unmount/mount
@@ -424,13 +451,13 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
424
451
  setTimeout(this._closeSocketIfRequired.bind(this), 1000);
425
452
  } else {
426
453
  logger.debug('closing WebSocket...');
427
- clearTimeout(this.keepAliveTimeoutId);
454
+ if (this.keepAliveTimeoutId) clearTimeout(this.keepAliveTimeoutId);
428
455
  const tempSocket = this.awsRealTimeSocket;
429
456
  // Cleaning callbacks to avoid race condition, socket still exists
430
- tempSocket.onclose = undefined;
431
- tempSocket.onerror = undefined;
457
+ tempSocket.onclose = null;
458
+ tempSocket.onerror = null;
432
459
  tempSocket.close(1000);
433
- this.awsRealTimeSocket = null;
460
+ this.awsRealTimeSocket = undefined;
434
461
  this.socketStatus = SOCKET_STATUS.CLOSED;
435
462
  }
436
463
  }
@@ -478,29 +505,31 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
478
505
  if (typeof subscriptionReadyCallback === 'function') {
479
506
  subscriptionReadyCallback();
480
507
  }
481
- clearTimeout(startAckTimeoutId);
508
+ if (startAckTimeoutId) clearTimeout(startAckTimeoutId);
482
509
  dispatchApiEvent(
483
510
  CONTROL_MSG.SUBSCRIPTION_ACK,
484
511
  { query, variables },
485
512
  'Connection established for subscription'
486
513
  );
487
514
  const subscriptionState = SUBSCRIPTION_STATUS.CONNECTED;
488
- this.subscriptionObserverMap.set(id, {
489
- observer,
490
- query,
491
- variables,
492
- startAckTimeoutId: null,
493
- subscriptionState,
494
- subscriptionReadyCallback,
495
- subscriptionFailedCallback,
496
- });
515
+ if (observer) {
516
+ this.subscriptionObserverMap.set(id, {
517
+ observer,
518
+ query,
519
+ variables,
520
+ startAckTimeoutId: undefined,
521
+ subscriptionState,
522
+ subscriptionReadyCallback,
523
+ subscriptionFailedCallback,
524
+ });
525
+ }
497
526
 
498
527
  // TODO: emit event on hub but it requires to store the id first
499
528
  return;
500
529
  }
501
530
 
502
531
  if (type === MESSAGE_TYPES.GQL_CONNECTION_KEEP_ALIVE) {
503
- clearTimeout(this.keepAliveTimeoutId);
532
+ if (this.keepAliveTimeoutId) clearTimeout(this.keepAliveTimeoutId);
504
533
  this.keepAliveTimeoutId = setTimeout(
505
534
  this._errorDisconnect.bind(this, CONTROL_MSG.TIMEOUT_DISCONNECT),
506
535
  this.keepAliveTimeout
@@ -510,30 +539,32 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
510
539
 
511
540
  if (type === MESSAGE_TYPES.GQL_ERROR) {
512
541
  const subscriptionState = SUBSCRIPTION_STATUS.FAILED;
513
- this.subscriptionObserverMap.set(id, {
514
- observer,
515
- query,
516
- variables,
517
- startAckTimeoutId,
518
- subscriptionReadyCallback,
519
- subscriptionFailedCallback,
520
- subscriptionState,
521
- });
542
+ if (observer) {
543
+ this.subscriptionObserverMap.set(id, {
544
+ observer,
545
+ query,
546
+ variables,
547
+ startAckTimeoutId,
548
+ subscriptionReadyCallback,
549
+ subscriptionFailedCallback,
550
+ subscriptionState,
551
+ });
522
552
 
523
- observer.error({
524
- errors: [
525
- {
526
- ...new GraphQLError(
527
- `${CONTROL_MSG.CONNECTION_FAILED}: ${JSON.stringify(payload)}`
528
- ),
529
- },
530
- ],
531
- });
532
- clearTimeout(startAckTimeoutId);
553
+ observer.error({
554
+ errors: [
555
+ {
556
+ ...new GraphQLError(
557
+ `${CONTROL_MSG.CONNECTION_FAILED}: ${JSON.stringify(payload)}`
558
+ ),
559
+ },
560
+ ],
561
+ });
562
+ if (startAckTimeoutId) clearTimeout(startAckTimeoutId);
533
563
 
534
- observer.complete();
535
- if (typeof subscriptionFailedCallback === 'function') {
536
- subscriptionFailedCallback();
564
+ observer.complete();
565
+ if (typeof subscriptionFailedCallback === 'function') {
566
+ subscriptionFailedCallback();
567
+ }
537
568
  }
538
569
  }
539
570
  }
@@ -555,39 +586,42 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
555
586
  this.socketStatus = SOCKET_STATUS.CLOSED;
556
587
  }
557
588
 
558
- private _timeoutStartSubscriptionAck(subscriptionId) {
559
- const { observer, query, variables } =
560
- this.subscriptionObserverMap.get(subscriptionId) || {};
561
- if (!observer) {
562
- return;
563
- }
564
- this.subscriptionObserverMap.set(subscriptionId, {
565
- observer,
566
- query,
567
- variables,
568
- subscriptionState: SUBSCRIPTION_STATUS.FAILED,
569
- });
570
-
571
- if (observer && !observer.closed) {
572
- observer.error({
573
- errors: [
574
- {
575
- ...new GraphQLError(
576
- `Subscription timeout ${JSON.stringify({
577
- query,
578
- variables,
579
- })}`
580
- ),
581
- },
582
- ],
589
+ private _timeoutStartSubscriptionAck(subscriptionId: string) {
590
+ const subscriptionObserver =
591
+ this.subscriptionObserverMap.get(subscriptionId);
592
+ if (subscriptionObserver) {
593
+ const { observer, query, variables } = subscriptionObserver;
594
+ if (!observer) {
595
+ return;
596
+ }
597
+ this.subscriptionObserverMap.set(subscriptionId, {
598
+ observer,
599
+ query,
600
+ variables,
601
+ subscriptionState: SUBSCRIPTION_STATUS.FAILED,
583
602
  });
584
- // Cleanup will be automatically executed
585
- observer.complete();
603
+
604
+ if (observer && !observer.closed) {
605
+ observer.error({
606
+ errors: [
607
+ {
608
+ ...new GraphQLError(
609
+ `Subscription timeout ${JSON.stringify({
610
+ query,
611
+ variables,
612
+ })}`
613
+ ),
614
+ },
615
+ ],
616
+ });
617
+ // Cleanup will be automatically executed
618
+ observer.complete();
619
+ }
620
+ logger.debug(
621
+ 'timeoutStartSubscription',
622
+ JSON.stringify({ query, variables })
623
+ );
586
624
  }
587
- logger.debug(
588
- 'timeoutStartSubscription',
589
- JSON.stringify({ query, variables })
590
- );
591
625
  }
592
626
 
593
627
  private _initializeWebSocketConnection({
@@ -596,7 +630,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
596
630
  apiKey,
597
631
  region,
598
632
  additionalHeaders,
599
- }) {
633
+ }: AWSAppSyncRealTimeProviderOptions) {
600
634
  if (this.socketStatus === SOCKET_STATUS.READY) {
601
635
  return;
602
636
  }
@@ -623,7 +657,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
623
657
 
624
658
  const payloadQs = Buffer.from(payloadString).toString('base64');
625
659
 
626
- let discoverableEndpoint = appSyncGraphqlEndpoint;
660
+ let discoverableEndpoint = appSyncGraphqlEndpoint ?? '';
627
661
 
628
662
  if (this.isCustomDomain(discoverableEndpoint)) {
629
663
  discoverableEndpoint =
@@ -642,7 +676,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
642
676
 
643
677
  const awsRealTimeUrl = `${discoverableEndpoint}?header=${headerQs}&payload=${payloadQs}`;
644
678
 
645
- await this._initializeRetryableHandshake({ awsRealTimeUrl });
679
+ await this._initializeRetryableHandshake(awsRealTimeUrl);
646
680
 
647
681
  this.promiseArray.forEach(({ res }) => {
648
682
  logger.debug('Notifying connection successful');
@@ -659,23 +693,23 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
659
693
  ) {
660
694
  this.awsRealTimeSocket.close(3001);
661
695
  }
662
- this.awsRealTimeSocket = null;
696
+ this.awsRealTimeSocket = undefined;
663
697
  this.socketStatus = SOCKET_STATUS.CLOSED;
664
698
  }
665
699
  }
666
700
  });
667
701
  }
668
702
 
669
- private async _initializeRetryableHandshake({ awsRealTimeUrl }) {
703
+ private async _initializeRetryableHandshake(awsRealTimeUrl: string) {
670
704
  logger.debug(`Initializaling retryable Handshake`);
671
705
  await jitteredExponentialRetry(
672
706
  this._initializeHandshake.bind(this),
673
- [{ awsRealTimeUrl }],
707
+ [awsRealTimeUrl],
674
708
  MAX_DELAY_MS
675
709
  );
676
710
  }
677
711
 
678
- private async _initializeHandshake({ awsRealTimeUrl }) {
712
+ private async _initializeHandshake(awsRealTimeUrl: string) {
679
713
  logger.debug(`Initializing handshake ${awsRealTimeUrl}`);
680
714
  // Because connecting the socket is async, is waiting until connection is open
681
715
  // Step 1: connect websocket
@@ -699,60 +733,66 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
699
733
  // Step 2: wait for ack from AWS AppSyncReaTime after sending init
700
734
  await (() => {
701
735
  return new Promise((res, rej) => {
702
- let ackOk = false;
703
- this.awsRealTimeSocket.onerror = error => {
704
- logger.debug(`WebSocket error ${JSON.stringify(error)}`);
705
- };
706
- this.awsRealTimeSocket.onclose = event => {
707
- logger.debug(`WebSocket closed ${event.reason}`);
708
- rej(new Error(JSON.stringify(event)));
709
- };
710
-
711
- this.awsRealTimeSocket.onmessage = (message: MessageEvent) => {
712
- logger.debug(
713
- `subscription message from AWS AppSyncRealTime: ${message.data} `
714
- );
715
- const data = JSON.parse(message.data);
716
- const {
717
- type,
718
- payload: {
719
- connectionTimeoutMs = DEFAULT_KEEP_ALIVE_TIMEOUT,
720
- } = {},
721
- } = data;
722
- if (type === MESSAGE_TYPES.GQL_CONNECTION_ACK) {
723
- ackOk = true;
724
- this.keepAliveTimeout = connectionTimeoutMs;
725
- this.awsRealTimeSocket.onmessage =
726
- this._handleIncomingSubscriptionMessage.bind(this);
727
- this.awsRealTimeSocket.onerror = err => {
728
- logger.debug(err);
729
- this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
730
- };
731
- this.awsRealTimeSocket.onclose = event => {
732
- logger.debug(`WebSocket closed ${event.reason}`);
733
- this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
734
- };
735
- res('Cool, connected to AWS AppSyncRealTime');
736
- return;
737
- }
738
-
739
- if (type === MESSAGE_TYPES.GQL_CONNECTION_ERROR) {
736
+ if (this.awsRealTimeSocket) {
737
+ let ackOk = false;
738
+ this.awsRealTimeSocket.onerror = error => {
739
+ logger.debug(`WebSocket error ${JSON.stringify(error)}`);
740
+ };
741
+ this.awsRealTimeSocket.onclose = event => {
742
+ logger.debug(`WebSocket closed ${event.reason}`);
743
+ rej(new Error(JSON.stringify(event)));
744
+ };
745
+
746
+ this.awsRealTimeSocket.onmessage = (message: MessageEvent) => {
747
+ logger.debug(
748
+ `subscription message from AWS AppSyncRealTime: ${message.data} `
749
+ );
750
+ const data = JSON.parse(message.data);
740
751
  const {
752
+ type,
741
753
  payload: {
742
- errors: [{ errorType = '', errorCode = 0 } = {}] = [],
754
+ connectionTimeoutMs = DEFAULT_KEEP_ALIVE_TIMEOUT,
743
755
  } = {},
744
756
  } = data;
757
+ if (type === MESSAGE_TYPES.GQL_CONNECTION_ACK) {
758
+ ackOk = true;
759
+ if (this.awsRealTimeSocket) {
760
+ this.keepAliveTimeout = connectionTimeoutMs;
761
+ this.awsRealTimeSocket.onmessage =
762
+ this._handleIncomingSubscriptionMessage.bind(this);
763
+ this.awsRealTimeSocket.onerror = err => {
764
+ logger.debug(err);
765
+ this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
766
+ };
767
+ this.awsRealTimeSocket.onclose = event => {
768
+ logger.debug(`WebSocket closed ${event.reason}`);
769
+ this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
770
+ };
771
+ }
772
+ res('Cool, connected to AWS AppSyncRealTime');
773
+ return;
774
+ }
775
+
776
+ if (type === MESSAGE_TYPES.GQL_CONNECTION_ERROR) {
777
+ const {
778
+ payload: {
779
+ errors: [{ errorType = '', errorCode = 0 } = {}] = [],
780
+ } = {},
781
+ } = data;
782
+
783
+ rej({ errorType, errorCode });
784
+ }
785
+ };
786
+
787
+ const gqlInit = {
788
+ type: MESSAGE_TYPES.GQL_CONNECTION_INIT,
789
+ };
790
+ this.awsRealTimeSocket.send(JSON.stringify(gqlInit));
791
+
792
+ setTimeout(checkAckOk.bind(this, ackOk), CONNECTION_INIT_TIMEOUT);
793
+ }
745
794
 
746
- rej({ errorType, errorCode });
747
- }
748
- };
749
-
750
- const gqlInit = {
751
- type: MESSAGE_TYPES.GQL_CONNECTION_INIT,
752
- };
753
- this.awsRealTimeSocket.send(JSON.stringify(gqlInit));
754
-
755
- function checkAckOk() {
795
+ function checkAckOk(ackOk: boolean) {
756
796
  if (!ackOk) {
757
797
  rej(
758
798
  new Error(
@@ -761,12 +801,13 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
761
801
  );
762
802
  }
763
803
  }
764
-
765
- setTimeout(checkAckOk.bind(this), CONNECTION_INIT_TIMEOUT);
766
804
  });
767
805
  })();
768
806
  } catch (err) {
769
- const { errorType, errorCode } = err;
807
+ const { errorType, errorCode } = err as {
808
+ errorType: string;
809
+ errorCode: number;
810
+ };
770
811
 
771
812
  if (NON_RETRYABLE_CODES.includes(errorCode)) {
772
813
  throw new NonRetryableError(errorType);
@@ -786,8 +827,10 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
786
827
  apiKey,
787
828
  region,
788
829
  additionalHeaders,
789
- }): Promise<any> {
790
- const headerHandler = {
830
+ }: AWSAppSyncRealTimeProviderOptions): Promise<any> {
831
+ const headerHandler: {
832
+ [key in GraphqlAuthModes]: (AWSAppSyncRealTimeAuthInput) => {};
833
+ } = {
791
834
  API_KEY: this._awsRealTimeApiKeyHeader.bind(this),
792
835
  AWS_IAM: this._awsRealTimeIAMHeader.bind(this),
793
836
  OPENID_CONNECT: this._awsRealTimeOPENIDHeader.bind(this),
@@ -795,29 +838,29 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
795
838
  AWS_LAMBDA: this._customAuthHeader,
796
839
  };
797
840
 
798
- const handler = headerHandler[authenticationType];
799
-
800
- if (typeof handler !== 'function') {
841
+ if (!authenticationType || !headerHandler[authenticationType]) {
801
842
  logger.debug(`Authentication type ${authenticationType} not supported`);
802
843
  return '';
803
- }
844
+ } else {
845
+ const handler = headerHandler[authenticationType];
804
846
 
805
- const { host } = url.parse(appSyncGraphqlEndpoint);
847
+ const { host } = url.parse(appSyncGraphqlEndpoint ?? '');
806
848
 
807
- const result = await handler({
808
- payload,
809
- canonicalUri,
810
- appSyncGraphqlEndpoint,
811
- apiKey,
812
- region,
813
- host,
814
- additionalHeaders,
815
- });
849
+ const result = await handler({
850
+ payload,
851
+ canonicalUri,
852
+ appSyncGraphqlEndpoint,
853
+ apiKey,
854
+ region,
855
+ host,
856
+ additionalHeaders,
857
+ });
816
858
 
817
- return result;
859
+ return result;
860
+ }
818
861
  }
819
862
 
820
- private async _awsRealTimeCUPHeader({ host }) {
863
+ private async _awsRealTimeCUPHeader({ host }: AWSAppSyncRealTimeAuthInput) {
821
864
  const session = await Auth.currentSession();
822
865
  return {
823
866
  Authorization: session.getAccessToken().getJwtToken(),
@@ -825,7 +868,9 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
825
868
  };
826
869
  }
827
870
 
828
- private async _awsRealTimeOPENIDHeader({ host }) {
871
+ private async _awsRealTimeOPENIDHeader({
872
+ host,
873
+ }: AWSAppSyncRealTimeAuthInput) {
829
874
  let token;
830
875
  // backwards compatibility
831
876
  const federatedInfo = await Cache.getItem('federatedInfo');
@@ -846,7 +891,10 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
846
891
  };
847
892
  }
848
893
 
849
- private async _awsRealTimeApiKeyHeader({ apiKey, host }) {
894
+ private async _awsRealTimeApiKeyHeader({
895
+ apiKey,
896
+ host,
897
+ }: AWSAppSyncRealTimeAuthInput) {
850
898
  const dt = new Date();
851
899
  const dtStr = dt.toISOString().replace(/[:\-]|\.\d{3}/g, '');
852
900
 
@@ -862,7 +910,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
862
910
  canonicalUri,
863
911
  appSyncGraphqlEndpoint,
864
912
  region,
865
- }) {
913
+ }: AWSAppSyncRealTimeAuthInput) {
866
914
  const endpointInfo = {
867
915
  region,
868
916
  service: 'appsync',
@@ -872,11 +920,16 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
872
920
  if (!credentialsOK) {
873
921
  throw new Error('No credentials');
874
922
  }
875
- const creds = await Credentials.get().then(credentials => ({
876
- secret_key: credentials.secretAccessKey,
877
- access_key: credentials.accessKeyId,
878
- session_token: credentials.sessionToken,
879
- }));
923
+ const creds = await Credentials.get().then((credentials: any) => {
924
+ const { secretAccessKey, accessKeyId, sessionToken } =
925
+ credentials as ICredentials;
926
+
927
+ return {
928
+ secret_key: secretAccessKey,
929
+ access_key: accessKeyId,
930
+ session_token: sessionToken,
931
+ };
932
+ });
880
933
 
881
934
  const request = {
882
935
  url: `${appSyncGraphqlEndpoint}${canonicalUri}`,
@@ -889,8 +942,11 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
889
942
  return signed_params.headers;
890
943
  }
891
944
 
892
- private _customAuthHeader({ host, additionalHeaders }) {
893
- if (!additionalHeaders.Authorization) {
945
+ private _customAuthHeader({
946
+ host,
947
+ additionalHeaders,
948
+ }: AWSAppSyncRealTimeAuthInput) {
949
+ if (!additionalHeaders || !additionalHeaders['Authorization']) {
894
950
  throw new Error('No auth token specified');
895
951
  }
896
952
 
@@ -905,14 +961,14 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
905
961
  */
906
962
  _ensureCredentials() {
907
963
  return Credentials.get()
908
- .then(credentials => {
964
+ .then((credentials: any) => {
909
965
  if (!credentials) return false;
910
966
  const cred = Credentials.shear(credentials);
911
967
  logger.debug('set credentials for AWSAppSyncRealTimeProvider', cred);
912
968
 
913
969
  return true;
914
970
  })
915
- .catch(err => {
971
+ .catch((err: any) => {
916
972
  logger.warn('ensure credentials error', err);
917
973
  return false;
918
974
  });