@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
package/dist/index.cjs CHANGED
@@ -195,6 +195,8 @@ var init_constants = __esm({
195
195
  TRACKED_ADDRESSES: "tracked_addresses",
196
196
  /** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */
197
197
  LAST_WALLET_EVENT_TS: "last_wallet_event_ts",
198
+ /** Last processed Nostr DM (gift-wrap) event timestamp (unix seconds), keyed per pubkey */
199
+ LAST_DM_EVENT_TS: "last_dm_event_ts",
198
200
  /** Group chat: last used relay URL (stale data detection) — global, same relay for all addresses */
199
201
  GROUP_CHAT_RELAY_URL: "group_chat_relay_url",
200
202
  /** Cached token registry JSON (fetched from remote) */
@@ -1412,8 +1414,12 @@ var NostrTransportProvider = class _NostrTransportProvider {
1412
1414
  storage = null;
1413
1415
  /** In-memory max event timestamp to avoid read-before-write races in updateLastEventTimestamp. */
1414
1416
  lastEventTs = 0;
1417
+ /** In-memory max DM (gift-wrap) event timestamp. */
1418
+ lastDmEventTs = 0;
1415
1419
  /** Fallback 'since' timestamp for first-time address subscriptions (consumed once). */
1416
1420
  fallbackSince = null;
1421
+ /** Fallback 'since' timestamp for DM (gift-wrap) subscriptions (consumed once). */
1422
+ fallbackDmSince = null;
1417
1423
  identity = null;
1418
1424
  keyManager = null;
1419
1425
  status = "disconnected";
@@ -1668,6 +1674,8 @@ var NostrTransportProvider = class _NostrTransportProvider {
1668
1674
  this.identity = identity;
1669
1675
  this.processedEventIds.clear();
1670
1676
  this.lastEventTs = 0;
1677
+ this.lastDmEventTs = 0;
1678
+ this.fallbackDmSince = null;
1671
1679
  const secretKey = import_buffer.Buffer.from(identity.privateKey, "hex");
1672
1680
  this.keyManager = import_nostr_js_sdk.NostrKeyManager.fromPrivateKey(secretKey);
1673
1681
  const nostrPubkey = this.keyManager.getPublicKeyHex();
@@ -1713,6 +1721,9 @@ var NostrTransportProvider = class _NostrTransportProvider {
1713
1721
  setFallbackSince(sinceSeconds) {
1714
1722
  this.fallbackSince = sinceSeconds;
1715
1723
  }
1724
+ setFallbackDmSince(sinceSeconds) {
1725
+ this.fallbackDmSince = sinceSeconds;
1726
+ }
1716
1727
  /**
1717
1728
  * Get the Nostr-format public key (32 bytes / 64 hex chars)
1718
1729
  * This is the x-coordinate only, without the 02/03 prefix.
@@ -2247,6 +2258,17 @@ var NostrTransportProvider = class _NostrTransportProvider {
2247
2258
  logger.debug("Nostr", "Failed to save last event timestamp:", err);
2248
2259
  });
2249
2260
  }
2261
+ /** Persist the max DM (gift-wrap) event timestamp for the since filter on next connect. */
2262
+ updateLastDmEventTimestamp(createdAt) {
2263
+ if (!this.storage || !this.keyManager) return;
2264
+ if (createdAt <= this.lastDmEventTs) return;
2265
+ this.lastDmEventTs = createdAt;
2266
+ const pubkey = this.keyManager.getPublicKeyHex();
2267
+ const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_DM_EVENT_TS}_${pubkey.slice(0, 16)}`;
2268
+ this.storage.set(storageKey, createdAt.toString()).catch((err) => {
2269
+ logger.debug("Nostr", "Failed to save last DM event timestamp:", err);
2270
+ });
2271
+ }
2250
2272
  async handleDirectMessage(event) {
2251
2273
  logger.debug("Nostr", "Ignoring NIP-04 kind 4 event (DMs use NIP-17):", event.id?.slice(0, 12));
2252
2274
  }
@@ -2257,6 +2279,9 @@ var NostrTransportProvider = class _NostrTransportProvider {
2257
2279
  }
2258
2280
  try {
2259
2281
  const pm = import_nostr_js_sdk.NIP17.unwrap(event, this.keyManager);
2282
+ if (event.created_at) {
2283
+ this.updateLastDmEventTimestamp(event.created_at);
2284
+ }
2260
2285
  logger.debug("Nostr", "Gift wrap unwrapped, sender:", pm.senderPubkey?.slice(0, 16), "kind:", pm.kind);
2261
2286
  if (pm.senderPubkey === this.keyManager.getPublicKeyHex()) {
2262
2287
  try {
@@ -2703,9 +2728,50 @@ var NostrTransportProvider = class _NostrTransportProvider {
2703
2728
  }
2704
2729
  });
2705
2730
  logger.debug("Nostr", "Wallet subscription created, subId:", this.walletSubscriptionId);
2731
+ let dmSince;
2732
+ if (this.storage) {
2733
+ const dmStorageKey = `${STORAGE_KEYS_GLOBAL.LAST_DM_EVENT_TS}_${nostrPubkey.slice(0, 16)}`;
2734
+ try {
2735
+ const stored = await this.storage.get(dmStorageKey);
2736
+ const parsed = stored ? parseInt(stored, 10) : NaN;
2737
+ if (Number.isFinite(parsed)) {
2738
+ dmSince = parsed;
2739
+ this.lastDmEventTs = dmSince;
2740
+ this.fallbackDmSince = null;
2741
+ logger.debug("Nostr", "DM resuming from stored timestamp:", dmSince);
2742
+ } else if (this.fallbackDmSince !== null) {
2743
+ dmSince = this.fallbackDmSince;
2744
+ this.lastDmEventTs = dmSince;
2745
+ this.fallbackDmSince = null;
2746
+ logger.debug("Nostr", "DM using fallback since timestamp:", dmSince);
2747
+ } else {
2748
+ dmSince = Math.floor(Date.now() / 1e3);
2749
+ logger.debug("Nostr", "No stored DM timestamp, starting from now:", dmSince);
2750
+ }
2751
+ } catch (err) {
2752
+ if (this.fallbackDmSince !== null) {
2753
+ dmSince = this.fallbackDmSince;
2754
+ this.lastDmEventTs = dmSince;
2755
+ this.fallbackDmSince = null;
2756
+ logger.debug("Nostr", "Storage read failed, using DM fallback since:", dmSince, err);
2757
+ } else {
2758
+ dmSince = Math.floor(Date.now() / 1e3);
2759
+ logger.debug("Nostr", "Failed to read last DM event timestamp, falling back to now:", err);
2760
+ }
2761
+ }
2762
+ } else if (this.fallbackDmSince !== null) {
2763
+ dmSince = this.fallbackDmSince;
2764
+ this.lastDmEventTs = dmSince;
2765
+ this.fallbackDmSince = null;
2766
+ logger.debug("Nostr", "No storage adapter for DM, using fallback since:", dmSince);
2767
+ } else {
2768
+ dmSince = Math.floor(Date.now() / 1e3);
2769
+ logger.debug("Nostr", "No storage adapter for DM, starting from now:", dmSince);
2770
+ }
2706
2771
  const chatFilter = new import_nostr_js_sdk.Filter();
2707
2772
  chatFilter.kinds = [import_nostr_js_sdk.EventKinds.GIFT_WRAP];
2708
2773
  chatFilter["#p"] = [nostrPubkey];
2774
+ chatFilter.since = dmSince;
2709
2775
  this.chatSubscriptionId = this.nostrClient.subscribe(chatFilter, {
2710
2776
  onEvent: (event) => {
2711
2777
  logger.debug("Nostr", "Received chat event kind:", event.kind, "id:", event.id?.slice(0, 12));
@@ -2950,7 +3016,9 @@ var MultiAddressTransportMux = class {
2950
3016
  nostrPubkey,
2951
3017
  adapter,
2952
3018
  lastEventTs: 0,
2953
- fallbackSince: null
3019
+ lastDmEventTs: 0,
3020
+ fallbackSince: null,
3021
+ fallbackDmSince: null
2954
3022
  };
2955
3023
  this.addresses.set(index, entry);
2956
3024
  this.pubkeyToIndex.set(nostrPubkey, index);
@@ -2992,6 +3060,12 @@ var MultiAddressTransportMux = class {
2992
3060
  entry.fallbackSince = sinceSeconds;
2993
3061
  }
2994
3062
  }
3063
+ setFallbackDmSince(index, sinceSeconds) {
3064
+ const entry = this.addresses.get(index);
3065
+ if (entry) {
3066
+ entry.fallbackDmSince = sinceSeconds;
3067
+ }
3068
+ }
2995
3069
  // ===========================================================================
2996
3070
  // Connection Management (delegated from adapters)
2997
3071
  // ===========================================================================
@@ -3127,11 +3201,20 @@ var MultiAddressTransportMux = class {
3127
3201
  }
3128
3202
  logger.debug("Mux", `Subscribing for ${allPubkeys.length} address(es):`, allPubkeys.map((p) => p.slice(0, 12)).join(", "));
3129
3203
  let globalSince = Math.floor(Date.now() / 1e3);
3130
- for (const entry of this.addresses.values()) {
3131
- const since = await this.getAddressSince(entry);
3132
- if (since < globalSince) {
3133
- globalSince = since;
3134
- }
3204
+ let globalDmSince = Math.floor(Date.now() / 1e3);
3205
+ const entries = [...this.addresses.values()];
3206
+ const sinceResults = await Promise.all(
3207
+ entries.map(async (entry) => {
3208
+ const [walletSince, dmSince] = await Promise.all([
3209
+ this.getAddressSince(entry),
3210
+ this.getAddressDmSince(entry)
3211
+ ]);
3212
+ return { walletSince, dmSince };
3213
+ })
3214
+ );
3215
+ for (const { walletSince, dmSince } of sinceResults) {
3216
+ if (walletSince < globalSince) globalSince = walletSince;
3217
+ if (dmSince < globalDmSince) globalDmSince = dmSince;
3135
3218
  }
3136
3219
  const walletFilter = new import_nostr_js_sdk2.Filter();
3137
3220
  walletFilter.kinds = [
@@ -3164,6 +3247,7 @@ var MultiAddressTransportMux = class {
3164
3247
  const chatFilter = new import_nostr_js_sdk2.Filter();
3165
3248
  chatFilter.kinds = [import_nostr_js_sdk2.EventKinds.GIFT_WRAP];
3166
3249
  chatFilter["#p"] = allPubkeys;
3250
+ chatFilter.since = globalDmSince;
3167
3251
  this.chatSubscriptionId = this.nostrClient.subscribe(chatFilter, {
3168
3252
  onEvent: (event) => {
3169
3253
  this.handleEvent({
@@ -3270,6 +3354,9 @@ var MultiAddressTransportMux = class {
3270
3354
  for (const entry of this.addresses.values()) {
3271
3355
  try {
3272
3356
  const pm = import_nostr_js_sdk2.NIP17.unwrap(event, entry.keyManager);
3357
+ if (event.created_at) {
3358
+ this.updateLastDmEventTimestamp(entry, event.created_at);
3359
+ }
3273
3360
  logger.debug("Mux", `Gift wrap decrypted by address ${entry.index}, sender: ${pm.senderPubkey?.slice(0, 16)}`);
3274
3361
  if (pm.senderPubkey === entry.nostrPubkey) {
3275
3362
  try {
@@ -3626,6 +3713,47 @@ var MultiAddressTransportMux = class {
3626
3713
  logger.debug("Mux", "Failed to save last event timestamp:", err);
3627
3714
  });
3628
3715
  }
3716
+ updateLastDmEventTimestamp(entry, createdAt) {
3717
+ if (!this.storage) return;
3718
+ if (createdAt <= entry.lastDmEventTs) return;
3719
+ entry.lastDmEventTs = createdAt;
3720
+ const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_DM_EVENT_TS}_${entry.nostrPubkey.slice(0, 16)}`;
3721
+ this.storage.set(storageKey, createdAt.toString()).catch((err) => {
3722
+ logger.debug("Mux", "Failed to save last DM event timestamp:", err);
3723
+ });
3724
+ }
3725
+ async getAddressDmSince(entry) {
3726
+ if (this.storage) {
3727
+ const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_DM_EVENT_TS}_${entry.nostrPubkey.slice(0, 16)}`;
3728
+ try {
3729
+ const stored = await this.storage.get(storageKey);
3730
+ const parsed = stored ? parseInt(stored, 10) : NaN;
3731
+ if (Number.isFinite(parsed)) {
3732
+ entry.lastDmEventTs = parsed;
3733
+ entry.fallbackDmSince = null;
3734
+ return parsed;
3735
+ } else if (entry.fallbackDmSince !== null) {
3736
+ const ts = entry.fallbackDmSince;
3737
+ entry.lastDmEventTs = ts;
3738
+ entry.fallbackDmSince = null;
3739
+ return ts;
3740
+ }
3741
+ } catch {
3742
+ if (entry.fallbackDmSince !== null) {
3743
+ const ts = entry.fallbackDmSince;
3744
+ entry.lastDmEventTs = ts;
3745
+ entry.fallbackDmSince = null;
3746
+ return ts;
3747
+ }
3748
+ }
3749
+ } else if (entry.fallbackDmSince !== null) {
3750
+ const ts = entry.fallbackDmSince;
3751
+ entry.lastDmEventTs = ts;
3752
+ entry.fallbackDmSince = null;
3753
+ return ts;
3754
+ }
3755
+ return Math.floor(Date.now() / 1e3);
3756
+ }
3629
3757
  // ===========================================================================
3630
3758
  // Mux-level event system
3631
3759
  // ===========================================================================
@@ -3922,6 +4050,9 @@ var AddressTransportAdapter = class {
3922
4050
  setFallbackSince(sinceSeconds) {
3923
4051
  this.mux.setFallbackSince(this.addressIndex, sinceSeconds);
3924
4052
  }
4053
+ setFallbackDmSince(sinceSeconds) {
4054
+ this.mux.setFallbackDmSince(this.addressIndex, sinceSeconds);
4055
+ }
3925
4056
  async fetchPendingEvents() {
3926
4057
  }
3927
4058
  onChatReady(handler) {
@@ -16737,6 +16868,8 @@ var Sphere = class _Sphere {
16737
16868
  // Per-address module instances (Phase 2: independent parallel operation)
16738
16869
  _addressModules = /* @__PURE__ */ new Map();
16739
16870
  _transportMux = null;
16871
+ /** Fallback DM since timestamp from init options, forwarded to mux on creation. */
16872
+ _dmSince = null;
16740
16873
  // Stored configs for creating per-address modules
16741
16874
  _l1Config;
16742
16875
  _groupChatConfig;
@@ -16838,6 +16971,9 @@ var Sphere = class _Sphere {
16838
16971
  discoverAddresses: options.discoverAddresses,
16839
16972
  onProgress: options.onProgress
16840
16973
  });
16974
+ if (options.dmSince != null) {
16975
+ sphere2._dmSince = options.dmSince;
16976
+ }
16841
16977
  return { sphere: sphere2, created: false };
16842
16978
  }
16843
16979
  let mnemonic = options.mnemonic;
@@ -16869,6 +17005,9 @@ var Sphere = class _Sphere {
16869
17005
  discoverAddresses: options.discoverAddresses,
16870
17006
  onProgress: options.onProgress
16871
17007
  });
17008
+ if (options.dmSince != null) {
17009
+ sphere._dmSince = options.dmSince;
17010
+ }
16872
17011
  return { sphere, created: true, generatedMnemonic };
16873
17012
  }
16874
17013
  /**
@@ -18142,6 +18281,9 @@ var Sphere = class _Sphere {
18142
18281
  const emitEvent = this.emitEvent.bind(this);
18143
18282
  const adapter = await this.ensureTransportMux(index, identity);
18144
18283
  const addressTransport = adapter ?? this._transport;
18284
+ if (!adapter && this._dmSince != null && addressTransport.setFallbackDmSince) {
18285
+ addressTransport.setFallbackDmSince(this._dmSince);
18286
+ }
18145
18287
  const payments = createPaymentsModule({ l1: this._l1Config });
18146
18288
  const communications = createCommunicationsModule();
18147
18289
  const groupChat = this._groupChatConfig ? createGroupChatModule(this._groupChatConfig) : null;
@@ -18225,6 +18367,9 @@ var Sphere = class _Sphere {
18225
18367
  }
18226
18368
  logger.debug("Sphere", "Transport mux created and connected");
18227
18369
  }
18370
+ if (this._dmSince != null) {
18371
+ this._transportMux.setFallbackDmSince(index, this._dmSince);
18372
+ }
18228
18373
  const adapter = await this._transportMux.addAddress(index, identity, this._transport);
18229
18374
  return adapter;
18230
18375
  }