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