@agentcash/router 1.11.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +15 -4
- package/README.md +40 -6
- package/dist/index.cjs +269 -259
- package/dist/index.d.cts +92 -34
- package/dist/index.d.ts +92 -34
- package/dist/index.js +268 -259
- package/package.json +5 -5
package/dist/index.cjs
CHANGED
|
@@ -473,6 +473,7 @@ __export(index_exports, {
|
|
|
473
473
|
DEFAULT_SOLANA_FACILITATOR_URL: () => DEFAULT_SOLANA_FACILITATOR_URL,
|
|
474
474
|
DEFAULT_TEMPO_RPC_URL: () => DEFAULT_TEMPO_RPC_URL,
|
|
475
475
|
HttpError: () => HttpError,
|
|
476
|
+
RouteDefinitionError: () => RouteDefinitionError,
|
|
476
477
|
RouterConfigError: () => RouterConfigError,
|
|
477
478
|
SOLANA_MAINNET_NETWORK: () => SOLANA_MAINNET_NETWORK,
|
|
478
479
|
TEMPO_USDC_ADDRESS: () => TEMPO_USDC_ADDRESS,
|
|
@@ -873,6 +874,13 @@ var HttpError = class extends Error {
|
|
|
873
874
|
this.name = "HttpError";
|
|
874
875
|
}
|
|
875
876
|
};
|
|
877
|
+
var RouteDefinitionError = class extends Error {
|
|
878
|
+
constructor(route, detail) {
|
|
879
|
+
super(`route '${route}': ${detail}`);
|
|
880
|
+
this.route = route;
|
|
881
|
+
this.name = "RouteDefinitionError";
|
|
882
|
+
}
|
|
883
|
+
};
|
|
876
884
|
|
|
877
885
|
// src/auth/agent-identity.ts
|
|
878
886
|
var PROTOCOL_VERSION = 1;
|
|
@@ -1400,6 +1408,23 @@ function multiplyDecimal(decimal, factor) {
|
|
|
1400
1408
|
return fracPart ? `${intPart}.${fracPart}` : intPart;
|
|
1401
1409
|
}
|
|
1402
1410
|
|
|
1411
|
+
// src/protocols/detect.ts
|
|
1412
|
+
function hasX402Payment(request) {
|
|
1413
|
+
return Boolean(
|
|
1414
|
+
request.headers.get(HEADERS.X402_PAYMENT_SIGNATURE) ?? request.headers.get(HEADERS.X402_PAYMENT_LEGACY)
|
|
1415
|
+
);
|
|
1416
|
+
}
|
|
1417
|
+
function hasMppPayment(request) {
|
|
1418
|
+
const auth = request.headers.get(HEADERS.AUTHORIZATION);
|
|
1419
|
+
return Boolean(auth && auth.startsWith(AUTH_SCHEME.MPP_PAYMENT));
|
|
1420
|
+
}
|
|
1421
|
+
function detectProtocol(request) {
|
|
1422
|
+
if (hasX402Payment(request)) return "x402";
|
|
1423
|
+
if (hasMppPayment(request)) return "mpp";
|
|
1424
|
+
if (request.headers.get(HEADERS.SIWX)) return "siwx";
|
|
1425
|
+
return null;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1403
1428
|
// src/protocols/mpp/credential.ts
|
|
1404
1429
|
var import_mppx = require("mppx");
|
|
1405
1430
|
var import_viem = require("viem");
|
|
@@ -1766,10 +1791,7 @@ function settleHashMode(args) {
|
|
|
1766
1791
|
// src/protocols/mpp/strategy.ts
|
|
1767
1792
|
var mppStrategy = {
|
|
1768
1793
|
protocol: "mpp",
|
|
1769
|
-
detects
|
|
1770
|
-
const auth = request.headers.get(HEADERS.AUTHORIZATION);
|
|
1771
|
-
return Boolean(auth && auth.startsWith(AUTH_SCHEME.MPP_PAYMENT));
|
|
1772
|
-
},
|
|
1794
|
+
detects: hasMppPayment,
|
|
1773
1795
|
preflight(request, _routeEntry) {
|
|
1774
1796
|
const info = readMppCredential(request);
|
|
1775
1797
|
if (!info?.sessionAction) return null;
|
|
@@ -2204,11 +2226,7 @@ function formatVerifyFailureMessage(failure) {
|
|
|
2204
2226
|
}
|
|
2205
2227
|
var x402Strategy = {
|
|
2206
2228
|
protocol: "x402",
|
|
2207
|
-
detects
|
|
2208
|
-
return Boolean(
|
|
2209
|
-
request.headers.get(HEADERS.X402_PAYMENT_SIGNATURE) ?? request.headers.get(HEADERS.X402_PAYMENT_LEGACY)
|
|
2210
|
-
);
|
|
2211
|
-
},
|
|
2229
|
+
detects: hasX402Payment,
|
|
2212
2230
|
verify: (args) => verifyX402(args),
|
|
2213
2231
|
settle: (args) => settleX402(args),
|
|
2214
2232
|
buildChallenge: (args) => buildX402ChallengeContribution(args)
|
|
@@ -2355,21 +2373,6 @@ function getAllowedStrategies(allowed) {
|
|
|
2355
2373
|
return allowed.map((name) => STRATEGIES[name]);
|
|
2356
2374
|
}
|
|
2357
2375
|
|
|
2358
|
-
// src/protocols/detect.ts
|
|
2359
|
-
function detectProtocol(request) {
|
|
2360
|
-
if (request.headers.get(HEADERS.X402_PAYMENT_SIGNATURE) ?? request.headers.get(HEADERS.X402_PAYMENT_LEGACY)) {
|
|
2361
|
-
return "x402";
|
|
2362
|
-
}
|
|
2363
|
-
const auth = request.headers.get(HEADERS.AUTHORIZATION);
|
|
2364
|
-
if (auth && auth.startsWith(AUTH_SCHEME.MPP_PAYMENT)) {
|
|
2365
|
-
return "mpp";
|
|
2366
|
-
}
|
|
2367
|
-
if (request.headers.get(HEADERS.SIWX)) {
|
|
2368
|
-
return "siwx";
|
|
2369
|
-
}
|
|
2370
|
-
return null;
|
|
2371
|
-
}
|
|
2372
|
-
|
|
2373
2376
|
// src/pipeline/flows/api-key-only.ts
|
|
2374
2377
|
async function runApiKeyOnlyFlow(ctx) {
|
|
2375
2378
|
if (!ctx.routeEntry.apiKeyResolver) {
|
|
@@ -2692,6 +2695,61 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
|
|
|
2692
2695
|
return response;
|
|
2693
2696
|
}
|
|
2694
2697
|
|
|
2698
|
+
// src/pipeline/flows/paid-preamble.ts
|
|
2699
|
+
async function runPaidPreamble(ctx) {
|
|
2700
|
+
const { request, routeEntry, deps, report } = ctx;
|
|
2701
|
+
const apiKeyGate = await runApiKeyGate(ctx);
|
|
2702
|
+
if (!apiKeyGate.ok) return { done: true, response: apiKeyGate.response };
|
|
2703
|
+
const { account } = apiKeyGate;
|
|
2704
|
+
const pricing = selectPricing(routeEntry.pricing, {
|
|
2705
|
+
alert: report,
|
|
2706
|
+
maxPrice: routeEntry.maxPrice,
|
|
2707
|
+
minPrice: routeEntry.minPrice,
|
|
2708
|
+
route: routeEntry.key
|
|
2709
|
+
});
|
|
2710
|
+
const incomingStrategy = selectIncomingStrategy(request, routeEntry.protocols);
|
|
2711
|
+
const earlyResolution = await resolveEarlyBody({ ctx, pricing, incomingStrategy });
|
|
2712
|
+
if (!earlyResolution.ok) return { done: true, response: earlyResolution.response };
|
|
2713
|
+
const { earlyBody } = earlyResolution;
|
|
2714
|
+
const siwxFastPath = await trySiwxFastPath(ctx, account);
|
|
2715
|
+
if (siwxFastPath) return { done: true, response: siwxFastPath };
|
|
2716
|
+
if (!incomingStrategy) {
|
|
2717
|
+
const initError = protocolInitError(routeEntry, deps);
|
|
2718
|
+
if (initError) return { done: true, response: fail(ctx, 500, initError) };
|
|
2719
|
+
return { done: true, response: await buildChallengeResponse(ctx, pricing, earlyBody) };
|
|
2720
|
+
}
|
|
2721
|
+
return { done: false, account, pricing, incomingStrategy, earlyBody };
|
|
2722
|
+
}
|
|
2723
|
+
async function runPaidVerify(args) {
|
|
2724
|
+
const { ctx, strategy, pricing, parsedBody, price } = args;
|
|
2725
|
+
const { request, routeEntry, deps, report } = ctx;
|
|
2726
|
+
const verifyOutcome = await strategy.verify({
|
|
2727
|
+
request,
|
|
2728
|
+
body: parsedBody,
|
|
2729
|
+
price,
|
|
2730
|
+
routeEntry,
|
|
2731
|
+
deps,
|
|
2732
|
+
report
|
|
2733
|
+
});
|
|
2734
|
+
if (verifyOutcome.ok === false) {
|
|
2735
|
+
if (verifyOutcome.kind === "config") {
|
|
2736
|
+
return { ok: false, response: fail(ctx, 500, verifyOutcome.message, parsedBody) };
|
|
2737
|
+
}
|
|
2738
|
+
return {
|
|
2739
|
+
ok: false,
|
|
2740
|
+
response: await buildChallengeResponse(ctx, pricing, parsedBody, verifyOutcome.failure)
|
|
2741
|
+
};
|
|
2742
|
+
}
|
|
2743
|
+
ctx.pluginCtx.setVerifiedWallet(verifyOutcome.wallet);
|
|
2744
|
+
firePaymentVerified(ctx, {
|
|
2745
|
+
protocol: strategy.protocol,
|
|
2746
|
+
payer: verifyOutcome.wallet,
|
|
2747
|
+
amount: price,
|
|
2748
|
+
network: verifyOutcome.payment.network
|
|
2749
|
+
});
|
|
2750
|
+
return { ok: true, verifyOutcome };
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2695
2753
|
// src/pipeline/flows/dynamic/dynamic-body-and-price.ts
|
|
2696
2754
|
async function resolveDynamicBodyAndPrice(args) {
|
|
2697
2755
|
const { ctx, pricing, skipBody } = args;
|
|
@@ -3058,27 +3116,10 @@ async function runDynamicStreamFlow(args) {
|
|
|
3058
3116
|
|
|
3059
3117
|
// src/pipeline/flows/dynamic/dynamic-paid.ts
|
|
3060
3118
|
async function runDynamicPaidFlow(ctx) {
|
|
3061
|
-
const { request, routeEntry
|
|
3062
|
-
const
|
|
3063
|
-
if (
|
|
3064
|
-
const { account } =
|
|
3065
|
-
const pricing = selectPricing(routeEntry.pricing, {
|
|
3066
|
-
alert: report,
|
|
3067
|
-
maxPrice: routeEntry.maxPrice,
|
|
3068
|
-
minPrice: routeEntry.minPrice,
|
|
3069
|
-
route: routeEntry.key
|
|
3070
|
-
});
|
|
3071
|
-
const incomingStrategy = selectIncomingStrategy(request, routeEntry.protocols);
|
|
3072
|
-
const earlyResolution = await resolveEarlyBody({ ctx, pricing, incomingStrategy });
|
|
3073
|
-
if (!earlyResolution.ok) return earlyResolution.response;
|
|
3074
|
-
const { earlyBody } = earlyResolution;
|
|
3075
|
-
const siwxFastPath = await trySiwxFastPath(ctx, account);
|
|
3076
|
-
if (siwxFastPath) return siwxFastPath;
|
|
3077
|
-
if (!incomingStrategy) {
|
|
3078
|
-
const initError = protocolInitError(routeEntry, deps);
|
|
3079
|
-
if (initError) return fail(ctx, 500, initError);
|
|
3080
|
-
return buildChallengeResponse(ctx, pricing, earlyBody);
|
|
3081
|
-
}
|
|
3119
|
+
const { request, routeEntry } = ctx;
|
|
3120
|
+
const preamble = await runPaidPreamble(ctx);
|
|
3121
|
+
if (preamble.done) return preamble.response;
|
|
3122
|
+
const { account, pricing, incomingStrategy } = preamble;
|
|
3082
3123
|
const { skipBody, skipHandler } = resolveDynamicPreflight(incomingStrategy, request, routeEntry);
|
|
3083
3124
|
if (skipHandler) {
|
|
3084
3125
|
return runDynamicChannelMgmtFlow({
|
|
@@ -3092,27 +3133,15 @@ async function runDynamicPaidFlow(ctx) {
|
|
|
3092
3133
|
const bodyAndPrice = await resolveDynamicBodyAndPrice({ ctx, pricing, skipBody });
|
|
3093
3134
|
if (!bodyAndPrice.ok) return bodyAndPrice.response;
|
|
3094
3135
|
const { parsedBody, price } = bodyAndPrice;
|
|
3095
|
-
const
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
report
|
|
3102
|
-
});
|
|
3103
|
-
if (verifyOutcome.ok === false) {
|
|
3104
|
-
if (verifyOutcome.kind === "config") {
|
|
3105
|
-
return fail(ctx, 500, verifyOutcome.message, parsedBody);
|
|
3106
|
-
}
|
|
3107
|
-
return buildChallengeResponse(ctx, pricing, parsedBody, verifyOutcome.failure);
|
|
3108
|
-
}
|
|
3109
|
-
ctx.pluginCtx.setVerifiedWallet(verifyOutcome.wallet);
|
|
3110
|
-
firePaymentVerified(ctx, {
|
|
3111
|
-
protocol: incomingStrategy.protocol,
|
|
3112
|
-
payer: verifyOutcome.wallet,
|
|
3113
|
-
amount: price,
|
|
3114
|
-
network: verifyOutcome.payment.network
|
|
3136
|
+
const verify = await runPaidVerify({
|
|
3137
|
+
ctx,
|
|
3138
|
+
strategy: incomingStrategy,
|
|
3139
|
+
pricing,
|
|
3140
|
+
parsedBody,
|
|
3141
|
+
price
|
|
3115
3142
|
});
|
|
3143
|
+
if (!verify.ok) return verify.response;
|
|
3144
|
+
const { verifyOutcome } = verify;
|
|
3116
3145
|
const result = await invokeDynamic(ctx, verifyOutcome, account, parsedBody);
|
|
3117
3146
|
switch (result.kind) {
|
|
3118
3147
|
case "stream":
|
|
@@ -3244,51 +3273,21 @@ function failureFromCause2(cause) {
|
|
|
3244
3273
|
|
|
3245
3274
|
// src/pipeline/flows/static/static-paid.ts
|
|
3246
3275
|
async function runStaticPaidFlow(ctx) {
|
|
3247
|
-
const
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
const { account } = apiKeyGate;
|
|
3251
|
-
const pricing = selectPricing(routeEntry.pricing, {
|
|
3252
|
-
alert: report,
|
|
3253
|
-
maxPrice: routeEntry.maxPrice,
|
|
3254
|
-
minPrice: routeEntry.minPrice,
|
|
3255
|
-
route: routeEntry.key
|
|
3256
|
-
});
|
|
3257
|
-
const incomingStrategy = selectIncomingStrategy(request, routeEntry.protocols);
|
|
3258
|
-
const earlyResolution = await resolveEarlyBody({ ctx, pricing, incomingStrategy });
|
|
3259
|
-
if (!earlyResolution.ok) return earlyResolution.response;
|
|
3260
|
-
const { earlyBody } = earlyResolution;
|
|
3261
|
-
const siwxFastPath = await trySiwxFastPath(ctx, account);
|
|
3262
|
-
if (siwxFastPath) return siwxFastPath;
|
|
3263
|
-
if (!incomingStrategy) {
|
|
3264
|
-
const initError = protocolInitError(routeEntry, deps);
|
|
3265
|
-
if (initError) return fail(ctx, 500, initError);
|
|
3266
|
-
return buildChallengeResponse(ctx, pricing, earlyBody);
|
|
3267
|
-
}
|
|
3276
|
+
const preamble = await runPaidPreamble(ctx);
|
|
3277
|
+
if (preamble.done) return preamble.response;
|
|
3278
|
+
const { account, pricing, incomingStrategy } = preamble;
|
|
3268
3279
|
const bodyAndPrice = await resolveStaticBodyAndPrice({ ctx, pricing });
|
|
3269
3280
|
if (!bodyAndPrice.ok) return bodyAndPrice.response;
|
|
3270
3281
|
const { parsedBody, price } = bodyAndPrice;
|
|
3271
|
-
const
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
report
|
|
3278
|
-
});
|
|
3279
|
-
if (verifyOutcome.ok === false) {
|
|
3280
|
-
if (verifyOutcome.kind === "config") {
|
|
3281
|
-
return fail(ctx, 500, verifyOutcome.message, parsedBody);
|
|
3282
|
-
}
|
|
3283
|
-
return buildChallengeResponse(ctx, pricing, parsedBody, verifyOutcome.failure);
|
|
3284
|
-
}
|
|
3285
|
-
ctx.pluginCtx.setVerifiedWallet(verifyOutcome.wallet);
|
|
3286
|
-
firePaymentVerified(ctx, {
|
|
3287
|
-
protocol: incomingStrategy.protocol,
|
|
3288
|
-
payer: verifyOutcome.wallet,
|
|
3289
|
-
amount: price,
|
|
3290
|
-
network: verifyOutcome.payment.network
|
|
3282
|
+
const verify = await runPaidVerify({
|
|
3283
|
+
ctx,
|
|
3284
|
+
strategy: incomingStrategy,
|
|
3285
|
+
pricing,
|
|
3286
|
+
parsedBody,
|
|
3287
|
+
price
|
|
3291
3288
|
});
|
|
3289
|
+
if (!verify.ok) return verify.response;
|
|
3290
|
+
const { verifyOutcome } = verify;
|
|
3292
3291
|
const result = await invokePaidStatic(
|
|
3293
3292
|
ctx,
|
|
3294
3293
|
verifyOutcome.wallet,
|
|
@@ -3780,55 +3779,35 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3780
3779
|
return next;
|
|
3781
3780
|
}
|
|
3782
3781
|
paid(arg, options) {
|
|
3783
|
-
|
|
3782
|
+
const self = this;
|
|
3783
|
+
return self.applyPaid(normalizePaidArg(self.#s.key, arg, options), "paid");
|
|
3784
3784
|
}
|
|
3785
|
-
/**
|
|
3786
|
-
* x402-only handler-computed billing. The handler receives `charge(amount)`
|
|
3787
|
-
* and the request settles once for the accumulated total, capped at
|
|
3788
|
-
* `maxPrice`. Requires an `'upto'` accept on at least one configured network.
|
|
3789
|
-
* Pass a bare string as sugar for `{ maxPrice }`.
|
|
3790
|
-
*
|
|
3791
|
-
* @example
|
|
3792
|
-
* ```ts
|
|
3793
|
-
* router.route('llm')
|
|
3794
|
-
* .upTo('0.05')
|
|
3795
|
-
* .body(schema)
|
|
3796
|
-
* .handler(async ({ body, charge }) => { await charge('0.001'); ... });
|
|
3797
|
-
* ```
|
|
3798
|
-
*/
|
|
3799
3785
|
upTo(arg) {
|
|
3800
|
-
|
|
3786
|
+
const self = this;
|
|
3787
|
+
return self.applyPaid(normalizeUpToArg(self.#s.key, arg), "upTo");
|
|
3801
3788
|
}
|
|
3802
|
-
/**
|
|
3803
|
-
* MPP-only per-tick billing. `.handler()` bills exactly `tickCost`;
|
|
3804
|
-
* `.stream()` calls `charge()` (no-arg) per yield, settling per tick up to
|
|
3805
|
-
* `maxPrice`. Requires `RouterConfig.mpp.session`.
|
|
3806
|
-
*
|
|
3807
|
-
* @example
|
|
3808
|
-
* ```ts
|
|
3809
|
-
* router.route('llm/stream')
|
|
3810
|
-
* .metered({ tickCost: '0.0001', maxPrice: '0.05', unitType: 'token' })
|
|
3811
|
-
* .stream(async function* ({ charge }) { await charge(); yield 'hi'; });
|
|
3812
|
-
* ```
|
|
3813
|
-
*/
|
|
3814
3789
|
metered(options) {
|
|
3815
|
-
|
|
3790
|
+
const self = this;
|
|
3791
|
+
return self.applyPaid(normalizeMeteredArg(self.#s.key, options), "metered");
|
|
3816
3792
|
}
|
|
3817
3793
|
applyPaid(normalized, method) {
|
|
3818
3794
|
const { pricing, resolvedOptions, billing, tickCost, unitType, maxPrice } = normalized;
|
|
3819
3795
|
if (this.#s.authMode === "unprotected") {
|
|
3820
|
-
throw new
|
|
3821
|
-
|
|
3796
|
+
throw new RouteDefinitionError(
|
|
3797
|
+
this.#s.key,
|
|
3798
|
+
`Cannot combine .unprotected() and .${method}() on the same route.`
|
|
3822
3799
|
);
|
|
3823
3800
|
}
|
|
3824
3801
|
if (this.#s.pricing !== void 0) {
|
|
3825
|
-
throw new
|
|
3826
|
-
|
|
3802
|
+
throw new RouteDefinitionError(
|
|
3803
|
+
this.#s.key,
|
|
3804
|
+
`Cannot combine .paid(), .upTo(), and .metered() \u2014 pick one pricing mode.`
|
|
3827
3805
|
);
|
|
3828
3806
|
}
|
|
3829
3807
|
if (this.#s.siwxEnabled && billing === "metered") {
|
|
3830
|
-
throw new
|
|
3831
|
-
|
|
3808
|
+
throw new RouteDefinitionError(
|
|
3809
|
+
this.#s.key,
|
|
3810
|
+
`Cannot combine .siwx() and .metered() \u2014 per-tick MPP billing has no entitlement model. Use .paid() or .upTo() with .siwx(), or drop .siwx() for metered routes.`
|
|
3832
3811
|
);
|
|
3833
3812
|
}
|
|
3834
3813
|
const next = this.fork();
|
|
@@ -3836,15 +3815,17 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3836
3815
|
next.#s.pricing = pricing;
|
|
3837
3816
|
if (billing === "upto") {
|
|
3838
3817
|
if (resolvedOptions.protocols?.some((p) => p !== "x402")) {
|
|
3839
|
-
throw new
|
|
3840
|
-
|
|
3818
|
+
throw new RouteDefinitionError(
|
|
3819
|
+
this.#s.key,
|
|
3820
|
+
`.upTo() is x402-only \u2014 remove the conflicting protocols override.`
|
|
3841
3821
|
);
|
|
3842
3822
|
}
|
|
3843
3823
|
next.#s.protocols = ["x402"];
|
|
3844
3824
|
} else if (billing === "metered") {
|
|
3845
3825
|
if (resolvedOptions.protocols?.some((p) => p !== "mpp")) {
|
|
3846
|
-
throw new
|
|
3847
|
-
|
|
3826
|
+
throw new RouteDefinitionError(
|
|
3827
|
+
this.#s.key,
|
|
3828
|
+
`.metered() is MPP-only \u2014 remove the conflicting protocols override.`
|
|
3848
3829
|
);
|
|
3849
3830
|
}
|
|
3850
3831
|
next.#s.protocols = ["mpp"];
|
|
@@ -3868,73 +3849,69 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3868
3849
|
if (typeof pricing === "object" && "tiers" in pricing) {
|
|
3869
3850
|
for (const [tierKey, tierConfig] of Object.entries(pricing.tiers)) {
|
|
3870
3851
|
if (!tierKey) {
|
|
3871
|
-
throw new
|
|
3852
|
+
throw new RouteDefinitionError(this.#s.key, `tier key cannot be empty`);
|
|
3872
3853
|
}
|
|
3873
3854
|
if (!isPositiveDecimal(tierConfig.price)) {
|
|
3874
|
-
throw new
|
|
3875
|
-
|
|
3855
|
+
throw new RouteDefinitionError(
|
|
3856
|
+
this.#s.key,
|
|
3857
|
+
`tier '${tierKey}' price '${tierConfig.price}' must be a positive decimal string`
|
|
3876
3858
|
);
|
|
3877
3859
|
}
|
|
3878
3860
|
}
|
|
3879
3861
|
}
|
|
3880
3862
|
if (billing === "exact" && typeof pricing === "string" && !isPositiveDecimal(pricing)) {
|
|
3881
|
-
throw new
|
|
3882
|
-
|
|
3863
|
+
throw new RouteDefinitionError(
|
|
3864
|
+
this.#s.key,
|
|
3865
|
+
`price '${pricing}' must be a positive decimal string`
|
|
3883
3866
|
);
|
|
3884
3867
|
}
|
|
3885
3868
|
if (typeof pricing === "function" && next.#s.maxPrice === void 0) {
|
|
3886
|
-
throw new
|
|
3887
|
-
|
|
3869
|
+
throw new RouteDefinitionError(
|
|
3870
|
+
this.#s.key,
|
|
3871
|
+
`dynamic pricing requires maxPrice \u2014 without it, bare probes would advertise a $0 challenge`
|
|
3888
3872
|
);
|
|
3889
3873
|
}
|
|
3890
3874
|
if (next.#s.maxPrice !== void 0 && !isPositiveDecimal(next.#s.maxPrice)) {
|
|
3891
|
-
throw new
|
|
3892
|
-
|
|
3875
|
+
throw new RouteDefinitionError(
|
|
3876
|
+
this.#s.key,
|
|
3877
|
+
`maxPrice '${next.#s.maxPrice}' must be a positive decimal string`
|
|
3893
3878
|
);
|
|
3894
3879
|
}
|
|
3895
3880
|
if (next.#s.minPrice !== void 0 && !isPositiveDecimal(next.#s.minPrice)) {
|
|
3896
|
-
throw new
|
|
3897
|
-
|
|
3881
|
+
throw new RouteDefinitionError(
|
|
3882
|
+
this.#s.key,
|
|
3883
|
+
`minPrice '${next.#s.minPrice}' must be a positive decimal string`
|
|
3898
3884
|
);
|
|
3899
3885
|
}
|
|
3900
3886
|
if (next.#s.tickCost !== void 0 && !isPositiveDecimal(next.#s.tickCost)) {
|
|
3901
|
-
throw new
|
|
3902
|
-
|
|
3887
|
+
throw new RouteDefinitionError(
|
|
3888
|
+
this.#s.key,
|
|
3889
|
+
`tickCost '${next.#s.tickCost}' must be a positive decimal string`
|
|
3903
3890
|
);
|
|
3904
3891
|
}
|
|
3905
3892
|
return next;
|
|
3906
3893
|
}
|
|
3907
|
-
/**
|
|
3908
|
-
* Require Sign-In-with-X wallet identity on this route — clients prove
|
|
3909
|
-
* control of a wallet via a signed challenge. Composes with `.paid()` and
|
|
3910
|
-
* `.upTo()` for pay-once-then-replay: the first request settles normally,
|
|
3911
|
-
* subsequent requests with a valid SIWX signature for the same wallet skip
|
|
3912
|
-
* payment (on `.upTo()`, `charge(amount)` becomes a no-op on the replay).
|
|
3913
|
-
* Mutually exclusive with `.metered()`.
|
|
3914
|
-
*
|
|
3915
|
-
* @example
|
|
3916
|
-
* ```ts
|
|
3917
|
-
* router.route('profile').siwx().handler(async ({ wallet }) => getProfile(wallet));
|
|
3918
|
-
* router.route('inbox').paid('0.01').siwx().handler(async ({ wallet }) => getInbox(wallet));
|
|
3919
|
-
* ```
|
|
3920
|
-
*/
|
|
3921
3894
|
siwx() {
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3895
|
+
const self = this;
|
|
3896
|
+
if (self.#s.authMode === "unprotected") {
|
|
3897
|
+
throw new RouteDefinitionError(
|
|
3898
|
+
self.#s.key,
|
|
3899
|
+
`Cannot combine .unprotected() and .siwx() on the same route.`
|
|
3925
3900
|
);
|
|
3926
3901
|
}
|
|
3927
|
-
if (
|
|
3928
|
-
throw new
|
|
3929
|
-
|
|
3902
|
+
if (self.#s.apiKeyResolver) {
|
|
3903
|
+
throw new RouteDefinitionError(
|
|
3904
|
+
self.#s.key,
|
|
3905
|
+
`Combining .siwx() and .apiKey() is not supported on the same route.`
|
|
3930
3906
|
);
|
|
3931
3907
|
}
|
|
3932
|
-
if (
|
|
3933
|
-
throw new
|
|
3934
|
-
|
|
3908
|
+
if (self.#s.billing === "metered") {
|
|
3909
|
+
throw new RouteDefinitionError(
|
|
3910
|
+
self.#s.key,
|
|
3911
|
+
`Cannot combine .metered() and .siwx() \u2014 per-tick MPP billing has no entitlement model. Use .paid() or .upTo() with .siwx(), or drop .siwx() for metered routes.`
|
|
3935
3912
|
);
|
|
3936
3913
|
}
|
|
3937
|
-
const next =
|
|
3914
|
+
const next = self.fork();
|
|
3938
3915
|
next.#s.siwxEnabled = true;
|
|
3939
3916
|
if (next.#s.authMode === "paid" || next.#s.pricing) {
|
|
3940
3917
|
next.#s.authMode = "paid";
|
|
@@ -3945,59 +3922,48 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3945
3922
|
next.#s.protocols = [];
|
|
3946
3923
|
return next;
|
|
3947
3924
|
}
|
|
3948
|
-
/**
|
|
3949
|
-
* Require an `X-API-Key` header (or `Authorization: Bearer <key>`); the
|
|
3950
|
-
* resolver returns the account record, or `null` for 401. Composes with
|
|
3951
|
-
* `.paid()` — key is checked first, payment second.
|
|
3952
|
-
*
|
|
3953
|
-
* @example
|
|
3954
|
-
* ```ts
|
|
3955
|
-
* router
|
|
3956
|
-
* .route('admin/users')
|
|
3957
|
-
* .apiKey(async (key) => db.admin.findByKey(key))
|
|
3958
|
-
* .handler(async ({ account }) => db.user.list(account.orgId));
|
|
3959
|
-
* ```
|
|
3960
|
-
*/
|
|
3961
3925
|
apiKey(resolver) {
|
|
3962
|
-
|
|
3963
|
-
|
|
3964
|
-
|
|
3926
|
+
const self = this;
|
|
3927
|
+
if (self.#s.authMode === "unprotected") {
|
|
3928
|
+
throw new RouteDefinitionError(
|
|
3929
|
+
self.#s.key,
|
|
3930
|
+
`Cannot combine .unprotected() and .apiKey() on the same route.`
|
|
3965
3931
|
);
|
|
3966
3932
|
}
|
|
3967
|
-
|
|
3933
|
+
if (self.#s.siwxEnabled) {
|
|
3934
|
+
throw new RouteDefinitionError(
|
|
3935
|
+
self.#s.key,
|
|
3936
|
+
`Combining .apiKey() and .siwx() is not supported on the same route.`
|
|
3937
|
+
);
|
|
3938
|
+
}
|
|
3939
|
+
const next = self.fork();
|
|
3968
3940
|
next.#s.authMode = "apiKey";
|
|
3969
3941
|
next.#s.apiKeyResolver = resolver;
|
|
3970
3942
|
return next;
|
|
3971
3943
|
}
|
|
3972
|
-
/**
|
|
3973
|
-
* Mark the route as public — no auth, no payment, no SIWX. The handler
|
|
3974
|
-
* receives `null` for `wallet`, `payment`, and `account`.
|
|
3975
|
-
*
|
|
3976
|
-
* @example
|
|
3977
|
-
* ```ts
|
|
3978
|
-
* router.route('health').unprotected().handler(async () => ({ status: 'ok' }));
|
|
3979
|
-
* ```
|
|
3980
|
-
*/
|
|
3981
3944
|
unprotected() {
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3945
|
+
const self = this;
|
|
3946
|
+
if (self.#s.authMode && self.#s.authMode !== "unprotected") {
|
|
3947
|
+
throw new RouteDefinitionError(
|
|
3948
|
+
self.#s.key,
|
|
3949
|
+
`Cannot combine .unprotected() and .${self.#s.authMode}() on the same route.`
|
|
3985
3950
|
);
|
|
3986
3951
|
}
|
|
3987
|
-
if (
|
|
3988
|
-
throw new
|
|
3989
|
-
|
|
3952
|
+
if (self.#s.pricing) {
|
|
3953
|
+
throw new RouteDefinitionError(
|
|
3954
|
+
self.#s.key,
|
|
3955
|
+
`Cannot combine .unprotected() and .paid() on the same route.`
|
|
3990
3956
|
);
|
|
3991
3957
|
}
|
|
3992
|
-
const next =
|
|
3958
|
+
const next = self.fork();
|
|
3993
3959
|
next.#s.authMode = "unprotected";
|
|
3994
3960
|
next.#s.protocols = [];
|
|
3995
3961
|
return next;
|
|
3996
3962
|
}
|
|
3997
3963
|
/**
|
|
3998
3964
|
* Tag the route with an upstream provider for discovery and provider-side
|
|
3999
|
-
* monitoring. The provider name and config surface in
|
|
4000
|
-
*
|
|
3965
|
+
* monitoring. The provider name and config surface in OpenAPI discovery
|
|
3966
|
+
* output.
|
|
4001
3967
|
*
|
|
4002
3968
|
* @example
|
|
4003
3969
|
* ```ts
|
|
@@ -4094,8 +4060,8 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
4094
4060
|
return next;
|
|
4095
4061
|
}
|
|
4096
4062
|
/**
|
|
4097
|
-
* Set a human-readable summary of the route. Surfaces in OpenAPI
|
|
4098
|
-
* `
|
|
4063
|
+
* Set a human-readable summary of the route. Surfaces in OpenAPI and
|
|
4064
|
+
* `llms.txt` discovery output.
|
|
4099
4065
|
*
|
|
4100
4066
|
* @example
|
|
4101
4067
|
* ```ts
|
|
@@ -4231,38 +4197,46 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
4231
4197
|
}
|
|
4232
4198
|
register(handlerFn, streaming) {
|
|
4233
4199
|
if (!this.#s.authMode) {
|
|
4234
|
-
throw new
|
|
4235
|
-
|
|
4200
|
+
throw new RouteDefinitionError(
|
|
4201
|
+
this.#s.key,
|
|
4202
|
+
`Select an auth mode: .paid(pricing), .upTo(maxPrice), .metered(options), .siwx(), .apiKey(resolver), or .unprotected()`
|
|
4236
4203
|
);
|
|
4237
4204
|
}
|
|
4238
4205
|
if (this.#s.validateFn && !this.#s.bodySchema) {
|
|
4239
|
-
throw new
|
|
4240
|
-
|
|
4206
|
+
throw new RouteDefinitionError(
|
|
4207
|
+
this.#s.key,
|
|
4208
|
+
`.validate() requires .body() \u2014 validation runs on parsed body`
|
|
4241
4209
|
);
|
|
4242
4210
|
}
|
|
4243
4211
|
if (this.#s.settlement && !this.#s.pricing) {
|
|
4244
|
-
throw new
|
|
4212
|
+
throw new RouteDefinitionError(this.#s.key, `.settlement() requires a paid route`);
|
|
4245
4213
|
}
|
|
4246
4214
|
if (this.#s.mppInfo?.settleBeforeHandler) {
|
|
4247
4215
|
if (!this.#s.pricing) {
|
|
4248
|
-
throw new
|
|
4216
|
+
throw new RouteDefinitionError(
|
|
4217
|
+
this.#s.key,
|
|
4218
|
+
`mpp.settleBeforeHandler requires a paid route`
|
|
4219
|
+
);
|
|
4249
4220
|
}
|
|
4250
4221
|
if (this.#s.billing !== "exact") {
|
|
4251
|
-
throw new
|
|
4252
|
-
|
|
4222
|
+
throw new RouteDefinitionError(
|
|
4223
|
+
this.#s.key,
|
|
4224
|
+
`mpp.settleBeforeHandler is only supported on .paid() routes`
|
|
4253
4225
|
);
|
|
4254
4226
|
}
|
|
4255
4227
|
if (this.#s.settlement?.beforeSettle) {
|
|
4256
|
-
throw new
|
|
4257
|
-
|
|
4228
|
+
throw new RouteDefinitionError(
|
|
4229
|
+
this.#s.key,
|
|
4230
|
+
`mpp.settleBeforeHandler is incompatible with .settlement({ beforeSettle }) \u2014 MPP payment is already broadcast before the handler runs`
|
|
4258
4231
|
);
|
|
4259
4232
|
}
|
|
4260
4233
|
}
|
|
4261
4234
|
if (this.#s.billing === "upto") {
|
|
4262
4235
|
const hasUpto = this.#s.deps.x402Accepts.some((accept) => accept.scheme === "upto");
|
|
4263
4236
|
if (!hasUpto) {
|
|
4264
|
-
throw new
|
|
4265
|
-
|
|
4237
|
+
throw new RouteDefinitionError(
|
|
4238
|
+
this.#s.key,
|
|
4239
|
+
`.upTo() requires an 'upto' accept on at least one configured network. Add { scheme: 'upto', network, asset } to RouterConfig.x402.accepts.`
|
|
4266
4240
|
);
|
|
4267
4241
|
}
|
|
4268
4242
|
}
|
|
@@ -4271,26 +4245,30 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
4271
4245
|
(accept) => (accept.scheme ?? "exact") !== "upto"
|
|
4272
4246
|
);
|
|
4273
4247
|
if (!hasExact) {
|
|
4274
|
-
throw new
|
|
4275
|
-
|
|
4248
|
+
throw new RouteDefinitionError(
|
|
4249
|
+
this.#s.key,
|
|
4250
|
+
`.paid() needs a non-'upto' x402 accept \u2014 an 'upto'-only accept list cannot serve a fixed-price route. Add { scheme: 'exact', network } to RouterConfig.x402.accepts, or use .upTo() for handler-computed billing.`
|
|
4276
4251
|
);
|
|
4277
4252
|
}
|
|
4278
4253
|
}
|
|
4279
4254
|
if (this.#s.billing === "metered") {
|
|
4280
4255
|
if (!this.#s.deps.mppSessionConfig) {
|
|
4281
|
-
throw new
|
|
4282
|
-
|
|
4256
|
+
throw new RouteDefinitionError(
|
|
4257
|
+
this.#s.key,
|
|
4258
|
+
`.metered() requires MPP session mode. Set RouterConfig.mpp.session = {} and provide mpp.operatorKey.`
|
|
4283
4259
|
);
|
|
4284
4260
|
}
|
|
4285
4261
|
}
|
|
4286
4262
|
if (streaming && this.#s.billing !== "metered") {
|
|
4287
|
-
throw new
|
|
4288
|
-
|
|
4263
|
+
throw new RouteDefinitionError(
|
|
4264
|
+
this.#s.key,
|
|
4265
|
+
`.stream() requires .metered() \u2014 static/free/upto routes can't meter per-chunk billing.`
|
|
4289
4266
|
);
|
|
4290
4267
|
}
|
|
4291
4268
|
if (this.#s.description !== void 0 && this.#s.description.length > MAX_X402_DESCRIPTION_LENGTH && this.#s.pricing !== void 0 && this.#s.protocols.includes("x402")) {
|
|
4292
|
-
throw new
|
|
4293
|
-
|
|
4269
|
+
throw new RouteDefinitionError(
|
|
4270
|
+
this.#s.key,
|
|
4271
|
+
`.description() is ${this.#s.description.length} chars; must be \u2264 ${MAX_X402_DESCRIPTION_LENGTH} chars \u2014 the CDP x402 facilitator rejects payments whose 402 challenge resource.description exceeds ~500 chars.`
|
|
4294
4272
|
);
|
|
4295
4273
|
}
|
|
4296
4274
|
validateExamples(
|
|
@@ -4358,14 +4336,15 @@ function normalizePaidArg(routeKey, arg, options) {
|
|
|
4358
4336
|
if ("price" in arg && typeof arg.price === "string") {
|
|
4359
4337
|
return { pricing: arg.price, resolvedOptions: arg, billing: "exact" };
|
|
4360
4338
|
}
|
|
4361
|
-
throw new
|
|
4362
|
-
|
|
4339
|
+
throw new RouteDefinitionError(
|
|
4340
|
+
routeKey,
|
|
4341
|
+
`.paid() requires one of: a price string, a (body) => string function, { price }, or { field, tiers }. For handler-computed billing use .upTo(); for per-tick billing use .metered().`
|
|
4363
4342
|
);
|
|
4364
4343
|
}
|
|
4365
4344
|
function normalizeUpToArg(routeKey, arg) {
|
|
4366
4345
|
const options = typeof arg === "string" ? { maxPrice: arg } : arg;
|
|
4367
4346
|
if (!options.maxPrice) {
|
|
4368
|
-
throw new
|
|
4347
|
+
throw new RouteDefinitionError(routeKey, `.upTo() requires maxPrice`);
|
|
4369
4348
|
}
|
|
4370
4349
|
return {
|
|
4371
4350
|
pricing: options.maxPrice,
|
|
@@ -4377,10 +4356,10 @@ function normalizeUpToArg(routeKey, arg) {
|
|
|
4377
4356
|
}
|
|
4378
4357
|
function normalizeMeteredArg(routeKey, options) {
|
|
4379
4358
|
if (!options.maxPrice) {
|
|
4380
|
-
throw new
|
|
4359
|
+
throw new RouteDefinitionError(routeKey, `.metered() requires maxPrice`);
|
|
4381
4360
|
}
|
|
4382
4361
|
if (!options.tickCost) {
|
|
4383
|
-
throw new
|
|
4362
|
+
throw new RouteDefinitionError(routeKey, `.metered() requires tickCost`);
|
|
4384
4363
|
}
|
|
4385
4364
|
return {
|
|
4386
4365
|
pricing: options.maxPrice,
|
|
@@ -4687,9 +4666,9 @@ function createNotFoundHandler(baseUrl) {
|
|
|
4687
4666
|
code: "route_not_found",
|
|
4688
4667
|
error: "Route not found. Rediscover this origin and retry with the current discovery document.",
|
|
4689
4668
|
requestedUrl: request.url,
|
|
4669
|
+
// The deprecated /.well-known/x402 surface is intentionally not advertised.
|
|
4690
4670
|
discovery: {
|
|
4691
4671
|
openapi: `${normalizedBase}/openapi.json`,
|
|
4692
|
-
wellKnown: `${normalizedBase}/.well-known/x402`,
|
|
4693
4672
|
llmsTxt: `${normalizedBase}/llms.txt`
|
|
4694
4673
|
}
|
|
4695
4674
|
},
|
|
@@ -4723,6 +4702,7 @@ function formatRouterConfigIssues(issues) {
|
|
|
4723
4702
|
|
|
4724
4703
|
// src/config/schema.ts
|
|
4725
4704
|
var import_zod = require("zod");
|
|
4705
|
+
init_accepts();
|
|
4726
4706
|
init_constants();
|
|
4727
4707
|
|
|
4728
4708
|
// src/config/utils.ts
|
|
@@ -4911,18 +4891,8 @@ function deriveBaseUrlEnv(env) {
|
|
|
4911
4891
|
BASE_URL: vercelBaseUrl
|
|
4912
4892
|
};
|
|
4913
4893
|
}
|
|
4914
|
-
function getConfiguredX402Accepts2(config) {
|
|
4915
|
-
if (config.x402?.accepts?.length) return [...config.x402.accepts];
|
|
4916
|
-
return [
|
|
4917
|
-
{
|
|
4918
|
-
scheme: "exact",
|
|
4919
|
-
network: config.network ?? BASE_MAINNET_NETWORK,
|
|
4920
|
-
payTo: config.payeeAddress
|
|
4921
|
-
}
|
|
4922
|
-
];
|
|
4923
|
-
}
|
|
4924
4894
|
function validateX402Config(config, env) {
|
|
4925
|
-
const accepts =
|
|
4895
|
+
const accepts = getConfiguredX402Accepts(config);
|
|
4926
4896
|
const issues = [];
|
|
4927
4897
|
const push = (code, message) => issues.push({ code, protocol: "x402", message });
|
|
4928
4898
|
if (accepts.length === 0) {
|
|
@@ -5223,7 +5193,8 @@ function getMppxRequestContext(args) {
|
|
|
5223
5193
|
recipient: mppConfig.recipient ?? payeeAddress,
|
|
5224
5194
|
getClient,
|
|
5225
5195
|
...feePayerAccount ? { feePayer: feePayerAccount } : {},
|
|
5226
|
-
...resolvedStore ? { store: resolvedStore } : {}
|
|
5196
|
+
...resolvedStore ? { store: resolvedStore } : {},
|
|
5197
|
+
...mppConfig.feePayerPolicy ? { feePayerPolicy: mppConfig.feePayerPolicy } : {}
|
|
5227
5198
|
}),
|
|
5228
5199
|
...sessionEnabled ? [
|
|
5229
5200
|
tempo.session({
|
|
@@ -5261,7 +5232,7 @@ async function initMpp(config, resolvedBaseUrl, kvStore, configError) {
|
|
|
5261
5232
|
try {
|
|
5262
5233
|
const { Mppx, tempo } = await import("mppx/server");
|
|
5263
5234
|
const { createClient, http } = await import("viem");
|
|
5264
|
-
const { tempo: tempoChain } = await import("viem/chains");
|
|
5235
|
+
const { tempo: tempoChain } = await import("viem/tempo/chains");
|
|
5265
5236
|
const { privateKeyToAccount: privateKeyToAccount2 } = await import("viem/accounts");
|
|
5266
5237
|
const rpcUrl = config.mpp.rpcUrl ?? process.env.TEMPO_RPC_URL ?? DEFAULT_TEMPO_RPC_URL;
|
|
5267
5238
|
const tempoClient = createClient({ chain: tempoChain, transport: http(rpcUrl) });
|
|
@@ -5279,7 +5250,9 @@ async function initMpp(config, resolvedBaseUrl, kvStore, configError) {
|
|
|
5279
5250
|
getClient,
|
|
5280
5251
|
...operatorAccount ? { account: operatorAccount } : {},
|
|
5281
5252
|
...feePayerAccount ? { feePayer: feePayerAccount } : {},
|
|
5282
|
-
...resolvedStore ? { store: resolvedStore } : {}
|
|
5253
|
+
...resolvedStore ? { store: resolvedStore } : {},
|
|
5254
|
+
...mppConfig.feePayerPolicy ? { feePayerPolicy: mppConfig.feePayerPolicy } : {},
|
|
5255
|
+
...mppConfig.session?.settlementSchedule ? { settlementSchedule: mppConfig.session.settlementSchedule } : {}
|
|
5283
5256
|
};
|
|
5284
5257
|
const mppxArgs = {
|
|
5285
5258
|
Mppx,
|
|
@@ -5295,6 +5268,7 @@ async function initMpp(config, resolvedBaseUrl, kvStore, configError) {
|
|
|
5295
5268
|
};
|
|
5296
5269
|
const primary = getMppxRequestContext(mppxArgs);
|
|
5297
5270
|
const streaming = getMppxStreamingContext(mppxArgs);
|
|
5271
|
+
subscribePaymentFailedAlerts(config.plugin, [primary, streaming]);
|
|
5298
5272
|
const mppx = {
|
|
5299
5273
|
charge: primary.charge,
|
|
5300
5274
|
...primary.session ? { sessionRequest: primary.session } : {},
|
|
@@ -5305,6 +5279,41 @@ async function initMpp(config, resolvedBaseUrl, kvStore, configError) {
|
|
|
5305
5279
|
return { initError: err instanceof Error ? err.message : String(err) };
|
|
5306
5280
|
}
|
|
5307
5281
|
}
|
|
5282
|
+
function subscribePaymentFailedAlerts(plugin, instances) {
|
|
5283
|
+
if (!plugin?.onAlert) return;
|
|
5284
|
+
const ctx = {
|
|
5285
|
+
requestId: "mppx",
|
|
5286
|
+
route: "mpp",
|
|
5287
|
+
walletAddress: null,
|
|
5288
|
+
clientId: null,
|
|
5289
|
+
sessionId: null,
|
|
5290
|
+
verifiedWallet: null,
|
|
5291
|
+
setVerifiedWallet() {
|
|
5292
|
+
}
|
|
5293
|
+
};
|
|
5294
|
+
for (const instance of instances) {
|
|
5295
|
+
const events = instance;
|
|
5296
|
+
if (typeof events?.onPaymentFailed !== "function") continue;
|
|
5297
|
+
events.onPaymentFailed((payload) => {
|
|
5298
|
+
try {
|
|
5299
|
+
const error = payload?.error ?? {};
|
|
5300
|
+
firePluginHook(plugin, "onAlert", ctx, {
|
|
5301
|
+
level: (error.status ?? 402) >= 500 ? "error" : "warn",
|
|
5302
|
+
message: `MPP payment failed: ${error.message ?? error.name ?? "unknown error"}`,
|
|
5303
|
+
route: "mpp",
|
|
5304
|
+
meta: {
|
|
5305
|
+
...payload?.method ? { method: `${payload.method.name}/${payload.method.intent}` } : {},
|
|
5306
|
+
...error.type ? { errorType: error.type } : {},
|
|
5307
|
+
...error.status !== void 0 ? { status: error.status } : {},
|
|
5308
|
+
...error.hint ? { hint: error.hint } : {},
|
|
5309
|
+
...payload?.credential?.source ? { payer: payload.credential.source } : {}
|
|
5310
|
+
}
|
|
5311
|
+
});
|
|
5312
|
+
} catch {
|
|
5313
|
+
}
|
|
5314
|
+
});
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5308
5317
|
|
|
5309
5318
|
// src/index.ts
|
|
5310
5319
|
init_constants();
|
|
@@ -5448,6 +5457,7 @@ function createRouterFromEnv(options) {
|
|
|
5448
5457
|
DEFAULT_SOLANA_FACILITATOR_URL,
|
|
5449
5458
|
DEFAULT_TEMPO_RPC_URL,
|
|
5450
5459
|
HttpError,
|
|
5460
|
+
RouteDefinitionError,
|
|
5451
5461
|
RouterConfigError,
|
|
5452
5462
|
SOLANA_MAINNET_NETWORK,
|
|
5453
5463
|
TEMPO_USDC_ADDRESS,
|