v1.13.0
Minor Changes
-
0e27642: Developer/agent-experience audit fixes: real compile-time builder safety, typed registration errors, and doc corrections.
Builder invariants are now compile-time errors. The
RouteBuilderphantom generics previously only enforced "pick an auth mode before.handler()"; every other documented mutual-exclusion rule compiled clean and threw at module-import time. The builder now tracks identity mode (IdentMode:'none' | 'siwx' | 'apiKey' | 'open') and pricing mode (BillingModegains'exact'), so all of these are TypeScript errors with readableRouteError<'…'>messages, matching the runtime throws: repeat pricing calls (.paid().upTo()),.unprotected()combined with anything,.siwx()+.apiKey(),.siwx()+.metered(), and.stream()off.metered(). Type-level regression tests live intests/builder.test-d.ts, run by vitest's typecheck pass. Code that compiled before but threw at import time may now failtsc— that's the point; runtime behavior is unchanged, with one fix below.Fix:
.unprotected().apiKey(...)no longer silently ignored.unprotected()..apiKey()was missing the mutual-exclusion guard every sibling method has; the combination now throws at registration (and fails to compile), in both call orders.New:
RouteDefinitionError. All registration-time builder throws (invalid combos, malformed prices, missing protocol config) are now instances of the exportedRouteDefinitionError(with a.routefield) instead of plainError— the registration-time sibling ofRouterConfigError. Messages are unchanged.Deprecated:
.wellKnown()//.well-known/x402as a discovery surface. The handler keeps working — existing deployments and legacy x402-native clients are unaffected — but it is no longer recommended:ServiceRouter.wellKnown()carries an@deprecatedJSDoc tag, the README no longer suggests mounting it, the example apps no longer mount it at all, and therouter.notFound()404 body'sdiscoveryhint now lists onlyopenapiandllmsTxt(thewellKnownfield was removed). Recommended discovery surfaces are/openapi.jsonand/llms.txt.Docs. Fixed contradictory discovery paths in shipped doc comments (
/api/openapiand.well-known/agentcash→ the real/openapi.json); README documents the recommended discovery route files (openapi(),llmsTxt()), adds.method('GET')to the health example (the exported const name never affects the advertised discovery verb), documents the 402 challenge shape per auth mode (header-only for payment routes, JSON body for SIWX), theX-Agent-IdentityDID-auth header,.upTo()'sCHARGE_OVER_CAPbehavior, the init-time facilitator fetch, when the body is validated relative to the 402 challenge, and a local-dev MPP keypair recipe.Internal. De-duplicated
getConfiguredX402Accepts(config/schema now imports the canonical copy), protocol header detection (hasX402Payment/hasMppPaymentshared betweendetectProtocoland the strategies), and the verbatim static/dynamic paid-flow prefix (newrunPaidPreamble/runPaidVerifyinpipeline/flows/paid-preamble.ts). -
3586d3e: Migrate to mppx 0.8.x (TIP-1034 sessions) and viem ≥2.54.
mppx ^0.6.16 → ^0.8.5: MPP session challenges are now TIP-1034 reserve-precompile sessions (sessionProtocol: "v2", escrow0x4d5050…) — the format current clients expect. TheagentcashCLI ≥0.16 (mppx 0.8.x) can now open sessions against.metered()routes; on the old server it failed session negotiation entirely. One-shot MPP charge, x402 (exact/upto), SIWX, and entitlement replay are wire-unchanged.viem ^2.47.6 → ^2.54.0: mppx 0.8.3+ requires viem ≥2.54 (Tempo transfer call builders moved to the two-argument convention); pnpm silently satisfies the peer range with the host copy, so the router's own floor must be ≥2.54 or every non-zero Tempo charge fails at credential verify.Compatibility notes:
- Clients on mppx <0.7 (e.g.
agentcashCLI ≤0.15) can no longer open MPP sessions against the router — they sign the legacy v1 flow against the v2 precompile and revert. Those CLI versions also fail one-shot MPP charge due to a client-side response-clone bug fixed in newer releases. x402 routes are unaffected for all clients. - Fee-sponsored (gas-sponsored) flows now pass mppx's sponsor policy checks (0.6.16 rejected current clients' fee budgets outright). Sponsorship requires the
MPP_FEE_PAYER_KEYaccount to hold the Tempo fee token (pathUSD) — with an unfunded sponsor, verification fails at broadcast withinsufficient funds for gas.
New options adopted from the 0.6.17→0.8.5 changelog review:
mpp.session.settlementSchedule— server-owned automatic settlement cadence for session channels ({ units?, amount?, intervalMs? }; whichever threshold trips first). Omitted, channels settle only on client close, as before.mpp.feePayerPolicy— partial override of mppx's sponsor fee-budget ceilings (maxGas,maxFeePerGas,maxPriorityFeePerGas,maxTotalFee,maxValidityWindowSeconds) for fee-sponsored charge co-signs and session open/topUp/close.- mppx
payment.failedserver events are now forwarded toplugin.onAlert(levelwarn, orerrorfor status ≥500, with method/error-type/hint/payer metadata) — previously these details only appeared in mppx's ownconsole.error. - Tempo chain config now imports from
viem/tempo/chains, the canonical entrypoint mppx itself uses.
Internal: mppx stopped exporting the SSE
SessionControllertype from a public subpath; the router now declares the structural equivalent locally. The middleware contract (charge/session → 402 challenge | 200 withReceipt),Credential.fromRequest, session credential actions (open/topUp/voucher/close), and theStore.upstashatomic-store adapter are all unchanged. - Clients on mppx <0.7 (e.g.