@agentcash/router 1.6.0 → 1.7.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/dist/index.d.cts CHANGED
@@ -4,7 +4,6 @@ import { ZodType } from 'zod';
4
4
  import { PaymentRequirements, PaymentRequired, VerifyResponse, SettleResponse, Network } from '@x402/core/types';
5
5
  import * as viem from 'viem';
6
6
  import { Transport } from 'mppx/server';
7
- import { Store } from 'mppx';
8
7
 
9
8
  interface KvStore {
10
9
  get(key: string): Promise<unknown>;
@@ -26,42 +25,15 @@ type KvChange<R> = {
26
25
  op: 'delete';
27
26
  result: R;
28
27
  };
29
- declare function withPrefix(kv: KvStore, prefix: string): KvStore;
30
28
 
31
- declare const SIWX_CHALLENGE_EXPIRY_MS: number;
32
29
  interface NonceStore {
33
30
  check(nonce: string): Promise<boolean>;
34
31
  }
35
- declare class MemoryNonceStore implements NonceStore {
36
- private seen;
37
- check(nonce: string): Promise<boolean>;
38
- private evict;
39
- }
40
- interface KvNonceStoreOptions {
41
- prefix?: string;
42
- ttlMs?: number;
43
- }
44
- declare function createKvNonceStore(kv: KvStore, options?: KvNonceStoreOptions): NonceStore;
45
32
 
46
33
  interface EntitlementStore {
47
34
  has(route: string, wallet: string): Promise<boolean>;
48
35
  grant(route: string, wallet: string): Promise<void>;
49
36
  }
50
- declare class MemoryEntitlementStore implements EntitlementStore {
51
- private readonly routeToWallets;
52
- has(route: string, wallet: string): Promise<boolean>;
53
- grant(route: string, wallet: string): Promise<void>;
54
- }
55
- interface KvEntitlementStoreOptions {
56
- prefix?: string;
57
- }
58
- declare function createKvEntitlementStore(kv: KvStore, options?: KvEntitlementStoreOptions): EntitlementStore;
59
-
60
- type MppStore = Store.Store;
61
- interface KvMppStoreOptions {
62
- prefix?: string;
63
- }
64
- declare function createKvMppStore(kv: KvStore, options?: KvMppStoreOptions): Promise<MppStore>;
65
37
 
66
38
  interface RequestMeta {
67
39
  requestId: string;
@@ -137,7 +109,6 @@ interface RouterPlugin {
137
109
  onAlert?(ctx: PluginContext, alert: AlertEvent): void;
138
110
  onProviderQuota?(ctx: PluginContext, event: ProviderQuotaEvent): void;
139
111
  }
140
- declare function consolePlugin(): RouterPlugin;
141
112
 
142
113
  declare class HttpError extends Error {
143
114
  readonly status: number;
@@ -222,10 +193,6 @@ interface X402AcceptConfig extends X402AcceptBase {
222
193
  /** Per-accept payee override. Function form receives the request and parsed body for dynamic recipient routing. Falls back to `RouterConfig.payeeAddress`. */
223
194
  payTo?: PayToConfig;
224
195
  }
225
- interface X402ResolvedAccept extends X402AcceptBase {
226
- scheme: string;
227
- payTo: string;
228
- }
229
196
  interface X402RouterFacilitatorConfig extends FacilitatorConfig {
230
197
  /** Async header builder invoked per facilitator call. Use for short-lived auth tokens (e.g. CDP signed headers). */
231
198
  createAcceptsHeaders?: () => Promise<Record<string, string>>;
@@ -233,9 +200,7 @@ interface X402RouterFacilitatorConfig extends FacilitatorConfig {
233
200
  /** A facilitator URL or a full `FacilitatorConfig` (URL + auth header builders). */
234
201
  type X402FacilitatorTarget = string | X402RouterFacilitatorConfig;
235
202
  interface X402FacilitatorsConfig {
236
- /** Facilitator for EVM chains (Base, etc.). Defaults to the Coinbase facilitator using `CDP_API_KEY_ID`/`CDP_API_KEY_SECRET`. */
237
- evm?: X402FacilitatorTarget;
238
- /** Facilitator for Solana. Required to accept Solana payments — there's no default. */
203
+ /** Facilitator for Solana. Defaults to {@link DEFAULT_SOLANA_FACILITATOR_URL}. The EVM facilitator is hardcoded to Coinbase (CDP) set `CDP_API_KEY_ID` / `CDP_API_KEY_SECRET`. */
239
204
  solana?: X402FacilitatorTarget;
240
205
  }
241
206
  interface MppProtocolInfo {
@@ -409,7 +374,7 @@ interface RouterConfig {
409
374
  /** Per-chain facilitator overrides (`evm`/`solana`). Defaults to the Coinbase facilitator on EVM; set `solana` to accept Solana payments. */
410
375
  facilitators?: X402FacilitatorsConfig;
411
376
  };
412
- /** Observability hook receiving request/auth/payment/settlement events. Use `consolePlugin` for dev, or implement `RouterPlugin` for structured logs/analytics. */
377
+ /** Observability hook receiving request/auth/payment/settlement events. Implement `RouterPlugin` for structured logs/analytics. */
413
378
  plugin?: RouterPlugin;
414
379
  /** Single KV cache for SIWX nonce, SIWX entitlement, and MPP tx-hash replay (prefixed `siwx:nonce:`, `siwx:ent:`, `mpp:`). Pass `{ url, token }` for an Upstash-compatible REST endpoint (Upstash, Vercel KV), or a custom `KvStore` implementation. Omitted: auto-bootstraps from `KV_REST_API_URL` + `KV_REST_API_TOKEN`; falls back to in-memory when missing (unsafe in serverless). */
415
380
  kvStore?: KvStore | {
@@ -422,7 +387,7 @@ interface RouterConfig {
422
387
  mpp?: {
423
388
  /** HMAC key for signing/verifying MPP challenge nonces. Persist across deploys — rotating invalidates outstanding 402 challenges. Falls back to `MPP_SECRET_KEY`. */
424
389
  secretKey: string;
425
- /** Tempo currency contract address (0x-prefixed). Use `TEMPO_USDC_CURRENCY` for USDC on Tempo. */
390
+ /** Tempo currency contract address (0x-prefixed). Use `TEMPO_USDC_ADDRESS` for USDC on Tempo. */
426
391
  currency: string;
427
392
  /** MPP payee address (EVM). Overrides `payeeAddress` for MPP only. Required when `payeeAddress` is unset. MUST equal `operatorKey`'s derived address when `session` is enabled. */
428
393
  recipient?: string;
@@ -827,50 +792,83 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
827
792
  private register;
828
793
  }
829
794
 
830
- declare const BASE_NETWORK = "eip155:8453";
831
- declare const SOLANA_MAINNET_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
832
- declare const TEMPO_USDC_CURRENCY = "0x20c000000000000000000000b9537d11c60e8b50";
833
- declare const ZERO_EVM_ADDRESS = "0x0000000000000000000000000000000000000000";
834
-
835
- type RouterEnv = Record<string, string | undefined>;
836
- type RouterConfigIssueCode = 'missing_base_url' | 'empty_protocols' | 'missing_x402_accepts' | 'missing_x402_network' | 'unsupported_x402_network' | 'missing_x402_asset' | 'invalid_x402_decimals' | 'missing_x402_payee' | 'missing_cdp_keys' | 'placeholder_payee' | 'missing_mpp_config' | 'missing_mpp_secret_key' | 'missing_mpp_currency' | 'invalid_mpp_currency' | 'missing_mpp_recipient' | 'invalid_mpp_recipient' | 'missing_mpp_rpc_url' | 'invalid_mpp_fee_payer_key' | 'invalid_mpp_operator_key' | 'mpp_operator_equals_fee_payer';
795
+ type RouterConfigIssueCode = 'missing_base_url' | 'invalid_base_url' | 'empty_protocols' | 'missing_x402_accepts' | 'missing_x402_network' | 'unsupported_x402_network' | 'missing_x402_asset' | 'invalid_x402_decimals' | 'missing_x402_payee' | 'invalid_x402_payee' | 'invalid_solana_payee' | 'invalid_solana_facilitator_url' | 'missing_cdp_keys' | 'placeholder_payee' | 'missing_mpp_config' | 'missing_mpp_secret_key' | 'missing_mpp_currency' | 'invalid_mpp_currency' | 'missing_mpp_recipient' | 'invalid_mpp_recipient' | 'missing_mpp_rpc_url' | 'invalid_mpp_rpc_url' | 'invalid_mpp_fee_payer_key' | 'invalid_mpp_operator_key' | 'mpp_operator_equals_fee_payer' | 'missing_discovery_title' | 'missing_discovery_description' | 'missing_discovery_guidance' | 'invalid_server_url' | 'kv_url_without_token' | 'kv_token_without_url' | 'invalid_kv_url' | 'missing_kv_in_production';
796
+ type RouterConfigIssueSeverity = 'error' | 'warning';
837
797
  interface RouterConfigIssue {
838
798
  code: RouterConfigIssueCode;
839
799
  message: string;
840
800
  protocol?: ProtocolType;
841
- }
842
- interface RouterConfigValidationOptions {
843
- env?: RouterEnv;
844
- requireCdpKeys?: boolean;
801
+ /** @default 'error' — warnings are surfaced via `console.warn` and do not throw. */
802
+ severity?: RouterConfigIssueSeverity;
803
+ }
804
+ /** Options for {@link createRouterFromEnv} / {@link routerConfigFromEnv}. */
805
+ interface CreateRouterFromEnvOptions<TPrices extends Record<string, string> = Record<never, string>> {
806
+ /** Defaults to `process.env`. Pass an explicit object in tests. */
807
+ env?: Record<string, string | undefined>;
808
+ /** Discovery title. Shown in `.well-known/agentcash`, OpenAPI, and `/llms.txt`. */
809
+ title: string;
810
+ /** Discovery description. */
811
+ description: string;
812
+ /** Long-form usage guidance for agent consumers. Served at `/llms.txt`. Pass an empty string to opt out. */
813
+ guidance: string;
814
+ /** Discovery version. @default '1.0.0' */
815
+ version?: string;
816
+ /** Optional contact metadata published in discovery. */
817
+ contact?: DiscoveryConfig['contact'];
818
+ /** Optional ownership proofs published in `.well-known/agentcash`. */
819
+ ownershipProofs?: string[];
820
+ /** Per-route HTTP method hint visibility. */
821
+ methodHints?: DiscoveryConfig['methodHints'];
822
+ /** Override the OpenAPI `servers[].url`. Defaults to `BASE_URL`. */
823
+ serverUrl?: string;
824
+ /** Centralized price map keyed by route id. `route(key)` auto-applies `.paid(prices[key])` for matching keys. */
825
+ prices?: TPrices;
826
+ /** Observability plugin. */
827
+ plugin?: RouterPlugin;
828
+ /** Custom KV store. When omitted, the router auto-bootstraps from `KV_REST_API_URL` + `KV_REST_API_TOKEN`. */
829
+ kvStore?: KvStore;
830
+ /** Override x402 facilitators. The Solana facilitator defaults to `SOLANA_FACILITATOR_URL` env or `DEFAULT_SOLANA_FACILITATOR_URL`. */
831
+ x402Facilitators?: X402FacilitatorsConfig;
832
+ /** Explicit protocol list. Default: `['x402']`, with `'mpp'` added when `MPP_SECRET_KEY` is set. */
833
+ protocols?: readonly ProtocolType[];
834
+ /** Require `route({ path })` form for every route. @default false */
835
+ strictRoutes?: boolean;
845
836
  }
846
837
 
847
838
  declare class RouterConfigError extends Error {
848
839
  readonly issues: RouterConfigIssue[];
849
840
  constructor(issues: RouterConfigIssue[]);
850
841
  }
851
- declare function formatRouterConfigIssues(issues: readonly RouterConfigIssue[]): string;
852
-
853
- declare function validateRouterConfig(config: RouterConfig, options?: RouterConfigValidationOptions): void;
854
- declare function getRouterConfigIssues(config: RouterConfig, options?: RouterConfigValidationOptions): RouterConfigIssue[];
855
842
 
856
- declare function mppFromEnv(env: RouterEnv, options?: {
857
- recipient?: string;
858
- require?: boolean;
859
- feePayerKey?: string;
860
- }): RouterConfig['mpp'] | undefined;
861
- declare function x402AcceptsFromEnv(env: RouterEnv, options?: {
862
- payeeAddress?: string;
863
- payeeEnv?: string;
864
- network?: string;
865
- solanaPayeeAddress?: string;
866
- solanaPayeeEnv?: string;
867
- }): X402AcceptConfig[];
868
- declare function paidOptionsForProtocols(protocols: readonly ProtocolType[]): PaidOptions;
843
+ /**
844
+ * Build a {@link RouterConfig} from environment variables.
845
+ *
846
+ * `envShape` in this file is the single source of truth for env vars; README
847
+ * and `.env.example` are drift-tested against `ENV_KEYS`. Validates every
848
+ * required value up front and throws a single {@link RouterConfigError}
849
+ * containing all issues at once. Soft warnings (e.g. half-configured KV) are
850
+ * emitted via `console.warn`.
851
+ */
852
+ declare function routerConfigFromEnv<const TPrices extends Record<string, string> = Record<never, string>>(options: CreateRouterFromEnvOptions<TPrices>): RouterConfig & {
853
+ prices?: TPrices;
854
+ };
869
855
 
870
- /** SIWX verification error codes. */
871
- type SiwxErrorCode = 'siwx_missing_header' | 'siwx_malformed' | 'siwx_expired' | 'siwx_nonce_used' | 'siwx_invalid_signature';
872
- /** Human-readable error messages for each SIWX error code. */
873
- declare const SIWX_ERROR_MESSAGES: Record<SiwxErrorCode, string>;
856
+ /** Base mainnet CAIP-2 network ID (`eip155:8453`). */
857
+ declare const BASE_MAINNET_NETWORK = "eip155:8453";
858
+ /** Solana mainnet CAIP-2 network ID. */
859
+ declare const SOLANA_MAINNET_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
860
+ /** USDC contract address on Tempo (the `mpp.currency` value for Tempo USDC). */
861
+ declare const TEMPO_USDC_ADDRESS = "0x20c000000000000000000000b9537d11c60e8b50";
862
+ /** USDC has 6 decimals on Tempo. */
863
+ declare const TEMPO_USDC_DECIMALS = 6;
864
+ /** USDC contract on Base mainnet. */
865
+ declare const BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
866
+ /** USDC has 6 decimals on Base. */
867
+ declare const BASE_USDC_DECIMALS = 6;
868
+ /** All-zeros EVM address. Used as a placeholder/sentinel; not a valid payee. */
869
+ declare const ZERO_EVM_ADDRESS = "0x0000000000000000000000000000000000000000";
870
+ /** Public Solana x402 facilitator. Override per-deployment via `SOLANA_FACILITATOR_URL`. */
871
+ declare const DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.corbits.dev";
874
872
 
875
873
  interface MonitorEntry {
876
874
  provider: string;
@@ -891,5 +889,26 @@ interface ServiceRouter<TPriceKeys extends string = never> {
891
889
  declare function createRouter<const P extends Record<string, string> = Record<never, string>>(config: RouterConfig & {
892
890
  prices?: P;
893
891
  }): ServiceRouter<Extract<keyof P, string>>;
892
+ /**
893
+ * Build a {@link ServiceRouter} from environment variables.
894
+ *
895
+ * Validates every required env var up front and throws a single
896
+ * {@link RouterConfigError} containing all problems at once. Most consumers
897
+ * should use this entry point. Use {@link createRouter} when you need to
898
+ * construct a {@link RouterConfig} programmatically.
899
+ *
900
+ * The env vars this function reads are the canonical schema in
901
+ * `src/config/schema.ts` (`ENV_SPEC`).
902
+ *
903
+ * @example
904
+ * ```ts
905
+ * export const router = createRouterFromEnv({
906
+ * title: 'My API',
907
+ * description: 'Pay-per-call search.',
908
+ * guidance: 'POST /search with { q: string }. Returns top 10 results.',
909
+ * });
910
+ * ```
911
+ */
912
+ declare function createRouterFromEnv<const P extends Record<string, string> = Record<never, string>>(options: CreateRouterFromEnvOptions<P>): ServiceRouter<Extract<keyof P, string>>;
894
913
 
895
- export { type AlertEvent, type AlertFn, type AlertLevel, type AuthEvent, type AuthMode, BASE_NETWORK, type DiscoveryConfig, type EntitlementStore, type ErrorEvent, type HandlerContext, type HandlerPaymentContext, HttpError, type KvChange, type KvEntitlementStoreOptions, type KvMppStoreOptions, type KvNonceStoreOptions, type KvStore, MemoryEntitlementStore, MemoryNonceStore, type MonitorEntry, type MppProtocolInfo, type NonceStore, type OveragePolicy, type PaidOptions, type PayToConfig, type PaymentEvent, type PaymentStatus, type PluginContext, type PricingConfig, type ProtocolType, type ProviderConfig, type ProviderQuotaEvent, type QuotaInfo, type QuotaLevel, type RequestMeta, type ResponseMeta, RouteBuilder, type RouteEntry, RouteRegistry, type RouterConfig, RouterConfigError, type RouterConfigIssue, type RouterConfigIssueCode, type RouterConfigValidationOptions, type RouterEnv, type RouterPlugin, SIWX_CHALLENGE_EXPIRY_MS, SIWX_ERROR_MESSAGES, SOLANA_MAINNET_NETWORK, type ServiceRouter, type SettledHandlerErrorContext, type SettlementErrorContext, type SettlementEvent, type SettlementLifecycle, type SettlementLifecycleContext, type SettlementSettledContext, type SiwxErrorCode, type StreamingHandlerContext, TEMPO_USDC_CURRENCY, type TierConfig, type X402AcceptConfig, type X402FacilitatorTarget, type X402FacilitatorsConfig, type X402ResolvedAccept, type X402RouterFacilitatorConfig, type X402Server, ZERO_EVM_ADDRESS, consolePlugin, createKvEntitlementStore, createKvMppStore, createKvNonceStore, createRouter, formatRouterConfigIssues, getRouterConfigIssues, mppFromEnv, paidOptionsForProtocols, validateRouterConfig, withPrefix, x402AcceptsFromEnv };
914
+ export { BASE_MAINNET_NETWORK, BASE_USDC_ADDRESS, BASE_USDC_DECIMALS, type CreateRouterFromEnvOptions, DEFAULT_SOLANA_FACILITATOR_URL, type DiscoveryConfig, type HandlerContext, HttpError, type KvStore, type PaidOptions, type ProtocolType, type RouterConfig, RouterConfigError, type RouterConfigIssue, type RouterConfigIssueCode, type RouterConfigIssueSeverity, type RouterPlugin, SOLANA_MAINNET_NETWORK, type ServiceRouter, type SettlementErrorContext, type SettlementLifecycleContext, type SettlementSettledContext, TEMPO_USDC_ADDRESS, TEMPO_USDC_DECIMALS, type X402FacilitatorsConfig, ZERO_EVM_ADDRESS, createRouter, createRouterFromEnv, routerConfigFromEnv };
package/dist/index.d.ts CHANGED
@@ -4,7 +4,6 @@ import { ZodType } from 'zod';
4
4
  import { PaymentRequirements, PaymentRequired, VerifyResponse, SettleResponse, Network } from '@x402/core/types';
5
5
  import * as viem from 'viem';
6
6
  import { Transport } from 'mppx/server';
7
- import { Store } from 'mppx';
8
7
 
9
8
  interface KvStore {
10
9
  get(key: string): Promise<unknown>;
@@ -26,42 +25,15 @@ type KvChange<R> = {
26
25
  op: 'delete';
27
26
  result: R;
28
27
  };
29
- declare function withPrefix(kv: KvStore, prefix: string): KvStore;
30
28
 
31
- declare const SIWX_CHALLENGE_EXPIRY_MS: number;
32
29
  interface NonceStore {
33
30
  check(nonce: string): Promise<boolean>;
34
31
  }
35
- declare class MemoryNonceStore implements NonceStore {
36
- private seen;
37
- check(nonce: string): Promise<boolean>;
38
- private evict;
39
- }
40
- interface KvNonceStoreOptions {
41
- prefix?: string;
42
- ttlMs?: number;
43
- }
44
- declare function createKvNonceStore(kv: KvStore, options?: KvNonceStoreOptions): NonceStore;
45
32
 
46
33
  interface EntitlementStore {
47
34
  has(route: string, wallet: string): Promise<boolean>;
48
35
  grant(route: string, wallet: string): Promise<void>;
49
36
  }
50
- declare class MemoryEntitlementStore implements EntitlementStore {
51
- private readonly routeToWallets;
52
- has(route: string, wallet: string): Promise<boolean>;
53
- grant(route: string, wallet: string): Promise<void>;
54
- }
55
- interface KvEntitlementStoreOptions {
56
- prefix?: string;
57
- }
58
- declare function createKvEntitlementStore(kv: KvStore, options?: KvEntitlementStoreOptions): EntitlementStore;
59
-
60
- type MppStore = Store.Store;
61
- interface KvMppStoreOptions {
62
- prefix?: string;
63
- }
64
- declare function createKvMppStore(kv: KvStore, options?: KvMppStoreOptions): Promise<MppStore>;
65
37
 
66
38
  interface RequestMeta {
67
39
  requestId: string;
@@ -137,7 +109,6 @@ interface RouterPlugin {
137
109
  onAlert?(ctx: PluginContext, alert: AlertEvent): void;
138
110
  onProviderQuota?(ctx: PluginContext, event: ProviderQuotaEvent): void;
139
111
  }
140
- declare function consolePlugin(): RouterPlugin;
141
112
 
142
113
  declare class HttpError extends Error {
143
114
  readonly status: number;
@@ -222,10 +193,6 @@ interface X402AcceptConfig extends X402AcceptBase {
222
193
  /** Per-accept payee override. Function form receives the request and parsed body for dynamic recipient routing. Falls back to `RouterConfig.payeeAddress`. */
223
194
  payTo?: PayToConfig;
224
195
  }
225
- interface X402ResolvedAccept extends X402AcceptBase {
226
- scheme: string;
227
- payTo: string;
228
- }
229
196
  interface X402RouterFacilitatorConfig extends FacilitatorConfig {
230
197
  /** Async header builder invoked per facilitator call. Use for short-lived auth tokens (e.g. CDP signed headers). */
231
198
  createAcceptsHeaders?: () => Promise<Record<string, string>>;
@@ -233,9 +200,7 @@ interface X402RouterFacilitatorConfig extends FacilitatorConfig {
233
200
  /** A facilitator URL or a full `FacilitatorConfig` (URL + auth header builders). */
234
201
  type X402FacilitatorTarget = string | X402RouterFacilitatorConfig;
235
202
  interface X402FacilitatorsConfig {
236
- /** Facilitator for EVM chains (Base, etc.). Defaults to the Coinbase facilitator using `CDP_API_KEY_ID`/`CDP_API_KEY_SECRET`. */
237
- evm?: X402FacilitatorTarget;
238
- /** Facilitator for Solana. Required to accept Solana payments — there's no default. */
203
+ /** Facilitator for Solana. Defaults to {@link DEFAULT_SOLANA_FACILITATOR_URL}. The EVM facilitator is hardcoded to Coinbase (CDP) set `CDP_API_KEY_ID` / `CDP_API_KEY_SECRET`. */
239
204
  solana?: X402FacilitatorTarget;
240
205
  }
241
206
  interface MppProtocolInfo {
@@ -409,7 +374,7 @@ interface RouterConfig {
409
374
  /** Per-chain facilitator overrides (`evm`/`solana`). Defaults to the Coinbase facilitator on EVM; set `solana` to accept Solana payments. */
410
375
  facilitators?: X402FacilitatorsConfig;
411
376
  };
412
- /** Observability hook receiving request/auth/payment/settlement events. Use `consolePlugin` for dev, or implement `RouterPlugin` for structured logs/analytics. */
377
+ /** Observability hook receiving request/auth/payment/settlement events. Implement `RouterPlugin` for structured logs/analytics. */
413
378
  plugin?: RouterPlugin;
414
379
  /** Single KV cache for SIWX nonce, SIWX entitlement, and MPP tx-hash replay (prefixed `siwx:nonce:`, `siwx:ent:`, `mpp:`). Pass `{ url, token }` for an Upstash-compatible REST endpoint (Upstash, Vercel KV), or a custom `KvStore` implementation. Omitted: auto-bootstraps from `KV_REST_API_URL` + `KV_REST_API_TOKEN`; falls back to in-memory when missing (unsafe in serverless). */
415
380
  kvStore?: KvStore | {
@@ -422,7 +387,7 @@ interface RouterConfig {
422
387
  mpp?: {
423
388
  /** HMAC key for signing/verifying MPP challenge nonces. Persist across deploys — rotating invalidates outstanding 402 challenges. Falls back to `MPP_SECRET_KEY`. */
424
389
  secretKey: string;
425
- /** Tempo currency contract address (0x-prefixed). Use `TEMPO_USDC_CURRENCY` for USDC on Tempo. */
390
+ /** Tempo currency contract address (0x-prefixed). Use `TEMPO_USDC_ADDRESS` for USDC on Tempo. */
426
391
  currency: string;
427
392
  /** MPP payee address (EVM). Overrides `payeeAddress` for MPP only. Required when `payeeAddress` is unset. MUST equal `operatorKey`'s derived address when `session` is enabled. */
428
393
  recipient?: string;
@@ -827,50 +792,83 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
827
792
  private register;
828
793
  }
829
794
 
830
- declare const BASE_NETWORK = "eip155:8453";
831
- declare const SOLANA_MAINNET_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
832
- declare const TEMPO_USDC_CURRENCY = "0x20c000000000000000000000b9537d11c60e8b50";
833
- declare const ZERO_EVM_ADDRESS = "0x0000000000000000000000000000000000000000";
834
-
835
- type RouterEnv = Record<string, string | undefined>;
836
- type RouterConfigIssueCode = 'missing_base_url' | 'empty_protocols' | 'missing_x402_accepts' | 'missing_x402_network' | 'unsupported_x402_network' | 'missing_x402_asset' | 'invalid_x402_decimals' | 'missing_x402_payee' | 'missing_cdp_keys' | 'placeholder_payee' | 'missing_mpp_config' | 'missing_mpp_secret_key' | 'missing_mpp_currency' | 'invalid_mpp_currency' | 'missing_mpp_recipient' | 'invalid_mpp_recipient' | 'missing_mpp_rpc_url' | 'invalid_mpp_fee_payer_key' | 'invalid_mpp_operator_key' | 'mpp_operator_equals_fee_payer';
795
+ type RouterConfigIssueCode = 'missing_base_url' | 'invalid_base_url' | 'empty_protocols' | 'missing_x402_accepts' | 'missing_x402_network' | 'unsupported_x402_network' | 'missing_x402_asset' | 'invalid_x402_decimals' | 'missing_x402_payee' | 'invalid_x402_payee' | 'invalid_solana_payee' | 'invalid_solana_facilitator_url' | 'missing_cdp_keys' | 'placeholder_payee' | 'missing_mpp_config' | 'missing_mpp_secret_key' | 'missing_mpp_currency' | 'invalid_mpp_currency' | 'missing_mpp_recipient' | 'invalid_mpp_recipient' | 'missing_mpp_rpc_url' | 'invalid_mpp_rpc_url' | 'invalid_mpp_fee_payer_key' | 'invalid_mpp_operator_key' | 'mpp_operator_equals_fee_payer' | 'missing_discovery_title' | 'missing_discovery_description' | 'missing_discovery_guidance' | 'invalid_server_url' | 'kv_url_without_token' | 'kv_token_without_url' | 'invalid_kv_url' | 'missing_kv_in_production';
796
+ type RouterConfigIssueSeverity = 'error' | 'warning';
837
797
  interface RouterConfigIssue {
838
798
  code: RouterConfigIssueCode;
839
799
  message: string;
840
800
  protocol?: ProtocolType;
841
- }
842
- interface RouterConfigValidationOptions {
843
- env?: RouterEnv;
844
- requireCdpKeys?: boolean;
801
+ /** @default 'error' — warnings are surfaced via `console.warn` and do not throw. */
802
+ severity?: RouterConfigIssueSeverity;
803
+ }
804
+ /** Options for {@link createRouterFromEnv} / {@link routerConfigFromEnv}. */
805
+ interface CreateRouterFromEnvOptions<TPrices extends Record<string, string> = Record<never, string>> {
806
+ /** Defaults to `process.env`. Pass an explicit object in tests. */
807
+ env?: Record<string, string | undefined>;
808
+ /** Discovery title. Shown in `.well-known/agentcash`, OpenAPI, and `/llms.txt`. */
809
+ title: string;
810
+ /** Discovery description. */
811
+ description: string;
812
+ /** Long-form usage guidance for agent consumers. Served at `/llms.txt`. Pass an empty string to opt out. */
813
+ guidance: string;
814
+ /** Discovery version. @default '1.0.0' */
815
+ version?: string;
816
+ /** Optional contact metadata published in discovery. */
817
+ contact?: DiscoveryConfig['contact'];
818
+ /** Optional ownership proofs published in `.well-known/agentcash`. */
819
+ ownershipProofs?: string[];
820
+ /** Per-route HTTP method hint visibility. */
821
+ methodHints?: DiscoveryConfig['methodHints'];
822
+ /** Override the OpenAPI `servers[].url`. Defaults to `BASE_URL`. */
823
+ serverUrl?: string;
824
+ /** Centralized price map keyed by route id. `route(key)` auto-applies `.paid(prices[key])` for matching keys. */
825
+ prices?: TPrices;
826
+ /** Observability plugin. */
827
+ plugin?: RouterPlugin;
828
+ /** Custom KV store. When omitted, the router auto-bootstraps from `KV_REST_API_URL` + `KV_REST_API_TOKEN`. */
829
+ kvStore?: KvStore;
830
+ /** Override x402 facilitators. The Solana facilitator defaults to `SOLANA_FACILITATOR_URL` env or `DEFAULT_SOLANA_FACILITATOR_URL`. */
831
+ x402Facilitators?: X402FacilitatorsConfig;
832
+ /** Explicit protocol list. Default: `['x402']`, with `'mpp'` added when `MPP_SECRET_KEY` is set. */
833
+ protocols?: readonly ProtocolType[];
834
+ /** Require `route({ path })` form for every route. @default false */
835
+ strictRoutes?: boolean;
845
836
  }
846
837
 
847
838
  declare class RouterConfigError extends Error {
848
839
  readonly issues: RouterConfigIssue[];
849
840
  constructor(issues: RouterConfigIssue[]);
850
841
  }
851
- declare function formatRouterConfigIssues(issues: readonly RouterConfigIssue[]): string;
852
-
853
- declare function validateRouterConfig(config: RouterConfig, options?: RouterConfigValidationOptions): void;
854
- declare function getRouterConfigIssues(config: RouterConfig, options?: RouterConfigValidationOptions): RouterConfigIssue[];
855
842
 
856
- declare function mppFromEnv(env: RouterEnv, options?: {
857
- recipient?: string;
858
- require?: boolean;
859
- feePayerKey?: string;
860
- }): RouterConfig['mpp'] | undefined;
861
- declare function x402AcceptsFromEnv(env: RouterEnv, options?: {
862
- payeeAddress?: string;
863
- payeeEnv?: string;
864
- network?: string;
865
- solanaPayeeAddress?: string;
866
- solanaPayeeEnv?: string;
867
- }): X402AcceptConfig[];
868
- declare function paidOptionsForProtocols(protocols: readonly ProtocolType[]): PaidOptions;
843
+ /**
844
+ * Build a {@link RouterConfig} from environment variables.
845
+ *
846
+ * `envShape` in this file is the single source of truth for env vars; README
847
+ * and `.env.example` are drift-tested against `ENV_KEYS`. Validates every
848
+ * required value up front and throws a single {@link RouterConfigError}
849
+ * containing all issues at once. Soft warnings (e.g. half-configured KV) are
850
+ * emitted via `console.warn`.
851
+ */
852
+ declare function routerConfigFromEnv<const TPrices extends Record<string, string> = Record<never, string>>(options: CreateRouterFromEnvOptions<TPrices>): RouterConfig & {
853
+ prices?: TPrices;
854
+ };
869
855
 
870
- /** SIWX verification error codes. */
871
- type SiwxErrorCode = 'siwx_missing_header' | 'siwx_malformed' | 'siwx_expired' | 'siwx_nonce_used' | 'siwx_invalid_signature';
872
- /** Human-readable error messages for each SIWX error code. */
873
- declare const SIWX_ERROR_MESSAGES: Record<SiwxErrorCode, string>;
856
+ /** Base mainnet CAIP-2 network ID (`eip155:8453`). */
857
+ declare const BASE_MAINNET_NETWORK = "eip155:8453";
858
+ /** Solana mainnet CAIP-2 network ID. */
859
+ declare const SOLANA_MAINNET_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
860
+ /** USDC contract address on Tempo (the `mpp.currency` value for Tempo USDC). */
861
+ declare const TEMPO_USDC_ADDRESS = "0x20c000000000000000000000b9537d11c60e8b50";
862
+ /** USDC has 6 decimals on Tempo. */
863
+ declare const TEMPO_USDC_DECIMALS = 6;
864
+ /** USDC contract on Base mainnet. */
865
+ declare const BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
866
+ /** USDC has 6 decimals on Base. */
867
+ declare const BASE_USDC_DECIMALS = 6;
868
+ /** All-zeros EVM address. Used as a placeholder/sentinel; not a valid payee. */
869
+ declare const ZERO_EVM_ADDRESS = "0x0000000000000000000000000000000000000000";
870
+ /** Public Solana x402 facilitator. Override per-deployment via `SOLANA_FACILITATOR_URL`. */
871
+ declare const DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.corbits.dev";
874
872
 
875
873
  interface MonitorEntry {
876
874
  provider: string;
@@ -891,5 +889,26 @@ interface ServiceRouter<TPriceKeys extends string = never> {
891
889
  declare function createRouter<const P extends Record<string, string> = Record<never, string>>(config: RouterConfig & {
892
890
  prices?: P;
893
891
  }): ServiceRouter<Extract<keyof P, string>>;
892
+ /**
893
+ * Build a {@link ServiceRouter} from environment variables.
894
+ *
895
+ * Validates every required env var up front and throws a single
896
+ * {@link RouterConfigError} containing all problems at once. Most consumers
897
+ * should use this entry point. Use {@link createRouter} when you need to
898
+ * construct a {@link RouterConfig} programmatically.
899
+ *
900
+ * The env vars this function reads are the canonical schema in
901
+ * `src/config/schema.ts` (`ENV_SPEC`).
902
+ *
903
+ * @example
904
+ * ```ts
905
+ * export const router = createRouterFromEnv({
906
+ * title: 'My API',
907
+ * description: 'Pay-per-call search.',
908
+ * guidance: 'POST /search with { q: string }. Returns top 10 results.',
909
+ * });
910
+ * ```
911
+ */
912
+ declare function createRouterFromEnv<const P extends Record<string, string> = Record<never, string>>(options: CreateRouterFromEnvOptions<P>): ServiceRouter<Extract<keyof P, string>>;
894
913
 
895
- export { type AlertEvent, type AlertFn, type AlertLevel, type AuthEvent, type AuthMode, BASE_NETWORK, type DiscoveryConfig, type EntitlementStore, type ErrorEvent, type HandlerContext, type HandlerPaymentContext, HttpError, type KvChange, type KvEntitlementStoreOptions, type KvMppStoreOptions, type KvNonceStoreOptions, type KvStore, MemoryEntitlementStore, MemoryNonceStore, type MonitorEntry, type MppProtocolInfo, type NonceStore, type OveragePolicy, type PaidOptions, type PayToConfig, type PaymentEvent, type PaymentStatus, type PluginContext, type PricingConfig, type ProtocolType, type ProviderConfig, type ProviderQuotaEvent, type QuotaInfo, type QuotaLevel, type RequestMeta, type ResponseMeta, RouteBuilder, type RouteEntry, RouteRegistry, type RouterConfig, RouterConfigError, type RouterConfigIssue, type RouterConfigIssueCode, type RouterConfigValidationOptions, type RouterEnv, type RouterPlugin, SIWX_CHALLENGE_EXPIRY_MS, SIWX_ERROR_MESSAGES, SOLANA_MAINNET_NETWORK, type ServiceRouter, type SettledHandlerErrorContext, type SettlementErrorContext, type SettlementEvent, type SettlementLifecycle, type SettlementLifecycleContext, type SettlementSettledContext, type SiwxErrorCode, type StreamingHandlerContext, TEMPO_USDC_CURRENCY, type TierConfig, type X402AcceptConfig, type X402FacilitatorTarget, type X402FacilitatorsConfig, type X402ResolvedAccept, type X402RouterFacilitatorConfig, type X402Server, ZERO_EVM_ADDRESS, consolePlugin, createKvEntitlementStore, createKvMppStore, createKvNonceStore, createRouter, formatRouterConfigIssues, getRouterConfigIssues, mppFromEnv, paidOptionsForProtocols, validateRouterConfig, withPrefix, x402AcceptsFromEnv };
914
+ export { BASE_MAINNET_NETWORK, BASE_USDC_ADDRESS, BASE_USDC_DECIMALS, type CreateRouterFromEnvOptions, DEFAULT_SOLANA_FACILITATOR_URL, type DiscoveryConfig, type HandlerContext, HttpError, type KvStore, type PaidOptions, type ProtocolType, type RouterConfig, RouterConfigError, type RouterConfigIssue, type RouterConfigIssueCode, type RouterConfigIssueSeverity, type RouterPlugin, SOLANA_MAINNET_NETWORK, type ServiceRouter, type SettlementErrorContext, type SettlementLifecycleContext, type SettlementSettledContext, TEMPO_USDC_ADDRESS, TEMPO_USDC_DECIMALS, type X402FacilitatorsConfig, ZERO_EVM_ADDRESS, createRouter, createRouterFromEnv, routerConfigFromEnv };