@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
|
@@ -591,36 +591,61 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
591
591
|
return meta !== null;
|
|
592
592
|
}
|
|
593
593
|
async clear() {
|
|
594
|
-
|
|
595
|
-
this.db.close();
|
|
596
|
-
this.db = null;
|
|
597
|
-
}
|
|
598
|
-
this.status = "disconnected";
|
|
599
|
-
const CLEAR_TIMEOUT = 1500;
|
|
600
|
-
const withTimeout = (promise, ms, label) => Promise.race([
|
|
601
|
-
promise,
|
|
602
|
-
new Promise(
|
|
603
|
-
(_, reject) => setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms)
|
|
604
|
-
)
|
|
605
|
-
]);
|
|
606
|
-
const deleteDb = (name) => new Promise((resolve) => {
|
|
607
|
-
const req = indexedDB.deleteDatabase(name);
|
|
608
|
-
req.onsuccess = () => resolve();
|
|
609
|
-
req.onerror = () => resolve();
|
|
610
|
-
req.onblocked = () => resolve();
|
|
611
|
-
});
|
|
594
|
+
const dbNames = [this.dbName];
|
|
612
595
|
try {
|
|
596
|
+
if (this.db) {
|
|
597
|
+
await this.clearStore(STORE_TOKENS);
|
|
598
|
+
await this.clearStore(STORE_META);
|
|
599
|
+
this.db.close();
|
|
600
|
+
this.db = null;
|
|
601
|
+
}
|
|
602
|
+
this.status = "disconnected";
|
|
613
603
|
if (typeof indexedDB.databases === "function") {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
604
|
+
try {
|
|
605
|
+
const dbs = await Promise.race([
|
|
606
|
+
indexedDB.databases(),
|
|
607
|
+
new Promise(
|
|
608
|
+
(_, reject) => setTimeout(() => reject(new Error("timeout")), 1500)
|
|
609
|
+
)
|
|
610
|
+
]);
|
|
611
|
+
for (const dbInfo of dbs) {
|
|
612
|
+
if (dbInfo.name && dbInfo.name.startsWith(this.dbNamePrefix) && dbInfo.name !== this.dbName) {
|
|
613
|
+
dbNames.push(dbInfo.name);
|
|
614
|
+
try {
|
|
615
|
+
const db = await new Promise((resolve, reject) => {
|
|
616
|
+
const req = indexedDB.open(dbInfo.name, DB_VERSION);
|
|
617
|
+
req.onsuccess = () => resolve(req.result);
|
|
618
|
+
req.onerror = () => reject(req.error);
|
|
619
|
+
req.onupgradeneeded = (e) => {
|
|
620
|
+
const d = e.target.result;
|
|
621
|
+
if (!d.objectStoreNames.contains(STORE_TOKENS)) d.createObjectStore(STORE_TOKENS, { keyPath: "id" });
|
|
622
|
+
if (!d.objectStoreNames.contains(STORE_META)) d.createObjectStore(STORE_META);
|
|
623
|
+
};
|
|
624
|
+
});
|
|
625
|
+
const clearTx = db.transaction([STORE_TOKENS, STORE_META], "readwrite");
|
|
626
|
+
clearTx.objectStore(STORE_TOKENS).clear();
|
|
627
|
+
clearTx.objectStore(STORE_META).clear();
|
|
628
|
+
await new Promise((resolve) => {
|
|
629
|
+
clearTx.oncomplete = () => resolve();
|
|
630
|
+
clearTx.onerror = () => resolve();
|
|
631
|
+
});
|
|
632
|
+
db.close();
|
|
633
|
+
} catch {
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
} catch {
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
for (const name of dbNames) {
|
|
641
|
+
try {
|
|
642
|
+
const req = indexedDB.deleteDatabase(name);
|
|
643
|
+
req.onerror = () => {
|
|
644
|
+
};
|
|
645
|
+
req.onblocked = () => {
|
|
646
|
+
};
|
|
647
|
+
} catch {
|
|
648
|
+
}
|
|
624
649
|
}
|
|
625
650
|
return true;
|
|
626
651
|
} catch (err) {
|
|
@@ -1378,6 +1403,8 @@ var NostrTransportProvider = class {
|
|
|
1378
1403
|
transferHandlers = /* @__PURE__ */ new Set();
|
|
1379
1404
|
paymentRequestHandlers = /* @__PURE__ */ new Set();
|
|
1380
1405
|
paymentRequestResponseHandlers = /* @__PURE__ */ new Set();
|
|
1406
|
+
readReceiptHandlers = /* @__PURE__ */ new Set();
|
|
1407
|
+
typingIndicatorHandlers = /* @__PURE__ */ new Set();
|
|
1381
1408
|
broadcastHandlers = /* @__PURE__ */ new Map();
|
|
1382
1409
|
eventCallbacks = /* @__PURE__ */ new Set();
|
|
1383
1410
|
constructor(config) {
|
|
@@ -1629,6 +1656,18 @@ var NostrTransportProvider = class {
|
|
|
1629
1656
|
const wrappedContent = senderNametag ? JSON.stringify({ senderNametag, text: content }) : content;
|
|
1630
1657
|
const giftWrap = import_nostr_js_sdk.NIP17.createGiftWrap(this.keyManager, nostrRecipient, wrappedContent);
|
|
1631
1658
|
await this.publishEvent(giftWrap);
|
|
1659
|
+
const selfWrapContent = JSON.stringify({
|
|
1660
|
+
selfWrap: true,
|
|
1661
|
+
originalId: giftWrap.id,
|
|
1662
|
+
recipientPubkey,
|
|
1663
|
+
senderNametag,
|
|
1664
|
+
text: content
|
|
1665
|
+
});
|
|
1666
|
+
const selfPubkey = this.keyManager.getPublicKeyHex();
|
|
1667
|
+
const selfGiftWrap = import_nostr_js_sdk.NIP17.createGiftWrap(this.keyManager, selfPubkey, selfWrapContent);
|
|
1668
|
+
this.publishEvent(selfGiftWrap).catch((err) => {
|
|
1669
|
+
this.log("Self-wrap publish failed:", err);
|
|
1670
|
+
});
|
|
1632
1671
|
this.emitEvent({
|
|
1633
1672
|
type: "message:sent",
|
|
1634
1673
|
timestamp: Date.now(),
|
|
@@ -1727,6 +1766,37 @@ var NostrTransportProvider = class {
|
|
|
1727
1766
|
this.paymentRequestResponseHandlers.add(handler);
|
|
1728
1767
|
return () => this.paymentRequestResponseHandlers.delete(handler);
|
|
1729
1768
|
}
|
|
1769
|
+
// ===========================================================================
|
|
1770
|
+
// Read Receipts
|
|
1771
|
+
// ===========================================================================
|
|
1772
|
+
async sendReadReceipt(recipientTransportPubkey, messageEventId) {
|
|
1773
|
+
if (!this.keyManager) throw new Error("Not initialized");
|
|
1774
|
+
const nostrRecipient = recipientTransportPubkey.length === 66 ? recipientTransportPubkey.slice(2) : recipientTransportPubkey;
|
|
1775
|
+
const event = import_nostr_js_sdk.NIP17.createReadReceipt(this.keyManager, nostrRecipient, messageEventId);
|
|
1776
|
+
await this.publishEvent(event);
|
|
1777
|
+
this.log("Sent read receipt for:", messageEventId, "to:", nostrRecipient.slice(0, 16));
|
|
1778
|
+
}
|
|
1779
|
+
onReadReceipt(handler) {
|
|
1780
|
+
this.readReceiptHandlers.add(handler);
|
|
1781
|
+
return () => this.readReceiptHandlers.delete(handler);
|
|
1782
|
+
}
|
|
1783
|
+
// ===========================================================================
|
|
1784
|
+
// Typing Indicators
|
|
1785
|
+
// ===========================================================================
|
|
1786
|
+
async sendTypingIndicator(recipientTransportPubkey) {
|
|
1787
|
+
if (!this.keyManager) throw new Error("Not initialized");
|
|
1788
|
+
const nostrRecipient = recipientTransportPubkey.length === 66 ? recipientTransportPubkey.slice(2) : recipientTransportPubkey;
|
|
1789
|
+
const content = JSON.stringify({
|
|
1790
|
+
type: "typing",
|
|
1791
|
+
senderNametag: this.identity?.nametag
|
|
1792
|
+
});
|
|
1793
|
+
const event = import_nostr_js_sdk.NIP17.createGiftWrap(this.keyManager, nostrRecipient, content);
|
|
1794
|
+
await this.publishEvent(event);
|
|
1795
|
+
}
|
|
1796
|
+
onTypingIndicator(handler) {
|
|
1797
|
+
this.typingIndicatorHandlers.add(handler);
|
|
1798
|
+
return () => this.typingIndicatorHandlers.delete(handler);
|
|
1799
|
+
}
|
|
1730
1800
|
/**
|
|
1731
1801
|
* Resolve any identifier to full peer information.
|
|
1732
1802
|
* Routes to the appropriate specific resolve method based on identifier format.
|
|
@@ -2180,11 +2250,74 @@ var NostrTransportProvider = class {
|
|
|
2180
2250
|
const pm = import_nostr_js_sdk.NIP17.unwrap(event, this.keyManager);
|
|
2181
2251
|
this.log("Gift wrap unwrapped, sender:", pm.senderPubkey?.slice(0, 16), "kind:", pm.kind);
|
|
2182
2252
|
if (pm.senderPubkey === this.keyManager.getPublicKeyHex()) {
|
|
2183
|
-
|
|
2253
|
+
try {
|
|
2254
|
+
const parsed = JSON.parse(pm.content);
|
|
2255
|
+
if (parsed?.selfWrap && parsed.recipientPubkey) {
|
|
2256
|
+
this.log("Self-wrap replay for recipient:", parsed.recipientPubkey?.slice(0, 16));
|
|
2257
|
+
const message2 = {
|
|
2258
|
+
id: parsed.originalId || pm.eventId,
|
|
2259
|
+
senderTransportPubkey: pm.senderPubkey,
|
|
2260
|
+
senderNametag: parsed.senderNametag,
|
|
2261
|
+
recipientTransportPubkey: parsed.recipientPubkey,
|
|
2262
|
+
content: parsed.text ?? "",
|
|
2263
|
+
timestamp: pm.timestamp * 1e3,
|
|
2264
|
+
encrypted: true,
|
|
2265
|
+
isSelfWrap: true
|
|
2266
|
+
};
|
|
2267
|
+
for (const handler of this.messageHandlers) {
|
|
2268
|
+
try {
|
|
2269
|
+
handler(message2);
|
|
2270
|
+
} catch (e) {
|
|
2271
|
+
this.log("Self-wrap handler error:", e);
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
return;
|
|
2275
|
+
}
|
|
2276
|
+
} catch {
|
|
2277
|
+
}
|
|
2278
|
+
this.log("Skipping own non-self-wrap message");
|
|
2184
2279
|
return;
|
|
2185
2280
|
}
|
|
2186
|
-
if (
|
|
2187
|
-
this.log("
|
|
2281
|
+
if ((0, import_nostr_js_sdk.isReadReceipt)(pm)) {
|
|
2282
|
+
this.log("Read receipt from:", pm.senderPubkey?.slice(0, 16), "for:", pm.replyToEventId);
|
|
2283
|
+
if (pm.replyToEventId) {
|
|
2284
|
+
const receipt = {
|
|
2285
|
+
senderTransportPubkey: pm.senderPubkey,
|
|
2286
|
+
messageEventId: pm.replyToEventId,
|
|
2287
|
+
timestamp: pm.timestamp * 1e3
|
|
2288
|
+
};
|
|
2289
|
+
for (const handler of this.readReceiptHandlers) {
|
|
2290
|
+
try {
|
|
2291
|
+
handler(receipt);
|
|
2292
|
+
} catch (e) {
|
|
2293
|
+
this.log("Read receipt handler error:", e);
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
return;
|
|
2298
|
+
}
|
|
2299
|
+
try {
|
|
2300
|
+
const parsed = JSON.parse(pm.content);
|
|
2301
|
+
if (parsed?.type === "typing") {
|
|
2302
|
+
this.log("Typing indicator from:", pm.senderPubkey?.slice(0, 16));
|
|
2303
|
+
const indicator = {
|
|
2304
|
+
senderTransportPubkey: pm.senderPubkey,
|
|
2305
|
+
senderNametag: parsed.senderNametag,
|
|
2306
|
+
timestamp: pm.timestamp * 1e3
|
|
2307
|
+
};
|
|
2308
|
+
for (const handler of this.typingIndicatorHandlers) {
|
|
2309
|
+
try {
|
|
2310
|
+
handler(indicator);
|
|
2311
|
+
} catch (e) {
|
|
2312
|
+
this.log("Typing handler error:", e);
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
return;
|
|
2316
|
+
}
|
|
2317
|
+
} catch {
|
|
2318
|
+
}
|
|
2319
|
+
if (!(0, import_nostr_js_sdk.isChatMessage)(pm)) {
|
|
2320
|
+
this.log("Skipping unknown message kind:", pm.kind);
|
|
2188
2321
|
return;
|
|
2189
2322
|
}
|
|
2190
2323
|
let content = pm.content;
|
|
@@ -2199,7 +2332,9 @@ var NostrTransportProvider = class {
|
|
|
2199
2332
|
}
|
|
2200
2333
|
this.log("DM received from:", senderNametag || pm.senderPubkey?.slice(0, 16), "content:", content?.slice(0, 50));
|
|
2201
2334
|
const message = {
|
|
2202
|
-
id
|
|
2335
|
+
// Use outer gift wrap event.id so it matches the sender's stored giftWrap.id.
|
|
2336
|
+
// This ensures read receipts reference an ID the sender recognizes.
|
|
2337
|
+
id: event.id,
|
|
2203
2338
|
senderTransportPubkey: pm.senderPubkey,
|
|
2204
2339
|
senderNametag,
|
|
2205
2340
|
content,
|