🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@getalby/lightning-tools

Package Overview
Dependencies
Maintainers
4
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@getalby/lightning-tools - npm Package Compare versions

Comparing version
8.0.0
to
8.1.0
+116
-7
dist/cjs/402.cjs

@@ -1179,2 +1179,15 @@ 'use strict';

};
function validatePreimage(preimage, paymentHash) {
try {
if (!/^[0-9a-fA-F]{64}$/.test(preimage))
return false;
if (!/^[0-9a-fA-F]{64}$/.test(paymentHash))
return false;
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return paymentHash === preimageHash;
}
catch {
return false;
}
}

@@ -1219,9 +1232,3 @@ class Invoice {

return false;
try {
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return this.paymentHash === preimageHash;
}
catch {
return false;
}
return validatePreimage(preimage, this.paymentHash);
}

@@ -1269,2 +1276,7 @@ async verifyPayment() {

/**
* Client: parse "www-authenticate" header from server response
* @param input
* @returns details from the header value (token or macaroon, invoice)
*/
const parseL402 = (input) => {

@@ -1284,2 +1296,15 @@ // Remove the L402 and LSAT identifiers

}
if (!keyValuePairs["token"] && keyValuePairs["macaroon"]) {
// fallback to old naming
keyValuePairs["token"] = keyValuePairs["macaroon"];
delete keyValuePairs["macaroon"];
}
if (!("token" in keyValuePairs) ||
typeof keyValuePairs["token"] !== "string") {
throw new Error("No macaroon or token found in www-authenticate header");
}
if (!("invoice" in keyValuePairs) ||
typeof keyValuePairs["invoice"] !== "string") {
throw new Error("No invoice found in www-authenticate header");
}
return keyValuePairs;

@@ -1584,2 +1609,81 @@ };

async function issueL402Macaroon(secret, paymentHash, params) {
if (params !== undefined &&
Object.prototype.hasOwnProperty.call(params, "paymentHash")) {
throw new Error("paymentHash is reserved");
}
const payload = { ...params, paymentHash };
const encoded = Buffer.from(JSON.stringify(payload)).toString("base64url");
const mac = await sign(secret, encoded);
return `${encoded}.${mac}`;
}
async function verifyL402Macaroon(secret, token) {
const { timingSafeEqual } = await import('crypto');
const dotIndex = token.lastIndexOf(".");
if (dotIndex === -1)
throw new Error("Invalid macaroon token");
const encoded = token.slice(0, dotIndex);
const mac = token.slice(dotIndex + 1);
// Constant-time comparison to prevent timing attacks
const expectedMac = await sign(secret, encoded);
try {
if (!timingSafeEqual(Buffer.from(mac, "hex"), Buffer.from(expectedMac, "hex"))) {
throw new Error("Invalid macaroon token");
}
}
catch (e) {
throw new Error("Invalid macaroon token");
}
try {
const parsed = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
if (parsed === null ||
typeof parsed !== "object" ||
Array.isArray(parsed) ||
typeof parsed.paymentHash !== "string") {
throw new Error("Invalid macaroon payload");
}
return parsed;
}
catch {
throw new Error("Invalid macaroon token");
}
}
async function sign(secret, payload) {
const { createHmac } = await import('crypto');
return createHmac("sha256", secret).update(payload).digest("hex");
}
/**
* Server: create a WWW-Authenticate header for a given macaroon and invoice
* @param args the macaroon/token and invoice generated for the client's request
* @returns the header value
*/
const makeL402AuthenticateHeader = (args) => {
if (!args.token) {
throw new Error("token must be provided");
}
return `L402 version="0" token="${args.token}", invoice="${args.invoice}"`;
};
/**
* Server: parse "authorization" header sent from client
* @param input value from authorization header
* @returns the macaroon and preimage
*/
function parseL402Authorization(input) {
// Backwards compat: LSAT was the former name of L402
const normalized = input.replace(/^LSAT /, "L402 ");
const prefix = "L402 ";
if (!normalized.startsWith(prefix))
return null;
const credentials = normalized.slice(prefix.length);
const colonIndex = credentials.indexOf(":");
if (colonIndex === -1) {
throw new Error("Invalid authorization header value");
}
return {
token: credentials.slice(0, colonIndex),
preimage: credentials.slice(colonIndex + 1),
};
}
exports.createGuardedWallet = createGuardedWallet;

@@ -1590,2 +1694,7 @@ exports.fetch402 = fetch402;

exports.fetchWithX402 = fetchWithX402;
exports.issueL402Macaroon = issueL402Macaroon;
exports.makeL402AuthenticateHeader = makeL402AuthenticateHeader;
exports.parseL402 = parseL402;
exports.parseL402Authorization = parseL402Authorization;
exports.verifyL402Macaroon = verifyL402Macaroon;
//# sourceMappingURL=402.cjs.map
'use strict';
/**
* Client: parse "www-authenticate" header from server response
* @param input
* @returns details from the header value (token or macaroon, invoice)
*/
const parseL402 = (input) => {

@@ -17,2 +22,15 @@ // Remove the L402 and LSAT identifiers

}
if (!keyValuePairs["token"] && keyValuePairs["macaroon"]) {
// fallback to old naming
keyValuePairs["token"] = keyValuePairs["macaroon"];
delete keyValuePairs["macaroon"];
}
if (!("token" in keyValuePairs) ||
typeof keyValuePairs["token"] !== "string") {
throw new Error("No macaroon or token found in www-authenticate header");
}
if (!("invoice" in keyValuePairs) ||
typeof keyValuePairs["invoice"] !== "string") {
throw new Error("No invoice found in www-authenticate header");
}
return keyValuePairs;

@@ -55,3 +73,87 @@ };

async function issueL402Macaroon(secret, paymentHash, params) {
if (params !== undefined &&
Object.prototype.hasOwnProperty.call(params, "paymentHash")) {
throw new Error("paymentHash is reserved");
}
const payload = { ...params, paymentHash };
const encoded = Buffer.from(JSON.stringify(payload)).toString("base64url");
const mac = await sign(secret, encoded);
return `${encoded}.${mac}`;
}
async function verifyL402Macaroon(secret, token) {
const { timingSafeEqual } = await import('crypto');
const dotIndex = token.lastIndexOf(".");
if (dotIndex === -1)
throw new Error("Invalid macaroon token");
const encoded = token.slice(0, dotIndex);
const mac = token.slice(dotIndex + 1);
// Constant-time comparison to prevent timing attacks
const expectedMac = await sign(secret, encoded);
try {
if (!timingSafeEqual(Buffer.from(mac, "hex"), Buffer.from(expectedMac, "hex"))) {
throw new Error("Invalid macaroon token");
}
}
catch (e) {
throw new Error("Invalid macaroon token");
}
try {
const parsed = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
if (parsed === null ||
typeof parsed !== "object" ||
Array.isArray(parsed) ||
typeof parsed.paymentHash !== "string") {
throw new Error("Invalid macaroon payload");
}
return parsed;
}
catch {
throw new Error("Invalid macaroon token");
}
}
async function sign(secret, payload) {
const { createHmac } = await import('crypto');
return createHmac("sha256", secret).update(payload).digest("hex");
}
/**
* Server: create a WWW-Authenticate header for a given macaroon and invoice
* @param args the macaroon/token and invoice generated for the client's request
* @returns the header value
*/
const makeL402AuthenticateHeader = (args) => {
if (!args.token) {
throw new Error("token must be provided");
}
return `L402 version="0" token="${args.token}", invoice="${args.invoice}"`;
};
/**
* Server: parse "authorization" header sent from client
* @param input value from authorization header
* @returns the macaroon and preimage
*/
function parseL402Authorization(input) {
// Backwards compat: LSAT was the former name of L402
const normalized = input.replace(/^LSAT /, "L402 ");
const prefix = "L402 ";
if (!normalized.startsWith(prefix))
return null;
const credentials = normalized.slice(prefix.length);
const colonIndex = credentials.indexOf(":");
if (colonIndex === -1) {
throw new Error("Invalid authorization header value");
}
return {
token: credentials.slice(0, colonIndex),
preimage: credentials.slice(colonIndex + 1),
};
}
exports.fetchWithL402 = fetchWithL402;
exports.issueL402Macaroon = issueL402Macaroon;
exports.makeL402AuthenticateHeader = makeL402AuthenticateHeader;
exports.parseL402 = parseL402;
exports.parseL402Authorization = parseL402Authorization;
exports.verifyL402Macaroon = verifyL402Macaroon;
//# sourceMappingURL=l402.cjs.map
+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"l402.cjs","sources":["../../../src/402/l402/utils.ts","../../../src/402/l402/l402.ts"],"sourcesContent":["export const parseL402 = (input: string): Record<string, string> => {\n // Remove the L402 and LSAT identifiers\n const string = input.replace(\"L402\", \"\").replace(\"LSAT\", \"\").trim();\n\n // Initialize an object to store the key-value pairs\n const keyValuePairs = {};\n\n // Regular expression to match key and (quoted or unquoted) value\n const regex = /(\\w+)=(\"([^\"]*)\"|'([^']*)'|([^,]*))/g;\n let match;\n\n // Use regex to find all key-value pairs\n while ((match = regex.exec(string)) !== null) {\n // Key is always match[1]\n // Value is either match[3] (double-quoted), match[4] (single-quoted), or match[5] (unquoted)\n keyValuePairs[match[1]] = match[3] || match[4] || match[5];\n }\n\n return keyValuePairs;\n};\n\nexport const makeL402AuthenticateHeader = (args: {\n macaroon?: string;\n token?: string;\n invoice: string;\n}) => {\n if (args.macaroon) {\n return `L402 version=\"0\" macaroon=\"${args.macaroon}\", invoice=\"${args.invoice}\"`;\n } else {\n return `L402 version=\"0\" token=\"${args.token}\", invoice=\"${args.invoice}\"`;\n }\n};\n","import { Wallet } from \"../utils\";\nimport { parseL402 } from \"./utils\";\n\nexport const handleL402Payment = async (\n l402Header: string,\n url: string,\n fetchArgs: RequestInit,\n headers: Headers,\n wallet: Wallet,\n): Promise<Response> => {\n const details = parseL402(l402Header);\n const token = details.token || details.macaroon;\n const invoice = details.invoice;\n\n if (!token) {\n throw new Error(\"L402: missing token/macaroon in WWW-Authenticate header\");\n }\n if (!invoice) {\n throw new Error(\"L402: missing invoice in WWW-Authenticate header\");\n }\n\n const invResp = await wallet.payInvoice({ invoice });\n headers.set(\"Authorization\", `L402 ${token}:${invResp.preimage}`);\n return fetch(url, fetchArgs);\n};\n\nexport const fetchWithL402 = async (\n url: string,\n fetchArgs: RequestInit,\n options: {\n wallet: Wallet;\n },\n) => {\n const wallet = options.wallet;\n if (!wallet) {\n throw new Error(\"wallet is missing\");\n }\n if (!fetchArgs) {\n fetchArgs = {};\n }\n fetchArgs.cache = \"no-store\";\n fetchArgs.mode = \"cors\";\n const headers = new Headers(fetchArgs.headers ?? undefined);\n fetchArgs.headers = headers;\n\n const initResp = await fetch(url, fetchArgs);\n const header = initResp.headers.get(\"www-authenticate\");\n if (!header) {\n return initResp;\n }\n\n return handleL402Payment(header, url, fetchArgs, headers, wallet);\n};\n"],"names":[],"mappings":";;AAAO,MAAM,SAAS,GAAG,CAAC,KAAa,KAA4B;;IAEjE,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;;IAGnE,MAAM,aAAa,GAAG,EAAE;;IAGxB,MAAM,KAAK,GAAG,sCAAsC;AACpD,IAAA,IAAI,KAAK;;AAGT,IAAA,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE;;;QAG5C,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;IAC5D;AAEA,IAAA,OAAO,aAAa;AACtB,CAAC;;AChBM,MAAM,iBAAiB,GAAG,OAC/B,UAAkB,EAClB,GAAW,EACX,SAAsB,EACtB,OAAgB,EAChB,MAAc,KACO;AACrB,IAAA,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,CAAC;IACrC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,QAAQ;AAC/C,IAAA,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO;IAE/B,IAAI,CAAC,KAAK,EAAE;AACV,QAAA,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC;IAC5E;IACA,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC;IACrE;IAEA,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;AACpD,IAAA,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,CAAA,KAAA,EAAQ,KAAK,CAAA,CAAA,EAAI,OAAO,CAAC,QAAQ,CAAA,CAAE,CAAC;AACjE,IAAA,OAAO,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC;AAC9B,CAAC;AAEM,MAAM,aAAa,GAAG,OAC3B,GAAW,EACX,SAAsB,EACtB,OAEC,KACC;AACF,IAAA,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM;IAC7B,IAAI,CAAC,MAAM,EAAE;AACX,QAAA,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC;IACtC;IACA,IAAI,CAAC,SAAS,EAAE;QACd,SAAS,GAAG,EAAE;IAChB;AACA,IAAA,SAAS,CAAC,KAAK,GAAG,UAAU;AAC5B,IAAA,SAAS,CAAC,IAAI,GAAG,MAAM;IACvB,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC;AAC3D,IAAA,SAAS,CAAC,OAAO,GAAG,OAAO;IAE3B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC;IAC5C,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IACvD,IAAI,CAAC,MAAM,EAAE;AACX,QAAA,OAAO,QAAQ;IACjB;AAEA,IAAA,OAAO,iBAAiB,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC;AACnE;;;;"}
{"version":3,"file":"l402.cjs","sources":["../../../src/402/l402/utils.ts","../../../src/402/l402/l402.ts","../../../src/402/l402/server/l402.ts","../../../src/402/l402/server/utils.ts"],"sourcesContent":["interface WwwAuthenticatePayload {\n token: string;\n invoice: string;\n [key: string]: string; // Allows any other string properties\n}\n\n/**\n * Client: parse \"www-authenticate\" header from server response\n * @param input\n * @returns details from the header value (token or macaroon, invoice)\n */\nexport const parseL402 = (input: string): WwwAuthenticatePayload => {\n // Remove the L402 and LSAT identifiers\n const string = input.replace(\"L402\", \"\").replace(\"LSAT\", \"\").trim();\n\n // Initialize an object to store the key-value pairs\n const keyValuePairs: Record<string, string> = {};\n\n // Regular expression to match key and (quoted or unquoted) value\n const regex = /(\\w+)=(\"([^\"]*)\"|'([^']*)'|([^,]*))/g;\n let match;\n\n // Use regex to find all key-value pairs\n while ((match = regex.exec(string)) !== null) {\n // Key is always match[1]\n // Value is either match[3] (double-quoted), match[4] (single-quoted), or match[5] (unquoted)\n keyValuePairs[match[1]] = match[3] || match[4] || match[5];\n }\n\n if (!keyValuePairs[\"token\"] && keyValuePairs[\"macaroon\"]) {\n // fallback to old naming\n keyValuePairs[\"token\"] = keyValuePairs[\"macaroon\"];\n delete keyValuePairs[\"macaroon\"];\n }\n\n if (\n !(\"token\" in keyValuePairs) ||\n typeof keyValuePairs[\"token\"] !== \"string\"\n ) {\n throw new Error(\"No macaroon or token found in www-authenticate header\");\n }\n if (\n !(\"invoice\" in keyValuePairs) ||\n typeof keyValuePairs[\"invoice\"] !== \"string\"\n ) {\n throw new Error(\"No invoice found in www-authenticate header\");\n }\n\n return keyValuePairs as WwwAuthenticatePayload;\n};\n","import { Wallet } from \"../utils\";\nimport { parseL402 } from \"./utils\";\n\nexport const handleL402Payment = async (\n l402Header: string,\n url: string,\n fetchArgs: RequestInit,\n headers: Headers,\n wallet: Wallet,\n): Promise<Response> => {\n const details = parseL402(l402Header);\n const token = details.token || details.macaroon;\n const invoice = details.invoice;\n\n if (!token) {\n throw new Error(\"L402: missing token/macaroon in WWW-Authenticate header\");\n }\n if (!invoice) {\n throw new Error(\"L402: missing invoice in WWW-Authenticate header\");\n }\n\n const invResp = await wallet.payInvoice({ invoice });\n headers.set(\"Authorization\", `L402 ${token}:${invResp.preimage}`);\n return fetch(url, fetchArgs);\n};\n\nexport const fetchWithL402 = async (\n url: string,\n fetchArgs: RequestInit,\n options: {\n wallet: Wallet;\n },\n) => {\n const wallet = options.wallet;\n if (!wallet) {\n throw new Error(\"wallet is missing\");\n }\n if (!fetchArgs) {\n fetchArgs = {};\n }\n fetchArgs.cache = \"no-store\";\n fetchArgs.mode = \"cors\";\n const headers = new Headers(fetchArgs.headers ?? undefined);\n fetchArgs.headers = headers;\n\n const initResp = await fetch(url, fetchArgs);\n const header = initResp.headers.get(\"www-authenticate\");\n if (!header) {\n return initResp;\n }\n\n return handleL402Payment(header, url, fetchArgs, headers, wallet);\n};\n","export type MacaroonPayload<T> = T & {\n paymentHash: string; // hex — SHA256 of the preimage\n};\n\nexport async function issueL402Macaroon<T extends Record<string, unknown>>(\n secret: string,\n paymentHash: string,\n params?: T,\n): Promise<string> {\n if (\n params !== undefined &&\n Object.prototype.hasOwnProperty.call(params, \"paymentHash\")\n ) {\n throw new Error(\"paymentHash is reserved\");\n }\n const payload = { ...params, paymentHash } as MacaroonPayload<T>;\n const encoded = Buffer.from(JSON.stringify(payload)).toString(\"base64url\");\n const mac = await sign(secret, encoded);\n return `${encoded}.${mac}`;\n}\n\nexport async function verifyL402Macaroon<T = unknown>(\n secret: string,\n token: string,\n): Promise<MacaroonPayload<T>> {\n const { timingSafeEqual } = await import(\"crypto\");\n const dotIndex = token.lastIndexOf(\".\");\n if (dotIndex === -1) throw new Error(\"Invalid macaroon token\");\n\n const encoded = token.slice(0, dotIndex);\n const mac = token.slice(dotIndex + 1);\n\n // Constant-time comparison to prevent timing attacks\n const expectedMac = await sign(secret, encoded);\n try {\n if (\n !timingSafeEqual(Buffer.from(mac, \"hex\"), Buffer.from(expectedMac, \"hex\"))\n ) {\n throw new Error(\"Invalid macaroon token\");\n }\n } catch (e) {\n throw new Error(\"Invalid macaroon token\");\n }\n\n try {\n const parsed: unknown = JSON.parse(\n Buffer.from(encoded, \"base64url\").toString(\"utf8\"),\n );\n if (\n parsed === null ||\n typeof parsed !== \"object\" ||\n Array.isArray(parsed) ||\n typeof (parsed as Record<string, unknown>).paymentHash !== \"string\"\n ) {\n throw new Error(\"Invalid macaroon payload\");\n }\n return parsed as MacaroonPayload<T>;\n } catch {\n throw new Error(\"Invalid macaroon token\");\n }\n}\n\nasync function sign(secret: string, payload: string): Promise<string> {\n const { createHmac } = await import(\"crypto\");\n return createHmac(\"sha256\", secret).update(payload).digest(\"hex\");\n}\n","/**\n * Server: create a WWW-Authenticate header for a given macaroon and invoice\n * @param args the macaroon/token and invoice generated for the client's request\n * @returns the header value\n */\nexport const makeL402AuthenticateHeader = (args: {\n token?: string;\n invoice: string;\n}) => {\n if (!args.token) {\n throw new Error(\"token must be provided\");\n }\n\n return `L402 version=\"0\" token=\"${args.token}\", invoice=\"${args.invoice}\"`;\n};\n\n/**\n * Server: parse \"authorization\" header sent from client\n * @param input value from authorization header\n * @returns the macaroon and preimage\n */\nexport function parseL402Authorization(\n input: string,\n): { token: string; preimage: string } | null {\n // Backwards compat: LSAT was the former name of L402\n const normalized = input.replace(/^LSAT /, \"L402 \");\n const prefix = \"L402 \";\n if (!normalized.startsWith(prefix)) return null;\n const credentials = normalized.slice(prefix.length);\n const colonIndex = credentials.indexOf(\":\");\n if (colonIndex === -1) {\n throw new Error(\"Invalid authorization header value\");\n }\n return {\n token: credentials.slice(0, colonIndex),\n preimage: credentials.slice(colonIndex + 1),\n };\n}\n"],"names":[],"mappings":"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"}

@@ -15,2 +15,309 @@ 'use strict';

function bytes(b, ...lengths) {
if (!(b instanceof Uint8Array))
throw new Error('Expected Uint8Array');
if (lengths.length > 0 && !lengths.includes(b.length))
throw new Error(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`);
}
function exists(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 output(out, instance) {
bytes(out);
const min = instance.outputLen;
if (out.length < min) {
throw new Error(`digestInto() expects output buffer of length at least ${min}`);
}
}
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
// node.js versions earlier than v19 don't declare it in global scope.
// For node.js, package.json#exports field mapping rewrites import
// from `crypto` to `cryptoNode`, which imports native module.
// Makes the utils un-importable in browsers without a bundler.
// Once node.js 18 is deprecated, we can just drop the import.
const u8a = (a) => a instanceof Uint8Array;
// Cast array to view
const createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
// The rotate right (circular right shift) operation for uint32
const rotr = (word, shift) => (word << (32 - shift)) | (word >>> shift);
// big-endian hardware is rare. Just in case someone still decides to run hashes:
// early-throw an error because we don't support BE yet.
const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
if (!isLE)
throw new Error('Non little-endian hardware is not supported');
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
/**
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
*/
function bytesToHex(bytes) {
if (!u8a(bytes))
throw new Error('Uint8Array expected');
// pre-caching improves the speed 6x
let hex = '';
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
}
return hex;
}
/**
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
*/
function utf8ToBytes(str) {
if (typeof str !== 'string')
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
}
/**
* Normalizes (non-hex) string or Uint8Array to Uint8Array.
* Warning: when Uint8Array is passed, it would NOT get copied.
* Keep in mind for future mutable operations.
*/
function toBytes(data) {
if (typeof data === 'string')
data = utf8ToBytes(data);
if (!u8a(data))
throw new Error(`expected Uint8Array, got ${typeof data}`);
return data;
}
// For runtime check if class implements interface
class Hash {
// Safe version that clones internal state
clone() {
return this._cloneInto();
}
}
function wrapConstructor(hashCons) {
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
const tmp = hashCons();
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = () => hashCons();
return hashC;
}
// Polyfill for Safari 14
function setBigUint64(view, byteOffset, value, isLE) {
if (typeof view.setBigUint64 === 'function')
return view.setBigUint64(byteOffset, value, isLE);
const _32n = BigInt(32);
const _u32_max = BigInt(0xffffffff);
const wh = Number((value >> _32n) & _u32_max);
const wl = Number(value & _u32_max);
const h = isLE ? 4 : 0;
const l = isLE ? 0 : 4;
view.setUint32(byteOffset + h, wh, isLE);
view.setUint32(byteOffset + l, wl, isLE);
}
// Base SHA2 class (RFC 6234)
class SHA2 extends Hash {
constructor(blockLen, outputLen, padOffset, isLE) {
super();
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE;
this.finished = false;
this.length = 0;
this.pos = 0;
this.destroyed = false;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
exists(this);
const { view, buffer, blockLen } = this;
data = toBytes(data);
const len = data.length;
for (let pos = 0; pos < len;) {
const take = Math.min(blockLen - this.pos, len - pos);
// Fast path: we have at least one block in input, cast it to view and process
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) {
exists(this);
output(out, this);
this.finished = true;
// Padding
// We can avoid allocation of buffer for padding completely if it
// was previously not allocated here. But it won't change performance.
const { buffer, view, blockLen, isLE } = this;
let { pos } = this;
// append the bit '1' to the message
buffer[pos++] = 0b10000000;
this.buffer.subarray(pos).fill(0);
// we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
pos = 0;
}
// Pad until full block byte with zeros
for (let i = pos; i < blockLen; i++)
buffer[i] = 0;
// Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
// You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
// So we just write lowest 64 bits of that value.
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
// NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
if (len % 4)
throw new Error('_sha2: outputLen should 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 i = 0; i < outLen; i++)
oview.setUint32(4 * i, state[i], isLE);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
to || (to = new this.constructor());
to.set(...this.get());
const { blockLen, buffer, length, finished, destroyed, pos } = this;
to.length = length;
to.pos = pos;
to.finished = finished;
to.destroyed = destroyed;
if (length % blockLen)
to.buffer.set(buffer);
return to;
}
}
// SHA2-256 need to try 2^128 hashes to execute birthday attack.
// BTC network is doing 2^67 hashes/sec as per early 2023.
// Choice: a ? b : c
const Chi = (a, b, c) => (a & b) ^ (~a & c);
// Majority function, true if any two inpust is true
const Maj = (a, b, c) => (a & b) ^ (a & c) ^ (b & c);
// Round constants:
// first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
// prettier-ignore
const SHA256_K = /* @__PURE__ */ new Uint32Array([
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
]);
// Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
// prettier-ignore
const IV = /* @__PURE__ */ new Uint32Array([
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
]);
// Temporary buffer, not used to store anything between runs
// Named this way because it matches specification.
const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
class SHA256 extends SHA2 {
constructor() {
super(64, 32, 8, false);
// We cannot use array here since array allows indexing by variable
// which means optimizer/compiler cannot use registers.
this.A = IV[0] | 0;
this.B = IV[1] | 0;
this.C = IV[2] | 0;
this.D = IV[3] | 0;
this.E = IV[4] | 0;
this.F = IV[5] | 0;
this.G = IV[6] | 0;
this.H = IV[7] | 0;
}
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) {
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
for (let i = 0; i < 16; i++, offset += 4)
SHA256_W[i] = view.getUint32(offset, false);
for (let i = 16; i < 64; i++) {
const W15 = SHA256_W[i - 15];
const W2 = SHA256_W[i - 2];
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
}
// Compression function main loop, 64 rounds
let { A, B, C, D, E, F, G, H } = this;
for (let i = 0; i < 64; i++) {
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 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;
}
// Add the compressed chunk to the current hash value
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() {
SHA256_W.fill(0);
}
destroy() {
this.set(0, 0, 0, 0, 0, 0, 0, 0);
this.buffer.fill(0);
}
}
/**
* SHA2-256 hash function
* @param message - data that would be hashed
*/
const sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256());
var lib = {};

@@ -885,310 +1192,16 @@

};
function bytes(b, ...lengths) {
if (!(b instanceof Uint8Array))
throw new Error('Expected Uint8Array');
if (lengths.length > 0 && !lengths.includes(b.length))
throw new Error(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`);
}
function exists(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 output(out, instance) {
bytes(out);
const min = instance.outputLen;
if (out.length < min) {
throw new Error(`digestInto() expects output buffer of length at least ${min}`);
function validatePreimage(preimage, paymentHash) {
try {
if (!/^[0-9a-fA-F]{64}$/.test(preimage))
return false;
if (!/^[0-9a-fA-F]{64}$/.test(paymentHash))
return false;
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return paymentHash === preimageHash;
}
}
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
// node.js versions earlier than v19 don't declare it in global scope.
// For node.js, package.json#exports field mapping rewrites import
// from `crypto` to `cryptoNode`, which imports native module.
// Makes the utils un-importable in browsers without a bundler.
// Once node.js 18 is deprecated, we can just drop the import.
const u8a = (a) => a instanceof Uint8Array;
// Cast array to view
const createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
// The rotate right (circular right shift) operation for uint32
const rotr = (word, shift) => (word << (32 - shift)) | (word >>> shift);
// big-endian hardware is rare. Just in case someone still decides to run hashes:
// early-throw an error because we don't support BE yet.
const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
if (!isLE)
throw new Error('Non little-endian hardware is not supported');
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
/**
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
*/
function bytesToHex(bytes) {
if (!u8a(bytes))
throw new Error('Uint8Array expected');
// pre-caching improves the speed 6x
let hex = '';
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
catch {
return false;
}
return hex;
}
/**
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
*/
function utf8ToBytes(str) {
if (typeof str !== 'string')
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
}
/**
* Normalizes (non-hex) string or Uint8Array to Uint8Array.
* Warning: when Uint8Array is passed, it would NOT get copied.
* Keep in mind for future mutable operations.
*/
function toBytes(data) {
if (typeof data === 'string')
data = utf8ToBytes(data);
if (!u8a(data))
throw new Error(`expected Uint8Array, got ${typeof data}`);
return data;
}
// For runtime check if class implements interface
class Hash {
// Safe version that clones internal state
clone() {
return this._cloneInto();
}
}
function wrapConstructor(hashCons) {
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
const tmp = hashCons();
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = () => hashCons();
return hashC;
}
// Polyfill for Safari 14
function setBigUint64(view, byteOffset, value, isLE) {
if (typeof view.setBigUint64 === 'function')
return view.setBigUint64(byteOffset, value, isLE);
const _32n = BigInt(32);
const _u32_max = BigInt(0xffffffff);
const wh = Number((value >> _32n) & _u32_max);
const wl = Number(value & _u32_max);
const h = isLE ? 4 : 0;
const l = isLE ? 0 : 4;
view.setUint32(byteOffset + h, wh, isLE);
view.setUint32(byteOffset + l, wl, isLE);
}
// Base SHA2 class (RFC 6234)
class SHA2 extends Hash {
constructor(blockLen, outputLen, padOffset, isLE) {
super();
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE;
this.finished = false;
this.length = 0;
this.pos = 0;
this.destroyed = false;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
exists(this);
const { view, buffer, blockLen } = this;
data = toBytes(data);
const len = data.length;
for (let pos = 0; pos < len;) {
const take = Math.min(blockLen - this.pos, len - pos);
// Fast path: we have at least one block in input, cast it to view and process
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) {
exists(this);
output(out, this);
this.finished = true;
// Padding
// We can avoid allocation of buffer for padding completely if it
// was previously not allocated here. But it won't change performance.
const { buffer, view, blockLen, isLE } = this;
let { pos } = this;
// append the bit '1' to the message
buffer[pos++] = 0b10000000;
this.buffer.subarray(pos).fill(0);
// we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
pos = 0;
}
// Pad until full block byte with zeros
for (let i = pos; i < blockLen; i++)
buffer[i] = 0;
// Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
// You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
// So we just write lowest 64 bits of that value.
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
// NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
if (len % 4)
throw new Error('_sha2: outputLen should 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 i = 0; i < outLen; i++)
oview.setUint32(4 * i, state[i], isLE);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
to || (to = new this.constructor());
to.set(...this.get());
const { blockLen, buffer, length, finished, destroyed, pos } = this;
to.length = length;
to.pos = pos;
to.finished = finished;
to.destroyed = destroyed;
if (length % blockLen)
to.buffer.set(buffer);
return to;
}
}
// SHA2-256 need to try 2^128 hashes to execute birthday attack.
// BTC network is doing 2^67 hashes/sec as per early 2023.
// Choice: a ? b : c
const Chi = (a, b, c) => (a & b) ^ (~a & c);
// Majority function, true if any two inpust is true
const Maj = (a, b, c) => (a & b) ^ (a & c) ^ (b & c);
// Round constants:
// first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
// prettier-ignore
const SHA256_K = /* @__PURE__ */ new Uint32Array([
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
]);
// Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
// prettier-ignore
const IV = /* @__PURE__ */ new Uint32Array([
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
]);
// Temporary buffer, not used to store anything between runs
// Named this way because it matches specification.
const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
class SHA256 extends SHA2 {
constructor() {
super(64, 32, 8, false);
// We cannot use array here since array allows indexing by variable
// which means optimizer/compiler cannot use registers.
this.A = IV[0] | 0;
this.B = IV[1] | 0;
this.C = IV[2] | 0;
this.D = IV[3] | 0;
this.E = IV[4] | 0;
this.F = IV[5] | 0;
this.G = IV[6] | 0;
this.H = IV[7] | 0;
}
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) {
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
for (let i = 0; i < 16; i++, offset += 4)
SHA256_W[i] = view.getUint32(offset, false);
for (let i = 16; i < 64; i++) {
const W15 = SHA256_W[i - 15];
const W2 = SHA256_W[i - 2];
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
}
// Compression function main loop, 64 rounds
let { A, B, C, D, E, F, G, H } = this;
for (let i = 0; i < 64; i++) {
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 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;
}
// Add the compressed chunk to the current hash value
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() {
SHA256_W.fill(0);
}
destroy() {
this.set(0, 0, 0, 0, 0, 0, 0, 0);
this.buffer.fill(0);
}
}
/**
* SHA2-256 hash function
* @param message - data that would be hashed
*/
const sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256());
class Invoice {

@@ -1232,9 +1245,3 @@ constructor(args) {

return false;
try {
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return this.paymentHash === preimageHash;
}
catch {
return false;
}
return validatePreimage(preimage, this.paymentHash);
}

@@ -1241,0 +1248,0 @@ async verifyPayment() {

'use strict';
function bytes(b, ...lengths) {
if (!(b instanceof Uint8Array))
throw new Error('Expected Uint8Array');
if (lengths.length > 0 && !lengths.includes(b.length))
throw new Error(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`);
}
function exists(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 output(out, instance) {
bytes(out);
const min = instance.outputLen;
if (out.length < min) {
throw new Error(`digestInto() expects output buffer of length at least ${min}`);
}
}
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
// node.js versions earlier than v19 don't declare it in global scope.
// For node.js, package.json#exports field mapping rewrites import
// from `crypto` to `cryptoNode`, which imports native module.
// Makes the utils un-importable in browsers without a bundler.
// Once node.js 18 is deprecated, we can just drop the import.
const u8a = (a) => a instanceof Uint8Array;
// Cast array to view
const createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
// The rotate right (circular right shift) operation for uint32
const rotr = (word, shift) => (word << (32 - shift)) | (word >>> shift);
// big-endian hardware is rare. Just in case someone still decides to run hashes:
// early-throw an error because we don't support BE yet.
const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
if (!isLE)
throw new Error('Non little-endian hardware is not supported');
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
/**
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
*/
function bytesToHex(bytes) {
if (!u8a(bytes))
throw new Error('Uint8Array expected');
// pre-caching improves the speed 6x
let hex = '';
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
}
return hex;
}
/**
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
*/
function utf8ToBytes(str) {
if (typeof str !== 'string')
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
}
/**
* Normalizes (non-hex) string or Uint8Array to Uint8Array.
* Warning: when Uint8Array is passed, it would NOT get copied.
* Keep in mind for future mutable operations.
*/
function toBytes(data) {
if (typeof data === 'string')
data = utf8ToBytes(data);
if (!u8a(data))
throw new Error(`expected Uint8Array, got ${typeof data}`);
return data;
}
// For runtime check if class implements interface
class Hash {
// Safe version that clones internal state
clone() {
return this._cloneInto();
}
}
function wrapConstructor(hashCons) {
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
const tmp = hashCons();
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = () => hashCons();
return hashC;
}
// Polyfill for Safari 14
function setBigUint64(view, byteOffset, value, isLE) {
if (typeof view.setBigUint64 === 'function')
return view.setBigUint64(byteOffset, value, isLE);
const _32n = BigInt(32);
const _u32_max = BigInt(0xffffffff);
const wh = Number((value >> _32n) & _u32_max);
const wl = Number(value & _u32_max);
const h = isLE ? 4 : 0;
const l = isLE ? 0 : 4;
view.setUint32(byteOffset + h, wh, isLE);
view.setUint32(byteOffset + l, wl, isLE);
}
// Base SHA2 class (RFC 6234)
class SHA2 extends Hash {
constructor(blockLen, outputLen, padOffset, isLE) {
super();
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE;
this.finished = false;
this.length = 0;
this.pos = 0;
this.destroyed = false;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
exists(this);
const { view, buffer, blockLen } = this;
data = toBytes(data);
const len = data.length;
for (let pos = 0; pos < len;) {
const take = Math.min(blockLen - this.pos, len - pos);
// Fast path: we have at least one block in input, cast it to view and process
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) {
exists(this);
output(out, this);
this.finished = true;
// Padding
// We can avoid allocation of buffer for padding completely if it
// was previously not allocated here. But it won't change performance.
const { buffer, view, blockLen, isLE } = this;
let { pos } = this;
// append the bit '1' to the message
buffer[pos++] = 0b10000000;
this.buffer.subarray(pos).fill(0);
// we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
pos = 0;
}
// Pad until full block byte with zeros
for (let i = pos; i < blockLen; i++)
buffer[i] = 0;
// Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
// You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
// So we just write lowest 64 bits of that value.
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
// NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
if (len % 4)
throw new Error('_sha2: outputLen should 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 i = 0; i < outLen; i++)
oview.setUint32(4 * i, state[i], isLE);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
to || (to = new this.constructor());
to.set(...this.get());
const { blockLen, buffer, length, finished, destroyed, pos } = this;
to.length = length;
to.pos = pos;
to.finished = finished;
to.destroyed = destroyed;
if (length % blockLen)
to.buffer.set(buffer);
return to;
}
}
// SHA2-256 need to try 2^128 hashes to execute birthday attack.
// BTC network is doing 2^67 hashes/sec as per early 2023.
// Choice: a ? b : c
const Chi = (a, b, c) => (a & b) ^ (~a & c);
// Majority function, true if any two inpust is true
const Maj = (a, b, c) => (a & b) ^ (a & c) ^ (b & c);
// Round constants:
// first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
// prettier-ignore
const SHA256_K = /* @__PURE__ */ new Uint32Array([
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
]);
// Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
// prettier-ignore
const IV = /* @__PURE__ */ new Uint32Array([
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
]);
// Temporary buffer, not used to store anything between runs
// Named this way because it matches specification.
const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
class SHA256 extends SHA2 {
constructor() {
super(64, 32, 8, false);
// We cannot use array here since array allows indexing by variable
// which means optimizer/compiler cannot use registers.
this.A = IV[0] | 0;
this.B = IV[1] | 0;
this.C = IV[2] | 0;
this.D = IV[3] | 0;
this.E = IV[4] | 0;
this.F = IV[5] | 0;
this.G = IV[6] | 0;
this.H = IV[7] | 0;
}
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) {
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
for (let i = 0; i < 16; i++, offset += 4)
SHA256_W[i] = view.getUint32(offset, false);
for (let i = 16; i < 64; i++) {
const W15 = SHA256_W[i - 15];
const W2 = SHA256_W[i - 2];
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
}
// Compression function main loop, 64 rounds
let { A, B, C, D, E, F, G, H } = this;
for (let i = 0; i < 64; i++) {
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 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;
}
// Add the compressed chunk to the current hash value
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() {
SHA256_W.fill(0);
}
destroy() {
this.set(0, 0, 0, 0, 0, 0, 0, 0);
this.buffer.fill(0);
}
}
/**
* SHA2-256 hash function
* @param message - data that would be hashed
*/
const sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256());
var lib = {};

@@ -872,310 +1179,16 @@

};
function bytes(b, ...lengths) {
if (!(b instanceof Uint8Array))
throw new Error('Expected Uint8Array');
if (lengths.length > 0 && !lengths.includes(b.length))
throw new Error(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`);
}
function exists(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 output(out, instance) {
bytes(out);
const min = instance.outputLen;
if (out.length < min) {
throw new Error(`digestInto() expects output buffer of length at least ${min}`);
function validatePreimage(preimage, paymentHash) {
try {
if (!/^[0-9a-fA-F]{64}$/.test(preimage))
return false;
if (!/^[0-9a-fA-F]{64}$/.test(paymentHash))
return false;
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return paymentHash === preimageHash;
}
}
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
// node.js versions earlier than v19 don't declare it in global scope.
// For node.js, package.json#exports field mapping rewrites import
// from `crypto` to `cryptoNode`, which imports native module.
// Makes the utils un-importable in browsers without a bundler.
// Once node.js 18 is deprecated, we can just drop the import.
const u8a = (a) => a instanceof Uint8Array;
// Cast array to view
const createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
// The rotate right (circular right shift) operation for uint32
const rotr = (word, shift) => (word << (32 - shift)) | (word >>> shift);
// big-endian hardware is rare. Just in case someone still decides to run hashes:
// early-throw an error because we don't support BE yet.
const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
if (!isLE)
throw new Error('Non little-endian hardware is not supported');
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
/**
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
*/
function bytesToHex(bytes) {
if (!u8a(bytes))
throw new Error('Uint8Array expected');
// pre-caching improves the speed 6x
let hex = '';
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
catch {
return false;
}
return hex;
}
/**
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
*/
function utf8ToBytes(str) {
if (typeof str !== 'string')
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
}
/**
* Normalizes (non-hex) string or Uint8Array to Uint8Array.
* Warning: when Uint8Array is passed, it would NOT get copied.
* Keep in mind for future mutable operations.
*/
function toBytes(data) {
if (typeof data === 'string')
data = utf8ToBytes(data);
if (!u8a(data))
throw new Error(`expected Uint8Array, got ${typeof data}`);
return data;
}
// For runtime check if class implements interface
class Hash {
// Safe version that clones internal state
clone() {
return this._cloneInto();
}
}
function wrapConstructor(hashCons) {
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
const tmp = hashCons();
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = () => hashCons();
return hashC;
}
// Polyfill for Safari 14
function setBigUint64(view, byteOffset, value, isLE) {
if (typeof view.setBigUint64 === 'function')
return view.setBigUint64(byteOffset, value, isLE);
const _32n = BigInt(32);
const _u32_max = BigInt(0xffffffff);
const wh = Number((value >> _32n) & _u32_max);
const wl = Number(value & _u32_max);
const h = isLE ? 4 : 0;
const l = isLE ? 0 : 4;
view.setUint32(byteOffset + h, wh, isLE);
view.setUint32(byteOffset + l, wl, isLE);
}
// Base SHA2 class (RFC 6234)
class SHA2 extends Hash {
constructor(blockLen, outputLen, padOffset, isLE) {
super();
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE;
this.finished = false;
this.length = 0;
this.pos = 0;
this.destroyed = false;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
exists(this);
const { view, buffer, blockLen } = this;
data = toBytes(data);
const len = data.length;
for (let pos = 0; pos < len;) {
const take = Math.min(blockLen - this.pos, len - pos);
// Fast path: we have at least one block in input, cast it to view and process
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) {
exists(this);
output(out, this);
this.finished = true;
// Padding
// We can avoid allocation of buffer for padding completely if it
// was previously not allocated here. But it won't change performance.
const { buffer, view, blockLen, isLE } = this;
let { pos } = this;
// append the bit '1' to the message
buffer[pos++] = 0b10000000;
this.buffer.subarray(pos).fill(0);
// we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
pos = 0;
}
// Pad until full block byte with zeros
for (let i = pos; i < blockLen; i++)
buffer[i] = 0;
// Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
// You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
// So we just write lowest 64 bits of that value.
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
// NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
if (len % 4)
throw new Error('_sha2: outputLen should 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 i = 0; i < outLen; i++)
oview.setUint32(4 * i, state[i], isLE);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
to || (to = new this.constructor());
to.set(...this.get());
const { blockLen, buffer, length, finished, destroyed, pos } = this;
to.length = length;
to.pos = pos;
to.finished = finished;
to.destroyed = destroyed;
if (length % blockLen)
to.buffer.set(buffer);
return to;
}
}
// SHA2-256 need to try 2^128 hashes to execute birthday attack.
// BTC network is doing 2^67 hashes/sec as per early 2023.
// Choice: a ? b : c
const Chi = (a, b, c) => (a & b) ^ (~a & c);
// Majority function, true if any two inpust is true
const Maj = (a, b, c) => (a & b) ^ (a & c) ^ (b & c);
// Round constants:
// first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
// prettier-ignore
const SHA256_K = /* @__PURE__ */ new Uint32Array([
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
]);
// Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
// prettier-ignore
const IV = /* @__PURE__ */ new Uint32Array([
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
]);
// Temporary buffer, not used to store anything between runs
// Named this way because it matches specification.
const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
class SHA256 extends SHA2 {
constructor() {
super(64, 32, 8, false);
// We cannot use array here since array allows indexing by variable
// which means optimizer/compiler cannot use registers.
this.A = IV[0] | 0;
this.B = IV[1] | 0;
this.C = IV[2] | 0;
this.D = IV[3] | 0;
this.E = IV[4] | 0;
this.F = IV[5] | 0;
this.G = IV[6] | 0;
this.H = IV[7] | 0;
}
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) {
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
for (let i = 0; i < 16; i++, offset += 4)
SHA256_W[i] = view.getUint32(offset, false);
for (let i = 16; i < 64; i++) {
const W15 = SHA256_W[i - 15];
const W2 = SHA256_W[i - 2];
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
}
// Compression function main loop, 64 rounds
let { A, B, C, D, E, F, G, H } = this;
for (let i = 0; i < 64; i++) {
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 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;
}
// Add the compressed chunk to the current hash value
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() {
SHA256_W.fill(0);
}
destroy() {
this.set(0, 0, 0, 0, 0, 0, 0, 0);
this.buffer.fill(0);
}
}
/**
* SHA2-256 hash function
* @param message - data that would be hashed
*/
const sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256());
class Invoice {

@@ -1219,9 +1232,3 @@ constructor(args) {

return false;
try {
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return this.paymentHash === preimageHash;
}
catch {
return false;
}
return validatePreimage(preimage, this.paymentHash);
}

@@ -1260,2 +1267,3 @@ async verifyPayment() {

exports.fromHexString = fromHexString;
exports.validatePreimage = validatePreimage;
//# sourceMappingURL=bolt11.cjs.map

@@ -1350,2 +1350,15 @@ 'use strict';

};
function validatePreimage(preimage, paymentHash) {
try {
if (!/^[0-9a-fA-F]{64}$/.test(preimage))
return false;
if (!/^[0-9a-fA-F]{64}$/.test(paymentHash))
return false;
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return paymentHash === preimageHash;
}
catch {
return false;
}
}

@@ -1390,9 +1403,3 @@ class Invoice {

return false;
try {
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return this.paymentHash === preimageHash;
}
catch {
return false;
}
return validatePreimage(preimage, this.paymentHash);
}

@@ -1399,0 +1406,0 @@ async verifyPayment() {

@@ -1177,2 +1177,15 @@ function bytes(b, ...lengths) {

};
function validatePreimage(preimage, paymentHash) {
try {
if (!/^[0-9a-fA-F]{64}$/.test(preimage))
return false;
if (!/^[0-9a-fA-F]{64}$/.test(paymentHash))
return false;
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return paymentHash === preimageHash;
}
catch {
return false;
}
}

@@ -1217,9 +1230,3 @@ class Invoice {

return false;
try {
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return this.paymentHash === preimageHash;
}
catch {
return false;
}
return validatePreimage(preimage, this.paymentHash);
}

@@ -1267,2 +1274,7 @@ async verifyPayment() {

/**
* Client: parse "www-authenticate" header from server response
* @param input
* @returns details from the header value (token or macaroon, invoice)
*/
const parseL402 = (input) => {

@@ -1282,2 +1294,15 @@ // Remove the L402 and LSAT identifiers

}
if (!keyValuePairs["token"] && keyValuePairs["macaroon"]) {
// fallback to old naming
keyValuePairs["token"] = keyValuePairs["macaroon"];
delete keyValuePairs["macaroon"];
}
if (!("token" in keyValuePairs) ||
typeof keyValuePairs["token"] !== "string") {
throw new Error("No macaroon or token found in www-authenticate header");
}
if (!("invoice" in keyValuePairs) ||
typeof keyValuePairs["invoice"] !== "string") {
throw new Error("No invoice found in www-authenticate header");
}
return keyValuePairs;

@@ -1582,3 +1607,82 @@ };

export { createGuardedWallet, fetch402, fetchWithL402, fetchWithMpp, fetchWithX402 };
async function issueL402Macaroon(secret, paymentHash, params) {
if (params !== undefined &&
Object.prototype.hasOwnProperty.call(params, "paymentHash")) {
throw new Error("paymentHash is reserved");
}
const payload = { ...params, paymentHash };
const encoded = Buffer.from(JSON.stringify(payload)).toString("base64url");
const mac = await sign(secret, encoded);
return `${encoded}.${mac}`;
}
async function verifyL402Macaroon(secret, token) {
const { timingSafeEqual } = await import('crypto');
const dotIndex = token.lastIndexOf(".");
if (dotIndex === -1)
throw new Error("Invalid macaroon token");
const encoded = token.slice(0, dotIndex);
const mac = token.slice(dotIndex + 1);
// Constant-time comparison to prevent timing attacks
const expectedMac = await sign(secret, encoded);
try {
if (!timingSafeEqual(Buffer.from(mac, "hex"), Buffer.from(expectedMac, "hex"))) {
throw new Error("Invalid macaroon token");
}
}
catch (e) {
throw new Error("Invalid macaroon token");
}
try {
const parsed = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
if (parsed === null ||
typeof parsed !== "object" ||
Array.isArray(parsed) ||
typeof parsed.paymentHash !== "string") {
throw new Error("Invalid macaroon payload");
}
return parsed;
}
catch {
throw new Error("Invalid macaroon token");
}
}
async function sign(secret, payload) {
const { createHmac } = await import('crypto');
return createHmac("sha256", secret).update(payload).digest("hex");
}
/**
* Server: create a WWW-Authenticate header for a given macaroon and invoice
* @param args the macaroon/token and invoice generated for the client's request
* @returns the header value
*/
const makeL402AuthenticateHeader = (args) => {
if (!args.token) {
throw new Error("token must be provided");
}
return `L402 version="0" token="${args.token}", invoice="${args.invoice}"`;
};
/**
* Server: parse "authorization" header sent from client
* @param input value from authorization header
* @returns the macaroon and preimage
*/
function parseL402Authorization(input) {
// Backwards compat: LSAT was the former name of L402
const normalized = input.replace(/^LSAT /, "L402 ");
const prefix = "L402 ";
if (!normalized.startsWith(prefix))
return null;
const credentials = normalized.slice(prefix.length);
const colonIndex = credentials.indexOf(":");
if (colonIndex === -1) {
throw new Error("Invalid authorization header value");
}
return {
token: credentials.slice(0, colonIndex),
preimage: credentials.slice(colonIndex + 1),
};
}
export { createGuardedWallet, fetch402, fetchWithL402, fetchWithMpp, fetchWithX402, issueL402Macaroon, makeL402AuthenticateHeader, parseL402, parseL402Authorization, verifyL402Macaroon };
//# sourceMappingURL=402.js.map

@@ -0,1 +1,6 @@

/**
* Client: parse "www-authenticate" header from server response
* @param input
* @returns details from the header value (token or macaroon, invoice)
*/
const parseL402 = (input) => {

@@ -15,2 +20,15 @@ // Remove the L402 and LSAT identifiers

}
if (!keyValuePairs["token"] && keyValuePairs["macaroon"]) {
// fallback to old naming
keyValuePairs["token"] = keyValuePairs["macaroon"];
delete keyValuePairs["macaroon"];
}
if (!("token" in keyValuePairs) ||
typeof keyValuePairs["token"] !== "string") {
throw new Error("No macaroon or token found in www-authenticate header");
}
if (!("invoice" in keyValuePairs) ||
typeof keyValuePairs["invoice"] !== "string") {
throw new Error("No invoice found in www-authenticate header");
}
return keyValuePairs;

@@ -53,3 +71,82 @@ };

export { fetchWithL402 };
async function issueL402Macaroon(secret, paymentHash, params) {
if (params !== undefined &&
Object.prototype.hasOwnProperty.call(params, "paymentHash")) {
throw new Error("paymentHash is reserved");
}
const payload = { ...params, paymentHash };
const encoded = Buffer.from(JSON.stringify(payload)).toString("base64url");
const mac = await sign(secret, encoded);
return `${encoded}.${mac}`;
}
async function verifyL402Macaroon(secret, token) {
const { timingSafeEqual } = await import('crypto');
const dotIndex = token.lastIndexOf(".");
if (dotIndex === -1)
throw new Error("Invalid macaroon token");
const encoded = token.slice(0, dotIndex);
const mac = token.slice(dotIndex + 1);
// Constant-time comparison to prevent timing attacks
const expectedMac = await sign(secret, encoded);
try {
if (!timingSafeEqual(Buffer.from(mac, "hex"), Buffer.from(expectedMac, "hex"))) {
throw new Error("Invalid macaroon token");
}
}
catch (e) {
throw new Error("Invalid macaroon token");
}
try {
const parsed = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
if (parsed === null ||
typeof parsed !== "object" ||
Array.isArray(parsed) ||
typeof parsed.paymentHash !== "string") {
throw new Error("Invalid macaroon payload");
}
return parsed;
}
catch {
throw new Error("Invalid macaroon token");
}
}
async function sign(secret, payload) {
const { createHmac } = await import('crypto');
return createHmac("sha256", secret).update(payload).digest("hex");
}
/**
* Server: create a WWW-Authenticate header for a given macaroon and invoice
* @param args the macaroon/token and invoice generated for the client's request
* @returns the header value
*/
const makeL402AuthenticateHeader = (args) => {
if (!args.token) {
throw new Error("token must be provided");
}
return `L402 version="0" token="${args.token}", invoice="${args.invoice}"`;
};
/**
* Server: parse "authorization" header sent from client
* @param input value from authorization header
* @returns the macaroon and preimage
*/
function parseL402Authorization(input) {
// Backwards compat: LSAT was the former name of L402
const normalized = input.replace(/^LSAT /, "L402 ");
const prefix = "L402 ";
if (!normalized.startsWith(prefix))
return null;
const credentials = normalized.slice(prefix.length);
const colonIndex = credentials.indexOf(":");
if (colonIndex === -1) {
throw new Error("Invalid authorization header value");
}
return {
token: credentials.slice(0, colonIndex),
preimage: credentials.slice(colonIndex + 1),
};
}
export { fetchWithL402, issueL402Macaroon, makeL402AuthenticateHeader, parseL402, parseL402Authorization, verifyL402Macaroon };
//# sourceMappingURL=l402.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"l402.js","sources":["../../../src/402/l402/utils.ts","../../../src/402/l402/l402.ts"],"sourcesContent":["export const parseL402 = (input: string): Record<string, string> => {\n // Remove the L402 and LSAT identifiers\n const string = input.replace(\"L402\", \"\").replace(\"LSAT\", \"\").trim();\n\n // Initialize an object to store the key-value pairs\n const keyValuePairs = {};\n\n // Regular expression to match key and (quoted or unquoted) value\n const regex = /(\\w+)=(\"([^\"]*)\"|'([^']*)'|([^,]*))/g;\n let match;\n\n // Use regex to find all key-value pairs\n while ((match = regex.exec(string)) !== null) {\n // Key is always match[1]\n // Value is either match[3] (double-quoted), match[4] (single-quoted), or match[5] (unquoted)\n keyValuePairs[match[1]] = match[3] || match[4] || match[5];\n }\n\n return keyValuePairs;\n};\n\nexport const makeL402AuthenticateHeader = (args: {\n macaroon?: string;\n token?: string;\n invoice: string;\n}) => {\n if (args.macaroon) {\n return `L402 version=\"0\" macaroon=\"${args.macaroon}\", invoice=\"${args.invoice}\"`;\n } else {\n return `L402 version=\"0\" token=\"${args.token}\", invoice=\"${args.invoice}\"`;\n }\n};\n","import { Wallet } from \"../utils\";\nimport { parseL402 } from \"./utils\";\n\nexport const handleL402Payment = async (\n l402Header: string,\n url: string,\n fetchArgs: RequestInit,\n headers: Headers,\n wallet: Wallet,\n): Promise<Response> => {\n const details = parseL402(l402Header);\n const token = details.token || details.macaroon;\n const invoice = details.invoice;\n\n if (!token) {\n throw new Error(\"L402: missing token/macaroon in WWW-Authenticate header\");\n }\n if (!invoice) {\n throw new Error(\"L402: missing invoice in WWW-Authenticate header\");\n }\n\n const invResp = await wallet.payInvoice({ invoice });\n headers.set(\"Authorization\", `L402 ${token}:${invResp.preimage}`);\n return fetch(url, fetchArgs);\n};\n\nexport const fetchWithL402 = async (\n url: string,\n fetchArgs: RequestInit,\n options: {\n wallet: Wallet;\n },\n) => {\n const wallet = options.wallet;\n if (!wallet) {\n throw new Error(\"wallet is missing\");\n }\n if (!fetchArgs) {\n fetchArgs = {};\n }\n fetchArgs.cache = \"no-store\";\n fetchArgs.mode = \"cors\";\n const headers = new Headers(fetchArgs.headers ?? undefined);\n fetchArgs.headers = headers;\n\n const initResp = await fetch(url, fetchArgs);\n const header = initResp.headers.get(\"www-authenticate\");\n if (!header) {\n return initResp;\n }\n\n return handleL402Payment(header, url, fetchArgs, headers, wallet);\n};\n"],"names":[],"mappings":"AAAO,MAAM,SAAS,GAAG,CAAC,KAAa,KAA4B;;IAEjE,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;;IAGnE,MAAM,aAAa,GAAG,EAAE;;IAGxB,MAAM,KAAK,GAAG,sCAAsC;AACpD,IAAA,IAAI,KAAK;;AAGT,IAAA,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE;;;QAG5C,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC;IAC5D;AAEA,IAAA,OAAO,aAAa;AACtB,CAAC;;AChBM,MAAM,iBAAiB,GAAG,OAC/B,UAAkB,EAClB,GAAW,EACX,SAAsB,EACtB,OAAgB,EAChB,MAAc,KACO;AACrB,IAAA,MAAM,OAAO,GAAG,SAAS,CAAC,UAAU,CAAC;IACrC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,QAAQ;AAC/C,IAAA,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO;IAE/B,IAAI,CAAC,KAAK,EAAE;AACV,QAAA,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC;IAC5E;IACA,IAAI,CAAC,OAAO,EAAE;AACZ,QAAA,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC;IACrE;IAEA,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,CAAC;AACpD,IAAA,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,CAAA,KAAA,EAAQ,KAAK,CAAA,CAAA,EAAI,OAAO,CAAC,QAAQ,CAAA,CAAE,CAAC;AACjE,IAAA,OAAO,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC;AAC9B,CAAC;AAEM,MAAM,aAAa,GAAG,OAC3B,GAAW,EACX,SAAsB,EACtB,OAEC,KACC;AACF,IAAA,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM;IAC7B,IAAI,CAAC,MAAM,EAAE;AACX,QAAA,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC;IACtC;IACA,IAAI,CAAC,SAAS,EAAE;QACd,SAAS,GAAG,EAAE;IAChB;AACA,IAAA,SAAS,CAAC,KAAK,GAAG,UAAU;AAC5B,IAAA,SAAS,CAAC,IAAI,GAAG,MAAM;IACvB,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,SAAS,CAAC,OAAO,IAAI,SAAS,CAAC;AAC3D,IAAA,SAAS,CAAC,OAAO,GAAG,OAAO;IAE3B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,SAAS,CAAC;IAC5C,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IACvD,IAAI,CAAC,MAAM,EAAE;AACX,QAAA,OAAO,QAAQ;IACjB;AAEA,IAAA,OAAO,iBAAiB,CAAC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC;AACnE;;;;"}
{"version":3,"file":"l402.js","sources":["../../../src/402/l402/utils.ts","../../../src/402/l402/l402.ts","../../../src/402/l402/server/l402.ts","../../../src/402/l402/server/utils.ts"],"sourcesContent":["interface WwwAuthenticatePayload {\n token: string;\n invoice: string;\n [key: string]: string; // Allows any other string properties\n}\n\n/**\n * Client: parse \"www-authenticate\" header from server response\n * @param input\n * @returns details from the header value (token or macaroon, invoice)\n */\nexport const parseL402 = (input: string): WwwAuthenticatePayload => {\n // Remove the L402 and LSAT identifiers\n const string = input.replace(\"L402\", \"\").replace(\"LSAT\", \"\").trim();\n\n // Initialize an object to store the key-value pairs\n const keyValuePairs: Record<string, string> = {};\n\n // Regular expression to match key and (quoted or unquoted) value\n const regex = /(\\w+)=(\"([^\"]*)\"|'([^']*)'|([^,]*))/g;\n let match;\n\n // Use regex to find all key-value pairs\n while ((match = regex.exec(string)) !== null) {\n // Key is always match[1]\n // Value is either match[3] (double-quoted), match[4] (single-quoted), or match[5] (unquoted)\n keyValuePairs[match[1]] = match[3] || match[4] || match[5];\n }\n\n if (!keyValuePairs[\"token\"] && keyValuePairs[\"macaroon\"]) {\n // fallback to old naming\n keyValuePairs[\"token\"] = keyValuePairs[\"macaroon\"];\n delete keyValuePairs[\"macaroon\"];\n }\n\n if (\n !(\"token\" in keyValuePairs) ||\n typeof keyValuePairs[\"token\"] !== \"string\"\n ) {\n throw new Error(\"No macaroon or token found in www-authenticate header\");\n }\n if (\n !(\"invoice\" in keyValuePairs) ||\n typeof keyValuePairs[\"invoice\"] !== \"string\"\n ) {\n throw new Error(\"No invoice found in www-authenticate header\");\n }\n\n return keyValuePairs as WwwAuthenticatePayload;\n};\n","import { Wallet } from \"../utils\";\nimport { parseL402 } from \"./utils\";\n\nexport const handleL402Payment = async (\n l402Header: string,\n url: string,\n fetchArgs: RequestInit,\n headers: Headers,\n wallet: Wallet,\n): Promise<Response> => {\n const details = parseL402(l402Header);\n const token = details.token || details.macaroon;\n const invoice = details.invoice;\n\n if (!token) {\n throw new Error(\"L402: missing token/macaroon in WWW-Authenticate header\");\n }\n if (!invoice) {\n throw new Error(\"L402: missing invoice in WWW-Authenticate header\");\n }\n\n const invResp = await wallet.payInvoice({ invoice });\n headers.set(\"Authorization\", `L402 ${token}:${invResp.preimage}`);\n return fetch(url, fetchArgs);\n};\n\nexport const fetchWithL402 = async (\n url: string,\n fetchArgs: RequestInit,\n options: {\n wallet: Wallet;\n },\n) => {\n const wallet = options.wallet;\n if (!wallet) {\n throw new Error(\"wallet is missing\");\n }\n if (!fetchArgs) {\n fetchArgs = {};\n }\n fetchArgs.cache = \"no-store\";\n fetchArgs.mode = \"cors\";\n const headers = new Headers(fetchArgs.headers ?? undefined);\n fetchArgs.headers = headers;\n\n const initResp = await fetch(url, fetchArgs);\n const header = initResp.headers.get(\"www-authenticate\");\n if (!header) {\n return initResp;\n }\n\n return handleL402Payment(header, url, fetchArgs, headers, wallet);\n};\n","export type MacaroonPayload<T> = T & {\n paymentHash: string; // hex — SHA256 of the preimage\n};\n\nexport async function issueL402Macaroon<T extends Record<string, unknown>>(\n secret: string,\n paymentHash: string,\n params?: T,\n): Promise<string> {\n if (\n params !== undefined &&\n Object.prototype.hasOwnProperty.call(params, \"paymentHash\")\n ) {\n throw new Error(\"paymentHash is reserved\");\n }\n const payload = { ...params, paymentHash } as MacaroonPayload<T>;\n const encoded = Buffer.from(JSON.stringify(payload)).toString(\"base64url\");\n const mac = await sign(secret, encoded);\n return `${encoded}.${mac}`;\n}\n\nexport async function verifyL402Macaroon<T = unknown>(\n secret: string,\n token: string,\n): Promise<MacaroonPayload<T>> {\n const { timingSafeEqual } = await import(\"crypto\");\n const dotIndex = token.lastIndexOf(\".\");\n if (dotIndex === -1) throw new Error(\"Invalid macaroon token\");\n\n const encoded = token.slice(0, dotIndex);\n const mac = token.slice(dotIndex + 1);\n\n // Constant-time comparison to prevent timing attacks\n const expectedMac = await sign(secret, encoded);\n try {\n if (\n !timingSafeEqual(Buffer.from(mac, \"hex\"), Buffer.from(expectedMac, \"hex\"))\n ) {\n throw new Error(\"Invalid macaroon token\");\n }\n } catch (e) {\n throw new Error(\"Invalid macaroon token\");\n }\n\n try {\n const parsed: unknown = JSON.parse(\n Buffer.from(encoded, \"base64url\").toString(\"utf8\"),\n );\n if (\n parsed === null ||\n typeof parsed !== \"object\" ||\n Array.isArray(parsed) ||\n typeof (parsed as Record<string, unknown>).paymentHash !== \"string\"\n ) {\n throw new Error(\"Invalid macaroon payload\");\n }\n return parsed as MacaroonPayload<T>;\n } catch {\n throw new Error(\"Invalid macaroon token\");\n }\n}\n\nasync function sign(secret: string, payload: string): Promise<string> {\n const { createHmac } = await import(\"crypto\");\n return createHmac(\"sha256\", secret).update(payload).digest(\"hex\");\n}\n","/**\n * Server: create a WWW-Authenticate header for a given macaroon and invoice\n * @param args the macaroon/token and invoice generated for the client's request\n * @returns the header value\n */\nexport const makeL402AuthenticateHeader = (args: {\n token?: string;\n invoice: string;\n}) => {\n if (!args.token) {\n throw new Error(\"token must be provided\");\n }\n\n return `L402 version=\"0\" token=\"${args.token}\", invoice=\"${args.invoice}\"`;\n};\n\n/**\n * Server: parse \"authorization\" header sent from client\n * @param input value from authorization header\n * @returns the macaroon and preimage\n */\nexport function parseL402Authorization(\n input: string,\n): { token: string; preimage: string } | null {\n // Backwards compat: LSAT was the former name of L402\n const normalized = input.replace(/^LSAT /, \"L402 \");\n const prefix = \"L402 \";\n if (!normalized.startsWith(prefix)) return null;\n const credentials = normalized.slice(prefix.length);\n const colonIndex = credentials.indexOf(\":\");\n if (colonIndex === -1) {\n throw new Error(\"Invalid authorization header value\");\n }\n return {\n token: credentials.slice(0, colonIndex),\n preimage: credentials.slice(colonIndex + 1),\n };\n}\n"],"names":[],"mappings":"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"}

@@ -13,2 +13,309 @@ const buildX402PaymentSignature = (scheme, network, invoice, requirements) => {

function bytes(b, ...lengths) {
if (!(b instanceof Uint8Array))
throw new Error('Expected Uint8Array');
if (lengths.length > 0 && !lengths.includes(b.length))
throw new Error(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`);
}
function exists(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 output(out, instance) {
bytes(out);
const min = instance.outputLen;
if (out.length < min) {
throw new Error(`digestInto() expects output buffer of length at least ${min}`);
}
}
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
// node.js versions earlier than v19 don't declare it in global scope.
// For node.js, package.json#exports field mapping rewrites import
// from `crypto` to `cryptoNode`, which imports native module.
// Makes the utils un-importable in browsers without a bundler.
// Once node.js 18 is deprecated, we can just drop the import.
const u8a = (a) => a instanceof Uint8Array;
// Cast array to view
const createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
// The rotate right (circular right shift) operation for uint32
const rotr = (word, shift) => (word << (32 - shift)) | (word >>> shift);
// big-endian hardware is rare. Just in case someone still decides to run hashes:
// early-throw an error because we don't support BE yet.
const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
if (!isLE)
throw new Error('Non little-endian hardware is not supported');
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
/**
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
*/
function bytesToHex(bytes) {
if (!u8a(bytes))
throw new Error('Uint8Array expected');
// pre-caching improves the speed 6x
let hex = '';
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
}
return hex;
}
/**
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
*/
function utf8ToBytes(str) {
if (typeof str !== 'string')
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
}
/**
* Normalizes (non-hex) string or Uint8Array to Uint8Array.
* Warning: when Uint8Array is passed, it would NOT get copied.
* Keep in mind for future mutable operations.
*/
function toBytes(data) {
if (typeof data === 'string')
data = utf8ToBytes(data);
if (!u8a(data))
throw new Error(`expected Uint8Array, got ${typeof data}`);
return data;
}
// For runtime check if class implements interface
class Hash {
// Safe version that clones internal state
clone() {
return this._cloneInto();
}
}
function wrapConstructor(hashCons) {
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
const tmp = hashCons();
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = () => hashCons();
return hashC;
}
// Polyfill for Safari 14
function setBigUint64(view, byteOffset, value, isLE) {
if (typeof view.setBigUint64 === 'function')
return view.setBigUint64(byteOffset, value, isLE);
const _32n = BigInt(32);
const _u32_max = BigInt(0xffffffff);
const wh = Number((value >> _32n) & _u32_max);
const wl = Number(value & _u32_max);
const h = isLE ? 4 : 0;
const l = isLE ? 0 : 4;
view.setUint32(byteOffset + h, wh, isLE);
view.setUint32(byteOffset + l, wl, isLE);
}
// Base SHA2 class (RFC 6234)
class SHA2 extends Hash {
constructor(blockLen, outputLen, padOffset, isLE) {
super();
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE;
this.finished = false;
this.length = 0;
this.pos = 0;
this.destroyed = false;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
exists(this);
const { view, buffer, blockLen } = this;
data = toBytes(data);
const len = data.length;
for (let pos = 0; pos < len;) {
const take = Math.min(blockLen - this.pos, len - pos);
// Fast path: we have at least one block in input, cast it to view and process
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) {
exists(this);
output(out, this);
this.finished = true;
// Padding
// We can avoid allocation of buffer for padding completely if it
// was previously not allocated here. But it won't change performance.
const { buffer, view, blockLen, isLE } = this;
let { pos } = this;
// append the bit '1' to the message
buffer[pos++] = 0b10000000;
this.buffer.subarray(pos).fill(0);
// we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
pos = 0;
}
// Pad until full block byte with zeros
for (let i = pos; i < blockLen; i++)
buffer[i] = 0;
// Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
// You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
// So we just write lowest 64 bits of that value.
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
// NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
if (len % 4)
throw new Error('_sha2: outputLen should 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 i = 0; i < outLen; i++)
oview.setUint32(4 * i, state[i], isLE);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
to || (to = new this.constructor());
to.set(...this.get());
const { blockLen, buffer, length, finished, destroyed, pos } = this;
to.length = length;
to.pos = pos;
to.finished = finished;
to.destroyed = destroyed;
if (length % blockLen)
to.buffer.set(buffer);
return to;
}
}
// SHA2-256 need to try 2^128 hashes to execute birthday attack.
// BTC network is doing 2^67 hashes/sec as per early 2023.
// Choice: a ? b : c
const Chi = (a, b, c) => (a & b) ^ (~a & c);
// Majority function, true if any two inpust is true
const Maj = (a, b, c) => (a & b) ^ (a & c) ^ (b & c);
// Round constants:
// first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
// prettier-ignore
const SHA256_K = /* @__PURE__ */ new Uint32Array([
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
]);
// Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
// prettier-ignore
const IV = /* @__PURE__ */ new Uint32Array([
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
]);
// Temporary buffer, not used to store anything between runs
// Named this way because it matches specification.
const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
class SHA256 extends SHA2 {
constructor() {
super(64, 32, 8, false);
// We cannot use array here since array allows indexing by variable
// which means optimizer/compiler cannot use registers.
this.A = IV[0] | 0;
this.B = IV[1] | 0;
this.C = IV[2] | 0;
this.D = IV[3] | 0;
this.E = IV[4] | 0;
this.F = IV[5] | 0;
this.G = IV[6] | 0;
this.H = IV[7] | 0;
}
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) {
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
for (let i = 0; i < 16; i++, offset += 4)
SHA256_W[i] = view.getUint32(offset, false);
for (let i = 16; i < 64; i++) {
const W15 = SHA256_W[i - 15];
const W2 = SHA256_W[i - 2];
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
}
// Compression function main loop, 64 rounds
let { A, B, C, D, E, F, G, H } = this;
for (let i = 0; i < 64; i++) {
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 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;
}
// Add the compressed chunk to the current hash value
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() {
SHA256_W.fill(0);
}
destroy() {
this.set(0, 0, 0, 0, 0, 0, 0, 0);
this.buffer.fill(0);
}
}
/**
* SHA2-256 hash function
* @param message - data that would be hashed
*/
const sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256());
var lib = {};

@@ -883,310 +1190,16 @@

};
function bytes(b, ...lengths) {
if (!(b instanceof Uint8Array))
throw new Error('Expected Uint8Array');
if (lengths.length > 0 && !lengths.includes(b.length))
throw new Error(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`);
}
function exists(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 output(out, instance) {
bytes(out);
const min = instance.outputLen;
if (out.length < min) {
throw new Error(`digestInto() expects output buffer of length at least ${min}`);
function validatePreimage(preimage, paymentHash) {
try {
if (!/^[0-9a-fA-F]{64}$/.test(preimage))
return false;
if (!/^[0-9a-fA-F]{64}$/.test(paymentHash))
return false;
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return paymentHash === preimageHash;
}
}
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
// node.js versions earlier than v19 don't declare it in global scope.
// For node.js, package.json#exports field mapping rewrites import
// from `crypto` to `cryptoNode`, which imports native module.
// Makes the utils un-importable in browsers without a bundler.
// Once node.js 18 is deprecated, we can just drop the import.
const u8a = (a) => a instanceof Uint8Array;
// Cast array to view
const createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
// The rotate right (circular right shift) operation for uint32
const rotr = (word, shift) => (word << (32 - shift)) | (word >>> shift);
// big-endian hardware is rare. Just in case someone still decides to run hashes:
// early-throw an error because we don't support BE yet.
const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
if (!isLE)
throw new Error('Non little-endian hardware is not supported');
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
/**
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
*/
function bytesToHex(bytes) {
if (!u8a(bytes))
throw new Error('Uint8Array expected');
// pre-caching improves the speed 6x
let hex = '';
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
catch {
return false;
}
return hex;
}
/**
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
*/
function utf8ToBytes(str) {
if (typeof str !== 'string')
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
}
/**
* Normalizes (non-hex) string or Uint8Array to Uint8Array.
* Warning: when Uint8Array is passed, it would NOT get copied.
* Keep in mind for future mutable operations.
*/
function toBytes(data) {
if (typeof data === 'string')
data = utf8ToBytes(data);
if (!u8a(data))
throw new Error(`expected Uint8Array, got ${typeof data}`);
return data;
}
// For runtime check if class implements interface
class Hash {
// Safe version that clones internal state
clone() {
return this._cloneInto();
}
}
function wrapConstructor(hashCons) {
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
const tmp = hashCons();
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = () => hashCons();
return hashC;
}
// Polyfill for Safari 14
function setBigUint64(view, byteOffset, value, isLE) {
if (typeof view.setBigUint64 === 'function')
return view.setBigUint64(byteOffset, value, isLE);
const _32n = BigInt(32);
const _u32_max = BigInt(0xffffffff);
const wh = Number((value >> _32n) & _u32_max);
const wl = Number(value & _u32_max);
const h = isLE ? 4 : 0;
const l = isLE ? 0 : 4;
view.setUint32(byteOffset + h, wh, isLE);
view.setUint32(byteOffset + l, wl, isLE);
}
// Base SHA2 class (RFC 6234)
class SHA2 extends Hash {
constructor(blockLen, outputLen, padOffset, isLE) {
super();
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE;
this.finished = false;
this.length = 0;
this.pos = 0;
this.destroyed = false;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
exists(this);
const { view, buffer, blockLen } = this;
data = toBytes(data);
const len = data.length;
for (let pos = 0; pos < len;) {
const take = Math.min(blockLen - this.pos, len - pos);
// Fast path: we have at least one block in input, cast it to view and process
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) {
exists(this);
output(out, this);
this.finished = true;
// Padding
// We can avoid allocation of buffer for padding completely if it
// was previously not allocated here. But it won't change performance.
const { buffer, view, blockLen, isLE } = this;
let { pos } = this;
// append the bit '1' to the message
buffer[pos++] = 0b10000000;
this.buffer.subarray(pos).fill(0);
// we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
pos = 0;
}
// Pad until full block byte with zeros
for (let i = pos; i < blockLen; i++)
buffer[i] = 0;
// Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
// You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
// So we just write lowest 64 bits of that value.
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
// NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
if (len % 4)
throw new Error('_sha2: outputLen should 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 i = 0; i < outLen; i++)
oview.setUint32(4 * i, state[i], isLE);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
to || (to = new this.constructor());
to.set(...this.get());
const { blockLen, buffer, length, finished, destroyed, pos } = this;
to.length = length;
to.pos = pos;
to.finished = finished;
to.destroyed = destroyed;
if (length % blockLen)
to.buffer.set(buffer);
return to;
}
}
// SHA2-256 need to try 2^128 hashes to execute birthday attack.
// BTC network is doing 2^67 hashes/sec as per early 2023.
// Choice: a ? b : c
const Chi = (a, b, c) => (a & b) ^ (~a & c);
// Majority function, true if any two inpust is true
const Maj = (a, b, c) => (a & b) ^ (a & c) ^ (b & c);
// Round constants:
// first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
// prettier-ignore
const SHA256_K = /* @__PURE__ */ new Uint32Array([
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
]);
// Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
// prettier-ignore
const IV = /* @__PURE__ */ new Uint32Array([
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
]);
// Temporary buffer, not used to store anything between runs
// Named this way because it matches specification.
const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
class SHA256 extends SHA2 {
constructor() {
super(64, 32, 8, false);
// We cannot use array here since array allows indexing by variable
// which means optimizer/compiler cannot use registers.
this.A = IV[0] | 0;
this.B = IV[1] | 0;
this.C = IV[2] | 0;
this.D = IV[3] | 0;
this.E = IV[4] | 0;
this.F = IV[5] | 0;
this.G = IV[6] | 0;
this.H = IV[7] | 0;
}
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) {
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
for (let i = 0; i < 16; i++, offset += 4)
SHA256_W[i] = view.getUint32(offset, false);
for (let i = 16; i < 64; i++) {
const W15 = SHA256_W[i - 15];
const W2 = SHA256_W[i - 2];
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
}
// Compression function main loop, 64 rounds
let { A, B, C, D, E, F, G, H } = this;
for (let i = 0; i < 64; i++) {
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 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;
}
// Add the compressed chunk to the current hash value
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() {
SHA256_W.fill(0);
}
destroy() {
this.set(0, 0, 0, 0, 0, 0, 0, 0);
this.buffer.fill(0);
}
}
/**
* SHA2-256 hash function
* @param message - data that would be hashed
*/
const sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256());
class Invoice {

@@ -1230,9 +1243,3 @@ constructor(args) {

return false;
try {
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return this.paymentHash === preimageHash;
}
catch {
return false;
}
return validatePreimage(preimage, this.paymentHash);
}

@@ -1239,0 +1246,0 @@ async verifyPayment() {

@@ -0,1 +1,308 @@

function bytes(b, ...lengths) {
if (!(b instanceof Uint8Array))
throw new Error('Expected Uint8Array');
if (lengths.length > 0 && !lengths.includes(b.length))
throw new Error(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`);
}
function exists(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 output(out, instance) {
bytes(out);
const min = instance.outputLen;
if (out.length < min) {
throw new Error(`digestInto() expects output buffer of length at least ${min}`);
}
}
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
// node.js versions earlier than v19 don't declare it in global scope.
// For node.js, package.json#exports field mapping rewrites import
// from `crypto` to `cryptoNode`, which imports native module.
// Makes the utils un-importable in browsers without a bundler.
// Once node.js 18 is deprecated, we can just drop the import.
const u8a = (a) => a instanceof Uint8Array;
// Cast array to view
const createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
// The rotate right (circular right shift) operation for uint32
const rotr = (word, shift) => (word << (32 - shift)) | (word >>> shift);
// big-endian hardware is rare. Just in case someone still decides to run hashes:
// early-throw an error because we don't support BE yet.
const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
if (!isLE)
throw new Error('Non little-endian hardware is not supported');
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
/**
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
*/
function bytesToHex(bytes) {
if (!u8a(bytes))
throw new Error('Uint8Array expected');
// pre-caching improves the speed 6x
let hex = '';
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
}
return hex;
}
/**
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
*/
function utf8ToBytes(str) {
if (typeof str !== 'string')
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
}
/**
* Normalizes (non-hex) string or Uint8Array to Uint8Array.
* Warning: when Uint8Array is passed, it would NOT get copied.
* Keep in mind for future mutable operations.
*/
function toBytes(data) {
if (typeof data === 'string')
data = utf8ToBytes(data);
if (!u8a(data))
throw new Error(`expected Uint8Array, got ${typeof data}`);
return data;
}
// For runtime check if class implements interface
class Hash {
// Safe version that clones internal state
clone() {
return this._cloneInto();
}
}
function wrapConstructor(hashCons) {
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
const tmp = hashCons();
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = () => hashCons();
return hashC;
}
// Polyfill for Safari 14
function setBigUint64(view, byteOffset, value, isLE) {
if (typeof view.setBigUint64 === 'function')
return view.setBigUint64(byteOffset, value, isLE);
const _32n = BigInt(32);
const _u32_max = BigInt(0xffffffff);
const wh = Number((value >> _32n) & _u32_max);
const wl = Number(value & _u32_max);
const h = isLE ? 4 : 0;
const l = isLE ? 0 : 4;
view.setUint32(byteOffset + h, wh, isLE);
view.setUint32(byteOffset + l, wl, isLE);
}
// Base SHA2 class (RFC 6234)
class SHA2 extends Hash {
constructor(blockLen, outputLen, padOffset, isLE) {
super();
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE;
this.finished = false;
this.length = 0;
this.pos = 0;
this.destroyed = false;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
exists(this);
const { view, buffer, blockLen } = this;
data = toBytes(data);
const len = data.length;
for (let pos = 0; pos < len;) {
const take = Math.min(blockLen - this.pos, len - pos);
// Fast path: we have at least one block in input, cast it to view and process
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) {
exists(this);
output(out, this);
this.finished = true;
// Padding
// We can avoid allocation of buffer for padding completely if it
// was previously not allocated here. But it won't change performance.
const { buffer, view, blockLen, isLE } = this;
let { pos } = this;
// append the bit '1' to the message
buffer[pos++] = 0b10000000;
this.buffer.subarray(pos).fill(0);
// we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
pos = 0;
}
// Pad until full block byte with zeros
for (let i = pos; i < blockLen; i++)
buffer[i] = 0;
// Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
// You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
// So we just write lowest 64 bits of that value.
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
// NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
if (len % 4)
throw new Error('_sha2: outputLen should 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 i = 0; i < outLen; i++)
oview.setUint32(4 * i, state[i], isLE);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
to || (to = new this.constructor());
to.set(...this.get());
const { blockLen, buffer, length, finished, destroyed, pos } = this;
to.length = length;
to.pos = pos;
to.finished = finished;
to.destroyed = destroyed;
if (length % blockLen)
to.buffer.set(buffer);
return to;
}
}
// SHA2-256 need to try 2^128 hashes to execute birthday attack.
// BTC network is doing 2^67 hashes/sec as per early 2023.
// Choice: a ? b : c
const Chi = (a, b, c) => (a & b) ^ (~a & c);
// Majority function, true if any two inpust is true
const Maj = (a, b, c) => (a & b) ^ (a & c) ^ (b & c);
// Round constants:
// first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
// prettier-ignore
const SHA256_K = /* @__PURE__ */ new Uint32Array([
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
]);
// Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
// prettier-ignore
const IV = /* @__PURE__ */ new Uint32Array([
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
]);
// Temporary buffer, not used to store anything between runs
// Named this way because it matches specification.
const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
class SHA256 extends SHA2 {
constructor() {
super(64, 32, 8, false);
// We cannot use array here since array allows indexing by variable
// which means optimizer/compiler cannot use registers.
this.A = IV[0] | 0;
this.B = IV[1] | 0;
this.C = IV[2] | 0;
this.D = IV[3] | 0;
this.E = IV[4] | 0;
this.F = IV[5] | 0;
this.G = IV[6] | 0;
this.H = IV[7] | 0;
}
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) {
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
for (let i = 0; i < 16; i++, offset += 4)
SHA256_W[i] = view.getUint32(offset, false);
for (let i = 16; i < 64; i++) {
const W15 = SHA256_W[i - 15];
const W2 = SHA256_W[i - 2];
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
}
// Compression function main loop, 64 rounds
let { A, B, C, D, E, F, G, H } = this;
for (let i = 0; i < 64; i++) {
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 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;
}
// Add the compressed chunk to the current hash value
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() {
SHA256_W.fill(0);
}
destroy() {
this.set(0, 0, 0, 0, 0, 0, 0, 0);
this.buffer.fill(0);
}
}
/**
* SHA2-256 hash function
* @param message - data that would be hashed
*/
const sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256());
var lib = {};

@@ -870,310 +1177,16 @@

};
function bytes(b, ...lengths) {
if (!(b instanceof Uint8Array))
throw new Error('Expected Uint8Array');
if (lengths.length > 0 && !lengths.includes(b.length))
throw new Error(`Expected Uint8Array of length ${lengths}, not of length=${b.length}`);
}
function exists(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 output(out, instance) {
bytes(out);
const min = instance.outputLen;
if (out.length < min) {
throw new Error(`digestInto() expects output buffer of length at least ${min}`);
function validatePreimage(preimage, paymentHash) {
try {
if (!/^[0-9a-fA-F]{64}$/.test(preimage))
return false;
if (!/^[0-9a-fA-F]{64}$/.test(paymentHash))
return false;
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return paymentHash === preimageHash;
}
}
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */
// We use WebCrypto aka globalThis.crypto, which exists in browsers and node.js 16+.
// node.js versions earlier than v19 don't declare it in global scope.
// For node.js, package.json#exports field mapping rewrites import
// from `crypto` to `cryptoNode`, which imports native module.
// Makes the utils un-importable in browsers without a bundler.
// Once node.js 18 is deprecated, we can just drop the import.
const u8a = (a) => a instanceof Uint8Array;
// Cast array to view
const createView = (arr) => new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
// The rotate right (circular right shift) operation for uint32
const rotr = (word, shift) => (word << (32 - shift)) | (word >>> shift);
// big-endian hardware is rare. Just in case someone still decides to run hashes:
// early-throw an error because we don't support BE yet.
const isLE = new Uint8Array(new Uint32Array([0x11223344]).buffer)[0] === 0x44;
if (!isLE)
throw new Error('Non little-endian hardware is not supported');
const hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
/**
* @example bytesToHex(Uint8Array.from([0xca, 0xfe, 0x01, 0x23])) // 'cafe0123'
*/
function bytesToHex(bytes) {
if (!u8a(bytes))
throw new Error('Uint8Array expected');
// pre-caching improves the speed 6x
let hex = '';
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
catch {
return false;
}
return hex;
}
/**
* @example utf8ToBytes('abc') // new Uint8Array([97, 98, 99])
*/
function utf8ToBytes(str) {
if (typeof str !== 'string')
throw new Error(`utf8ToBytes expected string, got ${typeof str}`);
return new Uint8Array(new TextEncoder().encode(str)); // https://bugzil.la/1681809
}
/**
* Normalizes (non-hex) string or Uint8Array to Uint8Array.
* Warning: when Uint8Array is passed, it would NOT get copied.
* Keep in mind for future mutable operations.
*/
function toBytes(data) {
if (typeof data === 'string')
data = utf8ToBytes(data);
if (!u8a(data))
throw new Error(`expected Uint8Array, got ${typeof data}`);
return data;
}
// For runtime check if class implements interface
class Hash {
// Safe version that clones internal state
clone() {
return this._cloneInto();
}
}
function wrapConstructor(hashCons) {
const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
const tmp = hashCons();
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.create = () => hashCons();
return hashC;
}
// Polyfill for Safari 14
function setBigUint64(view, byteOffset, value, isLE) {
if (typeof view.setBigUint64 === 'function')
return view.setBigUint64(byteOffset, value, isLE);
const _32n = BigInt(32);
const _u32_max = BigInt(0xffffffff);
const wh = Number((value >> _32n) & _u32_max);
const wl = Number(value & _u32_max);
const h = isLE ? 4 : 0;
const l = isLE ? 0 : 4;
view.setUint32(byteOffset + h, wh, isLE);
view.setUint32(byteOffset + l, wl, isLE);
}
// Base SHA2 class (RFC 6234)
class SHA2 extends Hash {
constructor(blockLen, outputLen, padOffset, isLE) {
super();
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE;
this.finished = false;
this.length = 0;
this.pos = 0;
this.destroyed = false;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
exists(this);
const { view, buffer, blockLen } = this;
data = toBytes(data);
const len = data.length;
for (let pos = 0; pos < len;) {
const take = Math.min(blockLen - this.pos, len - pos);
// Fast path: we have at least one block in input, cast it to view and process
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) {
exists(this);
output(out, this);
this.finished = true;
// Padding
// We can avoid allocation of buffer for padding completely if it
// was previously not allocated here. But it won't change performance.
const { buffer, view, blockLen, isLE } = this;
let { pos } = this;
// append the bit '1' to the message
buffer[pos++] = 0b10000000;
this.buffer.subarray(pos).fill(0);
// we have less than padOffset left in buffer, so we cannot put length in current block, need process it and pad again
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
pos = 0;
}
// Pad until full block byte with zeros
for (let i = pos; i < blockLen; i++)
buffer[i] = 0;
// Note: sha512 requires length to be 128bit integer, but length in JS will overflow before that
// You need to write around 2 exabytes (u64_max / 8 / (1024**6)) for this to happen.
// So we just write lowest 64 bits of that value.
setBigUint64(view, blockLen - 8, BigInt(this.length * 8), isLE);
this.process(view, 0);
const oview = createView(out);
const len = this.outputLen;
// NOTE: we do division by 4 later, which should be fused in single op with modulo by JIT
if (len % 4)
throw new Error('_sha2: outputLen should 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 i = 0; i < outLen; i++)
oview.setUint32(4 * i, state[i], isLE);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
to || (to = new this.constructor());
to.set(...this.get());
const { blockLen, buffer, length, finished, destroyed, pos } = this;
to.length = length;
to.pos = pos;
to.finished = finished;
to.destroyed = destroyed;
if (length % blockLen)
to.buffer.set(buffer);
return to;
}
}
// SHA2-256 need to try 2^128 hashes to execute birthday attack.
// BTC network is doing 2^67 hashes/sec as per early 2023.
// Choice: a ? b : c
const Chi = (a, b, c) => (a & b) ^ (~a & c);
// Majority function, true if any two inpust is true
const Maj = (a, b, c) => (a & b) ^ (a & c) ^ (b & c);
// Round constants:
// first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
// prettier-ignore
const SHA256_K = /* @__PURE__ */ new Uint32Array([
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
]);
// Initial state (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):
// prettier-ignore
const IV = /* @__PURE__ */ new Uint32Array([
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
]);
// Temporary buffer, not used to store anything between runs
// Named this way because it matches specification.
const SHA256_W = /* @__PURE__ */ new Uint32Array(64);
class SHA256 extends SHA2 {
constructor() {
super(64, 32, 8, false);
// We cannot use array here since array allows indexing by variable
// which means optimizer/compiler cannot use registers.
this.A = IV[0] | 0;
this.B = IV[1] | 0;
this.C = IV[2] | 0;
this.D = IV[3] | 0;
this.E = IV[4] | 0;
this.F = IV[5] | 0;
this.G = IV[6] | 0;
this.H = IV[7] | 0;
}
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) {
// Extend the first 16 words into the remaining 48 words w[16..63] of the message schedule array
for (let i = 0; i < 16; i++, offset += 4)
SHA256_W[i] = view.getUint32(offset, false);
for (let i = 16; i < 64; i++) {
const W15 = SHA256_W[i - 15];
const W2 = SHA256_W[i - 2];
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ (W15 >>> 3);
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ (W2 >>> 10);
SHA256_W[i] = (s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16]) | 0;
}
// Compression function main loop, 64 rounds
let { A, B, C, D, E, F, G, H } = this;
for (let i = 0; i < 64; i++) {
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
const T1 = (H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i]) | 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;
}
// Add the compressed chunk to the current hash value
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() {
SHA256_W.fill(0);
}
destroy() {
this.set(0, 0, 0, 0, 0, 0, 0, 0);
this.buffer.fill(0);
}
}
/**
* SHA2-256 hash function
* @param message - data that would be hashed
*/
const sha256 = /* @__PURE__ */ wrapConstructor(() => new SHA256());
class Invoice {

@@ -1217,9 +1230,3 @@ constructor(args) {

return false;
try {
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return this.paymentHash === preimageHash;
}
catch {
return false;
}
return validatePreimage(preimage, this.paymentHash);
}

@@ -1255,3 +1262,3 @@ async verifyPayment() {

export { Invoice, decodeInvoice, fromHexString };
export { Invoice, decodeInvoice, fromHexString, validatePreimage };
//# sourceMappingURL=bolt11.js.map

@@ -1348,2 +1348,15 @@ function bytes(b, ...lengths) {

};
function validatePreimage(preimage, paymentHash) {
try {
if (!/^[0-9a-fA-F]{64}$/.test(preimage))
return false;
if (!/^[0-9a-fA-F]{64}$/.test(paymentHash))
return false;
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return paymentHash === preimageHash;
}
catch {
return false;
}
}

@@ -1388,9 +1401,3 @@ class Invoice {

return false;
try {
const preimageHash = bytesToHex(sha256(fromHexString(preimage)));
return this.paymentHash === preimageHash;
}
catch {
return false;
}
return validatePreimage(preimage, this.paymentHash);
}

@@ -1397,0 +1404,0 @@ async verifyPayment() {

@@ -1,5 +0,5 @@

!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).LightningTools={})}(this,function(e){"use strict";var t,r,n,o={};var s=function(){if(n)return r;n=1;const{bech32:e,hex:s,utf8:i}=(t||(t=1,function(e){function t(e){if(!Number.isSafeInteger(e))throw new Error(`Wrong integer: ${e}`)}function r(...e){const t=(e,t)=>r=>e(t(r));return{encode:Array.from(e).reverse().reduce((e,r)=>e?t(e,r.encode):r.encode,void 0),decode:e.reduce((e,r)=>e?t(e,r.decode):r.decode,void 0)}}function n(e){return{encode:r=>{if(!Array.isArray(r)||r.length&&"number"!=typeof r[0])throw new Error("alphabet.encode input should be an array of numbers");return r.map(r=>{if(t(r),r<0||r>=e.length)throw new Error(`Digit index outside alphabet: ${r} (alphabet: ${e.length})`);return e[r]})},decode:t=>{if(!Array.isArray(t)||t.length&&"string"!=typeof t[0])throw new Error("alphabet.decode input should be array of strings");return t.map(t=>{if("string"!=typeof t)throw new Error(`alphabet.decode: not string element=${t}`);const r=e.indexOf(t);if(-1===r)throw new Error(`Unknown letter: "${t}". Allowed: ${e}`);return r})}}}function o(e=""){if("string"!=typeof e)throw new Error("join separator should be string");return{encode:t=>{if(!Array.isArray(t)||t.length&&"string"!=typeof t[0])throw new Error("join.encode input should be array of strings");for(let e of t)if("string"!=typeof e)throw new Error(`join.encode: non-string input=${e}`);return t.join(e)},decode:t=>{if("string"!=typeof t)throw new Error("join.decode input should be string");return t.split(e)}}}function s(e,r="="){if(t(e),"string"!=typeof r)throw new Error("padding chr should be string");return{encode(t){if(!Array.isArray(t)||t.length&&"string"!=typeof t[0])throw new Error("padding.encode input should be array of strings");for(let e of t)if("string"!=typeof e)throw new Error(`padding.encode: non-string input=${e}`);for(;t.length*e%8;)t.push(r);return t},decode(t){if(!Array.isArray(t)||t.length&&"string"!=typeof t[0])throw new Error("padding.encode input should be array of strings");for(let e of t)if("string"!=typeof e)throw new Error(`padding.decode: non-string input=${e}`);let n=t.length;if(n*e%8)throw new Error("Invalid padding: string should have whole number of bytes");for(;n>0&&t[n-1]===r;n--)if(!((n-1)*e%8))throw new Error("Invalid padding: string has too much padding");return t.slice(0,n)}}}function i(e){if("function"!=typeof e)throw new Error("normalize fn should be function");return{encode:e=>e,decode:t=>e(t)}}function a(e,r,n){if(r<2)throw new Error(`convertRadix: wrong from=${r}, base cannot be less than 2`);if(n<2)throw new Error(`convertRadix: wrong to=${n}, base cannot be less than 2`);if(!Array.isArray(e))throw new Error("convertRadix: data should be array");if(!e.length)return[];let o=0;const s=[],i=Array.from(e);for(i.forEach(e=>{if(t(e),e<0||e>=r)throw new Error(`Wrong integer: ${e}`)});;){let e=0,t=!0;for(let s=o;s<i.length;s++){const a=i[s],c=r*e+a;if(!Number.isSafeInteger(c)||r*e/r!==e||c-a!==r*e)throw new Error("convertRadix: carry overflow");if(e=c%n,i[s]=Math.floor(c/n),!Number.isSafeInteger(i[s])||i[s]*n+e!==c)throw new Error("convertRadix: carry overflow");t&&(i[s]?t=!1:o=s)}if(s.push(e),t)break}for(let t=0;t<e.length-1&&0===e[t];t++)s.push(0);return s.reverse()}
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).LightningTools={})}(this,function(e){"use strict";function t(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")}function r(e,t){!function(e,...t){if(!(e instanceof Uint8Array))throw new Error("Expected Uint8Array");if(t.length>0&&!t.includes(e.length))throw new Error(`Expected Uint8Array of length ${t}, not of length=${e.length}`)}(e);const r=t.outputLen;if(e.length<r)throw new Error(`digestInto() expects output buffer of length at least ${r}`)}
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */const n=e=>e instanceof Uint8Array,o=e=>new DataView(e.buffer,e.byteOffset,e.byteLength),s=(e,t)=>e<<32-t|e>>>t;if(!(68===new Uint8Array(new Uint32Array([287454020]).buffer)[0]))throw new Error("Non little-endian hardware is not supported");const i=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));function a(e){if(!n(e))throw new Error("Uint8Array expected");let t="";for(let r=0;r<e.length;r++)t+=i[e[r]];return t}function c(e){if("string"==typeof e&&(e=function(e){if("string"!=typeof e)throw new Error("utf8ToBytes expected string, got "+typeof e);return new Uint8Array((new TextEncoder).encode(e))}(e)),!n(e))throw new Error("expected Uint8Array, got "+typeof e);return e}class h{clone(){return this._cloneInto()}}function l(e){const t=t=>e().update(c(t)).digest(),r=e();return t.outputLen=r.outputLen,t.blockLen=r.blockLen,t.create=()=>e(),t}class u extends h{constructor(e,t,r,n){super(),this.blockLen=e,this.outputLen=t,this.padOffset=r,this.isLE=n,this.finished=!1,this.length=0,this.pos=0,this.destroyed=!1,this.buffer=new Uint8Array(e),this.view=o(this.buffer)}update(e){t(this);const{view:r,buffer:n,blockLen:s}=this,i=(e=c(e)).length;for(let t=0;t<i;){const a=Math.min(s-this.pos,i-t);if(a===s){const r=o(e);for(;s<=i-t;t+=s)this.process(r,t);continue}n.set(e.subarray(t,t+a),this.pos),this.pos+=a,t+=a,this.pos===s&&(this.process(r,0),this.pos=0)}return this.length+=e.length,this.roundClean(),this}digestInto(e){t(this),r(e,this),this.finished=!0;const{buffer:n,view:s,blockLen:i,isLE:a}=this;let{pos:c}=this;n[c++]=128,this.buffer.subarray(c).fill(0),this.padOffset>i-c&&(this.process(s,0),c=0);for(let e=c;e<i;e++)n[e]=0;!function(e,t,r,n){if("function"==typeof e.setBigUint64)return e.setBigUint64(t,r,n);const o=BigInt(32),s=BigInt(4294967295),i=Number(r>>o&s),a=Number(r&s),c=n?4:0,h=n?0:4;e.setUint32(t+c,i,n),e.setUint32(t+h,a,n)}(s,i-8,BigInt(8*this.length),a),this.process(s,0);const h=o(e),l=this.outputLen;if(l%4)throw new Error("_sha2: outputLen should be aligned to 32bit");const u=l/4,f=this.get();if(u>f.length)throw new Error("_sha2: outputLen bigger than state");for(let e=0;e<u;e++)h.setUint32(4*e,f[e],a)}digest(){const{buffer:e,outputLen:t}=this;this.digestInto(e);const r=e.slice(0,t);return this.destroy(),r}_cloneInto(e){e||(e=new this.constructor),e.set(...this.get());const{blockLen:t,buffer:r,length:n,finished:o,destroyed:s,pos:i}=this;return e.length=n,e.pos=i,e.finished=o,e.destroyed=s,n%t&&e.buffer.set(r),e}}const f=(e,t,r)=>e&t^~e&r,d=(e,t,r)=>e&t^e&r^t&r,p=new Uint32Array([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]),w=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),m=new Uint32Array(64);class y extends u{constructor(){super(64,32,8,!1),this.A=0|w[0],this.B=0|w[1],this.C=0|w[2],this.D=0|w[3],this.E=0|w[4],this.F=0|w[5],this.G=0|w[6],this.H=0|w[7]}get(){const{A:e,B:t,C:r,D:n,E:o,F:s,G:i,H:a}=this;return[e,t,r,n,o,s,i,a]}set(e,t,r,n,o,s,i,a){this.A=0|e,this.B=0|t,this.C=0|r,this.D=0|n,this.E=0|o,this.F=0|s,this.G=0|i,this.H=0|a}process(e,t){for(let r=0;r<16;r++,t+=4)m[r]=e.getUint32(t,!1);for(let e=16;e<64;e++){const t=m[e-15],r=m[e-2],n=s(t,7)^s(t,18)^t>>>3,o=s(r,17)^s(r,19)^r>>>10;m[e]=o+m[e-7]+n+m[e-16]|0}let{A:r,B:n,C:o,D:i,E:a,F:c,G:h,H:l}=this;for(let e=0;e<64;e++){const t=l+(s(a,6)^s(a,11)^s(a,25))+f(a,c,h)+p[e]+m[e]|0,u=(s(r,2)^s(r,13)^s(r,22))+d(r,n,o)|0;l=h,h=c,c=a,a=i+t|0,i=o,o=n,n=r,r=t+u|0}r=r+this.A|0,n=n+this.B|0,o=o+this.C|0,i=i+this.D|0,a=a+this.E|0,c=c+this.F|0,h=h+this.G|0,l=l+this.H|0,this.set(r,n,o,i,a,c,h,l)}roundClean(){m.fill(0)}destroy(){this.set(0,0,0,0,0,0,0,0),this.buffer.fill(0)}}const g=l(()=>new y);var b,E,v,x={};var A=function(){if(v)return E;v=1;const{bech32:e,hex:t,utf8:r}=(b||(b=1,function(e){function t(e){if(!Number.isSafeInteger(e))throw new Error(`Wrong integer: ${e}`)}function r(...e){const t=(e,t)=>r=>e(t(r));return{encode:Array.from(e).reverse().reduce((e,r)=>e?t(e,r.encode):r.encode,void 0),decode:e.reduce((e,r)=>e?t(e,r.decode):r.decode,void 0)}}function n(e){return{encode:r=>{if(!Array.isArray(r)||r.length&&"number"!=typeof r[0])throw new Error("alphabet.encode input should be an array of numbers");return r.map(r=>{if(t(r),r<0||r>=e.length)throw new Error(`Digit index outside alphabet: ${r} (alphabet: ${e.length})`);return e[r]})},decode:t=>{if(!Array.isArray(t)||t.length&&"string"!=typeof t[0])throw new Error("alphabet.decode input should be array of strings");return t.map(t=>{if("string"!=typeof t)throw new Error(`alphabet.decode: not string element=${t}`);const r=e.indexOf(t);if(-1===r)throw new Error(`Unknown letter: "${t}". Allowed: ${e}`);return r})}}}function o(e=""){if("string"!=typeof e)throw new Error("join separator should be string");return{encode:t=>{if(!Array.isArray(t)||t.length&&"string"!=typeof t[0])throw new Error("join.encode input should be array of strings");for(let e of t)if("string"!=typeof e)throw new Error(`join.encode: non-string input=${e}`);return t.join(e)},decode:t=>{if("string"!=typeof t)throw new Error("join.decode input should be string");return t.split(e)}}}function s(e,r="="){if(t(e),"string"!=typeof r)throw new Error("padding chr should be string");return{encode(t){if(!Array.isArray(t)||t.length&&"string"!=typeof t[0])throw new Error("padding.encode input should be array of strings");for(let e of t)if("string"!=typeof e)throw new Error(`padding.encode: non-string input=${e}`);for(;t.length*e%8;)t.push(r);return t},decode(t){if(!Array.isArray(t)||t.length&&"string"!=typeof t[0])throw new Error("padding.encode input should be array of strings");for(let e of t)if("string"!=typeof e)throw new Error(`padding.decode: non-string input=${e}`);let n=t.length;if(n*e%8)throw new Error("Invalid padding: string should have whole number of bytes");for(;n>0&&t[n-1]===r;n--)if(!((n-1)*e%8))throw new Error("Invalid padding: string has too much padding");return t.slice(0,n)}}}function i(e){if("function"!=typeof e)throw new Error("normalize fn should be function");return{encode:e=>e,decode:t=>e(t)}}function a(e,r,n){if(r<2)throw new Error(`convertRadix: wrong from=${r}, base cannot be less than 2`);if(n<2)throw new Error(`convertRadix: wrong to=${n}, base cannot be less than 2`);if(!Array.isArray(e))throw new Error("convertRadix: data should be array");if(!e.length)return[];let o=0;const s=[],i=Array.from(e);for(i.forEach(e=>{if(t(e),e<0||e>=r)throw new Error(`Wrong integer: ${e}`)});;){let e=0,t=!0;for(let s=o;s<i.length;s++){const a=i[s],c=r*e+a;if(!Number.isSafeInteger(c)||r*e/r!==e||c-a!==r*e)throw new Error("convertRadix: carry overflow");if(e=c%n,i[s]=Math.floor(c/n),!Number.isSafeInteger(i[s])||i[s]*n+e!==c)throw new Error("convertRadix: carry overflow");t&&(i[s]?t=!1:o=s)}if(s.push(e),t)break}for(let t=0;t<e.length-1&&0===e[t];t++)s.push(0);return s.reverse()}
/*! scure-base - MIT License (c) 2022 Paul Miller (paulmillr.com) */
Object.defineProperty(e,"__esModule",{value:!0}),e.bytes=e.stringToBytes=e.str=e.bytesToString=e.hex=e.utf8=e.bech32m=e.bech32=e.base58check=e.base58xmr=e.base58xrp=e.base58flickr=e.base58=e.base64url=e.base64=e.base32crockford=e.base32hex=e.base32=e.base16=e.utils=e.assertNumber=void 0,e.assertNumber=t;const c=(e,t)=>t?c(t,e%t):e,h=(e,t)=>e+(t-c(e,t));function l(e,r,n,o){if(!Array.isArray(e))throw new Error("convertRadix2: data should be array");if(r<=0||r>32)throw new Error(`convertRadix2: wrong from=${r}`);if(n<=0||n>32)throw new Error(`convertRadix2: wrong to=${n}`);if(h(r,n)>32)throw new Error(`convertRadix2: carry overflow from=${r} to=${n} carryBits=${h(r,n)}`);let s=0,i=0;const a=2**n-1,c=[];for(const o of e){if(t(o),o>=2**r)throw new Error(`convertRadix2: invalid data word=${o} from=${r}`);if(s=s<<r|o,i+r>32)throw new Error(`convertRadix2: carry overflow pos=${i} from=${r}`);for(i+=r;i>=n;i-=n)c.push((s>>i-n&a)>>>0);s&=2**i-1}if(s=s<<n-i&a,!o&&i>=r)throw new Error("Excess padding");if(!o&&s)throw new Error(`Non-zero padding: ${s}`);return o&&i>0&&c.push(s>>>0),c}function u(e){return t(e),{encode:t=>{if(!(t instanceof Uint8Array))throw new Error("radix.encode input should be Uint8Array");return a(Array.from(t),256,e)},decode:t=>{if(!Array.isArray(t)||t.length&&"number"!=typeof t[0])throw new Error("radix.decode input should be array of strings");return Uint8Array.from(a(t,e,256))}}}function d(e,r=!1){if(t(e),e<=0||e>32)throw new Error("radix2: bits should be in (0..32]");if(h(8,e)>32||h(e,8)>32)throw new Error("radix2: carry overflow");return{encode:t=>{if(!(t instanceof Uint8Array))throw new Error("radix2.encode input should be Uint8Array");return l(Array.from(t),8,e,!r)},decode:t=>{if(!Array.isArray(t)||t.length&&"number"!=typeof t[0])throw new Error("radix2.decode input should be array of strings");return Uint8Array.from(l(t,e,8,r))}}}function f(e){if("function"!=typeof e)throw new Error("unsafeWrapper fn should be function");return function(...t){try{return e.apply(null,t)}catch(e){}}}function p(e,r){if(t(e),"function"!=typeof r)throw new Error("checksum fn should be function");return{encode(t){if(!(t instanceof Uint8Array))throw new Error("checksum.encode: input should be Uint8Array");const n=r(t).slice(0,e),o=new Uint8Array(t.length+e);return o.set(t),o.set(n,t.length),o},decode(t){if(!(t instanceof Uint8Array))throw new Error("checksum.decode: input should be Uint8Array");const n=t.slice(0,-e),o=r(n).slice(0,e),s=t.slice(-e);for(let t=0;t<e;t++)if(o[t]!==s[t])throw new Error("Invalid checksum");return n}}}e.utils={alphabet:n,chain:r,checksum:p,radix:u,radix2:d,join:o,padding:s},e.base16=r(d(4),n("0123456789ABCDEF"),o("")),e.base32=r(d(5),n("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"),s(5),o("")),e.base32hex=r(d(5),n("0123456789ABCDEFGHIJKLMNOPQRSTUV"),s(5),o("")),e.base32crockford=r(d(5),n("0123456789ABCDEFGHJKMNPQRSTVWXYZ"),o(""),i(e=>e.toUpperCase().replace(/O/g,"0").replace(/[IL]/g,"1"))),e.base64=r(d(6),n("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),s(6),o("")),e.base64url=r(d(6),n("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"),s(6),o(""));const w=e=>r(u(58),n(e),o(""));e.base58=w("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"),e.base58flickr=w("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"),e.base58xrp=w("rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz");const y=[0,2,3,5,6,7,9,10,11];e.base58xmr={encode(t){let r="";for(let n=0;n<t.length;n+=8){const o=t.subarray(n,n+8);r+=e.base58.encode(o).padStart(y[o.length],"1")}return r},decode(t){let r=[];for(let n=0;n<t.length;n+=11){const o=t.slice(n,n+11),s=y.indexOf(o.length),i=e.base58.decode(o);for(let e=0;e<i.length-s;e++)if(0!==i[e])throw new Error("base58xmr: wrong padding");r=r.concat(Array.from(i.slice(i.length-s)))}return Uint8Array.from(r)}},e.base58check=t=>r(p(4,e=>t(t(e))),e.base58);const m=r(n("qpzry9x8gf2tvdw0s3jn54khce6mua7l"),o("")),g=[996825010,642813549,513874426,1027748829,705979059];function b(e){const t=e>>25;let r=(33554431&e)<<5;for(let e=0;e<g.length;e++)1==(t>>e&1)&&(r^=g[e]);return r}function E(e,t,r=1){const n=e.length;let o=1;for(let t=0;t<n;t++){const r=e.charCodeAt(t);if(r<33||r>126)throw new Error(`Invalid prefix (${e})`);o=b(o)^r>>5}o=b(o);for(let t=0;t<n;t++)o=b(o)^31&e.charCodeAt(t);for(let e of t)o=b(o)^e;for(let e=0;e<6;e++)o=b(o);return o^=r,m.encode(l([o%2**30],30,5,!1))}function v(e){const t="bech32"===e?1:734539939,r=d(5),n=r.decode,o=r.encode,s=f(n);function i(e,r=90){if("string"!=typeof e)throw new Error("bech32.decode input should be string, not "+typeof e);if(e.length<8||!1!==r&&e.length>r)throw new TypeError(`Wrong string length: ${e.length} (${e}). Expected (8..${r})`);const n=e.toLowerCase();if(e!==n&&e!==e.toUpperCase())throw new Error("String must be lowercase or uppercase");const o=(e=n).lastIndexOf("1");if(0===o||-1===o)throw new Error('Letter "1" must be present between prefix and data only');const s=e.slice(0,o),i=e.slice(o+1);if(i.length<6)throw new Error("Data must be at least 6 characters long");const a=m.decode(i).slice(0,-6),c=E(s,a,t);if(!i.endsWith(c))throw new Error(`Invalid checksum in ${e}: expected "${c}"`);return{prefix:s,words:a}}return{encode:function(e,r,n=90){if("string"!=typeof e)throw new Error("bech32.encode prefix should be string, not "+typeof e);if(!Array.isArray(r)||r.length&&"number"!=typeof r[0])throw new Error("bech32.encode words should be array of numbers, not "+typeof r);const o=e.length+7+r.length;if(!1!==n&&o>n)throw new TypeError(`Length ${o} exceeds limit ${n}`);return`${e=e.toLowerCase()}1${m.encode(r)}${E(e,r,t)}`},decode:i,decodeToBytes:function(e){const{prefix:t,words:r}=i(e,!1);return{prefix:t,words:r,bytes:n(r)}},decodeUnsafe:f(i),fromWords:n,fromWordsUnsafe:s,toWords:o}}e.bech32=v("bech32"),e.bech32m=v("bech32m"),e.utf8={encode:e=>(new TextDecoder).decode(e),decode:e=>(new TextEncoder).encode(e)},e.hex=r(d(4),n("0123456789abcdef"),o(""),i(e=>{if("string"!=typeof e||e.length%2)throw new TypeError(`hex.decode: expected string, got ${typeof e} with length ${e.length}`);return e.toLowerCase()}));const x={utf8:e.utf8,hex:e.hex,base16:e.base16,base32:e.base32,base64:e.base64,base64url:e.base64url,base58:e.base58,base58xmr:e.base58xmr},A=`Invalid encoding type. Available types: ${Object.keys(x).join(", ")}`;e.bytesToString=(e,t)=>{if("string"!=typeof e||!x.hasOwnProperty(e))throw new TypeError(A);if(!(t instanceof Uint8Array))throw new TypeError("bytesToString() expects Uint8Array");return x[e].encode(t)},e.str=e.bytesToString,e.stringToBytes=(e,t)=>{if(!x.hasOwnProperty(e))throw new TypeError(A);if("string"!=typeof t)throw new TypeError("stringToBytes() expects string");return x[e].decode(t)},e.bytes=e.stringToBytes}(o)),o),a={bech32:"bc",pubKeyHash:0,scriptHash:5,validWitnessVersions:[0]},c={bech32:"tb",pubKeyHash:111,scriptHash:196,validWitnessVersions:[0]},h={bech32:"tbs",pubKeyHash:111,scriptHash:196,validWitnessVersions:[0]},l={bech32:"bcrt",pubKeyHash:111,scriptHash:196,validWitnessVersions:[0]},u={bech32:"sb",pubKeyHash:63,scriptHash:123,validWitnessVersions:[0]},d=["option_data_loss_protect","initial_routing_sync","option_upfront_shutdown_script","gossip_queries","var_onion_optin","gossip_queries_ex","option_static_remotekey","payment_secret","basic_mpp","option_support_large_channel"],f={m:BigInt(1e3),u:BigInt(1e6),n:BigInt(1e9),p:BigInt(1e12)},p=BigInt("2100000000000000000"),w=BigInt(1e11),y={payment_hash:1,payment_secret:16,description:13,payee:19,description_hash:23,expiry:6,min_final_cltv_expiry:24,fallback_address:9,route_hint:3,feature_bits:5,metadata:27},m={};for(let e=0,t=Object.keys(y);e<t.length;e++){const r=t[e],n=y[t[e]].toString();m[n]=r}const g={1:t=>s.encode(e.fromWordsUnsafe(t)),16:t=>s.encode(e.fromWordsUnsafe(t)),13:t=>i.encode(e.fromWordsUnsafe(t)),19:t=>s.encode(e.fromWordsUnsafe(t)),23:t=>s.encode(e.fromWordsUnsafe(t)),27:t=>s.encode(e.fromWordsUnsafe(t)),6:E,24:E,3:function(t){const r=[];let n,o,i,a,c,h=e.fromWordsUnsafe(t);for(;h.length>0;)n=s.encode(h.slice(0,33)),o=s.encode(h.slice(33,41)),i=parseInt(s.encode(h.slice(41,45)),16),a=parseInt(s.encode(h.slice(45,49)),16),c=parseInt(s.encode(h.slice(49,51)),16),h=h.slice(51),r.push({pubkey:n,short_channel_id:o,fee_base_msat:i,fee_proportional_millionths:a,cltv_expiry_delta:c});return r},5:function(e){const t=e.slice().reverse().map(e=>[!!(1&e),!!(2&e),!!(4&e),!!(8&e),!!(16&e)]).reduce((e,t)=>e.concat(t),[]);for(;t.length<2*d.length;)t.push(!1);const r={};d.forEach((e,n)=>{let o;o=t[2*n]?"required":t[2*n+1]?"supported":"unsupported",r[e]=o});const n=t.slice(2*d.length);return r.extra_bits={start_bit:2*d.length,bits:n,has_required:n.reduce((e,t,r)=>r%2!=0?e||!1:e||t,!1)},r}};function b(t){return r=>({tagCode:parseInt(t),words:e.encode("unknown",r,Number.MAX_SAFE_INTEGER)})}function E(e){return e.reverse().reduce((e,t,r)=>e+t*Math.pow(32,r),0)}function v(e,t){let r,n;if(e.slice(-1).match(/^[munp]$/))r=e.slice(-1),n=e.slice(0,-1);else{if(e.slice(-1).match(/^[^munp0-9]$/))throw new Error("Not a valid multiplier for the amount");n=e}if(!n.match(/^\d+$/))throw new Error("Not a valid human readable amount");const o=BigInt(n),s=r?o*w/f[r]:o*w;if("p"===r&&o%BigInt(10)!==BigInt(0)||s>p)throw new Error("Amount is outside of valid range");return t?s.toString():s}return r={decode:function(t,r){if("string"!=typeof t)throw new Error("Lightning Payment Request must be string");if("ln"!==t.slice(0,2).toLowerCase())throw new Error("Not a proper lightning payment request");const n=[],o=e.decode(t,Number.MAX_SAFE_INTEGER);t=t.toLowerCase();const i=o.prefix;let d=o.words,f=t.slice(i.length+1),p=d.slice(-104);d=d.slice(0,-104);let w=i.match(/^ln(\S+?)(\d*)([a-zA-Z]?)$/);if(w&&!w[2]&&(w=i.match(/^ln(\S+)$/)),!w)throw new Error("Not a proper lightning payment request");n.push({name:"lightning_network",letters:"ln"});const x=w[1];let A;if(r){if(void 0===r.bech32||void 0===r.pubKeyHash||void 0===r.scriptHash||!Array.isArray(r.validWitnessVersions))throw new Error("Invalid network");A=r}else switch(x){case a.bech32:A=a;break;case c.bech32:A=c;break;case h.bech32:A=h;break;case l.bech32:A=l;break;case u.bech32:A=u}if(!A||A.bech32!==x)throw new Error("Unknown coin bech32 prefix");n.push({name:"coin_network",letters:x,value:A});const k=w[2];let U;if(k){U=v(k+w[3],!0),n.push({name:"amount",letters:w[2]+w[3],value:U})}else U=null;n.push({name:"separator",letters:"1"});const $=E(d.slice(0,7));let L,R,_,I;for(d=d.slice(7),n.push({name:"timestamp",letters:f.slice(0,7),value:$}),f=f.slice(7);d.length>0;){const e=d[0].toString();L=m[e]||"unknown_tag",R=g[e]||b(e),d=d.slice(1),_=E(d.slice(0,2)),d=d.slice(2),I=d.slice(0,_),d=d.slice(_),n.push({name:L,tag:f[0],letters:f.slice(0,3+_),value:R(I)}),f=f.slice(3+_)}n.push({name:"signature",letters:f.slice(0,104),value:s.encode(e.fromWordsUnsafe(p))}),f=f.slice(104),n.push({name:"checksum",letters:f});let N={paymentRequest:t,sections:n,get expiry(){let e=n.find(e=>"expiry"===e.name);if(e)return D("timestamp")+e.value},get route_hints(){return n.filter(e=>"route_hint"===e.name).map(e=>e.value)}};for(let e in y)"route_hint"!==e&&Object.defineProperty(N,e,{get:()=>D(e)});return N;function D(e){let t=n.find(t=>t.name===e);return t?t.value:void 0}},hrpToMillisat:v}}();const i=e=>Uint8Array.from(e.match(/.{1,2}/g).map(e=>parseInt(e,16))),a=e=>{if(!e)return null;try{const t=s.decode(e);if(!t||!t.sections)return null;const r=t.sections.find(e=>"payment_hash"===e.name);if("payment_hash"!==r?.name||!r.value)return null;const n=r.value;let o=0,i=0,a="0";const c=t.sections.find(e=>"amount"===e.name);"amount"===c?.name&&c.value&&(a=c.value,i=parseInt(c.value),o=parseInt(c.value)/1e3);const h=t.sections.find(e=>"timestamp"===e.name);if("timestamp"!==h?.name||!h.value)return null;const l=h.value;let u;const d=t.sections.find(e=>"expiry"===e.name);"expiry"===d?.name&&(u=d.value);const f=t.sections.find(e=>"description"===e.name);return{paymentHash:n,satoshi:o,millisatoshi:i,amountRaw:a,timestamp:l,expiry:u,description:"description"===f?.name?f?.value:void 0}}catch{return null}};function c(e,t=!0){if(e.destroyed)throw new Error("Hash instance has been destroyed");if(t&&e.finished)throw new Error("Hash#digest() has already been called")}function h(e,t){!function(e,...t){if(!(e instanceof Uint8Array))throw new Error("Expected Uint8Array");if(t.length>0&&!t.includes(e.length))throw new Error(`Expected Uint8Array of length ${t}, not of length=${e.length}`)}(e);const r=t.outputLen;if(e.length<r)throw new Error(`digestInto() expects output buffer of length at least ${r}`)}
/*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) */const l=e=>e instanceof Uint8Array,u=e=>new DataView(e.buffer,e.byteOffset,e.byteLength),d=(e,t)=>e<<32-t|e>>>t;if(!(68===new Uint8Array(new Uint32Array([287454020]).buffer)[0]))throw new Error("Non little-endian hardware is not supported");const f=Array.from({length:256},(e,t)=>t.toString(16).padStart(2,"0"));function p(e){if(!l(e))throw new Error("Uint8Array expected");let t="";for(let r=0;r<e.length;r++)t+=f[e[r]];return t}function w(e){if("string"==typeof e&&(e=function(e){if("string"!=typeof e)throw new Error("utf8ToBytes expected string, got "+typeof e);return new Uint8Array((new TextEncoder).encode(e))}(e)),!l(e))throw new Error("expected Uint8Array, got "+typeof e);return e}class y{clone(){return this._cloneInto()}}function m(e){const t=t=>e().update(w(t)).digest(),r=e();return t.outputLen=r.outputLen,t.blockLen=r.blockLen,t.create=()=>e(),t}class g extends y{constructor(e,t,r,n){super(),this.blockLen=e,this.outputLen=t,this.padOffset=r,this.isLE=n,this.finished=!1,this.length=0,this.pos=0,this.destroyed=!1,this.buffer=new Uint8Array(e),this.view=u(this.buffer)}update(e){c(this);const{view:t,buffer:r,blockLen:n}=this,o=(e=w(e)).length;for(let s=0;s<o;){const i=Math.min(n-this.pos,o-s);if(i===n){const t=u(e);for(;n<=o-s;s+=n)this.process(t,s);continue}r.set(e.subarray(s,s+i),this.pos),this.pos+=i,s+=i,this.pos===n&&(this.process(t,0),this.pos=0)}return this.length+=e.length,this.roundClean(),this}digestInto(e){c(this),h(e,this),this.finished=!0;const{buffer:t,view:r,blockLen:n,isLE:o}=this;let{pos:s}=this;t[s++]=128,this.buffer.subarray(s).fill(0),this.padOffset>n-s&&(this.process(r,0),s=0);for(let e=s;e<n;e++)t[e]=0;!function(e,t,r,n){if("function"==typeof e.setBigUint64)return e.setBigUint64(t,r,n);const o=BigInt(32),s=BigInt(4294967295),i=Number(r>>o&s),a=Number(r&s),c=n?4:0,h=n?0:4;e.setUint32(t+c,i,n),e.setUint32(t+h,a,n)}(r,n-8,BigInt(8*this.length),o),this.process(r,0);const i=u(e),a=this.outputLen;if(a%4)throw new Error("_sha2: outputLen should be aligned to 32bit");const l=a/4,d=this.get();if(l>d.length)throw new Error("_sha2: outputLen bigger than state");for(let e=0;e<l;e++)i.setUint32(4*e,d[e],o)}digest(){const{buffer:e,outputLen:t}=this;this.digestInto(e);const r=e.slice(0,t);return this.destroy(),r}_cloneInto(e){e||(e=new this.constructor),e.set(...this.get());const{blockLen:t,buffer:r,length:n,finished:o,destroyed:s,pos:i}=this;return e.length=n,e.pos=i,e.finished=o,e.destroyed=s,n%t&&e.buffer.set(r),e}}const b=(e,t,r)=>e&t^~e&r,E=(e,t,r)=>e&t^e&r^t&r,v=new Uint32Array([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]),x=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),A=new Uint32Array(64);class k extends g{constructor(){super(64,32,8,!1),this.A=0|x[0],this.B=0|x[1],this.C=0|x[2],this.D=0|x[3],this.E=0|x[4],this.F=0|x[5],this.G=0|x[6],this.H=0|x[7]}get(){const{A:e,B:t,C:r,D:n,E:o,F:s,G:i,H:a}=this;return[e,t,r,n,o,s,i,a]}set(e,t,r,n,o,s,i,a){this.A=0|e,this.B=0|t,this.C=0|r,this.D=0|n,this.E=0|o,this.F=0|s,this.G=0|i,this.H=0|a}process(e,t){for(let r=0;r<16;r++,t+=4)A[r]=e.getUint32(t,!1);for(let e=16;e<64;e++){const t=A[e-15],r=A[e-2],n=d(t,7)^d(t,18)^t>>>3,o=d(r,17)^d(r,19)^r>>>10;A[e]=o+A[e-7]+n+A[e-16]|0}let{A:r,B:n,C:o,D:s,E:i,F:a,G:c,H:h}=this;for(let e=0;e<64;e++){const t=h+(d(i,6)^d(i,11)^d(i,25))+b(i,a,c)+v[e]+A[e]|0,l=(d(r,2)^d(r,13)^d(r,22))+E(r,n,o)|0;h=c,c=a,a=i,i=s+t|0,s=o,o=n,n=r,r=t+l|0}r=r+this.A|0,n=n+this.B|0,o=o+this.C|0,s=s+this.D|0,i=i+this.E|0,a=a+this.F|0,c=c+this.G|0,h=h+this.H|0,this.set(r,n,o,s,i,a,c,h)}roundClean(){A.fill(0)}destroy(){this.set(0,0,0,0,0,0,0,0),this.buffer.fill(0)}}const U=m(()=>new k);class ${constructor(e){if(this.paymentRequest=e.pr,!this.paymentRequest)throw new Error("Invalid payment request");const t=a(this.paymentRequest);if(!t)throw new Error("Failed to decode payment request");this.paymentHash=t.paymentHash,this.satoshi=t.satoshi,this.millisatoshi=t.millisatoshi,this.amountRaw=t.amountRaw,this.timestamp=t.timestamp,this.expiry=t.expiry,this.createdDate=new Date(1e3*this.timestamp),this.expiryDate=this.expiry?new Date(1e3*(this.timestamp+this.expiry)):void 0,this.description=t.description??null,this.verify=e.verify??null,this.preimage=e.preimage??null,this.successAction=e.successAction??null}async isPaid(){if(this.preimage)return this.validatePreimage(this.preimage);if(this.verify)return await this.verifyPayment();throw new Error("Could not verify payment")}validatePreimage(e){if(!e||!this.paymentHash)return!1;try{const t=p(U(i(e)));return this.paymentHash===t}catch{return!1}}async verifyPayment(){try{if(!this.verify)throw new Error("LNURL verify not available");const e=await fetch(this.verify);if(!e.ok)throw new Error(`Verification request failed: ${e.status} ${e.statusText}`);const t=await e.json();return t.preimage&&(this.preimage=t.preimage),t.settled}catch(e){return console.error("Failed to check LNURL-verify",e),!1}}hasExpired(){const{expiryDate:e}=this;return!!e&&e.getTime()<Date.now()}}const L=e=>{if("keysend"!==e.tag)throw new Error("Invalid keysend params");if("OK"!==e.status)throw new Error("Keysend status not OK");if(!e.pubkey)throw new Error("Pubkey does not exist");const t=e.pubkey;let r,n;return e.customData&&e.customData[0]&&(r=e.customData[0].customKey,n=e.customData[0].customValue),{destination:t,customKey:r,customValue:n}};async function R({satoshi:e,comment:t,p:r,e:n,relays:o},s={}){const i=s.nostr||globalThis.nostr;if(!i)throw new Error("nostr option or window.nostr is not available");const a=[["relays",...o],["amount",e.toString()]];r&&a.push(["p",r]),n&&a.push(["e",n]);const c={pubkey:await i.getPublicKey(),created_at:Math.floor(Date.now()/1e3),kind:9734,tags:a,content:t??""};return c.id=N(c),await i.signEvent(c)}function _(e){if("string"!=typeof e.content)return!1;if("number"!=typeof e.created_at)return!1;if(!Array.isArray(e.tags))return!1;for(let t=0;t<e.tags.length;t++){const r=e.tags[t];if(!Array.isArray(r))return!1;for(let e=0;e<r.length;e++)if("object"==typeof r[e])return!1}return!0}function I(e){if(!_(e))throw new Error("can't serialize event with wrong or missing properties");return JSON.stringify([0,e.pubkey,e.created_at,e.kind,e.tags,e.content])}function N(e){return p(U(I(e)))}function D(e,t){let r,n;return t&&e&&(r=e.names?.[t],n=r?e.relays?.[r]:void 0),[e,r,n]}const S=/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/,W=e=>!!e&&S.test(e),T=({amount:e,min:t,max:r})=>e>0&&e>=t&&e<=r,P=async e=>{if("payRequest"!==e.tag)throw new Error("Invalid pay service params");const t=(e.callback+"").trim();if(!W(t))throw new Error("Callback must be a valid url");const r=Math.ceil(Number(e.minSendable||0)),n=Math.floor(Number(e.maxSendable));if(!r||!n||r>n)throw new Error("Invalid pay service params");let o,s;try{o=JSON.parse(e.metadata+""),s=p(U(e.metadata+""))}catch{o=[],s=p(U("[]"))}let i="",a="",c="",h="";for(let e=0;e<o.length;e++){const[t,r]=o[e];switch(t){case"text/plain":c=r;break;case"text/identifier":h=r;break;case"text/email":i=r;break;case"image/png;base64":case"image/jpeg;base64":a="data:"+t+","+r}}const l=e.payerData;let u;try{u=new URL(t).hostname}catch{}return{callback:t,fixed:r===n,min:r,max:n,domain:u,metadata:o,metadataHash:s,identifier:h,email:i,description:c,image:a,payerData:l,commentAllowed:Number(e.commentAllowed)||0,rawData:e,allowsNostr:e.allowsNostr||!1}},C=async(e,t)=>{const{boost:r}=e;t||(t={});const n=t.webln||globalThis.webln;if(!n)throw new Error("WebLN not available");if(!n.keysend)throw new Error("Keysend not available in current WebLN provider");const o=e.amount||Math.floor(r.value_msat/1e3),s={destination:e.destination,amount:o,customRecords:{7629169:JSON.stringify(r)}};e.customKey&&e.customValue&&(s.customRecords[e.customKey]=e.customValue),await n.enable();return await n.keysend(s)},B=/^((?:[^<>()[\]\\.,;:\s@"]+(?:\.[^<>()[\]\\.,;:\s@"]+)*)|(?:".+"))@((?:\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(?:(?:[a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,H="https://api.getalby.com/lnurl";function j(e,t){return{payInvoice:async r=>{const n=new $({pr:r.invoice});if(n.satoshi>t)throw new Error(`Invoice amount (${n.satoshi} sats) exceeds maxAmount (${t} sats)`);return e.payInvoice(r)}}}const O=async(e,t,r,n,o)=>{const s=(e=>{const t=e.replace("L402","").replace("LSAT","").trim(),r={},n=/(\w+)=("([^"]*)"|'([^']*)'|([^,]*))/g;let o;for(;null!==(o=n.exec(t));)r[o[1]]=o[3]||o[4]||o[5];return r})(e),i=s.token||s.macaroon,a=s.invoice;if(!i)throw new Error("L402: missing token/macaroon in WWW-Authenticate header");if(!a)throw new Error("L402: missing invoice in WWW-Authenticate header");const c=await o.payInvoice({invoice:a});return n.set("Authorization",`L402 ${i}:${c.preimage}`),fetch(t,r)},q=async(e,t,r,n,o)=>{let s;try{s=JSON.parse(decodeURIComponent(escape(atob(e))))}catch(e){throw new Error("x402: invalid PAYMENT-REQUIRED header (not valid base64-encoded JSON)")}if(!Array.isArray(s.accepts)||0===s.accepts.length)throw new Error("x402: PAYMENT-REQUIRED header contains no payment options");const i=s.accepts.find(e=>"lightning"===e.extra?.paymentMethod);if(!i)throw new Error("x402: unsupported x402 network, only Bitcoin lightning network is supported.");if(!i.extra?.invoice)throw new Error("x402: payment requirements missing lightning invoice");const a=new $({pr:i.extra.invoice});if(a.amountRaw!=i.amount)throw new Error(`Invalid invoice amount: ${a.amountRaw}. expected ${i.amount}`);return await o.payInvoice({invoice:a.paymentRequest}),n.set("payment-signature",((e,t,r,n)=>{const o=JSON.stringify({x402Version:2,scheme:e,network:t,payload:{invoice:r},accepted:n});return btoa(unescape(encodeURIComponent(o)))})(i.scheme,i.network,a.paymentRequest,i)),fetch(t,r)},K=e=>{if(null===e||"object"!=typeof e)return JSON.stringify(e);if(Array.isArray(e))return"["+e.map(K).join(",")+"]";return"{"+Object.keys(e).sort().map(t=>JSON.stringify(t)+":"+K(e[t])).join(",")+"}"},F=(e,t,r)=>{const n={id:e.id,intent:e.intent,method:e.method,realm:e.realm,request:e.request};e.expires&&(n.expires=e.expires);return(e=>{const t=(new TextEncoder).encode(e);let r="";for(let e=0;e<t.length;e++)r+=String.fromCharCode(t[e]);return btoa(r).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")})(K({challenge:n,payload:{preimage:t}}))},V=async(e,t,r,n,o)=>{const s=(e=>{if(!e.trimStart().toLowerCase().startsWith("payment"))return null;const t=e.slice(e.toLowerCase().indexOf("payment")+7).trim(),r={},n=/(\w+)=("([^"]*)"|'([^']*)'|([^,\s]*))/g;let o;for(;null!==(o=n.exec(t));)r[o[1]]=o[3]??o[4]??o[5]??"";return"lightning"===r.method&&"charge"===r.intent&&r.id&&r.realm&&r.request?{id:r.id,realm:r.realm,method:r.method,intent:r.intent,request:r.request,...r.expires?{expires:r.expires}:{}}:null})(e);if(!s)throw new Error("mpp: invalid or unsupported WWW-Authenticate challenge (expected Payment method=lightning intent=charge)");let i;try{i=JSON.parse((e=>{const t=e.replace(/-/g,"+").replace(/_/g,"/"),r=atob(t),n=new Uint8Array(r.length);for(let e=0;e<r.length;e++)n[e]=r.charCodeAt(e);return new TextDecoder("utf-8").decode(n)})(s.request))}catch(e){throw new Error("mpp: invalid request auth-param (not valid base64url-encoded JSON)")}const a=i.methodDetails?.invoice;if(!a)throw new Error("mpp: missing invoice in charge request");const c=await o.payInvoice({invoice:a}),h=F(s,c.preimage);return n.set("Authorization",`Payment ${h}`),fetch(t,r)},M=async e=>{const t="https://getalby.com/api/rates/"+e.toLowerCase()+".json",r=await fetch(t);if(!r.ok)throw new Error(`Failed to fetch rate: ${r.status} ${r.statusText}`);return(await r.json()).rate_float/1e8},z=async({satoshi:e,currency:t})=>{const r=await M(t);return Number(e)*r};e.DEFAULT_PROXY=H,e.Invoice=$,e.LN_ADDRESS_REGEX=B,e.LightningAddress=class{constructor(e,t){this.address=e,this.options={proxy:H},this.options=Object.assign(this.options,t),this.parse(),this.webln=this.options.webln}parse(){const e=B.exec(this.address.toLowerCase());e&&(this.username=e[1],this.domain=e[2])}getWebLN(){return this.webln||globalThis.webln}async fetch(){return this.options.proxy?this.fetchWithProxy():this.fetchWithoutProxy()}async fetchWithProxy(){const e=await fetch(`${this.options.proxy}/lightning-address-details?${new URLSearchParams({ln:this.address}).toString()}`);if(!e.ok)throw new Error(`Failed to fetch lnurl info: ${e.status} ${e.statusText}`);const t=await e.json();await this.parseLnUrlPayResponse(t.lnurlp),this.parseKeysendResponse(t.keysend),this.parseNostrResponse(t.nostr)}async fetchWithoutProxy(){this.domain&&this.username&&await Promise.all([this.fetchLnurlData(),this.fetchKeysendData(),this.fetchNostrData()])}async fetchLnurlData(){const e=await fetch(this.lnurlpUrl());if(e.ok){const t=await e.json();await this.parseLnUrlPayResponse(t)}}async fetchKeysendData(){const e=await fetch(this.keysendUrl());if(e.ok){const t=await e.json();this.parseKeysendResponse(t)}}async fetchNostrData(){const e=await fetch(this.nostrUrl());if(e.ok){const t=await e.json();this.parseNostrResponse(t)}}lnurlpUrl(){return`https://${this.domain}/.well-known/lnurlp/${this.username}`}keysendUrl(){return`https://${this.domain}/.well-known/keysend/${this.username}`}nostrUrl(){return`https://${this.domain}/.well-known/nostr.json?name=${this.username}`}async generateInvoice(e){let t;if(this.options.proxy){const r=await fetch(`${this.options.proxy}/generate-invoice?${new URLSearchParams({ln:this.address,...e}).toString()}`);if(!r.ok)throw new Error(`Failed to generate invoice: ${r.status} ${r.statusText}`);t=(await r.json()).invoice}else{if(!this.lnurlpData)throw new Error("No lnurlpData available. Please call fetch() first.");if(!this.lnurlpData.callback||!W(this.lnurlpData.callback))throw new Error("Valid callback does not exist in lnurlpData");const r=new URL(this.lnurlpData.callback);r.search=new URLSearchParams(e).toString();const n=await fetch(r.toString());if(!n.ok)throw new Error(`Failed to generate invoice: ${n.status} ${n.statusText}`);t=await n.json()}const r=t&&t.pr&&t.pr.toString();if(!r)throw new Error("Invalid pay service invoice");const n={pr:r};if(t&&t.verify&&(n.verify=t.verify.toString()),t&&t.successAction&&"object"==typeof t.successAction){const{tag:e,message:r,description:o,url:s}=t.successAction;"message"===e?n.successAction={tag:e,message:r}:"url"===e&&(n.successAction={tag:e,description:o,url:s})}return new $(n)}async requestInvoice(e){if(!this.lnurlpData)throw new Error("No lnurlpData available. Please call fetch() first.");const t=1e3*e.satoshi,{commentAllowed:r,min:n,max:o}=this.lnurlpData;if(!T({amount:t,min:n,max:o}))throw new Error("Invalid amount");if(e.comment&&r&&r>0&&e.comment.length>r)throw new Error(`The comment length must be ${r} characters or fewer`);const s={amount:t.toString()};return e.comment&&(s.comment=e.comment),e.payerdata&&(s.payerdata=JSON.stringify(e.payerdata)),this.generateInvoice(s)}async boost(e,t=0){if(!this.keysendData)throw new Error("No keysendData available. Please call fetch() first.");const{destination:r,customKey:n,customValue:o}=this.keysendData,s=this.getWebLN();if(!s)throw new Error("WebLN not available");return C({destination:r,customKey:n,customValue:o,amount:t,boost:e},{webln:s})}async zapInvoice({satoshi:e,comment:t,relays:r,e:n},o={}){if(!this.lnurlpData)throw new Error("No lnurlpData available. Please call fetch() first.");if(!this.nostrPubkey)throw new Error("Nostr Pubkey is missing");const s=this.nostrPubkey,i=1e3*e,{allowsNostr:a,min:c,max:h}=this.lnurlpData;if(!T({amount:i,min:c,max:h}))throw new Error("Invalid amount");if(!a)throw new Error("Your provider does not support zaps");const l=await R({satoshi:i,comment:t,p:s,e:n,relays:r},o),u={amount:i.toString(),nostr:JSON.stringify(l)};return await this.generateInvoice(u)}async zap(e,t={}){const r=this.zapInvoice(e,t),n=this.getWebLN();if(!n)throw new Error("WebLN not available");await n.enable();return n.sendPayment((await r).paymentRequest)}async parseLnUrlPayResponse(e){e&&(this.lnurlpData=await P(e))}parseKeysendResponse(e){e&&(this.keysendData=L(e))}parseNostrResponse(e){e&&([this.nostrData,this.nostrPubkey,this.nostrRelays]=D(e,this.username))}},e.createGuardedWallet=j,e.decodeInvoice=a,e.fetch402=async(e,t,r)=>{const n=r.maxAmount?j(r.wallet,r.maxAmount):r.wallet;t||(t={}),t.cache="no-store",t.mode="cors";const o=new Headers(t.headers??void 0);t.headers=o;const s=await fetch(e,t),i=s.headers.get("www-authenticate");if(i){const r=i.trimStart().toLowerCase();if(r.startsWith("payment"))return V(i,e,t,o,n);if(r.startsWith("l402")||r.startsWith("lsat"))return O(i,e,t,o,n);throw new Error(`fetch402: unsupported WWW-Authenticate scheme: ${i}`)}const a=s.headers.get("PAYMENT-REQUIRED");return a?q(a,e,t,o,n):s},e.fetchWithL402=async(e,t,r)=>{const n=r.wallet;if(!n)throw new Error("wallet is missing");t||(t={}),t.cache="no-store",t.mode="cors";const o=new Headers(t.headers??void 0);t.headers=o;const s=await fetch(e,t),i=s.headers.get("www-authenticate");return i?O(i,e,t,o,n):s},e.fetchWithMpp=async(e,t,r)=>{const n=r.wallet;if(!n)throw new Error("wallet is missing");t||(t={}),t.cache="no-store",t.mode="cors";const o=new Headers(t.headers??void 0);t.headers=o;const s=await fetch(e,t),i=s.headers.get("www-authenticate");return i&&i.trimStart().toLowerCase().startsWith("payment")?V(i,e,t,o,n):s},e.fetchWithX402=async(e,t,r)=>{const n=r.wallet;t||(t={}),t.cache="no-store",t.mode="cors";const o=new Headers(t.headers??void 0);t.headers=o;const s=await fetch(e,t),i=s.headers.get("PAYMENT-REQUIRED");return i?q(i,e,t,o,n):s},e.fromHexString=i,e.generateZapEvent=R,e.getEventHash=N,e.getFiatBtcRate=M,e.getFiatCurrencies=async()=>{const e=await fetch("https://getalby.com/api/rates");if(!e.ok)throw new Error(`Failed to fetch currencies: ${e.status} ${e.statusText}`);const t=await e.json();return Object.entries(t).filter(([e])=>"BTC"!==e.toUpperCase()).map(([e,t])=>({code:e.toUpperCase(),name:t.name,priority:t.priority,symbol:t.symbol})).sort((e,t)=>e.name.localeCompare(t.name)).sort((e,t)=>e.priority-t.priority)},e.getFiatValue=z,e.getFormattedFiatValue=async({satoshi:e,currency:t,locale:r})=>{r||(r="en");return(await z({satoshi:e,currency:t})).toLocaleString(r,{style:"currency",currency:t})},e.getSatoshiValue=async({amount:e,currency:t})=>{const r=await M(t);return Math.floor(Number(e)/r)},e.isUrl=W,e.isValidAmount=T,e.parseKeysendResponse=L,e.parseLnUrlPayResponse=P,e.parseNostrResponse=D,e.sendBoostagram=C,e.serializeEvent=I,e.validateEvent=_});
Object.defineProperty(e,"__esModule",{value:!0}),e.bytes=e.stringToBytes=e.str=e.bytesToString=e.hex=e.utf8=e.bech32m=e.bech32=e.base58check=e.base58xmr=e.base58xrp=e.base58flickr=e.base58=e.base64url=e.base64=e.base32crockford=e.base32hex=e.base32=e.base16=e.utils=e.assertNumber=void 0,e.assertNumber=t;const c=(e,t)=>t?c(t,e%t):e,h=(e,t)=>e+(t-c(e,t));function l(e,r,n,o){if(!Array.isArray(e))throw new Error("convertRadix2: data should be array");if(r<=0||r>32)throw new Error(`convertRadix2: wrong from=${r}`);if(n<=0||n>32)throw new Error(`convertRadix2: wrong to=${n}`);if(h(r,n)>32)throw new Error(`convertRadix2: carry overflow from=${r} to=${n} carryBits=${h(r,n)}`);let s=0,i=0;const a=2**n-1,c=[];for(const o of e){if(t(o),o>=2**r)throw new Error(`convertRadix2: invalid data word=${o} from=${r}`);if(s=s<<r|o,i+r>32)throw new Error(`convertRadix2: carry overflow pos=${i} from=${r}`);for(i+=r;i>=n;i-=n)c.push((s>>i-n&a)>>>0);s&=2**i-1}if(s=s<<n-i&a,!o&&i>=r)throw new Error("Excess padding");if(!o&&s)throw new Error(`Non-zero padding: ${s}`);return o&&i>0&&c.push(s>>>0),c}function u(e){return t(e),{encode:t=>{if(!(t instanceof Uint8Array))throw new Error("radix.encode input should be Uint8Array");return a(Array.from(t),256,e)},decode:t=>{if(!Array.isArray(t)||t.length&&"number"!=typeof t[0])throw new Error("radix.decode input should be array of strings");return Uint8Array.from(a(t,e,256))}}}function f(e,r=!1){if(t(e),e<=0||e>32)throw new Error("radix2: bits should be in (0..32]");if(h(8,e)>32||h(e,8)>32)throw new Error("radix2: carry overflow");return{encode:t=>{if(!(t instanceof Uint8Array))throw new Error("radix2.encode input should be Uint8Array");return l(Array.from(t),8,e,!r)},decode:t=>{if(!Array.isArray(t)||t.length&&"number"!=typeof t[0])throw new Error("radix2.decode input should be array of strings");return Uint8Array.from(l(t,e,8,r))}}}function d(e){if("function"!=typeof e)throw new Error("unsafeWrapper fn should be function");return function(...t){try{return e.apply(null,t)}catch(e){}}}function p(e,r){if(t(e),"function"!=typeof r)throw new Error("checksum fn should be function");return{encode(t){if(!(t instanceof Uint8Array))throw new Error("checksum.encode: input should be Uint8Array");const n=r(t).slice(0,e),o=new Uint8Array(t.length+e);return o.set(t),o.set(n,t.length),o},decode(t){if(!(t instanceof Uint8Array))throw new Error("checksum.decode: input should be Uint8Array");const n=t.slice(0,-e),o=r(n).slice(0,e),s=t.slice(-e);for(let t=0;t<e;t++)if(o[t]!==s[t])throw new Error("Invalid checksum");return n}}}e.utils={alphabet:n,chain:r,checksum:p,radix:u,radix2:f,join:o,padding:s},e.base16=r(f(4),n("0123456789ABCDEF"),o("")),e.base32=r(f(5),n("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"),s(5),o("")),e.base32hex=r(f(5),n("0123456789ABCDEFGHIJKLMNOPQRSTUV"),s(5),o("")),e.base32crockford=r(f(5),n("0123456789ABCDEFGHJKMNPQRSTVWXYZ"),o(""),i(e=>e.toUpperCase().replace(/O/g,"0").replace(/[IL]/g,"1"))),e.base64=r(f(6),n("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"),s(6),o("")),e.base64url=r(f(6),n("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"),s(6),o(""));const w=e=>r(u(58),n(e),o(""));e.base58=w("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"),e.base58flickr=w("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"),e.base58xrp=w("rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz");const m=[0,2,3,5,6,7,9,10,11];e.base58xmr={encode(t){let r="";for(let n=0;n<t.length;n+=8){const o=t.subarray(n,n+8);r+=e.base58.encode(o).padStart(m[o.length],"1")}return r},decode(t){let r=[];for(let n=0;n<t.length;n+=11){const o=t.slice(n,n+11),s=m.indexOf(o.length),i=e.base58.decode(o);for(let e=0;e<i.length-s;e++)if(0!==i[e])throw new Error("base58xmr: wrong padding");r=r.concat(Array.from(i.slice(i.length-s)))}return Uint8Array.from(r)}},e.base58check=t=>r(p(4,e=>t(t(e))),e.base58);const y=r(n("qpzry9x8gf2tvdw0s3jn54khce6mua7l"),o("")),g=[996825010,642813549,513874426,1027748829,705979059];function b(e){const t=e>>25;let r=(33554431&e)<<5;for(let e=0;e<g.length;e++)1==(t>>e&1)&&(r^=g[e]);return r}function E(e,t,r=1){const n=e.length;let o=1;for(let t=0;t<n;t++){const r=e.charCodeAt(t);if(r<33||r>126)throw new Error(`Invalid prefix (${e})`);o=b(o)^r>>5}o=b(o);for(let t=0;t<n;t++)o=b(o)^31&e.charCodeAt(t);for(let e of t)o=b(o)^e;for(let e=0;e<6;e++)o=b(o);return o^=r,y.encode(l([o%2**30],30,5,!1))}function v(e){const t="bech32"===e?1:734539939,r=f(5),n=r.decode,o=r.encode,s=d(n);function i(e,r=90){if("string"!=typeof e)throw new Error("bech32.decode input should be string, not "+typeof e);if(e.length<8||!1!==r&&e.length>r)throw new TypeError(`Wrong string length: ${e.length} (${e}). Expected (8..${r})`);const n=e.toLowerCase();if(e!==n&&e!==e.toUpperCase())throw new Error("String must be lowercase or uppercase");const o=(e=n).lastIndexOf("1");if(0===o||-1===o)throw new Error('Letter "1" must be present between prefix and data only');const s=e.slice(0,o),i=e.slice(o+1);if(i.length<6)throw new Error("Data must be at least 6 characters long");const a=y.decode(i).slice(0,-6),c=E(s,a,t);if(!i.endsWith(c))throw new Error(`Invalid checksum in ${e}: expected "${c}"`);return{prefix:s,words:a}}return{encode:function(e,r,n=90){if("string"!=typeof e)throw new Error("bech32.encode prefix should be string, not "+typeof e);if(!Array.isArray(r)||r.length&&"number"!=typeof r[0])throw new Error("bech32.encode words should be array of numbers, not "+typeof r);const o=e.length+7+r.length;if(!1!==n&&o>n)throw new TypeError(`Length ${o} exceeds limit ${n}`);return`${e=e.toLowerCase()}1${y.encode(r)}${E(e,r,t)}`},decode:i,decodeToBytes:function(e){const{prefix:t,words:r}=i(e,!1);return{prefix:t,words:r,bytes:n(r)}},decodeUnsafe:d(i),fromWords:n,fromWordsUnsafe:s,toWords:o}}e.bech32=v("bech32"),e.bech32m=v("bech32m"),e.utf8={encode:e=>(new TextDecoder).decode(e),decode:e=>(new TextEncoder).encode(e)},e.hex=r(f(4),n("0123456789abcdef"),o(""),i(e=>{if("string"!=typeof e||e.length%2)throw new TypeError(`hex.decode: expected string, got ${typeof e} with length ${e.length}`);return e.toLowerCase()}));const x={utf8:e.utf8,hex:e.hex,base16:e.base16,base32:e.base32,base64:e.base64,base64url:e.base64url,base58:e.base58,base58xmr:e.base58xmr},A=`Invalid encoding type. Available types: ${Object.keys(x).join(", ")}`;e.bytesToString=(e,t)=>{if("string"!=typeof e||!x.hasOwnProperty(e))throw new TypeError(A);if(!(t instanceof Uint8Array))throw new TypeError("bytesToString() expects Uint8Array");return x[e].encode(t)},e.str=e.bytesToString,e.stringToBytes=(e,t)=>{if(!x.hasOwnProperty(e))throw new TypeError(A);if("string"!=typeof t)throw new TypeError("stringToBytes() expects string");return x[e].decode(t)},e.bytes=e.stringToBytes}(x)),x),n={bech32:"bc",pubKeyHash:0,scriptHash:5,validWitnessVersions:[0]},o={bech32:"tb",pubKeyHash:111,scriptHash:196,validWitnessVersions:[0]},s={bech32:"tbs",pubKeyHash:111,scriptHash:196,validWitnessVersions:[0]},i={bech32:"bcrt",pubKeyHash:111,scriptHash:196,validWitnessVersions:[0]},a={bech32:"sb",pubKeyHash:63,scriptHash:123,validWitnessVersions:[0]},c=["option_data_loss_protect","initial_routing_sync","option_upfront_shutdown_script","gossip_queries","var_onion_optin","gossip_queries_ex","option_static_remotekey","payment_secret","basic_mpp","option_support_large_channel"],h={m:BigInt(1e3),u:BigInt(1e6),n:BigInt(1e9),p:BigInt(1e12)},l=BigInt("2100000000000000000"),u=BigInt(1e11),f={payment_hash:1,payment_secret:16,description:13,payee:19,description_hash:23,expiry:6,min_final_cltv_expiry:24,fallback_address:9,route_hint:3,feature_bits:5,metadata:27},d={};for(let e=0,t=Object.keys(f);e<t.length;e++){const r=t[e],n=f[t[e]].toString();d[n]=r}const p={1:r=>t.encode(e.fromWordsUnsafe(r)),16:r=>t.encode(e.fromWordsUnsafe(r)),13:t=>r.encode(e.fromWordsUnsafe(t)),19:r=>t.encode(e.fromWordsUnsafe(r)),23:r=>t.encode(e.fromWordsUnsafe(r)),27:r=>t.encode(e.fromWordsUnsafe(r)),6:m,24:m,3:function(r){const n=[];let o,s,i,a,c,h=e.fromWordsUnsafe(r);for(;h.length>0;)o=t.encode(h.slice(0,33)),s=t.encode(h.slice(33,41)),i=parseInt(t.encode(h.slice(41,45)),16),a=parseInt(t.encode(h.slice(45,49)),16),c=parseInt(t.encode(h.slice(49,51)),16),h=h.slice(51),n.push({pubkey:o,short_channel_id:s,fee_base_msat:i,fee_proportional_millionths:a,cltv_expiry_delta:c});return n},5:function(e){const t=e.slice().reverse().map(e=>[!!(1&e),!!(2&e),!!(4&e),!!(8&e),!!(16&e)]).reduce((e,t)=>e.concat(t),[]);for(;t.length<2*c.length;)t.push(!1);const r={};c.forEach((e,n)=>{let o;o=t[2*n]?"required":t[2*n+1]?"supported":"unsupported",r[e]=o});const n=t.slice(2*c.length);return r.extra_bits={start_bit:2*c.length,bits:n,has_required:n.reduce((e,t,r)=>r%2!=0?e||!1:e||t,!1)},r}};function w(t){return r=>({tagCode:parseInt(t),words:e.encode("unknown",r,Number.MAX_SAFE_INTEGER)})}function m(e){return e.reverse().reduce((e,t,r)=>e+t*Math.pow(32,r),0)}function y(e,t){let r,n;if(e.slice(-1).match(/^[munp]$/))r=e.slice(-1),n=e.slice(0,-1);else{if(e.slice(-1).match(/^[^munp0-9]$/))throw new Error("Not a valid multiplier for the amount");n=e}if(!n.match(/^\d+$/))throw new Error("Not a valid human readable amount");const o=BigInt(n),s=r?o*u/h[r]:o*u;if("p"===r&&o%BigInt(10)!==BigInt(0)||s>l)throw new Error("Amount is outside of valid range");return t?s.toString():s}return E={decode:function(r,c){if("string"!=typeof r)throw new Error("Lightning Payment Request must be string");if("ln"!==r.slice(0,2).toLowerCase())throw new Error("Not a proper lightning payment request");const h=[],l=e.decode(r,Number.MAX_SAFE_INTEGER);r=r.toLowerCase();const u=l.prefix;let g=l.words,b=r.slice(u.length+1),E=g.slice(-104);g=g.slice(0,-104);let v=u.match(/^ln(\S+?)(\d*)([a-zA-Z]?)$/);if(v&&!v[2]&&(v=u.match(/^ln(\S+)$/)),!v)throw new Error("Not a proper lightning payment request");h.push({name:"lightning_network",letters:"ln"});const x=v[1];let A;if(c){if(void 0===c.bech32||void 0===c.pubKeyHash||void 0===c.scriptHash||!Array.isArray(c.validWitnessVersions))throw new Error("Invalid network");A=c}else switch(x){case n.bech32:A=n;break;case o.bech32:A=o;break;case s.bech32:A=s;break;case i.bech32:A=i;break;case a.bech32:A=a}if(!A||A.bech32!==x)throw new Error("Unknown coin bech32 prefix");h.push({name:"coin_network",letters:x,value:A});const k=v[2];let $;if(k){$=y(k+v[3],!0),h.push({name:"amount",letters:v[2]+v[3],value:$})}else $=null;h.push({name:"separator",letters:"1"});const U=m(g.slice(0,7));let L,I,N,R;for(g=g.slice(7),h.push({name:"timestamp",letters:b.slice(0,7),value:U}),b=b.slice(7);g.length>0;){const e=g[0].toString();L=d[e]||"unknown_tag",I=p[e]||w(e),g=g.slice(1),N=m(g.slice(0,2)),g=g.slice(2),R=g.slice(0,N),g=g.slice(N),h.push({name:L,tag:b[0],letters:b.slice(0,3+N),value:I(R)}),b=b.slice(3+N)}h.push({name:"signature",letters:b.slice(0,104),value:t.encode(e.fromWordsUnsafe(E))}),b=b.slice(104),h.push({name:"checksum",letters:b});let _={paymentRequest:r,sections:h,get expiry(){let e=h.find(e=>"expiry"===e.name);if(e)return S("timestamp")+e.value},get route_hints(){return h.filter(e=>"route_hint"===e.name).map(e=>e.value)}};for(let e in f)"route_hint"!==e&&Object.defineProperty(_,e,{get:()=>S(e)});return _;function S(e){let t=h.find(t=>t.name===e);return t?t.value:void 0}},hrpToMillisat:y}}();const k=e=>Uint8Array.from(e.match(/.{1,2}/g).map(e=>parseInt(e,16))),$=e=>{if(!e)return null;try{const t=A.decode(e);if(!t||!t.sections)return null;const r=t.sections.find(e=>"payment_hash"===e.name);if("payment_hash"!==r?.name||!r.value)return null;const n=r.value;let o=0,s=0,i="0";const a=t.sections.find(e=>"amount"===e.name);"amount"===a?.name&&a.value&&(i=a.value,s=parseInt(a.value),o=parseInt(a.value)/1e3);const c=t.sections.find(e=>"timestamp"===e.name);if("timestamp"!==c?.name||!c.value)return null;const h=c.value;let l;const u=t.sections.find(e=>"expiry"===e.name);"expiry"===u?.name&&(l=u.value);const f=t.sections.find(e=>"description"===e.name);return{paymentHash:n,satoshi:o,millisatoshi:s,amountRaw:i,timestamp:h,expiry:l,description:"description"===f?.name?f?.value:void 0}}catch{return null}};function U(e,t){try{if(!/^[0-9a-fA-F]{64}$/.test(e))return!1;if(!/^[0-9a-fA-F]{64}$/.test(t))return!1;return t===a(g(k(e)))}catch{return!1}}class L{constructor(e){if(this.paymentRequest=e.pr,!this.paymentRequest)throw new Error("Invalid payment request");const t=$(this.paymentRequest);if(!t)throw new Error("Failed to decode payment request");this.paymentHash=t.paymentHash,this.satoshi=t.satoshi,this.millisatoshi=t.millisatoshi,this.amountRaw=t.amountRaw,this.timestamp=t.timestamp,this.expiry=t.expiry,this.createdDate=new Date(1e3*this.timestamp),this.expiryDate=this.expiry?new Date(1e3*(this.timestamp+this.expiry)):void 0,this.description=t.description??null,this.verify=e.verify??null,this.preimage=e.preimage??null,this.successAction=e.successAction??null}async isPaid(){if(this.preimage)return this.validatePreimage(this.preimage);if(this.verify)return await this.verifyPayment();throw new Error("Could not verify payment")}validatePreimage(e){return!(!e||!this.paymentHash)&&U(e,this.paymentHash)}async verifyPayment(){try{if(!this.verify)throw new Error("LNURL verify not available");const e=await fetch(this.verify);if(!e.ok)throw new Error(`Verification request failed: ${e.status} ${e.statusText}`);const t=await e.json();return t.preimage&&(this.preimage=t.preimage),t.settled}catch(e){return console.error("Failed to check LNURL-verify",e),!1}}hasExpired(){const{expiryDate:e}=this;return!!e&&e.getTime()<Date.now()}}const I=e=>{if("keysend"!==e.tag)throw new Error("Invalid keysend params");if("OK"!==e.status)throw new Error("Keysend status not OK");if(!e.pubkey)throw new Error("Pubkey does not exist");const t=e.pubkey;let r,n;return e.customData&&e.customData[0]&&(r=e.customData[0].customKey,n=e.customData[0].customValue),{destination:t,customKey:r,customValue:n}};async function N({satoshi:e,comment:t,p:r,e:n,relays:o},s={}){const i=s.nostr||globalThis.nostr;if(!i)throw new Error("nostr option or window.nostr is not available");const a=[["relays",...o],["amount",e.toString()]];r&&a.push(["p",r]),n&&a.push(["e",n]);const c={pubkey:await i.getPublicKey(),created_at:Math.floor(Date.now()/1e3),kind:9734,tags:a,content:t??""};return c.id=S(c),await i.signEvent(c)}function R(e){if("string"!=typeof e.content)return!1;if("number"!=typeof e.created_at)return!1;if(!Array.isArray(e.tags))return!1;for(let t=0;t<e.tags.length;t++){const r=e.tags[t];if(!Array.isArray(r))return!1;for(let e=0;e<r.length;e++)if("object"==typeof r[e])return!1}return!0}function _(e){if(!R(e))throw new Error("can't serialize event with wrong or missing properties");return JSON.stringify([0,e.pubkey,e.created_at,e.kind,e.tags,e.content])}function S(e){return a(g(_(e)))}function D(e,t){let r,n;return t&&e&&(r=e.names?.[t],n=r?e.relays?.[r]:void 0),[e,r,n]}const W=/((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/,T=e=>!!e&&W.test(e),P=({amount:e,min:t,max:r})=>e>0&&e>=t&&e<=r,H=async e=>{if("payRequest"!==e.tag)throw new Error("Invalid pay service params");const t=(e.callback+"").trim();if(!T(t))throw new Error("Callback must be a valid url");const r=Math.ceil(Number(e.minSendable||0)),n=Math.floor(Number(e.maxSendable));if(!r||!n||r>n)throw new Error("Invalid pay service params");let o,s;try{o=JSON.parse(e.metadata+""),s=a(g(e.metadata+""))}catch{o=[],s=a(g("[]"))}let i="",c="",h="",l="";for(let e=0;e<o.length;e++){const[t,r]=o[e];switch(t){case"text/plain":h=r;break;case"text/identifier":l=r;break;case"text/email":i=r;break;case"image/png;base64":case"image/jpeg;base64":c="data:"+t+","+r}}const u=e.payerData;let f;try{f=new URL(t).hostname}catch{}return{callback:t,fixed:r===n,min:r,max:n,domain:f,metadata:o,metadataHash:s,identifier:l,email:i,description:h,image:c,payerData:u,commentAllowed:Number(e.commentAllowed)||0,rawData:e,allowsNostr:e.allowsNostr||!1}},C=async(e,t)=>{const{boost:r}=e;t||(t={});const n=t.webln||globalThis.webln;if(!n)throw new Error("WebLN not available");if(!n.keysend)throw new Error("Keysend not available in current WebLN provider");const o=e.amount||Math.floor(r.value_msat/1e3),s={destination:e.destination,amount:o,customRecords:{7629169:JSON.stringify(r)}};e.customKey&&e.customValue&&(s.customRecords[e.customKey]=e.customValue),await n.enable();return await n.keysend(s)},B=/^((?:[^<>()[\]\\.,;:\s@"]+(?:\.[^<>()[\]\\.,;:\s@"]+)*)|(?:".+"))@((?:\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(?:(?:[a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,O="https://api.getalby.com/lnurl";function j(e,t){return{payInvoice:async r=>{const n=new L({pr:r.invoice});if(n.satoshi>t)throw new Error(`Invoice amount (${n.satoshi} sats) exceeds maxAmount (${t} sats)`);return e.payInvoice(r)}}}const q=e=>{const t=e.replace("L402","").replace("LSAT","").trim(),r={},n=/(\w+)=("([^"]*)"|'([^']*)'|([^,]*))/g;let o;for(;null!==(o=n.exec(t));)r[o[1]]=o[3]||o[4]||o[5];if(!r.token&&r.macaroon&&(r.token=r.macaroon,delete r.macaroon),!("token"in r)||"string"!=typeof r.token)throw new Error("No macaroon or token found in www-authenticate header");if(!("invoice"in r)||"string"!=typeof r.invoice)throw new Error("No invoice found in www-authenticate header");return r},F=async(e,t,r,n,o)=>{const s=q(e),i=s.token||s.macaroon,a=s.invoice;if(!i)throw new Error("L402: missing token/macaroon in WWW-Authenticate header");if(!a)throw new Error("L402: missing invoice in WWW-Authenticate header");const c=await o.payInvoice({invoice:a});return n.set("Authorization",`L402 ${i}:${c.preimage}`),fetch(t,r)},K=async(e,t,r,n,o)=>{let s;try{s=JSON.parse(decodeURIComponent(escape(atob(e))))}catch(e){throw new Error("x402: invalid PAYMENT-REQUIRED header (not valid base64-encoded JSON)")}if(!Array.isArray(s.accepts)||0===s.accepts.length)throw new Error("x402: PAYMENT-REQUIRED header contains no payment options");const i=s.accepts.find(e=>"lightning"===e.extra?.paymentMethod);if(!i)throw new Error("x402: unsupported x402 network, only Bitcoin lightning network is supported.");if(!i.extra?.invoice)throw new Error("x402: payment requirements missing lightning invoice");const a=new L({pr:i.extra.invoice});if(a.amountRaw!=i.amount)throw new Error(`Invalid invoice amount: ${a.amountRaw}. expected ${i.amount}`);return await o.payInvoice({invoice:a.paymentRequest}),n.set("payment-signature",((e,t,r,n)=>{const o=JSON.stringify({x402Version:2,scheme:e,network:t,payload:{invoice:r},accepted:n});return btoa(unescape(encodeURIComponent(o)))})(i.scheme,i.network,a.paymentRequest,i)),fetch(t,r)},M=e=>{if(null===e||"object"!=typeof e)return JSON.stringify(e);if(Array.isArray(e))return"["+e.map(M).join(",")+"]";return"{"+Object.keys(e).sort().map(t=>JSON.stringify(t)+":"+M(e[t])).join(",")+"}"},V=(e,t,r)=>{const n={id:e.id,intent:e.intent,method:e.method,realm:e.realm,request:e.request};e.expires&&(n.expires=e.expires);return(e=>{const t=(new TextEncoder).encode(e);let r="";for(let e=0;e<t.length;e++)r+=String.fromCharCode(t[e]);return btoa(r).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")})(M({challenge:n,payload:{preimage:t}}))},z=async(e,t,r,n,o)=>{const s=(e=>{if(!e.trimStart().toLowerCase().startsWith("payment"))return null;const t=e.slice(e.toLowerCase().indexOf("payment")+7).trim(),r={},n=/(\w+)=("([^"]*)"|'([^']*)'|([^,\s]*))/g;let o;for(;null!==(o=n.exec(t));)r[o[1]]=o[3]??o[4]??o[5]??"";return"lightning"===r.method&&"charge"===r.intent&&r.id&&r.realm&&r.request?{id:r.id,realm:r.realm,method:r.method,intent:r.intent,request:r.request,...r.expires?{expires:r.expires}:{}}:null})(e);if(!s)throw new Error("mpp: invalid or unsupported WWW-Authenticate challenge (expected Payment method=lightning intent=charge)");let i;try{i=JSON.parse((e=>{const t=e.replace(/-/g,"+").replace(/_/g,"/"),r=atob(t),n=new Uint8Array(r.length);for(let e=0;e<r.length;e++)n[e]=r.charCodeAt(e);return new TextDecoder("utf-8").decode(n)})(s.request))}catch(e){throw new Error("mpp: invalid request auth-param (not valid base64url-encoded JSON)")}const a=i.methodDetails?.invoice;if(!a)throw new Error("mpp: missing invoice in charge request");const c=await o.payInvoice({invoice:a}),h=V(s,c.preimage);return n.set("Authorization",`Payment ${h}`),fetch(t,r)};async function J(e,t){const{createHmac:r}=await import("crypto");return r("sha256",e).update(t).digest("hex")}const G=async e=>{const t="https://getalby.com/api/rates/"+e.toLowerCase()+".json",r=await fetch(t);if(!r.ok)throw new Error(`Failed to fetch rate: ${r.status} ${r.statusText}`);return(await r.json()).rate_float/1e8},Z=async({satoshi:e,currency:t})=>{const r=await G(t);return Number(e)*r};e.DEFAULT_PROXY=O,e.Invoice=L,e.LN_ADDRESS_REGEX=B,e.LightningAddress=class{constructor(e,t){this.address=e,this.options={proxy:O},this.options=Object.assign(this.options,t),this.parse(),this.webln=this.options.webln}parse(){const e=B.exec(this.address.toLowerCase());e&&(this.username=e[1],this.domain=e[2])}getWebLN(){return this.webln||globalThis.webln}async fetch(){return this.options.proxy?this.fetchWithProxy():this.fetchWithoutProxy()}async fetchWithProxy(){const e=await fetch(`${this.options.proxy}/lightning-address-details?${new URLSearchParams({ln:this.address}).toString()}`);if(!e.ok)throw new Error(`Failed to fetch lnurl info: ${e.status} ${e.statusText}`);const t=await e.json();await this.parseLnUrlPayResponse(t.lnurlp),this.parseKeysendResponse(t.keysend),this.parseNostrResponse(t.nostr)}async fetchWithoutProxy(){this.domain&&this.username&&await Promise.all([this.fetchLnurlData(),this.fetchKeysendData(),this.fetchNostrData()])}async fetchLnurlData(){const e=await fetch(this.lnurlpUrl());if(e.ok){const t=await e.json();await this.parseLnUrlPayResponse(t)}}async fetchKeysendData(){const e=await fetch(this.keysendUrl());if(e.ok){const t=await e.json();this.parseKeysendResponse(t)}}async fetchNostrData(){const e=await fetch(this.nostrUrl());if(e.ok){const t=await e.json();this.parseNostrResponse(t)}}lnurlpUrl(){return`https://${this.domain}/.well-known/lnurlp/${this.username}`}keysendUrl(){return`https://${this.domain}/.well-known/keysend/${this.username}`}nostrUrl(){return`https://${this.domain}/.well-known/nostr.json?name=${this.username}`}async generateInvoice(e){let t;if(this.options.proxy){const r=await fetch(`${this.options.proxy}/generate-invoice?${new URLSearchParams({ln:this.address,...e}).toString()}`);if(!r.ok)throw new Error(`Failed to generate invoice: ${r.status} ${r.statusText}`);t=(await r.json()).invoice}else{if(!this.lnurlpData)throw new Error("No lnurlpData available. Please call fetch() first.");if(!this.lnurlpData.callback||!T(this.lnurlpData.callback))throw new Error("Valid callback does not exist in lnurlpData");const r=new URL(this.lnurlpData.callback);r.search=new URLSearchParams(e).toString();const n=await fetch(r.toString());if(!n.ok)throw new Error(`Failed to generate invoice: ${n.status} ${n.statusText}`);t=await n.json()}const r=t&&t.pr&&t.pr.toString();if(!r)throw new Error("Invalid pay service invoice");const n={pr:r};if(t&&t.verify&&(n.verify=t.verify.toString()),t&&t.successAction&&"object"==typeof t.successAction){const{tag:e,message:r,description:o,url:s}=t.successAction;"message"===e?n.successAction={tag:e,message:r}:"url"===e&&(n.successAction={tag:e,description:o,url:s})}return new L(n)}async requestInvoice(e){if(!this.lnurlpData)throw new Error("No lnurlpData available. Please call fetch() first.");const t=1e3*e.satoshi,{commentAllowed:r,min:n,max:o}=this.lnurlpData;if(!P({amount:t,min:n,max:o}))throw new Error("Invalid amount");if(e.comment&&r&&r>0&&e.comment.length>r)throw new Error(`The comment length must be ${r} characters or fewer`);const s={amount:t.toString()};return e.comment&&(s.comment=e.comment),e.payerdata&&(s.payerdata=JSON.stringify(e.payerdata)),this.generateInvoice(s)}async boost(e,t=0){if(!this.keysendData)throw new Error("No keysendData available. Please call fetch() first.");const{destination:r,customKey:n,customValue:o}=this.keysendData,s=this.getWebLN();if(!s)throw new Error("WebLN not available");return C({destination:r,customKey:n,customValue:o,amount:t,boost:e},{webln:s})}async zapInvoice({satoshi:e,comment:t,relays:r,e:n},o={}){if(!this.lnurlpData)throw new Error("No lnurlpData available. Please call fetch() first.");if(!this.nostrPubkey)throw new Error("Nostr Pubkey is missing");const s=this.nostrPubkey,i=1e3*e,{allowsNostr:a,min:c,max:h}=this.lnurlpData;if(!P({amount:i,min:c,max:h}))throw new Error("Invalid amount");if(!a)throw new Error("Your provider does not support zaps");const l=await N({satoshi:i,comment:t,p:s,e:n,relays:r},o),u={amount:i.toString(),nostr:JSON.stringify(l)};return await this.generateInvoice(u)}async zap(e,t={}){const r=this.zapInvoice(e,t),n=this.getWebLN();if(!n)throw new Error("WebLN not available");await n.enable();return n.sendPayment((await r).paymentRequest)}async parseLnUrlPayResponse(e){e&&(this.lnurlpData=await H(e))}parseKeysendResponse(e){e&&(this.keysendData=I(e))}parseNostrResponse(e){e&&([this.nostrData,this.nostrPubkey,this.nostrRelays]=D(e,this.username))}},e.createGuardedWallet=j,e.decodeInvoice=$,e.fetch402=async(e,t,r)=>{const n=r.maxAmount?j(r.wallet,r.maxAmount):r.wallet;t||(t={}),t.cache="no-store",t.mode="cors";const o=new Headers(t.headers??void 0);t.headers=o;const s=await fetch(e,t),i=s.headers.get("www-authenticate");if(i){const r=i.trimStart().toLowerCase();if(r.startsWith("payment"))return z(i,e,t,o,n);if(r.startsWith("l402")||r.startsWith("lsat"))return F(i,e,t,o,n);throw new Error(`fetch402: unsupported WWW-Authenticate scheme: ${i}`)}const a=s.headers.get("PAYMENT-REQUIRED");return a?K(a,e,t,o,n):s},e.fetchWithL402=async(e,t,r)=>{const n=r.wallet;if(!n)throw new Error("wallet is missing");t||(t={}),t.cache="no-store",t.mode="cors";const o=new Headers(t.headers??void 0);t.headers=o;const s=await fetch(e,t),i=s.headers.get("www-authenticate");return i?F(i,e,t,o,n):s},e.fetchWithMpp=async(e,t,r)=>{const n=r.wallet;if(!n)throw new Error("wallet is missing");t||(t={}),t.cache="no-store",t.mode="cors";const o=new Headers(t.headers??void 0);t.headers=o;const s=await fetch(e,t),i=s.headers.get("www-authenticate");return i&&i.trimStart().toLowerCase().startsWith("payment")?z(i,e,t,o,n):s},e.fetchWithX402=async(e,t,r)=>{const n=r.wallet;t||(t={}),t.cache="no-store",t.mode="cors";const o=new Headers(t.headers??void 0);t.headers=o;const s=await fetch(e,t),i=s.headers.get("PAYMENT-REQUIRED");return i?K(i,e,t,o,n):s},e.fromHexString=k,e.generateZapEvent=N,e.getEventHash=S,e.getFiatBtcRate=G,e.getFiatCurrencies=async()=>{const e=await fetch("https://getalby.com/api/rates");if(!e.ok)throw new Error(`Failed to fetch currencies: ${e.status} ${e.statusText}`);const t=await e.json();return Object.entries(t).filter(([e])=>"BTC"!==e.toUpperCase()).map(([e,t])=>({code:e.toUpperCase(),name:t.name,priority:t.priority,symbol:t.symbol})).sort((e,t)=>e.name.localeCompare(t.name)).sort((e,t)=>e.priority-t.priority)},e.getFiatValue=Z,e.getFormattedFiatValue=async({satoshi:e,currency:t,locale:r})=>{r||(r="en");return(await Z({satoshi:e,currency:t})).toLocaleString(r,{style:"currency",currency:t})},e.getSatoshiValue=async({amount:e,currency:t})=>{const r=await G(t);return Math.floor(Number(e)/r)},e.isUrl=T,e.isValidAmount=P,e.issueL402Macaroon=async function(e,t,r){if(void 0!==r&&Object.prototype.hasOwnProperty.call(r,"paymentHash"))throw new Error("paymentHash is reserved");const n={...r,paymentHash:t},o=Buffer.from(JSON.stringify(n)).toString("base64url");return`${o}.${await J(e,o)}`},e.makeL402AuthenticateHeader=e=>{if(!e.token)throw new Error("token must be provided");return`L402 version="0" token="${e.token}", invoice="${e.invoice}"`},e.parseKeysendResponse=I,e.parseL402=q,e.parseL402Authorization=function(e){const t=e.replace(/^LSAT /,"L402 "),r="L402 ";if(!t.startsWith(r))return null;const n=t.slice(5),o=n.indexOf(":");if(-1===o)throw new Error("Invalid authorization header value");return{token:n.slice(0,o),preimage:n.slice(o+1)}},e.parseLnUrlPayResponse=H,e.parseNostrResponse=D,e.sendBoostagram=C,e.serializeEvent=_,e.validateEvent=R,e.validatePreimage=U,e.verifyL402Macaroon=async function(e,t){const{timingSafeEqual:r}=await import("crypto"),n=t.lastIndexOf(".");if(-1===n)throw new Error("Invalid macaroon token");const o=t.slice(0,n),s=t.slice(n+1),i=await J(e,o);try{if(!r(Buffer.from(s,"hex"),Buffer.from(i,"hex")))throw new Error("Invalid macaroon token")}catch(e){throw new Error("Invalid macaroon token")}try{const e=JSON.parse(Buffer.from(o,"base64url").toString("utf8"));if(null===e||"object"!=typeof e||Array.isArray(e)||"string"!=typeof e.paymentHash)throw new Error("Invalid macaroon payload");return e}catch{throw new Error("Invalid macaroon token")}}});
//# sourceMappingURL=lightning-tools.umd.js.map

@@ -19,2 +19,39 @@ interface Wallet {

interface WwwAuthenticatePayload {
token: string;
invoice: string;
[key: string]: string;
}
/**
* Client: parse "www-authenticate" header from server response
* @param input
* @returns details from the header value (token or macaroon, invoice)
*/
declare const parseL402: (input: string) => WwwAuthenticatePayload;
type MacaroonPayload<T> = T & {
paymentHash: string;
};
declare function issueL402Macaroon<T extends Record<string, unknown>>(secret: string, paymentHash: string, params?: T): Promise<string>;
declare function verifyL402Macaroon<T = unknown>(secret: string, token: string): Promise<MacaroonPayload<T>>;
/**
* Server: create a WWW-Authenticate header for a given macaroon and invoice
* @param args the macaroon/token and invoice generated for the client's request
* @returns the header value
*/
declare const makeL402AuthenticateHeader: (args: {
token?: string;
invoice: string;
}) => string;
/**
* Server: parse "authorization" header sent from client
* @param input value from authorization header
* @returns the macaroon and preimage
*/
declare function parseL402Authorization(input: string): {
token: string;
preimage: string;
} | null;
declare const fetchWithX402: (url: string, fetchArgs: RequestInit, options: {

@@ -41,3 +78,3 @@ wallet: Wallet;

export { createGuardedWallet, fetch402, fetchWithL402, fetchWithMpp, fetchWithX402 };
export type { Wallet };
export { createGuardedWallet, fetch402, fetchWithL402, fetchWithMpp, fetchWithX402, issueL402Macaroon, makeL402AuthenticateHeader, parseL402, parseL402Authorization, verifyL402Macaroon };
export type { MacaroonPayload, Wallet };

@@ -13,2 +13,40 @@ interface Wallet {

export { fetchWithL402 };
interface WwwAuthenticatePayload {
token: string;
invoice: string;
[key: string]: string;
}
/**
* Client: parse "www-authenticate" header from server response
* @param input
* @returns details from the header value (token or macaroon, invoice)
*/
declare const parseL402: (input: string) => WwwAuthenticatePayload;
type MacaroonPayload<T> = T & {
paymentHash: string;
};
declare function issueL402Macaroon<T extends Record<string, unknown>>(secret: string, paymentHash: string, params?: T): Promise<string>;
declare function verifyL402Macaroon<T = unknown>(secret: string, token: string): Promise<MacaroonPayload<T>>;
/**
* Server: create a WWW-Authenticate header for a given macaroon and invoice
* @param args the macaroon/token and invoice generated for the client's request
* @returns the header value
*/
declare const makeL402AuthenticateHeader: (args: {
token?: string;
invoice: string;
}) => string;
/**
* Server: parse "authorization" header sent from client
* @param input value from authorization header
* @returns the macaroon and preimage
*/
declare function parseL402Authorization(input: string): {
token: string;
preimage: string;
} | null;
export { fetchWithL402, issueL402Macaroon, makeL402AuthenticateHeader, parseL402, parseL402Authorization, verifyL402Macaroon };
export type { MacaroonPayload };

@@ -27,2 +27,3 @@ type InvoiceArgs = {

declare const decodeInvoice: (paymentRequest: string) => DecodedInvoice | null;
declare function validatePreimage(preimage: string, paymentHash: string): boolean;

@@ -50,3 +51,3 @@ declare class Invoice {

export { Invoice, decodeInvoice, fromHexString };
export { Invoice, decodeInvoice, fromHexString, validatePreimage };
export type { InvoiceArgs, SuccessAction };

@@ -30,2 +30,3 @@ import * as _webbtc_webln_types from '@webbtc/webln-types';

declare const decodeInvoice: (paymentRequest: string) => DecodedInvoice | null;
declare function validatePreimage(preimage: string, paymentHash: string): boolean;

@@ -261,2 +262,39 @@ declare class Invoice {

interface WwwAuthenticatePayload {
token: string;
invoice: string;
[key: string]: string;
}
/**
* Client: parse "www-authenticate" header from server response
* @param input
* @returns details from the header value (token or macaroon, invoice)
*/
declare const parseL402: (input: string) => WwwAuthenticatePayload;
type MacaroonPayload<T> = T & {
paymentHash: string;
};
declare function issueL402Macaroon<T extends Record<string, unknown>>(secret: string, paymentHash: string, params?: T): Promise<string>;
declare function verifyL402Macaroon<T = unknown>(secret: string, token: string): Promise<MacaroonPayload<T>>;
/**
* Server: create a WWW-Authenticate header for a given macaroon and invoice
* @param args the macaroon/token and invoice generated for the client's request
* @returns the header value
*/
declare const makeL402AuthenticateHeader: (args: {
token?: string;
invoice: string;
}) => string;
/**
* Server: parse "authorization" header sent from client
* @param input value from authorization header
* @returns the macaroon and preimage
*/
declare function parseL402Authorization(input: string): {
token: string;
preimage: string;
} | null;
declare const fetchWithX402: (url: string, fetchArgs: RequestInit, options: {

@@ -305,3 +343,3 @@ wallet: Wallet;

export { DEFAULT_PROXY, Invoice, LN_ADDRESS_REGEX, LightningAddress, createGuardedWallet, decodeInvoice, fetch402, fetchWithL402, fetchWithMpp, fetchWithX402, fromHexString, generateZapEvent, getEventHash, getFiatBtcRate, getFiatCurrencies, getFiatValue, getFormattedFiatValue, getSatoshiValue, isUrl, isValidAmount, parseKeysendResponse, parseLnUrlPayResponse, parseNostrResponse, sendBoostagram, serializeEvent, validateEvent };
export type { Boost, BoostArguments, BoostOptions, Event, FiatCurrency, InvoiceArgs, KeySendRawData, KeysendResponse, LUD18PayerData, LUD18ServicePayerData, LnUrlPayResponse, LnUrlRawData, NostrProvider, NostrResponse, RequestInvoiceArgs, SuccessAction, Wallet, WeblnBoostParams, ZapArgs, ZapOptions };
export { DEFAULT_PROXY, Invoice, LN_ADDRESS_REGEX, LightningAddress, createGuardedWallet, decodeInvoice, fetch402, fetchWithL402, fetchWithMpp, fetchWithX402, fromHexString, generateZapEvent, getEventHash, getFiatBtcRate, getFiatCurrencies, getFiatValue, getFormattedFiatValue, getSatoshiValue, isUrl, isValidAmount, issueL402Macaroon, makeL402AuthenticateHeader, parseKeysendResponse, parseL402, parseL402Authorization, parseLnUrlPayResponse, parseNostrResponse, sendBoostagram, serializeEvent, validateEvent, validatePreimage, verifyL402Macaroon };
export type { Boost, BoostArguments, BoostOptions, Event, FiatCurrency, InvoiceArgs, KeySendRawData, KeysendResponse, LUD18PayerData, LUD18ServicePayerData, LnUrlPayResponse, LnUrlRawData, MacaroonPayload, NostrProvider, NostrResponse, RequestInvoiceArgs, SuccessAction, Wallet, WeblnBoostParams, ZapArgs, ZapOptions };
{
"name": "@getalby/lightning-tools",
"version": "8.0.0",
"version": "8.1.0",
"description": "Collection of helpful building blocks and tools to develop Bitcoin Lightning web apps",

@@ -5,0 +5,0 @@ "type": "module",

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display