@unicitylabs/sphere-sdk 0.14.1-dev.2 → 0.14.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 (39) hide show
  1. package/dist/connect/index.cjs +1 -1
  2. package/dist/connect/index.cjs.map +1 -1
  3. package/dist/connect/index.js +1 -1
  4. package/dist/connect/index.js.map +1 -1
  5. package/dist/core/index.cjs +69 -27
  6. package/dist/core/index.cjs.map +1 -1
  7. package/dist/core/index.d.cts +21 -1
  8. package/dist/core/index.d.ts +21 -1
  9. package/dist/core/index.js +69 -27
  10. package/dist/core/index.js.map +1 -1
  11. package/dist/impl/browser/connect/index.cjs +1 -1
  12. package/dist/impl/browser/connect/index.cjs.map +1 -1
  13. package/dist/impl/browser/connect/index.js +1 -1
  14. package/dist/impl/browser/connect/index.js.map +1 -1
  15. package/dist/impl/browser/index.cjs +33 -0
  16. package/dist/impl/browser/index.cjs.map +1 -1
  17. package/dist/impl/browser/index.js +33 -0
  18. package/dist/impl/browser/index.js.map +1 -1
  19. package/dist/impl/nodejs/index.cjs +33 -0
  20. package/dist/impl/nodejs/index.cjs.map +1 -1
  21. package/dist/impl/nodejs/index.d.cts +41 -1
  22. package/dist/impl/nodejs/index.d.ts +41 -1
  23. package/dist/impl/nodejs/index.js +33 -0
  24. package/dist/impl/nodejs/index.js.map +1 -1
  25. package/dist/impl/shared/wallet-api/index.d.cts +21 -1
  26. package/dist/impl/shared/wallet-api/index.d.ts +21 -1
  27. package/dist/index.cjs +69 -27
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +21 -1
  30. package/dist/index.d.ts +21 -1
  31. package/dist/index.js +69 -27
  32. package/dist/index.js.map +1 -1
  33. package/dist/modules/payments-v2/index.cjs +36 -26
  34. package/dist/modules/payments-v2/index.cjs.map +1 -1
  35. package/dist/modules/payments-v2/index.d.cts +16 -6
  36. package/dist/modules/payments-v2/index.d.ts +16 -6
  37. package/dist/modules/payments-v2/index.js +35 -26
  38. package/dist/modules/payments-v2/index.js.map +1 -1
  39. package/package.json +1 -1
@@ -922,6 +922,15 @@ var TIMEOUTS = {
922
922
  var COMPOSING_INDICATOR_KIND = 25050;
923
923
  var TIMESTAMP_RANDOMIZATION = 2 * 24 * 60 * 60;
924
924
  var EVENT_KINDS = NOSTR_EVENT_KINDS;
925
+ function declaredNetwork(event) {
926
+ let value;
927
+ try {
928
+ value = JSON.parse(event.content)?.network;
929
+ } catch {
930
+ return void 0;
931
+ }
932
+ return typeof value === "string" && value !== "" ? value : void 0;
933
+ }
925
934
  var NostrTransportProvider = class _NostrTransportProvider {
926
935
  id = "nostr";
927
936
  name = "Nostr Transport";
@@ -1418,6 +1427,26 @@ var NostrTransportProvider = class _NostrTransportProvider {
1418
1427
  }
1419
1428
  /**
1420
1429
  * Convert a BindingInfo (from nostr-js-sdk) to PeerInfo (sphere-sdk type).
1430
+ *
1431
+ * `network` IS DELIBERATELY ABSENT HERE — a live limitation, not an oversight
1432
+ * (#734). `queryBindingByNametag`/`queryBindingByAddress` are the whole public
1433
+ * resolution API for `@nametag` and `DIRECT://`, and both hardcode
1434
+ * `parseBindingInfo` inside the SDK's PRIVATE `queryWithFirstSeenWins`: the
1435
+ * caller never sees the signed event that resolution selected, and the parse
1436
+ * has already dropped every content field outside its whitelist. Re-querying
1437
+ * raw would mean re-deriving UNIP-01 ownership ourselves (marker preference,
1438
+ * cross-author first-seen-wins, ambiguity→null, multi-relay settle — all
1439
+ * private), and a second resolver that can disagree with the SDK's is worse
1440
+ * than a missing field on a MONEY guard. Nothing can declare a network today
1441
+ * regardless: the publish builders whitelist the same fields.
1442
+ *
1443
+ * CONSEQUENCE, stated plainly: for `@nametag` and `DIRECT://` recipients the
1444
+ * §5.6 cross-network guard can only SIGNAL (`recipient:network-unverified`),
1445
+ * never refuse. Upstream #734 must add `network` to the binding builders AND
1446
+ * to `BindingInfo`; the tripwire in
1447
+ * tests/unit/payments-v2/recipient-network.transport.test.ts fails the day it
1448
+ * lands, so this wiring cannot be forgotten. Do not "fix" this by inventing a
1449
+ * value — a stamped network is what made the guard unfalsifiable (#733).
1421
1450
  */
1422
1451
  async bindingInfoToPeerInfo(binding, nametag) {
1423
1452
  return {
@@ -1444,11 +1473,13 @@ var NostrTransportProvider = class _NostrTransportProvider {
1444
1473
  const bindingEvent = events[0];
1445
1474
  try {
1446
1475
  const content = JSON.parse(bindingEvent.content);
1476
+ const network = declaredNetwork(bindingEvent);
1447
1477
  return {
1448
1478
  nametag: content.nametag || void 0,
1449
1479
  transportPubkey: bindingEvent.pubkey,
1450
1480
  chainPubkey: content.public_key || "",
1451
1481
  directAddress: content.direct_address || "",
1482
+ ...network !== void 0 ? { network } : {},
1452
1483
  timestamp: bindingEvent.created_at * 1e3
1453
1484
  };
1454
1485
  } catch {
@@ -1484,11 +1515,13 @@ var NostrTransportProvider = class _NostrTransportProvider {
1484
1515
  for (const [pubkey, event] of byAuthor) {
1485
1516
  try {
1486
1517
  const content = JSON.parse(event.content);
1518
+ const network = declaredNetwork(event);
1487
1519
  results.push({
1488
1520
  nametag: content.nametag || void 0,
1489
1521
  transportPubkey: pubkey,
1490
1522
  chainPubkey: content.public_key || "",
1491
1523
  directAddress: content.direct_address || "",
1524
+ ...network !== void 0 ? { network } : {},
1492
1525
  timestamp: event.created_at * 1e3
1493
1526
  });
1494
1527
  } catch {
@@ -12081,6 +12114,31 @@ function distinctOpCount(entries) {
12081
12114
  return new Set(entries.map((entry) => entry.opIndex)).size;
12082
12115
  }
12083
12116
 
12117
+ // modules/payments-v2/recipient.ts
12118
+ var ATTENTION_RECIPIENT_NETWORK_UNVERIFIED = "recipient:network-unverified";
12119
+ async function requireSameNetworkRecipient(deps, identifier) {
12120
+ const recipient = await deps.resolveRecipient(identifier);
12121
+ if (recipient === null || recipient.chainPubkey === "") {
12122
+ throw new SphereError(`Recipient ${identifier} has no published chain pubkey`, "INVALID_RECIPIENT");
12123
+ }
12124
+ if (recipient.network === null) {
12125
+ deps.emit("transfer:attention", {
12126
+ transferId: "",
12127
+ // the gate precedes plan allocation — no transferId exists yet
12128
+ code: ATTENTION_RECIPIENT_NETWORK_UNVERIFIED,
12129
+ detail: `could not verify the network of recipient ${identifier} \u2014 assuming this session's "${deps.network}"`
12130
+ });
12131
+ return recipient;
12132
+ }
12133
+ if (recipient.network !== deps.network) {
12134
+ throw new SphereError(
12135
+ `Recipient ${identifier} is on network "${recipient.network}" but this session is on "${deps.network}" \u2014 a cross-network deposit is unrecoverable`,
12136
+ "INVALID_RECIPIENT"
12137
+ );
12138
+ }
12139
+ return recipient;
12140
+ }
12141
+
12084
12142
  // modules/payments-v2/restore.ts
12085
12143
  var ATTENTION_RESEED_REJECTED = "intent:reseed-rejected";
12086
12144
  var ALL_STREAMS = ["inventory", "mailbox", "payment_requests", "history"];
@@ -13673,6 +13731,10 @@ var PaymentsFacade = class {
13673
13731
  history(page) {
13674
13732
  return this.historyStore.page(page ?? {});
13675
13733
  }
13734
+ /** §4: read through to the session — the same value `connection:status` carries (sphere#473). No session ⇒ 'offline'. */
13735
+ connectionStatus() {
13736
+ return this.started ? this.deps.session.status() : "offline";
13737
+ }
13676
13738
  /** §4 pending-transfers UI surface — derived on read, never cached (convergence.ts). */
13677
13739
  pendingTransfers() {
13678
13740
  return derivePendingTransfers(this.machineStores, this.machineDeps.decryptPayload);
@@ -13747,7 +13809,7 @@ var PaymentsFacade = class {
13747
13809
  this.deps.emit("transfer:updated", failed);
13748
13810
  }
13749
13811
  async sendWithPolicy(request, run) {
13750
- const recipient = await this.requireSameNetworkRecipient(request.recipient);
13812
+ const recipient = await requireSameNetworkRecipient(this.deps, request.recipient);
13751
13813
  for (let attempt = 0; ; attempt++) {
13752
13814
  let ctx;
13753
13815
  try {
@@ -13770,20 +13832,6 @@ var PaymentsFacade = class {
13770
13832
  if (surfaced !== null) return surfaced;
13771
13833
  }
13772
13834
  }
13773
- /** §5.6 cross-network deposit trap: refused BEFORE any reserve/certification. */
13774
- async requireSameNetworkRecipient(identifier) {
13775
- const recipient = await this.deps.resolveRecipient(identifier);
13776
- if (recipient === null || recipient.chainPubkey === "") {
13777
- throw new SphereError(`Recipient ${identifier} has no published chain pubkey`, "INVALID_RECIPIENT");
13778
- }
13779
- if (recipient.network !== this.deps.network) {
13780
- throw new SphereError(
13781
- `Recipient ${identifier} is on network "${recipient.network}" but this session is on "${this.deps.network}" \u2014 a cross-network deposit is unrecoverable`,
13782
- "INVALID_RECIPIENT"
13783
- );
13784
- }
13785
- return recipient;
13786
- }
13787
13835
  async runAttempt(ctx) {
13788
13836
  this.activeMoneyOps.add(ctx.transferId);
13789
13837
  try {
@@ -14160,19 +14208,12 @@ var PaymentsFacade = class {
14160
14208
  }
14161
14209
  toUiToken(tokenId, coinId, amount) {
14162
14210
  const now = this.nowMs();
14163
- return toToken(
14164
- tokenId,
14165
- { assets: [], createdAt: now, updatedAt: now },
14166
- { coinId, amount: amount.toString() },
14167
- this.deps.registry,
14168
- { transferring: true, suspectedSpent: false }
14169
- );
14211
+ const snapshot = { assets: [], createdAt: now, updatedAt: now };
14212
+ const flags = { transferring: true, suspectedSpent: false };
14213
+ return toToken(tokenId, snapshot, { coinId, amount: amount.toString() }, this.deps.registry, flags);
14170
14214
  }
14171
14215
  track(op) {
14172
- const settled = op.then(
14173
- () => void 0,
14174
- () => void 0
14175
- );
14216
+ const settled = op.then(() => void 0, () => void 0);
14176
14217
  this.pendingOps.add(settled);
14177
14218
  void settled.finally(() => this.pendingOps.delete(settled));
14178
14219
  return op;
@@ -15273,7 +15314,8 @@ async function resolveRecipientInfo(identifier, network, resolvePeer) {
15273
15314
  if (!peer?.chainPubkey) return null;
15274
15315
  return {
15275
15316
  chainPubkey: peer.chainPubkey,
15276
- network,
15317
+ // Only what the binding declares (blank declares nothing) — never a local stamp.
15318
+ network: peer.network || null,
15277
15319
  ...peer.nametag !== void 0 ? { nametag: peer.nametag } : {}
15278
15320
  };
15279
15321
  }