@agentcash/router 1.10.5 → 1.10.7
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/README.md +15 -0
- package/dist/index.cjs +236 -38
- package/dist/index.d.cts +28 -3
- package/dist/index.d.ts +28 -3
- package/dist/index.js +238 -36
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -150,6 +150,21 @@ The barrel forces every route module to load before the discovery handler walks
|
|
|
150
150
|
|
|
151
151
|
The `openapi.json` should be hosted at `GET <origin>/openapi.json`.
|
|
152
152
|
|
|
153
|
+
### 4. Unmatched route fallback
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
// app/api/[[...path]]/route.ts
|
|
157
|
+
import { router } from '@/lib/router';
|
|
158
|
+
|
|
159
|
+
export const GET = router.notFound();
|
|
160
|
+
export const POST = router.notFound();
|
|
161
|
+
export const DELETE = router.notFound();
|
|
162
|
+
export const PUT = router.notFound();
|
|
163
|
+
export const PATCH = router.notFound();
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
This catches stale agent calls to API paths that no longer exist and returns a JSON 404 telling the client to rediscover the origin.
|
|
167
|
+
|
|
153
168
|
## Auth modes
|
|
154
169
|
|
|
155
170
|
| Method | Purpose |
|
package/dist/index.cjs
CHANGED
|
@@ -542,7 +542,8 @@ var HEADERS = {
|
|
|
542
542
|
X402_PAYMENT_REQUIRED: "PAYMENT-REQUIRED",
|
|
543
543
|
X402_PAYMENT_RESPONSE: "PAYMENT-RESPONSE",
|
|
544
544
|
MPP_PAYMENT_RECEIPT: "Payment-Receipt",
|
|
545
|
-
REQUEST_ID: "X-Request-ID"
|
|
545
|
+
REQUEST_ID: "X-Request-ID",
|
|
546
|
+
AGENT_IDENTITY: "X-Agent-Identity"
|
|
546
547
|
};
|
|
547
548
|
var AUTH_SCHEME = {
|
|
548
549
|
BEARER: "Bearer ",
|
|
@@ -677,6 +678,7 @@ function firePaymentSettled(ctx, event) {
|
|
|
677
678
|
}
|
|
678
679
|
function firePluginResponse(ctx, response, requestBody, responseBody, failure) {
|
|
679
680
|
attachRequestId(response, ctx.meta.requestId);
|
|
681
|
+
const error = response.status >= 400 && response.status !== 402 ? buildErrorEvent(ctx, response, failure) : void 0;
|
|
680
682
|
firePluginHook(ctx.deps.plugin, "onResponse", ctx.pluginCtx, {
|
|
681
683
|
statusCode: response.status,
|
|
682
684
|
statusText: response.statusText,
|
|
@@ -684,10 +686,10 @@ function firePluginResponse(ctx, response, requestBody, responseBody, failure) {
|
|
|
684
686
|
contentType: response.headers.get("content-type"),
|
|
685
687
|
headers: Object.fromEntries(response.headers.entries()),
|
|
686
688
|
requestBody,
|
|
687
|
-
responseBody
|
|
689
|
+
responseBody,
|
|
690
|
+
error
|
|
688
691
|
});
|
|
689
|
-
if (
|
|
690
|
-
const error = buildErrorEvent(ctx, response, failure);
|
|
692
|
+
if (error) {
|
|
691
693
|
if (response.status >= 500) logRouterFailure(error);
|
|
692
694
|
firePluginHook(ctx.deps.plugin, "onError", ctx.pluginCtx, error);
|
|
693
695
|
}
|
|
@@ -860,6 +862,9 @@ async function runValidate(ctx, body) {
|
|
|
860
862
|
// src/pipeline/flows/static/static-invoke.ts
|
|
861
863
|
var import_server4 = require("next/server");
|
|
862
864
|
|
|
865
|
+
// src/auth/agent-identity.ts
|
|
866
|
+
var import_did_auth_challenge = require("did-auth-challenge");
|
|
867
|
+
|
|
863
868
|
// src/types.ts
|
|
864
869
|
var HttpError = class extends Error {
|
|
865
870
|
constructor(message, status) {
|
|
@@ -869,18 +874,87 @@ var HttpError = class extends Error {
|
|
|
869
874
|
}
|
|
870
875
|
};
|
|
871
876
|
|
|
872
|
-
// src/
|
|
873
|
-
|
|
874
|
-
|
|
877
|
+
// src/auth/agent-identity.ts
|
|
878
|
+
var PROTOCOL_VERSION = 1;
|
|
879
|
+
function base64urlEncode(value) {
|
|
880
|
+
return Buffer.from(JSON.stringify(value)).toString("base64url");
|
|
881
|
+
}
|
|
882
|
+
function base64urlDecode(value) {
|
|
883
|
+
return JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
|
|
884
|
+
}
|
|
885
|
+
function challengeBindings(request) {
|
|
886
|
+
const url = new URL(request.url);
|
|
887
|
+
return { domain: url.hostname, route: url.pathname };
|
|
888
|
+
}
|
|
889
|
+
async function buildAgentIdentityChallengeHeader(request, nonceStore) {
|
|
890
|
+
const bindings = challengeBindings(request);
|
|
891
|
+
const challenge = await (0, import_did_auth_challenge.createChallenge)(bindings, { nonceStore });
|
|
892
|
+
return base64urlEncode({
|
|
893
|
+
v: PROTOCOL_VERSION,
|
|
894
|
+
challenge
|
|
895
|
+
});
|
|
875
896
|
}
|
|
876
|
-
function
|
|
877
|
-
|
|
897
|
+
async function attachAgentIdentityChallenge(response, request, nonceStore) {
|
|
898
|
+
response.headers.set(
|
|
899
|
+
HEADERS.AGENT_IDENTITY,
|
|
900
|
+
await buildAgentIdentityChallengeHeader(request, nonceStore)
|
|
901
|
+
);
|
|
902
|
+
}
|
|
903
|
+
async function resolveActor(request, nonceStore) {
|
|
904
|
+
const header = request.headers.get(HEADERS.AGENT_IDENTITY);
|
|
905
|
+
if (!header) return null;
|
|
906
|
+
let envelope;
|
|
907
|
+
try {
|
|
908
|
+
envelope = base64urlDecode(header);
|
|
909
|
+
} catch {
|
|
910
|
+
throw new HttpError("Malformed X-Agent-Identity header", 401);
|
|
911
|
+
}
|
|
912
|
+
if (envelope.v !== PROTOCOL_VERSION || !envelope.challenge || !envelope.did || !envelope.signature) {
|
|
913
|
+
throw new HttpError("Invalid X-Agent-Identity proof", 401);
|
|
914
|
+
}
|
|
915
|
+
const bindings = challengeBindings(request);
|
|
916
|
+
try {
|
|
917
|
+
await (0, import_did_auth_challenge.verifySignature)({
|
|
918
|
+
did: envelope.did,
|
|
919
|
+
authenticationKey: envelope.authenticationKey,
|
|
920
|
+
challenge: envelope.challenge,
|
|
921
|
+
signature: envelope.signature,
|
|
922
|
+
options: {
|
|
923
|
+
nonceStore,
|
|
924
|
+
expected: bindings
|
|
925
|
+
}
|
|
926
|
+
});
|
|
927
|
+
} catch (err) {
|
|
928
|
+
const message = (0, import_did_auth_challenge.isIdentityError)(err) ? err.code : "Invalid agent identity";
|
|
929
|
+
throw new HttpError(message, 401);
|
|
930
|
+
}
|
|
931
|
+
return envelope.did;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// src/pipeline/flows/static/static-invoke.ts
|
|
935
|
+
async function invokePaidStatic(ctx, wallet, account, body, payment) {
|
|
936
|
+
const actorResult = await resolveActorForHandler(ctx);
|
|
937
|
+
if (actorResult.kind === "error") return actorResult.result;
|
|
938
|
+
return runHandler(ctx, buildHandlerCtx(ctx, wallet, account, body, payment, actorResult.actor));
|
|
939
|
+
}
|
|
940
|
+
async function invokeUnauthed(ctx, wallet, account, body) {
|
|
941
|
+
const actorResult = await resolveActorForHandler(ctx);
|
|
942
|
+
if (actorResult.kind === "error") return actorResult.result;
|
|
943
|
+
const base = buildHandlerCtx(ctx, wallet, account, body, null, actorResult.actor);
|
|
878
944
|
if (ctx.routeEntry.billing !== "upto") return runHandler(ctx, base);
|
|
879
945
|
const uptoCtx = { ...base, charge: async () => {
|
|
880
946
|
} };
|
|
881
947
|
return runHandler(ctx, uptoCtx);
|
|
882
948
|
}
|
|
883
|
-
function
|
|
949
|
+
async function resolveActorForHandler(ctx) {
|
|
950
|
+
try {
|
|
951
|
+
const actor = await resolveActor(ctx.request, ctx.deps.agentIdentityNonceStore);
|
|
952
|
+
return { kind: "ok", actor };
|
|
953
|
+
} catch (error) {
|
|
954
|
+
return { kind: "error", result: errorResult(error) };
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
function buildHandlerCtx(ctx, wallet, account, body, payment, actor) {
|
|
884
958
|
return {
|
|
885
959
|
body,
|
|
886
960
|
query: ctx.query,
|
|
@@ -888,6 +962,7 @@ function buildHandlerCtx(ctx, wallet, account, body, payment) {
|
|
|
888
962
|
requestId: ctx.meta.requestId,
|
|
889
963
|
route: ctx.routeEntry.key,
|
|
890
964
|
wallet,
|
|
965
|
+
actor,
|
|
891
966
|
payment,
|
|
892
967
|
account,
|
|
893
968
|
alert: ctx.report,
|
|
@@ -1207,7 +1282,7 @@ async function trySiwxFastPath(ctx, account) {
|
|
|
1207
1282
|
function shouldParseBodyEarly(incomingStrategy, routeEntry, pricing) {
|
|
1208
1283
|
if (incomingStrategy) return false;
|
|
1209
1284
|
if (!routeEntry.bodySchema) return false;
|
|
1210
|
-
return (pricing?.needsBody ?? false) || !!routeEntry.validateFn;
|
|
1285
|
+
return (pricing?.needsBody ?? false) || !!routeEntry.validateFn || !!routeEntry.checkoutSession;
|
|
1211
1286
|
}
|
|
1212
1287
|
|
|
1213
1288
|
// src/pipeline/steps/resolve-early-body.ts
|
|
@@ -2012,7 +2087,7 @@ function tagBareDecimalAsDollars(amount) {
|
|
|
2012
2087
|
}
|
|
2013
2088
|
|
|
2014
2089
|
// src/protocols/x402/verify.ts
|
|
2015
|
-
var
|
|
2090
|
+
var import_types3 = require("@x402/core/types");
|
|
2016
2091
|
async function verifyX402Payment(opts) {
|
|
2017
2092
|
const { server, request, price, accepts, report } = opts;
|
|
2018
2093
|
const payment = await readPaymentPayload(request);
|
|
@@ -2038,7 +2113,7 @@ async function verifyX402Payment(opts) {
|
|
|
2038
2113
|
try {
|
|
2039
2114
|
verify = await server.verifyPayment(payload, matching);
|
|
2040
2115
|
} catch (err) {
|
|
2041
|
-
if (err instanceof
|
|
2116
|
+
if (err instanceof import_types3.VerifyError && err.statusCode >= 400 && err.statusCode < 500) {
|
|
2042
2117
|
return invalidPaymentVerification({
|
|
2043
2118
|
reason: err.invalidReason ?? "verify_error",
|
|
2044
2119
|
...err.invalidMessage ? { message: err.invalidMessage } : {},
|
|
@@ -2549,30 +2624,37 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
|
|
|
2549
2624
|
return errorResponse;
|
|
2550
2625
|
}
|
|
2551
2626
|
const extensions = await buildChallengeExtensions(ctx);
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
status: 402,
|
|
2555
|
-
headers: {
|
|
2556
|
-
"Content-Type": "application/json",
|
|
2557
|
-
"Cache-Control": "no-store"
|
|
2558
|
-
}
|
|
2559
|
-
});
|
|
2560
|
-
for (const strategy of getAllowedStrategies(ctx.routeEntry.protocols)) {
|
|
2627
|
+
let checkoutSession;
|
|
2628
|
+
if (ctx.routeEntry.checkoutSession) {
|
|
2561
2629
|
try {
|
|
2562
|
-
|
|
2630
|
+
checkoutSession = await ctx.routeEntry.checkoutSession({
|
|
2563
2631
|
request: ctx.request,
|
|
2564
|
-
|
|
2632
|
+
route: ctx.routeEntry.key,
|
|
2565
2633
|
body,
|
|
2566
|
-
price: challengePrice
|
|
2567
|
-
extensions,
|
|
2568
|
-
deps: ctx.deps,
|
|
2569
|
-
report: ctx.report
|
|
2634
|
+
price: challengePrice
|
|
2570
2635
|
});
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
}
|
|
2636
|
+
} catch (err) {
|
|
2637
|
+
const message = errorMessage(err, "Checkout session build failed");
|
|
2638
|
+
const responseBody2 = { success: false, error: message };
|
|
2639
|
+
const errorResponse = import_server5.NextResponse.json(responseBody2, { status: errorStatus(err, 500) });
|
|
2640
|
+
firePluginResponse(ctx, errorResponse, body, responseBody2, { message, cause: err });
|
|
2641
|
+
return errorResponse;
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
const contributions = [];
|
|
2645
|
+
for (const strategy of getAllowedStrategies(ctx.routeEntry.protocols)) {
|
|
2646
|
+
try {
|
|
2647
|
+
contributions.push(
|
|
2648
|
+
await strategy.buildChallenge({
|
|
2649
|
+
request: ctx.request,
|
|
2650
|
+
routeEntry: ctx.routeEntry,
|
|
2651
|
+
body,
|
|
2652
|
+
price: challengePrice,
|
|
2653
|
+
extensions,
|
|
2654
|
+
deps: ctx.deps,
|
|
2655
|
+
report: ctx.report
|
|
2656
|
+
})
|
|
2657
|
+
);
|
|
2576
2658
|
} catch (err) {
|
|
2577
2659
|
const message = `${strategy.protocol} challenge build failed: ${errorMessage(err, String(err))}`;
|
|
2578
2660
|
ctx.report("critical", message);
|
|
@@ -2584,6 +2666,27 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
|
|
|
2584
2666
|
}
|
|
2585
2667
|
}
|
|
2586
2668
|
}
|
|
2669
|
+
const responsePayload = {
|
|
2670
|
+
...Object.assign({}, ...contributions.map((contribution) => contribution.body ?? {})),
|
|
2671
|
+
...failure && { error: failure.message ?? null, reason: failure.reason },
|
|
2672
|
+
...checkoutSession && { checkout_session: checkoutSession }
|
|
2673
|
+
};
|
|
2674
|
+
const responseBody = Object.keys(responsePayload).length ? JSON.stringify(responsePayload) : null;
|
|
2675
|
+
const response = new import_server5.NextResponse(responseBody, {
|
|
2676
|
+
status: 402,
|
|
2677
|
+
headers: {
|
|
2678
|
+
"Content-Type": "application/json",
|
|
2679
|
+
"Cache-Control": "no-store"
|
|
2680
|
+
}
|
|
2681
|
+
});
|
|
2682
|
+
for (const contribution of contributions) {
|
|
2683
|
+
if (contribution.headers) {
|
|
2684
|
+
for (const [name, value] of Object.entries(contribution.headers)) {
|
|
2685
|
+
response.headers.set(name, value);
|
|
2686
|
+
}
|
|
2687
|
+
}
|
|
2688
|
+
}
|
|
2689
|
+
await attachAgentIdentityChallenge(response, ctx.request, ctx.deps.agentIdentityNonceStore);
|
|
2587
2690
|
firePluginResponse(ctx, response);
|
|
2588
2691
|
return response;
|
|
2589
2692
|
}
|
|
@@ -2718,7 +2821,7 @@ function createChargeContext(args) {
|
|
|
2718
2821
|
|
|
2719
2822
|
// src/pipeline/flows/dynamic/dynamic-invoke/shared.ts
|
|
2720
2823
|
var import_server7 = require("next/server");
|
|
2721
|
-
function buildBaseHandlerCtx(ctx, wallet, account, body, payment) {
|
|
2824
|
+
function buildBaseHandlerCtx(ctx, wallet, account, body, payment, actor = null) {
|
|
2722
2825
|
return {
|
|
2723
2826
|
body,
|
|
2724
2827
|
query: ctx.query,
|
|
@@ -2726,12 +2829,21 @@ function buildBaseHandlerCtx(ctx, wallet, account, body, payment) {
|
|
|
2726
2829
|
requestId: ctx.meta.requestId,
|
|
2727
2830
|
route: ctx.routeEntry.key,
|
|
2728
2831
|
wallet,
|
|
2832
|
+
actor,
|
|
2729
2833
|
payment,
|
|
2730
2834
|
account,
|
|
2731
2835
|
alert: ctx.report,
|
|
2732
2836
|
setVerifiedWallet: (addr) => ctx.pluginCtx.setVerifiedWallet(addr)
|
|
2733
2837
|
};
|
|
2734
2838
|
}
|
|
2839
|
+
async function resolveActorOrError(ctx) {
|
|
2840
|
+
try {
|
|
2841
|
+
const actor = await resolveActor(ctx.request, ctx.deps.agentIdentityNonceStore);
|
|
2842
|
+
return { actor };
|
|
2843
|
+
} catch (error) {
|
|
2844
|
+
return errorResult2(error);
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2735
2847
|
function toResponse(rawResult) {
|
|
2736
2848
|
return rawResult instanceof Response ? rawResult : import_server7.NextResponse.json(rawResult);
|
|
2737
2849
|
}
|
|
@@ -2755,12 +2867,21 @@ function isThenable2(value) {
|
|
|
2755
2867
|
|
|
2756
2868
|
// src/pipeline/flows/dynamic/dynamic-invoke/metered-invoke.ts
|
|
2757
2869
|
async function invokeMetered(ctx, wallet, account, body, payment) {
|
|
2870
|
+
const actorResult = await resolveActorOrError(ctx);
|
|
2871
|
+
if ("response" in actorResult) return actorResult;
|
|
2758
2872
|
const chargeContext = ctx.routeEntry.streaming ? createChargeContext({
|
|
2759
2873
|
tickCost: ctx.routeEntry.tickCost,
|
|
2760
2874
|
maxPrice: ctx.routeEntry.maxPrice,
|
|
2761
2875
|
route: ctx.routeEntry.key
|
|
2762
2876
|
}) : null;
|
|
2763
|
-
const baseHandlerCtx = buildBaseHandlerCtx(
|
|
2877
|
+
const baseHandlerCtx = buildBaseHandlerCtx(
|
|
2878
|
+
ctx,
|
|
2879
|
+
wallet,
|
|
2880
|
+
account,
|
|
2881
|
+
body,
|
|
2882
|
+
payment,
|
|
2883
|
+
actorResult.actor
|
|
2884
|
+
);
|
|
2764
2885
|
const handlerCtx = chargeContext !== null ? { ...baseHandlerCtx, charge: chargeContext.charge } : baseHandlerCtx;
|
|
2765
2886
|
let returned;
|
|
2766
2887
|
try {
|
|
@@ -2819,12 +2940,14 @@ function createUptoChargeContext(args) {
|
|
|
2819
2940
|
|
|
2820
2941
|
// src/pipeline/flows/dynamic/dynamic-invoke/upto-invoke.ts
|
|
2821
2942
|
async function invokeUpto(ctx, wallet, account, body, payment) {
|
|
2943
|
+
const actorResult = await resolveActorOrError(ctx);
|
|
2944
|
+
if ("response" in actorResult) return actorResult;
|
|
2822
2945
|
const uptoCtx = createUptoChargeContext({
|
|
2823
2946
|
maxPrice: ctx.routeEntry.maxPrice,
|
|
2824
2947
|
route: ctx.routeEntry.key
|
|
2825
2948
|
});
|
|
2826
2949
|
const handlerCtx = {
|
|
2827
|
-
...buildBaseHandlerCtx(ctx, wallet, account, body, payment),
|
|
2950
|
+
...buildBaseHandlerCtx(ctx, wallet, account, body, payment, actorResult.actor),
|
|
2828
2951
|
charge: uptoCtx.charge
|
|
2829
2952
|
};
|
|
2830
2953
|
let returned;
|
|
@@ -3357,6 +3480,45 @@ async function createKvMppStore(kv, options) {
|
|
|
3357
3480
|
});
|
|
3358
3481
|
}
|
|
3359
3482
|
|
|
3483
|
+
// src/kv-store/agent-identity-nonce.ts
|
|
3484
|
+
var import_did_auth_challenge2 = require("did-auth-challenge");
|
|
3485
|
+
function createKvAgentIdentityNonceStore(kv, options) {
|
|
3486
|
+
const prefix = options?.prefix ?? "actor:nonce:";
|
|
3487
|
+
return {
|
|
3488
|
+
async add(nonce, expiresAt, challengeJson) {
|
|
3489
|
+
const ttl = Math.max(1, Math.ceil((expiresAt.getTime() - Date.now()) / 1e3));
|
|
3490
|
+
const record = { challengeJson, expiresAt: expiresAt.getTime() };
|
|
3491
|
+
await kv.setNxEx(`${prefix}${nonce}`, record, ttl);
|
|
3492
|
+
},
|
|
3493
|
+
async get(nonce) {
|
|
3494
|
+
const raw = await kv.get(`${prefix}${nonce}`);
|
|
3495
|
+
if (!raw) return null;
|
|
3496
|
+
const record = raw;
|
|
3497
|
+
if (Date.now() > record.expiresAt) {
|
|
3498
|
+
await kv.del(`${prefix}${nonce}`);
|
|
3499
|
+
return null;
|
|
3500
|
+
}
|
|
3501
|
+
return record;
|
|
3502
|
+
},
|
|
3503
|
+
async has(nonce) {
|
|
3504
|
+
return await this.get(nonce) !== null;
|
|
3505
|
+
},
|
|
3506
|
+
async consume(nonce) {
|
|
3507
|
+
return kv.update(`${prefix}${nonce}`, (current) => {
|
|
3508
|
+
if (!current) return { op: "noop", result: null };
|
|
3509
|
+
const record = current;
|
|
3510
|
+
if (Date.now() > record.expiresAt) {
|
|
3511
|
+
return { op: "delete", result: null };
|
|
3512
|
+
}
|
|
3513
|
+
return { op: "delete", result: record };
|
|
3514
|
+
});
|
|
3515
|
+
}
|
|
3516
|
+
};
|
|
3517
|
+
}
|
|
3518
|
+
function createAgentIdentityNonceStore(kv) {
|
|
3519
|
+
return kv ? createKvAgentIdentityNonceStore(kv) : new import_did_auth_challenge2.NonceStore();
|
|
3520
|
+
}
|
|
3521
|
+
|
|
3360
3522
|
// src/protocols/mpp/siwx-mode.ts
|
|
3361
3523
|
var import_mppx3 = require("mppx");
|
|
3362
3524
|
async function verifyMppSiwx(request, mppx) {
|
|
@@ -3483,6 +3645,7 @@ async function buildSiwxChallenge(ctx) {
|
|
|
3483
3645
|
} catch {
|
|
3484
3646
|
}
|
|
3485
3647
|
}
|
|
3648
|
+
await attachAgentIdentityChallenge(response, request, deps.agentIdentityNonceStore);
|
|
3486
3649
|
firePluginResponse(ctx, response);
|
|
3487
3650
|
return response;
|
|
3488
3651
|
}
|
|
@@ -3602,7 +3765,8 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3602
3765
|
validateFn: void 0,
|
|
3603
3766
|
settlement: void 0,
|
|
3604
3767
|
mppInfo: void 0,
|
|
3605
|
-
hasCheckout: false
|
|
3768
|
+
hasCheckout: false,
|
|
3769
|
+
checkoutSession: void 0
|
|
3606
3770
|
};
|
|
3607
3771
|
}
|
|
3608
3772
|
fork() {
|
|
@@ -3693,7 +3857,8 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3693
3857
|
if (resolvedOptions.minPrice) next.#s.minPrice = resolvedOptions.minPrice;
|
|
3694
3858
|
if (resolvedOptions.payTo) next.#s.payTo = resolvedOptions.payTo;
|
|
3695
3859
|
if (resolvedOptions.mpp) next.#s.mppInfo = resolvedOptions.mpp;
|
|
3696
|
-
if (resolvedOptions.checkout) next.#s.hasCheckout = true;
|
|
3860
|
+
if (resolvedOptions.checkout || resolvedOptions.checkoutSession) next.#s.hasCheckout = true;
|
|
3861
|
+
if (resolvedOptions.checkoutSession) next.#s.checkoutSession = resolvedOptions.checkoutSession;
|
|
3697
3862
|
next.#s.billing = billing;
|
|
3698
3863
|
if (tickCost) next.#s.tickCost = tickCost;
|
|
3699
3864
|
if (unitType) next.#s.unitType = unitType;
|
|
@@ -4128,6 +4293,7 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
4128
4293
|
settlement: this.#s.settlement,
|
|
4129
4294
|
mppInfo: this.#s.mppInfo,
|
|
4130
4295
|
hasCheckout: this.#s.hasCheckout ? true : void 0,
|
|
4296
|
+
checkoutSession: this.#s.checkoutSession,
|
|
4131
4297
|
tickCost: this.#s.tickCost,
|
|
4132
4298
|
unitType: this.#s.unitType
|
|
4133
4299
|
};
|
|
@@ -4475,6 +4641,33 @@ function createLlmsTxtHandler(discovery) {
|
|
|
4475
4641
|
};
|
|
4476
4642
|
}
|
|
4477
4643
|
|
|
4644
|
+
// src/discovery/not-found.ts
|
|
4645
|
+
var import_server12 = require("next/server");
|
|
4646
|
+
function createNotFoundHandler(baseUrl) {
|
|
4647
|
+
const normalizedBase = baseUrl.replace(/\/+$/, "");
|
|
4648
|
+
return async (request) => import_server12.NextResponse.json(
|
|
4649
|
+
{
|
|
4650
|
+
success: false,
|
|
4651
|
+
code: "route_not_found",
|
|
4652
|
+
error: "Route not found. Rediscover this origin and retry with the current discovery document.",
|
|
4653
|
+
requestedUrl: request.url,
|
|
4654
|
+
discovery: {
|
|
4655
|
+
openapi: `${normalizedBase}/openapi.json`,
|
|
4656
|
+
wellKnown: `${normalizedBase}/.well-known/x402`,
|
|
4657
|
+
llmsTxt: `${normalizedBase}/llms.txt`
|
|
4658
|
+
}
|
|
4659
|
+
},
|
|
4660
|
+
{
|
|
4661
|
+
status: 404,
|
|
4662
|
+
headers: {
|
|
4663
|
+
"Access-Control-Allow-Origin": "*",
|
|
4664
|
+
"Access-Control-Allow-Methods": "GET, POST, DELETE, PUT, PATCH, OPTIONS",
|
|
4665
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization, X-API-Key, SIGN-IN-WITH-X, X-Agent-Identity"
|
|
4666
|
+
}
|
|
4667
|
+
}
|
|
4668
|
+
);
|
|
4669
|
+
}
|
|
4670
|
+
|
|
4478
4671
|
// src/index.ts
|
|
4479
4672
|
init_accepts();
|
|
4480
4673
|
init_constants();
|
|
@@ -5083,6 +5276,7 @@ function createRouter(config) {
|
|
|
5083
5276
|
const registry = new RouteRegistry();
|
|
5084
5277
|
const kvStore = resolveKvStore(config.kvStore);
|
|
5085
5278
|
const nonceStore = kvStore ? createKvNonceStore(kvStore) : new MemoryNonceStore();
|
|
5279
|
+
const agentIdentityNonceStore = createAgentIdentityNonceStore(kvStore);
|
|
5086
5280
|
const entitlementStore = kvStore ? createKvEntitlementStore(kvStore) : new MemoryEntitlementStore();
|
|
5087
5281
|
const network = config.network ?? BASE_MAINNET_NETWORK;
|
|
5088
5282
|
const x402Accepts = getConfiguredX402Accepts(config);
|
|
@@ -5117,6 +5311,7 @@ function createRouter(config) {
|
|
|
5117
5311
|
initPromise: Promise.resolve(),
|
|
5118
5312
|
plugin: config.plugin,
|
|
5119
5313
|
nonceStore,
|
|
5314
|
+
agentIdentityNonceStore,
|
|
5120
5315
|
entitlementStore,
|
|
5121
5316
|
payeeAddress: config.payeeAddress ?? "",
|
|
5122
5317
|
mppRecipient: config.mpp?.recipient ?? config.payeeAddress,
|
|
@@ -5178,6 +5373,9 @@ function createRouter(config) {
|
|
|
5178
5373
|
llmsTxt() {
|
|
5179
5374
|
return createLlmsTxtHandler(config.discovery);
|
|
5180
5375
|
},
|
|
5376
|
+
notFound() {
|
|
5377
|
+
return createNotFoundHandler(resolvedBaseUrl);
|
|
5378
|
+
},
|
|
5181
5379
|
monitors() {
|
|
5182
5380
|
const result = [];
|
|
5183
5381
|
for (const [, entry] of registry.entries()) {
|
package/dist/index.d.cts
CHANGED
|
@@ -4,6 +4,7 @@ import { ZodType } from 'zod';
|
|
|
4
4
|
import { PaymentRequirements, PaymentRequired, VerifyResponse, SettleResponse, Network } from '@x402/core/types';
|
|
5
5
|
import * as viem from 'viem';
|
|
6
6
|
import { Transport } from 'mppx/server';
|
|
7
|
+
import { NonceStoreInterface } from 'did-auth-challenge';
|
|
7
8
|
|
|
8
9
|
interface KvStore {
|
|
9
10
|
get(key: string): Promise<unknown>;
|
|
@@ -79,6 +80,8 @@ interface ResponseMeta {
|
|
|
79
80
|
requestBody?: unknown;
|
|
80
81
|
/** Handler return value or structured router-generated error body. */
|
|
81
82
|
responseBody?: unknown;
|
|
83
|
+
/** Rich error details for non-402 failure responses. */
|
|
84
|
+
error?: ErrorEvent;
|
|
82
85
|
}
|
|
83
86
|
interface ErrorEvent {
|
|
84
87
|
status: number;
|
|
@@ -219,6 +222,15 @@ interface MppProtocolInfo {
|
|
|
219
222
|
intent?: string;
|
|
220
223
|
currency?: string;
|
|
221
224
|
}
|
|
225
|
+
type CheckoutSessionResponse = Record<string, unknown>;
|
|
226
|
+
interface CheckoutSessionContext<TBody = unknown> {
|
|
227
|
+
request: NextRequest;
|
|
228
|
+
route: string;
|
|
229
|
+
body: TBody | undefined;
|
|
230
|
+
/** Decimal-dollar price quoted for this 402 challenge. */
|
|
231
|
+
price: string;
|
|
232
|
+
}
|
|
233
|
+
type CheckoutSessionFn<TBody = unknown> = (ctx: CheckoutSessionContext<TBody>) => CheckoutSessionResponse | null | undefined | Promise<CheckoutSessionResponse | null | undefined>;
|
|
222
234
|
interface PaidOptions {
|
|
223
235
|
protocols?: ProtocolType[];
|
|
224
236
|
maxPrice?: string;
|
|
@@ -229,6 +241,14 @@ interface PaidOptions {
|
|
|
229
241
|
mpp?: MppProtocolInfo;
|
|
230
242
|
/** Signal in discovery that clients should use an explicit checkout flow before payment. */
|
|
231
243
|
checkout?: boolean;
|
|
244
|
+
/**
|
|
245
|
+
* Build dynamic checkout review metadata for the router-owned 402 response body.
|
|
246
|
+
*
|
|
247
|
+
* The returned object is emitted as `{ "checkout_session": ... }` on the unpaid
|
|
248
|
+
* payment challenge response. Payment terms remain authoritative in the x402/MPP
|
|
249
|
+
* challenge headers.
|
|
250
|
+
*/
|
|
251
|
+
checkoutSession?: CheckoutSessionFn;
|
|
232
252
|
}
|
|
233
253
|
type PaidArg = (PaidOptions & {
|
|
234
254
|
price: string;
|
|
@@ -303,6 +323,8 @@ interface HandlerContext<TBody = undefined, TQuery = undefined> {
|
|
|
303
323
|
requestId: string;
|
|
304
324
|
route: string;
|
|
305
325
|
wallet: string | null;
|
|
326
|
+
/** Optional DID from `X-Agent-Identity` proof. Null when the client omits identity. */
|
|
327
|
+
actor: string | null;
|
|
306
328
|
payment: HandlerPaymentContext | null;
|
|
307
329
|
account: unknown;
|
|
308
330
|
alert: AlertFn;
|
|
@@ -374,6 +396,7 @@ interface RouteEntry {
|
|
|
374
396
|
settlement?: SettlementLifecycle;
|
|
375
397
|
mppInfo?: MppProtocolInfo;
|
|
376
398
|
hasCheckout?: boolean;
|
|
399
|
+
checkoutSession?: CheckoutSessionFn;
|
|
377
400
|
/** Per-tick cost (decimal-dollar). Required when `metered` is true. */
|
|
378
401
|
tickCost?: string;
|
|
379
402
|
/** Cosmetic unit label for 402 challenges and client UIs. */
|
|
@@ -480,6 +503,7 @@ interface RouterDeps {
|
|
|
480
503
|
mppInitError?: string;
|
|
481
504
|
plugin?: RouterPlugin;
|
|
482
505
|
nonceStore: NonceStore;
|
|
506
|
+
agentIdentityNonceStore: NonceStoreInterface;
|
|
483
507
|
entitlementStore: EntitlementStore;
|
|
484
508
|
payeeAddress: string;
|
|
485
509
|
mppRecipient?: string;
|
|
@@ -557,8 +581,8 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
|
|
|
557
581
|
* - `{ price }` — fixed price (object form of the string sugar).
|
|
558
582
|
* - `{ field, tiers, default? }` — pick a tier from `body[field]`.
|
|
559
583
|
*
|
|
560
|
-
* Common knobs (`protocols`, `maxPrice`, `minPrice`, `payTo`, `mpp`, `checkout
|
|
561
|
-
* alongside the pricing shape. For handler-computed billing use `.upTo()`;
|
|
584
|
+
* Common knobs (`protocols`, `maxPrice`, `minPrice`, `payTo`, `mpp`, `checkout`,
|
|
585
|
+
* `checkoutSession`) live alongside the pricing shape. For handler-computed billing use `.upTo()`;
|
|
562
586
|
* for per-tick billing use `.metered()`.
|
|
563
587
|
*
|
|
564
588
|
* @example
|
|
@@ -900,6 +924,7 @@ interface ServiceRouter<TPriceKeys extends string = never> {
|
|
|
900
924
|
wellKnown(): (request: NextRequest) => Promise<NextResponse>;
|
|
901
925
|
openapi(): (request: NextRequest) => Promise<NextResponse>;
|
|
902
926
|
llmsTxt(): (request: NextRequest) => Promise<NextResponse>;
|
|
927
|
+
notFound(): (request: NextRequest) => Promise<NextResponse>;
|
|
903
928
|
monitors(): MonitorEntry[];
|
|
904
929
|
registry: RouteRegistry;
|
|
905
930
|
}
|
|
@@ -928,4 +953,4 @@ declare function createRouter<const P extends Record<string, string> = Record<ne
|
|
|
928
953
|
*/
|
|
929
954
|
declare function createRouterFromEnv<const P extends Record<string, string> = Record<never, string>>(options: CreateRouterFromEnvOptions<P>): ServiceRouter<Extract<keyof P, string>>;
|
|
930
955
|
|
|
931
|
-
export { BASE_MAINNET_NETWORK, BASE_USDC_ADDRESS, BASE_USDC_DECIMALS, type CreateRouterFromEnvOptions, DEFAULT_SOLANA_FACILITATOR_URL, DEFAULT_TEMPO_RPC_URL, type DiscoveryConfig, type HandlerContext, HttpError, type KvStore, type PaidOptions, type ProtocolType, type RouterConfig, RouterConfigError, type RouterConfigIssue, type RouterConfigIssueCode, type RouterConfigIssueSeverity, type RouterPlugin, SOLANA_MAINNET_NETWORK, type ServiceRouter, type SettlementErrorContext, type SettlementLifecycleContext, type SettlementSettledContext, TEMPO_USDC_ADDRESS, TEMPO_USDC_DECIMALS, type X402FacilitatorsConfig, ZERO_EVM_ADDRESS, createRouter, createRouterFromEnv, routerConfigFromEnv };
|
|
956
|
+
export { BASE_MAINNET_NETWORK, BASE_USDC_ADDRESS, BASE_USDC_DECIMALS, type CheckoutSessionContext, type CheckoutSessionFn, type CheckoutSessionResponse, type CreateRouterFromEnvOptions, DEFAULT_SOLANA_FACILITATOR_URL, DEFAULT_TEMPO_RPC_URL, type DiscoveryConfig, type HandlerContext, HttpError, type KvStore, type PaidOptions, type ProtocolType, type RouterConfig, RouterConfigError, type RouterConfigIssue, type RouterConfigIssueCode, type RouterConfigIssueSeverity, type RouterPlugin, SOLANA_MAINNET_NETWORK, type ServiceRouter, type SettlementErrorContext, type SettlementLifecycleContext, type SettlementSettledContext, TEMPO_USDC_ADDRESS, TEMPO_USDC_DECIMALS, type X402FacilitatorsConfig, ZERO_EVM_ADDRESS, createRouter, createRouterFromEnv, routerConfigFromEnv };
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { ZodType } from 'zod';
|
|
|
4
4
|
import { PaymentRequirements, PaymentRequired, VerifyResponse, SettleResponse, Network } from '@x402/core/types';
|
|
5
5
|
import * as viem from 'viem';
|
|
6
6
|
import { Transport } from 'mppx/server';
|
|
7
|
+
import { NonceStoreInterface } from 'did-auth-challenge';
|
|
7
8
|
|
|
8
9
|
interface KvStore {
|
|
9
10
|
get(key: string): Promise<unknown>;
|
|
@@ -79,6 +80,8 @@ interface ResponseMeta {
|
|
|
79
80
|
requestBody?: unknown;
|
|
80
81
|
/** Handler return value or structured router-generated error body. */
|
|
81
82
|
responseBody?: unknown;
|
|
83
|
+
/** Rich error details for non-402 failure responses. */
|
|
84
|
+
error?: ErrorEvent;
|
|
82
85
|
}
|
|
83
86
|
interface ErrorEvent {
|
|
84
87
|
status: number;
|
|
@@ -219,6 +222,15 @@ interface MppProtocolInfo {
|
|
|
219
222
|
intent?: string;
|
|
220
223
|
currency?: string;
|
|
221
224
|
}
|
|
225
|
+
type CheckoutSessionResponse = Record<string, unknown>;
|
|
226
|
+
interface CheckoutSessionContext<TBody = unknown> {
|
|
227
|
+
request: NextRequest;
|
|
228
|
+
route: string;
|
|
229
|
+
body: TBody | undefined;
|
|
230
|
+
/** Decimal-dollar price quoted for this 402 challenge. */
|
|
231
|
+
price: string;
|
|
232
|
+
}
|
|
233
|
+
type CheckoutSessionFn<TBody = unknown> = (ctx: CheckoutSessionContext<TBody>) => CheckoutSessionResponse | null | undefined | Promise<CheckoutSessionResponse | null | undefined>;
|
|
222
234
|
interface PaidOptions {
|
|
223
235
|
protocols?: ProtocolType[];
|
|
224
236
|
maxPrice?: string;
|
|
@@ -229,6 +241,14 @@ interface PaidOptions {
|
|
|
229
241
|
mpp?: MppProtocolInfo;
|
|
230
242
|
/** Signal in discovery that clients should use an explicit checkout flow before payment. */
|
|
231
243
|
checkout?: boolean;
|
|
244
|
+
/**
|
|
245
|
+
* Build dynamic checkout review metadata for the router-owned 402 response body.
|
|
246
|
+
*
|
|
247
|
+
* The returned object is emitted as `{ "checkout_session": ... }` on the unpaid
|
|
248
|
+
* payment challenge response. Payment terms remain authoritative in the x402/MPP
|
|
249
|
+
* challenge headers.
|
|
250
|
+
*/
|
|
251
|
+
checkoutSession?: CheckoutSessionFn;
|
|
232
252
|
}
|
|
233
253
|
type PaidArg = (PaidOptions & {
|
|
234
254
|
price: string;
|
|
@@ -303,6 +323,8 @@ interface HandlerContext<TBody = undefined, TQuery = undefined> {
|
|
|
303
323
|
requestId: string;
|
|
304
324
|
route: string;
|
|
305
325
|
wallet: string | null;
|
|
326
|
+
/** Optional DID from `X-Agent-Identity` proof. Null when the client omits identity. */
|
|
327
|
+
actor: string | null;
|
|
306
328
|
payment: HandlerPaymentContext | null;
|
|
307
329
|
account: unknown;
|
|
308
330
|
alert: AlertFn;
|
|
@@ -374,6 +396,7 @@ interface RouteEntry {
|
|
|
374
396
|
settlement?: SettlementLifecycle;
|
|
375
397
|
mppInfo?: MppProtocolInfo;
|
|
376
398
|
hasCheckout?: boolean;
|
|
399
|
+
checkoutSession?: CheckoutSessionFn;
|
|
377
400
|
/** Per-tick cost (decimal-dollar). Required when `metered` is true. */
|
|
378
401
|
tickCost?: string;
|
|
379
402
|
/** Cosmetic unit label for 402 challenges and client UIs. */
|
|
@@ -480,6 +503,7 @@ interface RouterDeps {
|
|
|
480
503
|
mppInitError?: string;
|
|
481
504
|
plugin?: RouterPlugin;
|
|
482
505
|
nonceStore: NonceStore;
|
|
506
|
+
agentIdentityNonceStore: NonceStoreInterface;
|
|
483
507
|
entitlementStore: EntitlementStore;
|
|
484
508
|
payeeAddress: string;
|
|
485
509
|
mppRecipient?: string;
|
|
@@ -557,8 +581,8 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, TOutput = unde
|
|
|
557
581
|
* - `{ price }` — fixed price (object form of the string sugar).
|
|
558
582
|
* - `{ field, tiers, default? }` — pick a tier from `body[field]`.
|
|
559
583
|
*
|
|
560
|
-
* Common knobs (`protocols`, `maxPrice`, `minPrice`, `payTo`, `mpp`, `checkout
|
|
561
|
-
* alongside the pricing shape. For handler-computed billing use `.upTo()`;
|
|
584
|
+
* Common knobs (`protocols`, `maxPrice`, `minPrice`, `payTo`, `mpp`, `checkout`,
|
|
585
|
+
* `checkoutSession`) live alongside the pricing shape. For handler-computed billing use `.upTo()`;
|
|
562
586
|
* for per-tick billing use `.metered()`.
|
|
563
587
|
*
|
|
564
588
|
* @example
|
|
@@ -900,6 +924,7 @@ interface ServiceRouter<TPriceKeys extends string = never> {
|
|
|
900
924
|
wellKnown(): (request: NextRequest) => Promise<NextResponse>;
|
|
901
925
|
openapi(): (request: NextRequest) => Promise<NextResponse>;
|
|
902
926
|
llmsTxt(): (request: NextRequest) => Promise<NextResponse>;
|
|
927
|
+
notFound(): (request: NextRequest) => Promise<NextResponse>;
|
|
903
928
|
monitors(): MonitorEntry[];
|
|
904
929
|
registry: RouteRegistry;
|
|
905
930
|
}
|
|
@@ -928,4 +953,4 @@ declare function createRouter<const P extends Record<string, string> = Record<ne
|
|
|
928
953
|
*/
|
|
929
954
|
declare function createRouterFromEnv<const P extends Record<string, string> = Record<never, string>>(options: CreateRouterFromEnvOptions<P>): ServiceRouter<Extract<keyof P, string>>;
|
|
930
955
|
|
|
931
|
-
export { BASE_MAINNET_NETWORK, BASE_USDC_ADDRESS, BASE_USDC_DECIMALS, type CreateRouterFromEnvOptions, DEFAULT_SOLANA_FACILITATOR_URL, DEFAULT_TEMPO_RPC_URL, type DiscoveryConfig, type HandlerContext, HttpError, type KvStore, type PaidOptions, type ProtocolType, type RouterConfig, RouterConfigError, type RouterConfigIssue, type RouterConfigIssueCode, type RouterConfigIssueSeverity, type RouterPlugin, SOLANA_MAINNET_NETWORK, type ServiceRouter, type SettlementErrorContext, type SettlementLifecycleContext, type SettlementSettledContext, TEMPO_USDC_ADDRESS, TEMPO_USDC_DECIMALS, type X402FacilitatorsConfig, ZERO_EVM_ADDRESS, createRouter, createRouterFromEnv, routerConfigFromEnv };
|
|
956
|
+
export { BASE_MAINNET_NETWORK, BASE_USDC_ADDRESS, BASE_USDC_DECIMALS, type CheckoutSessionContext, type CheckoutSessionFn, type CheckoutSessionResponse, type CreateRouterFromEnvOptions, DEFAULT_SOLANA_FACILITATOR_URL, DEFAULT_TEMPO_RPC_URL, type DiscoveryConfig, type HandlerContext, HttpError, type KvStore, type PaidOptions, type ProtocolType, type RouterConfig, RouterConfigError, type RouterConfigIssue, type RouterConfigIssueCode, type RouterConfigIssueSeverity, type RouterPlugin, SOLANA_MAINNET_NETWORK, type ServiceRouter, type SettlementErrorContext, type SettlementLifecycleContext, type SettlementSettledContext, TEMPO_USDC_ADDRESS, TEMPO_USDC_DECIMALS, type X402FacilitatorsConfig, ZERO_EVM_ADDRESS, createRouter, createRouterFromEnv, routerConfigFromEnv };
|
package/dist/index.js
CHANGED
|
@@ -500,7 +500,8 @@ var HEADERS = {
|
|
|
500
500
|
X402_PAYMENT_REQUIRED: "PAYMENT-REQUIRED",
|
|
501
501
|
X402_PAYMENT_RESPONSE: "PAYMENT-RESPONSE",
|
|
502
502
|
MPP_PAYMENT_RECEIPT: "Payment-Receipt",
|
|
503
|
-
REQUEST_ID: "X-Request-ID"
|
|
503
|
+
REQUEST_ID: "X-Request-ID",
|
|
504
|
+
AGENT_IDENTITY: "X-Agent-Identity"
|
|
504
505
|
};
|
|
505
506
|
var AUTH_SCHEME = {
|
|
506
507
|
BEARER: "Bearer ",
|
|
@@ -635,6 +636,7 @@ function firePaymentSettled(ctx, event) {
|
|
|
635
636
|
}
|
|
636
637
|
function firePluginResponse(ctx, response, requestBody, responseBody, failure) {
|
|
637
638
|
attachRequestId(response, ctx.meta.requestId);
|
|
639
|
+
const error = response.status >= 400 && response.status !== 402 ? buildErrorEvent(ctx, response, failure) : void 0;
|
|
638
640
|
firePluginHook(ctx.deps.plugin, "onResponse", ctx.pluginCtx, {
|
|
639
641
|
statusCode: response.status,
|
|
640
642
|
statusText: response.statusText,
|
|
@@ -642,10 +644,10 @@ function firePluginResponse(ctx, response, requestBody, responseBody, failure) {
|
|
|
642
644
|
contentType: response.headers.get("content-type"),
|
|
643
645
|
headers: Object.fromEntries(response.headers.entries()),
|
|
644
646
|
requestBody,
|
|
645
|
-
responseBody
|
|
647
|
+
responseBody,
|
|
648
|
+
error
|
|
646
649
|
});
|
|
647
|
-
if (
|
|
648
|
-
const error = buildErrorEvent(ctx, response, failure);
|
|
650
|
+
if (error) {
|
|
649
651
|
if (response.status >= 500) logRouterFailure(error);
|
|
650
652
|
firePluginHook(ctx.deps.plugin, "onError", ctx.pluginCtx, error);
|
|
651
653
|
}
|
|
@@ -818,6 +820,13 @@ async function runValidate(ctx, body) {
|
|
|
818
820
|
// src/pipeline/flows/static/static-invoke.ts
|
|
819
821
|
import { NextResponse as NextResponse4 } from "next/server";
|
|
820
822
|
|
|
823
|
+
// src/auth/agent-identity.ts
|
|
824
|
+
import {
|
|
825
|
+
createChallenge,
|
|
826
|
+
isIdentityError,
|
|
827
|
+
verifySignature
|
|
828
|
+
} from "did-auth-challenge";
|
|
829
|
+
|
|
821
830
|
// src/types.ts
|
|
822
831
|
var HttpError = class extends Error {
|
|
823
832
|
constructor(message, status) {
|
|
@@ -827,18 +836,87 @@ var HttpError = class extends Error {
|
|
|
827
836
|
}
|
|
828
837
|
};
|
|
829
838
|
|
|
830
|
-
// src/
|
|
831
|
-
|
|
832
|
-
|
|
839
|
+
// src/auth/agent-identity.ts
|
|
840
|
+
var PROTOCOL_VERSION = 1;
|
|
841
|
+
function base64urlEncode(value) {
|
|
842
|
+
return Buffer.from(JSON.stringify(value)).toString("base64url");
|
|
843
|
+
}
|
|
844
|
+
function base64urlDecode(value) {
|
|
845
|
+
return JSON.parse(Buffer.from(value, "base64url").toString("utf8"));
|
|
846
|
+
}
|
|
847
|
+
function challengeBindings(request) {
|
|
848
|
+
const url = new URL(request.url);
|
|
849
|
+
return { domain: url.hostname, route: url.pathname };
|
|
850
|
+
}
|
|
851
|
+
async function buildAgentIdentityChallengeHeader(request, nonceStore) {
|
|
852
|
+
const bindings = challengeBindings(request);
|
|
853
|
+
const challenge = await createChallenge(bindings, { nonceStore });
|
|
854
|
+
return base64urlEncode({
|
|
855
|
+
v: PROTOCOL_VERSION,
|
|
856
|
+
challenge
|
|
857
|
+
});
|
|
833
858
|
}
|
|
834
|
-
function
|
|
835
|
-
|
|
859
|
+
async function attachAgentIdentityChallenge(response, request, nonceStore) {
|
|
860
|
+
response.headers.set(
|
|
861
|
+
HEADERS.AGENT_IDENTITY,
|
|
862
|
+
await buildAgentIdentityChallengeHeader(request, nonceStore)
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
async function resolveActor(request, nonceStore) {
|
|
866
|
+
const header = request.headers.get(HEADERS.AGENT_IDENTITY);
|
|
867
|
+
if (!header) return null;
|
|
868
|
+
let envelope;
|
|
869
|
+
try {
|
|
870
|
+
envelope = base64urlDecode(header);
|
|
871
|
+
} catch {
|
|
872
|
+
throw new HttpError("Malformed X-Agent-Identity header", 401);
|
|
873
|
+
}
|
|
874
|
+
if (envelope.v !== PROTOCOL_VERSION || !envelope.challenge || !envelope.did || !envelope.signature) {
|
|
875
|
+
throw new HttpError("Invalid X-Agent-Identity proof", 401);
|
|
876
|
+
}
|
|
877
|
+
const bindings = challengeBindings(request);
|
|
878
|
+
try {
|
|
879
|
+
await verifySignature({
|
|
880
|
+
did: envelope.did,
|
|
881
|
+
authenticationKey: envelope.authenticationKey,
|
|
882
|
+
challenge: envelope.challenge,
|
|
883
|
+
signature: envelope.signature,
|
|
884
|
+
options: {
|
|
885
|
+
nonceStore,
|
|
886
|
+
expected: bindings
|
|
887
|
+
}
|
|
888
|
+
});
|
|
889
|
+
} catch (err) {
|
|
890
|
+
const message = isIdentityError(err) ? err.code : "Invalid agent identity";
|
|
891
|
+
throw new HttpError(message, 401);
|
|
892
|
+
}
|
|
893
|
+
return envelope.did;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
// src/pipeline/flows/static/static-invoke.ts
|
|
897
|
+
async function invokePaidStatic(ctx, wallet, account, body, payment) {
|
|
898
|
+
const actorResult = await resolveActorForHandler(ctx);
|
|
899
|
+
if (actorResult.kind === "error") return actorResult.result;
|
|
900
|
+
return runHandler(ctx, buildHandlerCtx(ctx, wallet, account, body, payment, actorResult.actor));
|
|
901
|
+
}
|
|
902
|
+
async function invokeUnauthed(ctx, wallet, account, body) {
|
|
903
|
+
const actorResult = await resolveActorForHandler(ctx);
|
|
904
|
+
if (actorResult.kind === "error") return actorResult.result;
|
|
905
|
+
const base = buildHandlerCtx(ctx, wallet, account, body, null, actorResult.actor);
|
|
836
906
|
if (ctx.routeEntry.billing !== "upto") return runHandler(ctx, base);
|
|
837
907
|
const uptoCtx = { ...base, charge: async () => {
|
|
838
908
|
} };
|
|
839
909
|
return runHandler(ctx, uptoCtx);
|
|
840
910
|
}
|
|
841
|
-
function
|
|
911
|
+
async function resolveActorForHandler(ctx) {
|
|
912
|
+
try {
|
|
913
|
+
const actor = await resolveActor(ctx.request, ctx.deps.agentIdentityNonceStore);
|
|
914
|
+
return { kind: "ok", actor };
|
|
915
|
+
} catch (error) {
|
|
916
|
+
return { kind: "error", result: errorResult(error) };
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
function buildHandlerCtx(ctx, wallet, account, body, payment, actor) {
|
|
842
920
|
return {
|
|
843
921
|
body,
|
|
844
922
|
query: ctx.query,
|
|
@@ -846,6 +924,7 @@ function buildHandlerCtx(ctx, wallet, account, body, payment) {
|
|
|
846
924
|
requestId: ctx.meta.requestId,
|
|
847
925
|
route: ctx.routeEntry.key,
|
|
848
926
|
wallet,
|
|
927
|
+
actor,
|
|
849
928
|
payment,
|
|
850
929
|
account,
|
|
851
930
|
alert: ctx.report,
|
|
@@ -1165,7 +1244,7 @@ async function trySiwxFastPath(ctx, account) {
|
|
|
1165
1244
|
function shouldParseBodyEarly(incomingStrategy, routeEntry, pricing) {
|
|
1166
1245
|
if (incomingStrategy) return false;
|
|
1167
1246
|
if (!routeEntry.bodySchema) return false;
|
|
1168
|
-
return (pricing?.needsBody ?? false) || !!routeEntry.validateFn;
|
|
1247
|
+
return (pricing?.needsBody ?? false) || !!routeEntry.validateFn || !!routeEntry.checkoutSession;
|
|
1169
1248
|
}
|
|
1170
1249
|
|
|
1171
1250
|
// src/pipeline/steps/resolve-early-body.ts
|
|
@@ -2507,30 +2586,37 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
|
|
|
2507
2586
|
return errorResponse;
|
|
2508
2587
|
}
|
|
2509
2588
|
const extensions = await buildChallengeExtensions(ctx);
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
status: 402,
|
|
2513
|
-
headers: {
|
|
2514
|
-
"Content-Type": "application/json",
|
|
2515
|
-
"Cache-Control": "no-store"
|
|
2516
|
-
}
|
|
2517
|
-
});
|
|
2518
|
-
for (const strategy of getAllowedStrategies(ctx.routeEntry.protocols)) {
|
|
2589
|
+
let checkoutSession;
|
|
2590
|
+
if (ctx.routeEntry.checkoutSession) {
|
|
2519
2591
|
try {
|
|
2520
|
-
|
|
2592
|
+
checkoutSession = await ctx.routeEntry.checkoutSession({
|
|
2521
2593
|
request: ctx.request,
|
|
2522
|
-
|
|
2594
|
+
route: ctx.routeEntry.key,
|
|
2523
2595
|
body,
|
|
2524
|
-
price: challengePrice
|
|
2525
|
-
extensions,
|
|
2526
|
-
deps: ctx.deps,
|
|
2527
|
-
report: ctx.report
|
|
2596
|
+
price: challengePrice
|
|
2528
2597
|
});
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
}
|
|
2598
|
+
} catch (err) {
|
|
2599
|
+
const message = errorMessage(err, "Checkout session build failed");
|
|
2600
|
+
const responseBody2 = { success: false, error: message };
|
|
2601
|
+
const errorResponse = NextResponse5.json(responseBody2, { status: errorStatus(err, 500) });
|
|
2602
|
+
firePluginResponse(ctx, errorResponse, body, responseBody2, { message, cause: err });
|
|
2603
|
+
return errorResponse;
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
const contributions = [];
|
|
2607
|
+
for (const strategy of getAllowedStrategies(ctx.routeEntry.protocols)) {
|
|
2608
|
+
try {
|
|
2609
|
+
contributions.push(
|
|
2610
|
+
await strategy.buildChallenge({
|
|
2611
|
+
request: ctx.request,
|
|
2612
|
+
routeEntry: ctx.routeEntry,
|
|
2613
|
+
body,
|
|
2614
|
+
price: challengePrice,
|
|
2615
|
+
extensions,
|
|
2616
|
+
deps: ctx.deps,
|
|
2617
|
+
report: ctx.report
|
|
2618
|
+
})
|
|
2619
|
+
);
|
|
2534
2620
|
} catch (err) {
|
|
2535
2621
|
const message = `${strategy.protocol} challenge build failed: ${errorMessage(err, String(err))}`;
|
|
2536
2622
|
ctx.report("critical", message);
|
|
@@ -2542,6 +2628,27 @@ async function buildChallengeResponse(ctx, pricing, body, failure) {
|
|
|
2542
2628
|
}
|
|
2543
2629
|
}
|
|
2544
2630
|
}
|
|
2631
|
+
const responsePayload = {
|
|
2632
|
+
...Object.assign({}, ...contributions.map((contribution) => contribution.body ?? {})),
|
|
2633
|
+
...failure && { error: failure.message ?? null, reason: failure.reason },
|
|
2634
|
+
...checkoutSession && { checkout_session: checkoutSession }
|
|
2635
|
+
};
|
|
2636
|
+
const responseBody = Object.keys(responsePayload).length ? JSON.stringify(responsePayload) : null;
|
|
2637
|
+
const response = new NextResponse5(responseBody, {
|
|
2638
|
+
status: 402,
|
|
2639
|
+
headers: {
|
|
2640
|
+
"Content-Type": "application/json",
|
|
2641
|
+
"Cache-Control": "no-store"
|
|
2642
|
+
}
|
|
2643
|
+
});
|
|
2644
|
+
for (const contribution of contributions) {
|
|
2645
|
+
if (contribution.headers) {
|
|
2646
|
+
for (const [name, value] of Object.entries(contribution.headers)) {
|
|
2647
|
+
response.headers.set(name, value);
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
}
|
|
2651
|
+
await attachAgentIdentityChallenge(response, ctx.request, ctx.deps.agentIdentityNonceStore);
|
|
2545
2652
|
firePluginResponse(ctx, response);
|
|
2546
2653
|
return response;
|
|
2547
2654
|
}
|
|
@@ -2676,7 +2783,7 @@ function createChargeContext(args) {
|
|
|
2676
2783
|
|
|
2677
2784
|
// src/pipeline/flows/dynamic/dynamic-invoke/shared.ts
|
|
2678
2785
|
import { NextResponse as NextResponse7 } from "next/server";
|
|
2679
|
-
function buildBaseHandlerCtx(ctx, wallet, account, body, payment) {
|
|
2786
|
+
function buildBaseHandlerCtx(ctx, wallet, account, body, payment, actor = null) {
|
|
2680
2787
|
return {
|
|
2681
2788
|
body,
|
|
2682
2789
|
query: ctx.query,
|
|
@@ -2684,12 +2791,21 @@ function buildBaseHandlerCtx(ctx, wallet, account, body, payment) {
|
|
|
2684
2791
|
requestId: ctx.meta.requestId,
|
|
2685
2792
|
route: ctx.routeEntry.key,
|
|
2686
2793
|
wallet,
|
|
2794
|
+
actor,
|
|
2687
2795
|
payment,
|
|
2688
2796
|
account,
|
|
2689
2797
|
alert: ctx.report,
|
|
2690
2798
|
setVerifiedWallet: (addr) => ctx.pluginCtx.setVerifiedWallet(addr)
|
|
2691
2799
|
};
|
|
2692
2800
|
}
|
|
2801
|
+
async function resolveActorOrError(ctx) {
|
|
2802
|
+
try {
|
|
2803
|
+
const actor = await resolveActor(ctx.request, ctx.deps.agentIdentityNonceStore);
|
|
2804
|
+
return { actor };
|
|
2805
|
+
} catch (error) {
|
|
2806
|
+
return errorResult2(error);
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2693
2809
|
function toResponse(rawResult) {
|
|
2694
2810
|
return rawResult instanceof Response ? rawResult : NextResponse7.json(rawResult);
|
|
2695
2811
|
}
|
|
@@ -2713,12 +2829,21 @@ function isThenable2(value) {
|
|
|
2713
2829
|
|
|
2714
2830
|
// src/pipeline/flows/dynamic/dynamic-invoke/metered-invoke.ts
|
|
2715
2831
|
async function invokeMetered(ctx, wallet, account, body, payment) {
|
|
2832
|
+
const actorResult = await resolveActorOrError(ctx);
|
|
2833
|
+
if ("response" in actorResult) return actorResult;
|
|
2716
2834
|
const chargeContext = ctx.routeEntry.streaming ? createChargeContext({
|
|
2717
2835
|
tickCost: ctx.routeEntry.tickCost,
|
|
2718
2836
|
maxPrice: ctx.routeEntry.maxPrice,
|
|
2719
2837
|
route: ctx.routeEntry.key
|
|
2720
2838
|
}) : null;
|
|
2721
|
-
const baseHandlerCtx = buildBaseHandlerCtx(
|
|
2839
|
+
const baseHandlerCtx = buildBaseHandlerCtx(
|
|
2840
|
+
ctx,
|
|
2841
|
+
wallet,
|
|
2842
|
+
account,
|
|
2843
|
+
body,
|
|
2844
|
+
payment,
|
|
2845
|
+
actorResult.actor
|
|
2846
|
+
);
|
|
2722
2847
|
const handlerCtx = chargeContext !== null ? { ...baseHandlerCtx, charge: chargeContext.charge } : baseHandlerCtx;
|
|
2723
2848
|
let returned;
|
|
2724
2849
|
try {
|
|
@@ -2777,12 +2902,14 @@ function createUptoChargeContext(args) {
|
|
|
2777
2902
|
|
|
2778
2903
|
// src/pipeline/flows/dynamic/dynamic-invoke/upto-invoke.ts
|
|
2779
2904
|
async function invokeUpto(ctx, wallet, account, body, payment) {
|
|
2905
|
+
const actorResult = await resolveActorOrError(ctx);
|
|
2906
|
+
if ("response" in actorResult) return actorResult;
|
|
2780
2907
|
const uptoCtx = createUptoChargeContext({
|
|
2781
2908
|
maxPrice: ctx.routeEntry.maxPrice,
|
|
2782
2909
|
route: ctx.routeEntry.key
|
|
2783
2910
|
});
|
|
2784
2911
|
const handlerCtx = {
|
|
2785
|
-
...buildBaseHandlerCtx(ctx, wallet, account, body, payment),
|
|
2912
|
+
...buildBaseHandlerCtx(ctx, wallet, account, body, payment, actorResult.actor),
|
|
2786
2913
|
charge: uptoCtx.charge
|
|
2787
2914
|
};
|
|
2788
2915
|
let returned;
|
|
@@ -3315,6 +3442,45 @@ async function createKvMppStore(kv, options) {
|
|
|
3315
3442
|
});
|
|
3316
3443
|
}
|
|
3317
3444
|
|
|
3445
|
+
// src/kv-store/agent-identity-nonce.ts
|
|
3446
|
+
import { NonceStore } from "did-auth-challenge";
|
|
3447
|
+
function createKvAgentIdentityNonceStore(kv, options) {
|
|
3448
|
+
const prefix = options?.prefix ?? "actor:nonce:";
|
|
3449
|
+
return {
|
|
3450
|
+
async add(nonce, expiresAt, challengeJson) {
|
|
3451
|
+
const ttl = Math.max(1, Math.ceil((expiresAt.getTime() - Date.now()) / 1e3));
|
|
3452
|
+
const record = { challengeJson, expiresAt: expiresAt.getTime() };
|
|
3453
|
+
await kv.setNxEx(`${prefix}${nonce}`, record, ttl);
|
|
3454
|
+
},
|
|
3455
|
+
async get(nonce) {
|
|
3456
|
+
const raw = await kv.get(`${prefix}${nonce}`);
|
|
3457
|
+
if (!raw) return null;
|
|
3458
|
+
const record = raw;
|
|
3459
|
+
if (Date.now() > record.expiresAt) {
|
|
3460
|
+
await kv.del(`${prefix}${nonce}`);
|
|
3461
|
+
return null;
|
|
3462
|
+
}
|
|
3463
|
+
return record;
|
|
3464
|
+
},
|
|
3465
|
+
async has(nonce) {
|
|
3466
|
+
return await this.get(nonce) !== null;
|
|
3467
|
+
},
|
|
3468
|
+
async consume(nonce) {
|
|
3469
|
+
return kv.update(`${prefix}${nonce}`, (current) => {
|
|
3470
|
+
if (!current) return { op: "noop", result: null };
|
|
3471
|
+
const record = current;
|
|
3472
|
+
if (Date.now() > record.expiresAt) {
|
|
3473
|
+
return { op: "delete", result: null };
|
|
3474
|
+
}
|
|
3475
|
+
return { op: "delete", result: record };
|
|
3476
|
+
});
|
|
3477
|
+
}
|
|
3478
|
+
};
|
|
3479
|
+
}
|
|
3480
|
+
function createAgentIdentityNonceStore(kv) {
|
|
3481
|
+
return kv ? createKvAgentIdentityNonceStore(kv) : new NonceStore();
|
|
3482
|
+
}
|
|
3483
|
+
|
|
3318
3484
|
// src/protocols/mpp/siwx-mode.ts
|
|
3319
3485
|
import { Credential as Credential2 } from "mppx";
|
|
3320
3486
|
async function verifyMppSiwx(request, mppx) {
|
|
@@ -3441,6 +3607,7 @@ async function buildSiwxChallenge(ctx) {
|
|
|
3441
3607
|
} catch {
|
|
3442
3608
|
}
|
|
3443
3609
|
}
|
|
3610
|
+
await attachAgentIdentityChallenge(response, request, deps.agentIdentityNonceStore);
|
|
3444
3611
|
firePluginResponse(ctx, response);
|
|
3445
3612
|
return response;
|
|
3446
3613
|
}
|
|
@@ -3560,7 +3727,8 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3560
3727
|
validateFn: void 0,
|
|
3561
3728
|
settlement: void 0,
|
|
3562
3729
|
mppInfo: void 0,
|
|
3563
|
-
hasCheckout: false
|
|
3730
|
+
hasCheckout: false,
|
|
3731
|
+
checkoutSession: void 0
|
|
3564
3732
|
};
|
|
3565
3733
|
}
|
|
3566
3734
|
fork() {
|
|
@@ -3651,7 +3819,8 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
3651
3819
|
if (resolvedOptions.minPrice) next.#s.minPrice = resolvedOptions.minPrice;
|
|
3652
3820
|
if (resolvedOptions.payTo) next.#s.payTo = resolvedOptions.payTo;
|
|
3653
3821
|
if (resolvedOptions.mpp) next.#s.mppInfo = resolvedOptions.mpp;
|
|
3654
|
-
if (resolvedOptions.checkout) next.#s.hasCheckout = true;
|
|
3822
|
+
if (resolvedOptions.checkout || resolvedOptions.checkoutSession) next.#s.hasCheckout = true;
|
|
3823
|
+
if (resolvedOptions.checkoutSession) next.#s.checkoutSession = resolvedOptions.checkoutSession;
|
|
3655
3824
|
next.#s.billing = billing;
|
|
3656
3825
|
if (tickCost) next.#s.tickCost = tickCost;
|
|
3657
3826
|
if (unitType) next.#s.unitType = unitType;
|
|
@@ -4086,6 +4255,7 @@ var RouteBuilder = class _RouteBuilder {
|
|
|
4086
4255
|
settlement: this.#s.settlement,
|
|
4087
4256
|
mppInfo: this.#s.mppInfo,
|
|
4088
4257
|
hasCheckout: this.#s.hasCheckout ? true : void 0,
|
|
4258
|
+
checkoutSession: this.#s.checkoutSession,
|
|
4089
4259
|
tickCost: this.#s.tickCost,
|
|
4090
4260
|
unitType: this.#s.unitType
|
|
4091
4261
|
};
|
|
@@ -4433,6 +4603,33 @@ function createLlmsTxtHandler(discovery) {
|
|
|
4433
4603
|
};
|
|
4434
4604
|
}
|
|
4435
4605
|
|
|
4606
|
+
// src/discovery/not-found.ts
|
|
4607
|
+
import { NextResponse as NextResponse12 } from "next/server";
|
|
4608
|
+
function createNotFoundHandler(baseUrl) {
|
|
4609
|
+
const normalizedBase = baseUrl.replace(/\/+$/, "");
|
|
4610
|
+
return async (request) => NextResponse12.json(
|
|
4611
|
+
{
|
|
4612
|
+
success: false,
|
|
4613
|
+
code: "route_not_found",
|
|
4614
|
+
error: "Route not found. Rediscover this origin and retry with the current discovery document.",
|
|
4615
|
+
requestedUrl: request.url,
|
|
4616
|
+
discovery: {
|
|
4617
|
+
openapi: `${normalizedBase}/openapi.json`,
|
|
4618
|
+
wellKnown: `${normalizedBase}/.well-known/x402`,
|
|
4619
|
+
llmsTxt: `${normalizedBase}/llms.txt`
|
|
4620
|
+
}
|
|
4621
|
+
},
|
|
4622
|
+
{
|
|
4623
|
+
status: 404,
|
|
4624
|
+
headers: {
|
|
4625
|
+
"Access-Control-Allow-Origin": "*",
|
|
4626
|
+
"Access-Control-Allow-Methods": "GET, POST, DELETE, PUT, PATCH, OPTIONS",
|
|
4627
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization, X-API-Key, SIGN-IN-WITH-X, X-Agent-Identity"
|
|
4628
|
+
}
|
|
4629
|
+
}
|
|
4630
|
+
);
|
|
4631
|
+
}
|
|
4632
|
+
|
|
4436
4633
|
// src/index.ts
|
|
4437
4634
|
init_accepts();
|
|
4438
4635
|
init_constants();
|
|
@@ -5041,6 +5238,7 @@ function createRouter(config) {
|
|
|
5041
5238
|
const registry = new RouteRegistry();
|
|
5042
5239
|
const kvStore = resolveKvStore(config.kvStore);
|
|
5043
5240
|
const nonceStore = kvStore ? createKvNonceStore(kvStore) : new MemoryNonceStore();
|
|
5241
|
+
const agentIdentityNonceStore = createAgentIdentityNonceStore(kvStore);
|
|
5044
5242
|
const entitlementStore = kvStore ? createKvEntitlementStore(kvStore) : new MemoryEntitlementStore();
|
|
5045
5243
|
const network = config.network ?? BASE_MAINNET_NETWORK;
|
|
5046
5244
|
const x402Accepts = getConfiguredX402Accepts(config);
|
|
@@ -5075,6 +5273,7 @@ function createRouter(config) {
|
|
|
5075
5273
|
initPromise: Promise.resolve(),
|
|
5076
5274
|
plugin: config.plugin,
|
|
5077
5275
|
nonceStore,
|
|
5276
|
+
agentIdentityNonceStore,
|
|
5078
5277
|
entitlementStore,
|
|
5079
5278
|
payeeAddress: config.payeeAddress ?? "",
|
|
5080
5279
|
mppRecipient: config.mpp?.recipient ?? config.payeeAddress,
|
|
@@ -5136,6 +5335,9 @@ function createRouter(config) {
|
|
|
5136
5335
|
llmsTxt() {
|
|
5137
5336
|
return createLlmsTxtHandler(config.discovery);
|
|
5138
5337
|
},
|
|
5338
|
+
notFound() {
|
|
5339
|
+
return createNotFoundHandler(resolvedBaseUrl);
|
|
5340
|
+
},
|
|
5139
5341
|
monitors() {
|
|
5140
5342
|
const result = [];
|
|
5141
5343
|
for (const [, entry] of registry.entries()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentcash/router",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.7",
|
|
4
4
|
"description": "Unified route builder for Next.js App Router APIs with x402, MPP, SIWX, and API key auth",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
"@x402/evm": "^2.13.0",
|
|
33
33
|
"@x402/extensions": "^2.13.0",
|
|
34
34
|
"@x402/svm": "^2.13.0",
|
|
35
|
+
"did-auth-challenge": "^0.0.1",
|
|
35
36
|
"mppx": "^0.6.16",
|
|
36
37
|
"viem": "^2.47.6",
|
|
37
38
|
"zod-openapi": "^5.0.0"
|