@aws-amplify/api-graphql 4.7.8 → 4.7.9-unstable.e10bf3b.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.
- package/dist/cjs/Providers/AWSAppSyncEventsProvider/index.js +22 -17
- package/dist/cjs/Providers/AWSAppSyncEventsProvider/index.js.map +1 -1
- package/dist/cjs/Providers/AWSWebSocketProvider/index.js +28 -7
- package/dist/cjs/Providers/AWSWebSocketProvider/index.js.map +1 -1
- package/dist/cjs/internals/events/index.js +35 -9
- package/dist/cjs/internals/events/index.js.map +1 -1
- package/dist/cjs/internals/events/utils.js +1 -1
- package/dist/cjs/internals/events/utils.js.map +1 -1
- package/dist/esm/Providers/AWSAppSyncEventsProvider/index.d.ts +1 -0
- package/dist/esm/Providers/AWSAppSyncEventsProvider/index.mjs +22 -17
- package/dist/esm/Providers/AWSAppSyncEventsProvider/index.mjs.map +1 -1
- package/dist/esm/Providers/AWSWebSocketProvider/index.d.ts +2 -1
- package/dist/esm/Providers/AWSWebSocketProvider/index.mjs +28 -7
- package/dist/esm/Providers/AWSWebSocketProvider/index.mjs.map +1 -1
- package/dist/esm/internals/events/index.mjs +28 -2
- package/dist/esm/internals/events/index.mjs.map +1 -1
- package/dist/esm/internals/events/types.d.ts +24 -1
- package/dist/esm/internals/events/utils.d.ts +1 -1
- package/dist/esm/internals/events/utils.mjs +1 -1
- package/dist/esm/internals/events/utils.mjs.map +1 -1
- package/package.json +4 -4
- package/src/Providers/AWSAppSyncEventsProvider/index.ts +24 -17
- package/src/Providers/AWSWebSocketProvider/index.ts +34 -10
- package/src/internals/events/index.ts +22 -5
- package/src/internals/events/types.ts +27 -1
- package/src/internals/events/utils.ts +1 -1
|
@@ -27,7 +27,7 @@ const configure = () => {
|
|
|
27
27
|
return options;
|
|
28
28
|
};
|
|
29
29
|
/**
|
|
30
|
-
* Event API expects
|
|
30
|
+
* Event API expects an array of JSON strings
|
|
31
31
|
*
|
|
32
32
|
* @param events - JSON-serializable value or an array of values
|
|
33
33
|
* @returns array of JSON strings
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.mjs","sources":["../../../../src/internals/events/utils.ts"],"sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport { Amplify } from '@aws-amplify/core';\nexport const normalizeAuth = (explicitAuthMode, defaultAuthMode) => {\n if (!explicitAuthMode) {\n return defaultAuthMode;\n }\n if (explicitAuthMode === 'identityPool') {\n return 'iam';\n }\n return explicitAuthMode;\n};\nexport const configure = () => {\n const config = Amplify.getConfig();\n const eventsConfig = config.API?.Events;\n if (!eventsConfig) {\n throw new Error('Amplify configuration is missing. Have you called Amplify.configure()?');\n }\n const configAuthMode = normalizeAuth(eventsConfig.defaultAuthMode, 'apiKey');\n const options = {\n appSyncGraphqlEndpoint: eventsConfig.endpoint,\n region: eventsConfig.region,\n authenticationType: configAuthMode,\n apiKey: eventsConfig.apiKey,\n };\n return options;\n};\n/**\n * Event API expects
|
|
1
|
+
{"version":3,"file":"utils.mjs","sources":["../../../../src/internals/events/utils.ts"],"sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport { Amplify } from '@aws-amplify/core';\nexport const normalizeAuth = (explicitAuthMode, defaultAuthMode) => {\n if (!explicitAuthMode) {\n return defaultAuthMode;\n }\n if (explicitAuthMode === 'identityPool') {\n return 'iam';\n }\n return explicitAuthMode;\n};\nexport const configure = () => {\n const config = Amplify.getConfig();\n const eventsConfig = config.API?.Events;\n if (!eventsConfig) {\n throw new Error('Amplify configuration is missing. Have you called Amplify.configure()?');\n }\n const configAuthMode = normalizeAuth(eventsConfig.defaultAuthMode, 'apiKey');\n const options = {\n appSyncGraphqlEndpoint: eventsConfig.endpoint,\n region: eventsConfig.region,\n authenticationType: configAuthMode,\n apiKey: eventsConfig.apiKey,\n };\n return options;\n};\n/**\n * Event API expects an array of JSON strings\n *\n * @param events - JSON-serializable value or an array of values\n * @returns array of JSON strings\n */\nexport const serializeEvents = (events) => {\n if (Array.isArray(events)) {\n return events.map((ev, idx) => {\n const eventJson = JSON.stringify(ev);\n if (eventJson === undefined) {\n throw new Error(`Event must be a valid JSON value. Received ${ev} at index ${idx}`);\n }\n return eventJson;\n });\n }\n const eventJson = JSON.stringify(events);\n if (eventJson === undefined) {\n throw new Error(`Event must be a valid JSON value. Received ${events}`);\n }\n return [eventJson];\n};\n"],"names":[],"mappings":";;AAAA;AACA;AAEY,MAAC,aAAa,GAAG,CAAC,gBAAgB,EAAE,eAAe,KAAK;AACpE,IAAI,IAAI,CAAC,gBAAgB,EAAE;AAC3B,QAAQ,OAAO,eAAe,CAAC;AAC/B,KAAK;AACL,IAAI,IAAI,gBAAgB,KAAK,cAAc,EAAE;AAC7C,QAAQ,OAAO,KAAK,CAAC;AACrB,KAAK;AACL,IAAI,OAAO,gBAAgB,CAAC;AAC5B,EAAE;AACU,MAAC,SAAS,GAAG,MAAM;AAC/B,IAAI,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;AACvC,IAAI,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC;AAC5C,IAAI,IAAI,CAAC,YAAY,EAAE;AACvB,QAAQ,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;AAClG,KAAK;AACL,IAAI,MAAM,cAAc,GAAG,aAAa,CAAC,YAAY,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;AACjF,IAAI,MAAM,OAAO,GAAG;AACpB,QAAQ,sBAAsB,EAAE,YAAY,CAAC,QAAQ;AACrD,QAAQ,MAAM,EAAE,YAAY,CAAC,MAAM;AACnC,QAAQ,kBAAkB,EAAE,cAAc;AAC1C,QAAQ,MAAM,EAAE,YAAY,CAAC,MAAM;AACnC,KAAK,CAAC;AACN,IAAI,OAAO,OAAO,CAAC;AACnB,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACY,MAAC,eAAe,GAAG,CAAC,MAAM,KAAK;AAC3C,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AAC/B,QAAQ,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,KAAK;AACvC,YAAY,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;AACjD,YAAY,IAAI,SAAS,KAAK,SAAS,EAAE;AACzC,gBAAgB,MAAM,IAAI,KAAK,CAAC,CAAC,2CAA2C,EAAE,EAAE,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;AACpG,aAAa;AACb,YAAY,OAAO,SAAS,CAAC;AAC7B,SAAS,CAAC,CAAC;AACX,KAAK;AACL,IAAI,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AAC7C,IAAI,IAAI,SAAS,KAAK,SAAS,EAAE;AACjC,QAAQ,MAAM,IAAI,KAAK,CAAC,CAAC,2CAA2C,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AAChF,KAAK;AACL,IAAI,OAAO,CAAC,SAAS,CAAC,CAAC;AACvB;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aws-amplify/api-graphql",
|
|
3
|
-
"version": "4.7.
|
|
3
|
+
"version": "4.7.9-unstable.e10bf3b.0+e10bf3b",
|
|
4
4
|
"description": "Api-graphql category of aws-amplify",
|
|
5
5
|
"main": "./dist/cjs/index.js",
|
|
6
6
|
"module": "./dist/esm/index.mjs",
|
|
@@ -84,8 +84,8 @@
|
|
|
84
84
|
"server"
|
|
85
85
|
],
|
|
86
86
|
"dependencies": {
|
|
87
|
-
"@aws-amplify/api-rest": "4.0.
|
|
88
|
-
"@aws-amplify/core": "6.10.
|
|
87
|
+
"@aws-amplify/api-rest": "4.0.74-unstable.e10bf3b.0+e10bf3b",
|
|
88
|
+
"@aws-amplify/core": "6.10.5-unstable.e10bf3b.0+e10bf3b",
|
|
89
89
|
"@aws-amplify/data-schema": "^1.7.0",
|
|
90
90
|
"@aws-sdk/types": "3.387.0",
|
|
91
91
|
"graphql": "15.8.0",
|
|
@@ -101,5 +101,5 @@
|
|
|
101
101
|
"limit": "91.7 kB"
|
|
102
102
|
}
|
|
103
103
|
],
|
|
104
|
-
"gitHead": "
|
|
104
|
+
"gitHead": "e10bf3bc880879a40d5711e0aa6c51d7c3410c5d"
|
|
105
105
|
}
|
|
@@ -12,6 +12,7 @@ import { CustomHeaders } from '@aws-amplify/data-schema/runtime';
|
|
|
12
12
|
import { DEFAULT_KEEP_ALIVE_TIMEOUT, MESSAGE_TYPES } from '../constants';
|
|
13
13
|
import { AWSWebSocketProvider } from '../AWSWebSocketProvider';
|
|
14
14
|
import { awsRealTimeHeaderBasedAuth } from '../AWSWebSocketProvider/authHeaders';
|
|
15
|
+
import { serializeEvents } from '../../internals/events/utils';
|
|
15
16
|
|
|
16
17
|
// resolved/actual AuthMode values. identityPool gets resolves to IAM upstream in InternalGraphQLAPI._graphqlSubscribe
|
|
17
18
|
type ResolvedGraphQLAuthModes = Exclude<GraphQLAuthMode, 'identityPool'>;
|
|
@@ -52,6 +53,7 @@ export class AWSAppSyncEventProvider extends AWSWebSocketProvider {
|
|
|
52
53
|
wsProtocolName: WS_PROTOCOL_NAME,
|
|
53
54
|
connectUri: CONNECT_URI,
|
|
54
55
|
});
|
|
56
|
+
this.allowNoSubscriptions = true;
|
|
55
57
|
}
|
|
56
58
|
|
|
57
59
|
getProviderName() {
|
|
@@ -73,7 +75,11 @@ export class AWSAppSyncEventProvider extends AWSWebSocketProvider {
|
|
|
73
75
|
options: AWSAppSyncEventProviderOptions,
|
|
74
76
|
customUserAgentDetails?: CustomUserAgentDetails,
|
|
75
77
|
) {
|
|
76
|
-
super.publish(options, customUserAgentDetails);
|
|
78
|
+
return super.publish(options, customUserAgentDetails);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public closeIfNoActiveSubscription() {
|
|
82
|
+
this._closeSocketIfRequired();
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
protected async _prepareSubscriptionPayload({
|
|
@@ -97,14 +103,14 @@ export class AWSAppSyncEventProvider extends AWSWebSocketProvider {
|
|
|
97
103
|
query,
|
|
98
104
|
apiKey,
|
|
99
105
|
region,
|
|
106
|
+
variables,
|
|
100
107
|
} = options;
|
|
101
108
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const serializedData = JSON.stringify({ channel: query });
|
|
109
|
+
const data = {
|
|
110
|
+
channel: query,
|
|
111
|
+
events: variables !== undefined ? serializeEvents(variables) : undefined,
|
|
112
|
+
};
|
|
113
|
+
const serializedData = JSON.stringify(data);
|
|
108
114
|
|
|
109
115
|
const headers = {
|
|
110
116
|
...(await awsRealTimeHeaderBasedAuth({
|
|
@@ -121,22 +127,23 @@ export class AWSAppSyncEventProvider extends AWSWebSocketProvider {
|
|
|
121
127
|
[USER_AGENT_HEADER]: getAmplifyUserAgent(customUserAgentDetails),
|
|
122
128
|
};
|
|
123
129
|
|
|
124
|
-
// Commented out code will be needed for WS publish
|
|
125
130
|
const subscriptionMessage = {
|
|
126
131
|
id: subscriptionId,
|
|
127
132
|
channel: query,
|
|
128
|
-
|
|
133
|
+
events: variables !== undefined ? serializeEvents(variables) : undefined,
|
|
129
134
|
authorization: {
|
|
130
135
|
...headers,
|
|
131
136
|
},
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
137
|
+
payload: {
|
|
138
|
+
events:
|
|
139
|
+
variables !== undefined ? serializeEvents(variables) : undefined,
|
|
140
|
+
channel: query,
|
|
141
|
+
extensions: {
|
|
142
|
+
authorization: {
|
|
143
|
+
...headers,
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
},
|
|
140
147
|
type: publish
|
|
141
148
|
? MESSAGE_TYPES.EVENT_PUBLISH
|
|
142
149
|
: MESSAGE_TYPES.EVENT_SUBSCRIBE,
|
|
@@ -80,6 +80,7 @@ interface AWSWebSocketProviderArgs {
|
|
|
80
80
|
export abstract class AWSWebSocketProvider {
|
|
81
81
|
protected logger: ConsoleLogger;
|
|
82
82
|
protected subscriptionObserverMap = new Map<string, ObserverQuery>();
|
|
83
|
+
protected allowNoSubscriptions = false;
|
|
83
84
|
|
|
84
85
|
protected awsRealTimeSocket?: WebSocket;
|
|
85
86
|
private socketStatus: SOCKET_STATUS = SOCKET_STATUS.CLOSED;
|
|
@@ -263,22 +264,43 @@ export abstract class AWSWebSocketProvider {
|
|
|
263
264
|
'message',
|
|
264
265
|
publishListener,
|
|
265
266
|
);
|
|
266
|
-
|
|
267
|
+
cleanup();
|
|
267
268
|
resolve();
|
|
268
269
|
}
|
|
269
270
|
|
|
270
|
-
if (data.
|
|
271
|
-
|
|
271
|
+
if (data.errors && data.errors.length > 0) {
|
|
272
|
+
const errorTypes = data.errors.map((error: any) => error.errorType);
|
|
273
|
+
cleanup();
|
|
274
|
+
reject(new Error(`Publish errors: ${errorTypes.join(', ')}`));
|
|
272
275
|
}
|
|
273
276
|
};
|
|
274
|
-
|
|
275
|
-
|
|
277
|
+
|
|
278
|
+
const errorListener = (error: Event) => {
|
|
279
|
+
cleanup();
|
|
280
|
+
reject(new Error(`WebSocket error: ${error}`));
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const closeListener = () => {
|
|
284
|
+
cleanup();
|
|
276
285
|
reject(new Error('WebSocket is closed'));
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const cleanup = () => {
|
|
289
|
+
this.awsRealTimeSocket?.removeEventListener(
|
|
290
|
+
'message',
|
|
291
|
+
publishListener,
|
|
292
|
+
);
|
|
293
|
+
this.awsRealTimeSocket?.removeEventListener('error', errorListener);
|
|
294
|
+
this.awsRealTimeSocket?.removeEventListener('close', closeListener);
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
this.awsRealTimeSocket.addEventListener('message', publishListener);
|
|
298
|
+
this.awsRealTimeSocket.addEventListener('error', errorListener);
|
|
299
|
+
this.awsRealTimeSocket.addEventListener('close', closeListener);
|
|
280
300
|
|
|
281
301
|
this.awsRealTimeSocket.send(serializedSubscriptionMessage);
|
|
302
|
+
} else {
|
|
303
|
+
reject(new Error('WebSocket is not connected'));
|
|
282
304
|
}
|
|
283
305
|
});
|
|
284
306
|
}
|
|
@@ -522,10 +544,12 @@ export abstract class AWSWebSocketProvider {
|
|
|
522
544
|
this.subscriptionObserverMap.delete(subscriptionId);
|
|
523
545
|
|
|
524
546
|
// Verifying 1000ms after removing subscription in case there are new subscription unmount/mount
|
|
525
|
-
|
|
547
|
+
if (!this.allowNoSubscriptions) {
|
|
548
|
+
setTimeout(this._closeSocketIfRequired.bind(this), 1000);
|
|
549
|
+
}
|
|
526
550
|
}
|
|
527
551
|
|
|
528
|
-
|
|
552
|
+
protected _closeSocketIfRequired() {
|
|
529
553
|
if (this.subscriptionObserverMap.size > 0) {
|
|
530
554
|
// Active subscriptions on the WebSocket
|
|
531
555
|
return;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import { Subscription } from 'rxjs';
|
|
5
5
|
import { Amplify } from '@aws-amplify/core';
|
|
6
|
-
import { DocumentType } from '@aws-amplify/core/internals/utils';
|
|
6
|
+
import { DocumentType, amplifyUuid } from '@aws-amplify/core/internals/utils';
|
|
7
7
|
|
|
8
8
|
import { AppSyncEventProvider as eventProvider } from '../../Providers/AWSAppSyncEventsProvider';
|
|
9
9
|
|
|
@@ -17,6 +17,9 @@ import type {
|
|
|
17
17
|
SubscriptionObserver,
|
|
18
18
|
} from './types';
|
|
19
19
|
|
|
20
|
+
// Keeps a list of open channels in the websocket
|
|
21
|
+
const openChannels = new Set<string>();
|
|
22
|
+
|
|
20
23
|
/**
|
|
21
24
|
* @experimental API may change in future versions
|
|
22
25
|
*
|
|
@@ -50,12 +53,18 @@ async function connect(
|
|
|
50
53
|
|
|
51
54
|
await eventProvider.connect(providerOptions);
|
|
52
55
|
|
|
56
|
+
const channelId = amplifyUuid();
|
|
57
|
+
openChannels.add(channelId);
|
|
58
|
+
|
|
53
59
|
let _subscription: Subscription;
|
|
54
60
|
|
|
55
61
|
const sub = (
|
|
56
62
|
observer: SubscriptionObserver<any>,
|
|
57
63
|
subOptions?: EventsOptions,
|
|
58
64
|
): Subscription => {
|
|
65
|
+
if (!openChannels.has(channelId)) {
|
|
66
|
+
throw new Error('Channel is closed');
|
|
67
|
+
}
|
|
59
68
|
const subscribeOptions = { ...providerOptions, query: channel };
|
|
60
69
|
subscribeOptions.authenticationType = normalizeAuth(
|
|
61
70
|
subOptions?.authMode,
|
|
@@ -69,11 +78,13 @@ async function connect(
|
|
|
69
78
|
return _subscription;
|
|
70
79
|
};
|
|
71
80
|
|
|
72
|
-
|
|
73
|
-
const _pub = async (
|
|
81
|
+
const pub = async (
|
|
74
82
|
event: DocumentType,
|
|
75
83
|
pubOptions?: EventsOptions,
|
|
76
84
|
): Promise<any> => {
|
|
85
|
+
if (!openChannels.has(channelId)) {
|
|
86
|
+
throw new Error('Channel is closed');
|
|
87
|
+
}
|
|
77
88
|
const publishOptions = {
|
|
78
89
|
...providerOptions,
|
|
79
90
|
query: channel,
|
|
@@ -87,14 +98,20 @@ async function connect(
|
|
|
87
98
|
return eventProvider.publish(publishOptions);
|
|
88
99
|
};
|
|
89
100
|
|
|
90
|
-
const close = () => {
|
|
101
|
+
const close = async () => {
|
|
91
102
|
_subscription && _subscription.unsubscribe();
|
|
103
|
+
openChannels.delete(channelId);
|
|
104
|
+
setTimeout(() => {
|
|
105
|
+
if (openChannels.size === 0) {
|
|
106
|
+
eventProvider.closeIfNoActiveSubscription();
|
|
107
|
+
}
|
|
108
|
+
}, 1000);
|
|
92
109
|
};
|
|
93
110
|
|
|
94
111
|
return {
|
|
95
112
|
subscribe: sub,
|
|
96
113
|
close,
|
|
97
|
-
|
|
114
|
+
publish: pub,
|
|
98
115
|
};
|
|
99
116
|
}
|
|
100
117
|
|
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
|
|
4
4
|
import { Subscription } from 'rxjs';
|
|
5
|
-
import type {
|
|
5
|
+
import type {
|
|
6
|
+
DocumentType,
|
|
7
|
+
GraphQLAuthMode,
|
|
8
|
+
} from '@aws-amplify/core/internals/utils';
|
|
6
9
|
|
|
7
10
|
export interface SubscriptionObserver<T> {
|
|
8
11
|
next(value: T): void;
|
|
@@ -39,6 +42,29 @@ export interface EventsChannel {
|
|
|
39
42
|
observer: SubscriptionObserver<any>,
|
|
40
43
|
subOptions?: EventsOptions,
|
|
41
44
|
): Subscription;
|
|
45
|
+
/**
|
|
46
|
+
* @experimental API may change in future versions
|
|
47
|
+
*
|
|
48
|
+
* Publish events to a channel via WebSocket
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* const channel = await events.connect("default/channel")
|
|
52
|
+
*
|
|
53
|
+
* await channel.publish({ some: "data" });
|
|
54
|
+
*
|
|
55
|
+
* @example // event batching
|
|
56
|
+
* await channel.publish("default/channel", [{ some: "event" }, { some: "event2" }])
|
|
57
|
+
*
|
|
58
|
+
* @example // authMode override
|
|
59
|
+
* await channel.publish({ some: "data" }, { authMode: "userPool" });
|
|
60
|
+
*
|
|
61
|
+
* @param event - JSON-serializable value or an array of values
|
|
62
|
+
* @param pubOptions - request overrides: `authMode`, `authToken`
|
|
63
|
+
*
|
|
64
|
+
* @returns void on success
|
|
65
|
+
* @throws on error
|
|
66
|
+
*/
|
|
67
|
+
publish(event: DocumentType, pubOptions?: EventsOptions): Promise<any>;
|
|
42
68
|
/**
|
|
43
69
|
* @experimental API may change in future versions
|
|
44
70
|
*
|