@piprail/sdk 2.13.1 → 2.14.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/CHANGELOG.md +70 -0
- package/dist/{algorand-TQCYK2XT.js → algorand-6J3IABVF.js} +12 -11
- package/dist/{algorand-AQK5EAUF.cjs → algorand-QU6G2DQZ.cjs} +43 -42
- package/dist/{aptos-RYQOSFBQ.js → aptos-DHOMTBLZ.js} +11 -10
- package/dist/{aptos-65UX7GKA.cjs → aptos-LFTQGBBK.cjs} +41 -40
- package/dist/{chunk-DCOUJZPL.cjs → chunk-GYM46G5L.cjs} +16 -0
- package/dist/{chunk-O32N6MFN.js → chunk-PAMKCWVW.js} +16 -0
- package/dist/index.cjs +484 -231
- package/dist/index.d.cts +270 -7
- package/dist/index.d.ts +270 -7
- package/dist/index.js +280 -27
- package/dist/{ledger-mF_SoiDB.d.ts → ledger-uFtXlIHY.d.cts} +31 -1
- package/dist/{ledger-mF_SoiDB.d.cts → ledger-uFtXlIHY.d.ts} +31 -1
- package/dist/{near-VDATC5AV.js → near-5PXTVQ47.js} +14 -5
- package/dist/{near-UDPFA6SV.cjs → near-YNNK7RW7.cjs} +39 -30
- package/dist/node.d.cts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/{solana-VYLWFNAH.js → solana-HITVI3HF.js} +22 -7
- package/dist/{solana-RQNXFCZO.cjs → solana-N3UCNCYE.cjs} +54 -39
- package/dist/{stellar-KBR4V77T.js → stellar-2QT6YYKN.js} +4 -4
- package/dist/{stellar-OK2HW5PZ.cjs → stellar-Y3SQN7S5.cjs} +23 -23
- package/dist/{sui-SVFBJFW5.cjs → sui-4AL4E6XU.cjs} +35 -27
- package/dist/{sui-BXHB6D3W.js → sui-FV5L6WF5.js} +20 -12
- package/dist/{ton-NNKQFQ6U.js → ton-5FWDQ4QR.js} +18 -7
- package/dist/{ton-D7YN6BGR.cjs → ton-5HDVOTMR.cjs} +33 -22
- package/dist/{tron-W2D5PQXV.js → tron-AZDY7BMQ.js} +10 -10
- package/dist/{tron-WZFU57NX.cjs → tron-TX2B4N2A.cjs} +39 -39
- package/dist/{xrpl-5NHY3NEL.cjs → xrpl-5TYDLQFS.cjs} +31 -31
- package/dist/{xrpl-37E23W53.js → xrpl-UJL5J7CY.js} +13 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
parseUnits,
|
|
32
32
|
rejectForeignToken,
|
|
33
33
|
toInsufficientFundsError
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-PAMKCWVW.js";
|
|
35
35
|
|
|
36
36
|
// src/drivers/registry.ts
|
|
37
37
|
var byFamily = /* @__PURE__ */ new Map();
|
|
@@ -1780,6 +1780,37 @@ function buildReceiptExtension(bundle) {
|
|
|
1780
1780
|
if (bundle.attestation) info.receipt = bundle.attestation;
|
|
1781
1781
|
return { [EXT_OFFER_RECEIPT]: { info } };
|
|
1782
1782
|
}
|
|
1783
|
+
var EXT_PAYMENT_IDENTIFIER = "payment-identifier";
|
|
1784
|
+
var PAYMENT_ID_MIN = 16;
|
|
1785
|
+
var PAYMENT_ID_MAX = 128;
|
|
1786
|
+
var PAYMENT_ID_RE = /^[A-Za-z0-9_-]+$/;
|
|
1787
|
+
function buildPaymentIdentifierAdvertisement() {
|
|
1788
|
+
return {
|
|
1789
|
+
[EXT_PAYMENT_IDENTIFIER]: {
|
|
1790
|
+
info: { required: false },
|
|
1791
|
+
schema: { properties: { id: { type: "string", minLength: PAYMENT_ID_MIN, maxLength: PAYMENT_ID_MAX } } }
|
|
1792
|
+
}
|
|
1793
|
+
};
|
|
1794
|
+
}
|
|
1795
|
+
function readPaymentIdentifier(payload) {
|
|
1796
|
+
if (typeof payload !== "object" || payload === null) return null;
|
|
1797
|
+
const ext = payload.extensions;
|
|
1798
|
+
if (typeof ext !== "object" || ext === null) return null;
|
|
1799
|
+
const block = ext[EXT_PAYMENT_IDENTIFIER];
|
|
1800
|
+
if (typeof block !== "object" || block === null) return null;
|
|
1801
|
+
const info = block.info;
|
|
1802
|
+
if (typeof info !== "object" || info === null) return null;
|
|
1803
|
+
const id = info.id;
|
|
1804
|
+
if (id === void 0) return null;
|
|
1805
|
+
if (typeof id !== "string") return { invalid: "payment-identifier id must be a string" };
|
|
1806
|
+
if (id.length < PAYMENT_ID_MIN || id.length > PAYMENT_ID_MAX) {
|
|
1807
|
+
return { invalid: `payment-identifier id must be ${PAYMENT_ID_MIN}\u2013${PAYMENT_ID_MAX} chars (got ${id.length})` };
|
|
1808
|
+
}
|
|
1809
|
+
if (!PAYMENT_ID_RE.test(id)) {
|
|
1810
|
+
return { invalid: "payment-identifier id must match [A-Za-z0-9_-]" };
|
|
1811
|
+
}
|
|
1812
|
+
return id;
|
|
1813
|
+
}
|
|
1783
1814
|
function buildSignatureHeader(signature) {
|
|
1784
1815
|
return toBase64Json(signature);
|
|
1785
1816
|
}
|
|
@@ -1806,7 +1837,10 @@ function parseReceipt(response) {
|
|
|
1806
1837
|
const headerValue = response.headers.get(HEADER_RESPONSE) ?? response.headers.get(HEADER_RESPONSE_V1);
|
|
1807
1838
|
if (!headerValue) return null;
|
|
1808
1839
|
const parsed = fromBase64Json(headerValue);
|
|
1809
|
-
|
|
1840
|
+
if (!isValidReceipt(parsed)) return null;
|
|
1841
|
+
const r = parsed;
|
|
1842
|
+
if (typeof r.transaction !== "string" && typeof r.txHash === "string") r.transaction = r.txHash;
|
|
1843
|
+
return r;
|
|
1810
1844
|
}
|
|
1811
1845
|
function parseReceiptExtension(response) {
|
|
1812
1846
|
const headerValue = response.headers.get(HEADER_RESPONSE) ?? response.headers.get(HEADER_RESPONSE_V1);
|
|
@@ -1836,7 +1870,8 @@ function parseSettleResponse(response) {
|
|
|
1836
1870
|
if (!parsed || typeof parsed !== "object" || typeof parsed.success !== "boolean") return null;
|
|
1837
1871
|
return {
|
|
1838
1872
|
success: parsed.success,
|
|
1839
|
-
|
|
1873
|
+
// Tolerate the legacy v1 `txHash` alias for `transaction` (mirrors isValidReceipt/parseReceipt).
|
|
1874
|
+
...typeof parsed.transaction === "string" ? { transaction: parsed.transaction } : typeof parsed.txHash === "string" ? { transaction: parsed.txHash } : {},
|
|
1840
1875
|
...typeof parsed.network === "string" ? { network: parsed.network } : {},
|
|
1841
1876
|
...typeof parsed.payer === "string" ? { payer: parsed.payer } : {},
|
|
1842
1877
|
...typeof parsed.errorReason === "string" ? { errorReason: parsed.errorReason } : {},
|
|
@@ -1855,6 +1890,14 @@ function parseSignatureObject(parsed) {
|
|
|
1855
1890
|
if (!payload || typeof payload.txHash !== "string" || typeof payload.nonce !== "string") {
|
|
1856
1891
|
return null;
|
|
1857
1892
|
}
|
|
1893
|
+
if (!accepted) {
|
|
1894
|
+
const synthesized = {
|
|
1895
|
+
scheme: "onchain-proof",
|
|
1896
|
+
...typeof v.network === "string" ? { network: v.network } : {},
|
|
1897
|
+
...typeof v.asset === "string" ? { asset: v.asset } : {}
|
|
1898
|
+
};
|
|
1899
|
+
return { ...v, accepted: synthesized, payload };
|
|
1900
|
+
}
|
|
1858
1901
|
return parsed;
|
|
1859
1902
|
}
|
|
1860
1903
|
function parseSignatureHeader(value) {
|
|
@@ -1994,7 +2037,11 @@ var evmDriver = {
|
|
|
1994
2037
|
resolve(opts) {
|
|
1995
2038
|
if (typeof opts.chain === "string" && /^(solana|ton|stellar)/.test(opts.chain)) return null;
|
|
1996
2039
|
if (typeof opts.chain === "string") {
|
|
1997
|
-
|
|
2040
|
+
try {
|
|
2041
|
+
return makeEvmNetwork(resolveChain(opts.chain, opts.rpcUrl));
|
|
2042
|
+
} catch (err) {
|
|
2043
|
+
throw new UnsupportedNetworkError(err instanceof Error ? err.message : String(err), { cause: err });
|
|
2044
|
+
}
|
|
1998
2045
|
}
|
|
1999
2046
|
let resolved;
|
|
2000
2047
|
try {
|
|
@@ -2039,8 +2086,13 @@ function makeEvmNetwork(resolved) {
|
|
|
2039
2086
|
`chain ${network} is EVM; a custom token must be { address, decimals }.`
|
|
2040
2087
|
);
|
|
2041
2088
|
}
|
|
2089
|
+
if (!isAddress(token.address)) {
|
|
2090
|
+
throw new WrongFamilyError(
|
|
2091
|
+
`chain ${network} is EVM, but token address "${token.address}" is not a valid 0x address.`
|
|
2092
|
+
);
|
|
2093
|
+
}
|
|
2042
2094
|
return {
|
|
2043
|
-
asset: token.address,
|
|
2095
|
+
asset: getAddress5(token.address),
|
|
2044
2096
|
decimals: token.decimals,
|
|
2045
2097
|
...token.symbol ? { symbol: token.symbol } : {}
|
|
2046
2098
|
};
|
|
@@ -2121,9 +2173,9 @@ function makeEvmNetwork(resolved) {
|
|
|
2121
2173
|
},
|
|
2122
2174
|
async estimateCost(accept) {
|
|
2123
2175
|
const { decimals, symbol } = resolved.chain.nativeCurrency;
|
|
2124
|
-
if (accept.scheme === "exact") {
|
|
2125
|
-
const m = accept.extra
|
|
2126
|
-
const permit2 = m === "permit2" || m === "permit2-exact";
|
|
2176
|
+
if (accept.scheme === "exact" || accept.scheme === "upto") {
|
|
2177
|
+
const m = accept.extra?.assetTransferMethod;
|
|
2178
|
+
const permit2 = m === "permit2" || m === "permit2-exact" || m === "permit2-upto";
|
|
2127
2179
|
return nativeCost({
|
|
2128
2180
|
symbol,
|
|
2129
2181
|
decimals,
|
|
@@ -2329,7 +2381,7 @@ var loaders = {
|
|
|
2329
2381
|
solana: async () => {
|
|
2330
2382
|
let mod;
|
|
2331
2383
|
try {
|
|
2332
|
-
mod = await import("./solana-
|
|
2384
|
+
mod = await import("./solana-HITVI3HF.js");
|
|
2333
2385
|
} catch (cause) {
|
|
2334
2386
|
throw new MissingDriverError(
|
|
2335
2387
|
`Solana selected, but its packages aren't installed. Run: npm install @solana/web3.js @solana/spl-token bs58`,
|
|
@@ -2341,7 +2393,7 @@ var loaders = {
|
|
|
2341
2393
|
ton: async () => {
|
|
2342
2394
|
let mod;
|
|
2343
2395
|
try {
|
|
2344
|
-
mod = await import("./ton-
|
|
2396
|
+
mod = await import("./ton-5FWDQ4QR.js");
|
|
2345
2397
|
} catch (cause) {
|
|
2346
2398
|
throw new MissingDriverError(
|
|
2347
2399
|
`TON selected, but its packages aren't installed. Run: npm install @ton/ton @ton/core @ton/crypto`,
|
|
@@ -2353,7 +2405,7 @@ var loaders = {
|
|
|
2353
2405
|
stellar: async () => {
|
|
2354
2406
|
let mod;
|
|
2355
2407
|
try {
|
|
2356
|
-
mod = await import("./stellar-
|
|
2408
|
+
mod = await import("./stellar-2QT6YYKN.js");
|
|
2357
2409
|
} catch (cause) {
|
|
2358
2410
|
throw new MissingDriverError(
|
|
2359
2411
|
`Stellar selected, but its package isn't installed. Run: npm install @stellar/stellar-sdk`,
|
|
@@ -2365,7 +2417,7 @@ var loaders = {
|
|
|
2365
2417
|
xrpl: async () => {
|
|
2366
2418
|
let mod;
|
|
2367
2419
|
try {
|
|
2368
|
-
mod = await import("./xrpl-
|
|
2420
|
+
mod = await import("./xrpl-UJL5J7CY.js");
|
|
2369
2421
|
} catch (cause) {
|
|
2370
2422
|
throw new MissingDriverError(
|
|
2371
2423
|
`XRPL selected, but its package isn't installed. Run: npm install xrpl`,
|
|
@@ -2377,7 +2429,7 @@ var loaders = {
|
|
|
2377
2429
|
tron: async () => {
|
|
2378
2430
|
let mod;
|
|
2379
2431
|
try {
|
|
2380
|
-
mod = await import("./tron-
|
|
2432
|
+
mod = await import("./tron-AZDY7BMQ.js");
|
|
2381
2433
|
} catch (cause) {
|
|
2382
2434
|
throw new MissingDriverError(
|
|
2383
2435
|
`Tron selected, but its package isn't installed. Run: npm install tronweb`,
|
|
@@ -2389,7 +2441,7 @@ var loaders = {
|
|
|
2389
2441
|
sui: async () => {
|
|
2390
2442
|
let mod;
|
|
2391
2443
|
try {
|
|
2392
|
-
mod = await import("./sui-
|
|
2444
|
+
mod = await import("./sui-FV5L6WF5.js");
|
|
2393
2445
|
} catch (cause) {
|
|
2394
2446
|
throw new MissingDriverError(
|
|
2395
2447
|
`Sui selected, but its package isn't installed. Run: npm install @mysten/sui`,
|
|
@@ -2401,7 +2453,7 @@ var loaders = {
|
|
|
2401
2453
|
near: async () => {
|
|
2402
2454
|
let mod;
|
|
2403
2455
|
try {
|
|
2404
|
-
mod = await import("./near-
|
|
2456
|
+
mod = await import("./near-5PXTVQ47.js");
|
|
2405
2457
|
} catch (cause) {
|
|
2406
2458
|
throw new MissingDriverError(
|
|
2407
2459
|
`NEAR selected, but its package isn't installed. Run: npm install near-api-js`,
|
|
@@ -2413,7 +2465,7 @@ var loaders = {
|
|
|
2413
2465
|
aptos: async () => {
|
|
2414
2466
|
let mod;
|
|
2415
2467
|
try {
|
|
2416
|
-
mod = await import("./aptos-
|
|
2468
|
+
mod = await import("./aptos-DHOMTBLZ.js");
|
|
2417
2469
|
} catch (cause) {
|
|
2418
2470
|
throw new MissingDriverError(
|
|
2419
2471
|
`Aptos selected, but its package isn't installed. Run: npm install @aptos-labs/ts-sdk`,
|
|
@@ -2425,7 +2477,7 @@ var loaders = {
|
|
|
2425
2477
|
algorand: async () => {
|
|
2426
2478
|
let mod;
|
|
2427
2479
|
try {
|
|
2428
|
-
mod = await import("./algorand-
|
|
2480
|
+
mod = await import("./algorand-6J3IABVF.js");
|
|
2429
2481
|
} catch (cause) {
|
|
2430
2482
|
throw new MissingDriverError(
|
|
2431
2483
|
`Algorand selected, but its package isn't installed. Run: npm install algosdk`,
|
|
@@ -4032,7 +4084,8 @@ var PipRailClient = class {
|
|
|
4032
4084
|
* before publishing, so retry with a brief backoff if a fresh listing is missing.
|
|
4033
4085
|
* - Results are cross-scheme (mostly the mainstream `exact` scheme); `fetch()` pays
|
|
4034
4086
|
* `onchain-proof` rails by default, and standard `exact` rails too once you opt in
|
|
4035
|
-
* with `schemes: ['onchain-proof', 'exact']` (EVM EIP-3009/Permit2 + Solana SVM + Algorand
|
|
4087
|
+
* with `schemes: ['onchain-proof', 'exact']` (EVM EIP-3009/Permit2 + Solana SVM + Algorand
|
|
4088
|
+
* + Aptos + NEAR).
|
|
4036
4089
|
*/
|
|
4037
4090
|
async discover(opts = {}) {
|
|
4038
4091
|
const found = await searchOpenIndexes({
|
|
@@ -4240,7 +4293,7 @@ var PipRailClient = class {
|
|
|
4240
4293
|
);
|
|
4241
4294
|
if (schemes.includes("exact") && exactOnNet && typeof net.payExact !== "function") {
|
|
4242
4295
|
throw new UnsupportedSchemeError(
|
|
4243
|
-
`This 402 offers a standard 'exact' rail on ${net.network}, but the ${net.family} family can't pay 'exact' (supported on EVM, Solana, Algorand + NEAR today), and no 'onchain-proof' rail was offered.`
|
|
4296
|
+
`This 402 offers a standard 'exact' rail on ${net.network}, but the ${net.family} family can't pay 'exact' (supported on EVM, Solana, Algorand, Aptos + NEAR today), and no 'onchain-proof' rail was offered.`
|
|
4244
4297
|
);
|
|
4245
4298
|
}
|
|
4246
4299
|
if (!schemes.includes("exact") && exactOnNet && typeof net.payExact === "function") {
|
|
@@ -4293,7 +4346,15 @@ var PipRailClient = class {
|
|
|
4293
4346
|
if (schemes.includes("exact")) {
|
|
4294
4347
|
out.push(
|
|
4295
4348
|
...challenge.accepts.filter(
|
|
4296
|
-
(a) => a.scheme === "exact" && this.supportsNetwork(net, a.network) && typeof net.payExact === "function" &&
|
|
4349
|
+
(a) => a.scheme === "exact" && this.supportsNetwork(net, a.network) && typeof net.payExact === "function" && // `native` is never `exact`-payable on ANY family (exact = an EIP-3009/Permit2-style
|
|
4350
|
+
// signed-authorization scheme a native coin can't support; every driver's payExact
|
|
4351
|
+
// throws/returns-null for it). describeAsset('native') IS non-null (onchain-proof needs
|
|
4352
|
+
// it), so without this guard a malformed 402 advertising a native `exact` rail would be
|
|
4353
|
+
// gathered, planned `payable`, even chosen by autoRoute — then throw at pay time.
|
|
4354
|
+
a.asset !== "native" && // the exact pay path (payExact → driver) reads `extra.assetTransferMethod`; a malformed
|
|
4355
|
+
// 402 offering an exact rail for a RECOGNISED token but omitting `extra` would otherwise
|
|
4356
|
+
// be planned payable then throw a raw TypeError mid-pay. Require it at gather time.
|
|
4357
|
+
typeof a.extra?.assetTransferMethod === "string" && net.describeAsset(a.asset) != null && // a foreign rail's maxTimeoutSeconds must be a usable positive integer, or
|
|
4297
4358
|
// signing it would build a NaN/garbage validBefore — drop it silently
|
|
4298
4359
|
// (symmetric with an unrecognised token) rather than leak a raw SyntaxError.
|
|
4299
4360
|
Number.isInteger(a.maxTimeoutSeconds) && a.maxTimeoutSeconds > 0
|
|
@@ -4303,7 +4364,8 @@ var PipRailClient = class {
|
|
|
4303
4364
|
if (schemes.includes("upto")) {
|
|
4304
4365
|
out.push(
|
|
4305
4366
|
...challenge.accepts.filter(
|
|
4306
|
-
(a) => a.scheme === "upto" && this.supportsNetwork(net, a.network) && typeof net.payUpto === "function" &&
|
|
4367
|
+
(a) => a.scheme === "upto" && this.supportsNetwork(net, a.network) && typeof net.payUpto === "function" && a.asset !== "native" && // native is not upto-payable either (same reason as exact)
|
|
4368
|
+
net.describeAsset(a.asset) != null && typeof a.extra?.facilitatorAddress === "string" && a.extra.facilitatorAddress.length > 0 && Number.isInteger(a.maxTimeoutSeconds) && a.maxTimeoutSeconds > 0
|
|
4307
4369
|
)
|
|
4308
4370
|
);
|
|
4309
4371
|
}
|
|
@@ -5517,8 +5579,8 @@ A 402 may offer up to three rails; you don't choose per payment \u2014 the clien
|
|
|
5517
5579
|
(the native coin \u2014 ETH/SOL/\u2026). Works on every chain.
|
|
5518
5580
|
- exact (the ratified x402 rail, opt-in): you only SIGN; the server \u2014 or a facilitator it chose
|
|
5519
5581
|
(e.g. PayAI) \u2014 broadcasts it, so you pay ZERO gas (you need only the token, no native coin). It
|
|
5520
|
-
works on EVM, Solana +
|
|
5521
|
-
fee-pooled group) is picked automatically.
|
|
5582
|
+
works on EVM, Solana, Algorand, Aptos + NEAR, and the on-chain method (EIP-3009 / Permit2 / SVM /
|
|
5583
|
+
Algorand fee-pooled group / Aptos fee-payer / NEAR SignedDelegateAction) is picked automatically.
|
|
5522
5584
|
- upto (the metered/variable x402 rail, opt-in, EVM): the amount you see is a MAXIMUM \u2014 you sign
|
|
5523
5585
|
a ceiling, the server meters real usage and settles the ACTUAL (<= the max). BUDGET AGAINST THE MAX:
|
|
5524
5586
|
the plan/policy treat the ceiling as the spend (a server may charge up to it), so a payable plan
|
|
@@ -6063,6 +6125,23 @@ function buildWellKnownX402(input) {
|
|
|
6063
6125
|
...input.ownershipProofs && input.ownershipProofs.length > 0 ? { ownershipProofs: input.ownershipProofs } : {}
|
|
6064
6126
|
};
|
|
6065
6127
|
}
|
|
6128
|
+
function buildWellKnownX402Manifest(input) {
|
|
6129
|
+
return {
|
|
6130
|
+
x402Version: 2,
|
|
6131
|
+
lastUpdated: input.lastUpdated ?? Math.floor(Date.now() / 1e3),
|
|
6132
|
+
items: input.resources.map((r) => ({
|
|
6133
|
+
resource: {
|
|
6134
|
+
url: r.url,
|
|
6135
|
+
...r.description ? { description: r.description } : {},
|
|
6136
|
+
...r.mimeType ? { mimeType: r.mimeType } : {}
|
|
6137
|
+
},
|
|
6138
|
+
type: "http",
|
|
6139
|
+
accepts: r.accepts,
|
|
6140
|
+
input: { method: (r.method ?? "GET").toUpperCase() },
|
|
6141
|
+
...r.mimeType ? { output: { mimeType: r.mimeType } } : {}
|
|
6142
|
+
}))
|
|
6143
|
+
};
|
|
6144
|
+
}
|
|
6066
6145
|
function buildX402DnsTxt(input) {
|
|
6067
6146
|
const descriptor = input.descriptor ? `descriptor=${input.descriptor};` : "";
|
|
6068
6147
|
return {
|
|
@@ -6793,7 +6872,7 @@ function createPaymentGate(options) {
|
|
|
6793
6872
|
if (hasCustomStore) {
|
|
6794
6873
|
return options.isUsed ? Boolean(await options.isUsed(ref)) : false;
|
|
6795
6874
|
}
|
|
6796
|
-
const key = ref.toLowerCase();
|
|
6875
|
+
const key = ref.startsWith("pid:") ? ref : ref.toLowerCase();
|
|
6797
6876
|
const now = Date.now();
|
|
6798
6877
|
pruneUsed(now);
|
|
6799
6878
|
if (localUsed.has(key)) return true;
|
|
@@ -6805,7 +6884,7 @@ function createPaymentGate(options) {
|
|
|
6805
6884
|
if (ok && options.markUsed) await options.markUsed(ref);
|
|
6806
6885
|
return;
|
|
6807
6886
|
}
|
|
6808
|
-
if (!ok) localUsed.delete(ref.toLowerCase());
|
|
6887
|
+
if (!ok) localUsed.delete(ref.startsWith("pid:") ? ref : ref.toLowerCase());
|
|
6809
6888
|
}
|
|
6810
6889
|
function buildAccept(s, nonce) {
|
|
6811
6890
|
return {
|
|
@@ -6878,6 +6957,7 @@ function createPaymentGate(options) {
|
|
|
6878
6957
|
const specs = await ready();
|
|
6879
6958
|
const nonce = genNonce();
|
|
6880
6959
|
const bazaar = options.discovery ? { bazaar: buildBazaarExtension(options.discovery === true ? {} : options.discovery) } : void 0;
|
|
6960
|
+
const paymentIdAd = options.paymentIdentifier ? buildPaymentIdentifierAdvertisement() : void 0;
|
|
6881
6961
|
const accepts = buildAccepts(specs, nonce);
|
|
6882
6962
|
const endpointInfo = buildEndpointInfo({
|
|
6883
6963
|
...options.description ? { description: options.description } : {},
|
|
@@ -6895,11 +6975,13 @@ function createPaymentGate(options) {
|
|
|
6895
6975
|
const bodyPiprail = { ...selfDescribe ?? {}, ...rejectionPiprail };
|
|
6896
6976
|
const bodyExtensions = {
|
|
6897
6977
|
...bazaar,
|
|
6978
|
+
...paymentIdAd,
|
|
6898
6979
|
...rejectionExt,
|
|
6899
6980
|
...Object.keys(bodyPiprail).length > 0 ? { piprail: bodyPiprail } : {}
|
|
6900
6981
|
};
|
|
6901
6982
|
const headerExtensions = {
|
|
6902
6983
|
...bazaar,
|
|
6984
|
+
...paymentIdAd,
|
|
6903
6985
|
...Object.keys(rejectionPiprail).length > 0 ? { piprail: rejectionPiprail } : {}
|
|
6904
6986
|
};
|
|
6905
6987
|
const challenge2 = {
|
|
@@ -7109,7 +7191,17 @@ function createPaymentGate(options) {
|
|
|
7109
7191
|
await settleTx(ref, false);
|
|
7110
7192
|
return rejection(result.error, result.detail);
|
|
7111
7193
|
}
|
|
7112
|
-
|
|
7194
|
+
const verified = result.receipt.transaction;
|
|
7195
|
+
if (verified && verified !== ref) {
|
|
7196
|
+
if (await claimTx(verified)) {
|
|
7197
|
+
await settleTx(ref, false);
|
|
7198
|
+
return rejection("tx_already_used", `Payment ${verified} was already redeemed.`);
|
|
7199
|
+
}
|
|
7200
|
+
await settleTx(ref, false);
|
|
7201
|
+
await settleTx(verified, true);
|
|
7202
|
+
} else {
|
|
7203
|
+
await settleTx(ref, true);
|
|
7204
|
+
}
|
|
7113
7205
|
await deliverOnPaid(spec, result.receipt);
|
|
7114
7206
|
return await buildPaidResult(spec, result.receipt, sig.payload.nonce);
|
|
7115
7207
|
}
|
|
@@ -7315,7 +7407,7 @@ function createPaymentGate(options) {
|
|
|
7315
7407
|
if (result.kind === "invalid") await deliverOnFailed(result);
|
|
7316
7408
|
return result;
|
|
7317
7409
|
}
|
|
7318
|
-
async function
|
|
7410
|
+
async function routeVerdictObject(obj) {
|
|
7319
7411
|
if (obj === void 0 || obj === null) return asChallenge();
|
|
7320
7412
|
const sig = parseSignatureObject(obj);
|
|
7321
7413
|
if (sig && sig.accepted && typeof sig.accepted.network === "string" && typeof sig.accepted.asset === "string") {
|
|
@@ -7327,6 +7419,44 @@ function createPaymentGate(options) {
|
|
|
7327
7419
|
if (exact) return verifyExact(exact);
|
|
7328
7420
|
return asChallenge();
|
|
7329
7421
|
}
|
|
7422
|
+
function echoPaymentIdentifier(result, id) {
|
|
7423
|
+
try {
|
|
7424
|
+
const decoded = decodeBase64Json(result.receiptHeader);
|
|
7425
|
+
if (!decoded) return result;
|
|
7426
|
+
const { extensions: existing, ...receiptOnly } = decoded;
|
|
7427
|
+
const merged = {
|
|
7428
|
+
...existing ?? {},
|
|
7429
|
+
[EXT_PAYMENT_IDENTIFIER]: { info: { required: false, id } }
|
|
7430
|
+
};
|
|
7431
|
+
return { ...result, receiptHeader: buildReceiptHeader(receiptOnly, merged) };
|
|
7432
|
+
} catch {
|
|
7433
|
+
return result;
|
|
7434
|
+
}
|
|
7435
|
+
}
|
|
7436
|
+
async function resolveVerdictObject(obj) {
|
|
7437
|
+
if (!options.paymentIdentifier) return routeVerdictObject(obj);
|
|
7438
|
+
const id = readPaymentIdentifier(obj);
|
|
7439
|
+
if (id !== null && typeof id === "object") {
|
|
7440
|
+
return rejection("signature_invalid", `payment-identifier: ${id.invalid}.`);
|
|
7441
|
+
}
|
|
7442
|
+
if (id === null) return routeVerdictObject(obj);
|
|
7443
|
+
const idKey = "pid:" + id;
|
|
7444
|
+
if (await claimTx(idKey)) {
|
|
7445
|
+
return rejection(
|
|
7446
|
+
"tx_already_used",
|
|
7447
|
+
`Idempotency id "${id}" is already bound to a settled payment; use a fresh id for a new payment.`
|
|
7448
|
+
);
|
|
7449
|
+
}
|
|
7450
|
+
let result;
|
|
7451
|
+
try {
|
|
7452
|
+
result = await routeVerdictObject(obj);
|
|
7453
|
+
} catch (err) {
|
|
7454
|
+
await settleTx(idKey, false);
|
|
7455
|
+
throw err;
|
|
7456
|
+
}
|
|
7457
|
+
await settleTx(idKey, result.kind === "paid");
|
|
7458
|
+
return result.kind === "paid" ? echoPaymentIdentifier(result, id) : result;
|
|
7459
|
+
}
|
|
7330
7460
|
return { challenge, verify, verifyObject, describe, landingPage };
|
|
7331
7461
|
}
|
|
7332
7462
|
function requirePayment(options) {
|
|
@@ -7726,6 +7856,115 @@ function resourceUrlFromMessage(message) {
|
|
|
7726
7856
|
}
|
|
7727
7857
|
return "";
|
|
7728
7858
|
}
|
|
7859
|
+
|
|
7860
|
+
// src/transports/mcp-types.ts
|
|
7861
|
+
var MCP_PAYMENT_META_KEY = "x402/payment";
|
|
7862
|
+
var MCP_PAYMENT_RESPONSE_META_KEY = "x402/payment-response";
|
|
7863
|
+
|
|
7864
|
+
// src/transports/mcp.ts
|
|
7865
|
+
function toMcpPaymentRequired(challenge) {
|
|
7866
|
+
const text = JSON.stringify(challenge);
|
|
7867
|
+
return {
|
|
7868
|
+
isError: true,
|
|
7869
|
+
structuredContent: challenge,
|
|
7870
|
+
content: [{ type: "text", text }]
|
|
7871
|
+
};
|
|
7872
|
+
}
|
|
7873
|
+
function toMcpPaymentResponse(content, receipt) {
|
|
7874
|
+
return {
|
|
7875
|
+
content,
|
|
7876
|
+
_meta: {
|
|
7877
|
+
[MCP_PAYMENT_RESPONSE_META_KEY]: {
|
|
7878
|
+
success: true,
|
|
7879
|
+
transaction: receipt.transaction,
|
|
7880
|
+
network: receipt.network,
|
|
7881
|
+
payer: receipt.payer
|
|
7882
|
+
}
|
|
7883
|
+
}
|
|
7884
|
+
};
|
|
7885
|
+
}
|
|
7886
|
+
function fromMcpPayment(params) {
|
|
7887
|
+
const meta = params?._meta?.[MCP_PAYMENT_META_KEY];
|
|
7888
|
+
return meta == null ? null : meta;
|
|
7889
|
+
}
|
|
7890
|
+
function fromMcpPaymentRequired(result) {
|
|
7891
|
+
if (!result || result.isError !== true) return null;
|
|
7892
|
+
const sc = result.structuredContent;
|
|
7893
|
+
if (sc && typeof sc === "object" && typeof sc.x402Version === "number") {
|
|
7894
|
+
return sc;
|
|
7895
|
+
}
|
|
7896
|
+
const text = result.content?.[0]?.text;
|
|
7897
|
+
if (typeof text === "string") {
|
|
7898
|
+
try {
|
|
7899
|
+
const parsed = JSON.parse(text);
|
|
7900
|
+
if (parsed && typeof parsed === "object" && typeof parsed.x402Version === "number") {
|
|
7901
|
+
return parsed;
|
|
7902
|
+
}
|
|
7903
|
+
} catch {
|
|
7904
|
+
}
|
|
7905
|
+
}
|
|
7906
|
+
return null;
|
|
7907
|
+
}
|
|
7908
|
+
function isMcpPaymentRequired(result) {
|
|
7909
|
+
return fromMcpPaymentRequired(result) != null;
|
|
7910
|
+
}
|
|
7911
|
+
function fromMcpPaymentResponse(result) {
|
|
7912
|
+
const meta = result?._meta?.[MCP_PAYMENT_RESPONSE_META_KEY];
|
|
7913
|
+
if (!meta || typeof meta !== "object") return null;
|
|
7914
|
+
return meta;
|
|
7915
|
+
}
|
|
7916
|
+
function buildMcpPaymentMeta(input) {
|
|
7917
|
+
return {
|
|
7918
|
+
[MCP_PAYMENT_META_KEY]: {
|
|
7919
|
+
x402Version: input.x402Version ?? 2,
|
|
7920
|
+
...input.resource ? { resource: input.resource } : {},
|
|
7921
|
+
accepted: input.accepted,
|
|
7922
|
+
payload: input.payload
|
|
7923
|
+
}
|
|
7924
|
+
};
|
|
7925
|
+
}
|
|
7926
|
+
function createMcpPaymentTool(options) {
|
|
7927
|
+
const gate = options.gate ?? createPaymentGate(options);
|
|
7928
|
+
function settlementFailed(code, detail) {
|
|
7929
|
+
return {
|
|
7930
|
+
isError: true,
|
|
7931
|
+
content: [
|
|
7932
|
+
{
|
|
7933
|
+
type: "text",
|
|
7934
|
+
text: `x402 settlement failed (${toA2AErrorCode(code)}): ${detail}. The buyer can retry, or pay the onchain-proof rail directly.`
|
|
7935
|
+
}
|
|
7936
|
+
]
|
|
7937
|
+
};
|
|
7938
|
+
}
|
|
7939
|
+
async function handleToolCall(params) {
|
|
7940
|
+
const raw = fromMcpPayment(params);
|
|
7941
|
+
if (raw == null) {
|
|
7942
|
+
const { challenge } = await gate.challenge(options.resourceUrl ?? "");
|
|
7943
|
+
return toMcpPaymentRequired(challenge);
|
|
7944
|
+
}
|
|
7945
|
+
let result;
|
|
7946
|
+
try {
|
|
7947
|
+
result = await gate.verifyObject(raw);
|
|
7948
|
+
} catch (err) {
|
|
7949
|
+
if (err instanceof SettlementError) return settlementFailed("settlement_failed", err.message);
|
|
7950
|
+
throw err;
|
|
7951
|
+
}
|
|
7952
|
+
if (result.kind === "paid") {
|
|
7953
|
+
try {
|
|
7954
|
+
const content = await options.fulfill({ receipt: result.receipt, params });
|
|
7955
|
+
return toMcpPaymentResponse(content, result.receipt);
|
|
7956
|
+
} catch (err) {
|
|
7957
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
7958
|
+
return toMcpPaymentResponse(
|
|
7959
|
+
[{ type: "text", text: `Payment settled (tx ${result.receipt.transaction}), but serving the result failed: ${detail}` }],
|
|
7960
|
+
result.receipt
|
|
7961
|
+
);
|
|
7962
|
+
}
|
|
7963
|
+
}
|
|
7964
|
+
return toMcpPaymentRequired(result.challenge);
|
|
7965
|
+
}
|
|
7966
|
+
return { handleToolCall, gate };
|
|
7967
|
+
}
|
|
7729
7968
|
export {
|
|
7730
7969
|
A2A_ERROR_KEY,
|
|
7731
7970
|
A2A_EXTENSIONS_HEADER,
|
|
@@ -7744,6 +7983,7 @@ export {
|
|
|
7744
7983
|
EIP3009_TYPES,
|
|
7745
7984
|
EXACT_NETWORK_SLUGS,
|
|
7746
7985
|
EXT_OFFER_RECEIPT,
|
|
7986
|
+
EXT_PAYMENT_IDENTIFIER,
|
|
7747
7987
|
GENERATOR,
|
|
7748
7988
|
HEADER_REQUIRED,
|
|
7749
7989
|
HEADER_RESPONSE,
|
|
@@ -7753,6 +7993,8 @@ export {
|
|
|
7753
7993
|
InsufficientFundsError,
|
|
7754
7994
|
InvalidEnvelopeError,
|
|
7755
7995
|
KNOWN_FACILITATORS,
|
|
7996
|
+
MCP_PAYMENT_META_KEY,
|
|
7997
|
+
MCP_PAYMENT_RESPONSE_META_KEY,
|
|
7756
7998
|
MaxRetriesExceededError,
|
|
7757
7999
|
MissingDriverError,
|
|
7758
8000
|
MultiChainPayer,
|
|
@@ -7790,18 +8032,22 @@ export {
|
|
|
7790
8032
|
buildEndpointInfo,
|
|
7791
8033
|
buildExactAuthorization,
|
|
7792
8034
|
buildExactSignatureHeader,
|
|
8035
|
+
buildMcpPaymentMeta,
|
|
7793
8036
|
buildOpenApi,
|
|
8037
|
+
buildPaymentIdentifierAdvertisement,
|
|
7794
8038
|
buildReceiptExtension,
|
|
7795
8039
|
buildReceiptHeader,
|
|
7796
8040
|
buildSelfDescription,
|
|
7797
8041
|
buildSignatureHeader,
|
|
7798
8042
|
buildUptoSignatureHeader,
|
|
7799
8043
|
buildWellKnownX402,
|
|
8044
|
+
buildWellKnownX402Manifest,
|
|
7800
8045
|
buildX402DnsTxt,
|
|
7801
8046
|
chainIdForExactNetwork,
|
|
7802
8047
|
claim402IndexDomain,
|
|
7803
8048
|
classifyChallenge,
|
|
7804
8049
|
createA2APaymentHandler,
|
|
8050
|
+
createMcpPaymentTool,
|
|
7805
8051
|
createPaymentGate,
|
|
7806
8052
|
decodeBase64Json,
|
|
7807
8053
|
decorateOutcome,
|
|
@@ -7819,7 +8065,11 @@ export {
|
|
|
7819
8065
|
formatSpendReport,
|
|
7820
8066
|
fromA2APaymentPayload,
|
|
7821
8067
|
fromA2APaymentRequired,
|
|
8068
|
+
fromMcpPayment,
|
|
8069
|
+
fromMcpPaymentRequired,
|
|
8070
|
+
fromMcpPaymentResponse,
|
|
7822
8071
|
getDirectoryInfo,
|
|
8072
|
+
isMcpPaymentRequired,
|
|
7823
8073
|
isPermit2ProxyChain,
|
|
7824
8074
|
isUptoProxyChain,
|
|
7825
8075
|
knownFacilitatorsFor,
|
|
@@ -7842,6 +8092,7 @@ export {
|
|
|
7842
8092
|
planAcross,
|
|
7843
8093
|
rankResources,
|
|
7844
8094
|
readExactDomain,
|
|
8095
|
+
readPaymentIdentifier,
|
|
7845
8096
|
register402Index,
|
|
7846
8097
|
registerDriver,
|
|
7847
8098
|
registerX402Scan,
|
|
@@ -7858,5 +8109,7 @@ export {
|
|
|
7858
8109
|
toA2APaymentRequired,
|
|
7859
8110
|
toInsufficientFundsError,
|
|
7860
8111
|
toInvalidBody,
|
|
8112
|
+
toMcpPaymentRequired,
|
|
8113
|
+
toMcpPaymentResponse,
|
|
7861
8114
|
verify402IndexDomain
|
|
7862
8115
|
};
|
|
@@ -210,6 +210,13 @@ interface X402PaymentSignature {
|
|
|
210
210
|
nonce: string;
|
|
211
211
|
txHash: string;
|
|
212
212
|
};
|
|
213
|
+
/**
|
|
214
|
+
* Optional v2 extensions the client attaches to its payload — e.g. the
|
|
215
|
+
* `payment-identifier` idempotency id at `extensions['payment-identifier'].info.id`
|
|
216
|
+
* (read by the gate via {@link readPaymentIdentifier}). A standard reader ignores it,
|
|
217
|
+
* and omitting it keeps the payload byte-identical.
|
|
218
|
+
*/
|
|
219
|
+
extensions?: Record<string, unknown>;
|
|
213
220
|
}
|
|
214
221
|
/**
|
|
215
222
|
* The EIP-3009 authorization a payer signs for a standard `exact` rail. All
|
|
@@ -590,6 +597,29 @@ declare function buildReceiptExtension(bundle: {
|
|
|
590
597
|
decimals?: number;
|
|
591
598
|
attestation?: SignedReceipt;
|
|
592
599
|
}): Record<string, unknown>;
|
|
600
|
+
/** The x402 extension key for the optional idempotency identifier (the official
|
|
601
|
+
* `payment-identifier` extension). A client MAY attach a stable `id` so the server dedupes
|
|
602
|
+
* retries and rejects a reused id bound to a DIFFERENT payment. */
|
|
603
|
+
declare const EXT_PAYMENT_IDENTIFIER = "payment-identifier";
|
|
604
|
+
/**
|
|
605
|
+
* Advertise the `payment-identifier` extension on a 402 challenge — PURE JSON, viem-free. The
|
|
606
|
+
* v2 `{ info, schema }` shape: `info.required:false` (PipRail never MANDATES an id) plus a
|
|
607
|
+
* JSON-Schema bound of {@link PAYMENT_ID_MIN}–{@link PAYMENT_ID_MAX} chars. A client reads this
|
|
608
|
+
* from the challenge and MAY echo an `id` back on its payload; the gate dedupes it on its
|
|
609
|
+
* existing used-proof set. The gate merges this into the challenge `extensions` (a sibling key,
|
|
610
|
+
* never inside `extensions.piprail`).
|
|
611
|
+
*/
|
|
612
|
+
declare function buildPaymentIdentifierAdvertisement(): Record<string, unknown>;
|
|
613
|
+
/**
|
|
614
|
+
* Read + validate an inbound `payment-identifier` id from a decoded payment-payload object
|
|
615
|
+
* (`payload.extensions['payment-identifier'].info.id`). PURE, NEVER throws. Returns:
|
|
616
|
+
* - the `id` string when present + valid (16–128 chars, `[A-Za-z0-9_-]`),
|
|
617
|
+
* - `null` when ABSENT (the id is OPTIONAL — the gate proceeds exactly as without the feature),
|
|
618
|
+
* - `{ invalid }` when PRESENT but malformed (the gate re-challenges so the buyer can fix it).
|
|
619
|
+
*/
|
|
620
|
+
declare function readPaymentIdentifier(payload: unknown): string | null | {
|
|
621
|
+
invalid: string;
|
|
622
|
+
};
|
|
593
623
|
declare function buildSignatureHeader(signature: X402PaymentSignature): string;
|
|
594
624
|
/**
|
|
595
625
|
* Build the v2 PAYMENT-SIGNATURE header value for a standard x402 `exact` payment:
|
|
@@ -928,4 +958,4 @@ declare class SpendLedger {
|
|
|
928
958
|
summary(): SpendSummary;
|
|
929
959
|
}
|
|
930
960
|
|
|
931
|
-
export {
|
|
961
|
+
export { parseSettleResponse as $, type AddressId as A, type X402ExactAcceptEntry as B, type Caip2 as C, type X402PaymentSignature as D, EXT_OFFER_RECEIPT as E, type X402Receipt as F, type X402ResourceObject as G, HEADER_REQUIRED as H, type X402UptoAcceptEntry as I, buildChallengeHeader as J, buildExactSignatureHeader as K, buildPaymentIdentifierAdvertisement as L, buildReceiptExtension as M, buildReceiptHeader as N, buildSignatureHeader as O, type PaidReceipt as P, buildUptoSignatureHeader as Q, decodeBase64Json as R, type SettleOutcome as S, memorySpendStore as T, parseChallenge as U, type VerifyErrorCode as V, parseExactObject as W, type X402AcceptEntry as X, parseExactPaymentHeader as Y, parseReceipt as Z, parseReceiptExtension as _, type AssetId as a, parseSignatureHeader as a0, parseSignatureObject as a1, parseUptoObject as a2, parseUptoPaymentHeader as a3, pickAccept as a4, readPaymentIdentifier as a5, EXT_PAYMENT_IDENTIFIER as b, type ExactAuthorizationWire as c, type ExactPaymentPayload as d, type ExactPaymentPayloadAny as e, HEADER_RESPONSE as f, HEADER_RESPONSE_V1 as g, HEADER_SIGNATURE as h, HEADER_SIGNATURE_V1 as i, type ParsedExactPayment as j, type ParsedUptoPayment as k, type Permit2Authorization as l, type Permit2PaymentPayload as m, type Permit2UptoAuthorization as n, type Permit2UptoPaymentPayload as o, type PipRailReceipt as p, type SignedReceipt as q, type SpendAssetTotal as r, type SpendDenomTotal as s, SpendLedger as t, type SpendRecord as u, type SpendStore as v, type SpendSummary as w, type VerifyResult as x, type X402AnyAccept as y, type X402Challenge as z };
|