@agentcash/router 1.6.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/AGENTS.md +85 -0
- package/README.md +133 -550
- package/dist/index.cjs +993 -824
- package/dist/index.d.cts +96 -101
- package/dist/index.d.ts +96 -101
- package/dist/index.js +985 -805
- package/package.json +6 -14
- package/.claude/CLAUDE.md +0 -343
- package/.claude/skills/router-guide/SKILL.md +0 -585
package/dist/index.cjs
CHANGED
|
@@ -31,14 +31,18 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
31
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
32
|
|
|
33
33
|
// src/constants.ts
|
|
34
|
-
var
|
|
34
|
+
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;
|
|
35
35
|
var init_constants = __esm({
|
|
36
36
|
"src/constants.ts"() {
|
|
37
37
|
"use strict";
|
|
38
|
-
|
|
38
|
+
BASE_MAINNET_NETWORK = "eip155:8453";
|
|
39
39
|
SOLANA_MAINNET_NETWORK = "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp";
|
|
40
|
-
|
|
40
|
+
TEMPO_USDC_ADDRESS = "0x20c000000000000000000000b9537d11c60e8b50";
|
|
41
|
+
TEMPO_USDC_DECIMALS = 6;
|
|
42
|
+
BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
43
|
+
BASE_USDC_DECIMALS = 6;
|
|
41
44
|
ZERO_EVM_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
45
|
+
DEFAULT_SOLANA_FACILITATOR_URL = "https://facilitator.corbits.dev";
|
|
42
46
|
}
|
|
43
47
|
});
|
|
44
48
|
|
|
@@ -55,7 +59,7 @@ function getConfiguredX402Accepts(config) {
|
|
|
55
59
|
return [
|
|
56
60
|
{
|
|
57
61
|
scheme: "exact",
|
|
58
|
-
network: config.network ??
|
|
62
|
+
network: config.network ?? BASE_MAINNET_NETWORK,
|
|
59
63
|
payTo: config.payeeAddress
|
|
60
64
|
}
|
|
61
65
|
];
|
|
@@ -235,7 +239,10 @@ async function getAcceptsHeadersForFacilitator(facilitator) {
|
|
|
235
239
|
return {};
|
|
236
240
|
}
|
|
237
241
|
function resolveX402FacilitatorTarget(config, network, defaultEvmFacilitator) {
|
|
238
|
-
|
|
242
|
+
if (isSolanaNetwork(network)) {
|
|
243
|
+
return config.x402?.facilitators?.solana ?? DEFAULT_SOLANA_FACILITATOR_URL;
|
|
244
|
+
}
|
|
245
|
+
return defaultEvmFacilitator;
|
|
239
246
|
}
|
|
240
247
|
function normalizeFacilitatorTarget(target) {
|
|
241
248
|
return typeof target === "string" ? { url: target } : target;
|
|
@@ -248,22 +255,148 @@ function getNetworkFamily(network) {
|
|
|
248
255
|
function sameFacilitatorConfig(a, b) {
|
|
249
256
|
return a.url === b.url && a.createAuthHeaders === b.createAuthHeaders && a.createAcceptsHeaders === b.createAcceptsHeaders;
|
|
250
257
|
}
|
|
251
|
-
var DEFAULT_SOLANA_FACILITATOR_URL;
|
|
252
258
|
var init_facilitators = __esm({
|
|
253
259
|
"src/protocols/x402/facilitators.ts"() {
|
|
254
260
|
"use strict";
|
|
255
261
|
init_evm();
|
|
256
262
|
init_solana();
|
|
257
|
-
|
|
263
|
+
init_constants();
|
|
264
|
+
}
|
|
265
|
+
});
|
|
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();
|
|
258
391
|
}
|
|
259
392
|
});
|
|
260
393
|
|
|
261
|
-
// src/server.ts
|
|
262
|
-
var
|
|
263
|
-
__export(
|
|
394
|
+
// src/init/x402-server.ts
|
|
395
|
+
var x402_server_exports = {};
|
|
396
|
+
__export(x402_server_exports, {
|
|
264
397
|
createX402Server: () => createX402Server
|
|
265
398
|
});
|
|
266
|
-
async function createX402Server(config) {
|
|
399
|
+
async function createX402Server(config, kvStore) {
|
|
267
400
|
const { x402ResourceServer, HTTPFacilitatorClient } = await import("@x402/core/server");
|
|
268
401
|
const { registerExactEvmScheme } = await import("@x402/evm/exact/server");
|
|
269
402
|
const { bazaarResourceServerExtension } = await import("@x402/extensions/bazaar");
|
|
@@ -277,7 +410,11 @@ async function createX402Server(config) {
|
|
|
277
410
|
);
|
|
278
411
|
const evmNetworks = filterEvmNetworks(configuredNetworks);
|
|
279
412
|
const svmNetworks = filterSolanaNetworks(configuredNetworks);
|
|
280
|
-
const facilitatorClients = createFacilitatorClients(
|
|
413
|
+
const facilitatorClients = createFacilitatorClients(
|
|
414
|
+
facilitatorsByNetwork,
|
|
415
|
+
HTTPFacilitatorClient,
|
|
416
|
+
kvStore
|
|
417
|
+
);
|
|
281
418
|
const server = new x402ResourceServer(
|
|
282
419
|
facilitatorClients.length === 1 ? facilitatorClients[0] : facilitatorClients
|
|
283
420
|
);
|
|
@@ -301,48 +438,13 @@ async function createX402Server(config) {
|
|
|
301
438
|
facilitatorsByNetwork
|
|
302
439
|
};
|
|
303
440
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
return groups.map((group) => {
|
|
307
|
-
const inner = new HTTPFacilitatorClient(group.config);
|
|
308
|
-
const kinds = buildSupportedKinds(group);
|
|
309
|
-
return hardcodedSupportedClient(inner, kinds);
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
function hardcodedSupportedClient(inner, kinds) {
|
|
313
|
-
return {
|
|
314
|
-
verify: inner.verify.bind(inner),
|
|
315
|
-
settle: inner.settle.bind(inner),
|
|
316
|
-
getSupported: async () => ({ kinds, extensions: [], signers: {} })
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
function buildSupportedKinds(group) {
|
|
320
|
-
return group.networks.flatMap((network) => {
|
|
321
|
-
const exactKind = {
|
|
322
|
-
x402Version: 2,
|
|
323
|
-
scheme: "exact",
|
|
324
|
-
network,
|
|
325
|
-
...group.family === "solana" ? {
|
|
326
|
-
extra: {
|
|
327
|
-
features: {
|
|
328
|
-
xSettlementAccountSupported: true
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
} : {}
|
|
332
|
-
};
|
|
333
|
-
const uptoKind = { x402Version: 2, scheme: "upto", network };
|
|
334
|
-
if (group.family === "evm") {
|
|
335
|
-
return [exactKind, uptoKind];
|
|
336
|
-
}
|
|
337
|
-
return [exactKind, uptoKind];
|
|
338
|
-
});
|
|
339
|
-
}
|
|
340
|
-
var init_server = __esm({
|
|
341
|
-
"src/server.ts"() {
|
|
441
|
+
var init_x402_server = __esm({
|
|
442
|
+
"src/init/x402-server.ts"() {
|
|
342
443
|
"use strict";
|
|
343
444
|
init_evm();
|
|
344
445
|
init_solana();
|
|
345
446
|
init_facilitators();
|
|
447
|
+
init_facilitator_clients();
|
|
346
448
|
init_accepts();
|
|
347
449
|
}
|
|
348
450
|
});
|
|
@@ -350,30 +452,19 @@ var init_server = __esm({
|
|
|
350
452
|
// src/index.ts
|
|
351
453
|
var index_exports = {};
|
|
352
454
|
__export(index_exports, {
|
|
353
|
-
|
|
455
|
+
BASE_MAINNET_NETWORK: () => BASE_MAINNET_NETWORK,
|
|
456
|
+
BASE_USDC_ADDRESS: () => BASE_USDC_ADDRESS,
|
|
457
|
+
BASE_USDC_DECIMALS: () => BASE_USDC_DECIMALS,
|
|
458
|
+
DEFAULT_SOLANA_FACILITATOR_URL: () => DEFAULT_SOLANA_FACILITATOR_URL,
|
|
354
459
|
HttpError: () => HttpError,
|
|
355
|
-
MemoryEntitlementStore: () => MemoryEntitlementStore,
|
|
356
|
-
MemoryNonceStore: () => MemoryNonceStore,
|
|
357
|
-
RouteBuilder: () => RouteBuilder,
|
|
358
|
-
RouteRegistry: () => RouteRegistry,
|
|
359
460
|
RouterConfigError: () => RouterConfigError,
|
|
360
|
-
SIWX_CHALLENGE_EXPIRY_MS: () => SIWX_CHALLENGE_EXPIRY_MS,
|
|
361
|
-
SIWX_ERROR_MESSAGES: () => SIWX_ERROR_MESSAGES,
|
|
362
461
|
SOLANA_MAINNET_NETWORK: () => SOLANA_MAINNET_NETWORK,
|
|
363
|
-
|
|
462
|
+
TEMPO_USDC_ADDRESS: () => TEMPO_USDC_ADDRESS,
|
|
463
|
+
TEMPO_USDC_DECIMALS: () => TEMPO_USDC_DECIMALS,
|
|
364
464
|
ZERO_EVM_ADDRESS: () => ZERO_EVM_ADDRESS,
|
|
365
|
-
consolePlugin: () => consolePlugin,
|
|
366
|
-
createKvEntitlementStore: () => createKvEntitlementStore,
|
|
367
|
-
createKvMppStore: () => createKvMppStore,
|
|
368
|
-
createKvNonceStore: () => createKvNonceStore,
|
|
369
465
|
createRouter: () => createRouter,
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
mppFromEnv: () => mppFromEnv,
|
|
373
|
-
paidOptionsForProtocols: () => paidOptionsForProtocols,
|
|
374
|
-
validateRouterConfig: () => validateRouterConfig,
|
|
375
|
-
withPrefix: () => withPrefix,
|
|
376
|
-
x402AcceptsFromEnv: () => x402AcceptsFromEnv
|
|
466
|
+
createRouterFromEnv: () => createRouterFromEnv,
|
|
467
|
+
routerConfigFromEnv: () => routerConfigFromEnv
|
|
377
468
|
});
|
|
378
469
|
module.exports = __toCommonJS(index_exports);
|
|
379
470
|
|
|
@@ -441,7 +532,7 @@ var AUTH_SCHEME = {
|
|
|
441
532
|
MPP_PAYMENT: "Payment "
|
|
442
533
|
};
|
|
443
534
|
|
|
444
|
-
// src/plugin.ts
|
|
535
|
+
// src/plugin/index.ts
|
|
445
536
|
function createDefaultContext(meta) {
|
|
446
537
|
const ctx = {
|
|
447
538
|
requestId: meta.requestId,
|
|
@@ -477,46 +568,8 @@ function firePluginHook(plugin, method, ...args) {
|
|
|
477
568
|
return void 0;
|
|
478
569
|
}
|
|
479
570
|
}
|
|
480
|
-
function consolePlugin() {
|
|
481
|
-
return {
|
|
482
|
-
onRequest(meta) {
|
|
483
|
-
const ctx = createDefaultContext(meta);
|
|
484
|
-
return ctx;
|
|
485
|
-
},
|
|
486
|
-
onAuthVerified(_ctx, auth) {
|
|
487
|
-
const wallet = auth.wallet ? ` wallet=${auth.wallet}` : "";
|
|
488
|
-
console.log(`[router] AUTH ${auth.authMode} ${auth.route}${wallet}`);
|
|
489
|
-
},
|
|
490
|
-
onPaymentVerified(_ctx, payment) {
|
|
491
|
-
console.log(`[router] VERIFIED ${payment.protocol} ${payment.payer} ${payment.amount}`);
|
|
492
|
-
},
|
|
493
|
-
onPaymentSettled(_ctx, settlement) {
|
|
494
|
-
console.log(`[router] SETTLED ${settlement.protocol} tx=${settlement.transaction}`);
|
|
495
|
-
},
|
|
496
|
-
onResponse(ctx, response) {
|
|
497
|
-
const wallet = ctx.verifiedWallet ? ` wallet=${ctx.verifiedWallet}` : "";
|
|
498
|
-
console.log(
|
|
499
|
-
`[router] ${ctx.route} \u2192 ${response.statusCode} (${response.duration}ms)${wallet}`
|
|
500
|
-
);
|
|
501
|
-
},
|
|
502
|
-
onError(_ctx, error) {
|
|
503
|
-
console.error(`[router] ERROR ${error.status}: ${error.message}`);
|
|
504
|
-
},
|
|
505
|
-
onAlert(_ctx, alert) {
|
|
506
|
-
const logFn = alert.level === "critical" || alert.level === "error" ? console.error : alert.level === "warn" ? console.warn : console.log;
|
|
507
|
-
logFn(
|
|
508
|
-
`[router] ${alert.level.toUpperCase()} ${alert.route}: ${alert.message}`,
|
|
509
|
-
alert.meta ?? ""
|
|
510
|
-
);
|
|
511
|
-
},
|
|
512
|
-
onProviderQuota(_ctx, event) {
|
|
513
|
-
const logFn = event.level === "critical" ? console.error : event.level === "warn" ? console.warn : console.log;
|
|
514
|
-
logFn(`[router] QUOTA ${event.level.toUpperCase()} ${event.provider}: ${event.message}`);
|
|
515
|
-
}
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
571
|
|
|
519
|
-
// src/
|
|
572
|
+
// src/plugin/reporter.ts
|
|
520
573
|
function createReporter(plugin, pluginCtx, route) {
|
|
521
574
|
return (level, message, meta) => {
|
|
522
575
|
firePluginHook(plugin, "onAlert", pluginCtx, {
|
|
@@ -528,7 +581,7 @@ function createReporter(plugin, pluginCtx, route) {
|
|
|
528
581
|
};
|
|
529
582
|
}
|
|
530
583
|
|
|
531
|
-
// src/pipeline/
|
|
584
|
+
// src/pipeline/steps/preflight.ts
|
|
532
585
|
function preflight(routeEntry, handler, deps, request) {
|
|
533
586
|
const meta = buildMeta(request, routeEntry);
|
|
534
587
|
const pluginCtx = firePluginHook(deps.plugin, "onRequest", meta) ?? createDefaultContext(meta);
|
|
@@ -558,10 +611,10 @@ function buildMeta(request, routeEntry) {
|
|
|
558
611
|
};
|
|
559
612
|
}
|
|
560
613
|
|
|
561
|
-
// src/pipeline/
|
|
614
|
+
// src/pipeline/steps/parse-body.ts
|
|
562
615
|
var import_server = require("next/server");
|
|
563
616
|
|
|
564
|
-
// src/body.ts
|
|
617
|
+
// src/pipeline/body.ts
|
|
565
618
|
async function bufferBody(request) {
|
|
566
619
|
const text = await request.text();
|
|
567
620
|
if (!text) return void 0;
|
|
@@ -585,7 +638,19 @@ function validateBody(parsed, schema) {
|
|
|
585
638
|
};
|
|
586
639
|
}
|
|
587
640
|
|
|
588
|
-
// src/
|
|
641
|
+
// src/plugin/events.ts
|
|
642
|
+
function fireAuthVerified(ctx, event) {
|
|
643
|
+
firePluginHook(ctx.deps.plugin, "onAuthVerified", ctx.pluginCtx, {
|
|
644
|
+
...event,
|
|
645
|
+
route: ctx.routeEntry.key
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
function firePaymentVerified(ctx, event) {
|
|
649
|
+
firePluginHook(ctx.deps.plugin, "onPaymentVerified", ctx.pluginCtx, event);
|
|
650
|
+
}
|
|
651
|
+
function firePaymentSettled(ctx, event) {
|
|
652
|
+
firePluginHook(ctx.deps.plugin, "onPaymentSettled", ctx.pluginCtx, event);
|
|
653
|
+
}
|
|
589
654
|
function firePluginResponse(ctx, response, requestBody, responseBody) {
|
|
590
655
|
firePluginHook(ctx.deps.plugin, "onResponse", ctx.pluginCtx, {
|
|
591
656
|
statusCode: response.status,
|
|
@@ -604,8 +669,37 @@ function firePluginResponse(ctx, response, requestBody, responseBody) {
|
|
|
604
669
|
});
|
|
605
670
|
}
|
|
606
671
|
}
|
|
672
|
+
function fireProviderQuota(ctx, response, handlerResult) {
|
|
673
|
+
const { providerName, providerConfig } = ctx.routeEntry;
|
|
674
|
+
if (!providerName || !providerConfig?.extractQuota) return;
|
|
675
|
+
if (response.status >= 400) return;
|
|
676
|
+
try {
|
|
677
|
+
const quota = providerConfig.extractQuota(handlerResult, response.headers);
|
|
678
|
+
if (!quota) return;
|
|
679
|
+
const level = computeQuotaLevel(quota.remaining, providerConfig.warn, providerConfig.critical);
|
|
680
|
+
const overage = providerConfig.overage ?? "same-rate";
|
|
681
|
+
const event = {
|
|
682
|
+
provider: providerName,
|
|
683
|
+
route: ctx.routeEntry.key,
|
|
684
|
+
remaining: quota.remaining,
|
|
685
|
+
limit: quota.limit,
|
|
686
|
+
spend: quota.spend,
|
|
687
|
+
level,
|
|
688
|
+
overage,
|
|
689
|
+
message: quota.remaining !== null ? `${providerName}: ${quota.remaining}${quota.limit ? `/${quota.limit}` : ""} remaining` : `${providerName}: quota info unavailable`
|
|
690
|
+
};
|
|
691
|
+
firePluginHook(ctx.deps.plugin, "onProviderQuota", ctx.pluginCtx, event);
|
|
692
|
+
} catch {
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
function computeQuotaLevel(remaining, warn, critical) {
|
|
696
|
+
if (remaining === null) return "healthy";
|
|
697
|
+
if (critical !== void 0 && remaining <= critical) return "critical";
|
|
698
|
+
if (warn !== void 0 && remaining <= warn) return "warn";
|
|
699
|
+
return "healthy";
|
|
700
|
+
}
|
|
607
701
|
|
|
608
|
-
// src/pipeline/
|
|
702
|
+
// src/pipeline/steps/parse-body.ts
|
|
609
703
|
async function parseBody(ctx, request = ctx.request) {
|
|
610
704
|
if (!ctx.routeEntry.bodySchema) return { ok: true, data: void 0 };
|
|
611
705
|
const raw = await bufferBody(request);
|
|
@@ -619,15 +713,7 @@ async function parseBody(ctx, request = ctx.request) {
|
|
|
619
713
|
return { ok: false, response };
|
|
620
714
|
}
|
|
621
715
|
|
|
622
|
-
// src/pipeline/
|
|
623
|
-
function parseQuery(request, routeEntry) {
|
|
624
|
-
if (!routeEntry.querySchema) return void 0;
|
|
625
|
-
const params = Object.fromEntries(request.nextUrl.searchParams.entries());
|
|
626
|
-
const result = routeEntry.querySchema.safeParse(params);
|
|
627
|
-
return result.success ? result.data : params;
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
// src/pipeline/context/errors.ts
|
|
716
|
+
// src/pipeline/steps/errors.ts
|
|
631
717
|
function errorStatus(error, fallback) {
|
|
632
718
|
const status = error?.status;
|
|
633
719
|
return typeof status === "number" ? status : fallback;
|
|
@@ -640,7 +726,7 @@ function handlerFailureError(response) {
|
|
|
640
726
|
return Object.assign(new Error(message), { status: response.status });
|
|
641
727
|
}
|
|
642
728
|
|
|
643
|
-
// src/pipeline/
|
|
729
|
+
// src/pipeline/steps/fail.ts
|
|
644
730
|
var import_server2 = require("next/server");
|
|
645
731
|
function fail(ctx, status, message, requestBody) {
|
|
646
732
|
const response = import_server2.NextResponse.json({ success: false, error: message }, { status });
|
|
@@ -648,7 +734,7 @@ function fail(ctx, status, message, requestBody) {
|
|
|
648
734
|
return response;
|
|
649
735
|
}
|
|
650
736
|
|
|
651
|
-
// src/pipeline/
|
|
737
|
+
// src/pipeline/steps/run-validate.ts
|
|
652
738
|
async function runValidate(ctx, body) {
|
|
653
739
|
if (!ctx.routeEntry.validateFn) return null;
|
|
654
740
|
try {
|
|
@@ -671,6 +757,14 @@ var HttpError = class extends Error {
|
|
|
671
757
|
}
|
|
672
758
|
};
|
|
673
759
|
|
|
760
|
+
// src/pipeline/steps/parse-query.ts
|
|
761
|
+
function parseQuery(request, routeEntry) {
|
|
762
|
+
if (!routeEntry.querySchema) return void 0;
|
|
763
|
+
const params = Object.fromEntries(request.nextUrl.searchParams.entries());
|
|
764
|
+
const result = routeEntry.querySchema.safeParse(params);
|
|
765
|
+
return result.success ? result.data : params;
|
|
766
|
+
}
|
|
767
|
+
|
|
674
768
|
// src/pipeline/flows/static/static-invoke.ts
|
|
675
769
|
function invokePaidStatic(ctx, wallet, account, body, payment) {
|
|
676
770
|
return runHandler(ctx, buildHandlerCtx(ctx, wallet, account, body, payment));
|
|
@@ -688,14 +782,7 @@ function buildHandlerCtx(ctx, wallet, account, body, payment) {
|
|
|
688
782
|
wallet,
|
|
689
783
|
payment,
|
|
690
784
|
account,
|
|
691
|
-
alert
|
|
692
|
-
firePluginHook(ctx.deps.plugin, "onAlert", ctx.pluginCtx, {
|
|
693
|
-
level,
|
|
694
|
-
message,
|
|
695
|
-
route: ctx.routeEntry.key,
|
|
696
|
-
meta: alertMeta
|
|
697
|
-
});
|
|
698
|
-
},
|
|
785
|
+
alert: ctx.report,
|
|
699
786
|
setVerifiedWallet: (addr) => ctx.pluginCtx.setVerifiedWallet(addr)
|
|
700
787
|
};
|
|
701
788
|
}
|
|
@@ -739,45 +826,14 @@ function isThenable(value) {
|
|
|
739
826
|
return value != null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
|
|
740
827
|
}
|
|
741
828
|
|
|
742
|
-
// src/pipeline/
|
|
743
|
-
function fireProviderQuota(ctx, response, handlerResult) {
|
|
744
|
-
const { providerName, providerConfig } = ctx.routeEntry;
|
|
745
|
-
if (!providerName || !providerConfig?.extractQuota) return;
|
|
746
|
-
if (response.status >= 400) return;
|
|
747
|
-
try {
|
|
748
|
-
const quota = providerConfig.extractQuota(handlerResult, response.headers);
|
|
749
|
-
if (!quota) return;
|
|
750
|
-
const level = computeQuotaLevel(quota.remaining, providerConfig.warn, providerConfig.critical);
|
|
751
|
-
const overage = providerConfig.overage ?? "same-rate";
|
|
752
|
-
const event = {
|
|
753
|
-
provider: providerName,
|
|
754
|
-
route: ctx.routeEntry.key,
|
|
755
|
-
remaining: quota.remaining,
|
|
756
|
-
limit: quota.limit,
|
|
757
|
-
spend: quota.spend,
|
|
758
|
-
level,
|
|
759
|
-
overage,
|
|
760
|
-
message: quota.remaining !== null ? `${providerName}: ${quota.remaining}${quota.limit ? `/${quota.limit}` : ""} remaining` : `${providerName}: quota info unavailable`
|
|
761
|
-
};
|
|
762
|
-
firePluginHook(ctx.deps.plugin, "onProviderQuota", ctx.pluginCtx, event);
|
|
763
|
-
} catch {
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
function computeQuotaLevel(remaining, warn, critical) {
|
|
767
|
-
if (remaining === null) return "healthy";
|
|
768
|
-
if (critical !== void 0 && remaining <= critical) return "critical";
|
|
769
|
-
if (warn !== void 0 && remaining <= warn) return "warn";
|
|
770
|
-
return "healthy";
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
// src/pipeline/context/finalize/response.ts
|
|
829
|
+
// src/pipeline/steps/finalize/response.ts
|
|
774
830
|
function finalize(ctx, response, rawResult, requestBody) {
|
|
775
831
|
fireProviderQuota(ctx, response, rawResult);
|
|
776
832
|
firePluginResponse(ctx, response, requestBody, rawResult);
|
|
777
833
|
return response;
|
|
778
834
|
}
|
|
779
835
|
|
|
780
|
-
// src/pipeline/
|
|
836
|
+
// src/pipeline/steps/grant-entitlement.ts
|
|
781
837
|
async function grantEntitlementIfSiwx(ctx, wallet) {
|
|
782
838
|
if (!ctx.routeEntry.siwxEnabled) return;
|
|
783
839
|
try {
|
|
@@ -790,7 +846,7 @@ async function grantEntitlementIfSiwx(ctx, wallet) {
|
|
|
790
846
|
}
|
|
791
847
|
}
|
|
792
848
|
|
|
793
|
-
// src/pipeline/
|
|
849
|
+
// src/pipeline/steps/settlement-context.ts
|
|
794
850
|
function settlementContext(ctx, scope) {
|
|
795
851
|
return {
|
|
796
852
|
route: ctx.routeEntry.key,
|
|
@@ -804,7 +860,7 @@ function settlementContext(ctx, scope) {
|
|
|
804
860
|
};
|
|
805
861
|
}
|
|
806
862
|
|
|
807
|
-
// src/pipeline/
|
|
863
|
+
// src/pipeline/steps/run-settlement-error.ts
|
|
808
864
|
async function runSettlementError(ctx, scope, error, phase) {
|
|
809
865
|
const hook = ctx.routeEntry.settlement?.onSettlementError;
|
|
810
866
|
if (!hook) return;
|
|
@@ -816,7 +872,7 @@ async function runSettlementError(ctx, scope, error, phase) {
|
|
|
816
872
|
}
|
|
817
873
|
}
|
|
818
874
|
|
|
819
|
-
// src/pipeline/
|
|
875
|
+
// src/pipeline/steps/run-after-settle.ts
|
|
820
876
|
async function runAfterSettle(ctx, scope) {
|
|
821
877
|
const hook = ctx.routeEntry.settlement?.afterSettle;
|
|
822
878
|
if (!hook) return;
|
|
@@ -829,11 +885,11 @@ async function runAfterSettle(ctx, scope) {
|
|
|
829
885
|
}
|
|
830
886
|
}
|
|
831
887
|
|
|
832
|
-
// src/pipeline/
|
|
888
|
+
// src/pipeline/steps/finalize/epilogue.ts
|
|
833
889
|
async function runPostSettleEpilogue(args) {
|
|
834
890
|
const { ctx, strategy, wallet, settle, afterSettleScope, rawResult, body } = args;
|
|
835
891
|
await grantEntitlementIfSiwx(ctx, wallet);
|
|
836
|
-
|
|
892
|
+
firePaymentSettled(ctx, {
|
|
837
893
|
protocol: strategy.protocol,
|
|
838
894
|
payer: wallet,
|
|
839
895
|
transaction: settle.settledPayment.transaction ?? "",
|
|
@@ -843,7 +899,7 @@ async function runPostSettleEpilogue(args) {
|
|
|
843
899
|
return finalize(ctx, settle.response, rawResult, body);
|
|
844
900
|
}
|
|
845
901
|
|
|
846
|
-
// src/pipeline/
|
|
902
|
+
// src/pipeline/steps/finalize/request.ts
|
|
847
903
|
async function settleAndFinalizeRequest(args) {
|
|
848
904
|
const { ctx, strategy, verifyOutcome, scope, rawResult, body, billedAmount, onSettleError } = args;
|
|
849
905
|
const { request, routeEntry, deps, report } = ctx;
|
|
@@ -876,7 +932,7 @@ async function settleAndFinalizeRequest(args) {
|
|
|
876
932
|
});
|
|
877
933
|
}
|
|
878
934
|
|
|
879
|
-
// src/pipeline/
|
|
935
|
+
// src/pipeline/steps/finalize/stream.ts
|
|
880
936
|
async function settleAndFinalizeStream(args) {
|
|
881
937
|
const { ctx, strategy, verifyOutcome, source, account, body, bindChannelCharge } = args;
|
|
882
938
|
const { request, routeEntry, deps, report } = ctx;
|
|
@@ -914,7 +970,7 @@ async function settleAndFinalizeStream(args) {
|
|
|
914
970
|
});
|
|
915
971
|
}
|
|
916
972
|
|
|
917
|
-
// src/pipeline/
|
|
973
|
+
// src/pipeline/steps/run-handler-only.ts
|
|
918
974
|
async function runHandlerOnly(ctx, wallet, account) {
|
|
919
975
|
const body = await parseBody(ctx);
|
|
920
976
|
if (!body.ok) return body.response;
|
|
@@ -924,7 +980,7 @@ async function runHandlerOnly(ctx, wallet, account) {
|
|
|
924
980
|
return finalize(ctx, result.response, result.rawResult, body.data);
|
|
925
981
|
}
|
|
926
982
|
|
|
927
|
-
// src/pipeline/
|
|
983
|
+
// src/pipeline/steps/run-before-settle.ts
|
|
928
984
|
async function runBeforeSettle(ctx, scope) {
|
|
929
985
|
const hook = ctx.routeEntry.settlement?.beforeSettle;
|
|
930
986
|
if (!hook) return null;
|
|
@@ -941,7 +997,7 @@ async function runBeforeSettle(ctx, scope) {
|
|
|
941
997
|
}
|
|
942
998
|
}
|
|
943
999
|
|
|
944
|
-
// src/pipeline/
|
|
1000
|
+
// src/pipeline/steps/run-settled-handler-error.ts
|
|
945
1001
|
async function runSettledHandlerError(ctx, scope, error = scope.handlerError ?? handlerFailureError(scope.response)) {
|
|
946
1002
|
const hook = ctx.routeEntry.settlement?.onSettledHandlerError;
|
|
947
1003
|
if (!hook) return;
|
|
@@ -1015,7 +1071,7 @@ async function buildSIWXExtension() {
|
|
|
1015
1071
|
return declareSIWxExtension();
|
|
1016
1072
|
}
|
|
1017
1073
|
|
|
1018
|
-
// src/pipeline/
|
|
1074
|
+
// src/pipeline/steps/try-siwx-fast-path.ts
|
|
1019
1075
|
async function trySiwxFastPath(ctx, account) {
|
|
1020
1076
|
const { request, routeEntry, deps } = ctx;
|
|
1021
1077
|
if (!routeEntry.siwxEnabled) return null;
|
|
@@ -1027,22 +1083,18 @@ async function trySiwxFastPath(ctx, account) {
|
|
|
1027
1083
|
ctx.pluginCtx.setVerifiedWallet(wallet);
|
|
1028
1084
|
const entitled = await deps.entitlementStore.has(routeEntry.key, wallet);
|
|
1029
1085
|
if (!entitled) return null;
|
|
1030
|
-
|
|
1031
|
-
authMode: "siwx",
|
|
1032
|
-
wallet,
|
|
1033
|
-
route: routeEntry.key
|
|
1034
|
-
});
|
|
1086
|
+
fireAuthVerified(ctx, { authMode: "siwx", wallet });
|
|
1035
1087
|
return runHandlerOnly(ctx, wallet, account);
|
|
1036
1088
|
}
|
|
1037
1089
|
|
|
1038
|
-
// src/pipeline/
|
|
1090
|
+
// src/pipeline/steps/should-parse-body-early.ts
|
|
1039
1091
|
function shouldParseBodyEarly(incomingStrategy, routeEntry, pricing) {
|
|
1040
1092
|
if (incomingStrategy) return false;
|
|
1041
1093
|
if (!routeEntry.bodySchema) return false;
|
|
1042
1094
|
return (pricing?.needsBody ?? false) || !!routeEntry.validateFn;
|
|
1043
1095
|
}
|
|
1044
1096
|
|
|
1045
|
-
// src/pipeline/
|
|
1097
|
+
// src/pipeline/steps/resolve-early-body.ts
|
|
1046
1098
|
async function resolveEarlyBody(args) {
|
|
1047
1099
|
const { ctx, pricing, incomingStrategy } = args;
|
|
1048
1100
|
if (!shouldParseBodyEarly(incomingStrategy, ctx.routeEntry, pricing)) {
|
|
@@ -1074,24 +1126,19 @@ function extractBearerToken(header) {
|
|
|
1074
1126
|
return null;
|
|
1075
1127
|
}
|
|
1076
1128
|
|
|
1077
|
-
// src/pipeline/
|
|
1129
|
+
// src/pipeline/steps/run-api-key-gate.ts
|
|
1078
1130
|
async function runApiKeyGate(ctx) {
|
|
1079
|
-
const { request, routeEntry
|
|
1131
|
+
const { request, routeEntry } = ctx;
|
|
1080
1132
|
if (!routeEntry.apiKeyResolver) return { ok: true, account: void 0 };
|
|
1081
1133
|
const apiKeyResult = await verifyApiKey(request, routeEntry.apiKeyResolver);
|
|
1082
1134
|
if (!apiKeyResult.valid) {
|
|
1083
1135
|
return { ok: false, response: fail(ctx, 401, "Invalid or missing API key") };
|
|
1084
1136
|
}
|
|
1085
|
-
|
|
1086
|
-
authMode: "apiKey",
|
|
1087
|
-
wallet: null,
|
|
1088
|
-
route: routeEntry.key,
|
|
1089
|
-
account: apiKeyResult.account
|
|
1090
|
-
});
|
|
1137
|
+
fireAuthVerified(ctx, { authMode: "apiKey", wallet: null, account: apiKeyResult.account });
|
|
1091
1138
|
return { ok: true, account: apiKeyResult.account };
|
|
1092
1139
|
}
|
|
1093
1140
|
|
|
1094
|
-
// src/pipeline/
|
|
1141
|
+
// src/pipeline/steps/protocol-init-error.ts
|
|
1095
1142
|
function protocolInitError(routeEntry, deps) {
|
|
1096
1143
|
if (!routeEntry.pricing) return null;
|
|
1097
1144
|
const errors = [];
|
|
@@ -1114,15 +1161,65 @@ async function runApiKeyOnlyFlow(ctx) {
|
|
|
1114
1161
|
}
|
|
1115
1162
|
const result = await verifyApiKey(ctx.request, ctx.routeEntry.apiKeyResolver);
|
|
1116
1163
|
if (!result.valid) return fail(ctx, 401, "Invalid or missing API key");
|
|
1117
|
-
|
|
1118
|
-
authMode: "apiKey",
|
|
1119
|
-
wallet: null,
|
|
1120
|
-
route: ctx.routeEntry.key,
|
|
1121
|
-
account: result.account
|
|
1122
|
-
});
|
|
1164
|
+
fireAuthVerified(ctx, { authMode: "apiKey", wallet: null, account: result.account });
|
|
1123
1165
|
return runHandlerOnly(ctx, null, result.account);
|
|
1124
1166
|
}
|
|
1125
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
|
+
|
|
1126
1223
|
// src/pricing/dynamic.ts
|
|
1127
1224
|
var DynamicPricing = class {
|
|
1128
1225
|
constructor(opts) {
|
|
@@ -1158,9 +1255,13 @@ var DynamicPricing = class {
|
|
|
1158
1255
|
}
|
|
1159
1256
|
cap(raw, body) {
|
|
1160
1257
|
if (!this.opts.maxPrice) return raw;
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1258
|
+
let overCap;
|
|
1259
|
+
try {
|
|
1260
|
+
overCap = compareDecimals(raw, this.opts.maxPrice) > 0;
|
|
1261
|
+
} catch {
|
|
1262
|
+
overCap = true;
|
|
1263
|
+
}
|
|
1264
|
+
if (overCap) {
|
|
1164
1265
|
this.alert("warn", `Price ${raw} exceeds maxPrice ${this.opts.maxPrice}, capping`, {
|
|
1165
1266
|
calculated: raw,
|
|
1166
1267
|
maxPrice: this.opts.maxPrice,
|
|
@@ -1237,7 +1338,7 @@ var TieredPricing = class {
|
|
|
1237
1338
|
maxTierPrice() {
|
|
1238
1339
|
let max = "0";
|
|
1239
1340
|
for (const tier of Object.values(this.opts.tiers)) {
|
|
1240
|
-
if (
|
|
1341
|
+
if (compareDecimals(tier.price, max) > 0) max = tier.price;
|
|
1241
1342
|
}
|
|
1242
1343
|
return max;
|
|
1243
1344
|
}
|
|
@@ -1715,17 +1816,6 @@ var mppStrategy = {
|
|
|
1715
1816
|
return buildChargeChallenge(args);
|
|
1716
1817
|
}
|
|
1717
1818
|
};
|
|
1718
|
-
function multiplyDecimal(decimal, factor) {
|
|
1719
|
-
if (!Number.isFinite(factor) || factor <= 0) return decimal;
|
|
1720
|
-
const [whole, fraction = ""] = decimal.split(".");
|
|
1721
|
-
const scaled = (BigInt(whole + fraction) * BigInt(factor)).toString();
|
|
1722
|
-
const decimals = fraction.length;
|
|
1723
|
-
if (decimals === 0) return scaled;
|
|
1724
|
-
const padded = scaled.padStart(decimals + 1, "0");
|
|
1725
|
-
const intPart = padded.slice(0, padded.length - decimals);
|
|
1726
|
-
const fracPart = padded.slice(padded.length - decimals).replace(/0+$/, "");
|
|
1727
|
-
return fracPart ? `${intPart}.${fracPart}` : intPart;
|
|
1728
|
-
}
|
|
1729
1819
|
async function buildChargeChallenge(args) {
|
|
1730
1820
|
if (!args.deps.mppx) return {};
|
|
1731
1821
|
try {
|
|
@@ -1818,26 +1908,13 @@ function buildCustomRequirement(price, accept) {
|
|
|
1818
1908
|
return {
|
|
1819
1909
|
scheme: accept.scheme,
|
|
1820
1910
|
network: accept.network,
|
|
1821
|
-
amount:
|
|
1911
|
+
amount: decimalToAtomic(price, accept.decimals ?? 6).toString(),
|
|
1822
1912
|
asset: accept.asset,
|
|
1823
1913
|
payTo: accept.payTo,
|
|
1824
1914
|
maxTimeoutSeconds: accept.maxTimeoutSeconds ?? 300,
|
|
1825
1915
|
extra: accept.extra ?? {}
|
|
1826
1916
|
};
|
|
1827
1917
|
}
|
|
1828
|
-
function decimalToAtomicUnits(amount, decimals) {
|
|
1829
|
-
const match = /^(?<whole>\d+)(?:\.(?<fraction>\d+))?$/.exec(amount);
|
|
1830
|
-
if (!match?.groups) {
|
|
1831
|
-
throw new Error(`Invalid decimal amount '${amount}'`);
|
|
1832
|
-
}
|
|
1833
|
-
const whole = match.groups.whole;
|
|
1834
|
-
const fraction = match.groups.fraction ?? "";
|
|
1835
|
-
if (fraction.length > decimals) {
|
|
1836
|
-
throw new Error(`Amount '${amount}' exceeds ${decimals} decimal places`);
|
|
1837
|
-
}
|
|
1838
|
-
const normalized = `${whole}${fraction.padEnd(decimals, "0")}`.replace(/^0+(?=\d)/, "");
|
|
1839
|
-
return normalized === "" ? "0" : normalized;
|
|
1840
|
-
}
|
|
1841
1918
|
|
|
1842
1919
|
// src/protocols/x402/challenge.ts
|
|
1843
1920
|
async function buildX402Challenge(opts) {
|
|
@@ -2200,28 +2277,14 @@ async function buildX402ChallengeContribution(args) {
|
|
|
2200
2277
|
}
|
|
2201
2278
|
function reportSettleFailure(report, err, network) {
|
|
2202
2279
|
const facilitator = err ?? {};
|
|
2203
|
-
|
|
2280
|
+
const meta = {
|
|
2204
2281
|
error: err instanceof Error ? err.message : String(err),
|
|
2205
2282
|
network,
|
|
2206
2283
|
errorReason: facilitator.errorReason,
|
|
2207
2284
|
facilitatorStatus: facilitator.response?.status,
|
|
2208
2285
|
facilitatorBody: facilitator.response?.data ?? facilitator.response?.body
|
|
2209
|
-
}
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
// src/protocols/detect.ts
|
|
2213
|
-
function detectProtocol(request) {
|
|
2214
|
-
if (request.headers.get(HEADERS.X402_PAYMENT_SIGNATURE) ?? request.headers.get(HEADERS.X402_PAYMENT_LEGACY)) {
|
|
2215
|
-
return "x402";
|
|
2216
|
-
}
|
|
2217
|
-
const auth = request.headers.get(HEADERS.AUTHORIZATION);
|
|
2218
|
-
if (auth && auth.startsWith(AUTH_SCHEME.MPP_PAYMENT)) {
|
|
2219
|
-
return "mpp";
|
|
2220
|
-
}
|
|
2221
|
-
if (request.headers.get(HEADERS.SIWX)) {
|
|
2222
|
-
return "siwx";
|
|
2223
|
-
}
|
|
2224
|
-
return null;
|
|
2286
|
+
};
|
|
2287
|
+
report("error", "Settlement failed", meta);
|
|
2225
2288
|
}
|
|
2226
2289
|
|
|
2227
2290
|
// src/protocols/index.ts
|
|
@@ -2244,13 +2307,14 @@ function getAllowedStrategies(allowed) {
|
|
|
2244
2307
|
var import_server4 = require("next/server");
|
|
2245
2308
|
|
|
2246
2309
|
// src/pipeline/challenge-extensions.ts
|
|
2310
|
+
init_evm();
|
|
2247
2311
|
async function buildChallengeExtensions(ctx) {
|
|
2248
2312
|
const { routeEntry } = ctx;
|
|
2249
2313
|
let extensions;
|
|
2250
2314
|
try {
|
|
2251
|
-
const { z } = await import("zod");
|
|
2315
|
+
const { z: z2 } = await import("zod");
|
|
2252
2316
|
const { declareDiscoveryExtension } = await import("@x402/extensions/bazaar");
|
|
2253
|
-
const toJSON = (schema) =>
|
|
2317
|
+
const toJSON = (schema) => z2.toJSONSchema(schema, {
|
|
2254
2318
|
target: "draft-2020-12",
|
|
2255
2319
|
unrepresentable: "any"
|
|
2256
2320
|
});
|
|
@@ -2271,11 +2335,10 @@ async function buildChallengeExtensions(ctx) {
|
|
|
2271
2335
|
extensions = declareDiscoveryExtension(config);
|
|
2272
2336
|
}
|
|
2273
2337
|
} catch (err) {
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
});
|
|
2338
|
+
ctx.report(
|
|
2339
|
+
"warn",
|
|
2340
|
+
`Bazaar schema generation failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2341
|
+
);
|
|
2279
2342
|
}
|
|
2280
2343
|
if (routeEntry.siwxEnabled) {
|
|
2281
2344
|
try {
|
|
@@ -2289,7 +2352,24 @@ async function buildChallengeExtensions(ctx) {
|
|
|
2289
2352
|
} catch {
|
|
2290
2353
|
}
|
|
2291
2354
|
}
|
|
2292
|
-
|
|
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
|
+
}
|
|
2372
|
+
return extensions;
|
|
2293
2373
|
}
|
|
2294
2374
|
|
|
2295
2375
|
// src/pipeline/flows/build402.ts
|
|
@@ -2409,7 +2489,7 @@ async function runDynamicChannelMgmtFlow(args) {
|
|
|
2409
2489
|
return build402(ctx, pricing, parsedBody, verifyOutcome.failure);
|
|
2410
2490
|
}
|
|
2411
2491
|
ctx.pluginCtx.setVerifiedWallet(verifyOutcome.wallet);
|
|
2412
|
-
|
|
2492
|
+
firePaymentVerified(ctx, {
|
|
2413
2493
|
protocol: strategy.protocol,
|
|
2414
2494
|
payer: verifyOutcome.wallet,
|
|
2415
2495
|
amount: price,
|
|
@@ -2444,27 +2524,6 @@ async function runDynamicChannelMgmtFlow(args) {
|
|
|
2444
2524
|
// src/pipeline/flows/dynamic/dynamic-invoke.ts
|
|
2445
2525
|
var import_server6 = require("next/server");
|
|
2446
2526
|
|
|
2447
|
-
// src/pricing/atomic.ts
|
|
2448
|
-
var USDC_DECIMALS = 6;
|
|
2449
|
-
function decimalToAtomic(amount) {
|
|
2450
|
-
const m = /^(\d+)(?:\.(\d+))?$/.exec(amount.trim());
|
|
2451
|
-
if (!m) {
|
|
2452
|
-
throw Object.assign(new Error(`'${amount}' is not a valid decimal-dollar string`), {
|
|
2453
|
-
status: 400
|
|
2454
|
-
});
|
|
2455
|
-
}
|
|
2456
|
-
const whole = m[1];
|
|
2457
|
-
const fraction = (m[2] ?? "").slice(0, USDC_DECIMALS).padEnd(USDC_DECIMALS, "0");
|
|
2458
|
-
return BigInt(`${whole}${fraction}`.replace(/^0+(?=\d)/, "") || "0");
|
|
2459
|
-
}
|
|
2460
|
-
function atomicToDecimal(atomic) {
|
|
2461
|
-
const whole = atomic / 10n ** BigInt(USDC_DECIMALS);
|
|
2462
|
-
const fraction = atomic % 10n ** BigInt(USDC_DECIMALS);
|
|
2463
|
-
if (fraction === 0n) return whole.toString();
|
|
2464
|
-
const fractionStr = fraction.toString().padStart(USDC_DECIMALS, "0").replace(/0+$/, "");
|
|
2465
|
-
return `${whole}.${fractionStr}`;
|
|
2466
|
-
}
|
|
2467
|
-
|
|
2468
2527
|
// src/pricing/charge-context.ts
|
|
2469
2528
|
function createChargeContext(args) {
|
|
2470
2529
|
const { tickCost, maxPrice, route } = args;
|
|
@@ -2517,14 +2576,7 @@ async function invokeDynamic(ctx, wallet, account, body, payment) {
|
|
|
2517
2576
|
wallet,
|
|
2518
2577
|
payment,
|
|
2519
2578
|
account,
|
|
2520
|
-
alert
|
|
2521
|
-
firePluginHook(ctx.deps.plugin, "onAlert", ctx.pluginCtx, {
|
|
2522
|
-
level,
|
|
2523
|
-
message,
|
|
2524
|
-
route: ctx.routeEntry.key,
|
|
2525
|
-
meta: alertMeta
|
|
2526
|
-
});
|
|
2527
|
-
},
|
|
2579
|
+
alert: ctx.report,
|
|
2528
2580
|
setVerifiedWallet: (addr) => ctx.pluginCtx.setVerifiedWallet(addr)
|
|
2529
2581
|
};
|
|
2530
2582
|
const handlerCtx = chargeContext !== null ? { ...baseHandlerCtx, charge: chargeContext.charge } : baseHandlerCtx;
|
|
@@ -2589,7 +2641,7 @@ function resolveDynamicPreflight(strategy, request, routeEntry) {
|
|
|
2589
2641
|
// src/pipeline/flows/dynamic/dynamic-request.ts
|
|
2590
2642
|
async function runDynamicRequestFlow(args) {
|
|
2591
2643
|
const { ctx, strategy, verifyOutcome, account, body, result } = args;
|
|
2592
|
-
const {
|
|
2644
|
+
const { routeEntry } = ctx;
|
|
2593
2645
|
const settleScope = {
|
|
2594
2646
|
wallet: verifyOutcome.wallet,
|
|
2595
2647
|
account,
|
|
@@ -2615,11 +2667,10 @@ async function runDynamicRequestFlow(args) {
|
|
|
2615
2667
|
billedAmount,
|
|
2616
2668
|
onSettleError: async (error, failMessage) => {
|
|
2617
2669
|
await runSettlementError(ctx, settleScope, error, "settle");
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
});
|
|
2670
|
+
ctx.report(
|
|
2671
|
+
"critical",
|
|
2672
|
+
`${strategy.protocol} ${failMessage}: ${errorMessage(error, "unknown")}`
|
|
2673
|
+
);
|
|
2623
2674
|
}
|
|
2624
2675
|
});
|
|
2625
2676
|
}
|
|
@@ -2689,7 +2740,7 @@ async function runDynamicPaidFlow(ctx) {
|
|
|
2689
2740
|
return build402(ctx, pricing, parsedBody, verifyOutcome.failure);
|
|
2690
2741
|
}
|
|
2691
2742
|
ctx.pluginCtx.setVerifiedWallet(verifyOutcome.wallet);
|
|
2692
|
-
|
|
2743
|
+
firePaymentVerified(ctx, {
|
|
2693
2744
|
protocol: incomingStrategy.protocol,
|
|
2694
2745
|
payer: verifyOutcome.wallet,
|
|
2695
2746
|
amount: price,
|
|
@@ -2755,7 +2806,6 @@ async function resolveStaticBodyAndPrice(args) {
|
|
|
2755
2806
|
// src/pipeline/flows/static/static-request.ts
|
|
2756
2807
|
async function runStaticRequestFlow(args) {
|
|
2757
2808
|
const { ctx, strategy, verifyOutcome, account, body, price, result } = args;
|
|
2758
|
-
const { deps, routeEntry } = ctx;
|
|
2759
2809
|
const settleScope = {
|
|
2760
2810
|
wallet: verifyOutcome.wallet,
|
|
2761
2811
|
account,
|
|
@@ -2796,11 +2846,10 @@ async function runStaticRequestFlow(args) {
|
|
|
2796
2846
|
billedAmount: price,
|
|
2797
2847
|
onSettleError: async (error, failMessage) => {
|
|
2798
2848
|
await runSettlementError(ctx, settleScope, error, "settle");
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
});
|
|
2849
|
+
ctx.report(
|
|
2850
|
+
"critical",
|
|
2851
|
+
`${strategy.protocol} ${failMessage}: ${errorMessage(error, "unknown")}`
|
|
2852
|
+
);
|
|
2804
2853
|
}
|
|
2805
2854
|
});
|
|
2806
2855
|
}
|
|
@@ -2846,7 +2895,7 @@ async function runStaticPaidFlow(ctx) {
|
|
|
2846
2895
|
return build402(ctx, pricing, parsedBody, verifyOutcome.failure);
|
|
2847
2896
|
}
|
|
2848
2897
|
ctx.pluginCtx.setVerifiedWallet(verifyOutcome.wallet);
|
|
2849
|
-
|
|
2898
|
+
firePaymentVerified(ctx, {
|
|
2850
2899
|
protocol: incomingStrategy.protocol,
|
|
2851
2900
|
payer: verifyOutcome.wallet,
|
|
2852
2901
|
amount: price,
|
|
@@ -2885,6 +2934,19 @@ async function runPaidFlow(ctx) {
|
|
|
2885
2934
|
var import_server7 = require("next/server");
|
|
2886
2935
|
|
|
2887
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
|
+
}
|
|
2888
2950
|
function restKvStore(url, token) {
|
|
2889
2951
|
const base = url.replace(/\/+$/, "");
|
|
2890
2952
|
const authHeader = { Authorization: `Bearer ${token}` };
|
|
@@ -2906,16 +2968,22 @@ function restKvStore(url, token) {
|
|
|
2906
2968
|
const res = await fetch(`${base}/get/${encodeURIComponent(key)}`, { headers: authHeader });
|
|
2907
2969
|
if (!res.ok) throw new Error(`[kv-store] GET ${key}: ${res.status}`);
|
|
2908
2970
|
const { result } = await res.json();
|
|
2909
|
-
|
|
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
|
+
}
|
|
2910
2978
|
}
|
|
2911
2979
|
async function set(key, value) {
|
|
2912
|
-
await exec(["SET", key,
|
|
2980
|
+
await exec(["SET", key, stringifyValue(value)]);
|
|
2913
2981
|
}
|
|
2914
2982
|
async function del(key) {
|
|
2915
2983
|
await exec(["DEL", key]);
|
|
2916
2984
|
}
|
|
2917
2985
|
async function setNxEx(key, value, ttlSeconds) {
|
|
2918
|
-
const result = await exec(["SET", key,
|
|
2986
|
+
const result = await exec(["SET", key, stringifyValue(value), "EX", ttlSeconds, "NX"]);
|
|
2919
2987
|
return result === "OK";
|
|
2920
2988
|
}
|
|
2921
2989
|
async function sadd(key, member) {
|
|
@@ -3030,6 +3098,21 @@ async function createKvMppStore(kv, options) {
|
|
|
3030
3098
|
});
|
|
3031
3099
|
}
|
|
3032
3100
|
|
|
3101
|
+
// src/protocols/detect.ts
|
|
3102
|
+
function detectProtocol(request) {
|
|
3103
|
+
if (request.headers.get(HEADERS.X402_PAYMENT_SIGNATURE) ?? request.headers.get(HEADERS.X402_PAYMENT_LEGACY)) {
|
|
3104
|
+
return "x402";
|
|
3105
|
+
}
|
|
3106
|
+
const auth = request.headers.get(HEADERS.AUTHORIZATION);
|
|
3107
|
+
if (auth && auth.startsWith(AUTH_SCHEME.MPP_PAYMENT)) {
|
|
3108
|
+
return "mpp";
|
|
3109
|
+
}
|
|
3110
|
+
if (request.headers.get(HEADERS.SIWX)) {
|
|
3111
|
+
return "siwx";
|
|
3112
|
+
}
|
|
3113
|
+
return null;
|
|
3114
|
+
}
|
|
3115
|
+
|
|
3033
3116
|
// src/protocols/mpp/siwx-mode.ts
|
|
3034
3117
|
var import_mppx3 = require("mppx");
|
|
3035
3118
|
async function verifyMppSiwx(request, mppx) {
|
|
@@ -3069,11 +3152,7 @@ async function runSiwxOnlyFlow(ctx) {
|
|
|
3069
3152
|
}
|
|
3070
3153
|
if (mppSiwxResult.valid) {
|
|
3071
3154
|
ctx.pluginCtx.setVerifiedWallet(mppSiwxResult.wallet);
|
|
3072
|
-
|
|
3073
|
-
authMode: "siwx",
|
|
3074
|
-
wallet: mppSiwxResult.wallet,
|
|
3075
|
-
route: routeEntry.key
|
|
3076
|
-
});
|
|
3155
|
+
fireAuthVerified(ctx, { authMode: "siwx", wallet: mppSiwxResult.wallet });
|
|
3077
3156
|
const authResponse = await runHandlerOnly(ctx, mppSiwxResult.wallet, void 0);
|
|
3078
3157
|
if (authResponse.status < 400) {
|
|
3079
3158
|
return mppSiwxResult.withReceipt(authResponse);
|
|
@@ -3095,11 +3174,7 @@ async function runSiwxOnlyFlow(ctx) {
|
|
|
3095
3174
|
}
|
|
3096
3175
|
const wallet = normalizeWalletAddress(siwx.wallet);
|
|
3097
3176
|
ctx.pluginCtx.setVerifiedWallet(wallet);
|
|
3098
|
-
|
|
3099
|
-
authMode: "siwx",
|
|
3100
|
-
wallet,
|
|
3101
|
-
route: routeEntry.key
|
|
3102
|
-
});
|
|
3177
|
+
fireAuthVerified(ctx, { authMode: "siwx", wallet });
|
|
3103
3178
|
return runHandlerOnly(ctx, wallet, void 0);
|
|
3104
3179
|
}
|
|
3105
3180
|
async function buildSiwxChallenge(ctx) {
|
|
@@ -3192,7 +3267,7 @@ async function runUnprotectedFlow(ctx) {
|
|
|
3192
3267
|
return runHandlerOnly(ctx, null, void 0);
|
|
3193
3268
|
}
|
|
3194
3269
|
|
|
3195
|
-
// src/orchestrate.ts
|
|
3270
|
+
// src/pipeline/orchestrate.ts
|
|
3196
3271
|
function createRequestHandler(routeEntry, handler, deps) {
|
|
3197
3272
|
return async (request) => {
|
|
3198
3273
|
await deps.initPromise;
|
|
@@ -3237,142 +3312,109 @@ ${issues}`
|
|
|
3237
3312
|
}
|
|
3238
3313
|
|
|
3239
3314
|
// src/builder.ts
|
|
3240
|
-
var RouteBuilder = class {
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
_inputExample = void 0;
|
|
3275
|
-
/** @internal */
|
|
3276
|
-
_hasInputExample = false;
|
|
3277
|
-
/** @internal */
|
|
3278
|
-
_outputExample = void 0;
|
|
3279
|
-
/** @internal */
|
|
3280
|
-
_hasOutputExample = false;
|
|
3281
|
-
/** @internal */
|
|
3282
|
-
_description;
|
|
3283
|
-
/** @internal */
|
|
3284
|
-
_path;
|
|
3285
|
-
/** @internal */
|
|
3286
|
-
_method = "POST";
|
|
3287
|
-
/** @internal */
|
|
3288
|
-
_apiKeyResolver;
|
|
3289
|
-
/** @internal */
|
|
3290
|
-
_providerName;
|
|
3291
|
-
/** @internal */
|
|
3292
|
-
_providerConfig;
|
|
3293
|
-
/** @internal */
|
|
3294
|
-
_validateFn;
|
|
3295
|
-
/** @internal */
|
|
3296
|
-
_settlement;
|
|
3297
|
-
/** @internal */
|
|
3298
|
-
_mppInfo;
|
|
3299
|
-
constructor(key, registry, deps) {
|
|
3300
|
-
this._key = key;
|
|
3301
|
-
this._registry = registry;
|
|
3302
|
-
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
|
+
};
|
|
3303
3349
|
}
|
|
3304
3350
|
fork() {
|
|
3305
|
-
const next =
|
|
3306
|
-
|
|
3307
|
-
|
|
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] };
|
|
3308
3357
|
return next;
|
|
3309
3358
|
}
|
|
3310
3359
|
paid(pricingOrOptions, options) {
|
|
3311
|
-
const { pricing, resolvedOptions } = resolvePaidArgs(this.
|
|
3312
|
-
if (this.
|
|
3360
|
+
const { pricing, resolvedOptions } = resolvePaidArgs(this.#s.key, pricingOrOptions, options);
|
|
3361
|
+
if (this.#s.authMode === "unprotected") {
|
|
3313
3362
|
throw new Error(
|
|
3314
|
-
`route '${this.
|
|
3363
|
+
`route '${this.#s.key}': Cannot combine .unprotected() and .paid() on the same route.`
|
|
3315
3364
|
);
|
|
3316
3365
|
}
|
|
3317
|
-
if (this.
|
|
3366
|
+
if (this.#s.pricing !== void 0) {
|
|
3318
3367
|
throw new Error(
|
|
3319
|
-
`route '${this.
|
|
3368
|
+
`route '${this.#s.key}': Cannot call .paid() more than once on the same route.`
|
|
3320
3369
|
);
|
|
3321
3370
|
}
|
|
3322
3371
|
const next = this.fork();
|
|
3323
|
-
next.
|
|
3324
|
-
next.
|
|
3372
|
+
next.#s.authMode = "paid";
|
|
3373
|
+
next.#s.pricing = pricing;
|
|
3325
3374
|
if (resolvedOptions?.protocols) {
|
|
3326
|
-
next.
|
|
3327
|
-
} else if (next.
|
|
3328
|
-
next.
|
|
3375
|
+
next.#s.protocols = [...resolvedOptions.protocols];
|
|
3376
|
+
} else if (next.#s.protocols.length === 0) {
|
|
3377
|
+
next.#s.protocols = ["x402"];
|
|
3329
3378
|
}
|
|
3330
|
-
if (resolvedOptions?.maxPrice) next.
|
|
3331
|
-
if (resolvedOptions?.minPrice) next.
|
|
3332
|
-
if (resolvedOptions?.payTo) next.
|
|
3333
|
-
if (resolvedOptions?.mpp) next.
|
|
3334
|
-
if (resolvedOptions?.dynamic) next.
|
|
3335
|
-
if (resolvedOptions?.tickCost) next.
|
|
3336
|
-
if (resolvedOptions?.unitType) next.
|
|
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;
|
|
3337
3386
|
if (typeof pricing === "object" && "tiers" in pricing) {
|
|
3338
|
-
if (next.
|
|
3387
|
+
if (next.#s.dynamicPrice) {
|
|
3339
3388
|
throw new Error(
|
|
3340
|
-
`route '${this.
|
|
3389
|
+
`route '${this.#s.key}': .paid({ dynamic: true }) is incompatible with tiered pricing`
|
|
3341
3390
|
);
|
|
3342
3391
|
}
|
|
3343
3392
|
for (const [tierKey, tierConfig] of Object.entries(pricing.tiers)) {
|
|
3344
3393
|
if (!tierKey) {
|
|
3345
|
-
throw new Error(`route '${this.
|
|
3394
|
+
throw new Error(`route '${this.#s.key}': tier key cannot be empty`);
|
|
3346
3395
|
}
|
|
3347
|
-
|
|
3348
|
-
if (isNaN(tierPrice) || tierPrice <= 0) {
|
|
3396
|
+
if (!isPositiveDecimal(tierConfig.price)) {
|
|
3349
3397
|
throw new Error(
|
|
3350
|
-
`route '${this.
|
|
3398
|
+
`route '${this.#s.key}': tier '${tierKey}' price '${tierConfig.price}' must be a positive decimal string`
|
|
3351
3399
|
);
|
|
3352
3400
|
}
|
|
3353
3401
|
}
|
|
3354
3402
|
}
|
|
3355
|
-
if (resolvedOptions?.maxPrice !== void 0) {
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
`route '${this._key}': maxPrice '${resolvedOptions.maxPrice}' must be a positive decimal string`
|
|
3360
|
-
);
|
|
3361
|
-
}
|
|
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
|
+
);
|
|
3362
3407
|
}
|
|
3363
|
-
if (resolvedOptions?.tickCost !== void 0) {
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
`route '${this._key}': tickCost '${resolvedOptions.tickCost}' must be a positive decimal string`
|
|
3368
|
-
);
|
|
3369
|
-
}
|
|
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
|
+
);
|
|
3370
3412
|
}
|
|
3371
|
-
if (next.
|
|
3372
|
-
throw new Error(`route '${this.
|
|
3413
|
+
if (next.#s.dynamicPrice && !next.#s.maxPrice) {
|
|
3414
|
+
throw new Error(`route '${this.#s.key}': .paid({ dynamic: true }) requires maxPrice`);
|
|
3373
3415
|
}
|
|
3374
|
-
if (next.
|
|
3375
|
-
throw new Error(`route '${this.
|
|
3416
|
+
if (next.#s.dynamicPrice && !next.#s.tickCost) {
|
|
3417
|
+
throw new Error(`route '${this.#s.key}': .paid({ dynamic: true }) requires tickCost`);
|
|
3376
3418
|
}
|
|
3377
3419
|
return next;
|
|
3378
3420
|
}
|
|
@@ -3387,25 +3429,25 @@ var RouteBuilder = class {
|
|
|
3387
3429
|
* ```
|
|
3388
3430
|
*/
|
|
3389
3431
|
siwx() {
|
|
3390
|
-
if (this.
|
|
3432
|
+
if (this.#s.authMode === "unprotected") {
|
|
3391
3433
|
throw new Error(
|
|
3392
|
-
`route '${this.
|
|
3434
|
+
`route '${this.#s.key}': Cannot combine .unprotected() and .siwx() on the same route.`
|
|
3393
3435
|
);
|
|
3394
3436
|
}
|
|
3395
|
-
if (this.
|
|
3437
|
+
if (this.#s.apiKeyResolver) {
|
|
3396
3438
|
throw new Error(
|
|
3397
|
-
`route '${this.
|
|
3439
|
+
`route '${this.#s.key}': Combining .siwx() and .apiKey() is not supported on the same route.`
|
|
3398
3440
|
);
|
|
3399
3441
|
}
|
|
3400
3442
|
const next = this.fork();
|
|
3401
|
-
next.
|
|
3402
|
-
if (next.
|
|
3403
|
-
next.
|
|
3404
|
-
if (next.
|
|
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"];
|
|
3405
3447
|
return next;
|
|
3406
3448
|
}
|
|
3407
|
-
next.
|
|
3408
|
-
next.
|
|
3449
|
+
next.#s.authMode = "siwx";
|
|
3450
|
+
next.#s.protocols = [];
|
|
3409
3451
|
return next;
|
|
3410
3452
|
}
|
|
3411
3453
|
/**
|
|
@@ -3422,14 +3464,14 @@ var RouteBuilder = class {
|
|
|
3422
3464
|
* ```
|
|
3423
3465
|
*/
|
|
3424
3466
|
apiKey(resolver) {
|
|
3425
|
-
if (this.
|
|
3467
|
+
if (this.#s.siwxEnabled) {
|
|
3426
3468
|
throw new Error(
|
|
3427
|
-
`route '${this.
|
|
3469
|
+
`route '${this.#s.key}': Combining .apiKey() and .siwx() is not supported on the same route.`
|
|
3428
3470
|
);
|
|
3429
3471
|
}
|
|
3430
3472
|
const next = this.fork();
|
|
3431
|
-
next.
|
|
3432
|
-
next.
|
|
3473
|
+
next.#s.authMode = "apiKey";
|
|
3474
|
+
next.#s.apiKeyResolver = resolver;
|
|
3433
3475
|
return next;
|
|
3434
3476
|
}
|
|
3435
3477
|
/**
|
|
@@ -3442,19 +3484,19 @@ var RouteBuilder = class {
|
|
|
3442
3484
|
* ```
|
|
3443
3485
|
*/
|
|
3444
3486
|
unprotected() {
|
|
3445
|
-
if (this.
|
|
3487
|
+
if (this.#s.authMode && this.#s.authMode !== "unprotected") {
|
|
3446
3488
|
throw new Error(
|
|
3447
|
-
`route '${this.
|
|
3489
|
+
`route '${this.#s.key}': Cannot combine .unprotected() and .${this.#s.authMode}() on the same route.`
|
|
3448
3490
|
);
|
|
3449
3491
|
}
|
|
3450
|
-
if (this.
|
|
3492
|
+
if (this.#s.pricing) {
|
|
3451
3493
|
throw new Error(
|
|
3452
|
-
`route '${this.
|
|
3494
|
+
`route '${this.#s.key}': Cannot combine .unprotected() and .paid() on the same route.`
|
|
3453
3495
|
);
|
|
3454
3496
|
}
|
|
3455
3497
|
const next = this.fork();
|
|
3456
|
-
next.
|
|
3457
|
-
next.
|
|
3498
|
+
next.#s.authMode = "unprotected";
|
|
3499
|
+
next.#s.protocols = [];
|
|
3458
3500
|
return next;
|
|
3459
3501
|
}
|
|
3460
3502
|
/**
|
|
@@ -3473,8 +3515,8 @@ var RouteBuilder = class {
|
|
|
3473
3515
|
*/
|
|
3474
3516
|
provider(name, config) {
|
|
3475
3517
|
const next = this.fork();
|
|
3476
|
-
next.
|
|
3477
|
-
next.
|
|
3518
|
+
next.#s.providerName = name;
|
|
3519
|
+
next.#s.providerConfig = config ?? {};
|
|
3478
3520
|
return next;
|
|
3479
3521
|
}
|
|
3480
3522
|
/**
|
|
@@ -3489,7 +3531,7 @@ var RouteBuilder = class {
|
|
|
3489
3531
|
*/
|
|
3490
3532
|
body(schema) {
|
|
3491
3533
|
const next = this.fork();
|
|
3492
|
-
next.
|
|
3534
|
+
next.#s.bodySchema = schema;
|
|
3493
3535
|
return next;
|
|
3494
3536
|
}
|
|
3495
3537
|
/**
|
|
@@ -3505,8 +3547,8 @@ var RouteBuilder = class {
|
|
|
3505
3547
|
*/
|
|
3506
3548
|
query(schema) {
|
|
3507
3549
|
const next = this.fork();
|
|
3508
|
-
next.
|
|
3509
|
-
next.
|
|
3550
|
+
next.#s.querySchema = schema;
|
|
3551
|
+
next.#s.method = "GET";
|
|
3510
3552
|
return next;
|
|
3511
3553
|
}
|
|
3512
3554
|
/**
|
|
@@ -3523,7 +3565,7 @@ var RouteBuilder = class {
|
|
|
3523
3565
|
*/
|
|
3524
3566
|
output(schema) {
|
|
3525
3567
|
const next = this.fork();
|
|
3526
|
-
next.
|
|
3568
|
+
next.#s.outputSchema = schema;
|
|
3527
3569
|
return next;
|
|
3528
3570
|
}
|
|
3529
3571
|
/**
|
|
@@ -3537,8 +3579,8 @@ var RouteBuilder = class {
|
|
|
3537
3579
|
*/
|
|
3538
3580
|
inputExample(example) {
|
|
3539
3581
|
const next = this.fork();
|
|
3540
|
-
next.
|
|
3541
|
-
next.
|
|
3582
|
+
next.#s.inputExample = example;
|
|
3583
|
+
next.#s.hasInputExample = true;
|
|
3542
3584
|
return next;
|
|
3543
3585
|
}
|
|
3544
3586
|
/**
|
|
@@ -3552,8 +3594,8 @@ var RouteBuilder = class {
|
|
|
3552
3594
|
*/
|
|
3553
3595
|
outputExample(example) {
|
|
3554
3596
|
const next = this.fork();
|
|
3555
|
-
next.
|
|
3556
|
-
next.
|
|
3597
|
+
next.#s.outputExample = example;
|
|
3598
|
+
next.#s.hasOutputExample = true;
|
|
3557
3599
|
return next;
|
|
3558
3600
|
}
|
|
3559
3601
|
/**
|
|
@@ -3567,7 +3609,7 @@ var RouteBuilder = class {
|
|
|
3567
3609
|
*/
|
|
3568
3610
|
description(text) {
|
|
3569
3611
|
const next = this.fork();
|
|
3570
|
-
next.
|
|
3612
|
+
next.#s.description = text;
|
|
3571
3613
|
return next;
|
|
3572
3614
|
}
|
|
3573
3615
|
/**
|
|
@@ -3581,7 +3623,7 @@ var RouteBuilder = class {
|
|
|
3581
3623
|
*/
|
|
3582
3624
|
path(p) {
|
|
3583
3625
|
const next = this.fork();
|
|
3584
|
-
next.
|
|
3626
|
+
next.#s.path = p;
|
|
3585
3627
|
return next;
|
|
3586
3628
|
}
|
|
3587
3629
|
/**
|
|
@@ -3595,7 +3637,7 @@ var RouteBuilder = class {
|
|
|
3595
3637
|
*/
|
|
3596
3638
|
method(m) {
|
|
3597
3639
|
const next = this.fork();
|
|
3598
|
-
next.
|
|
3640
|
+
next.#s.method = m;
|
|
3599
3641
|
return next;
|
|
3600
3642
|
}
|
|
3601
3643
|
/**
|
|
@@ -3614,7 +3656,7 @@ var RouteBuilder = class {
|
|
|
3614
3656
|
*/
|
|
3615
3657
|
validate(fn) {
|
|
3616
3658
|
const next = this.fork();
|
|
3617
|
-
next.
|
|
3659
|
+
next.#s.validateFn = fn;
|
|
3618
3660
|
return next;
|
|
3619
3661
|
}
|
|
3620
3662
|
/**
|
|
@@ -3632,7 +3674,7 @@ var RouteBuilder = class {
|
|
|
3632
3674
|
*/
|
|
3633
3675
|
settlement(lifecycle) {
|
|
3634
3676
|
const next = this.fork();
|
|
3635
|
-
next.
|
|
3677
|
+
next.#s.settlement = lifecycle;
|
|
3636
3678
|
return next;
|
|
3637
3679
|
}
|
|
3638
3680
|
/**
|
|
@@ -3675,79 +3717,79 @@ var RouteBuilder = class {
|
|
|
3675
3717
|
return this.register(fn, true);
|
|
3676
3718
|
}
|
|
3677
3719
|
register(handlerFn, streaming) {
|
|
3678
|
-
if (!this.
|
|
3720
|
+
if (!this.#s.authMode) {
|
|
3679
3721
|
throw new Error(
|
|
3680
|
-
`route '${this.
|
|
3722
|
+
`route '${this.#s.key}': Select an auth mode: .paid(pricing), .siwx(), .apiKey(resolver), or .unprotected()`
|
|
3681
3723
|
);
|
|
3682
3724
|
}
|
|
3683
|
-
if (this.
|
|
3725
|
+
if (this.#s.validateFn && !this.#s.bodySchema) {
|
|
3684
3726
|
throw new Error(
|
|
3685
|
-
`route '${this.
|
|
3727
|
+
`route '${this.#s.key}': .validate() requires .body() \u2014 validation runs on parsed body`
|
|
3686
3728
|
);
|
|
3687
3729
|
}
|
|
3688
|
-
if (this.
|
|
3689
|
-
throw new Error(`route '${this.
|
|
3730
|
+
if (this.#s.settlement && !this.#s.pricing) {
|
|
3731
|
+
throw new Error(`route '${this.#s.key}': .settlement() requires a paid route`);
|
|
3690
3732
|
}
|
|
3691
|
-
if (this.
|
|
3692
|
-
const hasUpto = this.
|
|
3733
|
+
if (this.#s.dynamicPrice && this.#s.protocols.includes("x402")) {
|
|
3734
|
+
const hasUpto = this.#s.deps.x402Accepts.some((accept) => accept.scheme === "upto");
|
|
3693
3735
|
if (!hasUpto) {
|
|
3694
3736
|
throw new Error(
|
|
3695
|
-
`route '${this.
|
|
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.`
|
|
3696
3738
|
);
|
|
3697
3739
|
}
|
|
3698
3740
|
}
|
|
3699
|
-
if (this.
|
|
3700
|
-
if (!this.
|
|
3741
|
+
if (this.#s.dynamicPrice && this.#s.protocols.includes("mpp")) {
|
|
3742
|
+
if (!this.#s.deps.mppSessionConfig) {
|
|
3701
3743
|
throw new Error(
|
|
3702
|
-
`route '${this.
|
|
3744
|
+
`route '${this.#s.key}': .paid({ dynamic: true }) on an MPP route requires session mode. Set RouterConfig.mpp.session = {} and provide mpp.operatorKey.`
|
|
3703
3745
|
);
|
|
3704
3746
|
}
|
|
3705
3747
|
}
|
|
3706
|
-
if (streaming && !this.
|
|
3748
|
+
if (streaming && !this.#s.dynamicPrice) {
|
|
3707
3749
|
throw new Error(
|
|
3708
|
-
`route '${this.
|
|
3750
|
+
`route '${this.#s.key}': .stream() requires .paid({ dynamic: true }) \u2014 static/free routes can't meter per-chunk billing.`
|
|
3709
3751
|
);
|
|
3710
3752
|
}
|
|
3711
3753
|
validateExamples(
|
|
3712
|
-
this.
|
|
3713
|
-
this.
|
|
3714
|
-
this.
|
|
3715
|
-
this.
|
|
3716
|
-
this.
|
|
3717
|
-
this.
|
|
3718
|
-
this.
|
|
3719
|
-
this.
|
|
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
|
|
3720
3762
|
);
|
|
3721
3763
|
const entry = {
|
|
3722
|
-
key: this.
|
|
3723
|
-
authMode: this.
|
|
3724
|
-
siwxEnabled: this.
|
|
3725
|
-
pricing: this.
|
|
3726
|
-
dynamicPrice: this.
|
|
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,
|
|
3727
3769
|
streaming: streaming ? true : void 0,
|
|
3728
|
-
protocols: this.
|
|
3729
|
-
bodySchema: this.
|
|
3730
|
-
querySchema: this.
|
|
3731
|
-
outputSchema: this.
|
|
3732
|
-
inputExample: this.
|
|
3733
|
-
outputExample: this.
|
|
3734
|
-
description: this.
|
|
3735
|
-
path: this.
|
|
3736
|
-
method: this.
|
|
3737
|
-
maxPrice: this.
|
|
3738
|
-
minPrice: this.
|
|
3739
|
-
payTo: this.
|
|
3740
|
-
apiKeyResolver: this.
|
|
3741
|
-
providerName: this.
|
|
3742
|
-
providerConfig: this.
|
|
3743
|
-
validateFn: this.
|
|
3744
|
-
settlement: this.
|
|
3745
|
-
mppInfo: this.
|
|
3746
|
-
tickCost: this.
|
|
3747
|
-
unitType: this.
|
|
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
|
|
3748
3790
|
};
|
|
3749
|
-
this.
|
|
3750
|
-
return createRequestHandler(entry, handlerFn, this.
|
|
3791
|
+
this.#s.registry.register(entry);
|
|
3792
|
+
return createRequestHandler(entry, handlerFn, this.#s.deps);
|
|
3751
3793
|
}
|
|
3752
3794
|
};
|
|
3753
3795
|
function resolvePaidArgs(routeKey, pricingOrOptions, options) {
|
|
@@ -3967,7 +4009,7 @@ function toProtocolObject(protocol, mppInfo) {
|
|
|
3967
4009
|
mpp: {
|
|
3968
4010
|
method: mppInfo?.method ?? "tempo",
|
|
3969
4011
|
intent: mppInfo?.intent ?? "charge",
|
|
3970
|
-
currency: mppInfo?.currency ??
|
|
4012
|
+
currency: mppInfo?.currency ?? TEMPO_USDC_ADDRESS
|
|
3971
4013
|
}
|
|
3972
4014
|
};
|
|
3973
4015
|
}
|
|
@@ -3991,17 +4033,16 @@ function buildPricingInfo(entry) {
|
|
|
3991
4033
|
};
|
|
3992
4034
|
}
|
|
3993
4035
|
if ("tiers" in entry.pricing) {
|
|
3994
|
-
const tierPrices = Object.values(entry.pricing.tiers).map((tier) =>
|
|
3995
|
-
const
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
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) {
|
|
3999
4040
|
return {
|
|
4000
|
-
price: { mode: "fixed", currency: "USD", amount:
|
|
4041
|
+
price: { mode: "fixed", currency: "USD", amount: extrema.min }
|
|
4001
4042
|
};
|
|
4002
4043
|
}
|
|
4003
4044
|
return {
|
|
4004
|
-
price: { mode: "dynamic", currency: "USD", min:
|
|
4045
|
+
price: { mode: "dynamic", currency: "USD", min: extrema.min, max: extrema.max }
|
|
4005
4046
|
};
|
|
4006
4047
|
}
|
|
4007
4048
|
return {
|
|
@@ -4015,6 +4056,20 @@ function buildPricingInfo(entry) {
|
|
|
4015
4056
|
}
|
|
4016
4057
|
return void 0;
|
|
4017
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
|
+
}
|
|
4018
4073
|
|
|
4019
4074
|
// src/discovery/llms-txt.ts
|
|
4020
4075
|
var import_server10 = require("next/server");
|
|
@@ -4047,142 +4102,256 @@ function formatRouterConfigIssues(issues) {
|
|
|
4047
4102
|
return issues.map((issue) => issue.message).join("\n");
|
|
4048
4103
|
}
|
|
4049
4104
|
|
|
4050
|
-
// src/config/
|
|
4051
|
-
|
|
4105
|
+
// src/config/schema.ts
|
|
4106
|
+
var import_zod = require("zod");
|
|
4107
|
+
init_constants();
|
|
4052
4108
|
|
|
4053
|
-
// src/config/
|
|
4054
|
-
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
}
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4109
|
+
// src/config/utils.ts
|
|
4110
|
+
var import_accounts = require("viem/accounts");
|
|
4111
|
+
var EVM_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
|
|
4112
|
+
var EVM_PRIVATE_KEY_RE = /^0x[a-fA-F0-9]{64}$/;
|
|
4113
|
+
var SOLANA_ADDRESS_RE = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
|
|
4114
|
+
var ZERO_EVM_ADDRESS_RE = /^0x0{40}$/i;
|
|
4115
|
+
function isUrl(value) {
|
|
4116
|
+
try {
|
|
4117
|
+
new URL(value);
|
|
4118
|
+
return true;
|
|
4119
|
+
} catch {
|
|
4120
|
+
return false;
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4123
|
+
var isEvmAddress = (v) => EVM_ADDRESS_RE.test(v);
|
|
4124
|
+
var isEvmPrivateKey = (v) => EVM_PRIVATE_KEY_RE.test(v);
|
|
4125
|
+
var isPlaceholderEvm = (v) => ZERO_EVM_ADDRESS_RE.test(v);
|
|
4126
|
+
var isSolanaAddress = (v) => SOLANA_ADDRESS_RE.test(v);
|
|
4127
|
+
var isX402Network = (v) => v.startsWith("eip155:") || v.startsWith("solana:");
|
|
4128
|
+
var canonicalizeEvm = (addr) => addr.toLowerCase();
|
|
4129
|
+
function operatorAddressesCollide(opKey, fpKey) {
|
|
4130
|
+
if (!opKey || !fpKey || !isEvmPrivateKey(opKey) || !isEvmPrivateKey(fpKey)) return null;
|
|
4131
|
+
const op = (0, import_accounts.privateKeyToAccount)(opKey).address.toLowerCase();
|
|
4132
|
+
const fp = (0, import_accounts.privateKeyToAccount)(fpKey).address.toLowerCase();
|
|
4133
|
+
return op === fp ? op : null;
|
|
4134
|
+
}
|
|
4135
|
+
function trimAll(raw) {
|
|
4136
|
+
const out = {};
|
|
4137
|
+
for (const [k, v] of Object.entries(raw)) {
|
|
4138
|
+
if (typeof v !== "string") {
|
|
4139
|
+
out[k] = void 0;
|
|
4140
|
+
continue;
|
|
4141
|
+
}
|
|
4142
|
+
const trimmed = v.trim();
|
|
4143
|
+
out[k] = trimmed.length > 0 ? trimmed : void 0;
|
|
4144
|
+
}
|
|
4145
|
+
return out;
|
|
4073
4146
|
}
|
|
4074
4147
|
|
|
4075
|
-
// src/config/
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
4085
|
-
|
|
4086
|
-
|
|
4087
|
-
|
|
4148
|
+
// src/config/schema.ts
|
|
4149
|
+
function addIssue(ctx, params, message, path = []) {
|
|
4150
|
+
ctx.addIssue({ code: "custom", path, params, message });
|
|
4151
|
+
}
|
|
4152
|
+
var x402 = { protocol: "x402" };
|
|
4153
|
+
var mpp = { protocol: "mpp" };
|
|
4154
|
+
var envShape = {
|
|
4155
|
+
BASE_URL: import_zod.z.string().refine(isUrl, {
|
|
4156
|
+
params: { code: "invalid_base_url" },
|
|
4157
|
+
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."
|
|
4158
|
+
}).optional(),
|
|
4159
|
+
EVM_PAYEE_ADDRESS: import_zod.z.string().refine(isEvmAddress, {
|
|
4160
|
+
params: { code: "invalid_x402_payee", ...x402 },
|
|
4161
|
+
message: "EVM_PAYEE_ADDRESS must be a 0x-prefixed 20-byte EVM address \u2014 the wallet that receives x402 and MPP payments."
|
|
4162
|
+
}).refine((v) => !isPlaceholderEvm(v), {
|
|
4163
|
+
params: { code: "placeholder_payee", ...x402 },
|
|
4164
|
+
message: "EVM_PAYEE_ADDRESS is the zero address (0x000\u2026000) \u2014 payments to this address are unrecoverable. Set it to a wallet you control."
|
|
4165
|
+
}).optional(),
|
|
4166
|
+
CDP_API_KEY_ID: import_zod.z.string().optional(),
|
|
4167
|
+
CDP_API_KEY_SECRET: import_zod.z.string().optional(),
|
|
4168
|
+
SOLANA_PAYEE_ADDRESS: import_zod.z.string().refine(isSolanaAddress, {
|
|
4169
|
+
params: { code: "invalid_solana_payee", ...x402 },
|
|
4170
|
+
message: "SOLANA_PAYEE_ADDRESS must be a base58 Solana address (32\u201344 chars). When set, the router also accepts Solana payments."
|
|
4171
|
+
}).optional(),
|
|
4172
|
+
SOLANA_FACILITATOR_URL: import_zod.z.string().refine(isUrl, {
|
|
4173
|
+
params: { code: "invalid_solana_facilitator_url", ...x402 },
|
|
4174
|
+
message: "SOLANA_FACILITATOR_URL must be a valid URL \u2014 override for the Solana x402 facilitator. Defaults to DEFAULT_SOLANA_FACILITATOR_URL."
|
|
4175
|
+
}).optional(),
|
|
4176
|
+
MPP_SECRET_KEY: import_zod.z.string().optional(),
|
|
4177
|
+
MPP_CURRENCY: import_zod.z.string().refine(isEvmAddress, {
|
|
4178
|
+
params: { code: "invalid_mpp_currency", ...mpp },
|
|
4179
|
+
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."
|
|
4180
|
+
}).optional(),
|
|
4181
|
+
TEMPO_RPC_URL: import_zod.z.string().refine(isUrl, {
|
|
4182
|
+
params: { code: "invalid_mpp_rpc_url", ...mpp },
|
|
4183
|
+
message: "TEMPO_RPC_URL must be a valid URL \u2014 authenticated Tempo JSON-RPC endpoint. Public rpc.tempo.xyz returns 401."
|
|
4184
|
+
}).optional(),
|
|
4185
|
+
MPP_OPERATOR_KEY: import_zod.z.string().refine(isEvmPrivateKey, {
|
|
4186
|
+
params: { code: "invalid_mpp_operator_key", ...mpp },
|
|
4187
|
+
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."
|
|
4188
|
+
}).optional(),
|
|
4189
|
+
MPP_FEE_PAYER_KEY: import_zod.z.string().refine(isEvmPrivateKey, {
|
|
4190
|
+
params: { code: "invalid_mpp_fee_payer_key", ...mpp },
|
|
4191
|
+
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."
|
|
4192
|
+
}).optional(),
|
|
4193
|
+
KV_REST_API_URL: import_zod.z.string().optional(),
|
|
4194
|
+
KV_REST_API_TOKEN: import_zod.z.string().optional(),
|
|
4195
|
+
NODE_ENV: import_zod.z.string().optional()
|
|
4196
|
+
};
|
|
4197
|
+
var ENV_KEYS = Object.keys(envShape);
|
|
4198
|
+
var EnvInputSchema = import_zod.z.object(envShape).passthrough().superRefine((env, ctx) => {
|
|
4199
|
+
if (env.BASE_URL === void 0) {
|
|
4200
|
+
addIssue(
|
|
4201
|
+
ctx,
|
|
4202
|
+
{ code: "missing_base_url" },
|
|
4203
|
+
"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.",
|
|
4204
|
+
["BASE_URL"]
|
|
4205
|
+
);
|
|
4206
|
+
}
|
|
4207
|
+
if (env.EVM_PAYEE_ADDRESS === void 0) {
|
|
4208
|
+
addIssue(
|
|
4209
|
+
ctx,
|
|
4210
|
+
{ code: "missing_x402_payee", ...x402 },
|
|
4211
|
+
"EVM_PAYEE_ADDRESS is required \u2014 the EVM address that receives x402 and MPP payments.",
|
|
4212
|
+
["EVM_PAYEE_ADDRESS"]
|
|
4213
|
+
);
|
|
4214
|
+
}
|
|
4215
|
+
if (env.MPP_SECRET_KEY) {
|
|
4216
|
+
if (env.MPP_CURRENCY === void 0) {
|
|
4217
|
+
addIssue(
|
|
4218
|
+
ctx,
|
|
4219
|
+
{ code: "missing_mpp_currency", ...mpp },
|
|
4220
|
+
"MPP_CURRENCY is required when MPP is enabled \u2014 the Tempo currency address MPP charges in. Use TEMPO_USDC_ADDRESS for Tempo USDC.",
|
|
4221
|
+
["MPP_CURRENCY"]
|
|
4222
|
+
);
|
|
4223
|
+
}
|
|
4224
|
+
if (env.TEMPO_RPC_URL === void 0) {
|
|
4225
|
+
addIssue(
|
|
4226
|
+
ctx,
|
|
4227
|
+
{ code: "missing_mpp_rpc_url", ...mpp },
|
|
4228
|
+
"TEMPO_RPC_URL is required when MPP is enabled \u2014 authenticated Tempo JSON-RPC endpoint. Public rpc.tempo.xyz returns 401.",
|
|
4229
|
+
["TEMPO_RPC_URL"]
|
|
4230
|
+
);
|
|
4231
|
+
}
|
|
4232
|
+
}
|
|
4233
|
+
const collision = operatorAddressesCollide(env.MPP_OPERATOR_KEY, env.MPP_FEE_PAYER_KEY);
|
|
4234
|
+
if (collision) {
|
|
4235
|
+
addIssue(
|
|
4236
|
+
ctx,
|
|
4237
|
+
{ code: "mpp_operator_equals_fee_payer", ...mpp },
|
|
4238
|
+
`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.`,
|
|
4239
|
+
["MPP_FEE_PAYER_KEY"]
|
|
4240
|
+
);
|
|
4241
|
+
}
|
|
4242
|
+
});
|
|
4243
|
+
function collectKvWarnings(env, kvStoreOptionProvided) {
|
|
4244
|
+
if (kvStoreOptionProvided) return [];
|
|
4245
|
+
const warn = (code, message) => ({
|
|
4246
|
+
code,
|
|
4247
|
+
severity: "warning",
|
|
4248
|
+
message
|
|
4249
|
+
});
|
|
4250
|
+
if (env.KV_REST_API_URL && !env.KV_REST_API_TOKEN) {
|
|
4088
4251
|
return [
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
}
|
|
4252
|
+
warn(
|
|
4253
|
+
"kv_url_without_token",
|
|
4254
|
+
"KV_REST_API_URL is set but KV_REST_API_TOKEN is missing \u2014 falling back to in-memory KV (unsafe in serverless production)."
|
|
4255
|
+
)
|
|
4094
4256
|
];
|
|
4095
4257
|
}
|
|
4096
|
-
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
}
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
4107
|
-
|
|
4108
|
-
|
|
4109
|
-
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4258
|
+
if (env.KV_REST_API_TOKEN && !env.KV_REST_API_URL) {
|
|
4259
|
+
return [
|
|
4260
|
+
warn(
|
|
4261
|
+
"kv_token_without_url",
|
|
4262
|
+
"KV_REST_API_TOKEN is set but KV_REST_API_URL is missing \u2014 falling back to in-memory KV (unsafe in serverless production)."
|
|
4263
|
+
)
|
|
4264
|
+
];
|
|
4265
|
+
}
|
|
4266
|
+
if (env.KV_REST_API_URL && env.KV_REST_API_TOKEN && !isUrl(env.KV_REST_API_URL)) {
|
|
4267
|
+
return [
|
|
4268
|
+
warn(
|
|
4269
|
+
"invalid_kv_url",
|
|
4270
|
+
`KV_REST_API_URL is not a valid URL \u2014 KV calls will fail at request time. Got: ${env.KV_REST_API_URL}`
|
|
4271
|
+
)
|
|
4272
|
+
];
|
|
4273
|
+
}
|
|
4274
|
+
if (!env.KV_REST_API_URL && !env.KV_REST_API_TOKEN && env.NODE_ENV === "production") {
|
|
4275
|
+
return [
|
|
4276
|
+
warn(
|
|
4277
|
+
"missing_kv_in_production",
|
|
4278
|
+
"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."
|
|
4279
|
+
)
|
|
4280
|
+
];
|
|
4281
|
+
}
|
|
4282
|
+
return [];
|
|
4121
4283
|
}
|
|
4122
|
-
function
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
};
|
|
4284
|
+
function getConfiguredX402Accepts2(config) {
|
|
4285
|
+
if (config.x402?.accepts?.length) return [...config.x402.accepts];
|
|
4286
|
+
return [
|
|
4287
|
+
{
|
|
4288
|
+
scheme: "exact",
|
|
4289
|
+
network: config.network ?? BASE_MAINNET_NETWORK,
|
|
4290
|
+
payTo: config.payeeAddress
|
|
4291
|
+
}
|
|
4292
|
+
];
|
|
4132
4293
|
}
|
|
4133
|
-
function
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
}
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4294
|
+
function validateX402Config(config, env, options) {
|
|
4295
|
+
const accepts = getConfiguredX402Accepts2(config);
|
|
4296
|
+
const issues = [];
|
|
4297
|
+
const push = (code, message) => issues.push({ code, protocol: "x402", message });
|
|
4298
|
+
if (accepts.length === 0) {
|
|
4299
|
+
push("missing_x402_accepts", "x402 requires at least one accept configuration.");
|
|
4300
|
+
return issues;
|
|
4301
|
+
}
|
|
4302
|
+
if (accepts.some((a) => !a.network)) {
|
|
4303
|
+
push("missing_x402_network", "x402 accepts require a network.");
|
|
4304
|
+
}
|
|
4305
|
+
const unsupported = accepts.find((a) => a.network && !isX402Network(a.network));
|
|
4306
|
+
if (unsupported) {
|
|
4307
|
+
push(
|
|
4308
|
+
"unsupported_x402_network",
|
|
4309
|
+
`unsupported x402 network '${unsupported.network}'. Use eip155:* or solana:*.`
|
|
4310
|
+
);
|
|
4311
|
+
}
|
|
4312
|
+
if (accepts.some((a) => (a.scheme ?? "exact") !== "exact" && !a.asset)) {
|
|
4313
|
+
push("missing_x402_asset", "non-exact x402 accepts require an asset.");
|
|
4314
|
+
}
|
|
4315
|
+
if (accepts.some(
|
|
4316
|
+
(a) => a.decimals !== void 0 && (!Number.isInteger(a.decimals) || a.decimals < 0)
|
|
4317
|
+
)) {
|
|
4318
|
+
push("invalid_x402_decimals", "x402 accept decimals must be a non-negative integer.");
|
|
4319
|
+
}
|
|
4320
|
+
if (!config.payeeAddress && accepts.some((a) => !a.payTo)) {
|
|
4321
|
+
push(
|
|
4322
|
+
"missing_x402_payee",
|
|
4323
|
+
"x402 requires payeeAddress in router config or payTo on every x402 accept."
|
|
4324
|
+
);
|
|
4325
|
+
}
|
|
4326
|
+
const placeholder = [
|
|
4146
4327
|
config.payeeAddress,
|
|
4147
|
-
...accepts.map((
|
|
4148
|
-
]);
|
|
4149
|
-
if (
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
}
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
}
|
|
4328
|
+
...accepts.map((a) => typeof a.payTo === "string" ? a.payTo : void 0)
|
|
4329
|
+
].find((v) => v !== void 0 && isPlaceholderEvm(v));
|
|
4330
|
+
if (placeholder) {
|
|
4331
|
+
push(
|
|
4332
|
+
"placeholder_payee",
|
|
4333
|
+
`x402 payee '${placeholder}' is a placeholder address and cannot receive payments.`
|
|
4334
|
+
);
|
|
4335
|
+
}
|
|
4336
|
+
if (options.requireCdpKeys !== false) {
|
|
4337
|
+
const hasEvm = accepts.some(
|
|
4338
|
+
(a) => typeof a.network === "string" && a.network.startsWith("eip155:")
|
|
4339
|
+
);
|
|
4340
|
+
if (hasEvm) {
|
|
4341
|
+
const missing = ["CDP_API_KEY_ID", "CDP_API_KEY_SECRET"].filter((k) => !env[k]);
|
|
4342
|
+
if (missing.length > 0) {
|
|
4343
|
+
push(
|
|
4344
|
+
"missing_cdp_keys",
|
|
4345
|
+
`x402 EVM facilitator (Coinbase) requires ${missing.join(" and ")}.`
|
|
4346
|
+
);
|
|
4347
|
+
}
|
|
4348
|
+
}
|
|
4349
|
+
}
|
|
4350
|
+
return issues;
|
|
4169
4351
|
}
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
|
|
4173
|
-
var CHECKS2 = [
|
|
4174
|
-
checkSecretKey,
|
|
4175
|
-
checkCurrency,
|
|
4176
|
-
checkRecipient,
|
|
4177
|
-
checkPlaceholderRecipient,
|
|
4178
|
-
checkRpcUrl,
|
|
4179
|
-
checkFeePayerKey,
|
|
4180
|
-
checkOperatorKey,
|
|
4181
|
-
checkOperatorMatchesFeePayer
|
|
4182
|
-
];
|
|
4183
|
-
function validateMppConfig(config, env) {
|
|
4184
|
-
const mpp = config.mpp;
|
|
4185
|
-
if (!mpp) {
|
|
4352
|
+
function validateMppConfig(config) {
|
|
4353
|
+
const m = config.mpp;
|
|
4354
|
+
if (!m) {
|
|
4186
4355
|
return [
|
|
4187
4356
|
{
|
|
4188
4357
|
code: "missing_mpp_config",
|
|
@@ -4191,109 +4360,184 @@ function validateMppConfig(config, env) {
|
|
|
4191
4360
|
}
|
|
4192
4361
|
];
|
|
4193
4362
|
}
|
|
4194
|
-
const
|
|
4195
|
-
|
|
4196
|
-
|
|
4363
|
+
const issues = [];
|
|
4364
|
+
const push = (code, message) => issues.push({ code, protocol: "mpp", message });
|
|
4365
|
+
if (!m.secretKey) {
|
|
4366
|
+
push(
|
|
4367
|
+
"missing_mpp_secret_key",
|
|
4368
|
+
"MPP requires secretKey. Set MPP_SECRET_KEY or pass mpp.secretKey."
|
|
4369
|
+
);
|
|
4370
|
+
}
|
|
4371
|
+
if (!m.currency) {
|
|
4372
|
+
push("missing_mpp_currency", "MPP requires currency. Set MPP_CURRENCY or pass mpp.currency.");
|
|
4373
|
+
} else if (!isEvmAddress(m.currency)) {
|
|
4374
|
+
push(
|
|
4375
|
+
"invalid_mpp_currency",
|
|
4376
|
+
"MPP currency must be a 0x-prefixed 20-byte Tempo currency address. Use TEMPO_USDC_ADDRESS for Tempo USDC."
|
|
4377
|
+
);
|
|
4378
|
+
}
|
|
4379
|
+
const recipient = m.recipient ?? config.payeeAddress;
|
|
4380
|
+
if (!recipient) {
|
|
4381
|
+
push(
|
|
4382
|
+
"missing_mpp_recipient",
|
|
4383
|
+
"MPP requires a recipient address. Set mpp.recipient or payeeAddress in your router config."
|
|
4384
|
+
);
|
|
4385
|
+
} else if (!isEvmAddress(recipient)) {
|
|
4386
|
+
push(
|
|
4387
|
+
"invalid_mpp_recipient",
|
|
4388
|
+
"MPP recipient must be a 0x-prefixed EVM address. Solana recipients require x402."
|
|
4389
|
+
);
|
|
4390
|
+
}
|
|
4391
|
+
const placeholder = [m.recipient, config.payeeAddress].find(
|
|
4392
|
+
(v) => typeof v === "string" && isPlaceholderEvm(v)
|
|
4197
4393
|
);
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
protocol: "mpp",
|
|
4204
|
-
message: "MPP requires secretKey. Set MPP_SECRET_KEY or pass mpp.secretKey."
|
|
4205
|
-
};
|
|
4206
|
-
}
|
|
4207
|
-
function checkCurrency({ mpp }) {
|
|
4208
|
-
if (!mpp.currency) {
|
|
4209
|
-
return {
|
|
4210
|
-
code: "missing_mpp_currency",
|
|
4211
|
-
protocol: "mpp",
|
|
4212
|
-
message: "MPP requires currency. Set MPP_CURRENCY or pass mpp.currency."
|
|
4213
|
-
};
|
|
4394
|
+
if (placeholder) {
|
|
4395
|
+
push(
|
|
4396
|
+
"placeholder_payee",
|
|
4397
|
+
`MPP recipient '${placeholder}' is a placeholder address and cannot receive payments.`
|
|
4398
|
+
);
|
|
4214
4399
|
}
|
|
4215
|
-
if (!
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
};
|
|
4400
|
+
if (!m.rpcUrl) {
|
|
4401
|
+
push(
|
|
4402
|
+
"missing_mpp_rpc_url",
|
|
4403
|
+
"MPP requires an authenticated Tempo RPC URL. Set TEMPO_RPC_URL env var or pass rpcUrl in the mpp config object."
|
|
4404
|
+
);
|
|
4221
4405
|
}
|
|
4222
|
-
|
|
4406
|
+
if (m.feePayerKey && !isEvmPrivateKey(m.feePayerKey)) {
|
|
4407
|
+
push(
|
|
4408
|
+
"invalid_mpp_fee_payer_key",
|
|
4409
|
+
"MPP feePayerKey must be a 0x-prefixed 32-byte EVM private key."
|
|
4410
|
+
);
|
|
4411
|
+
}
|
|
4412
|
+
if (m.operatorKey && !isEvmPrivateKey(m.operatorKey)) {
|
|
4413
|
+
push(
|
|
4414
|
+
"invalid_mpp_operator_key",
|
|
4415
|
+
"MPP operatorKey must be a 0x-prefixed 32-byte EVM private key."
|
|
4416
|
+
);
|
|
4417
|
+
}
|
|
4418
|
+
const collision = operatorAddressesCollide(m.operatorKey, m.feePayerKey);
|
|
4419
|
+
if (collision) {
|
|
4420
|
+
push(
|
|
4421
|
+
"mpp_operator_equals_fee_payer",
|
|
4422
|
+
`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).`
|
|
4423
|
+
);
|
|
4424
|
+
}
|
|
4425
|
+
return issues;
|
|
4223
4426
|
}
|
|
4224
|
-
function
|
|
4225
|
-
|
|
4226
|
-
|
|
4427
|
+
function translateZodIssues(error) {
|
|
4428
|
+
return error.issues.map((issue) => {
|
|
4429
|
+
const params = issue.params;
|
|
4430
|
+
if (!params?.code) {
|
|
4431
|
+
throw new Error(
|
|
4432
|
+
`[router] schema issue missing params.code (path=${issue.path.join(".")}, message=${issue.message}). Every refinement / addIssue call must set params.code.`
|
|
4433
|
+
);
|
|
4434
|
+
}
|
|
4227
4435
|
return {
|
|
4228
|
-
code:
|
|
4229
|
-
|
|
4230
|
-
|
|
4436
|
+
code: params.code,
|
|
4437
|
+
message: issue.message,
|
|
4438
|
+
...params.protocol ? { protocol: params.protocol } : {},
|
|
4439
|
+
...params.severity ? { severity: params.severity } : {}
|
|
4231
4440
|
};
|
|
4441
|
+
});
|
|
4442
|
+
}
|
|
4443
|
+
function routerConfigFromEnv(options) {
|
|
4444
|
+
const rawEnv = options.env ?? process.env;
|
|
4445
|
+
const env = trimAll(rawEnv);
|
|
4446
|
+
const optionIssues = [];
|
|
4447
|
+
if (!options.title?.trim()) {
|
|
4448
|
+
optionIssues.push({
|
|
4449
|
+
code: "missing_discovery_title",
|
|
4450
|
+
message: "discovery `title` is required. Pass a short product name."
|
|
4451
|
+
});
|
|
4232
4452
|
}
|
|
4233
|
-
if (!
|
|
4234
|
-
|
|
4235
|
-
code: "
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
};
|
|
4453
|
+
if (!options.description?.trim()) {
|
|
4454
|
+
optionIssues.push({
|
|
4455
|
+
code: "missing_discovery_description",
|
|
4456
|
+
message: "discovery `description` is required. One sentence is enough."
|
|
4457
|
+
});
|
|
4239
4458
|
}
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
}
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
}
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
const
|
|
4279
|
-
const
|
|
4280
|
-
|
|
4459
|
+
if (options.guidance === void 0) {
|
|
4460
|
+
optionIssues.push({
|
|
4461
|
+
code: "missing_discovery_guidance",
|
|
4462
|
+
message: "discovery `guidance` is required. Provide an empty string to opt out of `/llms.txt`."
|
|
4463
|
+
});
|
|
4464
|
+
}
|
|
4465
|
+
if (options.serverUrl !== void 0 && !isUrl(options.serverUrl)) {
|
|
4466
|
+
optionIssues.push({
|
|
4467
|
+
code: "invalid_server_url",
|
|
4468
|
+
message: `discovery \`serverUrl\` must be a valid URL. Got: ${options.serverUrl}`
|
|
4469
|
+
});
|
|
4470
|
+
}
|
|
4471
|
+
const parsed = EnvInputSchema.safeParse(env);
|
|
4472
|
+
const envIssues = parsed.success ? [] : translateZodIssues(parsed.error);
|
|
4473
|
+
const issues = [...envIssues, ...optionIssues];
|
|
4474
|
+
if (issues.length > 0) throw new RouterConfigError(issues);
|
|
4475
|
+
for (const warning of collectKvWarnings(env, options.kvStore !== void 0)) {
|
|
4476
|
+
console.warn(`[router] ${warning.message}`);
|
|
4477
|
+
}
|
|
4478
|
+
const payeeAddress = canonicalizeEvm(env.EVM_PAYEE_ADDRESS);
|
|
4479
|
+
const accepts = [
|
|
4480
|
+
{ scheme: "exact", network: BASE_MAINNET_NETWORK, payTo: payeeAddress },
|
|
4481
|
+
{
|
|
4482
|
+
scheme: "upto",
|
|
4483
|
+
network: BASE_MAINNET_NETWORK,
|
|
4484
|
+
payTo: payeeAddress,
|
|
4485
|
+
asset: BASE_USDC_ADDRESS,
|
|
4486
|
+
decimals: BASE_USDC_DECIMALS
|
|
4487
|
+
}
|
|
4488
|
+
];
|
|
4489
|
+
if (env.SOLANA_PAYEE_ADDRESS) {
|
|
4490
|
+
accepts.push({
|
|
4491
|
+
scheme: "exact",
|
|
4492
|
+
network: SOLANA_MAINNET_NETWORK,
|
|
4493
|
+
payTo: env.SOLANA_PAYEE_ADDRESS
|
|
4494
|
+
});
|
|
4495
|
+
}
|
|
4496
|
+
const configuredSolanaFacilitator = options.x402Facilitators?.solana;
|
|
4497
|
+
const solanaFacilitator = typeof configuredSolanaFacilitator === "string" ? configuredSolanaFacilitator : configuredSolanaFacilitator ?? env.SOLANA_FACILITATOR_URL ?? DEFAULT_SOLANA_FACILITATOR_URL;
|
|
4498
|
+
const mppEnabled = options.protocols?.includes("mpp") ?? Boolean(env.MPP_SECRET_KEY);
|
|
4499
|
+
const protocols = options.protocols ? [...options.protocols] : mppEnabled ? ["x402", "mpp"] : ["x402"];
|
|
4500
|
+
const mppConfig = mppEnabled ? {
|
|
4501
|
+
secretKey: env.MPP_SECRET_KEY,
|
|
4502
|
+
currency: canonicalizeEvm(env.MPP_CURRENCY),
|
|
4503
|
+
rpcUrl: env.TEMPO_RPC_URL,
|
|
4504
|
+
recipient: payeeAddress,
|
|
4505
|
+
...env.MPP_FEE_PAYER_KEY ? { feePayerKey: env.MPP_FEE_PAYER_KEY } : {},
|
|
4506
|
+
...env.MPP_OPERATOR_KEY ? { operatorKey: env.MPP_OPERATOR_KEY, session: {} } : {}
|
|
4507
|
+
} : void 0;
|
|
4281
4508
|
return {
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4509
|
+
payeeAddress,
|
|
4510
|
+
baseUrl: env.BASE_URL,
|
|
4511
|
+
network: BASE_MAINNET_NETWORK,
|
|
4512
|
+
protocols,
|
|
4513
|
+
x402: {
|
|
4514
|
+
accepts,
|
|
4515
|
+
facilitators: {
|
|
4516
|
+
...options.x402Facilitators,
|
|
4517
|
+
solana: solanaFacilitator
|
|
4518
|
+
}
|
|
4519
|
+
},
|
|
4520
|
+
...mppConfig ? { mpp: mppConfig } : {},
|
|
4521
|
+
discovery: {
|
|
4522
|
+
title: options.title,
|
|
4523
|
+
version: options.version ?? "1.0.0",
|
|
4524
|
+
description: options.description,
|
|
4525
|
+
guidance: options.guidance,
|
|
4526
|
+
...options.contact ? { contact: options.contact } : {},
|
|
4527
|
+
...options.ownershipProofs ? { ownershipProofs: options.ownershipProofs } : {},
|
|
4528
|
+
...options.methodHints ? { methodHints: options.methodHints } : {},
|
|
4529
|
+
...options.serverUrl ? { serverUrl: options.serverUrl } : {}
|
|
4530
|
+
},
|
|
4531
|
+
...options.prices ? { prices: options.prices } : {},
|
|
4532
|
+
...options.plugin ? { plugin: options.plugin } : {},
|
|
4533
|
+
...options.kvStore ? { kvStore: options.kvStore } : {},
|
|
4534
|
+
strictRoutes: options.strictRoutes ?? false
|
|
4285
4535
|
};
|
|
4286
4536
|
}
|
|
4287
|
-
|
|
4288
|
-
// src/config/validate.ts
|
|
4289
|
-
function validateRouterConfig(config, options = {}) {
|
|
4290
|
-
const issues = getRouterConfigIssues(config, options);
|
|
4291
|
-
if (issues.length > 0) throw new RouterConfigError(issues);
|
|
4292
|
-
}
|
|
4293
4537
|
function getRouterConfigIssues(config, options = {}) {
|
|
4294
|
-
const env = options.env ??
|
|
4295
|
-
const issues = [];
|
|
4538
|
+
const env = options.env ?? {};
|
|
4296
4539
|
const protocols = config.protocols ?? ["x402"];
|
|
4540
|
+
const issues = [];
|
|
4297
4541
|
if (!config.baseUrl) {
|
|
4298
4542
|
issues.push({
|
|
4299
4543
|
code: "missing_base_url",
|
|
@@ -4306,84 +4550,17 @@ function getRouterConfigIssues(config, options = {}) {
|
|
|
4306
4550
|
message: "RouterConfig.protocols cannot be empty. Omit the field to use default ['x402'] or specify protocols explicitly."
|
|
4307
4551
|
});
|
|
4308
4552
|
}
|
|
4309
|
-
if (protocols.includes("x402"))
|
|
4310
|
-
|
|
4311
|
-
}
|
|
4312
|
-
if (protocols.includes("mpp")) {
|
|
4313
|
-
issues.push(...validateMppConfig(config, env));
|
|
4314
|
-
}
|
|
4553
|
+
if (protocols.includes("x402")) issues.push(...validateX402Config(config, env, options));
|
|
4554
|
+
if (protocols.includes("mpp")) issues.push(...validateMppConfig(config));
|
|
4315
4555
|
return issues;
|
|
4316
4556
|
}
|
|
4317
4557
|
|
|
4318
|
-
// src/config/env.ts
|
|
4319
|
-
init_constants();
|
|
4320
|
-
function mppFromEnv(env, options = {}) {
|
|
4321
|
-
const secretKey = env.MPP_SECRET_KEY;
|
|
4322
|
-
const currency = env.MPP_CURRENCY;
|
|
4323
|
-
const rpcUrl = env.TEMPO_RPC_URL;
|
|
4324
|
-
const feePayerKey = options.feePayerKey ?? env.MPP_FEE_PAYER_KEY;
|
|
4325
|
-
const feePayerKeySource = options.feePayerKey !== void 0 ? "feePayerKey" : "MPP_FEE_PAYER_KEY";
|
|
4326
|
-
const hasAnyMppEnv = Boolean(secretKey || currency || rpcUrl || options.require);
|
|
4327
|
-
if (!hasAnyMppEnv) return void 0;
|
|
4328
|
-
const missing = [
|
|
4329
|
-
secretKey ? null : "MPP_SECRET_KEY",
|
|
4330
|
-
currency ? null : "MPP_CURRENCY",
|
|
4331
|
-
rpcUrl ? null : "TEMPO_RPC_URL"
|
|
4332
|
-
].filter(Boolean);
|
|
4333
|
-
if (missing.length > 0) {
|
|
4334
|
-
throw new Error(`MPP env is incomplete. Missing: ${missing.join(", ")}`);
|
|
4335
|
-
}
|
|
4336
|
-
if (!isEvmAddress(currency)) {
|
|
4337
|
-
throw new Error("MPP_CURRENCY must be a 0x-prefixed 20-byte Tempo currency address");
|
|
4338
|
-
}
|
|
4339
|
-
if (options.recipient && !isEvmAddress(options.recipient)) {
|
|
4340
|
-
throw new Error("MPP recipient must be a 0x-prefixed EVM address");
|
|
4341
|
-
}
|
|
4342
|
-
if (feePayerKey && !isEvmPrivateKey(feePayerKey)) {
|
|
4343
|
-
throw new Error(`${feePayerKeySource} must be a 0x-prefixed 32-byte EVM private key`);
|
|
4344
|
-
}
|
|
4345
|
-
return {
|
|
4346
|
-
secretKey,
|
|
4347
|
-
currency,
|
|
4348
|
-
rpcUrl,
|
|
4349
|
-
...options.recipient ? { recipient: options.recipient } : {},
|
|
4350
|
-
...feePayerKey ? { feePayerKey } : {}
|
|
4351
|
-
};
|
|
4352
|
-
}
|
|
4353
|
-
function x402AcceptsFromEnv(env, options = {}) {
|
|
4354
|
-
const payeeEnv = options.payeeEnv ?? "X402_WALLET_ADDRESS";
|
|
4355
|
-
const solanaPayeeEnv = options.solanaPayeeEnv ?? "SOLANA_PAYEE_ADDRESS";
|
|
4356
|
-
const payeeAddress = options.payeeAddress ?? env[payeeEnv];
|
|
4357
|
-
if (!payeeAddress) {
|
|
4358
|
-
throw new Error(`${payeeEnv} is required to build x402 accepts`);
|
|
4359
|
-
}
|
|
4360
|
-
const accepts = [
|
|
4361
|
-
{
|
|
4362
|
-
scheme: "exact",
|
|
4363
|
-
network: options.network ?? BASE_NETWORK,
|
|
4364
|
-
payTo: payeeAddress
|
|
4365
|
-
}
|
|
4366
|
-
];
|
|
4367
|
-
const solanaPayeeAddress = options.solanaPayeeAddress ?? env[solanaPayeeEnv];
|
|
4368
|
-
if (solanaPayeeAddress) {
|
|
4369
|
-
accepts.push({
|
|
4370
|
-
scheme: "exact",
|
|
4371
|
-
network: SOLANA_MAINNET_NETWORK,
|
|
4372
|
-
payTo: solanaPayeeAddress
|
|
4373
|
-
});
|
|
4374
|
-
}
|
|
4375
|
-
return accepts;
|
|
4376
|
-
}
|
|
4377
|
-
function paidOptionsForProtocols(protocols) {
|
|
4378
|
-
return { protocols: [...protocols] };
|
|
4379
|
-
}
|
|
4380
|
-
|
|
4381
4558
|
// src/init/x402.ts
|
|
4382
|
-
async function initX402(config, configError) {
|
|
4559
|
+
async function initX402(config, kvStore, configError) {
|
|
4383
4560
|
if (configError) return { initError: configError };
|
|
4384
4561
|
try {
|
|
4385
|
-
const { createX402Server: createX402Server2 } = await Promise.resolve().then(() => (
|
|
4386
|
-
const result = await createX402Server2(config);
|
|
4562
|
+
const { createX402Server: createX402Server2 } = await Promise.resolve().then(() => (init_x402_server(), x402_server_exports));
|
|
4563
|
+
const result = await createX402Server2(config, kvStore);
|
|
4387
4564
|
await result.initPromise;
|
|
4388
4565
|
return {
|
|
4389
4566
|
server: result.server,
|
|
@@ -4394,7 +4571,7 @@ async function initX402(config, configError) {
|
|
|
4394
4571
|
}
|
|
4395
4572
|
}
|
|
4396
4573
|
|
|
4397
|
-
// src/mppx
|
|
4574
|
+
// src/init/mppx.ts
|
|
4398
4575
|
function getMppxRequestContext(args) {
|
|
4399
4576
|
const {
|
|
4400
4577
|
Mppx,
|
|
@@ -4516,9 +4693,10 @@ function createRouter(config) {
|
|
|
4516
4693
|
const kvStore = resolveKvStore(config.kvStore);
|
|
4517
4694
|
const nonceStore = kvStore ? createKvNonceStore(kvStore) : new MemoryNonceStore();
|
|
4518
4695
|
const entitlementStore = kvStore ? createKvEntitlementStore(kvStore) : new MemoryEntitlementStore();
|
|
4519
|
-
const network = config.network ??
|
|
4696
|
+
const network = config.network ?? BASE_MAINNET_NETWORK;
|
|
4520
4697
|
const x402Accepts = getConfiguredX402Accepts(config);
|
|
4521
4698
|
const configIssues = getRouterConfigIssues(config, {
|
|
4699
|
+
env: process.env,
|
|
4522
4700
|
requireCdpKeys: process.env.NODE_ENV === "production"
|
|
4523
4701
|
});
|
|
4524
4702
|
const baseUrlIssue = configIssues.find((issue) => issue.code === "missing_base_url");
|
|
@@ -4565,7 +4743,7 @@ function createRouter(config) {
|
|
|
4565
4743
|
mppSessionConfig: config.mpp?.session ? { depositMultiplier: config.mpp.session.depositMultiplier ?? 10 } : null
|
|
4566
4744
|
};
|
|
4567
4745
|
deps.initPromise = (async () => {
|
|
4568
|
-
const x402Result = await initX402(config, x402ConfigError);
|
|
4746
|
+
const x402Result = await initX402(config, kvStore, x402ConfigError);
|
|
4569
4747
|
deps.x402Server = x402Result.server ?? null;
|
|
4570
4748
|
deps.x402FacilitatorsByNetwork = x402Result.facilitatorsByNetwork;
|
|
4571
4749
|
if (x402Result.initError) deps.x402InitError = x402Result.initError;
|
|
@@ -4594,11 +4772,10 @@ function createRouter(config) {
|
|
|
4594
4772
|
`[router] strictRoutes=true forbids key/path divergence for route '${definition.path}'. Remove custom \`key\` or make it equal to \`path\`.`
|
|
4595
4773
|
);
|
|
4596
4774
|
}
|
|
4597
|
-
let builder = new RouteBuilder(key, registry, deps
|
|
4775
|
+
let builder = new RouteBuilder(key, registry, deps, {
|
|
4776
|
+
protocols: config.protocols
|
|
4777
|
+
});
|
|
4598
4778
|
builder = builder.path(normalizedPath);
|
|
4599
|
-
if (config.protocols) {
|
|
4600
|
-
builder._protocols = [...config.protocols];
|
|
4601
|
-
}
|
|
4602
4779
|
if (definition.method) {
|
|
4603
4780
|
builder = builder.method(definition.method);
|
|
4604
4781
|
}
|
|
@@ -4641,30 +4818,22 @@ function normalizePath(path) {
|
|
|
4641
4818
|
normalized = normalized.replace(/^api\/+/, "");
|
|
4642
4819
|
return normalized.replace(/\/+$/, "");
|
|
4643
4820
|
}
|
|
4821
|
+
function createRouterFromEnv(options) {
|
|
4822
|
+
return createRouter(routerConfigFromEnv(options));
|
|
4823
|
+
}
|
|
4644
4824
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4645
4825
|
0 && (module.exports = {
|
|
4646
|
-
|
|
4826
|
+
BASE_MAINNET_NETWORK,
|
|
4827
|
+
BASE_USDC_ADDRESS,
|
|
4828
|
+
BASE_USDC_DECIMALS,
|
|
4829
|
+
DEFAULT_SOLANA_FACILITATOR_URL,
|
|
4647
4830
|
HttpError,
|
|
4648
|
-
MemoryEntitlementStore,
|
|
4649
|
-
MemoryNonceStore,
|
|
4650
|
-
RouteBuilder,
|
|
4651
|
-
RouteRegistry,
|
|
4652
4831
|
RouterConfigError,
|
|
4653
|
-
SIWX_CHALLENGE_EXPIRY_MS,
|
|
4654
|
-
SIWX_ERROR_MESSAGES,
|
|
4655
4832
|
SOLANA_MAINNET_NETWORK,
|
|
4656
|
-
|
|
4833
|
+
TEMPO_USDC_ADDRESS,
|
|
4834
|
+
TEMPO_USDC_DECIMALS,
|
|
4657
4835
|
ZERO_EVM_ADDRESS,
|
|
4658
|
-
consolePlugin,
|
|
4659
|
-
createKvEntitlementStore,
|
|
4660
|
-
createKvMppStore,
|
|
4661
|
-
createKvNonceStore,
|
|
4662
4836
|
createRouter,
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
mppFromEnv,
|
|
4666
|
-
paidOptionsForProtocols,
|
|
4667
|
-
validateRouterConfig,
|
|
4668
|
-
withPrefix,
|
|
4669
|
-
x402AcceptsFromEnv
|
|
4837
|
+
createRouterFromEnv,
|
|
4838
|
+
routerConfigFromEnv
|
|
4670
4839
|
});
|