@aws-amplify/datastore 3.12.12 → 3.12.13-ds-allow-applicable-data.6

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 (131) hide show
  1. package/CHANGELOG.md +19 -114
  2. package/dist/aws-amplify-datastore.js +4815 -2572
  3. package/dist/aws-amplify-datastore.js.map +1 -1
  4. package/dist/aws-amplify-datastore.min.js +9 -9
  5. package/dist/aws-amplify-datastore.min.js.map +1 -1
  6. package/lib/authModeStrategies/multiAuthStrategy.d.ts +11 -0
  7. package/lib/authModeStrategies/multiAuthStrategy.js +11 -0
  8. package/lib/authModeStrategies/multiAuthStrategy.js.map +1 -1
  9. package/lib/datastore/datastore.d.ts +91 -17
  10. package/lib/datastore/datastore.js +535 -332
  11. package/lib/datastore/datastore.js.map +1 -1
  12. package/lib/index.d.ts +3 -19
  13. package/lib/predicates/index.d.ts +3 -2
  14. package/lib/predicates/index.js +12 -2
  15. package/lib/predicates/index.js.map +1 -1
  16. package/lib/storage/adapter/AsyncStorageAdapter.d.ts +4 -3
  17. package/lib/storage/adapter/AsyncStorageAdapter.js +354 -203
  18. package/lib/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  19. package/lib/storage/adapter/AsyncStorageDatabase.d.ts +14 -4
  20. package/lib/storage/adapter/AsyncStorageDatabase.js +65 -28
  21. package/lib/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  22. package/lib/storage/adapter/IndexedDBAdapter.d.ts +5 -4
  23. package/lib/storage/adapter/IndexedDBAdapter.js +389 -267
  24. package/lib/storage/adapter/IndexedDBAdapter.js.map +1 -1
  25. package/lib/storage/adapter/index.d.ts +1 -1
  26. package/lib/storage/storage.d.ts +1 -1
  27. package/lib/storage/storage.js +93 -28
  28. package/lib/storage/storage.js.map +1 -1
  29. package/lib/sync/datastoreConnectivity.d.ts +1 -0
  30. package/lib/sync/datastoreConnectivity.js +45 -0
  31. package/lib/sync/datastoreConnectivity.js.map +1 -1
  32. package/lib/sync/index.d.ts +27 -4
  33. package/lib/sync/index.js +354 -210
  34. package/lib/sync/index.js.map +1 -1
  35. package/lib/sync/merger.d.ts +9 -3
  36. package/lib/sync/merger.js +13 -6
  37. package/lib/sync/merger.js.map +1 -1
  38. package/lib/sync/outbox.d.ts +2 -2
  39. package/lib/sync/outbox.js +77 -71
  40. package/lib/sync/outbox.js.map +1 -1
  41. package/lib/sync/processors/mutation.d.ts +2 -0
  42. package/lib/sync/processors/mutation.js +256 -200
  43. package/lib/sync/processors/mutation.js.map +1 -1
  44. package/lib/sync/processors/subscription.d.ts +2 -0
  45. package/lib/sync/processors/subscription.js +212 -171
  46. package/lib/sync/processors/subscription.js.map +1 -1
  47. package/lib/sync/processors/sync.d.ts +2 -1
  48. package/lib/sync/processors/sync.js +88 -67
  49. package/lib/sync/processors/sync.js.map +1 -1
  50. package/lib/sync/utils.d.ts +3 -2
  51. package/lib/sync/utils.js +59 -8
  52. package/lib/sync/utils.js.map +1 -1
  53. package/lib/types.d.ts +64 -25
  54. package/lib/types.js +10 -1
  55. package/lib/types.js.map +1 -1
  56. package/lib/util.d.ts +56 -24
  57. package/lib/util.js +334 -170
  58. package/lib/util.js.map +1 -1
  59. package/lib-esm/authModeStrategies/multiAuthStrategy.d.ts +11 -0
  60. package/lib-esm/authModeStrategies/multiAuthStrategy.js +11 -0
  61. package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +1 -1
  62. package/lib-esm/datastore/datastore.d.ts +91 -17
  63. package/lib-esm/datastore/datastore.js +537 -334
  64. package/lib-esm/datastore/datastore.js.map +1 -1
  65. package/lib-esm/index.d.ts +3 -19
  66. package/lib-esm/predicates/index.d.ts +3 -2
  67. package/lib-esm/predicates/index.js +13 -3
  68. package/lib-esm/predicates/index.js.map +1 -1
  69. package/lib-esm/storage/adapter/AsyncStorageAdapter.d.ts +4 -3
  70. package/lib-esm/storage/adapter/AsyncStorageAdapter.js +355 -204
  71. package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  72. package/lib-esm/storage/adapter/AsyncStorageDatabase.d.ts +14 -4
  73. package/lib-esm/storage/adapter/AsyncStorageDatabase.js +66 -29
  74. package/lib-esm/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  75. package/lib-esm/storage/adapter/IndexedDBAdapter.d.ts +5 -4
  76. package/lib-esm/storage/adapter/IndexedDBAdapter.js +390 -268
  77. package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +1 -1
  78. package/lib-esm/storage/adapter/index.d.ts +1 -1
  79. package/lib-esm/storage/storage.d.ts +1 -1
  80. package/lib-esm/storage/storage.js +93 -28
  81. package/lib-esm/storage/storage.js.map +1 -1
  82. package/lib-esm/sync/datastoreConnectivity.d.ts +1 -0
  83. package/lib-esm/sync/datastoreConnectivity.js +45 -0
  84. package/lib-esm/sync/datastoreConnectivity.js.map +1 -1
  85. package/lib-esm/sync/index.d.ts +27 -4
  86. package/lib-esm/sync/index.js +357 -213
  87. package/lib-esm/sync/index.js.map +1 -1
  88. package/lib-esm/sync/merger.d.ts +9 -3
  89. package/lib-esm/sync/merger.js +13 -6
  90. package/lib-esm/sync/merger.js.map +1 -1
  91. package/lib-esm/sync/outbox.d.ts +2 -2
  92. package/lib-esm/sync/outbox.js +78 -72
  93. package/lib-esm/sync/outbox.js.map +1 -1
  94. package/lib-esm/sync/processors/mutation.d.ts +2 -0
  95. package/lib-esm/sync/processors/mutation.js +258 -202
  96. package/lib-esm/sync/processors/mutation.js.map +1 -1
  97. package/lib-esm/sync/processors/subscription.d.ts +2 -0
  98. package/lib-esm/sync/processors/subscription.js +213 -172
  99. package/lib-esm/sync/processors/subscription.js.map +1 -1
  100. package/lib-esm/sync/processors/sync.d.ts +2 -1
  101. package/lib-esm/sync/processors/sync.js +89 -68
  102. package/lib-esm/sync/processors/sync.js.map +1 -1
  103. package/lib-esm/sync/utils.d.ts +3 -2
  104. package/lib-esm/sync/utils.js +60 -10
  105. package/lib-esm/sync/utils.js.map +1 -1
  106. package/lib-esm/types.d.ts +64 -25
  107. package/lib-esm/types.js +9 -2
  108. package/lib-esm/types.js.map +1 -1
  109. package/lib-esm/util.d.ts +56 -24
  110. package/lib-esm/util.js +334 -170
  111. package/lib-esm/util.js.map +1 -1
  112. package/not-tsconfig.json +32 -0
  113. package/package.json +7 -7
  114. package/src/authModeStrategies/multiAuthStrategy.ts +11 -0
  115. package/src/datastore/datastore.ts +672 -391
  116. package/src/predicates/index.ts +32 -10
  117. package/src/storage/adapter/AsyncStorageAdapter.ts +309 -93
  118. package/src/storage/adapter/AsyncStorageDatabase.ts +74 -26
  119. package/src/storage/adapter/IndexedDBAdapter.ts +319 -136
  120. package/src/storage/adapter/index.ts +1 -1
  121. package/src/storage/storage.ts +69 -22
  122. package/src/sync/datastoreConnectivity.ts +6 -0
  123. package/src/sync/index.ts +473 -353
  124. package/src/sync/merger.ts +20 -4
  125. package/src/sync/outbox.ts +22 -9
  126. package/src/sync/processors/mutation.ts +194 -149
  127. package/src/sync/processors/subscription.ts +279 -246
  128. package/src/sync/processors/sync.ts +162 -138
  129. package/src/sync/utils.ts +67 -12
  130. package/src/types.ts +181 -29
  131. package/src/util.ts +415 -176
@@ -65,11 +65,11 @@ var __spread = (this && this.__spread) || function () {
65
65
  for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
66
66
  return ar;
67
67
  };
68
- import { browserOrNode, ConsoleLogger as Logger } from '@aws-amplify/core';
68
+ import { browserOrNode, ConsoleLogger as Logger, BackgroundProcessManager, } from '@aws-amplify/core';
69
69
  import { CONTROL_MSG as PUBSUB_CONTROL_MSG } from '@aws-amplify/pubsub';
70
70
  import Observable from 'zen-observable-ts';
71
71
  import { ModelPredicateCreator } from '../predicates';
72
- import { OpType, } from '../types';
72
+ import { OpType, __modelMeta__, } from '../types';
73
73
  import { exhaustiveCheck, getNow, SYNC, USER } from '../util';
74
74
  import DataStoreConnectivity from './datastoreConnectivity';
75
75
  import { ModelMerger } from './merger';
@@ -77,7 +77,7 @@ import { MutationEventOutbox } from './outbox';
77
77
  import { MutationProcessor } from './processors/mutation';
78
78
  import { CONTROL_MSG, SubscriptionProcessor } from './processors/subscription';
79
79
  import { SyncProcessor } from './processors/sync';
80
- import { createMutationInstanceFromModelOperation, predicateToGraphQLCondition, } from './utils';
80
+ import { createMutationInstanceFromModelOperation, getIdentifierValue, predicateToGraphQLCondition, } from './utils';
81
81
  var isNode = browserOrNode().isNode;
82
82
  var logger = new Logger('DataStore');
83
83
  var ownSymbol = Symbol('sync');
@@ -109,6 +109,7 @@ var SyncEngine = /** @class */ (function () {
109
109
  this.amplifyContext = amplifyContext;
110
110
  this.online = false;
111
111
  this.modelSyncedStatus = new WeakMap();
112
+ this.runningProcesses = new BackgroundProcessManager();
112
113
  var MutationEvent = this.modelClasses['MutationEvent'];
113
114
  this.outbox = new MutationEventOutbox(this.schema, MutationEvent, modelInstanceCreator, ownSymbol);
114
115
  this.modelMerger = new ModelMerger(this.outbox, ownSymbol);
@@ -125,7 +126,7 @@ var SyncEngine = /** @class */ (function () {
125
126
  return new Observable(function (observer) {
126
127
  logger.log('starting sync engine...');
127
128
  var subscriptions = [];
128
- (function () { return __awaiter(_this, void 0, void 0, function () {
129
+ _this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
129
130
  var err_1, startPromise, hasMutationsInOutbox;
130
131
  var _this = this;
131
132
  return __generator(this, function (_a) {
@@ -141,154 +142,184 @@ var SyncEngine = /** @class */ (function () {
141
142
  observer.error(err_1);
142
143
  return [2 /*return*/];
143
144
  case 3:
144
- startPromise = new Promise(function (resolve) {
145
+ startPromise = new Promise(function (doneStarting) {
145
146
  _this.datastoreConnectivity.status().subscribe(function (_a) {
146
147
  var online = _a.online;
147
148
  return __awaiter(_this, void 0, void 0, function () {
148
- var ctlSubsObservable_1, dataSubsObservable, err_2, error_1;
149
- var _b;
150
149
  var _this = this;
151
- return __generator(this, function (_c) {
152
- switch (_c.label) {
153
- case 0:
154
- if (!(online && !this.online)) return [3 /*break*/, 10];
155
- this.online = online;
156
- observer.next({
157
- type: ControlMessage.SYNC_ENGINE_NETWORK_STATUS,
158
- data: {
159
- active: this.online,
160
- },
161
- });
162
- dataSubsObservable = void 0;
163
- if (!isNode) return [3 /*break*/, 1];
164
- logger.warn('Realtime disabled when in a server-side environment');
165
- return [3 /*break*/, 6];
166
- case 1:
167
- //#region GraphQL Subscriptions
168
- _b = __read(this.subscriptionsProcessor.start(), 2),
169
- // const ctlObservable: Observable<CONTROL_MSG>
170
- ctlSubsObservable_1 = _b[0],
171
- // const dataObservable: Observable<[TransformerMutationType, SchemaModel, Readonly<{
172
- // id: string;
173
- // } & Record<string, any>>]>
174
- dataSubsObservable = _b[1];
175
- _c.label = 2;
176
- case 2:
177
- _c.trys.push([2, 4, , 5]);
178
- return [4 /*yield*/, new Promise(function (resolve, reject) {
179
- var ctlSubsSubscription = ctlSubsObservable_1.subscribe({
180
- next: function (msg) {
181
- if (msg === CONTROL_MSG.CONNECTED) {
182
- resolve();
183
- }
184
- },
185
- error: function (err) {
186
- reject(err);
187
- var handleDisconnect = _this.disconnectionHandler();
188
- handleDisconnect(err);
189
- },
190
- });
191
- subscriptions.push(ctlSubsSubscription);
192
- })];
193
- case 3:
194
- _c.sent();
195
- return [3 /*break*/, 5];
196
- case 4:
197
- err_2 = _c.sent();
198
- observer.error(err_2);
199
- return [2 /*return*/];
200
- case 5:
201
- logger.log('Realtime ready');
202
- observer.next({
203
- type: ControlMessage.SYNC_ENGINE_SUBSCRIPTIONS_ESTABLISHED,
150
+ return __generator(this, function (_b) {
151
+ return [2 /*return*/, this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
152
+ var ctlSubsObservable_1, dataSubsObservable, err_2, error_1;
153
+ var _a;
154
+ var _this = this;
155
+ return __generator(this, function (_b) {
156
+ switch (_b.label) {
157
+ case 0:
158
+ if (!(online && !this.online)) return [3 /*break*/, 10];
159
+ this.online = online;
160
+ observer.next({
161
+ type: ControlMessage.SYNC_ENGINE_NETWORK_STATUS,
162
+ data: {
163
+ active: this.online,
164
+ },
165
+ });
166
+ dataSubsObservable = void 0;
167
+ if (!isNode) return [3 /*break*/, 1];
168
+ logger.warn('Realtime disabled when in a server-side environment');
169
+ return [3 /*break*/, 6];
170
+ case 1:
171
+ //#region GraphQL Subscriptions
172
+ _a = __read(this.subscriptionsProcessor.start(), 2),
173
+ // const ctlObservable: Observable<CONTROL_MSG>
174
+ ctlSubsObservable_1 = _a[0],
175
+ // const dataObservable: Observable<[TransformerMutationType, SchemaModel, Readonly<{
176
+ // id: string;
177
+ // } & Record<string, any>>]>
178
+ dataSubsObservable = _a[1];
179
+ _b.label = 2;
180
+ case 2:
181
+ _b.trys.push([2, 4, , 5]);
182
+ return [4 /*yield*/, new Promise(function (resolve, reject) {
183
+ var ctlSubsSubscription = ctlSubsObservable_1.subscribe({
184
+ next: function (msg) {
185
+ if (msg === CONTROL_MSG.CONNECTED) {
186
+ resolve();
187
+ }
188
+ },
189
+ error: function (err) {
190
+ reject(err);
191
+ var handleDisconnect = _this.disconnectionHandler();
192
+ handleDisconnect(err);
193
+ },
194
+ });
195
+ subscriptions.push(ctlSubsSubscription);
196
+ })];
197
+ case 3:
198
+ _b.sent();
199
+ return [3 /*break*/, 5];
200
+ case 4:
201
+ err_2 = _b.sent();
202
+ observer.error(err_2);
203
+ return [2 /*return*/];
204
+ case 5:
205
+ logger.log('Realtime ready');
206
+ observer.next({
207
+ type: ControlMessage.SYNC_ENGINE_SUBSCRIPTIONS_ESTABLISHED,
208
+ });
209
+ _b.label = 6;
210
+ case 6:
211
+ _b.trys.push([6, 8, , 9]);
212
+ return [4 /*yield*/, new Promise(function (resolve, reject) {
213
+ var syncQuerySubscription = _this.syncQueriesObservable().subscribe({
214
+ next: function (message) {
215
+ var type = message.type;
216
+ if (type ===
217
+ ControlMessage.SYNC_ENGINE_SYNC_QUERIES_READY) {
218
+ resolve();
219
+ }
220
+ observer.next(message);
221
+ },
222
+ complete: function () {
223
+ resolve();
224
+ },
225
+ error: function (error) {
226
+ reject(error);
227
+ },
228
+ });
229
+ if (syncQuerySubscription) {
230
+ subscriptions.push(syncQuerySubscription);
231
+ }
232
+ })];
233
+ case 7:
234
+ _b.sent();
235
+ return [3 /*break*/, 9];
236
+ case 8:
237
+ error_1 = _b.sent();
238
+ observer.error(error_1);
239
+ return [2 /*return*/];
240
+ case 9:
241
+ //#endregion
242
+ //#region process mutations (outbox)
243
+ subscriptions.push(this.mutationsProcessor
244
+ .start()
245
+ .subscribe(function (_a) {
246
+ var modelDefinition = _a.modelDefinition, item = _a.model, hasMore = _a.hasMore;
247
+ return _this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
248
+ var modelConstructor, model;
249
+ var _this = this;
250
+ return __generator(this, function (_a) {
251
+ switch (_a.label) {
252
+ case 0:
253
+ modelConstructor = this.userModelClasses[modelDefinition.name];
254
+ model = this.modelInstanceCreator(modelConstructor, item);
255
+ return [4 /*yield*/, this.storage.runExclusive(function (storage) {
256
+ return _this.modelMerger.merge(storage, model, modelDefinition);
257
+ })];
258
+ case 1:
259
+ _a.sent();
260
+ observer.next({
261
+ type: ControlMessage.SYNC_ENGINE_OUTBOX_MUTATION_PROCESSED,
262
+ data: {
263
+ model: modelConstructor,
264
+ element: model,
265
+ },
266
+ });
267
+ observer.next({
268
+ type: ControlMessage.SYNC_ENGINE_OUTBOX_STATUS,
269
+ data: {
270
+ isEmpty: !hasMore,
271
+ },
272
+ });
273
+ return [2 /*return*/];
274
+ }
275
+ });
276
+ }); }, 'mutation processor event');
277
+ }));
278
+ //#endregion
279
+ //#region Merge subscriptions buffer
280
+ // TODO: extract to function
281
+ if (!isNode) {
282
+ subscriptions.push(dataSubsObservable.subscribe(function (_a) {
283
+ var _b = __read(_a, 3), _transformerMutationType = _b[0], modelDefinition = _b[1], item = _b[2];
284
+ return _this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
285
+ var modelConstructor, model;
286
+ var _this = this;
287
+ return __generator(this, function (_a) {
288
+ switch (_a.label) {
289
+ case 0:
290
+ modelConstructor = this.userModelClasses[modelDefinition.name];
291
+ model = this.modelInstanceCreator(modelConstructor, item);
292
+ return [4 /*yield*/, this.storage.runExclusive(function (storage) {
293
+ return _this.modelMerger.merge(storage, model, modelDefinition);
294
+ })];
295
+ case 1:
296
+ _a.sent();
297
+ return [2 /*return*/];
298
+ }
299
+ });
300
+ }); }, 'subscription dataSubsObservable event');
301
+ }));
302
+ }
303
+ return [3 /*break*/, 11];
304
+ case 10:
305
+ if (!online) {
306
+ this.online = online;
307
+ observer.next({
308
+ type: ControlMessage.SYNC_ENGINE_NETWORK_STATUS,
309
+ data: {
310
+ active: this.online,
311
+ },
312
+ });
313
+ subscriptions.forEach(function (sub) { return sub.unsubscribe(); });
314
+ subscriptions = [];
315
+ }
316
+ _b.label = 11;
317
+ case 11:
318
+ doneStarting();
319
+ return [2 /*return*/];
320
+ }
204
321
  });
205
- _c.label = 6;
206
- case 6:
207
- _c.trys.push([6, 8, , 9]);
208
- return [4 /*yield*/, new Promise(function (resolve, reject) {
209
- var syncQuerySubscription = _this.syncQueriesObservable().subscribe({
210
- next: function (message) {
211
- var type = message.type;
212
- if (type === ControlMessage.SYNC_ENGINE_SYNC_QUERIES_READY) {
213
- resolve();
214
- }
215
- observer.next(message);
216
- },
217
- complete: function () {
218
- resolve();
219
- },
220
- error: function (error) {
221
- reject(error);
222
- },
223
- });
224
- if (syncQuerySubscription) {
225
- subscriptions.push(syncQuerySubscription);
226
- }
227
- })];
228
- case 7:
229
- _c.sent();
230
- return [3 /*break*/, 9];
231
- case 8:
232
- error_1 = _c.sent();
233
- observer.error(error_1);
234
- return [2 /*return*/];
235
- case 9:
236
- //#endregion
237
- //#region process mutations
238
- subscriptions.push(this.mutationsProcessor
239
- .start()
240
- .subscribe(function (_a) {
241
- var modelDefinition = _a.modelDefinition, item = _a.model, hasMore = _a.hasMore;
242
- var modelConstructor = _this.userModelClasses[modelDefinition.name];
243
- var model = _this.modelInstanceCreator(modelConstructor, item);
244
- _this.storage.runExclusive(function (storage) {
245
- return _this.modelMerger.merge(storage, model);
246
- });
247
- observer.next({
248
- type: ControlMessage.SYNC_ENGINE_OUTBOX_MUTATION_PROCESSED,
249
- data: {
250
- model: modelConstructor,
251
- element: model,
252
- },
253
- });
254
- observer.next({
255
- type: ControlMessage.SYNC_ENGINE_OUTBOX_STATUS,
256
- data: {
257
- isEmpty: !hasMore,
258
- },
259
- });
260
- }));
261
- //#endregion
262
- //#region Merge subscriptions buffer
263
- // TODO: extract to function
264
- if (!isNode) {
265
- subscriptions.push(dataSubsObservable.subscribe(function (_a) {
266
- var _b = __read(_a, 3), _transformerMutationType = _b[0], modelDefinition = _b[1], item = _b[2];
267
- var modelConstructor = _this.userModelClasses[modelDefinition.name];
268
- var model = _this.modelInstanceCreator(modelConstructor, item);
269
- _this.storage.runExclusive(function (storage) {
270
- return _this.modelMerger.merge(storage, model);
271
- });
272
- }));
273
- }
274
- return [3 /*break*/, 11];
275
- case 10:
276
- if (!online) {
277
- this.online = online;
278
- observer.next({
279
- type: ControlMessage.SYNC_ENGINE_NETWORK_STATUS,
280
- data: {
281
- active: this.online,
282
- },
283
- });
284
- subscriptions.forEach(function (sub) { return sub.unsubscribe(); });
285
- subscriptions = [];
286
- }
287
- _c.label = 11;
288
- case 11:
289
- resolve();
290
- return [2 /*return*/];
291
- }
322
+ }); }, 'datastore connectivity event')];
292
323
  });
293
324
  });
294
325
  });
@@ -304,38 +335,44 @@ var SyncEngine = /** @class */ (function () {
304
335
  next: function (_a) {
305
336
  var opType = _a.opType, model = _a.model, element = _a.element, condition = _a.condition;
306
337
  return __awaiter(_this, void 0, void 0, function () {
307
- var namespace, MutationEventConstructor, graphQLCondition, mutationEvent;
338
+ var _this = this;
308
339
  return __generator(this, function (_b) {
309
- switch (_b.label) {
310
- case 0:
311
- namespace = this.schema.namespaces[this.namespaceResolver(model)];
312
- MutationEventConstructor = this.modelClasses['MutationEvent'];
313
- graphQLCondition = predicateToGraphQLCondition(condition);
314
- mutationEvent = createMutationInstanceFromModelOperation(namespace.relationships, this.getModelDefinition(model), opType, model, element, graphQLCondition, MutationEventConstructor, this.modelInstanceCreator);
315
- return [4 /*yield*/, this.outbox.enqueue(this.storage, mutationEvent)];
316
- case 1:
317
- _b.sent();
318
- observer.next({
319
- type: ControlMessage.SYNC_ENGINE_OUTBOX_MUTATION_ENQUEUED,
320
- data: {
321
- model: model,
322
- element: element,
323
- },
324
- });
325
- observer.next({
326
- type: ControlMessage.SYNC_ENGINE_OUTBOX_STATUS,
327
- data: {
328
- isEmpty: false,
329
- },
340
+ return [2 /*return*/, this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
341
+ var namespace, MutationEventConstructor, modelDefinition, graphQLCondition, mutationEvent;
342
+ return __generator(this, function (_a) {
343
+ switch (_a.label) {
344
+ case 0:
345
+ namespace = this.schema.namespaces[this.namespaceResolver(model)];
346
+ MutationEventConstructor = this.modelClasses['MutationEvent'];
347
+ modelDefinition = this.getModelDefinition(model);
348
+ graphQLCondition = predicateToGraphQLCondition(condition, modelDefinition);
349
+ mutationEvent = createMutationInstanceFromModelOperation(namespace.relationships, this.getModelDefinition(model), opType, model, element, graphQLCondition, MutationEventConstructor, this.modelInstanceCreator);
350
+ return [4 /*yield*/, this.outbox.enqueue(this.storage, mutationEvent)];
351
+ case 1:
352
+ _a.sent();
353
+ observer.next({
354
+ type: ControlMessage.SYNC_ENGINE_OUTBOX_MUTATION_ENQUEUED,
355
+ data: {
356
+ model: model,
357
+ element: element,
358
+ },
359
+ });
360
+ observer.next({
361
+ type: ControlMessage.SYNC_ENGINE_OUTBOX_STATUS,
362
+ data: {
363
+ isEmpty: false,
364
+ },
365
+ });
366
+ return [4 /*yield*/, startPromise];
367
+ case 2:
368
+ _a.sent();
369
+ if (this.online) {
370
+ this.mutationsProcessor.resume();
371
+ }
372
+ return [2 /*return*/];
373
+ }
330
374
  });
331
- return [4 /*yield*/, startPromise];
332
- case 2:
333
- _b.sent();
334
- if (this.online) {
335
- this.mutationsProcessor.resume();
336
- }
337
- return [2 /*return*/];
338
- }
375
+ }); }, 'storage event')];
339
376
  });
340
377
  });
341
378
  },
@@ -361,10 +398,13 @@ var SyncEngine = /** @class */ (function () {
361
398
  return [2 /*return*/];
362
399
  }
363
400
  });
364
- }); })();
365
- return function () {
366
- subscriptions.forEach(function (sub) { return sub.unsubscribe(); });
367
- };
401
+ }); }, 'sync start');
402
+ return _this.runningProcesses.addCleaner(function () { return __awaiter(_this, void 0, void 0, function () {
403
+ return __generator(this, function (_a) {
404
+ subscriptions.forEach(function (sub) { return sub.unsubscribe(); });
405
+ return [2 /*return*/];
406
+ });
407
+ }); }, 'sync start cleaner');
368
408
  });
369
409
  };
370
410
  SyncEngine.prototype.getModelsMetadataWithNextFullSync = function (currentTimeStamp) {
@@ -375,7 +415,7 @@ var SyncEngine = /** @class */ (function () {
375
415
  switch (_b.label) {
376
416
  case 0:
377
417
  _a = Map.bind;
378
- return [4 /*yield*/, this.getModelsMetadata()];
418
+ return [4 /*yield*/, this.runningProcesses.add(function () { return _this.getModelsMetadata(); }, 'sync/index getModelsMetadataWithNextFullSync')];
379
419
  case 1:
380
420
  modelLastSync = new (_a.apply(Map, [void 0, (_b.sent()).map(function (_a) {
381
421
  var namespace = _a.namespace, model = _a.model, lastSync = _a.lastSync, lastFullSync = _a.lastFullSync, fullSyncInterval = _a.fullSyncInterval, lastSyncPredicate = _a.lastSyncPredicate;
@@ -400,13 +440,13 @@ var SyncEngine = /** @class */ (function () {
400
440
  }
401
441
  return new Observable(function (observer) {
402
442
  var syncQueriesSubscription;
403
- var waitTimeoutId;
404
- (function () { return __awaiter(_this, void 0, void 0, function () {
405
- var _loop_1, this_1;
443
+ _this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
444
+ var terminated, _loop_1, this_1;
406
445
  var _this = this;
407
446
  return __generator(this, function (_a) {
408
447
  switch (_a.label) {
409
448
  case 0:
449
+ terminated = false;
410
450
  _loop_1 = function () {
411
451
  var count, modelLastSync, paginatingModels, newestFullSyncStartedAt, theInterval, start, duration, newestStartedAt, msNextFullSync;
412
452
  return __generator(this, function (_a) {
@@ -423,11 +463,11 @@ var SyncEngine = /** @class */ (function () {
423
463
  .subscribe({
424
464
  next: function (_a) {
425
465
  var namespace = _a.namespace, modelDefinition = _a.modelDefinition, items = _a.items, done = _a.done, startedAt = _a.startedAt, isFullSync = _a.isFullSync;
426
- return __awaiter(_this, void 0, void 0, function () {
466
+ return _this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
427
467
  var modelConstructor, modelName, modelMetadata_1, lastFullSync, fullSyncInterval, counts;
428
468
  var _this = this;
429
- return __generator(this, function (_b) {
430
- switch (_b.label) {
469
+ return __generator(this, function (_a) {
470
+ switch (_a.label) {
431
471
  case 0:
432
472
  modelConstructor = this.userModelClasses[modelDefinition.name];
433
473
  if (!count.has(modelConstructor)) {
@@ -456,7 +496,8 @@ var SyncEngine = /** @class */ (function () {
456
496
  idsInOutbox = _e.sent();
457
497
  oneByOne = [];
458
498
  page = items.filter(function (item) {
459
- if (!idsInOutbox.has(item.id)) {
499
+ var itemId = getIdentifierValue(modelDefinition, item);
500
+ if (!idsInOutbox.has(itemId)) {
460
501
  return true;
461
502
  }
462
503
  oneByOne.push(item);
@@ -471,7 +512,7 @@ var SyncEngine = /** @class */ (function () {
471
512
  case 3:
472
513
  if (!!oneByOne_1_1.done) return [3 /*break*/, 6];
473
514
  item = oneByOne_1_1.value;
474
- return [4 /*yield*/, this.modelMerger.merge(storage, item)];
515
+ return [4 /*yield*/, this.modelMerger.merge(storage, item, modelDefinition)];
475
516
  case 4:
476
517
  opType = _e.sent();
477
518
  if (opType !== undefined) {
@@ -495,7 +536,7 @@ var SyncEngine = /** @class */ (function () {
495
536
  case 9:
496
537
  _b = (_a = opTypeCount.push).apply;
497
538
  _c = [opTypeCount];
498
- return [4 /*yield*/, this.modelMerger.mergePage(storage, modelConstructor, page)];
539
+ return [4 /*yield*/, this.modelMerger.mergePage(storage, modelConstructor, page, modelDefinition)];
499
540
  case 10:
500
541
  _b.apply(_a, _c.concat([__spread.apply(void 0, [(_e.sent())])]));
501
542
  counts = count.get(modelConstructor);
@@ -524,12 +565,12 @@ var SyncEngine = /** @class */ (function () {
524
565
  * If there are mutations in the outbox for a given id, those need to be
525
566
  * merged individually. Otherwise, we can merge them in batches.
526
567
  */
527
- _b.sent();
568
+ _a.sent();
528
569
  if (!done) return [3 /*break*/, 4];
529
570
  modelName = modelDefinition.name;
530
571
  return [4 /*yield*/, this.getModelMetadata(namespace, modelName)];
531
572
  case 2:
532
- modelMetadata_1 = _b.sent();
573
+ modelMetadata_1 = _a.sent();
533
574
  lastFullSync = modelMetadata_1.lastFullSync, fullSyncInterval = modelMetadata_1.fullSyncInterval;
534
575
  theInterval = fullSyncInterval;
535
576
  newestFullSyncStartedAt =
@@ -545,7 +586,7 @@ var SyncEngine = /** @class */ (function () {
545
586
  });
546
587
  return [4 /*yield*/, this.storage.save(modelMetadata_1, undefined, ownSymbol)];
547
588
  case 3:
548
- _b.sent();
589
+ _a.sent();
549
590
  counts = count.get(modelConstructor);
550
591
  this.modelSyncedStatus.set(modelConstructor, true);
551
592
  observer.next({
@@ -566,11 +607,11 @@ var SyncEngine = /** @class */ (function () {
566
607
  });
567
608
  syncQueriesSubscription.unsubscribe();
568
609
  }
569
- _b.label = 4;
610
+ _a.label = 4;
570
611
  case 4: return [2 /*return*/];
571
612
  }
572
613
  });
573
- });
614
+ }); }, 'syncQueriesObservable syncQueriesSubscription event');
574
615
  },
575
616
  error: function (error) {
576
617
  observer.error(error);
@@ -592,10 +633,47 @@ var SyncEngine = /** @class */ (function () {
592
633
  theInterval -
593
634
  (newestStartedAt + duration);
594
635
  logger.debug("Next fullSync in " + msNextFullSync / 1000 + " seconds. (" + new Date(Date.now() + msNextFullSync) + ")");
595
- return [4 /*yield*/, new Promise(function (res) {
596
- waitTimeoutId = setTimeout(res, msNextFullSync);
597
- })];
636
+ // TODO: create `BackgroundProcessManager.sleep()` ... but, need to put
637
+ // a lot of thought into what that contract looks like to
638
+ // support possible use-cases:
639
+ //
640
+ // 1. non-cancelable
641
+ // 2. cancelable, unsleep on exit()
642
+ // 3. cancelable, throw Error on exit()
643
+ // 4. cancelable, callback first on exit()?
644
+ // 5. ... etc. ? ...
645
+ //
646
+ // TLDR; this is a lot of complexity here for a sleep(),
647
+ // but, it's not clear to me yet how to support an
648
+ // extensible, centralized cancelable `sleep()` elegantly.
649
+ return [4 /*yield*/, this_1.runningProcesses.add(function (onTerminate) { return __awaiter(_this, void 0, void 0, function () {
650
+ var sleepTimer, unsleep, sleep;
651
+ return __generator(this, function (_a) {
652
+ sleep = new Promise(function (_unsleep) {
653
+ unsleep = _unsleep;
654
+ sleepTimer = setTimeout(unsleep, msNextFullSync);
655
+ });
656
+ onTerminate.then(function () {
657
+ terminated = true;
658
+ unsleep();
659
+ });
660
+ return [2 /*return*/, sleep];
661
+ });
662
+ }); }, 'syncQueriesObservable sleep')];
598
663
  case 3:
664
+ // TODO: create `BackgroundProcessManager.sleep()` ... but, need to put
665
+ // a lot of thought into what that contract looks like to
666
+ // support possible use-cases:
667
+ //
668
+ // 1. non-cancelable
669
+ // 2. cancelable, unsleep on exit()
670
+ // 3. cancelable, throw Error on exit()
671
+ // 4. cancelable, callback first on exit()?
672
+ // 5. ... etc. ? ...
673
+ //
674
+ // TLDR; this is a lot of complexity here for a sleep(),
675
+ // but, it's not clear to me yet how to support an
676
+ // extensible, centralized cancelable `sleep()` elegantly.
599
677
  _a.sent();
600
678
  return [2 /*return*/];
601
679
  }
@@ -604,7 +682,7 @@ var SyncEngine = /** @class */ (function () {
604
682
  this_1 = this;
605
683
  _a.label = 1;
606
684
  case 1:
607
- if (!!observer.closed) return [3 /*break*/, 3];
685
+ if (!(!observer.closed && !terminated)) return [3 /*break*/, 3];
608
686
  return [5 /*yield**/, _loop_1()];
609
687
  case 2:
610
688
  _a.sent();
@@ -612,15 +690,16 @@ var SyncEngine = /** @class */ (function () {
612
690
  case 3: return [2 /*return*/];
613
691
  }
614
692
  });
615
- }); })();
616
- return function () {
617
- if (syncQueriesSubscription) {
618
- syncQueriesSubscription.unsubscribe();
619
- }
620
- if (waitTimeoutId) {
621
- clearTimeout(waitTimeoutId);
622
- }
623
- };
693
+ }); }, 'syncQueriesObservable main');
694
+ return _this.runningProcesses.addCleaner(function () { return __awaiter(_this, void 0, void 0, function () {
695
+ return __generator(this, function (_a) {
696
+ logger.debug('cleaning syncQueriesObservable');
697
+ if (syncQueriesSubscription) {
698
+ syncQueriesSubscription.unsubscribe();
699
+ }
700
+ return [2 /*return*/];
701
+ });
702
+ }); }, 'syncQueriesObservable cleaner');
624
703
  });
625
704
  };
626
705
  SyncEngine.prototype.disconnectionHandler = function () {
@@ -636,16 +715,81 @@ var SyncEngine = /** @class */ (function () {
636
715
  SyncEngine.prototype.unsubscribeConnectivity = function () {
637
716
  this.datastoreConnectivity.unsubscribe();
638
717
  };
718
+ /**
719
+ * Stops all subscription activities and resolves when all activies report
720
+ * that they're disconnected, done retrying, etc..
721
+ */
722
+ SyncEngine.prototype.stop = function () {
723
+ return __awaiter(this, void 0, void 0, function () {
724
+ return __generator(this, function (_a) {
725
+ switch (_a.label) {
726
+ case 0:
727
+ logger.debug('stopping sync engine');
728
+ /**
729
+ * Gracefully disconnecting subscribers first just prevents *more* work
730
+ * from entering the pipelines.
731
+ */
732
+ this.unsubscribeConnectivity();
733
+ /**
734
+ * aggressively shut down any lingering background processes.
735
+ * some of this might be semi-redundant with unsubscribing. however,
736
+ * unsubscribing doesn't allow us to wait for settling.
737
+ * (Whereas `stop()` does.)
738
+ */
739
+ return [4 /*yield*/, this.mutationsProcessor.stop()];
740
+ case 1:
741
+ /**
742
+ * aggressively shut down any lingering background processes.
743
+ * some of this might be semi-redundant with unsubscribing. however,
744
+ * unsubscribing doesn't allow us to wait for settling.
745
+ * (Whereas `stop()` does.)
746
+ */
747
+ _a.sent();
748
+ return [4 /*yield*/, this.subscriptionsProcessor.stop()];
749
+ case 2:
750
+ _a.sent();
751
+ return [4 /*yield*/, this.datastoreConnectivity.stop()];
752
+ case 3:
753
+ _a.sent();
754
+ return [4 /*yield*/, this.syncQueriesProcessor.stop()];
755
+ case 4:
756
+ _a.sent();
757
+ /**
758
+ * TODO: *consider* refactoring shutdowns ^ into this context as child
759
+ * job contexts, as cleaner methods (added with `addCleaner()`), or by
760
+ * passing this context through to child processes.
761
+ */
762
+ return [4 /*yield*/, this.runningProcesses.close()];
763
+ case 5:
764
+ /**
765
+ * TODO: *consider* refactoring shutdowns ^ into this context as child
766
+ * job contexts, as cleaner methods (added with `addCleaner()`), or by
767
+ * passing this context through to child processes.
768
+ */
769
+ _a.sent();
770
+ /**
771
+ * Not 100% sure this is necessary. In most cases, we would expect the
772
+ * sync engine to be replaced with a new instance after stopping.
773
+ *
774
+ * TODO: Remove this and see if everything still works.
775
+ */
776
+ this.runningProcesses = new BackgroundProcessManager();
777
+ logger.debug('sync engine stopped and ready to restart');
778
+ return [2 /*return*/];
779
+ }
780
+ });
781
+ });
782
+ };
639
783
  SyncEngine.prototype.setupModels = function (params) {
640
784
  return __awaiter(this, void 0, void 0, function () {
641
- var fullSyncInterval, ModelMetadata, models, savedModel, promises, result, _a, _b, modelMetadata, modelName, e_2_1;
785
+ var fullSyncInterval, ModelMetadataConstructor, models, savedModel, promises, result, _a, _b, modelMetadata, modelName, e_2_1;
642
786
  var e_2, _c;
643
787
  var _this = this;
644
788
  return __generator(this, function (_d) {
645
789
  switch (_d.label) {
646
790
  case 0:
647
791
  fullSyncInterval = params.fullSyncInterval;
648
- ModelMetadata = this.modelClasses
792
+ ModelMetadataConstructor = this.modelClasses
649
793
  .ModelMetadata;
650
794
  models = [];
651
795
  Object.values(this.schema.namespaces).forEach(function (namespace) {
@@ -677,7 +821,7 @@ var SyncEngine = /** @class */ (function () {
677
821
  ? JSON.stringify(syncPredicate)
678
822
  : null;
679
823
  if (!(modelMetadata === undefined)) return [3 /*break*/, 3];
680
- return [4 /*yield*/, this.storage.save(this.modelInstanceCreator(ModelMetadata, {
824
+ return [4 /*yield*/, this.storage.save(this.modelInstanceCreator(ModelMetadataConstructor, {
681
825
  model: model.name,
682
826
  namespace: namespace,
683
827
  lastSync: null,
@@ -693,7 +837,7 @@ var SyncEngine = /** @class */ (function () {
693
837
  ? modelMetadata.lastSyncPredicate
694
838
  : null;
695
839
  syncPredicateUpdated_1 = prevSyncPredicate !== lastSyncPredicate;
696
- return [4 /*yield*/, this.storage.save(this.modelClasses.ModelMetadata.copyOf(modelMetadata, function (draft) {
840
+ return [4 /*yield*/, this.storage.save(ModelMetadataConstructor.copyOf(modelMetadata, function (draft) {
697
841
  draft.fullSyncInterval = fullSyncInterval;
698
842
  // perform a base sync if the syncPredicate changed in between calls to DataStore.start
699
843
  // ensures that the local store contains all the data specified by the syncExpression