A lightweight WebSocket relay that bridges the @jaw.id/cli package with keys.jaw.id.
Browsers like Brave and Safari block mixed-content WebSocket connections (ws://) from HTTPS pages, and neither supports the Private Network Access (PNA) preflight required to reach a local WebSocket server. This makes direct ws:// use from the browser not feasible.
jaw-relay solves this by acting as a secure wss:// intermediary — the CLI connects outward to the relay, and so does the browser, so no inbound connection to localhost is ever needed. The relay operates as a blind pipe: all messages are end-to-end encrypted, so the relay has no visibility into what it's passing.
@jaw.id/cli ──wss──► jaw-relay.jaw.id ◄──wss── keys.jaw.id
The hosted instance is available at wss://relay.jaw.id — no setup needed if you're using @jaw.id/cli.
- The CLI opens a WebSocket to the relay with a session ID and the
clirole - The browser opens a second connection to the same session with the
browserrole - The relay forwards messages transparently between them
- Sessions expire after 15 minutes of inactivity and support reconnection
docker build -t jaw-relay .
docker run -p 8080:8080 jaw-relaynpm install
npm run build
PORT=8080 node dist/index.js| Variable | Default | Description |
|---|---|---|
PORT |
8080 |
Port the server listens on |
WebSocket URL format:
wss://your-host?session=<sessionId>&role=<cli|browser>
Both the CLI and browser must use the same sessionId. The CLI always connects first.