tinyrelaycommit

Commit 8b51870933f8

browse files at this commit | history

1diff --git a/internal/webui/blossom-encryption.js b/internal/webui/blossom-encryption.js
2new file mode 100644
3index 0000000..0524813
4--- /dev/null
5+++ b/internal/webui/blossom-encryption.js
6@@ -0,0 +1,73 @@
7+// BUD-15 draft (June 2026), BUD-15: Client-side CHK encrypted blobs.
8+// https://raw.githubusercontent.com/mmalmi/blossom/codex/bud-15-chk-encryption/buds/15.md
9+// Keys are client-only values. Callers must not include k in requests to a server.
10+(() => {
11+ "use strict";
12+
13+ const encoder = new TextEncoder();
14+ const zeroNonce = new Uint8Array(12);
15+ const salt = encoder.encode("hashtree-chk");
16+ const info = encoder.encode("encryption-key");
17+
18+ const hex = bytes => Array.from(bytes, byte => byte.toString(16).padStart(2, "0")).join("");
19+ const bytes = value => {
20+ if (value instanceof Uint8Array) return value;
21+ if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
22+ throw new TypeError("expected Uint8Array");
23+ };
24+ const fromHex = value => {
25+ if (typeof value !== "string" || !/^[0-9a-f]{64}$/.test(value)) throw new Error("expected a 64-character lowercase hex key");
26+ const result = new Uint8Array(32);
27+ for (let index = 0; index < result.length; index++) result[index] = parseInt(value.slice(index * 2, index * 2 + 2), 16);
28+ return result;
29+ };
30+ const equal = (left, right) => left.length === right.length && left.every((value, index) => value === right[index]);
31+ const digest = async value => new Uint8Array(await crypto.subtle.digest("SHA-256", bytes(value)));
32+ const aesKey = async key => {
33+ const material = await crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveKey"]);
34+ return crypto.subtle.deriveKey({name: "HKDF", hash: "SHA-256", salt, info}, material,
35+ {name: "AES-GCM", length: 256}, false, ["encrypt", "decrypt"]);
36+ };
37+
38+ const encryptCHK = async plaintext => {
39+ const input = bytes(plaintext);
40+ const key = await digest(input);
41+ const encrypted = new Uint8Array(await crypto.subtle.encrypt({name: "AES-GCM", iv: zeroNonce}, await aesKey(key), input));
42+ return {ciphertext: encrypted, key: hex(key), hash: hex(await digest(encrypted))};
43+ };
44+
45+ const decryptCHK = async (ciphertext, key, hash) => {
46+ const input = bytes(ciphertext);
47+ const chkKey = fromHex(key);
48+ if (typeof hash !== "string" || !/^[0-9a-f]{64}$/.test(hash)) throw new Error("expected a 64-character lowercase blob hash");
49+ if (hex(await digest(input)) !== hash) throw new Error("ciphertext hash mismatch");
50+ let plain;
51+ try {
52+ plain = new Uint8Array(await crypto.subtle.decrypt({name: "AES-GCM", iv: zeroNonce}, await aesKey(chkKey), input));
53+ } catch {
54+ throw new Error("CHK decryption failed");
55+ }
56+ if (!equal(await digest(plain), chkKey)) throw new Error("plaintext hash mismatch");
57+ return plain;
58+ };
59+
60+ const createURI = (hash, extension, key) => {
61+ if (typeof hash !== "string" || !/^[0-9a-f]{64}$/.test(hash)) throw new Error("expected a 64-character lowercase blob hash");
62+ const path = "blossom:" + hash + (extension ? "." + String(extension).replace(/^\.+/, "") : "");
63+ fromHex(key);
64+ const params = new URLSearchParams({enc: "chk-v1", k: key});
65+ return path + "?" + params;
66+ };
67+
68+ const parseURI = value => {
69+ if (typeof value !== "string" || !value.startsWith("blossom:")) throw new Error("expected a Blossom URI");
70+ const parsed = new URL(value.slice("blossom:".length), "https://blossom.invalid");
71+ const match = parsed.pathname.match(/^\/([0-9a-f]{64})(?:\.([A-Za-z0-9]+))?$/);
72+ if (!match || parsed.searchParams.get("enc") !== "chk-v1") throw new Error("invalid CHK Blossom URI");
73+ const key = parsed.searchParams.get("k");
74+ fromHex(key);
75+ return {hash: match[1], extension: match[2] || "", key};
76+ };
77+
78+ globalThis.TinyBlossomEncryption = Object.freeze({encryptCHK, decryptCHK, createURI, parseURI});
79+})();
80diff --git a/internal/webui/blossom-manifests.js b/internal/webui/blossom-manifests.js
81new file mode 100644
82index 0000000..3390f32
83--- /dev/null
84+++ b/internal/webui/blossom-manifests.js
85@@ -0,0 +1,466 @@
86+(() => {
87+ (() => {
88+ "use strict";
89+ const CHUNK_SIZE = 2 * 1024 * 1024;
90+ const MAX_LINKS = 174;
91+ const MAX_DEPTH = 64;
92+ const MAX_MANIFEST_BYTES = 16 * 1024 * 1024;
93+ const te = new TextEncoder(), td = new TextDecoder("utf-8", { fatal: true });
94+ const asBytes = (v) => v instanceof Uint8Array ? v : ArrayBuffer.isView(v) ? new Uint8Array(v.buffer, v.byteOffset, v.byteLength) : (() => {
95+ throw new TypeError("expected bytes");
96+ })();
97+ const hashBytes = (h) => {
98+ if (typeof h !== "string" || !/^[0-9a-f]{64}$/.test(h)) throw new Error("expected lowercase SHA-256 hash");
99+ return Uint8Array.from(h.match(/../g), (x) => parseInt(x, 16));
100+ };
101+ const keyBytes = (k) => {
102+ if (k === void 0) return;
103+ const b = asBytes(k);
104+ if (b.length !== 32) throw new Error("manifest keys must be 32 bytes");
105+ return b;
106+ };
107+ const wellFormed = (value) => {
108+ for (let i = 0; i < value.length; i++) {
109+ const c = value.charCodeAt(i);
110+ if (c >= 55296 && c <= 56319) {
111+ if (++i >= value.length || value.charCodeAt(i) < 56320 || value.charCodeAt(i) > 57343) return false;
112+ } else if (c >= 56320 && c <= 57343) return false;
113+ }
114+ return true;
115+ };
116+ const nameOK = (n) => typeof n === "string" && n.length > 0 && n !== "." && n !== ".." && wellFormed(n) && !n.includes("/") && !n.includes("\0") && te.encode(n).length <= 1024;
117+ const int = (n) => Number.isSafeInteger(n) && n >= 0;
118+ const utf8cmp = (a, b) => {
119+ const x = te.encode(a), y = te.encode(b);
120+ for (let i = 0; i < Math.min(x.length, y.length); i++) if (x[i] !== y[i]) return x[i] - y[i];
121+ return x.length - y.length;
122+ };
123+ class Writer {
124+ constructor() {
125+ this.a = [];
126+ }
127+ push(...x) {
128+ this.a.push(...x);
129+ }
130+ u8(n) {
131+ this.a.push(n & 255);
132+ }
133+ bytes() {
134+ return Uint8Array.from(this.a);
135+ }
136+ }
137+ const putInt = (w, n) => {
138+ if (!Number.isSafeInteger(n)) throw new Error("manifest integers must be safe integers");
139+ if (n >= 0) {
140+ if (n < 128) w.u8(n);
141+ else if (n < 256) w.push(204, n);
142+ else if (n < 65536) w.push(205, n >> 8, n);
143+ else if (n < 4294967296) w.push(206, n >>> 24, n >>> 16, n >>> 8, n);
144+ else {
145+ w.u8(207);
146+ let x = BigInt(n);
147+ for (let i = 7; i >= 0; i--) w.u8(Number(x >> BigInt(i * 8) & 255n));
148+ }
149+ } else if (n >= -32) w.u8(256 + n);
150+ else if (n >= -128) w.push(208, n & 255);
151+ else if (n >= -32768) w.push(209, n >> 8 & 255, n & 255);
152+ else if (n >= -2147483648) w.push(210, n >>> 24, n >>> 16, n >>> 8, n);
153+ else {
154+ w.u8(211);
155+ let x = BigInt.asUintN(64, BigInt(n));
156+ for (let i = 7; i >= 0; i--) w.u8(Number(x >> BigInt(i * 8) & 255n));
157+ }
158+ };
159+ const put = (w, v) => {
160+ if (v === null) return w.u8(192);
161+ if (v === false) return w.u8(194);
162+ if (v === true) return w.u8(195);
163+ if (typeof v === "number") {
164+ if (Number.isInteger(v)) return putInt(w, v);
165+ if (!Number.isFinite(v)) throw Error("metadata number must be finite");
166+ w.u8(203);
167+ const b = new DataView(new ArrayBuffer(8));
168+ b.setFloat64(0, v);
169+ for (let i = 0; i < 8; i++) w.u8(b.getUint8(i));
170+ return;
171+ }
172+ if (typeof v === "string") {
173+ const b = te.encode(v);
174+ if (b.length < 32) w.u8(160 | b.length);
175+ else if (b.length < 256) w.push(217, b.length);
176+ else if (b.length < 65536) w.push(218, b.length >> 8, b.length);
177+ else throw new Error("string too large");
178+ w.push(...b);
179+ return;
180+ }
181+ if (v instanceof Uint8Array) {
182+ if (v.length < 256) w.push(196, v.length);
183+ else if (v.length < 65536) w.push(197, v.length >> 8, v.length);
184+ else throw new Error("binary value too large");
185+ w.push(...v);
186+ return;
187+ }
188+ if (Array.isArray(v)) {
189+ if (v.length < 16) w.u8(144 | v.length);
190+ else if (v.length < 65536) w.push(220, v.length >> 8, v.length);
191+ else throw new Error("array too large");
192+ v.forEach((x) => put(w, x));
193+ return;
194+ }
195+ if (v && typeof v === "object") {
196+ const keys = Object.keys(v).sort(utf8cmp);
197+ if (keys.length < 16) w.u8(128 | keys.length);
198+ else if (keys.length < 65536) w.push(222, keys.length >> 8, keys.length);
199+ else throw new Error("map too large");
200+ keys.forEach((k) => {
201+ put(w, k);
202+ put(w, v[k]);
203+ });
204+ return;
205+ }
206+ throw new Error("unsupported manifest value");
207+ };
208+ class Reader {
209+ constructor(b) {
210+ this.b = asBytes(b);
211+ this.i = 0;
212+ }
213+ need(n) {
214+ if (this.i + n > this.b.length) throw new Error("truncated MessagePack");
215+ }
216+ u8() {
217+ this.need(1);
218+ return this.b[this.i++];
219+ }
220+ n(len) {
221+ this.need(len);
222+ const x = this.b.slice(this.i, this.i + len);
223+ this.i += len;
224+ return x;
225+ }
226+ }
227+ const readMap = (r, n, depth) => {
228+ const o = /* @__PURE__ */ Object.create(null);
229+ for (let i = 0; i < n; i++) {
230+ const k = get(r, depth + 1);
231+ if (typeof k !== "string" || Object.prototype.hasOwnProperty.call(o, k)) throw Error("invalid map key");
232+ o[k] = get(r, depth + 1);
233+ }
234+ return o;
235+ };
236+ const get = (r, depth = 0) => {
237+ if (depth > MAX_DEPTH) throw Error("MessagePack recursion limit exceeded");
238+ const t = r.u8();
239+ if (t <= 127) return t;
240+ if (t >= 224) return t - 256;
241+ if ((t & 224) === 160) return td.decode(r.n(t & 31));
242+ if ((t & 240) === 144) return Array.from({ length: t & 15 }, () => get(r, depth + 1));
243+ if ((t & 240) === 128) return readMap(r, t & 15, depth);
244+ if (t === 192) return null;
245+ if (t === 194) return false;
246+ if (t === 195) return true;
247+ let n;
248+ if (t === 204) n = r.u8();
249+ else if (t === 205) n = r.u8() << 8 | r.u8();
250+ else if (t === 206) n = r.u8() * 16777216 + (r.u8() << 16) + (r.u8() << 8) + r.u8();
251+ else if (t === 207) {
252+ let x = 0n;
253+ for (let i = 0; i < 8; i++) x = x << 8n | BigInt(r.u8());
254+ if (x > BigInt(Number.MAX_SAFE_INTEGER)) throw Error("integer exceeds safe range");
255+ n = Number(x);
256+ } else if (t === 208) n = r.u8() << 24 >> 24;
257+ else if (t === 209) {
258+ n = r.u8() << 8 | r.u8();
259+ if (n & 32768) n -= 65536;
260+ } else if (t === 210) {
261+ n = r.u8() * 16777216 + (r.u8() << 16) + (r.u8() << 8) + r.u8();
262+ if (n >= 2147483648) n -= 4294967296;
263+ } else if (t === 211) {
264+ let x = 0n;
265+ for (let i = 0; i < 8; i++) x = x << 8n | BigInt(r.u8());
266+ if (x & 0x8000000000000000n) x -= 0x10000000000000000n;
267+ if (x > BigInt(Number.MAX_SAFE_INTEGER) || x < BigInt(Number.MIN_SAFE_INTEGER)) throw Error("integer exceeds safe range");
268+ n = Number(x);
269+ } else if (t === 202) {
270+ const b = new ArrayBuffer(4), d = new DataView(b);
271+ for (let i = 0; i < 4; i++) d.setUint8(i, r.u8());
272+ n = d.getFloat32(0);
273+ } else if (t === 203) {
274+ const b = new ArrayBuffer(8), d = new DataView(b);
275+ for (let i = 0; i < 8; i++) d.setUint8(i, r.u8());
276+ n = d.getFloat64(0);
277+ } else if (t === 217) n = td.decode(r.n(r.u8()));
278+ else if (t === 218) n = td.decode(r.n(r.u8() << 8 | r.u8()));
279+ else if (t === 196) n = r.n(r.u8());
280+ else if (t === 197) n = r.n(r.u8() << 8 | r.u8());
281+ else if (t === 220) {
282+ n = r.u8() << 8 | r.u8();
283+ return Array.from({ length: n }, () => get(r, depth + 1));
284+ } else if (t === 222) {
285+ n = r.u8() << 8 | r.u8();
286+ return readMap(r, n, depth);
287+ } else throw Error("unsupported MessagePack type");
288+ return n;
289+ };
290+ const validateMeta = (m, depth = 0) => {
291+ if (m === void 0) return;
292+ if (depth > MAX_DEPTH || !m || Array.isArray(m) || typeof m !== "object" || m instanceof Uint8Array) throw Error("metadata must be a JSON map");
293+ const keys = Object.keys(m);
294+ if (keys.length > 64) throw Error("too many metadata keys");
295+ for (const [k, v] of Object.entries(m)) {
296+ if (typeof k !== "string" || te.encode(k).length > 256) throw Error("invalid metadata key");
297+ if (v === void 0 || typeof v === "bigint" || typeof v === "function" || typeof v === "symbol" || typeof v === "number" && !Number.isFinite(v)) throw Error("metadata is not JSON-compatible");
298+ if (v && typeof v === "object") {
299+ if (Array.isArray(v)) {
300+ if (v.length > 256) throw Error("metadata array too large");
301+ v.forEach((x) => validateMeta({ x }, depth + 1));
302+ } else validateMeta(v, depth + 1);
303+ }
304+ }
305+ };
306+ const validateLink = (x, nodeType) => {
307+ if (!x || typeof x !== "object" || Array.isArray(x)) throw Error("invalid manifest link");
308+ if (Object.keys(x).some((k) => !["h", "k", "m", "n", "s", "t"].includes(k))) throw Error("unknown manifest link field");
309+ if (!(x.h instanceof Uint8Array) || x.h.length !== 32) throw Error("link hash must be 32 bytes");
310+ if (x.k !== void 0) keyBytes(x.k);
311+ if (x.m !== void 0) validateMeta(x.m);
312+ if (!int(x.s)) throw Error("invalid link size");
313+ if (!int(x.t) || x.t < 0 || x.t > 3) throw Error("unsupported link type");
314+ if (nodeType === 1 && x.t !== 0 && x.t !== 1) throw Error("invalid file link type");
315+ if (nodeType === 1 && x.n !== void 0) throw Error("file links cannot have names");
316+ if (nodeType === 3 && x.n !== void 0) throw Error("fanout links cannot have names");
317+ if (nodeType === 3 && x.t !== 2 && x.t !== 3) throw Error("invalid fanout child type");
318+ if (nodeType === 2 && !nameOK(x.n)) throw Error("invalid directory entry name");
319+ };
320+ const validateNode = (node, depth = 0) => {
321+ if (depth > MAX_DEPTH) throw Error("manifest recursion limit exceeded");
322+ if (!node || typeof node !== "object" || Array.isArray(node) || !Array.isArray(node.l) || !int(node.t) || ![1, 2, 3].includes(node.t) || Object.keys(node).some((k) => k !== "l" && k !== "t")) throw Error("invalid manifest node");
323+ if (node.l.length > MAX_LINKS) throw Error("too many manifest links");
324+ const seen = /* @__PURE__ */ new Set(), links = node.l;
325+ for (const x of links) {
326+ validateLink(x, node.t);
327+ if (node.t === 2) {
328+ if (seen.has(x.n)) throw Error("duplicate directory entry");
329+ seen.add(x.n);
330+ }
331+ if (node.t === 3) {
332+ if (!x.m || !int(x.m.count) || x.m.count < 1 || !nameOK(x.m.first) || !nameOK(x.m.last) || utf8cmp(x.m.first, x.m.last) > 0) throw Error("invalid fanout bounds");
333+ }
334+ }
335+ if (node.t === 2 && links.some((x, i) => i && utf8cmp(links[i - 1].n, x.n) >= 0)) throw Error("directory links are not canonical");
336+ return node;
337+ };
338+ const encodeManifest = (node) => {
339+ validateNode(node);
340+ const w = new Writer();
341+ w.u8(130);
342+ put(w, "l");
343+ if (node.l.length < 16) w.u8(144 | node.l.length);
344+ else w.push(220, node.l.length >> 8, node.l.length);
345+ for (const x of node.l) {
346+ const fields = ["h", ...x.k !== void 0 ? ["k"] : [], ...x.m !== void 0 ? ["m"] : [], ...x.n !== void 0 ? ["n"] : [], "s", "t"];
347+ if (fields.length < 16) w.u8(128 | fields.length);
348+ else w.push(222, fields.length >> 8, fields.length);
349+ for (const k of fields) {
350+ put(w, k);
351+ put(w, k === "h" || k === "k" ? asBytes(x[k]) : x[k]);
352+ }
353+ }
354+ put(w, "t");
355+ put(w, node.t);
356+ const out = w.bytes();
357+ if (out.length > MAX_MANIFEST_BYTES) throw Error("manifest too large");
358+ return out;
359+ };
360+ const decodeManifest = (bytes, options = {}) => {
361+ const b = asBytes(bytes);
362+ if (b.length > MAX_MANIFEST_BYTES) throw Error("manifest too large");
363+ const r = new Reader(b), node = get(r);
364+ if (r.i !== b.length) throw Error("trailing MessagePack data");
365+ validateNode(node);
366+ if (node.t === 3) for (const x of node.l) {
367+ if (x.m.count > Number(options.maxEntries || 1e9)) throw Error("fanout count limit exceeded");
368+ }
369+ return node;
370+ };
371+ const sha256 = async (b) => new Uint8Array(await crypto.subtle.digest("SHA-256", asBytes(b)));
372+ const hex = (b) => Array.from(asBytes(b), (x) => x.toString(16).padStart(2, "0")).join("");
373+ const manifestHash = async (node) => hex(await sha256(encodeManifest(node)));
374+ const leaf = (hash, size, key) => {
375+ const x = { h: hashBytes(hash), s: size, t: 0 };
376+ if (key !== void 0) x.k = keyBytes(key);
377+ return x;
378+ };
379+ const storeNode = async (node, options, manifests) => {
380+ const bytes = encodeManifest(node), computed = hex(await sha256(bytes));
381+ let result = { hash: computed };
382+ if (options.store) {
383+ const stored = await options.store({ hash: computed, bytes, node });
384+ if (stored) {
385+ if (typeof stored === "string") result.hash = stored;
386+ else result = { ...result, ...stored };
387+ }
388+ }
389+ if (!/^[0-9a-f]{64}$/.test(result.hash)) throw Error("store returned invalid manifest hash");
390+ if (result.key !== void 0) keyBytes(result.key);
391+ manifests.push({ hash: result.hash, bytes, node, key: result.key });
392+ return result;
393+ };
394+ const buildFile = async (chunks, options = {}) => {
395+ const max = options.maxLinks ?? MAX_LINKS;
396+ if (!Number.isInteger(max) || max < 2 || max > MAX_LINKS) throw Error("invalid maxLinks");
397+ const leaves = chunks.map((c) => typeof c === "string" ? leaf(c, options.chunkSize || 0) : leaf(c.hash, c.size, c.key));
398+ if (leaves.some((x) => x.s < 0 || x.s > CHUNK_SIZE)) throw Error("invalid chunk size");
399+ const manifests = [];
400+ let level = leaves;
401+ while (level.length > max) {
402+ const next = [];
403+ for (let i = 0; i < level.length; i += max) {
404+ const group = level.slice(i, i + max), child = { l: group, t: 1 }, stored = await storeNode(child, options, manifests);
405+ next.push({ h: hashBytes(stored.hash), ...stored.key ? { k: keyBytes(stored.key) } : {}, s: group.reduce((n, x) => n + x.s, 0), t: 1 });
406+ }
407+ level = next;
408+ }
409+ const root = { l: level, t: 1 };
410+ await storeNode(root, options, manifests);
411+ return options.returnDetails ? { root, manifests } : root;
412+ };
413+ const buildDirectory = async (entries, options = {}) => {
414+ if (!Array.isArray(entries)) throw Error("entries must be an array");
415+ const max = options.maxLinks ?? MAX_LINKS;
416+ if (!Number.isInteger(max) || max < 2 || max > MAX_LINKS) throw Error("invalid maxLinks");
417+ const sorted = entries.map((e) => {
418+ const x = { h: hashBytes(e.hash), n: e.name, s: e.size || 0, t: e.type || 0 };
419+ if (e.key !== void 0) x.k = keyBytes(e.key);
420+ if (e.metadata !== void 0) x.m = e.metadata;
421+ return x;
422+ }).sort((a, b) => utf8cmp(a.n, b.n));
423+ for (let i = 1; i < sorted.length; i++) if (sorted[i - 1].n === sorted[i].n) throw Error("duplicate directory entry");
424+ const manifests = [];
425+ if (sorted.length <= max) {
426+ const root2 = { l: sorted, t: 2 };
427+ await storeNode(root2, options, manifests);
428+ return options.returnDetails ? { root: root2, manifests } : root2;
429+ }
430+ let level = [];
431+ for (let i = 0; i < sorted.length; i += max) {
432+ const l = sorted.slice(i, i + max), child = { l, t: 2 }, stored = await storeNode(child, options, manifests);
433+ level.push({ h: hashBytes(stored.hash), ...stored.key ? { k: keyBytes(stored.key) } : {}, m: { count: l.length, first: l[0].n, last: l[l.length - 1].n }, s: l.reduce((n, x) => n + x.s, 0), t: 2 });
434+ }
435+ while (level.length > max) {
436+ const next = [];
437+ for (let i = 0; i < level.length; i += max) {
438+ const l = level.slice(i, i + max), child = { l, t: 3 }, stored = await storeNode(child, options, manifests);
439+ next.push({ h: hashBytes(stored.hash), ...stored.key ? { k: keyBytes(stored.key) } : {}, m: { count: l.reduce((n, x) => n + x.m.count, 0), first: l[0].m.first, last: l[l.length - 1].m.last }, s: l.reduce((n, x) => n + x.s, 0), t: 3 });
440+ }
441+ level = next;
442+ }
443+ const root = { l: level, t: 3 };
444+ await storeNode(root, options, manifests);
445+ return options.returnDetails ? { root, manifests } : root;
446+ };
447+ const flattenDirectory = (node, out = []) => {
448+ validateNode(node);
449+ if (node.t === 2) {
450+ out.push(...node.l);
451+ return out;
452+ }
453+ if (node.t !== 3) throw Error("not a directory");
454+ for (const x of node.l) if (x.child) flattenDirectory(x.child, out);
455+ return out;
456+ };
457+ const resolveDirectory = async (root, fetchNode, options = {}) => {
458+ if (typeof fetchNode !== "function") throw Error("fetchNode is required");
459+ const maxDepth = options.maxDepth ?? MAX_DEPTH, maxEntries = options.maxEntries ?? 1e5, maxManifests = options.maxManifests ?? 1e4, maxBytes = options.maxBytes ?? 64 * 1024 * 1024;
460+ if ([maxDepth, maxEntries, maxManifests, maxBytes].some(value => !Number.isSafeInteger(value) || value < 0)) throw Error("invalid directory limits");
461+ let count = 0, manifestCount = 0, fetched = 0;
462+ const active = /* @__PURE__ */ new Set();
463+ const walk = async (node, depth) => {
464+ if (depth > maxDepth) throw Error("directory recursion limit exceeded");
465+ if (++manifestCount > maxManifests) throw Error("manifest count limit exceeded");
466+ validateNode(node);
467+ if (node.t === 2) {
468+ count += node.l.length;
469+ if (count > maxEntries) throw Error("directory entry limit exceeded");
470+ return node.l.slice();
471+ }
472+ if (node.t !== 3) throw Error("not a directory");
473+ const result = [];
474+ let previous = "";
475+ for (const link of node.l) {
476+ if (previous && utf8cmp(previous, link.m.first) >= 0) throw Error("fanout bounds are not ordered");
477+ previous = link.m.last;
478+ const linkHash = hex(link.h);
479+ if (active.has(linkHash)) throw Error("manifest cycle detected");
480+ active.add(linkHash);
481+ let raw = asBytes(await fetchNode(linkHash, link));
482+ fetched += raw.length;
483+ if (fetched > maxBytes) throw Error("directory byte limit exceeded");
484+ if (hex(await sha256(raw)) !== linkHash) throw Error("manifest hash mismatch");
485+ if (link.k) {
486+ if (typeof options.decrypt !== "function") throw Error("encrypted manifest requires decrypt callback");
487+ raw = asBytes(await options.decrypt(raw, link));
488+ }
489+ const child = decodeManifest(raw);
490+ if (child.t !== link.t) throw Error("fanout child type mismatch");
491+ const links = await walk(child, depth + 1);
492+ active.delete(linkHash);
493+ if (links.length !== link.m.count || links[0]?.n !== link.m.first || links.at(-1)?.n !== link.m.last) throw Error("fanout bounds mismatch");
494+ result.push(...links);
495+ }
496+ for (let i = 1; i < result.length; i++) if (utf8cmp(result[i - 1].n, result[i].n) >= 0) throw Error("duplicate or unordered directory entry");
497+ return result;
498+ };
499+ return walk(root, 0);
500+ };
501+ const readFile = async (root, fetchBlob, options = {}) => {
502+ if (typeof fetchBlob !== "function") throw Error("fetchBlob is required");
503+ const maxDepth = options.maxDepth ?? MAX_DEPTH, maxBytes = options.maxBytes ?? 512 * 1024 * 1024, maxManifests = options.maxManifests ?? 1e4;
504+ const maxFetchedBytes = options.maxFetchedBytes ?? maxBytes + 16 * 1024 * 1024;
505+ if ([maxDepth, maxBytes, maxManifests, maxFetchedBytes].some(value => !Number.isSafeInteger(value) || value < 0)) throw Error("invalid file limits");
506+ let used = 0, fetched = 0, manifests = 0;
507+ const active = /* @__PURE__ */ new Set(), parts = [];
508+ const readNode = async (node, depth) => {
509+ if (depth > maxDepth) throw Error("file recursion limit exceeded");
510+ validateNode(node);
511+ if (node.t !== 1) throw Error("not a file manifest");
512+ if (++manifests > maxManifests) throw Error("manifest count limit exceeded");
513+ for (const link of node.l) {
514+ const hash = hex(link.h);
515+ if (active.has(hash)) throw Error("manifest cycle detected");
516+ active.add(hash);
517+ let raw = asBytes(await fetchBlob(hash, link));
518+ fetched += raw.length;
519+ if (fetched > maxFetchedBytes) throw Error("file fetched byte limit exceeded");
520+ if (hex(await sha256(raw)) !== hash) throw Error("blob hash mismatch");
521+ if (link.t === 1) {
522+ if (typeof options.decrypt !== "function" && link.k) throw Error("encrypted manifest requires decrypt callback");
523+ if (link.k) raw = asBytes(await options.decrypt(raw, link));
524+ const child = decodeManifest(raw);
525+ if (child.t !== 1) throw Error("file child type mismatch");
526+ const before = used;
527+ await readNode(child, depth + 1);
528+ if (used - before !== link.s) throw Error("file manifest size mismatch");
529+ } else {
530+ if (link.k && typeof options.decrypt !== "function") throw Error("encrypted chunk requires decrypt callback");
531+ const data = link.k ? asBytes(await options.decrypt(raw, link)) : raw;
532+ if (data.length !== link.s) throw Error("file chunk size mismatch");
533+ used += data.length;
534+ if (used > maxBytes) throw Error("file byte limit exceeded");
535+ parts.push(data);
536+ }
537+ active.delete(hash);
538+ }
539+ };
540+ await readNode(root, 0);
541+ const out = new Uint8Array(used);
542+ let at = 0;
543+ for (const p of parts) {
544+ out.set(p, at);
545+ at += p.length;
546+ }
547+ return out;
548+ };
549+ globalThis.TinyBlossomManifests = Object.freeze({ CHUNK_SIZE, MAX_LINKS, encodeManifest, decodeManifest, encode: encodeManifest, decode: decodeManifest, manifestHash, buildFile, buildDirectory, flattenDirectory, resolveDirectory, readFile, sha256, hex });
550+ })();
551+})();
552diff --git a/internal/webui/blossom-upload.js b/internal/webui/blossom-upload.js
553new file mode 100644
554index 0000000..a5b8acb
555--- /dev/null
556+++ b/internal/webui/blossom-upload.js
557@@ -0,0 +1,160 @@
558+// BUD-14 draft multipart uploads.
559+// https://raw.githubusercontent.com/hzrd149/blossom/multi-part-uploads-2/buds/14.md
560+// Upload state is deliberately held by the caller. It does not survive a page
561+// navigation because BUD-14 has no offset discovery protocol.
562+(() => {
563+ "use strict";
564+
565+ const sha256 = async bytes => new Uint8Array(await crypto.subtle.digest("SHA-256", bytes));
566+ const hex = bytes => Array.from(bytes, value => value.toString(16).padStart(2, "0")).join("");
567+ const asBytes = async value => {
568+ if (value instanceof Uint8Array) return value;
569+ if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
570+ if (value instanceof ArrayBuffer) return new Uint8Array(value);
571+ if (value instanceof Blob) return new Uint8Array(await value.arrayBuffer());
572+ throw new TypeError("expected Blob, ArrayBuffer, or Uint8Array");
573+ };
574+ const responseBody = async response => {
575+ try { return await response.json(); } catch { return null; }
576+ };
577+ const abortError = () => { const error = new Error("upload canceled"); error.name = "AbortError"; return error; };
578+ const verifyDescriptor = (descriptor, hash, size) => {
579+ if (!descriptor || typeof descriptor !== "object" || descriptor.sha256 !== hash || descriptor.size !== size) throw new Error("invalid Blossom upload descriptor");
580+ return descriptor;
581+ };
582+
583+ const uploadTask = async (source, options = {}, controller) => {
584+ const bytes = await asBytes(source);
585+ const hash = options.hash || hex(await sha256(bytes));
586+ if (!/^[0-9a-f]{64}$/.test(hash)) throw new Error("expected a lowercase SHA-256 hash");
587+ if (options.hash && hash !== hex(await sha256(bytes))) throw new Error("upload hash mismatch");
588+ const type = options.type || source.type || "application/octet-stream";
589+ const base = options.url || options.endpoint;
590+ if (typeof base !== "string" || base === "") throw new Error("upload URL is required");
591+ let parsed;
592+ try { parsed = new URL(base, globalThis.location?.href || "https://blossom.invalid"); } catch { throw new Error("invalid upload URL"); }
593+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new Error("upload URL must use HTTP or HTTPS");
594+ if (parsed.username || parsed.password || parsed.hash || parsed.search) throw new Error("upload URL must not contain credentials, query, or fragment");
595+ const extension = options.extension ? String(options.extension).replace(/^\.+/, "") : "";
596+ if (extension && !/^[a-z0-9]{1,8}$/.test(extension)) throw new Error("invalid file extension");
597+ const path = parsed.pathname;
598+ const target = new RegExp("/" + hash + "(?:\\.[a-z0-9]{1,8})?/?$").test(path) ? base : base.replace(/\/$/, "") + "/" + hash + (extension ? "." + extension : "");
599+ const url = target;
600+ const fetcher = options.fetch || globalThis.fetch;
601+ if (typeof fetcher !== "function") throw new Error("fetch is unavailable");
602+ const chunkSize = Number.isSafeInteger(options.chunkSize) && options.chunkSize > 0 ? options.chunkSize : 5 * 1024 * 1024;
603+ const timeoutMs = Number.isSafeInteger(options.timeoutMs) && options.timeoutMs > 0 ? options.timeoutMs : 30000;
604+ const retries = Number.isSafeInteger(options.retries) && options.retries >= 0 ? options.retries : 0;
605+ const state = options.state instanceof Map ? options.state : new Map();
606+ const notify = (offset, length, status) => options.onState?.({offset, length, status, state});
607+ const progress = sent => options.onProgress?.({sent, total: bytes.byteLength, fraction: bytes.byteLength ? sent / bytes.byteLength : 1});
608+ const request = async (method, body, headers, authBody = body) => {
609+ if (controller.signal.aborted) throw abortError();
610+ const requestController = new AbortController();
611+ let timer, rejectCanceled;
612+ const cancel = () => { requestController.abort(); rejectCanceled?.(abortError()); };
613+ controller.signal.addEventListener("abort", cancel, {once: true});
614+ try {
615+ return await Promise.race([
616+ (async () => {
617+ const requestHeaders = {...headers};
618+ if (options.authorize && method !== "OPTIONS") {
619+ const value = await options.authorize(url, method, authBody, {hash, type});
620+ if (typeof value === "string") requestHeaders.authorization = value;
621+ else if (value && typeof value === "object") Object.assign(requestHeaders, value);
622+ }
623+ if (requestController.signal.aborted) throw abortError();
624+ const response = await fetcher(url, {method, headers: requestHeaders, body: method === "OPTIONS" ? undefined : body, signal: requestController.signal});
625+ // Keep the request deadline and cancellation active until the
626+ // descriptor body has arrived, not only until headers arrive.
627+ const descriptor = response.status === 200 || response.status === 201 ? await responseBody(response) : null;
628+ if (!descriptor) await response.body?.cancel?.();
629+ return {status: response.status, ok: response.ok, headers: response.headers, json: async () => descriptor};
630+ })(),
631+ new Promise((_, reject) => {
632+ timer = setTimeout(() => { requestController.abort(); reject(Error("upload request timed out")); }, timeoutMs);
633+ }),
634+ new Promise((_, reject) => { rejectCanceled = reject; })
635+ ]);
636+ } finally {
637+ clearTimeout(timer);
638+ controller.signal.removeEventListener("abort", cancel);
639+ requestController.abort();
640+ }
641+ };
642+ const retry = async (action, offset, length) => {
643+ let attempt = 0;
644+ while (true) {
645+ if (controller.signal.aborted) throw abortError();
646+ try {
647+ const result = await action();
648+ if (!result.ok && result.status >= 500 && attempt++ < retries) { notify(offset, length, "retrying"); continue; }
649+ return result;
650+ } catch (error) {
651+ if (controller.signal.aborted) throw abortError();
652+ if (attempt++ >= retries) throw error;
653+ notify(offset, length, "retrying");
654+ }
655+ }
656+ };
657+
658+ let supportsPatch = options.probe === false;
659+ if (options.probe !== false) {
660+ try {
661+ const response = await request("OPTIONS", null, {});
662+ supportsPatch = /(?:^|,|\s)PATCH(?:,|\s|$)/i.test(response.headers?.get?.("allow") || "");
663+ } catch { supportsPatch = false; }
664+ }
665+ if (!supportsPatch) {
666+ const response = await retry(() => request("PUT", bytes, {"content-type": type}), 0, bytes.byteLength);
667+ if (!response.ok) throw new Error("Blossom upload failed: " + response.status);
668+ return {hash, descriptor: verifyDescriptor(await responseBody(response), hash, bytes.byteLength), state};
669+ }
670+
671+ const metadata = state.meta;
672+ if (!metadata || metadata.hash !== hash || metadata.size !== bytes.byteLength || metadata.chunkSize !== chunkSize || metadata.url !== url || metadata.type !== type || Date.now() - (metadata.lastAcceptedAt || 0) >= 60000) {
673+ state.clear();
674+ state.meta = {hash, size: bytes.byteLength, chunkSize, url, type, lastAcceptedAt: 0};
675+ }
676+ let sent = 0;
677+ let replayed = false;
678+ while (true) {
679+ for (let offset = 0; offset < bytes.byteLength || (bytes.byteLength === 0 && offset === 0); offset += chunkSize) {
680+ const end = Math.min(offset + chunkSize, bytes.byteLength);
681+ const chunk = bytes.slice(offset, end);
682+ const length = chunk.byteLength;
683+ const prior = state.get(offset);
684+ if (!replayed && prior?.status === 204 && Date.now() - (state.meta.lastAcceptedAt || 0) < 60000) { sent = end; progress(sent); continue; }
685+ const result = await retry(() => request("PATCH", chunk, {
686+ "upload-type": type,
687+ "upload-length": String(bytes.byteLength),
688+ "upload-offset": String(offset),
689+ "content-type": "application/octet-stream"
690+ }, options.authorizationMode === "final-hash" ? bytes : chunk), offset, length);
691+ if (![200, 201, 204].includes(result.status)) throw new Error("Blossom chunk upload failed: " + result.status);
692+ state.set(offset, {offset, length, status: result.status});
693+ state.meta.lastAcceptedAt = Date.now();
694+ sent = end;
695+ notify(offset, length, result.status === 204 ? "uploaded" : "complete");
696+ progress(sent);
697+ if (result.status !== 204) return {hash, descriptor: verifyDescriptor(await responseBody(result), hash, bytes.byteLength), state};
698+ if (bytes.byteLength === 0) break;
699+ }
700+ if (!replayed) { replayed = true; continue; }
701+ throw new Error("multipart upload ended without completion");
702+ }
703+ };
704+
705+ const upload = (source, options = {}) => {
706+ const controller = new AbortController();
707+ if (options.signal) {
708+ if (options.signal.aborted) controller.abort();
709+ else options.signal.addEventListener("abort", () => controller.abort(), {once: true});
710+ }
711+ const task = uploadTask(source, options, controller);
712+ task.cancel = () => controller.abort();
713+ return task;
714+ };
715+
716+ globalThis.TinyBlossomUpload = Object.freeze({upload});
717+})();
718diff --git a/internal/webui/bridge.js b/internal/webui/bridge.js
719index c3fc81f..c193ea9 100644
720--- a/internal/webui/bridge.js
721+++ b/internal/webui/bridge.js
722@@ -34,7 +34,7 @@
723 const event = await window.nostr.signEvent({
724 kind: 27235,
725 created_at: Math.floor(Date.now() / 1000),
726- tags: [["u", url], ["method", method], ["payload", await sha256hex(bytes)]],
727+ tags: [["u", url], ["method", method], ["payload", await sha256hex(bytes)], ["nonce", randomHex()]],
728 content: ""
729 });
730 return "Nostr " + btoa(JSON.stringify(event));
731diff --git a/internal/webui/browse.html b/internal/webui/browse.html
732index c760f71..eaecf22 100644
733--- a/internal/webui/browse.html
734+++ b/internal/webui/browse.html
735@@ -14,6 +14,8 @@
736
737 {{define "files"}}<section>
738 <h1>Files</h1>
739+<form method="get" action="/files" id="file-search"><label>Search <input name="q" value="{{.Query.Get "q"}}" placeholder="hash, type or uploader" autocomplete="off"></label> <button>Search</button>{{if .Query.Get "q"}} <a href="/files">clear</a>{{end}}</form>
740+{{if .Actor}}<div id="file-actions"><h2>Store a file</h2><signed-form action="/upload" method="PUT"><label>File <input type="file" name="file" required></label><button>Upload</button></signed-form><file-mirror action="/mirror"></file-mirror><file-tools></file-tools><file-workspace></file-workspace><p><small>Encrypted uploads keep the file contents and key in your browser. The relay stores only encrypted bytes. Keep the complete share link to decrypt the file later.</small></p><noscript><p>Connect a signer and enable JavaScript to authorize uploads. Folder manifests require JavaScript.</p></noscript></div>{{end}}
741 {{if .Error}}{{template "alert" .Error}}
742 {{else if .Feed}}<table id="rows">
743 <thead><tr><th>hash</th><th>type</th><th>uploaded</th></tr></thead>
744@@ -36,6 +38,9 @@
745 {{with index $file "blossom_uri"}}<tr><th>blossom</th><td><code>{{.}}</code></td></tr>{{end}}
746 <tr><th>download</th><td><a fx-ignore href="/files/raw?hash={{urlquery (str (index $file "sha256"))}}">raw</a></td></tr>
747 </table>
748+<file-workspace-root hash="{{str (index $file "sha256")}}" type="{{str (index $file "type")}}" hidden></file-workspace-root>
749+<noscript><p>Enable JavaScript to decrypt files and browse folder manifests locally. Raw downloads remain available above.</p></noscript>
750+<file-tools hash="{{str (index $file "sha256")}}" type="{{str (index $file "type")}}" size="{{str (index $file "size")}}" name="{{shortID (index $file "sha256")}}"></file-tools>
751 {{$type := str (index $file "type")}}{{$raw := printf "/files/raw?hash=%s" (urlquery (str (index $file "sha256")))}}{{if hasPrefix $type "image/"}}<div id="media"><img src="{{$raw}}" alt=""></div>
752 {{else if hasPrefix $type "video/"}}<div id="media"><video controls src="{{$raw}}"></video></div>
753 {{else if hasPrefix $type "audio/"}}<div id="media"><audio controls src="{{$raw}}"></audio></div>
754diff --git a/internal/webui/components.js b/internal/webui/components.js
755index 3e91365..af07cd6 100644
756--- a/internal/webui/components.js
757+++ b/internal/webui/components.js
758@@ -18,6 +18,12 @@
759 // Tables sit inside a <scroll-box> so wide rows scroll sideways.
760 // <nostr-key hex="…">
761 // Shortened key with the full hex as title; click copies it.
762+// <file-mirror action="/mirror">
763+// Signed BUD-04 mirror of a URL or Blossom URI into this relay.
764+// <file-tools [hash="…"] [type="…"]>
765+// Copies Blossom links, encrypts and uploads a file, decrypts a share
766+// link fragment and sends a random-key file as a NIP-17 message.
767+// <file-workspace> and <file-workspace-root> live in file-workspace.js.
768 (() => {
769 "use strict";
770
771@@ -167,6 +173,222 @@
772 }
773 }
774
775+ class FileMirror extends FormElement {
776+ async submit(form) {
777+ let source = form.elements.namedItem("url").value.trim();
778+ if (!source) throw Error("Enter a URL or Blossom URI.");
779+ if (/^blossom:/i.test(source) && new URLSearchParams(source.split("?", 2)[1] || "").has("k")) throw Error("Encrypted Blossom URIs keep k client side; paste the public URI without its key.");
780+ if (/^https?:/i.test(source)) { const url = new URL(source); url.hash = ""; source = url.href; }
781+ const action = this.getAttribute("action") || "/mirror";
782+ const body = JSON.stringify({url: source});
783+ this.report("Signing…");
784+ const response = await tiny.signedFetch(action, "PUT", body, {contentType: "application/json"});
785+ let result;
786+ try { result = await response.json(); } catch { result = await response.text(); }
787+ this.report("Stored.");
788+ const view = el("json-view");
789+ view.value = result;
790+ this.append(view);
791+ }
792+
793+ connectedCallback() {
794+ if (this.form) return;
795+ this.innerHTML = '<form><label>URL or Blossom URI <input name="url" type="text" placeholder="https://… or blossom:…" required></label><button>Mirror</button></form>';
796+ super.connectedCallback();
797+ }
798+ }
799+
800+ const b64url = bytes => {
801+ let binary = "";
802+ bytes.forEach(byte => { binary += String.fromCharCode(byte); });
803+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
804+ };
805+ const fromB64url = value => {
806+ const text = value.replace(/-/g, "+").replace(/_/g, "/") + "===".slice((value.length + 3) % 4);
807+ return Uint8Array.from(atob(text), char => char.charCodeAt(0));
808+ };
809+
810+ class FileTools extends HTMLElement {
811+ disconnectedCallback() {
812+ if (this.downloadURL) URL.revokeObjectURL(this.downloadURL);
813+ this.uploadTask?.cancel?.();
814+ this.uploadController?.abort();
815+ this.uploadCanceled = true;
816+ }
817+
818+ connectedCallback() {
819+ if (this.bound) return;
820+ this.bound = true;
821+ this.innerHTML = '<h3>File tools</h3><p><button type="button" data-copy>Copy Blossom URI</button> <button type="button" data-link>Copy share link</button></p><form><label>Encrypt a file <input type="file" name="file"></label><label>Encryption <select name="scheme"><option value="random">Random key</option><option value="chk">Deduplicated key</option></select></label><button>Encrypt and upload</button></form><p><button type="button" data-upload-cancel disabled>Cancel upload</button> <button type="button" data-upload-retry disabled>Retry upload</button></p><p><small>Random keys keep identical files distinct. Deduplication reveals matching files and allows guesses about predictable content.</small></p><form data-share><label>Send to <input name="recipient" inputmode="text" placeholder="npub or hex pubkey"></label><button>Send privately</button></form><label>Share link <input data-share-url readonly></label><output role="status"></output>';
822+ this.output = this.querySelector("output");
823+ this.querySelector("[data-copy]").addEventListener("click", () => this.copy(this.blossomURI()));
824+ this.querySelector("[data-link]").addEventListener("click", () => this.copy(this.shareLink()));
825+ this.querySelector("form:not([data-share])").addEventListener("submit", event => { event.preventDefault(); this.encryptUpload(event.currentTarget); });
826+ this.querySelector("[data-upload-cancel]").addEventListener("click", () => { this.uploadCanceled = true; this.uploadTask?.cancel?.(); this.uploadController?.abort(); });
827+ this.querySelector("[data-upload-retry]").addEventListener("click", () => this.retryUpload());
828+ this.querySelector("[data-share]").addEventListener("submit", event => { event.preventDefault(); this.share(event.currentTarget); });
829+ this.updateFileControls();
830+ this.decryptFromFragment();
831+ }
832+
833+ hash() { return this.fileHash || this.getAttribute("hash") || ""; }
834+ type() { return this.getAttribute("type") || "application/octet-stream"; }
835+ updateFileControls() {
836+ const available = Boolean(this.hash());
837+ this.querySelectorAll("[data-copy], [data-link], [data-share] button").forEach(button => { button.disabled = !available; });
838+ }
839+ blossomURI() {
840+ const params = new URLSearchParams(this.fileFragment || location.hash.slice(1));
841+ const extension = params.has("manifest") ? (["2", "3"].includes(params.get("node") || "2") ? "bdir" : params.get("node") === "1" ? "bfile" : "bin") : "bin";
842+ const uri = (params.get("enc") === "chk-v1" || params.has("manifest")) && params.get("key") ? TinyBlossomEncryption.createURI(this.hash(), extension, params.get("key")) : "blossom:" + this.hash();
843+ return tiny.root ? uri : uri + (uri.includes("?") ? "&" : "?") + "xs=" + encodeURIComponent(new URL(location.href).host);
844+ }
845+ shareLink() {
846+ if (this.fileShareLink) return this.fileShareLink;
847+ const fragment = this.fileFragment || location.hash.slice(1);
848+ const params = new URLSearchParams(fragment);
849+ if ((params.get("key") && params.get("iv")) || ((params.get("enc") === "chk-v1" || params.has("manifest")) && params.get("key"))) return location.href.split("#", 1)[0] + "#" + fragment;
850+ return location.href.split("#", 1)[0] + "#blossom=" + encodeURIComponent(this.hash());
851+ }
852+ async copy(value) {
853+ try { await navigator.clipboard.writeText(value); this.say("Copied."); }
854+ catch { this.say(value); }
855+ }
856+ say(value, error) { this.output.textContent = value; if (error) this.output.dataset.error = ""; else delete this.output.dataset.error; }
857+
858+ uploadBusy(value) {
859+ this.busy = value;
860+ this.querySelector("[data-upload-cancel]").disabled = !value;
861+ this.querySelector("[data-upload-retry]").disabled = value || !this.pendingUpload;
862+ }
863+
864+ async encryptUpload(form) {
865+ if (this.busy) return;
866+ const file = form.elements.namedItem("file").files[0];
867+ if (!file) { this.say("Choose a file first.", true); return; }
868+ this.uploadBusy(true);
869+ this.uploadCanceled = false;
870+ try {
871+ if (file.size > 256 * 1024 * 1024) throw Error("Encrypted browser uploads are limited to 256 MiB.");
872+ this.say("Encrypting and signing…");
873+ const scheme = form.elements.namedItem("scheme").value;
874+ const plaintext = new Uint8Array(await file.arrayBuffer());
875+ const plaintextHash = await tiny.sha256hex(plaintext);
876+ let ciphertext, fragment;
877+ if (scheme === "chk") {
878+ if (!globalThis.TinyBlossomEncryption) throw Error("CHK encryption is unavailable. Reload this page.");
879+ const encrypted = await TinyBlossomEncryption.encryptCHK(plaintext);
880+ ciphertext = encrypted.ciphertext;
881+ fragment = "enc=chk-v1&key=" + encrypted.key;
882+ } else {
883+ const key = await crypto.subtle.generateKey({name: "AES-GCM", length: 256}, true, ["encrypt", "decrypt"]);
884+ const iv = crypto.getRandomValues(new Uint8Array(12));
885+ ciphertext = new Uint8Array(await crypto.subtle.encrypt({name: "AES-GCM", iv}, key, plaintext));
886+ const rawKey = new Uint8Array(await crypto.subtle.exportKey("raw", key));
887+ fragment = "key=" + b64url(rawKey) + "&iv=" + b64url(iv);
888+ }
889+ fragment += "&name=" + encodeURIComponent(file.name) + "&type=" + encodeURIComponent(file.type || "application/octet-stream") + "&ox=" + plaintextHash;
890+ this.pendingUpload = {ciphertext, fragment, file, state: new Map()};
891+ if (this.uploadCanceled) throw Error("Upload canceled.");
892+ await this.storePreparedUpload();
893+ } catch (error) { this.say("Upload stopped: " + error.message + (this.pendingUpload ? " Retry while this page stays open." : ""), true); }
894+ finally { this.uploadBusy(false); }
895+ }
896+
897+ async retryUpload() {
898+ if (this.busy || !this.pendingUpload) return;
899+ this.uploadBusy(true);
900+ this.uploadCanceled = false;
901+ try { await this.storePreparedUpload(); }
902+ catch (error) { this.say("Upload stopped: " + error.message + " Retry while this page stays open.", true); }
903+ finally { this.uploadBusy(false); }
904+ }
905+
906+ async storePreparedUpload() {
907+ const {ciphertext, fragment, file, state} = this.pendingUpload;
908+ const actualHash = await tiny.sha256hex(ciphertext);
909+ this.uploadController = new AbortController();
910+ let descriptor;
911+ if (globalThis.TinyBlossomUpload?.upload) {
912+ const task = TinyBlossomUpload.upload(ciphertext, {
913+ url: new URL(tiny.localPath("/"), location.href).href, hash: actualHash,
914+ type: "application/octet-stream", state, signal: this.uploadController.signal,
915+ authorize: (url, verb, body) => tiny.authorization(url, verb, body),
916+ onProgress: progress => this.say("Uploading " + Math.round(progress.fraction * 100) + "%…")
917+ });
918+ this.uploadTask = task;
919+ descriptor = (await task).descriptor;
920+ } else {
921+ const response = await tiny.signedFetch("/upload", "PUT", ciphertext, {contentType: "application/octet-stream", signal: this.uploadController.signal});
922+ descriptor = await response.json();
923+ }
924+ if (descriptor.sha256 !== actualHash) throw Error("relay returned an unexpected hash");
925+ this.fileHash = actualHash;
926+ this.fileFragment = fragment;
927+ this.setAttribute("hash", actualHash);
928+ this.setAttribute("type", file.type || "application/octet-stream");
929+ this.setAttribute("size", String(ciphertext.length));
930+ this.updateFileControls();
931+ const link = new URL(location.href);
932+ link.pathname = location.pathname.replace(/\/files?$/, "/file");
933+ link.search = "?hash=" + actualHash;
934+ link.hash = fragment;
935+ this.fileShareLink = link.href;
936+ const share = this.querySelector("[data-share-url]");
937+ if (share) share.value = link.href;
938+ this.pendingUpload = null;
939+ this.uploadTask = null;
940+ try {
941+ if (!navigator.clipboard?.writeText) throw Error("Clipboard unavailable");
942+ await navigator.clipboard.writeText(link.href);
943+ this.say("Encrypted file stored. Share link copied; the key is only in its fragment.");
944+ } catch {
945+ if (share) share.select?.();
946+ this.say("Encrypted file stored. Copy the share link above; the key is only in its fragment.");
947+ }
948+ }
949+
950+ async decryptFromFragment() {
951+ const params = new URLSearchParams(this.fileFragment || location.hash.slice(1));
952+ if ((!params.get("key") || !params.get("iv")) && !(params.get("enc") === "chk-v1" && params.get("key"))) return;
953+ try {
954+ this.say("Decrypting…");
955+ const response = await fetch(tiny.localPath("/files/raw?hash=" + encodeURIComponent(this.hash())));
956+ if (!response.ok) throw Error("download failed (" + response.status + ")");
957+ const encrypted = new Uint8Array(await response.arrayBuffer());
958+ if (await tiny.sha256hex(encrypted) !== this.hash()) throw Error("ciphertext hash mismatch");
959+ let plain;
960+ if (params.get("enc") === "chk-v1") plain = await TinyBlossomEncryption.decryptCHK(encrypted, params.get("key"), this.hash());
961+ else {
962+ const key = await crypto.subtle.importKey("raw", fromB64url(params.get("key")), "AES-GCM", false, ["decrypt"]);
963+ plain = await crypto.subtle.decrypt({name: "AES-GCM", iv: fromB64url(params.get("iv"))}, key, encrypted);
964+ }
965+ if (params.get("ox") && await tiny.sha256hex(plain) !== params.get("ox")) throw Error("plaintext hash mismatch");
966+ if (this.downloadURL) URL.revokeObjectURL(this.downloadURL);
967+ const link = el("a"); this.downloadURL = URL.createObjectURL(new Blob([plain], {type: params.get("type") || this.type()})); link.href = this.downloadURL; link.download = params.get("name") || "decrypted-file"; link.textContent = "download decrypted file"; this.append(link); this.say("Decrypted locally.");
968+ } catch (error) { this.say("Could not decrypt this file: " + error.message, true); }
969+ }
970+
971+ async share(form) {
972+ if (this.sharing) return;
973+ const recipient = form.elements.namedItem("recipient").value.trim();
974+ if (!recipient) { this.say("Enter a public key or npub.", true); return; }
975+ const params = new URLSearchParams(this.fileFragment || location.hash.slice(1));
976+ const signer = globalThis.tinySigner || globalThis.nostr;
977+ if (!globalThis.TinyFileMessages || !signer) { this.say("Connect a NIP-44 signer first. Use the encrypted link, which keeps its key in the URL fragment.", true); return; }
978+ if (!params.get("key") || !params.get("iv")) { this.say("NIP-17 sharing currently requires a random AES-GCM encrypted file.", true); return; }
979+ this.sharing = true;
980+ try {
981+ const key = fromB64url(params.get("key")), nonce = fromB64url(params.get("iv"));
982+ if (key.length !== 32 || nonce.length !== 12) throw Error("Invalid file key or nonce.");
983+ const hex = bytes => Array.from(bytes, value => value.toString(16).padStart(2, "0")).join("");
984+ this.say("Preparing sealed NIP-17 delivery…");
985+ await TinyFileMessages.share({recipient, fileURL: new URL(tiny.localPath("/files/raw?hash=" + this.hash()), location.href).href, ciphertextHash: this.hash(), plaintextHash: params.get("ox") || undefined, key: hex(key), nonce: hex(nonce), mimeType: params.get("type") || this.type(), size: Number(this.getAttribute("size") || 0) || undefined}, {signer});
986+ this.say("Encrypted message delivered; sender copy saved.");
987+ } catch (error) { this.say("NIP-17 delivery failed: " + error.message, true); } finally { this.sharing = false; }
988+ }
989+ }
990+
991 class PublishList extends FormElement {
992 async submit(form) {
993 if (!window.nostr?.signEvent) throw Error("Connect a signer first.");
994@@ -549,6 +771,8 @@
995 customElements.define("connect-list", ConnectList);
996 customElements.define("relay-lists", RelayLists);
997 customElements.define("signed-form", SignedForm);
998+ customElements.define("file-mirror", FileMirror);
999+ customElements.define("file-tools", FileTools);
1000 customElements.define("publish-list", PublishList);
1001 customElements.define("nostr-key", NostrKey);
1002 customElements.define("json-view", JsonView);
1003diff --git a/internal/webui/file-messages.js b/internal/webui/file-messages.js
1004new file mode 100644
1005index 0000000..c6d9ba2
1006--- /dev/null
1007+++ b/internal/webui/file-messages.js
1008@@ -0,0 +1,209 @@
1009+/* NIP-17 file messages. This module never publishes to ordinary relays. */
1010+(function (root) {
1011+ "use strict";
1012+
1013+ const MAX_RELAYS = 8;
1014+ const DAY = 86400;
1015+
1016+ function api() {
1017+ const signer = root.NostrSigner;
1018+ if (!signer || !signer.nip44 || !signer.finalizeEvent || !signer.generateSecretKey) {
1019+ throw new Error("NIP-44 support is unavailable");
1020+ }
1021+ return signer;
1022+ }
1023+
1024+ function relayURL(value) {
1025+ if (typeof value !== "string" || value.length > 2048) return null;
1026+ let url;
1027+ try { url = new URL(value); } catch { return null; }
1028+ if (url.protocol !== "wss:" && url.protocol !== "ws:") return null;
1029+ if (url.username || url.password || url.hash) return null;
1030+ return url.toString().replace(/\/$/, "");
1031+ }
1032+
1033+ function relayList(event, pubkey) {
1034+ if (Array.isArray(event)) {
1035+ event = event.filter((candidate) => candidate?.kind === 10050 && candidate.pubkey === pubkey)
1036+ .sort((a, b) => b.created_at - a.created_at)[0];
1037+ }
1038+ if (!event || event.kind !== 10050 || event.pubkey !== pubkey) {
1039+ throw new Error("recipient has no valid kind 10050 relay list");
1040+ }
1041+ const signer = api();
1042+ if (!signer.verifyEvent(event)) throw new Error("invalid kind 10050 relay list signature");
1043+ const relays = [...new Set(event.tags.filter((tag) => tag[0] === "relay").map((tag) => relayURL(tag[1])).filter(Boolean))];
1044+ if (!relays.length) throw new Error("kind 10050 relay list is empty");
1045+ return relays.slice(0, MAX_RELAYS);
1046+ }
1047+
1048+ function normalizePubkey(value) {
1049+ const text = String(value || "").trim();
1050+ if (/^[0-9a-f]{64}$/i.test(text)) return text.toLowerCase();
1051+ const decoded = api().decodeNpub?.(text);
1052+ if (typeof decoded === "string" && /^[0-9a-f]{64}$/i.test(decoded)) return decoded.toLowerCase();
1053+ throw new Error("public key must be a 64 character hex key or npub");
1054+ }
1055+
1056+ async function bounded(value, timeout, label) {
1057+ const ms = Number.isFinite(timeout) && timeout > 0 ? timeout : 10000;
1058+ let timer;
1059+ try {
1060+ return await Promise.race([Promise.resolve(value), new Promise((_, reject) => {
1061+ timer = setTimeout(() => reject(new Error(label + " timed out")), ms);
1062+ })]);
1063+ } finally { clearTimeout(timer); }
1064+ }
1065+
1066+ function sent(result) {
1067+ if (result === false || result == null) return false;
1068+ if (Array.isArray(result)) return result.some(sent);
1069+ if (typeof result === "object" && "ok" in result) return result.ok === true;
1070+ return true;
1071+ }
1072+
1073+ function past(now) {
1074+ return Math.max(0, Math.floor(now) - Math.floor(Math.random() * (2 * DAY + 1)));
1075+ }
1076+
1077+ async function publicKey(signer, getPublicKey) {
1078+ const key = getPublicKey ? await getPublicKey() : await signer.getPublicKey();
1079+ if (typeof key !== "string" || !/^[0-9a-f]{64}$/i.test(key)) throw new Error("invalid signer public key");
1080+ return key.toLowerCase();
1081+ }
1082+
1083+ async function queryRelayList(pubkey, options) {
1084+ if (!root.tiny?.signedFetch) throw new Error("signed local query is unavailable");
1085+ const response = await root.tiny.signedFetch("/query", "POST", JSON.stringify([{ kinds: [10050], authors: [pubkey], limit: 1 }]), { contentType: "application/json" });
1086+ return response.json();
1087+ }
1088+
1089+ function publishEvent(event, relays, options) {
1090+ const signer = options.signer || root.tinySigner || root.nostr;
1091+ const WebSocketImpl = options.WebSocket || root.WebSocket;
1092+ if (typeof WebSocketImpl !== "function") throw new Error("WebSocket support is unavailable");
1093+ const timeout = Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? options.timeoutMs : 10000;
1094+ return Promise.all(relays.map((url) => new Promise((resolve) => {
1095+ let socket;
1096+ let timer;
1097+ let settled = false;
1098+ let authID = "";
1099+ let authAttempts = 0;
1100+ let eventSent = false;
1101+ const finish = (ok) => { if (settled) return; settled = true; clearTimeout(timer); try { socket?.close(); } catch {} resolve(ok); };
1102+ const sendEvent = () => { if (!settled && !eventSent) { eventSent = true; socket.send(JSON.stringify(["EVENT", event])); } };
1103+ try {
1104+ socket = new WebSocketImpl(url);
1105+ timer = setTimeout(() => finish(false), timeout);
1106+ socket.onopen = sendEvent;
1107+ socket.onmessage = async (message) => {
1108+ let frame;
1109+ try { frame = JSON.parse(typeof message.data === "string" ? message.data : ""); } catch { return; }
1110+ if (settled || !Array.isArray(frame)) return;
1111+ if (frame[0] === "OK" && frame[1] === authID) {
1112+ if (frame[2] === true) { eventSent = false; sendEvent(); } else finish(false);
1113+ return;
1114+ }
1115+ if (frame[0] === "OK" && frame[1] === event.id) {
1116+ if (frame[2] !== true && String(frame[3] || "").toLowerCase().startsWith("auth-required")) { eventSent = false; return; }
1117+ finish(frame[2] === true); return;
1118+ }
1119+ if (frame[0] !== "AUTH" || typeof signer?.signEvent !== "function") return;
1120+ if (typeof frame[1] !== "string" || frame[1].length > 4096) { finish(false); return; }
1121+ if (authAttempts++ >= 1) { finish(false); return; }
1122+ try {
1123+ const auth = await signer.signEvent({ kind: 22242, created_at: Math.floor(Date.now() / 1000), tags: [["relay", url], ["challenge", frame[1]], ["method", "AUTH"]], content: "" });
1124+ if (auth && !settled && auth.kind === 22242 && auth.content === "" && auth.tags.length === 3 && auth.tags[0][0] === "relay" && auth.tags[0][1] === url && auth.tags[1][0] === "challenge" && auth.tags[1][1] === frame[1] && auth.tags[2][0] === "method" && auth.tags[2][1] === "AUTH" && api().verifyEvent(auth) && auth.pubkey === await publicKey(signer)) { authID = auth.id; socket.send(JSON.stringify(["AUTH", auth])); }
1125+ else finish(false);
1126+ } catch { finish(false); }
1127+ };
1128+ socket.onerror = () => finish(false);
1129+ socket.onclose = () => finish(false);
1130+ } catch { finish(false); }
1131+ })));
1132+ }
1133+
1134+ function unsignedRumor(input, sender, now) {
1135+ if (!input.fileURL || !/^https?:\/\//i.test(input.fileURL)) throw new Error("fileURL must be an HTTP(S) URL");
1136+ if (!/^[0-9a-f]{64}$/i.test(input.ciphertextHash || "")) throw new Error("ciphertextHash must be SHA-256 hex");
1137+ if (!input.key || !input.nonce) throw new Error("encrypted file messages require a decryption key and nonce");
1138+ const tags = [["p", input.recipient]];
1139+ if (input.mimeType) tags.push(["file-type", input.mimeType]);
1140+ tags.push(["encryption-algorithm", "aes-gcm"]);
1141+ if (input.key) tags.push(["decryption-key", input.key]);
1142+ if (input.nonce) tags.push(["decryption-nonce", input.nonce]);
1143+ tags.push(["x", input.ciphertextHash.toLowerCase()]);
1144+ if (input.plaintextHash) {
1145+ if (!/^[0-9a-f]{64}$/i.test(input.plaintextHash)) throw new Error("plaintextHash must be SHA-256 hex");
1146+ tags.push(["ox", input.plaintextHash.toLowerCase()]);
1147+ }
1148+ if (input.size != null) tags.push(["size", String(input.size)]);
1149+ const rumor = { pubkey: sender, created_at: Math.floor(now), kind: 15, tags, content: input.fileURL };
1150+ rumor.id = api().getEventHash(rumor);
1151+ return rumor;
1152+ }
1153+
1154+ async function encryptFor(signer, recipient, plaintext) {
1155+ if (typeof signer.nip44Encrypt === "function") return signer.nip44Encrypt(recipient, plaintext);
1156+ if (signer.nip44?.encrypt) return signer.nip44.encrypt(recipient, plaintext);
1157+ throw new Error("signer has no NIP-44 encrypt method");
1158+ }
1159+
1160+ async function seal(rumor, recipient, signer, now) {
1161+ const content = await encryptFor(signer, recipient, JSON.stringify(rumor));
1162+ const unsigned = { kind: 13, tags: [], content, created_at: past(now), pubkey: rumor.pubkey };
1163+ const event = await signer.signEvent(unsigned);
1164+ if (!event || event.kind !== 13 || event.pubkey !== rumor.pubkey || event.tags.length || event.content !== unsigned.content || event.created_at !== unsigned.created_at) throw new Error("signer returned an invalid NIP-17 seal");
1165+ if (!api().verifyEvent(event)) throw new Error("signer returned an invalid seal signature");
1166+ return event;
1167+ }
1168+
1169+ function wrap(sealEvent, recipient, now) {
1170+ const signer = api();
1171+ const secret = signer.generateSecretKey();
1172+ const pubkey = signer.getPublicKey(secret);
1173+ const key = signer.nip44.getConversationKey(secret, recipient);
1174+ const content = signer.nip44.encrypt(JSON.stringify(sealEvent), key);
1175+ const event = signer.finalizeEvent({ kind: 1059, tags: [["p", recipient]], content, created_at: past(now) }, secret);
1176+ if (!signer.verifyEvent(event)) throw new Error("failed to verify gift wrap");
1177+ return { event, secret, pubkey };
1178+ }
1179+
1180+ async function build(input, options = {}) {
1181+ const signer = options.signer || root.tinySigner || root.nostr;
1182+ if (!signer || typeof signer.signEvent !== "function" || (typeof signer.nip44Encrypt !== "function" && !signer.nip44?.encrypt)) throw new Error("a NIP-44 signer is required");
1183+ const recipient = normalizePubkey(input.recipient);
1184+ const sender = await publicKey(signer, options.getPublicKey);
1185+ const now = (options.now || Date.now() / 1000);
1186+ const rumor = unsignedRumor({ ...input, recipient }, sender, now);
1187+ const receiverSeal = await seal(rumor, recipient, signer, now);
1188+ const senderSeal = await seal(rumor, sender, signer, now);
1189+ const receiver = wrap(receiverSeal, recipient, now).event;
1190+ const own = wrap(senderSeal, sender, now).event;
1191+ return { rumor, events: [{ recipient, event: receiver }, { recipient: sender, event: own }] };
1192+ }
1193+
1194+ async function share(input, options = {}) {
1195+ const signer = options.signer || root.tinySigner || root.nostr;
1196+ const query = options.queryRelayList || ((pubkey) => queryRelayList(pubkey, options));
1197+ const publish = options.publish || ((event, relays) => publishEvent(event, relays, options));
1198+ if (typeof query !== "function" || typeof publish !== "function") throw new Error("private NIP-17 delivery is unavailable");
1199+ const sender = await publicKey(signer, options.getPublicKey);
1200+ const recipient = normalizePubkey(input.recipient);
1201+ const timeout = options.timeoutMs;
1202+ const receiverList = relayList(await bounded(query(recipient), timeout, "recipient relay lookup"), recipient);
1203+ const senderList = relayList(await bounded(query(sender), timeout, "sender relay lookup"), sender);
1204+ const built = await build(input, options);
1205+ if (built.rumor.pubkey !== sender) throw new Error("signer changed during file sharing; try again");
1206+ const deliveries = [];
1207+ for (const target of built.events) {
1208+ const relays = target.recipient === recipient ? receiverList : senderList;
1209+ const delivery = await bounded(publish(target.event, relays), timeout, "NIP-17 delivery");
1210+ if (!sent(delivery)) throw new Error("NIP-17 delivery failed on every inbox relay");
1211+ deliveries.push(delivery);
1212+ }
1213+ return { ...built, relays: { recipient: receiverList, sender: senderList }, deliveries };
1214+ }
1215+
1216+ root.TinyFileMessages = { build, share, relayList, queryRelayList, publishEvent };
1217+})(globalThis);
1218diff --git a/internal/webui/file-workspace.js b/internal/webui/file-workspace.js
1219new file mode 100644
1220index 0000000..17b9c1c
1221--- /dev/null
1222+++ b/internal/webui/file-workspace.js
1223@@ -0,0 +1,291 @@
1224+// Draft BUD-16/17 trees. Every object written here is encrypted with BUD-15.
1225+(() => {
1226+ "use strict";
1227+
1228+ const MAX_FILES = 10000;
1229+ const MAX_DEPTH = 32;
1230+ const MAX_FILE_BYTES = 256 * 1024 * 1024;
1231+ const MAX_FOLDER_BYTES = 1024 * 1024 * 1024;
1232+ const MAX_FETCH_BYTES = 16 * 1024 * 1024 + 16;
1233+ const directoryType = "application/vnd.blossom.directory+msgpack";
1234+ const codec = () => globalThis.TinyBlossomManifests;
1235+ const hex = value => codec().hex(value);
1236+ const fromHex = value => {
1237+ if (!/^[0-9a-f]{64}$/.test(value || "")) throw Error("Invalid hash or encryption key.");
1238+ return Uint8Array.from(value.match(/../g), byte => parseInt(byte, 16));
1239+ };
1240+ const element = (tag, text) => {
1241+ const node = document.createElement(tag);
1242+ if (text !== undefined) node.textContent = text;
1243+ return node;
1244+ };
1245+ const checkAbort = signal => {
1246+ if (signal?.aborted) throw Object.assign(Error("Upload canceled. Retry while this page stays open."), {name: "AbortError"});
1247+ };
1248+ const validName = name => typeof name === "string" && name.length > 0 && name.isWellFormed() && ![".", ".."].includes(name) && !/[\/\u0000]/.test(name) && new TextEncoder().encode(name).length <= 1024;
1249+ const folderNode = () => ({directories: new Map(), files: new Map()});
1250+
1251+ function selectionTree(files) {
1252+ if (!files.length || files.length > MAX_FILES) throw Error("Choose a folder with 1 to 10,000 files.");
1253+ const root = folderNode();
1254+ let total = 0;
1255+ const paths = files.map(file => (file.webkitRelativePath || file.name).split("/"));
1256+ const commonRoot = paths.every(path => path.length > 1 && path[0] === paths[0][0]);
1257+ for (let index = 0; index < files.length; index++) {
1258+ const file = files[index];
1259+ const path = commonRoot ? paths[index].slice(1) : paths[index];
1260+ if (path.length > MAX_DEPTH || path.some(name => !validName(name))) throw Error("Invalid folder path.");
1261+ if (!Number.isSafeInteger(file.size) || file.size < 0 || file.size > MAX_FILE_BYTES) throw Error("Files must be at most 256 MiB in the browser workspace.");
1262+ total += file.size;
1263+ if (total > MAX_FOLDER_BYTES) throw Error("The selected folder exceeds 1 GiB.");
1264+ let directory = root;
1265+ for (const name of path.slice(0, -1)) {
1266+ if (directory.files.has(name)) throw Error("A file and folder use the same name.");
1267+ if (!directory.directories.has(name)) directory.directories.set(name, folderNode());
1268+ directory = directory.directories.get(name);
1269+ }
1270+ const name = path.at(-1);
1271+ if (directory.files.has(name) || directory.directories.has(name)) throw Error("Duplicate folder entry.");
1272+ directory.files.set(name, file);
1273+ }
1274+ return {root, name: commonRoot ? paths[0][0] : "folder"};
1275+ }
1276+
1277+ async function storeEncrypted(plaintext, type, signal) {
1278+ checkAbort(signal);
1279+ const encrypted = await TinyBlossomEncryption.encryptCHK(plaintext);
1280+ checkAbort(signal);
1281+ const url = new URL(tiny.localPath("/"), location.href).href;
1282+ const result = await TinyBlossomUpload.upload(encrypted.ciphertext, {
1283+ url, hash: encrypted.hash, type, signal,
1284+ authorize: (target, method, body) => tiny.authorization(target, method, body)
1285+ });
1286+ if (result.descriptor.sha256 !== encrypted.hash || result.descriptor.size !== encrypted.ciphertext.length) throw Error("Relay returned an unexpected blob descriptor.");
1287+ return {hash: encrypted.hash, key: fromHex(encrypted.key)};
1288+ }
1289+
1290+ const manifestStore = signal => async ({bytes, node}) => storeEncrypted(bytes, node.t === 2 || node.t === 3 ? directoryType : "application/octet-stream", signal);
1291+ const rootReference = details => {
1292+ const stored = details.manifests.at(-1);
1293+ return {hash: stored.hash, key: stored.key, type: details.root.t, size: details.root.l.reduce((sum, link) => sum + link.s, 0)};
1294+ };
1295+
1296+ async function storeFile(file, signal, progress) {
1297+ if (file.size > MAX_FILE_BYTES) throw Error("Files must be at most 256 MiB in the browser workspace.");
1298+ const chunks = [];
1299+ for (let offset = 0; offset < file.size || offset === 0; offset += codec().CHUNK_SIZE) {
1300+ checkAbort(signal);
1301+ const plain = new Uint8Array(await file.slice(offset, offset + codec().CHUNK_SIZE).arrayBuffer());
1302+ const stored = await storeEncrypted(plain, "application/octet-stream", signal);
1303+ chunks.push({...stored, size: plain.length});
1304+ progress?.(plain.length);
1305+ if (file.size === 0) break;
1306+ }
1307+ if (chunks.length === 1) return {...chunks[0], type: 0};
1308+ return rootReference(await codec().buildFile(chunks, {store: manifestStore(signal), returnDetails: true}));
1309+ }
1310+
1311+ async function storeDirectory(directory, signal, progress) {
1312+ const entries = [];
1313+ for (const [name, file] of directory.files) {
1314+ const stored = await storeFile(file, signal, progress);
1315+ entries.push({...stored, name, metadata: {type: file.type || "application/octet-stream"}});
1316+ }
1317+ for (const [name, child] of directory.directories) {
1318+ const stored = await storeDirectory(child, signal, progress);
1319+ entries.push({...stored, name});
1320+ }
1321+ return rootReference(await codec().buildDirectory(entries, {store: manifestStore(signal), returnDetails: true}));
1322+ }
1323+
1324+ const shareURL = (reference, name, type) => {
1325+ const url = new URL(tiny.localPath("/file"), location.href);
1326+ url.searchParams.set("hash", reference.hash);
1327+ url.hash = new URLSearchParams({manifest: reference.hash, key: hex(reference.key), node: String(reference.type), name, type: type || "application/octet-stream"}).toString();
1328+ return url.href;
1329+ };
1330+
1331+ class Workspace extends HTMLElement {
1332+ connectedCallback() {
1333+ if (this.bound) return;
1334+ this.bound = true;
1335+ this.innerHTML = '<h3>Folders and large files</h3><p>Encrypt folders and split large files into portable chunks. Deduplicated encryption reveals matching content and permits guesses about predictable files.</p><form data-folder><label>Folder <input type="file" name="folder" webkitdirectory directory multiple required></label><button>Encrypt and store folder</button></form><form data-chunked><label>File to split into chunks <input type="file" name="file" required></label><button>Encrypt and store file</button></form><p><button type="button" data-cancel disabled>Cancel upload</button> <button type="button" data-retry disabled>Retry upload</button></p><label>Share link <input data-tree-share readonly></label><p><a data-open hidden>Browse stored content</a></p><output role="status"></output>';
1336+ this.out = this.querySelector("output");
1337+ for (const form of this.querySelectorAll("form")) form.addEventListener("submit", event => {
1338+ event.preventDefault();
1339+ this.run(form).catch(error => this.say(error.message, true));
1340+ });
1341+ this.querySelector("[data-cancel]").addEventListener("click", () => this.controller?.abort());
1342+ this.querySelector("[data-retry]").addEventListener("click", () => this.run().catch(error => this.say(error.message, true)));
1343+ }
1344+ disconnectedCallback() { this.controller?.abort(); }
1345+ say(message, error = false) {
1346+ this.out.textContent = message;
1347+ if (error) this.out.dataset.error = "";
1348+ else delete this.out.dataset.error;
1349+ }
1350+ async run(form) {
1351+ if (this.busy) return;
1352+ if (form) {
1353+ const folder = form.elements.namedItem("folder");
1354+ const input = folder || form.elements.namedItem("file");
1355+ this.selection = {files: [...input.files], folder: Boolean(folder)};
1356+ }
1357+ if (!this.selection?.files.length) throw Error("Choose a file or folder first.");
1358+ this.busy = true;
1359+ this.controller = new AbortController();
1360+ this.querySelector("[data-cancel]").disabled = false;
1361+ this.querySelector("[data-retry]").disabled = true;
1362+ let completed = false;
1363+ try {
1364+ let reference, name, type;
1365+ let sent = 0;
1366+ const progress = size => { sent += size; this.say("Stored " + sent.toLocaleString() + " bytes. Encrypting the remaining content…"); };
1367+ this.say("Encrypting selected content…");
1368+ if (this.selection.folder) {
1369+ const selected = selectionTree(this.selection.files);
1370+ name = selected.name;
1371+ reference = await storeDirectory(selected.root, this.controller.signal, progress);
1372+ } else {
1373+ const file = this.selection.files[0];
1374+ name = file.name; type = file.type;
1375+ reference = await storeFile(file, this.controller.signal, progress);
1376+ }
1377+ checkAbort(this.controller.signal);
1378+ const url = shareURL(reference, name, type);
1379+ this.querySelector("[data-tree-share]").value = url;
1380+ const open = this.querySelector("[data-open]");
1381+ open.href = url; open.hidden = false;
1382+ this.say("Stored. Keep the complete share link to decrypt and browse this content.");
1383+ completed = true;
1384+ return url;
1385+ } finally {
1386+ this.busy = false;
1387+ this.querySelector("[data-cancel]").disabled = true;
1388+ this.querySelector("[data-retry]").disabled = completed;
1389+ if (completed) this.selection = null;
1390+ }
1391+ }
1392+ }
1393+
1394+ async function fetchBlob(hash, signal) {
1395+ fromHex(hash);
1396+ const response = await fetch(tiny.localPath("/files/raw?hash=" + hash), {signal});
1397+ if (!response.ok) throw Error("Download failed (" + response.status + ").");
1398+ if (Number(response.headers.get("Content-Length")) > MAX_FETCH_BYTES) throw Error("Linked blob exceeds the browser fetch limit.");
1399+ const reader = response.body?.getReader();
1400+ if (!reader) {
1401+ const bytes = new Uint8Array(await response.arrayBuffer());
1402+ if (bytes.length > MAX_FETCH_BYTES) throw Error("Linked blob exceeds the browser fetch limit.");
1403+ return bytes;
1404+ }
1405+ const parts = [];
1406+ let size = 0;
1407+ try {
1408+ for (;;) {
1409+ const {value, done} = await reader.read();
1410+ if (done) break;
1411+ size += value.length;
1412+ if (size > MAX_FETCH_BYTES) { await reader.cancel(); throw Error("Linked blob exceeds the browser fetch limit."); }
1413+ parts.push(value);
1414+ }
1415+ } finally { reader.releaseLock(); }
1416+ const bytes = new Uint8Array(size);
1417+ let offset = 0;
1418+ for (const part of parts) { bytes.set(part, offset); offset += part.length; }
1419+ return bytes;
1420+ }
1421+
1422+ async function plaintext(reference, signal) {
1423+ const hash = hex(reference.h);
1424+ const raw = await fetchBlob(hash, signal);
1425+ if (hex(await codec().sha256(raw)) !== hash) throw Error("Blob hash mismatch.");
1426+ return reference.k ? TinyBlossomEncryption.decryptCHK(raw, hex(reference.k), hash) : raw;
1427+ }
1428+ const decrypt = (raw, link) => TinyBlossomEncryption.decryptCHK(raw, hex(link.k), hex(link.h));
1429+
1430+ class Root extends HTMLElement {
1431+ connectedCallback() {
1432+ if (this.bound) return;
1433+ this.bound = true;
1434+ const params = new URLSearchParams(location.hash.slice(1));
1435+ if (!params.has("manifest") && this.getAttribute("type") !== directoryType) { this.hidden = true; return; }
1436+ this.hidden = false;
1437+ this.load().catch(error => this.fail(error.message));
1438+ }
1439+ disconnectedCallback() {
1440+ this.controller?.abort();
1441+ if (this.downloadURL) URL.revokeObjectURL(this.downloadURL);
1442+ }
1443+ fail(message) {
1444+ const error = element("p", "Content unavailable: " + message);
1445+ error.setAttribute("role", "alert");
1446+ this.replaceChildren(error);
1447+ }
1448+ async load() {
1449+ this.controller?.abort();
1450+ this.controller = new AbortController();
1451+ const params = new URLSearchParams(location.hash.slice(1));
1452+ const reference = {h: fromHex(params.get("manifest") || this.getAttribute("hash"))};
1453+ if (params.has("key")) reference.k = fromHex(params.get("key"));
1454+ const type = params.has("node") ? Number(params.get("node")) : 2;
1455+ if (![0, 1, 2, 3].includes(type)) throw Error("Unsupported manifest type.");
1456+ const data = await plaintext(reference, this.controller.signal);
1457+ const heading = element("h2", params.get("name") || "Stored content");
1458+ this.replaceChildren(heading);
1459+ if (type === 0) { this.offerDownload(data, params.get("name") || "file", params.get("type")); return; }
1460+ const root = codec().decodeManifest(data);
1461+ if (root.t !== type) throw Error("Manifest type does not match its reference.");
1462+ if (type === 1) {
1463+ const button = element("button", "Download decrypted file");
1464+ button.type = "button";
1465+ button.addEventListener("click", () => this.download({...reference, t: 1, s: root.l.reduce((sum, link) => sum + link.s, 0), n: params.get("name") || "file", m: {type: params.get("type")}}).catch(error => this.fail(error.message)));
1466+ this.append(button); return;
1467+ }
1468+ const entries = await codec().resolveDirectory(root, (hash) => fetchBlob(hash, this.controller.signal), {decrypt, maxDepth: MAX_DEPTH, maxEntries: MAX_FILES, maxBytes: 64 * 1024 * 1024});
1469+ const list = element("ul");
1470+ if (!entries.length) this.append(element("p", "This folder is empty."));
1471+ for (const link of entries) {
1472+ const item = element("li");
1473+ if (link.t === 2 || link.t === 3) {
1474+ const open = element("a", link.n + "/");
1475+ const url = new URL(tiny.localPath("/file"), location.href);
1476+ url.searchParams.set("hash", hex(link.h));
1477+ const fragment = new URLSearchParams({manifest: hex(link.h), node: String(link.t), name: link.n});
1478+ if (link.k) fragment.set("key", hex(link.k));
1479+ url.hash = fragment.toString(); open.href = url.href;
1480+ item.append(open);
1481+ } else {
1482+ const button = element("button", link.n + " (" + link.s.toLocaleString() + " bytes)");
1483+ button.type = "button";
1484+ button.addEventListener("click", () => this.download(link).catch(error => this.fail(error.message)));
1485+ item.append(button);
1486+ }
1487+ list.append(item);
1488+ }
1489+ this.append(list);
1490+ this.entries = entries;
1491+ }
1492+ async download(link) {
1493+ let data;
1494+ if (link.t === 0) data = await plaintext(link, this.controller.signal);
1495+ else if (link.t === 1) {
1496+ const manifest = codec().decodeManifest(await plaintext(link, this.controller.signal));
1497+ data = await codec().readFile(manifest, hash => fetchBlob(hash, this.controller.signal), {decrypt, maxDepth: MAX_DEPTH, maxBytes: MAX_FILE_BYTES});
1498+ } else throw Error("Unsupported file link.");
1499+ if (data.length !== link.s) throw Error("File size does not match its directory entry.");
1500+ this.offerDownload(data, link.n, link.m?.type);
1501+ return data;
1502+ }
1503+ offerDownload(data, name, type) {
1504+ if (this.downloadURL) URL.revokeObjectURL(this.downloadURL);
1505+ this.downloadURL = URL.createObjectURL(new Blob([data], {type: type || "application/octet-stream"}));
1506+ const link = element("a", "Save " + name);
1507+ link.href = this.downloadURL; link.download = name;
1508+ this.append(link);
1509+ link.click();
1510+ }
1511+ }
1512+ customElements.define("file-workspace", Workspace);
1513+ customElements.define("file-workspace-root", Root);
1514+})();
1515diff --git a/internal/webui/page.html b/internal/webui/page.html
1516index 903431d..5659f1c 100644
1517--- a/internal/webui/page.html
1518+++ b/internal/webui/page.html
1519@@ -57,6 +57,11 @@
1520 </tr></tbody></table>
1521 <footer id="footer"><table><tr><td><span id="prompt"><b>{{.Slug}}</b> &raquo; {{prompt .Path .Query}}</span></td><td><span id="who">{{if .Private}}private relay{{else if .Actor}}signed in as {{template "nostrKey" .Actor}} (<button id="session-logout" type="button">sign out</button>){{else}}browsing as guest (<a href="/signin">Sign in</a>){{end}}</span> <span id="session-status" role="status"></span><span id="navigation-status" role="status" aria-live="polite"></span><button id="theme" type="button" aria-label="Switch theme">theme</button></td></tr></table></footer>
1522 <script>{{script "bridge.js"}}</script>
1523+<script>{{script "blossom-encryption.js"}}</script>
1524+<script>{{script "blossom-manifests.js"}}</script>
1525+<script>{{script "blossom-upload.js"}}</script>
1526+<script>{{script "file-messages.js"}}</script>
1527+<script>{{script "file-workspace.js"}}</script>
1528 <script>{{script "components.js"}}</script>
1529 </body>
1530 </html>
1531diff --git a/internal/webui/signer.js b/internal/webui/signer.js
1532index 0900cd3..cad8094 100644
1533--- a/internal/webui/signer.js
1534+++ b/internal/webui/signer.js
1535@@ -1,5 +1,5 @@
1536 "use strict";
1537-(()=>{var Ri=Object.defineProperty;var _i=(e,t,n)=>t in e?Ri(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var u=(e,t,n)=>_i(e,typeof t!="symbol"?t+"":t,n);function pt(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function xe(e,t=""){if(!Number.isSafeInteger(e)||e<0){let n=t&&`"${t}" `;throw new Error(`${n}expected integer >= 0, got ${e}`)}}function N(e,t,n=""){let r=pt(e),o=e?.length,s=t!==void 0;if(!r||s&&o!==t){let i=n&&`"${n}" `,a=s?` of length ${t}`:"",c=r?`length=${o}`:`type=${typeof e}`;throw new Error(i+"expected Uint8Array"+a+", got "+c)}return e}function Bt(e){if(typeof e!="function"||typeof e.create!="function")throw new Error("Hash must wrapped by utils.createHasher");xe(e.outputLen),xe(e.blockLen)}function nt(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")}function Jr(e,t){N(e,void 0,"digestInto() output");let n=t.outputLen;if(e.length<n)throw new Error('"digestInto() output" expected to be of length >='+n)}function $e(...e){for(let t=0;t<e.length;t++)e[t].fill(0)}function Rt(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}function be(e,t){return e<<32-t|e>>>t}var Xr=typeof Uint8Array.from([]).toHex=="function"&&typeof Uint8Array.fromHex=="function",ki=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));function We(e){if(N(e),Xr)return e.toHex();let t="";for(let n=0;n<e.length;n++)t+=ki[e[n]];return t}var Se={_0:48,_9:57,A:65,F:70,a:97,f:102};function Zr(e){if(e>=Se._0&&e<=Se._9)return e-Se._0;if(e>=Se.A&&e<=Se.F)return e-(Se.A-10);if(e>=Se.a&&e<=Se.f)return e-(Se.a-10)}function Ve(e){if(typeof e!="string")throw new Error("hex string expected, got "+typeof e);if(Xr)return Uint8Array.fromHex(e);let t=e.length,n=t/2;if(t%2)throw new Error("hex string expected, got unpadded hex of length "+t);let r=new Uint8Array(n);for(let o=0,s=0;o<n;o++,s+=2){let i=Zr(e.charCodeAt(s)),a=Zr(e.charCodeAt(s+1));if(i===void 0||a===void 0){let c=e[s]+e[s+1];throw new Error('hex string expected, got non-hex character "'+c+'" at index '+s)}r[o]=i*16+a}return r}function ce(...e){let t=0;for(let r=0;r<e.length;r++){let o=e[r];N(o),t+=o.length}let n=new Uint8Array(t);for(let r=0,o=0;r<e.length;r++){let s=e[r];n.set(s,o),o+=s.length}return n}function Yr(e,t={}){let n=(o,s)=>e(s).update(o).digest(),r=e(void 0);return n.outputLen=r.outputLen,n.blockLen=r.blockLen,n.create=o=>e(o),Object.assign(n,t),Object.freeze(n)}function Ge(e=32){let t=typeof globalThis=="object"?globalThis.crypto:null;if(typeof t?.getRandomValues!="function")throw new Error("crypto.getRandomValues must be defined");return t.getRandomValues(new Uint8Array(e))}var Qr=e=>({oid:Uint8Array.from([6,9,96,134,72,1,101,3,4,2,e])});function eo(e,t,n){return e&t^~e&n}function to(e,t,n){return e&t^e&n^t&n}var _t=class{constructor(t,n,r,o){u(this,"blockLen");u(this,"outputLen");u(this,"padOffset");u(this,"isLE");u(this,"buffer");u(this,"view");u(this,"finished",!1);u(this,"length",0);u(this,"pos",0);u(this,"destroyed",!1);this.blockLen=t,this.outputLen=n,this.padOffset=r,this.isLE=o,this.buffer=new Uint8Array(t),this.view=Rt(this.buffer)}update(t){nt(this),N(t);let{view:n,buffer:r,blockLen:o}=this,s=t.length;for(let i=0;i<s;){let a=Math.min(o-this.pos,s-i);if(a===o){let c=Rt(t);for(;o<=s-i;i+=o)this.process(c,i);continue}r.set(t.subarray(i,i+a),this.pos),this.pos+=a,i+=a,this.pos===o&&(this.process(n,0),this.pos=0)}return this.length+=t.length,this.roundClean(),this}digestInto(t){nt(this),Jr(t,this),this.finished=!0;let{buffer:n,view:r,blockLen:o,isLE:s}=this,{pos:i}=this;n[i++]=128,$e(this.buffer.subarray(i)),this.padOffset>o-i&&(this.process(r,0),i=0);for(let h=i;h<o;h++)n[h]=0;r.setBigUint64(o-8,BigInt(this.length*8),s),this.process(r,0);let a=Rt(t),c=this.outputLen;if(c%4)throw new Error("_sha2: outputLen must be aligned to 32bit");let l=c/4,f=this.get();if(l>f.length)throw new Error("_sha2: outputLen bigger than state");for(let h=0;h<l;h++)a.setUint32(4*h,f[h],s)}digest(){let{buffer:t,outputLen:n}=this;this.digestInto(t);let r=t.slice(0,n);return this.destroy(),r}_cloneInto(t){t||(t=new this.constructor),t.set(...this.get());let{blockLen:n,buffer:r,length:o,finished:s,destroyed:i,pos:a}=this;return t.destroyed=i,t.finished=s,t.length=o,t.pos=a,o%n&&t.buffer.set(r),t}clone(){return this._cloneInto()}},Ae=Uint32Array.from([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]);var Li=Uint32Array.from([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),Oe=new Uint32Array(64),yn=class extends _t{constructor(t){super(64,t,8,!1)}get(){let{A:t,B:n,C:r,D:o,E:s,F:i,G:a,H:c}=this;return[t,n,r,o,s,i,a,c]}set(t,n,r,o,s,i,a,c){this.A=t|0,this.B=n|0,this.C=r|0,this.D=o|0,this.E=s|0,this.F=i|0,this.G=a|0,this.H=c|0}process(t,n){for(let h=0;h<16;h++,n+=4)Oe[h]=t.getUint32(n,!1);for(let h=16;h<64;h++){let d=Oe[h-15],p=Oe[h-2],y=be(d,7)^be(d,18)^d>>>3,m=be(p,17)^be(p,19)^p>>>10;Oe[h]=m+Oe[h-7]+y+Oe[h-16]|0}let{A:r,B:o,C:s,D:i,E:a,F:c,G:l,H:f}=this;for(let h=0;h<64;h++){let d=be(a,6)^be(a,11)^be(a,25),p=f+d+eo(a,c,l)+Li[h]+Oe[h]|0,m=(be(r,2)^be(r,13)^be(r,22))+to(r,o,s)|0;f=l,l=c,c=a,a=i+p|0,i=s,s=o,o=r,r=p+m|0}r=r+this.A|0,o=o+this.B|0,s=s+this.C|0,i=i+this.D|0,a=a+this.E|0,c=c+this.F|0,l=l+this.G|0,f=f+this.H|0,this.set(r,o,s,i,a,c,l,f)}roundClean(){$e(Oe)}destroy(){this.set(0,0,0,0,0,0,0,0),$e(this.buffer)}},gn=class extends yn{constructor(){super(32);u(this,"A",Ae[0]|0);u(this,"B",Ae[1]|0);u(this,"C",Ae[2]|0);u(this,"D",Ae[3]|0);u(this,"E",Ae[4]|0);u(this,"F",Ae[5]|0);u(this,"G",Ae[6]|0);u(this,"H",Ae[7]|0)}};var kt=Yr(()=>new gn,Qr(1));var mn=BigInt(0),bn=BigInt(1);function yt(e,t=""){if(typeof e!="boolean"){let n=t&&`"${t}" `;throw new Error(n+"expected boolean, got type="+typeof e)}return e}function no(e){if(typeof e=="bigint"){if(!Lt(e))throw new Error("positive bigint expected, got "+e)}else xe(e);return e}function gt(e){let t=no(e).toString(16);return t.length&1?"0"+t:t}function ro(e){if(typeof e!="string")throw new Error("hex string expected, got "+typeof e);return e===""?mn:BigInt("0x"+e)}function Ue(e){return ro(We(e))}function wn(e){return ro(We(Ci(N(e)).reverse()))}function Ct(e,t){xe(t),e=no(e);let n=Ve(e.toString(16).padStart(t*2,"0"));if(n.length!==t)throw new Error("number too large");return n}function xn(e,t){return Ct(e,t).reverse()}function Ci(e){return Uint8Array.from(e)}function oo(e){return Uint8Array.from(e,(t,n)=>{let r=t.charCodeAt(0);if(t.length!==1||r>127)throw new Error(`string contains non-ASCII character "${e[n]}" with code ${r} at position ${n}`);return r})}var Lt=e=>typeof e=="bigint"&&mn<=e;function Ii(e,t,n){return Lt(e)&&Lt(t)&&Lt(n)&&t<=e&&e<n}function so(e,t,n,r){if(!Ii(t,n,r))throw new Error("expected valid "+e+": "+n+" <= n < "+r+", got "+t)}function vn(e){let t;for(t=0;e>mn;e>>=bn,t+=1);return t}var bt=e=>(bn<<BigInt(e))-bn;function io(e,t,n){if(xe(e,"hashLen"),xe(t,"qByteLen"),typeof n!="function")throw new Error("hmacFn must be a function");let r=w=>new Uint8Array(w),o=Uint8Array.of(),s=Uint8Array.of(0),i=Uint8Array.of(1),a=1e3,c=r(e),l=r(e),f=0,h=()=>{c.fill(1),l.fill(0),f=0},d=(...w)=>n(l,ce(c,...w)),p=(w=o)=>{l=d(s,w),c=d(),w.length!==0&&(l=d(i,w),c=d())},y=()=>{if(f++>=a)throw new Error("drbg: tried max amount of iterations");let w=0,x=[];for(;w<t;){c=d();let A=c.slice();x.push(A),w+=c.length}return ce(...x)};return(w,x)=>{h(),p(w);let A;for(;!(A=x(y()));)p();return h(),A}}function mt(e,t={},n={}){if(!e||typeof e!="object")throw new Error("expected valid options object");function r(s,i,a){let c=e[s];if(a&&c===void 0)return;let l=typeof c;if(l!==i||c===null)throw new Error(`param "${s}" is invalid: expected ${i}, got ${l}`)}let o=(s,i)=>Object.entries(s).forEach(([a,c])=>r(a,c,i));o(t,!1),o(n,!0)}function En(e){let t=new WeakMap;return(n,...r)=>{let o=t.get(n);if(o!==void 0)return o;let s=e(n,...r);return t.set(n,s),s}}var ae=BigInt(0),se=BigInt(1),Ke=BigInt(2),lo=BigInt(3),uo=BigInt(4),fo=BigInt(5),Hi=BigInt(7),ho=BigInt(8),Oi=BigInt(9),po=BigInt(16);function me(e,t){let n=e%t;return n>=ae?n:t+n}function fe(e,t,n){let r=e;for(;t-- >ae;)r*=r,r%=n;return r}function ao(e,t){if(e===ae)throw new Error("invert: expected non-zero number");if(t<=ae)throw new Error("invert: expected positive modulus, got "+t);let n=me(e,t),r=t,o=ae,s=se,i=se,a=ae;for(;n!==ae;){let l=r/n,f=r%n,h=o-i*l,d=s-a*l;r=n,n=f,o=i,s=a,i=h,a=d}if(r!==se)throw new Error("invert: does not exist");return me(o,t)}function An(e,t,n){if(!e.eql(e.sqr(t),n))throw new Error("Cannot find square root")}function yo(e,t){let n=(e.ORDER+se)/uo,r=e.pow(t,n);return An(e,r,t),r}function Ui(e,t){let n=(e.ORDER-fo)/ho,r=e.mul(t,Ke),o=e.pow(r,n),s=e.mul(t,o),i=e.mul(e.mul(s,Ke),o),a=e.mul(s,e.sub(i,e.ONE));return An(e,a,t),a}function Pi(e){let t=rt(e),n=go(e),r=n(t,t.neg(t.ONE)),o=n(t,r),s=n(t,t.neg(r)),i=(e+Hi)/po;return(a,c)=>{let l=a.pow(c,i),f=a.mul(l,r),h=a.mul(l,o),d=a.mul(l,s),p=a.eql(a.sqr(f),c),y=a.eql(a.sqr(h),c);l=a.cmov(l,f,p),f=a.cmov(d,h,y);let m=a.eql(a.sqr(f),c),w=a.cmov(l,f,m);return An(a,w,c),w}}function go(e){if(e<lo)throw new Error("sqrt is not defined for small field");let t=e-se,n=0;for(;t%Ke===ae;)t/=Ke,n++;let r=Ke,o=rt(e);for(;co(o,r)===1;)if(r++>1e3)throw new Error("Cannot find square root: probably non-prime P");if(n===1)return yo;let s=o.pow(r,t),i=(t+se)/Ke;return function(c,l){if(c.is0(l))return l;if(co(c,l)!==1)throw new Error("Cannot find square root");let f=n,h=c.mul(c.ONE,s),d=c.pow(l,t),p=c.pow(l,i);for(;!c.eql(d,c.ONE);){if(c.is0(d))return c.ZERO;let y=1,m=c.sqr(d);for(;!c.eql(m,c.ONE);)if(y++,m=c.sqr(m),y===f)throw new Error("Cannot find square root");let w=se<<BigInt(f-y-1),x=c.pow(h,w);f=y,h=c.sqr(x),d=c.mul(d,h),p=c.mul(p,x)}return p}}function Ni(e){return e%uo===lo?yo:e%ho===fo?Ui:e%po===Oi?Pi(e):go(e)}var Mi=["create","isValid","is0","neg","inv","sqrt","sqr","eql","add","sub","mul","pow","div","addN","subN","mulN","sqrN"];function Tn(e){let t={ORDER:"bigint",BYTES:"number",BITS:"number"},n=Mi.reduce((r,o)=>(r[o]="function",r),t);return mt(e,n),e}function qi(e,t,n){if(n<ae)throw new Error("invalid exponent, negatives unsupported");if(n===ae)return e.ONE;if(n===se)return t;let r=e.ONE,o=t;for(;n>ae;)n&se&&(r=e.mul(r,o)),o=e.sqr(o),n>>=se;return r}function It(e,t,n=!1){let r=new Array(t.length).fill(n?e.ZERO:void 0),o=t.reduce((i,a,c)=>e.is0(a)?i:(r[c]=i,e.mul(i,a)),e.ONE),s=e.inv(o);return t.reduceRight((i,a,c)=>e.is0(a)?i:(r[c]=e.mul(i,r[c]),e.mul(i,a)),s),r}function co(e,t){let n=(e.ORDER-se)/Ke,r=e.pow(t,n),o=e.eql(r,e.ONE),s=e.eql(r,e.ZERO),i=e.eql(r,e.neg(e.ONE));if(!o&&!s&&!i)throw new Error("invalid Legendre symbol result");return o?1:s?0:-1}function Di(e,t){t!==void 0&&xe(t);let n=t!==void 0?t:e.toString(2).length,r=Math.ceil(n/8);return{nBitLength:n,nByteLength:r}}var Sn=class{constructor(t,n={}){u(this,"ORDER");u(this,"BITS");u(this,"BYTES");u(this,"isLE");u(this,"ZERO",ae);u(this,"ONE",se);u(this,"_lengths");u(this,"_sqrt");u(this,"_mod");if(t<=ae)throw new Error("invalid field: expected ORDER > 0, got "+t);let r;this.isLE=!1,n!=null&&typeof n=="object"&&(typeof n.BITS=="number"&&(r=n.BITS),typeof n.sqrt=="function"&&(this.sqrt=n.sqrt),typeof n.isLE=="boolean"&&(this.isLE=n.isLE),n.allowedLengths&&(this._lengths=n.allowedLengths?.slice()),typeof n.modFromBytes=="boolean"&&(this._mod=n.modFromBytes));let{nBitLength:o,nByteLength:s}=Di(t,r);if(s>2048)throw new Error("invalid field: expected ORDER of <= 2048 bytes");this.ORDER=t,this.BITS=o,this.BYTES=s,this._sqrt=void 0,Object.preventExtensions(this)}create(t){return me(t,this.ORDER)}isValid(t){if(typeof t!="bigint")throw new Error("invalid field element: expected bigint, got "+typeof t);return ae<=t&&t<this.ORDER}is0(t){return t===ae}isValidNot0(t){return!this.is0(t)&&this.isValid(t)}isOdd(t){return(t&se)===se}neg(t){return me(-t,this.ORDER)}eql(t,n){return t===n}sqr(t){return me(t*t,this.ORDER)}add(t,n){return me(t+n,this.ORDER)}sub(t,n){return me(t-n,this.ORDER)}mul(t,n){return me(t*n,this.ORDER)}pow(t,n){return qi(this,t,n)}div(t,n){return me(t*ao(n,this.ORDER),this.ORDER)}sqrN(t){return t*t}addN(t,n){return t+n}subN(t,n){return t-n}mulN(t,n){return t*n}inv(t){return ao(t,this.ORDER)}sqrt(t){return this._sqrt||(this._sqrt=Ni(this.ORDER)),this._sqrt(this,t)}toBytes(t){return this.isLE?xn(t,this.BYTES):Ct(t,this.BYTES)}fromBytes(t,n=!1){N(t);let{_lengths:r,BYTES:o,isLE:s,ORDER:i,_mod:a}=this;if(r){if(!r.includes(t.length)||t.length>o)throw new Error("Field.fromBytes: expected "+r+" bytes, got "+t.length);let l=new Uint8Array(o);l.set(t,s?0:l.length-t.length),t=l}if(t.length!==o)throw new Error("Field.fromBytes: expected "+o+" bytes, got "+t.length);let c=s?wn(t):Ue(t);if(a&&(c=me(c,i)),!n&&!this.isValid(c))throw new Error("invalid field element: outside of range 0..ORDER");return c}invertBatch(t){return It(this,t)}cmov(t,n,r){return r?n:t}};function rt(e,t={}){return new Sn(e,t)}function bo(e){if(typeof e!="bigint")throw new Error("field order must be bigint");let t=e.toString(2).length;return Math.ceil(t/8)}function Bn(e){let t=bo(e);return t+Math.ceil(t/2)}function Ht(e,t,n=!1){N(e);let r=e.length,o=bo(t),s=Bn(t);if(r<16||r<s||r>1024)throw new Error("expected "+s+"-1024 bytes of input, got "+r);let i=n?wn(e):Ue(e),a=me(i,t-se)+se;return n?xn(a,o):Ct(a,o)}var ot=BigInt(0),Fe=BigInt(1);function wt(e,t){let n=t.negate();return e?n:t}function Ln(e,t){let n=It(e.Fp,t.map(r=>r.Z));return t.map((r,o)=>e.fromAffine(r.toAffine(n[o])))}function vo(e,t){if(!Number.isSafeInteger(e)||e<=0||e>t)throw new Error("invalid window size, expected [1.."+t+"], got W="+e)}function Rn(e,t){vo(e,t);let n=Math.ceil(t/e)+1,r=2**(e-1),o=2**e,s=bt(e),i=BigInt(e);return{windows:n,windowSize:r,mask:s,maxNumber:o,shiftBy:i}}function mo(e,t,n){let{windowSize:r,mask:o,maxNumber:s,shiftBy:i}=n,a=Number(e&o),c=e>>i;a>r&&(a-=s,c+=Fe);let l=t*r,f=l+Math.abs(a)-1,h=a===0,d=a<0,p=t%2!==0;return{nextN:c,offset:f,isZero:h,isNeg:d,isNegF:p,offsetF:l}}var _n=new WeakMap,Eo=new WeakMap;function kn(e){return Eo.get(e)||1}function wo(e){if(e!==ot)throw new Error("invalid wNAF")}var Ot=class{constructor(t,n){u(this,"BASE");u(this,"ZERO");u(this,"Fn");u(this,"bits");this.BASE=t.BASE,this.ZERO=t.ZERO,this.Fn=t.Fn,this.bits=n}_unsafeLadder(t,n,r=this.ZERO){let o=t;for(;n>ot;)n&Fe&&(r=r.add(o)),o=o.double(),n>>=Fe;return r}precomputeWindow(t,n){let{windows:r,windowSize:o}=Rn(n,this.bits),s=[],i=t,a=i;for(let c=0;c<r;c++){a=i,s.push(a);for(let l=1;l<o;l++)a=a.add(i),s.push(a);i=a.double()}return s}wNAF(t,n,r){if(!this.Fn.isValid(r))throw new Error("invalid scalar");let o=this.ZERO,s=this.BASE,i=Rn(t,this.bits);for(let a=0;a<i.windows;a++){let{nextN:c,offset:l,isZero:f,isNeg:h,isNegF:d,offsetF:p}=mo(r,a,i);r=c,f?s=s.add(wt(d,n[p])):o=o.add(wt(h,n[l]))}return wo(r),{p:o,f:s}}wNAFUnsafe(t,n,r,o=this.ZERO){let s=Rn(t,this.bits);for(let i=0;i<s.windows&&r!==ot;i++){let{nextN:a,offset:c,isZero:l,isNeg:f}=mo(r,i,s);if(r=a,!l){let h=n[c];o=o.add(f?h.negate():h)}}return wo(r),o}getPrecomputes(t,n,r){let o=_n.get(n);return o||(o=this.precomputeWindow(n,t),t!==1&&(typeof r=="function"&&(o=r(o)),_n.set(n,o))),o}cached(t,n,r){let o=kn(t);return this.wNAF(o,this.getPrecomputes(o,t,r),n)}unsafe(t,n,r,o){let s=kn(t);return s===1?this._unsafeLadder(t,n,o):this.wNAFUnsafe(s,this.getPrecomputes(s,t,r),n,o)}createCache(t,n){vo(n,this.bits),Eo.set(t,n),_n.delete(t)}hasCache(t){return kn(t)!==1}};function So(e,t,n,r){let o=t,s=e.ZERO,i=e.ZERO;for(;n>ot||r>ot;)n&Fe&&(s=s.add(o)),r&Fe&&(i=i.add(o)),o=o.double(),n>>=Fe,r>>=Fe;return{p1:s,p2:i}}function xo(e,t,n){if(t){if(t.ORDER!==e)throw new Error("Field.ORDER must match order: Fp == p, Fn == n");return Tn(t),t}else return rt(e,{isLE:n})}function Ao(e,t,n={},r){if(r===void 0&&(r=e==="edwards"),!t||typeof t!="object")throw new Error(`expected valid ${e} CURVE object`);for(let c of["p","n","h"]){let l=t[c];if(!(typeof l=="bigint"&&l>ot))throw new Error(`CURVE.${c} must be positive bigint`)}let o=xo(t.p,n.Fp,r),s=xo(t.n,n.Fn,r),a=["Gx","Gy","a",e==="weierstrass"?"b":"d"];for(let c of a)if(!o.isValid(t[c]))throw new Error(`CURVE.${c} must be valid field element of CURVE.Fp`);return t=Object.freeze(Object.assign({},t)),{CURVE:t,Fp:o,Fn:s}}function Ut(e,t){return function(r){let o=e(r);return{secretKey:o,publicKey:t(o)}}}var Pt=class{constructor(t,n){u(this,"oHash");u(this,"iHash");u(this,"blockLen");u(this,"outputLen");u(this,"finished",!1);u(this,"destroyed",!1);if(Bt(t),N(n,void 0,"key"),this.iHash=t.create(),typeof this.iHash.update!="function")throw new Error("Expected instance of class which extends utils.Hash");this.blockLen=this.iHash.blockLen,this.outputLen=this.iHash.outputLen;let r=this.blockLen,o=new Uint8Array(r);o.set(n.length>r?t.create().update(n).digest():n);for(let s=0;s<o.length;s++)o[s]^=54;this.iHash.update(o),this.oHash=t.create();for(let s=0;s<o.length;s++)o[s]^=106;this.oHash.update(o),$e(o)}update(t){return nt(this),this.iHash.update(t),this}digestInto(t){nt(this),N(t,this.outputLen,"output"),this.finished=!0,this.iHash.digestInto(t),this.oHash.update(t),this.oHash.digestInto(t),this.destroy()}digest(){let t=new Uint8Array(this.oHash.outputLen);return this.digestInto(t),t}_cloneInto(t){t||(t=Object.create(Object.getPrototypeOf(this),{}));let{oHash:n,iHash:r,finished:o,destroyed:s,blockLen:i,outputLen:a}=this;return t=t,t.finished=o,t.destroyed=s,t.blockLen=i,t.outputLen=a,t.oHash=n._cloneInto(t.oHash),t.iHash=r._cloneInto(t.iHash),t}clone(){return this._cloneInto()}destroy(){this.destroyed=!0,this.oHash.destroy(),this.iHash.destroy()}},Cn=(e,t,n)=>new Pt(e,t).update(n).digest();Cn.create=(e,t)=>new Pt(e,t);var To=(e,t)=>(e+(e>=0?t:-t)/Bo)/t;function $i(e,t,n){let[[r,o],[s,i]]=t,a=To(i*e,n),c=To(-o*e,n),l=e-a*r-c*s,f=-a*o-c*i,h=l<Te,d=f<Te;h&&(l=-l),d&&(f=-f);let p=bt(Math.ceil(vn(n)/2))+st;if(l<Te||l>=p||f<Te||f>=p)throw new Error("splitScalar (endomorphism): failed, k="+e);return{k1neg:h,k1:l,k2neg:d,k2:f}}function Hn(e){if(!["compact","recovered","der"].includes(e))throw new Error('Signature format must be "compact", "recovered", or "der"');return e}function In(e,t){let n={};for(let r of Object.keys(t))n[r]=e[r]===void 0?t[r]:e[r];return yt(n.lowS,"lowS"),yt(n.prehash,"prehash"),n.format!==void 0&&Hn(n.format),n}var On=class extends Error{constructor(t=""){super(t)}},Pe={Err:On,_tlv:{encode:(e,t)=>{let{Err:n}=Pe;if(e<0||e>256)throw new n("tlv.encode: wrong tag");if(t.length&1)throw new n("tlv.encode: unpadded data");let r=t.length/2,o=gt(r);if(o.length/2&128)throw new n("tlv.encode: long form length too big");let s=r>127?gt(o.length/2|128):"";return gt(e)+s+o+t},decode(e,t){let{Err:n}=Pe,r=0;if(e<0||e>256)throw new n("tlv.encode: wrong tag");if(t.length<2||t[r++]!==e)throw new n("tlv.decode: wrong tlv");let o=t[r++],s=!!(o&128),i=0;if(!s)i=o;else{let c=o&127;if(!c)throw new n("tlv.decode(long): indefinite length not supported");if(c>4)throw new n("tlv.decode(long): byte length is too big");let l=t.subarray(r,r+c);if(l.length!==c)throw new n("tlv.decode: length bytes not complete");if(l[0]===0)throw new n("tlv.decode(long): zero leftmost byte");for(let f of l)i=i<<8|f;if(r+=c,i<128)throw new n("tlv.decode(long): not minimal encoding")}let a=t.subarray(r,r+i);if(a.length!==i)throw new n("tlv.decode: wrong value length");return{v:a,l:t.subarray(r+i)}}},_int:{encode(e){let{Err:t}=Pe;if(e<Te)throw new t("integer: negative integers are not allowed");let n=gt(e);if(Number.parseInt(n[0],16)&8&&(n="00"+n),n.length&1)throw new t("unexpected DER parsing assertion: unpadded hex");return n},decode(e){let{Err:t}=Pe;if(e[0]&128)throw new t("invalid signature integer: negative");if(e[0]===0&&!(e[1]&128))throw new t("invalid signature integer: unnecessary leading zero");return Ue(e)}},toSig(e){let{Err:t,_int:n,_tlv:r}=Pe,o=N(e,void 0,"signature"),{v:s,l:i}=r.decode(48,o);if(i.length)throw new t("invalid signature: left bytes after parsing");let{v:a,l:c}=r.decode(2,s),{v:l,l:f}=r.decode(2,c);if(f.length)throw new t("invalid signature: left bytes after parsing");return{r:n.decode(a),s:n.decode(l)}},hexFromSig(e){let{_tlv:t,_int:n}=Pe,r=t.encode(2,n.encode(e.r)),o=t.encode(2,n.encode(e.s)),s=r+o;return t.encode(48,s)}},Te=BigInt(0),st=BigInt(1),Bo=BigInt(2),Nt=BigInt(3),Wi=BigInt(4);function Ro(e,t={}){let n=Ao("weierstrass",e,t),{Fp:r,Fn:o}=n,s=n.CURVE,{h:i,n:a}=s;mt(t,{},{allowInfinityPoint:"boolean",clearCofactor:"function",isTorsionFree:"function",fromBytes:"function",toBytes:"function",endo:"object"});let{endo:c}=t;if(c&&(!r.is0(s.a)||typeof c.beta!="bigint"||!Array.isArray(c.basises)))throw new Error('invalid endo: expected "beta": bigint and "basises": array');let l=ko(r,o);function f(){if(!r.isOdd)throw new Error("compression is not supported: Field does not have .isOdd()")}function h(L,b,g){let{x:E,y:S}=b.toAffine(),B=r.toBytes(E);if(yt(g,"isCompressed"),g){f();let v=!r.isOdd(S);return ce(_o(v),B)}else return ce(Uint8Array.of(4),B,r.toBytes(S))}function d(L){N(L,void 0,"Point");let{publicKey:b,publicKeyUncompressed:g}=l,E=L.length,S=L[0],B=L.subarray(1);if(E===b&&(S===2||S===3)){let v=r.fromBytes(B);if(!r.isValid(v))throw new Error("bad point: is not on curve, wrong x");let R=m(v),T;try{T=r.sqrt(R)}catch(K){let q=K instanceof Error?": "+K.message:"";throw new Error("bad point: is not on curve, sqrt error"+q)}f();let _=r.isOdd(T);return(S&1)===1!==_&&(T=r.neg(T)),{x:v,y:T}}else if(E===g&&S===4){let v=r.BYTES,R=r.fromBytes(B.subarray(0,v)),T=r.fromBytes(B.subarray(v,v*2));if(!w(R,T))throw new Error("bad point: is not on curve");return{x:R,y:T}}else throw new Error(`bad point: got length ${E}, expected compressed=${b} or uncompressed=${g}`)}let p=t.toBytes||h,y=t.fromBytes||d;function m(L){let b=r.sqr(L),g=r.mul(b,L);return r.add(r.add(g,r.mul(L,s.a)),s.b)}function w(L,b){let g=r.sqr(b),E=m(L);return r.eql(g,E)}if(!w(s.Gx,s.Gy))throw new Error("bad curve params: generator point");let x=r.mul(r.pow(s.a,Nt),Wi),A=r.mul(r.sqr(s.b),BigInt(27));if(r.is0(r.add(x,A)))throw new Error("bad curve params: a or b");function I(L,b,g=!1){if(!r.isValid(b)||g&&r.is0(b))throw new Error(`bad point coordinate ${L}`);return b}function P(L){if(!(L instanceof U))throw new Error("Weierstrass Point expected")}function Q(L){if(!c||!c.basises)throw new Error("no endo");return $i(L,c.basises,o.ORDER)}let V=En((L,b)=>{let{X:g,Y:E,Z:S}=L;if(r.eql(S,r.ONE))return{x:g,y:E};let B=L.is0();b==null&&(b=B?r.ONE:r.inv(S));let v=r.mul(g,b),R=r.mul(E,b),T=r.mul(S,b);if(B)return{x:r.ZERO,y:r.ZERO};if(!r.eql(T,r.ONE))throw new Error("invZ was invalid");return{x:v,y:R}}),Z=En(L=>{if(L.is0()){if(t.allowInfinityPoint&&!r.is0(L.Y))return;throw new Error("bad point: ZERO")}let{x:b,y:g}=L.toAffine();if(!r.isValid(b)||!r.isValid(g))throw new Error("bad point: x or y not field elements");if(!w(b,g))throw new Error("bad point: equation left != right");if(!L.isTorsionFree())throw new Error("bad point: not in prime-order subgroup");return!0});function j(L,b,g,E,S){return g=new U(r.mul(g.X,L),g.Y,g.Z),b=wt(E,b),g=wt(S,g),b.add(g)}let C=class C{constructor(b,g,E){u(this,"X");u(this,"Y");u(this,"Z");this.X=I("x",b),this.Y=I("y",g,!0),this.Z=I("z",E),Object.freeze(this)}static CURVE(){return s}static fromAffine(b){let{x:g,y:E}=b||{};if(!b||!r.isValid(g)||!r.isValid(E))throw new Error("invalid affine point");if(b instanceof C)throw new Error("projective point not allowed");return r.is0(g)&&r.is0(E)?C.ZERO:new C(g,E,r.ONE)}static fromBytes(b){let g=C.fromAffine(y(N(b,void 0,"point")));return g.assertValidity(),g}static fromHex(b){return C.fromBytes(Ve(b))}get x(){return this.toAffine().x}get y(){return this.toAffine().y}precompute(b=8,g=!0){return M.createCache(this,b),g||this.multiply(Nt),this}assertValidity(){Z(this)}hasEvenY(){let{y:b}=this.toAffine();if(!r.isOdd)throw new Error("Field doesn't support isOdd");return!r.isOdd(b)}equals(b){P(b);let{X:g,Y:E,Z:S}=this,{X:B,Y:v,Z:R}=b,T=r.eql(r.mul(g,R),r.mul(B,S)),_=r.eql(r.mul(E,R),r.mul(v,S));return T&&_}negate(){return new C(this.X,r.neg(this.Y),this.Z)}double(){let{a:b,b:g}=s,E=r.mul(g,Nt),{X:S,Y:B,Z:v}=this,R=r.ZERO,T=r.ZERO,_=r.ZERO,H=r.mul(S,S),K=r.mul(B,B),q=r.mul(v,v),O=r.mul(S,B);return O=r.add(O,O),_=r.mul(S,v),_=r.add(_,_),R=r.mul(b,_),T=r.mul(E,q),T=r.add(R,T),R=r.sub(K,T),T=r.add(K,T),T=r.mul(R,T),R=r.mul(O,R),_=r.mul(E,_),q=r.mul(b,q),O=r.sub(H,q),O=r.mul(b,O),O=r.add(O,_),_=r.add(H,H),H=r.add(_,H),H=r.add(H,q),H=r.mul(H,O),T=r.add(T,H),q=r.mul(B,v),q=r.add(q,q),H=r.mul(q,O),R=r.sub(R,H),_=r.mul(q,K),_=r.add(_,_),_=r.add(_,_),new C(R,T,_)}add(b){P(b);let{X:g,Y:E,Z:S}=this,{X:B,Y:v,Z:R}=b,T=r.ZERO,_=r.ZERO,H=r.ZERO,K=s.a,q=r.mul(s.b,Nt),O=r.mul(g,B),z=r.mul(E,v),J=r.mul(S,R),Y=r.add(g,E),X=r.add(B,v);Y=r.mul(Y,X),X=r.add(O,z),Y=r.sub(Y,X),X=r.add(g,S);let ie=r.add(B,R);return X=r.mul(X,ie),ie=r.add(O,J),X=r.sub(X,ie),ie=r.add(E,S),T=r.add(v,R),ie=r.mul(ie,T),T=r.add(z,J),ie=r.sub(ie,T),H=r.mul(K,X),T=r.mul(q,J),H=r.add(T,H),T=r.sub(z,H),H=r.add(z,H),_=r.mul(T,H),z=r.add(O,O),z=r.add(z,O),J=r.mul(K,J),X=r.mul(q,X),z=r.add(z,J),J=r.sub(O,J),J=r.mul(K,J),X=r.add(X,J),O=r.mul(z,X),_=r.add(_,O),O=r.mul(ie,X),T=r.mul(Y,T),T=r.sub(T,O),O=r.mul(Y,z),H=r.mul(ie,H),H=r.add(H,O),new C(T,_,H)}subtract(b){return this.add(b.negate())}is0(){return this.equals(C.ZERO)}multiply(b){let{endo:g}=t;if(!o.isValidNot0(b))throw new Error("invalid scalar: out of range");let E,S,B=v=>M.cached(this,v,R=>Ln(C,R));if(g){let{k1neg:v,k1:R,k2neg:T,k2:_}=Q(b),{p:H,f:K}=B(R),{p:q,f:O}=B(_);S=K.add(O),E=j(g.beta,H,q,v,T)}else{let{p:v,f:R}=B(b);E=v,S=R}return Ln(C,[E,S])[0]}multiplyUnsafe(b){let{endo:g}=t,E=this;if(!o.isValid(b))throw new Error("invalid scalar: out of range");if(b===Te||E.is0())return C.ZERO;if(b===st)return E;if(M.hasCache(this))return this.multiply(b);if(g){let{k1neg:S,k1:B,k2neg:v,k2:R}=Q(b),{p1:T,p2:_}=So(C,E,B,R);return j(g.beta,T,_,S,v)}else return M.unsafe(E,b)}toAffine(b){return V(this,b)}isTorsionFree(){let{isTorsionFree:b}=t;return i===st?!0:b?b(C,this):M.unsafe(this,a).is0()}clearCofactor(){let{clearCofactor:b}=t;return i===st?this:b?b(C,this):this.multiplyUnsafe(i)}isSmallOrder(){return this.multiplyUnsafe(i).is0()}toBytes(b=!0){return yt(b,"isCompressed"),this.assertValidity(),p(C,this,b)}toHex(b=!0){return We(this.toBytes(b))}toString(){return`<Point ${this.is0()?"ZERO":this.toHex()}>`}};u(C,"BASE",new C(s.Gx,s.Gy,r.ONE)),u(C,"ZERO",new C(r.ZERO,r.ONE,r.ZERO)),u(C,"Fp",r),u(C,"Fn",o);let U=C,W=o.BITS,M=new Ot(U,t.endo?Math.ceil(W/2):W);return U.BASE.precompute(8),U}function _o(e){return Uint8Array.of(e?2:3)}function ko(e,t){return{secretKey:t.BYTES,publicKey:1+e.BYTES,publicKeyUncompressed:1+2*e.BYTES,publicKeyHasPrefix:!0,signature:2*t.BYTES}}function Vi(e,t={}){let{Fn:n}=e,r=t.randomBytes||Ge,o=Object.assign(ko(e.Fp,n),{seed:Bn(n.ORDER)});function s(p){try{let y=n.fromBytes(p);return n.isValidNot0(y)}catch{return!1}}function i(p,y){let{publicKey:m,publicKeyUncompressed:w}=o;try{let x=p.length;return y===!0&&x!==m||y===!1&&x!==w?!1:!!e.fromBytes(p)}catch{return!1}}function a(p=r(o.seed)){return Ht(N(p,o.seed,"seed"),n.ORDER)}function c(p,y=!0){return e.BASE.multiply(n.fromBytes(p)).toBytes(y)}function l(p){let{secretKey:y,publicKey:m,publicKeyUncompressed:w}=o;if(!pt(p)||"_lengths"in n&&n._lengths||y===m)return;let x=N(p,void 0,"key").length;return x===m||x===w}function f(p,y,m=!0){if(l(p)===!0)throw new Error("first arg must be private key");if(l(y)===!1)throw new Error("second arg must be public key");let w=n.fromBytes(p);return e.fromBytes(y).multiply(w).toBytes(m)}let h={isValidSecretKey:s,isValidPublicKey:i,randomSecretKey:a},d=Ut(a,c);return Object.freeze({getPublicKey:c,getSharedSecret:f,keygen:d,Point:e,utils:h,lengths:o})}function Lo(e,t,n={}){Bt(t),mt(n,{},{hmac:"function",lowS:"boolean",randomBytes:"function",bits2int:"function",bits2int_modN:"function"}),n=Object.assign({},n);let r=n.randomBytes||Ge,o=n.hmac||((b,g)=>Cn(t,b,g)),{Fp:s,Fn:i}=e,{ORDER:a,BITS:c}=i,{keygen:l,getPublicKey:f,getSharedSecret:h,utils:d,lengths:p}=Vi(e,n),y={prehash:!0,lowS:typeof n.lowS=="boolean"?n.lowS:!0,format:"compact",extraEntropy:!1},m=a*Bo<s.ORDER;function w(b){let g=a>>st;return b>g}function x(b,g){if(!i.isValidNot0(g))throw new Error(`invalid signature ${b}: out of range 1..Point.Fn.ORDER`);return g}function A(){if(m)throw new Error('"recovered" sig type is not supported for cofactor >2 curves')}function I(b,g){Hn(g);let E=p.signature,S=g==="compact"?E:g==="recovered"?E+1:void 0;return N(b,S)}class P{constructor(g,E,S){u(this,"r");u(this,"s");u(this,"recovery");if(this.r=x("r",g),this.s=x("s",E),S!=null){if(A(),![0,1,2,3].includes(S))throw new Error("invalid recovery id");this.recovery=S}Object.freeze(this)}static fromBytes(g,E=y.format){I(g,E);let S;if(E==="der"){let{r:T,s:_}=Pe.toSig(N(g));return new P(T,_)}E==="recovered"&&(S=g[0],E="compact",g=g.subarray(1));let B=p.signature/2,v=g.subarray(0,B),R=g.subarray(B,B*2);return new P(i.fromBytes(v),i.fromBytes(R),S)}static fromHex(g,E){return this.fromBytes(Ve(g),E)}assertRecovery(){let{recovery:g}=this;if(g==null)throw new Error("invalid recovery id: must be present");return g}addRecoveryBit(g){return new P(this.r,this.s,g)}recoverPublicKey(g){let{r:E,s:S}=this,B=this.assertRecovery(),v=B===2||B===3?E+a:E;if(!s.isValid(v))throw new Error("invalid recovery id: sig.r+curve.n != R.x");let R=s.toBytes(v),T=e.fromBytes(ce(_o((B&1)===0),R)),_=i.inv(v),H=V(N(g,void 0,"msgHash")),K=i.create(-H*_),q=i.create(S*_),O=e.BASE.multiplyUnsafe(K).add(T.multiplyUnsafe(q));if(O.is0())throw new Error("invalid recovery: point at infinify");return O.assertValidity(),O}hasHighS(){return w(this.s)}toBytes(g=y.format){if(Hn(g),g==="der")return Ve(Pe.hexFromSig(this));let{r:E,s:S}=this,B=i.toBytes(E),v=i.toBytes(S);return g==="recovered"?(A(),ce(Uint8Array.of(this.assertRecovery()),B,v)):ce(B,v)}toHex(g){return We(this.toBytes(g))}}let Q=n.bits2int||function(g){if(g.length>8192)throw new Error("input is too large");let E=Ue(g),S=g.length*8-c;return S>0?E>>BigInt(S):E},V=n.bits2int_modN||function(g){return i.create(Q(g))},Z=bt(c);function j(b){return so("num < 2^"+c,b,Te,Z),i.toBytes(b)}function U(b,g){return N(b,void 0,"message"),g?N(t(b),void 0,"prehashed message"):b}function W(b,g,E){let{lowS:S,prehash:B,extraEntropy:v}=In(E,y);b=U(b,B);let R=V(b),T=i.fromBytes(g);if(!i.isValidNot0(T))throw new Error("invalid private key");let _=[j(T),j(R)];if(v!=null&&v!==!1){let O=v===!0?r(p.secretKey):v;_.push(N(O,void 0,"extraEntropy"))}let H=ce(..._),K=R;function q(O){let z=Q(O);if(!i.isValidNot0(z))return;let J=i.inv(z),Y=e.BASE.multiply(z).toAffine(),X=i.create(Y.x);if(X===Te)return;let ie=i.create(J*i.create(K+X*T));if(ie===Te)return;let jr=(Y.x===X?0:2)|Number(Y.y&st),zr=ie;return S&&w(ie)&&(zr=i.neg(ie),jr^=1),new P(X,zr,m?void 0:jr)}return{seed:H,k2sig:q}}function M(b,g,E={}){let{seed:S,k2sig:B}=W(b,g,E);return io(t.outputLen,i.BYTES,o)(S,B).toBytes(E.format)}function C(b,g,E,S={}){let{lowS:B,prehash:v,format:R}=In(S,y);if(E=N(E,void 0,"publicKey"),g=U(g,v),!pt(b)){let T=b instanceof P?", use sig.toBytes()":"";throw new Error("verify expects Uint8Array signature"+T)}I(b,R);try{let T=P.fromBytes(b,R),_=e.fromBytes(E);if(B&&T.hasHighS())return!1;let{r:H,s:K}=T,q=V(g),O=i.inv(K),z=i.create(q*O),J=i.create(H*O),Y=e.BASE.multiplyUnsafe(z).add(_.multiplyUnsafe(J));return Y.is0()?!1:i.create(Y.x)===H}catch{return!1}}function L(b,g,E={}){let{prehash:S}=In(E,y);return g=U(g,S),P.fromBytes(b,"recovered").recoverPublicKey(g).toBytes()}return Object.freeze({keygen:l,getPublicKey:f,getSharedSecret:h,utils:d,lengths:p,Point:e,sign:M,verify:C,recoverPublicKey:L,Signature:P,hash:t})}var Dt={p:BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),n:BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),h:BigInt(1),a:BigInt(0),b:BigInt(7),Gx:BigInt("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),Gy:BigInt("0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")},Gi={beta:BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"),basises:[[BigInt("0x3086d221a7d46bcde86c90e49284eb15"),-BigInt("0xe4437ed6010e88286f547fa90abfe4c3")],[BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"),BigInt("0x3086d221a7d46bcde86c90e49284eb15")]]},Ki=BigInt(0),Un=BigInt(2);function Fi(e){let t=Dt.p,n=BigInt(3),r=BigInt(6),o=BigInt(11),s=BigInt(22),i=BigInt(23),a=BigInt(44),c=BigInt(88),l=e*e*e%t,f=l*l*e%t,h=fe(f,n,t)*f%t,d=fe(h,n,t)*f%t,p=fe(d,Un,t)*l%t,y=fe(p,o,t)*p%t,m=fe(y,s,t)*y%t,w=fe(m,a,t)*m%t,x=fe(w,c,t)*w%t,A=fe(x,a,t)*m%t,I=fe(A,n,t)*f%t,P=fe(I,i,t)*y%t,Q=fe(P,r,t)*l%t,V=fe(Q,Un,t);if(!Mt.eql(Mt.sqr(V),e))throw new Error("Cannot find square root");return V}var Mt=rt(Dt.p,{sqrt:Fi}),je=Ro(Dt,{Fp:Mt,endo:Gi}),ze=Lo(je,kt),Co={};function qt(e,...t){let n=Co[e];if(n===void 0){let r=kt(oo(e));n=ce(r,r),Co[e]=n}return kt(ce(n,...t))}var Nn=e=>e.toBytes(!0).slice(1),Mn=e=>e%Un===Ki;function Pn(e){let{Fn:t,BASE:n}=je,r=t.fromBytes(e),o=n.multiply(r);return{scalar:Mn(o.y)?r:t.neg(r),bytes:Nn(o)}}function Ho(e){let t=Mt;if(!t.isValidNot0(e))throw new Error("invalid x: Fail if x \u2265 p");let n=t.create(e*e),r=t.create(n*e+BigInt(7)),o=t.sqrt(r);Mn(o)||(o=t.neg(o));let s=je.fromAffine({x:e,y:o});return s.assertValidity(),s}var xt=Ue;function Oo(...e){return je.Fn.create(xt(qt("BIP0340/challenge",...e)))}function Io(e){return Pn(e).bytes}function ji(e,t,n=Ge(32)){let{Fn:r}=je,o=N(e,void 0,"message"),{bytes:s,scalar:i}=Pn(t),a=N(n,32,"auxRand"),c=r.toBytes(i^xt(qt("BIP0340/aux",a))),l=qt("BIP0340/nonce",c,s,o),{bytes:f,scalar:h}=Pn(l),d=Oo(f,s,o),p=new Uint8Array(64);if(p.set(f,0),p.set(r.toBytes(r.create(h+d*i)),32),!Uo(p,o,s))throw new Error("sign: Invalid signature produced");return p}function Uo(e,t,n){let{Fp:r,Fn:o,BASE:s}=je,i=N(e,64,"signature"),a=N(t,void 0,"message"),c=N(n,32,"publicKey");try{let l=Ho(xt(c)),f=xt(i.subarray(0,32));if(!r.isValidNot0(f))return!1;let h=xt(i.subarray(32,64));if(!o.isValidNot0(h))return!1;let d=Oo(o.toBytes(f),Nn(l),a),p=s.multiplyUnsafe(h).add(l.multiplyUnsafe(o.neg(d))),{x:y,y:m}=p.toAffine();return!(p.is0()||!Mn(m)||y!==f)}catch{return!1}}var he=(()=>{let n=(r=Ge(48))=>Ht(r,Dt.n);return{keygen:Ut(n,Io),getPublicKey:Io,sign:ji,verify:Uo,Point:je,utils:{randomSecretKey:n,taggedHash:qt,lift_x:Ho,pointToBytes:Nn},lengths:{secretKey:32,publicKey:32,publicKeyHasPrefix:!1,signature:64,seed:48}}})();function zi(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function $t(e,t=""){if(!Number.isSafeInteger(e)||e<0){let n=t&&`"${t}" `;throw new Error(`${n}expected integer >= 0, got ${e}`)}}function ve(e,t,n=""){let r=zi(e),o=e?.length,s=t!==void 0;if(!r||s&&o!==t){let i=n&&`"${n}" `,a=s?` of length ${t}`:"",c=r?`length=${o}`:`type=${typeof e}`;throw new Error(i+"expected Uint8Array"+a+", got "+c)}return e}function vt(e){if(typeof e!="function"||typeof e.create!="function")throw new Error("Hash must wrapped by utils.createHasher");$t(e.outputLen),$t(e.blockLen)}function it(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")}function No(e,t){ve(e,void 0,"digestInto() output");let n=t.outputLen;if(e.length<n)throw new Error('"digestInto() output" expected to be of length >='+n)}function Re(...e){for(let t=0;t<e.length;t++)e[t].fill(0)}function Wt(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}function we(e,t){return e<<32-t|e>>>t}var Mo=typeof Uint8Array.from([]).toHex=="function"&&typeof Uint8Array.fromHex=="function",Zi=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));function D(e){if(ve(e),Mo)return e.toHex();let t="";for(let n=0;n<e.length;n++)t+=Zi[e[n]];return t}var Be={_0:48,_9:57,A:65,F:70,a:97,f:102};function Po(e){if(e>=Be._0&&e<=Be._9)return e-Be._0;if(e>=Be.A&&e<=Be.F)return e-(Be.A-10);if(e>=Be.a&&e<=Be.f)return e-(Be.a-10)}function $(e){if(typeof e!="string")throw new Error("hex string expected, got "+typeof e);if(Mo)return Uint8Array.fromHex(e);let t=e.length,n=t/2;if(t%2)throw new Error("hex string expected, got unpadded hex of length "+t);let r=new Uint8Array(n);for(let o=0,s=0;o<n;o++,s+=2){let i=Po(e.charCodeAt(s)),a=Po(e.charCodeAt(s+1));if(i===void 0||a===void 0){let c=e[s]+e[s+1];throw new Error('hex string expected, got non-hex character "'+c+'" at index '+s)}r[o]=i*16+a}return r}function de(...e){let t=0;for(let r=0;r<e.length;r++){let o=e[r];ve(o),t+=o.length}let n=new Uint8Array(t);for(let r=0,o=0;r<e.length;r++){let s=e[r];n.set(s,o),o+=s.length}return n}function qo(e,t={}){let n=(o,s)=>e(s).update(o).digest(),r=e(void 0);return n.outputLen=r.outputLen,n.blockLen=r.blockLen,n.create=o=>e(o),Object.assign(n,t),Object.freeze(n)}function at(e=32){let t=typeof globalThis=="object"?globalThis.crypto:null;if(typeof t?.getRandomValues!="function")throw new Error("crypto.getRandomValues must be defined");return t.getRandomValues(new Uint8Array(e))}var Do=e=>({oid:Uint8Array.from([6,9,96,134,72,1,101,3,4,2,e])});function $o(e,t,n){return e&t^~e&n}function Wo(e,t,n){return e&t^e&n^t&n}var Vt=class{constructor(t,n,r,o){u(this,"blockLen");u(this,"outputLen");u(this,"padOffset");u(this,"isLE");u(this,"buffer");u(this,"view");u(this,"finished",!1);u(this,"length",0);u(this,"pos",0);u(this,"destroyed",!1);this.blockLen=t,this.outputLen=n,this.padOffset=r,this.isLE=o,this.buffer=new Uint8Array(t),this.view=Wt(this.buffer)}update(t){it(this),ve(t);let{view:n,buffer:r,blockLen:o}=this,s=t.length;for(let i=0;i<s;){let a=Math.min(o-this.pos,s-i);if(a===o){let c=Wt(t);for(;o<=s-i;i+=o)this.process(c,i);continue}r.set(t.subarray(i,i+a),this.pos),this.pos+=a,i+=a,this.pos===o&&(this.process(n,0),this.pos=0)}return this.length+=t.length,this.roundClean(),this}digestInto(t){it(this),No(t,this),this.finished=!0;let{buffer:n,view:r,blockLen:o,isLE:s}=this,{pos:i}=this;n[i++]=128,Re(this.buffer.subarray(i)),this.padOffset>o-i&&(this.process(r,0),i=0);for(let h=i;h<o;h++)n[h]=0;r.setBigUint64(o-8,BigInt(this.length*8),s),this.process(r,0);let a=Wt(t),c=this.outputLen;if(c%4)throw new Error("_sha2: outputLen must be aligned to 32bit");let l=c/4,f=this.get();if(l>f.length)throw new Error("_sha2: outputLen bigger than state");for(let h=0;h<l;h++)a.setUint32(4*h,f[h],s)}digest(){let{buffer:t,outputLen:n}=this;this.digestInto(t);let r=t.slice(0,n);return this.destroy(),r}_cloneInto(t){t||(t=new this.constructor),t.set(...this.get());let{blockLen:n,buffer:r,length:o,finished:s,destroyed:i,pos:a}=this;return t.destroyed=i,t.finished=s,t.length=o,t.pos=a,o%n&&t.buffer.set(r),t}clone(){return this._cloneInto()}},_e=Uint32Array.from([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]);var Ji=Uint32Array.from([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),Ne=new Uint32Array(64),qn=class extends Vt{constructor(t){super(64,t,8,!1)}get(){let{A:t,B:n,C:r,D:o,E:s,F:i,G:a,H:c}=this;return[t,n,r,o,s,i,a,c]}set(t,n,r,o,s,i,a,c){this.A=t|0,this.B=n|0,this.C=r|0,this.D=o|0,this.E=s|0,this.F=i|0,this.G=a|0,this.H=c|0}process(t,n){for(let h=0;h<16;h++,n+=4)Ne[h]=t.getUint32(n,!1);for(let h=16;h<64;h++){let d=Ne[h-15],p=Ne[h-2],y=we(d,7)^we(d,18)^d>>>3,m=we(p,17)^we(p,19)^p>>>10;Ne[h]=m+Ne[h-7]+y+Ne[h-16]|0}let{A:r,B:o,C:s,D:i,E:a,F:c,G:l,H:f}=this;for(let h=0;h<64;h++){let d=we(a,6)^we(a,11)^we(a,25),p=f+d+$o(a,c,l)+Ji[h]+Ne[h]|0,m=(we(r,2)^we(r,13)^we(r,22))+Wo(r,o,s)|0;f=l,l=c,c=a,a=i+p|0,i=s,s=o,o=r,r=p+m|0}r=r+this.A|0,o=o+this.B|0,s=s+this.C|0,i=i+this.D|0,a=a+this.E|0,c=c+this.F|0,l=l+this.G|0,f=f+this.H|0,this.set(r,o,s,i,a,c,l,f)}roundClean(){Re(Ne)}destroy(){this.set(0,0,0,0,0,0,0,0),Re(this.buffer)}},Dn=class extends qn{constructor(){super(32);u(this,"A",_e[0]|0);u(this,"B",_e[1]|0);u(this,"C",_e[2]|0);u(this,"D",_e[3]|0);u(this,"E",_e[4]|0);u(this,"F",_e[5]|0);u(this,"G",_e[6]|0);u(this,"H",_e[7]|0)}};var te=qo(()=>new Dn,Do(1));function Gn(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function Xi(e){if(!Gn(e))throw new Error("Uint8Array expected")}function Fo(e,t){return Array.isArray(t)?t.length===0?!0:e?t.every(n=>typeof n=="string"):t.every(n=>Number.isSafeInteger(n)):!1}function Yi(e){if(typeof e!="function")throw new Error("function expected");return!0}function Ze(e,t){if(typeof t!="string")throw new Error(`${e}: string expected`);return!0}function Kn(e){if(!Number.isSafeInteger(e))throw new Error(`invalid integer: ${e}`)}function $n(e){if(!Array.isArray(e))throw new Error("array expected")}function Kt(e,t){if(!Fo(!0,t))throw new Error(`${e}: array of strings expected`)}function jo(e,t){if(!Fo(!1,t))throw new Error(`${e}: array of numbers expected`)}function zo(...e){let t=s=>s,n=(s,i)=>a=>s(i(a)),r=e.map(s=>s.encode).reduceRight(n,t),o=e.map(s=>s.decode).reduce(n,t);return{encode:r,decode:o}}function Zo(e){let t=typeof e=="string"?e.split(""):e,n=t.length;Kt("alphabet",t);let r=new Map(t.map((o,s)=>[o,s]));return{encode:o=>($n(o),o.map(s=>{if(!Number.isSafeInteger(s)||s<0||s>=n)throw new Error(`alphabet.encode: digit index outside alphabet "${s}". Allowed: ${e}`);return t[s]})),decode:o=>($n(o),o.map(s=>{Ze("alphabet.decode",s);let i=r.get(s);if(i===void 0)throw new Error(`Unknown letter: "${s}". Allowed: ${e}`);return i}))}}function Jo(e=""){return Ze("join",e),{encode:t=>(Kt("join.decode",t),t.join(e)),decode:t=>(Ze("join.decode",t),t.split(e))}}function Qi(e,t="="){return Kn(e),Ze("padding",t),{encode(n){for(Kt("padding.encode",n);n.length*e%8;)n.push(t);return n},decode(n){Kt("padding.decode",n);let r=n.length;if(r*e%8)throw new Error("padding: invalid, string should have whole number of bytes");for(;r>0&&n[r-1]===t;r--)if((r-1)*e%8===0)throw new Error("padding: invalid, string has too much padding");return n.slice(0,r)}}}var Xo=(e,t)=>t===0?e:Xo(t,e%t),Ft=(e,t)=>e+(t-Xo(e,t)),Gt=(()=>{let e=[];for(let t=0;t<40;t++)e.push(2**t);return e})();function Wn(e,t,n,r){if($n(e),t<=0||t>32)throw new Error(`convertRadix2: wrong from=${t}`);if(n<=0||n>32)throw new Error(`convertRadix2: wrong to=${n}`);if(Ft(t,n)>32)throw new Error(`convertRadix2: carry overflow from=${t} to=${n} carryBits=${Ft(t,n)}`);let o=0,s=0,i=Gt[t],a=Gt[n]-1,c=[];for(let l of e){if(Kn(l),l>=i)throw new Error(`convertRadix2: invalid data word=${l} from=${t}`);if(o=o<<t|l,s+t>32)throw new Error(`convertRadix2: carry overflow pos=${s} from=${t}`);for(s+=t;s>=n;s-=n)c.push((o>>s-n&a)>>>0);let f=Gt[s];if(f===void 0)throw new Error("invalid carry");o&=f-1}if(o=o<<n-s&a,!r&&s>=t)throw new Error("Excess padding");if(!r&&o>0)throw new Error(`Non-zero padding: ${o}`);return r&&s>0&&c.push(o>>>0),c}function Yo(e,t=!1){if(Kn(e),e<=0||e>32)throw new Error("radix2: bits should be in (0..32]");if(Ft(8,e)>32||Ft(e,8)>32)throw new Error("radix2: carry overflow");return{encode:n=>{if(!Gn(n))throw new Error("radix2.encode input should be Uint8Array");return Wn(Array.from(n),8,e,!t)},decode:n=>(jo("radix2.decode",n),Uint8Array.from(Wn(n,e,8,t)))}}function Vo(e){return Yi(e),function(...t){try{return e.apply(null,t)}catch{}}}var ea=typeof Uint8Array.from([]).toBase64=="function"&&typeof Uint8Array.fromBase64=="function",ta=(e,t)=>{Ze("base64",e);let n=t?/^[A-Za-z0-9=_-]+$/:/^[A-Za-z0-9=+/]+$/,r=t?"base64url":"base64";if(e.length>0&&!n.test(e))throw new Error("invalid base64");return Uint8Array.fromBase64(e,{alphabet:r,lastChunkHandling:"strict"})},le=ea?{encode(e){return Xi(e),e.toBase64()},decode(e){return ta(e,!1)}}:zo(Yo(6),Zo("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),Qi(6),Jo(""));var Vn=zo(Zo("qpzry9x8gf2tvdw0s3jn54khce6mua7l"),Jo("")),Go=[996825010,642813549,513874426,1027748829,705979059];function Et(e){let t=e>>25,n=(e&33554431)<<5;for(let r=0;r<Go.length;r++)(t>>r&1)===1&&(n^=Go[r]);return n}function Ko(e,t,n=1){let r=e.length,o=1;for(let s=0;s<r;s++){let i=e.charCodeAt(s);if(i<33||i>126)throw new Error(`Invalid prefix (${e})`);o=Et(o)^i>>5}o=Et(o);for(let s=0;s<r;s++)o=Et(o)^e.charCodeAt(s)&31;for(let s of t)o=Et(o)^s;for(let s=0;s<6;s++)o=Et(o);return o^=n,Vn.encode(Wn([o%Gt[30]],30,5,!1))}function na(e){let t=e==="bech32"?1:734539939,n=Yo(5),r=n.decode,o=n.encode,s=Vo(r);function i(h,d,p=90){Ze("bech32.encode prefix",h),Gn(d)&&(d=Array.from(d)),jo("bech32.encode",d);let y=h.length;if(y===0)throw new TypeError(`Invalid prefix length ${y}`);let m=y+7+d.length;if(p!==!1&&m>p)throw new TypeError(`Length ${m} exceeds limit ${p}`);let w=h.toLowerCase(),x=Ko(w,d,t);return`${w}1${Vn.encode(d)}${x}`}function a(h,d=90){Ze("bech32.decode input",h);let p=h.length;if(p<8||d!==!1&&p>d)throw new TypeError(`invalid string length: ${p} (${h}). Expected (8..${d})`);let y=h.toLowerCase();if(h!==y&&h!==h.toUpperCase())throw new Error("String must be lowercase or uppercase");let m=y.lastIndexOf("1");if(m===0||m===-1)throw new Error('Letter "1" must be present between prefix and data only');let w=y.slice(0,m),x=y.slice(m+1);if(x.length<6)throw new Error("Data must be at least 6 characters long");let A=Vn.decode(x).slice(0,-6),I=Ko(w,A,t);if(!x.endsWith(I))throw new Error(`Invalid checksum in ${h}: expected "${I}"`);return{prefix:w,words:A}}let c=Vo(a);function l(h){let{prefix:d,words:p}=a(h,!1);return{prefix:d,words:p,bytes:r(p)}}function f(h,d){return i(h,o(d))}return{encode:i,decode:a,encodeFromBytes:f,decodeToBytes:l,decodeUnsafe:c,fromWords:r,fromWordsUnsafe:s,toWords:o}}var Me=na("bech32");function ra(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function jt(e){if(typeof e!="boolean")throw new Error(`boolean expected, not ${e}`)}function St(e){if(!Number.isSafeInteger(e)||e<0)throw new Error("positive integer expected, got "+e)}function F(e,t,n=""){let r=ra(e),o=e?.length,s=t!==void 0;if(!r||s&&o!==t){let i=n&&`"${n}" `,a=s?` of length ${t}`:"",c=r?`length=${o}`:`type=${typeof e}`;throw new Error(i+"expected Uint8Array"+a+", got "+c)}return e}function Fn(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")}function Qo(e,t){F(e,void 0,"output");let n=t.outputLen;if(e.length<n)throw new Error("digestInto() expects output buffer of length at least "+n)}function ee(e){return new Uint32Array(e.buffer,e.byteOffset,Math.floor(e.byteLength/4))}function re(...e){for(let t=0;t<e.length;t++)e[t].fill(0)}function es(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}var oa=new Uint8Array(new Uint32Array([287454020]).buffer)[0]===68;function ts(e,t){return e.buffer===t.buffer&&e.byteOffset<t.byteOffset+t.byteLength&&t.byteOffset<e.byteOffset+e.byteLength}function jn(e,t){if(ts(e,t)&&e.byteOffset<t.byteOffset)throw new Error("complex overlap of input and output is not supported")}function ns(e,t){if(t==null||typeof t!="object")throw new Error("options must be defined");return Object.assign(e,t)}function Je(e,t){if(e.length!==t.length)return!1;let n=0;for(let r=0;r<e.length;r++)n|=e[r]^t[r];return n===0}var At=(e,t)=>{function n(r,...o){if(F(r,void 0,"key"),!oa)throw new Error("Non little-endian hardware is not yet supported");if(e.nonceLength!==void 0){let f=o[0];F(f,e.varSizeNonce?void 0:e.nonceLength,"nonce")}let s=e.tagLength;s&&o[1]!==void 0&&F(o[1],void 0,"AAD");let i=t(r,...o),a=(f,h)=>{if(h!==void 0){if(f!==2)throw new Error("cipher output not supported");F(h,void 0,"output")}},c=!1;return{encrypt(f,h){if(c)throw new Error("cannot encrypt() twice with same key + nonce");return c=!0,F(f),a(i.encrypt.length,h),i.encrypt(f,h)},decrypt(f,h){if(F(f),s&&f.length<s)throw new Error('"ciphertext" expected length bigger than tagLength='+s);return a(i.decrypt.length,h),i.decrypt(f,h)}}}return Object.assign(n,e),n};function ct(e,t,n=!0){if(t===void 0)return new Uint8Array(e);if(t.length!==e)throw new Error('"output" expected Uint8Array of length '+e+", got: "+t.length);if(n&&!Xe(t))throw new Error("invalid output, must be aligned");return t}function zn(e,t,n){jt(n);let r=new Uint8Array(16),o=es(r);return o.setBigUint64(0,BigInt(t),n),o.setBigUint64(8,BigInt(e),n),r}function Xe(e){return e.byteOffset%4===0}function pe(e){return Uint8Array.from(e)}var ne=16;var ia=283;function os(e){if(![16,24,32].includes(e.length))throw new Error('"aes key" expected Uint8Array of length 16/24/32, got length='+e.length)}function Qn(e){return e<<1^ia&-(e>>7)}function lt(e,t){let n=0;for(;t>0;t>>=1)n^=e&-(t&1),e=Qn(e);return n}var Xn=(()=>{let e=new Uint8Array(256);for(let n=0,r=1;n<256;n++,r^=Qn(r))e[n]=r;let t=new Uint8Array(256);t[0]=99;for(let n=0;n<255;n++){let r=e[255-n];r|=r<<8,t[e[n]]=(r^r>>4^r>>5^r>>6^r>>7^99)&255}return re(e),t})(),aa=Xn.map((e,t)=>Xn.indexOf(t)),ca=e=>e<<24|e>>>8,Zn=e=>e<<8|e>>>24;function ss(e,t){if(e.length!==256)throw new Error("Wrong sbox length");let n=new Uint32Array(256).map((l,f)=>t(e[f])),r=n.map(Zn),o=r.map(Zn),s=o.map(Zn),i=new Uint32Array(256*256),a=new Uint32Array(256*256),c=new Uint16Array(256*256);for(let l=0;l<256;l++)for(let f=0;f<256;f++){let h=l*256+f;i[h]=n[l]^r[f],a[h]=o[l]^s[f],c[h]=e[l]<<8|e[f]}return{sbox:e,sbox2:c,T0:n,T1:r,T2:o,T3:s,T01:i,T23:a}}var er=ss(Xn,e=>lt(e,3)<<24|e<<16|e<<8|lt(e,2)),is=ss(aa,e=>lt(e,11)<<24|lt(e,13)<<16|lt(e,9)<<8|lt(e,14)),la=(()=>{let e=new Uint8Array(16);for(let t=0,n=1;t<16;t++,n=Qn(n))e[t]=n;return e})();function tr(e){F(e);let t=e.length;os(e);let{sbox2:n}=er,r=[];Xe(e)||r.push(e=pe(e));let o=ee(e),s=o.length,i=c=>Ee(n,c,c,c,c),a=new Uint32Array(t+28);a.set(o);for(let c=s;c<a.length;c++){let l=a[c-1];c%s===0?l=i(ca(l))^la[c/s-1]:s>6&&c%s===4&&(l=i(l)),a[c]=a[c-s]^l}return re(...r),a}function ua(e){let t=tr(e),n=t.slice(),r=t.length,{sbox2:o}=er,{T0:s,T1:i,T2:a,T3:c}=is;for(let l=0;l<r;l+=4)for(let f=0;f<4;f++)n[l+f]=t[r-l-4+f];re(t);for(let l=4;l<r-4;l++){let f=n[l],h=Ee(o,f,f,f,f);n[l]=s[h&255]^i[h>>>8&255]^a[h>>>16&255]^c[h>>>24]}return n}function qe(e,t,n,r,o,s){return e[n<<8&65280|r>>>8&255]^t[o>>>8&65280|s>>>24&255]}function Ee(e,t,n,r,o){return e[t&255|n&65280]|e[r>>>16&255|o>>>16&65280]<<16}function Yn(e,t,n,r,o){let{sbox2:s,T01:i,T23:a}=er,c=0;t^=e[c++],n^=e[c++],r^=e[c++],o^=e[c++];let l=e.length/4-2;for(let y=0;y<l;y++){let m=e[c++]^qe(i,a,t,n,r,o),w=e[c++]^qe(i,a,n,r,o,t),x=e[c++]^qe(i,a,r,o,t,n),A=e[c++]^qe(i,a,o,t,n,r);t=m,n=w,r=x,o=A}let f=e[c++]^Ee(s,t,n,r,o),h=e[c++]^Ee(s,n,r,o,t),d=e[c++]^Ee(s,r,o,t,n),p=e[c++]^Ee(s,o,t,n,r);return{s0:f,s1:h,s2:d,s3:p}}function fa(e,t,n,r,o){let{sbox2:s,T01:i,T23:a}=is,c=0;t^=e[c++],n^=e[c++],r^=e[c++],o^=e[c++];let l=e.length/4-2;for(let y=0;y<l;y++){let m=e[c++]^qe(i,a,t,o,r,n),w=e[c++]^qe(i,a,n,t,o,r),x=e[c++]^qe(i,a,r,n,t,o),A=e[c++]^qe(i,a,o,r,n,t);t=m,n=w,r=x,o=A}let f=e[c++]^Ee(s,t,o,r,n),h=e[c++]^Ee(s,n,t,o,r),d=e[c++]^Ee(s,r,n,t,o),p=e[c++]^Ee(s,o,r,n,t);return{s0:f,s1:h,s2:d,s3:p}}function ha(e){if(F(e),e.length%ne!==0)throw new Error("aes-(cbc/ecb).decrypt ciphertext should consist of blocks with size "+ne)}function da(e,t,n){F(e);let r=e.length,o=r%ne;if(!t&&o!==0)throw new Error("aec/(cbc-ecb): unpadded plaintext with disabled padding");Xe(e)||(e=pe(e));let s=ee(e);if(t){let a=ne-o;a||(a=ne),r=r+a}n=ct(r,n),jn(e,n);let i=ee(n);return{b:s,o:i,out:n}}function pa(e,t){if(!t)return e;let n=e.length;if(!n)throw new Error("aes/pcks5: empty ciphertext not allowed");let r=e[n-1];if(r<=0||r>16)throw new Error("aes/pcks5: wrong padding");let o=e.subarray(0,-r);for(let s=0;s<r;s++)if(e[n-s-1]!==r)throw new Error("aes/pcks5: wrong padding");return o}function ya(e){let t=new Uint8Array(16),n=ee(t);t.set(e);let r=ne-e.length;for(let o=ne-r;o<ne;o++)t[o]=r;return n}var nr=At({blockSize:16,nonceLength:16},function(t,n,r={}){let o=!r.disablePadding;return{encrypt(s,i){let a=tr(t),{b:c,o:l,out:f}=da(s,o,i),h=n,d=[a];Xe(h)||d.push(h=pe(h));let p=ee(h),y=p[0],m=p[1],w=p[2],x=p[3],A=0;for(;A+4<=c.length;)y^=c[A+0],m^=c[A+1],w^=c[A+2],x^=c[A+3],{s0:y,s1:m,s2:w,s3:x}=Yn(a,y,m,w,x),l[A++]=y,l[A++]=m,l[A++]=w,l[A++]=x;if(o){let I=ya(s.subarray(A*4));y^=I[0],m^=I[1],w^=I[2],x^=I[3],{s0:y,s1:m,s2:w,s3:x}=Yn(a,y,m,w,x),l[A++]=y,l[A++]=m,l[A++]=w,l[A++]=x}return re(...d),f},decrypt(s,i){ha(s);let a=ua(t),c=n,l=[a];Xe(c)||l.push(c=pe(c));let f=ee(c);i=ct(s.length,i),Xe(s)||l.push(s=pe(s)),jn(s,i);let h=ee(s),d=ee(i),p=f[0],y=f[1],m=f[2],w=f[3];for(let x=0;x+4<=h.length;){let A=p,I=y,P=m,Q=w;p=h[x+0],y=h[x+1],m=h[x+2],w=h[x+3];let{s0:V,s1:Z,s2:j,s3:U}=fa(a,p,y,m,w);d[x++]=V^A,d[x++]=Z^I,d[x++]=j^P,d[x++]=U^Q}return re(...l),pa(i,o)}}});function ga(e){return e instanceof Uint32Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint32Array"}function Jn(e,t){if(F(t,16,"block"),!ga(e))throw new Error("_encryptBlock accepts result of expandKeyLE");let n=ee(t),{s0:r,s1:o,s2:s,s3:i}=Yn(e,n[0],n[1],n[2],n[3]);return n[0]=r,n[1]=o,n[2]=s,n[3]=i,t}function rs(e){let t=0;for(let n=ne-1;n>=0;n--){let r=(e[n]&128)>>>7;e[n]=e[n]<<1|t,t=r}return t&&(e[ne-1]^=135),e}function zt(e,t){if(e.length!==t.length)throw new Error("xorBlock: blocks must have same length");for(let n=0;n<e.length;n++)e[n]=e[n]^t[n];return e}var Zt=class{constructor(t){u(this,"buffer");u(this,"destroyed");u(this,"k1");u(this,"k2");u(this,"xk");F(t),os(t),this.xk=tr(t),this.buffer=new Uint8Array(0),this.destroyed=!1;let n=new Uint8Array(ne);Jn(this.xk,n),this.k1=rs(n),this.k2=rs(new Uint8Array(this.k1))}update(t){let{destroyed:n,buffer:r}=this;if(n)throw new Error("CMAC instance was destroyed");F(t);let o=new Uint8Array(r.length+t.length);return o.set(r),o.set(t,r.length),this.buffer=o,this}digest(){if(this.destroyed)throw new Error("CMAC instance was destroyed");let{buffer:t}=this,n=t.length,r=Math.ceil(n/ne),o;r===0?(r=1,o=!1):o=n%ne===0;let s=(r-1)*ne,i=t.subarray(s),a;if(o)a=zt(new Uint8Array(i),this.k1);else{let l=new Uint8Array(ne);l.set(i),l[i.length]=128,a=zt(l,this.k2)}let c=new Uint8Array(ne);for(let l=0;l<r-1;l++){let f=t.subarray(l*ne,(l+1)*ne);zt(c,f),Jn(this.xk,c)}return zt(c,a),Jn(this.xk,c),re(a),c}destroy(){let{buffer:t,destroyed:n,xk:r,k1:o,k2:s}=this;n||(this.destroyed=!0,re(t,r,o,s))}},ba=(e,t)=>new Zt(e).update(t).digest();ba.create=e=>new Zt(e);var cs=e=>Uint8Array.from(e.split(""),t=>t.charCodeAt(0)),ma=cs("expand 16-byte k"),wa=cs("expand 32-byte k"),xa=ee(ma),va=ee(wa);function k(e,t){return e<<t|e>>>32-t}function rr(e){return e.byteOffset%4===0}var Jt=64,Ea=16,ls=2**32-1,as=Uint32Array.of();function Sa(e,t,n,r,o,s,i,a){let c=o.length,l=new Uint8Array(Jt),f=ee(l),h=rr(o)&&rr(s),d=h?ee(o):as,p=h?ee(s):as;for(let y=0;y<c;i++){if(e(t,n,r,f,i,a),i>=ls)throw new Error("arx: counter overflow");let m=Math.min(Jt,c-y);if(h&&m===Jt){let w=y/4;if(y%4!==0)throw new Error("arx: invalid block position");for(let x=0,A;x<Ea;x++)A=w+x,p[A]=d[A]^f[x];y+=Jt;continue}for(let w=0,x;w<m;w++)x=y+w,s[x]=o[x]^l[w];y+=m}}function or(e,t){let{allowShortKeys:n,extendNonceFn:r,counterLength:o,counterRight:s,rounds:i}=ns({allowShortKeys:!1,counterLength:8,counterRight:!1,rounds:20},t);if(typeof e!="function")throw new Error("core must be a function");return St(o),St(i),jt(s),jt(n),(a,c,l,f,h=0)=>{F(a,void 0,"key"),F(c,void 0,"nonce"),F(l,void 0,"data");let d=l.length;if(f===void 0&&(f=new Uint8Array(d)),F(f,void 0,"output"),St(h),h<0||h>=ls)throw new Error("arx: counter overflow");if(f.length<d)throw new Error(`arx: output (${f.length}) is shorter than data (${d})`);let p=[],y=a.length,m,w;if(y===32)p.push(m=pe(a)),w=va;else if(y===16&&n)m=new Uint8Array(32),m.set(a),m.set(a,16),w=xa,p.push(m);else throw F(a,32,"arx key"),new Error("invalid key size");rr(c)||p.push(c=pe(c));let x=ee(m);if(r){if(c.length!==24)throw new Error("arx: extended nonce must be 24 bytes");r(w,x,ee(c.subarray(0,16)),x),c=c.subarray(16)}let A=16-o;if(A!==c.length)throw new Error(`arx: nonce must be ${A} or 16 bytes`);if(A!==12){let P=new Uint8Array(12);P.set(c,s?0:12-c.length),c=P,p.push(c)}let I=ee(c);return Sa(e,w,x,I,l,f,h,i),re(...p),f}}function oe(e,t){return e[t++]&255|(e[t++]&255)<<8}var sr=class{constructor(t){u(this,"blockLen",16);u(this,"outputLen",16);u(this,"buffer",new Uint8Array(16));u(this,"r",new Uint16Array(10));u(this,"h",new Uint16Array(10));u(this,"pad",new Uint16Array(8));u(this,"pos",0);u(this,"finished",!1);t=pe(F(t,32,"key"));let n=oe(t,0),r=oe(t,2),o=oe(t,4),s=oe(t,6),i=oe(t,8),a=oe(t,10),c=oe(t,12),l=oe(t,14);this.r[0]=n&8191,this.r[1]=(n>>>13|r<<3)&8191,this.r[2]=(r>>>10|o<<6)&7939,this.r[3]=(o>>>7|s<<9)&8191,this.r[4]=(s>>>4|i<<12)&255,this.r[5]=i>>>1&8190,this.r[6]=(i>>>14|a<<2)&8191,this.r[7]=(a>>>11|c<<5)&8065,this.r[8]=(c>>>8|l<<8)&8191,this.r[9]=l>>>5&127;for(let f=0;f<8;f++)this.pad[f]=oe(t,16+2*f)}process(t,n,r=!1){let o=r?0:2048,{h:s,r:i}=this,a=i[0],c=i[1],l=i[2],f=i[3],h=i[4],d=i[5],p=i[6],y=i[7],m=i[8],w=i[9],x=oe(t,n+0),A=oe(t,n+2),I=oe(t,n+4),P=oe(t,n+6),Q=oe(t,n+8),V=oe(t,n+10),Z=oe(t,n+12),j=oe(t,n+14),U=s[0]+(x&8191),W=s[1]+((x>>>13|A<<3)&8191),M=s[2]+((A>>>10|I<<6)&8191),C=s[3]+((I>>>7|P<<9)&8191),L=s[4]+((P>>>4|Q<<12)&8191),b=s[5]+(Q>>>1&8191),g=s[6]+((Q>>>14|V<<2)&8191),E=s[7]+((V>>>11|Z<<5)&8191),S=s[8]+((Z>>>8|j<<8)&8191),B=s[9]+(j>>>5|o),v=0,R=v+U*a+W*(5*w)+M*(5*m)+C*(5*y)+L*(5*p);v=R>>>13,R&=8191,R+=b*(5*d)+g*(5*h)+E*(5*f)+S*(5*l)+B*(5*c),v+=R>>>13,R&=8191;let T=v+U*c+W*a+M*(5*w)+C*(5*m)+L*(5*y);v=T>>>13,T&=8191,T+=b*(5*p)+g*(5*d)+E*(5*h)+S*(5*f)+B*(5*l),v+=T>>>13,T&=8191;let _=v+U*l+W*c+M*a+C*(5*w)+L*(5*m);v=_>>>13,_&=8191,_+=b*(5*y)+g*(5*p)+E*(5*d)+S*(5*h)+B*(5*f),v+=_>>>13,_&=8191;let H=v+U*f+W*l+M*c+C*a+L*(5*w);v=H>>>13,H&=8191,H+=b*(5*m)+g*(5*y)+E*(5*p)+S*(5*d)+B*(5*h),v+=H>>>13,H&=8191;let K=v+U*h+W*f+M*l+C*c+L*a;v=K>>>13,K&=8191,K+=b*(5*w)+g*(5*m)+E*(5*y)+S*(5*p)+B*(5*d),v+=K>>>13,K&=8191;let q=v+U*d+W*h+M*f+C*l+L*c;v=q>>>13,q&=8191,q+=b*a+g*(5*w)+E*(5*m)+S*(5*y)+B*(5*p),v+=q>>>13,q&=8191;let O=v+U*p+W*d+M*h+C*f+L*l;v=O>>>13,O&=8191,O+=b*c+g*a+E*(5*w)+S*(5*m)+B*(5*y),v+=O>>>13,O&=8191;let z=v+U*y+W*p+M*d+C*h+L*f;v=z>>>13,z&=8191,z+=b*l+g*c+E*a+S*(5*w)+B*(5*m),v+=z>>>13,z&=8191;let J=v+U*m+W*y+M*p+C*d+L*h;v=J>>>13,J&=8191,J+=b*f+g*l+E*c+S*a+B*(5*w),v+=J>>>13,J&=8191;let Y=v+U*w+W*m+M*y+C*p+L*d;v=Y>>>13,Y&=8191,Y+=b*h+g*f+E*l+S*c+B*a,v+=Y>>>13,Y&=8191,v=(v<<2)+v|0,v=v+R|0,R=v&8191,v=v>>>13,T+=v,s[0]=R,s[1]=T,s[2]=_,s[3]=H,s[4]=K,s[5]=q,s[6]=O,s[7]=z,s[8]=J,s[9]=Y}finalize(){let{h:t,pad:n}=this,r=new Uint16Array(10),o=t[1]>>>13;t[1]&=8191;for(let a=2;a<10;a++)t[a]+=o,o=t[a]>>>13,t[a]&=8191;t[0]+=o*5,o=t[0]>>>13,t[0]&=8191,t[1]+=o,o=t[1]>>>13,t[1]&=8191,t[2]+=o,r[0]=t[0]+5,o=r[0]>>>13,r[0]&=8191;for(let a=1;a<10;a++)r[a]=t[a]+o,o=r[a]>>>13,r[a]&=8191;r[9]-=8192;let s=(o^1)-1;for(let a=0;a<10;a++)r[a]&=s;s=~s;for(let a=0;a<10;a++)t[a]=t[a]&s|r[a];t[0]=(t[0]|t[1]<<13)&65535,t[1]=(t[1]>>>3|t[2]<<10)&65535,t[2]=(t[2]>>>6|t[3]<<7)&65535,t[3]=(t[3]>>>9|t[4]<<4)&65535,t[4]=(t[4]>>>12|t[5]<<1|t[6]<<14)&65535,t[5]=(t[6]>>>2|t[7]<<11)&65535,t[6]=(t[7]>>>5|t[8]<<8)&65535,t[7]=(t[8]>>>8|t[9]<<5)&65535;let i=t[0]+n[0];t[0]=i&65535;for(let a=1;a<8;a++)i=(t[a]+n[a]|0)+(i>>>16)|0,t[a]=i&65535;re(r)}update(t){Fn(this),F(t),t=pe(t);let{buffer:n,blockLen:r}=this,o=t.length;for(let s=0;s<o;){let i=Math.min(r-this.pos,o-s);if(i===r){for(;r<=o-s;s+=r)this.process(t,s);continue}n.set(t.subarray(s,s+i),this.pos),this.pos+=i,s+=i,this.pos===r&&(this.process(n,0,!1),this.pos=0)}return this}destroy(){re(this.h,this.r,this.buffer,this.pad)}digestInto(t){Fn(this),Qo(t,this),this.finished=!0;let{buffer:n,h:r}=this,{pos:o}=this;if(o){for(n[o++]=1;o<16;o++)n[o]=0;this.process(n,0,!0)}this.finalize();let s=0;for(let i=0;i<8;i++)t[s++]=r[i]>>>0,t[s++]=r[i]>>>8;return t}digest(){let{buffer:t,outputLen:n}=this;this.digestInto(t);let r=t.slice(0,n);return this.destroy(),r}};function Aa(e){let t=(r,o)=>e(o).update(r).digest(),n=e(new Uint8Array(32));return t.outputLen=n.outputLen,t.blockLen=n.blockLen,t.create=r=>e(r),t}var us=Aa(e=>new sr(e));function ds(e,t,n,r,o,s=20){let i=e[0],a=e[1],c=e[2],l=e[3],f=t[0],h=t[1],d=t[2],p=t[3],y=t[4],m=t[5],w=t[6],x=t[7],A=o,I=n[0],P=n[1],Q=n[2],V=i,Z=a,j=c,U=l,W=f,M=h,C=d,L=p,b=y,g=m,E=w,S=x,B=A,v=I,R=P,T=Q;for(let H=0;H<s;H+=2)V=V+W|0,B=k(B^V,16),b=b+B|0,W=k(W^b,12),V=V+W|0,B=k(B^V,8),b=b+B|0,W=k(W^b,7),Z=Z+M|0,v=k(v^Z,16),g=g+v|0,M=k(M^g,12),Z=Z+M|0,v=k(v^Z,8),g=g+v|0,M=k(M^g,7),j=j+C|0,R=k(R^j,16),E=E+R|0,C=k(C^E,12),j=j+C|0,R=k(R^j,8),E=E+R|0,C=k(C^E,7),U=U+L|0,T=k(T^U,16),S=S+T|0,L=k(L^S,12),U=U+L|0,T=k(T^U,8),S=S+T|0,L=k(L^S,7),V=V+M|0,T=k(T^V,16),E=E+T|0,M=k(M^E,12),V=V+M|0,T=k(T^V,8),E=E+T|0,M=k(M^E,7),Z=Z+C|0,B=k(B^Z,16),S=S+B|0,C=k(C^S,12),Z=Z+C|0,B=k(B^Z,8),S=S+B|0,C=k(C^S,7),j=j+L|0,v=k(v^j,16),b=b+v|0,L=k(L^b,12),j=j+L|0,v=k(v^j,8),b=b+v|0,L=k(L^b,7),U=U+W|0,R=k(R^U,16),g=g+R|0,W=k(W^g,12),U=U+W|0,R=k(R^U,8),g=g+R|0,W=k(W^g,7);let _=0;r[_++]=i+V|0,r[_++]=a+Z|0,r[_++]=c+j|0,r[_++]=l+U|0,r[_++]=f+W|0,r[_++]=h+M|0,r[_++]=d+C|0,r[_++]=p+L|0,r[_++]=y+b|0,r[_++]=m+g|0,r[_++]=w+E|0,r[_++]=x+S|0,r[_++]=A+B|0,r[_++]=I+v|0,r[_++]=P+R|0,r[_++]=Q+T|0}function Ta(e,t,n,r){let o=e[0],s=e[1],i=e[2],a=e[3],c=t[0],l=t[1],f=t[2],h=t[3],d=t[4],p=t[5],y=t[6],m=t[7],w=n[0],x=n[1],A=n[2],I=n[3];for(let Q=0;Q<20;Q+=2)o=o+c|0,w=k(w^o,16),d=d+w|0,c=k(c^d,12),o=o+c|0,w=k(w^o,8),d=d+w|0,c=k(c^d,7),s=s+l|0,x=k(x^s,16),p=p+x|0,l=k(l^p,12),s=s+l|0,x=k(x^s,8),p=p+x|0,l=k(l^p,7),i=i+f|0,A=k(A^i,16),y=y+A|0,f=k(f^y,12),i=i+f|0,A=k(A^i,8),y=y+A|0,f=k(f^y,7),a=a+h|0,I=k(I^a,16),m=m+I|0,h=k(h^m,12),a=a+h|0,I=k(I^a,8),m=m+I|0,h=k(h^m,7),o=o+l|0,I=k(I^o,16),y=y+I|0,l=k(l^y,12),o=o+l|0,I=k(I^o,8),y=y+I|0,l=k(l^y,7),s=s+f|0,w=k(w^s,16),m=m+w|0,f=k(f^m,12),s=s+f|0,w=k(w^s,8),m=m+w|0,f=k(f^m,7),i=i+h|0,x=k(x^i,16),d=d+x|0,h=k(h^d,12),i=i+h|0,x=k(x^i,8),d=d+x|0,h=k(h^d,7),a=a+c|0,A=k(A^a,16),p=p+A|0,c=k(c^p,12),a=a+c|0,A=k(A^a,8),p=p+A|0,c=k(c^p,7);let P=0;r[P++]=o,r[P++]=s,r[P++]=i,r[P++]=a,r[P++]=w,r[P++]=x,r[P++]=A,r[P++]=I}var Ye=or(ds,{counterRight:!1,counterLength:4,allowShortKeys:!1}),Ba=or(ds,{counterRight:!1,counterLength:8,extendNonceFn:Ta,allowShortKeys:!1});var Ra=new Uint8Array(16),fs=(e,t)=>{e.update(t);let n=t.length%16;n&&e.update(Ra.subarray(n))},_a=new Uint8Array(32);function hs(e,t,n,r,o){o!==void 0&&F(o,void 0,"AAD");let s=e(t,n,_a),i=zn(r.length,o?o.length:0,!0),a=us.create(s);o&&fs(a,o),fs(a,r),a.update(i);let c=a.digest();return re(s,i),c}var ps=e=>(t,n,r)=>({encrypt(s,i){let a=s.length;i=ct(a+16,i,!1),i.set(s);let c=i.subarray(0,-16);e(t,n,c,c,1);let l=hs(e,t,n,c,r);return i.set(l,a),re(l),i},decrypt(s,i){i=ct(s.length-16,i,!1);let a=s.subarray(0,-16),c=s.subarray(-16),l=hs(e,t,n,a,r);if(!Je(c,l))throw new Error("invalid tag");return i.set(s.subarray(0,-16)),e(t,n,i,i,1),re(l),i}}),$0=At({blockSize:64,nonceLength:12,tagLength:16},ps(Ye)),W0=At({blockSize:64,nonceLength:24,tagLength:16},ps(Ba));var Xt=class{constructor(t,n){u(this,"oHash");u(this,"iHash");u(this,"blockLen");u(this,"outputLen");u(this,"finished",!1);u(this,"destroyed",!1);if(vt(t),ve(n,void 0,"key"),this.iHash=t.create(),typeof this.iHash.update!="function")throw new Error("Expected instance of class which extends utils.Hash");this.blockLen=this.iHash.blockLen,this.outputLen=this.iHash.outputLen;let r=this.blockLen,o=new Uint8Array(r);o.set(n.length>r?t.create().update(n).digest():n);for(let s=0;s<o.length;s++)o[s]^=54;this.iHash.update(o),this.oHash=t.create();for(let s=0;s<o.length;s++)o[s]^=106;this.oHash.update(o),Re(o)}update(t){return it(this),this.iHash.update(t),this}digestInto(t){it(this),ve(t,this.outputLen,"output"),this.finished=!0,this.iHash.digestInto(t),this.oHash.update(t),this.oHash.digestInto(t),this.destroy()}digest(){let t=new Uint8Array(this.oHash.outputLen);return this.digestInto(t),t}_cloneInto(t){t||(t=Object.create(Object.getPrototypeOf(this),{}));let{oHash:n,iHash:r,finished:o,destroyed:s,blockLen:i,outputLen:a}=this;return t=t,t.finished=o,t.destroyed=s,t.blockLen=i,t.outputLen=a,t.oHash=n._cloneInto(t.oHash),t.iHash=r._cloneInto(t.iHash),t}clone(){return this._cloneInto()}destroy(){this.destroyed=!0,this.oHash.destroy(),this.iHash.destroy()}},De=(e,t,n)=>new Xt(e,t).update(n).digest();De.create=(e,t)=>new Xt(e,t);function Yt(e,t,n){return vt(e),n===void 0&&(n=new Uint8Array(e.outputLen)),De(e,n,t)}var ir=Uint8Array.of(0),ys=Uint8Array.of();function Qt(e,t,n,r=32){vt(e),$t(r,"length");let o=e.outputLen;if(r>255*o)throw new Error("Length must be <= 255*HashLen");let s=Math.ceil(r/o);n===void 0?n=ys:ve(n,void 0,"info");let i=new Uint8Array(s*o),a=De.create(e,t),c=a._cloneInto(),l=new Uint8Array(a.outputLen);for(let f=0;f<s;f++)ir[0]=f+1,c.update(f===0?ys:l).update(n).update(ir).digestInto(l),i.set(l,o*f),a._cloneInto(c);return a.destroy(),c.destroy(),Re(l,ir),i.slice(0,r)}var ka=Object.defineProperty,G=(e,t)=>{for(var n in t)ka(e,n,{get:t[n],enumerable:!0})},La={};G(La,{binarySearch:()=>dr,bytesToHex:()=>D,hexToBytes:()=>$,insertEventIntoAscendingList:()=>Ia,insertEventIntoDescendingList:()=>Ca,isHex32:()=>ue,mergeReverseSortedLists:()=>Ha,normalizeURL:()=>et,utf8Decoder:()=>Ce,utf8Encoder:()=>ye});var Ce=new TextDecoder("utf-8"),ye=new TextEncoder;function et(e){try{e.indexOf("://")===-1&&(e="wss://"+e);let t=new URL(e);return t.protocol==="http:"?t.protocol="ws:":t.protocol==="https:"&&(t.protocol="wss:"),t.pathname=t.pathname.replace(/\/+/g,"/"),t.pathname.endsWith("/")&&(t.pathname=t.pathname.slice(0,-1)),(t.port==="80"&&t.protocol==="ws:"||t.port==="443"&&t.protocol==="wss:")&&(t.port=""),t.searchParams.sort(),t.hash="",t.toString()}catch{throw new Error(`Invalid URL: ${e}`)}}function Ca(e,t){let[n,r]=dr(e,o=>t.id===o.id?0:t.created_at===o.created_at?-1:o.created_at-t.created_at);return r||e.splice(n,0,t),e}function Ia(e,t){let[n,r]=dr(e,o=>t.id===o.id?0:t.created_at===o.created_at?-1:t.created_at-o.created_at);return r||e.splice(n,0,t),e}function dr(e,t){let n=0,r=e.length-1;for(;n<=r;){let o=Math.floor((n+r)/2),s=t(e[o]);if(s===0)return[o,!0];s<0?r=o-1:n=o+1}return[n,!1]}function Ha(e,t){let n=new Array(e.length+t.length);n.length=0;let r=0,o=0,s=[];for(;r<e.length&&o<t.length;){let i;if(e[r]?.created_at>t[o]?.created_at?(i=e[r],r++):(i=t[o],o++),n.length>0&&n[n.length-1].created_at===i.created_at){if(s.includes(i.id))continue}else s.length=0;n.push(i),s.push(i.id)}for(;r<e.length;){let i=e[r];if(r++,n.length>0&&n[n.length-1].created_at===i.created_at){if(s.includes(i.id))continue}else s.length=0;n.push(i),s.push(i.id)}for(;o<t.length;){let i=t[o];if(o++,n.length>0&&n[n.length-1].created_at===i.created_at){if(s.includes(i.id))continue}else s.length=0;n.push(i),s.push(i.id)}return n}function ue(e){if(e.length!==64)return!1;for(let t=0;t<64;t++){let n=e.charCodeAt(t);if(isNaN(n)||n<48||n>102||n>57&&n<97)return!1}return!0}var ut=Symbol("verified"),Oa=e=>e instanceof Object;function pr(e){if(!Oa(e)||typeof e.kind!="number"||typeof e.content!="string"||typeof e.created_at!="number"||typeof e.pubkey!="string"||!ue(e.pubkey)||!Array.isArray(e.tags))return!1;for(let t=0;t<e.tags.length;t++){let n=e.tags[t];if(!Array.isArray(n))return!1;for(let r=0;r<n.length;r++)if(typeof n[r]!="string")return!1}return!0}var Ua=class{generateSecretKey(){return he.utils.randomSecretKey()}getPublicKey(e){return D(he.getPublicKey(e))}finalizeEvent(e,t){let n=e;return n.pubkey=D(he.getPublicKey(t)),n.id=tn(n),n.sig=D(he.sign($(tn(n)),t)),n[ut]=!0,n}verifyEvent(e){if(typeof e[ut]=="boolean")return e[ut];try{let t=tn(e);if(t!==e.id)return e[ut]=!1,!1;let n=he.verify($(e.sig),$(t),$(e.pubkey));return e[ut]=n,n}catch{return e[ut]=!1,!1}}};function Pa(e){if(!pr(e))throw new Error("can't serialize event with wrong or missing properties");return JSON.stringify([0,e.pubkey,e.created_at,e.kind,e.tags,e.content])}function tn(e){let t=te(ye.encode(Pa(e)));return D(t)}var an=new Ua,yr=an.generateSecretKey,Tt=an.getPublicKey,ge=an.finalizeEvent,tt=an.verifyEvent,Na={};G(Na,{AIEmbeddings:()=>Cc,AppCurationSet:()=>hu,Application:()=>uu,AuthoredPodcasts:()=>Cl,BadgeAward:()=>Ka,BadgeDefinition:()=>Yl,Bid:()=>ic,BidConfirmation:()=>ac,BlobsAuth:()=>Vl,BlockedRelaysList:()=>dl,BlossomServerList:()=>Bl,BookmarkList:()=>ul,Bookmarksets:()=>jl,Calendar:()=>ku,CalendarEventRSVP:()=>Lu,CashuMintAnnouncement:()=>$u,CashuWalletEvent:()=>ql,CashuWalletHistory:()=>Vc,CashuWalletTokens:()=>Wc,ChannelCreation:()=>Ts,ChannelHideMessage:()=>_s,ChannelMessage:()=>Rs,ChannelMetadata:()=>Bs,ChannelMuteUser:()=>ks,ChatMessage:()=>Fa,Chess:()=>rc,ClassifiedListing:()=>mu,ClientAuth:()=>Ls,CodeSnippet:()=>gc,CoinjoinPool:()=>Oc,Comment:()=>fc,CommunitiesList:()=>fl,CommunityDefinition:()=>Nu,CommunityPostApproval:()=>Nc,ConferenceEvent:()=>yu,Contacts:()=>Wa,CreateOrUpdateProduct:()=>tu,CreateOrUpdateStall:()=>eu,CuratedVideoSets:()=>Zl,Curationsets:()=>zl,Date:()=>Ru,DecoupledEncryptionKeyDistribution:()=>Pc,DecoupledKeyAnnouncement:()=>Sl,DecoupledKeyClientAnnouncement:()=>Uc,DirectMessageRelaysList:()=>Al,DraftClassifiedListing:()=>wu,DraftEvent:()=>Au,DraftLong:()=>su,Emojisets:()=>iu,EncryptedDirectMessage:()=>Va,EventDeletion:()=>Ga,FavoriteFollowSets:()=>vl,FavoritePodcasts:()=>Tl,FavoriteRelays:()=>gl,FedimintAnnouncement:()=>Wu,Feed:()=>Bu,FileMessage:()=>Ja,FileMetadata:()=>lc,FileServerPreference:()=>Rl,Followsets:()=>Gl,ForumThread:()=>za,GenericRepost:()=>xr,Genericlists:()=>Kl,GeocacheListing:()=>qu,GeocacheLog:()=>Gc,GeocacheLogEntry:()=>Du,GeocacheProofOfFind:()=>Kc,GiftWrap:()=>on,GitPullRequest:()=>mc,GitPullRequestUpdate:()=>wc,GoodWikiAuthorList:()=>_l,GoodWikiRelayList:()=>kl,GroupMetadata:()=>Gu,HTTPAuth:()=>vr,Handlerinformation:()=>Hu,Handlerrecommendation:()=>Iu,Highlights:()=>il,InteractiveRoom:()=>pu,InterestsList:()=>ml,Interestsets:()=>Ql,Issue:()=>xc,JobFeedback:()=>Dc,JobRequest:()=>Mc,JobResult:()=>qc,Label:()=>kc,LegacyNsiteFile:()=>Uu,LightningPubRPC:()=>Dl,LinkSet:()=>Tu,LiveChatMessage:()=>yc,LiveEvent:()=>du,LongFormArticle:()=>ou,MarketplaceUI:()=>nu,MediaFollows:()=>xl,MediaStarterPacks:()=>Ju,MergeRequests:()=>oc,Metadata:()=>Da,ModularArticleContent:()=>cu,ModularArticleHeader:()=>au,MuteSets:()=>Jl,Mutelist:()=>al,NWCWalletInfo:()=>Nl,NWCWalletRequest:()=>Cs,NWCWalletResponse:()=>$l,NormalVideo:()=>Qa,NostrConnect:()=>Wl,NsiteNamed:()=>Mu,NsiteRoot:()=>Ml,NutZap:()=>nl,NutZapInfo:()=>wl,OpenTimestamps:()=>cc,Patch:()=>bc,PeerToPeerOrderEvents:()=>Vu,Photo:()=>Ya,Pinlist:()=>cl,PodcastEpisode:()=>nc,PodcastMetadata:()=>Ll,Poll:()=>uc,PollResponse:()=>sc,PrivateDirectMessage:()=>As,PrivateEventRelayList:()=>bl,ProblemTracker:()=>Bc,ProductSoldAsAuction:()=>ru,ProfileBadges:()=>Xl,ProxyAnnouncement:()=>Ul,PublicChatsList:()=>hl,PublicMessage:()=>tc,Reaction:()=>wr,ReactionToWebsite:()=>Xa,RecommendRelay:()=>$a,Redirects:()=>Su,RelayDiscovery:()=>fu,RelayList:()=>ll,RelayMonitorAnnouncement:()=>Il,RelayReview:()=>Cu,RelayReviews:()=>Lc,Relaysets:()=>Fl,ReleaseArtifactSets:()=>lu,Reply:()=>vc,Report:()=>Rc,Reporting:()=>_c,RepositoryAnnouncement:()=>xu,RepositoryState:()=>vu,Repost:()=>mr,ReservedCashuWalletTokens:()=>$c,RoomPresence:()=>Hl,Scroll:()=>dc,Seal:()=>rn,SearchRelaysList:()=>pl,ShortTextNote:()=>Ss,ShortVideo:()=>ec,SimpleGroupAdmins:()=>Ku,SimpleGroupCreateGroup:()=>Jc,SimpleGroupCreateInvite:()=>Yc,SimpleGroupDeleteEvent:()=>Zc,SimpleGroupDeleteGroup:()=>Xc,SimpleGroupEditMetadata:()=>zc,SimpleGroupJoinRequest:()=>Qc,SimpleGroupLeaveRequest:()=>el,SimpleGroupList:()=>yl,SimpleGroupLiveKitParticipants:()=>zu,SimpleGroupMembers:()=>Fu,SimpleGroupPutUser:()=>Fc,SimpleGroupRemoveUser:()=>jc,SimpleGroupReply:()=>Za,SimpleGroupRoles:()=>ju,SimpleGroupThreadedReply:()=>ja,SlideSet:()=>bu,SoftwareApplication:()=>Ou,StarterPacks:()=>Zu,StatusApplied:()=>Sc,StatusClosed:()=>Ac,StatusDraft:()=>Tc,StatusOpen:()=>Ec,TidalLogin:()=>rl,Time:()=>_u,Torrent:()=>Ic,TorrentComment:()=>Hc,TransportMethodAnnouncement:()=>Pl,UserEmojiList:()=>El,UserGraspList:()=>Ol,UserStatuses:()=>gu,VideoViewEvent:()=>Pu,Voice:()=>hc,VoiceComment:()=>pc,WebBookmarks:()=>Xu,WikiArticle:()=>Eu,Zap:()=>sl,ZapGoal:()=>tl,ZapRequest:()=>ol,classifyKind:()=>Ma,isAddressableKind:()=>br,isEphemeralKind:()=>Es,isKind:()=>qa,isRegularKind:()=>vs,isReplaceableKind:()=>gr});function vs(e){return e<1e4&&e!==0&&e!==3}function gr(e){return e===0||e===3||1e4<=e&&e<2e4}function Es(e){return 2e4<=e&&e<3e4}function br(e){return 3e4<=e&&e<4e4}function Ma(e){return vs(e)?"regular":gr(e)?"replaceable":Es(e)?"ephemeral":br(e)?"parameterized":"unknown"}function qa(e,t){let n=t instanceof Array?t:[t];return pr(e)&&n.includes(e.kind)||!1}var Da=0,Ss=1,$a=2,Wa=3,Va=4,Ga=5,mr=6,wr=7,Ka=8,Fa=9,ja=10,za=11,Za=12,rn=13,As=14,Ja=15,xr=16,Xa=17,Ya=20,Qa=21,ec=22,tc=24,Ts=40,Bs=41,Rs=42,_s=43,ks=44,nc=54,rc=64,oc=818,sc=1018,ic=1021,ac=1022,cc=1040,on=1059,lc=1063,uc=1068,fc=1111,hc=1222,dc=1227,pc=1244,yc=1311,gc=1337,bc=1617,mc=1618,wc=1619,xc=1621,vc=1622,Ec=1630,Sc=1631,Ac=1632,Tc=1633,Bc=1971,Rc=1984,_c=1984,kc=1985,Lc=1986,Cc=1987,Ic=2003,Hc=2004,Oc=2022,Uc=4454,Pc=4455,Nc=4550,Mc=5999,qc=6999,Dc=7e3,$c=7374,Wc=7375,Vc=7376,Gc=7516,Kc=7517,Fc=9e3,jc=9001,zc=9002,Zc=9005,Jc=9007,Xc=9008,Yc=9009,Qc=9021,el=9022,tl=9041,nl=9321,rl=9467,ol=9734,sl=9735,il=9802,al=1e4,cl=10001,ll=10002,ul=10003,fl=10004,hl=10005,dl=10006,pl=10007,yl=10009,gl=10012,bl=10013,ml=10015,wl=10019,xl=10020,vl=10021,El=10030,Sl=10044,Al=10050,Tl=10054,Bl=10063,Rl=10096,_l=10101,kl=10102,Ll=10154,Cl=10164,Il=10166,Hl=10312,Ol=10317,Ul=10377,Pl=11111,Nl=13194,Ml=15128,ql=17375,Dl=21e3,Ls=22242,Cs=23194,$l=23195,Wl=24133,Vl=24242,vr=27235,Gl=3e4,Kl=30001,Fl=30002,jl=30003,zl=30004,Zl=30005,Jl=30007,Xl=30008,Yl=30009,Ql=30015,eu=30017,tu=30018,nu=30019,ru=30020,ou=30023,su=30024,iu=30030,au=30040,cu=30041,lu=30063,uu=30078,fu=30166,hu=30267,du=30311,pu=30312,yu=30313,gu=30315,bu=30388,mu=30402,wu=30403,xu=30617,vu=30618,Eu=30818,Su=30819,Au=31234,Tu=31388,Bu=31890,Ru=31922,_u=31923,ku=31924,Lu=31925,Cu=31987,Iu=31989,Hu=31990,Ou=32267,Uu=34128,Pu=34237,Nu=34550,Mu=35128,qu=37515,Du=37516,$u=38172,Wu=38173,Vu=38383,Gu=39e3,Ku=39001,Fu=39002,ju=39003,zu=39004,Zu=39089,Ju=39092,Xu=39701;function Yu(e,t){if(e.ids&&e.ids.indexOf(t.id)===-1||e.kinds&&e.kinds.indexOf(t.kind)===-1||e.authors&&e.authors.indexOf(t.pubkey)===-1)return!1;for(let n in e)if(n[0]==="#"){let r=n.slice(1),o=e[`#${r}`];if(o&&!t.tags.find(([s,i])=>s===n.slice(1)&&o.indexOf(i)!==-1))return!1}return!(e.since&&t.created_at<e.since||e.until&&t.created_at>e.until)}function Qu(e,t){for(let n=0;n<e.length;n++)if(Yu(e[n],t))return!0;return!1}var ef={};G(ef,{getHex64:()=>cn,getInt:()=>Is,getSubscriptionId:()=>Hs,matchEventId:()=>tf,matchEventKind:()=>rf,matchEventPubkey:()=>nf});function cn(e,t){let n=t.length+3,r=e.indexOf(`"${t}":`)+n,o=e.slice(r).indexOf('"')+r+1;return e.slice(o,o+64)}function Is(e,t){let n=t.length,r=e.indexOf(`"${t}":`)+n+3,o=e.slice(r),s=Math.min(o.indexOf(","),o.indexOf("}"));return parseInt(o.slice(0,s),10)}function Hs(e){let t=e.slice(0,22).indexOf('"EVENT"');if(t===-1)return null;let n=e.slice(t+7+1).indexOf('"');if(n===-1)return null;let r=t+7+1+n,o=e.slice(r+1,80).indexOf('"');if(o===-1)return null;let s=r+1+o;return e.slice(r+1,s)}function tf(e,t){return t===cn(e,"id")}function nf(e,t){return t===cn(e,"pubkey")}function rf(e,t){return t===Is(e,"kind")}var of={};G(of,{makeAuthEvent:()=>Os});function Os(e,t){return{kind:Ls,created_at:Math.floor(Date.now()/1e3),tags:[["relay",e],["challenge",t]],content:""}}var hr=class extends Error{constructor(e,t){super(`Tried to send message '${e} on a closed connection to ${t}.`),this.name="SendingOnClosedConnection"}},Us=class{constructor(e,t){u(this,"url");u(this,"_connected",!1);u(this,"onclose",null);u(this,"onnotice",e=>console.debug(`NOTICE from ${this.url}: ${e}`));u(this,"onauth");u(this,"baseEoseTimeout",4400);u(this,"publishTimeout",4400);u(this,"pingFrequency",29e3);u(this,"pingTimeout",2e4);u(this,"resubscribeBackoff",[1e4,1e4,1e4,2e4,2e4,3e4,6e4]);u(this,"openSubs",new Map);u(this,"enablePing");u(this,"enableReconnect");u(this,"idleTimeout",0);u(this,"idleSince",Date.now());u(this,"ongoingOperations",0);u(this,"reconnectTimeoutHandle");u(this,"pingIntervalHandle");u(this,"reconnectAttempts",0);u(this,"skipReconnection",!1);u(this,"idleTimeoutHandle");u(this,"connectionPromise");u(this,"openCountRequests",new Map);u(this,"openEventPublishes",new Map);u(this,"ws");u(this,"challenge");u(this,"authPromise");u(this,"serial",0);u(this,"verifyEvent");u(this,"_WebSocket");this.url=et(e),this.verifyEvent=t.verifyEvent,this._WebSocket=t.websocketImplementation||WebSocket,this.enablePing=t.enablePing,this.enableReconnect=t.enableReconnect||!1,t.idleTimeout&&(this.idleTimeout=t.idleTimeout)}static async connect(e,t){let n=new Us(e,t);return await n.connect(t),n}closeAllSubscriptions(e){for(let[t,n]of this.openSubs)n.close(e);this.openSubs.clear();for(let[t,n]of this.openEventPublishes)n.reject(new Error(e));this.openEventPublishes.clear();for(let[t,n]of this.openCountRequests)n.reject(new Error(e));this.openCountRequests.clear()}get connected(){return this._connected}clearIdleTimeout(){this.idleTimeoutHandle&&(clearTimeout(this.idleTimeoutHandle),this.idleTimeoutHandle=void 0)}scheduleIdleClose(){this.clearIdleTimeout(),this.idleTimeout>0&&(this.idleTimeoutHandle=setTimeout(()=>{this.ongoingOperations===0&&this.idleSince&&this.close()},this.idleTimeout))}async reconnect(){let e=this.resubscribeBackoff[Math.min(this.reconnectAttempts,this.resubscribeBackoff.length-1)];this.reconnectAttempts++,this.reconnectTimeoutHandle=setTimeout(async()=>{try{await this.connect()}catch{}},e)}handleHardClose(e){this.ws&&(this.ws.onopen=null,this.ws.onerror=null,this.ws.onclose=null),this.pingIntervalHandle&&(clearInterval(this.pingIntervalHandle),this.pingIntervalHandle=void 0),this._connected=!1,this.connectionPromise=void 0,this.idleSince=void 0,this.clearIdleTimeout(),this.enableReconnect&&!this.skipReconnection?this.reconnect():(this.onclose?.(),this.closeAllSubscriptions(e))}async connect(e){let t;return this.connectionPromise?this.connectionPromise:(this.challenge=void 0,this.authPromise=void 0,this.skipReconnection=!1,this.connectionPromise=new Promise((n,r)=>{e?.timeout&&(t=setTimeout(()=>{r("connection timed out"),this.connectionPromise=void 0,this.reconnectAttempts===0&&(this.skipReconnection=!0),this.handleHardClose("relay connection timed out")},e.timeout)),e?.abort&&(e.abort.onabort=r);try{this.ws=new this._WebSocket(this.url)}catch(o){clearTimeout(t),r(o);return}this.ws.onopen=()=>{this.reconnectTimeoutHandle&&(clearTimeout(this.reconnectTimeoutHandle),this.reconnectTimeoutHandle=void 0),clearTimeout(t),this._connected=!0;let o=this.reconnectAttempts>0;this.reconnectAttempts=0;for(let s of this.openSubs.values()){if(s.eosed=!1,o)for(let i=0;i<s.filters.length;i++)s.lastEmitted&&(s.filters[i].since=s.lastEmitted+1);s.fire()}this.enablePing&&(this.pingIntervalHandle=setInterval(()=>this.pingpong(),this.pingFrequency)),n()},this.ws.onerror=()=>{clearTimeout(t),r("connection failed"),this.connectionPromise=void 0,this.reconnectAttempts===0&&(this.skipReconnection=!0),this.handleHardClose("relay connection failed")},this.ws.onclose=o=>{clearTimeout(t),r(o.message||"websocket closed"),this.handleHardClose("relay connection closed")},this.ws.onmessage=this._onmessage.bind(this)}),this.connectionPromise)}waitForPingPong(){return new Promise(e=>{this.ws.once("pong",()=>e(!0)),this.ws.ping()})}waitForDummyReq(){return new Promise((e,t)=>{if(!this.connectionPromise)return t(new Error(`no connection to ${this.url}, can't ping`));try{let n=this.subscribe([{ids:["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"],limit:0}],{label:"<forced-ping>",oneose:()=>{e(!0),n.close()},onclose(){e(!0)},eoseTimeout:this.pingTimeout+1e3})}catch(n){t(n)}})}async pingpong(){this.ws?.readyState===1&&(await Promise.any([this.ws&&this.ws.ping&&this.ws.once?this.waitForPingPong():this.waitForDummyReq(),new Promise(t=>setTimeout(()=>t(!1),this.pingTimeout))])||this.ws?.readyState===this._WebSocket.OPEN&&this.ws?.close())}async send(e){if(!this.connectionPromise)throw new hr(e,this.url);this.connectionPromise.then(()=>{this.ws?.send(e)})}async auth(e){let t=this.challenge;if(!t)throw new Error("can't perform auth, no challenge was received");return this.authPromise?this.authPromise:(this.authPromise=new Promise(async(n,r)=>{try{let o=await e(Os(this.url,t)),s=setTimeout(()=>{let i=this.openEventPublishes.get(o.id);i&&(i.reject(new Error("auth timed out")),this.openEventPublishes.delete(o.id))},this.publishTimeout);this.openEventPublishes.set(o.id,{resolve:n,reject:r,timeout:s}),this.send('["AUTH",'+JSON.stringify(o)+"]")}catch(o){console.warn("subscribe auth function failed:",o)}}),this.authPromise)}async publish(e){this.idleSince=void 0,this.clearIdleTimeout(),this.ongoingOperations++;let t=new Promise((n,r)=>{let o=setTimeout(()=>{let s=this.openEventPublishes.get(e.id);s&&(s.reject(new Error("publish timed out")),this.openEventPublishes.delete(e.id))},this.publishTimeout);this.openEventPublishes.set(e.id,{resolve:n,reject:r,timeout:o})});try{await this.send('["EVENT",'+JSON.stringify(e)+"]")}catch(n){let r=this.openEventPublishes.get(e.id);r&&(r.reject(n),this.openEventPublishes.delete(e.id))}return this.ongoingOperations--,this.ongoingOperations===0&&(this.idleSince=Date.now(),this.scheduleIdleClose()),t}async count(e,t){return(await this.countWithHLL(e,t)).count}async countWithHLL(e,t){this.serial++;let n=t?.id||"count:"+this.serial,r=new Promise((o,s)=>{this.openCountRequests.set(n,{resolve:o,reject:s})});try{await this.send('["COUNT","'+n+'",'+JSON.stringify(e).substring(1))}catch(o){let s=this.openCountRequests.get(n);s&&(s.reject(o),this.openCountRequests.delete(n))}return r}subscribe(e,t){t.label!=="<forced-ping>"&&(this.idleSince=void 0,this.clearIdleTimeout(),this.ongoingOperations++);let n=this.prepareSubscription(e,t);return n.fire(),t.abort&&(t.abort.onabort=()=>n.close(String(t.abort.reason||"<aborted>"))),n}prepareSubscription(e,t){this.serial++;let n=t.id||(t.label?t.label+":":"sub:")+this.serial,r=new sf(this,n,e,t);return this.openSubs.set(n,r),r}close(){this.skipReconnection=!0,this.reconnectTimeoutHandle&&(clearTimeout(this.reconnectTimeoutHandle),this.reconnectTimeoutHandle=void 0),this.pingIntervalHandle&&(clearInterval(this.pingIntervalHandle),this.pingIntervalHandle=void 0),this.closeAllSubscriptions("relay connection closed by us"),this._connected=!1,this.connectionPromise=void 0,this.idleSince=void 0,this.clearIdleTimeout(),this.onclose?.(),this.ws&&(this.ws.onopen=null,this.ws.onerror=null,this.ws.onclose=null,this.ws.readyState!==this._WebSocket.CLOSING&&this.ws.readyState!==this._WebSocket.CLOSED&&this.ws.close())}_onmessage(e){let t=e.data;if(!t)return;let n=Hs(t);if(n){let r=this.openSubs.get(n);if(!r)return;let o=cn(t,"id"),s=r.alreadyHaveEvent?.(o);if(r.receivedEvent?.(this,o),s)return}try{let r=JSON.parse(t);switch(r[0]){case"EVENT":{let o=this.openSubs.get(r[1]),s=r[2];Qu(o.filters,s)&&this.verifyEvent(s,this.url)?o.onevent(s):o.oninvalidevent?.(s),(!o.lastEmitted||o.lastEmitted<s.created_at)&&(o.lastEmitted=s.created_at);return}case"COUNT":{let o=r[1],s=r[2],i=this.openCountRequests.get(o);i&&(i.resolve(s),this.openCountRequests.delete(o));return}case"EOSE":{let o=this.openSubs.get(r[1]);if(!o)return;o.receivedEose();return}case"OK":{let o=r[1],s=r[2],i=r[3],a=this.openEventPublishes.get(o);a&&(clearTimeout(a.timeout),s?a.resolve(i):a.reject(new Error(i)),this.openEventPublishes.delete(o));return}case"CLOSED":{let o=r[1],s=this.openSubs.get(o);if(!s){let i=this.openCountRequests.get(o);i&&(i.reject(new Error(r[2])),this.openCountRequests.delete(o));return}s.closed=!0,s.close(r[2]);return}case"NOTICE":{this.onnotice(r[1]);return}case"AUTH":{this.challenge=r[1],this.onauth&&this.auth(this.onauth).catch(o=>{if(!(o instanceof hr))throw o});return}default:{this.openSubs.get(r[1])?.oncustom?.(r);return}}}catch(r){try{let[o,s,i]=JSON.parse(t);console.warn(`[nostr] relay ${this.url} error processing message:`,r,i)}catch{console.warn(`[nostr] relay ${this.url} error processing message:`,r)}return}}},sf=class{constructor(e,t,n,r){u(this,"relay");u(this,"id");u(this,"lastEmitted");u(this,"closed",!1);u(this,"eosed",!1);u(this,"filters");u(this,"alreadyHaveEvent");u(this,"receivedEvent");u(this,"onevent");u(this,"oninvalidevent");u(this,"oneose");u(this,"onclose");u(this,"oncustom");u(this,"eoseTimeout");u(this,"eoseTimeoutHandle");if(n.length===0)throw new Error("subscription can't be created with zero filters");this.relay=e,this.filters=n,this.id=t,this.alreadyHaveEvent=r.alreadyHaveEvent,this.receivedEvent=r.receivedEvent,this.eoseTimeout=r.eoseTimeout||e.baseEoseTimeout,this.oneose=r.oneose,this.onclose=r.onclose,this.oninvalidevent=r.oninvalidevent,this.onevent=r.onevent||(o=>{console.warn(`onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,o)})}fire(){this.relay.send('["REQ","'+this.id+'",'+JSON.stringify(this.filters).substring(1)),this.eoseTimeoutHandle=setTimeout(this.receivedEose.bind(this),this.eoseTimeout)}receivedEose(){this.eosed||(clearTimeout(this.eoseTimeoutHandle),this.eosed=!0,this.oneose?.())}close(e="closed by caller"){if(!this.closed&&this.relay.connected){try{this.relay.send('["CLOSE",'+JSON.stringify(this.id)+"]")}catch(t){if(!(t instanceof hr))throw t}this.closed=!0}this.relay.openSubs.delete(this.id),this.id.startsWith("<forced-ping>")||(this.relay.ongoingOperations--,this.relay.ongoingOperations===0&&(this.relay.idleSince=Date.now(),this.relay.scheduleIdleClose())),this.onclose?.(e)}},af;try{af=WebSocket}catch{}var Ie=256,cf=Ie*2,ep=new TextEncoder;function lf(e,t){switch(t){case"reactions":return{"#e":[e],kinds:[7]};case"reposts":return{"#e":[e],kinds:[6]};case"quotes":return{"#q":[e],kinds:[1,1111]};case"replies":return{"#e":[e],kinds:[1]};case"comments":return{"#E":[e],kinds:[1111]};case"followers":return{"#p":[e],kinds:[3]}}}function uf(){return new Uint8Array(Ie)}function ff(e){if(e.length!==cf||!/^[0-9a-f]+$/.test(e))return;let t=new Uint8Array(Ie);for(let n=0;n<Ie;n++)t[n]=parseInt(e.slice(n*2,n*2+2),16);return t}function hf(e){if(e.length!==Ie)throw new Error(`invalid number of registers ${e.length}`);let t="";for(let n=0;n<Ie;n++)t+=e[n].toString(16).padStart(2,"0");return t}function df(e,t){if(e.length===0&&(e=uf()),e.length!==Ie)throw new Error(`invalid number of registers ${e.length}`);if(t.length!==Ie)throw new Error(`invalid number of registers ${t.length}`);for(let n=0;n<Ie;n++)t[n]>e[n]&&(e[n]=t[n]);return e}var pf=class{constructor(e){u(this,"relays",new Map);u(this,"seenOn",new Map);u(this,"trackRelays",!1);u(this,"verifyEvent");u(this,"enablePing");u(this,"enableReconnect");u(this,"idleTimeout",2e4);u(this,"automaticallyAuth");u(this,"onRelayConnectionFailure");u(this,"onRelayConnectionSuccess");u(this,"allowConnectingToRelay");u(this,"maxWaitForConnection");u(this,"_WebSocket");this.verifyEvent=e.verifyEvent,this._WebSocket=e.websocketImplementation,this.enablePing=e.enablePing,this.enableReconnect=e.enableReconnect||!1,e.idleTimeout&&(this.idleTimeout=e.idleTimeout),this.automaticallyAuth=e.automaticallyAuth,this.onRelayConnectionFailure=e.onRelayConnectionFailure,this.onRelayConnectionSuccess=e.onRelayConnectionSuccess,this.allowConnectingToRelay=e.allowConnectingToRelay,this.maxWaitForConnection=e.maxWaitForConnection||3e3}async ensureRelay(e,t){e=et(e);let n=this.relays.get(e);if(n||(n=new Us(e,{verifyEvent:this.verifyEvent,websocketImplementation:this._WebSocket,enablePing:this.enablePing,enableReconnect:this.enableReconnect,idleTimeout:this.idleTimeout}),n.onclose=()=>{this.relays.delete(e)},this.relays.set(e,n)),this.automaticallyAuth){let r=this.automaticallyAuth(e);r&&(n.onauth=r)}try{await n.connect({timeout:t?.connectionTimeout,abort:t?.abort})}catch(r){throw this.relays.delete(e),r}return n}close(e){e.map(et).forEach(t=>{this.relays.get(t)?.close(),this.relays.delete(t)})}subscribe(e,t,n){let r=[],o=[];for(let s=0;s<e.length;s++){let i=et(e[s]);r.find(a=>a.url===i)||o.indexOf(i)===-1&&(o.push(i),r.push({url:i,filter:t}))}return this.subscribeMap(r,n)}subscribeMany(e,t,n){return this.subscribe(e,t,n)}subscribeMap(e,t){let n=new Map;for(let d of e){let{url:p,filter:y}=d;n.has(p)||n.set(p,[]),n.get(p).push(y)}let r=Array.from(n.entries()).map(([d,p])=>({url:d,filters:p}));this.trackRelays&&(t.receivedEvent=(d,p)=>{let y=this.seenOn.get(p);y||(y=new Set,this.seenOn.set(p,y)),y.add(d)});let o=new Set,s=[],i=[],a=d=>{i[d]||(i[d]=!0,i.filter(p=>p).length===r.length&&(t.oneose?.(),a=()=>{}))},c=[],l=(d,p,y)=>{c[d]||(a(d),c[d]={url:p,reason:y},c.filter(m=>m).length===r.length&&(t.onclose?.(c),l=()=>{}))},f=d=>{if(t.alreadyHaveEvent?.(d))return!0;let p=o.has(d);return o.add(d),p},h=Promise.all(r.map(async({url:d,filters:p},y)=>{if(this.allowConnectingToRelay?.(d,["read",p])===!1){l(y,d,"connection skipped by allowConnectingToRelay");return}let m;try{m=await this.ensureRelay(d,{connectionTimeout:this.maxWaitForConnection<(t.maxWait||0)?Math.max(t.maxWait*.8,t.maxWait-1e3):this.maxWaitForConnection,abort:t.abort})}catch(x){this.onRelayConnectionFailure?.(d),l(y,d,x?.message||String(x));return}this.onRelayConnectionSuccess?.(d);let w=m.subscribe(p,{...t,oneose:()=>a(y),onclose:x=>{x.startsWith("auth-required: ")&&t.onauth?m.auth(t.onauth).then(()=>{m.subscribe(p,{...t,oneose:()=>a(y),onclose:A=>{l(y,d,A)},alreadyHaveEvent:f,eoseTimeout:t.maxWait,abort:t.abort})}).catch(A=>{l(y,d,`auth was required and attempted, but failed with: ${A}`)}):l(y,d,x)},alreadyHaveEvent:f,eoseTimeout:t.maxWait,abort:t.abort});s.push(w)}));return{async close(d){await h,s.forEach(p=>{p.close(d)})}}}subscribeEose(e,t,n){let r;return r=this.subscribe(e,t,{...n,oneose(){let o="closed automatically on eose";r?r.close(o):n.onclose?.(e.map(s=>({url:s,reason:o})))}}),r}subscribeManyEose(e,t,n){return this.subscribeEose(e,t,n)}async querySync(e,t,n){return new Promise(async r=>{let o=[];this.subscribeEose(e,t,{...n,onevent(s){o.push(s)},onclose(s){r(o)}})})}async get(e,t,n){t.limit=1;let r=await this.querySync(e,t,n);return r.sort((o,s)=>s.created_at-o.created_at),r[0]||null}async countMany(e,t,n,r){let o=lf(t,n),s=[];for(let l=0;l<e.length;l++){let f=et(e[l]);s.indexOf(f)===-1&&s.push(f)}let i=await Promise.all(s.map(async l=>{if(this.allowConnectingToRelay?.(l,["read",[o]])===!1)return null;let f;try{f=await this.ensureRelay(l,{connectionTimeout:this.maxWaitForConnection<(r?.maxWait||0)?Math.max(r.maxWait*.8,r.maxWait-1e3):this.maxWaitForConnection,abort:r?.abort})}catch{return this.onRelayConnectionFailure?.(l),null}return this.onRelayConnectionSuccess?.(l),f.countWithHLL([o],{id:r?.id}).catch(()=>null)})),a=0,c;for(let l of i){if(!l||(l.count>a&&(a=l.count),!l.hll||l.hll.length!==512))continue;let f=ff(l.hll);f&&(c=df(c||new Uint8Array(0),f))}return c?{count:a,hll:hf(c)}:{count:a}}publish(e,t,n){return e.map(et).map(async(r,o,s)=>{if(s.indexOf(r)!==o)return Promise.reject("duplicate url");if(this.allowConnectingToRelay?.(r,["write",t])===!1)return Promise.reject("connection skipped by allowConnectingToRelay");let i;try{i=await this.ensureRelay(r,{connectionTimeout:this.maxWaitForConnection<(n?.maxWait||0)?Math.max(n.maxWait*.8,n.maxWait-1e3):this.maxWaitForConnection,abort:n?.abort})}catch(a){return this.onRelayConnectionFailure?.(r),Promise.reject("connection failure: "+String(a))}return i.publish(t).catch(async a=>{if(a instanceof Error&&a.message.startsWith("auth-required: ")&&n?.onauth)return await i.auth(n.onauth),i.publish(t);throw a}).then(a=>{if(this.trackRelays){let c=this.seenOn.get(t.id);c||(c=new Set,this.seenOn.set(t.id,c)),c.add(i)}return a})})}listConnectionStatus(){let e=new Map;return this.relays.forEach((t,n)=>e.set(n,t.connected)),e}destroy(){this.relays.forEach(e=>e.close()),this.relays=new Map}pruneIdleRelays(e=1e4){let t=[];for(let[n,r]of this.relays)r.idleSince&&Date.now()-r.idleSince>=e&&(this.relays.delete(n),t.push(n),r.close());return t}},Ps;try{Ps=WebSocket}catch{}var Ns=class extends pf{constructor(e){super({verifyEvent:tt,websocketImplementation:Ps,maxWaitForConnection:3e3,...e})}},Er={};G(Er,{BECH32_REGEX:()=>Ms,Bech32MaxSize:()=>Sr,NostrTypeGuard:()=>yf,decode:()=>ln,decodeNostrURI:()=>bf,encodeBytes:()=>fn,naddrEncode:()=>Sf,neventEncode:()=>Ef,noteEncode:()=>xf,nprofileEncode:()=>vf,npubEncode:()=>wf,nsecEncode:()=>mf});var yf={isNProfile:e=>/^nprofile1[a-z\d]+$/.test(e||""),isNEvent:e=>/^nevent1[a-z\d]+$/.test(e||""),isNAddr:e=>/^naddr1[a-z\d]+$/.test(e||""),isNSec:e=>/^nsec1[a-z\d]{58}$/.test(e||""),isNPub:e=>/^npub1[a-z\d]{58}$/.test(e||""),isNote:e=>/^note1[a-z\d]+$/.test(e||""),isNcryptsec:e=>/^ncryptsec1[a-z\d]+$/.test(e||"")},Sr=5e3,Ms=/[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/;function gf(e){let t=new Uint8Array(4);return t[0]=e>>24&255,t[1]=e>>16&255,t[2]=e>>8&255,t[3]=e&255,t}function bf(e){try{return e.startsWith("nostr:")&&(e=e.substring(6)),ln(e)}catch{return{type:"invalid",data:null}}}function ln(e){let{prefix:t,words:n}=Me.decode(e,Sr),r=new Uint8Array(Me.fromWords(n));switch(t){case"nprofile":{let o=ar(r);if(!o[0]?.[0])throw new Error("missing TLV 0 for nprofile");if(o[0][0].length!==32)throw new Error("TLV 0 should be 32 bytes");return{type:"nprofile",data:{pubkey:D(o[0][0]),relays:o[1]?o[1].map(s=>Ce.decode(s)):[]}}}case"nevent":{let o=ar(r);if(!o[0]?.[0])throw new Error("missing TLV 0 for nevent");if(o[0][0].length!==32)throw new Error("TLV 0 should be 32 bytes");if(o[2]&&o[2][0].length!==32)throw new Error("TLV 2 should be 32 bytes");if(o[3]&&o[3][0].length!==4)throw new Error("TLV 3 should be 4 bytes");return{type:"nevent",data:{id:D(o[0][0]),relays:o[1]?o[1].map(s=>Ce.decode(s)):[],author:o[2]?.[0]?D(o[2][0]):void 0,kind:o[3]?.[0]?parseInt(D(o[3][0]),16):void 0}}}case"naddr":{let o=ar(r);if(!o[0]?.[0])throw new Error("missing TLV 0 for naddr");if(!o[2]?.[0])throw new Error("missing TLV 2 for naddr");if(o[2][0].length!==32)throw new Error("TLV 2 should be 32 bytes");if(!o[3]?.[0])throw new Error("missing TLV 3 for naddr");if(o[3][0].length!==4)throw new Error("TLV 3 should be 4 bytes");return{type:"naddr",data:{identifier:Ce.decode(o[0][0]),pubkey:D(o[2][0]),kind:parseInt(D(o[3][0]),16),relays:o[1]?o[1].map(s=>Ce.decode(s)):[]}}}case"nsec":return{type:t,data:r};case"npub":case"note":return{type:t,data:D(r)};default:throw new Error(`unknown prefix ${t}`)}}function ar(e){let t={},n=e;for(;n.length>0;){if(n.length<2)throw new Error("not enough data to read TLV");let r=n[0],o=n[1],s=n.slice(2,2+o);if(n=n.slice(2+o),s.length<o)throw new Error(`not enough data to read on TLV ${r}`);t[r]=t[r]||[],t[r].push(s)}return t}function mf(e){return fn("nsec",e)}function wf(e){return fn("npub",$(e))}function xf(e){return fn("note",$(e))}function un(e,t){let n=Me.toWords(t);return Me.encode(e,n,Sr)}function fn(e,t){return un(e,t)}function vf(e){let t=Ar({0:[$(e.pubkey)],1:(e.relays||[]).map(n=>ye.encode(n))});return un("nprofile",t)}function Ef(e){let t;e.kind!==void 0&&(t=gf(e.kind));let n=Ar({0:[$(e.id)],1:(e.relays||[]).map(r=>ye.encode(r)),2:e.author?[$(e.author)]:[],3:t?[new Uint8Array(t)]:[]});return un("nevent",n)}function Sf(e){let t=new ArrayBuffer(4);new DataView(t).setUint32(0,e.kind,!1);let n=Ar({0:[ye.encode(e.identifier)],1:(e.relays||[]).map(r=>ye.encode(r)),2:[$(e.pubkey)],3:[new Uint8Array(t)]});return un("naddr",n)}function Ar(e){let t=[];return Object.entries(e).reverse().forEach(([n,r])=>{r.forEach(o=>{let s=new Uint8Array(o.length+2);s.set([parseInt(n)],0),s.set([o.length],1),s.set(o,2),t.push(s)})}),de(...t)}var Af={};G(Af,{decrypt:()=>Tf,encrypt:()=>qs});function qs(e,t,n){let r=e instanceof Uint8Array?e:$(e),o=ze.getSharedSecret(r,$("02"+t)),s=Ds(o),i=Uint8Array.from(at(16)),a=ye.encode(n),c=nr(s,i).encrypt(a),l=le.encode(new Uint8Array(c)),f=le.encode(new Uint8Array(i.buffer));return`${l}?iv=${f}`}function Tf(e,t,n){let r=e instanceof Uint8Array?e:$(e),[o,s]=n.split("?iv="),i=ze.getSharedSecret(r,$("02"+t)),a=Ds(i),c=le.decode(s),l=le.decode(o),f=nr(a,c).decrypt(l);return Ce.decode(f)}function Ds(e){return e.slice(1,33)}var Bf={};G(Bf,{NIP05_REGEX:()=>Tr,isNip05:()=>Rf,isValid:()=>Lf,queryProfile:()=>$s,searchDomain:()=>kf,useFetchImplementation:()=>_f});var Tr=/^(?:([\w.+-]+)@)?([\w_-]+(\.[\w_-]+)+)$/,Rf=e=>Tr.test(e||""),hn;try{hn=fetch}catch{}function _f(e){hn=e}async function kf(e,t=""){try{let n=`https://${e}/.well-known/nostr.json?name=${t}`,r=await hn(n,{redirect:"manual"});if(r.status!==200)throw Error("Wrong response code");return(await r.json()).names}catch{return{}}}async function $s(e){let t=e.match(Tr);if(!t)return null;let[,n="_",r]=t;try{let o=`https://${r}/.well-known/nostr.json?name=${n}`,s=await hn(o,{redirect:"manual"});if(s.status!==200)throw Error("Wrong response code");let i=await s.json(),a=i.names[n];return a?{pubkey:a,relays:i.relays?.[a]}:null}catch{return null}}async function Lf(e,t){let n=await $s(t);return n?n.pubkey===e:!1}var Cf={};G(Cf,{parse:()=>If});function If(e){let t={reply:void 0,root:void 0,mentions:[],profiles:[],quotes:[]},n,r;for(let o=e.tags.length-1;o>=0;o--){let s=e.tags[o];if(s[0]==="e"&&s[1]&&ue(s[1])){let[i,a,c,l,f]=s,h={id:a,relays:c?[c]:[],author:f&&ue(f)?f:void 0};if(l==="root"){t.root=h;continue}if(l==="reply"){t.reply=h;continue}if(l==="mention"){t.mentions.push(h);continue}n?r=h:n=h,t.mentions.push(h);continue}if(s[0]==="q"&&s[1]&&ue(s[1])){let[i,a,c]=s;t.quotes.push({id:a,relays:c?[c]:[]})}if(s[0]==="p"&&s[1]&&ue(s[1])){t.profiles.push({pubkey:s[1],relays:s[2]?[s[2]]:[]});continue}}return t.root||(t.root=r||n||t.reply),t.reply||(t.reply=n||t.root),[t.reply,t.root].forEach(o=>{if(!o)return;let s=t.mentions.indexOf(o);if(s!==-1&&t.mentions.splice(s,1),o.author){let i=t.profiles.find(a=>a.pubkey===o.author);i&&i.relays&&(o.relays||(o.relays=[]),i.relays.forEach(a=>{o.relays?.indexOf(a)===-1&&o.relays.push(a)}),i.relays=o.relays)}}),t.mentions.forEach(o=>{if(o.author){let s=t.profiles.find(i=>i.pubkey===o.author);s&&s.relays&&(o.relays||(o.relays=[]),s.relays.forEach(i=>{o.relays.indexOf(i)===-1&&o.relays.push(i)}),s.relays=o.relays)}}),t}var Hf={};G(Hf,{fetchRelayInformation:()=>Uf,useFetchImplementation:()=>Of});var Ws;try{Ws=fetch}catch{}function Of(e){Ws=e}async function Uf(e){return await(await fetch(e.replace("ws://","http://").replace("wss://","https://"),{headers:{Accept:"application/nostr+json"}})).json()}var Pf={};G(Pf,{getPow:()=>Nf,minePow:()=>qf});function Nf(e){let t=0;for(let n=0;n<64;n+=8){let r=parseInt(e.substring(n,n+8),16);if(r===0)t+=32;else{t+=Math.clz32(r);break}}return t}function Mf(e){let t=0;for(let n=0;n<e.length;n++){let r=e[n];if(r===0)t+=8;else{t+=Math.clz32(r)-24;break}}return t}function qf(e,t){let n=0,r=e,o=["nonce",n.toString(),t.toString()];for(r.tags.push(o);;){let s=Math.floor(new Date().getTime()/1e3);s!==r.created_at&&(n=0,r.created_at=s),o[1]=(++n).toString();let i=te(ye.encode(JSON.stringify([0,r.pubkey,r.created_at,r.kind,r.tags,r.content])));if(Mf(i)>=t){r.id=D(i);break}}return r}var Df={};G(Df,{unwrapEvent:()=>Xf,unwrapManyEvents:()=>Yf,wrapEvent:()=>ti,wrapManyEvents:()=>Jf});var $f={};G($f,{createRumor:()=>Xs,createSeal:()=>Ys,createWrap:()=>Qs,unwrapEvent:()=>Hr,unwrapManyEvents:()=>ei,wrapEvent:()=>sn,wrapManyEvents:()=>zf});var Wf={};G(Wf,{decrypt:()=>Ir,encrypt:()=>Cr,getConversationKey:()=>kr,v2:()=>Ff});var Br=1,Rr=4294967295,_r=65536;function kr(e,t){let n=ze.getSharedSecret(e,$("02"+t)).subarray(1,33);return Yt(te,n,ye.encode("nip44-v2"))}function Vs(e,t){let n=Qt(te,e,t,76);return{chacha_key:n.subarray(0,32),chacha_nonce:n.subarray(32,44),hmac_key:n.subarray(44,76)}}function Lr(e){if(!Number.isSafeInteger(e)||e<1)throw new Error("expected positive integer");if(e<=32)return 32;let t=2**(Math.floor(Math.log2(e-1))+1),n=t<=256?32:t/8;return n*(Math.floor((e-1)/n)+1)}function Vf(e){if(!Number.isSafeInteger(e)||e<Br||e>65535)throw new Error("invalid plaintext size: must be between 1 and 65535 bytes");let t=new Uint8Array(2);return new DataView(t.buffer).setUint16(0,e,!1),t}function Gf(e){if(!Number.isSafeInteger(e)||e<_r||e>Rr)throw new Error("invalid plaintext size: must be between 65536 and 4294967295 bytes");let t=new Uint8Array(4);return new DataView(t.buffer).setUint32(0,e,!1),t}function Gs(e){let t=ye.encode(e),n=t.length;if(n<Br||n>Rr)throw new Error("invalid plaintext size: must be between 1 and 4294967295 bytes");let r=n>=_r?de(new Uint8Array([0,0]),Gf(n)):Vf(n),o=new Uint8Array(Lr(n)-n);return de(r,t,o)}function Ks(e){let t=new DataView(e.buffer,e.byteOffset,e.byteLength),n=t.getUint16(0),r,o;if(n===0){if(r=t.getUint32(2),r<_r)throw new Error("invalid padding");o=6}else r=n,o=2;let s=e.subarray(o,o+r);if(r<Br||r>Rr||s.length!==r||e.length!==o+Lr(r))throw new Error("invalid padding");return Ce.decode(s)}function Fs(e,t,n){if(n.length!==32)throw new Error("AAD associated data must be 32 bytes");let r=de(n,t);return De(te,e,r)}function Kf(e){if(typeof e!="string")throw new Error("payload must be a valid string");let t=e.length;if(t<132)throw new Error("invalid payload length: "+t);if(e[0]==="#")throw new Error("unknown encryption version");let n;try{n=le.decode(e)}catch(s){throw new Error("invalid base64: "+s.message)}let r=n.length;if(r<99)throw new Error("invalid data length: "+r);let o=n[0];if(o!==2)throw new Error("unknown encryption version "+o);return{nonce:n.subarray(1,33),ciphertext:n.subarray(33,-32),mac:n.subarray(-32)}}function Cr(e,t,n=at(32)){let{chacha_key:r,chacha_nonce:o,hmac_key:s}=Vs(t,n),i=Gs(e),a=Ye(r,o,i),c=Fs(s,a,n);return le.encode(de(new Uint8Array([2]),n,a,c))}function Ir(e,t){let{nonce:n,ciphertext:r,mac:o}=Kf(e),{chacha_key:s,chacha_nonce:i,hmac_key:a}=Vs(t,n),c=Fs(a,r,n);if(!Je(c,o))throw new Error("invalid MAC");let l=Ye(s,i,r);return Ks(l)}var Ff={utils:{getConversationKey:kr,calcPaddedLen:Lr,pad:Gs,unpad:Ks},encrypt:Cr,decrypt:Ir},jf=2880*60,js=()=>Math.round(Date.now()/1e3),zs=()=>Math.round(js()-Math.random()*jf),Zs=(e,t)=>kr(e,t),Js=(e,t,n)=>Cr(JSON.stringify(e),Zs(t,n)),gs=(e,t)=>JSON.parse(Ir(e.content,Zs(t,e.pubkey)));function Xs(e,t){let n={created_at:js(),content:"",tags:[],...e,pubkey:Tt(t)};return n.id=tn(n),n}function Ys(e,t,n){return ge({kind:rn,content:Js(e,t,n),created_at:zs(),tags:[]},t)}function Qs(e,t){let n=yr();return ge({kind:on,content:Js(e,n,t),created_at:zs(),tags:[["p",t]]},n)}function sn(e,t,n){let r=Xs(e,t),o=Ys(r,t,n);return Qs(o,n)}function zf(e,t,n){if(!n||n.length===0)throw new Error("At least one recipient is required.");let r=Tt(t),o=[sn(e,t,r)];return n.forEach(s=>{o.push(sn(e,t,s))}),o}function Hr(e,t){if(e.kind!==on)throw new Error(`unexpected wrap kind ${e.kind}, expected ${on}`);let n=gs(e,t);if(n.kind!==rn)throw new Error(`unexpected seal kind ${n.kind}, expected ${rn}`);if(!tt(n))throw new Error("seal signature is invalid");let r=gs(n,t);if(r.pubkey!==n.pubkey)throw new Error(`rumor pubkey ${r.pubkey} does not match seal pubkey ${n.pubkey}`);return r}function ei(e,t){let n=[];return e.forEach(r=>{try{n.push(Hr(r,t))}catch{}}),n.sort((r,o)=>r.created_at-o.created_at),n}function Zf(e,t,n,r){let o={created_at:Math.ceil(Date.now()/1e3),kind:As,tags:[],content:t};return(Array.isArray(e)?e:[e]).forEach(({publicKey:i,relayUrl:a})=>{o.tags.push(a?["p",i,a]:["p",i])}),r&&o.tags.push(["e",r.eventId,r.relayUrl||"","reply"]),n&&o.tags.push(["subject",n]),o}function ti(e,t,n,r,o){let s=Zf(t,n,r,o);return sn(s,e,t.publicKey)}function Jf(e,t,n,r,o){if(!t||t.length===0)throw new Error("At least one recipient is required.");return[{publicKey:Tt(e)},...t].map(i=>ti(e,i,n,r,o))}var Xf=Hr,Yf=ei,Qf={};G(Qf,{finishRepostEvent:()=>eh,getRepostedEvent:()=>th,getRepostedEventPointer:()=>ni});function eh(e,t,n,r){let o,s=[...e.tags??[],["e",t.id,n],["p",t.pubkey]];return t.kind===Ss?o=mr:(o=xr,s.push(["k",String(t.kind)])),ge({kind:o,tags:s,content:e.content===""||t.tags?.find(i=>i[0]==="-")?"":JSON.stringify(t),created_at:e.created_at},r)}function ni(e){if(![mr,xr].includes(e.kind))return;let t,n;for(let r=e.tags.length-1;r>=0&&(t===void 0||n===void 0);r--){let o=e.tags[r];o.length>=2&&(o[0]==="e"&&t===void 0?t=o:o[0]==="p"&&n===void 0&&(n=o))}if(t!==void 0)return{id:t[1],relays:[t[2],n?.[2]].filter(r=>typeof r=="string"),author:n?.[1]}}function th(e,{skipVerification:t}={}){let n=ni(e);if(n===void 0||e.content==="")return;let r;try{r=JSON.parse(e.content)}catch{return}if(r.id===n.id&&!(!t&&!tt(r)))return r}var nh={};G(nh,{NOSTR_URI_REGEX:()=>Or,parse:()=>oh,test:()=>rh});var Or=new RegExp(`nostr:(${Ms.source})`);function rh(e){return typeof e=="string"&&new RegExp(`^${Or.source}$`).test(e)}function oh(e){let t=e.match(new RegExp(`^${Or.source}$`));if(!t)throw new Error(`Invalid Nostr URI: ${e}`);return{uri:t[0],value:t[1],decoded:ln(t[1])}}var sh={};G(sh,{parse:()=>ah});function bs(e){if(e)return/^\d+$/.test(e)?parseInt(e,10):e}function ri(e,t){let n=e.indexOf(":"),r=e.indexOf(":",n+1);if(n===-1||r===-1)return;let o=parseInt(e.slice(0,n),10);if(Number.isNaN(o))return;let s=e.slice(n+1,r);if(ue(s))return{kind:o,pubkey:s,identifier:e.slice(r+1),relays:t?[t]:[]}}function ms(e){switch(e[0]){case"E":case"e":return!e[1]||!ue(e[1])?void 0:{id:e[1],relays:e[2]?[e[2]]:[],author:e[3]&&ue(e[3])?e[3]:void 0};case"A":case"a":return e[1]?ri(e[1],e[2]):void 0;case"I":case"i":return e[1]?{value:e[1],hint:e[2]}:void 0}}function ih(e){if(e[1]){if(e[1].includes(":"))return ri(e[1],e[2]);if(ue(e[1]))return{id:e[1],relays:e[2]?[e[2]]:[],author:e[3]&&ue(e[3])?e[3]:void 0}}}function ws(e){return e.findLast(t=>t.tagName==="A"||t.tagName==="a")?.pointer||e.findLast(t=>t.tagName==="I"||t.tagName==="i")?.pointer||e.findLast(t=>t.tagName==="E"||t.tagName==="e")?.pointer}function cr(e,t){if(!e||!("id"in e)||!e.author)return;let n=t.find(r=>r.pubkey===e.author);!n||!n.relays||(e.relays||(e.relays=[]),n.relays.forEach(r=>{e.relays.indexOf(r)===-1&&e.relays.push(r)}),n.relays=e.relays)}function ah(e){let t={root:void 0,rootKind:void 0,reply:void 0,replyKind:void 0,mentions:[],quotes:[],profiles:[]},n=[],r=[];for(let o of e.tags){if((o[0]==="E"||o[0]==="A"||o[0]==="I")&&o[1]){let s=ms(o);s&&n.push({tagName:o[0],pointer:s});continue}if((o[0]==="e"||o[0]==="a"||o[0]==="i")&&o[1]){let s=ms(o);s&&r.push({tagName:o[0],pointer:s});continue}if(o[0]==="K"){t.rootKind=bs(o[1]);continue}if(o[0]==="k"){t.replyKind=bs(o[1]);continue}if(o[0]==="q"){let s=ih(o);s&&t.quotes.push(s);continue}(o[0]==="P"||o[0]==="p")&&o[1]&&ue(o[1])&&t.profiles.push({pubkey:o[1],relays:o[2]?[o[2]]:[]})}return t.root=ws(n),t.reply=ws(r),cr(t.root,t.profiles),cr(t.reply,t.profiles),t.quotes.forEach(o=>cr(o,t.profiles)),t}var ch={};G(ch,{finishReactionEvent:()=>lh,getReactedEventPointer:()=>uh});function lh(e,t,n){let r=t.tags.filter(o=>o.length>=2&&(o[0]==="e"||o[0]==="p"));return ge({...e,kind:wr,tags:[...e.tags??[],...r,["e",t.id],["p",t.pubkey]],content:e.content??"+"},n)}function uh(e){if(e.kind!==wr)return;let t,n;for(let r=e.tags.length-1;r>=0&&(t===void 0||n===void 0);r--){let o=e.tags[r];o.length>=2&&(o[0]==="e"&&t===void 0?t=o:o[0]==="p"&&n===void 0&&(n=o))}if(!(t===void 0||n===void 0))return{id:t[1],relays:[t[2],n[2]].filter(r=>r!==void 0),author:n[1]}}var fh={};G(fh,{parse:()=>dh});var lr=/\W/m,xs=/[^\w\/] |[^\w\/]$|$|,| /m,hh=42;function*dh(e){let t=[];if(typeof e!="string"){for(let s=0;s<e.tags.length;s++){let i=e.tags[s];i[0]==="emoji"&&i.length>=3&&t.push({type:"emoji",shortcode:i[1],url:i[2]})}e=e.content}let n=e.length,r=0,o=0;e:for(;o<n;){let s=e.indexOf(":",o),i=e.indexOf("#",o);if(s===-1&&i===-1)break e;if(s===-1||i>=0&&i<s){if(i===0||e[i-1].match(lr)){let a=e.slice(i+1,i+hh).match(lr),c=a?i+1+a.index:n;yield{type:"text",text:e.slice(r,i),start:r,end:i},yield{type:"hashtag",value:e.slice(i+1,c),start:i,end:c},o=c,r=o;continue e}o=i+1;continue e}if(e.slice(s-5,s)==="nostr"){let a=e.slice(s+60).match(lr),c=a?s+60+a.index:n;try{let l,{data:f,type:h}=ln(e.slice(s+1,c));switch(h){case"npub":l={pubkey:f};break;case"note":l={id:f};break;case"nsec":o=c+1;continue;default:l=f}r!==s-5&&(yield{type:"text",text:e.slice(r,s-5),start:r,end:s-5}),yield{type:"reference",pointer:l,start:s-5,end:c},o=c,r=o;continue e}catch{o=s+1;continue e}}else if(e.slice(s-5,s)==="https"||e.slice(s-4,s)==="http"){let a=e.slice(s+4).match(xs),c=a?s+4+a.index:n,l=e[s-1]==="s"?5:4;try{let f=new URL(e.slice(s-l,c));if(f.hostname.indexOf(".")===-1)throw new Error("invalid url");if(r!==s-l&&(yield{type:"text",text:e.slice(r,s-l),start:r,end:s-l}),/\.(png|jpe?g|gif|webp|heic|svg)$/i.test(f.pathname)){yield{type:"image",url:f.toString(),start:s-l,end:c},o=c,r=o;continue e}if(/\.(mp4|avi|webm|mkv|mov)$/i.test(f.pathname)){yield{type:"video",url:f.toString(),start:s-l,end:c},o=c,r=o;continue e}if(/\.(mp3|aac|ogg|opus|wav|flac)$/i.test(f.pathname)){yield{type:"audio",url:f.toString(),start:s-l,end:c},o=c,r=o;continue e}yield{type:"url",url:f.toString(),start:s-l,end:c},o=c,r=o;continue e}catch{o=c+1;continue e}}else if(e.slice(s-3,s)==="wss"||e.slice(s-2,s)==="ws"){let a=e.slice(s+4).match(xs),c=a?s+4+a.index:n,l=e[s-1]==="s"?3:2;try{let f=new URL(e.slice(s-l,c));if(f.hostname.indexOf(".")===-1)throw new Error("invalid ws url");r!==s-l&&(yield{type:"text",text:e.slice(r,s-l),start:r,end:s-l}),yield{type:"relay",url:f.toString(),start:s-l,end:c},o=c,r=o;continue e}catch{o=c+1;continue e}}else{for(let a=0;a<t.length;a++){let c=t[a];if(e[s+c.shortcode.length+1]===":"&&e.slice(s+1,s+c.shortcode.length+1)===c.shortcode){r!==s&&(yield{type:"text",text:e.slice(r,s),start:r,end:s}),yield{...c,start:s,end:s+c.shortcode.length+2},o=s+c.shortcode.length+2,r=o;continue e}}o=s+1;continue e}}r!==n&&(yield{type:"text",text:e.slice(r),start:r,end:n})}var ph={};G(ph,{channelCreateEvent:()=>yh,channelHideMessageEvent:()=>mh,channelMessageEvent:()=>bh,channelMetadataEvent:()=>gh,channelMuteUserEvent:()=>wh});var yh=(e,t)=>{let n;if(typeof e.content=="object")n=JSON.stringify(e.content);else if(typeof e.content=="string")n=e.content;else return;return ge({kind:Ts,tags:[...e.tags??[]],content:n,created_at:e.created_at},t)},gh=(e,t)=>{let n;if(typeof e.content=="object")n=JSON.stringify(e.content);else if(typeof e.content=="string")n=e.content;else return;return ge({kind:Bs,tags:[["e",e.channel_create_event_id],...e.tags??[]],content:n,created_at:e.created_at},t)},bh=(e,t)=>{let n=[["e",e.channel_create_event_id,e.relay_url,"root"]];return e.reply_to_channel_message_event_id&&n.push(["e",e.reply_to_channel_message_event_id,e.relay_url,"reply"]),ge({kind:Rs,tags:[...n,...e.tags??[]],content:e.content,created_at:e.created_at},t)},mh=(e,t)=>{let n;if(typeof e.content=="object")n=JSON.stringify(e.content);else if(typeof e.content=="string")n=e.content;else return;return ge({kind:_s,tags:[["e",e.channel_message_event_id],...e.tags??[]],content:n,created_at:e.created_at},t)},wh=(e,t)=>{let n;if(typeof e.content=="object")n=JSON.stringify(e.content);else if(typeof e.content=="string")n=e.content;else return;return ge({kind:ks,tags:[["p",e.pubkey_to_mute],...e.tags??[]],content:n,created_at:e.created_at},t)},xh={};G(xh,{EMOJI_SHORTCODE_REGEX:()=>oi,matchAll:()=>vh,regex:()=>Ur,replaceAll:()=>Eh});var oi=/:(\w+):/,Ur=()=>new RegExp(`\\B${oi.source}\\B`,"g");function*vh(e){let t=e.matchAll(Ur());for(let n of t)try{let[r,o]=n;yield{shortcode:r,name:o,start:n.index,end:n.index+r.length}}catch{}}function Eh(e,t){return e.replaceAll(Ur(),(n,r)=>t({shortcode:n,name:r}))}var Sh={};G(Sh,{useFetchImplementation:()=>Ah,validateGithub:()=>Th});var Pr;try{Pr=fetch}catch{}function Ah(e){Pr=e}async function Th(e,t,n){try{return await(await Pr(`https://gist.github.com/${t}/${n}/raw`)).text()===`Verifying that I control the following Nostr public key: ${e}`}catch{return!1}}var Bh={};G(Bh,{makeNwcRequestEvent:()=>_h,parseConnectionString:()=>Rh});function Rh(e){let{host:t,pathname:n,searchParams:r}=new URL(e),o=n||t,s=r.getAll("relay"),i=r.get("secret");if(!o||s.length===0||!i)throw new Error("invalid connection string");return{pubkey:o,relay:s[0],relays:s,secret:i}}async function _h(e,t,n){let o=qs(t,e,JSON.stringify({method:"pay_invoice",params:{invoice:n}})),s={kind:Cs,created_at:Math.round(Date.now()/1e3),content:o,tags:[["p",e]]};return ge(s,t)}var kh={};G(kh,{normalizeIdentifier:()=>Lh});function Lh(e){return e=e.trim().toLowerCase(),e=e.normalize("NFKC"),Array.from(e).map(t=>/\p{Letter}/u.test(t)||/\p{Number}/u.test(t)?t:"-").join("")}var Ch={};G(Ch,{getSatoshisAmountFromBolt11:()=>Nh,getZapEndpoint:()=>Hh,makeZapReceipt:()=>Ph,makeZapRequest:()=>Oh,useFetchImplementation:()=>Ih,validateZapRequest:()=>Uh});var Nr;try{Nr=fetch}catch{}function Ih(e){Nr=e}async function Hh(e){try{let t="",{lud06:n,lud16:r}=JSON.parse(e.content);if(r){let[i,a]=r.split("@");t=new URL(`/.well-known/lnurlp/${i}`,`https://${a}`).toString()}else if(n){let{words:i}=Me.decode(n,1e3),a=Me.fromWords(i);t=Ce.decode(a)}else return null;let s=await(await Nr(t)).json();if(s.allowsNostr&&s.nostrPubkey)return s.callback}catch{}return null}function Oh(e){let t={kind:9734,created_at:Math.round(Date.now()/1e3),content:e.comment||"",tags:[["p","pubkey"in e?e.pubkey:e.event.pubkey],["amount",e.amount.toString()],["relays",...e.relays]]};if("event"in e){if(t.tags.push(["e",e.event.id]),gr(e.event.kind)){let n=["a",`${e.event.kind}:${e.event.pubkey}:`];t.tags.push(n)}else if(br(e.event.kind)){let n=e.event.tags.find(([o,s])=>o==="d"&&s);if(!n)throw new Error("d tag not found or is empty");let r=["a",`${e.event.kind}:${e.event.pubkey}:${n[1]}`];t.tags.push(r)}t.tags.push(["k",e.event.kind.toString()])}return t}function Uh(e){let t;try{t=JSON.parse(e)}catch{return"Invalid zap request JSON."}if(!pr(t))return"Zap request is not a valid Nostr event.";if(!tt(t))return"Invalid signature on zap request.";let n=t.tags.find(([s,i])=>s==="p"&&i);if(!n)return"Zap request doesn't have a 'p' tag.";if(!ue(n[1]))return"Zap request 'p' tag is not valid hex.";let r=t.tags.find(([s,i])=>s==="e"&&i);return r&&!ue(r[1])?"Zap request 'e' tag is not valid hex.":t.tags.find(([s,i])=>s==="relays"&&i)?null:"Zap request doesn't have a 'relays' tag."}function Ph({zapRequest:e,preimage:t,bolt11:n,paidAt:r}){let o=JSON.parse(e),s=o.tags.filter(([a])=>a==="e"||a==="p"||a==="a"),i={kind:9735,created_at:Math.round(r.getTime()/1e3),content:"",tags:[...s,["P",o.pubkey],["bolt11",n],["description",e]]};return t&&i.tags.push(["preimage",t]),i}function Nh(e){if(e.length<50)return 0;e=e.substring(0,50);let t=e.lastIndexOf("1");if(t===-1)return 0;let n=e.substring(0,t);if(!n.startsWith("lnbc"))return 0;let r=n.substring(4);if(r.length<1)return 0;let o=r[r.length-1],s=o.charCodeAt(0)-48,i=s>=0&&s<=9,a=r.length-1;if(i&&a++,a<1)return 0;let c=parseInt(r.substring(0,a));switch(o){case"m":return c*1e5;case"u":return c*100;case"n":return c/10;case"p":return c/1e4;default:return c*1e8}}var Mh={};G(Mh,{Negentropy:()=>ii,NegentropyStorageVector:()=>$h,NegentropySync:()=>Wh});var ur=97,ft=32,si=16,Qe={Skip:0,Fingerprint:1,IdList:2},Le=class{constructor(e){u(this,"_raw");u(this,"length");typeof e=="number"?(this._raw=new Uint8Array(e),this.length=0):e instanceof Uint8Array?(this._raw=new Uint8Array(e),this.length=e.length):(this._raw=new Uint8Array(512),this.length=0)}unwrap(){return this._raw.subarray(0,this.length)}get capacity(){return this._raw.byteLength}extend(e){if(e instanceof Le&&(e=e.unwrap()),typeof e.length!="number")throw Error("bad length");let t=e.length+this.length;if(this.capacity<t){let n=this._raw,r=Math.max(this.capacity*2,t);this._raw=new Uint8Array(r),this._raw.set(n)}this._raw.set(e,this.length),this.length+=e.length}shift(){let e=this._raw[0];return this._raw=this._raw.subarray(1),this.length--,e}shiftN(e=1){let t=this._raw.subarray(0,e);return this._raw=this._raw.subarray(e),this.length-=e,t}};function en(e){let t=0;for(;;){if(e.length===0)throw Error("parse ends prematurely");let n=e.shift();if(t=t<<7|n&127,(n&128)===0)break}return t}function ke(e){if(e===0)return new Le(new Uint8Array([0]));let t=[];for(;e!==0;)t.push(e&127),e>>>=7;t.reverse();for(let n=0;n<t.length-1;n++)t[n]|=128;return new Le(new Uint8Array(t))}function qh(e){return nn(e,1)[0]}function nn(e,t){if(e.length<t)throw Error("parse ends prematurely");return e.shiftN(t)}var Dh=class{constructor(){u(this,"buf");this.setToZero()}setToZero(){this.buf=new Uint8Array(ft)}add(e){let t=0,n=0,r=new DataView(this.buf.buffer),o=new DataView(e.buffer);for(let s=0;s<8;s++){let i=s*4,a=r.getUint32(i,!0),c=o.getUint32(i,!0),l=a;l+=t,l+=c,l>4294967295&&(n=1),r.setUint32(i,l&4294967295,!0),t=n,n=0}}negate(){let e=new DataView(this.buf.buffer);for(let n=0;n<8;n++){let r=n*4;e.setUint32(r,~e.getUint32(r,!0))}let t=new Uint8Array(ft);t[0]=1,this.add(t)}getFingerprint(e){let t=new Le;return t.extend(this.buf),t.extend(ke(e)),te(t.unwrap()).subarray(0,si)}},$h=class{constructor(){u(this,"items");u(this,"sealed");this.items=[],this.sealed=!1}insert(e,t){if(this.sealed)throw Error("already sealed");let n=$(t);if(n.byteLength!==ft)throw Error("bad id size for added item");this.items.push({timestamp:e,id:n})}seal(){if(this.sealed)throw Error("already sealed");this.sealed=!0,this.items.sort(fr);for(let e=1;e<this.items.length;e++)if(fr(this.items[e-1],this.items[e])===0)throw Error("duplicate item inserted")}unseal(){this.sealed=!1}size(){return this._checkSealed(),this.items.length}getItem(e){if(this._checkSealed(),e>=this.items.length)throw Error("out of range");return this.items[e]}iterate(e,t,n){this._checkSealed(),this._checkBounds(e,t);for(let r=e;r<t&&n(this.items[r],r);++r);}findLowerBound(e,t,n){return this._checkSealed(),this._checkBounds(e,t),this._binarySearch(this.items,e,t,r=>fr(r,n)<0)}fingerprint(e,t){let n=new Dh;return n.setToZero(),this.iterate(e,t,r=>(n.add(r.id),!0)),n.getFingerprint(t-e)}_checkSealed(){if(!this.sealed)throw Error("not sealed")}_checkBounds(e,t){if(e>t||t>this.items.length)throw Error("bad range")}_binarySearch(e,t,n,r){let o=n-t;for(;o>0;){let s=t,i=Math.floor(o/2);s+=i,r(e[s])?(t=++s,o-=i+1):o=i}return t}},ii=class{constructor(e,t=6e4){u(this,"storage");u(this,"frameSizeLimit");u(this,"lastTimestampIn");u(this,"lastTimestampOut");if(t<4096)throw Error("frameSizeLimit too small");this.storage=e,this.frameSizeLimit=t,this.lastTimestampIn=0,this.lastTimestampOut=0}_bound(e,t){return{timestamp:e,id:t||new Uint8Array(0)}}initiate(){let e=new Le;return e.extend(new Uint8Array([ur])),this.splitRange(0,this.storage.size(),this._bound(Number.MAX_VALUE),e),D(e.unwrap())}reconcile(e,t,n){let r=new Le($(e));this.lastTimestampIn=this.lastTimestampOut=0;let o=new Le;o.extend(new Uint8Array([ur]));let s=qh(r);if(s<96||s>111)throw Error("invalid negentropy protocol version byte");if(s!==ur)throw Error("unsupported negentropy protocol version requested: "+(s-96));let i=this.storage.size(),a=this._bound(0),c=0,l=!1;for(;r.length!==0;){let f=new Le,h=()=>{l&&(l=!1,f.extend(this.encodeBound(a)),f.extend(ke(Qe.Skip)))},d=this.decodeBound(r),p=en(r),y=c,m=this.storage.findLowerBound(c,i,d);if(p===Qe.Skip)l=!0;else if(p===Qe.Fingerprint){let w=nn(r,si),x=this.storage.fingerprint(y,m);ai(w,x)!==0?(h(),this.splitRange(y,m,d,f)):l=!0}else if(p===Qe.IdList){let w=en(r),x={};for(let A=0;A<w;A++){let I=nn(r,ft);x[D(I)]=I}if(l=!0,this.storage.iterate(y,m,A=>{let I=A.id,P=D(I);return x[P]?delete x[D(I)]:t?.(P),!0}),n)for(let A of Object.values(x))n(D(A))}else throw Error("unexpected mode");if(this.exceededFrameSizeLimit(o.length+f.length)){let w=this.storage.fingerprint(m,i);o.extend(this.encodeBound(this._bound(Number.MAX_VALUE))),o.extend(ke(Qe.Fingerprint)),o.extend(w);break}else o.extend(f);c=m,a=d}return o.length===1?null:D(o.unwrap())}splitRange(e,t,n,r){let o=t-e,s=16;if(o<s*2)r.extend(this.encodeBound(n)),r.extend(ke(Qe.IdList)),r.extend(ke(o)),this.storage.iterate(e,t,i=>(r.extend(i.id),!0));else{let i=Math.floor(o/s),a=o%s,c=e;for(let l=0;l<s;l++){let f=i+(l<a?1:0),h=this.storage.fingerprint(c,c+f);c+=f;let d;if(c===t)d=n;else{let p,y;this.storage.iterate(c-1,c+1,(m,w)=>(w===c-1?p=m:y=m,!0)),d=this.getMinimalBound(p,y)}r.extend(this.encodeBound(d)),r.extend(ke(Qe.Fingerprint)),r.extend(h)}}}exceededFrameSizeLimit(e){return e>this.frameSizeLimit-200}decodeTimestampIn(e){let t=en(e);return t=t===0?Number.MAX_VALUE:t-1,this.lastTimestampIn===Number.MAX_VALUE||t===Number.MAX_VALUE?(this.lastTimestampIn=Number.MAX_VALUE,Number.MAX_VALUE):(t+=this.lastTimestampIn,this.lastTimestampIn=t,t)}decodeBound(e){let t=this.decodeTimestampIn(e),n=en(e);if(n>ft)throw Error("bound key too long");let r=nn(e,n);return{timestamp:t,id:r}}encodeTimestampOut(e){if(e===Number.MAX_VALUE)return this.lastTimestampOut=Number.MAX_VALUE,ke(0);let t=e;return e-=this.lastTimestampOut,this.lastTimestampOut=t,ke(e+1)}encodeBound(e){let t=new Le;return t.extend(this.encodeTimestampOut(e.timestamp)),t.extend(ke(e.id.length)),t.extend(e.id),t}getMinimalBound(e,t){if(t.timestamp!==e.timestamp)return this._bound(t.timestamp);{let n=0,r=t.id,o=e.id;for(let s=0;s<ft&&r[s]===o[s];s++)n++;return this._bound(t.timestamp,t.id.subarray(0,n+1))}}};function ai(e,t){for(let n=0;n<e.byteLength;n++){if(e[n]<t[n])return-1;if(e[n]>t[n])return 1}return e.byteLength>t.byteLength?1:e.byteLength<t.byteLength?-1:0}function fr(e,t){return e.timestamp===t.timestamp?ai(e.id,t.id):e.timestamp-t.timestamp}var Wh=class{constructor(e,t,n,r={}){u(this,"relay");u(this,"storage");u(this,"neg");u(this,"filter");u(this,"subscription");u(this,"onhave");u(this,"onneed");this.relay=e,this.storage=t,this.neg=new ii(t),this.onhave=r.onhave,this.onneed=r.onneed,this.filter=n,this.subscription=this.relay.prepareSubscription([{}],{label:r.label||"negentropy"}),this.subscription.oncustom=o=>{switch(o[0]){case"NEG-MSG":{o.length<3&&console.warn(`got invalid NEG-MSG from ${this.relay.url}: ${o}`);try{let s=this.neg.reconcile(o[2],this.onhave,this.onneed);s?this.relay.send(`["NEG-MSG", "${this.subscription.id}", "${s}"]`):(this.close(),r.onclose?.())}catch(s){console.error("negentropy reconcile error:",s),r?.onclose?.(`reconcile error: ${s}`)}break}case"NEG-CLOSE":{let s=o[2];console.warn("negentropy error:",s),r.onclose?.(s);break}case"NEG-ERR":r.onclose?.()}}}async start(){let e=this.neg.initiate();this.relay.send(`["NEG-OPEN","${this.subscription.id}",${JSON.stringify(this.filter)},"${e}"]`)}close(){this.relay.send(`["NEG-CLOSE","${this.subscription.id}"]`),this.subscription.close()}},Vh={};G(Vh,{getToken:()=>Gh,hashPayload:()=>Mr,unpackEventFromToken:()=>li,validateEvent:()=>yi,validateEventKind:()=>fi,validateEventMethodTag:()=>di,validateEventPayloadTag:()=>pi,validateEventTimestamp:()=>ui,validateEventUrlTag:()=>hi,validateToken:()=>Kh});var ci="Nostr ";async function Gh(e,t,n,r=!1,o){let s={kind:vr,tags:[["u",e],["method",t]],created_at:Math.round(new Date().getTime()/1e3),content:""};o&&s.tags.push(["payload",Mr(o)]);let i=await n(s);return(r?ci:"")+le.encode(ye.encode(JSON.stringify(i)))}async function Kh(e,t,n){let r=await li(e).catch(s=>{throw s});return await yi(r,t,n).catch(s=>{throw s})}async function li(e){if(!e)throw new Error("Missing token");e=e.replace(ci,"");let t=Ce.decode(le.decode(e));if(!t||t.length===0||!t.startsWith("{"))throw new Error("Invalid token");return JSON.parse(t)}function ui(e){return e.created_at?Math.abs(Math.round(new Date().getTime()/1e3)-e.created_at)<60:!1}function fi(e){return e.kind===vr}function hi(e,t){let n=e.tags.find(r=>r[0]==="u");return n?n.length>0&&n[1]===t:!1}function di(e,t){let n=e.tags.find(r=>r[0]==="method");return n?n.length>0&&n[1].toLowerCase()===t.toLowerCase():!1}function Mr(e){let t=te(ye.encode(JSON.stringify(e)));return D(t)}function pi(e,t){let n=e.tags.find(o=>o[0]==="payload");if(!n)return!1;let r=Mr(t);return n.length>0&&n[1]===r}async function yi(e,t,n,r){if(!tt(e))throw new Error("Invalid nostr event, signature invalid");if(!fi(e))throw new Error("Invalid nostr event, kind invalid");if(!ui(e))throw new Error("Invalid nostr event, created_at timestamp invalid");if(!hi(e,t))throw new Error("Invalid nostr event, url tag invalid");if(!di(e,n))throw new Error("Invalid nostr event, method tag invalid");if(r&&typeof r=="object"&&Object.keys(r).length>0&&!pi(e,r))throw new Error("Invalid nostr event, payload tag does not match request body hash");return!0}var Fh=new TextDecoder("utf-8"),Vr=new TextEncoder;function dt(e){try{e.indexOf("://")===-1&&(e="wss://"+e);let t=new URL(e);return t.protocol==="http:"?t.protocol="ws:":t.protocol==="https:"&&(t.protocol="wss:"),t.pathname=t.pathname.replace(/\/+/g,"/"),t.pathname.endsWith("/")&&(t.pathname=t.pathname.slice(0,-1)),(t.port==="80"&&t.protocol==="ws:"||t.port==="443"&&t.protocol==="wss:")&&(t.port=""),t.searchParams.sort(),t.hash="",t.toString()}catch{throw new Error(`Invalid URL: ${e}`)}}function jh(e){if(e.length!==64)return!1;for(let t=0;t<64;t++){let n=e.charCodeAt(t);if(isNaN(n)||n<48||n>102||n>57&&n<97)return!1}return!0}var ht=Symbol("verified"),zh=e=>e instanceof Object;function Zh(e){if(!zh(e)||typeof e.kind!="number"||typeof e.content!="string"||typeof e.created_at!="number"||typeof e.pubkey!="string"||!jh(e.pubkey)||!Array.isArray(e.tags))return!1;for(let t=0;t<e.tags.length;t++){let n=e.tags[t];if(!Array.isArray(n))return!1;for(let r=0;r<n.length;r++)if(typeof n[r]!="string")return!1}return!0}var Jh=class{generateSecretKey(){return he.utils.randomSecretKey()}getPublicKey(e){return D(he.getPublicKey(e))}finalizeEvent(e,t){let n=e;return n.pubkey=D(he.getPublicKey(t)),n.id=qr(n),n.sig=D(he.sign($(qr(n)),t)),n[ht]=!0,n}verifyEvent(e){if(typeof e[ht]=="boolean")return e[ht];try{let t=qr(e);if(t!==e.id)return e[ht]=!1,!1;let n=he.verify($(e.sig),$(t),$(e.pubkey));return e[ht]=n,n}catch{return e[ht]=!1,!1}}};function Xh(e){if(!Zh(e))throw new Error("can't serialize event with wrong or missing properties");return JSON.stringify([0,e.pubkey,e.created_at,e.kind,e.tags,e.content])}function qr(e){let t=te(Vr.encode(Xh(e)));return D(t)}var pn=new Jh,qp=pn.generateSecretKey,gi=pn.getPublicKey,Yh=pn.finalizeEvent,mi=pn.verifyEvent,Gr=1,Kr=4294967295,Fr=65536;function Dr(e,t){let n=ze.getSharedSecret(e,$("02"+t)).subarray(1,33);return Yt(te,n,Vr.encode("nip44-v2"))}function wi(e,t){let n=Qt(te,e,t,76);return{chacha_key:n.subarray(0,32),chacha_nonce:n.subarray(32,44),hmac_key:n.subarray(44,76)}}function xi(e){if(!Number.isSafeInteger(e)||e<1)throw new Error("expected positive integer");if(e<=32)return 32;let t=2**(Math.floor(Math.log2(e-1))+1),n=t<=256?32:t/8;return n*(Math.floor((e-1)/n)+1)}function Qh(e){if(!Number.isSafeInteger(e)||e<Gr||e>65535)throw new Error("invalid plaintext size: must be between 1 and 65535 bytes");let t=new Uint8Array(2);return new DataView(t.buffer).setUint16(0,e,!1),t}function ed(e){if(!Number.isSafeInteger(e)||e<Fr||e>Kr)throw new Error("invalid plaintext size: must be between 65536 and 4294967295 bytes");let t=new Uint8Array(4);return new DataView(t.buffer).setUint32(0,e,!1),t}function td(e){let t=Vr.encode(e),n=t.length;if(n<Gr||n>Kr)throw new Error("invalid plaintext size: must be between 1 and 4294967295 bytes");let r=n>=Fr?de(new Uint8Array([0,0]),ed(n)):Qh(n),o=new Uint8Array(xi(n)-n);return de(r,t,o)}function nd(e){let t=new DataView(e.buffer,e.byteOffset,e.byteLength),n=t.getUint16(0),r,o;if(n===0){if(r=t.getUint32(2),r<Fr)throw new Error("invalid padding");o=6}else r=n,o=2;let s=e.subarray(o,o+r);if(r<Gr||r>Kr||s.length!==r||e.length!==o+xi(r))throw new Error("invalid padding");return Fh.decode(s)}function vi(e,t,n){if(n.length!==32)throw new Error("AAD associated data must be 32 bytes");let r=de(n,t);return De(te,e,r)}function rd(e){if(typeof e!="string")throw new Error("payload must be a valid string");let t=e.length;if(t<132)throw new Error("invalid payload length: "+t);if(e[0]==="#")throw new Error("unknown encryption version");let n;try{n=le.decode(e)}catch(s){throw new Error("invalid base64: "+s.message)}let r=n.length;if(r<99)throw new Error("invalid data length: "+r);let o=n[0];if(o!==2)throw new Error("unknown encryption version "+o);return{nonce:n.subarray(1,33),ciphertext:n.subarray(33,-32),mac:n.subarray(-32)}}function od(e,t,n=at(32)){let{chacha_key:r,chacha_nonce:o,hmac_key:s}=wi(t,n),i=td(e),a=Ye(r,o,i),c=vi(s,a,n);return le.encode(de(new Uint8Array([2]),n,a,c))}function bi(e,t){let{nonce:n,ciphertext:r,mac:o}=rd(e),{chacha_key:s,chacha_nonce:i,hmac_key:a}=wi(t,n),c=vi(a,r,n);if(!Je(c,o))throw new Error("invalid MAC");let l=Ye(s,i,r);return nd(l)}var sd=/^(?:([\w.+-]+)@)?([\w_-]+(\.[\w_-]+)+)$/,id;try{id=fetch}catch{}var ad=22242,$r=24133;function cd(e,t){if(e.ids&&e.ids.indexOf(t.id)===-1||e.kinds&&e.kinds.indexOf(t.kind)===-1||e.authors&&e.authors.indexOf(t.pubkey)===-1)return!1;for(let n in e)if(n[0]==="#"){let r=n.slice(1),o=e[`#${r}`];if(o&&!t.tags.find(([s,i])=>s===n.slice(1)&&o.indexOf(i)!==-1))return!1}return!(e.since&&t.created_at<e.since||e.until&&t.created_at>e.until)}function ld(e,t){for(let n=0;n<e.length;n++)if(cd(e[n],t))return!0;return!1}function ud(e,t){let n=t.length+3,r=e.indexOf(`"${t}":`)+n,o=e.slice(r).indexOf('"')+r+1;return e.slice(o,o+64)}function fd(e){let t=e.slice(0,22).indexOf('"EVENT"');if(t===-1)return null;let n=e.slice(t+7+1).indexOf('"');if(n===-1)return null;let r=t+7+1+n,o=e.slice(r+1,80).indexOf('"');if(o===-1)return null;let s=r+1+o;return e.slice(r+1,s)}function hd(e,t){return{kind:ad,created_at:Math.floor(Date.now()/1e3),tags:[["relay",e],["challenge",t]],content:""}}var Wr=class extends Error{constructor(e,t){super(`Tried to send message '${e} on a closed connection to ${t}.`),this.name="SendingOnClosedConnection"}},Ei=class{constructor(e,t){u(this,"url");u(this,"_connected",!1);u(this,"onclose",null);u(this,"onnotice",e=>console.debug(`NOTICE from ${this.url}: ${e}`));u(this,"onauth");u(this,"baseEoseTimeout",4400);u(this,"publishTimeout",4400);u(this,"pingFrequency",29e3);u(this,"pingTimeout",2e4);u(this,"resubscribeBackoff",[1e4,1e4,1e4,2e4,2e4,3e4,6e4]);u(this,"openSubs",new Map);u(this,"enablePing");u(this,"enableReconnect");u(this,"idleTimeout",0);u(this,"idleSince",Date.now());u(this,"ongoingOperations",0);u(this,"reconnectTimeoutHandle");u(this,"pingIntervalHandle");u(this,"reconnectAttempts",0);u(this,"skipReconnection",!1);u(this,"idleTimeoutHandle");u(this,"connectionPromise");u(this,"openCountRequests",new Map);u(this,"openEventPublishes",new Map);u(this,"ws");u(this,"challenge");u(this,"authPromise");u(this,"serial",0);u(this,"verifyEvent");u(this,"_WebSocket");this.url=dt(e),this.verifyEvent=t.verifyEvent,this._WebSocket=t.websocketImplementation||WebSocket,this.enablePing=t.enablePing,this.enableReconnect=t.enableReconnect||!1,t.idleTimeout&&(this.idleTimeout=t.idleTimeout)}static async connect(e,t){let n=new Ei(e,t);return await n.connect(t),n}closeAllSubscriptions(e){for(let[t,n]of this.openSubs)n.close(e);this.openSubs.clear();for(let[t,n]of this.openEventPublishes)n.reject(new Error(e));this.openEventPublishes.clear();for(let[t,n]of this.openCountRequests)n.reject(new Error(e));this.openCountRequests.clear()}get connected(){return this._connected}clearIdleTimeout(){this.idleTimeoutHandle&&(clearTimeout(this.idleTimeoutHandle),this.idleTimeoutHandle=void 0)}scheduleIdleClose(){this.clearIdleTimeout(),this.idleTimeout>0&&(this.idleTimeoutHandle=setTimeout(()=>{this.ongoingOperations===0&&this.idleSince&&this.close()},this.idleTimeout))}async reconnect(){let e=this.resubscribeBackoff[Math.min(this.reconnectAttempts,this.resubscribeBackoff.length-1)];this.reconnectAttempts++,this.reconnectTimeoutHandle=setTimeout(async()=>{try{await this.connect()}catch{}},e)}handleHardClose(e){this.ws&&(this.ws.onopen=null,this.ws.onerror=null,this.ws.onclose=null),this.pingIntervalHandle&&(clearInterval(this.pingIntervalHandle),this.pingIntervalHandle=void 0),this._connected=!1,this.connectionPromise=void 0,this.idleSince=void 0,this.clearIdleTimeout(),this.enableReconnect&&!this.skipReconnection?this.reconnect():(this.onclose?.(),this.closeAllSubscriptions(e))}async connect(e){let t;return this.connectionPromise?this.connectionPromise:(this.challenge=void 0,this.authPromise=void 0,this.skipReconnection=!1,this.connectionPromise=new Promise((n,r)=>{e?.timeout&&(t=setTimeout(()=>{r("connection timed out"),this.connectionPromise=void 0,this.reconnectAttempts===0&&(this.skipReconnection=!0),this.handleHardClose("relay connection timed out")},e.timeout)),e?.abort&&(e.abort.onabort=r);try{this.ws=new this._WebSocket(this.url)}catch(o){clearTimeout(t),r(o);return}this.ws.onopen=()=>{this.reconnectTimeoutHandle&&(clearTimeout(this.reconnectTimeoutHandle),this.reconnectTimeoutHandle=void 0),clearTimeout(t),this._connected=!0;let o=this.reconnectAttempts>0;this.reconnectAttempts=0;for(let s of this.openSubs.values()){if(s.eosed=!1,o)for(let i=0;i<s.filters.length;i++)s.lastEmitted&&(s.filters[i].since=s.lastEmitted+1);s.fire()}this.enablePing&&(this.pingIntervalHandle=setInterval(()=>this.pingpong(),this.pingFrequency)),n()},this.ws.onerror=()=>{clearTimeout(t),r("connection failed"),this.connectionPromise=void 0,this.reconnectAttempts===0&&(this.skipReconnection=!0),this.handleHardClose("relay connection failed")},this.ws.onclose=o=>{clearTimeout(t),r(o.message||"websocket closed"),this.handleHardClose("relay connection closed")},this.ws.onmessage=this._onmessage.bind(this)}),this.connectionPromise)}waitForPingPong(){return new Promise(e=>{this.ws.once("pong",()=>e(!0)),this.ws.ping()})}waitForDummyReq(){return new Promise((e,t)=>{if(!this.connectionPromise)return t(new Error(`no connection to ${this.url}, can't ping`));try{let n=this.subscribe([{ids:["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"],limit:0}],{label:"<forced-ping>",oneose:()=>{e(!0),n.close()},onclose(){e(!0)},eoseTimeout:this.pingTimeout+1e3})}catch(n){t(n)}})}async pingpong(){this.ws?.readyState===1&&(await Promise.any([this.ws&&this.ws.ping&&this.ws.once?this.waitForPingPong():this.waitForDummyReq(),new Promise(t=>setTimeout(()=>t(!1),this.pingTimeout))])||this.ws?.readyState===this._WebSocket.OPEN&&this.ws?.close())}async send(e){if(!this.connectionPromise)throw new Wr(e,this.url);this.connectionPromise.then(()=>{this.ws?.send(e)})}async auth(e){let t=this.challenge;if(!t)throw new Error("can't perform auth, no challenge was received");return this.authPromise?this.authPromise:(this.authPromise=new Promise(async(n,r)=>{try{let o=await e(hd(this.url,t)),s=setTimeout(()=>{let i=this.openEventPublishes.get(o.id);i&&(i.reject(new Error("auth timed out")),this.openEventPublishes.delete(o.id))},this.publishTimeout);this.openEventPublishes.set(o.id,{resolve:n,reject:r,timeout:s}),this.send('["AUTH",'+JSON.stringify(o)+"]")}catch(o){console.warn("subscribe auth function failed:",o)}}),this.authPromise)}async publish(e){this.idleSince=void 0,this.clearIdleTimeout(),this.ongoingOperations++;let t=new Promise((n,r)=>{let o=setTimeout(()=>{let s=this.openEventPublishes.get(e.id);s&&(s.reject(new Error("publish timed out")),this.openEventPublishes.delete(e.id))},this.publishTimeout);this.openEventPublishes.set(e.id,{resolve:n,reject:r,timeout:o})});try{await this.send('["EVENT",'+JSON.stringify(e)+"]")}catch(n){let r=this.openEventPublishes.get(e.id);r&&(r.reject(n),this.openEventPublishes.delete(e.id))}return this.ongoingOperations--,this.ongoingOperations===0&&(this.idleSince=Date.now(),this.scheduleIdleClose()),t}async count(e,t){return(await this.countWithHLL(e,t)).count}async countWithHLL(e,t){this.serial++;let n=t?.id||"count:"+this.serial,r=new Promise((o,s)=>{this.openCountRequests.set(n,{resolve:o,reject:s})});try{await this.send('["COUNT","'+n+'",'+JSON.stringify(e).substring(1))}catch(o){let s=this.openCountRequests.get(n);s&&(s.reject(o),this.openCountRequests.delete(n))}return r}subscribe(e,t){t.label!=="<forced-ping>"&&(this.idleSince=void 0,this.clearIdleTimeout(),this.ongoingOperations++);let n=this.prepareSubscription(e,t);return n.fire(),t.abort&&(t.abort.onabort=()=>n.close(String(t.abort.reason||"<aborted>"))),n}prepareSubscription(e,t){this.serial++;let n=t.id||(t.label?t.label+":":"sub:")+this.serial,r=new dd(this,n,e,t);return this.openSubs.set(n,r),r}close(){this.skipReconnection=!0,this.reconnectTimeoutHandle&&(clearTimeout(this.reconnectTimeoutHandle),this.reconnectTimeoutHandle=void 0),this.pingIntervalHandle&&(clearInterval(this.pingIntervalHandle),this.pingIntervalHandle=void 0),this.closeAllSubscriptions("relay connection closed by us"),this._connected=!1,this.connectionPromise=void 0,this.idleSince=void 0,this.clearIdleTimeout(),this.onclose?.(),this.ws&&(this.ws.onopen=null,this.ws.onerror=null,this.ws.onclose=null,this.ws.readyState!==this._WebSocket.CLOSING&&this.ws.readyState!==this._WebSocket.CLOSED&&this.ws.close())}_onmessage(e){let t=e.data;if(!t)return;let n=fd(t);if(n){let r=this.openSubs.get(n);if(!r)return;let o=ud(t,"id"),s=r.alreadyHaveEvent?.(o);if(r.receivedEvent?.(this,o),s)return}try{let r=JSON.parse(t);switch(r[0]){case"EVENT":{let o=this.openSubs.get(r[1]),s=r[2];ld(o.filters,s)&&this.verifyEvent(s,this.url)?o.onevent(s):o.oninvalidevent?.(s),(!o.lastEmitted||o.lastEmitted<s.created_at)&&(o.lastEmitted=s.created_at);return}case"COUNT":{let o=r[1],s=r[2],i=this.openCountRequests.get(o);i&&(i.resolve(s),this.openCountRequests.delete(o));return}case"EOSE":{let o=this.openSubs.get(r[1]);if(!o)return;o.receivedEose();return}case"OK":{let o=r[1],s=r[2],i=r[3],a=this.openEventPublishes.get(o);a&&(clearTimeout(a.timeout),s?a.resolve(i):a.reject(new Error(i)),this.openEventPublishes.delete(o));return}case"CLOSED":{let o=r[1],s=this.openSubs.get(o);if(!s){let i=this.openCountRequests.get(o);i&&(i.reject(new Error(r[2])),this.openCountRequests.delete(o));return}s.closed=!0,s.close(r[2]);return}case"NOTICE":{this.onnotice(r[1]);return}case"AUTH":{this.challenge=r[1],this.onauth&&this.auth(this.onauth).catch(o=>{if(!(o instanceof Wr))throw o});return}default:{this.openSubs.get(r[1])?.oncustom?.(r);return}}}catch(r){try{let[o,s,i]=JSON.parse(t);console.warn(`[nostr] relay ${this.url} error processing message:`,r,i)}catch{console.warn(`[nostr] relay ${this.url} error processing message:`,r)}return}}},dd=class{constructor(e,t,n,r){u(this,"relay");u(this,"id");u(this,"lastEmitted");u(this,"closed",!1);u(this,"eosed",!1);u(this,"filters");u(this,"alreadyHaveEvent");u(this,"receivedEvent");u(this,"onevent");u(this,"oninvalidevent");u(this,"oneose");u(this,"onclose");u(this,"oncustom");u(this,"eoseTimeout");u(this,"eoseTimeoutHandle");if(n.length===0)throw new Error("subscription can't be created with zero filters");this.relay=e,this.filters=n,this.id=t,this.alreadyHaveEvent=r.alreadyHaveEvent,this.receivedEvent=r.receivedEvent,this.eoseTimeout=r.eoseTimeout||e.baseEoseTimeout,this.oneose=r.oneose,this.onclose=r.onclose,this.oninvalidevent=r.oninvalidevent,this.onevent=r.onevent||(o=>{console.warn(`onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,o)})}fire(){this.relay.send('["REQ","'+this.id+'",'+JSON.stringify(this.filters).substring(1)),this.eoseTimeoutHandle=setTimeout(this.receivedEose.bind(this),this.eoseTimeout)}receivedEose(){this.eosed||(clearTimeout(this.eoseTimeoutHandle),this.eosed=!0,this.oneose?.())}close(e="closed by caller"){if(!this.closed&&this.relay.connected){try{this.relay.send('["CLOSE",'+JSON.stringify(this.id)+"]")}catch(t){if(!(t instanceof Wr))throw t}this.closed=!0}this.relay.openSubs.delete(this.id),this.id.startsWith("<forced-ping>")||(this.relay.ongoingOperations--,this.relay.ongoingOperations===0&&(this.relay.idleSince=Date.now(),this.relay.scheduleIdleClose())),this.onclose?.(e)}},He=256,pd=He*2,zp=new TextEncoder;function yd(e,t){switch(t){case"reactions":return{"#e":[e],kinds:[7]};case"reposts":return{"#e":[e],kinds:[6]};case"quotes":return{"#q":[e],kinds:[1,1111]};case"replies":return{"#e":[e],kinds:[1]};case"comments":return{"#E":[e],kinds:[1111]};case"followers":return{"#p":[e],kinds:[3]}}}function gd(){return new Uint8Array(He)}function bd(e){if(e.length!==pd||!/^[0-9a-f]+$/.test(e))return;let t=new Uint8Array(He);for(let n=0;n<He;n++)t[n]=parseInt(e.slice(n*2,n*2+2),16);return t}function md(e){if(e.length!==He)throw new Error(`invalid number of registers ${e.length}`);let t="";for(let n=0;n<He;n++)t+=e[n].toString(16).padStart(2,"0");return t}function wd(e,t){if(e.length===0&&(e=gd()),e.length!==He)throw new Error(`invalid number of registers ${e.length}`);if(t.length!==He)throw new Error(`invalid number of registers ${t.length}`);for(let n=0;n<He;n++)t[n]>e[n]&&(e[n]=t[n]);return e}var xd=class{constructor(e){u(this,"relays",new Map);u(this,"seenOn",new Map);u(this,"trackRelays",!1);u(this,"verifyEvent");u(this,"enablePing");u(this,"enableReconnect");u(this,"idleTimeout",2e4);u(this,"automaticallyAuth");u(this,"onRelayConnectionFailure");u(this,"onRelayConnectionSuccess");u(this,"allowConnectingToRelay");u(this,"maxWaitForConnection");u(this,"_WebSocket");this.verifyEvent=e.verifyEvent,this._WebSocket=e.websocketImplementation,this.enablePing=e.enablePing,this.enableReconnect=e.enableReconnect||!1,e.idleTimeout&&(this.idleTimeout=e.idleTimeout),this.automaticallyAuth=e.automaticallyAuth,this.onRelayConnectionFailure=e.onRelayConnectionFailure,this.onRelayConnectionSuccess=e.onRelayConnectionSuccess,this.allowConnectingToRelay=e.allowConnectingToRelay,this.maxWaitForConnection=e.maxWaitForConnection||3e3}async ensureRelay(e,t){e=dt(e);let n=this.relays.get(e);if(n||(n=new Ei(e,{verifyEvent:this.verifyEvent,websocketImplementation:this._WebSocket,enablePing:this.enablePing,enableReconnect:this.enableReconnect,idleTimeout:this.idleTimeout}),n.onclose=()=>{this.relays.delete(e)},this.relays.set(e,n)),this.automaticallyAuth){let r=this.automaticallyAuth(e);r&&(n.onauth=r)}try{await n.connect({timeout:t?.connectionTimeout,abort:t?.abort})}catch(r){throw this.relays.delete(e),r}return n}close(e){e.map(dt).forEach(t=>{this.relays.get(t)?.close(),this.relays.delete(t)})}subscribe(e,t,n){let r=[],o=[];for(let s=0;s<e.length;s++){let i=dt(e[s]);r.find(a=>a.url===i)||o.indexOf(i)===-1&&(o.push(i),r.push({url:i,filter:t}))}return this.subscribeMap(r,n)}subscribeMany(e,t,n){return this.subscribe(e,t,n)}subscribeMap(e,t){let n=new Map;for(let d of e){let{url:p,filter:y}=d;n.has(p)||n.set(p,[]),n.get(p).push(y)}let r=Array.from(n.entries()).map(([d,p])=>({url:d,filters:p}));this.trackRelays&&(t.receivedEvent=(d,p)=>{let y=this.seenOn.get(p);y||(y=new Set,this.seenOn.set(p,y)),y.add(d)});let o=new Set,s=[],i=[],a=d=>{i[d]||(i[d]=!0,i.filter(p=>p).length===r.length&&(t.oneose?.(),a=()=>{}))},c=[],l=(d,p,y)=>{c[d]||(a(d),c[d]={url:p,reason:y},c.filter(m=>m).length===r.length&&(t.onclose?.(c),l=()=>{}))},f=d=>{if(t.alreadyHaveEvent?.(d))return!0;let p=o.has(d);return o.add(d),p},h=Promise.all(r.map(async({url:d,filters:p},y)=>{if(this.allowConnectingToRelay?.(d,["read",p])===!1){l(y,d,"connection skipped by allowConnectingToRelay");return}let m;try{m=await this.ensureRelay(d,{connectionTimeout:this.maxWaitForConnection<(t.maxWait||0)?Math.max(t.maxWait*.8,t.maxWait-1e3):this.maxWaitForConnection,abort:t.abort})}catch(x){this.onRelayConnectionFailure?.(d),l(y,d,x?.message||String(x));return}this.onRelayConnectionSuccess?.(d);let w=m.subscribe(p,{...t,oneose:()=>a(y),onclose:x=>{x.startsWith("auth-required: ")&&t.onauth?m.auth(t.onauth).then(()=>{m.subscribe(p,{...t,oneose:()=>a(y),onclose:A=>{l(y,d,A)},alreadyHaveEvent:f,eoseTimeout:t.maxWait,abort:t.abort})}).catch(A=>{l(y,d,`auth was required and attempted, but failed with: ${A}`)}):l(y,d,x)},alreadyHaveEvent:f,eoseTimeout:t.maxWait,abort:t.abort});s.push(w)}));return{async close(d){await h,s.forEach(p=>{p.close(d)})}}}subscribeEose(e,t,n){let r;return r=this.subscribe(e,t,{...n,oneose(){let o="closed automatically on eose";r?r.close(o):n.onclose?.(e.map(s=>({url:s,reason:o})))}}),r}subscribeManyEose(e,t,n){return this.subscribeEose(e,t,n)}async querySync(e,t,n){return new Promise(async r=>{let o=[];this.subscribeEose(e,t,{...n,onevent(s){o.push(s)},onclose(s){r(o)}})})}async get(e,t,n){t.limit=1;let r=await this.querySync(e,t,n);return r.sort((o,s)=>s.created_at-o.created_at),r[0]||null}async countMany(e,t,n,r){let o=yd(t,n),s=[];for(let l=0;l<e.length;l++){let f=dt(e[l]);s.indexOf(f)===-1&&s.push(f)}let i=await Promise.all(s.map(async l=>{if(this.allowConnectingToRelay?.(l,["read",[o]])===!1)return null;let f;try{f=await this.ensureRelay(l,{connectionTimeout:this.maxWaitForConnection<(r?.maxWait||0)?Math.max(r.maxWait*.8,r.maxWait-1e3):this.maxWaitForConnection,abort:r?.abort})}catch{return this.onRelayConnectionFailure?.(l),null}return this.onRelayConnectionSuccess?.(l),f.countWithHLL([o],{id:r?.id}).catch(()=>null)})),a=0,c;for(let l of i){if(!l||(l.count>a&&(a=l.count),!l.hll||l.hll.length!==512))continue;let f=bd(l.hll);f&&(c=wd(c||new Uint8Array(0),f))}return c?{count:a,hll:md(c)}:{count:a}}publish(e,t,n){return e.map(dt).map(async(r,o,s)=>{if(s.indexOf(r)!==o)return Promise.reject("duplicate url");if(this.allowConnectingToRelay?.(r,["write",t])===!1)return Promise.reject("connection skipped by allowConnectingToRelay");let i;try{i=await this.ensureRelay(r,{connectionTimeout:this.maxWaitForConnection<(n?.maxWait||0)?Math.max(n.maxWait*.8,n.maxWait-1e3):this.maxWaitForConnection,abort:n?.abort})}catch(a){return this.onRelayConnectionFailure?.(r),Promise.reject("connection failure: "+String(a))}return i.publish(t).catch(async a=>{if(a instanceof Error&&a.message.startsWith("auth-required: ")&&n?.onauth)return await i.auth(n.onauth),i.publish(t);throw a}).then(a=>{if(this.trackRelays){let c=this.seenOn.get(t.id);c||(c=new Set,this.seenOn.set(t.id,c)),c.add(i)}return a})})}listConnectionStatus(){let e=new Map;return this.relays.forEach((t,n)=>e.set(n,t.connected)),e}destroy(){this.relays.forEach(e=>e.close()),this.relays=new Map}pruneIdleRelays(e=1e4){let t=[];for(let[n,r]of this.relays)r.idleSince&&Date.now()-r.idleSince>=e&&(this.relays.delete(n),t.push(n),r.close());return t}},Si;try{Si=WebSocket}catch{}var vd=class extends xd{constructor(e){super({verifyEvent:mi,websocketImplementation:Si,maxWaitForConnection:3e3,...e})}},Ai;try{Ai=fetch}catch{}var Ed=/^bunker:\/\/([0-9a-f]{64})\??([?\/\w:.=&%-]*)$/;async function Ti(e){let t=e.match(Ed);if(t)try{let n=t[1],r=new URLSearchParams(t[2]);return{pubkey:n,relays:r.getAll("relay"),secret:r.get("secret")}}catch{}return Sd(e)}async function Sd(e){let t=e.match(sd);if(!t)return null;let[n,r="_",o]=t;try{let s=`https://${o}/.well-known/nostr.json?name=${r}`,i=await(await Ai(s,{redirect:"error"})).json(),a=i.names[r],c=i.nip46[a]||[];return{pubkey:a,relays:c,secret:null}}catch{return null}}function Bi(e){let t=new URLSearchParams;return e.relays.forEach(n=>{t.append("relay",n)}),t.append("secret",e.secret),e.perms&&e.perms.length>0&&t.append("perms",e.perms.join(",")),e.name&&t.append("name",e.name),e.url&&t.append("url",e.url),e.image&&t.append("image",e.image),`nostrconnect://${e.clientPubkey}?${t.toString()}`}var dn=class{constructor(e,t){u(this,"params");u(this,"pool");u(this,"subCloser");u(this,"isOpen");u(this,"serial");u(this,"idPrefix");u(this,"listeners");u(this,"waitingForAuth");u(this,"secretKey");u(this,"conversationKey");u(this,"bp");u(this,"cachedPubKey");this.params=t,this.pool=t.pool||new vd,this.secretKey=e,this.isOpen=!1,this.idPrefix=Math.random().toString(36).substring(7),this.serial=0,this.listeners={},this.waitingForAuth={}}static fromBunker(e,t,n={}){if(t.relays.length===0)throw new Error("no relays specified for this bunker");let r=new dn(e,n);return r.conversationKey=Dr(e,t.pubkey),r.bp=t,r.setupSubscription(),r}static async fromURI(e,t,n={},r=3e5){let o=new URL(t),s=o.searchParams.get("secret");if(!s)throw new Error("nostrconnect:// URI has no secret");let i=new dn(e,n),a=gi(e);return new Promise((c,l)=>{let f=!1,h=i.pool.subscribe(o.searchParams.getAll("relay"),{kinds:[$r],"#p":[a],limit:0},{onevent:async d=>{try{let p=Dr(e,d.pubkey),y=bi(d.content,p);JSON.parse(y).result===s&&(h.close(),i.bp={pubkey:d.pubkey,relays:o.searchParams.getAll("relay"),secret:s},i.conversationKey=Dr(e,d.pubkey),i.setupSubscription(),f=!0,n.skipSwitchRelays||await Promise.race([new Promise(w=>setTimeout(w,1e3)),i.switchRelays()]),c(i))}catch(p){console.warn("failed to process potential connection event",p)}},onclose:()=>{f||l(new Error("subscription closed before connection was established."))},maxWait:typeof r=="number"?r:void 0,abort:typeof r!="number"?r:void 0})})}setupSubscription(){let e=this.listeners,t=this.waitingForAuth,n=this.conversationKey;this.subCloser=this.pool.subscribe(this.bp.relays,{kinds:[$r],authors:[this.bp.pubkey],"#p":[gi(this.secretKey)],limit:0},{onevent:async r=>{let o=JSON.parse(bi(r.content,n)),{id:s,result:i,error:a}=o;if(i==="auth_url"&&t[s]){delete t[s],this.params.onauth?this.params.onauth(a):console.warn(`nostr-tools/nip46: remote signer ${this.bp.pubkey} tried to send an "auth_url"='${a}' but there was no onauth() callback configured.`);return}let c=e[s];c&&(a?c.reject(a):i&&c.resolve(i),delete e[s])},onclose:()=>{this.subCloser=void 0}}),this.isOpen=!0}async switchRelays(){try{let e=await this.sendRequest("switch_relays",[]),t=JSON.parse(e);if(!t||JSON.stringify(t.sort())===JSON.stringify(this.bp.relays))return!1;this.bp.relays=t;let n=this.subCloser;return setTimeout(()=>{n.close()},5e3),this.subCloser=void 0,this.setupSubscription(),!0}catch{return!1}}async close(){this.isOpen=!1,this.subCloser?.close(),this.subCloser=void 0}async sendRequest(e,t){return new Promise(async(n,r)=>{try{if(!this.isOpen)throw new Error("this signer is not open anymore, create a new one");this.subCloser||this.setupSubscription(),this.serial++;let o=`${this.idPrefix}-${this.serial}`,s=od(JSON.stringify({id:o,method:e,params:t}),this.conversationKey),i=Yh({kind:$r,tags:[["p",this.bp.pubkey]],content:s,created_at:Math.floor(Date.now()/1e3)},this.secretKey);this.listeners[o]={resolve:n,reject:r},this.waitingForAuth[o]=!0,await Promise.any(this.pool.publish(this.bp.relays,i))}catch(o){r(o)}})}async ping(){let e=await this.sendRequest("ping",[]);if(e!=="pong")throw new Error(`result is not pong: ${e}`)}async connect(e){let t=[this.bp.pubkey,this.bp.secret||""];e&&(t.push(""),t.push(JSON.stringify(e))),await this.sendRequest("connect",t)}async logout(){let e=await this.sendRequest("logout",[]);if(e!=="ack")throw new Error(`result is not ack: ${e}`);await this.close()}async getPublicKey(){return this.cachedPubKey||(this.cachedPubKey=await this.sendRequest("get_public_key",[])),this.cachedPubKey}async signEvent(e){let t=await this.sendRequest("sign_event",[JSON.stringify(e)]),n=JSON.parse(t);if(mi(n))return n;throw new Error(`event returned from bunker is improperly signed: ${JSON.stringify(n)}`)}async nip04Encrypt(e,t){return await this.sendRequest("nip04_encrypt",[e,t])}async nip04Decrypt(e,t){return await this.sendRequest("nip04_decrypt",[e,t])}async nip44Encrypt(e,t){return await this.sendRequest("nip44_encrypt",[e,t])}async nip44Decrypt(e,t){return await this.sendRequest("nip44_decrypt",[e,t])}};globalThis.NostrSigner={generateSecretKey:yr,getPublicKey:Tt,finalizeEvent:ge,verifyEvent:tt,SimplePool:Ns,BunkerSigner:dn,parseBunkerInput:Ti,createNostrConnectURI:Bi,npubEncode:Er.npubEncode,bytesToHex:e=>Array.from(e,t=>t.toString(16).padStart(2,"0")).join(""),hexToBytes:e=>Uint8Array.from(e.match(/.{1,2}/g)??[],t=>parseInt(t,16))};})();
1538+(()=>{var _i=Object.defineProperty;var ki=(e,t,n)=>t in e?_i(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var u=(e,t,n)=>ki(e,typeof t!="symbol"?t+"":t,n);function yt(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function xe(e,t=""){if(!Number.isSafeInteger(e)||e<0){let n=t&&`"${t}" `;throw new Error(`${n}expected integer >= 0, got ${e}`)}}function N(e,t,n=""){let r=yt(e),o=e?.length,s=t!==void 0;if(!r||s&&o!==t){let i=n&&`"${n}" `,a=s?` of length ${t}`:"",c=r?`length=${o}`:`type=${typeof e}`;throw new Error(i+"expected Uint8Array"+a+", got "+c)}return e}function Rt(e){if(typeof e!="function"||typeof e.create!="function")throw new Error("Hash must wrapped by utils.createHasher");xe(e.outputLen),xe(e.blockLen)}function nt(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")}function Xr(e,t){N(e,void 0,"digestInto() output");let n=t.outputLen;if(e.length<n)throw new Error('"digestInto() output" expected to be of length >='+n)}function $e(...e){for(let t=0;t<e.length;t++)e[t].fill(0)}function _t(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}function be(e,t){return e<<32-t|e>>>t}var Yr=typeof Uint8Array.from([]).toHex=="function"&&typeof Uint8Array.fromHex=="function",Li=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));function We(e){if(N(e),Yr)return e.toHex();let t="";for(let n=0;n<e.length;n++)t+=Li[e[n]];return t}var Se={_0:48,_9:57,A:65,F:70,a:97,f:102};function Jr(e){if(e>=Se._0&&e<=Se._9)return e-Se._0;if(e>=Se.A&&e<=Se.F)return e-(Se.A-10);if(e>=Se.a&&e<=Se.f)return e-(Se.a-10)}function Ve(e){if(typeof e!="string")throw new Error("hex string expected, got "+typeof e);if(Yr)return Uint8Array.fromHex(e);let t=e.length,n=t/2;if(t%2)throw new Error("hex string expected, got unpadded hex of length "+t);let r=new Uint8Array(n);for(let o=0,s=0;o<n;o++,s+=2){let i=Jr(e.charCodeAt(s)),a=Jr(e.charCodeAt(s+1));if(i===void 0||a===void 0){let c=e[s]+e[s+1];throw new Error('hex string expected, got non-hex character "'+c+'" at index '+s)}r[o]=i*16+a}return r}function ce(...e){let t=0;for(let r=0;r<e.length;r++){let o=e[r];N(o),t+=o.length}let n=new Uint8Array(t);for(let r=0,o=0;r<e.length;r++){let s=e[r];n.set(s,o),o+=s.length}return n}function Qr(e,t={}){let n=(o,s)=>e(s).update(o).digest(),r=e(void 0);return n.outputLen=r.outputLen,n.blockLen=r.blockLen,n.create=o=>e(o),Object.assign(n,t),Object.freeze(n)}function Ge(e=32){let t=typeof globalThis=="object"?globalThis.crypto:null;if(typeof t?.getRandomValues!="function")throw new Error("crypto.getRandomValues must be defined");return t.getRandomValues(new Uint8Array(e))}var eo=e=>({oid:Uint8Array.from([6,9,96,134,72,1,101,3,4,2,e])});function to(e,t,n){return e&t^~e&n}function no(e,t,n){return e&t^e&n^t&n}var kt=class{constructor(t,n,r,o){u(this,"blockLen");u(this,"outputLen");u(this,"padOffset");u(this,"isLE");u(this,"buffer");u(this,"view");u(this,"finished",!1);u(this,"length",0);u(this,"pos",0);u(this,"destroyed",!1);this.blockLen=t,this.outputLen=n,this.padOffset=r,this.isLE=o,this.buffer=new Uint8Array(t),this.view=_t(this.buffer)}update(t){nt(this),N(t);let{view:n,buffer:r,blockLen:o}=this,s=t.length;for(let i=0;i<s;){let a=Math.min(o-this.pos,s-i);if(a===o){let c=_t(t);for(;o<=s-i;i+=o)this.process(c,i);continue}r.set(t.subarray(i,i+a),this.pos),this.pos+=a,i+=a,this.pos===o&&(this.process(n,0),this.pos=0)}return this.length+=t.length,this.roundClean(),this}digestInto(t){nt(this),Xr(t,this),this.finished=!0;let{buffer:n,view:r,blockLen:o,isLE:s}=this,{pos:i}=this;n[i++]=128,$e(this.buffer.subarray(i)),this.padOffset>o-i&&(this.process(r,0),i=0);for(let h=i;h<o;h++)n[h]=0;r.setBigUint64(o-8,BigInt(this.length*8),s),this.process(r,0);let a=_t(t),c=this.outputLen;if(c%4)throw new Error("_sha2: outputLen must be aligned to 32bit");let l=c/4,f=this.get();if(l>f.length)throw new Error("_sha2: outputLen bigger than state");for(let h=0;h<l;h++)a.setUint32(4*h,f[h],s)}digest(){let{buffer:t,outputLen:n}=this;this.digestInto(t);let r=t.slice(0,n);return this.destroy(),r}_cloneInto(t){t||(t=new this.constructor),t.set(...this.get());let{blockLen:n,buffer:r,length:o,finished:s,destroyed:i,pos:a}=this;return t.destroyed=i,t.finished=s,t.length=o,t.pos=a,o%n&&t.buffer.set(r),t}clone(){return this._cloneInto()}},Ae=Uint32Array.from([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]);var Ci=Uint32Array.from([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),Oe=new Uint32Array(64),gn=class extends kt{constructor(t){super(64,t,8,!1)}get(){let{A:t,B:n,C:r,D:o,E:s,F:i,G:a,H:c}=this;return[t,n,r,o,s,i,a,c]}set(t,n,r,o,s,i,a,c){this.A=t|0,this.B=n|0,this.C=r|0,this.D=o|0,this.E=s|0,this.F=i|0,this.G=a|0,this.H=c|0}process(t,n){for(let h=0;h<16;h++,n+=4)Oe[h]=t.getUint32(n,!1);for(let h=16;h<64;h++){let d=Oe[h-15],p=Oe[h-2],y=be(d,7)^be(d,18)^d>>>3,m=be(p,17)^be(p,19)^p>>>10;Oe[h]=m+Oe[h-7]+y+Oe[h-16]|0}let{A:r,B:o,C:s,D:i,E:a,F:c,G:l,H:f}=this;for(let h=0;h<64;h++){let d=be(a,6)^be(a,11)^be(a,25),p=f+d+to(a,c,l)+Ci[h]+Oe[h]|0,m=(be(r,2)^be(r,13)^be(r,22))+no(r,o,s)|0;f=l,l=c,c=a,a=i+p|0,i=s,s=o,o=r,r=p+m|0}r=r+this.A|0,o=o+this.B|0,s=s+this.C|0,i=i+this.D|0,a=a+this.E|0,c=c+this.F|0,l=l+this.G|0,f=f+this.H|0,this.set(r,o,s,i,a,c,l,f)}roundClean(){$e(Oe)}destroy(){this.set(0,0,0,0,0,0,0,0),$e(this.buffer)}},bn=class extends gn{constructor(){super(32);u(this,"A",Ae[0]|0);u(this,"B",Ae[1]|0);u(this,"C",Ae[2]|0);u(this,"D",Ae[3]|0);u(this,"E",Ae[4]|0);u(this,"F",Ae[5]|0);u(this,"G",Ae[6]|0);u(this,"H",Ae[7]|0)}};var Lt=Qr(()=>new bn,eo(1));var wn=BigInt(0),mn=BigInt(1);function gt(e,t=""){if(typeof e!="boolean"){let n=t&&`"${t}" `;throw new Error(n+"expected boolean, got type="+typeof e)}return e}function ro(e){if(typeof e=="bigint"){if(!Ct(e))throw new Error("positive bigint expected, got "+e)}else xe(e);return e}function bt(e){let t=ro(e).toString(16);return t.length&1?"0"+t:t}function oo(e){if(typeof e!="string")throw new Error("hex string expected, got "+typeof e);return e===""?wn:BigInt("0x"+e)}function Ue(e){return oo(We(e))}function xn(e){return oo(We(Ii(N(e)).reverse()))}function It(e,t){xe(t),e=ro(e);let n=Ve(e.toString(16).padStart(t*2,"0"));if(n.length!==t)throw new Error("number too large");return n}function vn(e,t){return It(e,t).reverse()}function Ii(e){return Uint8Array.from(e)}function so(e){return Uint8Array.from(e,(t,n)=>{let r=t.charCodeAt(0);if(t.length!==1||r>127)throw new Error(`string contains non-ASCII character "${e[n]}" with code ${r} at position ${n}`);return r})}var Ct=e=>typeof e=="bigint"&&wn<=e;function Hi(e,t,n){return Ct(e)&&Ct(t)&&Ct(n)&&t<=e&&e<n}function io(e,t,n,r){if(!Hi(t,n,r))throw new Error("expected valid "+e+": "+n+" <= n < "+r+", got "+t)}function En(e){let t;for(t=0;e>wn;e>>=mn,t+=1);return t}var mt=e=>(mn<<BigInt(e))-mn;function ao(e,t,n){if(xe(e,"hashLen"),xe(t,"qByteLen"),typeof n!="function")throw new Error("hmacFn must be a function");let r=w=>new Uint8Array(w),o=Uint8Array.of(),s=Uint8Array.of(0),i=Uint8Array.of(1),a=1e3,c=r(e),l=r(e),f=0,h=()=>{c.fill(1),l.fill(0),f=0},d=(...w)=>n(l,ce(c,...w)),p=(w=o)=>{l=d(s,w),c=d(),w.length!==0&&(l=d(i,w),c=d())},y=()=>{if(f++>=a)throw new Error("drbg: tried max amount of iterations");let w=0,x=[];for(;w<t;){c=d();let A=c.slice();x.push(A),w+=c.length}return ce(...x)};return(w,x)=>{h(),p(w);let A;for(;!(A=x(y()));)p();return h(),A}}function wt(e,t={},n={}){if(!e||typeof e!="object")throw new Error("expected valid options object");function r(s,i,a){let c=e[s];if(a&&c===void 0)return;let l=typeof c;if(l!==i||c===null)throw new Error(`param "${s}" is invalid: expected ${i}, got ${l}`)}let o=(s,i)=>Object.entries(s).forEach(([a,c])=>r(a,c,i));o(t,!1),o(n,!0)}function Sn(e){let t=new WeakMap;return(n,...r)=>{let o=t.get(n);if(o!==void 0)return o;let s=e(n,...r);return t.set(n,s),s}}var ae=BigInt(0),se=BigInt(1),Ke=BigInt(2),uo=BigInt(3),fo=BigInt(4),ho=BigInt(5),Oi=BigInt(7),po=BigInt(8),Ui=BigInt(9),yo=BigInt(16);function me(e,t){let n=e%t;return n>=ae?n:t+n}function fe(e,t,n){let r=e;for(;t-- >ae;)r*=r,r%=n;return r}function co(e,t){if(e===ae)throw new Error("invert: expected non-zero number");if(t<=ae)throw new Error("invert: expected positive modulus, got "+t);let n=me(e,t),r=t,o=ae,s=se,i=se,a=ae;for(;n!==ae;){let l=r/n,f=r%n,h=o-i*l,d=s-a*l;r=n,n=f,o=i,s=a,i=h,a=d}if(r!==se)throw new Error("invert: does not exist");return me(o,t)}function Tn(e,t,n){if(!e.eql(e.sqr(t),n))throw new Error("Cannot find square root")}function go(e,t){let n=(e.ORDER+se)/fo,r=e.pow(t,n);return Tn(e,r,t),r}function Pi(e,t){let n=(e.ORDER-ho)/po,r=e.mul(t,Ke),o=e.pow(r,n),s=e.mul(t,o),i=e.mul(e.mul(s,Ke),o),a=e.mul(s,e.sub(i,e.ONE));return Tn(e,a,t),a}function Ni(e){let t=rt(e),n=bo(e),r=n(t,t.neg(t.ONE)),o=n(t,r),s=n(t,t.neg(r)),i=(e+Oi)/yo;return(a,c)=>{let l=a.pow(c,i),f=a.mul(l,r),h=a.mul(l,o),d=a.mul(l,s),p=a.eql(a.sqr(f),c),y=a.eql(a.sqr(h),c);l=a.cmov(l,f,p),f=a.cmov(d,h,y);let m=a.eql(a.sqr(f),c),w=a.cmov(l,f,m);return Tn(a,w,c),w}}function bo(e){if(e<uo)throw new Error("sqrt is not defined for small field");let t=e-se,n=0;for(;t%Ke===ae;)t/=Ke,n++;let r=Ke,o=rt(e);for(;lo(o,r)===1;)if(r++>1e3)throw new Error("Cannot find square root: probably non-prime P");if(n===1)return go;let s=o.pow(r,t),i=(t+se)/Ke;return function(c,l){if(c.is0(l))return l;if(lo(c,l)!==1)throw new Error("Cannot find square root");let f=n,h=c.mul(c.ONE,s),d=c.pow(l,t),p=c.pow(l,i);for(;!c.eql(d,c.ONE);){if(c.is0(d))return c.ZERO;let y=1,m=c.sqr(d);for(;!c.eql(m,c.ONE);)if(y++,m=c.sqr(m),y===f)throw new Error("Cannot find square root");let w=se<<BigInt(f-y-1),x=c.pow(h,w);f=y,h=c.sqr(x),d=c.mul(d,h),p=c.mul(p,x)}return p}}function Mi(e){return e%fo===uo?go:e%po===ho?Pi:e%yo===Ui?Ni(e):bo(e)}var qi=["create","isValid","is0","neg","inv","sqrt","sqr","eql","add","sub","mul","pow","div","addN","subN","mulN","sqrN"];function Bn(e){let t={ORDER:"bigint",BYTES:"number",BITS:"number"},n=qi.reduce((r,o)=>(r[o]="function",r),t);return wt(e,n),e}function Di(e,t,n){if(n<ae)throw new Error("invalid exponent, negatives unsupported");if(n===ae)return e.ONE;if(n===se)return t;let r=e.ONE,o=t;for(;n>ae;)n&se&&(r=e.mul(r,o)),o=e.sqr(o),n>>=se;return r}function Ht(e,t,n=!1){let r=new Array(t.length).fill(n?e.ZERO:void 0),o=t.reduce((i,a,c)=>e.is0(a)?i:(r[c]=i,e.mul(i,a)),e.ONE),s=e.inv(o);return t.reduceRight((i,a,c)=>e.is0(a)?i:(r[c]=e.mul(i,r[c]),e.mul(i,a)),s),r}function lo(e,t){let n=(e.ORDER-se)/Ke,r=e.pow(t,n),o=e.eql(r,e.ONE),s=e.eql(r,e.ZERO),i=e.eql(r,e.neg(e.ONE));if(!o&&!s&&!i)throw new Error("invalid Legendre symbol result");return o?1:s?0:-1}function $i(e,t){t!==void 0&&xe(t);let n=t!==void 0?t:e.toString(2).length,r=Math.ceil(n/8);return{nBitLength:n,nByteLength:r}}var An=class{constructor(t,n={}){u(this,"ORDER");u(this,"BITS");u(this,"BYTES");u(this,"isLE");u(this,"ZERO",ae);u(this,"ONE",se);u(this,"_lengths");u(this,"_sqrt");u(this,"_mod");if(t<=ae)throw new Error("invalid field: expected ORDER > 0, got "+t);let r;this.isLE=!1,n!=null&&typeof n=="object"&&(typeof n.BITS=="number"&&(r=n.BITS),typeof n.sqrt=="function"&&(this.sqrt=n.sqrt),typeof n.isLE=="boolean"&&(this.isLE=n.isLE),n.allowedLengths&&(this._lengths=n.allowedLengths?.slice()),typeof n.modFromBytes=="boolean"&&(this._mod=n.modFromBytes));let{nBitLength:o,nByteLength:s}=$i(t,r);if(s>2048)throw new Error("invalid field: expected ORDER of <= 2048 bytes");this.ORDER=t,this.BITS=o,this.BYTES=s,this._sqrt=void 0,Object.preventExtensions(this)}create(t){return me(t,this.ORDER)}isValid(t){if(typeof t!="bigint")throw new Error("invalid field element: expected bigint, got "+typeof t);return ae<=t&&t<this.ORDER}is0(t){return t===ae}isValidNot0(t){return!this.is0(t)&&this.isValid(t)}isOdd(t){return(t&se)===se}neg(t){return me(-t,this.ORDER)}eql(t,n){return t===n}sqr(t){return me(t*t,this.ORDER)}add(t,n){return me(t+n,this.ORDER)}sub(t,n){return me(t-n,this.ORDER)}mul(t,n){return me(t*n,this.ORDER)}pow(t,n){return Di(this,t,n)}div(t,n){return me(t*co(n,this.ORDER),this.ORDER)}sqrN(t){return t*t}addN(t,n){return t+n}subN(t,n){return t-n}mulN(t,n){return t*n}inv(t){return co(t,this.ORDER)}sqrt(t){return this._sqrt||(this._sqrt=Mi(this.ORDER)),this._sqrt(this,t)}toBytes(t){return this.isLE?vn(t,this.BYTES):It(t,this.BYTES)}fromBytes(t,n=!1){N(t);let{_lengths:r,BYTES:o,isLE:s,ORDER:i,_mod:a}=this;if(r){if(!r.includes(t.length)||t.length>o)throw new Error("Field.fromBytes: expected "+r+" bytes, got "+t.length);let l=new Uint8Array(o);l.set(t,s?0:l.length-t.length),t=l}if(t.length!==o)throw new Error("Field.fromBytes: expected "+o+" bytes, got "+t.length);let c=s?xn(t):Ue(t);if(a&&(c=me(c,i)),!n&&!this.isValid(c))throw new Error("invalid field element: outside of range 0..ORDER");return c}invertBatch(t){return Ht(this,t)}cmov(t,n,r){return r?n:t}};function rt(e,t={}){return new An(e,t)}function mo(e){if(typeof e!="bigint")throw new Error("field order must be bigint");let t=e.toString(2).length;return Math.ceil(t/8)}function Rn(e){let t=mo(e);return t+Math.ceil(t/2)}function Ot(e,t,n=!1){N(e);let r=e.length,o=mo(t),s=Rn(t);if(r<16||r<s||r>1024)throw new Error("expected "+s+"-1024 bytes of input, got "+r);let i=n?xn(e):Ue(e),a=me(i,t-se)+se;return n?vn(a,o):It(a,o)}var ot=BigInt(0),Fe=BigInt(1);function xt(e,t){let n=t.negate();return e?n:t}function Cn(e,t){let n=Ht(e.Fp,t.map(r=>r.Z));return t.map((r,o)=>e.fromAffine(r.toAffine(n[o])))}function Eo(e,t){if(!Number.isSafeInteger(e)||e<=0||e>t)throw new Error("invalid window size, expected [1.."+t+"], got W="+e)}function _n(e,t){Eo(e,t);let n=Math.ceil(t/e)+1,r=2**(e-1),o=2**e,s=mt(e),i=BigInt(e);return{windows:n,windowSize:r,mask:s,maxNumber:o,shiftBy:i}}function wo(e,t,n){let{windowSize:r,mask:o,maxNumber:s,shiftBy:i}=n,a=Number(e&o),c=e>>i;a>r&&(a-=s,c+=Fe);let l=t*r,f=l+Math.abs(a)-1,h=a===0,d=a<0,p=t%2!==0;return{nextN:c,offset:f,isZero:h,isNeg:d,isNegF:p,offsetF:l}}var kn=new WeakMap,So=new WeakMap;function Ln(e){return So.get(e)||1}function xo(e){if(e!==ot)throw new Error("invalid wNAF")}var Ut=class{constructor(t,n){u(this,"BASE");u(this,"ZERO");u(this,"Fn");u(this,"bits");this.BASE=t.BASE,this.ZERO=t.ZERO,this.Fn=t.Fn,this.bits=n}_unsafeLadder(t,n,r=this.ZERO){let o=t;for(;n>ot;)n&Fe&&(r=r.add(o)),o=o.double(),n>>=Fe;return r}precomputeWindow(t,n){let{windows:r,windowSize:o}=_n(n,this.bits),s=[],i=t,a=i;for(let c=0;c<r;c++){a=i,s.push(a);for(let l=1;l<o;l++)a=a.add(i),s.push(a);i=a.double()}return s}wNAF(t,n,r){if(!this.Fn.isValid(r))throw new Error("invalid scalar");let o=this.ZERO,s=this.BASE,i=_n(t,this.bits);for(let a=0;a<i.windows;a++){let{nextN:c,offset:l,isZero:f,isNeg:h,isNegF:d,offsetF:p}=wo(r,a,i);r=c,f?s=s.add(xt(d,n[p])):o=o.add(xt(h,n[l]))}return xo(r),{p:o,f:s}}wNAFUnsafe(t,n,r,o=this.ZERO){let s=_n(t,this.bits);for(let i=0;i<s.windows&&r!==ot;i++){let{nextN:a,offset:c,isZero:l,isNeg:f}=wo(r,i,s);if(r=a,!l){let h=n[c];o=o.add(f?h.negate():h)}}return xo(r),o}getPrecomputes(t,n,r){let o=kn.get(n);return o||(o=this.precomputeWindow(n,t),t!==1&&(typeof r=="function"&&(o=r(o)),kn.set(n,o))),o}cached(t,n,r){let o=Ln(t);return this.wNAF(o,this.getPrecomputes(o,t,r),n)}unsafe(t,n,r,o){let s=Ln(t);return s===1?this._unsafeLadder(t,n,o):this.wNAFUnsafe(s,this.getPrecomputes(s,t,r),n,o)}createCache(t,n){Eo(n,this.bits),So.set(t,n),kn.delete(t)}hasCache(t){return Ln(t)!==1}};function Ao(e,t,n,r){let o=t,s=e.ZERO,i=e.ZERO;for(;n>ot||r>ot;)n&Fe&&(s=s.add(o)),r&Fe&&(i=i.add(o)),o=o.double(),n>>=Fe,r>>=Fe;return{p1:s,p2:i}}function vo(e,t,n){if(t){if(t.ORDER!==e)throw new Error("Field.ORDER must match order: Fp == p, Fn == n");return Bn(t),t}else return rt(e,{isLE:n})}function To(e,t,n={},r){if(r===void 0&&(r=e==="edwards"),!t||typeof t!="object")throw new Error(`expected valid ${e} CURVE object`);for(let c of["p","n","h"]){let l=t[c];if(!(typeof l=="bigint"&&l>ot))throw new Error(`CURVE.${c} must be positive bigint`)}let o=vo(t.p,n.Fp,r),s=vo(t.n,n.Fn,r),a=["Gx","Gy","a",e==="weierstrass"?"b":"d"];for(let c of a)if(!o.isValid(t[c]))throw new Error(`CURVE.${c} must be valid field element of CURVE.Fp`);return t=Object.freeze(Object.assign({},t)),{CURVE:t,Fp:o,Fn:s}}function Pt(e,t){return function(r){let o=e(r);return{secretKey:o,publicKey:t(o)}}}var Nt=class{constructor(t,n){u(this,"oHash");u(this,"iHash");u(this,"blockLen");u(this,"outputLen");u(this,"finished",!1);u(this,"destroyed",!1);if(Rt(t),N(n,void 0,"key"),this.iHash=t.create(),typeof this.iHash.update!="function")throw new Error("Expected instance of class which extends utils.Hash");this.blockLen=this.iHash.blockLen,this.outputLen=this.iHash.outputLen;let r=this.blockLen,o=new Uint8Array(r);o.set(n.length>r?t.create().update(n).digest():n);for(let s=0;s<o.length;s++)o[s]^=54;this.iHash.update(o),this.oHash=t.create();for(let s=0;s<o.length;s++)o[s]^=106;this.oHash.update(o),$e(o)}update(t){return nt(this),this.iHash.update(t),this}digestInto(t){nt(this),N(t,this.outputLen,"output"),this.finished=!0,this.iHash.digestInto(t),this.oHash.update(t),this.oHash.digestInto(t),this.destroy()}digest(){let t=new Uint8Array(this.oHash.outputLen);return this.digestInto(t),t}_cloneInto(t){t||(t=Object.create(Object.getPrototypeOf(this),{}));let{oHash:n,iHash:r,finished:o,destroyed:s,blockLen:i,outputLen:a}=this;return t=t,t.finished=o,t.destroyed=s,t.blockLen=i,t.outputLen=a,t.oHash=n._cloneInto(t.oHash),t.iHash=r._cloneInto(t.iHash),t}clone(){return this._cloneInto()}destroy(){this.destroyed=!0,this.oHash.destroy(),this.iHash.destroy()}},In=(e,t,n)=>new Nt(e,t).update(n).digest();In.create=(e,t)=>new Nt(e,t);var Bo=(e,t)=>(e+(e>=0?t:-t)/Ro)/t;function Wi(e,t,n){let[[r,o],[s,i]]=t,a=Bo(i*e,n),c=Bo(-o*e,n),l=e-a*r-c*s,f=-a*o-c*i,h=l<Te,d=f<Te;h&&(l=-l),d&&(f=-f);let p=mt(Math.ceil(En(n)/2))+st;if(l<Te||l>=p||f<Te||f>=p)throw new Error("splitScalar (endomorphism): failed, k="+e);return{k1neg:h,k1:l,k2neg:d,k2:f}}function On(e){if(!["compact","recovered","der"].includes(e))throw new Error('Signature format must be "compact", "recovered", or "der"');return e}function Hn(e,t){let n={};for(let r of Object.keys(t))n[r]=e[r]===void 0?t[r]:e[r];return gt(n.lowS,"lowS"),gt(n.prehash,"prehash"),n.format!==void 0&&On(n.format),n}var Un=class extends Error{constructor(t=""){super(t)}},Pe={Err:Un,_tlv:{encode:(e,t)=>{let{Err:n}=Pe;if(e<0||e>256)throw new n("tlv.encode: wrong tag");if(t.length&1)throw new n("tlv.encode: unpadded data");let r=t.length/2,o=bt(r);if(o.length/2&128)throw new n("tlv.encode: long form length too big");let s=r>127?bt(o.length/2|128):"";return bt(e)+s+o+t},decode(e,t){let{Err:n}=Pe,r=0;if(e<0||e>256)throw new n("tlv.encode: wrong tag");if(t.length<2||t[r++]!==e)throw new n("tlv.decode: wrong tlv");let o=t[r++],s=!!(o&128),i=0;if(!s)i=o;else{let c=o&127;if(!c)throw new n("tlv.decode(long): indefinite length not supported");if(c>4)throw new n("tlv.decode(long): byte length is too big");let l=t.subarray(r,r+c);if(l.length!==c)throw new n("tlv.decode: length bytes not complete");if(l[0]===0)throw new n("tlv.decode(long): zero leftmost byte");for(let f of l)i=i<<8|f;if(r+=c,i<128)throw new n("tlv.decode(long): not minimal encoding")}let a=t.subarray(r,r+i);if(a.length!==i)throw new n("tlv.decode: wrong value length");return{v:a,l:t.subarray(r+i)}}},_int:{encode(e){let{Err:t}=Pe;if(e<Te)throw new t("integer: negative integers are not allowed");let n=bt(e);if(Number.parseInt(n[0],16)&8&&(n="00"+n),n.length&1)throw new t("unexpected DER parsing assertion: unpadded hex");return n},decode(e){let{Err:t}=Pe;if(e[0]&128)throw new t("invalid signature integer: negative");if(e[0]===0&&!(e[1]&128))throw new t("invalid signature integer: unnecessary leading zero");return Ue(e)}},toSig(e){let{Err:t,_int:n,_tlv:r}=Pe,o=N(e,void 0,"signature"),{v:s,l:i}=r.decode(48,o);if(i.length)throw new t("invalid signature: left bytes after parsing");let{v:a,l:c}=r.decode(2,s),{v:l,l:f}=r.decode(2,c);if(f.length)throw new t("invalid signature: left bytes after parsing");return{r:n.decode(a),s:n.decode(l)}},hexFromSig(e){let{_tlv:t,_int:n}=Pe,r=t.encode(2,n.encode(e.r)),o=t.encode(2,n.encode(e.s)),s=r+o;return t.encode(48,s)}},Te=BigInt(0),st=BigInt(1),Ro=BigInt(2),Mt=BigInt(3),Vi=BigInt(4);function _o(e,t={}){let n=To("weierstrass",e,t),{Fp:r,Fn:o}=n,s=n.CURVE,{h:i,n:a}=s;wt(t,{},{allowInfinityPoint:"boolean",clearCofactor:"function",isTorsionFree:"function",fromBytes:"function",toBytes:"function",endo:"object"});let{endo:c}=t;if(c&&(!r.is0(s.a)||typeof c.beta!="bigint"||!Array.isArray(c.basises)))throw new Error('invalid endo: expected "beta": bigint and "basises": array');let l=Lo(r,o);function f(){if(!r.isOdd)throw new Error("compression is not supported: Field does not have .isOdd()")}function h(L,b,g){let{x:E,y:S}=b.toAffine(),B=r.toBytes(E);if(gt(g,"isCompressed"),g){f();let v=!r.isOdd(S);return ce(ko(v),B)}else return ce(Uint8Array.of(4),B,r.toBytes(S))}function d(L){N(L,void 0,"Point");let{publicKey:b,publicKeyUncompressed:g}=l,E=L.length,S=L[0],B=L.subarray(1);if(E===b&&(S===2||S===3)){let v=r.fromBytes(B);if(!r.isValid(v))throw new Error("bad point: is not on curve, wrong x");let R=m(v),T;try{T=r.sqrt(R)}catch(K){let q=K instanceof Error?": "+K.message:"";throw new Error("bad point: is not on curve, sqrt error"+q)}f();let _=r.isOdd(T);return(S&1)===1!==_&&(T=r.neg(T)),{x:v,y:T}}else if(E===g&&S===4){let v=r.BYTES,R=r.fromBytes(B.subarray(0,v)),T=r.fromBytes(B.subarray(v,v*2));if(!w(R,T))throw new Error("bad point: is not on curve");return{x:R,y:T}}else throw new Error(`bad point: got length ${E}, expected compressed=${b} or uncompressed=${g}`)}let p=t.toBytes||h,y=t.fromBytes||d;function m(L){let b=r.sqr(L),g=r.mul(b,L);return r.add(r.add(g,r.mul(L,s.a)),s.b)}function w(L,b){let g=r.sqr(b),E=m(L);return r.eql(g,E)}if(!w(s.Gx,s.Gy))throw new Error("bad curve params: generator point");let x=r.mul(r.pow(s.a,Mt),Vi),A=r.mul(r.sqr(s.b),BigInt(27));if(r.is0(r.add(x,A)))throw new Error("bad curve params: a or b");function I(L,b,g=!1){if(!r.isValid(b)||g&&r.is0(b))throw new Error(`bad point coordinate ${L}`);return b}function P(L){if(!(L instanceof U))throw new Error("Weierstrass Point expected")}function Q(L){if(!c||!c.basises)throw new Error("no endo");return Wi(L,c.basises,o.ORDER)}let V=Sn((L,b)=>{let{X:g,Y:E,Z:S}=L;if(r.eql(S,r.ONE))return{x:g,y:E};let B=L.is0();b==null&&(b=B?r.ONE:r.inv(S));let v=r.mul(g,b),R=r.mul(E,b),T=r.mul(S,b);if(B)return{x:r.ZERO,y:r.ZERO};if(!r.eql(T,r.ONE))throw new Error("invZ was invalid");return{x:v,y:R}}),Z=Sn(L=>{if(L.is0()){if(t.allowInfinityPoint&&!r.is0(L.Y))return;throw new Error("bad point: ZERO")}let{x:b,y:g}=L.toAffine();if(!r.isValid(b)||!r.isValid(g))throw new Error("bad point: x or y not field elements");if(!w(b,g))throw new Error("bad point: equation left != right");if(!L.isTorsionFree())throw new Error("bad point: not in prime-order subgroup");return!0});function j(L,b,g,E,S){return g=new U(r.mul(g.X,L),g.Y,g.Z),b=xt(E,b),g=xt(S,g),b.add(g)}let C=class C{constructor(b,g,E){u(this,"X");u(this,"Y");u(this,"Z");this.X=I("x",b),this.Y=I("y",g,!0),this.Z=I("z",E),Object.freeze(this)}static CURVE(){return s}static fromAffine(b){let{x:g,y:E}=b||{};if(!b||!r.isValid(g)||!r.isValid(E))throw new Error("invalid affine point");if(b instanceof C)throw new Error("projective point not allowed");return r.is0(g)&&r.is0(E)?C.ZERO:new C(g,E,r.ONE)}static fromBytes(b){let g=C.fromAffine(y(N(b,void 0,"point")));return g.assertValidity(),g}static fromHex(b){return C.fromBytes(Ve(b))}get x(){return this.toAffine().x}get y(){return this.toAffine().y}precompute(b=8,g=!0){return M.createCache(this,b),g||this.multiply(Mt),this}assertValidity(){Z(this)}hasEvenY(){let{y:b}=this.toAffine();if(!r.isOdd)throw new Error("Field doesn't support isOdd");return!r.isOdd(b)}equals(b){P(b);let{X:g,Y:E,Z:S}=this,{X:B,Y:v,Z:R}=b,T=r.eql(r.mul(g,R),r.mul(B,S)),_=r.eql(r.mul(E,R),r.mul(v,S));return T&&_}negate(){return new C(this.X,r.neg(this.Y),this.Z)}double(){let{a:b,b:g}=s,E=r.mul(g,Mt),{X:S,Y:B,Z:v}=this,R=r.ZERO,T=r.ZERO,_=r.ZERO,H=r.mul(S,S),K=r.mul(B,B),q=r.mul(v,v),O=r.mul(S,B);return O=r.add(O,O),_=r.mul(S,v),_=r.add(_,_),R=r.mul(b,_),T=r.mul(E,q),T=r.add(R,T),R=r.sub(K,T),T=r.add(K,T),T=r.mul(R,T),R=r.mul(O,R),_=r.mul(E,_),q=r.mul(b,q),O=r.sub(H,q),O=r.mul(b,O),O=r.add(O,_),_=r.add(H,H),H=r.add(_,H),H=r.add(H,q),H=r.mul(H,O),T=r.add(T,H),q=r.mul(B,v),q=r.add(q,q),H=r.mul(q,O),R=r.sub(R,H),_=r.mul(q,K),_=r.add(_,_),_=r.add(_,_),new C(R,T,_)}add(b){P(b);let{X:g,Y:E,Z:S}=this,{X:B,Y:v,Z:R}=b,T=r.ZERO,_=r.ZERO,H=r.ZERO,K=s.a,q=r.mul(s.b,Mt),O=r.mul(g,B),z=r.mul(E,v),J=r.mul(S,R),Y=r.add(g,E),X=r.add(B,v);Y=r.mul(Y,X),X=r.add(O,z),Y=r.sub(Y,X),X=r.add(g,S);let ie=r.add(B,R);return X=r.mul(X,ie),ie=r.add(O,J),X=r.sub(X,ie),ie=r.add(E,S),T=r.add(v,R),ie=r.mul(ie,T),T=r.add(z,J),ie=r.sub(ie,T),H=r.mul(K,X),T=r.mul(q,J),H=r.add(T,H),T=r.sub(z,H),H=r.add(z,H),_=r.mul(T,H),z=r.add(O,O),z=r.add(z,O),J=r.mul(K,J),X=r.mul(q,X),z=r.add(z,J),J=r.sub(O,J),J=r.mul(K,J),X=r.add(X,J),O=r.mul(z,X),_=r.add(_,O),O=r.mul(ie,X),T=r.mul(Y,T),T=r.sub(T,O),O=r.mul(Y,z),H=r.mul(ie,H),H=r.add(H,O),new C(T,_,H)}subtract(b){return this.add(b.negate())}is0(){return this.equals(C.ZERO)}multiply(b){let{endo:g}=t;if(!o.isValidNot0(b))throw new Error("invalid scalar: out of range");let E,S,B=v=>M.cached(this,v,R=>Cn(C,R));if(g){let{k1neg:v,k1:R,k2neg:T,k2:_}=Q(b),{p:H,f:K}=B(R),{p:q,f:O}=B(_);S=K.add(O),E=j(g.beta,H,q,v,T)}else{let{p:v,f:R}=B(b);E=v,S=R}return Cn(C,[E,S])[0]}multiplyUnsafe(b){let{endo:g}=t,E=this;if(!o.isValid(b))throw new Error("invalid scalar: out of range");if(b===Te||E.is0())return C.ZERO;if(b===st)return E;if(M.hasCache(this))return this.multiply(b);if(g){let{k1neg:S,k1:B,k2neg:v,k2:R}=Q(b),{p1:T,p2:_}=Ao(C,E,B,R);return j(g.beta,T,_,S,v)}else return M.unsafe(E,b)}toAffine(b){return V(this,b)}isTorsionFree(){let{isTorsionFree:b}=t;return i===st?!0:b?b(C,this):M.unsafe(this,a).is0()}clearCofactor(){let{clearCofactor:b}=t;return i===st?this:b?b(C,this):this.multiplyUnsafe(i)}isSmallOrder(){return this.multiplyUnsafe(i).is0()}toBytes(b=!
Diff preview truncated (256 KiB or 10,000 lines).

About

ownerc01503e8035f
visibilitypublic
head8b51870933f8

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs