@piprail/sdk 1.12.0 → 1.13.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 +23 -0
- package/README.md +21 -9
- package/dist/index.cjs +128 -80
- package/dist/index.d.cts +56 -7
- package/dist/index.d.ts +56 -7
- package/dist/index.js +108 -60
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,28 @@ 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.13.0] — 2026-06-10
|
|
8
|
+
|
|
9
|
+
### Added — gate `discovery` option (one flag → x402scan-listable)
|
|
10
|
+
- **`createPaymentGate`/`requirePayment` now take an opt-in `discovery` option** that emits an
|
|
11
|
+
`extensions.bazaar` block **in the 402 challenge itself** — so the gate alone satisfies x402scan's
|
|
12
|
+
mandatory input-schema check (no separately-served file needed). `discovery: true` for a no-input
|
|
13
|
+
GET, or a `DiscoveryDescriptor` (`{ method, queryParams, output }`). Omitting it leaves the challenge
|
|
14
|
+
byte-identical. New export `buildBazaarExtension` + the `DiscoveryDescriptor`/`BazaarExtension` types.
|
|
15
|
+
- `DomainClaim` now also surfaces `verificationToken`, and `verificationHash` is **always** populated —
|
|
16
|
+
from the API, or computed as `sha256(verificationToken)` — so an agent always has the exact bytes to serve.
|
|
17
|
+
|
|
18
|
+
### Fixed — conformance bug hunt (20-agent audit, every finding verified against the live API)
|
|
19
|
+
- **`hostOf` returned `''` for a bare `host:port`** (`new URL('x.com:8080')` parses the host as a scheme) —
|
|
20
|
+
`claimDomain`/`verifyDomain` now extract the host correctly.
|
|
21
|
+
- **`indexes.ts` base64 was Latin1-only** (`btoa`) — now UTF-8-safe, matching `x402.ts` (a non-ASCII SIWX
|
|
22
|
+
field could have thrown in the browser).
|
|
23
|
+
- **SIWX message** now reads `chainId` from `supportedChains[]` as a fallback (not only `info.chainId`),
|
|
24
|
+
so it always signs the correct `Chain ID`.
|
|
25
|
+
- Removed an invented `x-payment-info.bazaar:{discoverable:true}` marker from `buildOpenApi` (no index read it).
|
|
26
|
+
- Documented the caveat that the open indexes' agents are standard `exact` clients — advertise an `exact`
|
|
27
|
+
rail to be *payable*, not just listed (README + the `piprail_register` MCP tool).
|
|
28
|
+
|
|
7
29
|
## [1.12.0] — 2026-06-09
|
|
8
30
|
|
|
9
31
|
### Added — One-call domain verification (pending-review → searchable)
|
|
@@ -593,6 +615,7 @@ straight into your wallet. The API is small and self-contained.
|
|
|
593
615
|
to your wallet; PipRail never holds funds.
|
|
594
616
|
- `viem ^2.21` is a peer dependency. Node 20+ or a modern browser.
|
|
595
617
|
|
|
618
|
+
[1.13.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
596
619
|
[1.12.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
597
620
|
[1.11.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
598
621
|
[1.10.0]: https://www.npmjs.com/package/@piprail/sdk
|
package/README.md
CHANGED
|
@@ -206,22 +206,34 @@ listing won't appear here, so don't read that absence as failure. `network` defa
|
|
|
206
206
|
chain); pass `'any'` for every chain, or a CAIP-2 id (`'eip155:8453'`). Slugs map to CAIP-2 via
|
|
207
207
|
`SLUG_TO_CAIP2`; an unresolved network is kept, never hidden.
|
|
208
208
|
|
|
209
|
-
**4) Make your endpoint self-describing**
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
listing accepted:
|
|
209
|
+
**4) Make your endpoint self-describing.** **x402scan REQUIRES an input schema or it won't list you.**
|
|
210
|
+
The simplest path: set the gate's `discovery` option — it emits an `extensions.bazaar` block **in the 402
|
|
211
|
+
itself**, so the challenge alone is x402scan-listable (no extra file to serve):
|
|
213
212
|
|
|
214
213
|
```ts
|
|
215
|
-
|
|
214
|
+
// `discovery: true` for a no-input GET, or describe the request:
|
|
215
|
+
const gate = createPaymentGate({
|
|
216
|
+
chain: 'base', token: 'USDC', amount: '0.05', payTo,
|
|
217
|
+
exact: { settle: { facilitator: 'https://facilitator.payai.network' } }, // be payable by exact clients (see caveat)
|
|
218
|
+
discovery: { method: 'GET', output: { type: 'json', example: { ok: true } } },
|
|
219
|
+
})
|
|
220
|
+
```
|
|
216
221
|
|
|
217
|
-
|
|
222
|
+
Optionally also serve the static discovery files (richer listings; OpenAPI carries the `x-generator`
|
|
223
|
+
attribution stamp) from your own origin — all pure, no I/O:
|
|
224
|
+
|
|
225
|
+
```ts
|
|
226
|
+
import { buildOpenApi, buildWellKnownX402, buildX402DnsTxt } from '@piprail/sdk'
|
|
218
227
|
const desc = await gate.describe('https://api.example.com/report')
|
|
219
|
-
const openapi = buildOpenApi({ origin: 'https://api.example.com', resources: [desc] })
|
|
220
|
-
|
|
221
|
-
const wellKnown = buildWellKnownX402({ resources: [desc] }) // serve at /.well-known/x402
|
|
228
|
+
const openapi = buildOpenApi({ origin: 'https://api.example.com', resources: [desc] }) // → /openapi.json
|
|
229
|
+
const wellKnown = buildWellKnownX402({ resources: [desc] }) // → /.well-known/x402
|
|
222
230
|
// buildX402DnsTxt(...) emits the _x402 DNS line too.
|
|
223
231
|
```
|
|
224
232
|
|
|
233
|
+
> **Caveat — be *payable*, not just listed.** The open indexes' agents are overwhelmingly standard
|
|
234
|
+
> `exact` clients; a default `onchain-proof`-only gate gets listed but they can't pay it. Advertise an
|
|
235
|
+
> `exact` rail (above) so a discovered resource is actually payable.
|
|
236
|
+
|
|
225
237
|
**Know each index before you call** — the facts are one import, `DIRECTORY_INFO`, and `register()`
|
|
226
238
|
projects them onto every outcome (`visibility` + `note`), so an agent never has to guess:
|
|
227
239
|
|
package/dist/index.cjs
CHANGED
|
@@ -1593,11 +1593,14 @@ async function claim402IndexDomain(domainOrUrl, opts = {}) {
|
|
|
1593
1593
|
if (!res.ok) {
|
|
1594
1594
|
return { ok: false, domain, httpStatus: res.status, detail: _nullishCoalesce(pickString(body, "error", "detail", "message"), () => ( `402 Index claim returned HTTP ${res.status}.`)) };
|
|
1595
1595
|
}
|
|
1596
|
+
const verificationToken = pickString(body, "verification_token");
|
|
1597
|
+
const verificationHash = await _asyncNullishCoalesce(pickString(body, "verification_hash"), async () => ( (verificationToken ? await sha256Hex(verificationToken) : void 0)));
|
|
1596
1598
|
return {
|
|
1597
1599
|
ok: true,
|
|
1598
1600
|
domain,
|
|
1599
1601
|
httpStatus: res.status,
|
|
1600
|
-
...optionalString("verificationHash",
|
|
1602
|
+
...optionalString("verificationHash", verificationHash),
|
|
1603
|
+
...optionalString("verificationToken", verificationToken),
|
|
1601
1604
|
...optionalString("verificationUrl", pickString(body, "verification_url")),
|
|
1602
1605
|
...optionalString("instructions", pickString(body, "instructions"))
|
|
1603
1606
|
};
|
|
@@ -1605,6 +1608,10 @@ async function claim402IndexDomain(domainOrUrl, opts = {}) {
|
|
|
1605
1608
|
return { ok: false, domain, detail: errMsg(err) };
|
|
1606
1609
|
}
|
|
1607
1610
|
}
|
|
1611
|
+
async function sha256Hex(input) {
|
|
1612
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(input));
|
|
1613
|
+
return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1614
|
+
}
|
|
1608
1615
|
async function verify402IndexDomain(domainOrUrl) {
|
|
1609
1616
|
const domain = hostOf(domainOrUrl);
|
|
1610
1617
|
try {
|
|
@@ -1634,6 +1641,12 @@ async function readSiwxInfo(res) {
|
|
|
1634
1641
|
const ext = body.extensions;
|
|
1635
1642
|
const siwx = _optionalChain([ext, 'optionalAccess', _8 => _8["sign-in-with-x"]]);
|
|
1636
1643
|
const info = _nullishCoalesce(_optionalChain([siwx, 'optionalAccess', _9 => _9.info]), () => ( siwx));
|
|
1644
|
+
if (info && info.chainId == null && Array.isArray(_optionalChain([siwx, 'optionalAccess', _10 => _10.supportedChains]))) {
|
|
1645
|
+
const evm = siwx.supportedChains.find(
|
|
1646
|
+
(c) => typeof _optionalChain([c, 'optionalAccess', _11 => _11.chainId]) === "string" && c.chainId.startsWith("eip155:")
|
|
1647
|
+
);
|
|
1648
|
+
if (evm && typeof evm.chainId === "string") info.chainId = evm.chainId;
|
|
1649
|
+
}
|
|
1637
1650
|
if (info && typeof info.domain === "string" && info.domain.length > 0 && typeof info.nonce === "string" && info.nonce.length > 0 && typeof info.uri === "string" && info.uri.length > 0) {
|
|
1638
1651
|
return info;
|
|
1639
1652
|
}
|
|
@@ -1686,7 +1699,7 @@ function mapRails(accepts) {
|
|
|
1686
1699
|
}
|
|
1687
1700
|
function matchesQuery(r, query) {
|
|
1688
1701
|
const q = query.toLowerCase();
|
|
1689
|
-
return r.resource.toLowerCase().includes(q) || (_nullishCoalesce(_optionalChain([r, 'access',
|
|
1702
|
+
return r.resource.toLowerCase().includes(q) || (_nullishCoalesce(_optionalChain([r, 'access', _12 => _12.name, 'optionalAccess', _13 => _13.toLowerCase, 'call', _14 => _14(), 'access', _15 => _15.includes, 'call', _16 => _16(q)]), () => ( false))) || (_nullishCoalesce(_optionalChain([r, 'access', _17 => _17.description, 'optionalAccess', _18 => _18.toLowerCase, 'call', _19 => _19(), 'access', _20 => _20.includes, 'call', _21 => _21(q)]), () => ( false)));
|
|
1690
1703
|
}
|
|
1691
1704
|
function pickString(o, ...keys) {
|
|
1692
1705
|
for (const k of keys) {
|
|
@@ -1717,7 +1730,8 @@ function firstArray(o, ...keys) {
|
|
|
1717
1730
|
}
|
|
1718
1731
|
function hostOf(url) {
|
|
1719
1732
|
try {
|
|
1720
|
-
|
|
1733
|
+
const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(url) ? url : `https://${url}`;
|
|
1734
|
+
return new URL(withScheme).hostname || url;
|
|
1721
1735
|
} catch (e20) {
|
|
1722
1736
|
return url;
|
|
1723
1737
|
}
|
|
@@ -1726,8 +1740,13 @@ function errMsg(err) {
|
|
|
1726
1740
|
return err instanceof Error ? err.message : String(err);
|
|
1727
1741
|
}
|
|
1728
1742
|
function encodeBase642(str) {
|
|
1729
|
-
if (typeof btoa === "function") return btoa(str);
|
|
1730
1743
|
if (typeof Buffer !== "undefined") return Buffer.from(str, "utf8").toString("base64");
|
|
1744
|
+
if (typeof btoa === "function" && typeof TextEncoder !== "undefined") {
|
|
1745
|
+
const bytes = new TextEncoder().encode(str);
|
|
1746
|
+
let binary = "";
|
|
1747
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
1748
|
+
return btoa(binary);
|
|
1749
|
+
}
|
|
1731
1750
|
throw new Error("No base64 encoder available in this runtime.");
|
|
1732
1751
|
}
|
|
1733
1752
|
|
|
@@ -1824,7 +1843,7 @@ var SpendLedger = (_class = class {constructor() { _class.prototype.__init.call(
|
|
|
1824
1843
|
}
|
|
1825
1844
|
/** Running total (base units) already spent on this (network, asset). */
|
|
1826
1845
|
totalFor(network, asset) {
|
|
1827
|
-
return _nullishCoalesce(_optionalChain([this, 'access',
|
|
1846
|
+
return _nullishCoalesce(_optionalChain([this, 'access', _22 => _22.buckets, 'access', _23 => _23.get, 'call', _24 => _24(keyFor(network, asset)), 'optionalAccess', _25 => _25.total]), () => ( 0n));
|
|
1828
1847
|
}
|
|
1829
1848
|
/** An immutable snapshot of all spend so far. */
|
|
1830
1849
|
summary() {
|
|
@@ -1898,7 +1917,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1898
1917
|
* as-is) or a plain object (serialised as JSON).
|
|
1899
1918
|
*/
|
|
1900
1919
|
post(url, body, init) {
|
|
1901
|
-
const headers = new Headers(_optionalChain([init, 'optionalAccess',
|
|
1920
|
+
const headers = new Headers(_optionalChain([init, 'optionalAccess', _26 => _26.headers]));
|
|
1902
1921
|
let payload;
|
|
1903
1922
|
if (body === void 0 || body === null) {
|
|
1904
1923
|
payload = void 0;
|
|
@@ -1929,7 +1948,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1929
1948
|
* "0.05 USDC on Base, within budget → pay it." No funds move.
|
|
1930
1949
|
*/
|
|
1931
1950
|
async quote(url, init) {
|
|
1932
|
-
const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess',
|
|
1951
|
+
const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _27 => _27.method]), () => ( "GET")) });
|
|
1933
1952
|
if (res.status !== 402) return null;
|
|
1934
1953
|
const { quote } = await this.resolveChallenge(url, res);
|
|
1935
1954
|
return quote;
|
|
@@ -1948,7 +1967,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1948
1967
|
* on Tron, where a USD₮ transfer can cost real TRX.
|
|
1949
1968
|
*/
|
|
1950
1969
|
async estimateCost(url, init) {
|
|
1951
|
-
const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess',
|
|
1970
|
+
const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _28 => _28.method]), () => ( "GET")) });
|
|
1952
1971
|
if (res.status !== 402) return null;
|
|
1953
1972
|
const { net, accept, quote } = await this.resolveChallenge(url, res);
|
|
1954
1973
|
const cost = await net.estimateCost(accept);
|
|
@@ -1979,7 +1998,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1979
1998
|
* the plan yourself. No funds move.
|
|
1980
1999
|
*/
|
|
1981
2000
|
async planPayment(url, init) {
|
|
1982
|
-
const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess',
|
|
2001
|
+
const res = await fetch(url, { ..._nullishCoalesce(init, () => ( {})), method: _nullishCoalesce(_optionalChain([init, 'optionalAccess', _29 => _29.method]), () => ( "GET")) });
|
|
1983
2002
|
if (res.status !== 402) return null;
|
|
1984
2003
|
const challenge = await parseChallenge(res);
|
|
1985
2004
|
if (!challenge) {
|
|
@@ -2146,7 +2165,7 @@ var PipRailClient = (_class2 = class {
|
|
|
2146
2165
|
* streams throw `NonReplayableBodyError`.
|
|
2147
2166
|
*/
|
|
2148
2167
|
async fetch(url, init) {
|
|
2149
|
-
const body = _optionalChain([init, 'optionalAccess',
|
|
2168
|
+
const body = _optionalChain([init, 'optionalAccess', _30 => _30.body]);
|
|
2150
2169
|
if (body !== void 0 && body !== null && !isReplayableBodyInit(body)) {
|
|
2151
2170
|
throw new (0, _chunkMDLZJGLYcjs.NonReplayableBodyError)(
|
|
2152
2171
|
"fetch(): init.body is not replayable. Pass a string, FormData, URLSearchParams, ArrayBuffer, or Blob \u2014 not a ReadableStream."
|
|
@@ -2158,7 +2177,7 @@ var PipRailClient = (_class2 = class {
|
|
|
2158
2177
|
const { net, wallet, challenge } = resolved;
|
|
2159
2178
|
let accept = resolved.accept;
|
|
2160
2179
|
let quote = resolved.quote;
|
|
2161
|
-
const autoRoute = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'optionalAccess',
|
|
2180
|
+
const autoRoute = _nullishCoalesce(_nullishCoalesce(_optionalChain([init, 'optionalAccess', _31 => _31.autoRoute]), () => ( this.opts.autoRoute)), () => ( false));
|
|
2162
2181
|
if (autoRoute) {
|
|
2163
2182
|
const plan = await this.planFromChallenge(net, wallet, challenge, url);
|
|
2164
2183
|
if (!plan.best) {
|
|
@@ -2320,8 +2339,8 @@ var PipRailClient = (_class2 = class {
|
|
|
2320
2339
|
}
|
|
2321
2340
|
const amountBase = BigInt(accept.amount);
|
|
2322
2341
|
const described = net.describeAsset(accept.asset);
|
|
2323
|
-
const decimals = _nullishCoalesce(_optionalChain([described, 'optionalAccess',
|
|
2324
|
-
const symbol = _nullishCoalesce(_optionalChain([described, 'optionalAccess',
|
|
2342
|
+
const decimals = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _32 => _32.decimals]), () => ( accept.extra.decimals));
|
|
2343
|
+
const symbol = _nullishCoalesce(_optionalChain([described, 'optionalAccess', _33 => _33.symbol]), () => ( accept.extra.symbol));
|
|
2325
2344
|
const amountFormatted = _chunkMDLZJGLYcjs.formatUnits.call(void 0, amountBase, decimals);
|
|
2326
2345
|
const intent = {
|
|
2327
2346
|
host: hostOf2(url),
|
|
@@ -2430,7 +2449,7 @@ var PipRailClient = (_class2 = class {
|
|
|
2430
2449
|
accepted: accept,
|
|
2431
2450
|
payload: { nonce: accept.extra.nonce, txHash: ref }
|
|
2432
2451
|
};
|
|
2433
|
-
const headers = new Headers(_optionalChain([originalInit, 'optionalAccess',
|
|
2452
|
+
const headers = new Headers(_optionalChain([originalInit, 'optionalAccess', _34 => _34.headers]));
|
|
2434
2453
|
headers.set(HEADER_SIGNATURE, buildSignatureHeader(signature));
|
|
2435
2454
|
let lastResponse = null;
|
|
2436
2455
|
let lastReason = null;
|
|
@@ -2445,7 +2464,7 @@ var PipRailClient = (_class2 = class {
|
|
|
2445
2464
|
() => timeoutController.abort(),
|
|
2446
2465
|
this.retryTimeoutMs
|
|
2447
2466
|
);
|
|
2448
|
-
const signal = _optionalChain([originalInit, 'optionalAccess',
|
|
2467
|
+
const signal = _optionalChain([originalInit, 'optionalAccess', _35 => _35.signal]) && typeof AbortSignal.any === "function" ? AbortSignal.any([timeoutController.signal, originalInit.signal]) : timeoutController.signal;
|
|
2449
2468
|
try {
|
|
2450
2469
|
lastResponse = await fetch(url, {
|
|
2451
2470
|
..._nullishCoalesce(originalInit, () => ( {})),
|
|
@@ -2518,10 +2537,10 @@ function buildFundingHint(options, chainLabel) {
|
|
|
2518
2537
|
return `Couldn't fully read your wallet on ${chainLabel} (RPC throttled) \u2014 retry; you may already be able to pay ${target.quote.amountFormatted} ${sym}.`;
|
|
2519
2538
|
}
|
|
2520
2539
|
const parts = [];
|
|
2521
|
-
if (target.blockers.includes("INSUFFICIENT_TOKEN") && _optionalChain([target, 'access',
|
|
2540
|
+
if (target.blockers.includes("INSUFFICIENT_TOKEN") && _optionalChain([target, 'access', _36 => _36.shortfall, 'optionalAccess', _37 => _37.token])) {
|
|
2522
2541
|
parts.push(`top up ${target.shortfall.token} ${sym}`);
|
|
2523
2542
|
}
|
|
2524
|
-
if (target.blockers.includes("INSUFFICIENT_GAS") && _optionalChain([target, 'access',
|
|
2543
|
+
if (target.blockers.includes("INSUFFICIENT_GAS") && _optionalChain([target, 'access', _38 => _38.shortfall, 'optionalAccess', _39 => _39.native])) {
|
|
2525
2544
|
parts.push(`add ~${target.shortfall.native} ${target.cost.feeSymbol} for gas`);
|
|
2526
2545
|
}
|
|
2527
2546
|
return parts.length ? `Can't settle on ${chainLabel}: ${parts.join(" and ")} (to pay ${target.quote.amountFormatted} ${sym}).` : `Can't settle on ${chainLabel} for ${target.quote.amountFormatted} ${sym}.`;
|
|
@@ -2535,7 +2554,7 @@ async function planAcross(clients, url, init) {
|
|
|
2535
2554
|
const status = best ? "ready" : options.some((o) => o.state === "unknown") ? "unknown" : "blocked";
|
|
2536
2555
|
return {
|
|
2537
2556
|
url,
|
|
2538
|
-
network: _nullishCoalesce(_optionalChain([best, 'optionalAccess',
|
|
2557
|
+
network: _nullishCoalesce(_optionalChain([best, 'optionalAccess', _40 => _40.accept, 'access', _41 => _41.network]), () => ( live[0].network)),
|
|
2539
2558
|
status,
|
|
2540
2559
|
payable: best !== null,
|
|
2541
2560
|
best,
|
|
@@ -2568,8 +2587,8 @@ function isReplayableBodyInit(value) {
|
|
|
2568
2587
|
async function readInvalidReason(response) {
|
|
2569
2588
|
try {
|
|
2570
2589
|
const body = await response.clone().json();
|
|
2571
|
-
const ext = _optionalChain([body, 'optionalAccess',
|
|
2572
|
-
const piprail = _optionalChain([ext, 'optionalAccess',
|
|
2590
|
+
const ext = _optionalChain([body, 'optionalAccess', _42 => _42.extensions]);
|
|
2591
|
+
const piprail = _optionalChain([ext, 'optionalAccess', _43 => _43.piprail]);
|
|
2573
2592
|
if (piprail && typeof piprail.code === "string") {
|
|
2574
2593
|
return {
|
|
2575
2594
|
error: piprail.code,
|
|
@@ -2773,7 +2792,7 @@ function paymentTools(client) {
|
|
|
2773
2792
|
},
|
|
2774
2793
|
{
|
|
2775
2794
|
name: "piprail_register",
|
|
2776
|
-
description: "List an x402 payment-gated resource YOU run on the open indexes so other agents can discover it. Default target is 402 Index \u2014 no auth, no signature, no payment; a self-registered listing is pending review (verify your domain on 402index.io for instant approval). Returns one outcome per index ({ source, ok, detail, visibility, note }); a step the chain can't satisfy comes back ok:false with the reason. Moves no funds; nothing is PipRail-hosted.",
|
|
2795
|
+
description: "List an x402 payment-gated resource YOU run on the open indexes so other agents can discover it. Default target is 402 Index \u2014 no auth, no signature, no payment; a self-registered listing is pending review (verify your domain on 402index.io for instant approval). Returns one outcome per index ({ source, ok, detail, visibility, note }); a step the chain can't satisfy comes back ok:false with the reason. Moves no funds; nothing is PipRail-hosted. NOTE: index/agent payers are overwhelmingly standard `exact` clients \u2014 a default onchain-proof-only gate gets listed but they cannot pay it, so add an `exact` rail (and set the gate's `discovery` option, required for x402scan) to be usefully discoverable AND payable.",
|
|
2777
2796
|
annotations: {
|
|
2778
2797
|
title: "Register an x402 endpoint",
|
|
2779
2798
|
readOnlyHint: false,
|
|
@@ -2807,6 +2826,87 @@ function paymentTools(client) {
|
|
|
2807
2826
|
];
|
|
2808
2827
|
}
|
|
2809
2828
|
|
|
2829
|
+
// src/discovery.ts
|
|
2830
|
+
var GENERATOR = "@piprail/sdk \xB7 https://piprail.com";
|
|
2831
|
+
function buildBazaarExtension(descriptor = {}) {
|
|
2832
|
+
const method = (_nullishCoalesce(descriptor.method, () => ( "GET"))).toUpperCase();
|
|
2833
|
+
const queryParams = _nullishCoalesce(descriptor.queryParams, () => ( {}));
|
|
2834
|
+
return {
|
|
2835
|
+
info: {
|
|
2836
|
+
input: { type: "http", method, queryParams },
|
|
2837
|
+
output: _nullishCoalesce(descriptor.output, () => ( { type: "json" }))
|
|
2838
|
+
},
|
|
2839
|
+
schema: {
|
|
2840
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
2841
|
+
type: "object",
|
|
2842
|
+
properties: {
|
|
2843
|
+
input: {
|
|
2844
|
+
type: "object",
|
|
2845
|
+
properties: {
|
|
2846
|
+
type: { type: "string", const: "http" },
|
|
2847
|
+
method: { type: "string", enum: ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"] },
|
|
2848
|
+
queryParams: { type: "object", properties: queryParams, additionalProperties: false }
|
|
2849
|
+
},
|
|
2850
|
+
required: ["type", "method"],
|
|
2851
|
+
additionalProperties: false
|
|
2852
|
+
}
|
|
2853
|
+
},
|
|
2854
|
+
required: ["input"]
|
|
2855
|
+
}
|
|
2856
|
+
};
|
|
2857
|
+
}
|
|
2858
|
+
function pathOf(url) {
|
|
2859
|
+
try {
|
|
2860
|
+
return new URL(url).pathname || "/";
|
|
2861
|
+
} catch (e26) {
|
|
2862
|
+
return url.startsWith("/") ? url : `/${url}`;
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
function buildOpenApi(input) {
|
|
2866
|
+
const paths = {};
|
|
2867
|
+
for (const r of input.resources) {
|
|
2868
|
+
const path = pathOf(r.url);
|
|
2869
|
+
const method = (_nullishCoalesce(r.method, () => ( "GET"))).toLowerCase();
|
|
2870
|
+
const op = {
|
|
2871
|
+
...r.description ? { summary: r.description } : {},
|
|
2872
|
+
responses: {
|
|
2873
|
+
"200": { description: "Paid \u2014 the resource." },
|
|
2874
|
+
"402": { description: "Payment required (x402)." }
|
|
2875
|
+
},
|
|
2876
|
+
"x-payment-info": {
|
|
2877
|
+
x402Version: 2,
|
|
2878
|
+
accepts: r.accepts
|
|
2879
|
+
}
|
|
2880
|
+
};
|
|
2881
|
+
paths[path] = { ..._nullishCoalesce(paths[path], () => ( {})), [method]: op };
|
|
2882
|
+
}
|
|
2883
|
+
return {
|
|
2884
|
+
openapi: "3.1.0",
|
|
2885
|
+
info: { title: _nullishCoalesce(input.title, () => ( "PipRail x402 resources")), version: _nullishCoalesce(input.version, () => ( "1.0.0")) },
|
|
2886
|
+
servers: [{ url: input.origin }],
|
|
2887
|
+
paths,
|
|
2888
|
+
// "Built with @piprail/sdk" — default on (opt out with attribution:false). At the
|
|
2889
|
+
// document ROOT so `info` stays exactly { title, version }.
|
|
2890
|
+
...input.attribution === false ? {} : { "x-generator": GENERATOR },
|
|
2891
|
+
...input.ownershipProofs && input.ownershipProofs.length > 0 ? { "x-agentcash-provenance": { ownershipProofs: input.ownershipProofs } } : {}
|
|
2892
|
+
};
|
|
2893
|
+
}
|
|
2894
|
+
function buildWellKnownX402(input) {
|
|
2895
|
+
return {
|
|
2896
|
+
version: 1,
|
|
2897
|
+
resources: input.resources.map((r) => r.url),
|
|
2898
|
+
...input.ownershipProofs && input.ownershipProofs.length > 0 ? { ownershipProofs: input.ownershipProofs } : {}
|
|
2899
|
+
};
|
|
2900
|
+
}
|
|
2901
|
+
function buildX402DnsTxt(input) {
|
|
2902
|
+
const descriptor = input.descriptor ? `descriptor=${input.descriptor};` : "";
|
|
2903
|
+
return {
|
|
2904
|
+
name: `_x402.${input.host}`,
|
|
2905
|
+
type: "TXT",
|
|
2906
|
+
value: `v=x4021;${descriptor}url=${input.discoveryUrl}`
|
|
2907
|
+
};
|
|
2908
|
+
}
|
|
2909
|
+
|
|
2810
2910
|
// src/facilitator.ts
|
|
2811
2911
|
function safeStringify(value) {
|
|
2812
2912
|
return JSON.stringify(value, (_k, v) => typeof v === "bigint" ? v.toString() : v);
|
|
@@ -2831,7 +2931,7 @@ async function post(url, body, headers) {
|
|
|
2831
2931
|
let json = null;
|
|
2832
2932
|
try {
|
|
2833
2933
|
json = await res.json();
|
|
2834
|
-
} catch (
|
|
2934
|
+
} catch (e27) {
|
|
2835
2935
|
}
|
|
2836
2936
|
return { status: res.status, json };
|
|
2837
2937
|
}
|
|
@@ -3055,6 +3155,8 @@ function createPaymentGate(options) {
|
|
|
3055
3155
|
async function makeChallenge(resourceUrl, opts) {
|
|
3056
3156
|
const specs = await ready();
|
|
3057
3157
|
const nonce = genNonce();
|
|
3158
|
+
const bazaar = options.discovery ? { bazaar: buildBazaarExtension(options.discovery === true ? {} : options.discovery) } : void 0;
|
|
3159
|
+
const extensions = { ...bazaar, ..._optionalChain([opts, 'optionalAccess', _44 => _44.extensions]) };
|
|
3058
3160
|
const challenge2 = {
|
|
3059
3161
|
x402Version: 2,
|
|
3060
3162
|
resource: {
|
|
@@ -3062,8 +3164,8 @@ function createPaymentGate(options) {
|
|
|
3062
3164
|
...options.description ? { description: options.description } : {}
|
|
3063
3165
|
},
|
|
3064
3166
|
accepts: buildAccepts(specs, nonce),
|
|
3065
|
-
..._optionalChain([opts, 'optionalAccess',
|
|
3066
|
-
...
|
|
3167
|
+
..._optionalChain([opts, 'optionalAccess', _45 => _45.error]) ? { error: opts.error } : {},
|
|
3168
|
+
...Object.keys(extensions).length > 0 ? { extensions } : {}
|
|
3067
3169
|
};
|
|
3068
3170
|
return { challenge: challenge2, requiredHeader: buildChallengeHeader(challenge2) };
|
|
3069
3171
|
}
|
|
@@ -3085,7 +3187,7 @@ function createPaymentGate(options) {
|
|
|
3085
3187
|
if (options.onPaid) {
|
|
3086
3188
|
try {
|
|
3087
3189
|
options.onPaid(receipt);
|
|
3088
|
-
} catch (
|
|
3190
|
+
} catch (e28) {
|
|
3089
3191
|
}
|
|
3090
3192
|
}
|
|
3091
3193
|
}
|
|
@@ -3250,60 +3352,6 @@ function normaliseHeader(value) {
|
|
|
3250
3352
|
return value;
|
|
3251
3353
|
}
|
|
3252
3354
|
|
|
3253
|
-
// src/discovery.ts
|
|
3254
|
-
var GENERATOR = "@piprail/sdk \xB7 https://piprail.com";
|
|
3255
|
-
function pathOf(url) {
|
|
3256
|
-
try {
|
|
3257
|
-
return new URL(url).pathname || "/";
|
|
3258
|
-
} catch (e28) {
|
|
3259
|
-
return url.startsWith("/") ? url : `/${url}`;
|
|
3260
|
-
}
|
|
3261
|
-
}
|
|
3262
|
-
function buildOpenApi(input) {
|
|
3263
|
-
const paths = {};
|
|
3264
|
-
for (const r of input.resources) {
|
|
3265
|
-
const path = pathOf(r.url);
|
|
3266
|
-
const method = (_nullishCoalesce(r.method, () => ( "GET"))).toLowerCase();
|
|
3267
|
-
const op = {
|
|
3268
|
-
...r.description ? { summary: r.description } : {},
|
|
3269
|
-
responses: {
|
|
3270
|
-
"200": { description: "Paid \u2014 the resource." },
|
|
3271
|
-
"402": { description: "Payment required (x402)." }
|
|
3272
|
-
},
|
|
3273
|
-
"x-payment-info": {
|
|
3274
|
-
x402Version: 2,
|
|
3275
|
-
accepts: r.accepts,
|
|
3276
|
-
bazaar: { discoverable: true }
|
|
3277
|
-
}
|
|
3278
|
-
};
|
|
3279
|
-
paths[path] = { ..._nullishCoalesce(paths[path], () => ( {})), [method]: op };
|
|
3280
|
-
}
|
|
3281
|
-
return {
|
|
3282
|
-
openapi: "3.1.0",
|
|
3283
|
-
info: { title: _nullishCoalesce(input.title, () => ( "PipRail x402 resources")), version: _nullishCoalesce(input.version, () => ( "1.0.0")) },
|
|
3284
|
-
servers: [{ url: input.origin }],
|
|
3285
|
-
paths,
|
|
3286
|
-
// "Built with @piprail/sdk" — default on (opt out with attribution:false). At the
|
|
3287
|
-
// document ROOT so `info` stays exactly { title, version }.
|
|
3288
|
-
...input.attribution === false ? {} : { "x-generator": GENERATOR },
|
|
3289
|
-
...input.ownershipProofs && input.ownershipProofs.length > 0 ? { "x-agentcash-provenance": { ownershipProofs: input.ownershipProofs } } : {}
|
|
3290
|
-
};
|
|
3291
|
-
}
|
|
3292
|
-
function buildWellKnownX402(input) {
|
|
3293
|
-
return {
|
|
3294
|
-
version: 1,
|
|
3295
|
-
resources: input.resources.map((r) => r.url),
|
|
3296
|
-
...input.ownershipProofs && input.ownershipProofs.length > 0 ? { ownershipProofs: input.ownershipProofs } : {}
|
|
3297
|
-
};
|
|
3298
|
-
}
|
|
3299
|
-
function buildX402DnsTxt(input) {
|
|
3300
|
-
const descriptor = input.descriptor ? `descriptor=${input.descriptor};` : "";
|
|
3301
|
-
return {
|
|
3302
|
-
name: `_x402.${input.host}`,
|
|
3303
|
-
type: "TXT",
|
|
3304
|
-
value: `v=x4021;${descriptor}url=${input.discoveryUrl}`
|
|
3305
|
-
};
|
|
3306
|
-
}
|
|
3307
3355
|
|
|
3308
3356
|
|
|
3309
3357
|
|
|
@@ -3367,4 +3415,4 @@ function buildX402DnsTxt(input) {
|
|
|
3367
3415
|
|
|
3368
3416
|
|
|
3369
3417
|
|
|
3370
|
-
exports.CHAINS = CHAINS; exports.ConfirmationTimeoutError = _chunkMDLZJGLYcjs.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 = _chunkMDLZJGLYcjs.InsufficientFundsError; exports.InvalidEnvelopeError = _chunkMDLZJGLYcjs.InvalidEnvelopeError; exports.MaxRetriesExceededError = _chunkMDLZJGLYcjs.MaxRetriesExceededError; exports.MissingDriverError = _chunkMDLZJGLYcjs.MissingDriverError; exports.NoCompatibleAcceptError = _chunkMDLZJGLYcjs.NoCompatibleAcceptError; exports.NonReplayableBodyError = _chunkMDLZJGLYcjs.NonReplayableBodyError; exports.PaymentDeclinedError = _chunkMDLZJGLYcjs.PaymentDeclinedError; exports.PaymentTimeoutError = _chunkMDLZJGLYcjs.PaymentTimeoutError; exports.PipRailClient = PipRailClient; exports.PipRailError = _chunkMDLZJGLYcjs.PipRailError; exports.RecipientNotReadyError = _chunkMDLZJGLYcjs.RecipientNotReadyError; exports.SettlementError = _chunkMDLZJGLYcjs.SettlementError; exports.UnknownTokenError = _chunkMDLZJGLYcjs.UnknownTokenError; exports.UnsupportedNetworkError = _chunkMDLZJGLYcjs.UnsupportedNetworkError; exports.WrongChainError = _chunkMDLZJGLYcjs.WrongChainError; exports.WrongFamilyError = _chunkMDLZJGLYcjs.WrongFamilyError; exports.buildChallengeHeader = buildChallengeHeader; exports.buildExactAuthorization = buildExactAuthorization; exports.buildOpenApi = buildOpenApi; exports.buildReceiptHeader = buildReceiptHeader; exports.buildSignatureHeader = buildSignatureHeader; exports.buildWellKnownX402 = buildWellKnownX402; exports.buildX402DnsTxt = buildX402DnsTxt; exports.chainIdForExactNetwork = chainIdForExactNetwork; exports.claim402IndexDomain = claim402IndexDomain; exports.createPaymentGate = createPaymentGate; exports.decorateOutcome = decorateOutcome; exports.eip3009Abi = eip3009Abi; exports.encodeXPaymentHeader = encodeXPaymentHeader; exports.evaluatePolicy = evaluatePolicy; exports.getDirectoryInfo = getDirectoryInfo; exports.normalizeNetwork = normalizeNetwork; exports.parseChallenge = parseChallenge; exports.parseExactPaymentHeader = parseExactPaymentHeader; exports.parseExactRequirements = parseExactRequirements; exports.parseReceipt = parseReceipt; 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.requirePayment = requirePayment; exports.resolveChain = resolveChain; exports.searchOpenIndexes = searchOpenIndexes; exports.settleViaFacilitator = settleViaFacilitator; exports.toInsufficientFundsError = _chunkMDLZJGLYcjs.toInsufficientFundsError; exports.toInvalidBody = toInvalidBody; exports.verify402IndexDomain = verify402IndexDomain;
|
|
3418
|
+
exports.CHAINS = CHAINS; exports.ConfirmationTimeoutError = _chunkMDLZJGLYcjs.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 = _chunkMDLZJGLYcjs.InsufficientFundsError; exports.InvalidEnvelopeError = _chunkMDLZJGLYcjs.InvalidEnvelopeError; exports.MaxRetriesExceededError = _chunkMDLZJGLYcjs.MaxRetriesExceededError; exports.MissingDriverError = _chunkMDLZJGLYcjs.MissingDriverError; exports.NoCompatibleAcceptError = _chunkMDLZJGLYcjs.NoCompatibleAcceptError; exports.NonReplayableBodyError = _chunkMDLZJGLYcjs.NonReplayableBodyError; exports.PaymentDeclinedError = _chunkMDLZJGLYcjs.PaymentDeclinedError; exports.PaymentTimeoutError = _chunkMDLZJGLYcjs.PaymentTimeoutError; exports.PipRailClient = PipRailClient; exports.PipRailError = _chunkMDLZJGLYcjs.PipRailError; exports.RecipientNotReadyError = _chunkMDLZJGLYcjs.RecipientNotReadyError; exports.SettlementError = _chunkMDLZJGLYcjs.SettlementError; exports.UnknownTokenError = _chunkMDLZJGLYcjs.UnknownTokenError; exports.UnsupportedNetworkError = _chunkMDLZJGLYcjs.UnsupportedNetworkError; exports.WrongChainError = _chunkMDLZJGLYcjs.WrongChainError; exports.WrongFamilyError = _chunkMDLZJGLYcjs.WrongFamilyError; exports.buildBazaarExtension = buildBazaarExtension; exports.buildChallengeHeader = buildChallengeHeader; exports.buildExactAuthorization = buildExactAuthorization; exports.buildOpenApi = buildOpenApi; exports.buildReceiptHeader = buildReceiptHeader; exports.buildSignatureHeader = buildSignatureHeader; exports.buildWellKnownX402 = buildWellKnownX402; exports.buildX402DnsTxt = buildX402DnsTxt; exports.chainIdForExactNetwork = chainIdForExactNetwork; exports.claim402IndexDomain = claim402IndexDomain; exports.createPaymentGate = createPaymentGate; exports.decorateOutcome = decorateOutcome; exports.eip3009Abi = eip3009Abi; exports.encodeXPaymentHeader = encodeXPaymentHeader; exports.evaluatePolicy = evaluatePolicy; exports.getDirectoryInfo = getDirectoryInfo; exports.normalizeNetwork = normalizeNetwork; exports.parseChallenge = parseChallenge; exports.parseExactPaymentHeader = parseExactPaymentHeader; exports.parseExactRequirements = parseExactRequirements; exports.parseReceipt = parseReceipt; 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.requirePayment = requirePayment; exports.resolveChain = resolveChain; exports.searchOpenIndexes = searchOpenIndexes; exports.settleViaFacilitator = settleViaFacilitator; exports.toInsufficientFundsError = _chunkMDLZJGLYcjs.toInsufficientFundsError; exports.toInvalidBody = toInvalidBody; exports.verify402IndexDomain = verify402IndexDomain;
|
package/dist/index.d.cts
CHANGED
|
@@ -4370,9 +4370,14 @@ declare function registerX402Scan(input: {
|
|
|
4370
4370
|
interface DomainClaim {
|
|
4371
4371
|
ok: boolean;
|
|
4372
4372
|
domain: string;
|
|
4373
|
-
/**
|
|
4373
|
+
/** The exact text to serve as the ENTIRE body of `verificationUrl` — this is what
|
|
4374
|
+
* 402 Index fetches and checks (the SHA-256 of the token). Always populated on
|
|
4375
|
+
* success: read from the response, or computed as `sha256(verificationToken)` if
|
|
4376
|
+
* the API returns only the token. Serve THIS. */
|
|
4374
4377
|
verificationHash?: string;
|
|
4375
|
-
/**
|
|
4378
|
+
/** The raw 64-hex token 402 Index issued (the preimage of `verificationHash`). */
|
|
4379
|
+
verificationToken?: string;
|
|
4380
|
+
/** Where to serve `verificationHash` — your `https://<domain>/.well-known/402index-verify.txt`. */
|
|
4376
4381
|
verificationUrl?: string;
|
|
4377
4382
|
/** 402 Index's own human instructions. */
|
|
4378
4383
|
instructions?: string;
|
|
@@ -5129,10 +5134,6 @@ interface OpenApiOperation {
|
|
|
5129
5134
|
'x-payment-info': {
|
|
5130
5135
|
x402Version: 2;
|
|
5131
5136
|
accepts: PaymentRail[];
|
|
5132
|
-
/** Bazaar-style input schema marker so a strict index doesn't "skip" the op. */
|
|
5133
|
-
bazaar: {
|
|
5134
|
-
discoverable: true;
|
|
5135
|
-
};
|
|
5136
5137
|
};
|
|
5137
5138
|
}
|
|
5138
5139
|
/** x402scan's legacy origin file (`/.well-known/x402`). */
|
|
@@ -5141,6 +5142,46 @@ interface WellKnownX402 {
|
|
|
5141
5142
|
resources: string[];
|
|
5142
5143
|
ownershipProofs?: string[];
|
|
5143
5144
|
}
|
|
5145
|
+
/**
|
|
5146
|
+
* Describes a resource's INPUT for discovery. The open indexes that REQUIRE an
|
|
5147
|
+
* input schema (x402scan rejects a listing without one) read this from a
|
|
5148
|
+
* `extensions.bazaar` block. Pass it to a gate's `discovery` option (emits the
|
|
5149
|
+
* block in the 402 challenge) or build it directly with {@link buildBazaarExtension}.
|
|
5150
|
+
*/
|
|
5151
|
+
interface DiscoveryDescriptor {
|
|
5152
|
+
/** HTTP method the resource answers. Default `'GET'`. */
|
|
5153
|
+
method?: string;
|
|
5154
|
+
/** Query params the resource reads, as a JSON-Schema `properties` object
|
|
5155
|
+
* (name → schema). Default `{}` — a no-input GET. */
|
|
5156
|
+
queryParams?: Record<string, unknown>;
|
|
5157
|
+
/** Optional output hint (shape/example) for a richer listing. */
|
|
5158
|
+
output?: {
|
|
5159
|
+
type?: string;
|
|
5160
|
+
example?: unknown;
|
|
5161
|
+
};
|
|
5162
|
+
}
|
|
5163
|
+
/** The `extensions.bazaar` discovery block (the x402 "bazaar" convention the open
|
|
5164
|
+
* indexes parse: `info.input` describes the request, `schema` is its JSON Schema). */
|
|
5165
|
+
interface BazaarExtension {
|
|
5166
|
+
info: {
|
|
5167
|
+
input: {
|
|
5168
|
+
type: 'http';
|
|
5169
|
+
method: string;
|
|
5170
|
+
queryParams: Record<string, unknown>;
|
|
5171
|
+
};
|
|
5172
|
+
output?: {
|
|
5173
|
+
type?: string;
|
|
5174
|
+
example?: unknown;
|
|
5175
|
+
};
|
|
5176
|
+
};
|
|
5177
|
+
schema: Record<string, unknown>;
|
|
5178
|
+
}
|
|
5179
|
+
/**
|
|
5180
|
+
* Build the `extensions.bazaar` block that satisfies x402scan's mandatory input-schema
|
|
5181
|
+
* check, from a {@link DiscoveryDescriptor}. Pure. Defaults to a no-input GET — the
|
|
5182
|
+
* minimal shape a live x402scan listing accepts.
|
|
5183
|
+
*/
|
|
5184
|
+
declare function buildBazaarExtension(descriptor?: DiscoveryDescriptor): BazaarExtension;
|
|
5144
5185
|
/** The `_x402` DNS TXT pointer record (experimental draft). */
|
|
5145
5186
|
interface X402DnsRecord {
|
|
5146
5187
|
name: string;
|
|
@@ -5292,6 +5333,14 @@ interface RequirePaymentOptions {
|
|
|
5292
5333
|
* Omit to keep the gate exactly as today (`onchain-proof` only).
|
|
5293
5334
|
*/
|
|
5294
5335
|
exact?: ExactRailOption;
|
|
5336
|
+
/**
|
|
5337
|
+
* Make this gate's 402 self-describing for the open indexes — **x402scan REQUIRES
|
|
5338
|
+
* an input schema or it won't list the resource.** Set `true` for a no-input GET,
|
|
5339
|
+
* or pass a {@link DiscoveryDescriptor} to describe the request. Emits an
|
|
5340
|
+
* `extensions.bazaar` block in the 402 challenge. Opt-in; omitting it leaves the
|
|
5341
|
+
* challenge byte-identical to before.
|
|
5342
|
+
*/
|
|
5343
|
+
discovery?: boolean | DiscoveryDescriptor;
|
|
5295
5344
|
}
|
|
5296
5345
|
type VerifyPaymentResult = {
|
|
5297
5346
|
kind: 'paid';
|
|
@@ -5898,4 +5947,4 @@ declare function readExactDomain(publicClient: PublicClient, asset: string): Pro
|
|
|
5898
5947
|
version: string;
|
|
5899
5948
|
} | null>;
|
|
5900
5949
|
|
|
5901
|
-
export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoverySigner, type DiscoverySource, type DomainClaim, type DomainVerification, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, PaymentTimeoutError, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, type XrplToken, buildChallengeHeader, buildExactAuthorization, buildOpenApi, buildReceiptHeader, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, createPaymentGate, decorateOutcome, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, getDirectoryInfo, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseReceipt, parseSignatureHeader, paymentTools, pickAccept, planAcross, readExactDomain, register402Index, registerDriver, registerX402Scan, requirePayment, resolveChain, searchOpenIndexes, settleViaFacilitator, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };
|
|
5950
|
+
export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, type BazaarExtension, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoveryDescriptor, type DiscoverySigner, type DiscoverySource, type DomainClaim, type DomainVerification, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, PaymentTimeoutError, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, type XrplToken, buildBazaarExtension, buildChallengeHeader, buildExactAuthorization, buildOpenApi, buildReceiptHeader, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, createPaymentGate, decorateOutcome, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, getDirectoryInfo, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseReceipt, parseSignatureHeader, paymentTools, pickAccept, planAcross, readExactDomain, register402Index, registerDriver, registerX402Scan, requirePayment, resolveChain, searchOpenIndexes, settleViaFacilitator, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };
|
package/dist/index.d.ts
CHANGED
|
@@ -4370,9 +4370,14 @@ declare function registerX402Scan(input: {
|
|
|
4370
4370
|
interface DomainClaim {
|
|
4371
4371
|
ok: boolean;
|
|
4372
4372
|
domain: string;
|
|
4373
|
-
/**
|
|
4373
|
+
/** The exact text to serve as the ENTIRE body of `verificationUrl` — this is what
|
|
4374
|
+
* 402 Index fetches and checks (the SHA-256 of the token). Always populated on
|
|
4375
|
+
* success: read from the response, or computed as `sha256(verificationToken)` if
|
|
4376
|
+
* the API returns only the token. Serve THIS. */
|
|
4374
4377
|
verificationHash?: string;
|
|
4375
|
-
/**
|
|
4378
|
+
/** The raw 64-hex token 402 Index issued (the preimage of `verificationHash`). */
|
|
4379
|
+
verificationToken?: string;
|
|
4380
|
+
/** Where to serve `verificationHash` — your `https://<domain>/.well-known/402index-verify.txt`. */
|
|
4376
4381
|
verificationUrl?: string;
|
|
4377
4382
|
/** 402 Index's own human instructions. */
|
|
4378
4383
|
instructions?: string;
|
|
@@ -5129,10 +5134,6 @@ interface OpenApiOperation {
|
|
|
5129
5134
|
'x-payment-info': {
|
|
5130
5135
|
x402Version: 2;
|
|
5131
5136
|
accepts: PaymentRail[];
|
|
5132
|
-
/** Bazaar-style input schema marker so a strict index doesn't "skip" the op. */
|
|
5133
|
-
bazaar: {
|
|
5134
|
-
discoverable: true;
|
|
5135
|
-
};
|
|
5136
5137
|
};
|
|
5137
5138
|
}
|
|
5138
5139
|
/** x402scan's legacy origin file (`/.well-known/x402`). */
|
|
@@ -5141,6 +5142,46 @@ interface WellKnownX402 {
|
|
|
5141
5142
|
resources: string[];
|
|
5142
5143
|
ownershipProofs?: string[];
|
|
5143
5144
|
}
|
|
5145
|
+
/**
|
|
5146
|
+
* Describes a resource's INPUT for discovery. The open indexes that REQUIRE an
|
|
5147
|
+
* input schema (x402scan rejects a listing without one) read this from a
|
|
5148
|
+
* `extensions.bazaar` block. Pass it to a gate's `discovery` option (emits the
|
|
5149
|
+
* block in the 402 challenge) or build it directly with {@link buildBazaarExtension}.
|
|
5150
|
+
*/
|
|
5151
|
+
interface DiscoveryDescriptor {
|
|
5152
|
+
/** HTTP method the resource answers. Default `'GET'`. */
|
|
5153
|
+
method?: string;
|
|
5154
|
+
/** Query params the resource reads, as a JSON-Schema `properties` object
|
|
5155
|
+
* (name → schema). Default `{}` — a no-input GET. */
|
|
5156
|
+
queryParams?: Record<string, unknown>;
|
|
5157
|
+
/** Optional output hint (shape/example) for a richer listing. */
|
|
5158
|
+
output?: {
|
|
5159
|
+
type?: string;
|
|
5160
|
+
example?: unknown;
|
|
5161
|
+
};
|
|
5162
|
+
}
|
|
5163
|
+
/** The `extensions.bazaar` discovery block (the x402 "bazaar" convention the open
|
|
5164
|
+
* indexes parse: `info.input` describes the request, `schema` is its JSON Schema). */
|
|
5165
|
+
interface BazaarExtension {
|
|
5166
|
+
info: {
|
|
5167
|
+
input: {
|
|
5168
|
+
type: 'http';
|
|
5169
|
+
method: string;
|
|
5170
|
+
queryParams: Record<string, unknown>;
|
|
5171
|
+
};
|
|
5172
|
+
output?: {
|
|
5173
|
+
type?: string;
|
|
5174
|
+
example?: unknown;
|
|
5175
|
+
};
|
|
5176
|
+
};
|
|
5177
|
+
schema: Record<string, unknown>;
|
|
5178
|
+
}
|
|
5179
|
+
/**
|
|
5180
|
+
* Build the `extensions.bazaar` block that satisfies x402scan's mandatory input-schema
|
|
5181
|
+
* check, from a {@link DiscoveryDescriptor}. Pure. Defaults to a no-input GET — the
|
|
5182
|
+
* minimal shape a live x402scan listing accepts.
|
|
5183
|
+
*/
|
|
5184
|
+
declare function buildBazaarExtension(descriptor?: DiscoveryDescriptor): BazaarExtension;
|
|
5144
5185
|
/** The `_x402` DNS TXT pointer record (experimental draft). */
|
|
5145
5186
|
interface X402DnsRecord {
|
|
5146
5187
|
name: string;
|
|
@@ -5292,6 +5333,14 @@ interface RequirePaymentOptions {
|
|
|
5292
5333
|
* Omit to keep the gate exactly as today (`onchain-proof` only).
|
|
5293
5334
|
*/
|
|
5294
5335
|
exact?: ExactRailOption;
|
|
5336
|
+
/**
|
|
5337
|
+
* Make this gate's 402 self-describing for the open indexes — **x402scan REQUIRES
|
|
5338
|
+
* an input schema or it won't list the resource.** Set `true` for a no-input GET,
|
|
5339
|
+
* or pass a {@link DiscoveryDescriptor} to describe the request. Emits an
|
|
5340
|
+
* `extensions.bazaar` block in the 402 challenge. Opt-in; omitting it leaves the
|
|
5341
|
+
* challenge byte-identical to before.
|
|
5342
|
+
*/
|
|
5343
|
+
discovery?: boolean | DiscoveryDescriptor;
|
|
5295
5344
|
}
|
|
5296
5345
|
type VerifyPaymentResult = {
|
|
5297
5346
|
kind: 'paid';
|
|
@@ -5898,4 +5947,4 @@ declare function readExactDomain(publicClient: PublicClient, asset: string): Pro
|
|
|
5898
5947
|
version: string;
|
|
5899
5948
|
} | null>;
|
|
5900
5949
|
|
|
5901
|
-
export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoverySigner, type DiscoverySource, type DomainClaim, type DomainVerification, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, PaymentTimeoutError, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, type XrplToken, buildChallengeHeader, buildExactAuthorization, buildOpenApi, buildReceiptHeader, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, createPaymentGate, decorateOutcome, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, getDirectoryInfo, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseReceipt, parseSignatureHeader, paymentTools, pickAccept, planAcross, readExactDomain, register402Index, registerDriver, registerX402Scan, requirePayment, resolveChain, searchOpenIndexes, settleViaFacilitator, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };
|
|
5950
|
+
export { type AcceptOption, type AddressId, type AgentTool, type AlgorandToken, type AptosToken, type AssetId, type BazaarExtension, type BuildExactParams, CHAINS, type Caip2, type ChainFamily, type ChainInput, type ChainName, type ChainPreset, type ChainSelector, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DirectoryInfo, type DiscoverOptions, type DiscoveredRail, type DiscoveredResource, type DiscoveryDescriptor, type DiscoverySigner, type DiscoverySource, type DomainClaim, type DomainVerification, EIP3009_TYPES, EXACT_NETWORK_SLUGS, type EvmToken, type ExactAccept, type ExactAuthorization, type ExactAuthorizationWire, type ExactPaymentPayload, type ExactRailOption, type ExpressLikeMiddleware, type ExpressLikeNext, type ExpressLikeRequest, type ExpressLikeResponse, type FacilitatorConfig, type FacilitatorPaymentRequirements, GENERATOR, HEADER_REQUIRED, HEADER_RESPONSE, HEADER_RESPONSE_V1, HEADER_SIGNATURE, HEADER_SIGNATURE_V1, InsufficientFundsError, InvalidEnvelopeError, type ListingVisibility, type ManifestInput, MaxRetriesExceededError, MissingDriverError, type NearToken, NoCompatibleAcceptError, NonReplayableBodyError, type OpenApiDocument, type OpenApiOperation, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, PaymentTimeoutError, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, type VerifyErrorCode, type VerifyPaymentResult, type VerifyResult, type WalletBalance, type WalletHandle, type WalletInput, type WellKnownX402, WrongChainError, WrongFamilyError, type X402AcceptEntry, type X402AnyAccept, type X402Challenge, type X402DnsRecord, type X402ExactAcceptEntry, type X402InvalidBody, type X402PaymentSignature, type X402Receipt, type X402ResourceObject, type XrplToken, buildBazaarExtension, buildChallengeHeader, buildExactAuthorization, buildOpenApi, buildReceiptHeader, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, createPaymentGate, decorateOutcome, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, getDirectoryInfo, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseReceipt, parseSignatureHeader, paymentTools, pickAccept, planAcross, readExactDomain, register402Index, registerDriver, registerX402Scan, requirePayment, resolveChain, searchOpenIndexes, settleViaFacilitator, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };
|
package/dist/index.js
CHANGED
|
@@ -1593,11 +1593,14 @@ async function claim402IndexDomain(domainOrUrl, opts = {}) {
|
|
|
1593
1593
|
if (!res.ok) {
|
|
1594
1594
|
return { ok: false, domain, httpStatus: res.status, detail: pickString(body, "error", "detail", "message") ?? `402 Index claim returned HTTP ${res.status}.` };
|
|
1595
1595
|
}
|
|
1596
|
+
const verificationToken = pickString(body, "verification_token");
|
|
1597
|
+
const verificationHash = pickString(body, "verification_hash") ?? (verificationToken ? await sha256Hex(verificationToken) : void 0);
|
|
1596
1598
|
return {
|
|
1597
1599
|
ok: true,
|
|
1598
1600
|
domain,
|
|
1599
1601
|
httpStatus: res.status,
|
|
1600
|
-
...optionalString("verificationHash",
|
|
1602
|
+
...optionalString("verificationHash", verificationHash),
|
|
1603
|
+
...optionalString("verificationToken", verificationToken),
|
|
1601
1604
|
...optionalString("verificationUrl", pickString(body, "verification_url")),
|
|
1602
1605
|
...optionalString("instructions", pickString(body, "instructions"))
|
|
1603
1606
|
};
|
|
@@ -1605,6 +1608,10 @@ async function claim402IndexDomain(domainOrUrl, opts = {}) {
|
|
|
1605
1608
|
return { ok: false, domain, detail: errMsg(err) };
|
|
1606
1609
|
}
|
|
1607
1610
|
}
|
|
1611
|
+
async function sha256Hex(input) {
|
|
1612
|
+
const digest = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(input));
|
|
1613
|
+
return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
1614
|
+
}
|
|
1608
1615
|
async function verify402IndexDomain(domainOrUrl) {
|
|
1609
1616
|
const domain = hostOf(domainOrUrl);
|
|
1610
1617
|
try {
|
|
@@ -1634,6 +1641,12 @@ async function readSiwxInfo(res) {
|
|
|
1634
1641
|
const ext = body.extensions;
|
|
1635
1642
|
const siwx = ext?.["sign-in-with-x"];
|
|
1636
1643
|
const info = siwx?.info ?? siwx;
|
|
1644
|
+
if (info && info.chainId == null && Array.isArray(siwx?.supportedChains)) {
|
|
1645
|
+
const evm = siwx.supportedChains.find(
|
|
1646
|
+
(c) => typeof c?.chainId === "string" && c.chainId.startsWith("eip155:")
|
|
1647
|
+
);
|
|
1648
|
+
if (evm && typeof evm.chainId === "string") info.chainId = evm.chainId;
|
|
1649
|
+
}
|
|
1637
1650
|
if (info && typeof info.domain === "string" && info.domain.length > 0 && typeof info.nonce === "string" && info.nonce.length > 0 && typeof info.uri === "string" && info.uri.length > 0) {
|
|
1638
1651
|
return info;
|
|
1639
1652
|
}
|
|
@@ -1717,7 +1730,8 @@ function firstArray(o, ...keys) {
|
|
|
1717
1730
|
}
|
|
1718
1731
|
function hostOf(url) {
|
|
1719
1732
|
try {
|
|
1720
|
-
|
|
1733
|
+
const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(url) ? url : `https://${url}`;
|
|
1734
|
+
return new URL(withScheme).hostname || url;
|
|
1721
1735
|
} catch {
|
|
1722
1736
|
return url;
|
|
1723
1737
|
}
|
|
@@ -1726,8 +1740,13 @@ function errMsg(err) {
|
|
|
1726
1740
|
return err instanceof Error ? err.message : String(err);
|
|
1727
1741
|
}
|
|
1728
1742
|
function encodeBase642(str) {
|
|
1729
|
-
if (typeof btoa === "function") return btoa(str);
|
|
1730
1743
|
if (typeof Buffer !== "undefined") return Buffer.from(str, "utf8").toString("base64");
|
|
1744
|
+
if (typeof btoa === "function" && typeof TextEncoder !== "undefined") {
|
|
1745
|
+
const bytes = new TextEncoder().encode(str);
|
|
1746
|
+
let binary = "";
|
|
1747
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
1748
|
+
return btoa(binary);
|
|
1749
|
+
}
|
|
1731
1750
|
throw new Error("No base64 encoder available in this runtime.");
|
|
1732
1751
|
}
|
|
1733
1752
|
|
|
@@ -2773,7 +2792,7 @@ function paymentTools(client) {
|
|
|
2773
2792
|
},
|
|
2774
2793
|
{
|
|
2775
2794
|
name: "piprail_register",
|
|
2776
|
-
description: "List an x402 payment-gated resource YOU run on the open indexes so other agents can discover it. Default target is 402 Index \u2014 no auth, no signature, no payment; a self-registered listing is pending review (verify your domain on 402index.io for instant approval). Returns one outcome per index ({ source, ok, detail, visibility, note }); a step the chain can't satisfy comes back ok:false with the reason. Moves no funds; nothing is PipRail-hosted.",
|
|
2795
|
+
description: "List an x402 payment-gated resource YOU run on the open indexes so other agents can discover it. Default target is 402 Index \u2014 no auth, no signature, no payment; a self-registered listing is pending review (verify your domain on 402index.io for instant approval). Returns one outcome per index ({ source, ok, detail, visibility, note }); a step the chain can't satisfy comes back ok:false with the reason. Moves no funds; nothing is PipRail-hosted. NOTE: index/agent payers are overwhelmingly standard `exact` clients \u2014 a default onchain-proof-only gate gets listed but they cannot pay it, so add an `exact` rail (and set the gate's `discovery` option, required for x402scan) to be usefully discoverable AND payable.",
|
|
2777
2796
|
annotations: {
|
|
2778
2797
|
title: "Register an x402 endpoint",
|
|
2779
2798
|
readOnlyHint: false,
|
|
@@ -2807,6 +2826,87 @@ function paymentTools(client) {
|
|
|
2807
2826
|
];
|
|
2808
2827
|
}
|
|
2809
2828
|
|
|
2829
|
+
// src/discovery.ts
|
|
2830
|
+
var GENERATOR = "@piprail/sdk \xB7 https://piprail.com";
|
|
2831
|
+
function buildBazaarExtension(descriptor = {}) {
|
|
2832
|
+
const method = (descriptor.method ?? "GET").toUpperCase();
|
|
2833
|
+
const queryParams = descriptor.queryParams ?? {};
|
|
2834
|
+
return {
|
|
2835
|
+
info: {
|
|
2836
|
+
input: { type: "http", method, queryParams },
|
|
2837
|
+
output: descriptor.output ?? { type: "json" }
|
|
2838
|
+
},
|
|
2839
|
+
schema: {
|
|
2840
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
2841
|
+
type: "object",
|
|
2842
|
+
properties: {
|
|
2843
|
+
input: {
|
|
2844
|
+
type: "object",
|
|
2845
|
+
properties: {
|
|
2846
|
+
type: { type: "string", const: "http" },
|
|
2847
|
+
method: { type: "string", enum: ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"] },
|
|
2848
|
+
queryParams: { type: "object", properties: queryParams, additionalProperties: false }
|
|
2849
|
+
},
|
|
2850
|
+
required: ["type", "method"],
|
|
2851
|
+
additionalProperties: false
|
|
2852
|
+
}
|
|
2853
|
+
},
|
|
2854
|
+
required: ["input"]
|
|
2855
|
+
}
|
|
2856
|
+
};
|
|
2857
|
+
}
|
|
2858
|
+
function pathOf(url) {
|
|
2859
|
+
try {
|
|
2860
|
+
return new URL(url).pathname || "/";
|
|
2861
|
+
} catch {
|
|
2862
|
+
return url.startsWith("/") ? url : `/${url}`;
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
function buildOpenApi(input) {
|
|
2866
|
+
const paths = {};
|
|
2867
|
+
for (const r of input.resources) {
|
|
2868
|
+
const path = pathOf(r.url);
|
|
2869
|
+
const method = (r.method ?? "GET").toLowerCase();
|
|
2870
|
+
const op = {
|
|
2871
|
+
...r.description ? { summary: r.description } : {},
|
|
2872
|
+
responses: {
|
|
2873
|
+
"200": { description: "Paid \u2014 the resource." },
|
|
2874
|
+
"402": { description: "Payment required (x402)." }
|
|
2875
|
+
},
|
|
2876
|
+
"x-payment-info": {
|
|
2877
|
+
x402Version: 2,
|
|
2878
|
+
accepts: r.accepts
|
|
2879
|
+
}
|
|
2880
|
+
};
|
|
2881
|
+
paths[path] = { ...paths[path] ?? {}, [method]: op };
|
|
2882
|
+
}
|
|
2883
|
+
return {
|
|
2884
|
+
openapi: "3.1.0",
|
|
2885
|
+
info: { title: input.title ?? "PipRail x402 resources", version: input.version ?? "1.0.0" },
|
|
2886
|
+
servers: [{ url: input.origin }],
|
|
2887
|
+
paths,
|
|
2888
|
+
// "Built with @piprail/sdk" — default on (opt out with attribution:false). At the
|
|
2889
|
+
// document ROOT so `info` stays exactly { title, version }.
|
|
2890
|
+
...input.attribution === false ? {} : { "x-generator": GENERATOR },
|
|
2891
|
+
...input.ownershipProofs && input.ownershipProofs.length > 0 ? { "x-agentcash-provenance": { ownershipProofs: input.ownershipProofs } } : {}
|
|
2892
|
+
};
|
|
2893
|
+
}
|
|
2894
|
+
function buildWellKnownX402(input) {
|
|
2895
|
+
return {
|
|
2896
|
+
version: 1,
|
|
2897
|
+
resources: input.resources.map((r) => r.url),
|
|
2898
|
+
...input.ownershipProofs && input.ownershipProofs.length > 0 ? { ownershipProofs: input.ownershipProofs } : {}
|
|
2899
|
+
};
|
|
2900
|
+
}
|
|
2901
|
+
function buildX402DnsTxt(input) {
|
|
2902
|
+
const descriptor = input.descriptor ? `descriptor=${input.descriptor};` : "";
|
|
2903
|
+
return {
|
|
2904
|
+
name: `_x402.${input.host}`,
|
|
2905
|
+
type: "TXT",
|
|
2906
|
+
value: `v=x4021;${descriptor}url=${input.discoveryUrl}`
|
|
2907
|
+
};
|
|
2908
|
+
}
|
|
2909
|
+
|
|
2810
2910
|
// src/facilitator.ts
|
|
2811
2911
|
function safeStringify(value) {
|
|
2812
2912
|
return JSON.stringify(value, (_k, v) => typeof v === "bigint" ? v.toString() : v);
|
|
@@ -3055,6 +3155,8 @@ function createPaymentGate(options) {
|
|
|
3055
3155
|
async function makeChallenge(resourceUrl, opts) {
|
|
3056
3156
|
const specs = await ready();
|
|
3057
3157
|
const nonce = genNonce();
|
|
3158
|
+
const bazaar = options.discovery ? { bazaar: buildBazaarExtension(options.discovery === true ? {} : options.discovery) } : void 0;
|
|
3159
|
+
const extensions = { ...bazaar, ...opts?.extensions };
|
|
3058
3160
|
const challenge2 = {
|
|
3059
3161
|
x402Version: 2,
|
|
3060
3162
|
resource: {
|
|
@@ -3063,7 +3165,7 @@ function createPaymentGate(options) {
|
|
|
3063
3165
|
},
|
|
3064
3166
|
accepts: buildAccepts(specs, nonce),
|
|
3065
3167
|
...opts?.error ? { error: opts.error } : {},
|
|
3066
|
-
...
|
|
3168
|
+
...Object.keys(extensions).length > 0 ? { extensions } : {}
|
|
3067
3169
|
};
|
|
3068
3170
|
return { challenge: challenge2, requiredHeader: buildChallengeHeader(challenge2) };
|
|
3069
3171
|
}
|
|
@@ -3249,61 +3351,6 @@ function normaliseHeader(value) {
|
|
|
3249
3351
|
if (Array.isArray(value)) return value[0];
|
|
3250
3352
|
return value;
|
|
3251
3353
|
}
|
|
3252
|
-
|
|
3253
|
-
// src/discovery.ts
|
|
3254
|
-
var GENERATOR = "@piprail/sdk \xB7 https://piprail.com";
|
|
3255
|
-
function pathOf(url) {
|
|
3256
|
-
try {
|
|
3257
|
-
return new URL(url).pathname || "/";
|
|
3258
|
-
} catch {
|
|
3259
|
-
return url.startsWith("/") ? url : `/${url}`;
|
|
3260
|
-
}
|
|
3261
|
-
}
|
|
3262
|
-
function buildOpenApi(input) {
|
|
3263
|
-
const paths = {};
|
|
3264
|
-
for (const r of input.resources) {
|
|
3265
|
-
const path = pathOf(r.url);
|
|
3266
|
-
const method = (r.method ?? "GET").toLowerCase();
|
|
3267
|
-
const op = {
|
|
3268
|
-
...r.description ? { summary: r.description } : {},
|
|
3269
|
-
responses: {
|
|
3270
|
-
"200": { description: "Paid \u2014 the resource." },
|
|
3271
|
-
"402": { description: "Payment required (x402)." }
|
|
3272
|
-
},
|
|
3273
|
-
"x-payment-info": {
|
|
3274
|
-
x402Version: 2,
|
|
3275
|
-
accepts: r.accepts,
|
|
3276
|
-
bazaar: { discoverable: true }
|
|
3277
|
-
}
|
|
3278
|
-
};
|
|
3279
|
-
paths[path] = { ...paths[path] ?? {}, [method]: op };
|
|
3280
|
-
}
|
|
3281
|
-
return {
|
|
3282
|
-
openapi: "3.1.0",
|
|
3283
|
-
info: { title: input.title ?? "PipRail x402 resources", version: input.version ?? "1.0.0" },
|
|
3284
|
-
servers: [{ url: input.origin }],
|
|
3285
|
-
paths,
|
|
3286
|
-
// "Built with @piprail/sdk" — default on (opt out with attribution:false). At the
|
|
3287
|
-
// document ROOT so `info` stays exactly { title, version }.
|
|
3288
|
-
...input.attribution === false ? {} : { "x-generator": GENERATOR },
|
|
3289
|
-
...input.ownershipProofs && input.ownershipProofs.length > 0 ? { "x-agentcash-provenance": { ownershipProofs: input.ownershipProofs } } : {}
|
|
3290
|
-
};
|
|
3291
|
-
}
|
|
3292
|
-
function buildWellKnownX402(input) {
|
|
3293
|
-
return {
|
|
3294
|
-
version: 1,
|
|
3295
|
-
resources: input.resources.map((r) => r.url),
|
|
3296
|
-
...input.ownershipProofs && input.ownershipProofs.length > 0 ? { ownershipProofs: input.ownershipProofs } : {}
|
|
3297
|
-
};
|
|
3298
|
-
}
|
|
3299
|
-
function buildX402DnsTxt(input) {
|
|
3300
|
-
const descriptor = input.descriptor ? `descriptor=${input.descriptor};` : "";
|
|
3301
|
-
return {
|
|
3302
|
-
name: `_x402.${input.host}`,
|
|
3303
|
-
type: "TXT",
|
|
3304
|
-
value: `v=x4021;${descriptor}url=${input.discoveryUrl}`
|
|
3305
|
-
};
|
|
3306
|
-
}
|
|
3307
3354
|
export {
|
|
3308
3355
|
CHAINS,
|
|
3309
3356
|
ConfirmationTimeoutError,
|
|
@@ -3332,6 +3379,7 @@ export {
|
|
|
3332
3379
|
UnsupportedNetworkError,
|
|
3333
3380
|
WrongChainError,
|
|
3334
3381
|
WrongFamilyError,
|
|
3382
|
+
buildBazaarExtension,
|
|
3335
3383
|
buildChallengeHeader,
|
|
3336
3384
|
buildExactAuthorization,
|
|
3337
3385
|
buildOpenApi,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@piprail/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "Accept x402 crypto payments across 29 chains — every major EVM chain plus Solana, TON, Tron, NEAR, Sui, Aptos, Algorand, Stellar & XRPL — in a couple of lines. No backend, no database, no fee; payments settle straight to your wallet.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|