@abraca/dabra 1.0.17 → 1.0.19

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.
@@ -2714,8 +2714,10 @@ var OfflineStore = class {
2714
2714
  }
2715
2715
  destroy() {
2716
2716
  this._destroyed = true;
2717
+ const db = this.db;
2717
2718
  this.db = null;
2718
2719
  this.dbPromise = null;
2720
+ if (db) Promise.resolve().then(() => db.close());
2719
2721
  }
2720
2722
  };
2721
2723
 
@@ -3070,8 +3072,11 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
3070
3072
  }
3071
3073
  destroy() {
3072
3074
  this.document.off("subdocs", this.boundHandleYSubdocsChange);
3075
+ const childIds = [...this.childProviders.keys()];
3073
3076
  for (const provider of this.childProviders.values()) provider.destroy();
3074
3077
  this.childProviders.clear();
3078
+ const wsProviderMap = this.configuration.websocketProvider?.configuration?.providerMap;
3079
+ if (wsProviderMap) for (const childId of childIds) wsProviderMap.delete(childId);
3075
3080
  this.offlineStore?.destroy();
3076
3081
  this.offlineStore = null;
3077
3082
  super.destroy();
@@ -8367,7 +8372,9 @@ var BackgroundSyncManager = class extends EventEmitter {
8367
8372
  this.opts = {
8368
8373
  concurrency: opts?.concurrency ?? 2,
8369
8374
  syncTimeout: opts?.syncTimeout ?? 15e3,
8370
- prefetchFiles: opts?.prefetchFiles ?? true
8375
+ prefetchFiles: opts?.prefetchFiles ?? true,
8376
+ throttleMs: opts?.throttleMs ?? 50,
8377
+ maxRetries: opts?.maxRetries ?? 2
8371
8378
  };
8372
8379
  let serverOrigin = "default";
8373
8380
  try {
@@ -8401,7 +8408,38 @@ var BackgroundSyncManager = class extends EventEmitter {
8401
8408
  for (const [docId, v] of entries) updatedAtMap.set(docId, v?.updatedAt ?? v?.createdAt ?? 0);
8402
8409
  this._prefetchCovers(entries).catch(() => null);
8403
8410
  const queue = this._buildQueue(entries);
8404
- await Promise.all(queue.map((docId) => this._syncWithSemaphore(docId, updatedAtMap.get(docId) ?? 0)));
8411
+ const failed = [];
8412
+ let idx = 0;
8413
+ const next = async () => {
8414
+ while (idx < queue.length) {
8415
+ if (this._destroyed) return;
8416
+ const docId = queue[idx++];
8417
+ const updatedAt = updatedAtMap.get(docId) ?? 0;
8418
+ if (!await this._syncWithSemaphore(docId, updatedAt)) failed.push(docId);
8419
+ if (this.opts.throttleMs > 0 && idx < queue.length) await new Promise((r) => setTimeout(r, this.opts.throttleMs));
8420
+ }
8421
+ };
8422
+ const workers = Array.from({ length: this.opts.concurrency }, () => next());
8423
+ await Promise.all(workers);
8424
+ for (let retry = 0; retry < this.opts.maxRetries && failed.length > 0; retry++) {
8425
+ if (this._destroyed) return;
8426
+ const batch = failed.splice(0, failed.length);
8427
+ const backoff = 2e3 * 2 ** retry;
8428
+ await new Promise((r) => setTimeout(r, backoff));
8429
+ idx = 0;
8430
+ const retryQueue = batch;
8431
+ const retryNext = async () => {
8432
+ while (idx < retryQueue.length) {
8433
+ if (this._destroyed) return;
8434
+ const docId = retryQueue[idx++];
8435
+ const updatedAt = updatedAtMap.get(docId) ?? 0;
8436
+ if (!await this._syncWithSemaphore(docId, updatedAt)) failed.push(docId);
8437
+ if (this.opts.throttleMs > 0 && idx < retryQueue.length) await new Promise((r) => setTimeout(r, this.opts.throttleMs));
8438
+ }
8439
+ };
8440
+ const retryWorkers = Array.from({ length: this.opts.concurrency }, () => retryNext());
8441
+ await Promise.all(retryWorkers);
8442
+ }
8405
8443
  }
8406
8444
  /** Sync a single document by ID. */
8407
8445
  async syncDoc(docId) {
@@ -8482,15 +8520,16 @@ var BackgroundSyncManager = class extends EventEmitter {
8482
8520
  items.sort((a, b) => b.priority - a.priority);
8483
8521
  return items.map((i) => i.docId);
8484
8522
  }
8523
+ /** Returns true on success (or skip), false on error. */
8485
8524
  async _syncWithSemaphore(docId, updatedAt) {
8486
- if (this._destroyed) return;
8525
+ if (this._destroyed) return true;
8487
8526
  const existing = this.syncStates.get(docId);
8488
8527
  if (existing && existing.status === "synced" && existing.lastSynced !== null && existing.lastSynced >= updatedAt) {
8489
8528
  this.emit("stateChanged", {
8490
8529
  docId,
8491
8530
  state: existing
8492
8531
  });
8493
- return;
8532
+ return true;
8494
8533
  }
8495
8534
  await this.semaphore.acquire();
8496
8535
  try {
@@ -8501,6 +8540,7 @@ var BackgroundSyncManager = class extends EventEmitter {
8501
8540
  docId,
8502
8541
  state
8503
8542
  });
8543
+ return state.status !== "error";
8504
8544
  } finally {
8505
8545
  this.semaphore.release();
8506
8546
  }
@@ -8536,10 +8576,12 @@ var BackgroundSyncManager = class extends EventEmitter {
8536
8576
  }
8537
8577
  }
8538
8578
  async _syncNonE2EDoc(docId) {
8579
+ const alreadyCached = this.rootProvider.children.has(docId);
8539
8580
  const childProvider = await this.rootProvider.loadChild(docId);
8540
8581
  await childProvider.ready;
8541
8582
  await this._waitForSynced(childProvider);
8542
8583
  if (this.opts.prefetchFiles && this.fileBlobStore) this._prefetchDocFiles(docId, childProvider.document).catch(() => null);
8584
+ if (!alreadyCached) this.rootProvider.unloadChild(docId);
8543
8585
  return {
8544
8586
  docId,
8545
8587
  status: "synced",