@agentcash/router 1.10.3 → 1.10.4
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 +147 -53
- package/dist/index.d.cts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +147 -53
- 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
|
|
@@ -2459,11 +2532,9 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
|
|
|
2459
2532
|
challengePrice = pricing ? await pricing.challengeQuote(body) : "0";
|
|
2460
2533
|
} catch (err) {
|
|
2461
2534
|
const message = errorMessage(err, "Price calculation failed");
|
|
2462
|
-
const
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
);
|
|
2466
|
-
firePluginResponse(ctx, errorResponse);
|
|
2535
|
+
const responseBody2 = { success: false, error: message };
|
|
2536
|
+
const errorResponse = import_server5.NextResponse.json(responseBody2, { status: errorStatus(err, 500) });
|
|
2537
|
+
firePluginResponse(ctx, errorResponse, body, responseBody2, { message, cause: err });
|
|
2467
2538
|
return errorResponse;
|
|
2468
2539
|
}
|
|
2469
2540
|
const extensions = await buildChallengeExtensions(ctx);
|
|
@@ -2495,11 +2566,9 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
|
|
|
2495
2566
|
const message = `${strategy.protocol} challenge build failed: ${errorMessage(err, String(err))}`;
|
|
2496
2567
|
ctx.report("critical", message);
|
|
2497
2568
|
if (strategy.protocol === "x402") {
|
|
2498
|
-
const
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
);
|
|
2502
|
-
firePluginResponse(ctx, errorResponse);
|
|
2569
|
+
const responseBody2 = { success: false, error: message };
|
|
2570
|
+
const errorResponse = import_server5.NextResponse.json(responseBody2, { status: 500 });
|
|
2571
|
+
firePluginResponse(ctx, errorResponse, body, responseBody2, { message, cause: err });
|
|
2503
2572
|
return errorResponse;
|
|
2504
2573
|
}
|
|
2505
2574
|
}
|
|
@@ -2658,10 +2727,11 @@ function toResponse(rawResult) {
|
|
|
2658
2727
|
function errorResult2(error) {
|
|
2659
2728
|
const status = error instanceof HttpError ? error.status : typeof error?.status === "number" ? error.status : 500;
|
|
2660
2729
|
const message = error instanceof Error ? error.message : "Internal error";
|
|
2730
|
+
const responseBody = { success: false, error: message };
|
|
2661
2731
|
return {
|
|
2662
2732
|
kind: "request",
|
|
2663
|
-
response: import_server7.NextResponse.json(
|
|
2664
|
-
rawResult:
|
|
2733
|
+
response: import_server7.NextResponse.json(responseBody, { status }),
|
|
2734
|
+
rawResult: responseBody,
|
|
2665
2735
|
handlerError: error
|
|
2666
2736
|
};
|
|
2667
2737
|
}
|
|
@@ -2792,7 +2862,13 @@ async function runDynamicRequestFlow(args) {
|
|
|
2792
2862
|
handlerError: result.handlerError
|
|
2793
2863
|
};
|
|
2794
2864
|
if (result.response.status >= 400) {
|
|
2795
|
-
return finalize(
|
|
2865
|
+
return finalize(
|
|
2866
|
+
ctx,
|
|
2867
|
+
result.response,
|
|
2868
|
+
result.rawResult,
|
|
2869
|
+
body,
|
|
2870
|
+
failureFromCause(result.handlerError)
|
|
2871
|
+
);
|
|
2796
2872
|
}
|
|
2797
2873
|
const beforeErr = await runBeforeSettle(ctx, settleScope);
|
|
2798
2874
|
if (beforeErr) return beforeErr;
|
|
@@ -2814,6 +2890,9 @@ async function runDynamicRequestFlow(args) {
|
|
|
2814
2890
|
}
|
|
2815
2891
|
});
|
|
2816
2892
|
}
|
|
2893
|
+
function failureFromCause(cause) {
|
|
2894
|
+
return cause === void 0 ? void 0 : { cause };
|
|
2895
|
+
}
|
|
2817
2896
|
function computeBilledAmount(routeEntry, result) {
|
|
2818
2897
|
if (routeEntry.billing === "upto") {
|
|
2819
2898
|
const total = result.uptoContext?.atomicTotal() ?? 0n;
|
|
@@ -2978,7 +3057,13 @@ async function runStaticRequestFlow(args) {
|
|
|
2978
3057
|
if (result.response.status >= 400) {
|
|
2979
3058
|
const settledScope = settleScope;
|
|
2980
3059
|
await runSettledHandlerError(ctx, settledScope);
|
|
2981
|
-
return finalize(
|
|
3060
|
+
return finalize(
|
|
3061
|
+
ctx,
|
|
3062
|
+
result.response,
|
|
3063
|
+
result.rawResult,
|
|
3064
|
+
body,
|
|
3065
|
+
failureFromCause2(result.handlerError)
|
|
3066
|
+
);
|
|
2982
3067
|
}
|
|
2983
3068
|
return settleAndFinalizeRequest({
|
|
2984
3069
|
ctx,
|
|
@@ -2991,7 +3076,13 @@ async function runStaticRequestFlow(args) {
|
|
|
2991
3076
|
});
|
|
2992
3077
|
}
|
|
2993
3078
|
if (result.response.status >= 400) {
|
|
2994
|
-
return finalize(
|
|
3079
|
+
return finalize(
|
|
3080
|
+
ctx,
|
|
3081
|
+
result.response,
|
|
3082
|
+
result.rawResult,
|
|
3083
|
+
body,
|
|
3084
|
+
failureFromCause2(result.handlerError)
|
|
3085
|
+
);
|
|
2995
3086
|
}
|
|
2996
3087
|
const beforeErr = await runBeforeSettle(ctx, settleScope);
|
|
2997
3088
|
if (beforeErr) return beforeErr;
|
|
@@ -3012,6 +3103,9 @@ async function runStaticRequestFlow(args) {
|
|
|
3012
3103
|
}
|
|
3013
3104
|
});
|
|
3014
3105
|
}
|
|
3106
|
+
function failureFromCause2(cause) {
|
|
3107
|
+
return cause === void 0 ? void 0 : { cause };
|
|
3108
|
+
}
|
|
3015
3109
|
|
|
3016
3110
|
// src/pipeline/flows/static/static-paid.ts
|
|
3017
3111
|
async function runStaticPaidFlow(ctx) {
|
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 */
|
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 */
|
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
|
|
@@ -2417,11 +2490,9 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
|
|
|
2417
2490
|
challengePrice = pricing ? await pricing.challengeQuote(body) : "0";
|
|
2418
2491
|
} catch (err) {
|
|
2419
2492
|
const message = errorMessage(err, "Price calculation failed");
|
|
2420
|
-
const
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
);
|
|
2424
|
-
firePluginResponse(ctx, errorResponse);
|
|
2493
|
+
const responseBody2 = { success: false, error: message };
|
|
2494
|
+
const errorResponse = NextResponse5.json(responseBody2, { status: errorStatus(err, 500) });
|
|
2495
|
+
firePluginResponse(ctx, errorResponse, body, responseBody2, { message, cause: err });
|
|
2425
2496
|
return errorResponse;
|
|
2426
2497
|
}
|
|
2427
2498
|
const extensions = await buildChallengeExtensions(ctx);
|
|
@@ -2453,11 +2524,9 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
|
|
|
2453
2524
|
const message = `${strategy.protocol} challenge build failed: ${errorMessage(err, String(err))}`;
|
|
2454
2525
|
ctx.report("critical", message);
|
|
2455
2526
|
if (strategy.protocol === "x402") {
|
|
2456
|
-
const
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
);
|
|
2460
|
-
firePluginResponse(ctx, errorResponse);
|
|
2527
|
+
const responseBody2 = { success: false, error: message };
|
|
2528
|
+
const errorResponse = NextResponse5.json(responseBody2, { status: 500 });
|
|
2529
|
+
firePluginResponse(ctx, errorResponse, body, responseBody2, { message, cause: err });
|
|
2461
2530
|
return errorResponse;
|
|
2462
2531
|
}
|
|
2463
2532
|
}
|
|
@@ -2616,10 +2685,11 @@ function toResponse(rawResult) {
|
|
|
2616
2685
|
function errorResult2(error) {
|
|
2617
2686
|
const status = error instanceof HttpError ? error.status : typeof error?.status === "number" ? error.status : 500;
|
|
2618
2687
|
const message = error instanceof Error ? error.message : "Internal error";
|
|
2688
|
+
const responseBody = { success: false, error: message };
|
|
2619
2689
|
return {
|
|
2620
2690
|
kind: "request",
|
|
2621
|
-
response: NextResponse7.json(
|
|
2622
|
-
rawResult:
|
|
2691
|
+
response: NextResponse7.json(responseBody, { status }),
|
|
2692
|
+
rawResult: responseBody,
|
|
2623
2693
|
handlerError: error
|
|
2624
2694
|
};
|
|
2625
2695
|
}
|
|
@@ -2750,7 +2820,13 @@ async function runDynamicRequestFlow(args) {
|
|
|
2750
2820
|
handlerError: result.handlerError
|
|
2751
2821
|
};
|
|
2752
2822
|
if (result.response.status >= 400) {
|
|
2753
|
-
return finalize(
|
|
2823
|
+
return finalize(
|
|
2824
|
+
ctx,
|
|
2825
|
+
result.response,
|
|
2826
|
+
result.rawResult,
|
|
2827
|
+
body,
|
|
2828
|
+
failureFromCause(result.handlerError)
|
|
2829
|
+
);
|
|
2754
2830
|
}
|
|
2755
2831
|
const beforeErr = await runBeforeSettle(ctx, settleScope);
|
|
2756
2832
|
if (beforeErr) return beforeErr;
|
|
@@ -2772,6 +2848,9 @@ async function runDynamicRequestFlow(args) {
|
|
|
2772
2848
|
}
|
|
2773
2849
|
});
|
|
2774
2850
|
}
|
|
2851
|
+
function failureFromCause(cause) {
|
|
2852
|
+
return cause === void 0 ? void 0 : { cause };
|
|
2853
|
+
}
|
|
2775
2854
|
function computeBilledAmount(routeEntry, result) {
|
|
2776
2855
|
if (routeEntry.billing === "upto") {
|
|
2777
2856
|
const total = result.uptoContext?.atomicTotal() ?? 0n;
|
|
@@ -2936,7 +3015,13 @@ async function runStaticRequestFlow(args) {
|
|
|
2936
3015
|
if (result.response.status >= 400) {
|
|
2937
3016
|
const settledScope = settleScope;
|
|
2938
3017
|
await runSettledHandlerError(ctx, settledScope);
|
|
2939
|
-
return finalize(
|
|
3018
|
+
return finalize(
|
|
3019
|
+
ctx,
|
|
3020
|
+
result.response,
|
|
3021
|
+
result.rawResult,
|
|
3022
|
+
body,
|
|
3023
|
+
failureFromCause2(result.handlerError)
|
|
3024
|
+
);
|
|
2940
3025
|
}
|
|
2941
3026
|
return settleAndFinalizeRequest({
|
|
2942
3027
|
ctx,
|
|
@@ -2949,7 +3034,13 @@ async function runStaticRequestFlow(args) {
|
|
|
2949
3034
|
});
|
|
2950
3035
|
}
|
|
2951
3036
|
if (result.response.status >= 400) {
|
|
2952
|
-
return finalize(
|
|
3037
|
+
return finalize(
|
|
3038
|
+
ctx,
|
|
3039
|
+
result.response,
|
|
3040
|
+
result.rawResult,
|
|
3041
|
+
body,
|
|
3042
|
+
failureFromCause2(result.handlerError)
|
|
3043
|
+
);
|
|
2953
3044
|
}
|
|
2954
3045
|
const beforeErr = await runBeforeSettle(ctx, settleScope);
|
|
2955
3046
|
if (beforeErr) return beforeErr;
|
|
@@ -2970,6 +3061,9 @@ async function runStaticRequestFlow(args) {
|
|
|
2970
3061
|
}
|
|
2971
3062
|
});
|
|
2972
3063
|
}
|
|
3064
|
+
function failureFromCause2(cause) {
|
|
3065
|
+
return cause === void 0 ? void 0 : { cause };
|
|
3066
|
+
}
|
|
2973
3067
|
|
|
2974
3068
|
// src/pipeline/flows/static/static-paid.ts
|
|
2975
3069
|
async function runStaticPaidFlow(ctx) {
|