x402-proxy 0.5.2 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -1
- package/README.md +11 -2
- package/dist/bin/cli.js +472 -167
- package/dist/{derive-CISr_ond.js → derive-ibF2UinV.js} +2 -2
- package/dist/index.d.ts +43 -8
- package/dist/index.js +104 -13
- package/dist/{setup-gla-Qyqi.js → setup-hJGkO2Lo.js} +1 -1
- package/dist/setup-j_xQ14-4.js +4 -0
- package/dist/{status-BoH_1kIH.js → status-JNGv2Ghp.js} +12 -6
- package/dist/{status-BVIU3-b6.js → status-w5y-fhhe.js} +1 -1
- package/dist/wallet-DjixXCHy.js +4 -0
- package/dist/{wallet-BMYYtAP6.js → wallet-DxKCHa7U.js} +45 -11
- package/package.json +5 -2
- package/skills/SKILL.md +9 -6
- package/dist/setup-Crq9TylJ.js +0 -4
- package/dist/wallet-BoY0fgX7.js +0 -4
package/dist/bin/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { n as setupCommand } from "../setup-
|
|
5
|
-
import { n as statusCommand } from "../status-
|
|
2
|
+
import { _ as formatTxLine, c as resolveWallet, d as info, f as isTTY, g as displayNetwork, h as calcSpend, l as dim, m as appendHistory, o as walletInfoCommand, p as warn, s as buildX402Client, u as error, v as readHistory } from "../wallet-DxKCHa7U.js";
|
|
3
|
+
import { a as getHistoryPath, c as loadConfig, l as loadWalletFile, s as isConfigured } from "../derive-ibF2UinV.js";
|
|
4
|
+
import { n as setupCommand } from "../setup-hJGkO2Lo.js";
|
|
5
|
+
import { n as statusCommand } from "../status-JNGv2Ghp.js";
|
|
6
6
|
import { buildApplication, buildCommand, buildRouteMap, run } from "@stricli/core";
|
|
7
7
|
import pc from "picocolors";
|
|
8
8
|
import { decodePaymentResponseHeader, wrapFetchWithPayment } from "@x402/fetch";
|
|
@@ -11,25 +11,35 @@ import * as prompts from "@clack/prompts";
|
|
|
11
11
|
|
|
12
12
|
//#region src/handler.ts
|
|
13
13
|
/**
|
|
14
|
+
* Detect which payment protocols a 402 response advertises.
|
|
15
|
+
* - x402: PAYMENT-REQUIRED or X-PAYMENT-REQUIRED header
|
|
16
|
+
* - MPP: WWW-Authenticate header with Payment scheme
|
|
17
|
+
*/
|
|
18
|
+
function detectProtocols(response) {
|
|
19
|
+
const pr = response.headers.get("PAYMENT-REQUIRED") ?? response.headers.get("X-PAYMENT-REQUIRED");
|
|
20
|
+
const wwwAuth = response.headers.get("WWW-Authenticate");
|
|
21
|
+
return {
|
|
22
|
+
x402: !!pr,
|
|
23
|
+
mpp: !!(wwwAuth && /^Payment\b/i.test(wwwAuth.trim()))
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
14
27
|
* Extract the on-chain transaction signature from an x402 payment response header.
|
|
15
28
|
*/
|
|
16
29
|
function extractTxSignature(response) {
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
19
|
-
|
|
20
|
-
|
|
30
|
+
const x402Header = response.headers.get("PAYMENT-RESPONSE") ?? response.headers.get("X-PAYMENT-RESPONSE");
|
|
31
|
+
if (x402Header) try {
|
|
32
|
+
return decodePaymentResponseHeader(x402Header).transaction ?? void 0;
|
|
33
|
+
} catch {}
|
|
34
|
+
const mppHeader = response.headers.get("Payment-Receipt");
|
|
35
|
+
if (mppHeader) try {
|
|
36
|
+
return JSON.parse(Buffer.from(mppHeader, "base64url").toString()).reference ?? void 0;
|
|
21
37
|
} catch {
|
|
22
38
|
return;
|
|
23
39
|
}
|
|
24
40
|
}
|
|
25
41
|
/**
|
|
26
42
|
* Create an x402 proxy handler that wraps fetch with automatic payment.
|
|
27
|
-
*
|
|
28
|
-
* Chain-agnostic: accepts a pre-configured x402Client with any registered
|
|
29
|
-
* schemes (SVM, EVM, etc). The handler captures payment info via the
|
|
30
|
-
* onAfterPaymentCreation hook. Callers use `x402Fetch` for requests that
|
|
31
|
-
* may require x402 payment, and `shiftPayment` to retrieve captured
|
|
32
|
-
* payment info after each call.
|
|
33
43
|
*/
|
|
34
44
|
function createX402ProxyHandler(opts) {
|
|
35
45
|
const { client } = opts;
|
|
@@ -37,6 +47,7 @@ function createX402ProxyHandler(opts) {
|
|
|
37
47
|
client.onAfterPaymentCreation(async (hookCtx) => {
|
|
38
48
|
const raw = hookCtx.selectedRequirements.amount;
|
|
39
49
|
paymentQueue.push({
|
|
50
|
+
protocol: "x402",
|
|
40
51
|
network: hookCtx.selectedRequirements.network,
|
|
41
52
|
payTo: hookCtx.selectedRequirements.payTo,
|
|
42
53
|
amount: raw,
|
|
@@ -48,6 +59,80 @@ function createX402ProxyHandler(opts) {
|
|
|
48
59
|
shiftPayment: () => paymentQueue.shift()
|
|
49
60
|
};
|
|
50
61
|
}
|
|
62
|
+
const TEMPO_NETWORK = "eip155:4217";
|
|
63
|
+
/**
|
|
64
|
+
* Create an MPP proxy handler using mppx client.
|
|
65
|
+
* Dynamically imports mppx/client to keep startup fast.
|
|
66
|
+
*/
|
|
67
|
+
async function createMppProxyHandler(opts) {
|
|
68
|
+
const { Mppx, tempo } = await import("mppx/client");
|
|
69
|
+
const { privateKeyToAccount } = await import("viem/accounts");
|
|
70
|
+
const account = privateKeyToAccount(opts.evmKey);
|
|
71
|
+
const maxDeposit = opts.maxDeposit ?? "1";
|
|
72
|
+
const paymentQueue = [];
|
|
73
|
+
const mppx = Mppx.create({
|
|
74
|
+
methods: [tempo({
|
|
75
|
+
account,
|
|
76
|
+
maxDeposit
|
|
77
|
+
})],
|
|
78
|
+
polyfill: false
|
|
79
|
+
});
|
|
80
|
+
let session;
|
|
81
|
+
return {
|
|
82
|
+
async fetch(input, init) {
|
|
83
|
+
const response = await mppx.fetch(typeof input === "string" ? input : input.toString(), init);
|
|
84
|
+
const receiptHeader = response.headers.get("Payment-Receipt");
|
|
85
|
+
if (receiptHeader) try {
|
|
86
|
+
const receipt = JSON.parse(Buffer.from(receiptHeader, "base64url").toString());
|
|
87
|
+
paymentQueue.push({
|
|
88
|
+
protocol: "mpp",
|
|
89
|
+
network: TEMPO_NETWORK,
|
|
90
|
+
receipt
|
|
91
|
+
});
|
|
92
|
+
} catch {
|
|
93
|
+
paymentQueue.push({
|
|
94
|
+
protocol: "mpp",
|
|
95
|
+
network: TEMPO_NETWORK
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
return response;
|
|
99
|
+
},
|
|
100
|
+
async sse(input, init) {
|
|
101
|
+
session ??= tempo.session({
|
|
102
|
+
account,
|
|
103
|
+
maxDeposit
|
|
104
|
+
});
|
|
105
|
+
const url = typeof input === "string" ? input : input.toString();
|
|
106
|
+
const iterable = await session.sse(url, init);
|
|
107
|
+
paymentQueue.push({
|
|
108
|
+
protocol: "mpp",
|
|
109
|
+
network: TEMPO_NETWORK,
|
|
110
|
+
intent: "session"
|
|
111
|
+
});
|
|
112
|
+
return iterable;
|
|
113
|
+
},
|
|
114
|
+
shiftPayment: () => paymentQueue.shift(),
|
|
115
|
+
async close() {
|
|
116
|
+
if (session?.opened) {
|
|
117
|
+
const receipt = await session.close();
|
|
118
|
+
if (receipt) paymentQueue.push({
|
|
119
|
+
protocol: "mpp",
|
|
120
|
+
network: TEMPO_NETWORK,
|
|
121
|
+
intent: "session",
|
|
122
|
+
channelId: session.channelId ?? void 0,
|
|
123
|
+
receipt: {
|
|
124
|
+
method: receipt.method,
|
|
125
|
+
reference: receipt.reference,
|
|
126
|
+
status: receipt.status,
|
|
127
|
+
timestamp: receipt.timestamp,
|
|
128
|
+
acceptedCumulative: receipt.acceptedCumulative,
|
|
129
|
+
txHash: receipt.txHash
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
51
136
|
|
|
52
137
|
//#endregion
|
|
53
138
|
//#region src/commands/fetch.ts
|
|
@@ -96,7 +181,13 @@ Examples:
|
|
|
96
181
|
},
|
|
97
182
|
network: {
|
|
98
183
|
kind: "parsed",
|
|
99
|
-
brief: "Require specific network (base, solana)",
|
|
184
|
+
brief: "Require specific network (base, solana, tempo)",
|
|
185
|
+
parse: String,
|
|
186
|
+
optional: true
|
|
187
|
+
},
|
|
188
|
+
protocol: {
|
|
189
|
+
kind: "parsed",
|
|
190
|
+
brief: "Payment protocol (x402, mpp)",
|
|
100
191
|
parse: String,
|
|
101
192
|
optional: true
|
|
102
193
|
},
|
|
@@ -118,7 +209,7 @@ Examples:
|
|
|
118
209
|
async func(flags, url) {
|
|
119
210
|
if (!url) {
|
|
120
211
|
if (isConfigured()) {
|
|
121
|
-
const { displayStatus } = await import("../status-
|
|
212
|
+
const { displayStatus } = await import("../status-w5y-fhhe.js");
|
|
122
213
|
await displayStatus();
|
|
123
214
|
console.log();
|
|
124
215
|
console.log(pc.dim(" Commands:"));
|
|
@@ -170,28 +261,24 @@ Examples:
|
|
|
170
261
|
process.exit(1);
|
|
171
262
|
}
|
|
172
263
|
dim(" No wallet found. Let's set one up first.\n");
|
|
173
|
-
const { runSetup } = await import("../setup-
|
|
264
|
+
const { runSetup } = await import("../setup-j_xQ14-4.js");
|
|
174
265
|
await runSetup();
|
|
175
266
|
console.log();
|
|
176
267
|
wallet = resolveWallet();
|
|
177
268
|
if (wallet.source === "none") return;
|
|
178
269
|
}
|
|
179
270
|
const config = loadConfig();
|
|
271
|
+
const resolvedProtocol = flags.protocol ?? config?.preferredProtocol;
|
|
272
|
+
const maxDeposit = config?.mppSessionBudget ?? "1";
|
|
180
273
|
let preferredNetwork = config?.defaultNetwork;
|
|
181
274
|
if (!preferredNetwork && wallet.evmAddress && wallet.solanaAddress) {
|
|
182
|
-
const {
|
|
183
|
-
const
|
|
184
|
-
const evmUsdc =
|
|
185
|
-
const solUsdc =
|
|
275
|
+
const { fetchAllBalances } = await import("../wallet-DjixXCHy.js");
|
|
276
|
+
const balances = await fetchAllBalances(wallet.evmAddress, wallet.solanaAddress);
|
|
277
|
+
const evmUsdc = balances.evm ? Number(balances.evm.usdc) : 0;
|
|
278
|
+
const solUsdc = balances.sol ? Number(balances.sol.usdc) : 0;
|
|
186
279
|
if (evmUsdc > solUsdc) preferredNetwork = "base";
|
|
187
280
|
else if (solUsdc > evmUsdc) preferredNetwork = "solana";
|
|
188
281
|
}
|
|
189
|
-
const { x402Fetch, shiftPayment } = createX402ProxyHandler({ client: await buildX402Client(wallet, {
|
|
190
|
-
preferredNetwork,
|
|
191
|
-
network: flags.network,
|
|
192
|
-
spendLimitDaily: config?.spendLimitDaily,
|
|
193
|
-
spendLimitPerTx: config?.spendLimitPerTx
|
|
194
|
-
}) });
|
|
195
282
|
const headers = new Headers();
|
|
196
283
|
if (flags.header) for (const h of flags.header) {
|
|
197
284
|
const idx = h.indexOf(":");
|
|
@@ -206,16 +293,102 @@ Examples:
|
|
|
206
293
|
if (isTTY()) dim(` ${method} ${parsedUrl.toString()}`);
|
|
207
294
|
const startMs = Date.now();
|
|
208
295
|
let response;
|
|
296
|
+
let x402Payment;
|
|
297
|
+
let mppPayment;
|
|
298
|
+
let usedProtocol;
|
|
209
299
|
try {
|
|
210
|
-
|
|
300
|
+
if (resolvedProtocol === "mpp") {
|
|
301
|
+
if (!wallet.evmKey) {
|
|
302
|
+
error("MPP requires an EVM wallet. Configure one with: npx x402-proxy setup");
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
const mppHandler = await createMppProxyHandler({
|
|
306
|
+
evmKey: wallet.evmKey,
|
|
307
|
+
maxDeposit
|
|
308
|
+
});
|
|
309
|
+
if (flags.body != null && /"stream"\s*:\s*true/.test(flags.body)) {
|
|
310
|
+
try {
|
|
311
|
+
const tokens = await mppHandler.sse(parsedUrl.toString(), init);
|
|
312
|
+
for await (const token of tokens) process.stdout.write(token);
|
|
313
|
+
} finally {
|
|
314
|
+
await mppHandler.close();
|
|
315
|
+
}
|
|
316
|
+
mppPayment = mppHandler.shiftPayment();
|
|
317
|
+
usedProtocol = "mpp";
|
|
318
|
+
const elapsedMs = Date.now() - startMs;
|
|
319
|
+
if (mppPayment && isTTY()) info(` MPP session (${displayNetwork(mppPayment.network)})`);
|
|
320
|
+
if (isTTY()) dim(` Streamed (${elapsedMs}ms)`);
|
|
321
|
+
if (mppPayment) {
|
|
322
|
+
const record = {
|
|
323
|
+
t: Date.now(),
|
|
324
|
+
ok: true,
|
|
325
|
+
kind: "mpp_payment",
|
|
326
|
+
net: mppPayment.network,
|
|
327
|
+
from: wallet.evmAddress ?? "unknown",
|
|
328
|
+
tx: mppPayment.receipt?.reference,
|
|
329
|
+
amount: void 0,
|
|
330
|
+
token: "USDC",
|
|
331
|
+
ms: elapsedMs,
|
|
332
|
+
label: parsedUrl.hostname
|
|
333
|
+
};
|
|
334
|
+
appendHistory(getHistoryPath(), record);
|
|
335
|
+
}
|
|
336
|
+
if (isTTY()) process.stdout.write("\n");
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
response = await mppHandler.fetch(parsedUrl.toString(), init);
|
|
341
|
+
} finally {
|
|
342
|
+
await mppHandler.close();
|
|
343
|
+
}
|
|
344
|
+
mppPayment = mppHandler.shiftPayment();
|
|
345
|
+
usedProtocol = "mpp";
|
|
346
|
+
} else if (resolvedProtocol === "x402") {
|
|
347
|
+
const handler = createX402ProxyHandler({ client: await buildX402Client(wallet, {
|
|
348
|
+
preferredNetwork,
|
|
349
|
+
network: flags.network,
|
|
350
|
+
spendLimitDaily: config?.spendLimitDaily,
|
|
351
|
+
spendLimitPerTx: config?.spendLimitPerTx
|
|
352
|
+
}) });
|
|
353
|
+
response = await handler.x402Fetch(parsedUrl.toString(), init);
|
|
354
|
+
x402Payment = handler.shiftPayment();
|
|
355
|
+
usedProtocol = "x402";
|
|
356
|
+
} else {
|
|
357
|
+
const handler = createX402ProxyHandler({ client: await buildX402Client(wallet, {
|
|
358
|
+
preferredNetwork,
|
|
359
|
+
network: flags.network,
|
|
360
|
+
spendLimitDaily: config?.spendLimitDaily,
|
|
361
|
+
spendLimitPerTx: config?.spendLimitPerTx
|
|
362
|
+
}) });
|
|
363
|
+
response = await handler.x402Fetch(parsedUrl.toString(), init);
|
|
364
|
+
x402Payment = handler.shiftPayment();
|
|
365
|
+
usedProtocol = "x402";
|
|
366
|
+
if (response.status === 402 && wallet.evmKey) {
|
|
367
|
+
if (detectProtocols(response).mpp) {
|
|
368
|
+
const mppHandler = await createMppProxyHandler({
|
|
369
|
+
evmKey: wallet.evmKey,
|
|
370
|
+
maxDeposit
|
|
371
|
+
});
|
|
372
|
+
try {
|
|
373
|
+
response = await mppHandler.fetch(parsedUrl.toString(), init);
|
|
374
|
+
} finally {
|
|
375
|
+
await mppHandler.close();
|
|
376
|
+
}
|
|
377
|
+
mppPayment = mppHandler.shiftPayment();
|
|
378
|
+
x402Payment = void 0;
|
|
379
|
+
usedProtocol = "mpp";
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
211
383
|
} catch (err) {
|
|
212
384
|
error(`Request failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
213
385
|
process.exit(1);
|
|
214
386
|
}
|
|
215
387
|
const elapsedMs = Date.now() - startMs;
|
|
216
|
-
const payment =
|
|
388
|
+
const payment = x402Payment ?? mppPayment;
|
|
217
389
|
const txSig = extractTxSignature(response);
|
|
218
390
|
if (response.status === 402 && isTTY()) {
|
|
391
|
+
const detected = detectProtocols(response);
|
|
219
392
|
const prHeader = response.headers.get("PAYMENT-REQUIRED") ?? response.headers.get("X-PAYMENT-REQUIRED");
|
|
220
393
|
let accepts = [];
|
|
221
394
|
if (prHeader) try {
|
|
@@ -230,19 +403,14 @@ Examples:
|
|
|
230
403
|
}
|
|
231
404
|
const hasEvm = accepts.some((a) => a.network.startsWith("eip155:"));
|
|
232
405
|
const hasSolana = accepts.some((a) => a.network.startsWith("solana:"));
|
|
406
|
+
const hasMpp = detected.mpp;
|
|
233
407
|
const hasOther = accepts.some((a) => !a.network.startsWith("eip155:") && !a.network.startsWith("solana:"));
|
|
234
|
-
const {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
} catch {}
|
|
241
|
-
if (hasSolana && wallet.solanaAddress) try {
|
|
242
|
-
const bal = await fetchSolanaBalances(wallet.solanaAddress);
|
|
243
|
-
solUsdc = Number(bal.usdc);
|
|
244
|
-
} catch {}
|
|
245
|
-
if (hasEvm && evmUsdc >= costNum || hasSolana && solUsdc >= costNum) {
|
|
408
|
+
const { fetchAllBalances } = await import("../wallet-DjixXCHy.js");
|
|
409
|
+
const balances = await fetchAllBalances(wallet.evmAddress, wallet.solanaAddress);
|
|
410
|
+
const evmUsdc = hasEvm && balances.evm ? Number(balances.evm.usdc) : 0;
|
|
411
|
+
const solUsdc = hasSolana && balances.sol ? Number(balances.sol.usdc) : 0;
|
|
412
|
+
const tempoUsdc = hasMpp && balances.tempo ? Number(balances.tempo.usdc) : 0;
|
|
413
|
+
if (hasEvm && evmUsdc >= costNum || hasSolana && solUsdc >= costNum || hasMpp && tempoUsdc >= costNum) {
|
|
246
414
|
let serverReason;
|
|
247
415
|
try {
|
|
248
416
|
const body = await response.text();
|
|
@@ -257,24 +425,30 @@ Examples:
|
|
|
257
425
|
else dim(" Payment was not attempted despite sufficient balance.");
|
|
258
426
|
if (serverReason) dim(` Reason: ${serverReason}`);
|
|
259
427
|
if (hasEvm && wallet.evmAddress && evmUsdc > 0) console.error(` Base: ${pc.cyan(wallet.evmAddress)} ${pc.dim(`(${evmUsdc.toFixed(4)} USDC)`)}`);
|
|
428
|
+
if (hasMpp && wallet.evmAddress && tempoUsdc > 0) console.error(` Tempo: ${pc.cyan(wallet.evmAddress)} ${pc.dim(`(${tempoUsdc.toFixed(4)} USDC)`)}`);
|
|
260
429
|
if (hasSolana && wallet.solanaAddress && solUsdc > 0) console.error(` Solana: ${pc.cyan(wallet.solanaAddress)} ${pc.dim(`(${solUsdc.toFixed(4)} USDC)`)}`);
|
|
261
430
|
console.error();
|
|
262
431
|
dim(" This may be a temporary server-side issue. Try again in a moment.");
|
|
263
432
|
console.error();
|
|
264
433
|
} else {
|
|
265
434
|
error(`Payment required: ${costStr} USDC`);
|
|
266
|
-
if (hasEvm || hasSolana) {
|
|
435
|
+
if (hasEvm || hasSolana || hasMpp) {
|
|
267
436
|
console.error();
|
|
268
437
|
dim(" Fund your wallet with USDC:");
|
|
269
438
|
if (hasEvm && wallet.evmAddress) {
|
|
270
439
|
const balHint = evmUsdc > 0 ? pc.dim(` (${evmUsdc.toFixed(4)} USDC)`) : "";
|
|
271
440
|
console.error(` Base: ${pc.cyan(wallet.evmAddress)}${balHint}`);
|
|
272
441
|
}
|
|
442
|
+
if (hasMpp && wallet.evmAddress) {
|
|
443
|
+
const balHint = tempoUsdc > 0 ? pc.dim(` (${tempoUsdc.toFixed(4)} USDC)`) : "";
|
|
444
|
+
console.error(` Tempo: ${pc.cyan(wallet.evmAddress)}${balHint}`);
|
|
445
|
+
}
|
|
273
446
|
if (hasSolana && wallet.solanaAddress) {
|
|
274
447
|
const balHint = solUsdc > 0 ? pc.dim(` (${solUsdc.toFixed(4)} USDC)`) : "";
|
|
275
448
|
console.error(` Solana: ${pc.cyan(wallet.solanaAddress)}${balHint}`);
|
|
276
449
|
}
|
|
277
450
|
if (hasEvm && !wallet.evmAddress) dim(" Base: endpoint accepts EVM but no EVM wallet configured");
|
|
451
|
+
if (hasMpp && !wallet.evmAddress) dim(" Tempo: endpoint accepts MPP but no EVM wallet configured");
|
|
278
452
|
if (hasSolana && !wallet.solanaAddress) dim(" Solana: endpoint accepts Solana but no Solana wallet configured");
|
|
279
453
|
} else if (hasOther) {
|
|
280
454
|
const networks = [...new Set(accepts.map((a) => a.network))].join(", ");
|
|
@@ -289,21 +463,34 @@ Examples:
|
|
|
289
463
|
return;
|
|
290
464
|
}
|
|
291
465
|
if (payment && isTTY()) {
|
|
292
|
-
|
|
466
|
+
if (usedProtocol === "mpp" && mppPayment) info(` Payment: MPP (${displayNetwork(mppPayment.network)})`);
|
|
467
|
+
else if (x402Payment) info(` Payment: ${x402Payment.amount ? (Number(x402Payment.amount) / 1e6).toFixed(4) : "?"} USDC (${displayNetwork(x402Payment.network ?? "unknown")})`);
|
|
293
468
|
if (txSig) dim(` Tx: ${txSig}`);
|
|
294
469
|
}
|
|
295
470
|
if (isTTY()) dim(` ${response.status} ${response.statusText} (${elapsedMs}ms)`);
|
|
296
|
-
if (
|
|
297
|
-
ensureConfigDir();
|
|
471
|
+
if (x402Payment) {
|
|
298
472
|
const record = {
|
|
299
473
|
t: Date.now(),
|
|
300
474
|
ok: response.ok,
|
|
301
475
|
kind: "x402_payment",
|
|
302
|
-
net:
|
|
476
|
+
net: x402Payment.network ?? "unknown",
|
|
303
477
|
from: wallet.evmAddress ?? wallet.solanaAddress ?? "unknown",
|
|
304
|
-
to:
|
|
478
|
+
to: x402Payment.payTo,
|
|
305
479
|
tx: txSig,
|
|
306
|
-
amount:
|
|
480
|
+
amount: x402Payment.amount ? Number(x402Payment.amount) / 1e6 : void 0,
|
|
481
|
+
token: "USDC",
|
|
482
|
+
ms: elapsedMs,
|
|
483
|
+
label: parsedUrl.hostname
|
|
484
|
+
};
|
|
485
|
+
appendHistory(getHistoryPath(), record);
|
|
486
|
+
} else if (mppPayment) {
|
|
487
|
+
const record = {
|
|
488
|
+
t: Date.now(),
|
|
489
|
+
ok: response.ok,
|
|
490
|
+
kind: "mpp_payment",
|
|
491
|
+
net: mppPayment.network,
|
|
492
|
+
from: wallet.evmAddress ?? "unknown",
|
|
493
|
+
tx: mppPayment.receipt?.reference ?? txSig,
|
|
307
494
|
token: "USDC",
|
|
308
495
|
ms: elapsedMs,
|
|
309
496
|
label: parsedUrl.hostname
|
|
@@ -330,8 +517,8 @@ Examples:
|
|
|
330
517
|
//#region src/commands/mcp.ts
|
|
331
518
|
const mcpCommand = buildCommand({
|
|
332
519
|
docs: {
|
|
333
|
-
brief: "Start MCP stdio proxy with
|
|
334
|
-
fullDescription: `Start an MCP stdio proxy with automatic x402
|
|
520
|
+
brief: "Start MCP stdio proxy with automatic payment",
|
|
521
|
+
fullDescription: `Start an MCP stdio proxy with automatic payment (x402 or MPP) for AI agents.
|
|
335
522
|
|
|
336
523
|
Add to your MCP client config (Claude, Cursor, etc.):
|
|
337
524
|
"command": "npx",
|
|
@@ -354,7 +541,13 @@ Add to your MCP client config (Claude, Cursor, etc.):
|
|
|
354
541
|
},
|
|
355
542
|
network: {
|
|
356
543
|
kind: "parsed",
|
|
357
|
-
brief: "Require specific network (base, solana)",
|
|
544
|
+
brief: "Require specific network (base, solana, tempo)",
|
|
545
|
+
parse: String,
|
|
546
|
+
optional: true
|
|
547
|
+
},
|
|
548
|
+
protocol: {
|
|
549
|
+
kind: "parsed",
|
|
550
|
+
brief: "Payment protocol (x402, mpp)",
|
|
358
551
|
parse: String,
|
|
359
552
|
optional: true
|
|
360
553
|
}
|
|
@@ -380,132 +573,244 @@ Add to your MCP client config (Claude, Cursor, etc.):
|
|
|
380
573
|
if (wallet.evmAddress) dim(` EVM: ${wallet.evmAddress}`);
|
|
381
574
|
if (wallet.solanaAddress) dim(` Solana: ${wallet.solanaAddress}`);
|
|
382
575
|
const config = loadConfig();
|
|
383
|
-
|
|
384
|
-
if (!preferredNetwork && wallet.evmAddress && wallet.solanaAddress) {
|
|
385
|
-
const { fetchEvmBalances, fetchSolanaBalances } = await import("../wallet-BoY0fgX7.js");
|
|
386
|
-
const [evmBal, solBal] = await Promise.allSettled([fetchEvmBalances(wallet.evmAddress), fetchSolanaBalances(wallet.solanaAddress)]);
|
|
387
|
-
const evmUsdc = evmBal.status === "fulfilled" ? Number(evmBal.value?.usdc ?? 0) : 0;
|
|
388
|
-
const solUsdc = solBal.status === "fulfilled" ? Number(solBal.value?.usdc ?? 0) : 0;
|
|
389
|
-
if (evmUsdc > solUsdc) preferredNetwork = "base";
|
|
390
|
-
else if (solUsdc > evmUsdc) preferredNetwork = "solana";
|
|
391
|
-
}
|
|
392
|
-
const x402PaymentClient = await buildX402Client(wallet, {
|
|
393
|
-
preferredNetwork,
|
|
394
|
-
network: flags.network,
|
|
395
|
-
spendLimitDaily: config?.spendLimitDaily,
|
|
396
|
-
spendLimitPerTx: config?.spendLimitPerTx
|
|
397
|
-
});
|
|
576
|
+
const resolvedProtocol = flags.protocol ?? config?.preferredProtocol ?? "x402";
|
|
398
577
|
const { Client } = await import("@modelcontextprotocol/sdk/client/index.js");
|
|
399
578
|
const { SSEClientTransport } = await import("@modelcontextprotocol/sdk/client/sse.js");
|
|
400
579
|
const { StreamableHTTPClientTransport } = await import("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
401
580
|
const { Server } = await import("@modelcontextprotocol/sdk/server/index.js");
|
|
402
581
|
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
403
|
-
const {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
582
|
+
const { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ToolListChangedNotificationSchema, ResourceListChangedNotificationSchema } = await import("@modelcontextprotocol/sdk/types.js");
|
|
583
|
+
async function connectTransport(target) {
|
|
584
|
+
try {
|
|
585
|
+
const transport = new StreamableHTTPClientTransport(new URL(remoteUrl));
|
|
586
|
+
await target.connect(transport);
|
|
587
|
+
dim(" Connected via StreamableHTTP");
|
|
588
|
+
return;
|
|
589
|
+
} catch {}
|
|
590
|
+
try {
|
|
591
|
+
const transport = new SSEClientTransport(new URL(remoteUrl));
|
|
592
|
+
await target.connect(transport);
|
|
593
|
+
dim(" Connected via SSE");
|
|
594
|
+
} catch (err) {
|
|
595
|
+
error(`Failed to connect to ${remoteUrl}: ${err instanceof Error ? err.message : String(err)}`);
|
|
596
|
+
process.exit(1);
|
|
414
597
|
}
|
|
415
|
-
});
|
|
416
|
-
x402Mcp.onAfterPayment(async (ctx) => {
|
|
417
|
-
ensureConfigDir();
|
|
418
|
-
const accepted = ctx.paymentPayload.accepted;
|
|
419
|
-
const tx = ctx.settleResponse?.transaction;
|
|
420
|
-
const record = {
|
|
421
|
-
t: Date.now(),
|
|
422
|
-
ok: true,
|
|
423
|
-
kind: "x402_payment",
|
|
424
|
-
net: accepted?.network ?? "unknown",
|
|
425
|
-
from: wallet.evmAddress ?? wallet.solanaAddress ?? "unknown",
|
|
426
|
-
to: accepted?.payTo,
|
|
427
|
-
tx: typeof tx === "string" ? tx : void 0,
|
|
428
|
-
amount: accepted?.amount ? Number(accepted.amount) / 1e6 : void 0,
|
|
429
|
-
token: "USDC",
|
|
430
|
-
label: `mcp:${ctx.toolName}`
|
|
431
|
-
};
|
|
432
|
-
appendHistory(getHistoryPath(), record);
|
|
433
|
-
});
|
|
434
|
-
let connected = false;
|
|
435
|
-
try {
|
|
436
|
-
const transport = new StreamableHTTPClientTransport(new URL(remoteUrl));
|
|
437
|
-
await x402Mcp.connect(transport);
|
|
438
|
-
connected = true;
|
|
439
|
-
dim(" Connected via StreamableHTTP");
|
|
440
|
-
} catch {}
|
|
441
|
-
if (!connected) try {
|
|
442
|
-
const transport = new SSEClientTransport(new URL(remoteUrl));
|
|
443
|
-
await x402Mcp.connect(transport);
|
|
444
|
-
connected = true;
|
|
445
|
-
dim(" Connected via SSE");
|
|
446
|
-
} catch (err) {
|
|
447
|
-
error(`Failed to connect to ${remoteUrl}: ${err instanceof Error ? err.message : String(err)}`);
|
|
448
|
-
process.exit(1);
|
|
449
598
|
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
599
|
+
if (resolvedProtocol === "mpp") await startMppProxy();
|
|
600
|
+
else await startX402Proxy();
|
|
601
|
+
async function startX402Proxy() {
|
|
602
|
+
let preferredNetwork = config?.defaultNetwork;
|
|
603
|
+
if (!preferredNetwork && wallet.evmAddress && wallet.solanaAddress) {
|
|
604
|
+
const { fetchAllBalances } = await import("../wallet-DjixXCHy.js");
|
|
605
|
+
const balances = await fetchAllBalances(wallet.evmAddress, wallet.solanaAddress);
|
|
606
|
+
const evmUsdc = balances.evm ? Number(balances.evm.usdc) : 0;
|
|
607
|
+
const solUsdc = balances.sol ? Number(balances.sol.usdc) : 0;
|
|
608
|
+
if (evmUsdc > solUsdc) preferredNetwork = "base";
|
|
609
|
+
else if (solUsdc > evmUsdc) preferredNetwork = "solana";
|
|
610
|
+
}
|
|
611
|
+
const x402PaymentClient = await buildX402Client(wallet, {
|
|
612
|
+
preferredNetwork,
|
|
613
|
+
network: flags.network,
|
|
614
|
+
spendLimitDaily: config?.spendLimitDaily,
|
|
615
|
+
spendLimitPerTx: config?.spendLimitPerTx
|
|
616
|
+
});
|
|
617
|
+
const { x402MCPClient } = await import("@x402/mcp");
|
|
618
|
+
const remoteClient = new Client({
|
|
619
|
+
name: "x402-proxy",
|
|
620
|
+
version: "0.6.0"
|
|
621
|
+
});
|
|
622
|
+
const x402Mcp = new x402MCPClient(remoteClient, x402PaymentClient, {
|
|
623
|
+
autoPayment: true,
|
|
624
|
+
onPaymentRequested: (ctx) => {
|
|
625
|
+
const accept = ctx.paymentRequired.accepts?.[0];
|
|
626
|
+
if (accept) warn(` Payment: ${accept.amount ? (Number(accept.amount) / 1e6).toFixed(4) : "?"} USDC on ${displayNetwork(accept.network)} for tool "${ctx.toolName}"`);
|
|
627
|
+
return true;
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
x402Mcp.onAfterPayment(async (ctx) => {
|
|
631
|
+
const accepted = ctx.paymentPayload.accepted;
|
|
632
|
+
const tx = ctx.settleResponse?.transaction;
|
|
633
|
+
const record = {
|
|
634
|
+
t: Date.now(),
|
|
635
|
+
ok: true,
|
|
636
|
+
kind: "x402_payment",
|
|
637
|
+
net: accepted?.network ?? "unknown",
|
|
638
|
+
from: wallet.evmAddress ?? wallet.solanaAddress ?? "unknown",
|
|
639
|
+
to: accepted?.payTo,
|
|
640
|
+
tx: typeof tx === "string" ? tx : void 0,
|
|
641
|
+
amount: accepted?.amount ? Number(accepted.amount) / 1e6 : void 0,
|
|
642
|
+
token: "USDC",
|
|
643
|
+
label: `mcp:${ctx.toolName}`
|
|
644
|
+
};
|
|
645
|
+
appendHistory(getHistoryPath(), record);
|
|
646
|
+
});
|
|
647
|
+
await connectTransport(x402Mcp);
|
|
648
|
+
let { tools } = await x402Mcp.listTools();
|
|
649
|
+
dim(` ${tools.length} tools available`);
|
|
650
|
+
let remoteResources = [];
|
|
651
|
+
try {
|
|
652
|
+
remoteResources = (await x402Mcp.listResources()).resources;
|
|
653
|
+
if (remoteResources.length > 0) dim(` ${remoteResources.length} resources available`);
|
|
654
|
+
} catch {
|
|
655
|
+
dim(" Resources not available from remote");
|
|
656
|
+
}
|
|
657
|
+
const localServer = new Server({
|
|
658
|
+
name: "x402-proxy",
|
|
659
|
+
version: "0.6.0"
|
|
660
|
+
}, { capabilities: {
|
|
661
|
+
tools: tools.length > 0 ? {} : void 0,
|
|
662
|
+
resources: remoteResources.length > 0 ? {} : void 0
|
|
663
|
+
} });
|
|
664
|
+
localServer.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: tools.map((t) => ({
|
|
665
|
+
name: t.name,
|
|
666
|
+
description: t.description,
|
|
667
|
+
inputSchema: t.inputSchema,
|
|
668
|
+
annotations: t.annotations
|
|
669
|
+
})) }));
|
|
670
|
+
localServer.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
671
|
+
const { name, arguments: args } = request.params;
|
|
672
|
+
const result = await x402Mcp.callTool(name, args ?? {});
|
|
673
|
+
return {
|
|
674
|
+
content: result.content,
|
|
675
|
+
isError: result.isError
|
|
676
|
+
};
|
|
677
|
+
});
|
|
678
|
+
if (remoteResources.length > 0) {
|
|
679
|
+
localServer.setRequestHandler(ListResourcesRequestSchema, async () => ({ resources: remoteResources.map((r) => ({
|
|
680
|
+
name: r.name,
|
|
681
|
+
uri: r.uri,
|
|
682
|
+
description: r.description,
|
|
683
|
+
mimeType: r.mimeType
|
|
684
|
+
})) }));
|
|
685
|
+
localServer.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
686
|
+
return { contents: (await x402Mcp.readResource({ uri: request.params.uri })).contents.map((c) => ({ ...c })) };
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
remoteClient.setNotificationHandler(ToolListChangedNotificationSchema, async () => {
|
|
690
|
+
tools = (await x402Mcp.listTools()).tools;
|
|
691
|
+
dim(` Tools updated: ${tools.length} available`);
|
|
692
|
+
await localServer.notification({ method: "notifications/tools/list_changed" });
|
|
693
|
+
});
|
|
694
|
+
if (remoteResources.length > 0) remoteClient.setNotificationHandler(ResourceListChangedNotificationSchema, async () => {
|
|
695
|
+
remoteResources = (await x402Mcp.listResources()).resources;
|
|
696
|
+
dim(` Resources updated: ${remoteResources.length} available`);
|
|
697
|
+
await localServer.notification({ method: "notifications/resources/list_changed" });
|
|
698
|
+
});
|
|
699
|
+
const stdioTransport = new StdioServerTransport();
|
|
700
|
+
await localServer.connect(stdioTransport);
|
|
701
|
+
dim(" MCP proxy running (stdio, x402)");
|
|
702
|
+
let closing = false;
|
|
703
|
+
const cleanup = async () => {
|
|
704
|
+
if (closing) return;
|
|
705
|
+
closing = true;
|
|
706
|
+
await x402Mcp.close();
|
|
707
|
+
process.exit(0);
|
|
479
708
|
};
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
709
|
+
process.stdin.on("end", cleanup);
|
|
710
|
+
process.on("SIGINT", cleanup);
|
|
711
|
+
process.on("SIGTERM", cleanup);
|
|
712
|
+
}
|
|
713
|
+
async function startMppProxy() {
|
|
714
|
+
if (!wallet.evmKey) {
|
|
715
|
+
error("MPP requires an EVM wallet. Configure one with: npx x402-proxy setup");
|
|
716
|
+
process.exit(1);
|
|
717
|
+
}
|
|
718
|
+
const { tempo } = await import("mppx/client");
|
|
719
|
+
const { McpClient } = await import("mppx/mcp-sdk/client");
|
|
720
|
+
const { privateKeyToAccount } = await import("viem/accounts");
|
|
721
|
+
const account = privateKeyToAccount(wallet.evmKey);
|
|
722
|
+
const maxDeposit = config?.mppSessionBudget ?? "1";
|
|
723
|
+
const remoteClient = new Client({
|
|
724
|
+
name: "x402-proxy",
|
|
725
|
+
version: "0.6.0"
|
|
726
|
+
});
|
|
727
|
+
await connectTransport(remoteClient);
|
|
728
|
+
const mppClient = McpClient.wrap(remoteClient, { methods: [tempo({
|
|
729
|
+
account,
|
|
730
|
+
maxDeposit
|
|
731
|
+
})] });
|
|
732
|
+
let { tools } = await remoteClient.listTools();
|
|
733
|
+
dim(` ${tools.length} tools available`);
|
|
734
|
+
let remoteResources = [];
|
|
735
|
+
try {
|
|
736
|
+
remoteResources = (await remoteClient.listResources()).resources;
|
|
737
|
+
if (remoteResources.length > 0) dim(` ${remoteResources.length} resources available`);
|
|
738
|
+
} catch {
|
|
739
|
+
dim(" Resources not available from remote");
|
|
740
|
+
}
|
|
741
|
+
const localServer = new Server({
|
|
742
|
+
name: "x402-proxy",
|
|
743
|
+
version: "0.6.0"
|
|
744
|
+
}, { capabilities: {
|
|
745
|
+
tools: tools.length > 0 ? {} : void 0,
|
|
746
|
+
resources: remoteResources.length > 0 ? {} : void 0
|
|
747
|
+
} });
|
|
748
|
+
localServer.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: tools.map((t) => ({
|
|
749
|
+
name: t.name,
|
|
750
|
+
description: t.description,
|
|
751
|
+
inputSchema: t.inputSchema,
|
|
752
|
+
annotations: t.annotations
|
|
487
753
|
})) }));
|
|
488
|
-
localServer.setRequestHandler(
|
|
489
|
-
|
|
754
|
+
localServer.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
755
|
+
const { name, arguments: args } = request.params;
|
|
756
|
+
const result = await mppClient.callTool({
|
|
757
|
+
name,
|
|
758
|
+
arguments: args ?? {}
|
|
759
|
+
});
|
|
760
|
+
if (result.receipt) {
|
|
761
|
+
const record = {
|
|
762
|
+
t: Date.now(),
|
|
763
|
+
ok: true,
|
|
764
|
+
kind: "mpp_payment",
|
|
765
|
+
net: TEMPO_NETWORK,
|
|
766
|
+
from: wallet.evmAddress ?? "unknown",
|
|
767
|
+
tx: result.receipt.reference,
|
|
768
|
+
token: "USDC",
|
|
769
|
+
label: `mcp:${name}`
|
|
770
|
+
};
|
|
771
|
+
appendHistory(getHistoryPath(), record);
|
|
772
|
+
warn(` MPP payment for tool "${name}" (Tempo)`);
|
|
773
|
+
}
|
|
774
|
+
return {
|
|
775
|
+
content: result.content,
|
|
776
|
+
isError: result.isError
|
|
777
|
+
};
|
|
490
778
|
});
|
|
779
|
+
if (remoteResources.length > 0) {
|
|
780
|
+
localServer.setRequestHandler(ListResourcesRequestSchema, async () => ({ resources: remoteResources.map((r) => ({
|
|
781
|
+
name: r.name,
|
|
782
|
+
uri: r.uri,
|
|
783
|
+
description: r.description,
|
|
784
|
+
mimeType: r.mimeType
|
|
785
|
+
})) }));
|
|
786
|
+
localServer.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
787
|
+
return { contents: (await remoteClient.readResource({ uri: request.params.uri })).contents.map((c) => ({ ...c })) };
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
remoteClient.setNotificationHandler(ToolListChangedNotificationSchema, async () => {
|
|
791
|
+
tools = (await remoteClient.listTools()).tools;
|
|
792
|
+
dim(` Tools updated: ${tools.length} available`);
|
|
793
|
+
await localServer.notification({ method: "notifications/tools/list_changed" });
|
|
794
|
+
});
|
|
795
|
+
if (remoteResources.length > 0) remoteClient.setNotificationHandler(ResourceListChangedNotificationSchema, async () => {
|
|
796
|
+
remoteResources = (await remoteClient.listResources()).resources;
|
|
797
|
+
dim(` Resources updated: ${remoteResources.length} available`);
|
|
798
|
+
await localServer.notification({ method: "notifications/resources/list_changed" });
|
|
799
|
+
});
|
|
800
|
+
const stdioTransport = new StdioServerTransport();
|
|
801
|
+
await localServer.connect(stdioTransport);
|
|
802
|
+
dim(" MCP proxy running (stdio, mpp)");
|
|
803
|
+
let closing = false;
|
|
804
|
+
const cleanup = async () => {
|
|
805
|
+
if (closing) return;
|
|
806
|
+
closing = true;
|
|
807
|
+
await remoteClient.close();
|
|
808
|
+
process.exit(0);
|
|
809
|
+
};
|
|
810
|
+
process.stdin.on("end", cleanup);
|
|
811
|
+
process.on("SIGINT", cleanup);
|
|
812
|
+
process.on("SIGTERM", cleanup);
|
|
491
813
|
}
|
|
492
|
-
remoteClient.setNotificationHandler(ToolListChangedNotificationSchema, async () => {
|
|
493
|
-
tools = (await x402Mcp.listTools()).tools;
|
|
494
|
-
dim(` Tools updated: ${tools.length} available`);
|
|
495
|
-
await localServer.notification({ method: "notifications/tools/list_changed" });
|
|
496
|
-
});
|
|
497
|
-
if (remoteResources.length > 0) remoteClient.setNotificationHandler(ResourceListChangedNotificationSchema, async () => {
|
|
498
|
-
remoteResources = (await x402Mcp.listResources()).resources;
|
|
499
|
-
dim(` Resources updated: ${remoteResources.length} available`);
|
|
500
|
-
await localServer.notification({ method: "notifications/resources/list_changed" });
|
|
501
|
-
});
|
|
502
|
-
const stdioTransport = new StdioServerTransport();
|
|
503
|
-
await localServer.connect(stdioTransport);
|
|
504
|
-
dim(" MCP proxy running (stdio)");
|
|
505
|
-
process.stdin.on("end", async () => {
|
|
506
|
-
await x402Mcp.close();
|
|
507
|
-
process.exit(0);
|
|
508
|
-
});
|
|
509
814
|
}
|
|
510
815
|
});
|
|
511
816
|
|
|
@@ -635,7 +940,7 @@ const routes = buildRouteMap({
|
|
|
635
940
|
});
|
|
636
941
|
const app = buildApplication(routes, {
|
|
637
942
|
name: "x402-proxy",
|
|
638
|
-
versionInfo: { currentVersion: "0.
|
|
943
|
+
versionInfo: { currentVersion: "0.6.0" },
|
|
639
944
|
scanner: { caseStyle: "allow-kebab-for-camel" }
|
|
640
945
|
});
|
|
641
946
|
|