clone

a self-hosted multitenant nostr relay with sites, file storage, git hosting, and inbox and outbox delivery

add encrypted uploads, folders and file messages to the Files page

Dami committed 8b51870
commit
8b51870933f832641be527f6d6d57c99f97f9c5f
parent
ac4fefc833a3a19b92c6644ebc1ed5b3f1c662c7
author
Dami <dami.etoile@gmail.com>
20 files changed, +2213 -10
Ainternal/webui/blossom-encryption.js73+++++
Ainternal/webui/blossom-manifests.js466++++++++++++++++++++++++++++++
Ainternal/webui/blossom-upload.js160++++++++++
Minternal/webui/bridge.js2+-
Minternal/webui/browse.html5+
Minternal/webui/components.js224++++++++++++++
Ainternal/webui/file-messages.js209+++++++++++++
Ainternal/webui/file-workspace.js291+++++++++++++++++++
Minternal/webui/page.html5+
Minternal/webui/signer.js2+-
Minternal/webui/style.css19+-
Minternal/webui/templates.go17+-
Mpackage.json3+-
Ascripts/blossom-encryption.test.mjs58++++
Ascripts/blossom-manifests-review.test.mjs92++++++
Ascripts/blossom-manifests.test.mjs70+++++
Ascripts/blossom-upload.test.mjs126++++++++
Ascripts/file-messages.test.mjs132++++++++
Ascripts/file-workspace.test.mjs260+++++++++++++++++
Mscripts/signer-entry.mjs9+
A internal/webui/blossom-encryption.js +73 -0
@@ -0,0 +1,73 @@
1+// BUD-15 draft (June 2026), BUD-15: Client-side CHK encrypted blobs.2+// https://raw.githubusercontent.com/mmalmi/blossom/codex/bud-15-chk-encryption/buds/15.md3+// Keys are client-only values. Callers must not include k in requests to a server.4+(() => {5+ "use strict";6+7+ const encoder = new TextEncoder();8+ const zeroNonce = new Uint8Array(12);9+ const salt = encoder.encode("hashtree-chk");10+ const info = encoder.encode("encryption-key");11+12+ const hex = bytes => Array.from(bytes, byte => byte.toString(16).padStart(2, "0")).join("");13+ const bytes = value => {14+ if (value instanceof Uint8Array) return value;15+ if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);16+ throw new TypeError("expected Uint8Array");17+ };18+ const fromHex = value => {19+ if (typeof value !== "string" || !/^[0-9a-f]{64}$/.test(value)) throw new Error("expected a 64-character lowercase hex key");20+ const result = new Uint8Array(32);21+ for (let index = 0; index < result.length; index++) result[index] = parseInt(value.slice(index * 2, index * 2 + 2), 16);22+ return result;23+ };24+ const equal = (left, right) => left.length === right.length && left.every((value, index) => value === right[index]);25+ const digest = async value => new Uint8Array(await crypto.subtle.digest("SHA-256", bytes(value)));26+ const aesKey = async key => {27+ const material = await crypto.subtle.importKey("raw", key, "HKDF", false, ["deriveKey"]);28+ return crypto.subtle.deriveKey({name: "HKDF", hash: "SHA-256", salt, info}, material,29+ {name: "AES-GCM", length: 256}, false, ["encrypt", "decrypt"]);30+ };31+32+ const encryptCHK = async plaintext => {33+ const input = bytes(plaintext);34+ const key = await digest(input);35+ const encrypted = new Uint8Array(await crypto.subtle.encrypt({name: "AES-GCM", iv: zeroNonce}, await aesKey(key), input));36+ return {ciphertext: encrypted, key: hex(key), hash: hex(await digest(encrypted))};37+ };38+39+ const decryptCHK = async (ciphertext, key, hash) => {40+ const input = bytes(ciphertext);41+ const chkKey = fromHex(key);42+ if (typeof hash !== "string" || !/^[0-9a-f]{64}$/.test(hash)) throw new Error("expected a 64-character lowercase blob hash");43+ if (hex(await digest(input)) !== hash) throw new Error("ciphertext hash mismatch");44+ let plain;45+ try {46+ plain = new Uint8Array(await crypto.subtle.decrypt({name: "AES-GCM", iv: zeroNonce}, await aesKey(chkKey), input));47+ } catch {48+ throw new Error("CHK decryption failed");49+ }50+ if (!equal(await digest(plain), chkKey)) throw new Error("plaintext hash mismatch");51+ return plain;52+ };53+54+ const createURI = (hash, extension, key) => {55+ if (typeof hash !== "string" || !/^[0-9a-f]{64}$/.test(hash)) throw new Error("expected a 64-character lowercase blob hash");56+ const path = "blossom:" + hash + (extension ? "." + String(extension).replace(/^\.+/, "") : "");57+ fromHex(key);58+ const params = new URLSearchParams({enc: "chk-v1", k: key});59+ return path + "?" + params;60+ };61+62+ const parseURI = value => {63+ if (typeof value !== "string" || !value.startsWith("blossom:")) throw new Error("expected a Blossom URI");64+ const parsed = new URL(value.slice("blossom:".length), "https://blossom.invalid");65+ const match = parsed.pathname.match(/^\/([0-9a-f]{64})(?:\.([A-Za-z0-9]+))?$/);66+ if (!match || parsed.searchParams.get("enc") !== "chk-v1") throw new Error("invalid CHK Blossom URI");67+ const key = parsed.searchParams.get("k");68+ fromHex(key);69+ return {hash: match[1], extension: match[2] || "", key};70+ };71+72+ globalThis.TinyBlossomEncryption = Object.freeze({encryptCHK, decryptCHK, createURI, parseURI});73+})();
A internal/webui/blossom-manifests.js +466 -0
@@ -0,0 +1,466 @@
1+(() => {2+ (() => {3+ "use strict";4+ const CHUNK_SIZE = 2 * 1024 * 1024;5+ const MAX_LINKS = 174;6+ const MAX_DEPTH = 64;7+ const MAX_MANIFEST_BYTES = 16 * 1024 * 1024;8+ const te = new TextEncoder(), td = new TextDecoder("utf-8", { fatal: true });9+ const asBytes = (v) => v instanceof Uint8Array ? v : ArrayBuffer.isView(v) ? new Uint8Array(v.buffer, v.byteOffset, v.byteLength) : (() => {10+ throw new TypeError("expected bytes");11+ })();12+ const hashBytes = (h) => {13+ if (typeof h !== "string" || !/^[0-9a-f]{64}$/.test(h)) throw new Error("expected lowercase SHA-256 hash");14+ return Uint8Array.from(h.match(/../g), (x) => parseInt(x, 16));15+ };16+ const keyBytes = (k) => {17+ if (k === void 0) return;18+ const b = asBytes(k);19+ if (b.length !== 32) throw new Error("manifest keys must be 32 bytes");20+ return b;21+ };22+ const wellFormed = (value) => {23+ for (let i = 0; i < value.length; i++) {24+ const c = value.charCodeAt(i);25+ if (c >= 55296 && c <= 56319) {26+ if (++i >= value.length || value.charCodeAt(i) < 56320 || value.charCodeAt(i) > 57343) return false;27+ } else if (c >= 56320 && c <= 57343) return false;28+ }29+ return true;30+ };31+ const nameOK = (n) => typeof n === "string" && n.length > 0 && n !== "." && n !== ".." && wellFormed(n) && !n.includes("/") && !n.includes("\0") && te.encode(n).length <= 1024;32+ const int = (n) => Number.isSafeInteger(n) && n >= 0;33+ const utf8cmp = (a, b) => {34+ const x = te.encode(a), y = te.encode(b);35+ for (let i = 0; i < Math.min(x.length, y.length); i++) if (x[i] !== y[i]) return x[i] - y[i];36+ return x.length - y.length;37+ };38+ class Writer {39+ constructor() {40+ this.a = [];41+ }42+ push(...x) {43+ this.a.push(...x);44+ }45+ u8(n) {46+ this.a.push(n & 255);47+ }48+ bytes() {49+ return Uint8Array.from(this.a);50+ }51+ }52+ const putInt = (w, n) => {53+ if (!Number.isSafeInteger(n)) throw new Error("manifest integers must be safe integers");54+ if (n >= 0) {55+ if (n < 128) w.u8(n);56+ else if (n < 256) w.push(204, n);57+ else if (n < 65536) w.push(205, n >> 8, n);58+ else if (n < 4294967296) w.push(206, n >>> 24, n >>> 16, n >>> 8, n);59+ else {60+ w.u8(207);61+ let x = BigInt(n);62+ for (let i = 7; i >= 0; i--) w.u8(Number(x >> BigInt(i * 8) & 255n));63+ }64+ } else if (n >= -32) w.u8(256 + n);65+ else if (n >= -128) w.push(208, n & 255);66+ else if (n >= -32768) w.push(209, n >> 8 & 255, n & 255);67+ else if (n >= -2147483648) w.push(210, n >>> 24, n >>> 16, n >>> 8, n);68+ else {69+ w.u8(211);70+ let x = BigInt.asUintN(64, BigInt(n));71+ for (let i = 7; i >= 0; i--) w.u8(Number(x >> BigInt(i * 8) & 255n));72+ }73+ };74+ const put = (w, v) => {75+ if (v === null) return w.u8(192);76+ if (v === false) return w.u8(194);77+ if (v === true) return w.u8(195);78+ if (typeof v === "number") {79+ if (Number.isInteger(v)) return putInt(w, v);80+ if (!Number.isFinite(v)) throw Error("metadata number must be finite");81+ w.u8(203);82+ const b = new DataView(new ArrayBuffer(8));83+ b.setFloat64(0, v);84+ for (let i = 0; i < 8; i++) w.u8(b.getUint8(i));85+ return;86+ }87+ if (typeof v === "string") {88+ const b = te.encode(v);89+ if (b.length < 32) w.u8(160 | b.length);90+ else if (b.length < 256) w.push(217, b.length);91+ else if (b.length < 65536) w.push(218, b.length >> 8, b.length);92+ else throw new Error("string too large");93+ w.push(...b);94+ return;95+ }96+ if (v instanceof Uint8Array) {97+ if (v.length < 256) w.push(196, v.length);98+ else if (v.length < 65536) w.push(197, v.length >> 8, v.length);99+ else throw new Error("binary value too large");100+ w.push(...v);101+ return;102+ }103+ if (Array.isArray(v)) {104+ if (v.length < 16) w.u8(144 | v.length);105+ else if (v.length < 65536) w.push(220, v.length >> 8, v.length);106+ else throw new Error("array too large");107+ v.forEach((x) => put(w, x));108+ return;109+ }110+ if (v && typeof v === "object") {111+ const keys = Object.keys(v).sort(utf8cmp);112+ if (keys.length < 16) w.u8(128 | keys.length);113+ else if (keys.length < 65536) w.push(222, keys.length >> 8, keys.length);114+ else throw new Error("map too large");115+ keys.forEach((k) => {116+ put(w, k);117+ put(w, v[k]);118+ });119+ return;120+ }121+ throw new Error("unsupported manifest value");122+ };123+ class Reader {124+ constructor(b) {125+ this.b = asBytes(b);126+ this.i = 0;127+ }128+ need(n) {129+ if (this.i + n > this.b.length) throw new Error("truncated MessagePack");130+ }131+ u8() {132+ this.need(1);133+ return this.b[this.i++];134+ }135+ n(len) {136+ this.need(len);137+ const x = this.b.slice(this.i, this.i + len);138+ this.i += len;139+ return x;140+ }141+ }142+ const readMap = (r, n, depth) => {143+ const o = /* @__PURE__ */ Object.create(null);144+ for (let i = 0; i < n; i++) {145+ const k = get(r, depth + 1);146+ if (typeof k !== "string" || Object.prototype.hasOwnProperty.call(o, k)) throw Error("invalid map key");147+ o[k] = get(r, depth + 1);148+ }149+ return o;150+ };151+ const get = (r, depth = 0) => {152+ if (depth > MAX_DEPTH) throw Error("MessagePack recursion limit exceeded");153+ const t = r.u8();154+ if (t <= 127) return t;155+ if (t >= 224) return t - 256;156+ if ((t & 224) === 160) return td.decode(r.n(t & 31));157+ if ((t & 240) === 144) return Array.from({ length: t & 15 }, () => get(r, depth + 1));158+ if ((t & 240) === 128) return readMap(r, t & 15, depth);159+ if (t === 192) return null;160+ if (t === 194) return false;161+ if (t === 195) return true;162+ let n;163+ if (t === 204) n = r.u8();164+ else if (t === 205) n = r.u8() << 8 | r.u8();165+ else if (t === 206) n = r.u8() * 16777216 + (r.u8() << 16) + (r.u8() << 8) + r.u8();166+ else if (t === 207) {167+ let x = 0n;168+ for (let i = 0; i < 8; i++) x = x << 8n | BigInt(r.u8());169+ if (x > BigInt(Number.MAX_SAFE_INTEGER)) throw Error("integer exceeds safe range");170+ n = Number(x);171+ } else if (t === 208) n = r.u8() << 24 >> 24;172+ else if (t === 209) {173+ n = r.u8() << 8 | r.u8();174+ if (n & 32768) n -= 65536;175+ } else if (t === 210) {176+ n = r.u8() * 16777216 + (r.u8() << 16) + (r.u8() << 8) + r.u8();177+ if (n >= 2147483648) n -= 4294967296;178+ } else if (t === 211) {179+ let x = 0n;180+ for (let i = 0; i < 8; i++) x = x << 8n | BigInt(r.u8());181+ if (x & 0x8000000000000000n) x -= 0x10000000000000000n;182+ if (x > BigInt(Number.MAX_SAFE_INTEGER) || x < BigInt(Number.MIN_SAFE_INTEGER)) throw Error("integer exceeds safe range");183+ n = Number(x);184+ } else if (t === 202) {185+ const b = new ArrayBuffer(4), d = new DataView(b);186+ for (let i = 0; i < 4; i++) d.setUint8(i, r.u8());187+ n = d.getFloat32(0);188+ } else if (t === 203) {189+ const b = new ArrayBuffer(8), d = new DataView(b);190+ for (let i = 0; i < 8; i++) d.setUint8(i, r.u8());191+ n = d.getFloat64(0);192+ } else if (t === 217) n = td.decode(r.n(r.u8()));193+ else if (t === 218) n = td.decode(r.n(r.u8() << 8 | r.u8()));194+ else if (t === 196) n = r.n(r.u8());195+ else if (t === 197) n = r.n(r.u8() << 8 | r.u8());196+ else if (t === 220) {197+ n = r.u8() << 8 | r.u8();198+ return Array.from({ length: n }, () => get(r, depth + 1));199+ } else if (t === 222) {200+ n = r.u8() << 8 | r.u8();201+ return readMap(r, n, depth);202+ } else throw Error("unsupported MessagePack type");203+ return n;204+ };205+ const validateMeta = (m, depth = 0) => {206+ if (m === void 0) return;207+ if (depth > MAX_DEPTH || !m || Array.isArray(m) || typeof m !== "object" || m instanceof Uint8Array) throw Error("metadata must be a JSON map");208+ const keys = Object.keys(m);209+ if (keys.length > 64) throw Error("too many metadata keys");210+ for (const [k, v] of Object.entries(m)) {211+ if (typeof k !== "string" || te.encode(k).length > 256) throw Error("invalid metadata key");212+ 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");213+ if (v && typeof v === "object") {214+ if (Array.isArray(v)) {215+ if (v.length > 256) throw Error("metadata array too large");216+ v.forEach((x) => validateMeta({ x }, depth + 1));217+ } else validateMeta(v, depth + 1);218+ }219+ }220+ };221+ const validateLink = (x, nodeType) => {222+ if (!x || typeof x !== "object" || Array.isArray(x)) throw Error("invalid manifest link");223+ if (Object.keys(x).some((k) => !["h", "k", "m", "n", "s", "t"].includes(k))) throw Error("unknown manifest link field");224+ if (!(x.h instanceof Uint8Array) || x.h.length !== 32) throw Error("link hash must be 32 bytes");225+ if (x.k !== void 0) keyBytes(x.k);226+ if (x.m !== void 0) validateMeta(x.m);227+ if (!int(x.s)) throw Error("invalid link size");228+ if (!int(x.t) || x.t < 0 || x.t > 3) throw Error("unsupported link type");229+ if (nodeType === 1 && x.t !== 0 && x.t !== 1) throw Error("invalid file link type");230+ if (nodeType === 1 && x.n !== void 0) throw Error("file links cannot have names");231+ if (nodeType === 3 && x.n !== void 0) throw Error("fanout links cannot have names");232+ if (nodeType === 3 && x.t !== 2 && x.t !== 3) throw Error("invalid fanout child type");233+ if (nodeType === 2 && !nameOK(x.n)) throw Error("invalid directory entry name");234+ };235+ const validateNode = (node, depth = 0) => {236+ if (depth > MAX_DEPTH) throw Error("manifest recursion limit exceeded");237+ 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");238+ if (node.l.length > MAX_LINKS) throw Error("too many manifest links");239+ const seen = /* @__PURE__ */ new Set(), links = node.l;240+ for (const x of links) {241+ validateLink(x, node.t);242+ if (node.t === 2) {243+ if (seen.has(x.n)) throw Error("duplicate directory entry");244+ seen.add(x.n);245+ }246+ if (node.t === 3) {247+ 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");248+ }249+ }250+ if (node.t === 2 && links.some((x, i) => i && utf8cmp(links[i - 1].n, x.n) >= 0)) throw Error("directory links are not canonical");251+ return node;252+ };253+ const encodeManifest = (node) => {254+ validateNode(node);255+ const w = new Writer();256+ w.u8(130);257+ put(w, "l");258+ if (node.l.length < 16) w.u8(144 | node.l.length);259+ else w.push(220, node.l.length >> 8, node.l.length);260+ for (const x of node.l) {261+ const fields = ["h", ...x.k !== void 0 ? ["k"] : [], ...x.m !== void 0 ? ["m"] : [], ...x.n !== void 0 ? ["n"] : [], "s", "t"];262+ if (fields.length < 16) w.u8(128 | fields.length);263+ else w.push(222, fields.length >> 8, fields.length);264+ for (const k of fields) {265+ put(w, k);266+ put(w, k === "h" || k === "k" ? asBytes(x[k]) : x[k]);267+ }268+ }269+ put(w, "t");270+ put(w, node.t);271+ const out = w.bytes();272+ if (out.length > MAX_MANIFEST_BYTES) throw Error("manifest too large");273+ return out;274+ };275+ const decodeManifest = (bytes, options = {}) => {276+ const b = asBytes(bytes);277+ if (b.length > MAX_MANIFEST_BYTES) throw Error("manifest too large");278+ const r = new Reader(b), node = get(r);279+ if (r.i !== b.length) throw Error("trailing MessagePack data");280+ validateNode(node);281+ if (node.t === 3) for (const x of node.l) {282+ if (x.m.count > Number(options.maxEntries || 1e9)) throw Error("fanout count limit exceeded");283+ }284+ return node;285+ };286+ const sha256 = async (b) => new Uint8Array(await crypto.subtle.digest("SHA-256", asBytes(b)));287+ const hex = (b) => Array.from(asBytes(b), (x) => x.toString(16).padStart(2, "0")).join("");288+ const manifestHash = async (node) => hex(await sha256(encodeManifest(node)));289+ const leaf = (hash, size, key) => {290+ const x = { h: hashBytes(hash), s: size, t: 0 };291+ if (key !== void 0) x.k = keyBytes(key);292+ return x;293+ };294+ const storeNode = async (node, options, manifests) => {295+ const bytes = encodeManifest(node), computed = hex(await sha256(bytes));296+ let result = { hash: computed };297+ if (options.store) {298+ const stored = await options.store({ hash: computed, bytes, node });299+ if (stored) {300+ if (typeof stored === "string") result.hash = stored;301+ else result = { ...result, ...stored };302+ }303+ }304+ if (!/^[0-9a-f]{64}$/.test(result.hash)) throw Error("store returned invalid manifest hash");305+ if (result.key !== void 0) keyBytes(result.key);306+ manifests.push({ hash: result.hash, bytes, node, key: result.key });307+ return result;308+ };309+ const buildFile = async (chunks, options = {}) => {310+ const max = options.maxLinks ?? MAX_LINKS;311+ if (!Number.isInteger(max) || max < 2 || max > MAX_LINKS) throw Error("invalid maxLinks");312+ const leaves = chunks.map((c) => typeof c === "string" ? leaf(c, options.chunkSize || 0) : leaf(c.hash, c.size, c.key));313+ if (leaves.some((x) => x.s < 0 || x.s > CHUNK_SIZE)) throw Error("invalid chunk size");314+ const manifests = [];315+ let level = leaves;316+ while (level.length > max) {317+ const next = [];318+ for (let i = 0; i < level.length; i += max) {319+ const group = level.slice(i, i + max), child = { l: group, t: 1 }, stored = await storeNode(child, options, manifests);320+ next.push({ h: hashBytes(stored.hash), ...stored.key ? { k: keyBytes(stored.key) } : {}, s: group.reduce((n, x) => n + x.s, 0), t: 1 });321+ }322+ level = next;323+ }324+ const root = { l: level, t: 1 };325+ await storeNode(root, options, manifests);326+ return options.returnDetails ? { root, manifests } : root;327+ };328+ const buildDirectory = async (entries, options = {}) => {329+ if (!Array.isArray(entries)) throw Error("entries must be an array");330+ const max = options.maxLinks ?? MAX_LINKS;331+ if (!Number.isInteger(max) || max < 2 || max > MAX_LINKS) throw Error("invalid maxLinks");332+ const sorted = entries.map((e) => {333+ const x = { h: hashBytes(e.hash), n: e.name, s: e.size || 0, t: e.type || 0 };334+ if (e.key !== void 0) x.k = keyBytes(e.key);335+ if (e.metadata !== void 0) x.m = e.metadata;336+ return x;337+ }).sort((a, b) => utf8cmp(a.n, b.n));338+ for (let i = 1; i < sorted.length; i++) if (sorted[i - 1].n === sorted[i].n) throw Error("duplicate directory entry");339+ const manifests = [];340+ if (sorted.length <= max) {341+ const root2 = { l: sorted, t: 2 };342+ await storeNode(root2, options, manifests);343+ return options.returnDetails ? { root: root2, manifests } : root2;344+ }345+ let level = [];346+ for (let i = 0; i < sorted.length; i += max) {347+ const l = sorted.slice(i, i + max), child = { l, t: 2 }, stored = await storeNode(child, options, manifests);348+ 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 });349+ }350+ while (level.length > max) {351+ const next = [];352+ for (let i = 0; i < level.length; i += max) {353+ const l = level.slice(i, i + max), child = { l, t: 3 }, stored = await storeNode(child, options, manifests);354+ 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 });355+ }356+ level = next;357+ }358+ const root = { l: level, t: 3 };359+ await storeNode(root, options, manifests);360+ return options.returnDetails ? { root, manifests } : root;361+ };362+ const flattenDirectory = (node, out = []) => {363+ validateNode(node);364+ if (node.t === 2) {365+ out.push(...node.l);366+ return out;367+ }368+ if (node.t !== 3) throw Error("not a directory");369+ for (const x of node.l) if (x.child) flattenDirectory(x.child, out);370+ return out;371+ };372+ const resolveDirectory = async (root, fetchNode, options = {}) => {373+ if (typeof fetchNode !== "function") throw Error("fetchNode is required");374+ const maxDepth = options.maxDepth ?? MAX_DEPTH, maxEntries = options.maxEntries ?? 1e5, maxManifests = options.maxManifests ?? 1e4, maxBytes = options.maxBytes ?? 64 * 1024 * 1024;375+ if ([maxDepth, maxEntries, maxManifests, maxBytes].some(value => !Number.isSafeInteger(value) || value < 0)) throw Error("invalid directory limits");376+ let count = 0, manifestCount = 0, fetched = 0;377+ const active = /* @__PURE__ */ new Set();378+ const walk = async (node, depth) => {379+ if (depth > maxDepth) throw Error("directory recursion limit exceeded");380+ if (++manifestCount > maxManifests) throw Error("manifest count limit exceeded");381+ validateNode(node);382+ if (node.t === 2) {383+ count += node.l.length;384+ if (count > maxEntries) throw Error("directory entry limit exceeded");385+ return node.l.slice();386+ }387+ if (node.t !== 3) throw Error("not a directory");388+ const result = [];389+ let previous = "";390+ for (const link of node.l) {391+ if (previous && utf8cmp(previous, link.m.first) >= 0) throw Error("fanout bounds are not ordered");392+ previous = link.m.last;393+ const linkHash = hex(link.h);394+ if (active.has(linkHash)) throw Error("manifest cycle detected");395+ active.add(linkHash);396+ let raw = asBytes(await fetchNode(linkHash, link));397+ fetched += raw.length;398+ if (fetched > maxBytes) throw Error("directory byte limit exceeded");399+ if (hex(await sha256(raw)) !== linkHash) throw Error("manifest hash mismatch");400+ if (link.k) {401+ if (typeof options.decrypt !== "function") throw Error("encrypted manifest requires decrypt callback");402+ raw = asBytes(await options.decrypt(raw, link));403+ }404+ const child = decodeManifest(raw);405+ if (child.t !== link.t) throw Error("fanout child type mismatch");406+ const links = await walk(child, depth + 1);407+ active.delete(linkHash);408+ if (links.length !== link.m.count || links[0]?.n !== link.m.first || links.at(-1)?.n !== link.m.last) throw Error("fanout bounds mismatch");409+ result.push(...links);410+ }411+ 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");412+ return result;413+ };414+ return walk(root, 0);415+ };416+ const readFile = async (root, fetchBlob, options = {}) => {417+ if (typeof fetchBlob !== "function") throw Error("fetchBlob is required");418+ const maxDepth = options.maxDepth ?? MAX_DEPTH, maxBytes = options.maxBytes ?? 512 * 1024 * 1024, maxManifests = options.maxManifests ?? 1e4;419+ const maxFetchedBytes = options.maxFetchedBytes ?? maxBytes + 16 * 1024 * 1024;420+ if ([maxDepth, maxBytes, maxManifests, maxFetchedBytes].some(value => !Number.isSafeInteger(value) || value < 0)) throw Error("invalid file limits");421+ let used = 0, fetched = 0, manifests = 0;422+ const active = /* @__PURE__ */ new Set(), parts = [];423+ const readNode = async (node, depth) => {424+ if (depth > maxDepth) throw Error("file recursion limit exceeded");425+ validateNode(node);426+ if (node.t !== 1) throw Error("not a file manifest");427+ if (++manifests > maxManifests) throw Error("manifest count limit exceeded");428+ for (const link of node.l) {429+ const hash = hex(link.h);430+ if (active.has(hash)) throw Error("manifest cycle detected");431+ active.add(hash);432+ let raw = asBytes(await fetchBlob(hash, link));433+ fetched += raw.length;434+ if (fetched > maxFetchedBytes) throw Error("file fetched byte limit exceeded");435+ if (hex(await sha256(raw)) !== hash) throw Error("blob hash mismatch");436+ if (link.t === 1) {437+ if (typeof options.decrypt !== "function" && link.k) throw Error("encrypted manifest requires decrypt callback");438+ if (link.k) raw = asBytes(await options.decrypt(raw, link));439+ const child = decodeManifest(raw);440+ if (child.t !== 1) throw Error("file child type mismatch");441+ const before = used;442+ await readNode(child, depth + 1);443+ if (used - before !== link.s) throw Error("file manifest size mismatch");444+ } else {445+ if (link.k && typeof options.decrypt !== "function") throw Error("encrypted chunk requires decrypt callback");446+ const data = link.k ? asBytes(await options.decrypt(raw, link)) : raw;447+ if (data.length !== link.s) throw Error("file chunk size mismatch");448+ used += data.length;449+ if (used > maxBytes) throw Error("file byte limit exceeded");450+ parts.push(data);451+ }452+ active.delete(hash);453+ }454+ };455+ await readNode(root, 0);456+ const out = new Uint8Array(used);457+ let at = 0;458+ for (const p of parts) {459+ out.set(p, at);460+ at += p.length;461+ }462+ return out;463+ };464+ globalThis.TinyBlossomManifests = Object.freeze({ CHUNK_SIZE, MAX_LINKS, encodeManifest, decodeManifest, encode: encodeManifest, decode: decodeManifest, manifestHash, buildFile, buildDirectory, flattenDirectory, resolveDirectory, readFile, sha256, hex });465+ })();466+})();
A internal/webui/blossom-upload.js +160 -0
@@ -0,0 +1,160 @@
1+// BUD-14 draft multipart uploads.2+// https://raw.githubusercontent.com/hzrd149/blossom/multi-part-uploads-2/buds/14.md3+// Upload state is deliberately held by the caller. It does not survive a page4+// navigation because BUD-14 has no offset discovery protocol.5+(() => {6+ "use strict";7+8+ const sha256 = async bytes => new Uint8Array(await crypto.subtle.digest("SHA-256", bytes));9+ const hex = bytes => Array.from(bytes, value => value.toString(16).padStart(2, "0")).join("");10+ const asBytes = async value => {11+ if (value instanceof Uint8Array) return value;12+ if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);13+ if (value instanceof ArrayBuffer) return new Uint8Array(value);14+ if (value instanceof Blob) return new Uint8Array(await value.arrayBuffer());15+ throw new TypeError("expected Blob, ArrayBuffer, or Uint8Array");16+ };17+ const responseBody = async response => {18+ try { return await response.json(); } catch { return null; }19+ };20+ const abortError = () => { const error = new Error("upload canceled"); error.name = "AbortError"; return error; };21+ const verifyDescriptor = (descriptor, hash, size) => {22+ if (!descriptor || typeof descriptor !== "object" || descriptor.sha256 !== hash || descriptor.size !== size) throw new Error("invalid Blossom upload descriptor");23+ return descriptor;24+ };25+26+ const uploadTask = async (source, options = {}, controller) => {27+ const bytes = await asBytes(source);28+ const hash = options.hash || hex(await sha256(bytes));29+ if (!/^[0-9a-f]{64}$/.test(hash)) throw new Error("expected a lowercase SHA-256 hash");30+ if (options.hash && hash !== hex(await sha256(bytes))) throw new Error("upload hash mismatch");31+ const type = options.type || source.type || "application/octet-stream";32+ const base = options.url || options.endpoint;33+ if (typeof base !== "string" || base === "") throw new Error("upload URL is required");34+ let parsed;35+ try { parsed = new URL(base, globalThis.location?.href || "https://blossom.invalid"); } catch { throw new Error("invalid upload URL"); }36+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw new Error("upload URL must use HTTP or HTTPS");37+ if (parsed.username || parsed.password || parsed.hash || parsed.search) throw new Error("upload URL must not contain credentials, query, or fragment");38+ const extension = options.extension ? String(options.extension).replace(/^\.+/, "") : "";39+ if (extension && !/^[a-z0-9]{1,8}$/.test(extension)) throw new Error("invalid file extension");40+ const path = parsed.pathname;41+ const target = new RegExp("/" + hash + "(?:\\.[a-z0-9]{1,8})?/?$").test(path) ? base : base.replace(/\/$/, "") + "/" + hash + (extension ? "." + extension : "");42+ const url = target;43+ const fetcher = options.fetch || globalThis.fetch;44+ if (typeof fetcher !== "function") throw new Error("fetch is unavailable");45+ const chunkSize = Number.isSafeInteger(options.chunkSize) && options.chunkSize > 0 ? options.chunkSize : 5 * 1024 * 1024;46+ const timeoutMs = Number.isSafeInteger(options.timeoutMs) && options.timeoutMs > 0 ? options.timeoutMs : 30000;47+ const retries = Number.isSafeInteger(options.retries) && options.retries >= 0 ? options.retries : 0;48+ const state = options.state instanceof Map ? options.state : new Map();49+ const notify = (offset, length, status) => options.onState?.({offset, length, status, state});50+ const progress = sent => options.onProgress?.({sent, total: bytes.byteLength, fraction: bytes.byteLength ? sent / bytes.byteLength : 1});51+ const request = async (method, body, headers, authBody = body) => {52+ if (controller.signal.aborted) throw abortError();53+ const requestController = new AbortController();54+ let timer, rejectCanceled;55+ const cancel = () => { requestController.abort(); rejectCanceled?.(abortError()); };56+ controller.signal.addEventListener("abort", cancel, {once: true});57+ try {58+ return await Promise.race([59+ (async () => {60+ const requestHeaders = {...headers};61+ if (options.authorize && method !== "OPTIONS") {62+ const value = await options.authorize(url, method, authBody, {hash, type});63+ if (typeof value === "string") requestHeaders.authorization = value;64+ else if (value && typeof value === "object") Object.assign(requestHeaders, value);65+ }66+ if (requestController.signal.aborted) throw abortError();67+ const response = await fetcher(url, {method, headers: requestHeaders, body: method === "OPTIONS" ? undefined : body, signal: requestController.signal});68+ // Keep the request deadline and cancellation active until the69+ // descriptor body has arrived, not only until headers arrive.70+ const descriptor = response.status === 200 || response.status === 201 ? await responseBody(response) : null;71+ if (!descriptor) await response.body?.cancel?.();72+ return {status: response.status, ok: response.ok, headers: response.headers, json: async () => descriptor};73+ })(),74+ new Promise((_, reject) => {75+ timer = setTimeout(() => { requestController.abort(); reject(Error("upload request timed out")); }, timeoutMs);76+ }),77+ new Promise((_, reject) => { rejectCanceled = reject; })78+ ]);79+ } finally {80+ clearTimeout(timer);81+ controller.signal.removeEventListener("abort", cancel);82+ requestController.abort();83+ }84+ };85+ const retry = async (action, offset, length) => {86+ let attempt = 0;87+ while (true) {88+ if (controller.signal.aborted) throw abortError();89+ try {90+ const result = await action();91+ if (!result.ok && result.status >= 500 && attempt++ < retries) { notify(offset, length, "retrying"); continue; }92+ return result;93+ } catch (error) {94+ if (controller.signal.aborted) throw abortError();95+ if (attempt++ >= retries) throw error;96+ notify(offset, length, "retrying");97+ }98+ }99+ };100+101+ let supportsPatch = options.probe === false;102+ if (options.probe !== false) {103+ try {104+ const response = await request("OPTIONS", null, {});105+ supportsPatch = /(?:^|,|\s)PATCH(?:,|\s|$)/i.test(response.headers?.get?.("allow") || "");106+ } catch { supportsPatch = false; }107+ }108+ if (!supportsPatch) {109+ const response = await retry(() => request("PUT", bytes, {"content-type": type}), 0, bytes.byteLength);110+ if (!response.ok) throw new Error("Blossom upload failed: " + response.status);111+ return {hash, descriptor: verifyDescriptor(await responseBody(response), hash, bytes.byteLength), state};112+ }113+114+ const metadata = state.meta;115+ if (!metadata || metadata.hash !== hash || metadata.size !== bytes.byteLength || metadata.chunkSize !== chunkSize || metadata.url !== url || metadata.type !== type || Date.now() - (metadata.lastAcceptedAt || 0) >= 60000) {116+ state.clear();117+ state.meta = {hash, size: bytes.byteLength, chunkSize, url, type, lastAcceptedAt: 0};118+ }119+ let sent = 0;120+ let replayed = false;121+ while (true) {122+ for (let offset = 0; offset < bytes.byteLength || (bytes.byteLength === 0 && offset === 0); offset += chunkSize) {123+ const end = Math.min(offset + chunkSize, bytes.byteLength);124+ const chunk = bytes.slice(offset, end);125+ const length = chunk.byteLength;126+ const prior = state.get(offset);127+ if (!replayed && prior?.status === 204 && Date.now() - (state.meta.lastAcceptedAt || 0) < 60000) { sent = end; progress(sent); continue; }128+ const result = await retry(() => request("PATCH", chunk, {129+ "upload-type": type,130+ "upload-length": String(bytes.byteLength),131+ "upload-offset": String(offset),132+ "content-type": "application/octet-stream"133+ }, options.authorizationMode === "final-hash" ? bytes : chunk), offset, length);134+ if (![200, 201, 204].includes(result.status)) throw new Error("Blossom chunk upload failed: " + result.status);135+ state.set(offset, {offset, length, status: result.status});136+ state.meta.lastAcceptedAt = Date.now();137+ sent = end;138+ notify(offset, length, result.status === 204 ? "uploaded" : "complete");139+ progress(sent);140+ if (result.status !== 204) return {hash, descriptor: verifyDescriptor(await responseBody(result), hash, bytes.byteLength), state};141+ if (bytes.byteLength === 0) break;142+ }143+ if (!replayed) { replayed = true; continue; }144+ throw new Error("multipart upload ended without completion");145+ }146+ };147+148+ const upload = (source, options = {}) => {149+ const controller = new AbortController();150+ if (options.signal) {151+ if (options.signal.aborted) controller.abort();152+ else options.signal.addEventListener("abort", () => controller.abort(), {once: true});153+ }154+ const task = uploadTask(source, options, controller);155+ task.cancel = () => controller.abort();156+ return task;157+ };158+159+ globalThis.TinyBlossomUpload = Object.freeze({upload});160+})();
M internal/webui/bridge.js +1 -1
M internal/webui/browse.html +5 -0
@@ -14,6 +14,8 @@
1414 1515 {{define "files"}}<section>1616 <h1>Files</h1>17+<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>18+{{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}}1719 {{if .Error}}{{template "alert" .Error}}1820 {{else if .Feed}}<table id="rows">1921 <thead><tr><th>hash</th><th>type</th><th>uploaded</th></tr></thead>
@@ -36,6 +38,9 @@
3638 {{with index $file "blossom_uri"}}<tr><th>blossom</th><td><code>{{.}}</code></td></tr>{{end}}3739 <tr><th>download</th><td><a fx-ignore href="/files/raw?hash={{urlquery (str (index $file "sha256"))}}">raw</a></td></tr>3840 </table>41+<file-workspace-root hash="{{str (index $file "sha256")}}" type="{{str (index $file "type")}}" hidden></file-workspace-root>42+<noscript><p>Enable JavaScript to decrypt files and browse folder manifests locally. Raw downloads remain available above.</p></noscript>43+<file-tools hash="{{str (index $file "sha256")}}" type="{{str (index $file "type")}}" size="{{str (index $file "size")}}" name="{{shortID (index $file "sha256")}}"></file-tools>3944 {{$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>4045 {{else if hasPrefix $type "video/"}}<div id="media"><video controls src="{{$raw}}"></video></div>4146 {{else if hasPrefix $type "audio/"}}<div id="media"><audio controls src="{{$raw}}"></audio></div>
M internal/webui/components.js +224 -0
@@ -18,6 +18,12 @@
1818 // Tables sit inside a <scroll-box> so wide rows scroll sideways.1919 // <nostr-key hex="…">2020 // Shortened key with the full hex as title; click copies it.21+// <file-mirror action="/mirror">22+// Signed BUD-04 mirror of a URL or Blossom URI into this relay.23+// <file-tools [hash="…"] [type="…"]>24+// Copies Blossom links, encrypts and uploads a file, decrypts a share25+// link fragment and sends a random-key file as a NIP-17 message.26+// <file-workspace> and <file-workspace-root> live in file-workspace.js.2127 (() => {2228 "use strict";2329
@@ -167,6 +173,222 @@
167173 }168174 }169175 176+ class FileMirror extends FormElement {177+ async submit(form) {178+ let source = form.elements.namedItem("url").value.trim();179+ if (!source) throw Error("Enter a URL or Blossom URI.");180+ 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.");181+ if (/^https?:/i.test(source)) { const url = new URL(source); url.hash = ""; source = url.href; }182+ const action = this.getAttribute("action") || "/mirror";183+ const body = JSON.stringify({url: source});184+ this.report("Signing…");185+ const response = await tiny.signedFetch(action, "PUT", body, {contentType: "application/json"});186+ let result;187+ try { result = await response.json(); } catch { result = await response.text(); }188+ this.report("Stored.");189+ const view = el("json-view");190+ view.value = result;191+ this.append(view);192+ }193+194+ connectedCallback() {195+ if (this.form) return;196+ this.innerHTML = '<form><label>URL or Blossom URI <input name="url" type="text" placeholder="https://… or blossom:…" required></label><button>Mirror</button></form>';197+ super.connectedCallback();198+ }199+ }200+201+ const b64url = bytes => {202+ let binary = "";203+ bytes.forEach(byte => { binary += String.fromCharCode(byte); });204+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");205+ };206+ const fromB64url = value => {207+ const text = value.replace(/-/g, "+").replace(/_/g, "/") + "===".slice((value.length + 3) % 4);208+ return Uint8Array.from(atob(text), char => char.charCodeAt(0));209+ };210+211+ class FileTools extends HTMLElement {212+ disconnectedCallback() {213+ if (this.downloadURL) URL.revokeObjectURL(this.downloadURL);214+ this.uploadTask?.cancel?.();215+ this.uploadController?.abort();216+ this.uploadCanceled = true;217+ }218+219+ connectedCallback() {220+ if (this.bound) return;221+ this.bound = true;222+ 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>';223+ this.output = this.querySelector("output");224+ this.querySelector("[data-copy]").addEventListener("click", () => this.copy(this.blossomURI()));225+ this.querySelector("[data-link]").addEventListener("click", () => this.copy(this.shareLink()));226+ this.querySelector("form:not([data-share])").addEventListener("submit", event => { event.preventDefault(); this.encryptUpload(event.currentTarget); });227+ this.querySelector("[data-upload-cancel]").addEventListener("click", () => { this.uploadCanceled = true; this.uploadTask?.cancel?.(); this.uploadController?.abort(); });228+ this.querySelector("[data-upload-retry]").addEventListener("click", () => this.retryUpload());229+ this.querySelector("[data-share]").addEventListener("submit", event => { event.preventDefault(); this.share(event.currentTarget); });230+ this.updateFileControls();231+ this.decryptFromFragment();232+ }233+234+ hash() { return this.fileHash || this.getAttribute("hash") || ""; }235+ type() { return this.getAttribute("type") || "application/octet-stream"; }236+ updateFileControls() {237+ const available = Boolean(this.hash());238+ this.querySelectorAll("[data-copy], [data-link], [data-share] button").forEach(button => { button.disabled = !available; });239+ }240+ blossomURI() {241+ const params = new URLSearchParams(this.fileFragment || location.hash.slice(1));242+ const extension = params.has("manifest") ? (["2", "3"].includes(params.get("node") || "2") ? "bdir" : params.get("node") === "1" ? "bfile" : "bin") : "bin";243+ const uri = (params.get("enc") === "chk-v1" || params.has("manifest")) && params.get("key") ? TinyBlossomEncryption.createURI(this.hash(), extension, params.get("key")) : "blossom:" + this.hash();244+ return tiny.root ? uri : uri + (uri.includes("?") ? "&" : "?") + "xs=" + encodeURIComponent(new URL(location.href).host);245+ }246+ shareLink() {247+ if (this.fileShareLink) return this.fileShareLink;248+ const fragment = this.fileFragment || location.hash.slice(1);249+ const params = new URLSearchParams(fragment);250+ 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;251+ return location.href.split("#", 1)[0] + "#blossom=" + encodeURIComponent(this.hash());252+ }253+ async copy(value) {254+ try { await navigator.clipboard.writeText(value); this.say("Copied."); }255+ catch { this.say(value); }256+ }257+ say(value, error) { this.output.textContent = value; if (error) this.output.dataset.error = ""; else delete this.output.dataset.error; }258+259+ uploadBusy(value) {260+ this.busy = value;261+ this.querySelector("[data-upload-cancel]").disabled = !value;262+ this.querySelector("[data-upload-retry]").disabled = value || !this.pendingUpload;263+ }264+265+ async encryptUpload(form) {266+ if (this.busy) return;267+ const file = form.elements.namedItem("file").files[0];268+ if (!file) { this.say("Choose a file first.", true); return; }269+ this.uploadBusy(true);270+ this.uploadCanceled = false;271+ try {272+ if (file.size > 256 * 1024 * 1024) throw Error("Encrypted browser uploads are limited to 256 MiB.");273+ this.say("Encrypting and signing…");274+ const scheme = form.elements.namedItem("scheme").value;275+ const plaintext = new Uint8Array(await file.arrayBuffer());276+ const plaintextHash = await tiny.sha256hex(plaintext);277+ let ciphertext, fragment;278+ if (scheme === "chk") {279+ if (!globalThis.TinyBlossomEncryption) throw Error("CHK encryption is unavailable. Reload this page.");280+ const encrypted = await TinyBlossomEncryption.encryptCHK(plaintext);281+ ciphertext = encrypted.ciphertext;282+ fragment = "enc=chk-v1&key=" + encrypted.key;283+ } else {284+ const key = await crypto.subtle.generateKey({name: "AES-GCM", length: 256}, true, ["encrypt", "decrypt"]);285+ const iv = crypto.getRandomValues(new Uint8Array(12));286+ ciphertext = new Uint8Array(await crypto.subtle.encrypt({name: "AES-GCM", iv}, key, plaintext));287+ const rawKey = new Uint8Array(await crypto.subtle.exportKey("raw", key));288+ fragment = "key=" + b64url(rawKey) + "&iv=" + b64url(iv);289+ }290+ fragment += "&name=" + encodeURIComponent(file.name) + "&type=" + encodeURIComponent(file.type || "application/octet-stream") + "&ox=" + plaintextHash;291+ this.pendingUpload = {ciphertext, fragment, file, state: new Map()};292+ if (this.uploadCanceled) throw Error("Upload canceled.");293+ await this.storePreparedUpload();294+ } catch (error) { this.say("Upload stopped: " + error.message + (this.pendingUpload ? " Retry while this page stays open." : ""), true); }295+ finally { this.uploadBusy(false); }296+ }297+298+ async retryUpload() {299+ if (this.busy || !this.pendingUpload) return;300+ this.uploadBusy(true);301+ this.uploadCanceled = false;302+ try { await this.storePreparedUpload(); }303+ catch (error) { this.say("Upload stopped: " + error.message + " Retry while this page stays open.", true); }304+ finally { this.uploadBusy(false); }305+ }306+307+ async storePreparedUpload() {308+ const {ciphertext, fragment, file, state} = this.pendingUpload;309+ const actualHash = await tiny.sha256hex(ciphertext);310+ this.uploadController = new AbortController();311+ let descriptor;312+ if (globalThis.TinyBlossomUpload?.upload) {313+ const task = TinyBlossomUpload.upload(ciphertext, {314+ url: new URL(tiny.localPath("/"), location.href).href, hash: actualHash,315+ type: "application/octet-stream", state, signal: this.uploadController.signal,316+ authorize: (url, verb, body) => tiny.authorization(url, verb, body),317+ onProgress: progress => this.say("Uploading " + Math.round(progress.fraction * 100) + "%…")318+ });319+ this.uploadTask = task;320+ descriptor = (await task).descriptor;321+ } else {322+ const response = await tiny.signedFetch("/upload", "PUT", ciphertext, {contentType: "application/octet-stream", signal: this.uploadController.signal});323+ descriptor = await response.json();324+ }325+ if (descriptor.sha256 !== actualHash) throw Error("relay returned an unexpected hash");326+ this.fileHash = actualHash;327+ this.fileFragment = fragment;328+ this.setAttribute("hash", actualHash);329+ this.setAttribute("type", file.type || "application/octet-stream");330+ this.setAttribute("size", String(ciphertext.length));331+ this.updateFileControls();332+ const link = new URL(location.href);333+ link.pathname = location.pathname.replace(/\/files?$/, "/file");334+ link.search = "?hash=" + actualHash;335+ link.hash = fragment;336+ this.fileShareLink = link.href;337+ const share = this.querySelector("[data-share-url]");338+ if (share) share.value = link.href;339+ this.pendingUpload = null;340+ this.uploadTask = null;341+ try {342+ if (!navigator.clipboard?.writeText) throw Error("Clipboard unavailable");343+ await navigator.clipboard.writeText(link.href);344+ this.say("Encrypted file stored. Share link copied; the key is only in its fragment.");345+ } catch {346+ if (share) share.select?.();347+ this.say("Encrypted file stored. Copy the share link above; the key is only in its fragment.");348+ }349+ }350+351+ async decryptFromFragment() {352+ const params = new URLSearchParams(this.fileFragment || location.hash.slice(1));353+ if ((!params.get("key") || !params.get("iv")) && !(params.get("enc") === "chk-v1" && params.get("key"))) return;354+ try {355+ this.say("Decrypting…");356+ const response = await fetch(tiny.localPath("/files/raw?hash=" + encodeURIComponent(this.hash())));357+ if (!response.ok) throw Error("download failed (" + response.status + ")");358+ const encrypted = new Uint8Array(await response.arrayBuffer());359+ if (await tiny.sha256hex(encrypted) !== this.hash()) throw Error("ciphertext hash mismatch");360+ let plain;361+ if (params.get("enc") === "chk-v1") plain = await TinyBlossomEncryption.decryptCHK(encrypted, params.get("key"), this.hash());362+ else {363+ const key = await crypto.subtle.importKey("raw", fromB64url(params.get("key")), "AES-GCM", false, ["decrypt"]);364+ plain = await crypto.subtle.decrypt({name: "AES-GCM", iv: fromB64url(params.get("iv"))}, key, encrypted);365+ }366+ if (params.get("ox") && await tiny.sha256hex(plain) !== params.get("ox")) throw Error("plaintext hash mismatch");367+ if (this.downloadURL) URL.revokeObjectURL(this.downloadURL);368+ 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.");369+ } catch (error) { this.say("Could not decrypt this file: " + error.message, true); }370+ }371+372+ async share(form) {373+ if (this.sharing) return;374+ const recipient = form.elements.namedItem("recipient").value.trim();375+ if (!recipient) { this.say("Enter a public key or npub.", true); return; }376+ const params = new URLSearchParams(this.fileFragment || location.hash.slice(1));377+ const signer = globalThis.tinySigner || globalThis.nostr;378+ 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; }379+ if (!params.get("key") || !params.get("iv")) { this.say("NIP-17 sharing currently requires a random AES-GCM encrypted file.", true); return; }380+ this.sharing = true;381+ try {382+ const key = fromB64url(params.get("key")), nonce = fromB64url(params.get("iv"));383+ if (key.length !== 32 || nonce.length !== 12) throw Error("Invalid file key or nonce.");384+ const hex = bytes => Array.from(bytes, value => value.toString(16).padStart(2, "0")).join("");385+ this.say("Preparing sealed NIP-17 delivery…");386+ 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});387+ this.say("Encrypted message delivered; sender copy saved.");388+ } catch (error) { this.say("NIP-17 delivery failed: " + error.message, true); } finally { this.sharing = false; }389+ }390+ }391+170392 class PublishList extends FormElement {171393 async submit(form) {172394 if (!window.nostr?.signEvent) throw Error("Connect a signer first.");
@@ -549,6 +771,8 @@
549771 customElements.define("connect-list", ConnectList);550772 customElements.define("relay-lists", RelayLists);551773 customElements.define("signed-form", SignedForm);774+ customElements.define("file-mirror", FileMirror);775+ customElements.define("file-tools", FileTools);552776 customElements.define("publish-list", PublishList);553777 customElements.define("nostr-key", NostrKey);554778 customElements.define("json-view", JsonView);
A internal/webui/file-messages.js +209 -0
@@ -0,0 +1,209 @@
1+/* NIP-17 file messages. This module never publishes to ordinary relays. */2+(function (root) {3+ "use strict";4+5+ const MAX_RELAYS = 8;6+ const DAY = 86400;7+8+ function api() {9+ const signer = root.NostrSigner;10+ if (!signer || !signer.nip44 || !signer.finalizeEvent || !signer.generateSecretKey) {11+ throw new Error("NIP-44 support is unavailable");12+ }13+ return signer;14+ }15+16+ function relayURL(value) {17+ if (typeof value !== "string" || value.length > 2048) return null;18+ let url;19+ try { url = new URL(value); } catch { return null; }20+ if (url.protocol !== "wss:" && url.protocol !== "ws:") return null;21+ if (url.username || url.password || url.hash) return null;22+ return url.toString().replace(/\/$/, "");23+ }24+25+ function relayList(event, pubkey) {26+ if (Array.isArray(event)) {27+ event = event.filter((candidate) => candidate?.kind === 10050 && candidate.pubkey === pubkey)28+ .sort((a, b) => b.created_at - a.created_at)[0];29+ }30+ if (!event || event.kind !== 10050 || event.pubkey !== pubkey) {31+ throw new Error("recipient has no valid kind 10050 relay list");32+ }33+ const signer = api();34+ if (!signer.verifyEvent(event)) throw new Error("invalid kind 10050 relay list signature");35+ const relays = [...new Set(event.tags.filter((tag) => tag[0] === "relay").map((tag) => relayURL(tag[1])).filter(Boolean))];36+ if (!relays.length) throw new Error("kind 10050 relay list is empty");37+ return relays.slice(0, MAX_RELAYS);38+ }39+40+ function normalizePubkey(value) {41+ const text = String(value || "").trim();42+ if (/^[0-9a-f]{64}$/i.test(text)) return text.toLowerCase();43+ const decoded = api().decodeNpub?.(text);44+ if (typeof decoded === "string" && /^[0-9a-f]{64}$/i.test(decoded)) return decoded.toLowerCase();45+ throw new Error("public key must be a 64 character hex key or npub");46+ }47+48+ async function bounded(value, timeout, label) {49+ const ms = Number.isFinite(timeout) && timeout > 0 ? timeout : 10000;50+ let timer;51+ try {52+ return await Promise.race([Promise.resolve(value), new Promise((_, reject) => {53+ timer = setTimeout(() => reject(new Error(label + " timed out")), ms);54+ })]);55+ } finally { clearTimeout(timer); }56+ }57+58+ function sent(result) {59+ if (result === false || result == null) return false;60+ if (Array.isArray(result)) return result.some(sent);61+ if (typeof result === "object" && "ok" in result) return result.ok === true;62+ return true;63+ }64+65+ function past(now) {66+ return Math.max(0, Math.floor(now) - Math.floor(Math.random() * (2 * DAY + 1)));67+ }68+69+ async function publicKey(signer, getPublicKey) {70+ const key = getPublicKey ? await getPublicKey() : await signer.getPublicKey();71+ if (typeof key !== "string" || !/^[0-9a-f]{64}$/i.test(key)) throw new Error("invalid signer public key");72+ return key.toLowerCase();73+ }74+75+ async function queryRelayList(pubkey, options) {76+ if (!root.tiny?.signedFetch) throw new Error("signed local query is unavailable");77+ const response = await root.tiny.signedFetch("/query", "POST", JSON.stringify([{ kinds: [10050], authors: [pubkey], limit: 1 }]), { contentType: "application/json" });78+ return response.json();79+ }80+81+ function publishEvent(event, relays, options) {82+ const signer = options.signer || root.tinySigner || root.nostr;83+ const WebSocketImpl = options.WebSocket || root.WebSocket;84+ if (typeof WebSocketImpl !== "function") throw new Error("WebSocket support is unavailable");85+ const timeout = Number.isFinite(options.timeoutMs) && options.timeoutMs > 0 ? options.timeoutMs : 10000;86+ return Promise.all(relays.map((url) => new Promise((resolve) => {87+ let socket;88+ let timer;89+ let settled = false;90+ let authID = "";91+ let authAttempts = 0;92+ let eventSent = false;93+ const finish = (ok) => { if (settled) return; settled = true; clearTimeout(timer); try { socket?.close(); } catch {} resolve(ok); };94+ const sendEvent = () => { if (!settled && !eventSent) { eventSent = true; socket.send(JSON.stringify(["EVENT", event])); } };95+ try {96+ socket = new WebSocketImpl(url);97+ timer = setTimeout(() => finish(false), timeout);98+ socket.onopen = sendEvent;99+ socket.onmessage = async (message) => {100+ let frame;101+ try { frame = JSON.parse(typeof message.data === "string" ? message.data : ""); } catch { return; }102+ if (settled || !Array.isArray(frame)) return;103+ if (frame[0] === "OK" && frame[1] === authID) {104+ if (frame[2] === true) { eventSent = false; sendEvent(); } else finish(false);105+ return;106+ }107+ if (frame[0] === "OK" && frame[1] === event.id) {108+ if (frame[2] !== true && String(frame[3] || "").toLowerCase().startsWith("auth-required")) { eventSent = false; return; }109+ finish(frame[2] === true); return;110+ }111+ if (frame[0] !== "AUTH" || typeof signer?.signEvent !== "function") return;112+ if (typeof frame[1] !== "string" || frame[1].length > 4096) { finish(false); return; }113+ if (authAttempts++ >= 1) { finish(false); return; }114+ try {115+ const auth = await signer.signEvent({ kind: 22242, created_at: Math.floor(Date.now() / 1000), tags: [["relay", url], ["challenge", frame[1]], ["method", "AUTH"]], content: "" });116+ 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])); }117+ else finish(false);118+ } catch { finish(false); }119+ };120+ socket.onerror = () => finish(false);121+ socket.onclose = () => finish(false);122+ } catch { finish(false); }123+ })));124+ }125+126+ function unsignedRumor(input, sender, now) {127+ if (!input.fileURL || !/^https?:\/\//i.test(input.fileURL)) throw new Error("fileURL must be an HTTP(S) URL");128+ if (!/^[0-9a-f]{64}$/i.test(input.ciphertextHash || "")) throw new Error("ciphertextHash must be SHA-256 hex");129+ if (!input.key || !input.nonce) throw new Error("encrypted file messages require a decryption key and nonce");130+ const tags = [["p", input.recipient]];131+ if (input.mimeType) tags.push(["file-type", input.mimeType]);132+ tags.push(["encryption-algorithm", "aes-gcm"]);133+ if (input.key) tags.push(["decryption-key", input.key]);134+ if (input.nonce) tags.push(["decryption-nonce", input.nonce]);135+ tags.push(["x", input.ciphertextHash.toLowerCase()]);136+ if (input.plaintextHash) {137+ if (!/^[0-9a-f]{64}$/i.test(input.plaintextHash)) throw new Error("plaintextHash must be SHA-256 hex");138+ tags.push(["ox", input.plaintextHash.toLowerCase()]);139+ }140+ if (input.size != null) tags.push(["size", String(input.size)]);141+ const rumor = { pubkey: sender, created_at: Math.floor(now), kind: 15, tags, content: input.fileURL };142+ rumor.id = api().getEventHash(rumor);143+ return rumor;144+ }145+146+ async function encryptFor(signer, recipient, plaintext) {147+ if (typeof signer.nip44Encrypt === "function") return signer.nip44Encrypt(recipient, plaintext);148+ if (signer.nip44?.encrypt) return signer.nip44.encrypt(recipient, plaintext);149+ throw new Error("signer has no NIP-44 encrypt method");150+ }151+152+ async function seal(rumor, recipient, signer, now) {153+ const content = await encryptFor(signer, recipient, JSON.stringify(rumor));154+ const unsigned = { kind: 13, tags: [], content, created_at: past(now), pubkey: rumor.pubkey };155+ const event = await signer.signEvent(unsigned);156+ 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");157+ if (!api().verifyEvent(event)) throw new Error("signer returned an invalid seal signature");158+ return event;159+ }160+161+ function wrap(sealEvent, recipient, now) {162+ const signer = api();163+ const secret = signer.generateSecretKey();164+ const pubkey = signer.getPublicKey(secret);165+ const key = signer.nip44.getConversationKey(secret, recipient);166+ const content = signer.nip44.encrypt(JSON.stringify(sealEvent), key);167+ const event = signer.finalizeEvent({ kind: 1059, tags: [["p", recipient]], content, created_at: past(now) }, secret);168+ if (!signer.verifyEvent(event)) throw new Error("failed to verify gift wrap");169+ return { event, secret, pubkey };170+ }171+172+ async function build(input, options = {}) {173+ const signer = options.signer || root.tinySigner || root.nostr;174+ if (!signer || typeof signer.signEvent !== "function" || (typeof signer.nip44Encrypt !== "function" && !signer.nip44?.encrypt)) throw new Error("a NIP-44 signer is required");175+ const recipient = normalizePubkey(input.recipient);176+ const sender = await publicKey(signer, options.getPublicKey);177+ const now = (options.now || Date.now() / 1000);178+ const rumor = unsignedRumor({ ...input, recipient }, sender, now);179+ const receiverSeal = await seal(rumor, recipient, signer, now);180+ const senderSeal = await seal(rumor, sender, signer, now);181+ const receiver = wrap(receiverSeal, recipient, now).event;182+ const own = wrap(senderSeal, sender, now).event;183+ return { rumor, events: [{ recipient, event: receiver }, { recipient: sender, event: own }] };184+ }185+186+ async function share(input, options = {}) {187+ const signer = options.signer || root.tinySigner || root.nostr;188+ const query = options.queryRelayList || ((pubkey) => queryRelayList(pubkey, options));189+ const publish = options.publish || ((event, relays) => publishEvent(event, relays, options));190+ if (typeof query !== "function" || typeof publish !== "function") throw new Error("private NIP-17 delivery is unavailable");191+ const sender = await publicKey(signer, options.getPublicKey);192+ const recipient = normalizePubkey(input.recipient);193+ const timeout = options.timeoutMs;194+ const receiverList = relayList(await bounded(query(recipient), timeout, "recipient relay lookup"), recipient);195+ const senderList = relayList(await bounded(query(sender), timeout, "sender relay lookup"), sender);196+ const built = await build(input, options);197+ if (built.rumor.pubkey !== sender) throw new Error("signer changed during file sharing; try again");198+ const deliveries = [];199+ for (const target of built.events) {200+ const relays = target.recipient === recipient ? receiverList : senderList;201+ const delivery = await bounded(publish(target.event, relays), timeout, "NIP-17 delivery");202+ if (!sent(delivery)) throw new Error("NIP-17 delivery failed on every inbox relay");203+ deliveries.push(delivery);204+ }205+ return { ...built, relays: { recipient: receiverList, sender: senderList }, deliveries };206+ }207+208+ root.TinyFileMessages = { build, share, relayList, queryRelayList, publishEvent };209+})(globalThis);
A internal/webui/file-workspace.js +291 -0
@@ -0,0 +1,291 @@
1+// Draft BUD-16/17 trees. Every object written here is encrypted with BUD-15.2+(() => {3+ "use strict";4+5+ const MAX_FILES = 10000;6+ const MAX_DEPTH = 32;7+ const MAX_FILE_BYTES = 256 * 1024 * 1024;8+ const MAX_FOLDER_BYTES = 1024 * 1024 * 1024;9+ const MAX_FETCH_BYTES = 16 * 1024 * 1024 + 16;10+ const directoryType = "application/vnd.blossom.directory+msgpack";11+ const codec = () => globalThis.TinyBlossomManifests;12+ const hex = value => codec().hex(value);13+ const fromHex = value => {14+ if (!/^[0-9a-f]{64}$/.test(value || "")) throw Error("Invalid hash or encryption key.");15+ return Uint8Array.from(value.match(/../g), byte => parseInt(byte, 16));16+ };17+ const element = (tag, text) => {18+ const node = document.createElement(tag);19+ if (text !== undefined) node.textContent = text;20+ return node;21+ };22+ const checkAbort = signal => {23+ if (signal?.aborted) throw Object.assign(Error("Upload canceled. Retry while this page stays open."), {name: "AbortError"});24+ };25+ const validName = name => typeof name === "string" && name.length > 0 && name.isWellFormed() && ![".", ".."].includes(name) && !/[\/\u0000]/.test(name) && new TextEncoder().encode(name).length <= 1024;26+ const folderNode = () => ({directories: new Map(), files: new Map()});27+28+ function selectionTree(files) {29+ if (!files.length || files.length > MAX_FILES) throw Error("Choose a folder with 1 to 10,000 files.");30+ const root = folderNode();31+ let total = 0;32+ const paths = files.map(file => (file.webkitRelativePath || file.name).split("/"));33+ const commonRoot = paths.every(path => path.length > 1 && path[0] === paths[0][0]);34+ for (let index = 0; index < files.length; index++) {35+ const file = files[index];36+ const path = commonRoot ? paths[index].slice(1) : paths[index];37+ if (path.length > MAX_DEPTH || path.some(name => !validName(name))) throw Error("Invalid folder path.");38+ 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.");39+ total += file.size;40+ if (total > MAX_FOLDER_BYTES) throw Error("The selected folder exceeds 1 GiB.");41+ let directory = root;42+ for (const name of path.slice(0, -1)) {43+ if (directory.files.has(name)) throw Error("A file and folder use the same name.");44+ if (!directory.directories.has(name)) directory.directories.set(name, folderNode());45+ directory = directory.directories.get(name);46+ }47+ const name = path.at(-1);48+ if (directory.files.has(name) || directory.directories.has(name)) throw Error("Duplicate folder entry.");49+ directory.files.set(name, file);50+ }51+ return {root, name: commonRoot ? paths[0][0] : "folder"};52+ }53+54+ async function storeEncrypted(plaintext, type, signal) {55+ checkAbort(signal);56+ const encrypted = await TinyBlossomEncryption.encryptCHK(plaintext);57+ checkAbort(signal);58+ const url = new URL(tiny.localPath("/"), location.href).href;59+ const result = await TinyBlossomUpload.upload(encrypted.ciphertext, {60+ url, hash: encrypted.hash, type, signal,61+ authorize: (target, method, body) => tiny.authorization(target, method, body)62+ });63+ if (result.descriptor.sha256 !== encrypted.hash || result.descriptor.size !== encrypted.ciphertext.length) throw Error("Relay returned an unexpected blob descriptor.");64+ return {hash: encrypted.hash, key: fromHex(encrypted.key)};65+ }66+67+ const manifestStore = signal => async ({bytes, node}) => storeEncrypted(bytes, node.t === 2 || node.t === 3 ? directoryType : "application/octet-stream", signal);68+ const rootReference = details => {69+ const stored = details.manifests.at(-1);70+ return {hash: stored.hash, key: stored.key, type: details.root.t, size: details.root.l.reduce((sum, link) => sum + link.s, 0)};71+ };72+73+ async function storeFile(file, signal, progress) {74+ if (file.size > MAX_FILE_BYTES) throw Error("Files must be at most 256 MiB in the browser workspace.");75+ const chunks = [];76+ for (let offset = 0; offset < file.size || offset === 0; offset += codec().CHUNK_SIZE) {77+ checkAbort(signal);78+ const plain = new Uint8Array(await file.slice(offset, offset + codec().CHUNK_SIZE).arrayBuffer());79+ const stored = await storeEncrypted(plain, "application/octet-stream", signal);80+ chunks.push({...stored, size: plain.length});81+ progress?.(plain.length);82+ if (file.size === 0) break;83+ }84+ if (chunks.length === 1) return {...chunks[0], type: 0};85+ return rootReference(await codec().buildFile(chunks, {store: manifestStore(signal), returnDetails: true}));86+ }87+88+ async function storeDirectory(directory, signal, progress) {89+ const entries = [];90+ for (const [name, file] of directory.files) {91+ const stored = await storeFile(file, signal, progress);92+ entries.push({...stored, name, metadata: {type: file.type || "application/octet-stream"}});93+ }94+ for (const [name, child] of directory.directories) {95+ const stored = await storeDirectory(child, signal, progress);96+ entries.push({...stored, name});97+ }98+ return rootReference(await codec().buildDirectory(entries, {store: manifestStore(signal), returnDetails: true}));99+ }100+101+ const shareURL = (reference, name, type) => {102+ const url = new URL(tiny.localPath("/file"), location.href);103+ url.searchParams.set("hash", reference.hash);104+ url.hash = new URLSearchParams({manifest: reference.hash, key: hex(reference.key), node: String(reference.type), name, type: type || "application/octet-stream"}).toString();105+ return url.href;106+ };107+108+ class Workspace extends HTMLElement {109+ connectedCallback() {110+ if (this.bound) return;111+ this.bound = true;112+ 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>';113+ this.out = this.querySelector("output");114+ for (const form of this.querySelectorAll("form")) form.addEventListener("submit", event => {115+ event.preventDefault();116+ this.run(form).catch(error => this.say(error.message, true));117+ });118+ this.querySelector("[data-cancel]").addEventListener("click", () => this.controller?.abort());119+ this.querySelector("[data-retry]").addEventListener("click", () => this.run().catch(error => this.say(error.message, true)));120+ }121+ disconnectedCallback() { this.controller?.abort(); }122+ say(message, error = false) {123+ this.out.textContent = message;124+ if (error) this.out.dataset.error = "";125+ else delete this.out.dataset.error;126+ }127+ async run(form) {128+ if (this.busy) return;129+ if (form) {130+ const folder = form.elements.namedItem("folder");131+ const input = folder || form.elements.namedItem("file");132+ this.selection = {files: [...input.files], folder: Boolean(folder)};133+ }134+ if (!this.selection?.files.length) throw Error("Choose a file or folder first.");135+ this.busy = true;136+ this.controller = new AbortController();137+ this.querySelector("[data-cancel]").disabled = false;138+ this.querySelector("[data-retry]").disabled = true;139+ let completed = false;140+ try {141+ let reference, name, type;142+ let sent = 0;143+ const progress = size => { sent += size; this.say("Stored " + sent.toLocaleString() + " bytes. Encrypting the remaining content…"); };144+ this.say("Encrypting selected content…");145+ if (this.selection.folder) {146+ const selected = selectionTree(this.selection.files);147+ name = selected.name;148+ reference = await storeDirectory(selected.root, this.controller.signal, progress);149+ } else {150+ const file = this.selection.files[0];151+ name = file.name; type = file.type;152+ reference = await storeFile(file, this.controller.signal, progress);153+ }154+ checkAbort(this.controller.signal);155+ const url = shareURL(reference, name, type);156+ this.querySelector("[data-tree-share]").value = url;157+ const open = this.querySelector("[data-open]");158+ open.href = url; open.hidden = false;159+ this.say("Stored. Keep the complete share link to decrypt and browse this content.");160+ completed = true;161+ return url;162+ } finally {163+ this.busy = false;164+ this.querySelector("[data-cancel]").disabled = true;165+ this.querySelector("[data-retry]").disabled = completed;166+ if (completed) this.selection = null;167+ }168+ }169+ }170+171+ async function fetchBlob(hash, signal) {172+ fromHex(hash);173+ const response = await fetch(tiny.localPath("/files/raw?hash=" + hash), {signal});174+ if (!response.ok) throw Error("Download failed (" + response.status + ").");175+ if (Number(response.headers.get("Content-Length")) > MAX_FETCH_BYTES) throw Error("Linked blob exceeds the browser fetch limit.");176+ const reader = response.body?.getReader();177+ if (!reader) {178+ const bytes = new Uint8Array(await response.arrayBuffer());179+ if (bytes.length > MAX_FETCH_BYTES) throw Error("Linked blob exceeds the browser fetch limit.");180+ return bytes;181+ }182+ const parts = [];183+ let size = 0;184+ try {185+ for (;;) {186+ const {value, done} = await reader.read();187+ if (done) break;188+ size += value.length;189+ if (size > MAX_FETCH_BYTES) { await reader.cancel(); throw Error("Linked blob exceeds the browser fetch limit."); }190+ parts.push(value);191+ }192+ } finally { reader.releaseLock(); }193+ const bytes = new Uint8Array(size);194+ let offset = 0;195+ for (const part of parts) { bytes.set(part, offset); offset += part.length; }196+ return bytes;197+ }198+199+ async function plaintext(reference, signal) {200+ const hash = hex(reference.h);201+ const raw = await fetchBlob(hash, signal);202+ if (hex(await codec().sha256(raw)) !== hash) throw Error("Blob hash mismatch.");203+ return reference.k ? TinyBlossomEncryption.decryptCHK(raw, hex(reference.k), hash) : raw;204+ }205+ const decrypt = (raw, link) => TinyBlossomEncryption.decryptCHK(raw, hex(link.k), hex(link.h));206+207+ class Root extends HTMLElement {208+ connectedCallback() {209+ if (this.bound) return;210+ this.bound = true;211+ const params = new URLSearchParams(location.hash.slice(1));212+ if (!params.has("manifest") && this.getAttribute("type") !== directoryType) { this.hidden = true; return; }213+ this.hidden = false;214+ this.load().catch(error => this.fail(error.message));215+ }216+ disconnectedCallback() {217+ this.controller?.abort();218+ if (this.downloadURL) URL.revokeObjectURL(this.downloadURL);219+ }220+ fail(message) {221+ const error = element("p", "Content unavailable: " + message);222+ error.setAttribute("role", "alert");223+ this.replaceChildren(error);224+ }225+ async load() {226+ this.controller?.abort();227+ this.controller = new AbortController();228+ const params = new URLSearchParams(location.hash.slice(1));229+ const reference = {h: fromHex(params.get("manifest") || this.getAttribute("hash"))};230+ if (params.has("key")) reference.k = fromHex(params.get("key"));231+ const type = params.has("node") ? Number(params.get("node")) : 2;232+ if (![0, 1, 2, 3].includes(type)) throw Error("Unsupported manifest type.");233+ const data = await plaintext(reference, this.controller.signal);234+ const heading = element("h2", params.get("name") || "Stored content");235+ this.replaceChildren(heading);236+ if (type === 0) { this.offerDownload(data, params.get("name") || "file", params.get("type")); return; }237+ const root = codec().decodeManifest(data);238+ if (root.t !== type) throw Error("Manifest type does not match its reference.");239+ if (type === 1) {240+ const button = element("button", "Download decrypted file");241+ button.type = "button";242+ 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)));243+ this.append(button); return;244+ }245+ const entries = await codec().resolveDirectory(root, (hash) => fetchBlob(hash, this.controller.signal), {decrypt, maxDepth: MAX_DEPTH, maxEntries: MAX_FILES, maxBytes: 64 * 1024 * 1024});246+ const list = element("ul");247+ if (!entries.length) this.append(element("p", "This folder is empty."));248+ for (const link of entries) {249+ const item = element("li");250+ if (link.t === 2 || link.t === 3) {251+ const open = element("a", link.n + "/");252+ const url = new URL(tiny.localPath("/file"), location.href);253+ url.searchParams.set("hash", hex(link.h));254+ const fragment = new URLSearchParams({manifest: hex(link.h), node: String(link.t), name: link.n});255+ if (link.k) fragment.set("key", hex(link.k));256+ url.hash = fragment.toString(); open.href = url.href;257+ item.append(open);258+ } else {259+ const button = element("button", link.n + " (" + link.s.toLocaleString() + " bytes)");260+ button.type = "button";261+ button.addEventListener("click", () => this.download(link).catch(error => this.fail(error.message)));262+ item.append(button);263+ }264+ list.append(item);265+ }266+ this.append(list);267+ this.entries = entries;268+ }269+ async download(link) {270+ let data;271+ if (link.t === 0) data = await plaintext(link, this.controller.signal);272+ else if (link.t === 1) {273+ const manifest = codec().decodeManifest(await plaintext(link, this.controller.signal));274+ data = await codec().readFile(manifest, hash => fetchBlob(hash, this.controller.signal), {decrypt, maxDepth: MAX_DEPTH, maxBytes: MAX_FILE_BYTES});275+ } else throw Error("Unsupported file link.");276+ if (data.length !== link.s) throw Error("File size does not match its directory entry.");277+ this.offerDownload(data, link.n, link.m?.type);278+ return data;279+ }280+ offerDownload(data, name, type) {281+ if (this.downloadURL) URL.revokeObjectURL(this.downloadURL);282+ this.downloadURL = URL.createObjectURL(new Blob([data], {type: type || "application/octet-stream"}));283+ const link = element("a", "Save " + name);284+ link.href = this.downloadURL; link.download = name;285+ this.append(link);286+ link.click();287+ }288+ }289+ customElements.define("file-workspace", Workspace);290+ customElements.define("file-workspace-root", Root);291+})();
M internal/webui/page.html +5 -0
M internal/webui/signer.js +1 -1
@@ -1,5 +1,5 @@
11 "use strict";2-(()=>{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))};})();2+(()=>{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=!0){return gt(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 Ut(U,t.endo?Math.ceil(W/2):W);return U.BASE.precompute(8),U}function ko(e){return Uint8Array.of(e?2:3)}function Lo(e,t){return{secretKey:t.BYTES,publicKey:1+e.BYTES,publicKeyUncompressed:1+2*e.BYTES,publicKeyHasPrefix:!0,signature:2*t.BYTES}}function Gi(e,t={}){let{Fn:n}=e,r=t.randomBytes||Ge,o=Object.assign(Lo(e.Fp,n),{seed:Rn(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 Ot(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(!yt(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=Pt(a,c);return Object.freeze({getPublicKey:c,getSharedSecret:f,keygen:d,Point:e,utils:h,lengths:o})}function Co(e,t,n={}){Rt(t),wt(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)=>In(t,b,g)),{Fp:s,Fn:i}=e,{ORDER:a,BITS:c}=i,{keygen:l,getPublicKey:f,getSharedSecret:h,utils:d,lengths:p}=Gi(e,n),y={prehash:!0,lowS:typeof n.lowS=="boolean"?n.lowS:!0,format:"compact",extraEntropy:!1},m=a*Ro<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){On(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(ko((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(On(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=mt(c);function j(b){return io("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}=Hn(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 zr=(Y.x===X?0:2)|Number(Y.y&st),Zr=ie;return S&&w(ie)&&(Zr=i.neg(ie),zr^=1),new P(X,Zr,m?void 0:zr)}return{seed:H,k2sig:q}}function M(b,g,E={}){let{seed:S,k2sig:B}=W(b,g,E);return ao(t.outputLen,i.BYTES,o)(S,B).toBytes(E.format)}function C(b,g,E,S={}){let{lowS:B,prehash:v,format:R}=Hn(S,y);if(E=N(E,void 0,"publicKey"),g=U(g,v),!yt(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}=Hn(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 $t={p:BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),n:BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),h:BigInt(1),a:BigInt(0),b:BigInt(7),Gx:BigInt("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),Gy:BigInt("0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")},Ki={beta:BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"),basises:[[BigInt("0x3086d221a7d46bcde86c90e49284eb15"),-BigInt("0xe4437ed6010e88286f547fa90abfe4c3")],[BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"),BigInt("0x3086d221a7d46bcde86c90e49284eb15")]]},Fi=BigInt(0),Pn=BigInt(2);function ji(e){let t=$t.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,Pn,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,Pn,t);if(!qt.eql(qt.sqr(V),e))throw new Error("Cannot find square root");return V}var qt=rt($t.p,{sqrt:ji}),je=_o($t,{Fp:qt,endo:Ki}),ze=Co(je,Lt),Io={};function Dt(e,...t){let n=Io[e];if(n===void 0){let r=Lt(so(e));n=ce(r,r),Io[e]=n}return Lt(ce(n,...t))}var Mn=e=>e.toBytes(!0).slice(1),qn=e=>e%Pn===Fi;function Nn(e){let{Fn:t,BASE:n}=je,r=t.fromBytes(e),o=n.multiply(r);return{scalar:qn(o.y)?r:t.neg(r),bytes:Mn(o)}}function Oo(e){let t=qt;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);qn(o)||(o=t.neg(o));let s=je.fromAffine({x:e,y:o});return s.assertValidity(),s}var vt=Ue;function Uo(...e){return je.Fn.create(vt(Dt("BIP0340/challenge",...e)))}function Ho(e){return Nn(e).bytes}function zi(e,t,n=Ge(32)){let{Fn:r}=je,o=N(e,void 0,"message"),{bytes:s,scalar:i}=Nn(t),a=N(n,32,"auxRand"),c=r.toBytes(i^vt(Dt("BIP0340/aux",a))),l=Dt("BIP0340/nonce",c,s,o),{bytes:f,scalar:h}=Nn(l),d=Uo(f,s,o),p=new Uint8Array(64);if(p.set(f,0),p.set(r.toBytes(r.create(h+d*i)),32),!Po(p,o,s))throw new Error("sign: Invalid signature produced");return p}function Po(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=Oo(vt(c)),f=vt(i.subarray(0,32));if(!r.isValidNot0(f))return!1;let h=vt(i.subarray(32,64));if(!o.isValidNot0(h))return!1;let d=Uo(o.toBytes(f),Mn(l),a),p=s.multiplyUnsafe(h).add(l.multiplyUnsafe(o.neg(d))),{x:y,y:m}=p.toAffine();return!(p.is0()||!qn(m)||y!==f)}catch{return!1}}var he=(()=>{let n=(r=Ge(48))=>Ot(r,$t.n);return{keygen:Pt(n,Ho),getPublicKey:Ho,sign:zi,verify:Po,Point:je,utils:{randomSecretKey:n,taggedHash:Dt,lift_x:Oo,pointToBytes:Mn},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 Wt(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 Et(e){if(typeof e!="function"||typeof e.create!="function")throw new Error("Hash must wrapped by utils.createHasher");Wt(e.outputLen),Wt(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 Mo(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 Vt(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}function we(e,t){return e<<32-t|e>>>t}var qo=typeof Uint8Array.from([]).toHex=="function"&&typeof Uint8Array.fromHex=="function",Ji=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));function D(e){if(ve(e),qo)return e.toHex();let t="";for(let n=0;n<e.length;n++)t+=Ji[e[n]];return t}var Be={_0:48,_9:57,A:65,F:70,a:97,f:102};function No(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(qo)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=No(e.charCodeAt(s)),a=No(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 Do(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 $o=e=>({oid:Uint8Array.from([6,9,96,134,72,1,101,3,4,2,e])});function Wo(e,t,n){return e&t^~e&n}function Vo(e,t,n){return e&t^e&n^t&n}var Gt=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=Vt(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=Vt(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),Mo(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=Vt(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 Xi=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),Dn=class extends Gt{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+Wo(a,c,l)+Xi[h]+Ne[h]|0,m=(we(r,2)^we(r,13)^we(r,22))+Vo(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)}},$n=class extends Dn{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=Do(()=>new $n,$o(1));function Kn(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function Yi(e){if(!Kn(e))throw new Error("Uint8Array expected")}function jo(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 Qi(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 Fn(e){if(!Number.isSafeInteger(e))throw new Error(`invalid integer: ${e}`)}function Wn(e){if(!Array.isArray(e))throw new Error("array expected")}function Ft(e,t){if(!jo(!0,t))throw new Error(`${e}: array of strings expected`)}function zo(e,t){if(!jo(!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 Jo(e){let t=typeof e=="string"?e.split(""):e,n=t.length;Ft("alphabet",t);let r=new Map(t.map((o,s)=>[o,s]));return{encode:o=>(Wn(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=>(Wn(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 Xo(e=""){return Ze("join",e),{encode:t=>(Ft("join.decode",t),t.join(e)),decode:t=>(Ze("join.decode",t),t.split(e))}}function ea(e,t="="){return Fn(e),Ze("padding",t),{encode(n){for(Ft("padding.encode",n);n.length*e%8;)n.push(t);return n},decode(n){Ft("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 Yo=(e,t)=>t===0?e:Yo(t,e%t),jt=(e,t)=>e+(t-Yo(e,t)),Kt=(()=>{let e=[];for(let t=0;t<40;t++)e.push(2**t);return e})();function Vn(e,t,n,r){if(Wn(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(jt(t,n)>32)throw new Error(`convertRadix2: carry overflow from=${t} to=${n} carryBits=${jt(t,n)}`);let o=0,s=0,i=Kt[t],a=Kt[n]-1,c=[];for(let l of e){if(Fn(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=Kt[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 Qo(e,t=!1){if(Fn(e),e<=0||e>32)throw new Error("radix2: bits should be in (0..32]");if(jt(8,e)>32||jt(e,8)>32)throw new Error("radix2: carry overflow");return{encode:n=>{if(!Kn(n))throw new Error("radix2.encode input should be Uint8Array");return Vn(Array.from(n),8,e,!t)},decode:n=>(zo("radix2.decode",n),Uint8Array.from(Vn(n,e,8,t)))}}function Go(e){return Qi(e),function(...t){try{return e.apply(null,t)}catch{}}}var ta=typeof Uint8Array.from([]).toBase64=="function"&&typeof Uint8Array.fromBase64=="function",na=(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=ta?{encode(e){return Yi(e),e.toBase64()},decode(e){return na(e,!1)}}:Zo(Qo(6),Jo("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),ea(6),Xo(""));var Gn=Zo(Jo("qpzry9x8gf2tvdw0s3jn54khce6mua7l"),Xo("")),Ko=[996825010,642813549,513874426,1027748829,705979059];function St(e){let t=e>>25,n=(e&33554431)<<5;for(let r=0;r<Ko.length;r++)(t>>r&1)===1&&(n^=Ko[r]);return n}function Fo(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=St(o)^i>>5}o=St(o);for(let s=0;s<r;s++)o=St(o)^e.charCodeAt(s)&31;for(let s of t)o=St(o)^s;for(let s=0;s<6;s++)o=St(o);return o^=n,Gn.encode(Vn([o%Kt[30]],30,5,!1))}function ra(e){let t=e==="bech32"?1:734539939,n=Qo(5),r=n.decode,o=n.encode,s=Go(r);function i(h,d,p=90){Ze("bech32.encode prefix",h),Kn(d)&&(d=Array.from(d)),zo("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=Fo(w,d,t);return`${w}1${Gn.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=Gn.decode(x).slice(0,-6),I=Fo(w,A,t);if(!x.endsWith(I))throw new Error(`Invalid checksum in ${h}: expected "${I}"`);return{prefix:w,words:A}}let c=Go(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=ra("bech32");function oa(e){return e instanceof Uint8Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint8Array"}function zt(e){if(typeof e!="boolean")throw new Error(`boolean expected, not ${e}`)}function At(e){if(!Number.isSafeInteger(e)||e<0)throw new Error("positive integer expected, got "+e)}function F(e,t,n=""){let r=oa(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 jn(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 es(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 ts(e){return new DataView(e.buffer,e.byteOffset,e.byteLength)}var sa=new Uint8Array(new Uint32Array([287454020]).buffer)[0]===68;function ns(e,t){return e.buffer===t.buffer&&e.byteOffset<t.byteOffset+t.byteLength&&t.byteOffset<e.byteOffset+e.byteLength}function zn(e,t){if(ns(e,t)&&e.byteOffset<t.byteOffset)throw new Error("complex overlap of input and output is not supported")}function rs(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 Tt=(e,t)=>{function n(r,...o){if(F(r,void 0,"key"),!sa)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){zt(n);let r=new Uint8Array(16),o=ts(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 aa=283;function ss(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 er(e){return e<<1^aa&-(e>>7)}function lt(e,t){let n=0;for(;t>0;t>>=1)n^=e&-(t&1),e=er(e);return n}var Yn=(()=>{let e=new Uint8Array(256);for(let n=0,r=1;n<256;n++,r^=er(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})(),ca=Yn.map((e,t)=>Yn.indexOf(t)),la=e=>e<<24|e>>>8,Jn=e=>e<<8|e>>>24;function is(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(Jn),o=r.map(Jn),s=o.map(Jn),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 tr=is(Yn,e=>lt(e,3)<<24|e<<16|e<<8|lt(e,2)),as=is(ca,e=>lt(e,11)<<24|lt(e,13)<<16|lt(e,9)<<8|lt(e,14)),ua=(()=>{let e=new Uint8Array(16);for(let t=0,n=1;t<16;t++,n=er(n))e[t]=n;return e})();function nr(e){F(e);let t=e.length;ss(e);let{sbox2:n}=tr,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(la(l))^ua[c/s-1]:s>6&&c%s===4&&(l=i(l)),a[c]=a[c-s]^l}return re(...r),a}function fa(e){let t=nr(e),n=t.slice(),r=t.length,{sbox2:o}=tr,{T0:s,T1:i,T2:a,T3:c}=as;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 Qn(e,t,n,r,o){let{sbox2:s,T01:i,T23:a}=tr,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 ha(e,t,n,r,o){let{sbox2:s,T01:i,T23:a}=as,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 da(e){if(F(e),e.length%ne!==0)throw new Error("aes-(cbc/ecb).decrypt ciphertext should consist of blocks with size "+ne)}function pa(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),zn(e,n);let i=ee(n);return{b:s,o:i,out:n}}function ya(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 ga(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 rr=Tt({blockSize:16,nonceLength:16},function(t,n,r={}){let o=!r.disablePadding;return{encrypt(s,i){let a=nr(t),{b:c,o:l,out:f}=pa(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}=Qn(a,y,m,w,x),l[A++]=y,l[A++]=m,l[A++]=w,l[A++]=x;if(o){let I=ga(s.subarray(A*4));y^=I[0],m^=I[1],w^=I[2],x^=I[3],{s0:y,s1:m,s2:w,s3:x}=Qn(a,y,m,w,x),l[A++]=y,l[A++]=m,l[A++]=w,l[A++]=x}return re(...d),f},decrypt(s,i){da(s);let a=fa(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)),zn(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}=ha(a,p,y,m,w);d[x++]=V^A,d[x++]=Z^I,d[x++]=j^P,d[x++]=U^Q}return re(...l),ya(i,o)}}});function ba(e){return e instanceof Uint32Array||ArrayBuffer.isView(e)&&e.constructor.name==="Uint32Array"}function Xn(e,t){if(F(t,16,"block"),!ba(e))throw new Error("_encryptBlock accepts result of expandKeyLE");let n=ee(t),{s0:r,s1:o,s2:s,s3:i}=Qn(e,n[0],n[1],n[2],n[3]);return n[0]=r,n[1]=o,n[2]=s,n[3]=i,t}function os(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 Jt=class{constructor(t){u(this,"buffer");u(this,"destroyed");u(this,"k1");u(this,"k2");u(this,"xk");F(t),ss(t),this.xk=nr(t),this.buffer=new Uint8Array(0),this.destroyed=!1;let n=new Uint8Array(ne);Xn(this.xk,n),this.k1=os(n),this.k2=os(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),Xn(this.xk,c)}return Zt(c,a),Xn(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))}},ma=(e,t)=>new Jt(e).update(t).digest();ma.create=e=>new Jt(e);var ls=e=>Uint8Array.from(e.split(""),t=>t.charCodeAt(0)),wa=ls("expand 16-byte k"),xa=ls("expand 32-byte k"),va=ee(wa),Ea=ee(xa);function k(e,t){return e<<t|e>>>32-t}function or(e){return e.byteOffset%4===0}var Xt=64,Sa=16,us=2**32-1,cs=Uint32Array.of();function Aa(e,t,n,r,o,s,i,a){let c=o.length,l=new Uint8Array(Xt),f=ee(l),h=or(o)&&or(s),d=h?ee(o):cs,p=h?ee(s):cs;for(let y=0;y<c;i++){if(e(t,n,r,f,i,a),i>=us)throw new Error("arx: counter overflow");let m=Math.min(Xt,c-y);if(h&&m===Xt){let w=y/4;if(y%4!==0)throw new Error("arx: invalid block position");for(let x=0,A;x<Sa;x++)A=w+x,p[A]=d[A]^f[x];y+=Xt;continue}for(let w=0,x;w<m;w++)x=y+w,s[x]=o[x]^l[w];y+=m}}function sr(e,t){let{allowShortKeys:n,extendNonceFn:r,counterLength:o,counterRight:s,rounds:i}=rs({allowShortKeys:!1,counterLength:8,counterRight:!1,rounds:20},t);if(typeof e!="function")throw new Error("core must be a function");return At(o),At(i),zt(s),zt(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"),At(h),h<0||h>=us)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=Ea;else if(y===16&&n)m=new Uint8Array(32),m.set(a),m.set(a,16),w=va,p.push(m);else throw F(a,32,"arx key"),new Error("invalid key size");or(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 Aa(e,w,x,I,l,f,h,i),re(...p),f}}function oe(e,t){return e[t++]&255|(e[t++]&255)<<8}var ir=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){jn(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){jn(this),es(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 Ta(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 fs=Ta(e=>new ir(e));function ps(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 Ba(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=sr(ps,{counterRight:!1,counterLength:4,allowShortKeys:!1}),Ra=sr(ps,{counterRight:!1,counterLength:8,extendNonceFn:Ba,allowShortKeys:!1});var _a=new Uint8Array(16),hs=(e,t)=>{e.update(t);let n=t.length%16;n&&e.update(_a.subarray(n))},ka=new Uint8Array(32);function ds(e,t,n,r,o){o!==void 0&&F(o,void 0,"AAD");let s=e(t,n,ka),i=Zn(r.length,o?o.length:0,!0),a=fs.create(s);o&&hs(a,o),hs(a,r),a.update(i);let c=a.digest();return re(s,i),c}var ys=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=ds(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=ds(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=Tt({blockSize:64,nonceLength:12,tagLength:16},ys(Ye)),W0=Tt({blockSize:64,nonceLength:24,tagLength:16},ys(Ra));var Yt=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(Et(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 Yt(e,t).update(n).digest();De.create=(e,t)=>new Yt(e,t);function Qt(e,t,n){return Et(e),n===void 0&&(n=new Uint8Array(e.outputLen)),De(e,n,t)}var ar=Uint8Array.of(0),gs=Uint8Array.of();function en(e,t,n,r=32){Et(e),Wt(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=gs: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++)ar[0]=f+1,c.update(f===0?gs:l).update(n).update(ar).digestInto(l),i.set(l,o*f),a._cloneInto(c);return a.destroy(),c.destroy(),Re(l,ar),i.slice(0,r)}var La=Object.defineProperty,G=(e,t)=>{for(var n in t)La(e,n,{get:t[n],enumerable:!0})},Ca={};G(Ca,{binarySearch:()=>pr,bytesToHex:()=>D,hexToBytes:()=>$,insertEventIntoAscendingList:()=>Ha,insertEventIntoDescendingList:()=>Ia,isHex32:()=>ue,mergeReverseSortedLists:()=>Oa,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 Ia(e,t){let[n,r]=pr(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 Ha(e,t){let[n,r]=pr(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 pr(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 Oa(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"),Ua=e=>e instanceof Object;function yr(e){if(!Ua(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 Pa=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=ft(n),n.sig=D(he.sign($(ft(n)),t)),n[ut]=!0,n}verifyEvent(e){if(typeof e[ut]=="boolean")return e[ut];try{let t=ft(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 Na(e){if(!yr(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 ft(e){let t=te(ye.encode(Na(e)));return D(t)}var an=new Pa,gr=an.generateSecretKey,Bt=an.getPublicKey,ge=an.finalizeEvent,tt=an.verifyEvent,Ma={};G(Ma,{AIEmbeddings:()=>Ic,AppCurationSet:()=>du,Application:()=>fu,AuthoredPodcasts:()=>Il,BadgeAward:()=>Fa,BadgeDefinition:()=>Ql,Bid:()=>ac,BidConfirmation:()=>cc,BlobsAuth:()=>Gl,BlockedRelaysList:()=>pl,BlossomServerList:()=>Rl,BookmarkList:()=>fl,Bookmarksets:()=>zl,Calendar:()=>Lu,CalendarEventRSVP:()=>Cu,CashuMintAnnouncement:()=>Wu,CashuWalletEvent:()=>Dl,CashuWalletHistory:()=>Gc,CashuWalletTokens:()=>Vc,ChannelCreation:()=>Bs,ChannelHideMessage:()=>ks,ChannelMessage:()=>_s,ChannelMetadata:()=>Rs,ChannelMuteUser:()=>Ls,ChatMessage:()=>ja,Chess:()=>oc,ClassifiedListing:()=>wu,ClientAuth:()=>Cs,CodeSnippet:()=>bc,CoinjoinPool:()=>Uc,Comment:()=>hc,CommunitiesList:()=>hl,CommunityDefinition:()=>Mu,CommunityPostApproval:()=>Mc,ConferenceEvent:()=>gu,Contacts:()=>Va,CreateOrUpdateProduct:()=>nu,CreateOrUpdateStall:()=>tu,CuratedVideoSets:()=>Jl,Curationsets:()=>Zl,Date:()=>_u,DecoupledEncryptionKeyDistribution:()=>Nc,DecoupledKeyAnnouncement:()=>Al,DecoupledKeyClientAnnouncement:()=>Pc,DirectMessageRelaysList:()=>Tl,DraftClassifiedListing:()=>xu,DraftEvent:()=>Tu,DraftLong:()=>iu,Emojisets:()=>au,EncryptedDirectMessage:()=>Ga,EventDeletion:()=>Ka,FavoriteFollowSets:()=>El,FavoritePodcasts:()=>Bl,FavoriteRelays:()=>bl,FedimintAnnouncement:()=>Vu,Feed:()=>Ru,FileMessage:()=>Xa,FileMetadata:()=>uc,FileServerPreference:()=>_l,Followsets:()=>Kl,ForumThread:()=>Za,GenericRepost:()=>vr,Genericlists:()=>Fl,GeocacheListing:()=>Du,GeocacheLog:()=>Kc,GeocacheLogEntry:()=>$u,GeocacheProofOfFind:()=>Fc,GiftWrap:()=>on,GitPullRequest:()=>wc,GitPullRequestUpdate:()=>xc,GoodWikiAuthorList:()=>kl,GoodWikiRelayList:()=>Ll,GroupMetadata:()=>Ku,HTTPAuth:()=>Er,Handlerinformation:()=>Ou,Handlerrecommendation:()=>Hu,Highlights:()=>al,InteractiveRoom:()=>yu,InterestsList:()=>wl,Interestsets:()=>eu,Issue:()=>vc,JobFeedback:()=>$c,JobRequest:()=>qc,JobResult:()=>Dc,Label:()=>Lc,LegacyNsiteFile:()=>Pu,LightningPubRPC:()=>$l,LinkSet:()=>Bu,LiveChatMessage:()=>gc,LiveEvent:()=>pu,LongFormArticle:()=>su,MarketplaceUI:()=>ru,MediaFollows:()=>vl,MediaStarterPacks:()=>Xu,MergeRequests:()=>sc,Metadata:()=>$a,ModularArticleContent:()=>lu,ModularArticleHeader:()=>cu,MuteSets:()=>Xl,Mutelist:()=>cl,NWCWalletInfo:()=>Ml,NWCWalletRequest:()=>Is,NWCWalletResponse:()=>Wl,NormalVideo:()=>ec,NostrConnect:()=>Vl,NsiteNamed:()=>qu,NsiteRoot:()=>ql,NutZap:()=>rl,NutZapInfo:()=>xl,OpenTimestamps:()=>lc,Patch:()=>mc,PeerToPeerOrderEvents:()=>Gu,Photo:()=>Qa,Pinlist:()=>ll,PodcastEpisode:()=>rc,PodcastMetadata:()=>Cl,Poll:()=>fc,PollResponse:()=>ic,PrivateDirectMessage:()=>Ts,PrivateEventRelayList:()=>ml,ProblemTracker:()=>Rc,ProductSoldAsAuction:()=>ou,ProfileBadges:()=>Yl,ProxyAnnouncement:()=>Pl,PublicChatsList:()=>dl,PublicMessage:()=>nc,Reaction:()=>xr,ReactionToWebsite:()=>Ya,RecommendRelay:()=>Wa,Redirects:()=>Au,RelayDiscovery:()=>hu,RelayList:()=>ul,RelayMonitorAnnouncement:()=>Hl,RelayReview:()=>Iu,RelayReviews:()=>Cc,Relaysets:()=>jl,ReleaseArtifactSets:()=>uu,Reply:()=>Ec,Report:()=>_c,Reporting:()=>kc,RepositoryAnnouncement:()=>vu,RepositoryState:()=>Eu,Repost:()=>wr,ReservedCashuWalletTokens:()=>Wc,RoomPresence:()=>Ol,Scroll:()=>pc,Seal:()=>rn,SearchRelaysList:()=>yl,ShortTextNote:()=>As,ShortVideo:()=>tc,SimpleGroupAdmins:()=>Fu,SimpleGroupCreateGroup:()=>Xc,SimpleGroupCreateInvite:()=>Qc,SimpleGroupDeleteEvent:()=>Jc,SimpleGroupDeleteGroup:()=>Yc,SimpleGroupEditMetadata:()=>Zc,SimpleGroupJoinRequest:()=>el,SimpleGroupLeaveRequest:()=>tl,SimpleGroupList:()=>gl,SimpleGroupLiveKitParticipants:()=>Zu,SimpleGroupMembers:()=>ju,SimpleGroupPutUser:()=>jc,SimpleGroupRemoveUser:()=>zc,SimpleGroupReply:()=>Ja,SimpleGroupRoles:()=>zu,SimpleGroupThreadedReply:()=>za,SlideSet:()=>mu,SoftwareApplication:()=>Uu,StarterPacks:()=>Ju,StatusApplied:()=>Ac,StatusClosed:()=>Tc,StatusDraft:()=>Bc,StatusOpen:()=>Sc,TidalLogin:()=>ol,Time:()=>ku,Torrent:()=>Hc,TorrentComment:()=>Oc,TransportMethodAnnouncement:()=>Nl,UserEmojiList:()=>Sl,UserGraspList:()=>Ul,UserStatuses:()=>bu,VideoViewEvent:()=>Nu,Voice:()=>dc,VoiceComment:()=>yc,WebBookmarks:()=>Yu,WikiArticle:()=>Su,Zap:()=>il,ZapGoal:()=>nl,ZapRequest:()=>sl,classifyKind:()=>qa,isAddressableKind:()=>mr,isEphemeralKind:()=>Ss,isKind:()=>Da,isRegularKind:()=>Es,isReplaceableKind:()=>br});function Es(e){return e<1e4&&e!==0&&e!==3}function br(e){return e===0||e===3||1e4<=e&&e<2e4}function Ss(e){return 2e4<=e&&e<3e4}function mr(e){return 3e4<=e&&e<4e4}function qa(e){return Es(e)?"regular":br(e)?"replaceable":Ss(e)?"ephemeral":mr(e)?"parameterized":"unknown"}function Da(e,t){let n=t instanceof Array?t:[t];return yr(e)&&n.includes(e.kind)||!1}var $a=0,As=1,Wa=2,Va=3,Ga=4,Ka=5,wr=6,xr=7,Fa=8,ja=9,za=10,Za=11,Ja=12,rn=13,Ts=14,Xa=15,vr=16,Ya=17,Qa=20,ec=21,tc=22,nc=24,Bs=40,Rs=41,_s=42,ks=43,Ls=44,rc=54,oc=64,sc=818,ic=1018,ac=1021,cc=1022,lc=1040,on=1059,uc=1063,fc=1068,hc=1111,dc=1222,pc=1227,yc=1244,gc=1311,bc=1337,mc=1617,wc=1618,xc=1619,vc=1621,Ec=1622,Sc=1630,Ac=1631,Tc=1632,Bc=1633,Rc=1971,_c=1984,kc=1984,Lc=1985,Cc=1986,Ic=1987,Hc=2003,Oc=2004,Uc=2022,Pc=4454,Nc=4455,Mc=4550,qc=5999,Dc=6999,$c=7e3,Wc=7374,Vc=7375,Gc=7376,Kc=7516,Fc=7517,jc=9e3,zc=9001,Zc=9002,Jc=9005,Xc=9007,Yc=9008,Qc=9009,el=9021,tl=9022,nl=9041,rl=9321,ol=9467,sl=9734,il=9735,al=9802,cl=1e4,ll=10001,ul=10002,fl=10003,hl=10004,dl=10005,pl=10006,yl=10007,gl=10009,bl=10012,ml=10013,wl=10015,xl=10019,vl=10020,El=10021,Sl=10030,Al=10044,Tl=10050,Bl=10054,Rl=10063,_l=10096,kl=10101,Ll=10102,Cl=10154,Il=10164,Hl=10166,Ol=10312,Ul=10317,Pl=10377,Nl=11111,Ml=13194,ql=15128,Dl=17375,$l=21e3,Cs=22242,Is=23194,Wl=23195,Vl=24133,Gl=24242,Er=27235,Kl=3e4,Fl=30001,jl=30002,zl=30003,Zl=30004,Jl=30005,Xl=30007,Yl=30008,Ql=30009,eu=30015,tu=30017,nu=30018,ru=30019,ou=30020,su=30023,iu=30024,au=30030,cu=30040,lu=30041,uu=30063,fu=30078,hu=30166,du=30267,pu=30311,yu=30312,gu=30313,bu=30315,mu=30388,wu=30402,xu=30403,vu=30617,Eu=30618,Su=30818,Au=30819,Tu=31234,Bu=31388,Ru=31890,_u=31922,ku=31923,Lu=31924,Cu=31925,Iu=31987,Hu=31989,Ou=31990,Uu=32267,Pu=34128,Nu=34237,Mu=34550,qu=35128,Du=37515,$u=37516,Wu=38172,Vu=38173,Gu=38383,Ku=39e3,Fu=39001,ju=39002,zu=39003,Zu=39004,Ju=39089,Xu=39092,Yu=39701;function Qu(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 ef(e,t){for(let n=0;n<e.length;n++)if(Qu(e[n],t))return!0;return!1}var tf={};G(tf,{getHex64:()=>cn,getInt:()=>Hs,getSubscriptionId:()=>Os,matchEventId:()=>nf,matchEventKind:()=>of,matchEventPubkey:()=>rf});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 Hs(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 Os(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 nf(e,t){return t===cn(e,"id")}function rf(e,t){return t===cn(e,"pubkey")}function of(e,t){return t===Hs(e,"kind")}var sf={};G(sf,{makeAuthEvent:()=>Us});function Us(e,t){return{kind:Cs,created_at:Math.floor(Date.now()/1e3),tags:[["relay",e],["challenge",t]],content:""}}var dr=class extends Error{constructor(e,t){super(`Tried to send message '${e} on a closed connection to ${t}.`),this.name="SendingOnClosedConnection"}},Ps=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 Ps(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 dr(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(Us(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 af(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=Os(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];ef(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 dr))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}}},af=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 dr))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)}},cf;try{cf=WebSocket}catch{}var Ie=256,lf=Ie*2,ep=new TextEncoder;function uf(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 ff(){return new Uint8Array(Ie)}function hf(e){if(e.length!==lf||!/^[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 df(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 pf(e,t){if(e.length===0&&(e=ff()),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 yf=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 Ps(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=uf(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=hf(l.hll);f&&(c=pf(c||new Uint8Array(0),f))}return c?{count:a,hll:df(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}},Ns;try{Ns=WebSocket}catch{}var Ms=class extends yf{constructor(e){super({verifyEvent:tt,websocketImplementation:Ns,maxWaitForConnection:3e3,...e})}},ln={};G(ln,{BECH32_REGEX:()=>qs,Bech32MaxSize:()=>Sr,NostrTypeGuard:()=>gf,decode:()=>un,decodeNostrURI:()=>mf,encodeBytes:()=>hn,naddrEncode:()=>Af,neventEncode:()=>Sf,noteEncode:()=>vf,nprofileEncode:()=>Ef,npubEncode:()=>xf,nsecEncode:()=>wf});var gf={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,qs=/[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/;function bf(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 mf(e){try{return e.startsWith("nostr:")&&(e=e.substring(6)),un(e)}catch{return{type:"invalid",data:null}}}function un(e){let{prefix:t,words:n}=Me.decode(e,Sr),r=new Uint8Array(Me.fromWords(n));switch(t){case"nprofile":{let o=cr(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=cr(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=cr(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 cr(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 wf(e){return hn("nsec",e)}function xf(e){return hn("npub",$(e))}function vf(e){return hn("note",$(e))}function fn(e,t){let n=Me.toWords(t);return Me.encode(e,n,Sr)}function hn(e,t){return fn(e,t)}function Ef(e){let t=Ar({0:[$(e.pubkey)],1:(e.relays||[]).map(n=>ye.encode(n))});return fn("nprofile",t)}function Sf(e){let t;e.kind!==void 0&&(t=bf(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 fn("nevent",n)}function Af(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 fn("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 Tf={};G(Tf,{decrypt:()=>Bf,encrypt:()=>Ds});function Ds(e,t,n){let r=e instanceof Uint8Array?e:$(e),o=ze.getSharedSecret(r,$("02"+t)),s=$s(o),i=Uint8Array.from(at(16)),a=ye.encode(n),c=rr(s,i).encrypt(a),l=le.encode(new Uint8Array(c)),f=le.encode(new Uint8Array(i.buffer));return`${l}?iv=${f}`}function Bf(e,t,n){let r=e instanceof Uint8Array?e:$(e),[o,s]=n.split("?iv="),i=ze.getSharedSecret(r,$("02"+t)),a=$s(i),c=le.decode(s),l=le.decode(o),f=rr(a,c).decrypt(l);return Ce.decode(f)}function $s(e){return e.slice(1,33)}var Rf={};G(Rf,{NIP05_REGEX:()=>Tr,isNip05:()=>_f,isValid:()=>Cf,queryProfile:()=>Ws,searchDomain:()=>Lf,useFetchImplementation:()=>kf});var Tr=/^(?:([\w.+-]+)@)?([\w_-]+(\.[\w_-]+)+)$/,_f=e=>Tr.test(e||""),dn;try{dn=fetch}catch{}function kf(e){dn=e}async function Lf(e,t=""){try{let n=`https://${e}/.well-known/nostr.json?name=${t}`,r=await dn(n,{redirect:"manual"});if(r.status!==200)throw Error("Wrong response code");return(await r.json()).names}catch{return{}}}async function Ws(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 dn(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 Cf(e,t){let n=await Ws(t);return n?n.pubkey===e:!1}var If={};G(If,{parse:()=>Hf});function Hf(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 Of={};G(Of,{fetchRelayInformation:()=>Pf,useFetchImplementation:()=>Uf});var Vs;try{Vs=fetch}catch{}function Uf(e){Vs=e}async function Pf(e){return await(await fetch(e.replace("ws://","http://").replace("wss://","https://"),{headers:{Accept:"application/nostr+json"}})).json()}var Nf={};G(Nf,{getPow:()=>Mf,minePow:()=>Df});function Mf(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 qf(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 Df(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(qf(i)>=t){r.id=D(i);break}}return r}var $f={};G($f,{unwrapEvent:()=>Xf,unwrapManyEvents:()=>Yf,wrapEvent:()=>ni,wrapManyEvents:()=>Jf});var Wf={};G(Wf,{createRumor:()=>Ys,createSeal:()=>Qs,createWrap:()=>ei,unwrapEvent:()=>Or,unwrapManyEvents:()=>ti,wrapEvent:()=>sn,wrapManyEvents:()=>zf});var Br={};G(Br,{decrypt:()=>Hr,encrypt:()=>Ir,getConversationKey:()=>Lr,v2:()=>Ff});var Rr=1,_r=4294967295,kr=65536;function Lr(e,t){let n=ze.getSharedSecret(e,$("02"+t)).subarray(1,33);return Qt(te,n,ye.encode("nip44-v2"))}function Gs(e,t){let n=en(te,e,t,76);return{chacha_key:n.subarray(0,32),chacha_nonce:n.subarray(32,44),hmac_key:n.subarray(44,76)}}function Cr(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<Rr||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<kr||e>_r)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 Ks(e){let t=ye.encode(e),n=t.length;if(n<Rr||n>_r)throw new Error("invalid plaintext size: must be between 1 and 4294967295 bytes");let r=n>=kr?de(new Uint8Array([0,0]),Gf(n)):Vf(n),o=new Uint8Array(Cr(n)-n);return de(r,t,o)}function Fs(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<kr)throw new Error("invalid padding");o=6}else r=n,o=2;let s=e.subarray(o,o+r);if(r<Rr||r>_r||s.length!==r||e.length!==o+Cr(r))throw new Error("invalid padding");return Ce.decode(s)}function js(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 Ir(e,t,n=at(32)){let{chacha_key:r,chacha_nonce:o,hmac_key:s}=Gs(t,n),i=Ks(e),a=Ye(r,o,i),c=js(s,a,n);return le.encode(de(new Uint8Array([2]),n,a,c))}function Hr(e,t){let{nonce:n,ciphertext:r,mac:o}=Kf(e),{chacha_key:s,chacha_nonce:i,hmac_key:a}=Gs(t,n),c=js(a,r,n);if(!Je(c,o))throw new Error("invalid MAC");let l=Ye(s,i,r);return Fs(l)}var Ff={utils:{getConversationKey:Lr,calcPaddedLen:Cr,pad:Ks,unpad:Fs},encrypt:Ir,decrypt:Hr},jf=2880*60,zs=()=>Math.round(Date.now()/1e3),Zs=()=>Math.round(zs()-Math.random()*jf),Js=(e,t)=>Lr(e,t),Xs=(e,t,n)=>Ir(JSON.stringify(e),Js(t,n)),bs=(e,t)=>JSON.parse(Hr(e.content,Js(t,e.pubkey)));function Ys(e,t){let n={created_at:zs(),content:"",tags:[],...e,pubkey:Bt(t)};return n.id=ft(n),n}function Qs(e,t,n){return ge({kind:rn,content:Xs(e,t,n),created_at:Zs(),tags:[]},t)}function ei(e,t){let n=gr();return ge({kind:on,content:Xs(e,n,t),created_at:Zs(),tags:[["p",t]]},n)}function sn(e,t,n){let r=Ys(e,t),o=Qs(r,t,n);return ei(o,n)}function zf(e,t,n){if(!n||n.length===0)throw new Error("At least one recipient is required.");let r=Bt(t),o=[sn(e,t,r)];return n.forEach(s=>{o.push(sn(e,t,s))}),o}function Or(e,t){if(e.kind!==on)throw new Error(`unexpected wrap kind ${e.kind}, expected ${on}`);let n=bs(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=bs(n,t);if(r.pubkey!==n.pubkey)throw new Error(`rumor pubkey ${r.pubkey} does not match seal pubkey ${n.pubkey}`);return r}function ti(e,t){let n=[];return e.forEach(r=>{try{n.push(Or(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:Ts,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 ni(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:Bt(e)},...t].map(i=>ni(e,i,n,r,o))}var Xf=Or,Yf=ti,Qf={};G(Qf,{finishRepostEvent:()=>eh,getRepostedEvent:()=>th,getRepostedEventPointer:()=>ri});function eh(e,t,n,r){let o,s=[...e.tags??[],["e",t.id,n],["p",t.pubkey]];return t.kind===As?o=wr:(o=vr,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 ri(e){if(![wr,vr].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=ri(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:()=>Ur,parse:()=>oh,test:()=>rh});var Ur=new RegExp(`nostr:(${qs.source})`);function rh(e){return typeof e=="string"&&new RegExp(`^${Ur.source}$`).test(e)}function oh(e){let t=e.match(new RegExp(`^${Ur.source}$`));if(!t)throw new Error(`Invalid Nostr URI: ${e}`);return{uri:t[0],value:t[1],decoded:un(t[1])}}var sh={};G(sh,{parse:()=>ah});function ms(e){if(e)return/^\d+$/.test(e)?parseInt(e,10):e}function oi(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 ws(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]?oi(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 oi(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 xs(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 lr(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=ws(o);s&&n.push({tagName:o[0],pointer:s});continue}if((o[0]==="e"||o[0]==="a"||o[0]==="i")&&o[1]){let s=ws(o);s&&r.push({tagName:o[0],pointer:s});continue}if(o[0]==="K"){t.rootKind=ms(o[1]);continue}if(o[0]==="k"){t.replyKind=ms(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=xs(n),t.reply=xs(r),lr(t.root,t.profiles),lr(t.reply,t.profiles),t.quotes.forEach(o=>lr(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:xr,tags:[...e.tags??[],...r,["e",t.id],["p",t.pubkey]],content:e.content??"+"},n)}function uh(e){if(e.kind!==xr)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 ur=/\W/m,vs=/[^\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(ur)){let a=e.slice(i+1,i+hh).match(ur),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(ur),c=a?s+60+a.index:n;try{let l,{data:f,type:h}=un(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(vs),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(vs),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:Bs,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:Rs,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:_s,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:ks,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:Ls,tags:[["p",e.pubkey_to_mute],...e.tags??[]],content:n,created_at:e.created_at},t)},xh={};G(xh,{EMOJI_SHORTCODE_REGEX:()=>si,matchAll:()=>vh,regex:()=>Pr,replaceAll:()=>Eh});var si=/:(\w+):/,Pr=()=>new RegExp(`\\B${si.source}\\B`,"g");function*vh(e){let t=e.matchAll(Pr());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(Pr(),(n,r)=>t({shortcode:n,name:r}))}var Sh={};G(Sh,{useFetchImplementation:()=>Ah,validateGithub:()=>Th});var Nr;try{Nr=fetch}catch{}function Ah(e){Nr=e}async function Th(e,t,n){try{return await(await Nr(`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=Ds(t,e,JSON.stringify({method:"pay_invoice",params:{invoice:n}})),s={kind:Is,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 Mr;try{Mr=fetch}catch{}function Ih(e){Mr=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 Mr(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]),br(e.event.kind)){let n=["a",`${e.event.kind}:${e.event.pubkey}:`];t.tags.push(n)}else if(mr(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(!yr(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:()=>ai,NegentropyStorageVector:()=>$h,NegentropySync:()=>Wh});var fr=97,ht=32,ii=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 tn(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(ht)}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(ht);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,ii)}},$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!==ht)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(hr);for(let e=1;e<this.items.length;e++)if(hr(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=>hr(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}},ai=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([fr])),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([fr]));let s=qh(r);if(s<96||s>111)throw Error("invalid negentropy protocol version byte");if(s!==fr)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=tn(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,ii),x=this.storage.fingerprint(y,m);ci(w,x)!==0?(h(),this.splitRange(y,m,d,f)):l=!0}else if(p===Qe.IdList){let w=tn(r),x={};for(let A=0;A<w;A++){let I=nn(r,ht);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=tn(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=tn(e);if(n>ht)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<ht&&r[s]===o[s];s++)n++;return this._bound(t.timestamp,t.id.subarray(0,n+1))}}};function ci(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 hr(e,t){return e.timestamp===t.timestamp?ci(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 ai(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:()=>qr,unpackEventFromToken:()=>ui,validateEvent:()=>gi,validateEventKind:()=>hi,validateEventMethodTag:()=>pi,validateEventPayloadTag:()=>yi,validateEventTimestamp:()=>fi,validateEventUrlTag:()=>di,validateToken:()=>Kh});var li="Nostr ";async function Gh(e,t,n,r=!1,o){let s={kind:Er,tags:[["u",e],["method",t]],created_at:Math.round(new Date().getTime()/1e3),content:""};o&&s.tags.push(["payload",qr(o)]);let i=await n(s);return(r?li:"")+le.encode(ye.encode(JSON.stringify(i)))}async function Kh(e,t,n){let r=await ui(e).catch(s=>{throw s});return await gi(r,t,n).catch(s=>{throw s})}async function ui(e){if(!e)throw new Error("Missing token");e=e.replace(li,"");let t=Ce.decode(le.decode(e));if(!t||t.length===0||!t.startsWith("{"))throw new Error("Invalid token");return JSON.parse(t)}function fi(e){return e.created_at?Math.abs(Math.round(new Date().getTime()/1e3)-e.created_at)<60:!1}function hi(e){return e.kind===Er}function di(e,t){let n=e.tags.find(r=>r[0]==="u");return n?n.length>0&&n[1]===t:!1}function pi(e,t){let n=e.tags.find(r=>r[0]==="method");return n?n.length>0&&n[1].toLowerCase()===t.toLowerCase():!1}function qr(e){let t=te(ye.encode(JSON.stringify(e)));return D(t)}function yi(e,t){let n=e.tags.find(o=>o[0]==="payload");if(!n)return!1;let r=qr(t);return n.length>0&&n[1]===r}async function gi(e,t,n,r){if(!tt(e))throw new Error("Invalid nostr event, signature invalid");if(!hi(e))throw new Error("Invalid nostr event, kind invalid");if(!fi(e))throw new Error("Invalid nostr event, created_at timestamp invalid");if(!di(e,t))throw new Error("Invalid nostr event, url tag invalid");if(!pi(e,n))throw new Error("Invalid nostr event, method tag invalid");if(r&&typeof r=="object"&&Object.keys(r).length>0&&!yi(e,r))throw new Error("Invalid nostr event, payload tag does not match request body hash");return!0}var Fh=new TextDecoder("utf-8"),Gr=new TextEncoder;function pt(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 dt=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=Dr(n),n.sig=D(he.sign($(Dr(n)),t)),n[dt]=!0,n}verifyEvent(e){if(typeof e[dt]=="boolean")return e[dt];try{let t=Dr(e);if(t!==e.id)return e[dt]=!1,!1;let n=he.verify($(e.sig),$(t),$(e.pubkey));return e[dt]=n,n}catch{return e[dt]=!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 Dr(e){let t=te(Gr.encode(Xh(e)));return D(t)}var yn=new Jh,qp=yn.generateSecretKey,bi=yn.getPublicKey,Yh=yn.finalizeEvent,wi=yn.verifyEvent,Kr=1,Fr=4294967295,jr=65536;function $r(e,t){let n=ze.getSharedSecret(e,$("02"+t)).subarray(1,33);return Qt(te,n,Gr.encode("nip44-v2"))}function xi(e,t){let n=en(te,e,t,76);return{chacha_key:n.subarray(0,32),chacha_nonce:n.subarray(32,44),hmac_key:n.subarray(44,76)}}function vi(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<Kr||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<jr||e>Fr)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=Gr.encode(e),n=t.length;if(n<Kr||n>Fr)throw new Error("invalid plaintext size: must be between 1 and 4294967295 bytes");let r=n>=jr?de(new Uint8Array([0,0]),ed(n)):Qh(n),o=new Uint8Array(vi(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<jr)throw new Error("invalid padding");o=6}else r=n,o=2;let s=e.subarray(o,o+r);if(r<Kr||r>Fr||s.length!==r||e.length!==o+vi(r))throw new Error("invalid padding");return Fh.decode(s)}function Ei(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}=xi(t,n),i=td(e),a=Ye(r,o,i),c=Ei(s,a,n);return le.encode(de(new Uint8Array([2]),n,a,c))}function mi(e,t){let{nonce:n,ciphertext:r,mac:o}=rd(e),{chacha_key:s,chacha_nonce:i,hmac_key:a}=xi(t,n),c=Ei(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,Wr=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 Vr=class extends Error{constructor(e,t){super(`Tried to send message '${e} on a closed connection to ${t}.`),this.name="SendingOnClosedConnection"}},Si=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=pt(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 Si(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 Vr(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 Vr))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 Vr))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=pt(e);let n=this.relays.get(e);if(n||(n=new Si(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(pt).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=pt(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=pt(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(pt).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}},Ai;try{Ai=WebSocket}catch{}var vd=class extends xd{constructor(e){super({verifyEvent:wi,websocketImplementation:Ai,maxWaitForConnection:3e3,...e})}},Ti;try{Ti=fetch}catch{}var Ed=/^bunker:\/\/([0-9a-f]{64})\??([?\/\w:.=&%-]*)$/;async function Bi(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 Ti(s,{redirect:"error"})).json(),a=i.names[r],c=i.nip46[a]||[];return{pubkey:a,relays:c,secret:null}}catch{return null}}function Ri(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 pn=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 pn(e,n);return r.conversationKey=$r(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 pn(e,n),a=bi(e);return new Promise((c,l)=>{let f=!1,h=i.pool.subscribe(o.searchParams.getAll("relay"),{kinds:[Wr],"#p":[a],limit:0},{onevent:async d=>{try{let p=$r(e,d.pubkey),y=mi(d.content,p);JSON.parse(y).result===s&&(h.close(),i.bp={pubkey:d.pubkey,relays:o.searchParams.getAll("relay"),secret:s},i.conversationKey=$r(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:[Wr],authors:[this.bp.pubkey],"#p":[bi(this.secretKey)],limit:0},{onevent:async r=>{let o=JSON.parse(mi(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:Wr,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(wi(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:gr,getPublicKey:Bt,finalizeEvent:ge,getEventHash:ft,verifyEvent:tt,nip44:Br,SimplePool:Ms,BunkerSigner:pn,parseBunkerInput:Bi,createNostrConnectURI:Ri,npubEncode:ln.npubEncode,decodeNpub:e=>{let t=ln.decode(e);if(t.type!=="npub")throw new Error("expected an npub");return t.data},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))};})();33 /*! Bundled license information:44 55 @noble/hashes/utils.js:
M internal/webui/style.css +13 -6
@@ -20,7 +20,7 @@ pre{white-space:pre-wrap;overflow-wrap:anywhere}
2020 img{max-width:100%}2121 2222 /* Selection: chrome is not selectable, content and values are. */23-#rail,#footer,#topbar,#panel h4,#panel label,#panel th,#rows th,#grid,#gridhead,#tree header small,#tree li>span,#preview header,button,summary,rpc-form label,signed-form label,publish-list label,nostr-event>header,diff-view caption small{user-select:none;-webkit-user-select:none}23+#rail,#footer,#topbar,#panel h4,#panel label,#panel th,#rows th,#grid,#gridhead,#tree header small,#tree li>span,#preview header,button,summary,rpc-form label,signed-form label,publish-list label,file-tools label,file-workspace label,nostr-event>header,diff-view caption small{user-select:none;-webkit-user-select:none}2424 2525 /* Shell: a table with three columns; each column scrolls on its own. */2626 #topbar{display:none}
@@ -76,6 +76,8 @@ img{max-width:100%}
7676 #rows th:last-child{text-align:right}7777 #rows td a{color:inherit}#rows td:first-child a{color:var(--accent)}7878 #pages{font:12px var(--mono)}79+#file-search{margin:0 0 14px;padding:0 0 8px;border-bottom:1px solid var(--line)}80+#file-actions{max-width:720px;margin:0 0 18px}7981 8082 /* Data tables inside content, including json-view results. */8183 scroll-box{display:block;overflow-x:auto;max-width:100%}
@@ -103,12 +105,17 @@ dl{margin:.5rem 0}dt{font-weight:600}dd{margin:0 0 .35rem 1rem}
103105 #readme code{font-size:12.5px}#readme ul,#readme ol{padding-left:20px}104106 105107 /* rpc-form, signed-form, publish-list: one signed call each. */106-rpc-form,signed-form,publish-list{display:block;border-bottom:1px solid var(--line);padding:10px 0}107-rpc-form label,signed-form label,publish-list label{display:inline-block;margin:0 10px 6px 0;vertical-align:top;font:13px var(--sans);color:var(--muted)}108-rpc-form label input,rpc-form label select,signed-form label input{display:block;margin-top:2px;font:13px var(--mono);min-width:200px}108+rpc-form,signed-form,publish-list,file-tools,file-workspace,file-workspace-root:not([hidden]){display:block;border-bottom:1px solid var(--line);padding:10px 0}109+file-tools,file-workspace,file-workspace-root{max-width:720px}110+file-tools h3,file-workspace h3{margin:0 0 4px}file-tools p,file-workspace p{margin:6px 0}111+rpc-form label,signed-form label,publish-list label,file-tools label,file-workspace label,#file-search label{display:inline-block;margin:0 10px 6px 0;vertical-align:top;font:13px var(--sans);color:var(--muted)}112+rpc-form label input,rpc-form label select,signed-form label input,file-tools label input,file-tools label select,file-workspace label input,#file-search label input{display:block;margin-top:2px;font:13px var(--mono);min-width:200px}113+file-tools label:has([data-share-url]),file-workspace label:has([data-tree-share]){display:block}file-tools input[data-share-url],file-workspace input[data-tree-share]{width:100%}109114 rpc-form label:has(textarea),publish-list label:has(textarea){display:block}110-rpc-form output,signed-form output,publish-list output{display:block;font:12px var(--mono);color:var(--muted);margin-top:4px}111-rpc-form output[data-error]{color:var(--alert)}115+rpc-form output,signed-form output,publish-list output,file-tools output,file-workspace output,file-workspace-root output{display:block;font:12px var(--mono);color:var(--muted);margin-top:4px;overflow-wrap:anywhere}116+rpc-form output[data-error],file-tools output[data-error],file-workspace output[data-error]{color:var(--alert)}117+file-workspace-root ul{list-style:none;margin:8px 0 0;padding:0 0 0 16px;border-left:1px solid var(--line)}file-workspace-root li{padding:3px 0}118+file-workspace-root button{background:transparent;border:0;padding:0;color:var(--accent);font:inherit;text-align:left}112119 #content>section>h3{border-bottom:0;margin-top:22px;font-size:15px}113120 114121 connect-list{display:block}connect-list #rows td{height:auto;padding:8px 10px;white-space:normal;vertical-align:middle}connect-list #rows td:first-child{width:150px}connect-list #rows td:nth-child(2){color:var(--muted)}connect-list #rows td:nth-child(2) b{color:var(--ink);font-weight:normal}connect-list #rows td:nth-child(3){width:110px}connect-list #rows td:last-child{width:190px;white-space:nowrap}connect-list button,connect-list select{font-size:12px}connect-list output{display:block;font:12px var(--mono);color:var(--muted);margin-top:4px}connect-list output[data-error]{color:var(--alert)}
M internal/webui/templates.go +16 -1
M package.json +2 -1
A scripts/blossom-encryption.test.mjs +58 -0
@@ -0,0 +1,58 @@
1+import assert from "node:assert/strict";2+import {webcrypto} from "node:crypto";3+import {readFile} from "node:fs/promises";4+import test from "node:test";5+import vm from "node:vm";6+7+const source = await readFile(new URL("../internal/webui/blossom-encryption.js", import.meta.url), "utf8");8+const sandbox = {crypto: webcrypto, TextEncoder, URL, URLSearchParams, Uint8Array, ArrayBuffer};9+sandbox.globalThis = sandbox;10+vm.runInNewContext(source, sandbox);11+const api = sandbox.TinyBlossomEncryption;12+const utf8 = value => new TextEncoder().encode(value);13+const hex = bytes => Buffer.from(bytes).toString("hex");14+15+test("matches BUD-15 empty plaintext vector", async () => {16+ const result = await api.encryptCHK(new Uint8Array());17+ assert.equal(result.key, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");18+ assert.equal(hex(result.ciphertext), "7cd161ae8406d82cdf553c1100d012db");19+ assert.equal(result.hash, "346c46e7cc6722c99efe7f7bc316d8f3ff5f025f1031bf94418ef4db891e04cd");20+ assert.deepEqual(await api.decryptCHK(result.ciphertext, result.key, result.hash), new Uint8Array());21+});22+23+test("matches BUD-15 hello vector", async () => {24+ const result = await api.encryptCHK(utf8("hello"));25+ assert.equal(result.key, "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824");26+ assert.equal(hex(result.ciphertext), "c65308d9c8649ff1c59820d0b3a030db34ad00f92d");27+ assert.equal(result.hash, "70b977414934faa6270f323f117d05dbcc412e9d7ba2354b4d0f88f60aad2461");28+ assert.deepEqual(await api.decryptCHK(result.ciphertext, result.key, result.hash), utf8("hello"));29+});30+31+test("rejects tampered ciphertext, hash, and key", async () => {32+ const result = await api.encryptCHK(utf8("private"));33+ const tampered = new Uint8Array(result.ciphertext);34+ tampered[0] ^= 1;35+ await assert.rejects(api.decryptCHK(tampered, result.key, result.hash), /ciphertext hash mismatch/);36+ await assert.rejects(api.decryptCHK(result.ciphertext, result.key, "0".repeat(64)), /ciphertext hash mismatch/);37+ const wrongKey = "f".repeat(64);38+ await assert.rejects(api.decryptCHK(result.ciphertext, wrongKey, result.hash), /CHK decryption failed|plaintext hash mismatch/);39+});40+41+test("creates and parses a CHK URI without altering the key", async () => {42+ const result = await api.encryptCHK(utf8("hello"));43+ const uri = api.createURI(result.hash, "txt", result.key);44+ assert.equal(uri, "blossom:" + result.hash + ".txt?enc=chk-v1&k=" + result.key);45+ const parsed = api.parseURI(uri);46+ assert.equal(parsed.hash, result.hash);47+ assert.equal(parsed.extension, "txt");48+ assert.equal(parsed.key, result.key);49+ assert.throws(() => api.parseURI("blossom:" + result.hash + "?enc=chk-v1&k=" + result.key.toUpperCase()), /lowercase hex key/);50+});51+52+test("derives a distinct key and zero-nonce ciphertext for each content", async () => {53+ const first = await api.encryptCHK(utf8("first"));54+ const second = await api.encryptCHK(utf8("second"));55+ assert.notEqual(first.key, second.key);56+ assert.notEqual(first.hash, second.hash);57+ assert.notDeepEqual(first.ciphertext, second.ciphertext);58+});
A scripts/blossom-manifests-review.test.mjs +92 -0
@@ -0,0 +1,92 @@
1+import assert from "node:assert/strict";2+import {readFile} from "node:fs/promises";3+import test from "node:test";4+import vm from "node:vm";5+6+const source = await readFile(new URL("../internal/webui/blossom-manifests.js", import.meta.url), "utf8");7+const sandbox = {TextEncoder, TextDecoder, Uint8Array, ArrayBuffer, crypto: (await import("node:crypto")).webcrypto};8+sandbox.globalThis = sandbox;9+vm.runInNewContext(source, sandbox);10+const api = sandbox.TinyBlossomManifests;11+const hash = value => value.repeat(64);12+const bytes = hex => Uint8Array.from(hex.match(/../g), value => parseInt(value, 16));13+14+test("rejects duplicate names split across directory fanout children", async () => {15+ const entries = Array.from({length: 173}, (_, i) => ({hash: hash("a"), name: `a${String(i).padStart(3, "0")}`, size: 1}));16+ entries.push({hash: hash("b"), name: "dup", size: 1}, {hash: hash("c"), name: "dup", size: 1});17+ await assert.rejects(api.buildDirectory(entries), /duplicate directory entry/);18+});19+20+test("decrypts encrypted file-manifest children before decoding", async () => {21+ const leaf = new TextEncoder().encode("ok");22+ const leafHash = api.hex(await api.sha256(leaf));23+ const child = {l: [{h: bytes(leafHash), s: leaf.length, t: 0}], t: 1};24+ const childBytes = api.encodeManifest(child);25+ const encrypted = Uint8Array.from(childBytes, value => value ^ 0xff);26+ const childHash = await api.hex(await api.sha256(encrypted));27+ const root = {l: [{h: bytes(childHash), k: new Uint8Array(32), s: 2, t: 1}], t: 1};28+ const result = await api.readFile(root, async (wantedHash) => {29+ if (wantedHash === childHash) return encrypted;30+ assert.equal(wantedHash, leafHash);31+ return leaf;32+ }, {decrypt: async value => {33+ assert.equal(api.hex(value), api.hex(encrypted));34+ return childBytes;35+ }});36+ assert.equal(result.length, 2);37+});38+39+test("decrypts encrypted directory-manifest children before decoding", async () => {40+ const leaf = new TextEncoder().encode("ok");41+ const leafHash = api.hex(await api.sha256(leaf));42+ const child = {l: [{h: bytes(leafHash), n: "a.txt", s: leaf.length, t: 0}], t: 2};43+ const childBytes = api.encodeManifest(child);44+ const encrypted = Uint8Array.from(childBytes, value => value ^ 0xff);45+ const childHash = await api.hex(await api.sha256(encrypted));46+ const root = {l: [{h: bytes(childHash), k: new Uint8Array(32), m: {count: 1, first: "a.txt", last: "a.txt"}, s: leaf.length, t: 2}], t: 3};47+ const result = await api.resolveDirectory(root, async wantedHash => {48+ assert.equal(wantedHash, childHash);49+ return encrypted;50+ }, {decrypt: async value => {51+ assert.equal(api.hex(value), api.hex(encrypted));52+ return childBytes;53+ }});54+ assert.equal(result[0].n, "a.txt");55+});56+57+test("matches the BUD-17 directory fanout vector", async () => {58+ const node = {l: [59+ {h: bytes("11".repeat(32)), m: {count: 2, first: "a.txt", last: "b.txt"}, s: 30, t: 2},60+ {h: bytes("22".repeat(32)), m: {count: 1, first: "c.txt", last: "c.txt"}, s: 40, t: 2}61+ ], t: 3};62+ assert.equal(await api.manifestHash(node), "6626ab03b5468f417d888fa25fa22b48f5bcb7dfafb88eef34c638d167afc0a3");63+});64+65+test("sorts and preserves non-ASCII names by UTF-8 byte order", async () => {66+ const node = await api.buildDirectory([67+ {hash: hash("a"), name: "é", size: 1},68+ {hash: hash("b"), name: "e\u0301", size: 1},69+ {hash: hash("c"), name: "😀", size: 1}70+ ]);71+ assert.deepEqual(node.l.map(link => link.n), ["e\u0301", "é", "😀"]);72+});73+74+test("honors zero traversal budgets", async () => {75+ const one = new TextEncoder().encode("x");76+ const oneHash = api.hex(await api.sha256(one));77+ const file = {l: [{h: bytes(oneHash), s: 1, t: 0}], t: 1};78+ await assert.rejects(api.readFile(file, async () => one, {maxManifests: 0}), /manifest count limit exceeded/);79+ await assert.rejects(api.readFile(file, async () => one, {maxBytes: 0}), /file byte limit exceeded/);80+ await assert.rejects(api.resolveDirectory({l: [], t: 3}, async () => new Uint8Array(), {maxManifests: 0}), /manifest count limit exceeded/);81+});82+83+test("bounds total directory fetches and permits encryption overhead separately", async () => {84+ const child = {l: [{h: bytes("aa".repeat(32)), n: "a", s: 2, t: 0}], t: 2};85+ const raw = api.encodeManifest(child), digest = api.hex(await api.sha256(raw));86+ const root = {l: [{h: bytes(digest), m: {count: 1, first: "a", last: "a"}, s: 2, t: 2}], t: 3};87+ await assert.rejects(api.resolveDirectory(root, async () => raw, {maxBytes: 1}), /byte limit/);88+ const ciphertext = new Uint8Array(18), hash = api.hex(await api.sha256(ciphertext));89+ const file = {l: [{h: bytes(hash), k: new Uint8Array(32), s: 2, t: 0}], t: 1};90+ assert.equal((await api.readFile(file, async () => ciphertext, {maxBytes: 2, decrypt: async () => new Uint8Array(2)})).length, 2);91+ await assert.rejects(api.readFile(file, async () => ciphertext, {maxBytes: 2, maxFetchedBytes: 1}), /byte limit/);92+});
A scripts/blossom-manifests.test.mjs +70 -0
@@ -0,0 +1,70 @@
1+import assert from "node:assert/strict";2+import {readFile} from "node:fs/promises";3+import test from "node:test";4+import vm from "node:vm";5+6+const source = await readFile(new URL("../internal/webui/blossom-manifests.js", import.meta.url), "utf8");7+const sandbox = {TextEncoder, TextDecoder, Uint8Array, ArrayBuffer, crypto: (await import("node:crypto")).webcrypto};8+sandbox.globalThis = sandbox;9+vm.runInNewContext(source, sandbox);10+const api = sandbox.TinyBlossomManifests;11+const bytes = hex => Uint8Array.from(hex.match(/../g), x => parseInt(x, 16));12+const hash = c => c.repeat(64);13+14+test("matches the BUD-16 empty and single-entry vectors", async () => {15+ const empty = {l: [], t: 2};16+ assert.equal(Buffer.from(api.encodeManifest(empty)).toString("hex"), "82a16c90a17402");17+ assert.equal(await api.manifestHash(empty), "0218ed9a4fbb0993757f17e5d08d089cb0c6ac851928ba1ba82d337d76c41c0c");18+ const one = {l: [{h: bytes("ab".repeat(32)), n: "test.txt", s: 100, t: 0}], t: 2};19+ assert.equal(await api.manifestHash(one), "16121fa792b3afc72ec8bfc1dc85060518b6adba1429973ecc12891165cbe67e");20+ const decoded = api.decodeManifest(api.encodeManifest(one));21+ assert.equal(decoded.t, 2);22+ assert.equal(decoded.l[0].n, "test.txt");23+ assert.equal(Buffer.from(decoded.l[0].h).toString("hex"), "ab".repeat(32));24+});25+26+test("matches the BUD-17 two-chunk vector and preserves chunk order", async () => {27+ const node = {l: [{h: bytes("aa".repeat(32)), s: 100, t: 0}, {h: bytes("bb".repeat(32)), s: 50, t: 0}], t: 1};28+ assert.equal(await api.manifestHash(node), "559b726c38295aa0ecbbaef43d438cc86dd63324a0c3e9426dc5f1d0285f483f");29+ const decoded = api.decodeManifest(api.encodeManifest(node));30+ assert.equal(decoded.t, 1);31+ assert.equal(JSON.stringify(decoded.l.map(x => [Buffer.from(x.h).toString("hex"), x.s, x.t])), JSON.stringify([["aa".repeat(32), 100, 0], ["bb".repeat(32), 50, 0]]));32+});33+34+test("canonicalizes directory names by UTF-8 bytes and builds file manifests", async () => {35+ const directory = await api.buildDirectory([36+ {hash: hash("a"), name: "z", size: 2}, {hash: hash("b"), name: "a", size: 1}37+ ]);38+ assert.deepEqual(directory.l.map(x => x.n), ["a", "z"]);39+ const details = await api.buildFile(Array.from({length: 175}, (_, i) => ({hash: hash((i % 10).toString()), size: 1})), {returnDetails: true});40+ assert.equal(details.root.t, 1);41+ assert.equal(details.root.l.length, 2);42+ assert.equal(details.manifests.length, 3);43+ assert.equal(details.root.l.reduce((n, x) => n + x.s, 0), 175);44+});45+46+test("builds typed directory fanout nodes with bounded child metadata", async () => {47+ const details = await api.buildDirectory(Array.from({length: 175}, (_, i) => ({hash: hash("a"), name: `file-${String(i).padStart(3, "0")}`, size: 1})), {returnDetails: true});48+ assert.equal(details.root.t, 3);49+ assert.equal(details.root.l.length, 2);50+ assert.equal(JSON.stringify(details.root.l[0].m), JSON.stringify({count: 174, first: "file-000", last: "file-173"}));51+ assert.equal(details.root.l[0].t, 2);52+});53+54+test("resolves fanout children only after hash and bound verification", async () => {55+ const child = {l: [{h: bytes("aa".repeat(32)), n: "a.txt", s: 1, t: 0}], t: 2};56+ const childHash = await api.manifestHash(child);57+ const root = {l: [{h: bytes(childHash), m: {count: 1, first: "a.txt", last: "a.txt"}, s: 1, t: 2}], t: 3};58+ const resolved = await api.resolveDirectory(root, async hash => hash === childHash ? api.encodeManifest(child) : new Uint8Array());59+ assert.equal(resolved.length, 1);60+ await assert.rejects(api.resolveDirectory(root, async () => api.encodeManifest({...child, l: []})), /manifest hash mismatch/);61+});62+63+test("rejects traversal, duplicate names, unknown types and malformed bytes", () => {64+ const link = {h: bytes("aa".repeat(32)), n: "ok", s: 1, t: 0};65+ assert.throws(() => api.encodeManifest({l: [{...link, n: "../secret"}], t: 2}), /invalid directory entry name/);66+ assert.throws(() => api.encodeManifest({l: [link, link], t: 2}), /duplicate directory entry/);67+ assert.throws(() => api.encodeManifest({l: [{...link, t: 9}], t: 2}), /unsupported link type/);68+ assert.throws(() => api.decodeManifest(Uint8Array.from([0x82, 0xa1, 0x6c])), /truncated/);69+ assert.throws(() => api.encodeManifest({l: [{...link, n: "b"}, {...link, n: "a"}], t: 2}), /canonical/);70+});
A scripts/blossom-upload.test.mjs +126 -0
@@ -0,0 +1,126 @@
1+import assert from "node:assert/strict";2+import {webcrypto} from "node:crypto";3+import {createServer} from "node:http";4+import {readFile} from "node:fs/promises";5+import test from "node:test";6+import vm from "node:vm";7+8+const source = await readFile(new URL("../internal/webui/blossom-upload.js", import.meta.url), "utf8");9+const sandbox = {crypto: webcrypto, Blob, ArrayBuffer, Uint8Array, AbortController, Map, setTimeout, clearTimeout, URL};10+sandbox.globalThis = sandbox;11+vm.runInNewContext(source, sandbox);12+const upload = sandbox.TinyBlossomUpload.upload;13+const digest = async bytes => Buffer.from(await webcrypto.subtle.digest("SHA-256", bytes)).toString("hex");14+const response = (status, headers = {}, body = null) => ({15+ status, ok: status >= 200 && status < 300,16+ headers: {get(name) { return headers[name.toLowerCase()] ?? null; }},17+ async json() { if (body === null) throw Error("no body"); return body; }18+});19+20+test("uses BUD-14 PATCH chunks and signs each chunk payload", async () => {21+ const bytes = new TextEncoder().encode("abcdefghij");22+ const hash = await digest(bytes);23+ const calls = [];24+ const result = await upload(bytes, {25+ url: "https://blossom.example/upload",26+ hash,27+ type: "text/plain",28+ chunkSize: 4,29+ fetch: async (url, init) => {30+ calls.push({url, init});31+ return calls.length === 1 ? response(204, {allow: "GET, PUT, PATCH"}) :32+ calls.length === 4 ? response(201, {}, {sha256: hash, size: bytes.length}) : response(204);33+ },34+ authorize: async (url, method, body) => "Nostr " + await digest(body)35+ });36+ assert.equal(result.hash, hash);37+ assert.equal(calls.length, 4);38+ assert.equal(calls[1].init.method, "PATCH");39+ assert.equal(calls[1].init.headers["upload-offset"], "0");40+ assert.equal(calls[2].init.headers["upload-offset"], "4");41+ assert.equal(calls[3].init.headers["content-length"], undefined);42+ assert.equal(calls[1].init.headers["content-type"], "application/octet-stream");43+ assert.match(calls[1].init.headers.authorization, new RegExp((await digest(bytes.slice(0, 4)))));44+});45+46+test("falls back to BUD-13 PUT when PATCH is not advertised", async () => {47+ const bytes = new TextEncoder().encode("fallback");48+ const hash = await digest(bytes);49+ const calls = [];50+ const result = await upload(bytes, {51+ url: "https://blossom.example/upload",52+ hash,53+ type: "text/plain",54+ fetch: async (url, init) => {55+ calls.push({url, init});56+ return calls.length === 1 ? response(204, {allow: "GET, PUT"}) : response(201, {}, {sha256: hash, size: bytes.length});57+ }58+ });59+ assert.equal(result.descriptor.sha256, hash);60+ assert.equal(calls[1].init.method, "PUT");61+ assert.deepEqual([...calls[1].init.body], [...bytes]);62+ assert.equal(calls[1].init.headers["content-type"], "text/plain");63+});64+65+test("retries transient chunks, reports local state, and can be canceled", async () => {66+ const bytes = new Uint8Array([1, 2, 3, 4]);67+ const hash = await digest(bytes);68+ let attempts = 0;69+ const states = [];70+ const task = upload(bytes, {71+ url: "https://blossom.example/upload", hash, chunkSize: 2, retries: 1,72+ fetch: async (url, init) => {73+ if (init.method === "OPTIONS") return response(204, {allow: "PATCH"});74+ attempts++;75+ if (attempts === 1) return response(503);76+ return response(204);77+ },78+ onState: state => states.push(state)79+ });80+ await assert.rejects(task, /without completion/);81+ assert.equal(attempts, 5);82+ assert.equal(states.at(-1).status, "uploaded");83+84+ const canceled = upload(bytes, {url: "https://blossom.example/upload", hash, fetch: async (url, init) => {85+ if (init.signal.aborted) throw Object.assign(new Error("aborted"), {name: "AbortError"});86+ return new Promise((resolve, reject) => init.signal.addEventListener("abort", () => reject(Object.assign(new Error("aborted"), {name: "AbortError"}))));87+ }});88+ canceled.cancel();89+ await assert.rejects(canceled, error => error.name === "AbortError");90+});91+92+test("resumes recent local chunks, rejects stale state, and checks the descriptor", async () => {93+ const bytes = new Uint8Array([7, 8, 9, 10]);94+ const hash = await digest(bytes);95+ const state = new Map([[0, {offset: 0, length: 2, status: 204}]]);96+ state.meta = {hash, size: bytes.length, chunkSize: 2, url: "https://blossom.example/tenant/" + hash, type: "application/octet-stream", lastAcceptedAt: Date.now()};97+ const offsets = [];98+ await upload(bytes, {url: "https://blossom.example/tenant/" + hash, hash, chunkSize: 2, state,99+ fetch: async (url, init) => {100+ if (init.method === "OPTIONS") return response(204, {allow: "PATCH"});101+ offsets.push(init.headers["upload-offset"]);102+ return offsets.length === 1 ? response(201, {}, {sha256: hash, size: bytes.length}) : response(204);103+ }104+ });105+ assert.deepEqual(offsets, ["2"]);106+107+ await assert.rejects(upload(bytes, {url: "https://blossom.example", hash, probe: false,108+ fetch: async () => response(201, {}, {sha256: "0".repeat(64), size: bytes.length})109+ }), /invalid Blossom upload descriptor/);110+});111+112+test("keeps the response body readable after headers arrive", async () => {113+ const bytes = new Uint8Array([11, 12]);114+ const hash = await digest(bytes);115+ const server = createServer((request, reply) => {116+ if (request.method === "OPTIONS") { reply.writeHead(204, {Allow: "PATCH"}); return reply.end(); }117+ reply.writeHead(201, {"content-type": "application/json"});118+ setTimeout(() => reply.end(JSON.stringify({sha256: hash, size: bytes.length})), 20);119+ });120+ await new Promise(resolve => server.listen(0, "127.0.0.1", resolve));121+ try {122+ const address = server.address();123+ const result = await upload(bytes, {url: `http://127.0.0.1:${address.port}`, hash, chunkSize: bytes.length, timeoutMs: 1000, fetch});124+ assert.equal(result.descriptor.sha256, hash);125+ } finally { await new Promise(resolve => server.close(resolve)); }126+});
A scripts/file-messages.test.mjs +132 -0
@@ -0,0 +1,132 @@
1+import test from "node:test";2+import assert from "node:assert/strict";3+import fs from "node:fs";4+import vm from "node:vm";5+import { finalizeEvent, generateSecretKey, getEventHash, getPublicKey, nip19, nip44, verifyEvent } from "nostr-tools";6+7+globalThis.NostrSigner = { generateSecretKey, getEventHash, getPublicKey, finalizeEvent, verifyEvent, nip44, decodeNpub: (value) => nip19.decode(value).data };8+vm.runInThisContext(fs.readFileSync("internal/webui/file-messages.js", "utf8"), { filename: "file-messages.js" });9+10+const alice = generateSecretKey();11+const bob = generateSecretKey();12+const alicePub = getPublicKey(alice);13+const bobPub = getPublicKey(bob);14+const signer = {15+ async getPublicKey() { return alicePub; },16+ async signEvent(event) { return finalizeEvent(event, alice); },17+ async nip44Encrypt(recipient, plaintext) { return nip44.encrypt(plaintext, nip44.getConversationKey(alice, recipient)); },18+};19+const list = (pubkey, relays = ["wss://inbox.example"]) => finalizeEvent({ kind: 10050, tags: relays.map((relay) => ["relay", relay]), content: "", created_at: 100 }, pubkey === alicePub ? alice : bob);20+21+test("build creates independently decryptable NIP-17 file gift wraps", async () => {22+ const result = await TinyFileMessages.build({ fileURL: "https://files.example/abc", ciphertextHash: "a".repeat(64), plaintextHash: "b".repeat(64), mimeType: "image/png", key: "11".repeat(32), nonce: "22".repeat(12), recipient: bobPub }, { signer, now: 200 });23+ assert.equal(result.rumor.pubkey, alicePub);24+ assert.equal(result.rumor.id, getEventHash(result.rumor));25+ assert.equal(result.rumor.kind, 15);26+ assert.equal(result.rumor.tags.find((tag) => tag[0] === "x")[1], "a".repeat(64));27+ assert.equal(result.events.length, 2);28+ const receiver = result.events[0].event;29+ assert.equal(receiver.kind, 1059);30+ assert.deepEqual(receiver.tags, [["p", bobPub]]);31+ assert.notEqual(receiver.pubkey, result.events[1].event.pubkey);32+ const sealJSON = nip44.decrypt(receiver.content, nip44.getConversationKey(bob, receiver.pubkey));33+ const seal = JSON.parse(sealJSON);34+ assert.equal(seal.kind, 13);35+ assert.deepEqual(seal.tags, []);36+ assert.equal(seal.pubkey, alicePub);37+ assert.equal(verifyEvent(seal), true);38+ const rumor = JSON.parse(nip44.decrypt(seal.content, nip44.getConversationKey(bob, alicePub)));39+ assert.equal(rumor.pubkey, alicePub);40+ assert.equal(rumor.content, "https://files.example/abc");41+ assert.equal("" + receiver.content.includes("11".repeat(32)), "false");42+});43+44+test("share requires valid inbox lists and publishes only to those lists", async () => {45+ const published = [];46+ const result = await TinyFileMessages.share({ fileURL: "https://files.example/a", ciphertextHash: "c".repeat(64), key: "11".repeat(32), nonce: "22".repeat(12), recipient: bobPub }, {47+ signer,48+ queryRelayList: async (pubkey) => list(pubkey, pubkey === bobPub ? ["wss://bob.example"] : ["ws://127.0.0.1:7777"]),49+ publish: async (event, relays) => { published.push({ event, relays }); return true; },50+ now: 200,51+ });52+ assert.equal(published.length, 2);53+ assert.deepEqual(published[0].relays, ["wss://bob.example"]);54+ assert.deepEqual(published[1].relays, ["ws://127.0.0.1:7777"]);55+ assert.deepEqual(result.relays.recipient, ["wss://bob.example"]);56+});57+58+test("share refuses to send when either inbox list is absent", async () => {59+ let sends = 0;60+ await assert.rejects(() => TinyFileMessages.share({ fileURL: "https://files.example/a", ciphertextHash: "d".repeat(64), key: "11".repeat(32), nonce: "22".repeat(12), recipient: bobPub }, {61+ signer,62+ queryRelayList: async () => null,63+ publish: async () => { sends++; },64+ }), /valid kind 10050/);65+ assert.equal(sends, 0);66+});67+68+test("share accepts npub recipients and rejects signer identity mismatches", async () => {69+ const published = [];70+ await TinyFileMessages.share({ fileURL: "https://files.example/a", ciphertextHash: "e".repeat(64), key: "11".repeat(32), nonce: "22".repeat(12), recipient: nip19.npubEncode(bobPub) }, {71+ signer,72+ queryRelayList: async (pubkey) => list(pubkey),73+ publish: async (event) => { published.push(event); return true; },74+ });75+ assert.equal(published.length, 2);76+ const mismatched = { ...signer, async signEvent(event) { return finalizeEvent(event, bob); } };77+ await assert.rejects(() => TinyFileMessages.build({ fileURL: "https://files.example/a", ciphertextHash: "f".repeat(64), key: "11".repeat(32), nonce: "22".repeat(12), recipient: bobPub }, { signer: mismatched }), /invalid NIP-17 seal/);78+});79+80+test("share rejects an all-failed publish result", async () => {81+ await assert.rejects(() => TinyFileMessages.share({ fileURL: "https://files.example/a", ciphertextHash: "1".repeat(64), key: "11".repeat(32), nonce: "22".repeat(12), recipient: bobPub }, {82+ signer,83+ queryRelayList: async (pubkey) => list(pubkey),84+ publish: async () => [false, false],85+ }), /every inbox relay/);86+});87+88+test("default transport queries locally and publishes only inbox WebSockets", async () => {89+ const queries = [];90+ const sockets = [];91+ globalThis.tiny = {92+ signedFetch: async (path, method, body) => {93+ queries.push({ path, method, body });94+ const author = JSON.parse(body)[0].authors[0];95+ return { json: async () => [list(author, [author === bobPub ? "wss://bob.example" : "wss://alice.example"]) ] };96+ },97+ };98+ globalThis.WebSocket = class {99+ constructor(url) { this.url = url; sockets.push(this); setTimeout(() => this.onopen?.(), 0); }100+ send(data) { const event = JSON.parse(data)[1]; setTimeout(() => this.onmessage?.({ data: JSON.stringify(["OK", event.id, true, ""]) }), 0); }101+ close() { this.closed = true; }102+ };103+ const result = await TinyFileMessages.share({ fileURL: "https://files.example/a", ciphertextHash: "2".repeat(64), key: "11".repeat(32), nonce: "22".repeat(12), recipient: bobPub }, { signer, timeoutMs: 1000 });104+ assert.equal(queries.length, 2);105+ assert.deepEqual(sockets.map((socket) => socket.url), ["wss://bob.example", "wss://alice.example"]);106+ assert.deepEqual(result.deliveries, [[true], [true]]);107+ delete globalThis.tiny;108+ delete globalThis.WebSocket;109+});110+111+test("default transport answers one NIP-42 challenge and retries the event", async () => {112+ let eventAttempts = 0;113+ globalThis.WebSocket = class {114+ constructor() { setTimeout(() => this.onopen?.(), 0); }115+ send(data) {116+ const frame = JSON.parse(data);117+ if (frame[0] === "EVENT") {118+ eventAttempts++;119+ if (eventAttempts === 1) {120+ setTimeout(() => this.onmessage?.({ data: JSON.stringify(["AUTH", "challenge"]) }), 0);121+ setTimeout(() => this.onmessage?.({ data: JSON.stringify(["OK", frame[1].id, false, "auth-required"]) }), 1);122+ }123+ else setTimeout(() => this.onmessage?.({ data: JSON.stringify(["OK", frame[1].id, true, ""]) }), 0);124+ } else if (frame[0] === "AUTH") setTimeout(() => this.onmessage?.({ data: JSON.stringify(["OK", frame[1].id, true, ""]) }), 0);125+ }126+ close() {}127+ };128+ const result = await TinyFileMessages.publishEvent({ id: "1".repeat(64) }, ["wss://inbox.example"], { signer, timeoutMs: 1000 });129+ assert.deepEqual(result, [true]);130+ assert.equal(eventAttempts, 2);131+ delete globalThis.WebSocket;132+});
A scripts/file-workspace.test.mjs +260 -0
@@ -0,0 +1,260 @@
1+import test from "node:test";2+import assert from "node:assert/strict";3+import fs from "node:fs";4+import vm from "node:vm";5+import { webcrypto } from "node:crypto";6+7+class Node {8+ constructor(tag = "") { this.tagName = tag.toUpperCase(); this.children = []; this.attributes = {}; this.listeners = {}; this.dataset = {}; this.textContent = ""; }9+ append(...nodes) { nodes.forEach(node => { if (node) { this.children.push(node); node.parentNode = this; } }); }10+ replaceChildren(...nodes) { this.children = []; this.append(...nodes); }11+ click() {}12+ setAttribute(name, value) { this.attributes[name] = String(value); }13+ getAttribute(name) { return this.attributes[name] ?? null; }14+ hasAttribute(name) { return name in this.attributes; }15+ addEventListener(name, fn) { (this.listeners[name] ||= []).push(fn); }16+ set innerHTML(value) { this.children = []; parse(value, this); }17+ get childNodes() { return this.children; }18+ querySelector(selector) { return this.querySelectorAll(selector)[0] || null; }19+ querySelectorAll(selector) {20+ const result = [];21+ const match = node => {22+ if (selector === "output") return node.tagName === "OUTPUT";23+ if (selector === "form:not([data-share])") return node.tagName === "FORM" && !node.hasAttribute("data-share");24+ if (selector === "input[type=file]") return node.tagName === "INPUT" && node.getAttribute("type") === "file";25+ const attr = selector.match(/^([^[]+)?\[([^=\]]+)(?:=\"([^\"]+)\")?\]$/);26+ if (attr) return (!attr[1] || node.tagName === attr[1].toUpperCase()) && node.hasAttribute(attr[2]) && (attr[3] === undefined || node.getAttribute(attr[2]) === attr[3]);27+ return node.tagName === selector.toUpperCase();28+ };29+ const walk = node => { node.children.forEach(child => { if (match(child)) result.push(child); walk(child); }); };30+ walk(this); return result;31+ }32+}33+class Form extends Node {34+ constructor() { super("form"); this.elements = { namedItem: name => this.querySelectorAll("input").concat(this.querySelectorAll("select")).find(node => node.getAttribute("name") === name) }; }35+}36+const parse = (html, parent) => {37+ const stack = [parent];38+ for (const token of html.match(/<[^>]+>|[^<]+/g) || []) {39+ if (!token.startsWith("<")) continue;40+ if (/^<\/(option|input|br|meta|img)>/.test(token)) continue;41+ if (/^<\//.test(token)) { stack.pop(); continue; }42+ const match = token.match(/^<([\w-]+)([^>]*)>/); if (!match) continue;43+ const node = match[1] === "form" ? new Form() : new Node(match[1]);44+ for (const [, name, quote, value] of match[2].matchAll(/([\w-]+)(?:=(['"])(.*?)\2)?/g)) node.setAttribute(name, value ?? "");45+ if (node.tagName === "INPUT" || node.tagName === "SELECT") node.value = node.getAttribute("value") || (node.tagName === "SELECT" ? "random" : "");46+ stack.at(-1).append(node);47+ if (!/^(input|br|meta|option|img)$/.test(match[1])) stack.push(node);48+ }49+};50+const load = (workspace = false) => {51+ const document = new Node("document"); document.documentElement = new Node("html"); document.body = new Node("body"); document.createElement = name => name === "form" ? new Form() : new Node(name); document.addEventListener = () => {}; document.dispatchEvent = () => {};52+ const customElements = {registry: {}, define(name, ctor) { this.registry[name] = ctor; }};53+ const window = {document, customElements, tiny: {}, location: {href: "https://relay.test/files", origin: "https://relay.test", pathname: "/files", hash: ""}, addEventListener: () => {}, matchMedia: () => ({matches: false, addEventListener: () => {}})};54+ class HTMLElement extends Node {}55+ Object.assign(globalThis, {window, document, customElements, HTMLElement, location: window.location, Blob, URL, CustomEvent: class {}});56+ globalThis.tiny = window.tiny;57+ Object.defineProperty(globalThis, "navigator", {configurable: true, value: {clipboard: {writeText: async () => { throw Error("clipboard unavailable"); }}}});58+ globalThis.btoa = value => Buffer.from(value, "binary").toString("base64"); globalThis.atob = value => Buffer.from(value, "base64").toString("binary");59+ if (workspace) { vm.runInThisContext(fs.readFileSync("internal/webui/blossom-manifests.js", "utf8")); vm.runInThisContext(fs.readFileSync("internal/webui/blossom-encryption.js", "utf8")); vm.runInThisContext(fs.readFileSync("internal/webui/blossom-upload.js", "utf8")); vm.runInThisContext(fs.readFileSync("internal/webui/file-workspace.js", "utf8")); } else { delete globalThis.TinyBlossomUpload; }60+ vm.runInThisContext(fs.readFileSync("internal/webui/components.js", "utf8"));61+ return {document, window, FileTools: customElements.registry["file-tools"], FileMirror: customElements.registry["file-mirror"]};62+};63+64+const workspaceServer = t => {65+ const loaded = load(true);66+ const {window} = loaded;67+ const blobs = new Map(), pending = new Map(), requests = [];68+ const originalFetch = globalThis.fetch;69+ window.tiny.localPath = path => "/r/test" + path;70+ window.tiny.sha256hex = async bytes => Buffer.from(await webcrypto.subtle.digest("SHA-256", bytes)).toString("hex");71+ window.tiny.authorization = async (url, method, body) => {72+ assert.equal(new URL(url).hash, "");73+ return "Nostr " + await window.tiny.sha256hex(body);74+ };75+ globalThis.fetch = async (target, init = {}) => {76+ const url = new URL(target, window.location.href);77+ requests.push({url, init});78+ assert.equal(url.hash, "");79+ assert.equal(url.searchParams.has("key"), false);80+ if (init.method === "OPTIONS") return new Response(null, {status: 204, headers: {Allow: "PATCH"}});81+ if (init.method === "PATCH") {82+ const hash = url.pathname.split("/").at(-1);83+ assert.match(url.pathname, /^\/r\/test\/[0-9a-f]{64}$/);84+ const length = Number(init.headers["upload-length"]), offset = Number(init.headers["upload-offset"]);85+ if (!pending.has(hash)) pending.set(hash, new Uint8Array(length));86+ pending.get(hash).set(init.body, offset);87+ if (offset + init.body.length < length) return new Response(null, {status: 204});88+ const bytes = pending.get(hash);89+ assert.equal(hash, await window.tiny.sha256hex(bytes));90+ blobs.set(hash, bytes); pending.delete(hash);91+ return Response.json({sha256: hash, size: bytes.length}, {status: 201});92+ }93+ const hash = url.searchParams.get("hash");94+ return blobs.has(hash) ? new Response(blobs.get(hash)) : new Response(null, {status: 404});95+ };96+ t.after(() => { globalThis.fetch = originalFetch; });97+ const open = async url => {98+ const value = new URL(url);99+ Object.assign(window.location, {href: value.href, pathname: value.pathname, hash: value.hash});100+ const root = new customElements.registry["file-workspace-root"]();101+ await root.load();102+ t.after(() => root.disconnectedCallback());103+ return root;104+ };105+ const store = async files => {106+ const workspace = new customElements.registry["file-workspace"]();107+ workspace.connectedCallback();108+ const form = workspace.querySelector("[data-folder]");109+ form.elements.namedItem("folder").files = files;110+ return workspace.run(form);111+ };112+ return {...loaded, blobs, requests, store, open, originalFetch};113+};114+const folderFile = (contents, path) => {115+ const file = new File([contents], path.split("/").at(-1), {type: "text/plain"});116+ Object.defineProperty(file, "webkitRelativePath", {value: path});117+ return file;118+};119+120+test("nested folder components upload and decrypt large files without exposing keys", async t => {121+ const server = workspaceServer(t);122+ const large = new Uint8Array(2 * 1024 * 1024 + 19); large[2] = 91; large[large.length - 1] = 73;123+ const url = await server.store([124+ folderFile(large, "root/__proto__/f"), folderFile("héllo", "root/é.txt"),125+ folderFile("emoji", "root/😀.txt"), folderFile("constructor", "root/constructor")126+ ]);127+ const root = await server.open(url);128+ assert.deepEqual(root.entries.map(entry => entry.n), ["__proto__", "constructor", "é.txt", "😀.txt"]);129+ const child = await server.open(root.querySelector("a").href);130+ assert.equal(child.entries[0].n, "f");131+ assert.deepEqual(await child.download(child.entries[0]), large);132+ const key = new URLSearchParams(new URL(url).hash.slice(1)).get("key");133+ for (const {url: target, init} of server.requests) {134+ assert.equal(target.href.includes(key), false);135+ if (init.body) assert.equal(new TextDecoder().decode(init.body).includes("héllo"), false);136+ }137+ assert.ok(server.blobs.size >= 8);138+});139+140+test("directory fanout stays invisible while 175 entries remain browsable", async t => {141+ const server = workspaceServer(t);142+ const files = Array.from({length: 175}, (_, index) => folderFile("content " + index, "wide/file-" + String(index).padStart(3, "0")));143+ const root = await server.open(await server.store(files));144+ assert.equal(root.entries.length, 175);145+ assert.equal(root.entries[174].n, "file-174");146+ assert.equal(new TextDecoder().decode(await root.download(root.entries[174])), "content 174");147+});148+149+test("folder upload rejects unexpected server hashes", async t => {150+ const server = workspaceServer(t);151+ globalThis.fetch = async (_url, init = {}) => init.method === "OPTIONS" ? new Response(null, {status:204, headers:{Allow:"PATCH"}}) : Response.json({sha256:"0".repeat(64), size: init.body.length}, {status:201});152+ await assert.rejects(server.store([folderFile("private", "root/private.txt")]), /descriptor/);153+});154+155+test("encrypted upload keeps ciphertext and link when clipboard fails", async () => {156+ const {document, window, FileTools} = load(); const requests = [];157+ window.tiny.sha256hex = async bytes => Buffer.from(await webcrypto.subtle.digest("SHA-256", bytes)).toString("hex");158+ window.tiny.signedFetch = async (path, method, body) => { const bytes = new Uint8Array(body); requests.push(bytes); return {json: async () => ({sha256: await window.tiny.sha256hex(bytes)})}; };159+ const tools = new FileTools(); document.append(tools); tools.connectedCallback();160+ const form = tools.querySelector("form:not([data-share])");161+ form.querySelector("input[type=file]").files = [new File(["secret plaintext"], "secret.txt", {type: "text/plain"})];162+ await tools.encryptUpload(form);163+ assert.equal(requests.length, 1); assert.notEqual(new TextDecoder().decode(requests[0]), "secret plaintext");164+ assert.match(tools.querySelector("[data-share-url]").value, /#key=.*&iv=/); assert.match(tools.output.textContent, /Copy the share link above/);165+ assert.equal(tools.shareLink(), tools.querySelector("[data-share-url]").value);166+});167+168+test("BUD15 key is rejected before mirror request", async () => {169+ const {document, window, FileMirror} = load(); const mirror = new FileMirror(); document.append(mirror); mirror.connectedCallback();170+ mirror.form.querySelector("input").value = "blossom:" + "a".repeat(64) + "?enc=chk-v1&k=" + "1".repeat(64);171+ let sent = false; window.tiny.signedFetch = async () => { sent = true; };172+ await assert.rejects(() => mirror.submit(mirror.form), /keep k client side/);173+ assert.equal(sent, false);174+});175+176+test("sharing a newly uploaded file uses its current key, hash and ciphertext size", async () => {177+ const {document, window, FileTools} = load();178+ window.tiny.sha256hex = async bytes => Buffer.from(await webcrypto.subtle.digest("SHA-256", bytes)).toString("hex");179+ window.tiny.localPath = path => path;180+ let uploaded;181+ window.tiny.signedFetch = async (_path, _method, body) => { uploaded = new Uint8Array(body); return {json: async () => ({sha256: await window.tiny.sha256hex(body)})}; };182+ const element = new FileTools(); document.append(element); element.connectedCallback();183+ const form = element.querySelector("form:not([data-share])");184+ form.querySelector("input[type=file]").files = [new File(["new secret"], "private.txt", {type: "text/plain"})];185+ await element.encryptUpload(form);186+ const shareForm = element.querySelector("[data-share]");187+ shareForm.querySelector("input").value = "b".repeat(64);188+ globalThis.nostr = {signEvent: async value => value};189+ let input;190+ globalThis.TinyFileMessages = {share: async (value, options) => { input = value; assert.equal(options.signer, globalThis.nostr); return {}; }};191+ await element.share(shareForm);192+ assert.ok(input, element.output.textContent);193+ assert.equal(input.ciphertextHash, await window.tiny.sha256hex(uploaded));194+ assert.equal(input.size, uploaded.length);195+ assert.equal(input.plaintextHash, await window.tiny.sha256hex(new TextEncoder().encode("new secret")));196+ assert.match(input.key, /^[0-9a-f]{64}$/);197+ assert.match(input.nonce, /^[0-9a-f]{24}$/);198+ const key = await webcrypto.subtle.importKey("raw", Buffer.from(input.key, "hex"), "AES-GCM", false, ["decrypt"]);199+ const plain = await webcrypto.subtle.decrypt({name: "AES-GCM", iv: Buffer.from(input.nonce, "hex")}, key, uploaded);200+ assert.equal(new TextDecoder().decode(plain), "new secret");201+ assert.equal(new URL(input.fileURL).hash, "");202+});203+204+test("HTTP mirror input never submits its secret fragment", async () => {205+ const {document, window, FileMirror} = load();206+ const mirror = new FileMirror(); document.append(mirror); mirror.connectedCallback();207+ mirror.form.querySelector("input").value = "https://files.example/blob#key=secret";208+ let body;209+ window.tiny.signedFetch = async (_path, _method, value) => { body = value; return {json: async () => ({sha256: "a".repeat(64)})}; };210+ await mirror.submit(mirror.form);211+ assert.equal(JSON.parse(body).url, "https://files.example/blob");212+});213+214+test("local downloads verify integrity, decrypt and release their temporary URL", async () => {215+ const {document, window, FileTools} = load();216+ window.tiny.sha256hex = async bytes => Buffer.from(await webcrypto.subtle.digest("SHA-256", bytes)).toString("hex");217+ window.tiny.localPath = path => path;218+ let uploaded;219+ window.tiny.signedFetch = async (_path, _method, body) => { uploaded = new Uint8Array(body); return {json: async () => ({sha256: await window.tiny.sha256hex(body)})}; };220+ const element = new FileTools(); document.append(element); element.connectedCallback();221+ const form = element.querySelector("form:not([data-share])");222+ form.querySelector("input[type=file]").files = [new File(["round trip"], "round.txt", {type: "text/plain"})];223+ await element.encryptUpload(form);224+ const originalFetch = globalThis.fetch;225+ try {226+ globalThis.fetch = async () => new Response(uploaded);227+ await element.decryptFromFragment();228+ assert.equal(element.output.textContent, "Decrypted locally.");229+ assert.equal(await (await originalFetch(element.downloadURL)).text(), "round trip");230+ const temporaryURL = element.downloadURL;231+ element.disconnectedCallback();232+ await assert.rejects(originalFetch(temporaryURL));233+ uploaded[0] ^= 1;234+ await element.decryptFromFragment();235+ assert.match(element.output.textContent, /ciphertext hash mismatch/);236+ } finally { globalThis.fetch = originalFetch; }237+});238+239+test("retry keeps the original ciphertext and key after interrupted encrypted upload", async () => {240+ const {document, window, FileTools} = load();241+ window.tiny.localPath = path => path;242+ window.tiny.sha256hex = async bytes => Buffer.from(await webcrypto.subtle.digest("SHA-256", bytes)).toString("hex");243+ const sent = [];244+ globalThis.TinyBlossomUpload = {upload: async (bytes, options) => {245+ assert.equal(options.url, "https://relay.test/");246+ sent.push(bytes.slice());247+ if (sent.length === 1) throw Error("connection interrupted");248+ return {descriptor: {sha256: await window.tiny.sha256hex(bytes), size: bytes.length}};249+ }};250+ const fileTools = new FileTools(); document.append(fileTools); fileTools.connectedCallback();251+ const form = fileTools.querySelector("form:not([data-share])");252+ form.elements.namedItem("file").files = [new File(["keep the same key"], "private.txt")];253+ await fileTools.encryptUpload(form);254+ const originalFragment = fileTools.pendingUpload.fragment;255+ assert.equal(fileTools.querySelector("[data-upload-retry]").disabled, false);256+ await fileTools.retryUpload();257+ assert.deepEqual(sent[1], sent[0]);258+ assert.equal(fileTools.fileFragment, originalFragment);259+ assert.equal(fileTools.pendingUpload, null);260+});
M scripts/signer-entry.mjs +9 -0