@aws-amplify/datastore 4.7.6-api-v6-models.b3abc9b.0 → 5.0.0

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 (187) hide show
  1. package/README.md +4 -0
  2. package/lib/authModeStrategies/defaultAuthStrategy.js +3 -2
  3. package/lib/authModeStrategies/index.js +3 -3
  4. package/lib/authModeStrategies/multiAuthStrategy.js +38 -53
  5. package/lib/datastore/datastore.d.ts +4 -5
  6. package/lib/datastore/datastore.js +929 -1284
  7. package/lib/index.d.ts +1 -1
  8. package/lib/index.js +26 -13
  9. package/lib/predicates/index.js +54 -69
  10. package/lib/predicates/next.d.ts +2 -2
  11. package/lib/predicates/next.js +313 -462
  12. package/lib/predicates/sort.js +24 -28
  13. package/lib/ssr/index.js +2 -2
  14. package/lib/storage/adapter/AsyncStorageAdapter.js +120 -342
  15. package/lib/storage/adapter/AsyncStorageDatabase.js +217 -421
  16. package/lib/storage/adapter/InMemoryStore.js +28 -51
  17. package/lib/storage/adapter/InMemoryStore.native.js +5 -3
  18. package/lib/storage/adapter/IndexedDBAdapter.js +466 -871
  19. package/lib/storage/adapter/StorageAdapterBase.js +180 -330
  20. package/lib/storage/adapter/getDefaultAdapter/index.js +8 -10
  21. package/lib/storage/adapter/getDefaultAdapter/index.native.js +5 -4
  22. package/lib/storage/adapter/index.js +0 -1
  23. package/lib/storage/relationship.js +177 -253
  24. package/lib/storage/storage.d.ts +4 -4
  25. package/lib/storage/storage.js +255 -433
  26. package/lib/sync/datastoreConnectivity.d.ts +2 -2
  27. package/lib/sync/datastoreConnectivity.js +29 -39
  28. package/lib/sync/datastoreReachability/index.d.ts +1 -3
  29. package/lib/sync/datastoreReachability/index.js +3 -3
  30. package/lib/sync/datastoreReachability/index.native.d.ts +1 -3
  31. package/lib/sync/datastoreReachability/index.native.js +4 -5
  32. package/lib/sync/index.d.ts +2 -2
  33. package/lib/sync/index.js +522 -827
  34. package/lib/sync/merger.js +31 -63
  35. package/lib/sync/outbox.js +148 -232
  36. package/lib/sync/processors/errorMaps.d.ts +1 -1
  37. package/lib/sync/processors/errorMaps.js +30 -47
  38. package/lib/sync/processors/mutation.d.ts +2 -2
  39. package/lib/sync/processors/mutation.js +343 -502
  40. package/lib/sync/processors/subscription.d.ts +5 -2
  41. package/lib/sync/processors/subscription.js +283 -437
  42. package/lib/sync/processors/sync.d.ts +2 -2
  43. package/lib/sync/processors/sync.js +279 -404
  44. package/lib/sync/utils.d.ts +5 -4
  45. package/lib/sync/utils.js +267 -320
  46. package/lib/tsconfig.tsbuildinfo +1 -0
  47. package/lib/types.d.ts +138 -140
  48. package/lib/types.js +17 -24
  49. package/lib/util.d.ts +9 -17
  50. package/lib/util.js +387 -511
  51. package/lib-esm/authModeStrategies/defaultAuthStrategy.js +1 -2
  52. package/lib-esm/authModeStrategies/index.js +0 -1
  53. package/lib-esm/authModeStrategies/multiAuthStrategy.js +35 -52
  54. package/lib-esm/datastore/datastore.d.ts +4 -5
  55. package/lib-esm/datastore/datastore.js +888 -1247
  56. package/lib-esm/index.d.ts +1 -1
  57. package/lib-esm/index.js +6 -7
  58. package/lib-esm/predicates/index.js +53 -70
  59. package/lib-esm/predicates/next.d.ts +2 -2
  60. package/lib-esm/predicates/next.js +306 -459
  61. package/lib-esm/predicates/sort.js +23 -28
  62. package/lib-esm/ssr/index.js +1 -2
  63. package/lib-esm/storage/adapter/AsyncStorageAdapter.js +111 -338
  64. package/lib-esm/storage/adapter/AsyncStorageDatabase.js +212 -416
  65. package/lib-esm/storage/adapter/InMemoryStore.js +27 -52
  66. package/lib-esm/storage/adapter/InMemoryStore.native.js +0 -1
  67. package/lib-esm/storage/adapter/IndexedDBAdapter.js +438 -866
  68. package/lib-esm/storage/adapter/StorageAdapterBase.js +173 -325
  69. package/lib-esm/storage/adapter/getDefaultAdapter/index.js +2 -6
  70. package/lib-esm/storage/adapter/getDefaultAdapter/index.native.js +1 -2
  71. package/lib-esm/storage/adapter/index.js +1 -1
  72. package/lib-esm/storage/relationship.js +173 -251
  73. package/lib-esm/storage/storage.d.ts +4 -4
  74. package/lib-esm/storage/storage.js +242 -424
  75. package/lib-esm/sync/datastoreConnectivity.d.ts +2 -2
  76. package/lib-esm/sync/datastoreConnectivity.js +28 -39
  77. package/lib-esm/sync/datastoreReachability/index.d.ts +1 -3
  78. package/lib-esm/sync/datastoreReachability/index.js +2 -3
  79. package/lib-esm/sync/datastoreReachability/index.native.d.ts +1 -3
  80. package/lib-esm/sync/datastoreReachability/index.native.js +3 -4
  81. package/lib-esm/sync/index.d.ts +2 -2
  82. package/lib-esm/sync/index.js +502 -812
  83. package/lib-esm/sync/merger.js +28 -61
  84. package/lib-esm/sync/outbox.js +143 -228
  85. package/lib-esm/sync/processors/errorMaps.d.ts +1 -1
  86. package/lib-esm/sync/processors/errorMaps.js +32 -50
  87. package/lib-esm/sync/processors/mutation.d.ts +2 -2
  88. package/lib-esm/sync/processors/mutation.js +329 -490
  89. package/lib-esm/sync/processors/subscription.d.ts +5 -2
  90. package/lib-esm/sync/processors/subscription.js +266 -421
  91. package/lib-esm/sync/processors/sync.d.ts +2 -2
  92. package/lib-esm/sync/processors/sync.js +271 -397
  93. package/lib-esm/sync/utils.d.ts +5 -4
  94. package/lib-esm/sync/utils.js +252 -307
  95. package/lib-esm/tsconfig.tsbuildinfo +1 -0
  96. package/lib-esm/types.d.ts +138 -140
  97. package/lib-esm/types.js +16 -25
  98. package/lib-esm/util.d.ts +9 -17
  99. package/lib-esm/util.js +335 -497
  100. package/package.json +31 -26
  101. package/src/authModeStrategies/multiAuthStrategy.ts +15 -12
  102. package/src/datastore/datastore.ts +36 -35
  103. package/src/predicates/sort.ts +3 -1
  104. package/src/storage/adapter/InMemoryStore.ts +1 -1
  105. package/src/storage/adapter/IndexedDBAdapter.ts +2 -2
  106. package/src/storage/adapter/StorageAdapterBase.ts +2 -2
  107. package/src/storage/adapter/getDefaultAdapter/index.ts +1 -4
  108. package/src/storage/storage.ts +29 -24
  109. package/src/sync/datastoreConnectivity.ts +6 -6
  110. package/src/sync/datastoreReachability/index.native.ts +5 -3
  111. package/src/sync/datastoreReachability/index.ts +1 -1
  112. package/src/sync/index.ts +79 -89
  113. package/src/sync/processors/errorMaps.ts +7 -7
  114. package/src/sync/processors/mutation.ts +19 -13
  115. package/src/sync/processors/subscription.ts +221 -295
  116. package/src/sync/processors/sync.ts +11 -8
  117. package/src/sync/utils.ts +30 -15
  118. package/src/types.ts +4 -8
  119. package/src/util.ts +46 -9
  120. package/lib/.tsbuildinfo +0 -3
  121. package/lib/authModeStrategies/defaultAuthStrategy.js.map +0 -1
  122. package/lib/authModeStrategies/index.js.map +0 -1
  123. package/lib/authModeStrategies/multiAuthStrategy.js.map +0 -1
  124. package/lib/datastore/datastore.js.map +0 -1
  125. package/lib/index.js.map +0 -1
  126. package/lib/predicates/index.js.map +0 -1
  127. package/lib/predicates/next.js.map +0 -1
  128. package/lib/predicates/sort.js.map +0 -1
  129. package/lib/ssr/index.js.map +0 -1
  130. package/lib/storage/adapter/AsyncStorageAdapter.js.map +0 -1
  131. package/lib/storage/adapter/AsyncStorageDatabase.js.map +0 -1
  132. package/lib/storage/adapter/InMemoryStore.js.map +0 -1
  133. package/lib/storage/adapter/InMemoryStore.native.js.map +0 -1
  134. package/lib/storage/adapter/IndexedDBAdapter.js.map +0 -1
  135. package/lib/storage/adapter/StorageAdapterBase.js.map +0 -1
  136. package/lib/storage/adapter/getDefaultAdapter/index.js.map +0 -1
  137. package/lib/storage/adapter/getDefaultAdapter/index.native.js.map +0 -1
  138. package/lib/storage/adapter/index.js.map +0 -1
  139. package/lib/storage/relationship.js.map +0 -1
  140. package/lib/storage/storage.js.map +0 -1
  141. package/lib/sync/datastoreConnectivity.js.map +0 -1
  142. package/lib/sync/datastoreReachability/index.js.map +0 -1
  143. package/lib/sync/datastoreReachability/index.native.js.map +0 -1
  144. package/lib/sync/index.js.map +0 -1
  145. package/lib/sync/merger.js.map +0 -1
  146. package/lib/sync/outbox.js.map +0 -1
  147. package/lib/sync/processors/errorMaps.js.map +0 -1
  148. package/lib/sync/processors/mutation.js.map +0 -1
  149. package/lib/sync/processors/subscription.js.map +0 -1
  150. package/lib/sync/processors/sync.js.map +0 -1
  151. package/lib/sync/utils.js.map +0 -1
  152. package/lib/types.js.map +0 -1
  153. package/lib/util.js.map +0 -1
  154. package/lib-esm/.tsbuildinfo +0 -3
  155. package/lib-esm/authModeStrategies/defaultAuthStrategy.js.map +0 -1
  156. package/lib-esm/authModeStrategies/index.js.map +0 -1
  157. package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +0 -1
  158. package/lib-esm/datastore/datastore.js.map +0 -1
  159. package/lib-esm/index.js.map +0 -1
  160. package/lib-esm/predicates/index.js.map +0 -1
  161. package/lib-esm/predicates/next.js.map +0 -1
  162. package/lib-esm/predicates/sort.js.map +0 -1
  163. package/lib-esm/ssr/index.js.map +0 -1
  164. package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +0 -1
  165. package/lib-esm/storage/adapter/AsyncStorageDatabase.js.map +0 -1
  166. package/lib-esm/storage/adapter/InMemoryStore.js.map +0 -1
  167. package/lib-esm/storage/adapter/InMemoryStore.native.js.map +0 -1
  168. package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +0 -1
  169. package/lib-esm/storage/adapter/StorageAdapterBase.js.map +0 -1
  170. package/lib-esm/storage/adapter/getDefaultAdapter/index.js.map +0 -1
  171. package/lib-esm/storage/adapter/getDefaultAdapter/index.native.js.map +0 -1
  172. package/lib-esm/storage/adapter/index.js.map +0 -1
  173. package/lib-esm/storage/relationship.js.map +0 -1
  174. package/lib-esm/storage/storage.js.map +0 -1
  175. package/lib-esm/sync/datastoreConnectivity.js.map +0 -1
  176. package/lib-esm/sync/datastoreReachability/index.js.map +0 -1
  177. package/lib-esm/sync/datastoreReachability/index.native.js.map +0 -1
  178. package/lib-esm/sync/index.js.map +0 -1
  179. package/lib-esm/sync/merger.js.map +0 -1
  180. package/lib-esm/sync/outbox.js.map +0 -1
  181. package/lib-esm/sync/processors/errorMaps.js.map +0 -1
  182. package/lib-esm/sync/processors/mutation.js.map +0 -1
  183. package/lib-esm/sync/processors/subscription.js.map +0 -1
  184. package/lib-esm/sync/processors/sync.js.map +0 -1
  185. package/lib-esm/sync/utils.js.map +0 -1
  186. package/lib-esm/types.js.map +0 -1
  187. package/lib-esm/util.js.map +0 -1
@@ -1,9 +1,8 @@
1
- import { __awaiter, __generator, __read, __spread, __values } from "tslib";
2
1
  // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
2
  // SPDX-License-Identifier: Apache-2.0
4
- import { browserOrNode, ConsoleLogger as Logger, BackgroundProcessManager, Hub, } from '@aws-amplify/core';
5
- import { CONTROL_MSG as PUBSUB_CONTROL_MSG, CONNECTION_STATE_CHANGE as PUBSUB_CONNECTION_STATE_CHANGE, ConnectionState, } from '@aws-amplify/pubsub';
6
- import Observable from 'zen-observable-ts';
3
+ import { BackgroundProcessManager } from '@aws-amplify/core/internals/utils';
4
+ import { Hub, ConsoleLogger } from '@aws-amplify/core';
5
+ import { filter, Observable, of } from 'rxjs';
7
6
  import { ModelPredicateCreator } from '../predicates';
8
7
  import { OpType, } from '../types';
9
8
  import { getNow, SYNC, USER } from '../util';
@@ -14,9 +13,9 @@ import { MutationProcessor } from './processors/mutation';
14
13
  import { CONTROL_MSG, SubscriptionProcessor } from './processors/subscription';
15
14
  import { SyncProcessor } from './processors/sync';
16
15
  import { createMutationInstanceFromModelOperation, getIdentifierValue, predicateToGraphQLCondition, } from './utils';
17
- var isNode = browserOrNode().isNode;
18
- var logger = new Logger('DataStore');
19
- var ownSymbol = Symbol('sync');
16
+ import { CONTROL_MSG as PUBSUB_CONTROL_MSG, ConnectionState, CONNECTION_STATE_CHANGE as PUBSUB_CONNECTION_STATE_CHANGE, } from '@aws-amplify/api-graphql';
17
+ const logger = new ConsoleLogger('DataStore');
18
+ const ownSymbol = Symbol('sync');
20
19
  export var ControlMessage;
21
20
  (function (ControlMessage) {
22
21
  ControlMessage["SYNC_ENGINE_STORAGE_SUBSCRIBED"] = "storageSubscribed";
@@ -30,10 +29,11 @@ export var ControlMessage;
30
29
  ControlMessage["SYNC_ENGINE_NETWORK_STATUS"] = "networkStatus";
31
30
  ControlMessage["SYNC_ENGINE_READY"] = "ready";
32
31
  })(ControlMessage || (ControlMessage = {}));
33
- var SyncEngine = /** @class */ (function () {
34
- function SyncEngine(schema, namespaceResolver, modelClasses, userModelClasses, storage, modelInstanceCreator, conflictHandler, errorHandler, syncPredicates, amplifyConfig, authModeStrategy, amplifyContext, connectivityMonitor) {
35
- var _this = this;
36
- if (amplifyConfig === void 0) { amplifyConfig = {}; }
32
+ export class SyncEngine {
33
+ getModelSyncedStatus(modelConstructor) {
34
+ return this.modelSyncedStatus.get(modelConstructor);
35
+ }
36
+ constructor(schema, namespaceResolver, modelClasses, userModelClasses, storage, modelInstanceCreator, conflictHandler, errorHandler, syncPredicates, amplifyConfig = {}, authModeStrategy, amplifyContext, connectivityMonitor) {
37
37
  this.schema = schema;
38
38
  this.namespaceResolver = namespaceResolver;
39
39
  this.modelClasses = modelClasses;
@@ -49,10 +49,10 @@ var SyncEngine = /** @class */ (function () {
49
49
  this.modelSyncedStatus = new WeakMap();
50
50
  this.connectionDisrupted = false;
51
51
  this.runningProcesses = new BackgroundProcessManager();
52
- this.waitForSleepState = new Promise(function (resolve) {
53
- _this.syncQueriesObservableStartSleeping = resolve;
52
+ this.waitForSleepState = new Promise(resolve => {
53
+ this.syncQueriesObservableStartSleeping = resolve;
54
54
  });
55
- var MutationEvent = this.modelClasses['MutationEvent'];
55
+ const MutationEvent = this.modelClasses['MutationEvent'];
56
56
  this.outbox = new MutationEventOutbox(this.schema, MutationEvent, modelInstanceCreator, ownSymbol);
57
57
  this.modelMerger = new ModelMerger(this.outbox, ownSymbol);
58
58
  this.syncQueriesProcessor = new SyncProcessor(this.schema, this.syncPredicates, this.amplifyConfig, this.authModeStrategy, errorHandler, this.amplifyContext);
@@ -61,813 +61,510 @@ var SyncEngine = /** @class */ (function () {
61
61
  this.datastoreConnectivity =
62
62
  this.connectivityMonitor || new DataStoreConnectivity();
63
63
  }
64
- SyncEngine.prototype.getModelSyncedStatus = function (modelConstructor) {
65
- return this.modelSyncedStatus.get(modelConstructor);
66
- };
67
- SyncEngine.prototype.start = function (params) {
68
- var _this = this;
69
- return new Observable(function (observer) {
64
+ start(params) {
65
+ return new Observable(observer => {
70
66
  logger.log('starting sync engine...');
71
- var subscriptions = [];
72
- _this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
73
- var err_1, startPromise, hasMutationsInOutbox;
74
- var _this = this;
75
- return __generator(this, function (_a) {
76
- switch (_a.label) {
77
- case 0:
78
- _a.trys.push([0, 2, , 3]);
79
- return [4 /*yield*/, this.setupModels(params)];
80
- case 1:
81
- _a.sent();
82
- return [3 /*break*/, 3];
83
- case 2:
84
- err_1 = _a.sent();
85
- observer.error(err_1);
86
- return [2 /*return*/];
87
- case 3:
88
- startPromise = new Promise(function (doneStarting, failedStarting) {
89
- _this.datastoreConnectivity.status().subscribe(function (_a) {
90
- var online = _a.online;
91
- return __awaiter(_this, void 0, void 0, function () {
92
- var _this = this;
93
- return __generator(this, function (_b) {
94
- return [2 /*return*/, this.runningProcesses.isOpen &&
95
- this.runningProcesses.add(function (onTerminate) { return __awaiter(_this, void 0, void 0, function () {
96
- var ctlSubsObservable_1, dataSubsObservable, err_2, error_1;
97
- var _a;
98
- var _this = this;
99
- return __generator(this, function (_b) {
100
- switch (_b.label) {
101
- case 0:
102
- if (!(online && !this.online)) return [3 /*break*/, 10];
103
- this.online = online;
104
- observer.next({
105
- type: ControlMessage.SYNC_ENGINE_NETWORK_STATUS,
106
- data: {
107
- active: this.online,
108
- },
109
- });
110
- dataSubsObservable = void 0;
111
- if (!isNode) return [3 /*break*/, 1];
112
- logger.warn('Realtime disabled when in a server-side environment');
113
- return [3 /*break*/, 6];
114
- case 1:
115
- this.stopDisruptionListener =
116
- this.startDisruptionListener();
117
- //#region GraphQL Subscriptions
118
- _a = __read(this.subscriptionsProcessor.start(), 2), ctlSubsObservable_1 = _a[0], dataSubsObservable = _a[1];
119
- _b.label = 2;
120
- case 2:
121
- _b.trys.push([2, 4, , 5]);
122
- return [4 /*yield*/, new Promise(function (resolve, reject) {
123
- onTerminate.then(reject);
124
- var ctlSubsSubscription = ctlSubsObservable_1.subscribe({
125
- next: function (msg) {
126
- if (msg === CONTROL_MSG.CONNECTED) {
127
- resolve();
128
- }
129
- },
130
- error: function (err) {
131
- reject(err);
132
- var handleDisconnect = _this.disconnectionHandler();
133
- handleDisconnect(err);
134
- },
135
- });
136
- subscriptions.push(ctlSubsSubscription);
137
- })];
138
- case 3:
139
- _b.sent();
140
- return [3 /*break*/, 5];
141
- case 4:
142
- err_2 = _b.sent();
143
- observer.error(err_2);
144
- failedStarting();
145
- return [2 /*return*/];
146
- case 5:
147
- logger.log('Realtime ready');
148
- observer.next({
149
- type: ControlMessage.SYNC_ENGINE_SUBSCRIPTIONS_ESTABLISHED,
150
- });
151
- _b.label = 6;
152
- case 6:
153
- _b.trys.push([6, 8, , 9]);
154
- return [4 /*yield*/, new Promise(function (resolve, reject) {
155
- var syncQuerySubscription = _this.syncQueriesObservable().subscribe({
156
- next: function (message) {
157
- var type = message.type;
158
- if (type ===
159
- ControlMessage.SYNC_ENGINE_SYNC_QUERIES_READY) {
160
- resolve();
161
- }
162
- observer.next(message);
163
- },
164
- complete: function () {
165
- resolve();
166
- },
167
- error: function (error) {
168
- reject(error);
169
- },
170
- });
171
- if (syncQuerySubscription) {
172
- subscriptions.push(syncQuerySubscription);
173
- }
174
- })];
175
- case 7:
176
- _b.sent();
177
- return [3 /*break*/, 9];
178
- case 8:
179
- error_1 = _b.sent();
180
- observer.error(error_1);
181
- failedStarting();
182
- return [2 /*return*/];
183
- case 9:
184
- //#endregion
185
- //#region process mutations (outbox)
186
- subscriptions.push(this.mutationsProcessor
187
- .start()
188
- .subscribe(function (_a) {
189
- var modelDefinition = _a.modelDefinition, item = _a.model, hasMore = _a.hasMore;
190
- return _this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
191
- var modelConstructor, model;
192
- var _this = this;
193
- return __generator(this, function (_a) {
194
- switch (_a.label) {
195
- case 0:
196
- modelConstructor = this.userModelClasses[modelDefinition.name];
197
- model = this.modelInstanceCreator(modelConstructor, item);
198
- return [4 /*yield*/, this.storage.runExclusive(function (storage) {
199
- return _this.modelMerger.merge(storage, model, modelDefinition);
200
- })];
201
- case 1:
202
- _a.sent();
203
- observer.next({
204
- type: ControlMessage.SYNC_ENGINE_OUTBOX_MUTATION_PROCESSED,
205
- data: {
206
- model: modelConstructor,
207
- element: model,
208
- },
209
- });
210
- observer.next({
211
- type: ControlMessage.SYNC_ENGINE_OUTBOX_STATUS,
212
- data: {
213
- isEmpty: !hasMore,
214
- },
215
- });
216
- return [2 /*return*/];
217
- }
218
- });
219
- }); }, 'mutation processor event');
220
- }));
221
- //#endregion
222
- //#region Merge subscriptions buffer
223
- // TODO: extract to function
224
- if (!isNode) {
225
- subscriptions.push(dataSubsObservable.subscribe(function (_a) {
226
- var _b = __read(_a, 3), _transformerMutationType = _b[0], modelDefinition = _b[1], item = _b[2];
227
- return _this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
228
- var modelConstructor, model;
229
- var _this = this;
230
- return __generator(this, function (_a) {
231
- switch (_a.label) {
232
- case 0:
233
- modelConstructor = this.userModelClasses[modelDefinition.name];
234
- model = this.modelInstanceCreator(modelConstructor, item);
235
- return [4 /*yield*/, this.storage.runExclusive(function (storage) {
236
- return _this.modelMerger.merge(storage, model, modelDefinition);
237
- })];
238
- case 1:
239
- _a.sent();
240
- return [2 /*return*/];
241
- }
242
- });
243
- }); }, 'subscription dataSubsObservable event');
244
- }));
245
- }
246
- return [3 /*break*/, 11];
247
- case 10:
248
- if (!online) {
249
- this.online = online;
250
- observer.next({
251
- type: ControlMessage.SYNC_ENGINE_NETWORK_STATUS,
252
- data: {
253
- active: this.online,
254
- },
255
- });
256
- subscriptions.forEach(function (sub) { return sub.unsubscribe(); });
257
- subscriptions = [];
258
- }
259
- _b.label = 11;
260
- case 11:
261
- doneStarting();
262
- return [2 /*return*/];
263
- }
264
- });
265
- }); }, 'datastore connectivity event')];
67
+ let subscriptions = [];
68
+ this.runningProcesses.add(async () => {
69
+ try {
70
+ await this.setupModels(params);
71
+ }
72
+ catch (err) {
73
+ observer.error(err);
74
+ return;
75
+ }
76
+ // this is awaited at the bottom. so, we don't need to register
77
+ // this explicitly with the context. it's already contained.
78
+ const startPromise = new Promise((doneStarting, failedStarting) => {
79
+ this.datastoreConnectivity.status().subscribe(async ({ online }) => this.runningProcesses.isOpen &&
80
+ this.runningProcesses.add(async (onTerminate) => {
81
+ // From offline to online
82
+ if (online && !this.online) {
83
+ this.online = online;
84
+ observer.next({
85
+ type: ControlMessage.SYNC_ENGINE_NETWORK_STATUS,
86
+ data: {
87
+ active: this.online,
88
+ },
89
+ });
90
+ let ctlSubsObservable;
91
+ let dataSubsObservable;
92
+ this.stopDisruptionListener =
93
+ this.startDisruptionListener();
94
+ //#region GraphQL Subscriptions
95
+ [ctlSubsObservable, dataSubsObservable] =
96
+ this.subscriptionsProcessor.start();
97
+ try {
98
+ await new Promise((resolve, reject) => {
99
+ onTerminate.then(reject);
100
+ const ctlSubsSubscription = ctlSubsObservable.subscribe({
101
+ next: msg => {
102
+ if (msg === CONTROL_MSG.CONNECTED) {
103
+ resolve();
104
+ }
105
+ },
106
+ error: err => {
107
+ reject(err);
108
+ const handleDisconnect = this.disconnectionHandler();
109
+ handleDisconnect(err);
110
+ },
266
111
  });
112
+ subscriptions.push(ctlSubsSubscription);
267
113
  });
114
+ }
115
+ catch (err) {
116
+ observer.error(err);
117
+ failedStarting();
118
+ return;
119
+ }
120
+ logger.log('Realtime ready');
121
+ observer.next({
122
+ type: ControlMessage.SYNC_ENGINE_SUBSCRIPTIONS_ESTABLISHED,
268
123
  });
269
- });
270
- this.storage
271
- .observe(null, null, ownSymbol)
272
- .filter(function (_a) {
273
- var model = _a.model;
274
- var modelDefinition = _this.getModelDefinition(model);
275
- return modelDefinition.syncable === true;
276
- })
124
+ //#endregion
125
+ //#region Base & Sync queries
126
+ try {
127
+ await new Promise((resolve, reject) => {
128
+ const syncQuerySubscription = this.syncQueriesObservable().subscribe({
129
+ next: message => {
130
+ const { type } = message;
131
+ if (type ===
132
+ ControlMessage.SYNC_ENGINE_SYNC_QUERIES_READY) {
133
+ resolve();
134
+ }
135
+ observer.next(message);
136
+ },
137
+ complete: () => {
138
+ resolve();
139
+ },
140
+ error: error => {
141
+ reject(error);
142
+ },
143
+ });
144
+ if (syncQuerySubscription) {
145
+ subscriptions.push(syncQuerySubscription);
146
+ }
147
+ });
148
+ }
149
+ catch (error) {
150
+ observer.error(error);
151
+ failedStarting();
152
+ return;
153
+ }
154
+ //#endregion
155
+ //#region process mutations (outbox)
156
+ subscriptions.push(this.mutationsProcessor
157
+ .start()
158
+ .subscribe(({ modelDefinition, model: item, hasMore }) => this.runningProcesses.add(async () => {
159
+ const modelConstructor = this.userModelClasses[modelDefinition.name];
160
+ const model = this.modelInstanceCreator(modelConstructor, item);
161
+ await this.storage.runExclusive(storage => this.modelMerger.merge(storage, model, modelDefinition));
162
+ observer.next({
163
+ type: ControlMessage.SYNC_ENGINE_OUTBOX_MUTATION_PROCESSED,
164
+ data: {
165
+ model: modelConstructor,
166
+ element: model,
167
+ },
168
+ });
169
+ observer.next({
170
+ type: ControlMessage.SYNC_ENGINE_OUTBOX_STATUS,
171
+ data: {
172
+ isEmpty: !hasMore,
173
+ },
174
+ });
175
+ }, 'mutation processor event')));
176
+ //#endregion
177
+ //#region Merge subscriptions buffer
178
+ subscriptions.push(dataSubsObservable.subscribe(([_transformerMutationType, modelDefinition, item]) => this.runningProcesses.add(async () => {
179
+ const modelConstructor = this.userModelClasses[modelDefinition.name];
180
+ const model = this.modelInstanceCreator(modelConstructor, item);
181
+ await this.storage.runExclusive(storage => this.modelMerger.merge(storage, model, modelDefinition));
182
+ }, 'subscription dataSubsObservable event')));
183
+ //#endregion
184
+ }
185
+ else if (!online) {
186
+ this.online = online;
187
+ observer.next({
188
+ type: ControlMessage.SYNC_ENGINE_NETWORK_STATUS,
189
+ data: {
190
+ active: this.online,
191
+ },
192
+ });
193
+ subscriptions.forEach(sub => sub.unsubscribe());
194
+ subscriptions = [];
195
+ }
196
+ doneStarting();
197
+ }, 'datastore connectivity event'));
198
+ });
199
+ this.storage
200
+ .observe(null, null, ownSymbol)
201
+ .pipe(filter(({ model }) => {
202
+ const modelDefinition = this.getModelDefinition(model);
203
+ return modelDefinition.syncable === true;
204
+ }))
205
+ .subscribe({
206
+ next: async ({ opType, model, element, condition }) => this.runningProcesses.add(async () => {
207
+ const namespace = this.schema.namespaces[this.namespaceResolver(model)];
208
+ const MutationEventConstructor = this.modelClasses['MutationEvent'];
209
+ const modelDefinition = this.getModelDefinition(model);
210
+ const graphQLCondition = predicateToGraphQLCondition(condition, modelDefinition);
211
+ const mutationEvent = createMutationInstanceFromModelOperation(namespace.relationships, this.getModelDefinition(model), opType, model, element, graphQLCondition, MutationEventConstructor, this.modelInstanceCreator);
212
+ await this.outbox.enqueue(this.storage, mutationEvent);
213
+ observer.next({
214
+ type: ControlMessage.SYNC_ENGINE_OUTBOX_MUTATION_ENQUEUED,
215
+ data: {
216
+ model,
217
+ element,
218
+ },
219
+ });
220
+ observer.next({
221
+ type: ControlMessage.SYNC_ENGINE_OUTBOX_STATUS,
222
+ data: {
223
+ isEmpty: false,
224
+ },
225
+ });
226
+ await startPromise;
227
+ // Set by the this.datastoreConnectivity.status().subscribe() loop
228
+ if (this.online) {
229
+ this.mutationsProcessor.resume();
230
+ }
231
+ }, 'storage event'),
232
+ });
233
+ observer.next({
234
+ type: ControlMessage.SYNC_ENGINE_STORAGE_SUBSCRIBED,
235
+ });
236
+ const hasMutationsInOutbox = (await this.outbox.peek(this.storage)) === undefined;
237
+ observer.next({
238
+ type: ControlMessage.SYNC_ENGINE_OUTBOX_STATUS,
239
+ data: {
240
+ isEmpty: hasMutationsInOutbox,
241
+ },
242
+ });
243
+ await startPromise;
244
+ observer.next({
245
+ type: ControlMessage.SYNC_ENGINE_READY,
246
+ });
247
+ }, 'sync start');
248
+ });
249
+ }
250
+ async getModelsMetadataWithNextFullSync(currentTimeStamp) {
251
+ const modelLastSync = new Map((await this.runningProcesses.add(() => this.getModelsMetadata(), 'sync/index getModelsMetadataWithNextFullSync')).map(({ namespace, model, lastSync, lastFullSync, fullSyncInterval, lastSyncPredicate, }) => {
252
+ const nextFullSync = lastFullSync + fullSyncInterval;
253
+ const syncFrom = !lastFullSync || nextFullSync < currentTimeStamp
254
+ ? 0 // perform full sync if expired
255
+ : lastSync; // perform delta sync
256
+ return [
257
+ this.schema.namespaces[namespace].models[model],
258
+ [namespace, syncFrom],
259
+ ];
260
+ }));
261
+ return modelLastSync;
262
+ }
263
+ syncQueriesObservable() {
264
+ if (!this.online) {
265
+ return of({}); // TODO(v6): fix this
266
+ }
267
+ return new Observable(observer => {
268
+ let syncQueriesSubscription;
269
+ this.runningProcesses.isOpen &&
270
+ this.runningProcesses.add(async (onTerminate) => {
271
+ let terminated = false;
272
+ while (!observer.closed && !terminated) {
273
+ const count = new WeakMap();
274
+ const modelLastSync = await this.getModelsMetadataWithNextFullSync(Date.now());
275
+ const paginatingModels = new Set(modelLastSync.keys());
276
+ let lastFullSyncStartedAt;
277
+ let syncInterval;
278
+ let start;
279
+ let syncDuration;
280
+ let lastStartedAt;
281
+ await new Promise((resolve, reject) => {
282
+ if (!this.runningProcesses.isOpen)
283
+ resolve();
284
+ onTerminate.then(() => resolve());
285
+ syncQueriesSubscription = this.syncQueriesProcessor
286
+ .start(modelLastSync)
277
287
  .subscribe({
278
- next: function (_a) {
279
- var opType = _a.opType, model = _a.model, element = _a.element, condition = _a.condition;
280
- return __awaiter(_this, void 0, void 0, function () {
281
- var _this = this;
282
- return __generator(this, function (_b) {
283
- return [2 /*return*/, this.runningProcesses.add(function () { return __awaiter(_this, void 0, void 0, function () {
284
- var namespace, MutationEventConstructor, modelDefinition, graphQLCondition, mutationEvent;
285
- return __generator(this, function (_a) {
286
- switch (_a.label) {
287
- case 0:
288
- namespace = this.schema.namespaces[this.namespaceResolver(model)];
289
- MutationEventConstructor = this.modelClasses['MutationEvent'];
290
- modelDefinition = this.getModelDefinition(model);
291
- graphQLCondition = predicateToGraphQLCondition(condition, modelDefinition);
292
- mutationEvent = createMutationInstanceFromModelOperation(namespace.relationships, this.getModelDefinition(model), opType, model, element, graphQLCondition, MutationEventConstructor, this.modelInstanceCreator);
293
- return [4 /*yield*/, this.outbox.enqueue(this.storage, mutationEvent)];
294
- case 1:
295
- _a.sent();
296
- observer.next({
297
- type: ControlMessage.SYNC_ENGINE_OUTBOX_MUTATION_ENQUEUED,
298
- data: {
299
- model: model,
300
- element: element,
301
- },
302
- });
303
- observer.next({
304
- type: ControlMessage.SYNC_ENGINE_OUTBOX_STATUS,
305
- data: {
306
- isEmpty: false,
307
- },
308
- });
309
- return [4 /*yield*/, startPromise];
310
- case 2:
311
- _a.sent();
312
- // Set by the this.datastoreConnectivity.status().subscribe() loop
313
- if (this.online) {
314
- this.mutationsProcessor.resume();
315
- }
316
- return [2 /*return*/];
317
- }
318
- });
319
- }); }, 'storage event')];
288
+ next: async ({ namespace, modelDefinition, items, done, startedAt, isFullSync, }) => {
289
+ const modelConstructor = this.userModelClasses[modelDefinition.name];
290
+ if (!count.has(modelConstructor)) {
291
+ count.set(modelConstructor, {
292
+ new: 0,
293
+ updated: 0,
294
+ deleted: 0,
295
+ });
296
+ start = getNow();
297
+ lastStartedAt =
298
+ lastStartedAt === undefined
299
+ ? startedAt
300
+ : Math.max(lastStartedAt, startedAt);
301
+ }
302
+ /**
303
+ * If there are mutations in the outbox for a given id, those need to be
304
+ * merged individually. Otherwise, we can merge them in batches.
305
+ */
306
+ await this.storage.runExclusive(async (storage) => {
307
+ const idsInOutbox = await this.outbox.getModelIds(storage);
308
+ const oneByOne = [];
309
+ const page = items.filter(item => {
310
+ const itemId = getIdentifierValue(modelDefinition, item);
311
+ if (!idsInOutbox.has(itemId)) {
312
+ return true;
313
+ }
314
+ oneByOne.push(item);
315
+ return false;
316
+ });
317
+ const opTypeCount = [];
318
+ for (const item of oneByOne) {
319
+ const opType = await this.modelMerger.merge(storage, item, modelDefinition);
320
+ if (opType !== undefined) {
321
+ opTypeCount.push([item, opType]);
322
+ }
323
+ }
324
+ opTypeCount.push(...(await this.modelMerger.mergePage(storage, modelConstructor, page, modelDefinition)));
325
+ const counts = count.get(modelConstructor);
326
+ opTypeCount.forEach(([, opType]) => {
327
+ switch (opType) {
328
+ case OpType.INSERT:
329
+ counts.new++;
330
+ break;
331
+ case OpType.UPDATE:
332
+ counts.updated++;
333
+ break;
334
+ case OpType.DELETE:
335
+ counts.deleted++;
336
+ break;
337
+ default:
338
+ throw new Error(`Invalid opType ${opType}`);
339
+ }
320
340
  });
321
341
  });
342
+ if (done) {
343
+ const { name: modelName } = modelDefinition;
344
+ //#region update last sync for type
345
+ let modelMetadata = await this.getModelMetadata(namespace, modelName);
346
+ const { lastFullSync, fullSyncInterval } = modelMetadata;
347
+ syncInterval = fullSyncInterval;
348
+ lastFullSyncStartedAt =
349
+ lastFullSyncStartedAt === undefined
350
+ ? lastFullSync
351
+ : Math.max(lastFullSyncStartedAt, isFullSync ? startedAt : lastFullSync);
352
+ modelMetadata = this.modelClasses
353
+ .ModelMetadata.copyOf(modelMetadata, draft => {
354
+ draft.lastSync = startedAt;
355
+ draft.lastFullSync = isFullSync
356
+ ? startedAt
357
+ : modelMetadata.lastFullSync;
358
+ });
359
+ await this.storage.save(modelMetadata, undefined, ownSymbol);
360
+ //#endregion
361
+ const counts = count.get(modelConstructor);
362
+ this.modelSyncedStatus.set(modelConstructor, true);
363
+ observer.next({
364
+ type: ControlMessage.SYNC_ENGINE_MODEL_SYNCED,
365
+ data: {
366
+ model: modelConstructor,
367
+ isFullSync,
368
+ isDeltaSync: !isFullSync,
369
+ counts,
370
+ },
371
+ });
372
+ paginatingModels.delete(modelDefinition);
373
+ if (paginatingModels.size === 0) {
374
+ syncDuration = getNow() - start;
375
+ resolve();
376
+ observer.next({
377
+ type: ControlMessage.SYNC_ENGINE_SYNC_QUERIES_READY,
378
+ });
379
+ syncQueriesSubscription.unsubscribe();
380
+ }
381
+ }
382
+ },
383
+ error: error => {
384
+ observer.error(error);
322
385
  },
323
386
  });
324
387
  observer.next({
325
- type: ControlMessage.SYNC_ENGINE_STORAGE_SUBSCRIBED,
326
- });
327
- return [4 /*yield*/, this.outbox.peek(this.storage)];
328
- case 4:
329
- hasMutationsInOutbox = (_a.sent()) === undefined;
330
- observer.next({
331
- type: ControlMessage.SYNC_ENGINE_OUTBOX_STATUS,
388
+ type: ControlMessage.SYNC_ENGINE_SYNC_QUERIES_STARTED,
332
389
  data: {
333
- isEmpty: hasMutationsInOutbox,
390
+ models: Array.from(paginatingModels).map(({ name }) => name),
334
391
  },
335
392
  });
336
- return [4 /*yield*/, startPromise];
337
- case 5:
338
- _a.sent();
339
- observer.next({
340
- type: ControlMessage.SYNC_ENGINE_READY,
393
+ });
394
+ // null is cast to 0 resulting in unexpected behavior.
395
+ // undefined in arithmetic operations results in NaN also resulting in unexpected behavior.
396
+ // If lastFullSyncStartedAt is null this is the first sync.
397
+ // Assume lastStartedAt is is also newest full sync.
398
+ let msNextFullSync;
399
+ if (!lastFullSyncStartedAt) {
400
+ msNextFullSync = syncInterval - syncDuration;
401
+ }
402
+ else {
403
+ msNextFullSync =
404
+ lastFullSyncStartedAt +
405
+ syncInterval -
406
+ (lastStartedAt + syncDuration);
407
+ }
408
+ logger.debug(`Next fullSync in ${msNextFullSync / 1000} seconds. (${new Date(Date.now() + msNextFullSync)})`);
409
+ // TODO: create `BackgroundProcessManager.sleep()` ... but, need to put
410
+ // a lot of thought into what that contract looks like to
411
+ // support possible use-cases:
412
+ //
413
+ // 1. non-cancelable
414
+ // 2. cancelable, unsleep on exit()
415
+ // 3. cancelable, throw Error on exit()
416
+ // 4. cancelable, callback first on exit()?
417
+ // 5. ... etc. ? ...
418
+ //
419
+ // TLDR; this is a lot of complexity here for a sleep(),
420
+ // but, it's not clear to me yet how to support an
421
+ // extensible, centralized cancelable `sleep()` elegantly.
422
+ await this.runningProcesses.add(async (onTerminate) => {
423
+ let sleepTimer;
424
+ let unsleep;
425
+ const sleep = new Promise(_unsleep => {
426
+ unsleep = _unsleep;
427
+ sleepTimer = setTimeout(unsleep, msNextFullSync);
428
+ });
429
+ onTerminate.then(() => {
430
+ terminated = true;
431
+ this.syncQueriesObservableStartSleeping();
432
+ unsleep();
341
433
  });
342
- return [2 /*return*/];
434
+ this.unsleepSyncQueriesObservable = unsleep;
435
+ this.syncQueriesObservableStartSleeping();
436
+ return sleep;
437
+ }, 'syncQueriesObservable sleep');
438
+ this.unsleepSyncQueriesObservable = null;
439
+ this.waitForSleepState = new Promise(resolve => {
440
+ this.syncQueriesObservableStartSleeping = resolve;
441
+ });
343
442
  }
344
- });
345
- }); }, 'sync start');
346
- });
347
- };
348
- SyncEngine.prototype.getModelsMetadataWithNextFullSync = function (currentTimeStamp) {
349
- return __awaiter(this, void 0, void 0, function () {
350
- var modelLastSync, _a;
351
- var _this = this;
352
- return __generator(this, function (_b) {
353
- switch (_b.label) {
354
- case 0:
355
- _a = Map.bind;
356
- return [4 /*yield*/, this.runningProcesses.add(function () { return _this.getModelsMetadata(); }, 'sync/index getModelsMetadataWithNextFullSync')];
357
- case 1:
358
- modelLastSync = new (_a.apply(Map, [void 0, (_b.sent()).map(function (_a) {
359
- var namespace = _a.namespace, model = _a.model, lastSync = _a.lastSync, lastFullSync = _a.lastFullSync, fullSyncInterval = _a.fullSyncInterval, lastSyncPredicate = _a.lastSyncPredicate;
360
- var nextFullSync = lastFullSync + fullSyncInterval;
361
- var syncFrom = !lastFullSync || nextFullSync < currentTimeStamp
362
- ? 0 // perform full sync if expired
363
- : lastSync; // perform delta sync
364
- return [
365
- _this.schema.namespaces[namespace].models[model],
366
- [namespace, syncFrom],
367
- ];
368
- })]))();
369
- return [2 /*return*/, modelLastSync];
370
- }
371
- });
372
- });
373
- };
374
- SyncEngine.prototype.syncQueriesObservable = function () {
375
- var _this = this;
376
- if (!this.online) {
377
- return Observable.of();
378
- }
379
- return new Observable(function (observer) {
380
- var syncQueriesSubscription;
381
- _this.runningProcesses.isOpen &&
382
- _this.runningProcesses.add(function (onTerminate) { return __awaiter(_this, void 0, void 0, function () {
383
- var terminated, _loop_1, this_1;
384
- var _this = this;
385
- return __generator(this, function (_a) {
386
- switch (_a.label) {
387
- case 0:
388
- terminated = false;
389
- _loop_1 = function () {
390
- var count, modelLastSync, paginatingModels, lastFullSyncStartedAt, syncInterval, start, syncDuration, lastStartedAt, msNextFullSync;
391
- return __generator(this, function (_a) {
392
- switch (_a.label) {
393
- case 0:
394
- count = new WeakMap();
395
- return [4 /*yield*/, this_1.getModelsMetadataWithNextFullSync(Date.now())];
396
- case 1:
397
- modelLastSync = _a.sent();
398
- paginatingModels = new Set(modelLastSync.keys());
399
- return [4 /*yield*/, new Promise(function (resolve, reject) {
400
- if (!_this.runningProcesses.isOpen)
401
- resolve();
402
- onTerminate.then(function () { return resolve(); });
403
- syncQueriesSubscription = _this.syncQueriesProcessor
404
- .start(modelLastSync)
405
- .subscribe({
406
- next: function (_a) {
407
- var namespace = _a.namespace, modelDefinition = _a.modelDefinition, items = _a.items, done = _a.done, startedAt = _a.startedAt, isFullSync = _a.isFullSync;
408
- return __awaiter(_this, void 0, void 0, function () {
409
- var modelConstructor, modelName, modelMetadata_1, lastFullSync, fullSyncInterval, counts;
410
- var _this = this;
411
- return __generator(this, function (_b) {
412
- switch (_b.label) {
413
- case 0:
414
- modelConstructor = this.userModelClasses[modelDefinition.name];
415
- if (!count.has(modelConstructor)) {
416
- count.set(modelConstructor, {
417
- new: 0,
418
- updated: 0,
419
- deleted: 0,
420
- });
421
- start = getNow();
422
- lastStartedAt =
423
- lastStartedAt === undefined
424
- ? startedAt
425
- : Math.max(lastStartedAt, startedAt);
426
- }
427
- /**
428
- * If there are mutations in the outbox for a given id, those need to be
429
- * merged individually. Otherwise, we can merge them in batches.
430
- */
431
- return [4 /*yield*/, this.storage.runExclusive(function (storage) { return __awaiter(_this, void 0, void 0, function () {
432
- var idsInOutbox, oneByOne, page, opTypeCount, oneByOne_1, oneByOne_1_1, item, opType, e_1_1, _a, _b, _c, counts;
433
- var e_1, _d;
434
- return __generator(this, function (_e) {
435
- switch (_e.label) {
436
- case 0: return [4 /*yield*/, this.outbox.getModelIds(storage)];
437
- case 1:
438
- idsInOutbox = _e.sent();
439
- oneByOne = [];
440
- page = items.filter(function (item) {
441
- var itemId = getIdentifierValue(modelDefinition, item);
442
- if (!idsInOutbox.has(itemId)) {
443
- return true;
444
- }
445
- oneByOne.push(item);
446
- return false;
447
- });
448
- opTypeCount = [];
449
- _e.label = 2;
450
- case 2:
451
- _e.trys.push([2, 7, 8, 9]);
452
- oneByOne_1 = __values(oneByOne), oneByOne_1_1 = oneByOne_1.next();
453
- _e.label = 3;
454
- case 3:
455
- if (!!oneByOne_1_1.done) return [3 /*break*/, 6];
456
- item = oneByOne_1_1.value;
457
- return [4 /*yield*/, this.modelMerger.merge(storage, item, modelDefinition)];
458
- case 4:
459
- opType = _e.sent();
460
- if (opType !== undefined) {
461
- opTypeCount.push([item, opType]);
462
- }
463
- _e.label = 5;
464
- case 5:
465
- oneByOne_1_1 = oneByOne_1.next();
466
- return [3 /*break*/, 3];
467
- case 6: return [3 /*break*/, 9];
468
- case 7:
469
- e_1_1 = _e.sent();
470
- e_1 = { error: e_1_1 };
471
- return [3 /*break*/, 9];
472
- case 8:
473
- try {
474
- if (oneByOne_1_1 && !oneByOne_1_1.done && (_d = oneByOne_1.return)) _d.call(oneByOne_1);
475
- }
476
- finally { if (e_1) throw e_1.error; }
477
- return [7 /*endfinally*/];
478
- case 9:
479
- _b = (_a = opTypeCount.push).apply;
480
- _c = [opTypeCount];
481
- return [4 /*yield*/, this.modelMerger.mergePage(storage, modelConstructor, page, modelDefinition)];
482
- case 10:
483
- _b.apply(_a, _c.concat([__spread.apply(void 0, [(_e.sent())])]));
484
- counts = count.get(modelConstructor);
485
- opTypeCount.forEach(function (_a) {
486
- var _b = __read(_a, 2), opType = _b[1];
487
- switch (opType) {
488
- case OpType.INSERT:
489
- counts.new++;
490
- break;
491
- case OpType.UPDATE:
492
- counts.updated++;
493
- break;
494
- case OpType.DELETE:
495
- counts.deleted++;
496
- break;
497
- default:
498
- throw new Error("Invalid opType " + opType);
499
- }
500
- });
501
- return [2 /*return*/];
502
- }
503
- });
504
- }); })];
505
- case 1:
506
- /**
507
- * If there are mutations in the outbox for a given id, those need to be
508
- * merged individually. Otherwise, we can merge them in batches.
509
- */
510
- _b.sent();
511
- if (!done) return [3 /*break*/, 4];
512
- modelName = modelDefinition.name;
513
- return [4 /*yield*/, this.getModelMetadata(namespace, modelName)];
514
- case 2:
515
- modelMetadata_1 = _b.sent();
516
- lastFullSync = modelMetadata_1.lastFullSync, fullSyncInterval = modelMetadata_1.fullSyncInterval;
517
- syncInterval = fullSyncInterval;
518
- lastFullSyncStartedAt =
519
- lastFullSyncStartedAt === undefined
520
- ? lastFullSync
521
- : Math.max(lastFullSyncStartedAt, isFullSync ? startedAt : lastFullSync);
522
- modelMetadata_1 = this.modelClasses
523
- .ModelMetadata.copyOf(modelMetadata_1, function (draft) {
524
- draft.lastSync = startedAt;
525
- draft.lastFullSync = isFullSync
526
- ? startedAt
527
- : modelMetadata_1.lastFullSync;
528
- });
529
- return [4 /*yield*/, this.storage.save(modelMetadata_1, undefined, ownSymbol)];
530
- case 3:
531
- _b.sent();
532
- counts = count.get(modelConstructor);
533
- this.modelSyncedStatus.set(modelConstructor, true);
534
- observer.next({
535
- type: ControlMessage.SYNC_ENGINE_MODEL_SYNCED,
536
- data: {
537
- model: modelConstructor,
538
- isFullSync: isFullSync,
539
- isDeltaSync: !isFullSync,
540
- counts: counts,
541
- },
542
- });
543
- paginatingModels.delete(modelDefinition);
544
- if (paginatingModels.size === 0) {
545
- syncDuration = getNow() - start;
546
- resolve();
547
- observer.next({
548
- type: ControlMessage.SYNC_ENGINE_SYNC_QUERIES_READY,
549
- });
550
- syncQueriesSubscription.unsubscribe();
551
- }
552
- _b.label = 4;
553
- case 4: return [2 /*return*/];
554
- }
555
- });
556
- });
557
- },
558
- error: function (error) {
559
- observer.error(error);
560
- },
561
- });
562
- observer.next({
563
- type: ControlMessage.SYNC_ENGINE_SYNC_QUERIES_STARTED,
564
- data: {
565
- models: Array.from(paginatingModels).map(function (_a) {
566
- var name = _a.name;
567
- return name;
568
- }),
569
- },
570
- });
571
- })];
572
- case 2:
573
- _a.sent();
574
- if (!lastFullSyncStartedAt) {
575
- msNextFullSync = syncInterval - syncDuration;
576
- }
577
- else {
578
- msNextFullSync =
579
- lastFullSyncStartedAt +
580
- syncInterval -
581
- (lastStartedAt + syncDuration);
582
- }
583
- logger.debug("Next fullSync in " + msNextFullSync / 1000 + " seconds. (" + new Date(Date.now() + msNextFullSync) + ")");
584
- // TODO: create `BackgroundProcessManager.sleep()` ... but, need to put
585
- // a lot of thought into what that contract looks like to
586
- // support possible use-cases:
587
- //
588
- // 1. non-cancelable
589
- // 2. cancelable, unsleep on exit()
590
- // 3. cancelable, throw Error on exit()
591
- // 4. cancelable, callback first on exit()?
592
- // 5. ... etc. ? ...
593
- //
594
- // TLDR; this is a lot of complexity here for a sleep(),
595
- // but, it's not clear to me yet how to support an
596
- // extensible, centralized cancelable `sleep()` elegantly.
597
- return [4 /*yield*/, this_1.runningProcesses.add(function (onTerminate) { return __awaiter(_this, void 0, void 0, function () {
598
- var sleepTimer, unsleep, sleep;
599
- var _this = this;
600
- return __generator(this, function (_a) {
601
- sleep = new Promise(function (_unsleep) {
602
- unsleep = _unsleep;
603
- sleepTimer = setTimeout(unsleep, msNextFullSync);
604
- });
605
- onTerminate.then(function () {
606
- terminated = true;
607
- _this.syncQueriesObservableStartSleeping();
608
- unsleep();
609
- });
610
- this.unsleepSyncQueriesObservable = unsleep;
611
- this.syncQueriesObservableStartSleeping();
612
- return [2 /*return*/, sleep];
613
- });
614
- }); }, 'syncQueriesObservable sleep')];
615
- case 3:
616
- // TODO: create `BackgroundProcessManager.sleep()` ... but, need to put
617
- // a lot of thought into what that contract looks like to
618
- // support possible use-cases:
619
- //
620
- // 1. non-cancelable
621
- // 2. cancelable, unsleep on exit()
622
- // 3. cancelable, throw Error on exit()
623
- // 4. cancelable, callback first on exit()?
624
- // 5. ... etc. ? ...
625
- //
626
- // TLDR; this is a lot of complexity here for a sleep(),
627
- // but, it's not clear to me yet how to support an
628
- // extensible, centralized cancelable `sleep()` elegantly.
629
- _a.sent();
630
- this_1.unsleepSyncQueriesObservable = null;
631
- this_1.waitForSleepState = new Promise(function (resolve) {
632
- _this.syncQueriesObservableStartSleeping = resolve;
633
- });
634
- return [2 /*return*/];
635
- }
636
- });
637
- };
638
- this_1 = this;
639
- _a.label = 1;
640
- case 1:
641
- if (!(!observer.closed && !terminated)) return [3 /*break*/, 3];
642
- return [5 /*yield**/, _loop_1()];
643
- case 2:
644
- _a.sent();
645
- return [3 /*break*/, 1];
646
- case 3: return [2 /*return*/];
647
- }
648
- });
649
- }); }, 'syncQueriesObservable main');
443
+ }, 'syncQueriesObservable main');
650
444
  });
651
- };
652
- SyncEngine.prototype.disconnectionHandler = function () {
653
- var _this = this;
654
- return function (msg) {
445
+ }
446
+ disconnectionHandler() {
447
+ return (msg) => {
655
448
  // This implementation is tied to AWSAppSyncRealTimeProvider 'Connection closed', 'Timeout disconnect' msg
656
449
  if (PUBSUB_CONTROL_MSG.CONNECTION_CLOSED === msg ||
657
450
  PUBSUB_CONTROL_MSG.TIMEOUT_DISCONNECT === msg) {
658
- _this.datastoreConnectivity.socketDisconnected();
451
+ this.datastoreConnectivity.socketDisconnected();
659
452
  }
660
453
  };
661
- };
662
- SyncEngine.prototype.unsubscribeConnectivity = function () {
454
+ }
455
+ unsubscribeConnectivity() {
663
456
  this.datastoreConnectivity.unsubscribe();
664
- };
457
+ }
665
458
  /**
666
459
  * Stops all subscription activities and resolves when all activies report
667
460
  * that they're disconnected, done retrying, etc..
668
461
  */
669
- SyncEngine.prototype.stop = function () {
670
- return __awaiter(this, void 0, void 0, function () {
671
- return __generator(this, function (_a) {
672
- switch (_a.label) {
673
- case 0:
674
- logger.debug('stopping sync engine');
675
- /**
676
- * Gracefully disconnecting subscribers first just prevents *more* work
677
- * from entering the pipelines.
678
- */
679
- this.unsubscribeConnectivity();
680
- /**
681
- * Stop listening for websocket connection disruption
682
- */
683
- this.stopDisruptionListener && this.stopDisruptionListener();
684
- /**
685
- * aggressively shut down any lingering background processes.
686
- * some of this might be semi-redundant with unsubscribing. however,
687
- * unsubscribing doesn't allow us to wait for settling.
688
- * (Whereas `stop()` does.)
689
- */
690
- return [4 /*yield*/, this.mutationsProcessor.stop()];
691
- case 1:
692
- /**
693
- * aggressively shut down any lingering background processes.
694
- * some of this might be semi-redundant with unsubscribing. however,
695
- * unsubscribing doesn't allow us to wait for settling.
696
- * (Whereas `stop()` does.)
697
- */
698
- _a.sent();
699
- return [4 /*yield*/, this.subscriptionsProcessor.stop()];
700
- case 2:
701
- _a.sent();
702
- return [4 /*yield*/, this.datastoreConnectivity.stop()];
703
- case 3:
704
- _a.sent();
705
- return [4 /*yield*/, this.syncQueriesProcessor.stop()];
706
- case 4:
707
- _a.sent();
708
- return [4 /*yield*/, this.runningProcesses.close()];
709
- case 5:
710
- _a.sent();
711
- return [4 /*yield*/, this.runningProcesses.open()];
712
- case 6:
713
- _a.sent();
714
- logger.debug('sync engine stopped and ready to restart');
715
- return [2 /*return*/];
716
- }
717
- });
718
- });
719
- };
720
- SyncEngine.prototype.setupModels = function (params) {
721
- return __awaiter(this, void 0, void 0, function () {
722
- var fullSyncInterval, ModelMetadataConstructor, models, savedModel, promises, result, _a, _b, modelMetadata, modelName, e_2_1;
723
- var e_2, _c;
724
- var _this = this;
725
- return __generator(this, function (_d) {
726
- switch (_d.label) {
727
- case 0:
728
- fullSyncInterval = params.fullSyncInterval;
729
- ModelMetadataConstructor = this.modelClasses
730
- .ModelMetadata;
731
- models = [];
732
- Object.values(this.schema.namespaces).forEach(function (namespace) {
733
- Object.values(namespace.models)
734
- .filter(function (_a) {
735
- var syncable = _a.syncable;
736
- return syncable;
737
- })
738
- .forEach(function (model) {
739
- models.push([namespace.name, model]);
740
- if (namespace.name === USER) {
741
- var modelConstructor = _this.userModelClasses[model.name];
742
- _this.modelSyncedStatus.set(modelConstructor, false);
743
- }
744
- });
745
- });
746
- promises = models.map(function (_a) {
747
- var _b = __read(_a, 2), namespace = _b[0], model = _b[1];
748
- return __awaiter(_this, void 0, void 0, function () {
749
- var modelMetadata, syncPredicate, lastSyncPredicate, prevSyncPredicate, syncPredicateUpdated_1;
750
- var _c, _d, _e, _f;
751
- return __generator(this, function (_g) {
752
- switch (_g.label) {
753
- case 0: return [4 /*yield*/, this.getModelMetadata(namespace, model.name)];
754
- case 1:
755
- modelMetadata = _g.sent();
756
- syncPredicate = ModelPredicateCreator.getPredicates(this.syncPredicates.get(model), false);
757
- lastSyncPredicate = syncPredicate
758
- ? JSON.stringify(syncPredicate)
759
- : null;
760
- if (!(modelMetadata === undefined)) return [3 /*break*/, 3];
761
- return [4 /*yield*/, this.storage.save(this.modelInstanceCreator(ModelMetadataConstructor, {
762
- model: model.name,
763
- namespace: namespace,
764
- lastSync: null,
765
- fullSyncInterval: fullSyncInterval,
766
- lastFullSync: null,
767
- lastSyncPredicate: lastSyncPredicate,
768
- }), undefined, ownSymbol)];
769
- case 2:
770
- _c = __read.apply(void 0, [_g.sent(), 1]), _d = __read(_c[0], 1), savedModel = _d[0];
771
- return [3 /*break*/, 5];
772
- case 3:
773
- prevSyncPredicate = modelMetadata.lastSyncPredicate
774
- ? modelMetadata.lastSyncPredicate
775
- : null;
776
- syncPredicateUpdated_1 = prevSyncPredicate !== lastSyncPredicate;
777
- return [4 /*yield*/, this.storage.save(ModelMetadataConstructor.copyOf(modelMetadata, function (draft) {
778
- draft.fullSyncInterval = fullSyncInterval;
779
- // perform a base sync if the syncPredicate changed in between calls to DataStore.start
780
- // ensures that the local store contains all the data specified by the syncExpression
781
- if (syncPredicateUpdated_1) {
782
- draft.lastSync = null;
783
- draft.lastFullSync = null;
784
- draft.lastSyncPredicate = lastSyncPredicate;
785
- }
786
- }))];
787
- case 4:
788
- _e = __read.apply(void 0, [_g.sent(), 1]), _f = __read(_e[0], 1), savedModel = _f[0];
789
- _g.label = 5;
790
- case 5: return [2 /*return*/, savedModel];
791
- }
792
- });
793
- });
794
- });
795
- result = {};
796
- _d.label = 1;
797
- case 1:
798
- _d.trys.push([1, 6, 7, 8]);
799
- return [4 /*yield*/, Promise.all(promises)];
800
- case 2:
801
- _a = __values.apply(void 0, [_d.sent()]), _b = _a.next();
802
- _d.label = 3;
803
- case 3:
804
- if (!!_b.done) return [3 /*break*/, 5];
805
- modelMetadata = _b.value;
806
- modelName = modelMetadata.model;
807
- result[modelName] = modelMetadata;
808
- _d.label = 4;
809
- case 4:
810
- _b = _a.next();
811
- return [3 /*break*/, 3];
812
- case 5: return [3 /*break*/, 8];
813
- case 6:
814
- e_2_1 = _d.sent();
815
- e_2 = { error: e_2_1 };
816
- return [3 /*break*/, 8];
817
- case 7:
818
- try {
819
- if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
820
- }
821
- finally { if (e_2) throw e_2.error; }
822
- return [7 /*endfinally*/];
823
- case 8: return [2 /*return*/, result];
462
+ async stop() {
463
+ logger.debug('stopping sync engine');
464
+ /**
465
+ * Gracefully disconnecting subscribers first just prevents *more* work
466
+ * from entering the pipelines.
467
+ */
468
+ this.unsubscribeConnectivity();
469
+ /**
470
+ * Stop listening for websocket connection disruption
471
+ */
472
+ this.stopDisruptionListener && this.stopDisruptionListener();
473
+ /**
474
+ * aggressively shut down any lingering background processes.
475
+ * some of this might be semi-redundant with unsubscribing. however,
476
+ * unsubscribing doesn't allow us to wait for settling.
477
+ * (Whereas `stop()` does.)
478
+ */
479
+ await this.mutationsProcessor.stop();
480
+ await this.subscriptionsProcessor.stop();
481
+ await this.datastoreConnectivity.stop();
482
+ await this.syncQueriesProcessor.stop();
483
+ await this.runningProcesses.close();
484
+ await this.runningProcesses.open();
485
+ logger.debug('sync engine stopped and ready to restart');
486
+ }
487
+ async setupModels(params) {
488
+ const { fullSyncInterval } = params;
489
+ const ModelMetadataConstructor = this.modelClasses
490
+ .ModelMetadata;
491
+ const models = [];
492
+ let savedModel;
493
+ Object.values(this.schema.namespaces).forEach(namespace => {
494
+ Object.values(namespace.models)
495
+ .filter(({ syncable }) => syncable)
496
+ .forEach(model => {
497
+ models.push([namespace.name, model]);
498
+ if (namespace.name === USER) {
499
+ const modelConstructor = this.userModelClasses[model.name];
500
+ this.modelSyncedStatus.set(modelConstructor, false);
824
501
  }
825
502
  });
826
503
  });
827
- };
828
- SyncEngine.prototype.getModelsMetadata = function () {
829
- return __awaiter(this, void 0, void 0, function () {
830
- var ModelMetadata, modelsMetadata;
831
- return __generator(this, function (_a) {
832
- switch (_a.label) {
833
- case 0:
834
- ModelMetadata = this.modelClasses
835
- .ModelMetadata;
836
- return [4 /*yield*/, this.storage.query(ModelMetadata)];
837
- case 1:
838
- modelsMetadata = _a.sent();
839
- return [2 /*return*/, modelsMetadata];
840
- }
841
- });
504
+ const promises = models.map(async ([namespace, model]) => {
505
+ const modelMetadata = await this.getModelMetadata(namespace, model.name);
506
+ const syncPredicate = ModelPredicateCreator.getPredicates(this.syncPredicates.get(model), false);
507
+ const lastSyncPredicate = syncPredicate
508
+ ? JSON.stringify(syncPredicate)
509
+ : null;
510
+ if (modelMetadata === undefined) {
511
+ [[savedModel]] = await this.storage.save(this.modelInstanceCreator(ModelMetadataConstructor, {
512
+ model: model.name,
513
+ namespace,
514
+ lastSync: null,
515
+ fullSyncInterval,
516
+ lastFullSync: null,
517
+ lastSyncPredicate,
518
+ }), undefined, ownSymbol);
519
+ }
520
+ else {
521
+ const prevSyncPredicate = modelMetadata.lastSyncPredicate
522
+ ? modelMetadata.lastSyncPredicate
523
+ : null;
524
+ const syncPredicateUpdated = prevSyncPredicate !== lastSyncPredicate;
525
+ [[savedModel]] = await this.storage.save(ModelMetadataConstructor.copyOf(modelMetadata, draft => {
526
+ draft.fullSyncInterval = fullSyncInterval;
527
+ // perform a base sync if the syncPredicate changed in between calls to DataStore.start
528
+ // ensures that the local store contains all the data specified by the syncExpression
529
+ if (syncPredicateUpdated) {
530
+ draft.lastSync = null;
531
+ draft.lastFullSync = null;
532
+ draft.lastSyncPredicate = lastSyncPredicate;
533
+ }
534
+ }));
535
+ }
536
+ return savedModel;
842
537
  });
843
- };
844
- SyncEngine.prototype.getModelMetadata = function (namespace, model) {
845
- return __awaiter(this, void 0, void 0, function () {
846
- var ModelMetadata, predicate, _a, modelMetadata;
847
- return __generator(this, function (_b) {
848
- switch (_b.label) {
849
- case 0:
850
- ModelMetadata = this.modelClasses
851
- .ModelMetadata;
852
- predicate = ModelPredicateCreator.createFromAST(this.schema.namespaces[SYNC].models[ModelMetadata.name], { and: [{ namespace: { eq: namespace } }, { model: { eq: model } }] });
853
- return [4 /*yield*/, this.storage.query(ModelMetadata, predicate, {
854
- page: 0,
855
- limit: 1,
856
- })];
857
- case 1:
858
- _a = __read.apply(void 0, [_b.sent(), 1]), modelMetadata = _a[0];
859
- return [2 /*return*/, modelMetadata];
860
- }
861
- });
538
+ const result = {};
539
+ for (const modelMetadata of await Promise.all(promises)) {
540
+ const { model: modelName } = modelMetadata;
541
+ result[modelName] = modelMetadata;
542
+ }
543
+ return result;
544
+ }
545
+ async getModelsMetadata() {
546
+ const ModelMetadata = this.modelClasses
547
+ .ModelMetadata;
548
+ const modelsMetadata = await this.storage.query(ModelMetadata);
549
+ return modelsMetadata;
550
+ }
551
+ async getModelMetadata(namespace, model) {
552
+ const ModelMetadata = this.modelClasses
553
+ .ModelMetadata;
554
+ const predicate = ModelPredicateCreator.createFromAST(this.schema.namespaces[SYNC].models[ModelMetadata.name], { and: [{ namespace: { eq: namespace } }, { model: { eq: model } }] });
555
+ const [modelMetadata] = await this.storage.query(ModelMetadata, predicate, {
556
+ page: 0,
557
+ limit: 1,
862
558
  });
863
- };
864
- SyncEngine.prototype.getModelDefinition = function (modelConstructor) {
865
- var namespaceName = this.namespaceResolver(modelConstructor);
866
- var modelDefinition = this.schema.namespaces[namespaceName].models[modelConstructor.name];
559
+ return modelMetadata;
560
+ }
561
+ getModelDefinition(modelConstructor) {
562
+ const namespaceName = this.namespaceResolver(modelConstructor);
563
+ const modelDefinition = this.schema.namespaces[namespaceName].models[modelConstructor.name];
867
564
  return modelDefinition;
868
- };
869
- SyncEngine.getNamespace = function () {
870
- var namespace = {
565
+ }
566
+ static getNamespace() {
567
+ const namespace = {
871
568
  name: SYNC,
872
569
  relationships: {},
873
570
  enums: {
@@ -975,7 +672,7 @@ var SyncEngine = /** @class */ (function () {
975
672
  },
976
673
  };
977
674
  return namespace;
978
- };
675
+ }
979
676
  /**
980
677
  * listen for websocket connection disruption
981
678
  *
@@ -983,44 +680,37 @@ var SyncEngine = /** @class */ (function () {
983
680
  * from AppSync were missed. A sync needs to be triggered to
984
681
  * retrieve the missed data.
985
682
  */
986
- SyncEngine.prototype.startDisruptionListener = function () {
987
- var _this = this;
988
- return Hub.listen('api', function (data) {
683
+ startDisruptionListener() {
684
+ return Hub.listen('api', (data) => {
989
685
  if (data.source === 'PubSub' &&
990
686
  data.payload.event === PUBSUB_CONNECTION_STATE_CHANGE) {
991
- var connectionState = data.payload.data
687
+ const connectionState = data.payload.data
992
688
  .connectionState;
993
689
  switch (connectionState) {
994
690
  // Do not need to listen for ConnectionDisruptedPendingNetwork
995
691
  // Normal network reconnection logic will handle the sync
996
692
  case ConnectionState.ConnectionDisrupted:
997
- _this.connectionDisrupted = true;
693
+ this.connectionDisrupted = true;
998
694
  break;
999
695
  case ConnectionState.Connected:
1000
- if (_this.connectionDisrupted) {
1001
- _this.scheduleSync();
696
+ if (this.connectionDisrupted) {
697
+ this.scheduleSync();
1002
698
  }
1003
- _this.connectionDisrupted = false;
699
+ this.connectionDisrupted = false;
1004
700
  break;
1005
701
  }
1006
702
  }
1007
703
  });
1008
- };
704
+ }
1009
705
  /*
1010
706
  * Schedule a sync to start when syncQueriesObservable enters sleep state
1011
707
  * Start sync immediately if syncQueriesObservable is already in sleep state
1012
708
  */
1013
- SyncEngine.prototype.scheduleSync = function () {
1014
- var _this = this;
709
+ scheduleSync() {
1015
710
  return (this.runningProcesses.isOpen &&
1016
- this.runningProcesses.add(function () {
1017
- return _this.waitForSleepState.then(function () {
1018
- // unsleepSyncQueriesObservable will be set if waitForSleepState has resolved
1019
- _this.unsleepSyncQueriesObservable();
1020
- });
1021
- }));
1022
- };
1023
- return SyncEngine;
1024
- }());
1025
- export { SyncEngine };
1026
- //# sourceMappingURL=index.js.map
711
+ this.runningProcesses.add(() => this.waitForSleepState.then(() => {
712
+ // unsleepSyncQueriesObservable will be set if waitForSleepState has resolved
713
+ this.unsleepSyncQueriesObservable();
714
+ })));
715
+ }
716
+ }