@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,5 +1,5 @@
1
1
  import { __awaiter, __generator, __read, __spread, __values } from "tslib";
2
- import { browserOrNode, ConsoleLogger as Logger } from '@aws-amplify/core';
2
+ import { browserOrNode, ConsoleLogger as Logger, BackgroundProcessManager, } from '@aws-amplify/core';
3
3
  import { CONTROL_MSG as PUBSUB_CONTROL_MSG } from '@aws-amplify/pubsub';
4
4
  import Observable from 'zen-observable-ts';
5
5
  import { ModelPredicateCreator } from '../predicates';
@@ -11,7 +11,7 @@ import { MutationEventOutbox } from './outbox';
11
11
  import { MutationProcessor } from './processors/mutation';
12
12
  import { CONTROL_MSG, SubscriptionProcessor } from './processors/subscription';
13
13
  import { SyncProcessor } from './processors/sync';
14
- import { createMutationInstanceFromModelOperation, predicateToGraphQLCondition, } from './utils';
14
+ import { createMutationInstanceFromModelOperation, getIdentifierValue, predicateToGraphQLCondition, } from './utils';
15
15
  var isNode = browserOrNode().isNode;
16
16
  var logger = new Logger('DataStore');
17
17
  var ownSymbol = Symbol('sync');
@@ -29,7 +29,7 @@ export var ControlMessage;
29
29
  ControlMessage["SYNC_ENGINE_READY"] = "ready";
30
30
  })(ControlMessage || (ControlMessage = {}));
31
31
  var SyncEngine = /** @class */ (function () {
32
- function SyncEngine(schema, namespaceResolver, modelClasses, userModelClasses, storage, modelInstanceCreator, conflictHandler, errorHandler, syncPredicates, amplifyConfig, authModeStrategy, amplifyContext) {
32
+ function SyncEngine(schema, namespaceResolver, modelClasses, userModelClasses, storage, modelInstanceCreator, conflictHandler, errorHandler, syncPredicates, amplifyConfig, authModeStrategy, amplifyContext, connectivityMonitor) {
33
33
  if (amplifyConfig === void 0) { amplifyConfig = {}; }
34
34
  this.schema = schema;
35
35
  this.namespaceResolver = namespaceResolver;
@@ -41,15 +41,18 @@ var SyncEngine = /** @class */ (function () {
41
41
  this.amplifyConfig = amplifyConfig;
42
42
  this.authModeStrategy = authModeStrategy;
43
43
  this.amplifyContext = amplifyContext;
44
+ this.connectivityMonitor = connectivityMonitor;
44
45
  this.online = false;
45
46
  this.modelSyncedStatus = new WeakMap();
47
+ this.runningProcesses = new BackgroundProcessManager();
46
48
  var MutationEvent = this.modelClasses['MutationEvent'];
47
49
  this.outbox = new MutationEventOutbox(this.schema, MutationEvent, modelInstanceCreator, ownSymbol);
48
50
  this.modelMerger = new ModelMerger(this.outbox, ownSymbol);
49
51
  this.syncQueriesProcessor = new SyncProcessor(this.schema, this.syncPredicates, this.amplifyConfig, this.authModeStrategy, errorHandler, this.amplifyContext);
50
52
  this.subscriptionsProcessor = new SubscriptionProcessor(this.schema, this.syncPredicates, this.amplifyConfig, this.authModeStrategy, errorHandler, this.amplifyContext);
51
53
  this.mutationsProcessor = new MutationProcessor(this.schema, this.storage, this.userModelClasses, this.outbox, this.modelInstanceCreator, MutationEvent, this.amplifyConfig, this.authModeStrategy, errorHandler, conflictHandler, this.amplifyContext);
52
- this.datastoreConnectivity = new DataStoreConnectivity();
54
+ this.datastoreConnectivity =
55
+ this.connectivityMonitor || new DataStoreConnectivity();
53
56
  }
54
57
  SyncEngine.prototype.getModelSyncedStatus = function (modelConstructor) {
55
58
  return this.modelSyncedStatus.get(modelConstructor);
@@ -59,7 +62,7 @@ var SyncEngine = /** @class */ (function () {
59
62
  return new Observable(function (observer) {
60
63
  logger.log('starting sync engine...');
61
64
  var subscriptions = [];
62
- (function () { return __awaiter(_this, void 0, void 0, function () {
65
+ _this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
63
66
  var err_1, startPromise, hasMutationsInOutbox;
64
67
  var _this = this;
65
68
  return __generator(this, function (_a) {
@@ -75,154 +78,188 @@ var SyncEngine = /** @class */ (function () {
75
78
  observer.error(err_1);
76
79
  return [2 /*return*/];
77
80
  case 3:
78
- startPromise = new Promise(function (resolve) {
81
+ startPromise = new Promise(function (doneStarting, failedStarting) {
79
82
  _this.datastoreConnectivity.status().subscribe(function (_a) {
80
83
  var online = _a.online;
81
84
  return __awaiter(_this, void 0, void 0, function () {
82
- var ctlSubsObservable_1, dataSubsObservable, err_2, error_1;
83
- var _b;
84
85
  var _this = this;
85
- return __generator(this, function (_c) {
86
- switch (_c.label) {
87
- case 0:
88
- if (!(online && !this.online)) return [3 /*break*/, 10];
89
- this.online = online;
90
- observer.next({
91
- type: ControlMessage.SYNC_ENGINE_NETWORK_STATUS,
92
- data: {
93
- active: this.online,
94
- },
95
- });
96
- dataSubsObservable = void 0;
97
- if (!isNode) return [3 /*break*/, 1];
98
- logger.warn('Realtime disabled when in a server-side environment');
99
- return [3 /*break*/, 6];
100
- case 1:
101
- //#region GraphQL Subscriptions
102
- _b = __read(this.subscriptionsProcessor.start(), 2),
103
- // const ctlObservable: Observable<CONTROL_MSG>
104
- ctlSubsObservable_1 = _b[0],
105
- // const dataObservable: Observable<[TransformerMutationType, SchemaModel, Readonly<{
106
- // id: string;
107
- // } & Record<string, any>>]>
108
- dataSubsObservable = _b[1];
109
- _c.label = 2;
110
- case 2:
111
- _c.trys.push([2, 4, , 5]);
112
- return [4 /*yield*/, new Promise(function (resolve, reject) {
113
- var ctlSubsSubscription = ctlSubsObservable_1.subscribe({
114
- next: function (msg) {
115
- if (msg === CONTROL_MSG.CONNECTED) {
116
- resolve();
86
+ return __generator(this, function (_b) {
87
+ return [2 /*return*/, this.runningProcesses.isOpen &&
88
+ this.runningProcesses.add(function (onTerminate) { return __awaiter(_this, void 0, void 0, function () {
89
+ var ctlSubsObservable_1, dataSubsObservable, err_2, error_1;
90
+ var _a;
91
+ var _this = this;
92
+ return __generator(this, function (_b) {
93
+ switch (_b.label) {
94
+ case 0:
95
+ if (!(online && !this.online)) return [3 /*break*/, 10];
96
+ this.online = online;
97
+ observer.next({
98
+ type: ControlMessage.SYNC_ENGINE_NETWORK_STATUS,
99
+ data: {
100
+ active: this.online,
101
+ },
102
+ });
103
+ dataSubsObservable = void 0;
104
+ if (!isNode) return [3 /*break*/, 1];
105
+ logger.warn('Realtime disabled when in a server-side environment');
106
+ return [3 /*break*/, 6];
107
+ case 1:
108
+ //#region GraphQL Subscriptions
109
+ _a = __read(this.subscriptionsProcessor.start(), 2),
110
+ // const ctlObservable: Observable<CONTROL_MSG>
111
+ ctlSubsObservable_1 = _a[0],
112
+ // const dataObservable: Observable<[TransformerMutationType, SchemaModel, Readonly<{
113
+ // id: string;
114
+ // } & Record<string, any>>]>
115
+ dataSubsObservable = _a[1];
116
+ _b.label = 2;
117
+ case 2:
118
+ _b.trys.push([2, 4, , 5]);
119
+ return [4 /*yield*/, new Promise(function (resolve, reject) {
120
+ onTerminate.then(reject);
121
+ var ctlSubsSubscription = ctlSubsObservable_1.subscribe({
122
+ next: function (msg) {
123
+ if (msg === CONTROL_MSG.CONNECTED) {
124
+ resolve();
125
+ }
126
+ },
127
+ error: function (err) {
128
+ reject(err);
129
+ var handleDisconnect = _this.disconnectionHandler();
130
+ handleDisconnect(err);
131
+ },
132
+ });
133
+ subscriptions.push(ctlSubsSubscription);
134
+ })];
135
+ case 3:
136
+ _b.sent();
137
+ return [3 /*break*/, 5];
138
+ case 4:
139
+ err_2 = _b.sent();
140
+ observer.error(err_2);
141
+ failedStarting();
142
+ return [2 /*return*/];
143
+ case 5:
144
+ logger.log('Realtime ready');
145
+ observer.next({
146
+ type: ControlMessage.SYNC_ENGINE_SUBSCRIPTIONS_ESTABLISHED,
147
+ });
148
+ _b.label = 6;
149
+ case 6:
150
+ _b.trys.push([6, 8, , 9]);
151
+ return [4 /*yield*/, new Promise(function (resolve, reject) {
152
+ var syncQuerySubscription = _this.syncQueriesObservable().subscribe({
153
+ next: function (message) {
154
+ var type = message.type;
155
+ if (type ===
156
+ ControlMessage.SYNC_ENGINE_SYNC_QUERIES_READY) {
157
+ resolve();
158
+ }
159
+ observer.next(message);
160
+ },
161
+ complete: function () {
162
+ resolve();
163
+ },
164
+ error: function (error) {
165
+ reject(error);
166
+ },
167
+ });
168
+ if (syncQuerySubscription) {
169
+ subscriptions.push(syncQuerySubscription);
170
+ }
171
+ })];
172
+ case 7:
173
+ _b.sent();
174
+ return [3 /*break*/, 9];
175
+ case 8:
176
+ error_1 = _b.sent();
177
+ observer.error(error_1);
178
+ failedStarting();
179
+ return [2 /*return*/];
180
+ case 9:
181
+ //#endregion
182
+ //#region process mutations (outbox)
183
+ subscriptions.push(this.mutationsProcessor
184
+ .start()
185
+ .subscribe(function (_a) {
186
+ var modelDefinition = _a.modelDefinition, item = _a.model, hasMore = _a.hasMore;
187
+ return _this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
188
+ var modelConstructor, model;
189
+ var _this = this;
190
+ return __generator(this, function (_a) {
191
+ switch (_a.label) {
192
+ case 0:
193
+ modelConstructor = this.userModelClasses[modelDefinition.name];
194
+ model = this.modelInstanceCreator(modelConstructor, item);
195
+ return [4 /*yield*/, this.storage.runExclusive(function (storage) {
196
+ return _this.modelMerger.merge(storage, model, modelDefinition);
197
+ })];
198
+ case 1:
199
+ _a.sent();
200
+ observer.next({
201
+ type: ControlMessage.SYNC_ENGINE_OUTBOX_MUTATION_PROCESSED,
202
+ data: {
203
+ model: modelConstructor,
204
+ element: model,
205
+ },
206
+ });
207
+ observer.next({
208
+ type: ControlMessage.SYNC_ENGINE_OUTBOX_STATUS,
209
+ data: {
210
+ isEmpty: !hasMore,
211
+ },
212
+ });
213
+ return [2 /*return*/];
214
+ }
215
+ });
216
+ }); }, 'mutation processor event');
217
+ }));
218
+ //#endregion
219
+ //#region Merge subscriptions buffer
220
+ // TODO: extract to function
221
+ if (!isNode) {
222
+ subscriptions.push(dataSubsObservable.subscribe(function (_a) {
223
+ var _b = __read(_a, 3), _transformerMutationType = _b[0], modelDefinition = _b[1], item = _b[2];
224
+ return _this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
225
+ var modelConstructor, model;
226
+ var _this = this;
227
+ return __generator(this, function (_a) {
228
+ switch (_a.label) {
229
+ case 0:
230
+ modelConstructor = this.userModelClasses[modelDefinition.name];
231
+ model = this.modelInstanceCreator(modelConstructor, item);
232
+ return [4 /*yield*/, this.storage.runExclusive(function (storage) {
233
+ return _this.modelMerger.merge(storage, model, modelDefinition);
234
+ })];
235
+ case 1:
236
+ _a.sent();
237
+ return [2 /*return*/];
238
+ }
239
+ });
240
+ }); }, 'subscription dataSubsObservable event');
241
+ }));
117
242
  }
118
- },
119
- error: function (err) {
120
- reject(err);
121
- var handleDisconnect = _this.disconnectionHandler();
122
- handleDisconnect(err);
123
- },
124
- });
125
- subscriptions.push(ctlSubsSubscription);
126
- })];
127
- case 3:
128
- _c.sent();
129
- return [3 /*break*/, 5];
130
- case 4:
131
- err_2 = _c.sent();
132
- observer.error(err_2);
133
- return [2 /*return*/];
134
- case 5:
135
- logger.log('Realtime ready');
136
- observer.next({
137
- type: ControlMessage.SYNC_ENGINE_SUBSCRIPTIONS_ESTABLISHED,
138
- });
139
- _c.label = 6;
140
- case 6:
141
- _c.trys.push([6, 8, , 9]);
142
- return [4 /*yield*/, new Promise(function (resolve, reject) {
143
- var syncQuerySubscription = _this.syncQueriesObservable().subscribe({
144
- next: function (message) {
145
- var type = message.type;
146
- if (type === ControlMessage.SYNC_ENGINE_SYNC_QUERIES_READY) {
147
- resolve();
243
+ return [3 /*break*/, 11];
244
+ case 10:
245
+ if (!online) {
246
+ this.online = online;
247
+ observer.next({
248
+ type: ControlMessage.SYNC_ENGINE_NETWORK_STATUS,
249
+ data: {
250
+ active: this.online,
251
+ },
252
+ });
253
+ subscriptions.forEach(function (sub) { return sub.unsubscribe(); });
254
+ subscriptions = [];
148
255
  }
149
- observer.next(message);
150
- },
151
- complete: function () {
152
- resolve();
153
- },
154
- error: function (error) {
155
- reject(error);
156
- },
157
- });
158
- if (syncQuerySubscription) {
159
- subscriptions.push(syncQuerySubscription);
256
+ _b.label = 11;
257
+ case 11:
258
+ doneStarting();
259
+ return [2 /*return*/];
160
260
  }
161
- })];
162
- case 7:
163
- _c.sent();
164
- return [3 /*break*/, 9];
165
- case 8:
166
- error_1 = _c.sent();
167
- observer.error(error_1);
168
- return [2 /*return*/];
169
- case 9:
170
- //#endregion
171
- //#region process mutations
172
- subscriptions.push(this.mutationsProcessor
173
- .start()
174
- .subscribe(function (_a) {
175
- var modelDefinition = _a.modelDefinition, item = _a.model, hasMore = _a.hasMore;
176
- var modelConstructor = _this.userModelClasses[modelDefinition.name];
177
- var model = _this.modelInstanceCreator(modelConstructor, item);
178
- _this.storage.runExclusive(function (storage) {
179
- return _this.modelMerger.merge(storage, model);
180
- });
181
- observer.next({
182
- type: ControlMessage.SYNC_ENGINE_OUTBOX_MUTATION_PROCESSED,
183
- data: {
184
- model: modelConstructor,
185
- element: model,
186
- },
187
- });
188
- observer.next({
189
- type: ControlMessage.SYNC_ENGINE_OUTBOX_STATUS,
190
- data: {
191
- isEmpty: !hasMore,
192
- },
193
261
  });
194
- }));
195
- //#endregion
196
- //#region Merge subscriptions buffer
197
- // TODO: extract to function
198
- if (!isNode) {
199
- subscriptions.push(dataSubsObservable.subscribe(function (_a) {
200
- var _b = __read(_a, 3), _transformerMutationType = _b[0], modelDefinition = _b[1], item = _b[2];
201
- var modelConstructor = _this.userModelClasses[modelDefinition.name];
202
- var model = _this.modelInstanceCreator(modelConstructor, item);
203
- _this.storage.runExclusive(function (storage) {
204
- return _this.modelMerger.merge(storage, model);
205
- });
206
- }));
207
- }
208
- return [3 /*break*/, 11];
209
- case 10:
210
- if (!online) {
211
- this.online = online;
212
- observer.next({
213
- type: ControlMessage.SYNC_ENGINE_NETWORK_STATUS,
214
- data: {
215
- active: this.online,
216
- },
217
- });
218
- subscriptions.forEach(function (sub) { return sub.unsubscribe(); });
219
- subscriptions = [];
220
- }
221
- _c.label = 11;
222
- case 11:
223
- resolve();
224
- return [2 /*return*/];
225
- }
262
+ }); }, 'datastore connectivity event')];
226
263
  });
227
264
  });
228
265
  });
@@ -238,38 +275,44 @@ var SyncEngine = /** @class */ (function () {
238
275
  next: function (_a) {
239
276
  var opType = _a.opType, model = _a.model, element = _a.element, condition = _a.condition;
240
277
  return __awaiter(_this, void 0, void 0, function () {
241
- var namespace, MutationEventConstructor, graphQLCondition, mutationEvent;
278
+ var _this = this;
242
279
  return __generator(this, function (_b) {
243
- switch (_b.label) {
244
- case 0:
245
- namespace = this.schema.namespaces[this.namespaceResolver(model)];
246
- MutationEventConstructor = this.modelClasses['MutationEvent'];
247
- graphQLCondition = predicateToGraphQLCondition(condition);
248
- mutationEvent = createMutationInstanceFromModelOperation(namespace.relationships, this.getModelDefinition(model), opType, model, element, graphQLCondition, MutationEventConstructor, this.modelInstanceCreator);
249
- return [4 /*yield*/, this.outbox.enqueue(this.storage, mutationEvent)];
250
- case 1:
251
- _b.sent();
252
- observer.next({
253
- type: ControlMessage.SYNC_ENGINE_OUTBOX_MUTATION_ENQUEUED,
254
- data: {
255
- model: model,
256
- element: element,
257
- },
258
- });
259
- observer.next({
260
- type: ControlMessage.SYNC_ENGINE_OUTBOX_STATUS,
261
- data: {
262
- isEmpty: false,
263
- },
280
+ return [2 /*return*/, this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
281
+ var namespace, MutationEventConstructor, modelDefinition, graphQLCondition, mutationEvent;
282
+ return __generator(this, function (_a) {
283
+ switch (_a.label) {
284
+ case 0:
285
+ namespace = this.schema.namespaces[this.namespaceResolver(model)];
286
+ MutationEventConstructor = this.modelClasses['MutationEvent'];
287
+ modelDefinition = this.getModelDefinition(model);
288
+ graphQLCondition = predicateToGraphQLCondition(condition, modelDefinition);
289
+ mutationEvent = createMutationInstanceFromModelOperation(namespace.relationships, this.getModelDefinition(model), opType, model, element, graphQLCondition, MutationEventConstructor, this.modelInstanceCreator);
290
+ return [4 /*yield*/, this.outbox.enqueue(this.storage, mutationEvent)];
291
+ case 1:
292
+ _a.sent();
293
+ observer.next({
294
+ type: ControlMessage.SYNC_ENGINE_OUTBOX_MUTATION_ENQUEUED,
295
+ data: {
296
+ model: model,
297
+ element: element,
298
+ },
299
+ });
300
+ observer.next({
301
+ type: ControlMessage.SYNC_ENGINE_OUTBOX_STATUS,
302
+ data: {
303
+ isEmpty: false,
304
+ },
305
+ });
306
+ return [4 /*yield*/, startPromise];
307
+ case 2:
308
+ _a.sent();
309
+ if (this.online) {
310
+ this.mutationsProcessor.resume();
311
+ }
312
+ return [2 /*return*/];
313
+ }
264
314
  });
265
- return [4 /*yield*/, startPromise];
266
- case 2:
267
- _b.sent();
268
- if (this.online) {
269
- this.mutationsProcessor.resume();
270
- }
271
- return [2 /*return*/];
272
- }
315
+ }); }, 'storage event')];
273
316
  });
274
317
  });
275
318
  },
@@ -295,10 +338,7 @@ var SyncEngine = /** @class */ (function () {
295
338
  return [2 /*return*/];
296
339
  }
297
340
  });
298
- }); })();
299
- return function () {
300
- subscriptions.forEach(function (sub) { return sub.unsubscribe(); });
301
- };
341
+ }); }, 'sync start');
302
342
  });
303
343
  };
304
344
  SyncEngine.prototype.getModelsMetadataWithNextFullSync = function (currentTimeStamp) {
@@ -309,7 +349,7 @@ var SyncEngine = /** @class */ (function () {
309
349
  switch (_b.label) {
310
350
  case 0:
311
351
  _a = Map.bind;
312
- return [4 /*yield*/, this.getModelsMetadata()];
352
+ return [4 /*yield*/, this.runningProcesses.add(function () { return _this.getModelsMetadata(); }, 'sync/index getModelsMetadataWithNextFullSync')];
313
353
  case 1:
314
354
  modelLastSync = new (_a.apply(Map, [void 0, (_b.sent()).map(function (_a) {
315
355
  var namespace = _a.namespace, model = _a.model, lastSync = _a.lastSync, lastFullSync = _a.lastFullSync, fullSyncInterval = _a.fullSyncInterval, lastSyncPredicate = _a.lastSyncPredicate;
@@ -334,227 +374,261 @@ var SyncEngine = /** @class */ (function () {
334
374
  }
335
375
  return new Observable(function (observer) {
336
376
  var syncQueriesSubscription;
337
- var waitTimeoutId;
338
- (function () { return __awaiter(_this, void 0, void 0, function () {
339
- var _loop_1, this_1;
340
- var _this = this;
341
- return __generator(this, function (_a) {
342
- switch (_a.label) {
343
- case 0:
344
- _loop_1 = function () {
345
- var count, modelLastSync, paginatingModels, newestFullSyncStartedAt, theInterval, start, duration, newestStartedAt, msNextFullSync;
346
- return __generator(this, function (_a) {
347
- switch (_a.label) {
348
- case 0:
349
- count = new WeakMap();
350
- return [4 /*yield*/, this_1.getModelsMetadataWithNextFullSync(Date.now())];
351
- case 1:
352
- modelLastSync = _a.sent();
353
- paginatingModels = new Set(modelLastSync.keys());
354
- return [4 /*yield*/, new Promise(function (resolve) {
355
- syncQueriesSubscription = _this.syncQueriesProcessor
356
- .start(modelLastSync)
357
- .subscribe({
358
- next: function (_a) {
359
- var namespace = _a.namespace, modelDefinition = _a.modelDefinition, items = _a.items, done = _a.done, startedAt = _a.startedAt, isFullSync = _a.isFullSync;
360
- return __awaiter(_this, void 0, void 0, function () {
361
- var modelConstructor, modelName, modelMetadata_1, lastFullSync, fullSyncInterval, counts;
362
- var _this = this;
363
- return __generator(this, function (_b) {
364
- switch (_b.label) {
365
- case 0:
366
- modelConstructor = this.userModelClasses[modelDefinition.name];
367
- if (!count.has(modelConstructor)) {
368
- count.set(modelConstructor, {
369
- new: 0,
370
- updated: 0,
371
- deleted: 0,
372
- });
373
- start = getNow();
374
- newestStartedAt =
375
- newestStartedAt === undefined
376
- ? startedAt
377
- : Math.max(newestStartedAt, startedAt);
378
- }
379
- /**
380
- * If there are mutations in the outbox for a given id, those need to be
381
- * merged individually. Otherwise, we can merge them in batches.
382
- */
383
- return [4 /*yield*/, this.storage.runExclusive(function (storage) { return __awaiter(_this, void 0, void 0, function () {
384
- var idsInOutbox, oneByOne, page, opTypeCount, oneByOne_1, oneByOne_1_1, item, opType, e_1_1, _a, _b, _c, counts;
385
- var e_1, _d;
386
- return __generator(this, function (_e) {
387
- switch (_e.label) {
388
- case 0: return [4 /*yield*/, this.outbox.getModelIds(storage)];
389
- case 1:
390
- idsInOutbox = _e.sent();
391
- oneByOne = [];
392
- page = items.filter(function (item) {
393
- if (!idsInOutbox.has(item.id)) {
394
- return true;
377
+ _this.runningProcesses.isOpen &&
378
+ _this.runningProcesses.add(function (onTerminate) { return __awaiter(_this, void 0, void 0, function () {
379
+ var terminated, _loop_1, this_1;
380
+ var _this = this;
381
+ return __generator(this, function (_a) {
382
+ switch (_a.label) {
383
+ case 0:
384
+ terminated = false;
385
+ _loop_1 = function () {
386
+ var count, modelLastSync, paginatingModels, newestFullSyncStartedAt, theInterval, start, duration, newestStartedAt, msNextFullSync;
387
+ return __generator(this, function (_a) {
388
+ switch (_a.label) {
389
+ case 0:
390
+ count = new WeakMap();
391
+ return [4 /*yield*/, this_1.getModelsMetadataWithNextFullSync(Date.now())];
392
+ case 1:
393
+ modelLastSync = _a.sent();
394
+ paginatingModels = new Set(modelLastSync.keys());
395
+ return [4 /*yield*/, new Promise(function (resolve, reject) {
396
+ if (!_this.runningProcesses.isOpen)
397
+ resolve();
398
+ onTerminate.then(function () { return resolve(); });
399
+ syncQueriesSubscription = _this.syncQueriesProcessor
400
+ .start(modelLastSync)
401
+ .subscribe({
402
+ next: function (_a) {
403
+ var namespace = _a.namespace, modelDefinition = _a.modelDefinition, items = _a.items, done = _a.done, startedAt = _a.startedAt, isFullSync = _a.isFullSync;
404
+ return __awaiter(_this, void 0, void 0, function () {
405
+ var modelConstructor, modelName, modelMetadata_1, lastFullSync, fullSyncInterval, counts;
406
+ var _this = this;
407
+ return __generator(this, function (_b) {
408
+ switch (_b.label) {
409
+ case 0:
410
+ modelConstructor = this.userModelClasses[modelDefinition.name];
411
+ if (!count.has(modelConstructor)) {
412
+ count.set(modelConstructor, {
413
+ new: 0,
414
+ updated: 0,
415
+ deleted: 0,
416
+ });
417
+ start = getNow();
418
+ newestStartedAt =
419
+ newestStartedAt === undefined
420
+ ? startedAt
421
+ : Math.max(newestStartedAt, startedAt);
422
+ }
423
+ /**
424
+ * If there are mutations in the outbox for a given id, those need to be
425
+ * merged individually. Otherwise, we can merge them in batches.
426
+ */
427
+ return [4 /*yield*/, this.storage.runExclusive(function (storage) { return __awaiter(_this, void 0, void 0, function () {
428
+ var idsInOutbox, oneByOne, page, opTypeCount, oneByOne_1, oneByOne_1_1, item, opType, e_1_1, _a, _b, _c, counts;
429
+ var e_1, _d;
430
+ return __generator(this, function (_e) {
431
+ switch (_e.label) {
432
+ case 0: return [4 /*yield*/, this.outbox.getModelIds(storage)];
433
+ case 1:
434
+ idsInOutbox = _e.sent();
435
+ oneByOne = [];
436
+ page = items.filter(function (item) {
437
+ var itemId = getIdentifierValue(modelDefinition, item);
438
+ if (!idsInOutbox.has(itemId)) {
439
+ return true;
440
+ }
441
+ oneByOne.push(item);
442
+ return false;
443
+ });
444
+ opTypeCount = [];
445
+ _e.label = 2;
446
+ case 2:
447
+ _e.trys.push([2, 7, 8, 9]);
448
+ oneByOne_1 = __values(oneByOne), oneByOne_1_1 = oneByOne_1.next();
449
+ _e.label = 3;
450
+ case 3:
451
+ if (!!oneByOne_1_1.done) return [3 /*break*/, 6];
452
+ item = oneByOne_1_1.value;
453
+ return [4 /*yield*/, this.modelMerger.merge(storage, item, modelDefinition)];
454
+ case 4:
455
+ opType = _e.sent();
456
+ if (opType !== undefined) {
457
+ opTypeCount.push([item, opType]);
395
458
  }
396
- oneByOne.push(item);
397
- return false;
398
- });
399
- opTypeCount = [];
400
- _e.label = 2;
401
- case 2:
402
- _e.trys.push([2, 7, 8, 9]);
403
- oneByOne_1 = __values(oneByOne), oneByOne_1_1 = oneByOne_1.next();
404
- _e.label = 3;
405
- case 3:
406
- if (!!oneByOne_1_1.done) return [3 /*break*/, 6];
407
- item = oneByOne_1_1.value;
408
- return [4 /*yield*/, this.modelMerger.merge(storage, item)];
409
- case 4:
410
- opType = _e.sent();
411
- if (opType !== undefined) {
412
- opTypeCount.push([item, opType]);
413
- }
414
- _e.label = 5;
415
- case 5:
416
- oneByOne_1_1 = oneByOne_1.next();
417
- return [3 /*break*/, 3];
418
- case 6: return [3 /*break*/, 9];
419
- case 7:
420
- e_1_1 = _e.sent();
421
- e_1 = { error: e_1_1 };
422
- return [3 /*break*/, 9];
423
- case 8:
424
- try {
425
- if (oneByOne_1_1 && !oneByOne_1_1.done && (_d = oneByOne_1.return)) _d.call(oneByOne_1);
426
- }
427
- finally { if (e_1) throw e_1.error; }
428
- return [7 /*endfinally*/];
429
- case 9:
430
- _b = (_a = opTypeCount.push).apply;
431
- _c = [opTypeCount];
432
- return [4 /*yield*/, this.modelMerger.mergePage(storage, modelConstructor, page)];
433
- case 10:
434
- _b.apply(_a, _c.concat([__spread.apply(void 0, [(_e.sent())])]));
435
- counts = count.get(modelConstructor);
436
- opTypeCount.forEach(function (_a) {
437
- var _b = __read(_a, 2), opType = _b[1];
438
- switch (opType) {
439
- case OpType.INSERT:
440
- counts.new++;
441
- break;
442
- case OpType.UPDATE:
443
- counts.updated++;
444
- break;
445
- case OpType.DELETE:
446
- counts.deleted++;
447
- break;
448
- default:
449
- exhaustiveCheck(opType);
459
+ _e.label = 5;
460
+ case 5:
461
+ oneByOne_1_1 = oneByOne_1.next();
462
+ return [3 /*break*/, 3];
463
+ case 6: return [3 /*break*/, 9];
464
+ case 7:
465
+ e_1_1 = _e.sent();
466
+ e_1 = { error: e_1_1 };
467
+ return [3 /*break*/, 9];
468
+ case 8:
469
+ try {
470
+ if (oneByOne_1_1 && !oneByOne_1_1.done && (_d = oneByOne_1.return)) _d.call(oneByOne_1);
450
471
  }
451
- });
452
- return [2 /*return*/];
453
- }
454
- });
455
- }); })];
456
- case 1:
457
- /**
458
- * If there are mutations in the outbox for a given id, those need to be
459
- * merged individually. Otherwise, we can merge them in batches.
460
- */
461
- _b.sent();
462
- if (!done) return [3 /*break*/, 4];
463
- modelName = modelDefinition.name;
464
- return [4 /*yield*/, this.getModelMetadata(namespace, modelName)];
465
- case 2:
466
- modelMetadata_1 = _b.sent();
467
- lastFullSync = modelMetadata_1.lastFullSync, fullSyncInterval = modelMetadata_1.fullSyncInterval;
468
- theInterval = fullSyncInterval;
469
- newestFullSyncStartedAt =
470
- newestFullSyncStartedAt === undefined
471
- ? lastFullSync
472
- : Math.max(newestFullSyncStartedAt, isFullSync ? startedAt : lastFullSync);
473
- modelMetadata_1 = this.modelClasses
474
- .ModelMetadata.copyOf(modelMetadata_1, function (draft) {
475
- draft.lastSync = startedAt;
476
- draft.lastFullSync = isFullSync
477
- ? startedAt
478
- : modelMetadata_1.lastFullSync;
479
- });
480
- return [4 /*yield*/, this.storage.save(modelMetadata_1, undefined, ownSymbol)];
481
- case 3:
482
- _b.sent();
483
- counts = count.get(modelConstructor);
484
- this.modelSyncedStatus.set(modelConstructor, true);
485
- observer.next({
486
- type: ControlMessage.SYNC_ENGINE_MODEL_SYNCED,
487
- data: {
488
- model: modelConstructor,
489
- isFullSync: isFullSync,
490
- isDeltaSync: !isFullSync,
491
- counts: counts,
492
- },
493
- });
494
- paginatingModels.delete(modelDefinition);
495
- if (paginatingModels.size === 0) {
496
- duration = getNow() - start;
497
- resolve();
472
+ finally { if (e_1) throw e_1.error; }
473
+ return [7 /*endfinally*/];
474
+ case 9:
475
+ _b = (_a = opTypeCount.push).apply;
476
+ _c = [opTypeCount];
477
+ return [4 /*yield*/, this.modelMerger.mergePage(storage, modelConstructor, page, modelDefinition)];
478
+ case 10:
479
+ _b.apply(_a, _c.concat([__spread.apply(void 0, [(_e.sent())])]));
480
+ counts = count.get(modelConstructor);
481
+ opTypeCount.forEach(function (_a) {
482
+ var _b = __read(_a, 2), opType = _b[1];
483
+ switch (opType) {
484
+ case OpType.INSERT:
485
+ counts.new++;
486
+ break;
487
+ case OpType.UPDATE:
488
+ counts.updated++;
489
+ break;
490
+ case OpType.DELETE:
491
+ counts.deleted++;
492
+ break;
493
+ default:
494
+ exhaustiveCheck(opType);
495
+ }
496
+ });
497
+ return [2 /*return*/];
498
+ }
499
+ });
500
+ }); })];
501
+ case 1:
502
+ /**
503
+ * If there are mutations in the outbox for a given id, those need to be
504
+ * merged individually. Otherwise, we can merge them in batches.
505
+ */
506
+ _b.sent();
507
+ if (!done) return [3 /*break*/, 4];
508
+ modelName = modelDefinition.name;
509
+ return [4 /*yield*/, this.getModelMetadata(namespace, modelName)];
510
+ case 2:
511
+ modelMetadata_1 = _b.sent();
512
+ lastFullSync = modelMetadata_1.lastFullSync, fullSyncInterval = modelMetadata_1.fullSyncInterval;
513
+ theInterval = fullSyncInterval;
514
+ newestFullSyncStartedAt =
515
+ newestFullSyncStartedAt === undefined
516
+ ? lastFullSync
517
+ : Math.max(newestFullSyncStartedAt, isFullSync ? startedAt : lastFullSync);
518
+ modelMetadata_1 = this.modelClasses
519
+ .ModelMetadata.copyOf(modelMetadata_1, function (draft) {
520
+ draft.lastSync = startedAt;
521
+ draft.lastFullSync = isFullSync
522
+ ? startedAt
523
+ : modelMetadata_1.lastFullSync;
524
+ });
525
+ return [4 /*yield*/, this.storage.save(modelMetadata_1, undefined, ownSymbol)];
526
+ case 3:
527
+ _b.sent();
528
+ counts = count.get(modelConstructor);
529
+ this.modelSyncedStatus.set(modelConstructor, true);
498
530
  observer.next({
499
- type: ControlMessage.SYNC_ENGINE_SYNC_QUERIES_READY,
531
+ type: ControlMessage.SYNC_ENGINE_MODEL_SYNCED,
532
+ data: {
533
+ model: modelConstructor,
534
+ isFullSync: isFullSync,
535
+ isDeltaSync: !isFullSync,
536
+ counts: counts,
537
+ },
500
538
  });
501
- syncQueriesSubscription.unsubscribe();
502
- }
503
- _b.label = 4;
504
- case 4: return [2 /*return*/];
505
- }
539
+ paginatingModels.delete(modelDefinition);
540
+ if (paginatingModels.size === 0) {
541
+ duration = getNow() - start;
542
+ resolve();
543
+ observer.next({
544
+ type: ControlMessage.SYNC_ENGINE_SYNC_QUERIES_READY,
545
+ });
546
+ syncQueriesSubscription.unsubscribe();
547
+ }
548
+ _b.label = 4;
549
+ case 4: return [2 /*return*/];
550
+ }
551
+ });
506
552
  });
553
+ },
554
+ error: function (error) {
555
+ observer.error(error);
556
+ },
557
+ });
558
+ observer.next({
559
+ type: ControlMessage.SYNC_ENGINE_SYNC_QUERIES_STARTED,
560
+ data: {
561
+ models: Array.from(paginatingModels).map(function (_a) {
562
+ var name = _a.name;
563
+ return name;
564
+ }),
565
+ },
566
+ });
567
+ })];
568
+ case 2:
569
+ _a.sent();
570
+ msNextFullSync = newestFullSyncStartedAt +
571
+ theInterval -
572
+ (newestStartedAt + duration);
573
+ logger.debug("Next fullSync in " + msNextFullSync / 1000 + " seconds. (" + new Date(Date.now() + msNextFullSync) + ")");
574
+ // TODO: create `BackgroundProcessManager.sleep()` ... but, need to put
575
+ // a lot of thought into what that contract looks like to
576
+ // support possible use-cases:
577
+ //
578
+ // 1. non-cancelable
579
+ // 2. cancelable, unsleep on exit()
580
+ // 3. cancelable, throw Error on exit()
581
+ // 4. cancelable, callback first on exit()?
582
+ // 5. ... etc. ? ...
583
+ //
584
+ // TLDR; this is a lot of complexity here for a sleep(),
585
+ // but, it's not clear to me yet how to support an
586
+ // extensible, centralized cancelable `sleep()` elegantly.
587
+ return [4 /*yield*/, this_1.runningProcesses.add(function (onTerminate) { return __awaiter(_this, void 0, void 0, function () {
588
+ var sleepTimer, unsleep, sleep;
589
+ return __generator(this, function (_a) {
590
+ sleep = new Promise(function (_unsleep) {
591
+ unsleep = _unsleep;
592
+ sleepTimer = setTimeout(unsleep, msNextFullSync);
507
593
  });
508
- },
509
- error: function (error) {
510
- observer.error(error);
511
- },
512
- });
513
- observer.next({
514
- type: ControlMessage.SYNC_ENGINE_SYNC_QUERIES_STARTED,
515
- data: {
516
- models: Array.from(paginatingModels).map(function (_a) {
517
- var name = _a.name;
518
- return name;
519
- }),
520
- },
521
- });
522
- })];
523
- case 2:
524
- _a.sent();
525
- msNextFullSync = newestFullSyncStartedAt +
526
- theInterval -
527
- (newestStartedAt + duration);
528
- logger.debug("Next fullSync in " + msNextFullSync / 1000 + " seconds. (" + new Date(Date.now() + msNextFullSync) + ")");
529
- return [4 /*yield*/, new Promise(function (res) {
530
- waitTimeoutId = setTimeout(res, msNextFullSync);
531
- })];
532
- case 3:
533
- _a.sent();
534
- return [2 /*return*/];
535
- }
536
- });
537
- };
538
- this_1 = this;
539
- _a.label = 1;
540
- case 1:
541
- if (!!observer.closed) return [3 /*break*/, 3];
542
- return [5 /*yield**/, _loop_1()];
543
- case 2:
544
- _a.sent();
545
- return [3 /*break*/, 1];
546
- case 3: return [2 /*return*/];
547
- }
548
- });
549
- }); })();
550
- return function () {
551
- if (syncQueriesSubscription) {
552
- syncQueriesSubscription.unsubscribe();
553
- }
554
- if (waitTimeoutId) {
555
- clearTimeout(waitTimeoutId);
556
- }
557
- };
594
+ onTerminate.then(function () {
595
+ terminated = true;
596
+ unsleep();
597
+ });
598
+ return [2 /*return*/, sleep];
599
+ });
600
+ }); }, 'syncQueriesObservable sleep')];
601
+ case 3:
602
+ // TODO: create `BackgroundProcessManager.sleep()` ... but, need to put
603
+ // a lot of thought into what that contract looks like to
604
+ // support possible use-cases:
605
+ //
606
+ // 1. non-cancelable
607
+ // 2. cancelable, unsleep on exit()
608
+ // 3. cancelable, throw Error on exit()
609
+ // 4. cancelable, callback first on exit()?
610
+ // 5. ... etc. ? ...
611
+ //
612
+ // TLDR; this is a lot of complexity here for a sleep(),
613
+ // but, it's not clear to me yet how to support an
614
+ // extensible, centralized cancelable `sleep()` elegantly.
615
+ _a.sent();
616
+ return [2 /*return*/];
617
+ }
618
+ });
619
+ };
620
+ this_1 = this;
621
+ _a.label = 1;
622
+ case 1:
623
+ if (!(!observer.closed && !terminated)) return [3 /*break*/, 3];
624
+ return [5 /*yield**/, _loop_1()];
625
+ case 2:
626
+ _a.sent();
627
+ return [3 /*break*/, 1];
628
+ case 3: return [2 /*return*/];
629
+ }
630
+ });
631
+ }); }, 'syncQueriesObservable main');
558
632
  });
559
633
  };
560
634
  SyncEngine.prototype.disconnectionHandler = function () {
@@ -570,16 +644,67 @@ var SyncEngine = /** @class */ (function () {
570
644
  SyncEngine.prototype.unsubscribeConnectivity = function () {
571
645
  this.datastoreConnectivity.unsubscribe();
572
646
  };
647
+ /**
648
+ * Stops all subscription activities and resolves when all activies report
649
+ * that they're disconnected, done retrying, etc..
650
+ */
651
+ SyncEngine.prototype.stop = function () {
652
+ return __awaiter(this, void 0, void 0, function () {
653
+ return __generator(this, function (_a) {
654
+ switch (_a.label) {
655
+ case 0:
656
+ logger.debug('stopping sync engine');
657
+ /**
658
+ * Gracefully disconnecting subscribers first just prevents *more* work
659
+ * from entering the pipelines.
660
+ */
661
+ this.unsubscribeConnectivity();
662
+ /**
663
+ * aggressively shut down any lingering background processes.
664
+ * some of this might be semi-redundant with unsubscribing. however,
665
+ * unsubscribing doesn't allow us to wait for settling.
666
+ * (Whereas `stop()` does.)
667
+ */
668
+ return [4 /*yield*/, this.mutationsProcessor.stop()];
669
+ case 1:
670
+ /**
671
+ * aggressively shut down any lingering background processes.
672
+ * some of this might be semi-redundant with unsubscribing. however,
673
+ * unsubscribing doesn't allow us to wait for settling.
674
+ * (Whereas `stop()` does.)
675
+ */
676
+ _a.sent();
677
+ return [4 /*yield*/, this.subscriptionsProcessor.stop()];
678
+ case 2:
679
+ _a.sent();
680
+ return [4 /*yield*/, this.datastoreConnectivity.stop()];
681
+ case 3:
682
+ _a.sent();
683
+ return [4 /*yield*/, this.syncQueriesProcessor.stop()];
684
+ case 4:
685
+ _a.sent();
686
+ return [4 /*yield*/, this.runningProcesses.close()];
687
+ case 5:
688
+ _a.sent();
689
+ return [4 /*yield*/, this.runningProcesses.open()];
690
+ case 6:
691
+ _a.sent();
692
+ logger.debug('sync engine stopped and ready to restart');
693
+ return [2 /*return*/];
694
+ }
695
+ });
696
+ });
697
+ };
573
698
  SyncEngine.prototype.setupModels = function (params) {
574
699
  return __awaiter(this, void 0, void 0, function () {
575
- var fullSyncInterval, ModelMetadata, models, savedModel, promises, result, _a, _b, modelMetadata, modelName, e_2_1;
700
+ var fullSyncInterval, ModelMetadataConstructor, models, savedModel, promises, result, _a, _b, modelMetadata, modelName, e_2_1;
576
701
  var e_2, _c;
577
702
  var _this = this;
578
703
  return __generator(this, function (_d) {
579
704
  switch (_d.label) {
580
705
  case 0:
581
706
  fullSyncInterval = params.fullSyncInterval;
582
- ModelMetadata = this.modelClasses
707
+ ModelMetadataConstructor = this.modelClasses
583
708
  .ModelMetadata;
584
709
  models = [];
585
710
  Object.values(this.schema.namespaces).forEach(function (namespace) {
@@ -611,7 +736,7 @@ var SyncEngine = /** @class */ (function () {
611
736
  ? JSON.stringify(syncPredicate)
612
737
  : null;
613
738
  if (!(modelMetadata === undefined)) return [3 /*break*/, 3];
614
- return [4 /*yield*/, this.storage.save(this.modelInstanceCreator(ModelMetadata, {
739
+ return [4 /*yield*/, this.storage.save(this.modelInstanceCreator(ModelMetadataConstructor, {
615
740
  model: model.name,
616
741
  namespace: namespace,
617
742
  lastSync: null,
@@ -627,7 +752,7 @@ var SyncEngine = /** @class */ (function () {
627
752
  ? modelMetadata.lastSyncPredicate
628
753
  : null;
629
754
  syncPredicateUpdated_1 = prevSyncPredicate !== lastSyncPredicate;
630
- return [4 /*yield*/, this.storage.save(this.modelClasses.ModelMetadata.copyOf(modelMetadata, function (draft) {
755
+ return [4 /*yield*/, this.storage.save(ModelMetadataConstructor.copyOf(modelMetadata, function (draft) {
631
756
  draft.fullSyncInterval = fullSyncInterval;
632
757
  // perform a base sync if the syncPredicate changed in between calls to DataStore.start
633
758
  // ensures that the local store contains all the data specified by the syncExpression