@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/core/index.cjs +61 -1
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +57 -1
- package/dist/core/index.d.ts +57 -1
- package/dist/core/index.js +61 -1
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/index.cjs +167 -32
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +170 -33
- package/dist/impl/browser/index.js.map +1 -1
- package/dist/impl/nodejs/index.cjs +114 -4
- package/dist/impl/nodejs/index.cjs.map +1 -1
- package/dist/impl/nodejs/index.d.cts +49 -0
- package/dist/impl/nodejs/index.d.ts +49 -0
- package/dist/impl/nodejs/index.js +117 -5
- package/dist/impl/nodejs/index.js.map +1 -1
- package/dist/index.cjs +61 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -1
- package/dist/index.d.ts +57 -1
- package/dist/index.js +61 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -422,6 +422,27 @@ interface TransportProvider extends BaseProvider {
|
|
|
422
422
|
* @returns Unsubscribe function
|
|
423
423
|
*/
|
|
424
424
|
onPaymentRequestResponse?(handler: PaymentRequestResponseHandler): () => void;
|
|
425
|
+
/**
|
|
426
|
+
* Send a read receipt for a message
|
|
427
|
+
* @param recipientTransportPubkey - Transport pubkey of the message sender
|
|
428
|
+
* @param messageEventId - Event ID of the message being acknowledged
|
|
429
|
+
*/
|
|
430
|
+
sendReadReceipt?(recipientTransportPubkey: string, messageEventId: string): Promise<void>;
|
|
431
|
+
/**
|
|
432
|
+
* Subscribe to incoming read receipts
|
|
433
|
+
* @returns Unsubscribe function
|
|
434
|
+
*/
|
|
435
|
+
onReadReceipt?(handler: ReadReceiptHandler): () => void;
|
|
436
|
+
/**
|
|
437
|
+
* Send typing indicator to a recipient
|
|
438
|
+
* @param recipientTransportPubkey - Transport pubkey of the conversation partner
|
|
439
|
+
*/
|
|
440
|
+
sendTypingIndicator?(recipientTransportPubkey: string): Promise<void>;
|
|
441
|
+
/**
|
|
442
|
+
* Subscribe to incoming typing indicators
|
|
443
|
+
* @returns Unsubscribe function
|
|
444
|
+
*/
|
|
445
|
+
onTypingIndicator?(handler: TypingIndicatorHandler): () => void;
|
|
425
446
|
/**
|
|
426
447
|
* Get list of configured relay URLs
|
|
427
448
|
*/
|
|
@@ -511,6 +532,10 @@ interface IncomingMessage {
|
|
|
511
532
|
content: string;
|
|
512
533
|
timestamp: number;
|
|
513
534
|
encrypted: boolean;
|
|
535
|
+
/** Set when this is a self-wrap replay (sent message recovered from relay) */
|
|
536
|
+
isSelfWrap?: boolean;
|
|
537
|
+
/** Recipient pubkey — only present on self-wrap replays */
|
|
538
|
+
recipientTransportPubkey?: string;
|
|
514
539
|
}
|
|
515
540
|
type MessageHandler = (message: IncomingMessage) => void;
|
|
516
541
|
interface TokenTransferPayload {
|
|
@@ -632,6 +657,24 @@ interface PeerInfo {
|
|
|
632
657
|
/** Event timestamp */
|
|
633
658
|
timestamp: number;
|
|
634
659
|
}
|
|
660
|
+
interface IncomingReadReceipt {
|
|
661
|
+
/** Transport-specific pubkey of the sender who read the message */
|
|
662
|
+
senderTransportPubkey: string;
|
|
663
|
+
/** Event ID of the message that was read */
|
|
664
|
+
messageEventId: string;
|
|
665
|
+
/** Timestamp */
|
|
666
|
+
timestamp: number;
|
|
667
|
+
}
|
|
668
|
+
type ReadReceiptHandler = (receipt: IncomingReadReceipt) => void;
|
|
669
|
+
interface IncomingTypingIndicator {
|
|
670
|
+
/** Transport-specific pubkey of the sender who is typing */
|
|
671
|
+
senderTransportPubkey: string;
|
|
672
|
+
/** Sender's nametag (if known) */
|
|
673
|
+
senderNametag?: string;
|
|
674
|
+
/** Timestamp */
|
|
675
|
+
timestamp: number;
|
|
676
|
+
}
|
|
677
|
+
type TypingIndicatorHandler = (indicator: IncomingTypingIndicator) => void;
|
|
635
678
|
|
|
636
679
|
/**
|
|
637
680
|
* WebSocket Abstraction
|
|
@@ -724,6 +767,8 @@ declare class NostrTransportProvider implements TransportProvider {
|
|
|
724
767
|
private transferHandlers;
|
|
725
768
|
private paymentRequestHandlers;
|
|
726
769
|
private paymentRequestResponseHandlers;
|
|
770
|
+
private readReceiptHandlers;
|
|
771
|
+
private typingIndicatorHandlers;
|
|
727
772
|
private broadcastHandlers;
|
|
728
773
|
private eventCallbacks;
|
|
729
774
|
constructor(config: NostrTransportProviderConfig);
|
|
@@ -773,6 +818,10 @@ declare class NostrTransportProvider implements TransportProvider {
|
|
|
773
818
|
onPaymentRequest(handler: PaymentRequestHandler): () => void;
|
|
774
819
|
sendPaymentRequestResponse(recipientPubkey: string, payload: PaymentRequestResponsePayload): Promise<string>;
|
|
775
820
|
onPaymentRequestResponse(handler: PaymentRequestResponseHandler): () => void;
|
|
821
|
+
sendReadReceipt(recipientTransportPubkey: string, messageEventId: string): Promise<void>;
|
|
822
|
+
onReadReceipt(handler: ReadReceiptHandler): () => void;
|
|
823
|
+
sendTypingIndicator(recipientTransportPubkey: string): Promise<void>;
|
|
824
|
+
onTypingIndicator(handler: TypingIndicatorHandler): () => void;
|
|
776
825
|
/**
|
|
777
826
|
* Resolve any identifier to full peer information.
|
|
778
827
|
* Routes to the appropriate specific resolve method based on identifier format.
|
|
@@ -422,6 +422,27 @@ interface TransportProvider extends BaseProvider {
|
|
|
422
422
|
* @returns Unsubscribe function
|
|
423
423
|
*/
|
|
424
424
|
onPaymentRequestResponse?(handler: PaymentRequestResponseHandler): () => void;
|
|
425
|
+
/**
|
|
426
|
+
* Send a read receipt for a message
|
|
427
|
+
* @param recipientTransportPubkey - Transport pubkey of the message sender
|
|
428
|
+
* @param messageEventId - Event ID of the message being acknowledged
|
|
429
|
+
*/
|
|
430
|
+
sendReadReceipt?(recipientTransportPubkey: string, messageEventId: string): Promise<void>;
|
|
431
|
+
/**
|
|
432
|
+
* Subscribe to incoming read receipts
|
|
433
|
+
* @returns Unsubscribe function
|
|
434
|
+
*/
|
|
435
|
+
onReadReceipt?(handler: ReadReceiptHandler): () => void;
|
|
436
|
+
/**
|
|
437
|
+
* Send typing indicator to a recipient
|
|
438
|
+
* @param recipientTransportPubkey - Transport pubkey of the conversation partner
|
|
439
|
+
*/
|
|
440
|
+
sendTypingIndicator?(recipientTransportPubkey: string): Promise<void>;
|
|
441
|
+
/**
|
|
442
|
+
* Subscribe to incoming typing indicators
|
|
443
|
+
* @returns Unsubscribe function
|
|
444
|
+
*/
|
|
445
|
+
onTypingIndicator?(handler: TypingIndicatorHandler): () => void;
|
|
425
446
|
/**
|
|
426
447
|
* Get list of configured relay URLs
|
|
427
448
|
*/
|
|
@@ -511,6 +532,10 @@ interface IncomingMessage {
|
|
|
511
532
|
content: string;
|
|
512
533
|
timestamp: number;
|
|
513
534
|
encrypted: boolean;
|
|
535
|
+
/** Set when this is a self-wrap replay (sent message recovered from relay) */
|
|
536
|
+
isSelfWrap?: boolean;
|
|
537
|
+
/** Recipient pubkey — only present on self-wrap replays */
|
|
538
|
+
recipientTransportPubkey?: string;
|
|
514
539
|
}
|
|
515
540
|
type MessageHandler = (message: IncomingMessage) => void;
|
|
516
541
|
interface TokenTransferPayload {
|
|
@@ -632,6 +657,24 @@ interface PeerInfo {
|
|
|
632
657
|
/** Event timestamp */
|
|
633
658
|
timestamp: number;
|
|
634
659
|
}
|
|
660
|
+
interface IncomingReadReceipt {
|
|
661
|
+
/** Transport-specific pubkey of the sender who read the message */
|
|
662
|
+
senderTransportPubkey: string;
|
|
663
|
+
/** Event ID of the message that was read */
|
|
664
|
+
messageEventId: string;
|
|
665
|
+
/** Timestamp */
|
|
666
|
+
timestamp: number;
|
|
667
|
+
}
|
|
668
|
+
type ReadReceiptHandler = (receipt: IncomingReadReceipt) => void;
|
|
669
|
+
interface IncomingTypingIndicator {
|
|
670
|
+
/** Transport-specific pubkey of the sender who is typing */
|
|
671
|
+
senderTransportPubkey: string;
|
|
672
|
+
/** Sender's nametag (if known) */
|
|
673
|
+
senderNametag?: string;
|
|
674
|
+
/** Timestamp */
|
|
675
|
+
timestamp: number;
|
|
676
|
+
}
|
|
677
|
+
type TypingIndicatorHandler = (indicator: IncomingTypingIndicator) => void;
|
|
635
678
|
|
|
636
679
|
/**
|
|
637
680
|
* WebSocket Abstraction
|
|
@@ -724,6 +767,8 @@ declare class NostrTransportProvider implements TransportProvider {
|
|
|
724
767
|
private transferHandlers;
|
|
725
768
|
private paymentRequestHandlers;
|
|
726
769
|
private paymentRequestResponseHandlers;
|
|
770
|
+
private readReceiptHandlers;
|
|
771
|
+
private typingIndicatorHandlers;
|
|
727
772
|
private broadcastHandlers;
|
|
728
773
|
private eventCallbacks;
|
|
729
774
|
constructor(config: NostrTransportProviderConfig);
|
|
@@ -773,6 +818,10 @@ declare class NostrTransportProvider implements TransportProvider {
|
|
|
773
818
|
onPaymentRequest(handler: PaymentRequestHandler): () => void;
|
|
774
819
|
sendPaymentRequestResponse(recipientPubkey: string, payload: PaymentRequestResponsePayload): Promise<string>;
|
|
775
820
|
onPaymentRequestResponse(handler: PaymentRequestResponseHandler): () => void;
|
|
821
|
+
sendReadReceipt(recipientTransportPubkey: string, messageEventId: string): Promise<void>;
|
|
822
|
+
onReadReceipt(handler: ReadReceiptHandler): () => void;
|
|
823
|
+
sendTypingIndicator(recipientTransportPubkey: string): Promise<void>;
|
|
824
|
+
onTypingIndicator(handler: TypingIndicatorHandler): () => void;
|
|
776
825
|
/**
|
|
777
826
|
* Resolve any identifier to full peer information.
|
|
778
827
|
* Routes to the appropriate specific resolve method based on identifier format.
|
|
@@ -938,7 +938,9 @@ import {
|
|
|
938
938
|
EventKinds,
|
|
939
939
|
hashNametag,
|
|
940
940
|
NostrClient,
|
|
941
|
-
Filter
|
|
941
|
+
Filter,
|
|
942
|
+
isChatMessage,
|
|
943
|
+
isReadReceipt
|
|
942
944
|
} from "@unicitylabs/nostr-js-sdk";
|
|
943
945
|
|
|
944
946
|
// core/crypto.ts
|
|
@@ -1156,6 +1158,8 @@ var NostrTransportProvider = class {
|
|
|
1156
1158
|
transferHandlers = /* @__PURE__ */ new Set();
|
|
1157
1159
|
paymentRequestHandlers = /* @__PURE__ */ new Set();
|
|
1158
1160
|
paymentRequestResponseHandlers = /* @__PURE__ */ new Set();
|
|
1161
|
+
readReceiptHandlers = /* @__PURE__ */ new Set();
|
|
1162
|
+
typingIndicatorHandlers = /* @__PURE__ */ new Set();
|
|
1159
1163
|
broadcastHandlers = /* @__PURE__ */ new Map();
|
|
1160
1164
|
eventCallbacks = /* @__PURE__ */ new Set();
|
|
1161
1165
|
constructor(config) {
|
|
@@ -1407,6 +1411,18 @@ var NostrTransportProvider = class {
|
|
|
1407
1411
|
const wrappedContent = senderNametag ? JSON.stringify({ senderNametag, text: content }) : content;
|
|
1408
1412
|
const giftWrap = NIP17.createGiftWrap(this.keyManager, nostrRecipient, wrappedContent);
|
|
1409
1413
|
await this.publishEvent(giftWrap);
|
|
1414
|
+
const selfWrapContent = JSON.stringify({
|
|
1415
|
+
selfWrap: true,
|
|
1416
|
+
originalId: giftWrap.id,
|
|
1417
|
+
recipientPubkey,
|
|
1418
|
+
senderNametag,
|
|
1419
|
+
text: content
|
|
1420
|
+
});
|
|
1421
|
+
const selfPubkey = this.keyManager.getPublicKeyHex();
|
|
1422
|
+
const selfGiftWrap = NIP17.createGiftWrap(this.keyManager, selfPubkey, selfWrapContent);
|
|
1423
|
+
this.publishEvent(selfGiftWrap).catch((err) => {
|
|
1424
|
+
this.log("Self-wrap publish failed:", err);
|
|
1425
|
+
});
|
|
1410
1426
|
this.emitEvent({
|
|
1411
1427
|
type: "message:sent",
|
|
1412
1428
|
timestamp: Date.now(),
|
|
@@ -1505,6 +1521,37 @@ var NostrTransportProvider = class {
|
|
|
1505
1521
|
this.paymentRequestResponseHandlers.add(handler);
|
|
1506
1522
|
return () => this.paymentRequestResponseHandlers.delete(handler);
|
|
1507
1523
|
}
|
|
1524
|
+
// ===========================================================================
|
|
1525
|
+
// Read Receipts
|
|
1526
|
+
// ===========================================================================
|
|
1527
|
+
async sendReadReceipt(recipientTransportPubkey, messageEventId) {
|
|
1528
|
+
if (!this.keyManager) throw new Error("Not initialized");
|
|
1529
|
+
const nostrRecipient = recipientTransportPubkey.length === 66 ? recipientTransportPubkey.slice(2) : recipientTransportPubkey;
|
|
1530
|
+
const event = NIP17.createReadReceipt(this.keyManager, nostrRecipient, messageEventId);
|
|
1531
|
+
await this.publishEvent(event);
|
|
1532
|
+
this.log("Sent read receipt for:", messageEventId, "to:", nostrRecipient.slice(0, 16));
|
|
1533
|
+
}
|
|
1534
|
+
onReadReceipt(handler) {
|
|
1535
|
+
this.readReceiptHandlers.add(handler);
|
|
1536
|
+
return () => this.readReceiptHandlers.delete(handler);
|
|
1537
|
+
}
|
|
1538
|
+
// ===========================================================================
|
|
1539
|
+
// Typing Indicators
|
|
1540
|
+
// ===========================================================================
|
|
1541
|
+
async sendTypingIndicator(recipientTransportPubkey) {
|
|
1542
|
+
if (!this.keyManager) throw new Error("Not initialized");
|
|
1543
|
+
const nostrRecipient = recipientTransportPubkey.length === 66 ? recipientTransportPubkey.slice(2) : recipientTransportPubkey;
|
|
1544
|
+
const content = JSON.stringify({
|
|
1545
|
+
type: "typing",
|
|
1546
|
+
senderNametag: this.identity?.nametag
|
|
1547
|
+
});
|
|
1548
|
+
const event = NIP17.createGiftWrap(this.keyManager, nostrRecipient, content);
|
|
1549
|
+
await this.publishEvent(event);
|
|
1550
|
+
}
|
|
1551
|
+
onTypingIndicator(handler) {
|
|
1552
|
+
this.typingIndicatorHandlers.add(handler);
|
|
1553
|
+
return () => this.typingIndicatorHandlers.delete(handler);
|
|
1554
|
+
}
|
|
1508
1555
|
/**
|
|
1509
1556
|
* Resolve any identifier to full peer information.
|
|
1510
1557
|
* Routes to the appropriate specific resolve method based on identifier format.
|
|
@@ -1958,11 +2005,74 @@ var NostrTransportProvider = class {
|
|
|
1958
2005
|
const pm = NIP17.unwrap(event, this.keyManager);
|
|
1959
2006
|
this.log("Gift wrap unwrapped, sender:", pm.senderPubkey?.slice(0, 16), "kind:", pm.kind);
|
|
1960
2007
|
if (pm.senderPubkey === this.keyManager.getPublicKeyHex()) {
|
|
1961
|
-
|
|
2008
|
+
try {
|
|
2009
|
+
const parsed = JSON.parse(pm.content);
|
|
2010
|
+
if (parsed?.selfWrap && parsed.recipientPubkey) {
|
|
2011
|
+
this.log("Self-wrap replay for recipient:", parsed.recipientPubkey?.slice(0, 16));
|
|
2012
|
+
const message2 = {
|
|
2013
|
+
id: parsed.originalId || pm.eventId,
|
|
2014
|
+
senderTransportPubkey: pm.senderPubkey,
|
|
2015
|
+
senderNametag: parsed.senderNametag,
|
|
2016
|
+
recipientTransportPubkey: parsed.recipientPubkey,
|
|
2017
|
+
content: parsed.text ?? "",
|
|
2018
|
+
timestamp: pm.timestamp * 1e3,
|
|
2019
|
+
encrypted: true,
|
|
2020
|
+
isSelfWrap: true
|
|
2021
|
+
};
|
|
2022
|
+
for (const handler of this.messageHandlers) {
|
|
2023
|
+
try {
|
|
2024
|
+
handler(message2);
|
|
2025
|
+
} catch (e) {
|
|
2026
|
+
this.log("Self-wrap handler error:", e);
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
return;
|
|
2030
|
+
}
|
|
2031
|
+
} catch {
|
|
2032
|
+
}
|
|
2033
|
+
this.log("Skipping own non-self-wrap message");
|
|
1962
2034
|
return;
|
|
1963
2035
|
}
|
|
1964
|
-
if (pm
|
|
1965
|
-
this.log("
|
|
2036
|
+
if (isReadReceipt(pm)) {
|
|
2037
|
+
this.log("Read receipt from:", pm.senderPubkey?.slice(0, 16), "for:", pm.replyToEventId);
|
|
2038
|
+
if (pm.replyToEventId) {
|
|
2039
|
+
const receipt = {
|
|
2040
|
+
senderTransportPubkey: pm.senderPubkey,
|
|
2041
|
+
messageEventId: pm.replyToEventId,
|
|
2042
|
+
timestamp: pm.timestamp * 1e3
|
|
2043
|
+
};
|
|
2044
|
+
for (const handler of this.readReceiptHandlers) {
|
|
2045
|
+
try {
|
|
2046
|
+
handler(receipt);
|
|
2047
|
+
} catch (e) {
|
|
2048
|
+
this.log("Read receipt handler error:", e);
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
return;
|
|
2053
|
+
}
|
|
2054
|
+
try {
|
|
2055
|
+
const parsed = JSON.parse(pm.content);
|
|
2056
|
+
if (parsed?.type === "typing") {
|
|
2057
|
+
this.log("Typing indicator from:", pm.senderPubkey?.slice(0, 16));
|
|
2058
|
+
const indicator = {
|
|
2059
|
+
senderTransportPubkey: pm.senderPubkey,
|
|
2060
|
+
senderNametag: parsed.senderNametag,
|
|
2061
|
+
timestamp: pm.timestamp * 1e3
|
|
2062
|
+
};
|
|
2063
|
+
for (const handler of this.typingIndicatorHandlers) {
|
|
2064
|
+
try {
|
|
2065
|
+
handler(indicator);
|
|
2066
|
+
} catch (e) {
|
|
2067
|
+
this.log("Typing handler error:", e);
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
return;
|
|
2071
|
+
}
|
|
2072
|
+
} catch {
|
|
2073
|
+
}
|
|
2074
|
+
if (!isChatMessage(pm)) {
|
|
2075
|
+
this.log("Skipping unknown message kind:", pm.kind);
|
|
1966
2076
|
return;
|
|
1967
2077
|
}
|
|
1968
2078
|
let content = pm.content;
|
|
@@ -1977,7 +2087,9 @@ var NostrTransportProvider = class {
|
|
|
1977
2087
|
}
|
|
1978
2088
|
this.log("DM received from:", senderNametag || pm.senderPubkey?.slice(0, 16), "content:", content?.slice(0, 50));
|
|
1979
2089
|
const message = {
|
|
1980
|
-
id
|
|
2090
|
+
// Use outer gift wrap event.id so it matches the sender's stored giftWrap.id.
|
|
2091
|
+
// This ensures read receipts reference an ID the sender recognizes.
|
|
2092
|
+
id: event.id,
|
|
1981
2093
|
senderTransportPubkey: pm.senderPubkey,
|
|
1982
2094
|
senderNametag,
|
|
1983
2095
|
content,
|