@piprail/sdk 1.22.0 → 1.23.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 +47 -0
- package/README.md +6 -0
- package/dist/index.cjs +232 -19
- package/dist/index.d.cts +240 -2
- package/dist/index.d.ts +240 -2
- package/dist/index.js +222 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,53 @@ All notable changes to `@piprail/sdk` are documented here. The format
|
|
|
4
4
|
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
|
|
5
5
|
versions follow [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [1.23.0] — 2026-06-14 — self-describing endpoints + discovery reach
|
|
8
|
+
|
|
9
|
+
### Added — self-describing, more discoverable endpoints (discoverability plan: Phases 1, 2, 4, 5)
|
|
10
|
+
|
|
11
|
+
- **Self-describing 402s, ON by default.** Every challenge a gate builds now carries an
|
|
12
|
+
`extensions.piprail` block — identity, per-rail how-to-pay, `npm i @piprail/sdk` + a paste-ready
|
|
13
|
+
snippet, the MCP command, and docs + discovery pointers — so any human, AI agent, or crawler that
|
|
14
|
+
lands on a gated endpoint (even the `onchain-proof` scheme a stock x402 client can't pay) knows what
|
|
15
|
+
it is and how to pay it. **Purely-additive** metadata in the spec-opaque `extensions` bag, and it
|
|
16
|
+
rides in the response **body** only — the base64 `payment-required` **header stays slim** (just
|
|
17
|
+
`accepts[]` + a small `bazaar`/rejection block), so the header, pay path, `accepts[]`, and status are
|
|
18
|
+
byte-identical (a rejection's `{code,detail}` are deep-merged as siblings and still win). Opt out with
|
|
19
|
+
`requirePayment({ selfDescribe: false })`. New exports: `buildSelfDescription`, `describeChallenge`, `BRAND`.
|
|
20
|
+
- **Human landing page + HTTP pointers.** `gate.landingPage(challenge)` / `renderLandingPage()` render a
|
|
21
|
+
tiny, HTML-escaped 402 page for a browser (serve it on `Accept: text/html`; agents/crawlers keep the
|
|
22
|
+
JSON 402). It leads with **how to pay** and a clear **caution** that a manual send to the address won't
|
|
23
|
+
unlock the resource (pay via an x402 client — no custody, no manual-payment desk). `discoveryHeaders()`
|
|
24
|
+
+ `POWERED_BY` emit a `Link` (rel `service-desc` / `x402-discovery`) + `x-powered-by` header bag to
|
|
25
|
+
spread on every response. The SDK serves nothing — the merchant does.
|
|
26
|
+
- **Facilitator-coverage map.** `KNOWN_FACILITATORS` (+ `knownFacilitatorsFor` /
|
|
27
|
+
`firstKeylessFacilitator`) — shipped data of which keyless facilitators settle `exact` on which
|
|
28
|
+
networks (seeded: PayAI on Base + Solana, dated-verified). `facilitatorCoverage(url)` /
|
|
29
|
+
`parseFacilitatorSupported(body)` read a facilitator's live `GET /supported` (best-effort, never throw).
|
|
30
|
+
- **Agent guide** gained a "landing cold — read the self-description" section (surfaced over the MCP).
|
|
31
|
+
|
|
32
|
+
All of the above is additive + opt-in; the zero-config pay path is byte-identical to before. New pure
|
|
33
|
+
modules (`selfdescribe.ts`, `landing.ts`, `facilitators.ts`) join the viem-free protocol-layer grep.
|
|
34
|
+
|
|
35
|
+
### Removed
|
|
36
|
+
- **`base-sepolia` (84532) testnet entry** from `EXACT_NETWORK_SLUGS` and the Permit2 proxy chain-id set
|
|
37
|
+
— mainnets only, no testnet presets (it was dead reference data; nothing settles on a testnet).
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
- **`x-powered-by` is now ASCII** (`PipRail x402 | https://piprail.com`) — the previous non-ASCII middot
|
|
41
|
+
mangled to `·` over Node's latin1 header transport. `GENERATOR` keeps its `·` (JSON body only).
|
|
42
|
+
- **`renderLandingPage` never throws** on a rail missing `amount`/`asset` (matches the module's
|
|
43
|
+
never-throw contract).
|
|
44
|
+
- **`fetchFacilitatorFeePayer` matches the network normalized** (CAIP-2 *or* slug) so a slug-reporting
|
|
45
|
+
facilitator's Solana exact fee-payer is found instead of silently dropped.
|
|
46
|
+
|
|
47
|
+
## [1.22.1] — 2026-06-13 — docs: community links + integrations signposting
|
|
48
|
+
|
|
49
|
+
Docs-only patch — **no code change** (the SDK is byte-identical to 1.22.0). Refreshes the README:
|
|
50
|
+
adds a "Spread the word" section (GitHub · X · piprail.com · docs) and surfaces the first-party
|
|
51
|
+
integrations (the OpenClaw skill, `clawhub install piprail`) from the repo. Published so the npm
|
|
52
|
+
package page carries the updated front door.
|
|
53
|
+
|
|
7
54
|
## [1.22.0] — 2026-06-13 — optional wallet (read-only client)
|
|
8
55
|
|
|
9
56
|
A purely **additive, opt-in** feature: `PipRailClient`'s `wallet` is now **optional**. Omit it for a
|
package/README.md
CHANGED
|
@@ -55,6 +55,12 @@ The same app can **take** payments and **make** them. → [Making payments](http
|
|
|
55
55
|
| **[MCP server](https://docs.piprail.com/mcp/overview/)** | Give any AI agent a budget-bound wallet |
|
|
56
56
|
| **[Reference](https://docs.piprail.com/reference/api/)** | The complete API surface |
|
|
57
57
|
|
|
58
|
+
## Spread the word
|
|
59
|
+
|
|
60
|
+
PipRail is free, open-source, and has no backend to sell you. If it saved you from building a payments backend, help other developers (and their agents) find it:
|
|
61
|
+
|
|
62
|
+
⭐ **[Star on GitHub](https://github.com/piprail/piprail)** · 𝕏 **[Follow @piprailhq](https://x.com/piprailhq)** · 🌐 **[piprail.com](https://piprail.com)** · 📖 **[docs.piprail.com](https://docs.piprail.com)**
|
|
63
|
+
|
|
58
64
|
## License & trademark
|
|
59
65
|
|
|
60
66
|
The code is **MIT** — use it, fork it, ship it. **PipRail™**, the logo, and the `@piprail` npm scope are trademarks of the PipRail project: build on the code freely, but please don't call a fork "PipRail" or imply it's official. See [TRADEMARK.md](https://github.com/piprail/piprail/blob/main/TRADEMARK.md).
|
package/dist/index.cjs
CHANGED
|
@@ -511,7 +511,6 @@ function sumTransfersTo(logs, asset, payTo) {
|
|
|
511
511
|
var EXACT_NETWORK_SLUGS = {
|
|
512
512
|
ethereum: 1,
|
|
513
513
|
base: 8453,
|
|
514
|
-
"base-sepolia": 84532,
|
|
515
514
|
arbitrum: 42161,
|
|
516
515
|
optimism: 10,
|
|
517
516
|
polygon: 137,
|
|
@@ -983,8 +982,6 @@ var PERMIT2_PROXY_CHAIN_IDS = /* @__PURE__ */ new Set([
|
|
|
983
982
|
// Ethereum
|
|
984
983
|
8453,
|
|
985
984
|
// Base
|
|
986
|
-
84532,
|
|
987
|
-
// Base Sepolia
|
|
988
985
|
42161,
|
|
989
986
|
// Arbitrum
|
|
990
987
|
10,
|
|
@@ -3604,6 +3601,48 @@ async function readInvalidReason(response) {
|
|
|
3604
3601
|
return null;
|
|
3605
3602
|
}
|
|
3606
3603
|
|
|
3604
|
+
// src/selfdescribe.ts
|
|
3605
|
+
var BRAND = {
|
|
3606
|
+
name: "PipRail",
|
|
3607
|
+
home: "https://piprail.com",
|
|
3608
|
+
docs: "https://docs.piprail.com",
|
|
3609
|
+
payDocs: "https://docs.piprail.com/paying",
|
|
3610
|
+
sdkInstall: "npm i @piprail/sdk",
|
|
3611
|
+
sdkSnippet: "import { PipRailClient } from '@piprail/sdk'\nconst client = new PipRailClient({ chain: '<your-chain>', wallet })\nawait client.fetch('<this-url>')",
|
|
3612
|
+
mcpRun: "npx -y @piprail/mcp"
|
|
3613
|
+
};
|
|
3614
|
+
var WHAT = 'This is an x402 "402 Payment Required" endpoint. Pay one of the offered rails to access it.';
|
|
3615
|
+
function howFor(scheme) {
|
|
3616
|
+
return scheme === "exact" ? "Standard x402 exact rail \u2014 sign an EIP-3009 / Permit2 / SVM authorization; any stock x402 client (e.g. @x402/fetch) can pay this." : "Pay this amount on-chain to payTo, then resubmit with a payment-signature header carrying the proof ref + nonce. Easiest with @piprail/sdk (see sdk.install).";
|
|
3617
|
+
}
|
|
3618
|
+
function railOf(a) {
|
|
3619
|
+
const extra = _nullishCoalesce(a.extra, () => ( {}));
|
|
3620
|
+
return {
|
|
3621
|
+
scheme: a.scheme,
|
|
3622
|
+
network: a.network,
|
|
3623
|
+
asset: a.asset,
|
|
3624
|
+
payTo: a.payTo,
|
|
3625
|
+
amount: a.amount,
|
|
3626
|
+
...extra.amountFormatted ? { amountFormatted: extra.amountFormatted } : {},
|
|
3627
|
+
...extra.symbol ? { symbol: extra.symbol } : {},
|
|
3628
|
+
how: howFor(a.scheme)
|
|
3629
|
+
};
|
|
3630
|
+
}
|
|
3631
|
+
function buildSelfDescription(input) {
|
|
3632
|
+
return {
|
|
3633
|
+
name: "PipRail",
|
|
3634
|
+
protocol: "x402",
|
|
3635
|
+
version: "2",
|
|
3636
|
+
what: WHAT,
|
|
3637
|
+
pay: input.accepts.map(railOf),
|
|
3638
|
+
sdk: { install: BRAND.sdkInstall, snippet: BRAND.sdkSnippet },
|
|
3639
|
+
mcp: { run: BRAND.mcpRun, tool: "piprail_pay_request" },
|
|
3640
|
+
docs: { home: BRAND.home, agents: BRAND.docs, pay: BRAND.payDocs },
|
|
3641
|
+
discovery: { openapi: "/openapi.json", wellKnown: "/.well-known/x402" },
|
|
3642
|
+
...input.instruction ? { instruction: input.instruction } : {}
|
|
3643
|
+
};
|
|
3644
|
+
}
|
|
3645
|
+
|
|
3607
3646
|
// src/render.ts
|
|
3608
3647
|
function summarizePlan(plan) {
|
|
3609
3648
|
if (plan == null) return "No payment required \u2014 the URL is not payment-gated.";
|
|
@@ -3644,6 +3683,18 @@ function formatSpendReport(summary) {
|
|
|
3644
3683
|
(a) => `${a.totalFormatted} ${_nullishCoalesce(a.symbol, () => ( a.asset))} on ${a.network} (${a.count} payment${a.count === 1 ? "" : "s"})`
|
|
3645
3684
|
).join("; ");
|
|
3646
3685
|
}
|
|
3686
|
+
function describeChallenge(challenge) {
|
|
3687
|
+
const first = challenge.accepts[0];
|
|
3688
|
+
if (!first) {
|
|
3689
|
+
return `${BRAND.name} x402 payment endpoint. Pay with @piprail/sdk (${BRAND.sdkInstall}). Docs: ${BRAND.home}.`;
|
|
3690
|
+
}
|
|
3691
|
+
const extra = _nullishCoalesce(first.extra, () => ( {}));
|
|
3692
|
+
const amount = _nullishCoalesce(extra.amountFormatted, () => ( first.amount));
|
|
3693
|
+
const token = _nullishCoalesce(extra.symbol, () => ( first.asset));
|
|
3694
|
+
const hasExact = challenge.accepts.some((a) => a.scheme === "exact");
|
|
3695
|
+
const standard = hasExact ? "; or any standard x402 client (an exact rail is offered)" : "";
|
|
3696
|
+
return `${BRAND.name} x402 payment endpoint \u2014 pay ${amount} ${token} on ${first.network} to ${first.payTo}. Programmatic: ${BRAND.sdkInstall} then client.fetch(url)${standard}. Docs: ${BRAND.home}.`;
|
|
3697
|
+
}
|
|
3647
3698
|
|
|
3648
3699
|
// src/agentGuide.ts
|
|
3649
3700
|
var PIPRAIL_AGENT_GUIDE = `# Paying with PipRail \u2014 the agent contract
|
|
@@ -3651,6 +3702,13 @@ var PIPRAIL_AGENT_GUIDE = `# Paying with PipRail \u2014 the agent contract
|
|
|
3651
3702
|
You can pay for x402 "402 Payment Required" resources autonomously. Money moves
|
|
3652
3703
|
straight from your wallet to the server; PipRail custodies nothing. Follow this.
|
|
3653
3704
|
|
|
3705
|
+
## Landing cold \u2014 read the self-description
|
|
3706
|
+
Every PipRail 402 self-describes. Read challenge.extensions.piprail for { name, what, pay[]
|
|
3707
|
+
(each rail's how-to-pay), sdk.install, mcp, docs } \u2014 never guess what an endpoint is. If your
|
|
3708
|
+
tooling can't pay a rail (e.g. a stock x402 client can't pay the onchain-proof scheme), the
|
|
3709
|
+
block says how: install @piprail/sdk (npm i @piprail/sdk) or run the MCP (npx -y @piprail/mcp)
|
|
3710
|
+
and pay with the tools below.
|
|
3711
|
+
|
|
3654
3712
|
## The loop: quote \u2192 plan \u2192 pay
|
|
3655
3713
|
1. piprail_quote_payment(url) \u2014 PRICE it. Returns the amount, token, chain, and
|
|
3656
3714
|
whether it is within your spend policy. No funds move. Use it to decide if a
|
|
@@ -4011,6 +4069,13 @@ function classifyChallenge(challenge, opts) {
|
|
|
4011
4069
|
|
|
4012
4070
|
// src/discovery.ts
|
|
4013
4071
|
var GENERATOR = "@piprail/sdk \xB7 https://piprail.com";
|
|
4072
|
+
var POWERED_BY = "PipRail x402 | https://piprail.com";
|
|
4073
|
+
function discoveryHeaders(opts = {}) {
|
|
4074
|
+
return {
|
|
4075
|
+
link: '</openapi.json>; rel="service-desc", </.well-known/x402>; rel="x402-discovery"',
|
|
4076
|
+
...opts.attribution === false ? {} : { "x-powered-by": POWERED_BY }
|
|
4077
|
+
};
|
|
4078
|
+
}
|
|
4014
4079
|
function buildBazaarExtension(descriptor = {}) {
|
|
4015
4080
|
const method = (_nullishCoalesce(descriptor.method, () => ( "GET"))).toUpperCase();
|
|
4016
4081
|
const queryParams = _nullishCoalesce(descriptor.queryParams, () => ( {}));
|
|
@@ -4090,6 +4155,57 @@ function buildX402DnsTxt(input) {
|
|
|
4090
4155
|
};
|
|
4091
4156
|
}
|
|
4092
4157
|
|
|
4158
|
+
// src/landing.ts
|
|
4159
|
+
function esc(s) {
|
|
4160
|
+
return String(_nullishCoalesce(s, () => ( ""))).replace(
|
|
4161
|
+
/[&<>"']/g,
|
|
4162
|
+
(c) => c === "&" ? "&" : c === "<" ? "<" : c === ">" ? ">" : c === '"' ? """ : "'"
|
|
4163
|
+
);
|
|
4164
|
+
}
|
|
4165
|
+
var STYLE = `:root{color-scheme:dark}
|
|
4166
|
+
*{box-sizing:border-box}
|
|
4167
|
+
body{margin:0;background:#0a0e0f;color:#e6edf0;font:16px/1.6 ui-sans-serif,system-ui,-apple-system,Inter,sans-serif}
|
|
4168
|
+
main{max-width:680px;margin:0 auto;padding:48px 24px}
|
|
4169
|
+
h1{font-size:1.6rem;margin:0 0 .25rem}
|
|
4170
|
+
.lede{color:#9fb0b5;margin:.25rem 0 2rem}
|
|
4171
|
+
h2{font-size:1rem;text-transform:uppercase;letter-spacing:.05em;color:#34d399;margin:2rem 0 .75rem}
|
|
4172
|
+
table{width:100%;border-collapse:collapse;font-size:.92rem}
|
|
4173
|
+
th,td{text-align:left;padding:.5rem .6rem;border-bottom:1px solid #1c2426;vertical-align:top}
|
|
4174
|
+
th{color:#9fb0b5;font-weight:600}
|
|
4175
|
+
code,pre{font-family:ui-monospace,JetBrains Mono,monospace;font-size:.85rem}
|
|
4176
|
+
pre{background:#11181a;border:1px solid #1c2426;border-radius:8px;padding:14px;overflow-x:auto;color:#cfe9df}
|
|
4177
|
+
a{color:#34d399}
|
|
4178
|
+
.mono{font-family:ui-monospace,monospace;word-break:break-all}
|
|
4179
|
+
.warn{margin:0 0 2rem;padding:14px 16px;border:1px solid #5a4a1f;background:#17130a;border-radius:8px;color:#e8d9a8;font-size:.92rem;line-height:1.55}
|
|
4180
|
+
.warn strong{color:#f5d77a}
|
|
4181
|
+
.muted{color:#5b6b6f;font-weight:400;text-transform:none;letter-spacing:0;font-size:.8rem}
|
|
4182
|
+
footer{margin-top:2.5rem;color:#5b6b6f;font-size:.8rem}`;
|
|
4183
|
+
function renderLandingPage(sd) {
|
|
4184
|
+
const lede = esc(_nullishCoalesce(sd.instruction, () => ( sd.what)));
|
|
4185
|
+
const rows = sd.pay.map(
|
|
4186
|
+
(r) => `<tr><td><code>${esc(r.scheme)}</code></td><td>${esc(r.network)}</td><td>${esc(_nullishCoalesce(r.amountFormatted, () => ( r.amount)))} ${esc(_nullishCoalesce(r.symbol, () => ( r.asset)))}</td><td class="mono">${esc(r.payTo)}</td></tr>`
|
|
4187
|
+
).join("");
|
|
4188
|
+
return `<!doctype html>
|
|
4189
|
+
<html lang="en"><head><meta charset="utf-8">
|
|
4190
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
4191
|
+
<title>${esc(sd.name)} \xB7 x402 payment required</title>
|
|
4192
|
+
<style>${STYLE}</style>
|
|
4193
|
+
</head><body><main>
|
|
4194
|
+
<h1>402 \u2014 Payment Required</h1>
|
|
4195
|
+
<p class="lede">${lede}</p>
|
|
4196
|
+
<div class="warn"><strong>Pay with an x402 client \u2014 not by hand.</strong> This endpoint is paid programmatically: an x402 client (the ${esc(sd.name)} SDK or MCP below, or any x402-compatible wallet) makes the payment <em>and proves it</em>, which is what unlocks the resource. Sending funds straight to the address below from an ordinary wallet will reach the merchant but <strong>will NOT unlock this resource and won't be matched to your request</strong> \u2014 there is no custody and no manual-payment desk. Use one of the methods below.</div>
|
|
4197
|
+
<h2>How to pay</h2>
|
|
4198
|
+
<pre>${esc(sd.sdk.install)}</pre>
|
|
4199
|
+
<pre>${esc(sd.sdk.snippet)}</pre>
|
|
4200
|
+
<p>For AI agents (MCP): <code>${esc(sd.mcp.run)}</code> → tool <code>${esc(sd.mcp.tool)}</code></p>
|
|
4201
|
+
<h2>Payment details <span class="muted">\u2014 what the client pays, NOT a manual-send address</span></h2>
|
|
4202
|
+
<table><thead><tr><th>Scheme</th><th>Chain</th><th>Amount</th><th>Settles to</th></tr></thead>
|
|
4203
|
+
<tbody>${rows}</tbody></table>
|
|
4204
|
+
<p>Docs: <a href="${esc(sd.docs.pay)}">paying</a> · <a href="${esc(sd.docs.home)}">${esc(sd.docs.home)}</a> · <a href="${esc(sd.discovery.openapi)}">${esc(sd.discovery.openapi)}</a></p>
|
|
4205
|
+
<footer>Powered by ${esc(sd.name)} · x402 · no backend, no fee, settled straight to the merchant's wallet (no custody).</footer>
|
|
4206
|
+
</main></body></html>`;
|
|
4207
|
+
}
|
|
4208
|
+
|
|
4093
4209
|
// src/facilitator.ts
|
|
4094
4210
|
async function fetchFacilitatorFeePayer(url, network, timeoutMs = 8e3) {
|
|
4095
4211
|
const base2 = url.replace(/\/+$/, "");
|
|
@@ -4100,7 +4216,8 @@ async function fetchFacilitatorFeePayer(url, network, timeoutMs = 8e3) {
|
|
|
4100
4216
|
if (!res.ok) return void 0;
|
|
4101
4217
|
const body = await res.json();
|
|
4102
4218
|
const kinds = Array.isArray(_optionalChain([body, 'optionalAccess', _64 => _64.kinds])) ? body.kinds : [];
|
|
4103
|
-
const
|
|
4219
|
+
const want = normalizeNetwork(network);
|
|
4220
|
+
const kind = kinds.find((k) => _optionalChain([k, 'optionalAccess', _65 => _65.scheme]) === "exact" && normalizeNetwork(String(_nullishCoalesce(_optionalChain([k, 'optionalAccess', _66 => _66.network]), () => ( "")))) === want);
|
|
4104
4221
|
const fp = _optionalChain([kind, 'optionalAccess', _67 => _67.extra, 'optionalAccess', _68 => _68.feePayer]);
|
|
4105
4222
|
return typeof fp === "string" ? fp : void 0;
|
|
4106
4223
|
} catch (e32) {
|
|
@@ -4109,6 +4226,33 @@ async function fetchFacilitatorFeePayer(url, network, timeoutMs = 8e3) {
|
|
|
4109
4226
|
clearTimeout(timer);
|
|
4110
4227
|
}
|
|
4111
4228
|
}
|
|
4229
|
+
function parseFacilitatorSupported(body) {
|
|
4230
|
+
const kinds = _optionalChain([body, 'optionalAccess', _69 => _69.kinds]);
|
|
4231
|
+
if (!Array.isArray(kinds)) return [];
|
|
4232
|
+
const out = [];
|
|
4233
|
+
for (const k of kinds) {
|
|
4234
|
+
if (!k || typeof k !== "object") continue;
|
|
4235
|
+
const o = k;
|
|
4236
|
+
if (typeof o.scheme !== "string" || typeof o.network !== "string") continue;
|
|
4237
|
+
const fp = _optionalChain([o, 'access', _70 => _70.extra, 'optionalAccess', _71 => _71.feePayer]);
|
|
4238
|
+
out.push({ scheme: o.scheme, network: o.network, ...typeof fp === "string" ? { feePayer: fp } : {} });
|
|
4239
|
+
}
|
|
4240
|
+
return out;
|
|
4241
|
+
}
|
|
4242
|
+
async function facilitatorCoverage(url, timeoutMs = 8e3) {
|
|
4243
|
+
const base2 = url.replace(/\/+$/, "");
|
|
4244
|
+
const ctrl = new AbortController();
|
|
4245
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
4246
|
+
try {
|
|
4247
|
+
const res = await fetch(`${base2}/supported`, { signal: ctrl.signal });
|
|
4248
|
+
if (!res.ok) return [];
|
|
4249
|
+
return parseFacilitatorSupported(await res.json());
|
|
4250
|
+
} catch (e33) {
|
|
4251
|
+
return [];
|
|
4252
|
+
} finally {
|
|
4253
|
+
clearTimeout(timer);
|
|
4254
|
+
}
|
|
4255
|
+
}
|
|
4112
4256
|
function safeStringify(value) {
|
|
4113
4257
|
return JSON.stringify(value, (_k, v) => typeof v === "bigint" ? v.toString() : v);
|
|
4114
4258
|
}
|
|
@@ -4132,7 +4276,7 @@ async function post(url, body, headers) {
|
|
|
4132
4276
|
let json = null;
|
|
4133
4277
|
try {
|
|
4134
4278
|
json = await res.json();
|
|
4135
|
-
} catch (
|
|
4279
|
+
} catch (e34) {
|
|
4136
4280
|
}
|
|
4137
4281
|
return { status: res.status, json };
|
|
4138
4282
|
}
|
|
@@ -4386,22 +4530,47 @@ function createPaymentGate(options) {
|
|
|
4386
4530
|
const specs = await ready();
|
|
4387
4531
|
const nonce = genNonce();
|
|
4388
4532
|
const bazaar = options.discovery ? { bazaar: buildBazaarExtension(options.discovery === true ? {} : options.discovery) } : void 0;
|
|
4389
|
-
const
|
|
4533
|
+
const accepts = buildAccepts(specs, nonce);
|
|
4534
|
+
const selfDescribe = options.selfDescribe === false ? void 0 : buildSelfDescription({
|
|
4535
|
+
accepts,
|
|
4536
|
+
instruction: describeChallenge({ x402Version: 2, resource: { url: resourceUrl }, accepts })
|
|
4537
|
+
});
|
|
4538
|
+
const rejectionExt = _nullishCoalesce(_optionalChain([opts, 'optionalAccess', _72 => _72.extensions]), () => ( {}));
|
|
4539
|
+
const rejectionPiprail = _nullishCoalesce(rejectionExt.piprail, () => ( {}));
|
|
4540
|
+
const bodyPiprail = { ..._nullishCoalesce(selfDescribe, () => ( {})), ...rejectionPiprail };
|
|
4541
|
+
const bodyExtensions = {
|
|
4542
|
+
...bazaar,
|
|
4543
|
+
...rejectionExt,
|
|
4544
|
+
...Object.keys(bodyPiprail).length > 0 ? { piprail: bodyPiprail } : {}
|
|
4545
|
+
};
|
|
4546
|
+
const headerExtensions = {
|
|
4547
|
+
...bazaar,
|
|
4548
|
+
...Object.keys(rejectionPiprail).length > 0 ? { piprail: rejectionPiprail } : {}
|
|
4549
|
+
};
|
|
4390
4550
|
const challenge2 = {
|
|
4391
4551
|
x402Version: 2,
|
|
4392
4552
|
resource: {
|
|
4393
4553
|
url: resourceUrl,
|
|
4394
4554
|
...options.description ? { description: options.description } : {}
|
|
4395
4555
|
},
|
|
4396
|
-
accepts
|
|
4397
|
-
..._optionalChain([opts, 'optionalAccess',
|
|
4398
|
-
...Object.keys(
|
|
4556
|
+
accepts,
|
|
4557
|
+
..._optionalChain([opts, 'optionalAccess', _73 => _73.error]) ? { error: opts.error } : {},
|
|
4558
|
+
...Object.keys(bodyExtensions).length > 0 ? { extensions: bodyExtensions } : {}
|
|
4559
|
+
};
|
|
4560
|
+
const headerChallenge = {
|
|
4561
|
+
...challenge2,
|
|
4562
|
+
...Object.keys(headerExtensions).length > 0 ? { extensions: headerExtensions } : { extensions: void 0 }
|
|
4399
4563
|
};
|
|
4400
|
-
return { challenge: challenge2, requiredHeader: buildChallengeHeader(
|
|
4564
|
+
return { challenge: challenge2, requiredHeader: buildChallengeHeader(headerChallenge) };
|
|
4401
4565
|
}
|
|
4402
4566
|
async function challenge(resourceUrl = "") {
|
|
4403
4567
|
return makeChallenge(resourceUrl);
|
|
4404
4568
|
}
|
|
4569
|
+
function landingPage(ch) {
|
|
4570
|
+
return renderLandingPage(
|
|
4571
|
+
buildSelfDescription({ accepts: ch.accepts, instruction: describeChallenge(ch) })
|
|
4572
|
+
);
|
|
4573
|
+
}
|
|
4405
4574
|
async function asChallenge() {
|
|
4406
4575
|
const { challenge: c, requiredHeader } = await makeChallenge("");
|
|
4407
4576
|
return { kind: "challenge", challenge: c, requiredHeader, statusCode: 402 };
|
|
@@ -4417,7 +4586,7 @@ function createPaymentGate(options) {
|
|
|
4417
4586
|
let amountFormatted = receipt.amount;
|
|
4418
4587
|
try {
|
|
4419
4588
|
amountFormatted = _chunkU35MG4TFcjs.formatUnits.call(void 0, BigInt(receipt.amount), spec.decimals);
|
|
4420
|
-
} catch (
|
|
4589
|
+
} catch (e35) {
|
|
4421
4590
|
}
|
|
4422
4591
|
return {
|
|
4423
4592
|
...receipt,
|
|
@@ -4431,7 +4600,7 @@ function createPaymentGate(options) {
|
|
|
4431
4600
|
if (!options.onPaidError) return;
|
|
4432
4601
|
try {
|
|
4433
4602
|
options.onPaidError(error, receipt);
|
|
4434
|
-
} catch (
|
|
4603
|
+
} catch (e36) {
|
|
4435
4604
|
}
|
|
4436
4605
|
}
|
|
4437
4606
|
function fireOnPaid(receipt) {
|
|
@@ -4528,7 +4697,7 @@ function createPaymentGate(options) {
|
|
|
4528
4697
|
if ("transaction" in exact.payload) {
|
|
4529
4698
|
try {
|
|
4530
4699
|
nonce = Buffer.from(exact.payload.transaction, "base64").toString("base64");
|
|
4531
|
-
} catch (
|
|
4700
|
+
} catch (e37) {
|
|
4532
4701
|
nonce = exact.payload.transaction;
|
|
4533
4702
|
}
|
|
4534
4703
|
} else if ("permit2Authorization" in exact.payload) {
|
|
@@ -4597,7 +4766,7 @@ function createPaymentGate(options) {
|
|
|
4597
4766
|
if (exact) return verifyExact(exact);
|
|
4598
4767
|
return asChallenge();
|
|
4599
4768
|
}
|
|
4600
|
-
return { challenge, verify, describe };
|
|
4769
|
+
return { challenge, verify, describe, landingPage };
|
|
4601
4770
|
}
|
|
4602
4771
|
function requirePayment(options) {
|
|
4603
4772
|
const gate = createPaymentGate(options);
|
|
@@ -4637,6 +4806,39 @@ function normaliseHeader(value) {
|
|
|
4637
4806
|
return value;
|
|
4638
4807
|
}
|
|
4639
4808
|
|
|
4809
|
+
// src/facilitators.ts
|
|
4810
|
+
var KNOWN_FACILITATORS = {
|
|
4811
|
+
// PayAI — keyless (no API key), sponsors the gas. Verified 2026-06-14 against
|
|
4812
|
+
// https://facilitator.payai.network/supported (exact · eip155:8453) + the live demo.
|
|
4813
|
+
"eip155:8453": [
|
|
4814
|
+
{
|
|
4815
|
+
url: "https://facilitator.payai.network",
|
|
4816
|
+
keyless: true,
|
|
4817
|
+
schemes: ["exact"],
|
|
4818
|
+
settles: ["eip3009"],
|
|
4819
|
+
note: "PayAI \u2014 keyless, sponsors gas (Base USDC EIP-3009)"
|
|
4820
|
+
}
|
|
4821
|
+
],
|
|
4822
|
+
// PayAI on Solana — keyless fee-payer sponsor for the SVM exact rail. Verified 2026-06-14.
|
|
4823
|
+
"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": [
|
|
4824
|
+
{
|
|
4825
|
+
url: "https://facilitator.payai.network",
|
|
4826
|
+
keyless: true,
|
|
4827
|
+
schemes: ["exact"],
|
|
4828
|
+
settles: ["svm"],
|
|
4829
|
+
note: "PayAI \u2014 keyless fee-payer sponsor (Solana SPL SVM)"
|
|
4830
|
+
}
|
|
4831
|
+
]
|
|
4832
|
+
};
|
|
4833
|
+
function knownFacilitatorsFor(network) {
|
|
4834
|
+
return _nullishCoalesce(KNOWN_FACILITATORS[network], () => ( []));
|
|
4835
|
+
}
|
|
4836
|
+
function firstKeylessFacilitator(network, method) {
|
|
4837
|
+
return knownFacilitatorsFor(network).find(
|
|
4838
|
+
(f) => f.keyless && f.schemes.includes("exact") && (method === void 0 || f.settles.includes(method))
|
|
4839
|
+
);
|
|
4840
|
+
}
|
|
4841
|
+
|
|
4640
4842
|
// src/receipts.ts
|
|
4641
4843
|
var DEFAULT_RETRIES = 5;
|
|
4642
4844
|
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
@@ -4649,7 +4851,7 @@ function isRetryableStatus(status) {
|
|
|
4649
4851
|
}
|
|
4650
4852
|
var sleep = (ms) => ms > 0 ? new Promise((resolve) => setTimeout(resolve, ms)) : Promise.resolve();
|
|
4651
4853
|
async function signBody(secret, body) {
|
|
4652
|
-
const subtle = _optionalChain([globalThis, 'access',
|
|
4854
|
+
const subtle = _optionalChain([globalThis, 'access', _74 => _74.crypto, 'optionalAccess', _75 => _75.subtle]);
|
|
4653
4855
|
if (!subtle) return null;
|
|
4654
4856
|
try {
|
|
4655
4857
|
const enc = new TextEncoder();
|
|
@@ -4659,7 +4861,7 @@ async function signBody(secret, body) {
|
|
|
4659
4861
|
const sig = await subtle.sign("HMAC", key, enc.encode(body));
|
|
4660
4862
|
const hex = Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
4661
4863
|
return `sha256=${hex}`;
|
|
4662
|
-
} catch (
|
|
4864
|
+
} catch (e38) {
|
|
4663
4865
|
return null;
|
|
4664
4866
|
}
|
|
4665
4867
|
}
|
|
@@ -4719,8 +4921,8 @@ async function deliverReceipt(receipt, options) {
|
|
|
4719
4921
|
const retryable = status === void 0 ? true : isRetryableStatus(status);
|
|
4720
4922
|
const willRetry = !ok && retryable && attempt < maxAttempts;
|
|
4721
4923
|
try {
|
|
4722
|
-
_optionalChain([onAttempt, 'optionalCall',
|
|
4723
|
-
} catch (
|
|
4924
|
+
_optionalChain([onAttempt, 'optionalCall', _76 => _76({ attempt, ok, ...status !== void 0 ? { status } : {}, ...error ? { error } : {}, willRetry })]);
|
|
4925
|
+
} catch (e39) {
|
|
4724
4926
|
}
|
|
4725
4927
|
if (ok) return { delivered: true, attempts: attempt, status };
|
|
4726
4928
|
if (!willRetry) {
|
|
@@ -4822,4 +5024,15 @@ async function deliverReceipt(receipt, options) {
|
|
|
4822
5024
|
|
|
4823
5025
|
|
|
4824
5026
|
|
|
4825
|
-
|
|
5027
|
+
|
|
5028
|
+
|
|
5029
|
+
|
|
5030
|
+
|
|
5031
|
+
|
|
5032
|
+
|
|
5033
|
+
|
|
5034
|
+
|
|
5035
|
+
|
|
5036
|
+
|
|
5037
|
+
|
|
5038
|
+
exports.BRAND = BRAND; exports.CHAINS = CHAINS; exports.ConfirmationTimeoutError = _chunkU35MG4TFcjs.ConfirmationTimeoutError; exports.DIRECTORY_INFO = DIRECTORY_INFO; exports.EIP3009_TYPES = EIP3009_TYPES; exports.EXACT_NETWORK_SLUGS = EXACT_NETWORK_SLUGS; exports.GENERATOR = GENERATOR; exports.HEADER_REQUIRED = HEADER_REQUIRED; exports.HEADER_RESPONSE = HEADER_RESPONSE; exports.HEADER_RESPONSE_V1 = HEADER_RESPONSE_V1; exports.HEADER_SIGNATURE = HEADER_SIGNATURE; exports.HEADER_SIGNATURE_V1 = HEADER_SIGNATURE_V1; exports.InsufficientFundsError = _chunkU35MG4TFcjs.InsufficientFundsError; exports.InvalidEnvelopeError = _chunkU35MG4TFcjs.InvalidEnvelopeError; exports.KNOWN_FACILITATORS = KNOWN_FACILITATORS; exports.MaxRetriesExceededError = _chunkU35MG4TFcjs.MaxRetriesExceededError; exports.MissingDriverError = _chunkU35MG4TFcjs.MissingDriverError; exports.NoCompatibleAcceptError = _chunkU35MG4TFcjs.NoCompatibleAcceptError; exports.NonReplayableBodyError = _chunkU35MG4TFcjs.NonReplayableBodyError; exports.PERMIT2_ADDRESS = PERMIT2_ADDRESS; exports.PERMIT2_PROXY_CHAIN_IDS = PERMIT2_PROXY_CHAIN_IDS; exports.PERMIT2_WITNESS_TYPES = PERMIT2_WITNESS_TYPES; exports.PIPRAIL_AGENT_GUIDE = PIPRAIL_AGENT_GUIDE; exports.POWERED_BY = POWERED_BY; exports.PaymentDeclinedError = _chunkU35MG4TFcjs.PaymentDeclinedError; exports.PaymentTimeoutError = _chunkU35MG4TFcjs.PaymentTimeoutError; exports.PipRailClient = PipRailClient; exports.PipRailError = _chunkU35MG4TFcjs.PipRailError; exports.REGISTER_ATTRIBUTION = REGISTER_ATTRIBUTION; exports.RecipientNotReadyError = _chunkU35MG4TFcjs.RecipientNotReadyError; exports.SettlementError = _chunkU35MG4TFcjs.SettlementError; exports.UnknownTokenError = _chunkU35MG4TFcjs.UnknownTokenError; exports.UnsupportedNetworkError = _chunkU35MG4TFcjs.UnsupportedNetworkError; exports.UnsupportedSchemeError = _chunkU35MG4TFcjs.UnsupportedSchemeError; exports.WalletRequiredError = _chunkU35MG4TFcjs.WalletRequiredError; exports.WrongChainError = _chunkU35MG4TFcjs.WrongChainError; exports.WrongFamilyError = _chunkU35MG4TFcjs.WrongFamilyError; exports.X402_EXACT_PERMIT2_PROXY = X402_EXACT_PERMIT2_PROXY; exports.agentGuide = agentGuide; exports.appendAttribution = appendAttribution; exports.buildBazaarExtension = buildBazaarExtension; exports.buildChallengeHeader = buildChallengeHeader; exports.buildExactAuthorization = buildExactAuthorization; exports.buildExactSignatureHeader = buildExactSignatureHeader; exports.buildOpenApi = buildOpenApi; exports.buildReceiptHeader = buildReceiptHeader; exports.buildSelfDescription = buildSelfDescription; exports.buildSignatureHeader = buildSignatureHeader; exports.buildWellKnownX402 = buildWellKnownX402; exports.buildX402DnsTxt = buildX402DnsTxt; exports.chainIdForExactNetwork = chainIdForExactNetwork; exports.claim402IndexDomain = claim402IndexDomain; exports.classifyChallenge = classifyChallenge; exports.createPaymentGate = createPaymentGate; exports.decorateOutcome = decorateOutcome; exports.deliverReceipt = deliverReceipt; exports.describeChallenge = describeChallenge; exports.discoveryHeaders = discoveryHeaders; exports.eip3009Abi = eip3009Abi; exports.encodeXPaymentHeader = encodeXPaymentHeader; exports.evaluatePolicy = evaluatePolicy; exports.explainDecline = explainDecline; exports.facilitatorCoverage = facilitatorCoverage; exports.firstKeylessFacilitator = firstKeylessFacilitator; exports.formatSpendReport = formatSpendReport; exports.getDirectoryInfo = getDirectoryInfo; exports.isPermit2ProxyChain = isPermit2ProxyChain; exports.knownFacilitatorsFor = knownFacilitatorsFor; exports.normalizeNetwork = normalizeNetwork; exports.parseChallenge = parseChallenge; exports.parseExactPaymentHeader = parseExactPaymentHeader; exports.parseExactRequirements = parseExactRequirements; exports.parseFacilitatorSupported = parseFacilitatorSupported; exports.parseReceipt = parseReceipt; exports.parseSettleResponse = parseSettleResponse; exports.parseSignatureHeader = parseSignatureHeader; exports.paymentTools = paymentTools; exports.pickAccept = pickAccept; exports.planAcross = planAcross; exports.readExactDomain = readExactDomain; exports.register402Index = register402Index; exports.registerDriver = registerDriver; exports.registerX402Scan = registerX402Scan; exports.renderLandingPage = renderLandingPage; exports.requirePayment = requirePayment; exports.resolveChain = resolveChain; exports.searchOpenIndexes = searchOpenIndexes; exports.settleViaFacilitator = settleViaFacilitator; exports.summarizePlan = summarizePlan; exports.toInsufficientFundsError = _chunkU35MG4TFcjs.toInsufficientFundsError; exports.toInvalidBody = toInvalidBody; exports.verify402IndexDomain = verify402IndexDomain;
|