@tinycloud/replica 0.4.0-beta.1 → 0.4.0-beta.3

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.
@@ -6362,6 +6362,8 @@ var DEFAULT_PAGE_LIMIT = 500;
6362
6362
  var DEFAULT_LEASE_TTL_MS = 12e4;
6363
6363
  var FETCH_CHUNK = 100;
6364
6364
  var REPAIR_BATCH = 100;
6365
+ var REPAIR_MAX_TRIES = 5;
6366
+ var REPAIR_BACKOFF_BASE_MS = 6e4;
6365
6367
  var RETENTION_REVOKED = /* @__PURE__ */ new Set(["retention-grant-revoked", "retention-grant-ancestor-revoked"]);
6366
6368
  var PENDING_REFUSALS = /* @__PURE__ */ new Set([
6367
6369
  ReplicaErrorCode.GRANT_UNAUTHORIZED,
@@ -6371,6 +6373,9 @@ var PENDING_REFUSALS = /* @__PURE__ */ new Set([
6371
6373
  function contentHash(bytes) {
6372
6374
  return bytesToHex(blake3(bytes));
6373
6375
  }
6376
+ function repairId(entry) {
6377
+ return `${entry.hash}\0${entry.key}`;
6378
+ }
6374
6379
  function sameEtag(a, b) {
6375
6380
  return a.replace(/^"|"$/g, "") === b.replace(/^"|"$/g, "");
6376
6381
  }
@@ -6387,6 +6392,9 @@ var Replica = class {
6387
6392
  #now;
6388
6393
  #leaseTtlMs;
6389
6394
  #onCommit;
6395
+ #contentFetch;
6396
+ /** Failed repair fetches of this session, by key and ETag hash. Never persisted: a new `Replica` retries afresh. */
6397
+ #repairTries = /* @__PURE__ */ new Map();
6390
6398
  constructor(options) {
6391
6399
  this.#store = options.store;
6392
6400
  const transport = options.transport;
@@ -6394,6 +6402,7 @@ var Replica = class {
6394
6402
  this.#now = options.now ?? Date.now;
6395
6403
  this.#leaseTtlMs = options.leaseTtlMs ?? DEFAULT_LEASE_TTL_MS;
6396
6404
  this.#onCommit = options.onCommit;
6405
+ this.#contentFetch = options.contentFetch ?? "eager";
6397
6406
  }
6398
6407
  async #state() {
6399
6408
  const state = await this.#store.open();
@@ -6722,6 +6731,7 @@ var Replica = class {
6722
6731
  changes[candidate.index].content = true;
6723
6732
  return false;
6724
6733
  });
6734
+ if (this.#contentFetch === "lazy") return { changes, blobs, fetched: 0 };
6725
6735
  let fetched2 = 0;
6726
6736
  for (let start = 0; start < needed.length; start += FETCH_CHUNK) {
6727
6737
  const chunk = needed.slice(start, start + FETCH_CHUNK);
@@ -6741,7 +6751,15 @@ var Replica = class {
6741
6751
  return { changes, blobs, fetched: fetched2 };
6742
6752
  }
6743
6753
  async #repair(attempt, cursor, nodeDid, coverage, retentionGrantCid) {
6744
- const pending = await this.#store.pendingRepairs(Number.MAX_SAFE_INTEGER);
6754
+ if (this.#contentFetch === "lazy") return 0;
6755
+ const all = await this.#store.pendingRepairs(Number.MAX_SAFE_INTEGER);
6756
+ const now = this.#now();
6757
+ const pendingIds = new Set(all.map((entry) => repairId(entry)));
6758
+ for (const id of this.#repairTries.keys()) if (!pendingIds.has(id)) this.#repairTries.delete(id);
6759
+ const pending = all.filter((entry) => {
6760
+ const state = this.#repairTries.get(repairId(entry));
6761
+ return state === void 0 || state.tries < REPAIR_MAX_TRIES && now >= state.nextAttemptAt;
6762
+ });
6745
6763
  let repaired = 0;
6746
6764
  for (let start = 0; start < pending.length; start += REPAIR_BATCH) {
6747
6765
  const chunk = pending.slice(start, start + REPAIR_BATCH);
@@ -6753,7 +6771,14 @@ var Replica = class {
6753
6771
  const changes = [];
6754
6772
  for (const entry of chunk) {
6755
6773
  const bytes = acceptContent(entry, contents.get(entry.key));
6756
- if (bytes === void 0) continue;
6774
+ const id = repairId(entry);
6775
+ if (bytes === void 0) {
6776
+ const tries = (this.#repairTries.get(id)?.tries ?? 0) + 1;
6777
+ const wait = tries === 1 ? 0 : REPAIR_BACKOFF_BASE_MS * 2 ** (tries - 2);
6778
+ this.#repairTries.set(id, { tries, nextAttemptAt: this.#now() + wait });
6779
+ continue;
6780
+ }
6781
+ this.#repairTries.delete(id);
6757
6782
  blobs.set(entry.hash, bytes);
6758
6783
  changes.push({ ...entry, content: true });
6759
6784
  }