@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.
- package/CHANGELOG.md +24 -49
- package/dist/aws-amplify-pubsub.js +238 -202
- 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/AWSAppSyncProvider.d.ts +3 -0
- package/lib/Providers/AWSAppSyncProvider.js +3 -0
- package/lib/Providers/AWSAppSyncProvider.js.map +1 -1
- package/lib/Providers/AWSAppSyncRealTimeProvider.d.ts +19 -4
- package/lib/Providers/AWSAppSyncRealTimeProvider.js +174 -154
- package/lib/Providers/AWSAppSyncRealTimeProvider.js.map +1 -1
- package/lib/Providers/AWSIotProvider.d.ts +6 -1
- package/lib/Providers/AWSIotProvider.js +3 -2
- package/lib/Providers/AWSIotProvider.js.map +1 -1
- package/lib/Providers/MqttOverWSProvider.d.ts +14 -11
- package/lib/Providers/MqttOverWSProvider.js +17 -10
- package/lib/Providers/MqttOverWSProvider.js.map +1 -1
- package/lib/Providers/PubSubProvider.d.ts +7 -7
- package/lib/Providers/PubSubProvider.js.map +1 -1
- package/lib/PubSub.d.ts +6 -6
- package/lib/PubSub.js +2 -2
- package/lib/PubSub.js.map +1 -1
- package/lib/types/Provider.d.ts +3 -3
- package/lib/types/PubSub.d.ts +5 -1
- package/lib-esm/Providers/AWSAppSyncProvider.d.ts +3 -0
- package/lib-esm/Providers/AWSAppSyncProvider.js +3 -0
- package/lib-esm/Providers/AWSAppSyncProvider.js.map +1 -1
- package/lib-esm/Providers/AWSAppSyncRealTimeProvider.d.ts +19 -4
- package/lib-esm/Providers/AWSAppSyncRealTimeProvider.js +174 -154
- package/lib-esm/Providers/AWSAppSyncRealTimeProvider.js.map +1 -1
- package/lib-esm/Providers/AWSIotProvider.d.ts +6 -1
- package/lib-esm/Providers/AWSIotProvider.js +3 -2
- package/lib-esm/Providers/AWSIotProvider.js.map +1 -1
- package/lib-esm/Providers/MqttOverWSProvider.d.ts +14 -11
- package/lib-esm/Providers/MqttOverWSProvider.js +17 -10
- package/lib-esm/Providers/MqttOverWSProvider.js.map +1 -1
- package/lib-esm/Providers/PubSubProvider.d.ts +7 -7
- package/lib-esm/Providers/PubSubProvider.js.map +1 -1
- package/lib-esm/PubSub.d.ts +6 -6
- package/lib-esm/PubSub.js +2 -2
- package/lib-esm/PubSub.js.map +1 -1
- package/lib-esm/types/Provider.d.ts +3 -3
- package/lib-esm/types/PubSub.d.ts +5 -1
- package/package.json +5 -5
- package/src/Providers/AWSAppSyncProvider.ts +27 -26
- package/src/Providers/AWSAppSyncRealTimeProvider.ts +247 -191
- package/src/Providers/AWSIotProvider.ts +10 -1
- package/src/Providers/MqttOverWSProvider.ts +52 -33
- package/src/Providers/PubSubProvider.ts +8 -8
- package/src/PubSub.ts +10 -10
- package/src/types/Provider.ts +3 -7
- 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 {
|
|
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
|
|
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?:
|
|
198
|
+
options?: AWSAppSyncRealTimeProviderOptions
|
|
179
199
|
): Observable<any> {
|
|
180
|
-
const
|
|
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:
|
|
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
|
|
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
|
-
|
|
351
|
-
|
|
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
|
|
388
|
+
private async _waitForSubscriptionToBeConnected(subscriptionId: string) {
|
|
389
|
+
const subscriptionObserver =
|
|
366
390
|
this.subscriptionObserverMap.get(subscriptionId);
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
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 =
|
|
431
|
-
tempSocket.onerror =
|
|
457
|
+
tempSocket.onclose = null;
|
|
458
|
+
tempSocket.onerror = null;
|
|
432
459
|
tempSocket.close(1000);
|
|
433
|
-
this.awsRealTimeSocket =
|
|
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
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
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
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
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
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
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
|
-
|
|
535
|
-
|
|
536
|
-
|
|
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
|
|
560
|
-
this.subscriptionObserverMap.get(subscriptionId)
|
|
561
|
-
if (
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
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
|
-
|
|
585
|
-
observer.
|
|
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(
|
|
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 =
|
|
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(
|
|
703
|
+
private async _initializeRetryableHandshake(awsRealTimeUrl: string) {
|
|
670
704
|
logger.debug(`Initializaling retryable Handshake`);
|
|
671
705
|
await jitteredExponentialRetry(
|
|
672
706
|
this._initializeHandshake.bind(this),
|
|
673
|
-
[
|
|
707
|
+
[awsRealTimeUrl],
|
|
674
708
|
MAX_DELAY_MS
|
|
675
709
|
);
|
|
676
710
|
}
|
|
677
711
|
|
|
678
|
-
private async _initializeHandshake(
|
|
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
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
847
|
+
const { host } = url.parse(appSyncGraphqlEndpoint ?? '');
|
|
806
848
|
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
849
|
+
const result = await handler({
|
|
850
|
+
payload,
|
|
851
|
+
canonicalUri,
|
|
852
|
+
appSyncGraphqlEndpoint,
|
|
853
|
+
apiKey,
|
|
854
|
+
region,
|
|
855
|
+
host,
|
|
856
|
+
additionalHeaders,
|
|
857
|
+
});
|
|
816
858
|
|
|
817
|
-
|
|
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({
|
|
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({
|
|
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
|
-
|
|
877
|
-
|
|
878
|
-
|
|
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({
|
|
893
|
-
|
|
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
|
});
|