@aws-amplify/api-graphql 4.0.1-console-preview.d745d43.0 → 4.0.1-ssr-api.df60e41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/lib/GraphQLAPI.d.ts +1 -1
  2. package/lib/GraphQLAPI.js +23 -30
  3. package/lib/Providers/AWSAppSyncRealTimeProvider/index.js +467 -582
  4. package/lib/index.js +1 -1
  5. package/lib/internals/InternalGraphQLAPI.d.ts +1 -1
  6. package/lib/internals/InternalGraphQLAPI.js +204 -246
  7. package/lib/internals/v6.js +3 -3
  8. package/lib/tsconfig.tsbuildinfo +180 -20
  9. package/lib/types/index.d.ts +17 -3
  10. package/lib/utils/ConnectionStateMonitor.js +51 -64
  11. package/lib/utils/ReachabilityMonitor/index.js +2 -2
  12. package/lib/utils/ReachabilityMonitor/index.native.js +4 -6
  13. package/lib/utils/ReconnectionMonitor.js +20 -24
  14. package/lib/utils/errors/APIError.js +7 -11
  15. package/lib/utils/errors/assertValidationError.js +4 -4
  16. package/lib/utils/errors/validation.js +5 -6
  17. package/lib/utils/resolveConfig.js +9 -10
  18. package/lib/utils/resolveLibraryOptions.js +4 -5
  19. package/lib-esm/GraphQLAPI.d.ts +1 -1
  20. package/lib-esm/GraphQLAPI.js +22 -30
  21. package/lib-esm/Providers/AWSAppSyncRealTimeProvider/index.js +458 -574
  22. package/lib-esm/Providers/constants.js +10 -10
  23. package/lib-esm/internals/InternalGraphQLAPI.d.ts +1 -1
  24. package/lib-esm/internals/InternalGraphQLAPI.js +201 -244
  25. package/lib-esm/internals/v6.js +1 -1
  26. package/lib-esm/tsconfig.tsbuildinfo +180 -20
  27. package/lib-esm/types/index.d.ts +17 -3
  28. package/lib-esm/types/index.js +1 -1
  29. package/lib-esm/utils/ConnectionStateMonitor.js +49 -63
  30. package/lib-esm/utils/ReachabilityMonitor/index.js +1 -1
  31. package/lib-esm/utils/ReachabilityMonitor/index.native.js +1 -3
  32. package/lib-esm/utils/ReconnectionMonitor.js +19 -24
  33. package/lib-esm/utils/errors/APIError.js +6 -11
  34. package/lib-esm/utils/errors/assertValidationError.js +2 -2
  35. package/lib-esm/utils/errors/validation.js +5 -6
  36. package/lib-esm/utils/resolveConfig.js +8 -9
  37. package/lib-esm/utils/resolveLibraryOptions.js +4 -5
  38. package/package.json +6 -6
  39. package/src/GraphQLAPI.ts +3 -2
  40. package/src/internals/InternalGraphQLAPI.ts +35 -10
  41. package/src/types/index.ts +38 -8
@@ -1,4 +1,3 @@
1
- import { __assign, __awaiter, __generator, __read } from "tslib";
2
1
  // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
2
  // SPDX-License-Identifier: Apache-2.0
4
3
  import { Observable } from 'rxjs';
@@ -10,16 +9,14 @@ import { CONTROL_MSG, ConnectionState, } from '../../types/PubSub';
10
9
  import { AMPLIFY_SYMBOL, AWS_APPSYNC_REALTIME_HEADERS, CONNECTION_INIT_TIMEOUT, DEFAULT_KEEP_ALIVE_TIMEOUT, DEFAULT_KEEP_ALIVE_ALERT_TIMEOUT, MAX_DELAY_MS, MESSAGE_TYPES, NON_RETRYABLE_CODES, SOCKET_STATUS, START_ACK_TIMEOUT, SUBSCRIPTION_STATUS, CONNECTION_STATE_CHANGE, } from '../constants';
11
10
  import { ConnectionStateMonitor, CONNECTION_CHANGE, } from '../../utils/ConnectionStateMonitor';
12
11
  import { ReconnectEvent, ReconnectionMonitor, } from '../../utils/ReconnectionMonitor';
13
- var logger = new ConsoleLogger('AWSAppSyncRealTimeProvider');
14
- var dispatchApiEvent = function (payload) {
12
+ const logger = new ConsoleLogger('AWSAppSyncRealTimeProvider');
13
+ const dispatchApiEvent = payload => {
15
14
  Hub.dispatch('api', payload, 'PubSub', AMPLIFY_SYMBOL);
16
15
  };
17
- var standardDomainPattern = /^https:\/\/\w{26}\.appsync\-api\.\w{2}(?:(?:\-\w{2,})+)\-\d\.amazonaws.com(?:\.cn)?\/graphql$/i;
18
- var customDomainPath = '/realtime';
19
- var AWSAppSyncRealTimeProvider = /** @class */ (function () {
20
- function AWSAppSyncRealTimeProvider(options) {
21
- var _this = this;
22
- if (options === void 0) { options = {}; }
16
+ const standardDomainPattern = /^https:\/\/\w{26}\.appsync\-api\.\w{2}(?:(?:\-\w{2,})+)\-\d\.amazonaws.com(?:\.cn)?\/graphql$/i;
17
+ const customDomainPath = '/realtime';
18
+ export class AWSAppSyncRealTimeProvider {
19
+ constructor(options = {}) {
23
20
  this.socketStatus = SOCKET_STATUS.CLOSED;
24
21
  this.keepAliveTimeout = DEFAULT_KEEP_ALIVE_TIMEOUT;
25
22
  this.subscriptionObserverMap = new Map();
@@ -28,19 +25,19 @@ var AWSAppSyncRealTimeProvider = /** @class */ (function () {
28
25
  this.reconnectionMonitor = new ReconnectionMonitor();
29
26
  // Monitor the connection state and pass changes along to Hub
30
27
  this.connectionStateMonitorSubscription =
31
- this.connectionStateMonitor.connectionStateObservable.subscribe(function (connectionState) {
28
+ this.connectionStateMonitor.connectionStateObservable.subscribe(connectionState => {
32
29
  dispatchApiEvent({
33
30
  event: CONNECTION_STATE_CHANGE,
34
31
  data: {
35
- provider: _this,
36
- connectionState: connectionState,
32
+ provider: this,
33
+ connectionState,
37
34
  },
38
- message: "Connection state is " + connectionState,
35
+ message: `Connection state is ${connectionState}`,
39
36
  });
40
- _this.connectionState = connectionState;
37
+ this.connectionState = connectionState;
41
38
  // Trigger START_RECONNECT when the connection is disrupted
42
39
  if (connectionState === ConnectionState.ConnectionDisrupted) {
43
- _this.reconnectionMonitor.record(ReconnectEvent.START_RECONNECT);
40
+ this.reconnectionMonitor.record(ReconnectEvent.START_RECONNECT);
44
41
  }
45
42
  // Trigger HALT_RECONNECT to halt reconnection attempts when the state is anything other than
46
43
  // ConnectionDisrupted or Connecting
@@ -52,14 +49,14 @@ var AWSAppSyncRealTimeProvider = /** @class */ (function () {
52
49
  ConnectionState.ConnectionDisruptedPendingNetwork,
53
50
  ConnectionState.Disconnected,
54
51
  ].includes(connectionState)) {
55
- _this.reconnectionMonitor.record(ReconnectEvent.HALT_RECONNECT);
52
+ this.reconnectionMonitor.record(ReconnectEvent.HALT_RECONNECT);
56
53
  }
57
54
  });
58
55
  }
59
56
  /**
60
57
  * Mark the socket closed and release all active listeners
61
58
  */
62
- AWSAppSyncRealTimeProvider.prototype.close = function () {
59
+ close() {
63
60
  // Mark the socket closed both in status and the connection monitor
64
61
  this.socketStatus = SOCKET_STATUS.CLOSED;
65
62
  this.connectionStateMonitor.record(CONNECTION_CHANGE.CONNECTION_FAILED);
@@ -67,202 +64,177 @@ var AWSAppSyncRealTimeProvider = /** @class */ (function () {
67
64
  this.connectionStateMonitorSubscription.unsubscribe();
68
65
  // Complete all reconnect observers
69
66
  this.reconnectionMonitor.close();
70
- };
71
- AWSAppSyncRealTimeProvider.prototype.getNewWebSocket = function (url, protocol) {
67
+ }
68
+ getNewWebSocket(url, protocol) {
72
69
  return new WebSocket(url, protocol);
73
- };
74
- AWSAppSyncRealTimeProvider.prototype.getProviderName = function () {
70
+ }
71
+ getProviderName() {
75
72
  return 'AWSAppSyncRealTimeProvider';
76
- };
73
+ }
77
74
  // Check if url matches standard domain pattern
78
- AWSAppSyncRealTimeProvider.prototype.isCustomDomain = function (url) {
75
+ isCustomDomain(url) {
79
76
  return url.match(standardDomainPattern) === null;
80
- };
81
- AWSAppSyncRealTimeProvider.prototype.subscribe = function (options, customUserAgentDetails) {
82
- var _this = this;
83
- var _a = options || {}, appSyncGraphqlEndpoint = _a.appSyncGraphqlEndpoint, region = _a.region, query = _a.query, variables = _a.variables, authenticationType = _a.authenticationType, additionalHeaders = _a.additionalHeaders, apiKey = _a.apiKey;
84
- return new Observable(function (observer) {
77
+ }
78
+ subscribe(options, customUserAgentDetails) {
79
+ const { appSyncGraphqlEndpoint, region, query, variables, authenticationType, additionalHeaders, apiKey, } = options || {};
80
+ return new Observable(observer => {
85
81
  if (!options || !appSyncGraphqlEndpoint) {
86
82
  observer.error({
87
83
  errors: [
88
- __assign({}, new GraphQLError("Subscribe only available for AWS AppSync endpoint")),
84
+ {
85
+ ...new GraphQLError(`Subscribe only available for AWS AppSync endpoint`),
86
+ },
89
87
  ],
90
88
  });
91
89
  observer.complete();
92
90
  }
93
91
  else {
94
- var subscriptionStartActive_1 = false;
95
- var subscriptionId_1 = amplifyUuid();
96
- var startSubscription_1 = function () {
97
- if (!subscriptionStartActive_1) {
98
- subscriptionStartActive_1 = true;
99
- var startSubscriptionPromise = _this._startSubscriptionWithAWSAppSyncRealTime({
92
+ let subscriptionStartActive = false;
93
+ const subscriptionId = amplifyUuid();
94
+ const startSubscription = () => {
95
+ if (!subscriptionStartActive) {
96
+ subscriptionStartActive = true;
97
+ const startSubscriptionPromise = this._startSubscriptionWithAWSAppSyncRealTime({
100
98
  options: {
101
- query: query,
102
- variables: variables,
103
- region: region,
104
- authenticationType: authenticationType,
105
- appSyncGraphqlEndpoint: appSyncGraphqlEndpoint,
106
- additionalHeaders: additionalHeaders,
107
- apiKey: apiKey,
99
+ query,
100
+ variables,
101
+ region,
102
+ authenticationType,
103
+ appSyncGraphqlEndpoint,
104
+ additionalHeaders,
105
+ apiKey,
108
106
  },
109
- observer: observer,
110
- subscriptionId: subscriptionId_1,
111
- customUserAgentDetails: customUserAgentDetails,
112
- }).catch(function (err) {
113
- logger.debug(CONTROL_MSG.REALTIME_SUBSCRIPTION_INIT_ERROR + ": " + err);
114
- _this.connectionStateMonitor.record(CONNECTION_CHANGE.CLOSED);
107
+ observer,
108
+ subscriptionId,
109
+ customUserAgentDetails,
110
+ }).catch(err => {
111
+ logger.debug(`${CONTROL_MSG.REALTIME_SUBSCRIPTION_INIT_ERROR}: ${err}`);
112
+ this.connectionStateMonitor.record(CONNECTION_CHANGE.CLOSED);
115
113
  });
116
- startSubscriptionPromise.finally(function () {
117
- subscriptionStartActive_1 = false;
114
+ startSubscriptionPromise.finally(() => {
115
+ subscriptionStartActive = false;
118
116
  });
119
117
  }
120
118
  };
121
- var reconnectSubscription_1;
119
+ let reconnectSubscription;
122
120
  // Add an observable to the reconnection list to manage reconnection for this subscription
123
- reconnectSubscription_1 = new Observable(function (observer) {
124
- _this.reconnectionMonitor.addObserver(observer);
125
- }).subscribe(function () {
126
- startSubscription_1();
121
+ reconnectSubscription = new Observable(observer => {
122
+ this.reconnectionMonitor.addObserver(observer);
123
+ }).subscribe(() => {
124
+ startSubscription();
127
125
  });
128
- startSubscription_1();
129
- return function () { return __awaiter(_this, void 0, void 0, function () {
130
- var subscriptionState, err_1;
131
- return __generator(this, function (_a) {
132
- switch (_a.label) {
133
- case 0:
134
- // Cleanup reconnection subscription
135
- reconnectSubscription_1 === null || reconnectSubscription_1 === void 0 ? void 0 : reconnectSubscription_1.unsubscribe();
136
- _a.label = 1;
137
- case 1:
138
- _a.trys.push([1, 3, 4, 5]);
139
- // Waiting that subscription has been connected before trying to unsubscribe
140
- return [4 /*yield*/, this._waitForSubscriptionToBeConnected(subscriptionId_1)];
141
- case 2:
142
- // Waiting that subscription has been connected before trying to unsubscribe
143
- _a.sent();
144
- subscriptionState = (this.subscriptionObserverMap.get(subscriptionId_1) || {}).subscriptionState;
145
- if (!subscriptionState) {
146
- // subscription already unsubscribed
147
- return [2 /*return*/];
148
- }
149
- if (subscriptionState === SUBSCRIPTION_STATUS.CONNECTED) {
150
- this._sendUnsubscriptionMessage(subscriptionId_1);
151
- }
152
- else {
153
- throw new Error('Subscription never connected');
154
- }
155
- return [3 /*break*/, 5];
156
- case 3:
157
- err_1 = _a.sent();
158
- logger.debug("Error while unsubscribing " + err_1);
159
- return [3 /*break*/, 5];
160
- case 4:
161
- this._removeSubscriptionObserver(subscriptionId_1);
162
- return [7 /*endfinally*/];
163
- case 5: return [2 /*return*/];
126
+ startSubscription();
127
+ return async () => {
128
+ // Cleanup reconnection subscription
129
+ reconnectSubscription?.unsubscribe();
130
+ // Cleanup after unsubscribing or observer.complete was called after _startSubscriptionWithAWSAppSyncRealTime
131
+ try {
132
+ // Waiting that subscription has been connected before trying to unsubscribe
133
+ await this._waitForSubscriptionToBeConnected(subscriptionId);
134
+ const { subscriptionState } = this.subscriptionObserverMap.get(subscriptionId) || {};
135
+ if (!subscriptionState) {
136
+ // subscription already unsubscribed
137
+ return;
164
138
  }
165
- });
166
- }); };
139
+ if (subscriptionState === SUBSCRIPTION_STATUS.CONNECTED) {
140
+ this._sendUnsubscriptionMessage(subscriptionId);
141
+ }
142
+ else {
143
+ throw new Error('Subscription never connected');
144
+ }
145
+ }
146
+ catch (err) {
147
+ logger.debug(`Error while unsubscribing ${err}`);
148
+ }
149
+ finally {
150
+ this._removeSubscriptionObserver(subscriptionId);
151
+ }
152
+ };
167
153
  }
168
154
  });
169
- };
170
- AWSAppSyncRealTimeProvider.prototype._startSubscriptionWithAWSAppSyncRealTime = function (_a) {
171
- var options = _a.options, observer = _a.observer, subscriptionId = _a.subscriptionId, customUserAgentDetails = _a.customUserAgentDetails;
172
- var _b;
173
- return __awaiter(this, void 0, void 0, function () {
174
- var appSyncGraphqlEndpoint, authenticationType, query, variables, apiKey, region, _c, graphql_headers, _d, additionalHeaders, subscriptionState, data, dataString, headerObj, _e, _f, subscriptionMessage, stringToAWSRealTime, err_2, _g, subscriptionFailedCallback, subscriptionReadyCallback;
175
- var _h;
176
- var _this = this;
177
- return __generator(this, function (_j) {
178
- switch (_j.label) {
179
- case 0:
180
- appSyncGraphqlEndpoint = options.appSyncGraphqlEndpoint, authenticationType = options.authenticationType, query = options.query, variables = options.variables, apiKey = options.apiKey, region = options.region, _c = options.graphql_headers, graphql_headers = _c === void 0 ? function () { return ({}); } : _c, _d = options.additionalHeaders, additionalHeaders = _d === void 0 ? {} : _d;
181
- subscriptionState = SUBSCRIPTION_STATUS.PENDING;
182
- data = {
183
- query: query,
184
- variables: variables,
185
- };
186
- // Having a subscription id map will make it simple to forward messages received
187
- this.subscriptionObserverMap.set(subscriptionId, {
188
- observer: observer,
189
- query: query !== null && query !== void 0 ? query : '',
190
- variables: variables !== null && variables !== void 0 ? variables : {},
191
- subscriptionState: subscriptionState,
192
- startAckTimeoutId: undefined,
193
- });
194
- dataString = JSON.stringify(data);
195
- _e = [{}];
196
- return [4 /*yield*/, this._awsRealTimeHeaderBasedAuth({
197
- apiKey: apiKey,
198
- appSyncGraphqlEndpoint: appSyncGraphqlEndpoint,
199
- authenticationType: authenticationType,
200
- payload: dataString,
201
- canonicalUri: '',
202
- region: region,
203
- additionalHeaders: additionalHeaders,
204
- })];
205
- case 1:
206
- _f = [__assign.apply(void 0, _e.concat([(_j.sent())]))];
207
- return [4 /*yield*/, graphql_headers()];
208
- case 2:
209
- headerObj = __assign.apply(void 0, [__assign.apply(void 0, [__assign.apply(void 0, _f.concat([(_j.sent())])), additionalHeaders]), (_h = {}, _h[USER_AGENT_HEADER] = getAmplifyUserAgent(customUserAgentDetails), _h)]);
210
- subscriptionMessage = {
211
- id: subscriptionId,
212
- payload: {
213
- data: dataString,
214
- extensions: {
215
- authorization: __assign({}, headerObj),
216
- },
217
- },
218
- type: MESSAGE_TYPES.GQL_START,
219
- };
220
- stringToAWSRealTime = JSON.stringify(subscriptionMessage);
221
- _j.label = 3;
222
- case 3:
223
- _j.trys.push([3, 5, , 6]);
224
- this.connectionStateMonitor.record(CONNECTION_CHANGE.OPENING_CONNECTION);
225
- return [4 /*yield*/, this._initializeWebSocketConnection({
226
- apiKey: apiKey,
227
- appSyncGraphqlEndpoint: appSyncGraphqlEndpoint,
228
- authenticationType: authenticationType,
229
- region: region,
230
- additionalHeaders: additionalHeaders,
231
- })];
232
- case 4:
233
- _j.sent();
234
- return [3 /*break*/, 6];
235
- case 5:
236
- err_2 = _j.sent();
237
- this._logStartSubscriptionError(subscriptionId, observer, err_2);
238
- return [2 /*return*/];
239
- case 6:
240
- _g = (_b = this.subscriptionObserverMap.get(subscriptionId)) !== null && _b !== void 0 ? _b : {}, subscriptionFailedCallback = _g.subscriptionFailedCallback, subscriptionReadyCallback = _g.subscriptionReadyCallback;
241
- // This must be done before sending the message in order to be listening immediately
242
- this.subscriptionObserverMap.set(subscriptionId, {
243
- observer: observer,
244
- subscriptionState: subscriptionState,
245
- query: query !== null && query !== void 0 ? query : '',
246
- variables: variables !== null && variables !== void 0 ? variables : {},
247
- subscriptionReadyCallback: subscriptionReadyCallback,
248
- subscriptionFailedCallback: subscriptionFailedCallback,
249
- startAckTimeoutId: setTimeout(function () {
250
- _this._timeoutStartSubscriptionAck.call(_this, subscriptionId);
251
- }, START_ACK_TIMEOUT),
252
- });
253
- if (this.awsRealTimeSocket) {
254
- this.awsRealTimeSocket.send(stringToAWSRealTime);
255
- }
256
- return [2 /*return*/];
257
- }
155
+ }
156
+ async _startSubscriptionWithAWSAppSyncRealTime({ options, observer, subscriptionId, customUserAgentDetails, }) {
157
+ const { appSyncGraphqlEndpoint, authenticationType, query, variables, apiKey, region, graphql_headers = () => ({}), additionalHeaders = {}, } = options;
158
+ const subscriptionState = SUBSCRIPTION_STATUS.PENDING;
159
+ const data = {
160
+ query,
161
+ variables,
162
+ };
163
+ // Having a subscription id map will make it simple to forward messages received
164
+ this.subscriptionObserverMap.set(subscriptionId, {
165
+ observer,
166
+ query: query ?? '',
167
+ variables: variables ?? {},
168
+ subscriptionState,
169
+ startAckTimeoutId: undefined,
170
+ });
171
+ // Preparing payload for subscription message
172
+ const dataString = JSON.stringify(data);
173
+ const headerObj = {
174
+ ...(await this._awsRealTimeHeaderBasedAuth({
175
+ apiKey,
176
+ appSyncGraphqlEndpoint,
177
+ authenticationType,
178
+ payload: dataString,
179
+ canonicalUri: '',
180
+ region,
181
+ additionalHeaders,
182
+ })),
183
+ ...(await graphql_headers()),
184
+ ...additionalHeaders,
185
+ [USER_AGENT_HEADER]: getAmplifyUserAgent(customUserAgentDetails),
186
+ };
187
+ const subscriptionMessage = {
188
+ id: subscriptionId,
189
+ payload: {
190
+ data: dataString,
191
+ extensions: {
192
+ authorization: {
193
+ ...headerObj,
194
+ },
195
+ },
196
+ },
197
+ type: MESSAGE_TYPES.GQL_START,
198
+ };
199
+ const stringToAWSRealTime = JSON.stringify(subscriptionMessage);
200
+ try {
201
+ this.connectionStateMonitor.record(CONNECTION_CHANGE.OPENING_CONNECTION);
202
+ await this._initializeWebSocketConnection({
203
+ apiKey,
204
+ appSyncGraphqlEndpoint,
205
+ authenticationType,
206
+ region,
207
+ additionalHeaders,
258
208
  });
209
+ }
210
+ catch (err) {
211
+ this._logStartSubscriptionError(subscriptionId, observer, err);
212
+ return;
213
+ }
214
+ // Potential race condition can occur when unsubscribe is called during _initializeWebSocketConnection.
215
+ // E.g.unsubscribe gets invoked prior to finishing WebSocket handshake or START_ACK.
216
+ // Both subscriptionFailedCallback and subscriptionReadyCallback are used to synchronized this.
217
+ const { subscriptionFailedCallback, subscriptionReadyCallback } = this.subscriptionObserverMap.get(subscriptionId) ?? {};
218
+ // This must be done before sending the message in order to be listening immediately
219
+ this.subscriptionObserverMap.set(subscriptionId, {
220
+ observer,
221
+ subscriptionState,
222
+ query: query ?? '',
223
+ variables: variables ?? {},
224
+ subscriptionReadyCallback,
225
+ subscriptionFailedCallback,
226
+ startAckTimeoutId: setTimeout(() => {
227
+ this._timeoutStartSubscriptionAck.call(this, subscriptionId);
228
+ }, START_ACK_TIMEOUT),
259
229
  });
260
- };
230
+ if (this.awsRealTimeSocket) {
231
+ this.awsRealTimeSocket.send(stringToAWSRealTime);
232
+ }
233
+ }
261
234
  // Log logic for start subscription failures
262
- AWSAppSyncRealTimeProvider.prototype._logStartSubscriptionError = function (subscriptionId, observer, err) {
263
- var _a;
264
- logger.debug({ err: err });
265
- var message = String((_a = err.message) !== null && _a !== void 0 ? _a : '');
235
+ _logStartSubscriptionError(subscriptionId, observer, err) {
236
+ logger.debug({ err });
237
+ const message = String(err.message ?? '');
266
238
  // Resolving to give the state observer time to propogate the update
267
239
  Promise.resolve(this.connectionStateMonitor.record(CONNECTION_CHANGE.CLOSED));
268
240
  // Capture the error only when the network didn't cause disruption
@@ -271,73 +243,68 @@ var AWSAppSyncRealTimeProvider = /** @class */ (function () {
271
243
  if (isNonRetryableError(err)) {
272
244
  observer.error({
273
245
  errors: [
274
- __assign({}, new GraphQLError(CONTROL_MSG.CONNECTION_FAILED + ": " + message)),
246
+ {
247
+ ...new GraphQLError(`${CONTROL_MSG.CONNECTION_FAILED}: ${message}`),
248
+ },
275
249
  ],
276
250
  });
277
251
  }
278
252
  else {
279
- logger.debug(CONTROL_MSG.CONNECTION_FAILED + ": " + message);
253
+ logger.debug(`${CONTROL_MSG.CONNECTION_FAILED}: ${message}`);
280
254
  }
281
- var subscriptionFailedCallback = (this.subscriptionObserverMap.get(subscriptionId) || {}).subscriptionFailedCallback;
255
+ const { subscriptionFailedCallback } = this.subscriptionObserverMap.get(subscriptionId) || {};
282
256
  // Notify concurrent unsubscription
283
257
  if (typeof subscriptionFailedCallback === 'function') {
284
258
  subscriptionFailedCallback();
285
259
  }
286
260
  }
287
- };
261
+ }
288
262
  // Waiting that subscription has been connected before trying to unsubscribe
289
- AWSAppSyncRealTimeProvider.prototype._waitForSubscriptionToBeConnected = function (subscriptionId) {
290
- return __awaiter(this, void 0, void 0, function () {
291
- var subscriptionObserver, subscriptionState;
292
- var _this = this;
293
- return __generator(this, function (_a) {
294
- subscriptionObserver = this.subscriptionObserverMap.get(subscriptionId);
295
- if (subscriptionObserver) {
296
- subscriptionState = subscriptionObserver.subscriptionState;
297
- // This in case unsubscribe is invoked before sending start subscription message
298
- if (subscriptionState === SUBSCRIPTION_STATUS.PENDING) {
299
- return [2 /*return*/, new Promise(function (res, rej) {
300
- var observer = subscriptionObserver.observer, subscriptionState = subscriptionObserver.subscriptionState, variables = subscriptionObserver.variables, query = subscriptionObserver.query;
301
- _this.subscriptionObserverMap.set(subscriptionId, {
302
- observer: observer,
303
- subscriptionState: subscriptionState,
304
- variables: variables,
305
- query: query,
306
- subscriptionReadyCallback: res,
307
- subscriptionFailedCallback: rej,
308
- });
309
- })];
310
- }
311
- }
312
- return [2 /*return*/];
313
- });
314
- });
315
- };
316
- AWSAppSyncRealTimeProvider.prototype._sendUnsubscriptionMessage = function (subscriptionId) {
263
+ async _waitForSubscriptionToBeConnected(subscriptionId) {
264
+ const subscriptionObserver = this.subscriptionObserverMap.get(subscriptionId);
265
+ if (subscriptionObserver) {
266
+ const { subscriptionState } = subscriptionObserver;
267
+ // This in case unsubscribe is invoked before sending start subscription message
268
+ if (subscriptionState === SUBSCRIPTION_STATUS.PENDING) {
269
+ return new Promise((res, rej) => {
270
+ const { observer, subscriptionState, variables, query } = subscriptionObserver;
271
+ this.subscriptionObserverMap.set(subscriptionId, {
272
+ observer,
273
+ subscriptionState,
274
+ variables,
275
+ query,
276
+ subscriptionReadyCallback: res,
277
+ subscriptionFailedCallback: rej,
278
+ });
279
+ });
280
+ }
281
+ }
282
+ }
283
+ _sendUnsubscriptionMessage(subscriptionId) {
317
284
  try {
318
285
  if (this.awsRealTimeSocket &&
319
286
  this.awsRealTimeSocket.readyState === WebSocket.OPEN &&
320
287
  this.socketStatus === SOCKET_STATUS.READY) {
321
288
  // Preparing unsubscribe message to stop receiving messages for that subscription
322
- var unsubscribeMessage = {
289
+ const unsubscribeMessage = {
323
290
  id: subscriptionId,
324
291
  type: MESSAGE_TYPES.GQL_STOP,
325
292
  };
326
- var stringToAWSRealTime = JSON.stringify(unsubscribeMessage);
293
+ const stringToAWSRealTime = JSON.stringify(unsubscribeMessage);
327
294
  this.awsRealTimeSocket.send(stringToAWSRealTime);
328
295
  }
329
296
  }
330
297
  catch (err) {
331
298
  // If GQL_STOP is not sent because of disconnection issue, then there is nothing the client can do
332
- logger.debug({ err: err });
299
+ logger.debug({ err });
333
300
  }
334
- };
335
- AWSAppSyncRealTimeProvider.prototype._removeSubscriptionObserver = function (subscriptionId) {
301
+ }
302
+ _removeSubscriptionObserver(subscriptionId) {
336
303
  this.subscriptionObserverMap.delete(subscriptionId);
337
304
  // Verifying 1000ms after removing subscription in case there are new subscription unmount/mount
338
305
  setTimeout(this._closeSocketIfRequired.bind(this), 1000);
339
- };
340
- AWSAppSyncRealTimeProvider.prototype._closeSocketIfRequired = function () {
306
+ }
307
+ _closeSocketIfRequired() {
341
308
  if (this.subscriptionObserverMap.size > 0) {
342
309
  // Active subscriptions on the WebSocket
343
310
  return;
@@ -359,7 +326,7 @@ var AWSAppSyncRealTimeProvider = /** @class */ (function () {
359
326
  if (this.keepAliveAlertTimeoutId) {
360
327
  clearTimeout(this.keepAliveAlertTimeoutId);
361
328
  }
362
- var tempSocket = this.awsRealTimeSocket;
329
+ const tempSocket = this.awsRealTimeSocket;
363
330
  // Cleaning callbacks to avoid race condition, socket still exists
364
331
  tempSocket.onclose = null;
365
332
  tempSocket.onerror = null;
@@ -368,27 +335,26 @@ var AWSAppSyncRealTimeProvider = /** @class */ (function () {
368
335
  this.socketStatus = SOCKET_STATUS.CLOSED;
369
336
  this.connectionStateMonitor.record(CONNECTION_CHANGE.CLOSED);
370
337
  }
371
- };
372
- AWSAppSyncRealTimeProvider.prototype._handleIncomingSubscriptionMessage = function (message) {
373
- var _this = this;
338
+ }
339
+ _handleIncomingSubscriptionMessage(message) {
374
340
  if (typeof message.data !== 'string') {
375
341
  return;
376
342
  }
377
- logger.debug("subscription message from AWS AppSync RealTime: " + message.data);
378
- var _a = JSON.parse(String(message.data)), _b = _a.id, id = _b === void 0 ? '' : _b, payload = _a.payload, type = _a.type;
379
- var _c = this.subscriptionObserverMap.get(id) || {}, _d = _c.observer, observer = _d === void 0 ? null : _d, _e = _c.query, query = _e === void 0 ? '' : _e, _f = _c.variables, variables = _f === void 0 ? {} : _f, startAckTimeoutId = _c.startAckTimeoutId, subscriptionReadyCallback = _c.subscriptionReadyCallback, subscriptionFailedCallback = _c.subscriptionFailedCallback;
380
- logger.debug({ id: id, observer: observer, query: query, variables: variables });
343
+ logger.debug(`subscription message from AWS AppSync RealTime: ${message.data}`);
344
+ const { id = '', payload, type, } = JSON.parse(String(message.data));
345
+ const { observer = null, query = '', variables = {}, startAckTimeoutId, subscriptionReadyCallback, subscriptionFailedCallback, } = this.subscriptionObserverMap.get(id) || {};
346
+ logger.debug({ id, observer, query, variables });
381
347
  if (type === MESSAGE_TYPES.GQL_DATA && payload && payload.data) {
382
348
  if (observer) {
383
349
  observer.next(payload);
384
350
  }
385
351
  else {
386
- logger.debug("observer not found for id: " + id);
352
+ logger.debug(`observer not found for id: ${id}`);
387
353
  }
388
354
  return;
389
355
  }
390
356
  if (type === MESSAGE_TYPES.GQL_START_ACK) {
391
- logger.debug("subscription ready for " + JSON.stringify({ query: query, variables: variables }));
357
+ logger.debug(`subscription ready for ${JSON.stringify({ query, variables })}`);
392
358
  if (typeof subscriptionReadyCallback === 'function') {
393
359
  subscriptionReadyCallback();
394
360
  }
@@ -396,19 +362,19 @@ var AWSAppSyncRealTimeProvider = /** @class */ (function () {
396
362
  clearTimeout(startAckTimeoutId);
397
363
  dispatchApiEvent({
398
364
  event: CONTROL_MSG.SUBSCRIPTION_ACK,
399
- data: { query: query, variables: variables },
365
+ data: { query, variables },
400
366
  message: 'Connection established for subscription',
401
367
  });
402
- var subscriptionState = SUBSCRIPTION_STATUS.CONNECTED;
368
+ const subscriptionState = SUBSCRIPTION_STATUS.CONNECTED;
403
369
  if (observer) {
404
370
  this.subscriptionObserverMap.set(id, {
405
- observer: observer,
406
- query: query,
407
- variables: variables,
371
+ observer,
372
+ query,
373
+ variables,
408
374
  startAckTimeoutId: undefined,
409
- subscriptionState: subscriptionState,
410
- subscriptionReadyCallback: subscriptionReadyCallback,
411
- subscriptionFailedCallback: subscriptionFailedCallback,
375
+ subscriptionState,
376
+ subscriptionReadyCallback,
377
+ subscriptionFailedCallback,
412
378
  });
413
379
  }
414
380
  this.connectionStateMonitor.record(CONNECTION_CHANGE.CONNECTION_ESTABLISHED);
@@ -419,29 +385,31 @@ var AWSAppSyncRealTimeProvider = /** @class */ (function () {
419
385
  clearTimeout(this.keepAliveTimeoutId);
420
386
  if (this.keepAliveAlertTimeoutId)
421
387
  clearTimeout(this.keepAliveAlertTimeoutId);
422
- this.keepAliveTimeoutId = setTimeout(function () { return _this._errorDisconnect(CONTROL_MSG.TIMEOUT_DISCONNECT); }, this.keepAliveTimeout);
423
- this.keepAliveAlertTimeoutId = setTimeout(function () {
424
- _this.connectionStateMonitor.record(CONNECTION_CHANGE.KEEP_ALIVE_MISSED);
388
+ this.keepAliveTimeoutId = setTimeout(() => this._errorDisconnect(CONTROL_MSG.TIMEOUT_DISCONNECT), this.keepAliveTimeout);
389
+ this.keepAliveAlertTimeoutId = setTimeout(() => {
390
+ this.connectionStateMonitor.record(CONNECTION_CHANGE.KEEP_ALIVE_MISSED);
425
391
  }, DEFAULT_KEEP_ALIVE_ALERT_TIMEOUT);
426
392
  this.connectionStateMonitor.record(CONNECTION_CHANGE.KEEP_ALIVE);
427
393
  return;
428
394
  }
429
395
  if (type === MESSAGE_TYPES.GQL_ERROR) {
430
- var subscriptionState = SUBSCRIPTION_STATUS.FAILED;
396
+ const subscriptionState = SUBSCRIPTION_STATUS.FAILED;
431
397
  if (observer) {
432
398
  this.subscriptionObserverMap.set(id, {
433
- observer: observer,
434
- query: query,
435
- variables: variables,
436
- startAckTimeoutId: startAckTimeoutId,
437
- subscriptionReadyCallback: subscriptionReadyCallback,
438
- subscriptionFailedCallback: subscriptionFailedCallback,
439
- subscriptionState: subscriptionState,
399
+ observer,
400
+ query,
401
+ variables,
402
+ startAckTimeoutId,
403
+ subscriptionReadyCallback,
404
+ subscriptionFailedCallback,
405
+ subscriptionState,
440
406
  });
441
- logger.debug(CONTROL_MSG.CONNECTION_FAILED + ": " + JSON.stringify(payload));
407
+ logger.debug(`${CONTROL_MSG.CONNECTION_FAILED}: ${JSON.stringify(payload)}`);
442
408
  observer.error({
443
409
  errors: [
444
- __assign({}, new GraphQLError(CONTROL_MSG.CONNECTION_FAILED + ": " + JSON.stringify(payload))),
410
+ {
411
+ ...new GraphQLError(`${CONTROL_MSG.CONNECTION_FAILED}: ${JSON.stringify(payload)}`),
412
+ },
445
413
  ],
446
414
  });
447
415
  if (startAckTimeoutId)
@@ -451,353 +419,269 @@ var AWSAppSyncRealTimeProvider = /** @class */ (function () {
451
419
  }
452
420
  }
453
421
  }
454
- };
455
- AWSAppSyncRealTimeProvider.prototype._errorDisconnect = function (msg) {
456
- logger.debug("Disconnect error: " + msg);
422
+ }
423
+ _errorDisconnect(msg) {
424
+ logger.debug(`Disconnect error: ${msg}`);
457
425
  if (this.awsRealTimeSocket) {
458
426
  this.connectionStateMonitor.record(CONNECTION_CHANGE.CLOSED);
459
427
  this.awsRealTimeSocket.close();
460
428
  }
461
429
  this.socketStatus = SOCKET_STATUS.CLOSED;
462
- };
463
- AWSAppSyncRealTimeProvider.prototype._timeoutStartSubscriptionAck = function (subscriptionId) {
464
- var subscriptionObserver = this.subscriptionObserverMap.get(subscriptionId);
430
+ }
431
+ _timeoutStartSubscriptionAck(subscriptionId) {
432
+ const subscriptionObserver = this.subscriptionObserverMap.get(subscriptionId);
465
433
  if (subscriptionObserver) {
466
- var observer = subscriptionObserver.observer, query = subscriptionObserver.query, variables = subscriptionObserver.variables;
434
+ const { observer, query, variables } = subscriptionObserver;
467
435
  if (!observer) {
468
436
  return;
469
437
  }
470
438
  this.subscriptionObserverMap.set(subscriptionId, {
471
- observer: observer,
472
- query: query,
473
- variables: variables,
439
+ observer,
440
+ query,
441
+ variables,
474
442
  subscriptionState: SUBSCRIPTION_STATUS.FAILED,
475
443
  });
476
444
  this.connectionStateMonitor.record(CONNECTION_CHANGE.CLOSED);
477
- logger.debug('timeoutStartSubscription', JSON.stringify({ query: query, variables: variables }));
445
+ logger.debug('timeoutStartSubscription', JSON.stringify({ query, variables }));
478
446
  }
479
- };
480
- AWSAppSyncRealTimeProvider.prototype._initializeWebSocketConnection = function (_a) {
481
- var _this = this;
482
- var appSyncGraphqlEndpoint = _a.appSyncGraphqlEndpoint, authenticationType = _a.authenticationType, apiKey = _a.apiKey, region = _a.region, additionalHeaders = _a.additionalHeaders;
447
+ }
448
+ _initializeWebSocketConnection({ appSyncGraphqlEndpoint, authenticationType, apiKey, region, additionalHeaders, }) {
483
449
  if (this.socketStatus === SOCKET_STATUS.READY) {
484
450
  return;
485
451
  }
486
- return new Promise(function (res, rej) { return __awaiter(_this, void 0, void 0, function () {
487
- var payloadString, authHeader, headerString, headerQs, payloadQs, discoverableEndpoint, protocol, awsRealTimeUrl, err_3;
488
- return __generator(this, function (_a) {
489
- switch (_a.label) {
490
- case 0:
491
- this.promiseArray.push({ res: res, rej: rej });
492
- if (!(this.socketStatus === SOCKET_STATUS.CLOSED)) return [3 /*break*/, 5];
493
- _a.label = 1;
494
- case 1:
495
- _a.trys.push([1, 4, , 5]);
496
- this.socketStatus = SOCKET_STATUS.CONNECTING;
497
- payloadString = '{}';
498
- return [4 /*yield*/, this._awsRealTimeHeaderBasedAuth({
499
- authenticationType: authenticationType,
500
- payload: payloadString,
501
- canonicalUri: '/connect',
502
- apiKey: apiKey,
503
- appSyncGraphqlEndpoint: appSyncGraphqlEndpoint,
504
- region: region,
505
- additionalHeaders: additionalHeaders,
506
- })];
507
- case 2:
508
- authHeader = _a.sent();
509
- headerString = authHeader ? JSON.stringify(authHeader) : '';
510
- headerQs = base64Encoder.convert(headerString);
511
- payloadQs = base64Encoder.convert(payloadString);
512
- discoverableEndpoint = appSyncGraphqlEndpoint !== null && appSyncGraphqlEndpoint !== void 0 ? appSyncGraphqlEndpoint : '';
513
- if (this.isCustomDomain(discoverableEndpoint)) {
514
- discoverableEndpoint =
515
- discoverableEndpoint.concat(customDomainPath);
516
- }
517
- else {
518
- discoverableEndpoint = discoverableEndpoint
519
- .replace('appsync-api', 'appsync-realtime-api')
520
- .replace('gogi-beta', 'grt-beta');
521
- }
522
- protocol = 'wss://';
452
+ return new Promise(async (res, rej) => {
453
+ this.promiseArray.push({ res, rej });
454
+ if (this.socketStatus === SOCKET_STATUS.CLOSED) {
455
+ try {
456
+ this.socketStatus = SOCKET_STATUS.CONNECTING;
457
+ const payloadString = '{}';
458
+ const authHeader = await this._awsRealTimeHeaderBasedAuth({
459
+ authenticationType,
460
+ payload: payloadString,
461
+ canonicalUri: '/connect',
462
+ apiKey,
463
+ appSyncGraphqlEndpoint,
464
+ region,
465
+ additionalHeaders,
466
+ });
467
+ const headerString = authHeader ? JSON.stringify(authHeader) : '';
468
+ const headerQs = base64Encoder.convert(headerString);
469
+ const payloadQs = base64Encoder.convert(payloadString);
470
+ let discoverableEndpoint = appSyncGraphqlEndpoint ?? '';
471
+ if (this.isCustomDomain(discoverableEndpoint)) {
472
+ discoverableEndpoint =
473
+ discoverableEndpoint.concat(customDomainPath);
474
+ }
475
+ else {
523
476
  discoverableEndpoint = discoverableEndpoint
524
- .replace('https://', protocol)
525
- .replace('http://', protocol);
526
- awsRealTimeUrl = discoverableEndpoint + "?header=" + headerQs + "&payload=" + payloadQs;
527
- return [4 /*yield*/, this._initializeRetryableHandshake(awsRealTimeUrl)];
528
- case 3:
529
- _a.sent();
530
- this.promiseArray.forEach(function (_a) {
531
- var res = _a.res;
532
- logger.debug('Notifying connection successful');
533
- res();
534
- });
535
- this.socketStatus = SOCKET_STATUS.READY;
536
- this.promiseArray = [];
537
- return [3 /*break*/, 5];
538
- case 4:
539
- err_3 = _a.sent();
540
- logger.debug('Connection exited with', err_3);
541
- this.promiseArray.forEach(function (_a) {
542
- var rej = _a.rej;
543
- return rej(err_3);
544
- });
545
- this.promiseArray = [];
546
- if (this.awsRealTimeSocket &&
547
- this.awsRealTimeSocket.readyState === WebSocket.OPEN) {
548
- this.awsRealTimeSocket.close(3001);
549
- }
550
- this.awsRealTimeSocket = undefined;
551
- this.socketStatus = SOCKET_STATUS.CLOSED;
552
- return [3 /*break*/, 5];
553
- case 5: return [2 /*return*/];
477
+ .replace('appsync-api', 'appsync-realtime-api')
478
+ .replace('gogi-beta', 'grt-beta');
479
+ }
480
+ // Creating websocket url with required query strings
481
+ const protocol = 'wss://';
482
+ discoverableEndpoint = discoverableEndpoint
483
+ .replace('https://', protocol)
484
+ .replace('http://', protocol);
485
+ const awsRealTimeUrl = `${discoverableEndpoint}?header=${headerQs}&payload=${payloadQs}`;
486
+ await this._initializeRetryableHandshake(awsRealTimeUrl);
487
+ this.promiseArray.forEach(({ res }) => {
488
+ logger.debug('Notifying connection successful');
489
+ res();
490
+ });
491
+ this.socketStatus = SOCKET_STATUS.READY;
492
+ this.promiseArray = [];
554
493
  }
555
- });
556
- }); });
557
- };
558
- AWSAppSyncRealTimeProvider.prototype._initializeRetryableHandshake = function (awsRealTimeUrl) {
559
- return __awaiter(this, void 0, void 0, function () {
560
- return __generator(this, function (_a) {
561
- switch (_a.label) {
562
- case 0:
563
- logger.debug("Initializaling retryable Handshake");
564
- return [4 /*yield*/, jitteredExponentialRetry(this._initializeHandshake.bind(this), [awsRealTimeUrl], MAX_DELAY_MS)];
565
- case 1:
566
- _a.sent();
567
- return [2 /*return*/];
494
+ catch (err) {
495
+ logger.debug('Connection exited with', err);
496
+ this.promiseArray.forEach(({ rej }) => rej(err));
497
+ this.promiseArray = [];
498
+ if (this.awsRealTimeSocket &&
499
+ this.awsRealTimeSocket.readyState === WebSocket.OPEN) {
500
+ this.awsRealTimeSocket.close(3001);
501
+ }
502
+ this.awsRealTimeSocket = undefined;
503
+ this.socketStatus = SOCKET_STATUS.CLOSED;
568
504
  }
569
- });
505
+ }
570
506
  });
571
- };
572
- AWSAppSyncRealTimeProvider.prototype._initializeHandshake = function (awsRealTimeUrl) {
573
- return __awaiter(this, void 0, void 0, function () {
574
- var err_4, _a, errorType, errorCode;
575
- var _this = this;
576
- return __generator(this, function (_b) {
577
- switch (_b.label) {
578
- case 0:
579
- logger.debug("Initializing handshake " + awsRealTimeUrl);
580
- _b.label = 1;
581
- case 1:
582
- _b.trys.push([1, 4, , 5]);
583
- return [4 /*yield*/, (function () {
584
- return new Promise(function (res, rej) {
585
- var newSocket = _this.getNewWebSocket(awsRealTimeUrl, 'graphql-ws');
586
- newSocket.onerror = function () {
587
- logger.debug("WebSocket connection error");
588
- };
589
- newSocket.onclose = function () {
590
- rej(new Error('Connection handshake error'));
507
+ }
508
+ async _initializeRetryableHandshake(awsRealTimeUrl) {
509
+ logger.debug(`Initializaling retryable Handshake`);
510
+ await jitteredExponentialRetry(this._initializeHandshake.bind(this), [awsRealTimeUrl], MAX_DELAY_MS);
511
+ }
512
+ async _initializeHandshake(awsRealTimeUrl) {
513
+ logger.debug(`Initializing handshake ${awsRealTimeUrl}`);
514
+ // Because connecting the socket is async, is waiting until connection is open
515
+ // Step 1: connect websocket
516
+ try {
517
+ await (() => {
518
+ return new Promise((res, rej) => {
519
+ const newSocket = this.getNewWebSocket(awsRealTimeUrl, 'graphql-ws');
520
+ newSocket.onerror = () => {
521
+ logger.debug(`WebSocket connection error`);
522
+ };
523
+ newSocket.onclose = () => {
524
+ rej(new Error('Connection handshake error'));
525
+ };
526
+ newSocket.onopen = () => {
527
+ this.awsRealTimeSocket = newSocket;
528
+ return res();
529
+ };
530
+ });
531
+ })();
532
+ // Step 2: wait for ack from AWS AppSyncReaTime after sending init
533
+ await (() => {
534
+ return new Promise((res, rej) => {
535
+ if (this.awsRealTimeSocket) {
536
+ let ackOk = false;
537
+ this.awsRealTimeSocket.onerror = error => {
538
+ logger.debug(`WebSocket error ${JSON.stringify(error)}`);
539
+ };
540
+ this.awsRealTimeSocket.onclose = event => {
541
+ logger.debug(`WebSocket closed ${event.reason}`);
542
+ rej(new Error(JSON.stringify(event)));
543
+ };
544
+ this.awsRealTimeSocket.onmessage = (message) => {
545
+ if (typeof message.data !== 'string') {
546
+ return;
547
+ }
548
+ logger.debug(`subscription message from AWS AppSyncRealTime: ${message.data} `);
549
+ const data = JSON.parse(message.data);
550
+ const { type, payload: { connectionTimeoutMs = DEFAULT_KEEP_ALIVE_TIMEOUT, } = {}, } = data;
551
+ if (type === MESSAGE_TYPES.GQL_CONNECTION_ACK) {
552
+ ackOk = true;
553
+ if (this.awsRealTimeSocket) {
554
+ this.keepAliveTimeout = connectionTimeoutMs;
555
+ this.awsRealTimeSocket.onmessage =
556
+ this._handleIncomingSubscriptionMessage.bind(this);
557
+ this.awsRealTimeSocket.onerror = err => {
558
+ logger.debug(err);
559
+ this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
591
560
  };
592
- newSocket.onopen = function () {
593
- _this.awsRealTimeSocket = newSocket;
594
- return res();
561
+ this.awsRealTimeSocket.onclose = event => {
562
+ logger.debug(`WebSocket closed ${event.reason}`);
563
+ this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
595
564
  };
596
- });
597
- })()];
598
- case 2:
599
- _b.sent();
600
- // Step 2: wait for ack from AWS AppSyncReaTime after sending init
601
- return [4 /*yield*/, (function () {
602
- return new Promise(function (res, rej) {
603
- if (_this.awsRealTimeSocket) {
604
- var ackOk_1 = false;
605
- _this.awsRealTimeSocket.onerror = function (error) {
606
- logger.debug("WebSocket error " + JSON.stringify(error));
607
- };
608
- _this.awsRealTimeSocket.onclose = function (event) {
609
- logger.debug("WebSocket closed " + event.reason);
610
- rej(new Error(JSON.stringify(event)));
611
- };
612
- _this.awsRealTimeSocket.onmessage = function (message) {
613
- if (typeof message.data !== 'string') {
614
- return;
615
- }
616
- logger.debug("subscription message from AWS AppSyncRealTime: " + message.data + " ");
617
- var data = JSON.parse(message.data);
618
- var type = data.type, _a = data.payload, _b = (_a === void 0 ? {} : _a).connectionTimeoutMs, connectionTimeoutMs = _b === void 0 ? DEFAULT_KEEP_ALIVE_TIMEOUT : _b;
619
- if (type === MESSAGE_TYPES.GQL_CONNECTION_ACK) {
620
- ackOk_1 = true;
621
- if (_this.awsRealTimeSocket) {
622
- _this.keepAliveTimeout = connectionTimeoutMs;
623
- _this.awsRealTimeSocket.onmessage =
624
- _this._handleIncomingSubscriptionMessage.bind(_this);
625
- _this.awsRealTimeSocket.onerror = function (err) {
626
- logger.debug(err);
627
- _this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
628
- };
629
- _this.awsRealTimeSocket.onclose = function (event) {
630
- logger.debug("WebSocket closed " + event.reason);
631
- _this._errorDisconnect(CONTROL_MSG.CONNECTION_CLOSED);
632
- };
633
- }
634
- res('Cool, connected to AWS AppSyncRealTime');
635
- return;
636
- }
637
- if (type === MESSAGE_TYPES.GQL_CONNECTION_ERROR) {
638
- var _c = data.payload, _d = (_c === void 0 ? {} : _c).errors, _e = __read(_d === void 0 ? [] : _d, 1), _f = _e[0], _g = _f === void 0 ? {} : _f, _h = _g.errorType, errorType = _h === void 0 ? '' : _h, _j = _g.errorCode, errorCode = _j === void 0 ? 0 : _j;
639
- rej({ errorType: errorType, errorCode: errorCode });
640
- }
641
- };
642
- var gqlInit = {
643
- type: MESSAGE_TYPES.GQL_CONNECTION_INIT,
644
- };
645
- _this.awsRealTimeSocket.send(JSON.stringify(gqlInit));
646
- var checkAckOk_1 = function (ackOk) {
647
- if (!ackOk) {
648
- _this.connectionStateMonitor.record(CONNECTION_CHANGE.CONNECTION_FAILED);
649
- rej(new Error("Connection timeout: ack from AWSAppSyncRealTime was not received after " + CONNECTION_INIT_TIMEOUT + " ms"));
650
- }
651
- };
652
- setTimeout(function () { return checkAckOk_1(ackOk_1); }, CONNECTION_INIT_TIMEOUT);
653
- }
654
- });
655
- })()];
656
- case 3:
657
- // Step 2: wait for ack from AWS AppSyncReaTime after sending init
658
- _b.sent();
659
- return [3 /*break*/, 5];
660
- case 4:
661
- err_4 = _b.sent();
662
- _a = err_4, errorType = _a.errorType, errorCode = _a.errorCode;
663
- if (NON_RETRYABLE_CODES.includes(errorCode)) {
664
- throw new NonRetryableError(errorType);
665
- }
666
- else if (errorType) {
667
- throw new Error(errorType);
668
- }
669
- else {
670
- throw err_4;
671
- }
672
- return [3 /*break*/, 5];
673
- case 5: return [2 /*return*/];
674
- }
675
- });
676
- });
677
- };
678
- AWSAppSyncRealTimeProvider.prototype._awsRealTimeHeaderBasedAuth = function (_a) {
679
- var apiKey = _a.apiKey, authenticationType = _a.authenticationType, payload = _a.payload, canonicalUri = _a.canonicalUri, appSyncGraphqlEndpoint = _a.appSyncGraphqlEndpoint, region = _a.region, additionalHeaders = _a.additionalHeaders;
680
- return __awaiter(this, void 0, void 0, function () {
681
- var headerHandler, handler, host, resolvedApiKey, result;
682
- return __generator(this, function (_b) {
683
- switch (_b.label) {
684
- case 0:
685
- headerHandler = {
686
- apiKey: this._awsRealTimeApiKeyHeader.bind(this),
687
- iam: this._awsRealTimeIAMHeader.bind(this),
688
- oidc: this._awsAuthTokenHeader.bind(this),
689
- userPool: this._awsAuthTokenHeader.bind(this),
690
- lambda: this._customAuthHeader,
691
- none: this._customAuthHeader,
565
+ }
566
+ res('Cool, connected to AWS AppSyncRealTime');
567
+ return;
568
+ }
569
+ if (type === MESSAGE_TYPES.GQL_CONNECTION_ERROR) {
570
+ const { payload: { errors: [{ errorType = '', errorCode = 0 } = {}] = [], } = {}, } = data;
571
+ rej({ errorType, errorCode });
572
+ }
692
573
  };
693
- if (!(!authenticationType || !headerHandler[authenticationType])) return [3 /*break*/, 1];
694
- logger.debug("Authentication type " + authenticationType + " not supported");
695
- return [2 /*return*/, undefined];
696
- case 1:
697
- handler = headerHandler[authenticationType];
698
- host = appSyncGraphqlEndpoint
699
- ? new AmplifyUrl(appSyncGraphqlEndpoint).host
700
- : undefined;
701
- logger.debug("Authenticating with " + JSON.stringify(authenticationType));
702
- resolvedApiKey = void 0;
703
- if (authenticationType === 'apiKey') {
704
- resolvedApiKey = apiKey;
705
- }
706
- return [4 /*yield*/, handler({
707
- payload: payload,
708
- canonicalUri: canonicalUri,
709
- appSyncGraphqlEndpoint: appSyncGraphqlEndpoint,
710
- apiKey: resolvedApiKey,
711
- region: region,
712
- host: host,
713
- additionalHeaders: additionalHeaders,
714
- })];
715
- case 2:
716
- result = _b.sent();
717
- return [2 /*return*/, result];
718
- }
719
- });
720
- });
721
- };
722
- AWSAppSyncRealTimeProvider.prototype._awsAuthTokenHeader = function (_a) {
723
- var host = _a.host;
724
- var _b, _c;
725
- return __awaiter(this, void 0, void 0, function () {
726
- var session;
727
- return __generator(this, function (_d) {
728
- switch (_d.label) {
729
- case 0: return [4 /*yield*/, fetchAuthSession()];
730
- case 1:
731
- session = _d.sent();
732
- return [2 /*return*/, {
733
- Authorization: (_c = (_b = session === null || session === void 0 ? void 0 : session.tokens) === null || _b === void 0 ? void 0 : _b.accessToken) === null || _c === void 0 ? void 0 : _c.toString(),
734
- host: host,
735
- }];
736
- }
737
- });
738
- });
739
- };
740
- AWSAppSyncRealTimeProvider.prototype._awsRealTimeApiKeyHeader = function (_a) {
741
- var apiKey = _a.apiKey, host = _a.host;
742
- return __awaiter(this, void 0, void 0, function () {
743
- var dt, dtStr;
744
- return __generator(this, function (_b) {
745
- dt = new Date();
746
- dtStr = dt.toISOString().replace(/[:\-]|\.\d{3}/g, '');
747
- return [2 /*return*/, {
748
- host: host,
749
- 'x-amz-date': dtStr,
750
- 'x-api-key': apiKey,
751
- }];
752
- });
753
- });
754
- };
755
- AWSAppSyncRealTimeProvider.prototype._awsRealTimeIAMHeader = function (_a) {
756
- var payload = _a.payload, canonicalUri = _a.canonicalUri, appSyncGraphqlEndpoint = _a.appSyncGraphqlEndpoint, region = _a.region;
757
- return __awaiter(this, void 0, void 0, function () {
758
- var endpointInfo, creds, request, signed_params;
759
- return __generator(this, function (_b) {
760
- switch (_b.label) {
761
- case 0:
762
- endpointInfo = {
763
- region: region,
764
- service: 'appsync',
574
+ const gqlInit = {
575
+ type: MESSAGE_TYPES.GQL_CONNECTION_INIT,
765
576
  };
766
- return [4 /*yield*/, fetchAuthSession()];
767
- case 1:
768
- creds = (_b.sent()).credentials;
769
- request = {
770
- url: "" + appSyncGraphqlEndpoint + canonicalUri,
771
- data: payload,
772
- method: 'POST',
773
- headers: __assign({}, AWS_APPSYNC_REALTIME_HEADERS),
577
+ this.awsRealTimeSocket.send(JSON.stringify(gqlInit));
578
+ const checkAckOk = (ackOk) => {
579
+ if (!ackOk) {
580
+ this.connectionStateMonitor.record(CONNECTION_CHANGE.CONNECTION_FAILED);
581
+ rej(new Error(`Connection timeout: ack from AWSAppSyncRealTime was not received after ${CONNECTION_INIT_TIMEOUT} ms`));
582
+ }
774
583
  };
775
- signed_params = signRequest({
776
- headers: request.headers,
777
- method: request.method,
778
- url: new AmplifyUrl(request.url),
779
- body: request.data,
780
- }, {
781
- // TODO: What do we need to do to remove these !'s?
782
- credentials: creds,
783
- signingRegion: endpointInfo.region,
784
- signingService: endpointInfo.service,
785
- });
786
- return [2 /*return*/, signed_params.headers];
787
- }
584
+ setTimeout(() => checkAckOk(ackOk), CONNECTION_INIT_TIMEOUT);
585
+ }
586
+ });
587
+ })();
588
+ }
589
+ catch (err) {
590
+ const { errorType, errorCode } = err;
591
+ if (NON_RETRYABLE_CODES.includes(errorCode)) {
592
+ throw new NonRetryableError(errorType);
593
+ }
594
+ else if (errorType) {
595
+ throw new Error(errorType);
596
+ }
597
+ else {
598
+ throw err;
599
+ }
600
+ }
601
+ }
602
+ async _awsRealTimeHeaderBasedAuth({ apiKey, authenticationType, payload, canonicalUri, appSyncGraphqlEndpoint, region, additionalHeaders, }) {
603
+ const headerHandler = {
604
+ apiKey: this._awsRealTimeApiKeyHeader.bind(this),
605
+ iam: this._awsRealTimeIAMHeader.bind(this),
606
+ oidc: this._awsAuthTokenHeader.bind(this),
607
+ userPool: this._awsAuthTokenHeader.bind(this),
608
+ lambda: this._customAuthHeader,
609
+ none: this._customAuthHeader,
610
+ };
611
+ if (!authenticationType || !headerHandler[authenticationType]) {
612
+ logger.debug(`Authentication type ${authenticationType} not supported`);
613
+ return undefined;
614
+ }
615
+ else {
616
+ const handler = headerHandler[authenticationType];
617
+ const host = appSyncGraphqlEndpoint
618
+ ? new AmplifyUrl(appSyncGraphqlEndpoint).host
619
+ : undefined;
620
+ logger.debug(`Authenticating with ${JSON.stringify(authenticationType)}`);
621
+ let resolvedApiKey;
622
+ if (authenticationType === 'apiKey') {
623
+ resolvedApiKey = apiKey;
624
+ }
625
+ const result = await handler({
626
+ payload,
627
+ canonicalUri,
628
+ appSyncGraphqlEndpoint,
629
+ apiKey: resolvedApiKey,
630
+ region,
631
+ host,
632
+ additionalHeaders,
788
633
  });
634
+ return result;
635
+ }
636
+ }
637
+ async _awsAuthTokenHeader({ host }) {
638
+ const session = await fetchAuthSession();
639
+ return {
640
+ Authorization: session?.tokens?.accessToken?.toString(),
641
+ host,
642
+ };
643
+ }
644
+ async _awsRealTimeApiKeyHeader({ apiKey, host, }) {
645
+ const dt = new Date();
646
+ const dtStr = dt.toISOString().replace(/[:\-]|\.\d{3}/g, '');
647
+ return {
648
+ host,
649
+ 'x-amz-date': dtStr,
650
+ 'x-api-key': apiKey,
651
+ };
652
+ }
653
+ async _awsRealTimeIAMHeader({ payload, canonicalUri, appSyncGraphqlEndpoint, region, }) {
654
+ const endpointInfo = {
655
+ region,
656
+ service: 'appsync',
657
+ };
658
+ const creds = (await fetchAuthSession()).credentials;
659
+ const request = {
660
+ url: `${appSyncGraphqlEndpoint}${canonicalUri}`,
661
+ data: payload,
662
+ method: 'POST',
663
+ headers: { ...AWS_APPSYNC_REALTIME_HEADERS },
664
+ };
665
+ const signed_params = signRequest({
666
+ headers: request.headers,
667
+ method: request.method,
668
+ url: new AmplifyUrl(request.url),
669
+ body: request.data,
670
+ }, {
671
+ // TODO: What do we need to do to remove these !'s?
672
+ credentials: creds,
673
+ signingRegion: endpointInfo.region,
674
+ signingService: endpointInfo.service,
789
675
  });
790
- };
791
- AWSAppSyncRealTimeProvider.prototype._customAuthHeader = function (_a) {
792
- var host = _a.host, additionalHeaders = _a.additionalHeaders;
793
- if (!(additionalHeaders === null || additionalHeaders === void 0 ? void 0 : additionalHeaders['Authorization'])) {
676
+ return signed_params.headers;
677
+ }
678
+ _customAuthHeader({ host, additionalHeaders, }) {
679
+ if (!additionalHeaders?.['Authorization']) {
794
680
  throw new Error('No auth token specified');
795
681
  }
796
682
  return {
797
683
  Authorization: additionalHeaders.Authorization,
798
- host: host,
684
+ host,
799
685
  };
800
- };
801
- return AWSAppSyncRealTimeProvider;
802
- }());
803
- export { AWSAppSyncRealTimeProvider };
686
+ }
687
+ }