@unicitylabs/sphere-sdk 0.14.0-dev.5 → 0.14.0-dev.7

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.
@@ -742,7 +742,10 @@ var STORE_KEYS = {
742
742
  shortfalls: "shortfalls",
743
743
  settlingLinks: "settling",
744
744
  streamCursor: (s) => `cursor:${s}`,
745
- epochLatch: "epoch-latch"
745
+ epochLatch: "epoch-latch",
746
+ // §5.2 InventoryView durable overlays (#625/#679).
747
+ suspectedSpent: "suspected-spent",
748
+ knownSpends: "known-spends"
746
749
  };
747
750
 
748
751
  // node_modules/@noble/curves/utils.js
@@ -2766,7 +2769,9 @@ var WalletApiSession = class {
2766
2769
  epochLatch = null;
2767
2770
  reseedChain = Promise.resolve();
2768
2771
  reseedsPending = 0;
2772
+ epochHandlers = /* @__PURE__ */ new Set();
2769
2773
  handlers = /* @__PURE__ */ new Map();
2774
+ statusHandlers = /* @__PURE__ */ new Set();
2770
2775
  socket = null;
2771
2776
  started = false;
2772
2777
  stopped = false;
@@ -2867,6 +2872,18 @@ var WalletApiSession = class {
2867
2872
  await this.deps.kv.set(this.refreshKey, tokens.refreshToken);
2868
2873
  }
2869
2874
  // ── epoch latch (F12) ─────────────────────────────────────────────────────
2875
+ /** §5.1: the latched server syncEpoch ('' before first server contact). */
2876
+ currentEpoch() {
2877
+ return this.epochLatch ?? "";
2878
+ }
2879
+ /**
2880
+ * §5.1 restore hook (FacadeSession contract): handlers are AWAITED inside
2881
+ * the reseed chain, BEFORE any stream nudge resumes.
2882
+ */
2883
+ subscribeEpochChange(handler) {
2884
+ this.epochHandlers.add(handler);
2885
+ return () => this.epochHandlers.delete(handler);
2886
+ }
2870
2887
  noteEpoch(epoch) {
2871
2888
  if (this.epochLatch === epoch) return;
2872
2889
  const previous = this.epochLatch;
@@ -2880,7 +2897,7 @@ var WalletApiSession = class {
2880
2897
  }
2881
2898
  async runReseed(epoch, previous) {
2882
2899
  try {
2883
- await this.deps.onEpochChange(epoch);
2900
+ for (const handler of [...this.epochHandlers]) await handler(epoch);
2884
2901
  await this.deps.kv.set(STORE_KEYS.epochLatch, epoch);
2885
2902
  } catch {
2886
2903
  if (this.epochLatch === epoch) this.epochLatch = previous;
@@ -2917,10 +2934,16 @@ var WalletApiSession = class {
2917
2934
  status() {
2918
2935
  return this.lastStatus ?? "offline";
2919
2936
  }
2937
+ /** Transition feed off the existing emitStatus point (FacadeSession.subscribeStatus). */
2938
+ subscribeStatus(handler) {
2939
+ this.statusHandlers.add(handler);
2940
+ return () => this.statusHandlers.delete(handler);
2941
+ }
2920
2942
  emitStatus(status) {
2921
2943
  if (this.stopped || this.lastStatus === status) return;
2922
2944
  this.lastStatus = status;
2923
2945
  this.deps.emitStatus(status);
2946
+ for (const handler of this.statusHandlers) handler(status);
2924
2947
  }
2925
2948
  async connect() {
2926
2949
  if (this.stopped) return;
@@ -4082,6 +4105,7 @@ var WalletApiDeliveryPort = class {
4082
4105
  wake;
4083
4106
  deriveFn;
4084
4107
  seenChain = new SerialChain();
4108
+ lastIncomingEpoch = null;
4085
4109
  constructor(config) {
4086
4110
  this.client = config.client;
4087
4111
  this.kv = config.kv;
@@ -4176,6 +4200,7 @@ var WalletApiDeliveryPort = class {
4176
4200
  const seen = await this.readSeen();
4177
4201
  let page = await this.client.listMailbox(sinceCursor === void 0 ? 0 : Number(sinceCursor));
4178
4202
  for (; ; ) {
4203
+ this.lastIncomingEpoch = String(page.syncEpoch);
4179
4204
  for (const entry of page.entries) {
4180
4205
  if (entry.status !== "unclaimed") continue;
4181
4206
  if (seen.has(entry.entryId)) continue;
@@ -4185,6 +4210,10 @@ var WalletApiDeliveryPort = class {
4185
4210
  page = await this.client.listMailbox(page.cursor);
4186
4211
  }
4187
4212
  }
4213
+ /** §5.7: the page-honest epoch — the restore-detection source Receive keys on. */
4214
+ incomingEpoch() {
4215
+ return this.lastIncomingEpoch;
4216
+ }
4188
4217
  toIncoming(entry) {
4189
4218
  const bundle = this.openEnvelope(entry);
4190
4219
  return {
@@ -4340,7 +4369,7 @@ var WalletApiSplitCheckpointStore = class {
4340
4369
  return utf8(`${transferId}:${String(opIndex)}`);
4341
4370
  }
4342
4371
  async put(transferId, opIndex, bytes) {
4343
- const { client, kv, fieldKey, signProgress } = this.config;
4372
+ const { kv, fieldKey } = this.config;
4344
4373
  const aad = this.aad(transferId, opIndex);
4345
4374
  const cacheKey = this.cacheKey(transferId, opIndex);
4346
4375
  let envelope = await kv.get(cacheKey);
@@ -4348,10 +4377,21 @@ var WalletApiSplitCheckpointStore = class {
4348
4377
  envelope = encryptFieldBytes(fieldKey, bytes, aad);
4349
4378
  await kv.set(cacheKey, envelope);
4350
4379
  }
4351
- const signature = await signProgress(progressSignMessage(transferId, opIndex, envelope));
4352
- const record = await client.postProgress(transferId, opIndex, envelope, signature);
4380
+ const record = await this.post(transferId, opIndex, envelope);
4353
4381
  return this.open(record.payload, aad);
4354
4382
  }
4383
+ /** §5.1 restore (CheckpointReseeder): re-POST the cached ciphertext byte-identical; false = none cached. */
4384
+ async reseedCheckpoint(transferId, opIndex) {
4385
+ const envelope = await this.config.kv.get(this.cacheKey(transferId, opIndex));
4386
+ if (envelope === null) return false;
4387
+ await this.post(transferId, opIndex, envelope);
4388
+ return true;
4389
+ }
4390
+ /** The ONE signed progress-append path put() and reseedCheckpoint() share. */
4391
+ async post(transferId, opIndex, envelope) {
4392
+ const signature = await this.config.signProgress(progressSignMessage(transferId, opIndex, envelope));
4393
+ return this.config.client.postProgress(transferId, opIndex, envelope, signature);
4394
+ }
4355
4395
  async get(transferId, opIndex) {
4356
4396
  const records = await this.config.client.getProgress(transferId);
4357
4397
  const record = records.find((r) => r.opIndex === opIndex);