@aws-amplify/api-graphql 4.0.2-unstable.ff85fa5.0 → 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.
Files changed (122) hide show
  1. package/dist/cjs/GraphQLAPI.js +1 -1
  2. package/dist/cjs/GraphQLAPI.js.map +1 -1
  3. package/dist/cjs/Providers/AWSAppSyncRealTimeProvider/index.js +1 -1
  4. package/dist/cjs/Providers/AWSAppSyncRealTimeProvider/index.js.map +1 -1
  5. package/dist/cjs/internals/APIClient.js +528 -0
  6. package/dist/cjs/internals/APIClient.js.map +1 -0
  7. package/dist/cjs/internals/InternalGraphQLAPI.js +14 -23
  8. package/dist/cjs/internals/InternalGraphQLAPI.js.map +1 -1
  9. package/dist/cjs/internals/generateClient.js +33 -0
  10. package/dist/cjs/internals/generateClient.js.map +1 -0
  11. package/dist/cjs/internals/generateModelsProperty.js +43 -0
  12. package/dist/cjs/internals/generateModelsProperty.js.map +1 -0
  13. package/dist/cjs/internals/index.js +3 -1
  14. package/dist/cjs/internals/index.js.map +1 -1
  15. package/dist/cjs/internals/operations/get.js +61 -0
  16. package/dist/cjs/internals/operations/get.js.map +1 -0
  17. package/dist/cjs/internals/operations/list.js +73 -0
  18. package/dist/cjs/internals/operations/list.js.map +1 -0
  19. package/dist/cjs/internals/operations/observeQuery.js +121 -0
  20. package/dist/cjs/internals/operations/observeQuery.js.map +1 -0
  21. package/dist/cjs/internals/operations/subscription.js +30 -0
  22. package/dist/cjs/internals/operations/subscription.js.map +1 -0
  23. package/dist/cjs/internals/server/generateClient.js +32 -0
  24. package/dist/cjs/internals/server/generateClient.js.map +1 -0
  25. package/dist/cjs/internals/server/generateModelsProperty.js +47 -0
  26. package/dist/cjs/internals/server/generateModelsProperty.js.map +1 -0
  27. package/dist/cjs/internals/server/index.js +9 -0
  28. package/dist/cjs/internals/server/index.js.map +1 -0
  29. package/dist/cjs/internals/types.js +4 -0
  30. package/dist/cjs/internals/types.js.map +1 -0
  31. package/dist/cjs/types/index.js +3 -1
  32. package/dist/cjs/types/index.js.map +1 -1
  33. package/dist/cjs/utils/findIndexByFields.js +25 -0
  34. package/dist/cjs/utils/findIndexByFields.js.map +1 -0
  35. package/dist/cjs/utils/index.js +5 -1
  36. package/dist/cjs/utils/index.js.map +1 -1
  37. package/dist/cjs/utils/resolveOwnerFields.js +42 -0
  38. package/dist/cjs/utils/resolveOwnerFields.js.map +1 -0
  39. package/dist/cjs/utils/resolvePKFields.js +17 -0
  40. package/dist/cjs/utils/resolvePKFields.js.map +1 -0
  41. package/dist/esm/GraphQLAPI.mjs +1 -1
  42. package/dist/esm/GraphQLAPI.mjs.map +1 -1
  43. package/dist/esm/Providers/AWSAppSyncRealTimeProvider/index.mjs +1 -1
  44. package/dist/esm/Providers/AWSAppSyncRealTimeProvider/index.mjs.map +1 -1
  45. package/dist/esm/index.mjs +1 -1
  46. package/dist/esm/internals/APIClient.d.ts +112 -0
  47. package/dist/esm/internals/APIClient.mjs +518 -0
  48. package/dist/esm/internals/APIClient.mjs.map +1 -0
  49. package/dist/esm/internals/InternalGraphQLAPI.d.ts +0 -11
  50. package/dist/esm/internals/InternalGraphQLAPI.mjs +14 -22
  51. package/dist/esm/internals/InternalGraphQLAPI.mjs.map +1 -1
  52. package/dist/esm/internals/generateClient.d.ts +12 -0
  53. package/dist/esm/internals/generateClient.mjs +31 -0
  54. package/dist/esm/internals/generateClient.mjs.map +1 -0
  55. package/dist/esm/internals/generateModelsProperty.d.ts +4 -0
  56. package/dist/esm/internals/generateModelsProperty.mjs +41 -0
  57. package/dist/esm/internals/generateModelsProperty.mjs.map +1 -0
  58. package/dist/esm/internals/index.d.ts +1 -0
  59. package/dist/esm/internals/index.mjs +1 -0
  60. package/dist/esm/internals/index.mjs.map +1 -1
  61. package/dist/esm/internals/operations/get.d.ts +5 -0
  62. package/dist/esm/internals/operations/get.mjs +59 -0
  63. package/dist/esm/internals/operations/get.mjs.map +1 -0
  64. package/dist/esm/internals/operations/list.d.ts +4 -0
  65. package/dist/esm/internals/operations/list.mjs +71 -0
  66. package/dist/esm/internals/operations/list.mjs.map +1 -0
  67. package/dist/esm/internals/operations/observeQuery.d.ts +3 -0
  68. package/dist/esm/internals/operations/observeQuery.mjs +122 -0
  69. package/dist/esm/internals/operations/observeQuery.mjs.map +1 -0
  70. package/dist/esm/internals/operations/subscription.d.ts +3 -0
  71. package/dist/esm/internals/operations/subscription.mjs +28 -0
  72. package/dist/esm/internals/operations/subscription.mjs.map +1 -0
  73. package/dist/esm/internals/server/generateClient.d.ts +11 -0
  74. package/dist/esm/internals/server/generateClient.mjs +34 -0
  75. package/dist/esm/internals/server/generateClient.mjs.map +1 -0
  76. package/dist/esm/internals/server/generateModelsProperty.d.ts +3 -0
  77. package/dist/esm/internals/server/generateModelsProperty.mjs +45 -0
  78. package/dist/esm/internals/server/generateModelsProperty.mjs.map +1 -0
  79. package/dist/esm/internals/server/index.d.ts +1 -0
  80. package/dist/esm/internals/server/index.mjs +2 -0
  81. package/dist/esm/internals/server/index.mjs.map +1 -0
  82. package/dist/esm/internals/types.d.ts +17 -0
  83. package/dist/esm/internals/types.mjs +2 -0
  84. package/dist/esm/internals/types.mjs.map +1 -0
  85. package/dist/esm/types/index.d.ts +32 -2
  86. package/dist/esm/types/index.mjs +3 -1
  87. package/dist/esm/types/index.mjs.map +1 -1
  88. package/dist/esm/utils/findIndexByFields.d.ts +9 -0
  89. package/dist/esm/utils/findIndexByFields.mjs +22 -0
  90. package/dist/esm/utils/findIndexByFields.mjs.map +1 -0
  91. package/dist/esm/utils/index.d.ts +2 -0
  92. package/dist/esm/utils/index.mjs +2 -0
  93. package/dist/esm/utils/index.mjs.map +1 -1
  94. package/dist/esm/utils/resolveOwnerFields.d.ts +12 -0
  95. package/dist/esm/utils/resolveOwnerFields.mjs +39 -0
  96. package/dist/esm/utils/resolveOwnerFields.mjs.map +1 -0
  97. package/dist/esm/utils/resolvePKFields.d.ts +13 -0
  98. package/dist/esm/utils/resolvePKFields.mjs +14 -0
  99. package/dist/esm/utils/resolvePKFields.mjs.map +1 -0
  100. package/internals/server/package.json +8 -0
  101. package/package.json +148 -146
  102. package/src/GraphQLAPI.ts +2 -2
  103. package/src/Providers/AWSAppSyncRealTimeProvider/index.ts +9 -4
  104. package/src/internals/APIClient.ts +780 -0
  105. package/src/internals/InternalGraphQLAPI.ts +21 -31
  106. package/src/internals/generateClient.ts +33 -0
  107. package/src/internals/generateModelsProperty.ts +73 -0
  108. package/src/internals/index.ts +1 -0
  109. package/src/internals/operations/get.ts +131 -0
  110. package/src/internals/operations/list.ts +132 -0
  111. package/src/internals/operations/observeQuery.ts +144 -0
  112. package/src/internals/operations/subscription.ts +65 -0
  113. package/src/internals/server/generateClient.ts +45 -0
  114. package/src/internals/server/generateModelsProperty.ts +80 -0
  115. package/src/internals/server/index.ts +4 -0
  116. package/src/internals/types.ts +21 -0
  117. package/src/types/index.ts +42 -2
  118. package/src/utils/ConnectionStateMonitor.ts +3 -1
  119. package/src/utils/findIndexByFields.ts +31 -0
  120. package/src/utils/index.ts +2 -0
  121. package/src/utils/resolveOwnerFields.ts +65 -0
  122. package/src/utils/resolvePKFields.ts +22 -0
@@ -35,17 +35,11 @@ const USER_AGENT_HEADER = 'x-amz-user-agent';
35
35
 
36
36
  const logger = new ConsoleLogger('GraphQLAPI');
37
37
 
38
- export const graphqlOperation = (
39
- query,
40
- variables = {},
41
- authToken?: string
42
- ) => ({
43
- query,
44
- variables,
45
- authToken,
46
- });
47
-
48
- const isAmplifyInstance = (amplify): amplify is AmplifyClassV6 => {
38
+ const isAmplifyInstance = (
39
+ amplify:
40
+ | AmplifyClassV6
41
+ | ((fn: (amplify: any) => Promise<any>) => Promise<AmplifyClassV6>)
42
+ ): amplify is AmplifyClassV6 => {
49
43
  return typeof amplify !== 'function';
50
44
  };
51
45
 
@@ -56,8 +50,7 @@ export class InternalGraphQLAPIClass {
56
50
  /**
57
51
  * @private
58
52
  */
59
- private _options;
60
- private appSyncRealTime: AWSAppSyncRealTimeProvider | null;
53
+ private appSyncRealTime = new AWSAppSyncRealTimeProvider();
61
54
 
62
55
  private _api = {
63
56
  post,
@@ -66,15 +59,6 @@ export class InternalGraphQLAPIClass {
66
59
  updateRequestToBeCancellable,
67
60
  };
68
61
 
69
- /**
70
- * Initialize GraphQL API with AWS configuration
71
- * @param {Object} options - Configuration object for API
72
- */
73
- constructor(options) {
74
- this._options = options;
75
- logger.debug('API Options', this._options);
76
- }
77
-
78
62
  public getModuleName() {
79
63
  return 'InternalGraphQLAPI';
80
64
  }
@@ -208,7 +192,7 @@ export class InternalGraphQLAPIClass {
208
192
  customUserAgentDetails
209
193
  );
210
194
  } else {
211
- const wrapper = amplifyInstance =>
195
+ const wrapper = (amplifyInstance: AmplifyClassV6) =>
212
196
  this._graphql<T>(
213
197
  amplifyInstance,
214
198
  { query, variables, authMode },
@@ -307,7 +291,7 @@ export class InternalGraphQLAPIClass {
307
291
  authMode !== 'iam' &&
308
292
  authMode !== 'lambda')
309
293
  ) {
310
- signingServiceInfo = null;
294
+ signingServiceInfo = undefined;
311
295
  } else {
312
296
  signingServiceInfo = {
313
297
  service: !customEndpointRegion ? 'appsync' : 'execute-api',
@@ -326,7 +310,7 @@ export class InternalGraphQLAPIClass {
326
310
  };
327
311
  }
328
312
 
329
- let response;
313
+ let response: any;
330
314
  try {
331
315
  const { body: responseBody } = await this._api.post({
332
316
  url: new AmplifyUrl(endpoint),
@@ -352,7 +336,16 @@ export class InternalGraphQLAPIClass {
352
336
 
353
337
  response = {
354
338
  data: {},
355
- errors: [new GraphQLError(err.message, null, null, null, null, err)],
339
+ errors: [
340
+ new GraphQLError(
341
+ (err as any).message,
342
+ null,
343
+ null,
344
+ null,
345
+ null,
346
+ err as any
347
+ ),
348
+ ],
356
349
  };
357
350
  }
358
351
 
@@ -391,16 +384,13 @@ export class InternalGraphQLAPIClass {
391
384
  ): Observable<any> {
392
385
  const config = resolveConfig(amplify);
393
386
 
394
- if (!this.appSyncRealTime) {
395
- this.appSyncRealTime = new AWSAppSyncRealTimeProvider();
396
- }
397
387
  return this.appSyncRealTime.subscribe(
398
388
  {
399
389
  query: print(query as DocumentNode),
400
390
  variables,
401
391
  appSyncGraphqlEndpoint: config?.endpoint,
402
392
  region: config?.region,
403
- authenticationType: authMode ?? config?.defaultAuthMode,
393
+ authenticationType: authMode || config?.defaultAuthMode,
404
394
  apiKey: config?.apiKey,
405
395
  additionalHeaders,
406
396
  },
@@ -409,4 +399,4 @@ export class InternalGraphQLAPIClass {
409
399
  }
410
400
  }
411
401
 
412
- export const InternalGraphQLAPI = new InternalGraphQLAPIClass(null);
402
+ export const InternalGraphQLAPI = new InternalGraphQLAPIClass();
@@ -0,0 +1,33 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { graphql, cancel, isCancelError } from './v6';
4
+ import { generateModelsProperty } from './generateModelsProperty';
5
+ import { V6Client, __amplify, __authMode, __authToken } from '../types';
6
+ import { ClientGenerationParams } from './types';
7
+
8
+ /**
9
+ * @private
10
+ *
11
+ * Creates a client that can be used to make GraphQL requests, using a provided `AmplifyClassV6`
12
+ * compatible context object for config and auth fetching.
13
+ *
14
+ * @param params
15
+ * @returns
16
+ */
17
+ export function generateClient<T extends Record<any, any> = never>(
18
+ params: ClientGenerationParams
19
+ ): V6Client<T> {
20
+ const client = {
21
+ [__amplify]: params.amplify,
22
+ [__authMode]: params.authMode,
23
+ [__authToken]: params.authToken,
24
+ graphql,
25
+ cancel,
26
+ isCancelError,
27
+ models: {},
28
+ } as any;
29
+
30
+ client.models = generateModelsProperty<T>(client, params);
31
+
32
+ return client as V6Client<T>;
33
+ }
@@ -0,0 +1,73 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { ModelTypes } from '@aws-amplify/data-schema-types';
4
+ import { graphQLOperationsInfo, ModelOperation } from './APIClient';
5
+ import { ClientGenerationParams } from './types';
6
+ import { V6Client, __authMode, __authToken } from '../types';
7
+
8
+ import { listFactory } from './operations/list';
9
+ import { getFactory } from './operations/get';
10
+ import { subscriptionFactory } from './operations/subscription';
11
+ import { observeQueryFactory } from './operations/observeQuery';
12
+ import { ModelIntrospectionSchema } from '@aws-amplify/core/internals/utils';
13
+
14
+ export function generateModelsProperty<T extends Record<any, any> = never>(
15
+ client: V6Client<Record<string, any>>,
16
+ params: ClientGenerationParams
17
+ ): ModelTypes<T> {
18
+ const models = {} as any;
19
+ const config = params.amplify.getConfig();
20
+
21
+ if (!config.API?.GraphQL) {
22
+ throw new Error(
23
+ 'The API configuration is missing. This is likely due to Amplify.configure() not being called prior to generateClient().'
24
+ );
25
+ }
26
+
27
+ const modelIntrospection: ModelIntrospectionSchema | undefined =
28
+ config.API.GraphQL.modelIntrospection;
29
+
30
+ if (!modelIntrospection) {
31
+ return {} as ModelTypes<never>;
32
+ }
33
+
34
+ const SUBSCRIPTION_OPS = ['ONCREATE', 'ONUPDATE', 'ONDELETE'];
35
+
36
+ for (const model of Object.values(modelIntrospection.models)) {
37
+ const { name } = model;
38
+
39
+ models[name] = {} as Record<string, any>;
40
+
41
+ Object.entries(graphQLOperationsInfo).forEach(
42
+ ([key, { operationPrefix }]) => {
43
+ const operation = key as ModelOperation;
44
+
45
+ if (operation === 'LIST') {
46
+ models[name][operationPrefix] = listFactory(
47
+ client,
48
+ modelIntrospection,
49
+ model
50
+ );
51
+ } else if (SUBSCRIPTION_OPS.includes(operation)) {
52
+ models[name][operationPrefix] = subscriptionFactory(
53
+ client,
54
+ modelIntrospection,
55
+ model,
56
+ operation
57
+ );
58
+ } else if (operation === 'OBSERVE_QUERY') {
59
+ models[name][operationPrefix] = observeQueryFactory(models, model);
60
+ } else {
61
+ models[name][operationPrefix] = getFactory(
62
+ client,
63
+ modelIntrospection,
64
+ model,
65
+ operation
66
+ );
67
+ }
68
+ }
69
+ );
70
+ }
71
+
72
+ return models;
73
+ }
@@ -6,3 +6,4 @@ export {
6
6
  } from './InternalGraphQLAPI';
7
7
 
8
8
  export { graphql, cancel, isCancelError } from './v6';
9
+ export { generateClient } from './generateClient';
@@ -0,0 +1,131 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { AmplifyServer } from '@aws-amplify/core/internals/adapter-core';
4
+ import {
5
+ initializeModel,
6
+ generateGraphQLDocument,
7
+ buildGraphQLVariables,
8
+ flattenItems,
9
+ authModeParams,
10
+ ModelOperation,
11
+ } from '../APIClient';
12
+ import {
13
+ AuthModeParams,
14
+ ClientWithModels,
15
+ GraphQLOptionsV6,
16
+ GraphQLResult,
17
+ ListArgs,
18
+ QueryArgs,
19
+ V6Client,
20
+ V6ClientSSRRequest,
21
+ } from '../../types';
22
+ import {
23
+ ModelIntrospectionSchema,
24
+ SchemaModel,
25
+ } from '@aws-amplify/core/internals/utils';
26
+
27
+ export function getFactory(
28
+ client: ClientWithModels,
29
+ modelIntrospection: ModelIntrospectionSchema,
30
+ model: SchemaModel,
31
+ operation: ModelOperation,
32
+ useContext = false
33
+ ) {
34
+ const getWithContext = async (
35
+ contextSpec: AmplifyServer.ContextSpec & GraphQLOptionsV6<unknown, string>,
36
+ arg?: any,
37
+ options?: any
38
+ ) => {
39
+ return _get(
40
+ client,
41
+ modelIntrospection,
42
+ model,
43
+ arg,
44
+ options,
45
+ operation,
46
+ contextSpec
47
+ );
48
+ };
49
+
50
+ const get = async (arg?: any, options?: any) => {
51
+ return _get(client, modelIntrospection, model, arg, options, operation);
52
+ };
53
+
54
+ return useContext ? getWithContext : get;
55
+ }
56
+
57
+ async function _get(
58
+ client: ClientWithModels,
59
+ modelIntrospection: ModelIntrospectionSchema,
60
+ model: SchemaModel,
61
+ arg: QueryArgs,
62
+ options: AuthModeParams & ListArgs,
63
+ operation: ModelOperation,
64
+ context?: AmplifyServer.ContextSpec
65
+ ) {
66
+ const { name } = model;
67
+
68
+ const query = generateGraphQLDocument(
69
+ modelIntrospection.models,
70
+ name,
71
+ operation,
72
+ options
73
+ );
74
+ const variables = buildGraphQLVariables(
75
+ model,
76
+ operation,
77
+ arg,
78
+ modelIntrospection
79
+ );
80
+
81
+ try {
82
+ const auth = authModeParams(client, options);
83
+ const { data, extensions } = context
84
+ ? ((await (client as V6ClientSSRRequest<Record<string, any>>).graphql(
85
+ context,
86
+ {
87
+ ...auth,
88
+ query,
89
+ variables,
90
+ }
91
+ )) as GraphQLResult<any>)
92
+ : ((await (client as V6Client<Record<string, any>>).graphql({
93
+ ...auth,
94
+ query,
95
+ variables,
96
+ })) as GraphQLResult<any>);
97
+
98
+ // flatten response
99
+ if (data) {
100
+ const [key] = Object.keys(data);
101
+ const flattenedResult = flattenItems(data)[key];
102
+
103
+ if (options?.selectionSet) {
104
+ return { data: flattenedResult, extensions };
105
+ } else {
106
+ // TODO: refactor to avoid destructuring here
107
+ const [initialized] = initializeModel(
108
+ client,
109
+ name,
110
+ [flattenedResult],
111
+ modelIntrospection,
112
+ auth.authMode,
113
+ auth.authToken,
114
+ !!context
115
+ );
116
+
117
+ return { data: initialized, extensions };
118
+ }
119
+ } else {
120
+ return { data: null, extensions };
121
+ }
122
+ } catch (error: any) {
123
+ if (error.errors) {
124
+ // graphql errors pass through
125
+ return error as any;
126
+ } else {
127
+ // non-graphql errors re re-thrown
128
+ throw error;
129
+ }
130
+ }
131
+ }
@@ -0,0 +1,132 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { AmplifyServer } from '@aws-amplify/core/internals/adapter-core';
4
+ import {
5
+ initializeModel,
6
+ generateGraphQLDocument,
7
+ buildGraphQLVariables,
8
+ flattenItems,
9
+ authModeParams,
10
+ } from '../APIClient';
11
+ import {
12
+ AuthModeParams,
13
+ ClientWithModels,
14
+ ListArgs,
15
+ V6Client,
16
+ V6ClientSSRRequest,
17
+ GraphQLResult,
18
+ } from '../../types';
19
+ import {
20
+ ModelIntrospectionSchema,
21
+ SchemaModel,
22
+ } from '@aws-amplify/core/internals/utils';
23
+
24
+ export function listFactory(
25
+ client: ClientWithModels,
26
+ modelIntrospection: ModelIntrospectionSchema,
27
+ model: SchemaModel,
28
+ context = false
29
+ ) {
30
+ const listWithContext = async (
31
+ contextSpec: AmplifyServer.ContextSpec,
32
+ args?: ListArgs
33
+ ) => {
34
+ return _list(client, modelIntrospection, model, args, contextSpec);
35
+ };
36
+
37
+ const list = async (args?: any) => {
38
+ return _list(client, modelIntrospection, model, args);
39
+ };
40
+
41
+ return context ? listWithContext : list;
42
+ }
43
+
44
+ async function _list(
45
+ client: ClientWithModels,
46
+ modelIntrospection: ModelIntrospectionSchema,
47
+ model: SchemaModel,
48
+ args?: ListArgs & AuthModeParams,
49
+ contextSpec?: AmplifyServer.ContextSpec
50
+ ) {
51
+ const { name } = model;
52
+
53
+ const query = generateGraphQLDocument(
54
+ modelIntrospection.models,
55
+ name,
56
+ 'LIST',
57
+ args
58
+ );
59
+ const variables = buildGraphQLVariables(
60
+ model,
61
+ 'LIST',
62
+ args,
63
+ modelIntrospection
64
+ );
65
+
66
+ try {
67
+ const auth = authModeParams(client, args);
68
+
69
+ const { data, extensions } = !!contextSpec
70
+ ? ((await (client as V6ClientSSRRequest<Record<string, any>>).graphql(
71
+ contextSpec,
72
+ {
73
+ ...auth,
74
+ query,
75
+ variables,
76
+ }
77
+ )) as GraphQLResult<any>)
78
+ : ((await (client as V6Client<Record<string, any>>).graphql({
79
+ ...auth,
80
+ query,
81
+ variables,
82
+ })) as GraphQLResult<any>);
83
+
84
+ // flatten response
85
+ if (data !== undefined) {
86
+ const [key] = Object.keys(data);
87
+
88
+ if (data[key].items) {
89
+ const flattenedResult = flattenItems(data)[key];
90
+
91
+ // don't init if custom selection set
92
+ if (args?.selectionSet) {
93
+ return {
94
+ data: flattenedResult,
95
+ nextToken: data[key].nextToken,
96
+ extensions,
97
+ };
98
+ } else {
99
+ const initialized = initializeModel(
100
+ client,
101
+ name,
102
+ flattenedResult,
103
+ modelIntrospection,
104
+ auth.authMode,
105
+ auth.authToken,
106
+ !!contextSpec
107
+ );
108
+
109
+ return {
110
+ data: initialized,
111
+ nextToken: data[key].nextToken,
112
+ extensions,
113
+ };
114
+ }
115
+ }
116
+
117
+ return {
118
+ data: data[key],
119
+ nextToken: data[key].nextToken,
120
+ extensions,
121
+ };
122
+ }
123
+ } catch (error: any) {
124
+ if (error.errors) {
125
+ // graphql errors pass through
126
+ return error as any;
127
+ } else {
128
+ // non-graphql errors re re-thrown
129
+ throw error;
130
+ }
131
+ }
132
+ }
@@ -0,0 +1,144 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { Observable } from 'rxjs';
4
+ import { findIndexByFields, resolvePKFields } from '../../utils';
5
+ import { SchemaModel } from '@aws-amplify/core/internals/utils';
6
+
7
+ export function observeQueryFactory(models: any, model: SchemaModel) {
8
+ const { name } = model;
9
+
10
+ const observeQuery = (arg?: any) =>
11
+ new Observable(subscriber => {
12
+ // what we'll be sending to our subscribers
13
+ const items: object[] = [];
14
+
15
+ // To enqueue subscription messages while we collect our initial
16
+ // result set.
17
+ const messageQueue = [] as {
18
+ type: 'create' | 'update' | 'delete';
19
+ item: object;
20
+ }[];
21
+
22
+ // operation to take when message(s) arrive.
23
+ // this operation will be swapped out once initial "sync" is complete
24
+ // to immediately ingest messsages.
25
+ let receiveMessages = (...messages: typeof messageQueue) => {
26
+ return messageQueue.push(...messages);
27
+ };
28
+
29
+ // start subscriptions
30
+ const onCreateSub = models[name].onCreate(arg).subscribe({
31
+ next(item: object) {
32
+ receiveMessages({ item, type: 'create' });
33
+ },
34
+ error(error: any) {
35
+ subscriber.error({ type: 'onCreate', error });
36
+ },
37
+ });
38
+ const onUpdateSub = models[name].onUpdate(arg).subscribe({
39
+ next(item: object) {
40
+ receiveMessages({ item, type: 'update' });
41
+ },
42
+ error(error: any) {
43
+ subscriber.error({ type: 'onUpdate', error });
44
+ },
45
+ });
46
+ const onDeleteSub = models[name].onDelete(arg).subscribe({
47
+ next(item: object) {
48
+ receiveMessages({ item, type: 'delete' });
49
+ },
50
+ error(error: any) {
51
+ subscriber.error({ type: 'onDelete', error });
52
+ },
53
+ });
54
+
55
+ // consumes a list of messages and sends a snapshot
56
+ function ingestMessages(messages: typeof messageQueue) {
57
+ for (const message of messages) {
58
+ const idx = findIndexByFields(message.item, items, pkFields as any);
59
+ switch (message.type) {
60
+ case 'create':
61
+ if (idx < 0) items.push(message.item);
62
+ break;
63
+ case 'update':
64
+ if (idx >= 0) items[idx] = message.item;
65
+ break;
66
+ case 'delete':
67
+ if (idx >= 0) items.splice(idx, 1);
68
+ break;
69
+ default:
70
+ console.error('Unrecognized message in observeQuery.', message);
71
+ }
72
+ }
73
+ subscriber.next({
74
+ items,
75
+ isSynced: true,
76
+ });
77
+ }
78
+
79
+ const pkFields = resolvePKFields(model);
80
+
81
+ // initial results
82
+ (async () => {
83
+ let firstPage = true;
84
+ let nextToken: string | null = null;
85
+ while (!subscriber.closed && (firstPage || nextToken)) {
86
+ firstPage = false;
87
+
88
+ const {
89
+ data: page,
90
+ errors,
91
+ nextToken: _nextToken,
92
+ }: {
93
+ data: any;
94
+ errors: any;
95
+ nextToken: string | null;
96
+ } = await models[name].list({ ...arg, nextToken });
97
+ nextToken = _nextToken;
98
+
99
+ items.push(...page);
100
+
101
+ // if there are no more pages and no items we already know about
102
+ // that need to be merged in from sub, we're "synced"
103
+ const isSynced =
104
+ messageQueue.length === 0 &&
105
+ (nextToken === null || nextToken === undefined);
106
+
107
+ subscriber.next({
108
+ items,
109
+ isSynced,
110
+ });
111
+
112
+ if (Array.isArray(errors)) {
113
+ for (const error of errors) {
114
+ subscriber.error(error);
115
+ }
116
+ }
117
+ }
118
+
119
+ // play through the queue
120
+ if (messageQueue.length > 0) {
121
+ ingestMessages(messageQueue);
122
+ }
123
+
124
+ // switch the queue to write directly to the items collection
125
+ receiveMessages = (...messages: typeof messageQueue) => {
126
+ ingestMessages(messages);
127
+ return items.length;
128
+ };
129
+ })();
130
+
131
+ // when subscriber unsubscribes, tear down internal subs
132
+ return () => {
133
+ // 1. tear down internal subs
134
+ onCreateSub.unsubscribe();
135
+ onUpdateSub.unsubscribe();
136
+ onDeleteSub.unsubscribe();
137
+
138
+ // 2. there is no need to explicitly stop paging. instead, we
139
+ // just check `subscriber.closed` above before fetching each page.
140
+ };
141
+ });
142
+
143
+ return observeQuery;
144
+ }
@@ -0,0 +1,65 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { map } from 'rxjs';
5
+ import { V6Client, GraphqlSubscriptionResult } from '../../types';
6
+ import {
7
+ initializeModel,
8
+ generateGraphQLDocument,
9
+ buildGraphQLVariables,
10
+ authModeParams,
11
+ ModelOperation,
12
+ } from '../APIClient';
13
+ import {
14
+ ModelIntrospectionSchema,
15
+ SchemaModel,
16
+ } from '@aws-amplify/core/internals/utils';
17
+
18
+ export function subscriptionFactory(
19
+ client: any,
20
+ modelIntrospection: ModelIntrospectionSchema,
21
+ model: SchemaModel,
22
+ operation: ModelOperation
23
+ ) {
24
+ const { name } = model as any;
25
+
26
+ const subscription = (args?: any) => {
27
+ const query = generateGraphQLDocument(
28
+ modelIntrospection.models,
29
+ name,
30
+ operation
31
+ );
32
+ const variables = buildGraphQLVariables(
33
+ model,
34
+ operation,
35
+ args,
36
+ modelIntrospection
37
+ );
38
+
39
+ const auth = authModeParams(client, args);
40
+
41
+ const observable = client.graphql({
42
+ ...auth,
43
+ query,
44
+ variables,
45
+ }) as GraphqlSubscriptionResult<object>;
46
+
47
+ return observable.pipe(
48
+ map(value => {
49
+ const [key] = Object.keys(value.data);
50
+ const data = (value.data as any)[key];
51
+ const [initialized] = initializeModel(
52
+ client as V6Client<Record<string, any>>,
53
+ name,
54
+ [data],
55
+ modelIntrospection,
56
+ auth.authMode,
57
+ auth.authToken
58
+ );
59
+ return initialized;
60
+ })
61
+ );
62
+ };
63
+
64
+ return subscription;
65
+ }