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

twd-relay

v1.2.3

Published

WebSocket relay for TWD — enables AI agents and external tools to run and observe in-browser tests

Readme

twd-relay

WebSocket relay for TWD — lets AI agents and external tools trigger and observe in-browser test runs.

Your app runs tests in the browser with twd-js. twd-relay adds a relay server and a browser client so a client (script, CI, or AI agent) can send a run command over WebSocket; the relay forwards it to the browser, and test events stream back.


Quick start (Vite)

The Vite plugin attaches the relay to the dev server and auto-injects the browser client into your index.html — one line in vite.config.ts and you're done.

1. Install:

npm install --save-dev twd-relay

Peer dependency: twd-js (>=1.4.0). Your app must use twd-js for tests; the browser client imports twd-js/runner at runtime.

2. Add the plugin:

// vite.config.ts
import { twdRemote } from 'twd-relay/vite';

export default defineConfig({
  plugins: [react(), twdRemote()],
});

That's the whole setup. The plugin only runs in dev (apply: 'serve'); production builds are untouched.

3. Run your app, then trigger a test run:

npm run dev                 # in one terminal
npx twd-relay run           # in another — connects, runs, exits 0/1

twd-relay run defaults to port 5173 (Vite). See CLI run command for filters and flags.

Visual feedback in the browser tab

When connected, the browser client sets a colored favicon and prefixes document.title so you can spot the active TWD tab among many:

| Favicon | Title prefix | State | |---|---|---| | Blue | [TWD] | Connected, idle | | Orange | [TWD ...] | Tests running | | Green | [TWD ✓] | Last run passed | | Red | [TWD ✗] | Last run had failures |

On disconnect or eviction (another tab taking over), the original favicon and title are restored.


Plugin options

twdRemote({
  path: '/__twd/ws',           // WebSocket path (relative to Vite `base`)
  autoConnect: true,            // inject the browser client into index.html
});

twdRemote({ autoConnect: false }); // opt out — wire createBrowserClient manually

twdRemote({                         // forward client options into the injected call
  autoConnect: { reconnect: false, log: true, maxTestDurationMs: 5000 },
});

| Option | Type | Default | Description | |---|---|---|---| | path | string | '/__twd/ws' (relative to Vite base) | WebSocket path. Used by the relay and the injected client — single source of truth. | | autoConnect | boolean \| AutoConnectOptions | true | Inject the browser client connect script into index.html. false opts out. Object form forwards reconnect, reconnectInterval, log, maxTestDurationMs into the injected createBrowserClient call. |


Operational reliability

These features are on by default — no configuration needed.

Aborting throttled runs

Chrome aggressively throttles timers in backgrounded tabs, which can stretch a 1-second test run to 30+ seconds. To avoid AI/CI hangs, the browser client monitors per-test wall-clock time. If any single test runs longer than 10 seconds, the browser emits run:aborted, the CLI prints a clear error, and the run exits with code 1.

Override the threshold with --max-test-duration <ms> on twd-relay run, or pass maxTestDurationMs to twdRemote({ autoConnect: { ... } }). Set it to 0 to disable detection:

twd-relay run --max-test-duration 20000   # raise to 20s for heavy multistep tests
twd-relay run --max-test-duration 0       # disable detection

The default of 10 s sits above the Testing Library default findBy* timeout (3 s). A legitimately failing test still completes under the threshold; throttled runs cluster in the 10–30 s range and trip the abort reliably.

Recovery: foreground the TWD tab (identified by the [TWD …] title prefix) and retry. For unattended runs, prefer twd-cli — it drives a headless browser where the tab is always focused.

Frozen-tab recovery (heartbeat)

During a run, the browser sends a heartbeat every 3 seconds. The relay tracks the last heartbeat and checks every 10 seconds. If no heartbeat arrives for 120 seconds during an active run, the relay considers the run dead (browser tab frozen by the OS), resets the run lock, and broadcasts:

{ "type": "run:abandoned", "reason": "heartbeat_timeout" }

The CLI prints Run abandoned — browser tab appears frozen. Refresh the browser tab and retry. and exits 1. AI agents get an actionable signal instead of a 180 s timeout followed by a cryptic RUN_IN_PROGRESS error.

Failures recap

When tests fail, the CLI prints a recap block at the very end of the output listing each failed test and its error. This survives tail -N truncation and is easy to copy as a single block.


Manual setup (non-Vite, or opting out)

Use this path for Webpack, Angular CLI, Rollup, esbuild, Rspack — anywhere the Vite plugin doesn't apply — or when you want full control over the browser client lifecycle in a Vite project (set autoConnect: false on the plugin).

1. Run a relay — either standalone, or attached to a dev server you control:

npx twd-relay
# Listens on ws://localhost:9876/__twd/ws (use --port to change)

2. Connect the browser client in your app entry file:

import { createBrowserClient } from 'twd-relay/browser';

const client = createBrowserClient({
  url: 'ws://localhost:9876/__twd/ws',
});
client.connect();

createBrowserClient accepts url, path, reconnect, reconnectInterval, log, and maxTestDurationMs. See src/browser/types.ts for the full interface.

3. Open the app in a browser, then trigger a run:

npx twd-relay run --port 9876

⚠️ Don't enable both auto-connect and a manual createBrowserClient call. Two clients will connect — visible in relay logs as a duplicate browser. Either remove the manual block, or set autoConnect: false on twdRemote().

One-liner to trigger a run from a script

When you don't want the CLI but already have ws available:

node -e 'const Ws=require("ws");const w=new Ws("ws://localhost:9876/__twd/ws");let s=false;w.on("open",()=>w.send(JSON.stringify({type:"hello",role:"client"})));w.on("message",d=>{const m=JSON.parse(d);console.log(m.type,m);if(m.type==="connected"&&m.browser&&!s){s=true;w.send(JSON.stringify({type:"run",scope:"all"}));}if(m.type==="run:complete"){w.close();}});w.on("close",()=>process.exit(0));'

CLI run command

Connect to a running relay, trigger tests, stream output, exit 0 (all pass) or 1 (failures).

# Run all tests (defaults to port 5173 — Vite dev server)
twd-relay run

# Different port (e.g. standalone relay)
twd-relay run --port 9876

# Filter tests by name (substring match, case-insensitive, repeatable)
twd-relay run --test "should show error"
twd-relay run --test "login" --test "signup"

| Flag | Description | Default | |---|---|---| | --port <port> | Relay port | 5173 | | --host <host> | Relay host | localhost | | --path <path> | WebSocket path | /__twd/ws | | --timeout <ms> | Run timeout | 180000 | | --max-test-duration <ms> | Per-test wall-clock abort threshold | 10000 | | --test <name> | Filter tests by name substring (repeatable) | — |

When --test is used and no tests match, the CLI prints the available test names so you can correct the filter.


Architecture

  • Relay server (twd-relay) — WebSocket server that accepts one browser connection and many client connections. Clients send commands (run, status); the relay forwards them. The browser runs tests and streams events back; the relay broadcasts to all clients. A lock prevents concurrent runs.
  • Browser client (twd-relay/browser) — Runs in your app. Connects to the relay, listens for commands, uses twd-js/runner to execute tests, and streams results back. Logs connection state to the console.
  • Vite plugin (twd-relay/vite) — Attaches the relay to your Vite dev server and auto-injects the browser client. The recommended path for Vite projects.
  • Standalone CLI (twd-relay bin) — Runs the relay on its own HTTP server (default port 9876) for projects that aren't on Vite.

Protocol summary

  1. Browser connects → sends { type: 'hello', role: 'browser' }
  2. Client connects → sends { type: 'hello', role: 'client' }
  3. Client sends { type: 'run', scope: 'all' } (optionally testNames: string[]) → relay forwards to browser
  4. Browser runs tests and streams events → relay broadcasts to clients
  5. Browser sends { type: 'heartbeat' } every 3 s during a run (consumed by the relay, not forwarded)
  6. run:complete clears the run lock

Exports

| Export | Use | |---|---| | twd-relay (main) | Relay server: createTwdRelay(httpServer, options) | | twd-relay/browser | Browser client: createBrowserClient(options) | | twd-relay/vite | Vite plugin: twdRemote(options) |

CLI: twd-relay (or npx twd-relay):

  • twd-relay serve (default) — start the standalone relay
  • twd-relay run — connect to a relay and trigger a test run

Scripts (this repo)

| Script | Description | |---|---| | npm run build | Build relay, browser, vite entry points + CLI | | npm run relay | Build and start the standalone relay (port 9876) | | npm run send-run | Connect as client and send run; exits on run:complete | | npm run dev | Start relay only (assumes already built) | | npm run test | Run tests (watch) | | npm run test:ci | Run tests with coverage |


License

MIT · BRIKEV