@agentcash/router 0.1.0 → 0.2.1
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 +142 -72
- package/dist/index.d.cts +28 -4
- package/dist/index.d.ts +28 -4
- package/dist/index.js +142 -89
- package/package.json +15 -14
package/dist/index.cjs
CHANGED
|
@@ -35,14 +35,15 @@ 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 } =
|
|
44
|
-
const
|
|
45
|
-
const
|
|
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
|
+
const raw = config.facilitatorUrl ?? defaultFacilitator;
|
|
45
|
+
const facilitatorConfig = typeof raw === "string" ? { url: raw } : raw;
|
|
46
|
+
const client = new HTTPFacilitatorClient(facilitatorConfig);
|
|
46
47
|
const server = new x402ResourceServer(client);
|
|
47
48
|
registerExactEvmScheme(server);
|
|
48
49
|
server.registerExtension(bazaarResourceServerExtension);
|
|
@@ -53,7 +54,7 @@ function createX402Server(config) {
|
|
|
53
54
|
async function retryInit(server, maxAttempts = 3, backoff = [1e3, 2e3, 4e3]) {
|
|
54
55
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
55
56
|
try {
|
|
56
|
-
await server.
|
|
57
|
+
await server.initialize();
|
|
57
58
|
return;
|
|
58
59
|
} catch (err) {
|
|
59
60
|
const is429 = err instanceof Error && (err.message.includes("429") || err.message.includes("rate limit"));
|
|
@@ -214,7 +215,7 @@ async function safeCallHandler(handler, ctx) {
|
|
|
214
215
|
if (result instanceof Response) return result;
|
|
215
216
|
return import_server.NextResponse.json(result);
|
|
216
217
|
} catch (error) {
|
|
217
|
-
const status = error instanceof HttpError ? error.status : 500;
|
|
218
|
+
const status = error instanceof HttpError ? error.status : typeof error.status === "number" ? error.status : 500;
|
|
218
219
|
const message = error instanceof Error ? error.message : "Internal error";
|
|
219
220
|
return import_server.NextResponse.json({ success: false, error: message }, { status });
|
|
220
221
|
}
|
|
@@ -288,8 +289,8 @@ function resolveMaxPrice(pricing) {
|
|
|
288
289
|
}
|
|
289
290
|
|
|
290
291
|
// src/protocols/x402.ts
|
|
291
|
-
function buildX402Challenge(server, routeEntry, request, price, payeeAddress, network, extensions) {
|
|
292
|
-
const { encodePaymentRequiredHeader } =
|
|
292
|
+
async function buildX402Challenge(server, routeEntry, request, price, payeeAddress, network, extensions) {
|
|
293
|
+
const { encodePaymentRequiredHeader } = await import("@x402/core/http");
|
|
293
294
|
const options = {
|
|
294
295
|
scheme: "exact",
|
|
295
296
|
network,
|
|
@@ -301,10 +302,10 @@ function buildX402Challenge(server, routeEntry, request, price, payeeAddress, ne
|
|
|
301
302
|
method: routeEntry.method,
|
|
302
303
|
description: routeEntry.description
|
|
303
304
|
};
|
|
304
|
-
const requirements = server.buildPaymentRequirementsFromOptions(options, {
|
|
305
|
+
const requirements = await server.buildPaymentRequirementsFromOptions([options], {
|
|
305
306
|
request
|
|
306
307
|
});
|
|
307
|
-
const paymentRequired = server.createPaymentRequiredResponse(
|
|
308
|
+
const paymentRequired = await server.createPaymentRequiredResponse(
|
|
308
309
|
requirements,
|
|
309
310
|
resource,
|
|
310
311
|
null,
|
|
@@ -314,7 +315,7 @@ function buildX402Challenge(server, routeEntry, request, price, payeeAddress, ne
|
|
|
314
315
|
return { encoded, requirements };
|
|
315
316
|
}
|
|
316
317
|
async function verifyX402Payment(server, request, routeEntry, price, payeeAddress, network) {
|
|
317
|
-
const { decodePaymentSignatureHeader } =
|
|
318
|
+
const { decodePaymentSignatureHeader } = await import("@x402/core/http");
|
|
318
319
|
const paymentHeader = request.headers.get("PAYMENT-SIGNATURE") ?? request.headers.get("X-PAYMENT");
|
|
319
320
|
if (!paymentHeader) return null;
|
|
320
321
|
const payload = decodePaymentSignatureHeader(paymentHeader);
|
|
@@ -324,7 +325,7 @@ async function verifyX402Payment(server, request, routeEntry, price, payeeAddres
|
|
|
324
325
|
price,
|
|
325
326
|
payTo: payeeAddress
|
|
326
327
|
};
|
|
327
|
-
const requirements = server.buildPaymentRequirementsFromOptions(options, {
|
|
328
|
+
const requirements = await server.buildPaymentRequirementsFromOptions([options], {
|
|
328
329
|
request
|
|
329
330
|
});
|
|
330
331
|
const matching = server.findMatchingRequirements(requirements, payload);
|
|
@@ -340,7 +341,7 @@ async function verifyX402Payment(server, request, routeEntry, price, payeeAddres
|
|
|
340
341
|
};
|
|
341
342
|
}
|
|
342
343
|
async function settleX402Payment(server, payload, requirements) {
|
|
343
|
-
const { encodePaymentResponseHeader } =
|
|
344
|
+
const { encodePaymentResponseHeader } = await import("@x402/core/http");
|
|
344
345
|
const result = await server.settlePayment(payload, requirements);
|
|
345
346
|
const encoded = encodePaymentResponseHeader(result);
|
|
346
347
|
return { encoded, result };
|
|
@@ -352,28 +353,28 @@ var Challenge;
|
|
|
352
353
|
var Credential;
|
|
353
354
|
var Receipt;
|
|
354
355
|
var tempo;
|
|
355
|
-
function ensureMpay() {
|
|
356
|
+
async function ensureMpay() {
|
|
356
357
|
if (mpayLoaded) return;
|
|
357
358
|
try {
|
|
358
|
-
const mpay =
|
|
359
|
+
const mpay = await import("mpay");
|
|
359
360
|
Challenge = mpay.Challenge;
|
|
360
361
|
Credential = mpay.Credential;
|
|
361
362
|
Receipt = mpay.Receipt;
|
|
362
|
-
const mpayServer =
|
|
363
|
+
const mpayServer = await import("mpay/server");
|
|
363
364
|
tempo = mpayServer.tempo;
|
|
364
365
|
mpayLoaded = true;
|
|
365
366
|
} catch {
|
|
366
367
|
throw new Error("mpay package is required for MPP protocol support. Install it: pnpm add mpay");
|
|
367
368
|
}
|
|
368
369
|
}
|
|
369
|
-
function buildMPPChallenge(routeEntry, request, mppConfig, price) {
|
|
370
|
-
ensureMpay();
|
|
371
|
-
const
|
|
370
|
+
async function buildMPPChallenge(routeEntry, request, mppConfig, price) {
|
|
371
|
+
await ensureMpay();
|
|
372
|
+
const methodIntent = tempo.charge({
|
|
372
373
|
amount: price,
|
|
373
374
|
currency: mppConfig.currency,
|
|
374
375
|
recipient: mppConfig.recipient ?? ""
|
|
375
|
-
};
|
|
376
|
-
const challenge = Challenge.fromIntent(
|
|
376
|
+
});
|
|
377
|
+
const challenge = Challenge.fromIntent(methodIntent, {
|
|
377
378
|
secretKey: mppConfig.secretKey,
|
|
378
379
|
realm: new URL(request.url).origin,
|
|
379
380
|
request
|
|
@@ -381,10 +382,10 @@ function buildMPPChallenge(routeEntry, request, mppConfig, price) {
|
|
|
381
382
|
return Challenge.serialize(challenge);
|
|
382
383
|
}
|
|
383
384
|
async function verifyMPPCredential(request, _routeEntry, mppConfig, price) {
|
|
384
|
-
ensureMpay();
|
|
385
|
+
await ensureMpay();
|
|
385
386
|
const credential = Credential.fromRequest(request);
|
|
386
387
|
if (!credential) return null;
|
|
387
|
-
const isValid = Challenge.verify(credential, { secretKey: mppConfig.secretKey });
|
|
388
|
+
const isValid = Challenge.verify(credential.challenge, { secretKey: mppConfig.secretKey });
|
|
388
389
|
if (!isValid) {
|
|
389
390
|
return { valid: false, payer: null };
|
|
390
391
|
}
|
|
@@ -402,24 +403,20 @@ async function verifyMPPCredential(request, _routeEntry, mppConfig, price) {
|
|
|
402
403
|
payer: verifyResult.payer
|
|
403
404
|
};
|
|
404
405
|
}
|
|
405
|
-
function buildMPPReceipt(reference) {
|
|
406
|
-
ensureMpay();
|
|
406
|
+
async function buildMPPReceipt(reference) {
|
|
407
|
+
await ensureMpay();
|
|
407
408
|
const receipt = Receipt.from({
|
|
408
409
|
method: "tempo",
|
|
409
410
|
status: "success",
|
|
410
411
|
reference,
|
|
411
|
-
timestamp: Date.
|
|
412
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
412
413
|
});
|
|
413
414
|
return Receipt.serialize(receipt);
|
|
414
415
|
}
|
|
415
416
|
|
|
416
417
|
// src/auth/siwx.ts
|
|
417
418
|
async function verifySIWX(request, _routeEntry, nonceStore) {
|
|
418
|
-
const {
|
|
419
|
-
parseSIWxHeader,
|
|
420
|
-
validateSIWxMessage,
|
|
421
|
-
verifySIWxSignature
|
|
422
|
-
} = require("@x402/extensions/sign-in-with-x");
|
|
419
|
+
const { parseSIWxHeader, validateSIWxMessage, verifySIWxSignature } = await import("@x402/extensions/sign-in-with-x");
|
|
423
420
|
const header = request.headers.get("SIGN-IN-WITH-X");
|
|
424
421
|
if (!header) return { valid: false, wallet: null };
|
|
425
422
|
const payload = parseSIWxHeader(header);
|
|
@@ -427,17 +424,17 @@ async function verifySIWX(request, _routeEntry, nonceStore) {
|
|
|
427
424
|
const validation = await validateSIWxMessage(payload, uri, {
|
|
428
425
|
checkNonce: (nonce) => nonceStore.check(nonce)
|
|
429
426
|
});
|
|
430
|
-
if (!validation.
|
|
427
|
+
if (!validation.valid) {
|
|
431
428
|
return { valid: false, wallet: null };
|
|
432
429
|
}
|
|
433
430
|
const verified = await verifySIWxSignature(payload);
|
|
434
|
-
if (!verified?.
|
|
431
|
+
if (!verified?.valid) {
|
|
435
432
|
return { valid: false, wallet: null };
|
|
436
433
|
}
|
|
437
434
|
return { valid: true, wallet: verified.address };
|
|
438
435
|
}
|
|
439
|
-
function buildSIWXExtension() {
|
|
440
|
-
const { declareSIWxExtension } =
|
|
436
|
+
async function buildSIWXExtension() {
|
|
437
|
+
const { declareSIWxExtension } = await import("@x402/extensions/sign-in-with-x");
|
|
441
438
|
return declareSIWxExtension();
|
|
442
439
|
}
|
|
443
440
|
|
|
@@ -537,11 +534,56 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
537
534
|
const protocol = detectProtocol(request);
|
|
538
535
|
if (routeEntry.authMode === "siwx") {
|
|
539
536
|
if (!request.headers.get("SIGN-IN-WITH-X")) {
|
|
540
|
-
const
|
|
537
|
+
const url = new URL(request.url);
|
|
538
|
+
const nonce = crypto.randomUUID();
|
|
539
|
+
const siwxInfo = {
|
|
540
|
+
domain: url.hostname,
|
|
541
|
+
uri: request.url,
|
|
542
|
+
version: "1",
|
|
543
|
+
chainId: deps.network,
|
|
544
|
+
type: "eip191",
|
|
545
|
+
nonce,
|
|
546
|
+
issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
547
|
+
expirationTime: new Date(Date.now() + 3e5).toISOString(),
|
|
548
|
+
statement: "Sign in to verify your wallet identity"
|
|
549
|
+
};
|
|
550
|
+
let siwxSchema;
|
|
541
551
|
try {
|
|
542
|
-
|
|
552
|
+
siwxSchema = await buildSIWXExtension();
|
|
543
553
|
} catch {
|
|
544
554
|
}
|
|
555
|
+
const paymentRequired = {
|
|
556
|
+
x402Version: 2,
|
|
557
|
+
error: "SIWX authentication required",
|
|
558
|
+
resource: {
|
|
559
|
+
url: request.url,
|
|
560
|
+
description: routeEntry.description ?? "SIWX-protected endpoint",
|
|
561
|
+
mimeType: "application/json"
|
|
562
|
+
},
|
|
563
|
+
accepts: [],
|
|
564
|
+
extensions: {
|
|
565
|
+
"sign-in-with-x": {
|
|
566
|
+
info: siwxInfo,
|
|
567
|
+
...siwxSchema ? { schema: siwxSchema } : {}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
let encoded;
|
|
572
|
+
try {
|
|
573
|
+
const { encodePaymentRequiredHeader } = await import("@x402/core/http");
|
|
574
|
+
encoded = encodePaymentRequiredHeader(paymentRequired);
|
|
575
|
+
} catch (err) {
|
|
576
|
+
firePluginHook(deps.plugin, "onAlert", pluginCtx, {
|
|
577
|
+
level: "warn",
|
|
578
|
+
message: `SIWX challenge header encoding failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
579
|
+
route: routeEntry.key
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
const response = new import_server2.NextResponse(JSON.stringify(paymentRequired), {
|
|
583
|
+
status: 402,
|
|
584
|
+
headers: { "Content-Type": "application/json" }
|
|
585
|
+
});
|
|
586
|
+
if (encoded) response.headers.set("PAYMENT-REQUIRED", encoded);
|
|
545
587
|
firePluginResponse(deps, pluginCtx, meta, response);
|
|
546
588
|
return response;
|
|
547
589
|
}
|
|
@@ -558,7 +600,7 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
558
600
|
return handleAuth(siwx.wallet, void 0);
|
|
559
601
|
}
|
|
560
602
|
if (!protocol || protocol === "siwx") {
|
|
561
|
-
return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
603
|
+
return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
562
604
|
}
|
|
563
605
|
const body = await parseBody(request, routeEntry);
|
|
564
606
|
if (!body.ok) {
|
|
@@ -589,7 +631,7 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
589
631
|
deps.payeeAddress,
|
|
590
632
|
deps.network
|
|
591
633
|
);
|
|
592
|
-
if (!verify?.valid) return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
634
|
+
if (!verify?.valid) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
593
635
|
pluginCtx.setVerifiedWallet(verify.payer);
|
|
594
636
|
firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
|
|
595
637
|
protocol: "x402",
|
|
@@ -631,9 +673,9 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
631
673
|
return response;
|
|
632
674
|
}
|
|
633
675
|
if (protocol === "mpp") {
|
|
634
|
-
if (!deps.mppConfig) return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
676
|
+
if (!deps.mppConfig) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
635
677
|
const verify = await verifyMPPCredential(request, routeEntry, deps.mppConfig, price);
|
|
636
|
-
if (!verify?.valid) return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
678
|
+
if (!verify?.valid) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
637
679
|
const wallet = verify.payer;
|
|
638
680
|
pluginCtx.setVerifiedWallet(wallet);
|
|
639
681
|
firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
|
|
@@ -652,14 +694,14 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
652
694
|
);
|
|
653
695
|
if (response.status < 400) {
|
|
654
696
|
try {
|
|
655
|
-
response.headers.set("Payment-Receipt", buildMPPReceipt(crypto.randomUUID()));
|
|
697
|
+
response.headers.set("Payment-Receipt", await buildMPPReceipt(crypto.randomUUID()));
|
|
656
698
|
} catch {
|
|
657
699
|
}
|
|
658
700
|
}
|
|
659
701
|
finalize(response, rawResult, meta, pluginCtx);
|
|
660
702
|
return response;
|
|
661
703
|
}
|
|
662
|
-
return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
704
|
+
return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
663
705
|
};
|
|
664
706
|
}
|
|
665
707
|
async function parseBody(request, routeEntry) {
|
|
@@ -696,7 +738,7 @@ function parseQuery(request, routeEntry) {
|
|
|
696
738
|
const result = routeEntry.querySchema.safeParse(params);
|
|
697
739
|
return result.success ? result.data : params;
|
|
698
740
|
}
|
|
699
|
-
function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
741
|
+
async function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
700
742
|
const response = new import_server2.NextResponse(null, { status: 402 });
|
|
701
743
|
let challengePrice;
|
|
702
744
|
if (routeEntry.maxPrice) {
|
|
@@ -712,8 +754,8 @@ function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
|
712
754
|
}
|
|
713
755
|
let extensions;
|
|
714
756
|
try {
|
|
715
|
-
const { z } =
|
|
716
|
-
const { declareDiscoveryExtension } =
|
|
757
|
+
const { z } = await import("zod");
|
|
758
|
+
const { declareDiscoveryExtension } = await import("@x402/extensions/bazaar");
|
|
717
759
|
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
760
|
const outputSchema = routeEntry.outputSchema ? z.toJSONSchema(routeEntry.outputSchema, { target: "draft-2020-12" }) : void 0;
|
|
719
761
|
if (inputSchema) {
|
|
@@ -728,7 +770,7 @@ function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
|
728
770
|
}
|
|
729
771
|
if (routeEntry.protocols.includes("x402") && deps.x402Server) {
|
|
730
772
|
try {
|
|
731
|
-
const { encoded } = buildX402Challenge(
|
|
773
|
+
const { encoded } = await buildX402Challenge(
|
|
732
774
|
deps.x402Server,
|
|
733
775
|
routeEntry,
|
|
734
776
|
request,
|
|
@@ -738,16 +780,26 @@ function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
|
738
780
|
extensions
|
|
739
781
|
);
|
|
740
782
|
response.headers.set("PAYMENT-REQUIRED", encoded);
|
|
741
|
-
} catch {
|
|
783
|
+
} catch (err) {
|
|
784
|
+
firePluginHook(deps.plugin, "onAlert", pluginCtx, {
|
|
785
|
+
level: "critical",
|
|
786
|
+
message: `x402 challenge build failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
787
|
+
route: routeEntry.key
|
|
788
|
+
});
|
|
742
789
|
}
|
|
743
790
|
}
|
|
744
791
|
if (routeEntry.protocols.includes("mpp") && deps.mppConfig) {
|
|
745
792
|
try {
|
|
746
793
|
response.headers.set(
|
|
747
794
|
"WWW-Authenticate",
|
|
748
|
-
buildMPPChallenge(routeEntry, request, deps.mppConfig, challengePrice)
|
|
795
|
+
await buildMPPChallenge(routeEntry, request, deps.mppConfig, challengePrice)
|
|
749
796
|
);
|
|
750
|
-
} catch {
|
|
797
|
+
} catch (err) {
|
|
798
|
+
firePluginHook(deps.plugin, "onAlert", pluginCtx, {
|
|
799
|
+
level: "critical",
|
|
800
|
+
message: `MPP challenge build failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
801
|
+
route: routeEntry.key
|
|
802
|
+
});
|
|
751
803
|
}
|
|
752
804
|
}
|
|
753
805
|
firePluginResponse(deps, pluginCtx, meta, response);
|
|
@@ -932,6 +984,11 @@ var RouteBuilder = class {
|
|
|
932
984
|
next._path = p;
|
|
933
985
|
return next;
|
|
934
986
|
}
|
|
987
|
+
method(m) {
|
|
988
|
+
const next = this.fork();
|
|
989
|
+
next._method = m;
|
|
990
|
+
return next;
|
|
991
|
+
}
|
|
935
992
|
handler(fn) {
|
|
936
993
|
const entry = {
|
|
937
994
|
key: this._key,
|
|
@@ -980,12 +1037,12 @@ function createWellKnownHandler(registry, baseUrl, pricesKeys, options = {}) {
|
|
|
980
1037
|
registry.validate(pricesKeys);
|
|
981
1038
|
validated = true;
|
|
982
1039
|
}
|
|
983
|
-
const
|
|
984
|
-
const
|
|
1040
|
+
const x402Set = /* @__PURE__ */ new Set();
|
|
1041
|
+
const mppSet = /* @__PURE__ */ new Set();
|
|
985
1042
|
for (const [key, entry] of registry.entries()) {
|
|
986
1043
|
const url = `${baseUrl}/api/${entry.path ?? key}`;
|
|
987
|
-
if (entry.
|
|
988
|
-
if (entry.protocols.includes("mpp"))
|
|
1044
|
+
if (entry.authMode !== "unprotected") x402Set.add(url);
|
|
1045
|
+
if (entry.protocols.includes("mpp")) mppSet.add(url);
|
|
989
1046
|
}
|
|
990
1047
|
let instructions;
|
|
991
1048
|
if (typeof options.instructions === "function") {
|
|
@@ -995,18 +1052,28 @@ function createWellKnownHandler(registry, baseUrl, pricesKeys, options = {}) {
|
|
|
995
1052
|
}
|
|
996
1053
|
const body = {
|
|
997
1054
|
version: 1,
|
|
998
|
-
resources:
|
|
1055
|
+
resources: Array.from(x402Set)
|
|
999
1056
|
};
|
|
1057
|
+
const mppResources = Array.from(mppSet);
|
|
1000
1058
|
if (mppResources.length > 0) {
|
|
1001
1059
|
body.mppResources = mppResources;
|
|
1002
1060
|
}
|
|
1061
|
+
if (options.description) {
|
|
1062
|
+
body.description = options.description;
|
|
1063
|
+
}
|
|
1003
1064
|
if (options.ownershipProofs) {
|
|
1004
1065
|
body.ownershipProofs = options.ownershipProofs;
|
|
1005
1066
|
}
|
|
1006
1067
|
if (instructions) {
|
|
1007
1068
|
body.instructions = instructions;
|
|
1008
1069
|
}
|
|
1009
|
-
return import_server3.NextResponse.json(body
|
|
1070
|
+
return import_server3.NextResponse.json(body, {
|
|
1071
|
+
headers: {
|
|
1072
|
+
"Access-Control-Allow-Origin": "*",
|
|
1073
|
+
"Access-Control-Allow-Methods": "GET",
|
|
1074
|
+
"Access-Control-Allow-Headers": "Content-Type"
|
|
1075
|
+
}
|
|
1076
|
+
});
|
|
1010
1077
|
};
|
|
1011
1078
|
}
|
|
1012
1079
|
|
|
@@ -1029,9 +1096,7 @@ function createOpenAPIHandler(registry, baseUrl, pricesKeys, options) {
|
|
|
1029
1096
|
const method = entry.method.toLowerCase();
|
|
1030
1097
|
const tag = deriveTag(key);
|
|
1031
1098
|
tagSet.add(tag);
|
|
1032
|
-
paths[apiPath] = {
|
|
1033
|
-
[method]: buildOperation(key, entry, tag)
|
|
1034
|
-
};
|
|
1099
|
+
paths[apiPath] = { ...paths[apiPath], [method]: buildOperation(key, entry, tag) };
|
|
1035
1100
|
}
|
|
1036
1101
|
cached = createDocument({
|
|
1037
1102
|
openapi: "3.1.0",
|
|
@@ -1109,7 +1174,11 @@ function createRouter(config) {
|
|
|
1109
1174
|
const baseUrl = typeof globalThis.process !== "undefined" ? process.env.NEXT_PUBLIC_BASE_URL ?? "http://localhost:3000" : "http://localhost:3000";
|
|
1110
1175
|
if (config.plugin?.init) {
|
|
1111
1176
|
try {
|
|
1112
|
-
config.plugin.init({ origin: baseUrl });
|
|
1177
|
+
const result = config.plugin.init({ origin: baseUrl });
|
|
1178
|
+
if (result && typeof result.catch === "function") {
|
|
1179
|
+
result.catch(() => {
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1113
1182
|
} catch {
|
|
1114
1183
|
}
|
|
1115
1184
|
}
|
|
@@ -1122,16 +1191,17 @@ function createRouter(config) {
|
|
|
1122
1191
|
network,
|
|
1123
1192
|
mppConfig: config.mpp
|
|
1124
1193
|
};
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1194
|
+
deps.initPromise = (async () => {
|
|
1195
|
+
try {
|
|
1196
|
+
const { createX402Server: createX402Server2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
1197
|
+
const result = await createX402Server2(config);
|
|
1198
|
+
deps.x402Server = result.server;
|
|
1199
|
+
await result.initPromise;
|
|
1200
|
+
} catch (err) {
|
|
1130
1201
|
deps.x402Server = null;
|
|
1131
1202
|
deps.x402InitError = err instanceof Error ? err.message : String(err);
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1203
|
+
}
|
|
1204
|
+
})();
|
|
1135
1205
|
const pricesKeys = config.prices ? Object.keys(config.prices) : void 0;
|
|
1136
1206
|
return {
|
|
1137
1207
|
route(key) {
|
package/dist/index.d.cts
CHANGED
|
@@ -82,6 +82,28 @@ interface AlertEvent {
|
|
|
82
82
|
meta?: Record<string, unknown>;
|
|
83
83
|
}
|
|
84
84
|
type AlertFn = (level: AlertLevel, message: string, meta?: Record<string, unknown>) => void;
|
|
85
|
+
interface X402Server {
|
|
86
|
+
initialize(): Promise<void>;
|
|
87
|
+
buildPaymentRequirementsFromOptions(options: Array<{
|
|
88
|
+
scheme: string;
|
|
89
|
+
network: string;
|
|
90
|
+
price: string;
|
|
91
|
+
payTo: string;
|
|
92
|
+
}>, context: {
|
|
93
|
+
request: Request;
|
|
94
|
+
}): Promise<unknown[]>;
|
|
95
|
+
createPaymentRequiredResponse(requirements: unknown[], resource: {
|
|
96
|
+
url: string;
|
|
97
|
+
method: string;
|
|
98
|
+
description?: string;
|
|
99
|
+
}, error: string | null, extensions?: Record<string, unknown>): Promise<unknown>;
|
|
100
|
+
findMatchingRequirements(requirements: unknown[], payload: unknown): unknown;
|
|
101
|
+
verifyPayment(payload: unknown, requirements: unknown): Promise<{
|
|
102
|
+
isValid: boolean;
|
|
103
|
+
payer?: string;
|
|
104
|
+
}>;
|
|
105
|
+
settlePayment(payload: unknown, requirements: unknown): Promise<unknown>;
|
|
106
|
+
}
|
|
85
107
|
type ProtocolType = 'x402' | 'mpp';
|
|
86
108
|
type AuthMode = 'paid' | 'siwx' | 'apiKey' | 'unprotected';
|
|
87
109
|
interface TierConfig {
|
|
@@ -142,7 +164,7 @@ interface RouteEntry {
|
|
|
142
164
|
outputSchema?: ZodType;
|
|
143
165
|
description?: string;
|
|
144
166
|
path?: string;
|
|
145
|
-
method: 'GET' | 'POST';
|
|
167
|
+
method: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH';
|
|
146
168
|
maxPrice?: string;
|
|
147
169
|
apiKeyResolver?: (key: string) => unknown | Promise<unknown>;
|
|
148
170
|
providerName?: string;
|
|
@@ -175,6 +197,7 @@ declare class RouteRegistry {
|
|
|
175
197
|
}
|
|
176
198
|
|
|
177
199
|
interface WellKnownOptions {
|
|
200
|
+
description?: string;
|
|
178
201
|
instructions?: string | (() => string | Promise<string>);
|
|
179
202
|
ownershipProofs?: string[];
|
|
180
203
|
}
|
|
@@ -191,7 +214,7 @@ interface OpenAPIOptions {
|
|
|
191
214
|
}
|
|
192
215
|
|
|
193
216
|
interface OrchestrateDeps {
|
|
194
|
-
x402Server:
|
|
217
|
+
x402Server: X402Server | null;
|
|
195
218
|
initPromise: Promise<void>;
|
|
196
219
|
x402InitError?: string;
|
|
197
220
|
plugin?: RouterPlugin;
|
|
@@ -220,7 +243,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, HasAuth extend
|
|
|
220
243
|
/** @internal */ _outputSchema: ZodType | undefined;
|
|
221
244
|
/** @internal */ _description: string | undefined;
|
|
222
245
|
/** @internal */ _path: string | undefined;
|
|
223
|
-
/** @internal */ _method: 'GET' | 'POST';
|
|
246
|
+
/** @internal */ _method: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH';
|
|
224
247
|
/** @internal */ _apiKeyResolver: ((key: string) => unknown | Promise<unknown>) | undefined;
|
|
225
248
|
/** @internal */ _providerName: string | undefined;
|
|
226
249
|
/** @internal */ _providerConfig: ProviderConfig | undefined;
|
|
@@ -247,6 +270,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, HasAuth extend
|
|
|
247
270
|
output(schema: ZodType): this;
|
|
248
271
|
description(text: string): this;
|
|
249
272
|
path(p: string): this;
|
|
273
|
+
method(m: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH'): this;
|
|
250
274
|
handler(this: RouteBuilder<TBody, TQuery, True, true, false>, fn: never): never;
|
|
251
275
|
handler(this: RouteBuilder<TBody, TQuery, false, boolean, boolean>, fn: never): never;
|
|
252
276
|
handler(this: RouteBuilder<TBody, TQuery, True, False, HasBody>, fn: (ctx: HandlerContext<TBody, TQuery>) => Promise<unknown>): (request: NextRequest) => Promise<Response>;
|
|
@@ -270,4 +294,4 @@ interface ServiceRouter {
|
|
|
270
294
|
}
|
|
271
295
|
declare function createRouter(config: RouterConfig): ServiceRouter;
|
|
272
296
|
|
|
273
|
-
export { type AlertEvent, type AlertFn, type AlertLevel, type AuthMode, type ErrorEvent, type HandlerContext, HttpError, MemoryNonceStore, type MonitorEntry, type NonceStore, type OveragePolicy, type PaidOptions, type PaymentEvent, type PluginContext, type PricingConfig, type ProtocolType, type ProviderConfig, type ProviderQuotaEvent, type QuotaInfo, type QuotaLevel, type RequestMeta, type ResponseMeta, RouteBuilder, type RouteEntry, RouteRegistry, type RouterConfig, type RouterPlugin, type ServiceRouter, type SettlementEvent, type TierConfig, consolePlugin, createRouter };
|
|
297
|
+
export { type AlertEvent, type AlertFn, type AlertLevel, type AuthMode, type ErrorEvent, type HandlerContext, HttpError, MemoryNonceStore, type MonitorEntry, type NonceStore, type OveragePolicy, type PaidOptions, type PaymentEvent, type PluginContext, type PricingConfig, type ProtocolType, type ProviderConfig, type ProviderQuotaEvent, type QuotaInfo, type QuotaLevel, type RequestMeta, type ResponseMeta, RouteBuilder, type RouteEntry, RouteRegistry, type RouterConfig, type RouterPlugin, type ServiceRouter, type SettlementEvent, type TierConfig, type X402Server, consolePlugin, createRouter };
|
package/dist/index.d.ts
CHANGED
|
@@ -82,6 +82,28 @@ interface AlertEvent {
|
|
|
82
82
|
meta?: Record<string, unknown>;
|
|
83
83
|
}
|
|
84
84
|
type AlertFn = (level: AlertLevel, message: string, meta?: Record<string, unknown>) => void;
|
|
85
|
+
interface X402Server {
|
|
86
|
+
initialize(): Promise<void>;
|
|
87
|
+
buildPaymentRequirementsFromOptions(options: Array<{
|
|
88
|
+
scheme: string;
|
|
89
|
+
network: string;
|
|
90
|
+
price: string;
|
|
91
|
+
payTo: string;
|
|
92
|
+
}>, context: {
|
|
93
|
+
request: Request;
|
|
94
|
+
}): Promise<unknown[]>;
|
|
95
|
+
createPaymentRequiredResponse(requirements: unknown[], resource: {
|
|
96
|
+
url: string;
|
|
97
|
+
method: string;
|
|
98
|
+
description?: string;
|
|
99
|
+
}, error: string | null, extensions?: Record<string, unknown>): Promise<unknown>;
|
|
100
|
+
findMatchingRequirements(requirements: unknown[], payload: unknown): unknown;
|
|
101
|
+
verifyPayment(payload: unknown, requirements: unknown): Promise<{
|
|
102
|
+
isValid: boolean;
|
|
103
|
+
payer?: string;
|
|
104
|
+
}>;
|
|
105
|
+
settlePayment(payload: unknown, requirements: unknown): Promise<unknown>;
|
|
106
|
+
}
|
|
85
107
|
type ProtocolType = 'x402' | 'mpp';
|
|
86
108
|
type AuthMode = 'paid' | 'siwx' | 'apiKey' | 'unprotected';
|
|
87
109
|
interface TierConfig {
|
|
@@ -142,7 +164,7 @@ interface RouteEntry {
|
|
|
142
164
|
outputSchema?: ZodType;
|
|
143
165
|
description?: string;
|
|
144
166
|
path?: string;
|
|
145
|
-
method: 'GET' | 'POST';
|
|
167
|
+
method: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH';
|
|
146
168
|
maxPrice?: string;
|
|
147
169
|
apiKeyResolver?: (key: string) => unknown | Promise<unknown>;
|
|
148
170
|
providerName?: string;
|
|
@@ -175,6 +197,7 @@ declare class RouteRegistry {
|
|
|
175
197
|
}
|
|
176
198
|
|
|
177
199
|
interface WellKnownOptions {
|
|
200
|
+
description?: string;
|
|
178
201
|
instructions?: string | (() => string | Promise<string>);
|
|
179
202
|
ownershipProofs?: string[];
|
|
180
203
|
}
|
|
@@ -191,7 +214,7 @@ interface OpenAPIOptions {
|
|
|
191
214
|
}
|
|
192
215
|
|
|
193
216
|
interface OrchestrateDeps {
|
|
194
|
-
x402Server:
|
|
217
|
+
x402Server: X402Server | null;
|
|
195
218
|
initPromise: Promise<void>;
|
|
196
219
|
x402InitError?: string;
|
|
197
220
|
plugin?: RouterPlugin;
|
|
@@ -220,7 +243,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, HasAuth extend
|
|
|
220
243
|
/** @internal */ _outputSchema: ZodType | undefined;
|
|
221
244
|
/** @internal */ _description: string | undefined;
|
|
222
245
|
/** @internal */ _path: string | undefined;
|
|
223
|
-
/** @internal */ _method: 'GET' | 'POST';
|
|
246
|
+
/** @internal */ _method: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH';
|
|
224
247
|
/** @internal */ _apiKeyResolver: ((key: string) => unknown | Promise<unknown>) | undefined;
|
|
225
248
|
/** @internal */ _providerName: string | undefined;
|
|
226
249
|
/** @internal */ _providerConfig: ProviderConfig | undefined;
|
|
@@ -247,6 +270,7 @@ declare class RouteBuilder<TBody = undefined, TQuery = undefined, HasAuth extend
|
|
|
247
270
|
output(schema: ZodType): this;
|
|
248
271
|
description(text: string): this;
|
|
249
272
|
path(p: string): this;
|
|
273
|
+
method(m: 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH'): this;
|
|
250
274
|
handler(this: RouteBuilder<TBody, TQuery, True, true, false>, fn: never): never;
|
|
251
275
|
handler(this: RouteBuilder<TBody, TQuery, false, boolean, boolean>, fn: never): never;
|
|
252
276
|
handler(this: RouteBuilder<TBody, TQuery, True, False, HasBody>, fn: (ctx: HandlerContext<TBody, TQuery>) => Promise<unknown>): (request: NextRequest) => Promise<Response>;
|
|
@@ -270,4 +294,4 @@ interface ServiceRouter {
|
|
|
270
294
|
}
|
|
271
295
|
declare function createRouter(config: RouterConfig): ServiceRouter;
|
|
272
296
|
|
|
273
|
-
export { type AlertEvent, type AlertFn, type AlertLevel, type AuthMode, type ErrorEvent, type HandlerContext, HttpError, MemoryNonceStore, type MonitorEntry, type NonceStore, type OveragePolicy, type PaidOptions, type PaymentEvent, type PluginContext, type PricingConfig, type ProtocolType, type ProviderConfig, type ProviderQuotaEvent, type QuotaInfo, type QuotaLevel, type RequestMeta, type ResponseMeta, RouteBuilder, type RouteEntry, RouteRegistry, type RouterConfig, type RouterPlugin, type ServiceRouter, type SettlementEvent, type TierConfig, consolePlugin, createRouter };
|
|
297
|
+
export { type AlertEvent, type AlertFn, type AlertLevel, type AuthMode, type ErrorEvent, type HandlerContext, HttpError, MemoryNonceStore, type MonitorEntry, type NonceStore, type OveragePolicy, type PaidOptions, type PaymentEvent, type PluginContext, type PricingConfig, type ProtocolType, type ProviderConfig, type ProviderQuotaEvent, type QuotaInfo, type QuotaLevel, type RequestMeta, type ResponseMeta, RouteBuilder, type RouteEntry, RouteRegistry, type RouterConfig, type RouterPlugin, type ServiceRouter, type SettlementEvent, type TierConfig, type X402Server, consolePlugin, createRouter };
|
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,29 +7,21 @@ 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 } =
|
|
39
|
-
const
|
|
40
|
-
const
|
|
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");
|
|
22
|
+
const raw = config.facilitatorUrl ?? defaultFacilitator;
|
|
23
|
+
const facilitatorConfig = typeof raw === "string" ? { url: raw } : raw;
|
|
24
|
+
const client = new HTTPFacilitatorClient(facilitatorConfig);
|
|
41
25
|
const server = new x402ResourceServer(client);
|
|
42
26
|
registerExactEvmScheme(server);
|
|
43
27
|
server.registerExtension(bazaarResourceServerExtension);
|
|
@@ -48,7 +32,7 @@ function createX402Server(config) {
|
|
|
48
32
|
async function retryInit(server, maxAttempts = 3, backoff = [1e3, 2e3, 4e3]) {
|
|
49
33
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
50
34
|
try {
|
|
51
|
-
await server.
|
|
35
|
+
await server.initialize();
|
|
52
36
|
return;
|
|
53
37
|
} catch (err) {
|
|
54
38
|
const is429 = err instanceof Error && (err.message.includes("429") || err.message.includes("rate limit"));
|
|
@@ -197,7 +181,7 @@ async function safeCallHandler(handler, ctx) {
|
|
|
197
181
|
if (result instanceof Response) return result;
|
|
198
182
|
return NextResponse.json(result);
|
|
199
183
|
} catch (error) {
|
|
200
|
-
const status = error instanceof HttpError ? error.status : 500;
|
|
184
|
+
const status = error instanceof HttpError ? error.status : typeof error.status === "number" ? error.status : 500;
|
|
201
185
|
const message = error instanceof Error ? error.message : "Internal error";
|
|
202
186
|
return NextResponse.json({ success: false, error: message }, { status });
|
|
203
187
|
}
|
|
@@ -271,8 +255,8 @@ function resolveMaxPrice(pricing) {
|
|
|
271
255
|
}
|
|
272
256
|
|
|
273
257
|
// src/protocols/x402.ts
|
|
274
|
-
function buildX402Challenge(server, routeEntry, request, price, payeeAddress, network, extensions) {
|
|
275
|
-
const { encodePaymentRequiredHeader } =
|
|
258
|
+
async function buildX402Challenge(server, routeEntry, request, price, payeeAddress, network, extensions) {
|
|
259
|
+
const { encodePaymentRequiredHeader } = await import("@x402/core/http");
|
|
276
260
|
const options = {
|
|
277
261
|
scheme: "exact",
|
|
278
262
|
network,
|
|
@@ -284,10 +268,10 @@ function buildX402Challenge(server, routeEntry, request, price, payeeAddress, ne
|
|
|
284
268
|
method: routeEntry.method,
|
|
285
269
|
description: routeEntry.description
|
|
286
270
|
};
|
|
287
|
-
const requirements = server.buildPaymentRequirementsFromOptions(options, {
|
|
271
|
+
const requirements = await server.buildPaymentRequirementsFromOptions([options], {
|
|
288
272
|
request
|
|
289
273
|
});
|
|
290
|
-
const paymentRequired = server.createPaymentRequiredResponse(
|
|
274
|
+
const paymentRequired = await server.createPaymentRequiredResponse(
|
|
291
275
|
requirements,
|
|
292
276
|
resource,
|
|
293
277
|
null,
|
|
@@ -297,7 +281,7 @@ function buildX402Challenge(server, routeEntry, request, price, payeeAddress, ne
|
|
|
297
281
|
return { encoded, requirements };
|
|
298
282
|
}
|
|
299
283
|
async function verifyX402Payment(server, request, routeEntry, price, payeeAddress, network) {
|
|
300
|
-
const { decodePaymentSignatureHeader } =
|
|
284
|
+
const { decodePaymentSignatureHeader } = await import("@x402/core/http");
|
|
301
285
|
const paymentHeader = request.headers.get("PAYMENT-SIGNATURE") ?? request.headers.get("X-PAYMENT");
|
|
302
286
|
if (!paymentHeader) return null;
|
|
303
287
|
const payload = decodePaymentSignatureHeader(paymentHeader);
|
|
@@ -307,7 +291,7 @@ async function verifyX402Payment(server, request, routeEntry, price, payeeAddres
|
|
|
307
291
|
price,
|
|
308
292
|
payTo: payeeAddress
|
|
309
293
|
};
|
|
310
|
-
const requirements = server.buildPaymentRequirementsFromOptions(options, {
|
|
294
|
+
const requirements = await server.buildPaymentRequirementsFromOptions([options], {
|
|
311
295
|
request
|
|
312
296
|
});
|
|
313
297
|
const matching = server.findMatchingRequirements(requirements, payload);
|
|
@@ -323,7 +307,7 @@ async function verifyX402Payment(server, request, routeEntry, price, payeeAddres
|
|
|
323
307
|
};
|
|
324
308
|
}
|
|
325
309
|
async function settleX402Payment(server, payload, requirements) {
|
|
326
|
-
const { encodePaymentResponseHeader } =
|
|
310
|
+
const { encodePaymentResponseHeader } = await import("@x402/core/http");
|
|
327
311
|
const result = await server.settlePayment(payload, requirements);
|
|
328
312
|
const encoded = encodePaymentResponseHeader(result);
|
|
329
313
|
return { encoded, result };
|
|
@@ -335,28 +319,28 @@ var Challenge;
|
|
|
335
319
|
var Credential;
|
|
336
320
|
var Receipt;
|
|
337
321
|
var tempo;
|
|
338
|
-
function ensureMpay() {
|
|
322
|
+
async function ensureMpay() {
|
|
339
323
|
if (mpayLoaded) return;
|
|
340
324
|
try {
|
|
341
|
-
const mpay =
|
|
325
|
+
const mpay = await import("mpay");
|
|
342
326
|
Challenge = mpay.Challenge;
|
|
343
327
|
Credential = mpay.Credential;
|
|
344
328
|
Receipt = mpay.Receipt;
|
|
345
|
-
const mpayServer =
|
|
329
|
+
const mpayServer = await import("mpay/server");
|
|
346
330
|
tempo = mpayServer.tempo;
|
|
347
331
|
mpayLoaded = true;
|
|
348
332
|
} catch {
|
|
349
333
|
throw new Error("mpay package is required for MPP protocol support. Install it: pnpm add mpay");
|
|
350
334
|
}
|
|
351
335
|
}
|
|
352
|
-
function buildMPPChallenge(routeEntry, request, mppConfig, price) {
|
|
353
|
-
ensureMpay();
|
|
354
|
-
const
|
|
336
|
+
async function buildMPPChallenge(routeEntry, request, mppConfig, price) {
|
|
337
|
+
await ensureMpay();
|
|
338
|
+
const methodIntent = tempo.charge({
|
|
355
339
|
amount: price,
|
|
356
340
|
currency: mppConfig.currency,
|
|
357
341
|
recipient: mppConfig.recipient ?? ""
|
|
358
|
-
};
|
|
359
|
-
const challenge = Challenge.fromIntent(
|
|
342
|
+
});
|
|
343
|
+
const challenge = Challenge.fromIntent(methodIntent, {
|
|
360
344
|
secretKey: mppConfig.secretKey,
|
|
361
345
|
realm: new URL(request.url).origin,
|
|
362
346
|
request
|
|
@@ -364,10 +348,10 @@ function buildMPPChallenge(routeEntry, request, mppConfig, price) {
|
|
|
364
348
|
return Challenge.serialize(challenge);
|
|
365
349
|
}
|
|
366
350
|
async function verifyMPPCredential(request, _routeEntry, mppConfig, price) {
|
|
367
|
-
ensureMpay();
|
|
351
|
+
await ensureMpay();
|
|
368
352
|
const credential = Credential.fromRequest(request);
|
|
369
353
|
if (!credential) return null;
|
|
370
|
-
const isValid = Challenge.verify(credential, { secretKey: mppConfig.secretKey });
|
|
354
|
+
const isValid = Challenge.verify(credential.challenge, { secretKey: mppConfig.secretKey });
|
|
371
355
|
if (!isValid) {
|
|
372
356
|
return { valid: false, payer: null };
|
|
373
357
|
}
|
|
@@ -385,24 +369,20 @@ async function verifyMPPCredential(request, _routeEntry, mppConfig, price) {
|
|
|
385
369
|
payer: verifyResult.payer
|
|
386
370
|
};
|
|
387
371
|
}
|
|
388
|
-
function buildMPPReceipt(reference) {
|
|
389
|
-
ensureMpay();
|
|
372
|
+
async function buildMPPReceipt(reference) {
|
|
373
|
+
await ensureMpay();
|
|
390
374
|
const receipt = Receipt.from({
|
|
391
375
|
method: "tempo",
|
|
392
376
|
status: "success",
|
|
393
377
|
reference,
|
|
394
|
-
timestamp: Date.
|
|
378
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
395
379
|
});
|
|
396
380
|
return Receipt.serialize(receipt);
|
|
397
381
|
}
|
|
398
382
|
|
|
399
383
|
// src/auth/siwx.ts
|
|
400
384
|
async function verifySIWX(request, _routeEntry, nonceStore) {
|
|
401
|
-
const {
|
|
402
|
-
parseSIWxHeader,
|
|
403
|
-
validateSIWxMessage,
|
|
404
|
-
verifySIWxSignature
|
|
405
|
-
} = __require("@x402/extensions/sign-in-with-x");
|
|
385
|
+
const { parseSIWxHeader, validateSIWxMessage, verifySIWxSignature } = await import("@x402/extensions/sign-in-with-x");
|
|
406
386
|
const header = request.headers.get("SIGN-IN-WITH-X");
|
|
407
387
|
if (!header) return { valid: false, wallet: null };
|
|
408
388
|
const payload = parseSIWxHeader(header);
|
|
@@ -410,17 +390,17 @@ async function verifySIWX(request, _routeEntry, nonceStore) {
|
|
|
410
390
|
const validation = await validateSIWxMessage(payload, uri, {
|
|
411
391
|
checkNonce: (nonce) => nonceStore.check(nonce)
|
|
412
392
|
});
|
|
413
|
-
if (!validation.
|
|
393
|
+
if (!validation.valid) {
|
|
414
394
|
return { valid: false, wallet: null };
|
|
415
395
|
}
|
|
416
396
|
const verified = await verifySIWxSignature(payload);
|
|
417
|
-
if (!verified?.
|
|
397
|
+
if (!verified?.valid) {
|
|
418
398
|
return { valid: false, wallet: null };
|
|
419
399
|
}
|
|
420
400
|
return { valid: true, wallet: verified.address };
|
|
421
401
|
}
|
|
422
|
-
function buildSIWXExtension() {
|
|
423
|
-
const { declareSIWxExtension } =
|
|
402
|
+
async function buildSIWXExtension() {
|
|
403
|
+
const { declareSIWxExtension } = await import("@x402/extensions/sign-in-with-x");
|
|
424
404
|
return declareSIWxExtension();
|
|
425
405
|
}
|
|
426
406
|
|
|
@@ -520,11 +500,56 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
520
500
|
const protocol = detectProtocol(request);
|
|
521
501
|
if (routeEntry.authMode === "siwx") {
|
|
522
502
|
if (!request.headers.get("SIGN-IN-WITH-X")) {
|
|
523
|
-
const
|
|
503
|
+
const url = new URL(request.url);
|
|
504
|
+
const nonce = crypto.randomUUID();
|
|
505
|
+
const siwxInfo = {
|
|
506
|
+
domain: url.hostname,
|
|
507
|
+
uri: request.url,
|
|
508
|
+
version: "1",
|
|
509
|
+
chainId: deps.network,
|
|
510
|
+
type: "eip191",
|
|
511
|
+
nonce,
|
|
512
|
+
issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
513
|
+
expirationTime: new Date(Date.now() + 3e5).toISOString(),
|
|
514
|
+
statement: "Sign in to verify your wallet identity"
|
|
515
|
+
};
|
|
516
|
+
let siwxSchema;
|
|
524
517
|
try {
|
|
525
|
-
|
|
518
|
+
siwxSchema = await buildSIWXExtension();
|
|
526
519
|
} catch {
|
|
527
520
|
}
|
|
521
|
+
const paymentRequired = {
|
|
522
|
+
x402Version: 2,
|
|
523
|
+
error: "SIWX authentication required",
|
|
524
|
+
resource: {
|
|
525
|
+
url: request.url,
|
|
526
|
+
description: routeEntry.description ?? "SIWX-protected endpoint",
|
|
527
|
+
mimeType: "application/json"
|
|
528
|
+
},
|
|
529
|
+
accepts: [],
|
|
530
|
+
extensions: {
|
|
531
|
+
"sign-in-with-x": {
|
|
532
|
+
info: siwxInfo,
|
|
533
|
+
...siwxSchema ? { schema: siwxSchema } : {}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
let encoded;
|
|
538
|
+
try {
|
|
539
|
+
const { encodePaymentRequiredHeader } = await import("@x402/core/http");
|
|
540
|
+
encoded = encodePaymentRequiredHeader(paymentRequired);
|
|
541
|
+
} catch (err) {
|
|
542
|
+
firePluginHook(deps.plugin, "onAlert", pluginCtx, {
|
|
543
|
+
level: "warn",
|
|
544
|
+
message: `SIWX challenge header encoding failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
545
|
+
route: routeEntry.key
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
const response = new NextResponse2(JSON.stringify(paymentRequired), {
|
|
549
|
+
status: 402,
|
|
550
|
+
headers: { "Content-Type": "application/json" }
|
|
551
|
+
});
|
|
552
|
+
if (encoded) response.headers.set("PAYMENT-REQUIRED", encoded);
|
|
528
553
|
firePluginResponse(deps, pluginCtx, meta, response);
|
|
529
554
|
return response;
|
|
530
555
|
}
|
|
@@ -541,7 +566,7 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
541
566
|
return handleAuth(siwx.wallet, void 0);
|
|
542
567
|
}
|
|
543
568
|
if (!protocol || protocol === "siwx") {
|
|
544
|
-
return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
569
|
+
return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
545
570
|
}
|
|
546
571
|
const body = await parseBody(request, routeEntry);
|
|
547
572
|
if (!body.ok) {
|
|
@@ -572,7 +597,7 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
572
597
|
deps.payeeAddress,
|
|
573
598
|
deps.network
|
|
574
599
|
);
|
|
575
|
-
if (!verify?.valid) return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
600
|
+
if (!verify?.valid) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
576
601
|
pluginCtx.setVerifiedWallet(verify.payer);
|
|
577
602
|
firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
|
|
578
603
|
protocol: "x402",
|
|
@@ -614,9 +639,9 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
614
639
|
return response;
|
|
615
640
|
}
|
|
616
641
|
if (protocol === "mpp") {
|
|
617
|
-
if (!deps.mppConfig) return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
642
|
+
if (!deps.mppConfig) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
618
643
|
const verify = await verifyMPPCredential(request, routeEntry, deps.mppConfig, price);
|
|
619
|
-
if (!verify?.valid) return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
644
|
+
if (!verify?.valid) return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
620
645
|
const wallet = verify.payer;
|
|
621
646
|
pluginCtx.setVerifiedWallet(wallet);
|
|
622
647
|
firePluginHook(deps.plugin, "onPaymentVerified", pluginCtx, {
|
|
@@ -635,14 +660,14 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
635
660
|
);
|
|
636
661
|
if (response.status < 400) {
|
|
637
662
|
try {
|
|
638
|
-
response.headers.set("Payment-Receipt", buildMPPReceipt(crypto.randomUUID()));
|
|
663
|
+
response.headers.set("Payment-Receipt", await buildMPPReceipt(crypto.randomUUID()));
|
|
639
664
|
} catch {
|
|
640
665
|
}
|
|
641
666
|
}
|
|
642
667
|
finalize(response, rawResult, meta, pluginCtx);
|
|
643
668
|
return response;
|
|
644
669
|
}
|
|
645
|
-
return build402(request, routeEntry, deps, meta, pluginCtx);
|
|
670
|
+
return await build402(request, routeEntry, deps, meta, pluginCtx);
|
|
646
671
|
};
|
|
647
672
|
}
|
|
648
673
|
async function parseBody(request, routeEntry) {
|
|
@@ -679,7 +704,7 @@ function parseQuery(request, routeEntry) {
|
|
|
679
704
|
const result = routeEntry.querySchema.safeParse(params);
|
|
680
705
|
return result.success ? result.data : params;
|
|
681
706
|
}
|
|
682
|
-
function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
707
|
+
async function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
683
708
|
const response = new NextResponse2(null, { status: 402 });
|
|
684
709
|
let challengePrice;
|
|
685
710
|
if (routeEntry.maxPrice) {
|
|
@@ -695,8 +720,8 @@ function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
|
695
720
|
}
|
|
696
721
|
let extensions;
|
|
697
722
|
try {
|
|
698
|
-
const { z } =
|
|
699
|
-
const { declareDiscoveryExtension } =
|
|
723
|
+
const { z } = await import("zod");
|
|
724
|
+
const { declareDiscoveryExtension } = await import("@x402/extensions/bazaar");
|
|
700
725
|
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
726
|
const outputSchema = routeEntry.outputSchema ? z.toJSONSchema(routeEntry.outputSchema, { target: "draft-2020-12" }) : void 0;
|
|
702
727
|
if (inputSchema) {
|
|
@@ -711,7 +736,7 @@ function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
|
711
736
|
}
|
|
712
737
|
if (routeEntry.protocols.includes("x402") && deps.x402Server) {
|
|
713
738
|
try {
|
|
714
|
-
const { encoded } = buildX402Challenge(
|
|
739
|
+
const { encoded } = await buildX402Challenge(
|
|
715
740
|
deps.x402Server,
|
|
716
741
|
routeEntry,
|
|
717
742
|
request,
|
|
@@ -721,16 +746,26 @@ function build402(request, routeEntry, deps, meta, pluginCtx) {
|
|
|
721
746
|
extensions
|
|
722
747
|
);
|
|
723
748
|
response.headers.set("PAYMENT-REQUIRED", encoded);
|
|
724
|
-
} catch {
|
|
749
|
+
} catch (err) {
|
|
750
|
+
firePluginHook(deps.plugin, "onAlert", pluginCtx, {
|
|
751
|
+
level: "critical",
|
|
752
|
+
message: `x402 challenge build failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
753
|
+
route: routeEntry.key
|
|
754
|
+
});
|
|
725
755
|
}
|
|
726
756
|
}
|
|
727
757
|
if (routeEntry.protocols.includes("mpp") && deps.mppConfig) {
|
|
728
758
|
try {
|
|
729
759
|
response.headers.set(
|
|
730
760
|
"WWW-Authenticate",
|
|
731
|
-
buildMPPChallenge(routeEntry, request, deps.mppConfig, challengePrice)
|
|
761
|
+
await buildMPPChallenge(routeEntry, request, deps.mppConfig, challengePrice)
|
|
732
762
|
);
|
|
733
|
-
} catch {
|
|
763
|
+
} catch (err) {
|
|
764
|
+
firePluginHook(deps.plugin, "onAlert", pluginCtx, {
|
|
765
|
+
level: "critical",
|
|
766
|
+
message: `MPP challenge build failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
767
|
+
route: routeEntry.key
|
|
768
|
+
});
|
|
734
769
|
}
|
|
735
770
|
}
|
|
736
771
|
firePluginResponse(deps, pluginCtx, meta, response);
|
|
@@ -915,6 +950,11 @@ var RouteBuilder = class {
|
|
|
915
950
|
next._path = p;
|
|
916
951
|
return next;
|
|
917
952
|
}
|
|
953
|
+
method(m) {
|
|
954
|
+
const next = this.fork();
|
|
955
|
+
next._method = m;
|
|
956
|
+
return next;
|
|
957
|
+
}
|
|
918
958
|
handler(fn) {
|
|
919
959
|
const entry = {
|
|
920
960
|
key: this._key,
|
|
@@ -963,12 +1003,12 @@ function createWellKnownHandler(registry, baseUrl, pricesKeys, options = {}) {
|
|
|
963
1003
|
registry.validate(pricesKeys);
|
|
964
1004
|
validated = true;
|
|
965
1005
|
}
|
|
966
|
-
const
|
|
967
|
-
const
|
|
1006
|
+
const x402Set = /* @__PURE__ */ new Set();
|
|
1007
|
+
const mppSet = /* @__PURE__ */ new Set();
|
|
968
1008
|
for (const [key, entry] of registry.entries()) {
|
|
969
1009
|
const url = `${baseUrl}/api/${entry.path ?? key}`;
|
|
970
|
-
if (entry.
|
|
971
|
-
if (entry.protocols.includes("mpp"))
|
|
1010
|
+
if (entry.authMode !== "unprotected") x402Set.add(url);
|
|
1011
|
+
if (entry.protocols.includes("mpp")) mppSet.add(url);
|
|
972
1012
|
}
|
|
973
1013
|
let instructions;
|
|
974
1014
|
if (typeof options.instructions === "function") {
|
|
@@ -978,18 +1018,28 @@ function createWellKnownHandler(registry, baseUrl, pricesKeys, options = {}) {
|
|
|
978
1018
|
}
|
|
979
1019
|
const body = {
|
|
980
1020
|
version: 1,
|
|
981
|
-
resources:
|
|
1021
|
+
resources: Array.from(x402Set)
|
|
982
1022
|
};
|
|
1023
|
+
const mppResources = Array.from(mppSet);
|
|
983
1024
|
if (mppResources.length > 0) {
|
|
984
1025
|
body.mppResources = mppResources;
|
|
985
1026
|
}
|
|
1027
|
+
if (options.description) {
|
|
1028
|
+
body.description = options.description;
|
|
1029
|
+
}
|
|
986
1030
|
if (options.ownershipProofs) {
|
|
987
1031
|
body.ownershipProofs = options.ownershipProofs;
|
|
988
1032
|
}
|
|
989
1033
|
if (instructions) {
|
|
990
1034
|
body.instructions = instructions;
|
|
991
1035
|
}
|
|
992
|
-
return NextResponse3.json(body
|
|
1036
|
+
return NextResponse3.json(body, {
|
|
1037
|
+
headers: {
|
|
1038
|
+
"Access-Control-Allow-Origin": "*",
|
|
1039
|
+
"Access-Control-Allow-Methods": "GET",
|
|
1040
|
+
"Access-Control-Allow-Headers": "Content-Type"
|
|
1041
|
+
}
|
|
1042
|
+
});
|
|
993
1043
|
};
|
|
994
1044
|
}
|
|
995
1045
|
|
|
@@ -1012,9 +1062,7 @@ function createOpenAPIHandler(registry, baseUrl, pricesKeys, options) {
|
|
|
1012
1062
|
const method = entry.method.toLowerCase();
|
|
1013
1063
|
const tag = deriveTag(key);
|
|
1014
1064
|
tagSet.add(tag);
|
|
1015
|
-
paths[apiPath] = {
|
|
1016
|
-
[method]: buildOperation(key, entry, tag)
|
|
1017
|
-
};
|
|
1065
|
+
paths[apiPath] = { ...paths[apiPath], [method]: buildOperation(key, entry, tag) };
|
|
1018
1066
|
}
|
|
1019
1067
|
cached = createDocument({
|
|
1020
1068
|
openapi: "3.1.0",
|
|
@@ -1092,7 +1140,11 @@ function createRouter(config) {
|
|
|
1092
1140
|
const baseUrl = typeof globalThis.process !== "undefined" ? process.env.NEXT_PUBLIC_BASE_URL ?? "http://localhost:3000" : "http://localhost:3000";
|
|
1093
1141
|
if (config.plugin?.init) {
|
|
1094
1142
|
try {
|
|
1095
|
-
config.plugin.init({ origin: baseUrl });
|
|
1143
|
+
const result = config.plugin.init({ origin: baseUrl });
|
|
1144
|
+
if (result && typeof result.catch === "function") {
|
|
1145
|
+
result.catch(() => {
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1096
1148
|
} catch {
|
|
1097
1149
|
}
|
|
1098
1150
|
}
|
|
@@ -1105,16 +1157,17 @@ function createRouter(config) {
|
|
|
1105
1157
|
network,
|
|
1106
1158
|
mppConfig: config.mpp
|
|
1107
1159
|
};
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1160
|
+
deps.initPromise = (async () => {
|
|
1161
|
+
try {
|
|
1162
|
+
const { createX402Server: createX402Server2 } = await Promise.resolve().then(() => (init_server(), server_exports));
|
|
1163
|
+
const result = await createX402Server2(config);
|
|
1164
|
+
deps.x402Server = result.server;
|
|
1165
|
+
await result.initPromise;
|
|
1166
|
+
} catch (err) {
|
|
1113
1167
|
deps.x402Server = null;
|
|
1114
1168
|
deps.x402InitError = err instanceof Error ? err.message : String(err);
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1169
|
+
}
|
|
1170
|
+
})();
|
|
1118
1171
|
const pricesKeys = config.prices ? Object.keys(config.prices) : void 0;
|
|
1119
1172
|
return {
|
|
1120
1173
|
route(key) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentcash/router",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
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
|
-
"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
|
+
"url": "git+https://github.com/merit-systems/agentcash-router.git"
|
|
73
74
|
}
|
|
74
|
-
}
|
|
75
|
+
}
|