@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.js CHANGED
@@ -9,14 +9,18 @@ var __export = (target, all) => {
9
9
  };
10
10
 
11
11
  // src/constants.ts
12
- var BASE_NETWORK, SOLANA_MAINNET_NETWORK, TEMPO_USDC_CURRENCY, ZERO_EVM_ADDRESS;
12
+ var BASE_MAINNET_NETWORK, SOLANA_MAINNET_NETWORK, TEMPO_USDC_ADDRESS, TEMPO_USDC_DECIMALS, BASE_USDC_ADDRESS, BASE_USDC_DECIMALS, ZERO_EVM_ADDRESS, DEFAULT_SOLANA_FACILITATOR_URL;
13
13
  var init_constants = __esm({
14
14
  "src/constants.ts"() {
15
15
  "use strict";
16
- BASE_NETWORK = "eip155:8453";
16
+ BASE_MAINNET_NETWORK = "eip155:8453";
17
17
  SOLANA_MAINNET_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
18
- TEMPO_USDC_CURRENCY = "0x20c000000000000000000000b9537d11c60e8b50";
18
+ TEMPO_USDC_ADDRESS = "0x20c000000000000000000000b9537d11c60e8b50";
19
+ TEMPO_USDC_DECIMALS = 6;
20
+ BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
21
+ BASE_USDC_DECIMALS = 6;
19
22
  ZERO_EVM_ADDRESS = "0x0000000000000000000000000000000000000000";
23
+ DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.corbits.dev";
20
24
  }
21
25
  });
22
26
 
@@ -33,7 +37,7 @@ function getConfiguredX402Accepts(config) {
33
37
  return [
34
38
  {
35
39
  scheme: "exact",
36
- network: config.network ?? BASE_NETWORK,
40
+ network: config.network ?? BASE_MAINNET_NETWORK,
37
41
  payTo: config.payeeAddress
38
42
  }
39
43
  ];
@@ -213,7 +217,10 @@ async function getAcceptsHeadersForFacilitator(facilitator) {
213
217
  return {};
214
218
  }
215
219
  function resolveX402FacilitatorTarget(config, network, defaultEvmFacilitator) {
216
- return (isSolanaNetwork(network) ? config.x402?.facilitators?.solana : void 0) ?? (isEvmNetwork(network) ? config.x402?.facilitators?.evm : void 0) ?? (isSolanaNetwork(network) ? DEFAULT_SOLANA_FACILITATOR_URL : defaultEvmFacilitator);
220
+ if (isSolanaNetwork(network)) {
221
+ return config.x402?.facilitators?.solana ?? DEFAULT_SOLANA_FACILITATOR_URL;
222
+ }
223
+ return defaultEvmFacilitator;
217
224
  }
218
225
  function normalizeFacilitatorTarget(target) {
219
226
  return typeof target === "string" ? { url: target } : target;
@@ -226,19 +233,18 @@ function getNetworkFamily(network) {
226
233
  function sameFacilitatorConfig(a, b) {
227
234
  return a.url === b.url && a.createAuthHeaders === b.createAuthHeaders && a.createAcceptsHeaders === b.createAcceptsHeaders;
228
235
  }
229
- var DEFAULT_SOLANA_FACILITATOR_URL;
230
236
  var init_facilitators = __esm({
231
237
  "src/protocols/x402/facilitators.ts"() {
232
238
  "use strict";
233
239
  init_evm();
234
240
  init_solana();
235
- DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.corbits.dev";
241
+ init_constants();
236
242
  }
237
243
  });
238
244
 
239
- // src/server.ts
240
- var server_exports = {};
241
- __export(server_exports, {
245
+ // src/init/x402-server.ts
246
+ var x402_server_exports = {};
247
+ __export(x402_server_exports, {
242
248
  createX402Server: () => createX402Server
243
249
  });
244
250
  async function createX402Server(config) {
@@ -315,8 +321,8 @@ function buildSupportedKinds(group) {
315
321
  return [exactKind, uptoKind];
316
322
  });
317
323
  }
318
- var init_server = __esm({
319
- "src/server.ts"() {
324
+ var init_x402_server = __esm({
325
+ "src/init/x402-server.ts"() {
320
326
  "use strict";
321
327
  init_evm();
322
328
  init_solana();
@@ -389,7 +395,7 @@ var AUTH_SCHEME = {
389
395
  MPP_PAYMENT: "Payment "
390
396
  };
391
397
 
392
- // src/plugin.ts
398
+ // src/plugin/index.ts
393
399
  function createDefaultContext(meta) {
394
400
  const ctx = {
395
401
  requestId: meta.requestId,
@@ -425,46 +431,8 @@ function firePluginHook(plugin, method, ...args) {
425
431
  return void 0;
426
432
  }
427
433
  }
428
- function consolePlugin() {
429
- return {
430
- onRequest(meta) {
431
- const ctx = createDefaultContext(meta);
432
- return ctx;
433
- },
434
- onAuthVerified(_ctx, auth) {
435
- const wallet = auth.wallet ? ` wallet=${auth.wallet}` : "";
436
- console.log(`[router] AUTH ${auth.authMode} ${auth.route}${wallet}`);
437
- },
438
- onPaymentVerified(_ctx, payment) {
439
- console.log(`[router] VERIFIED ${payment.protocol} ${payment.payer} ${payment.amount}`);
440
- },
441
- onPaymentSettled(_ctx, settlement) {
442
- console.log(`[router] SETTLED ${settlement.protocol} tx=${settlement.transaction}`);
443
- },
444
- onResponse(ctx, response) {
445
- const wallet = ctx.verifiedWallet ? ` wallet=${ctx.verifiedWallet}` : "";
446
- console.log(
447
- `[router] ${ctx.route} \u2192 ${response.statusCode} (${response.duration}ms)${wallet}`
448
- );
449
- },
450
- onError(_ctx, error) {
451
- console.error(`[router] ERROR ${error.status}: ${error.message}`);
452
- },
453
- onAlert(_ctx, alert) {
454
- const logFn = alert.level === "critical" || alert.level === "error" ? console.error : alert.level === "warn" ? console.warn : console.log;
455
- logFn(
456
- `[router] ${alert.level.toUpperCase()} ${alert.route}: ${alert.message}`,
457
- alert.meta ?? ""
458
- );
459
- },
460
- onProviderQuota(_ctx, event) {
461
- const logFn = event.level === "critical" ? console.error : event.level === "warn" ? console.warn : console.log;
462
- logFn(`[router] QUOTA ${event.level.toUpperCase()} ${event.provider}: ${event.message}`);
463
- }
464
- };
465
- }
466
434
 
467
- // src/alert.ts
435
+ // src/plugin/reporter.ts
468
436
  function createReporter(plugin, pluginCtx, route) {
469
437
  return (level, message, meta) => {
470
438
  firePluginHook(plugin, "onAlert", pluginCtx, {
@@ -476,7 +444,7 @@ function createReporter(plugin, pluginCtx, route) {
476
444
  };
477
445
  }
478
446
 
479
- // src/pipeline/context/preflight.ts
447
+ // src/pipeline/steps/preflight.ts
480
448
  function preflight(routeEntry, handler, deps, request) {
481
449
  const meta = buildMeta(request, routeEntry);
482
450
  const pluginCtx = firePluginHook(deps.plugin, "onRequest", meta) ?? createDefaultContext(meta);
@@ -506,10 +474,10 @@ function buildMeta(request, routeEntry) {
506
474
  };
507
475
  }
508
476
 
509
- // src/pipeline/context/parse-body.ts
477
+ // src/pipeline/steps/parse-body.ts
510
478
  import { NextResponse } from "next/server";
511
479
 
512
- // src/body.ts
480
+ // src/pipeline/body.ts
513
481
  async function bufferBody(request) {
514
482
  const text = await request.text();
515
483
  if (!text) return void 0;
@@ -533,7 +501,19 @@ function validateBody(parsed, schema) {
533
501
  };
534
502
  }
535
503
 
536
- // src/pipeline/context/fire-plugin-response.ts
504
+ // src/plugin/events.ts
505
+ function fireAuthVerified(ctx, event) {
506
+ firePluginHook(ctx.deps.plugin, "onAuthVerified", ctx.pluginCtx, {
507
+ ...event,
508
+ route: ctx.routeEntry.key
509
+ });
510
+ }
511
+ function firePaymentVerified(ctx, event) {
512
+ firePluginHook(ctx.deps.plugin, "onPaymentVerified", ctx.pluginCtx, event);
513
+ }
514
+ function firePaymentSettled(ctx, event) {
515
+ firePluginHook(ctx.deps.plugin, "onPaymentSettled", ctx.pluginCtx, event);
516
+ }
537
517
  function firePluginResponse(ctx, response, requestBody, responseBody) {
538
518
  firePluginHook(ctx.deps.plugin, "onResponse", ctx.pluginCtx, {
539
519
  statusCode: response.status,
@@ -552,8 +532,37 @@ function firePluginResponse(ctx, response, requestBody, responseBody) {
552
532
  });
553
533
  }
554
534
  }
535
+ function fireProviderQuota(ctx, response, handlerResult) {
536
+ const { providerName, providerConfig } = ctx.routeEntry;
537
+ if (!providerName || !providerConfig?.extractQuota) return;
538
+ if (response.status >= 400) return;
539
+ try {
540
+ const quota = providerConfig.extractQuota(handlerResult, response.headers);
541
+ if (!quota) return;
542
+ const level = computeQuotaLevel(quota.remaining, providerConfig.warn, providerConfig.critical);
543
+ const overage = providerConfig.overage ?? "same-rate";
544
+ const event = {
545
+ provider: providerName,
546
+ route: ctx.routeEntry.key,
547
+ remaining: quota.remaining,
548
+ limit: quota.limit,
549
+ spend: quota.spend,
550
+ level,
551
+ overage,
552
+ message: quota.remaining !== null ? `${providerName}: ${quota.remaining}${quota.limit ? `/${quota.limit}` : ""} remaining` : `${providerName}: quota info unavailable`
553
+ };
554
+ firePluginHook(ctx.deps.plugin, "onProviderQuota", ctx.pluginCtx, event);
555
+ } catch {
556
+ }
557
+ }
558
+ function computeQuotaLevel(remaining, warn, critical) {
559
+ if (remaining === null) return "healthy";
560
+ if (critical !== void 0 && remaining <= critical) return "critical";
561
+ if (warn !== void 0 && remaining <= warn) return "warn";
562
+ return "healthy";
563
+ }
555
564
 
556
- // src/pipeline/context/parse-body.ts
565
+ // src/pipeline/steps/parse-body.ts
557
566
  async function parseBody(ctx, request = ctx.request) {
558
567
  if (!ctx.routeEntry.bodySchema) return { ok: true, data: void 0 };
559
568
  const raw = await bufferBody(request);
@@ -567,15 +576,7 @@ async function parseBody(ctx, request = ctx.request) {
567
576
  return { ok: false, response };
568
577
  }
569
578
 
570
- // src/pipeline/context/parse-query.ts
571
- function parseQuery(request, routeEntry) {
572
- if (!routeEntry.querySchema) return void 0;
573
- const params = Object.fromEntries(request.nextUrl.searchParams.entries());
574
- const result = routeEntry.querySchema.safeParse(params);
575
- return result.success ? result.data : params;
576
- }
577
-
578
- // src/pipeline/context/errors.ts
579
+ // src/pipeline/steps/errors.ts
579
580
  function errorStatus(error, fallback) {
580
581
  const status = error?.status;
581
582
  return typeof status === "number" ? status : fallback;
@@ -588,7 +589,7 @@ function handlerFailureError(response) {
588
589
  return Object.assign(new Error(message), { status: response.status });
589
590
  }
590
591
 
591
- // src/pipeline/context/fail.ts
592
+ // src/pipeline/steps/fail.ts
592
593
  import { NextResponse as NextResponse2 } from "next/server";
593
594
  function fail(ctx, status, message, requestBody) {
594
595
  const response = NextResponse2.json({ success: false, error: message }, { status });
@@ -596,7 +597,7 @@ function fail(ctx, status, message, requestBody) {
596
597
  return response;
597
598
  }
598
599
 
599
- // src/pipeline/context/run-validate.ts
600
+ // src/pipeline/steps/run-validate.ts
600
601
  async function runValidate(ctx, body) {
601
602
  if (!ctx.routeEntry.validateFn) return null;
602
603
  try {
@@ -619,6 +620,14 @@ var HttpError = class extends Error {
619
620
  }
620
621
  };
621
622
 
623
+ // src/pipeline/steps/parse-query.ts
624
+ function parseQuery(request, routeEntry) {
625
+ if (!routeEntry.querySchema) return void 0;
626
+ const params = Object.fromEntries(request.nextUrl.searchParams.entries());
627
+ const result = routeEntry.querySchema.safeParse(params);
628
+ return result.success ? result.data : params;
629
+ }
630
+
622
631
  // src/pipeline/flows/static/static-invoke.ts
623
632
  function invokePaidStatic(ctx, wallet, account, body, payment) {
624
633
  return runHandler(ctx, buildHandlerCtx(ctx, wallet, account, body, payment));
@@ -636,14 +645,7 @@ function buildHandlerCtx(ctx, wallet, account, body, payment) {
636
645
  wallet,
637
646
  payment,
638
647
  account,
639
- alert(level, message, alertMeta) {
640
- firePluginHook(ctx.deps.plugin, "onAlert", ctx.pluginCtx, {
641
- level,
642
- message,
643
- route: ctx.routeEntry.key,
644
- meta: alertMeta
645
- });
646
- },
648
+ alert: ctx.report,
647
649
  setVerifiedWallet: (addr) => ctx.pluginCtx.setVerifiedWallet(addr)
648
650
  };
649
651
  }
@@ -687,45 +689,14 @@ function isThenable(value) {
687
689
  return value != null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
688
690
  }
689
691
 
690
- // src/pipeline/context/fire-provider-quota.ts
691
- function fireProviderQuota(ctx, response, handlerResult) {
692
- const { providerName, providerConfig } = ctx.routeEntry;
693
- if (!providerName || !providerConfig?.extractQuota) return;
694
- if (response.status >= 400) return;
695
- try {
696
- const quota = providerConfig.extractQuota(handlerResult, response.headers);
697
- if (!quota) return;
698
- const level = computeQuotaLevel(quota.remaining, providerConfig.warn, providerConfig.critical);
699
- const overage = providerConfig.overage ?? "same-rate";
700
- const event = {
701
- provider: providerName,
702
- route: ctx.routeEntry.key,
703
- remaining: quota.remaining,
704
- limit: quota.limit,
705
- spend: quota.spend,
706
- level,
707
- overage,
708
- message: quota.remaining !== null ? `${providerName}: ${quota.remaining}${quota.limit ? `/${quota.limit}` : ""} remaining` : `${providerName}: quota info unavailable`
709
- };
710
- firePluginHook(ctx.deps.plugin, "onProviderQuota", ctx.pluginCtx, event);
711
- } catch {
712
- }
713
- }
714
- function computeQuotaLevel(remaining, warn, critical) {
715
- if (remaining === null) return "healthy";
716
- if (critical !== void 0 && remaining <= critical) return "critical";
717
- if (warn !== void 0 && remaining <= warn) return "warn";
718
- return "healthy";
719
- }
720
-
721
- // src/pipeline/context/finalize/response.ts
692
+ // src/pipeline/steps/finalize/response.ts
722
693
  function finalize(ctx, response, rawResult, requestBody) {
723
694
  fireProviderQuota(ctx, response, rawResult);
724
695
  firePluginResponse(ctx, response, requestBody, rawResult);
725
696
  return response;
726
697
  }
727
698
 
728
- // src/pipeline/context/grant-entitlement.ts
699
+ // src/pipeline/steps/grant-entitlement.ts
729
700
  async function grantEntitlementIfSiwx(ctx, wallet) {
730
701
  if (!ctx.routeEntry.siwxEnabled) return;
731
702
  try {
@@ -738,7 +709,7 @@ async function grantEntitlementIfSiwx(ctx, wallet) {
738
709
  }
739
710
  }
740
711
 
741
- // src/pipeline/context/settlement-context.ts
712
+ // src/pipeline/steps/settlement-context.ts
742
713
  function settlementContext(ctx, scope) {
743
714
  return {
744
715
  route: ctx.routeEntry.key,
@@ -752,7 +723,7 @@ function settlementContext(ctx, scope) {
752
723
  };
753
724
  }
754
725
 
755
- // src/pipeline/context/run-settlement-error.ts
726
+ // src/pipeline/steps/run-settlement-error.ts
756
727
  async function runSettlementError(ctx, scope, error, phase) {
757
728
  const hook = ctx.routeEntry.settlement?.onSettlementError;
758
729
  if (!hook) return;
@@ -764,7 +735,7 @@ async function runSettlementError(ctx, scope, error, phase) {
764
735
  }
765
736
  }
766
737
 
767
- // src/pipeline/context/run-after-settle.ts
738
+ // src/pipeline/steps/run-after-settle.ts
768
739
  async function runAfterSettle(ctx, scope) {
769
740
  const hook = ctx.routeEntry.settlement?.afterSettle;
770
741
  if (!hook) return;
@@ -777,11 +748,11 @@ async function runAfterSettle(ctx, scope) {
777
748
  }
778
749
  }
779
750
 
780
- // src/pipeline/context/finalize/epilogue.ts
751
+ // src/pipeline/steps/finalize/epilogue.ts
781
752
  async function runPostSettleEpilogue(args) {
782
753
  const { ctx, strategy, wallet, settle, afterSettleScope, rawResult, body } = args;
783
754
  await grantEntitlementIfSiwx(ctx, wallet);
784
- firePluginHook(ctx.deps.plugin, "onPaymentSettled", ctx.pluginCtx, {
755
+ firePaymentSettled(ctx, {
785
756
  protocol: strategy.protocol,
786
757
  payer: wallet,
787
758
  transaction: settle.settledPayment.transaction ?? "",
@@ -791,7 +762,7 @@ async function runPostSettleEpilogue(args) {
791
762
  return finalize(ctx, settle.response, rawResult, body);
792
763
  }
793
764
 
794
- // src/pipeline/context/finalize/request.ts
765
+ // src/pipeline/steps/finalize/request.ts
795
766
  async function settleAndFinalizeRequest(args) {
796
767
  const { ctx, strategy, verifyOutcome, scope, rawResult, body, billedAmount, onSettleError } = args;
797
768
  const { request, routeEntry, deps, report } = ctx;
@@ -824,7 +795,7 @@ async function settleAndFinalizeRequest(args) {
824
795
  });
825
796
  }
826
797
 
827
- // src/pipeline/context/finalize/stream.ts
798
+ // src/pipeline/steps/finalize/stream.ts
828
799
  async function settleAndFinalizeStream(args) {
829
800
  const { ctx, strategy, verifyOutcome, source, account, body, bindChannelCharge } = args;
830
801
  const { request, routeEntry, deps, report } = ctx;
@@ -862,7 +833,7 @@ async function settleAndFinalizeStream(args) {
862
833
  });
863
834
  }
864
835
 
865
- // src/pipeline/context/run-handler-only.ts
836
+ // src/pipeline/steps/run-handler-only.ts
866
837
  async function runHandlerOnly(ctx, wallet, account) {
867
838
  const body = await parseBody(ctx);
868
839
  if (!body.ok) return body.response;
@@ -872,7 +843,7 @@ async function runHandlerOnly(ctx, wallet, account) {
872
843
  return finalize(ctx, result.response, result.rawResult, body.data);
873
844
  }
874
845
 
875
- // src/pipeline/context/run-before-settle.ts
846
+ // src/pipeline/steps/run-before-settle.ts
876
847
  async function runBeforeSettle(ctx, scope) {
877
848
  const hook = ctx.routeEntry.settlement?.beforeSettle;
878
849
  if (!hook) return null;
@@ -889,7 +860,7 @@ async function runBeforeSettle(ctx, scope) {
889
860
  }
890
861
  }
891
862
 
892
- // src/pipeline/context/run-settled-handler-error.ts
863
+ // src/pipeline/steps/run-settled-handler-error.ts
893
864
  async function runSettledHandlerError(ctx, scope, error = scope.handlerError ?? handlerFailureError(scope.response)) {
894
865
  const hook = ctx.routeEntry.settlement?.onSettledHandlerError;
895
866
  if (!hook) return;
@@ -963,7 +934,7 @@ async function buildSIWXExtension() {
963
934
  return declareSIWxExtension();
964
935
  }
965
936
 
966
- // src/pipeline/context/try-siwx-fast-path.ts
937
+ // src/pipeline/steps/try-siwx-fast-path.ts
967
938
  async function trySiwxFastPath(ctx, account) {
968
939
  const { request, routeEntry, deps } = ctx;
969
940
  if (!routeEntry.siwxEnabled) return null;
@@ -975,22 +946,18 @@ async function trySiwxFastPath(ctx, account) {
975
946
  ctx.pluginCtx.setVerifiedWallet(wallet);
976
947
  const entitled = await deps.entitlementStore.has(routeEntry.key, wallet);
977
948
  if (!entitled) return null;
978
- firePluginHook(deps.plugin, "onAuthVerified", ctx.pluginCtx, {
979
- authMode: "siwx",
980
- wallet,
981
- route: routeEntry.key
982
- });
949
+ fireAuthVerified(ctx, { authMode: "siwx", wallet });
983
950
  return runHandlerOnly(ctx, wallet, account);
984
951
  }
985
952
 
986
- // src/pipeline/context/should-parse-body-early.ts
953
+ // src/pipeline/steps/should-parse-body-early.ts
987
954
  function shouldParseBodyEarly(incomingStrategy, routeEntry, pricing) {
988
955
  if (incomingStrategy) return false;
989
956
  if (!routeEntry.bodySchema) return false;
990
957
  return (pricing?.needsBody ?? false) || !!routeEntry.validateFn;
991
958
  }
992
959
 
993
- // src/pipeline/context/resolve-early-body.ts
960
+ // src/pipeline/steps/resolve-early-body.ts
994
961
  async function resolveEarlyBody(args) {
995
962
  const { ctx, pricing, incomingStrategy } = args;
996
963
  if (!shouldParseBodyEarly(incomingStrategy, ctx.routeEntry, pricing)) {
@@ -1022,24 +989,19 @@ function extractBearerToken(header) {
1022
989
  return null;
1023
990
  }
1024
991
 
1025
- // src/pipeline/context/run-api-key-gate.ts
992
+ // src/pipeline/steps/run-api-key-gate.ts
1026
993
  async function runApiKeyGate(ctx) {
1027
- const { request, routeEntry, deps } = ctx;
994
+ const { request, routeEntry } = ctx;
1028
995
  if (!routeEntry.apiKeyResolver) return { ok: true, account: void 0 };
1029
996
  const apiKeyResult = await verifyApiKey(request, routeEntry.apiKeyResolver);
1030
997
  if (!apiKeyResult.valid) {
1031
998
  return { ok: false, response: fail(ctx, 401, "Invalid or missing API key") };
1032
999
  }
1033
- firePluginHook(deps.plugin, "onAuthVerified", ctx.pluginCtx, {
1034
- authMode: "apiKey",
1035
- wallet: null,
1036
- route: routeEntry.key,
1037
- account: apiKeyResult.account
1038
- });
1000
+ fireAuthVerified(ctx, { authMode: "apiKey", wallet: null, account: apiKeyResult.account });
1039
1001
  return { ok: true, account: apiKeyResult.account };
1040
1002
  }
1041
1003
 
1042
- // src/pipeline/context/protocol-init-error.ts
1004
+ // src/pipeline/steps/protocol-init-error.ts
1043
1005
  function protocolInitError(routeEntry, deps) {
1044
1006
  if (!routeEntry.pricing) return null;
1045
1007
  const errors = [];
@@ -1062,12 +1024,7 @@ async function runApiKeyOnlyFlow(ctx) {
1062
1024
  }
1063
1025
  const result = await verifyApiKey(ctx.request, ctx.routeEntry.apiKeyResolver);
1064
1026
  if (!result.valid) return fail(ctx, 401, "Invalid or missing API key");
1065
- firePluginHook(ctx.deps.plugin, "onAuthVerified", ctx.pluginCtx, {
1066
- authMode: "apiKey",
1067
- wallet: null,
1068
- route: ctx.routeEntry.key,
1069
- account: result.account
1070
- });
1027
+ fireAuthVerified(ctx, { authMode: "apiKey", wallet: null, account: result.account });
1071
1028
  return runHandlerOnly(ctx, null, result.account);
1072
1029
  }
1073
1030
 
@@ -2157,21 +2114,6 @@ function reportSettleFailure(report, err, network) {
2157
2114
  });
2158
2115
  }
2159
2116
 
2160
- // src/protocols/detect.ts
2161
- function detectProtocol(request) {
2162
- if (request.headers.get(HEADERS.X402_PAYMENT_SIGNATURE) ?? request.headers.get(HEADERS.X402_PAYMENT_LEGACY)) {
2163
- return "x402";
2164
- }
2165
- const auth = request.headers.get(HEADERS.AUTHORIZATION);
2166
- if (auth && auth.startsWith(AUTH_SCHEME.MPP_PAYMENT)) {
2167
- return "mpp";
2168
- }
2169
- if (request.headers.get(HEADERS.SIWX)) {
2170
- return "siwx";
2171
- }
2172
- return null;
2173
- }
2174
-
2175
2117
  // src/protocols/index.ts
2176
2118
  var STRATEGIES = {
2177
2119
  x402: x402Strategy,
@@ -2196,9 +2138,9 @@ async function buildChallengeExtensions(ctx) {
2196
2138
  const { routeEntry } = ctx;
2197
2139
  let extensions;
2198
2140
  try {
2199
- const { z } = await import("zod");
2141
+ const { z: z2 } = await import("zod");
2200
2142
  const { declareDiscoveryExtension } = await import("@x402/extensions/bazaar");
2201
- const toJSON = (schema) => z.toJSONSchema(schema, {
2143
+ const toJSON = (schema) => z2.toJSONSchema(schema, {
2202
2144
  target: "draft-2020-12",
2203
2145
  unrepresentable: "any"
2204
2146
  });
@@ -2219,11 +2161,10 @@ async function buildChallengeExtensions(ctx) {
2219
2161
  extensions = declareDiscoveryExtension(config);
2220
2162
  }
2221
2163
  } catch (err) {
2222
- firePluginHook(ctx.deps.plugin, "onAlert", ctx.pluginCtx, {
2223
- level: "warn",
2224
- message: `Bazaar schema generation failed: ${err instanceof Error ? err.message : String(err)}`,
2225
- route: routeEntry.key
2226
- });
2164
+ ctx.report(
2165
+ "warn",
2166
+ `Bazaar schema generation failed: ${err instanceof Error ? err.message : String(err)}`
2167
+ );
2227
2168
  }
2228
2169
  if (routeEntry.siwxEnabled) {
2229
2170
  try {
@@ -2357,7 +2298,7 @@ async function runDynamicChannelMgmtFlow(args) {
2357
2298
  return build402(ctx, pricing, parsedBody, verifyOutcome.failure);
2358
2299
  }
2359
2300
  ctx.pluginCtx.setVerifiedWallet(verifyOutcome.wallet);
2360
- firePluginHook(deps.plugin, "onPaymentVerified", ctx.pluginCtx, {
2301
+ firePaymentVerified(ctx, {
2361
2302
  protocol: strategy.protocol,
2362
2303
  payer: verifyOutcome.wallet,
2363
2304
  amount: price,
@@ -2465,14 +2406,7 @@ async function invokeDynamic(ctx, wallet, account, body, payment) {
2465
2406
  wallet,
2466
2407
  payment,
2467
2408
  account,
2468
- alert(level, message, alertMeta) {
2469
- firePluginHook(ctx.deps.plugin, "onAlert", ctx.pluginCtx, {
2470
- level,
2471
- message,
2472
- route: ctx.routeEntry.key,
2473
- meta: alertMeta
2474
- });
2475
- },
2409
+ alert: ctx.report,
2476
2410
  setVerifiedWallet: (addr) => ctx.pluginCtx.setVerifiedWallet(addr)
2477
2411
  };
2478
2412
  const handlerCtx = chargeContext !== null ? { ...baseHandlerCtx, charge: chargeContext.charge } : baseHandlerCtx;
@@ -2537,7 +2471,7 @@ function resolveDynamicPreflight(strategy, request, routeEntry) {
2537
2471
  // src/pipeline/flows/dynamic/dynamic-request.ts
2538
2472
  async function runDynamicRequestFlow(args) {
2539
2473
  const { ctx, strategy, verifyOutcome, account, body, result } = args;
2540
- const { deps, routeEntry } = ctx;
2474
+ const { routeEntry } = ctx;
2541
2475
  const settleScope = {
2542
2476
  wallet: verifyOutcome.wallet,
2543
2477
  account,
@@ -2563,11 +2497,10 @@ async function runDynamicRequestFlow(args) {
2563
2497
  billedAmount,
2564
2498
  onSettleError: async (error, failMessage) => {
2565
2499
  await runSettlementError(ctx, settleScope, error, "settle");
2566
- firePluginHook(deps.plugin, "onAlert", ctx.pluginCtx, {
2567
- level: "critical",
2568
- message: `${strategy.protocol} ${failMessage}: ${errorMessage(error, "unknown")}`,
2569
- route: routeEntry.key
2570
- });
2500
+ ctx.report(
2501
+ "critical",
2502
+ `${strategy.protocol} ${failMessage}: ${errorMessage(error, "unknown")}`
2503
+ );
2571
2504
  }
2572
2505
  });
2573
2506
  }
@@ -2637,7 +2570,7 @@ async function runDynamicPaidFlow(ctx) {
2637
2570
  return build402(ctx, pricing, parsedBody, verifyOutcome.failure);
2638
2571
  }
2639
2572
  ctx.pluginCtx.setVerifiedWallet(verifyOutcome.wallet);
2640
- firePluginHook(deps.plugin, "onPaymentVerified", ctx.pluginCtx, {
2573
+ firePaymentVerified(ctx, {
2641
2574
  protocol: incomingStrategy.protocol,
2642
2575
  payer: verifyOutcome.wallet,
2643
2576
  amount: price,
@@ -2703,7 +2636,6 @@ async function resolveStaticBodyAndPrice(args) {
2703
2636
  // src/pipeline/flows/static/static-request.ts
2704
2637
  async function runStaticRequestFlow(args) {
2705
2638
  const { ctx, strategy, verifyOutcome, account, body, price, result } = args;
2706
- const { deps, routeEntry } = ctx;
2707
2639
  const settleScope = {
2708
2640
  wallet: verifyOutcome.wallet,
2709
2641
  account,
@@ -2744,11 +2676,10 @@ async function runStaticRequestFlow(args) {
2744
2676
  billedAmount: price,
2745
2677
  onSettleError: async (error, failMessage) => {
2746
2678
  await runSettlementError(ctx, settleScope, error, "settle");
2747
- firePluginHook(deps.plugin, "onAlert", ctx.pluginCtx, {
2748
- level: "critical",
2749
- message: `${strategy.protocol} ${failMessage}: ${errorMessage(error, "unknown")}`,
2750
- route: routeEntry.key
2751
- });
2679
+ ctx.report(
2680
+ "critical",
2681
+ `${strategy.protocol} ${failMessage}: ${errorMessage(error, "unknown")}`
2682
+ );
2752
2683
  }
2753
2684
  });
2754
2685
  }
@@ -2794,7 +2725,7 @@ async function runStaticPaidFlow(ctx) {
2794
2725
  return build402(ctx, pricing, parsedBody, verifyOutcome.failure);
2795
2726
  }
2796
2727
  ctx.pluginCtx.setVerifiedWallet(verifyOutcome.wallet);
2797
- firePluginHook(deps.plugin, "onPaymentVerified", ctx.pluginCtx, {
2728
+ firePaymentVerified(ctx, {
2798
2729
  protocol: incomingStrategy.protocol,
2799
2730
  payer: verifyOutcome.wallet,
2800
2731
  amount: price,
@@ -2978,6 +2909,21 @@ async function createKvMppStore(kv, options) {
2978
2909
  });
2979
2910
  }
2980
2911
 
2912
+ // src/protocols/detect.ts
2913
+ function detectProtocol(request) {
2914
+ if (request.headers.get(HEADERS.X402_PAYMENT_SIGNATURE) ?? request.headers.get(HEADERS.X402_PAYMENT_LEGACY)) {
2915
+ return "x402";
2916
+ }
2917
+ const auth = request.headers.get(HEADERS.AUTHORIZATION);
2918
+ if (auth && auth.startsWith(AUTH_SCHEME.MPP_PAYMENT)) {
2919
+ return "mpp";
2920
+ }
2921
+ if (request.headers.get(HEADERS.SIWX)) {
2922
+ return "siwx";
2923
+ }
2924
+ return null;
2925
+ }
2926
+
2981
2927
  // src/protocols/mpp/siwx-mode.ts
2982
2928
  import { Credential as Credential2 } from "mppx";
2983
2929
  async function verifyMppSiwx(request, mppx) {
@@ -3017,11 +2963,7 @@ async function runSiwxOnlyFlow(ctx) {
3017
2963
  }
3018
2964
  if (mppSiwxResult.valid) {
3019
2965
  ctx.pluginCtx.setVerifiedWallet(mppSiwxResult.wallet);
3020
- firePluginHook(deps.plugin, "onAuthVerified", ctx.pluginCtx, {
3021
- authMode: "siwx",
3022
- wallet: mppSiwxResult.wallet,
3023
- route: routeEntry.key
3024
- });
2966
+ fireAuthVerified(ctx, { authMode: "siwx", wallet: mppSiwxResult.wallet });
3025
2967
  const authResponse = await runHandlerOnly(ctx, mppSiwxResult.wallet, void 0);
3026
2968
  if (authResponse.status < 400) {
3027
2969
  return mppSiwxResult.withReceipt(authResponse);
@@ -3043,11 +2985,7 @@ async function runSiwxOnlyFlow(ctx) {
3043
2985
  }
3044
2986
  const wallet = normalizeWalletAddress(siwx.wallet);
3045
2987
  ctx.pluginCtx.setVerifiedWallet(wallet);
3046
- firePluginHook(deps.plugin, "onAuthVerified", ctx.pluginCtx, {
3047
- authMode: "siwx",
3048
- wallet,
3049
- route: routeEntry.key
3050
- });
2988
+ fireAuthVerified(ctx, { authMode: "siwx", wallet });
3051
2989
  return runHandlerOnly(ctx, wallet, void 0);
3052
2990
  }
3053
2991
  async function buildSiwxChallenge(ctx) {
@@ -3140,7 +3078,7 @@ async function runUnprotectedFlow(ctx) {
3140
3078
  return runHandlerOnly(ctx, null, void 0);
3141
3079
  }
3142
3080
 
3143
- // src/orchestrate.ts
3081
+ // src/pipeline/orchestrate.ts
3144
3082
  function createRequestHandler(routeEntry, handler, deps) {
3145
3083
  return async (request) => {
3146
3084
  await deps.initPromise;
@@ -3915,7 +3853,7 @@ function toProtocolObject(protocol, mppInfo) {
3915
3853
  mpp: {
3916
3854
  method: mppInfo?.method ?? "tempo",
3917
3855
  intent: mppInfo?.intent ?? "charge",
3918
- currency: mppInfo?.currency ?? TEMPO_USDC_CURRENCY
3856
+ currency: mppInfo?.currency ?? TEMPO_USDC_ADDRESS
3919
3857
  }
3920
3858
  };
3921
3859
  }
@@ -3995,142 +3933,256 @@ function formatRouterConfigIssues(issues) {
3995
3933
  return issues.map((issue) => issue.message).join("\n");
3996
3934
  }
3997
3935
 
3998
- // src/config/validators/x402.ts
3999
- init_accepts();
3936
+ // src/config/schema.ts
3937
+ init_constants();
3938
+ import { z } from "zod";
4000
3939
 
4001
- // src/config/validators/shared.ts
4002
- init_evm();
4003
- init_solana();
4004
- init_accepts();
4005
- function isEvmAddress(value) {
4006
- return /^0x[a-fA-F0-9]{40}$/.test(value);
4007
- }
4008
- function isEvmPrivateKey(value) {
4009
- return /^0x[a-fA-F0-9]{64}$/.test(value);
4010
- }
4011
- function isSupportedX402Network(network) {
4012
- return isEvmNetwork(network) || isSolanaNetwork(network);
4013
- }
4014
- function findPlaceholderPayee(values) {
4015
- return values.find((value) => value !== void 0 && /^0x0{40}$/i.test(value)) ?? null;
4016
- }
4017
- function usesDefaultEvmFacilitator(config) {
4018
- return getConfiguredX402Networks(config).some(
4019
- (network) => typeof network === "string" && isEvmNetwork(network)
4020
- ) && config.x402?.facilitators?.evm === void 0;
3940
+ // src/config/utils.ts
3941
+ import { privateKeyToAccount } from "viem/accounts";
3942
+ var EVM_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
3943
+ var EVM_PRIVATE_KEY_RE = /^0x[a-fA-F0-9]{64}$/;
3944
+ var SOLANA_ADDRESS_RE = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
3945
+ var ZERO_EVM_ADDRESS_RE = /^0x0{40}$/i;
3946
+ function isUrl(value) {
3947
+ try {
3948
+ new URL(value);
3949
+ return true;
3950
+ } catch {
3951
+ return false;
3952
+ }
3953
+ }
3954
+ var isEvmAddress = (v) => EVM_ADDRESS_RE.test(v);
3955
+ var isEvmPrivateKey = (v) => EVM_PRIVATE_KEY_RE.test(v);
3956
+ var isPlaceholderEvm = (v) => ZERO_EVM_ADDRESS_RE.test(v);
3957
+ var isSolanaAddress = (v) => SOLANA_ADDRESS_RE.test(v);
3958
+ var isX402Network = (v) => v.startsWith("eip155:") || v.startsWith("solana:");
3959
+ var canonicalizeEvm = (addr) => addr.toLowerCase();
3960
+ function operatorAddressesCollide(opKey, fpKey) {
3961
+ if (!opKey || !fpKey || !isEvmPrivateKey(opKey) || !isEvmPrivateKey(fpKey)) return null;
3962
+ const op = privateKeyToAccount(opKey).address.toLowerCase();
3963
+ const fp = privateKeyToAccount(fpKey).address.toLowerCase();
3964
+ return op === fp ? op : null;
3965
+ }
3966
+ function trimAll(raw) {
3967
+ const out = {};
3968
+ for (const [k, v] of Object.entries(raw)) {
3969
+ if (typeof v !== "string") {
3970
+ out[k] = void 0;
3971
+ continue;
3972
+ }
3973
+ const trimmed = v.trim();
3974
+ out[k] = trimmed.length > 0 ? trimmed : void 0;
3975
+ }
3976
+ return out;
4021
3977
  }
4022
3978
 
4023
- // src/config/validators/x402.ts
4024
- var CHECKS = [
4025
- checkAcceptNetworkPresent,
4026
- checkAcceptNetworkSupported,
4027
- checkNonExactRequiresAsset,
4028
- checkDecimalsAreValid,
4029
- checkPayee,
4030
- checkPlaceholderPayeeAddress,
4031
- checkCdpKeys
4032
- ];
4033
- function validateX402Config(config, env, options) {
4034
- const accepts = getConfiguredX402Accepts(config);
4035
- if (accepts.length === 0) {
3979
+ // src/config/schema.ts
3980
+ function addIssue(ctx, params, message, path = []) {
3981
+ ctx.addIssue({ code: "custom", path, params, message });
3982
+ }
3983
+ var x402 = { protocol: "x402" };
3984
+ var mpp = { protocol: "mpp" };
3985
+ var envShape = {
3986
+ BASE_URL: z.string().refine(isUrl, {
3987
+ params: { code: "invalid_base_url" },
3988
+ message: "BASE_URL must be a valid URL \u2014 the public origin used as the 402 realm, OpenAPI server URL, and MPP memo prefix. Must match the public domain."
3989
+ }).optional(),
3990
+ EVM_PAYEE_ADDRESS: z.string().refine(isEvmAddress, {
3991
+ params: { code: "invalid_x402_payee", ...x402 },
3992
+ message: "EVM_PAYEE_ADDRESS must be a 0x-prefixed 20-byte EVM address \u2014 the wallet that receives x402 and MPP payments."
3993
+ }).refine((v) => !isPlaceholderEvm(v), {
3994
+ params: { code: "placeholder_payee", ...x402 },
3995
+ message: "EVM_PAYEE_ADDRESS is the zero address (0x000\u2026000) \u2014 payments to this address are unrecoverable. Set it to a wallet you control."
3996
+ }).optional(),
3997
+ CDP_API_KEY_ID: z.string().optional(),
3998
+ CDP_API_KEY_SECRET: z.string().optional(),
3999
+ SOLANA_PAYEE_ADDRESS: z.string().refine(isSolanaAddress, {
4000
+ params: { code: "invalid_solana_payee", ...x402 },
4001
+ message: "SOLANA_PAYEE_ADDRESS must be a base58 Solana address (32\u201344 chars). When set, the router also accepts Solana payments."
4002
+ }).optional(),
4003
+ SOLANA_FACILITATOR_URL: z.string().refine(isUrl, {
4004
+ params: { code: "invalid_solana_facilitator_url", ...x402 },
4005
+ message: "SOLANA_FACILITATOR_URL must be a valid URL \u2014 override for the Solana x402 facilitator. Defaults to DEFAULT_SOLANA_FACILITATOR_URL."
4006
+ }).optional(),
4007
+ MPP_SECRET_KEY: z.string().optional(),
4008
+ MPP_CURRENCY: z.string().refine(isEvmAddress, {
4009
+ params: { code: "invalid_mpp_currency", ...mpp },
4010
+ message: "MPP_CURRENCY must be a 0x-prefixed 20-byte Tempo currency address \u2014 the token contract MPP charges in. Use TEMPO_USDC_ADDRESS for Tempo USDC."
4011
+ }).optional(),
4012
+ TEMPO_RPC_URL: z.string().refine(isUrl, {
4013
+ params: { code: "invalid_mpp_rpc_url", ...mpp },
4014
+ message: "TEMPO_RPC_URL must be a valid URL \u2014 authenticated Tempo JSON-RPC endpoint. Public rpc.tempo.xyz returns 401."
4015
+ }).optional(),
4016
+ MPP_OPERATOR_KEY: z.string().refine(isEvmPrivateKey, {
4017
+ params: { code: "invalid_mpp_operator_key", ...mpp },
4018
+ message: "MPP_OPERATOR_KEY must be a 0x-prefixed 32-byte EVM private key \u2014 signs server-side close/settle; presence enables MPP session mode."
4019
+ }).optional(),
4020
+ MPP_FEE_PAYER_KEY: z.string().refine(isEvmPrivateKey, {
4021
+ params: { code: "invalid_mpp_fee_payer_key", ...mpp },
4022
+ message: "MPP_FEE_PAYER_KEY must be a 0x-prefixed 32-byte EVM private key \u2014 sponsors client gas for channel open/topUp. Must resolve to a different address than MPP_OPERATOR_KEY."
4023
+ }).optional(),
4024
+ KV_REST_API_URL: z.string().optional(),
4025
+ KV_REST_API_TOKEN: z.string().optional(),
4026
+ NODE_ENV: z.string().optional()
4027
+ };
4028
+ var ENV_KEYS = Object.keys(envShape);
4029
+ var EnvInputSchema = z.object(envShape).passthrough().superRefine((env, ctx) => {
4030
+ if (env.BASE_URL === void 0) {
4031
+ addIssue(
4032
+ ctx,
4033
+ { code: "missing_base_url" },
4034
+ "BASE_URL is required \u2014 the public origin used as the 402 realm, OpenAPI server URL, and MPP memo prefix. Set it to your production domain.",
4035
+ ["BASE_URL"]
4036
+ );
4037
+ }
4038
+ if (env.EVM_PAYEE_ADDRESS === void 0) {
4039
+ addIssue(
4040
+ ctx,
4041
+ { code: "missing_x402_payee", ...x402 },
4042
+ "EVM_PAYEE_ADDRESS is required \u2014 the EVM address that receives x402 and MPP payments.",
4043
+ ["EVM_PAYEE_ADDRESS"]
4044
+ );
4045
+ }
4046
+ if (env.MPP_SECRET_KEY) {
4047
+ if (env.MPP_CURRENCY === void 0) {
4048
+ addIssue(
4049
+ ctx,
4050
+ { code: "missing_mpp_currency", ...mpp },
4051
+ "MPP_CURRENCY is required when MPP is enabled \u2014 the Tempo currency address MPP charges in. Use TEMPO_USDC_ADDRESS for Tempo USDC.",
4052
+ ["MPP_CURRENCY"]
4053
+ );
4054
+ }
4055
+ if (env.TEMPO_RPC_URL === void 0) {
4056
+ addIssue(
4057
+ ctx,
4058
+ { code: "missing_mpp_rpc_url", ...mpp },
4059
+ "TEMPO_RPC_URL is required when MPP is enabled \u2014 authenticated Tempo JSON-RPC endpoint. Public rpc.tempo.xyz returns 401.",
4060
+ ["TEMPO_RPC_URL"]
4061
+ );
4062
+ }
4063
+ }
4064
+ const collision = operatorAddressesCollide(env.MPP_OPERATOR_KEY, env.MPP_FEE_PAYER_KEY);
4065
+ if (collision) {
4066
+ addIssue(
4067
+ ctx,
4068
+ { code: "mpp_operator_equals_fee_payer", ...mpp },
4069
+ `MPP_OPERATOR_KEY and MPP_FEE_PAYER_KEY resolve to the same address (${collision}). Tempo rejects fee-delegated txs with sender === feePayer. Use two distinct wallets, or unset MPP_FEE_PAYER_KEY to let clients pay their own gas.`,
4070
+ ["MPP_FEE_PAYER_KEY"]
4071
+ );
4072
+ }
4073
+ });
4074
+ function collectKvWarnings(env, kvStoreOptionProvided) {
4075
+ if (kvStoreOptionProvided) return [];
4076
+ const warn = (code, message) => ({
4077
+ code,
4078
+ severity: "warning",
4079
+ message
4080
+ });
4081
+ if (env.KV_REST_API_URL && !env.KV_REST_API_TOKEN) {
4036
4082
  return [
4037
- {
4038
- code: "missing_x402_accepts",
4039
- protocol: "x402",
4040
- message: "x402 requires at least one accept configuration."
4041
- }
4083
+ warn(
4084
+ "kv_url_without_token",
4085
+ "KV_REST_API_URL is set but KV_REST_API_TOKEN is missing \u2014 falling back to in-memory KV (unsafe in serverless production)."
4086
+ )
4042
4087
  ];
4043
4088
  }
4044
- const args = { config, accepts, env, options };
4045
- return CHECKS.map((check) => check(args)).filter(
4046
- (issue) => issue !== null
4047
- );
4048
- }
4049
- function checkAcceptNetworkPresent({ accepts }) {
4050
- return accepts.some((accept) => !accept.network) ? { code: "missing_x402_network", protocol: "x402", message: "x402 accepts require a network." } : null;
4051
- }
4052
- function checkAcceptNetworkSupported({ accepts }) {
4053
- const unsupported = accepts.find(
4054
- (accept) => accept.network && !isSupportedX402Network(accept.network)
4055
- );
4056
- if (!unsupported) return null;
4057
- return {
4058
- code: "unsupported_x402_network",
4059
- protocol: "x402",
4060
- message: `unsupported x402 network '${unsupported.network}'. Use eip155:* or solana:*.`
4061
- };
4062
- }
4063
- function checkNonExactRequiresAsset({ accepts }) {
4064
- return accepts.some((accept) => (accept.scheme ?? "exact") !== "exact" && !accept.asset) ? {
4065
- code: "missing_x402_asset",
4066
- protocol: "x402",
4067
- message: "non-exact x402 accepts require an asset."
4068
- } : null;
4089
+ if (env.KV_REST_API_TOKEN && !env.KV_REST_API_URL) {
4090
+ return [
4091
+ warn(
4092
+ "kv_token_without_url",
4093
+ "KV_REST_API_TOKEN is set but KV_REST_API_URL is missing \u2014 falling back to in-memory KV (unsafe in serverless production)."
4094
+ )
4095
+ ];
4096
+ }
4097
+ if (env.KV_REST_API_URL && env.KV_REST_API_TOKEN && !isUrl(env.KV_REST_API_URL)) {
4098
+ return [
4099
+ warn(
4100
+ "invalid_kv_url",
4101
+ `KV_REST_API_URL is not a valid URL \u2014 KV calls will fail at request time. Got: ${env.KV_REST_API_URL}`
4102
+ )
4103
+ ];
4104
+ }
4105
+ if (!env.KV_REST_API_URL && !env.KV_REST_API_TOKEN && env.NODE_ENV === "production") {
4106
+ return [
4107
+ warn(
4108
+ "missing_kv_in_production",
4109
+ "No KV_REST_API_URL/KV_REST_API_TOKEN set in production \u2014 using the in-memory KV store. SIWX nonce, SIWX entitlement, and MPP replay state will be lost across instances. Configure Upstash/Vercel KV or pass a custom kvStore."
4110
+ )
4111
+ ];
4112
+ }
4113
+ return [];
4069
4114
  }
4070
- function checkDecimalsAreValid({ accepts }) {
4071
- const invalid = accepts.find(
4072
- (accept) => accept.decimals !== void 0 && (!Number.isInteger(accept.decimals) || accept.decimals < 0)
4073
- );
4074
- if (!invalid) return null;
4075
- return {
4076
- code: "invalid_x402_decimals",
4077
- protocol: "x402",
4078
- message: "x402 accept decimals must be a non-negative integer."
4079
- };
4115
+ function getConfiguredX402Accepts2(config) {
4116
+ if (config.x402?.accepts?.length) return [...config.x402.accepts];
4117
+ return [
4118
+ {
4119
+ scheme: "exact",
4120
+ network: config.network ?? BASE_MAINNET_NETWORK,
4121
+ payTo: config.payeeAddress
4122
+ }
4123
+ ];
4080
4124
  }
4081
- function checkPayee({ config, accepts }) {
4082
- if (config.payeeAddress) return null;
4083
- return accepts.some((accept) => !accept.payTo) ? {
4084
- code: "missing_x402_payee",
4085
- protocol: "x402",
4086
- message: "x402 requires payeeAddress in router config or payTo on every x402 accept."
4087
- } : null;
4088
- }
4089
- function checkPlaceholderPayeeAddress({
4090
- config,
4091
- accepts
4092
- }) {
4093
- const placeholder = findPlaceholderPayee([
4125
+ function validateX402Config(config, env, options) {
4126
+ const accepts = getConfiguredX402Accepts2(config);
4127
+ const issues = [];
4128
+ const push = (code, message) => issues.push({ code, protocol: "x402", message });
4129
+ if (accepts.length === 0) {
4130
+ push("missing_x402_accepts", "x402 requires at least one accept configuration.");
4131
+ return issues;
4132
+ }
4133
+ if (accepts.some((a) => !a.network)) {
4134
+ push("missing_x402_network", "x402 accepts require a network.");
4135
+ }
4136
+ const unsupported = accepts.find((a) => a.network && !isX402Network(a.network));
4137
+ if (unsupported) {
4138
+ push(
4139
+ "unsupported_x402_network",
4140
+ `unsupported x402 network '${unsupported.network}'. Use eip155:* or solana:*.`
4141
+ );
4142
+ }
4143
+ if (accepts.some((a) => (a.scheme ?? "exact") !== "exact" && !a.asset)) {
4144
+ push("missing_x402_asset", "non-exact x402 accepts require an asset.");
4145
+ }
4146
+ if (accepts.some(
4147
+ (a) => a.decimals !== void 0 && (!Number.isInteger(a.decimals) || a.decimals < 0)
4148
+ )) {
4149
+ push("invalid_x402_decimals", "x402 accept decimals must be a non-negative integer.");
4150
+ }
4151
+ if (!config.payeeAddress && accepts.some((a) => !a.payTo)) {
4152
+ push(
4153
+ "missing_x402_payee",
4154
+ "x402 requires payeeAddress in router config or payTo on every x402 accept."
4155
+ );
4156
+ }
4157
+ const placeholder = [
4094
4158
  config.payeeAddress,
4095
- ...accepts.map((accept) => typeof accept.payTo === "string" ? accept.payTo : void 0)
4096
- ]);
4097
- if (!placeholder) return null;
4098
- return {
4099
- code: "placeholder_payee",
4100
- protocol: "x402",
4101
- message: `x402 payee '${placeholder}' is a placeholder address and cannot receive payments.`
4102
- };
4103
- }
4104
- function checkCdpKeys({ config, env, options }) {
4105
- if (options.requireCdpKeys === false) return null;
4106
- if (!usesDefaultEvmFacilitator(config)) return null;
4107
- const missing = [
4108
- env.CDP_API_KEY_ID ? null : "CDP_API_KEY_ID",
4109
- env.CDP_API_KEY_SECRET ? null : "CDP_API_KEY_SECRET"
4110
- ].filter(Boolean);
4111
- if (missing.length === 0) return null;
4112
- return {
4113
- code: "missing_cdp_keys",
4114
- protocol: "x402",
4115
- message: `default EVM x402 facilitator requires ${missing.join(" and ")}.`
4116
- };
4159
+ ...accepts.map((a) => typeof a.payTo === "string" ? a.payTo : void 0)
4160
+ ].find((v) => v !== void 0 && isPlaceholderEvm(v));
4161
+ if (placeholder) {
4162
+ push(
4163
+ "placeholder_payee",
4164
+ `x402 payee '${placeholder}' is a placeholder address and cannot receive payments.`
4165
+ );
4166
+ }
4167
+ if (options.requireCdpKeys !== false) {
4168
+ const hasEvm = accepts.some(
4169
+ (a) => typeof a.network === "string" && a.network.startsWith("eip155:")
4170
+ );
4171
+ if (hasEvm) {
4172
+ const missing = ["CDP_API_KEY_ID", "CDP_API_KEY_SECRET"].filter((k) => !env[k]);
4173
+ if (missing.length > 0) {
4174
+ push(
4175
+ "missing_cdp_keys",
4176
+ `x402 EVM facilitator (Coinbase) requires ${missing.join(" and ")}.`
4177
+ );
4178
+ }
4179
+ }
4180
+ }
4181
+ return issues;
4117
4182
  }
4118
-
4119
- // src/config/validators/mpp.ts
4120
- import { privateKeyToAccount } from "viem/accounts";
4121
- var CHECKS2 = [
4122
- checkSecretKey,
4123
- checkCurrency,
4124
- checkRecipient,
4125
- checkPlaceholderRecipient,
4126
- checkRpcUrl,
4127
- checkFeePayerKey,
4128
- checkOperatorKey,
4129
- checkOperatorMatchesFeePayer
4130
- ];
4131
- function validateMppConfig(config, env) {
4132
- const mpp = config.mpp;
4133
- if (!mpp) {
4183
+ function validateMppConfig(config) {
4184
+ const m = config.mpp;
4185
+ if (!m) {
4134
4186
  return [
4135
4187
  {
4136
4188
  code: "missing_mpp_config",
@@ -4139,109 +4191,184 @@ function validateMppConfig(config, env) {
4139
4191
  }
4140
4192
  ];
4141
4193
  }
4142
- const args = { config, mpp, env };
4143
- return CHECKS2.map((check) => check(args)).filter(
4144
- (issue) => issue !== null
4194
+ const issues = [];
4195
+ const push = (code, message) => issues.push({ code, protocol: "mpp", message });
4196
+ if (!m.secretKey) {
4197
+ push(
4198
+ "missing_mpp_secret_key",
4199
+ "MPP requires secretKey. Set MPP_SECRET_KEY or pass mpp.secretKey."
4200
+ );
4201
+ }
4202
+ if (!m.currency) {
4203
+ push("missing_mpp_currency", "MPP requires currency. Set MPP_CURRENCY or pass mpp.currency.");
4204
+ } else if (!isEvmAddress(m.currency)) {
4205
+ push(
4206
+ "invalid_mpp_currency",
4207
+ "MPP currency must be a 0x-prefixed 20-byte Tempo currency address. Use TEMPO_USDC_ADDRESS for Tempo USDC."
4208
+ );
4209
+ }
4210
+ const recipient = m.recipient ?? config.payeeAddress;
4211
+ if (!recipient) {
4212
+ push(
4213
+ "missing_mpp_recipient",
4214
+ "MPP requires a recipient address. Set mpp.recipient or payeeAddress in your router config."
4215
+ );
4216
+ } else if (!isEvmAddress(recipient)) {
4217
+ push(
4218
+ "invalid_mpp_recipient",
4219
+ "MPP recipient must be a 0x-prefixed EVM address. Solana recipients require x402."
4220
+ );
4221
+ }
4222
+ const placeholder = [m.recipient, config.payeeAddress].find(
4223
+ (v) => typeof v === "string" && isPlaceholderEvm(v)
4145
4224
  );
4146
- }
4147
- function checkSecretKey({ mpp }) {
4148
- if (mpp.secretKey) return null;
4149
- return {
4150
- code: "missing_mpp_secret_key",
4151
- protocol: "mpp",
4152
- message: "MPP requires secretKey. Set MPP_SECRET_KEY or pass mpp.secretKey."
4153
- };
4154
- }
4155
- function checkCurrency({ mpp }) {
4156
- if (!mpp.currency) {
4157
- return {
4158
- code: "missing_mpp_currency",
4159
- protocol: "mpp",
4160
- message: "MPP requires currency. Set MPP_CURRENCY or pass mpp.currency."
4161
- };
4225
+ if (placeholder) {
4226
+ push(
4227
+ "placeholder_payee",
4228
+ `MPP recipient '${placeholder}' is a placeholder address and cannot receive payments.`
4229
+ );
4162
4230
  }
4163
- if (!isEvmAddress(mpp.currency)) {
4164
- return {
4165
- code: "invalid_mpp_currency",
4166
- protocol: "mpp",
4167
- message: "MPP currency must be a 0x-prefixed 20-byte Tempo currency address. Use TEMPO_USDC_CURRENCY for Tempo USDC."
4168
- };
4231
+ if (!m.rpcUrl) {
4232
+ push(
4233
+ "missing_mpp_rpc_url",
4234
+ "MPP requires an authenticated Tempo RPC URL. Set TEMPO_RPC_URL env var or pass rpcUrl in the mpp config object."
4235
+ );
4169
4236
  }
4170
- return null;
4237
+ if (m.feePayerKey && !isEvmPrivateKey(m.feePayerKey)) {
4238
+ push(
4239
+ "invalid_mpp_fee_payer_key",
4240
+ "MPP feePayerKey must be a 0x-prefixed 32-byte EVM private key."
4241
+ );
4242
+ }
4243
+ if (m.operatorKey && !isEvmPrivateKey(m.operatorKey)) {
4244
+ push(
4245
+ "invalid_mpp_operator_key",
4246
+ "MPP operatorKey must be a 0x-prefixed 32-byte EVM private key."
4247
+ );
4248
+ }
4249
+ const collision = operatorAddressesCollide(m.operatorKey, m.feePayerKey);
4250
+ if (collision) {
4251
+ push(
4252
+ "mpp_operator_equals_fee_payer",
4253
+ `MPP operatorKey and feePayerKey resolve to the same address (${collision}). Tempo rejects fee-delegated txs with sender === feePayer, so channel close/settle would fail at runtime. Either use two distinct wallets, or omit feePayerKey to disable gas sponsorship (clients then pay their own gas).`
4254
+ );
4255
+ }
4256
+ return issues;
4171
4257
  }
4172
- function checkRecipient({ config, mpp }) {
4173
- const recipient = mpp.recipient ?? config.payeeAddress;
4174
- if (!recipient) {
4258
+ function translateZodIssues(error) {
4259
+ return error.issues.map((issue) => {
4260
+ const params = issue.params;
4261
+ if (!params?.code) {
4262
+ throw new Error(
4263
+ `[router] schema issue missing params.code (path=${issue.path.join(".")}, message=${issue.message}). Every refinement / addIssue call must set params.code.`
4264
+ );
4265
+ }
4175
4266
  return {
4176
- code: "missing_mpp_recipient",
4177
- protocol: "mpp",
4178
- message: "MPP requires a recipient address. Set mpp.recipient or payeeAddress in your router config."
4267
+ code: params.code,
4268
+ message: issue.message,
4269
+ ...params.protocol ? { protocol: params.protocol } : {},
4270
+ ...params.severity ? { severity: params.severity } : {}
4179
4271
  };
4272
+ });
4273
+ }
4274
+ function routerConfigFromEnv(options) {
4275
+ const rawEnv = options.env ?? process.env;
4276
+ const env = trimAll(rawEnv);
4277
+ const optionIssues = [];
4278
+ if (!options.title?.trim()) {
4279
+ optionIssues.push({
4280
+ code: "missing_discovery_title",
4281
+ message: "discovery `title` is required. Pass a short product name."
4282
+ });
4180
4283
  }
4181
- if (!isEvmAddress(recipient)) {
4182
- return {
4183
- code: "invalid_mpp_recipient",
4184
- protocol: "mpp",
4185
- message: "MPP recipient must be a 0x-prefixed EVM address. Solana recipients require x402."
4186
- };
4284
+ if (!options.description?.trim()) {
4285
+ optionIssues.push({
4286
+ code: "missing_discovery_description",
4287
+ message: "discovery `description` is required. One sentence is enough."
4288
+ });
4187
4289
  }
4188
- return null;
4189
- }
4190
- function checkPlaceholderRecipient({ config, mpp }) {
4191
- const placeholder = findPlaceholderPayee([mpp.recipient, config.payeeAddress]);
4192
- if (!placeholder) return null;
4193
- return {
4194
- code: "placeholder_payee",
4195
- protocol: "mpp",
4196
- message: `MPP recipient '${placeholder}' is a placeholder address and cannot receive payments.`
4197
- };
4198
- }
4199
- function checkRpcUrl({ mpp, env }) {
4200
- if (mpp.rpcUrl ?? env.TEMPO_RPC_URL) return null;
4201
- return {
4202
- code: "missing_mpp_rpc_url",
4203
- protocol: "mpp",
4204
- message: "MPP requires an authenticated Tempo RPC URL. Set TEMPO_RPC_URL env var or pass rpcUrl in the mpp config object."
4205
- };
4206
- }
4207
- function checkFeePayerKey({ mpp }) {
4208
- if (!mpp.feePayerKey || isEvmPrivateKey(mpp.feePayerKey)) return null;
4209
- return {
4210
- code: "invalid_mpp_fee_payer_key",
4211
- protocol: "mpp",
4212
- message: "MPP feePayerKey must be a 0x-prefixed 32-byte EVM private key."
4213
- };
4214
- }
4215
- function checkOperatorKey({ mpp }) {
4216
- if (!mpp.operatorKey || isEvmPrivateKey(mpp.operatorKey)) return null;
4217
- return {
4218
- code: "invalid_mpp_operator_key",
4219
- protocol: "mpp",
4220
- message: "MPP operatorKey must be a 0x-prefixed 32-byte EVM private key."
4221
- };
4222
- }
4223
- function checkOperatorMatchesFeePayer({ mpp }) {
4224
- if (!mpp.operatorKey || !mpp.feePayerKey) return null;
4225
- if (!isEvmPrivateKey(mpp.operatorKey) || !isEvmPrivateKey(mpp.feePayerKey)) return null;
4226
- const opAddr = privateKeyToAccount(mpp.operatorKey).address.toLowerCase();
4227
- const fpAddr = privateKeyToAccount(mpp.feePayerKey).address.toLowerCase();
4228
- if (opAddr !== fpAddr) return null;
4290
+ if (options.guidance === void 0) {
4291
+ optionIssues.push({
4292
+ code: "missing_discovery_guidance",
4293
+ message: "discovery `guidance` is required. Provide an empty string to opt out of `/llms.txt`."
4294
+ });
4295
+ }
4296
+ if (options.serverUrl !== void 0 && !isUrl(options.serverUrl)) {
4297
+ optionIssues.push({
4298
+ code: "invalid_server_url",
4299
+ message: `discovery \`serverUrl\` must be a valid URL. Got: ${options.serverUrl}`
4300
+ });
4301
+ }
4302
+ const parsed = EnvInputSchema.safeParse(env);
4303
+ const envIssues = parsed.success ? [] : translateZodIssues(parsed.error);
4304
+ const issues = [...envIssues, ...optionIssues];
4305
+ if (issues.length > 0) throw new RouterConfigError(issues);
4306
+ for (const warning of collectKvWarnings(env, options.kvStore !== void 0)) {
4307
+ console.warn(`[router] ${warning.message}`);
4308
+ }
4309
+ const payeeAddress = canonicalizeEvm(env.EVM_PAYEE_ADDRESS);
4310
+ const accepts = [
4311
+ { scheme: "exact", network: BASE_MAINNET_NETWORK, payTo: payeeAddress },
4312
+ {
4313
+ scheme: "upto",
4314
+ network: BASE_MAINNET_NETWORK,
4315
+ payTo: payeeAddress,
4316
+ asset: BASE_USDC_ADDRESS,
4317
+ decimals: BASE_USDC_DECIMALS
4318
+ }
4319
+ ];
4320
+ if (env.SOLANA_PAYEE_ADDRESS) {
4321
+ accepts.push({
4322
+ scheme: "exact",
4323
+ network: SOLANA_MAINNET_NETWORK,
4324
+ payTo: env.SOLANA_PAYEE_ADDRESS
4325
+ });
4326
+ }
4327
+ const configuredSolanaFacilitator = options.x402Facilitators?.solana;
4328
+ const solanaFacilitator = typeof configuredSolanaFacilitator === "string" ? configuredSolanaFacilitator : configuredSolanaFacilitator ?? env.SOLANA_FACILITATOR_URL ?? DEFAULT_SOLANA_FACILITATOR_URL;
4329
+ const mppEnabled = options.protocols?.includes("mpp") ?? Boolean(env.MPP_SECRET_KEY);
4330
+ const protocols = options.protocols ? [...options.protocols] : mppEnabled ? ["x402", "mpp"] : ["x402"];
4331
+ const mppConfig = mppEnabled ? {
4332
+ secretKey: env.MPP_SECRET_KEY,
4333
+ currency: canonicalizeEvm(env.MPP_CURRENCY),
4334
+ rpcUrl: env.TEMPO_RPC_URL,
4335
+ recipient: payeeAddress,
4336
+ ...env.MPP_FEE_PAYER_KEY ? { feePayerKey: env.MPP_FEE_PAYER_KEY } : {},
4337
+ ...env.MPP_OPERATOR_KEY ? { operatorKey: env.MPP_OPERATOR_KEY, session: {} } : {}
4338
+ } : void 0;
4229
4339
  return {
4230
- code: "mpp_operator_equals_fee_payer",
4231
- protocol: "mpp",
4232
- message: `MPP operatorKey and feePayerKey resolve to the same address (${opAddr}). Tempo rejects fee-delegated txs with sender === feePayer, so channel close/settle would fail at runtime. Either use two distinct wallets, or omit feePayerKey to disable gas sponsorship (clients then pay their own gas).`
4340
+ payeeAddress,
4341
+ baseUrl: env.BASE_URL,
4342
+ network: BASE_MAINNET_NETWORK,
4343
+ protocols,
4344
+ x402: {
4345
+ accepts,
4346
+ facilitators: {
4347
+ ...options.x402Facilitators,
4348
+ solana: solanaFacilitator
4349
+ }
4350
+ },
4351
+ ...mppConfig ? { mpp: mppConfig } : {},
4352
+ discovery: {
4353
+ title: options.title,
4354
+ version: options.version ?? "1.0.0",
4355
+ description: options.description,
4356
+ guidance: options.guidance,
4357
+ ...options.contact ? { contact: options.contact } : {},
4358
+ ...options.ownershipProofs ? { ownershipProofs: options.ownershipProofs } : {},
4359
+ ...options.methodHints ? { methodHints: options.methodHints } : {},
4360
+ ...options.serverUrl ? { serverUrl: options.serverUrl } : {}
4361
+ },
4362
+ ...options.prices ? { prices: options.prices } : {},
4363
+ ...options.plugin ? { plugin: options.plugin } : {},
4364
+ ...options.kvStore ? { kvStore: options.kvStore } : {},
4365
+ strictRoutes: options.strictRoutes ?? false
4233
4366
  };
4234
4367
  }
4235
-
4236
- // src/config/validate.ts
4237
- function validateRouterConfig(config, options = {}) {
4238
- const issues = getRouterConfigIssues(config, options);
4239
- if (issues.length > 0) throw new RouterConfigError(issues);
4240
- }
4241
4368
  function getRouterConfigIssues(config, options = {}) {
4242
- const env = options.env ?? process.env;
4243
- const issues = [];
4369
+ const env = options.env ?? {};
4244
4370
  const protocols = config.protocols ?? ["x402"];
4371
+ const issues = [];
4245
4372
  if (!config.baseUrl) {
4246
4373
  issues.push({
4247
4374
  code: "missing_base_url",
@@ -4254,83 +4381,16 @@ function getRouterConfigIssues(config, options = {}) {
4254
4381
  message: "RouterConfig.protocols cannot be empty. Omit the field to use default ['x402'] or specify protocols explicitly."
4255
4382
  });
4256
4383
  }
4257
- if (protocols.includes("x402")) {
4258
- issues.push(...validateX402Config(config, env, options));
4259
- }
4260
- if (protocols.includes("mpp")) {
4261
- issues.push(...validateMppConfig(config, env));
4262
- }
4384
+ if (protocols.includes("x402")) issues.push(...validateX402Config(config, env, options));
4385
+ if (protocols.includes("mpp")) issues.push(...validateMppConfig(config));
4263
4386
  return issues;
4264
4387
  }
4265
4388
 
4266
- // src/config/env.ts
4267
- init_constants();
4268
- function mppFromEnv(env, options = {}) {
4269
- const secretKey = env.MPP_SECRET_KEY;
4270
- const currency = env.MPP_CURRENCY;
4271
- const rpcUrl = env.TEMPO_RPC_URL;
4272
- const feePayerKey = options.feePayerKey ?? env.MPP_FEE_PAYER_KEY;
4273
- const feePayerKeySource = options.feePayerKey !== void 0 ? "feePayerKey" : "MPP_FEE_PAYER_KEY";
4274
- const hasAnyMppEnv = Boolean(secretKey || currency || rpcUrl || options.require);
4275
- if (!hasAnyMppEnv) return void 0;
4276
- const missing = [
4277
- secretKey ? null : "MPP_SECRET_KEY",
4278
- currency ? null : "MPP_CURRENCY",
4279
- rpcUrl ? null : "TEMPO_RPC_URL"
4280
- ].filter(Boolean);
4281
- if (missing.length > 0) {
4282
- throw new Error(`MPP env is incomplete. Missing: ${missing.join(", ")}`);
4283
- }
4284
- if (!isEvmAddress(currency)) {
4285
- throw new Error("MPP_CURRENCY must be a 0x-prefixed 20-byte Tempo currency address");
4286
- }
4287
- if (options.recipient && !isEvmAddress(options.recipient)) {
4288
- throw new Error("MPP recipient must be a 0x-prefixed EVM address");
4289
- }
4290
- if (feePayerKey && !isEvmPrivateKey(feePayerKey)) {
4291
- throw new Error(`${feePayerKeySource} must be a 0x-prefixed 32-byte EVM private key`);
4292
- }
4293
- return {
4294
- secretKey,
4295
- currency,
4296
- rpcUrl,
4297
- ...options.recipient ? { recipient: options.recipient } : {},
4298
- ...feePayerKey ? { feePayerKey } : {}
4299
- };
4300
- }
4301
- function x402AcceptsFromEnv(env, options = {}) {
4302
- const payeeEnv = options.payeeEnv ?? "X402_WALLET_ADDRESS";
4303
- const solanaPayeeEnv = options.solanaPayeeEnv ?? "SOLANA_PAYEE_ADDRESS";
4304
- const payeeAddress = options.payeeAddress ?? env[payeeEnv];
4305
- if (!payeeAddress) {
4306
- throw new Error(`${payeeEnv} is required to build x402 accepts`);
4307
- }
4308
- const accepts = [
4309
- {
4310
- scheme: "exact",
4311
- network: options.network ?? BASE_NETWORK,
4312
- payTo: payeeAddress
4313
- }
4314
- ];
4315
- const solanaPayeeAddress = options.solanaPayeeAddress ?? env[solanaPayeeEnv];
4316
- if (solanaPayeeAddress) {
4317
- accepts.push({
4318
- scheme: "exact",
4319
- network: SOLANA_MAINNET_NETWORK,
4320
- payTo: solanaPayeeAddress
4321
- });
4322
- }
4323
- return accepts;
4324
- }
4325
- function paidOptionsForProtocols(protocols) {
4326
- return { protocols: [...protocols] };
4327
- }
4328
-
4329
4389
  // src/init/x402.ts
4330
4390
  async function initX402(config, configError) {
4331
4391
  if (configError) return { initError: configError };
4332
4392
  try {
4333
- const { createX402Server: createX402Server2 } = await Promise.resolve().then(() => (init_server(), server_exports));
4393
+ const { createX402Server: createX402Server2 } = await Promise.resolve().then(() => (init_x402_server(), x402_server_exports));
4334
4394
  const result = await createX402Server2(config);
4335
4395
  await result.initPromise;
4336
4396
  return {
@@ -4342,7 +4402,7 @@ async function initX402(config, configError) {
4342
4402
  }
4343
4403
  }
4344
4404
 
4345
- // src/mppx-init.ts
4405
+ // src/init/mppx.ts
4346
4406
  function getMppxRequestContext(args) {
4347
4407
  const {
4348
4408
  Mppx,
@@ -4464,9 +4524,10 @@ function createRouter(config) {
4464
4524
  const kvStore = resolveKvStore(config.kvStore);
4465
4525
  const nonceStore = kvStore ? createKvNonceStore(kvStore) : new MemoryNonceStore();
4466
4526
  const entitlementStore = kvStore ? createKvEntitlementStore(kvStore) : new MemoryEntitlementStore();
4467
- const network = config.network ?? BASE_NETWORK;
4527
+ const network = config.network ?? BASE_MAINNET_NETWORK;
4468
4528
  const x402Accepts = getConfiguredX402Accepts(config);
4469
4529
  const configIssues = getRouterConfigIssues(config, {
4530
+ env: process.env,
4470
4531
  requireCdpKeys: process.env.NODE_ENV === "production"
4471
4532
  });
4472
4533
  const baseUrlIssue = configIssues.find((issue) => issue.code === "missing_base_url");
@@ -4589,29 +4650,21 @@ function normalizePath(path) {
4589
4650
  normalized = normalized.replace(/^api\/+/, "");
4590
4651
  return normalized.replace(/\/+$/, "");
4591
4652
  }
4653
+ function createRouterFromEnv(options) {
4654
+ return createRouter(routerConfigFromEnv(options));
4655
+ }
4592
4656
  export {
4593
- BASE_NETWORK,
4657
+ BASE_MAINNET_NETWORK,
4658
+ BASE_USDC_ADDRESS,
4659
+ BASE_USDC_DECIMALS,
4660
+ DEFAULT_SOLANA_FACILITATOR_URL,
4594
4661
  HttpError,
4595
- MemoryEntitlementStore,
4596
- MemoryNonceStore,
4597
- RouteBuilder,
4598
- RouteRegistry,
4599
4662
  RouterConfigError,
4600
- SIWX_CHALLENGE_EXPIRY_MS,
4601
- SIWX_ERROR_MESSAGES,
4602
4663
  SOLANA_MAINNET_NETWORK,
4603
- TEMPO_USDC_CURRENCY,
4664
+ TEMPO_USDC_ADDRESS,
4665
+ TEMPO_USDC_DECIMALS,
4604
4666
  ZERO_EVM_ADDRESS,
4605
- consolePlugin,
4606
- createKvEntitlementStore,
4607
- createKvMppStore,
4608
- createKvNonceStore,
4609
4667
  createRouter,
4610
- formatRouterConfigIssues,
4611
- getRouterConfigIssues,
4612
- mppFromEnv,
4613
- paidOptionsForProtocols,
4614
- validateRouterConfig,
4615
- withPrefix,
4616
- x402AcceptsFromEnv
4668
+ createRouterFromEnv,
4669
+ routerConfigFromEnv
4617
4670
  };