@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/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,50 @@ 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.12.0] — 2026-06-09
|
|
8
|
+
|
|
9
|
+
### Added — One-call domain verification (pending-review → searchable)
|
|
10
|
+
- **`client.verifyDomain()` takes a 402 Index listing all the way to searchable.** A self-registered
|
|
11
|
+
402 Index listing is `pending-review`; verifying the domain you control approves it (and every other
|
|
12
|
+
pending listing on it). `client.claimDomain(urlOrDomain, { contactEmail? })` returns the
|
|
13
|
+
`verificationHash` to serve at your `/.well-known/402index-verify.txt`; `client.verifyDomain(urlOrDomain)`
|
|
14
|
+
then flips it live. Standalone forms `claim402IndexDomain` / `verify402IndexDomain` + the
|
|
15
|
+
`DomainClaim` / `DomainVerification` types are exported. Never throws; moves no funds.
|
|
16
|
+
|
|
17
|
+
### Docs — a complete, agent-followable discovery playbook
|
|
18
|
+
- Rewrote the **"Be discoverable"** README section into a top-to-bottom **4-step playbook** an agent can
|
|
19
|
+
follow (list → verify domain → discover → self-describe), with the corrected lifecycle output
|
|
20
|
+
(`visibility` + `note`), a `DIRECTORY_INFO` reference table, and the caveats inline (402 Index is
|
|
21
|
+
pending-review; `discover()` doesn't read x402scan; x402scan needs an input schema). Updated
|
|
22
|
+
`llms-full.txt` to the same four moves (EMIT · REGISTER · VERIFY · DISCOVER).
|
|
23
|
+
|
|
24
|
+
## [1.11.0] — 2026-06-09
|
|
25
|
+
|
|
26
|
+
### Added — Agent-friendly discovery lifecycle
|
|
27
|
+
- **`register()` outcomes now tell an agent when/where a listing is findable.** Each
|
|
28
|
+
`RegisterOutcome` carries a `visibility: 'live' | 'pending-review' | 'not-listable'` plus a
|
|
29
|
+
plain-language `note` — projected from a new exported source-of-truth, **`DIRECTORY_INFO`**
|
|
30
|
+
(per-index: review mode, auth, chains, `readByDiscover`, caveat). So an agent reads the caveat
|
|
31
|
+
right where it already is instead of guessing. New exports: `DIRECTORY_INFO`, `getDirectoryInfo`,
|
|
32
|
+
`decorateOutcome`, and the `DirectoryInfo` / `ListingVisibility` types.
|
|
33
|
+
- **The sharp caveats are now explicit** (in the types, the `note`, and `register()`/`discover()`
|
|
34
|
+
JSDoc): **402 Index lists a self-registered resource as `pending-review`** (not searchable until
|
|
35
|
+
approved — verify your domain on 402index.io for instant approval), **`discover()` does NOT read
|
|
36
|
+
x402scan** (a live x402scan listing won't appear there — don't read its absence as failure), and
|
|
37
|
+
**CDP Bazaar can't list a backendless PipRail resource at all** (facilitator-coupled).
|
|
38
|
+
|
|
39
|
+
### Docs — x402 v1/v2 version posture made authoritative
|
|
40
|
+
- A definitive comment in `x402.ts` documents the stance: **emit strict v2, accept liberal v1 + v2**
|
|
41
|
+
(Postel). v2 *replaced* v1 on the wire; the current reference client `@x402/fetch` is v2, but the
|
|
42
|
+
original `x402-fetch`/`x402-express`/`x402-next` packages still send v1, so the gate keeps accepting
|
|
43
|
+
it. PipRail emits no v1 *body* on its own paths; the lone v1 emitter is the `encodeXPaymentHeader`
|
|
44
|
+
utility (its `x402Version: 1` default is correct — consistent with the v1-flat shape it builds).
|
|
45
|
+
|
|
46
|
+
### Fixed
|
|
47
|
+
- Corrected stale "searchable within seconds" wording for 402 Index (it added a review queue):
|
|
48
|
+
`register402Index`'s success `detail` now surfaces the index's own message, and the JSDoc + MCP
|
|
49
|
+
`piprail_register` tool description reflect the `pending-review` reality.
|
|
50
|
+
|
|
7
51
|
## [1.10.0] — 2026-06-09
|
|
8
52
|
|
|
9
53
|
### Added — Universal Payments (the standard x402 `exact` rail)
|
|
@@ -549,6 +593,8 @@ straight into your wallet. The API is small and self-contained.
|
|
|
549
593
|
to your wallet; PipRail never holds funds.
|
|
550
594
|
- `viem ^2.21` is a peer dependency. Node 20+ or a modern browser.
|
|
551
595
|
|
|
596
|
+
[1.12.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
597
|
+
[1.11.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
552
598
|
[1.10.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
553
599
|
[1.9.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
554
600
|
[1.8.0]: https://www.npmjs.com/package/@piprail/sdk
|
package/README.md
CHANGED
|
@@ -148,24 +148,38 @@ See [`examples/agent-tools.mjs`](../examples/agent-tools.mjs) for MCP / AI-SDK w
|
|
|
148
148
|
A 402 endpoint is payable, but nobody can *find* it. PipRail closes that gap by building on the
|
|
149
149
|
**open** x402 indexes that already exist (402 Index, the CDP Bazaar read API, x402scan) — **nothing
|
|
150
150
|
PipRail-hosted, no registry, no database.** All opt-in; the pay path is untouched. There's **no PipRail
|
|
151
|
-
account and no x402 sign-up anywhere** — the only thing ever registered is a merchant's own URL
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
account and no x402 sign-up anywhere** — the only thing ever registered is a merchant's own URL.
|
|
152
|
+
**The four steps below are the whole playbook** — an agent can follow them top to bottom (every method
|
|
153
|
+
never throws and returns a typed result that says what to do next); [DISCOVERY.md](./DISCOVERY.md) is
|
|
154
|
+
the deep reference.
|
|
154
155
|
|
|
155
156
|
> **Experimental.** Discovery integrates with third-party open indexes whose conventions are young
|
|
156
157
|
> and moving — treat this layer as experimental. The read path + 402 Index register are live-verified;
|
|
157
158
|
> x402scan SIWX isn't yet. Note **402 Index probes your URL and only lists endpoints that actually
|
|
158
159
|
> return a `402`** — so register a *deployed* gate, not a marketing page. (DISCOVERY.md §10 has the log.)
|
|
159
160
|
|
|
160
|
-
**1) List a resource you run** — one call, no auth, no signature:
|
|
161
|
+
**1) List a resource you run** — one call, no auth, no signature, no funds:
|
|
161
162
|
|
|
162
163
|
```ts
|
|
163
164
|
const client = new PipRailClient({ wallet: { privateKey: KEY }, chain: 'base' })
|
|
164
165
|
|
|
165
|
-
await client.register('https://api.example.com/report', {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
const outcomes = await client.register('https://api.example.com/report', {
|
|
167
|
+
name: 'Market Report', priceUsd: 0.05, asset: 'USDC',
|
|
168
|
+
targets: ['402index', 'x402scan'], // 402index is the default; x402scan adds SIWX (Base/Solana)
|
|
169
|
+
})
|
|
170
|
+
// Each outcome carries its LIFECYCLE — read `visibility` + `note`. "ok:true" ≠ "searchable now":
|
|
171
|
+
// • 402index → { ok:true, visibility:'pending-review', note:'… verify your domain for instant approval' }
|
|
172
|
+
// • x402scan → { ok:true, visibility:'live', note:"… discover() does NOT read x402scan" }
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
**2) Flip 402 Index `pending-review` → searchable** — verify the domain you control (no funds, no sign-up):
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
const claim = await client.claimDomain('https://api.example.com/report', { contactEmail: 'you@example.com' })
|
|
179
|
+
// Serve claim.verificationHash as the ENTIRE body of claim.verificationUrl
|
|
180
|
+
// (https://api.example.com/.well-known/402index-verify.txt) — then:
|
|
181
|
+
await client.verifyDomain('api.example.com') // → { ok:true, status:'verified', servicesCount }
|
|
182
|
+
// Now every pending listing on that domain is approved + searchable.
|
|
169
183
|
```
|
|
170
184
|
|
|
171
185
|
**Works on every chain.** 402 Index needs no signature and has no chain allowlist, so *any* chain —
|
|
@@ -179,7 +193,7 @@ request sends a `User-Agent: @piprail/sdk` — so the tech spreads through the f
|
|
|
179
193
|
the logs operators read, never by spamming listings. An opt-in `register(url, { attribution: true })`
|
|
180
194
|
adds a best-effort `via` tag; it's off by default (it's your listing).
|
|
181
195
|
|
|
182
|
-
**
|
|
196
|
+
**3) Find resources to pay** — read the open indexes (free), filtered to your chain by default:
|
|
183
197
|
|
|
184
198
|
```ts
|
|
185
199
|
const hits = await client.discover({ query: 'weather', maxPrice: 0.01 })
|
|
@@ -187,25 +201,39 @@ const hits = await client.discover({ query: 'weather', maxPrice: 0.01 })
|
|
|
187
201
|
const res = await client.fetch(hits[0].resource) // then quote → plan → pay as usual
|
|
188
202
|
```
|
|
189
203
|
|
|
190
|
-
`
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
network is kept, never hidden.
|
|
204
|
+
`discover()` reads **402 Index + CDP Bazaar**, **not x402scan** (its reads are paid) — a live x402scan
|
|
205
|
+
listing won't appear here, so don't read that absence as failure. `network` defaults to `'self'` (your
|
|
206
|
+
chain); pass `'any'` for every chain, or a CAIP-2 id (`'eip155:8453'`). Slugs map to CAIP-2 via
|
|
207
|
+
`SLUG_TO_CAIP2`; an unresolved network is kept, never hidden.
|
|
194
208
|
|
|
195
|
-
**
|
|
196
|
-
I/O); serve
|
|
209
|
+
**4) Make your endpoint self-describing** — turn your gate's config into the artifacts a crawler reads
|
|
210
|
+
(pure, no I/O); serve them on **your own** origin. **x402scan REQUIRES** a resolvable input schema (your
|
|
211
|
+
`/openapi.json` or an `extensions.bazaar` block in the 402 body), so this is what makes an x402scan
|
|
212
|
+
listing accepted:
|
|
197
213
|
|
|
198
214
|
```ts
|
|
199
|
-
import { createPaymentGate, buildOpenApi, buildX402DnsTxt } from '@piprail/sdk'
|
|
215
|
+
import { createPaymentGate, buildOpenApi, buildWellKnownX402, buildX402DnsTxt } from '@piprail/sdk'
|
|
200
216
|
|
|
201
217
|
const gate = createPaymentGate({ chain: 'base', token: 'USDC', amount: '0.05', payTo })
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
})
|
|
206
|
-
//
|
|
207
|
-
|
|
208
|
-
|
|
218
|
+
const desc = await gate.describe('https://api.example.com/report')
|
|
219
|
+
const openapi = buildOpenApi({ origin: 'https://api.example.com', resources: [desc] })
|
|
220
|
+
// serve at /openapi.json — each priced op carries an `x-payment-info` block + a root `x-generator` stamp.
|
|
221
|
+
const wellKnown = buildWellKnownX402({ resources: [desc] }) // serve at /.well-known/x402
|
|
222
|
+
// buildX402DnsTxt(...) emits the _x402 DNS line too.
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Know each index before you call** — the facts are one import, `DIRECTORY_INFO`, and `register()`
|
|
226
|
+
projects them onto every outcome (`visibility` + `note`), so an agent never has to guess:
|
|
227
|
+
|
|
228
|
+
| Index | Write auth | Chains | On a successful register | Read by `discover()`? |
|
|
229
|
+
|---|---|---|---|---|
|
|
230
|
+
| **402 Index** (default) | none | any | `pending-review` → `verifyDomain()` for instant approval | ✅ yes |
|
|
231
|
+
| **x402scan** | one wallet sig (SIWX) | Base / Solana | `live` on x402scan.com | ❌ no (paid reads) |
|
|
232
|
+
| **CDP Bazaar** | — (facilitator-only) | — | `not-listable` for PipRail (backendless) | ✅ read-only |
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
import { DIRECTORY_INFO } from '@piprail/sdk'
|
|
236
|
+
DIRECTORY_INFO['x402scan'].readByDiscover // false — branch on this, don't guess
|
|
209
237
|
```
|
|
210
238
|
|
|
211
239
|
For an LLM/MCP these are two more tools — **`piprail_discover`** (find) and **`piprail_register`**
|
package/dist/index.cjs
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: _nullishCoalesce(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 (e17) {
|
|
1522
|
+
return void 0;
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1473
1525
|
async function readIndexError(res) {
|
|
1474
1526
|
try {
|
|
1475
1527
|
const body = await res.json();
|
|
@@ -1477,7 +1529,7 @@ async function readIndexError(res) {
|
|
|
1477
1529
|
(p) => typeof p === "string" && p.length > 0
|
|
1478
1530
|
);
|
|
1479
1531
|
return parts.length ? [...new Set(parts)].join(" \u2014 ") : void 0;
|
|
1480
|
-
} catch (
|
|
1532
|
+
} catch (e18) {
|
|
1481
1533
|
return void 0;
|
|
1482
1534
|
}
|
|
1483
1535
|
}
|
|
@@ -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: _nullishCoalesce(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: _nullishCoalesce(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();
|
|
@@ -1539,7 +1638,7 @@ async function readSiwxInfo(res) {
|
|
|
1539
1638
|
return info;
|
|
1540
1639
|
}
|
|
1541
1640
|
return null;
|
|
1542
|
-
} catch (
|
|
1641
|
+
} catch (e19) {
|
|
1543
1642
|
return null;
|
|
1544
1643
|
}
|
|
1545
1644
|
}
|
|
@@ -1619,7 +1718,7 @@ function firstArray(o, ...keys) {
|
|
|
1619
1718
|
function hostOf(url) {
|
|
1620
1719
|
try {
|
|
1621
1720
|
return new URL(url).hostname;
|
|
1622
|
-
} catch (
|
|
1721
|
+
} catch (e20) {
|
|
1623
1722
|
return url;
|
|
1624
1723
|
}
|
|
1625
1724
|
}
|
|
@@ -1774,7 +1873,7 @@ var PipRailClient = (_class2 = class {
|
|
|
1774
1873
|
safeEmit(event) {
|
|
1775
1874
|
try {
|
|
1776
1875
|
this.onEvent(event);
|
|
1777
|
-
} catch (
|
|
1876
|
+
} catch (e21) {
|
|
1778
1877
|
}
|
|
1779
1878
|
}
|
|
1780
1879
|
/** Auto-mount the chain's driver, resolve the network, and bind the wallet — once. */
|
|
@@ -1908,9 +2007,15 @@ var PipRailClient = (_class2 = 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 = (_class2 = 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 = _nullishCoalesce(opts.targets, () => ( ["402index"]));
|
|
@@ -1979,7 +2099,33 @@ var PipRailClient = (_class2 = 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),
|
|
@@ -2339,7 +2485,7 @@ var PipRailClient = (_class2 = class {
|
|
|
2339
2485
|
function safeBig(s) {
|
|
2340
2486
|
try {
|
|
2341
2487
|
return BigInt(s);
|
|
2342
|
-
} catch (
|
|
2488
|
+
} catch (e22) {
|
|
2343
2489
|
return 0n;
|
|
2344
2490
|
}
|
|
2345
2491
|
}
|
|
@@ -2405,7 +2551,7 @@ function railOnNetwork(rail, matches) {
|
|
|
2405
2551
|
function hostOf2(url) {
|
|
2406
2552
|
try {
|
|
2407
2553
|
return new URL(url).hostname;
|
|
2408
|
-
} catch (
|
|
2554
|
+
} catch (e23) {
|
|
2409
2555
|
return url;
|
|
2410
2556
|
}
|
|
2411
2557
|
}
|
|
@@ -2436,7 +2582,7 @@ async function readInvalidReason(response) {
|
|
|
2436
2582
|
detail: typeof body.detail === "string" ? body.detail : ""
|
|
2437
2583
|
};
|
|
2438
2584
|
}
|
|
2439
|
-
} catch (
|
|
2585
|
+
} catch (e24) {
|
|
2440
2586
|
}
|
|
2441
2587
|
return null;
|
|
2442
2588
|
}
|
|
@@ -2447,7 +2593,7 @@ async function readBody(res) {
|
|
|
2447
2593
|
if (!text) return null;
|
|
2448
2594
|
try {
|
|
2449
2595
|
return JSON.parse(text);
|
|
2450
|
-
} catch (
|
|
2596
|
+
} catch (e25) {
|
|
2451
2597
|
return text;
|
|
2452
2598
|
}
|
|
2453
2599
|
}
|
|
@@ -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,
|
|
@@ -2685,7 +2831,7 @@ async function post(url, body, headers) {
|
|
|
2685
2831
|
let json = null;
|
|
2686
2832
|
try {
|
|
2687
2833
|
json = await res.json();
|
|
2688
|
-
} catch (
|
|
2834
|
+
} catch (e26) {
|
|
2689
2835
|
}
|
|
2690
2836
|
return { status: res.status, json };
|
|
2691
2837
|
}
|
|
@@ -2939,7 +3085,7 @@ function createPaymentGate(options) {
|
|
|
2939
3085
|
if (options.onPaid) {
|
|
2940
3086
|
try {
|
|
2941
3087
|
options.onPaid(receipt);
|
|
2942
|
-
} catch (
|
|
3088
|
+
} catch (e27) {
|
|
2943
3089
|
}
|
|
2944
3090
|
}
|
|
2945
3091
|
}
|
|
@@ -3109,7 +3255,7 @@ var GENERATOR = "@piprail/sdk \xB7 https://piprail.com";
|
|
|
3109
3255
|
function pathOf(url) {
|
|
3110
3256
|
try {
|
|
3111
3257
|
return new URL(url).pathname || "/";
|
|
3112
|
-
} catch (
|
|
3258
|
+
} catch (e28) {
|
|
3113
3259
|
return url.startsWith("/") ? url : `/${url}`;
|
|
3114
3260
|
}
|
|
3115
3261
|
}
|
|
@@ -3216,4 +3362,9 @@ function buildX402DnsTxt(input) {
|
|
|
3216
3362
|
|
|
3217
3363
|
|
|
3218
3364
|
|
|
3219
|
-
|
|
3365
|
+
|
|
3366
|
+
|
|
3367
|
+
|
|
3368
|
+
|
|
3369
|
+
|
|
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;
|