@getalby/lightning-tools 8.1.1 → 8.2.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 +78 -13
- package/dist/cjs/402/l402.cjs +1304 -2
- package/dist/cjs/402/l402.cjs.map +1 -1
- package/dist/cjs/402/mpp.cjs +1306 -5
- package/dist/cjs/402/mpp.cjs.map +1 -1
- package/dist/cjs/402/x402.cjs +46 -15
- package/dist/cjs/402/x402.cjs.map +1 -1
- package/dist/cjs/402.cjs +101 -10
- package/dist/cjs/402.cjs.map +1 -1
- package/dist/cjs/bip21.cjs +115 -0
- package/dist/cjs/bip21.cjs.map +1 -0
- package/dist/cjs/index.cjs +213 -10
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/402/l402.js +1304 -2
- package/dist/esm/402/l402.js.map +1 -1
- package/dist/esm/402/mpp.js +1306 -5
- package/dist/esm/402/mpp.js.map +1 -1
- package/dist/esm/402/x402.js +46 -15
- package/dist/esm/402/x402.js.map +1 -1
- package/dist/esm/402.js +98 -11
- package/dist/esm/402.js.map +1 -1
- package/dist/esm/bip21.js +112 -0
- package/dist/esm/bip21.js.map +1 -0
- package/dist/esm/index.js +208 -11
- package/dist/esm/index.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 +49 -3
- package/dist/types/402/mpp.d.ts +54 -6
- package/dist/types/402/x402.d.ts +49 -3
- package/dist/types/402.d.ts +68 -17
- package/dist/types/bip21.d.ts +46 -0
- package/dist/types/index.d.ts +112 -17
- package/package.json +6 -1
package/dist/esm/402.js
CHANGED
|
@@ -1257,6 +1257,28 @@ class Invoice {
|
|
|
1257
1257
|
}
|
|
1258
1258
|
}
|
|
1259
1259
|
|
|
1260
|
+
/** Apply a previously-obtained credential to the outgoing request headers. */
|
|
1261
|
+
const applyCredentials = (headers, credentials) => {
|
|
1262
|
+
headers.set(credentials.header, credentials.value);
|
|
1263
|
+
};
|
|
1264
|
+
/** Attach payment metadata to a response and return it (typed). */
|
|
1265
|
+
const attachPayment = (response, payment) => {
|
|
1266
|
+
if (payment) {
|
|
1267
|
+
response.payment = payment;
|
|
1268
|
+
}
|
|
1269
|
+
return response;
|
|
1270
|
+
};
|
|
1271
|
+
/** Payment metadata describing a request authorized with a reused credential. */
|
|
1272
|
+
const reusedCredentialPayment = (credentials) => credentials ? { paid: false, amount: 0, credentials } : undefined;
|
|
1273
|
+
/** Satoshi amount of a BOLT11 invoice (0 when it cannot be decoded). */
|
|
1274
|
+
const getInvoiceAmount = (invoice) => {
|
|
1275
|
+
try {
|
|
1276
|
+
return new Invoice({ pr: invoice }).satoshi;
|
|
1277
|
+
}
|
|
1278
|
+
catch (_) {
|
|
1279
|
+
return 0;
|
|
1280
|
+
}
|
|
1281
|
+
};
|
|
1260
1282
|
function createGuardedWallet(wallet, maxAmountSats) {
|
|
1261
1283
|
return {
|
|
1262
1284
|
payInvoice: async (args) => {
|
|
@@ -1308,6 +1330,9 @@ const handleL402Payment = async (l402Header, url, fetchArgs, headers, wallet) =>
|
|
|
1308
1330
|
const details = parseL402(l402Header);
|
|
1309
1331
|
const token = details.token || details.macaroon;
|
|
1310
1332
|
const invoice = details.invoice;
|
|
1333
|
+
// Preserve the scheme the server challenged with (L402 or LSAT) so the
|
|
1334
|
+
// retry's Authorization header matches what the server expects.
|
|
1335
|
+
const scheme = /^\s*LSAT\b/i.test(l402Header) ? "LSAT" : "L402";
|
|
1311
1336
|
if (!token) {
|
|
1312
1337
|
throw new Error("L402: missing token/macaroon in WWW-Authenticate header");
|
|
1313
1338
|
}
|
|
@@ -1315,8 +1340,16 @@ const handleL402Payment = async (l402Header, url, fetchArgs, headers, wallet) =>
|
|
|
1315
1340
|
throw new Error("L402: missing invoice in WWW-Authenticate header");
|
|
1316
1341
|
}
|
|
1317
1342
|
const invResp = await wallet.payInvoice({ invoice });
|
|
1318
|
-
|
|
1319
|
-
|
|
1343
|
+
const value = `${scheme} ${token}:${invResp.preimage}`;
|
|
1344
|
+
headers.set("Authorization", value);
|
|
1345
|
+
const response = await fetch(url, fetchArgs);
|
|
1346
|
+
return attachPayment(response, {
|
|
1347
|
+
paid: true,
|
|
1348
|
+
amount: getInvoiceAmount(invoice),
|
|
1349
|
+
feesPaid: invResp.fees_paid,
|
|
1350
|
+
preimage: invResp.preimage,
|
|
1351
|
+
credentials: { header: "Authorization", value },
|
|
1352
|
+
});
|
|
1320
1353
|
};
|
|
1321
1354
|
const fetchWithL402 = async (url, fetchArgs, options) => {
|
|
1322
1355
|
const wallet = options.wallet;
|
|
@@ -1330,6 +1363,15 @@ const fetchWithL402 = async (url, fetchArgs, options) => {
|
|
|
1330
1363
|
fetchArgs.mode = "cors";
|
|
1331
1364
|
const headers = new Headers(fetchArgs.headers ?? undefined);
|
|
1332
1365
|
fetchArgs.headers = headers;
|
|
1366
|
+
// If the caller supplied a credential, we MUST use it and never pay again —
|
|
1367
|
+
// even if the server still responds with a 402. Re-paying here is the exact
|
|
1368
|
+
// double-charge this API exists to prevent; the caller decides what to do
|
|
1369
|
+
// with a rejected credential (retry after settlement, top up, etc.).
|
|
1370
|
+
if (options.credentials) {
|
|
1371
|
+
applyCredentials(headers, options.credentials);
|
|
1372
|
+
const reusedResp = await fetch(url, fetchArgs);
|
|
1373
|
+
return attachPayment(reusedResp, reusedCredentialPayment(options.credentials));
|
|
1374
|
+
}
|
|
1333
1375
|
const initResp = await fetch(url, fetchArgs);
|
|
1334
1376
|
const header = initResp.headers.get("www-authenticate");
|
|
1335
1377
|
if (!header) {
|
|
@@ -1396,9 +1438,17 @@ const handleX402Payment = async (x402Header, url, fetchArgs, headers, wallet) =>
|
|
|
1396
1438
|
if (invoice.amountRaw != requirements.amount) {
|
|
1397
1439
|
throw new Error(`Invalid invoice amount: ${invoice.amountRaw}. expected ${requirements.amount}`);
|
|
1398
1440
|
}
|
|
1399
|
-
await wallet.payInvoice({ invoice: invoice.paymentRequest });
|
|
1400
|
-
|
|
1401
|
-
|
|
1441
|
+
const invResp = await wallet.payInvoice({ invoice: invoice.paymentRequest });
|
|
1442
|
+
const value = buildX402PaymentSignature(requirements.scheme, requirements.network, invoice.paymentRequest, requirements);
|
|
1443
|
+
headers.set("payment-signature", value);
|
|
1444
|
+
const response = await fetch(url, fetchArgs);
|
|
1445
|
+
return attachPayment(response, {
|
|
1446
|
+
paid: true,
|
|
1447
|
+
amount: invoice.satoshi,
|
|
1448
|
+
feesPaid: invResp.fees_paid,
|
|
1449
|
+
preimage: invResp.preimage,
|
|
1450
|
+
credentials: { header: "payment-signature", value },
|
|
1451
|
+
});
|
|
1402
1452
|
};
|
|
1403
1453
|
const fetchWithX402 = async (url, fetchArgs, options) => {
|
|
1404
1454
|
const wallet = options.wallet;
|
|
@@ -1409,6 +1459,15 @@ const fetchWithX402 = async (url, fetchArgs, options) => {
|
|
|
1409
1459
|
fetchArgs.mode = "cors";
|
|
1410
1460
|
const headers = new Headers(fetchArgs.headers ?? undefined);
|
|
1411
1461
|
fetchArgs.headers = headers;
|
|
1462
|
+
// If the caller supplied a credential, we MUST use it and never pay again —
|
|
1463
|
+
// even if the server still responds with a 402. Re-paying here is the exact
|
|
1464
|
+
// double-charge this API exists to prevent; the caller decides what to do
|
|
1465
|
+
// with a rejected credential (retry after settlement, top up, etc.).
|
|
1466
|
+
if (options.credentials) {
|
|
1467
|
+
applyCredentials(headers, options.credentials);
|
|
1468
|
+
const reusedResp = await fetch(url, fetchArgs);
|
|
1469
|
+
return attachPayment(reusedResp, reusedCredentialPayment(options.credentials));
|
|
1470
|
+
}
|
|
1412
1471
|
const initResp = await fetch(url, fetchArgs);
|
|
1413
1472
|
const header = initResp.headers.get("PAYMENT-REQUIRED");
|
|
1414
1473
|
if (!header) {
|
|
@@ -1555,8 +1614,16 @@ const handleMppChargePayment = async (wwwAuthHeader, url, fetchArgs, headers, wa
|
|
|
1555
1614
|
const invResp = await wallet.payInvoice({ invoice });
|
|
1556
1615
|
// Per spec: Authorization: Payment <base64url-token> (single token, no wrapper)
|
|
1557
1616
|
const credential = buildMppCredential(challenge, invResp.preimage);
|
|
1558
|
-
|
|
1559
|
-
|
|
1617
|
+
const value = `Payment ${credential}`;
|
|
1618
|
+
headers.set("Authorization", value);
|
|
1619
|
+
const response = await fetch(url, fetchArgs);
|
|
1620
|
+
return attachPayment(response, {
|
|
1621
|
+
paid: true,
|
|
1622
|
+
amount: getInvoiceAmount(invoice),
|
|
1623
|
+
feesPaid: invResp.fees_paid,
|
|
1624
|
+
preimage: invResp.preimage,
|
|
1625
|
+
credentials: { header: "Authorization", value },
|
|
1626
|
+
});
|
|
1560
1627
|
};
|
|
1561
1628
|
/**
|
|
1562
1629
|
* Fetch a resource protected by the draft-lightning-charge-00 payment
|
|
@@ -1567,9 +1634,11 @@ const handleMppChargePayment = async (wwwAuthHeader, url, fetchArgs, headers, wa
|
|
|
1567
1634
|
* the function pays the embedded BOLT11 invoice and retries with the
|
|
1568
1635
|
* resulting preimage as the credential.
|
|
1569
1636
|
*
|
|
1570
|
-
*
|
|
1571
|
-
*
|
|
1572
|
-
*
|
|
1637
|
+
* Pass a previous credential via `options.credentials` to reuse it (e.g. when
|
|
1638
|
+
* polling); the credential is applied and the function NEVER pays again, even
|
|
1639
|
+
* if the server still responds with a 402 (that response is returned as-is).
|
|
1640
|
+
* Note: lightning-charge typically uses consume-once challenge semantics, so a
|
|
1641
|
+
* reused credential is only accepted by servers that explicitly support it.
|
|
1573
1642
|
*/
|
|
1574
1643
|
const fetchWithMpp = async (url, fetchArgs, options) => {
|
|
1575
1644
|
const wallet = options.wallet;
|
|
@@ -1583,6 +1652,15 @@ const fetchWithMpp = async (url, fetchArgs, options) => {
|
|
|
1583
1652
|
fetchArgs.mode = "cors";
|
|
1584
1653
|
const headers = new Headers(fetchArgs.headers ?? undefined);
|
|
1585
1654
|
fetchArgs.headers = headers;
|
|
1655
|
+
// If the caller supplied a credential, we MUST use it and never pay again —
|
|
1656
|
+
// even if the server still responds with a 402. Re-paying here is the exact
|
|
1657
|
+
// double-charge this API exists to prevent; the caller decides what to do
|
|
1658
|
+
// with a rejected credential (retry after settlement, top up, etc.).
|
|
1659
|
+
if (options.credentials) {
|
|
1660
|
+
applyCredentials(headers, options.credentials);
|
|
1661
|
+
const reusedResp = await fetch(url, fetchArgs);
|
|
1662
|
+
return attachPayment(reusedResp, reusedCredentialPayment(options.credentials));
|
|
1663
|
+
}
|
|
1586
1664
|
const initResp = await fetch(url, fetchArgs);
|
|
1587
1665
|
const wwwAuthHeader = initResp.headers.get("www-authenticate");
|
|
1588
1666
|
if (!wwwAuthHeader ||
|
|
@@ -1603,6 +1681,15 @@ const fetch402 = async (url, fetchArgs, options) => {
|
|
|
1603
1681
|
fetchArgs.mode = "cors";
|
|
1604
1682
|
const headers = new Headers(fetchArgs.headers ?? undefined);
|
|
1605
1683
|
fetchArgs.headers = headers;
|
|
1684
|
+
// If the caller supplied a credential, we MUST use it and never pay again —
|
|
1685
|
+
// even if the server still responds with a 402. Re-paying here is the exact
|
|
1686
|
+
// double-charge this API exists to prevent; the caller decides what to do
|
|
1687
|
+
// with a rejected credential (retry after settlement, top up, etc.).
|
|
1688
|
+
if (options.credentials) {
|
|
1689
|
+
applyCredentials(headers, options.credentials);
|
|
1690
|
+
const reusedResp = await fetch(url, fetchArgs);
|
|
1691
|
+
return attachPayment(reusedResp, reusedCredentialPayment(options.credentials));
|
|
1692
|
+
}
|
|
1606
1693
|
const initResp = await fetch(url, fetchArgs);
|
|
1607
1694
|
// L402 / LSAT: dedicated scheme, dispatch directly.
|
|
1608
1695
|
const wwwAuthHeader = initResp.headers.get("www-authenticate");
|
|
@@ -1710,5 +1797,5 @@ function parseL402Authorization(input) {
|
|
|
1710
1797
|
};
|
|
1711
1798
|
}
|
|
1712
1799
|
|
|
1713
|
-
export { createGuardedWallet, fetch402, fetchWithL402, fetchWithMpp, fetchWithX402, findX402LightningRequirements, issueL402Macaroon, makeL402AuthenticateHeader, parseL402, parseL402Authorization, verifyL402Macaroon };
|
|
1800
|
+
export { applyCredentials, attachPayment, createGuardedWallet, fetch402, fetchWithL402, fetchWithMpp, fetchWithX402, findX402LightningRequirements, getInvoiceAmount, issueL402Macaroon, makeL402AuthenticateHeader, parseL402, parseL402Authorization, reusedCredentialPayment, verifyL402Macaroon };
|
|
1714
1801
|
//# sourceMappingURL=402.js.map
|