@unicitylabs/sphere-sdk 0.3.8 → 0.3.9
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/connect/index.cjs +770 -0
- package/dist/connect/index.cjs.map +1 -0
- package/dist/connect/index.d.cts +312 -0
- package/dist/connect/index.d.ts +312 -0
- package/dist/connect/index.js +747 -0
- package/dist/connect/index.js.map +1 -0
- package/dist/core/index.cjs +87 -7
- 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 +87 -7
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/connect/index.cjs +271 -0
- package/dist/impl/browser/connect/index.cjs.map +1 -0
- package/dist/impl/browser/connect/index.d.cts +137 -0
- package/dist/impl/browser/connect/index.d.ts +137 -0
- package/dist/impl/browser/connect/index.js +248 -0
- package/dist/impl/browser/connect/index.js.map +1 -0
- 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/browser/ipfs.cjs.map +1 -1
- package/dist/impl/browser/ipfs.js.map +1 -1
- package/dist/impl/nodejs/connect/index.cjs +372 -0
- package/dist/impl/nodejs/connect/index.cjs.map +1 -0
- package/dist/impl/nodejs/connect/index.d.cts +178 -0
- package/dist/impl/nodejs/connect/index.d.ts +178 -0
- package/dist/impl/nodejs/connect/index.js +333 -0
- package/dist/impl/nodejs/connect/index.js.map +1 -0
- 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 +87 -7
- 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 +87 -7
- package/dist/index.js.map +1 -1
- package/package.json +31 -1
|
@@ -536,36 +536,61 @@ var IndexedDBTokenStorageProvider = class {
|
|
|
536
536
|
return meta !== null;
|
|
537
537
|
}
|
|
538
538
|
async clear() {
|
|
539
|
-
|
|
540
|
-
this.db.close();
|
|
541
|
-
this.db = null;
|
|
542
|
-
}
|
|
543
|
-
this.status = "disconnected";
|
|
544
|
-
const CLEAR_TIMEOUT = 1500;
|
|
545
|
-
const withTimeout = (promise, ms, label) => Promise.race([
|
|
546
|
-
promise,
|
|
547
|
-
new Promise(
|
|
548
|
-
(_, reject) => setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms)
|
|
549
|
-
)
|
|
550
|
-
]);
|
|
551
|
-
const deleteDb = (name) => new Promise((resolve) => {
|
|
552
|
-
const req = indexedDB.deleteDatabase(name);
|
|
553
|
-
req.onsuccess = () => resolve();
|
|
554
|
-
req.onerror = () => resolve();
|
|
555
|
-
req.onblocked = () => resolve();
|
|
556
|
-
});
|
|
539
|
+
const dbNames = [this.dbName];
|
|
557
540
|
try {
|
|
541
|
+
if (this.db) {
|
|
542
|
+
await this.clearStore(STORE_TOKENS);
|
|
543
|
+
await this.clearStore(STORE_META);
|
|
544
|
+
this.db.close();
|
|
545
|
+
this.db = null;
|
|
546
|
+
}
|
|
547
|
+
this.status = "disconnected";
|
|
558
548
|
if (typeof indexedDB.databases === "function") {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
549
|
+
try {
|
|
550
|
+
const dbs = await Promise.race([
|
|
551
|
+
indexedDB.databases(),
|
|
552
|
+
new Promise(
|
|
553
|
+
(_, reject) => setTimeout(() => reject(new Error("timeout")), 1500)
|
|
554
|
+
)
|
|
555
|
+
]);
|
|
556
|
+
for (const dbInfo of dbs) {
|
|
557
|
+
if (dbInfo.name && dbInfo.name.startsWith(this.dbNamePrefix) && dbInfo.name !== this.dbName) {
|
|
558
|
+
dbNames.push(dbInfo.name);
|
|
559
|
+
try {
|
|
560
|
+
const db = await new Promise((resolve, reject) => {
|
|
561
|
+
const req = indexedDB.open(dbInfo.name, DB_VERSION);
|
|
562
|
+
req.onsuccess = () => resolve(req.result);
|
|
563
|
+
req.onerror = () => reject(req.error);
|
|
564
|
+
req.onupgradeneeded = (e) => {
|
|
565
|
+
const d = e.target.result;
|
|
566
|
+
if (!d.objectStoreNames.contains(STORE_TOKENS)) d.createObjectStore(STORE_TOKENS, { keyPath: "id" });
|
|
567
|
+
if (!d.objectStoreNames.contains(STORE_META)) d.createObjectStore(STORE_META);
|
|
568
|
+
};
|
|
569
|
+
});
|
|
570
|
+
const clearTx = db.transaction([STORE_TOKENS, STORE_META], "readwrite");
|
|
571
|
+
clearTx.objectStore(STORE_TOKENS).clear();
|
|
572
|
+
clearTx.objectStore(STORE_META).clear();
|
|
573
|
+
await new Promise((resolve) => {
|
|
574
|
+
clearTx.oncomplete = () => resolve();
|
|
575
|
+
clearTx.onerror = () => resolve();
|
|
576
|
+
});
|
|
577
|
+
db.close();
|
|
578
|
+
} catch {
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
} catch {
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
for (const name of dbNames) {
|
|
586
|
+
try {
|
|
587
|
+
const req = indexedDB.deleteDatabase(name);
|
|
588
|
+
req.onerror = () => {
|
|
589
|
+
};
|
|
590
|
+
req.onblocked = () => {
|
|
591
|
+
};
|
|
592
|
+
} catch {
|
|
593
|
+
}
|
|
569
594
|
}
|
|
570
595
|
return true;
|
|
571
596
|
} catch (err) {
|
|
@@ -1114,7 +1139,9 @@ import {
|
|
|
1114
1139
|
EventKinds,
|
|
1115
1140
|
hashNametag,
|
|
1116
1141
|
NostrClient,
|
|
1117
|
-
Filter
|
|
1142
|
+
Filter,
|
|
1143
|
+
isChatMessage,
|
|
1144
|
+
isReadReceipt
|
|
1118
1145
|
} from "@unicitylabs/nostr-js-sdk";
|
|
1119
1146
|
|
|
1120
1147
|
// core/crypto.ts
|
|
@@ -1332,6 +1359,8 @@ var NostrTransportProvider = class {
|
|
|
1332
1359
|
transferHandlers = /* @__PURE__ */ new Set();
|
|
1333
1360
|
paymentRequestHandlers = /* @__PURE__ */ new Set();
|
|
1334
1361
|
paymentRequestResponseHandlers = /* @__PURE__ */ new Set();
|
|
1362
|
+
readReceiptHandlers = /* @__PURE__ */ new Set();
|
|
1363
|
+
typingIndicatorHandlers = /* @__PURE__ */ new Set();
|
|
1335
1364
|
broadcastHandlers = /* @__PURE__ */ new Map();
|
|
1336
1365
|
eventCallbacks = /* @__PURE__ */ new Set();
|
|
1337
1366
|
constructor(config) {
|
|
@@ -1583,6 +1612,18 @@ var NostrTransportProvider = class {
|
|
|
1583
1612
|
const wrappedContent = senderNametag ? JSON.stringify({ senderNametag, text: content }) : content;
|
|
1584
1613
|
const giftWrap = NIP17.createGiftWrap(this.keyManager, nostrRecipient, wrappedContent);
|
|
1585
1614
|
await this.publishEvent(giftWrap);
|
|
1615
|
+
const selfWrapContent = JSON.stringify({
|
|
1616
|
+
selfWrap: true,
|
|
1617
|
+
originalId: giftWrap.id,
|
|
1618
|
+
recipientPubkey,
|
|
1619
|
+
senderNametag,
|
|
1620
|
+
text: content
|
|
1621
|
+
});
|
|
1622
|
+
const selfPubkey = this.keyManager.getPublicKeyHex();
|
|
1623
|
+
const selfGiftWrap = NIP17.createGiftWrap(this.keyManager, selfPubkey, selfWrapContent);
|
|
1624
|
+
this.publishEvent(selfGiftWrap).catch((err) => {
|
|
1625
|
+
this.log("Self-wrap publish failed:", err);
|
|
1626
|
+
});
|
|
1586
1627
|
this.emitEvent({
|
|
1587
1628
|
type: "message:sent",
|
|
1588
1629
|
timestamp: Date.now(),
|
|
@@ -1681,6 +1722,37 @@ var NostrTransportProvider = class {
|
|
|
1681
1722
|
this.paymentRequestResponseHandlers.add(handler);
|
|
1682
1723
|
return () => this.paymentRequestResponseHandlers.delete(handler);
|
|
1683
1724
|
}
|
|
1725
|
+
// ===========================================================================
|
|
1726
|
+
// Read Receipts
|
|
1727
|
+
// ===========================================================================
|
|
1728
|
+
async sendReadReceipt(recipientTransportPubkey, messageEventId) {
|
|
1729
|
+
if (!this.keyManager) throw new Error("Not initialized");
|
|
1730
|
+
const nostrRecipient = recipientTransportPubkey.length === 66 ? recipientTransportPubkey.slice(2) : recipientTransportPubkey;
|
|
1731
|
+
const event = NIP17.createReadReceipt(this.keyManager, nostrRecipient, messageEventId);
|
|
1732
|
+
await this.publishEvent(event);
|
|
1733
|
+
this.log("Sent read receipt for:", messageEventId, "to:", nostrRecipient.slice(0, 16));
|
|
1734
|
+
}
|
|
1735
|
+
onReadReceipt(handler) {
|
|
1736
|
+
this.readReceiptHandlers.add(handler);
|
|
1737
|
+
return () => this.readReceiptHandlers.delete(handler);
|
|
1738
|
+
}
|
|
1739
|
+
// ===========================================================================
|
|
1740
|
+
// Typing Indicators
|
|
1741
|
+
// ===========================================================================
|
|
1742
|
+
async sendTypingIndicator(recipientTransportPubkey) {
|
|
1743
|
+
if (!this.keyManager) throw new Error("Not initialized");
|
|
1744
|
+
const nostrRecipient = recipientTransportPubkey.length === 66 ? recipientTransportPubkey.slice(2) : recipientTransportPubkey;
|
|
1745
|
+
const content = JSON.stringify({
|
|
1746
|
+
type: "typing",
|
|
1747
|
+
senderNametag: this.identity?.nametag
|
|
1748
|
+
});
|
|
1749
|
+
const event = NIP17.createGiftWrap(this.keyManager, nostrRecipient, content);
|
|
1750
|
+
await this.publishEvent(event);
|
|
1751
|
+
}
|
|
1752
|
+
onTypingIndicator(handler) {
|
|
1753
|
+
this.typingIndicatorHandlers.add(handler);
|
|
1754
|
+
return () => this.typingIndicatorHandlers.delete(handler);
|
|
1755
|
+
}
|
|
1684
1756
|
/**
|
|
1685
1757
|
* Resolve any identifier to full peer information.
|
|
1686
1758
|
* Routes to the appropriate specific resolve method based on identifier format.
|
|
@@ -2134,11 +2206,74 @@ var NostrTransportProvider = class {
|
|
|
2134
2206
|
const pm = NIP17.unwrap(event, this.keyManager);
|
|
2135
2207
|
this.log("Gift wrap unwrapped, sender:", pm.senderPubkey?.slice(0, 16), "kind:", pm.kind);
|
|
2136
2208
|
if (pm.senderPubkey === this.keyManager.getPublicKeyHex()) {
|
|
2137
|
-
|
|
2209
|
+
try {
|
|
2210
|
+
const parsed = JSON.parse(pm.content);
|
|
2211
|
+
if (parsed?.selfWrap && parsed.recipientPubkey) {
|
|
2212
|
+
this.log("Self-wrap replay for recipient:", parsed.recipientPubkey?.slice(0, 16));
|
|
2213
|
+
const message2 = {
|
|
2214
|
+
id: parsed.originalId || pm.eventId,
|
|
2215
|
+
senderTransportPubkey: pm.senderPubkey,
|
|
2216
|
+
senderNametag: parsed.senderNametag,
|
|
2217
|
+
recipientTransportPubkey: parsed.recipientPubkey,
|
|
2218
|
+
content: parsed.text ?? "",
|
|
2219
|
+
timestamp: pm.timestamp * 1e3,
|
|
2220
|
+
encrypted: true,
|
|
2221
|
+
isSelfWrap: true
|
|
2222
|
+
};
|
|
2223
|
+
for (const handler of this.messageHandlers) {
|
|
2224
|
+
try {
|
|
2225
|
+
handler(message2);
|
|
2226
|
+
} catch (e) {
|
|
2227
|
+
this.log("Self-wrap handler error:", e);
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
return;
|
|
2231
|
+
}
|
|
2232
|
+
} catch {
|
|
2233
|
+
}
|
|
2234
|
+
this.log("Skipping own non-self-wrap message");
|
|
2138
2235
|
return;
|
|
2139
2236
|
}
|
|
2140
|
-
if (pm
|
|
2141
|
-
this.log("
|
|
2237
|
+
if (isReadReceipt(pm)) {
|
|
2238
|
+
this.log("Read receipt from:", pm.senderPubkey?.slice(0, 16), "for:", pm.replyToEventId);
|
|
2239
|
+
if (pm.replyToEventId) {
|
|
2240
|
+
const receipt = {
|
|
2241
|
+
senderTransportPubkey: pm.senderPubkey,
|
|
2242
|
+
messageEventId: pm.replyToEventId,
|
|
2243
|
+
timestamp: pm.timestamp * 1e3
|
|
2244
|
+
};
|
|
2245
|
+
for (const handler of this.readReceiptHandlers) {
|
|
2246
|
+
try {
|
|
2247
|
+
handler(receipt);
|
|
2248
|
+
} catch (e) {
|
|
2249
|
+
this.log("Read receipt handler error:", e);
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
return;
|
|
2254
|
+
}
|
|
2255
|
+
try {
|
|
2256
|
+
const parsed = JSON.parse(pm.content);
|
|
2257
|
+
if (parsed?.type === "typing") {
|
|
2258
|
+
this.log("Typing indicator from:", pm.senderPubkey?.slice(0, 16));
|
|
2259
|
+
const indicator = {
|
|
2260
|
+
senderTransportPubkey: pm.senderPubkey,
|
|
2261
|
+
senderNametag: parsed.senderNametag,
|
|
2262
|
+
timestamp: pm.timestamp * 1e3
|
|
2263
|
+
};
|
|
2264
|
+
for (const handler of this.typingIndicatorHandlers) {
|
|
2265
|
+
try {
|
|
2266
|
+
handler(indicator);
|
|
2267
|
+
} catch (e) {
|
|
2268
|
+
this.log("Typing handler error:", e);
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
return;
|
|
2272
|
+
}
|
|
2273
|
+
} catch {
|
|
2274
|
+
}
|
|
2275
|
+
if (!isChatMessage(pm)) {
|
|
2276
|
+
this.log("Skipping unknown message kind:", pm.kind);
|
|
2142
2277
|
return;
|
|
2143
2278
|
}
|
|
2144
2279
|
let content = pm.content;
|
|
@@ -2153,7 +2288,9 @@ var NostrTransportProvider = class {
|
|
|
2153
2288
|
}
|
|
2154
2289
|
this.log("DM received from:", senderNametag || pm.senderPubkey?.slice(0, 16), "content:", content?.slice(0, 50));
|
|
2155
2290
|
const message = {
|
|
2156
|
-
id
|
|
2291
|
+
// Use outer gift wrap event.id so it matches the sender's stored giftWrap.id.
|
|
2292
|
+
// This ensures read receipts reference an ID the sender recognizes.
|
|
2293
|
+
id: event.id,
|
|
2157
2294
|
senderTransportPubkey: pm.senderPubkey,
|
|
2158
2295
|
senderNametag,
|
|
2159
2296
|
content,
|