@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
@@ -1096,6 +1096,18 @@ var bip39 = __toESM(require("bip39"), 1);
1096
1096
  var import_crypto_js = __toESM(require("crypto-js"), 1);
1097
1097
  var import_elliptic = __toESM(require("elliptic"), 1);
1098
1098
 
1099
+ // core/errors.ts
1100
+ var SphereError = class extends Error {
1101
+ code;
1102
+ cause;
1103
+ constructor(message, code, cause) {
1104
+ super(message);
1105
+ this.name = "SphereError";
1106
+ this.code = code;
1107
+ this.cause = cause;
1108
+ }
1109
+ };
1110
+
1099
1111
  // core/bech32.ts
1100
1112
  var CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
1101
1113
  var GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
@@ -1152,11 +1164,11 @@ function bech32Checksum(hrp, data) {
1152
1164
  }
1153
1165
  function encodeBech32(hrp, version, program) {
1154
1166
  if (version < 0 || version > 16) {
1155
- throw new Error("Invalid witness version");
1167
+ throw new SphereError("Invalid witness version", "VALIDATION_ERROR");
1156
1168
  }
1157
1169
  const converted = convertBits(Array.from(program), 8, 5, true);
1158
1170
  if (!converted) {
1159
- throw new Error("Failed to convert bits");
1171
+ throw new SphereError("Failed to convert bits", "VALIDATION_ERROR");
1160
1172
  }
1161
1173
  const data = [version].concat(converted);
1162
1174
  const checksum = bech32Checksum(hrp, data);
@@ -1207,6 +1219,98 @@ function hexToBytes2(hex) {
1207
1219
  return Uint8Array.from(matches.map((x) => parseInt(x, 16)));
1208
1220
  }
1209
1221
 
1222
+ // core/logger.ts
1223
+ var LOGGER_KEY = "__sphere_sdk_logger__";
1224
+ function getState() {
1225
+ const g = globalThis;
1226
+ if (!g[LOGGER_KEY]) {
1227
+ g[LOGGER_KEY] = { debug: false, tags: {}, handler: null };
1228
+ }
1229
+ return g[LOGGER_KEY];
1230
+ }
1231
+ function isEnabled(tag) {
1232
+ const state = getState();
1233
+ if (tag in state.tags) return state.tags[tag];
1234
+ return state.debug;
1235
+ }
1236
+ var logger = {
1237
+ /**
1238
+ * Configure the logger. Can be called multiple times (last write wins).
1239
+ * Typically called by createBrowserProviders(), createNodeProviders(), or Sphere.init().
1240
+ */
1241
+ configure(config) {
1242
+ const state = getState();
1243
+ if (config.debug !== void 0) state.debug = config.debug;
1244
+ if (config.handler !== void 0) state.handler = config.handler;
1245
+ },
1246
+ /**
1247
+ * Enable/disable debug logging for a specific tag.
1248
+ * Per-tag setting overrides the global debug flag.
1249
+ *
1250
+ * @example
1251
+ * ```ts
1252
+ * logger.setTagDebug('Nostr', true); // enable only Nostr logs
1253
+ * logger.setTagDebug('Nostr', false); // disable Nostr logs even if global debug=true
1254
+ * ```
1255
+ */
1256
+ setTagDebug(tag, enabled) {
1257
+ getState().tags[tag] = enabled;
1258
+ },
1259
+ /**
1260
+ * Clear per-tag override, falling back to global debug flag.
1261
+ */
1262
+ clearTagDebug(tag) {
1263
+ delete getState().tags[tag];
1264
+ },
1265
+ /** Returns true if debug mode is enabled for the given tag (or globally). */
1266
+ isDebugEnabled(tag) {
1267
+ if (tag) return isEnabled(tag);
1268
+ return getState().debug;
1269
+ },
1270
+ /**
1271
+ * Debug-level log. Only shown when debug is enabled (globally or for this tag).
1272
+ * Use for detailed operational information.
1273
+ */
1274
+ debug(tag, message, ...args) {
1275
+ if (!isEnabled(tag)) return;
1276
+ const state = getState();
1277
+ if (state.handler) {
1278
+ state.handler("debug", tag, message, ...args);
1279
+ } else {
1280
+ console.log(`[${tag}]`, message, ...args);
1281
+ }
1282
+ },
1283
+ /**
1284
+ * Warning-level log. ALWAYS shown regardless of debug flag.
1285
+ * Use for important but non-critical issues (timeouts, retries, degraded state).
1286
+ */
1287
+ warn(tag, message, ...args) {
1288
+ const state = getState();
1289
+ if (state.handler) {
1290
+ state.handler("warn", tag, message, ...args);
1291
+ } else {
1292
+ console.warn(`[${tag}]`, message, ...args);
1293
+ }
1294
+ },
1295
+ /**
1296
+ * Error-level log. ALWAYS shown regardless of debug flag.
1297
+ * Use for critical failures that should never be silenced.
1298
+ */
1299
+ error(tag, message, ...args) {
1300
+ const state = getState();
1301
+ if (state.handler) {
1302
+ state.handler("error", tag, message, ...args);
1303
+ } else {
1304
+ console.error(`[${tag}]`, message, ...args);
1305
+ }
1306
+ },
1307
+ /** Reset all logger state (debug flag, tags, handler). Primarily for tests. */
1308
+ reset() {
1309
+ const g = globalThis;
1310
+ delete g[LOGGER_KEY];
1311
+ }
1312
+ };
1313
+
1210
1314
  // transport/websocket.ts
1211
1315
  var WebSocketReadyState = {
1212
1316
  CONNECTING: 0,
@@ -1349,18 +1453,18 @@ var NostrTransportProvider = class {
1349
1453
  });
1350
1454
  this.nostrClient.addConnectionListener({
1351
1455
  onConnect: (url) => {
1352
- this.log("NostrClient connected to relay:", url);
1456
+ logger.debug("Nostr", "NostrClient connected to relay:", url);
1353
1457
  this.emitEvent({ type: "transport:connected", timestamp: Date.now() });
1354
1458
  },
1355
1459
  onDisconnect: (url, reason) => {
1356
- this.log("NostrClient disconnected from relay:", url, "reason:", reason);
1460
+ logger.debug("Nostr", "NostrClient disconnected from relay:", url, "reason:", reason);
1357
1461
  },
1358
1462
  onReconnecting: (url, attempt) => {
1359
- this.log("NostrClient reconnecting to relay:", url, "attempt:", attempt);
1463
+ logger.debug("Nostr", "NostrClient reconnecting to relay:", url, "attempt:", attempt);
1360
1464
  this.emitEvent({ type: "transport:reconnecting", timestamp: Date.now() });
1361
1465
  },
1362
1466
  onReconnected: (url) => {
1363
- this.log("NostrClient reconnected to relay:", url);
1467
+ logger.debug("Nostr", "NostrClient reconnected to relay:", url);
1364
1468
  this.emitEvent({ type: "transport:connected", timestamp: Date.now() });
1365
1469
  }
1366
1470
  });
@@ -1373,11 +1477,11 @@ var NostrTransportProvider = class {
1373
1477
  )
1374
1478
  ]);
1375
1479
  if (!this.nostrClient.isConnected()) {
1376
- throw new Error("Failed to connect to any relay");
1480
+ throw new SphereError("Failed to connect to any relay", "TRANSPORT_ERROR");
1377
1481
  }
1378
1482
  this.status = "connected";
1379
1483
  this.emitEvent({ type: "transport:connected", timestamp: Date.now() });
1380
- this.log("Connected to", this.nostrClient.getConnectedRelays().size, "relays");
1484
+ logger.debug("Nostr", "Connected to", this.nostrClient.getConnectedRelays().size, "relays");
1381
1485
  if (this.identity) {
1382
1486
  await this.subscribeToEvents();
1383
1487
  }
@@ -1396,7 +1500,7 @@ var NostrTransportProvider = class {
1396
1500
  this.chatSubscriptionId = null;
1397
1501
  this.status = "disconnected";
1398
1502
  this.emitEvent({ type: "transport:disconnected", timestamp: Date.now() });
1399
- this.log("Disconnected from all relays");
1503
+ logger.debug("Nostr", "Disconnected from all relays");
1400
1504
  }
1401
1505
  isConnected() {
1402
1506
  return this.status === "connected" && this.nostrClient?.isConnected() === true;
@@ -1426,14 +1530,14 @@ var NostrTransportProvider = class {
1426
1530
  */
1427
1531
  async addRelay(relayUrl) {
1428
1532
  if (this.config.relays.includes(relayUrl)) {
1429
- this.log("Relay already configured:", relayUrl);
1533
+ logger.debug("Nostr", "Relay already configured:", relayUrl);
1430
1534
  return false;
1431
1535
  }
1432
1536
  this.config.relays.push(relayUrl);
1433
1537
  if (this.status === "connected" && this.nostrClient) {
1434
1538
  try {
1435
1539
  await this.nostrClient.connect(relayUrl);
1436
- this.log("Added and connected to relay:", relayUrl);
1540
+ logger.debug("Nostr", "Added and connected to relay:", relayUrl);
1437
1541
  this.emitEvent({
1438
1542
  type: "transport:relay_added",
1439
1543
  timestamp: Date.now(),
@@ -1441,7 +1545,7 @@ var NostrTransportProvider = class {
1441
1545
  });
1442
1546
  return true;
1443
1547
  } catch (error) {
1444
- this.log("Failed to connect to new relay:", relayUrl, error);
1548
+ logger.debug("Nostr", "Failed to connect to new relay:", relayUrl, error);
1445
1549
  this.emitEvent({
1446
1550
  type: "transport:relay_added",
1447
1551
  timestamp: Date.now(),
@@ -1466,11 +1570,11 @@ var NostrTransportProvider = class {
1466
1570
  async removeRelay(relayUrl) {
1467
1571
  const index = this.config.relays.indexOf(relayUrl);
1468
1572
  if (index === -1) {
1469
- this.log("Relay not found:", relayUrl);
1573
+ logger.debug("Nostr", "Relay not found:", relayUrl);
1470
1574
  return false;
1471
1575
  }
1472
1576
  this.config.relays.splice(index, 1);
1473
- this.log("Removed relay from config:", relayUrl);
1577
+ logger.debug("Nostr", "Removed relay from config:", relayUrl);
1474
1578
  this.emitEvent({
1475
1579
  type: "transport:relay_removed",
1476
1580
  timestamp: Date.now(),
@@ -1507,9 +1611,9 @@ var NostrTransportProvider = class {
1507
1611
  const secretKey = import_buffer.Buffer.from(identity.privateKey, "hex");
1508
1612
  this.keyManager = import_nostr_js_sdk.NostrKeyManager.fromPrivateKey(secretKey);
1509
1613
  const nostrPubkey = this.keyManager.getPublicKeyHex();
1510
- this.log("Identity set, Nostr pubkey:", nostrPubkey.slice(0, 16) + "...");
1614
+ logger.debug("Nostr", "Identity set, Nostr pubkey:", nostrPubkey.slice(0, 16) + "...");
1511
1615
  if (this.nostrClient && this.status === "connected") {
1512
- this.log("Identity changed while connected - recreating NostrClient");
1616
+ logger.debug("Nostr", "Identity changed while connected - recreating NostrClient");
1513
1617
  const oldClient = this.nostrClient;
1514
1618
  this.nostrClient = new import_nostr_js_sdk.NostrClient(this.keyManager, {
1515
1619
  autoReconnect: this.config.autoReconnect,
@@ -1520,16 +1624,16 @@ var NostrTransportProvider = class {
1520
1624
  });
1521
1625
  this.nostrClient.addConnectionListener({
1522
1626
  onConnect: (url) => {
1523
- this.log("NostrClient connected to relay:", url);
1627
+ logger.debug("Nostr", "NostrClient connected to relay:", url);
1524
1628
  },
1525
1629
  onDisconnect: (url, reason) => {
1526
- this.log("NostrClient disconnected from relay:", url, "reason:", reason);
1630
+ logger.debug("Nostr", "NostrClient disconnected from relay:", url, "reason:", reason);
1527
1631
  },
1528
1632
  onReconnecting: (url, attempt) => {
1529
- this.log("NostrClient reconnecting to relay:", url, "attempt:", attempt);
1633
+ logger.debug("Nostr", "NostrClient reconnecting to relay:", url, "attempt:", attempt);
1530
1634
  },
1531
1635
  onReconnected: (url) => {
1532
- this.log("NostrClient reconnected to relay:", url);
1636
+ logger.debug("Nostr", "NostrClient reconnected to relay:", url);
1533
1637
  }
1534
1638
  });
1535
1639
  await Promise.race([
@@ -1552,7 +1656,7 @@ var NostrTransportProvider = class {
1552
1656
  */
1553
1657
  getNostrPubkey() {
1554
1658
  if (!this.keyManager) {
1555
- throw new Error("KeyManager not initialized - call setIdentity first");
1659
+ throw new SphereError("KeyManager not initialized - call setIdentity first", "NOT_INITIALIZED");
1556
1660
  }
1557
1661
  return this.keyManager.getPublicKeyHex();
1558
1662
  }
@@ -1573,7 +1677,7 @@ var NostrTransportProvider = class {
1573
1677
  const selfPubkey = this.keyManager.getPublicKeyHex();
1574
1678
  const selfGiftWrap = import_nostr_js_sdk.NIP17.createGiftWrap(this.keyManager, selfPubkey, selfWrapContent);
1575
1679
  this.publishEvent(selfGiftWrap).catch((err) => {
1576
- this.log("Self-wrap publish failed:", err);
1680
+ logger.debug("Nostr", "Self-wrap publish failed:", err);
1577
1681
  });
1578
1682
  this.emitEvent({
1579
1683
  type: "message:sent",
@@ -1587,12 +1691,12 @@ var NostrTransportProvider = class {
1587
1691
  if (this.pendingMessages.length > 0) {
1588
1692
  const pending = this.pendingMessages;
1589
1693
  this.pendingMessages = [];
1590
- this.log("Flushing", pending.length, "buffered messages to new handler");
1694
+ logger.debug("Nostr", "Flushing", pending.length, "buffered messages to new handler");
1591
1695
  for (const message of pending) {
1592
1696
  try {
1593
1697
  handler(message);
1594
1698
  } catch (error) {
1595
- this.log("Message handler error (buffered):", error);
1699
+ logger.debug("Nostr", "Message handler error (buffered):", error);
1596
1700
  }
1597
1701
  }
1598
1702
  }
@@ -1651,7 +1755,7 @@ var NostrTransportProvider = class {
1651
1755
  tags
1652
1756
  );
1653
1757
  await this.publishEvent(event);
1654
- this.log("Sent payment request:", event.id);
1758
+ logger.debug("Nostr", "Sent payment request:", event.id);
1655
1759
  return event.id;
1656
1760
  }
1657
1761
  onPaymentRequest(handler) {
@@ -1679,7 +1783,7 @@ var NostrTransportProvider = class {
1679
1783
  ]
1680
1784
  );
1681
1785
  await this.publishEvent(event);
1682
- this.log("Sent payment request response:", event.id, "type:", payload.responseType);
1786
+ logger.debug("Nostr", "Sent payment request response:", event.id, "type:", payload.responseType);
1683
1787
  return event.id;
1684
1788
  }
1685
1789
  onPaymentRequestResponse(handler) {
@@ -1690,11 +1794,11 @@ var NostrTransportProvider = class {
1690
1794
  // Read Receipts
1691
1795
  // ===========================================================================
1692
1796
  async sendReadReceipt(recipientTransportPubkey, messageEventId) {
1693
- if (!this.keyManager) throw new Error("Not initialized");
1797
+ if (!this.keyManager) throw new SphereError("Not initialized", "NOT_INITIALIZED");
1694
1798
  const nostrRecipient = recipientTransportPubkey.length === 66 ? recipientTransportPubkey.slice(2) : recipientTransportPubkey;
1695
1799
  const event = import_nostr_js_sdk.NIP17.createReadReceipt(this.keyManager, nostrRecipient, messageEventId);
1696
1800
  await this.publishEvent(event);
1697
- this.log("Sent read receipt for:", messageEventId, "to:", nostrRecipient.slice(0, 16));
1801
+ logger.debug("Nostr", "Sent read receipt for:", messageEventId, "to:", nostrRecipient.slice(0, 16));
1698
1802
  }
1699
1803
  onReadReceipt(handler) {
1700
1804
  this.readReceiptHandlers.add(handler);
@@ -1704,7 +1808,7 @@ var NostrTransportProvider = class {
1704
1808
  // Typing Indicators
1705
1809
  // ===========================================================================
1706
1810
  async sendTypingIndicator(recipientTransportPubkey) {
1707
- if (!this.keyManager) throw new Error("Not initialized");
1811
+ if (!this.keyManager) throw new SphereError("Not initialized", "NOT_INITIALIZED");
1708
1812
  const nostrRecipient = recipientTransportPubkey.length === 66 ? recipientTransportPubkey.slice(2) : recipientTransportPubkey;
1709
1813
  const content = JSON.stringify({
1710
1814
  type: "typing",
@@ -1791,7 +1895,10 @@ var NostrTransportProvider = class {
1791
1895
  limit: 1
1792
1896
  });
1793
1897
  }
1794
- if (events.length === 0) return null;
1898
+ if (events.length === 0) {
1899
+ logger.debug("Nostr", `resolveNametagInfo: no binding events found for nametag "${nametag}"`);
1900
+ return null;
1901
+ }
1795
1902
  const bindingEvent = events[0];
1796
1903
  try {
1797
1904
  const content = JSON.parse(bindingEvent.content);
@@ -1809,7 +1916,7 @@ var NostrTransportProvider = class {
1809
1916
  timestamp: bindingEvent.created_at * 1e3
1810
1917
  };
1811
1918
  }
1812
- this.log("Legacy nametag event without extended fields:", nametag);
1919
+ logger.debug("Nostr", "Legacy nametag event without extended fields:", nametag);
1813
1920
  const pubkeyTag = bindingEvent.tags.find((t) => t[0] === "pubkey");
1814
1921
  const l1Tag = bindingEvent.tags.find((t) => t[0] === "l1");
1815
1922
  if (pubkeyTag?.[1] && l1Tag?.[1]) {
@@ -1965,10 +2072,10 @@ var NostrTransportProvider = class {
1965
2072
  async recoverNametag() {
1966
2073
  this.ensureReady();
1967
2074
  if (!this.identity || !this.keyManager) {
1968
- throw new Error("Identity not set");
2075
+ throw new SphereError("Identity not set", "NOT_INITIALIZED");
1969
2076
  }
1970
2077
  const nostrPubkey = this.getNostrPubkey();
1971
- this.log("Searching for nametag events for pubkey:", nostrPubkey.slice(0, 16) + "...");
2078
+ logger.debug("Nostr", "Searching for nametag events for pubkey:", nostrPubkey.slice(0, 16) + "...");
1972
2079
  const events = await this.queryEvents({
1973
2080
  kinds: [EVENT_KINDS.NAMETAG_BINDING],
1974
2081
  authors: [nostrPubkey],
@@ -1976,7 +2083,7 @@ var NostrTransportProvider = class {
1976
2083
  // Get recent events in case of updates
1977
2084
  });
1978
2085
  if (events.length === 0) {
1979
- this.log("No nametag events found for this pubkey");
2086
+ logger.debug("Nostr", "No nametag events found for this pubkey");
1980
2087
  return null;
1981
2088
  }
1982
2089
  events.sort((a, b) => b.created_at - a.created_at);
@@ -1989,7 +2096,7 @@ var NostrTransportProvider = class {
1989
2096
  this.identity.privateKey
1990
2097
  );
1991
2098
  if (decrypted) {
1992
- this.log("Recovered nametag:", decrypted);
2099
+ logger.debug("Nostr", "Recovered nametag:", decrypted);
1993
2100
  return decrypted;
1994
2101
  }
1995
2102
  }
@@ -1997,7 +2104,7 @@ var NostrTransportProvider = class {
1997
2104
  continue;
1998
2105
  }
1999
2106
  }
2000
- this.log("Could not decrypt nametag from any event");
2107
+ logger.debug("Nostr", "Could not decrypt nametag from any event");
2001
2108
  return null;
2002
2109
  }
2003
2110
  /**
@@ -2013,7 +2120,7 @@ var NostrTransportProvider = class {
2013
2120
  async publishIdentityBinding(chainPubkey, l1Address, directAddress, nametag) {
2014
2121
  this.ensureReady();
2015
2122
  if (!this.identity) {
2016
- throw new Error("Identity not set");
2123
+ throw new SphereError("Identity not set", "NOT_INITIALIZED");
2017
2124
  }
2018
2125
  const nostrPubkey = this.getNostrPubkey();
2019
2126
  const dTagBytes = new TextEncoder().encode("unicity:identity:" + nostrPubkey);
@@ -2032,7 +2139,7 @@ var NostrTransportProvider = class {
2032
2139
  if (nametag) {
2033
2140
  const existing = await this.resolveNametag(nametag);
2034
2141
  if (existing && existing !== nostrPubkey) {
2035
- this.log("Nametag already taken:", nametag, "- owner:", existing);
2142
+ logger.debug("Nostr", "Nametag already taken:", nametag, "- owner:", existing);
2036
2143
  return false;
2037
2144
  }
2038
2145
  const { ProxyAddress } = await import("@unicitylabs/state-transition-sdk/lib/address/ProxyAddress");
@@ -2050,9 +2157,9 @@ var NostrTransportProvider = class {
2050
2157
  const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, content, tags);
2051
2158
  await this.publishEvent(event);
2052
2159
  if (nametag) {
2053
- this.log("Published identity binding with nametag:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...");
2160
+ logger.debug("Nostr", "Published identity binding with nametag:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...");
2054
2161
  } else {
2055
- this.log("Published identity binding (no nametag) for pubkey:", nostrPubkey.slice(0, 16) + "...");
2162
+ logger.debug("Nostr", "Published identity binding (no nametag) for pubkey:", nostrPubkey.slice(0, 16) + "...");
2056
2163
  }
2057
2164
  return true;
2058
2165
  }
@@ -2065,18 +2172,18 @@ var NostrTransportProvider = class {
2065
2172
  ["a", address]
2066
2173
  ]);
2067
2174
  await this.publishEvent(event);
2068
- this.log("Published nametag binding:", nametag);
2175
+ logger.debug("Nostr", "Published nametag binding:", nametag);
2069
2176
  }
2070
2177
  async registerNametag(nametag, _publicKey, directAddress = "") {
2071
2178
  this.ensureReady();
2072
2179
  if (!this.identity) {
2073
- throw new Error("Identity not set");
2180
+ throw new SphereError("Identity not set", "NOT_INITIALIZED");
2074
2181
  }
2075
2182
  const nostrPubkey = this.getNostrPubkey();
2076
2183
  const existing = await this.resolveNametag(nametag);
2077
- this.log("registerNametag:", nametag, "existing:", existing, "myPubkey:", nostrPubkey);
2184
+ logger.debug("Nostr", "registerNametag:", nametag, "existing:", existing, "myPubkey:", nostrPubkey);
2078
2185
  if (existing && existing !== nostrPubkey) {
2079
- this.log("Nametag already taken:", nametag, "- owner:", existing);
2186
+ logger.debug("Nostr", "Nametag already taken:", nametag, "- owner:", existing);
2080
2187
  return false;
2081
2188
  }
2082
2189
  const privateKeyHex = this.identity.privateKey;
@@ -2110,7 +2217,7 @@ var NostrTransportProvider = class {
2110
2217
  ];
2111
2218
  const event = await this.createEvent(EVENT_KINDS.NAMETAG_BINDING, content, tags);
2112
2219
  await this.publishEvent(event);
2113
- this.log("Registered nametag:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...", "l1:", l1Address.slice(0, 12) + "...");
2220
+ logger.debug("Nostr", "Registered nametag:", nametag, "for pubkey:", nostrPubkey.slice(0, 16) + "...", "l1:", l1Address.slice(0, 12) + "...");
2114
2221
  return true;
2115
2222
  }
2116
2223
  // Track broadcast subscriptions
@@ -2161,14 +2268,14 @@ var NostrTransportProvider = class {
2161
2268
  if (event.id) {
2162
2269
  this.processedEventIds.add(event.id);
2163
2270
  }
2164
- this.log("Processing event kind:", event.kind, "id:", event.id?.slice(0, 12));
2271
+ logger.debug("Nostr", "Processing event kind:", event.kind, "id:", event.id?.slice(0, 12));
2165
2272
  try {
2166
2273
  switch (event.kind) {
2167
2274
  case EVENT_KINDS.DIRECT_MESSAGE:
2168
2275
  await this.handleDirectMessage(event);
2169
2276
  break;
2170
2277
  case import_nostr_js_sdk.EventKinds.GIFT_WRAP:
2171
- this.log("Handling gift wrap (NIP-17 DM)");
2278
+ logger.debug("Nostr", "Handling gift wrap (NIP-17 DM)");
2172
2279
  await this.handleGiftWrap(event);
2173
2280
  break;
2174
2281
  case EVENT_KINDS.TOKEN_TRANSFER:
@@ -2191,7 +2298,7 @@ var NostrTransportProvider = class {
2191
2298
  }
2192
2299
  }
2193
2300
  } catch (error) {
2194
- this.log("Failed to handle event:", error);
2301
+ logger.debug("Nostr", "Failed to handle event:", error);
2195
2302
  }
2196
2303
  }
2197
2304
  /**
@@ -2206,25 +2313,25 @@ var NostrTransportProvider = class {
2206
2313
  const pubkey = this.keyManager.getPublicKeyHex();
2207
2314
  const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_WALLET_EVENT_TS}_${pubkey.slice(0, 16)}`;
2208
2315
  this.storage.set(storageKey, createdAt.toString()).catch((err) => {
2209
- this.log("Failed to save last event timestamp:", err);
2316
+ logger.debug("Nostr", "Failed to save last event timestamp:", err);
2210
2317
  });
2211
2318
  }
2212
2319
  async handleDirectMessage(event) {
2213
- this.log("Ignoring NIP-04 kind 4 event (DMs use NIP-17):", event.id?.slice(0, 12));
2320
+ logger.debug("Nostr", "Ignoring NIP-04 kind 4 event (DMs use NIP-17):", event.id?.slice(0, 12));
2214
2321
  }
2215
2322
  async handleGiftWrap(event) {
2216
2323
  if (!this.identity || !this.keyManager) {
2217
- this.log("handleGiftWrap: no identity/keyManager");
2324
+ logger.debug("Nostr", "handleGiftWrap: no identity/keyManager");
2218
2325
  return;
2219
2326
  }
2220
2327
  try {
2221
2328
  const pm = import_nostr_js_sdk.NIP17.unwrap(event, this.keyManager);
2222
- this.log("Gift wrap unwrapped, sender:", pm.senderPubkey?.slice(0, 16), "kind:", pm.kind);
2329
+ logger.debug("Nostr", "Gift wrap unwrapped, sender:", pm.senderPubkey?.slice(0, 16), "kind:", pm.kind);
2223
2330
  if (pm.senderPubkey === this.keyManager.getPublicKeyHex()) {
2224
2331
  try {
2225
2332
  const parsed = JSON.parse(pm.content);
2226
2333
  if (parsed?.selfWrap && parsed.recipientPubkey) {
2227
- this.log("Self-wrap replay for recipient:", parsed.recipientPubkey?.slice(0, 16));
2334
+ logger.debug("Nostr", "Self-wrap replay for recipient:", parsed.recipientPubkey?.slice(0, 16));
2228
2335
  const message2 = {
2229
2336
  id: parsed.originalId || pm.eventId,
2230
2337
  senderTransportPubkey: pm.senderPubkey,
@@ -2239,18 +2346,18 @@ var NostrTransportProvider = class {
2239
2346
  try {
2240
2347
  handler(message2);
2241
2348
  } catch (e) {
2242
- this.log("Self-wrap handler error:", e);
2349
+ logger.debug("Nostr", "Self-wrap handler error:", e);
2243
2350
  }
2244
2351
  }
2245
2352
  return;
2246
2353
  }
2247
2354
  } catch {
2248
2355
  }
2249
- this.log("Skipping own non-self-wrap message");
2356
+ logger.debug("Nostr", "Skipping own non-self-wrap message");
2250
2357
  return;
2251
2358
  }
2252
2359
  if ((0, import_nostr_js_sdk.isReadReceipt)(pm)) {
2253
- this.log("Read receipt from:", pm.senderPubkey?.slice(0, 16), "for:", pm.replyToEventId);
2360
+ logger.debug("Nostr", "Read receipt from:", pm.senderPubkey?.slice(0, 16), "for:", pm.replyToEventId);
2254
2361
  if (pm.replyToEventId) {
2255
2362
  const receipt = {
2256
2363
  senderTransportPubkey: pm.senderPubkey,
@@ -2261,7 +2368,7 @@ var NostrTransportProvider = class {
2261
2368
  try {
2262
2369
  handler(receipt);
2263
2370
  } catch (e) {
2264
- this.log("Read receipt handler error:", e);
2371
+ logger.debug("Nostr", "Read receipt handler error:", e);
2265
2372
  }
2266
2373
  }
2267
2374
  }
@@ -2281,12 +2388,12 @@ var NostrTransportProvider = class {
2281
2388
  senderNametag: senderNametag2,
2282
2389
  expiresIn
2283
2390
  };
2284
- this.log("Composing indicator from:", indicator.senderNametag || pm.senderPubkey?.slice(0, 16));
2391
+ logger.debug("Nostr", "Composing indicator from:", indicator.senderNametag || pm.senderPubkey?.slice(0, 16));
2285
2392
  for (const handler of this.composingHandlers) {
2286
2393
  try {
2287
2394
  handler(indicator);
2288
2395
  } catch (e) {
2289
- this.log("Composing handler error:", e);
2396
+ logger.debug("Nostr", "Composing handler error:", e);
2290
2397
  }
2291
2398
  }
2292
2399
  return;
@@ -2294,7 +2401,7 @@ var NostrTransportProvider = class {
2294
2401
  try {
2295
2402
  const parsed = JSON.parse(pm.content);
2296
2403
  if (parsed?.type === "typing") {
2297
- this.log("Typing indicator from:", pm.senderPubkey?.slice(0, 16));
2404
+ logger.debug("Nostr", "Typing indicator from:", pm.senderPubkey?.slice(0, 16));
2298
2405
  const indicator = {
2299
2406
  senderTransportPubkey: pm.senderPubkey,
2300
2407
  senderNametag: parsed.senderNametag,
@@ -2304,7 +2411,7 @@ var NostrTransportProvider = class {
2304
2411
  try {
2305
2412
  handler(indicator);
2306
2413
  } catch (e) {
2307
- this.log("Typing handler error:", e);
2414
+ logger.debug("Nostr", "Typing handler error:", e);
2308
2415
  }
2309
2416
  }
2310
2417
  return;
@@ -2312,7 +2419,7 @@ var NostrTransportProvider = class {
2312
2419
  } catch {
2313
2420
  }
2314
2421
  if (!(0, import_nostr_js_sdk.isChatMessage)(pm)) {
2315
- this.log("Skipping unknown message kind:", pm.kind);
2422
+ logger.debug("Nostr", "Skipping unknown message kind:", pm.kind);
2316
2423
  return;
2317
2424
  }
2318
2425
  let content = pm.content;
@@ -2325,7 +2432,7 @@ var NostrTransportProvider = class {
2325
2432
  }
2326
2433
  } catch {
2327
2434
  }
2328
- this.log("DM received from:", senderNametag || pm.senderPubkey?.slice(0, 16), "content:", content?.slice(0, 50));
2435
+ logger.debug("Nostr", "DM received from:", senderNametag || pm.senderPubkey?.slice(0, 16), "content:", content?.slice(0, 50));
2329
2436
  const message = {
2330
2437
  // Use outer gift wrap event.id so it matches the sender's stored giftWrap.id.
2331
2438
  // This ensures read receipts reference an ID the sender recognizes.
@@ -2338,20 +2445,20 @@ var NostrTransportProvider = class {
2338
2445
  };
2339
2446
  this.emitEvent({ type: "message:received", timestamp: Date.now() });
2340
2447
  if (this.messageHandlers.size === 0) {
2341
- this.log("No message handlers registered, buffering message for later delivery");
2448
+ logger.debug("Nostr", "No message handlers registered, buffering message for later delivery");
2342
2449
  this.pendingMessages.push(message);
2343
2450
  } else {
2344
- this.log("Dispatching to", this.messageHandlers.size, "handlers");
2451
+ logger.debug("Nostr", "Dispatching to", this.messageHandlers.size, "handlers");
2345
2452
  for (const handler of this.messageHandlers) {
2346
2453
  try {
2347
2454
  handler(message);
2348
2455
  } catch (error) {
2349
- this.log("Message handler error:", error);
2456
+ logger.debug("Nostr", "Message handler error:", error);
2350
2457
  }
2351
2458
  }
2352
2459
  }
2353
2460
  } catch (err) {
2354
- this.log("Gift wrap decrypt failed (expected if not for us):", err?.message?.slice(0, 50));
2461
+ logger.debug("Nostr", "Gift wrap decrypt failed (expected if not for us):", err?.message?.slice(0, 50));
2355
2462
  }
2356
2463
  }
2357
2464
  async handleTokenTransfer(event) {
@@ -2369,7 +2476,7 @@ var NostrTransportProvider = class {
2369
2476
  try {
2370
2477
  await handler(transfer);
2371
2478
  } catch (error) {
2372
- this.log("Transfer handler error:", error);
2479
+ logger.debug("Nostr", "Transfer handler error:", error);
2373
2480
  }
2374
2481
  }
2375
2482
  }
@@ -2392,16 +2499,16 @@ var NostrTransportProvider = class {
2392
2499
  },
2393
2500
  timestamp: event.created_at * 1e3
2394
2501
  };
2395
- this.log("Received payment request:", request.id);
2502
+ logger.debug("Nostr", "Received payment request:", request.id);
2396
2503
  for (const handler of this.paymentRequestHandlers) {
2397
2504
  try {
2398
2505
  handler(request);
2399
2506
  } catch (error) {
2400
- this.log("Payment request handler error:", error);
2507
+ logger.debug("Nostr", "Payment request handler error:", error);
2401
2508
  }
2402
2509
  }
2403
2510
  } catch (error) {
2404
- this.log("Failed to handle payment request:", error);
2511
+ logger.debug("Nostr", "Failed to handle payment request:", error);
2405
2512
  }
2406
2513
  }
2407
2514
  async handlePaymentRequestResponse(event) {
@@ -2420,16 +2527,16 @@ var NostrTransportProvider = class {
2420
2527
  },
2421
2528
  timestamp: event.created_at * 1e3
2422
2529
  };
2423
- this.log("Received payment request response:", response.id, "type:", responseData.responseType);
2530
+ logger.debug("Nostr", "Received payment request response:", response.id, "type:", responseData.responseType);
2424
2531
  for (const handler of this.paymentRequestResponseHandlers) {
2425
2532
  try {
2426
2533
  handler(response);
2427
2534
  } catch (error) {
2428
- this.log("Payment request response handler error:", error);
2535
+ logger.debug("Nostr", "Payment request response handler error:", error);
2429
2536
  }
2430
2537
  }
2431
2538
  } catch (error) {
2432
- this.log("Failed to handle payment request response:", error);
2539
+ logger.debug("Nostr", "Failed to handle payment request response:", error);
2433
2540
  }
2434
2541
  }
2435
2542
  handleBroadcast(event) {
@@ -2448,7 +2555,7 @@ var NostrTransportProvider = class {
2448
2555
  try {
2449
2556
  handler(broadcast);
2450
2557
  } catch (error) {
2451
- this.log("Broadcast handler error:", error);
2558
+ logger.debug("Nostr", "Broadcast handler error:", error);
2452
2559
  }
2453
2560
  }
2454
2561
  }
@@ -2458,8 +2565,8 @@ var NostrTransportProvider = class {
2458
2565
  // Private: Event Creation & Publishing
2459
2566
  // ===========================================================================
2460
2567
  async createEvent(kind, content, tags) {
2461
- if (!this.identity) throw new Error("Identity not set");
2462
- if (!this.keyManager) throw new Error("KeyManager not initialized");
2568
+ if (!this.identity) throw new SphereError("Identity not set", "NOT_INITIALIZED");
2569
+ if (!this.keyManager) throw new SphereError("KeyManager not initialized", "NOT_INITIALIZED");
2463
2570
  const signedEvent = import_nostr_js_sdk.Event.create(this.keyManager, {
2464
2571
  kind,
2465
2572
  content,
@@ -2477,10 +2584,10 @@ var NostrTransportProvider = class {
2477
2584
  return event;
2478
2585
  }
2479
2586
  async createEncryptedEvent(kind, content, tags) {
2480
- if (!this.keyManager) throw new Error("KeyManager not initialized");
2587
+ if (!this.keyManager) throw new SphereError("KeyManager not initialized", "NOT_INITIALIZED");
2481
2588
  const recipientTag = tags.find((t) => t[0] === "p");
2482
2589
  if (!recipientTag || !recipientTag[1]) {
2483
- throw new Error("No recipient pubkey in tags for encryption");
2590
+ throw new SphereError("No recipient pubkey in tags for encryption", "VALIDATION_ERROR");
2484
2591
  }
2485
2592
  const recipientPubkey = recipientTag[1];
2486
2593
  const encrypted = await import_nostr_js_sdk.NIP04.encryptHex(
@@ -2492,14 +2599,14 @@ var NostrTransportProvider = class {
2492
2599
  }
2493
2600
  async publishEvent(event) {
2494
2601
  if (!this.nostrClient) {
2495
- throw new Error("NostrClient not initialized");
2602
+ throw new SphereError("NostrClient not initialized", "NOT_INITIALIZED");
2496
2603
  }
2497
2604
  const sdkEvent = import_nostr_js_sdk.Event.fromJSON(event);
2498
2605
  await this.nostrClient.publishEvent(sdkEvent);
2499
2606
  }
2500
2607
  async fetchPendingEvents() {
2501
2608
  if (!this.nostrClient?.isConnected() || !this.keyManager) {
2502
- throw new Error("Transport not connected");
2609
+ throw new SphereError("Transport not connected", "TRANSPORT_ERROR");
2503
2610
  }
2504
2611
  const nostrPubkey = this.keyManager.getPublicKeyHex();
2505
2612
  const walletFilter = new import_nostr_js_sdk.Filter();
@@ -2542,7 +2649,7 @@ var NostrTransportProvider = class {
2542
2649
  }
2543
2650
  async queryEvents(filterObj) {
2544
2651
  if (!this.nostrClient || !this.nostrClient.isConnected()) {
2545
- throw new Error("No connected relays");
2652
+ throw new SphereError("No connected relays", "TRANSPORT_ERROR");
2546
2653
  }
2547
2654
  const events = [];
2548
2655
  const filter = new import_nostr_js_sdk.Filter(filterObj);
@@ -2551,6 +2658,7 @@ var NostrTransportProvider = class {
2551
2658
  if (subId) {
2552
2659
  this.nostrClient?.unsubscribe(subId);
2553
2660
  }
2661
+ logger.warn("Nostr", `queryEvents timed out after 5s, returning ${events.length} event(s)`, { kinds: filterObj.kinds, limit: filterObj.limit });
2554
2662
  resolve(events);
2555
2663
  }, 5e3);
2556
2664
  const subId = this.nostrClient.subscribe(filter, {
@@ -2580,9 +2688,9 @@ var NostrTransportProvider = class {
2580
2688
  walletSubscriptionId = null;
2581
2689
  chatSubscriptionId = null;
2582
2690
  async subscribeToEvents() {
2583
- this.log("subscribeToEvents called, identity:", !!this.identity, "keyManager:", !!this.keyManager, "nostrClient:", !!this.nostrClient);
2691
+ logger.debug("Nostr", "subscribeToEvents called, identity:", !!this.identity, "keyManager:", !!this.keyManager, "nostrClient:", !!this.nostrClient);
2584
2692
  if (!this.identity || !this.keyManager || !this.nostrClient) {
2585
- this.log("subscribeToEvents: skipped - no identity, keyManager, or nostrClient");
2693
+ logger.debug("Nostr", "subscribeToEvents: skipped - no identity, keyManager, or nostrClient");
2586
2694
  return;
2587
2695
  }
2588
2696
  if (this.walletSubscriptionId) {
@@ -2598,7 +2706,7 @@ var NostrTransportProvider = class {
2598
2706
  this.mainSubscriptionId = null;
2599
2707
  }
2600
2708
  const nostrPubkey = this.keyManager.getPublicKeyHex();
2601
- this.log("Subscribing with Nostr pubkey:", nostrPubkey);
2709
+ logger.debug("Nostr", "Subscribing with Nostr pubkey:", nostrPubkey);
2602
2710
  let since;
2603
2711
  if (this.storage) {
2604
2712
  const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_WALLET_EVENT_TS}_${nostrPubkey.slice(0, 16)}`;
@@ -2607,18 +2715,18 @@ var NostrTransportProvider = class {
2607
2715
  if (stored) {
2608
2716
  since = parseInt(stored, 10);
2609
2717
  this.lastEventTs = since;
2610
- this.log("Resuming from stored event timestamp:", since);
2718
+ logger.debug("Nostr", "Resuming from stored event timestamp:", since);
2611
2719
  } else {
2612
2720
  since = Math.floor(Date.now() / 1e3);
2613
- this.log("No stored timestamp, starting from now:", since);
2721
+ logger.debug("Nostr", "No stored timestamp, starting from now:", since);
2614
2722
  }
2615
2723
  } catch (err) {
2616
- this.log("Failed to read last event timestamp, falling back to now:", err);
2724
+ logger.debug("Nostr", "Failed to read last event timestamp, falling back to now:", err);
2617
2725
  since = Math.floor(Date.now() / 1e3);
2618
2726
  }
2619
2727
  } else {
2620
2728
  since = Math.floor(Date.now() / 1e3) - 86400;
2621
- this.log("No storage adapter, using 24h fallback");
2729
+ logger.debug("Nostr", "No storage adapter, using 24h fallback");
2622
2730
  }
2623
2731
  const walletFilter = new import_nostr_js_sdk.Filter();
2624
2732
  walletFilter.kinds = [
@@ -2631,7 +2739,7 @@ var NostrTransportProvider = class {
2631
2739
  walletFilter.since = since;
2632
2740
  this.walletSubscriptionId = this.nostrClient.subscribe(walletFilter, {
2633
2741
  onEvent: (event) => {
2634
- this.log("Received wallet event kind:", event.kind, "id:", event.id?.slice(0, 12));
2742
+ logger.debug("Nostr", "Received wallet event kind:", event.kind, "id:", event.id?.slice(0, 12));
2635
2743
  this.handleEvent({
2636
2744
  id: event.id,
2637
2745
  kind: event.kind,
@@ -2643,19 +2751,19 @@ var NostrTransportProvider = class {
2643
2751
  });
2644
2752
  },
2645
2753
  onEndOfStoredEvents: () => {
2646
- this.log("Wallet subscription ready (EOSE)");
2754
+ logger.debug("Nostr", "Wallet subscription ready (EOSE)");
2647
2755
  },
2648
2756
  onError: (_subId, error) => {
2649
- this.log("Wallet subscription error:", error);
2757
+ logger.debug("Nostr", "Wallet subscription error:", error);
2650
2758
  }
2651
2759
  });
2652
- this.log("Wallet subscription created, subId:", this.walletSubscriptionId);
2760
+ logger.debug("Nostr", "Wallet subscription created, subId:", this.walletSubscriptionId);
2653
2761
  const chatFilter = new import_nostr_js_sdk.Filter();
2654
2762
  chatFilter.kinds = [import_nostr_js_sdk.EventKinds.GIFT_WRAP];
2655
2763
  chatFilter["#p"] = [nostrPubkey];
2656
2764
  this.chatSubscriptionId = this.nostrClient.subscribe(chatFilter, {
2657
2765
  onEvent: (event) => {
2658
- this.log("Received chat event kind:", event.kind, "id:", event.id?.slice(0, 12));
2766
+ logger.debug("Nostr", "Received chat event kind:", event.kind, "id:", event.id?.slice(0, 12));
2659
2767
  this.handleEvent({
2660
2768
  id: event.id,
2661
2769
  kind: event.kind,
@@ -2667,13 +2775,13 @@ var NostrTransportProvider = class {
2667
2775
  });
2668
2776
  },
2669
2777
  onEndOfStoredEvents: () => {
2670
- this.log("Chat subscription ready (EOSE)");
2778
+ logger.debug("Nostr", "Chat subscription ready (EOSE)");
2671
2779
  },
2672
2780
  onError: (_subId, error) => {
2673
- this.log("Chat subscription error:", error);
2781
+ logger.debug("Nostr", "Chat subscription error:", error);
2674
2782
  }
2675
2783
  });
2676
- this.log("Chat subscription created, subId:", this.chatSubscriptionId);
2784
+ logger.debug("Nostr", "Chat subscription created, subId:", this.chatSubscriptionId);
2677
2785
  }
2678
2786
  subscribeToTags(tags) {
2679
2787
  if (!this.nostrClient) return;
@@ -2703,7 +2811,7 @@ var NostrTransportProvider = class {
2703
2811
  // Private: Encryption
2704
2812
  // ===========================================================================
2705
2813
  async decryptContent(content, senderPubkey) {
2706
- if (!this.keyManager) throw new Error("KeyManager not initialized");
2814
+ if (!this.keyManager) throw new SphereError("KeyManager not initialized", "NOT_INITIALIZED");
2707
2815
  const decrypted = await import_nostr_js_sdk.NIP04.decryptHex(
2708
2816
  content,
2709
2817
  this.keyManager.getPrivateKeyHex(),
@@ -2733,13 +2841,13 @@ var NostrTransportProvider = class {
2733
2841
  // ===========================================================================
2734
2842
  ensureConnected() {
2735
2843
  if (!this.isConnected()) {
2736
- throw new Error("NostrTransportProvider not connected");
2844
+ throw new SphereError("NostrTransportProvider not connected", "TRANSPORT_ERROR");
2737
2845
  }
2738
2846
  }
2739
2847
  ensureReady() {
2740
2848
  this.ensureConnected();
2741
2849
  if (!this.identity) {
2742
- throw new Error("Identity not set");
2850
+ throw new SphereError("Identity not set", "NOT_INITIALIZED");
2743
2851
  }
2744
2852
  }
2745
2853
  emitEvent(event) {
@@ -2747,7 +2855,7 @@ var NostrTransportProvider = class {
2747
2855
  try {
2748
2856
  callback(event);
2749
2857
  } catch (error) {
2750
- this.log("Event callback error:", error);
2858
+ logger.debug("Nostr", "Event callback error:", error);
2751
2859
  }
2752
2860
  }
2753
2861
  }
@@ -2784,11 +2892,6 @@ var NostrTransportProvider = class {
2784
2892
  ephemeralKeys.clear();
2785
2893
  return giftWrap;
2786
2894
  }
2787
- log(...args) {
2788
- if (this.config.debug) {
2789
- console.log("[NostrTransportProvider]", ...args);
2790
- }
2791
- }
2792
2895
  };
2793
2896
 
2794
2897
  // impl/nodejs/transport/index.ts
@@ -2977,7 +3080,8 @@ var UnicityAggregatorProvider = class {
2977
3080
  proof: response.proof,
2978
3081
  timestamp: Date.now()
2979
3082
  };
2980
- } catch {
3083
+ } catch (error) {
3084
+ logger.warn("Aggregator", "getProof failed", error);
2981
3085
  return null;
2982
3086
  }
2983
3087
  }
@@ -2999,7 +3103,7 @@ var UnicityAggregatorProvider = class {
2999
3103
  }
3000
3104
  await new Promise((resolve) => setTimeout(resolve, pollInterval));
3001
3105
  }
3002
- throw new Error(`Timeout waiting for proof: ${requestId}`);
3106
+ throw new SphereError(`Timeout waiting for proof: ${requestId}`, "TIMEOUT");
3003
3107
  }
3004
3108
  async validateToken(tokenData) {
3005
3109
  this.ensureConnected();
@@ -3058,7 +3162,7 @@ var UnicityAggregatorProvider = class {
3058
3162
  async waitForProofSdk(commitment, signal) {
3059
3163
  this.ensureConnected();
3060
3164
  if (!this.trustBase) {
3061
- throw new Error("Trust base not initialized");
3165
+ throw new SphereError("Trust base not initialized", "NOT_INITIALIZED");
3062
3166
  }
3063
3167
  return await (0, import_InclusionProofUtils.waitInclusionProof)(
3064
3168
  this.trustBase,
@@ -3080,7 +3184,8 @@ var UnicityAggregatorProvider = class {
3080
3184
  this.spentCache.set(stateHash, true);
3081
3185
  }
3082
3186
  return spent;
3083
- } catch {
3187
+ } catch (error) {
3188
+ logger.warn("Aggregator", "isSpent check failed, assuming unspent", error);
3084
3189
  return false;
3085
3190
  }
3086
3191
  }
@@ -3098,7 +3203,8 @@ var UnicityAggregatorProvider = class {
3098
3203
  roundNumber: response.state.roundNumber,
3099
3204
  lastUpdated: Date.now()
3100
3205
  };
3101
- } catch {
3206
+ } catch (error) {
3207
+ logger.warn("Aggregator", "getTokenState failed", error);
3102
3208
  return null;
3103
3209
  }
3104
3210
  }
@@ -3158,11 +3264,11 @@ var UnicityAggregatorProvider = class {
3158
3264
  signal: controller.signal
3159
3265
  });
3160
3266
  if (!response.ok) {
3161
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
3267
+ throw new SphereError(`HTTP ${response.status}: ${response.statusText}`, "AGGREGATOR_ERROR");
3162
3268
  }
3163
3269
  const result = await response.json();
3164
3270
  if (result.error) {
3165
- throw new Error(result.error.message ?? "RPC error");
3271
+ throw new SphereError(result.error.message ?? "RPC error", "AGGREGATOR_ERROR");
3166
3272
  }
3167
3273
  return result.result ?? {};
3168
3274
  } finally {
@@ -3174,7 +3280,7 @@ var UnicityAggregatorProvider = class {
3174
3280
  // ===========================================================================
3175
3281
  ensureConnected() {
3176
3282
  if (this.status !== "connected") {
3177
- throw new Error("UnicityAggregatorProvider not connected");
3283
+ throw new SphereError("UnicityAggregatorProvider not connected", "NOT_INITIALIZED");
3178
3284
  }
3179
3285
  }
3180
3286
  emitEvent(event) {
@@ -3186,10 +3292,8 @@ var UnicityAggregatorProvider = class {
3186
3292
  }
3187
3293
  }
3188
3294
  }
3189
- log(...args) {
3190
- if (this.config.debug) {
3191
- console.log("[UnicityAggregatorProvider]", ...args);
3192
- }
3295
+ log(message, ...args) {
3296
+ logger.debug("Aggregator", message, ...args);
3193
3297
  }
3194
3298
  };
3195
3299
  var UnicityOracleProvider = UnicityAggregatorProvider;
@@ -3720,7 +3824,10 @@ var IpfsHttpClient = class {
3720
3824
  { headers: { Accept: "application/octet-stream" } }
3721
3825
  );
3722
3826
  if (!response.ok) {
3723
- const body = await response.text().catch(() => "");
3827
+ const body = await response.text().catch((err) => {
3828
+ logger.debug("IPFS-HTTP", "Failed to read error response body", err);
3829
+ return "";
3830
+ });
3724
3831
  throw new IpfsError(
3725
3832
  `Fetch failed: HTTP ${response.status}`,
3726
3833
  classifyHttpStatus(response.status, body),
@@ -3766,7 +3873,10 @@ var IpfsHttpClient = class {
3766
3873
  { method: "POST" }
3767
3874
  );
3768
3875
  if (!response.ok) {
3769
- const body = await response.text().catch(() => "");
3876
+ const body = await response.text().catch((err) => {
3877
+ logger.debug("IPFS-HTTP", "Failed to read error response body", err);
3878
+ return "";
3879
+ });
3770
3880
  const category = classifyHttpStatus(response.status, body);
3771
3881
  if (category === "NOT_FOUND") return null;
3772
3882
  throw new IpfsError(`Routing API: HTTP ${response.status}`, category, gateway);
@@ -3812,7 +3922,8 @@ var IpfsHttpClient = class {
3812
3922
  }
3813
3923
  }
3814
3924
  return { cid: "", content };
3815
- } catch {
3925
+ } catch (err) {
3926
+ logger.debug("IPFS-HTTP", "IPNS gateway resolution failed", err);
3816
3927
  return null;
3817
3928
  }
3818
3929
  }
@@ -3877,7 +3988,10 @@ var IpfsHttpClient = class {
3877
3988
  { method: "POST", body: formData }
3878
3989
  );
3879
3990
  if (!response.ok) {
3880
- const errorText = await response.text().catch(() => "");
3991
+ const errorText = await response.text().catch((err) => {
3992
+ logger.debug("IPFS-HTTP", "Failed to read error response body", err);
3993
+ return "";
3994
+ });
3881
3995
  throw new IpfsError(
3882
3996
  `IPNS publish: HTTP ${response.status}: ${errorText.slice(0, 100)}`,
3883
3997
  classifyHttpStatus(response.status, errorText),
@@ -3954,9 +4068,7 @@ var IpfsHttpClient = class {
3954
4068
  }
3955
4069
  }
3956
4070
  log(message) {
3957
- if (this.debug) {
3958
- console.log(`[IPFS-HTTP] ${message}`);
3959
- }
4071
+ logger.debug("IPFS-HTTP", message);
3960
4072
  }
3961
4073
  };
3962
4074
 
@@ -4400,10 +4512,12 @@ var IpnsSubscriptionClient = class {
4400
4512
  startFallbackPolling() {
4401
4513
  if (this.fallbackPollInterval || !this.fallbackPollFn || this.destroyed) return;
4402
4514
  this.log(`Starting fallback polling (${this.fallbackPollIntervalMs / 1e3}s interval)`);
4403
- this.fallbackPollFn().catch(() => {
4515
+ this.fallbackPollFn().catch((err) => {
4516
+ logger.warn("IPNS-WS", "Fallback poll error:", err);
4404
4517
  });
4405
4518
  this.fallbackPollInterval = setInterval(() => {
4406
- this.fallbackPollFn?.().catch(() => {
4519
+ this.fallbackPollFn?.().catch((err) => {
4520
+ logger.warn("IPNS-WS", "Fallback poll error:", err);
4407
4521
  });
4408
4522
  }, this.fallbackPollIntervalMs);
4409
4523
  }
@@ -4417,9 +4531,7 @@ var IpnsSubscriptionClient = class {
4417
4531
  // Internal: Logging
4418
4532
  // ---------------------------------------------------------------------------
4419
4533
  log(message) {
4420
- if (this.debugEnabled) {
4421
- console.log(`[IPNS-WS] ${message}`);
4422
- }
4534
+ logger.debug("IPNS-WS", message);
4423
4535
  }
4424
4536
  };
4425
4537
 
@@ -4608,7 +4720,8 @@ var IpfsStorageProvider = class {
4608
4720
  } else {
4609
4721
  this.log("Warning: no healthy gateways found");
4610
4722
  }
4611
- }).catch(() => {
4723
+ }).catch((err) => {
4724
+ logger.warn("IPFS-Storage", "Gateway health check failed (non-fatal):", err);
4612
4725
  });
4613
4726
  this.isShuttingDown = false;
4614
4727
  this.status = "connected";
@@ -4772,7 +4885,7 @@ var IpfsStorageProvider = class {
4772
4885
  };
4773
4886
  const result = await this._doSave(baseData);
4774
4887
  if (!result.success) {
4775
- throw new Error(result.error ?? "Save failed");
4888
+ throw new SphereError(result.error ?? "Save failed", "STORAGE_ERROR");
4776
4889
  }
4777
4890
  this.log(`Flushed successfully: CID=${result.cid}`);
4778
4891
  } catch (error) {
@@ -5012,10 +5125,12 @@ var IpfsStorageProvider = class {
5012
5125
  if (this.flushTimer) {
5013
5126
  clearTimeout(this.flushTimer);
5014
5127
  this.flushTimer = null;
5015
- await this.flushQueue.enqueue(() => this.executeFlush()).catch(() => {
5128
+ await this.flushQueue.enqueue(() => this.executeFlush()).catch((err) => {
5129
+ logger.warn("IPFS-Storage", "Flush on shutdown failed:", err);
5016
5130
  });
5017
5131
  } else if (!this.pendingBuffer.isEmpty) {
5018
- await this.flushQueue.enqueue(() => this.executeFlush()).catch(() => {
5132
+ await this.flushQueue.enqueue(() => this.executeFlush()).catch((err) => {
5133
+ logger.warn("IPFS-Storage", "Flush on shutdown failed:", err);
5019
5134
  });
5020
5135
  } else {
5021
5136
  await this.flushQueue.enqueue(async () => {
@@ -5069,9 +5184,7 @@ var IpfsStorageProvider = class {
5069
5184
  }
5070
5185
  }
5071
5186
  log(message) {
5072
- if (this.debug) {
5073
- console.log(`[IPFS-Storage] ${message}`);
5074
- }
5187
+ logger.debug("IPFS-Storage", message);
5075
5188
  }
5076
5189
  };
5077
5190
 
@@ -5181,7 +5294,7 @@ var CoinGeckoPriceProvider = class {
5181
5294
  const allCovered = uncachedNames.every((n) => this.fetchNames.has(n));
5182
5295
  if (allCovered) {
5183
5296
  if (this.debug) {
5184
- console.log(`[CoinGecko] Deduplicating request, reusing in-flight fetch`);
5297
+ logger.debug("CoinGecko", "Deduplicating request, reusing in-flight fetch");
5185
5298
  }
5186
5299
  const fetched = await this.fetchPromise;
5187
5300
  for (const name of uncachedNames) {
@@ -5220,7 +5333,7 @@ var CoinGeckoPriceProvider = class {
5220
5333
  headers["x-cg-pro-api-key"] = this.apiKey;
5221
5334
  }
5222
5335
  if (this.debug) {
5223
- console.log(`[CoinGecko] Fetching prices for: ${uncachedNames.join(", ")}`);
5336
+ logger.debug("CoinGecko", `Fetching prices for: ${uncachedNames.join(", ")}`);
5224
5337
  }
5225
5338
  const response = await fetch(url, {
5226
5339
  headers,
@@ -5230,7 +5343,7 @@ var CoinGeckoPriceProvider = class {
5230
5343
  if (response.status === 429) {
5231
5344
  this.extendCacheOnRateLimit(uncachedNames);
5232
5345
  }
5233
- throw new Error(`CoinGecko API error: ${response.status} ${response.statusText}`);
5346
+ throw new SphereError(`CoinGecko API error: ${response.status} ${response.statusText}`, "NETWORK_ERROR");
5234
5347
  }
5235
5348
  const data = await response.json();
5236
5349
  for (const [name, values] of Object.entries(data)) {
@@ -5260,12 +5373,12 @@ var CoinGeckoPriceProvider = class {
5260
5373
  }
5261
5374
  }
5262
5375
  if (this.debug) {
5263
- console.log(`[CoinGecko] Fetched ${result.size} prices`);
5376
+ logger.debug("CoinGecko", `Fetched ${result.size} prices`);
5264
5377
  }
5265
5378
  this.saveToStorage();
5266
5379
  } catch (error) {
5267
5380
  if (this.debug) {
5268
- console.warn("[CoinGecko] Fetch failed, using stale cache:", error);
5381
+ logger.warn("CoinGecko", "Fetch failed, using stale cache:", error);
5269
5382
  }
5270
5383
  for (const name of uncachedNames) {
5271
5384
  const stale = this.cache.get(name);
@@ -5315,7 +5428,7 @@ var CoinGeckoPriceProvider = class {
5315
5428
  }
5316
5429
  }
5317
5430
  if (this.debug) {
5318
- console.log(`[CoinGecko] Loaded ${Object.keys(data).length} prices from persistent cache`);
5431
+ logger.debug("CoinGecko", `Loaded ${Object.keys(data).length} prices from persistent cache`);
5319
5432
  }
5320
5433
  } catch {
5321
5434
  }
@@ -5332,8 +5445,7 @@ var CoinGeckoPriceProvider = class {
5332
5445
  Promise.all([
5333
5446
  this.storage.set(STORAGE_KEYS_GLOBAL.PRICE_CACHE, JSON.stringify(data)),
5334
5447
  this.storage.set(STORAGE_KEYS_GLOBAL.PRICE_CACHE_TS, String(Date.now()))
5335
- ]).catch(() => {
5336
- });
5448
+ ]).catch((err) => logger.debug("Price", "Cache save failed (non-critical)", err));
5337
5449
  }
5338
5450
  // ===========================================================================
5339
5451
  // Rate-limit handling
@@ -5352,7 +5464,7 @@ var CoinGeckoPriceProvider = class {
5352
5464
  }
5353
5465
  }
5354
5466
  if (this.debug) {
5355
- console.warn(`[CoinGecko] Rate-limited (429), extended cache TTL by ${backoffMs / 1e3}s`);
5467
+ logger.warn("CoinGecko", `Rate-limited (429), extended cache TTL by ${backoffMs / 1e3}s`);
5356
5468
  }
5357
5469
  }
5358
5470
  async getPrice(tokenName) {
@@ -5370,7 +5482,7 @@ function createPriceProvider(config) {
5370
5482
  case "coingecko":
5371
5483
  return new CoinGeckoPriceProvider(config);
5372
5484
  default:
5373
- throw new Error(`Unsupported price platform: ${String(config.platform)}`);
5485
+ throw new SphereError(`Unsupported price platform: ${String(config.platform)}`, "INVALID_CONFIG");
5374
5486
  }
5375
5487
  }
5376
5488
 
@@ -5595,14 +5707,12 @@ var TokenRegistry = class _TokenRegistry {
5595
5707
  clearTimeout(timer);
5596
5708
  }
5597
5709
  if (!response.ok) {
5598
- console.warn(
5599
- `[TokenRegistry] Remote fetch failed: HTTP ${response.status} ${response.statusText}`
5600
- );
5710
+ logger.warn("TokenRegistry", `Remote fetch failed: HTTP ${response.status} ${response.statusText}`);
5601
5711
  return false;
5602
5712
  }
5603
5713
  const data = await response.json();
5604
5714
  if (!this.isValidDefinitionsArray(data)) {
5605
- console.warn("[TokenRegistry] Remote data is not a valid token definitions array");
5715
+ logger.warn("TokenRegistry", "Remote data is not a valid token definitions array");
5606
5716
  return false;
5607
5717
  }
5608
5718
  const definitions = data;
@@ -5612,7 +5722,7 @@ var TokenRegistry = class _TokenRegistry {
5612
5722
  return true;
5613
5723
  } catch (error) {
5614
5724
  const message = error instanceof Error ? error.message : String(error);
5615
- console.warn(`[TokenRegistry] Remote refresh failed: ${message}`);
5725
+ logger.warn("TokenRegistry", `Remote refresh failed: ${message}`);
5616
5726
  return false;
5617
5727
  }
5618
5728
  }
@@ -5859,6 +5969,11 @@ function resolveMarketConfig(config) {
5859
5969
  // impl/nodejs/index.ts
5860
5970
  function createNodeProviders(config) {
5861
5971
  const network = config?.network ?? "mainnet";
5972
+ const globalDebug = config?.debug ?? false;
5973
+ logger.configure({ debug: globalDebug });
5974
+ if (config?.transport?.debug) logger.setTagDebug("Nostr", true);
5975
+ if (config?.oracle?.debug) logger.setTagDebug("Aggregator", true);
5976
+ if (config?.price?.debug) logger.setTagDebug("Price", true);
5862
5977
  const transportConfig = resolveTransportConfig(network, config?.transport);
5863
5978
  const oracleConfig = resolveOracleConfig(network, config?.oracle);
5864
5979
  const l1Config = resolveL1Config(network, config?.l1);