@aws-amplify/datastore 3.14.1-unstable.2 → 3.14.1

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 (111) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/aws-amplify-datastore.js +2798 -1458
  3. package/dist/aws-amplify-datastore.js.map +1 -1
  4. package/dist/aws-amplify-datastore.min.js +10 -10
  5. package/dist/aws-amplify-datastore.min.js.map +1 -1
  6. package/lib/authModeStrategies/multiAuthStrategy.js +11 -0
  7. package/lib/authModeStrategies/multiAuthStrategy.js.map +1 -1
  8. package/lib/datastore/datastore.js +524 -323
  9. package/lib/datastore/datastore.js.map +1 -1
  10. package/lib/storage/adapter/IndexedDBAdapter.js +76 -25
  11. package/lib/storage/adapter/IndexedDBAdapter.js.map +1 -1
  12. package/lib/storage/storage.js +2 -2
  13. package/lib/storage/storage.js.map +1 -1
  14. package/lib/sync/datastoreConnectivity.js +45 -0
  15. package/lib/sync/datastoreConnectivity.js.map +1 -1
  16. package/lib/sync/index.js +518 -395
  17. package/lib/sync/index.js.map +1 -1
  18. package/lib/sync/merger.js +6 -0
  19. package/lib/sync/merger.js.map +1 -1
  20. package/lib/sync/outbox.js +66 -62
  21. package/lib/sync/outbox.js.map +1 -1
  22. package/lib/sync/processors/mutation.js +207 -165
  23. package/lib/sync/processors/mutation.js.map +1 -1
  24. package/lib/sync/processors/subscription.js +210 -175
  25. package/lib/sync/processors/subscription.js.map +1 -1
  26. package/lib/sync/processors/sync.js +95 -72
  27. package/lib/sync/processors/sync.js.map +1 -1
  28. package/lib/sync/utils.js +1 -3
  29. package/lib/sync/utils.js.map +1 -1
  30. package/lib/util.js +89 -0
  31. package/lib/util.js.map +1 -1
  32. package/lib-esm/authModeStrategies/multiAuthStrategy.d.ts +11 -0
  33. package/lib-esm/authModeStrategies/multiAuthStrategy.js +11 -0
  34. package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +1 -1
  35. package/lib-esm/datastore/datastore.d.ts +95 -2
  36. package/lib-esm/datastore/datastore.js +524 -323
  37. package/lib-esm/datastore/datastore.js.map +1 -1
  38. package/lib-esm/storage/adapter/IndexedDBAdapter.d.ts +21 -0
  39. package/lib-esm/storage/adapter/IndexedDBAdapter.js +77 -26
  40. package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +1 -1
  41. package/lib-esm/storage/storage.js +2 -2
  42. package/lib-esm/storage/storage.js.map +1 -1
  43. package/lib-esm/sync/datastoreConnectivity.d.ts +1 -0
  44. package/lib-esm/sync/datastoreConnectivity.js +45 -0
  45. package/lib-esm/sync/datastoreConnectivity.js.map +1 -1
  46. package/lib-esm/sync/index.d.ts +9 -1
  47. package/lib-esm/sync/index.js +519 -396
  48. package/lib-esm/sync/index.js.map +1 -1
  49. package/lib-esm/sync/merger.d.ts +6 -0
  50. package/lib-esm/sync/merger.js +6 -0
  51. package/lib-esm/sync/merger.js.map +1 -1
  52. package/lib-esm/sync/outbox.js +66 -62
  53. package/lib-esm/sync/outbox.js.map +1 -1
  54. package/lib-esm/sync/processors/mutation.d.ts +2 -0
  55. package/lib-esm/sync/processors/mutation.js +208 -166
  56. package/lib-esm/sync/processors/mutation.js.map +1 -1
  57. package/lib-esm/sync/processors/subscription.d.ts +2 -0
  58. package/lib-esm/sync/processors/subscription.js +211 -176
  59. package/lib-esm/sync/processors/subscription.js.map +1 -1
  60. package/lib-esm/sync/processors/sync.d.ts +2 -0
  61. package/lib-esm/sync/processors/sync.js +96 -73
  62. package/lib-esm/sync/processors/sync.js.map +1 -1
  63. package/lib-esm/sync/utils.js +1 -3
  64. package/lib-esm/sync/utils.js.map +1 -1
  65. package/lib-esm/util.d.ts +11 -0
  66. package/lib-esm/util.js +89 -0
  67. package/lib-esm/util.js.map +1 -1
  68. package/package.json +7 -7
  69. package/src/authModeStrategies/multiAuthStrategy.ts +11 -0
  70. package/src/datastore/datastore.ts +572 -366
  71. package/src/storage/adapter/IndexedDBAdapter.ts +50 -9
  72. package/src/storage/storage.ts +2 -2
  73. package/src/sync/datastoreConnectivity.ts +6 -0
  74. package/src/sync/index.ts +492 -400
  75. package/src/sync/merger.ts +6 -0
  76. package/src/sync/outbox.ts +1 -1
  77. package/src/sync/processors/mutation.ts +139 -104
  78. package/src/sync/processors/subscription.ts +287 -250
  79. package/src/sync/processors/sync.ts +88 -60
  80. package/src/sync/utils.ts +1 -3
  81. package/src/util.ts +92 -2
  82. package/lib/authModeStrategies/defaultAuthStrategy.d.ts +0 -2
  83. package/lib/authModeStrategies/index.d.ts +0 -2
  84. package/lib/authModeStrategies/multiAuthStrategy.d.ts +0 -2
  85. package/lib/datastore/datastore.d.ts +0 -63
  86. package/lib/index.d.ts +0 -15
  87. package/lib/predicates/index.d.ts +0 -16
  88. package/lib/predicates/sort.d.ts +0 -8
  89. package/lib/ssr/index.d.ts +0 -3
  90. package/lib/storage/adapter/AsyncStorageAdapter.d.ts +0 -41
  91. package/lib/storage/adapter/AsyncStorageDatabase.d.ts +0 -39
  92. package/lib/storage/adapter/InMemoryStore.d.ts +0 -11
  93. package/lib/storage/adapter/InMemoryStore.native.d.ts +0 -1
  94. package/lib/storage/adapter/IndexedDBAdapter.d.ts +0 -38
  95. package/lib/storage/adapter/getDefaultAdapter/index.d.ts +0 -3
  96. package/lib/storage/adapter/getDefaultAdapter/index.native.d.ts +0 -3
  97. package/lib/storage/adapter/index.d.ts +0 -9
  98. package/lib/storage/storage.d.ts +0 -49
  99. package/lib/sync/datastoreConnectivity.d.ts +0 -15
  100. package/lib/sync/datastoreReachability/index.d.ts +0 -3
  101. package/lib/sync/datastoreReachability/index.native.d.ts +0 -3
  102. package/lib/sync/index.d.ts +0 -81
  103. package/lib/sync/merger.d.ts +0 -11
  104. package/lib/sync/outbox.d.ts +0 -27
  105. package/lib/sync/processors/errorMaps.d.ts +0 -17
  106. package/lib/sync/processors/mutation.d.ts +0 -56
  107. package/lib/sync/processors/subscription.d.ts +0 -31
  108. package/lib/sync/processors/sync.d.ts +0 -26
  109. package/lib/sync/utils.d.ts +0 -42
  110. package/lib/types.d.ts +0 -501
  111. package/lib/util.d.ts +0 -145
@@ -1,7 +1,12 @@
1
1
  import API, { GraphQLResult, GRAPHQL_AUTH_MODE } from '@aws-amplify/api';
2
2
  import { Auth } from '@aws-amplify/auth';
3
3
  import Cache from '@aws-amplify/cache';
4
- import { ConsoleLogger as Logger, Hub, HubCapsule } from '@aws-amplify/core';
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,260 +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
- >(<unknown>this.amplifyContext.API.graphql({ query, variables, ...{ authMode }, authToken, userAgentSuffix }));
397
-
398
- let subscriptionReadyCallback: () => void;
399
-
400
- subscriptions[modelDefinition.name][
401
- transformerMutationType
402
- ].push(
403
- queryObservable
404
- .map(({ value }) => {
405
- return value;
406
- })
407
- .subscribe({
408
- next: ({ data, errors }) => {
409
- if (Array.isArray(errors) && errors.length > 0) {
410
- const messages = (<
411
- {
412
- message: string;
413
- }[]
414
- >errors).map(({ message }) => message);
415
-
416
- logger.warn(
417
- `Skipping incoming subscription. Messages: ${messages.join(
418
- '\n'
419
- )}`
420
- );
421
375
 
422
- this.drainBuffer();
423
- return;
424
- }
376
+ const authToken = await getTokenForCustomAuth(
377
+ authMode,
378
+ this.amplifyConfig
379
+ );
425
380
 
426
- const predicatesGroup =
427
- ModelPredicateCreator.getPredicates(
428
- this.syncPredicates.get(modelDefinition),
429
- false
430
- );
381
+ const variables = {};
431
382
 
432
- const { [opName]: record } = data;
433
-
434
- // checking incoming subscription against syncPredicate.
435
- // once AppSync implements filters on subscriptions, we'll be
436
- // able to set these when establishing the subscription instead.
437
- // Until then, we'll need to filter inbound
438
- if (
439
- this.passesPredicateValidation(
440
- record,
441
- predicatesGroup
442
- )
443
- ) {
444
- this.pushToBuffer(
445
- transformerMutationType,
446
- modelDefinition,
447
- record
448
- );
449
- }
450
- this.drainBuffer();
451
- },
452
- error: async subscriptionError => {
453
- const {
454
- error: { errors: [{ message = '' } = {}] } = {
455
- 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);
456
564
  },
457
- } = subscriptionError;
458
-
459
- if (
460
- message.includes(
461
- PUBSUB_CONTROL_MSG.REALTIME_SUBSCRIPTION_INIT_ERROR
462
- ) ||
463
- message.includes(PUBSUB_CONTROL_MSG.CONNECTION_FAILED)
464
- ) {
465
- // Unsubscribe and clear subscription array for model/operation
466
- subscriptions[modelDefinition.name][
467
- transformerMutationType
468
- ].forEach(subscription => subscription.unsubscribe());
469
- subscriptions[modelDefinition.name][
470
- transformerMutationType
471
- ] = [];
472
-
473
- operationAuthModeAttempts[operation]++;
474
- if (
475
- operationAuthModeAttempts[operation] >=
476
- readAuthModes.length
477
- ) {
478
- // last auth mode retry. Continue with error
479
- logger.debug(
480
- `${operation} subscription failed with authMode: ${
481
- readAuthModes[
482
- operationAuthModeAttempts[operation] - 1
483
- ]
484
- }`
485
- );
486
- } else {
487
- // retry with different auth mode. Do not trigger
488
- // observer error or error handler
489
- logger.debug(
490
- `${operation} subscription failed with authMode: ${
491
- readAuthModes[
492
- operationAuthModeAttempts[operation] - 1
493
- ]
494
- }. Retrying with authMode: ${
495
- readAuthModes[
496
- operationAuthModeAttempts[operation]
497
- ]
498
- }`
499
- );
500
- authModeRetry(operation);
501
- return;
502
- }
503
- }
504
- logger.warn('subscriptionError', message);
505
-
506
- try {
507
- await this.errorHandler({
508
- recoverySuggestion:
509
- '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',
510
- localModel: null,
511
- message,
512
- model: modelDefinition.name,
513
- operation,
514
- errorType:
515
- getSubscriptionErrorType(subscriptionError),
516
- process: ProcessName.subscribe,
517
- remoteModel: null,
518
- cause: subscriptionError,
519
- });
520
- } catch (e) {
521
- logger.error(
522
- 'Subscription error handler failed with:',
523
- 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
524
577
  );
525
- }
526
-
527
- if (typeof subscriptionReadyCallback === 'function') {
528
- subscriptionReadyCallback();
529
- }
530
-
531
- if (
532
- message.includes('"errorType":"Unauthorized"') ||
533
- message.includes('"errorType":"OperationDisabled"')
534
- ) {
535
- return;
536
- }
537
- observer.error(message);
538
- },
539
- })
540
- );
541
-
542
- promises.push(
543
- (async () => {
544
- let boundFunction: any;
545
-
546
- await new Promise(res => {
547
- subscriptionReadyCallback = res;
548
- boundFunction = this.hubQueryCompletionListener.bind(
549
- this,
550
- res
551
- );
552
- Hub.listen('api', boundFunction);
553
- });
554
- Hub.remove('api', boundFunction);
555
- })()
556
- );
557
- };
558
-
559
- operations.forEach(op => authModeRetry(op));
560
- });
578
+ Hub.listen('api', boundFunction);
579
+ });
580
+ Hub.remove('api', boundFunction);
581
+ })()
582
+ );
583
+ };
584
+
585
+ operations.forEach(op => authModeRetry(op));
586
+ })
587
+ );
561
588
  });
562
589
 
563
- Promise.all(promises).then(() => observer.next(CONTROL_MSG.CONNECTED));
564
- })();
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');
565
597
 
566
- return () => {
598
+ return this.runningProcesses.addCleaner(async () => {
567
599
  Object.keys(subscriptions).forEach(modelName => {
568
600
  subscriptions[modelName][TransformerMutationType.CREATE].forEach(
569
601
  subscription => subscription.unsubscribe()
@@ -575,7 +607,7 @@ class SubscriptionProcessor {
575
607
  subscription => subscription.unsubscribe()
576
608
  );
577
609
  });
578
- };
610
+ });
579
611
  });
580
612
 
581
613
  const dataObservable = new Observable<
@@ -584,14 +616,19 @@ class SubscriptionProcessor {
584
616
  this.dataObserver = observer;
585
617
  this.drainBuffer();
586
618
 
587
- return () => {
619
+ return this.runningProcesses.addCleaner(async () => {
588
620
  this.dataObserver = null;
589
- };
621
+ });
590
622
  });
591
623
 
592
624
  return [ctlObservable, dataObservable];
593
625
  }
594
626
 
627
+ public async stop() {
628
+ await this.runningProcesses.close();
629
+ await this.runningProcesses.open();
630
+ }
631
+
595
632
  private passesPredicateValidation(
596
633
  record: PersistentModel,
597
634
  predicatesGroup: PredicatesGroup<any>