@agentcash/router 1.7.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -264,12 +264,139 @@ var init_facilitators = __esm({
264
264
  }
265
265
  });
266
266
 
267
+ // src/kv-store/facilitator-supported.ts
268
+ function withCachedSupported(inner, options = {}) {
269
+ const { kv, cacheKey, ttlSeconds = FACILITATOR_SUPPORTED_TTL_SECONDS, fallback } = options;
270
+ const kvKey = kv && cacheKey ? `${FACILITATOR_SUPPORTED_KV_PREFIX}${cacheKey}` : void 0;
271
+ let inflight;
272
+ return {
273
+ verify: inner.verify.bind(inner),
274
+ settle: inner.settle.bind(inner),
275
+ getSupported: () => {
276
+ if (inflight) return inflight;
277
+ const attempt = fetchSupported(inner, kv, kvKey, ttlSeconds, fallback);
278
+ inflight = attempt;
279
+ attempt.catch(() => {
280
+ if (inflight === attempt) inflight = void 0;
281
+ });
282
+ return attempt;
283
+ }
284
+ };
285
+ }
286
+ async function fetchSupported(inner, kv, kvKey, ttlSeconds, fallback) {
287
+ if (kv && kvKey) {
288
+ const cached = await readKvCache(kv, kvKey);
289
+ if (cached) return cached;
290
+ }
291
+ const fresh = await tryFetchLive(inner, fallback);
292
+ if (fresh === null) return fallback();
293
+ if (kv && kvKey) await writeKvCache(kv, kvKey, fresh, ttlSeconds);
294
+ return fresh;
295
+ }
296
+ async function tryFetchLive(inner, fallback) {
297
+ try {
298
+ return await inner.getSupported();
299
+ } catch (err) {
300
+ if (!fallback) throw err;
301
+ console.warn(
302
+ `[x402] facilitator /supported failed, using hardcoded baseline: ${err instanceof Error ? err.message : String(err)}`
303
+ );
304
+ return null;
305
+ }
306
+ }
307
+ async function readKvCache(kv, key) {
308
+ try {
309
+ const cached = await kv.get(key);
310
+ return isSupportedResponse(cached) ? cached : void 0;
311
+ } catch {
312
+ return void 0;
313
+ }
314
+ }
315
+ async function writeKvCache(kv, key, value, ttlSeconds) {
316
+ try {
317
+ await kv.setNxEx(key, value, ttlSeconds);
318
+ } catch {
319
+ }
320
+ }
321
+ function isSupportedResponse(value) {
322
+ return typeof value === "object" && value !== null && Array.isArray(value.kinds);
323
+ }
324
+ var FACILITATOR_SUPPORTED_TTL_SECONDS, FACILITATOR_SUPPORTED_KV_PREFIX;
325
+ var init_facilitator_supported = __esm({
326
+ "src/kv-store/facilitator-supported.ts"() {
327
+ "use strict";
328
+ FACILITATOR_SUPPORTED_TTL_SECONDS = 60 * 60;
329
+ FACILITATOR_SUPPORTED_KV_PREFIX = "x402:facilitator-supported:";
330
+ }
331
+ });
332
+
333
+ // src/protocols/x402/facilitator-clients.ts
334
+ function createFacilitatorClients(facilitatorsByNetwork, HTTPFacilitatorClient, kvStore) {
335
+ return getResolvedX402FacilitatorGroups(facilitatorsByNetwork).map((group) => {
336
+ const inner = new HTTPFacilitatorClient(group.config);
337
+ const kinds = buildSupportedKinds(group);
338
+ const baseline = () => ({
339
+ kinds,
340
+ extensions: [],
341
+ signers: {}
342
+ });
343
+ if (group.family === "solana") {
344
+ return hardcodedSupportedClient(inner, baseline);
345
+ }
346
+ const cached = withCachedSupported(inner, {
347
+ kv: kvStore,
348
+ cacheKey: group.config.url,
349
+ fallback: baseline
350
+ });
351
+ return withScopedKinds(cached, kinds);
352
+ });
353
+ }
354
+ function hardcodedSupportedClient(inner, build) {
355
+ return {
356
+ verify: inner.verify.bind(inner),
357
+ settle: inner.settle.bind(inner),
358
+ getSupported: async () => build()
359
+ };
360
+ }
361
+ function withScopedKinds(client, kinds) {
362
+ return {
363
+ verify: client.verify.bind(client),
364
+ settle: client.settle.bind(client),
365
+ getSupported: async () => ({ ...await client.getSupported(), kinds })
366
+ };
367
+ }
368
+ function buildSupportedKinds(group) {
369
+ return group.networks.flatMap((network) => {
370
+ if (group.family === "solana") {
371
+ return [
372
+ {
373
+ x402Version: 2,
374
+ scheme: "exact",
375
+ network,
376
+ extra: { features: { xSettlementAccountSupported: true } }
377
+ }
378
+ ];
379
+ }
380
+ return [
381
+ { x402Version: 2, scheme: "exact", network },
382
+ { x402Version: 2, scheme: "upto", network }
383
+ ];
384
+ });
385
+ }
386
+ var init_facilitator_clients = __esm({
387
+ "src/protocols/x402/facilitator-clients.ts"() {
388
+ "use strict";
389
+ init_facilitator_supported();
390
+ init_facilitators();
391
+ }
392
+ });
393
+
267
394
  // src/init/x402-server.ts
268
395
  var x402_server_exports = {};
269
396
  __export(x402_server_exports, {
270
397
  createX402Server: () => createX402Server
271
398
  });
272
- async function createX402Server(config) {
399
+ async function createX402Server(config, kvStore) {
273
400
  const { x402ResourceServer, HTTPFacilitatorClient } = await import("@x402/core/server");
274
401
  const { registerExactEvmScheme } = await import("@x402/evm/exact/server");
275
402
  const { bazaarResourceServerExtension } = await import("@x402/extensions/bazaar");
@@ -283,7 +410,11 @@ async function createX402Server(config) {
283
410
  );
284
411
  const evmNetworks = filterEvmNetworks(configuredNetworks);
285
412
  const svmNetworks = filterSolanaNetworks(configuredNetworks);
286
- const facilitatorClients = createFacilitatorClients(facilitatorsByNetwork, HTTPFacilitatorClient);
413
+ const facilitatorClients = createFacilitatorClients(
414
+ facilitatorsByNetwork,
415
+ HTTPFacilitatorClient,
416
+ kvStore
417
+ );
287
418
  const server = new x402ResourceServer(
288
419
  facilitatorClients.length === 1 ? facilitatorClients[0] : facilitatorClients
289
420
  );
@@ -307,48 +438,13 @@ async function createX402Server(config) {
307
438
  facilitatorsByNetwork
308
439
  };
309
440
  }
310
- function createFacilitatorClients(facilitatorsByNetwork, HTTPFacilitatorClient) {
311
- const groups = getResolvedX402FacilitatorGroups(facilitatorsByNetwork);
312
- return groups.map((group) => {
313
- const inner = new HTTPFacilitatorClient(group.config);
314
- const kinds = buildSupportedKinds(group);
315
- return hardcodedSupportedClient(inner, kinds);
316
- });
317
- }
318
- function hardcodedSupportedClient(inner, kinds) {
319
- return {
320
- verify: inner.verify.bind(inner),
321
- settle: inner.settle.bind(inner),
322
- getSupported: async () => ({ kinds, extensions: [], signers: {} })
323
- };
324
- }
325
- function buildSupportedKinds(group) {
326
- return group.networks.flatMap((network) => {
327
- const exactKind = {
328
- x402Version: 2,
329
- scheme: "exact",
330
- network,
331
- ...group.family === "solana" ? {
332
- extra: {
333
- features: {
334
- xSettlementAccountSupported: true
335
- }
336
- }
337
- } : {}
338
- };
339
- const uptoKind = { x402Version: 2, scheme: "upto", network };
340
- if (group.family === "evm") {
341
- return [exactKind, uptoKind];
342
- }
343
- return [exactKind, uptoKind];
344
- });
345
- }
346
441
  var init_x402_server = __esm({
347
442
  "src/init/x402-server.ts"() {
348
443
  "use strict";
349
444
  init_evm();
350
445
  init_solana();
351
446
  init_facilitators();
447
+ init_facilitator_clients();
352
448
  init_accepts();
353
449
  }
354
450
  });
@@ -1069,6 +1165,61 @@ async function runApiKeyOnlyFlow(ctx) {
1069
1165
  return runHandlerOnly(ctx, null, result.account);
1070
1166
  }
1071
1167
 
1168
+ // src/pricing/format.ts
1169
+ var USDC_DECIMALS = 6;
1170
+ var DECIMAL_RE = /^(\d+)(?:\.(\d+))?$/;
1171
+ function badDecimal(amount) {
1172
+ return Object.assign(new Error(`'${amount}' is not a valid decimal-dollar string`), {
1173
+ status: 400
1174
+ });
1175
+ }
1176
+ function decimalToAtomic(amount, decimals = USDC_DECIMALS) {
1177
+ const match = DECIMAL_RE.exec(amount.trim());
1178
+ if (!match) throw badDecimal(amount);
1179
+ const whole = match[1];
1180
+ const fraction = match[2] ?? "";
1181
+ if (fraction.length > decimals) {
1182
+ throw Object.assign(new Error(`Amount '${amount}' exceeds ${decimals} decimal places`), {
1183
+ status: 400
1184
+ });
1185
+ }
1186
+ const normalized = `${whole}${fraction.padEnd(decimals, "0")}`.replace(/^0+(?=\d)/, "");
1187
+ return BigInt(normalized || "0");
1188
+ }
1189
+ function atomicToDecimal(atomic, decimals = USDC_DECIMALS) {
1190
+ const divisor = 10n ** BigInt(decimals);
1191
+ const whole = atomic / divisor;
1192
+ const fraction = atomic % divisor;
1193
+ if (fraction === 0n) return whole.toString();
1194
+ const fractionStr = fraction.toString().padStart(decimals, "0").replace(/0+$/, "");
1195
+ return `${whole}.${fractionStr}`;
1196
+ }
1197
+ function compareDecimals(a, b) {
1198
+ const av = decimalToAtomic(a);
1199
+ const bv = decimalToAtomic(b);
1200
+ if (av < bv) return -1;
1201
+ if (av > bv) return 1;
1202
+ return 0;
1203
+ }
1204
+ function isPositiveDecimal(value) {
1205
+ try {
1206
+ return decimalToAtomic(value) > 0n;
1207
+ } catch {
1208
+ return false;
1209
+ }
1210
+ }
1211
+ function multiplyDecimal(decimal, factor) {
1212
+ if (!Number.isFinite(factor) || factor <= 0) return decimal;
1213
+ const [whole, fraction = ""] = decimal.split(".");
1214
+ const scaled = (BigInt(whole + fraction) * BigInt(factor)).toString();
1215
+ const decimals = fraction.length;
1216
+ if (decimals === 0) return scaled;
1217
+ const padded = scaled.padStart(decimals + 1, "0");
1218
+ const intPart = padded.slice(0, padded.length - decimals);
1219
+ const fracPart = padded.slice(padded.length - decimals).replace(/0+$/, "");
1220
+ return fracPart ? `${intPart}.${fracPart}` : intPart;
1221
+ }
1222
+
1072
1223
  // src/pricing/dynamic.ts
1073
1224
  var DynamicPricing = class {
1074
1225
  constructor(opts) {
@@ -1104,9 +1255,13 @@ var DynamicPricing = class {
1104
1255
  }
1105
1256
  cap(raw, body) {
1106
1257
  if (!this.opts.maxPrice) return raw;
1107
- const n = parseFloat(raw);
1108
- const max = parseFloat(this.opts.maxPrice);
1109
- if (!Number.isFinite(n) || n > max) {
1258
+ let overCap;
1259
+ try {
1260
+ overCap = compareDecimals(raw, this.opts.maxPrice) > 0;
1261
+ } catch {
1262
+ overCap = true;
1263
+ }
1264
+ if (overCap) {
1110
1265
  this.alert("warn", `Price ${raw} exceeds maxPrice ${this.opts.maxPrice}, capping`, {
1111
1266
  calculated: raw,
1112
1267
  maxPrice: this.opts.maxPrice,
@@ -1183,7 +1338,7 @@ var TieredPricing = class {
1183
1338
  maxTierPrice() {
1184
1339
  let max = "0";
1185
1340
  for (const tier of Object.values(this.opts.tiers)) {
1186
- if (parseFloat(tier.price) > parseFloat(max)) max = tier.price;
1341
+ if (compareDecimals(tier.price, max) > 0) max = tier.price;
1187
1342
  }
1188
1343
  return max;
1189
1344
  }
@@ -1661,17 +1816,6 @@ var mppStrategy = {
1661
1816
  return buildChargeChallenge(args);
1662
1817
  }
1663
1818
  };
1664
- function multiplyDecimal(decimal, factor) {
1665
- if (!Number.isFinite(factor) || factor <= 0) return decimal;
1666
- const [whole, fraction = ""] = decimal.split(".");
1667
- const scaled = (BigInt(whole + fraction) * BigInt(factor)).toString();
1668
- const decimals = fraction.length;
1669
- if (decimals === 0) return scaled;
1670
- const padded = scaled.padStart(decimals + 1, "0");
1671
- const intPart = padded.slice(0, padded.length - decimals);
1672
- const fracPart = padded.slice(padded.length - decimals).replace(/0+$/, "");
1673
- return fracPart ? `${intPart}.${fracPart}` : intPart;
1674
- }
1675
1819
  async function buildChargeChallenge(args) {
1676
1820
  if (!args.deps.mppx) return {};
1677
1821
  try {
@@ -1764,26 +1908,13 @@ function buildCustomRequirement(price, accept) {
1764
1908
  return {
1765
1909
  scheme: accept.scheme,
1766
1910
  network: accept.network,
1767
- amount: decimalToAtomicUnits(price, accept.decimals ?? 6),
1911
+ amount: decimalToAtomic(price, accept.decimals ?? 6).toString(),
1768
1912
  asset: accept.asset,
1769
1913
  payTo: accept.payTo,
1770
1914
  maxTimeoutSeconds: accept.maxTimeoutSeconds ?? 300,
1771
1915
  extra: accept.extra ?? {}
1772
1916
  };
1773
1917
  }
1774
- function decimalToAtomicUnits(amount, decimals) {
1775
- const match = /^(?<whole>\d+)(?:\.(?<fraction>\d+))?$/.exec(amount);
1776
- if (!match?.groups) {
1777
- throw new Error(`Invalid decimal amount '${amount}'`);
1778
- }
1779
- const whole = match.groups.whole;
1780
- const fraction = match.groups.fraction ?? "";
1781
- if (fraction.length > decimals) {
1782
- throw new Error(`Amount '${amount}' exceeds ${decimals} decimal places`);
1783
- }
1784
- const normalized = `${whole}${fraction.padEnd(decimals, "0")}`.replace(/^0+(?=\d)/, "");
1785
- return normalized === "" ? "0" : normalized;
1786
- }
1787
1918
 
1788
1919
  // src/protocols/x402/challenge.ts
1789
1920
  async function buildX402Challenge(opts) {
@@ -2146,13 +2277,14 @@ async function buildX402ChallengeContribution(args) {
2146
2277
  }
2147
2278
  function reportSettleFailure(report, err, network) {
2148
2279
  const facilitator = err ?? {};
2149
- report("error", "Settlement failed", {
2280
+ const meta = {
2150
2281
  error: err instanceof Error ? err.message : String(err),
2151
2282
  network,
2152
2283
  errorReason: facilitator.errorReason,
2153
2284
  facilitatorStatus: facilitator.response?.status,
2154
2285
  facilitatorBody: facilitator.response?.data ?? facilitator.response?.body
2155
- });
2286
+ };
2287
+ report("error", "Settlement failed", meta);
2156
2288
  }
2157
2289
 
2158
2290
  // src/protocols/index.ts
@@ -2175,6 +2307,7 @@ function getAllowedStrategies(allowed) {
2175
2307
  var import_server4 = require("next/server");
2176
2308
 
2177
2309
  // src/pipeline/challenge-extensions.ts
2310
+ init_evm();
2178
2311
  async function buildChallengeExtensions(ctx) {
2179
2312
  const { routeEntry } = ctx;
2180
2313
  let extensions;
@@ -2219,6 +2352,23 @@ async function buildChallengeExtensions(ctx) {
2219
2352
  } catch {
2220
2353
  }
2221
2354
  }
2355
+ const hasEvmUpto = ctx.deps.x402Accepts.some(
2356
+ (accept) => accept.scheme === "upto" && isEvmNetwork(accept.network)
2357
+ );
2358
+ if (hasEvmUpto) {
2359
+ try {
2360
+ const { declareEip2612GasSponsoringExtension } = await import("@x402/extensions");
2361
+ extensions = {
2362
+ ...extensions ?? {},
2363
+ ...declareEip2612GasSponsoringExtension()
2364
+ };
2365
+ } catch (err) {
2366
+ ctx.report(
2367
+ "warn",
2368
+ `EIP-2612 gas-sponsoring declaration failed: ${err instanceof Error ? err.message : String(err)}`
2369
+ );
2370
+ }
2371
+ }
2222
2372
  return extensions;
2223
2373
  }
2224
2374
 
@@ -2374,27 +2524,6 @@ async function runDynamicChannelMgmtFlow(args) {
2374
2524
  // src/pipeline/flows/dynamic/dynamic-invoke.ts
2375
2525
  var import_server6 = require("next/server");
2376
2526
 
2377
- // src/pricing/atomic.ts
2378
- var USDC_DECIMALS = 6;
2379
- function decimalToAtomic(amount) {
2380
- const m = /^(\d+)(?:\.(\d+))?$/.exec(amount.trim());
2381
- if (!m) {
2382
- throw Object.assign(new Error(`'${amount}' is not a valid decimal-dollar string`), {
2383
- status: 400
2384
- });
2385
- }
2386
- const whole = m[1];
2387
- const fraction = (m[2] ?? "").slice(0, USDC_DECIMALS).padEnd(USDC_DECIMALS, "0");
2388
- return BigInt(`${whole}${fraction}`.replace(/^0+(?=\d)/, "") || "0");
2389
- }
2390
- function atomicToDecimal(atomic) {
2391
- const whole = atomic / 10n ** BigInt(USDC_DECIMALS);
2392
- const fraction = atomic % 10n ** BigInt(USDC_DECIMALS);
2393
- if (fraction === 0n) return whole.toString();
2394
- const fractionStr = fraction.toString().padStart(USDC_DECIMALS, "0").replace(/0+$/, "");
2395
- return `${whole}.${fractionStr}`;
2396
- }
2397
-
2398
2527
  // src/pricing/charge-context.ts
2399
2528
  function createChargeContext(args) {
2400
2529
  const { tickCost, maxPrice, route } = args;
@@ -2805,6 +2934,19 @@ async function runPaidFlow(ctx) {
2805
2934
  var import_server7 = require("next/server");
2806
2935
 
2807
2936
  // src/kv-store/client.ts
2937
+ var BIGINT_SUFFIX = "#__bigint";
2938
+ function stringifyValue(value) {
2939
+ return JSON.stringify(
2940
+ value,
2941
+ (_key, v) => typeof v === "bigint" ? `${v.toString()}${BIGINT_SUFFIX}` : v
2942
+ );
2943
+ }
2944
+ function parseValue(raw) {
2945
+ return JSON.parse(
2946
+ raw,
2947
+ (_key, v) => typeof v === "string" && v.endsWith(BIGINT_SUFFIX) ? BigInt(v.slice(0, -BIGINT_SUFFIX.length)) : v
2948
+ );
2949
+ }
2808
2950
  function restKvStore(url, token) {
2809
2951
  const base = url.replace(/\/+$/, "");
2810
2952
  const authHeader = { Authorization: `Bearer ${token}` };
@@ -2826,16 +2968,22 @@ function restKvStore(url, token) {
2826
2968
  const res = await fetch(`${base}/get/${encodeURIComponent(key)}`, { headers: authHeader });
2827
2969
  if (!res.ok) throw new Error(`[kv-store] GET ${key}: ${res.status}`);
2828
2970
  const { result } = await res.json();
2829
- return result ?? null;
2971
+ if (result == null) return null;
2972
+ if (typeof result !== "string") return result;
2973
+ try {
2974
+ return parseValue(result);
2975
+ } catch {
2976
+ return result;
2977
+ }
2830
2978
  }
2831
2979
  async function set(key, value) {
2832
- await exec(["SET", key, JSON.stringify(value)]);
2980
+ await exec(["SET", key, stringifyValue(value)]);
2833
2981
  }
2834
2982
  async function del(key) {
2835
2983
  await exec(["DEL", key]);
2836
2984
  }
2837
2985
  async function setNxEx(key, value, ttlSeconds) {
2838
- const result = await exec(["SET", key, JSON.stringify(value), "EX", ttlSeconds, "NX"]);
2986
+ const result = await exec(["SET", key, stringifyValue(value), "EX", ttlSeconds, "NX"]);
2839
2987
  return result === "OK";
2840
2988
  }
2841
2989
  async function sadd(key, member) {
@@ -3164,142 +3312,109 @@ ${issues}`
3164
3312
  }
3165
3313
 
3166
3314
  // src/builder.ts
3167
- var RouteBuilder = class {
3168
- /** @internal */
3169
- _key;
3170
- /** @internal */
3171
- _registry;
3172
- /** @internal */
3173
- _deps;
3174
- /** @internal */
3175
- _authMode = null;
3176
- /** @internal */
3177
- _pricing;
3178
- /** @internal */
3179
- _siwxEnabled = false;
3180
- /** @internal */
3181
- _protocols = ["x402"];
3182
- /** @internal */
3183
- _maxPrice;
3184
- /** @internal */
3185
- _minPrice;
3186
- /** @internal */
3187
- _dynamicPrice = false;
3188
- /** @internal */
3189
- _tickCost;
3190
- /** @internal */
3191
- _unitType;
3192
- /** @internal */
3193
- _payTo;
3194
- /** @internal */
3195
- _bodySchema;
3196
- /** @internal */
3197
- _querySchema;
3198
- /** @internal */
3199
- _outputSchema;
3200
- /** @internal */
3201
- _inputExample = void 0;
3202
- /** @internal */
3203
- _hasInputExample = false;
3204
- /** @internal */
3205
- _outputExample = void 0;
3206
- /** @internal */
3207
- _hasOutputExample = false;
3208
- /** @internal */
3209
- _description;
3210
- /** @internal */
3211
- _path;
3212
- /** @internal */
3213
- _method = "POST";
3214
- /** @internal */
3215
- _apiKeyResolver;
3216
- /** @internal */
3217
- _providerName;
3218
- /** @internal */
3219
- _providerConfig;
3220
- /** @internal */
3221
- _validateFn;
3222
- /** @internal */
3223
- _settlement;
3224
- /** @internal */
3225
- _mppInfo;
3226
- constructor(key, registry, deps) {
3227
- this._key = key;
3228
- this._registry = registry;
3229
- this._deps = deps;
3315
+ var RouteBuilder = class _RouteBuilder {
3316
+ #s;
3317
+ constructor(key, registry, deps, defaults) {
3318
+ this.#s = {
3319
+ key,
3320
+ registry,
3321
+ deps,
3322
+ authMode: null,
3323
+ pricing: void 0,
3324
+ siwxEnabled: false,
3325
+ protocols: defaults?.protocols ? [...defaults.protocols] : ["x402"],
3326
+ maxPrice: void 0,
3327
+ minPrice: void 0,
3328
+ dynamicPrice: false,
3329
+ tickCost: void 0,
3330
+ unitType: void 0,
3331
+ payTo: void 0,
3332
+ bodySchema: void 0,
3333
+ querySchema: void 0,
3334
+ outputSchema: void 0,
3335
+ inputExample: void 0,
3336
+ hasInputExample: false,
3337
+ outputExample: void 0,
3338
+ hasOutputExample: false,
3339
+ description: void 0,
3340
+ path: void 0,
3341
+ method: "POST",
3342
+ apiKeyResolver: void 0,
3343
+ providerName: void 0,
3344
+ providerConfig: void 0,
3345
+ validateFn: void 0,
3346
+ settlement: void 0,
3347
+ mppInfo: void 0
3348
+ };
3230
3349
  }
3231
3350
  fork() {
3232
- const next = Object.create(Object.getPrototypeOf(this));
3233
- Object.assign(next, this);
3234
- next._protocols = [...this._protocols];
3351
+ const next = new _RouteBuilder(
3352
+ this.#s.key,
3353
+ this.#s.registry,
3354
+ this.#s.deps
3355
+ );
3356
+ next.#s = { ...this.#s, protocols: [...this.#s.protocols] };
3235
3357
  return next;
3236
3358
  }
3237
3359
  paid(pricingOrOptions, options) {
3238
- const { pricing, resolvedOptions } = resolvePaidArgs(this._key, pricingOrOptions, options);
3239
- if (this._authMode === "unprotected") {
3360
+ const { pricing, resolvedOptions } = resolvePaidArgs(this.#s.key, pricingOrOptions, options);
3361
+ if (this.#s.authMode === "unprotected") {
3240
3362
  throw new Error(
3241
- `route '${this._key}': Cannot combine .unprotected() and .paid() on the same route.`
3363
+ `route '${this.#s.key}': Cannot combine .unprotected() and .paid() on the same route.`
3242
3364
  );
3243
3365
  }
3244
- if (this._pricing !== void 0) {
3366
+ if (this.#s.pricing !== void 0) {
3245
3367
  throw new Error(
3246
- `route '${this._key}': Cannot call .paid() more than once on the same route.`
3368
+ `route '${this.#s.key}': Cannot call .paid() more than once on the same route.`
3247
3369
  );
3248
3370
  }
3249
3371
  const next = this.fork();
3250
- next._authMode = "paid";
3251
- next._pricing = pricing;
3372
+ next.#s.authMode = "paid";
3373
+ next.#s.pricing = pricing;
3252
3374
  if (resolvedOptions?.protocols) {
3253
- next._protocols = [...resolvedOptions.protocols];
3254
- } else if (next._protocols.length === 0) {
3255
- next._protocols = ["x402"];
3375
+ next.#s.protocols = [...resolvedOptions.protocols];
3376
+ } else if (next.#s.protocols.length === 0) {
3377
+ next.#s.protocols = ["x402"];
3256
3378
  }
3257
- if (resolvedOptions?.maxPrice) next._maxPrice = resolvedOptions.maxPrice;
3258
- if (resolvedOptions?.minPrice) next._minPrice = resolvedOptions.minPrice;
3259
- if (resolvedOptions?.payTo) next._payTo = resolvedOptions.payTo;
3260
- if (resolvedOptions?.mpp) next._mppInfo = resolvedOptions.mpp;
3261
- if (resolvedOptions?.dynamic) next._dynamicPrice = true;
3262
- if (resolvedOptions?.tickCost) next._tickCost = resolvedOptions.tickCost;
3263
- if (resolvedOptions?.unitType) next._unitType = resolvedOptions.unitType;
3379
+ if (resolvedOptions?.maxPrice) next.#s.maxPrice = resolvedOptions.maxPrice;
3380
+ if (resolvedOptions?.minPrice) next.#s.minPrice = resolvedOptions.minPrice;
3381
+ if (resolvedOptions?.payTo) next.#s.payTo = resolvedOptions.payTo;
3382
+ if (resolvedOptions?.mpp) next.#s.mppInfo = resolvedOptions.mpp;
3383
+ if (resolvedOptions?.dynamic) next.#s.dynamicPrice = true;
3384
+ if (resolvedOptions?.tickCost) next.#s.tickCost = resolvedOptions.tickCost;
3385
+ if (resolvedOptions?.unitType) next.#s.unitType = resolvedOptions.unitType;
3264
3386
  if (typeof pricing === "object" && "tiers" in pricing) {
3265
- if (next._dynamicPrice) {
3387
+ if (next.#s.dynamicPrice) {
3266
3388
  throw new Error(
3267
- `route '${this._key}': .paid({ dynamic: true }) is incompatible with tiered pricing`
3389
+ `route '${this.#s.key}': .paid({ dynamic: true }) is incompatible with tiered pricing`
3268
3390
  );
3269
3391
  }
3270
3392
  for (const [tierKey, tierConfig] of Object.entries(pricing.tiers)) {
3271
3393
  if (!tierKey) {
3272
- throw new Error(`route '${this._key}': tier key cannot be empty`);
3394
+ throw new Error(`route '${this.#s.key}': tier key cannot be empty`);
3273
3395
  }
3274
- const tierPrice = parseFloat(tierConfig.price);
3275
- if (isNaN(tierPrice) || tierPrice <= 0) {
3396
+ if (!isPositiveDecimal(tierConfig.price)) {
3276
3397
  throw new Error(
3277
- `route '${this._key}': tier '${tierKey}' price '${tierConfig.price}' must be a positive decimal string`
3398
+ `route '${this.#s.key}': tier '${tierKey}' price '${tierConfig.price}' must be a positive decimal string`
3278
3399
  );
3279
3400
  }
3280
3401
  }
3281
3402
  }
3282
- if (resolvedOptions?.maxPrice !== void 0) {
3283
- const parsed = parseFloat(resolvedOptions.maxPrice);
3284
- if (isNaN(parsed) || parsed <= 0) {
3285
- throw new Error(
3286
- `route '${this._key}': maxPrice '${resolvedOptions.maxPrice}' must be a positive decimal string`
3287
- );
3288
- }
3403
+ if (resolvedOptions?.maxPrice !== void 0 && !isPositiveDecimal(resolvedOptions.maxPrice)) {
3404
+ throw new Error(
3405
+ `route '${this.#s.key}': maxPrice '${resolvedOptions.maxPrice}' must be a positive decimal string`
3406
+ );
3289
3407
  }
3290
- if (resolvedOptions?.tickCost !== void 0) {
3291
- const parsed = parseFloat(resolvedOptions.tickCost);
3292
- if (isNaN(parsed) || parsed <= 0) {
3293
- throw new Error(
3294
- `route '${this._key}': tickCost '${resolvedOptions.tickCost}' must be a positive decimal string`
3295
- );
3296
- }
3408
+ if (resolvedOptions?.tickCost !== void 0 && !isPositiveDecimal(resolvedOptions.tickCost)) {
3409
+ throw new Error(
3410
+ `route '${this.#s.key}': tickCost '${resolvedOptions.tickCost}' must be a positive decimal string`
3411
+ );
3297
3412
  }
3298
- if (next._dynamicPrice && !next._maxPrice) {
3299
- throw new Error(`route '${this._key}': .paid({ dynamic: true }) requires maxPrice`);
3413
+ if (next.#s.dynamicPrice && !next.#s.maxPrice) {
3414
+ throw new Error(`route '${this.#s.key}': .paid({ dynamic: true }) requires maxPrice`);
3300
3415
  }
3301
- if (next._dynamicPrice && !next._tickCost) {
3302
- throw new Error(`route '${this._key}': .paid({ dynamic: true }) requires tickCost`);
3416
+ if (next.#s.dynamicPrice && !next.#s.tickCost) {
3417
+ throw new Error(`route '${this.#s.key}': .paid({ dynamic: true }) requires tickCost`);
3303
3418
  }
3304
3419
  return next;
3305
3420
  }
@@ -3314,25 +3429,25 @@ var RouteBuilder = class {
3314
3429
  * ```
3315
3430
  */
3316
3431
  siwx() {
3317
- if (this._authMode === "unprotected") {
3432
+ if (this.#s.authMode === "unprotected") {
3318
3433
  throw new Error(
3319
- `route '${this._key}': Cannot combine .unprotected() and .siwx() on the same route.`
3434
+ `route '${this.#s.key}': Cannot combine .unprotected() and .siwx() on the same route.`
3320
3435
  );
3321
3436
  }
3322
- if (this._apiKeyResolver) {
3437
+ if (this.#s.apiKeyResolver) {
3323
3438
  throw new Error(
3324
- `route '${this._key}': Combining .siwx() and .apiKey() is not supported on the same route.`
3439
+ `route '${this.#s.key}': Combining .siwx() and .apiKey() is not supported on the same route.`
3325
3440
  );
3326
3441
  }
3327
3442
  const next = this.fork();
3328
- next._siwxEnabled = true;
3329
- if (next._authMode === "paid" || next._pricing) {
3330
- next._authMode = "paid";
3331
- if (next._protocols.length === 0) next._protocols = ["x402"];
3443
+ next.#s.siwxEnabled = true;
3444
+ if (next.#s.authMode === "paid" || next.#s.pricing) {
3445
+ next.#s.authMode = "paid";
3446
+ if (next.#s.protocols.length === 0) next.#s.protocols = ["x402"];
3332
3447
  return next;
3333
3448
  }
3334
- next._authMode = "siwx";
3335
- next._protocols = [];
3449
+ next.#s.authMode = "siwx";
3450
+ next.#s.protocols = [];
3336
3451
  return next;
3337
3452
  }
3338
3453
  /**
@@ -3349,14 +3464,14 @@ var RouteBuilder = class {
3349
3464
  * ```
3350
3465
  */
3351
3466
  apiKey(resolver) {
3352
- if (this._siwxEnabled) {
3467
+ if (this.#s.siwxEnabled) {
3353
3468
  throw new Error(
3354
- `route '${this._key}': Combining .apiKey() and .siwx() is not supported on the same route.`
3469
+ `route '${this.#s.key}': Combining .apiKey() and .siwx() is not supported on the same route.`
3355
3470
  );
3356
3471
  }
3357
3472
  const next = this.fork();
3358
- next._authMode = "apiKey";
3359
- next._apiKeyResolver = resolver;
3473
+ next.#s.authMode = "apiKey";
3474
+ next.#s.apiKeyResolver = resolver;
3360
3475
  return next;
3361
3476
  }
3362
3477
  /**
@@ -3369,19 +3484,19 @@ var RouteBuilder = class {
3369
3484
  * ```
3370
3485
  */
3371
3486
  unprotected() {
3372
- if (this._authMode && this._authMode !== "unprotected") {
3487
+ if (this.#s.authMode && this.#s.authMode !== "unprotected") {
3373
3488
  throw new Error(
3374
- `route '${this._key}': Cannot combine .unprotected() and .${this._authMode}() on the same route.`
3489
+ `route '${this.#s.key}': Cannot combine .unprotected() and .${this.#s.authMode}() on the same route.`
3375
3490
  );
3376
3491
  }
3377
- if (this._pricing) {
3492
+ if (this.#s.pricing) {
3378
3493
  throw new Error(
3379
- `route '${this._key}': Cannot combine .unprotected() and .paid() on the same route.`
3494
+ `route '${this.#s.key}': Cannot combine .unprotected() and .paid() on the same route.`
3380
3495
  );
3381
3496
  }
3382
3497
  const next = this.fork();
3383
- next._authMode = "unprotected";
3384
- next._protocols = [];
3498
+ next.#s.authMode = "unprotected";
3499
+ next.#s.protocols = [];
3385
3500
  return next;
3386
3501
  }
3387
3502
  /**
@@ -3400,8 +3515,8 @@ var RouteBuilder = class {
3400
3515
  */
3401
3516
  provider(name, config) {
3402
3517
  const next = this.fork();
3403
- next._providerName = name;
3404
- next._providerConfig = config ?? {};
3518
+ next.#s.providerName = name;
3519
+ next.#s.providerConfig = config ?? {};
3405
3520
  return next;
3406
3521
  }
3407
3522
  /**
@@ -3416,7 +3531,7 @@ var RouteBuilder = class {
3416
3531
  */
3417
3532
  body(schema) {
3418
3533
  const next = this.fork();
3419
- next._bodySchema = schema;
3534
+ next.#s.bodySchema = schema;
3420
3535
  return next;
3421
3536
  }
3422
3537
  /**
@@ -3432,8 +3547,8 @@ var RouteBuilder = class {
3432
3547
  */
3433
3548
  query(schema) {
3434
3549
  const next = this.fork();
3435
- next._querySchema = schema;
3436
- next._method = "GET";
3550
+ next.#s.querySchema = schema;
3551
+ next.#s.method = "GET";
3437
3552
  return next;
3438
3553
  }
3439
3554
  /**
@@ -3450,7 +3565,7 @@ var RouteBuilder = class {
3450
3565
  */
3451
3566
  output(schema) {
3452
3567
  const next = this.fork();
3453
- next._outputSchema = schema;
3568
+ next.#s.outputSchema = schema;
3454
3569
  return next;
3455
3570
  }
3456
3571
  /**
@@ -3464,8 +3579,8 @@ var RouteBuilder = class {
3464
3579
  */
3465
3580
  inputExample(example) {
3466
3581
  const next = this.fork();
3467
- next._inputExample = example;
3468
- next._hasInputExample = true;
3582
+ next.#s.inputExample = example;
3583
+ next.#s.hasInputExample = true;
3469
3584
  return next;
3470
3585
  }
3471
3586
  /**
@@ -3479,8 +3594,8 @@ var RouteBuilder = class {
3479
3594
  */
3480
3595
  outputExample(example) {
3481
3596
  const next = this.fork();
3482
- next._outputExample = example;
3483
- next._hasOutputExample = true;
3597
+ next.#s.outputExample = example;
3598
+ next.#s.hasOutputExample = true;
3484
3599
  return next;
3485
3600
  }
3486
3601
  /**
@@ -3494,7 +3609,7 @@ var RouteBuilder = class {
3494
3609
  */
3495
3610
  description(text) {
3496
3611
  const next = this.fork();
3497
- next._description = text;
3612
+ next.#s.description = text;
3498
3613
  return next;
3499
3614
  }
3500
3615
  /**
@@ -3508,7 +3623,7 @@ var RouteBuilder = class {
3508
3623
  */
3509
3624
  path(p) {
3510
3625
  const next = this.fork();
3511
- next._path = p;
3626
+ next.#s.path = p;
3512
3627
  return next;
3513
3628
  }
3514
3629
  /**
@@ -3522,7 +3637,7 @@ var RouteBuilder = class {
3522
3637
  */
3523
3638
  method(m) {
3524
3639
  const next = this.fork();
3525
- next._method = m;
3640
+ next.#s.method = m;
3526
3641
  return next;
3527
3642
  }
3528
3643
  /**
@@ -3541,7 +3656,7 @@ var RouteBuilder = class {
3541
3656
  */
3542
3657
  validate(fn) {
3543
3658
  const next = this.fork();
3544
- next._validateFn = fn;
3659
+ next.#s.validateFn = fn;
3545
3660
  return next;
3546
3661
  }
3547
3662
  /**
@@ -3559,7 +3674,7 @@ var RouteBuilder = class {
3559
3674
  */
3560
3675
  settlement(lifecycle) {
3561
3676
  const next = this.fork();
3562
- next._settlement = lifecycle;
3677
+ next.#s.settlement = lifecycle;
3563
3678
  return next;
3564
3679
  }
3565
3680
  /**
@@ -3602,79 +3717,79 @@ var RouteBuilder = class {
3602
3717
  return this.register(fn, true);
3603
3718
  }
3604
3719
  register(handlerFn, streaming) {
3605
- if (!this._authMode) {
3720
+ if (!this.#s.authMode) {
3606
3721
  throw new Error(
3607
- `route '${this._key}': Select an auth mode: .paid(pricing), .siwx(), .apiKey(resolver), or .unprotected()`
3722
+ `route '${this.#s.key}': Select an auth mode: .paid(pricing), .siwx(), .apiKey(resolver), or .unprotected()`
3608
3723
  );
3609
3724
  }
3610
- if (this._validateFn && !this._bodySchema) {
3725
+ if (this.#s.validateFn && !this.#s.bodySchema) {
3611
3726
  throw new Error(
3612
- `route '${this._key}': .validate() requires .body() \u2014 validation runs on parsed body`
3727
+ `route '${this.#s.key}': .validate() requires .body() \u2014 validation runs on parsed body`
3613
3728
  );
3614
3729
  }
3615
- if (this._settlement && !this._pricing) {
3616
- throw new Error(`route '${this._key}': .settlement() requires a paid route`);
3730
+ if (this.#s.settlement && !this.#s.pricing) {
3731
+ throw new Error(`route '${this.#s.key}': .settlement() requires a paid route`);
3617
3732
  }
3618
- if (this._dynamicPrice && this._protocols.includes("x402")) {
3619
- const hasUpto = this._deps.x402Accepts.some((accept) => accept.scheme === "upto");
3733
+ if (this.#s.dynamicPrice && this.#s.protocols.includes("x402")) {
3734
+ const hasUpto = this.#s.deps.x402Accepts.some((accept) => accept.scheme === "upto");
3620
3735
  if (!hasUpto) {
3621
3736
  throw new Error(
3622
- `route '${this._key}': .paid({ dynamic: true }) on an x402 route requires an 'upto' accept on at least one configured network. Add { scheme: 'upto', network, asset } to RouterConfig.x402.accepts.`
3737
+ `route '${this.#s.key}': .paid({ dynamic: true }) on an x402 route requires an 'upto' accept on at least one configured network. Add { scheme: 'upto', network, asset } to RouterConfig.x402.accepts.`
3623
3738
  );
3624
3739
  }
3625
3740
  }
3626
- if (this._dynamicPrice && this._protocols.includes("mpp")) {
3627
- if (!this._deps.mppSessionConfig) {
3741
+ if (this.#s.dynamicPrice && this.#s.protocols.includes("mpp")) {
3742
+ if (!this.#s.deps.mppSessionConfig) {
3628
3743
  throw new Error(
3629
- `route '${this._key}': .paid({ dynamic: true }) on an MPP route requires session mode. Set RouterConfig.mpp.session = {} and provide mpp.operatorKey.`
3744
+ `route '${this.#s.key}': .paid({ dynamic: true }) on an MPP route requires session mode. Set RouterConfig.mpp.session = {} and provide mpp.operatorKey.`
3630
3745
  );
3631
3746
  }
3632
3747
  }
3633
- if (streaming && !this._dynamicPrice) {
3748
+ if (streaming && !this.#s.dynamicPrice) {
3634
3749
  throw new Error(
3635
- `route '${this._key}': .stream() requires .paid({ dynamic: true }) \u2014 static/free routes can't meter per-chunk billing.`
3750
+ `route '${this.#s.key}': .stream() requires .paid({ dynamic: true }) \u2014 static/free routes can't meter per-chunk billing.`
3636
3751
  );
3637
3752
  }
3638
3753
  validateExamples(
3639
- this._key,
3640
- this._bodySchema,
3641
- this._querySchema,
3642
- this._outputSchema,
3643
- this._inputExample,
3644
- this._hasInputExample,
3645
- this._outputExample,
3646
- this._hasOutputExample
3754
+ this.#s.key,
3755
+ this.#s.bodySchema,
3756
+ this.#s.querySchema,
3757
+ this.#s.outputSchema,
3758
+ this.#s.inputExample,
3759
+ this.#s.hasInputExample,
3760
+ this.#s.outputExample,
3761
+ this.#s.hasOutputExample
3647
3762
  );
3648
3763
  const entry = {
3649
- key: this._key,
3650
- authMode: this._authMode,
3651
- siwxEnabled: this._siwxEnabled,
3652
- pricing: this._pricing,
3653
- dynamicPrice: this._dynamicPrice ? true : void 0,
3764
+ key: this.#s.key,
3765
+ authMode: this.#s.authMode,
3766
+ siwxEnabled: this.#s.siwxEnabled,
3767
+ pricing: this.#s.pricing,
3768
+ dynamicPrice: this.#s.dynamicPrice ? true : void 0,
3654
3769
  streaming: streaming ? true : void 0,
3655
- protocols: this._protocols,
3656
- bodySchema: this._bodySchema,
3657
- querySchema: this._querySchema,
3658
- outputSchema: this._outputSchema,
3659
- inputExample: this._hasInputExample ? this._inputExample : void 0,
3660
- outputExample: this._hasOutputExample ? this._outputExample : void 0,
3661
- description: this._description,
3662
- path: this._path,
3663
- method: this._method,
3664
- maxPrice: this._maxPrice,
3665
- minPrice: this._minPrice,
3666
- payTo: this._payTo,
3667
- apiKeyResolver: this._apiKeyResolver,
3668
- providerName: this._providerName,
3669
- providerConfig: this._providerConfig,
3670
- validateFn: this._validateFn,
3671
- settlement: this._settlement,
3672
- mppInfo: this._mppInfo,
3673
- tickCost: this._tickCost,
3674
- unitType: this._unitType
3770
+ protocols: this.#s.protocols,
3771
+ bodySchema: this.#s.bodySchema,
3772
+ querySchema: this.#s.querySchema,
3773
+ outputSchema: this.#s.outputSchema,
3774
+ inputExample: this.#s.hasInputExample ? this.#s.inputExample : void 0,
3775
+ outputExample: this.#s.hasOutputExample ? this.#s.outputExample : void 0,
3776
+ description: this.#s.description,
3777
+ path: this.#s.path,
3778
+ method: this.#s.method,
3779
+ maxPrice: this.#s.maxPrice,
3780
+ minPrice: this.#s.minPrice,
3781
+ payTo: this.#s.payTo,
3782
+ apiKeyResolver: this.#s.apiKeyResolver,
3783
+ providerName: this.#s.providerName,
3784
+ providerConfig: this.#s.providerConfig,
3785
+ validateFn: this.#s.validateFn,
3786
+ settlement: this.#s.settlement,
3787
+ mppInfo: this.#s.mppInfo,
3788
+ tickCost: this.#s.tickCost,
3789
+ unitType: this.#s.unitType
3675
3790
  };
3676
- this._registry.register(entry);
3677
- return createRequestHandler(entry, handlerFn, this._deps);
3791
+ this.#s.registry.register(entry);
3792
+ return createRequestHandler(entry, handlerFn, this.#s.deps);
3678
3793
  }
3679
3794
  };
3680
3795
  function resolvePaidArgs(routeKey, pricingOrOptions, options) {
@@ -3918,17 +4033,16 @@ function buildPricingInfo(entry) {
3918
4033
  };
3919
4034
  }
3920
4035
  if ("tiers" in entry.pricing) {
3921
- const tierPrices = Object.values(entry.pricing.tiers).map((tier) => parseFloat(tier.price));
3922
- const min = Math.min(...tierPrices);
3923
- const max = Math.max(...tierPrices);
3924
- if (Number.isFinite(min) && Number.isFinite(max)) {
3925
- if (min === max) {
4036
+ const tierPrices = Object.values(entry.pricing.tiers).map((tier) => tier.price);
4037
+ const extrema = tierExtrema(tierPrices);
4038
+ if (extrema) {
4039
+ if (extrema.min === extrema.max) {
3926
4040
  return {
3927
- price: { mode: "fixed", currency: "USD", amount: String(min) }
4041
+ price: { mode: "fixed", currency: "USD", amount: extrema.min }
3928
4042
  };
3929
4043
  }
3930
4044
  return {
3931
- price: { mode: "dynamic", currency: "USD", min: String(min), max: String(max) }
4045
+ price: { mode: "dynamic", currency: "USD", min: extrema.min, max: extrema.max }
3932
4046
  };
3933
4047
  }
3934
4048
  return {
@@ -3942,6 +4056,20 @@ function buildPricingInfo(entry) {
3942
4056
  }
3943
4057
  return void 0;
3944
4058
  }
4059
+ function tierExtrema(prices) {
4060
+ if (prices.length === 0) return null;
4061
+ let min = prices[0];
4062
+ let max = prices[0];
4063
+ try {
4064
+ for (const price of prices.slice(1)) {
4065
+ if (compareDecimals(price, min) < 0) min = price;
4066
+ if (compareDecimals(price, max) > 0) max = price;
4067
+ }
4068
+ } catch {
4069
+ return null;
4070
+ }
4071
+ return { min, max };
4072
+ }
3945
4073
 
3946
4074
  // src/discovery/llms-txt.ts
3947
4075
  var import_server10 = require("next/server");
@@ -4428,11 +4556,11 @@ function getRouterConfigIssues(config, options = {}) {
4428
4556
  }
4429
4557
 
4430
4558
  // src/init/x402.ts
4431
- async function initX402(config, configError) {
4559
+ async function initX402(config, kvStore, configError) {
4432
4560
  if (configError) return { initError: configError };
4433
4561
  try {
4434
4562
  const { createX402Server: createX402Server2 } = await Promise.resolve().then(() => (init_x402_server(), x402_server_exports));
4435
- const result = await createX402Server2(config);
4563
+ const result = await createX402Server2(config, kvStore);
4436
4564
  await result.initPromise;
4437
4565
  return {
4438
4566
  server: result.server,
@@ -4615,7 +4743,7 @@ function createRouter(config) {
4615
4743
  mppSessionConfig: config.mpp?.session ? { depositMultiplier: config.mpp.session.depositMultiplier ?? 10 } : null
4616
4744
  };
4617
4745
  deps.initPromise = (async () => {
4618
- const x402Result = await initX402(config, x402ConfigError);
4746
+ const x402Result = await initX402(config, kvStore, x402ConfigError);
4619
4747
  deps.x402Server = x402Result.server ?? null;
4620
4748
  deps.x402FacilitatorsByNetwork = x402Result.facilitatorsByNetwork;
4621
4749
  if (x402Result.initError) deps.x402InitError = x402Result.initError;
@@ -4644,11 +4772,10 @@ function createRouter(config) {
4644
4772
  `[router] strictRoutes=true forbids key/path divergence for route '${definition.path}'. Remove custom \`key\` or make it equal to \`path\`.`
4645
4773
  );
4646
4774
  }
4647
- let builder = new RouteBuilder(key, registry, deps);
4775
+ let builder = new RouteBuilder(key, registry, deps, {
4776
+ protocols: config.protocols
4777
+ });
4648
4778
  builder = builder.path(normalizedPath);
4649
- if (config.protocols) {
4650
- builder._protocols = [...config.protocols];
4651
- }
4652
4779
  if (definition.method) {
4653
4780
  builder = builder.method(definition.method);
4654
4781
  }