@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.
@@ -2744,8 +2744,10 @@ var OfflineStore = class {
2744
2744
  }
2745
2745
  destroy() {
2746
2746
  this._destroyed = true;
2747
+ const db = this.db;
2747
2748
  this.db = null;
2748
2749
  this.dbPromise = null;
2750
+ if (db) Promise.resolve().then(() => db.close());
2749
2751
  }
2750
2752
  };
2751
2753
 
@@ -3100,8 +3102,11 @@ var AbracadabraProvider = class AbracadabraProvider extends AbracadabraBaseProvi
3100
3102
  }
3101
3103
  destroy() {
3102
3104
  this.document.off("subdocs", this.boundHandleYSubdocsChange);
3105
+ const childIds = [...this.childProviders.keys()];
3103
3106
  for (const provider of this.childProviders.values()) provider.destroy();
3104
3107
  this.childProviders.clear();
3108
+ const wsProviderMap = this.configuration.websocketProvider?.configuration?.providerMap;
3109
+ if (wsProviderMap) for (const childId of childIds) wsProviderMap.delete(childId);
3105
3110
  this.offlineStore?.destroy();
3106
3111
  this.offlineStore = null;
3107
3112
  super.destroy();
@@ -8419,7 +8424,9 @@ var BackgroundSyncManager = class extends EventEmitter {
8419
8424
  this.opts = {
8420
8425
  concurrency: opts?.concurrency ?? 2,
8421
8426
  syncTimeout: opts?.syncTimeout ?? 15e3,
8422
- prefetchFiles: opts?.prefetchFiles ?? true
8427
+ prefetchFiles: opts?.prefetchFiles ?? true,
8428
+ throttleMs: opts?.throttleMs ?? 50,
8429
+ maxRetries: opts?.maxRetries ?? 2
8423
8430
  };
8424
8431
  let serverOrigin = "default";
8425
8432
  try {
@@ -8453,7 +8460,38 @@ var BackgroundSyncManager = class extends EventEmitter {
8453
8460
  for (const [docId, v] of entries) updatedAtMap.set(docId, v?.updatedAt ?? v?.createdAt ?? 0);
8454
8461
  this._prefetchCovers(entries).catch(() => null);
8455
8462
  const queue = this._buildQueue(entries);
8456
- await Promise.all(queue.map((docId) => this._syncWithSemaphore(docId, updatedAtMap.get(docId) ?? 0)));
8463
+ const failed = [];
8464
+ let idx = 0;
8465
+ const next = async () => {
8466
+ while (idx < queue.length) {
8467
+ if (this._destroyed) return;
8468
+ const docId = queue[idx++];
8469
+ const updatedAt = updatedAtMap.get(docId) ?? 0;
8470
+ if (!await this._syncWithSemaphore(docId, updatedAt)) failed.push(docId);
8471
+ if (this.opts.throttleMs > 0 && idx < queue.length) await new Promise((r) => setTimeout(r, this.opts.throttleMs));
8472
+ }
8473
+ };
8474
+ const workers = Array.from({ length: this.opts.concurrency }, () => next());
8475
+ await Promise.all(workers);
8476
+ for (let retry = 0; retry < this.opts.maxRetries && failed.length > 0; retry++) {
8477
+ if (this._destroyed) return;
8478
+ const batch = failed.splice(0, failed.length);
8479
+ const backoff = 2e3 * 2 ** retry;
8480
+ await new Promise((r) => setTimeout(r, backoff));
8481
+ idx = 0;
8482
+ const retryQueue = batch;
8483
+ const retryNext = async () => {
8484
+ while (idx < retryQueue.length) {
8485
+ if (this._destroyed) return;
8486
+ const docId = retryQueue[idx++];
8487
+ const updatedAt = updatedAtMap.get(docId) ?? 0;
8488
+ if (!await this._syncWithSemaphore(docId, updatedAt)) failed.push(docId);
8489
+ if (this.opts.throttleMs > 0 && idx < retryQueue.length) await new Promise((r) => setTimeout(r, this.opts.throttleMs));
8490
+ }
8491
+ };
8492
+ const retryWorkers = Array.from({ length: this.opts.concurrency }, () => retryNext());
8493
+ await Promise.all(retryWorkers);
8494
+ }
8457
8495
  }
8458
8496
  /** Sync a single document by ID. */
8459
8497
  async syncDoc(docId) {
@@ -8534,15 +8572,16 @@ var BackgroundSyncManager = class extends EventEmitter {
8534
8572
  items.sort((a, b) => b.priority - a.priority);
8535
8573
  return items.map((i) => i.docId);
8536
8574
  }
8575
+ /** Returns true on success (or skip), false on error. */
8537
8576
  async _syncWithSemaphore(docId, updatedAt) {
8538
- if (this._destroyed) return;
8577
+ if (this._destroyed) return true;
8539
8578
  const existing = this.syncStates.get(docId);
8540
8579
  if (existing && existing.status === "synced" && existing.lastSynced !== null && existing.lastSynced >= updatedAt) {
8541
8580
  this.emit("stateChanged", {
8542
8581
  docId,
8543
8582
  state: existing
8544
8583
  });
8545
- return;
8584
+ return true;
8546
8585
  }
8547
8586
  await this.semaphore.acquire();
8548
8587
  try {
@@ -8553,6 +8592,7 @@ var BackgroundSyncManager = class extends EventEmitter {
8553
8592
  docId,
8554
8593
  state
8555
8594
  });
8595
+ return state.status !== "error";
8556
8596
  } finally {
8557
8597
  this.semaphore.release();
8558
8598
  }
@@ -8588,10 +8628,12 @@ var BackgroundSyncManager = class extends EventEmitter {
8588
8628
  }
8589
8629
  }
8590
8630
  async _syncNonE2EDoc(docId) {
8631
+ const alreadyCached = this.rootProvider.children.has(docId);
8591
8632
  const childProvider = await this.rootProvider.loadChild(docId);
8592
8633
  await childProvider.ready;
8593
8634
  await this._waitForSynced(childProvider);
8594
8635
  if (this.opts.prefetchFiles && this.fileBlobStore) this._prefetchDocFiles(docId, childProvider.document).catch(() => null);
8636
+ if (!alreadyCached) this.rootProvider.unloadChild(docId);
8595
8637
  return {
8596
8638
  docId,
8597
8639
  status: "synced",