@powersync/common 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +6 -0
- package/lib/client/AbstractPowerSyncDatabase.d.ts +367 -0
- package/lib/client/AbstractPowerSyncDatabase.js +645 -0
- package/lib/client/AbstractPowerSyncDatabase.js.map +1 -0
- package/lib/client/AbstractPowerSyncOpenFactory.d.ts +29 -0
- package/lib/client/AbstractPowerSyncOpenFactory.js +25 -0
- package/lib/client/AbstractPowerSyncOpenFactory.js.map +1 -0
- package/lib/client/connection/PowerSyncBackendConnector.d.ts +23 -0
- package/lib/client/connection/PowerSyncBackendConnector.js +2 -0
- package/lib/client/connection/PowerSyncBackendConnector.js.map +1 -0
- package/lib/client/connection/PowerSyncCredentials.d.ts +5 -0
- package/lib/client/connection/PowerSyncCredentials.js +2 -0
- package/lib/client/connection/PowerSyncCredentials.js.map +1 -0
- package/lib/client/sync/bucket/BucketStorageAdapter.d.ts +71 -0
- package/lib/client/sync/bucket/BucketStorageAdapter.js +8 -0
- package/lib/client/sync/bucket/BucketStorageAdapter.js.map +1 -0
- package/lib/client/sync/bucket/CrudBatch.d.ts +31 -0
- package/lib/client/sync/bucket/CrudBatch.js +26 -0
- package/lib/client/sync/bucket/CrudBatch.js.map +1 -0
- package/lib/client/sync/bucket/CrudEntry.d.ts +86 -0
- package/lib/client/sync/bucket/CrudEntry.js +85 -0
- package/lib/client/sync/bucket/CrudEntry.js.map +1 -0
- package/lib/client/sync/bucket/CrudTransaction.d.ts +29 -0
- package/lib/client/sync/bucket/CrudTransaction.js +25 -0
- package/lib/client/sync/bucket/CrudTransaction.js.map +1 -0
- package/lib/client/sync/bucket/OpType.d.ts +16 -0
- package/lib/client/sync/bucket/OpType.js +23 -0
- package/lib/client/sync/bucket/OpType.js.map +1 -0
- package/lib/client/sync/bucket/OplogEntry.d.ts +23 -0
- package/lib/client/sync/bucket/OplogEntry.js +34 -0
- package/lib/client/sync/bucket/OplogEntry.js.map +1 -0
- package/lib/client/sync/bucket/SqliteBucketStorage.d.ts +66 -0
- package/lib/client/sync/bucket/SqliteBucketStorage.js +299 -0
- package/lib/client/sync/bucket/SqliteBucketStorage.js.map +1 -0
- package/lib/client/sync/bucket/SyncDataBatch.d.ts +6 -0
- package/lib/client/sync/bucket/SyncDataBatch.js +12 -0
- package/lib/client/sync/bucket/SyncDataBatch.js.map +1 -0
- package/lib/client/sync/bucket/SyncDataBucket.d.ts +40 -0
- package/lib/client/sync/bucket/SyncDataBucket.js +41 -0
- package/lib/client/sync/bucket/SyncDataBucket.js.map +1 -0
- package/lib/client/sync/stream/AbstractRemote.d.ts +25 -0
- package/lib/client/sync/stream/AbstractRemote.js +43 -0
- package/lib/client/sync/stream/AbstractRemote.js.map +1 -0
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.d.ts +101 -0
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js +478 -0
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js.map +1 -0
- package/lib/client/sync/stream/streaming-sync-types.d.ts +116 -0
- package/lib/client/sync/stream/streaming-sync-types.js +23 -0
- package/lib/client/sync/stream/streaming-sync-types.js.map +1 -0
- package/lib/db/Column.d.ts +19 -0
- package/lib/db/Column.js +26 -0
- package/lib/db/Column.js.map +1 -0
- package/lib/db/DBAdapter.d.ts +95 -0
- package/lib/db/DBAdapter.js +20 -0
- package/lib/db/DBAdapter.js.map +1 -0
- package/lib/db/crud/SyncStatus.d.ts +38 -0
- package/lib/db/crud/SyncStatus.js +58 -0
- package/lib/db/crud/SyncStatus.js.map +1 -0
- package/lib/db/crud/UploadQueueStatus.d.ts +20 -0
- package/lib/db/crud/UploadQueueStatus.js +25 -0
- package/lib/db/crud/UploadQueueStatus.js.map +1 -0
- package/lib/db/schema/Index.d.ts +22 -0
- package/lib/db/schema/Index.js +30 -0
- package/lib/db/schema/Index.js.map +1 -0
- package/lib/db/schema/IndexedColumn.d.ts +19 -0
- package/lib/db/schema/IndexedColumn.js +30 -0
- package/lib/db/schema/IndexedColumn.js.map +1 -0
- package/lib/db/schema/Schema.d.ts +38 -0
- package/lib/db/schema/Schema.js +38 -0
- package/lib/db/schema/Schema.js.map +1 -0
- package/lib/db/schema/Table.d.ts +51 -0
- package/lib/db/schema/Table.js +114 -0
- package/lib/db/schema/Table.js.map +1 -0
- package/lib/db/schema/TableV2.d.ts +30 -0
- package/lib/db/schema/TableV2.js +44 -0
- package/lib/db/schema/TableV2.js.map +1 -0
- package/lib/index.d.ts +30 -0
- package/lib/index.js +31 -0
- package/lib/index.js.map +1 -0
- package/lib/utils/AbortOperation.d.ts +9 -0
- package/lib/utils/AbortOperation.js +19 -0
- package/lib/utils/AbortOperation.js.map +1 -0
- package/lib/utils/BaseObserver.d.ts +20 -0
- package/lib/utils/BaseObserver.js +23 -0
- package/lib/utils/BaseObserver.js.map +1 -0
- package/lib/utils/mutex.d.ts +7 -0
- package/lib/utils/mutex.js +29 -0
- package/lib/utils/mutex.js.map +1 -0
- package/lib/utils/strings.d.ts +3 -0
- package/lib/utils/strings.js +10 -0
- package/lib/utils/strings.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
import throttle from 'lodash/throttle';
|
|
2
|
+
import Logger from 'js-logger';
|
|
3
|
+
import { isStreamingKeepalive, isStreamingSyncCheckpoint, isStreamingSyncCheckpointComplete, isStreamingSyncCheckpointDiff, isStreamingSyncData } from './streaming-sync-types';
|
|
4
|
+
import ndjsonStream from 'can-ndjson-stream';
|
|
5
|
+
import { SyncStatus } from '../../../db/crud/SyncStatus';
|
|
6
|
+
import { SyncDataBucket } from '../bucket/SyncDataBucket';
|
|
7
|
+
import { BaseObserver } from '../../../utils/BaseObserver';
|
|
8
|
+
import { AbortOperation } from '../../../utils/AbortOperation';
|
|
9
|
+
export var LockType;
|
|
10
|
+
(function (LockType) {
|
|
11
|
+
LockType["CRUD"] = "crud";
|
|
12
|
+
LockType["SYNC"] = "sync";
|
|
13
|
+
})(LockType || (LockType = {}));
|
|
14
|
+
export const DEFAULT_CRUD_UPLOAD_THROTTLE_MS = 1000;
|
|
15
|
+
export const DEFAULT_STREAMING_SYNC_OPTIONS = {
|
|
16
|
+
retryDelayMs: 5000,
|
|
17
|
+
logger: Logger.get('PowerSyncStream'),
|
|
18
|
+
crudUploadThrottleMs: DEFAULT_CRUD_UPLOAD_THROTTLE_MS
|
|
19
|
+
};
|
|
20
|
+
export class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
21
|
+
_lastSyncedAt;
|
|
22
|
+
options;
|
|
23
|
+
abortController;
|
|
24
|
+
crudUpdateListener;
|
|
25
|
+
streamingSyncPromise;
|
|
26
|
+
syncStatus;
|
|
27
|
+
triggerCrudUpload;
|
|
28
|
+
constructor(options) {
|
|
29
|
+
super();
|
|
30
|
+
this.options = { ...DEFAULT_STREAMING_SYNC_OPTIONS, ...options };
|
|
31
|
+
this.syncStatus = new SyncStatus({
|
|
32
|
+
connected: false,
|
|
33
|
+
lastSyncedAt: undefined,
|
|
34
|
+
dataFlow: {
|
|
35
|
+
uploading: false,
|
|
36
|
+
downloading: false
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
this.abortController = null;
|
|
40
|
+
this.triggerCrudUpload = throttle(() => {
|
|
41
|
+
if (!this.syncStatus.connected || this.syncStatus.dataFlowStatus.uploading) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
this._uploadAllCrud();
|
|
45
|
+
}, this.options.crudUploadThrottleMs, { trailing: true });
|
|
46
|
+
}
|
|
47
|
+
async waitForReady() { }
|
|
48
|
+
waitForStatus(status) {
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
const l = this.registerListener({
|
|
51
|
+
statusChanged: (updatedStatus) => {
|
|
52
|
+
/**
|
|
53
|
+
* Match only the partial status options provided in the
|
|
54
|
+
* matching status
|
|
55
|
+
*/
|
|
56
|
+
const matchPartialObject = (compA, compB) => {
|
|
57
|
+
return Object.entries(compA).every(([key, value]) => {
|
|
58
|
+
const comparisonBValue = compB[key];
|
|
59
|
+
if (typeof value == 'object' && typeof comparisonBValue == 'object') {
|
|
60
|
+
return matchPartialObject(value, comparisonBValue);
|
|
61
|
+
}
|
|
62
|
+
return value == comparisonBValue;
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
if (matchPartialObject(status, updatedStatus.toJSON())) {
|
|
66
|
+
resolve();
|
|
67
|
+
l?.();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
get lastSyncedAt() {
|
|
74
|
+
const lastSynced = this.syncStatus.lastSyncedAt;
|
|
75
|
+
return lastSynced && new Date(lastSynced);
|
|
76
|
+
}
|
|
77
|
+
get isConnected() {
|
|
78
|
+
return this.syncStatus.connected;
|
|
79
|
+
}
|
|
80
|
+
get logger() {
|
|
81
|
+
return this.options.logger;
|
|
82
|
+
}
|
|
83
|
+
async dispose() {
|
|
84
|
+
this.crudUpdateListener?.();
|
|
85
|
+
this.crudUpdateListener = undefined;
|
|
86
|
+
}
|
|
87
|
+
async hasCompletedSync() {
|
|
88
|
+
return this.options.adapter.hasCompletedSync();
|
|
89
|
+
}
|
|
90
|
+
async getWriteCheckpoint() {
|
|
91
|
+
const response = await this.options.remote.get('/write-checkpoint2.json');
|
|
92
|
+
return response['data']['write_checkpoint'];
|
|
93
|
+
}
|
|
94
|
+
async _uploadAllCrud() {
|
|
95
|
+
return this.obtainLock({
|
|
96
|
+
type: LockType.CRUD,
|
|
97
|
+
callback: async () => {
|
|
98
|
+
this.updateSyncStatus({
|
|
99
|
+
dataFlow: {
|
|
100
|
+
uploading: true
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
while (true) {
|
|
104
|
+
try {
|
|
105
|
+
const done = await this.uploadCrudBatch();
|
|
106
|
+
if (done) {
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (ex) {
|
|
111
|
+
this.updateSyncStatus({
|
|
112
|
+
connected: false,
|
|
113
|
+
dataFlow: {
|
|
114
|
+
uploading: false
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
await this.delayRetry();
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
this.updateSyncStatus({
|
|
122
|
+
dataFlow: {
|
|
123
|
+
uploading: false
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
async uploadCrudBatch() {
|
|
132
|
+
const hasCrud = await this.options.adapter.hasCrud();
|
|
133
|
+
if (hasCrud) {
|
|
134
|
+
await this.options.uploadCrud();
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
await this.options.adapter.updateLocalTarget(() => this.getWriteCheckpoint());
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async connect() {
|
|
143
|
+
if (this.abortController) {
|
|
144
|
+
await this.disconnect();
|
|
145
|
+
}
|
|
146
|
+
this.abortController = new AbortController();
|
|
147
|
+
this.streamingSyncPromise = this.streamingSync(this.abortController.signal);
|
|
148
|
+
// Return a promise that resolves when the connection status is updated
|
|
149
|
+
return new Promise((resolve) => {
|
|
150
|
+
const l = this.registerListener({
|
|
151
|
+
statusUpdated: (update) => {
|
|
152
|
+
// This is triggered as soon as a connection is read from
|
|
153
|
+
if (typeof update.connected == 'undefined') {
|
|
154
|
+
// only concern with connection updates
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (update.connected == false) {
|
|
158
|
+
/**
|
|
159
|
+
* This function does not reject if initial connect attempt failed
|
|
160
|
+
*/
|
|
161
|
+
this.logger.warn('Initial connect attempt did not successfully connect to server');
|
|
162
|
+
}
|
|
163
|
+
resolve();
|
|
164
|
+
l();
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
async disconnect() {
|
|
170
|
+
if (!this.abortController) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
// This might be called multiple times
|
|
174
|
+
if (!this.abortController.signal.aborted) {
|
|
175
|
+
this.abortController.abort(new AbortOperation('Disconnect has been requested'));
|
|
176
|
+
}
|
|
177
|
+
// Await any pending operations before completing the disconnect operation
|
|
178
|
+
try {
|
|
179
|
+
await this.streamingSyncPromise;
|
|
180
|
+
}
|
|
181
|
+
catch (ex) {
|
|
182
|
+
// The operation might have failed, all we care about is if it has completed
|
|
183
|
+
this.logger.warn(ex);
|
|
184
|
+
}
|
|
185
|
+
this.streamingSyncPromise = undefined;
|
|
186
|
+
this.abortController = null;
|
|
187
|
+
this.updateSyncStatus({ connected: false });
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* @deprecated use [connect instead]
|
|
191
|
+
*/
|
|
192
|
+
async streamingSync(signal) {
|
|
193
|
+
if (!signal) {
|
|
194
|
+
this.abortController = new AbortController();
|
|
195
|
+
signal = this.abortController.signal;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Listen for CRUD updates and trigger upstream uploads
|
|
199
|
+
*/
|
|
200
|
+
this.crudUpdateListener = this.options.adapter.registerListener({
|
|
201
|
+
crudUpdate: () => this.triggerCrudUpload()
|
|
202
|
+
});
|
|
203
|
+
/**
|
|
204
|
+
* Create a new abort controller which aborts items downstream.
|
|
205
|
+
* This is needed to close any previous connections on exception.
|
|
206
|
+
*/
|
|
207
|
+
let nestedAbortController = new AbortController();
|
|
208
|
+
signal.addEventListener('abort', () => {
|
|
209
|
+
/**
|
|
210
|
+
* A request for disconnect was received upstream. Relay the request
|
|
211
|
+
* to the nested abort controller.
|
|
212
|
+
*/
|
|
213
|
+
nestedAbortController.abort(signal?.reason ?? new AbortOperation('Received command to disconnect from upstream'));
|
|
214
|
+
this.crudUpdateListener?.();
|
|
215
|
+
this.crudUpdateListener = undefined;
|
|
216
|
+
this.updateSyncStatus({
|
|
217
|
+
connected: false,
|
|
218
|
+
dataFlow: {
|
|
219
|
+
downloading: false
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
/**
|
|
224
|
+
* This loops runs until [retry] is false or the abort signal is set to aborted.
|
|
225
|
+
* Aborting the nestedAbortController will:
|
|
226
|
+
* - Abort any pending fetch requests
|
|
227
|
+
* - Close any sync stream ReadableStreams (which will also close any established network requests)
|
|
228
|
+
*/
|
|
229
|
+
while (true) {
|
|
230
|
+
try {
|
|
231
|
+
if (signal?.aborted) {
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
const { retry } = await this.streamingSyncIteration(nestedAbortController.signal);
|
|
235
|
+
if (!retry) {
|
|
236
|
+
/**
|
|
237
|
+
* A sync error ocurred that we cannot recover from here.
|
|
238
|
+
* This loop must terminate.
|
|
239
|
+
* The nestedAbortController will close any open network requests and streams below.
|
|
240
|
+
*/
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
// Continue immediately
|
|
244
|
+
}
|
|
245
|
+
catch (ex) {
|
|
246
|
+
/**
|
|
247
|
+
* Either:
|
|
248
|
+
* - A network request failed with a failed connection or not OKAY response code.
|
|
249
|
+
* - There was a sync processing error.
|
|
250
|
+
* This loop will retry.
|
|
251
|
+
* The nested abort controller will cleanup any open network requests and streams.
|
|
252
|
+
* The WebRemote should only abort pending fetch requests or close active Readable streams.
|
|
253
|
+
*/
|
|
254
|
+
if (ex instanceof AbortOperation) {
|
|
255
|
+
this.logger.warn(ex);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
this.logger.error(ex);
|
|
259
|
+
}
|
|
260
|
+
await this.delayRetry();
|
|
261
|
+
}
|
|
262
|
+
finally {
|
|
263
|
+
if (!signal.aborted) {
|
|
264
|
+
nestedAbortController.abort(new AbortOperation('Closing sync stream network requests before retry.'));
|
|
265
|
+
nestedAbortController = new AbortController();
|
|
266
|
+
}
|
|
267
|
+
this.updateSyncStatus({
|
|
268
|
+
connected: false
|
|
269
|
+
});
|
|
270
|
+
// On error, wait a little before retrying
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// Mark as disconnected if here
|
|
274
|
+
this.updateSyncStatus({ connected: false });
|
|
275
|
+
}
|
|
276
|
+
async streamingSyncIteration(signal, progress) {
|
|
277
|
+
return await this.obtainLock({
|
|
278
|
+
type: LockType.SYNC,
|
|
279
|
+
signal,
|
|
280
|
+
callback: async () => {
|
|
281
|
+
this.logger.debug('Streaming sync iteration started');
|
|
282
|
+
this.options.adapter.startSession();
|
|
283
|
+
const bucketEntries = await this.options.adapter.getBucketStates();
|
|
284
|
+
const initialBuckets = new Map();
|
|
285
|
+
bucketEntries.forEach((entry) => {
|
|
286
|
+
initialBuckets.set(entry.bucket, entry.op_id);
|
|
287
|
+
});
|
|
288
|
+
const req = Array.from(initialBuckets.entries()).map(([bucket, after]) => ({
|
|
289
|
+
name: bucket,
|
|
290
|
+
after: after
|
|
291
|
+
}));
|
|
292
|
+
// These are compared by reference
|
|
293
|
+
let targetCheckpoint = null;
|
|
294
|
+
let validatedCheckpoint = null;
|
|
295
|
+
let appliedCheckpoint = null;
|
|
296
|
+
let bucketSet = new Set(initialBuckets.keys());
|
|
297
|
+
for await (const line of this.streamingSyncRequest({
|
|
298
|
+
buckets: req,
|
|
299
|
+
include_checksum: true,
|
|
300
|
+
raw_data: true
|
|
301
|
+
}, signal)) {
|
|
302
|
+
if (isStreamingSyncCheckpoint(line)) {
|
|
303
|
+
targetCheckpoint = line.checkpoint;
|
|
304
|
+
const bucketsToDelete = new Set(bucketSet);
|
|
305
|
+
const newBuckets = new Set();
|
|
306
|
+
for (const checksum of line.checkpoint.buckets) {
|
|
307
|
+
newBuckets.add(checksum.bucket);
|
|
308
|
+
bucketsToDelete.delete(checksum.bucket);
|
|
309
|
+
}
|
|
310
|
+
if (bucketsToDelete.size > 0) {
|
|
311
|
+
this.logger.debug('Removing buckets', [...bucketsToDelete]);
|
|
312
|
+
}
|
|
313
|
+
bucketSet = newBuckets;
|
|
314
|
+
await this.options.adapter.removeBuckets([...bucketsToDelete]);
|
|
315
|
+
await this.options.adapter.setTargetCheckpoint(targetCheckpoint);
|
|
316
|
+
}
|
|
317
|
+
else if (isStreamingSyncCheckpointComplete(line)) {
|
|
318
|
+
this.logger.debug('Checkpoint complete', targetCheckpoint);
|
|
319
|
+
const result = await this.options.adapter.syncLocalDatabase(targetCheckpoint);
|
|
320
|
+
if (!result.checkpointValid) {
|
|
321
|
+
// This means checksums failed. Start again with a new checkpoint.
|
|
322
|
+
// TODO: better back-off
|
|
323
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
324
|
+
return { retry: true };
|
|
325
|
+
}
|
|
326
|
+
else if (!result.ready) {
|
|
327
|
+
// Checksums valid, but need more data for a consistent checkpoint.
|
|
328
|
+
// Continue waiting.
|
|
329
|
+
// landing here the whole time
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
appliedCheckpoint = targetCheckpoint;
|
|
333
|
+
this.logger.debug('validated checkpoint', appliedCheckpoint);
|
|
334
|
+
this.updateSyncStatus({
|
|
335
|
+
connected: true,
|
|
336
|
+
lastSyncedAt: new Date(),
|
|
337
|
+
dataFlow: {
|
|
338
|
+
downloading: false
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
validatedCheckpoint = targetCheckpoint;
|
|
343
|
+
}
|
|
344
|
+
else if (isStreamingSyncCheckpointDiff(line)) {
|
|
345
|
+
// TODO: It may be faster to just keep track of the diff, instead of the entire checkpoint
|
|
346
|
+
if (targetCheckpoint == null) {
|
|
347
|
+
throw new Error('Checkpoint diff without previous checkpoint');
|
|
348
|
+
}
|
|
349
|
+
const diff = line.checkpoint_diff;
|
|
350
|
+
const newBuckets = new Map();
|
|
351
|
+
for (const checksum of targetCheckpoint.buckets) {
|
|
352
|
+
newBuckets.set(checksum.bucket, checksum);
|
|
353
|
+
}
|
|
354
|
+
for (const checksum of diff.updated_buckets) {
|
|
355
|
+
newBuckets.set(checksum.bucket, checksum);
|
|
356
|
+
}
|
|
357
|
+
for (const bucket of diff.removed_buckets) {
|
|
358
|
+
newBuckets.delete(bucket);
|
|
359
|
+
}
|
|
360
|
+
const newCheckpoint = {
|
|
361
|
+
last_op_id: diff.last_op_id,
|
|
362
|
+
buckets: [...newBuckets.values()],
|
|
363
|
+
write_checkpoint: diff.write_checkpoint
|
|
364
|
+
};
|
|
365
|
+
targetCheckpoint = newCheckpoint;
|
|
366
|
+
bucketSet = new Set(newBuckets.keys());
|
|
367
|
+
const bucketsToDelete = diff.removed_buckets;
|
|
368
|
+
if (bucketsToDelete.length > 0) {
|
|
369
|
+
this.logger.debug('Remove buckets', bucketsToDelete);
|
|
370
|
+
}
|
|
371
|
+
await this.options.adapter.removeBuckets(bucketsToDelete);
|
|
372
|
+
await this.options.adapter.setTargetCheckpoint(targetCheckpoint);
|
|
373
|
+
}
|
|
374
|
+
else if (isStreamingSyncData(line)) {
|
|
375
|
+
const { data } = line;
|
|
376
|
+
this.updateSyncStatus({
|
|
377
|
+
dataFlow: {
|
|
378
|
+
downloading: true
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
await this.options.adapter.saveSyncData({ buckets: [SyncDataBucket.fromRow(data)] });
|
|
382
|
+
}
|
|
383
|
+
else if (isStreamingKeepalive(line)) {
|
|
384
|
+
const remaining_seconds = line.token_expires_in;
|
|
385
|
+
if (remaining_seconds == 0) {
|
|
386
|
+
// Connection would be closed automatically right after this
|
|
387
|
+
this.logger.debug('Token expiring; reconnect');
|
|
388
|
+
return { retry: true };
|
|
389
|
+
}
|
|
390
|
+
this.triggerCrudUpload();
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
this.logger.debug('Sync complete');
|
|
394
|
+
if (targetCheckpoint === appliedCheckpoint) {
|
|
395
|
+
this.updateSyncStatus({
|
|
396
|
+
connected: true,
|
|
397
|
+
lastSyncedAt: new Date()
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
else if (validatedCheckpoint === targetCheckpoint) {
|
|
401
|
+
const result = await this.options.adapter.syncLocalDatabase(targetCheckpoint);
|
|
402
|
+
if (!result.checkpointValid) {
|
|
403
|
+
// This means checksums failed. Start again with a new checkpoint.
|
|
404
|
+
// TODO: better back-off
|
|
405
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
406
|
+
return { retry: false };
|
|
407
|
+
}
|
|
408
|
+
else if (!result.ready) {
|
|
409
|
+
// Checksums valid, but need more data for a consistent checkpoint.
|
|
410
|
+
// Continue waiting.
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
appliedCheckpoint = targetCheckpoint;
|
|
414
|
+
this.updateSyncStatus({
|
|
415
|
+
connected: true,
|
|
416
|
+
lastSyncedAt: new Date(),
|
|
417
|
+
dataFlow: {
|
|
418
|
+
downloading: false
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
progress?.();
|
|
425
|
+
}
|
|
426
|
+
this.logger.debug('Stream input empty');
|
|
427
|
+
// Connection closed. Likely due to auth issue.
|
|
428
|
+
return { retry: true };
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
async *streamingSyncRequest(req, signal) {
|
|
433
|
+
const body = await this.options.remote.postStreaming('/sync/stream', req, {}, signal);
|
|
434
|
+
// A connection is active
|
|
435
|
+
// There is a connection now
|
|
436
|
+
Promise.resolve().then(() => this.triggerCrudUpload());
|
|
437
|
+
this.updateSyncStatus({
|
|
438
|
+
connected: true
|
|
439
|
+
});
|
|
440
|
+
const stream = ndjsonStream(body);
|
|
441
|
+
const reader = stream.getReader();
|
|
442
|
+
try {
|
|
443
|
+
while (true) {
|
|
444
|
+
// Read from the stream
|
|
445
|
+
const { done, value } = await reader.read();
|
|
446
|
+
// Exit if we're done
|
|
447
|
+
if (done)
|
|
448
|
+
return;
|
|
449
|
+
// Else yield the chunk
|
|
450
|
+
yield value;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
finally {
|
|
454
|
+
reader.releaseLock();
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
updateSyncStatus(options) {
|
|
458
|
+
const updatedStatus = new SyncStatus({
|
|
459
|
+
connected: options.connected ?? this.syncStatus.connected,
|
|
460
|
+
lastSyncedAt: options.lastSyncedAt ?? this.syncStatus.lastSyncedAt,
|
|
461
|
+
dataFlow: {
|
|
462
|
+
...this.syncStatus.dataFlowStatus,
|
|
463
|
+
...options.dataFlow
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
if (!this.syncStatus.isEqual(updatedStatus)) {
|
|
467
|
+
this.syncStatus = updatedStatus;
|
|
468
|
+
// Only trigger this is there was a change
|
|
469
|
+
this.iterateListeners((cb) => cb.statusChanged?.(updatedStatus));
|
|
470
|
+
}
|
|
471
|
+
// trigger this for all updates
|
|
472
|
+
this.iterateListeners((cb) => cb.statusUpdated?.(options));
|
|
473
|
+
}
|
|
474
|
+
async delayRetry() {
|
|
475
|
+
return new Promise((resolve) => setTimeout(resolve, this.options.retryDelayMs));
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
//# sourceMappingURL=AbstractStreamingSyncImplementation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AbstractStreamingSyncImplementation.js","sourceRoot":"","sources":["../../../../src/client/sync/stream/AbstractStreamingSyncImplementation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { BucketChecksum, Checkpoint } from '../bucket/BucketStorageAdapter';
|
|
2
|
+
import { CrudEntry, OpId } from '../bucket/CrudEntry';
|
|
3
|
+
import { SyncDataBucketJSON } from '../bucket/SyncDataBucket';
|
|
4
|
+
/**
|
|
5
|
+
* For sync2.json
|
|
6
|
+
*/
|
|
7
|
+
export interface ContinueCheckpointRequest {
|
|
8
|
+
/**
|
|
9
|
+
* Existing bucket states. Only these buckets are synchronized.
|
|
10
|
+
*/
|
|
11
|
+
buckets: BucketRequest[];
|
|
12
|
+
checkpoint_token: string;
|
|
13
|
+
limit?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface SyncNewCheckpointRequest {
|
|
16
|
+
/**
|
|
17
|
+
* Existing bucket states. Used if include_data is specified.
|
|
18
|
+
*/
|
|
19
|
+
buckets?: BucketRequest[];
|
|
20
|
+
request_checkpoint: {
|
|
21
|
+
/**
|
|
22
|
+
* Whether or not to include an initial data request.
|
|
23
|
+
*/
|
|
24
|
+
include_data: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Whether or not to compute a checksum.
|
|
27
|
+
*/
|
|
28
|
+
include_checksum: boolean;
|
|
29
|
+
};
|
|
30
|
+
limit?: number;
|
|
31
|
+
}
|
|
32
|
+
export type SyncRequest = ContinueCheckpointRequest | SyncNewCheckpointRequest;
|
|
33
|
+
export interface SyncResponse {
|
|
34
|
+
/**
|
|
35
|
+
* Data for the buckets returned. May not have an an entry for each bucket in the request.
|
|
36
|
+
*/
|
|
37
|
+
data?: SyncDataBucketJSON[];
|
|
38
|
+
/**
|
|
39
|
+
* True if the response limit has been reached, and another request must be made.
|
|
40
|
+
*/
|
|
41
|
+
has_more: boolean;
|
|
42
|
+
checkpoint_token?: string;
|
|
43
|
+
checkpoint?: Checkpoint;
|
|
44
|
+
}
|
|
45
|
+
export interface StreamingSyncRequest {
|
|
46
|
+
/**
|
|
47
|
+
* Existing bucket states.
|
|
48
|
+
*/
|
|
49
|
+
buckets?: BucketRequest[];
|
|
50
|
+
/**
|
|
51
|
+
* If specified, limit the response to only include these buckets.
|
|
52
|
+
*/
|
|
53
|
+
only?: string[];
|
|
54
|
+
/**
|
|
55
|
+
* Whether or not to compute a checksum for each checkpoint
|
|
56
|
+
*/
|
|
57
|
+
include_checksum: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Changes the response to stringified data in each OplogEntry
|
|
60
|
+
*/
|
|
61
|
+
raw_data: boolean;
|
|
62
|
+
}
|
|
63
|
+
export interface StreamingSyncCheckpoint {
|
|
64
|
+
checkpoint: Checkpoint;
|
|
65
|
+
}
|
|
66
|
+
export interface StreamingSyncCheckpointDiff {
|
|
67
|
+
checkpoint_diff: {
|
|
68
|
+
last_op_id: OpId;
|
|
69
|
+
updated_buckets: BucketChecksum[];
|
|
70
|
+
removed_buckets: string[];
|
|
71
|
+
write_checkpoint: string;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export interface StreamingSyncDataJSON {
|
|
75
|
+
data: SyncDataBucketJSON;
|
|
76
|
+
}
|
|
77
|
+
export interface StreamingSyncCheckpointComplete {
|
|
78
|
+
checkpoint_complete: {
|
|
79
|
+
last_op_id: OpId;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
export interface StreamingSyncKeepalive {
|
|
83
|
+
/** If specified, token expires in this many seconds. */
|
|
84
|
+
token_expires_in: number;
|
|
85
|
+
}
|
|
86
|
+
export type StreamingSyncLine = StreamingSyncDataJSON | StreamingSyncCheckpoint | StreamingSyncCheckpointDiff | StreamingSyncCheckpointComplete | StreamingSyncKeepalive;
|
|
87
|
+
export interface BucketRequest {
|
|
88
|
+
name: string;
|
|
89
|
+
/**
|
|
90
|
+
* Base-10 number. Sync all data from this bucket with op_id > after.
|
|
91
|
+
*/
|
|
92
|
+
after: OpId;
|
|
93
|
+
}
|
|
94
|
+
export declare function isStreamingSyncData(line: StreamingSyncLine): line is StreamingSyncDataJSON;
|
|
95
|
+
export declare function isStreamingKeepalive(line: StreamingSyncLine): line is StreamingSyncKeepalive;
|
|
96
|
+
export declare function isStreamingSyncCheckpoint(line: StreamingSyncLine): line is StreamingSyncCheckpoint;
|
|
97
|
+
export declare function isStreamingSyncCheckpointComplete(line: StreamingSyncLine): line is StreamingSyncCheckpointComplete;
|
|
98
|
+
export declare function isStreamingSyncCheckpointDiff(line: StreamingSyncLine): line is StreamingSyncCheckpointDiff;
|
|
99
|
+
export declare function isContinueCheckpointRequest(request: SyncRequest): request is ContinueCheckpointRequest;
|
|
100
|
+
export declare function isSyncNewCheckpointRequest(request: SyncRequest): request is SyncNewCheckpointRequest;
|
|
101
|
+
/**
|
|
102
|
+
* For crud.json
|
|
103
|
+
*/
|
|
104
|
+
export interface CrudRequest {
|
|
105
|
+
data: CrudEntry[];
|
|
106
|
+
}
|
|
107
|
+
export interface CrudResponse {
|
|
108
|
+
/**
|
|
109
|
+
* A sync response with a checkpoint >= this checkpoint would contain all the changes in this request.
|
|
110
|
+
*
|
|
111
|
+
* Any earlier checkpoint may or may not contain these changes.
|
|
112
|
+
*
|
|
113
|
+
* May be empty when the request contains no ops.
|
|
114
|
+
*/
|
|
115
|
+
checkpoint?: OpId;
|
|
116
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function isStreamingSyncData(line) {
|
|
2
|
+
return line.data != null;
|
|
3
|
+
}
|
|
4
|
+
export function isStreamingKeepalive(line) {
|
|
5
|
+
return line.token_expires_in != null;
|
|
6
|
+
}
|
|
7
|
+
export function isStreamingSyncCheckpoint(line) {
|
|
8
|
+
return line.checkpoint != null;
|
|
9
|
+
}
|
|
10
|
+
export function isStreamingSyncCheckpointComplete(line) {
|
|
11
|
+
return line.checkpoint_complete != null;
|
|
12
|
+
}
|
|
13
|
+
export function isStreamingSyncCheckpointDiff(line) {
|
|
14
|
+
return line.checkpoint_diff != null;
|
|
15
|
+
}
|
|
16
|
+
export function isContinueCheckpointRequest(request) {
|
|
17
|
+
return (Array.isArray(request.buckets) &&
|
|
18
|
+
typeof request.checkpoint_token == 'string');
|
|
19
|
+
}
|
|
20
|
+
export function isSyncNewCheckpointRequest(request) {
|
|
21
|
+
return typeof request.request_checkpoint == 'object';
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=streaming-sync-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming-sync-types.js","sourceRoot":"","sources":["../../../../src/client/sync/stream/streaming-sync-types.ts"],"names":[],"mappings":"AA2HA,MAAM,UAAU,mBAAmB,CAAC,IAAuB;IACzD,OAAQ,IAA8B,CAAC,IAAI,IAAI,IAAI,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAuB;IAC1D,OAAQ,IAA+B,CAAC,gBAAgB,IAAI,IAAI,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,IAAuB;IAC/D,OAAQ,IAAgC,CAAC,UAAU,IAAI,IAAI,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,iCAAiC,CAAC,IAAuB;IACvE,OAAQ,IAAwC,CAAC,mBAAmB,IAAI,IAAI,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,IAAuB;IACnE,OAAQ,IAAoC,CAAC,eAAe,IAAI,IAAI,CAAC;AACvE,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,OAAoB;IAC9D,OAAO,CACL,KAAK,CAAC,OAAO,CAAE,OAAqC,CAAC,OAAO,CAAC;QAC7D,OAAQ,OAAqC,CAAC,gBAAgB,IAAI,QAAQ,CAC3E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,OAAoB;IAC7D,OAAO,OAAQ,OAAoC,CAAC,kBAAkB,IAAI,QAAQ,CAAC;AACrF,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare enum ColumnType {
|
|
2
|
+
TEXT = "TEXT",
|
|
3
|
+
INTEGER = "INTEGER",
|
|
4
|
+
REAL = "REAL"
|
|
5
|
+
}
|
|
6
|
+
export interface ColumnOptions {
|
|
7
|
+
name: string;
|
|
8
|
+
type?: ColumnType;
|
|
9
|
+
}
|
|
10
|
+
export declare class Column {
|
|
11
|
+
protected options: ColumnOptions;
|
|
12
|
+
constructor(options: ColumnOptions);
|
|
13
|
+
get name(): string;
|
|
14
|
+
get type(): ColumnType | undefined;
|
|
15
|
+
toJSON(): {
|
|
16
|
+
name: string;
|
|
17
|
+
type: ColumnType | undefined;
|
|
18
|
+
};
|
|
19
|
+
}
|