@agentcash/router 1.2.3 → 1.2.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/skills/router-guide/SKILL.md +45 -0
- package/dist/index.cjs +71 -9
- package/dist/index.d.cts +32 -1
- package/dist/index.d.ts +32 -1
- package/dist/index.js +71 -9
- package/package.json +4 -4
|
@@ -104,6 +104,7 @@ Response out
|
|
|
104
104
|
| `src/server.ts` | x402 server initialization with retry |
|
|
105
105
|
| `src/auth/siwx.ts` | SIWX verification |
|
|
106
106
|
| `src/auth/api-key.ts` | API key verification |
|
|
107
|
+
| `src/upstash-rest.ts` | Minimal fetch-only Upstash REST client for `useDefaultStore` |
|
|
107
108
|
| `src/auth/nonce.ts` | `NonceStore` interface + `MemoryNonceStore` |
|
|
108
109
|
| `src/discovery/well-known.ts` | `.well-known/x402` generation |
|
|
109
110
|
| `src/discovery/openapi.ts` | OpenAPI 3.1 spec generation |
|
|
@@ -180,6 +181,7 @@ export const router = createRouter({
|
|
|
180
181
|
currency: '0x20c0000000000000000000000000000000000000', // PathUSD on Tempo
|
|
181
182
|
recipient: process.env.X402_PAYEE_ADDRESS!,
|
|
182
183
|
rpcUrl: process.env.TEMPO_RPC_URL, // falls back to TEMPO_RPC_URL env var
|
|
184
|
+
useDefaultStore: true, // auto-configures Upstash from KV_REST_API_URL + KV_REST_API_TOKEN
|
|
183
185
|
},
|
|
184
186
|
siwx: { nonceStore }, // custom nonce store
|
|
185
187
|
});
|
|
@@ -420,6 +422,48 @@ The type system (generic parameters `HasAuth`, `NeedsBody`, `HasBody`) prevents
|
|
|
420
422
|
- `.siwx()` is mutually exclusive with `.paid()`
|
|
421
423
|
- `.apiKey()` CAN compose with `.paid()`
|
|
422
424
|
|
|
425
|
+
## MPP Persistent Store
|
|
426
|
+
|
|
427
|
+
mppx uses a key-value store for transaction hash replay protection. Without a persistent store, `Store.memory()` is used — which is wiped on every cold start. This is unsafe on Vercel or any multi-instance deployment.
|
|
428
|
+
|
|
429
|
+
### Vercel (zero config)
|
|
430
|
+
|
|
431
|
+
Set `useDefaultStore: true` to auto-configure an Upstash-backed store from Vercel KV environment variables (`KV_REST_API_URL` + `KV_REST_API_TOKEN`). Uses raw `fetch` — no extra npm dependencies.
|
|
432
|
+
|
|
433
|
+
```typescript
|
|
434
|
+
createRouter({
|
|
435
|
+
mpp: {
|
|
436
|
+
secretKey: process.env.MPP_SECRET_KEY!,
|
|
437
|
+
currency: USDC,
|
|
438
|
+
useDefaultStore: true, // reads KV_REST_API_URL + KV_REST_API_TOKEN automatically
|
|
439
|
+
}
|
|
440
|
+
})
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Cloudflare / custom
|
|
444
|
+
|
|
445
|
+
Pass any `Store.Store` implementation directly via `mpp.store`:
|
|
446
|
+
|
|
447
|
+
```typescript
|
|
448
|
+
import { Store } from 'mppx'
|
|
449
|
+
|
|
450
|
+
createRouter({
|
|
451
|
+
mpp: {
|
|
452
|
+
secretKey: process.env.MPP_SECRET_KEY!,
|
|
453
|
+
currency: USDC,
|
|
454
|
+
store: Store.cloudflare(env.MY_KV_NAMESPACE),
|
|
455
|
+
}
|
|
456
|
+
})
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
Available adapters from `mppx`: `Store.upstash(redis)`, `Store.cloudflare(kv)`, `Store.redis(client)`, `Store.memory()`, `Store.from(custom)`.
|
|
460
|
+
|
|
461
|
+
### Resolution order
|
|
462
|
+
|
|
463
|
+
1. Explicit `store` wins if provided
|
|
464
|
+
2. `useDefaultStore: true` creates an Upstash store from env vars
|
|
465
|
+
3. Neither → mppx defaults to `Store.memory()`
|
|
466
|
+
|
|
423
467
|
## MPP Internals
|
|
424
468
|
|
|
425
469
|
The router uses `mppx`'s high-level `Mppx.create()` API, which encapsulates the entire challenge-credential-receipt lifecycle.
|
|
@@ -509,6 +553,7 @@ Barrel validation catches mismatches: keys in `prices` but not registered → er
|
|
|
509
553
|
| MPP 401 `unauthorized: authentication required` | Using default unauthenticated Tempo RPC | Set `TEMPO_RPC_URL` env var or `mpp.rpcUrl` config with authenticated URL |
|
|
510
554
|
| `route 'X' in prices map but not registered` | Discovery endpoint hit before route module loaded | Add barrel import to discovery route files |
|
|
511
555
|
| `mppx package is required` | mppx not installed | `pnpm add mppx` — it's an optional peer dep |
|
|
556
|
+
| `useDefaultStore requires KV_REST_API_URL` | Vercel KV env vars not set | Add Vercel KV integration or set `KV_REST_API_URL` + `KV_REST_API_TOKEN` manually |
|
|
512
557
|
|
|
513
558
|
## Maintaining This Skill
|
|
514
559
|
|
package/dist/index.cjs
CHANGED
|
@@ -189,10 +189,10 @@ var init_x402_facilitators = __esm({
|
|
|
189
189
|
});
|
|
190
190
|
|
|
191
191
|
// src/x402-config.ts
|
|
192
|
-
async function resolvePayToValue(payTo, request, fallback) {
|
|
192
|
+
async function resolvePayToValue(payTo, request, fallback, body) {
|
|
193
193
|
if (!payTo) return fallback;
|
|
194
194
|
if (typeof payTo === "string") return payTo;
|
|
195
|
-
return payTo(request);
|
|
195
|
+
return payTo(request, body);
|
|
196
196
|
}
|
|
197
197
|
function getConfiguredX402Accepts(config) {
|
|
198
198
|
if (config.x402?.accepts?.length) {
|
|
@@ -209,12 +209,17 @@ function getConfiguredX402Accepts(config) {
|
|
|
209
209
|
function getConfiguredX402Networks(config) {
|
|
210
210
|
return [...new Set(getConfiguredX402Accepts(config).map((accept) => accept.network))];
|
|
211
211
|
}
|
|
212
|
-
async function resolveX402Accepts(request, routeEntry, accepts, fallbackPayTo) {
|
|
212
|
+
async function resolveX402Accepts(request, routeEntry, accepts, fallbackPayTo, body) {
|
|
213
213
|
return Promise.all(
|
|
214
214
|
accepts.map(async (accept) => ({
|
|
215
215
|
network: accept.network,
|
|
216
216
|
scheme: accept.scheme ?? "exact",
|
|
217
|
-
payTo: await resolvePayToValue(
|
|
217
|
+
payTo: await resolvePayToValue(
|
|
218
|
+
routeEntry.payTo ?? accept.payTo,
|
|
219
|
+
request,
|
|
220
|
+
fallbackPayTo,
|
|
221
|
+
body
|
|
222
|
+
),
|
|
218
223
|
...accept.asset ? { asset: accept.asset } : {},
|
|
219
224
|
...accept.decimals !== void 0 ? { decimals: accept.decimals } : {},
|
|
220
225
|
...accept.maxTimeoutSeconds !== void 0 ? { maxTimeoutSeconds: accept.maxTimeoutSeconds } : {},
|
|
@@ -307,6 +312,47 @@ var init_server = __esm({
|
|
|
307
312
|
}
|
|
308
313
|
});
|
|
309
314
|
|
|
315
|
+
// src/upstash-rest.ts
|
|
316
|
+
var upstash_rest_exports = {};
|
|
317
|
+
__export(upstash_rest_exports, {
|
|
318
|
+
createUpstashRest: () => createUpstashRest
|
|
319
|
+
});
|
|
320
|
+
function createUpstashRest(url, token) {
|
|
321
|
+
const base = url.replace(/\/+$/, "");
|
|
322
|
+
const headers = { Authorization: `Bearer ${token}` };
|
|
323
|
+
return {
|
|
324
|
+
async get(key) {
|
|
325
|
+
const res = await fetch(`${base}/get/${key}`, { headers });
|
|
326
|
+
if (!res.ok) throw new Error(`[upstash-rest] GET ${key}: ${res.status}`);
|
|
327
|
+
const { result } = await res.json();
|
|
328
|
+
return result ?? null;
|
|
329
|
+
},
|
|
330
|
+
async set(key, value) {
|
|
331
|
+
const res = await fetch(`${base}`, {
|
|
332
|
+
method: "POST",
|
|
333
|
+
headers: { ...headers, "Content-Type": "application/json" },
|
|
334
|
+
body: JSON.stringify(["SET", key, JSON.stringify(value)])
|
|
335
|
+
});
|
|
336
|
+
if (!res.ok) throw new Error(`[upstash-rest] SET ${key}: ${res.status}`);
|
|
337
|
+
return await res.json();
|
|
338
|
+
},
|
|
339
|
+
async del(key) {
|
|
340
|
+
const res = await fetch(`${base}`, {
|
|
341
|
+
method: "POST",
|
|
342
|
+
headers: { ...headers, "Content-Type": "application/json" },
|
|
343
|
+
body: JSON.stringify(["DEL", key])
|
|
344
|
+
});
|
|
345
|
+
if (!res.ok) throw new Error(`[upstash-rest] DEL ${key}: ${res.status}`);
|
|
346
|
+
return await res.json();
|
|
347
|
+
}
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
var init_upstash_rest = __esm({
|
|
351
|
+
"src/upstash-rest.ts"() {
|
|
352
|
+
"use strict";
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
|
|
310
356
|
// src/index.ts
|
|
311
357
|
var index_exports = {};
|
|
312
358
|
__export(index_exports, {
|
|
@@ -1302,7 +1348,8 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
1302
1348
|
request,
|
|
1303
1349
|
routeEntry,
|
|
1304
1350
|
deps.x402Accepts,
|
|
1305
|
-
deps.payeeAddress
|
|
1351
|
+
deps.payeeAddress,
|
|
1352
|
+
body.data
|
|
1306
1353
|
);
|
|
1307
1354
|
const verify = await verifyX402Payment({
|
|
1308
1355
|
server: deps.x402Server,
|
|
@@ -1733,7 +1780,8 @@ async function build402(request, routeEntry, deps, meta, pluginCtx, bodyData) {
|
|
|
1733
1780
|
request,
|
|
1734
1781
|
routeEntry,
|
|
1735
1782
|
deps.x402Accepts,
|
|
1736
|
-
deps.payeeAddress
|
|
1783
|
+
deps.payeeAddress,
|
|
1784
|
+
bodyData
|
|
1737
1785
|
);
|
|
1738
1786
|
const { encoded } = await buildX402Challenge({
|
|
1739
1787
|
server: deps.x402Server,
|
|
@@ -2474,8 +2522,21 @@ function createRouter(config) {
|
|
|
2474
2522
|
const getClient = async () => deps.tempoClient;
|
|
2475
2523
|
let feePayerAccount;
|
|
2476
2524
|
if (config.mpp.feePayerKey) {
|
|
2477
|
-
const {
|
|
2478
|
-
feePayerAccount =
|
|
2525
|
+
const { privateKeyToAccount } = await import("viem/accounts");
|
|
2526
|
+
feePayerAccount = privateKeyToAccount(config.mpp.feePayerKey);
|
|
2527
|
+
}
|
|
2528
|
+
let resolvedStore = config.mpp.store;
|
|
2529
|
+
if (!resolvedStore && config.mpp.useDefaultStore) {
|
|
2530
|
+
const kvUrl = process.env.KV_REST_API_URL;
|
|
2531
|
+
const kvToken = process.env.KV_REST_API_TOKEN;
|
|
2532
|
+
if (!kvUrl || !kvToken) {
|
|
2533
|
+
throw new Error(
|
|
2534
|
+
"mpp.useDefaultStore requires KV_REST_API_URL and KV_REST_API_TOKEN environment variables. These are automatically set by Vercel KV."
|
|
2535
|
+
);
|
|
2536
|
+
}
|
|
2537
|
+
const { Store } = await import("mppx");
|
|
2538
|
+
const { createUpstashRest: createUpstashRest2 } = await Promise.resolve().then(() => (init_upstash_rest(), upstash_rest_exports));
|
|
2539
|
+
resolvedStore = Store.upstash(createUpstashRest2(kvUrl, kvToken));
|
|
2479
2540
|
}
|
|
2480
2541
|
deps.mppx = Mppx.create({
|
|
2481
2542
|
methods: [
|
|
@@ -2483,7 +2544,8 @@ function createRouter(config) {
|
|
|
2483
2544
|
currency: config.mpp.currency,
|
|
2484
2545
|
recipient: config.mpp.recipient ?? config.payeeAddress,
|
|
2485
2546
|
getClient,
|
|
2486
|
-
...feePayerAccount ? { feePayer: feePayerAccount } : {}
|
|
2547
|
+
...feePayerAccount ? { feePayer: feePayerAccount } : {},
|
|
2548
|
+
...resolvedStore ? { store: resolvedStore } : {}
|
|
2487
2549
|
})
|
|
2488
2550
|
],
|
|
2489
2551
|
secretKey: config.mpp.secretKey,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FacilitatorConfig } from '@x402/core/http';
|
|
2
2
|
import { NextRequest, NextResponse } from 'next/server';
|
|
3
3
|
import { ZodType } from 'zod';
|
|
4
|
+
import { Store } from 'mppx';
|
|
4
5
|
import { PaymentRequirements, PaymentRequired, SettleResponse, Network } from '@x402/core/types';
|
|
5
6
|
import * as viem from 'viem';
|
|
6
7
|
export { S as SIWX_ERROR_MESSAGES, a as SiwxErrorCode } from './siwx-BMlja_nt.cjs';
|
|
@@ -216,7 +217,7 @@ type PricingConfig<TBody = unknown> = string | ((body: TBody) => string | Promis
|
|
|
216
217
|
tiers: Record<string, TierConfig>;
|
|
217
218
|
default?: string;
|
|
218
219
|
};
|
|
219
|
-
type PayToConfig = string | ((request: Request) => string | Promise<string>);
|
|
220
|
+
type PayToConfig = string | ((request: Request, body?: unknown) => string | Promise<string>);
|
|
220
221
|
interface X402AcceptBase {
|
|
221
222
|
network: string;
|
|
222
223
|
asset?: string;
|
|
@@ -354,6 +355,36 @@ interface RouterConfig {
|
|
|
354
355
|
* Must be a hex-encoded private key (e.g. `0xabc123...`).
|
|
355
356
|
*/
|
|
356
357
|
feePayerKey?: string;
|
|
358
|
+
/**
|
|
359
|
+
* Persistent store for transaction hash replay protection.
|
|
360
|
+
*
|
|
361
|
+
* Without this, mppx defaults to `Store.memory()` which is wiped on every cold start —
|
|
362
|
+
* unsafe on Vercel or any multi-instance deployment. Pass `Store.upstash(redis)` or
|
|
363
|
+
* `Store.cloudflare(kv)` for a shared persistent store.
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* import { Store } from 'mppx'
|
|
367
|
+
* store: Store.upstash({ get, set, del })
|
|
368
|
+
* store: Store.cloudflare(env.MY_KV_NAMESPACE)
|
|
369
|
+
*/
|
|
370
|
+
store?: Store.Store;
|
|
371
|
+
/**
|
|
372
|
+
* When `true`, auto-configures an Upstash-backed persistent store from Vercel KV
|
|
373
|
+
* environment variables (`KV_REST_API_URL` + `KV_REST_API_TOKEN`).
|
|
374
|
+
*
|
|
375
|
+
* Uses raw `fetch` against the Upstash REST API — no extra npm dependencies.
|
|
376
|
+
* Ignored when `store` is explicitly provided.
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* createRouter({
|
|
380
|
+
* mpp: {
|
|
381
|
+
* secretKey: process.env.MPP_SECRET_KEY!,
|
|
382
|
+
* currency: USDC,
|
|
383
|
+
* useDefaultStore: true,
|
|
384
|
+
* }
|
|
385
|
+
* })
|
|
386
|
+
*/
|
|
387
|
+
useDefaultStore?: boolean;
|
|
357
388
|
};
|
|
358
389
|
/**
|
|
359
390
|
* Payment protocols to accept on auto-priced routes (those using the `prices` config).
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FacilitatorConfig } from '@x402/core/http';
|
|
2
2
|
import { NextRequest, NextResponse } from 'next/server';
|
|
3
3
|
import { ZodType } from 'zod';
|
|
4
|
+
import { Store } from 'mppx';
|
|
4
5
|
import { PaymentRequirements, PaymentRequired, SettleResponse, Network } from '@x402/core/types';
|
|
5
6
|
import * as viem from 'viem';
|
|
6
7
|
export { S as SIWX_ERROR_MESSAGES, a as SiwxErrorCode } from './siwx-BMlja_nt.js';
|
|
@@ -216,7 +217,7 @@ type PricingConfig<TBody = unknown> = string | ((body: TBody) => string | Promis
|
|
|
216
217
|
tiers: Record<string, TierConfig>;
|
|
217
218
|
default?: string;
|
|
218
219
|
};
|
|
219
|
-
type PayToConfig = string | ((request: Request) => string | Promise<string>);
|
|
220
|
+
type PayToConfig = string | ((request: Request, body?: unknown) => string | Promise<string>);
|
|
220
221
|
interface X402AcceptBase {
|
|
221
222
|
network: string;
|
|
222
223
|
asset?: string;
|
|
@@ -354,6 +355,36 @@ interface RouterConfig {
|
|
|
354
355
|
* Must be a hex-encoded private key (e.g. `0xabc123...`).
|
|
355
356
|
*/
|
|
356
357
|
feePayerKey?: string;
|
|
358
|
+
/**
|
|
359
|
+
* Persistent store for transaction hash replay protection.
|
|
360
|
+
*
|
|
361
|
+
* Without this, mppx defaults to `Store.memory()` which is wiped on every cold start —
|
|
362
|
+
* unsafe on Vercel or any multi-instance deployment. Pass `Store.upstash(redis)` or
|
|
363
|
+
* `Store.cloudflare(kv)` for a shared persistent store.
|
|
364
|
+
*
|
|
365
|
+
* @example
|
|
366
|
+
* import { Store } from 'mppx'
|
|
367
|
+
* store: Store.upstash({ get, set, del })
|
|
368
|
+
* store: Store.cloudflare(env.MY_KV_NAMESPACE)
|
|
369
|
+
*/
|
|
370
|
+
store?: Store.Store;
|
|
371
|
+
/**
|
|
372
|
+
* When `true`, auto-configures an Upstash-backed persistent store from Vercel KV
|
|
373
|
+
* environment variables (`KV_REST_API_URL` + `KV_REST_API_TOKEN`).
|
|
374
|
+
*
|
|
375
|
+
* Uses raw `fetch` against the Upstash REST API — no extra npm dependencies.
|
|
376
|
+
* Ignored when `store` is explicitly provided.
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* createRouter({
|
|
380
|
+
* mpp: {
|
|
381
|
+
* secretKey: process.env.MPP_SECRET_KEY!,
|
|
382
|
+
* currency: USDC,
|
|
383
|
+
* useDefaultStore: true,
|
|
384
|
+
* }
|
|
385
|
+
* })
|
|
386
|
+
*/
|
|
387
|
+
useDefaultStore?: boolean;
|
|
357
388
|
};
|
|
358
389
|
/**
|
|
359
390
|
* Payment protocols to accept on auto-priced routes (those using the `prices` config).
|
package/dist/index.js
CHANGED
|
@@ -167,10 +167,10 @@ var init_x402_facilitators = __esm({
|
|
|
167
167
|
});
|
|
168
168
|
|
|
169
169
|
// src/x402-config.ts
|
|
170
|
-
async function resolvePayToValue(payTo, request, fallback) {
|
|
170
|
+
async function resolvePayToValue(payTo, request, fallback, body) {
|
|
171
171
|
if (!payTo) return fallback;
|
|
172
172
|
if (typeof payTo === "string") return payTo;
|
|
173
|
-
return payTo(request);
|
|
173
|
+
return payTo(request, body);
|
|
174
174
|
}
|
|
175
175
|
function getConfiguredX402Accepts(config) {
|
|
176
176
|
if (config.x402?.accepts?.length) {
|
|
@@ -187,12 +187,17 @@ function getConfiguredX402Accepts(config) {
|
|
|
187
187
|
function getConfiguredX402Networks(config) {
|
|
188
188
|
return [...new Set(getConfiguredX402Accepts(config).map((accept) => accept.network))];
|
|
189
189
|
}
|
|
190
|
-
async function resolveX402Accepts(request, routeEntry, accepts, fallbackPayTo) {
|
|
190
|
+
async function resolveX402Accepts(request, routeEntry, accepts, fallbackPayTo, body) {
|
|
191
191
|
return Promise.all(
|
|
192
192
|
accepts.map(async (accept) => ({
|
|
193
193
|
network: accept.network,
|
|
194
194
|
scheme: accept.scheme ?? "exact",
|
|
195
|
-
payTo: await resolvePayToValue(
|
|
195
|
+
payTo: await resolvePayToValue(
|
|
196
|
+
routeEntry.payTo ?? accept.payTo,
|
|
197
|
+
request,
|
|
198
|
+
fallbackPayTo,
|
|
199
|
+
body
|
|
200
|
+
),
|
|
196
201
|
...accept.asset ? { asset: accept.asset } : {},
|
|
197
202
|
...accept.decimals !== void 0 ? { decimals: accept.decimals } : {},
|
|
198
203
|
...accept.maxTimeoutSeconds !== void 0 ? { maxTimeoutSeconds: accept.maxTimeoutSeconds } : {},
|
|
@@ -285,6 +290,47 @@ var init_server = __esm({
|
|
|
285
290
|
}
|
|
286
291
|
});
|
|
287
292
|
|
|
293
|
+
// src/upstash-rest.ts
|
|
294
|
+
var upstash_rest_exports = {};
|
|
295
|
+
__export(upstash_rest_exports, {
|
|
296
|
+
createUpstashRest: () => createUpstashRest
|
|
297
|
+
});
|
|
298
|
+
function createUpstashRest(url, token) {
|
|
299
|
+
const base = url.replace(/\/+$/, "");
|
|
300
|
+
const headers = { Authorization: `Bearer ${token}` };
|
|
301
|
+
return {
|
|
302
|
+
async get(key) {
|
|
303
|
+
const res = await fetch(`${base}/get/${key}`, { headers });
|
|
304
|
+
if (!res.ok) throw new Error(`[upstash-rest] GET ${key}: ${res.status}`);
|
|
305
|
+
const { result } = await res.json();
|
|
306
|
+
return result ?? null;
|
|
307
|
+
},
|
|
308
|
+
async set(key, value) {
|
|
309
|
+
const res = await fetch(`${base}`, {
|
|
310
|
+
method: "POST",
|
|
311
|
+
headers: { ...headers, "Content-Type": "application/json" },
|
|
312
|
+
body: JSON.stringify(["SET", key, JSON.stringify(value)])
|
|
313
|
+
});
|
|
314
|
+
if (!res.ok) throw new Error(`[upstash-rest] SET ${key}: ${res.status}`);
|
|
315
|
+
return await res.json();
|
|
316
|
+
},
|
|
317
|
+
async del(key) {
|
|
318
|
+
const res = await fetch(`${base}`, {
|
|
319
|
+
method: "POST",
|
|
320
|
+
headers: { ...headers, "Content-Type": "application/json" },
|
|
321
|
+
body: JSON.stringify(["DEL", key])
|
|
322
|
+
});
|
|
323
|
+
if (!res.ok) throw new Error(`[upstash-rest] DEL ${key}: ${res.status}`);
|
|
324
|
+
return await res.json();
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
var init_upstash_rest = __esm({
|
|
329
|
+
"src/upstash-rest.ts"() {
|
|
330
|
+
"use strict";
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
|
|
288
334
|
// src/registry.ts
|
|
289
335
|
var RouteRegistry = class {
|
|
290
336
|
routes = /* @__PURE__ */ new Map();
|
|
@@ -1263,7 +1309,8 @@ function createRequestHandler(routeEntry, handler, deps) {
|
|
|
1263
1309
|
request,
|
|
1264
1310
|
routeEntry,
|
|
1265
1311
|
deps.x402Accepts,
|
|
1266
|
-
deps.payeeAddress
|
|
1312
|
+
deps.payeeAddress,
|
|
1313
|
+
body.data
|
|
1267
1314
|
);
|
|
1268
1315
|
const verify = await verifyX402Payment({
|
|
1269
1316
|
server: deps.x402Server,
|
|
@@ -1694,7 +1741,8 @@ async function build402(request, routeEntry, deps, meta, pluginCtx, bodyData) {
|
|
|
1694
1741
|
request,
|
|
1695
1742
|
routeEntry,
|
|
1696
1743
|
deps.x402Accepts,
|
|
1697
|
-
deps.payeeAddress
|
|
1744
|
+
deps.payeeAddress,
|
|
1745
|
+
bodyData
|
|
1698
1746
|
);
|
|
1699
1747
|
const { encoded } = await buildX402Challenge({
|
|
1700
1748
|
server: deps.x402Server,
|
|
@@ -2435,8 +2483,21 @@ function createRouter(config) {
|
|
|
2435
2483
|
const getClient = async () => deps.tempoClient;
|
|
2436
2484
|
let feePayerAccount;
|
|
2437
2485
|
if (config.mpp.feePayerKey) {
|
|
2438
|
-
const {
|
|
2439
|
-
feePayerAccount =
|
|
2486
|
+
const { privateKeyToAccount } = await import("viem/accounts");
|
|
2487
|
+
feePayerAccount = privateKeyToAccount(config.mpp.feePayerKey);
|
|
2488
|
+
}
|
|
2489
|
+
let resolvedStore = config.mpp.store;
|
|
2490
|
+
if (!resolvedStore && config.mpp.useDefaultStore) {
|
|
2491
|
+
const kvUrl = process.env.KV_REST_API_URL;
|
|
2492
|
+
const kvToken = process.env.KV_REST_API_TOKEN;
|
|
2493
|
+
if (!kvUrl || !kvToken) {
|
|
2494
|
+
throw new Error(
|
|
2495
|
+
"mpp.useDefaultStore requires KV_REST_API_URL and KV_REST_API_TOKEN environment variables. These are automatically set by Vercel KV."
|
|
2496
|
+
);
|
|
2497
|
+
}
|
|
2498
|
+
const { Store } = await import("mppx");
|
|
2499
|
+
const { createUpstashRest: createUpstashRest2 } = await Promise.resolve().then(() => (init_upstash_rest(), upstash_rest_exports));
|
|
2500
|
+
resolvedStore = Store.upstash(createUpstashRest2(kvUrl, kvToken));
|
|
2440
2501
|
}
|
|
2441
2502
|
deps.mppx = Mppx.create({
|
|
2442
2503
|
methods: [
|
|
@@ -2444,7 +2505,8 @@ function createRouter(config) {
|
|
|
2444
2505
|
currency: config.mpp.currency,
|
|
2445
2506
|
recipient: config.mpp.recipient ?? config.payeeAddress,
|
|
2446
2507
|
getClient,
|
|
2447
|
-
...feePayerAccount ? { feePayer: feePayerAccount } : {}
|
|
2508
|
+
...feePayerAccount ? { feePayer: feePayerAccount } : {},
|
|
2509
|
+
...resolvedStore ? { store: resolvedStore } : {}
|
|
2448
2510
|
})
|
|
2449
2511
|
],
|
|
2450
2512
|
secretKey: config.mpp.secretKey,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentcash/router",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
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": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@x402/evm": "^2.3.0",
|
|
30
30
|
"@x402/extensions": "^2.3.0",
|
|
31
31
|
"@x402/svm": "2.3.0",
|
|
32
|
-
"mppx": "^0.4.
|
|
32
|
+
"mppx": "^0.4.11",
|
|
33
33
|
"next": ">=15.0.0",
|
|
34
34
|
"zod": "^4.0.0",
|
|
35
35
|
"zod-openapi": "^5.0.0"
|
|
@@ -61,14 +61,14 @@
|
|
|
61
61
|
"@x402/extensions": "^2.3.0",
|
|
62
62
|
"@x402/svm": "2.3.0",
|
|
63
63
|
"eslint": "^10.0.0",
|
|
64
|
-
"mppx": "^0.4.
|
|
64
|
+
"mppx": "^0.4.11",
|
|
65
65
|
"next": "^15.0.0",
|
|
66
66
|
"prettier": "^3.8.1",
|
|
67
67
|
"react": "^19.0.0",
|
|
68
68
|
"tsup": "^8.0.0",
|
|
69
69
|
"typescript": "^5.8.0",
|
|
70
70
|
"typescript-eslint": "^8.55.0",
|
|
71
|
-
"viem": "^2.47.
|
|
71
|
+
"viem": "^2.47.6",
|
|
72
72
|
"vitest": "^3.0.0",
|
|
73
73
|
"zod": "^4.0.0",
|
|
74
74
|
"zod-openapi": "^5.0.0"
|