@aws-amplify/datastore 3.12.6-next.20 → 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 (144) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/lib/authModeStrategies/multiAuthStrategy.js +13 -2
  3. package/lib/authModeStrategies/multiAuthStrategy.js.map +1 -1
  4. package/lib/datastore/datastore.js +648 -344
  5. package/lib/datastore/datastore.js.map +1 -1
  6. package/lib/predicates/index.js +12 -2
  7. package/lib/predicates/index.js.map +1 -1
  8. package/lib/storage/adapter/AsyncStorageAdapter.js +354 -203
  9. package/lib/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  10. package/lib/storage/adapter/AsyncStorageDatabase.js +65 -28
  11. package/lib/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  12. package/lib/storage/adapter/IndexedDBAdapter.js +444 -271
  13. package/lib/storage/adapter/IndexedDBAdapter.js.map +1 -1
  14. package/lib/storage/storage.js +93 -28
  15. package/lib/storage/storage.js.map +1 -1
  16. package/lib/sync/datastoreConnectivity.js +9 -0
  17. package/lib/sync/datastoreConnectivity.js.map +1 -1
  18. package/lib/sync/index.js +522 -397
  19. package/lib/sync/index.js.map +1 -1
  20. package/lib/sync/merger.js +13 -6
  21. package/lib/sync/merger.js.map +1 -1
  22. package/lib/sync/outbox.js +77 -71
  23. package/lib/sync/outbox.js.map +1 -1
  24. package/lib/sync/processors/mutation.js +269 -209
  25. package/lib/sync/processors/mutation.js.map +1 -1
  26. package/lib/sync/processors/subscription.js +213 -178
  27. package/lib/sync/processors/subscription.js.map +1 -1
  28. package/lib/sync/processors/sync.js +126 -121
  29. package/lib/sync/processors/sync.js.map +1 -1
  30. package/lib/sync/utils.js +43 -8
  31. package/lib/sync/utils.js.map +1 -1
  32. package/lib/types.js +10 -1
  33. package/lib/types.js.map +1 -1
  34. package/lib/util.js +419 -166
  35. package/lib/util.js.map +1 -1
  36. package/lib-esm/authModeStrategies/multiAuthStrategy.d.ts +11 -0
  37. package/lib-esm/authModeStrategies/multiAuthStrategy.js +12 -1
  38. package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +1 -1
  39. package/lib-esm/datastore/datastore.d.ts +107 -17
  40. package/lib-esm/datastore/datastore.js +648 -344
  41. package/lib-esm/datastore/datastore.js.map +1 -1
  42. package/lib-esm/index.d.ts +3 -19
  43. package/lib-esm/predicates/index.d.ts +3 -2
  44. package/lib-esm/predicates/index.js +13 -3
  45. package/lib-esm/predicates/index.js.map +1 -1
  46. package/lib-esm/storage/adapter/AsyncStorageAdapter.d.ts +4 -3
  47. package/lib-esm/storage/adapter/AsyncStorageAdapter.js +355 -204
  48. package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  49. package/lib-esm/storage/adapter/AsyncStorageDatabase.d.ts +14 -4
  50. package/lib-esm/storage/adapter/AsyncStorageDatabase.js +66 -29
  51. package/lib-esm/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  52. package/lib-esm/storage/adapter/IndexedDBAdapter.d.ts +26 -4
  53. package/lib-esm/storage/adapter/IndexedDBAdapter.js +445 -272
  54. package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +1 -1
  55. package/lib-esm/storage/adapter/index.d.ts +1 -1
  56. package/lib-esm/storage/storage.d.ts +1 -1
  57. package/lib-esm/storage/storage.js +93 -28
  58. package/lib-esm/storage/storage.js.map +1 -1
  59. package/lib-esm/sync/datastoreConnectivity.d.ts +1 -0
  60. package/lib-esm/sync/datastoreConnectivity.js +10 -1
  61. package/lib-esm/sync/datastoreConnectivity.js.map +1 -1
  62. package/lib-esm/sync/index.d.ts +31 -5
  63. package/lib-esm/sync/index.js +524 -399
  64. package/lib-esm/sync/index.js.map +1 -1
  65. package/lib-esm/sync/merger.d.ts +9 -3
  66. package/lib-esm/sync/merger.js +13 -6
  67. package/lib-esm/sync/merger.js.map +1 -1
  68. package/lib-esm/sync/outbox.d.ts +2 -2
  69. package/lib-esm/sync/outbox.js +78 -72
  70. package/lib-esm/sync/outbox.js.map +1 -1
  71. package/lib-esm/sync/processors/mutation.d.ts +2 -0
  72. package/lib-esm/sync/processors/mutation.js +270 -210
  73. package/lib-esm/sync/processors/mutation.js.map +1 -1
  74. package/lib-esm/sync/processors/subscription.d.ts +2 -0
  75. package/lib-esm/sync/processors/subscription.js +213 -178
  76. package/lib-esm/sync/processors/subscription.js.map +1 -1
  77. package/lib-esm/sync/processors/sync.d.ts +2 -1
  78. package/lib-esm/sync/processors/sync.js +126 -121
  79. package/lib-esm/sync/processors/sync.js.map +1 -1
  80. package/lib-esm/sync/utils.d.ts +3 -2
  81. package/lib-esm/sync/utils.js +45 -11
  82. package/lib-esm/sync/utils.js.map +1 -1
  83. package/lib-esm/types.d.ts +65 -26
  84. package/lib-esm/types.js +9 -2
  85. package/lib-esm/types.js.map +1 -1
  86. package/lib-esm/util.d.ts +67 -24
  87. package/lib-esm/util.js +419 -166
  88. package/lib-esm/util.js.map +1 -1
  89. package/package.json +13 -7
  90. package/src/authModeStrategies/multiAuthStrategy.ts +12 -1
  91. package/src/datastore/datastore.ts +798 -397
  92. package/src/predicates/index.ts +32 -10
  93. package/src/storage/adapter/AsyncStorageAdapter.ts +309 -93
  94. package/src/storage/adapter/AsyncStorageDatabase.ts +74 -26
  95. package/src/storage/adapter/IndexedDBAdapter.ts +358 -134
  96. package/src/storage/adapter/index.ts +1 -1
  97. package/src/storage/storage.ts +69 -22
  98. package/src/sync/datastoreConnectivity.ts +6 -0
  99. package/src/sync/index.ts +521 -412
  100. package/src/sync/merger.ts +20 -4
  101. package/src/sync/outbox.ts +22 -9
  102. package/src/sync/processors/mutation.ts +188 -150
  103. package/src/sync/processors/subscription.ts +289 -253
  104. package/src/sync/processors/sync.ts +151 -138
  105. package/src/sync/utils.ts +67 -12
  106. package/src/types.ts +182 -30
  107. package/src/util.ts +505 -176
  108. package/build.js +0 -5
  109. package/dist/aws-amplify-datastore.js +0 -83311
  110. package/dist/aws-amplify-datastore.js.map +0 -1
  111. package/dist/aws-amplify-datastore.min.js +0 -168
  112. package/dist/aws-amplify-datastore.min.js.map +0 -1
  113. package/index.js +0 -7
  114. package/lib/authModeStrategies/defaultAuthStrategy.d.ts +0 -2
  115. package/lib/authModeStrategies/index.d.ts +0 -2
  116. package/lib/authModeStrategies/multiAuthStrategy.d.ts +0 -2
  117. package/lib/datastore/datastore.d.ts +0 -66
  118. package/lib/index.d.ts +0 -31
  119. package/lib/predicates/index.d.ts +0 -15
  120. package/lib/predicates/sort.d.ts +0 -8
  121. package/lib/ssr/index.d.ts +0 -3
  122. package/lib/storage/adapter/AsyncStorageAdapter.d.ts +0 -40
  123. package/lib/storage/adapter/AsyncStorageDatabase.d.ts +0 -29
  124. package/lib/storage/adapter/InMemoryStore.d.ts +0 -11
  125. package/lib/storage/adapter/InMemoryStore.native.d.ts +0 -1
  126. package/lib/storage/adapter/IndexedDBAdapter.d.ts +0 -37
  127. package/lib/storage/adapter/getDefaultAdapter/index.d.ts +0 -3
  128. package/lib/storage/adapter/getDefaultAdapter/index.native.d.ts +0 -3
  129. package/lib/storage/adapter/index.d.ts +0 -9
  130. package/lib/storage/storage.d.ts +0 -49
  131. package/lib/sync/datastoreConnectivity.d.ts +0 -15
  132. package/lib/sync/datastoreReachability/index.d.ts +0 -3
  133. package/lib/sync/datastoreReachability/index.native.d.ts +0 -3
  134. package/lib/sync/index.d.ts +0 -63
  135. package/lib/sync/merger.d.ts +0 -11
  136. package/lib/sync/outbox.d.ts +0 -27
  137. package/lib/sync/processors/errorMaps.d.ts +0 -17
  138. package/lib/sync/processors/mutation.d.ts +0 -56
  139. package/lib/sync/processors/subscription.d.ts +0 -31
  140. package/lib/sync/processors/sync.d.ts +0 -27
  141. package/lib/sync/utils.d.ts +0 -41
  142. package/lib/types.d.ts +0 -462
  143. package/lib/util.d.ts +0 -113
  144. 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>