@powersync/web 1.38.0 → 1.38.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/worker/SharedSyncImplementation.umd.js +72 -63
- package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
- package/dist/worker/WASQLiteDB.umd.js +72 -63
- package/dist/worker/WASQLiteDB.umd.js.map +1 -1
- package/lib/package.json +2 -2
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
|
@@ -4163,30 +4163,44 @@ function throttleTrailing(func, wait) {
|
|
|
4163
4163
|
}
|
|
4164
4164
|
};
|
|
4165
4165
|
}
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
|
|
4188
|
-
|
|
4189
|
-
|
|
4166
|
+
function asyncNotifier() {
|
|
4167
|
+
let waitingConsumer = null;
|
|
4168
|
+
let hasPendingNotification = false;
|
|
4169
|
+
return {
|
|
4170
|
+
notify() {
|
|
4171
|
+
if (waitingConsumer != null) {
|
|
4172
|
+
waitingConsumer();
|
|
4173
|
+
waitingConsumer = null;
|
|
4174
|
+
}
|
|
4175
|
+
else {
|
|
4176
|
+
hasPendingNotification = true;
|
|
4177
|
+
}
|
|
4178
|
+
},
|
|
4179
|
+
waitForNotification(signal) {
|
|
4180
|
+
return new Promise((resolve) => {
|
|
4181
|
+
if (waitingConsumer != null) {
|
|
4182
|
+
throw new Error('Illegal call to waitForNotification, already has a waiter.');
|
|
4183
|
+
}
|
|
4184
|
+
if (signal.aborted) {
|
|
4185
|
+
resolve();
|
|
4186
|
+
}
|
|
4187
|
+
else if (hasPendingNotification) {
|
|
4188
|
+
resolve();
|
|
4189
|
+
hasPendingNotification = false;
|
|
4190
|
+
}
|
|
4191
|
+
else {
|
|
4192
|
+
function complete() {
|
|
4193
|
+
signal.removeEventListener('abort', onAbort);
|
|
4194
|
+
resolve();
|
|
4195
|
+
}
|
|
4196
|
+
function onAbort() {
|
|
4197
|
+
waitingConsumer = null;
|
|
4198
|
+
resolve();
|
|
4199
|
+
}
|
|
4200
|
+
waitingConsumer = complete;
|
|
4201
|
+
signal.addEventListener('abort', onAbort);
|
|
4202
|
+
}
|
|
4203
|
+
});
|
|
4190
4204
|
}
|
|
4191
4205
|
};
|
|
4192
4206
|
}
|
|
@@ -12388,7 +12402,7 @@ function requireDist () {
|
|
|
12388
12402
|
|
|
12389
12403
|
var distExports = requireDist();
|
|
12390
12404
|
|
|
12391
|
-
var version = "1.53.
|
|
12405
|
+
var version = "1.53.2";
|
|
12392
12406
|
var PACKAGE = {
|
|
12393
12407
|
version: version};
|
|
12394
12408
|
|
|
@@ -12572,6 +12586,7 @@ function injectable(source) {
|
|
|
12572
12586
|
let waiter = undefined; // An active, waiting next() call.
|
|
12573
12587
|
// A pending upstream event that couldn't be dispatched because inject() has been called before it was resolved.
|
|
12574
12588
|
let pendingSourceEvent = null;
|
|
12589
|
+
let sourceFetchInFlight = false;
|
|
12575
12590
|
let pendingInjectedEvents = [];
|
|
12576
12591
|
const consumeWaiter = () => {
|
|
12577
12592
|
const pending = waiter;
|
|
@@ -12580,6 +12595,7 @@ function injectable(source) {
|
|
|
12580
12595
|
};
|
|
12581
12596
|
const fetchFromSource = () => {
|
|
12582
12597
|
const resolveWaiter = (propagate) => {
|
|
12598
|
+
sourceFetchInFlight = false;
|
|
12583
12599
|
const active = consumeWaiter();
|
|
12584
12600
|
if (active) {
|
|
12585
12601
|
propagate(active);
|
|
@@ -12588,6 +12604,7 @@ function injectable(source) {
|
|
|
12588
12604
|
pendingSourceEvent = propagate;
|
|
12589
12605
|
}
|
|
12590
12606
|
};
|
|
12607
|
+
sourceFetchInFlight = true;
|
|
12591
12608
|
const nextFromSource = source.next();
|
|
12592
12609
|
nextFromSource.then((value) => {
|
|
12593
12610
|
sourceIsDone = value.done == true;
|
|
@@ -12614,7 +12631,9 @@ function injectable(source) {
|
|
|
12614
12631
|
}
|
|
12615
12632
|
// Nothing pending? Fetch from source
|
|
12616
12633
|
waiter = { resolve, reject };
|
|
12617
|
-
|
|
12634
|
+
if (!sourceFetchInFlight) {
|
|
12635
|
+
fetchFromSource();
|
|
12636
|
+
}
|
|
12618
12637
|
});
|
|
12619
12638
|
},
|
|
12620
12639
|
inject: (event) => {
|
|
@@ -13291,19 +13310,15 @@ const DEFAULT_STREAM_CONNECTION_OPTIONS = {
|
|
|
13291
13310
|
class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
13292
13311
|
options;
|
|
13293
13312
|
abortController;
|
|
13294
|
-
// In rare cases, mostly for tests, uploads can be triggered without being properly connected.
|
|
13295
|
-
// This allows ensuring that all upload processes can be aborted.
|
|
13296
|
-
uploadAbortController;
|
|
13297
13313
|
crudUpdateListener;
|
|
13298
13314
|
streamingSyncPromise;
|
|
13299
13315
|
logger;
|
|
13300
13316
|
activeStreams;
|
|
13301
13317
|
connectionMayHaveChanged = false;
|
|
13302
|
-
|
|
13318
|
+
crudUploadNotifier = asyncNotifier();
|
|
13303
13319
|
notifyCompletedUploads;
|
|
13304
13320
|
handleActiveStreamsChange;
|
|
13305
13321
|
syncStatus;
|
|
13306
|
-
triggerCrudUpload;
|
|
13307
13322
|
constructor(options) {
|
|
13308
13323
|
super();
|
|
13309
13324
|
this.options = options;
|
|
@@ -13319,16 +13334,9 @@ class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
|
13319
13334
|
}
|
|
13320
13335
|
});
|
|
13321
13336
|
this.abortController = null;
|
|
13322
|
-
|
|
13323
|
-
|
|
13324
|
-
|
|
13325
|
-
}
|
|
13326
|
-
this.isUploadingCrud = true;
|
|
13327
|
-
this._uploadAllCrud().finally(() => {
|
|
13328
|
-
this.notifyCompletedUploads?.();
|
|
13329
|
-
this.isUploadingCrud = false;
|
|
13330
|
-
});
|
|
13331
|
-
}, this.options.crudUploadThrottleMs);
|
|
13337
|
+
}
|
|
13338
|
+
triggerCrudUpload() {
|
|
13339
|
+
this.crudUploadNotifier.notify();
|
|
13332
13340
|
}
|
|
13333
13341
|
async waitForReady() { }
|
|
13334
13342
|
waitForStatus(status) {
|
|
@@ -13376,7 +13384,6 @@ class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
|
13376
13384
|
super.dispose();
|
|
13377
13385
|
this.crudUpdateListener?.();
|
|
13378
13386
|
this.crudUpdateListener = undefined;
|
|
13379
|
-
this.uploadAbortController?.abort();
|
|
13380
13387
|
}
|
|
13381
13388
|
async getWriteCheckpoint() {
|
|
13382
13389
|
const clientId = await this.options.adapter.getClientId();
|
|
@@ -13386,7 +13393,17 @@ class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
|
13386
13393
|
this.logger.debug(`Created write checkpoint: ${checkpoint}`);
|
|
13387
13394
|
return checkpoint;
|
|
13388
13395
|
}
|
|
13389
|
-
async
|
|
13396
|
+
async crudUploadLoop(signal) {
|
|
13397
|
+
while (!signal.aborted) {
|
|
13398
|
+
await Promise.all([
|
|
13399
|
+
// Start the initial CRUD upload on connect. Then, keep polling until we're done.
|
|
13400
|
+
this._uploadAllCrud(signal),
|
|
13401
|
+
this.delayRetry(signal, this.options.crudUploadThrottleMs)
|
|
13402
|
+
]);
|
|
13403
|
+
await this.crudUploadNotifier.waitForNotification(signal);
|
|
13404
|
+
}
|
|
13405
|
+
}
|
|
13406
|
+
async _uploadAllCrud(signal) {
|
|
13390
13407
|
return this.obtainLock({
|
|
13391
13408
|
type: LockType.CRUD,
|
|
13392
13409
|
callback: async () => {
|
|
@@ -13394,12 +13411,7 @@ class AbstractStreamingSyncImplementation extends BaseObserver {
|
|
|
13394
13411
|
* Keep track of the first item in the CRUD queue for the last `uploadCrud` iteration.
|
|
13395
13412
|
*/
|
|
13396
13413
|
let checkedCrudItem;
|
|
13397
|
-
|
|
13398
|
-
this.uploadAbortController = controller;
|
|
13399
|
-
this.abortController?.signal.addEventListener('abort', () => {
|
|
13400
|
-
controller.abort();
|
|
13401
|
-
}, { once: true });
|
|
13402
|
-
while (!controller.signal.aborted) {
|
|
13414
|
+
while (!signal.aborted) {
|
|
13403
13415
|
try {
|
|
13404
13416
|
/**
|
|
13405
13417
|
* This is the first item in the FIFO CRUD queue.
|
|
@@ -13429,7 +13441,10 @@ The next upload iteration will be delayed.`);
|
|
|
13429
13441
|
else {
|
|
13430
13442
|
// Uploading is completed
|
|
13431
13443
|
const neededUpdate = await this.options.adapter.updateLocalTarget(() => this.getWriteCheckpoint());
|
|
13432
|
-
if (neededUpdate
|
|
13444
|
+
if (neededUpdate) {
|
|
13445
|
+
this.notifyCompletedUploads?.();
|
|
13446
|
+
}
|
|
13447
|
+
else if (checkedCrudItem != null) {
|
|
13433
13448
|
// Only log this if there was something to upload
|
|
13434
13449
|
this.logger.debug('Upload complete, no write checkpoint needed.');
|
|
13435
13450
|
}
|
|
@@ -13444,7 +13459,7 @@ The next upload iteration will be delayed.`);
|
|
|
13444
13459
|
uploadError: ex
|
|
13445
13460
|
}
|
|
13446
13461
|
});
|
|
13447
|
-
await this.delayRetry(
|
|
13462
|
+
await this.delayRetry(signal);
|
|
13448
13463
|
if (!this.isConnected) {
|
|
13449
13464
|
// Exit the upload loop if the sync stream is no longer connected
|
|
13450
13465
|
break;
|
|
@@ -13459,7 +13474,6 @@ The next upload iteration will be delayed.`);
|
|
|
13459
13474
|
});
|
|
13460
13475
|
}
|
|
13461
13476
|
}
|
|
13462
|
-
this.uploadAbortController = undefined;
|
|
13463
13477
|
}
|
|
13464
13478
|
});
|
|
13465
13479
|
}
|
|
@@ -13469,7 +13483,10 @@ The next upload iteration will be delayed.`);
|
|
|
13469
13483
|
}
|
|
13470
13484
|
const controller = new AbortController();
|
|
13471
13485
|
this.abortController = controller;
|
|
13472
|
-
this.streamingSyncPromise =
|
|
13486
|
+
this.streamingSyncPromise = Promise.all([
|
|
13487
|
+
this.crudUploadLoop(controller.signal).catch((ex) => this.logger.error('Error in crud upload loop', ex)),
|
|
13488
|
+
this.streamingSync(controller.signal, options)
|
|
13489
|
+
]);
|
|
13473
13490
|
// Return a promise that resolves when the connection status is updated to indicate that we're connected.
|
|
13474
13491
|
return new Promise((resolve) => {
|
|
13475
13492
|
const disposer = this.registerListener({
|
|
@@ -13507,14 +13524,7 @@ The next upload iteration will be delayed.`);
|
|
|
13507
13524
|
this.abortController = null;
|
|
13508
13525
|
this.updateSyncStatus({ connected: false, connecting: false });
|
|
13509
13526
|
}
|
|
13510
|
-
/**
|
|
13511
|
-
* @deprecated use [connect instead]
|
|
13512
|
-
*/
|
|
13513
13527
|
async streamingSync(signal, options) {
|
|
13514
|
-
if (!signal) {
|
|
13515
|
-
this.abortController = new AbortController();
|
|
13516
|
-
signal = this.abortController.signal;
|
|
13517
|
-
}
|
|
13518
13528
|
/**
|
|
13519
13529
|
* Listen for CRUD updates and trigger upstream uploads
|
|
13520
13530
|
*/
|
|
@@ -13888,14 +13898,13 @@ The next upload iteration will be delayed.`);
|
|
|
13888
13898
|
// trigger this for all updates
|
|
13889
13899
|
this.iterateListeners((cb) => cb.statusUpdated?.(options));
|
|
13890
13900
|
}
|
|
13891
|
-
async delayRetry(signal) {
|
|
13901
|
+
async delayRetry(signal, delay = this.options.retryDelayMs) {
|
|
13892
13902
|
return new Promise((resolve) => {
|
|
13893
13903
|
if (signal?.aborted) {
|
|
13894
13904
|
// If the signal is already aborted, resolve immediately
|
|
13895
13905
|
resolve();
|
|
13896
13906
|
return;
|
|
13897
13907
|
}
|
|
13898
|
-
const { retryDelayMs } = this.options;
|
|
13899
13908
|
let timeoutId;
|
|
13900
13909
|
const endDelay = () => {
|
|
13901
13910
|
resolve();
|
|
@@ -13906,7 +13915,7 @@ The next upload iteration will be delayed.`);
|
|
|
13906
13915
|
signal?.removeEventListener('abort', endDelay);
|
|
13907
13916
|
};
|
|
13908
13917
|
signal?.addEventListener('abort', endDelay, { once: true });
|
|
13909
|
-
timeoutId = setTimeout(endDelay,
|
|
13918
|
+
timeoutId = setTimeout(endDelay, delay);
|
|
13910
13919
|
});
|
|
13911
13920
|
}
|
|
13912
13921
|
updateSubscriptions(subscriptions) {
|