@bankofai/x402-cli 1.0.1-beta.0 → 1.0.1-beta.10
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/README.md +56 -20
- package/dist/args.js +96 -0
- package/dist/catalog-commands.js +558 -0
- package/dist/cli.js +104 -1372
- package/dist/daemon.js +47 -0
- package/dist/gateway/catalog.js +56 -0
- package/dist/gateway/config.js +88 -18
- package/dist/gateway/index.js +3 -0
- package/dist/gateway/server.js +192 -53
- package/dist/gateway/tokens.js +19 -7
- package/dist/gateway-commands.js +145 -0
- package/dist/help.js +169 -0
- package/dist/http-client.js +82 -0
- package/dist/output.js +91 -0
- package/dist/tokens.js +22 -10
- package/dist/x402.js +25 -11
- package/package.json +12 -8
package/README.md
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
TypeScript command-line client for BankofAI x402 payments. This version uses
|
|
4
4
|
the npm TypeScript SDK packages only:
|
|
5
5
|
|
|
6
|
-
- `@bankofai/x402-core@1.0.1
|
|
7
|
-
- `@bankofai/x402-evm@1.0.1
|
|
8
|
-
- `@bankofai/x402-tron@1.0.1
|
|
6
|
+
- `@bankofai/x402-core@1.0.1`
|
|
7
|
+
- `@bankofai/x402-evm@1.0.1`
|
|
8
|
+
- `@bankofai/x402-tron@1.0.1`
|
|
9
9
|
|
|
10
10
|
Stablecoin payments support `scheme=exact` and TRON `scheme=exact_gasfree`.
|
|
11
11
|
The GasFree flow lets the relayer pay network energy while deducting its fee
|
|
@@ -13,6 +13,15 @@ from the payment token, so the payer does not need TRX.
|
|
|
13
13
|
|
|
14
14
|
## Install
|
|
15
15
|
|
|
16
|
+
Install the CLI package:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g @bankofai/x402-cli@beta
|
|
20
|
+
x402-cli --version
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
For repository development:
|
|
24
|
+
|
|
16
25
|
```bash
|
|
17
26
|
npm install
|
|
18
27
|
npm run build
|
|
@@ -21,7 +30,7 @@ npm run build
|
|
|
21
30
|
Run from source during development:
|
|
22
31
|
|
|
23
32
|
```bash
|
|
24
|
-
npm run dev -- serve --pay-to <recipient> --amount 0.0001 --network tron:
|
|
33
|
+
npm run dev -- serve --pay-to <recipient> --amount 0.0001 --network tron:0xcd8690dc --token USDT
|
|
25
34
|
```
|
|
26
35
|
|
|
27
36
|
Run the compiled CLI:
|
|
@@ -49,10 +58,10 @@ envelope with `ok`, `command`, `result`, or structured `error` fields.
|
|
|
49
58
|
Start a local x402 paywall endpoint:
|
|
50
59
|
|
|
51
60
|
```bash
|
|
52
|
-
|
|
61
|
+
x402-cli serve \
|
|
53
62
|
--pay-to <recipient> \
|
|
54
63
|
--amount 0.0001 \
|
|
55
|
-
--network tron:
|
|
64
|
+
--network tron:0xcd8690dc \
|
|
56
65
|
--token USDT \
|
|
57
66
|
--port 4020
|
|
58
67
|
```
|
|
@@ -61,8 +70,8 @@ The server exposes:
|
|
|
61
70
|
|
|
62
71
|
- `GET /health`
|
|
63
72
|
- `GET /.well-known/x402`
|
|
64
|
-
-
|
|
65
|
-
-
|
|
73
|
+
- `/pay` returns `402 Payment Required` without a payment signature
|
|
74
|
+
- The signed retry uses the same HTTP method, then verifies and settles with the facilitator
|
|
66
75
|
|
|
67
76
|
### Pay
|
|
68
77
|
|
|
@@ -70,18 +79,21 @@ Pay an x402-protected URL:
|
|
|
70
79
|
|
|
71
80
|
```bash
|
|
72
81
|
TRON_PRIVATE_KEY=<hex> \
|
|
73
|
-
|
|
74
|
-
--network tron:
|
|
82
|
+
x402-cli pay http://127.0.0.1:4020/pay \
|
|
83
|
+
--network tron:0xcd8690dc \
|
|
75
84
|
--token USDT
|
|
76
85
|
```
|
|
77
86
|
|
|
87
|
+
For automated or unfamiliar endpoints, set `--max-amount` or
|
|
88
|
+
`--max-raw-amount` before allowing the CLI to sign a payment.
|
|
89
|
+
|
|
78
90
|
Pay a TRON GasFree endpoint (the CLI normally selects this automatically from
|
|
79
91
|
the server challenge):
|
|
80
92
|
|
|
81
93
|
```bash
|
|
82
94
|
TRON_PRIVATE_KEY=<hex> \
|
|
83
|
-
|
|
84
|
-
--network tron:
|
|
95
|
+
x402-cli pay https://api.example.com/pay \
|
|
96
|
+
--network tron:0xcd8690dc \
|
|
85
97
|
--token USDT \
|
|
86
98
|
--scheme exact_gasfree
|
|
87
99
|
```
|
|
@@ -89,7 +101,31 @@ node dist/cli.js pay https://api.example.com/pay \
|
|
|
89
101
|
Use `--gasfree-api-url <url>` or `X402_GASFREE_API_URL` to override the SDK's
|
|
90
102
|
default relayer endpoint.
|
|
91
103
|
|
|
104
|
+
GasFree fees are separate from the advertised payment amount. Set a fee limit
|
|
105
|
+
so the CLI estimates the relayer fee and rejects the payment before signing if
|
|
106
|
+
the estimate is too high:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
x402-cli pay https://api.example.com/pay \
|
|
110
|
+
--scheme exact_gasfree \
|
|
111
|
+
--max-amount 0.01 \
|
|
112
|
+
--max-gasfree-fee 0.5 \
|
|
113
|
+
--json
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Use `--max-gasfree-fee-raw` to express the fee limit in the token's smallest
|
|
117
|
+
unit. Successful and failed paid responses distinguish `settled` (payment
|
|
118
|
+
completed) from `delivered` (HTTP business response succeeded). A settled
|
|
119
|
+
upstream failure has `paid=true`, `settled=true`, and `delivered=false` and
|
|
120
|
+
includes its transaction information.
|
|
121
|
+
|
|
92
122
|
For EVM networks use `EVM_PRIVATE_KEY` or `PRIVATE_KEY`.
|
|
123
|
+
Prefer environment variables over `--private-key` in shared environments,
|
|
124
|
+
because command-line arguments may be visible to other local processes.
|
|
125
|
+
|
|
126
|
+
If the gateway settles a payment but the upstream request fails, JSON error
|
|
127
|
+
output includes `error.details.paymentResponse` for reconciliation. Do not retry
|
|
128
|
+
such a request blindly; inspect the transaction and provider behavior first.
|
|
93
129
|
|
|
94
130
|
### Roundtrip
|
|
95
131
|
|
|
@@ -97,10 +133,10 @@ Start a temporary local server and immediately pay it:
|
|
|
97
133
|
|
|
98
134
|
```bash
|
|
99
135
|
TRON_PRIVATE_KEY=<hex> \
|
|
100
|
-
|
|
136
|
+
x402-cli roundtrip \
|
|
101
137
|
--pay-to <recipient> \
|
|
102
138
|
--amount 0.0001 \
|
|
103
|
-
--network tron:
|
|
139
|
+
--network tron:0xcd8690dc \
|
|
104
140
|
--token USDT
|
|
105
141
|
```
|
|
106
142
|
|
|
@@ -108,16 +144,16 @@ node dist/cli.js roundtrip \
|
|
|
108
144
|
|
|
109
145
|
Supported built-in token registry:
|
|
110
146
|
|
|
111
|
-
- `tron:
|
|
112
|
-
- `tron:
|
|
113
|
-
- `tron:
|
|
147
|
+
- `tron:0x2b6653dc` USDT, USDD
|
|
148
|
+
- `tron:0xcd8690dc` USDT, USDD
|
|
149
|
+
- `tron:0x94a9059e` USDT
|
|
114
150
|
- `eip155:56` USDT
|
|
115
151
|
- `eip155:97` USDT, USDC
|
|
116
152
|
|
|
117
|
-
|
|
153
|
+
Non-CAIP TRON aliases are rejected. Use the canonical TRON IDs above.
|
|
154
|
+
|
|
155
|
+
EVM convenience aliases accepted:
|
|
118
156
|
|
|
119
|
-
- `tron-mainnet` -> `tron:mainnet`
|
|
120
|
-
- `tron-nile` -> `tron:nile`
|
|
121
157
|
- `bsc-mainnet` -> `eip155:56`
|
|
122
158
|
- `bsc-testnet` -> `eip155:97`
|
|
123
159
|
|
package/dist/args.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const BOOLEAN_FLAGS = new Set([
|
|
2
|
+
"daemon", "dry-run", "force", "help", "human", "include-blocked", "json", "raw", "version",
|
|
3
|
+
]);
|
|
4
|
+
export class CliError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
hint;
|
|
7
|
+
exitCode;
|
|
8
|
+
details;
|
|
9
|
+
constructor(code, message, hint, exitCode = 1, details) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.hint = hint;
|
|
13
|
+
this.exitCode = exitCode;
|
|
14
|
+
this.details = details;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function parseArgs(argv) {
|
|
18
|
+
const [command = "help", ...rest] = argv;
|
|
19
|
+
const positional = [];
|
|
20
|
+
const options = {};
|
|
21
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
22
|
+
const item = rest[i];
|
|
23
|
+
if (item === "-h") {
|
|
24
|
+
options.help = true;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (item === "-V") {
|
|
28
|
+
options.version = true;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (item === "-d") {
|
|
32
|
+
options.daemon = true;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (item === "-n") {
|
|
36
|
+
const next = rest[i + 1];
|
|
37
|
+
if (!next || next.startsWith("-"))
|
|
38
|
+
options.limit = true;
|
|
39
|
+
else {
|
|
40
|
+
options.limit = next;
|
|
41
|
+
i += 1;
|
|
42
|
+
}
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (!item.startsWith("--")) {
|
|
46
|
+
positional.push(item);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const eq = item.indexOf("=");
|
|
50
|
+
const key = eq > 2 ? item.slice(2, eq) : item.slice(2);
|
|
51
|
+
const inline = eq > 2 ? item.slice(eq + 1) : undefined;
|
|
52
|
+
const next = rest[i + 1];
|
|
53
|
+
if (inline !== undefined)
|
|
54
|
+
options[key] = inline;
|
|
55
|
+
else if (BOOLEAN_FLAGS.has(key))
|
|
56
|
+
options[key] = true;
|
|
57
|
+
else if (!next || next.startsWith("--")) {
|
|
58
|
+
throw new CliError("MISSING_ARGUMENT", `--${key} requires a value`, `Pass --${key} <value>.`, 2);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
if (key === "header") {
|
|
62
|
+
const current = options[key];
|
|
63
|
+
options[key] = Array.isArray(current) ? [...current, next] : current ? [String(current), next] : [next];
|
|
64
|
+
}
|
|
65
|
+
else
|
|
66
|
+
options[key] = next;
|
|
67
|
+
i += 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { command, positional, options };
|
|
71
|
+
}
|
|
72
|
+
export function opt(options, key, fallback) {
|
|
73
|
+
const value = options[key];
|
|
74
|
+
return typeof value === "string" ? value : fallback;
|
|
75
|
+
}
|
|
76
|
+
export function hasFlag(options, key) {
|
|
77
|
+
return options[key] === true;
|
|
78
|
+
}
|
|
79
|
+
export function outputMode(options) {
|
|
80
|
+
if (hasFlag(options, "json") && hasFlag(options, "human")) {
|
|
81
|
+
throw new CliError("INVALID_ARGUMENT", "--json and --human are mutually exclusive", "Pass either --json or --human, not both.", 2);
|
|
82
|
+
}
|
|
83
|
+
return hasFlag(options, "json") ? "json" : "human";
|
|
84
|
+
}
|
|
85
|
+
export function requireArgument(value, name, usage) {
|
|
86
|
+
if (value === undefined || value === "") {
|
|
87
|
+
throw new CliError("MISSING_ARGUMENT", `${name} is required`, `Usage: ${usage}`, 2);
|
|
88
|
+
}
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
export function optAll(options, key) {
|
|
92
|
+
const value = options[key];
|
|
93
|
+
if (Array.isArray(value))
|
|
94
|
+
return value;
|
|
95
|
+
return typeof value === "string" ? [value] : [];
|
|
96
|
+
}
|