@unicitylabs/sphere-sdk 0.4.6 → 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.
@@ -2800,6 +2800,12 @@ declare class GroupChatModule {
2800
2800
  onMessage(handler: (message: GroupMessageData) => void): () => void;
2801
2801
  getRelayUrls(): string[];
2802
2802
  getMyPublicKey(): string | null;
2803
+ /**
2804
+ * Returns the latest message timestamp (in Nostr seconds) across the given groups,
2805
+ * or 0 if no messages exist. Used to set `since` on subscriptions so the relay
2806
+ * only sends events we don't already have.
2807
+ */
2808
+ private getLatestMessageTimestamp;
2803
2809
  private fetchRelayAdmins;
2804
2810
  private doFetchRelayAdmins;
2805
2811
  private fetchGroupMetadataInternal;
@@ -3509,14 +3515,9 @@ declare class Sphere {
3509
3515
  * });
3510
3516
  * ```
3511
3517
  */
3512
- static importFromJSON(options: {
3518
+ static importFromJSON(options: Omit<SphereImportOptions, 'mnemonic' | 'masterKey' | 'chainCode' | 'derivationPath' | 'basePath' | 'derivationMode'> & {
3513
3519
  jsonContent: string;
3514
3520
  password?: string;
3515
- storage: StorageProvider;
3516
- transport: TransportProvider;
3517
- oracle: OracleProvider;
3518
- tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;
3519
- l1?: L1Config;
3520
3521
  }): Promise<{
3521
3522
  success: boolean;
3522
3523
  mnemonic?: string;
@@ -3552,7 +3553,7 @@ declare class Sphere {
3552
3553
  * });
3553
3554
  * ```
3554
3555
  */
3555
- static importFromLegacyFile(options: {
3556
+ static importFromLegacyFile(options: Omit<SphereImportOptions, 'mnemonic' | 'masterKey' | 'chainCode' | 'derivationPath' | 'basePath' | 'derivationMode'> & {
3556
3557
  /** File content - Uint8Array for .dat, string for .txt */
3557
3558
  fileContent: string | Uint8Array;
3558
3559
  /** File name (used for type detection) */
@@ -3561,18 +3562,6 @@ declare class Sphere {
3561
3562
  password?: string;
3562
3563
  /** Progress callback for long decryption operations */
3563
3564
  onDecryptProgress?: DecryptionProgressCallback;
3564
- /** Storage provider instance */
3565
- storage: StorageProvider;
3566
- /** Transport provider instance */
3567
- transport: TransportProvider;
3568
- /** Oracle provider instance */
3569
- oracle: OracleProvider;
3570
- /** Optional token storage provider */
3571
- tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;
3572
- /** Optional nametag to register */
3573
- nametag?: string;
3574
- /** L1 (ALPHA blockchain) configuration */
3575
- l1?: L1Config;
3576
3565
  }): Promise<{
3577
3566
  success: boolean;
3578
3567
  sphere?: Sphere;
@@ -2800,6 +2800,12 @@ declare class GroupChatModule {
2800
2800
  onMessage(handler: (message: GroupMessageData) => void): () => void;
2801
2801
  getRelayUrls(): string[];
2802
2802
  getMyPublicKey(): string | null;
2803
+ /**
2804
+ * Returns the latest message timestamp (in Nostr seconds) across the given groups,
2805
+ * or 0 if no messages exist. Used to set `since` on subscriptions so the relay
2806
+ * only sends events we don't already have.
2807
+ */
2808
+ private getLatestMessageTimestamp;
2803
2809
  private fetchRelayAdmins;
2804
2810
  private doFetchRelayAdmins;
2805
2811
  private fetchGroupMetadataInternal;
@@ -3509,14 +3515,9 @@ declare class Sphere {
3509
3515
  * });
3510
3516
  * ```
3511
3517
  */
3512
- static importFromJSON(options: {
3518
+ static importFromJSON(options: Omit<SphereImportOptions, 'mnemonic' | 'masterKey' | 'chainCode' | 'derivationPath' | 'basePath' | 'derivationMode'> & {
3513
3519
  jsonContent: string;
3514
3520
  password?: string;
3515
- storage: StorageProvider;
3516
- transport: TransportProvider;
3517
- oracle: OracleProvider;
3518
- tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;
3519
- l1?: L1Config;
3520
3521
  }): Promise<{
3521
3522
  success: boolean;
3522
3523
  mnemonic?: string;
@@ -3552,7 +3553,7 @@ declare class Sphere {
3552
3553
  * });
3553
3554
  * ```
3554
3555
  */
3555
- static importFromLegacyFile(options: {
3556
+ static importFromLegacyFile(options: Omit<SphereImportOptions, 'mnemonic' | 'masterKey' | 'chainCode' | 'derivationPath' | 'basePath' | 'derivationMode'> & {
3556
3557
  /** File content - Uint8Array for .dat, string for .txt */
3557
3558
  fileContent: string | Uint8Array;
3558
3559
  /** File name (used for type detection) */
@@ -3561,18 +3562,6 @@ declare class Sphere {
3561
3562
  password?: string;
3562
3563
  /** Progress callback for long decryption operations */
3563
3564
  onDecryptProgress?: DecryptionProgressCallback;
3564
- /** Storage provider instance */
3565
- storage: StorageProvider;
3566
- /** Transport provider instance */
3567
- transport: TransportProvider;
3568
- /** Oracle provider instance */
3569
- oracle: OracleProvider;
3570
- /** Optional token storage provider */
3571
- tokenStorage?: TokenStorageProvider<TxfStorageDataBase>;
3572
- /** Optional nametag to register */
3573
- nametag?: string;
3574
- /** L1 (ALPHA blockchain) configuration */
3575
- l1?: L1Config;
3576
3565
  }): Promise<{
3577
3566
  success: boolean;
3578
3567
  sphere?: Sphere;
@@ -8065,10 +8065,12 @@ var GroupChatModule = class {
8065
8065
  if (!this.client) return;
8066
8066
  const groupIds = Array.from(this.groups.keys());
8067
8067
  if (groupIds.length === 0) return;
8068
+ const latestTimestamp = this.getLatestMessageTimestamp(groupIds);
8068
8069
  this.trackSubscription(
8069
8070
  createNip29Filter({
8070
8071
  kinds: [NIP29_KINDS.CHAT_MESSAGE, NIP29_KINDS.THREAD_ROOT, NIP29_KINDS.THREAD_REPLY],
8071
- "#h": groupIds
8072
+ "#h": groupIds,
8073
+ ...latestTimestamp ? { since: latestTimestamp } : {}
8072
8074
  }),
8073
8075
  { onEvent: (event) => this.handleGroupEvent(event) }
8074
8076
  );
@@ -8089,10 +8091,12 @@ var GroupChatModule = class {
8089
8091
  }
8090
8092
  subscribeToGroup(groupId) {
8091
8093
  if (!this.client) return;
8094
+ const latestTimestamp = this.getLatestMessageTimestamp([groupId]);
8092
8095
  this.trackSubscription(
8093
8096
  createNip29Filter({
8094
8097
  kinds: [NIP29_KINDS.CHAT_MESSAGE, NIP29_KINDS.THREAD_ROOT, NIP29_KINDS.THREAD_REPLY],
8095
- "#h": [groupId]
8098
+ "#h": [groupId],
8099
+ ...latestTimestamp ? { since: latestTimestamp } : {}
8096
8100
  }),
8097
8101
  { onEvent: (event) => this.handleGroupEvent(event) }
8098
8102
  );
@@ -8784,6 +8788,23 @@ var GroupChatModule = class {
8784
8788
  getMyPublicKey() {
8785
8789
  return this.keyManager?.getPublicKeyHex() || null;
8786
8790
  }
8791
+ /**
8792
+ * Returns the latest message timestamp (in Nostr seconds) across the given groups,
8793
+ * or 0 if no messages exist. Used to set `since` on subscriptions so the relay
8794
+ * only sends events we don't already have.
8795
+ */
8796
+ getLatestMessageTimestamp(groupIds) {
8797
+ let latest = 0;
8798
+ for (const gid of groupIds) {
8799
+ const msgs = this.messages.get(gid);
8800
+ if (!msgs) continue;
8801
+ for (const m of msgs) {
8802
+ const ts = Math.floor(m.timestamp / 1e3);
8803
+ if (ts > latest) latest = ts;
8804
+ }
8805
+ }
8806
+ return latest;
8807
+ }
8787
8808
  // ===========================================================================
8788
8809
  // Private — Relay Admin
8789
8810
  // ===========================================================================
@@ -13315,55 +13336,44 @@ var Sphere = class _Sphere {
13315
13336
  * ```
13316
13337
  */
13317
13338
  static async importFromJSON(options) {
13339
+ const { jsonContent, password, ...baseOptions } = options;
13318
13340
  try {
13319
- const data = JSON.parse(options.jsonContent);
13341
+ const data = JSON.parse(jsonContent);
13320
13342
  if (data.version !== "1.0" || data.type !== "sphere-wallet") {
13321
13343
  return { success: false, error: "Invalid wallet format" };
13322
13344
  }
13323
13345
  let mnemonic = data.mnemonic;
13324
13346
  let masterKey = data.wallet.masterPrivateKey;
13325
- if (data.encrypted && options.password) {
13347
+ if (data.encrypted && password) {
13326
13348
  if (mnemonic) {
13327
- const decrypted = decryptSimple(mnemonic, options.password);
13349
+ const decrypted = decryptSimple(mnemonic, password);
13328
13350
  if (!decrypted) {
13329
13351
  return { success: false, error: "Failed to decrypt mnemonic - wrong password?" };
13330
13352
  }
13331
13353
  mnemonic = decrypted;
13332
13354
  }
13333
13355
  if (masterKey) {
13334
- const decrypted = decryptSimple(masterKey, options.password);
13356
+ const decrypted = decryptSimple(masterKey, password);
13335
13357
  if (!decrypted) {
13336
13358
  return { success: false, error: "Failed to decrypt master key - wrong password?" };
13337
13359
  }
13338
13360
  masterKey = decrypted;
13339
13361
  }
13340
- } else if (data.encrypted && !options.password) {
13362
+ } else if (data.encrypted && !password) {
13341
13363
  return { success: false, error: "Password required for encrypted wallet" };
13342
13364
  }
13343
13365
  const basePath = data.wallet.descriptorPath ? `m/${data.wallet.descriptorPath}` : DEFAULT_BASE_PATH;
13344
13366
  if (mnemonic) {
13345
- await _Sphere.import({
13346
- mnemonic,
13347
- basePath,
13348
- storage: options.storage,
13349
- transport: options.transport,
13350
- oracle: options.oracle,
13351
- tokenStorage: options.tokenStorage,
13352
- l1: options.l1
13353
- });
13367
+ await _Sphere.import({ ...baseOptions, mnemonic, basePath });
13354
13368
  return { success: true, mnemonic };
13355
13369
  }
13356
13370
  if (masterKey) {
13357
13371
  await _Sphere.import({
13372
+ ...baseOptions,
13358
13373
  masterKey,
13359
13374
  chainCode: data.wallet.chainCode,
13360
13375
  basePath,
13361
- derivationMode: data.derivationMode || (data.wallet.isBIP32 ? "bip32" : "wif_hmac"),
13362
- storage: options.storage,
13363
- transport: options.transport,
13364
- oracle: options.oracle,
13365
- tokenStorage: options.tokenStorage,
13366
- l1: options.l1
13376
+ derivationMode: data.derivationMode || (data.wallet.isBIP32 ? "bip32" : "wif_hmac")
13367
13377
  });
13368
13378
  return { success: true };
13369
13379
  }
@@ -13406,7 +13416,7 @@ var Sphere = class _Sphere {
13406
13416
  * ```
13407
13417
  */
13408
13418
  static async importFromLegacyFile(options) {
13409
- const { fileContent, fileName, password, onDecryptProgress } = options;
13419
+ const { fileContent, fileName, password, onDecryptProgress, ...baseOptions } = options;
13410
13420
  const fileType = _Sphere.detectLegacyFileType(fileName, fileContent);
13411
13421
  if (fileType === "unknown") {
13412
13422
  return { success: false, error: "Unknown file format" };
@@ -13416,15 +13426,7 @@ var Sphere = class _Sphere {
13416
13426
  if (!_Sphere.validateMnemonic(mnemonic)) {
13417
13427
  return { success: false, error: "Invalid mnemonic phrase" };
13418
13428
  }
13419
- const sphere = await _Sphere.import({
13420
- mnemonic,
13421
- storage: options.storage,
13422
- transport: options.transport,
13423
- oracle: options.oracle,
13424
- tokenStorage: options.tokenStorage,
13425
- nametag: options.nametag,
13426
- l1: options.l1
13427
- });
13429
+ const sphere = await _Sphere.import({ ...baseOptions, mnemonic });
13428
13430
  return { success: true, sphere, mnemonic };
13429
13431
  }
13430
13432
  if (fileType === "dat") {
@@ -13444,16 +13446,11 @@ var Sphere = class _Sphere {
13444
13446
  const { masterKey, chainCode, descriptorPath, derivationMode } = parseResult.data;
13445
13447
  const basePath = descriptorPath ? `m/${descriptorPath}` : DEFAULT_BASE_PATH;
13446
13448
  const sphere = await _Sphere.import({
13449
+ ...baseOptions,
13447
13450
  masterKey,
13448
13451
  chainCode,
13449
13452
  basePath,
13450
- derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac"),
13451
- storage: options.storage,
13452
- transport: options.transport,
13453
- oracle: options.oracle,
13454
- tokenStorage: options.tokenStorage,
13455
- nametag: options.nametag,
13456
- l1: options.l1
13453
+ derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac")
13457
13454
  });
13458
13455
  return { success: true, sphere };
13459
13456
  }
@@ -13476,16 +13473,11 @@ var Sphere = class _Sphere {
13476
13473
  const { masterKey, chainCode, descriptorPath, derivationMode } = parseResult.data;
13477
13474
  const basePath = descriptorPath ? `m/${descriptorPath}` : DEFAULT_BASE_PATH;
13478
13475
  const sphere = await _Sphere.import({
13476
+ ...baseOptions,
13479
13477
  masterKey,
13480
13478
  chainCode,
13481
13479
  basePath,
13482
- derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac"),
13483
- storage: options.storage,
13484
- transport: options.transport,
13485
- oracle: options.oracle,
13486
- tokenStorage: options.tokenStorage,
13487
- nametag: options.nametag,
13488
- l1: options.l1
13480
+ derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac")
13489
13481
  });
13490
13482
  return { success: true, sphere };
13491
13483
  }
@@ -13499,13 +13491,9 @@ var Sphere = class _Sphere {
13499
13491
  }
13500
13492
  if (parsed.type === "sphere-wallet") {
13501
13493
  const result = await _Sphere.importFromJSON({
13494
+ ...baseOptions,
13502
13495
  jsonContent: content,
13503
- password,
13504
- storage: options.storage,
13505
- transport: options.transport,
13506
- oracle: options.oracle,
13507
- tokenStorage: options.tokenStorage,
13508
- l1: options.l1
13496
+ password
13509
13497
  });
13510
13498
  if (result.success) {
13511
13499
  const sphere2 = _Sphere.getInstance();
@@ -13547,29 +13535,15 @@ var Sphere = class _Sphere {
13547
13535
  const isBIP32 = derivationMode === "bip32" || !!chainCode;
13548
13536
  const basePath = descriptorPath ? `m/${descriptorPath}` : isBIP32 ? "m/84'/1'/0'" : DEFAULT_BASE_PATH;
13549
13537
  if (mnemonic) {
13550
- const sphere2 = await _Sphere.import({
13551
- mnemonic,
13552
- basePath,
13553
- storage: options.storage,
13554
- transport: options.transport,
13555
- oracle: options.oracle,
13556
- tokenStorage: options.tokenStorage,
13557
- nametag: options.nametag,
13558
- l1: options.l1
13559
- });
13538
+ const sphere2 = await _Sphere.import({ ...baseOptions, mnemonic, basePath });
13560
13539
  return { success: true, sphere: sphere2, mnemonic };
13561
13540
  }
13562
13541
  const sphere = await _Sphere.import({
13542
+ ...baseOptions,
13563
13543
  masterKey,
13564
13544
  chainCode,
13565
13545
  basePath,
13566
- derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac"),
13567
- storage: options.storage,
13568
- transport: options.transport,
13569
- oracle: options.oracle,
13570
- tokenStorage: options.tokenStorage,
13571
- nametag: options.nametag,
13572
- l1: options.l1
13546
+ derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac")
13573
13547
  });
13574
13548
  return { success: true, sphere };
13575
13549
  }