@agentcash/router 1.6.0 → 1.7.1

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;
@@ -473,6 +438,7 @@ type MppxMiddlewareResponse<T extends Transport.AnyTransport> = {
473
438
  withReceipt: Transport.WithReceipt<T>;
474
439
  };
475
440
  type MppxMiddleware<TOptions, T extends Transport.AnyTransport> = (options: TOptions) => (input: Request) => Promise<MppxMiddlewareResponse<T>>;
441
+
476
442
  interface RouterDeps {
477
443
  x402Server: X402Server | null;
478
444
  initPromise: Promise<void>;
@@ -527,37 +493,12 @@ type StreamArg<TBody, TQuery, HasAuth extends boolean, NeedsBody extends boolean
527
493
  } : {
528
494
  __missing: 'Select an auth mode: .paid({ dynamic: true, ... }) — streaming requires handler-driven dynamic pricing';
529
495
  };
496
+ interface RouteBuilderDefaults {
497
+ protocols?: ProtocolType[];
498
+ }
530
499
  declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = undefined, HasAuth extends boolean = false, NeedsBody extends boolean = false, HasBody extends boolean = false, IsDynamic extends boolean = false> {
531
- /** @internal */ readonly _key: string;
532
- /** @internal */ readonly _registry: RouteRegistry;
533
- /** @internal */ readonly _deps: OrchestrateDeps;
534
- /** @internal */ _authMode: AuthMode | null;
535
- /** @internal */ _pricing: PricingConfig | undefined;
536
- /** @internal */ _siwxEnabled: boolean;
537
- /** @internal */ _protocols: ProtocolType[];
538
- /** @internal */ _maxPrice: string | undefined;
539
- /** @internal */ _minPrice: string | undefined;
540
- /** @internal */ _dynamicPrice: boolean;
541
- /** @internal */ _tickCost: string | undefined;
542
- /** @internal */ _unitType: string | undefined;
543
- /** @internal */ _payTo: PayToConfig | undefined;
544
- /** @internal */ _bodySchema: ZodType | undefined;
545
- /** @internal */ _querySchema: ZodType | undefined;
546
- /** @internal */ _outputSchema: ZodType | undefined;
547
- /** @internal */ _inputExample: JsonObject | undefined;
548
- /** @internal */ _hasInputExample: boolean;
549
- /** @internal */ _outputExample: JsonValue | undefined;
550
- /** @internal */ _hasOutputExample: boolean;
551
- /** @internal */ _description: string | undefined;
552
- /** @internal */ _path: string | undefined;
553
- /** @internal */ _method: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH';
554
- /** @internal */ _apiKeyResolver: ((key: string) => unknown | Promise<unknown>) | undefined;
555
- /** @internal */ _providerName: string | undefined;
556
- /** @internal */ _providerConfig: ProviderConfig | undefined;
557
- /** @internal */ _validateFn: ((body: TBody) => void | Promise<void>) | undefined;
558
- /** @internal */ _settlement: SettlementLifecycle<TBody> | undefined;
559
- /** @internal */ _mppInfo: MppProtocolInfo | undefined;
560
- constructor(key: string, registry: RouteRegistry, deps: OrchestrateDeps);
500
+ #private;
501
+ constructor(key: string, registry: RouteRegistry, deps: OrchestrateDeps, defaults?: RouteBuilderDefaults);
561
502
  private fork;
562
503
  /**
563
504
  * Charge a fixed price per request, denominated in USDC as a decimal string.
@@ -827,50 +768,83 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
827
768
  private register;
828
769
  }
829
770
 
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';
771
+ 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';
772
+ type RouterConfigIssueSeverity = 'error' | 'warning';
837
773
  interface RouterConfigIssue {
838
774
  code: RouterConfigIssueCode;
839
775
  message: string;
840
776
  protocol?: ProtocolType;
841
- }
842
- interface RouterConfigValidationOptions {
843
- env?: RouterEnv;
844
- requireCdpKeys?: boolean;
777
+ /** @default 'error' — warnings are surfaced via `console.warn` and do not throw. */
778
+ severity?: RouterConfigIssueSeverity;
779
+ }
780
+ /** Options for {@link createRouterFromEnv} / {@link routerConfigFromEnv}. */
781
+ interface CreateRouterFromEnvOptions<TPrices extends Record<string, string> = Record<never, string>> {
782
+ /** Defaults to `process.env`. Pass an explicit object in tests. */
783
+ env?: Record<string, string | undefined>;
784
+ /** Discovery title. Shown in `.well-known/agentcash`, OpenAPI, and `/llms.txt`. */
785
+ title: string;
786
+ /** Discovery description. */
787
+ description: string;
788
+ /** Long-form usage guidance for agent consumers. Served at `/llms.txt`. Pass an empty string to opt out. */
789
+ guidance: string;
790
+ /** Discovery version. @default '1.0.0' */
791
+ version?: string;
792
+ /** Optional contact metadata published in discovery. */
793
+ contact?: DiscoveryConfig['contact'];
794
+ /** Optional ownership proofs published in `.well-known/agentcash`. */
795
+ ownershipProofs?: string[];
796
+ /** Per-route HTTP method hint visibility. */
797
+ methodHints?: DiscoveryConfig['methodHints'];
798
+ /** Override the OpenAPI `servers[].url`. Defaults to `BASE_URL`. */
799
+ serverUrl?: string;
800
+ /** Centralized price map keyed by route id. `route(key)` auto-applies `.paid(prices[key])` for matching keys. */
801
+ prices?: TPrices;
802
+ /** Observability plugin. */
803
+ plugin?: RouterPlugin;
804
+ /** Custom KV store. When omitted, the router auto-bootstraps from `KV_REST_API_URL` + `KV_REST_API_TOKEN`. */
805
+ kvStore?: KvStore;
806
+ /** Override x402 facilitators. The Solana facilitator defaults to `SOLANA_FACILITATOR_URL` env or `DEFAULT_SOLANA_FACILITATOR_URL`. */
807
+ x402Facilitators?: X402FacilitatorsConfig;
808
+ /** Explicit protocol list. Default: `['x402']`, with `'mpp'` added when `MPP_SECRET_KEY` is set. */
809
+ protocols?: readonly ProtocolType[];
810
+ /** Require `route({ path })` form for every route. @default false */
811
+ strictRoutes?: boolean;
845
812
  }
846
813
 
847
814
  declare class RouterConfigError extends Error {
848
815
  readonly issues: RouterConfigIssue[];
849
816
  constructor(issues: RouterConfigIssue[]);
850
817
  }
851
- declare function formatRouterConfigIssues(issues: readonly RouterConfigIssue[]): string;
852
818
 
853
- declare function validateRouterConfig(config: RouterConfig, options?: RouterConfigValidationOptions): void;
854
- declare function getRouterConfigIssues(config: RouterConfig, options?: RouterConfigValidationOptions): RouterConfigIssue[];
855
-
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;
819
+ /**
820
+ * Build a {@link RouterConfig} from environment variables.
821
+ *
822
+ * `envShape` in this file is the single source of truth for env vars; README
823
+ * and `.env.example` are drift-tested against `ENV_KEYS`. Validates every
824
+ * required value up front and throws a single {@link RouterConfigError}
825
+ * containing all issues at once. Soft warnings (e.g. half-configured KV) are
826
+ * emitted via `console.warn`.
827
+ */
828
+ declare function routerConfigFromEnv<const TPrices extends Record<string, string> = Record<never, string>>(options: CreateRouterFromEnvOptions<TPrices>): RouterConfig & {
829
+ prices?: TPrices;
830
+ };
869
831
 
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>;
832
+ /** Base mainnet CAIP-2 network ID (`eip155:8453`). */
833
+ declare const BASE_MAINNET_NETWORK = "eip155:8453";
834
+ /** Solana mainnet CAIP-2 network ID. */
835
+ declare const SOLANA_MAINNET_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
836
+ /** USDC contract address on Tempo (the `mpp.currency` value for Tempo USDC). */
837
+ declare const TEMPO_USDC_ADDRESS = "0x20c000000000000000000000b9537d11c60e8b50";
838
+ /** USDC has 6 decimals on Tempo. */
839
+ declare const TEMPO_USDC_DECIMALS = 6;
840
+ /** USDC contract on Base mainnet. */
841
+ declare const BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
842
+ /** USDC has 6 decimals on Base. */
843
+ declare const BASE_USDC_DECIMALS = 6;
844
+ /** All-zeros EVM address. Used as a placeholder/sentinel; not a valid payee. */
845
+ declare const ZERO_EVM_ADDRESS = "0x0000000000000000000000000000000000000000";
846
+ /** Public Solana x402 facilitator. Override per-deployment via `SOLANA_FACILITATOR_URL`. */
847
+ declare const DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.corbits.dev";
874
848
 
875
849
  interface MonitorEntry {
876
850
  provider: string;
@@ -891,5 +865,26 @@ interface ServiceRouter<TPriceKeys extends string = never> {
891
865
  declare function createRouter<const P extends Record<string, string> = Record<never, string>>(config: RouterConfig & {
892
866
  prices?: P;
893
867
  }): ServiceRouter<Extract<keyof P, string>>;
868
+ /**
869
+ * Build a {@link ServiceRouter} from environment variables.
870
+ *
871
+ * Validates every required env var up front and throws a single
872
+ * {@link RouterConfigError} containing all problems at once. Most consumers
873
+ * should use this entry point. Use {@link createRouter} when you need to
874
+ * construct a {@link RouterConfig} programmatically.
875
+ *
876
+ * The env vars this function reads are the canonical schema in
877
+ * `src/config/schema.ts` (`ENV_SPEC`).
878
+ *
879
+ * @example
880
+ * ```ts
881
+ * export const router = createRouterFromEnv({
882
+ * title: 'My API',
883
+ * description: 'Pay-per-call search.',
884
+ * guidance: 'POST /search with { q: string }. Returns top 10 results.',
885
+ * });
886
+ * ```
887
+ */
888
+ declare function createRouterFromEnv<const P extends Record<string, string> = Record<never, string>>(options: CreateRouterFromEnvOptions<P>): ServiceRouter<Extract<keyof P, string>>;
894
889
 
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 };
890
+ 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;
@@ -473,6 +438,7 @@ type MppxMiddlewareResponse<T extends Transport.AnyTransport> = {
473
438
  withReceipt: Transport.WithReceipt<T>;
474
439
  };
475
440
  type MppxMiddleware<TOptions, T extends Transport.AnyTransport> = (options: TOptions) => (input: Request) => Promise<MppxMiddlewareResponse<T>>;
441
+
476
442
  interface RouterDeps {
477
443
  x402Server: X402Server | null;
478
444
  initPromise: Promise<void>;
@@ -527,37 +493,12 @@ type StreamArg<TBody, TQuery, HasAuth extends boolean, NeedsBody extends boolean
527
493
  } : {
528
494
  __missing: 'Select an auth mode: .paid({ dynamic: true, ... }) — streaming requires handler-driven dynamic pricing';
529
495
  };
496
+ interface RouteBuilderDefaults {
497
+ protocols?: ProtocolType[];
498
+ }
530
499
  declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = undefined, HasAuth extends boolean = false, NeedsBody extends boolean = false, HasBody extends boolean = false, IsDynamic extends boolean = false> {
531
- /** @internal */ readonly _key: string;
532
- /** @internal */ readonly _registry: RouteRegistry;
533
- /** @internal */ readonly _deps: OrchestrateDeps;
534
- /** @internal */ _authMode: AuthMode | null;
535
- /** @internal */ _pricing: PricingConfig | undefined;
536
- /** @internal */ _siwxEnabled: boolean;
537
- /** @internal */ _protocols: ProtocolType[];
538
- /** @internal */ _maxPrice: string | undefined;
539
- /** @internal */ _minPrice: string | undefined;
540
- /** @internal */ _dynamicPrice: boolean;
541
- /** @internal */ _tickCost: string | undefined;
542
- /** @internal */ _unitType: string | undefined;
543
- /** @internal */ _payTo: PayToConfig | undefined;
544
- /** @internal */ _bodySchema: ZodType | undefined;
545
- /** @internal */ _querySchema: ZodType | undefined;
546
- /** @internal */ _outputSchema: ZodType | undefined;
547
- /** @internal */ _inputExample: JsonObject | undefined;
548
- /** @internal */ _hasInputExample: boolean;
549
- /** @internal */ _outputExample: JsonValue | undefined;
550
- /** @internal */ _hasOutputExample: boolean;
551
- /** @internal */ _description: string | undefined;
552
- /** @internal */ _path: string | undefined;
553
- /** @internal */ _method: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH';
554
- /** @internal */ _apiKeyResolver: ((key: string) => unknown | Promise<unknown>) | undefined;
555
- /** @internal */ _providerName: string | undefined;
556
- /** @internal */ _providerConfig: ProviderConfig | undefined;
557
- /** @internal */ _validateFn: ((body: TBody) => void | Promise<void>) | undefined;
558
- /** @internal */ _settlement: SettlementLifecycle<TBody> | undefined;
559
- /** @internal */ _mppInfo: MppProtocolInfo | undefined;
560
- constructor(key: string, registry: RouteRegistry, deps: OrchestrateDeps);
500
+ #private;
501
+ constructor(key: string, registry: RouteRegistry, deps: OrchestrateDeps, defaults?: RouteBuilderDefaults);
561
502
  private fork;
562
503
  /**
563
504
  * Charge a fixed price per request, denominated in USDC as a decimal string.
@@ -827,50 +768,83 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
827
768
  private register;
828
769
  }
829
770
 
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';
771
+ 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';
772
+ type RouterConfigIssueSeverity = 'error' | 'warning';
837
773
  interface RouterConfigIssue {
838
774
  code: RouterConfigIssueCode;
839
775
  message: string;
840
776
  protocol?: ProtocolType;
841
- }
842
- interface RouterConfigValidationOptions {
843
- env?: RouterEnv;
844
- requireCdpKeys?: boolean;
777
+ /** @default 'error' — warnings are surfaced via `console.warn` and do not throw. */
778
+ severity?: RouterConfigIssueSeverity;
779
+ }
780
+ /** Options for {@link createRouterFromEnv} / {@link routerConfigFromEnv}. */
781
+ interface CreateRouterFromEnvOptions<TPrices extends Record<string, string> = Record<never, string>> {
782
+ /** Defaults to `process.env`. Pass an explicit object in tests. */
783
+ env?: Record<string, string | undefined>;
784
+ /** Discovery title. Shown in `.well-known/agentcash`, OpenAPI, and `/llms.txt`. */
785
+ title: string;
786
+ /** Discovery description. */
787
+ description: string;
788
+ /** Long-form usage guidance for agent consumers. Served at `/llms.txt`. Pass an empty string to opt out. */
789
+ guidance: string;
790
+ /** Discovery version. @default '1.0.0' */
791
+ version?: string;
792
+ /** Optional contact metadata published in discovery. */
793
+ contact?: DiscoveryConfig['contact'];
794
+ /** Optional ownership proofs published in `.well-known/agentcash`. */
795
+ ownershipProofs?: string[];
796
+ /** Per-route HTTP method hint visibility. */
797
+ methodHints?: DiscoveryConfig['methodHints'];
798
+ /** Override the OpenAPI `servers[].url`. Defaults to `BASE_URL`. */
799
+ serverUrl?: string;
800
+ /** Centralized price map keyed by route id. `route(key)` auto-applies `.paid(prices[key])` for matching keys. */
801
+ prices?: TPrices;
802
+ /** Observability plugin. */
803
+ plugin?: RouterPlugin;
804
+ /** Custom KV store. When omitted, the router auto-bootstraps from `KV_REST_API_URL` + `KV_REST_API_TOKEN`. */
805
+ kvStore?: KvStore;
806
+ /** Override x402 facilitators. The Solana facilitator defaults to `SOLANA_FACILITATOR_URL` env or `DEFAULT_SOLANA_FACILITATOR_URL`. */
807
+ x402Facilitators?: X402FacilitatorsConfig;
808
+ /** Explicit protocol list. Default: `['x402']`, with `'mpp'` added when `MPP_SECRET_KEY` is set. */
809
+ protocols?: readonly ProtocolType[];
810
+ /** Require `route({ path })` form for every route. @default false */
811
+ strictRoutes?: boolean;
845
812
  }
846
813
 
847
814
  declare class RouterConfigError extends Error {
848
815
  readonly issues: RouterConfigIssue[];
849
816
  constructor(issues: RouterConfigIssue[]);
850
817
  }
851
- declare function formatRouterConfigIssues(issues: readonly RouterConfigIssue[]): string;
852
818
 
853
- declare function validateRouterConfig(config: RouterConfig, options?: RouterConfigValidationOptions): void;
854
- declare function getRouterConfigIssues(config: RouterConfig, options?: RouterConfigValidationOptions): RouterConfigIssue[];
855
-
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;
819
+ /**
820
+ * Build a {@link RouterConfig} from environment variables.
821
+ *
822
+ * `envShape` in this file is the single source of truth for env vars; README
823
+ * and `.env.example` are drift-tested against `ENV_KEYS`. Validates every
824
+ * required value up front and throws a single {@link RouterConfigError}
825
+ * containing all issues at once. Soft warnings (e.g. half-configured KV) are
826
+ * emitted via `console.warn`.
827
+ */
828
+ declare function routerConfigFromEnv<const TPrices extends Record<string, string> = Record<never, string>>(options: CreateRouterFromEnvOptions<TPrices>): RouterConfig & {
829
+ prices?: TPrices;
830
+ };
869
831
 
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>;
832
+ /** Base mainnet CAIP-2 network ID (`eip155:8453`). */
833
+ declare const BASE_MAINNET_NETWORK = "eip155:8453";
834
+ /** Solana mainnet CAIP-2 network ID. */
835
+ declare const SOLANA_MAINNET_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
836
+ /** USDC contract address on Tempo (the `mpp.currency` value for Tempo USDC). */
837
+ declare const TEMPO_USDC_ADDRESS = "0x20c000000000000000000000b9537d11c60e8b50";
838
+ /** USDC has 6 decimals on Tempo. */
839
+ declare const TEMPO_USDC_DECIMALS = 6;
840
+ /** USDC contract on Base mainnet. */
841
+ declare const BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
842
+ /** USDC has 6 decimals on Base. */
843
+ declare const BASE_USDC_DECIMALS = 6;
844
+ /** All-zeros EVM address. Used as a placeholder/sentinel; not a valid payee. */
845
+ declare const ZERO_EVM_ADDRESS = "0x0000000000000000000000000000000000000000";
846
+ /** Public Solana x402 facilitator. Override per-deployment via `SOLANA_FACILITATOR_URL`. */
847
+ declare const DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.corbits.dev";
874
848
 
875
849
  interface MonitorEntry {
876
850
  provider: string;
@@ -891,5 +865,26 @@ interface ServiceRouter<TPriceKeys extends string = never> {
891
865
  declare function createRouter<const P extends Record<string, string> = Record<never, string>>(config: RouterConfig & {
892
866
  prices?: P;
893
867
  }): ServiceRouter<Extract<keyof P, string>>;
868
+ /**
869
+ * Build a {@link ServiceRouter} from environment variables.
870
+ *
871
+ * Validates every required env var up front and throws a single
872
+ * {@link RouterConfigError} containing all problems at once. Most consumers
873
+ * should use this entry point. Use {@link createRouter} when you need to
874
+ * construct a {@link RouterConfig} programmatically.
875
+ *
876
+ * The env vars this function reads are the canonical schema in
877
+ * `src/config/schema.ts` (`ENV_SPEC`).
878
+ *
879
+ * @example
880
+ * ```ts
881
+ * export const router = createRouterFromEnv({
882
+ * title: 'My API',
883
+ * description: 'Pay-per-call search.',
884
+ * guidance: 'POST /search with { q: string }. Returns top 10 results.',
885
+ * });
886
+ * ```
887
+ */
888
+ declare function createRouterFromEnv<const P extends Record<string, string> = Record<never, string>>(options: CreateRouterFromEnvOptions<P>): ServiceRouter<Extract<keyof P, string>>;
894
889
 
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 };
890
+ 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 };