@agentcash/router 1.10.5 → 1.10.6

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/README.md CHANGED
@@ -150,6 +150,21 @@ The barrel forces every route module to load before the discovery handler walks
150
150
 
151
151
  The `openapi.json` should be hosted at `GET <origin>/openapi.json`.
152
152
 
153
+ ### 4. Unmatched route fallback
154
+
155
+ ```typescript
156
+ // app/api/[[...path]]/route.ts
157
+ import { router } from '@/lib/router';
158
+
159
+ export const GET = router.notFound();
160
+ export const POST = router.notFound();
161
+ export const DELETE = router.notFound();
162
+ export const PUT = router.notFound();
163
+ export const PATCH = router.notFound();
164
+ ```
165
+
166
+ This catches stale agent calls to API paths that no longer exist and returns a JSON 404 telling the client to rediscover the origin.
167
+
153
168
  ## Auth modes
154
169
 
155
170
  | Method | Purpose |
package/dist/index.cjs CHANGED
@@ -1207,7 +1207,7 @@ async function trySiwxFastPath(ctx, account) {
1207
1207
  function shouldParseBodyEarly(incomingStrategy, routeEntry, pricing) {
1208
1208
  if (incomingStrategy) return false;
1209
1209
  if (!routeEntry.bodySchema) return false;
1210
- return (pricing?.needsBody ?? false) || !!routeEntry.validateFn;
1210
+ return (pricing?.needsBody ?? false) || !!routeEntry.validateFn || !!routeEntry.checkoutSession;
1211
1211
  }
1212
1212
 
1213
1213
  // src/pipeline/steps/resolve-early-body.ts
@@ -2549,30 +2549,37 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
2549
2549
  return errorResponse;
2550
2550
  }
2551
2551
  const extensions = await buildChallengeExtensions(ctx);
2552
- const responseBody = failure ? JSON.stringify({ error: failure.message ?? null, reason: failure.reason }) : null;
2553
- const response = new import_server5.NextResponse(responseBody, {
2554
- status: 402,
2555
- headers: {
2556
- "Content-Type": "application/json",
2557
- "Cache-Control": "no-store"
2558
- }
2559
- });
2560
- for (const strategy of getAllowedStrategies(ctx.routeEntry.protocols)) {
2552
+ let checkoutSession;
2553
+ if (ctx.routeEntry.checkoutSession) {
2561
2554
  try {
2562
- const contribution = await strategy.buildChallenge({
2555
+ checkoutSession = await ctx.routeEntry.checkoutSession({
2563
2556
  request: ctx.request,
2564
- routeEntry: ctx.routeEntry,
2557
+ route: ctx.routeEntry.key,
2565
2558
  body,
2566
- price: challengePrice,
2567
- extensions,
2568
- deps: ctx.deps,
2569
- report: ctx.report
2559
+ price: challengePrice
2570
2560
  });
2571
- if (contribution.headers) {
2572
- for (const [name, value] of Object.entries(contribution.headers)) {
2573
- response.headers.set(name, value);
2574
- }
2575
- }
2561
+ } catch (err) {
2562
+ const message = errorMessage(err, "Checkout session build failed");
2563
+ const responseBody2 = { success: false, error: message };
2564
+ const errorResponse = import_server5.NextResponse.json(responseBody2, { status: errorStatus(err, 500) });
2565
+ firePluginResponse(ctx, errorResponse, body, responseBody2, { message, cause: err });
2566
+ return errorResponse;
2567
+ }
2568
+ }
2569
+ const contributions = [];
2570
+ for (const strategy of getAllowedStrategies(ctx.routeEntry.protocols)) {
2571
+ try {
2572
+ contributions.push(
2573
+ await strategy.buildChallenge({
2574
+ request: ctx.request,
2575
+ routeEntry: ctx.routeEntry,
2576
+ body,
2577
+ price: challengePrice,
2578
+ extensions,
2579
+ deps: ctx.deps,
2580
+ report: ctx.report
2581
+ })
2582
+ );
2576
2583
  } catch (err) {
2577
2584
  const message = `${strategy.protocol} challenge build failed: ${errorMessage(err, String(err))}`;
2578
2585
  ctx.report("critical", message);
@@ -2584,6 +2591,26 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
2584
2591
  }
2585
2592
  }
2586
2593
  }
2594
+ const responsePayload = {
2595
+ ...Object.assign({}, ...contributions.map((contribution) => contribution.body ?? {})),
2596
+ ...failure && { error: failure.message ?? null, reason: failure.reason },
2597
+ ...checkoutSession && { checkout_session: checkoutSession }
2598
+ };
2599
+ const responseBody = Object.keys(responsePayload).length ? JSON.stringify(responsePayload) : null;
2600
+ const response = new import_server5.NextResponse(responseBody, {
2601
+ status: 402,
2602
+ headers: {
2603
+ "Content-Type": "application/json",
2604
+ "Cache-Control": "no-store"
2605
+ }
2606
+ });
2607
+ for (const contribution of contributions) {
2608
+ if (contribution.headers) {
2609
+ for (const [name, value] of Object.entries(contribution.headers)) {
2610
+ response.headers.set(name, value);
2611
+ }
2612
+ }
2613
+ }
2587
2614
  firePluginResponse(ctx, response);
2588
2615
  return response;
2589
2616
  }
@@ -3602,7 +3629,8 @@ var RouteBuilder = class _RouteBuilder {
3602
3629
  validateFn: void 0,
3603
3630
  settlement: void 0,
3604
3631
  mppInfo: void 0,
3605
- hasCheckout: false
3632
+ hasCheckout: false,
3633
+ checkoutSession: void 0
3606
3634
  };
3607
3635
  }
3608
3636
  fork() {
@@ -3693,7 +3721,8 @@ var RouteBuilder = class _RouteBuilder {
3693
3721
  if (resolvedOptions.minPrice) next.#s.minPrice = resolvedOptions.minPrice;
3694
3722
  if (resolvedOptions.payTo) next.#s.payTo = resolvedOptions.payTo;
3695
3723
  if (resolvedOptions.mpp) next.#s.mppInfo = resolvedOptions.mpp;
3696
- if (resolvedOptions.checkout) next.#s.hasCheckout = true;
3724
+ if (resolvedOptions.checkout || resolvedOptions.checkoutSession) next.#s.hasCheckout = true;
3725
+ if (resolvedOptions.checkoutSession) next.#s.checkoutSession = resolvedOptions.checkoutSession;
3697
3726
  next.#s.billing = billing;
3698
3727
  if (tickCost) next.#s.tickCost = tickCost;
3699
3728
  if (unitType) next.#s.unitType = unitType;
@@ -4128,6 +4157,7 @@ var RouteBuilder = class _RouteBuilder {
4128
4157
  settlement: this.#s.settlement,
4129
4158
  mppInfo: this.#s.mppInfo,
4130
4159
  hasCheckout: this.#s.hasCheckout ? true : void 0,
4160
+ checkoutSession: this.#s.checkoutSession,
4131
4161
  tickCost: this.#s.tickCost,
4132
4162
  unitType: this.#s.unitType
4133
4163
  };
@@ -4475,6 +4505,33 @@ function createLlmsTxtHandler(discovery) {
4475
4505
  };
4476
4506
  }
4477
4507
 
4508
+ // src/discovery/not-found.ts
4509
+ var import_server12 = require("next/server");
4510
+ function createNotFoundHandler(baseUrl) {
4511
+ const normalizedBase = baseUrl.replace(/\/+$/, "");
4512
+ return async (request) => import_server12.NextResponse.json(
4513
+ {
4514
+ success: false,
4515
+ code: "route_not_found",
4516
+ error: "Route not found. Rediscover this origin and retry with the current discovery document.",
4517
+ requestedUrl: request.url,
4518
+ discovery: {
4519
+ openapi: `${normalizedBase}/openapi.json`,
4520
+ wellKnown: `${normalizedBase}/.well-known/x402`,
4521
+ llmsTxt: `${normalizedBase}/llms.txt`
4522
+ }
4523
+ },
4524
+ {
4525
+ status: 404,
4526
+ headers: {
4527
+ "Access-Control-Allow-Origin": "*",
4528
+ "Access-Control-Allow-Methods": "GET, POST, DELETE, PUT, PATCH, OPTIONS",
4529
+ "Access-Control-Allow-Headers": "Content-Type, Authorization, X-API-Key, SIGN-IN-WITH-X"
4530
+ }
4531
+ }
4532
+ );
4533
+ }
4534
+
4478
4535
  // src/index.ts
4479
4536
  init_accepts();
4480
4537
  init_constants();
@@ -5178,6 +5235,9 @@ function createRouter(config) {
5178
5235
  llmsTxt() {
5179
5236
  return createLlmsTxtHandler(config.discovery);
5180
5237
  },
5238
+ notFound() {
5239
+ return createNotFoundHandler(resolvedBaseUrl);
5240
+ },
5181
5241
  monitors() {
5182
5242
  const result = [];
5183
5243
  for (const [, entry] of registry.entries()) {
package/dist/index.d.cts CHANGED
@@ -219,6 +219,15 @@ interface MppProtocolInfo {
219
219
  intent?: string;
220
220
  currency?: string;
221
221
  }
222
+ type CheckoutSessionResponse = Record<string, unknown>;
223
+ interface CheckoutSessionContext<TBody = unknown> {
224
+ request: NextRequest;
225
+ route: string;
226
+ body: TBody | undefined;
227
+ /** Decimal-dollar price quoted for this 402 challenge. */
228
+ price: string;
229
+ }
230
+ type CheckoutSessionFn<TBody = unknown> = (ctx: CheckoutSessionContext<TBody>) => CheckoutSessionResponse | null | undefined | Promise<CheckoutSessionResponse | null | undefined>;
222
231
  interface PaidOptions {
223
232
  protocols?: ProtocolType[];
224
233
  maxPrice?: string;
@@ -229,6 +238,14 @@ interface PaidOptions {
229
238
  mpp?: MppProtocolInfo;
230
239
  /** Signal in discovery that clients should use an explicit checkout flow before payment. */
231
240
  checkout?: boolean;
241
+ /**
242
+ * Build dynamic checkout review metadata for the router-owned 402 response body.
243
+ *
244
+ * The returned object is emitted as `{ "checkout_session": ... }` on the unpaid
245
+ * payment challenge response. Payment terms remain authoritative in the x402/MPP
246
+ * challenge headers.
247
+ */
248
+ checkoutSession?: CheckoutSessionFn;
232
249
  }
233
250
  type PaidArg = (PaidOptions & {
234
251
  price: string;
@@ -374,6 +391,7 @@ interface RouteEntry {
374
391
  settlement?: SettlementLifecycle;
375
392
  mppInfo?: MppProtocolInfo;
376
393
  hasCheckout?: boolean;
394
+ checkoutSession?: CheckoutSessionFn;
377
395
  /** Per-tick cost (decimal-dollar). Required when `metered` is true. */
378
396
  tickCost?: string;
379
397
  /** Cosmetic unit label for 402 challenges and client UIs. */
@@ -557,8 +575,8 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
557
575
  * - `{ price }` — fixed price (object form of the string sugar).
558
576
  * - `{ field, tiers, default? }` — pick a tier from `body[field]`.
559
577
  *
560
- * Common knobs (`protocols`, `maxPrice`, `minPrice`, `payTo`, `mpp`, `checkout`) live
561
- * alongside the pricing shape. For handler-computed billing use `.upTo()`;
578
+ * Common knobs (`protocols`, `maxPrice`, `minPrice`, `payTo`, `mpp`, `checkout`,
579
+ * `checkoutSession`) live alongside the pricing shape. For handler-computed billing use `.upTo()`;
562
580
  * for per-tick billing use `.metered()`.
563
581
  *
564
582
  * @example
@@ -900,6 +918,7 @@ interface ServiceRouter<TPriceKeys extends string = never> {
900
918
  wellKnown(): (request: NextRequest) => Promise<NextResponse>;
901
919
  openapi(): (request: NextRequest) => Promise<NextResponse>;
902
920
  llmsTxt(): (request: NextRequest) => Promise<NextResponse>;
921
+ notFound(): (request: NextRequest) => Promise<NextResponse>;
903
922
  monitors(): MonitorEntry[];
904
923
  registry: RouteRegistry;
905
924
  }
@@ -928,4 +947,4 @@ declare function createRouter<const P extends Record<string, string> = Record<ne
928
947
  */
929
948
  declare function createRouterFromEnv<const P extends Record<string, string> = Record<never, string>>(options: CreateRouterFromEnvOptions<P>): ServiceRouter<Extract<keyof P, string>>;
930
949
 
931
- export { BASE_MAINNET_NETWORK, BASE_USDC_ADDRESS, BASE_USDC_DECIMALS, type CreateRouterFromEnvOptions, DEFAULT_SOLANA_FACILITATOR_URL, DEFAULT_TEMPO_RPC_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 };
950
+ export { BASE_MAINNET_NETWORK, BASE_USDC_ADDRESS, BASE_USDC_DECIMALS, type CheckoutSessionContext, type CheckoutSessionFn, type CheckoutSessionResponse, type CreateRouterFromEnvOptions, DEFAULT_SOLANA_FACILITATOR_URL, DEFAULT_TEMPO_RPC_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
@@ -219,6 +219,15 @@ interface MppProtocolInfo {
219
219
  intent?: string;
220
220
  currency?: string;
221
221
  }
222
+ type CheckoutSessionResponse = Record<string, unknown>;
223
+ interface CheckoutSessionContext<TBody = unknown> {
224
+ request: NextRequest;
225
+ route: string;
226
+ body: TBody | undefined;
227
+ /** Decimal-dollar price quoted for this 402 challenge. */
228
+ price: string;
229
+ }
230
+ type CheckoutSessionFn<TBody = unknown> = (ctx: CheckoutSessionContext<TBody>) => CheckoutSessionResponse | null | undefined | Promise<CheckoutSessionResponse | null | undefined>;
222
231
  interface PaidOptions {
223
232
  protocols?: ProtocolType[];
224
233
  maxPrice?: string;
@@ -229,6 +238,14 @@ interface PaidOptions {
229
238
  mpp?: MppProtocolInfo;
230
239
  /** Signal in discovery that clients should use an explicit checkout flow before payment. */
231
240
  checkout?: boolean;
241
+ /**
242
+ * Build dynamic checkout review metadata for the router-owned 402 response body.
243
+ *
244
+ * The returned object is emitted as `{ "checkout_session": ... }` on the unpaid
245
+ * payment challenge response. Payment terms remain authoritative in the x402/MPP
246
+ * challenge headers.
247
+ */
248
+ checkoutSession?: CheckoutSessionFn;
232
249
  }
233
250
  type PaidArg = (PaidOptions & {
234
251
  price: string;
@@ -374,6 +391,7 @@ interface RouteEntry {
374
391
  settlement?: SettlementLifecycle;
375
392
  mppInfo?: MppProtocolInfo;
376
393
  hasCheckout?: boolean;
394
+ checkoutSession?: CheckoutSessionFn;
377
395
  /** Per-tick cost (decimal-dollar). Required when `metered` is true. */
378
396
  tickCost?: string;
379
397
  /** Cosmetic unit label for 402 challenges and client UIs. */
@@ -557,8 +575,8 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
557
575
  * - `{ price }` — fixed price (object form of the string sugar).
558
576
  * - `{ field, tiers, default? }` — pick a tier from `body[field]`.
559
577
  *
560
- * Common knobs (`protocols`, `maxPrice`, `minPrice`, `payTo`, `mpp`, `checkout`) live
561
- * alongside the pricing shape. For handler-computed billing use `.upTo()`;
578
+ * Common knobs (`protocols`, `maxPrice`, `minPrice`, `payTo`, `mpp`, `checkout`,
579
+ * `checkoutSession`) live alongside the pricing shape. For handler-computed billing use `.upTo()`;
562
580
  * for per-tick billing use `.metered()`.
563
581
  *
564
582
  * @example
@@ -900,6 +918,7 @@ interface ServiceRouter<TPriceKeys extends string = never> {
900
918
  wellKnown(): (request: NextRequest) => Promise<NextResponse>;
901
919
  openapi(): (request: NextRequest) => Promise<NextResponse>;
902
920
  llmsTxt(): (request: NextRequest) => Promise<NextResponse>;
921
+ notFound(): (request: NextRequest) => Promise<NextResponse>;
903
922
  monitors(): MonitorEntry[];
904
923
  registry: RouteRegistry;
905
924
  }
@@ -928,4 +947,4 @@ declare function createRouter<const P extends Record<string, string> = Record<ne
928
947
  */
929
948
  declare function createRouterFromEnv<const P extends Record<string, string> = Record<never, string>>(options: CreateRouterFromEnvOptions<P>): ServiceRouter<Extract<keyof P, string>>;
930
949
 
931
- export { BASE_MAINNET_NETWORK, BASE_USDC_ADDRESS, BASE_USDC_DECIMALS, type CreateRouterFromEnvOptions, DEFAULT_SOLANA_FACILITATOR_URL, DEFAULT_TEMPO_RPC_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 };
950
+ export { BASE_MAINNET_NETWORK, BASE_USDC_ADDRESS, BASE_USDC_DECIMALS, type CheckoutSessionContext, type CheckoutSessionFn, type CheckoutSessionResponse, type CreateRouterFromEnvOptions, DEFAULT_SOLANA_FACILITATOR_URL, DEFAULT_TEMPO_RPC_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.js CHANGED
@@ -1165,7 +1165,7 @@ async function trySiwxFastPath(ctx, account) {
1165
1165
  function shouldParseBodyEarly(incomingStrategy, routeEntry, pricing) {
1166
1166
  if (incomingStrategy) return false;
1167
1167
  if (!routeEntry.bodySchema) return false;
1168
- return (pricing?.needsBody ?? false) || !!routeEntry.validateFn;
1168
+ return (pricing?.needsBody ?? false) || !!routeEntry.validateFn || !!routeEntry.checkoutSession;
1169
1169
  }
1170
1170
 
1171
1171
  // src/pipeline/steps/resolve-early-body.ts
@@ -2507,30 +2507,37 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
2507
2507
  return errorResponse;
2508
2508
  }
2509
2509
  const extensions = await buildChallengeExtensions(ctx);
2510
- const responseBody = failure ? JSON.stringify({ error: failure.message ?? null, reason: failure.reason }) : null;
2511
- const response = new NextResponse5(responseBody, {
2512
- status: 402,
2513
- headers: {
2514
- "Content-Type": "application/json",
2515
- "Cache-Control": "no-store"
2516
- }
2517
- });
2518
- for (const strategy of getAllowedStrategies(ctx.routeEntry.protocols)) {
2510
+ let checkoutSession;
2511
+ if (ctx.routeEntry.checkoutSession) {
2519
2512
  try {
2520
- const contribution = await strategy.buildChallenge({
2513
+ checkoutSession = await ctx.routeEntry.checkoutSession({
2521
2514
  request: ctx.request,
2522
- routeEntry: ctx.routeEntry,
2515
+ route: ctx.routeEntry.key,
2523
2516
  body,
2524
- price: challengePrice,
2525
- extensions,
2526
- deps: ctx.deps,
2527
- report: ctx.report
2517
+ price: challengePrice
2528
2518
  });
2529
- if (contribution.headers) {
2530
- for (const [name, value] of Object.entries(contribution.headers)) {
2531
- response.headers.set(name, value);
2532
- }
2533
- }
2519
+ } catch (err) {
2520
+ const message = errorMessage(err, "Checkout session build failed");
2521
+ const responseBody2 = { success: false, error: message };
2522
+ const errorResponse = NextResponse5.json(responseBody2, { status: errorStatus(err, 500) });
2523
+ firePluginResponse(ctx, errorResponse, body, responseBody2, { message, cause: err });
2524
+ return errorResponse;
2525
+ }
2526
+ }
2527
+ const contributions = [];
2528
+ for (const strategy of getAllowedStrategies(ctx.routeEntry.protocols)) {
2529
+ try {
2530
+ contributions.push(
2531
+ await strategy.buildChallenge({
2532
+ request: ctx.request,
2533
+ routeEntry: ctx.routeEntry,
2534
+ body,
2535
+ price: challengePrice,
2536
+ extensions,
2537
+ deps: ctx.deps,
2538
+ report: ctx.report
2539
+ })
2540
+ );
2534
2541
  } catch (err) {
2535
2542
  const message = `${strategy.protocol} challenge build failed: ${errorMessage(err, String(err))}`;
2536
2543
  ctx.report("critical", message);
@@ -2542,6 +2549,26 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
2542
2549
  }
2543
2550
  }
2544
2551
  }
2552
+ const responsePayload = {
2553
+ ...Object.assign({}, ...contributions.map((contribution) => contribution.body ?? {})),
2554
+ ...failure && { error: failure.message ?? null, reason: failure.reason },
2555
+ ...checkoutSession && { checkout_session: checkoutSession }
2556
+ };
2557
+ const responseBody = Object.keys(responsePayload).length ? JSON.stringify(responsePayload) : null;
2558
+ const response = new NextResponse5(responseBody, {
2559
+ status: 402,
2560
+ headers: {
2561
+ "Content-Type": "application/json",
2562
+ "Cache-Control": "no-store"
2563
+ }
2564
+ });
2565
+ for (const contribution of contributions) {
2566
+ if (contribution.headers) {
2567
+ for (const [name, value] of Object.entries(contribution.headers)) {
2568
+ response.headers.set(name, value);
2569
+ }
2570
+ }
2571
+ }
2545
2572
  firePluginResponse(ctx, response);
2546
2573
  return response;
2547
2574
  }
@@ -3560,7 +3587,8 @@ var RouteBuilder = class _RouteBuilder {
3560
3587
  validateFn: void 0,
3561
3588
  settlement: void 0,
3562
3589
  mppInfo: void 0,
3563
- hasCheckout: false
3590
+ hasCheckout: false,
3591
+ checkoutSession: void 0
3564
3592
  };
3565
3593
  }
3566
3594
  fork() {
@@ -3651,7 +3679,8 @@ var RouteBuilder = class _RouteBuilder {
3651
3679
  if (resolvedOptions.minPrice) next.#s.minPrice = resolvedOptions.minPrice;
3652
3680
  if (resolvedOptions.payTo) next.#s.payTo = resolvedOptions.payTo;
3653
3681
  if (resolvedOptions.mpp) next.#s.mppInfo = resolvedOptions.mpp;
3654
- if (resolvedOptions.checkout) next.#s.hasCheckout = true;
3682
+ if (resolvedOptions.checkout || resolvedOptions.checkoutSession) next.#s.hasCheckout = true;
3683
+ if (resolvedOptions.checkoutSession) next.#s.checkoutSession = resolvedOptions.checkoutSession;
3655
3684
  next.#s.billing = billing;
3656
3685
  if (tickCost) next.#s.tickCost = tickCost;
3657
3686
  if (unitType) next.#s.unitType = unitType;
@@ -4086,6 +4115,7 @@ var RouteBuilder = class _RouteBuilder {
4086
4115
  settlement: this.#s.settlement,
4087
4116
  mppInfo: this.#s.mppInfo,
4088
4117
  hasCheckout: this.#s.hasCheckout ? true : void 0,
4118
+ checkoutSession: this.#s.checkoutSession,
4089
4119
  tickCost: this.#s.tickCost,
4090
4120
  unitType: this.#s.unitType
4091
4121
  };
@@ -4433,6 +4463,33 @@ function createLlmsTxtHandler(discovery) {
4433
4463
  };
4434
4464
  }
4435
4465
 
4466
+ // src/discovery/not-found.ts
4467
+ import { NextResponse as NextResponse12 } from "next/server";
4468
+ function createNotFoundHandler(baseUrl) {
4469
+ const normalizedBase = baseUrl.replace(/\/+$/, "");
4470
+ return async (request) => NextResponse12.json(
4471
+ {
4472
+ success: false,
4473
+ code: "route_not_found",
4474
+ error: "Route not found. Rediscover this origin and retry with the current discovery document.",
4475
+ requestedUrl: request.url,
4476
+ discovery: {
4477
+ openapi: `${normalizedBase}/openapi.json`,
4478
+ wellKnown: `${normalizedBase}/.well-known/x402`,
4479
+ llmsTxt: `${normalizedBase}/llms.txt`
4480
+ }
4481
+ },
4482
+ {
4483
+ status: 404,
4484
+ headers: {
4485
+ "Access-Control-Allow-Origin": "*",
4486
+ "Access-Control-Allow-Methods": "GET, POST, DELETE, PUT, PATCH, OPTIONS",
4487
+ "Access-Control-Allow-Headers": "Content-Type, Authorization, X-API-Key, SIGN-IN-WITH-X"
4488
+ }
4489
+ }
4490
+ );
4491
+ }
4492
+
4436
4493
  // src/index.ts
4437
4494
  init_accepts();
4438
4495
  init_constants();
@@ -5136,6 +5193,9 @@ function createRouter(config) {
5136
5193
  llmsTxt() {
5137
5194
  return createLlmsTxtHandler(config.discovery);
5138
5195
  },
5196
+ notFound() {
5197
+ return createNotFoundHandler(resolvedBaseUrl);
5198
+ },
5139
5199
  monitors() {
5140
5200
  const result = [];
5141
5201
  for (const [, entry] of registry.entries()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentcash/router",
3
- "version": "1.10.5",
3
+ "version": "1.10.6",
4
4
  "description": "Unified route builder for Next.js App Router APIs with x402, MPP, SIWX, and API key auth",
5
5
  "type": "module",
6
6
  "exports": {