@unicitylabs/sphere-sdk 0.3.8 → 0.4.0

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 (49) hide show
  1. package/dist/connect/index.cjs +770 -0
  2. package/dist/connect/index.cjs.map +1 -0
  3. package/dist/connect/index.d.cts +312 -0
  4. package/dist/connect/index.d.ts +312 -0
  5. package/dist/connect/index.js +747 -0
  6. package/dist/connect/index.js.map +1 -0
  7. package/dist/core/index.cjs +2744 -56
  8. package/dist/core/index.cjs.map +1 -1
  9. package/dist/core/index.d.cts +277 -3
  10. package/dist/core/index.d.ts +277 -3
  11. package/dist/core/index.js +2740 -52
  12. package/dist/core/index.js.map +1 -1
  13. package/dist/impl/browser/connect/index.cjs +271 -0
  14. package/dist/impl/browser/connect/index.cjs.map +1 -0
  15. package/dist/impl/browser/connect/index.d.cts +137 -0
  16. package/dist/impl/browser/connect/index.d.ts +137 -0
  17. package/dist/impl/browser/connect/index.js +248 -0
  18. package/dist/impl/browser/connect/index.js.map +1 -0
  19. package/dist/impl/browser/index.cjs +583 -45
  20. package/dist/impl/browser/index.cjs.map +1 -1
  21. package/dist/impl/browser/index.js +587 -46
  22. package/dist/impl/browser/index.js.map +1 -1
  23. package/dist/impl/browser/ipfs.cjs.map +1 -1
  24. package/dist/impl/browser/ipfs.js.map +1 -1
  25. package/dist/impl/nodejs/connect/index.cjs +372 -0
  26. package/dist/impl/nodejs/connect/index.cjs.map +1 -0
  27. package/dist/impl/nodejs/connect/index.d.cts +178 -0
  28. package/dist/impl/nodejs/connect/index.d.ts +178 -0
  29. package/dist/impl/nodejs/connect/index.js +333 -0
  30. package/dist/impl/nodejs/connect/index.js.map +1 -0
  31. package/dist/impl/nodejs/index.cjs +266 -12
  32. package/dist/impl/nodejs/index.cjs.map +1 -1
  33. package/dist/impl/nodejs/index.d.cts +96 -0
  34. package/dist/impl/nodejs/index.d.ts +96 -0
  35. package/dist/impl/nodejs/index.js +270 -13
  36. package/dist/impl/nodejs/index.js.map +1 -1
  37. package/dist/index.cjs +2761 -56
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/index.d.cts +375 -5
  40. package/dist/index.d.ts +375 -5
  41. package/dist/index.js +2750 -52
  42. package/dist/index.js.map +1 -1
  43. package/dist/l1/index.cjs +5 -1
  44. package/dist/l1/index.cjs.map +1 -1
  45. package/dist/l1/index.d.cts +2 -1
  46. package/dist/l1/index.d.ts +2 -1
  47. package/dist/l1/index.js +5 -1
  48. package/dist/l1/index.js.map +1 -1
  49. package/package.json +31 -1
@@ -655,6 +655,11 @@ interface BroadcastMessage {
655
655
  readonly timestamp: number;
656
656
  readonly tags?: string[];
657
657
  }
658
+ interface ComposingIndicator {
659
+ readonly senderPubkey: string;
660
+ readonly senderNametag?: string;
661
+ readonly expiresIn: number;
662
+ }
658
663
  /**
659
664
  * Minimal data stored in persistent storage for a tracked address.
660
665
  * Only contains user state — derived fields are computed on load.
@@ -685,7 +690,7 @@ interface TrackedAddress extends TrackedAddressEntry {
685
690
  /** Primary nametag (from nametag cache, without @ prefix) */
686
691
  readonly nametag?: string;
687
692
  }
688
- type SphereEventType = 'transfer:incoming' | 'transfer:confirmed' | 'transfer:failed' | 'payment_request:incoming' | 'payment_request:accepted' | 'payment_request:rejected' | 'payment_request:paid' | 'payment_request:response' | 'message:dm' | 'message:broadcast' | 'sync:started' | 'sync:completed' | 'sync:provider' | 'sync:error' | 'connection:changed' | 'nametag:registered' | 'nametag:recovered' | 'identity:changed' | 'address:activated' | 'address:hidden' | 'address:unhidden' | 'sync:remote-update' | 'groupchat:message' | 'groupchat:joined' | 'groupchat:left' | 'groupchat:kicked' | 'groupchat:group_deleted' | 'groupchat:updated' | 'groupchat:connection';
693
+ type SphereEventType = 'transfer:incoming' | 'transfer:confirmed' | 'transfer:failed' | 'payment_request:incoming' | 'payment_request:accepted' | 'payment_request:rejected' | 'payment_request:paid' | 'payment_request:response' | 'message:dm' | 'message:read' | 'message:typing' | 'composing:started' | 'message:broadcast' | 'sync:started' | 'sync:completed' | 'sync:provider' | 'sync:error' | 'connection:changed' | 'nametag:registered' | 'nametag:recovered' | 'identity:changed' | 'address:activated' | 'address:hidden' | 'address:unhidden' | 'sync:remote-update' | 'groupchat:message' | 'groupchat:joined' | 'groupchat:left' | 'groupchat:kicked' | 'groupchat:group_deleted' | 'groupchat:updated' | 'groupchat:connection';
689
694
  interface SphereEventMap {
690
695
  'transfer:incoming': IncomingTransfer;
691
696
  'transfer:confirmed': TransferResult;
@@ -696,6 +701,16 @@ interface SphereEventMap {
696
701
  'payment_request:paid': IncomingPaymentRequest$1;
697
702
  'payment_request:response': PaymentRequestResponse;
698
703
  'message:dm': DirectMessage;
704
+ 'message:read': {
705
+ messageIds: string[];
706
+ peerPubkey: string;
707
+ };
708
+ 'message:typing': {
709
+ senderPubkey: string;
710
+ senderNametag?: string;
711
+ timestamp: number;
712
+ };
713
+ 'composing:started': ComposingIndicator;
699
714
  'message:broadcast': BroadcastMessage;
700
715
  'sync:started': {
701
716
  source: string;
@@ -1023,6 +1038,38 @@ interface TransportProvider extends BaseProvider {
1023
1038
  * @returns Unsubscribe function
1024
1039
  */
1025
1040
  onPaymentRequestResponse?(handler: PaymentRequestResponseHandler): () => void;
1041
+ /**
1042
+ * Send a read receipt for a message
1043
+ * @param recipientTransportPubkey - Transport pubkey of the message sender
1044
+ * @param messageEventId - Event ID of the message being acknowledged
1045
+ */
1046
+ sendReadReceipt?(recipientTransportPubkey: string, messageEventId: string): Promise<void>;
1047
+ /**
1048
+ * Subscribe to incoming read receipts
1049
+ * @returns Unsubscribe function
1050
+ */
1051
+ onReadReceipt?(handler: ReadReceiptHandler): () => void;
1052
+ /**
1053
+ * Send typing indicator to a recipient
1054
+ * @param recipientTransportPubkey - Transport pubkey of the conversation partner
1055
+ */
1056
+ sendTypingIndicator?(recipientTransportPubkey: string): Promise<void>;
1057
+ /**
1058
+ * Subscribe to incoming typing indicators
1059
+ * @returns Unsubscribe function
1060
+ */
1061
+ onTypingIndicator?(handler: TypingIndicatorHandler): () => void;
1062
+ /**
1063
+ * Send composing indicator to a recipient using NIP-44 encrypted gift wrap
1064
+ * @param recipientTransportPubkey - Transport pubkey of the conversation partner
1065
+ * @param content - JSON payload with senderNametag and expiresIn
1066
+ */
1067
+ sendComposingIndicator?(recipientTransportPubkey: string, content: string): Promise<void>;
1068
+ /**
1069
+ * Subscribe to incoming composing indicators
1070
+ * @returns Unsubscribe function
1071
+ */
1072
+ onComposing?(handler: ComposingHandler): () => void;
1026
1073
  /**
1027
1074
  * Get list of configured relay URLs
1028
1075
  */
@@ -1112,6 +1159,10 @@ interface IncomingMessage {
1112
1159
  content: string;
1113
1160
  timestamp: number;
1114
1161
  encrypted: boolean;
1162
+ /** Set when this is a self-wrap replay (sent message recovered from relay) */
1163
+ isSelfWrap?: boolean;
1164
+ /** Recipient pubkey — only present on self-wrap replays */
1165
+ recipientTransportPubkey?: string;
1115
1166
  }
1116
1167
  type MessageHandler = (message: IncomingMessage) => void;
1117
1168
  interface TokenTransferPayload {
@@ -1225,6 +1276,25 @@ interface PeerInfo {
1225
1276
  /** Event timestamp */
1226
1277
  timestamp: number;
1227
1278
  }
1279
+ interface IncomingReadReceipt {
1280
+ /** Transport-specific pubkey of the sender who read the message */
1281
+ senderTransportPubkey: string;
1282
+ /** Event ID of the message that was read */
1283
+ messageEventId: string;
1284
+ /** Timestamp */
1285
+ timestamp: number;
1286
+ }
1287
+ type ReadReceiptHandler = (receipt: IncomingReadReceipt) => void;
1288
+ interface IncomingTypingIndicator {
1289
+ /** Transport-specific pubkey of the sender who is typing */
1290
+ senderTransportPubkey: string;
1291
+ /** Sender's nametag (if known) */
1292
+ senderNametag?: string;
1293
+ /** Timestamp */
1294
+ timestamp: number;
1295
+ }
1296
+ type TypingIndicatorHandler = (indicator: IncomingTypingIndicator) => void;
1297
+ type ComposingHandler = (indicator: ComposingIndicator) => void;
1228
1298
 
1229
1299
  /**
1230
1300
  * L1 Payments Sub-Module
@@ -2440,6 +2510,11 @@ declare class PaymentsModule {
2440
2510
  * Create SigningService from identity private key
2441
2511
  */
2442
2512
  private createSigningService;
2513
+ /**
2514
+ * Get the wallet's signing public key (used for token ownership predicates).
2515
+ * This is the key that token state predicates are checked against.
2516
+ */
2517
+ getSigningPublicKey(): Promise<Uint8Array>;
2443
2518
  /**
2444
2519
  * Create DirectAddress from a public key using UnmaskedPredicateReference
2445
2520
  */
@@ -2504,11 +2579,24 @@ declare class PaymentsModule {
2504
2579
  interface CommunicationsModuleConfig {
2505
2580
  /** Auto-save messages */
2506
2581
  autoSave?: boolean;
2507
- /** Max messages in memory */
2582
+ /** Max messages in memory (global cap) */
2508
2583
  maxMessages?: number;
2584
+ /** Max messages per conversation (default: 200) */
2585
+ maxPerConversation?: number;
2509
2586
  /** Enable read receipts */
2510
2587
  readReceipts?: boolean;
2511
2588
  }
2589
+ interface ConversationPage {
2590
+ messages: DirectMessage[];
2591
+ hasMore: boolean;
2592
+ oldestTimestamp: number | null;
2593
+ }
2594
+ interface GetConversationPageOptions {
2595
+ /** Max messages to return (default: 20) */
2596
+ limit?: number;
2597
+ /** Return messages older than this timestamp */
2598
+ before?: number;
2599
+ }
2512
2600
  interface CommunicationsModuleDependencies {
2513
2601
  identity: FullIdentity;
2514
2602
  storage: StorageProvider;
@@ -2521,8 +2609,10 @@ declare class CommunicationsModule {
2521
2609
  private messages;
2522
2610
  private broadcasts;
2523
2611
  private unsubscribeMessages;
2612
+ private unsubscribeComposing;
2524
2613
  private broadcastSubscriptions;
2525
2614
  private dmHandlers;
2615
+ private composingHandlers;
2526
2616
  private broadcastHandlers;
2527
2617
  constructor(config?: CommunicationsModuleConfig);
2528
2618
  /**
@@ -2530,7 +2620,10 @@ declare class CommunicationsModule {
2530
2620
  */
2531
2621
  initialize(deps: CommunicationsModuleDependencies): void;
2532
2622
  /**
2533
- * Load messages from storage
2623
+ * Load messages from storage.
2624
+ * Uses per-address key (STORAGE_KEYS_ADDRESS.MESSAGES) which is automatically
2625
+ * scoped by LocalStorageProvider to sphere_DIRECT_xxx_yyy_messages.
2626
+ * Falls back to legacy global 'direct_messages' key for migration.
2534
2627
  */
2535
2628
  load(): Promise<void>;
2536
2629
  /**
@@ -2557,6 +2650,28 @@ declare class CommunicationsModule {
2557
2650
  * Get unread count
2558
2651
  */
2559
2652
  getUnreadCount(peerPubkey?: string): number;
2653
+ /**
2654
+ * Get a page of messages from a conversation (for lazy loading).
2655
+ * Returns messages in chronological order with a cursor for loading older messages.
2656
+ */
2657
+ getConversationPage(peerPubkey: string, options?: GetConversationPageOptions): ConversationPage;
2658
+ /**
2659
+ * Delete all messages in a conversation with a peer
2660
+ */
2661
+ deleteConversation(peerPubkey: string): Promise<void>;
2662
+ /**
2663
+ * Send typing indicator to a peer
2664
+ */
2665
+ sendTypingIndicator(peerPubkey: string): Promise<void>;
2666
+ /**
2667
+ * Send a composing indicator to a peer.
2668
+ * Fire-and-forget — does not save to message history.
2669
+ */
2670
+ sendComposingIndicator(recipientPubkeyOrNametag: string): Promise<void>;
2671
+ /**
2672
+ * Subscribe to incoming composing indicators
2673
+ */
2674
+ onComposingIndicator(handler: (indicator: ComposingIndicator) => void): () => void;
2560
2675
  /**
2561
2676
  * Subscribe to incoming DMs
2562
2677
  */
@@ -2578,6 +2693,7 @@ declare class CommunicationsModule {
2578
2693
  */
2579
2694
  onBroadcast(handler: (message: BroadcastMessage) => void): () => void;
2580
2695
  private handleIncomingMessage;
2696
+ private handleComposingIndicator;
2581
2697
  private handleIncomingBroadcast;
2582
2698
  private save;
2583
2699
  private pruneIfNeeded;
@@ -2705,6 +2821,146 @@ declare class GroupChatModule {
2705
2821
  private randomId;
2706
2822
  }
2707
2823
 
2824
+ /**
2825
+ * Market Module Types
2826
+ * Intent bulletin board for posting and discovering intents,
2827
+ * plus real-time feed subscription.
2828
+ */
2829
+ type IntentType = 'buy' | 'sell' | 'service' | 'announcement' | 'other' | (string & {});
2830
+ type IntentStatus = 'active' | 'closed' | 'expired';
2831
+ interface MarketModuleConfig {
2832
+ /** Market API base URL (default: https://market-api.unicity.network) */
2833
+ apiUrl?: string;
2834
+ /** Request timeout in ms (default: 30000) */
2835
+ timeout?: number;
2836
+ }
2837
+ interface MarketModuleDependencies {
2838
+ identity: FullIdentity;
2839
+ emitEvent: <T extends SphereEventType>(type: T, data: SphereEventMap[T]) => void;
2840
+ }
2841
+ interface PostIntentRequest {
2842
+ description: string;
2843
+ intentType: IntentType;
2844
+ category?: string;
2845
+ price?: number;
2846
+ currency?: string;
2847
+ location?: string;
2848
+ contactHandle?: string;
2849
+ expiresInDays?: number;
2850
+ }
2851
+ interface PostIntentResult {
2852
+ intentId: string;
2853
+ message: string;
2854
+ expiresAt: string;
2855
+ }
2856
+ interface MarketIntent {
2857
+ id: string;
2858
+ intentType: IntentType;
2859
+ category?: string;
2860
+ price?: string;
2861
+ currency: string;
2862
+ location?: string;
2863
+ status: IntentStatus;
2864
+ createdAt: string;
2865
+ expiresAt: string;
2866
+ }
2867
+ interface SearchIntentResult {
2868
+ id: string;
2869
+ score: number;
2870
+ agentNametag?: string;
2871
+ agentPublicKey: string;
2872
+ description: string;
2873
+ intentType: IntentType;
2874
+ category?: string;
2875
+ price?: number;
2876
+ currency: string;
2877
+ location?: string;
2878
+ contactMethod: string;
2879
+ contactHandle?: string;
2880
+ createdAt: string;
2881
+ expiresAt: string;
2882
+ }
2883
+ interface SearchFilters {
2884
+ intentType?: IntentType;
2885
+ category?: string;
2886
+ minPrice?: number;
2887
+ maxPrice?: number;
2888
+ location?: string;
2889
+ /** Minimum similarity score (0–1). Results below this threshold are excluded (client-side). */
2890
+ minScore?: number;
2891
+ }
2892
+ interface SearchOptions {
2893
+ filters?: SearchFilters;
2894
+ limit?: number;
2895
+ }
2896
+ interface SearchResult {
2897
+ intents: SearchIntentResult[];
2898
+ count: number;
2899
+ }
2900
+ /** A listing broadcast on the live feed */
2901
+ interface FeedListing {
2902
+ id: string;
2903
+ title: string;
2904
+ descriptionPreview: string;
2905
+ agentName: string;
2906
+ agentId: number;
2907
+ type: IntentType;
2908
+ createdAt: string;
2909
+ }
2910
+ /** WebSocket message: initial batch of recent listings */
2911
+ interface FeedInitialMessage {
2912
+ type: 'initial';
2913
+ listings: FeedListing[];
2914
+ }
2915
+ /** WebSocket message: single new listing */
2916
+ interface FeedNewMessage {
2917
+ type: 'new';
2918
+ listing: FeedListing;
2919
+ }
2920
+ type FeedMessage = FeedInitialMessage | FeedNewMessage;
2921
+ /** Callback for live feed events */
2922
+ type FeedListener = (message: FeedMessage) => void;
2923
+
2924
+ declare class MarketModule {
2925
+ private readonly apiUrl;
2926
+ private readonly timeout;
2927
+ private identity;
2928
+ private registered;
2929
+ constructor(config?: MarketModuleConfig);
2930
+ /** Called by Sphere after construction */
2931
+ initialize(deps: MarketModuleDependencies): void;
2932
+ /** No-op — stateless module */
2933
+ load(): Promise<void>;
2934
+ /** No-op — stateless module */
2935
+ destroy(): void;
2936
+ /** Post a new intent (agent is auto-registered on first post) */
2937
+ postIntent(intent: PostIntentRequest): Promise<PostIntentResult>;
2938
+ /** Semantic search for intents (public — no auth required) */
2939
+ search(query: string, opts?: SearchOptions): Promise<SearchResult>;
2940
+ /** List own intents (authenticated) */
2941
+ getMyIntents(): Promise<MarketIntent[]>;
2942
+ /** Close (delete) an intent */
2943
+ closeIntent(intentId: string): Promise<void>;
2944
+ /** Fetch the most recent listings via REST (public — no auth required) */
2945
+ getRecentListings(): Promise<FeedListing[]>;
2946
+ /**
2947
+ * Subscribe to the live listing feed via WebSocket.
2948
+ * Returns an unsubscribe function that closes the connection.
2949
+ *
2950
+ * Requires a WebSocket implementation — works natively in browsers
2951
+ * and in Node.js 21+ (or with the `ws` package).
2952
+ */
2953
+ subscribeFeed(listener: FeedListener): () => void;
2954
+ private ensureIdentity;
2955
+ /** Register the agent's public key with the server (idempotent) */
2956
+ private ensureRegistered;
2957
+ private parseResponse;
2958
+ private apiPost;
2959
+ private apiGet;
2960
+ private apiDelete;
2961
+ private apiPublicPost;
2962
+ }
2963
+
2708
2964
  /** Network configurations */
2709
2965
  declare const NETWORKS: {
2710
2966
  readonly mainnet: {
@@ -2848,6 +3104,8 @@ interface SphereCreateOptions {
2848
3104
  network?: NetworkType;
2849
3105
  /** Group chat configuration (NIP-29). Omit to disable groupchat. */
2850
3106
  groupChat?: GroupChatModuleConfig | boolean;
3107
+ /** Market module configuration. true = enable with defaults, object = custom config. */
3108
+ market?: MarketModuleConfig | boolean;
2851
3109
  /** Optional password to encrypt the wallet. If omitted, mnemonic is stored as plaintext. */
2852
3110
  password?: string;
2853
3111
  }
@@ -2873,6 +3131,8 @@ interface SphereLoadOptions {
2873
3131
  network?: NetworkType;
2874
3132
  /** Group chat configuration (NIP-29). Omit to disable groupchat. */
2875
3133
  groupChat?: GroupChatModuleConfig | boolean;
3134
+ /** Market module configuration. true = enable with defaults, object = custom config. */
3135
+ market?: MarketModuleConfig | boolean;
2876
3136
  /** Optional password to decrypt the wallet. Must match the password used during creation. */
2877
3137
  password?: string;
2878
3138
  }
@@ -2906,6 +3166,8 @@ interface SphereImportOptions {
2906
3166
  price?: PriceProvider;
2907
3167
  /** Group chat configuration (NIP-29). Omit to disable groupchat. */
2908
3168
  groupChat?: GroupChatModuleConfig | boolean;
3169
+ /** Market module configuration. true = enable with defaults, object = custom config. */
3170
+ market?: MarketModuleConfig | boolean;
2909
3171
  /** Optional password to encrypt the wallet. If omitted, mnemonic/key is stored as plaintext. */
2910
3172
  password?: string;
2911
3173
  }
@@ -2953,6 +3215,8 @@ interface SphereInitOptions {
2953
3215
  * - Omit/undefined: No groupchat module
2954
3216
  */
2955
3217
  groupChat?: GroupChatModuleConfig | boolean;
3218
+ /** Market module configuration. true = enable with defaults, object = custom config. */
3219
+ market?: MarketModuleConfig | boolean;
2956
3220
  /** Optional password to encrypt/decrypt the wallet. If omitted, mnemonic is stored as plaintext. */
2957
3221
  password?: string;
2958
3222
  }
@@ -2992,6 +3256,7 @@ declare class Sphere {
2992
3256
  private _payments;
2993
3257
  private _communications;
2994
3258
  private _groupChat;
3259
+ private _market;
2995
3260
  private eventHandlers;
2996
3261
  private _disabledProviders;
2997
3262
  private _providerEventCleanups;
@@ -3039,6 +3304,13 @@ declare class Sphere {
3039
3304
  * (different input shape: { enabled?, relays? }). Both fill relay URLs from network defaults.
3040
3305
  */
3041
3306
  private static resolveGroupChatConfig;
3307
+ /**
3308
+ * Resolve market module config from Sphere.init() options.
3309
+ * - `true` → enable with default API URL
3310
+ * - `MarketModuleConfig` → pass through
3311
+ * - `undefined` → no market module
3312
+ */
3313
+ private static resolveMarketConfig;
3042
3314
  /**
3043
3315
  * Configure TokenRegistry in the main bundle context.
3044
3316
  *
@@ -3107,6 +3379,8 @@ declare class Sphere {
3107
3379
  get communications(): CommunicationsModule;
3108
3380
  /** Group chat module (NIP-29). Null if not configured. */
3109
3381
  get groupChat(): GroupChatModule | null;
3382
+ /** Market module (intent bulletin board). Null if not configured. */
3383
+ get market(): MarketModule | null;
3110
3384
  /** Current identity (public info only) */
3111
3385
  get identity(): Identity | null;
3112
3386
  /** Is ready */