@agentcash/router 0.6.3 → 0.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/CLAUDE.md +14 -0
- package/dist/index.cjs +29 -31
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +29 -31
- package/package.json +1 -1
package/.claude/CLAUDE.md
CHANGED
|
@@ -131,6 +131,20 @@ router
|
|
|
131
131
|
|
|
132
132
|
## Environment Variables
|
|
133
133
|
|
|
134
|
+
### Base URL Resolution
|
|
135
|
+
|
|
136
|
+
`baseUrl` is auto-detected — most consumers don't need to pass it:
|
|
137
|
+
|
|
138
|
+
1. **`config.baseUrl`** — Explicit override (for non-Vercel deployments)
|
|
139
|
+
2. **`VERCEL_URL`** — Auto-detected on Vercel (set by the platform on every build and deployment)
|
|
140
|
+
3. **`localhost:PORT`** — Fallback for local dev (`PORT` env var, defaults to 3000)
|
|
141
|
+
|
|
142
|
+
In production on a non-Vercel host, pass `baseUrl` explicitly. On Vercel, it just works. In dev, it just works. No custom env vars needed.
|
|
143
|
+
|
|
144
|
+
**Do NOT use `NEXT_PUBLIC_BASE_URL`.** It was removed in 0.6.5. The library handles base URL resolution internally.
|
|
145
|
+
|
|
146
|
+
### CDP API Keys
|
|
147
|
+
|
|
134
148
|
The router uses the default facilitator from `@coinbase/x402`, which requires CDP API keys in `process.env`:
|
|
135
149
|
|
|
136
150
|
- `CDP_API_KEY_ID` — Coinbase Developer Platform API key ID
|
package/dist/index.cjs
CHANGED
|
@@ -382,7 +382,8 @@ async function buildX402Challenge(server, routeEntry, request, price, payeeAddre
|
|
|
382
382
|
const resource = {
|
|
383
383
|
url: request.url,
|
|
384
384
|
method: routeEntry.method,
|
|
385
|
-
description: routeEntry.description
|
|
385
|
+
description: routeEntry.description,
|
|
386
|
+
mimeType: "application/json"
|
|
386
387
|
};
|
|
387
388
|
const requirements = await server.buildPaymentRequirementsFromOptions([options], {
|
|
388
389
|
request
|
|
@@ -605,18 +606,16 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
605
606
|
if (needsEarlyParse) {
|
|
606
607
|
const requestForPricing = request.clone();
|
|
607
608
|
const earlyBodyResult = await parseBody(requestForPricing, routeEntry);
|
|
608
|
-
if (
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
const message = err instanceof Error ? err.message : "Validation failed";
|
|
619
|
-
return fail(status, message, meta, pluginCtx, earlyBodyData);
|
|
609
|
+
if (earlyBodyResult.ok) {
|
|
610
|
+
earlyBodyData = earlyBodyResult.data;
|
|
611
|
+
if (routeEntry.validateFn) {
|
|
612
|
+
try {
|
|
613
|
+
await routeEntry.validateFn(earlyBodyData);
|
|
614
|
+
} catch (err) {
|
|
615
|
+
const status = err.status ?? 400;
|
|
616
|
+
const message = err instanceof Error ? err.message : "Validation failed";
|
|
617
|
+
return fail(status, message, meta, pluginCtx, earlyBodyData);
|
|
618
|
+
}
|
|
620
619
|
}
|
|
621
620
|
}
|
|
622
621
|
}
|
|
@@ -624,16 +623,14 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
624
623
|
if (routeEntry.validateFn && routeEntry.bodySchema && !request.headers.get("SIGN-IN-WITH-X")) {
|
|
625
624
|
const requestForValidation = request.clone();
|
|
626
625
|
const earlyBodyResult = await parseBody(requestForValidation, routeEntry);
|
|
627
|
-
if (
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
const message = err instanceof Error ? err.message : "Validation failed";
|
|
636
|
-
return fail(status, message, meta, pluginCtx, earlyBodyResult.data);
|
|
626
|
+
if (earlyBodyResult.ok) {
|
|
627
|
+
try {
|
|
628
|
+
await routeEntry.validateFn(earlyBodyResult.data);
|
|
629
|
+
} catch (err) {
|
|
630
|
+
const status = err.status ?? 400;
|
|
631
|
+
const message = err instanceof Error ? err.message : "Validation failed";
|
|
632
|
+
return fail(status, message, meta, pluginCtx, earlyBodyResult.data);
|
|
633
|
+
}
|
|
637
634
|
}
|
|
638
635
|
}
|
|
639
636
|
if (!request.headers.get("SIGN-IN-WITH-X")) {
|
|
@@ -1470,20 +1467,21 @@ function createRouter(config) {
|
|
|
1470
1467
|
const registry = new RouteRegistry();
|
|
1471
1468
|
const nonceStore = config.siwx?.nonceStore ?? new MemoryNonceStore();
|
|
1472
1469
|
const network = config.network ?? "eip155:8453";
|
|
1473
|
-
const baseUrl = config.baseUrl ?? (typeof globalThis.process !== "undefined" ? process.env.
|
|
1470
|
+
const baseUrl = config.baseUrl ?? (typeof globalThis.process !== "undefined" && process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : void 0);
|
|
1474
1471
|
if (config.protocols && config.protocols.length === 0) {
|
|
1475
1472
|
throw new Error(
|
|
1476
1473
|
"RouterConfig.protocols cannot be empty. Omit the field to use default ['x402'] or specify protocols explicitly."
|
|
1477
1474
|
);
|
|
1478
1475
|
}
|
|
1479
|
-
if (!baseUrl) {
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
}
|
|
1484
|
-
console.warn(`[router] ${msg}`);
|
|
1476
|
+
if (!baseUrl && process.env.NODE_ENV === "production") {
|
|
1477
|
+
console.warn(
|
|
1478
|
+
"[router] baseUrl was not provided and VERCEL_URL is not set. Falling back to localhost. Pass baseUrl in RouterConfig for non-Vercel deployments."
|
|
1479
|
+
);
|
|
1485
1480
|
}
|
|
1486
|
-
const resolvedBaseUrl = (baseUrl ??
|
|
1481
|
+
const resolvedBaseUrl = (baseUrl ?? `http://localhost:${process.env.PORT ?? 3e3}`).replace(
|
|
1482
|
+
/\/+$/,
|
|
1483
|
+
""
|
|
1484
|
+
);
|
|
1487
1485
|
let x402ConfigError;
|
|
1488
1486
|
let mppConfigError;
|
|
1489
1487
|
if ((!config.protocols || config.protocols.includes("x402")) && !config.payeeAddress) {
|
package/dist/index.d.cts
CHANGED
|
@@ -235,11 +235,11 @@ interface RouteEntry {
|
|
|
235
235
|
interface RouterConfig {
|
|
236
236
|
payeeAddress: string;
|
|
237
237
|
/**
|
|
238
|
-
*
|
|
238
|
+
* Origin URL (e.g. `https://myapp.com`).
|
|
239
239
|
* Used for discovery URLs, OpenAPI servers, and MPP realm.
|
|
240
240
|
*
|
|
241
|
-
* Falls back to `
|
|
242
|
-
*
|
|
241
|
+
* Auto-detected on Vercel via `VERCEL_URL`. Falls back to `localhost:PORT` in dev.
|
|
242
|
+
* Only needed for non-Vercel production deployments.
|
|
243
243
|
*/
|
|
244
244
|
baseUrl?: string;
|
|
245
245
|
network?: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -235,11 +235,11 @@ interface RouteEntry {
|
|
|
235
235
|
interface RouterConfig {
|
|
236
236
|
payeeAddress: string;
|
|
237
237
|
/**
|
|
238
|
-
*
|
|
238
|
+
* Origin URL (e.g. `https://myapp.com`).
|
|
239
239
|
* Used for discovery URLs, OpenAPI servers, and MPP realm.
|
|
240
240
|
*
|
|
241
|
-
* Falls back to `
|
|
242
|
-
*
|
|
241
|
+
* Auto-detected on Vercel via `VERCEL_URL`. Falls back to `localhost:PORT` in dev.
|
|
242
|
+
* Only needed for non-Vercel production deployments.
|
|
243
243
|
*/
|
|
244
244
|
baseUrl?: string;
|
|
245
245
|
network?: string;
|
package/dist/index.js
CHANGED
|
@@ -345,7 +345,8 @@ async function buildX402Challenge(server, routeEntry, request, price, payeeAddre
|
|
|
345
345
|
const resource = {
|
|
346
346
|
url: request.url,
|
|
347
347
|
method: routeEntry.method,
|
|
348
|
-
description: routeEntry.description
|
|
348
|
+
description: routeEntry.description,
|
|
349
|
+
mimeType: "application/json"
|
|
349
350
|
};
|
|
350
351
|
const requirements = await server.buildPaymentRequirementsFromOptions([options], {
|
|
351
352
|
request
|
|
@@ -568,18 +569,16 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
568
569
|
if (needsEarlyParse) {
|
|
569
570
|
const requestForPricing = request.clone();
|
|
570
571
|
const earlyBodyResult = await parseBody(requestForPricing, routeEntry);
|
|
571
|
-
if (
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
const message = err instanceof Error ? err.message : "Validation failed";
|
|
582
|
-
return fail(status, message, meta, pluginCtx, earlyBodyData);
|
|
572
|
+
if (earlyBodyResult.ok) {
|
|
573
|
+
earlyBodyData = earlyBodyResult.data;
|
|
574
|
+
if (routeEntry.validateFn) {
|
|
575
|
+
try {
|
|
576
|
+
await routeEntry.validateFn(earlyBodyData);
|
|
577
|
+
} catch (err) {
|
|
578
|
+
const status = err.status ?? 400;
|
|
579
|
+
const message = err instanceof Error ? err.message : "Validation failed";
|
|
580
|
+
return fail(status, message, meta, pluginCtx, earlyBodyData);
|
|
581
|
+
}
|
|
583
582
|
}
|
|
584
583
|
}
|
|
585
584
|
}
|
|
@@ -587,16 +586,14 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
587
586
|
if (routeEntry.validateFn && routeEntry.bodySchema && !request.headers.get("SIGN-IN-WITH-X")) {
|
|
588
587
|
const requestForValidation = request.clone();
|
|
589
588
|
const earlyBodyResult = await parseBody(requestForValidation, routeEntry);
|
|
590
|
-
if (
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
const message = err instanceof Error ? err.message : "Validation failed";
|
|
599
|
-
return fail(status, message, meta, pluginCtx, earlyBodyResult.data);
|
|
589
|
+
if (earlyBodyResult.ok) {
|
|
590
|
+
try {
|
|
591
|
+
await routeEntry.validateFn(earlyBodyResult.data);
|
|
592
|
+
} catch (err) {
|
|
593
|
+
const status = err.status ?? 400;
|
|
594
|
+
const message = err instanceof Error ? err.message : "Validation failed";
|
|
595
|
+
return fail(status, message, meta, pluginCtx, earlyBodyResult.data);
|
|
596
|
+
}
|
|
600
597
|
}
|
|
601
598
|
}
|
|
602
599
|
if (!request.headers.get("SIGN-IN-WITH-X")) {
|
|
@@ -1433,20 +1430,21 @@ function createRouter(config) {
|
|
|
1433
1430
|
const registry = new RouteRegistry();
|
|
1434
1431
|
const nonceStore = config.siwx?.nonceStore ?? new MemoryNonceStore();
|
|
1435
1432
|
const network = config.network ?? "eip155:8453";
|
|
1436
|
-
const baseUrl = config.baseUrl ?? (typeof globalThis.process !== "undefined" ? process.env.
|
|
1433
|
+
const baseUrl = config.baseUrl ?? (typeof globalThis.process !== "undefined" && process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : void 0);
|
|
1437
1434
|
if (config.protocols && config.protocols.length === 0) {
|
|
1438
1435
|
throw new Error(
|
|
1439
1436
|
"RouterConfig.protocols cannot be empty. Omit the field to use default ['x402'] or specify protocols explicitly."
|
|
1440
1437
|
);
|
|
1441
1438
|
}
|
|
1442
|
-
if (!baseUrl) {
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
}
|
|
1447
|
-
console.warn(`[router] ${msg}`);
|
|
1439
|
+
if (!baseUrl && process.env.NODE_ENV === "production") {
|
|
1440
|
+
console.warn(
|
|
1441
|
+
"[router] baseUrl was not provided and VERCEL_URL is not set. Falling back to localhost. Pass baseUrl in RouterConfig for non-Vercel deployments."
|
|
1442
|
+
);
|
|
1448
1443
|
}
|
|
1449
|
-
const resolvedBaseUrl = (baseUrl ??
|
|
1444
|
+
const resolvedBaseUrl = (baseUrl ?? `http://localhost:${process.env.PORT ?? 3e3}`).replace(
|
|
1445
|
+
/\/+$/,
|
|
1446
|
+
""
|
|
1447
|
+
);
|
|
1450
1448
|
let x402ConfigError;
|
|
1451
1449
|
let mppConfigError;
|
|
1452
1450
|
if ((!config.protocols || config.protocols.includes("x402")) && !config.payeeAddress) {
|