@agentcash/router 1.4.1 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -166,6 +166,18 @@ var init_x402_facilitators = __esm({
166
166
  }
167
167
  });
168
168
 
169
+ // src/constants.ts
170
+ var BASE_NETWORK, SOLANA_MAINNET_NETWORK, TEMPO_USDC_CURRENCY, ZERO_EVM_ADDRESS;
171
+ var init_constants = __esm({
172
+ "src/constants.ts"() {
173
+ "use strict";
174
+ BASE_NETWORK = "eip155:8453";
175
+ SOLANA_MAINNET_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
176
+ TEMPO_USDC_CURRENCY = "0x20c000000000000000000000b9537d11c60e8b50";
177
+ ZERO_EVM_ADDRESS = "0x0000000000000000000000000000000000000000";
178
+ }
179
+ });
180
+
169
181
  // src/x402-config.ts
170
182
  async function resolvePayToValue(payTo, request, fallback, body) {
171
183
  if (!payTo) return fallback;
@@ -179,7 +191,7 @@ function getConfiguredX402Accepts(config) {
179
191
  return [
180
192
  {
181
193
  scheme: "exact",
182
- network: config.network ?? "eip155:8453",
194
+ network: config.network ?? BASE_NETWORK,
183
195
  payTo: config.payeeAddress
184
196
  }
185
197
  ];
@@ -208,6 +220,7 @@ async function resolveX402Accepts(request, routeEntry, accepts, fallbackPayTo, b
208
220
  var init_x402_config = __esm({
209
221
  "src/x402-config.ts"() {
210
222
  "use strict";
223
+ init_constants();
211
224
  }
212
225
  });
213
226
 
@@ -407,7 +420,7 @@ import { NextResponse as NextResponse2 } from "next/server";
407
420
 
408
421
  // src/auth/normalize-wallet.ts
409
422
  function normalizeWalletAddress(address) {
410
- return address.startsWith("0x") ? address.toLowerCase() : address;
423
+ return /^0x/i.test(address) ? address.toLowerCase() : address;
411
424
  }
412
425
 
413
426
  // src/plugin.ts
@@ -572,12 +585,13 @@ var HttpError = class extends Error {
572
585
  };
573
586
 
574
587
  // src/handler.ts
575
- async function safeCallHandler(handler, ctx) {
588
+ async function safeCallHandler(handler, ctx, options = {}) {
576
589
  try {
577
590
  const result = await handler(ctx);
578
591
  if (result instanceof Response) return result;
579
592
  return NextResponse.json(result);
580
593
  } catch (error) {
594
+ options.onError?.(error);
581
595
  const status = error instanceof HttpError ? error.status : typeof error.status === "number" ? error.status : 500;
582
596
  const message = error instanceof Error ? error.message : "Internal error";
583
597
  return NextResponse.json({ success: false, error: message }, { status });
@@ -700,6 +714,9 @@ async function verifyX402Payment(opts) {
700
714
  throw err;
701
715
  }
702
716
  if (!verify.isValid) return invalidPaymentVerification();
717
+ if (typeof verify.payer !== "string" || verify.payer.length === 0) {
718
+ throw new Error("x402 verification succeeded without a payer address");
719
+ }
703
720
  return {
704
721
  valid: true,
705
722
  payer: verify.payer,
@@ -990,6 +1007,21 @@ function getRequirementNetwork(requirements, fallback) {
990
1007
  const network = requirements?.network;
991
1008
  return typeof network === "string" ? network : fallback;
992
1009
  }
1010
+ function getRequirementRecipient(requirements) {
1011
+ const payTo = requirements?.payTo;
1012
+ return typeof payTo === "string" ? payTo : void 0;
1013
+ }
1014
+ function errorStatus(error, fallback) {
1015
+ const status = error?.status;
1016
+ return typeof status === "number" ? status : fallback;
1017
+ }
1018
+ function errorMessage(error, fallback) {
1019
+ return error instanceof Error ? error.message : fallback;
1020
+ }
1021
+ function handlerFailureError(response) {
1022
+ const message = response.statusText || `Handler returned HTTP ${response.status}`;
1023
+ return Object.assign(new Error(message), { status: response.status });
1024
+ }
993
1025
  function siwxSignatureType(network) {
994
1026
  return network.startsWith("solana:") ? "ed25519" : "eip191";
995
1027
  }
@@ -1008,7 +1040,7 @@ function getSupportedChains(x402Accepts, fallbackNetwork) {
1008
1040
  return chains;
1009
1041
  }
1010
1042
  function createRequestHandler(routeEntry, handler, deps) {
1011
- async function invoke(request, meta, pluginCtx, wallet, account, parsedBody) {
1043
+ async function invoke(request, meta, pluginCtx, wallet, account, parsedBody, payment) {
1012
1044
  const ctx = {
1013
1045
  body: parsedBody,
1014
1046
  query: parseQuery(request, routeEntry),
@@ -1016,6 +1048,7 @@ function createRequestHandler(routeEntry, handler, deps) {
1016
1048
  requestId: meta.requestId,
1017
1049
  route: routeEntry.key,
1018
1050
  wallet,
1051
+ payment,
1019
1052
  account,
1020
1053
  alert(level, message, alertMeta) {
1021
1054
  firePluginHook(deps.plugin, "onAlert", pluginCtx, {
@@ -1028,11 +1061,20 @@ function createRequestHandler(routeEntry, handler, deps) {
1028
1061
  setVerifiedWallet: (addr) => pluginCtx.setVerifiedWallet(addr)
1029
1062
  };
1030
1063
  let rawResult;
1031
- const response = await safeCallHandler(async (c) => {
1032
- rawResult = await handler(c);
1033
- return rawResult;
1034
- }, ctx);
1035
- return { response, rawResult };
1064
+ let handlerError;
1065
+ const response = await safeCallHandler(
1066
+ async (c) => {
1067
+ rawResult = await handler(c);
1068
+ return rawResult;
1069
+ },
1070
+ ctx,
1071
+ {
1072
+ onError(error) {
1073
+ handlerError = error;
1074
+ }
1075
+ }
1076
+ );
1077
+ return { response, rawResult, handlerError };
1036
1078
  }
1037
1079
  function finalize(response, rawResult, meta, pluginCtx, requestBody) {
1038
1080
  fireProviderQuota(routeEntry, response, rawResult, deps, pluginCtx);
@@ -1043,6 +1085,87 @@ function createRequestHandler(routeEntry, handler, deps) {
1043
1085
  firePluginResponse(deps, pluginCtx, meta, response, requestBody);
1044
1086
  return response;
1045
1087
  }
1088
+ function settlementContext(scope) {
1089
+ return {
1090
+ route: routeEntry.key,
1091
+ request: scope.request,
1092
+ body: scope.parsedBody,
1093
+ wallet: scope.wallet,
1094
+ account: scope.account,
1095
+ payment: scope.payment,
1096
+ response: scope.response,
1097
+ result: scope.rawResult
1098
+ };
1099
+ }
1100
+ async function runBeforeSettle(scope) {
1101
+ const hook = routeEntry.settlement?.beforeSettle;
1102
+ if (!hook) return null;
1103
+ try {
1104
+ await hook(settlementContext(scope));
1105
+ return null;
1106
+ } catch (error) {
1107
+ return fail(
1108
+ errorStatus(error, 500),
1109
+ errorMessage(error, "Pre-settlement validation failed"),
1110
+ scope.meta,
1111
+ scope.pluginCtx,
1112
+ scope.parsedBody
1113
+ );
1114
+ }
1115
+ }
1116
+ async function runSettlementError(scope, error, phase) {
1117
+ const hook = routeEntry.settlement?.onSettlementError;
1118
+ if (!hook) return;
1119
+ try {
1120
+ await hook({
1121
+ ...settlementContext(scope),
1122
+ error,
1123
+ phase
1124
+ });
1125
+ } catch (hookError) {
1126
+ const message = errorMessage(hookError, "Settlement error hook failed");
1127
+ console.error(`[router] ${routeEntry.key}: onSettlementError failed: ${message}`);
1128
+ firePluginHook(deps.plugin, "onAlert", scope.pluginCtx, {
1129
+ level: "error",
1130
+ message: `Settlement error hook failed: ${message}`,
1131
+ route: routeEntry.key
1132
+ });
1133
+ }
1134
+ }
1135
+ async function runAfterSettle(scope) {
1136
+ const hook = routeEntry.settlement?.afterSettle;
1137
+ if (!hook) return;
1138
+ try {
1139
+ await hook(settlementContext(scope));
1140
+ } catch (error) {
1141
+ const message = errorMessage(error, "Post-settlement hook failed");
1142
+ console.error(`[router] ${routeEntry.key}: afterSettle failed: ${message}`);
1143
+ firePluginHook(deps.plugin, "onAlert", scope.pluginCtx, {
1144
+ level: "error",
1145
+ message: `Post-settlement hook failed: ${message}`,
1146
+ route: routeEntry.key
1147
+ });
1148
+ await runSettlementError(scope, error, "afterSettle");
1149
+ }
1150
+ }
1151
+ async function runSettledHandlerError(scope, error = scope.handlerError ?? handlerFailureError(scope.response)) {
1152
+ const hook = routeEntry.settlement?.onSettledHandlerError;
1153
+ if (!hook) return;
1154
+ try {
1155
+ await hook({
1156
+ ...settlementContext(scope),
1157
+ error
1158
+ });
1159
+ } catch (hookError) {
1160
+ const message = errorMessage(hookError, "Settled handler error hook failed");
1161
+ console.error(`[router] ${routeEntry.key}: onSettledHandlerError failed: ${message}`);
1162
+ firePluginHook(deps.plugin, "onAlert", scope.pluginCtx, {
1163
+ level: "error",
1164
+ message: `Settled handler error hook failed: ${message}`,
1165
+ route: routeEntry.key
1166
+ });
1167
+ }
1168
+ }
1046
1169
  return async (request) => {
1047
1170
  await deps.initPromise;
1048
1171
  const meta = buildMeta(request, routeEntry);
@@ -1068,7 +1191,8 @@ function createRequestHandler(routeEntry, handler, deps) {
1068
1191
  pluginCtx,
1069
1192
  wallet,
1070
1193
  account2,
1071
- body2.data
1194
+ body2.data,
1195
+ null
1072
1196
  );
1073
1197
  finalize(response, rawResult, meta, pluginCtx, body2.data);
1074
1198
  return response;
@@ -1297,18 +1421,9 @@ function createRequestHandler(routeEntry, handler, deps) {
1297
1421
  return fail(status, message, meta, pluginCtx, body.data);
1298
1422
  }
1299
1423
  }
1300
- let price;
1301
- try {
1302
- price = await resolvePrice(routeEntry.pricing, body.data);
1303
- } catch (err) {
1304
- return fail(
1305
- err.status ?? 500,
1306
- err instanceof Error ? err.message : "Price resolution failed",
1307
- meta,
1308
- pluginCtx,
1309
- body.data
1310
- );
1311
- }
1424
+ const priceResult = await resolveDynamicPrice(body.data, routeEntry, deps, pluginCtx, meta);
1425
+ if ("error" in priceResult) return priceResult.error;
1426
+ const price = priceResult.price;
1312
1427
  if (!routeEntry.protocols.includes(protocol)) {
1313
1428
  const accepted = routeEntry.protocols.join(", ") || "none";
1314
1429
  console.warn(
@@ -1345,7 +1460,16 @@ function createRequestHandler(routeEntry, handler, deps) {
1345
1460
  return await build402(request, routeEntry, deps, meta, pluginCtx, body.data);
1346
1461
  const { payload: verifyPayload, requirements: verifyRequirements } = verify;
1347
1462
  const matchedNetwork = getRequirementNetwork(verifyRequirements, deps.network);
1463
+ const matchedRecipient = getRequirementRecipient(verifyRequirements);
1348
1464
  const wallet = normalizeWalletAddress(verify.payer);
1465
+ const payment = {
1466
+ protocol: "x402",
1467
+ status: "verified",
1468
+ payer: wallet,
1469
+ amount: price,
1470
+ network: matchedNetwork,
1471
+ ...matchedRecipient ? { recipient: matchedRecipient } : {}
1472
+ };
1349
1473
  pluginCtx.setVerifiedWallet(wallet);
1350
1474
  firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
1351
1475
  protocol: "x402",
@@ -1353,15 +1477,30 @@ function createRequestHandler(routeEntry, handler, deps) {
1353
1477
  amount: price,
1354
1478
  network: matchedNetwork
1355
1479
  });
1356
- const { response, rawResult } = await invoke(
1480
+ const { response, rawResult, handlerError } = await invoke(
1357
1481
  request,
1358
1482
  meta,
1359
1483
  pluginCtx,
1360
1484
  wallet,
1361
1485
  account,
1362
- body.data
1486
+ body.data,
1487
+ payment
1363
1488
  );
1489
+ const settleScope = {
1490
+ request,
1491
+ meta,
1492
+ pluginCtx,
1493
+ wallet,
1494
+ account,
1495
+ parsedBody: body.data,
1496
+ payment,
1497
+ response,
1498
+ rawResult,
1499
+ handlerError
1500
+ };
1364
1501
  if (response.status < 400) {
1502
+ const validationFailure = await runBeforeSettle(settleScope);
1503
+ if (validationFailure) return validationFailure;
1365
1504
  try {
1366
1505
  const settle = await settleX402Payment(
1367
1506
  deps.x402Server,
@@ -1387,13 +1526,21 @@ function createRequestHandler(routeEntry, handler, deps) {
1387
1526
  }
1388
1527
  response.headers.set("PAYMENT-RESPONSE", settle.encoded);
1389
1528
  response.headers.set("Cache-Control", "private");
1529
+ const transaction = String(settle.result?.transaction ?? "");
1530
+ const settledPayment = {
1531
+ ...payment,
1532
+ status: "settled",
1533
+ ...transaction ? { transaction } : {}
1534
+ };
1390
1535
  firePluginHook(deps.plugin, "onPaymentSettled", pluginCtx, {
1391
1536
  protocol: "x402",
1392
- payer: verify.payer,
1393
- transaction: String(settle.result?.transaction ?? ""),
1537
+ payer: wallet,
1538
+ transaction,
1394
1539
  network: matchedNetwork
1395
1540
  });
1541
+ await runAfterSettle({ ...settleScope, payment: settledPayment });
1396
1542
  } catch (err) {
1543
+ await runSettlementError(settleScope, err, "settle");
1397
1544
  const errObj = err;
1398
1545
  console.error("Settlement failed", {
1399
1546
  message: err instanceof Error ? err.message : String(err),
@@ -1452,19 +1599,44 @@ function createRequestHandler(routeEntry, handler, deps) {
1452
1599
  amount: price,
1453
1600
  network: "tempo:4217"
1454
1601
  });
1455
- const { response: response2, rawResult: rawResult2 } = await invoke(
1602
+ const mppRecipient2 = deps.mppRecipient ?? deps.payeeAddress;
1603
+ const payment2 = {
1604
+ protocol: "mpp",
1605
+ status: "verified",
1606
+ payer: wallet,
1607
+ amount: price,
1608
+ network: "tempo:4217",
1609
+ ...mppRecipient2 ? { recipient: mppRecipient2 } : {}
1610
+ };
1611
+ const { response: response2, rawResult: rawResult2, handlerError: handlerError2 } = await invoke(
1456
1612
  request,
1457
1613
  meta,
1458
1614
  pluginCtx,
1459
1615
  wallet,
1460
1616
  account,
1461
- body.data
1617
+ body.data,
1618
+ payment2
1462
1619
  );
1620
+ const settleScope2 = {
1621
+ request,
1622
+ meta,
1623
+ pluginCtx,
1624
+ wallet,
1625
+ account,
1626
+ parsedBody: body.data,
1627
+ payment: payment2,
1628
+ response: response2,
1629
+ rawResult: rawResult2,
1630
+ handlerError: handlerError2
1631
+ };
1463
1632
  if (response2.status < 400) {
1633
+ const validationFailure = await runBeforeSettle(settleScope2);
1634
+ if (validationFailure) return validationFailure;
1464
1635
  let mppResult2;
1465
1636
  try {
1466
1637
  mppResult2 = await deps.mppx.charge({ amount: price })(request);
1467
1638
  } catch (err) {
1639
+ await runSettlementError(settleScope2, err, "settle");
1468
1640
  const message = err instanceof Error ? err.message : String(err);
1469
1641
  console.error(
1470
1642
  `[router] ${routeEntry.key}: MPP broadcast failed after handler: ${message}`
@@ -1493,6 +1665,13 @@ function createRequestHandler(routeEntry, handler, deps) {
1493
1665
  } catch {
1494
1666
  }
1495
1667
  const detail = rejectReason || "transaction reverted on-chain after handler execution";
1668
+ const settlementError = Object.assign(new Error(detail), {
1669
+ status: 402,
1670
+ detail,
1671
+ mppResult: mppResult2,
1672
+ challenge: mppResult2.challenge
1673
+ });
1674
+ await runSettlementError(settleScope2, settlementError, "settle");
1496
1675
  console.error(
1497
1676
  `[router] ${routeEntry.key}: MPP payment failed after handler \u2014 ${detail}`
1498
1677
  );
@@ -1530,6 +1709,17 @@ function createRequestHandler(routeEntry, handler, deps) {
1530
1709
  transaction: txHash2,
1531
1710
  network: "tempo:4217"
1532
1711
  });
1712
+ const settledPayment = {
1713
+ ...payment2,
1714
+ status: "settled",
1715
+ ...txHash2 ? { transaction: txHash2 } : {},
1716
+ ...receiptHeader2 ? { receipt: receiptHeader2 } : {}
1717
+ };
1718
+ await runAfterSettle({
1719
+ ...settleScope2,
1720
+ payment: settledPayment,
1721
+ response: receiptResponse
1722
+ });
1533
1723
  finalize(receiptResponse, rawResult2, meta, pluginCtx, body.data);
1534
1724
  return receiptResponse;
1535
1725
  }
@@ -1585,14 +1775,38 @@ function createRequestHandler(routeEntry, handler, deps) {
1585
1775
  amount: price,
1586
1776
  network: "tempo:4217"
1587
1777
  });
1588
- const { response, rawResult } = await invoke(
1778
+ const mppRecipient = deps.mppRecipient ?? deps.payeeAddress;
1779
+ const payment = {
1780
+ protocol: "mpp",
1781
+ status: "settled",
1782
+ payer: wallet,
1783
+ amount: price,
1784
+ network: "tempo:4217",
1785
+ ...mppRecipient ? { recipient: mppRecipient } : {},
1786
+ ...txHash ? { transaction: txHash } : {},
1787
+ ...receiptHeader ? { receipt: receiptHeader } : {}
1788
+ };
1789
+ const { response, rawResult, handlerError } = await invoke(
1589
1790
  request,
1590
1791
  meta,
1591
1792
  pluginCtx,
1592
1793
  wallet,
1593
1794
  account,
1594
- body.data
1795
+ body.data,
1796
+ payment
1595
1797
  );
1798
+ const settleScope = {
1799
+ request,
1800
+ meta,
1801
+ pluginCtx,
1802
+ wallet,
1803
+ account,
1804
+ parsedBody: body.data,
1805
+ payment,
1806
+ response,
1807
+ rawResult,
1808
+ handlerError
1809
+ };
1596
1810
  if (response.status < 400) {
1597
1811
  if (routeEntry.siwxEnabled) {
1598
1812
  try {
@@ -1613,9 +1827,11 @@ function createRequestHandler(routeEntry, handler, deps) {
1613
1827
  transaction: txHash,
1614
1828
  network: "tempo:4217"
1615
1829
  });
1830
+ await runAfterSettle({ ...settleScope, response: receiptResponse });
1616
1831
  finalize(receiptResponse, rawResult, meta, pluginCtx, body.data);
1617
1832
  return receiptResponse;
1618
1833
  }
1834
+ await runSettledHandlerError(settleScope);
1619
1835
  finalize(response, rawResult, meta, pluginCtx, body.data);
1620
1836
  return response;
1621
1837
  }
@@ -1688,9 +1904,10 @@ async function resolveDynamicPrice(bodyData, routeEntry, deps, pluginCtx, meta)
1688
1904
  });
1689
1905
  return { price: routeEntry.maxPrice };
1690
1906
  } else {
1907
+ const message = errorMessage(err, "Price calculation failed");
1691
1908
  const errorResponse = NextResponse2.json(
1692
- { success: false, error: "Price calculation failed" },
1693
- { status: 500 }
1909
+ { success: false, error: message },
1910
+ { status: errorStatus(err, 500) }
1694
1911
  );
1695
1912
  firePluginResponse(deps, pluginCtx, meta, errorResponse);
1696
1913
  return { error: errorResponse };
@@ -1863,22 +2080,13 @@ function fireProviderQuota(routeEntry, response, handlerResult, deps, pluginCtx)
1863
2080
 
1864
2081
  // src/validate-examples.ts
1865
2082
  function validateExamples(key, bodySchema, querySchema, outputSchema, inputExample, hasInputExample, outputExample, hasOutputExample) {
1866
- if (bodySchema && !hasInputExample) {
1867
- throw new Error(
1868
- `route '${key}': .body() requires a matching .inputExample() \u2014 the bazaar discovery extension needs a conforming sample body to advertise.`
1869
- );
1870
- }
1871
- if (querySchema && !hasInputExample) {
1872
- throw new Error(
1873
- `route '${key}': .query() requires a matching .inputExample() \u2014 the bazaar discovery extension needs a conforming sample query to advertise.`
1874
- );
2083
+ const inputSchema = bodySchema ?? querySchema;
2084
+ if (hasInputExample && !inputSchema) {
2085
+ throw new Error(`route '${key}': .inputExample() requires .body() or .query()`);
1875
2086
  }
1876
- if (outputSchema && !hasOutputExample) {
1877
- throw new Error(
1878
- `route '${key}': .output() requires a matching .outputExample() \u2014 the bazaar discovery extension needs a conforming sample response to advertise.`
1879
- );
2087
+ if (hasOutputExample && !outputSchema) {
2088
+ throw new Error(`route '${key}': .outputExample() requires .output()`);
1880
2089
  }
1881
- const inputSchema = bodySchema ?? querySchema;
1882
2090
  if (inputSchema && hasInputExample) {
1883
2091
  const result = inputSchema.safeParse(inputExample);
1884
2092
  if (!result.success) {
@@ -1952,6 +2160,8 @@ var RouteBuilder = class {
1952
2160
  /** @internal */
1953
2161
  _validateFn;
1954
2162
  /** @internal */
2163
+ _settlement;
2164
+ /** @internal */
1955
2165
  _mppInfo;
1956
2166
  constructor(key, registry, deps) {
1957
2167
  this._key = key;
@@ -1965,11 +2175,21 @@ var RouteBuilder = class {
1965
2175
  return next;
1966
2176
  }
1967
2177
  paid(pricing, options) {
2178
+ if (this._authMode === "unprotected") {
2179
+ throw new Error(
2180
+ `route '${this._key}': Cannot combine .unprotected() and .paid() on the same route.`
2181
+ );
2182
+ }
2183
+ if (this._pricing !== void 0) {
2184
+ throw new Error(
2185
+ `route '${this._key}': Cannot call .paid() more than once on the same route.`
2186
+ );
2187
+ }
1968
2188
  const next = this.fork();
1969
2189
  next._authMode = "paid";
1970
2190
  next._pricing = pricing;
1971
2191
  if (options?.protocols) {
1972
- next._protocols = options.protocols;
2192
+ next._protocols = [...options.protocols];
1973
2193
  } else if (next._protocols.length === 0) {
1974
2194
  next._protocols = ["x402"];
1975
2195
  }
@@ -2034,6 +2254,16 @@ var RouteBuilder = class {
2034
2254
  return next;
2035
2255
  }
2036
2256
  unprotected() {
2257
+ if (this._authMode && this._authMode !== "unprotected") {
2258
+ throw new Error(
2259
+ `route '${this._key}': Cannot combine .unprotected() and .${this._authMode}() on the same route.`
2260
+ );
2261
+ }
2262
+ if (this._pricing) {
2263
+ throw new Error(
2264
+ `route '${this._key}': Cannot combine .unprotected() and .paid() on the same route.`
2265
+ );
2266
+ }
2037
2267
  const next = this.fork();
2038
2268
  next._authMode = "unprotected";
2039
2269
  next._protocols = [];
@@ -2048,32 +2278,43 @@ var RouteBuilder = class {
2048
2278
  next._providerConfig = config ?? {};
2049
2279
  return next;
2050
2280
  }
2051
- // -------------------------------------------------------------------------
2052
- // Schema methods
2053
- // -------------------------------------------------------------------------
2054
- body(schema) {
2281
+ body(schema, example) {
2055
2282
  const next = this.fork();
2056
2283
  next._bodySchema = schema;
2284
+ if (example !== void 0) {
2285
+ next._inputExample = example;
2286
+ next._hasInputExample = true;
2287
+ }
2057
2288
  return next;
2058
2289
  }
2059
- query(schema) {
2290
+ query(schema, example) {
2060
2291
  const next = this.fork();
2061
2292
  next._querySchema = schema;
2293
+ if (example !== void 0) {
2294
+ next._inputExample = example;
2295
+ next._hasInputExample = true;
2296
+ }
2062
2297
  next._method = "GET";
2063
2298
  return next;
2064
2299
  }
2065
- output(schema) {
2300
+ output(schema, example) {
2066
2301
  const next = this.fork();
2067
2302
  next._outputSchema = schema;
2303
+ if (example !== void 0) {
2304
+ next._outputExample = example;
2305
+ next._hasOutputExample = true;
2306
+ }
2068
2307
  return next;
2069
2308
  }
2070
2309
  /**
2071
2310
  * Provide a conforming example of the request input (body or query params).
2072
2311
  *
2073
- * **Required** whenever `.body()` or `.query()` is set enforced at compile time via
2074
- * `.handler()` overloads, and at route-registration time via Zod validation of the
2075
- * example against the schema. The example is embedded in the bazaar discovery extension
2076
- * so indexers can advertise a working sample call.
2312
+ * Optional. When provided, the example is validated against the request schema
2313
+ * at route registration and embedded in the bazaar discovery extension so
2314
+ * indexers can advertise a working sample call.
2315
+ *
2316
+ * For the common case, pass the example directly to `.body(schema, example)` or
2317
+ * `.query(schema, example)` instead.
2077
2318
  *
2078
2319
  * @example
2079
2320
  * ```ts
@@ -2093,10 +2334,11 @@ var RouteBuilder = class {
2093
2334
  /**
2094
2335
  * Provide a conforming example of the response output.
2095
2336
  *
2096
- * **Required** whenever `.output()` is set enforced at compile time via `.handler()`
2097
- * overloads, and at route-registration time via Zod validation of the example against
2098
- * the schema. The example is embedded in the bazaar discovery extension so indexers
2099
- * can advertise the response shape.
2337
+ * Optional. When provided, the example is validated against the output schema
2338
+ * at route registration and embedded in the bazaar discovery extension so
2339
+ * indexers can advertise the response shape.
2340
+ *
2341
+ * For the common case, pass the example directly to `.output(schema, example)` instead.
2100
2342
  *
2101
2343
  * Accepts any JSON value (objects, arrays, or primitives) — top-level array
2102
2344
  * or primitive responses (e.g. `z.array(...)`) are supported alongside the
@@ -2169,15 +2411,39 @@ var RouteBuilder = class {
2169
2411
  return next;
2170
2412
  }
2171
2413
  // -------------------------------------------------------------------------
2414
+ // Settlement lifecycle
2415
+ // -------------------------------------------------------------------------
2416
+ /**
2417
+ * Add route-specific settlement hooks.
2418
+ *
2419
+ * `beforeSettle` runs after a successful handler response but before
2420
+ * router-controlled settlement/broadcast, so it can still prevent the charge
2421
+ * for x402 and MPP transaction-payload flows. `afterSettle` runs after
2422
+ * settlement and is intended for durable ledgers or app-owned refund queues.
2423
+ */
2424
+ settlement(lifecycle) {
2425
+ const next = this.fork();
2426
+ next._settlement = lifecycle;
2427
+ return next;
2428
+ }
2429
+ // -------------------------------------------------------------------------
2172
2430
  // Terminal method
2173
2431
  // -------------------------------------------------------------------------
2174
2432
  handler(fn) {
2175
2433
  const handlerFn = fn;
2434
+ if (!this._authMode) {
2435
+ throw new Error(
2436
+ `route '${this._key}': Select an auth mode: .paid(pricing), .siwx(), .apiKey(resolver), or .unprotected()`
2437
+ );
2438
+ }
2176
2439
  if (this._validateFn && !this._bodySchema) {
2177
2440
  throw new Error(
2178
2441
  `route '${this._key}': .validate() requires .body() \u2014 validation runs on parsed body`
2179
2442
  );
2180
2443
  }
2444
+ if (this._settlement && !this._pricing) {
2445
+ throw new Error(`route '${this._key}': .settlement() requires a paid route`);
2446
+ }
2181
2447
  validateExamples(
2182
2448
  this._key,
2183
2449
  this._bodySchema,
@@ -2209,6 +2475,7 @@ var RouteBuilder = class {
2209
2475
  providerName: this._providerName,
2210
2476
  providerConfig: this._providerConfig,
2211
2477
  validateFn: this._validateFn,
2478
+ settlement: this._settlement,
2212
2479
  mppInfo: this._mppInfo
2213
2480
  };
2214
2481
  this._registry.register(entry);
@@ -2344,6 +2611,7 @@ function toDiscoveryResource(method, url, mode) {
2344
2611
  }
2345
2612
 
2346
2613
  // src/discovery/openapi.ts
2614
+ init_constants();
2347
2615
  import { NextResponse as NextResponse4 } from "next/server";
2348
2616
  function createOpenAPIHandler(registry, baseUrl, pricesKeys, discovery) {
2349
2617
  const normalizedBase = baseUrl.replace(/\/+$/, "");
@@ -2486,7 +2754,7 @@ function toProtocolObject(protocol, mppInfo) {
2486
2754
  mpp: {
2487
2755
  method: mppInfo?.method ?? "tempo",
2488
2756
  intent: mppInfo?.intent ?? "charge",
2489
- currency: mppInfo?.currency ?? "0x20c0000000000000000000000000000000000001"
2757
+ currency: mppInfo?.currency ?? TEMPO_USDC_CURRENCY
2490
2758
  }
2491
2759
  };
2492
2760
  }
@@ -2551,61 +2819,319 @@ function createLlmsTxtHandler(discovery) {
2551
2819
 
2552
2820
  // src/index.ts
2553
2821
  init_x402_config();
2822
+ init_constants();
2823
+
2824
+ // src/config.ts
2825
+ init_constants();
2554
2826
  init_evm();
2555
2827
  init_solana();
2828
+ init_x402_config();
2829
+ var RouterConfigError = class extends Error {
2830
+ issues;
2831
+ constructor(issues) {
2832
+ super(formatRouterConfigIssues(issues));
2833
+ this.name = "RouterConfigError";
2834
+ this.issues = issues;
2835
+ }
2836
+ };
2837
+ function validateRouterConfig(config, options = {}) {
2838
+ const issues = getRouterConfigIssues(config, options);
2839
+ if (issues.length > 0) throw new RouterConfigError(issues);
2840
+ }
2841
+ function getRouterConfigIssues(config, options = {}) {
2842
+ const env = options.env ?? process.env;
2843
+ const issues = [];
2844
+ const protocols = config.protocols ?? ["x402"];
2845
+ if (!config.baseUrl) {
2846
+ issues.push({
2847
+ code: "missing_base_url",
2848
+ message: '[router] baseUrl is required in RouterConfig. Set it to your production domain (e.g., "https://api.example.com"). The realm is used for payment matching and must be correct.'
2849
+ });
2850
+ }
2851
+ if (config.protocols && config.protocols.length === 0) {
2852
+ issues.push({
2853
+ code: "empty_protocols",
2854
+ message: "RouterConfig.protocols cannot be empty. Omit the field to use default ['x402'] or specify protocols explicitly."
2855
+ });
2856
+ }
2857
+ if (protocols.includes("x402")) {
2858
+ issues.push(...validateX402Config(config, env, options));
2859
+ }
2860
+ if (protocols.includes("mpp")) {
2861
+ issues.push(...validateMppConfig(config, env));
2862
+ }
2863
+ return issues;
2864
+ }
2865
+ function formatRouterConfigIssues(issues) {
2866
+ return issues.map((issue) => issue.message).join("\n");
2867
+ }
2868
+ function mppFromEnv(env, options = {}) {
2869
+ const secretKey = env.MPP_SECRET_KEY;
2870
+ const currency = env.MPP_CURRENCY;
2871
+ const rpcUrl = env.TEMPO_RPC_URL;
2872
+ const feePayerKey = options.feePayerKey ?? env.MPP_FEE_PAYER_KEY;
2873
+ const feePayerKeySource = options.feePayerKey !== void 0 ? "feePayerKey" : "MPP_FEE_PAYER_KEY";
2874
+ const hasAnyMppEnv = Boolean(secretKey || currency || rpcUrl || options.require);
2875
+ if (!hasAnyMppEnv) return void 0;
2876
+ const missing = [
2877
+ secretKey ? null : "MPP_SECRET_KEY",
2878
+ currency ? null : "MPP_CURRENCY",
2879
+ rpcUrl ? null : "TEMPO_RPC_URL"
2880
+ ].filter(Boolean);
2881
+ if (missing.length > 0) {
2882
+ throw new Error(`MPP env is incomplete. Missing: ${missing.join(", ")}`);
2883
+ }
2884
+ if (!isEvmAddress(currency)) {
2885
+ throw new Error("MPP_CURRENCY must be a 0x-prefixed 20-byte Tempo currency address");
2886
+ }
2887
+ if (options.recipient && !isEvmAddress(options.recipient)) {
2888
+ throw new Error("MPP recipient must be a 0x-prefixed EVM address");
2889
+ }
2890
+ if (feePayerKey && !isEvmPrivateKey(feePayerKey)) {
2891
+ throw new Error(`${feePayerKeySource} must be a 0x-prefixed 32-byte EVM private key`);
2892
+ }
2893
+ return {
2894
+ secretKey,
2895
+ currency,
2896
+ rpcUrl,
2897
+ ...options.recipient ? { recipient: options.recipient } : {},
2898
+ ...feePayerKey ? { feePayerKey } : {},
2899
+ ...options.useDefaultStore !== void 0 ? { useDefaultStore: options.useDefaultStore } : {}
2900
+ };
2901
+ }
2902
+ function x402AcceptsFromEnv(env, options = {}) {
2903
+ const payeeEnv = options.payeeEnv ?? "X402_WALLET_ADDRESS";
2904
+ const solanaPayeeEnv = options.solanaPayeeEnv ?? "SOLANA_PAYEE_ADDRESS";
2905
+ const payeeAddress = options.payeeAddress ?? env[payeeEnv];
2906
+ if (!payeeAddress) {
2907
+ throw new Error(`${payeeEnv} is required to build x402 accepts`);
2908
+ }
2909
+ const accepts = [
2910
+ {
2911
+ scheme: "exact",
2912
+ network: options.network ?? BASE_NETWORK,
2913
+ payTo: payeeAddress
2914
+ }
2915
+ ];
2916
+ const solanaPayeeAddress = options.solanaPayeeAddress ?? env[solanaPayeeEnv];
2917
+ if (solanaPayeeAddress) {
2918
+ accepts.push({
2919
+ scheme: "exact",
2920
+ network: SOLANA_MAINNET_NETWORK,
2921
+ payTo: solanaPayeeAddress
2922
+ });
2923
+ }
2924
+ return accepts;
2925
+ }
2926
+ function paidOptionsForProtocols(protocols) {
2927
+ return { protocols: [...protocols] };
2928
+ }
2929
+ function validateX402Config(config, env, options) {
2930
+ const issues = [];
2931
+ const accepts = getConfiguredX402Accepts(config);
2932
+ if (accepts.length === 0) {
2933
+ issues.push({
2934
+ code: "missing_x402_accepts",
2935
+ protocol: "x402",
2936
+ message: "x402 requires at least one accept configuration."
2937
+ });
2938
+ return issues;
2939
+ }
2940
+ const acceptWithoutNetwork = accepts.find((accept) => !accept.network);
2941
+ if (acceptWithoutNetwork) {
2942
+ issues.push({
2943
+ code: "missing_x402_network",
2944
+ protocol: "x402",
2945
+ message: "x402 accepts require a network."
2946
+ });
2947
+ }
2948
+ const unsupported = accepts.find(
2949
+ (accept) => accept.network && !isSupportedX402Network(accept.network)
2950
+ );
2951
+ if (unsupported) {
2952
+ issues.push({
2953
+ code: "unsupported_x402_network",
2954
+ protocol: "x402",
2955
+ message: `unsupported x402 network '${unsupported.network}'. Use eip155:* or solana:*.`
2956
+ });
2957
+ }
2958
+ const missingAsset = accepts.find(
2959
+ (accept) => (accept.scheme ?? "exact") !== "exact" && !accept.asset
2960
+ );
2961
+ if (missingAsset) {
2962
+ issues.push({
2963
+ code: "missing_x402_asset",
2964
+ protocol: "x402",
2965
+ message: "non-exact x402 accepts require an asset."
2966
+ });
2967
+ }
2968
+ const invalidDecimals = accepts.find(
2969
+ (accept) => accept.decimals !== void 0 && (!Number.isInteger(accept.decimals) || accept.decimals < 0)
2970
+ );
2971
+ if (invalidDecimals) {
2972
+ issues.push({
2973
+ code: "invalid_x402_decimals",
2974
+ protocol: "x402",
2975
+ message: "x402 accept decimals must be a non-negative integer."
2976
+ });
2977
+ }
2978
+ if (accepts.some((accept) => !accept.payTo) && !config.payeeAddress) {
2979
+ issues.push({
2980
+ code: "missing_x402_payee",
2981
+ protocol: "x402",
2982
+ message: "x402 requires payeeAddress in router config or payTo on every x402 accept."
2983
+ });
2984
+ }
2985
+ const placeholder = findPlaceholderPayee([
2986
+ config.payeeAddress,
2987
+ ...accepts.map((accept) => typeof accept.payTo === "string" ? accept.payTo : void 0)
2988
+ ]);
2989
+ if (placeholder) {
2990
+ issues.push({
2991
+ code: "placeholder_payee",
2992
+ protocol: "x402",
2993
+ message: `x402 payee '${placeholder}' is a placeholder address and cannot receive payments.`
2994
+ });
2995
+ }
2996
+ if (options.requireCdpKeys !== false && usesDefaultEvmFacilitator(config)) {
2997
+ const missing = [
2998
+ env.CDP_API_KEY_ID ? null : "CDP_API_KEY_ID",
2999
+ env.CDP_API_KEY_SECRET ? null : "CDP_API_KEY_SECRET"
3000
+ ].filter(Boolean);
3001
+ if (missing.length > 0) {
3002
+ issues.push({
3003
+ code: "missing_cdp_keys",
3004
+ protocol: "x402",
3005
+ message: `default EVM x402 facilitator requires ${missing.join(" and ")}.`
3006
+ });
3007
+ }
3008
+ }
3009
+ return issues;
3010
+ }
3011
+ function validateMppConfig(config, env) {
3012
+ const issues = [];
3013
+ const mpp = config.mpp;
3014
+ if (!mpp) {
3015
+ return [
3016
+ {
3017
+ code: "missing_mpp_config",
3018
+ protocol: "mpp",
3019
+ message: 'protocols includes "mpp" but mpp config is missing. Add mpp: { secretKey, currency, recipient } to your router config.'
3020
+ }
3021
+ ];
3022
+ }
3023
+ if (!mpp.secretKey) {
3024
+ issues.push({
3025
+ code: "missing_mpp_secret_key",
3026
+ protocol: "mpp",
3027
+ message: "MPP requires secretKey. Set MPP_SECRET_KEY or pass mpp.secretKey."
3028
+ });
3029
+ }
3030
+ if (!mpp.currency) {
3031
+ issues.push({
3032
+ code: "missing_mpp_currency",
3033
+ protocol: "mpp",
3034
+ message: "MPP requires currency. Set MPP_CURRENCY or pass mpp.currency."
3035
+ });
3036
+ } else if (!isEvmAddress(mpp.currency)) {
3037
+ issues.push({
3038
+ code: "invalid_mpp_currency",
3039
+ protocol: "mpp",
3040
+ message: "MPP currency must be a 0x-prefixed 20-byte Tempo currency address. Use TEMPO_USDC_CURRENCY for Tempo USDC."
3041
+ });
3042
+ }
3043
+ const mppRecipient = mpp.recipient ?? config.payeeAddress;
3044
+ if (!mppRecipient) {
3045
+ issues.push({
3046
+ code: "missing_mpp_recipient",
3047
+ protocol: "mpp",
3048
+ message: "MPP requires a recipient address. Set mpp.recipient or payeeAddress in your router config."
3049
+ });
3050
+ } else if (!isEvmAddress(mppRecipient)) {
3051
+ issues.push({
3052
+ code: "invalid_mpp_recipient",
3053
+ protocol: "mpp",
3054
+ message: "MPP recipient must be a 0x-prefixed EVM address. Solana recipients require x402."
3055
+ });
3056
+ }
3057
+ const placeholder = findPlaceholderPayee([mpp.recipient, config.payeeAddress]);
3058
+ if (placeholder) {
3059
+ issues.push({
3060
+ code: "placeholder_payee",
3061
+ protocol: "mpp",
3062
+ message: `MPP recipient '${placeholder}' is a placeholder address and cannot receive payments.`
3063
+ });
3064
+ }
3065
+ if (!(mpp.rpcUrl ?? env.TEMPO_RPC_URL)) {
3066
+ issues.push({
3067
+ code: "missing_mpp_rpc_url",
3068
+ protocol: "mpp",
3069
+ message: "MPP requires an authenticated Tempo RPC URL. Set TEMPO_RPC_URL env var or pass rpcUrl in the mpp config object."
3070
+ });
3071
+ }
3072
+ if (mpp.feePayerKey && !isEvmPrivateKey(mpp.feePayerKey)) {
3073
+ issues.push({
3074
+ code: "invalid_mpp_fee_payer_key",
3075
+ protocol: "mpp",
3076
+ message: "MPP feePayerKey must be a 0x-prefixed 32-byte EVM private key."
3077
+ });
3078
+ }
3079
+ if (mpp.useDefaultStore && !mpp.store && (!env.KV_REST_API_URL || !env.KV_REST_API_TOKEN)) {
3080
+ issues.push({
3081
+ code: "missing_mpp_default_store_env",
3082
+ protocol: "mpp",
3083
+ message: "mpp.useDefaultStore requires KV_REST_API_URL and KV_REST_API_TOKEN environment variables. These are automatically set by Vercel KV."
3084
+ });
3085
+ }
3086
+ return issues;
3087
+ }
3088
+ function usesDefaultEvmFacilitator(config) {
3089
+ return getConfiguredX402Networks(config).some(
3090
+ (network) => typeof network === "string" && isEvmNetwork(network)
3091
+ ) && config.x402?.facilitators?.evm === void 0;
3092
+ }
3093
+ function isSupportedX402Network(network) {
3094
+ return isEvmNetwork(network) || isSolanaNetwork(network);
3095
+ }
3096
+ function isEvmAddress(value) {
3097
+ return /^0x[a-fA-F0-9]{40}$/.test(value);
3098
+ }
3099
+ function isEvmPrivateKey(value) {
3100
+ return /^0x[a-fA-F0-9]{64}$/.test(value);
3101
+ }
3102
+ function findPlaceholderPayee(values) {
3103
+ return values.find((value) => value !== void 0 && /^0x0{40}$/i.test(value)) ?? null;
3104
+ }
3105
+
3106
+ // src/index.ts
3107
+ init_constants();
2556
3108
  function createRouter(config) {
2557
3109
  const registry = new RouteRegistry();
2558
3110
  const nonceStore = config.siwx?.nonceStore ?? new MemoryNonceStore();
2559
3111
  const entitlementStore = config.siwx?.entitlementStore ?? new MemoryEntitlementStore();
2560
- const network = config.network ?? "eip155:8453";
3112
+ const network = config.network ?? BASE_NETWORK;
2561
3113
  const x402Accepts = getConfiguredX402Accepts(config);
2562
- if (!config.baseUrl) {
2563
- throw new Error(
2564
- '[router] baseUrl is required in RouterConfig. Set it to your production domain (e.g., "https://api.example.com"). The realm is used for payment matching and must be correct.'
2565
- );
2566
- }
2567
- if (config.protocols && config.protocols.length === 0) {
2568
- throw new Error(
2569
- "RouterConfig.protocols cannot be empty. Omit the field to use default ['x402'] or specify protocols explicitly."
2570
- );
2571
- }
2572
- const resolvedBaseUrl = config.baseUrl.replace(/\/+$/, "");
2573
- let x402ConfigError;
2574
- let mppConfigError;
2575
- if (!config.protocols || config.protocols.includes("x402")) {
2576
- if (x402Accepts.length === 0) {
2577
- x402ConfigError = "x402 requires at least one accept configuration.";
2578
- } else if (x402Accepts.some((accept) => !accept.network)) {
2579
- x402ConfigError = "x402 accepts require a network.";
2580
- } else if (x402Accepts.some((accept) => !isSupportedX402Network(accept.network))) {
2581
- const unsupported = x402Accepts.find((accept) => !isSupportedX402Network(accept.network));
2582
- x402ConfigError = `unsupported x402 network '${unsupported?.network}'. Use eip155:* or solana:*.`;
2583
- } else if (x402Accepts.some((accept) => (accept.scheme ?? "exact") !== "exact" && !accept.asset)) {
2584
- x402ConfigError = "non-exact x402 accepts require an asset.";
2585
- } else if (x402Accepts.some(
2586
- (accept) => accept.decimals !== void 0 && (!Number.isInteger(accept.decimals) || accept.decimals < 0)
2587
- )) {
2588
- x402ConfigError = "x402 accept decimals must be a non-negative integer.";
2589
- } else if (x402Accepts.some((accept) => !accept.payTo) && !config.payeeAddress) {
2590
- x402ConfigError = "x402 requires payeeAddress in router config or payTo on every x402 accept.";
2591
- }
2592
- }
2593
- if (config.protocols?.includes("mpp")) {
2594
- if (!config.mpp) {
2595
- mppConfigError = 'protocols includes "mpp" but mpp config is missing. Add mpp: { secretKey, currency, recipient } to your router config.';
2596
- } else if (!config.mpp.recipient && !config.payeeAddress) {
2597
- mppConfigError = "MPP requires a recipient address. Set mpp.recipient or payeeAddress in your router config.";
2598
- } else if (!(config.mpp.rpcUrl ?? process.env.TEMPO_RPC_URL)) {
2599
- mppConfigError = "MPP requires an authenticated Tempo RPC URL. Set TEMPO_RPC_URL env var or pass rpcUrl in the mpp config object.";
2600
- }
2601
- }
2602
- const allConfigErrors = [x402ConfigError, mppConfigError].filter(Boolean);
2603
- if (allConfigErrors.length > 0) {
2604
- for (const err of allConfigErrors) console.error(`[router] ${err}`);
3114
+ const configIssues = getRouterConfigIssues(config, {
3115
+ requireCdpKeys: process.env.NODE_ENV === "production"
3116
+ });
3117
+ const baseUrlIssue = configIssues.find((issue) => issue.code === "missing_base_url");
3118
+ if (baseUrlIssue) throw new RouterConfigError([baseUrlIssue]);
3119
+ const emptyProtocolsIssue = configIssues.find((issue) => issue.code === "empty_protocols");
3120
+ if (emptyProtocolsIssue) throw new RouterConfigError([emptyProtocolsIssue]);
3121
+ const protocolConfigIssues = configIssues.filter(
3122
+ (issue) => issue.code !== "missing_base_url" && issue.code !== "empty_protocols"
3123
+ );
3124
+ const x402ConfigIssues = protocolConfigIssues.filter((issue) => issue.protocol === "x402");
3125
+ const mppConfigIssues = protocolConfigIssues.filter((issue) => issue.protocol === "mpp");
3126
+ const x402ConfigError = x402ConfigIssues.length > 0 ? formatRouterConfigIssues(x402ConfigIssues) : void 0;
3127
+ const mppConfigError = mppConfigIssues.length > 0 ? formatRouterConfigIssues(mppConfigIssues) : void 0;
3128
+ if (protocolConfigIssues.length > 0) {
3129
+ for (const issue of protocolConfigIssues) console.error(`[router] ${issue.message}`);
2605
3130
  if (process.env.NODE_ENV === "production") {
2606
- throw new Error(allConfigErrors.join("\n"));
3131
+ throw new RouterConfigError(protocolConfigIssues);
2607
3132
  }
2608
3133
  }
3134
+ const resolvedBaseUrl = config.baseUrl.replace(/\/+$/, "");
2609
3135
  if (config.plugin?.init) {
2610
3136
  try {
2611
3137
  const result = config.plugin.init({ origin: resolvedBaseUrl });
@@ -2623,6 +3149,7 @@ function createRouter(config) {
2623
3149
  nonceStore,
2624
3150
  entitlementStore,
2625
3151
  payeeAddress: config.payeeAddress ?? "",
3152
+ mppRecipient: config.mpp?.recipient ?? config.payeeAddress,
2626
3153
  network,
2627
3154
  x402FacilitatorsByNetwork: void 0,
2628
3155
  x402Accepts,
@@ -2750,9 +3277,6 @@ function createRouter(config) {
2750
3277
  registry
2751
3278
  };
2752
3279
  }
2753
- function isSupportedX402Network(network) {
2754
- return isEvmNetwork(network) || isSolanaNetwork(network);
2755
- }
2756
3280
  function normalizePath(path) {
2757
3281
  let normalized = path.trim();
2758
3282
  normalized = normalized.replace(/^\/+/, "");
@@ -2760,15 +3284,26 @@ function normalizePath(path) {
2760
3284
  return normalized.replace(/\/+$/, "");
2761
3285
  }
2762
3286
  export {
3287
+ BASE_NETWORK,
2763
3288
  HttpError,
2764
3289
  MemoryEntitlementStore,
2765
3290
  MemoryNonceStore,
2766
3291
  RouteBuilder,
2767
3292
  RouteRegistry,
3293
+ RouterConfigError,
2768
3294
  SIWX_CHALLENGE_EXPIRY_MS,
2769
3295
  SIWX_ERROR_MESSAGES,
3296
+ SOLANA_MAINNET_NETWORK,
3297
+ TEMPO_USDC_CURRENCY,
3298
+ ZERO_EVM_ADDRESS,
2770
3299
  consolePlugin,
2771
3300
  createRedisEntitlementStore,
2772
3301
  createRedisNonceStore,
2773
- createRouter
3302
+ createRouter,
3303
+ formatRouterConfigIssues,
3304
+ getRouterConfigIssues,
3305
+ mppFromEnv,
3306
+ paidOptionsForProtocols,
3307
+ validateRouterConfig,
3308
+ x402AcceptsFromEnv
2774
3309
  };