- commit
- 8b51870933f832641be527f6d6d57c99f97f9c5f
- parent
- ac4fefc833a3a19b92c6644ebc1ed5b3f1c662c7
- author
- Dami <dami.etoile@gmail.com>
| A | internal/ | 73 | +++++ |
| A | internal/ | 466 | ++++++++++++++++++++++++++++++ |
| A | internal/ | 160 | ++++++++++ |
| M | internal/ | 2 | +- |
| M | internal/ | 5 | + |
| M | internal/ | 224 | ++++++++++++++ |
| A | internal/ | 209 | +++++++++++++ |
| A | internal/ | 291 | +++++++++++++++++++ |
| M | internal/ | 5 | + |
| M | internal/ | 2 | +- |
| M | internal/ | 19 | +- |
| M | internal/ | 17 | +- |
| M | package.json | 3 | +- |
| A | scripts/ | 58 | ++++ |
| A | scripts/ | 92 | ++++++ |
| A | scripts/ | 70 | +++++ |
| A | scripts/ | 126 | ++++++++ |
| A | scripts/ | 132 | ++++++++ |
| A | scripts/ | 260 | +++++++++++++++++ |
| M | scripts/ | 9 | + |
@@ -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+})();@@ -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+})();@@ -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+})();@@ -34,7 +34,7 @@
3434 const event = await window.nostr.signEvent({3535 kind: 27235,3636 created_at: Math.floor(Date.now() / 1000),37- tags: [["u", url], ["method", method], ["payload", await sha256hex(bytes)]],37+ tags: [["u", url], ["method", method], ["payload", await sha256hex(bytes)], ["nonce", randomHex()]],3838 content: ""3939 });4040 return "Nostr " + btoa(JSON.stringify(event));@@ -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>@@ -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);@@ -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);@@ -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+})();@@ -57,6 +57,11 @@
5757 </tr></tbody></table>5858 <footer id="footer"><table><tr><td><span id="prompt"><b>{{.Slug}}</b> » {{prompt .Path .Query}}</span></td><td><span id="who">{{if .Private}}private relay{{else if .Actor}}signed in as {{template "nostrKey" .Actor}} (<button id="session-logout" type="button">sign out</button>){{else}}browsing as guest (<a href="/signin">Sign in</a>){{end}}</span> <span id="session-status" role="status"></span><span id="navigation-status" role="status" aria-live="polite"></span><button id="theme" type="button" aria-label="Switch theme">theme</button></td></tr></table></footer>5959 <script>{{script "bridge.js"}}</script>60+<script>{{script "blossom-encryption.js"}}</script>61+<script>{{script "blossom-manifests.js"}}</script>62+<script>{{script "blossom-upload.js"}}</script>63+<script>{{script "file-messages.js"}}</script>64+<script>{{script "file-workspace.js"}}</script>6065 <script>{{script "components.js"}}</script>6166 </body>6267 </html>@@ -1,5 +1,5 @@
11 ;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:@@ -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)}@@ -32,6 +32,21 @@ var bridgeJS string
3232 //go:embed components.js3333 var componentsJS string3434 35+//go:embed blossom-encryption.js36+var blossomEncryptionJS string37+38+//go:embed blossom-manifests.js39+var blossomManifestsJS string40+41+//go:embed file-messages.js42+var fileMessagesJS string43+44+//go:embed blossom-upload.js45+var blossomUploadJS string46+47+//go:embed file-workspace.js48+var fileWorkspaceJS string49+3550 // Installable app assets. The manifest is a template: NAME and BASE are3651 // replaced per request so tenant prefixes and relay names stay correct.3752 //@@ -110,7 +125,7 @@ func repoView(query url.Values) string {
110125 }111126 112127 func parseTemplates() (*template.Template, error) {113- scripts := map[string]string{"bridge.js": bridgeJS, "components.js": componentsJS}128+ scripts := map[string]string{"bridge.js": bridgeJS, "components.js": componentsJS, "blossom-encryption.js": blossomEncryptionJS, "blossom-manifests.js": blossomManifestsJS, "blossom-upload.js": blossomUploadJS, "file-messages.js": fileMessagesJS, "file-workspace.js": fileWorkspaceJS}114129 funcs := template.FuncMap{115130 "stylesheet": func() template.CSS { return template.CSS(styleCSS) },116131 "script": func(name string) (template.JS, error) {@@ -6,7 +6,8 @@
66 "build:signer": "node scripts/build-signer.mjs",77 "test:conformance": "node scripts/conformance/run.mjs",88 "test:webmcp": "node --test scripts/webmcp.test.mjs",9- "test:signer": "node --test scripts/signer.test.mjs"9+ "test:signer": "node --test scripts/signer.test.mjs",10+ "test:files": "node --test scripts/blossom-encryption.test.mjs scripts/blossom-manifests.test.mjs scripts/blossom-manifests-review.test.mjs scripts/blossom-upload.test.mjs scripts/file-messages.test.mjs scripts/file-workspace.test.mjs scripts/private-services.test.mjs"1011 },1112 "devDependencies": {1213 "@noble/hashes": "2.4.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+});@@ -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+});@@ -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+});@@ -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+});@@ -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+});@@ -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+});@@ -3,6 +3,8 @@ import {
33 finalizeEvent,44 generateSecretKey,55 getPublicKey,6+ getEventHash,7+ nip44,68 nip19,79 verifyEvent,810 } from "nostr-tools";@@ -16,12 +18,19 @@ globalThis.NostrSigner = {
1618 generateSecretKey,1719 getPublicKey,1820 finalizeEvent,21+ getEventHash,1922 verifyEvent,23+ nip44,2024 SimplePool,2125 BunkerSigner,2226 parseBunkerInput,2327 createNostrConnectURI,2428 npubEncode: nip19.npubEncode,29+ decodeNpub: (value) => {30+ const decoded = nip19.decode(value);31+ if (decoded.type !== "npub") throw new Error("expected an npub");32+ return decoded.data;33+ },2534 bytesToHex: (bytes) => Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(""),2635 hexToBytes: (hex) => Uint8Array.from(hex.match(/.{1,2}/g) ?? [], (byte) => parseInt(byte, 16)),2736 };