@powersync/common 1.53.0 → 1.53.2
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/dist/bundle.cjs +72 -63
- package/dist/bundle.cjs.map +1 -1
- package/dist/bundle.mjs +72 -63
- package/dist/bundle.mjs.map +1 -1
- package/dist/bundle.node.cjs +72 -63
- package/dist/bundle.node.cjs.map +1 -1
- package/dist/bundle.node.mjs +72 -63
- package/dist/bundle.node.mjs.map +1 -1
- package/dist/index.d.cts +6 -9
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.d.ts +6 -9
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js +28 -43
- package/lib/client/sync/stream/AbstractStreamingSyncImplementation.js.map +1 -1
- package/lib/utils/async.d.ts +13 -7
- package/lib/utils/async.js +38 -24
- package/lib/utils/async.js.map +1 -1
- package/lib/utils/stream_transform.js +6 -1
- package/lib/utils/stream_transform.js.map +1 -1
- package/package.json +1 -1
- package/src/client/sync/stream/AbstractStreamingSyncImplementation.ts +31 -54
- package/src/utils/async.ts +51 -24
- package/src/utils/stream_transform.ts +7 -1
package/dist/bundle.node.cjs
CHANGED
|
@@ -2278,30 +2278,44 @@ function throttleTrailing(func, wait) {
|
|
|
2278
2278
|
}
|
|
2279
2279
|
};
|
|
2280
2280
|
}
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2281
|
+
function asyncNotifier() {
|
|
2282
|
+
let waitingConsumer = null;
|
|
2283
|
+
let hasPendingNotification = false;
|
|
2284
|
+
return {
|
|
2285
|
+
notify() {
|
|
2286
|
+
if (waitingConsumer != null) {
|
|
2287
|
+
waitingConsumer();
|
|
2288
|
+
waitingConsumer = null;
|
|
2289
|
+
}
|
|
2290
|
+
else {
|
|
2291
|
+
hasPendingNotification = true;
|
|
2292
|
+
}
|
|
2293
|
+
},
|
|
2294
|
+
waitForNotification(signal) {
|
|
2295
|
+
return new Promise((resolve) => {
|
|
2296
|
+
if (waitingConsumer != null) {
|
|
2297
|
+
throw new Error('Illegal call to waitForNotification, already has a waiter.');
|
|
2298
|
+
}
|
|
2299
|
+
if (signal.aborted) {
|
|
2300
|
+
resolve();
|
|
2301
|
+
}
|
|
2302
|
+
else if (hasPendingNotification) {
|
|
2303
|
+
resolve();
|
|
2304
|
+
hasPendingNotification = false;
|
|
2305
|
+
}
|
|
2306
|
+
else {
|
|
2307
|
+
function complete() {
|
|
2308
|
+
signal.removeEventListener('abort', onAbort);
|
|
2309
|
+
resolve();
|
|
2310
|
+
}
|
|
2311
|
+
function onAbort() {
|
|
2312
|
+
waitingConsumer = null;
|
|
2313
|
+
resolve();
|
|
2314
|
+
}
|
|
2315
|
+
waitingConsumer = complete;
|
|
2316
|
+
signal.addEventListener('abort', onAbort);
|
|
2317
|
+
}
|
|
2318
|
+
});
|
|
2305
2319
|
}
|
|
2306
2320
|
};
|
|
2307
2321
|
}
|
|
@@ -8132,7 +8146,7 @@ function requireDist () {
|
|
|
8132
8146
|
|
|
8133
8147
|
var distExports = requireDist();
|
|
8134
8148
|
|
|
8135
|
-
var version = "1.53.
|
|
8149
|
+
var version = "1.53.2";
|
|
8136
8150
|
var PACKAGE = {
|
|
8137
8151
|
version: version};
|
|
8138
8152
|
|
|
@@ -8316,6 +8330,7 @@ function injectable(source) {
|
|
|
8316
8330
|
let waiter = undefined; // An active, waiting next() call.
|
|
8317
8331
|
// A pending upstream event that couldn't be dispatched because inject() has been called before it was resolved.
|
|
8318
8332
|
let pendingSourceEvent = null;
|
|
8333
|
+
let sourceFetchInFlight = false;
|
|
8319
8334
|
let pendingInjectedEvents = [];
|
|
8320
8335
|
const consumeWaiter = () => {
|
|
8321
8336
|
const pending = waiter;
|
|
@@ -8324,6 +8339,7 @@ function injectable(source) {
|
|
|
8324
8339
|
};
|
|
8325
8340
|
const fetchFromSource = () => {
|
|
8326
8341
|
const resolveWaiter = (propagate) => {
|
|
8342
|
+
sourceFetchInFlight = false;
|
|
8327
8343
|
const active = consumeWaiter();
|
|
8328
8344
|
if (active) {
|
|
8329
8345
|
propagate(active);
|
|
@@ -8332,6 +8348,7 @@ function injectable(source) {
|
|
|
8332
8348
|
pendingSourceEvent = propagate;
|
|
8333
8349
|
}
|
|
8334
8350
|
};
|
|
8351
|
+
sourceFetchInFlight = true;
|
|
8335
8352
|
const nextFromSource = source.next();
|
|
8336
8353
|
nextFromSource.then((value) => {
|
|
8337
8354
|
sourceIsDone = value.done == true;
|
|
@@ -8358,7 +8375,9 @@ function injectable(source) {
|
|
|
8358
8375
|
}
|
|
8359
8376
|
// Nothing pending? Fetch from source
|
|
8360
8377
|
waiter = { resolve, reject };
|
|
8361
|
-
|
|
8378
|
+
if (!sourceFetchInFlight) {
|
|
8379
|
+
fetchFromSource();
|
|
8380
|
+
}
|
|
8362
8381
|
});
|
|
8363
8382
|
},
|
|
8364
8383
|
inject: (event) => {
|
|
@@ -9035,19 +9054,15 @@ const DEFAULT_STREAM_CONNECTION_OPTIONS = {
|
|
|
9035
9054
|
class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
9036
9055
|
options;
|
|
9037
9056
|
abortController;
|
|
9038
|
-
// In rare cases, mostly for tests, uploads can be triggered without being properly connected.
|
|
9039
|
-
// This allows ensuring that all upload processes can be aborted.
|
|
9040
|
-
uploadAbortController;
|
|
9041
9057
|
crudUpdateListener;
|
|
9042
9058
|
streamingSyncPromise;
|
|
9043
9059
|
logger;
|
|
9044
9060
|
activeStreams;
|
|
9045
9061
|
connectionMayHaveChanged = false;
|
|
9046
|
-
|
|
9062
|
+
crudUploadNotifier = asyncNotifier();
|
|
9047
9063
|
notifyCompletedUploads;
|
|
9048
9064
|
handleActiveStreamsChange;
|
|
9049
9065
|
syncStatus;
|
|
9050
|
-
triggerCrudUpload;
|
|
9051
9066
|
constructor(options) {
|
|
9052
9067
|
super();
|
|
9053
9068
|
this.options = options;
|
|
@@ -9063,16 +9078,9 @@ class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
|
9063
9078
|
}
|
|
9064
9079
|
});
|
|
9065
9080
|
this.abortController = null;
|
|
9066
|
-
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
}
|
|
9070
|
-
this.isUploadingCrud = true;
|
|
9071
|
-
this._uploadAllCrud().finally(() => {
|
|
9072
|
-
this.notifyCompletedUploads?.();
|
|
9073
|
-
this.isUploadingCrud = false;
|
|
9074
|
-
});
|
|
9075
|
-
}, this.options.crudUploadThrottleMs);
|
|
9081
|
+
}
|
|
9082
|
+
triggerCrudUpload() {
|
|
9083
|
+
this.crudUploadNotifier.notify();
|
|
9076
9084
|
}
|
|
9077
9085
|
async waitForReady() { }
|
|
9078
9086
|
waitForStatus(status) {
|
|
@@ -9120,7 +9128,6 @@ class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
|
9120
9128
|
super.dispose();
|
|
9121
9129
|
this.crudUpdateListener?.();
|
|
9122
9130
|
this.crudUpdateListener = undefined;
|
|
9123
|
-
this.uploadAbortController?.abort();
|
|
9124
9131
|
}
|
|
9125
9132
|
async getWriteCheckpoint() {
|
|
9126
9133
|
const clientId = await this.options.adapter.getClientId();
|
|
@@ -9130,7 +9137,17 @@ class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
|
9130
9137
|
this.logger.debug(`Created write checkpoint: ${checkpoint}`);
|
|
9131
9138
|
return checkpoint;
|
|
9132
9139
|
}
|
|
9133
|
-
async
|
|
9140
|
+
async crudUploadLoop(signal) {
|
|
9141
|
+
while (!signal.aborted) {
|
|
9142
|
+
await Promise.all([
|
|
9143
|
+
// Start the initial CRUD upload on connect. Then, keep polling until we're done.
|
|
9144
|
+
this._uploadAllCrud(signal),
|
|
9145
|
+
this.delayRetry(signal, this.options.crudUploadThrottleMs)
|
|
9146
|
+
]);
|
|
9147
|
+
await this.crudUploadNotifier.waitForNotification(signal);
|
|
9148
|
+
}
|
|
9149
|
+
}
|
|
9150
|
+
async _uploadAllCrud(signal) {
|
|
9134
9151
|
return this.obtainLock({
|
|
9135
9152
|
type: exports.LockType.CRUD,
|
|
9136
9153
|
callback: async () => {
|
|
@@ -9138,12 +9155,7 @@ class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
|
9138
9155
|
* Keep track of the first item in the CRUD queue for the last `uploadCrud` iteration.
|
|
9139
9156
|
*/
|
|
9140
9157
|
let checkedCrudItem;
|
|
9141
|
-
|
|
9142
|
-
this.uploadAbortController = controller;
|
|
9143
|
-
this.abortController?.signal.addEventListener('abort', () => {
|
|
9144
|
-
controller.abort();
|
|
9145
|
-
}, { once: true });
|
|
9146
|
-
while (!controller.signal.aborted) {
|
|
9158
|
+
while (!signal.aborted) {
|
|
9147
9159
|
try {
|
|
9148
9160
|
/**
|
|
9149
9161
|
* This is the first item in the FIFO CRUD queue.
|
|
@@ -9173,7 +9185,10 @@ The next upload iteration will be delayed.`);
|
|
|
9173
9185
|
else {
|
|
9174
9186
|
// Uploading is completed
|
|
9175
9187
|
const neededUpdate = await this.options.adapter.updateLocalTarget(() => this.getWriteCheckpoint());
|
|
9176
|
-
if (neededUpdate
|
|
9188
|
+
if (neededUpdate) {
|
|
9189
|
+
this.notifyCompletedUploads?.();
|
|
9190
|
+
}
|
|
9191
|
+
else if (checkedCrudItem != null) {
|
|
9177
9192
|
// Only log this if there was something to upload
|
|
9178
9193
|
this.logger.debug('Upload complete, no write checkpoint needed.');
|
|
9179
9194
|
}
|
|
@@ -9188,7 +9203,7 @@ The next upload iteration will be delayed.`);
|
|
|
9188
9203
|
uploadError: ex
|
|
9189
9204
|
}
|
|
9190
9205
|
});
|
|
9191
|
-
await this.delayRetry(
|
|
9206
|
+
await this.delayRetry(signal);
|
|
9192
9207
|
if (!this.isConnected) {
|
|
9193
9208
|
// Exit the upload loop if the sync stream is no longer connected
|
|
9194
9209
|
break;
|
|
@@ -9203,7 +9218,6 @@ The next upload iteration will be delayed.`);
|
|
|
9203
9218
|
});
|
|
9204
9219
|
}
|
|
9205
9220
|
}
|
|
9206
|
-
this.uploadAbortController = undefined;
|
|
9207
9221
|
}
|
|
9208
9222
|
});
|
|
9209
9223
|
}
|
|
@@ -9213,7 +9227,10 @@ The next upload iteration will be delayed.`);
|
|
|
9213
9227
|
}
|
|
9214
9228
|
const controller = new AbortController();
|
|
9215
9229
|
this.abortController = controller;
|
|
9216
|
-
this.streamingSyncPromise =
|
|
9230
|
+
this.streamingSyncPromise = Promise.all([
|
|
9231
|
+
this.crudUploadLoop(controller.signal).catch((ex) => this.logger.error('Error in crud upload loop', ex)),
|
|
9232
|
+
this.streamingSync(controller.signal, options)
|
|
9233
|
+
]);
|
|
9217
9234
|
// Return a promise that resolves when the connection status is updated to indicate that we're connected.
|
|
9218
9235
|
return new Promise((resolve) => {
|
|
9219
9236
|
const disposer = this.registerListener({
|
|
@@ -9251,14 +9268,7 @@ The next upload iteration will be delayed.`);
|
|
|
9251
9268
|
this.abortController = null;
|
|
9252
9269
|
this.updateSyncStatus({ connected: false, connecting: false });
|
|
9253
9270
|
}
|
|
9254
|
-
/**
|
|
9255
|
-
* @deprecated use [connect instead]
|
|
9256
|
-
*/
|
|
9257
9271
|
async streamingSync(signal, options) {
|
|
9258
|
-
if (!signal) {
|
|
9259
|
-
this.abortController = new AbortController();
|
|
9260
|
-
signal = this.abortController.signal;
|
|
9261
|
-
}
|
|
9262
9272
|
/**
|
|
9263
9273
|
* Listen for CRUD updates and trigger upstream uploads
|
|
9264
9274
|
*/
|
|
@@ -9632,14 +9642,13 @@ The next upload iteration will be delayed.`);
|
|
|
9632
9642
|
// trigger this for all updates
|
|
9633
9643
|
this.iterateListeners((cb) => cb.statusUpdated?.(options));
|
|
9634
9644
|
}
|
|
9635
|
-
async delayRetry(signal) {
|
|
9645
|
+
async delayRetry(signal, delay = this.options.retryDelayMs) {
|
|
9636
9646
|
return new Promise((resolve) => {
|
|
9637
9647
|
if (signal?.aborted) {
|
|
9638
9648
|
// If the signal is already aborted, resolve immediately
|
|
9639
9649
|
resolve();
|
|
9640
9650
|
return;
|
|
9641
9651
|
}
|
|
9642
|
-
const { retryDelayMs } = this.options;
|
|
9643
9652
|
let timeoutId;
|
|
9644
9653
|
const endDelay = () => {
|
|
9645
9654
|
resolve();
|
|
@@ -9650,7 +9659,7 @@ The next upload iteration will be delayed.`);
|
|
|
9650
9659
|
signal?.removeEventListener('abort', endDelay);
|
|
9651
9660
|
};
|
|
9652
9661
|
signal?.addEventListener('abort', endDelay, { once: true });
|
|
9653
|
-
timeoutId = setTimeout(endDelay,
|
|
9662
|
+
timeoutId = setTimeout(endDelay, delay);
|
|
9654
9663
|
});
|
|
9655
9664
|
}
|
|
9656
9665
|
updateSubscriptions(subscriptions) {
|