@aws-amplify/pubsub 4.2.9-unstable.9 → 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 +27 -44
- package/dist/aws-amplify-pubsub.js +258 -209
- 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 +192 -159
- 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 +192 -159
- 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 +276 -214
- 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,18 +25,20 @@ 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
|
|
|
34
35
|
const logger = new Logger('AWSAppSyncRealTimeProvider');
|
|
35
36
|
|
|
36
|
-
const AMPLIFY_SYMBOL = (
|
|
37
|
-
typeof Symbol.for === 'function'
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
const AMPLIFY_SYMBOL = (
|
|
38
|
+
typeof Symbol !== 'undefined' && typeof Symbol.for === 'function'
|
|
39
|
+
? Symbol.for('amplify_default')
|
|
40
|
+
: '@@amplify_default'
|
|
41
|
+
) as Symbol;
|
|
40
42
|
|
|
41
43
|
const dispatchApiEvent = (event: string, data: any, message: string) => {
|
|
42
44
|
Hub.dispatch('api', { event, data, message }, 'PubSub', AMPLIFY_SYMBOL);
|
|
@@ -53,7 +55,7 @@ type ObserverQuery = {
|
|
|
53
55
|
subscriptionState: SUBSCRIPTION_STATUS;
|
|
54
56
|
subscriptionReadyCallback?: Function;
|
|
55
57
|
subscriptionFailedCallback?: Function;
|
|
56
|
-
startAckTimeoutId
|
|
58
|
+
startAckTimeoutId?: ReturnType<typeof setTimeout>;
|
|
57
59
|
};
|
|
58
60
|
|
|
59
61
|
enum MESSAGE_TYPES {
|
|
@@ -142,14 +144,34 @@ const START_ACK_TIMEOUT = 15000;
|
|
|
142
144
|
*/
|
|
143
145
|
const DEFAULT_KEEP_ALIVE_TIMEOUT = 5 * 60 * 1000;
|
|
144
146
|
|
|
145
|
-
const standardDomainPattern =
|
|
147
|
+
const standardDomainPattern =
|
|
148
|
+
/^https:\/\/\w{26}\.appsync\-api\.\w{2}(?:(?:\-\w{2,})+)\-\d\.amazonaws.com\/graphql$/i;
|
|
146
149
|
|
|
147
150
|
const customDomainPath = '/realtime';
|
|
148
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
|
+
|
|
149
171
|
export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
150
|
-
private awsRealTimeSocket
|
|
172
|
+
private awsRealTimeSocket?: WebSocket;
|
|
151
173
|
private socketStatus: SOCKET_STATUS = SOCKET_STATUS.CLOSED;
|
|
152
|
-
private keepAliveTimeoutId
|
|
174
|
+
private keepAliveTimeoutId?: ReturnType<typeof setTimeout>;
|
|
153
175
|
private keepAliveTimeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
|
|
154
176
|
private subscriptionObserverMap: Map<string, ObserverQuery> = new Map();
|
|
155
177
|
private promiseArray: Array<{ res: Function; rej: Function }> = [];
|
|
@@ -173,12 +195,12 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
173
195
|
|
|
174
196
|
subscribe(
|
|
175
197
|
_topics: string[] | string,
|
|
176
|
-
options?:
|
|
198
|
+
options?: AWSAppSyncRealTimeProviderOptions
|
|
177
199
|
): Observable<any> {
|
|
178
|
-
const
|
|
200
|
+
const appSyncGraphqlEndpoint = options?.appSyncGraphqlEndpoint;
|
|
179
201
|
|
|
180
202
|
return new Observable(observer => {
|
|
181
|
-
if (!appSyncGraphqlEndpoint) {
|
|
203
|
+
if (!options || !appSyncGraphqlEndpoint) {
|
|
182
204
|
observer.error({
|
|
183
205
|
errors: [
|
|
184
206
|
{
|
|
@@ -195,7 +217,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
195
217
|
options,
|
|
196
218
|
observer,
|
|
197
219
|
subscriptionId,
|
|
198
|
-
}).catch(err => {
|
|
220
|
+
}).catch<any>(err => {
|
|
199
221
|
observer.error({
|
|
200
222
|
errors: [
|
|
201
223
|
{
|
|
@@ -241,10 +263,15 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
241
263
|
return !this.options
|
|
242
264
|
.aws_appsync_dangerously_connect_to_http_endpoint_for_testing;
|
|
243
265
|
}
|
|
266
|
+
|
|
244
267
|
private async _startSubscriptionWithAWSAppSyncRealTime({
|
|
245
268
|
options,
|
|
246
269
|
observer,
|
|
247
270
|
subscriptionId,
|
|
271
|
+
}: {
|
|
272
|
+
options: AWSAppSyncRealTimeProviderOptions;
|
|
273
|
+
observer: ZenObservable.SubscriptionObserver<any>;
|
|
274
|
+
subscriptionId: string;
|
|
248
275
|
}) {
|
|
249
276
|
const {
|
|
250
277
|
appSyncGraphqlEndpoint,
|
|
@@ -265,10 +292,10 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
265
292
|
// Having a subscription id map will make it simple to forward messages received
|
|
266
293
|
this.subscriptionObserverMap.set(subscriptionId, {
|
|
267
294
|
observer,
|
|
268
|
-
query,
|
|
269
|
-
variables,
|
|
295
|
+
query: query ?? '',
|
|
296
|
+
variables: variables ?? {},
|
|
270
297
|
subscriptionState,
|
|
271
|
-
startAckTimeoutId:
|
|
298
|
+
startAckTimeoutId: undefined,
|
|
272
299
|
});
|
|
273
300
|
|
|
274
301
|
// Preparing payload for subscription message
|
|
@@ -314,7 +341,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
314
341
|
});
|
|
315
342
|
} catch (err) {
|
|
316
343
|
logger.debug({ err });
|
|
317
|
-
const
|
|
344
|
+
const message = err['message'] ?? '';
|
|
318
345
|
observer.error({
|
|
319
346
|
errors: [
|
|
320
347
|
{
|
|
@@ -323,7 +350,6 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
323
350
|
],
|
|
324
351
|
});
|
|
325
352
|
observer.complete();
|
|
326
|
-
|
|
327
353
|
const { subscriptionFailedCallback } =
|
|
328
354
|
this.subscriptionObserverMap.get(subscriptionId) || {};
|
|
329
355
|
|
|
@@ -338,17 +364,15 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
338
364
|
// E.g.unsubscribe gets invoked prior to finishing WebSocket handshake or START_ACK.
|
|
339
365
|
// Both subscriptionFailedCallback and subscriptionReadyCallback are used to synchronized this.
|
|
340
366
|
|
|
341
|
-
const {
|
|
342
|
-
|
|
343
|
-
subscriptionReadyCallback,
|
|
344
|
-
} = this.subscriptionObserverMap.get(subscriptionId);
|
|
367
|
+
const { subscriptionFailedCallback, subscriptionReadyCallback } =
|
|
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,32 +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
|
|
366
|
-
subscriptionId
|
|
367
|
-
)
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
observer,
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
subscriptionReadyCallback: res,
|
|
383
|
-
subscriptionFailedCallback: rej,
|
|
388
|
+
private async _waitForSubscriptionToBeConnected(subscriptionId: string) {
|
|
389
|
+
const subscriptionObserver =
|
|
390
|
+
this.subscriptionObserverMap.get(subscriptionId);
|
|
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
|
+
});
|
|
384
406
|
});
|
|
385
|
-
}
|
|
407
|
+
}
|
|
386
408
|
}
|
|
387
409
|
}
|
|
388
410
|
|
|
389
|
-
private _sendUnsubscriptionMessage(subscriptionId) {
|
|
411
|
+
private _sendUnsubscriptionMessage(subscriptionId: string) {
|
|
390
412
|
try {
|
|
391
413
|
if (
|
|
392
414
|
this.awsRealTimeSocket &&
|
|
@@ -407,7 +429,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
407
429
|
}
|
|
408
430
|
}
|
|
409
431
|
|
|
410
|
-
private _removeSubscriptionObserver(subscriptionId) {
|
|
432
|
+
private _removeSubscriptionObserver(subscriptionId: string) {
|
|
411
433
|
this.subscriptionObserverMap.delete(subscriptionId);
|
|
412
434
|
|
|
413
435
|
// Verifying 1000ms after removing subscription in case there are new subscription unmount/mount
|
|
@@ -429,21 +451,28 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
429
451
|
setTimeout(this._closeSocketIfRequired.bind(this), 1000);
|
|
430
452
|
} else {
|
|
431
453
|
logger.debug('closing WebSocket...');
|
|
432
|
-
clearTimeout(this.keepAliveTimeoutId);
|
|
454
|
+
if (this.keepAliveTimeoutId) clearTimeout(this.keepAliveTimeoutId);
|
|
433
455
|
const tempSocket = this.awsRealTimeSocket;
|
|
434
456
|
// Cleaning callbacks to avoid race condition, socket still exists
|
|
435
|
-
tempSocket.onclose =
|
|
436
|
-
tempSocket.onerror =
|
|
457
|
+
tempSocket.onclose = null;
|
|
458
|
+
tempSocket.onerror = null;
|
|
437
459
|
tempSocket.close(1000);
|
|
438
|
-
this.awsRealTimeSocket =
|
|
460
|
+
this.awsRealTimeSocket = undefined;
|
|
439
461
|
this.socketStatus = SOCKET_STATUS.CLOSED;
|
|
440
462
|
}
|
|
441
463
|
}
|
|
442
464
|
|
|
443
465
|
private _handleIncomingSubscriptionMessage(message: MessageEvent) {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
466
|
+
if (message.data && message.data === '{"type":"ka"}') {
|
|
467
|
+
logger.verbose(
|
|
468
|
+
`subscription message from AWS AppSync RealTime: ${message.data}`
|
|
469
|
+
);
|
|
470
|
+
} else {
|
|
471
|
+
logger.debug(
|
|
472
|
+
`subscription message from AWS AppSync RealTime: ${message.data}`
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
|
|
447
476
|
const { id = '', payload, type } = JSON.parse(message.data);
|
|
448
477
|
const {
|
|
449
478
|
observer = null,
|
|
@@ -454,7 +483,11 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
454
483
|
subscriptionFailedCallback,
|
|
455
484
|
} = this.subscriptionObserverMap.get(id) || {};
|
|
456
485
|
|
|
457
|
-
|
|
486
|
+
if (!id && !observer && !query && Object.keys(variables).length === 0) {
|
|
487
|
+
logger.verbose({ id, observer, query, variables });
|
|
488
|
+
} else {
|
|
489
|
+
logger.debug({ id, observer, query, variables });
|
|
490
|
+
}
|
|
458
491
|
|
|
459
492
|
if (type === MESSAGE_TYPES.GQL_DATA && payload && payload.data) {
|
|
460
493
|
if (observer) {
|
|
@@ -472,29 +505,31 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
472
505
|
if (typeof subscriptionReadyCallback === 'function') {
|
|
473
506
|
subscriptionReadyCallback();
|
|
474
507
|
}
|
|
475
|
-
clearTimeout(startAckTimeoutId);
|
|
508
|
+
if (startAckTimeoutId) clearTimeout(startAckTimeoutId);
|
|
476
509
|
dispatchApiEvent(
|
|
477
510
|
CONTROL_MSG.SUBSCRIPTION_ACK,
|
|
478
511
|
{ query, variables },
|
|
479
512
|
'Connection established for subscription'
|
|
480
513
|
);
|
|
481
514
|
const subscriptionState = SUBSCRIPTION_STATUS.CONNECTED;
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
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
|
+
}
|
|
491
526
|
|
|
492
527
|
// TODO: emit event on hub but it requires to store the id first
|
|
493
528
|
return;
|
|
494
529
|
}
|
|
495
530
|
|
|
496
531
|
if (type === MESSAGE_TYPES.GQL_CONNECTION_KEEP_ALIVE) {
|
|
497
|
-
clearTimeout(this.keepAliveTimeoutId);
|
|
532
|
+
if (this.keepAliveTimeoutId) clearTimeout(this.keepAliveTimeoutId);
|
|
498
533
|
this.keepAliveTimeoutId = setTimeout(
|
|
499
534
|
this._errorDisconnect.bind(this, CONTROL_MSG.TIMEOUT_DISCONNECT),
|
|
500
535
|
this.keepAliveTimeout
|
|
@@ -504,30 +539,32 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
504
539
|
|
|
505
540
|
if (type === MESSAGE_TYPES.GQL_ERROR) {
|
|
506
541
|
const subscriptionState = SUBSCRIPTION_STATUS.FAILED;
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
542
|
+
if (observer) {
|
|
543
|
+
this.subscriptionObserverMap.set(id, {
|
|
544
|
+
observer,
|
|
545
|
+
query,
|
|
546
|
+
variables,
|
|
547
|
+
startAckTimeoutId,
|
|
548
|
+
subscriptionReadyCallback,
|
|
549
|
+
subscriptionFailedCallback,
|
|
550
|
+
subscriptionState,
|
|
551
|
+
});
|
|
516
552
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
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);
|
|
527
563
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
564
|
+
observer.complete();
|
|
565
|
+
if (typeof subscriptionFailedCallback === 'function') {
|
|
566
|
+
subscriptionFailedCallback();
|
|
567
|
+
}
|
|
531
568
|
}
|
|
532
569
|
}
|
|
533
570
|
}
|
|
@@ -549,39 +586,42 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
549
586
|
this.socketStatus = SOCKET_STATUS.CLOSED;
|
|
550
587
|
}
|
|
551
588
|
|
|
552
|
-
private _timeoutStartSubscriptionAck(subscriptionId) {
|
|
553
|
-
const
|
|
554
|
-
this.subscriptionObserverMap.get(subscriptionId)
|
|
555
|
-
if (
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
if (observer && !observer.closed) {
|
|
566
|
-
observer.error({
|
|
567
|
-
errors: [
|
|
568
|
-
{
|
|
569
|
-
...new GraphQLError(
|
|
570
|
-
`Subscription timeout ${JSON.stringify({
|
|
571
|
-
query,
|
|
572
|
-
variables,
|
|
573
|
-
})}`
|
|
574
|
-
),
|
|
575
|
-
},
|
|
576
|
-
],
|
|
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,
|
|
577
602
|
});
|
|
578
|
-
|
|
579
|
-
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
|
+
);
|
|
580
624
|
}
|
|
581
|
-
logger.debug(
|
|
582
|
-
'timeoutStartSubscription',
|
|
583
|
-
JSON.stringify({ query, variables })
|
|
584
|
-
);
|
|
585
625
|
}
|
|
586
626
|
|
|
587
627
|
private _initializeWebSocketConnection({
|
|
@@ -590,7 +630,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
590
630
|
apiKey,
|
|
591
631
|
region,
|
|
592
632
|
additionalHeaders,
|
|
593
|
-
}) {
|
|
633
|
+
}: AWSAppSyncRealTimeProviderOptions) {
|
|
594
634
|
if (this.socketStatus === SOCKET_STATUS.READY) {
|
|
595
635
|
return;
|
|
596
636
|
}
|
|
@@ -617,17 +657,18 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
617
657
|
|
|
618
658
|
const payloadQs = Buffer.from(payloadString).toString('base64');
|
|
619
659
|
|
|
620
|
-
let discoverableEndpoint = appSyncGraphqlEndpoint;
|
|
660
|
+
let discoverableEndpoint = appSyncGraphqlEndpoint ?? '';
|
|
621
661
|
|
|
622
662
|
if (this.isCustomDomain(discoverableEndpoint)) {
|
|
623
|
-
discoverableEndpoint =
|
|
624
|
-
customDomainPath
|
|
625
|
-
);
|
|
663
|
+
discoverableEndpoint =
|
|
664
|
+
discoverableEndpoint.concat(customDomainPath);
|
|
626
665
|
} else {
|
|
627
|
-
discoverableEndpoint = discoverableEndpoint
|
|
666
|
+
discoverableEndpoint = discoverableEndpoint
|
|
667
|
+
.replace('appsync-api', 'appsync-realtime-api')
|
|
668
|
+
.replace('gogi-beta', 'grt-beta');
|
|
628
669
|
}
|
|
629
670
|
|
|
630
|
-
|
|
671
|
+
// Creating websocket url with required query strings
|
|
631
672
|
const protocol = this.isSSLEnabled ? 'wss://' : 'ws://';
|
|
632
673
|
discoverableEndpoint = discoverableEndpoint
|
|
633
674
|
.replace('https://', protocol)
|
|
@@ -635,7 +676,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
635
676
|
|
|
636
677
|
const awsRealTimeUrl = `${discoverableEndpoint}?header=${headerQs}&payload=${payloadQs}`;
|
|
637
678
|
|
|
638
|
-
await this._initializeRetryableHandshake(
|
|
679
|
+
await this._initializeRetryableHandshake(awsRealTimeUrl);
|
|
639
680
|
|
|
640
681
|
this.promiseArray.forEach(({ res }) => {
|
|
641
682
|
logger.debug('Notifying connection successful');
|
|
@@ -652,23 +693,23 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
652
693
|
) {
|
|
653
694
|
this.awsRealTimeSocket.close(3001);
|
|
654
695
|
}
|
|
655
|
-
this.awsRealTimeSocket =
|
|
696
|
+
this.awsRealTimeSocket = undefined;
|
|
656
697
|
this.socketStatus = SOCKET_STATUS.CLOSED;
|
|
657
698
|
}
|
|
658
699
|
}
|
|
659
700
|
});
|
|
660
701
|
}
|
|
661
702
|
|
|
662
|
-
private async _initializeRetryableHandshake(
|
|
703
|
+
private async _initializeRetryableHandshake(awsRealTimeUrl: string) {
|
|
663
704
|
logger.debug(`Initializaling retryable Handshake`);
|
|
664
705
|
await jitteredExponentialRetry(
|
|
665
706
|
this._initializeHandshake.bind(this),
|
|
666
|
-
[
|
|
707
|
+
[awsRealTimeUrl],
|
|
667
708
|
MAX_DELAY_MS
|
|
668
709
|
);
|
|
669
710
|
}
|
|
670
711
|
|
|
671
|
-
private async _initializeHandshake(
|
|
712
|
+
private async _initializeHandshake(awsRealTimeUrl: string) {
|
|
672
713
|
logger.debug(`Initializing handshake ${awsRealTimeUrl}`);
|
|
673
714
|
// Because connecting the socket is async, is waiting until connection is open
|
|
674
715
|
// Step 1: connect websocket
|
|
@@ -692,61 +733,66 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
692
733
|
// Step 2: wait for ack from AWS AppSyncReaTime after sending init
|
|
693
734
|
await (() => {
|
|
694
735
|
return new Promise((res, rej) => {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
const data = JSON.parse(message.data);
|
|
709
|
-
const {
|
|
710
|
-
type,
|
|
711
|
-
payload: {
|
|
712
|
-
connectionTimeoutMs = DEFAULT_KEEP_ALIVE_TIMEOUT,
|
|
713
|
-
} = {},
|
|
714
|
-
} = data;
|
|
715
|
-
if (type === MESSAGE_TYPES.GQL_CONNECTION_ACK) {
|
|
716
|
-
ackOk = true;
|
|
717
|
-
this.keepAliveTimeout = connectionTimeoutMs;
|
|
718
|
-
this.awsRealTimeSocket.onmessage = this._handleIncomingSubscriptionMessage.bind(
|
|
719
|
-
this
|
|
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} `
|
|
720
749
|
);
|
|
721
|
-
|
|
722
|
-
logger.debug(err);
|
|
723
|
-
this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
|
|
724
|
-
};
|
|
725
|
-
this.awsRealTimeSocket.onclose = event => {
|
|
726
|
-
logger.debug(`WebSocket closed ${event.reason}`);
|
|
727
|
-
this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
|
|
728
|
-
};
|
|
729
|
-
res('Cool, connected to AWS AppSyncRealTime');
|
|
730
|
-
return;
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
if (type === MESSAGE_TYPES.GQL_CONNECTION_ERROR) {
|
|
750
|
+
const data = JSON.parse(message.data);
|
|
734
751
|
const {
|
|
752
|
+
type,
|
|
735
753
|
payload: {
|
|
736
|
-
|
|
754
|
+
connectionTimeoutMs = DEFAULT_KEEP_ALIVE_TIMEOUT,
|
|
737
755
|
} = {},
|
|
738
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
|
+
}
|
|
739
794
|
|
|
740
|
-
|
|
741
|
-
}
|
|
742
|
-
};
|
|
743
|
-
|
|
744
|
-
const gqlInit = {
|
|
745
|
-
type: MESSAGE_TYPES.GQL_CONNECTION_INIT,
|
|
746
|
-
};
|
|
747
|
-
this.awsRealTimeSocket.send(JSON.stringify(gqlInit));
|
|
748
|
-
|
|
749
|
-
function checkAckOk() {
|
|
795
|
+
function checkAckOk(ackOk: boolean) {
|
|
750
796
|
if (!ackOk) {
|
|
751
797
|
rej(
|
|
752
798
|
new Error(
|
|
@@ -755,12 +801,13 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
755
801
|
);
|
|
756
802
|
}
|
|
757
803
|
}
|
|
758
|
-
|
|
759
|
-
setTimeout(checkAckOk.bind(this), CONNECTION_INIT_TIMEOUT);
|
|
760
804
|
});
|
|
761
805
|
})();
|
|
762
806
|
} catch (err) {
|
|
763
|
-
const { errorType, errorCode } = err
|
|
807
|
+
const { errorType, errorCode } = err as {
|
|
808
|
+
errorType: string;
|
|
809
|
+
errorCode: number;
|
|
810
|
+
};
|
|
764
811
|
|
|
765
812
|
if (NON_RETRYABLE_CODES.includes(errorCode)) {
|
|
766
813
|
throw new NonRetryableError(errorType);
|
|
@@ -780,8 +827,10 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
780
827
|
apiKey,
|
|
781
828
|
region,
|
|
782
829
|
additionalHeaders,
|
|
783
|
-
}): Promise<any> {
|
|
784
|
-
const headerHandler
|
|
830
|
+
}: AWSAppSyncRealTimeProviderOptions): Promise<any> {
|
|
831
|
+
const headerHandler: {
|
|
832
|
+
[key in GraphqlAuthModes]: (AWSAppSyncRealTimeAuthInput) => {};
|
|
833
|
+
} = {
|
|
785
834
|
API_KEY: this._awsRealTimeApiKeyHeader.bind(this),
|
|
786
835
|
AWS_IAM: this._awsRealTimeIAMHeader.bind(this),
|
|
787
836
|
OPENID_CONNECT: this._awsRealTimeOPENIDHeader.bind(this),
|
|
@@ -789,29 +838,29 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
789
838
|
AWS_LAMBDA: this._customAuthHeader,
|
|
790
839
|
};
|
|
791
840
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
if (typeof handler !== 'function') {
|
|
841
|
+
if (!authenticationType || !headerHandler[authenticationType]) {
|
|
795
842
|
logger.debug(`Authentication type ${authenticationType} not supported`);
|
|
796
843
|
return '';
|
|
797
|
-
}
|
|
844
|
+
} else {
|
|
845
|
+
const handler = headerHandler[authenticationType];
|
|
798
846
|
|
|
799
|
-
|
|
847
|
+
const { host } = url.parse(appSyncGraphqlEndpoint ?? '');
|
|
800
848
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
849
|
+
const result = await handler({
|
|
850
|
+
payload,
|
|
851
|
+
canonicalUri,
|
|
852
|
+
appSyncGraphqlEndpoint,
|
|
853
|
+
apiKey,
|
|
854
|
+
region,
|
|
855
|
+
host,
|
|
856
|
+
additionalHeaders,
|
|
857
|
+
});
|
|
810
858
|
|
|
811
|
-
|
|
859
|
+
return result;
|
|
860
|
+
}
|
|
812
861
|
}
|
|
813
862
|
|
|
814
|
-
private async _awsRealTimeCUPHeader({ host }) {
|
|
863
|
+
private async _awsRealTimeCUPHeader({ host }: AWSAppSyncRealTimeAuthInput) {
|
|
815
864
|
const session = await Auth.currentSession();
|
|
816
865
|
return {
|
|
817
866
|
Authorization: session.getAccessToken().getJwtToken(),
|
|
@@ -819,7 +868,9 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
819
868
|
};
|
|
820
869
|
}
|
|
821
870
|
|
|
822
|
-
private async _awsRealTimeOPENIDHeader({
|
|
871
|
+
private async _awsRealTimeOPENIDHeader({
|
|
872
|
+
host,
|
|
873
|
+
}: AWSAppSyncRealTimeAuthInput) {
|
|
823
874
|
let token;
|
|
824
875
|
// backwards compatibility
|
|
825
876
|
const federatedInfo = await Cache.getItem('federatedInfo');
|
|
@@ -840,7 +891,10 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
840
891
|
};
|
|
841
892
|
}
|
|
842
893
|
|
|
843
|
-
private async _awsRealTimeApiKeyHeader({
|
|
894
|
+
private async _awsRealTimeApiKeyHeader({
|
|
895
|
+
apiKey,
|
|
896
|
+
host,
|
|
897
|
+
}: AWSAppSyncRealTimeAuthInput) {
|
|
844
898
|
const dt = new Date();
|
|
845
899
|
const dtStr = dt.toISOString().replace(/[:\-]|\.\d{3}/g, '');
|
|
846
900
|
|
|
@@ -856,7 +910,7 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
856
910
|
canonicalUri,
|
|
857
911
|
appSyncGraphqlEndpoint,
|
|
858
912
|
region,
|
|
859
|
-
}) {
|
|
913
|
+
}: AWSAppSyncRealTimeAuthInput) {
|
|
860
914
|
const endpointInfo = {
|
|
861
915
|
region,
|
|
862
916
|
service: 'appsync',
|
|
@@ -866,11 +920,16 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
866
920
|
if (!credentialsOK) {
|
|
867
921
|
throw new Error('No credentials');
|
|
868
922
|
}
|
|
869
|
-
const creds = await Credentials.get().then(credentials =>
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
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
|
+
});
|
|
874
933
|
|
|
875
934
|
const request = {
|
|
876
935
|
url: `${appSyncGraphqlEndpoint}${canonicalUri}`,
|
|
@@ -883,8 +942,11 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
883
942
|
return signed_params.headers;
|
|
884
943
|
}
|
|
885
944
|
|
|
886
|
-
private _customAuthHeader({
|
|
887
|
-
|
|
945
|
+
private _customAuthHeader({
|
|
946
|
+
host,
|
|
947
|
+
additionalHeaders,
|
|
948
|
+
}: AWSAppSyncRealTimeAuthInput) {
|
|
949
|
+
if (!additionalHeaders || !additionalHeaders['Authorization']) {
|
|
888
950
|
throw new Error('No auth token specified');
|
|
889
951
|
}
|
|
890
952
|
|
|
@@ -899,14 +961,14 @@ export class AWSAppSyncRealTimeProvider extends AbstractPubSubProvider {
|
|
|
899
961
|
*/
|
|
900
962
|
_ensureCredentials() {
|
|
901
963
|
return Credentials.get()
|
|
902
|
-
.then(credentials => {
|
|
964
|
+
.then((credentials: any) => {
|
|
903
965
|
if (!credentials) return false;
|
|
904
966
|
const cred = Credentials.shear(credentials);
|
|
905
967
|
logger.debug('set credentials for AWSAppSyncRealTimeProvider', cred);
|
|
906
968
|
|
|
907
969
|
return true;
|
|
908
970
|
})
|
|
909
|
-
.catch(err => {
|
|
971
|
+
.catch((err: any) => {
|
|
910
972
|
logger.warn('ensure credentials error', err);
|
|
911
973
|
return false;
|
|
912
974
|
});
|