@agentcash/router 1.10.3 → 1.10.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +167 -57
- package/dist/index.d.cts +16 -2
- package/dist/index.d.ts +16 -2
- package/dist/index.js +167 -57
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -541,7 +541,8 @@ var HEADERS = {
|
|
|
541
541
|
X402_PAYMENT_LEGACY: "X-PAYMENT",
|
|
542
542
|
X402_PAYMENT_REQUIRED: "PAYMENT-REQUIRED",
|
|
543
543
|
X402_PAYMENT_RESPONSE: "PAYMENT-RESPONSE",
|
|
544
|
-
MPP_PAYMENT_RECEIPT: "Payment-Receipt"
|
|
544
|
+
MPP_PAYMENT_RECEIPT: "Payment-Receipt",
|
|
545
|
+
REQUEST_ID: "X-Request-ID"
|
|
545
546
|
};
|
|
546
547
|
var AUTH_SCHEME = {
|
|
547
548
|
BEARER: "Bearer ",
|
|
@@ -571,19 +572,19 @@ function firePluginHook(plugin, method, ...args) {
|
|
|
571
572
|
const result = fn.apply(plugin, args);
|
|
572
573
|
if (result && typeof result.catch === "function") {
|
|
573
574
|
result.catch((error) => {
|
|
574
|
-
console.error(
|
|
575
|
-
`[router] ERROR ${method}: ${error instanceof Error ? error.message : String(error)}`
|
|
576
|
-
);
|
|
575
|
+
console.error(`[router] ERROR ${method}: ${formatUnknownError(error)}`);
|
|
577
576
|
});
|
|
578
577
|
}
|
|
579
578
|
return result;
|
|
580
579
|
} catch (error) {
|
|
581
|
-
console.error(
|
|
582
|
-
`[router] ERROR ${method}: ${error instanceof Error ? error.message : String(error)}`
|
|
583
|
-
);
|
|
580
|
+
console.error(`[router] ERROR ${method}: ${formatUnknownError(error)}`);
|
|
584
581
|
return void 0;
|
|
585
582
|
}
|
|
586
583
|
}
|
|
584
|
+
function formatUnknownError(error) {
|
|
585
|
+
if (error instanceof Error) return error.stack ?? error.message;
|
|
586
|
+
return String(error);
|
|
587
|
+
}
|
|
587
588
|
|
|
588
589
|
// src/plugin/reporter.ts
|
|
589
590
|
function createReporter(plugin, pluginCtx, route) {
|
|
@@ -674,7 +675,8 @@ function firePaymentVerified(ctx, event) {
|
|
|
674
675
|
function firePaymentSettled(ctx, event) {
|
|
675
676
|
firePluginHook(ctx.deps.plugin, "onPaymentSettled", ctx.pluginCtx, event);
|
|
676
677
|
}
|
|
677
|
-
function firePluginResponse(ctx, response, requestBody, responseBody) {
|
|
678
|
+
function firePluginResponse(ctx, response, requestBody, responseBody, failure) {
|
|
679
|
+
attachRequestId(response, ctx.meta.requestId);
|
|
678
680
|
firePluginHook(ctx.deps.plugin, "onResponse", ctx.pluginCtx, {
|
|
679
681
|
statusCode: response.status,
|
|
680
682
|
statusText: response.statusText,
|
|
@@ -685,11 +687,9 @@ function firePluginResponse(ctx, response, requestBody, responseBody) {
|
|
|
685
687
|
responseBody
|
|
686
688
|
});
|
|
687
689
|
if (response.status >= 400 && response.status !== 402) {
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
settled: false
|
|
692
|
-
});
|
|
690
|
+
const error = buildErrorEvent(ctx, response, failure);
|
|
691
|
+
if (response.status >= 500) logRouterFailure(error);
|
|
692
|
+
firePluginHook(ctx.deps.plugin, "onError", ctx.pluginCtx, error);
|
|
693
693
|
}
|
|
694
694
|
}
|
|
695
695
|
function fireProviderQuota(ctx, response, handlerResult) {
|
|
@@ -721,6 +721,67 @@ function computeQuotaLevel(remaining, warn, critical) {
|
|
|
721
721
|
if (warn !== void 0 && remaining <= warn) return "warn";
|
|
722
722
|
return "healthy";
|
|
723
723
|
}
|
|
724
|
+
function attachRequestId(response, requestId) {
|
|
725
|
+
try {
|
|
726
|
+
if (!response.headers.has(HEADERS.REQUEST_ID)) {
|
|
727
|
+
response.headers.set(HEADERS.REQUEST_ID, requestId);
|
|
728
|
+
}
|
|
729
|
+
} catch {
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
function buildErrorEvent(ctx, response, failure) {
|
|
733
|
+
const error = errorDetails(failure?.cause);
|
|
734
|
+
const responseMessage = response.statusText || `HTTP ${response.status}`;
|
|
735
|
+
const message = failure?.message ?? error.message ?? responseMessage;
|
|
736
|
+
return {
|
|
737
|
+
status: response.status,
|
|
738
|
+
message,
|
|
739
|
+
settled: failure?.settled ?? false,
|
|
740
|
+
requestId: ctx.meta.requestId,
|
|
741
|
+
route: ctx.meta.route,
|
|
742
|
+
method: ctx.meta.method,
|
|
743
|
+
duration: Date.now() - ctx.meta.startTime,
|
|
744
|
+
walletAddress: ctx.meta.walletAddress,
|
|
745
|
+
verifiedWallet: ctx.pluginCtx.verifiedWallet,
|
|
746
|
+
clientId: ctx.meta.clientId,
|
|
747
|
+
sessionId: ctx.meta.sessionId,
|
|
748
|
+
errorName: error.name,
|
|
749
|
+
stack: error.stack,
|
|
750
|
+
cause: failure?.cause
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
function errorDetails(error) {
|
|
754
|
+
if (error instanceof Error) {
|
|
755
|
+
return {
|
|
756
|
+
message: error.message,
|
|
757
|
+
name: error.name,
|
|
758
|
+
stack: error.stack
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
if (typeof error === "object" && error !== null) {
|
|
762
|
+
const record = error;
|
|
763
|
+
return {
|
|
764
|
+
message: typeof record.message === "string" ? record.message : void 0,
|
|
765
|
+
name: typeof record.name === "string" ? record.name : void 0,
|
|
766
|
+
stack: typeof record.stack === "string" ? record.stack : void 0
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
if (typeof error === "string") return { message: error };
|
|
770
|
+
return {};
|
|
771
|
+
}
|
|
772
|
+
function logRouterFailure(error) {
|
|
773
|
+
console.error(`[router] ERROR ${error.route ?? "unknown"} ${error.status}: ${error.message}`, {
|
|
774
|
+
requestId: error.requestId,
|
|
775
|
+
method: error.method,
|
|
776
|
+
duration: error.duration,
|
|
777
|
+
walletAddress: error.walletAddress,
|
|
778
|
+
verifiedWallet: error.verifiedWallet,
|
|
779
|
+
clientId: error.clientId,
|
|
780
|
+
sessionId: error.sessionId,
|
|
781
|
+
errorName: error.errorName,
|
|
782
|
+
stack: error.stack
|
|
783
|
+
});
|
|
784
|
+
}
|
|
724
785
|
|
|
725
786
|
// src/pipeline/steps/parse-body.ts
|
|
726
787
|
async function parseBody(ctx, request = ctx.request) {
|
|
@@ -730,20 +791,19 @@ async function parseBody(ctx, request = ctx.request) {
|
|
|
730
791
|
raw = await bufferBody(request);
|
|
731
792
|
} catch (err) {
|
|
732
793
|
if (!(err instanceof MalformedJsonError)) throw err;
|
|
733
|
-
const
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
794
|
+
const responseBody2 = { success: false, error: "Invalid JSON", issues: [] };
|
|
795
|
+
const response2 = import_server.NextResponse.json(responseBody2, { status: 400 });
|
|
796
|
+
firePluginResponse(ctx, response2, void 0, responseBody2, {
|
|
797
|
+
message: responseBody2.error,
|
|
798
|
+
cause: err
|
|
799
|
+
});
|
|
738
800
|
return { ok: false, response: response2 };
|
|
739
801
|
}
|
|
740
802
|
const result = validateBody(raw, ctx.routeEntry.bodySchema);
|
|
741
803
|
if (result.success) return { ok: true, data: result.data };
|
|
742
|
-
const
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
);
|
|
746
|
-
firePluginResponse(ctx, response);
|
|
804
|
+
const responseBody = { success: false, error: result.error, issues: result.issues };
|
|
805
|
+
const response = import_server.NextResponse.json(responseBody, { status: 400 });
|
|
806
|
+
firePluginResponse(ctx, response, raw, responseBody, { message: result.error });
|
|
747
807
|
return { ok: false, response };
|
|
748
808
|
}
|
|
749
809
|
|
|
@@ -755,11 +815,9 @@ function validateQuery(ctx) {
|
|
|
755
815
|
const params = Object.fromEntries(ctx.request.nextUrl.searchParams.entries());
|
|
756
816
|
const result = validateBody(params, querySchema);
|
|
757
817
|
if (result.success) return { ok: true, data: result.data };
|
|
758
|
-
const
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
);
|
|
762
|
-
firePluginResponse(ctx, response);
|
|
818
|
+
const responseBody = { success: false, error: result.error, issues: result.issues };
|
|
819
|
+
const response = import_server2.NextResponse.json(responseBody, { status: 400 });
|
|
820
|
+
firePluginResponse(ctx, response, params, responseBody, { message: result.error });
|
|
763
821
|
return { ok: false, response };
|
|
764
822
|
}
|
|
765
823
|
|
|
@@ -778,9 +836,13 @@ function handlerFailureError(response) {
|
|
|
778
836
|
|
|
779
837
|
// src/pipeline/steps/fail.ts
|
|
780
838
|
var import_server3 = require("next/server");
|
|
781
|
-
function fail(ctx, status, message, requestBody) {
|
|
782
|
-
const
|
|
783
|
-
|
|
839
|
+
function fail(ctx, status, message, requestBody, failure) {
|
|
840
|
+
const responseBody = { success: false, error: message };
|
|
841
|
+
const response = import_server3.NextResponse.json(responseBody, { status });
|
|
842
|
+
firePluginResponse(ctx, response, requestBody, responseBody, {
|
|
843
|
+
...failure,
|
|
844
|
+
message: failure?.message ?? message
|
|
845
|
+
});
|
|
784
846
|
return response;
|
|
785
847
|
}
|
|
786
848
|
|
|
@@ -856,9 +918,10 @@ async function runHandler(ctx, handlerCtx) {
|
|
|
856
918
|
function errorResult(error) {
|
|
857
919
|
const status = error instanceof HttpError ? error.status : typeof error?.status === "number" ? error.status : 500;
|
|
858
920
|
const message = error instanceof Error ? error.message : "Internal error";
|
|
921
|
+
const responseBody = { success: false, error: message };
|
|
859
922
|
return {
|
|
860
|
-
response: import_server4.NextResponse.json(
|
|
861
|
-
rawResult:
|
|
923
|
+
response: import_server4.NextResponse.json(responseBody, { status }),
|
|
924
|
+
rawResult: responseBody,
|
|
862
925
|
handlerError: error
|
|
863
926
|
};
|
|
864
927
|
}
|
|
@@ -870,9 +933,9 @@ function isThenable(value) {
|
|
|
870
933
|
}
|
|
871
934
|
|
|
872
935
|
// src/pipeline/steps/finalize/response.ts
|
|
873
|
-
function finalize(ctx, response, rawResult, requestBody) {
|
|
936
|
+
function finalize(ctx, response, rawResult, requestBody, failure) {
|
|
874
937
|
fireProviderQuota(ctx, response, rawResult);
|
|
875
|
-
firePluginResponse(ctx, response, requestBody, rawResult);
|
|
938
|
+
firePluginResponse(ctx, response, requestBody, rawResult, failure);
|
|
876
939
|
return response;
|
|
877
940
|
}
|
|
878
941
|
|
|
@@ -958,7 +1021,9 @@ async function settleAndFinalizeRequest(args) {
|
|
|
958
1021
|
});
|
|
959
1022
|
if (!settle.ok) {
|
|
960
1023
|
if (onSettleError) await onSettleError(settle.error, settle.failMessage);
|
|
961
|
-
return fail(ctx, settle.failStatus ?? 500, settle.failMessage, body
|
|
1024
|
+
return fail(ctx, settle.failStatus ?? 500, settle.failMessage, body, {
|
|
1025
|
+
cause: settle.error
|
|
1026
|
+
});
|
|
962
1027
|
}
|
|
963
1028
|
return runPostSettleEpilogue({
|
|
964
1029
|
ctx,
|
|
@@ -993,7 +1058,9 @@ async function settleAndFinalizeStream(args) {
|
|
|
993
1058
|
report
|
|
994
1059
|
});
|
|
995
1060
|
if (!settle.ok) {
|
|
996
|
-
return fail(ctx, settle.failStatus ?? 500, settle.failMessage, body
|
|
1061
|
+
return fail(ctx, settle.failStatus ?? 500, settle.failMessage, body, {
|
|
1062
|
+
cause: settle.error
|
|
1063
|
+
});
|
|
997
1064
|
}
|
|
998
1065
|
return runPostSettleEpilogue({
|
|
999
1066
|
ctx,
|
|
@@ -1020,7 +1087,13 @@ async function runHandlerOnly(ctx, wallet, account) {
|
|
|
1020
1087
|
const validateErr = await runValidate(ctx, body.data);
|
|
1021
1088
|
if (validateErr) return validateErr;
|
|
1022
1089
|
const result = await invokeUnauthed(ctx, wallet, account, body.data);
|
|
1023
|
-
return finalize(
|
|
1090
|
+
return finalize(
|
|
1091
|
+
ctx,
|
|
1092
|
+
result.response,
|
|
1093
|
+
result.rawResult,
|
|
1094
|
+
body.data,
|
|
1095
|
+
result.handlerError === void 0 ? void 0 : { cause: result.handlerError }
|
|
1096
|
+
);
|
|
1024
1097
|
}
|
|
1025
1098
|
|
|
1026
1099
|
// src/pipeline/steps/run-before-settle.ts
|
|
@@ -2033,6 +2106,7 @@ function invalidPaymentVerification(failure) {
|
|
|
2033
2106
|
}
|
|
2034
2107
|
|
|
2035
2108
|
// src/protocols/x402/strategy.ts
|
|
2109
|
+
var SETTLE_RETRY_DELAYS_MS = [500, 1e3];
|
|
2036
2110
|
function formatVerifyFailureMessage(failure) {
|
|
2037
2111
|
if (failure.reason === "permit2_allowance_required") {
|
|
2038
2112
|
const wallet = failure.payer ?? "<the payer wallet>";
|
|
@@ -2123,7 +2197,17 @@ async function settleX402(args) {
|
|
|
2123
2197
|
const { payload, requirements } = token;
|
|
2124
2198
|
const override = routeEntry.billing === "exact" ? void 0 : { amount: billedAmount };
|
|
2125
2199
|
try {
|
|
2126
|
-
|
|
2200
|
+
let settle = await settleX402Payment(deps.x402Server, payload, requirements, override);
|
|
2201
|
+
for (let attempt = 0; !settle.result?.success && attempt < SETTLE_RETRY_DELAYS_MS.length; attempt++) {
|
|
2202
|
+
report("warn", "Retrying x402 settlement", {
|
|
2203
|
+
attempt: attempt + 1,
|
|
2204
|
+
errorReason: settle.result?.errorReason
|
|
2205
|
+
});
|
|
2206
|
+
await new Promise((resolve) => {
|
|
2207
|
+
setTimeout(resolve, SETTLE_RETRY_DELAYS_MS[attempt]);
|
|
2208
|
+
});
|
|
2209
|
+
settle = await settleX402Payment(deps.x402Server, payload, requirements, override);
|
|
2210
|
+
}
|
|
2127
2211
|
if (!settle.result?.success) {
|
|
2128
2212
|
throw Object.assign(
|
|
2129
2213
|
new Error(settle.result?.errorReason ?? "x402 settlement returned success=false"),
|
|
@@ -2459,11 +2543,9 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
|
|
|
2459
2543
|
challengePrice = pricing ? await pricing.challengeQuote(body) : "0";
|
|
2460
2544
|
} catch (err) {
|
|
2461
2545
|
const message = errorMessage(err, "Price calculation failed");
|
|
2462
|
-
const
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
);
|
|
2466
|
-
firePluginResponse(ctx, errorResponse);
|
|
2546
|
+
const responseBody2 = { success: false, error: message };
|
|
2547
|
+
const errorResponse = import_server5.NextResponse.json(responseBody2, { status: errorStatus(err, 500) });
|
|
2548
|
+
firePluginResponse(ctx, errorResponse, body, responseBody2, { message, cause: err });
|
|
2467
2549
|
return errorResponse;
|
|
2468
2550
|
}
|
|
2469
2551
|
const extensions = await buildChallengeExtensions(ctx);
|
|
@@ -2495,11 +2577,9 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
|
|
|
2495
2577
|
const message = `${strategy.protocol} challenge build failed: ${errorMessage(err, String(err))}`;
|
|
2496
2578
|
ctx.report("critical", message);
|
|
2497
2579
|
if (strategy.protocol === "x402") {
|
|
2498
|
-
const
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
);
|
|
2502
|
-
firePluginResponse(ctx, errorResponse);
|
|
2580
|
+
const responseBody2 = { success: false, error: message };
|
|
2581
|
+
const errorResponse = import_server5.NextResponse.json(responseBody2, { status: 500 });
|
|
2582
|
+
firePluginResponse(ctx, errorResponse, body, responseBody2, { message, cause: err });
|
|
2503
2583
|
return errorResponse;
|
|
2504
2584
|
}
|
|
2505
2585
|
}
|
|
@@ -2658,10 +2738,11 @@ function toResponse(rawResult) {
|
|
|
2658
2738
|
function errorResult2(error) {
|
|
2659
2739
|
const status = error instanceof HttpError ? error.status : typeof error?.status === "number" ? error.status : 500;
|
|
2660
2740
|
const message = error instanceof Error ? error.message : "Internal error";
|
|
2741
|
+
const responseBody = { success: false, error: message };
|
|
2661
2742
|
return {
|
|
2662
2743
|
kind: "request",
|
|
2663
|
-
response: import_server7.NextResponse.json(
|
|
2664
|
-
rawResult:
|
|
2744
|
+
response: import_server7.NextResponse.json(responseBody, { status }),
|
|
2745
|
+
rawResult: responseBody,
|
|
2665
2746
|
handlerError: error
|
|
2666
2747
|
};
|
|
2667
2748
|
}
|
|
@@ -2792,7 +2873,13 @@ async function runDynamicRequestFlow(args) {
|
|
|
2792
2873
|
handlerError: result.handlerError
|
|
2793
2874
|
};
|
|
2794
2875
|
if (result.response.status >= 400) {
|
|
2795
|
-
return finalize(
|
|
2876
|
+
return finalize(
|
|
2877
|
+
ctx,
|
|
2878
|
+
result.response,
|
|
2879
|
+
result.rawResult,
|
|
2880
|
+
body,
|
|
2881
|
+
failureFromCause(result.handlerError)
|
|
2882
|
+
);
|
|
2796
2883
|
}
|
|
2797
2884
|
const beforeErr = await runBeforeSettle(ctx, settleScope);
|
|
2798
2885
|
if (beforeErr) return beforeErr;
|
|
@@ -2814,6 +2901,9 @@ async function runDynamicRequestFlow(args) {
|
|
|
2814
2901
|
}
|
|
2815
2902
|
});
|
|
2816
2903
|
}
|
|
2904
|
+
function failureFromCause(cause) {
|
|
2905
|
+
return cause === void 0 ? void 0 : { cause };
|
|
2906
|
+
}
|
|
2817
2907
|
function computeBilledAmount(routeEntry, result) {
|
|
2818
2908
|
if (routeEntry.billing === "upto") {
|
|
2819
2909
|
const total = result.uptoContext?.atomicTotal() ?? 0n;
|
|
@@ -2978,7 +3068,13 @@ async function runStaticRequestFlow(args) {
|
|
|
2978
3068
|
if (result.response.status >= 400) {
|
|
2979
3069
|
const settledScope = settleScope;
|
|
2980
3070
|
await runSettledHandlerError(ctx, settledScope);
|
|
2981
|
-
return finalize(
|
|
3071
|
+
return finalize(
|
|
3072
|
+
ctx,
|
|
3073
|
+
result.response,
|
|
3074
|
+
result.rawResult,
|
|
3075
|
+
body,
|
|
3076
|
+
failureFromCause2(result.handlerError)
|
|
3077
|
+
);
|
|
2982
3078
|
}
|
|
2983
3079
|
return settleAndFinalizeRequest({
|
|
2984
3080
|
ctx,
|
|
@@ -2991,7 +3087,13 @@ async function runStaticRequestFlow(args) {
|
|
|
2991
3087
|
});
|
|
2992
3088
|
}
|
|
2993
3089
|
if (result.response.status >= 400) {
|
|
2994
|
-
return finalize(
|
|
3090
|
+
return finalize(
|
|
3091
|
+
ctx,
|
|
3092
|
+
result.response,
|
|
3093
|
+
result.rawResult,
|
|
3094
|
+
body,
|
|
3095
|
+
failureFromCause2(result.handlerError)
|
|
3096
|
+
);
|
|
2995
3097
|
}
|
|
2996
3098
|
const beforeErr = await runBeforeSettle(ctx, settleScope);
|
|
2997
3099
|
if (beforeErr) return beforeErr;
|
|
@@ -3012,6 +3114,9 @@ async function runStaticRequestFlow(args) {
|
|
|
3012
3114
|
}
|
|
3013
3115
|
});
|
|
3014
3116
|
}
|
|
3117
|
+
function failureFromCause2(cause) {
|
|
3118
|
+
return cause === void 0 ? void 0 : { cause };
|
|
3119
|
+
}
|
|
3015
3120
|
|
|
3016
3121
|
// src/pipeline/flows/static/static-paid.ts
|
|
3017
3122
|
async function runStaticPaidFlow(ctx) {
|
|
@@ -3496,7 +3601,8 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3496
3601
|
providerConfig: void 0,
|
|
3497
3602
|
validateFn: void 0,
|
|
3498
3603
|
settlement: void 0,
|
|
3499
|
-
mppInfo: void 0
|
|
3604
|
+
mppInfo: void 0,
|
|
3605
|
+
hasCheckout: false
|
|
3500
3606
|
};
|
|
3501
3607
|
}
|
|
3502
3608
|
fork() {
|
|
@@ -3587,6 +3693,7 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3587
3693
|
if (resolvedOptions.minPrice) next.#s.minPrice = resolvedOptions.minPrice;
|
|
3588
3694
|
if (resolvedOptions.payTo) next.#s.payTo = resolvedOptions.payTo;
|
|
3589
3695
|
if (resolvedOptions.mpp) next.#s.mppInfo = resolvedOptions.mpp;
|
|
3696
|
+
if (resolvedOptions.checkout) next.#s.hasCheckout = true;
|
|
3590
3697
|
next.#s.billing = billing;
|
|
3591
3698
|
if (tickCost) next.#s.tickCost = tickCost;
|
|
3592
3699
|
if (unitType) next.#s.unitType = unitType;
|
|
@@ -4020,6 +4127,7 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
4020
4127
|
validateFn: this.#s.validateFn,
|
|
4021
4128
|
settlement: this.#s.settlement,
|
|
4022
4129
|
mppInfo: this.#s.mppInfo,
|
|
4130
|
+
hasCheckout: this.#s.hasCheckout ? true : void 0,
|
|
4023
4131
|
tickCost: this.#s.tickCost,
|
|
4024
4132
|
unitType: this.#s.unitType
|
|
4025
4133
|
};
|
|
@@ -4226,6 +4334,7 @@ function buildOperation(routeKey, entry, tag) {
|
|
|
4226
4334
|
const requiresSiwxScheme = entry.authMode === "siwx" || Boolean(entry.siwxEnabled);
|
|
4227
4335
|
const requiresApiKeyScheme = Boolean(entry.apiKeyResolver) && entry.authMode !== "siwx";
|
|
4228
4336
|
const pricingInfo = buildPricingInfo(entry);
|
|
4337
|
+
const hasCheckout = entry.hasCheckout === true;
|
|
4229
4338
|
const operation = {
|
|
4230
4339
|
operationId: routeKey.replace(/\//g, "_"),
|
|
4231
4340
|
summary: entry.description ?? routeKey,
|
|
@@ -4251,10 +4360,11 @@ function buildOperation(routeKey, entry, tag) {
|
|
|
4251
4360
|
}
|
|
4252
4361
|
}
|
|
4253
4362
|
};
|
|
4254
|
-
if (paymentRequired && (pricingInfo || protocols)) {
|
|
4363
|
+
if (paymentRequired && (pricingInfo || protocols || hasCheckout)) {
|
|
4255
4364
|
operation["x-payment-info"] = {
|
|
4256
4365
|
...pricingInfo ?? {},
|
|
4257
|
-
...protocols && { protocols }
|
|
4366
|
+
...protocols && { protocols },
|
|
4367
|
+
...hasCheckout && { has_checkout: true }
|
|
4258
4368
|
};
|
|
4259
4369
|
}
|
|
4260
4370
|
if (requiresSiwxScheme) {
|
package/dist/index.d.cts
CHANGED
|
@@ -77,13 +77,24 @@ interface ResponseMeta {
|
|
|
77
77
|
headers: Record<string, string>;
|
|
78
78
|
/** Parsed request body (when .body() was used). undefined when no body was parsed. */
|
|
79
79
|
requestBody?: unknown;
|
|
80
|
-
/** Handler return value
|
|
80
|
+
/** Handler return value or structured router-generated error body. */
|
|
81
81
|
responseBody?: unknown;
|
|
82
82
|
}
|
|
83
83
|
interface ErrorEvent {
|
|
84
84
|
status: number;
|
|
85
85
|
message: string;
|
|
86
86
|
settled: boolean;
|
|
87
|
+
requestId?: string;
|
|
88
|
+
route?: string;
|
|
89
|
+
method?: string;
|
|
90
|
+
duration?: number;
|
|
91
|
+
walletAddress?: string | null;
|
|
92
|
+
verifiedWallet?: string | null;
|
|
93
|
+
clientId?: string | null;
|
|
94
|
+
sessionId?: string | null;
|
|
95
|
+
errorName?: string;
|
|
96
|
+
stack?: string;
|
|
97
|
+
cause?: unknown;
|
|
87
98
|
}
|
|
88
99
|
interface AuthEvent {
|
|
89
100
|
/** Authentication mode that was verified */
|
|
@@ -216,6 +227,8 @@ interface PaidOptions {
|
|
|
216
227
|
payTo?: PayToConfig;
|
|
217
228
|
/** Override MPP protocol metadata in x-payment-info discovery. */
|
|
218
229
|
mpp?: MppProtocolInfo;
|
|
230
|
+
/** Signal in discovery that clients should use an explicit checkout flow before payment. */
|
|
231
|
+
checkout?: boolean;
|
|
219
232
|
}
|
|
220
233
|
type PaidArg = (PaidOptions & {
|
|
221
234
|
price: string;
|
|
@@ -360,6 +373,7 @@ interface RouteEntry {
|
|
|
360
373
|
validateFn?: (body: unknown) => void | Promise<void>;
|
|
361
374
|
settlement?: SettlementLifecycle;
|
|
362
375
|
mppInfo?: MppProtocolInfo;
|
|
376
|
+
hasCheckout?: boolean;
|
|
363
377
|
/** Per-tick cost (decimal-dollar). Required when `metered` is true. */
|
|
364
378
|
tickCost?: string;
|
|
365
379
|
/** Cosmetic unit label for 402 challenges and client UIs. */
|
|
@@ -543,7 +557,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
|
|
|
543
557
|
* - `{ price }` — fixed price (object form of the string sugar).
|
|
544
558
|
* - `{ field, tiers, default? }` — pick a tier from `body[field]`.
|
|
545
559
|
*
|
|
546
|
-
* Common knobs (`protocols`, `maxPrice`, `minPrice`, `payTo`, `mpp`) live
|
|
560
|
+
* Common knobs (`protocols`, `maxPrice`, `minPrice`, `payTo`, `mpp`, `checkout`) live
|
|
547
561
|
* alongside the pricing shape. For handler-computed billing use `.upTo()`;
|
|
548
562
|
* for per-tick billing use `.metered()`.
|
|
549
563
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -77,13 +77,24 @@ interface ResponseMeta {
|
|
|
77
77
|
headers: Record<string, string>;
|
|
78
78
|
/** Parsed request body (when .body() was used). undefined when no body was parsed. */
|
|
79
79
|
requestBody?: unknown;
|
|
80
|
-
/** Handler return value
|
|
80
|
+
/** Handler return value or structured router-generated error body. */
|
|
81
81
|
responseBody?: unknown;
|
|
82
82
|
}
|
|
83
83
|
interface ErrorEvent {
|
|
84
84
|
status: number;
|
|
85
85
|
message: string;
|
|
86
86
|
settled: boolean;
|
|
87
|
+
requestId?: string;
|
|
88
|
+
route?: string;
|
|
89
|
+
method?: string;
|
|
90
|
+
duration?: number;
|
|
91
|
+
walletAddress?: string | null;
|
|
92
|
+
verifiedWallet?: string | null;
|
|
93
|
+
clientId?: string | null;
|
|
94
|
+
sessionId?: string | null;
|
|
95
|
+
errorName?: string;
|
|
96
|
+
stack?: string;
|
|
97
|
+
cause?: unknown;
|
|
87
98
|
}
|
|
88
99
|
interface AuthEvent {
|
|
89
100
|
/** Authentication mode that was verified */
|
|
@@ -216,6 +227,8 @@ interface PaidOptions {
|
|
|
216
227
|
payTo?: PayToConfig;
|
|
217
228
|
/** Override MPP protocol metadata in x-payment-info discovery. */
|
|
218
229
|
mpp?: MppProtocolInfo;
|
|
230
|
+
/** Signal in discovery that clients should use an explicit checkout flow before payment. */
|
|
231
|
+
checkout?: boolean;
|
|
219
232
|
}
|
|
220
233
|
type PaidArg = (PaidOptions & {
|
|
221
234
|
price: string;
|
|
@@ -360,6 +373,7 @@ interface RouteEntry {
|
|
|
360
373
|
validateFn?: (body: unknown) => void | Promise<void>;
|
|
361
374
|
settlement?: SettlementLifecycle;
|
|
362
375
|
mppInfo?: MppProtocolInfo;
|
|
376
|
+
hasCheckout?: boolean;
|
|
363
377
|
/** Per-tick cost (decimal-dollar). Required when `metered` is true. */
|
|
364
378
|
tickCost?: string;
|
|
365
379
|
/** Cosmetic unit label for 402 challenges and client UIs. */
|
|
@@ -543,7 +557,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
|
|
|
543
557
|
* - `{ price }` — fixed price (object form of the string sugar).
|
|
544
558
|
* - `{ field, tiers, default? }` — pick a tier from `body[field]`.
|
|
545
559
|
*
|
|
546
|
-
* Common knobs (`protocols`, `maxPrice`, `minPrice`, `payTo`, `mpp`) live
|
|
560
|
+
* Common knobs (`protocols`, `maxPrice`, `minPrice`, `payTo`, `mpp`, `checkout`) live
|
|
547
561
|
* alongside the pricing shape. For handler-computed billing use `.upTo()`;
|
|
548
562
|
* for per-tick billing use `.metered()`.
|
|
549
563
|
*
|
package/dist/index.js
CHANGED
|
@@ -499,7 +499,8 @@ var HEADERS = {
|
|
|
499
499
|
X402_PAYMENT_LEGACY: "X-PAYMENT",
|
|
500
500
|
X402_PAYMENT_REQUIRED: "PAYMENT-REQUIRED",
|
|
501
501
|
X402_PAYMENT_RESPONSE: "PAYMENT-RESPONSE",
|
|
502
|
-
MPP_PAYMENT_RECEIPT: "Payment-Receipt"
|
|
502
|
+
MPP_PAYMENT_RECEIPT: "Payment-Receipt",
|
|
503
|
+
REQUEST_ID: "X-Request-ID"
|
|
503
504
|
};
|
|
504
505
|
var AUTH_SCHEME = {
|
|
505
506
|
BEARER: "Bearer ",
|
|
@@ -529,19 +530,19 @@ function firePluginHook(plugin, method, ...args) {
|
|
|
529
530
|
const result = fn.apply(plugin, args);
|
|
530
531
|
if (result && typeof result.catch === "function") {
|
|
531
532
|
result.catch((error) => {
|
|
532
|
-
console.error(
|
|
533
|
-
`[router] ERROR ${method}: ${error instanceof Error ? error.message : String(error)}`
|
|
534
|
-
);
|
|
533
|
+
console.error(`[router] ERROR ${method}: ${formatUnknownError(error)}`);
|
|
535
534
|
});
|
|
536
535
|
}
|
|
537
536
|
return result;
|
|
538
537
|
} catch (error) {
|
|
539
|
-
console.error(
|
|
540
|
-
`[router] ERROR ${method}: ${error instanceof Error ? error.message : String(error)}`
|
|
541
|
-
);
|
|
538
|
+
console.error(`[router] ERROR ${method}: ${formatUnknownError(error)}`);
|
|
542
539
|
return void 0;
|
|
543
540
|
}
|
|
544
541
|
}
|
|
542
|
+
function formatUnknownError(error) {
|
|
543
|
+
if (error instanceof Error) return error.stack ?? error.message;
|
|
544
|
+
return String(error);
|
|
545
|
+
}
|
|
545
546
|
|
|
546
547
|
// src/plugin/reporter.ts
|
|
547
548
|
function createReporter(plugin, pluginCtx, route) {
|
|
@@ -632,7 +633,8 @@ function firePaymentVerified(ctx, event) {
|
|
|
632
633
|
function firePaymentSettled(ctx, event) {
|
|
633
634
|
firePluginHook(ctx.deps.plugin, "onPaymentSettled", ctx.pluginCtx, event);
|
|
634
635
|
}
|
|
635
|
-
function firePluginResponse(ctx, response, requestBody, responseBody) {
|
|
636
|
+
function firePluginResponse(ctx, response, requestBody, responseBody, failure) {
|
|
637
|
+
attachRequestId(response, ctx.meta.requestId);
|
|
636
638
|
firePluginHook(ctx.deps.plugin, "onResponse", ctx.pluginCtx, {
|
|
637
639
|
statusCode: response.status,
|
|
638
640
|
statusText: response.statusText,
|
|
@@ -643,11 +645,9 @@ function firePluginResponse(ctx, response, requestBody, responseBody) {
|
|
|
643
645
|
responseBody
|
|
644
646
|
});
|
|
645
647
|
if (response.status >= 400 && response.status !== 402) {
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
settled: false
|
|
650
|
-
});
|
|
648
|
+
const error = buildErrorEvent(ctx, response, failure);
|
|
649
|
+
if (response.status >= 500) logRouterFailure(error);
|
|
650
|
+
firePluginHook(ctx.deps.plugin, "onError", ctx.pluginCtx, error);
|
|
651
651
|
}
|
|
652
652
|
}
|
|
653
653
|
function fireProviderQuota(ctx, response, handlerResult) {
|
|
@@ -679,6 +679,67 @@ function computeQuotaLevel(remaining, warn, critical) {
|
|
|
679
679
|
if (warn !== void 0 && remaining <= warn) return "warn";
|
|
680
680
|
return "healthy";
|
|
681
681
|
}
|
|
682
|
+
function attachRequestId(response, requestId) {
|
|
683
|
+
try {
|
|
684
|
+
if (!response.headers.has(HEADERS.REQUEST_ID)) {
|
|
685
|
+
response.headers.set(HEADERS.REQUEST_ID, requestId);
|
|
686
|
+
}
|
|
687
|
+
} catch {
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
function buildErrorEvent(ctx, response, failure) {
|
|
691
|
+
const error = errorDetails(failure?.cause);
|
|
692
|
+
const responseMessage = response.statusText || `HTTP ${response.status}`;
|
|
693
|
+
const message = failure?.message ?? error.message ?? responseMessage;
|
|
694
|
+
return {
|
|
695
|
+
status: response.status,
|
|
696
|
+
message,
|
|
697
|
+
settled: failure?.settled ?? false,
|
|
698
|
+
requestId: ctx.meta.requestId,
|
|
699
|
+
route: ctx.meta.route,
|
|
700
|
+
method: ctx.meta.method,
|
|
701
|
+
duration: Date.now() - ctx.meta.startTime,
|
|
702
|
+
walletAddress: ctx.meta.walletAddress,
|
|
703
|
+
verifiedWallet: ctx.pluginCtx.verifiedWallet,
|
|
704
|
+
clientId: ctx.meta.clientId,
|
|
705
|
+
sessionId: ctx.meta.sessionId,
|
|
706
|
+
errorName: error.name,
|
|
707
|
+
stack: error.stack,
|
|
708
|
+
cause: failure?.cause
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
function errorDetails(error) {
|
|
712
|
+
if (error instanceof Error) {
|
|
713
|
+
return {
|
|
714
|
+
message: error.message,
|
|
715
|
+
name: error.name,
|
|
716
|
+
stack: error.stack
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
if (typeof error === "object" && error !== null) {
|
|
720
|
+
const record = error;
|
|
721
|
+
return {
|
|
722
|
+
message: typeof record.message === "string" ? record.message : void 0,
|
|
723
|
+
name: typeof record.name === "string" ? record.name : void 0,
|
|
724
|
+
stack: typeof record.stack === "string" ? record.stack : void 0
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
if (typeof error === "string") return { message: error };
|
|
728
|
+
return {};
|
|
729
|
+
}
|
|
730
|
+
function logRouterFailure(error) {
|
|
731
|
+
console.error(`[router] ERROR ${error.route ?? "unknown"} ${error.status}: ${error.message}`, {
|
|
732
|
+
requestId: error.requestId,
|
|
733
|
+
method: error.method,
|
|
734
|
+
duration: error.duration,
|
|
735
|
+
walletAddress: error.walletAddress,
|
|
736
|
+
verifiedWallet: error.verifiedWallet,
|
|
737
|
+
clientId: error.clientId,
|
|
738
|
+
sessionId: error.sessionId,
|
|
739
|
+
errorName: error.errorName,
|
|
740
|
+
stack: error.stack
|
|
741
|
+
});
|
|
742
|
+
}
|
|
682
743
|
|
|
683
744
|
// src/pipeline/steps/parse-body.ts
|
|
684
745
|
async function parseBody(ctx, request = ctx.request) {
|
|
@@ -688,20 +749,19 @@ async function parseBody(ctx, request = ctx.request) {
|
|
|
688
749
|
raw = await bufferBody(request);
|
|
689
750
|
} catch (err) {
|
|
690
751
|
if (!(err instanceof MalformedJsonError)) throw err;
|
|
691
|
-
const
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
752
|
+
const responseBody2 = { success: false, error: "Invalid JSON", issues: [] };
|
|
753
|
+
const response2 = NextResponse.json(responseBody2, { status: 400 });
|
|
754
|
+
firePluginResponse(ctx, response2, void 0, responseBody2, {
|
|
755
|
+
message: responseBody2.error,
|
|
756
|
+
cause: err
|
|
757
|
+
});
|
|
696
758
|
return { ok: false, response: response2 };
|
|
697
759
|
}
|
|
698
760
|
const result = validateBody(raw, ctx.routeEntry.bodySchema);
|
|
699
761
|
if (result.success) return { ok: true, data: result.data };
|
|
700
|
-
const
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
);
|
|
704
|
-
firePluginResponse(ctx, response);
|
|
762
|
+
const responseBody = { success: false, error: result.error, issues: result.issues };
|
|
763
|
+
const response = NextResponse.json(responseBody, { status: 400 });
|
|
764
|
+
firePluginResponse(ctx, response, raw, responseBody, { message: result.error });
|
|
705
765
|
return { ok: false, response };
|
|
706
766
|
}
|
|
707
767
|
|
|
@@ -713,11 +773,9 @@ function validateQuery(ctx) {
|
|
|
713
773
|
const params = Object.fromEntries(ctx.request.nextUrl.searchParams.entries());
|
|
714
774
|
const result = validateBody(params, querySchema);
|
|
715
775
|
if (result.success) return { ok: true, data: result.data };
|
|
716
|
-
const
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
);
|
|
720
|
-
firePluginResponse(ctx, response);
|
|
776
|
+
const responseBody = { success: false, error: result.error, issues: result.issues };
|
|
777
|
+
const response = NextResponse2.json(responseBody, { status: 400 });
|
|
778
|
+
firePluginResponse(ctx, response, params, responseBody, { message: result.error });
|
|
721
779
|
return { ok: false, response };
|
|
722
780
|
}
|
|
723
781
|
|
|
@@ -736,9 +794,13 @@ function handlerFailureError(response) {
|
|
|
736
794
|
|
|
737
795
|
// src/pipeline/steps/fail.ts
|
|
738
796
|
import { NextResponse as NextResponse3 } from "next/server";
|
|
739
|
-
function fail(ctx, status, message, requestBody) {
|
|
740
|
-
const
|
|
741
|
-
|
|
797
|
+
function fail(ctx, status, message, requestBody, failure) {
|
|
798
|
+
const responseBody = { success: false, error: message };
|
|
799
|
+
const response = NextResponse3.json(responseBody, { status });
|
|
800
|
+
firePluginResponse(ctx, response, requestBody, responseBody, {
|
|
801
|
+
...failure,
|
|
802
|
+
message: failure?.message ?? message
|
|
803
|
+
});
|
|
742
804
|
return response;
|
|
743
805
|
}
|
|
744
806
|
|
|
@@ -814,9 +876,10 @@ async function runHandler(ctx, handlerCtx) {
|
|
|
814
876
|
function errorResult(error) {
|
|
815
877
|
const status = error instanceof HttpError ? error.status : typeof error?.status === "number" ? error.status : 500;
|
|
816
878
|
const message = error instanceof Error ? error.message : "Internal error";
|
|
879
|
+
const responseBody = { success: false, error: message };
|
|
817
880
|
return {
|
|
818
|
-
response: NextResponse4.json(
|
|
819
|
-
rawResult:
|
|
881
|
+
response: NextResponse4.json(responseBody, { status }),
|
|
882
|
+
rawResult: responseBody,
|
|
820
883
|
handlerError: error
|
|
821
884
|
};
|
|
822
885
|
}
|
|
@@ -828,9 +891,9 @@ function isThenable(value) {
|
|
|
828
891
|
}
|
|
829
892
|
|
|
830
893
|
// src/pipeline/steps/finalize/response.ts
|
|
831
|
-
function finalize(ctx, response, rawResult, requestBody) {
|
|
894
|
+
function finalize(ctx, response, rawResult, requestBody, failure) {
|
|
832
895
|
fireProviderQuota(ctx, response, rawResult);
|
|
833
|
-
firePluginResponse(ctx, response, requestBody, rawResult);
|
|
896
|
+
firePluginResponse(ctx, response, requestBody, rawResult, failure);
|
|
834
897
|
return response;
|
|
835
898
|
}
|
|
836
899
|
|
|
@@ -916,7 +979,9 @@ async function settleAndFinalizeRequest(args) {
|
|
|
916
979
|
});
|
|
917
980
|
if (!settle.ok) {
|
|
918
981
|
if (onSettleError) await onSettleError(settle.error, settle.failMessage);
|
|
919
|
-
return fail(ctx, settle.failStatus ?? 500, settle.failMessage, body
|
|
982
|
+
return fail(ctx, settle.failStatus ?? 500, settle.failMessage, body, {
|
|
983
|
+
cause: settle.error
|
|
984
|
+
});
|
|
920
985
|
}
|
|
921
986
|
return runPostSettleEpilogue({
|
|
922
987
|
ctx,
|
|
@@ -951,7 +1016,9 @@ async function settleAndFinalizeStream(args) {
|
|
|
951
1016
|
report
|
|
952
1017
|
});
|
|
953
1018
|
if (!settle.ok) {
|
|
954
|
-
return fail(ctx, settle.failStatus ?? 500, settle.failMessage, body
|
|
1019
|
+
return fail(ctx, settle.failStatus ?? 500, settle.failMessage, body, {
|
|
1020
|
+
cause: settle.error
|
|
1021
|
+
});
|
|
955
1022
|
}
|
|
956
1023
|
return runPostSettleEpilogue({
|
|
957
1024
|
ctx,
|
|
@@ -978,7 +1045,13 @@ async function runHandlerOnly(ctx, wallet, account) {
|
|
|
978
1045
|
const validateErr = await runValidate(ctx, body.data);
|
|
979
1046
|
if (validateErr) return validateErr;
|
|
980
1047
|
const result = await invokeUnauthed(ctx, wallet, account, body.data);
|
|
981
|
-
return finalize(
|
|
1048
|
+
return finalize(
|
|
1049
|
+
ctx,
|
|
1050
|
+
result.response,
|
|
1051
|
+
result.rawResult,
|
|
1052
|
+
body.data,
|
|
1053
|
+
result.handlerError === void 0 ? void 0 : { cause: result.handlerError }
|
|
1054
|
+
);
|
|
982
1055
|
}
|
|
983
1056
|
|
|
984
1057
|
// src/pipeline/steps/run-before-settle.ts
|
|
@@ -1991,6 +2064,7 @@ function invalidPaymentVerification(failure) {
|
|
|
1991
2064
|
}
|
|
1992
2065
|
|
|
1993
2066
|
// src/protocols/x402/strategy.ts
|
|
2067
|
+
var SETTLE_RETRY_DELAYS_MS = [500, 1e3];
|
|
1994
2068
|
function formatVerifyFailureMessage(failure) {
|
|
1995
2069
|
if (failure.reason === "permit2_allowance_required") {
|
|
1996
2070
|
const wallet = failure.payer ?? "<the payer wallet>";
|
|
@@ -2081,7 +2155,17 @@ async function settleX402(args) {
|
|
|
2081
2155
|
const { payload, requirements } = token;
|
|
2082
2156
|
const override = routeEntry.billing === "exact" ? void 0 : { amount: billedAmount };
|
|
2083
2157
|
try {
|
|
2084
|
-
|
|
2158
|
+
let settle = await settleX402Payment(deps.x402Server, payload, requirements, override);
|
|
2159
|
+
for (let attempt = 0; !settle.result?.success && attempt < SETTLE_RETRY_DELAYS_MS.length; attempt++) {
|
|
2160
|
+
report("warn", "Retrying x402 settlement", {
|
|
2161
|
+
attempt: attempt + 1,
|
|
2162
|
+
errorReason: settle.result?.errorReason
|
|
2163
|
+
});
|
|
2164
|
+
await new Promise((resolve) => {
|
|
2165
|
+
setTimeout(resolve, SETTLE_RETRY_DELAYS_MS[attempt]);
|
|
2166
|
+
});
|
|
2167
|
+
settle = await settleX402Payment(deps.x402Server, payload, requirements, override);
|
|
2168
|
+
}
|
|
2085
2169
|
if (!settle.result?.success) {
|
|
2086
2170
|
throw Object.assign(
|
|
2087
2171
|
new Error(settle.result?.errorReason ?? "x402 settlement returned success=false"),
|
|
@@ -2417,11 +2501,9 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
|
|
|
2417
2501
|
challengePrice = pricing ? await pricing.challengeQuote(body) : "0";
|
|
2418
2502
|
} catch (err) {
|
|
2419
2503
|
const message = errorMessage(err, "Price calculation failed");
|
|
2420
|
-
const
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
);
|
|
2424
|
-
firePluginResponse(ctx, errorResponse);
|
|
2504
|
+
const responseBody2 = { success: false, error: message };
|
|
2505
|
+
const errorResponse = NextResponse5.json(responseBody2, { status: errorStatus(err, 500) });
|
|
2506
|
+
firePluginResponse(ctx, errorResponse, body, responseBody2, { message, cause: err });
|
|
2425
2507
|
return errorResponse;
|
|
2426
2508
|
}
|
|
2427
2509
|
const extensions = await buildChallengeExtensions(ctx);
|
|
@@ -2453,11 +2535,9 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
|
|
|
2453
2535
|
const message = `${strategy.protocol} challenge build failed: ${errorMessage(err, String(err))}`;
|
|
2454
2536
|
ctx.report("critical", message);
|
|
2455
2537
|
if (strategy.protocol === "x402") {
|
|
2456
|
-
const
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
);
|
|
2460
|
-
firePluginResponse(ctx, errorResponse);
|
|
2538
|
+
const responseBody2 = { success: false, error: message };
|
|
2539
|
+
const errorResponse = NextResponse5.json(responseBody2, { status: 500 });
|
|
2540
|
+
firePluginResponse(ctx, errorResponse, body, responseBody2, { message, cause: err });
|
|
2461
2541
|
return errorResponse;
|
|
2462
2542
|
}
|
|
2463
2543
|
}
|
|
@@ -2616,10 +2696,11 @@ function toResponse(rawResult) {
|
|
|
2616
2696
|
function errorResult2(error) {
|
|
2617
2697
|
const status = error instanceof HttpError ? error.status : typeof error?.status === "number" ? error.status : 500;
|
|
2618
2698
|
const message = error instanceof Error ? error.message : "Internal error";
|
|
2699
|
+
const responseBody = { success: false, error: message };
|
|
2619
2700
|
return {
|
|
2620
2701
|
kind: "request",
|
|
2621
|
-
response: NextResponse7.json(
|
|
2622
|
-
rawResult:
|
|
2702
|
+
response: NextResponse7.json(responseBody, { status }),
|
|
2703
|
+
rawResult: responseBody,
|
|
2623
2704
|
handlerError: error
|
|
2624
2705
|
};
|
|
2625
2706
|
}
|
|
@@ -2750,7 +2831,13 @@ async function runDynamicRequestFlow(args) {
|
|
|
2750
2831
|
handlerError: result.handlerError
|
|
2751
2832
|
};
|
|
2752
2833
|
if (result.response.status >= 400) {
|
|
2753
|
-
return finalize(
|
|
2834
|
+
return finalize(
|
|
2835
|
+
ctx,
|
|
2836
|
+
result.response,
|
|
2837
|
+
result.rawResult,
|
|
2838
|
+
body,
|
|
2839
|
+
failureFromCause(result.handlerError)
|
|
2840
|
+
);
|
|
2754
2841
|
}
|
|
2755
2842
|
const beforeErr = await runBeforeSettle(ctx, settleScope);
|
|
2756
2843
|
if (beforeErr) return beforeErr;
|
|
@@ -2772,6 +2859,9 @@ async function runDynamicRequestFlow(args) {
|
|
|
2772
2859
|
}
|
|
2773
2860
|
});
|
|
2774
2861
|
}
|
|
2862
|
+
function failureFromCause(cause) {
|
|
2863
|
+
return cause === void 0 ? void 0 : { cause };
|
|
2864
|
+
}
|
|
2775
2865
|
function computeBilledAmount(routeEntry, result) {
|
|
2776
2866
|
if (routeEntry.billing === "upto") {
|
|
2777
2867
|
const total = result.uptoContext?.atomicTotal() ?? 0n;
|
|
@@ -2936,7 +3026,13 @@ async function runStaticRequestFlow(args) {
|
|
|
2936
3026
|
if (result.response.status >= 400) {
|
|
2937
3027
|
const settledScope = settleScope;
|
|
2938
3028
|
await runSettledHandlerError(ctx, settledScope);
|
|
2939
|
-
return finalize(
|
|
3029
|
+
return finalize(
|
|
3030
|
+
ctx,
|
|
3031
|
+
result.response,
|
|
3032
|
+
result.rawResult,
|
|
3033
|
+
body,
|
|
3034
|
+
failureFromCause2(result.handlerError)
|
|
3035
|
+
);
|
|
2940
3036
|
}
|
|
2941
3037
|
return settleAndFinalizeRequest({
|
|
2942
3038
|
ctx,
|
|
@@ -2949,7 +3045,13 @@ async function runStaticRequestFlow(args) {
|
|
|
2949
3045
|
});
|
|
2950
3046
|
}
|
|
2951
3047
|
if (result.response.status >= 400) {
|
|
2952
|
-
return finalize(
|
|
3048
|
+
return finalize(
|
|
3049
|
+
ctx,
|
|
3050
|
+
result.response,
|
|
3051
|
+
result.rawResult,
|
|
3052
|
+
body,
|
|
3053
|
+
failureFromCause2(result.handlerError)
|
|
3054
|
+
);
|
|
2953
3055
|
}
|
|
2954
3056
|
const beforeErr = await runBeforeSettle(ctx, settleScope);
|
|
2955
3057
|
if (beforeErr) return beforeErr;
|
|
@@ -2970,6 +3072,9 @@ async function runStaticRequestFlow(args) {
|
|
|
2970
3072
|
}
|
|
2971
3073
|
});
|
|
2972
3074
|
}
|
|
3075
|
+
function failureFromCause2(cause) {
|
|
3076
|
+
return cause === void 0 ? void 0 : { cause };
|
|
3077
|
+
}
|
|
2973
3078
|
|
|
2974
3079
|
// src/pipeline/flows/static/static-paid.ts
|
|
2975
3080
|
async function runStaticPaidFlow(ctx) {
|
|
@@ -3454,7 +3559,8 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3454
3559
|
providerConfig: void 0,
|
|
3455
3560
|
validateFn: void 0,
|
|
3456
3561
|
settlement: void 0,
|
|
3457
|
-
mppInfo: void 0
|
|
3562
|
+
mppInfo: void 0,
|
|
3563
|
+
hasCheckout: false
|
|
3458
3564
|
};
|
|
3459
3565
|
}
|
|
3460
3566
|
fork() {
|
|
@@ -3545,6 +3651,7 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3545
3651
|
if (resolvedOptions.minPrice) next.#s.minPrice = resolvedOptions.minPrice;
|
|
3546
3652
|
if (resolvedOptions.payTo) next.#s.payTo = resolvedOptions.payTo;
|
|
3547
3653
|
if (resolvedOptions.mpp) next.#s.mppInfo = resolvedOptions.mpp;
|
|
3654
|
+
if (resolvedOptions.checkout) next.#s.hasCheckout = true;
|
|
3548
3655
|
next.#s.billing = billing;
|
|
3549
3656
|
if (tickCost) next.#s.tickCost = tickCost;
|
|
3550
3657
|
if (unitType) next.#s.unitType = unitType;
|
|
@@ -3978,6 +4085,7 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3978
4085
|
validateFn: this.#s.validateFn,
|
|
3979
4086
|
settlement: this.#s.settlement,
|
|
3980
4087
|
mppInfo: this.#s.mppInfo,
|
|
4088
|
+
hasCheckout: this.#s.hasCheckout ? true : void 0,
|
|
3981
4089
|
tickCost: this.#s.tickCost,
|
|
3982
4090
|
unitType: this.#s.unitType
|
|
3983
4091
|
};
|
|
@@ -4184,6 +4292,7 @@ function buildOperation(routeKey, entry, tag) {
|
|
|
4184
4292
|
const requiresSiwxScheme = entry.authMode === "siwx" || Boolean(entry.siwxEnabled);
|
|
4185
4293
|
const requiresApiKeyScheme = Boolean(entry.apiKeyResolver) && entry.authMode !== "siwx";
|
|
4186
4294
|
const pricingInfo = buildPricingInfo(entry);
|
|
4295
|
+
const hasCheckout = entry.hasCheckout === true;
|
|
4187
4296
|
const operation = {
|
|
4188
4297
|
operationId: routeKey.replace(/\//g, "_"),
|
|
4189
4298
|
summary: entry.description ?? routeKey,
|
|
@@ -4209,10 +4318,11 @@ function buildOperation(routeKey, entry, tag) {
|
|
|
4209
4318
|
}
|
|
4210
4319
|
}
|
|
4211
4320
|
};
|
|
4212
|
-
if (paymentRequired && (pricingInfo || protocols)) {
|
|
4321
|
+
if (paymentRequired && (pricingInfo || protocols || hasCheckout)) {
|
|
4213
4322
|
operation["x-payment-info"] = {
|
|
4214
4323
|
...pricingInfo ?? {},
|
|
4215
|
-
...protocols && { protocols }
|
|
4324
|
+
...protocols && { protocols },
|
|
4325
|
+
...hasCheckout && { has_checkout: true }
|
|
4216
4326
|
};
|
|
4217
4327
|
}
|
|
4218
4328
|
if (requiresSiwxScheme) {
|