@piprail/sdk 1.11.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 +41 -0
- package/README.md +64 -24
- package/dist/index.cjs +204 -79
- package/dist/index.d.cts +122 -5
- package/dist/index.d.ts +122 -5
- package/dist/index.js +185 -60
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,45 @@ 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
|
+
|
|
29
|
+
## [1.12.0] — 2026-06-09
|
|
30
|
+
|
|
31
|
+
### Added — One-call domain verification (pending-review → searchable)
|
|
32
|
+
- **`client.verifyDomain()` takes a 402 Index listing all the way to searchable.** A self-registered
|
|
33
|
+
402 Index listing is `pending-review`; verifying the domain you control approves it (and every other
|
|
34
|
+
pending listing on it). `client.claimDomain(urlOrDomain, { contactEmail? })` returns the
|
|
35
|
+
`verificationHash` to serve at your `/.well-known/402index-verify.txt`; `client.verifyDomain(urlOrDomain)`
|
|
36
|
+
then flips it live. Standalone forms `claim402IndexDomain` / `verify402IndexDomain` + the
|
|
37
|
+
`DomainClaim` / `DomainVerification` types are exported. Never throws; moves no funds.
|
|
38
|
+
|
|
39
|
+
### Docs — a complete, agent-followable discovery playbook
|
|
40
|
+
- Rewrote the **"Be discoverable"** README section into a top-to-bottom **4-step playbook** an agent can
|
|
41
|
+
follow (list → verify domain → discover → self-describe), with the corrected lifecycle output
|
|
42
|
+
(`visibility` + `note`), a `DIRECTORY_INFO` reference table, and the caveats inline (402 Index is
|
|
43
|
+
pending-review; `discover()` doesn't read x402scan; x402scan needs an input schema). Updated
|
|
44
|
+
`llms-full.txt` to the same four moves (EMIT · REGISTER · VERIFY · DISCOVER).
|
|
45
|
+
|
|
7
46
|
## [1.11.0] — 2026-06-09
|
|
8
47
|
|
|
9
48
|
### Added — Agent-friendly discovery lifecycle
|
|
@@ -576,6 +615,8 @@ straight into your wallet. The API is small and self-contained.
|
|
|
576
615
|
to your wallet; PipRail never holds funds.
|
|
577
616
|
- `viem ^2.21` is a peer dependency. Node 20+ or a modern browser.
|
|
578
617
|
|
|
618
|
+
[1.13.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
619
|
+
[1.12.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
579
620
|
[1.11.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
580
621
|
[1.10.0]: https://www.npmjs.com/package/@piprail/sdk
|
|
581
622
|
[1.9.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,51 @@ 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
|
-
|
|
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):
|
|
197
212
|
|
|
198
213
|
```ts
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
resources: [await gate.describe('https://api.example.com/report')],
|
|
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 } } },
|
|
205
219
|
})
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
220
|
+
```
|
|
221
|
+
|
|
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'
|
|
227
|
+
const desc = await gate.describe('https://api.example.com/report')
|
|
228
|
+
const openapi = buildOpenApi({ origin: 'https://api.example.com', resources: [desc] }) // → /openapi.json
|
|
229
|
+
const wellKnown = buildWellKnownX402({ resources: [desc] }) // → /.well-known/x402
|
|
230
|
+
// buildX402DnsTxt(...) emits the _x402 DNS line too.
|
|
231
|
+
```
|
|
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
|
+
|
|
237
|
+
**Know each index before you call** — the facts are one import, `DIRECTORY_INFO`, and `register()`
|
|
238
|
+
projects them onto every outcome (`visibility` + `note`), so an agent never has to guess:
|
|
239
|
+
|
|
240
|
+
| Index | Write auth | Chains | On a successful register | Read by `discover()`? |
|
|
241
|
+
|---|---|---|---|---|
|
|
242
|
+
| **402 Index** (default) | none | any | `pending-review` → `verifyDomain()` for instant approval | ✅ yes |
|
|
243
|
+
| **x402scan** | one wallet sig (SIWX) | Base / Solana | `live` on x402scan.com | ❌ no (paid reads) |
|
|
244
|
+
| **CDP Bazaar** | — (facilitator-only) | — | `not-listable` for PipRail (backendless) | ✅ read-only |
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
import { DIRECTORY_INFO } from '@piprail/sdk'
|
|
248
|
+
DIRECTORY_INFO['x402scan'].readByDiscover // false — branch on this, don't guess
|
|
209
249
|
```
|
|
210
250
|
|
|
211
251
|
For an LLM/MCP these are two more tools — **`piprail_discover`** (find) and **`piprail_register`**
|