@unicitylabs/sphere-sdk 0.5.3 → 0.5.5

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 (50) hide show
  1. package/README.md +2 -0
  2. package/dist/connect/index.cjs +145 -23
  3. package/dist/connect/index.cjs.map +1 -1
  4. package/dist/connect/index.d.cts +15 -2
  5. package/dist/connect/index.d.ts +15 -2
  6. package/dist/connect/index.js +145 -23
  7. package/dist/connect/index.js.map +1 -1
  8. package/dist/core/index.cjs +670 -473
  9. package/dist/core/index.cjs.map +1 -1
  10. package/dist/core/index.d.cts +123 -2
  11. package/dist/core/index.d.ts +123 -2
  12. package/dist/core/index.js +667 -473
  13. package/dist/core/index.js.map +1 -1
  14. package/dist/impl/browser/connect/index.cjs +119 -1
  15. package/dist/impl/browser/connect/index.cjs.map +1 -1
  16. package/dist/impl/browser/connect/index.d.cts +53 -1
  17. package/dist/impl/browser/connect/index.d.ts +53 -1
  18. package/dist/impl/browser/connect/index.js +119 -1
  19. package/dist/impl/browser/connect/index.js.map +1 -1
  20. package/dist/impl/browser/index.cjs +306 -193
  21. package/dist/impl/browser/index.cjs.map +1 -1
  22. package/dist/impl/browser/index.js +306 -193
  23. package/dist/impl/browser/index.js.map +1 -1
  24. package/dist/impl/browser/ipfs.cjs +134 -19
  25. package/dist/impl/browser/ipfs.cjs.map +1 -1
  26. package/dist/impl/browser/ipfs.js +134 -19
  27. package/dist/impl/browser/ipfs.js.map +1 -1
  28. package/dist/impl/nodejs/connect/index.cjs +101 -6
  29. package/dist/impl/nodejs/connect/index.cjs.map +1 -1
  30. package/dist/impl/nodejs/connect/index.d.cts +2 -0
  31. package/dist/impl/nodejs/connect/index.d.ts +2 -0
  32. package/dist/impl/nodejs/connect/index.js +101 -6
  33. package/dist/impl/nodejs/connect/index.js.map +1 -1
  34. package/dist/impl/nodejs/index.cjs +267 -152
  35. package/dist/impl/nodejs/index.cjs.map +1 -1
  36. package/dist/impl/nodejs/index.d.cts +2 -1
  37. package/dist/impl/nodejs/index.d.ts +2 -1
  38. package/dist/impl/nodejs/index.js +267 -152
  39. package/dist/impl/nodejs/index.js.map +1 -1
  40. package/dist/index.cjs +682 -493
  41. package/dist/index.cjs.map +1 -1
  42. package/dist/index.d.cts +124 -8
  43. package/dist/index.d.ts +124 -8
  44. package/dist/index.js +680 -493
  45. package/dist/index.js.map +1 -1
  46. package/dist/l1/index.cjs +139 -32
  47. package/dist/l1/index.cjs.map +1 -1
  48. package/dist/l1/index.js +139 -32
  49. package/dist/l1/index.js.map +1 -1
  50. package/package.json +1 -16
@@ -1059,6 +1059,18 @@ import * as bip39 from "bip39";
1059
1059
  import CryptoJS from "crypto-js";
1060
1060
  import elliptic from "elliptic";
1061
1061
 
1062
+ // core/errors.ts
1063
+ var SphereError = class extends Error {
1064
+ code;
1065
+ cause;
1066
+ constructor(message, code, cause) {
1067
+ super(message);
1068
+ this.name = "SphereError";
1069
+ this.code = code;
1070
+ this.cause = cause;
1071
+ }
1072
+ };
1073
+
1062
1074
  // core/bech32.ts
1063
1075
  var CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
1064
1076
  var GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
@@ -1115,11 +1127,11 @@ function bech32Checksum(hrp, data) {
1115
1127
  }
1116
1128
  function encodeBech32(hrp, version, program) {
1117
1129
  if (version < 0 || version > 16) {
1118
- throw new Error("Invalid witness version");
1130
+ throw new SphereError("Invalid witness version", "VALIDATION_ERROR");
1119
1131
  }
1120
1132
  const converted = convertBits(Array.from(program), 8, 5, true);
1121
1133
  if (!converted) {
1122
- throw new Error("Failed to convert bits");
1134
+ throw new SphereError("Failed to convert bits", "VALIDATION_ERROR");
1123
1135
  }
1124
1136
  const data = [version].concat(converted);
1125
1137
  const checksum = bech32Checksum(hrp, data);
@@ -1170,6 +1182,98 @@ function hexToBytes2(hex) {
1170
1182
  return Uint8Array.from(matches.map((x) => parseInt(x, 16)));
1171
1183
  }
1172
1184
 
1185
+ // core/logger.ts
1186
+ var LOGGER_KEY = "__sphere_sdk_logger__";
1187
+ function getState() {
1188
+ const g = globalThis;
1189
+ if (!g[LOGGER_KEY]) {
1190
+ g[LOGGER_KEY] = { debug: false, tags: {}, handler: null };
1191
+ }
1192
+ return g[LOGGER_KEY];
1193
+ }
1194
+ function isEnabled(tag) {
1195
+ const state = getState();
1196
+ if (tag in state.tags) return state.tags[tag];
1197
+ return state.debug;
1198
+ }
1199
+ var logger = {
1200
+ /**
1201
+ * Configure the logger. Can be called multiple times (last write wins).
1202
+ * Typically called by createBrowserProviders(), createNodeProviders(), or Sphere.init().
1203
+ */
1204
+ configure(config) {
1205
+ const state = getState();
1206
+ if (config.debug !== void 0) state.debug = config.debug;
1207
+ if (config.handler !== void 0) state.handler = config.handler;
1208
+ },
1209
+ /**
1210
+ * Enable/disable debug logging for a specific tag.
1211
+ * Per-tag setting overrides the global debug flag.
1212
+ *
1213
+ * @example
1214
+ * ```ts
1215
+ * logger.setTagDebug('Nostr', true); // enable only Nostr logs
1216
+ * logger.setTagDebug('Nostr', false); // disable Nostr logs even if global debug=true
1217
+ * ```
1218
+ */
1219
+ setTagDebug(tag, enabled) {
1220
+ getState().tags[tag] = enabled;
1221
+ },
1222
+ /**
1223
+ * Clear per-tag override, falling back to global debug flag.
1224
+ */
1225
+ clearTagDebug(tag) {
1226
+ delete getState().tags[tag];
1227
+ },
1228
+ /** Returns true if debug mode is enabled for the given tag (or globally). */
1229
+ isDebugEnabled(tag) {
1230
+ if (tag) return isEnabled(tag);
1231
+ return getState().debug;
1232
+ },
1233
+ /**
1234
+ * Debug-level log. Only shown when debug is enabled (globally or for this tag).
1235
+ * Use for detailed operational information.
1236
+ */
1237
+ debug(tag, message, ...args) {
1238
+ if (!isEnabled(tag)) return;
1239
+ const state = getState();
1240
+ if (state.handler) {
1241
+ state.handler("debug", tag, message, ...args);
1242
+ } else {
1243
+ console.log(`[${tag}]`, message, ...args);
1244
+ }
1245
+ },
1246
+ /**
1247
+ * Warning-level log. ALWAYS shown regardless of debug flag.
1248
+ * Use for important but non-critical issues (timeouts, retries, degraded state).
1249
+ */
1250
+ warn(tag, message, ...args) {
1251
+ const state = getState();
1252
+ if (state.handler) {
1253
+ state.handler("warn", tag, message, ...args);
1254
+ } else {
1255
+ console.warn(`[${tag}]`, message, ...args);
1256
+ }
1257
+ },
1258
+ /**
1259
+ * Error-level log. ALWAYS shown regardless of debug flag.
1260
+ * Use for critical failures that should never be silenced.
1261
+ */
1262
+ error(tag, message, ...args) {
1263
+ const state = getState();
1264
+ if (state.handler) {
1265
+ state.handler("error", tag, message, ...args);
1266
+ } else {
1267
+ console.error(`[${tag}]`, message, ...args);
1268
+ }
1269
+ },
1270
+ /** Reset all logger state (debug flag, tags, handler). Primarily for tests. */
1271
+ reset() {
1272
+ const g = globalThis;
1273
+ delete g[LOGGER_KEY];
1274
+ }
1275
+ };
1276
+
1173
1277
  // transport/websocket.ts
1174
1278
  var WebSocketReadyState = {
1175
1279
  CONNECTING: 0,
@@ -1312,18 +1416,18 @@ var NostrTransportProvider = class {
1312
1416
  });
1313
1417
  this.nostrClient.addConnectionListener({
1314
1418
  onConnect: (url) => {
1315
- this.log("NostrClient connected to relay:", url);
1419
+ logger.debug("Nostr", "NostrClient connected to relay:", url);
1316
1420
  this.emitEvent({ type: "transport:connected", timestamp: Date.now() });
1317
1421
  },
1318
1422
  onDisconnect: (url, reason) => {
1319
- this.log("NostrClient disconnected from relay:", url, "reason:", reason);
1423
+ logger.debug("Nostr", "NostrClient disconnected from relay:", url, "reason:", reason);
1320
1424
  },
1321
1425
  onReconnecting: (url, attempt) => {
1322
- this.log("NostrClient reconnecting to relay:", url, "attempt:", attempt);
1426
+ logger.debug("Nostr", "NostrClient reconnecting to relay:", url, "attempt:", attempt);
1323
1427
  this.emitEvent({ type: "transport:reconnecting", timestamp: Date.now() });
1324
1428
  },
1325
1429
  onReconnected: (url) => {
1326
- this.log("NostrClient reconnected to relay:", url);
1430
+ logger.debug("Nostr", "NostrClient reconnected to relay:", url);
1327
1431
  this.emitEvent({ type: "transport:connected", timestamp: Date.now() });
1328
1432
  }
1329
1433
  });
@@ -1336,11 +1440,11 @@ var NostrTransportProvider = class {
1336
1440
  )
1337
1441
  ]);
1338
1442
  if (!this.nostrClient.isConnected()) {
1339
- throw new Error("Failed to connect to any relay");
1443
+ throw new SphereError("Failed to connect to any relay", "TRANSPORT_ERROR");
1340
1444
  }
1341
1445
  this.status = "connected";
1342
1446
  this.emitEvent({ type: "transport:connected", timestamp: Date.now() });
1343
- this.log("Connected to", this.nostrClient.getConnectedRelays().size, "relays");
1447
+ logger.debug("Nostr", "Connected to", this.nostrClient.getConnectedRelays().size, "relays");
1344
1448
  if (this.identity) {
1345
1449
  await this.subscribeToEvents();
1346
1450
  }
@@ -1359,7 +1463,7 @@ var NostrTransportProvider = class {
1359
1463
  this.chatSubscriptionId = null;
1360
1464
  this.status = "disconnected";
1361
1465
  this.emitEvent({ type: "transport:disconnected", timestamp: Date.now() });
1362
- this.log("Disconnected from all relays");
1466
+ logger.debug("Nostr", "Disconnected from all relays");
1363
1467
  }
1364
1468
  isConnected() {
1365
1469
  return this.status === "connected" && this.nostrClient?.isConnected() === true;
@@ -1389,14 +1493,14 @@ var NostrTransportProvider = class {
1389
1493
  */
1390
1494
  async addRelay(relayUrl) {
1391
1495
  if (this.config.relays.includes(relayUrl)) {
1392
- this.log("Relay already configured:", relayUrl);
1496
+ logger.debug("Nostr", "Relay already configured:", relayUrl);
1393
1497
  return false;
1394
1498
  }
1395
1499
  this.config.relays.push(relayUrl);
1396
1500
  if (this.status === "connected" && this.nostrClient) {
1397
1501
  try {
1398
1502
  await this.nostrClient.connect(relayUrl);
1399
- this.log("Added and connected to relay:", relayUrl);
1503
+ logger.debug("Nostr", "Added and connected to relay:", relayUrl);
1400
1504
  this.emitEvent({
1401
1505
  type: "transport:relay_added",
1402
1506
  timestamp: Date.now(),
@@ -1404,7 +1508,7 @@ var NostrTransportProvider = class {
1404
1508
  });
1405
1509
  return true;
1406
1510
  } catch (error) {
1407
- this.log("Failed to connect to new relay:", relayUrl, error);
1511
+ logger.debug("Nostr", "Failed to connect to new relay:", relayUrl, error);
1408
1512
  this.emitEvent({
1409
1513
  type: "transport:relay_added",
1410
1514
  timestamp: Date.now(),
@@ -1429,11 +1533,11 @@ var NostrTransportProvider = class {
1429
1533
  async removeRelay(relayUrl) {
1430
1534
  const index = this.config.relays.indexOf(relayUrl);
1431
1535
  if (index === -1) {
1432
- this.log("Relay not found:", relayUrl);
1536
+ logger.debug("Nostr", "Relay not found:", relayUrl);
1433
1537
  return false;
1434
1538
  }
1435
1539
  this.config.relays.splice(index, 1);
1436
- this.log("Removed relay from config:", relayUrl);
1540
+ logger.debug("Nostr", "Removed relay from config:", relayUrl);
1437
1541
  this.emitEvent({
1438
1542
  type: "transport:relay_removed",
1439
1543
  timestamp: Date.now(),
@@ -1470,9 +1574,9 @@ var NostrTransportProvider = class {
1470
1574
  const secretKey = Buffer2.from(identity.privateKey, "hex");
1471
1575
  this.keyManager = NostrKeyManager.fromPrivateKey(secretKey);
1472
1576
  const nostrPubkey = this.keyManager.getPublicKeyHex();
1473
- this.log("Identity set, Nostr pubkey:", nostrPubkey.slice(0, 16) + "...");
1577
+ logger.debug("Nostr", "Identity set, Nostr pubkey:", nostrPubkey.slice(0, 16) + "...");
1474
1578
  if (this.nostrClient && this.status === "connected") {
1475
- this.log("Identity changed while connected - recreating NostrClient");
1579
+ logger.debug("Nostr", "Identity changed while connected - recreating NostrClient");
1476
1580
  const oldClient = this.nostrClient;
1477
1581
  this.nostrClient = new NostrClient(this.keyManager, {
1478
1582
  autoReconnect: this.config.autoReconnect,
@@ -1483,16 +1587,16 @@ var NostrTransportProvider = class {
1483
1587
  });
1484
1588
  this.nostrClient.addConnectionListener({
1485
1589
  onConnect: (url) => {
1486
- this.log("NostrClient connected to relay:", url);
1590
+ logger.debug("Nostr", "NostrClient connected to relay:", url);
1487
1591
  },
1488
1592
  onDisconnect: (url, reason) => {
1489
- this.log("NostrClient disconnected from relay:", url, "reason:", reason);
1593
+ logger.debug("Nostr", "NostrClient disconnected from relay:", url, "reason:", reason);
1490
1594
  },
1491
1595
  onReconnecting: (url, attempt) => {
1492
- this.log("NostrClient reconnecting to relay:", url, "attempt:", attempt);
1596
+ logger.debug("Nostr", "NostrClient reconnecting to relay:", url, "attempt:", attempt);
1493
1597
  },
1494
1598
  onReconnected: (url) => {
1495
- this.log("NostrClient reconnected to relay:", url);
1599
+ logger.debug("Nostr", "NostrClient reconnected to relay:", url);
1496
1600
  }
1497
1601
  });
1498
1602
  await Promise.race([
@@ -1515,7 +1619,7 @@ var NostrTransportProvider = class {
1515
1619
  */
1516
1620
  getNostrPubkey() {
1517
1621
  if (!this.keyManager) {
1518
- throw new Error("KeyManager not initialized - call setIdentity first");
1622
+ throw new SphereError("KeyManager not initialized - call setIdentity first", "NOT_INITIALIZED");
1519
1623
  }
1520
1624
  return this.keyManager.getPublicKeyHex();
1521
1625
  }
@@ -1536,7 +1640,7 @@ var NostrTransportProvider = class {
1536
1640
  const selfPubkey = this.keyManager.getPublicKeyHex();
1537
1641
  const selfGiftWrap = NIP17.createGiftWrap(this.keyManager, selfPubkey, selfWrapContent);
1538
1642
  this.publishEvent(selfGiftWrap).catch((err) => {
1539
- this.log("Self-wrap publish failed:", err);
1643
+ logger.debug("Nostr", "Self-wrap publish failed:", err);
1540
1644
  });
1541
1645
  this.emitEvent({
1542
1646
  type: "message:sent",
@@ -1550,12 +1654,12 @@ var NostrTransportProvider = class {
1550
1654
  if (this.pendingMessages.length > 0) {
1551
1655
  const pending = this.pendingMessages;
1552
1656
  this.pendingMessages = [];
1553
- this.log("Flushing", pending.length, "buffered messages to new handler");
1657
+ logger.debug("Nostr", "Flushing", pending.length, "buffered messages to new handler");
1554
1658
  for (const message of pending) {
1555
1659
  try {
1556
1660
  handler(message);
1557
1661
  } catch (error) {
1558
- this.log("Message handler error (buffered):", error);
1662
+ logger.debug("Nostr", "Message handler error (buffered):", error);
1559
1663
  }
1560
1664
  }
1561
1665
  }
@@ -1614,7 +1718,7 @@ var NostrTransportProvider = class {
1614
1718
  tags
1615
1719
  );
1616
1720
  await this.publishEvent(event);
1617
- this.log("Sent payment request:", event.id);
1721
+ logger.debug("Nostr", "Sent payment request:", event.id);
1618
1722
  return event.id;
1619
1723
  }
1620
1724
  onPaymentRequest(handler) {
@@ -1642,7 +1746,7 @@ var NostrTransportProvider = class {
1642
1746
  ]
1643
1747
  );
1644
1748
  await this.publishEvent(event);
1645
- this.log("Sent payment request response:", event.id, "type:", payload.responseType);
1749
+ logger.debug("Nostr", "Sent payment request response:", event.id, "type:", payload.responseType);
1646
1750
  return event.id;
1647
1751
  }
1648
1752
  onPaymentRequestResponse(handler) {
@@ -1653,11 +1757,11 @@ var NostrTransportProvider = class {
1653
1757
  // Read Receipts
1654
1758
  // ===========================================================================
1655
1759
  async sendReadReceipt(recipientTransportPubkey, messageEventId) {
1656
- if (!this.keyManager) throw new Error("Not initialized");
1760
+ if (!this.keyManager) throw new SphereError("Not initialized", "NOT_INITIALIZED");
1657
1761
  const nostrRecipient = recipientTransportPubkey.length === 66 ? recipientTransportPubkey.slice(2) : recipientTransportPubkey;
1658
1762
  const event = NIP17.createReadReceipt(this.keyManager, nostrRecipient, messageEventId);
1659
1763
  await this.publishEvent(event);
1660
- this.log("Sent read receipt for:", messageEventId, "to:", nostrRecipient.slice(0, 16));
1764
+ logger.debug("Nostr", "Sent read receipt for:", messageEventId, "to:", nostrRecipient.slice(0, 16));
1661
1765
  }
1662
1766
  onReadReceipt(handler) {
1663
1767
  this.readReceiptHandlers.add(handler);
@@ -1667,7 +1771,7 @@ var NostrTransportProvider = class {
1667
1771
  // Typing Indicators
1668
1772
  // ===========================================================================
1669
1773
  async sendTypingIndicator(recipientTransportPubkey) {
1670
- if (!this.keyManager) throw new Error("Not initialized");
1774
+ if (!this.keyManager) throw new SphereError("Not initialized", "NOT_INITIALIZED");
1671
1775
  const nostrRecipient = recipientTransportPubkey.length === 66 ? recipientTransportPubkey.slice(2) : recipientTransportPubkey;
1672
1776
  const content = JSON.stringify({
1673
1777
  type: "typing",
@@ -1754,7 +1858,10 @@ var NostrTransportProvider = class {
1754
1858
  limit: 1
1755
1859
  });
1756
1860
  }
1757
- if (events.length === 0) return null;
1861
+ if (events.length === 0) {
1862
+ logger.debug("Nostr", `resolveNametagInfo: no binding events found for nametag "${nametag}"`);
1863
+ return null;
1864
+ }
1758
1865
  const bindingEvent = events[0];
1759
1866
  try {
1760
1867
  const content = JSON.parse(bindingEvent.content);
@@ -1772,7 +1879,7 @@ var NostrTransportProvider = class {
1772
1879
  timestamp: bindingEvent.created_at * 1e3
1773
1880
  };
1774
1881
  }
1775
- this.log("Legacy nametag event without extended fields:", nametag);
1882
+ logger.debug("Nostr", "Legacy nametag event without extended fields:", nametag);
1776
1883
  const pubkeyTag = bindingEvent.tags.find((t) => t[0] === "pubkey");
1777
1884
  const l1Tag = bindingEvent.tags.find((t) => t[0] === "l1");
1778
1885
  if (pubkeyTag?.[1] && l1Tag?.[1]) {
@@ -1928,10 +2035,10 @@ var NostrTransportProvider = class {
1928
2035
  async recoverNametag() {
1929
2036
  this.ensureReady();
1930
2037
  if (!this.identity || !this.keyManager) {
1931
- throw new Error("Identity not set");
2038
+ throw new SphereError("Identity not set", "NOT_INITIALIZED");
1932
2039
  }
1933
2040
  const nostrPubkey = this.getNostrPubkey();
1934
- this.log("Searching for nametag events for pubkey:", nostrPubkey.slice(0, 16) + "...");
2041
+ logger.debug("Nostr", "Searching for nametag events for pubkey:", nostrPubkey.slice(0, 16) + "...");
1935
2042
  const events = await this.queryEvents({
1936
2043
  kinds: [EVENT_KINDS.NAMETAG_BINDING],
1937
2044
  authors: [nostrPubkey],
@@ -1939,7 +2046,7 @@ var NostrTransportProvider = class {
1939
2046
  // Get recent events in case of updates
1940
2047
  });
1941
2048
  if (events.length === 0) {
1942
- this.log("No nametag events found for this pubkey");
2049
+ logger.debug("Nostr", "No nametag events found for this pubkey");
1943
2050
  return null;
1944
2051
  }
1945
2052
  events.sort((a, b) => b.created_at - a.created_at);
@@ -1952,7 +2059,7 @@ var NostrTransportProvider = class {
1952
2059
  this.identity.privateKey
1953
2060
  );
1954
2061
  if (decrypted) {
1955
- this.log("Recovered nametag:", decrypted);
2062
+ logger.debug("Nostr", "Recovered nametag:", decrypted);
1956
2063
  return decrypted;
1957
2064
  }
1958
2065
  }
@@ -1960,7 +2067,7 @@ var NostrTransportProvider = class {
1960
2067
  continue;
1961
2068
  }
1962
2069
  }
1963
- this.log("Could not decrypt nametag from any event");
2070
+ logger.debug("Nostr", "Could not decrypt nametag from any event");
1964
2071
  return null;
1965
2072
  }
1966
2073
  /**
@@ -1976,7 +2083,7 @@ var NostrTransportProvider = class {
1976
2083
  async publishIdentityBinding(chainPubkey, l1Address, directAddress, nametag) {
1977
2084
  this.ensureReady();
1978
2085
  if (!this.identity) {
1979
- throw new Error("Identity not set");
2086
+ throw new SphereError("Identity not set", "NOT_INITIALIZED");
1980
2087
  }
1981
2088
  const nostrPubkey = this.getNostrPubkey();
1982
2089
  const dTagBytes = new TextEncoder().encode("unicity:identity:" + nostrPubkey);
@@ -1995,7 +2102,7 @@ var NostrTransportProvider = class {
1995
2102
  if (nametag) {
1996
2103
  const existing = await this.resolveNametag(nametag);
1997
2104
  if (existing && existing !== nostrPubkey) {
1998
- this.log("Nametag already taken:", nametag, "- owner:", existing);
2105
+ logger.debug("Nostr", "Nametag already taken:", nametag, "- owner:", existing);
1999
2106
  return false;
2000
2107
  }
2001
2108
  const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
@@ -2013,9 +2120,9 @@ var NostrTransportProvider = class {
2013
2120
  const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, content, tags);
2014
2121
  await this.publishEvent(event);
2015
2122
  if (nametag) {
2016
- this.log("Published identity binding with nametag:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...");
2123
+ logger.debug("Nostr", "Published identity binding with nametag:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...");
2017
2124
  } else {
2018
- this.log("Published identity binding (no nametag) for pubkey:", nostrPubkey.slice(0, 16) + "...");
2125
+ logger.debug("Nostr", "Published identity binding (no nametag) for pubkey:", nostrPubkey.slice(0, 16) + "...");
2019
2126
  }
2020
2127
  return true;
2021
2128
  }
@@ -2028,18 +2135,18 @@ var NostrTransportProvider = class {
2028
2135
  ["a", address]
2029
2136
  ]);
2030
2137
  await this.publishEvent(event);
2031
- this.log("Published nametag binding:", nametag);
2138
+ logger.debug("Nostr", "Published nametag binding:", nametag);
2032
2139
  }
2033
2140
  async registerNametag(nametag, _publicKey, directAddress = "") {
2034
2141
  this.ensureReady();
2035
2142
  if (!this.identity) {
2036
- throw new Error("Identity not set");
2143
+ throw new SphereError("Identity not set", "NOT_INITIALIZED");
2037
2144
  }
2038
2145
  const nostrPubkey = this.getNostrPubkey();
2039
2146
  const existing = await this.resolveNametag(nametag);
2040
- this.log("registerNametag:", nametag, "existing:", existing, "myPubkey:", nostrPubkey);
2147
+ logger.debug("Nostr", "registerNametag:", nametag, "existing:", existing, "myPubkey:", nostrPubkey);
2041
2148
  if (existing && existing !== nostrPubkey) {
2042
- this.log("Nametag already taken:", nametag, "- owner:", existing);
2149
+ logger.debug("Nostr", "Nametag already taken:", nametag, "- owner:", existing);
2043
2150
  return false;
2044
2151
  }
2045
2152
  const privateKeyHex = this.identity.privateKey;
@@ -2073,7 +2180,7 @@ var NostrTransportProvider = class {
2073
2180
  ];
2074
2181
  const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, content, tags);
2075
2182
  await this.publishEvent(event);
2076
- this.log("Registered nametag:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...", "l1:", l1Address.slice(0, 12) + "...");
2183
+ logger.debug("Nostr", "Registered nametag:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...", "l1:", l1Address.slice(0, 12) + "...");
2077
2184
  return true;
2078
2185
  }
2079
2186
  // Track broadcast subscriptions
@@ -2124,14 +2231,14 @@ var NostrTransportProvider = class {
2124
2231
  if (event.id) {
2125
2232
  this.processedEventIds.add(event.id);
2126
2233
  }
2127
- this.log("Processing event kind:", event.kind, "id:", event.id?.slice(0, 12));
2234
+ logger.debug("Nostr", "Processing event kind:", event.kind, "id:", event.id?.slice(0, 12));
2128
2235
  try {
2129
2236
  switch (event.kind) {
2130
2237
  case EVENT_KINDS.DIRECT_MESSAGE:
2131
2238
  await this.handleDirectMessage(event);
2132
2239
  break;
2133
2240
  case EventKinds.GIFT_WRAP:
2134
- this.log("Handling gift wrap (NIP-17 DM)");
2241
+ logger.debug("Nostr", "Handling gift wrap (NIP-17 DM)");
2135
2242
  await this.handleGiftWrap(event);
2136
2243
  break;
2137
2244
  case EVENT_KINDS.TOKEN_TRANSFER:
@@ -2154,7 +2261,7 @@ var NostrTransportProvider = class {
2154
2261
  }
2155
2262
  }
2156
2263
  } catch (error) {
2157
- this.log("Failed to handle event:", error);
2264
+ logger.debug("Nostr", "Failed to handle event:", error);
2158
2265
  }
2159
2266
  }
2160
2267
  /**
@@ -2169,25 +2276,25 @@ var NostrTransportProvider = class {
2169
2276
  const pubkey = this.keyManager.getPublicKeyHex();
2170
2277
  const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_WALLET_EVENT_TS}_${pubkey.slice(0, 16)}`;
2171
2278
  this.storage.set(storageKey, createdAt.toString()).catch((err) => {
2172
- this.log("Failed to save last event timestamp:", err);
2279
+ logger.debug("Nostr", "Failed to save last event timestamp:", err);
2173
2280
  });
2174
2281
  }
2175
2282
  async handleDirectMessage(event) {
2176
- this.log("Ignoring NIP-04 kind 4 event (DMs use NIP-17):", event.id?.slice(0, 12));
2283
+ logger.debug("Nostr", "Ignoring NIP-04 kind 4 event (DMs use NIP-17):", event.id?.slice(0, 12));
2177
2284
  }
2178
2285
  async handleGiftWrap(event) {
2179
2286
  if (!this.identity || !this.keyManager) {
2180
- this.log("handleGiftWrap: no identity/keyManager");
2287
+ logger.debug("Nostr", "handleGiftWrap: no identity/keyManager");
2181
2288
  return;
2182
2289
  }
2183
2290
  try {
2184
2291
  const pm = NIP17.unwrap(event, this.keyManager);
2185
- this.log("Gift wrap unwrapped, sender:", pm.senderPubkey?.slice(0, 16), "kind:", pm.kind);
2292
+ logger.debug("Nostr", "Gift wrap unwrapped, sender:", pm.senderPubkey?.slice(0, 16), "kind:", pm.kind);
2186
2293
  if (pm.senderPubkey === this.keyManager.getPublicKeyHex()) {
2187
2294
  try {
2188
2295
  const parsed = JSON.parse(pm.content);
2189
2296
  if (parsed?.selfWrap && parsed.recipientPubkey) {
2190
- this.log("Self-wrap replay for recipient:", parsed.recipientPubkey?.slice(0, 16));
2297
+ logger.debug("Nostr", "Self-wrap replay for recipient:", parsed.recipientPubkey?.slice(0, 16));
2191
2298
  const message2 = {
2192
2299
  id: parsed.originalId || pm.eventId,
2193
2300
  senderTransportPubkey: pm.senderPubkey,
@@ -2202,18 +2309,18 @@ var NostrTransportProvider = class {
2202
2309
  try {
2203
2310
  handler(message2);
2204
2311
  } catch (e) {
2205
- this.log("Self-wrap handler error:", e);
2312
+ logger.debug("Nostr", "Self-wrap handler error:", e);
2206
2313
  }
2207
2314
  }
2208
2315
  return;
2209
2316
  }
2210
2317
  } catch {
2211
2318
  }
2212
- this.log("Skipping own non-self-wrap message");
2319
+ logger.debug("Nostr", "Skipping own non-self-wrap message");
2213
2320
  return;
2214
2321
  }
2215
2322
  if (isReadReceipt(pm)) {
2216
- this.log("Read receipt from:", pm.senderPubkey?.slice(0, 16), "for:", pm.replyToEventId);
2323
+ logger.debug("Nostr", "Read receipt from:", pm.senderPubkey?.slice(0, 16), "for:", pm.replyToEventId);
2217
2324
  if (pm.replyToEventId) {
2218
2325
  const receipt = {
2219
2326
  senderTransportPubkey: pm.senderPubkey,
@@ -2224,7 +2331,7 @@ var NostrTransportProvider = class {
2224
2331
  try {
2225
2332
  handler(receipt);
2226
2333
  } catch (e) {
2227
- this.log("Read receipt handler error:", e);
2334
+ logger.debug("Nostr", "Read receipt handler error:", e);
2228
2335
  }
2229
2336
  }
2230
2337
  }
@@ -2244,12 +2351,12 @@ var NostrTransportProvider = class {
2244
2351
  senderNametag: senderNametag2,
2245
2352
  expiresIn
2246
2353
  };
2247
- this.log("Composing indicator from:", indicator.senderNametag || pm.senderPubkey?.slice(0, 16));
2354
+ logger.debug("Nostr", "Composing indicator from:", indicator.senderNametag || pm.senderPubkey?.slice(0, 16));
2248
2355
  for (const handler of this.composingHandlers) {
2249
2356
  try {
2250
2357
  handler(indicator);
2251
2358
  } catch (e) {
2252
- this.log("Composing handler error:", e);
2359
+ logger.debug("Nostr", "Composing handler error:", e);
2253
2360
  }
2254
2361
  }
2255
2362
  return;
@@ -2257,7 +2364,7 @@ var NostrTransportProvider = class {
2257
2364
  try {
2258
2365
  const parsed = JSON.parse(pm.content);
2259
2366
  if (parsed?.type === "typing") {
2260
- this.log("Typing indicator from:", pm.senderPubkey?.slice(0, 16));
2367
+ logger.debug("Nostr", "Typing indicator from:", pm.senderPubkey?.slice(0, 16));
2261
2368
  const indicator = {
2262
2369
  senderTransportPubkey: pm.senderPubkey,
2263
2370
  senderNametag: parsed.senderNametag,
@@ -2267,7 +2374,7 @@ var NostrTransportProvider = class {
2267
2374
  try {
2268
2375
  handler(indicator);
2269
2376
  } catch (e) {
2270
- this.log("Typing handler error:", e);
2377
+ logger.debug("Nostr", "Typing handler error:", e);
2271
2378
  }
2272
2379
  }
2273
2380
  return;
@@ -2275,7 +2382,7 @@ var NostrTransportProvider = class {
2275
2382
  } catch {
2276
2383
  }
2277
2384
  if (!isChatMessage(pm)) {
2278
- this.log("Skipping unknown message kind:", pm.kind);
2385
+ logger.debug("Nostr", "Skipping unknown message kind:", pm.kind);
2279
2386
  return;
2280
2387
  }
2281
2388
  let content = pm.content;
@@ -2288,7 +2395,7 @@ var NostrTransportProvider = class {
2288
2395
  }
2289
2396
  } catch {
2290
2397
  }
2291
- this.log("DM received from:", senderNametag || pm.senderPubkey?.slice(0, 16), "content:", content?.slice(0, 50));
2398
+ logger.debug("Nostr", "DM received from:", senderNametag || pm.senderPubkey?.slice(0, 16), "content:", content?.slice(0, 50));
2292
2399
  const message = {
2293
2400
  // Use outer gift wrap event.id so it matches the sender's stored giftWrap.id.
2294
2401
  // This ensures read receipts reference an ID the sender recognizes.
@@ -2301,20 +2408,20 @@ var NostrTransportProvider = class {
2301
2408
  };
2302
2409
  this.emitEvent({ type: "message:received", timestamp: Date.now() });
2303
2410
  if (this.messageHandlers.size === 0) {
2304
- this.log("No message handlers registered, buffering message for later delivery");
2411
+ logger.debug("Nostr", "No message handlers registered, buffering message for later delivery");
2305
2412
  this.pendingMessages.push(message);
2306
2413
  } else {
2307
- this.log("Dispatching to", this.messageHandlers.size, "handlers");
2414
+ logger.debug("Nostr", "Dispatching to", this.messageHandlers.size, "handlers");
2308
2415
  for (const handler of this.messageHandlers) {
2309
2416
  try {
2310
2417
  handler(message);
2311
2418
  } catch (error) {
2312
- this.log("Message handler error:", error);
2419
+ logger.debug("Nostr", "Message handler error:", error);
2313
2420
  }
2314
2421
  }
2315
2422
  }
2316
2423
  } catch (err) {
2317
- this.log("Gift wrap decrypt failed (expected if not for us):", err?.message?.slice(0, 50));
2424
+ logger.debug("Nostr", "Gift wrap decrypt failed (expected if not for us):", err?.message?.slice(0, 50));
2318
2425
  }
2319
2426
  }
2320
2427
  async handleTokenTransfer(event) {
@@ -2332,7 +2439,7 @@ var NostrTransportProvider = class {
2332
2439
  try {
2333
2440
  await handler(transfer);
2334
2441
  } catch (error) {
2335
- this.log("Transfer handler error:", error);
2442
+ logger.debug("Nostr", "Transfer handler error:", error);
2336
2443
  }
2337
2444
  }
2338
2445
  }
@@ -2355,16 +2462,16 @@ var NostrTransportProvider = class {
2355
2462
  },
2356
2463
  timestamp: event.created_at * 1e3
2357
2464
  };
2358
- this.log("Received payment request:", request.id);
2465
+ logger.debug("Nostr", "Received payment request:", request.id);
2359
2466
  for (const handler of this.paymentRequestHandlers) {
2360
2467
  try {
2361
2468
  handler(request);
2362
2469
  } catch (error) {
2363
- this.log("Payment request handler error:", error);
2470
+ logger.debug("Nostr", "Payment request handler error:", error);
2364
2471
  }
2365
2472
  }
2366
2473
  } catch (error) {
2367
- this.log("Failed to handle payment request:", error);
2474
+ logger.debug("Nostr", "Failed to handle payment request:", error);
2368
2475
  }
2369
2476
  }
2370
2477
  async handlePaymentRequestResponse(event) {
@@ -2383,16 +2490,16 @@ var NostrTransportProvider = class {
2383
2490
  },
2384
2491
  timestamp: event.created_at * 1e3
2385
2492
  };
2386
- this.log("Received payment request response:", response.id, "type:", responseData.responseType);
2493
+ logger.debug("Nostr", "Received payment request response:", response.id, "type:", responseData.responseType);
2387
2494
  for (const handler of this.paymentRequestResponseHandlers) {
2388
2495
  try {
2389
2496
  handler(response);
2390
2497
  } catch (error) {
2391
- this.log("Payment request response handler error:", error);
2498
+ logger.debug("Nostr", "Payment request response handler error:", error);
2392
2499
  }
2393
2500
  }
2394
2501
  } catch (error) {
2395
- this.log("Failed to handle payment request response:", error);
2502
+ logger.debug("Nostr", "Failed to handle payment request response:", error);
2396
2503
  }
2397
2504
  }
2398
2505
  handleBroadcast(event) {
@@ -2411,7 +2518,7 @@ var NostrTransportProvider = class {
2411
2518
  try {
2412
2519
  handler(broadcast);
2413
2520
  } catch (error) {
2414
- this.log("Broadcast handler error:", error);
2521
+ logger.debug("Nostr", "Broadcast handler error:", error);
2415
2522
  }
2416
2523
  }
2417
2524
  }
@@ -2421,8 +2528,8 @@ var NostrTransportProvider = class {
2421
2528
  // Private: Event Creation & Publishing
2422
2529
  // ===========================================================================
2423
2530
  async createEvent(kind, content, tags) {
2424
- if (!this.identity) throw new Error("Identity not set");
2425
- if (!this.keyManager) throw new Error("KeyManager not initialized");
2531
+ if (!this.identity) throw new SphereError("Identity not set", "NOT_INITIALIZED");
2532
+ if (!this.keyManager) throw new SphereError("KeyManager not initialized", "NOT_INITIALIZED");
2426
2533
  const signedEvent = NostrEventClass.create(this.keyManager, {
2427
2534
  kind,
2428
2535
  content,
@@ -2440,10 +2547,10 @@ var NostrTransportProvider = class {
2440
2547
  return event;
2441
2548
  }
2442
2549
  async createEncryptedEvent(kind, content, tags) {
2443
- if (!this.keyManager) throw new Error("KeyManager not initialized");
2550
+ if (!this.keyManager) throw new SphereError("KeyManager not initialized", "NOT_INITIALIZED");
2444
2551
  const recipientTag = tags.find((t) => t[0] === "p");
2445
2552
  if (!recipientTag || !recipientTag[1]) {
2446
- throw new Error("No recipient pubkey in tags for encryption");
2553
+ throw new SphereError("No recipient pubkey in tags for encryption", "VALIDATION_ERROR");
2447
2554
  }
2448
2555
  const recipientPubkey = recipientTag[1];
2449
2556
  const encrypted = await NIP04.encryptHex(
@@ -2455,14 +2562,14 @@ var NostrTransportProvider = class {
2455
2562
  }
2456
2563
  async publishEvent(event) {
2457
2564
  if (!this.nostrClient) {
2458
- throw new Error("NostrClient not initialized");
2565
+ throw new SphereError("NostrClient not initialized", "NOT_INITIALIZED");
2459
2566
  }
2460
2567
  const sdkEvent = NostrEventClass.fromJSON(event);
2461
2568
  await this.nostrClient.publishEvent(sdkEvent);
2462
2569
  }
2463
2570
  async fetchPendingEvents() {
2464
2571
  if (!this.nostrClient?.isConnected() || !this.keyManager) {
2465
- throw new Error("Transport not connected");
2572
+ throw new SphereError("Transport not connected", "TRANSPORT_ERROR");
2466
2573
  }
2467
2574
  const nostrPubkey = this.keyManager.getPublicKeyHex();
2468
2575
  const walletFilter = new Filter();
@@ -2505,7 +2612,7 @@ var NostrTransportProvider = class {
2505
2612
  }
2506
2613
  async queryEvents(filterObj) {
2507
2614
  if (!this.nostrClient || !this.nostrClient.isConnected()) {
2508
- throw new Error("No connected relays");
2615
+ throw new SphereError("No connected relays", "TRANSPORT_ERROR");
2509
2616
  }
2510
2617
  const events = [];
2511
2618
  const filter = new Filter(filterObj);
@@ -2514,6 +2621,7 @@ var NostrTransportProvider = class {
2514
2621
  if (subId) {
2515
2622
  this.nostrClient?.unsubscribe(subId);
2516
2623
  }
2624
+ logger.warn("Nostr", `queryEvents timed out after 5s, returning ${events.length} event(s)`, { kinds: filterObj.kinds, limit: filterObj.limit });
2517
2625
  resolve(events);
2518
2626
  }, 5e3);
2519
2627
  const subId = this.nostrClient.subscribe(filter, {
@@ -2543,9 +2651,9 @@ var NostrTransportProvider = class {
2543
2651
  walletSubscriptionId = null;
2544
2652
  chatSubscriptionId = null;
2545
2653
  async subscribeToEvents() {
2546
- this.log("subscribeToEvents called, identity:", !!this.identity, "keyManager:", !!this.keyManager, "nostrClient:", !!this.nostrClient);
2654
+ logger.debug("Nostr", "subscribeToEvents called, identity:", !!this.identity, "keyManager:", !!this.keyManager, "nostrClient:", !!this.nostrClient);
2547
2655
  if (!this.identity || !this.keyManager || !this.nostrClient) {
2548
- this.log("subscribeToEvents: skipped - no identity, keyManager, or nostrClient");
2656
+ logger.debug("Nostr", "subscribeToEvents: skipped - no identity, keyManager, or nostrClient");
2549
2657
  return;
2550
2658
  }
2551
2659
  if (this.walletSubscriptionId) {
@@ -2561,7 +2669,7 @@ var NostrTransportProvider = class {
2561
2669
  this.mainSubscriptionId = null;
2562
2670
  }
2563
2671
  const nostrPubkey = this.keyManager.getPublicKeyHex();
2564
- this.log("Subscribing with Nostr pubkey:", nostrPubkey);
2672
+ logger.debug("Nostr", "Subscribing with Nostr pubkey:", nostrPubkey);
2565
2673
  let since;
2566
2674
  if (this.storage) {
2567
2675
  const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_WALLET_EVENT_TS}_${nostrPubkey.slice(0, 16)}`;
@@ -2570,18 +2678,18 @@ var NostrTransportProvider = class {
2570
2678
  if (stored) {
2571
2679
  since = parseInt(stored, 10);
2572
2680
  this.lastEventTs = since;
2573
- this.log("Resuming from stored event timestamp:", since);
2681
+ logger.debug("Nostr", "Resuming from stored event timestamp:", since);
2574
2682
  } else {
2575
2683
  since = Math.floor(Date.now() / 1e3);
2576
- this.log("No stored timestamp, starting from now:", since);
2684
+ logger.debug("Nostr", "No stored timestamp, starting from now:", since);
2577
2685
  }
2578
2686
  } catch (err) {
2579
- this.log("Failed to read last event timestamp, falling back to now:", err);
2687
+ logger.debug("Nostr", "Failed to read last event timestamp, falling back to now:", err);
2580
2688
  since = Math.floor(Date.now() / 1e3);
2581
2689
  }
2582
2690
  } else {
2583
2691
  since = Math.floor(Date.now() / 1e3) - 86400;
2584
- this.log("No storage adapter, using 24h fallback");
2692
+ logger.debug("Nostr", "No storage adapter, using 24h fallback");
2585
2693
  }
2586
2694
  const walletFilter = new Filter();
2587
2695
  walletFilter.kinds = [
@@ -2594,7 +2702,7 @@ var NostrTransportProvider = class {
2594
2702
  walletFilter.since = since;
2595
2703
  this.walletSubscriptionId = this.nostrClient.subscribe(walletFilter, {
2596
2704
  onEvent: (event) => {
2597
- this.log("Received wallet event kind:", event.kind, "id:", event.id?.slice(0, 12));
2705
+ logger.debug("Nostr", "Received wallet event kind:", event.kind, "id:", event.id?.slice(0, 12));
2598
2706
  this.handleEvent({
2599
2707
  id: event.id,
2600
2708
  kind: event.kind,
@@ -2606,19 +2714,19 @@ var NostrTransportProvider = class {
2606
2714
  });
2607
2715
  },
2608
2716
  onEndOfStoredEvents: () => {
2609
- this.log("Wallet subscription ready (EOSE)");
2717
+ logger.debug("Nostr", "Wallet subscription ready (EOSE)");
2610
2718
  },
2611
2719
  onError: (_subId, error) => {
2612
- this.log("Wallet subscription error:", error);
2720
+ logger.debug("Nostr", "Wallet subscription error:", error);
2613
2721
  }
2614
2722
  });
2615
- this.log("Wallet subscription created, subId:", this.walletSubscriptionId);
2723
+ logger.debug("Nostr", "Wallet subscription created, subId:", this.walletSubscriptionId);
2616
2724
  const chatFilter = new Filter();
2617
2725
  chatFilter.kinds = [EventKinds.GIFT_WRAP];
2618
2726
  chatFilter["#p"] = [nostrPubkey];
2619
2727
  this.chatSubscriptionId = this.nostrClient.subscribe(chatFilter, {
2620
2728
  onEvent: (event) => {
2621
- this.log("Received chat event kind:", event.kind, "id:", event.id?.slice(0, 12));
2729
+ logger.debug("Nostr", "Received chat event kind:", event.kind, "id:", event.id?.slice(0, 12));
2622
2730
  this.handleEvent({
2623
2731
  id: event.id,
2624
2732
  kind: event.kind,
@@ -2630,13 +2738,13 @@ var NostrTransportProvider = class {
2630
2738
  });
2631
2739
  },
2632
2740
  onEndOfStoredEvents: () => {
2633
- this.log("Chat subscription ready (EOSE)");
2741
+ logger.debug("Nostr", "Chat subscription ready (EOSE)");
2634
2742
  },
2635
2743
  onError: (_subId, error) => {
2636
- this.log("Chat subscription error:", error);
2744
+ logger.debug("Nostr", "Chat subscription error:", error);
2637
2745
  }
2638
2746
  });
2639
- this.log("Chat subscription created, subId:", this.chatSubscriptionId);
2747
+ logger.debug("Nostr", "Chat subscription created, subId:", this.chatSubscriptionId);
2640
2748
  }
2641
2749
  subscribeToTags(tags) {
2642
2750
  if (!this.nostrClient) return;
@@ -2666,7 +2774,7 @@ var NostrTransportProvider = class {
2666
2774
  // Private: Encryption
2667
2775
  // ===========================================================================
2668
2776
  async decryptContent(content, senderPubkey) {
2669
- if (!this.keyManager) throw new Error("KeyManager not initialized");
2777
+ if (!this.keyManager) throw new SphereError("KeyManager not initialized", "NOT_INITIALIZED");
2670
2778
  const decrypted = await NIP04.decryptHex(
2671
2779
  content,
2672
2780
  this.keyManager.getPrivateKeyHex(),
@@ -2696,13 +2804,13 @@ var NostrTransportProvider = class {
2696
2804
  // ===========================================================================
2697
2805
  ensureConnected() {
2698
2806
  if (!this.isConnected()) {
2699
- throw new Error("NostrTransportProvider not connected");
2807
+ throw new SphereError("NostrTransportProvider not connected", "TRANSPORT_ERROR");
2700
2808
  }
2701
2809
  }
2702
2810
  ensureReady() {
2703
2811
  this.ensureConnected();
2704
2812
  if (!this.identity) {
2705
- throw new Error("Identity not set");
2813
+ throw new SphereError("Identity not set", "NOT_INITIALIZED");
2706
2814
  }
2707
2815
  }
2708
2816
  emitEvent(event) {
@@ -2710,7 +2818,7 @@ var NostrTransportProvider = class {
2710
2818
  try {
2711
2819
  callback(event);
2712
2820
  } catch (error) {
2713
- this.log("Event callback error:", error);
2821
+ logger.debug("Nostr", "Event callback error:", error);
2714
2822
  }
2715
2823
  }
2716
2824
  }
@@ -2747,11 +2855,6 @@ var NostrTransportProvider = class {
2747
2855
  ephemeralKeys.clear();
2748
2856
  return giftWrap;
2749
2857
  }
2750
- log(...args) {
2751
- if (this.config.debug) {
2752
- console.log("[NostrTransportProvider]", ...args);
2753
- }
2754
- }
2755
2858
  };
2756
2859
 
2757
2860
  // impl/nodejs/transport/index.ts
@@ -2940,7 +3043,8 @@ var UnicityAggregatorProvider = class {
2940
3043
  proof: response.proof,
2941
3044
  timestamp: Date.now()
2942
3045
  };
2943
- } catch {
3046
+ } catch (error) {
3047
+ logger.warn("Aggregator", "getProof failed", error);
2944
3048
  return null;
2945
3049
  }
2946
3050
  }
@@ -2962,7 +3066,7 @@ var UnicityAggregatorProvider = class {
2962
3066
  }
2963
3067
  await new Promise((resolve) => setTimeout(resolve, pollInterval));
2964
3068
  }
2965
- throw new Error(`Timeout waiting for proof: ${requestId}`);
3069
+ throw new SphereError(`Timeout waiting for proof: ${requestId}`, "TIMEOUT");
2966
3070
  }
2967
3071
  async validateToken(tokenData) {
2968
3072
  this.ensureConnected();
@@ -3021,7 +3125,7 @@ var UnicityAggregatorProvider = class {
3021
3125
  async waitForProofSdk(commitment, signal) {
3022
3126
  this.ensureConnected();
3023
3127
  if (!this.trustBase) {
3024
- throw new Error("Trust base not initialized");
3128
+ throw new SphereError("Trust base not initialized", "NOT_INITIALIZED");
3025
3129
  }
3026
3130
  return await waitInclusionProof(
3027
3131
  this.trustBase,
@@ -3043,7 +3147,8 @@ var UnicityAggregatorProvider = class {
3043
3147
  this.spentCache.set(stateHash, true);
3044
3148
  }
3045
3149
  return spent;
3046
- } catch {
3150
+ } catch (error) {
3151
+ logger.warn("Aggregator", "isSpent check failed, assuming unspent", error);
3047
3152
  return false;
3048
3153
  }
3049
3154
  }
@@ -3061,7 +3166,8 @@ var UnicityAggregatorProvider = class {
3061
3166
  roundNumber: response.state.roundNumber,
3062
3167
  lastUpdated: Date.now()
3063
3168
  };
3064
- } catch {
3169
+ } catch (error) {
3170
+ logger.warn("Aggregator", "getTokenState failed", error);
3065
3171
  return null;
3066
3172
  }
3067
3173
  }
@@ -3121,11 +3227,11 @@ var UnicityAggregatorProvider = class {
3121
3227
  signal: controller.signal
3122
3228
  });
3123
3229
  if (!response.ok) {
3124
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
3230
+ throw new SphereError(`HTTP ${response.status}: ${response.statusText}`, "AGGREGATOR_ERROR");
3125
3231
  }
3126
3232
  const result = await response.json();
3127
3233
  if (result.error) {
3128
- throw new Error(result.error.message ?? "RPC error");
3234
+ throw new SphereError(result.error.message ?? "RPC error", "AGGREGATOR_ERROR");
3129
3235
  }
3130
3236
  return result.result ?? {};
3131
3237
  } finally {
@@ -3137,7 +3243,7 @@ var UnicityAggregatorProvider = class {
3137
3243
  // ===========================================================================
3138
3244
  ensureConnected() {
3139
3245
  if (this.status !== "connected") {
3140
- throw new Error("UnicityAggregatorProvider not connected");
3246
+ throw new SphereError("UnicityAggregatorProvider not connected", "NOT_INITIALIZED");
3141
3247
  }
3142
3248
  }
3143
3249
  emitEvent(event) {
@@ -3149,10 +3255,8 @@ var UnicityAggregatorProvider = class {
3149
3255
  }
3150
3256
  }
3151
3257
  }
3152
- log(...args) {
3153
- if (this.config.debug) {
3154
- console.log("[UnicityAggregatorProvider]", ...args);
3155
- }
3258
+ log(message, ...args) {
3259
+ logger.debug("Aggregator", message, ...args);
3156
3260
  }
3157
3261
  };
3158
3262
  var UnicityOracleProvider = UnicityAggregatorProvider;
@@ -3683,7 +3787,10 @@ var IpfsHttpClient = class {
3683
3787
  { headers: { Accept: "application/octet-stream" } }
3684
3788
  );
3685
3789
  if (!response.ok) {
3686
- const body = await response.text().catch(() => "");
3790
+ const body = await response.text().catch((err) => {
3791
+ logger.debug("IPFS-HTTP", "Failed to read error response body", err);
3792
+ return "";
3793
+ });
3687
3794
  throw new IpfsError(
3688
3795
  `Fetch failed: HTTP ${response.status}`,
3689
3796
  classifyHttpStatus(response.status, body),
@@ -3729,7 +3836,10 @@ var IpfsHttpClient = class {
3729
3836
  { method: "POST" }
3730
3837
  );
3731
3838
  if (!response.ok) {
3732
- const body = await response.text().catch(() => "");
3839
+ const body = await response.text().catch((err) => {
3840
+ logger.debug("IPFS-HTTP", "Failed to read error response body", err);
3841
+ return "";
3842
+ });
3733
3843
  const category = classifyHttpStatus(response.status, body);
3734
3844
  if (category === "NOT_FOUND") return null;
3735
3845
  throw new IpfsError(`Routing API: HTTP ${response.status}`, category, gateway);
@@ -3775,7 +3885,8 @@ var IpfsHttpClient = class {
3775
3885
  }
3776
3886
  }
3777
3887
  return { cid: "", content };
3778
- } catch {
3888
+ } catch (err) {
3889
+ logger.debug("IPFS-HTTP", "IPNS gateway resolution failed", err);
3779
3890
  return null;
3780
3891
  }
3781
3892
  }
@@ -3840,7 +3951,10 @@ var IpfsHttpClient = class {
3840
3951
  { method: "POST", body: formData }
3841
3952
  );
3842
3953
  if (!response.ok) {
3843
- const errorText = await response.text().catch(() => "");
3954
+ const errorText = await response.text().catch((err) => {
3955
+ logger.debug("IPFS-HTTP", "Failed to read error response body", err);
3956
+ return "";
3957
+ });
3844
3958
  throw new IpfsError(
3845
3959
  `IPNS publish: HTTP ${response.status}: ${errorText.slice(0, 100)}`,
3846
3960
  classifyHttpStatus(response.status, errorText),
@@ -3917,9 +4031,7 @@ var IpfsHttpClient = class {
3917
4031
  }
3918
4032
  }
3919
4033
  log(message) {
3920
- if (this.debug) {
3921
- console.log(`[IPFS-HTTP] ${message}`);
3922
- }
4034
+ logger.debug("IPFS-HTTP", message);
3923
4035
  }
3924
4036
  };
3925
4037
 
@@ -4363,10 +4475,12 @@ var IpnsSubscriptionClient = class {
4363
4475
  startFallbackPolling() {
4364
4476
  if (this.fallbackPollInterval || !this.fallbackPollFn || this.destroyed) return;
4365
4477
  this.log(`Starting fallback polling (${this.fallbackPollIntervalMs / 1e3}s interval)`);
4366
- this.fallbackPollFn().catch(() => {
4478
+ this.fallbackPollFn().catch((err) => {
4479
+ logger.warn("IPNS-WS", "Fallback poll error:", err);
4367
4480
  });
4368
4481
  this.fallbackPollInterval = setInterval(() => {
4369
- this.fallbackPollFn?.().catch(() => {
4482
+ this.fallbackPollFn?.().catch((err) => {
4483
+ logger.warn("IPNS-WS", "Fallback poll error:", err);
4370
4484
  });
4371
4485
  }, this.fallbackPollIntervalMs);
4372
4486
  }
@@ -4380,9 +4494,7 @@ var IpnsSubscriptionClient = class {
4380
4494
  // Internal: Logging
4381
4495
  // ---------------------------------------------------------------------------
4382
4496
  log(message) {
4383
- if (this.debugEnabled) {
4384
- console.log(`[IPNS-WS] ${message}`);
4385
- }
4497
+ logger.debug("IPNS-WS", message);
4386
4498
  }
4387
4499
  };
4388
4500
 
@@ -4571,7 +4683,8 @@ var IpfsStorageProvider = class {
4571
4683
  } else {
4572
4684
  this.log("Warning: no healthy gateways found");
4573
4685
  }
4574
- }).catch(() => {
4686
+ }).catch((err) => {
4687
+ logger.warn("IPFS-Storage", "Gateway health check failed (non-fatal):", err);
4575
4688
  });
4576
4689
  this.isShuttingDown = false;
4577
4690
  this.status = "connected";
@@ -4735,7 +4848,7 @@ var IpfsStorageProvider = class {
4735
4848
  };
4736
4849
  const result = await this._doSave(baseData);
4737
4850
  if (!result.success) {
4738
- throw new Error(result.error ?? "Save failed");
4851
+ throw new SphereError(result.error ?? "Save failed", "STORAGE_ERROR");
4739
4852
  }
4740
4853
  this.log(`Flushed successfully: CID=${result.cid}`);
4741
4854
  } catch (error) {
@@ -4975,10 +5088,12 @@ var IpfsStorageProvider = class {
4975
5088
  if (this.flushTimer) {
4976
5089
  clearTimeout(this.flushTimer);
4977
5090
  this.flushTimer = null;
4978
- await this.flushQueue.enqueue(() => this.executeFlush()).catch(() => {
5091
+ await this.flushQueue.enqueue(() => this.executeFlush()).catch((err) => {
5092
+ logger.warn("IPFS-Storage", "Flush on shutdown failed:", err);
4979
5093
  });
4980
5094
  } else if (!this.pendingBuffer.isEmpty) {
4981
- await this.flushQueue.enqueue(() => this.executeFlush()).catch(() => {
5095
+ await this.flushQueue.enqueue(() => this.executeFlush()).catch((err) => {
5096
+ logger.warn("IPFS-Storage", "Flush on shutdown failed:", err);
4982
5097
  });
4983
5098
  } else {
4984
5099
  await this.flushQueue.enqueue(async () => {
@@ -5032,9 +5147,7 @@ var IpfsStorageProvider = class {
5032
5147
  }
5033
5148
  }
5034
5149
  log(message) {
5035
- if (this.debug) {
5036
- console.log(`[IPFS-Storage] ${message}`);
5037
- }
5150
+ logger.debug("IPFS-Storage", message);
5038
5151
  }
5039
5152
  };
5040
5153
 
@@ -5144,7 +5257,7 @@ var CoinGeckoPriceProvider = class {
5144
5257
  const allCovered = uncachedNames.every((n) => this.fetchNames.has(n));
5145
5258
  if (allCovered) {
5146
5259
  if (this.debug) {
5147
- console.log(`[CoinGecko] Deduplicating request, reusing in-flight fetch`);
5260
+ logger.debug("CoinGecko", "Deduplicating request, reusing in-flight fetch");
5148
5261
  }
5149
5262
  const fetched = await this.fetchPromise;
5150
5263
  for (const name of uncachedNames) {
@@ -5183,7 +5296,7 @@ var CoinGeckoPriceProvider = class {
5183
5296
  headers["x-cg-pro-api-key"] = this.apiKey;
5184
5297
  }
5185
5298
  if (this.debug) {
5186
- console.log(`[CoinGecko] Fetching prices for: ${uncachedNames.join(", ")}`);
5299
+ logger.debug("CoinGecko", `Fetching prices for: ${uncachedNames.join(", ")}`);
5187
5300
  }
5188
5301
  const response = await fetch(url, {
5189
5302
  headers,
@@ -5193,7 +5306,7 @@ var CoinGeckoPriceProvider = class {
5193
5306
  if (response.status === 429) {
5194
5307
  this.extendCacheOnRateLimit(uncachedNames);
5195
5308
  }
5196
- throw new Error(`CoinGecko API error: ${response.status} ${response.statusText}`);
5309
+ throw new SphereError(`CoinGecko API error: ${response.status} ${response.statusText}`, "NETWORK_ERROR");
5197
5310
  }
5198
5311
  const data = await response.json();
5199
5312
  for (const [name, values] of Object.entries(data)) {
@@ -5223,12 +5336,12 @@ var CoinGeckoPriceProvider = class {
5223
5336
  }
5224
5337
  }
5225
5338
  if (this.debug) {
5226
- console.log(`[CoinGecko] Fetched ${result.size} prices`);
5339
+ logger.debug("CoinGecko", `Fetched ${result.size} prices`);
5227
5340
  }
5228
5341
  this.saveToStorage();
5229
5342
  } catch (error) {
5230
5343
  if (this.debug) {
5231
- console.warn("[CoinGecko] Fetch failed, using stale cache:", error);
5344
+ logger.warn("CoinGecko", "Fetch failed, using stale cache:", error);
5232
5345
  }
5233
5346
  for (const name of uncachedNames) {
5234
5347
  const stale = this.cache.get(name);
@@ -5278,7 +5391,7 @@ var CoinGeckoPriceProvider = class {
5278
5391
  }
5279
5392
  }
5280
5393
  if (this.debug) {
5281
- console.log(`[CoinGecko] Loaded ${Object.keys(data).length} prices from persistent cache`);
5394
+ logger.debug("CoinGecko", `Loaded ${Object.keys(data).length} prices from persistent cache`);
5282
5395
  }
5283
5396
  } catch {
5284
5397
  }
@@ -5295,8 +5408,7 @@ var CoinGeckoPriceProvider = class {
5295
5408
  Promise.all([
5296
5409
  this.storage.set(STORAGE_KEYS_GLOBAL.PRICE_CACHE, JSON.stringify(data)),
5297
5410
  this.storage.set(STORAGE_KEYS_GLOBAL.PRICE_CACHE_TS, String(Date.now()))
5298
- ]).catch(() => {
5299
- });
5411
+ ]).catch((err) => logger.debug("Price", "Cache save failed (non-critical)", err));
5300
5412
  }
5301
5413
  // ===========================================================================
5302
5414
  // Rate-limit handling
@@ -5315,7 +5427,7 @@ var CoinGeckoPriceProvider = class {
5315
5427
  }
5316
5428
  }
5317
5429
  if (this.debug) {
5318
- console.warn(`[CoinGecko] Rate-limited (429), extended cache TTL by ${backoffMs / 1e3}s`);
5430
+ logger.warn("CoinGecko", `Rate-limited (429), extended cache TTL by ${backoffMs / 1e3}s`);
5319
5431
  }
5320
5432
  }
5321
5433
  async getPrice(tokenName) {
@@ -5333,7 +5445,7 @@ function createPriceProvider(config) {
5333
5445
  case "coingecko":
5334
5446
  return new CoinGeckoPriceProvider(config);
5335
5447
  default:
5336
- throw new Error(`Unsupported price platform: ${String(config.platform)}`);
5448
+ throw new SphereError(`Unsupported price platform: ${String(config.platform)}`, "INVALID_CONFIG");
5337
5449
  }
5338
5450
  }
5339
5451
 
@@ -5558,14 +5670,12 @@ var TokenRegistry = class _TokenRegistry {
5558
5670
  clearTimeout(timer);
5559
5671
  }
5560
5672
  if (!response.ok) {
5561
- console.warn(
5562
- `[TokenRegistry] Remote fetch failed: HTTP ${response.status} ${response.statusText}`
5563
- );
5673
+ logger.warn("TokenRegistry", `Remote fetch failed: HTTP ${response.status} ${response.statusText}`);
5564
5674
  return false;
5565
5675
  }
5566
5676
  const data = await response.json();
5567
5677
  if (!this.isValidDefinitionsArray(data)) {
5568
- console.warn("[TokenRegistry] Remote data is not a valid token definitions array");
5678
+ logger.warn("TokenRegistry", "Remote data is not a valid token definitions array");
5569
5679
  return false;
5570
5680
  }
5571
5681
  const definitions = data;
@@ -5575,7 +5685,7 @@ var TokenRegistry = class _TokenRegistry {
5575
5685
  return true;
5576
5686
  } catch (error) {
5577
5687
  const message = error instanceof Error ? error.message : String(error);
5578
- console.warn(`[TokenRegistry] Remote refresh failed: ${message}`);
5688
+ logger.warn("TokenRegistry", `Remote refresh failed: ${message}`);
5579
5689
  return false;
5580
5690
  }
5581
5691
  }
@@ -5822,6 +5932,11 @@ function resolveMarketConfig(config) {
5822
5932
  // impl/nodejs/index.ts
5823
5933
  function createNodeProviders(config) {
5824
5934
  const network = config?.network ?? "mainnet";
5935
+ const globalDebug = config?.debug ?? false;
5936
+ logger.configure({ debug: globalDebug });
5937
+ if (config?.transport?.debug) logger.setTagDebug("Nostr", true);
5938
+ if (config?.oracle?.debug) logger.setTagDebug("Aggregator", true);
5939
+ if (config?.price?.debug) logger.setTagDebug("Price", true);
5825
5940
  const transportConfig = resolveTransportConfig(network, config?.transport);
5826
5941
  const oracleConfig = resolveOracleConfig(network, config?.oracle);
5827
5942
  const l1Config = resolveL1Config(network, config?.l1);