@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
@@ -206,6 +206,14 @@ interface TransportProvider extends BaseProvider {
206
206
  * @param sinceSeconds - Unix timestamp in seconds
207
207
  */
208
208
  setFallbackSince?(sinceSeconds: number): void;
209
+ /**
210
+ * Set fallback 'since' timestamp for DM (gift-wrap) subscriptions.
211
+ * Used when no persisted DM timestamp exists in storage (e.g. first connect).
212
+ * Consumed once by the next subscription setup, then cleared.
213
+ *
214
+ * @param sinceSeconds - Unix timestamp in seconds
215
+ */
216
+ setFallbackDmSince?(sinceSeconds: number): void;
209
217
  /**
210
218
  * Fetch pending events from transport (one-shot query).
211
219
  * Creates a temporary subscription, processes events through normal handlers,
@@ -487,8 +495,12 @@ declare class NostrTransportProvider implements TransportProvider {
487
495
  private storage;
488
496
  /** In-memory max event timestamp to avoid read-before-write races in updateLastEventTimestamp. */
489
497
  private lastEventTs;
498
+ /** In-memory max DM (gift-wrap) event timestamp. */
499
+ private lastDmEventTs;
490
500
  /** Fallback 'since' timestamp for first-time address subscriptions (consumed once). */
491
501
  private fallbackSince;
502
+ /** Fallback 'since' timestamp for DM (gift-wrap) subscriptions (consumed once). */
503
+ private fallbackDmSince;
492
504
  private identity;
493
505
  private keyManager;
494
506
  private status;
@@ -559,6 +571,7 @@ declare class NostrTransportProvider implements TransportProvider {
559
571
  isRelayConnected(relayUrl: string): boolean;
560
572
  setIdentity(identity: FullIdentity): Promise<void>;
561
573
  setFallbackSince(sinceSeconds: number): void;
574
+ setFallbackDmSince(sinceSeconds: number): void;
562
575
  /**
563
576
  * Get the Nostr-format public key (32 bytes / 64 hex chars)
564
577
  * This is the x-coordinate only, without the 02/03 prefix.
@@ -633,6 +646,8 @@ declare class NostrTransportProvider implements TransportProvider {
633
646
  * when multiple events arrive in quick succession.
634
647
  */
635
648
  private updateLastEventTimestamp;
649
+ /** Persist the max DM (gift-wrap) event timestamp for the since filter on next connect. */
650
+ private updateLastDmEventTimestamp;
636
651
  private handleDirectMessage;
637
652
  private handleGiftWrap;
638
653
  private handleTokenTransfer;
@@ -206,6 +206,14 @@ interface TransportProvider extends BaseProvider {
206
206
  * @param sinceSeconds - Unix timestamp in seconds
207
207
  */
208
208
  setFallbackSince?(sinceSeconds: number): void;
209
+ /**
210
+ * Set fallback 'since' timestamp for DM (gift-wrap) subscriptions.
211
+ * Used when no persisted DM timestamp exists in storage (e.g. first connect).
212
+ * Consumed once by the next subscription setup, then cleared.
213
+ *
214
+ * @param sinceSeconds - Unix timestamp in seconds
215
+ */
216
+ setFallbackDmSince?(sinceSeconds: number): void;
209
217
  /**
210
218
  * Fetch pending events from transport (one-shot query).
211
219
  * Creates a temporary subscription, processes events through normal handlers,
@@ -487,8 +495,12 @@ declare class NostrTransportProvider implements TransportProvider {
487
495
  private storage;
488
496
  /** In-memory max event timestamp to avoid read-before-write races in updateLastEventTimestamp. */
489
497
  private lastEventTs;
498
+ /** In-memory max DM (gift-wrap) event timestamp. */
499
+ private lastDmEventTs;
490
500
  /** Fallback 'since' timestamp for first-time address subscriptions (consumed once). */
491
501
  private fallbackSince;
502
+ /** Fallback 'since' timestamp for DM (gift-wrap) subscriptions (consumed once). */
503
+ private fallbackDmSince;
492
504
  private identity;
493
505
  private keyManager;
494
506
  private status;
@@ -559,6 +571,7 @@ declare class NostrTransportProvider implements TransportProvider {
559
571
  isRelayConnected(relayUrl: string): boolean;
560
572
  setIdentity(identity: FullIdentity): Promise<void>;
561
573
  setFallbackSince(sinceSeconds: number): void;
574
+ setFallbackDmSince(sinceSeconds: number): void;
562
575
  /**
563
576
  * Get the Nostr-format public key (32 bytes / 64 hex chars)
564
577
  * This is the x-coordinate only, without the 02/03 prefix.
@@ -633,6 +646,8 @@ declare class NostrTransportProvider implements TransportProvider {
633
646
  * when multiple events arrive in quick succession.
634
647
  */
635
648
  private updateLastEventTimestamp;
649
+ /** Persist the max DM (gift-wrap) event timestamp for the since filter on next connect. */
650
+ private updateLastDmEventTimestamp;
636
651
  private handleDirectMessage;
637
652
  private handleGiftWrap;
638
653
  private handleTokenTransfer;
@@ -28,6 +28,8 @@ var STORAGE_KEYS_GLOBAL = {
28
28
  TRACKED_ADDRESSES: "tracked_addresses",
29
29
  /** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */
30
30
  LAST_WALLET_EVENT_TS: "last_wallet_event_ts",
31
+ /** Last processed Nostr DM (gift-wrap) event timestamp (unix seconds), keyed per pubkey */
32
+ LAST_DM_EVENT_TS: "last_dm_event_ts",
31
33
  /** Group chat: last used relay URL (stale data detection) — global, same relay for all addresses */
32
34
  GROUP_CHAT_RELAY_URL: "group_chat_relay_url",
33
35
  /** Cached token registry JSON (fetched from remote) */
@@ -1087,8 +1089,12 @@ var NostrTransportProvider = class _NostrTransportProvider {
1087
1089
  storage = null;
1088
1090
  /** In-memory max event timestamp to avoid read-before-write races in updateLastEventTimestamp. */
1089
1091
  lastEventTs = 0;
1092
+ /** In-memory max DM (gift-wrap) event timestamp. */
1093
+ lastDmEventTs = 0;
1090
1094
  /** Fallback 'since' timestamp for first-time address subscriptions (consumed once). */
1091
1095
  fallbackSince = null;
1096
+ /** Fallback 'since' timestamp for DM (gift-wrap) subscriptions (consumed once). */
1097
+ fallbackDmSince = null;
1092
1098
  identity = null;
1093
1099
  keyManager = null;
1094
1100
  status = "disconnected";
@@ -1343,6 +1349,8 @@ var NostrTransportProvider = class _NostrTransportProvider {
1343
1349
  this.identity = identity;
1344
1350
  this.processedEventIds.clear();
1345
1351
  this.lastEventTs = 0;
1352
+ this.lastDmEventTs = 0;
1353
+ this.fallbackDmSince = null;
1346
1354
  const secretKey = Buffer2.from(identity.privateKey, "hex");
1347
1355
  this.keyManager = NostrKeyManager.fromPrivateKey(secretKey);
1348
1356
  const nostrPubkey = this.keyManager.getPublicKeyHex();
@@ -1388,6 +1396,9 @@ var NostrTransportProvider = class _NostrTransportProvider {
1388
1396
  setFallbackSince(sinceSeconds) {
1389
1397
  this.fallbackSince = sinceSeconds;
1390
1398
  }
1399
+ setFallbackDmSince(sinceSeconds) {
1400
+ this.fallbackDmSince = sinceSeconds;
1401
+ }
1391
1402
  /**
1392
1403
  * Get the Nostr-format public key (32 bytes / 64 hex chars)
1393
1404
  * This is the x-coordinate only, without the 02/03 prefix.
@@ -1922,6 +1933,17 @@ var NostrTransportProvider = class _NostrTransportProvider {
1922
1933
  logger.debug("Nostr", "Failed to save last event timestamp:", err);
1923
1934
  });
1924
1935
  }
1936
+ /** Persist the max DM (gift-wrap) event timestamp for the since filter on next connect. */
1937
+ updateLastDmEventTimestamp(createdAt) {
1938
+ if (!this.storage || !this.keyManager) return;
1939
+ if (createdAt <= this.lastDmEventTs) return;
1940
+ this.lastDmEventTs = createdAt;
1941
+ const pubkey = this.keyManager.getPublicKeyHex();
1942
+ const storageKey = `${STORAGE_KEYS_GLOBAL.LAST_DM_EVENT_TS}_${pubkey.slice(0, 16)}`;
1943
+ this.storage.set(storageKey, createdAt.toString()).catch((err) => {
1944
+ logger.debug("Nostr", "Failed to save last DM event timestamp:", err);
1945
+ });
1946
+ }
1925
1947
  async handleDirectMessage(event) {
1926
1948
  logger.debug("Nostr", "Ignoring NIP-04 kind 4 event (DMs use NIP-17):", event.id?.slice(0, 12));
1927
1949
  }
@@ -1932,6 +1954,9 @@ var NostrTransportProvider = class _NostrTransportProvider {
1932
1954
  }
1933
1955
  try {
1934
1956
  const pm = NIP17.unwrap(event, this.keyManager);
1957
+ if (event.created_at) {
1958
+ this.updateLastDmEventTimestamp(event.created_at);
1959
+ }
1935
1960
  logger.debug("Nostr", "Gift wrap unwrapped, sender:", pm.senderPubkey?.slice(0, 16), "kind:", pm.kind);
1936
1961
  if (pm.senderPubkey === this.keyManager.getPublicKeyHex()) {
1937
1962
  try {
@@ -2378,9 +2403,50 @@ var NostrTransportProvider = class _NostrTransportProvider {
2378
2403
  }
2379
2404
  });
2380
2405
  logger.debug("Nostr", "Wallet subscription created, subId:", this.walletSubscriptionId);
2406
+ let dmSince;
2407
+ if (this.storage) {
2408
+ const dmStorageKey = `${STORAGE_KEYS_GLOBAL.LAST_DM_EVENT_TS}_${nostrPubkey.slice(0, 16)}`;
2409
+ try {
2410
+ const stored = await this.storage.get(dmStorageKey);
2411
+ const parsed = stored ? parseInt(stored, 10) : NaN;
2412
+ if (Number.isFinite(parsed)) {
2413
+ dmSince = parsed;
2414
+ this.lastDmEventTs = dmSince;
2415
+ this.fallbackDmSince = null;
2416
+ logger.debug("Nostr", "DM resuming from stored timestamp:", dmSince);
2417
+ } else if (this.fallbackDmSince !== null) {
2418
+ dmSince = this.fallbackDmSince;
2419
+ this.lastDmEventTs = dmSince;
2420
+ this.fallbackDmSince = null;
2421
+ logger.debug("Nostr", "DM using fallback since timestamp:", dmSince);
2422
+ } else {
2423
+ dmSince = Math.floor(Date.now() / 1e3);
2424
+ logger.debug("Nostr", "No stored DM timestamp, starting from now:", dmSince);
2425
+ }
2426
+ } catch (err) {
2427
+ if (this.fallbackDmSince !== null) {
2428
+ dmSince = this.fallbackDmSince;
2429
+ this.lastDmEventTs = dmSince;
2430
+ this.fallbackDmSince = null;
2431
+ logger.debug("Nostr", "Storage read failed, using DM fallback since:", dmSince, err);
2432
+ } else {
2433
+ dmSince = Math.floor(Date.now() / 1e3);
2434
+ logger.debug("Nostr", "Failed to read last DM event timestamp, falling back to now:", err);
2435
+ }
2436
+ }
2437
+ } else if (this.fallbackDmSince !== null) {
2438
+ dmSince = this.fallbackDmSince;
2439
+ this.lastDmEventTs = dmSince;
2440
+ this.fallbackDmSince = null;
2441
+ logger.debug("Nostr", "No storage adapter for DM, using fallback since:", dmSince);
2442
+ } else {
2443
+ dmSince = Math.floor(Date.now() / 1e3);
2444
+ logger.debug("Nostr", "No storage adapter for DM, starting from now:", dmSince);
2445
+ }
2381
2446
  const chatFilter = new Filter();
2382
2447
  chatFilter.kinds = [EventKinds.GIFT_WRAP];
2383
2448
  chatFilter["#p"] = [nostrPubkey];
2449
+ chatFilter.since = dmSince;
2384
2450
  this.chatSubscriptionId = this.nostrClient.subscribe(chatFilter, {
2385
2451
  onEvent: (event) => {
2386
2452
  logger.debug("Nostr", "Received chat event kind:", event.kind, "id:", event.id?.slice(0, 12));