A high-performance Wisp network client. Native Rust + WebAssembly.
Nova is a Rust implementation of the Wisp v2.1 protocol with full HTTP/1.1, HTTP/2, WebSocket, TLS, proxy chain, and compression support. It ships as native Rust crates for server/CLI use and a WebAssembly package (@nightnetwork/nova) for browsers.
- Wisp v2.1 protocol — multiplexed TCP streams over a single WebSocket
- HTTP/1.1 + HTTP/2 — HTTP/2 via patched
h2-wasmfor WASM targets - TLS — rustls-based, works on both native and WASM (via
futures-rustls) - WebSocket upgrade — client-initiated WS connections over wisp streams
- Proxy chains — SOCKS4/4a/5 and HTTP CONNECT proxies of arbitrary depth
- Compression — transparent gzip/brotli response decompression
- MoonBeam relay integration — route wisp traffic through a
@nightnetwork/moonbeamrelay viaMessagePorttransport - MessagePort transport — use any
MessagePort-based channel as the underlying wisp transport - libcurl-compatible JS API — drop-in
LibCurlclass for DuskJS and similar consumers - NovaClient — high-level reqwest-shaped Rust client with builder pattern
novaCLI — curl-shaped command-line tool (~40 flags)
| Crate | Purpose |
|---|---|
nova-core |
Low-level engine: wisp mux, transports, TLS, HTTP/1.1+2, WebSocket, proxy chains, compression |
nova |
High-level client: NovaClient, RequestBuilder, Response (reqwest-shaped) |
nova-cli |
The nova binary with curl-shaped flags |
nova-wasm |
wasm-bindgen glue exposing LibCurl, Nova, NovaClient, and NovaHTTPSession to JS |
nova-test-support |
Test utilities: mock wisp server, paired transports |
npm install @nightnetwork/nova[dependencies]
nova = { git = "https://github.com/nightnetwork/nova" }
nova-core = { git = "https://github.com/nightnetwork/nova" }import { MoonbeamRelay } from '@nightnetwork/moonbeam';
import init, { LibCurl } from '@nightnetwork/nova';
await init();
const lc = new LibCurl();
// Option A: Direct wisp WebSocket
lc.set_websocket('wss://wisp.example.com/');
// Option B: MoonBeam relay (preferred in production)
const relay = await MoonbeamRelay.create({ wispUrl: 'wss://wisp.example.com/' });
lc.set_moonbeam_relay(relay);
// Fetch
const resp = await lc.fetch('https://example.com/', { method: 'GET' });
console.log(resp.status, await resp.text());import init, { NovaClient, NovaClientOptions, attachMoonbeam } from '@nightnetwork/nova';
import { MoonbeamRelay } from '@nightnetwork/moonbeam';
await init();
const relay = await MoonbeamRelay.create({ wispUrl: 'wss://wisp.example.com/' });
const port = attachMoonbeam(relay);
const opts = new NovaClientOptions(port);
const client = new NovaClient(opts);
const resp = await client.fetch('https://example.com/');
console.log(resp.status);use std::sync::Arc;
use nova::NovaClient;
use nova_core::transport::WebSocketTransport;
use nova_core::wisp::Mux;
# async fn example() -> Result<(), Box<dyn std::error::Error>> {
let transport = WebSocketTransport::connect("wss://wisp.example.com/").await?;
let mux = Arc::new(Mux::new(transport));
mux.run_handshake(&[]).await?;
let client = NovaClient::builder().mux(mux).build()?;
let resp = client
.get("https://example.com/")
.header("x-foo", "bar")
.send()
.await?;
println!("{}: {}", resp.status(), resp.text()?);
# Ok(()) }The LibCurl class provides a libcurl.js-compatible interface for browser use.
Construct a new instance.
No-op in Nova. Kept for API compatibility with libcurl.js. Nova's WASM is loaded via init().
Set the wisp server WebSocket URL. All subsequent requests route through this endpoint.
Route wisp traffic through a MoonBeam relay instead of a direct WebSocket. relay must be a JS object with an .attach() method returning a MessagePort (matches @nightnetwork/moonbeam v0.2+ MoonbeamRelay). Calling this clears any previously set WebSocket URL.
Perform an HTTP fetch. Returns a standard Response. Options:
method— HTTP method string (default"GET")headers— plain object of{ name: value }pairsbody— string orUint8Array
Returns the NovaHTTPSession constructor for session-based fetching. Sessions reuse connection state across fetches.
const Session = lc.HTTPSession;
const session = new Session();
const resp = await session.fetch('https://example.com/');
session.close();Returns "wisp" — the transport protocol name.
Returns the Nova libcurl shim version string.
Currently returns undefined. Full WebSocket-over-wisp support is a follow-up.
Currently returns undefined. Raw TLS socket support is a follow-up.
NovaClient provides a high-level, reqwest-shaped interface.
let client = NovaClient::builder()
.mux(mux) // required: wisp Mux
.user_agent("myapp/1.0") // optional
.default_header("x-api-key", key) // optional, repeatable
.tls_options(tls_opts) // optional
.http_options(http_opts) // optional
.tcp_options(tcp_opts) // optional
.timeout_options(timeout_opts) // optional
.cookie_options(cookie_opts) // optional
.dns_options(dns_opts) // optional
.build()?;client.get(url)— start a GET requestclient.post(url)— start a POST requestclient.put(url)— start a PUT requestclient.delete(url)— start a DELETE requestclient.head(url)— start a HEAD requestclient.request(method, url)— start a request with a custom method
All return a RequestBuilder. Chain .header(name, value), .body(bytes), then .send().await.
For libcurl-parity control, use nova_core::NovaHandle directly:
let mut handle = NovaHandle::new();
handle.set_url("https://example.com/")?;
handle.set_method(Method::Post);
handle.add_header("content-type", "application/json");
handle.set_body(Body::Text("{\"key\":\"value\"}".into()));
handle.set_mux(mux);
let response = handle.perform().await?;
println!("Status: {}", response.status);Table-driven options via set_option(Opt, OptValue):
| Option | Value type | Description |
|---|---|---|
TlsVerifyPeer |
Bool |
Verify TLS peer certificate |
TlsVerifyHost |
Bool |
Verify TLS hostname |
TlsMinVersion |
TlsVersion |
Minimum TLS version |
TlsMaxVersion |
TlsVersion |
Maximum TLS version |
HttpFollowRedirects |
Bool |
Follow HTTP redirects |
HttpMaxRedirects |
U32 |
Maximum redirect hops |
TcpNodelay |
Bool |
TCP_NODELAY |
TcpKeepalive |
Bool |
TCP keepalive |
TimeoutTotal |
Duration / None |
Total request timeout |
TimeoutConnect |
Duration |
Connection timeout |
CookiesEnabled |
Bool |
Enable cookie jar |
UserAgent |
String |
User-Agent header |
Verbose |
Bool |
Debug logging |
MaxResponseSize |
U64 / None |
Max response body bytes |
nova https://example.com/
nova -X POST -H 'content-type: application/json' -d '{"hi":true}' https://example.com/
nova --wisp wss://wisp.example.com/ --proxy socks5://bastion:1080 https://example.com/
nova --help~40 curl-shaped flags supported. Not a full curl clone by design.
cargo build --workspacecargo build -p nova-core --target wasm32-unknown-unknown
cargo build -p nova-wasm --target wasm32-unknown-unknown
# JS-consumable package via wasm-pack:
wasm-pack build --target web nova-wasmcargo test --workspacecargo test -p nova-core --test integration_wisp_real --features integrationSet NOVA_TEST_WISP_URL to override the default endpoint.
Requires headless Chrome and MoonBeam v0.2:
wasm-pack test --headless --chrome nova-wasm┌─────────────────────────────────────────────────┐
│ Consumers │
│ nova-cli (curl-shaped) │ nova (NovaClient) │
├─────────────────────────┬───────────────────────┤
│ nova-core │
│ ┌─────────┐ ┌──────┐ ┌─────┐ ┌───────────┐ │
│ │NovaHandle│ │ HTTP │ │ TLS │ │ Proxy │ │
│ │(libcurl) │ │1.1+2 │ │rustls│ │SOCKS/HTTP│ │
│ └────┬─────┘ └──┬───┘ └──┬──┘ └─────┬────┘ │
│ └──────┬────┘─────────┘───────────┘ │
│ ┌────▼─────┐ │
│ │ Wisp Mux │ (v2.1 multiplexer) │
│ └────┬─────┘ │
│ ┌─────────┼──────────┐ │
│ ▼ ▼ ▼ │
│ WebSocket MessagePort (pluggable transport) │
│ Transport Transport │
└─────────────────────────────────────────────────┘
│ │
Direct WS MoonBeam Relay
nova-core owns the protocol stack: wisp mux, stream lifecycle, transports, TLS (rustls on native, futures-rustls on WASM), HTTP/1.1 codec, HTTP/2 (h2-wasm), WebSocket upgrade, SOCKS/HTTP CONNECT proxy chains, and gzip/brotli decompression.
nova wraps nova-core in a reqwest-shaped builder API (NovaClient → RequestBuilder → Response).
nova-wasm provides wasm-bindgen bindings exposing LibCurl (DuskJS-compatible), Nova (low-level handle), NovaClient (high-level), and NovaHTTPSession (session-based fetching) to JavaScript.
nova-cli is a curl-shaped binary built on nova.
- HTTP/3 / QUIC
- SMTP / FTP / LDAP / RTSP / other non-web protocols
- Full curl CLI compatibility (curl-shaped only)
- FIPS mode / aws-lc-rs crypto (WASM-incompatible)
- Pre-transport proxy (proxying between Nova and the wisp WebSocket itself)
- Dynamic-library plugin loading for custom protocols
Contributions are welcome. Please open an issue or pull request on GitHub.
Apache-2.0. See LICENSE.