@paynodelabs/paynode-402-cli 2.6.0 → 2.7.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/commands/check.ts +5 -2
- package/commands/invoke-paid-api.ts +9 -7
- package/commands/mint.ts +8 -3
- package/commands/request.ts +5 -3
- package/marketplace/client.ts +7 -5
- package/package.json +2 -2
- package/utils.ts +5 -4
package/commands/check.ts
CHANGED
|
@@ -24,7 +24,8 @@ export async function checkAction(options: CheckOptions) {
|
|
|
24
24
|
const { provider, usdcAddress, chainId, networkName, isSandbox } = await resolveNetwork(
|
|
25
25
|
options.rpc,
|
|
26
26
|
options.network,
|
|
27
|
-
options.rpcTimeout
|
|
27
|
+
options.rpcTimeout,
|
|
28
|
+
isJson
|
|
28
29
|
);
|
|
29
30
|
|
|
30
31
|
// Mainnet safety gate
|
|
@@ -43,7 +44,9 @@ export async function checkAction(options: CheckOptions) {
|
|
|
43
44
|
provider
|
|
44
45
|
).balanceOf(address)
|
|
45
46
|
]),
|
|
46
|
-
'balanceCheck'
|
|
47
|
+
'balanceCheck',
|
|
48
|
+
undefined,
|
|
49
|
+
isJson
|
|
47
50
|
);
|
|
48
51
|
|
|
49
52
|
// BigInt comparisons are used for logic (no precision loss).
|
|
@@ -32,18 +32,20 @@ function mergeHeaders(
|
|
|
32
32
|
return merged;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
function parsePayload(data?: string): any {
|
|
35
|
+
function parsePayload(data?: string, isJson?: boolean): any {
|
|
36
36
|
if (!data) return undefined;
|
|
37
37
|
|
|
38
38
|
try {
|
|
39
39
|
return JSON.parse(data);
|
|
40
40
|
} catch (err: any) {
|
|
41
41
|
const isJsonLike = data.trim().startsWith('{') || data.trim().startsWith('[');
|
|
42
|
-
if (
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
if (!isJson) {
|
|
43
|
+
if (isJsonLike) {
|
|
44
|
+
console.warn(`⚠️ [Warning] Invocation data looks like JSON but failed to parse: ${err.message}`);
|
|
45
|
+
console.warn(`Sending as raw string instead. Please verify your JSON syntax.`);
|
|
46
|
+
} else {
|
|
47
|
+
console.warn(`⚠️ [Warning] Invocation data is not valid JSON. Sending as raw string.`);
|
|
48
|
+
}
|
|
47
49
|
}
|
|
48
50
|
return data;
|
|
49
51
|
}
|
|
@@ -60,7 +62,7 @@ export async function invokePaidApiAction(apiId: string, options: InvokePaidApiO
|
|
|
60
62
|
|
|
61
63
|
const invoke = await client.prepareInvoke(apiId, {
|
|
62
64
|
network: options.network,
|
|
63
|
-
payload: parsePayload(options.data)
|
|
65
|
+
payload: parsePayload(options.data, isJson)
|
|
64
66
|
});
|
|
65
67
|
|
|
66
68
|
const requestHeaders = mergeHeaders(invoke.headers, options.header);
|
package/commands/mint.ts
CHANGED
|
@@ -21,7 +21,8 @@ export async function mintAction(options: MintOptions) {
|
|
|
21
21
|
const { provider, usdcAddress, chainId, networkName, isSandbox } = await resolveNetwork(
|
|
22
22
|
options.rpc,
|
|
23
23
|
options.network || 'testnet',
|
|
24
|
-
options.rpcTimeout
|
|
24
|
+
options.rpcTimeout,
|
|
25
|
+
isJson
|
|
25
26
|
);
|
|
26
27
|
|
|
27
28
|
if (!isSandbox) {
|
|
@@ -57,13 +58,17 @@ export async function mintAction(options: MintOptions) {
|
|
|
57
58
|
if (!isJson) console.error('⏳ Sending mint transaction...');
|
|
58
59
|
const tx = await withRetry(
|
|
59
60
|
() => usdc.mint(wallet.address, amount),
|
|
60
|
-
'mint'
|
|
61
|
+
'mint',
|
|
62
|
+
undefined,
|
|
63
|
+
isJson
|
|
61
64
|
);
|
|
62
65
|
|
|
63
66
|
if (!isJson) console.error('⏳ Waiting for confirmation...');
|
|
64
67
|
const receipt: any = await withRetry(
|
|
65
68
|
() => tx.wait(),
|
|
66
|
-
'mintConfirm'
|
|
69
|
+
'mintConfirm',
|
|
70
|
+
undefined,
|
|
71
|
+
isJson
|
|
67
72
|
);
|
|
68
73
|
|
|
69
74
|
if (!receipt || receipt.status !== 1) {
|
package/commands/request.ts
CHANGED
|
@@ -164,7 +164,7 @@ async function executeCore(url: string, args: string[], options: UnifiedRequestO
|
|
|
164
164
|
throw new Error(`Invalid destination URL: '${url}'. Must start with 'http://' or 'https://'.`);
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
const { rpcUrls, networkName, isSandbox } = await resolveNetwork(options.rpc, options.network, options.rpcTimeout);
|
|
167
|
+
const { rpcUrls, networkName, isSandbox } = await resolveNetwork(options.rpc, options.network, options.rpcTimeout, isJson);
|
|
168
168
|
requireMainnetConfirmation(isSandbox, !!options.confirmMainnet, isJson);
|
|
169
169
|
|
|
170
170
|
// Handle params (k=v)
|
|
@@ -262,10 +262,12 @@ async function executeCore(url: string, args: string[], options: UnifiedRequestO
|
|
|
262
262
|
|
|
263
263
|
const pk = getPrivateKey(isJson);
|
|
264
264
|
|
|
265
|
-
const client = new PayNodeAgentClient(pk, rpcUrls);
|
|
265
|
+
const client = new PayNodeAgentClient(pk, { rpcUrls, quiet: isJson });
|
|
266
266
|
const response = await withRetry(
|
|
267
267
|
() => client.requestGate(targetUrl, requestOptions),
|
|
268
|
-
'x402:requestGate'
|
|
268
|
+
'x402:requestGate',
|
|
269
|
+
undefined,
|
|
270
|
+
isJson
|
|
269
271
|
);
|
|
270
272
|
|
|
271
273
|
const contentType = response.headers.get('content-type') || 'application/octet-stream';
|
package/marketplace/client.ts
CHANGED
|
@@ -80,9 +80,9 @@ function normalizeCatalogItem(raw: RawCatalogApiItem): CatalogApiItem {
|
|
|
80
80
|
method: raw.method || raw.http_method,
|
|
81
81
|
payable_url: raw.payable_url || raw.payment_url,
|
|
82
82
|
invoke_url: raw.invoke_url,
|
|
83
|
-
input_schema: raw.input_schema,
|
|
84
|
-
sample_response: raw.sample_response,
|
|
85
|
-
headers_template: raw.headers_template
|
|
83
|
+
input_schema: raw.input_schema || {},
|
|
84
|
+
sample_response: raw.sample_response || {},
|
|
85
|
+
headers_template: raw.headers_template || {}
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
88
|
|
|
@@ -99,7 +99,9 @@ export class MarketplaceClient {
|
|
|
99
99
|
const url = joinUrl(this.baseUrl, path);
|
|
100
100
|
const response = await withRetry(
|
|
101
101
|
() => fetch(url, init),
|
|
102
|
-
`marketplace:${path}
|
|
102
|
+
`marketplace:${path}`,
|
|
103
|
+
undefined,
|
|
104
|
+
this.isJson
|
|
103
105
|
);
|
|
104
106
|
|
|
105
107
|
if (!response.ok) {
|
|
@@ -175,7 +177,7 @@ export class MarketplaceClient {
|
|
|
175
177
|
|
|
176
178
|
return preparation;
|
|
177
179
|
} catch (err: any) {
|
|
178
|
-
console.warn(`[Marketplace] /invoke preparation failed for ${apiId}, falling back to direct proxy. Error: ${err.message}`);
|
|
180
|
+
if (!this.isJson) console.warn(`[Marketplace] /invoke preparation failed for ${apiId}, falling back to direct proxy. Error: ${err.message}`);
|
|
179
181
|
const detail = await this.getApiDetail(apiId, options.network);
|
|
180
182
|
const invokeUrl = detail.payable_url || detail.invoke_url;
|
|
181
183
|
if (!invokeUrl) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paynodelabs/paynode-402-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"description": "The official command-line interface for the PayNode protocol. Designed for AI Agents to execute stateless micro-payments via HTTP 402.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.ts",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"build": "echo 'No build required for Bun' && exit 0"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@paynodelabs/sdk-js": "^2.
|
|
26
|
+
"@paynodelabs/sdk-js": "^2.5.0",
|
|
27
27
|
"cac": "7.0.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
package/utils.ts
CHANGED
|
@@ -134,7 +134,8 @@ const MAX_RETRIES = 3;
|
|
|
134
134
|
export async function withRetry<T>(
|
|
135
135
|
fn: () => Promise<T>,
|
|
136
136
|
label: string,
|
|
137
|
-
maxRetries = MAX_RETRIES
|
|
137
|
+
maxRetries = MAX_RETRIES,
|
|
138
|
+
quiet = false
|
|
138
139
|
): Promise<T> {
|
|
139
140
|
let lastError: Error | null = null;
|
|
140
141
|
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
@@ -144,7 +145,7 @@ export async function withRetry<T>(
|
|
|
144
145
|
lastError = error;
|
|
145
146
|
if (!isTransientError(error) || attempt >= maxRetries - 1) throw error;
|
|
146
147
|
const backoffMs = Math.pow(2, attempt) * 1000 * (0.5 + Math.random());
|
|
147
|
-
console.error(`⚠️ [${label}] ${error.message}. Retry #${attempt + 1} (of ${maxRetries - 1}) in ${Math.round(backoffMs)}ms...`);
|
|
148
|
+
if (!quiet) console.error(`⚠️ [${label}] ${error.message}. Retry #${attempt + 1} (of ${maxRetries - 1}) in ${Math.round(backoffMs)}ms...`);
|
|
148
149
|
await new Promise(resolve => setTimeout(resolve, backoffMs));
|
|
149
150
|
}
|
|
150
151
|
}
|
|
@@ -285,7 +286,7 @@ export function requireMainnetConfirmation(isSandbox: boolean, confirmMainnet: b
|
|
|
285
286
|
/**
|
|
286
287
|
* Resolves network configuration with multi-RPC failover.
|
|
287
288
|
*/
|
|
288
|
-
export async function resolveNetwork(providedRpcUrl?: string, network?: string, timeoutMs = DEFAULT_TIMEOUT_MS): Promise<NetworkConfig> {
|
|
289
|
+
export async function resolveNetwork(providedRpcUrl?: string, network?: string, timeoutMs = DEFAULT_TIMEOUT_MS, quiet = false): Promise<NetworkConfig> {
|
|
289
290
|
const {
|
|
290
291
|
PAYNODE_ROUTER_ADDRESS,
|
|
291
292
|
PAYNODE_ROUTER_ADDRESS_SANDBOX,
|
|
@@ -324,7 +325,7 @@ export async function resolveNetwork(providedRpcUrl?: string, network?: string,
|
|
|
324
325
|
break;
|
|
325
326
|
} catch (error: any) {
|
|
326
327
|
lastError = error;
|
|
327
|
-
if (rpcUrls.length > 1) console.error(`⚠️ [resolveNetwork] RPC ${url} failed: ${error.message}.`);
|
|
328
|
+
if (rpcUrls.length > 1 && !quiet) console.error(`⚠️ [resolveNetwork] RPC ${url} failed: ${error.message}.`);
|
|
328
329
|
}
|
|
329
330
|
}
|
|
330
331
|
|