@agentcash/router 1.12.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 +91 -34
- package/dist/index.d.ts +91 -34
- package/dist/index.js +268 -259
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -835,6 +835,13 @@ var HttpError = class extends Error {
|
|
|
835
835
|
this.name = "HttpError";
|
|
836
836
|
}
|
|
837
837
|
};
|
|
838
|
+
var RouteDefinitionError = class extends Error {
|
|
839
|
+
constructor(route, detail) {
|
|
840
|
+
super(`route '${route}': ${detail}`);
|
|
841
|
+
this.route = route;
|
|
842
|
+
this.name = "RouteDefinitionError";
|
|
843
|
+
}
|
|
844
|
+
};
|
|
838
845
|
|
|
839
846
|
// src/auth/agent-identity.ts
|
|
840
847
|
var PROTOCOL_VERSION = 1;
|
|
@@ -1362,6 +1369,23 @@ function multiplyDecimal(decimal, factor) {
|
|
|
1362
1369
|
return fracPart ? `${intPart}.${fracPart}` : intPart;
|
|
1363
1370
|
}
|
|
1364
1371
|
|
|
1372
|
+
// src/protocols/detect.ts
|
|
1373
|
+
function hasX402Payment(request) {
|
|
1374
|
+
return Boolean(
|
|
1375
|
+
request.headers.get(HEADERS.X402_PAYMENT_SIGNATURE) ?? request.headers.get(HEADERS.X402_PAYMENT_LEGACY)
|
|
1376
|
+
);
|
|
1377
|
+
}
|
|
1378
|
+
function hasMppPayment(request) {
|
|
1379
|
+
const auth = request.headers.get(HEADERS.AUTHORIZATION);
|
|
1380
|
+
return Boolean(auth && auth.startsWith(AUTH_SCHEME.MPP_PAYMENT));
|
|
1381
|
+
}
|
|
1382
|
+
function detectProtocol(request) {
|
|
1383
|
+
if (hasX402Payment(request)) return "x402";
|
|
1384
|
+
if (hasMppPayment(request)) return "mpp";
|
|
1385
|
+
if (request.headers.get(HEADERS.SIWX)) return "siwx";
|
|
1386
|
+
return null;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1365
1389
|
// src/protocols/mpp/credential.ts
|
|
1366
1390
|
import { Credential } from "mppx";
|
|
1367
1391
|
import { getAddress, isAddress } from "viem";
|
|
@@ -1728,10 +1752,7 @@ function settleHashMode(args) {
|
|
|
1728
1752
|
// src/protocols/mpp/strategy.ts
|
|
1729
1753
|
var mppStrategy = {
|
|
1730
1754
|
protocol: "mpp",
|
|
1731
|
-
detects
|
|
1732
|
-
const auth = request.headers.get(HEADERS.AUTHORIZATION);
|
|
1733
|
-
return Boolean(auth && auth.startsWith(AUTH_SCHEME.MPP_PAYMENT));
|
|
1734
|
-
},
|
|
1755
|
+
detects: hasMppPayment,
|
|
1735
1756
|
preflight(request, _routeEntry) {
|
|
1736
1757
|
const info = readMppCredential(request);
|
|
1737
1758
|
if (!info?.sessionAction) return null;
|
|
@@ -2166,11 +2187,7 @@ function formatVerifyFailureMessage(failure) {
|
|
|
2166
2187
|
}
|
|
2167
2188
|
var x402Strategy = {
|
|
2168
2189
|
protocol: "x402",
|
|
2169
|
-
detects
|
|
2170
|
-
return Boolean(
|
|
2171
|
-
request.headers.get(HEADERS.X402_PAYMENT_SIGNATURE) ?? request.headers.get(HEADERS.X402_PAYMENT_LEGACY)
|
|
2172
|
-
);
|
|
2173
|
-
},
|
|
2190
|
+
detects: hasX402Payment,
|
|
2174
2191
|
verify: (args) => verifyX402(args),
|
|
2175
2192
|
settle: (args) => settleX402(args),
|
|
2176
2193
|
buildChallenge: (args) => buildX402ChallengeContribution(args)
|
|
@@ -2317,21 +2334,6 @@ function getAllowedStrategies(allowed) {
|
|
|
2317
2334
|
return allowed.map((name) => STRATEGIES[name]);
|
|
2318
2335
|
}
|
|
2319
2336
|
|
|
2320
|
-
// src/protocols/detect.ts
|
|
2321
|
-
function detectProtocol(request) {
|
|
2322
|
-
if (request.headers.get(HEADERS.X402_PAYMENT_SIGNATURE) ?? request.headers.get(HEADERS.X402_PAYMENT_LEGACY)) {
|
|
2323
|
-
return "x402";
|
|
2324
|
-
}
|
|
2325
|
-
const auth = request.headers.get(HEADERS.AUTHORIZATION);
|
|
2326
|
-
if (auth && auth.startsWith(AUTH_SCHEME.MPP_PAYMENT)) {
|
|
2327
|
-
return "mpp";
|
|
2328
|
-
}
|
|
2329
|
-
if (request.headers.get(HEADERS.SIWX)) {
|
|
2330
|
-
return "siwx";
|
|
2331
|
-
}
|
|
2332
|
-
return null;
|
|
2333
|
-
}
|
|
2334
|
-
|
|
2335
2337
|
// src/pipeline/flows/api-key-only.ts
|
|
2336
2338
|
async function runApiKeyOnlyFlow(ctx) {
|
|
2337
2339
|
if (!ctx.routeEntry.apiKeyResolver) {
|
|
@@ -2654,6 +2656,61 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
|
|
|
2654
2656
|
return response;
|
|
2655
2657
|
}
|
|
2656
2658
|
|
|
2659
|
+
// src/pipeline/flows/paid-preamble.ts
|
|
2660
|
+
async function runPaidPreamble(ctx) {
|
|
2661
|
+
const { request, routeEntry, deps, report } = ctx;
|
|
2662
|
+
const apiKeyGate = await runApiKeyGate(ctx);
|
|
2663
|
+
if (!apiKeyGate.ok) return { done: true, response: apiKeyGate.response };
|
|
2664
|
+
const { account } = apiKeyGate;
|
|
2665
|
+
const pricing = selectPricing(routeEntry.pricing, {
|
|
2666
|
+
alert: report,
|
|
2667
|
+
maxPrice: routeEntry.maxPrice,
|
|
2668
|
+
minPrice: routeEntry.minPrice,
|
|
2669
|
+
route: routeEntry.key
|
|
2670
|
+
});
|
|
2671
|
+
const incomingStrategy = selectIncomingStrategy(request, routeEntry.protocols);
|
|
2672
|
+
const earlyResolution = await resolveEarlyBody({ ctx, pricing, incomingStrategy });
|
|
2673
|
+
if (!earlyResolution.ok) return { done: true, response: earlyResolution.response };
|
|
2674
|
+
const { earlyBody } = earlyResolution;
|
|
2675
|
+
const siwxFastPath = await trySiwxFastPath(ctx, account);
|
|
2676
|
+
if (siwxFastPath) return { done: true, response: siwxFastPath };
|
|
2677
|
+
if (!incomingStrategy) {
|
|
2678
|
+
const initError = protocolInitError(routeEntry, deps);
|
|
2679
|
+
if (initError) return { done: true, response: fail(ctx, 500, initError) };
|
|
2680
|
+
return { done: true, response: await buildChallengeResponse(ctx, pricing, earlyBody) };
|
|
2681
|
+
}
|
|
2682
|
+
return { done: false, account, pricing, incomingStrategy, earlyBody };
|
|
2683
|
+
}
|
|
2684
|
+
async function runPaidVerify(args) {
|
|
2685
|
+
const { ctx, strategy, pricing, parsedBody, price } = args;
|
|
2686
|
+
const { request, routeEntry, deps, report } = ctx;
|
|
2687
|
+
const verifyOutcome = await strategy.verify({
|
|
2688
|
+
request,
|
|
2689
|
+
body: parsedBody,
|
|
2690
|
+
price,
|
|
2691
|
+
routeEntry,
|
|
2692
|
+
deps,
|
|
2693
|
+
report
|
|
2694
|
+
});
|
|
2695
|
+
if (verifyOutcome.ok === false) {
|
|
2696
|
+
if (verifyOutcome.kind === "config") {
|
|
2697
|
+
return { ok: false, response: fail(ctx, 500, verifyOutcome.message, parsedBody) };
|
|
2698
|
+
}
|
|
2699
|
+
return {
|
|
2700
|
+
ok: false,
|
|
2701
|
+
response: await buildChallengeResponse(ctx, pricing, parsedBody, verifyOutcome.failure)
|
|
2702
|
+
};
|
|
2703
|
+
}
|
|
2704
|
+
ctx.pluginCtx.setVerifiedWallet(verifyOutcome.wallet);
|
|
2705
|
+
firePaymentVerified(ctx, {
|
|
2706
|
+
protocol: strategy.protocol,
|
|
2707
|
+
payer: verifyOutcome.wallet,
|
|
2708
|
+
amount: price,
|
|
2709
|
+
network: verifyOutcome.payment.network
|
|
2710
|
+
});
|
|
2711
|
+
return { ok: true, verifyOutcome };
|
|
2712
|
+
}
|
|
2713
|
+
|
|
2657
2714
|
// src/pipeline/flows/dynamic/dynamic-body-and-price.ts
|
|
2658
2715
|
async function resolveDynamicBodyAndPrice(args) {
|
|
2659
2716
|
const { ctx, pricing, skipBody } = args;
|
|
@@ -3020,27 +3077,10 @@ async function runDynamicStreamFlow(args) {
|
|
|
3020
3077
|
|
|
3021
3078
|
// src/pipeline/flows/dynamic/dynamic-paid.ts
|
|
3022
3079
|
async function runDynamicPaidFlow(ctx) {
|
|
3023
|
-
const { request, routeEntry
|
|
3024
|
-
const
|
|
3025
|
-
if (
|
|
3026
|
-
const { account } =
|
|
3027
|
-
const pricing = selectPricing(routeEntry.pricing, {
|
|
3028
|
-
alert: report,
|
|
3029
|
-
maxPrice: routeEntry.maxPrice,
|
|
3030
|
-
minPrice: routeEntry.minPrice,
|
|
3031
|
-
route: routeEntry.key
|
|
3032
|
-
});
|
|
3033
|
-
const incomingStrategy = selectIncomingStrategy(request, routeEntry.protocols);
|
|
3034
|
-
const earlyResolution = await resolveEarlyBody({ ctx, pricing, incomingStrategy });
|
|
3035
|
-
if (!earlyResolution.ok) return earlyResolution.response;
|
|
3036
|
-
const { earlyBody } = earlyResolution;
|
|
3037
|
-
const siwxFastPath = await trySiwxFastPath(ctx, account);
|
|
3038
|
-
if (siwxFastPath) return siwxFastPath;
|
|
3039
|
-
if (!incomingStrategy) {
|
|
3040
|
-
const initError = protocolInitError(routeEntry, deps);
|
|
3041
|
-
if (initError) return fail(ctx, 500, initError);
|
|
3042
|
-
return buildChallengeResponse(ctx, pricing, earlyBody);
|
|
3043
|
-
}
|
|
3080
|
+
const { request, routeEntry } = ctx;
|
|
3081
|
+
const preamble = await runPaidPreamble(ctx);
|
|
3082
|
+
if (preamble.done) return preamble.response;
|
|
3083
|
+
const { account, pricing, incomingStrategy } = preamble;
|
|
3044
3084
|
const { skipBody, skipHandler } = resolveDynamicPreflight(incomingStrategy, request, routeEntry);
|
|
3045
3085
|
if (skipHandler) {
|
|
3046
3086
|
return runDynamicChannelMgmtFlow({
|
|
@@ -3054,27 +3094,15 @@ async function runDynamicPaidFlow(ctx) {
|
|
|
3054
3094
|
const bodyAndPrice = await resolveDynamicBodyAndPrice({ ctx, pricing, skipBody });
|
|
3055
3095
|
if (!bodyAndPrice.ok) return bodyAndPrice.response;
|
|
3056
3096
|
const { parsedBody, price } = bodyAndPrice;
|
|
3057
|
-
const
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
report
|
|
3064
|
-
});
|
|
3065
|
-
if (verifyOutcome.ok === false) {
|
|
3066
|
-
if (verifyOutcome.kind === "config") {
|
|
3067
|
-
return fail(ctx, 500, verifyOutcome.message, parsedBody);
|
|
3068
|
-
}
|
|
3069
|
-
return buildChallengeResponse(ctx, pricing, parsedBody, verifyOutcome.failure);
|
|
3070
|
-
}
|
|
3071
|
-
ctx.pluginCtx.setVerifiedWallet(verifyOutcome.wallet);
|
|
3072
|
-
firePaymentVerified(ctx, {
|
|
3073
|
-
protocol: incomingStrategy.protocol,
|
|
3074
|
-
payer: verifyOutcome.wallet,
|
|
3075
|
-
amount: price,
|
|
3076
|
-
network: verifyOutcome.payment.network
|
|
3097
|
+
const verify = await runPaidVerify({
|
|
3098
|
+
ctx,
|
|
3099
|
+
strategy: incomingStrategy,
|
|
3100
|
+
pricing,
|
|
3101
|
+
parsedBody,
|
|
3102
|
+
price
|
|
3077
3103
|
});
|
|
3104
|
+
if (!verify.ok) return verify.response;
|
|
3105
|
+
const { verifyOutcome } = verify;
|
|
3078
3106
|
const result = await invokeDynamic(ctx, verifyOutcome, account, parsedBody);
|
|
3079
3107
|
switch (result.kind) {
|
|
3080
3108
|
case "stream":
|
|
@@ -3206,51 +3234,21 @@ function failureFromCause2(cause) {
|
|
|
3206
3234
|
|
|
3207
3235
|
// src/pipeline/flows/static/static-paid.ts
|
|
3208
3236
|
async function runStaticPaidFlow(ctx) {
|
|
3209
|
-
const
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
const { account } = apiKeyGate;
|
|
3213
|
-
const pricing = selectPricing(routeEntry.pricing, {
|
|
3214
|
-
alert: report,
|
|
3215
|
-
maxPrice: routeEntry.maxPrice,
|
|
3216
|
-
minPrice: routeEntry.minPrice,
|
|
3217
|
-
route: routeEntry.key
|
|
3218
|
-
});
|
|
3219
|
-
const incomingStrategy = selectIncomingStrategy(request, routeEntry.protocols);
|
|
3220
|
-
const earlyResolution = await resolveEarlyBody({ ctx, pricing, incomingStrategy });
|
|
3221
|
-
if (!earlyResolution.ok) return earlyResolution.response;
|
|
3222
|
-
const { earlyBody } = earlyResolution;
|
|
3223
|
-
const siwxFastPath = await trySiwxFastPath(ctx, account);
|
|
3224
|
-
if (siwxFastPath) return siwxFastPath;
|
|
3225
|
-
if (!incomingStrategy) {
|
|
3226
|
-
const initError = protocolInitError(routeEntry, deps);
|
|
3227
|
-
if (initError) return fail(ctx, 500, initError);
|
|
3228
|
-
return buildChallengeResponse(ctx, pricing, earlyBody);
|
|
3229
|
-
}
|
|
3237
|
+
const preamble = await runPaidPreamble(ctx);
|
|
3238
|
+
if (preamble.done) return preamble.response;
|
|
3239
|
+
const { account, pricing, incomingStrategy } = preamble;
|
|
3230
3240
|
const bodyAndPrice = await resolveStaticBodyAndPrice({ ctx, pricing });
|
|
3231
3241
|
if (!bodyAndPrice.ok) return bodyAndPrice.response;
|
|
3232
3242
|
const { parsedBody, price } = bodyAndPrice;
|
|
3233
|
-
const
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
report
|
|
3240
|
-
});
|
|
3241
|
-
if (verifyOutcome.ok === false) {
|
|
3242
|
-
if (verifyOutcome.kind === "config") {
|
|
3243
|
-
return fail(ctx, 500, verifyOutcome.message, parsedBody);
|
|
3244
|
-
}
|
|
3245
|
-
return buildChallengeResponse(ctx, pricing, parsedBody, verifyOutcome.failure);
|
|
3246
|
-
}
|
|
3247
|
-
ctx.pluginCtx.setVerifiedWallet(verifyOutcome.wallet);
|
|
3248
|
-
firePaymentVerified(ctx, {
|
|
3249
|
-
protocol: incomingStrategy.protocol,
|
|
3250
|
-
payer: verifyOutcome.wallet,
|
|
3251
|
-
amount: price,
|
|
3252
|
-
network: verifyOutcome.payment.network
|
|
3243
|
+
const verify = await runPaidVerify({
|
|
3244
|
+
ctx,
|
|
3245
|
+
strategy: incomingStrategy,
|
|
3246
|
+
pricing,
|
|
3247
|
+
parsedBody,
|
|
3248
|
+
price
|
|
3253
3249
|
});
|
|
3250
|
+
if (!verify.ok) return verify.response;
|
|
3251
|
+
const { verifyOutcome } = verify;
|
|
3254
3252
|
const result = await invokePaidStatic(
|
|
3255
3253
|
ctx,
|
|
3256
3254
|
verifyOutcome.wallet,
|
|
@@ -3742,55 +3740,35 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3742
3740
|
return next;
|
|
3743
3741
|
}
|
|
3744
3742
|
paid(arg, options) {
|
|
3745
|
-
|
|
3743
|
+
const self = this;
|
|
3744
|
+
return self.applyPaid(normalizePaidArg(self.#s.key, arg, options), "paid");
|
|
3746
3745
|
}
|
|
3747
|
-
/**
|
|
3748
|
-
* x402-only handler-computed billing. The handler receives `charge(amount)`
|
|
3749
|
-
* and the request settles once for the accumulated total, capped at
|
|
3750
|
-
* `maxPrice`. Requires an `'upto'` accept on at least one configured network.
|
|
3751
|
-
* Pass a bare string as sugar for `{ maxPrice }`.
|
|
3752
|
-
*
|
|
3753
|
-
* @example
|
|
3754
|
-
* ```ts
|
|
3755
|
-
* router.route('llm')
|
|
3756
|
-
* .upTo('0.05')
|
|
3757
|
-
* .body(schema)
|
|
3758
|
-
* .handler(async ({ body, charge }) => { await charge('0.001'); ... });
|
|
3759
|
-
* ```
|
|
3760
|
-
*/
|
|
3761
3746
|
upTo(arg) {
|
|
3762
|
-
|
|
3747
|
+
const self = this;
|
|
3748
|
+
return self.applyPaid(normalizeUpToArg(self.#s.key, arg), "upTo");
|
|
3763
3749
|
}
|
|
3764
|
-
/**
|
|
3765
|
-
* MPP-only per-tick billing. `.handler()` bills exactly `tickCost`;
|
|
3766
|
-
* `.stream()` calls `charge()` (no-arg) per yield, settling per tick up to
|
|
3767
|
-
* `maxPrice`. Requires `RouterConfig.mpp.session`.
|
|
3768
|
-
*
|
|
3769
|
-
* @example
|
|
3770
|
-
* ```ts
|
|
3771
|
-
* router.route('llm/stream')
|
|
3772
|
-
* .metered({ tickCost: '0.0001', maxPrice: '0.05', unitType: 'token' })
|
|
3773
|
-
* .stream(async function* ({ charge }) { await charge(); yield 'hi'; });
|
|
3774
|
-
* ```
|
|
3775
|
-
*/
|
|
3776
3750
|
metered(options) {
|
|
3777
|
-
|
|
3751
|
+
const self = this;
|
|
3752
|
+
return self.applyPaid(normalizeMeteredArg(self.#s.key, options), "metered");
|
|
3778
3753
|
}
|
|
3779
3754
|
applyPaid(normalized, method) {
|
|
3780
3755
|
const { pricing, resolvedOptions, billing, tickCost, unitType, maxPrice } = normalized;
|
|
3781
3756
|
if (this.#s.authMode === "unprotected") {
|
|
3782
|
-
throw new
|
|
3783
|
-
|
|
3757
|
+
throw new RouteDefinitionError(
|
|
3758
|
+
this.#s.key,
|
|
3759
|
+
`Cannot combine .unprotected() and .${method}() on the same route.`
|
|
3784
3760
|
);
|
|
3785
3761
|
}
|
|
3786
3762
|
if (this.#s.pricing !== void 0) {
|
|
3787
|
-
throw new
|
|
3788
|
-
|
|
3763
|
+
throw new RouteDefinitionError(
|
|
3764
|
+
this.#s.key,
|
|
3765
|
+
`Cannot combine .paid(), .upTo(), and .metered() \u2014 pick one pricing mode.`
|
|
3789
3766
|
);
|
|
3790
3767
|
}
|
|
3791
3768
|
if (this.#s.siwxEnabled && billing === "metered") {
|
|
3792
|
-
throw new
|
|
3793
|
-
|
|
3769
|
+
throw new RouteDefinitionError(
|
|
3770
|
+
this.#s.key,
|
|
3771
|
+
`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.`
|
|
3794
3772
|
);
|
|
3795
3773
|
}
|
|
3796
3774
|
const next = this.fork();
|
|
@@ -3798,15 +3776,17 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3798
3776
|
next.#s.pricing = pricing;
|
|
3799
3777
|
if (billing === "upto") {
|
|
3800
3778
|
if (resolvedOptions.protocols?.some((p) => p !== "x402")) {
|
|
3801
|
-
throw new
|
|
3802
|
-
|
|
3779
|
+
throw new RouteDefinitionError(
|
|
3780
|
+
this.#s.key,
|
|
3781
|
+
`.upTo() is x402-only \u2014 remove the conflicting protocols override.`
|
|
3803
3782
|
);
|
|
3804
3783
|
}
|
|
3805
3784
|
next.#s.protocols = ["x402"];
|
|
3806
3785
|
} else if (billing === "metered") {
|
|
3807
3786
|
if (resolvedOptions.protocols?.some((p) => p !== "mpp")) {
|
|
3808
|
-
throw new
|
|
3809
|
-
|
|
3787
|
+
throw new RouteDefinitionError(
|
|
3788
|
+
this.#s.key,
|
|
3789
|
+
`.metered() is MPP-only \u2014 remove the conflicting protocols override.`
|
|
3810
3790
|
);
|
|
3811
3791
|
}
|
|
3812
3792
|
next.#s.protocols = ["mpp"];
|
|
@@ -3830,73 +3810,69 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3830
3810
|
if (typeof pricing === "object" && "tiers" in pricing) {
|
|
3831
3811
|
for (const [tierKey, tierConfig] of Object.entries(pricing.tiers)) {
|
|
3832
3812
|
if (!tierKey) {
|
|
3833
|
-
throw new
|
|
3813
|
+
throw new RouteDefinitionError(this.#s.key, `tier key cannot be empty`);
|
|
3834
3814
|
}
|
|
3835
3815
|
if (!isPositiveDecimal(tierConfig.price)) {
|
|
3836
|
-
throw new
|
|
3837
|
-
|
|
3816
|
+
throw new RouteDefinitionError(
|
|
3817
|
+
this.#s.key,
|
|
3818
|
+
`tier '${tierKey}' price '${tierConfig.price}' must be a positive decimal string`
|
|
3838
3819
|
);
|
|
3839
3820
|
}
|
|
3840
3821
|
}
|
|
3841
3822
|
}
|
|
3842
3823
|
if (billing === "exact" && typeof pricing === "string" && !isPositiveDecimal(pricing)) {
|
|
3843
|
-
throw new
|
|
3844
|
-
|
|
3824
|
+
throw new RouteDefinitionError(
|
|
3825
|
+
this.#s.key,
|
|
3826
|
+
`price '${pricing}' must be a positive decimal string`
|
|
3845
3827
|
);
|
|
3846
3828
|
}
|
|
3847
3829
|
if (typeof pricing === "function" && next.#s.maxPrice === void 0) {
|
|
3848
|
-
throw new
|
|
3849
|
-
|
|
3830
|
+
throw new RouteDefinitionError(
|
|
3831
|
+
this.#s.key,
|
|
3832
|
+
`dynamic pricing requires maxPrice \u2014 without it, bare probes would advertise a $0 challenge`
|
|
3850
3833
|
);
|
|
3851
3834
|
}
|
|
3852
3835
|
if (next.#s.maxPrice !== void 0 && !isPositiveDecimal(next.#s.maxPrice)) {
|
|
3853
|
-
throw new
|
|
3854
|
-
|
|
3836
|
+
throw new RouteDefinitionError(
|
|
3837
|
+
this.#s.key,
|
|
3838
|
+
`maxPrice '${next.#s.maxPrice}' must be a positive decimal string`
|
|
3855
3839
|
);
|
|
3856
3840
|
}
|
|
3857
3841
|
if (next.#s.minPrice !== void 0 && !isPositiveDecimal(next.#s.minPrice)) {
|
|
3858
|
-
throw new
|
|
3859
|
-
|
|
3842
|
+
throw new RouteDefinitionError(
|
|
3843
|
+
this.#s.key,
|
|
3844
|
+
`minPrice '${next.#s.minPrice}' must be a positive decimal string`
|
|
3860
3845
|
);
|
|
3861
3846
|
}
|
|
3862
3847
|
if (next.#s.tickCost !== void 0 && !isPositiveDecimal(next.#s.tickCost)) {
|
|
3863
|
-
throw new
|
|
3864
|
-
|
|
3848
|
+
throw new RouteDefinitionError(
|
|
3849
|
+
this.#s.key,
|
|
3850
|
+
`tickCost '${next.#s.tickCost}' must be a positive decimal string`
|
|
3865
3851
|
);
|
|
3866
3852
|
}
|
|
3867
3853
|
return next;
|
|
3868
3854
|
}
|
|
3869
|
-
/**
|
|
3870
|
-
* Require Sign-In-with-X wallet identity on this route — clients prove
|
|
3871
|
-
* control of a wallet via a signed challenge. Composes with `.paid()` and
|
|
3872
|
-
* `.upTo()` for pay-once-then-replay: the first request settles normally,
|
|
3873
|
-
* subsequent requests with a valid SIWX signature for the same wallet skip
|
|
3874
|
-
* payment (on `.upTo()`, `charge(amount)` becomes a no-op on the replay).
|
|
3875
|
-
* Mutually exclusive with `.metered()`.
|
|
3876
|
-
*
|
|
3877
|
-
* @example
|
|
3878
|
-
* ```ts
|
|
3879
|
-
* router.route('profile').siwx().handler(async ({ wallet }) => getProfile(wallet));
|
|
3880
|
-
* router.route('inbox').paid('0.01').siwx().handler(async ({ wallet }) => getInbox(wallet));
|
|
3881
|
-
* ```
|
|
3882
|
-
*/
|
|
3883
3855
|
siwx() {
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3856
|
+
const self = this;
|
|
3857
|
+
if (self.#s.authMode === "unprotected") {
|
|
3858
|
+
throw new RouteDefinitionError(
|
|
3859
|
+
self.#s.key,
|
|
3860
|
+
`Cannot combine .unprotected() and .siwx() on the same route.`
|
|
3887
3861
|
);
|
|
3888
3862
|
}
|
|
3889
|
-
if (
|
|
3890
|
-
throw new
|
|
3891
|
-
|
|
3863
|
+
if (self.#s.apiKeyResolver) {
|
|
3864
|
+
throw new RouteDefinitionError(
|
|
3865
|
+
self.#s.key,
|
|
3866
|
+
`Combining .siwx() and .apiKey() is not supported on the same route.`
|
|
3892
3867
|
);
|
|
3893
3868
|
}
|
|
3894
|
-
if (
|
|
3895
|
-
throw new
|
|
3896
|
-
|
|
3869
|
+
if (self.#s.billing === "metered") {
|
|
3870
|
+
throw new RouteDefinitionError(
|
|
3871
|
+
self.#s.key,
|
|
3872
|
+
`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.`
|
|
3897
3873
|
);
|
|
3898
3874
|
}
|
|
3899
|
-
const next =
|
|
3875
|
+
const next = self.fork();
|
|
3900
3876
|
next.#s.siwxEnabled = true;
|
|
3901
3877
|
if (next.#s.authMode === "paid" || next.#s.pricing) {
|
|
3902
3878
|
next.#s.authMode = "paid";
|
|
@@ -3907,59 +3883,48 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3907
3883
|
next.#s.protocols = [];
|
|
3908
3884
|
return next;
|
|
3909
3885
|
}
|
|
3910
|
-
/**
|
|
3911
|
-
* Require an `X-API-Key` header (or `Authorization: Bearer <key>`); the
|
|
3912
|
-
* resolver returns the account record, or `null` for 401. Composes with
|
|
3913
|
-
* `.paid()` — key is checked first, payment second.
|
|
3914
|
-
*
|
|
3915
|
-
* @example
|
|
3916
|
-
* ```ts
|
|
3917
|
-
* router
|
|
3918
|
-
* .route('admin/users')
|
|
3919
|
-
* .apiKey(async (key) => db.admin.findByKey(key))
|
|
3920
|
-
* .handler(async ({ account }) => db.user.list(account.orgId));
|
|
3921
|
-
* ```
|
|
3922
|
-
*/
|
|
3923
3886
|
apiKey(resolver) {
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3887
|
+
const self = this;
|
|
3888
|
+
if (self.#s.authMode === "unprotected") {
|
|
3889
|
+
throw new RouteDefinitionError(
|
|
3890
|
+
self.#s.key,
|
|
3891
|
+
`Cannot combine .unprotected() and .apiKey() on the same route.`
|
|
3927
3892
|
);
|
|
3928
3893
|
}
|
|
3929
|
-
|
|
3894
|
+
if (self.#s.siwxEnabled) {
|
|
3895
|
+
throw new RouteDefinitionError(
|
|
3896
|
+
self.#s.key,
|
|
3897
|
+
`Combining .apiKey() and .siwx() is not supported on the same route.`
|
|
3898
|
+
);
|
|
3899
|
+
}
|
|
3900
|
+
const next = self.fork();
|
|
3930
3901
|
next.#s.authMode = "apiKey";
|
|
3931
3902
|
next.#s.apiKeyResolver = resolver;
|
|
3932
3903
|
return next;
|
|
3933
3904
|
}
|
|
3934
|
-
/**
|
|
3935
|
-
* Mark the route as public — no auth, no payment, no SIWX. The handler
|
|
3936
|
-
* receives `null` for `wallet`, `payment`, and `account`.
|
|
3937
|
-
*
|
|
3938
|
-
* @example
|
|
3939
|
-
* ```ts
|
|
3940
|
-
* router.route('health').unprotected().handler(async () => ({ status: 'ok' }));
|
|
3941
|
-
* ```
|
|
3942
|
-
*/
|
|
3943
3905
|
unprotected() {
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3906
|
+
const self = this;
|
|
3907
|
+
if (self.#s.authMode && self.#s.authMode !== "unprotected") {
|
|
3908
|
+
throw new RouteDefinitionError(
|
|
3909
|
+
self.#s.key,
|
|
3910
|
+
`Cannot combine .unprotected() and .${self.#s.authMode}() on the same route.`
|
|
3947
3911
|
);
|
|
3948
3912
|
}
|
|
3949
|
-
if (
|
|
3950
|
-
throw new
|
|
3951
|
-
|
|
3913
|
+
if (self.#s.pricing) {
|
|
3914
|
+
throw new RouteDefinitionError(
|
|
3915
|
+
self.#s.key,
|
|
3916
|
+
`Cannot combine .unprotected() and .paid() on the same route.`
|
|
3952
3917
|
);
|
|
3953
3918
|
}
|
|
3954
|
-
const next =
|
|
3919
|
+
const next = self.fork();
|
|
3955
3920
|
next.#s.authMode = "unprotected";
|
|
3956
3921
|
next.#s.protocols = [];
|
|
3957
3922
|
return next;
|
|
3958
3923
|
}
|
|
3959
3924
|
/**
|
|
3960
3925
|
* Tag the route with an upstream provider for discovery and provider-side
|
|
3961
|
-
* monitoring. The provider name and config surface in
|
|
3962
|
-
*
|
|
3926
|
+
* monitoring. The provider name and config surface in OpenAPI discovery
|
|
3927
|
+
* output.
|
|
3963
3928
|
*
|
|
3964
3929
|
* @example
|
|
3965
3930
|
* ```ts
|
|
@@ -4056,8 +4021,8 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
4056
4021
|
return next;
|
|
4057
4022
|
}
|
|
4058
4023
|
/**
|
|
4059
|
-
* Set a human-readable summary of the route. Surfaces in OpenAPI
|
|
4060
|
-
* `
|
|
4024
|
+
* Set a human-readable summary of the route. Surfaces in OpenAPI and
|
|
4025
|
+
* `llms.txt` discovery output.
|
|
4061
4026
|
*
|
|
4062
4027
|
* @example
|
|
4063
4028
|
* ```ts
|
|
@@ -4193,38 +4158,46 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
4193
4158
|
}
|
|
4194
4159
|
register(handlerFn, streaming) {
|
|
4195
4160
|
if (!this.#s.authMode) {
|
|
4196
|
-
throw new
|
|
4197
|
-
|
|
4161
|
+
throw new RouteDefinitionError(
|
|
4162
|
+
this.#s.key,
|
|
4163
|
+
`Select an auth mode: .paid(pricing), .upTo(maxPrice), .metered(options), .siwx(), .apiKey(resolver), or .unprotected()`
|
|
4198
4164
|
);
|
|
4199
4165
|
}
|
|
4200
4166
|
if (this.#s.validateFn && !this.#s.bodySchema) {
|
|
4201
|
-
throw new
|
|
4202
|
-
|
|
4167
|
+
throw new RouteDefinitionError(
|
|
4168
|
+
this.#s.key,
|
|
4169
|
+
`.validate() requires .body() \u2014 validation runs on parsed body`
|
|
4203
4170
|
);
|
|
4204
4171
|
}
|
|
4205
4172
|
if (this.#s.settlement && !this.#s.pricing) {
|
|
4206
|
-
throw new
|
|
4173
|
+
throw new RouteDefinitionError(this.#s.key, `.settlement() requires a paid route`);
|
|
4207
4174
|
}
|
|
4208
4175
|
if (this.#s.mppInfo?.settleBeforeHandler) {
|
|
4209
4176
|
if (!this.#s.pricing) {
|
|
4210
|
-
throw new
|
|
4177
|
+
throw new RouteDefinitionError(
|
|
4178
|
+
this.#s.key,
|
|
4179
|
+
`mpp.settleBeforeHandler requires a paid route`
|
|
4180
|
+
);
|
|
4211
4181
|
}
|
|
4212
4182
|
if (this.#s.billing !== "exact") {
|
|
4213
|
-
throw new
|
|
4214
|
-
|
|
4183
|
+
throw new RouteDefinitionError(
|
|
4184
|
+
this.#s.key,
|
|
4185
|
+
`mpp.settleBeforeHandler is only supported on .paid() routes`
|
|
4215
4186
|
);
|
|
4216
4187
|
}
|
|
4217
4188
|
if (this.#s.settlement?.beforeSettle) {
|
|
4218
|
-
throw new
|
|
4219
|
-
|
|
4189
|
+
throw new RouteDefinitionError(
|
|
4190
|
+
this.#s.key,
|
|
4191
|
+
`mpp.settleBeforeHandler is incompatible with .settlement({ beforeSettle }) \u2014 MPP payment is already broadcast before the handler runs`
|
|
4220
4192
|
);
|
|
4221
4193
|
}
|
|
4222
4194
|
}
|
|
4223
4195
|
if (this.#s.billing === "upto") {
|
|
4224
4196
|
const hasUpto = this.#s.deps.x402Accepts.some((accept) => accept.scheme === "upto");
|
|
4225
4197
|
if (!hasUpto) {
|
|
4226
|
-
throw new
|
|
4227
|
-
|
|
4198
|
+
throw new RouteDefinitionError(
|
|
4199
|
+
this.#s.key,
|
|
4200
|
+
`.upTo() requires an 'upto' accept on at least one configured network. Add { scheme: 'upto', network, asset } to RouterConfig.x402.accepts.`
|
|
4228
4201
|
);
|
|
4229
4202
|
}
|
|
4230
4203
|
}
|
|
@@ -4233,26 +4206,30 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
4233
4206
|
(accept) => (accept.scheme ?? "exact") !== "upto"
|
|
4234
4207
|
);
|
|
4235
4208
|
if (!hasExact) {
|
|
4236
|
-
throw new
|
|
4237
|
-
|
|
4209
|
+
throw new RouteDefinitionError(
|
|
4210
|
+
this.#s.key,
|
|
4211
|
+
`.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.`
|
|
4238
4212
|
);
|
|
4239
4213
|
}
|
|
4240
4214
|
}
|
|
4241
4215
|
if (this.#s.billing === "metered") {
|
|
4242
4216
|
if (!this.#s.deps.mppSessionConfig) {
|
|
4243
|
-
throw new
|
|
4244
|
-
|
|
4217
|
+
throw new RouteDefinitionError(
|
|
4218
|
+
this.#s.key,
|
|
4219
|
+
`.metered() requires MPP session mode. Set RouterConfig.mpp.session = {} and provide mpp.operatorKey.`
|
|
4245
4220
|
);
|
|
4246
4221
|
}
|
|
4247
4222
|
}
|
|
4248
4223
|
if (streaming && this.#s.billing !== "metered") {
|
|
4249
|
-
throw new
|
|
4250
|
-
|
|
4224
|
+
throw new RouteDefinitionError(
|
|
4225
|
+
this.#s.key,
|
|
4226
|
+
`.stream() requires .metered() \u2014 static/free/upto routes can't meter per-chunk billing.`
|
|
4251
4227
|
);
|
|
4252
4228
|
}
|
|
4253
4229
|
if (this.#s.description !== void 0 && this.#s.description.length > MAX_X402_DESCRIPTION_LENGTH && this.#s.pricing !== void 0 && this.#s.protocols.includes("x402")) {
|
|
4254
|
-
throw new
|
|
4255
|
-
|
|
4230
|
+
throw new RouteDefinitionError(
|
|
4231
|
+
this.#s.key,
|
|
4232
|
+
`.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.`
|
|
4256
4233
|
);
|
|
4257
4234
|
}
|
|
4258
4235
|
validateExamples(
|
|
@@ -4320,14 +4297,15 @@ function normalizePaidArg(routeKey, arg, options) {
|
|
|
4320
4297
|
if ("price" in arg && typeof arg.price === "string") {
|
|
4321
4298
|
return { pricing: arg.price, resolvedOptions: arg, billing: "exact" };
|
|
4322
4299
|
}
|
|
4323
|
-
throw new
|
|
4324
|
-
|
|
4300
|
+
throw new RouteDefinitionError(
|
|
4301
|
+
routeKey,
|
|
4302
|
+
`.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().`
|
|
4325
4303
|
);
|
|
4326
4304
|
}
|
|
4327
4305
|
function normalizeUpToArg(routeKey, arg) {
|
|
4328
4306
|
const options = typeof arg === "string" ? { maxPrice: arg } : arg;
|
|
4329
4307
|
if (!options.maxPrice) {
|
|
4330
|
-
throw new
|
|
4308
|
+
throw new RouteDefinitionError(routeKey, `.upTo() requires maxPrice`);
|
|
4331
4309
|
}
|
|
4332
4310
|
return {
|
|
4333
4311
|
pricing: options.maxPrice,
|
|
@@ -4339,10 +4317,10 @@ function normalizeUpToArg(routeKey, arg) {
|
|
|
4339
4317
|
}
|
|
4340
4318
|
function normalizeMeteredArg(routeKey, options) {
|
|
4341
4319
|
if (!options.maxPrice) {
|
|
4342
|
-
throw new
|
|
4320
|
+
throw new RouteDefinitionError(routeKey, `.metered() requires maxPrice`);
|
|
4343
4321
|
}
|
|
4344
4322
|
if (!options.tickCost) {
|
|
4345
|
-
throw new
|
|
4323
|
+
throw new RouteDefinitionError(routeKey, `.metered() requires tickCost`);
|
|
4346
4324
|
}
|
|
4347
4325
|
return {
|
|
4348
4326
|
pricing: options.maxPrice,
|
|
@@ -4649,9 +4627,9 @@ function createNotFoundHandler(baseUrl) {
|
|
|
4649
4627
|
code: "route_not_found",
|
|
4650
4628
|
error: "Route not found. Rediscover this origin and retry with the current discovery document.",
|
|
4651
4629
|
requestedUrl: request.url,
|
|
4630
|
+
// The deprecated /.well-known/x402 surface is intentionally not advertised.
|
|
4652
4631
|
discovery: {
|
|
4653
4632
|
openapi: `${normalizedBase}/openapi.json`,
|
|
4654
|
-
wellKnown: `${normalizedBase}/.well-known/x402`,
|
|
4655
4633
|
llmsTxt: `${normalizedBase}/llms.txt`
|
|
4656
4634
|
}
|
|
4657
4635
|
},
|
|
@@ -4684,6 +4662,7 @@ function formatRouterConfigIssues(issues) {
|
|
|
4684
4662
|
}
|
|
4685
4663
|
|
|
4686
4664
|
// src/config/schema.ts
|
|
4665
|
+
init_accepts();
|
|
4687
4666
|
init_constants();
|
|
4688
4667
|
import { z } from "zod";
|
|
4689
4668
|
|
|
@@ -4873,18 +4852,8 @@ function deriveBaseUrlEnv(env) {
|
|
|
4873
4852
|
BASE_URL: vercelBaseUrl
|
|
4874
4853
|
};
|
|
4875
4854
|
}
|
|
4876
|
-
function getConfiguredX402Accepts2(config) {
|
|
4877
|
-
if (config.x402?.accepts?.length) return [...config.x402.accepts];
|
|
4878
|
-
return [
|
|
4879
|
-
{
|
|
4880
|
-
scheme: "exact",
|
|
4881
|
-
network: config.network ?? BASE_MAINNET_NETWORK,
|
|
4882
|
-
payTo: config.payeeAddress
|
|
4883
|
-
}
|
|
4884
|
-
];
|
|
4885
|
-
}
|
|
4886
4855
|
function validateX402Config(config, env) {
|
|
4887
|
-
const accepts =
|
|
4856
|
+
const accepts = getConfiguredX402Accepts(config);
|
|
4888
4857
|
const issues = [];
|
|
4889
4858
|
const push = (code, message) => issues.push({ code, protocol: "x402", message });
|
|
4890
4859
|
if (accepts.length === 0) {
|
|
@@ -5185,7 +5154,8 @@ function getMppxRequestContext(args) {
|
|
|
5185
5154
|
recipient: mppConfig.recipient ?? payeeAddress,
|
|
5186
5155
|
getClient,
|
|
5187
5156
|
...feePayerAccount ? { feePayer: feePayerAccount } : {},
|
|
5188
|
-
...resolvedStore ? { store: resolvedStore } : {}
|
|
5157
|
+
...resolvedStore ? { store: resolvedStore } : {},
|
|
5158
|
+
...mppConfig.feePayerPolicy ? { feePayerPolicy: mppConfig.feePayerPolicy } : {}
|
|
5189
5159
|
}),
|
|
5190
5160
|
...sessionEnabled ? [
|
|
5191
5161
|
tempo.session({
|
|
@@ -5223,7 +5193,7 @@ async function initMpp(config, resolvedBaseUrl, kvStore, configError) {
|
|
|
5223
5193
|
try {
|
|
5224
5194
|
const { Mppx, tempo } = await import("mppx/server");
|
|
5225
5195
|
const { createClient, http } = await import("viem");
|
|
5226
|
-
const { tempo: tempoChain } = await import("viem/chains");
|
|
5196
|
+
const { tempo: tempoChain } = await import("viem/tempo/chains");
|
|
5227
5197
|
const { privateKeyToAccount: privateKeyToAccount2 } = await import("viem/accounts");
|
|
5228
5198
|
const rpcUrl = config.mpp.rpcUrl ?? process.env.TEMPO_RPC_URL ?? DEFAULT_TEMPO_RPC_URL;
|
|
5229
5199
|
const tempoClient = createClient({ chain: tempoChain, transport: http(rpcUrl) });
|
|
@@ -5241,7 +5211,9 @@ async function initMpp(config, resolvedBaseUrl, kvStore, configError) {
|
|
|
5241
5211
|
getClient,
|
|
5242
5212
|
...operatorAccount ? { account: operatorAccount } : {},
|
|
5243
5213
|
...feePayerAccount ? { feePayer: feePayerAccount } : {},
|
|
5244
|
-
...resolvedStore ? { store: resolvedStore } : {}
|
|
5214
|
+
...resolvedStore ? { store: resolvedStore } : {},
|
|
5215
|
+
...mppConfig.feePayerPolicy ? { feePayerPolicy: mppConfig.feePayerPolicy } : {},
|
|
5216
|
+
...mppConfig.session?.settlementSchedule ? { settlementSchedule: mppConfig.session.settlementSchedule } : {}
|
|
5245
5217
|
};
|
|
5246
5218
|
const mppxArgs = {
|
|
5247
5219
|
Mppx,
|
|
@@ -5257,6 +5229,7 @@ async function initMpp(config, resolvedBaseUrl, kvStore, configError) {
|
|
|
5257
5229
|
};
|
|
5258
5230
|
const primary = getMppxRequestContext(mppxArgs);
|
|
5259
5231
|
const streaming = getMppxStreamingContext(mppxArgs);
|
|
5232
|
+
subscribePaymentFailedAlerts(config.plugin, [primary, streaming]);
|
|
5260
5233
|
const mppx = {
|
|
5261
5234
|
charge: primary.charge,
|
|
5262
5235
|
...primary.session ? { sessionRequest: primary.session } : {},
|
|
@@ -5267,6 +5240,41 @@ async function initMpp(config, resolvedBaseUrl, kvStore, configError) {
|
|
|
5267
5240
|
return { initError: err instanceof Error ? err.message : String(err) };
|
|
5268
5241
|
}
|
|
5269
5242
|
}
|
|
5243
|
+
function subscribePaymentFailedAlerts(plugin, instances) {
|
|
5244
|
+
if (!plugin?.onAlert) return;
|
|
5245
|
+
const ctx = {
|
|
5246
|
+
requestId: "mppx",
|
|
5247
|
+
route: "mpp",
|
|
5248
|
+
walletAddress: null,
|
|
5249
|
+
clientId: null,
|
|
5250
|
+
sessionId: null,
|
|
5251
|
+
verifiedWallet: null,
|
|
5252
|
+
setVerifiedWallet() {
|
|
5253
|
+
}
|
|
5254
|
+
};
|
|
5255
|
+
for (const instance of instances) {
|
|
5256
|
+
const events = instance;
|
|
5257
|
+
if (typeof events?.onPaymentFailed !== "function") continue;
|
|
5258
|
+
events.onPaymentFailed((payload) => {
|
|
5259
|
+
try {
|
|
5260
|
+
const error = payload?.error ?? {};
|
|
5261
|
+
firePluginHook(plugin, "onAlert", ctx, {
|
|
5262
|
+
level: (error.status ?? 402) >= 500 ? "error" : "warn",
|
|
5263
|
+
message: `MPP payment failed: ${error.message ?? error.name ?? "unknown error"}`,
|
|
5264
|
+
route: "mpp",
|
|
5265
|
+
meta: {
|
|
5266
|
+
...payload?.method ? { method: `${payload.method.name}/${payload.method.intent}` } : {},
|
|
5267
|
+
...error.type ? { errorType: error.type } : {},
|
|
5268
|
+
...error.status !== void 0 ? { status: error.status } : {},
|
|
5269
|
+
...error.hint ? { hint: error.hint } : {},
|
|
5270
|
+
...payload?.credential?.source ? { payer: payload.credential.source } : {}
|
|
5271
|
+
}
|
|
5272
|
+
});
|
|
5273
|
+
} catch {
|
|
5274
|
+
}
|
|
5275
|
+
});
|
|
5276
|
+
}
|
|
5277
|
+
}
|
|
5270
5278
|
|
|
5271
5279
|
// src/index.ts
|
|
5272
5280
|
init_constants();
|
|
@@ -5409,6 +5417,7 @@ export {
|
|
|
5409
5417
|
DEFAULT_SOLANA_FACILITATOR_URL,
|
|
5410
5418
|
DEFAULT_TEMPO_RPC_URL,
|
|
5411
5419
|
HttpError,
|
|
5420
|
+
RouteDefinitionError,
|
|
5412
5421
|
RouterConfigError,
|
|
5413
5422
|
SOLANA_MAINNET_NETWORK,
|
|
5414
5423
|
TEMPO_USDC_ADDRESS,
|