@aws-amplify/datastore 3.12.6-next.13 → 3.12.6-next.32

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 (162) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/lib/authModeStrategies/multiAuthStrategy.js +17 -64
  3. package/lib/authModeStrategies/multiAuthStrategy.js.map +1 -1
  4. package/lib/datastore/datastore.js +682 -469
  5. package/lib/datastore/datastore.js.map +1 -1
  6. package/lib/index.js +2 -4
  7. package/lib/index.js.map +1 -1
  8. package/lib/predicates/index.js +12 -2
  9. package/lib/predicates/index.js.map +1 -1
  10. package/lib/storage/adapter/AsyncStorageAdapter.js +393 -298
  11. package/lib/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  12. package/lib/storage/adapter/AsyncStorageDatabase.js +97 -122
  13. package/lib/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  14. package/lib/storage/adapter/InMemoryStore.js +16 -67
  15. package/lib/storage/adapter/InMemoryStore.js.map +1 -1
  16. package/lib/storage/adapter/InMemoryStore.native.js +2 -4
  17. package/lib/storage/adapter/InMemoryStore.native.js.map +1 -1
  18. package/lib/storage/adapter/IndexedDBAdapter.js +497 -404
  19. package/lib/storage/adapter/IndexedDBAdapter.js.map +1 -1
  20. package/lib/storage/adapter/getDefaultAdapter/index.js +3 -5
  21. package/lib/storage/adapter/getDefaultAdapter/index.js.map +1 -1
  22. package/lib/storage/adapter/getDefaultAdapter/index.native.js +2 -4
  23. package/lib/storage/adapter/getDefaultAdapter/index.native.js.map +1 -1
  24. package/lib/storage/storage.js +129 -151
  25. package/lib/storage/storage.js.map +1 -1
  26. package/lib/sync/datastoreConnectivity.js +13 -17
  27. package/lib/sync/datastoreConnectivity.js.map +1 -1
  28. package/lib/sync/datastoreReachability/index.native.js +2 -4
  29. package/lib/sync/datastoreReachability/index.native.js.map +1 -1
  30. package/lib/sync/index.js +544 -488
  31. package/lib/sync/index.js.map +1 -1
  32. package/lib/sync/merger.js +21 -80
  33. package/lib/sync/merger.js.map +1 -1
  34. package/lib/sync/outbox.js +95 -162
  35. package/lib/sync/outbox.js.map +1 -1
  36. package/lib/sync/processors/errorMaps.js +4 -34
  37. package/lib/sync/processors/errorMaps.js.map +1 -1
  38. package/lib/sync/processors/mutation.js +285 -312
  39. package/lib/sync/processors/mutation.js.map +1 -1
  40. package/lib/sync/processors/subscription.js +218 -259
  41. package/lib/sync/processors/subscription.js.map +1 -1
  42. package/lib/sync/processors/sync.js +141 -212
  43. package/lib/sync/processors/sync.js.map +1 -1
  44. package/lib/sync/utils.js +50 -61
  45. package/lib/sync/utils.js.map +1 -1
  46. package/lib/types.js +13 -39
  47. package/lib/types.js.map +1 -1
  48. package/lib/util.js +429 -242
  49. package/lib/util.js.map +1 -1
  50. package/lib-esm/authModeStrategies/multiAuthStrategy.d.ts +11 -0
  51. package/lib-esm/authModeStrategies/multiAuthStrategy.js +13 -57
  52. package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +1 -1
  53. package/lib-esm/datastore/datastore.d.ts +107 -17
  54. package/lib-esm/datastore/datastore.js +649 -433
  55. package/lib-esm/datastore/datastore.js.map +1 -1
  56. package/lib-esm/index.d.ts +3 -19
  57. package/lib-esm/predicates/index.d.ts +3 -2
  58. package/lib-esm/predicates/index.js +13 -3
  59. package/lib-esm/predicates/index.js.map +1 -1
  60. package/lib-esm/storage/adapter/AsyncStorageAdapter.d.ts +4 -3
  61. package/lib-esm/storage/adapter/AsyncStorageAdapter.js +356 -258
  62. package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  63. package/lib-esm/storage/adapter/AsyncStorageDatabase.d.ts +14 -4
  64. package/lib-esm/storage/adapter/AsyncStorageDatabase.js +67 -92
  65. package/lib-esm/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  66. package/lib-esm/storage/adapter/InMemoryStore.js +1 -52
  67. package/lib-esm/storage/adapter/InMemoryStore.js.map +1 -1
  68. package/lib-esm/storage/adapter/IndexedDBAdapter.d.ts +26 -4
  69. package/lib-esm/storage/adapter/IndexedDBAdapter.js +446 -346
  70. package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +1 -1
  71. package/lib-esm/storage/adapter/index.d.ts +1 -1
  72. package/lib-esm/storage/storage.d.ts +1 -1
  73. package/lib-esm/storage/storage.js +94 -113
  74. package/lib-esm/storage/storage.js.map +1 -1
  75. package/lib-esm/sync/datastoreConnectivity.d.ts +1 -0
  76. package/lib-esm/sync/datastoreConnectivity.js +10 -11
  77. package/lib-esm/sync/datastoreConnectivity.js.map +1 -1
  78. package/lib-esm/sync/index.d.ts +31 -5
  79. package/lib-esm/sync/index.js +525 -466
  80. package/lib-esm/sync/index.js.map +1 -1
  81. package/lib-esm/sync/merger.d.ts +9 -3
  82. package/lib-esm/sync/merger.js +14 -73
  83. package/lib-esm/sync/merger.js.map +1 -1
  84. package/lib-esm/sync/outbox.d.ts +2 -2
  85. package/lib-esm/sync/outbox.js +79 -146
  86. package/lib-esm/sync/outbox.js.map +1 -1
  87. package/lib-esm/sync/processors/errorMaps.js +1 -31
  88. package/lib-esm/sync/processors/errorMaps.js.map +1 -1
  89. package/lib-esm/sync/processors/mutation.d.ts +2 -0
  90. package/lib-esm/sync/processors/mutation.js +271 -295
  91. package/lib-esm/sync/processors/mutation.js.map +1 -1
  92. package/lib-esm/sync/processors/subscription.d.ts +2 -0
  93. package/lib-esm/sync/processors/subscription.js +214 -245
  94. package/lib-esm/sync/processors/subscription.js.map +1 -1
  95. package/lib-esm/sync/processors/sync.d.ts +2 -1
  96. package/lib-esm/sync/processors/sync.js +127 -195
  97. package/lib-esm/sync/processors/sync.js.map +1 -1
  98. package/lib-esm/sync/utils.d.ts +3 -2
  99. package/lib-esm/sync/utils.js +45 -57
  100. package/lib-esm/sync/utils.js.map +1 -1
  101. package/lib-esm/types.d.ts +65 -26
  102. package/lib-esm/types.js +10 -38
  103. package/lib-esm/types.js.map +1 -1
  104. package/lib-esm/util.d.ts +67 -24
  105. package/lib-esm/util.js +420 -233
  106. package/lib-esm/util.js.map +1 -1
  107. package/package.json +14 -7
  108. package/src/authModeStrategies/multiAuthStrategy.ts +12 -1
  109. package/src/datastore/datastore.ts +798 -397
  110. package/src/predicates/index.ts +32 -10
  111. package/src/storage/adapter/AsyncStorageAdapter.ts +309 -93
  112. package/src/storage/adapter/AsyncStorageDatabase.ts +74 -26
  113. package/src/storage/adapter/IndexedDBAdapter.ts +358 -134
  114. package/src/storage/adapter/index.ts +1 -1
  115. package/src/storage/storage.ts +69 -22
  116. package/src/sync/datastoreConnectivity.ts +6 -0
  117. package/src/sync/index.ts +521 -412
  118. package/src/sync/merger.ts +20 -4
  119. package/src/sync/outbox.ts +22 -9
  120. package/src/sync/processors/mutation.ts +188 -150
  121. package/src/sync/processors/subscription.ts +289 -253
  122. package/src/sync/processors/sync.ts +151 -138
  123. package/src/sync/utils.ts +67 -12
  124. package/src/types.ts +182 -30
  125. package/src/util.ts +505 -176
  126. package/build.js +0 -5
  127. package/dist/aws-amplify-datastore.js +0 -98255
  128. package/dist/aws-amplify-datastore.js.map +0 -1
  129. package/dist/aws-amplify-datastore.min.js +0 -66
  130. package/dist/aws-amplify-datastore.min.js.map +0 -1
  131. package/index.js +0 -7
  132. package/lib/authModeStrategies/defaultAuthStrategy.d.ts +0 -2
  133. package/lib/authModeStrategies/index.d.ts +0 -2
  134. package/lib/authModeStrategies/multiAuthStrategy.d.ts +0 -2
  135. package/lib/datastore/datastore.d.ts +0 -66
  136. package/lib/index.d.ts +0 -31
  137. package/lib/predicates/index.d.ts +0 -15
  138. package/lib/predicates/sort.d.ts +0 -8
  139. package/lib/ssr/index.d.ts +0 -3
  140. package/lib/storage/adapter/AsyncStorageAdapter.d.ts +0 -40
  141. package/lib/storage/adapter/AsyncStorageDatabase.d.ts +0 -29
  142. package/lib/storage/adapter/InMemoryStore.d.ts +0 -11
  143. package/lib/storage/adapter/InMemoryStore.native.d.ts +0 -1
  144. package/lib/storage/adapter/IndexedDBAdapter.d.ts +0 -37
  145. package/lib/storage/adapter/getDefaultAdapter/index.d.ts +0 -3
  146. package/lib/storage/adapter/getDefaultAdapter/index.native.d.ts +0 -3
  147. package/lib/storage/adapter/index.d.ts +0 -9
  148. package/lib/storage/storage.d.ts +0 -49
  149. package/lib/sync/datastoreConnectivity.d.ts +0 -15
  150. package/lib/sync/datastoreReachability/index.d.ts +0 -3
  151. package/lib/sync/datastoreReachability/index.native.d.ts +0 -3
  152. package/lib/sync/index.d.ts +0 -63
  153. package/lib/sync/merger.d.ts +0 -11
  154. package/lib/sync/outbox.d.ts +0 -27
  155. package/lib/sync/processors/errorMaps.d.ts +0 -17
  156. package/lib/sync/processors/mutation.d.ts +0 -56
  157. package/lib/sync/processors/subscription.d.ts +0 -31
  158. package/lib/sync/processors/sync.d.ts +0 -27
  159. package/lib/sync/utils.d.ts +0 -41
  160. package/lib/types.d.ts +0 -462
  161. package/lib/util.d.ts +0 -113
  162. package/webpack.config.dev.js +0 -6
@@ -1,7 +1,12 @@
1
- import API, { GraphQLResult, GRAPHQL_AUTH_MODE } from '@aws-amplify/api';
1
+ import { API, GraphQLResult, GRAPHQL_AUTH_MODE } from '@aws-amplify/api';
2
2
  import { Auth } from '@aws-amplify/auth';
3
- import Cache from '@aws-amplify/cache';
4
- import { ConsoleLogger as Logger, Hub, HubCapsule } from '@aws-amplify/core';
3
+ import { BrowserStorageCache as Cache } from '@aws-amplify/cache';
4
+ import {
5
+ ConsoleLogger as Logger,
6
+ Hub,
7
+ HubCapsule,
8
+ BackgroundProcessManager,
9
+ } from '@aws-amplify/core';
5
10
  import { CONTROL_MSG as PUBSUB_CONTROL_MSG } from '@aws-amplify/pubsub';
6
11
  import Observable, { ZenObservable } from 'zen-observable-ts';
7
12
  import {
@@ -56,6 +61,8 @@ class SubscriptionProcessor {
56
61
  [];
57
62
  private dataObserver: ZenObservable.Observer<any>;
58
63
 
64
+ private runningProcesses = new BackgroundProcessManager();
65
+
59
66
  constructor(
60
67
  private readonly schema: InternalSchema,
61
68
  private readonly syncPredicates: WeakMap<SchemaModel, ModelPredicate<any>>,
@@ -252,7 +259,7 @@ class SubscriptionProcessor {
252
259
  let cognitoTokenPayload: { [field: string]: any },
253
260
  oidcTokenPayload: { [field: string]: any };
254
261
  let userCredentials = USER_CREDENTIALS.none;
255
- (async () => {
262
+ this.runningProcesses.add(async () => {
256
263
  try {
257
264
  // retrieving current AWS Credentials
258
265
  const credentials =
@@ -310,261 +317,285 @@ class SubscriptionProcessor {
310
317
  Object.values(this.schema.namespaces).forEach(namespace => {
311
318
  Object.values(namespace.models)
312
319
  .filter(({ syncable }) => syncable)
313
- .forEach(async modelDefinition => {
314
- const modelAuthModes = await getModelAuthModes({
315
- authModeStrategy: this.authModeStrategy,
316
- defaultAuthMode:
317
- this.amplifyConfig.aws_appsync_authenticationType,
318
- modelName: modelDefinition.name,
319
- schema: this.schema,
320
- });
321
-
322
- // subscriptions are created only based on the READ auth mode(s)
323
- const readAuthModes = modelAuthModes.READ;
324
-
325
- subscriptions = {
326
- ...subscriptions,
327
- [modelDefinition.name]: {
328
- [TransformerMutationType.CREATE]: [],
329
- [TransformerMutationType.UPDATE]: [],
330
- [TransformerMutationType.DELETE]: [],
331
- },
332
- };
333
-
334
- const operations = [
335
- TransformerMutationType.CREATE,
336
- TransformerMutationType.UPDATE,
337
- TransformerMutationType.DELETE,
338
- ];
339
-
340
- const operationAuthModeAttempts = {
341
- [TransformerMutationType.CREATE]: 0,
342
- [TransformerMutationType.UPDATE]: 0,
343
- [TransformerMutationType.DELETE]: 0,
344
- };
345
-
346
- // Retry failed subscriptions with next auth mode (if available)
347
- const authModeRetry = async operation => {
348
- const {
349
- opType: transformerMutationType,
350
- opName,
351
- query,
352
- isOwner,
353
- ownerField,
354
- ownerValue,
355
- authMode,
356
- } = this.buildSubscription(
357
- namespace,
358
- modelDefinition,
359
- operation,
360
- userCredentials,
361
- cognitoTokenPayload,
362
- oidcTokenPayload,
363
- readAuthModes[operationAuthModeAttempts[operation]]
364
- );
365
-
366
- const authToken = await getTokenForCustomAuth(
367
- authMode,
368
- this.amplifyConfig
369
- );
370
-
371
- const variables = {};
372
-
373
- if (isOwner) {
374
- if (!ownerValue) {
375
- observer.error(
376
- 'Owner field required, sign in is needed in order to perform this operation'
320
+ .forEach(
321
+ modelDefinition =>
322
+ this.runningProcesses.isOpen &&
323
+ this.runningProcesses.add(async () => {
324
+ const modelAuthModes = await getModelAuthModes({
325
+ authModeStrategy: this.authModeStrategy,
326
+ defaultAuthMode:
327
+ this.amplifyConfig.aws_appsync_authenticationType,
328
+ modelName: modelDefinition.name,
329
+ schema: this.schema,
330
+ });
331
+
332
+ // subscriptions are created only based on the READ auth mode(s)
333
+ const readAuthModes = modelAuthModes.READ;
334
+
335
+ subscriptions = {
336
+ ...subscriptions,
337
+ [modelDefinition.name]: {
338
+ [TransformerMutationType.CREATE]: [],
339
+ [TransformerMutationType.UPDATE]: [],
340
+ [TransformerMutationType.DELETE]: [],
341
+ },
342
+ };
343
+
344
+ const operations = [
345
+ TransformerMutationType.CREATE,
346
+ TransformerMutationType.UPDATE,
347
+ TransformerMutationType.DELETE,
348
+ ];
349
+
350
+ const operationAuthModeAttempts = {
351
+ [TransformerMutationType.CREATE]: 0,
352
+ [TransformerMutationType.UPDATE]: 0,
353
+ [TransformerMutationType.DELETE]: 0,
354
+ };
355
+
356
+ // Retry failed subscriptions with next auth mode (if available)
357
+ const authModeRetry = async operation => {
358
+ const {
359
+ opType: transformerMutationType,
360
+ opName,
361
+ query,
362
+ isOwner,
363
+ ownerField,
364
+ ownerValue,
365
+ authMode,
366
+ } = this.buildSubscription(
367
+ namespace,
368
+ modelDefinition,
369
+ operation,
370
+ userCredentials,
371
+ cognitoTokenPayload,
372
+ oidcTokenPayload,
373
+ readAuthModes[operationAuthModeAttempts[operation]]
377
374
  );
378
- return;
379
- }
380
-
381
- variables[ownerField] = ownerValue;
382
- }
383
-
384
- logger.debug(
385
- `Attempting ${operation} subscription with authMode: ${
386
- readAuthModes[operationAuthModeAttempts[operation]]
387
- }`
388
- );
389
-
390
- const userAgentSuffix = USER_AGENT_SUFFIX_DATASTORE;
391
-
392
- const queryObservable = <
393
- Observable<{
394
- value: GraphQLResult<Record<string, PersistentModel>>;
395
- }>
396
-
397
- >(<unknown>this.amplifyContext.API.graphql({ query, variables, ...{ authMode }, authToken, userAgentSuffix }));
398
-
399
- let subscriptionReadyCallback: () => void;
400
-
401
- subscriptions[modelDefinition.name][
402
- transformerMutationType
403
- ].push(
404
- queryObservable
405
- .map(({ value }) => {
406
- return value;
407
- })
408
- .subscribe({
409
- next: ({ data, errors }) => {
410
- if (Array.isArray(errors) && errors.length > 0) {
411
- const messages = (<
412
- {
413
- message: string;
414
- }[]
415
- >errors).map(({ message }) => message);
416
-
417
- logger.warn(
418
- `Skipping incoming subscription. Messages: ${messages.join(
419
- '\n'
420
- )}`
421
- );
422
375
 
423
- this.drainBuffer();
424
- return;
425
- }
376
+ const authToken = await getTokenForCustomAuth(
377
+ authMode,
378
+ this.amplifyConfig
379
+ );
426
380
 
427
- const predicatesGroup =
428
- ModelPredicateCreator.getPredicates(
429
- this.syncPredicates.get(modelDefinition),
430
- false
431
- );
381
+ const variables = {};
432
382
 
433
- const { [opName]: record } = data;
434
-
435
- // checking incoming subscription against syncPredicate.
436
- // once AppSync implements filters on subscriptions, we'll be
437
- // able to set these when establishing the subscription instead.
438
- // Until then, we'll need to filter inbound
439
- if (
440
- this.passesPredicateValidation(
441
- record,
442
- predicatesGroup
443
- )
444
- ) {
445
- this.pushToBuffer(
446
- transformerMutationType,
447
- modelDefinition,
448
- record
449
- );
450
- }
451
- this.drainBuffer();
452
- },
453
- error: async subscriptionError => {
454
- const {
455
- error: { errors: [{ message = '' } = {}] } = {
456
- errors: [],
383
+ if (isOwner) {
384
+ if (!ownerValue) {
385
+ observer.error(
386
+ 'Owner field required, sign in is needed in order to perform this operation'
387
+ );
388
+ return;
389
+ }
390
+
391
+ variables[ownerField] = ownerValue;
392
+ }
393
+
394
+ logger.debug(
395
+ `Attempting ${operation} subscription with authMode: ${
396
+ readAuthModes[operationAuthModeAttempts[operation]]
397
+ }`
398
+ );
399
+
400
+ const userAgentSuffix = USER_AGENT_SUFFIX_DATASTORE;
401
+
402
+ const queryObservable = <
403
+ Observable<{
404
+ value: GraphQLResult<Record<string, PersistentModel>>;
405
+ }>
406
+ >(<unknown>this.amplifyContext.API.graphql({
407
+ query,
408
+ variables,
409
+ ...{ authMode },
410
+ authToken,
411
+ userAgentSuffix,
412
+ }));
413
+
414
+ let subscriptionReadyCallback: () => void;
415
+
416
+ // TODO: consider onTerminate.then(() => API.cancel(...))
417
+
418
+ subscriptions[modelDefinition.name][
419
+ transformerMutationType
420
+ ].push(
421
+ queryObservable
422
+ .map(({ value }) => {
423
+ return value;
424
+ })
425
+ .subscribe({
426
+ next: ({ data, errors }) => {
427
+ if (Array.isArray(errors) && errors.length > 0) {
428
+ const messages = (<
429
+ {
430
+ message: string;
431
+ }[]
432
+ >errors).map(({ message }) => message);
433
+
434
+ logger.warn(
435
+ `Skipping incoming subscription. Messages: ${messages.join(
436
+ '\n'
437
+ )}`
438
+ );
439
+
440
+ this.drainBuffer();
441
+ return;
442
+ }
443
+
444
+ const predicatesGroup =
445
+ ModelPredicateCreator.getPredicates(
446
+ this.syncPredicates.get(modelDefinition),
447
+ false
448
+ );
449
+
450
+ const { [opName]: record } = data;
451
+
452
+ // checking incoming subscription against syncPredicate.
453
+ // once AppSync implements filters on subscriptions, we'll be
454
+ // able to set these when establishing the subscription instead.
455
+ // Until then, we'll need to filter inbound
456
+ if (
457
+ this.passesPredicateValidation(
458
+ record,
459
+ predicatesGroup
460
+ )
461
+ ) {
462
+ this.pushToBuffer(
463
+ transformerMutationType,
464
+ modelDefinition,
465
+ record
466
+ );
467
+ }
468
+ this.drainBuffer();
469
+ },
470
+ error: async subscriptionError => {
471
+ const {
472
+ error: { errors: [{ message = '' } = {}] } = {
473
+ errors: [],
474
+ },
475
+ } = subscriptionError;
476
+
477
+ if (
478
+ message.includes(
479
+ PUBSUB_CONTROL_MSG.REALTIME_SUBSCRIPTION_INIT_ERROR
480
+ ) ||
481
+ message.includes(
482
+ PUBSUB_CONTROL_MSG.CONNECTION_FAILED
483
+ )
484
+ ) {
485
+ // Unsubscribe and clear subscription array for model/operation
486
+ subscriptions[modelDefinition.name][
487
+ transformerMutationType
488
+ ].forEach(subscription =>
489
+ subscription.unsubscribe()
490
+ );
491
+ subscriptions[modelDefinition.name][
492
+ transformerMutationType
493
+ ] = [];
494
+
495
+ operationAuthModeAttempts[operation]++;
496
+ if (
497
+ operationAuthModeAttempts[operation] >=
498
+ readAuthModes.length
499
+ ) {
500
+ // last auth mode retry. Continue with error
501
+ logger.debug(
502
+ `${operation} subscription failed with authMode: ${
503
+ readAuthModes[
504
+ operationAuthModeAttempts[operation] - 1
505
+ ]
506
+ }`
507
+ );
508
+ } else {
509
+ // retry with different auth mode. Do not trigger
510
+ // observer error or error handler
511
+ logger.debug(
512
+ `${operation} subscription failed with authMode: ${
513
+ readAuthModes[
514
+ operationAuthModeAttempts[operation] - 1
515
+ ]
516
+ }. Retrying with authMode: ${
517
+ readAuthModes[
518
+ operationAuthModeAttempts[operation]
519
+ ]
520
+ }`
521
+ );
522
+ authModeRetry(operation);
523
+ return;
524
+ }
525
+ }
526
+ logger.warn('subscriptionError', message);
527
+
528
+ try {
529
+ await this.errorHandler({
530
+ recoverySuggestion:
531
+ 'Ensure app code is up to date, auth directives exist and are correct on each model, and that server-side data has not been invalidated by a schema change. If the problem persists, search for or create an issue: https://github.com/aws-amplify/amplify-js/issues',
532
+ localModel: null,
533
+ message,
534
+ model: modelDefinition.name,
535
+ operation,
536
+ errorType:
537
+ getSubscriptionErrorType(subscriptionError),
538
+ process: ProcessName.subscribe,
539
+ remoteModel: null,
540
+ cause: subscriptionError,
541
+ });
542
+ } catch (e) {
543
+ logger.error(
544
+ 'Subscription error handler failed with:',
545
+ e
546
+ );
547
+ }
548
+
549
+ if (
550
+ typeof subscriptionReadyCallback === 'function'
551
+ ) {
552
+ subscriptionReadyCallback();
553
+ }
554
+
555
+ if (
556
+ message.includes('"errorType":"Unauthorized"') ||
557
+ message.includes(
558
+ '"errorType":"OperationDisabled"'
559
+ )
560
+ ) {
561
+ return;
562
+ }
563
+ observer.error(message);
457
564
  },
458
- } = subscriptionError;
459
-
460
- if (
461
- message.includes(
462
- PUBSUB_CONTROL_MSG.REALTIME_SUBSCRIPTION_INIT_ERROR
463
- ) ||
464
- message.includes(PUBSUB_CONTROL_MSG.CONNECTION_FAILED)
465
- ) {
466
- // Unsubscribe and clear subscription array for model/operation
467
- subscriptions[modelDefinition.name][
468
- transformerMutationType
469
- ].forEach(subscription => subscription.unsubscribe());
470
- subscriptions[modelDefinition.name][
471
- transformerMutationType
472
- ] = [];
473
-
474
- operationAuthModeAttempts[operation]++;
475
- if (
476
- operationAuthModeAttempts[operation] >=
477
- readAuthModes.length
478
- ) {
479
- // last auth mode retry. Continue with error
480
- logger.debug(
481
- `${operation} subscription failed with authMode: ${
482
- readAuthModes[
483
- operationAuthModeAttempts[operation] - 1
484
- ]
485
- }`
486
- );
487
- } else {
488
- // retry with different auth mode. Do not trigger
489
- // observer error or error handler
490
- logger.debug(
491
- `${operation} subscription failed with authMode: ${
492
- readAuthModes[
493
- operationAuthModeAttempts[operation] - 1
494
- ]
495
- }. Retrying with authMode: ${
496
- readAuthModes[
497
- operationAuthModeAttempts[operation]
498
- ]
499
- }`
500
- );
501
- authModeRetry(operation);
502
- return;
503
- }
504
- }
505
- logger.warn('subscriptionError', message);
506
-
507
- try {
508
- await this.errorHandler({
509
- recoverySuggestion:
510
- 'Ensure app code is up to date, auth directives exist and are correct on each model, and that server-side data has not been invalidated by a schema change. If the problem persists, search for or create an issue: https://github.com/aws-amplify/amplify-js/issues',
511
- localModel: null,
512
- message,
513
- model: modelDefinition.name,
514
- operation,
515
- errorType:
516
- getSubscriptionErrorType(subscriptionError),
517
- process: ProcessName.subscribe,
518
- remoteModel: null,
519
- cause: subscriptionError,
520
- });
521
- } catch (e) {
522
- logger.error(
523
- 'Subscription error handler failed with:',
524
- e
565
+ })
566
+ );
567
+
568
+ promises.push(
569
+ (async () => {
570
+ let boundFunction: any;
571
+
572
+ await new Promise(res => {
573
+ subscriptionReadyCallback = res;
574
+ boundFunction = this.hubQueryCompletionListener.bind(
575
+ this,
576
+ res
525
577
  );
526
- }
527
-
528
- if (typeof subscriptionReadyCallback === 'function') {
529
- subscriptionReadyCallback();
530
- }
531
-
532
- if (
533
- message.includes('"errorType":"Unauthorized"') ||
534
- message.includes('"errorType":"OperationDisabled"')
535
- ) {
536
- return;
537
- }
538
- observer.error(message);
539
- },
540
- })
541
- );
542
-
543
- promises.push(
544
- (async () => {
545
- let boundFunction: any;
546
-
547
- await new Promise(res => {
548
- subscriptionReadyCallback = res;
549
- boundFunction = this.hubQueryCompletionListener.bind(
550
- this,
551
- res
552
- );
553
- Hub.listen('api', boundFunction);
554
- });
555
- Hub.remove('api', boundFunction);
556
- })()
557
- );
558
- };
559
-
560
- operations.forEach(op => authModeRetry(op));
561
- });
578
+ Hub.listen('api', boundFunction);
579
+ });
580
+ Hub.remove('api', boundFunction);
581
+ })()
582
+ );
583
+ };
584
+
585
+ operations.forEach(op => authModeRetry(op));
586
+ })
587
+ );
562
588
  });
563
589
 
564
- Promise.all(promises).then(() => observer.next(CONTROL_MSG.CONNECTED));
565
- })();
590
+ this.runningProcesses.isOpen &&
591
+ this.runningProcesses.add(() =>
592
+ Promise.all(promises).then(() => {
593
+ observer.next(CONTROL_MSG.CONNECTED);
594
+ })
595
+ );
596
+ }, 'subscription processor new subscriber');
566
597
 
567
- return () => {
598
+ return this.runningProcesses.addCleaner(async () => {
568
599
  Object.keys(subscriptions).forEach(modelName => {
569
600
  subscriptions[modelName][TransformerMutationType.CREATE].forEach(
570
601
  subscription => subscription.unsubscribe()
@@ -576,7 +607,7 @@ class SubscriptionProcessor {
576
607
  subscription => subscription.unsubscribe()
577
608
  );
578
609
  });
579
- };
610
+ });
580
611
  });
581
612
 
582
613
  const dataObservable = new Observable<
@@ -585,14 +616,19 @@ class SubscriptionProcessor {
585
616
  this.dataObserver = observer;
586
617
  this.drainBuffer();
587
618
 
588
- return () => {
619
+ return this.runningProcesses.addCleaner(async () => {
589
620
  this.dataObserver = null;
590
- };
621
+ });
591
622
  });
592
623
 
593
624
  return [ctlObservable, dataObservable];
594
625
  }
595
626
 
627
+ public async stop() {
628
+ await this.runningProcesses.close();
629
+ await this.runningProcesses.open();
630
+ }
631
+
596
632
  private passesPredicateValidation(
597
633
  record: PersistentModel,
598
634
  predicatesGroup: PredicatesGroup<any>