@getalby/lightning-tools 7.0.2 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -28
- package/dist/cjs/402/l402.cjs +55 -0
- package/dist/cjs/402/l402.cjs.map +1 -0
- package/dist/cjs/402/mpp.cjs +179 -0
- package/dist/cjs/402/mpp.cjs.map +1 -0
- package/dist/cjs/402/x402.cjs +1313 -0
- package/dist/cjs/402/x402.cjs.map +1 -0
- package/dist/cjs/402.cjs +1585 -0
- package/dist/cjs/402.cjs.map +1 -0
- package/dist/cjs/bolt11.cjs +8 -0
- package/dist/cjs/bolt11.cjs.map +1 -1
- package/dist/cjs/index.cjs +301 -53
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/lnurl.cjs +8 -0
- package/dist/cjs/lnurl.cjs.map +1 -1
- package/dist/esm/402/l402.js +53 -0
- package/dist/esm/402/l402.js.map +1 -0
- package/dist/esm/402/mpp.js +177 -0
- package/dist/esm/402/mpp.js.map +1 -0
- package/dist/esm/402/x402.js +1311 -0
- package/dist/esm/402/x402.js.map +1 -0
- package/dist/esm/402.js +1579 -0
- package/dist/esm/402.js.map +1 -0
- package/dist/esm/bolt11.js +8 -0
- package/dist/esm/bolt11.js.map +1 -1
- package/dist/esm/index.js +298 -50
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lnurl.js +8 -0
- package/dist/esm/lnurl.js.map +1 -1
- package/dist/lightning-tools.umd.js +2 -2
- package/dist/lightning-tools.umd.js.map +1 -1
- package/dist/types/402/l402.d.ts +13 -0
- package/dist/types/402/mpp.d.ts +26 -0
- package/dist/types/402/x402.d.ts +13 -0
- package/dist/types/402.d.ts +41 -0
- package/dist/types/bolt11.d.ts +4 -0
- package/dist/types/index.d.ts +38 -28
- package/dist/types/lnurl.d.ts +2 -0
- package/package.json +20 -5
- package/dist/cjs/l402.cjs +0 -93
- package/dist/cjs/l402.cjs.map +0 -1
- package/dist/esm/l402.js +0 -87
- package/dist/esm/l402.js.map +0 -1
- package/dist/types/l402.d.ts +0 -35
package/dist/cjs/index.cjs
CHANGED
|
@@ -834,8 +834,12 @@ const decodeInvoice = (paymentRequest) => {
|
|
|
834
834
|
return null;
|
|
835
835
|
const paymentHash = hashTag.value;
|
|
836
836
|
let satoshi = 0;
|
|
837
|
+
let millisatoshi = 0;
|
|
838
|
+
let amountRaw = "0";
|
|
837
839
|
const amountTag = decoded.sections.find((value) => value.name === "amount");
|
|
838
840
|
if (amountTag?.name === "amount" && amountTag.value) {
|
|
841
|
+
amountRaw = amountTag.value;
|
|
842
|
+
millisatoshi = parseInt(amountTag.value);
|
|
839
843
|
satoshi = parseInt(amountTag.value) / 1000; // millisats
|
|
840
844
|
}
|
|
841
845
|
const timestampTag = decoded.sections.find((value) => value.name === "timestamp");
|
|
@@ -854,6 +858,8 @@ const decodeInvoice = (paymentRequest) => {
|
|
|
854
858
|
return {
|
|
855
859
|
paymentHash,
|
|
856
860
|
satoshi,
|
|
861
|
+
millisatoshi,
|
|
862
|
+
amountRaw,
|
|
857
863
|
timestamp,
|
|
858
864
|
expiry,
|
|
859
865
|
description,
|
|
@@ -1183,6 +1189,8 @@ class Invoice {
|
|
|
1183
1189
|
}
|
|
1184
1190
|
this.paymentHash = decodedInvoice.paymentHash;
|
|
1185
1191
|
this.satoshi = decodedInvoice.satoshi;
|
|
1192
|
+
this.millisatoshi = decodedInvoice.millisatoshi;
|
|
1193
|
+
this.amountRaw = decodedInvoice.amountRaw;
|
|
1186
1194
|
this.timestamp = decodedInvoice.timestamp;
|
|
1187
1195
|
this.expiry = decodedInvoice.expiry;
|
|
1188
1196
|
this.createdDate = new Date(this.timestamp * 1000);
|
|
@@ -1659,24 +1667,18 @@ class LightningAddress {
|
|
|
1659
1667
|
}
|
|
1660
1668
|
}
|
|
1661
1669
|
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
}
|
|
1672
|
-
}
|
|
1673
|
-
class NoStorage {
|
|
1674
|
-
constructor(initial) { }
|
|
1675
|
-
getItem(key) {
|
|
1676
|
-
return null;
|
|
1677
|
-
}
|
|
1678
|
-
setItem(key, value) { }
|
|
1670
|
+
function createGuardedWallet(wallet, maxAmountSats) {
|
|
1671
|
+
return {
|
|
1672
|
+
payInvoice: async (args) => {
|
|
1673
|
+
const invoice = new Invoice({ pr: args.invoice });
|
|
1674
|
+
if (invoice.satoshi > maxAmountSats) {
|
|
1675
|
+
throw new Error(`Invoice amount (${invoice.satoshi} sats) exceeds maxAmount (${maxAmountSats} sats)`);
|
|
1676
|
+
}
|
|
1677
|
+
return wallet.payInvoice(args);
|
|
1678
|
+
},
|
|
1679
|
+
};
|
|
1679
1680
|
}
|
|
1681
|
+
|
|
1680
1682
|
const parseL402 = (input) => {
|
|
1681
1683
|
// Remove the L402 and LSAT identifiers
|
|
1682
1684
|
const string = input.replace("L402", "").replace("LSAT", "").trim();
|
|
@@ -1693,55 +1695,301 @@ const parseL402 = (input) => {
|
|
|
1693
1695
|
}
|
|
1694
1696
|
return keyValuePairs;
|
|
1695
1697
|
};
|
|
1696
|
-
const makeAuthenticateHeader = (args) => {
|
|
1697
|
-
const key = args.key || "L402";
|
|
1698
|
-
return `${key} macaroon="${args.macaroon}", invoice="${args.invoice}"`;
|
|
1699
|
-
};
|
|
1700
1698
|
|
|
1701
|
-
const
|
|
1702
|
-
const
|
|
1703
|
-
const
|
|
1704
|
-
|
|
1705
|
-
|
|
1699
|
+
const handleL402Payment = async (l402Header, url, fetchArgs, headers, wallet) => {
|
|
1700
|
+
const details = parseL402(l402Header);
|
|
1701
|
+
const token = details.token || details.macaroon;
|
|
1702
|
+
const invoice = details.invoice;
|
|
1703
|
+
if (!token) {
|
|
1704
|
+
throw new Error("L402: missing token/macaroon in WWW-Authenticate header");
|
|
1705
|
+
}
|
|
1706
|
+
if (!invoice) {
|
|
1707
|
+
throw new Error("L402: missing invoice in WWW-Authenticate header");
|
|
1706
1708
|
}
|
|
1707
|
-
const
|
|
1709
|
+
const invResp = await wallet.payInvoice({ invoice });
|
|
1710
|
+
headers.set("Authorization", `L402 ${token}:${invResp.preimage}`);
|
|
1711
|
+
return fetch(url, fetchArgs);
|
|
1712
|
+
};
|
|
1713
|
+
const fetchWithL402 = async (url, fetchArgs, options) => {
|
|
1708
1714
|
const wallet = options.wallet;
|
|
1709
1715
|
if (!wallet) {
|
|
1710
1716
|
throw new Error("wallet is missing");
|
|
1711
1717
|
}
|
|
1712
|
-
const store = options.store || memoryStorage;
|
|
1713
1718
|
if (!fetchArgs) {
|
|
1714
1719
|
fetchArgs = {};
|
|
1715
1720
|
}
|
|
1716
1721
|
fetchArgs.cache = "no-store";
|
|
1717
1722
|
fetchArgs.mode = "cors";
|
|
1718
|
-
|
|
1719
|
-
|
|
1723
|
+
const headers = new Headers(fetchArgs.headers ?? undefined);
|
|
1724
|
+
fetchArgs.headers = headers;
|
|
1725
|
+
const initResp = await fetch(url, fetchArgs);
|
|
1726
|
+
const header = initResp.headers.get("www-authenticate");
|
|
1727
|
+
if (!header) {
|
|
1728
|
+
return initResp;
|
|
1729
|
+
}
|
|
1730
|
+
return handleL402Payment(header, url, fetchArgs, headers, wallet);
|
|
1731
|
+
};
|
|
1732
|
+
|
|
1733
|
+
const buildX402PaymentSignature = (scheme, network, invoice, requirements) => {
|
|
1734
|
+
const json = JSON.stringify({
|
|
1735
|
+
x402Version: 2,
|
|
1736
|
+
scheme,
|
|
1737
|
+
network,
|
|
1738
|
+
payload: { invoice },
|
|
1739
|
+
accepted: requirements,
|
|
1740
|
+
});
|
|
1741
|
+
// btoa only handles latin1; encode via UTF-8 to be safe
|
|
1742
|
+
return btoa(unescape(encodeURIComponent(json)));
|
|
1743
|
+
};
|
|
1744
|
+
|
|
1745
|
+
const handleX402Payment = async (x402Header, url, fetchArgs, headers, wallet) => {
|
|
1746
|
+
let parsed;
|
|
1747
|
+
try {
|
|
1748
|
+
parsed = JSON.parse(decodeURIComponent(escape(atob(x402Header))));
|
|
1720
1749
|
}
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1750
|
+
catch (_) {
|
|
1751
|
+
throw new Error("x402: invalid PAYMENT-REQUIRED header (not valid base64-encoded JSON)");
|
|
1752
|
+
}
|
|
1753
|
+
if (!Array.isArray(parsed.accepts) || parsed.accepts.length === 0) {
|
|
1754
|
+
throw new Error("x402: PAYMENT-REQUIRED header contains no payment options");
|
|
1755
|
+
}
|
|
1756
|
+
const requirements = parsed.accepts.find((e) => {
|
|
1757
|
+
return e.extra?.paymentMethod === "lightning";
|
|
1758
|
+
});
|
|
1759
|
+
if (!requirements) {
|
|
1760
|
+
throw new Error("x402: unsupported x402 network, only Bitcoin lightning network is supported.");
|
|
1761
|
+
}
|
|
1762
|
+
if (!requirements.extra?.invoice) {
|
|
1763
|
+
throw new Error("x402: payment requirements missing lightning invoice");
|
|
1764
|
+
}
|
|
1765
|
+
const invoice = new Invoice({ pr: requirements.extra.invoice });
|
|
1766
|
+
if (invoice.amountRaw != requirements.amount) {
|
|
1767
|
+
throw new Error(`Invalid invoice amount: ${invoice.amountRaw}. expected ${requirements.amount}`);
|
|
1768
|
+
}
|
|
1769
|
+
await wallet.payInvoice({ invoice: invoice.paymentRequest });
|
|
1770
|
+
headers.set("payment-signature", buildX402PaymentSignature(requirements.scheme, requirements.network, invoice.paymentRequest, requirements));
|
|
1771
|
+
return fetch(url, fetchArgs);
|
|
1772
|
+
};
|
|
1773
|
+
const fetchWithX402 = async (url, fetchArgs, options) => {
|
|
1774
|
+
const wallet = options.wallet;
|
|
1775
|
+
if (!fetchArgs) {
|
|
1776
|
+
fetchArgs = {};
|
|
1727
1777
|
}
|
|
1728
|
-
fetchArgs.
|
|
1778
|
+
fetchArgs.cache = "no-store";
|
|
1779
|
+
fetchArgs.mode = "cors";
|
|
1780
|
+
const headers = new Headers(fetchArgs.headers ?? undefined);
|
|
1781
|
+
fetchArgs.headers = headers;
|
|
1729
1782
|
const initResp = await fetch(url, fetchArgs);
|
|
1730
|
-
const header = initResp.headers.get("
|
|
1783
|
+
const header = initResp.headers.get("PAYMENT-REQUIRED");
|
|
1731
1784
|
if (!header) {
|
|
1732
1785
|
return initResp;
|
|
1733
1786
|
}
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1787
|
+
return handleX402Payment(header, url, fetchArgs, headers, wallet);
|
|
1788
|
+
};
|
|
1789
|
+
|
|
1790
|
+
/**
|
|
1791
|
+
* Parse a `WWW-Authenticate: Payment …` header produced by a
|
|
1792
|
+
* draft-lightning-charge-00 server. Expected format:
|
|
1793
|
+
*
|
|
1794
|
+
* Payment id="<id>", realm="<realm>", method="lightning",
|
|
1795
|
+
* intent="charge", request="<base64url>" [, expires="<rfc3339>"]
|
|
1796
|
+
*
|
|
1797
|
+
* Returns null when the header is not a Payment lightning/charge challenge.
|
|
1798
|
+
*/
|
|
1799
|
+
const parseMppChallenge = (header) => {
|
|
1800
|
+
if (!header.trimStart().toLowerCase().startsWith("payment")) {
|
|
1801
|
+
return null;
|
|
1802
|
+
}
|
|
1803
|
+
const rest = header
|
|
1804
|
+
.slice(header.toLowerCase().indexOf("payment") + "payment".length)
|
|
1805
|
+
.trim();
|
|
1806
|
+
const result = {};
|
|
1807
|
+
const regex = /(\w+)=("([^"]*)"|'([^']*)'|([^,\s]*))/g;
|
|
1808
|
+
let match;
|
|
1809
|
+
while ((match = regex.exec(rest)) !== null) {
|
|
1810
|
+
result[match[1]] = match[3] ?? match[4] ?? match[5] ?? "";
|
|
1811
|
+
}
|
|
1812
|
+
if (result.method !== "lightning" ||
|
|
1813
|
+
result.intent !== "charge" ||
|
|
1814
|
+
!result.id ||
|
|
1815
|
+
!result.realm ||
|
|
1816
|
+
!result.request) {
|
|
1817
|
+
return null;
|
|
1818
|
+
}
|
|
1819
|
+
return {
|
|
1820
|
+
id: result.id,
|
|
1821
|
+
realm: result.realm,
|
|
1822
|
+
method: result.method,
|
|
1823
|
+
intent: result.intent,
|
|
1824
|
+
request: result.request,
|
|
1825
|
+
...(result.expires ? { expires: result.expires } : {}),
|
|
1826
|
+
};
|
|
1827
|
+
};
|
|
1828
|
+
/** Decode a base64url string (no padding required) to a UTF-8 string. */
|
|
1829
|
+
const decodeBase64url = (input) => {
|
|
1830
|
+
const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
1831
|
+
const binary = atob(base64);
|
|
1832
|
+
const bytes = new Uint8Array(binary.length);
|
|
1833
|
+
for (let i = 0; i < binary.length; i++) {
|
|
1834
|
+
bytes[i] = binary.charCodeAt(i);
|
|
1835
|
+
}
|
|
1836
|
+
return new TextDecoder("utf-8").decode(bytes);
|
|
1837
|
+
};
|
|
1838
|
+
/** Encode a UTF-8 string to base64url without padding. */
|
|
1839
|
+
const encodeBase64url = (input) => {
|
|
1840
|
+
const bytes = new TextEncoder().encode(input);
|
|
1841
|
+
let binary = "";
|
|
1842
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1843
|
+
binary += String.fromCharCode(bytes[i]);
|
|
1844
|
+
}
|
|
1845
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
1846
|
+
};
|
|
1847
|
+
/**
|
|
1848
|
+
* JSON Canonicalization Scheme (RFC 8785).
|
|
1849
|
+
* Produces compact JSON with object keys sorted lexicographically.
|
|
1850
|
+
*/
|
|
1851
|
+
const jcs = (value) => {
|
|
1852
|
+
if (value === null || typeof value !== "object") {
|
|
1853
|
+
return JSON.stringify(value);
|
|
1854
|
+
}
|
|
1855
|
+
if (Array.isArray(value)) {
|
|
1856
|
+
return "[" + value.map(jcs).join(",") + "]";
|
|
1857
|
+
}
|
|
1858
|
+
const keys = Object.keys(value).sort();
|
|
1859
|
+
return ("{" +
|
|
1860
|
+
keys
|
|
1861
|
+
.map((k) => JSON.stringify(k) + ":" + jcs(value[k]))
|
|
1862
|
+
.join(",") +
|
|
1863
|
+
"}");
|
|
1864
|
+
};
|
|
1865
|
+
/**
|
|
1866
|
+
* Build the base64url-encoded credential token for the `Authorization` header.
|
|
1867
|
+
*
|
|
1868
|
+
* Per the spec the credential is a JCS-serialised JSON object that echoes all
|
|
1869
|
+
* challenge auth-params (id, realm, method, intent, request, expires) and
|
|
1870
|
+
* carries the HTLC preimage that proves payment:
|
|
1871
|
+
*
|
|
1872
|
+
* {
|
|
1873
|
+
* "challenge": { "id": "…", "intent": "charge",
|
|
1874
|
+
* "method": "lightning", "realm": "…", "request": "…" },
|
|
1875
|
+
* "payload": { "preimage": "<64-char lowercase hex>" }
|
|
1876
|
+
* }
|
|
1877
|
+
*
|
|
1878
|
+
* Keys are sorted lexicographically at every level per JCS.
|
|
1879
|
+
*/
|
|
1880
|
+
const buildMppCredential = (challenge, preimage, source) => {
|
|
1881
|
+
const challengeEcho = {
|
|
1882
|
+
id: challenge.id,
|
|
1883
|
+
intent: challenge.intent,
|
|
1884
|
+
method: challenge.method,
|
|
1885
|
+
realm: challenge.realm,
|
|
1886
|
+
request: challenge.request,
|
|
1887
|
+
};
|
|
1888
|
+
if (challenge.expires) {
|
|
1889
|
+
challengeEcho.expires = challenge.expires;
|
|
1890
|
+
}
|
|
1891
|
+
const credential = {
|
|
1892
|
+
challenge: challengeEcho,
|
|
1893
|
+
payload: { preimage },
|
|
1894
|
+
};
|
|
1895
|
+
return encodeBase64url(jcs(credential));
|
|
1896
|
+
};
|
|
1897
|
+
|
|
1898
|
+
/**
|
|
1899
|
+
* Handle a `WWW-Authenticate: Payment …` challenge produced by a
|
|
1900
|
+
* draft-lightning-charge-00 server.
|
|
1901
|
+
*
|
|
1902
|
+
* Flow:
|
|
1903
|
+
* 1. Parse the challenge from the header.
|
|
1904
|
+
* 2. Decode the `request` auth-param to find the BOLT11 invoice.
|
|
1905
|
+
* 3. Pay the invoice via the wallet; receive the HTLC preimage.
|
|
1906
|
+
* 4. Build the `Authorization: Payment <credential>` header.
|
|
1907
|
+
* 5. Retry the original request with the credential.
|
|
1908
|
+
*/
|
|
1909
|
+
const handleMppChargePayment = async (wwwAuthHeader, url, fetchArgs, headers, wallet) => {
|
|
1910
|
+
const challenge = parseMppChallenge(wwwAuthHeader);
|
|
1911
|
+
if (!challenge) {
|
|
1912
|
+
throw new Error("mpp: invalid or unsupported WWW-Authenticate challenge (expected Payment method=lightning intent=charge)");
|
|
1913
|
+
}
|
|
1914
|
+
let request;
|
|
1915
|
+
try {
|
|
1916
|
+
request = JSON.parse(decodeBase64url(challenge.request));
|
|
1917
|
+
}
|
|
1918
|
+
catch (_) {
|
|
1919
|
+
throw new Error("mpp: invalid request auth-param (not valid base64url-encoded JSON)");
|
|
1920
|
+
}
|
|
1921
|
+
const invoice = request.methodDetails?.invoice;
|
|
1922
|
+
if (!invoice) {
|
|
1923
|
+
throw new Error("mpp: missing invoice in charge request");
|
|
1924
|
+
}
|
|
1925
|
+
const invResp = await wallet.payInvoice({ invoice });
|
|
1926
|
+
// Per spec: Authorization: Payment <base64url-token> (single token, no wrapper)
|
|
1927
|
+
const credential = buildMppCredential(challenge, invResp.preimage);
|
|
1928
|
+
headers.set("Authorization", `Payment ${credential}`);
|
|
1929
|
+
return fetch(url, fetchArgs);
|
|
1930
|
+
};
|
|
1931
|
+
/**
|
|
1932
|
+
* Fetch a resource protected by the draft-lightning-charge-00 payment
|
|
1933
|
+
* authentication protocol.
|
|
1934
|
+
*
|
|
1935
|
+
* On a `402 Payment Required` response that carries a
|
|
1936
|
+
* `WWW-Authenticate: Payment method="lightning" intent="charge" …` header
|
|
1937
|
+
* the function pays the embedded BOLT11 invoice and retries with the
|
|
1938
|
+
* resulting preimage as the credential.
|
|
1939
|
+
*
|
|
1940
|
+
* Note: lightning-charge uses consume-once challenge semantics – each
|
|
1941
|
+
* challenge embeds a fresh invoice, so paid credentials cannot be reused.
|
|
1942
|
+
* The `store` option is accepted for API consistency but is not used.
|
|
1943
|
+
*/
|
|
1944
|
+
const fetchWithMpp = async (url, fetchArgs, options) => {
|
|
1945
|
+
const wallet = options.wallet;
|
|
1946
|
+
if (!wallet) {
|
|
1947
|
+
throw new Error("wallet is missing");
|
|
1948
|
+
}
|
|
1949
|
+
if (!fetchArgs) {
|
|
1950
|
+
fetchArgs = {};
|
|
1951
|
+
}
|
|
1952
|
+
fetchArgs.cache = "no-store";
|
|
1953
|
+
fetchArgs.mode = "cors";
|
|
1954
|
+
const headers = new Headers(fetchArgs.headers ?? undefined);
|
|
1955
|
+
fetchArgs.headers = headers;
|
|
1956
|
+
const initResp = await fetch(url, fetchArgs);
|
|
1957
|
+
const wwwAuthHeader = initResp.headers.get("www-authenticate");
|
|
1958
|
+
if (!wwwAuthHeader ||
|
|
1959
|
+
!wwwAuthHeader.trimStart().toLowerCase().startsWith("payment")) {
|
|
1960
|
+
return initResp;
|
|
1961
|
+
}
|
|
1962
|
+
return handleMppChargePayment(wwwAuthHeader, url, fetchArgs, headers, wallet);
|
|
1963
|
+
};
|
|
1964
|
+
|
|
1965
|
+
const fetch402 = async (url, fetchArgs, options) => {
|
|
1966
|
+
const wallet = options.maxAmount
|
|
1967
|
+
? createGuardedWallet(options.wallet, options.maxAmount)
|
|
1968
|
+
: options.wallet;
|
|
1969
|
+
if (!fetchArgs) {
|
|
1970
|
+
fetchArgs = {};
|
|
1971
|
+
}
|
|
1972
|
+
fetchArgs.cache = "no-store";
|
|
1973
|
+
fetchArgs.mode = "cors";
|
|
1974
|
+
const headers = new Headers(fetchArgs.headers ?? undefined);
|
|
1975
|
+
fetchArgs.headers = headers;
|
|
1976
|
+
const initResp = await fetch(url, fetchArgs);
|
|
1977
|
+
const wwwAuthHeader = initResp.headers.get("www-authenticate");
|
|
1978
|
+
if (wwwAuthHeader) {
|
|
1979
|
+
const trimmed = wwwAuthHeader.trimStart().toLowerCase();
|
|
1980
|
+
if (trimmed.startsWith("payment")) {
|
|
1981
|
+
return handleMppChargePayment(wwwAuthHeader, url, fetchArgs, headers, wallet);
|
|
1982
|
+
}
|
|
1983
|
+
if (trimmed.startsWith("l402") || trimmed.startsWith("lsat")) {
|
|
1984
|
+
return handleL402Payment(wwwAuthHeader, url, fetchArgs, headers, wallet);
|
|
1985
|
+
}
|
|
1986
|
+
throw new Error(`fetch402: unsupported WWW-Authenticate scheme: ${wwwAuthHeader}`);
|
|
1987
|
+
}
|
|
1988
|
+
const x402Header = initResp.headers.get("PAYMENT-REQUIRED");
|
|
1989
|
+
if (x402Header) {
|
|
1990
|
+
return handleX402Payment(x402Header, url, fetchArgs, headers, wallet);
|
|
1991
|
+
}
|
|
1992
|
+
return initResp;
|
|
1745
1993
|
};
|
|
1746
1994
|
|
|
1747
1995
|
const numSatsInBtc = 100000000;
|
|
@@ -1797,10 +2045,12 @@ exports.DEFAULT_PROXY = DEFAULT_PROXY;
|
|
|
1797
2045
|
exports.Invoice = Invoice;
|
|
1798
2046
|
exports.LN_ADDRESS_REGEX = LN_ADDRESS_REGEX;
|
|
1799
2047
|
exports.LightningAddress = LightningAddress;
|
|
1800
|
-
exports.
|
|
1801
|
-
exports.NoStorage = NoStorage;
|
|
2048
|
+
exports.createGuardedWallet = createGuardedWallet;
|
|
1802
2049
|
exports.decodeInvoice = decodeInvoice;
|
|
2050
|
+
exports.fetch402 = fetch402;
|
|
1803
2051
|
exports.fetchWithL402 = fetchWithL402;
|
|
2052
|
+
exports.fetchWithMpp = fetchWithMpp;
|
|
2053
|
+
exports.fetchWithX402 = fetchWithX402;
|
|
1804
2054
|
exports.fromHexString = fromHexString;
|
|
1805
2055
|
exports.generateZapEvent = generateZapEvent;
|
|
1806
2056
|
exports.getEventHash = getEventHash;
|
|
@@ -1811,9 +2061,7 @@ exports.getFormattedFiatValue = getFormattedFiatValue;
|
|
|
1811
2061
|
exports.getSatoshiValue = getSatoshiValue;
|
|
1812
2062
|
exports.isUrl = isUrl;
|
|
1813
2063
|
exports.isValidAmount = isValidAmount;
|
|
1814
|
-
exports.makeAuthenticateHeader = makeAuthenticateHeader;
|
|
1815
2064
|
exports.parseKeysendResponse = parseKeysendResponse;
|
|
1816
|
-
exports.parseL402 = parseL402;
|
|
1817
2065
|
exports.parseLnUrlPayResponse = parseLnUrlPayResponse;
|
|
1818
2066
|
exports.parseNostrResponse = parseNostrResponse;
|
|
1819
2067
|
exports.sendBoostagram = sendBoostagram;
|