site/js/wizardconnect.js
Local Dev 8532711563 electrum: wire wss://silentmode.st/electrum as first-choice (port 443 reachable)
Bns-indexer on VPS was only exposed on port 50011 via nginx, which corporate
firewalls, mobile carriers, and many VPNs block. Added an nginx location on
443 that proxies to the same 127.0.0.1:50010, giving us a browser-friendly
WSS endpoint on the standard HTTPS port.

  * lib/electrum.js CHIPNET_ELECTRUM: wss://silentmode.st/electrum listed
    first (used by registrar.connect() + everything that depends on it).
  * lib/resolver-web.js CHIPNET_ELECTRUM: same, kept in lockstep per the
    "change both together" comment.
  * bns-register.js bundle rebuilt to bake the new list.
  * portal.html imports the bundle with ?v= so Chrome's in-memory ES-module
    map doesn't serve a stale copy across tabs.

Portal now connects successfully; next remaining issue is that
bns-indexer only supports (server.version, get_history, transaction.get) —
`blockchain.scripthash.listunspent` for wallet address queries is not
implemented, so the "list your names" step fails there. Follow-up: add a
GET /api/holdings/<address> to public-gateway.mjs backed by the existing
BCHN electrum access, so the portal can pull holdings over plain HTTP.
2026-08-31 03:35:39 +02:00

7059 lines
236 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __esm = (fn, res, err) => function __init() {
if (err) throw err[0];
try {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
} catch (e) {
throw err = [e], e;
}
};
var __commonJS = (cb, mod2) => function __require() {
try {
return mod2 || (0, cb[__getOwnPropNames(cb)[0]])((mod2 = { exports: {} }).exports, mod2), mod2.exports;
} catch (e) {
throw mod2 = 0, e;
}
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod2, isNodeMode, target) => (target = mod2 != null ? __create(__getProtoOf(mod2)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod2 || !mod2.__esModule ? __defProp(target, "default", { value: mod2, enumerable: true }) : target,
mod2
));
// node_modules/@wizardconnect/core/dist/primitives.js
function unwrap(value) {
if (typeof value === "string") {
throw new Error(`unwrap: ${value}`);
}
if (value instanceof Error) {
throw value;
}
return value;
}
var throwUnless;
var init_primitives = __esm({
"node_modules/@wizardconnect/core/dist/primitives.js"() {
throwUnless = (x, what) => {
if (!x) {
throw Error(`Internal application error: ${what}`);
}
};
}
});
// node_modules/@noble/hashes/utils.js
function isBytes(a) {
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
}
function anumber(n, title = "") {
if (!Number.isSafeInteger(n) || n < 0) {
const prefix = title && `"${title}" `;
throw new Error(`${prefix}expected integer >= 0, got ${n}`);
}
}
function abytes(value, length, title = "") {
const bytes = isBytes(value);
const len = value?.length;
const needsLen = length !== void 0;
if (!bytes || needsLen && len !== length) {
const prefix = title && `"${title}" `;
const ofLen = needsLen ? ` of length ${length}` : "";
const got = bytes ? `length=${len}` : `type=${typeof value}`;
throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
}
return value;
}
function ahash(h) {
if (typeof h !== "function" || typeof h.create !== "function")
throw new Error("Hash must wrapped by utils.createHasher");
anumber(h.outputLen);
anumber(h.blockLen);
}
function aexists(instance, checkFinished = true) {
if (instance.destroyed)
throw new Error("Hash instance has been destroyed");
if (checkFinished && instance.finished)
throw new Error("Hash#digest() has already been called");
}
function aoutput(out, instance) {
abytes(out, void 0, "digestInto() output");
const min = instance.outputLen;
if (out.length < min) {
throw new Error('"digestInto() output" expected to be of length >=' + min);
}
}
function clean(...arrays) {
for (let i3 = 0; i3 < arrays.length; i3++) {
arrays[i3].fill(0);
}
}
function createView(arr) {
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
}
function rotr(word, shift) {
return word << 32 - shift | word >>> shift;
}
function bytesToHex(bytes) {
abytes(bytes);
if (hasHexBuiltin)
return bytes.toHex();
let hex = "";
for (let i3 = 0; i3 < bytes.length; i3++) {
hex += hexes[bytes[i3]];
}
return hex;
}
function asciiToBase16(ch) {
if (ch >= asciis._0 && ch <= asciis._9)
return ch - asciis._0;
if (ch >= asciis.A && ch <= asciis.F)
return ch - (asciis.A - 10);
if (ch >= asciis.a && ch <= asciis.f)
return ch - (asciis.a - 10);
return;
}
function hexToBytes(hex) {
if (typeof hex !== "string")
throw new Error("hex string expected, got " + typeof hex);
if (hasHexBuiltin)
return Uint8Array.fromHex(hex);
const hl = hex.length;
const al = hl / 2;
if (hl % 2)
throw new Error("hex string expected, got unpadded hex of length " + hl);
const array = new Uint8Array(al);
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
const n1 = asciiToBase16(hex.charCodeAt(hi));
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
if (n1 === void 0 || n2 === void 0) {
const char = hex[hi] + hex[hi + 1];
throw new Error('hex string expected, got non-hex character "' + char + '" at index ' + hi);
}
array[ai] = n1 * 16 + n2;
}
return array;
}
function concatBytes(...arrays) {
let sum = 0;
for (let i3 = 0; i3 < arrays.length; i3++) {
const a = arrays[i3];
abytes(a);
sum += a.length;
}
const res = new Uint8Array(sum);
for (let i3 = 0, pad2 = 0; i3 < arrays.length; i3++) {
const a = arrays[i3];
res.set(a, pad2);
pad2 += a.length;
}
return res;
}
function createHasher(hashCons, info = {}) {
const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
const tmp = hashCons(void 0);
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = (opts) => hashCons(opts);
Object.assign(hashC, info);
return Object.freeze(hashC);
}
function randomBytes(bytesLength = 32) {
const cr = typeof globalThis === "object" ? globalThis.crypto : null;
if (typeof cr?.getRandomValues !== "function")
throw new Error("crypto.getRandomValues must be defined");
return cr.getRandomValues(new Uint8Array(bytesLength));
}
var hasHexBuiltin, hexes, asciis, oidNist;
var init_utils = __esm({
"node_modules/@noble/hashes/utils.js"() {
hasHexBuiltin = /* @__PURE__ */ (() => (
// @ts-ignore
typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
))();
hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i3) => i3.toString(16).padStart(2, "0"));
asciis = { _0: 48, _9: 57, A: 65, F: 70, a: 97, f: 102 };
oidNist = (suffix) => ({
oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
});
}
});
// node_modules/@noble/hashes/_md.js
function Chi(a, b, c) {
return a & b ^ ~a & c;
}
function Maj(a, b, c) {
return a & b ^ a & c ^ b & c;
}
var HashMD, SHA256_IV;
var init_md = __esm({
"node_modules/@noble/hashes/_md.js"() {
init_utils();
HashMD = class {
blockLen;
outputLen;
padOffset;
isLE;
// For partial updates less than block size
buffer;
view;
finished = false;
length = 0;
pos = 0;
destroyed = false;
constructor(blockLen, outputLen, padOffset, isLE2) {
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE2;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
aexists(this);
abytes(data);
const { view, buffer, blockLen } = this;
const len = data.length;
for (let pos = 0; pos < len; ) {
const take = Math.min(blockLen - this.pos, len - pos);
if (take === blockLen) {
const dataView = createView(data);
for (; blockLen <= len - pos; pos += blockLen)
this.process(dataView, pos);
continue;
}
buffer.set(data.subarray(pos, pos + take), this.pos);
this.pos += take;
pos += take;
if (this.pos === blockLen) {
this.process(view, 0);
this.pos = 0;
}
}
this.length += data.length;
this.roundClean();
return this;
}
digestInto(out) {
aexists(this);
aoutput(out, this);
this.finished = true;
const { buffer, view, blockLen, isLE: isLE2 } = this;
let { pos } = this;
buffer[pos++] = 128;
clean(this.buffer.subarray(pos));
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
pos = 0;
}
for (let i3 = pos; i3 < blockLen; i3++)
buffer[i3] = 0;
view.setBigUint64(blockLen - 8, BigInt(this.length * 8), isLE2);
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
if (len % 4)
throw new Error("_sha2: outputLen must be aligned to 32bit");
const outLen = len / 4;
const state = this.get();
if (outLen > state.length)
throw new Error("_sha2: outputLen bigger than state");
for (let i3 = 0; i3 < outLen; i3++)
oview.setUint32(4 * i3, state[i3], isLE2);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
to ||= new this.constructor();
to.set(...this.get());
const { blockLen, buffer, length, finished, destroyed, pos } = this;
to.destroyed = destroyed;
to.finished = finished;
to.length = length;
to.pos = pos;
if (length % blockLen)
to.buffer.set(buffer);
return to;
}
clone() {
return this._cloneInto();
}
};
SHA256_IV = /* @__PURE__ */ Uint32Array.from([
1779033703,
3144134277,
1013904242,
2773480762,
1359893119,
2600822924,
528734635,
1541459225
]);
}
});
// node_modules/@noble/hashes/sha2.js
var SHA256_K, SHA256_W, SHA2_32B, _SHA256, sha256;
var init_sha2 = __esm({
"node_modules/@noble/hashes/sha2.js"() {
init_md();
init_utils();
SHA256_K = /* @__PURE__ */ 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
]);
SHA256_W = /* @__PURE__ */ new Uint32Array(64);
SHA2_32B = class extends HashMD {
constructor(outputLen) {
super(64, outputLen, 8, false);
}
get() {
const { A, B, C, D, E, F, G, H } = this;
return [A, B, C, D, E, F, G, H];
}
// prettier-ignore
set(A, B, C, D, E, F, G, H) {
this.A = A | 0;
this.B = B | 0;
this.C = C | 0;
this.D = D | 0;
this.E = E | 0;
this.F = F | 0;
this.G = G | 0;
this.H = H | 0;
}
process(view, offset) {
for (let i3 = 0; i3 < 16; i3++, offset += 4)
SHA256_W[i3] = view.getUint32(offset, false);
for (let i3 = 16; i3 < 64; i3++) {
const W15 = SHA256_W[i3 - 15];
const W2 = SHA256_W[i3 - 2];
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
SHA256_W[i3] = s1 + SHA256_W[i3 - 7] + s0 + SHA256_W[i3 - 16] | 0;
}
let { A, B, C, D, E, F, G, H } = this;
for (let i3 = 0; i3 < 64; i3++) {
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i3] + SHA256_W[i3] | 0;
const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
const T2 = sigma0 + Maj(A, B, C) | 0;
H = G;
G = F;
F = E;
E = D + T1 | 0;
D = C;
C = B;
B = A;
A = T1 + T2 | 0;
}
A = A + this.A | 0;
B = B + this.B | 0;
C = C + this.C | 0;
D = D + this.D | 0;
E = E + this.E | 0;
F = F + this.F | 0;
G = G + this.G | 0;
H = H + this.H | 0;
this.set(A, B, C, D, E, F, G, H);
}
roundClean() {
clean(SHA256_W);
}
destroy() {
this.set(0, 0, 0, 0, 0, 0, 0, 0);
clean(this.buffer);
}
};
_SHA256 = class extends SHA2_32B {
// We cannot use array here since array allows indexing by variable
// which means optimizer/compiler cannot use registers.
A = SHA256_IV[0] | 0;
B = SHA256_IV[1] | 0;
C = SHA256_IV[2] | 0;
D = SHA256_IV[3] | 0;
E = SHA256_IV[4] | 0;
F = SHA256_IV[5] | 0;
G = SHA256_IV[6] | 0;
H = SHA256_IV[7] | 0;
constructor() {
super(32);
}
};
sha256 = /* @__PURE__ */ createHasher(
() => new _SHA256(),
/* @__PURE__ */ oidNist(1)
);
}
});
// node_modules/@noble/curves/utils.js
function abool(value, title = "") {
if (typeof value !== "boolean") {
const prefix = title && `"${title}" `;
throw new Error(prefix + "expected boolean, got type=" + typeof value);
}
return value;
}
function abignumber(n) {
if (typeof n === "bigint") {
if (!isPosBig(n))
throw new Error("positive bigint expected, got " + n);
} else
anumber(n);
return n;
}
function numberToHexUnpadded(num2) {
const hex = abignumber(num2).toString(16);
return hex.length & 1 ? "0" + hex : hex;
}
function hexToNumber(hex) {
if (typeof hex !== "string")
throw new Error("hex string expected, got " + typeof hex);
return hex === "" ? _0n : BigInt("0x" + hex);
}
function bytesToNumberBE(bytes) {
return hexToNumber(bytesToHex(bytes));
}
function bytesToNumberLE(bytes) {
return hexToNumber(bytesToHex(copyBytes(abytes(bytes)).reverse()));
}
function numberToBytesBE(n, len) {
anumber(len);
n = abignumber(n);
const res = hexToBytes(n.toString(16).padStart(len * 2, "0"));
if (res.length !== len)
throw new Error("number too large");
return res;
}
function numberToBytesLE(n, len) {
return numberToBytesBE(n, len).reverse();
}
function copyBytes(bytes) {
return Uint8Array.from(bytes);
}
function asciiToBytes(ascii) {
return Uint8Array.from(ascii, (c, i3) => {
const charCode = c.charCodeAt(0);
if (c.length !== 1 || charCode > 127) {
throw new Error(`string contains non-ASCII character "${ascii[i3]}" with code ${charCode} at position ${i3}`);
}
return charCode;
});
}
function inRange(n, min, max) {
return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max;
}
function aInRange(title, n, min, max) {
if (!inRange(n, min, max))
throw new Error("expected valid " + title + ": " + min + " <= n < " + max + ", got " + n);
}
function bitLen(n) {
let len;
for (len = 0; n > _0n; n >>= _1n, len += 1)
;
return len;
}
function createHmacDrbg(hashLen, qByteLen, hmacFn) {
anumber(hashLen, "hashLen");
anumber(qByteLen, "qByteLen");
if (typeof hmacFn !== "function")
throw new Error("hmacFn must be a function");
const u8n = (len) => new Uint8Array(len);
const NULL = Uint8Array.of();
const byte0 = Uint8Array.of(0);
const byte1 = Uint8Array.of(1);
const _maxDrbgIters = 1e3;
let v = u8n(hashLen);
let k = u8n(hashLen);
let i3 = 0;
const reset = () => {
v.fill(1);
k.fill(0);
i3 = 0;
};
const h = (...msgs) => hmacFn(k, concatBytes(v, ...msgs));
const reseed = (seed = NULL) => {
k = h(byte0, seed);
v = h();
if (seed.length === 0)
return;
k = h(byte1, seed);
v = h();
};
const gen = () => {
if (i3++ >= _maxDrbgIters)
throw new Error("drbg: tried max amount of iterations");
let len = 0;
const out = [];
while (len < qByteLen) {
v = h();
const sl = v.slice();
out.push(sl);
len += v.length;
}
return concatBytes(...out);
};
const genUntil = (seed, pred) => {
reset();
reseed(seed);
let res = void 0;
while (!(res = pred(gen())))
reseed();
reset();
return res;
};
return genUntil;
}
function validateObject(object, fields = {}, optFields = {}) {
if (!object || typeof object !== "object")
throw new Error("expected valid options object");
function checkField(fieldName, expectedType, isOpt) {
const val = object[fieldName];
if (isOpt && val === void 0)
return;
const current = typeof val;
if (current !== expectedType || val === null)
throw new Error(`param "${fieldName}" is invalid: expected ${expectedType}, got ${current}`);
}
const iter = (f, isOpt) => Object.entries(f).forEach(([k, v]) => checkField(k, v, isOpt));
iter(fields, false);
iter(optFields, true);
}
function memoized(fn) {
const map = /* @__PURE__ */ new WeakMap();
return (arg, ...args) => {
const val = map.get(arg);
if (val !== void 0)
return val;
const computed = fn(arg, ...args);
map.set(arg, computed);
return computed;
};
}
var _0n, _1n, isPosBig, bitMask;
var init_utils2 = __esm({
"node_modules/@noble/curves/utils.js"() {
init_utils();
init_utils();
_0n = /* @__PURE__ */ BigInt(0);
_1n = /* @__PURE__ */ BigInt(1);
isPosBig = (n) => typeof n === "bigint" && _0n <= n;
bitMask = (n) => (_1n << BigInt(n)) - _1n;
}
});
// node_modules/@noble/curves/abstract/modular.js
function mod(a, b) {
const result = a % b;
return result >= _0n2 ? result : b + result;
}
function pow2(x, power, modulo) {
let res = x;
while (power-- > _0n2) {
res *= res;
res %= modulo;
}
return res;
}
function invert(number, modulo) {
if (number === _0n2)
throw new Error("invert: expected non-zero number");
if (modulo <= _0n2)
throw new Error("invert: expected positive modulus, got " + modulo);
let a = mod(number, modulo);
let b = modulo;
let x = _0n2, y = _1n2, u = _1n2, v = _0n2;
while (a !== _0n2) {
const q = b / a;
const r = b % a;
const m = x - u * q;
const n = y - v * q;
b = a, a = r, x = u, y = v, u = m, v = n;
}
const gcd2 = b;
if (gcd2 !== _1n2)
throw new Error("invert: does not exist");
return mod(x, modulo);
}
function assertIsSquare(Fp, root, n) {
if (!Fp.eql(Fp.sqr(root), n))
throw new Error("Cannot find square root");
}
function sqrt3mod4(Fp, n) {
const p1div4 = (Fp.ORDER + _1n2) / _4n;
const root = Fp.pow(n, p1div4);
assertIsSquare(Fp, root, n);
return root;
}
function sqrt5mod8(Fp, n) {
const p5div8 = (Fp.ORDER - _5n) / _8n;
const n2 = Fp.mul(n, _2n);
const v = Fp.pow(n2, p5div8);
const nv = Fp.mul(n, v);
const i3 = Fp.mul(Fp.mul(nv, _2n), v);
const root = Fp.mul(nv, Fp.sub(i3, Fp.ONE));
assertIsSquare(Fp, root, n);
return root;
}
function sqrt9mod16(P) {
const Fp_ = Field(P);
const tn = tonelliShanks(P);
const c1 = tn(Fp_, Fp_.neg(Fp_.ONE));
const c2 = tn(Fp_, c1);
const c3 = tn(Fp_, Fp_.neg(c1));
const c4 = (P + _7n) / _16n;
return (Fp, n) => {
let tv1 = Fp.pow(n, c4);
let tv2 = Fp.mul(tv1, c1);
const tv3 = Fp.mul(tv1, c2);
const tv4 = Fp.mul(tv1, c3);
const e1 = Fp.eql(Fp.sqr(tv2), n);
const e2 = Fp.eql(Fp.sqr(tv3), n);
tv1 = Fp.cmov(tv1, tv2, e1);
tv2 = Fp.cmov(tv4, tv3, e2);
const e3 = Fp.eql(Fp.sqr(tv2), n);
const root = Fp.cmov(tv1, tv2, e3);
assertIsSquare(Fp, root, n);
return root;
};
}
function tonelliShanks(P) {
if (P < _3n)
throw new Error("sqrt is not defined for small field");
let Q = P - _1n2;
let S = 0;
while (Q % _2n === _0n2) {
Q /= _2n;
S++;
}
let Z = _2n;
const _Fp = Field(P);
while (FpLegendre(_Fp, Z) === 1) {
if (Z++ > 1e3)
throw new Error("Cannot find square root: probably non-prime P");
}
if (S === 1)
return sqrt3mod4;
let cc = _Fp.pow(Z, Q);
const Q1div2 = (Q + _1n2) / _2n;
return function tonelliSlow(Fp, n) {
if (Fp.is0(n))
return n;
if (FpLegendre(Fp, n) !== 1)
throw new Error("Cannot find square root");
let M2 = S;
let c = Fp.mul(Fp.ONE, cc);
let t = Fp.pow(n, Q);
let R = Fp.pow(n, Q1div2);
while (!Fp.eql(t, Fp.ONE)) {
if (Fp.is0(t))
return Fp.ZERO;
let i3 = 1;
let t_tmp = Fp.sqr(t);
while (!Fp.eql(t_tmp, Fp.ONE)) {
i3++;
t_tmp = Fp.sqr(t_tmp);
if (i3 === M2)
throw new Error("Cannot find square root");
}
const exponent = _1n2 << BigInt(M2 - i3 - 1);
const b = Fp.pow(c, exponent);
M2 = i3;
c = Fp.sqr(b);
t = Fp.mul(t, c);
R = Fp.mul(R, b);
}
return R;
};
}
function FpSqrt(P) {
if (P % _4n === _3n)
return sqrt3mod4;
if (P % _8n === _5n)
return sqrt5mod8;
if (P % _16n === _9n)
return sqrt9mod16(P);
return tonelliShanks(P);
}
function validateField(field) {
const initial = {
ORDER: "bigint",
BYTES: "number",
BITS: "number"
};
const opts = FIELD_FIELDS.reduce((map, val) => {
map[val] = "function";
return map;
}, initial);
validateObject(field, opts);
return field;
}
function FpPow(Fp, num2, power) {
if (power < _0n2)
throw new Error("invalid exponent, negatives unsupported");
if (power === _0n2)
return Fp.ONE;
if (power === _1n2)
return num2;
let p = Fp.ONE;
let d = num2;
while (power > _0n2) {
if (power & _1n2)
p = Fp.mul(p, d);
d = Fp.sqr(d);
power >>= _1n2;
}
return p;
}
function FpInvertBatch(Fp, nums, passZero = false) {
const inverted = new Array(nums.length).fill(passZero ? Fp.ZERO : void 0);
const multipliedAcc = nums.reduce((acc, num2, i3) => {
if (Fp.is0(num2))
return acc;
inverted[i3] = acc;
return Fp.mul(acc, num2);
}, Fp.ONE);
const invertedAcc = Fp.inv(multipliedAcc);
nums.reduceRight((acc, num2, i3) => {
if (Fp.is0(num2))
return acc;
inverted[i3] = Fp.mul(acc, inverted[i3]);
return Fp.mul(acc, num2);
}, invertedAcc);
return inverted;
}
function FpLegendre(Fp, n) {
const p1mod2 = (Fp.ORDER - _1n2) / _2n;
const powered = Fp.pow(n, p1mod2);
const yes = Fp.eql(powered, Fp.ONE);
const zero = Fp.eql(powered, Fp.ZERO);
const no = Fp.eql(powered, Fp.neg(Fp.ONE));
if (!yes && !zero && !no)
throw new Error("invalid Legendre symbol result");
return yes ? 1 : zero ? 0 : -1;
}
function nLength(n, nBitLength) {
if (nBitLength !== void 0)
anumber(nBitLength);
const _nBitLength = nBitLength !== void 0 ? nBitLength : n.toString(2).length;
const nByteLength = Math.ceil(_nBitLength / 8);
return { nBitLength: _nBitLength, nByteLength };
}
function Field(ORDER, opts = {}) {
return new _Field(ORDER, opts);
}
function getFieldBytesLength(fieldOrder) {
if (typeof fieldOrder !== "bigint")
throw new Error("field order must be bigint");
const bitLength = fieldOrder.toString(2).length;
return Math.ceil(bitLength / 8);
}
function getMinHashLength(fieldOrder) {
const length = getFieldBytesLength(fieldOrder);
return length + Math.ceil(length / 2);
}
function mapHashToField(key, fieldOrder, isLE2 = false) {
abytes(key);
const len = key.length;
const fieldLen = getFieldBytesLength(fieldOrder);
const minLen = getMinHashLength(fieldOrder);
if (len < 16 || len < minLen || len > 1024)
throw new Error("expected " + minLen + "-1024 bytes of input, got " + len);
const num2 = isLE2 ? bytesToNumberLE(key) : bytesToNumberBE(key);
const reduced = mod(num2, fieldOrder - _1n2) + _1n2;
return isLE2 ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);
}
var _0n2, _1n2, _2n, _3n, _4n, _5n, _7n, _8n, _9n, _16n, FIELD_FIELDS, _Field;
var init_modular = __esm({
"node_modules/@noble/curves/abstract/modular.js"() {
init_utils2();
_0n2 = /* @__PURE__ */ BigInt(0);
_1n2 = /* @__PURE__ */ BigInt(1);
_2n = /* @__PURE__ */ BigInt(2);
_3n = /* @__PURE__ */ BigInt(3);
_4n = /* @__PURE__ */ BigInt(4);
_5n = /* @__PURE__ */ BigInt(5);
_7n = /* @__PURE__ */ BigInt(7);
_8n = /* @__PURE__ */ BigInt(8);
_9n = /* @__PURE__ */ BigInt(9);
_16n = /* @__PURE__ */ BigInt(16);
FIELD_FIELDS = [
"create",
"isValid",
"is0",
"neg",
"inv",
"sqrt",
"sqr",
"eql",
"add",
"sub",
"mul",
"pow",
"div",
"addN",
"subN",
"mulN",
"sqrN"
];
_Field = class {
ORDER;
BITS;
BYTES;
isLE;
ZERO = _0n2;
ONE = _1n2;
_lengths;
_sqrt;
// cached sqrt
_mod;
constructor(ORDER, opts = {}) {
if (ORDER <= _0n2)
throw new Error("invalid field: expected ORDER > 0, got " + ORDER);
let _nbitLength = void 0;
this.isLE = false;
if (opts != null && typeof opts === "object") {
if (typeof opts.BITS === "number")
_nbitLength = opts.BITS;
if (typeof opts.sqrt === "function")
this.sqrt = opts.sqrt;
if (typeof opts.isLE === "boolean")
this.isLE = opts.isLE;
if (opts.allowedLengths)
this._lengths = opts.allowedLengths?.slice();
if (typeof opts.modFromBytes === "boolean")
this._mod = opts.modFromBytes;
}
const { nBitLength, nByteLength } = nLength(ORDER, _nbitLength);
if (nByteLength > 2048)
throw new Error("invalid field: expected ORDER of <= 2048 bytes");
this.ORDER = ORDER;
this.BITS = nBitLength;
this.BYTES = nByteLength;
this._sqrt = void 0;
Object.preventExtensions(this);
}
create(num2) {
return mod(num2, this.ORDER);
}
isValid(num2) {
if (typeof num2 !== "bigint")
throw new Error("invalid field element: expected bigint, got " + typeof num2);
return _0n2 <= num2 && num2 < this.ORDER;
}
is0(num2) {
return num2 === _0n2;
}
// is valid and invertible
isValidNot0(num2) {
return !this.is0(num2) && this.isValid(num2);
}
isOdd(num2) {
return (num2 & _1n2) === _1n2;
}
neg(num2) {
return mod(-num2, this.ORDER);
}
eql(lhs, rhs) {
return lhs === rhs;
}
sqr(num2) {
return mod(num2 * num2, this.ORDER);
}
add(lhs, rhs) {
return mod(lhs + rhs, this.ORDER);
}
sub(lhs, rhs) {
return mod(lhs - rhs, this.ORDER);
}
mul(lhs, rhs) {
return mod(lhs * rhs, this.ORDER);
}
pow(num2, power) {
return FpPow(this, num2, power);
}
div(lhs, rhs) {
return mod(lhs * invert(rhs, this.ORDER), this.ORDER);
}
// Same as above, but doesn't normalize
sqrN(num2) {
return num2 * num2;
}
addN(lhs, rhs) {
return lhs + rhs;
}
subN(lhs, rhs) {
return lhs - rhs;
}
mulN(lhs, rhs) {
return lhs * rhs;
}
inv(num2) {
return invert(num2, this.ORDER);
}
sqrt(num2) {
if (!this._sqrt)
this._sqrt = FpSqrt(this.ORDER);
return this._sqrt(this, num2);
}
toBytes(num2) {
return this.isLE ? numberToBytesLE(num2, this.BYTES) : numberToBytesBE(num2, this.BYTES);
}
fromBytes(bytes, skipValidation = false) {
abytes(bytes);
const { _lengths: allowedLengths, BYTES, isLE: isLE2, ORDER, _mod: modFromBytes } = this;
if (allowedLengths) {
if (!allowedLengths.includes(bytes.length) || bytes.length > BYTES) {
throw new Error("Field.fromBytes: expected " + allowedLengths + " bytes, got " + bytes.length);
}
const padded = new Uint8Array(BYTES);
padded.set(bytes, isLE2 ? 0 : padded.length - bytes.length);
bytes = padded;
}
if (bytes.length !== BYTES)
throw new Error("Field.fromBytes: expected " + BYTES + " bytes, got " + bytes.length);
let scalar = isLE2 ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
if (modFromBytes)
scalar = mod(scalar, ORDER);
if (!skipValidation) {
if (!this.isValid(scalar))
throw new Error("invalid field element: outside of range 0..ORDER");
}
return scalar;
}
// TODO: we don't need it here, move out to separate fn
invertBatch(lst) {
return FpInvertBatch(this, lst);
}
// We can't move this out because Fp6, Fp12 implement it
// and it's unclear what to return in there.
cmov(a, b, condition) {
return condition ? b : a;
}
};
}
});
// node_modules/@noble/curves/abstract/curve.js
function negateCt(condition, item) {
const neg = item.negate();
return condition ? neg : item;
}
function normalizeZ(c, points) {
const invertedZs = FpInvertBatch(c.Fp, points.map((p) => p.Z));
return points.map((p, i3) => c.fromAffine(p.toAffine(invertedZs[i3])));
}
function validateW(W, bits) {
if (!Number.isSafeInteger(W) || W <= 0 || W > bits)
throw new Error("invalid window size, expected [1.." + bits + "], got W=" + W);
}
function calcWOpts(W, scalarBits) {
validateW(W, scalarBits);
const windows = Math.ceil(scalarBits / W) + 1;
const windowSize = 2 ** (W - 1);
const maxNumber = 2 ** W;
const mask = bitMask(W);
const shiftBy = BigInt(W);
return { windows, windowSize, mask, maxNumber, shiftBy };
}
function calcOffsets(n, window2, wOpts) {
const { windowSize, mask, maxNumber, shiftBy } = wOpts;
let wbits = Number(n & mask);
let nextN = n >> shiftBy;
if (wbits > windowSize) {
wbits -= maxNumber;
nextN += _1n3;
}
const offsetStart = window2 * windowSize;
const offset = offsetStart + Math.abs(wbits) - 1;
const isZero = wbits === 0;
const isNeg = wbits < 0;
const isNegF = window2 % 2 !== 0;
const offsetF = offsetStart;
return { nextN, offset, isZero, isNeg, isNegF, offsetF };
}
function getW(P) {
return pointWindowSizes.get(P) || 1;
}
function assert0(n) {
if (n !== _0n3)
throw new Error("invalid wNAF");
}
function mulEndoUnsafe(Point, point, k1, k2) {
let acc = point;
let p1 = Point.ZERO;
let p2 = Point.ZERO;
while (k1 > _0n3 || k2 > _0n3) {
if (k1 & _1n3)
p1 = p1.add(acc);
if (k2 & _1n3)
p2 = p2.add(acc);
acc = acc.double();
k1 >>= _1n3;
k2 >>= _1n3;
}
return { p1, p2 };
}
function createField(order, field, isLE2) {
if (field) {
if (field.ORDER !== order)
throw new Error("Field.ORDER must match order: Fp == p, Fn == n");
validateField(field);
return field;
} else {
return Field(order, { isLE: isLE2 });
}
}
function createCurveFields(type, CURVE, curveOpts = {}, FpFnLE) {
if (FpFnLE === void 0)
FpFnLE = type === "edwards";
if (!CURVE || typeof CURVE !== "object")
throw new Error(`expected valid ${type} CURVE object`);
for (const p of ["p", "n", "h"]) {
const val = CURVE[p];
if (!(typeof val === "bigint" && val > _0n3))
throw new Error(`CURVE.${p} must be positive bigint`);
}
const Fp = createField(CURVE.p, curveOpts.Fp, FpFnLE);
const Fn = createField(CURVE.n, curveOpts.Fn, FpFnLE);
const _b = type === "weierstrass" ? "b" : "d";
const params = ["Gx", "Gy", "a", _b];
for (const p of params) {
if (!Fp.isValid(CURVE[p]))
throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`);
}
CURVE = Object.freeze(Object.assign({}, CURVE));
return { CURVE, Fp, Fn };
}
function createKeygen(randomSecretKey, getPublicKey3) {
return function keygen(seed) {
const secretKey = randomSecretKey(seed);
return { secretKey, publicKey: getPublicKey3(secretKey) };
};
}
var _0n3, _1n3, pointPrecomputes, pointWindowSizes, wNAF;
var init_curve = __esm({
"node_modules/@noble/curves/abstract/curve.js"() {
init_utils2();
init_modular();
_0n3 = /* @__PURE__ */ BigInt(0);
_1n3 = /* @__PURE__ */ BigInt(1);
pointPrecomputes = /* @__PURE__ */ new WeakMap();
pointWindowSizes = /* @__PURE__ */ new WeakMap();
wNAF = class {
BASE;
ZERO;
Fn;
bits;
// Parametrized with a given Point class (not individual point)
constructor(Point, bits) {
this.BASE = Point.BASE;
this.ZERO = Point.ZERO;
this.Fn = Point.Fn;
this.bits = bits;
}
// non-const time multiplication ladder
_unsafeLadder(elm, n, p = this.ZERO) {
let d = elm;
while (n > _0n3) {
if (n & _1n3)
p = p.add(d);
d = d.double();
n >>= _1n3;
}
return p;
}
/**
* Creates a wNAF precomputation window. Used for caching.
* Default window size is set by `utils.precompute()` and is equal to 8.
* Number of precomputed points depends on the curve size:
* 2^(𝑊1) * (Math.ceil(𝑛 / 𝑊) + 1), where:
* - 𝑊 is the window size
* - 𝑛 is the bitlength of the curve order.
* For a 256-bit curve and window size 8, the number of precomputed points is 128 * 33 = 4224.
* @param point Point instance
* @param W window size
* @returns precomputed point tables flattened to a single array
*/
precomputeWindow(point, W) {
const { windows, windowSize } = calcWOpts(W, this.bits);
const points = [];
let p = point;
let base = p;
for (let window2 = 0; window2 < windows; window2++) {
base = p;
points.push(base);
for (let i3 = 1; i3 < windowSize; i3++) {
base = base.add(p);
points.push(base);
}
p = base.double();
}
return points;
}
/**
* Implements ec multiplication using precomputed tables and w-ary non-adjacent form.
* More compact implementation:
* https://github.com/paulmillr/noble-secp256k1/blob/47cb1669b6e506ad66b35fe7d76132ae97465da2/index.ts#L502-L541
* @returns real and fake (for const-time) points
*/
wNAF(W, precomputes, n) {
if (!this.Fn.isValid(n))
throw new Error("invalid scalar");
let p = this.ZERO;
let f = this.BASE;
const wo = calcWOpts(W, this.bits);
for (let window2 = 0; window2 < wo.windows; window2++) {
const { nextN, offset, isZero, isNeg, isNegF, offsetF } = calcOffsets(n, window2, wo);
n = nextN;
if (isZero) {
f = f.add(negateCt(isNegF, precomputes[offsetF]));
} else {
p = p.add(negateCt(isNeg, precomputes[offset]));
}
}
assert0(n);
return { p, f };
}
/**
* Implements ec unsafe (non const-time) multiplication using precomputed tables and w-ary non-adjacent form.
* @param acc accumulator point to add result of multiplication
* @returns point
*/
wNAFUnsafe(W, precomputes, n, acc = this.ZERO) {
const wo = calcWOpts(W, this.bits);
for (let window2 = 0; window2 < wo.windows; window2++) {
if (n === _0n3)
break;
const { nextN, offset, isZero, isNeg } = calcOffsets(n, window2, wo);
n = nextN;
if (isZero) {
continue;
} else {
const item = precomputes[offset];
acc = acc.add(isNeg ? item.negate() : item);
}
}
assert0(n);
return acc;
}
getPrecomputes(W, point, transform) {
let comp = pointPrecomputes.get(point);
if (!comp) {
comp = this.precomputeWindow(point, W);
if (W !== 1) {
if (typeof transform === "function")
comp = transform(comp);
pointPrecomputes.set(point, comp);
}
}
return comp;
}
cached(point, scalar, transform) {
const W = getW(point);
return this.wNAF(W, this.getPrecomputes(W, point, transform), scalar);
}
unsafe(point, scalar, transform, prev) {
const W = getW(point);
if (W === 1)
return this._unsafeLadder(point, scalar, prev);
return this.wNAFUnsafe(W, this.getPrecomputes(W, point, transform), scalar, prev);
}
// We calculate precomputes for elliptic curve point multiplication
// using windowed method. This specifies window size and
// stores precomputed values. Usually only base point would be precomputed.
createCache(P, W) {
validateW(W, this.bits);
pointWindowSizes.set(P, W);
pointPrecomputes.delete(P);
}
hasCache(elm) {
return getW(elm) !== 1;
}
};
}
});
// node_modules/@noble/hashes/hmac.js
var _HMAC, hmac;
var init_hmac = __esm({
"node_modules/@noble/hashes/hmac.js"() {
init_utils();
_HMAC = class {
oHash;
iHash;
blockLen;
outputLen;
finished = false;
destroyed = false;
constructor(hash, key) {
ahash(hash);
abytes(key, void 0, "key");
this.iHash = hash.create();
if (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;
const blockLen = this.blockLen;
const pad2 = new Uint8Array(blockLen);
pad2.set(key.length > blockLen ? hash.create().update(key).digest() : key);
for (let i3 = 0; i3 < pad2.length; i3++)
pad2[i3] ^= 54;
this.iHash.update(pad2);
this.oHash = hash.create();
for (let i3 = 0; i3 < pad2.length; i3++)
pad2[i3] ^= 54 ^ 92;
this.oHash.update(pad2);
clean(pad2);
}
update(buf) {
aexists(this);
this.iHash.update(buf);
return this;
}
digestInto(out) {
aexists(this);
abytes(out, this.outputLen, "output");
this.finished = true;
this.iHash.digestInto(out);
this.oHash.update(out);
this.oHash.digestInto(out);
this.destroy();
}
digest() {
const out = new Uint8Array(this.oHash.outputLen);
this.digestInto(out);
return out;
}
_cloneInto(to) {
to ||= Object.create(Object.getPrototypeOf(this), {});
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
to = to;
to.finished = finished;
to.destroyed = destroyed;
to.blockLen = blockLen;
to.outputLen = outputLen;
to.oHash = oHash._cloneInto(to.oHash);
to.iHash = iHash._cloneInto(to.iHash);
return to;
}
clone() {
return this._cloneInto();
}
destroy() {
this.destroyed = true;
this.oHash.destroy();
this.iHash.destroy();
}
};
hmac = (hash, key, message) => new _HMAC(hash, key).update(message).digest();
hmac.create = (hash, key) => new _HMAC(hash, key);
}
});
// node_modules/@noble/curves/abstract/weierstrass.js
function _splitEndoScalar(k, basis, n) {
const [[a1, b1], [a2, b2]] = basis;
const c1 = divNearest(b2 * k, n);
const c2 = divNearest(-b1 * k, n);
let k1 = k - c1 * a1 - c2 * a2;
let k2 = -c1 * b1 - c2 * b2;
const k1neg = k1 < _0n4;
const k2neg = k2 < _0n4;
if (k1neg)
k1 = -k1;
if (k2neg)
k2 = -k2;
const MAX_NUM = bitMask(Math.ceil(bitLen(n) / 2)) + _1n4;
if (k1 < _0n4 || k1 >= MAX_NUM || k2 < _0n4 || k2 >= MAX_NUM) {
throw new Error("splitScalar (endomorphism): failed, k=" + k);
}
return { k1neg, k1, k2neg, k2 };
}
function validateSigFormat(format) {
if (!["compact", "recovered", "der"].includes(format))
throw new Error('Signature format must be "compact", "recovered", or "der"');
return format;
}
function validateSigOpts(opts, def) {
const optsn = {};
for (let optName of Object.keys(def)) {
optsn[optName] = opts[optName] === void 0 ? def[optName] : opts[optName];
}
abool(optsn.lowS, "lowS");
abool(optsn.prehash, "prehash");
if (optsn.format !== void 0)
validateSigFormat(optsn.format);
return optsn;
}
function weierstrass(params, extraOpts = {}) {
const validated = createCurveFields("weierstrass", params, extraOpts);
const { Fp, Fn } = validated;
let CURVE = validated.CURVE;
const { h: cofactor, n: CURVE_ORDER } = CURVE;
validateObject(extraOpts, {}, {
allowInfinityPoint: "boolean",
clearCofactor: "function",
isTorsionFree: "function",
fromBytes: "function",
toBytes: "function",
endo: "object"
});
const { endo } = extraOpts;
if (endo) {
if (!Fp.is0(CURVE.a) || typeof endo.beta !== "bigint" || !Array.isArray(endo.basises)) {
throw new Error('invalid endo: expected "beta": bigint and "basises": array');
}
}
const lengths = getWLengths(Fp, Fn);
function assertCompressionIsSupported() {
if (!Fp.isOdd)
throw new Error("compression is not supported: Field does not have .isOdd()");
}
function pointToBytes2(_c, point, isCompressed) {
const { x, y } = point.toAffine();
const bx = Fp.toBytes(x);
abool(isCompressed, "isCompressed");
if (isCompressed) {
assertCompressionIsSupported();
const hasEvenY = !Fp.isOdd(y);
return concatBytes(pprefix(hasEvenY), bx);
} else {
return concatBytes(Uint8Array.of(4), bx, Fp.toBytes(y));
}
}
function pointFromBytes(bytes) {
abytes(bytes, void 0, "Point");
const { publicKey: comp, publicKeyUncompressed: uncomp } = lengths;
const length = bytes.length;
const head = bytes[0];
const tail = bytes.subarray(1);
if (length === comp && (head === 2 || head === 3)) {
const x = Fp.fromBytes(tail);
if (!Fp.isValid(x))
throw new Error("bad point: is not on curve, wrong x");
const y2 = weierstrassEquation(x);
let y;
try {
y = Fp.sqrt(y2);
} catch (sqrtError) {
const err = sqrtError instanceof Error ? ": " + sqrtError.message : "";
throw new Error("bad point: is not on curve, sqrt error" + err);
}
assertCompressionIsSupported();
const evenY = Fp.isOdd(y);
const evenH = (head & 1) === 1;
if (evenH !== evenY)
y = Fp.neg(y);
return { x, y };
} else if (length === uncomp && head === 4) {
const L = Fp.BYTES;
const x = Fp.fromBytes(tail.subarray(0, L));
const y = Fp.fromBytes(tail.subarray(L, L * 2));
if (!isValidXY(x, y))
throw new Error("bad point: is not on curve");
return { x, y };
} else {
throw new Error(`bad point: got length ${length}, expected compressed=${comp} or uncompressed=${uncomp}`);
}
}
const encodePoint = extraOpts.toBytes || pointToBytes2;
const decodePoint = extraOpts.fromBytes || pointFromBytes;
function weierstrassEquation(x) {
const x2 = Fp.sqr(x);
const x3 = Fp.mul(x2, x);
return Fp.add(Fp.add(x3, Fp.mul(x, CURVE.a)), CURVE.b);
}
function isValidXY(x, y) {
const left = Fp.sqr(y);
const right = weierstrassEquation(x);
return Fp.eql(left, right);
}
if (!isValidXY(CURVE.Gx, CURVE.Gy))
throw new Error("bad curve params: generator point");
const _4a3 = Fp.mul(Fp.pow(CURVE.a, _3n2), _4n2);
const _27b2 = Fp.mul(Fp.sqr(CURVE.b), BigInt(27));
if (Fp.is0(Fp.add(_4a3, _27b2)))
throw new Error("bad curve params: a or b");
function acoord(title, n, banZero = false) {
if (!Fp.isValid(n) || banZero && Fp.is0(n))
throw new Error(`bad point coordinate ${title}`);
return n;
}
function aprjpoint(other) {
if (!(other instanceof Point))
throw new Error("Weierstrass Point expected");
}
function splitEndoScalarN(k) {
if (!endo || !endo.basises)
throw new Error("no endo");
return _splitEndoScalar(k, endo.basises, Fn.ORDER);
}
const toAffineMemo = memoized((p, iz) => {
const { X, Y, Z } = p;
if (Fp.eql(Z, Fp.ONE))
return { x: X, y: Y };
const is0 = p.is0();
if (iz == null)
iz = is0 ? Fp.ONE : Fp.inv(Z);
const x = Fp.mul(X, iz);
const y = Fp.mul(Y, iz);
const zz = Fp.mul(Z, iz);
if (is0)
return { x: Fp.ZERO, y: Fp.ZERO };
if (!Fp.eql(zz, Fp.ONE))
throw new Error("invZ was invalid");
return { x, y };
});
const assertValidMemo = memoized((p) => {
if (p.is0()) {
if (extraOpts.allowInfinityPoint && !Fp.is0(p.Y))
return;
throw new Error("bad point: ZERO");
}
const { x, y } = p.toAffine();
if (!Fp.isValid(x) || !Fp.isValid(y))
throw new Error("bad point: x or y not field elements");
if (!isValidXY(x, y))
throw new Error("bad point: equation left != right");
if (!p.isTorsionFree())
throw new Error("bad point: not in prime-order subgroup");
return true;
});
function finishEndo(endoBeta, k1p, k2p, k1neg, k2neg) {
k2p = new Point(Fp.mul(k2p.X, endoBeta), k2p.Y, k2p.Z);
k1p = negateCt(k1neg, k1p);
k2p = negateCt(k2neg, k2p);
return k1p.add(k2p);
}
class Point {
// base / generator point
static BASE = new Point(CURVE.Gx, CURVE.Gy, Fp.ONE);
// zero / infinity / identity point
static ZERO = new Point(Fp.ZERO, Fp.ONE, Fp.ZERO);
// 0, 1, 0
// math field
static Fp = Fp;
// scalar field
static Fn = Fn;
X;
Y;
Z;
/** Does NOT validate if the point is valid. Use `.assertValidity()`. */
constructor(X, Y, Z) {
this.X = acoord("x", X);
this.Y = acoord("y", Y, true);
this.Z = acoord("z", Z);
Object.freeze(this);
}
static CURVE() {
return CURVE;
}
/** Does NOT validate if the point is valid. Use `.assertValidity()`. */
static fromAffine(p) {
const { x, y } = p || {};
if (!p || !Fp.isValid(x) || !Fp.isValid(y))
throw new Error("invalid affine point");
if (p instanceof Point)
throw new Error("projective point not allowed");
if (Fp.is0(x) && Fp.is0(y))
return Point.ZERO;
return new Point(x, y, Fp.ONE);
}
static fromBytes(bytes) {
const P = Point.fromAffine(decodePoint(abytes(bytes, void 0, "point")));
P.assertValidity();
return P;
}
static fromHex(hex) {
return Point.fromBytes(hexToBytes(hex));
}
get x() {
return this.toAffine().x;
}
get y() {
return this.toAffine().y;
}
/**
*
* @param windowSize
* @param isLazy true will defer table computation until the first multiplication
* @returns
*/
precompute(windowSize = 8, isLazy = true) {
wnaf.createCache(this, windowSize);
if (!isLazy)
this.multiply(_3n2);
return this;
}
// TODO: return `this`
/** A point on curve is valid if it conforms to equation. */
assertValidity() {
assertValidMemo(this);
}
hasEvenY() {
const { y } = this.toAffine();
if (!Fp.isOdd)
throw new Error("Field doesn't support isOdd");
return !Fp.isOdd(y);
}
/** Compare one point to another. */
equals(other) {
aprjpoint(other);
const { X: X1, Y: Y1, Z: Z1 } = this;
const { X: X2, Y: Y2, Z: Z2 } = other;
const U1 = Fp.eql(Fp.mul(X1, Z2), Fp.mul(X2, Z1));
const U2 = Fp.eql(Fp.mul(Y1, Z2), Fp.mul(Y2, Z1));
return U1 && U2;
}
/** Flips point to one corresponding to (x, -y) in Affine coordinates. */
negate() {
return new Point(this.X, Fp.neg(this.Y), this.Z);
}
// Renes-Costello-Batina exception-free doubling formula.
// There is 30% faster Jacobian formula, but it is not complete.
// https://eprint.iacr.org/2015/1060, algorithm 3
// Cost: 8M + 3S + 3*a + 2*b3 + 15add.
double() {
const { a, b } = CURVE;
const b3 = Fp.mul(b, _3n2);
const { X: X1, Y: Y1, Z: Z1 } = this;
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO;
let t0 = Fp.mul(X1, X1);
let t1 = Fp.mul(Y1, Y1);
let t2 = Fp.mul(Z1, Z1);
let t3 = Fp.mul(X1, Y1);
t3 = Fp.add(t3, t3);
Z3 = Fp.mul(X1, Z1);
Z3 = Fp.add(Z3, Z3);
X3 = Fp.mul(a, Z3);
Y3 = Fp.mul(b3, t2);
Y3 = Fp.add(X3, Y3);
X3 = Fp.sub(t1, Y3);
Y3 = Fp.add(t1, Y3);
Y3 = Fp.mul(X3, Y3);
X3 = Fp.mul(t3, X3);
Z3 = Fp.mul(b3, Z3);
t2 = Fp.mul(a, t2);
t3 = Fp.sub(t0, t2);
t3 = Fp.mul(a, t3);
t3 = Fp.add(t3, Z3);
Z3 = Fp.add(t0, t0);
t0 = Fp.add(Z3, t0);
t0 = Fp.add(t0, t2);
t0 = Fp.mul(t0, t3);
Y3 = Fp.add(Y3, t0);
t2 = Fp.mul(Y1, Z1);
t2 = Fp.add(t2, t2);
t0 = Fp.mul(t2, t3);
X3 = Fp.sub(X3, t0);
Z3 = Fp.mul(t2, t1);
Z3 = Fp.add(Z3, Z3);
Z3 = Fp.add(Z3, Z3);
return new Point(X3, Y3, Z3);
}
// Renes-Costello-Batina exception-free addition formula.
// There is 30% faster Jacobian formula, but it is not complete.
// https://eprint.iacr.org/2015/1060, algorithm 1
// Cost: 12M + 0S + 3*a + 3*b3 + 23add.
add(other) {
aprjpoint(other);
const { X: X1, Y: Y1, Z: Z1 } = this;
const { X: X2, Y: Y2, Z: Z2 } = other;
let X3 = Fp.ZERO, Y3 = Fp.ZERO, Z3 = Fp.ZERO;
const a = CURVE.a;
const b3 = Fp.mul(CURVE.b, _3n2);
let t0 = Fp.mul(X1, X2);
let t1 = Fp.mul(Y1, Y2);
let t2 = Fp.mul(Z1, Z2);
let t3 = Fp.add(X1, Y1);
let t4 = Fp.add(X2, Y2);
t3 = Fp.mul(t3, t4);
t4 = Fp.add(t0, t1);
t3 = Fp.sub(t3, t4);
t4 = Fp.add(X1, Z1);
let t5 = Fp.add(X2, Z2);
t4 = Fp.mul(t4, t5);
t5 = Fp.add(t0, t2);
t4 = Fp.sub(t4, t5);
t5 = Fp.add(Y1, Z1);
X3 = Fp.add(Y2, Z2);
t5 = Fp.mul(t5, X3);
X3 = Fp.add(t1, t2);
t5 = Fp.sub(t5, X3);
Z3 = Fp.mul(a, t4);
X3 = Fp.mul(b3, t2);
Z3 = Fp.add(X3, Z3);
X3 = Fp.sub(t1, Z3);
Z3 = Fp.add(t1, Z3);
Y3 = Fp.mul(X3, Z3);
t1 = Fp.add(t0, t0);
t1 = Fp.add(t1, t0);
t2 = Fp.mul(a, t2);
t4 = Fp.mul(b3, t4);
t1 = Fp.add(t1, t2);
t2 = Fp.sub(t0, t2);
t2 = Fp.mul(a, t2);
t4 = Fp.add(t4, t2);
t0 = Fp.mul(t1, t4);
Y3 = Fp.add(Y3, t0);
t0 = Fp.mul(t5, t4);
X3 = Fp.mul(t3, X3);
X3 = Fp.sub(X3, t0);
t0 = Fp.mul(t3, t1);
Z3 = Fp.mul(t5, Z3);
Z3 = Fp.add(Z3, t0);
return new Point(X3, Y3, Z3);
}
subtract(other) {
return this.add(other.negate());
}
is0() {
return this.equals(Point.ZERO);
}
/**
* Constant time multiplication.
* Uses wNAF method. Windowed method may be 10% faster,
* but takes 2x longer to generate and consumes 2x memory.
* Uses precomputes when available.
* Uses endomorphism for Koblitz curves.
* @param scalar by which the point would be multiplied
* @returns New point
*/
multiply(scalar) {
const { endo: endo2 } = extraOpts;
if (!Fn.isValidNot0(scalar))
throw new Error("invalid scalar: out of range");
let point, fake;
const mul = (n) => wnaf.cached(this, n, (p) => normalizeZ(Point, p));
if (endo2) {
const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(scalar);
const { p: k1p, f: k1f } = mul(k1);
const { p: k2p, f: k2f } = mul(k2);
fake = k1f.add(k2f);
point = finishEndo(endo2.beta, k1p, k2p, k1neg, k2neg);
} else {
const { p, f } = mul(scalar);
point = p;
fake = f;
}
return normalizeZ(Point, [point, fake])[0];
}
/**
* Non-constant-time multiplication. Uses double-and-add algorithm.
* It's faster, but should only be used when you don't care about
* an exposed secret key e.g. sig verification, which works over *public* keys.
*/
multiplyUnsafe(sc) {
const { endo: endo2 } = extraOpts;
const p = this;
if (!Fn.isValid(sc))
throw new Error("invalid scalar: out of range");
if (sc === _0n4 || p.is0())
return Point.ZERO;
if (sc === _1n4)
return p;
if (wnaf.hasCache(this))
return this.multiply(sc);
if (endo2) {
const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(sc);
const { p1, p2 } = mulEndoUnsafe(Point, p, k1, k2);
return finishEndo(endo2.beta, p1, p2, k1neg, k2neg);
} else {
return wnaf.unsafe(p, sc);
}
}
/**
* Converts Projective point to affine (x, y) coordinates.
* @param invertedZ Z^-1 (inverted zero) - optional, precomputation is useful for invertBatch
*/
toAffine(invertedZ) {
return toAffineMemo(this, invertedZ);
}
/**
* Checks whether Point is free of torsion elements (is in prime subgroup).
* Always torsion-free for cofactor=1 curves.
*/
isTorsionFree() {
const { isTorsionFree } = extraOpts;
if (cofactor === _1n4)
return true;
if (isTorsionFree)
return isTorsionFree(Point, this);
return wnaf.unsafe(this, CURVE_ORDER).is0();
}
clearCofactor() {
const { clearCofactor } = extraOpts;
if (cofactor === _1n4)
return this;
if (clearCofactor)
return clearCofactor(Point, this);
return this.multiplyUnsafe(cofactor);
}
isSmallOrder() {
return this.multiplyUnsafe(cofactor).is0();
}
toBytes(isCompressed = true) {
abool(isCompressed, "isCompressed");
this.assertValidity();
return encodePoint(Point, this, isCompressed);
}
toHex(isCompressed = true) {
return bytesToHex(this.toBytes(isCompressed));
}
toString() {
return `<Point ${this.is0() ? "ZERO" : this.toHex()}>`;
}
}
const bits = Fn.BITS;
const wnaf = new wNAF(Point, extraOpts.endo ? Math.ceil(bits / 2) : bits);
Point.BASE.precompute(8);
return Point;
}
function pprefix(hasEvenY) {
return Uint8Array.of(hasEvenY ? 2 : 3);
}
function getWLengths(Fp, Fn) {
return {
secretKey: Fn.BYTES,
publicKey: 1 + Fp.BYTES,
publicKeyUncompressed: 1 + 2 * Fp.BYTES,
publicKeyHasPrefix: true,
signature: 2 * Fn.BYTES
};
}
function ecdh(Point, ecdhOpts = {}) {
const { Fn } = Point;
const randomBytes_ = ecdhOpts.randomBytes || randomBytes;
const lengths = Object.assign(getWLengths(Point.Fp, Fn), { seed: getMinHashLength(Fn.ORDER) });
function isValidSecretKey(secretKey) {
try {
const num2 = Fn.fromBytes(secretKey);
return Fn.isValidNot0(num2);
} catch (error2) {
return false;
}
}
function isValidPublicKey(publicKey, isCompressed) {
const { publicKey: comp, publicKeyUncompressed } = lengths;
try {
const l = publicKey.length;
if (isCompressed === true && l !== comp)
return false;
if (isCompressed === false && l !== publicKeyUncompressed)
return false;
return !!Point.fromBytes(publicKey);
} catch (error2) {
return false;
}
}
function randomSecretKey(seed = randomBytes_(lengths.seed)) {
return mapHashToField(abytes(seed, lengths.seed, "seed"), Fn.ORDER);
}
function getPublicKey3(secretKey, isCompressed = true) {
return Point.BASE.multiply(Fn.fromBytes(secretKey)).toBytes(isCompressed);
}
function isProbPub(item) {
const { secretKey, publicKey, publicKeyUncompressed } = lengths;
if (!isBytes(item))
return void 0;
if ("_lengths" in Fn && Fn._lengths || secretKey === publicKey)
return void 0;
const l = abytes(item, void 0, "key").length;
return l === publicKey || l === publicKeyUncompressed;
}
function getSharedSecret(secretKeyA, publicKeyB, isCompressed = true) {
if (isProbPub(secretKeyA) === true)
throw new Error("first arg must be private key");
if (isProbPub(publicKeyB) === false)
throw new Error("second arg must be public key");
const s = Fn.fromBytes(secretKeyA);
const b = Point.fromBytes(publicKeyB);
return b.multiply(s).toBytes(isCompressed);
}
const utils = {
isValidSecretKey,
isValidPublicKey,
randomSecretKey
};
const keygen = createKeygen(randomSecretKey, getPublicKey3);
return Object.freeze({ getPublicKey: getPublicKey3, getSharedSecret, keygen, Point, utils, lengths });
}
function ecdsa(Point, hash, ecdsaOpts = {}) {
ahash(hash);
validateObject(ecdsaOpts, {}, {
hmac: "function",
lowS: "boolean",
randomBytes: "function",
bits2int: "function",
bits2int_modN: "function"
});
ecdsaOpts = Object.assign({}, ecdsaOpts);
const randomBytes3 = ecdsaOpts.randomBytes || randomBytes;
const hmac2 = ecdsaOpts.hmac || ((key, msg) => hmac(hash, key, msg));
const { Fp, Fn } = Point;
const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
const { keygen, getPublicKey: getPublicKey3, getSharedSecret, utils, lengths } = ecdh(Point, ecdsaOpts);
const defaultSigOpts = {
prehash: true,
lowS: typeof ecdsaOpts.lowS === "boolean" ? ecdsaOpts.lowS : true,
format: "compact",
extraEntropy: false
};
const hasLargeCofactor = CURVE_ORDER * _2n2 < Fp.ORDER;
function isBiggerThanHalfOrder(number) {
const HALF = CURVE_ORDER >> _1n4;
return number > HALF;
}
function validateRS(title, num2) {
if (!Fn.isValidNot0(num2))
throw new Error(`invalid signature ${title}: out of range 1..Point.Fn.ORDER`);
return num2;
}
function assertSmallCofactor() {
if (hasLargeCofactor)
throw new Error('"recovered" sig type is not supported for cofactor >2 curves');
}
function validateSigLength(bytes, format) {
validateSigFormat(format);
const size = lengths.signature;
const sizer = format === "compact" ? size : format === "recovered" ? size + 1 : void 0;
return abytes(bytes, sizer);
}
class Signature {
r;
s;
recovery;
constructor(r, s, recovery) {
this.r = validateRS("r", r);
this.s = validateRS("s", s);
if (recovery != null) {
assertSmallCofactor();
if (![0, 1, 2, 3].includes(recovery))
throw new Error("invalid recovery id");
this.recovery = recovery;
}
Object.freeze(this);
}
static fromBytes(bytes, format = defaultSigOpts.format) {
validateSigLength(bytes, format);
let recid;
if (format === "der") {
const { r: r2, s: s2 } = DER.toSig(abytes(bytes));
return new Signature(r2, s2);
}
if (format === "recovered") {
recid = bytes[0];
format = "compact";
bytes = bytes.subarray(1);
}
const L = lengths.signature / 2;
const r = bytes.subarray(0, L);
const s = bytes.subarray(L, L * 2);
return new Signature(Fn.fromBytes(r), Fn.fromBytes(s), recid);
}
static fromHex(hex, format) {
return this.fromBytes(hexToBytes(hex), format);
}
assertRecovery() {
const { recovery } = this;
if (recovery == null)
throw new Error("invalid recovery id: must be present");
return recovery;
}
addRecoveryBit(recovery) {
return new Signature(this.r, this.s, recovery);
}
recoverPublicKey(messageHash) {
const { r, s } = this;
const recovery = this.assertRecovery();
const radj = recovery === 2 || recovery === 3 ? r + CURVE_ORDER : r;
if (!Fp.isValid(radj))
throw new Error("invalid recovery id: sig.r+curve.n != R.x");
const x = Fp.toBytes(radj);
const R = Point.fromBytes(concatBytes(pprefix((recovery & 1) === 0), x));
const ir = Fn.inv(radj);
const h = bits2int_modN(abytes(messageHash, void 0, "msgHash"));
const u1 = Fn.create(-h * ir);
const u2 = Fn.create(s * ir);
const Q = Point.BASE.multiplyUnsafe(u1).add(R.multiplyUnsafe(u2));
if (Q.is0())
throw new Error("invalid recovery: point at infinify");
Q.assertValidity();
return Q;
}
// Signatures should be low-s, to prevent malleability.
hasHighS() {
return isBiggerThanHalfOrder(this.s);
}
toBytes(format = defaultSigOpts.format) {
validateSigFormat(format);
if (format === "der")
return hexToBytes(DER.hexFromSig(this));
const { r, s } = this;
const rb = Fn.toBytes(r);
const sb = Fn.toBytes(s);
if (format === "recovered") {
assertSmallCofactor();
return concatBytes(Uint8Array.of(this.assertRecovery()), rb, sb);
}
return concatBytes(rb, sb);
}
toHex(format) {
return bytesToHex(this.toBytes(format));
}
}
const bits2int = ecdsaOpts.bits2int || function bits2int_def(bytes) {
if (bytes.length > 8192)
throw new Error("input is too large");
const num2 = bytesToNumberBE(bytes);
const delta = bytes.length * 8 - fnBits;
return delta > 0 ? num2 >> BigInt(delta) : num2;
};
const bits2int_modN = ecdsaOpts.bits2int_modN || function bits2int_modN_def(bytes) {
return Fn.create(bits2int(bytes));
};
const ORDER_MASK = bitMask(fnBits);
function int2octets(num2) {
aInRange("num < 2^" + fnBits, num2, _0n4, ORDER_MASK);
return Fn.toBytes(num2);
}
function validateMsgAndHash(message, prehash) {
abytes(message, void 0, "message");
return prehash ? abytes(hash(message), void 0, "prehashed message") : message;
}
function prepSig(message, secretKey, opts) {
const { lowS, prehash, extraEntropy } = validateSigOpts(opts, defaultSigOpts);
message = validateMsgAndHash(message, prehash);
const h1int = bits2int_modN(message);
const d = Fn.fromBytes(secretKey);
if (!Fn.isValidNot0(d))
throw new Error("invalid private key");
const seedArgs = [int2octets(d), int2octets(h1int)];
if (extraEntropy != null && extraEntropy !== false) {
const e = extraEntropy === true ? randomBytes3(lengths.secretKey) : extraEntropy;
seedArgs.push(abytes(e, void 0, "extraEntropy"));
}
const seed = concatBytes(...seedArgs);
const m = h1int;
function k2sig(kBytes) {
const k = bits2int(kBytes);
if (!Fn.isValidNot0(k))
return;
const ik = Fn.inv(k);
const q = Point.BASE.multiply(k).toAffine();
const r = Fn.create(q.x);
if (r === _0n4)
return;
const s = Fn.create(ik * Fn.create(m + r * d));
if (s === _0n4)
return;
let recovery = (q.x === r ? 0 : 2) | Number(q.y & _1n4);
let normS = s;
if (lowS && isBiggerThanHalfOrder(s)) {
normS = Fn.neg(s);
recovery ^= 1;
}
return new Signature(r, normS, hasLargeCofactor ? void 0 : recovery);
}
return { seed, k2sig };
}
function sign(message, secretKey, opts = {}) {
const { seed, k2sig } = prepSig(message, secretKey, opts);
const drbg = createHmacDrbg(hash.outputLen, Fn.BYTES, hmac2);
const sig = drbg(seed, k2sig);
return sig.toBytes(opts.format);
}
function verify(signature, message, publicKey, opts = {}) {
const { lowS, prehash, format } = validateSigOpts(opts, defaultSigOpts);
publicKey = abytes(publicKey, void 0, "publicKey");
message = validateMsgAndHash(message, prehash);
if (!isBytes(signature)) {
const end = signature instanceof Signature ? ", use sig.toBytes()" : "";
throw new Error("verify expects Uint8Array signature" + end);
}
validateSigLength(signature, format);
try {
const sig = Signature.fromBytes(signature, format);
const P = Point.fromBytes(publicKey);
if (lowS && sig.hasHighS())
return false;
const { r, s } = sig;
const h = bits2int_modN(message);
const is = Fn.inv(s);
const u1 = Fn.create(h * is);
const u2 = Fn.create(r * is);
const R = Point.BASE.multiplyUnsafe(u1).add(P.multiplyUnsafe(u2));
if (R.is0())
return false;
const v = Fn.create(R.x);
return v === r;
} catch (e) {
return false;
}
}
function recoverPublicKey(signature, message, opts = {}) {
const { prehash } = validateSigOpts(opts, defaultSigOpts);
message = validateMsgAndHash(message, prehash);
return Signature.fromBytes(signature, "recovered").recoverPublicKey(message).toBytes();
}
return Object.freeze({
keygen,
getPublicKey: getPublicKey3,
getSharedSecret,
utils,
lengths,
Point,
sign,
verify,
recoverPublicKey,
Signature,
hash
});
}
var divNearest, DERErr, DER, _0n4, _1n4, _2n2, _3n2, _4n2;
var init_weierstrass = __esm({
"node_modules/@noble/curves/abstract/weierstrass.js"() {
init_hmac();
init_utils();
init_utils2();
init_curve();
init_modular();
divNearest = (num2, den) => (num2 + (num2 >= 0 ? den : -den) / _2n2) / den;
DERErr = class extends Error {
constructor(m = "") {
super(m);
}
};
DER = {
// asn.1 DER encoding utils
Err: DERErr,
// Basic building block is TLV (Tag-Length-Value)
_tlv: {
encode: (tag, data) => {
const { Err: E } = DER;
if (tag < 0 || tag > 256)
throw new E("tlv.encode: wrong tag");
if (data.length & 1)
throw new E("tlv.encode: unpadded data");
const dataLen = data.length / 2;
const len = numberToHexUnpadded(dataLen);
if (len.length / 2 & 128)
throw new E("tlv.encode: long form length too big");
const lenLen = dataLen > 127 ? numberToHexUnpadded(len.length / 2 | 128) : "";
const t = numberToHexUnpadded(tag);
return t + lenLen + len + data;
},
// v - value, l - left bytes (unparsed)
decode(tag, data) {
const { Err: E } = DER;
let pos = 0;
if (tag < 0 || tag > 256)
throw new E("tlv.encode: wrong tag");
if (data.length < 2 || data[pos++] !== tag)
throw new E("tlv.decode: wrong tlv");
const first = data[pos++];
const isLong = !!(first & 128);
let length = 0;
if (!isLong)
length = first;
else {
const lenLen = first & 127;
if (!lenLen)
throw new E("tlv.decode(long): indefinite length not supported");
if (lenLen > 4)
throw new E("tlv.decode(long): byte length is too big");
const lengthBytes = data.subarray(pos, pos + lenLen);
if (lengthBytes.length !== lenLen)
throw new E("tlv.decode: length bytes not complete");
if (lengthBytes[0] === 0)
throw new E("tlv.decode(long): zero leftmost byte");
for (const b of lengthBytes)
length = length << 8 | b;
pos += lenLen;
if (length < 128)
throw new E("tlv.decode(long): not minimal encoding");
}
const v = data.subarray(pos, pos + length);
if (v.length !== length)
throw new E("tlv.decode: wrong value length");
return { v, l: data.subarray(pos + length) };
}
},
// https://crypto.stackexchange.com/a/57734 Leftmost bit of first byte is 'negative' flag,
// since we always use positive integers here. It must always be empty:
// - add zero byte if exists
// - if next byte doesn't have a flag, leading zero is not allowed (minimal encoding)
_int: {
encode(num2) {
const { Err: E } = DER;
if (num2 < _0n4)
throw new E("integer: negative integers are not allowed");
let hex = numberToHexUnpadded(num2);
if (Number.parseInt(hex[0], 16) & 8)
hex = "00" + hex;
if (hex.length & 1)
throw new E("unexpected DER parsing assertion: unpadded hex");
return hex;
},
decode(data) {
const { Err: E } = DER;
if (data[0] & 128)
throw new E("invalid signature integer: negative");
if (data[0] === 0 && !(data[1] & 128))
throw new E("invalid signature integer: unnecessary leading zero");
return bytesToNumberBE(data);
}
},
toSig(bytes) {
const { Err: E, _int: int, _tlv: tlv } = DER;
const data = abytes(bytes, void 0, "signature");
const { v: seqBytes, l: seqLeftBytes } = tlv.decode(48, data);
if (seqLeftBytes.length)
throw new E("invalid signature: left bytes after parsing");
const { v: rBytes, l: rLeftBytes } = tlv.decode(2, seqBytes);
const { v: sBytes, l: sLeftBytes } = tlv.decode(2, rLeftBytes);
if (sLeftBytes.length)
throw new E("invalid signature: left bytes after parsing");
return { r: int.decode(rBytes), s: int.decode(sBytes) };
},
hexFromSig(sig) {
const { _tlv: tlv, _int: int } = DER;
const rs = tlv.encode(2, int.encode(sig.r));
const ss = tlv.encode(2, int.encode(sig.s));
const seq = rs + ss;
return tlv.encode(48, seq);
}
};
_0n4 = BigInt(0);
_1n4 = BigInt(1);
_2n2 = BigInt(2);
_3n2 = BigInt(3);
_4n2 = BigInt(4);
}
});
// node_modules/@noble/curves/secp256k1.js
function sqrtMod(y) {
const P = secp256k1_CURVE.p;
const _3n3 = BigInt(3), _6n = BigInt(6), _11n = BigInt(11), _22n = BigInt(22);
const _23n = BigInt(23), _44n = BigInt(44), _88n = BigInt(88);
const b2 = y * y * y % P;
const b3 = b2 * b2 * y % P;
const b6 = pow2(b3, _3n3, P) * b3 % P;
const b9 = pow2(b6, _3n3, P) * b3 % P;
const b11 = pow2(b9, _2n3, P) * b2 % P;
const b22 = pow2(b11, _11n, P) * b11 % P;
const b44 = pow2(b22, _22n, P) * b22 % P;
const b88 = pow2(b44, _44n, P) * b44 % P;
const b176 = pow2(b88, _88n, P) * b88 % P;
const b220 = pow2(b176, _44n, P) * b44 % P;
const b223 = pow2(b220, _3n3, P) * b3 % P;
const t1 = pow2(b223, _23n, P) * b22 % P;
const t2 = pow2(t1, _6n, P) * b2 % P;
const root = pow2(t2, _2n3, P);
if (!Fpk1.eql(Fpk1.sqr(root), y))
throw new Error("Cannot find square root");
return root;
}
function taggedHash(tag, ...messages) {
let tagP = TAGGED_HASH_PREFIXES[tag];
if (tagP === void 0) {
const tagH = sha256(asciiToBytes(tag));
tagP = concatBytes(tagH, tagH);
TAGGED_HASH_PREFIXES[tag] = tagP;
}
return sha256(concatBytes(tagP, ...messages));
}
function schnorrGetExtPubKey(priv) {
const { Fn, BASE } = Pointk1;
const d_ = Fn.fromBytes(priv);
const p = BASE.multiply(d_);
const scalar = hasEven(p.y) ? d_ : Fn.neg(d_);
return { scalar, bytes: pointToBytes(p) };
}
function lift_x(x) {
const Fp = Fpk1;
if (!Fp.isValidNot0(x))
throw new Error("invalid x: Fail if x \u2265 p");
const xx = Fp.create(x * x);
const c = Fp.create(xx * x + BigInt(7));
let y = Fp.sqrt(c);
if (!hasEven(y))
y = Fp.neg(y);
const p = Pointk1.fromAffine({ x, y });
p.assertValidity();
return p;
}
function challenge(...args) {
return Pointk1.Fn.create(num(taggedHash("BIP0340/challenge", ...args)));
}
function schnorrGetPublicKey(secretKey) {
return schnorrGetExtPubKey(secretKey).bytes;
}
function schnorrSign(message, secretKey, auxRand = randomBytes(32)) {
const { Fn } = Pointk1;
const m = abytes(message, void 0, "message");
const { bytes: px, scalar: d } = schnorrGetExtPubKey(secretKey);
const a = abytes(auxRand, 32, "auxRand");
const t = Fn.toBytes(d ^ num(taggedHash("BIP0340/aux", a)));
const rand = taggedHash("BIP0340/nonce", t, px, m);
const { bytes: rx, scalar: k } = schnorrGetExtPubKey(rand);
const e = challenge(rx, px, m);
const sig = new Uint8Array(64);
sig.set(rx, 0);
sig.set(Fn.toBytes(Fn.create(k + e * d)), 32);
if (!schnorrVerify(sig, m, px))
throw new Error("sign: Invalid signature produced");
return sig;
}
function schnorrVerify(signature, message, publicKey) {
const { Fp, Fn, BASE } = Pointk1;
const sig = abytes(signature, 64, "signature");
const m = abytes(message, void 0, "message");
const pub = abytes(publicKey, 32, "publicKey");
try {
const P = lift_x(num(pub));
const r = num(sig.subarray(0, 32));
if (!Fp.isValidNot0(r))
return false;
const s = num(sig.subarray(32, 64));
if (!Fn.isValidNot0(s))
return false;
const e = challenge(Fn.toBytes(r), pointToBytes(P), m);
const R = BASE.multiplyUnsafe(s).add(P.multiplyUnsafe(Fn.neg(e)));
const { x, y } = R.toAffine();
if (R.is0() || !hasEven(y) || x !== r)
return false;
return true;
} catch (error2) {
return false;
}
}
var secp256k1_CURVE, secp256k1_ENDO, _0n5, _2n3, Fpk1, Pointk1, secp256k1, TAGGED_HASH_PREFIXES, pointToBytes, hasEven, num, schnorr;
var init_secp256k1 = __esm({
"node_modules/@noble/curves/secp256k1.js"() {
init_sha2();
init_utils();
init_curve();
init_modular();
init_weierstrass();
init_utils2();
secp256k1_CURVE = {
p: BigInt("0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"),
n: BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"),
h: BigInt(1),
a: BigInt(0),
b: BigInt(7),
Gx: BigInt("0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"),
Gy: BigInt("0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")
};
secp256k1_ENDO = {
beta: BigInt("0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee"),
basises: [
[BigInt("0x3086d221a7d46bcde86c90e49284eb15"), -BigInt("0xe4437ed6010e88286f547fa90abfe4c3")],
[BigInt("0x114ca50f7a8e2f3f657c1108d9d44cfd8"), BigInt("0x3086d221a7d46bcde86c90e49284eb15")]
]
};
_0n5 = /* @__PURE__ */ BigInt(0);
_2n3 = /* @__PURE__ */ BigInt(2);
Fpk1 = Field(secp256k1_CURVE.p, { sqrt: sqrtMod });
Pointk1 = /* @__PURE__ */ weierstrass(secp256k1_CURVE, {
Fp: Fpk1,
endo: secp256k1_ENDO
});
secp256k1 = /* @__PURE__ */ ecdsa(Pointk1, sha256);
TAGGED_HASH_PREFIXES = {};
pointToBytes = (point) => point.toBytes(true).slice(1);
hasEven = (y) => y % _2n3 === _0n5;
num = bytesToNumberBE;
schnorr = /* @__PURE__ */ (() => {
const size = 32;
const seedLength = 48;
const randomSecretKey = (seed = randomBytes(seedLength)) => {
return mapHashToField(seed, secp256k1_CURVE.n);
};
return {
keygen: createKeygen(randomSecretKey, schnorrGetPublicKey),
getPublicKey: schnorrGetPublicKey,
sign: schnorrSign,
verify: schnorrVerify,
Point: Pointk1,
utils: {
randomSecretKey,
taggedHash,
lift_x,
pointToBytes
},
lengths: {
secretKey: size,
publicKey: size,
publicKeyHasPrefix: false,
signature: size * 2,
seed: seedLength
}
};
})();
}
});
// node_modules/nostr-tools/lib/esm/pool.js
function normalizeURL(url) {
try {
if (url.indexOf("://") === -1)
url = "wss://" + url;
let p = new URL(url);
if (p.protocol === "http:")
p.protocol = "ws:";
else if (p.protocol === "https:")
p.protocol = "wss:";
p.pathname = p.pathname.replace(/\/+/g, "/");
if (p.pathname.endsWith("/"))
p.pathname = p.pathname.slice(0, -1);
if (p.port === "80" && p.protocol === "ws:" || p.port === "443" && p.protocol === "wss:")
p.port = "";
p.searchParams.sort();
p.hash = "";
return p.toString();
} catch (e) {
throw new Error(`Invalid URL: ${url}`);
}
}
function isHex32(input) {
if (input.length !== 64)
return false;
for (let i22 = 0; i22 < 64; i22++) {
let cc = input.charCodeAt(i22);
if (isNaN(cc) || cc < 48 || cc > 102 || cc > 57 && cc < 97) {
return false;
}
}
return true;
}
function validateEvent(event) {
if (!isRecord(event))
return false;
if (typeof event.kind !== "number")
return false;
if (typeof event.content !== "string")
return false;
if (typeof event.created_at !== "number")
return false;
if (typeof event.pubkey !== "string")
return false;
if (!isHex32(event.pubkey))
return false;
if (!Array.isArray(event.tags))
return false;
for (let i22 = 0; i22 < event.tags.length; i22++) {
let tag = event.tags[i22];
if (!Array.isArray(tag))
return false;
for (let j = 0; j < tag.length; j++) {
if (typeof tag[j] !== "string")
return false;
}
}
return true;
}
function serializeEvent(evt) {
if (!validateEvent(evt))
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash(event) {
let eventHash = sha256(utf8Encoder.encode(serializeEvent(event)));
return bytesToHex(eventHash);
}
function matchFilter(filter, event) {
if (filter.ids && filter.ids.indexOf(event.id) === -1) {
return false;
}
if (filter.kinds && filter.kinds.indexOf(event.kind) === -1) {
return false;
}
if (filter.authors && filter.authors.indexOf(event.pubkey) === -1) {
return false;
}
for (let f in filter) {
if (f[0] === "#") {
let tagName = f.slice(1);
let values = filter[`#${tagName}`];
if (values && !event.tags.find(([t, v]) => t === f.slice(1) && values.indexOf(v) !== -1))
return false;
}
}
if (filter.since && event.created_at < filter.since)
return false;
if (filter.until && event.created_at > filter.until)
return false;
return true;
}
function matchFilters(filters, event) {
for (let i22 = 0; i22 < filters.length; i22++) {
if (matchFilter(filters[i22], event)) {
return true;
}
}
return false;
}
function getHex64(json, field) {
let len = field.length + 3;
let idx = json.indexOf(`"${field}":`) + len;
let s = json.slice(idx).indexOf(`"`) + idx + 1;
return json.slice(s, s + 64);
}
function getSubscriptionId(json) {
let idx = json.slice(0, 22).indexOf(`"EVENT"`);
if (idx === -1)
return null;
let pstart = json.slice(idx + 7 + 1).indexOf(`"`);
if (pstart === -1)
return null;
let start = idx + 7 + 1 + pstart;
let pend = json.slice(start + 1, 80).indexOf(`"`);
if (pend === -1)
return null;
let end = start + 1 + pend;
return json.slice(start + 1, end);
}
function makeAuthEvent(relayURL, challenge2) {
return {
kind: ClientAuth,
created_at: Math.floor(Date.now() / 1e3),
tags: [
["relay", relayURL],
["challenge", challenge2]
],
content: ""
};
}
function getCountManyFilter(target, directive) {
switch (directive) {
case "reactions":
return { "#e": [target], kinds: [7] };
case "reposts":
return { "#e": [target], kinds: [6] };
case "quotes":
return { "#q": [target], kinds: [1, 1111] };
case "replies":
return { "#e": [target], kinds: [1] };
case "comments":
return { "#E": [target], kinds: [1111] };
case "followers":
return { "#p": [target], kinds: [3] };
}
}
function newHll() {
return new Uint8Array(M);
}
function hllDecode(hex) {
if (hex.length !== HLL_HEX_LENGTH || !/^[0-9a-f]+$/.test(hex))
return void 0;
const registers = new Uint8Array(M);
for (let i22 = 0; i22 < M; i22++) {
registers[i22] = parseInt(hex.slice(i22 * 2, i22 * 2 + 2), 16);
}
return registers;
}
function hllEncode(registers) {
if (registers.length !== M)
throw new Error(`invalid number of registers ${registers.length}`);
let hex = "";
for (let i22 = 0; i22 < M; i22++) {
hex += registers[i22].toString(16).padStart(2, "0");
}
return hex;
}
function mergeHll(target, source) {
if (target.length === 0)
target = newHll();
if (target.length !== M)
throw new Error(`invalid number of registers ${target.length}`);
if (source.length !== M)
throw new Error(`invalid number of registers ${source.length}`);
for (let i22 = 0; i22 < M; i22++) {
if (source[i22] > target[i22])
target[i22] = source[i22];
}
return target;
}
function useWebSocketImplementation(websocketImplementation) {
_WebSocket = websocketImplementation;
}
var utf8Decoder, utf8Encoder, verifiedSymbol, isRecord, JS, i, generateSecretKey, getPublicKey, finalizeEvent, verifyEvent, ClientAuth, SendingOnClosedConnection, AbstractRelay, Subscription, M, HLL_HEX_LENGTH, utf8Encoder2, AbstractSimplePool, _WebSocket, SimplePool;
var init_pool = __esm({
"node_modules/nostr-tools/lib/esm/pool.js"() {
init_secp256k1();
init_utils();
init_sha2();
utf8Decoder = new TextDecoder("utf-8");
utf8Encoder = new TextEncoder();
verifiedSymbol = /* @__PURE__ */ Symbol("verified");
isRecord = (obj) => obj instanceof Object;
JS = class {
generateSecretKey() {
return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey));
event.id = getEventHash(event);
event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash(event)), secretKey));
event[verifiedSymbol] = true;
return event;
}
verifyEvent(event) {
if (typeof event[verifiedSymbol] === "boolean")
return event[verifiedSymbol];
try {
const hash = getEventHash(event);
if (hash !== event.id) {
event[verifiedSymbol] = false;
return false;
}
const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey));
event[verifiedSymbol] = valid;
return valid;
} catch (err) {
event[verifiedSymbol] = false;
return false;
}
}
};
i = new JS();
generateSecretKey = i.generateSecretKey;
getPublicKey = i.getPublicKey;
finalizeEvent = i.finalizeEvent;
verifyEvent = i.verifyEvent;
ClientAuth = 22242;
SendingOnClosedConnection = class extends Error {
constructor(message, relay) {
super(`Tried to send message '${message} on a closed connection to ${relay}.`);
this.name = "SendingOnClosedConnection";
}
};
AbstractRelay = class {
url;
_connected = false;
onclose = null;
onnotice = (msg) => console.debug(`NOTICE from ${this.url}: ${msg}`);
onauth;
baseEoseTimeout = 4400;
publishTimeout = 4400;
pingFrequency = 29e3;
pingTimeout = 2e4;
resubscribeBackoff = [1e4, 1e4, 1e4, 2e4, 2e4, 3e4, 6e4];
openSubs = /* @__PURE__ */ new Map();
enablePing;
enableReconnect;
idleTimeout = 0;
idleSince = Date.now();
ongoingOperations = 0;
reconnectTimeoutHandle;
pingIntervalHandle;
reconnectAttempts = 0;
skipReconnection = false;
idleTimeoutHandle;
connectionPromise;
openCountRequests = /* @__PURE__ */ new Map();
openEventPublishes = /* @__PURE__ */ new Map();
ws;
challenge;
authPromise;
serial = 0;
verifyEvent;
_WebSocket;
constructor(url, opts) {
this.url = normalizeURL(url);
this.verifyEvent = opts.verifyEvent;
this._WebSocket = opts.websocketImplementation || WebSocket;
this.enablePing = opts.enablePing;
this.enableReconnect = opts.enableReconnect || false;
if (opts.idleTimeout)
this.idleTimeout = opts.idleTimeout;
}
static async connect(url, opts) {
const relay = new AbstractRelay(url, opts);
await relay.connect(opts);
return relay;
}
closeAllSubscriptions(reason) {
for (let [_, sub] of this.openSubs) {
sub.close(reason);
}
this.openSubs.clear();
for (let [_, ep] of this.openEventPublishes) {
ep.reject(new Error(reason));
}
this.openEventPublishes.clear();
for (let [_, cr] of this.openCountRequests) {
cr.reject(new Error(reason));
}
this.openCountRequests.clear();
}
get connected() {
return this._connected;
}
clearIdleTimeout() {
if (this.idleTimeoutHandle) {
clearTimeout(this.idleTimeoutHandle);
this.idleTimeoutHandle = void 0;
}
}
scheduleIdleClose() {
this.clearIdleTimeout();
if (this.idleTimeout > 0) {
this.idleTimeoutHandle = setTimeout(() => {
if (this.ongoingOperations === 0 && this.idleSince) {
this.close();
}
}, this.idleTimeout);
}
}
async reconnect() {
const backoff = this.resubscribeBackoff[Math.min(this.reconnectAttempts, this.resubscribeBackoff.length - 1)];
this.reconnectAttempts++;
this.reconnectTimeoutHandle = setTimeout(async () => {
try {
await this.connect();
} catch (err) {
}
}, backoff);
}
handleHardClose(reason) {
if (this.ws) {
this.ws.onopen = null;
this.ws.onerror = null;
this.ws.onclose = null;
}
if (this.pingIntervalHandle) {
clearInterval(this.pingIntervalHandle);
this.pingIntervalHandle = void 0;
}
this._connected = false;
this.connectionPromise = void 0;
this.idleSince = void 0;
this.clearIdleTimeout();
if (this.enableReconnect && !this.skipReconnection) {
this.reconnect();
} else {
this.onclose?.();
this.closeAllSubscriptions(reason);
}
}
async connect(opts) {
let connectionTimeoutHandle;
if (this.connectionPromise)
return this.connectionPromise;
this.challenge = void 0;
this.authPromise = void 0;
this.skipReconnection = false;
this.connectionPromise = new Promise((resolve, reject) => {
if (opts?.timeout) {
connectionTimeoutHandle = setTimeout(() => {
reject("connection timed out");
this.connectionPromise = void 0;
if (this.reconnectAttempts === 0) {
this.skipReconnection = true;
}
this.handleHardClose("relay connection timed out");
}, opts.timeout);
}
if (opts?.abort) {
opts.abort.onabort = reject;
}
try {
this.ws = new this._WebSocket(this.url);
} catch (err) {
clearTimeout(connectionTimeoutHandle);
reject(err);
return;
}
this.ws.onopen = () => {
if (this.reconnectTimeoutHandle) {
clearTimeout(this.reconnectTimeoutHandle);
this.reconnectTimeoutHandle = void 0;
}
clearTimeout(connectionTimeoutHandle);
this._connected = true;
const isReconnection = this.reconnectAttempts > 0;
this.reconnectAttempts = 0;
for (const sub of this.openSubs.values()) {
sub.eosed = false;
if (isReconnection) {
for (let f = 0; f < sub.filters.length; f++) {
if (sub.lastEmitted) {
sub.filters[f].since = sub.lastEmitted + 1;
}
}
}
sub.fire();
}
if (this.enablePing) {
this.pingIntervalHandle = setInterval(() => this.pingpong(), this.pingFrequency);
}
resolve();
};
this.ws.onerror = () => {
clearTimeout(connectionTimeoutHandle);
reject("connection failed");
this.connectionPromise = void 0;
if (this.reconnectAttempts === 0) {
this.skipReconnection = true;
}
this.handleHardClose("relay connection failed");
};
this.ws.onclose = (ev) => {
clearTimeout(connectionTimeoutHandle);
reject(ev.message || "websocket closed");
this.handleHardClose("relay connection closed");
};
this.ws.onmessage = this._onmessage.bind(this);
});
return this.connectionPromise;
}
waitForPingPong() {
return new Promise((resolve) => {
;
this.ws.once("pong", () => resolve(true));
this.ws.ping();
});
}
waitForDummyReq() {
return new Promise((resolve, reject) => {
if (!this.connectionPromise)
return reject(new Error(`no connection to ${this.url}, can't ping`));
try {
const sub = this.subscribe(
[{ ids: ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], limit: 0 }],
{
label: "<forced-ping>",
oneose: () => {
resolve(true);
sub.close();
},
onclose() {
resolve(true);
},
eoseTimeout: this.pingTimeout + 1e3
}
);
} catch (err) {
reject(err);
}
});
}
async pingpong() {
if (this.ws?.readyState === 1) {
const result = await Promise.any([
this.ws && this.ws.ping && this.ws.once ? this.waitForPingPong() : this.waitForDummyReq(),
new Promise((res) => setTimeout(() => res(false), this.pingTimeout))
]);
if (!result) {
if (this.ws?.readyState === this._WebSocket.OPEN) {
this.ws?.close();
}
}
}
}
async send(message) {
if (!this.connectionPromise)
throw new SendingOnClosedConnection(message, this.url);
this.connectionPromise.then(() => {
this.ws?.send(message);
});
}
async auth(signAuthEvent) {
const challenge2 = this.challenge;
if (!challenge2)
throw new Error("can't perform auth, no challenge was received");
if (this.authPromise)
return this.authPromise;
this.authPromise = new Promise(async (resolve, reject) => {
try {
let evt = await signAuthEvent(makeAuthEvent(this.url, challenge2));
let timeout = setTimeout(() => {
let ep = this.openEventPublishes.get(evt.id);
if (ep) {
ep.reject(new Error("auth timed out"));
this.openEventPublishes.delete(evt.id);
}
}, this.publishTimeout);
this.openEventPublishes.set(evt.id, { resolve, reject, timeout });
this.send('["AUTH",' + JSON.stringify(evt) + "]");
} catch (err) {
console.warn("subscribe auth function failed:", err);
}
});
return this.authPromise;
}
async publish(event) {
this.idleSince = void 0;
this.clearIdleTimeout();
this.ongoingOperations++;
const ret = new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
const ep = this.openEventPublishes.get(event.id);
if (ep) {
ep.reject(new Error("publish timed out"));
this.openEventPublishes.delete(event.id);
}
}, this.publishTimeout);
this.openEventPublishes.set(event.id, { resolve, reject, timeout });
});
try {
await this.send('["EVENT",' + JSON.stringify(event) + "]");
} catch (err) {
const ep = this.openEventPublishes.get(event.id);
if (ep) {
ep.reject(err);
this.openEventPublishes.delete(event.id);
}
}
this.ongoingOperations--;
if (this.ongoingOperations === 0) {
this.idleSince = Date.now();
this.scheduleIdleClose();
}
return ret;
}
async count(filters, params) {
return (await this.countWithHLL(filters, params)).count;
}
async countWithHLL(filters, params) {
this.serial++;
const id = params?.id || "count:" + this.serial;
const ret = new Promise((resolve, reject) => {
this.openCountRequests.set(id, { resolve, reject });
});
try {
await this.send('["COUNT","' + id + '",' + JSON.stringify(filters).substring(1));
} catch (err) {
const cr = this.openCountRequests.get(id);
if (cr) {
cr.reject(err);
this.openCountRequests.delete(id);
}
}
return ret;
}
subscribe(filters, params) {
if (params.label !== "<forced-ping>") {
this.idleSince = void 0;
this.clearIdleTimeout();
this.ongoingOperations++;
}
const sub = this.prepareSubscription(filters, params);
sub.fire();
if (params.abort) {
params.abort.onabort = () => sub.close(String(params.abort.reason || "<aborted>"));
}
return sub;
}
prepareSubscription(filters, params) {
this.serial++;
const id = params.id || (params.label ? params.label + ":" : "sub:") + this.serial;
const sub = new Subscription(this, id, filters, params);
this.openSubs.set(id, sub);
return sub;
}
close() {
this.skipReconnection = true;
if (this.reconnectTimeoutHandle) {
clearTimeout(this.reconnectTimeoutHandle);
this.reconnectTimeoutHandle = void 0;
}
if (this.pingIntervalHandle) {
clearInterval(this.pingIntervalHandle);
this.pingIntervalHandle = void 0;
}
this.closeAllSubscriptions("relay connection closed by us");
this._connected = false;
this.connectionPromise = void 0;
this.idleSince = void 0;
this.clearIdleTimeout();
this.onclose?.();
if (this.ws) {
this.ws.onopen = null;
this.ws.onerror = null;
this.ws.onclose = null;
if (this.ws.readyState !== this._WebSocket.CLOSING && this.ws.readyState !== this._WebSocket.CLOSED) {
this.ws.close();
}
}
}
_onmessage(ev) {
const json = ev.data;
if (!json) {
return;
}
const subid = getSubscriptionId(json);
if (subid) {
const so = this.openSubs.get(subid);
if (!so) {
return;
}
const id = getHex64(json, "id");
const alreadyHave = so.alreadyHaveEvent?.(id);
so.receivedEvent?.(this, id);
if (alreadyHave) {
return;
}
}
try {
let data = JSON.parse(json);
switch (data[0]) {
case "EVENT": {
const so = this.openSubs.get(data[1]);
const event = data[2];
if (matchFilters(so.filters, event) && this.verifyEvent(event, this.url)) {
so.onevent(event);
} else {
so.oninvalidevent?.(event);
}
if (!so.lastEmitted || so.lastEmitted < event.created_at)
so.lastEmitted = event.created_at;
return;
}
case "COUNT": {
const id = data[1];
const payload = data[2];
const cr = this.openCountRequests.get(id);
if (cr) {
cr.resolve(payload);
this.openCountRequests.delete(id);
}
return;
}
case "EOSE": {
const so = this.openSubs.get(data[1]);
if (!so)
return;
so.receivedEose();
return;
}
case "OK": {
const id = data[1];
const ok = data[2];
const reason = data[3];
const ep = this.openEventPublishes.get(id);
if (ep) {
clearTimeout(ep.timeout);
if (ok)
ep.resolve(reason);
else
ep.reject(new Error(reason));
this.openEventPublishes.delete(id);
}
return;
}
case "CLOSED": {
const id = data[1];
const so = this.openSubs.get(id);
if (!so) {
const cr = this.openCountRequests.get(id);
if (cr) {
cr.reject(new Error(data[2]));
this.openCountRequests.delete(id);
}
return;
}
so.closed = true;
so.close(data[2]);
return;
}
case "NOTICE": {
this.onnotice(data[1]);
return;
}
case "AUTH": {
this.challenge = data[1];
if (this.onauth) {
this.auth(this.onauth).catch((err) => {
if (!(err instanceof SendingOnClosedConnection)) {
throw err;
}
});
}
return;
}
default: {
const so = this.openSubs.get(data[1]);
so?.oncustom?.(data);
return;
}
}
} catch (err) {
try {
const [_, __, event] = JSON.parse(json);
console.warn(`[nostr] relay ${this.url} error processing message:`, err, event);
} catch (_) {
console.warn(`[nostr] relay ${this.url} error processing message:`, err);
}
return;
}
}
};
Subscription = class {
relay;
id;
lastEmitted;
closed = false;
eosed = false;
filters;
alreadyHaveEvent;
receivedEvent;
onevent;
oninvalidevent;
oneose;
onclose;
oncustom;
eoseTimeout;
eoseTimeoutHandle;
constructor(relay, id, filters, params) {
if (filters.length === 0)
throw new Error("subscription can't be created with zero filters");
this.relay = relay;
this.filters = filters;
this.id = id;
this.alreadyHaveEvent = params.alreadyHaveEvent;
this.receivedEvent = params.receivedEvent;
this.eoseTimeout = params.eoseTimeout || relay.baseEoseTimeout;
this.oneose = params.oneose;
this.onclose = params.onclose;
this.oninvalidevent = params.oninvalidevent;
this.onevent = params.onevent || ((event) => {
console.warn(
`onevent() callback not defined for subscription '${this.id}' in relay ${this.relay.url}. event received:`,
event
);
});
}
fire() {
this.relay.send('["REQ","' + this.id + '",' + JSON.stringify(this.filters).substring(1));
this.eoseTimeoutHandle = setTimeout(this.receivedEose.bind(this), this.eoseTimeout);
}
receivedEose() {
if (this.eosed)
return;
clearTimeout(this.eoseTimeoutHandle);
this.eosed = true;
this.oneose?.();
}
close(reason = "closed by caller") {
if (!this.closed && this.relay.connected) {
try {
this.relay.send('["CLOSE",' + JSON.stringify(this.id) + "]");
} catch (err) {
if (err instanceof SendingOnClosedConnection) {
} else {
throw err;
}
}
this.closed = true;
}
this.relay.openSubs.delete(this.id);
if (!this.id.startsWith("<forced-ping>")) {
this.relay.ongoingOperations--;
if (this.relay.ongoingOperations === 0) {
this.relay.idleSince = Date.now();
this.relay.scheduleIdleClose();
}
}
this.onclose?.(reason);
}
};
M = 256;
HLL_HEX_LENGTH = M * 2;
utf8Encoder2 = new TextEncoder();
AbstractSimplePool = class {
relays = /* @__PURE__ */ new Map();
seenOn = /* @__PURE__ */ new Map();
trackRelays = false;
verifyEvent;
enablePing;
enableReconnect;
idleTimeout = 2e4;
automaticallyAuth;
onRelayConnectionFailure;
onRelayConnectionSuccess;
allowConnectingToRelay;
maxWaitForConnection;
_WebSocket;
constructor(opts) {
this.verifyEvent = opts.verifyEvent;
this._WebSocket = opts.websocketImplementation;
this.enablePing = opts.enablePing;
this.enableReconnect = opts.enableReconnect || false;
if (opts.idleTimeout)
this.idleTimeout = opts.idleTimeout;
this.automaticallyAuth = opts.automaticallyAuth;
this.onRelayConnectionFailure = opts.onRelayConnectionFailure;
this.onRelayConnectionSuccess = opts.onRelayConnectionSuccess;
this.allowConnectingToRelay = opts.allowConnectingToRelay;
this.maxWaitForConnection = opts.maxWaitForConnection || 3e3;
}
async ensureRelay(url, params) {
url = normalizeURL(url);
let relay = this.relays.get(url);
if (!relay) {
relay = new AbstractRelay(url, {
verifyEvent: this.verifyEvent,
websocketImplementation: this._WebSocket,
enablePing: this.enablePing,
enableReconnect: this.enableReconnect,
idleTimeout: this.idleTimeout
});
relay.onclose = () => {
this.relays.delete(url);
};
this.relays.set(url, relay);
}
if (this.automaticallyAuth) {
const authSignerFn = this.automaticallyAuth(url);
if (authSignerFn) {
relay.onauth = authSignerFn;
}
}
try {
await relay.connect({
timeout: params?.connectionTimeout,
abort: params?.abort
});
} catch (err) {
this.relays.delete(url);
throw err;
}
return relay;
}
close(relays) {
relays.map(normalizeURL).forEach((url) => {
this.relays.get(url)?.close();
this.relays.delete(url);
});
}
subscribe(relays, filter, params) {
const request = [];
const uniqUrls = [];
for (let i22 = 0; i22 < relays.length; i22++) {
const url = normalizeURL(relays[i22]);
if (!request.find((r) => r.url === url)) {
if (uniqUrls.indexOf(url) === -1) {
uniqUrls.push(url);
request.push({ url, filter });
}
}
}
return this.subscribeMap(request, params);
}
subscribeMany(relays, filter, params) {
return this.subscribe(relays, filter, params);
}
subscribeMap(requests, params) {
const grouped = /* @__PURE__ */ new Map();
for (const req of requests) {
const { url, filter } = req;
if (!grouped.has(url))
grouped.set(url, []);
grouped.get(url).push(filter);
}
const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }));
if (this.trackRelays) {
params.receivedEvent = (relay, id) => {
let set = this.seenOn.get(id);
if (!set) {
set = /* @__PURE__ */ new Set();
this.seenOn.set(id, set);
}
set.add(relay);
};
}
const _knownIds = /* @__PURE__ */ new Set();
const subs = [];
const eosesReceived = [];
let handleEose = (i22) => {
if (eosesReceived[i22])
return;
eosesReceived[i22] = true;
if (eosesReceived.filter((a) => a).length === groupedRequests.length) {
params.oneose?.();
handleEose = () => {
};
}
};
const closesReceived = [];
let handleClose = (i22, url, reason) => {
if (closesReceived[i22])
return;
handleEose(i22);
closesReceived[i22] = { url, reason };
if (closesReceived.filter((a) => a).length === groupedRequests.length) {
params.onclose?.(closesReceived);
handleClose = () => {
};
}
};
const localAlreadyHaveEventHandler = (id) => {
if (params.alreadyHaveEvent?.(id)) {
return true;
}
const have = _knownIds.has(id);
_knownIds.add(id);
return have;
};
const allOpened = Promise.all(
groupedRequests.map(async ({ url, filters }, i22) => {
if (this.allowConnectingToRelay?.(url, ["read", filters]) === false) {
handleClose(i22, url, "connection skipped by allowConnectingToRelay");
return;
}
let relay;
try {
relay = await this.ensureRelay(url, {
connectionTimeout: this.maxWaitForConnection < (params.maxWait || 0) ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : this.maxWaitForConnection,
abort: params.abort
});
} catch (err) {
this.onRelayConnectionFailure?.(url);
handleClose(i22, url, err?.message || String(err));
return;
}
this.onRelayConnectionSuccess?.(url);
let subscription = relay.subscribe(filters, {
...params,
oneose: () => handleEose(i22),
onclose: (reason) => {
if (reason.startsWith("auth-required: ") && params.onauth) {
relay.auth(params.onauth).then(() => {
relay.subscribe(filters, {
...params,
oneose: () => handleEose(i22),
onclose: (reason2) => {
handleClose(i22, url, reason2);
},
alreadyHaveEvent: localAlreadyHaveEventHandler,
eoseTimeout: params.maxWait,
abort: params.abort
});
}).catch((err) => {
handleClose(i22, url, `auth was required and attempted, but failed with: ${err}`);
});
} else {
handleClose(i22, url, reason);
}
},
alreadyHaveEvent: localAlreadyHaveEventHandler,
eoseTimeout: params.maxWait,
abort: params.abort
});
subs.push(subscription);
})
);
return {
async close(reason) {
await allOpened;
subs.forEach((sub) => {
sub.close(reason);
});
}
};
}
subscribeEose(relays, filter, params) {
let subcloser;
subcloser = this.subscribe(relays, filter, {
...params,
oneose() {
const reason = "closed automatically on eose";
if (subcloser)
subcloser.close(reason);
else
params.onclose?.(relays.map((url) => ({ url, reason })));
}
});
return subcloser;
}
subscribeManyEose(relays, filter, params) {
return this.subscribeEose(relays, filter, params);
}
async querySync(relays, filter, params) {
return new Promise(async (resolve) => {
const events = [];
this.subscribeEose(relays, filter, {
...params,
onevent(event) {
events.push(event);
},
onclose(_) {
resolve(events);
}
});
});
}
async get(relays, filter, params) {
filter.limit = 1;
const events = await this.querySync(relays, filter, params);
events.sort((a, b) => b.created_at - a.created_at);
return events[0] || null;
}
async countMany(relays, target, directive, params) {
const filter = getCountManyFilter(target, directive);
const urls = [];
for (let i22 = 0; i22 < relays.length; i22++) {
const url = normalizeURL(relays[i22]);
if (urls.indexOf(url) === -1)
urls.push(url);
}
const responses = await Promise.all(
urls.map(async (url) => {
if (this.allowConnectingToRelay?.(url, ["read", [filter]]) === false)
return null;
let relay;
try {
relay = await this.ensureRelay(url, {
connectionTimeout: this.maxWaitForConnection < (params?.maxWait || 0) ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : this.maxWaitForConnection,
abort: params?.abort
});
} catch (err) {
this.onRelayConnectionFailure?.(url);
return null;
}
this.onRelayConnectionSuccess?.(url);
return relay.countWithHLL([filter], { id: params?.id }).catch(() => null);
})
);
let count = 0;
let hll;
for (const response of responses) {
if (!response)
continue;
if (response.count > count)
count = response.count;
if (!response.hll || response.hll.length !== 512)
continue;
const registers = hllDecode(response.hll);
if (!registers)
continue;
hll = mergeHll(hll || new Uint8Array(0), registers);
}
return hll ? { count, hll: hllEncode(hll) } : { count };
}
publish(relays, event, params) {
return relays.map(normalizeURL).map(async (url, i22, arr) => {
if (arr.indexOf(url) !== i22) {
return Promise.reject("duplicate url");
}
if (this.allowConnectingToRelay?.(url, ["write", event]) === false) {
return Promise.reject("connection skipped by allowConnectingToRelay");
}
let r;
try {
r = await this.ensureRelay(url, {
connectionTimeout: this.maxWaitForConnection < (params?.maxWait || 0) ? Math.max(params.maxWait * 0.8, params.maxWait - 1e3) : this.maxWaitForConnection,
abort: params?.abort
});
} catch (err) {
this.onRelayConnectionFailure?.(url);
return Promise.reject("connection failure: " + String(err));
}
return r.publish(event).catch(async (err) => {
if (err instanceof Error && err.message.startsWith("auth-required: ") && params?.onauth) {
await r.auth(params.onauth);
return r.publish(event);
}
throw err;
}).then((reason) => {
if (this.trackRelays) {
let set = this.seenOn.get(event.id);
if (!set) {
set = /* @__PURE__ */ new Set();
this.seenOn.set(event.id, set);
}
set.add(r);
}
return reason;
});
});
}
listConnectionStatus() {
const map = /* @__PURE__ */ new Map();
this.relays.forEach((relay, url) => map.set(url, relay.connected));
return map;
}
destroy() {
this.relays.forEach((conn) => conn.close());
this.relays = /* @__PURE__ */ new Map();
}
pruneIdleRelays(idleThresholdMs = 1e4) {
const prunedUrls = [];
for (const [url, relay] of this.relays) {
if (relay.idleSince && Date.now() - relay.idleSince >= idleThresholdMs) {
this.relays.delete(url);
prunedUrls.push(url);
relay.close();
}
}
return prunedUrls;
}
};
try {
_WebSocket = WebSocket;
} catch {
}
SimplePool = class extends AbstractSimplePool {
constructor(options) {
super({ verifyEvent, websocketImplementation: _WebSocket, maxWaitForConnection: 3e3, ...options });
}
};
}
});
// node_modules/@noble/ciphers/utils.js
function isBytes2(a) {
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
}
function abool2(b) {
if (typeof b !== "boolean")
throw new Error(`boolean expected, not ${b}`);
}
function anumber2(n) {
if (!Number.isSafeInteger(n) || n < 0)
throw new Error("positive integer expected, got " + n);
}
function abytes2(value, length, title = "") {
const bytes = isBytes2(value);
const len = value?.length;
const needsLen = length !== void 0;
if (!bytes || needsLen && len !== length) {
const prefix = title && `"${title}" `;
const ofLen = needsLen ? ` of length ${length}` : "";
const got = bytes ? `length=${len}` : `type=${typeof value}`;
throw new Error(prefix + "expected Uint8Array" + ofLen + ", got " + got);
}
return value;
}
function aexists2(instance, checkFinished = true) {
if (instance.destroyed)
throw new Error("Hash instance has been destroyed");
if (checkFinished && instance.finished)
throw new Error("Hash#digest() has already been called");
}
function aoutput2(out, instance) {
abytes2(out, void 0, "output");
const min = instance.outputLen;
if (out.length < min) {
throw new Error("digestInto() expects output buffer of length at least " + min);
}
}
function u32(arr) {
return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
}
function clean2(...arrays) {
for (let i3 = 0; i3 < arrays.length; i3++) {
arrays[i3].fill(0);
}
}
function createView2(arr) {
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
}
function checkOpts(defaults, opts) {
if (opts == null || typeof opts !== "object")
throw new Error("options must be defined");
const merged = Object.assign(defaults, opts);
return merged;
}
function equalBytes(a, b) {
if (a.length !== b.length)
return false;
let diff = 0;
for (let i3 = 0; i3 < a.length; i3++)
diff |= a[i3] ^ b[i3];
return diff === 0;
}
function getOutput(expectedLength, out, onlyAligned = true) {
if (out === void 0)
return new Uint8Array(expectedLength);
if (out.length !== expectedLength)
throw new Error('"output" expected Uint8Array of length ' + expectedLength + ", got: " + out.length);
if (onlyAligned && !isAligned32(out))
throw new Error("invalid output, must be aligned");
return out;
}
function u64Lengths(dataLength, aadLength, isLE2) {
abool2(isLE2);
const num2 = new Uint8Array(16);
const view = createView2(num2);
view.setBigUint64(0, BigInt(aadLength), isLE2);
view.setBigUint64(8, BigInt(dataLength), isLE2);
return num2;
}
function isAligned32(bytes) {
return bytes.byteOffset % 4 === 0;
}
function copyBytes2(bytes) {
return Uint8Array.from(bytes);
}
var isLE, wrapCipher;
var init_utils3 = __esm({
"node_modules/@noble/ciphers/utils.js"() {
isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
wrapCipher = /* @__NO_SIDE_EFFECTS__ */ (params, constructor) => {
function wrappedCipher(key, ...args) {
abytes2(key, void 0, "key");
if (!isLE)
throw new Error("Non little-endian hardware is not yet supported");
if (params.nonceLength !== void 0) {
const nonce = args[0];
abytes2(nonce, params.varSizeNonce ? void 0 : params.nonceLength, "nonce");
}
const tagl = params.tagLength;
if (tagl && args[1] !== void 0)
abytes2(args[1], void 0, "AAD");
const cipher = constructor(key, ...args);
const checkOutput = (fnLength, output) => {
if (output !== void 0) {
if (fnLength !== 2)
throw new Error("cipher output not supported");
abytes2(output, void 0, "output");
}
};
let called = false;
const wrCipher = {
encrypt(data, output) {
if (called)
throw new Error("cannot encrypt() twice with same key + nonce");
called = true;
abytes2(data);
checkOutput(cipher.encrypt.length, output);
return cipher.encrypt(data, output);
},
decrypt(data, output) {
abytes2(data);
if (tagl && data.length < tagl)
throw new Error('"ciphertext" expected length bigger than tagLength=' + tagl);
checkOutput(cipher.decrypt.length, output);
return cipher.decrypt(data, output);
}
};
return wrCipher;
}
Object.assign(wrappedCipher, params);
return wrappedCipher;
};
}
});
// node_modules/@noble/ciphers/_arx.js
function rotl(a, b) {
return a << b | a >>> 32 - b;
}
function isAligned322(b) {
return b.byteOffset % 4 === 0;
}
function runCipher(core, sigma, key, nonce, data, output, counter, rounds) {
const len = data.length;
const block = new Uint8Array(BLOCK_LEN);
const b32 = u32(block);
const isAligned = isAligned322(data) && isAligned322(output);
const d32 = isAligned ? u32(data) : U32_EMPTY;
const o32 = isAligned ? u32(output) : U32_EMPTY;
for (let pos = 0; pos < len; counter++) {
core(sigma, key, nonce, b32, counter, rounds);
if (counter >= MAX_COUNTER)
throw new Error("arx: counter overflow");
const take = Math.min(BLOCK_LEN, len - pos);
if (isAligned && take === BLOCK_LEN) {
const pos32 = pos / 4;
if (pos % 4 !== 0)
throw new Error("arx: invalid block position");
for (let j = 0, posj; j < BLOCK_LEN32; j++) {
posj = pos32 + j;
o32[posj] = d32[posj] ^ b32[j];
}
pos += BLOCK_LEN;
continue;
}
for (let j = 0, posj; j < take; j++) {
posj = pos + j;
output[posj] = data[posj] ^ block[j];
}
pos += take;
}
}
function createCipher(core, opts) {
const { allowShortKeys, extendNonceFn, counterLength, counterRight, rounds } = checkOpts({ allowShortKeys: false, counterLength: 8, counterRight: false, rounds: 20 }, opts);
if (typeof core !== "function")
throw new Error("core must be a function");
anumber2(counterLength);
anumber2(rounds);
abool2(counterRight);
abool2(allowShortKeys);
return (key, nonce, data, output, counter = 0) => {
abytes2(key, void 0, "key");
abytes2(nonce, void 0, "nonce");
abytes2(data, void 0, "data");
const len = data.length;
if (output === void 0)
output = new Uint8Array(len);
abytes2(output, void 0, "output");
anumber2(counter);
if (counter < 0 || counter >= MAX_COUNTER)
throw new Error("arx: counter overflow");
if (output.length < len)
throw new Error(`arx: output (${output.length}) is shorter than data (${len})`);
const toClean = [];
let l = key.length;
let k;
let sigma;
if (l === 32) {
toClean.push(k = copyBytes2(key));
sigma = sigma32_32;
} else if (l === 16 && allowShortKeys) {
k = new Uint8Array(32);
k.set(key);
k.set(key, 16);
sigma = sigma16_32;
toClean.push(k);
} else {
abytes2(key, 32, "arx key");
throw new Error("invalid key size");
}
if (!isAligned322(nonce))
toClean.push(nonce = copyBytes2(nonce));
const k32 = u32(k);
if (extendNonceFn) {
if (nonce.length !== 24)
throw new Error(`arx: extended nonce must be 24 bytes`);
extendNonceFn(sigma, k32, u32(nonce.subarray(0, 16)), k32);
nonce = nonce.subarray(16);
}
const nonceNcLen = 16 - counterLength;
if (nonceNcLen !== nonce.length)
throw new Error(`arx: nonce must be ${nonceNcLen} or 16 bytes`);
if (nonceNcLen !== 12) {
const nc = new Uint8Array(12);
nc.set(nonce, counterRight ? 0 : 12 - nonce.length);
nonce = nc;
toClean.push(nonce);
}
const n32 = u32(nonce);
runCipher(core, sigma, k32, n32, data, output, counter, rounds);
clean2(...toClean);
return output;
};
}
var encodeStr, sigma16, sigma32, sigma16_32, sigma32_32, BLOCK_LEN, BLOCK_LEN32, MAX_COUNTER, U32_EMPTY;
var init_arx = __esm({
"node_modules/@noble/ciphers/_arx.js"() {
init_utils3();
encodeStr = (str) => Uint8Array.from(str.split(""), (c) => c.charCodeAt(0));
sigma16 = encodeStr("expand 16-byte k");
sigma32 = encodeStr("expand 32-byte k");
sigma16_32 = u32(sigma16);
sigma32_32 = u32(sigma32);
BLOCK_LEN = 64;
BLOCK_LEN32 = 16;
MAX_COUNTER = 2 ** 32 - 1;
U32_EMPTY = Uint32Array.of();
}
});
// node_modules/@noble/ciphers/_poly1305.js
function u8to16(a, i3) {
return a[i3++] & 255 | (a[i3++] & 255) << 8;
}
function wrapConstructorWithKey(hashCons) {
const hashC = (msg, key) => hashCons(key).update(msg).digest();
const tmp = hashCons(new Uint8Array(32));
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = (key) => hashCons(key);
return hashC;
}
var Poly1305, poly1305;
var init_poly1305 = __esm({
"node_modules/@noble/ciphers/_poly1305.js"() {
init_utils3();
Poly1305 = class {
blockLen = 16;
outputLen = 16;
buffer = new Uint8Array(16);
r = new Uint16Array(10);
// Allocating 1 array with .subarray() here is slower than 3
h = new Uint16Array(10);
pad = new Uint16Array(8);
pos = 0;
finished = false;
// Can be speed-up using BigUint64Array, at the cost of complexity
constructor(key) {
key = copyBytes2(abytes2(key, 32, "key"));
const t0 = u8to16(key, 0);
const t1 = u8to16(key, 2);
const t2 = u8to16(key, 4);
const t3 = u8to16(key, 6);
const t4 = u8to16(key, 8);
const t5 = u8to16(key, 10);
const t6 = u8to16(key, 12);
const t7 = u8to16(key, 14);
this.r[0] = t0 & 8191;
this.r[1] = (t0 >>> 13 | t1 << 3) & 8191;
this.r[2] = (t1 >>> 10 | t2 << 6) & 7939;
this.r[3] = (t2 >>> 7 | t3 << 9) & 8191;
this.r[4] = (t3 >>> 4 | t4 << 12) & 255;
this.r[5] = t4 >>> 1 & 8190;
this.r[6] = (t4 >>> 14 | t5 << 2) & 8191;
this.r[7] = (t5 >>> 11 | t6 << 5) & 8065;
this.r[8] = (t6 >>> 8 | t7 << 8) & 8191;
this.r[9] = t7 >>> 5 & 127;
for (let i3 = 0; i3 < 8; i3++)
this.pad[i3] = u8to16(key, 16 + 2 * i3);
}
process(data, offset, isLast = false) {
const hibit = isLast ? 0 : 1 << 11;
const { h, r } = this;
const r0 = r[0];
const r1 = r[1];
const r2 = r[2];
const r3 = r[3];
const r4 = r[4];
const r5 = r[5];
const r6 = r[6];
const r7 = r[7];
const r8 = r[8];
const r9 = r[9];
const t0 = u8to16(data, offset + 0);
const t1 = u8to16(data, offset + 2);
const t2 = u8to16(data, offset + 4);
const t3 = u8to16(data, offset + 6);
const t4 = u8to16(data, offset + 8);
const t5 = u8to16(data, offset + 10);
const t6 = u8to16(data, offset + 12);
const t7 = u8to16(data, offset + 14);
let h0 = h[0] + (t0 & 8191);
let h1 = h[1] + ((t0 >>> 13 | t1 << 3) & 8191);
let h2 = h[2] + ((t1 >>> 10 | t2 << 6) & 8191);
let h3 = h[3] + ((t2 >>> 7 | t3 << 9) & 8191);
let h4 = h[4] + ((t3 >>> 4 | t4 << 12) & 8191);
let h5 = h[5] + (t4 >>> 1 & 8191);
let h6 = h[6] + ((t4 >>> 14 | t5 << 2) & 8191);
let h7 = h[7] + ((t5 >>> 11 | t6 << 5) & 8191);
let h8 = h[8] + ((t6 >>> 8 | t7 << 8) & 8191);
let h9 = h[9] + (t7 >>> 5 | hibit);
let c = 0;
let d0 = c + h0 * r0 + h1 * (5 * r9) + h2 * (5 * r8) + h3 * (5 * r7) + h4 * (5 * r6);
c = d0 >>> 13;
d0 &= 8191;
d0 += h5 * (5 * r5) + h6 * (5 * r4) + h7 * (5 * r3) + h8 * (5 * r2) + h9 * (5 * r1);
c += d0 >>> 13;
d0 &= 8191;
let d1 = c + h0 * r1 + h1 * r0 + h2 * (5 * r9) + h3 * (5 * r8) + h4 * (5 * r7);
c = d1 >>> 13;
d1 &= 8191;
d1 += h5 * (5 * r6) + h6 * (5 * r5) + h7 * (5 * r4) + h8 * (5 * r3) + h9 * (5 * r2);
c += d1 >>> 13;
d1 &= 8191;
let d2 = c + h0 * r2 + h1 * r1 + h2 * r0 + h3 * (5 * r9) + h4 * (5 * r8);
c = d2 >>> 13;
d2 &= 8191;
d2 += h5 * (5 * r7) + h6 * (5 * r6) + h7 * (5 * r5) + h8 * (5 * r4) + h9 * (5 * r3);
c += d2 >>> 13;
d2 &= 8191;
let d3 = c + h0 * r3 + h1 * r2 + h2 * r1 + h3 * r0 + h4 * (5 * r9);
c = d3 >>> 13;
d3 &= 8191;
d3 += h5 * (5 * r8) + h6 * (5 * r7) + h7 * (5 * r6) + h8 * (5 * r5) + h9 * (5 * r4);
c += d3 >>> 13;
d3 &= 8191;
let d4 = c + h0 * r4 + h1 * r3 + h2 * r2 + h3 * r1 + h4 * r0;
c = d4 >>> 13;
d4 &= 8191;
d4 += h5 * (5 * r9) + h6 * (5 * r8) + h7 * (5 * r7) + h8 * (5 * r6) + h9 * (5 * r5);
c += d4 >>> 13;
d4 &= 8191;
let d5 = c + h0 * r5 + h1 * r4 + h2 * r3 + h3 * r2 + h4 * r1;
c = d5 >>> 13;
d5 &= 8191;
d5 += h5 * r0 + h6 * (5 * r9) + h7 * (5 * r8) + h8 * (5 * r7) + h9 * (5 * r6);
c += d5 >>> 13;
d5 &= 8191;
let d6 = c + h0 * r6 + h1 * r5 + h2 * r4 + h3 * r3 + h4 * r2;
c = d6 >>> 13;
d6 &= 8191;
d6 += h5 * r1 + h6 * r0 + h7 * (5 * r9) + h8 * (5 * r8) + h9 * (5 * r7);
c += d6 >>> 13;
d6 &= 8191;
let d7 = c + h0 * r7 + h1 * r6 + h2 * r5 + h3 * r4 + h4 * r3;
c = d7 >>> 13;
d7 &= 8191;
d7 += h5 * r2 + h6 * r1 + h7 * r0 + h8 * (5 * r9) + h9 * (5 * r8);
c += d7 >>> 13;
d7 &= 8191;
let d8 = c + h0 * r8 + h1 * r7 + h2 * r6 + h3 * r5 + h4 * r4;
c = d8 >>> 13;
d8 &= 8191;
d8 += h5 * r3 + h6 * r2 + h7 * r1 + h8 * r0 + h9 * (5 * r9);
c += d8 >>> 13;
d8 &= 8191;
let d9 = c + h0 * r9 + h1 * r8 + h2 * r7 + h3 * r6 + h4 * r5;
c = d9 >>> 13;
d9 &= 8191;
d9 += h5 * r4 + h6 * r3 + h7 * r2 + h8 * r1 + h9 * r0;
c += d9 >>> 13;
d9 &= 8191;
c = (c << 2) + c | 0;
c = c + d0 | 0;
d0 = c & 8191;
c = c >>> 13;
d1 += c;
h[0] = d0;
h[1] = d1;
h[2] = d2;
h[3] = d3;
h[4] = d4;
h[5] = d5;
h[6] = d6;
h[7] = d7;
h[8] = d8;
h[9] = d9;
}
finalize() {
const { h, pad: pad2 } = this;
const g = new Uint16Array(10);
let c = h[1] >>> 13;
h[1] &= 8191;
for (let i3 = 2; i3 < 10; i3++) {
h[i3] += c;
c = h[i3] >>> 13;
h[i3] &= 8191;
}
h[0] += c * 5;
c = h[0] >>> 13;
h[0] &= 8191;
h[1] += c;
c = h[1] >>> 13;
h[1] &= 8191;
h[2] += c;
g[0] = h[0] + 5;
c = g[0] >>> 13;
g[0] &= 8191;
for (let i3 = 1; i3 < 10; i3++) {
g[i3] = h[i3] + c;
c = g[i3] >>> 13;
g[i3] &= 8191;
}
g[9] -= 1 << 13;
let mask = (c ^ 1) - 1;
for (let i3 = 0; i3 < 10; i3++)
g[i3] &= mask;
mask = ~mask;
for (let i3 = 0; i3 < 10; i3++)
h[i3] = h[i3] & mask | g[i3];
h[0] = (h[0] | h[1] << 13) & 65535;
h[1] = (h[1] >>> 3 | h[2] << 10) & 65535;
h[2] = (h[2] >>> 6 | h[3] << 7) & 65535;
h[3] = (h[3] >>> 9 | h[4] << 4) & 65535;
h[4] = (h[4] >>> 12 | h[5] << 1 | h[6] << 14) & 65535;
h[5] = (h[6] >>> 2 | h[7] << 11) & 65535;
h[6] = (h[7] >>> 5 | h[8] << 8) & 65535;
h[7] = (h[8] >>> 8 | h[9] << 5) & 65535;
let f = h[0] + pad2[0];
h[0] = f & 65535;
for (let i3 = 1; i3 < 8; i3++) {
f = (h[i3] + pad2[i3] | 0) + (f >>> 16) | 0;
h[i3] = f & 65535;
}
clean2(g);
}
update(data) {
aexists2(this);
abytes2(data);
data = copyBytes2(data);
const { buffer, blockLen } = this;
const len = data.length;
for (let pos = 0; pos < len; ) {
const take = Math.min(blockLen - this.pos, len - pos);
if (take === blockLen) {
for (; blockLen <= len - pos; pos += blockLen)
this.process(data, pos);
continue;
}
buffer.set(data.subarray(pos, pos + take), this.pos);
this.pos += take;
pos += take;
if (this.pos === blockLen) {
this.process(buffer, 0, false);
this.pos = 0;
}
}
return this;
}
destroy() {
clean2(this.h, this.r, this.buffer, this.pad);
}
digestInto(out) {
aexists2(this);
aoutput2(out, this);
this.finished = true;
const { buffer, h } = this;
let { pos } = this;
if (pos) {
buffer[pos++] = 1;
for (; pos < 16; pos++)
buffer[pos] = 0;
this.process(buffer, 0, true);
}
this.finalize();
let opos = 0;
for (let i3 = 0; i3 < 8; i3++) {
out[opos++] = h[i3] >>> 0;
out[opos++] = h[i3] >>> 8;
}
return out;
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
};
poly1305 = /* @__PURE__ */ (() => wrapConstructorWithKey((key) => new Poly1305(key)))();
}
});
// node_modules/@noble/ciphers/chacha.js
function chachaCore(s, k, n, out, cnt, rounds = 20) {
let y00 = s[0], y01 = s[1], y02 = s[2], y03 = s[3], y04 = k[0], y05 = k[1], y06 = k[2], y07 = k[3], y08 = k[4], y09 = k[5], y10 = k[6], y11 = k[7], y12 = cnt, y13 = n[0], y14 = n[1], y15 = n[2];
let x00 = y00, x01 = y01, x02 = y02, x03 = y03, x04 = y04, x05 = y05, x06 = y06, x07 = y07, x08 = y08, x09 = y09, x10 = y10, x11 = y11, x12 = y12, x13 = y13, x14 = y14, x15 = y15;
for (let r = 0; r < rounds; r += 2) {
x00 = x00 + x04 | 0;
x12 = rotl(x12 ^ x00, 16);
x08 = x08 + x12 | 0;
x04 = rotl(x04 ^ x08, 12);
x00 = x00 + x04 | 0;
x12 = rotl(x12 ^ x00, 8);
x08 = x08 + x12 | 0;
x04 = rotl(x04 ^ x08, 7);
x01 = x01 + x05 | 0;
x13 = rotl(x13 ^ x01, 16);
x09 = x09 + x13 | 0;
x05 = rotl(x05 ^ x09, 12);
x01 = x01 + x05 | 0;
x13 = rotl(x13 ^ x01, 8);
x09 = x09 + x13 | 0;
x05 = rotl(x05 ^ x09, 7);
x02 = x02 + x06 | 0;
x14 = rotl(x14 ^ x02, 16);
x10 = x10 + x14 | 0;
x06 = rotl(x06 ^ x10, 12);
x02 = x02 + x06 | 0;
x14 = rotl(x14 ^ x02, 8);
x10 = x10 + x14 | 0;
x06 = rotl(x06 ^ x10, 7);
x03 = x03 + x07 | 0;
x15 = rotl(x15 ^ x03, 16);
x11 = x11 + x15 | 0;
x07 = rotl(x07 ^ x11, 12);
x03 = x03 + x07 | 0;
x15 = rotl(x15 ^ x03, 8);
x11 = x11 + x15 | 0;
x07 = rotl(x07 ^ x11, 7);
x00 = x00 + x05 | 0;
x15 = rotl(x15 ^ x00, 16);
x10 = x10 + x15 | 0;
x05 = rotl(x05 ^ x10, 12);
x00 = x00 + x05 | 0;
x15 = rotl(x15 ^ x00, 8);
x10 = x10 + x15 | 0;
x05 = rotl(x05 ^ x10, 7);
x01 = x01 + x06 | 0;
x12 = rotl(x12 ^ x01, 16);
x11 = x11 + x12 | 0;
x06 = rotl(x06 ^ x11, 12);
x01 = x01 + x06 | 0;
x12 = rotl(x12 ^ x01, 8);
x11 = x11 + x12 | 0;
x06 = rotl(x06 ^ x11, 7);
x02 = x02 + x07 | 0;
x13 = rotl(x13 ^ x02, 16);
x08 = x08 + x13 | 0;
x07 = rotl(x07 ^ x08, 12);
x02 = x02 + x07 | 0;
x13 = rotl(x13 ^ x02, 8);
x08 = x08 + x13 | 0;
x07 = rotl(x07 ^ x08, 7);
x03 = x03 + x04 | 0;
x14 = rotl(x14 ^ x03, 16);
x09 = x09 + x14 | 0;
x04 = rotl(x04 ^ x09, 12);
x03 = x03 + x04 | 0;
x14 = rotl(x14 ^ x03, 8);
x09 = x09 + x14 | 0;
x04 = rotl(x04 ^ x09, 7);
}
let oi = 0;
out[oi++] = y00 + x00 | 0;
out[oi++] = y01 + x01 | 0;
out[oi++] = y02 + x02 | 0;
out[oi++] = y03 + x03 | 0;
out[oi++] = y04 + x04 | 0;
out[oi++] = y05 + x05 | 0;
out[oi++] = y06 + x06 | 0;
out[oi++] = y07 + x07 | 0;
out[oi++] = y08 + x08 | 0;
out[oi++] = y09 + x09 | 0;
out[oi++] = y10 + x10 | 0;
out[oi++] = y11 + x11 | 0;
out[oi++] = y12 + x12 | 0;
out[oi++] = y13 + x13 | 0;
out[oi++] = y14 + x14 | 0;
out[oi++] = y15 + x15 | 0;
}
function hchacha(s, k, i3, out) {
let x00 = s[0], x01 = s[1], x02 = s[2], x03 = s[3], x04 = k[0], x05 = k[1], x06 = k[2], x07 = k[3], x08 = k[4], x09 = k[5], x10 = k[6], x11 = k[7], x12 = i3[0], x13 = i3[1], x14 = i3[2], x15 = i3[3];
for (let r = 0; r < 20; r += 2) {
x00 = x00 + x04 | 0;
x12 = rotl(x12 ^ x00, 16);
x08 = x08 + x12 | 0;
x04 = rotl(x04 ^ x08, 12);
x00 = x00 + x04 | 0;
x12 = rotl(x12 ^ x00, 8);
x08 = x08 + x12 | 0;
x04 = rotl(x04 ^ x08, 7);
x01 = x01 + x05 | 0;
x13 = rotl(x13 ^ x01, 16);
x09 = x09 + x13 | 0;
x05 = rotl(x05 ^ x09, 12);
x01 = x01 + x05 | 0;
x13 = rotl(x13 ^ x01, 8);
x09 = x09 + x13 | 0;
x05 = rotl(x05 ^ x09, 7);
x02 = x02 + x06 | 0;
x14 = rotl(x14 ^ x02, 16);
x10 = x10 + x14 | 0;
x06 = rotl(x06 ^ x10, 12);
x02 = x02 + x06 | 0;
x14 = rotl(x14 ^ x02, 8);
x10 = x10 + x14 | 0;
x06 = rotl(x06 ^ x10, 7);
x03 = x03 + x07 | 0;
x15 = rotl(x15 ^ x03, 16);
x11 = x11 + x15 | 0;
x07 = rotl(x07 ^ x11, 12);
x03 = x03 + x07 | 0;
x15 = rotl(x15 ^ x03, 8);
x11 = x11 + x15 | 0;
x07 = rotl(x07 ^ x11, 7);
x00 = x00 + x05 | 0;
x15 = rotl(x15 ^ x00, 16);
x10 = x10 + x15 | 0;
x05 = rotl(x05 ^ x10, 12);
x00 = x00 + x05 | 0;
x15 = rotl(x15 ^ x00, 8);
x10 = x10 + x15 | 0;
x05 = rotl(x05 ^ x10, 7);
x01 = x01 + x06 | 0;
x12 = rotl(x12 ^ x01, 16);
x11 = x11 + x12 | 0;
x06 = rotl(x06 ^ x11, 12);
x01 = x01 + x06 | 0;
x12 = rotl(x12 ^ x01, 8);
x11 = x11 + x12 | 0;
x06 = rotl(x06 ^ x11, 7);
x02 = x02 + x07 | 0;
x13 = rotl(x13 ^ x02, 16);
x08 = x08 + x13 | 0;
x07 = rotl(x07 ^ x08, 12);
x02 = x02 + x07 | 0;
x13 = rotl(x13 ^ x02, 8);
x08 = x08 + x13 | 0;
x07 = rotl(x07 ^ x08, 7);
x03 = x03 + x04 | 0;
x14 = rotl(x14 ^ x03, 16);
x09 = x09 + x14 | 0;
x04 = rotl(x04 ^ x09, 12);
x03 = x03 + x04 | 0;
x14 = rotl(x14 ^ x03, 8);
x09 = x09 + x14 | 0;
x04 = rotl(x04 ^ x09, 7);
}
let oi = 0;
out[oi++] = x00;
out[oi++] = x01;
out[oi++] = x02;
out[oi++] = x03;
out[oi++] = x12;
out[oi++] = x13;
out[oi++] = x14;
out[oi++] = x15;
}
function computeTag(fn, key, nonce, ciphertext, AAD) {
if (AAD !== void 0)
abytes2(AAD, void 0, "AAD");
const authKey = fn(key, nonce, ZEROS32);
const lengths = u64Lengths(ciphertext.length, AAD ? AAD.length : 0, true);
const h = poly1305.create(authKey);
if (AAD)
updatePadded(h, AAD);
updatePadded(h, ciphertext);
h.update(lengths);
const res = h.digest();
clean2(authKey, lengths);
return res;
}
var chacha20, xchacha20, ZEROS16, updatePadded, ZEROS32, _poly1305_aead, chacha20poly1305, xchacha20poly1305;
var init_chacha = __esm({
"node_modules/@noble/ciphers/chacha.js"() {
init_arx();
init_poly1305();
init_utils3();
chacha20 = /* @__PURE__ */ createCipher(chachaCore, {
counterRight: false,
counterLength: 4,
allowShortKeys: false
});
xchacha20 = /* @__PURE__ */ createCipher(chachaCore, {
counterRight: false,
counterLength: 8,
extendNonceFn: hchacha,
allowShortKeys: false
});
ZEROS16 = /* @__PURE__ */ new Uint8Array(16);
updatePadded = (h, msg) => {
h.update(msg);
const leftover = msg.length % 16;
if (leftover)
h.update(ZEROS16.subarray(leftover));
};
ZEROS32 = /* @__PURE__ */ new Uint8Array(32);
_poly1305_aead = (xorStream) => (key, nonce, AAD) => {
const tagLength = 16;
return {
encrypt(plaintext, output) {
const plength = plaintext.length;
output = getOutput(plength + tagLength, output, false);
output.set(plaintext);
const oPlain = output.subarray(0, -tagLength);
xorStream(key, nonce, oPlain, oPlain, 1);
const tag = computeTag(xorStream, key, nonce, oPlain, AAD);
output.set(tag, plength);
clean2(tag);
return output;
},
decrypt(ciphertext, output) {
output = getOutput(ciphertext.length - tagLength, output, false);
const data = ciphertext.subarray(0, -tagLength);
const passedTag = ciphertext.subarray(-tagLength);
const tag = computeTag(xorStream, key, nonce, data, AAD);
if (!equalBytes(passedTag, tag))
throw new Error("invalid tag");
output.set(ciphertext.subarray(0, -tagLength));
xorStream(key, nonce, output, output, 1);
clean2(tag);
return output;
}
};
};
chacha20poly1305 = /* @__PURE__ */ wrapCipher({ blockSize: 64, nonceLength: 12, tagLength: 16 }, _poly1305_aead(chacha20));
xchacha20poly1305 = /* @__PURE__ */ wrapCipher({ blockSize: 64, nonceLength: 24, tagLength: 16 }, _poly1305_aead(xchacha20));
}
});
// node_modules/@noble/hashes/hkdf.js
function extract(hash, ikm, salt) {
ahash(hash);
if (salt === void 0)
salt = new Uint8Array(hash.outputLen);
return hmac(hash, salt, ikm);
}
function expand(hash, prk, info, length = 32) {
ahash(hash);
anumber(length, "length");
const olen = hash.outputLen;
if (length > 255 * olen)
throw new Error("Length must be <= 255*HashLen");
const blocks = Math.ceil(length / olen);
if (info === void 0)
info = EMPTY_BUFFER;
else
abytes(info, void 0, "info");
const okm = new Uint8Array(blocks * olen);
const HMAC = hmac.create(hash, prk);
const HMACTmp = HMAC._cloneInto();
const T = new Uint8Array(HMAC.outputLen);
for (let counter = 0; counter < blocks; counter++) {
HKDF_COUNTER[0] = counter + 1;
HMACTmp.update(counter === 0 ? EMPTY_BUFFER : T).update(info).update(HKDF_COUNTER).digestInto(T);
okm.set(T, olen * counter);
HMAC._cloneInto(HMACTmp);
}
HMAC.destroy();
HMACTmp.destroy();
clean(T, HKDF_COUNTER);
return okm.slice(0, length);
}
var HKDF_COUNTER, EMPTY_BUFFER;
var init_hkdf = __esm({
"node_modules/@noble/hashes/hkdf.js"() {
init_hmac();
init_utils();
HKDF_COUNTER = /* @__PURE__ */ Uint8Array.of(0);
EMPTY_BUFFER = /* @__PURE__ */ Uint8Array.of();
}
});
// node_modules/@scure/base/index.js
function isBytes3(a) {
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
}
function abytes3(b) {
if (!isBytes3(b))
throw new Error("Uint8Array expected");
}
function isArrayOf(isString, arr) {
if (!Array.isArray(arr))
return false;
if (arr.length === 0)
return true;
if (isString) {
return arr.every((item) => typeof item === "string");
} else {
return arr.every((item) => Number.isSafeInteger(item));
}
}
function astr(label, input) {
if (typeof input !== "string")
throw new Error(`${label}: string expected`);
return true;
}
function anumber3(n) {
if (!Number.isSafeInteger(n))
throw new Error(`invalid integer: ${n}`);
}
function aArr(input) {
if (!Array.isArray(input))
throw new Error("array expected");
}
function astrArr(label, input) {
if (!isArrayOf(true, input))
throw new Error(`${label}: array of strings expected`);
}
function anumArr(label, input) {
if (!isArrayOf(false, input))
throw new Error(`${label}: array of numbers expected`);
}
// @__NO_SIDE_EFFECTS__
function chain(...args) {
const id = (a) => a;
const wrap = (a, b) => (c) => a(b(c));
const encode = args.map((x) => x.encode).reduceRight(wrap, id);
const decode = args.map((x) => x.decode).reduce(wrap, id);
return { encode, decode };
}
// @__NO_SIDE_EFFECTS__
function alphabet(letters) {
const lettersA = typeof letters === "string" ? letters.split("") : letters;
const len = lettersA.length;
astrArr("alphabet", lettersA);
const indexes = new Map(lettersA.map((l, i3) => [l, i3]));
return {
encode: (digits) => {
aArr(digits);
return digits.map((i3) => {
if (!Number.isSafeInteger(i3) || i3 < 0 || i3 >= len)
throw new Error(`alphabet.encode: digit index outside alphabet "${i3}". Allowed: ${letters}`);
return lettersA[i3];
});
},
decode: (input) => {
aArr(input);
return input.map((letter) => {
astr("alphabet.decode", letter);
const i3 = indexes.get(letter);
if (i3 === void 0)
throw new Error(`Unknown letter: "${letter}". Allowed: ${letters}`);
return i3;
});
}
};
}
// @__NO_SIDE_EFFECTS__
function join(separator = "") {
astr("join", separator);
return {
encode: (from) => {
astrArr("join.decode", from);
return from.join(separator);
},
decode: (to) => {
astr("join.decode", to);
return to.split(separator);
}
};
}
// @__NO_SIDE_EFFECTS__
function padding(bits, chr = "=") {
anumber3(bits);
astr("padding", chr);
return {
encode(data) {
astrArr("padding.encode", data);
while (data.length * bits % 8)
data.push(chr);
return data;
},
decode(input) {
astrArr("padding.decode", input);
let end = input.length;
if (end * bits % 8)
throw new Error("padding: invalid, string should have whole number of bytes");
for (; end > 0 && input[end - 1] === chr; end--) {
const last = end - 1;
const byte = last * bits;
if (byte % 8 === 0)
throw new Error("padding: invalid, string has too much padding");
}
return input.slice(0, end);
}
};
}
function convertRadix2(data, from, to, padding2) {
aArr(data);
if (from <= 0 || from > 32)
throw new Error(`convertRadix2: wrong from=${from}`);
if (to <= 0 || to > 32)
throw new Error(`convertRadix2: wrong to=${to}`);
if (/* @__PURE__ */ radix2carry(from, to) > 32) {
throw new Error(`convertRadix2: carry overflow from=${from} to=${to} carryBits=${/* @__PURE__ */ radix2carry(from, to)}`);
}
let carry = 0;
let pos = 0;
const max = powers[from];
const mask = powers[to] - 1;
const res = [];
for (const n of data) {
anumber3(n);
if (n >= max)
throw new Error(`convertRadix2: invalid data word=${n} from=${from}`);
carry = carry << from | n;
if (pos + from > 32)
throw new Error(`convertRadix2: carry overflow pos=${pos} from=${from}`);
pos += from;
for (; pos >= to; pos -= to)
res.push((carry >> pos - to & mask) >>> 0);
const pow = powers[pos];
if (pow === void 0)
throw new Error("invalid carry");
carry &= pow - 1;
}
carry = carry << to - pos & mask;
if (!padding2 && pos >= from)
throw new Error("Excess padding");
if (!padding2 && carry > 0)
throw new Error(`Non-zero padding: ${carry}`);
if (padding2 && pos > 0)
res.push(carry >>> 0);
return res;
}
// @__NO_SIDE_EFFECTS__
function radix2(bits, revPadding = false) {
anumber3(bits);
if (bits <= 0 || bits > 32)
throw new Error("radix2: bits should be in (0..32]");
if (/* @__PURE__ */ radix2carry(8, bits) > 32 || /* @__PURE__ */ radix2carry(bits, 8) > 32)
throw new Error("radix2: carry overflow");
return {
encode: (bytes) => {
if (!isBytes3(bytes))
throw new Error("radix2.encode input should be Uint8Array");
return convertRadix2(Array.from(bytes), 8, bits, !revPadding);
},
decode: (digits) => {
anumArr("radix2.decode", digits);
return Uint8Array.from(convertRadix2(digits, bits, 8, revPadding));
}
};
}
var gcd, radix2carry, powers, hasBase64Builtin, decodeBase64Builtin, base64;
var init_base = __esm({
"node_modules/@scure/base/index.js"() {
gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
radix2carry = /* @__NO_SIDE_EFFECTS__ */ (from, to) => from + (to - gcd(from, to));
powers = /* @__PURE__ */ (() => {
let res = [];
for (let i3 = 0; i3 < 40; i3++)
res.push(2 ** i3);
return res;
})();
hasBase64Builtin = /* @__PURE__ */ (() => typeof Uint8Array.from([]).toBase64 === "function" && typeof Uint8Array.fromBase64 === "function")();
decodeBase64Builtin = (s, isUrl) => {
astr("base64", s);
const re = isUrl ? /^[A-Za-z0-9=_-]+$/ : /^[A-Za-z0-9=+/]+$/;
const alphabet2 = isUrl ? "base64url" : "base64";
if (s.length > 0 && !re.test(s))
throw new Error("invalid base64");
return Uint8Array.fromBase64(s, { alphabet: alphabet2, lastChunkHandling: "strict" });
};
base64 = hasBase64Builtin ? {
encode(b) {
abytes3(b);
return b.toBase64();
},
decode(s) {
return decodeBase64Builtin(s, false);
}
} : /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ padding(6), /* @__PURE__ */ join(""));
}
});
// node_modules/nostr-tools/lib/esm/nip59.js
function isHex322(input) {
if (input.length !== 64)
return false;
for (let i22 = 0; i22 < 64; i22++) {
let cc = input.charCodeAt(i22);
if (isNaN(cc) || cc < 48 || cc > 102 || cc > 57 && cc < 97) {
return false;
}
}
return true;
}
function getConversationKey(privkeyA, pubkeyB) {
const sharedX = secp256k1.getSharedSecret(privkeyA, hexToBytes("02" + pubkeyB)).subarray(1, 33);
return extract(sha256, sharedX, utf8Encoder3.encode("nip44-v2"));
}
function getMessageKeys(conversationKey, nonce) {
const keys = expand(sha256, conversationKey, nonce, 76);
return {
chacha_key: keys.subarray(0, 32),
chacha_nonce: keys.subarray(32, 44),
hmac_key: keys.subarray(44, 76)
};
}
function calcPaddedLen(len) {
if (!Number.isSafeInteger(len) || len < 1)
throw new Error("expected positive integer");
if (len <= 32)
return 32;
const nextPower = 2 ** (Math.floor(Math.log2(len - 1)) + 1);
const chunk = nextPower <= 256 ? 32 : nextPower / 8;
return chunk * (Math.floor((len - 1) / chunk) + 1);
}
function writeU16BE(num2) {
if (!Number.isSafeInteger(num2) || num2 < minPlaintextSize || num2 > 65535)
throw new Error("invalid plaintext size: must be between 1 and 65535 bytes");
const arr = new Uint8Array(2);
new DataView(arr.buffer).setUint16(0, num2, false);
return arr;
}
function writeU32BE(num2) {
if (!Number.isSafeInteger(num2) || num2 < extendedPrefixThreshold || num2 > maxPlaintextSize)
throw new Error("invalid plaintext size: must be between 65536 and 4294967295 bytes");
const arr = new Uint8Array(4);
new DataView(arr.buffer).setUint32(0, num2, false);
return arr;
}
function pad(plaintext) {
const unpadded = utf8Encoder3.encode(plaintext);
const unpaddedLen = unpadded.length;
if (unpaddedLen < minPlaintextSize || unpaddedLen > maxPlaintextSize)
throw new Error("invalid plaintext size: must be between 1 and 4294967295 bytes");
const prefix = unpaddedLen >= extendedPrefixThreshold ? concatBytes(new Uint8Array([0, 0]), writeU32BE(unpaddedLen)) : writeU16BE(unpaddedLen);
const suffix = new Uint8Array(calcPaddedLen(unpaddedLen) - unpaddedLen);
return concatBytes(prefix, unpadded, suffix);
}
function unpad(padded) {
const dv = new DataView(padded.buffer, padded.byteOffset, padded.byteLength);
const firstTwo = dv.getUint16(0);
let unpaddedLen;
let prefixLen;
if (firstTwo === 0) {
unpaddedLen = dv.getUint32(2);
if (unpaddedLen < extendedPrefixThreshold)
throw new Error("invalid padding");
prefixLen = 6;
} else {
unpaddedLen = firstTwo;
prefixLen = 2;
}
const unpadded = padded.subarray(prefixLen, prefixLen + unpaddedLen);
if (unpaddedLen < minPlaintextSize || unpaddedLen > maxPlaintextSize || unpadded.length !== unpaddedLen || padded.length !== prefixLen + calcPaddedLen(unpaddedLen))
throw new Error("invalid padding");
return utf8Decoder2.decode(unpadded);
}
function hmacAad(key, message, aad) {
if (aad.length !== 32)
throw new Error("AAD associated data must be 32 bytes");
const combined = concatBytes(aad, message);
return hmac(sha256, key, combined);
}
function decodePayload(payload) {
if (typeof payload !== "string")
throw new Error("payload must be a valid string");
const plen = payload.length;
if (plen < 132)
throw new Error("invalid payload length: " + plen);
if (payload[0] === "#")
throw new Error("unknown encryption version");
let data;
try {
data = base64.decode(payload);
} catch (error2) {
throw new Error("invalid base64: " + error2.message);
}
const dlen = data.length;
if (dlen < 99)
throw new Error("invalid data length: " + dlen);
const vers = data[0];
if (vers !== 2)
throw new Error("unknown encryption version " + vers);
return {
nonce: data.subarray(1, 33),
ciphertext: data.subarray(33, -32),
mac: data.subarray(-32)
};
}
function encrypt(plaintext, conversationKey, nonce = randomBytes(32)) {
const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce);
const padded = pad(plaintext);
const ciphertext = chacha20(chacha_key, chacha_nonce, padded);
const mac = hmacAad(hmac_key, ciphertext, nonce);
return base64.encode(concatBytes(new Uint8Array([2]), nonce, ciphertext, mac));
}
function decrypt(payload, conversationKey) {
const { nonce, ciphertext, mac } = decodePayload(payload);
const { chacha_key, chacha_nonce, hmac_key } = getMessageKeys(conversationKey, nonce);
const calculatedMac = hmacAad(hmac_key, ciphertext, nonce);
if (!equalBytes(calculatedMac, mac))
throw new Error("invalid MAC");
const padded = chacha20(chacha_key, chacha_nonce, ciphertext);
return unpad(padded);
}
function validateEvent2(event) {
if (!isRecord2(event))
return false;
if (typeof event.kind !== "number")
return false;
if (typeof event.content !== "string")
return false;
if (typeof event.created_at !== "number")
return false;
if (typeof event.pubkey !== "string")
return false;
if (!isHex322(event.pubkey))
return false;
if (!Array.isArray(event.tags))
return false;
for (let i22 = 0; i22 < event.tags.length; i22++) {
let tag = event.tags[i22];
if (!Array.isArray(tag))
return false;
for (let j = 0; j < tag.length; j++) {
if (typeof tag[j] !== "string")
return false;
}
}
return true;
}
function serializeEvent2(evt) {
if (!validateEvent2(evt))
throw new Error("can't serialize event with wrong or missing properties");
return JSON.stringify([0, evt.pubkey, evt.created_at, evt.kind, evt.tags, evt.content]);
}
function getEventHash2(event) {
let eventHash = sha256(utf8Encoder3.encode(serializeEvent2(event)));
return bytesToHex(eventHash);
}
function createRumor(event, privateKey) {
const rumor = {
created_at: now(),
content: "",
tags: [],
...event,
pubkey: getPublicKey2(privateKey)
};
rumor.id = getEventHash2(rumor);
return rumor;
}
function createSeal(rumor, privateKey, recipientPublicKey) {
return finalizeEvent2(
{
kind: Seal,
content: nip44Encrypt(rumor, privateKey, recipientPublicKey),
created_at: randomNow(),
tags: []
},
privateKey
);
}
function createWrap(seal, recipientPublicKey) {
const randomKey = generateSecretKey2();
return finalizeEvent2(
{
kind: GiftWrap,
content: nip44Encrypt(seal, randomKey, recipientPublicKey),
created_at: randomNow(),
tags: [["p", recipientPublicKey]]
},
randomKey
);
}
function wrapEvent(event, senderPrivateKey, recipientPublicKey) {
const rumor = createRumor(event, senderPrivateKey);
const seal = createSeal(rumor, senderPrivateKey, recipientPublicKey);
return createWrap(seal, recipientPublicKey);
}
function unwrapEvent(wrap, recipientPrivateKey) {
if (wrap.kind !== GiftWrap) {
throw new Error(`unexpected wrap kind ${wrap.kind}, expected ${GiftWrap}`);
}
const seal = nip44Decrypt(wrap, recipientPrivateKey);
if (seal.kind !== Seal) {
throw new Error(`unexpected seal kind ${seal.kind}, expected ${Seal}`);
}
if (!verifyEvent2(seal)) {
throw new Error("seal signature is invalid");
}
const rumor = nip44Decrypt(seal, recipientPrivateKey);
if (rumor.pubkey !== seal.pubkey) {
throw new Error(`rumor pubkey ${rumor.pubkey} does not match seal pubkey ${seal.pubkey}`);
}
return rumor;
}
var utf8Decoder2, utf8Encoder3, minPlaintextSize, maxPlaintextSize, extendedPrefixThreshold, verifiedSymbol2, isRecord2, JS2, i2, generateSecretKey2, getPublicKey2, finalizeEvent2, verifyEvent2, Seal, GiftWrap, TWO_DAYS, now, randomNow, nip44ConversationKey, nip44Encrypt, nip44Decrypt;
var init_nip59 = __esm({
"node_modules/nostr-tools/lib/esm/nip59.js"() {
init_chacha();
init_utils3();
init_secp256k1();
init_hkdf();
init_hmac();
init_sha2();
init_utils();
init_base();
init_secp256k1();
init_utils();
init_sha2();
utf8Decoder2 = new TextDecoder("utf-8");
utf8Encoder3 = new TextEncoder();
minPlaintextSize = 1;
maxPlaintextSize = 4294967295;
extendedPrefixThreshold = 65536;
verifiedSymbol2 = /* @__PURE__ */ Symbol("verified");
isRecord2 = (obj) => obj instanceof Object;
JS2 = class {
generateSecretKey() {
return schnorr.utils.randomSecretKey();
}
getPublicKey(secretKey) {
return bytesToHex(schnorr.getPublicKey(secretKey));
}
finalizeEvent(t, secretKey) {
const event = t;
event.pubkey = bytesToHex(schnorr.getPublicKey(secretKey));
event.id = getEventHash2(event);
event.sig = bytesToHex(schnorr.sign(hexToBytes(getEventHash2(event)), secretKey));
event[verifiedSymbol2] = true;
return event;
}
verifyEvent(event) {
if (typeof event[verifiedSymbol2] === "boolean")
return event[verifiedSymbol2];
try {
const hash = getEventHash2(event);
if (hash !== event.id) {
event[verifiedSymbol2] = false;
return false;
}
const valid = schnorr.verify(hexToBytes(event.sig), hexToBytes(hash), hexToBytes(event.pubkey));
event[verifiedSymbol2] = valid;
return valid;
} catch (err) {
event[verifiedSymbol2] = false;
return false;
}
}
};
i2 = new JS2();
generateSecretKey2 = i2.generateSecretKey;
getPublicKey2 = i2.getPublicKey;
finalizeEvent2 = i2.finalizeEvent;
verifyEvent2 = i2.verifyEvent;
Seal = 13;
GiftWrap = 1059;
TWO_DAYS = 2 * 24 * 60 * 60;
now = () => Math.round(Date.now() / 1e3);
randomNow = () => Math.round(now() - Math.random() * TWO_DAYS);
nip44ConversationKey = (privateKey, publicKey) => getConversationKey(privateKey, publicKey);
nip44Encrypt = (data, privateKey, publicKey) => encrypt(JSON.stringify(data), nip44ConversationKey(privateKey, publicKey));
nip44Decrypt = (data, privateKey) => JSON.parse(decrypt(data.content, nip44ConversationKey(privateKey, data.pubkey)));
}
});
// node_modules/isomorphic-ws/browser.js
var ws, browser_default;
var init_browser = __esm({
"node_modules/isomorphic-ws/browser.js"() {
ws = null;
if (typeof WebSocket !== "undefined") {
ws = WebSocket;
} else if (typeof MozWebSocket !== "undefined") {
ws = MozWebSocket;
} else if (typeof global !== "undefined") {
ws = global.WebSocket || global.MozWebSocket;
} else if (typeof window !== "undefined") {
ws = window.WebSocket || window.MozWebSocket;
} else if (typeof self !== "undefined") {
ws = self.WebSocket || self.MozWebSocket;
}
browser_default = ws;
}
});
// node_modules/eventemitter3/index.js
var require_eventemitter3 = __commonJS({
"node_modules/eventemitter3/index.js"(exports, module) {
"use strict";
var has = Object.prototype.hasOwnProperty;
var prefix = "~";
function Events() {
}
if (Object.create) {
Events.prototype = /* @__PURE__ */ Object.create(null);
if (!new Events().__proto__) prefix = false;
}
function EE(fn, context, once) {
this.fn = fn;
this.context = context;
this.once = once || false;
}
function addListener(emitter, event, fn, context, once) {
if (typeof fn !== "function") {
throw new TypeError("The listener must be a function");
}
var listener = new EE(fn, context || emitter, once), evt = prefix ? prefix + event : event;
if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;
else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);
else emitter._events[evt] = [emitter._events[evt], listener];
return emitter;
}
function clearEvent(emitter, evt) {
if (--emitter._eventsCount === 0) emitter._events = new Events();
else delete emitter._events[evt];
}
function EventEmitter2() {
this._events = new Events();
this._eventsCount = 0;
}
EventEmitter2.prototype.eventNames = function eventNames() {
var names = [], events, name;
if (this._eventsCount === 0) return names;
for (name in events = this._events) {
if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);
}
if (Object.getOwnPropertySymbols) {
return names.concat(Object.getOwnPropertySymbols(events));
}
return names;
};
EventEmitter2.prototype.listeners = function listeners(event) {
var evt = prefix ? prefix + event : event, handlers = this._events[evt];
if (!handlers) return [];
if (handlers.fn) return [handlers.fn];
for (var i3 = 0, l = handlers.length, ee = new Array(l); i3 < l; i3++) {
ee[i3] = handlers[i3].fn;
}
return ee;
};
EventEmitter2.prototype.listenerCount = function listenerCount(event) {
var evt = prefix ? prefix + event : event, listeners = this._events[evt];
if (!listeners) return 0;
if (listeners.fn) return 1;
return listeners.length;
};
EventEmitter2.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {
var evt = prefix ? prefix + event : event;
if (!this._events[evt]) return false;
var listeners = this._events[evt], len = arguments.length, args, i3;
if (listeners.fn) {
if (listeners.once) this.removeListener(event, listeners.fn, void 0, true);
switch (len) {
case 1:
return listeners.fn.call(listeners.context), true;
case 2:
return listeners.fn.call(listeners.context, a1), true;
case 3:
return listeners.fn.call(listeners.context, a1, a2), true;
case 4:
return listeners.fn.call(listeners.context, a1, a2, a3), true;
case 5:
return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;
case 6:
return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;
}
for (i3 = 1, args = new Array(len - 1); i3 < len; i3++) {
args[i3 - 1] = arguments[i3];
}
listeners.fn.apply(listeners.context, args);
} else {
var length = listeners.length, j;
for (i3 = 0; i3 < length; i3++) {
if (listeners[i3].once) this.removeListener(event, listeners[i3].fn, void 0, true);
switch (len) {
case 1:
listeners[i3].fn.call(listeners[i3].context);
break;
case 2:
listeners[i3].fn.call(listeners[i3].context, a1);
break;
case 3:
listeners[i3].fn.call(listeners[i3].context, a1, a2);
break;
case 4:
listeners[i3].fn.call(listeners[i3].context, a1, a2, a3);
break;
default:
if (!args) for (j = 1, args = new Array(len - 1); j < len; j++) {
args[j - 1] = arguments[j];
}
listeners[i3].fn.apply(listeners[i3].context, args);
}
}
}
return true;
};
EventEmitter2.prototype.on = function on(event, fn, context) {
return addListener(this, event, fn, context, false);
};
EventEmitter2.prototype.once = function once(event, fn, context) {
return addListener(this, event, fn, context, true);
};
EventEmitter2.prototype.removeListener = function removeListener(event, fn, context, once) {
var evt = prefix ? prefix + event : event;
if (!this._events[evt]) return this;
if (!fn) {
clearEvent(this, evt);
return this;
}
var listeners = this._events[evt];
if (listeners.fn) {
if (listeners.fn === fn && (!once || listeners.once) && (!context || listeners.context === context)) {
clearEvent(this, evt);
}
} else {
for (var i3 = 0, events = [], length = listeners.length; i3 < length; i3++) {
if (listeners[i3].fn !== fn || once && !listeners[i3].once || context && listeners[i3].context !== context) {
events.push(listeners[i3]);
}
}
if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;
else clearEvent(this, evt);
}
return this;
};
EventEmitter2.prototype.removeAllListeners = function removeAllListeners(event) {
var evt;
if (event) {
evt = prefix ? prefix + event : event;
if (this._events[evt]) clearEvent(this, evt);
} else {
this._events = new Events();
this._eventsCount = 0;
}
return this;
};
EventEmitter2.prototype.off = EventEmitter2.prototype.removeListener;
EventEmitter2.prototype.addListener = EventEmitter2.prototype.on;
EventEmitter2.prefixed = prefix;
EventEmitter2.EventEmitter = EventEmitter2;
if ("undefined" !== typeof module) {
module.exports = EventEmitter2;
}
}
});
// node_modules/eventemitter3/index.mjs
var import_index;
var init_eventemitter3 = __esm({
"node_modules/eventemitter3/index.mjs"() {
import_index = __toESM(require_eventemitter3(), 1);
}
});
// node_modules/@wizardconnect/core/dist/protocols/hdwalletv1.js
function isPathXpub(obj) {
return obj && typeof obj === "object" && typeof obj.name === "string" && typeof obj.xpub === "string";
}
function childIndexOfPathName(name) {
switch (name) {
case PATH_RECEIVE:
return 0;
case PATH_CHANGE:
return 1;
case PATH_DEFI:
return 7;
default:
return void 0;
}
}
function isHdwalletv1Session(obj) {
const s = obj;
return obj !== null && typeof obj === "object" && Array.isArray(s.paths) && s.paths.every((p) => isPathXpub(p)) && (s.extensions === void 0 || typeof s.extensions === "object" && s.extensions !== null);
}
function isProtocolMessage(payload) {
return payload && typeof payload === "object" && typeof payload.action === "string" && typeof payload.time === "number";
}
function isErrorMessage(payload) {
return payload && typeof payload === "object" && typeof payload.error === "string";
}
function isSignTransactionRequest(msg) {
return msg && typeof msg === "object" && msg.action === RelayMsgAction.SignTransactionRequest && msg.transaction && typeof msg.transaction === "object" && typeof msg.sequence === "number" && Array.isArray(msg.inputPaths) && msg.inputPaths.every((p) => Array.isArray(p) && p.length === 3 && typeof p[0] === "number" && typeof p[1] === "string" && typeof p[2] === "number");
}
function isSignCancelMessage(msg) {
return msg && typeof msg === "object" && msg.action === RelayMsgAction.SignCancel && typeof msg.sequence === "number";
}
function isChunkMessage(msg) {
return msg && typeof msg === "object" && msg.action === RelayMsgAction.Chunk && typeof msg.msgId === "string" && typeof msg.index === "number" && typeof msg.total === "number" && typeof msg.data === "string" && Number.isInteger(msg.index) && Number.isInteger(msg.total) && msg.total >= 1 && msg.index >= 0 && msg.index < msg.total;
}
var PROTOCOL_NAME, RelayMsgAction, PATH_RECEIVE, PATH_CHANGE, PATH_DEFI;
var init_hdwalletv1 = __esm({
"node_modules/@wizardconnect/core/dist/protocols/hdwalletv1.js"() {
PROTOCOL_NAME = "hdwalletv1";
(function(RelayMsgAction2) {
RelayMsgAction2["DappReady"] = "dapp_ready";
RelayMsgAction2["WalletReady"] = "wallet_ready";
RelayMsgAction2["SignTransactionRequest"] = "sign_transaction_request";
RelayMsgAction2["SignTransactionResponse"] = "sign_transaction_response";
RelayMsgAction2["SignCancel"] = "sign_cancel";
RelayMsgAction2["Disconnect"] = "disconnect";
RelayMsgAction2["Chunk"] = "chunk";
RelayMsgAction2["Ping"] = "ping";
RelayMsgAction2["Pong"] = "pong";
})(RelayMsgAction || (RelayMsgAction = {}));
PATH_RECEIVE = "receive";
PATH_CHANGE = "change";
PATH_DEFI = "defi";
}
});
// node_modules/@wizardconnect/core/dist/utilnostr.js
import { binToHex, secp256k1 as secp256k12 } from "@bitauth/libauth";
function deriveNostrPublicKey(privateKey) {
const publicKeyCompressed = unwrap(secp256k12.derivePublicKeyCompressed(privateKey));
const publicKeyNostr = publicKeyCompressed.slice(1);
return binToHex(publicKeyNostr);
}
function deriveNostrPublicKeyBytes(privateKey) {
const publicKeyCompressed = unwrap(secp256k12.derivePublicKeyCompressed(privateKey));
return publicKeyCompressed.slice(1);
}
var init_utilnostr = __esm({
"node_modules/@wizardconnect/core/dist/utilnostr.js"() {
init_primitives();
}
});
// node_modules/@wizardconnect/core/dist/log.js
function debug(scope, ...args) {
console.log(`[${scope}]`, ...args);
}
function warn(scope, ...args) {
console.warn(`[${scope}]`, ...args);
}
function error(scope, ...args) {
console.error(`[${scope}]`, ...args);
}
var Scope;
var init_log = __esm({
"node_modules/@wizardconnect/core/dist/log.js"() {
(function(Scope2) {
Scope2["Relay"] = "relay";
Scope2["Network"] = "network";
Scope2["Misc"] = "misc";
})(Scope || (Scope = {}));
}
});
// node_modules/@wizardconnect/core/dist/message-queue.js
var MessageQueue;
var init_message_queue = __esm({
"node_modules/@wizardconnect/core/dist/message-queue.js"() {
init_log();
MessageQueue = class {
queue = [];
isReady = false;
logActivity = false;
constructor(options) {
this.logActivity = options?.logActivity ?? false;
}
getReady() {
return this.isReady;
}
getQueueLength() {
return this.queue.length;
}
enqueue(message) {
if (this.isReady) {
return Promise.resolve();
}
if (this.logActivity) {
debug(Scope.Relay, `net: Relays not ready, queuing message ${message.action}`);
}
return new Promise((resolve, reject) => {
this.queue.push({ message, resolve, reject });
});
}
async setReady(publishFn) {
this.isReady = true;
const queuedMessages = [...this.queue];
this.queue = [];
if (queuedMessages.length > 0 && this.logActivity) {
debug(Scope.Relay, `Processing ${queuedMessages.length} queued messages`);
}
for (const queued of queuedMessages) {
try {
await publishFn(queued.message);
queued.resolve();
} catch (error2) {
queued.reject(error2);
}
}
}
setNotReady(errorMessage = "Connection closed before message could be sent") {
this.isReady = false;
const queuedMessages = [...this.queue];
this.queue = [];
for (const queued of queuedMessages) {
queued.reject(new Error(errorMessage));
}
}
clear() {
const queuedMessages = [...this.queue];
this.queue = [];
for (const queued of queuedMessages) {
queued.reject(new Error("Queue cleared"));
}
}
};
}
});
// node_modules/@wizardconnect/core/dist/transforms/chunk.js
function chunkExtensionAdvertisement() {
return { version: CHUNK_EXTENSION_VERSION };
}
function peerSupportsChunk(extensions) {
return !!extensions && extensions[CHUNK_EXTENSION_NAME] !== void 0;
}
function utf8ByteLength(s) {
return new TextEncoder().encode(s).length;
}
function needsChunking(serialized) {
return utf8ByteLength(serialized) > CHUNK_REQUIRED_BYTES;
}
function splitIntoChunks(serialized, opts) {
const msgId = opts?.msgId ?? newMsgId();
const time = opts?.time ?? Math.floor(Date.now() / 1e3);
const utf8 = new TextEncoder().encode(serialized);
const b64 = bytesToBase64(utf8);
const sliceChars = Math.ceil(CHUNK_RAW_BYTES * 4 / 3);
const total = Math.max(1, Math.ceil(b64.length / sliceChars));
const chunks = [];
for (let i3 = 0; i3 < total; i3++) {
chunks.push({
action: RelayMsgAction.Chunk,
time,
msgId,
index: i3,
total,
data: b64.slice(i3 * sliceChars, (i3 + 1) * sliceChars)
});
}
return chunks;
}
function bytesToBase64(bytes) {
const CHUNK = 32768;
let binary = "";
for (let i3 = 0; i3 < bytes.length; i3 += CHUNK) {
const slice = bytes.subarray(i3, i3 + CHUNK);
binary += String.fromCharCode.apply(null, slice);
}
return btoa(binary);
}
function base64ToBytes(b64) {
const binary = atob(b64);
const out = new Uint8Array(binary.length);
for (let i3 = 0; i3 < binary.length; i3++) {
out[i3] = binary.charCodeAt(i3);
}
return out;
}
function newMsgId() {
const g = globalThis;
if (g.crypto?.randomUUID)
return g.crypto.randomUUID();
const bytes = new Uint8Array(16);
const cryptoObj = globalThis.crypto;
if (cryptoObj?.getRandomValues)
cryptoObj.getRandomValues(bytes);
else
for (let i3 = 0; i3 < 16; i3++)
bytes[i3] = Math.floor(Math.random() * 256);
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
}
var CHUNK_EXTENSION_NAME, CHUNK_EXTENSION_VERSION, CHUNK_RAW_BYTES, CHUNK_REQUIRED_BYTES, REASSEMBLY_TTL_MS, SWEEP_INTERVAL_MS, ChunkReassembler;
var init_chunk = __esm({
"node_modules/@wizardconnect/core/dist/transforms/chunk.js"() {
init_hdwalletv1();
init_log();
CHUNK_EXTENSION_NAME = "chunk";
CHUNK_EXTENSION_VERSION = 1;
CHUNK_RAW_BYTES = 3e4;
CHUNK_REQUIRED_BYTES = 4e4;
REASSEMBLY_TTL_MS = 12e4;
SWEEP_INTERVAL_MS = 1e4;
ChunkReassembler = class {
onComplete;
logActivity;
now;
buffers = /* @__PURE__ */ new Map();
/// msgIds that have already been delivered, kept for a short grace period
/// so late-arriving duplicate chunks (e.g. cross-subscription replay after
/// reconnect) don't spawn a second reassembly and double-deliver.
completed = /* @__PURE__ */ new Map();
sweeperId = null;
constructor(onComplete, logActivity = true, now2 = () => Date.now()) {
this.onComplete = onComplete;
this.logActivity = logActivity;
this.now = now2;
}
start() {
if (this.sweeperId !== null)
return;
this.sweeperId = setInterval(() => this.sweep(), SWEEP_INTERVAL_MS);
}
stop() {
if (this.sweeperId !== null) {
clearInterval(this.sweeperId);
this.sweeperId = null;
}
this.buffers.clear();
this.completed.clear();
}
/// For tests. Otherwise start() schedules this automatically.
sweep() {
const now2 = this.now();
for (const [id, entry] of this.buffers) {
if (entry.expiresAt <= now2) {
this.buffers.delete(id);
if (this.logActivity) {
debug(Scope.Relay, `Chunk reassembly timeout: ${id} (${entry.received}/${entry.total} received)`);
}
}
}
for (const [id, expiresAt] of this.completed) {
if (expiresAt <= now2)
this.completed.delete(id);
}
}
/// Ingest one chunk. If this completes the message, onComplete fires.
/// Duplicate chunks (same msgId/index) are idempotent. Malformed chunks
/// are dropped silently.
ingest(chunk) {
if (this.completed.has(chunk.msgId)) {
return;
}
let entry = this.buffers.get(chunk.msgId);
if (!entry) {
entry = {
total: chunk.total,
chunks: new Array(chunk.total),
received: 0,
expiresAt: this.now() + REASSEMBLY_TTL_MS
};
this.buffers.set(chunk.msgId, entry);
} else if (entry.total !== chunk.total) {
if (this.logActivity) {
error(Scope.Relay, `Chunk total mismatch for ${chunk.msgId}: ${chunk.total} vs expected ${entry.total}`);
}
return;
}
if (entry.chunks[chunk.index] !== void 0) {
return;
}
entry.chunks[chunk.index] = chunk.data;
entry.received++;
if (entry.received !== entry.total)
return;
this.buffers.delete(chunk.msgId);
this.completed.set(chunk.msgId, this.now() + REASSEMBLY_TTL_MS);
let reassembled;
try {
const fullB64 = entry.chunks.join("");
const bytes = base64ToBytes(fullB64);
const json = new TextDecoder().decode(bytes);
const parsed = JSON.parse(json);
if (!isProtocolMessage(parsed)) {
if (this.logActivity) {
error(Scope.Relay, `Reassembled chunk msgId=${chunk.msgId} is not a valid ProtocolMessage`);
}
return;
}
reassembled = parsed;
} catch (e) {
if (this.logActivity) {
error(Scope.Relay, `Chunk reassembly failed for msgId=${chunk.msgId}:`, e);
}
return;
}
if (this.logActivity) {
debug(Scope.Relay, `Reassembled chunked message: action=${reassembled.action} chunks=${entry.total}`);
}
this.onComplete(reassembled);
}
/// Test helper: number of in-flight partial messages.
get bufferCount() {
return this.buffers.size;
}
};
}
});
// node_modules/@wizardconnect/core/dist/relay-client.js
import { binToHex as binToHex2, hash256, secp256k1 as secp256k13 } from "@bitauth/libauth";
var KIND_GIFT_WRAP, KIND_PRIVATE_DIRECT_MESSAGE, RelayClient;
var init_relay_client = __esm({
"node_modules/@wizardconnect/core/dist/relay-client.js"() {
init_primitives();
init_pool();
init_nip59();
init_browser();
init_eventemitter3();
init_hdwalletv1();
init_utilnostr();
init_message_queue();
init_log();
init_chunk();
useWebSocketImplementation(browser_default);
KIND_GIFT_WRAP = 1059;
KIND_PRIVATE_DIRECT_MESSAGE = 14;
RelayClient = class _RelayClient extends import_index.default {
// Keyed by "walletPubkeyHex:dappPubkeyHex". Persists the high-water mark
// across RelayClient instance teardowns within the same JS session so that
// reconnects after an explicit disconnect()+connect() still filter
// relay-replayed messages from the prior session.
static sessionTimestamps = /* @__PURE__ */ new Map();
pool;
sharedPool;
pairedPubkeyHex;
config;
subscription = null;
myPubkey;
myPubkeyHex;
lastProcessedTimestamp = 0;
messageQueue;
readyTimeoutId = null;
disconnecting = false;
/// Capability flag: peer advertised support for the `chunk` transport
/// extension in its dapp_ready / wallet_ready. Set via setPeerCapabilities.
peerSupportsChunk = false;
/// Receiver-side reassembly buffer. Always active — if no chunks arrive it
/// stays empty. Started in connect(), stopped in disconnect().
reassembler;
sequence = Math.floor(Math.random() * (Number.MAX_SAFE_INTEGER - 5e5));
pendingCalls = /* @__PURE__ */ new Map();
pendingDeliveries = /* @__PURE__ */ new Map();
get sessionKey() {
return this.pairedPubkeyHex ? `${this.myPubkeyHex}:${this.pairedPubkeyHex}` : null;
}
constructor(config, pool) {
super();
this.config = {
logNetworkActivity: true,
...config
};
this.pool = pool ?? new SimplePool({ enablePing: true });
this.sharedPool = pool !== void 0;
this.messageQueue = new MessageQueue({
logActivity: this.config.logNetworkActivity
});
this.reassembler = new ChunkReassembler((msg) => this.handleRelayMessage(msg), !!this.config.logNetworkActivity);
this.myPubkey = unwrap(secp256k13.derivePublicKeyCompressed(this.config.signerPrivateKey));
this.myPubkeyHex = deriveNostrPublicKey(this.config.signerPrivateKey);
if (this.config.pairedPublicKey) {
const pairedNostrPubkey = this.config.pairedPublicKey.length === 33 ? this.config.pairedPublicKey.slice(1) : this.config.pairedPublicKey;
this.pairedPubkeyHex = binToHex2(pairedNostrPubkey);
} else {
this.pairedPubkeyHex = "";
}
const saved = this.sessionKey ? _RelayClient.sessionTimestamps.get(this.sessionKey) : void 0;
if (saved)
this.lastProcessedTimestamp = saved;
}
setPairedPublicKey(pairedPublicKey) {
this.config.pairedPublicKey = pairedPublicKey;
const pairedNostrPubkey = pairedPublicKey.length === 33 ? pairedPublicKey.slice(1) : pairedPublicKey;
this.pairedPubkeyHex = binToHex2(pairedNostrPubkey);
const saved = _RelayClient.sessionTimestamps.get(this.sessionKey);
if (saved && saved > this.lastProcessedTimestamp) {
this.lastProcessedTimestamp = saved;
}
this.emit("paired");
}
/// Set transport-level capability flags based on the peer's advertisement in
/// its dapp_ready / wallet_ready `extensions` field. Called by the connection
/// manager after the handshake. New capability keys are additive — callers
/// may omit any they don't set.
setPeerCapabilities(caps) {
if (caps.chunk !== void 0) {
this.peerSupportsChunk = caps.chunk;
}
}
getPublicKey() {
return this.myPubkey;
}
getPublicKeyHex() {
return this.myPubkeyHex;
}
isKeyExchangeComplete() {
if (!this.config.pairedPublicKey) {
return false;
}
return !this.config.pairedPublicKey.every((byte) => byte === 0);
}
emitDisconnect(error2) {
if (this.disconnecting)
return;
this.disconnecting = true;
this.emit("disconnect", error2);
}
async connect() {
if (this.config.logNetworkActivity) {
debug(Scope.Relay, `Connecting to relay...`);
}
this.disconnecting = false;
this.reassembler.start();
if (this.lastProcessedTimestamp === 0) {
this.lastProcessedTimestamp = Math.floor(Date.now() / 1e3) - 2;
}
try {
this.subscription = this.pool.subscribeMany(this.config.explicitRelayUrls, { kinds: [KIND_GIFT_WRAP], "#p": [this.myPubkeyHex] }, {
onevent: (event) => this.handleWrappedEvent(event),
oneose: () => {
if (this.readyTimeoutId) {
clearTimeout(this.readyTimeoutId);
this.readyTimeoutId = null;
}
if (this.config.logNetworkActivity) {
debug(Scope.Relay, `EOSE received, relay connected`);
}
this.messageQueue.setReady((msg) => this.publishMessage(msg));
this.emit("connection");
},
onclose: (reasons) => {
if (this.config.logNetworkActivity) {
debug(Scope.Relay, `Subscription closed: ${reasons.join(", ")}`);
}
this.emitDisconnect(new Error("Subscription closed"));
}
});
this.readyTimeoutId = setTimeout(() => {
if (!this.messageQueue.getReady()) {
if (this.config.logNetworkActivity) {
debug(Scope.Relay, `EOSE timeout, assuming ready`);
}
this.messageQueue.setReady((msg) => this.publishMessage(msg));
this.emit("connection");
}
this.readyTimeoutId = null;
}, 5e3);
if (this.config.logNetworkActivity) {
debug(Scope.Relay, `Subscription created, waiting for relay connection`);
}
} catch (error2) {
if (this.config.logNetworkActivity) {
error(Scope.Relay, `Connection failed:`, error2);
}
throw error2;
}
}
async disconnect() {
this.lastProcessedTimestamp = Math.floor(Date.now() / 1e3);
const key = this.sessionKey;
if (key)
_RelayClient.sessionTimestamps.set(key, this.lastProcessedTimestamp);
this.messageQueue.setNotReady();
this.reassembler.stop();
if (this.readyTimeoutId) {
clearTimeout(this.readyTimeoutId);
this.readyTimeoutId = null;
}
if (this.subscription) {
this.subscription.close();
this.subscription = null;
}
if (!this.sharedPool) {
this.pool.close(this.config.explicitRelayUrls);
}
}
getLastProcessedTimestamp() {
return this.lastProcessedTimestamp;
}
setLastProcessedTimestamp(timestamp) {
this.lastProcessedTimestamp = timestamp;
}
async relay(message) {
if (!this.config.pairedPublicKey) {
throw new Error("Cannot relay message: paired public key not set. Call setPairedPublicKey() first.");
}
if (!this.messageQueue.getReady()) {
return this.messageQueue.enqueue(message);
}
return this.publishMessage(message);
}
async publishMessage(message) {
const serialized = JSON.stringify(message);
if (!needsChunking(serialized)) {
return this.publishSerialized(message.action, serialized);
}
if (!this.peerSupportsChunk) {
const err = new Error(`Cannot send ${message.action}: message is larger than NIP-44's 65,535-byte ceiling and the peer does not advertise the 'chunk' transport extension. Please update the connected wallet/dapp to a version that supports chunked messages.`);
if (this.config.logNetworkActivity) {
error(Scope.Relay, err.message);
}
throw err;
}
const chunks = splitIntoChunks(serialized);
if (this.config.logNetworkActivity) {
debug(Scope.Relay, `Chunking ${message.action}: ${chunks.length} chunks (serialized ~${serialized.length} bytes)`);
}
for (const chunk of chunks) {
await this.publishSerialized(`${message.action}[chunk ${chunk.index + 1}/${chunk.total}]`, JSON.stringify(chunk));
}
}
/// Wrap and publish one gift-wrap event. Used for both unchunked messages
/// and individual chunks. `displayAction` is only used for logs.
async publishSerialized(displayAction, serialized) {
this.netlog("send", displayAction);
const wrapped = wrapEvent({
kind: KIND_PRIVATE_DIRECT_MESSAGE,
content: serialized,
created_at: Math.floor(Date.now() / 1e3),
tags: [["p", this.pairedPubkeyHex]]
}, this.config.signerPrivateKey, this.pairedPubkeyHex);
const results = await Promise.allSettled(this.pool.publish(this.config.explicitRelayUrls, wrapped));
const fulfilled = results.filter((r) => r.status === "fulfilled");
const rejected = results.filter((r) => r.status === "rejected");
if (rejected.length > 0 && this.config.logNetworkActivity) {
for (const r of rejected) {
error(Scope.Relay, `Failed to publish ${displayAction} to a relay:`, r.reason);
}
}
if (fulfilled.length === 0) {
const error2 = new Error(`Failed to publish ${displayAction} to all relays`);
if (this.config.logNetworkActivity) {
error(Scope.Relay, error2.message);
}
this.emitDisconnect(error2);
throw error2;
}
if (this.config.logNetworkActivity) {
debug(Scope.Relay, `Published message ${displayAction} to ${fulfilled.length}/${results.length} relay(s)`);
}
}
handleWrappedEvent(wrappedEvent) {
try {
const rumor = unwrapEvent(wrappedEvent, this.config.signerPrivateKey);
if (rumor.kind !== KIND_PRIVATE_DIRECT_MESSAGE) {
if (this.config.logNetworkActivity) {
debug(Scope.Relay, `Ignoring non-PrivateDirectMessage, kind: ${rumor.kind}`);
}
return;
}
let payload;
try {
payload = JSON.parse(rumor.content);
} catch (e) {
if (this.config.logNetworkActivity) {
error(Scope.Relay, "Failed to parse message content as JSON:", e);
}
return;
}
this.routeIncoming(payload, rumor.pubkey);
} catch (error2) {
if (this.config.logNetworkActivity) {
error(Scope.Relay, "Error handling incoming message:", error2);
}
this.emitError(error2);
}
}
/// Apply timestamp dedup + peer filter, then dispatch to chunk reassembly
/// or the application-level handler. Called from handleWrappedEvent (one
/// path: unwrap → route). Kept separate to keep handleWrappedEvent focused
/// on decryption and to allow future transport-layer transforms to invoke
/// this path with already-decoded payloads.
routeIncoming(payload, fromPubkey) {
if (!payload.time || this.lastProcessedTimestamp > 0 && payload.time < this.lastProcessedTimestamp) {
if (this.config.logNetworkActivity) {
debug(Scope.Relay, `Ignoring already-processed message (time: ${payload.time}, action: ${payload.action}, last processed: ${this.lastProcessedTimestamp})`);
}
return;
}
if (payload.time > this.lastProcessedTimestamp) {
this.lastProcessedTimestamp = payload.time;
const key = this.sessionKey;
if (key)
_RelayClient.sessionTimestamps.set(key, this.lastProcessedTimestamp);
}
const isKeyExchangeMessage = payload.action === RelayMsgAction.WalletReady;
if (!isKeyExchangeMessage && this.config.pairedPublicKey) {
const pairedNostrPubkey = this.config.pairedPublicKey.length === 33 ? binToHex2(this.config.pairedPublicKey.slice(1)) : binToHex2(this.config.pairedPublicKey);
if (fromPubkey !== pairedNostrPubkey) {
if (this.config.logNetworkActivity) {
debug(Scope.Relay, `Ignoring '${payload.action}' message from unknown peer: ${fromPubkey} (expected: ${pairedNostrPubkey})`);
}
return;
}
}
if (isChunkMessage(payload)) {
if (this.config.logNetworkActivity) {
debug(Scope.Relay, `Received chunk ${payload.index + 1}/${payload.total} (msgId=${payload.msgId})`);
}
this.reassembler.ingest(payload);
return;
}
if (this.config.logNetworkActivity) {
debug(Scope.Relay, `Received message ${payload.action} from relay`);
}
this.handleRelayMessage(payload);
}
isConnected() {
return this.subscription !== null;
}
netlog(direction, what, sequence) {
if (!this.config.logNetworkActivity) {
return;
}
const us = binToHex2(hash256(this.config.signerPrivateKey)).slice(-6);
const them = this.config.pairedPublicKey ? binToHex2(this.config.pairedPublicKey).slice(-6) : "??????";
const pending = `c${this.pendingCalls.size} d${this.pendingDeliveries.size}`;
if (direction === "send") {
debug(Scope.Relay, `net [${sequence ?? "?"} ${pending}] ${us} -> ${them}: ${what}`);
} else {
debug(Scope.Relay, `net [${sequence ?? "?"} ${pending}] ${us} <- ${them}: ${what}`);
}
}
async handleRelayMessage(message) {
throwUnless(isProtocolMessage(message), `Invalid protocol message: ${message}`);
this.emit("message", message);
}
nextSequence() {
const current = this.sequence;
this.sequence += 2;
return current;
}
emitError(error2) {
this.emit("error", error2);
}
};
}
});
// node_modules/@wizardconnect/core/dist/connection-manager.js
async function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
var createConnectionManager;
var init_connection_manager = __esm({
"node_modules/@wizardconnect/core/dist/connection-manager.js"() {
init_log();
createConnectionManager = (client, callbacks, events, options = {}) => {
const { reconnectInterval = 5e3, maxReconnectAttempts = Infinity, enableVisibilityHandling = true, scope = Scope.Network, onVisibilityChange } = options;
let isPaused = false;
let reconnectLoop = null;
let visibilityChangeHandler = null;
const triggerReconnect = (reason) => {
if (!isPaused) {
callbacks.onReconnecting(client, reason);
reconnectLoop = null;
startConnectionLoop();
}
};
const onConnected = () => callbacks.onConnected(client);
client.on(events.connected, onConnected);
const onDisconnected = (...args) => {
const err = args[0] instanceof Error ? args[0].message : null;
debug(scope, "Disconnected event received", err);
triggerReconnect(err);
};
const onError = (err) => {
const errorMsg = err?.message || String(err);
debug(scope, "Error event received", errorMsg);
triggerReconnect(errorMsg);
if (callbacks.onError) {
callbacks.onError(client, err);
}
};
client.on(events.disconnected, onDisconnected);
if (events.error) {
client.on(events.error, onError);
}
const setupVisibilityHandling = () => {
if (typeof document === "undefined") {
return;
}
visibilityChangeHandler = () => {
const state = document.visibilityState;
if (onVisibilityChange) {
const context = {
client,
state,
setPaused: (value) => {
isPaused = value;
},
isPaused: () => isPaused,
startConnectionLoop
};
(async () => {
try {
await onVisibilityChange(context);
} catch (err) {
debug(scope, "Error in custom visibility change handler:", err);
}
})();
return;
}
if (state === "hidden") {
isPaused = true;
(async () => {
try {
await client.disconnect();
callbacks.onDisconnected(client);
} catch (err) {
debug(scope, "Error disconnecting on visibility change:", err);
}
})();
} else if (state === "visible") {
if (isPaused) {
isPaused = false;
startConnectionLoop();
}
}
};
document.addEventListener("visibilitychange", visibilityChangeHandler);
};
const startConnectionLoop = () => {
if (reconnectLoop) {
return;
}
reconnectLoop = (async () => {
let reconnectAttempts = 0;
let wasConnected = false;
while (true) {
if (isPaused) {
await sleep(1e3);
continue;
}
try {
await client.connect();
reconnectAttempts = 0;
wasConnected = true;
reconnectLoop = null;
return;
} catch (e) {
reconnectAttempts++;
if (wasConnected || reconnectAttempts === 1) {
callbacks.onReconnecting(client, `${e}`);
wasConnected = false;
}
if (reconnectAttempts > maxReconnectAttempts) {
callbacks.onDisconnected(client);
reconnectLoop = null;
return;
}
try {
await client.disconnect();
} catch (disconnectError) {
debug(scope, "Failed to disconnect client", disconnectError);
}
await sleep(reconnectInterval);
}
}
})();
};
if (enableVisibilityHandling) {
setupVisibilityHandling();
}
const cleanup = async () => {
isPaused = true;
if (typeof document !== "undefined" && visibilityChangeHandler !== null) {
document.removeEventListener("visibilitychange", visibilityChangeHandler);
}
client.off(events.connected, onConnected);
client.off(events.disconnected, onDisconnected);
if (events.error) {
client.off(events.error, onError);
}
callbacks.onDisconnected(client);
try {
await client.disconnect();
} catch (e) {
debug(scope, "Failed to disconnect client during cleanup", e);
}
};
return {
cleanup,
startConnectionLoop
};
};
}
});
// node_modules/@wizardconnect/core/dist/relay-handler.js
var RelayStatus, initiateRelay;
var init_relay_handler = __esm({
"node_modules/@wizardconnect/core/dist/relay-handler.js"() {
init_relay_client();
init_connection_manager();
init_log();
RelayStatus = class _RelayStatus {
status;
error;
sessionId;
constructor(status, error2, sessionId = null) {
this.status = status;
this.error = error2;
this.sessionId = sessionId;
}
static connected(sessionId) {
return new _RelayStatus("connected", null, sessionId || null);
}
static reconnecting(reason, sessionId) {
return new _RelayStatus("reconnecting", reason, sessionId || null);
}
static disconnected() {
return new _RelayStatus("disconnected", null, null);
}
static sessionDeleted() {
return new _RelayStatus("session_deleted", null, null);
}
};
initiateRelay = (dispatchCallback, signerPrivateKey, pairPublicKey, options) => {
const client = new RelayClient({
explicitRelayUrls: options?.explicitRelayUrls ?? [],
signerPrivateKey,
pairedPublicKey: pairPublicKey
});
let lastProcessedTimestamp = 0;
const connectionManager = createConnectionManager(client, {
onConnected: () => {
if (lastProcessedTimestamp > 0) {
client.setLastProcessedTimestamp(lastProcessedTimestamp);
} else {
lastProcessedTimestamp = client.getLastProcessedTimestamp();
}
dispatchCallback({
client,
status: RelayStatus.connected()
});
},
onReconnecting: (_client, reason) => {
dispatchCallback({
client,
status: RelayStatus.reconnecting(reason)
});
},
onDisconnected: () => {
dispatchCallback({
client,
status: RelayStatus.disconnected()
});
},
onError: (_client, _error) => {
}
}, {
connected: "connection",
disconnected: "disconnect",
error: "error"
}, {
reconnectInterval: options?.reconnectInterval,
maxReconnectAttempts: options?.maxReconnectAttempts,
enableVisibilityHandling: options?.enableVisibilityHandling ?? true,
scope: Scope.Relay,
onVisibilityChange: async (context) => {
if (context.state === "hidden") {
debug(Scope.Relay, "Page hidden, disconnecting relay");
context.setPaused(true);
try {
await client.disconnect();
lastProcessedTimestamp = client.getLastProcessedTimestamp();
debug(Scope.Relay, `Disconnected, last processed timestamp: ${lastProcessedTimestamp}`);
dispatchCallback({
client,
status: RelayStatus.disconnected()
});
} catch (error2) {
error(Scope.Relay, "Error disconnecting on visibility change:", error2);
}
} else if (context.state === "visible") {
if (context.isPaused()) {
debug(Scope.Relay, "Page visible, reconnecting relay");
context.setPaused(false);
context.startConnectionLoop();
}
}
}
});
connectionManager.startConnectionLoop();
return () => {
dispatchCallback({
client,
status: RelayStatus.disconnected()
});
(async () => {
try {
await connectionManager.cleanup();
} catch {
}
})();
};
};
}
});
// node_modules/@wizardconnect/core/dist/key-exchange.js
import { generatePrivateKey, binToHex as binToHex3, hexToBin, binToBech32Padded, bech32PaddedToBin } from "@bitauth/libauth";
function generateKeyExchangeCredentials() {
const privateKey = generatePrivateKey();
const privateKeyHex = binToHex3(privateKey);
const publicKeyHex = deriveNostrPublicKey(privateKey);
const secretBytes = generatePrivateKey();
const secretShort = secretBytes.slice(0, 8);
const secret = binToHex3(secretShort);
return {
privateKey: privateKeyHex,
publicKey: publicKeyHex,
secret
};
}
function encodeKeyExchangeURI(publicKey, secret, options = {}) {
const publicKeyBin = hexToBin(publicKey);
const secretBin = hexToBin(secret);
if (publicKeyBin.length !== 32) {
throw new Error(`Invalid public key length: expected 32 bytes, got ${publicKeyBin.length}`);
}
if (secretBin.length !== 8) {
throw new Error(`Invalid secret length: expected 8 bytes, got ${secretBin.length}`);
}
const publicKeyBech32 = binToBech32Padded(publicKeyBin).toLowerCase();
const secretBech32 = binToBech32Padded(secretBin).toLowerCase();
const hostname = options.hostname || DEFAULT_RELAY_HOSTNAME;
const port = options.port ?? DEFAULT_RELAY_PORT;
const protocol = options.protocol || DEFAULT_RELAY_PROTOCOL;
const isDefaultHostname = hostname === DEFAULT_RELAY_HOSTNAME;
const defaultPort = protocol === "wss" ? 443 : 80;
const isDefaultPort = port === defaultPort;
const isDefaultProtocol = protocol === DEFAULT_RELAY_PROTOCOL;
let uri;
if (isDefaultHostname && isDefaultPort && isDefaultProtocol) {
uri = `wiz://?p=${publicKeyBech32}&s=${secretBech32}`;
} else {
const portPart = isDefaultPort ? "" : `:${port}`;
const authority = `${hostname}${portPart}`;
uri = `wiz://${authority}?p=${publicKeyBech32}&s=${secretBech32}`;
if (!isDefaultProtocol) {
uri += `&pr=${protocol}`;
}
}
const qrUri = uri.toUpperCase().replace("?", "%3F").replace(/=/g, "%3D").replace(/&/g, "%26");
return { uri, qrUri };
}
function decodeKeyExchangeURI(uri) {
let url;
try {
const lower = uri.toLowerCase();
const isQr = lower.includes("%3f") && !lower.includes("?");
const toParse = isQr ? lower.replace("%3f", "?").replace(/%3d/g, "=").replace(/%26/g, "&") : lower;
url = new URL(toParse);
} catch (error2) {
throw new Error(`Invalid URI format: ${error2 instanceof Error ? error2.message : "unknown error"}`, { cause: error2 });
}
if (url.protocol !== "wiz:") {
throw new Error("Invalid URI scheme. Expected: wiz://");
}
let hostname = url.hostname || DEFAULT_RELAY_HOSTNAME;
let port;
if (url.port) {
const parsedPort = parseInt(url.port, 10);
if (isNaN(parsedPort) || parsedPort < 1 || parsedPort > 65535) {
throw new Error(`Invalid port number: ${url.port}`);
}
port = parsedPort;
} else {
port = DEFAULT_RELAY_PORT;
}
const publicKeyBech32 = url.searchParams.get("p");
const secretBech32 = url.searchParams.get("s");
if (!publicKeyBech32 || !secretBech32) {
throw new Error("Invalid URI format. Missing required parameters: p (public key) or s (secret)");
}
const protocol = url.searchParams.get("pr");
const publicKeyBech32Normalized = publicKeyBech32.toLowerCase();
const secretBech32Normalized = secretBech32.toLowerCase();
let publicKeyBin;
let secretBin;
try {
const pubkeyResult = bech32PaddedToBin(publicKeyBech32Normalized);
const secretResult = bech32PaddedToBin(secretBech32Normalized);
if (pubkeyResult instanceof Uint8Array && secretResult instanceof Uint8Array) {
publicKeyBin = pubkeyResult;
secretBin = secretResult;
} else {
const pubkeyError = typeof pubkeyResult === "string" ? pubkeyResult : "Unknown error";
const secretError = typeof secretResult === "string" ? secretResult : "Unknown error";
throw new Error(`Bech32 decoding failed: pubkey=${pubkeyError}, secret=${secretError}`);
}
} catch (error2) {
throw new Error(`Invalid bech32 encoding: ${error2 instanceof Error ? error2.message : "unknown error"}`, { cause: error2 });
}
if (publicKeyBin.length !== 32) {
throw new Error(`Invalid public key length: expected 32 bytes, got ${publicKeyBin.length}`);
}
if (secretBin.length !== 8) {
throw new Error(`Invalid secret length: expected 8 bytes, got ${secretBin.length}`);
}
if (protocol && protocol !== "ws" && protocol !== "wss") {
throw new Error(`Invalid protocol: ${protocol}. Must be 'ws' or 'wss'`);
}
if (!url.port && protocol === "ws") {
port = 80;
}
return {
publicKey: binToHex3(publicKeyBin),
secret: binToHex3(secretBin),
hostname,
port,
protocol: protocol || DEFAULT_RELAY_PROTOCOL
};
}
var DEFAULT_RELAY_HOSTNAME, DEFAULT_RELAY_PORT, DEFAULT_RELAY_PROTOCOL, DEFAULT_RELAY_URLS;
var init_key_exchange = __esm({
"node_modules/@wizardconnect/core/dist/key-exchange.js"() {
init_utilnostr();
DEFAULT_RELAY_HOSTNAME = "relay.riften.net";
DEFAULT_RELAY_PORT = 443;
DEFAULT_RELAY_PROTOCOL = "wss";
DEFAULT_RELAY_URLS = [
"wss://relay.riften.net:443",
"wss://relay.cauldron.quest:443"
];
}
});
// node_modules/@wizardconnect/core/dist/dapp-relay.js
import { hexToBin as hexToBin2, binToHex as binToHex4 } from "@bitauth/libauth";
function initiateDappRelay(statusCallback, options = {}) {
const events = new import_index.default();
let credentials;
let dappPrivateKey;
if (options.existingCredentials) {
const privateKeyHex = options.existingCredentials.privateKey;
if (privateKeyHex.length !== 64) {
throw new Error("Private key must be 64 hex characters (32 bytes)");
}
dappPrivateKey = hexToBin2(privateKeyHex);
const dappPublicKeyHex = deriveNostrPublicKey(dappPrivateKey);
credentials = {
privateKey: privateKeyHex,
publicKey: dappPublicKeyHex,
secret: options.existingCredentials.secret
};
} else {
credentials = generateKeyExchangeCredentials();
dappPrivateKey = hexToBin2(credentials.privateKey);
}
let uriOptions = {};
if (options.explicitRelayUrls && options.explicitRelayUrls.length > 0) {
const relayUrl = options.explicitRelayUrls[0];
const hostMatch = relayUrl.match(/^wss?:\/\/([^:/]+)/);
const portMatch = relayUrl.match(/:(\d+)/);
if (hostMatch) {
uriOptions.hostname = hostMatch[1];
}
if (portMatch) {
uriOptions.port = parseInt(portMatch[1], 10);
}
if (relayUrl.startsWith("wss://")) {
uriOptions.protocol = "wss";
} else if (relayUrl.startsWith("ws://")) {
uriOptions.protocol = "ws";
}
}
const { uri, qrUri } = encodeKeyExchangeURI(credentials.publicKey, credentials.secret, uriOptions);
let relayClient = null;
let keyExchanged = false;
let walletPublicKeyNostr = null;
if (options.existingCredentials) {
walletPublicKeyNostr = hexToBin2(options.existingCredentials.walletPublicKey);
keyExchanged = true;
}
const wrappedCallback = (payload) => {
if (!relayClient) {
relayClient = payload.client;
relayClient.on("message", async (message) => {
if (message.action === RelayMsgAction.WalletReady) {
const walletReady = message;
if (walletReady.secret !== credentials.secret) {
if (!keyExchanged) {
error(Scope.Relay, "Key exchange failed: secret mismatch");
}
return;
}
const receivedWalletKey = hexToBin2(walletReady.public_key);
if (receivedWalletKey.length !== 32) {
error(Scope.Relay, "Invalid wallet public key length");
return;
}
if (keyExchanged && walletPublicKeyNostr) {
if (binToHex4(receivedWalletKey) !== binToHex4(walletPublicKeyNostr)) {
warn(Scope.Relay, "Different wallet connected (different public key)");
}
}
walletPublicKeyNostr = receivedWalletKey;
relayClient.setPairedPublicKey(receivedWalletKey);
if (!keyExchanged) {
keyExchanged = true;
events.emit("keyexchangecomplete", receivedWalletKey);
}
}
});
}
if (payload.status.status === "connected") {
if (walletPublicKeyNostr && relayClient) {
relayClient.setPairedPublicKey(walletPublicKeyNostr);
keyExchanged = true;
}
}
statusCallback(payload);
};
const relayUrls = options.explicitRelayUrls && options.explicitRelayUrls.length > 0 ? options.explicitRelayUrls : [...DEFAULT_RELAY_URLS];
const cleanup = initiateRelay(wrappedCallback, dappPrivateKey, walletPublicKeyNostr ?? new Uint8Array(33), {
explicitRelayUrls: relayUrls,
reconnectInterval: options.reconnectInterval,
maxReconnectAttempts: options.maxReconnectAttempts
});
return {
client: relayClient,
uri,
qrUri,
credentials,
events,
cleanup
};
}
var init_dapp_relay = __esm({
"node_modules/@wizardconnect/core/dist/dapp-relay.js"() {
init_relay_handler();
init_hdwalletv1();
init_key_exchange();
init_eventemitter3();
init_utilnostr();
init_log();
}
});
// node_modules/@wizardconnect/core/dist/wallet-relay.js
import { hexToBin as hexToBin3 } from "@bitauth/libauth";
function initiateWalletRelay(statusCallback, options) {
let decoded;
try {
decoded = decodeKeyExchangeURI(options.uri);
} catch (err) {
throw new Error(`Failed to decode connection URI: ${err.message}`, {
cause: err
});
}
const dappPublicKeyHex = decoded.publicKey;
const secret = decoded.secret;
const dappPublicKeyNostr = hexToBin3(dappPublicKeyHex);
const hostname = decoded.hostname;
const protocol = decoded.protocol;
const port = decoded.port;
const relayUrl = `${protocol}://${hostname}:${port}`;
const walletPublicKeyNostr = deriveNostrPublicKeyBytes(options.walletPrivateKey);
let relayClient = null;
const wrappedCallback = (payload) => {
if (!relayClient) {
relayClient = payload.client;
}
if (payload.status.status === "connected") {
relayClient.setPairedPublicKey(dappPublicKeyNostr);
}
statusCallback(payload);
};
const relayUrls = [relayUrl];
const isDefaultRelay = DEFAULT_RELAY_URLS.includes(relayUrl);
if (isDefaultRelay) {
for (const defaultUrl of DEFAULT_RELAY_URLS) {
if (!relayUrls.includes(defaultUrl)) {
relayUrls.push(defaultUrl);
}
}
}
if (options.explicitRelayUrls && options.explicitRelayUrls.length > 0) {
for (const explicitUrl of options.explicitRelayUrls) {
if (!relayUrls.includes(explicitUrl)) {
relayUrls.push(explicitUrl);
}
}
}
const cleanup = initiateRelay(wrappedCallback, options.walletPrivateKey, dappPublicKeyNostr, {
explicitRelayUrls: relayUrls,
reconnectInterval: options.reconnectInterval,
maxReconnectAttempts: options.maxReconnectAttempts
});
const result = {
get client() {
if (!relayClient) {
throw new Error("Relay client not yet initialized. Wait for connection status callback.");
}
return relayClient;
},
dappPublicKey: dappPublicKeyNostr,
walletPublicKey: walletPublicKeyNostr,
secret,
cleanup
};
return result;
}
var init_wallet_relay = __esm({
"node_modules/@wizardconnect/core/dist/wallet-relay.js"() {
init_relay_handler();
init_key_exchange();
init_utilnostr();
}
});
// node_modules/@wizardconnect/core/dist/protocols/base.js
function isDappReadyMessage(msg) {
return isProtocolMessage(msg) && msg.action === RelayMsgAction.DappReady && Array.isArray(msg.supported_protocols) && typeof msg.wallet_discovered === "boolean";
}
function isWalletReadyMessage(msg) {
const m = msg;
return isProtocolMessage(msg) && msg.action === RelayMsgAction.WalletReady && typeof m.wallet_name === "string" && typeof m.wallet_icon === "string" && typeof m.dapp_discovered === "boolean" && Array.isArray(m.supported_protocols) && m.session !== null && typeof m.session === "object" && typeof m.public_key === "string" && typeof m.secret === "string";
}
function isDisconnectMessage(msg) {
return isProtocolMessage(msg) && msg.action === RelayMsgAction.Disconnect && typeof msg.reason === "string";
}
var DisconnectReason;
var init_base2 = __esm({
"node_modules/@wizardconnect/core/dist/protocols/base.js"() {
init_hdwalletv1();
(function(DisconnectReason2) {
DisconnectReason2["ProtocolMismatch"] = "protocol_mismatch";
DisconnectReason2["UserDisconnect"] = "user_disconnect";
})(DisconnectReason || (DisconnectReason = {}));
}
});
// node_modules/@wizardconnect/core/dist/serialize.js
import { hexToBin as hexToBin4 } from "@bitauth/libauth";
function parseExtendedJson(jsonString) {
return JSON.parse(jsonString, (_key, value) => {
if (typeof value === "string") {
const bigintMatch = value.match(BIGINT_RE);
if (bigintMatch)
return BigInt(bigintMatch[1]);
const uint8Match = value.match(UINT8_RE);
if (uint8Match)
return hexToBin4(uint8Match[1]);
}
return value;
});
}
function isExtendedJsonFormat(str) {
return UINT8_RE.test(str) || BIGINT_RE.test(str);
}
function parseExtendedJsonValue(value) {
const bigintMatch = value.match(BIGINT_RE);
if (bigintMatch)
return BigInt(bigintMatch[1]);
const uint8Match = value.match(UINT8_RE);
if (uint8Match)
return hexToBin4(uint8Match[1]);
return value;
}
function toUint8Array(value) {
if (value instanceof Uint8Array)
return value;
if (isExtendedJsonFormat(value))
return parseExtendedJsonValue(value);
return hexToBin4(value);
}
function toBigInt(value) {
if (typeof value === "bigint")
return value;
if (typeof value === "string") {
if (isExtendedJsonFormat(value))
return parseExtendedJsonValue(value);
return BigInt(value);
}
return BigInt(value);
}
var BIGINT_RE, UINT8_RE;
var init_serialize = __esm({
"node_modules/@wizardconnect/core/dist/serialize.js"() {
BIGINT_RE = /^<bigint: (?<bigint>[0-9]*)n>$/;
UINT8_RE = /^<Uint8Array: 0x(?<hex>[0-9a-f]*)>$/u;
}
});
// node_modules/@wizardconnect/core/dist/index.js
var dist_exports = {};
__export(dist_exports, {
CHUNK_EXTENSION_NAME: () => CHUNK_EXTENSION_NAME,
CHUNK_EXTENSION_VERSION: () => CHUNK_EXTENSION_VERSION,
DEFAULT_RELAY_HOSTNAME: () => DEFAULT_RELAY_HOSTNAME,
DEFAULT_RELAY_PORT: () => DEFAULT_RELAY_PORT,
DEFAULT_RELAY_PROTOCOL: () => DEFAULT_RELAY_PROTOCOL,
DEFAULT_RELAY_URLS: () => DEFAULT_RELAY_URLS,
DisconnectReason: () => DisconnectReason,
PATH_CHANGE: () => PATH_CHANGE,
PATH_DEFI: () => PATH_DEFI,
PATH_RECEIVE: () => PATH_RECEIVE,
PROTOCOL_NAME: () => PROTOCOL_NAME,
RelayClient: () => RelayClient,
RelayMsgAction: () => RelayMsgAction,
RelayStatus: () => RelayStatus,
SimplePool: () => SimplePool,
bech32PaddedToBin: () => bech32PaddedToBin2,
binToBech32Padded: () => binToBech32Padded2,
binToHex: () => binToHex5,
childIndexOfPathName: () => childIndexOfPathName,
chunkExtensionAdvertisement: () => chunkExtensionAdvertisement,
decodeKeyExchangeURI: () => decodeKeyExchangeURI,
encodeKeyExchangeURI: () => encodeKeyExchangeURI,
generateKeyExchangeCredentials: () => generateKeyExchangeCredentials,
hexToBin: () => hexToBin5,
initiateDappRelay: () => initiateDappRelay,
initiateRelay: () => initiateRelay,
initiateWalletRelay: () => initiateWalletRelay,
isChunkMessage: () => isChunkMessage,
isDappReadyMessage: () => isDappReadyMessage,
isDisconnectMessage: () => isDisconnectMessage,
isErrorMessage: () => isErrorMessage,
isExtendedJsonFormat: () => isExtendedJsonFormat,
isHdwalletv1Session: () => isHdwalletv1Session,
isPathXpub: () => isPathXpub,
isProtocolMessage: () => isProtocolMessage,
isSignCancelMessage: () => isSignCancelMessage,
isSignTransactionRequest: () => isSignTransactionRequest,
isWalletReadyMessage: () => isWalletReadyMessage,
parseExtendedJson: () => parseExtendedJson,
parseExtendedJsonValue: () => parseExtendedJsonValue,
peerSupportsChunk: () => peerSupportsChunk,
toBigInt: () => toBigInt,
toUint8Array: () => toUint8Array
});
import { binToHex as binToHex5, hexToBin as hexToBin5, binToBech32Padded as binToBech32Padded2, bech32PaddedToBin as bech32PaddedToBin2 } from "@bitauth/libauth";
var init_dist = __esm({
"node_modules/@wizardconnect/core/dist/index.js"() {
init_relay_client();
init_pool();
init_relay_handler();
init_dapp_relay();
init_wallet_relay();
init_key_exchange();
init_hdwalletv1();
init_base2();
init_chunk();
init_serialize();
}
});
// node_modules/@wizardconnect/dapp/dist/pubkey-state-manager.js
import { deriveHdPublicNodeChild } from "@bitauth/libauth";
var DappPubkeyStateManager;
var init_pubkey_state_manager = __esm({
"node_modules/@wizardconnect/dapp/dist/pubkey-state-manager.js"() {
DappPubkeyStateManager = class {
// xpub nodes for on-demand pubkey derivation
xpubNodes = /* @__PURE__ */ new Map();
/** Derive a pubkey on demand from the stored xpub node. */
getPubkey(childIndex, index) {
const xpubNode = this.xpubNodes.get(childIndex);
if (!xpubNode)
return void 0;
const child = deriveHdPublicNodeChild(xpubNode, Number(index));
if (typeof child === "string")
return void 0;
return child.publicKey;
}
/** Returns true if an xpub node is available for this child index. */
hasPath(childIndex) {
return this.xpubNodes.has(childIndex);
}
setXpubNode(childIndex, node) {
this.xpubNodes.set(childIndex, node);
}
getXpubNode(childIndex) {
return this.xpubNodes.get(childIndex);
}
};
}
});
// node_modules/@wizardconnect/dapp/dist/session.js
function defaultStorage() {
if (typeof localStorage !== "undefined" && typeof localStorage.getItem === "function")
return localStorage;
return null;
}
function resolveStorage(storage) {
return storage ?? defaultStorage();
}
function loadSession(key = DEFAULT_SESSION_KEY, storage) {
const s = resolveStorage(storage);
if (!s)
return null;
const raw = s.getItem(key);
if (!raw)
return null;
try {
const parsed = JSON.parse(raw);
if (!parsed.privateKey || !parsed.secret)
return null;
return parsed;
} catch {
return null;
}
}
function saveSession(key = DEFAULT_SESSION_KEY, data, storage) {
const s = resolveStorage(storage);
if (!s)
return;
const existing = loadSession(key, s);
const merged = { ...existing, ...data };
s.setItem(key, JSON.stringify(merged));
}
function clearSession(key = DEFAULT_SESSION_KEY, storage) {
const s = resolveStorage(storage);
if (!s)
return;
s.removeItem(key);
}
var DEFAULT_SESSION_KEY;
var init_session = __esm({
"node_modules/@wizardconnect/dapp/dist/session.js"() {
DEFAULT_SESSION_KEY = "wizardconnect-session";
}
});
// node_modules/@wizardconnect/dapp/dist/dapp-connection-manager.js
import { decodeHdPublicKey } from "@bitauth/libauth";
var DappConnectionManager;
var init_dapp_connection_manager = __esm({
"node_modules/@wizardconnect/dapp/dist/dapp-connection-manager.js"() {
init_eventemitter3();
init_dist();
init_pubkey_state_manager();
init_session();
DappConnectionManager = class extends import_index.default {
dappName;
dappIcon;
conn = null;
listenerAttached = false;
/** Pubkey state — exposed for callers that need to query by index. */
pubkeyState;
walletName = null;
walletIcon = null;
protocol = null;
/** Protocols this dapp supports, in preference order. */
supportedProtocols = [PROTOCOL_NAME];
walletDiscovered = false;
disconnectGraceTimer = null;
pingInterval = null;
/** Timestamp (ms) of the last pong or wallet_ready received. Used for liveness detection. */
lastPongTime = 0;
sessionPaths = [];
pendingSignatureRequests = /* @__PURE__ */ new Map();
sessionOptions = null;
/**
* @param dappName Optional display name of the dapp (sent in dapp_ready).
* @param dappIcon Optional icon URL/data-URI of the dapp (sent in dapp_ready).
* @param options Optional configuration. Session persistence is enabled by
* default (key: "wizardconnect-session", storage: localStorage).
* Pass `session: false` to disable.
*/
constructor(dappName, dappIcon, options) {
super();
this.dappName = dappName;
this.dappIcon = dappIcon;
this.pubkeyState = new DappPubkeyStateManager();
if (options?.session !== false) {
const sessionConf = options?.session ?? {};
this.sessionOptions = {
key: sessionConf.key ?? DEFAULT_SESSION_KEY,
storage: sessionConf.storage
};
const stored = loadSession(this.sessionOptions.key, this.sessionOptions.storage);
if (stored) {
if (stored.walletName)
this.walletName = stored.walletName;
if (stored.walletIcon)
this.walletIcon = stored.walletIcon;
if (stored.paths?.length) {
try {
this.restoreSessionPaths(stored.paths);
} catch {
}
}
}
}
}
// --- Session persistence (public API) ----------------------------------------
/**
* Attach a relay result from `initiateDappRelay()`. Automatically:
* - Saves relay credentials (privateKey, secret) to the session
* - Listens for `keyexchangecomplete` and saves the wallet public key
*
* No-op if session persistence is disabled.
*/
attachRelay(relay) {
if (!this.sessionOptions)
return;
saveSession(this.sessionOptions.key, {
privateKey: relay.credentials.privateKey,
secret: relay.credentials.secret
}, this.sessionOptions.storage);
relay.events.on("keyexchangecomplete", (walletPublicKey) => {
if (!this.sessionOptions)
return;
saveSession(this.sessionOptions.key, { walletPublicKey: binToHex5(walletPublicKey) }, this.sessionOptions.storage);
});
}
/**
* Load the stored session (e.g. for reconnection).
* Returns null if session persistence is disabled or no session exists.
*/
loadStoredSession() {
if (!this.sessionOptions)
return null;
return loadSession(this.sessionOptions.key, this.sessionOptions.storage);
}
/**
* Clear the stored session. Call on disconnect.
* No-op if session persistence is disabled.
*/
clearStoredSession() {
if (!this.sessionOptions)
return;
clearSession(this.sessionOptions.key, this.sessionOptions.storage);
}
// --- Relay connection -------------------------------------------------------
/**
* Call this from the RelayStatusCallback passed to `initiateDappRelay`.
* Attaches the message listener exactly once and re-sends dapp_ready
* each time the connection is established (handles reconnects).
*/
updateConnection(client, status) {
if (client) {
if (!this.listenerAttached) {
this.listenerAttached = true;
client.on("message", (msg) => this.handleMessage(msg));
}
this.conn = client;
}
if (status.status === "connected" && this.conn) {
this.onConnected();
} else if (status.status === "reconnecting" || status.status === "disconnected") {
this.stopPingInterval();
if (status.status === "reconnecting") {
this.emit("reconnecting");
}
}
}
isWalletDiscovered() {
return this.walletDiscovered;
}
/**
* Get a sequence number from the relay client.
* Use this to populate the `sequence` field of a SignTransactionRequest.
*/
nextSequence() {
if (!this.conn)
throw new Error("[wizardconnect/dapp] Not connected");
return this.conn.nextSequence();
}
/**
* Send a sign transaction request and wait for the wallet's response.
* The caller is responsible for creating the full SignTransactionRequest
* (including sequence from `nextSequence()`).
*/
async sendSignRequest(request) {
if (!this.conn)
throw new Error("[wizardconnect/dapp] Not connected");
return new Promise((resolve, reject) => {
this.pendingSignatureRequests.set(request.sequence, {
request,
resolve,
reject
});
this.conn.relay(request).then(() => {
this.emit("messagesent", request);
}).catch((err) => {
this.pendingSignatureRequests.delete(request.sequence);
reject(err instanceof Error ? err : new Error(String(err)));
});
});
}
/**
* Cancel an in-flight sign request.
* Immediately rejects the pending Promise and sends sign_cancel to the wallet.
*/
async sendSignCancel(sequence, reason) {
const handlers = this.pendingSignatureRequests.get(sequence);
if (handlers) {
this.pendingSignatureRequests.delete(sequence);
handlers.reject(new Error(reason ?? "Sign request cancelled"));
}
if (!this.conn)
return;
const msg = {
action: RelayMsgAction.SignCancel,
sequence,
...reason !== void 0 && { reason },
time: Math.floor(Date.now() / 1e3)
};
await this.conn.relay(msg);
this.emit("messagesent", msg);
}
/**
* Send a disconnect message to the wallet (courtesy notification).
* The caller is responsible for calling dappRelay.cleanup() afterwards.
*/
async sendDisconnect(message) {
if (!this.conn)
return;
const msg = {
action: RelayMsgAction.Disconnect,
reason: DisconnectReason.UserDisconnect,
time: Math.floor(Date.now() / 1e3),
...message !== void 0 && { message }
};
await this.conn.relay(msg);
this.emit("messagesent", msg);
}
/**
* Convenience method: build and send a sign transaction request.
* Auto-fills `action`, `sequence`, and `time`. Supports cancellation via
* AbortSignal — when aborted, sendSignCancel is called automatically.
*/
async signTransaction(request, options) {
const sequence = this.nextSequence();
const fullRequest = {
action: RelayMsgAction.SignTransactionRequest,
time: Math.floor(Date.now() / 1e3),
sequence,
...request
};
const signPromise = this.sendSignRequest(fullRequest);
if (!options?.signal)
return signPromise;
signPromise.catch(() => {
});
return new Promise((resolve, reject) => {
const onAbort = () => {
const reason = options.signal.reason instanceof Error ? options.signal.reason.message : typeof options.signal.reason === "string" ? options.signal.reason : "Sign request cancelled";
this.sendSignCancel(sequence, reason).catch(() => {
});
reject(new DOMException(reason, "AbortError"));
};
if (options.signal.aborted) {
onAbort();
return;
}
options.signal.addEventListener("abort", onAbort, { once: true });
signPromise.then(resolve).catch(reject).finally(() => {
options.signal.removeEventListener("abort", onAbort);
});
});
}
// --- Pubkey state delegation ------------------------------------------------
// Convenience methods that forward to pubkeyState.
getPubkey(childIndex, index) {
return this.pubkeyState.getPubkey(childIndex, index);
}
/** Returns true if an xpub node is available for this child index. */
hasPath(childIndex) {
return this.pubkeyState.hasPath(childIndex);
}
/**
* Returns the stored xpub node for the given child index.
* Available after wallet_ready is received.
*/
getXpubNode(childIndex) {
return this.pubkeyState.getXpubNode(childIndex);
}
/**
* Returns the raw PathXpub entries received from the wallet.
* Available after wallet_ready is received.
*/
getSessionPaths() {
return [...this.sessionPaths];
}
/**
* Restore session paths from a previous session (e.g. from localStorage).
* Decodes xpub strings and populates pubkeyState so getPubkey() works
* without waiting for wallet_ready.
*/
restoreSessionPaths(paths) {
this.sessionPaths = [...paths];
for (const pathInfo of paths) {
const decoded = decodeHdPublicKey(pathInfo.xpub);
if (typeof decoded === "string") {
throw new Error(`[wizardconnect/dapp] Invalid xpub for path "${pathInfo.name}": ${decoded}`);
}
const ci = childIndexOfPathName(pathInfo.name);
if (ci !== void 0) {
this.pubkeyState.setXpubNode(ci, decoded.node);
}
}
}
// --- Private protocol handling -------------------------------------------
onConnected() {
(async () => {
const deadline = Date.now() + 3e4;
while (this.conn && !this.conn.isKeyExchangeComplete()) {
if (Date.now() >= deadline) {
console.error("[wizardconnect/dapp] Key exchange timed out");
return;
}
await new Promise((r) => setTimeout(r, 100));
}
if (!this.conn)
return;
await this.pushDappReady();
})().catch((e) => console.error("[wizardconnect/dapp] Error in onConnected:", e));
}
startPingInterval() {
this.stopPingInterval();
this.lastPongTime = Date.now();
this.pingInterval = setInterval(() => {
if (!this.conn || !this.walletDiscovered)
return;
if (Date.now() - this.lastPongTime > 75e3) {
this.stopPingInterval();
this.emit("reconnecting");
return;
}
const ping = {
action: RelayMsgAction.Ping,
time: Math.floor(Date.now() / 1e3)
};
this.conn.relay(ping).catch(() => {
});
}, 1e4);
}
stopPingInterval() {
if (this.pingInterval !== null) {
clearInterval(this.pingInterval);
this.pingInterval = null;
}
}
destroy() {
this.stopPingInterval();
if (this.disconnectGraceTimer !== null) {
clearTimeout(this.disconnectGraceTimer);
this.disconnectGraceTimer = null;
}
}
async pushDappReady() {
if (!this.conn)
return;
const msg = {
action: RelayMsgAction.DappReady,
supported_protocols: this.supportedProtocols,
wallet_discovered: this.walletDiscovered,
time: Math.floor(Date.now() / 1e3),
// Include selected_protocol on the reactive send (after the dapp has seen the wallet)
...this.walletDiscovered && this.protocol && { selected_protocol: this.protocol },
...this.dappName !== void 0 && { dapp_name: this.dappName },
...this.dappIcon !== void 0 && { dapp_icon: this.dappIcon },
// Transport-level: advertise chunking so the wallet can send large
// SignTransactionResponses (signed tx hex can reach ~2 MB) that exceed
// NIP-44's plaintext ceiling.
extensions: { chunk: chunkExtensionAdvertisement() }
};
await this.conn.relay(msg);
this.emit("messagesent", msg);
}
handleMessage(msg) {
this.emit("messagereceived", msg);
switch (msg.action) {
case RelayMsgAction.WalletReady:
this.handleWalletReady(msg).catch((e) => console.error("[wizardconnect/dapp] Error handling wallet_ready:", e));
break;
case RelayMsgAction.SignTransactionResponse:
this.handleSignTransactionResponse(msg);
break;
case RelayMsgAction.Disconnect:
this.handleRemoteDisconnect(msg);
break;
case RelayMsgAction.Pong:
this.lastPongTime = Date.now();
break;
case RelayMsgAction.DappReady:
break;
default:
break;
}
}
handleRemoteDisconnect(msg) {
if (this.disconnectGraceTimer !== null) {
clearTimeout(this.disconnectGraceTimer);
}
this.disconnectGraceTimer = setTimeout(() => {
this.disconnectGraceTimer = null;
this.stopPingInterval();
this.emit("disconnect", msg.reason, msg.message);
}, 8e3);
}
async handleWalletReady(msg) {
if (this.disconnectGraceTimer !== null) {
clearTimeout(this.disconnectGraceTimer);
this.disconnectGraceTimer = null;
}
this.lastPongTime = Date.now();
this.walletDiscovered = true;
this.walletName = msg.wallet_name;
this.walletIcon = msg.wallet_icon;
const agreed = this.supportedProtocols.find((p) => msg.supported_protocols.includes(p));
if (!agreed) {
const detail = `No protocol overlap. Wallet: [${msg.supported_protocols}], Dapp: [${this.supportedProtocols}]`;
const disconnectMsg = {
action: RelayMsgAction.Disconnect,
reason: DisconnectReason.ProtocolMismatch,
message: detail,
time: Math.floor(Date.now() / 1e3)
};
this.conn?.relay(disconnectMsg).catch(() => {
});
this.stopPingInterval();
this.emit("disconnect", DisconnectReason.ProtocolMismatch, detail);
return;
}
this.protocol = agreed;
const sessionData = msg.session[agreed];
if (!isHdwalletv1Session(sessionData)) {
console.error("[wizardconnect/dapp] Invalid hdwalletv1 session data:", sessionData);
return;
}
if (this.conn) {
this.conn.setPeerCapabilities({
chunk: peerSupportsChunk(msg.extensions)
});
}
this.sessionPaths = [...sessionData.paths];
for (const pathInfo of sessionData.paths) {
const decoded = decodeHdPublicKey(pathInfo.xpub);
if (typeof decoded === "string") {
console.warn("[wizardconnect/dapp] Bad xpub for path", pathInfo.name, decoded);
continue;
}
const ci = childIndexOfPathName(pathInfo.name);
if (ci !== void 0) {
this.pubkeyState.setXpubNode(ci, decoded.node);
}
}
if (!msg.dapp_discovered) {
await this.pushDappReady().catch((e) => console.error("[wizardconnect/dapp] Error pushing dapp_ready:", e));
}
this.emit("walletready", msg);
if (this.pendingSignatureRequests.size > 0) {
const now2 = Math.floor(Date.now() / 1e3);
for (const [, entry] of this.pendingSignatureRequests) {
const refreshed = { ...entry.request, time: now2 };
this.conn.relay(refreshed).then(() => this.emit("messagesent", refreshed)).catch((err) => {
this.pendingSignatureRequests.delete(entry.request.sequence);
entry.reject(err instanceof Error ? err : new Error(String(err)));
});
}
}
if (this.sessionOptions) {
const sessionUpdate = {
walletName: this.walletName ?? void 0,
walletIcon: this.walletIcon ?? void 0,
paths: this.getSessionPaths()
};
saveSession(this.sessionOptions.key, sessionUpdate, this.sessionOptions.storage);
}
this.startPingInterval();
}
handleSignTransactionResponse(response) {
const handlers = this.pendingSignatureRequests.get(response.sequence);
if (!handlers) {
console.warn("[wizardconnect/dapp] No pending request for sequence:", response.sequence);
return;
}
this.pendingSignatureRequests.delete(response.sequence);
if (response.error) {
handlers.reject(new Error(response.error));
} else {
handlers.resolve(response);
}
}
};
}
});
// node_modules/@wizardconnect/dapp/dist/index.js
var dist_exports2 = {};
__export(dist_exports2, {
DEFAULT_SESSION_KEY: () => DEFAULT_SESSION_KEY,
DappConnectionManager: () => DappConnectionManager,
DappPubkeyStateManager: () => DappPubkeyStateManager,
clearSession: () => clearSession,
loadSession: () => loadSession,
saveSession: () => saveSession
});
var init_dist2 = __esm({
"node_modules/@wizardconnect/dapp/dist/index.js"() {
init_dapp_connection_manager();
init_pubkey_state_manager();
init_session();
}
});
// src/lib/connect/wizardconnect.js
var PATHS = { receive: 0, change: 1, defi: 7 };
var ADDRESS_WINDOW = 20;
async function openWizardSession({ dappName, dappIcon, prefix = "bchtest", crypto } = {}) {
const { pubkeyToAddress, pubkeyToLockingBytecode, binToHex: binToHex6, txidOfHex } = crypto ?? {};
if (!pubkeyToAddress || !pubkeyToLockingBytecode || !binToHex6 || !txidOfHex) {
throw new Error(
"openWizardSession needs `crypto: { pubkeyToAddress, pubkeyToLockingBytecode, binToHex, txidOfHex }` injected from the main bundle \u2014 see the note at the top of this file"
);
}
const [{ initiateDappRelay: initiateDappRelay2 }, { DappConnectionManager: DappConnectionManager2 }] = await Promise.all([
Promise.resolve().then(() => (init_dist(), dist_exports)),
Promise.resolve().then(() => (init_dist2(), dist_exports2))
]);
const manager = new DappConnectionManager2(dappName, dappIcon);
const relay = initiateDappRelay2((payload) => {
manager.updateConnection(payload.client, payload.status);
});
manager.attachRelay(relay);
let resolveReady, rejectReady;
const ready = new Promise((res, rej) => {
resolveReady = res;
rejectReady = rej;
});
manager.once("walletready", (msg) => resolveReady({ walletName: msg?.wallet_name ?? null }));
manager.once("disconnect", (reason, message) => rejectReady(new Error(`wallet disconnected: ${message ?? reason}`)));
const addressAt = (pathName, index) => {
const pubkey = manager.getPubkey(PATHS[pathName], BigInt(index));
if (!pubkey) return null;
return {
pathName,
index,
publicKey: pubkey,
address: pubkeyToAddress(pubkey, prefix, false),
tokenAddress: pubkeyToAddress(pubkey, prefix, true),
lockingBytecode: pubkeyToLockingBytecode(pubkey)
};
};
const derivedAddresses = (window2 = ADDRESS_WINDOW) => {
const out = [];
for (const pathName of ["receive", "change"]) {
if (!manager.hasPath(PATHS[pathName])) continue;
for (let i3 = 0; i3 < window2; i3++) {
const a = addressAt(pathName, i3);
if (a) out.push(a);
}
}
return out;
};
return {
label: "WizardConnect",
protocol: "hdwalletv1",
uri: relay.uri,
// wiz://?p=…&s=…
qrUri: relay.qrUri,
// QR-alphanumeric-safe variant
ready,
manager,
// hdwalletv1's `sign_transaction_response` carries ONLY `signedTransaction`
// (+ optional `error`) — there is no `signedTransactionHash`, and the wallet
// SDK has no broadcast step at all. So the dApp broadcasts, and we ask for
// `broadcast: false` to stop a wallet that reads the WC2-shaped payload's
// flag from doing it too. The registrar tolerates a duplicate anyway.
walletBroadcasts: false,
async getAddresses() {
if (!manager.isWalletDiscovered()) await ready;
return derivedAddresses().map((a) => a.address);
},
/** The full derived set, with the HD metadata `inputPaths` needs. */
async getDerivedAddresses(window2) {
if (!manager.isWalletDiscovered()) await ready;
return derivedAddresses(window2);
},
/**
* Sign a transaction built by register-tx.js.
*
* WizardConnect's differentiator is `inputPaths`: rather than the wallet
* guessing which key owns each input, we state it — [inputIndex, pathName,
* addressIndex]. The wallet re-derives each child key and checks it really
* does produce the source output's locking bytecode before signing, so a
* wrong triplet is a hard reject rather than a silent mis-sign.
*
* Note the wallet signs with SIGHASH_ALL|FORKID|UTXOS (stricter than WC2's
* ALL|FORKID). That is the wallet's business — our transaction is unchanged.
*/
async signTransaction(built, { userPrompt } = {}) {
if (!manager.isWalletDiscovered()) await ready;
const known = new Map(derivedAddresses().map((a) => [binToHex6(a.lockingBytecode), a]));
const inputPaths = built.sourceOutputs.map((src, inputIndex) => {
const a = known.get(binToHex6(src.lockingBytecode));
if (!a) {
throw new Error(
`input ${inputIndex} is not from this wallet \u2014 refusing to ask it to sign a coin it does not own`
);
}
return [inputIndex, a.pathName, a.index];
});
const response = await manager.signTransaction({
transaction: {
transaction: built.transaction,
sourceOutputs: built.sourceOutputs,
broadcast: false,
// we broadcast — see `walletBroadcasts` above
...userPrompt ? { userPrompt } : {}
},
inputPaths
});
if (response?.error) throw new Error(`wallet refused to sign: ${response.error}`);
if (!response?.signedTransaction) throw new Error("wallet returned no signed transaction");
return {
signedTransaction: response.signedTransaction,
// Derived locally: hdwalletv1 does not send the txid back.
signedTransactionHash: txidOfHex(response.signedTransaction)
};
},
async disconnect() {
try {
manager.clearStoredSession();
} catch {
}
try {
await manager.sendDisconnect("registration finished");
} catch {
}
try {
manager.destroy();
} catch {
}
try {
relay.cleanup();
} catch {
}
}
};
}
export {
ADDRESS_WINDOW,
PATHS,
openWizardSession
};