@piprail/sdk 1.10.0 → 1.12.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 +46 -0
- package/README.md +51 -23
- package/dist/index.cjs +175 -24
- package/dist/index.d.cts +176 -18
- package/dist/index.d.ts +176 -18
- package/dist/index.js +164 -13
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1305,9 +1305,47 @@ async function resolveNetwork2(opts) {
|
|
|
1305
1305
|
}
|
|
1306
1306
|
|
|
1307
1307
|
// src/indexes.ts
|
|
1308
|
+
var DIRECTORY_INFO = {
|
|
1309
|
+
"402index": {
|
|
1310
|
+
source: "402index",
|
|
1311
|
+
review: "probe-sync",
|
|
1312
|
+
auth: "none",
|
|
1313
|
+
chains: null,
|
|
1314
|
+
onSuccess: "pending-review",
|
|
1315
|
+
readByDiscover: true,
|
|
1316
|
+
caveat: "402 Index probes your URL on submit, then lists it as PENDING REVIEW \u2014 a self-registered resource is NOT in search until approved. Verify your domain on 402index.io for instant approval; otherwise it appears after manual review, so retry discover() later."
|
|
1317
|
+
},
|
|
1318
|
+
x402scan: {
|
|
1319
|
+
source: "x402scan",
|
|
1320
|
+
review: "probe-sync",
|
|
1321
|
+
auth: "siwx",
|
|
1322
|
+
chains: ["eip155:8453", "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"],
|
|
1323
|
+
onSuccess: "live",
|
|
1324
|
+
readByDiscover: false,
|
|
1325
|
+
caveat: "x402scan lists Base/Solana only, needs one wallet signature (SIWX), and requires a resolvable input schema (from /openapi.json or the bazaar extension in the 402 body). It goes live on x402scan.com immediately on success \u2014 but discover() does NOT read x402scan, so the listing won't appear in discover() results."
|
|
1326
|
+
},
|
|
1327
|
+
bazaar: {
|
|
1328
|
+
source: "bazaar",
|
|
1329
|
+
review: "settle-coupled",
|
|
1330
|
+
auth: "facilitator-only",
|
|
1331
|
+
chains: null,
|
|
1332
|
+
onSuccess: "not-listable",
|
|
1333
|
+
readByDiscover: true,
|
|
1334
|
+
caveat: "CDP Bazaar has no register endpoint \u2014 it catalogs a resource only when its own facilitator settles a payment. PipRail verifies locally with no facilitator, so a PipRail resource cannot be listed here (you can still READ Bazaar to find others). List on 402 Index or x402scan instead."
|
|
1335
|
+
}
|
|
1336
|
+
};
|
|
1337
|
+
function getDirectoryInfo(source) {
|
|
1338
|
+
return DIRECTORY_INFO[source];
|
|
1339
|
+
}
|
|
1340
|
+
function decorateOutcome(o) {
|
|
1341
|
+
const info = DIRECTORY_INFO[o.source];
|
|
1342
|
+
return { ...o, visibility: o.ok ? info.onSuccess : "not-listable", note: info.caveat };
|
|
1343
|
+
}
|
|
1308
1344
|
var BAZAAR_URL = "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources";
|
|
1309
1345
|
var INDEX402_SEARCH = "https://402index.io/api/v1/services";
|
|
1310
1346
|
var INDEX402_REGISTER = "https://402index.io/api/v1/register";
|
|
1347
|
+
var INDEX402_CLAIM = "https://402index.io/api/v1/claim";
|
|
1348
|
+
var INDEX402_VERIFY = "https://402index.io/api/v1/claim/verify";
|
|
1311
1349
|
var X402SCAN_REGISTER = "https://www.x402scan.com/api/x402/registry/register";
|
|
1312
1350
|
var USER_AGENT = "@piprail/sdk (+https://piprail.com)";
|
|
1313
1351
|
function clientHeaders(extra = {}) {
|
|
@@ -1457,7 +1495,13 @@ async function register402Index(input) {
|
|
|
1457
1495
|
body: JSON.stringify(payload)
|
|
1458
1496
|
});
|
|
1459
1497
|
if (res.ok) {
|
|
1460
|
-
|
|
1498
|
+
const msg = await readIndexMessage(res);
|
|
1499
|
+
return {
|
|
1500
|
+
source: "402index",
|
|
1501
|
+
ok: true,
|
|
1502
|
+
status: res.status,
|
|
1503
|
+
detail: msg ?? "Registered on 402 Index \u2014 pending review (verify your domain on 402index.io for instant approval)."
|
|
1504
|
+
};
|
|
1461
1505
|
}
|
|
1462
1506
|
const why = await readIndexError(res);
|
|
1463
1507
|
return {
|
|
@@ -1470,6 +1514,14 @@ async function register402Index(input) {
|
|
|
1470
1514
|
return { source: "402index", ok: false, detail: errMsg(err) };
|
|
1471
1515
|
}
|
|
1472
1516
|
}
|
|
1517
|
+
async function readIndexMessage(res) {
|
|
1518
|
+
try {
|
|
1519
|
+
const body = await res.json();
|
|
1520
|
+
return typeof body.message === "string" && body.message.length > 0 ? body.message : void 0;
|
|
1521
|
+
} catch {
|
|
1522
|
+
return void 0;
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1473
1525
|
async function readIndexError(res) {
|
|
1474
1526
|
try {
|
|
1475
1527
|
const body = await res.json();
|
|
@@ -1529,6 +1581,53 @@ async function registerX402Scan(input, signer) {
|
|
|
1529
1581
|
return { source: "x402scan", ok: false, detail: errMsg(err) };
|
|
1530
1582
|
}
|
|
1531
1583
|
}
|
|
1584
|
+
async function claim402IndexDomain(domainOrUrl, opts = {}) {
|
|
1585
|
+
const domain = hostOf(domainOrUrl);
|
|
1586
|
+
try {
|
|
1587
|
+
const res = await fetch(INDEX402_CLAIM, {
|
|
1588
|
+
method: "POST",
|
|
1589
|
+
headers: clientHeaders({ "content-type": "application/json", accept: "application/json" }),
|
|
1590
|
+
body: JSON.stringify({ domain, ...opts.contactEmail ? { contact_email: opts.contactEmail } : {} })
|
|
1591
|
+
});
|
|
1592
|
+
const body = await res.json().catch(() => ({}));
|
|
1593
|
+
if (!res.ok) {
|
|
1594
|
+
return { ok: false, domain, httpStatus: res.status, detail: pickString(body, "error", "detail", "message") ?? `402 Index claim returned HTTP ${res.status}.` };
|
|
1595
|
+
}
|
|
1596
|
+
return {
|
|
1597
|
+
ok: true,
|
|
1598
|
+
domain,
|
|
1599
|
+
httpStatus: res.status,
|
|
1600
|
+
...optionalString("verificationHash", pickString(body, "verification_hash")),
|
|
1601
|
+
...optionalString("verificationUrl", pickString(body, "verification_url")),
|
|
1602
|
+
...optionalString("instructions", pickString(body, "instructions"))
|
|
1603
|
+
};
|
|
1604
|
+
} catch (err) {
|
|
1605
|
+
return { ok: false, domain, detail: errMsg(err) };
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
async function verify402IndexDomain(domainOrUrl) {
|
|
1609
|
+
const domain = hostOf(domainOrUrl);
|
|
1610
|
+
try {
|
|
1611
|
+
const res = await fetch(INDEX402_VERIFY, {
|
|
1612
|
+
method: "POST",
|
|
1613
|
+
headers: clientHeaders({ "content-type": "application/json", accept: "application/json" }),
|
|
1614
|
+
body: JSON.stringify({ domain })
|
|
1615
|
+
});
|
|
1616
|
+
const body = await res.json().catch(() => ({}));
|
|
1617
|
+
if (!res.ok) {
|
|
1618
|
+
return { ok: false, domain, httpStatus: res.status, detail: pickString(body, "error", "detail", "message") ?? `402 Index verify returned HTTP ${res.status}.` };
|
|
1619
|
+
}
|
|
1620
|
+
return {
|
|
1621
|
+
ok: true,
|
|
1622
|
+
domain,
|
|
1623
|
+
httpStatus: res.status,
|
|
1624
|
+
...optionalString("status", pickString(body, "status")),
|
|
1625
|
+
...typeof body.services_count === "number" ? { servicesCount: body.services_count } : {}
|
|
1626
|
+
};
|
|
1627
|
+
} catch (err) {
|
|
1628
|
+
return { ok: false, domain, detail: errMsg(err) };
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1532
1631
|
async function readSiwxInfo(res) {
|
|
1533
1632
|
try {
|
|
1534
1633
|
const body = await res.json();
|
|
@@ -1908,9 +2007,15 @@ var PipRailClient = class {
|
|
|
1908
2007
|
*
|
|
1909
2008
|
* Nothing PipRail-hosted: these are third-party open directories. Never throws
|
|
1910
2009
|
* for a read problem — an index that's down or changed simply contributes
|
|
1911
|
-
* nothing. Honest
|
|
1912
|
-
*
|
|
1913
|
-
*
|
|
2010
|
+
* nothing. Honest caveats (see {@link DIRECTORY_INFO}):
|
|
2011
|
+
* - Reads **`bazaar` + `402index`** only — **NOT `x402scan`** (its reads are paid). A
|
|
2012
|
+
* resource you registered on x402scan is live there but will NOT appear here; don't
|
|
2013
|
+
* read that absence as failure. (Passing `sources:['x402scan']` explicitly yields `[]`.)
|
|
2014
|
+
* - A resource just listed via {@link register} may not appear yet — 402 Index reviews
|
|
2015
|
+
* before publishing, so retry with a brief backoff if a fresh listing is missing.
|
|
2016
|
+
* - Results are cross-scheme (mostly the mainstream `exact` scheme); `fetch()` pays
|
|
2017
|
+
* only `onchain-proof` rails directly (pay `exact` resources with the experimental
|
|
2018
|
+
* `drivers/evm/exact.ts`).
|
|
1914
2019
|
*/
|
|
1915
2020
|
async discover(opts = {}) {
|
|
1916
2021
|
const found = await searchOpenIndexes({
|
|
@@ -1935,12 +2040,27 @@ var PipRailClient = class {
|
|
|
1935
2040
|
}
|
|
1936
2041
|
/**
|
|
1937
2042
|
* List a resource you run on the OPEN x402 registries, so agents can find it.
|
|
1938
|
-
* Default target is **402 Index** — one POST, no auth, no signature, no payment
|
|
1939
|
-
*
|
|
1940
|
-
*
|
|
1941
|
-
*
|
|
1942
|
-
*
|
|
1943
|
-
*
|
|
2043
|
+
* Default target is **402 Index** — one POST, no auth, no signature, no payment.
|
|
2044
|
+
* Add `'x402scan'` to also register via SIWX (one wallet signature; EVM + a
|
|
2045
|
+
* Base/Solana rail). Returns one {@link RegisterOutcome} per target — a target the
|
|
2046
|
+
* chain can't satisfy comes back `{ ok:false, detail }`, never a throw. An explicit,
|
|
2047
|
+
* developer-invoked action; it moves no funds, and nothing is PipRail-hosted —
|
|
2048
|
+
* you're listing on third-party open directories.
|
|
2049
|
+
*
|
|
2050
|
+
* **Listing is asynchronous — each outcome carries a `visibility` + `note` so an
|
|
2051
|
+
* agent knows when/where the resource is findable (don't assume `ok:true` means
|
|
2052
|
+
* "searchable now"):**
|
|
2053
|
+
* - **402 Index** → `visibility:'pending-review'`. It probes your URL on submit, then lists it
|
|
2054
|
+
* PENDING REVIEW — not searchable until approved (verify your domain on 402index.io for instant
|
|
2055
|
+
* approval), so `discover()` returns nothing for a fresh listing until then. Retry later.
|
|
2056
|
+
* - **x402scan** → `visibility:'live'`, but **`discover()` does NOT read x402scan** — the
|
|
2057
|
+
* listing is real on x402scan.com yet won't show up in `discover()`. Base/Solana only;
|
|
2058
|
+
* needs a resolvable input schema (`/openapi.json` or the `extensions.bazaar` block).
|
|
2059
|
+
* - **Bazaar** → `visibility:'not-listable'` for PipRail (it lists only what its facilitator
|
|
2060
|
+
* settles; PipRail uses none). You can still READ Bazaar via {@link discover} to find others.
|
|
2061
|
+
*
|
|
2062
|
+
* The per-source facts live in {@link DIRECTORY_INFO} (importable) if you'd rather branch
|
|
2063
|
+
* on them before calling.
|
|
1944
2064
|
*/
|
|
1945
2065
|
async register(url, opts = {}) {
|
|
1946
2066
|
const targets = opts.targets ?? ["402index"];
|
|
@@ -1979,7 +2099,33 @@ var PipRailClient = class {
|
|
|
1979
2099
|
});
|
|
1980
2100
|
}
|
|
1981
2101
|
}
|
|
1982
|
-
return outcomes;
|
|
2102
|
+
return outcomes.map(decorateOutcome);
|
|
2103
|
+
}
|
|
2104
|
+
/**
|
|
2105
|
+
* **402 Index domain verification, step 1 of 2.** A self-registered 402 Index
|
|
2106
|
+
* listing is `pending-review` (see {@link register}); verifying your domain flips
|
|
2107
|
+
* it — and every other pending listing on that domain — to APPROVED/searchable.
|
|
2108
|
+
* Pass the resource URL or a bare domain; returns the `verificationHash` to serve
|
|
2109
|
+
* as the entire body of `verificationUrl` (your `/.well-known/402index-verify.txt`).
|
|
2110
|
+
* Then serve it and call {@link verifyDomain}. Moves no funds; never throws.
|
|
2111
|
+
*
|
|
2112
|
+
* ```ts
|
|
2113
|
+
* const claim = await client.claimDomain('https://api.example.com/report')
|
|
2114
|
+
* // serve claim.verificationHash at claim.verificationUrl, then:
|
|
2115
|
+
* const res = await client.verifyDomain('api.example.com') // → { ok:true, status:'verified' }
|
|
2116
|
+
* ```
|
|
2117
|
+
*/
|
|
2118
|
+
async claimDomain(urlOrDomain, opts = {}) {
|
|
2119
|
+
return claim402IndexDomain(urlOrDomain, opts);
|
|
2120
|
+
}
|
|
2121
|
+
/**
|
|
2122
|
+
* **402 Index domain verification, step 2 of 2.** After {@link claimDomain} and
|
|
2123
|
+
* serving the hash at your `/.well-known/402index-verify.txt`, this tells 402 Index
|
|
2124
|
+
* to re-fetch + approve. On success the domain's pending listings become searchable
|
|
2125
|
+
* (`{ ok:true, status:'verified', servicesCount }`). Moves no funds; never throws.
|
|
2126
|
+
*/
|
|
2127
|
+
async verifyDomain(urlOrDomain) {
|
|
2128
|
+
return verify402IndexDomain(urlOrDomain);
|
|
1983
2129
|
}
|
|
1984
2130
|
/**
|
|
1985
2131
|
* The discovery signer for the bound wallet (its address + a message signer),
|
|
@@ -2627,7 +2773,7 @@ function paymentTools(client) {
|
|
|
2627
2773
|
},
|
|
2628
2774
|
{
|
|
2629
2775
|
name: "piprail_register",
|
|
2630
|
-
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;
|
|
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.",
|
|
2631
2777
|
annotations: {
|
|
2632
2778
|
title: "Register an x402 endpoint",
|
|
2633
2779
|
readOnlyHint: false,
|
|
@@ -3161,6 +3307,7 @@ function buildX402DnsTxt(input) {
|
|
|
3161
3307
|
export {
|
|
3162
3308
|
CHAINS,
|
|
3163
3309
|
ConfirmationTimeoutError,
|
|
3310
|
+
DIRECTORY_INFO,
|
|
3164
3311
|
EIP3009_TYPES,
|
|
3165
3312
|
EXACT_NETWORK_SLUGS,
|
|
3166
3313
|
GENERATOR,
|
|
@@ -3193,10 +3340,13 @@ export {
|
|
|
3193
3340
|
buildWellKnownX402,
|
|
3194
3341
|
buildX402DnsTxt,
|
|
3195
3342
|
chainIdForExactNetwork,
|
|
3343
|
+
claim402IndexDomain,
|
|
3196
3344
|
createPaymentGate,
|
|
3345
|
+
decorateOutcome,
|
|
3197
3346
|
eip3009Abi,
|
|
3198
3347
|
encodeXPaymentHeader,
|
|
3199
3348
|
evaluatePolicy,
|
|
3349
|
+
getDirectoryInfo,
|
|
3200
3350
|
normalizeNetwork,
|
|
3201
3351
|
parseChallenge,
|
|
3202
3352
|
parseExactPaymentHeader,
|
|
@@ -3215,5 +3365,6 @@ export {
|
|
|
3215
3365
|
searchOpenIndexes,
|
|
3216
3366
|
settleViaFacilitator,
|
|
3217
3367
|
toInsufficientFundsError,
|
|
3218
|
-
toInvalidBody
|
|
3368
|
+
toInvalidBody,
|
|
3369
|
+
verify402IndexDomain
|
|
3219
3370
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@piprail/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.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",
|