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