@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.
- package/README.md +4 -0
- package/lib/authModeStrategies/defaultAuthStrategy.js +3 -2
- package/lib/authModeStrategies/index.js +3 -3
- package/lib/authModeStrategies/multiAuthStrategy.js +38 -53
- package/lib/datastore/datastore.d.ts +4 -5
- package/lib/datastore/datastore.js +929 -1284
- package/lib/index.d.ts +1 -1
- package/lib/index.js +26 -13
- package/lib/predicates/index.js +54 -69
- package/lib/predicates/next.d.ts +2 -2
- package/lib/predicates/next.js +313 -462
- package/lib/predicates/sort.js +24 -28
- package/lib/ssr/index.js +2 -2
- package/lib/storage/adapter/AsyncStorageAdapter.js +120 -342
- package/lib/storage/adapter/AsyncStorageDatabase.js +217 -421
- package/lib/storage/adapter/InMemoryStore.js +28 -51
- package/lib/storage/adapter/InMemoryStore.native.js +5 -3
- package/lib/storage/adapter/IndexedDBAdapter.js +466 -871
- package/lib/storage/adapter/StorageAdapterBase.js +180 -330
- package/lib/storage/adapter/getDefaultAdapter/index.js +8 -10
- package/lib/storage/adapter/getDefaultAdapter/index.native.js +5 -4
- package/lib/storage/adapter/index.js +0 -1
- package/lib/storage/relationship.js +177 -253
- package/lib/storage/storage.d.ts +4 -4
- package/lib/storage/storage.js +255 -433
- package/lib/sync/datastoreConnectivity.d.ts +2 -2
- package/lib/sync/datastoreConnectivity.js +29 -39
- package/lib/sync/datastoreReachability/index.d.ts +1 -3
- package/lib/sync/datastoreReachability/index.js +3 -3
- package/lib/sync/datastoreReachability/index.native.d.ts +1 -3
- package/lib/sync/datastoreReachability/index.native.js +4 -5
- package/lib/sync/index.d.ts +2 -2
- package/lib/sync/index.js +522 -827
- package/lib/sync/merger.js +31 -63
- package/lib/sync/outbox.js +148 -232
- package/lib/sync/processors/errorMaps.d.ts +1 -1
- package/lib/sync/processors/errorMaps.js +30 -47
- package/lib/sync/processors/mutation.d.ts +2 -2
- package/lib/sync/processors/mutation.js +343 -502
- package/lib/sync/processors/subscription.d.ts +5 -2
- package/lib/sync/processors/subscription.js +283 -437
- package/lib/sync/processors/sync.d.ts +2 -2
- package/lib/sync/processors/sync.js +279 -404
- package/lib/sync/utils.d.ts +5 -4
- package/lib/sync/utils.js +267 -320
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/lib/types.d.ts +138 -140
- package/lib/types.js +17 -24
- package/lib/util.d.ts +9 -17
- package/lib/util.js +387 -511
- package/lib-esm/authModeStrategies/defaultAuthStrategy.js +1 -2
- package/lib-esm/authModeStrategies/index.js +0 -1
- package/lib-esm/authModeStrategies/multiAuthStrategy.js +35 -52
- package/lib-esm/datastore/datastore.d.ts +4 -5
- package/lib-esm/datastore/datastore.js +888 -1247
- package/lib-esm/index.d.ts +1 -1
- package/lib-esm/index.js +6 -7
- package/lib-esm/predicates/index.js +53 -70
- package/lib-esm/predicates/next.d.ts +2 -2
- package/lib-esm/predicates/next.js +306 -459
- package/lib-esm/predicates/sort.js +23 -28
- package/lib-esm/ssr/index.js +1 -2
- package/lib-esm/storage/adapter/AsyncStorageAdapter.js +111 -338
- package/lib-esm/storage/adapter/AsyncStorageDatabase.js +212 -416
- package/lib-esm/storage/adapter/InMemoryStore.js +27 -52
- package/lib-esm/storage/adapter/InMemoryStore.native.js +0 -1
- package/lib-esm/storage/adapter/IndexedDBAdapter.js +438 -866
- package/lib-esm/storage/adapter/StorageAdapterBase.js +173 -325
- package/lib-esm/storage/adapter/getDefaultAdapter/index.js +2 -6
- package/lib-esm/storage/adapter/getDefaultAdapter/index.native.js +1 -2
- package/lib-esm/storage/adapter/index.js +1 -1
- package/lib-esm/storage/relationship.js +173 -251
- package/lib-esm/storage/storage.d.ts +4 -4
- package/lib-esm/storage/storage.js +242 -424
- package/lib-esm/sync/datastoreConnectivity.d.ts +2 -2
- package/lib-esm/sync/datastoreConnectivity.js +28 -39
- package/lib-esm/sync/datastoreReachability/index.d.ts +1 -3
- package/lib-esm/sync/datastoreReachability/index.js +2 -3
- package/lib-esm/sync/datastoreReachability/index.native.d.ts +1 -3
- package/lib-esm/sync/datastoreReachability/index.native.js +3 -4
- package/lib-esm/sync/index.d.ts +2 -2
- package/lib-esm/sync/index.js +502 -812
- package/lib-esm/sync/merger.js +28 -61
- package/lib-esm/sync/outbox.js +143 -228
- package/lib-esm/sync/processors/errorMaps.d.ts +1 -1
- package/lib-esm/sync/processors/errorMaps.js +32 -50
- package/lib-esm/sync/processors/mutation.d.ts +2 -2
- package/lib-esm/sync/processors/mutation.js +329 -490
- package/lib-esm/sync/processors/subscription.d.ts +5 -2
- package/lib-esm/sync/processors/subscription.js +266 -421
- package/lib-esm/sync/processors/sync.d.ts +2 -2
- package/lib-esm/sync/processors/sync.js +271 -397
- package/lib-esm/sync/utils.d.ts +5 -4
- package/lib-esm/sync/utils.js +252 -307
- package/lib-esm/tsconfig.tsbuildinfo +1 -0
- package/lib-esm/types.d.ts +138 -140
- package/lib-esm/types.js +16 -25
- package/lib-esm/util.d.ts +9 -17
- package/lib-esm/util.js +335 -497
- package/package.json +31 -26
- package/src/authModeStrategies/multiAuthStrategy.ts +15 -12
- package/src/datastore/datastore.ts +36 -35
- package/src/predicates/sort.ts +3 -1
- package/src/storage/adapter/InMemoryStore.ts +1 -1
- package/src/storage/adapter/IndexedDBAdapter.ts +2 -2
- package/src/storage/adapter/StorageAdapterBase.ts +2 -2
- package/src/storage/adapter/getDefaultAdapter/index.ts +1 -4
- package/src/storage/storage.ts +29 -24
- package/src/sync/datastoreConnectivity.ts +6 -6
- package/src/sync/datastoreReachability/index.native.ts +5 -3
- package/src/sync/datastoreReachability/index.ts +1 -1
- package/src/sync/index.ts +79 -89
- package/src/sync/processors/errorMaps.ts +7 -7
- package/src/sync/processors/mutation.ts +19 -13
- package/src/sync/processors/subscription.ts +221 -295
- package/src/sync/processors/sync.ts +11 -8
- package/src/sync/utils.ts +30 -15
- package/src/types.ts +4 -8
- package/src/util.ts +46 -9
- package/lib/.tsbuildinfo +0 -3
- package/lib/authModeStrategies/defaultAuthStrategy.js.map +0 -1
- package/lib/authModeStrategies/index.js.map +0 -1
- package/lib/authModeStrategies/multiAuthStrategy.js.map +0 -1
- package/lib/datastore/datastore.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/predicates/index.js.map +0 -1
- package/lib/predicates/next.js.map +0 -1
- package/lib/predicates/sort.js.map +0 -1
- package/lib/ssr/index.js.map +0 -1
- package/lib/storage/adapter/AsyncStorageAdapter.js.map +0 -1
- package/lib/storage/adapter/AsyncStorageDatabase.js.map +0 -1
- package/lib/storage/adapter/InMemoryStore.js.map +0 -1
- package/lib/storage/adapter/InMemoryStore.native.js.map +0 -1
- package/lib/storage/adapter/IndexedDBAdapter.js.map +0 -1
- package/lib/storage/adapter/StorageAdapterBase.js.map +0 -1
- package/lib/storage/adapter/getDefaultAdapter/index.js.map +0 -1
- package/lib/storage/adapter/getDefaultAdapter/index.native.js.map +0 -1
- package/lib/storage/adapter/index.js.map +0 -1
- package/lib/storage/relationship.js.map +0 -1
- package/lib/storage/storage.js.map +0 -1
- package/lib/sync/datastoreConnectivity.js.map +0 -1
- package/lib/sync/datastoreReachability/index.js.map +0 -1
- package/lib/sync/datastoreReachability/index.native.js.map +0 -1
- package/lib/sync/index.js.map +0 -1
- package/lib/sync/merger.js.map +0 -1
- package/lib/sync/outbox.js.map +0 -1
- package/lib/sync/processors/errorMaps.js.map +0 -1
- package/lib/sync/processors/mutation.js.map +0 -1
- package/lib/sync/processors/subscription.js.map +0 -1
- package/lib/sync/processors/sync.js.map +0 -1
- package/lib/sync/utils.js.map +0 -1
- package/lib/types.js.map +0 -1
- package/lib/util.js.map +0 -1
- package/lib-esm/.tsbuildinfo +0 -3
- package/lib-esm/authModeStrategies/defaultAuthStrategy.js.map +0 -1
- package/lib-esm/authModeStrategies/index.js.map +0 -1
- package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +0 -1
- package/lib-esm/datastore/datastore.js.map +0 -1
- package/lib-esm/index.js.map +0 -1
- package/lib-esm/predicates/index.js.map +0 -1
- package/lib-esm/predicates/next.js.map +0 -1
- package/lib-esm/predicates/sort.js.map +0 -1
- package/lib-esm/ssr/index.js.map +0 -1
- package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +0 -1
- package/lib-esm/storage/adapter/AsyncStorageDatabase.js.map +0 -1
- package/lib-esm/storage/adapter/InMemoryStore.js.map +0 -1
- package/lib-esm/storage/adapter/InMemoryStore.native.js.map +0 -1
- package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +0 -1
- package/lib-esm/storage/adapter/StorageAdapterBase.js.map +0 -1
- package/lib-esm/storage/adapter/getDefaultAdapter/index.js.map +0 -1
- package/lib-esm/storage/adapter/getDefaultAdapter/index.native.js.map +0 -1
- package/lib-esm/storage/adapter/index.js.map +0 -1
- package/lib-esm/storage/relationship.js.map +0 -1
- package/lib-esm/storage/storage.js.map +0 -1
- package/lib-esm/sync/datastoreConnectivity.js.map +0 -1
- package/lib-esm/sync/datastoreReachability/index.js.map +0 -1
- package/lib-esm/sync/datastoreReachability/index.native.js.map +0 -1
- package/lib-esm/sync/index.js.map +0 -1
- package/lib-esm/sync/merger.js.map +0 -1
- package/lib-esm/sync/outbox.js.map +0 -1
- package/lib-esm/sync/processors/errorMaps.js.map +0 -1
- package/lib-esm/sync/processors/mutation.js.map +0 -1
- package/lib-esm/sync/processors/subscription.js.map +0 -1
- package/lib-esm/sync/processors/sync.js.map +0 -1
- package/lib-esm/sync/utils.js.map +0 -1
- package/lib-esm/types.js.map +0 -1
- package/lib-esm/util.js.map +0 -1
package/lib-esm/sync/index.js
CHANGED
|
@@ -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 {
|
|
5
|
-
import {
|
|
6
|
-
import Observable from '
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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(
|
|
53
|
-
|
|
52
|
+
this.waitForSleepState = new Promise(resolve => {
|
|
53
|
+
this.syncQueriesObservableStartSleeping = resolve;
|
|
54
54
|
});
|
|
55
|
-
|
|
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
|
-
|
|
65
|
-
return
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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:
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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.
|
|
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
|
-
|
|
390
|
+
models: Array.from(paginatingModels).map(({ name }) => name),
|
|
334
391
|
},
|
|
335
392
|
});
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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
|
-
|
|
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
|
-
|
|
653
|
-
|
|
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
|
-
|
|
451
|
+
this.datastoreConnectivity.socketDisconnected();
|
|
659
452
|
}
|
|
660
453
|
};
|
|
661
|
-
}
|
|
662
|
-
|
|
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
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
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
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
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
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
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
|
-
|
|
865
|
-
|
|
866
|
-
|
|
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
|
-
|
|
870
|
-
|
|
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
|
-
|
|
987
|
-
|
|
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
|
-
|
|
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
|
-
|
|
693
|
+
this.connectionDisrupted = true;
|
|
998
694
|
break;
|
|
999
695
|
case ConnectionState.Connected:
|
|
1000
|
-
if (
|
|
1001
|
-
|
|
696
|
+
if (this.connectionDisrupted) {
|
|
697
|
+
this.scheduleSync();
|
|
1002
698
|
}
|
|
1003
|
-
|
|
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
|
-
|
|
1014
|
-
var _this = this;
|
|
709
|
+
scheduleSync() {
|
|
1015
710
|
return (this.runningProcesses.isOpen &&
|
|
1016
|
-
this.runningProcesses.add(
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
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
|
+
}
|