@unicitylabs/sphere-sdk 0.3.6 → 0.3.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.
package/dist/index.d.cts CHANGED
@@ -1162,7 +1162,7 @@ interface TrackedAddress extends TrackedAddressEntry {
1162
1162
  /** Primary nametag (from nametag cache, without @ prefix) */
1163
1163
  readonly nametag?: string;
1164
1164
  }
1165
- 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';
1165
+ 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' | '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';
1166
1166
  interface SphereEventMap {
1167
1167
  'transfer:incoming': IncomingTransfer;
1168
1168
  'transfer:confirmed': TransferResult;
@@ -1173,6 +1173,15 @@ interface SphereEventMap {
1173
1173
  'payment_request:paid': IncomingPaymentRequest$1;
1174
1174
  'payment_request:response': PaymentRequestResponse;
1175
1175
  'message:dm': DirectMessage;
1176
+ 'message:read': {
1177
+ messageIds: string[];
1178
+ peerPubkey: string;
1179
+ };
1180
+ 'message:typing': {
1181
+ senderPubkey: string;
1182
+ senderNametag?: string;
1183
+ timestamp: number;
1184
+ };
1176
1185
  'message:broadcast': BroadcastMessage;
1177
1186
  'sync:started': {
1178
1187
  source: string;
@@ -1542,6 +1551,27 @@ interface TransportProvider extends BaseProvider {
1542
1551
  * @returns Unsubscribe function
1543
1552
  */
1544
1553
  onPaymentRequestResponse?(handler: PaymentRequestResponseHandler): () => void;
1554
+ /**
1555
+ * Send a read receipt for a message
1556
+ * @param recipientTransportPubkey - Transport pubkey of the message sender
1557
+ * @param messageEventId - Event ID of the message being acknowledged
1558
+ */
1559
+ sendReadReceipt?(recipientTransportPubkey: string, messageEventId: string): Promise<void>;
1560
+ /**
1561
+ * Subscribe to incoming read receipts
1562
+ * @returns Unsubscribe function
1563
+ */
1564
+ onReadReceipt?(handler: ReadReceiptHandler): () => void;
1565
+ /**
1566
+ * Send typing indicator to a recipient
1567
+ * @param recipientTransportPubkey - Transport pubkey of the conversation partner
1568
+ */
1569
+ sendTypingIndicator?(recipientTransportPubkey: string): Promise<void>;
1570
+ /**
1571
+ * Subscribe to incoming typing indicators
1572
+ * @returns Unsubscribe function
1573
+ */
1574
+ onTypingIndicator?(handler: TypingIndicatorHandler): () => void;
1545
1575
  /**
1546
1576
  * Get list of configured relay URLs
1547
1577
  */
@@ -1631,6 +1661,10 @@ interface IncomingMessage {
1631
1661
  content: string;
1632
1662
  timestamp: number;
1633
1663
  encrypted: boolean;
1664
+ /** Set when this is a self-wrap replay (sent message recovered from relay) */
1665
+ isSelfWrap?: boolean;
1666
+ /** Recipient pubkey — only present on self-wrap replays */
1667
+ recipientTransportPubkey?: string;
1634
1668
  }
1635
1669
  type MessageHandler = (message: IncomingMessage) => void;
1636
1670
  interface TokenTransferPayload {
@@ -1752,6 +1786,24 @@ interface PeerInfo {
1752
1786
  /** Event timestamp */
1753
1787
  timestamp: number;
1754
1788
  }
1789
+ interface IncomingReadReceipt {
1790
+ /** Transport-specific pubkey of the sender who read the message */
1791
+ senderTransportPubkey: string;
1792
+ /** Event ID of the message that was read */
1793
+ messageEventId: string;
1794
+ /** Timestamp */
1795
+ timestamp: number;
1796
+ }
1797
+ type ReadReceiptHandler = (receipt: IncomingReadReceipt) => void;
1798
+ interface IncomingTypingIndicator {
1799
+ /** Transport-specific pubkey of the sender who is typing */
1800
+ senderTransportPubkey: string;
1801
+ /** Sender's nametag (if known) */
1802
+ senderNametag?: string;
1803
+ /** Timestamp */
1804
+ timestamp: number;
1805
+ }
1806
+ type TypingIndicatorHandler = (indicator: IncomingTypingIndicator) => void;
1755
1807
 
1756
1808
  /**
1757
1809
  * L1 Payments Sub-Module
@@ -3170,6 +3222,10 @@ declare class CommunicationsModule {
3170
3222
  * Get unread count
3171
3223
  */
3172
3224
  getUnreadCount(peerPubkey?: string): number;
3225
+ /**
3226
+ * Send typing indicator to a peer
3227
+ */
3228
+ sendTypingIndicator(peerPubkey: string): Promise<void>;
3173
3229
  /**
3174
3230
  * Subscribe to incoming DMs
3175
3231
  */
package/dist/index.d.ts CHANGED
@@ -1162,7 +1162,7 @@ interface TrackedAddress extends TrackedAddressEntry {
1162
1162
  /** Primary nametag (from nametag cache, without @ prefix) */
1163
1163
  readonly nametag?: string;
1164
1164
  }
1165
- 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';
1165
+ 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' | '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';
1166
1166
  interface SphereEventMap {
1167
1167
  'transfer:incoming': IncomingTransfer;
1168
1168
  'transfer:confirmed': TransferResult;
@@ -1173,6 +1173,15 @@ interface SphereEventMap {
1173
1173
  'payment_request:paid': IncomingPaymentRequest$1;
1174
1174
  'payment_request:response': PaymentRequestResponse;
1175
1175
  'message:dm': DirectMessage;
1176
+ 'message:read': {
1177
+ messageIds: string[];
1178
+ peerPubkey: string;
1179
+ };
1180
+ 'message:typing': {
1181
+ senderPubkey: string;
1182
+ senderNametag?: string;
1183
+ timestamp: number;
1184
+ };
1176
1185
  'message:broadcast': BroadcastMessage;
1177
1186
  'sync:started': {
1178
1187
  source: string;
@@ -1542,6 +1551,27 @@ interface TransportProvider extends BaseProvider {
1542
1551
  * @returns Unsubscribe function
1543
1552
  */
1544
1553
  onPaymentRequestResponse?(handler: PaymentRequestResponseHandler): () => void;
1554
+ /**
1555
+ * Send a read receipt for a message
1556
+ * @param recipientTransportPubkey - Transport pubkey of the message sender
1557
+ * @param messageEventId - Event ID of the message being acknowledged
1558
+ */
1559
+ sendReadReceipt?(recipientTransportPubkey: string, messageEventId: string): Promise<void>;
1560
+ /**
1561
+ * Subscribe to incoming read receipts
1562
+ * @returns Unsubscribe function
1563
+ */
1564
+ onReadReceipt?(handler: ReadReceiptHandler): () => void;
1565
+ /**
1566
+ * Send typing indicator to a recipient
1567
+ * @param recipientTransportPubkey - Transport pubkey of the conversation partner
1568
+ */
1569
+ sendTypingIndicator?(recipientTransportPubkey: string): Promise<void>;
1570
+ /**
1571
+ * Subscribe to incoming typing indicators
1572
+ * @returns Unsubscribe function
1573
+ */
1574
+ onTypingIndicator?(handler: TypingIndicatorHandler): () => void;
1545
1575
  /**
1546
1576
  * Get list of configured relay URLs
1547
1577
  */
@@ -1631,6 +1661,10 @@ interface IncomingMessage {
1631
1661
  content: string;
1632
1662
  timestamp: number;
1633
1663
  encrypted: boolean;
1664
+ /** Set when this is a self-wrap replay (sent message recovered from relay) */
1665
+ isSelfWrap?: boolean;
1666
+ /** Recipient pubkey — only present on self-wrap replays */
1667
+ recipientTransportPubkey?: string;
1634
1668
  }
1635
1669
  type MessageHandler = (message: IncomingMessage) => void;
1636
1670
  interface TokenTransferPayload {
@@ -1752,6 +1786,24 @@ interface PeerInfo {
1752
1786
  /** Event timestamp */
1753
1787
  timestamp: number;
1754
1788
  }
1789
+ interface IncomingReadReceipt {
1790
+ /** Transport-specific pubkey of the sender who read the message */
1791
+ senderTransportPubkey: string;
1792
+ /** Event ID of the message that was read */
1793
+ messageEventId: string;
1794
+ /** Timestamp */
1795
+ timestamp: number;
1796
+ }
1797
+ type ReadReceiptHandler = (receipt: IncomingReadReceipt) => void;
1798
+ interface IncomingTypingIndicator {
1799
+ /** Transport-specific pubkey of the sender who is typing */
1800
+ senderTransportPubkey: string;
1801
+ /** Sender's nametag (if known) */
1802
+ senderNametag?: string;
1803
+ /** Timestamp */
1804
+ timestamp: number;
1805
+ }
1806
+ type TypingIndicatorHandler = (indicator: IncomingTypingIndicator) => void;
1755
1807
 
1756
1808
  /**
1757
1809
  * L1 Payments Sub-Module
@@ -3170,6 +3222,10 @@ declare class CommunicationsModule {
3170
3222
  * Get unread count
3171
3223
  */
3172
3224
  getUnreadCount(peerPubkey?: string): number;
3225
+ /**
3226
+ * Send typing indicator to a peer
3227
+ */
3228
+ sendTypingIndicator(peerPubkey: string): Promise<void>;
3173
3229
  /**
3174
3230
  * Subscribe to incoming DMs
3175
3231
  */
package/dist/index.js CHANGED
@@ -7550,6 +7550,28 @@ var CommunicationsModule = class {
7550
7550
  this.unsubscribeMessages = deps.transport.onMessage((msg) => {
7551
7551
  this.handleIncomingMessage(msg);
7552
7552
  });
7553
+ if (deps.transport.onReadReceipt) {
7554
+ deps.transport.onReadReceipt((receipt) => {
7555
+ const msg = this.messages.get(receipt.messageEventId);
7556
+ if (msg && msg.senderPubkey === this.deps.identity.chainPubkey) {
7557
+ msg.isRead = true;
7558
+ this.save();
7559
+ this.deps.emitEvent("message:read", {
7560
+ messageIds: [receipt.messageEventId],
7561
+ peerPubkey: receipt.senderTransportPubkey
7562
+ });
7563
+ }
7564
+ });
7565
+ }
7566
+ if (deps.transport.onTypingIndicator) {
7567
+ deps.transport.onTypingIndicator((indicator) => {
7568
+ this.deps.emitEvent("message:typing", {
7569
+ senderPubkey: indicator.senderTransportPubkey,
7570
+ senderNametag: indicator.senderNametag,
7571
+ timestamp: indicator.timestamp
7572
+ });
7573
+ });
7574
+ }
7553
7575
  }
7554
7576
  /**
7555
7577
  * Load messages from storage
@@ -7593,7 +7615,7 @@ var CommunicationsModule = class {
7593
7615
  recipientPubkey,
7594
7616
  content,
7595
7617
  timestamp: Date.now(),
7596
- isRead: true
7618
+ isRead: false
7597
7619
  };
7598
7620
  this.messages.set(message.id, message);
7599
7621
  if (this.config.autoSave) {
@@ -7639,6 +7661,16 @@ var CommunicationsModule = class {
7639
7661
  if (this.config.autoSave) {
7640
7662
  await this.save();
7641
7663
  }
7664
+ if (this.config.readReceipts && this.deps?.transport.sendReadReceipt) {
7665
+ for (const id of messageIds) {
7666
+ const msg = this.messages.get(id);
7667
+ if (msg && msg.senderPubkey !== this.deps.identity.chainPubkey) {
7668
+ this.deps.transport.sendReadReceipt(msg.senderPubkey, id).catch((err) => {
7669
+ console.warn("[Communications] Failed to send read receipt:", err);
7670
+ });
7671
+ }
7672
+ }
7673
+ }
7642
7674
  }
7643
7675
  /**
7644
7676
  * Get unread count
@@ -7652,6 +7684,15 @@ var CommunicationsModule = class {
7652
7684
  }
7653
7685
  return messages.length;
7654
7686
  }
7687
+ /**
7688
+ * Send typing indicator to a peer
7689
+ */
7690
+ async sendTypingIndicator(peerPubkey) {
7691
+ this.ensureInitialized();
7692
+ if (this.deps.transport.sendTypingIndicator) {
7693
+ await this.deps.transport.sendTypingIndicator(peerPubkey);
7694
+ }
7695
+ }
7655
7696
  /**
7656
7697
  * Subscribe to incoming DMs
7657
7698
  */
@@ -7721,7 +7762,26 @@ var CommunicationsModule = class {
7721
7762
  // Private: Message Handling
7722
7763
  // ===========================================================================
7723
7764
  handleIncomingMessage(msg) {
7765
+ if (msg.isSelfWrap && msg.recipientTransportPubkey) {
7766
+ if (this.messages.has(msg.id)) return;
7767
+ const message2 = {
7768
+ id: msg.id,
7769
+ senderPubkey: this.deps.identity.chainPubkey,
7770
+ senderNametag: msg.senderNametag,
7771
+ recipientPubkey: msg.recipientTransportPubkey,
7772
+ content: msg.content,
7773
+ timestamp: msg.timestamp,
7774
+ isRead: false
7775
+ };
7776
+ this.messages.set(message2.id, message2);
7777
+ this.deps.emitEvent("message:dm", message2);
7778
+ if (this.config.autoSave) {
7779
+ this.save();
7780
+ }
7781
+ return;
7782
+ }
7724
7783
  if (msg.senderTransportPubkey === this.deps?.identity.chainPubkey) return;
7784
+ if (this.messages.has(msg.id)) return;
7725
7785
  const message = {
7726
7786
  id: msg.id,
7727
7787
  senderPubkey: msg.senderTransportPubkey,