@agentcash/router 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +108 -58
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +108 -75
- package/package.json +14 -13
package/dist/index.cjs
CHANGED
|
@@ -35,12 +35,12 @@ var server_exports = {};
|
|
|
35
35
|
__export(server_exports, {
|
|
36
36
|
createX402Server: () => createX402Server
|
|
37
37
|
});
|
|
38
|
-
function createX402Server(config) {
|
|
39
|
-
const { x402ResourceServer, HTTPFacilitatorClient } =
|
|
40
|
-
const { registerExactEvmScheme } =
|
|
41
|
-
const { bazaarResourceServerExtension } =
|
|
42
|
-
const { siwxResourceServerExtension } =
|
|
43
|
-
const { facilitator: defaultFacilitator } =
|
|
38
|
+
async function createX402Server(config) {
|
|
39
|
+
const { x402ResourceServer, HTTPFacilitatorClient } = await import("@x402/core/server");
|
|
40
|
+
const { registerExactEvmScheme } = await import("@x402/evm/exact/server");
|
|
41
|
+
const { bazaarResourceServerExtension } = await import("@x402/extensions/bazaar");
|
|
42
|
+
const { siwxResourceServerExtension } = await import("@x402/extensions/sign-in-with-x");
|
|
43
|
+
const { facilitator: defaultFacilitator } = await import("@coinbase/x402");
|
|
44
44
|
const facilitatorUrl = config.facilitatorUrl ?? defaultFacilitator;
|
|
45
45
|
const client = new HTTPFacilitatorClient(facilitatorUrl);
|
|
46
46
|
const server = new x402ResourceServer(client);
|
|
@@ -214,7 +214,7 @@ async function safeCallHandler(handler, ctx) {
|
|
|
214
214
|
if (result instanceof Response) return result;
|
|
215
215
|
return import_server.NextResponse.json(result);
|
|
216
216
|
} catch (error) {
|
|
217
|
-
const status = error instanceof HttpError ? error.status : 500;
|
|
217
|
+
const status = error instanceof HttpError ? error.status : typeof error.status === "number" ? error.status : 500;
|
|
218
218
|
const message = error instanceof Error ? error.message : "Internal error";
|
|
219
219
|
return import_server.NextResponse.json({ success: false, error: message }, { status });
|
|
220
220
|
}
|
|
@@ -288,8 +288,8 @@ function resolveMaxPrice(pricing) {
|
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
// src/protocols/x402.ts
|
|
291
|
-
function buildX402Challenge(server, routeEntry, request, price, payeeAddress, network, extensions) {
|
|
292
|
-
const { encodePaymentRequiredHeader } =
|
|
291
|
+
async function buildX402Challenge(server, routeEntry, request, price, payeeAddress, network, extensions) {
|
|
292
|
+
const { encodePaymentRequiredHeader } = await import("@x402/core/http");
|
|
293
293
|
const options = {
|
|
294
294
|
scheme: "exact",
|
|
295
295
|
network,
|
|
@@ -314,7 +314,7 @@ function buildX402Challenge(server, routeEntry, request, price, payeeAddress, ne
|
|
|
314
314
|
return { encoded, requirements };
|
|
315
315
|
}
|
|
316
316
|
async function verifyX402Payment(server, request, routeEntry, price, payeeAddress, network) {
|
|
317
|
-
const { decodePaymentSignatureHeader } =
|
|
317
|
+
const { decodePaymentSignatureHeader } = await import("@x402/core/http");
|
|
318
318
|
const paymentHeader = request.headers.get("PAYMENT-SIGNATURE") ?? request.headers.get("X-PAYMENT");
|
|
319
319
|
if (!paymentHeader) return null;
|
|
320
320
|
const payload = decodePaymentSignatureHeader(paymentHeader);
|
|
@@ -340,7 +340,7 @@ async function verifyX402Payment(server, request, routeEntry, price, payeeAddres
|
|
|
340
340
|
};
|
|
341
341
|
}
|
|
342
342
|
async function settleX402Payment(server, payload, requirements) {
|
|
343
|
-
const { encodePaymentResponseHeader } =
|
|
343
|
+
const { encodePaymentResponseHeader } = await import("@x402/core/http");
|
|
344
344
|
const result = await server.settlePayment(payload, requirements);
|
|
345
345
|
const encoded = encodePaymentResponseHeader(result);
|
|
346
346
|
return { encoded, result };
|
|
@@ -352,22 +352,22 @@ var Challenge;
|
|
|
352
352
|
var Credential;
|
|
353
353
|
var Receipt;
|
|
354
354
|
var tempo;
|
|
355
|
-
function ensureMpay() {
|
|
355
|
+
async function ensureMpay() {
|
|
356
356
|
if (mpayLoaded) return;
|
|
357
357
|
try {
|
|
358
|
-
const mpay =
|
|
358
|
+
const mpay = await import("mpay");
|
|
359
359
|
Challenge = mpay.Challenge;
|
|
360
360
|
Credential = mpay.Credential;
|
|
361
361
|
Receipt = mpay.Receipt;
|
|
362
|
-
const mpayServer =
|
|
362
|
+
const mpayServer = await import("mpay/server");
|
|
363
363
|
tempo = mpayServer.tempo;
|
|
364
364
|
mpayLoaded = true;
|
|
365
365
|
} catch {
|
|
366
366
|
throw new Error("mpay package is required for MPP protocol support. Install it: pnpm add mpay");
|
|
367
367
|
}
|
|
368
368
|
}
|
|
369
|
-
function buildMPPChallenge(routeEntry, request, mppConfig, price) {
|
|
370
|
-
ensureMpay();
|
|
369
|
+
async function buildMPPChallenge(routeEntry, request, mppConfig, price) {
|
|
370
|
+
await ensureMpay();
|
|
371
371
|
const intent = {
|
|
372
372
|
amount: price,
|
|
373
373
|
currency: mppConfig.currency,
|
|
@@ -381,7 +381,7 @@ function buildMPPChallenge(routeEntry, request, mppConfig, price) {
|
|
|
381
381
|
return Challenge.serialize(challenge);
|
|
382
382
|
}
|
|
383
383
|
async function verifyMPPCredential(request, _routeEntry, mppConfig, price) {
|
|
384
|
-
ensureMpay();
|
|
384
|
+
await ensureMpay();
|
|
385
385
|
const credential = Credential.fromRequest(request);
|
|
386
386
|
if (!credential) return null;
|
|
387
387
|
const isValid = Challenge.verify(credential, { secretKey: mppConfig.secretKey });
|
|
@@ -402,8 +402,8 @@ async function verifyMPPCredential(request, _routeEntry, mppConfig, price) {
|
|
|
402
402
|
payer: verifyResult.payer
|
|
403
403
|
};
|
|
404
404
|
}
|
|
405
|
-
function buildMPPReceipt(reference) {
|
|
406
|
-
ensureMpay();
|
|
405
|
+
async function buildMPPReceipt(reference) {
|
|
406
|
+
await ensureMpay();
|
|
407
407
|
const receipt = Receipt.from({
|
|
408
408
|
method: "tempo",
|
|
409
409
|
status: "success",
|
|
@@ -415,11 +415,7 @@ function buildMPPReceipt(reference) {
|
|
|
415
415
|
|
|
416
416
|
// src/auth/siwx.ts
|
|
417
417
|
async function verifySIWX(request, _routeEntry, nonceStore) {
|
|
418
|
-
const {
|
|
419
|
-
parseSIWxHeader,
|
|
420
|
-
validateSIWxMessage,
|
|
421
|
-
verifySIWxSignature
|
|
422
|
-
} = require("@x402/extensions/sign-in-with-x");
|
|
418
|
+
const { parseSIWxHeader, validateSIWxMessage, verifySIWxSignature } = await import("@x402/extensions/sign-in-with-x");
|
|
423
419
|
const header = request.headers.get("SIGN-IN-WITH-X");
|
|
424
420
|
if (!header) return { valid: false, wallet: null };
|
|
425
421
|
const payload = parseSIWxHeader(header);
|
|
@@ -427,17 +423,17 @@ async function verifySIWX(request, _routeEntry, nonceStore) {
|
|
|
427
423
|
const validation = await validateSIWxMessage(payload, uri, {
|
|
428
424
|
checkNonce: (nonce) => nonceStore.check(nonce)
|
|
429
425
|
});
|
|
430
|
-
if (!validation.
|
|
426
|
+
if (!validation.valid) {
|
|
431
427
|
return { valid: false, wallet: null };
|
|
432
428
|
}
|
|
433
429
|
const verified = await verifySIWxSignature(payload);
|
|
434
|
-
if (!verified?.
|
|
430
|
+
if (!verified?.valid) {
|
|
435
431
|
return { valid: false, wallet: null };
|
|
436
432
|
}
|
|
437
433
|
return { valid: true, wallet: verified.address };
|
|
438
434
|
}
|
|
439
|
-
function buildSIWXExtension() {
|
|
440
|
-
const { declareSIWxExtension } =
|
|
435
|
+
async function buildSIWXExtension() {
|
|
436
|
+
const { declareSIWxExtension } = await import("@x402/extensions/sign-in-with-x");
|
|
441
437
|
return declareSIWxExtension();
|
|
442
438
|
}
|
|
443
439
|
|
|
@@ -537,11 +533,51 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
537
533
|
const protocol = detectProtocol(request);
|
|
538
534
|
if (routeEntry.authMode === "siwx") {
|
|
539
535
|
if (!request.headers.get("SIGN-IN-WITH-X")) {
|
|
540
|
-
const
|
|
536
|
+
const url = new URL(request.url);
|
|
537
|
+
const nonce = crypto.randomUUID();
|
|
538
|
+
const siwxInfo = {
|
|
539
|
+
domain: url.hostname,
|
|
540
|
+
uri: request.url,
|
|
541
|
+
version: "1",
|
|
542
|
+
chainId: deps.network,
|
|
543
|
+
type: "eip191",
|
|
544
|
+
nonce,
|
|
545
|
+
issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
546
|
+
expirationTime: new Date(Date.now() + 3e5).toISOString(),
|
|
547
|
+
statement: "Sign in to verify your wallet identity"
|
|
548
|
+
};
|
|
549
|
+
let siwxSchema;
|
|
541
550
|
try {
|
|
542
|
-
|
|
551
|
+
siwxSchema = await buildSIWXExtension();
|
|
543
552
|
} catch {
|
|
544
553
|
}
|
|
554
|
+
const paymentRequired = {
|
|
555
|
+
x402Version: 2,
|
|
556
|
+
error: "SIWX authentication required",
|
|
557
|
+
resource: {
|
|
558
|
+
url: request.url,
|
|
559
|
+
description: routeEntry.description ?? "SIWX-protected endpoint",
|
|
560
|
+
mimeType: "application/json"
|
|
561
|
+
},
|
|
562
|
+
accepts: [],
|
|
563
|
+
extensions: {
|
|
564
|
+
"sign-in-with-x": {
|
|
565
|
+
info: siwxInfo,
|
|
566
|
+
...siwxSchema ? { schema: siwxSchema } : {}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
let encoded;
|
|
571
|
+
try {
|
|
572
|
+
const { encodePaymentRequiredHeader } = await import("@x402/core/http");
|
|
573
|
+
encoded = encodePaymentRequiredHeader(paymentRequired);
|
|
574
|
+
} catch {
|
|
575
|
+
}
|
|
576
|
+
const response = new import_server2.NextResponse(JSON.stringify(paymentRequired), {
|
|
577
|
+
status: 402,
|
|
578
|
+
headers: { "Content-Type": "application/json" }
|
|
579
|
+
});
|
|
580
|
+
if (encoded) response.headers.set("PAYMENT-REQUIRED", encoded);
|
|
545
581
|
firePluginResponse(deps, pluginCtx, meta, response);
|
|
546
582
|
return response;
|
|
547
583
|
}
|
|
@@ -558,7 +594,7 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
558
594
|
return handleAuth(siwx.wallet, void 0);
|
|
559
595
|
}
|
|
560
596
|
if (!protocol || protocol === "siwx") {
|
|
561
|
-
return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
597
|
+
return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
562
598
|
}
|
|
563
599
|
const body = await parseBody(request, routeEntry);
|
|
564
600
|
if (!body.ok) {
|
|
@@ -589,7 +625,7 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
589
625
|
deps.payeeAddress,
|
|
590
626
|
deps.network
|
|
591
627
|
);
|
|
592
|
-
if (!verify?.valid) return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
628
|
+
if (!verify?.valid) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
593
629
|
pluginCtx.setVerifiedWallet(verify.payer);
|
|
594
630
|
firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
|
|
595
631
|
protocol: "x402",
|
|
@@ -631,9 +667,9 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
631
667
|
return response;
|
|
632
668
|
}
|
|
633
669
|
if (protocol === "mpp") {
|
|
634
|
-
if (!deps.mppConfig) return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
670
|
+
if (!deps.mppConfig) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
635
671
|
const verify = await verifyMPPCredential(request, routeEntry, deps.mppConfig, price);
|
|
636
|
-
if (!verify?.valid) return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
672
|
+
if (!verify?.valid) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
637
673
|
const wallet = verify.payer;
|
|
638
674
|
pluginCtx.setVerifiedWallet(wallet);
|
|
639
675
|
firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
|
|
@@ -652,14 +688,14 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
652
688
|
);
|
|
653
689
|
if (response.status < 400) {
|
|
654
690
|
try {
|
|
655
|
-
response.headers.set("Payment-Receipt", buildMPPReceipt(crypto.randomUUID()));
|
|
691
|
+
response.headers.set("Payment-Receipt", await buildMPPReceipt(crypto.randomUUID()));
|
|
656
692
|
} catch {
|
|
657
693
|
}
|
|
658
694
|
}
|
|
659
695
|
finalize(response, rawResult, meta, pluginCtx);
|
|
660
696
|
return response;
|
|
661
697
|
}
|
|
662
|
-
return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
698
|
+
return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
663
699
|
};
|
|
664
700
|
}
|
|
665
701
|
async function parseBody(request, routeEntry) {
|
|
@@ -696,7 +732,7 @@ function parseQuery(request, routeEntry) {
|
|
|
696
732
|
const result = routeEntry.querySchema.safeParse(params);
|
|
697
733
|
return result.success ? result.data : params;
|
|
698
734
|
}
|
|
699
|
-
function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
735
|
+
async function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
700
736
|
const response = new import_server2.NextResponse(null, { status: 402 });
|
|
701
737
|
let challengePrice;
|
|
702
738
|
if (routeEntry.maxPrice) {
|
|
@@ -712,8 +748,8 @@ function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
|
712
748
|
}
|
|
713
749
|
let extensions;
|
|
714
750
|
try {
|
|
715
|
-
const { z } =
|
|
716
|
-
const { declareDiscoveryExtension } =
|
|
751
|
+
const { z } = await import("zod");
|
|
752
|
+
const { declareDiscoveryExtension } = await import("@x402/extensions/bazaar");
|
|
717
753
|
const inputSchema = routeEntry.bodySchema ? z.toJSONSchema(routeEntry.bodySchema, { target: "draft-2020-12" }) : routeEntry.querySchema ? z.toJSONSchema(routeEntry.querySchema, { target: "draft-2020-12" }) : void 0;
|
|
718
754
|
const outputSchema = routeEntry.outputSchema ? z.toJSONSchema(routeEntry.outputSchema, { target: "draft-2020-12" }) : void 0;
|
|
719
755
|
if (inputSchema) {
|
|
@@ -728,7 +764,7 @@ function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
|
728
764
|
}
|
|
729
765
|
if (routeEntry.protocols.includes("x402") && deps.x402Server) {
|
|
730
766
|
try {
|
|
731
|
-
const { encoded } = buildX402Challenge(
|
|
767
|
+
const { encoded } = await buildX402Challenge(
|
|
732
768
|
deps.x402Server,
|
|
733
769
|
routeEntry,
|
|
734
770
|
request,
|
|
@@ -745,7 +781,7 @@ function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
|
745
781
|
try {
|
|
746
782
|
response.headers.set(
|
|
747
783
|
"WWW-Authenticate",
|
|
748
|
-
buildMPPChallenge(routeEntry, request, deps.mppConfig, challengePrice)
|
|
784
|
+
await buildMPPChallenge(routeEntry, request, deps.mppConfig, challengePrice)
|
|
749
785
|
);
|
|
750
786
|
} catch {
|
|
751
787
|
}
|
|
@@ -932,6 +968,11 @@ var RouteBuilder = class {
|
|
|
932
968
|
next._path = p;
|
|
933
969
|
return next;
|
|
934
970
|
}
|
|
971
|
+
method(m) {
|
|
972
|
+
const next = this.fork();
|
|
973
|
+
next._method = m;
|
|
974
|
+
return next;
|
|
975
|
+
}
|
|
935
976
|
handler(fn) {
|
|
936
977
|
const entry = {
|
|
937
978
|
key: this._key,
|
|
@@ -980,12 +1021,12 @@ function createWellKnownHandler(registry, baseUrl, pricesKeys, options = {}) {
|
|
|
980
1021
|
registry.validate(pricesKeys);
|
|
981
1022
|
validated = true;
|
|
982
1023
|
}
|
|
983
|
-
const
|
|
984
|
-
const
|
|
1024
|
+
const x402Set = /* @__PURE__ */ new Set();
|
|
1025
|
+
const mppSet = /* @__PURE__ */ new Set();
|
|
985
1026
|
for (const [key, entry] of registry.entries()) {
|
|
986
1027
|
const url = `${baseUrl}/api/${entry.path ?? key}`;
|
|
987
|
-
if (entry.
|
|
988
|
-
if (entry.protocols.includes("mpp"))
|
|
1028
|
+
if (entry.authMode !== "unprotected") x402Set.add(url);
|
|
1029
|
+
if (entry.protocols.includes("mpp")) mppSet.add(url);
|
|
989
1030
|
}
|
|
990
1031
|
let instructions;
|
|
991
1032
|
if (typeof options.instructions === "function") {
|
|
@@ -995,18 +1036,28 @@ function createWellKnownHandler(registry, baseUrl, pricesKeys, options = {}) {
|
|
|
995
1036
|
}
|
|
996
1037
|
const body = {
|
|
997
1038
|
version: 1,
|
|
998
|
-
resources:
|
|
1039
|
+
resources: Array.from(x402Set)
|
|
999
1040
|
};
|
|
1041
|
+
const mppResources = Array.from(mppSet);
|
|
1000
1042
|
if (mppResources.length > 0) {
|
|
1001
1043
|
body.mppResources = mppResources;
|
|
1002
1044
|
}
|
|
1045
|
+
if (options.description) {
|
|
1046
|
+
body.description = options.description;
|
|
1047
|
+
}
|
|
1003
1048
|
if (options.ownershipProofs) {
|
|
1004
1049
|
body.ownershipProofs = options.ownershipProofs;
|
|
1005
1050
|
}
|
|
1006
1051
|
if (instructions) {
|
|
1007
1052
|
body.instructions = instructions;
|
|
1008
1053
|
}
|
|
1009
|
-
return import_server3.NextResponse.json(body
|
|
1054
|
+
return import_server3.NextResponse.json(body, {
|
|
1055
|
+
headers: {
|
|
1056
|
+
"Access-Control-Allow-Origin": "*",
|
|
1057
|
+
"Access-Control-Allow-Methods": "GET",
|
|
1058
|
+
"Access-Control-Allow-Headers": "Content-Type"
|
|
1059
|
+
}
|
|
1060
|
+
});
|
|
1010
1061
|
};
|
|
1011
1062
|
}
|
|
1012
1063
|
|
|
@@ -1029,9 +1080,7 @@ function createOpenAPIHandler(registry, baseUrl, pricesKeys, options) {
|
|
|
1029
1080
|
const method = entry.method.toLowerCase();
|
|
1030
1081
|
const tag = deriveTag(key);
|
|
1031
1082
|
tagSet.add(tag);
|
|
1032
|
-
paths[apiPath] = {
|
|
1033
|
-
[method]: buildOperation(key, entry, tag)
|
|
1034
|
-
};
|
|
1083
|
+
paths[apiPath] = { ...paths[apiPath], [method]: buildOperation(key, entry, tag) };
|
|
1035
1084
|
}
|
|
1036
1085
|
cached = createDocument({
|
|
1037
1086
|
openapi: "3.1.0",
|
|
@@ -1122,16 +1171,17 @@ function createRouter(config) {
|
|
|
1122
1171
|
network,
|
|
1123
1172
|
mppConfig: config.mpp
|
|
1124
1173
|
};
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1174
|
+
deps.initPromise = (async () => {
|
|
1175
|
+
try {
|
|
1176
|
+
const { createX402Server: createX402Server2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
1177
|
+
const result = await createX402Server2(config);
|
|
1178
|
+
deps.x402Server = result.server;
|
|
1179
|
+
await result.initPromise;
|
|
1180
|
+
} catch (err) {
|
|
1130
1181
|
deps.x402Server = null;
|
|
1131
1182
|
deps.x402InitError = err instanceof Error ? err.message : String(err);
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1183
|
+
}
|
|
1184
|
+
})();
|
|
1135
1185
|
const pricesKeys = config.prices ? Object.keys(config.prices) : void 0;
|
|
1136
1186
|
return {
|
|
1137
1187
|
route(key) {
|
package/dist/index.d.cts
CHANGED
|
@@ -142,7 +142,7 @@ interface RouteEntry {
|
|
|
142
142
|
outputSchema?: ZodType;
|
|
143
143
|
description?: string;
|
|
144
144
|
path?: string;
|
|
145
|
-
method: 'GET' | 'POST';
|
|
145
|
+
method: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH';
|
|
146
146
|
maxPrice?: string;
|
|
147
147
|
apiKeyResolver?: (key: string) => unknown | Promise<unknown>;
|
|
148
148
|
providerName?: string;
|
|
@@ -175,6 +175,7 @@ declare class RouteRegistry {
|
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
interface WellKnownOptions {
|
|
178
|
+
description?: string;
|
|
178
179
|
instructions?: string | (() => string | Promise<string>);
|
|
179
180
|
ownershipProofs?: string[];
|
|
180
181
|
}
|
|
@@ -220,7 +221,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, HasAuth extend
|
|
|
220
221
|
/** @internal */ _outputSchema: ZodType | undefined;
|
|
221
222
|
/** @internal */ _description: string | undefined;
|
|
222
223
|
/** @internal */ _path: string | undefined;
|
|
223
|
-
/** @internal */ _method: 'GET' | 'POST';
|
|
224
|
+
/** @internal */ _method: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH';
|
|
224
225
|
/** @internal */ _apiKeyResolver: ((key: string) => unknown | Promise<unknown>) | undefined;
|
|
225
226
|
/** @internal */ _providerName: string | undefined;
|
|
226
227
|
/** @internal */ _providerConfig: ProviderConfig | undefined;
|
|
@@ -247,6 +248,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, HasAuth extend
|
|
|
247
248
|
output(schema: ZodType): this;
|
|
248
249
|
description(text: string): this;
|
|
249
250
|
path(p: string): this;
|
|
251
|
+
method(m: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH'): this;
|
|
250
252
|
handler(this: RouteBuilder<TBody, TQuery, True, true, false>, fn: never): never;
|
|
251
253
|
handler(this: RouteBuilder<TBody, TQuery, false, boolean, boolean>, fn: never): never;
|
|
252
254
|
handler(this: RouteBuilder<TBody, TQuery, True, False, HasBody>, fn: (ctx: HandlerContext<TBody, TQuery>) => Promise<unknown>): (request: NextRequest) => Promise<Response>;
|
package/dist/index.d.ts
CHANGED
|
@@ -142,7 +142,7 @@ interface RouteEntry {
|
|
|
142
142
|
outputSchema?: ZodType;
|
|
143
143
|
description?: string;
|
|
144
144
|
path?: string;
|
|
145
|
-
method: 'GET' | 'POST';
|
|
145
|
+
method: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH';
|
|
146
146
|
maxPrice?: string;
|
|
147
147
|
apiKeyResolver?: (key: string) => unknown | Promise<unknown>;
|
|
148
148
|
providerName?: string;
|
|
@@ -175,6 +175,7 @@ declare class RouteRegistry {
|
|
|
175
175
|
}
|
|
176
176
|
|
|
177
177
|
interface WellKnownOptions {
|
|
178
|
+
description?: string;
|
|
178
179
|
instructions?: string | (() => string | Promise<string>);
|
|
179
180
|
ownershipProofs?: string[];
|
|
180
181
|
}
|
|
@@ -220,7 +221,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, HasAuth extend
|
|
|
220
221
|
/** @internal */ _outputSchema: ZodType | undefined;
|
|
221
222
|
/** @internal */ _description: string | undefined;
|
|
222
223
|
/** @internal */ _path: string | undefined;
|
|
223
|
-
/** @internal */ _method: 'GET' | 'POST';
|
|
224
|
+
/** @internal */ _method: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH';
|
|
224
225
|
/** @internal */ _apiKeyResolver: ((key: string) => unknown | Promise<unknown>) | undefined;
|
|
225
226
|
/** @internal */ _providerName: string | undefined;
|
|
226
227
|
/** @internal */ _providerConfig: ProviderConfig | undefined;
|
|
@@ -247,6 +248,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, HasAuth extend
|
|
|
247
248
|
output(schema: ZodType): this;
|
|
248
249
|
description(text: string): this;
|
|
249
250
|
path(p: string): this;
|
|
251
|
+
method(m: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH'): this;
|
|
250
252
|
handler(this: RouteBuilder<TBody, TQuery, True, true, false>, fn: never): never;
|
|
251
253
|
handler(this: RouteBuilder<TBody, TQuery, false, boolean, boolean>, fn: never): never;
|
|
252
254
|
handler(this: RouteBuilder<TBody, TQuery, True, False, HasBody>, fn: (ctx: HandlerContext<TBody, TQuery>) => Promise<unknown>): (request: NextRequest) => Promise<Response>;
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
6
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
7
|
-
}) : x)(function(x) {
|
|
8
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
9
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
10
|
-
});
|
|
11
3
|
var __esm = (fn, res) => function __init() {
|
|
12
4
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
13
5
|
};
|
|
@@ -15,27 +7,18 @@ var __export = (target, all) => {
|
|
|
15
7
|
for (var name in all)
|
|
16
8
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
9
|
};
|
|
18
|
-
var __copyProps = (to, from, except, desc) => {
|
|
19
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
-
for (let key of __getOwnPropNames(from))
|
|
21
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
-
}
|
|
24
|
-
return to;
|
|
25
|
-
};
|
|
26
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
27
10
|
|
|
28
11
|
// src/server.ts
|
|
29
12
|
var server_exports = {};
|
|
30
13
|
__export(server_exports, {
|
|
31
14
|
createX402Server: () => createX402Server
|
|
32
15
|
});
|
|
33
|
-
function createX402Server(config) {
|
|
34
|
-
const { x402ResourceServer, HTTPFacilitatorClient } =
|
|
35
|
-
const { registerExactEvmScheme } =
|
|
36
|
-
const { bazaarResourceServerExtension } =
|
|
37
|
-
const { siwxResourceServerExtension } =
|
|
38
|
-
const { facilitator: defaultFacilitator } =
|
|
16
|
+
async function createX402Server(config) {
|
|
17
|
+
const { x402ResourceServer, HTTPFacilitatorClient } = await import("@x402/core/server");
|
|
18
|
+
const { registerExactEvmScheme } = await import("@x402/evm/exact/server");
|
|
19
|
+
const { bazaarResourceServerExtension } = await import("@x402/extensions/bazaar");
|
|
20
|
+
const { siwxResourceServerExtension } = await import("@x402/extensions/sign-in-with-x");
|
|
21
|
+
const { facilitator: defaultFacilitator } = await import("@coinbase/x402");
|
|
39
22
|
const facilitatorUrl = config.facilitatorUrl ?? defaultFacilitator;
|
|
40
23
|
const client = new HTTPFacilitatorClient(facilitatorUrl);
|
|
41
24
|
const server = new x402ResourceServer(client);
|
|
@@ -197,7 +180,7 @@ async function safeCallHandler(handler, ctx) {
|
|
|
197
180
|
if (result instanceof Response) return result;
|
|
198
181
|
return NextResponse.json(result);
|
|
199
182
|
} catch (error) {
|
|
200
|
-
const status = error instanceof HttpError ? error.status : 500;
|
|
183
|
+
const status = error instanceof HttpError ? error.status : typeof error.status === "number" ? error.status : 500;
|
|
201
184
|
const message = error instanceof Error ? error.message : "Internal error";
|
|
202
185
|
return NextResponse.json({ success: false, error: message }, { status });
|
|
203
186
|
}
|
|
@@ -271,8 +254,8 @@ function resolveMaxPrice(pricing) {
|
|
|
271
254
|
}
|
|
272
255
|
|
|
273
256
|
// src/protocols/x402.ts
|
|
274
|
-
function buildX402Challenge(server, routeEntry, request, price, payeeAddress, network, extensions) {
|
|
275
|
-
const { encodePaymentRequiredHeader } =
|
|
257
|
+
async function buildX402Challenge(server, routeEntry, request, price, payeeAddress, network, extensions) {
|
|
258
|
+
const { encodePaymentRequiredHeader } = await import("@x402/core/http");
|
|
276
259
|
const options = {
|
|
277
260
|
scheme: "exact",
|
|
278
261
|
network,
|
|
@@ -297,7 +280,7 @@ function buildX402Challenge(server, routeEntry, request, price, payeeAddress, ne
|
|
|
297
280
|
return { encoded, requirements };
|
|
298
281
|
}
|
|
299
282
|
async function verifyX402Payment(server, request, routeEntry, price, payeeAddress, network) {
|
|
300
|
-
const { decodePaymentSignatureHeader } =
|
|
283
|
+
const { decodePaymentSignatureHeader } = await import("@x402/core/http");
|
|
301
284
|
const paymentHeader = request.headers.get("PAYMENT-SIGNATURE") ?? request.headers.get("X-PAYMENT");
|
|
302
285
|
if (!paymentHeader) return null;
|
|
303
286
|
const payload = decodePaymentSignatureHeader(paymentHeader);
|
|
@@ -323,7 +306,7 @@ async function verifyX402Payment(server, request, routeEntry, price, payeeAddres
|
|
|
323
306
|
};
|
|
324
307
|
}
|
|
325
308
|
async function settleX402Payment(server, payload, requirements) {
|
|
326
|
-
const { encodePaymentResponseHeader } =
|
|
309
|
+
const { encodePaymentResponseHeader } = await import("@x402/core/http");
|
|
327
310
|
const result = await server.settlePayment(payload, requirements);
|
|
328
311
|
const encoded = encodePaymentResponseHeader(result);
|
|
329
312
|
return { encoded, result };
|
|
@@ -335,22 +318,22 @@ var Challenge;
|
|
|
335
318
|
var Credential;
|
|
336
319
|
var Receipt;
|
|
337
320
|
var tempo;
|
|
338
|
-
function ensureMpay() {
|
|
321
|
+
async function ensureMpay() {
|
|
339
322
|
if (mpayLoaded) return;
|
|
340
323
|
try {
|
|
341
|
-
const mpay =
|
|
324
|
+
const mpay = await import("mpay");
|
|
342
325
|
Challenge = mpay.Challenge;
|
|
343
326
|
Credential = mpay.Credential;
|
|
344
327
|
Receipt = mpay.Receipt;
|
|
345
|
-
const mpayServer =
|
|
328
|
+
const mpayServer = await import("mpay/server");
|
|
346
329
|
tempo = mpayServer.tempo;
|
|
347
330
|
mpayLoaded = true;
|
|
348
331
|
} catch {
|
|
349
332
|
throw new Error("mpay package is required for MPP protocol support. Install it: pnpm add mpay");
|
|
350
333
|
}
|
|
351
334
|
}
|
|
352
|
-
function buildMPPChallenge(routeEntry, request, mppConfig, price) {
|
|
353
|
-
ensureMpay();
|
|
335
|
+
async function buildMPPChallenge(routeEntry, request, mppConfig, price) {
|
|
336
|
+
await ensureMpay();
|
|
354
337
|
const intent = {
|
|
355
338
|
amount: price,
|
|
356
339
|
currency: mppConfig.currency,
|
|
@@ -364,7 +347,7 @@ function buildMPPChallenge(routeEntry, request, mppConfig, price) {
|
|
|
364
347
|
return Challenge.serialize(challenge);
|
|
365
348
|
}
|
|
366
349
|
async function verifyMPPCredential(request, _routeEntry, mppConfig, price) {
|
|
367
|
-
ensureMpay();
|
|
350
|
+
await ensureMpay();
|
|
368
351
|
const credential = Credential.fromRequest(request);
|
|
369
352
|
if (!credential) return null;
|
|
370
353
|
const isValid = Challenge.verify(credential, { secretKey: mppConfig.secretKey });
|
|
@@ -385,8 +368,8 @@ async function verifyMPPCredential(request, _routeEntry, mppConfig, price) {
|
|
|
385
368
|
payer: verifyResult.payer
|
|
386
369
|
};
|
|
387
370
|
}
|
|
388
|
-
function buildMPPReceipt(reference) {
|
|
389
|
-
ensureMpay();
|
|
371
|
+
async function buildMPPReceipt(reference) {
|
|
372
|
+
await ensureMpay();
|
|
390
373
|
const receipt = Receipt.from({
|
|
391
374
|
method: "tempo",
|
|
392
375
|
status: "success",
|
|
@@ -398,11 +381,7 @@ function buildMPPReceipt(reference) {
|
|
|
398
381
|
|
|
399
382
|
// src/auth/siwx.ts
|
|
400
383
|
async function verifySIWX(request, _routeEntry, nonceStore) {
|
|
401
|
-
const {
|
|
402
|
-
parseSIWxHeader,
|
|
403
|
-
validateSIWxMessage,
|
|
404
|
-
verifySIWxSignature
|
|
405
|
-
} = __require("@x402/extensions/sign-in-with-x");
|
|
384
|
+
const { parseSIWxHeader, validateSIWxMessage, verifySIWxSignature } = await import("@x402/extensions/sign-in-with-x");
|
|
406
385
|
const header = request.headers.get("SIGN-IN-WITH-X");
|
|
407
386
|
if (!header) return { valid: false, wallet: null };
|
|
408
387
|
const payload = parseSIWxHeader(header);
|
|
@@ -410,17 +389,17 @@ async function verifySIWX(request, _routeEntry, nonceStore) {
|
|
|
410
389
|
const validation = await validateSIWxMessage(payload, uri, {
|
|
411
390
|
checkNonce: (nonce) => nonceStore.check(nonce)
|
|
412
391
|
});
|
|
413
|
-
if (!validation.
|
|
392
|
+
if (!validation.valid) {
|
|
414
393
|
return { valid: false, wallet: null };
|
|
415
394
|
}
|
|
416
395
|
const verified = await verifySIWxSignature(payload);
|
|
417
|
-
if (!verified?.
|
|
396
|
+
if (!verified?.valid) {
|
|
418
397
|
return { valid: false, wallet: null };
|
|
419
398
|
}
|
|
420
399
|
return { valid: true, wallet: verified.address };
|
|
421
400
|
}
|
|
422
|
-
function buildSIWXExtension() {
|
|
423
|
-
const { declareSIWxExtension } =
|
|
401
|
+
async function buildSIWXExtension() {
|
|
402
|
+
const { declareSIWxExtension } = await import("@x402/extensions/sign-in-with-x");
|
|
424
403
|
return declareSIWxExtension();
|
|
425
404
|
}
|
|
426
405
|
|
|
@@ -520,11 +499,51 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
520
499
|
const protocol = detectProtocol(request);
|
|
521
500
|
if (routeEntry.authMode === "siwx") {
|
|
522
501
|
if (!request.headers.get("SIGN-IN-WITH-X")) {
|
|
523
|
-
const
|
|
502
|
+
const url = new URL(request.url);
|
|
503
|
+
const nonce = crypto.randomUUID();
|
|
504
|
+
const siwxInfo = {
|
|
505
|
+
domain: url.hostname,
|
|
506
|
+
uri: request.url,
|
|
507
|
+
version: "1",
|
|
508
|
+
chainId: deps.network,
|
|
509
|
+
type: "eip191",
|
|
510
|
+
nonce,
|
|
511
|
+
issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
512
|
+
expirationTime: new Date(Date.now() + 3e5).toISOString(),
|
|
513
|
+
statement: "Sign in to verify your wallet identity"
|
|
514
|
+
};
|
|
515
|
+
let siwxSchema;
|
|
524
516
|
try {
|
|
525
|
-
|
|
517
|
+
siwxSchema = await buildSIWXExtension();
|
|
526
518
|
} catch {
|
|
527
519
|
}
|
|
520
|
+
const paymentRequired = {
|
|
521
|
+
x402Version: 2,
|
|
522
|
+
error: "SIWX authentication required",
|
|
523
|
+
resource: {
|
|
524
|
+
url: request.url,
|
|
525
|
+
description: routeEntry.description ?? "SIWX-protected endpoint",
|
|
526
|
+
mimeType: "application/json"
|
|
527
|
+
},
|
|
528
|
+
accepts: [],
|
|
529
|
+
extensions: {
|
|
530
|
+
"sign-in-with-x": {
|
|
531
|
+
info: siwxInfo,
|
|
532
|
+
...siwxSchema ? { schema: siwxSchema } : {}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
let encoded;
|
|
537
|
+
try {
|
|
538
|
+
const { encodePaymentRequiredHeader } = await import("@x402/core/http");
|
|
539
|
+
encoded = encodePaymentRequiredHeader(paymentRequired);
|
|
540
|
+
} catch {
|
|
541
|
+
}
|
|
542
|
+
const response = new NextResponse2(JSON.stringify(paymentRequired), {
|
|
543
|
+
status: 402,
|
|
544
|
+
headers: { "Content-Type": "application/json" }
|
|
545
|
+
});
|
|
546
|
+
if (encoded) response.headers.set("PAYMENT-REQUIRED", encoded);
|
|
528
547
|
firePluginResponse(deps, pluginCtx, meta, response);
|
|
529
548
|
return response;
|
|
530
549
|
}
|
|
@@ -541,7 +560,7 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
541
560
|
return handleAuth(siwx.wallet, void 0);
|
|
542
561
|
}
|
|
543
562
|
if (!protocol || protocol === "siwx") {
|
|
544
|
-
return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
563
|
+
return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
545
564
|
}
|
|
546
565
|
const body = await parseBody(request, routeEntry);
|
|
547
566
|
if (!body.ok) {
|
|
@@ -572,7 +591,7 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
572
591
|
deps.payeeAddress,
|
|
573
592
|
deps.network
|
|
574
593
|
);
|
|
575
|
-
if (!verify?.valid) return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
594
|
+
if (!verify?.valid) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
576
595
|
pluginCtx.setVerifiedWallet(verify.payer);
|
|
577
596
|
firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
|
|
578
597
|
protocol: "x402",
|
|
@@ -614,9 +633,9 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
614
633
|
return response;
|
|
615
634
|
}
|
|
616
635
|
if (protocol === "mpp") {
|
|
617
|
-
if (!deps.mppConfig) return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
636
|
+
if (!deps.mppConfig) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
618
637
|
const verify = await verifyMPPCredential(request, routeEntry, deps.mppConfig, price);
|
|
619
|
-
if (!verify?.valid) return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
638
|
+
if (!verify?.valid) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
620
639
|
const wallet = verify.payer;
|
|
621
640
|
pluginCtx.setVerifiedWallet(wallet);
|
|
622
641
|
firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
|
|
@@ -635,14 +654,14 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
635
654
|
);
|
|
636
655
|
if (response.status < 400) {
|
|
637
656
|
try {
|
|
638
|
-
response.headers.set("Payment-Receipt", buildMPPReceipt(crypto.randomUUID()));
|
|
657
|
+
response.headers.set("Payment-Receipt", await buildMPPReceipt(crypto.randomUUID()));
|
|
639
658
|
} catch {
|
|
640
659
|
}
|
|
641
660
|
}
|
|
642
661
|
finalize(response, rawResult, meta, pluginCtx);
|
|
643
662
|
return response;
|
|
644
663
|
}
|
|
645
|
-
return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
664
|
+
return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
646
665
|
};
|
|
647
666
|
}
|
|
648
667
|
async function parseBody(request, routeEntry) {
|
|
@@ -679,7 +698,7 @@ function parseQuery(request, routeEntry) {
|
|
|
679
698
|
const result = routeEntry.querySchema.safeParse(params);
|
|
680
699
|
return result.success ? result.data : params;
|
|
681
700
|
}
|
|
682
|
-
function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
701
|
+
async function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
683
702
|
const response = new NextResponse2(null, { status: 402 });
|
|
684
703
|
let challengePrice;
|
|
685
704
|
if (routeEntry.maxPrice) {
|
|
@@ -695,8 +714,8 @@ function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
|
695
714
|
}
|
|
696
715
|
let extensions;
|
|
697
716
|
try {
|
|
698
|
-
const { z } =
|
|
699
|
-
const { declareDiscoveryExtension } =
|
|
717
|
+
const { z } = await import("zod");
|
|
718
|
+
const { declareDiscoveryExtension } = await import("@x402/extensions/bazaar");
|
|
700
719
|
const inputSchema = routeEntry.bodySchema ? z.toJSONSchema(routeEntry.bodySchema, { target: "draft-2020-12" }) : routeEntry.querySchema ? z.toJSONSchema(routeEntry.querySchema, { target: "draft-2020-12" }) : void 0;
|
|
701
720
|
const outputSchema = routeEntry.outputSchema ? z.toJSONSchema(routeEntry.outputSchema, { target: "draft-2020-12" }) : void 0;
|
|
702
721
|
if (inputSchema) {
|
|
@@ -711,7 +730,7 @@ function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
|
711
730
|
}
|
|
712
731
|
if (routeEntry.protocols.includes("x402") && deps.x402Server) {
|
|
713
732
|
try {
|
|
714
|
-
const { encoded } = buildX402Challenge(
|
|
733
|
+
const { encoded } = await buildX402Challenge(
|
|
715
734
|
deps.x402Server,
|
|
716
735
|
routeEntry,
|
|
717
736
|
request,
|
|
@@ -728,7 +747,7 @@ function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
|
728
747
|
try {
|
|
729
748
|
response.headers.set(
|
|
730
749
|
"WWW-Authenticate",
|
|
731
|
-
buildMPPChallenge(routeEntry, request, deps.mppConfig, challengePrice)
|
|
750
|
+
await buildMPPChallenge(routeEntry, request, deps.mppConfig, challengePrice)
|
|
732
751
|
);
|
|
733
752
|
} catch {
|
|
734
753
|
}
|
|
@@ -915,6 +934,11 @@ var RouteBuilder = class {
|
|
|
915
934
|
next._path = p;
|
|
916
935
|
return next;
|
|
917
936
|
}
|
|
937
|
+
method(m) {
|
|
938
|
+
const next = this.fork();
|
|
939
|
+
next._method = m;
|
|
940
|
+
return next;
|
|
941
|
+
}
|
|
918
942
|
handler(fn) {
|
|
919
943
|
const entry = {
|
|
920
944
|
key: this._key,
|
|
@@ -963,12 +987,12 @@ function createWellKnownHandler(registry, baseUrl, pricesKeys, options = {}) {
|
|
|
963
987
|
registry.validate(pricesKeys);
|
|
964
988
|
validated = true;
|
|
965
989
|
}
|
|
966
|
-
const
|
|
967
|
-
const
|
|
990
|
+
const x402Set = /* @__PURE__ */ new Set();
|
|
991
|
+
const mppSet = /* @__PURE__ */ new Set();
|
|
968
992
|
for (const [key, entry] of registry.entries()) {
|
|
969
993
|
const url = `${baseUrl}/api/${entry.path ?? key}`;
|
|
970
|
-
if (entry.
|
|
971
|
-
if (entry.protocols.includes("mpp"))
|
|
994
|
+
if (entry.authMode !== "unprotected") x402Set.add(url);
|
|
995
|
+
if (entry.protocols.includes("mpp")) mppSet.add(url);
|
|
972
996
|
}
|
|
973
997
|
let instructions;
|
|
974
998
|
if (typeof options.instructions === "function") {
|
|
@@ -978,18 +1002,28 @@ function createWellKnownHandler(registry, baseUrl, pricesKeys, options = {}) {
|
|
|
978
1002
|
}
|
|
979
1003
|
const body = {
|
|
980
1004
|
version: 1,
|
|
981
|
-
resources:
|
|
1005
|
+
resources: Array.from(x402Set)
|
|
982
1006
|
};
|
|
1007
|
+
const mppResources = Array.from(mppSet);
|
|
983
1008
|
if (mppResources.length > 0) {
|
|
984
1009
|
body.mppResources = mppResources;
|
|
985
1010
|
}
|
|
1011
|
+
if (options.description) {
|
|
1012
|
+
body.description = options.description;
|
|
1013
|
+
}
|
|
986
1014
|
if (options.ownershipProofs) {
|
|
987
1015
|
body.ownershipProofs = options.ownershipProofs;
|
|
988
1016
|
}
|
|
989
1017
|
if (instructions) {
|
|
990
1018
|
body.instructions = instructions;
|
|
991
1019
|
}
|
|
992
|
-
return NextResponse3.json(body
|
|
1020
|
+
return NextResponse3.json(body, {
|
|
1021
|
+
headers: {
|
|
1022
|
+
"Access-Control-Allow-Origin": "*",
|
|
1023
|
+
"Access-Control-Allow-Methods": "GET",
|
|
1024
|
+
"Access-Control-Allow-Headers": "Content-Type"
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
993
1027
|
};
|
|
994
1028
|
}
|
|
995
1029
|
|
|
@@ -1012,9 +1046,7 @@ function createOpenAPIHandler(registry, baseUrl, pricesKeys, options) {
|
|
|
1012
1046
|
const method = entry.method.toLowerCase();
|
|
1013
1047
|
const tag = deriveTag(key);
|
|
1014
1048
|
tagSet.add(tag);
|
|
1015
|
-
paths[apiPath] = {
|
|
1016
|
-
[method]: buildOperation(key, entry, tag)
|
|
1017
|
-
};
|
|
1049
|
+
paths[apiPath] = { ...paths[apiPath], [method]: buildOperation(key, entry, tag) };
|
|
1018
1050
|
}
|
|
1019
1051
|
cached = createDocument({
|
|
1020
1052
|
openapi: "3.1.0",
|
|
@@ -1105,16 +1137,17 @@ function createRouter(config) {
|
|
|
1105
1137
|
network,
|
|
1106
1138
|
mppConfig: config.mpp
|
|
1107
1139
|
};
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1140
|
+
deps.initPromise = (async () => {
|
|
1141
|
+
try {
|
|
1142
|
+
const { createX402Server: createX402Server2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
1143
|
+
const result = await createX402Server2(config);
|
|
1144
|
+
deps.x402Server = result.server;
|
|
1145
|
+
await result.initPromise;
|
|
1146
|
+
} catch (err) {
|
|
1113
1147
|
deps.x402Server = null;
|
|
1114
1148
|
deps.x402InitError = err instanceof Error ? err.message : String(err);
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1149
|
+
}
|
|
1150
|
+
})();
|
|
1118
1151
|
const pricesKeys = config.prices ? Object.keys(config.prices) : void 0;
|
|
1119
1152
|
return {
|
|
1120
1153
|
route(key) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentcash/router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
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": {
|
|
@@ -21,6 +21,17 @@
|
|
|
21
21
|
"files": [
|
|
22
22
|
"dist"
|
|
23
23
|
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"typecheck": "tsc --noEmit",
|
|
27
|
+
"lint": "eslint src/",
|
|
28
|
+
"lint:fix": "eslint src/ --fix",
|
|
29
|
+
"format": "prettier --write 'src/**/*.ts' 'tests/**/*.ts' '*.json' '*.mjs'",
|
|
30
|
+
"format:check": "prettier --check 'src/**/*.ts' 'tests/**/*.ts' '*.json' '*.mjs'",
|
|
31
|
+
"test": "vitest run",
|
|
32
|
+
"test:watch": "vitest",
|
|
33
|
+
"check": "pnpm format:check && pnpm lint && pnpm typecheck && pnpm build && pnpm test"
|
|
34
|
+
},
|
|
24
35
|
"peerDependencies": {
|
|
25
36
|
"@coinbase/x402": "^2.1.0",
|
|
26
37
|
"@x402/core": "^2.3.0",
|
|
@@ -55,20 +66,10 @@
|
|
|
55
66
|
"zod": "^4.0.0",
|
|
56
67
|
"zod-openapi": "^5.0.0"
|
|
57
68
|
},
|
|
69
|
+
"packageManager": "pnpm@10.28.0",
|
|
58
70
|
"license": "MIT",
|
|
59
71
|
"repository": {
|
|
60
72
|
"type": "git",
|
|
61
73
|
"url": "https://github.com/merit-systems/agentcash-router"
|
|
62
|
-
},
|
|
63
|
-
"scripts": {
|
|
64
|
-
"build": "tsup",
|
|
65
|
-
"typecheck": "tsc --noEmit",
|
|
66
|
-
"lint": "eslint src/",
|
|
67
|
-
"lint:fix": "eslint src/ --fix",
|
|
68
|
-
"format": "prettier --write 'src/**/*.ts' 'tests/**/*.ts' '*.json' '*.mjs'",
|
|
69
|
-
"format:check": "prettier --check 'src/**/*.ts' 'tests/**/*.ts' '*.json' '*.mjs'",
|
|
70
|
-
"test": "vitest run",
|
|
71
|
-
"test:watch": "vitest",
|
|
72
|
-
"check": "pnpm format:check && pnpm lint && pnpm typecheck && pnpm build && pnpm test"
|
|
73
74
|
}
|
|
74
|
-
}
|
|
75
|
+
}
|