Skip to content

Commit 030d41f

Browse files
committed
fix(cli): add curl-style short flags and SSE stream resilience
- Add -X (method), -d (body) aliases via Stricli - Add -H (header) via argv preprocessing (Stricli reserves -H) - Swallow Node.js "terminated" errors on SSE stream close - Bump mppx to ^0.4.9 (204-safe receipts, idempotent vouchers)
1 parent d6b8839 commit 030d41f

6 files changed

Lines changed: 43 additions & 19 deletions

File tree

packages/x402-proxy/CHANGELOG.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.8.1] - 2026-03-24
11+
12+
### Added
13+
- Curl-style short flags: `-X` (method), `-H` (header), `-d` (body) for the `fetch` command
14+
- `-H` preprocessing in CLI entry point to work around Stricli reserving `-H` for `--help-all`
15+
16+
### Fixed
17+
- SSE streaming resilience: swallow Node.js "terminated" errors when server closes connection after final event, so payment logging still completes
18+
- Bumped `mppx` to ^0.4.9 (fixes 204-safe SSE receipt wrapping and idempotent voucher replay)
19+
1020
## [0.8.0] - 2026-03-21
1121

1222
### Added
@@ -204,7 +214,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
204214
- `appendHistory` / `readHistory` / `calcSpend` - JSONL transaction history
205215
- Re-exports from `@x402/fetch`, `@x402/svm`, `@x402/evm`
206216

207-
[Unreleased]: https://github.com/cascade-protocol/x402-proxy/compare/v0.8.0...HEAD
217+
[Unreleased]: https://github.com/cascade-protocol/x402-proxy/compare/v0.8.1...HEAD
218+
[0.8.1]: https://github.com/cascade-protocol/x402-proxy/compare/v0.8.0...v0.8.1
208219
[0.8.0]: https://github.com/cascade-protocol/x402-proxy/compare/v0.7.1...v0.8.0
209220
[0.7.1]: https://github.com/cascade-protocol/x402-proxy/compare/v0.7.0...v0.7.1
210221
[0.7.0]: https://github.com/cascade-protocol/x402-proxy/compare/v0.6.0...v0.7.0

packages/x402-proxy/README.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ Works like curl. Response body streams to stdout, payment info goes to stderr.
4040
# GET request
4141
$ npx x402-proxy https://twitter.surf.cascade.fyi/users/cascade_fyi
4242

43-
# POST with body and headers
44-
$ npx x402-proxy --method POST \
45-
--header "Content-Type: application/json" \
46-
--body '{"url":"https://x402.org"}' \
43+
# POST with body and headers (curl-style short flags: -X, -H, -d)
44+
$ npx x402-proxy -X POST \
45+
-H "Content-Type: application/json" \
46+
-d '{"url":"https://x402.org"}' \
4747
https://web.surf.cascade.fyi/v1/crawl
4848

4949
# Force a specific network
@@ -54,9 +54,8 @@ $ npx x402-proxy --verbose https://api.example.com/data
5454

5555
# Use MPP protocol for streaming payments
5656
$ npx x402-proxy --protocol mpp \
57-
--method POST \
58-
--header "Content-Type: application/json" \
59-
--body '{"model":"minimax/minimax-m2.5","stream":true,"messages":[{"role":"user","content":"Hello"}]}' \
57+
-X POST -H "Content-Type: application/json" \
58+
-d '{"model":"minimax/minimax-m2.5","stream":true,"messages":[{"role":"user","content":"Hello"}]}' \
6059
https://inference.surf.cascade.fyi/v1/chat/completions
6160

6261
# Pipe-safe

packages/x402-proxy/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "x402-proxy",
3-
"version": "0.8.0",
3+
"version": "0.8.1",
44
"description": "curl for x402 paid APIs. Auto-pays any endpoint on Base, Solana, and Tempo. Also works as an OpenClaw plugin.",
55
"type": "module",
66
"sideEffects": false,
@@ -47,7 +47,7 @@
4747
"@x402/evm": "^2.6.0",
4848
"@x402/fetch": "^2.6.0",
4949
"@x402/mcp": "^2.6.0",
50-
"mppx": "^0.4.7",
50+
"mppx": "^0.4.9",
5151
"@x402/svm": "^2.6.0",
5252
"ethers": "^6.0.0",
5353
"picocolors": "^1.1.1",

packages/x402-proxy/src/bin/cli.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,6 @@ import { run } from "@stricli/core";
22
import { app } from "../app.js";
33
import { buildContext } from "../context.js";
44

5-
await run(app, process.argv.slice(2), buildContext(process));
5+
// Stricli reserves -H for --help-all. Pre-process to support curl-style -H for headers.
6+
const args = process.argv.slice(2).map((a) => (a === "-H" ? "--header" : a));
7+
await run(app, args, buildContext(process));

packages/x402-proxy/src/commands/fetch.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ Examples:
9999
default: false,
100100
},
101101
},
102+
aliases: {
103+
X: "method",
104+
d: "body",
105+
},
102106
positional: {
103107
kind: "tuple",
104108
parameters: [
@@ -273,8 +277,16 @@ Examples:
273277
verbose("opening SSE session...");
274278
const tokens = await mppHandler.sse(parsedUrl.toString(), init);
275279
verbose("SSE stream opened, reading tokens...");
276-
for await (const token of tokens) {
277-
process.stdout.write(token);
280+
try {
281+
for await (const token of tokens) {
282+
process.stdout.write(token);
283+
}
284+
} catch (streamErr) {
285+
// Server may close connection after final SSE event (e.g. mppx 204 receipt bug).
286+
// Swallow "terminated" so payment/history logging still runs.
287+
const msg = streamErr instanceof Error ? streamErr.message : String(streamErr);
288+
verbose(`SSE stream error: ${msg}`);
289+
if (!msg.includes("terminated")) throw streamErr;
278290
}
279291
verbose("SSE stream complete");
280292
} finally {

pnpm-lock.yaml

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)