@agentcash/router 1.7.0 → 1.8.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
@@ -58,13 +58,13 @@ interface PluginContext {
58
58
  setVerifiedWallet(address: string): void;
59
59
  }
60
60
  interface PaymentEvent {
61
- protocol: 'x402' | 'mpp';
61
+ protocol: ProtocolType;
62
62
  payer: string;
63
63
  amount: string;
64
64
  network: string;
65
65
  }
66
66
  interface SettlementEvent {
67
- protocol: 'x402' | 'mpp';
67
+ protocol: ProtocolType;
68
68
  payer: string;
69
69
  transaction: string;
70
70
  network: string;
@@ -188,7 +188,7 @@ interface X402AcceptBase {
188
188
  extra?: Record<string, unknown>;
189
189
  }
190
190
  interface X402AcceptConfig extends X402AcceptBase {
191
- /** `'exact'` for fixed-price one-shot payments; `'upto'` for settle-≤-cap (required for `.paid({ dynamic: true })` on x402). @default 'exact' */
191
+ /** `'exact'` for fixed-price one-shot payments; `'upto'` for settle-≤-cap (required for `.upTo()` routes). @default 'exact' */
192
192
  scheme?: string;
193
193
  /** Per-accept payee override. Function form receives the request and parsed body for dynamic recipient routing. Falls back to `RouterConfig.payeeAddress`. */
194
194
  payTo?: PayToConfig;
@@ -212,14 +212,29 @@ interface PaidOptions {
212
212
  protocols?: ProtocolType[];
213
213
  maxPrice?: string;
214
214
  minPrice?: string;
215
- /** Override the payment recipient. String for static, function for dynamic (receives the Request). */
215
+ /** Override the payment recipient. String for static, function for body-derived (receives the Request). */
216
216
  payTo?: PayToConfig;
217
217
  /** Override MPP protocol metadata in x-payment-info discovery. */
218
218
  mpp?: MppProtocolInfo;
219
- /** Handler-driven dynamic pricing: handler calls `charge()` per tick, total billed is `tickCost × calls` capped at `maxPrice`. Requires `maxPrice`. Incompatible with tiered pricing. On x402 needs an `upto` accept; on MPP needs `RouterConfig.mpp.session`. */
220
- dynamic?: boolean;
221
- /** Per-tick cost (positive decimal-dollar string). Required for `.paid({ dynamic: true })`. Also the voucher-headroom granularity for MPP sessions. */
222
- tickCost?: string;
219
+ }
220
+ type PaidArg = (PaidOptions & {
221
+ price: string;
222
+ }) | (PaidOptions & {
223
+ field: string;
224
+ tiers: Record<string, TierConfig>;
225
+ default?: string;
226
+ });
227
+ interface UpToOptions extends Omit<PaidOptions, 'maxPrice'> {
228
+ /** Cap on total billed amount; handler-accumulated `charge(amount)` calls cannot exceed this. */
229
+ maxPrice: string;
230
+ /** Cosmetic unit label for 402 challenges / UIs. Does not affect billing. */
231
+ unitType?: string;
232
+ }
233
+ interface MeteredOptions extends Omit<PaidOptions, 'maxPrice'> {
234
+ /** Per-tick cost (positive decimal-dollar string). On `.handler()` bills exactly this per request; on `.stream()` is the voucher-headroom granularity. */
235
+ tickCost: string;
236
+ /** Cap on total billed amount (streaming only — request-mode bills exactly `tickCost`). */
237
+ maxPrice: string;
223
238
  /** Cosmetic unit label for 402 challenges / UIs (e.g. `'token'`, `'byte'`). Does not affect billing. */
224
239
  unitType?: string;
225
240
  }
@@ -267,6 +282,7 @@ interface SettlementLifecycle<TBody = unknown> {
267
282
  onSettlementError?: (ctx: SettlementErrorContext<TBody>) => void | Promise<void>;
268
283
  }
269
284
  type ChargeFn = () => Promise<void>;
285
+ type UptoChargeFn = (amount: string) => Promise<void>;
270
286
  interface HandlerContext<TBody = undefined, TQuery = undefined> {
271
287
  body: TBody;
272
288
  query: TQuery;
@@ -279,10 +295,14 @@ interface HandlerContext<TBody = undefined, TQuery = undefined> {
279
295
  alert: AlertFn;
280
296
  setVerifiedWallet: (addr: string) => void;
281
297
  }
282
- /** Handler context for streaming `.paid({ dynamic: true })` handlers (async generators). Call `charge()` once per billable unit. */
298
+ /** Handler context for streaming `.metered()` handlers (async generators). Call `charge()` once per billable unit. */
283
299
  interface StreamingHandlerContext<TBody = undefined, TQuery = undefined> extends HandlerContext<TBody, TQuery> {
284
300
  charge: ChargeFn;
285
301
  }
302
+ /** Handler context for `.upTo()` routes (x402-only). Call `charge(amount)` one or more times; the request settles for the accumulated total capped at `maxPrice`. */
303
+ interface UptoHandlerContext<TBody = undefined, TQuery = undefined> extends HandlerContext<TBody, TQuery> {
304
+ charge: UptoChargeFn;
305
+ }
286
306
  type OveragePolicy = 'same-rate' | 'increased-rate' | 'hard-stop';
287
307
  type QuotaLevel = 'healthy' | 'warn' | 'critical';
288
308
  interface QuotaInfo {
@@ -316,9 +336,9 @@ interface RouteEntry {
316
336
  */
317
337
  siwxEnabled?: boolean;
318
338
  pricing?: PricingConfig;
319
- /** When true the route is dynamic-priced; bills `tickCost` per request (request-mode) or per `charge()` call (streaming). */
320
- dynamicPrice?: boolean;
321
- /** True iff handler is an async generator. Streaming handlers settle per-tick over SSE; non-streaming dynamic handlers bill exactly `tickCost` per request. Set by the builder at `.handler(fn)` time. */
339
+ /** `'exact'` settles a fixed price once; `'upto'` (x402-only) settles the handler-accumulated `charge(amount)` total capped at `maxPrice`; `'metered'` (MPP-only) bills per `tickCost`. */
340
+ billing: 'exact' | 'upto' | 'metered';
341
+ /** True iff handler is an async generator. Streaming handlers settle per-tick over SSE; non-streaming metered handlers bill exactly `tickCost` per request. Set by the builder at `.handler(fn)` time. */
322
342
  streaming?: boolean;
323
343
  protocols: ProtocolType[];
324
344
  bodySchema?: ZodType;
@@ -340,7 +360,7 @@ interface RouteEntry {
340
360
  validateFn?: (body: unknown) => void | Promise<void>;
341
361
  settlement?: SettlementLifecycle;
342
362
  mppInfo?: MppProtocolInfo;
343
- /** Per-tick cost (decimal-dollar). Required when `dynamicPrice` is true. */
363
+ /** Per-tick cost (decimal-dollar). Required when `metered` is true. */
344
364
  tickCost?: string;
345
365
  /** Cosmetic unit label for 402 challenges and client UIs. */
346
366
  unitType?: string;
@@ -369,7 +389,7 @@ interface RouterConfig {
369
389
  network?: string;
370
390
  /** x402 protocol settings. Omit to default to a single `exact`/USDC accept on `network` paid to `payeeAddress`, verified via the Coinbase default facilitator (requires `CDP_API_KEY_ID`/`CDP_API_KEY_SECRET`). */
371
391
  x402?: {
372
- /** Explicit accepts list (scheme + network + asset). Overrides the auto-generated default. Add an `upto` accept here to enable `.paid({ dynamic: true })` on x402. */
392
+ /** Explicit accepts list (scheme + network + asset). Overrides the auto-generated default. Add an `upto` accept here to enable `.upTo()` routes. */
373
393
  accepts?: X402AcceptConfig[];
374
394
  /** Per-chain facilitator overrides (`evm`/`solana`). Defaults to the Coinbase facilitator on EVM; set `solana` to accept Solana payments. */
375
395
  facilitators?: X402FacilitatorsConfig;
@@ -397,7 +417,7 @@ interface RouterConfig {
397
417
  operatorKey?: string;
398
418
  /** Hex private key. Sponsors gas for client channel open/topUp. MUST resolve to a different address than `operatorKey` — Tempo rejects sender===feePayer. Validated at init. Omit to make clients pay their own gas. */
399
419
  feePayerKey?: string;
400
- /** Enables MPP payment-channel sessions for `.paid({ dynamic: true })` routes (registers both request and SSE session middleware). Also requires `mpp.operatorKey`. */
420
+ /** Enables MPP payment-channel sessions for `.metered()` routes (registers both request and SSE session middleware). Also requires `mpp.operatorKey`. */
401
421
  session?: {
402
422
  /** Suggested deposit on the 402 challenge = `tickCost × depositMultiplier` USDC. Route `maxPrice` overrides. @default 10 */
403
423
  depositMultiplier?: number;
@@ -438,6 +458,7 @@ type MppxMiddlewareResponse<T extends Transport.AnyTransport> = {
438
458
  withReceipt: Transport.WithReceipt<T>;
439
459
  };
440
460
  type MppxMiddleware<TOptions, T extends Transport.AnyTransport> = (options: TOptions) => (input: Request) => Promise<MppxMiddlewareResponse<T>>;
461
+
441
462
  interface RouterDeps {
442
463
  x402Server: X402Server | null;
443
464
  initPromise: Promise<void>;
@@ -472,123 +493,99 @@ interface RouterDeps {
472
493
  tempoClient?: viem.Client | null;
473
494
  }
474
495
 
475
- /** @deprecated alias kept for downstream consumers; use `RouterDeps`. */
476
- type OrchestrateDeps = RouterDeps;
477
-
478
496
  type True = true;
479
497
  type False = false;
498
+ declare const ROUTE_ERROR: unique symbol;
499
+ interface RouteError<M extends string> {
500
+ readonly [ROUTE_ERROR]: M;
501
+ }
480
502
  type InputTypeFor<TBody, TQuery> = [TBody] extends [undefined] ? [TQuery] extends [undefined] ? never : TQuery : TBody;
481
503
  type RequestHandlerFn<TBody, TQuery> = (ctx: HandlerContext<TBody, TQuery>) => Promise<unknown>;
504
+ type UptoHandlerFn<TBody, TQuery> = (ctx: UptoHandlerContext<TBody, TQuery>) => Promise<unknown>;
482
505
  type StreamingHandlerFn<TBody, TQuery> = (ctx: StreamingHandlerContext<TBody, TQuery>) => AsyncIterable<unknown>;
483
- type HandlerArg<TBody, TQuery, HasAuth extends boolean, NeedsBody extends boolean, HasBody extends boolean> = HasAuth extends true ? [NeedsBody, HasBody] extends [true, false] ? {
484
- __missing: 'Call .body(schema) dynamic/tiered pricing requires a body schema to resolve the price against';
485
- } : RequestHandlerFn<TBody, TQuery> : {
486
- __missing: 'Select an auth mode: .paid(pricing), .siwx(), .apiKey(resolver), or .unprotected()';
487
- };
488
- type StreamArg<TBody, TQuery, HasAuth extends boolean, NeedsBody extends boolean, HasBody extends boolean, IsDynamic extends boolean> = HasAuth extends true ? IsDynamic extends true ? [NeedsBody, HasBody] extends [true, false] ? {
489
- __missing: 'Call .body(schema) — dynamic pricing requires a body schema to resolve the price against';
490
- } : StreamingHandlerFn<TBody, TQuery> : {
491
- __missing: 'Streaming handlers require .paid({ dynamic: true, tickCost, unitType, maxPrice }) — static/free routes cannot meter per-chunk billing';
492
- } : {
493
- __missing: 'Select an auth mode: .paid({ dynamic: true, ... }) — streaming requires handler-driven dynamic pricing';
494
- };
495
- 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> {
496
- /** @internal */ readonly _key: string;
497
- /** @internal */ readonly _registry: RouteRegistry;
498
- /** @internal */ readonly _deps: OrchestrateDeps;
499
- /** @internal */ _authMode: AuthMode | null;
500
- /** @internal */ _pricing: PricingConfig | undefined;
501
- /** @internal */ _siwxEnabled: boolean;
502
- /** @internal */ _protocols: ProtocolType[];
503
- /** @internal */ _maxPrice: string | undefined;
504
- /** @internal */ _minPrice: string | undefined;
505
- /** @internal */ _dynamicPrice: boolean;
506
- /** @internal */ _tickCost: string | undefined;
507
- /** @internal */ _unitType: string | undefined;
508
- /** @internal */ _payTo: PayToConfig | undefined;
509
- /** @internal */ _bodySchema: ZodType | undefined;
510
- /** @internal */ _querySchema: ZodType | undefined;
511
- /** @internal */ _outputSchema: ZodType | undefined;
512
- /** @internal */ _inputExample: JsonObject | undefined;
513
- /** @internal */ _hasInputExample: boolean;
514
- /** @internal */ _outputExample: JsonValue | undefined;
515
- /** @internal */ _hasOutputExample: boolean;
516
- /** @internal */ _description: string | undefined;
517
- /** @internal */ _path: string | undefined;
518
- /** @internal */ _method: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH';
519
- /** @internal */ _apiKeyResolver: ((key: string) => unknown | Promise<unknown>) | undefined;
520
- /** @internal */ _providerName: string | undefined;
521
- /** @internal */ _providerConfig: ProviderConfig | undefined;
522
- /** @internal */ _validateFn: ((body: TBody) => void | Promise<void>) | undefined;
523
- /** @internal */ _settlement: SettlementLifecycle<TBody> | undefined;
524
- /** @internal */ _mppInfo: MppProtocolInfo | undefined;
525
- constructor(key: string, registry: RouteRegistry, deps: OrchestrateDeps);
506
+ /** Discriminator threaded through the builder so `.handler()` / `.stream()` can pick the right handler shape. */
507
+ type BillingMode = 'none' | 'upto' | 'metered';
508
+ type HandlerArg<TBody, TQuery, HasAuth extends boolean, NeedsBody extends boolean, HasBody extends boolean, Bill extends BillingMode> = HasAuth extends true ? [NeedsBody, HasBody] extends [true, false] ? RouteError<'Call .body(schema) — body-derived/tiered pricing reads the parsed body'> : Bill extends 'upto' ? UptoHandlerFn<TBody, TQuery> : RequestHandlerFn<TBody, TQuery> : RouteError<'Pick an auth mode first: .paid(...), .upTo(...), .metered(...), .siwx(), .apiKey(...), or .unprotected()'>;
509
+ type StreamArg<TBody, TQuery, HasAuth extends boolean, NeedsBody extends boolean, HasBody extends boolean, Bill extends BillingMode> = HasAuth extends true ? Bill extends 'metered' ? [NeedsBody, HasBody] extends [true, false] ? RouteError<'Call .body(schema) — metered pricing reads the parsed body'> : StreamingHandlerFn<TBody, TQuery> : Bill extends 'upto' ? RouteError<'Streaming is not supported on .upTo() — use .metered() on MPP for per-yield billing'> : RouteError<'Streaming requires .metered({ tickCost, maxPrice }) — static/free routes cannot meter per-chunk billing'> : RouteError<'Pick an auth mode first: .metered({ ... }) — streaming requires metered pricing'>;
510
+ interface RouteBuilderDefaults {
511
+ protocols?: ProtocolType[];
512
+ }
513
+ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = undefined, HasAuth extends boolean = false, NeedsBody extends boolean = false, HasBody extends boolean = false, Bill extends BillingMode = 'none'> {
514
+ #private;
515
+ constructor(key: string, registry: RouteRegistry, deps: RouterDeps, defaults?: RouteBuilderDefaults);
526
516
  private fork;
527
517
  /**
528
- * Charge a fixed price per request, denominated in USDC as a decimal string.
518
+ * Fixed-price string sugar: `paid('0.01')` charges 0.01 USDC per request.
529
519
  *
530
520
  * @example
531
521
  * ```ts
532
522
  * router.route('search').paid('0.01').handler(handler);
533
523
  * ```
534
524
  */
535
- paid(pricing: string, options?: PaidOptions): RouteBuilder<TBody, TQuery, TOutput, True, False, HasBody, IsDynamic>;
525
+ paid(price: string, options?: PaidOptions): RouteBuilder<TBody, TQuery, TOutput, True, False, HasBody, 'none'>;
536
526
  /**
537
- * Configure handler-driven dynamic pricing each tick costs `tickCost` USDC,
538
- * capped at `maxPrice`. Pair with `.handler()` for one-tick-per-request
539
- * billing, or with `.stream()` for per-yield metering.
527
+ * Compute the price from the parsed body before issuing the 402 challenge.
528
+ * Throw an `HttpError` from the pricing function to reject the request
529
+ * before payment is requested. Requires `.body(schema)`.
540
530
  *
541
531
  * @example
542
532
  * ```ts
543
- * router
544
- * .route('llm/stream')
545
- * .paid({ dynamic: true, tickCost: '0.0001', unitType: 'token', maxPrice: '0.05' })
546
- * .stream(async function* ({ charge }) { await charge(); yield 'hi'; });
533
+ * router.route('llm')
534
+ * .paid((body) => `${body.tokens * 0.0001}`, { maxPrice: '5.00' })
535
+ * .body(schema)
536
+ * .handler(handler);
547
537
  * ```
548
538
  */
549
- paid(options: PaidOptions & {
550
- dynamic: true;
551
- maxPrice: string;
552
- }): RouteBuilder<TBody, TQuery, TOutput, True, False, HasBody, True>;
539
+ paid<TBodyIn>(fn: (body: TBodyIn) => string | Promise<string>, options?: PaidOptions): RouteBuilder<TBody, TQuery, TOutput, True, True, HasBody, 'none'>;
553
540
  /**
554
- * Compute the price from the parsed body before issuing the 402 challenge.
555
- * Throw an `HttpError` from the pricing function to reject the request before
556
- * payment is requested.
541
+ * Options-object form of fixed or body-derived pricing. Pass exactly one of:
542
+ *
543
+ * - `{ price }` — fixed price (object form of the string sugar).
544
+ * - `{ field, tiers, default? }` — pick a tier from `body[field]`.
545
+ *
546
+ * Common knobs (`protocols`, `maxPrice`, `minPrice`, `payTo`, `mpp`) live
547
+ * alongside the pricing shape. For handler-computed billing use `.upTo()`;
548
+ * for per-tick billing use `.metered()`.
557
549
  *
558
550
  * @example
559
551
  * ```ts
560
- * router
561
- * .route('llm')
562
- * .paid((body) => `${body.tokens * 0.0001}`, { maxPrice: '5.00' })
563
- * .body(schema)
564
- * .handler(handler);
552
+ * router.route('upload')
553
+ * .paid({ field: 'size', tiers: { sm: { price: '0.01' }, lg: { price: '0.10' } } })
554
+ * .body(schema).handler(handler);
565
555
  * ```
566
556
  */
567
- paid<TBodyIn>(pricing: (body: TBodyIn) => string | Promise<string>, options?: PaidOptions & {
568
- maxPrice?: string;
569
- }): RouteBuilder<TBody, TQuery, TOutput, True, True, HasBody, IsDynamic>;
557
+ paid<T extends PaidArg>(arg: T): RouteBuilder<TBody, TQuery, TOutput, True, T extends {
558
+ tiers: Record<string, TierConfig>;
559
+ } ? True : False, HasBody, 'none'>;
570
560
  /**
571
- * Select a price tier from `body[field]`, optionally falling back to the
572
- * `default` tier when the value is missing. The 402 challenge advertises the
573
- * highest tier price.
561
+ * x402-only handler-computed billing. The handler receives `charge(amount)`
562
+ * and the request settles once for the accumulated total, capped at
563
+ * `maxPrice`. Requires an `'upto'` accept on at least one configured network.
564
+ * Pass a bare string as sugar for `{ maxPrice }`.
574
565
  *
575
566
  * @example
576
567
  * ```ts
577
- * router
578
- * .route('upload')
579
- * .paid({ field: 'size', tiers: { sm: { price: '0.01' }, lg: { price: '0.10' } } })
568
+ * router.route('llm')
569
+ * .upTo('0.05')
580
570
  * .body(schema)
581
- * .handler(handler);
571
+ * .handler(async ({ body, charge }) => { await charge('0.001'); ... });
572
+ * ```
573
+ */
574
+ upTo(arg: string | UpToOptions): RouteBuilder<TBody, TQuery, TOutput, True, False, HasBody, 'upto'>;
575
+ /**
576
+ * MPP-only per-tick billing. `.handler()` bills exactly `tickCost`;
577
+ * `.stream()` calls `charge()` (no-arg) per yield, settling per tick up to
578
+ * `maxPrice`. Requires `RouterConfig.mpp.session`.
579
+ *
580
+ * @example
581
+ * ```ts
582
+ * router.route('llm/stream')
583
+ * .metered({ tickCost: '0.0001', maxPrice: '0.05', unitType: 'token' })
584
+ * .stream(async function* ({ charge }) { await charge(); yield 'hi'; });
582
585
  * ```
583
586
  */
584
- paid(pricing: {
585
- field: string;
586
- tiers: Record<string, {
587
- price: string;
588
- label?: string;
589
- }>;
590
- default?: string;
591
- }, options?: PaidOptions): RouteBuilder<TBody, TQuery, TOutput, True, True, HasBody, IsDynamic>;
587
+ metered(options: MeteredOptions): RouteBuilder<TBody, TQuery, TOutput, True, False, HasBody, 'metered'>;
588
+ private applyPaid;
592
589
  /**
593
590
  * Require Sign-In-with-X wallet identity on this route — clients prove
594
591
  * control of a wallet via a signed challenge. Combine with `.paid()` to gate
@@ -599,7 +596,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
599
596
  * router.route('profile').siwx().handler(async ({ wallet }) => getProfile(wallet));
600
597
  * ```
601
598
  */
602
- siwx(): RouteBuilder<TBody, TQuery, TOutput, True, False, HasBody, IsDynamic>;
599
+ siwx(): RouteBuilder<TBody, TQuery, TOutput, True, False, HasBody, Bill>;
603
600
  /**
604
601
  * Require an `X-API-Key` header (or `Authorization: Bearer <key>`); the
605
602
  * resolver returns the account record, or `null` for 401. Composes with
@@ -613,7 +610,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
613
610
  * .handler(async ({ account }) => db.user.list(account.orgId));
614
611
  * ```
615
612
  */
616
- apiKey(resolver: (key: string) => unknown | Promise<unknown>): RouteBuilder<TBody, TQuery, TOutput, True, NeedsBody, HasBody, IsDynamic>;
613
+ apiKey(resolver: (key: string) => unknown | Promise<unknown>): RouteBuilder<TBody, TQuery, TOutput, True, NeedsBody, HasBody, Bill>;
617
614
  /**
618
615
  * Mark the route as public — no auth, no payment, no SIWX. The handler
619
616
  * receives `null` for `wallet`, `payment`, and `account`.
@@ -623,7 +620,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
623
620
  * router.route('health').unprotected().handler(async () => ({ status: 'ok' }));
624
621
  * ```
625
622
  */
626
- unprotected(): RouteBuilder<TBody, TQuery, TOutput, True, False, HasBody, IsDynamic>;
623
+ unprotected(): RouteBuilder<TBody, TQuery, TOutput, True, False, HasBody, Bill>;
627
624
  /**
628
625
  * Tag the route with an upstream provider for discovery and provider-side
629
626
  * monitoring. The provider name and config surface in `well-known` and
@@ -649,7 +646,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
649
646
  * .handler(async ({ body }) => search(body.query));
650
647
  * ```
651
648
  */
652
- body<T>(schema: ZodType<T>): RouteBuilder<T, TQuery, TOutput, HasAuth, NeedsBody, True, IsDynamic>;
649
+ body<T>(schema: ZodType<T>): RouteBuilder<T, TQuery, TOutput, HasAuth, NeedsBody, True, Bill>;
653
650
  /**
654
651
  * Declare a query-string Zod schema and switch the route to `GET`. Parsed
655
652
  * query is typed as `ctx.query` in the handler. Use `.inputExample()` to
@@ -661,7 +658,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
661
658
  * .handler(async ({ query }) => getById(query.id));
662
659
  * ```
663
660
  */
664
- query<T>(schema: ZodType<T>): RouteBuilder<TBody, T, TOutput, HasAuth, NeedsBody, HasBody, IsDynamic>;
661
+ query<T>(schema: ZodType<T>): RouteBuilder<TBody, T, TOutput, HasAuth, NeedsBody, HasBody, Bill>;
665
662
  /**
666
663
  * Declare the response output's Zod schema for OpenAPI generation. The
667
664
  * runtime does not validate handler return values — use Zod's `.parse()`
@@ -674,7 +671,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
674
671
  * .handler(async () => ({ result: 'ok' }));
675
672
  * ```
676
673
  */
677
- output<T>(schema: ZodType<T>): RouteBuilder<TBody, TQuery, T, HasAuth, NeedsBody, HasBody, IsDynamic>;
674
+ output<T>(schema: ZodType<T>): RouteBuilder<TBody, TQuery, T, HasAuth, NeedsBody, HasBody, Bill>;
678
675
  /**
679
676
  * Attach an example of the request body or query for discovery output,
680
677
  * validated against the registered schema at registration.
@@ -684,7 +681,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
684
681
  * .body(searchSchema).inputExample({ query: 'cats' });
685
682
  * ```
686
683
  */
687
- inputExample(example: InputTypeFor<TBody, TQuery> & JsonObject): RouteBuilder<TBody, TQuery, TOutput, HasAuth, NeedsBody, HasBody, IsDynamic>;
684
+ inputExample(example: InputTypeFor<TBody, TQuery> & JsonObject): RouteBuilder<TBody, TQuery, TOutput, HasAuth, NeedsBody, HasBody, Bill>;
688
685
  /**
689
686
  * Attach an example response for discovery output, validated against the
690
687
  * registered output schema at registration.
@@ -694,7 +691,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
694
691
  * .output(resultSchema).outputExample({ result: 'ok' });
695
692
  * ```
696
693
  */
697
- outputExample(example: TOutput & JsonValue): RouteBuilder<TBody, TQuery, TOutput, HasAuth, NeedsBody, HasBody, IsDynamic>;
694
+ outputExample(example: TOutput & JsonValue): RouteBuilder<TBody, TQuery, TOutput, HasAuth, NeedsBody, HasBody, Bill>;
698
695
  /**
699
696
  * Set a human-readable summary of the route. Surfaces in OpenAPI,
700
697
  * `well-known`, and `llms.txt` discovery output.
@@ -739,7 +736,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
739
736
  * });
740
737
  * ```
741
738
  */
742
- validate(fn: (body: TBody) => void | Promise<void>): RouteBuilder<TBody, TQuery, TOutput, HasAuth, NeedsBody, HasBody, IsDynamic>;
739
+ validate(fn: (body: TBody) => void | Promise<void>): RouteBuilder<TBody, TQuery, TOutput, HasAuth, NeedsBody, HasBody, Bill>;
743
740
  /**
744
741
  * Hook into the settlement lifecycle. `beforeSettle` runs after the handler
745
742
  * succeeds but before on-chain settlement and can cancel the charge;
@@ -753,7 +750,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
753
750
  * });
754
751
  * ```
755
752
  */
756
- settlement(lifecycle: SettlementLifecycle<TBody>): RouteBuilder<TBody, TQuery, TOutput, HasAuth, NeedsBody, HasBody, IsDynamic>;
753
+ settlement(lifecycle: SettlementLifecycle<TBody>): RouteBuilder<TBody, TQuery, TOutput, HasAuth, NeedsBody, HasBody, Bill>;
757
754
  /**
758
755
  * Register the request handler and return the Next.js route function. The
759
756
  * handler receives a typed context and may return a value (serialized to
@@ -768,17 +765,17 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
768
765
  * .handler(async ({ body, wallet }) => searchService(body, wallet));
769
766
  * ```
770
767
  */
771
- handler(fn: HandlerArg<TBody, TQuery, HasAuth, NeedsBody, HasBody>): (request: NextRequest) => Promise<Response>;
768
+ handler(fn: HandlerArg<TBody, TQuery, HasAuth, NeedsBody, HasBody, Bill>): (request: NextRequest) => Promise<Response>;
772
769
  /**
773
770
  * Register a streaming handler (`async function*`) and return the Next.js
774
771
  * route function. Each `charge()` call bills one tick (`tickCost` USDC) up
775
- * to `maxPrice`; requires `.paid({ dynamic: true, ... })` and MPP session mode.
772
+ * to `maxPrice`; requires `.metered({ ... })` and MPP session mode.
776
773
  *
777
774
  * @example
778
775
  * ```ts
779
776
  * export const POST = router
780
777
  * .route('llm/stream')
781
- * .paid({ dynamic: true, tickCost: '0.0001', unitType: 'token', maxPrice: '0.05' })
778
+ * .metered({ tickCost: '0.0001', maxPrice: '0.05', unitType: 'token' })
782
779
  * .body(schema)
783
780
  * .stream(async function* ({ body, charge }) {
784
781
  * for await (const token of streamLLM(body.prompt)) {
@@ -788,7 +785,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
788
785
  * });
789
786
  * ```
790
787
  */
791
- stream(fn: StreamArg<TBody, TQuery, HasAuth, NeedsBody, HasBody, IsDynamic>): (request: NextRequest) => Promise<Response>;
788
+ stream(fn: StreamArg<TBody, TQuery, HasAuth, NeedsBody, HasBody, Bill>): (request: NextRequest) => Promise<Response>;
792
789
  private register;
793
790
  }
794
791