Skip to content

Releases: Merit-Systems/agentcash-router

v1.20.0

Choose a tag to compare

@github-actions github-actions released this 20 Jul 18:41
1fc2987

Minor Changes

  • e01487b: Remove the non-spec info.guidance key from OpenAPI output. Guidance is now exposed only via the spec-compliant info.x-guidance extension (plus /llms.txt and the well-known instructions field). Consumers reading info.guidance should switch to info["x-guidance"].

v1.19.1

Choose a tag to compare

@github-actions github-actions released this 16 Jul 21:29
a08ba49

Patch Changes

  • d2052fd: Use mppx's public SSE session-controller type for metered streaming routes.

v1.19.0

Choose a tag to compare

@github-actions github-actions released this 15 Jul 23:08
48887ce

Minor Changes

  • c1f6bb4: Enforce CAIP-2 network identifiers at the type level and document the keyless local-dev path.
    • New exported X402Network type (`eip155:${string}` | `solana:${string}`), now used by RouterConfig.network and X402AcceptConfig.network. Friendly names like 'base-sepolia' are rejected at compile time instead of throwing unsupported_x402_network at construction. TS consumers passing a plain string variable for network will need to narrow it (or use the exported constants BASE_MAINNET_NETWORK / SOLANA_MAINNET_NETWORK); the runtime validator is unchanged.
    • Fixed JSDoc on network fields that incorrectly suggested friendly names (base, base-sepolia, solana-mainnet) and a wrong @default 'base'.
    • The missing_cdp_keys error now notes that Coinbase CDP signup requires phone verification and that placeholder key values are a supported local-dev path (paid routes serve correct 402 challenges via the hardcoded facilitator baseline; real keys are only needed to verify/settle payments). Same guidance added to the README quickstart, createRouter/createRouterFromEnv JSDoc, AGENTS.md, and .env.example.

v1.18.0

Choose a tag to compare

@github-actions github-actions released this 08 Jul 19:44
c5fd197

Minor Changes

  • dab4458: Add conditional settlement via beforeSettle returning 'skip'. A paid route can now return its 2xx handler body without charging when the hook returns 'skip'; 'continue' or void proceeds to settlement as before, and throw still fails the request without settling.

    Caveat: 'skip' only applies to post-handler settlement paths (x402 exact/upto, MPP transaction/pull). MPP hash/push mode settles at verify, before beforeSettle runs — 'skip' cannot un-charge a push-mode client.

v1.17.0

Choose a tag to compare

@github-actions github-actions released this 08 Jul 16:44
a0f3327

Minor Changes

  • 2d4c51d: routerConfigFromEnv / createRouterFromEnv now require one of MPP_SECRET_KEY or the CDP key pair, and infer enabled protocols from whichever credentials are present — MPP-only services no longer need Coinbase credentials.

    • x402 is auto-enabled when CDP_API_KEY_ID + CDP_API_KEY_SECRET are set, mirroring how MPP_SECRET_KEY toggles MPP. Default protocols: CDP keys only → ['x402'], MPP secret only → ['mpp'], both → ['x402', 'mpp']. An explicit protocols option still overrides inference.
    • Neither credential set → new missing_payment_credentials issue in the up-front RouterConfigError (previously an MPP-less env failed later at createRouter with missing_cdp_keys).
    • A partial CDP pair is treated as x402 intent and fails fast with missing_cdp_keys naming the missing variable, as does an explicit protocols including 'x402' without CDP keys.
    • Soft console.warn when SOLANA_PAYEE_ADDRESS is set while x402 is disabled, since the Solana accept would otherwise silently never be served.
    • Programmatic createRouter(config) validation is unchanged: CDP keys are required only when the config has EVM x402 accepts.
  • bdbcddb: Deprecate RouterConfig.prices (and CreateRouterFromEnvOptions.prices); fix prototype-chain key lookup in the prices map.

    • prices is marked @deprecated (JSDoc only — no runtime change; auto-pricing and barrel validation keep working until removal in the next major). Every fleet service already prices inline with .paid(); auto-priced routes can't take pricing options, and the map is the only reason createRouter is generic. Migration: .route('search').paid(PRICES.search) with an optional central PRICES const; for the map's barrel-validation side effect, use a consumer-side test that globs route files and asserts router.registry.has(key), or the catch-all adapter where a missing import 404s in dev.
    • Fixed: the auto-pricing lookup used key in config.prices, which walks the prototype chain — a route named toString/valueOf/etc. on any router with a prices map picked up the inherited function as its "price" and threw at registration. Now Object.hasOwn.
  • ec3722c: Type-performance pass: eliminate the consumer-side "Type instantiation is excessively deep" hazard and shrink per-route check cost.

    • createRouter / createRouterFromEnv no longer capture the whole config as a const generic. Inference is scoped to the prices map (PriceKeysOf<P>), so the router's exported type is a small named type instead of a deferred conditional over the entire config literal (guidance strings, accepts tuples, plugin closures). Large configs previously left that conditional unresolved until some consumer file forced it at the bottom of an already-deep check stack — tripping TS's instantiation-depth limit check-order-dependently (seen on Vercel builds). The router: ServiceRouter annotation workaround is no longer needed. Note: an explicit type argument (createRouter<typeof cfg>(cfg)) now names the prices map, not the config — drop the type argument and let it infer. A prices map typed as plain Record<string, string> (built at runtime) no longer types its routes as pre-priced; use a literal map or price inline with .paid().
    • .body() / .query() / .output() are now generic over the schema (S extends ZodType, output via lazy z.output<S>) instead of extracting T from ZodType<T>, which structurally walked zod's internals per call. Router-heavy route files check 2–8× faster (e.g. 13.3ms → 1.7ms) in a traced consumer build. Handler ctx.body / ctx.query types are unchanged. Note: an explicit type argument to these methods now names the schema type, not the output type.
    • zod is now declared as a peer dependency (^4.0.0). It was previously undeclared (dev-only) while being imported at runtime, which resolved by hoisting luck and gave consumers a second zod copy — paying cross-copy structural comparisons on every .body(schema) chain.

v1.16.0

Choose a tag to compare

@github-actions github-actions released this 07 Jul 21:27
cdfdf42

Minor Changes

  • 5fd92ff: Framework-agnostic core: the router now speaks Web-standard Request/Response and dispatches through an embedded Hono app. next is no longer a peer dependency (peers are just zod).

    Heads-up for TypeScript consumers: handler and discovery signatures are now typed against Web-standard Request/Response instead of NextRequest/NextResponse, and next is no longer a peer dependency. Runtime behavior in Next.js apps is unchanged (Next accepts standard fetch handlers), but handler code that uses NextRequest-only APIs (request.nextUrl, request.cookies) needs a cast — or better, new URL(request.url) / the new ctx.params.

    New:

    • router.fetch(request) — standard fetch handler serving all registered routes at /{basePath}/{path} plus discovery surfaces; unmatched paths get the notFound() envelope.
    • router.hono() — the internal Hono app, mountable into a larger app.
    • @agentcash/router/next subpath — nextHandlers(router) for one-file Next.js catch-all hosting (app/api/[[...route]]/route.ts), replacing per-route files and the discovery barrel.
    • {param} path templates with ctx.params, extracted identically in catch-all and per-file modes.
    • RouterConfig.basePath (default 'api') — controls the mounted and advertised URL prefix.
    • .path() values are normalized like .route() paths (leading slashes / api/ prefix stripped), so a leading slash no longer produces a // URL in discovery.

    Per-file Next.js hosting (export const POST = router.route(...)...handler(...)) is unchanged.

  • 3b9cecb: Rename .metered() to .session() and tickCost to unitCost, aligning the builder with MPP terminology (the session intent prices per-unit amount × unitType; "tick" was mppx SDK slang). .metered() and tickCost remain as deprecated aliases with identical behavior and will be removed in a future release. Registration-time and type-level error messages now reference .session()/unitCost. New exported types: SessionOptions (plus MeteredOptions/UpToOptions are now exported).

  • 5b76428: Two x402 2.14–2.15 features surfaced through router config:

    Base Builder Codes (ERC-8021 attribution). Set RouterConfig.x402.builderCode or X402_BUILDER_CODE (register at dashboard.base.org → Settings → Builder Codes) and the router declares the builder-code extension with your app code on every x402 payment challenge; the facilitator appends it to settlement calldata, attributing every settled payment to your service on-chain. Malformed codes fail at startup with a structured invalid_builder_code issue.

    Bazaar catalog metadata. DiscoveryConfig (and createRouterFromEnv options) gain serviceName, tags, and iconUrl, forwarded into PaymentRequired.resource on every x402 challenge — facilitators persist them into the Bazaar discovery catalog at settlement. serviceName defaults to the discovery title when the title fits the 32-char printable-ASCII constraint, and tags defaults per-resource to the same route-derived tag the OpenAPI document advertises. Explicit values that violate the catalog limits fail at startup (invalid_discovery_service_name / invalid_discovery_tags / invalid_discovery_icon_url) instead of being silently dropped by the facilitator.

Patch Changes

  • 821e508: MPP session channels now use one shared store across the request-mode and streaming middlewares (previously each defaulted to a private in-memory store, so a channel opened through one was channel-not-found through the other). Protocol-heavy dependencies (mppx, viem/tempo, @x402/evm, …) are now loaded lazily at their call sites instead of statically, so x402-only deployments no longer bundle the MPP dependency tree (and vice versa) — this also removes the webpack "Critical dependency" warning from ox/tempo in Next.js apps that don't use MPP.
  • ef798ea: Bump @x402/core/@x402/evm/@x402/svm/@x402/extensions from 2.13.0 to 2.17.0. Notable upstream changes for router deployments: the SIWX extension's nonce/issuedAt/expirationTime are now excluded from client-echo validation (fixes spurious extension_echo_mismatch on .siwx() routes, since those fields regenerate per 402), hardened wildcard route/network pattern matching, and x402ResourceServer.initialize() now fail-fasts on scheme/facilitator capability mismatches (surfaced through the router's existing x402InitError degraded-mode path, not a crash).

v1.15.0

Choose a tag to compare

@github-actions github-actions released this 06 Jul 21:06
81d5802

Minor Changes

  • 83cf6a5: Republish of 1.14.0. The 1.14.0 and 1.14.1 version slots on npm were burned by mid-review canary builds of PR #300 (published before the review fixes landed) and should not be used. This release contains no code changes over the repo's 1.14.0 — it is the canonical release of the Solana GET /supported enrichment migration.

v1.13.0

Choose a tag to compare

@github-actions github-actions released this 06 Jul 17:28
47ffb39

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 RouteBuilder phantom 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 (BillingMode gains 'exact'), so all of these are TypeScript errors with readable RouteError<'…'> 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 in tests/builder.test-d.ts, run by vitest's typecheck pass. Code that compiled before but threw at import time may now fail tsc — 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 exported RouteDefinitionError (with a .route field) instead of plain Error — the registration-time sibling of RouterConfigError. Messages are unchanged.

    Deprecated: .wellKnown() / /.well-known/x402 as 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 @deprecated JSDoc tag, the README no longer suggests mounting it, the example apps no longer mount it at all, and the router.notFound() 404 body's discovery hint now lists only openapi and llmsTxt (the wellKnown field was removed). Recommended discovery surfaces are /openapi.json and /llms.txt.

    Docs. Fixed contradictory discovery paths in shipped doc comments (/api/openapi and .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), the X-Agent-Identity DID-auth header, .upTo()'s CHARGE_OVER_CAP behavior, 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/hasMppPayment shared between detectProtocol and the strategies), and the verbatim static/dynamic paid-flow prefix (new runPaidPreamble/runPaidVerify in pipeline/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", escrow 0x4d5050…) — the format current clients expect. The agentcash CLI ≥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. agentcash CLI ≤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_KEY account to hold the Tempo fee token (pathUSD) — with an unfunded sponsor, verification fails at broadcast with insufficient 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.failed server events are now forwarded to plugin.onAlert (level warn, or error for status ≥500, with method/error-type/hint/payer metadata) — previously these details only appeared in mppx's own console.error.
    • Tempo chain config now imports from viem/tempo/chains, the canonical entrypoint mppx itself uses.

    Internal: mppx stopped exporting the SSE SessionController type 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 the Store.upstash atomic-store adapter are all unchanged.

v1.12.0

Choose a tag to compare

@github-actions github-actions released this 26 Jun 20:09
bf41af2

Minor Changes

  • 5b5c8ca: Add optional email to discovery.contact. It is published verbatim in the generated OpenAPI info.contact.email, letting origins expose a contact address for ownership verification, user contact, and merchant-page customization (e.g. on Poncho). Omit it to keep the existing behavior.

v1.11.0

Choose a tag to compare

@github-actions github-actions released this 19 Jun 15:43
4a35438

Minor Changes

  • 2e826be: Add mpp.settleBeforeHandler on .paid() / .mpp() for per-route eager MPP transaction (pull) settlement before the handler runs. x402 on the same route is unaffected.