@piprail/sdk 1.14.0 → 1.15.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.
Files changed (29) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/ERRORS.md +15 -1
  3. package/README.md +38 -2
  4. package/STANDARDS.md +4 -2
  5. package/dist/{algorand-OIHGJN5S.cjs → algorand-EJ3S2V7E.cjs} +17 -17
  6. package/dist/{algorand-7EUZYL2Z.js → algorand-F3OYB534.js} +1 -1
  7. package/dist/{aptos-WDWZOU25.cjs → aptos-GJGIZHNI.cjs} +16 -16
  8. package/dist/{aptos-CDEYDDM5.js → aptos-SUXOVP7B.js} +1 -1
  9. package/dist/{chunk-H3A4KWLJ.js → chunk-ILPABTI2.js} +6 -0
  10. package/dist/{chunk-FTKVCP6K.cjs → chunk-PA6YD3HL.cjs} +17 -11
  11. package/dist/index.cjs +493 -115
  12. package/dist/index.d.cts +264 -12
  13. package/dist/index.d.ts +264 -12
  14. package/dist/index.js +403 -25
  15. package/dist/{near-DT6LRIKB.js → near-LM7S3WUD.js} +1 -1
  16. package/dist/{near-FUH3VAXT.cjs → near-ZJLZE26R.cjs} +19 -19
  17. package/dist/{solana-QUVXPKBZ.cjs → solana-MPPE6K24.cjs} +14 -14
  18. package/dist/{solana-3TRYD4QB.js → solana-WDKWWF33.js} +1 -1
  19. package/dist/{stellar-IK3UML6O.js → stellar-FIJPQZVW.js} +1 -1
  20. package/dist/{stellar-APZEBFAD.cjs → stellar-XHLLNHQP.cjs} +21 -21
  21. package/dist/{sui-L7BQNJWO.cjs → sui-6CVLEXLA.cjs} +17 -17
  22. package/dist/{sui-VSE63WQM.js → sui-B7AVN7NK.js} +1 -1
  23. package/dist/{ton-QHGQLJX2.js → ton-CHJ26BVA.js} +1 -1
  24. package/dist/{ton-5DLKKOFE.cjs → ton-RNEFN25G.cjs} +14 -14
  25. package/dist/{tron-2N2GA62O.js → tron-DD3JDROV.js} +1 -1
  26. package/dist/{tron-HHIT6WKY.cjs → tron-TKJHNFGM.cjs} +24 -24
  27. package/dist/{xrpl-2GZMDYW5.js → xrpl-GTUPP6SK.js} +1 -1
  28. package/dist/{xrpl-USEG4AHX.cjs → xrpl-XN2NBNGI.cjs} +21 -21
  29. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -4527,6 +4527,31 @@ interface PaymentPolicy {
4527
4527
  * declined, because its true decimals can't be verified. When true, the
4528
4528
  * server-stated decimals are trusted (the explicit, opt-in risk). */
4529
4529
  allowUnknownTokens?: boolean;
4530
+ /**
4531
+ * Session time-to-live in SECONDS, relative to session start (client
4532
+ * construction). After the deadline EVERY payment is refused
4533
+ * (`SESSION_EXPIRED`), regardless of amount — a headless agent's time leash.
4534
+ * When both `ttlSeconds` and `expiresAt` are set, the EARLIER deadline wins.
4535
+ * Opt-in; omit for no time limit (default). PROCESS-SCOPED — resets on restart.
4536
+ */
4537
+ ttlSeconds?: number;
4538
+ /**
4539
+ * Absolute session deadline as epoch MILLISECONDS (matches `Date.now()`).
4540
+ * SDK-only — there is no MCP env knob (the MCP exposes only the relative-seconds
4541
+ * `PIPRAIL_TTL`). A small value expires immediately BY DESIGN; it is NOT
4542
+ * auto-corrected from seconds, so pass milliseconds. Opt-in; omit for no limit.
4543
+ */
4544
+ expiresAt?: number;
4545
+ /**
4546
+ * Rolling-window spend cap per (network, asset), in human units (e.g. '1.00').
4547
+ * Refuses a payment that would push spend within the last {@link windowSeconds}
4548
+ * past this cap (`OUTSIDE_WINDOW`) — a rate limit on top of the lifetime
4549
+ * `maxTotal`. REQUIRED together with `windowSeconds`: setting one without the
4550
+ * other is a config error (a half-armed leash is forbidden). Opt-in; heavier.
4551
+ */
4552
+ windowTotal?: string;
4553
+ /** Rolling-window width in seconds for {@link windowTotal}. REQUIRED together with it. */
4554
+ windowSeconds?: number;
4530
4555
  }
4531
4556
  /** What the policy reasons over — built by the client from the chosen accept. */
4532
4557
  interface PaymentIntent {
@@ -4545,19 +4570,50 @@ interface PaymentIntent {
4545
4570
  /** Did the driver's `describeAsset` recognise this asset? */
4546
4571
  recognized: boolean;
4547
4572
  }
4573
+ /**
4574
+ * A typed, machine-readable code for WHICH guard refused a payment — set by
4575
+ * `deny()` alongside the human `reason`, so the client routes a denial to the
4576
+ * right {@link PayBlocker}/`reasonCode` WITHOUT substring-matching the prose
4577
+ * (which would silently break on a wording tweak).
4578
+ */
4579
+ type PolicyDenyCode = 'CHAIN' | 'HOST' | 'UNKNOWN_TOKEN' | 'TOKEN' | 'MAX_AMOUNT' | 'MAX_TOTAL' | 'SESSION_EXPIRED' | 'WINDOW_TOTAL';
4548
4580
  interface PolicyDecision {
4549
4581
  allowed: boolean;
4550
4582
  /** Why it was refused (only when `allowed === false`). */
4551
4583
  reason?: string;
4584
+ /** Which guard fired, as a typed enum (only when `allowed === false`). */
4585
+ code?: PolicyDenyCode;
4586
+ }
4587
+ /**
4588
+ * INTERNAL — the injected clock + the pre-sliced per-asset window total the
4589
+ * client builds for the otherwise-pure {@link evaluatePolicy}. NOT exported: the
4590
+ * client is the only producer, and keeping it private de-risks a future
4591
+ * fold-`spentForAssetBase`-into-ctx refactor. All time state is process-scoped.
4592
+ */
4593
+ interface PolicyContext {
4594
+ /** A single `Date.now()` captured per quote — the expiry check and the window edge share it. */
4595
+ now: number;
4596
+ /** Session clock origin (epoch-ms) = client construction. */
4597
+ sessionStart: number;
4598
+ /** Base units spent on THIS (network, asset) within the rolling window; `0n` when no window cap. */
4599
+ spentInWindowBase: bigint;
4552
4600
  }
4553
4601
  /**
4554
4602
  * Evaluate a payment against the policy. `spentForAssetBase` is the running
4555
4603
  * total already spent on THIS (network, asset) — supplied by the client's
4556
4604
  * ledger — and powers the per-asset `maxTotal` cap.
4557
4605
  *
4558
- * Checks run cheapest-first; the first failure wins so the reason is specific.
4606
+ * The optional `ctx` carries the injected clock + the pre-sliced window total so
4607
+ * this function stays PURE (no `Date.now()` inside). Omit `ctx` and no time check
4608
+ * runs — behaviour is byte-identical to a time-free policy.
4609
+ *
4610
+ * Checks run in a pinned, deterministic order, first-failure-wins so the reason
4611
+ * is specific: **session expiry → chains → hosts → unknown-token → tokens →
4612
+ * maxAmount → maxTotal → windowTotal**. Expiry is first because it's
4613
+ * session-global (not asset-scoped) — an expired session must always report
4614
+ * expiry, not whichever other gate happens to also fail.
4559
4615
  */
4560
- declare function evaluatePolicy(intent: PaymentIntent, policy: PaymentPolicy | undefined, spentForAssetBase: bigint): PolicyDecision;
4616
+ declare function evaluatePolicy(intent: PaymentIntent, policy: PaymentPolicy | undefined, spentForAssetBase: bigint, ctx?: PolicyContext): PolicyDecision;
4561
4617
 
4562
4618
  interface SpendRecord {
4563
4619
  url: string;
@@ -4708,6 +4764,9 @@ interface PipRailQuote {
4708
4764
  withinPolicy: boolean;
4709
4765
  /** Why the policy would refuse it (only when `withinPolicy === false`). */
4710
4766
  policyReason?: string;
4767
+ /** The TYPED reason the policy refused it (only when `withinPolicy === false`) —
4768
+ * routes the denial to the right blocker/`reasonCode` without parsing prose. */
4769
+ policyCode?: PolicyDenyCode;
4711
4770
  }
4712
4771
  /**
4713
4772
  * What `client.estimateCost(url)` returns: the priced payment requirement plus
@@ -4723,7 +4782,7 @@ interface PipRailCostQuote {
4723
4782
  cost: CostEstimate;
4724
4783
  }
4725
4784
  /** A hard reason a rail can't be settled right now — each maps to a concrete fix. */
4726
- type PayBlocker = 'INSUFFICIENT_TOKEN' | 'INSUFFICIENT_GAS' | 'RECIPIENT_NOT_READY' | 'OUTSIDE_POLICY';
4785
+ type PayBlocker = 'INSUFFICIENT_TOKEN' | 'INSUFFICIENT_GAS' | 'RECIPIENT_NOT_READY' | 'OUTSIDE_POLICY' | 'OUTSIDE_WINDOW';
4727
4786
  /** A soft flag — never blocks, always worth surfacing to the agent. */
4728
4787
  type PayWarning = 'SYMBOL_MISMATCH' | 'BALANCE_UNREADABLE' | 'RECIPIENT_READINESS_UNKNOWN' | 'GAS_HEURISTIC' | 'THIN_GAS_MARGIN';
4729
4788
  /** One offered rail, fully analysed against the bound wallet's own holdings. */
@@ -4778,6 +4837,61 @@ interface PaymentPlan {
4778
4837
  options: PayOption[];
4779
4838
  /** When NOT payable: one human, actionable sentence on exactly what to do. */
4780
4839
  fundingHint: string | null;
4840
+ /**
4841
+ * Read-only TIME envelope — present ONLY when the policy configures one
4842
+ * (`ttlSeconds`/`expiresAt`). Lets a headless (Mode A) agent SEE its remaining
4843
+ * time leash before paying, rather than discovering it by hitting a decline.
4844
+ *
4845
+ * PROCESS-SCOPED: resets to a fresh window on restart; for crash-loop-resistant
4846
+ * limits supply a pluggable durable store (the `isUsed`/`markUsed` analogue).
4847
+ * `secondsRemaining` is a best-effort host wall-clock estimate, clamped ≥ 0.
4848
+ */
4849
+ session?: {
4850
+ expiresAt: number | null;
4851
+ secondsRemaining: number | null;
4852
+ };
4853
+ }
4854
+ /**
4855
+ * A read-only view of the spend leash for a Mode-A agent — `client.budget()`.
4856
+ * Composes the in-memory ledger + the configured policy WITHOUT coupling them.
4857
+ *
4858
+ * PROCESS-SCOPED: every figure resets on restart — the session IS the process.
4859
+ * For crash-loop-resistant limits supply a pluggable durable store (the
4860
+ * `isUsed`/`markUsed` analogue). `secondsRemaining` is clamped ≥ 0.
4861
+ */
4862
+ interface SessionBudget {
4863
+ /** The session's time envelope (null fields when no `ttlSeconds`/`expiresAt`). */
4864
+ session: {
4865
+ /** Session start, ISO. */
4866
+ start: string;
4867
+ /** Deadline as ISO, or null when no time limit is configured. */
4868
+ expiresAt: string | null;
4869
+ /** Seconds until expiry (clamped ≥ 0), or null when no time limit. */
4870
+ secondsRemaining: number | null;
4871
+ };
4872
+ /** Per-(network, asset) money leash — ONE row per pair the ledger has seen. */
4873
+ byAsset: SpendRemaining[];
4874
+ }
4875
+ /**
4876
+ * Per-(network, asset) remaining budget — the money half of the leash. One row
4877
+ * per pair the LEDGER already holds (decimals are known only after the first
4878
+ * spend), so a never-spent pair simply isn't a row. `cap`/`remaining` are
4879
+ * `undefined` when no `policy.maxTotal` is set (unbounded). Never a cross-token
4880
+ * sum — there is no price oracle.
4881
+ */
4882
+ interface SpendRemaining {
4883
+ network: Caip2;
4884
+ asset: string;
4885
+ symbol?: string;
4886
+ decimals: number;
4887
+ /** Base units spent so far on this pair. */
4888
+ spentBase: string;
4889
+ /** The `maxTotal` cap in base units; undefined when unbounded. */
4890
+ capBase?: string;
4891
+ /** `max(0, cap − spent)` in base units; undefined when unbounded. */
4892
+ remainingBase?: string;
4893
+ /** `remainingBase` in human units; undefined when unbounded. */
4894
+ remainingFormatted?: string;
4781
4895
  }
4782
4896
  interface PipRailClientOptions {
4783
4897
  /** Wallet for the chosen chain family. */
@@ -4906,6 +5020,16 @@ declare class PipRailClient {
4906
5020
  private readonly ledger;
4907
5021
  private bound?;
4908
5022
  constructor(opts: PipRailClientOptions);
5023
+ /**
5024
+ * Fail LOUDLY at construction on a misconfigured time policy — a security
5025
+ * boundary must never silently half-arm. Two invariants (a misconfiguration is
5026
+ * a programmer error → `TypeError`, no new SDK error code):
5027
+ * - the rolling window needs BOTH `windowTotal` and `windowSeconds`, or NEITHER
5028
+ * (one alone is a leash that silently doesn't bite);
5029
+ * - `ttlSeconds` must be a positive, safe integer whose `*1000` deadline stays
5030
+ * within `Number.MAX_SAFE_INTEGER` (else the arithmetic would lose precision).
5031
+ */
5032
+ private assertPolicyTimeOptions;
4909
5033
  /** Emit an observability event, never letting a throwing handler break the
4910
5034
  * payment flow (mirrors the server gate's `onPaid` isolation). */
4911
5035
  private safeEmit;
@@ -4950,6 +5074,25 @@ declare class PipRailClient {
4950
5074
  /** Aggregated snapshot of every payment this client has settled — total
4951
5075
  * count, cumulative spend per token, and the individual records. */
4952
5076
  spent(): SpendSummary;
5077
+ /**
5078
+ * Read-only budget + time leash for a Mode-A (headless) agent — the policy IS
5079
+ * the consent, and this is how the agent SEES what's left of it before paying.
5080
+ * Composes the in-memory ledger with the configured policy; never throws, moves
5081
+ * no funds. PROCESS-SCOPED — every figure resets on restart (see {@link SessionBudget}).
5082
+ */
5083
+ budget(): SessionBudget;
5084
+ /**
5085
+ * Per-(network, asset) remaining budget — ONE row per pair the ledger already
5086
+ * holds (decimals are known only after the first spend), so a fresh client with
5087
+ * a `maxTotal` set returns `[]` until its first payment. `cap`/`remaining` are
5088
+ * `undefined` when no `maxTotal` is configured (unbounded). Pure + in-memory;
5089
+ * never throws, never sums across tokens (no price oracle). PROCESS-SCOPED.
5090
+ */
5091
+ remaining(): SpendRemaining[];
5092
+ /** The read-only TIME envelope for the plan/budget surfaces, or `undefined`
5093
+ * when no session deadline (`ttlSeconds`/`expiresAt`) is set. `secondsRemaining`
5094
+ * is clamped ≥ 0 — a best-effort host wall-clock estimate. */
5095
+ private sessionView;
4953
5096
  /**
4954
5097
  * Plan a payment for a gated URL — WITHOUT paying. The read-only completion of
4955
5098
  * the `quote()` → `estimateCost()` → **`planPayment()`** trio: it surveys every
@@ -5086,7 +5229,9 @@ declare class PipRailClient {
5086
5229
  * driver's describeAsset) + the policy verdict + a symbol-mismatch flag. */
5087
5230
  private buildQuote;
5088
5231
  /** Enforce the spend policy and the onBeforePay hook — both refuse by
5089
- * throwing PaymentDeclinedError, before any funds move. */
5232
+ * throwing PaymentDeclinedError, before any funds move. Every refusal carries
5233
+ * a typed `reasonCode` so an agent can branch on the cause (and spot a
5234
+ * TERMINAL expiry/approval decline it must not retry) without parsing prose. */
5090
5235
  private authorize;
5091
5236
  /** Record a settled payment in the ledger (true decimals for the running total). */
5092
5237
  private recordSpend;
@@ -5151,11 +5296,15 @@ interface AgentTool {
5151
5296
  parameters: Record<string, unknown>;
5152
5297
  /** Advisory MCP-style hints about the tool's nature (read-only, value-moving, …). */
5153
5298
  annotations?: ToolAnnotations;
5299
+ /** Optional JSON Schema (draft-07 object) for the tool's RESULT — declared only
5300
+ * on stable read-only tools so a strict client can validate `structuredContent`.
5301
+ * Kept OPEN (no `additionalProperties:false`) so additive fields never break it. */
5302
+ outputSchema?: Record<string, unknown>;
5154
5303
  /** Execute the tool. Returns a JSON-serialisable result. */
5155
5304
  invoke: (args: Record<string, unknown>) => Promise<unknown>;
5156
5305
  }
5157
5306
  /**
5158
- * Five tools wrapping a configured {@link PipRailClient}:
5307
+ * Seven tools wrapping a configured {@link PipRailClient}:
5159
5308
  * - `piprail_discover(query?)` — FIND payable resources on the open x402
5160
5309
  * indexes, WITHOUT paying (the phone book — solves "what can I buy?").
5161
5310
  * - `piprail_quote_payment(url)` — price a gated URL WITHOUT paying.
@@ -5164,12 +5313,89 @@ interface AgentTool {
5164
5313
  * - `piprail_pay_request(url, method?, body?)` — pay if needed and return the result.
5165
5314
  * - `piprail_register(url, …)` — LIST a resource you run on the open indexes so
5166
5315
  * other agents can find it (402 Index, no signature).
5316
+ * - `piprail_budget()` — read the remaining spend budget + time leash (Mode A self-check).
5317
+ * - `piprail_guide()` — read the agent contract (how to quote/plan/pay + read a refusal).
5167
5318
  *
5168
- * A policy/approval refusal comes back as a structured `{ declined: true, reason }`
5169
- * (not a thrown error), so the model can reason about it instead of crashing.
5319
+ * The first five are byte-identical in name + order to before; the two read-only
5320
+ * tools are appended LAST. EVERY failure the pay tool sees comes back as a
5321
+ * STRUCTURED object (`{ ok:false, code, reason, explain, ref?, reasonCode?,
5322
+ * declined? }`) — never a thrown error — so the model reasons about it (and never
5323
+ * re-pays a broadcast-but-unconfirmed payment) instead of crashing.
5170
5324
  */
5171
5325
  declare function paymentTools(client: PipRailClient): AgentTool[];
5172
5326
 
5327
+ /**
5328
+ * One line summarising a {@link PaymentPlan} for a model: what's payable, on which
5329
+ * chain, the gas, and how many other rails aren't settleable. `null` (the URL
5330
+ * isn't gated) → "no payment required".
5331
+ */
5332
+ declare function summarizePlan(plan: PaymentPlan | null): string;
5333
+ /**
5334
+ * One line a model can act on for any failure. For a {@link PipRailError} it
5335
+ * switches on the stable `.code`; the broadcast-but-unconfirmed codes
5336
+ * (`PAYMENT_TIMEOUT`, `MAX_RETRIES_EXCEEDED`, `CONFIRMATION_TIMEOUT`) carry the
5337
+ * load-bearing recovery rule — **recover via `.ref`, never re-pay** (a fresh
5338
+ * payment would double-spend). A non-PipRailError → `'Payment failed: <message>'`.
5339
+ */
5340
+ declare function explainDecline(err: unknown): string;
5341
+ /**
5342
+ * One line summarising spend so far, per (network, asset) — NEVER a single
5343
+ * cross-token figure (there is no price oracle). Count 0 → "no payments yet".
5344
+ *
5345
+ * NOTE: spend totals are in-memory for THIS process and reset on restart — a
5346
+ * convenience, not a durable ledger.
5347
+ */
5348
+ declare function formatSpendReport(summary: SpendSummary): string;
5349
+
5350
+ /**
5351
+ * The PipRail agent contract, distilled into one string an LLM can read once and
5352
+ * use the tools correctly with near-zero other docs. PURE — a static constant, no
5353
+ * imports, no I/O. Exposed to MCP clients as a prompt + resource, and reachable
5354
+ * from the tool layer so a headless (non-MCP) agent can prepend it to its system
5355
+ * prompt.
5356
+ *
5357
+ * Keep it tight, concrete, and tool-name-accurate — an agent will trust it
5358
+ * literally, so a wrong name or order actively misleads. A test pins the load-
5359
+ * bearing phrases.
5360
+ */
5361
+ declare const PIPRAIL_AGENT_GUIDE = "# Paying with PipRail \u2014 the agent contract\n\nYou can pay for x402 \"402 Payment Required\" resources autonomously. Money moves\nstraight from your wallet to the server; PipRail custodies nothing. Follow this.\n\n## The loop: quote \u2192 plan \u2192 pay\n1. piprail_quote_payment(url) \u2014 PRICE it. Returns the amount, token, chain, and\n whether it is within your spend policy. No funds move. Use it to decide if a\n resource is worth buying.\n2. piprail_plan_payment(url) \u2014 can I afford it NOW? Reads your balance, native gas,\n and recipient-readiness across every rail, and returns { payable, best,\n fundingHint, session? }. If payable is false, do NOT attempt the payment \u2014\n fundingHint says exactly what to fix.\n3. piprail_pay_request(url, method?, body?) \u2014 PAY (only if the plan was payable)\n and return the result.\nAlways plan before you pay so you never commit to a payment you cannot finish.\n\n## Reading a refusal \u2014 never crash, never double-spend\nA failed pay returns a STRUCTURED object, never a thrown error you must catch:\n { ok:false, code, reason, explain, ref?, reasonCode?, declined? }\nBranch on `code` (always reliable). Key cases:\n- declined:true with reasonCode:'SESSION_EXPIRED' \u2014 your time budget is over. This\n is TERMINAL: STOP. Do not retry ANY payment this process; it cannot be undone\n without a restart / a longer TTL.\n- declined:true with reasonCode:'APPROVAL' \u2014 a human (or hook) declined this\n payment. Terminal for this pay: do NOT auto-retry \u2014 they said no, or no one\n answered.\n- declined:true with reasonCode:'OUTSIDE_WINDOW' \u2014 your rolling rate-limit is\n exhausted. Wait for it to free, then retry; do not raise the amount.\n- declined:true with reasonCode:'POLICY' or 'BUDGET' \u2014 a spend cap or allowlist\n refused it. Don't retry the same payment; pick a cheaper/allowed one.\n- code:'INSUFFICIENT_FUNDS' \u2014 top up the wallet (token and/or native gas), retry.\n- code:'PAYMENT_TIMEOUT' / 'MAX_RETRIES_EXCEEDED' / 'CONFIRMATION_TIMEOUT' \u2014 the\n payment may ALREADY be on-chain. Recover using the proof on `.ref` (re-verify\n or re-submit it); never re-pay \u2014 a fresh payment would double-spend.\n- code:'NO_COMPATIBLE_ACCEPT' / 'UNSUPPORTED_SCHEME' \u2014 the 402 isn't payable on\n your chain/scheme; `explain` says whether it's the wrong chain or a scheme to enable.\n\n## Knowing your leash \u2014 call piprail_budget\npiprail_budget tells you how much budget and time you have left, per\n(network, asset), plus your spend so far. Read-only; moves no funds. Use it in\nMode A to self-check before paying.\n\n## Two modes\n- Mode A (headless, default): you run FREE inside a pre-set budget + time\n envelope. The policy IS the consent \u2014 there is no per-payment prompt. Stay\n inside it; piprail_budget shows what's left.\n- Mode B (supervised): the host may ask a human to approve each payment. A\n decline/cancel/timeout comes back as declined:true (reasonCode:'APPROVAL') \u2014\n do NOT retry it as if it were a transient error.\n\n## Hard facts\n- Spend caps are PER (network, asset). There is no single cross-token dollar cap \u2014\n budgets aren't summed across tokens (no price oracle).\n- Spend totals and the time envelope live IN-MEMORY for THIS process; they reset on restart\n (a convenience, not a durable ledger).\n";
5362
+ /** Returns {@link PIPRAIL_AGENT_GUIDE} (a parity accessor for callers that prefer a function). */
5363
+ declare function agentGuide(): string;
5364
+
5365
+ /**
5366
+ * Scheme/chain triage for an x402 challenge — a pure, never-throwing read that
5367
+ * tells an agent WHY a 402 might be unpayable: "wrong chain" vs "the scheme isn't
5368
+ * enabled" vs "no rail at all". Stops those three very different fixes from being
5369
+ * conflated into one opaque `NO_COMPATIBLE_ACCEPT`.
5370
+ *
5371
+ * PURE: imports only types (`./x402.js`, `./client.js`) — zero chain libraries,
5372
+ * zero I/O. Feed it a challenge you already parsed (`parseChallenge`) plus your
5373
+ * client's bound network + enabled schemes.
5374
+ */
5375
+
5376
+ /** The verdict of a challenge triage — what's standing between you and paying. */
5377
+ type ChallengeVerdict = 'PAYABLE_RAIL' | 'UNPAYABLE_SCHEME' | 'WRONG_CHAIN' | 'NO_RAIL';
5378
+ interface ChallengeTriage {
5379
+ /** Does any offered rail sit on the client's bound network? */
5380
+ onClientChain: boolean;
5381
+ /** Does any rail on the client's network use an enabled scheme? */
5382
+ payableScheme: boolean;
5383
+ /** The distinct schemes the challenge offers. */
5384
+ offeredSchemes: PaymentScheme[];
5385
+ /** The distinct networks the challenge offers. */
5386
+ offeredNetworks: Caip2[];
5387
+ /** The one-word verdict. */
5388
+ verdict: ChallengeVerdict;
5389
+ }
5390
+ /**
5391
+ * Bucket `challenge.accepts[]` by (network === `opts.network`) and
5392
+ * (scheme ∈ `opts.schemes`) and return the verdict. Never throws.
5393
+ */
5394
+ declare function classifyChallenge(challenge: X402Challenge, opts: {
5395
+ network: Caip2;
5396
+ schemes: readonly PaymentScheme[];
5397
+ }): ChallengeTriage;
5398
+
5173
5399
  /**
5174
5400
  * Discovery — make a gated resource FINDABLE, by emitting the open-standard
5175
5401
  * artifacts a crawler/index reads. PURE: this file turns the config a gate
@@ -5772,15 +5998,41 @@ declare class MaxRetriesExceededError extends PipRailError {
5772
5998
  ref?: string;
5773
5999
  });
5774
6000
  }
6001
+ /**
6002
+ * A typed, machine-readable discriminator on a {@link PaymentDeclinedError} so an
6003
+ * agent can branch on WHY a payment was refused WITHOUT regexing the human
6004
+ * message. It's a HINT layered on top of the always-reliable `.code`
6005
+ * (`'PAYMENT_DECLINED'`) — the two-channel error model is unchanged; this adds NO
6006
+ * new `.code`. Values:
6007
+ * - `'POLICY'` — a chain/host/token/per-payment cap refused it.
6008
+ * - `'BUDGET'` — the per-(network,asset) lifetime `maxTotal` cap.
6009
+ * - `'OUTSIDE_WINDOW'` — the rolling `windowTotal` cap (wait for it to slide).
6010
+ * - `'SESSION_EXPIRED'`— the session TTL elapsed. **TERMINAL** — every payment
6011
+ * this process is now refused; do NOT retry, restart/extend the TTL.
6012
+ * - `'APPROVAL'` — an `onBeforePay` approval hook said no (e.g. an MCP
6013
+ * human-in-the-loop decline). Terminal for this pay — do NOT auto-retry.
6014
+ */
6015
+ type DeclineReasonCode = 'POLICY' | 'BUDGET' | 'OUTSIDE_WINDOW' | 'SESSION_EXPIRED' | 'APPROVAL';
5775
6016
  /**
5776
6017
  * The client refused to pay BEFORE any on-chain send — the quoted payment
5777
- * exceeded the configured {@link PaymentPolicy} (amount/total ceiling, or a
5778
- * chain/token/host outside the allowlist), or an `onBeforePay` hook returned
5779
- * `false`. No funds moved. The message names which guard fired; inspect the
5780
- * `quote` via `client.quote(url)` to see the full breakdown.
6018
+ * exceeded the configured {@link PaymentPolicy} (amount/total ceiling, a
6019
+ * chain/token/host outside the allowlist, or the session's time envelope), or an
6020
+ * `onBeforePay` hook returned `false`. No funds moved. The message names which
6021
+ * guard fired; inspect the `quote` via `client.quote(url)` to see the full
6022
+ * breakdown.
6023
+ *
6024
+ * `.reasonCode` is an optional, typed {@link DeclineReasonCode} the client stamps
6025
+ * so an agent can branch on the cause (and spot a TERMINAL `'SESSION_EXPIRED'` /
6026
+ * `'APPROVAL'` it must not retry) without parsing the prose. `.code` stays
6027
+ * `'PAYMENT_DECLINED'`.
5781
6028
  */
5782
6029
  declare class PaymentDeclinedError extends PipRailError {
5783
6030
  readonly code = "PAYMENT_DECLINED";
6031
+ /** Why it was declined, as a typed enum (a hint; `.code` is the reliable channel). */
6032
+ readonly reasonCode?: DeclineReasonCode;
6033
+ constructor(message: string, options?: ErrorOptions & {
6034
+ reasonCode?: DeclineReasonCode;
6035
+ });
5784
6036
  }
5785
6037
  /**
5786
6038
  * The payment broadcast but didn't confirm within the driver's polling window
@@ -6125,4 +6377,4 @@ declare function readExactDomain(publicClient: PublicClient, asset: string): Pro
6125
6377
  version: string;
6126
6378
  } | null>;
6127
6379
 
6128
- 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, type PaymentScheme, 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 SettleOutcome, 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, UnsupportedSchemeError, 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, buildExactSignatureHeader, buildOpenApi, buildReceiptHeader, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, createPaymentGate, decorateOutcome, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, getDirectoryInfo, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseReceipt, parseSettleResponse, parseSignatureHeader, paymentTools, pickAccept, planAcross, readExactDomain, register402Index, registerDriver, registerX402Scan, requirePayment, resolveChain, searchOpenIndexes, settleViaFacilitator, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };
6380
+ 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 ChallengeTriage, type ChallengeVerdict, type ConfirmInfo, ConfirmationTimeoutError, type CostEstimate, DIRECTORY_INFO, type DeclineReasonCode, 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, PIPRAIL_AGENT_GUIDE, type ParsedExactPayment, type PayBlocker, type PayOption, type PayWarning, PaymentDeclinedError, type PaymentDriver, type PaymentGate, type PaymentIntent, type PaymentPlan, type PaymentPolicy, type PaymentRail, type PaymentScheme, PaymentTimeoutError, PipRailClient, type PipRailClientOptions, type PipRailCostQuote, PipRailError, type PipRailEvent, type PipRailQuote, type PolicyDecision, type PolicyDenyCode, RecipientNotReadyError, type RecipientReason, type RegisterInput, type RegisterOptions, type RegisterOutcome, type RequirePaymentOptions, type ResolveOptions, type ResolvedChain, type ResolvedNetwork, type ResolvedToken, type ResourceDescription, type SearchOpenIndexesOptions, type SessionBudget, type SettleOutcome, type SettleViaFacilitatorInput, SettlementError, type SolanaToken, type SpendAssetTotal, type SpendRecord, type SpendRemaining, type SpendSummary, type StellarToken, type SuiToken, type TokenInfo, type TokenInput, type TonToken, type ToolAnnotations, type TronToken, UnknownTokenError, UnsupportedNetworkError, UnsupportedSchemeError, 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, agentGuide, buildBazaarExtension, buildChallengeHeader, buildExactAuthorization, buildExactSignatureHeader, buildOpenApi, buildReceiptHeader, buildSignatureHeader, buildWellKnownX402, buildX402DnsTxt, chainIdForExactNetwork, claim402IndexDomain, classifyChallenge, createPaymentGate, decorateOutcome, eip3009Abi, encodeXPaymentHeader, evaluatePolicy, explainDecline, formatSpendReport, getDirectoryInfo, normalizeNetwork, parseChallenge, parseExactPaymentHeader, parseExactRequirements, parseReceipt, parseSettleResponse, parseSignatureHeader, paymentTools, pickAccept, planAcross, readExactDomain, register402Index, registerDriver, registerX402Scan, requirePayment, resolveChain, searchOpenIndexes, settleViaFacilitator, summarizePlan, toInsufficientFundsError, toInvalidBody, verify402IndexDomain };