@unicitylabs/sphere-sdk 0.14.1-dev.1 → 0.14.1-dev.2

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.
Files changed (47) hide show
  1. package/dist/connect/index.cjs +20 -5
  2. package/dist/connect/index.cjs.map +1 -1
  3. package/dist/connect/index.d.cts +0 -1
  4. package/dist/connect/index.d.ts +0 -1
  5. package/dist/connect/index.js +20 -5
  6. package/dist/connect/index.js.map +1 -1
  7. package/dist/core/index.cjs +395 -213
  8. package/dist/core/index.cjs.map +1 -1
  9. package/dist/core/index.d.cts +10 -3
  10. package/dist/core/index.d.ts +10 -3
  11. package/dist/core/index.js +395 -213
  12. package/dist/core/index.js.map +1 -1
  13. package/dist/impl/browser/connect/index.cjs +10 -2
  14. package/dist/impl/browser/connect/index.cjs.map +1 -1
  15. package/dist/impl/browser/connect/index.d.cts +0 -1
  16. package/dist/impl/browser/connect/index.d.ts +0 -1
  17. package/dist/impl/browser/connect/index.js +10 -2
  18. package/dist/impl/browser/connect/index.js.map +1 -1
  19. package/dist/impl/nodejs/connect/index.cjs +9 -1
  20. package/dist/impl/nodejs/connect/index.cjs.map +1 -1
  21. package/dist/impl/nodejs/connect/index.d.cts +0 -1
  22. package/dist/impl/nodejs/connect/index.d.ts +0 -1
  23. package/dist/impl/nodejs/connect/index.js +9 -1
  24. package/dist/impl/nodejs/connect/index.js.map +1 -1
  25. package/dist/impl/nodejs/index.d.cts +8 -1
  26. package/dist/impl/nodejs/index.d.ts +8 -1
  27. package/dist/impl/shared/wallet-api/index.d.cts +8 -1
  28. package/dist/impl/shared/wallet-api/index.d.ts +8 -1
  29. package/dist/impl/wallet-api-v2/index.cjs +38 -5
  30. package/dist/impl/wallet-api-v2/index.cjs.map +1 -1
  31. package/dist/impl/wallet-api-v2/index.d.cts +23 -2
  32. package/dist/impl/wallet-api-v2/index.d.ts +23 -2
  33. package/dist/impl/wallet-api-v2/index.js +38 -5
  34. package/dist/impl/wallet-api-v2/index.js.map +1 -1
  35. package/dist/index.cjs +395 -213
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.d.cts +10 -3
  38. package/dist/index.d.ts +10 -3
  39. package/dist/index.js +395 -213
  40. package/dist/index.js.map +1 -1
  41. package/dist/modules/payments-v2/index.cjs +340 -199
  42. package/dist/modules/payments-v2/index.cjs.map +1 -1
  43. package/dist/modules/payments-v2/index.d.cts +68 -19
  44. package/dist/modules/payments-v2/index.d.ts +68 -19
  45. package/dist/modules/payments-v2/index.js +339 -199
  46. package/dist/modules/payments-v2/index.js.map +1 -1
  47. package/package.json +1 -1
@@ -319,8 +319,6 @@ interface WalletApiSessionDeps {
319
319
  kv: ScopedKV;
320
320
  webSocketFactory: WebSocketFactory;
321
321
  emitStatus: (status: ConnectionStatus) => void;
322
- /** Runs the syncEpoch re-seed protocol BEFORE any stream resumes. */
323
- onEpochChange: (epoch: string) => Promise<void>;
324
322
  timing?: Partial<SessionTiming>;
325
323
  timers?: SessionTimers;
326
324
  random?: () => number;
@@ -336,6 +334,7 @@ declare class WalletApiSession {
336
334
  private epochLatch;
337
335
  private reseedChain;
338
336
  private reseedsPending;
337
+ private readonly epochHandlers;
339
338
  private readonly handlers;
340
339
  private readonly statusHandlers;
341
340
  private socket;
@@ -359,6 +358,13 @@ declare class WalletApiSession {
359
358
  private authenticate;
360
359
  private tryRefresh;
361
360
  private challengeSignIn;
361
+ /** §5.1: the latched server syncEpoch ('' before first server contact). */
362
+ currentEpoch(): string;
363
+ /**
364
+ * §5.1 restore hook (FacadeSession contract): handlers are AWAITED inside
365
+ * the reseed chain, BEFORE any stream nudge resumes.
366
+ */
367
+ subscribeEpochChange(handler: (epoch: string) => Promise<void>): () => void;
362
368
  noteEpoch(epoch: string): void;
363
369
  private runReseed;
364
370
  subscribeStream(stream: WakeStream, handler: () => void): () => void;
@@ -441,6 +447,14 @@ interface DeliveryPort {
441
447
  deliver(recipientPubkey: string, blob: Uint8Array, options: DeliverOptions): Promise<DeliveryReceipt>;
442
448
  deliverBatch?(recipientPubkey: string, blobs: Uint8Array[], options: DeliverOptions): Promise<DeliveryReceipt[]>;
443
449
  incoming(sinceCursor?: string): AsyncIterable<IncomingDelivery>;
450
+ /**
451
+ * The syncEpoch of the most recent incoming() page — updated per page, null
452
+ * before the first. §5.7 restore self-detection: the mailbox page is the
453
+ * honest epoch source, so Receive voids its (cursor, epoch) continuity on a
454
+ * mismatch even when the wake socket missed a server restore. (Pinned by the
455
+ * S7 contract suite; wallet-api#119's S7 text carries the same sentence.)
456
+ */
457
+ incomingEpoch(): string | null;
444
458
  ack(deliveryId: string, disposition: 'claimed' | 'rejected', reason?: 'invalid' | 'not-owned' | 'storage-rejected' | 'other'): Promise<void>;
445
459
  onWake?(cb: () => void): () => void;
446
460
  }
@@ -495,6 +509,7 @@ declare class WalletApiDeliveryPort implements DeliveryPort {
495
509
  private readonly wake;
496
510
  private deriveFn;
497
511
  private readonly seenChain;
512
+ private lastIncomingEpoch;
498
513
  constructor(config: WalletApiDeliveryPortConfig);
499
514
  bindDeliveryKeys(derive: (blob: Uint8Array) => Promise<{
500
515
  tokenId: string;
@@ -508,6 +523,8 @@ declare class WalletApiDeliveryPort implements DeliveryPort {
508
523
  private depositAll;
509
524
  private depositOne;
510
525
  incoming(sinceCursor?: string): AsyncIterable<IncomingDelivery>;
526
+ /** §5.7: the page-honest epoch — the restore-detection source Receive keys on. */
527
+ incomingEpoch(): string | null;
511
528
  private toIncoming;
512
529
  private openEnvelope;
513
530
  private fetchVerified;
@@ -563,6 +580,10 @@ declare class WalletApiSplitCheckpointStore implements SplitCheckpointStore {
563
580
  private cacheKey;
564
581
  private aad;
565
582
  put(transferId: string, opIndex: number, bytes: Uint8Array): Promise<Uint8Array>;
583
+ /** §5.1 restore (CheckpointReseeder): re-POST the cached ciphertext byte-identical; false = none cached. */
584
+ reseedCheckpoint(transferId: string, opIndex: number): Promise<boolean>;
585
+ /** The ONE signed progress-append path put() and reseedCheckpoint() share. */
586
+ private post;
566
587
  get(transferId: string, opIndex: number): Promise<Uint8Array | null>;
567
588
  private open;
568
589
  }
@@ -319,8 +319,6 @@ interface WalletApiSessionDeps {
319
319
  kv: ScopedKV;
320
320
  webSocketFactory: WebSocketFactory;
321
321
  emitStatus: (status: ConnectionStatus) => void;
322
- /** Runs the syncEpoch re-seed protocol BEFORE any stream resumes. */
323
- onEpochChange: (epoch: string) => Promise<void>;
324
322
  timing?: Partial<SessionTiming>;
325
323
  timers?: SessionTimers;
326
324
  random?: () => number;
@@ -336,6 +334,7 @@ declare class WalletApiSession {
336
334
  private epochLatch;
337
335
  private reseedChain;
338
336
  private reseedsPending;
337
+ private readonly epochHandlers;
339
338
  private readonly handlers;
340
339
  private readonly statusHandlers;
341
340
  private socket;
@@ -359,6 +358,13 @@ declare class WalletApiSession {
359
358
  private authenticate;
360
359
  private tryRefresh;
361
360
  private challengeSignIn;
361
+ /** §5.1: the latched server syncEpoch ('' before first server contact). */
362
+ currentEpoch(): string;
363
+ /**
364
+ * §5.1 restore hook (FacadeSession contract): handlers are AWAITED inside
365
+ * the reseed chain, BEFORE any stream nudge resumes.
366
+ */
367
+ subscribeEpochChange(handler: (epoch: string) => Promise<void>): () => void;
362
368
  noteEpoch(epoch: string): void;
363
369
  private runReseed;
364
370
  subscribeStream(stream: WakeStream, handler: () => void): () => void;
@@ -441,6 +447,14 @@ interface DeliveryPort {
441
447
  deliver(recipientPubkey: string, blob: Uint8Array, options: DeliverOptions): Promise<DeliveryReceipt>;
442
448
  deliverBatch?(recipientPubkey: string, blobs: Uint8Array[], options: DeliverOptions): Promise<DeliveryReceipt[]>;
443
449
  incoming(sinceCursor?: string): AsyncIterable<IncomingDelivery>;
450
+ /**
451
+ * The syncEpoch of the most recent incoming() page — updated per page, null
452
+ * before the first. §5.7 restore self-detection: the mailbox page is the
453
+ * honest epoch source, so Receive voids its (cursor, epoch) continuity on a
454
+ * mismatch even when the wake socket missed a server restore. (Pinned by the
455
+ * S7 contract suite; wallet-api#119's S7 text carries the same sentence.)
456
+ */
457
+ incomingEpoch(): string | null;
444
458
  ack(deliveryId: string, disposition: 'claimed' | 'rejected', reason?: 'invalid' | 'not-owned' | 'storage-rejected' | 'other'): Promise<void>;
445
459
  onWake?(cb: () => void): () => void;
446
460
  }
@@ -495,6 +509,7 @@ declare class WalletApiDeliveryPort implements DeliveryPort {
495
509
  private readonly wake;
496
510
  private deriveFn;
497
511
  private readonly seenChain;
512
+ private lastIncomingEpoch;
498
513
  constructor(config: WalletApiDeliveryPortConfig);
499
514
  bindDeliveryKeys(derive: (blob: Uint8Array) => Promise<{
500
515
  tokenId: string;
@@ -508,6 +523,8 @@ declare class WalletApiDeliveryPort implements DeliveryPort {
508
523
  private depositAll;
509
524
  private depositOne;
510
525
  incoming(sinceCursor?: string): AsyncIterable<IncomingDelivery>;
526
+ /** §5.7: the page-honest epoch — the restore-detection source Receive keys on. */
527
+ incomingEpoch(): string | null;
511
528
  private toIncoming;
512
529
  private openEnvelope;
513
530
  private fetchVerified;
@@ -563,6 +580,10 @@ declare class WalletApiSplitCheckpointStore implements SplitCheckpointStore {
563
580
  private cacheKey;
564
581
  private aad;
565
582
  put(transferId: string, opIndex: number, bytes: Uint8Array): Promise<Uint8Array>;
583
+ /** §5.1 restore (CheckpointReseeder): re-POST the cached ciphertext byte-identical; false = none cached. */
584
+ reseedCheckpoint(transferId: string, opIndex: number): Promise<boolean>;
585
+ /** The ONE signed progress-append path put() and reseedCheckpoint() share. */
586
+ private post;
566
587
  get(transferId: string, opIndex: number): Promise<Uint8Array | null>;
567
588
  private open;
568
589
  }
@@ -694,7 +694,10 @@ var STORE_KEYS = {
694
694
  shortfalls: "shortfalls",
695
695
  settlingLinks: "settling",
696
696
  streamCursor: (s) => `cursor:${s}`,
697
- epochLatch: "epoch-latch"
697
+ epochLatch: "epoch-latch",
698
+ // §5.2 InventoryView durable overlays (#625/#679).
699
+ suspectedSpent: "suspected-spent",
700
+ knownSpends: "known-spends"
698
701
  };
699
702
 
700
703
  // node_modules/@noble/curves/utils.js
@@ -2718,6 +2721,7 @@ var WalletApiSession = class {
2718
2721
  epochLatch = null;
2719
2722
  reseedChain = Promise.resolve();
2720
2723
  reseedsPending = 0;
2724
+ epochHandlers = /* @__PURE__ */ new Set();
2721
2725
  handlers = /* @__PURE__ */ new Map();
2722
2726
  statusHandlers = /* @__PURE__ */ new Set();
2723
2727
  socket = null;
@@ -2820,6 +2824,18 @@ var WalletApiSession = class {
2820
2824
  await this.deps.kv.set(this.refreshKey, tokens.refreshToken);
2821
2825
  }
2822
2826
  // ── epoch latch (F12) ─────────────────────────────────────────────────────
2827
+ /** §5.1: the latched server syncEpoch ('' before first server contact). */
2828
+ currentEpoch() {
2829
+ return this.epochLatch ?? "";
2830
+ }
2831
+ /**
2832
+ * §5.1 restore hook (FacadeSession contract): handlers are AWAITED inside
2833
+ * the reseed chain, BEFORE any stream nudge resumes.
2834
+ */
2835
+ subscribeEpochChange(handler) {
2836
+ this.epochHandlers.add(handler);
2837
+ return () => this.epochHandlers.delete(handler);
2838
+ }
2823
2839
  noteEpoch(epoch) {
2824
2840
  if (this.epochLatch === epoch) return;
2825
2841
  const previous = this.epochLatch;
@@ -2833,7 +2849,7 @@ var WalletApiSession = class {
2833
2849
  }
2834
2850
  async runReseed(epoch, previous) {
2835
2851
  try {
2836
- await this.deps.onEpochChange(epoch);
2852
+ for (const handler of [...this.epochHandlers]) await handler(epoch);
2837
2853
  await this.deps.kv.set(STORE_KEYS.epochLatch, epoch);
2838
2854
  } catch {
2839
2855
  if (this.epochLatch === epoch) this.epochLatch = previous;
@@ -4041,6 +4057,7 @@ var WalletApiDeliveryPort = class {
4041
4057
  wake;
4042
4058
  deriveFn;
4043
4059
  seenChain = new SerialChain();
4060
+ lastIncomingEpoch = null;
4044
4061
  constructor(config) {
4045
4062
  this.client = config.client;
4046
4063
  this.kv = config.kv;
@@ -4135,6 +4152,7 @@ var WalletApiDeliveryPort = class {
4135
4152
  const seen = await this.readSeen();
4136
4153
  let page = await this.client.listMailbox(sinceCursor === void 0 ? 0 : Number(sinceCursor));
4137
4154
  for (; ; ) {
4155
+ this.lastIncomingEpoch = String(page.syncEpoch);
4138
4156
  for (const entry of page.entries) {
4139
4157
  if (entry.status !== "unclaimed") continue;
4140
4158
  if (seen.has(entry.entryId)) continue;
@@ -4144,6 +4162,10 @@ var WalletApiDeliveryPort = class {
4144
4162
  page = await this.client.listMailbox(page.cursor);
4145
4163
  }
4146
4164
  }
4165
+ /** §5.7: the page-honest epoch — the restore-detection source Receive keys on. */
4166
+ incomingEpoch() {
4167
+ return this.lastIncomingEpoch;
4168
+ }
4147
4169
  toIncoming(entry) {
4148
4170
  const bundle = this.openEnvelope(entry);
4149
4171
  return {
@@ -4299,7 +4321,7 @@ var WalletApiSplitCheckpointStore = class {
4299
4321
  return utf8(`${transferId}:${String(opIndex)}`);
4300
4322
  }
4301
4323
  async put(transferId, opIndex, bytes) {
4302
- const { client, kv, fieldKey, signProgress } = this.config;
4324
+ const { kv, fieldKey } = this.config;
4303
4325
  const aad = this.aad(transferId, opIndex);
4304
4326
  const cacheKey = this.cacheKey(transferId, opIndex);
4305
4327
  let envelope = await kv.get(cacheKey);
@@ -4307,10 +4329,21 @@ var WalletApiSplitCheckpointStore = class {
4307
4329
  envelope = encryptFieldBytes(fieldKey, bytes, aad);
4308
4330
  await kv.set(cacheKey, envelope);
4309
4331
  }
4310
- const signature = await signProgress(progressSignMessage(transferId, opIndex, envelope));
4311
- const record = await client.postProgress(transferId, opIndex, envelope, signature);
4332
+ const record = await this.post(transferId, opIndex, envelope);
4312
4333
  return this.open(record.payload, aad);
4313
4334
  }
4335
+ /** §5.1 restore (CheckpointReseeder): re-POST the cached ciphertext byte-identical; false = none cached. */
4336
+ async reseedCheckpoint(transferId, opIndex) {
4337
+ const envelope = await this.config.kv.get(this.cacheKey(transferId, opIndex));
4338
+ if (envelope === null) return false;
4339
+ await this.post(transferId, opIndex, envelope);
4340
+ return true;
4341
+ }
4342
+ /** The ONE signed progress-append path put() and reseedCheckpoint() share. */
4343
+ async post(transferId, opIndex, envelope) {
4344
+ const signature = await this.config.signProgress(progressSignMessage(transferId, opIndex, envelope));
4345
+ return this.config.client.postProgress(transferId, opIndex, envelope, signature);
4346
+ }
4314
4347
  async get(transferId, opIndex) {
4315
4348
  const records = await this.config.client.getProgress(transferId);
4316
4349
  const record = records.find((r) => r.opIndex === opIndex);