@unicitylabs/sphere-sdk 0.4.5 → 0.4.7

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.
package/dist/index.d.cts CHANGED
@@ -3345,6 +3345,12 @@ declare class CommunicationsModule {
3345
3345
  * Subscribe to incoming broadcasts
3346
3346
  */
3347
3347
  onBroadcast(handler: (message: BroadcastMessage) => void): () => void;
3348
+ /**
3349
+ * Resolve a peer's nametag by their transport pubkey.
3350
+ * Uses transport.resolveTransportPubkeyInfo() for live lookup from relay binding events.
3351
+ * Returns undefined if transport doesn't support resolution or peer has no nametag.
3352
+ */
3353
+ resolvePeerNametag(peerPubkey: string): Promise<string | undefined>;
3348
3354
  private handleIncomingMessage;
3349
3355
  private handleComposingIndicator;
3350
3356
  private handleIncomingBroadcast;
@@ -3440,6 +3446,12 @@ declare class GroupChatModule {
3440
3446
  onMessage(handler: (message: GroupMessageData) => void): () => void;
3441
3447
  getRelayUrls(): string[];
3442
3448
  getMyPublicKey(): string | null;
3449
+ /**
3450
+ * Returns the latest message timestamp (in Nostr seconds) across the given groups,
3451
+ * or 0 if no messages exist. Used to set `since` on subscriptions so the relay
3452
+ * only sends events we don't already have.
3453
+ */
3454
+ private getLatestMessageTimestamp;
3443
3455
  private fetchRelayAdmins;
3444
3456
  private doFetchRelayAdmins;
3445
3457
  private fetchGroupMetadataInternal;
@@ -4460,14 +4472,9 @@ declare class Sphere {
4460
4472
  * });
4461
4473
  * ```
4462
4474
  */
4463
- static importFromJSON(options: {
4475
+ static importFromJSON(options: Omit<SphereImportOptions, 'mnemonic' | 'masterKey' | 'chainCode' | 'derivationPath' | 'basePath' | 'derivationMode'> & {
4464
4476
  jsonContent: string;
4465
4477
  password?: string;
4466
- storage: StorageProvider;
4467
- transport: TransportProvider;
4468
- oracle: OracleProvider;
4469
- tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;
4470
- l1?: L1Config;
4471
4478
  }): Promise<{
4472
4479
  success: boolean;
4473
4480
  mnemonic?: string;
@@ -4503,7 +4510,7 @@ declare class Sphere {
4503
4510
  * });
4504
4511
  * ```
4505
4512
  */
4506
- static importFromLegacyFile(options: {
4513
+ static importFromLegacyFile(options: Omit<SphereImportOptions, 'mnemonic' | 'masterKey' | 'chainCode' | 'derivationPath' | 'basePath' | 'derivationMode'> & {
4507
4514
  /** File content - Uint8Array for .dat, string for .txt */
4508
4515
  fileContent: string | Uint8Array;
4509
4516
  /** File name (used for type detection) */
@@ -4512,18 +4519,6 @@ declare class Sphere {
4512
4519
  password?: string;
4513
4520
  /** Progress callback for long decryption operations */
4514
4521
  onDecryptProgress?: DecryptionProgressCallback;
4515
- /** Storage provider instance */
4516
- storage: StorageProvider;
4517
- /** Transport provider instance */
4518
- transport: TransportProvider;
4519
- /** Oracle provider instance */
4520
- oracle: OracleProvider;
4521
- /** Optional token storage provider */
4522
- tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;
4523
- /** Optional nametag to register */
4524
- nametag?: string;
4525
- /** L1 (ALPHA blockchain) configuration */
4526
- l1?: L1Config;
4527
4522
  }): Promise<{
4528
4523
  success: boolean;
4529
4524
  sphere?: Sphere;
package/dist/index.d.ts CHANGED
@@ -3345,6 +3345,12 @@ declare class CommunicationsModule {
3345
3345
  * Subscribe to incoming broadcasts
3346
3346
  */
3347
3347
  onBroadcast(handler: (message: BroadcastMessage) => void): () => void;
3348
+ /**
3349
+ * Resolve a peer's nametag by their transport pubkey.
3350
+ * Uses transport.resolveTransportPubkeyInfo() for live lookup from relay binding events.
3351
+ * Returns undefined if transport doesn't support resolution or peer has no nametag.
3352
+ */
3353
+ resolvePeerNametag(peerPubkey: string): Promise<string | undefined>;
3348
3354
  private handleIncomingMessage;
3349
3355
  private handleComposingIndicator;
3350
3356
  private handleIncomingBroadcast;
@@ -3440,6 +3446,12 @@ declare class GroupChatModule {
3440
3446
  onMessage(handler: (message: GroupMessageData) => void): () => void;
3441
3447
  getRelayUrls(): string[];
3442
3448
  getMyPublicKey(): string | null;
3449
+ /**
3450
+ * Returns the latest message timestamp (in Nostr seconds) across the given groups,
3451
+ * or 0 if no messages exist. Used to set `since` on subscriptions so the relay
3452
+ * only sends events we don't already have.
3453
+ */
3454
+ private getLatestMessageTimestamp;
3443
3455
  private fetchRelayAdmins;
3444
3456
  private doFetchRelayAdmins;
3445
3457
  private fetchGroupMetadataInternal;
@@ -4460,14 +4472,9 @@ declare class Sphere {
4460
4472
  * });
4461
4473
  * ```
4462
4474
  */
4463
- static importFromJSON(options: {
4475
+ static importFromJSON(options: Omit<SphereImportOptions, 'mnemonic' | 'masterKey' | 'chainCode' | 'derivationPath' | 'basePath' | 'derivationMode'> & {
4464
4476
  jsonContent: string;
4465
4477
  password?: string;
4466
- storage: StorageProvider;
4467
- transport: TransportProvider;
4468
- oracle: OracleProvider;
4469
- tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;
4470
- l1?: L1Config;
4471
4478
  }): Promise<{
4472
4479
  success: boolean;
4473
4480
  mnemonic?: string;
@@ -4503,7 +4510,7 @@ declare class Sphere {
4503
4510
  * });
4504
4511
  * ```
4505
4512
  */
4506
- static importFromLegacyFile(options: {
4513
+ static importFromLegacyFile(options: Omit<SphereImportOptions, 'mnemonic' | 'masterKey' | 'chainCode' | 'derivationPath' | 'basePath' | 'derivationMode'> & {
4507
4514
  /** File content - Uint8Array for .dat, string for .txt */
4508
4515
  fileContent: string | Uint8Array;
4509
4516
  /** File name (used for type detection) */
@@ -4512,18 +4519,6 @@ declare class Sphere {
4512
4519
  password?: string;
4513
4520
  /** Progress callback for long decryption operations */
4514
4521
  onDecryptProgress?: DecryptionProgressCallback;
4515
- /** Storage provider instance */
4516
- storage: StorageProvider;
4517
- /** Transport provider instance */
4518
- transport: TransportProvider;
4519
- /** Oracle provider instance */
4520
- oracle: OracleProvider;
4521
- /** Optional token storage provider */
4522
- tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;
4523
- /** Optional nametag to register */
4524
- nametag?: string;
4525
- /** L1 (ALPHA blockchain) configuration */
4526
- l1?: L1Config;
4527
4522
  }): Promise<{
4528
4523
  success: boolean;
4529
4524
  sphere?: Sphere;
package/dist/index.js CHANGED
@@ -7954,6 +7954,23 @@ var CommunicationsModule = class {
7954
7954
  return () => this.broadcastHandlers.delete(handler);
7955
7955
  }
7956
7956
  // ===========================================================================
7957
+ // Public API - Peer Resolution
7958
+ // ===========================================================================
7959
+ /**
7960
+ * Resolve a peer's nametag by their transport pubkey.
7961
+ * Uses transport.resolveTransportPubkeyInfo() for live lookup from relay binding events.
7962
+ * Returns undefined if transport doesn't support resolution or peer has no nametag.
7963
+ */
7964
+ async resolvePeerNametag(peerPubkey) {
7965
+ if (!this.deps?.transport.resolveTransportPubkeyInfo) return void 0;
7966
+ try {
7967
+ const info = await this.deps.transport.resolveTransportPubkeyInfo(peerPubkey);
7968
+ return info?.nametag;
7969
+ } catch {
7970
+ return void 0;
7971
+ }
7972
+ }
7973
+ // ===========================================================================
7957
7974
  // Private: Message Handling
7958
7975
  // ===========================================================================
7959
7976
  handleIncomingMessage(msg) {
@@ -8343,10 +8360,12 @@ var GroupChatModule = class {
8343
8360
  if (!this.client) return;
8344
8361
  const groupIds = Array.from(this.groups.keys());
8345
8362
  if (groupIds.length === 0) return;
8363
+ const latestTimestamp = this.getLatestMessageTimestamp(groupIds);
8346
8364
  this.trackSubscription(
8347
8365
  createNip29Filter({
8348
8366
  kinds: [NIP29_KINDS.CHAT_MESSAGE, NIP29_KINDS.THREAD_ROOT, NIP29_KINDS.THREAD_REPLY],
8349
- "#h": groupIds
8367
+ "#h": groupIds,
8368
+ ...latestTimestamp ? { since: latestTimestamp } : {}
8350
8369
  }),
8351
8370
  { onEvent: (event) => this.handleGroupEvent(event) }
8352
8371
  );
@@ -8367,10 +8386,12 @@ var GroupChatModule = class {
8367
8386
  }
8368
8387
  subscribeToGroup(groupId) {
8369
8388
  if (!this.client) return;
8389
+ const latestTimestamp = this.getLatestMessageTimestamp([groupId]);
8370
8390
  this.trackSubscription(
8371
8391
  createNip29Filter({
8372
8392
  kinds: [NIP29_KINDS.CHAT_MESSAGE, NIP29_KINDS.THREAD_ROOT, NIP29_KINDS.THREAD_REPLY],
8373
- "#h": [groupId]
8393
+ "#h": [groupId],
8394
+ ...latestTimestamp ? { since: latestTimestamp } : {}
8374
8395
  }),
8375
8396
  { onEvent: (event) => this.handleGroupEvent(event) }
8376
8397
  );
@@ -9062,6 +9083,23 @@ var GroupChatModule = class {
9062
9083
  getMyPublicKey() {
9063
9084
  return this.keyManager?.getPublicKeyHex() || null;
9064
9085
  }
9086
+ /**
9087
+ * Returns the latest message timestamp (in Nostr seconds) across the given groups,
9088
+ * or 0 if no messages exist. Used to set `since` on subscriptions so the relay
9089
+ * only sends events we don't already have.
9090
+ */
9091
+ getLatestMessageTimestamp(groupIds) {
9092
+ let latest = 0;
9093
+ for (const gid of groupIds) {
9094
+ const msgs = this.messages.get(gid);
9095
+ if (!msgs) continue;
9096
+ for (const m of msgs) {
9097
+ const ts = Math.floor(m.timestamp / 1e3);
9098
+ if (ts > latest) latest = ts;
9099
+ }
9100
+ }
9101
+ return latest;
9102
+ }
9065
9103
  // ===========================================================================
9066
9104
  // Private — Relay Admin
9067
9105
  // ===========================================================================
@@ -13508,55 +13546,44 @@ var Sphere = class _Sphere {
13508
13546
  * ```
13509
13547
  */
13510
13548
  static async importFromJSON(options) {
13549
+ const { jsonContent, password, ...baseOptions } = options;
13511
13550
  try {
13512
- const data = JSON.parse(options.jsonContent);
13551
+ const data = JSON.parse(jsonContent);
13513
13552
  if (data.version !== "1.0" || data.type !== "sphere-wallet") {
13514
13553
  return { success: false, error: "Invalid wallet format" };
13515
13554
  }
13516
13555
  let mnemonic = data.mnemonic;
13517
13556
  let masterKey = data.wallet.masterPrivateKey;
13518
- if (data.encrypted && options.password) {
13557
+ if (data.encrypted && password) {
13519
13558
  if (mnemonic) {
13520
- const decrypted = decryptSimple(mnemonic, options.password);
13559
+ const decrypted = decryptSimple(mnemonic, password);
13521
13560
  if (!decrypted) {
13522
13561
  return { success: false, error: "Failed to decrypt mnemonic - wrong password?" };
13523
13562
  }
13524
13563
  mnemonic = decrypted;
13525
13564
  }
13526
13565
  if (masterKey) {
13527
- const decrypted = decryptSimple(masterKey, options.password);
13566
+ const decrypted = decryptSimple(masterKey, password);
13528
13567
  if (!decrypted) {
13529
13568
  return { success: false, error: "Failed to decrypt master key - wrong password?" };
13530
13569
  }
13531
13570
  masterKey = decrypted;
13532
13571
  }
13533
- } else if (data.encrypted && !options.password) {
13572
+ } else if (data.encrypted && !password) {
13534
13573
  return { success: false, error: "Password required for encrypted wallet" };
13535
13574
  }
13536
13575
  const basePath = data.wallet.descriptorPath ? `m/${data.wallet.descriptorPath}` : DEFAULT_BASE_PATH;
13537
13576
  if (mnemonic) {
13538
- await _Sphere.import({
13539
- mnemonic,
13540
- basePath,
13541
- storage: options.storage,
13542
- transport: options.transport,
13543
- oracle: options.oracle,
13544
- tokenStorage: options.tokenStorage,
13545
- l1: options.l1
13546
- });
13577
+ await _Sphere.import({ ...baseOptions, mnemonic, basePath });
13547
13578
  return { success: true, mnemonic };
13548
13579
  }
13549
13580
  if (masterKey) {
13550
13581
  await _Sphere.import({
13582
+ ...baseOptions,
13551
13583
  masterKey,
13552
13584
  chainCode: data.wallet.chainCode,
13553
13585
  basePath,
13554
- derivationMode: data.derivationMode || (data.wallet.isBIP32 ? "bip32" : "wif_hmac"),
13555
- storage: options.storage,
13556
- transport: options.transport,
13557
- oracle: options.oracle,
13558
- tokenStorage: options.tokenStorage,
13559
- l1: options.l1
13586
+ derivationMode: data.derivationMode || (data.wallet.isBIP32 ? "bip32" : "wif_hmac")
13560
13587
  });
13561
13588
  return { success: true };
13562
13589
  }
@@ -13599,7 +13626,7 @@ var Sphere = class _Sphere {
13599
13626
  * ```
13600
13627
  */
13601
13628
  static async importFromLegacyFile(options) {
13602
- const { fileContent, fileName, password, onDecryptProgress } = options;
13629
+ const { fileContent, fileName, password, onDecryptProgress, ...baseOptions } = options;
13603
13630
  const fileType = _Sphere.detectLegacyFileType(fileName, fileContent);
13604
13631
  if (fileType === "unknown") {
13605
13632
  return { success: false, error: "Unknown file format" };
@@ -13609,15 +13636,7 @@ var Sphere = class _Sphere {
13609
13636
  if (!_Sphere.validateMnemonic(mnemonic)) {
13610
13637
  return { success: false, error: "Invalid mnemonic phrase" };
13611
13638
  }
13612
- const sphere = await _Sphere.import({
13613
- mnemonic,
13614
- storage: options.storage,
13615
- transport: options.transport,
13616
- oracle: options.oracle,
13617
- tokenStorage: options.tokenStorage,
13618
- nametag: options.nametag,
13619
- l1: options.l1
13620
- });
13639
+ const sphere = await _Sphere.import({ ...baseOptions, mnemonic });
13621
13640
  return { success: true, sphere, mnemonic };
13622
13641
  }
13623
13642
  if (fileType === "dat") {
@@ -13637,16 +13656,11 @@ var Sphere = class _Sphere {
13637
13656
  const { masterKey, chainCode, descriptorPath, derivationMode } = parseResult.data;
13638
13657
  const basePath = descriptorPath ? `m/${descriptorPath}` : DEFAULT_BASE_PATH;
13639
13658
  const sphere = await _Sphere.import({
13659
+ ...baseOptions,
13640
13660
  masterKey,
13641
13661
  chainCode,
13642
13662
  basePath,
13643
- derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac"),
13644
- storage: options.storage,
13645
- transport: options.transport,
13646
- oracle: options.oracle,
13647
- tokenStorage: options.tokenStorage,
13648
- nametag: options.nametag,
13649
- l1: options.l1
13663
+ derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac")
13650
13664
  });
13651
13665
  return { success: true, sphere };
13652
13666
  }
@@ -13669,16 +13683,11 @@ var Sphere = class _Sphere {
13669
13683
  const { masterKey, chainCode, descriptorPath, derivationMode } = parseResult.data;
13670
13684
  const basePath = descriptorPath ? `m/${descriptorPath}` : DEFAULT_BASE_PATH;
13671
13685
  const sphere = await _Sphere.import({
13686
+ ...baseOptions,
13672
13687
  masterKey,
13673
13688
  chainCode,
13674
13689
  basePath,
13675
- derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac"),
13676
- storage: options.storage,
13677
- transport: options.transport,
13678
- oracle: options.oracle,
13679
- tokenStorage: options.tokenStorage,
13680
- nametag: options.nametag,
13681
- l1: options.l1
13690
+ derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac")
13682
13691
  });
13683
13692
  return { success: true, sphere };
13684
13693
  }
@@ -13692,13 +13701,9 @@ var Sphere = class _Sphere {
13692
13701
  }
13693
13702
  if (parsed.type === "sphere-wallet") {
13694
13703
  const result = await _Sphere.importFromJSON({
13704
+ ...baseOptions,
13695
13705
  jsonContent: content,
13696
- password,
13697
- storage: options.storage,
13698
- transport: options.transport,
13699
- oracle: options.oracle,
13700
- tokenStorage: options.tokenStorage,
13701
- l1: options.l1
13706
+ password
13702
13707
  });
13703
13708
  if (result.success) {
13704
13709
  const sphere2 = _Sphere.getInstance();
@@ -13740,29 +13745,15 @@ var Sphere = class _Sphere {
13740
13745
  const isBIP32 = derivationMode === "bip32" || !!chainCode;
13741
13746
  const basePath = descriptorPath ? `m/${descriptorPath}` : isBIP32 ? "m/84'/1'/0'" : DEFAULT_BASE_PATH;
13742
13747
  if (mnemonic) {
13743
- const sphere2 = await _Sphere.import({
13744
- mnemonic,
13745
- basePath,
13746
- storage: options.storage,
13747
- transport: options.transport,
13748
- oracle: options.oracle,
13749
- tokenStorage: options.tokenStorage,
13750
- nametag: options.nametag,
13751
- l1: options.l1
13752
- });
13748
+ const sphere2 = await _Sphere.import({ ...baseOptions, mnemonic, basePath });
13753
13749
  return { success: true, sphere: sphere2, mnemonic };
13754
13750
  }
13755
13751
  const sphere = await _Sphere.import({
13752
+ ...baseOptions,
13756
13753
  masterKey,
13757
13754
  chainCode,
13758
13755
  basePath,
13759
- derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac"),
13760
- storage: options.storage,
13761
- transport: options.transport,
13762
- oracle: options.oracle,
13763
- tokenStorage: options.tokenStorage,
13764
- nametag: options.nametag,
13765
- l1: options.l1
13756
+ derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac")
13766
13757
  });
13767
13758
  return { success: true, sphere };
13768
13759
  }