@unicitylabs/sphere-sdk 0.6.8-dev.1 → 0.6.8-dev.3

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 (44) hide show
  1. package/README.md +30 -0
  2. package/dist/connect/index.cjs +2 -0
  3. package/dist/connect/index.cjs.map +1 -1
  4. package/dist/connect/index.js +2 -0
  5. package/dist/connect/index.js.map +1 -1
  6. package/dist/core/index.cjs +151 -6
  7. package/dist/core/index.cjs.map +1 -1
  8. package/dist/core/index.d.cts +20 -0
  9. package/dist/core/index.d.ts +20 -0
  10. package/dist/core/index.js +151 -6
  11. package/dist/core/index.js.map +1 -1
  12. package/dist/impl/browser/connect/index.cjs +2 -0
  13. package/dist/impl/browser/connect/index.cjs.map +1 -1
  14. package/dist/impl/browser/connect/index.js +2 -0
  15. package/dist/impl/browser/connect/index.js.map +1 -1
  16. package/dist/impl/browser/index.cjs +66 -0
  17. package/dist/impl/browser/index.cjs.map +1 -1
  18. package/dist/impl/browser/index.js +66 -0
  19. package/dist/impl/browser/index.js.map +1 -1
  20. package/dist/impl/browser/ipfs.cjs +2 -0
  21. package/dist/impl/browser/ipfs.cjs.map +1 -1
  22. package/dist/impl/browser/ipfs.js +2 -0
  23. package/dist/impl/browser/ipfs.js.map +1 -1
  24. package/dist/impl/nodejs/connect/index.cjs +2 -0
  25. package/dist/impl/nodejs/connect/index.cjs.map +1 -1
  26. package/dist/impl/nodejs/connect/index.js +2 -0
  27. package/dist/impl/nodejs/connect/index.js.map +1 -1
  28. package/dist/impl/nodejs/index.cjs +66 -0
  29. package/dist/impl/nodejs/index.cjs.map +1 -1
  30. package/dist/impl/nodejs/index.d.cts +15 -0
  31. package/dist/impl/nodejs/index.d.ts +15 -0
  32. package/dist/impl/nodejs/index.js +66 -0
  33. package/dist/impl/nodejs/index.js.map +1 -1
  34. package/dist/index.cjs +151 -6
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +20 -0
  37. package/dist/index.d.ts +20 -0
  38. package/dist/index.js +151 -6
  39. package/dist/index.js.map +1 -1
  40. package/dist/l1/index.cjs +2 -0
  41. package/dist/l1/index.cjs.map +1 -1
  42. package/dist/l1/index.js +2 -0
  43. package/dist/l1/index.js.map +1 -1
  44. package/package.json +1 -1
@@ -191,6 +191,8 @@ var init_constants = __esm({
191
191
  TRACKED_ADDRESSES: "tracked_addresses",
192
192
  /** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */
193
193
  LAST_WALLET_EVENT_TS: "last_wallet_event_ts",
194
+ /** Last processed Nostr DM (gift-wrap) event timestamp (unix seconds), keyed per pubkey */
195
+ LAST_DM_EVENT_TS: "last_dm_event_ts",
194
196
  /** Group chat: last used relay URL (stale data detection) — global, same relay for all addresses */
195
197
  GROUP_CHAT_RELAY_URL: "group_chat_relay_url",
196
198
  /** Cached token registry JSON (fetched from remote) */
@@ -1314,8 +1316,12 @@ var NostrTransportProvider = class _NostrTransportProvider {
1314
1316
  storage = null;
1315
1317
  /** In-memory max event timestamp to avoid read-before-write races in updateLastEventTimestamp. */
1316
1318
  lastEventTs = 0;
1319
+ /** In-memory max DM (gift-wrap) event timestamp. */
1320
+ lastDmEventTs = 0;
1317
1321
  /** Fallback 'since' timestamp for first-time address subscriptions (consumed once). */
1318
1322
  fallbackSince = null;
1323
+ /** Fallback 'since' timestamp for DM (gift-wrap) subscriptions (consumed once). */
1324
+ fallbackDmSince = null;
1319
1325
  identity = null;
1320
1326
  keyManager = null;
1321
1327
  status = "disconnected";
@@ -1570,6 +1576,8 @@ var NostrTransportProvider = class _NostrTransportProvider {
1570
1576
  this.identity = identity;
1571
1577
  this.processedEventIds.clear();
1572
1578
  this.lastEventTs = 0;
1579
+ this.lastDmEventTs = 0;
1580
+ this.fallbackDmSince = null;
1573
1581
  const secretKey = import_buffer.Buffer.from(identity.privateKey, "hex");
1574
1582
  this.keyManager = import_nostr_js_sdk.NostrKeyManager.fromPrivateKey(secretKey);
1575
1583
  const nostrPubkey = this.keyManager.getPublicKeyHex();
@@ -1615,6 +1623,9 @@ var NostrTransportProvider = class _NostrTransportProvider {
1615
1623
  setFallbackSince(sinceSeconds) {
1616
1624
  this.fallbackSince = sinceSeconds;
1617
1625
  }
1626
+ setFallbackDmSince(sinceSeconds) {
1627
+ this.fallbackDmSince = sinceSeconds;
1628
+ }
1618
1629
  /**
1619
1630
  * Get the Nostr-format public key (32 bytes / 64 hex chars)
1620
1631
  * This is the x-coordinate only, without the 02/03 prefix.
@@ -2149,6 +2160,17 @@ var NostrTransportProvider = class _NostrTransportProvider {
2149
2160
  logger.debug("Nostr", "Failed to save last event timestamp:", err);
2150
2161
  });
2151
2162
  }
2163
+ /** Persist the max DM (gift-wrap) event timestamp for the since filter on next connect. */
2164
+ updateLastDmEventTimestamp(createdAt) {
2165
+ if (!this.storage || !this.keyManager) return;
2166
+ if (createdAt <= this.lastDmEventTs) return;
2167
+ this.lastDmEventTs = createdAt;
2168
+ const pubkey = this.keyManager.getPublicKeyHex();
2169
+ const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_DM_EVENT_TS}_${pubkey.slice(0, 16)}`;
2170
+ this.storage.set(storageKey, createdAt.toString()).catch((err) => {
2171
+ logger.debug("Nostr", "Failed to save last DM event timestamp:", err);
2172
+ });
2173
+ }
2152
2174
  async handleDirectMessage(event) {
2153
2175
  logger.debug("Nostr", "Ignoring NIP-04 kind 4 event (DMs use NIP-17):", event.id?.slice(0, 12));
2154
2176
  }
@@ -2159,6 +2181,9 @@ var NostrTransportProvider = class _NostrTransportProvider {
2159
2181
  }
2160
2182
  try {
2161
2183
  const pm = import_nostr_js_sdk.NIP17.unwrap(event, this.keyManager);
2184
+ if (event.created_at) {
2185
+ this.updateLastDmEventTimestamp(event.created_at);
2186
+ }
2162
2187
  logger.debug("Nostr", "Gift wrap unwrapped, sender:", pm.senderPubkey?.slice(0, 16), "kind:", pm.kind);
2163
2188
  if (pm.senderPubkey === this.keyManager.getPublicKeyHex()) {
2164
2189
  try {
@@ -2605,9 +2630,50 @@ var NostrTransportProvider = class _NostrTransportProvider {
2605
2630
  }
2606
2631
  });
2607
2632
  logger.debug("Nostr", "Wallet subscription created, subId:", this.walletSubscriptionId);
2633
+ let dmSince;
2634
+ if (this.storage) {
2635
+ const dmStorageKey = `${STORAGE_KEYS_GLOBAL.LAST_DM_EVENT_TS}_${nostrPubkey.slice(0, 16)}`;
2636
+ try {
2637
+ const stored = await this.storage.get(dmStorageKey);
2638
+ const parsed = stored ? parseInt(stored, 10) : NaN;
2639
+ if (Number.isFinite(parsed)) {
2640
+ dmSince = parsed;
2641
+ this.lastDmEventTs = dmSince;
2642
+ this.fallbackDmSince = null;
2643
+ logger.debug("Nostr", "DM resuming from stored timestamp:", dmSince);
2644
+ } else if (this.fallbackDmSince !== null) {
2645
+ dmSince = this.fallbackDmSince;
2646
+ this.lastDmEventTs = dmSince;
2647
+ this.fallbackDmSince = null;
2648
+ logger.debug("Nostr", "DM using fallback since timestamp:", dmSince);
2649
+ } else {
2650
+ dmSince = Math.floor(Date.now() / 1e3);
2651
+ logger.debug("Nostr", "No stored DM timestamp, starting from now:", dmSince);
2652
+ }
2653
+ } catch (err) {
2654
+ if (this.fallbackDmSince !== null) {
2655
+ dmSince = this.fallbackDmSince;
2656
+ this.lastDmEventTs = dmSince;
2657
+ this.fallbackDmSince = null;
2658
+ logger.debug("Nostr", "Storage read failed, using DM fallback since:", dmSince, err);
2659
+ } else {
2660
+ dmSince = Math.floor(Date.now() / 1e3);
2661
+ logger.debug("Nostr", "Failed to read last DM event timestamp, falling back to now:", err);
2662
+ }
2663
+ }
2664
+ } else if (this.fallbackDmSince !== null) {
2665
+ dmSince = this.fallbackDmSince;
2666
+ this.lastDmEventTs = dmSince;
2667
+ this.fallbackDmSince = null;
2668
+ logger.debug("Nostr", "No storage adapter for DM, using fallback since:", dmSince);
2669
+ } else {
2670
+ dmSince = Math.floor(Date.now() / 1e3);
2671
+ logger.debug("Nostr", "No storage adapter for DM, starting from now:", dmSince);
2672
+ }
2608
2673
  const chatFilter = new import_nostr_js_sdk.Filter();
2609
2674
  chatFilter.kinds = [import_nostr_js_sdk.EventKinds.GIFT_WRAP];
2610
2675
  chatFilter["#p"] = [nostrPubkey];
2676
+ chatFilter.since = dmSince;
2611
2677
  this.chatSubscriptionId = this.nostrClient.subscribe(chatFilter, {
2612
2678
  onEvent: (event) => {
2613
2679
  logger.debug("Nostr", "Received chat event kind:", event.kind, "id:", event.id?.slice(0, 12));
@@ -2852,7 +2918,9 @@ var MultiAddressTransportMux = class {
2852
2918
  nostrPubkey,
2853
2919
  adapter,
2854
2920
  lastEventTs: 0,
2855
- fallbackSince: null
2921
+ lastDmEventTs: 0,
2922
+ fallbackSince: null,
2923
+ fallbackDmSince: null
2856
2924
  };
2857
2925
  this.addresses.set(index, entry);
2858
2926
  this.pubkeyToIndex.set(nostrPubkey, index);
@@ -2894,6 +2962,12 @@ var MultiAddressTransportMux = class {
2894
2962
  entry.fallbackSince = sinceSeconds;
2895
2963
  }
2896
2964
  }
2965
+ setFallbackDmSince(index, sinceSeconds) {
2966
+ const entry = this.addresses.get(index);
2967
+ if (entry) {
2968
+ entry.fallbackDmSince = sinceSeconds;
2969
+ }
2970
+ }
2897
2971
  // ===========================================================================
2898
2972
  // Connection Management (delegated from adapters)
2899
2973
  // ===========================================================================
@@ -3029,11 +3103,20 @@ var MultiAddressTransportMux = class {
3029
3103
  }
3030
3104
  logger.debug("Mux", `Subscribing for ${allPubkeys.length} address(es):`, allPubkeys.map((p) => p.slice(0, 12)).join(", "));
3031
3105
  let globalSince = Math.floor(Date.now() / 1e3);
3032
- for (const entry of this.addresses.values()) {
3033
- const since = await this.getAddressSince(entry);
3034
- if (since < globalSince) {
3035
- globalSince = since;
3036
- }
3106
+ let globalDmSince = Math.floor(Date.now() / 1e3);
3107
+ const entries = [...this.addresses.values()];
3108
+ const sinceResults = await Promise.all(
3109
+ entries.map(async (entry) => {
3110
+ const [walletSince, dmSince] = await Promise.all([
3111
+ this.getAddressSince(entry),
3112
+ this.getAddressDmSince(entry)
3113
+ ]);
3114
+ return { walletSince, dmSince };
3115
+ })
3116
+ );
3117
+ for (const { walletSince, dmSince } of sinceResults) {
3118
+ if (walletSince < globalSince) globalSince = walletSince;
3119
+ if (dmSince < globalDmSince) globalDmSince = dmSince;
3037
3120
  }
3038
3121
  const walletFilter = new import_nostr_js_sdk2.Filter();
3039
3122
  walletFilter.kinds = [
@@ -3066,6 +3149,7 @@ var MultiAddressTransportMux = class {
3066
3149
  const chatFilter = new import_nostr_js_sdk2.Filter();
3067
3150
  chatFilter.kinds = [import_nostr_js_sdk2.EventKinds.GIFT_WRAP];
3068
3151
  chatFilter["#p"] = allPubkeys;
3152
+ chatFilter.since = globalDmSince;
3069
3153
  this.chatSubscriptionId = this.nostrClient.subscribe(chatFilter, {
3070
3154
  onEvent: (event) => {
3071
3155
  this.handleEvent({
@@ -3172,6 +3256,9 @@ var MultiAddressTransportMux = class {
3172
3256
  for (const entry of this.addresses.values()) {
3173
3257
  try {
3174
3258
  const pm = import_nostr_js_sdk2.NIP17.unwrap(event, entry.keyManager);
3259
+ if (event.created_at) {
3260
+ this.updateLastDmEventTimestamp(entry, event.created_at);
3261
+ }
3175
3262
  logger.debug("Mux", `Gift wrap decrypted by address ${entry.index}, sender: ${pm.senderPubkey?.slice(0, 16)}`);
3176
3263
  if (pm.senderPubkey === entry.nostrPubkey) {
3177
3264
  try {
@@ -3528,6 +3615,47 @@ var MultiAddressTransportMux = class {
3528
3615
  logger.debug("Mux", "Failed to save last event timestamp:", err);
3529
3616
  });
3530
3617
  }
3618
+ updateLastDmEventTimestamp(entry, createdAt) {
3619
+ if (!this.storage) return;
3620
+ if (createdAt <= entry.lastDmEventTs) return;
3621
+ entry.lastDmEventTs = createdAt;
3622
+ const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_DM_EVENT_TS}_${entry.nostrPubkey.slice(0, 16)}`;
3623
+ this.storage.set(storageKey, createdAt.toString()).catch((err) => {
3624
+ logger.debug("Mux", "Failed to save last DM event timestamp:", err);
3625
+ });
3626
+ }
3627
+ async getAddressDmSince(entry) {
3628
+ if (this.storage) {
3629
+ const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_DM_EVENT_TS}_${entry.nostrPubkey.slice(0, 16)}`;
3630
+ try {
3631
+ const stored = await this.storage.get(storageKey);
3632
+ const parsed = stored ? parseInt(stored, 10) : NaN;
3633
+ if (Number.isFinite(parsed)) {
3634
+ entry.lastDmEventTs = parsed;
3635
+ entry.fallbackDmSince = null;
3636
+ return parsed;
3637
+ } else if (entry.fallbackDmSince !== null) {
3638
+ const ts = entry.fallbackDmSince;
3639
+ entry.lastDmEventTs = ts;
3640
+ entry.fallbackDmSince = null;
3641
+ return ts;
3642
+ }
3643
+ } catch {
3644
+ if (entry.fallbackDmSince !== null) {
3645
+ const ts = entry.fallbackDmSince;
3646
+ entry.lastDmEventTs = ts;
3647
+ entry.fallbackDmSince = null;
3648
+ return ts;
3649
+ }
3650
+ }
3651
+ } else if (entry.fallbackDmSince !== null) {
3652
+ const ts = entry.fallbackDmSince;
3653
+ entry.lastDmEventTs = ts;
3654
+ entry.fallbackDmSince = null;
3655
+ return ts;
3656
+ }
3657
+ return Math.floor(Date.now() / 1e3);
3658
+ }
3531
3659
  // ===========================================================================
3532
3660
  // Mux-level event system
3533
3661
  // ===========================================================================
@@ -3824,6 +3952,9 @@ var AddressTransportAdapter = class {
3824
3952
  setFallbackSince(sinceSeconds) {
3825
3953
  this.mux.setFallbackSince(this.addressIndex, sinceSeconds);
3826
3954
  }
3955
+ setFallbackDmSince(sinceSeconds) {
3956
+ this.mux.setFallbackDmSince(this.addressIndex, sinceSeconds);
3957
+ }
3827
3958
  async fetchPendingEvents() {
3828
3959
  }
3829
3960
  onChatReady(handler) {
@@ -16482,6 +16613,8 @@ var Sphere = class _Sphere {
16482
16613
  // Per-address module instances (Phase 2: independent parallel operation)
16483
16614
  _addressModules = /* @__PURE__ */ new Map();
16484
16615
  _transportMux = null;
16616
+ /** Fallback DM since timestamp from init options, forwarded to mux on creation. */
16617
+ _dmSince = null;
16485
16618
  // Stored configs for creating per-address modules
16486
16619
  _l1Config;
16487
16620
  _groupChatConfig;
@@ -16583,6 +16716,9 @@ var Sphere = class _Sphere {
16583
16716
  discoverAddresses: options.discoverAddresses,
16584
16717
  onProgress: options.onProgress
16585
16718
  });
16719
+ if (options.dmSince != null) {
16720
+ sphere2._dmSince = options.dmSince;
16721
+ }
16586
16722
  return { sphere: sphere2, created: false };
16587
16723
  }
16588
16724
  let mnemonic = options.mnemonic;
@@ -16614,6 +16750,9 @@ var Sphere = class _Sphere {
16614
16750
  discoverAddresses: options.discoverAddresses,
16615
16751
  onProgress: options.onProgress
16616
16752
  });
16753
+ if (options.dmSince != null) {
16754
+ sphere._dmSince = options.dmSince;
16755
+ }
16617
16756
  return { sphere, created: true, generatedMnemonic };
16618
16757
  }
16619
16758
  /**
@@ -17887,6 +18026,9 @@ var Sphere = class _Sphere {
17887
18026
  const emitEvent = this.emitEvent.bind(this);
17888
18027
  const adapter = await this.ensureTransportMux(index, identity);
17889
18028
  const addressTransport = adapter ?? this._transport;
18029
+ if (!adapter && this._dmSince != null && addressTransport.setFallbackDmSince) {
18030
+ addressTransport.setFallbackDmSince(this._dmSince);
18031
+ }
17890
18032
  const payments = createPaymentsModule({ l1: this._l1Config });
17891
18033
  const communications = createCommunicationsModule();
17892
18034
  const groupChat = this._groupChatConfig ? createGroupChatModule(this._groupChatConfig) : null;
@@ -17970,6 +18112,9 @@ var Sphere = class _Sphere {
17970
18112
  }
17971
18113
  logger.debug("Sphere", "Transport mux created and connected");
17972
18114
  }
18115
+ if (this._dmSince != null) {
18116
+ this._transportMux.setFallbackDmSince(index, this._dmSince);
18117
+ }
17973
18118
  const adapter = await this._transportMux.addAddress(index, identity, this._transport);
17974
18119
  return adapter;
17975
18120
  }