npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

relay-tty

v1.14.0

Published

Terminal relay — run commands locally, access them from anywhere via browser

Readme

relay-tty

Run terminal commands on your computer, access them from any browser — phone, tablet, whatever. Share your terminal with anyone via a link, or expose it publicly with zero config.

You don't need to know SSH. You don't need tmux. If you're getting into AI and someone told you to "run this in a terminal," relay-tty lets you do that and check on it from your phone. Sessions survive disconnects, and multiple people can watch the same session at once.

Install

curl -fsSL https://raw.githubusercontent.com/ddrscott/relay-tty/main/install.sh | bash

Or if you already have Node.js:

npm i -g relay-tty

Quick Start

relay bash                   # creates a session and attaches locally
                              # Ctrl+] to detach (session keeps running)

Start the web server

relay server start           # http://localhost:7680
relay server start --tunnel  # expose via relaytty.com (zero config)
relay server install         # install as system service (launchd/systemd)

Share a Session

Generate a read-only link so anyone can watch your terminal live — no login, no setup on their end.

relay share <session-id>
# https://abc123.relaytty.com/s/eyJ...
# Read-only link (expires in 60m)

The URL goes to stdout, metadata to stderr (POSIX convention). Default TTL is 1 hour; max is 24 hours (--ttl 86400). Viewers see a live terminal stream but can't type.

Public Access with --tunnel

--tunnel exposes your server publicly via <slug>.relaytty.com — no accounts, no DNS, no config files. On first run it provisions a stable subdomain and prints a QR code for quick mobile access.

relay server start --tunnel
# Tunnel active: https://abc123.relaytty.com
# [QR code]

Config is saved at ~/.config/relay-tty/tunnel.json and reused on subsequent runs (same subdomain every time). Combine with relay share to let anyone watch a session without giving them full access.

CLI

relay <command>              # run command, attach locally
relay --detach <command>     # run command, print URL, return to prompt
relay attach <id>            # reattach to existing session
relay list                   # list all sessions
relay stop <id>              # kill a session
relay share <id>             # generate read-only share link (1h default)
relay share <id> --ttl 86400 # share link with 24h TTL
relay server start           # start server in foreground
relay server start --tunnel  # start with public tunnel via relaytty.com
relay server install         # install as system service (launchd/systemd)
relay server uninstall       # remove system service

The CLI prints session URLs to stdout and status info to stderr (POSIX convention). Ctrl+] detaches without killing the session.

Architecture

Phone Browser                Mac/Linux Host
┌────────────────┐            ┌──────────────────────────────────┐
│  Session List  │───loader──▶│ Express + React Router SSR       │
│  (DaisyUI)     │            │   └─ SessionStore (in-memory)    │
├────────────────┤            ├──────────────────────────────────┤
│    xterm.js    │◀────WS────▶│ ws-handler ◀──Unix socket──▶     │
│    Terminal    │            │   (per-client connection)        │
└────────────────┘            └──────────┬───────────────────────┘
                                         │
CLI: relay htop ────POST /api/sessions──▶│
     │                                   │
     └──── attaches locally via WS ──────┘

                            ┌──────────────────────────────────┐
                            │ pty-host (detached process)      │
                            │   ├─ Rust binary (or Node.js)    │
                            │   ├─ OutputBuffer (10MB ring)    │
                            │   └─ Unix socket server          │
                            │       ~/.relay-tty/sockets/<id>  │
                            └──────────────────────────────────┘
                            Survives server restarts. Each session
                            runs in its own pty-host process.

WebSocket Protocol

Binary frames over WS and length-prefixed frames over Unix sockets. See docs/protocol.md for the full message type reference, connection flow, and delta resume protocol.

Key Design Decisions

  • Process separation — each session runs in a detached pty-host process that owns the PTY. The Rust implementation (crates/pty-host/) is preferred when available (~700KB, ~2MB RSS), with automatic fallback to Node.js. The server can crash, restart, or be upgraded without killing sessions. Session metadata is persisted to ~/.relay-tty/sessions/ and sockets live at ~/.relay-tty/sockets/. On restart, the server discovers and reconnects to surviving sessions.
  • CLI attaches by defaultrelay bash creates a session and enters raw TTY mode. --detach for fire-and-forget.
  • 10MB output ring buffer — new clients replay recent output on connect (buffer lives in pty-host). This is a session replay buffer for reconnecting viewers, not a logging system. relay-tty is built for interactive sessions, not permanent workloads — use proper log infrastructure if you need durable output retention.
  • Per-client socket connections — each WS client gets its own Unix socket to the pty-host, so each gets independent buffer replay.
  • Multi-client — CLI and browser can view/interact with the same session simultaneously.
  • Localhost auth bypass — CLI on the same machine skips authentication.
  • 8-char hex session IDs — short enough for CLI ergonomics.

Environment Variables

Configure via .env in the project root:

| Variable | Required | Description | |----------|----------|-------------| | JWT_SECRET | Yes (for remote) | Secret for signing auth JWTs. Generate with openssl rand -base64 32 | | PORT | No | Server port (default: 7680) | | APP_URL | No | Public URL for remote access (e.g., https://relay.example.com). Shown on startup and used for Discord notifications | | DISCORD_WEBHOOK | No | Discord webhook URL. When set, posts a clickable auth link on startup for quick mobile access |

Example .env:

JWT_SECRET='your-secret-here'
PORT=18701
APP_URL='https://relay.example.com'
DISCORD_WEBHOOK='https://discord.com/api/webhooks/...'

Auth

Set JWT_SECRET to enable bearer token auth for remote access (e.g., via Cloudflare Tunnel). Localhost connections always skip auth.

On startup, the server prints both local and public URLs:

relay-tty listening on http://localhost:18701
Public URL: https://relay.example.com
Auth token URL: http://localhost:18701/api/auth/callback?token=eyJ...

Visit the auth token URL in a browser to set the session cookie (30-day expiry). The token does not expire — rotate JWT_SECRET to revoke all tokens.

Discord Notifications

When both APP_URL and DISCORD_WEBHOOK are set, the server posts a clickable auth link to Discord on startup. Tap it on your phone to authenticate instantly — the callback sets a cookie and redirects to a clean URL. Useful for accessing relay-tty from mobile without copy/pasting tokens.

Tunnel Details

The tunnel opens an outbound WebSocket to relaytty.com, which reverse-proxies HTTP and WebSocket traffic back to localhost. It uses an ephemeral local port by default to avoid clashing with a normal relay server start instance. Use --port to override.

Service Management

relay server install     # macOS: ~/Library/LaunchAgents/com.relay-tty.plist
                         # Linux: ~/.config/systemd/user/relay-tty.service

relay server uninstall   # remove and stop the service

Development

npm run dev          # dev server with Vite HMR (auto-builds Rust if toolchain present)
npm run build        # production build (React Router + CLI + Rust pty-host)
npm start            # production server

Tunnel Test Environment

A fully isolated test environment is available for testing changes before deploying to production. See docs/testing.md for setup instructions.

Rust pty-host (optional but recommended)

The PTY session host is written in Rust for reliability. Without a Rust toolchain, relay-tty falls back to the Node.js implementation automatically.

# Install Rust (if needed)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Build the pty-host binary
cargo build --release --manifest-path crates/pty-host/Cargo.toml

# Run tests (53 unit + 19 integration)
cargo test --manifest-path crates/pty-host/Cargo.toml

The Rust binary provides 1/5/15-minute throughput metrics (like top load averages), lower memory usage (~2MB vs ~40MB per session), and eliminates the node-pty native addon as a crash risk.

Binary Distribution

When installed via npm, a postinstall script automatically downloads the pre-built Rust binary for your platform from GitHub releases. Supported platforms:

| Platform | Architecture | |----------|-------------| | macOS | ARM64 (M1/M2/M3), x86_64 (Intel) | | Linux | x86_64, ARM64 |

Windows: Not natively supported. Use WSL (Windows Subsystem for Linux) and install relay-tty inside your WSL distribution.

If the download fails (offline, unsupported platform), it falls back to the Node.js pty-host. Set RELAY_SKIP_BINARY_DOWNLOAD=1 to skip the download entirely.

Binaries are built via GitHub Actions on each tagged release (v*). The workflow cross-compiles for all four targets and attaches stripped binaries to the GitHub release.

Tech Stack

  • Frontend: React Router v7 (SSR) + Tailwind v4 + DaisyUI v5 + xterm.js
  • Backend: Express 5 + node-pty + ws
  • PTY Host: Rust (tokio + forkpty) with Node.js fallback
  • CLI: Commander
  • Service: launchd (macOS) / systemd (Linux)
  • Mobile: PWA (standalone, no browser chrome) + Web Speech API for voice input