v1.17.0
Minor Changes
-
2d4c51d:
routerConfigFromEnv/createRouterFromEnvnow require one ofMPP_SECRET_KEYor 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_SECRETare set, mirroring howMPP_SECRET_KEYtoggles MPP. Default protocols: CDP keys only →['x402'], MPP secret only →['mpp'], both →['x402', 'mpp']. An explicitprotocolsoption still overrides inference. - Neither credential set → new
missing_payment_credentialsissue in the up-frontRouterConfigError(previously an MPP-less env failed later atcreateRouterwithmissing_cdp_keys). - A partial CDP pair is treated as x402 intent and fails fast with
missing_cdp_keysnaming the missing variable, as does an explicitprotocolsincluding'x402'without CDP keys. - Soft
console.warnwhenSOLANA_PAYEE_ADDRESSis 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.
- x402 is auto-enabled when
-
bdbcddb: Deprecate
RouterConfig.prices(andCreateRouterFromEnvOptions.prices); fix prototype-chain key lookup in the prices map.pricesis 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 reasoncreateRouteris generic. Migration:.route('search').paid(PRICES.search)with an optional centralPRICESconst; for the map's barrel-validation side effect, use a consumer-side test that globs route files and assertsrouter.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 namedtoString/valueOf/etc. on any router with a prices map picked up the inherited function as its "price" and threw at registration. NowObject.hasOwn.
-
ec3722c: Type-performance pass: eliminate the consumer-side "Type instantiation is excessively deep" hazard and shrink per-route check cost.
createRouter/createRouterFromEnvno longer capture the whole config as aconstgeneric. Inference is scoped to thepricesmap (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). Therouter: ServiceRouterannotation 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 plainRecord<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 lazyz.output<S>) instead of extractingTfromZodType<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. Handlerctx.body/ctx.querytypes are unchanged. Note: an explicit type argument to these methods now names the schema type, not the output type.zodis 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.