@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
@@ -1,3 +1,107 @@
1
+ // core/logger.ts
2
+ var LOGGER_KEY = "__sphere_sdk_logger__";
3
+ function getState() {
4
+ const g = globalThis;
5
+ if (!g[LOGGER_KEY]) {
6
+ g[LOGGER_KEY] = { debug: false, tags: {}, handler: null };
7
+ }
8
+ return g[LOGGER_KEY];
9
+ }
10
+ function isEnabled(tag) {
11
+ const state = getState();
12
+ if (tag in state.tags) return state.tags[tag];
13
+ return state.debug;
14
+ }
15
+ var logger = {
16
+ /**
17
+ * Configure the logger. Can be called multiple times (last write wins).
18
+ * Typically called by createBrowserProviders(), createNodeProviders(), or Sphere.init().
19
+ */
20
+ configure(config) {
21
+ const state = getState();
22
+ if (config.debug !== void 0) state.debug = config.debug;
23
+ if (config.handler !== void 0) state.handler = config.handler;
24
+ },
25
+ /**
26
+ * Enable/disable debug logging for a specific tag.
27
+ * Per-tag setting overrides the global debug flag.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * logger.setTagDebug('Nostr', true); // enable only Nostr logs
32
+ * logger.setTagDebug('Nostr', false); // disable Nostr logs even if global debug=true
33
+ * ```
34
+ */
35
+ setTagDebug(tag, enabled) {
36
+ getState().tags[tag] = enabled;
37
+ },
38
+ /**
39
+ * Clear per-tag override, falling back to global debug flag.
40
+ */
41
+ clearTagDebug(tag) {
42
+ delete getState().tags[tag];
43
+ },
44
+ /** Returns true if debug mode is enabled for the given tag (or globally). */
45
+ isDebugEnabled(tag) {
46
+ if (tag) return isEnabled(tag);
47
+ return getState().debug;
48
+ },
49
+ /**
50
+ * Debug-level log. Only shown when debug is enabled (globally or for this tag).
51
+ * Use for detailed operational information.
52
+ */
53
+ debug(tag, message, ...args) {
54
+ if (!isEnabled(tag)) return;
55
+ const state = getState();
56
+ if (state.handler) {
57
+ state.handler("debug", tag, message, ...args);
58
+ } else {
59
+ console.log(`[${tag}]`, message, ...args);
60
+ }
61
+ },
62
+ /**
63
+ * Warning-level log. ALWAYS shown regardless of debug flag.
64
+ * Use for important but non-critical issues (timeouts, retries, degraded state).
65
+ */
66
+ warn(tag, message, ...args) {
67
+ const state = getState();
68
+ if (state.handler) {
69
+ state.handler("warn", tag, message, ...args);
70
+ } else {
71
+ console.warn(`[${tag}]`, message, ...args);
72
+ }
73
+ },
74
+ /**
75
+ * Error-level log. ALWAYS shown regardless of debug flag.
76
+ * Use for critical failures that should never be silenced.
77
+ */
78
+ error(tag, message, ...args) {
79
+ const state = getState();
80
+ if (state.handler) {
81
+ state.handler("error", tag, message, ...args);
82
+ } else {
83
+ console.error(`[${tag}]`, message, ...args);
84
+ }
85
+ },
86
+ /** Reset all logger state (debug flag, tags, handler). Primarily for tests. */
87
+ reset() {
88
+ const g = globalThis;
89
+ delete g[LOGGER_KEY];
90
+ }
91
+ };
92
+
93
+ // core/errors.ts
94
+ var SphereError = class extends Error {
95
+ code;
96
+ cause;
97
+ constructor(message, code, cause) {
98
+ super(message);
99
+ this.name = "SphereError";
100
+ this.code = code;
101
+ this.cause = cause;
102
+ }
103
+ };
104
+
1
105
  // constants.ts
2
106
  var STORAGE_KEYS_GLOBAL = {
3
107
  /** Encrypted BIP39 mnemonic */
@@ -262,7 +366,7 @@ var ConnectHost = class {
262
366
  return;
263
367
  }
264
368
  } catch (error) {
265
- console.warn("[ConnectHost] Error handling message:", error);
369
+ logger.warn("ConnectHost", "Error handling message:", error);
266
370
  }
267
371
  }
268
372
  // ===========================================================================
@@ -274,10 +378,16 @@ var ConnectHost = class {
274
378
  this.sendHandshakeResponse([], void 0, void 0);
275
379
  return;
276
380
  }
381
+ if (msg.sessionId && this.session?.active && this.session.id === msg.sessionId) {
382
+ const identity2 = this.getPublicIdentity();
383
+ this.sendHandshakeResponse([...this.grantedPermissions], this.session.id, identity2);
384
+ return;
385
+ }
277
386
  const requestedPermissions = msg.permissions;
278
387
  const { approved, grantedPermissions } = await this.config.onConnectionRequest(
279
388
  dapp,
280
- requestedPermissions
389
+ requestedPermissions,
390
+ msg.silent
281
391
  );
282
392
  if (!approved) {
283
393
  this.sendHandshakeResponse([], void 0, void 0);
@@ -327,8 +437,12 @@ var ConnectHost = class {
327
437
  return;
328
438
  }
329
439
  if (msg.method === RPC_METHODS.DISCONNECT) {
440
+ const disconnectedSession = this.session;
330
441
  this.revokeSession();
331
442
  this.sendResult(msg.id, { disconnected: true });
443
+ if (disconnectedSession && this.config.onDisconnect) {
444
+ Promise.resolve(this.config.onDisconnect(disconnectedSession)).catch((err) => logger.warn("Connect", "onDisconnect handler error", err));
445
+ }
332
446
  return;
333
447
  }
334
448
  if (!hasMethodPermission(this.grantedPermissions, msg.method)) {
@@ -399,17 +513,17 @@ var ConnectHost = class {
399
513
  return this.sphere.payments.getHistory();
400
514
  case RPC_METHODS.L1_GET_BALANCE:
401
515
  if (!this.sphere.payments.l1) {
402
- throw new Error("L1 module not available");
516
+ throw new SphereError("L1 module not available", "MODULE_NOT_AVAILABLE");
403
517
  }
404
518
  return this.sphere.payments.l1.getBalance();
405
519
  case RPC_METHODS.L1_GET_HISTORY:
406
520
  if (!this.sphere.payments.l1) {
407
- throw new Error("L1 module not available");
521
+ throw new SphereError("L1 module not available", "MODULE_NOT_AVAILABLE");
408
522
  }
409
523
  return this.sphere.payments.l1.getHistory(params.limit);
410
524
  case RPC_METHODS.RESOLVE:
411
525
  if (!params.identifier) {
412
- throw new Error("Missing required parameter: identifier");
526
+ throw new SphereError("Missing required parameter: identifier", "VALIDATION_ERROR");
413
527
  }
414
528
  return this.sphere.resolve(params.identifier);
415
529
  case RPC_METHODS.SUBSCRIBE:
@@ -417,7 +531,7 @@ var ConnectHost = class {
417
531
  case RPC_METHODS.UNSUBSCRIBE:
418
532
  return this.handleUnsubscribe(params.event);
419
533
  case RPC_METHODS.GET_CONVERSATIONS: {
420
- if (!this.sphere.communications) throw new Error("Communications module not available");
534
+ if (!this.sphere.communications) throw new SphereError("Communications module not available", "MODULE_NOT_AVAILABLE");
421
535
  const convos = this.sphere.communications.getConversations();
422
536
  const result = [];
423
537
  const needsResolve = [];
@@ -440,7 +554,10 @@ var ConnectHost = class {
440
554
  if (needsResolve.length > 0) {
441
555
  const resolved = await Promise.all(
442
556
  needsResolve.map(
443
- ({ peerPubkey }) => this.sphere.communications.resolvePeerNametag(peerPubkey).catch(() => void 0)
557
+ ({ peerPubkey }) => this.sphere.communications.resolvePeerNametag(peerPubkey).catch((err) => {
558
+ logger.debug("Connect", "Peer nametag resolution failed", err);
559
+ return void 0;
560
+ })
444
561
  )
445
562
  );
446
563
  for (let i = 0; i < needsResolve.length; i++) {
@@ -453,8 +570,8 @@ var ConnectHost = class {
453
570
  return result;
454
571
  }
455
572
  case RPC_METHODS.GET_MESSAGES: {
456
- if (!this.sphere.communications) throw new Error("Communications module not available");
457
- if (!params.peerPubkey) throw new Error("Missing required parameter: peerPubkey");
573
+ if (!this.sphere.communications) throw new SphereError("Communications module not available", "MODULE_NOT_AVAILABLE");
574
+ if (!params.peerPubkey) throw new SphereError("Missing required parameter: peerPubkey", "VALIDATION_ERROR");
458
575
  return this.sphere.communications.getConversationPage(
459
576
  params.peerPubkey,
460
577
  {
@@ -464,7 +581,7 @@ var ConnectHost = class {
464
581
  );
465
582
  }
466
583
  case RPC_METHODS.GET_DM_UNREAD_COUNT: {
467
- if (!this.sphere.communications) throw new Error("Communications module not available");
584
+ if (!this.sphere.communications) throw new SphereError("Communications module not available", "MODULE_NOT_AVAILABLE");
468
585
  return {
469
586
  unreadCount: this.sphere.communications.getUnreadCount(
470
587
  params.peerPubkey
@@ -472,22 +589,22 @@ var ConnectHost = class {
472
589
  };
473
590
  }
474
591
  case RPC_METHODS.MARK_AS_READ: {
475
- if (!this.sphere.communications) throw new Error("Communications module not available");
592
+ if (!this.sphere.communications) throw new SphereError("Communications module not available", "MODULE_NOT_AVAILABLE");
476
593
  if (!params.messageIds || !Array.isArray(params.messageIds)) {
477
- throw new Error("Missing required parameter: messageIds (string[])");
594
+ throw new SphereError("Missing required parameter: messageIds (string[])", "VALIDATION_ERROR");
478
595
  }
479
596
  await this.sphere.communications.markAsRead(params.messageIds);
480
597
  return { marked: true, count: params.messageIds.length };
481
598
  }
482
599
  default:
483
- throw new Error(`Unknown method: ${method}`);
600
+ throw new SphereError(`Unknown method: ${method}`, "VALIDATION_ERROR");
484
601
  }
485
602
  }
486
603
  // ===========================================================================
487
604
  // Event Subscriptions
488
605
  // ===========================================================================
489
606
  handleSubscribe(eventName) {
490
- if (!eventName) throw new Error("Missing required parameter: event");
607
+ if (!eventName) throw new SphereError("Missing required parameter: event", "VALIDATION_ERROR");
491
608
  if (this.eventSubscriptions.has(eventName)) {
492
609
  return { subscribed: true, event: eventName };
493
610
  }
@@ -504,7 +621,7 @@ var ConnectHost = class {
504
621
  return { subscribed: true, event: eventName };
505
622
  }
506
623
  handleUnsubscribe(eventName) {
507
- if (!eventName) throw new Error("Missing required parameter: event");
624
+ if (!eventName) throw new SphereError("Missing required parameter: event", "VALIDATION_ERROR");
508
625
  const unsub = this.eventSubscriptions.get(eventName);
509
626
  if (unsub) {
510
627
  unsub();
@@ -595,6 +712,8 @@ var ConnectClient = class {
595
712
  requestedPermissions;
596
713
  timeout;
597
714
  intentTimeout;
715
+ resumeSessionId;
716
+ silent;
598
717
  sessionId = null;
599
718
  grantedPermissions = [];
600
719
  identity = null;
@@ -610,6 +729,8 @@ var ConnectClient = class {
610
729
  this.requestedPermissions = config.permissions ?? [...ALL_PERMISSIONS];
611
730
  this.timeout = config.timeout ?? DEFAULT_TIMEOUT;
612
731
  this.intentTimeout = config.intentTimeout ?? DEFAULT_INTENT_TIMEOUT;
732
+ this.resumeSessionId = config.resumeSessionId ?? null;
733
+ this.silent = config.silent ?? false;
613
734
  }
614
735
  // ===========================================================================
615
736
  // Connection
@@ -629,7 +750,9 @@ var ConnectClient = class {
629
750
  type: "handshake",
630
751
  direction: "request",
631
752
  permissions: this.requestedPermissions,
632
- dapp: this.dapp
753
+ dapp: this.dapp,
754
+ ...this.resumeSessionId ? { sessionId: this.resumeSessionId } : {},
755
+ ...this.silent ? { silent: true } : {}
633
756
  });
634
757
  });
635
758
  }
@@ -664,7 +787,7 @@ var ConnectClient = class {
664
787
  // ===========================================================================
665
788
  /** Send a query request and return the result */
666
789
  async query(method, params) {
667
- if (!this.connected) throw new Error("Not connected");
790
+ if (!this.connected) throw new SphereError("Not connected", "NOT_INITIALIZED");
668
791
  const id = createRequestId();
669
792
  return new Promise((resolve, reject) => {
670
793
  const timer = setTimeout(() => {
@@ -691,7 +814,7 @@ var ConnectClient = class {
691
814
  // ===========================================================================
692
815
  /** Send an intent request. The wallet will open its UI for user confirmation. */
693
816
  async intent(action, params) {
694
- if (!this.connected) throw new Error("Not connected");
817
+ if (!this.connected) throw new SphereError("Not connected", "NOT_INITIALIZED");
695
818
  const id = createRequestId();
696
819
  return new Promise((resolve, reject) => {
697
820
  const timer = setTimeout(() => {
@@ -721,8 +844,7 @@ var ConnectClient = class {
721
844
  if (!this.eventHandlers.has(event)) {
722
845
  this.eventHandlers.set(event, /* @__PURE__ */ new Set());
723
846
  if (this.connected) {
724
- this.query(RPC_METHODS.SUBSCRIBE, { event }).catch(() => {
725
- });
847
+ this.query(RPC_METHODS.SUBSCRIBE, { event }).catch((err) => logger.debug("Connect", "Event subscription failed", err));
726
848
  }
727
849
  }
728
850
  this.eventHandlers.get(event).add(handler);
@@ -733,8 +855,7 @@ var ConnectClient = class {
733
855
  if (handlers.size === 0) {
734
856
  this.eventHandlers.delete(event);
735
857
  if (this.connected) {
736
- this.query(RPC_METHODS.UNSUBSCRIBE, { event }).catch(() => {
737
- });
858
+ this.query(RPC_METHODS.UNSUBSCRIBE, { event }).catch((err) => logger.debug("Connect", "Event unsubscription failed", err));
738
859
  }
739
860
  }
740
861
  }
@@ -762,7 +883,8 @@ var ConnectClient = class {
762
883
  for (const handler of handlers) {
763
884
  try {
764
885
  handler(msg.data);
765
- } catch {
886
+ } catch (err) {
887
+ logger.debug("Connect", "Event handler error", err);
766
888
  }
767
889
  }
768
890
  }