aws-appsync-subscription-link 4.0.1 → 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/__tests__/link/realtime-subscription-handshake-link-test.ts +99 -38
- package/lib/index.js +44 -26
- package/lib/index.mjs +44 -26
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
<a name="4.0.2"></a>
|
|
7
|
+
## [4.0.2](https://github.com/awslabs/aws-mobile-appsync-sdk-js/compare/aws-appsync-subscription-link@4.0.1...aws-appsync-subscription-link@4.0.2) (2026-03-19)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Bug Fixes
|
|
11
|
+
|
|
12
|
+
* **subscription-link:** move auth credentials from URL query string to Sec-WebSocket-Protocol header ([fb5dd3e](https://github.com/awslabs/aws-mobile-appsync-sdk-js/commit/fb5dd3e))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
<a name="4.1.0"></a>
|
|
7
18
|
# [4.1.0] (Unreleased)
|
|
8
19
|
|
|
@@ -69,6 +69,20 @@ class myWebSocket implements WebSocket {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Helper to decode a base64url-encoded header from the Sec-WebSocket-Protocol value.
|
|
74
|
+
* The protocol value is prefixed with "header-".
|
|
75
|
+
*/
|
|
76
|
+
function decodeProtocolHeader(protocols: string | string[]): Record<string, string> {
|
|
77
|
+
const arr = Array.isArray(protocols) ? protocols : [protocols];
|
|
78
|
+
const headerProtocol = arr.find(p => p.startsWith("header-"));
|
|
79
|
+
if (!headerProtocol) throw new Error("No header- protocol found");
|
|
80
|
+
const base64url = headerProtocol.slice("header-".length);
|
|
81
|
+
// Convert base64url back to standard base64
|
|
82
|
+
const base64 = base64url.replace(/-/g, "+").replace(/_/g, "/");
|
|
83
|
+
return JSON.parse(Buffer.from(base64, "base64").toString());
|
|
84
|
+
}
|
|
85
|
+
|
|
72
86
|
describe("RealTime subscription link", () => {
|
|
73
87
|
test("Can instantiate link", () => {
|
|
74
88
|
expect.assertions(1);
|
|
@@ -99,7 +113,7 @@ describe("RealTime subscription link", () => {
|
|
|
99
113
|
});
|
|
100
114
|
|
|
101
115
|
test("Initialize WebSocket correctly for API KEY", (done) => {
|
|
102
|
-
expect.assertions(
|
|
116
|
+
expect.assertions(3);
|
|
103
117
|
jest.spyOn(Date.prototype, "toISOString").mockImplementation(
|
|
104
118
|
jest.fn(() => {
|
|
105
119
|
return "2019-11-13T18:47:04.733Z";
|
|
@@ -107,10 +121,14 @@ describe("RealTime subscription link", () => {
|
|
|
107
121
|
);
|
|
108
122
|
AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket = jest.fn(
|
|
109
123
|
(url, protocol) => {
|
|
124
|
+
// URL should be clean — no query string with credentials
|
|
110
125
|
expect(url).toBe(
|
|
111
|
-
"wss://apikeytesturl1234567890123.appsync-realtime-api.us-west-2.amazonaws.com/graphql
|
|
126
|
+
"wss://apikeytesturl1234567890123.appsync-realtime-api.us-west-2.amazonaws.com/graphql"
|
|
112
127
|
);
|
|
113
|
-
|
|
128
|
+
// Protocol should be an array with graphql-ws and header- prefix
|
|
129
|
+
expect(Array.isArray(protocol)).toBe(true);
|
|
130
|
+
const header = decodeProtocolHeader(protocol);
|
|
131
|
+
expect(header["x-api-key"]).toBe("xxxxx");
|
|
114
132
|
done();
|
|
115
133
|
return new myWebSocket();
|
|
116
134
|
}
|
|
@@ -141,7 +159,7 @@ describe("RealTime subscription link", () => {
|
|
|
141
159
|
});
|
|
142
160
|
|
|
143
161
|
test("Initialize WebSocket correctly for API KEY with custom domain", (done) => {
|
|
144
|
-
expect.assertions(
|
|
162
|
+
expect.assertions(3);
|
|
145
163
|
jest.spyOn(Date.prototype, "toISOString").mockImplementation(
|
|
146
164
|
jest.fn(() => {
|
|
147
165
|
return "2019-11-13T18:47:04.733Z";
|
|
@@ -150,9 +168,11 @@ describe("RealTime subscription link", () => {
|
|
|
150
168
|
AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket = jest.fn(
|
|
151
169
|
(url, protocol) => {
|
|
152
170
|
expect(url).toBe(
|
|
153
|
-
"wss://apikeytest.testcustomdomain.com/graphql/realtime
|
|
171
|
+
"wss://apikeytest.testcustomdomain.com/graphql/realtime"
|
|
154
172
|
);
|
|
155
|
-
expect(protocol).toBe(
|
|
173
|
+
expect(Array.isArray(protocol)).toBe(true);
|
|
174
|
+
const header = decodeProtocolHeader(protocol);
|
|
175
|
+
expect(header["x-api-key"]).toBe("xxxxx");
|
|
156
176
|
done();
|
|
157
177
|
return new myWebSocket();
|
|
158
178
|
}
|
|
@@ -183,7 +203,7 @@ describe("RealTime subscription link", () => {
|
|
|
183
203
|
});
|
|
184
204
|
|
|
185
205
|
test("Initialize WebSocket correctly for COGNITO USER POOLS", (done) => {
|
|
186
|
-
expect.assertions(
|
|
206
|
+
expect.assertions(3);
|
|
187
207
|
jest.spyOn(Date.prototype, "toISOString").mockImplementation(
|
|
188
208
|
jest.fn(() => {
|
|
189
209
|
return "2019-11-13T18:47:04.733Z";
|
|
@@ -192,9 +212,11 @@ describe("RealTime subscription link", () => {
|
|
|
192
212
|
AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket = jest.fn(
|
|
193
213
|
(url, protocol) => {
|
|
194
214
|
expect(url).toBe(
|
|
195
|
-
"wss://cognitouserpooltesturl1234.appsync-realtime-api.us-west-2.amazonaws.com/graphql
|
|
215
|
+
"wss://cognitouserpooltesturl1234.appsync-realtime-api.us-west-2.amazonaws.com/graphql"
|
|
196
216
|
);
|
|
197
|
-
expect(protocol).toBe(
|
|
217
|
+
expect(Array.isArray(protocol)).toBe(true);
|
|
218
|
+
const header = decodeProtocolHeader(protocol);
|
|
219
|
+
expect(header["Authorization"]).toBe("token");
|
|
198
220
|
done();
|
|
199
221
|
return new myWebSocket();
|
|
200
222
|
}
|
|
@@ -225,7 +247,7 @@ describe("RealTime subscription link", () => {
|
|
|
225
247
|
});
|
|
226
248
|
|
|
227
249
|
test("Initialize WebSocket correctly for COGNITO USER POOLS with custom domain", (done) => {
|
|
228
|
-
expect.assertions(
|
|
250
|
+
expect.assertions(3);
|
|
229
251
|
jest.spyOn(Date.prototype, "toISOString").mockImplementation(
|
|
230
252
|
jest.fn(() => {
|
|
231
253
|
return "2019-11-13T18:47:04.733Z";
|
|
@@ -234,9 +256,11 @@ describe("RealTime subscription link", () => {
|
|
|
234
256
|
AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket = jest.fn(
|
|
235
257
|
(url, protocol) => {
|
|
236
258
|
expect(url).toBe(
|
|
237
|
-
"wss://cognitouserpools.testcustomdomain.com/graphql/realtime
|
|
259
|
+
"wss://cognitouserpools.testcustomdomain.com/graphql/realtime"
|
|
238
260
|
);
|
|
239
|
-
expect(protocol).toBe(
|
|
261
|
+
expect(Array.isArray(protocol)).toBe(true);
|
|
262
|
+
const header = decodeProtocolHeader(protocol);
|
|
263
|
+
expect(header["Authorization"]).toBe("token");
|
|
240
264
|
done();
|
|
241
265
|
return new myWebSocket();
|
|
242
266
|
}
|
|
@@ -267,7 +291,7 @@ describe("RealTime subscription link", () => {
|
|
|
267
291
|
});
|
|
268
292
|
|
|
269
293
|
test("Initialize WebSocket correctly for OPENID_CONNECT", (done) => {
|
|
270
|
-
expect.assertions(
|
|
294
|
+
expect.assertions(3);
|
|
271
295
|
jest.spyOn(Date.prototype, "toISOString").mockImplementation(
|
|
272
296
|
jest.fn(() => {
|
|
273
297
|
return "2019-11-13T18:47:04.733Z";
|
|
@@ -276,9 +300,11 @@ describe("RealTime subscription link", () => {
|
|
|
276
300
|
AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket = jest.fn(
|
|
277
301
|
(url, protocol) => {
|
|
278
302
|
expect(url).toBe(
|
|
279
|
-
"wss://openidconnecttesturl123456.appsync-realtime-api.us-west-2.amazonaws.com/graphql
|
|
303
|
+
"wss://openidconnecttesturl123456.appsync-realtime-api.us-west-2.amazonaws.com/graphql"
|
|
280
304
|
);
|
|
281
|
-
expect(protocol).toBe(
|
|
305
|
+
expect(Array.isArray(protocol)).toBe(true);
|
|
306
|
+
const header = decodeProtocolHeader(protocol);
|
|
307
|
+
expect(header["Authorization"]).toBe("token");
|
|
282
308
|
done();
|
|
283
309
|
return new myWebSocket();
|
|
284
310
|
}
|
|
@@ -309,7 +335,7 @@ describe("RealTime subscription link", () => {
|
|
|
309
335
|
});
|
|
310
336
|
|
|
311
337
|
test("Initialize WebSocket correctly for OPENID_CONNECT with custom domain", (done) => {
|
|
312
|
-
expect.assertions(
|
|
338
|
+
expect.assertions(3);
|
|
313
339
|
jest.spyOn(Date.prototype, "toISOString").mockImplementation(
|
|
314
340
|
jest.fn(() => {
|
|
315
341
|
return "2019-11-13T18:47:04.733Z";
|
|
@@ -318,9 +344,11 @@ describe("RealTime subscription link", () => {
|
|
|
318
344
|
AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket = jest.fn(
|
|
319
345
|
(url, protocol) => {
|
|
320
346
|
expect(url).toBe(
|
|
321
|
-
"wss://openidconnecttesturl.testcustomdomain.com/graphql/realtime
|
|
347
|
+
"wss://openidconnecttesturl.testcustomdomain.com/graphql/realtime"
|
|
322
348
|
);
|
|
323
|
-
expect(protocol).toBe(
|
|
349
|
+
expect(Array.isArray(protocol)).toBe(true);
|
|
350
|
+
const header = decodeProtocolHeader(protocol);
|
|
351
|
+
expect(header["Authorization"]).toBe("token");
|
|
324
352
|
done();
|
|
325
353
|
return new myWebSocket();
|
|
326
354
|
}
|
|
@@ -351,7 +379,7 @@ describe("RealTime subscription link", () => {
|
|
|
351
379
|
});
|
|
352
380
|
|
|
353
381
|
test("Initialize WebSocket correctly for AWS_LAMBDA", (done) => {
|
|
354
|
-
expect.assertions(
|
|
382
|
+
expect.assertions(3);
|
|
355
383
|
jest.spyOn(Date.prototype, "toISOString").mockImplementation(
|
|
356
384
|
jest.fn(() => {
|
|
357
385
|
return "2019-11-13T18:47:04.733Z";
|
|
@@ -360,9 +388,11 @@ describe("RealTime subscription link", () => {
|
|
|
360
388
|
AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket = jest.fn(
|
|
361
389
|
(url, protocol) => {
|
|
362
390
|
expect(url).toBe(
|
|
363
|
-
"wss://awslambdatesturl1234567890.appsync-realtime-api.us-west-2.amazonaws.com/graphql
|
|
391
|
+
"wss://awslambdatesturl1234567890.appsync-realtime-api.us-west-2.amazonaws.com/graphql"
|
|
364
392
|
);
|
|
365
|
-
expect(protocol).toBe(
|
|
393
|
+
expect(Array.isArray(protocol)).toBe(true);
|
|
394
|
+
const header = decodeProtocolHeader(protocol);
|
|
395
|
+
expect(header["Authorization"]).toBe("token");
|
|
366
396
|
done();
|
|
367
397
|
return new myWebSocket();
|
|
368
398
|
}
|
|
@@ -390,7 +420,7 @@ describe("RealTime subscription link", () => {
|
|
|
390
420
|
});
|
|
391
421
|
|
|
392
422
|
test("Initialize WebSocket correctly for AWS_LAMBDA with custom domain", (done) => {
|
|
393
|
-
expect.assertions(
|
|
423
|
+
expect.assertions(3);
|
|
394
424
|
jest.spyOn(Date.prototype, "toISOString").mockImplementation(
|
|
395
425
|
jest.fn(() => {
|
|
396
426
|
return "2019-11-13T18:47:04.733Z";
|
|
@@ -399,9 +429,11 @@ describe("RealTime subscription link", () => {
|
|
|
399
429
|
AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket = jest.fn(
|
|
400
430
|
(url, protocol) => {
|
|
401
431
|
expect(url).toBe(
|
|
402
|
-
"wss://awslambdatesturl.testcustomdomain.com/graphql/realtime
|
|
432
|
+
"wss://awslambdatesturl.testcustomdomain.com/graphql/realtime"
|
|
403
433
|
);
|
|
404
|
-
expect(protocol).toBe(
|
|
434
|
+
expect(Array.isArray(protocol)).toBe(true);
|
|
435
|
+
const header = decodeProtocolHeader(protocol);
|
|
436
|
+
expect(header["Authorization"]).toBe("token");
|
|
405
437
|
done();
|
|
406
438
|
return new myWebSocket();
|
|
407
439
|
}
|
|
@@ -455,14 +487,11 @@ describe("RealTime subscription link", () => {
|
|
|
455
487
|
AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket = jest.fn(
|
|
456
488
|
(url, protocol) => {
|
|
457
489
|
// WebSocket should connect to the proxy, not directly to AppSync
|
|
458
|
-
|
|
459
|
-
const urlObj = new URL(url);
|
|
460
|
-
expect(urlObj.origin + urlObj.pathname).toBe(
|
|
490
|
+
expect(url).toBe(
|
|
461
491
|
"wss://d111111abcdef8.cloudfront.net/realtime"
|
|
462
492
|
);
|
|
463
|
-
// Decode the header to verify the host is the AppSync endpoint, not CloudFront
|
|
464
|
-
const
|
|
465
|
-
const header = JSON.parse(Buffer.from(headerB64, "base64").toString());
|
|
493
|
+
// Decode the header from the protocol to verify the host is the AppSync endpoint, not CloudFront
|
|
494
|
+
const header = decodeProtocolHeader(protocol);
|
|
466
495
|
expect(header.host).toBe(
|
|
467
496
|
"proxytesturl12345678901234567.appsync-api.us-west-2.amazonaws.com"
|
|
468
497
|
);
|
|
@@ -504,12 +533,10 @@ describe("RealTime subscription link", () => {
|
|
|
504
533
|
);
|
|
505
534
|
AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket = jest.fn(
|
|
506
535
|
(url, protocol) => {
|
|
507
|
-
|
|
508
|
-
expect(urlObj.origin + urlObj.pathname).toBe(
|
|
536
|
+
expect(url).toBe(
|
|
509
537
|
"wss://mycdn.example.com/realtime"
|
|
510
538
|
);
|
|
511
|
-
const
|
|
512
|
-
const header = JSON.parse(Buffer.from(headerB64, "base64").toString());
|
|
539
|
+
const header = decodeProtocolHeader(protocol);
|
|
513
540
|
expect(header.host).toBe(
|
|
514
541
|
"cognitoproxytesturl123456789.appsync-api.us-west-2.amazonaws.com"
|
|
515
542
|
);
|
|
@@ -555,9 +582,9 @@ describe("RealTime subscription link", () => {
|
|
|
555
582
|
AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket = jest.fn(
|
|
556
583
|
(url, protocol) => {
|
|
557
584
|
expect(url).toBe(
|
|
558
|
-
"wss://apikeytest.testcustomdomain.com/graphql/realtime
|
|
585
|
+
"wss://apikeytest.testcustomdomain.com/graphql/realtime"
|
|
559
586
|
);
|
|
560
|
-
expect(protocol).toBe(
|
|
587
|
+
expect(Array.isArray(protocol)).toBe(true);
|
|
561
588
|
const socket = new myWebSocket();
|
|
562
589
|
|
|
563
590
|
setTimeout(() => {
|
|
@@ -638,9 +665,9 @@ describe("RealTime subscription link", () => {
|
|
|
638
665
|
AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket = jest.fn(
|
|
639
666
|
(url, protocol) => {
|
|
640
667
|
expect(url).toBe(
|
|
641
|
-
"wss://apikeytest.testcustomdomain.com/graphql/realtime
|
|
668
|
+
"wss://apikeytest.testcustomdomain.com/graphql/realtime"
|
|
642
669
|
);
|
|
643
|
-
expect(protocol).toBe(
|
|
670
|
+
expect(Array.isArray(protocol)).toBe(true);
|
|
644
671
|
const socket = new myWebSocket();
|
|
645
672
|
|
|
646
673
|
setTimeout(() => {
|
|
@@ -706,4 +733,38 @@ describe("RealTime subscription link", () => {
|
|
|
706
733
|
},
|
|
707
734
|
});
|
|
708
735
|
});
|
|
736
|
+
|
|
737
|
+
test("URL does not contain credentials in query string", (done) => {
|
|
738
|
+
expect.assertions(2);
|
|
739
|
+
jest.spyOn(Date.prototype, "toISOString").mockImplementation(
|
|
740
|
+
jest.fn(() => {
|
|
741
|
+
return "2019-11-13T18:47:04.733Z";
|
|
742
|
+
})
|
|
743
|
+
);
|
|
744
|
+
AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket = jest.fn(
|
|
745
|
+
(url, protocol) => {
|
|
746
|
+
// The URL must not contain any query parameters with auth material
|
|
747
|
+
expect(url.includes("?")).toBe(false);
|
|
748
|
+
// Auth should be in the protocol header instead
|
|
749
|
+
const header = decodeProtocolHeader(protocol);
|
|
750
|
+
expect(header["x-api-key"]).toBe("my-secret-key");
|
|
751
|
+
done();
|
|
752
|
+
return new myWebSocket();
|
|
753
|
+
}
|
|
754
|
+
);
|
|
755
|
+
const link = new AppSyncRealTimeSubscriptionHandshakeLink({
|
|
756
|
+
auth: {
|
|
757
|
+
type: AUTH_TYPE.API_KEY,
|
|
758
|
+
apiKey: "my-secret-key",
|
|
759
|
+
},
|
|
760
|
+
region: "us-west-2",
|
|
761
|
+
url: "https://securitytesturl12345678901.appsync-api.us-west-2.amazonaws.com/graphql",
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
execute(link, { query }, { client: mockClient }).subscribe({
|
|
765
|
+
error: () => { fail; },
|
|
766
|
+
next: () => { done(); },
|
|
767
|
+
complete: () => { done(); },
|
|
768
|
+
});
|
|
769
|
+
});
|
|
709
770
|
});
|
package/lib/index.js
CHANGED
|
@@ -2594,7 +2594,7 @@ function retry(functionToRetry, args, delayFn) {
|
|
|
2594
2594
|
return _ts_generator(this, function(_state) {
|
|
2595
2595
|
switch(_state.label){
|
|
2596
2596
|
case 0:
|
|
2597
|
-
logger2("Attempt #".concat(attempt
|
|
2597
|
+
logger2("Attempt #".concat(attempt));
|
|
2598
2598
|
_state.label = 1;
|
|
2599
2599
|
case 1:
|
|
2600
2600
|
_state.trys.push([
|
|
@@ -2707,6 +2707,12 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(_import_co
|
|
|
2707
2707
|
_this.auth = theAuth;
|
|
2708
2708
|
_this.proxyUrl = proxy === null || proxy === void 0 ? void 0 : proxy.url;
|
|
2709
2709
|
_this.keepAliveTimeout = keepAliveTimeoutMs;
|
|
2710
|
+
if (_this.url && !_this.url.startsWith("https://")) {
|
|
2711
|
+
logger3("WARNING: AppSync endpoint URL is not using HTTPS. Credentials may be sent unencrypted: ".concat(_this.url));
|
|
2712
|
+
}
|
|
2713
|
+
if (_this.proxyUrl && !_this.proxyUrl.startsWith("https://")) {
|
|
2714
|
+
logger3("WARNING: Proxy URL is not using HTTPS. Credentials may be sent unencrypted: ".concat(_this.proxyUrl));
|
|
2715
|
+
}
|
|
2710
2716
|
if (_this.keepAliveTimeout < SERVER_KEEP_ALIVE_TIMEOUT) {
|
|
2711
2717
|
var configName = "keepAliveTimeoutMs";
|
|
2712
2718
|
throw new Error("".concat(configName, " must be greater than or equal to ").concat(SERVER_KEEP_ALIVE_TIMEOUT, " (").concat(_this.keepAliveTimeout, " used)."));
|
|
@@ -3004,7 +3010,7 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(_import_co
|
|
|
3004
3010
|
}
|
|
3005
3011
|
return new Promise(function(res, rej) {
|
|
3006
3012
|
return _async_to_generator(function() {
|
|
3007
|
-
var payloadString,
|
|
3013
|
+
var payloadString, headerObj, headerString, headerBase64url, discoverableEndpoint, protocols, err;
|
|
3008
3014
|
return _ts_generator(this, function(_state) {
|
|
3009
3015
|
switch(_state.label){
|
|
3010
3016
|
case 0:
|
|
@@ -3026,7 +3032,6 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(_import_co
|
|
|
3026
3032
|
]);
|
|
3027
3033
|
this.socketStatus = 2 /* CONNECTING */ ;
|
|
3028
3034
|
payloadString = "{}";
|
|
3029
|
-
_ = JSON.stringify;
|
|
3030
3035
|
return [
|
|
3031
3036
|
4,
|
|
3032
3037
|
this._awsRealTimeHeaderBasedAuth({
|
|
@@ -3042,11 +3047,9 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(_import_co
|
|
|
3042
3047
|
})
|
|
3043
3048
|
];
|
|
3044
3049
|
case 2:
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
headerQs = Buffer.from(headerString).toString("base64");
|
|
3049
|
-
payloadQs = Buffer.from(payloadString).toString("base64");
|
|
3050
|
+
headerObj = _state.sent();
|
|
3051
|
+
headerString = JSON.stringify(headerObj);
|
|
3052
|
+
headerBase64url = Buffer.from(headerString).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
3050
3053
|
if (this.proxyUrl) {
|
|
3051
3054
|
discoverableEndpoint = this.proxyUrl.replace(/\/graphql$/, "").concat(customDomainPath).replace("https://", "wss://").replace("http://", "ws://");
|
|
3052
3055
|
} else if (this.isCustomDomain(appSyncGraphqlEndpoint)) {
|
|
@@ -3056,11 +3059,15 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(_import_co
|
|
|
3056
3059
|
discoverableEndpoint = appSyncGraphqlEndpoint.replace("appsync-api", "appsync-realtime-api").replace("gogi-beta", "grt-beta");
|
|
3057
3060
|
discoverableEndpoint = discoverableEndpoint.replace("https://", "wss://").replace("http://", "ws://");
|
|
3058
3061
|
}
|
|
3059
|
-
|
|
3062
|
+
protocols = [
|
|
3063
|
+
"graphql-ws",
|
|
3064
|
+
"header-".concat(headerBase64url)
|
|
3065
|
+
];
|
|
3060
3066
|
return [
|
|
3061
3067
|
4,
|
|
3062
3068
|
this._initializeRetryableHandshake({
|
|
3063
|
-
awsRealTimeUrl:
|
|
3069
|
+
awsRealTimeUrl: discoverableEndpoint,
|
|
3070
|
+
protocols: protocols
|
|
3064
3071
|
})
|
|
3065
3072
|
];
|
|
3066
3073
|
case 3:
|
|
@@ -3120,11 +3127,7 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(_import_co
|
|
|
3120
3127
|
};
|
|
3121
3128
|
handler = headerHandler[authenticationType];
|
|
3122
3129
|
if (typeof handler !== "function") {
|
|
3123
|
-
|
|
3124
|
-
return [
|
|
3125
|
-
2,
|
|
3126
|
-
{}
|
|
3127
|
-
];
|
|
3130
|
+
throw new NonRetryableError("Authentication type ".concat(authenticationType, " not supported"));
|
|
3128
3131
|
}
|
|
3129
3132
|
host = url.parse(this.url).host;
|
|
3130
3133
|
return [
|
|
@@ -3298,17 +3301,18 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(_import_co
|
|
|
3298
3301
|
key: "_initializeRetryableHandshake",
|
|
3299
3302
|
value: function _initializeRetryableHandshake(_0) {
|
|
3300
3303
|
return _async_to_generator(function(param) {
|
|
3301
|
-
var awsRealTimeUrl;
|
|
3304
|
+
var awsRealTimeUrl, protocols;
|
|
3302
3305
|
return _ts_generator(this, function(_state) {
|
|
3303
3306
|
switch(_state.label){
|
|
3304
3307
|
case 0:
|
|
3305
|
-
awsRealTimeUrl = param.awsRealTimeUrl;
|
|
3308
|
+
awsRealTimeUrl = param.awsRealTimeUrl, protocols = param.protocols;
|
|
3306
3309
|
logger3("Initializaling retryable Handshake");
|
|
3307
3310
|
return [
|
|
3308
3311
|
4,
|
|
3309
3312
|
jitteredExponentialRetry(this._initializeHandshake.bind(this), [
|
|
3310
3313
|
{
|
|
3311
|
-
awsRealTimeUrl: awsRealTimeUrl
|
|
3314
|
+
awsRealTimeUrl: awsRealTimeUrl,
|
|
3315
|
+
protocols: protocols
|
|
3312
3316
|
}
|
|
3313
3317
|
])
|
|
3314
3318
|
];
|
|
@@ -3326,12 +3330,12 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(_import_co
|
|
|
3326
3330
|
key: "_initializeHandshake",
|
|
3327
3331
|
value: function _initializeHandshake(_0) {
|
|
3328
3332
|
return _async_to_generator(function(param) {
|
|
3329
|
-
var _this, awsRealTimeUrl, err, errorType, errorCode;
|
|
3333
|
+
var _this, awsRealTimeUrl, protocols, err, errorType, errorCode;
|
|
3330
3334
|
return _ts_generator(this, function(_state) {
|
|
3331
3335
|
switch(_state.label){
|
|
3332
3336
|
case 0:
|
|
3333
3337
|
_this = this;
|
|
3334
|
-
awsRealTimeUrl = param.awsRealTimeUrl;
|
|
3338
|
+
awsRealTimeUrl = param.awsRealTimeUrl, protocols = param.protocols;
|
|
3335
3339
|
logger3("Initializing handshake ".concat(awsRealTimeUrl));
|
|
3336
3340
|
_state.label = 1;
|
|
3337
3341
|
case 1:
|
|
@@ -3345,7 +3349,7 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(_import_co
|
|
|
3345
3349
|
4,
|
|
3346
3350
|
function() {
|
|
3347
3351
|
return new Promise(function(res, rej) {
|
|
3348
|
-
var newSocket = _AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket(awsRealTimeUrl,
|
|
3352
|
+
var newSocket = _AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket(awsRealTimeUrl, protocols);
|
|
3349
3353
|
newSocket.onerror = function() {
|
|
3350
3354
|
logger3("WebSocket connection error");
|
|
3351
3355
|
};
|
|
@@ -3379,13 +3383,20 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(_import_co
|
|
|
3379
3383
|
rej(new Error(JSON.stringify(event)));
|
|
3380
3384
|
};
|
|
3381
3385
|
_this.awsRealTimeSocket.onmessage = function(message) {
|
|
3382
|
-
|
|
3383
|
-
|
|
3386
|
+
var data;
|
|
3387
|
+
try {
|
|
3388
|
+
data = JSON.parse(message.data);
|
|
3389
|
+
} catch (e) {
|
|
3390
|
+
logger3("Failed to parse WebSocket message");
|
|
3391
|
+
return;
|
|
3392
|
+
}
|
|
3384
3393
|
var type = data.type, tmp = data.payload, _ref = tmp === void 0 ? {} : tmp, _ref_connectionTimeoutMs = _ref.connectionTimeoutMs, connectionTimeoutMs = _ref_connectionTimeoutMs === void 0 ? DEFAULT_KEEP_ALIVE_TIMEOUT : _ref_connectionTimeoutMs;
|
|
3394
|
+
logger3("subscription message from AWS AppSyncRealTime: ".concat(type));
|
|
3385
3395
|
if (type === "connection_ack" /* GQL_CONNECTION_ACK */ ) {
|
|
3386
3396
|
ackOk = true;
|
|
3397
|
+
var validTimeout = typeof connectionTimeoutMs === "number" && connectionTimeoutMs >= SERVER_KEEP_ALIVE_TIMEOUT ? connectionTimeoutMs : DEFAULT_KEEP_ALIVE_TIMEOUT;
|
|
3387
3398
|
var _this_keepAliveTimeout;
|
|
3388
|
-
_this.keepAliveTimeout = (_this_keepAliveTimeout = _this.keepAliveTimeout) !== null && _this_keepAliveTimeout !== void 0 ? _this_keepAliveTimeout :
|
|
3399
|
+
_this.keepAliveTimeout = (_this_keepAliveTimeout = _this.keepAliveTimeout) !== null && _this_keepAliveTimeout !== void 0 ? _this_keepAliveTimeout : validTimeout;
|
|
3389
3400
|
_this.awsRealTimeSocket.onmessage = _this._handleIncomingSubscriptionMessage.bind(_this);
|
|
3390
3401
|
_this.awsRealTimeSocket.onerror = function(err) {
|
|
3391
3402
|
logger3(err);
|
|
@@ -3446,8 +3457,15 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(_import_co
|
|
|
3446
3457
|
{
|
|
3447
3458
|
key: "_handleIncomingSubscriptionMessage",
|
|
3448
3459
|
value: function _handleIncomingSubscriptionMessage(message) {
|
|
3449
|
-
|
|
3450
|
-
|
|
3460
|
+
var parsed;
|
|
3461
|
+
try {
|
|
3462
|
+
parsed = JSON.parse(message.data);
|
|
3463
|
+
} catch (e) {
|
|
3464
|
+
logger3("Failed to parse incoming subscription message");
|
|
3465
|
+
return;
|
|
3466
|
+
}
|
|
3467
|
+
var _parsed_id = parsed.id, id = _parsed_id === void 0 ? "" : _parsed_id, payload = parsed.payload, type = parsed.type;
|
|
3468
|
+
logger3("subscription message from AWS AppSync RealTime: ".concat(type, " id: ").concat(id));
|
|
3451
3469
|
var _ref = this.subscriptionObserverMap.get(id) || {}, _ref_observer = _ref.observer, observer = _ref_observer === void 0 ? null : _ref_observer, _ref_query = _ref.query, query = _ref_query === void 0 ? "" : _ref_query, _ref_variables = _ref.variables, variables = _ref_variables === void 0 ? {} : _ref_variables, _ref_startAckTimeoutId = _ref.startAckTimeoutId, startAckTimeoutId = _ref_startAckTimeoutId === void 0 ? 0 : _ref_startAckTimeoutId, _ref_subscriptionReadyCallback = _ref.subscriptionReadyCallback, subscriptionReadyCallback = _ref_subscriptionReadyCallback === void 0 ? null : _ref_subscriptionReadyCallback, _ref_subscriptionFailedCallback = _ref.subscriptionFailedCallback, subscriptionFailedCallback = _ref_subscriptionFailedCallback === void 0 ? null : _ref_subscriptionFailedCallback;
|
|
3452
3470
|
logger3({
|
|
3453
3471
|
id: id,
|
package/lib/index.mjs
CHANGED
|
@@ -2571,7 +2571,7 @@ function retry(functionToRetry, args, delayFn) {
|
|
|
2571
2571
|
return _ts_generator(this, function(_state) {
|
|
2572
2572
|
switch(_state.label){
|
|
2573
2573
|
case 0:
|
|
2574
|
-
logger2("Attempt #".concat(attempt
|
|
2574
|
+
logger2("Attempt #".concat(attempt));
|
|
2575
2575
|
_state.label = 1;
|
|
2576
2576
|
case 1:
|
|
2577
2577
|
_state.trys.push([
|
|
@@ -2684,6 +2684,12 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(ApolloLink
|
|
|
2684
2684
|
_this.auth = theAuth;
|
|
2685
2685
|
_this.proxyUrl = proxy === null || proxy === void 0 ? void 0 : proxy.url;
|
|
2686
2686
|
_this.keepAliveTimeout = keepAliveTimeoutMs;
|
|
2687
|
+
if (_this.url && !_this.url.startsWith("https://")) {
|
|
2688
|
+
logger3("WARNING: AppSync endpoint URL is not using HTTPS. Credentials may be sent unencrypted: ".concat(_this.url));
|
|
2689
|
+
}
|
|
2690
|
+
if (_this.proxyUrl && !_this.proxyUrl.startsWith("https://")) {
|
|
2691
|
+
logger3("WARNING: Proxy URL is not using HTTPS. Credentials may be sent unencrypted: ".concat(_this.proxyUrl));
|
|
2692
|
+
}
|
|
2687
2693
|
if (_this.keepAliveTimeout < SERVER_KEEP_ALIVE_TIMEOUT) {
|
|
2688
2694
|
var configName = "keepAliveTimeoutMs";
|
|
2689
2695
|
throw new Error("".concat(configName, " must be greater than or equal to ").concat(SERVER_KEEP_ALIVE_TIMEOUT, " (").concat(_this.keepAliveTimeout, " used)."));
|
|
@@ -2981,7 +2987,7 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(ApolloLink
|
|
|
2981
2987
|
}
|
|
2982
2988
|
return new Promise(function(res, rej) {
|
|
2983
2989
|
return _async_to_generator(function() {
|
|
2984
|
-
var payloadString,
|
|
2990
|
+
var payloadString, headerObj, headerString, headerBase64url, discoverableEndpoint, protocols, err;
|
|
2985
2991
|
return _ts_generator(this, function(_state) {
|
|
2986
2992
|
switch(_state.label){
|
|
2987
2993
|
case 0:
|
|
@@ -3003,7 +3009,6 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(ApolloLink
|
|
|
3003
3009
|
]);
|
|
3004
3010
|
this.socketStatus = 2 /* CONNECTING */ ;
|
|
3005
3011
|
payloadString = "{}";
|
|
3006
|
-
_ = JSON.stringify;
|
|
3007
3012
|
return [
|
|
3008
3013
|
4,
|
|
3009
3014
|
this._awsRealTimeHeaderBasedAuth({
|
|
@@ -3019,11 +3024,9 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(ApolloLink
|
|
|
3019
3024
|
})
|
|
3020
3025
|
];
|
|
3021
3026
|
case 2:
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
headerQs = Buffer.from(headerString).toString("base64");
|
|
3026
|
-
payloadQs = Buffer.from(payloadString).toString("base64");
|
|
3027
|
+
headerObj = _state.sent();
|
|
3028
|
+
headerString = JSON.stringify(headerObj);
|
|
3029
|
+
headerBase64url = Buffer.from(headerString).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
3027
3030
|
if (this.proxyUrl) {
|
|
3028
3031
|
discoverableEndpoint = this.proxyUrl.replace(/\/graphql$/, "").concat(customDomainPath).replace("https://", "wss://").replace("http://", "ws://");
|
|
3029
3032
|
} else if (this.isCustomDomain(appSyncGraphqlEndpoint)) {
|
|
@@ -3033,11 +3036,15 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(ApolloLink
|
|
|
3033
3036
|
discoverableEndpoint = appSyncGraphqlEndpoint.replace("appsync-api", "appsync-realtime-api").replace("gogi-beta", "grt-beta");
|
|
3034
3037
|
discoverableEndpoint = discoverableEndpoint.replace("https://", "wss://").replace("http://", "ws://");
|
|
3035
3038
|
}
|
|
3036
|
-
|
|
3039
|
+
protocols = [
|
|
3040
|
+
"graphql-ws",
|
|
3041
|
+
"header-".concat(headerBase64url)
|
|
3042
|
+
];
|
|
3037
3043
|
return [
|
|
3038
3044
|
4,
|
|
3039
3045
|
this._initializeRetryableHandshake({
|
|
3040
|
-
awsRealTimeUrl:
|
|
3046
|
+
awsRealTimeUrl: discoverableEndpoint,
|
|
3047
|
+
protocols: protocols
|
|
3041
3048
|
})
|
|
3042
3049
|
];
|
|
3043
3050
|
case 3:
|
|
@@ -3097,11 +3104,7 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(ApolloLink
|
|
|
3097
3104
|
};
|
|
3098
3105
|
handler = headerHandler[authenticationType];
|
|
3099
3106
|
if (typeof handler !== "function") {
|
|
3100
|
-
|
|
3101
|
-
return [
|
|
3102
|
-
2,
|
|
3103
|
-
{}
|
|
3104
|
-
];
|
|
3107
|
+
throw new NonRetryableError("Authentication type ".concat(authenticationType, " not supported"));
|
|
3105
3108
|
}
|
|
3106
3109
|
host = url.parse(this.url).host;
|
|
3107
3110
|
return [
|
|
@@ -3275,17 +3278,18 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(ApolloLink
|
|
|
3275
3278
|
key: "_initializeRetryableHandshake",
|
|
3276
3279
|
value: function _initializeRetryableHandshake(_0) {
|
|
3277
3280
|
return _async_to_generator(function(param) {
|
|
3278
|
-
var awsRealTimeUrl;
|
|
3281
|
+
var awsRealTimeUrl, protocols;
|
|
3279
3282
|
return _ts_generator(this, function(_state) {
|
|
3280
3283
|
switch(_state.label){
|
|
3281
3284
|
case 0:
|
|
3282
|
-
awsRealTimeUrl = param.awsRealTimeUrl;
|
|
3285
|
+
awsRealTimeUrl = param.awsRealTimeUrl, protocols = param.protocols;
|
|
3283
3286
|
logger3("Initializaling retryable Handshake");
|
|
3284
3287
|
return [
|
|
3285
3288
|
4,
|
|
3286
3289
|
jitteredExponentialRetry(this._initializeHandshake.bind(this), [
|
|
3287
3290
|
{
|
|
3288
|
-
awsRealTimeUrl: awsRealTimeUrl
|
|
3291
|
+
awsRealTimeUrl: awsRealTimeUrl,
|
|
3292
|
+
protocols: protocols
|
|
3289
3293
|
}
|
|
3290
3294
|
])
|
|
3291
3295
|
];
|
|
@@ -3303,12 +3307,12 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(ApolloLink
|
|
|
3303
3307
|
key: "_initializeHandshake",
|
|
3304
3308
|
value: function _initializeHandshake(_0) {
|
|
3305
3309
|
return _async_to_generator(function(param) {
|
|
3306
|
-
var _this, awsRealTimeUrl, err, errorType, errorCode;
|
|
3310
|
+
var _this, awsRealTimeUrl, protocols, err, errorType, errorCode;
|
|
3307
3311
|
return _ts_generator(this, function(_state) {
|
|
3308
3312
|
switch(_state.label){
|
|
3309
3313
|
case 0:
|
|
3310
3314
|
_this = this;
|
|
3311
|
-
awsRealTimeUrl = param.awsRealTimeUrl;
|
|
3315
|
+
awsRealTimeUrl = param.awsRealTimeUrl, protocols = param.protocols;
|
|
3312
3316
|
logger3("Initializing handshake ".concat(awsRealTimeUrl));
|
|
3313
3317
|
_state.label = 1;
|
|
3314
3318
|
case 1:
|
|
@@ -3322,7 +3326,7 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(ApolloLink
|
|
|
3322
3326
|
4,
|
|
3323
3327
|
function() {
|
|
3324
3328
|
return new Promise(function(res, rej) {
|
|
3325
|
-
var newSocket = _AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket(awsRealTimeUrl,
|
|
3329
|
+
var newSocket = _AppSyncRealTimeSubscriptionHandshakeLink.createWebSocket(awsRealTimeUrl, protocols);
|
|
3326
3330
|
newSocket.onerror = function() {
|
|
3327
3331
|
logger3("WebSocket connection error");
|
|
3328
3332
|
};
|
|
@@ -3356,13 +3360,20 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(ApolloLink
|
|
|
3356
3360
|
rej(new Error(JSON.stringify(event)));
|
|
3357
3361
|
};
|
|
3358
3362
|
_this.awsRealTimeSocket.onmessage = function(message) {
|
|
3359
|
-
|
|
3360
|
-
|
|
3363
|
+
var data;
|
|
3364
|
+
try {
|
|
3365
|
+
data = JSON.parse(message.data);
|
|
3366
|
+
} catch (e) {
|
|
3367
|
+
logger3("Failed to parse WebSocket message");
|
|
3368
|
+
return;
|
|
3369
|
+
}
|
|
3361
3370
|
var type = data.type, tmp = data.payload, _ref = tmp === void 0 ? {} : tmp, _ref_connectionTimeoutMs = _ref.connectionTimeoutMs, connectionTimeoutMs = _ref_connectionTimeoutMs === void 0 ? DEFAULT_KEEP_ALIVE_TIMEOUT : _ref_connectionTimeoutMs;
|
|
3371
|
+
logger3("subscription message from AWS AppSyncRealTime: ".concat(type));
|
|
3362
3372
|
if (type === "connection_ack" /* GQL_CONNECTION_ACK */ ) {
|
|
3363
3373
|
ackOk = true;
|
|
3374
|
+
var validTimeout = typeof connectionTimeoutMs === "number" && connectionTimeoutMs >= SERVER_KEEP_ALIVE_TIMEOUT ? connectionTimeoutMs : DEFAULT_KEEP_ALIVE_TIMEOUT;
|
|
3364
3375
|
var _this_keepAliveTimeout;
|
|
3365
|
-
_this.keepAliveTimeout = (_this_keepAliveTimeout = _this.keepAliveTimeout) !== null && _this_keepAliveTimeout !== void 0 ? _this_keepAliveTimeout :
|
|
3376
|
+
_this.keepAliveTimeout = (_this_keepAliveTimeout = _this.keepAliveTimeout) !== null && _this_keepAliveTimeout !== void 0 ? _this_keepAliveTimeout : validTimeout;
|
|
3366
3377
|
_this.awsRealTimeSocket.onmessage = _this._handleIncomingSubscriptionMessage.bind(_this);
|
|
3367
3378
|
_this.awsRealTimeSocket.onerror = function(err) {
|
|
3368
3379
|
logger3(err);
|
|
@@ -3423,8 +3434,15 @@ var AppSyncRealTimeSubscriptionHandshakeLink = /*#__PURE__*/ function(ApolloLink
|
|
|
3423
3434
|
{
|
|
3424
3435
|
key: "_handleIncomingSubscriptionMessage",
|
|
3425
3436
|
value: function _handleIncomingSubscriptionMessage(message) {
|
|
3426
|
-
|
|
3427
|
-
|
|
3437
|
+
var parsed;
|
|
3438
|
+
try {
|
|
3439
|
+
parsed = JSON.parse(message.data);
|
|
3440
|
+
} catch (e) {
|
|
3441
|
+
logger3("Failed to parse incoming subscription message");
|
|
3442
|
+
return;
|
|
3443
|
+
}
|
|
3444
|
+
var _parsed_id = parsed.id, id = _parsed_id === void 0 ? "" : _parsed_id, payload = parsed.payload, type = parsed.type;
|
|
3445
|
+
logger3("subscription message from AWS AppSync RealTime: ".concat(type, " id: ").concat(id));
|
|
3428
3446
|
var _ref = this.subscriptionObserverMap.get(id) || {}, _ref_observer = _ref.observer, observer = _ref_observer === void 0 ? null : _ref_observer, _ref_query = _ref.query, query = _ref_query === void 0 ? "" : _ref_query, _ref_variables = _ref.variables, variables = _ref_variables === void 0 ? {} : _ref_variables, _ref_startAckTimeoutId = _ref.startAckTimeoutId, startAckTimeoutId = _ref_startAckTimeoutId === void 0 ? 0 : _ref_startAckTimeoutId, _ref_subscriptionReadyCallback = _ref.subscriptionReadyCallback, subscriptionReadyCallback = _ref_subscriptionReadyCallback === void 0 ? null : _ref_subscriptionReadyCallback, _ref_subscriptionFailedCallback = _ref.subscriptionFailedCallback, subscriptionFailedCallback = _ref_subscriptionFailedCallback === void 0 ? null : _ref_subscriptionFailedCallback;
|
|
3429
3447
|
logger3({
|
|
3430
3448
|
id: id,
|