@direct.dev/cli
v1.0.6
Published
Local HTTP proxy and CLI for Direct.dev — routes JSON-RPC traffic through the SDK pipeline.
Downloads
729
Readme
@direct.dev/cli
A local HTTP proxy that routes JSON-RPC traffic through Direct.dev without touching your app code. Point any RPC client at http://localhost:3000/... and the proxy handles caching, sync, and failover on its behalf — the same engine that powers @direct.dev/sdk, packaged as a long-running server.
Because it speaks plain HTTP, any language can use the Direct.dev SDK through the CLI — Go (net/http), Rust (reqwest), Python (requests), C# (HttpClient), Java, PHP, Ruby, shell scripts. No SDK install needed in your target language; just point at http://localhost:3000/....
Highlights
Zero code change
Swap your RPC URL for http://localhost:3000/<project>.<token>/<network>. Works with any HTTP client — viem, ethers, hardhat, foundry, curl.
Same fast path as the SDK
Built on @direct.dev/sdk, so the cache, Direct Sync, and failover behave identically to a browser or server integration.
Live status panel A pinned footer shows current block height, preload state, and live sync state per network, refreshed in place.
Designed for dev loops Sub-millisecond cache hits, color-coded request log, graceful Ctrl+C, TTY-aware output that degrades cleanly when piped.
Install
Requires Node ≥22 (for native WebSocket support — used by Direct Sync).
No install needed — run with npx or bunx:
npx @direct.dev/cli serve --port 3000bunx @direct.dev/cli serve --port 3000Or install globally:
npm install -g @direct.dev/cli
direct serve --port 3000Quick start
Start the proxy:
npx @direct.dev/cli serve --port 3000bunx @direct.dev/cli serve --port 3000You'll see something like:
⚡ direct.dev v1.0.0 ready in 42ms
➜ Local: http://localhost:3000
➜ Network: prod https://prod.rpc.direct.dev
➜ Routes: /<project>.<token>/<network>
────────────────────────────────────────────────────────────────Point your RPC client at the local URL — the path is the same as your Direct.dev RPC URL minus the host and the /v1 prefix:
curl http://localhost:3000/<project>.<token>/ethereum \
-H "content-type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'The proxy forwards to https://prod.rpc.direct.dev/v1/<project>.<token>/ethereum, routes through the SDK pipeline, and streams the response back.
With viem
import { createPublicClient, http } from "viem";
import { mainnet } from "viem/chains";
const client = createPublicClient({
chain: mainnet,
transport: http("http://localhost:3000/<project>.<token>/ethereum"),
});
await client.getBlockNumber();With curl (or any language)
The proxy speaks plain JSON-RPC over HTTP, so any HTTP client works:
curl http://localhost:3000/<project>.<token>/ethereum \
-H "content-type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'The same call shape works from Go (net/http), Rust (reqwest), Python (requests), C# (HttpClient), Java (HttpClient), PHP (curl/Guzzle), Ruby (Net::HTTP), or a shell script. The Direct.dev SDK runs inside the proxy on Node — your client just sees a regular RPC endpoint.
What you'll see
As requests come in, the proxy logs each resolution and keeps a per-network status panel pinned at the bottom:
→ sonic initialized
→ ethereum initialized
→ sonic sync connected
→ ethereum sync connected
✓ sonic ready
✓ ethereum ready
→ ethereum eth_blockNumber 135ms upstream
→ ethereum eth_blockNumber 1.0ms cache
→ sonic eth_getBalance 2.0ms cache
────────────────────────────────────────────────────────────────
● sonic #70214141 preload ✓ sync ✓ ready ✓
● ethereum #25072205 preload ✓ sync ✓ ready ✓- Request log — one line per JSON-RPC method:
→ <network> <method> <latency> <source>. Latency is color-coded green / yellow / red. Source is one ofcache,preload,upstream,secondary,shadow,in-flight,public RPC,configured RPC. - Transition lines — sparse, one-time per network:
initialized,sync connected,preload applieduse→;readyuses ✓. In--verbose, every state transition is logged (including each reconnect/idle cycle). - Status panel — one row per active network with the current block height and capability flags (
preload,sync,ready).✓— capability is active↻— sync is reconnecting (after a stale-data detection)·— no signal yet, or sync is idle (paused after no traffic; will reconnect on demand)
Options
npx @direct.dev/cli serve \
--port 3000 \
--host 127.0.0.1 \
--env prod \
--preload https://prod.rpc.direct.dev/v1/<project>.<token>/ethereum \
--verbose| Option | Default | Description |
| --- | --- | --- |
| --port <port> | 3000 | Local port to listen on. |
| --host <host> | 127.0.0.1 | Local host to bind to. Use 0.0.0.0 to expose on the network. |
| --env <env> | prod | Direct environment: prod, staging. |
| --preload <url> | none | Endpoint to warm at startup. Repeat or comma-separate. |
| -v, --verbose | off | Verbose output — logs every state transition and debug-level SDK events. |
| -q, --quiet | off | Minimal output — errors and a single ready line. |
--preload
Preload URLs are issued as fire-and-forget warmup requests at startup, so the first real request resolves from the local cache. You can pass any of:
- A full Direct URL —
https://prod.rpc.direct.dev/v1/<project>.<token>/ethereum - A path —
/<project>.<token>/ethereum - Comma-separated —
--preload <project>.<token>/ethereum,<project>.<token>/polygon - Repeated —
--preload <project>.<token>/ethereum --preload <project>.<token>/polygon
The spinner clears as soon as the first network goes ready (or after all preload URLs report applied).
--env
Switches the upstream Direct.dev environment. The local path stays the same — only the host the proxy forwards to changes.
| Value | Upstream |
| --- | --- |
| prod | https://prod.rpc.direct.dev |
| staging | https://staging.rpc.direct.dev |
--host
Defaults to 127.0.0.1 so the proxy isn't exposed beyond your machine. Pass 0.0.0.0 if you need to reach it from another device on the network (e.g. a phone running a mobile dApp).
Local endpoint shape
The proxy accepts JSON-RPC POSTs at:
/<project>.<token>/<network>For compatibility, /v1/<project>.<token>/<network> is also accepted.
A GET / or GET /health returns:
{ "ok": true, "service": "@direct.dev/cli serve" }CORS is enabled for all origins (POST and OPTIONS), so browser dev tools can hit the proxy directly.
Response headers
Every proxied response includes two diagnostic headers:
| Header | Description |
| --- | --- |
| x-direct-cli-target | The upstream URL the request was forwarded to. |
| x-direct-cli-latency-ms | End-to-end proxy latency. |
TTY behavior
When stdout is a TTY the proxy renders the banner, color, spinner, and pinned status panel. When piped to a file or another process, all of those are stripped — output becomes plain text suitable for logs and CI. NO_COLOR=1 and TERM=dumb also disable color.
How it works
The CLI runs createFetch() from @direct.dev/sdk and exposes it as an HTTP server. Each incoming POST is forwarded through the SDK's pipeline — preload cache, block-state cache, in-memory cache, Direct Sync (WebSocket), Direct HTTP, then configured / public failover — and the resolved response is written back to the caller.
Because it's the same code that runs in browsers and Node integrations, the cache hit rates and sync behavior you see locally match what you'd get from @direct.dev/sdk in production.
License
Provided under the Direct.dev Terms and Conditions. Use of this package requires agreement to those terms.
For questions, reach out at [email protected].
