@tinycloud/cli 1.1.0-beta.17 → 1.1.0-beta.18

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.
@@ -20418,6 +20418,8 @@ var ReplicaErrorCode = {
20418
20418
  CONFIG_MISMATCH: "REPLICA_CONFIG_MISMATCH",
20419
20419
  /** The runtime has no supported durable store (e.g. Node < 22.13). */
20420
20420
  RUNTIME_UNSUPPORTED: "RUNTIME_UNSUPPORTED",
20421
+ /** A required open() argument is missing or malformed (e.g. `principal`). */
20422
+ INVALID_ARGUMENT: "REPLICA_INVALID_ARGUMENT",
20421
20423
  /** The local store failed (I/O, corruption, schema). */
20422
20424
  STORAGE_ERROR: "STORAGE_ERROR",
20423
20425
  /** The local disk is full. */
@@ -20458,7 +20460,9 @@ var ReplicaErrorCode = {
20458
20460
  /** Fetched bytes do not hash to the ETag the node attested for them. */
20459
20461
  CONTENT_MISMATCH: "CONTENT_MISMATCH",
20460
20462
  /** A stored blob no longer hashes to its name. */
20461
- INTEGRITY_ERROR: "INTEGRITY_ERROR"
20463
+ INTEGRITY_ERROR: "INTEGRITY_ERROR",
20464
+ /** The replica handle was closed; in-flight calls settle with this code. */
20465
+ CLOSED: "REPLICA_CLOSED"
20462
20466
  };
20463
20467
  var REPLICA_ERROR = /* @__PURE__ */ Symbol.for("tinycloud.replica.error");
20464
20468
  var ReplicaError = class extends Error {
@@ -20568,12 +20572,14 @@ var Replica = class {
20568
20572
  #transportFor;
20569
20573
  #now;
20570
20574
  #leaseTtlMs;
20575
+ #onCommit;
20571
20576
  constructor(options) {
20572
20577
  this.#store = options.store;
20573
20578
  const transport = options.transport;
20574
20579
  this.#transportFor = options.transportFor ?? (transport === void 0 ? void 0 : () => transport);
20575
20580
  this.#now = options.now ?? Date.now;
20576
20581
  this.#leaseTtlMs = options.leaseTtlMs ?? DEFAULT_LEASE_TTL_MS;
20582
+ this.#onCommit = options.onCommit;
20577
20583
  }
20578
20584
  async #state() {
20579
20585
  const state = await this.#store.open();
@@ -20768,9 +20774,10 @@ var Replica = class {
20768
20774
  let cursor = state.cursor;
20769
20775
  let pinned = state.nodeDid;
20770
20776
  let coverage = state.coverage;
20777
+ const retentionGrantCid = config.retentionGrantCid;
20771
20778
  for (; ; ) {
20772
20779
  let page;
20773
- const retentionGrant = config.retentionGrantCid;
20780
+ const retentionGrant = retentionGrantCid;
20774
20781
  try {
20775
20782
  page = await attempt.transport.syncPage({
20776
20783
  prefix: config.prefix,
@@ -20806,6 +20813,7 @@ var Replica = class {
20806
20813
  authority: page.authority,
20807
20814
  coverage,
20808
20815
  at,
20816
+ retentionGrantCid: retentionGrant,
20809
20817
  window,
20810
20818
  complete: !page.more,
20811
20819
  promoteGrant: attempt.promote
@@ -20815,6 +20823,7 @@ var Replica = class {
20815
20823
  attempt.promote = null;
20816
20824
  }
20817
20825
  report.pages += 1;
20826
+ this.#onCommit?.();
20818
20827
  report.changes += page.changes.length;
20819
20828
  report.deleted += page.changes.filter((change) => change.deleted).length;
20820
20829
  report.fetched += verified.fetched;
@@ -20824,7 +20833,7 @@ var Replica = class {
20824
20833
  await this.#store.renewLease(attempt.lease, this.#leaseTtlMs);
20825
20834
  if (!page.more) break;
20826
20835
  }
20827
- report.repaired = await this.#repair(attempt, cursor, pinned, coverage);
20836
+ report.repaired = await this.#repair(attempt, cursor, pinned, coverage, retentionGrantCid);
20828
20837
  report.blobsCollected = await this.#store.collectGarbage(attempt.lease);
20829
20838
  report.coverage = coverage;
20830
20839
  report.contentMissing = (await this.#store.pendingRepairs(Number.MAX_SAFE_INTEGER)).length;
@@ -20906,7 +20915,7 @@ var Replica = class {
20906
20915
  }
20907
20916
  return { changes, blobs, fetched: fetched2 };
20908
20917
  }
20909
- async #repair(attempt, cursor, nodeDid, coverage) {
20918
+ async #repair(attempt, cursor, nodeDid, coverage, retentionGrantCid) {
20910
20919
  const pending = await this.#store.pendingRepairs(Number.MAX_SAFE_INTEGER);
20911
20920
  let repaired = 0;
20912
20921
  for (let start = 0; start < pending.length; start += REPAIR_BATCH) {
@@ -20934,11 +20943,13 @@ var Replica = class {
20934
20943
  authority: null,
20935
20944
  coverage,
20936
20945
  at: new Date(this.#now()).toISOString(),
20946
+ retentionGrantCid,
20937
20947
  window: this.#syncWindow(state.authority, attempt.grant),
20938
20948
  complete: false,
20939
20949
  promoteGrant: null
20940
20950
  });
20941
20951
  repaired += changes.length;
20952
+ this.#onCommit?.();
20942
20953
  }
20943
20954
  return repaired;
20944
20955
  }
@@ -21286,6 +21297,8 @@ var ReplicaErrorCode2 = {
21286
21297
  CONFIG_MISMATCH: "REPLICA_CONFIG_MISMATCH",
21287
21298
  /** The runtime has no supported durable store (e.g. Node < 22.13). */
21288
21299
  RUNTIME_UNSUPPORTED: "RUNTIME_UNSUPPORTED",
21300
+ /** A required open() argument is missing or malformed (e.g. `principal`). */
21301
+ INVALID_ARGUMENT: "REPLICA_INVALID_ARGUMENT",
21289
21302
  /** The local store failed (I/O, corruption, schema). */
21290
21303
  STORAGE_ERROR: "STORAGE_ERROR",
21291
21304
  /** The local disk is full. */
@@ -21326,7 +21339,9 @@ var ReplicaErrorCode2 = {
21326
21339
  /** Fetched bytes do not hash to the ETag the node attested for them. */
21327
21340
  CONTENT_MISMATCH: "CONTENT_MISMATCH",
21328
21341
  /** A stored blob no longer hashes to its name. */
21329
- INTEGRITY_ERROR: "INTEGRITY_ERROR"
21342
+ INTEGRITY_ERROR: "INTEGRITY_ERROR",
21343
+ /** The replica handle was closed; in-flight calls settle with this code. */
21344
+ CLOSED: "REPLICA_CLOSED"
21330
21345
  };
21331
21346
  var REPLICA_ERROR2 = /* @__PURE__ */ Symbol.for("tinycloud.replica.error");
21332
21347
  var ReplicaError2 = class extends Error {
@@ -21729,9 +21744,10 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
21729
21744
  async setRetentionGrant(cid) {
21730
21745
  await this.#guardedWrite("Updating the retention grant", () => {
21731
21746
  this.#db.run(
21732
- "UPDATE replica SET retention_grant_cid = ?, local_read_policy = ? WHERE id = 1",
21747
+ "UPDATE replica SET retention_grant_cid = ?, local_read_policy = ?, retain_until = NULL WHERE id = 1 AND retention_grant_cid IS NOT ?",
21733
21748
  cid,
21734
- cid === null ? "whileGrantValid" : "retainAfterExpiry"
21749
+ cid === null ? "whileGrantValid" : "retainAfterExpiry",
21750
+ cid
21735
21751
  );
21736
21752
  });
21737
21753
  }
@@ -21934,9 +21950,13 @@ var SqliteReplicaStore = class _SqliteReplicaStore {
21934
21950
  const sets = ["cursor = ?", "coverage = ?"];
21935
21951
  const params = [p.cursor, p.coverage];
21936
21952
  if (p.authority !== null) {
21937
- sets.push("node_did = ?", "attested = 1", "not_before = ?", "expires_at = ?", "retain_until = ?", "last_sync_at = ?");
21938
- params.push(p.source.nodeDid, p.authority.notBefore, p.authority.expiresAt, p.authority.retainUntil, p.at);
21939
- if (p.authority.retainUntil !== null) sets.push("retention_revoked = NULL");
21953
+ sets.push("node_did = ?", "attested = 1", "not_before = ?", "expires_at = ?", "last_sync_at = ?");
21954
+ params.push(p.source.nodeDid, p.authority.notBefore, p.authority.expiresAt, p.at);
21955
+ if (this.#row().retention_grant_cid === p.retentionGrantCid) {
21956
+ sets.push("retain_until = ?");
21957
+ params.push(p.authority.retainUntil);
21958
+ if (p.authority.retainUntil !== null) sets.push("retention_revoked = NULL");
21959
+ }
21940
21960
  }
21941
21961
  if (p.complete) {
21942
21962
  sets.push("last_complete_at = ?", "last_error = NULL");