@unicitylabs/sphere-sdk 0.3.9 → 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.
- package/dist/connect/index.cjs +1 -1
- package/dist/connect/index.cjs.map +1 -1
- package/dist/connect/index.js +1 -1
- package/dist/connect/index.js.map +1 -1
- package/dist/core/index.cjs +2657 -49
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +221 -3
- package/dist/core/index.d.ts +221 -3
- package/dist/core/index.js +2653 -45
- package/dist/core/index.js.map +1 -1
- package/dist/impl/browser/index.cjs +450 -47
- package/dist/impl/browser/index.cjs.map +1 -1
- package/dist/impl/browser/index.js +451 -47
- package/dist/impl/browser/index.js.map +1 -1
- package/dist/impl/nodejs/index.cjs +152 -8
- package/dist/impl/nodejs/index.cjs.map +1 -1
- package/dist/impl/nodejs/index.d.cts +47 -0
- package/dist/impl/nodejs/index.d.ts +47 -0
- package/dist/impl/nodejs/index.js +153 -8
- package/dist/impl/nodejs/index.js.map +1 -1
- package/dist/index.cjs +2674 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +319 -5
- package/dist/index.d.ts +319 -5
- package/dist/index.js +2663 -45
- package/dist/index.js.map +1 -1
- package/dist/l1/index.cjs +5 -1
- package/dist/l1/index.cjs.map +1 -1
- package/dist/l1/index.d.cts +2 -1
- package/dist/l1/index.d.ts +2 -1
- package/dist/l1/index.js +5 -1
- package/dist/l1/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -597,6 +597,52 @@ function createView(arr) {
|
|
|
597
597
|
function rotr(word, shift) {
|
|
598
598
|
return word << 32 - shift | word >>> shift;
|
|
599
599
|
}
|
|
600
|
+
var hasHexBuiltin = /* @__PURE__ */ (() => (
|
|
601
|
+
// @ts-ignore
|
|
602
|
+
typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
|
|
603
|
+
))();
|
|
604
|
+
var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
|
|
605
|
+
function bytesToHex(bytes) {
|
|
606
|
+
abytes(bytes);
|
|
607
|
+
if (hasHexBuiltin)
|
|
608
|
+
return bytes.toHex();
|
|
609
|
+
let hex = "";
|
|
610
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
611
|
+
hex += hexes[bytes[i]];
|
|
612
|
+
}
|
|
613
|
+
return hex;
|
|
614
|
+
}
|
|
615
|
+
var asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
|
|
616
|
+
function asciiToBase16(ch) {
|
|
617
|
+
if (ch >= asciis._0 && ch <= asciis._9)
|
|
618
|
+
return ch - asciis._0;
|
|
619
|
+
if (ch >= asciis.A && ch <= asciis.F)
|
|
620
|
+
return ch - (asciis.A - 10);
|
|
621
|
+
if (ch >= asciis.a && ch <= asciis.f)
|
|
622
|
+
return ch - (asciis.a - 10);
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
function hexToBytes(hex) {
|
|
626
|
+
if (typeof hex !== "string")
|
|
627
|
+
throw new Error("hex string expected, got " + typeof hex);
|
|
628
|
+
if (hasHexBuiltin)
|
|
629
|
+
return Uint8Array.fromHex(hex);
|
|
630
|
+
const hl = hex.length;
|
|
631
|
+
const al = hl / 2;
|
|
632
|
+
if (hl % 2)
|
|
633
|
+
throw new Error("hex string expected, got unpadded hex of length " + hl);
|
|
634
|
+
const array = new Uint8Array(al);
|
|
635
|
+
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
|
|
636
|
+
const n1 = asciiToBase16(hex.charCodeAt(hi));
|
|
637
|
+
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
|
|
638
|
+
if (n1 === void 0 || n2 === void 0) {
|
|
639
|
+
const char = hex[hi] + hex[hi + 1];
|
|
640
|
+
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
|
|
641
|
+
}
|
|
642
|
+
array[ai] = n1 * 16 + n2;
|
|
643
|
+
}
|
|
644
|
+
return array;
|
|
645
|
+
}
|
|
600
646
|
function createHasher(hashCons, info = {}) {
|
|
601
647
|
const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
|
|
602
648
|
const tmp = hashCons(void 0);
|
|
@@ -1092,7 +1138,7 @@ function publicKeyToAddress(publicKey, prefix = "alpha", witnessVersion = 0) {
|
|
|
1092
1138
|
const programBytes = hash160ToBytes(pubKeyHash);
|
|
1093
1139
|
return encodeBech32(prefix, witnessVersion, programBytes);
|
|
1094
1140
|
}
|
|
1095
|
-
function
|
|
1141
|
+
function hexToBytes2(hex) {
|
|
1096
1142
|
const matches = hex.match(/../g);
|
|
1097
1143
|
if (!matches) {
|
|
1098
1144
|
return new Uint8Array(0);
|
|
@@ -1119,6 +1165,8 @@ function defaultUUIDGenerator() {
|
|
|
1119
1165
|
}
|
|
1120
1166
|
|
|
1121
1167
|
// transport/NostrTransportProvider.ts
|
|
1168
|
+
var COMPOSING_INDICATOR_KIND = 25050;
|
|
1169
|
+
var TIMESTAMP_RANDOMIZATION = 2 * 24 * 60 * 60;
|
|
1122
1170
|
var EVENT_KINDS = NOSTR_EVENT_KINDS;
|
|
1123
1171
|
function hashAddressForTag(address) {
|
|
1124
1172
|
const bytes = new TextEncoder().encode("unicity:address:" + address);
|
|
@@ -1201,6 +1249,8 @@ var NostrTransportProvider = class {
|
|
|
1201
1249
|
paymentRequestResponseHandlers = /* @__PURE__ */ new Set();
|
|
1202
1250
|
readReceiptHandlers = /* @__PURE__ */ new Set();
|
|
1203
1251
|
typingIndicatorHandlers = /* @__PURE__ */ new Set();
|
|
1252
|
+
composingHandlers = /* @__PURE__ */ new Set();
|
|
1253
|
+
pendingMessages = [];
|
|
1204
1254
|
broadcastHandlers = /* @__PURE__ */ new Map();
|
|
1205
1255
|
eventCallbacks = /* @__PURE__ */ new Set();
|
|
1206
1256
|
constructor(config) {
|
|
@@ -1473,6 +1523,18 @@ var NostrTransportProvider = class {
|
|
|
1473
1523
|
}
|
|
1474
1524
|
onMessage(handler) {
|
|
1475
1525
|
this.messageHandlers.add(handler);
|
|
1526
|
+
if (this.pendingMessages.length > 0) {
|
|
1527
|
+
const pending = this.pendingMessages;
|
|
1528
|
+
this.pendingMessages = [];
|
|
1529
|
+
this.log("Flushing", pending.length, "buffered messages to new handler");
|
|
1530
|
+
for (const message of pending) {
|
|
1531
|
+
try {
|
|
1532
|
+
handler(message);
|
|
1533
|
+
} catch (error) {
|
|
1534
|
+
this.log("Message handler error (buffered):", error);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1476
1538
|
return () => this.messageHandlers.delete(handler);
|
|
1477
1539
|
}
|
|
1478
1540
|
async sendTokenTransfer(recipientPubkey, payload) {
|
|
@@ -1593,6 +1655,19 @@ var NostrTransportProvider = class {
|
|
|
1593
1655
|
this.typingIndicatorHandlers.add(handler);
|
|
1594
1656
|
return () => this.typingIndicatorHandlers.delete(handler);
|
|
1595
1657
|
}
|
|
1658
|
+
// ===========================================================================
|
|
1659
|
+
// Composing Indicators (NIP-59 kind 25050)
|
|
1660
|
+
// ===========================================================================
|
|
1661
|
+
onComposing(handler) {
|
|
1662
|
+
this.composingHandlers.add(handler);
|
|
1663
|
+
return () => this.composingHandlers.delete(handler);
|
|
1664
|
+
}
|
|
1665
|
+
async sendComposingIndicator(recipientPubkey, content) {
|
|
1666
|
+
this.ensureReady();
|
|
1667
|
+
const nostrRecipient = recipientPubkey.length === 66 && (recipientPubkey.startsWith("02") || recipientPubkey.startsWith("03")) ? recipientPubkey.slice(2) : recipientPubkey;
|
|
1668
|
+
const giftWrap = this.createCustomKindGiftWrap(nostrRecipient, content, COMPOSING_INDICATOR_KIND);
|
|
1669
|
+
await this.publishEvent(giftWrap);
|
|
1670
|
+
}
|
|
1596
1671
|
/**
|
|
1597
1672
|
* Resolve any identifier to full peer information.
|
|
1598
1673
|
* Routes to the appropriate specific resolve method based on identifier format.
|
|
@@ -2092,6 +2167,30 @@ var NostrTransportProvider = class {
|
|
|
2092
2167
|
}
|
|
2093
2168
|
return;
|
|
2094
2169
|
}
|
|
2170
|
+
if (pm.kind === COMPOSING_INDICATOR_KIND) {
|
|
2171
|
+
let senderNametag2;
|
|
2172
|
+
let expiresIn = 3e4;
|
|
2173
|
+
try {
|
|
2174
|
+
const parsed = JSON.parse(pm.content);
|
|
2175
|
+
senderNametag2 = parsed.senderNametag || void 0;
|
|
2176
|
+
expiresIn = parsed.expiresIn ?? 3e4;
|
|
2177
|
+
} catch {
|
|
2178
|
+
}
|
|
2179
|
+
const indicator = {
|
|
2180
|
+
senderPubkey: pm.senderPubkey,
|
|
2181
|
+
senderNametag: senderNametag2,
|
|
2182
|
+
expiresIn
|
|
2183
|
+
};
|
|
2184
|
+
this.log("Composing indicator from:", indicator.senderNametag || pm.senderPubkey?.slice(0, 16));
|
|
2185
|
+
for (const handler of this.composingHandlers) {
|
|
2186
|
+
try {
|
|
2187
|
+
handler(indicator);
|
|
2188
|
+
} catch (e) {
|
|
2189
|
+
this.log("Composing handler error:", e);
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
return;
|
|
2193
|
+
}
|
|
2095
2194
|
try {
|
|
2096
2195
|
const parsed = JSON.parse(pm.content);
|
|
2097
2196
|
if (parsed?.type === "typing") {
|
|
@@ -2138,12 +2237,17 @@ var NostrTransportProvider = class {
|
|
|
2138
2237
|
encrypted: true
|
|
2139
2238
|
};
|
|
2140
2239
|
this.emitEvent({ type: "message:received", timestamp: Date.now() });
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2240
|
+
if (this.messageHandlers.size === 0) {
|
|
2241
|
+
this.log("No message handlers registered, buffering message for later delivery");
|
|
2242
|
+
this.pendingMessages.push(message);
|
|
2243
|
+
} else {
|
|
2244
|
+
this.log("Dispatching to", this.messageHandlers.size, "handlers");
|
|
2245
|
+
for (const handler of this.messageHandlers) {
|
|
2246
|
+
try {
|
|
2247
|
+
handler(message);
|
|
2248
|
+
} catch (error) {
|
|
2249
|
+
this.log("Message handler error:", error);
|
|
2250
|
+
}
|
|
2147
2251
|
}
|
|
2148
2252
|
}
|
|
2149
2253
|
} catch (err) {
|
|
@@ -2547,6 +2651,39 @@ var NostrTransportProvider = class {
|
|
|
2547
2651
|
}
|
|
2548
2652
|
}
|
|
2549
2653
|
}
|
|
2654
|
+
/**
|
|
2655
|
+
* Create a NIP-17 gift wrap with a custom inner rumor kind.
|
|
2656
|
+
* Replicates the three-layer NIP-59 envelope (rumor → seal → gift wrap)
|
|
2657
|
+
* because NIP17.createGiftWrap hardcodes kind 14 for the inner rumor.
|
|
2658
|
+
*/
|
|
2659
|
+
createCustomKindGiftWrap(recipientPubkeyHex, content, rumorKind) {
|
|
2660
|
+
const senderPubkey = this.keyManager.getPublicKeyHex();
|
|
2661
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
2662
|
+
const rumorTags = [["p", recipientPubkeyHex]];
|
|
2663
|
+
const rumorSerialized = JSON.stringify([0, senderPubkey, now, rumorKind, rumorTags, content]);
|
|
2664
|
+
const rumorId = bytesToHex(sha256(new TextEncoder().encode(rumorSerialized)));
|
|
2665
|
+
const rumor = { id: rumorId, pubkey: senderPubkey, created_at: now, kind: rumorKind, tags: rumorTags, content };
|
|
2666
|
+
const recipientPubkeyBytes = hexToBytes(recipientPubkeyHex);
|
|
2667
|
+
const encryptedRumor = import_nostr_js_sdk.NIP44.encrypt(JSON.stringify(rumor), this.keyManager.getPrivateKey(), recipientPubkeyBytes);
|
|
2668
|
+
const sealTimestamp = now + Math.floor(Math.random() * 2 * TIMESTAMP_RANDOMIZATION) - TIMESTAMP_RANDOMIZATION;
|
|
2669
|
+
const seal = import_nostr_js_sdk.Event.create(this.keyManager, {
|
|
2670
|
+
kind: import_nostr_js_sdk.EventKinds.SEAL,
|
|
2671
|
+
tags: [],
|
|
2672
|
+
content: encryptedRumor,
|
|
2673
|
+
created_at: sealTimestamp
|
|
2674
|
+
});
|
|
2675
|
+
const ephemeralKeys = import_nostr_js_sdk.NostrKeyManager.generate();
|
|
2676
|
+
const encryptedSeal = import_nostr_js_sdk.NIP44.encrypt(JSON.stringify(seal.toJSON()), ephemeralKeys.getPrivateKey(), recipientPubkeyBytes);
|
|
2677
|
+
const wrapTimestamp = now + Math.floor(Math.random() * 2 * TIMESTAMP_RANDOMIZATION) - TIMESTAMP_RANDOMIZATION;
|
|
2678
|
+
const giftWrap = import_nostr_js_sdk.Event.create(ephemeralKeys, {
|
|
2679
|
+
kind: import_nostr_js_sdk.EventKinds.GIFT_WRAP,
|
|
2680
|
+
tags: [["p", recipientPubkeyHex]],
|
|
2681
|
+
content: encryptedSeal,
|
|
2682
|
+
created_at: wrapTimestamp
|
|
2683
|
+
});
|
|
2684
|
+
ephemeralKeys.clear();
|
|
2685
|
+
return giftWrap;
|
|
2686
|
+
}
|
|
2550
2687
|
log(...args) {
|
|
2551
2688
|
if (this.config.debug) {
|
|
2552
2689
|
console.log("[NostrTransportProvider]", ...args);
|
|
@@ -3123,7 +3260,7 @@ async function loadLibp2pModules() {
|
|
|
3123
3260
|
};
|
|
3124
3261
|
}
|
|
3125
3262
|
function deriveEd25519KeyMaterial(privateKeyHex, info = IPNS_HKDF_INFO) {
|
|
3126
|
-
const walletSecret =
|
|
3263
|
+
const walletSecret = hexToBytes2(privateKeyHex);
|
|
3127
3264
|
const infoBytes = new TextEncoder().encode(info);
|
|
3128
3265
|
return hkdf(sha256, walletSecret, void 0, infoBytes, 32);
|
|
3129
3266
|
}
|
|
@@ -5608,6 +5745,11 @@ function resolveGroupChatConfig(network, config) {
|
|
|
5608
5745
|
relays: config.relays ?? [...netConfig.groupRelays]
|
|
5609
5746
|
};
|
|
5610
5747
|
}
|
|
5748
|
+
function resolveMarketConfig(config) {
|
|
5749
|
+
if (!config) return void 0;
|
|
5750
|
+
if (config === true) return {};
|
|
5751
|
+
return { apiUrl: config.apiUrl, timeout: config.timeout };
|
|
5752
|
+
}
|
|
5611
5753
|
|
|
5612
5754
|
// impl/nodejs/index.ts
|
|
5613
5755
|
function createNodeProviders(config) {
|
|
@@ -5623,11 +5765,13 @@ function createNodeProviders(config) {
|
|
|
5623
5765
|
const ipfsSync = config?.tokenSync?.ipfs;
|
|
5624
5766
|
const ipfsTokenStorage = ipfsSync?.enabled ? createNodeIpfsStorageProvider(ipfsSync.config, storage) : void 0;
|
|
5625
5767
|
const groupChat = resolveGroupChatConfig(network, config?.groupChat);
|
|
5768
|
+
const market = resolveMarketConfig(config?.market);
|
|
5626
5769
|
const networkConfig = getNetworkConfig(network);
|
|
5627
5770
|
TokenRegistry.configure({ remoteUrl: networkConfig.tokenRegistryUrl, storage });
|
|
5628
5771
|
return {
|
|
5629
5772
|
storage,
|
|
5630
5773
|
groupChat,
|
|
5774
|
+
market,
|
|
5631
5775
|
tokenStorage: createFileTokenStorageProvider({
|
|
5632
5776
|
tokensDir: config?.tokensDir ?? "./sphere-tokens"
|
|
5633
5777
|
}),
|