@aws-amplify/pubsub 4.3.1 → 4.3.2-unstable.5
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.
- package/dist/aws-amplify-pubsub.js +227 -198
- package/dist/aws-amplify-pubsub.js.map +1 -1
- package/dist/aws-amplify-pubsub.min.js +2 -2
- package/dist/aws-amplify-pubsub.min.js.map +1 -1
- package/lib/Providers/AWSAppSyncRealTimeProvider.d.ts +2 -2
- package/lib/Providers/AWSAppSyncRealTimeProvider.js +174 -154
- package/lib/Providers/AWSAppSyncRealTimeProvider.js.map +1 -1
- package/lib/Providers/MqttOverWSProvider.d.ts +4 -5
- package/lib/Providers/MqttOverWSProvider.js +17 -10
- package/lib/Providers/MqttOverWSProvider.js.map +1 -1
- package/lib-esm/Providers/AWSAppSyncRealTimeProvider.d.ts +2 -2
- package/lib-esm/Providers/AWSAppSyncRealTimeProvider.js +174 -154
- package/lib-esm/Providers/AWSAppSyncRealTimeProvider.js.map +1 -1
- package/lib-esm/Providers/MqttOverWSProvider.d.ts +4 -5
- package/lib-esm/Providers/MqttOverWSProvider.js +17 -10
- package/lib-esm/Providers/MqttOverWSProvider.js.map +1 -1
- package/package.json +5 -5
- package/src/Providers/AWSAppSyncRealTimeProvider.ts +231 -188
- package/src/Providers/MqttOverWSProvider.ts +37 -16
|
@@ -25,6 +25,7 @@ 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
31
|
import Auth, { GRAPHQL_AUTH_MODE } from '@aws-amplify/auth';
|
|
@@ -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 {
|
|
@@ -161,10 +162,16 @@ export interface AWSAppSyncRealTimeProviderOptions extends ProviderOptions {
|
|
|
161
162
|
additionalHeaders?: { [key: string]: string };
|
|
162
163
|
}
|
|
163
164
|
|
|
165
|
+
type AWSAppSyncRealTimeAuthInput =
|
|
166
|
+
Partial<AWSAppSyncRealTimeProviderOptions> & {
|
|
167
|
+
canonicalUri: string;
|
|
168
|
+
payload: string;
|
|
169
|
+
};
|
|
170
|
+
|
|
164
171
|
export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
165
|
-
private awsRealTimeSocket
|
|
172
|
+
private awsRealTimeSocket?: WebSocket;
|
|
166
173
|
private socketStatus: SOCKET_STATUS = SOCKET_STATUS.CLOSED;
|
|
167
|
-
private keepAliveTimeoutId
|
|
174
|
+
private keepAliveTimeoutId?: ReturnType<typeof setTimeout>;
|
|
168
175
|
private keepAliveTimeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
|
|
169
176
|
private subscriptionObserverMap: Map<string, ObserverQuery> = new Map();
|
|
170
177
|
private promiseArray: Array<{ res: Function; rej: Function }> = [];
|
|
@@ -190,10 +197,10 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
190
197
|
_topics: string[] | string,
|
|
191
198
|
options?: AWSAppSyncRealTimeProviderOptions
|
|
192
199
|
): Observable<any> {
|
|
193
|
-
const
|
|
200
|
+
const appSyncGraphqlEndpoint = options?.appSyncGraphqlEndpoint;
|
|
194
201
|
|
|
195
202
|
return new Observable(observer => {
|
|
196
|
-
if (!appSyncGraphqlEndpoint) {
|
|
203
|
+
if (!options || !appSyncGraphqlEndpoint) {
|
|
197
204
|
observer.error({
|
|
198
205
|
errors: [
|
|
199
206
|
{
|
|
@@ -210,7 +217,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
210
217
|
options,
|
|
211
218
|
observer,
|
|
212
219
|
subscriptionId,
|
|
213
|
-
}).catch(err => {
|
|
220
|
+
}).catch<any>(err => {
|
|
214
221
|
observer.error({
|
|
215
222
|
errors: [
|
|
216
223
|
{
|
|
@@ -256,10 +263,15 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
256
263
|
return !this.options
|
|
257
264
|
.aws_appsync_dangerously_connect_to_http_endpoint_for_testing;
|
|
258
265
|
}
|
|
266
|
+
|
|
259
267
|
private async _startSubscriptionWithAWSAppSyncRealTime({
|
|
260
268
|
options,
|
|
261
269
|
observer,
|
|
262
270
|
subscriptionId,
|
|
271
|
+
}: {
|
|
272
|
+
options: AWSAppSyncRealTimeProviderOptions;
|
|
273
|
+
observer: ZenObservable.SubscriptionObserver<any>;
|
|
274
|
+
subscriptionId: string;
|
|
263
275
|
}) {
|
|
264
276
|
const {
|
|
265
277
|
appSyncGraphqlEndpoint,
|
|
@@ -280,10 +292,10 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
280
292
|
// Having a subscription id map will make it simple to forward messages received
|
|
281
293
|
this.subscriptionObserverMap.set(subscriptionId, {
|
|
282
294
|
observer,
|
|
283
|
-
query,
|
|
284
|
-
variables,
|
|
295
|
+
query: query ?? '',
|
|
296
|
+
variables: variables ?? {},
|
|
285
297
|
subscriptionState,
|
|
286
|
-
startAckTimeoutId:
|
|
298
|
+
startAckTimeoutId: undefined,
|
|
287
299
|
});
|
|
288
300
|
|
|
289
301
|
// Preparing payload for subscription message
|
|
@@ -329,7 +341,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
329
341
|
});
|
|
330
342
|
} catch (err) {
|
|
331
343
|
logger.debug({ err });
|
|
332
|
-
const
|
|
344
|
+
const message = err['message'] ?? '';
|
|
333
345
|
observer.error({
|
|
334
346
|
errors: [
|
|
335
347
|
{
|
|
@@ -338,7 +350,6 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
338
350
|
],
|
|
339
351
|
});
|
|
340
352
|
observer.complete();
|
|
341
|
-
|
|
342
353
|
const { subscriptionFailedCallback } =
|
|
343
354
|
this.subscriptionObserverMap.get(subscriptionId) || {};
|
|
344
355
|
|
|
@@ -354,14 +365,14 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
354
365
|
// Both subscriptionFailedCallback and subscriptionReadyCallback are used to synchronized this.
|
|
355
366
|
|
|
356
367
|
const { subscriptionFailedCallback, subscriptionReadyCallback } =
|
|
357
|
-
this.subscriptionObserverMap.get(subscriptionId);
|
|
368
|
+
this.subscriptionObserverMap.get(subscriptionId) ?? {};
|
|
358
369
|
|
|
359
370
|
// This must be done before sending the message in order to be listening immediately
|
|
360
371
|
this.subscriptionObserverMap.set(subscriptionId, {
|
|
361
372
|
observer,
|
|
362
373
|
subscriptionState,
|
|
363
|
-
|
|
364
|
-
|
|
374
|
+
query: query ?? '',
|
|
375
|
+
variables: variables ?? {},
|
|
365
376
|
subscriptionReadyCallback,
|
|
366
377
|
subscriptionFailedCallback,
|
|
367
378
|
startAckTimeoutId: setTimeout(() => {
|
|
@@ -374,27 +385,30 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
374
385
|
}
|
|
375
386
|
|
|
376
387
|
// Waiting that subscription has been connected before trying to unsubscribe
|
|
377
|
-
private async _waitForSubscriptionToBeConnected(subscriptionId) {
|
|
378
|
-
const
|
|
388
|
+
private async _waitForSubscriptionToBeConnected(subscriptionId: string) {
|
|
389
|
+
const subscriptionObserver =
|
|
379
390
|
this.subscriptionObserverMap.get(subscriptionId);
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
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
|
+
});
|
|
392
406
|
});
|
|
393
|
-
}
|
|
407
|
+
}
|
|
394
408
|
}
|
|
395
409
|
}
|
|
396
410
|
|
|
397
|
-
private _sendUnsubscriptionMessage(subscriptionId) {
|
|
411
|
+
private _sendUnsubscriptionMessage(subscriptionId: string) {
|
|
398
412
|
try {
|
|
399
413
|
if (
|
|
400
414
|
this.awsRealTimeSocket &&
|
|
@@ -415,7 +429,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
415
429
|
}
|
|
416
430
|
}
|
|
417
431
|
|
|
418
|
-
private _removeSubscriptionObserver(subscriptionId) {
|
|
432
|
+
private _removeSubscriptionObserver(subscriptionId: string) {
|
|
419
433
|
this.subscriptionObserverMap.delete(subscriptionId);
|
|
420
434
|
|
|
421
435
|
// Verifying 1000ms after removing subscription in case there are new subscription unmount/mount
|
|
@@ -437,13 +451,13 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
437
451
|
setTimeout(this._closeSocketIfRequired.bind(this), 1000);
|
|
438
452
|
} else {
|
|
439
453
|
logger.debug('closing WebSocket...');
|
|
440
|
-
clearTimeout(this.keepAliveTimeoutId);
|
|
454
|
+
if (this.keepAliveTimeoutId) clearTimeout(this.keepAliveTimeoutId);
|
|
441
455
|
const tempSocket = this.awsRealTimeSocket;
|
|
442
456
|
// Cleaning callbacks to avoid race condition, socket still exists
|
|
443
|
-
tempSocket.onclose =
|
|
444
|
-
tempSocket.onerror =
|
|
457
|
+
tempSocket.onclose = null;
|
|
458
|
+
tempSocket.onerror = null;
|
|
445
459
|
tempSocket.close(1000);
|
|
446
|
-
this.awsRealTimeSocket =
|
|
460
|
+
this.awsRealTimeSocket = undefined;
|
|
447
461
|
this.socketStatus = SOCKET_STATUS.CLOSED;
|
|
448
462
|
}
|
|
449
463
|
}
|
|
@@ -480,29 +494,31 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
480
494
|
if (typeof subscriptionReadyCallback === 'function') {
|
|
481
495
|
subscriptionReadyCallback();
|
|
482
496
|
}
|
|
483
|
-
clearTimeout(startAckTimeoutId);
|
|
497
|
+
if (startAckTimeoutId) clearTimeout(startAckTimeoutId);
|
|
484
498
|
dispatchApiEvent(
|
|
485
499
|
CONTROL_MSG.SUBSCRIPTION_ACK,
|
|
486
500
|
{ query, variables },
|
|
487
501
|
'Connection established for subscription'
|
|
488
502
|
);
|
|
489
503
|
const subscriptionState = SUBSCRIPTION_STATUS.CONNECTED;
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
504
|
+
if (observer) {
|
|
505
|
+
this.subscriptionObserverMap.set(id, {
|
|
506
|
+
observer,
|
|
507
|
+
query,
|
|
508
|
+
variables,
|
|
509
|
+
startAckTimeoutId: undefined,
|
|
510
|
+
subscriptionState,
|
|
511
|
+
subscriptionReadyCallback,
|
|
512
|
+
subscriptionFailedCallback,
|
|
513
|
+
});
|
|
514
|
+
}
|
|
499
515
|
|
|
500
516
|
// TODO: emit event on hub but it requires to store the id first
|
|
501
517
|
return;
|
|
502
518
|
}
|
|
503
519
|
|
|
504
520
|
if (type === MESSAGE_TYPES.GQL_CONNECTION_KEEP_ALIVE) {
|
|
505
|
-
clearTimeout(this.keepAliveTimeoutId);
|
|
521
|
+
if (this.keepAliveTimeoutId) clearTimeout(this.keepAliveTimeoutId);
|
|
506
522
|
this.keepAliveTimeoutId = setTimeout(
|
|
507
523
|
this._errorDisconnect.bind(this, CONTROL_MSG.TIMEOUT_DISCONNECT),
|
|
508
524
|
this.keepAliveTimeout
|
|
@@ -512,30 +528,32 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
512
528
|
|
|
513
529
|
if (type === MESSAGE_TYPES.GQL_ERROR) {
|
|
514
530
|
const subscriptionState = SUBSCRIPTION_STATUS.FAILED;
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
531
|
+
if (observer) {
|
|
532
|
+
this.subscriptionObserverMap.set(id, {
|
|
533
|
+
observer,
|
|
534
|
+
query,
|
|
535
|
+
variables,
|
|
536
|
+
startAckTimeoutId,
|
|
537
|
+
subscriptionReadyCallback,
|
|
538
|
+
subscriptionFailedCallback,
|
|
539
|
+
subscriptionState,
|
|
540
|
+
});
|
|
524
541
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
542
|
+
observer.error({
|
|
543
|
+
errors: [
|
|
544
|
+
{
|
|
545
|
+
...new GraphQLError(
|
|
546
|
+
`${CONTROL_MSG.CONNECTION_FAILED}: ${JSON.stringify(payload)}`
|
|
547
|
+
),
|
|
548
|
+
},
|
|
549
|
+
],
|
|
550
|
+
});
|
|
551
|
+
if (startAckTimeoutId) clearTimeout(startAckTimeoutId);
|
|
535
552
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
553
|
+
observer.complete();
|
|
554
|
+
if (typeof subscriptionFailedCallback === 'function') {
|
|
555
|
+
subscriptionFailedCallback();
|
|
556
|
+
}
|
|
539
557
|
}
|
|
540
558
|
}
|
|
541
559
|
}
|
|
@@ -557,39 +575,42 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
557
575
|
this.socketStatus = SOCKET_STATUS.CLOSED;
|
|
558
576
|
}
|
|
559
577
|
|
|
560
|
-
private _timeoutStartSubscriptionAck(subscriptionId) {
|
|
561
|
-
const
|
|
562
|
-
this.subscriptionObserverMap.get(subscriptionId)
|
|
563
|
-
if (
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
if (observer && !observer.closed) {
|
|
574
|
-
observer.error({
|
|
575
|
-
errors: [
|
|
576
|
-
{
|
|
577
|
-
...new GraphQLError(
|
|
578
|
-
`Subscription timeout ${JSON.stringify({
|
|
579
|
-
query,
|
|
580
|
-
variables,
|
|
581
|
-
})}`
|
|
582
|
-
),
|
|
583
|
-
},
|
|
584
|
-
],
|
|
578
|
+
private _timeoutStartSubscriptionAck(subscriptionId: string) {
|
|
579
|
+
const subscriptionObserver =
|
|
580
|
+
this.subscriptionObserverMap.get(subscriptionId);
|
|
581
|
+
if (subscriptionObserver) {
|
|
582
|
+
const { observer, query, variables } = subscriptionObserver;
|
|
583
|
+
if (!observer) {
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
this.subscriptionObserverMap.set(subscriptionId, {
|
|
587
|
+
observer,
|
|
588
|
+
query,
|
|
589
|
+
variables,
|
|
590
|
+
subscriptionState: SUBSCRIPTION_STATUS.FAILED,
|
|
585
591
|
});
|
|
586
|
-
|
|
587
|
-
observer.
|
|
592
|
+
|
|
593
|
+
if (observer && !observer.closed) {
|
|
594
|
+
observer.error({
|
|
595
|
+
errors: [
|
|
596
|
+
{
|
|
597
|
+
...new GraphQLError(
|
|
598
|
+
`Subscription timeout ${JSON.stringify({
|
|
599
|
+
query,
|
|
600
|
+
variables,
|
|
601
|
+
})}`
|
|
602
|
+
),
|
|
603
|
+
},
|
|
604
|
+
],
|
|
605
|
+
});
|
|
606
|
+
// Cleanup will be automatically executed
|
|
607
|
+
observer.complete();
|
|
608
|
+
}
|
|
609
|
+
logger.debug(
|
|
610
|
+
'timeoutStartSubscription',
|
|
611
|
+
JSON.stringify({ query, variables })
|
|
612
|
+
);
|
|
588
613
|
}
|
|
589
|
-
logger.debug(
|
|
590
|
-
'timeoutStartSubscription',
|
|
591
|
-
JSON.stringify({ query, variables })
|
|
592
|
-
);
|
|
593
614
|
}
|
|
594
615
|
|
|
595
616
|
private _initializeWebSocketConnection({
|
|
@@ -598,7 +619,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
598
619
|
apiKey,
|
|
599
620
|
region,
|
|
600
621
|
additionalHeaders,
|
|
601
|
-
}) {
|
|
622
|
+
}: AWSAppSyncRealTimeProviderOptions) {
|
|
602
623
|
if (this.socketStatus === SOCKET_STATUS.READY) {
|
|
603
624
|
return;
|
|
604
625
|
}
|
|
@@ -625,7 +646,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
625
646
|
|
|
626
647
|
const payloadQs = Buffer.from(payloadString).toString('base64');
|
|
627
648
|
|
|
628
|
-
let discoverableEndpoint = appSyncGraphqlEndpoint;
|
|
649
|
+
let discoverableEndpoint = appSyncGraphqlEndpoint ?? '';
|
|
629
650
|
|
|
630
651
|
if (this.isCustomDomain(discoverableEndpoint)) {
|
|
631
652
|
discoverableEndpoint =
|
|
@@ -644,7 +665,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
644
665
|
|
|
645
666
|
const awsRealTimeUrl = `${discoverableEndpoint}?header=${headerQs}&payload=${payloadQs}`;
|
|
646
667
|
|
|
647
|
-
await this._initializeRetryableHandshake(
|
|
668
|
+
await this._initializeRetryableHandshake(awsRealTimeUrl);
|
|
648
669
|
|
|
649
670
|
this.promiseArray.forEach(({ res }) => {
|
|
650
671
|
logger.debug('Notifying connection successful');
|
|
@@ -661,23 +682,23 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
661
682
|
) {
|
|
662
683
|
this.awsRealTimeSocket.close(3001);
|
|
663
684
|
}
|
|
664
|
-
this.awsRealTimeSocket =
|
|
685
|
+
this.awsRealTimeSocket = undefined;
|
|
665
686
|
this.socketStatus = SOCKET_STATUS.CLOSED;
|
|
666
687
|
}
|
|
667
688
|
}
|
|
668
689
|
});
|
|
669
690
|
}
|
|
670
691
|
|
|
671
|
-
private async _initializeRetryableHandshake(
|
|
692
|
+
private async _initializeRetryableHandshake(awsRealTimeUrl: string) {
|
|
672
693
|
logger.debug(`Initializaling retryable Handshake`);
|
|
673
694
|
await jitteredExponentialRetry(
|
|
674
695
|
this._initializeHandshake.bind(this),
|
|
675
|
-
[
|
|
696
|
+
[awsRealTimeUrl],
|
|
676
697
|
MAX_DELAY_MS
|
|
677
698
|
);
|
|
678
699
|
}
|
|
679
700
|
|
|
680
|
-
private async _initializeHandshake(
|
|
701
|
+
private async _initializeHandshake(awsRealTimeUrl: string) {
|
|
681
702
|
logger.debug(`Initializing handshake ${awsRealTimeUrl}`);
|
|
682
703
|
// Because connecting the socket is async, is waiting until connection is open
|
|
683
704
|
// Step 1: connect websocket
|
|
@@ -701,60 +722,66 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
701
722
|
// Step 2: wait for ack from AWS AppSyncReaTime after sending init
|
|
702
723
|
await (() => {
|
|
703
724
|
return new Promise((res, rej) => {
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
type,
|
|
720
|
-
payload: {
|
|
721
|
-
connectionTimeoutMs = DEFAULT_KEEP_ALIVE_TIMEOUT,
|
|
722
|
-
} = {},
|
|
723
|
-
} = data;
|
|
724
|
-
if (type === MESSAGE_TYPES.GQL_CONNECTION_ACK) {
|
|
725
|
-
ackOk = true;
|
|
726
|
-
this.keepAliveTimeout = connectionTimeoutMs;
|
|
727
|
-
this.awsRealTimeSocket.onmessage =
|
|
728
|
-
this._handleIncomingSubscriptionMessage.bind(this);
|
|
729
|
-
this.awsRealTimeSocket.onerror = err => {
|
|
730
|
-
logger.debug(err);
|
|
731
|
-
this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
|
|
732
|
-
};
|
|
733
|
-
this.awsRealTimeSocket.onclose = event => {
|
|
734
|
-
logger.debug(`WebSocket closed ${event.reason}`);
|
|
735
|
-
this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
|
|
736
|
-
};
|
|
737
|
-
res('Cool, connected to AWS AppSyncRealTime');
|
|
738
|
-
return;
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
if (type === MESSAGE_TYPES.GQL_CONNECTION_ERROR) {
|
|
725
|
+
if (this.awsRealTimeSocket) {
|
|
726
|
+
let ackOk = false;
|
|
727
|
+
this.awsRealTimeSocket.onerror = error => {
|
|
728
|
+
logger.debug(`WebSocket error ${JSON.stringify(error)}`);
|
|
729
|
+
};
|
|
730
|
+
this.awsRealTimeSocket.onclose = event => {
|
|
731
|
+
logger.debug(`WebSocket closed ${event.reason}`);
|
|
732
|
+
rej(new Error(JSON.stringify(event)));
|
|
733
|
+
};
|
|
734
|
+
|
|
735
|
+
this.awsRealTimeSocket.onmessage = (message: MessageEvent) => {
|
|
736
|
+
logger.debug(
|
|
737
|
+
`subscription message from AWS AppSyncRealTime: ${message.data} `
|
|
738
|
+
);
|
|
739
|
+
const data = JSON.parse(message.data);
|
|
742
740
|
const {
|
|
741
|
+
type,
|
|
743
742
|
payload: {
|
|
744
|
-
|
|
743
|
+
connectionTimeoutMs = DEFAULT_KEEP_ALIVE_TIMEOUT,
|
|
745
744
|
} = {},
|
|
746
745
|
} = data;
|
|
746
|
+
if (type === MESSAGE_TYPES.GQL_CONNECTION_ACK) {
|
|
747
|
+
ackOk = true;
|
|
748
|
+
if (this.awsRealTimeSocket) {
|
|
749
|
+
this.keepAliveTimeout = connectionTimeoutMs;
|
|
750
|
+
this.awsRealTimeSocket.onmessage =
|
|
751
|
+
this._handleIncomingSubscriptionMessage.bind(this);
|
|
752
|
+
this.awsRealTimeSocket.onerror = err => {
|
|
753
|
+
logger.debug(err);
|
|
754
|
+
this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
|
|
755
|
+
};
|
|
756
|
+
this.awsRealTimeSocket.onclose = event => {
|
|
757
|
+
logger.debug(`WebSocket closed ${event.reason}`);
|
|
758
|
+
this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
res('Cool, connected to AWS AppSyncRealTime');
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
if (type === MESSAGE_TYPES.GQL_CONNECTION_ERROR) {
|
|
766
|
+
const {
|
|
767
|
+
payload: {
|
|
768
|
+
errors: [{ errorType = '', errorCode = 0 } = {}] = [],
|
|
769
|
+
} = {},
|
|
770
|
+
} = data;
|
|
771
|
+
|
|
772
|
+
rej({ errorType, errorCode });
|
|
773
|
+
}
|
|
774
|
+
};
|
|
775
|
+
|
|
776
|
+
const gqlInit = {
|
|
777
|
+
type: MESSAGE_TYPES.GQL_CONNECTION_INIT,
|
|
778
|
+
};
|
|
779
|
+
this.awsRealTimeSocket.send(JSON.stringify(gqlInit));
|
|
780
|
+
|
|
781
|
+
setTimeout(checkAckOk.bind(this, ackOk), CONNECTION_INIT_TIMEOUT);
|
|
782
|
+
}
|
|
747
783
|
|
|
748
|
-
|
|
749
|
-
}
|
|
750
|
-
};
|
|
751
|
-
|
|
752
|
-
const gqlInit = {
|
|
753
|
-
type: MESSAGE_TYPES.GQL_CONNECTION_INIT,
|
|
754
|
-
};
|
|
755
|
-
this.awsRealTimeSocket.send(JSON.stringify(gqlInit));
|
|
756
|
-
|
|
757
|
-
function checkAckOk() {
|
|
784
|
+
function checkAckOk(ackOk: boolean) {
|
|
758
785
|
if (!ackOk) {
|
|
759
786
|
rej(
|
|
760
787
|
new Error(
|
|
@@ -763,12 +790,13 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
763
790
|
);
|
|
764
791
|
}
|
|
765
792
|
}
|
|
766
|
-
|
|
767
|
-
setTimeout(checkAckOk.bind(this), CONNECTION_INIT_TIMEOUT);
|
|
768
793
|
});
|
|
769
794
|
})();
|
|
770
795
|
} catch (err) {
|
|
771
|
-
const { errorType, errorCode } = err
|
|
796
|
+
const { errorType, errorCode } = err as {
|
|
797
|
+
errorType: string;
|
|
798
|
+
errorCode: number;
|
|
799
|
+
};
|
|
772
800
|
|
|
773
801
|
if (NON_RETRYABLE_CODES.includes(errorCode)) {
|
|
774
802
|
throw new NonRetryableError(errorType);
|
|
@@ -788,8 +816,10 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
788
816
|
apiKey,
|
|
789
817
|
region,
|
|
790
818
|
additionalHeaders,
|
|
791
|
-
}): Promise<any> {
|
|
792
|
-
const headerHandler
|
|
819
|
+
}: AWSAppSyncRealTimeProviderOptions): Promise<any> {
|
|
820
|
+
const headerHandler: {
|
|
821
|
+
[key in GraphqlAuthModes]: (AWSAppSyncRealTimeAuthInput) => {};
|
|
822
|
+
} = {
|
|
793
823
|
API_KEY: this._awsRealTimeApiKeyHeader.bind(this),
|
|
794
824
|
AWS_IAM: this._awsRealTimeIAMHeader.bind(this),
|
|
795
825
|
OPENID_CONNECT: this._awsRealTimeOPENIDHeader.bind(this),
|
|
@@ -797,29 +827,29 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
797
827
|
AWS_LAMBDA: this._customAuthHeader,
|
|
798
828
|
};
|
|
799
829
|
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
if (typeof handler !== 'function') {
|
|
830
|
+
if (!authenticationType || !headerHandler[authenticationType]) {
|
|
803
831
|
logger.debug(`Authentication type ${authenticationType} not supported`);
|
|
804
832
|
return '';
|
|
805
|
-
}
|
|
833
|
+
} else {
|
|
834
|
+
const handler = headerHandler[authenticationType];
|
|
806
835
|
|
|
807
|
-
|
|
836
|
+
const { host } = url.parse(appSyncGraphqlEndpoint ?? '');
|
|
808
837
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
838
|
+
const result = await handler({
|
|
839
|
+
payload,
|
|
840
|
+
canonicalUri,
|
|
841
|
+
appSyncGraphqlEndpoint,
|
|
842
|
+
apiKey,
|
|
843
|
+
region,
|
|
844
|
+
host,
|
|
845
|
+
additionalHeaders,
|
|
846
|
+
});
|
|
818
847
|
|
|
819
|
-
|
|
848
|
+
return result;
|
|
849
|
+
}
|
|
820
850
|
}
|
|
821
851
|
|
|
822
|
-
private async _awsRealTimeCUPHeader({ host }) {
|
|
852
|
+
private async _awsRealTimeCUPHeader({ host }: AWSAppSyncRealTimeAuthInput) {
|
|
823
853
|
const session = await Auth.currentSession();
|
|
824
854
|
return {
|
|
825
855
|
Authorization: session.getAccessToken().getJwtToken(),
|
|
@@ -827,7 +857,9 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
827
857
|
};
|
|
828
858
|
}
|
|
829
859
|
|
|
830
|
-
private async _awsRealTimeOPENIDHeader({
|
|
860
|
+
private async _awsRealTimeOPENIDHeader({
|
|
861
|
+
host,
|
|
862
|
+
}: AWSAppSyncRealTimeAuthInput) {
|
|
831
863
|
let token;
|
|
832
864
|
// backwards compatibility
|
|
833
865
|
const federatedInfo = await Cache.getItem('federatedInfo');
|
|
@@ -848,7 +880,10 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
848
880
|
};
|
|
849
881
|
}
|
|
850
882
|
|
|
851
|
-
private async _awsRealTimeApiKeyHeader({
|
|
883
|
+
private async _awsRealTimeApiKeyHeader({
|
|
884
|
+
apiKey,
|
|
885
|
+
host,
|
|
886
|
+
}: AWSAppSyncRealTimeAuthInput) {
|
|
852
887
|
const dt = new Date();
|
|
853
888
|
const dtStr = dt.toISOString().replace(/[:\-]|\.\d{3}/g, '');
|
|
854
889
|
|
|
@@ -864,7 +899,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
864
899
|
canonicalUri,
|
|
865
900
|
appSyncGraphqlEndpoint,
|
|
866
901
|
region,
|
|
867
|
-
}) {
|
|
902
|
+
}: AWSAppSyncRealTimeAuthInput) {
|
|
868
903
|
const endpointInfo = {
|
|
869
904
|
region,
|
|
870
905
|
service: 'appsync',
|
|
@@ -874,11 +909,16 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
874
909
|
if (!credentialsOK) {
|
|
875
910
|
throw new Error('No credentials');
|
|
876
911
|
}
|
|
877
|
-
const creds = await Credentials.get().then(credentials =>
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
912
|
+
const creds = await Credentials.get().then((credentials: any) => {
|
|
913
|
+
const { secretAccessKey, accessKeyId, sessionToken } =
|
|
914
|
+
credentials as ICredentials;
|
|
915
|
+
|
|
916
|
+
return {
|
|
917
|
+
secret_key: secretAccessKey,
|
|
918
|
+
access_key: accessKeyId,
|
|
919
|
+
session_token: sessionToken,
|
|
920
|
+
};
|
|
921
|
+
});
|
|
882
922
|
|
|
883
923
|
const request = {
|
|
884
924
|
url: `${appSyncGraphqlEndpoint}${canonicalUri}`,
|
|
@@ -891,8 +931,11 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
891
931
|
return signed_params.headers;
|
|
892
932
|
}
|
|
893
933
|
|
|
894
|
-
private _customAuthHeader({
|
|
895
|
-
|
|
934
|
+
private _customAuthHeader({
|
|
935
|
+
host,
|
|
936
|
+
additionalHeaders,
|
|
937
|
+
}: AWSAppSyncRealTimeAuthInput) {
|
|
938
|
+
if (!additionalHeaders || !additionalHeaders['Authorization']) {
|
|
896
939
|
throw new Error('No auth token specified');
|
|
897
940
|
}
|
|
898
941
|
|
|
@@ -907,14 +950,14 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
907
950
|
*/
|
|
908
951
|
_ensureCredentials() {
|
|
909
952
|
return Credentials.get()
|
|
910
|
-
.then(credentials => {
|
|
953
|
+
.then((credentials: any) => {
|
|
911
954
|
if (!credentials) return false;
|
|
912
955
|
const cred = Credentials.shear(credentials);
|
|
913
956
|
logger.debug('set credentials for AWSAppSyncRealTimeProvider', cred);
|
|
914
957
|
|
|
915
958
|
return true;
|
|
916
959
|
})
|
|
917
|
-
.catch(err => {
|
|
960
|
+
.catch((err: any) => {
|
|
918
961
|
logger.warn('ensure credentials error', err);
|
|
919
962
|
return false;
|
|
920
963
|
});
|