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

@nktkas/rews

v2.0.2

Published

Drop-in WebSocket replacement with automatic reconnection.

Readme

@nktkas/rews

npm JSR bundlejs

Drop-in WebSocket replacement with automatic reconnection.


Without rews — manual reconnection, listener re-attachment, message queuing:

let ws: WebSocket;
let attempts = 0;
const queue: string[] = [];
const onMessage = (e: MessageEvent) => console.log(e.data);

function connect() {
  ws = new WebSocket("wss://example.com");
  ws.addEventListener("message", onMessage);
  ws.onopen = () => {
    attempts = 0;
    while (queue.length) ws.send(queue.shift()!);
  };
  ws.onclose = () => {
    if (attempts++ < 3) setTimeout(connect, 1000);
  };
}

function send(data: string) {
  ws.readyState === WebSocket.OPEN ? ws.send(data) : queue.push(data);
}

connect();
send("hello");

With rews:

import { ReconnectingWebSocket } from "@nktkas/rews";

const ws = new ReconnectingWebSocket("wss://example.com");
ws.addEventListener("message", (e) => console.log(e.data));
ws.send("hello");

How It Works

sequenceDiagram
    participant App
    participant rews
    participant Server

    Server-->>rews: open  
    rews-->>App: open event

    App->>rews: send("hello")
    rews->>Server: "hello"
    Server-->>rews: "world"
    rews-->>App: message event

    Server--xrews: connection lost
    rews-->>App: close event
    Note over rews: ← standard WebSocket dies here,<br/>App must handle reconnection manually

    Note over rews: reconnecting...
    rews->>Server: reconnect

    App->>rews: send("hello")
    Note over rews: buffered

    Server-->>rews: open
    rews-->>App: open event
    rews->>Server: "hello" (from buffer)
    Server-->>rews: "world"
    rews-->>App: message event

    Note over App: App didn't notice the disruption — just a slight delay

Features

  • Drop-in replacement — standard WebSocket API, swap one line
  • Auto-reconnection — configurable retries with exponential backoff
  • Persistent listenersaddEventListener and on* handlers survive reconnections
  • Dynamic URL & protocols — factory functions for per-reconnect resolution
  • Zero dependencies — works in Node.js, Deno, Bun, and browsers

Install

npm i @nktkas/rews        # npm / pnpm / yarn
deno add jsr:@nktkas/rews # Deno
bun add @nktkas/rews      # Bun

Usage

import { ReconnectingWebSocket } from "@nktkas/rews";

const ws = new ReconnectingWebSocket("wss://example.com", {
  maxRetries: 5,
  reconnectionDelay: (attempt) => Math.min(2 ** attempt * 200, 30_000),
});

ws.addEventListener("message", (e) => console.log(e.data));
ws.addEventListener("terminate", (e) => console.error(e.detail.code));

ws.send("hello"); // buffered if not yet connected

Options

interface ReconnectingWebSocketOptions {
  /** Custom WebSocket constructor. @default globalThis.WebSocket */
  WebSocket?: typeof WebSocket;
  /** Maximum number of reconnection attempts. @default 3 */
  maxRetries?: number;
  /** Connection timeout in ms (null to disable). @default 10_000 */
  connectionTimeout?: number | null;
  /** Delay before reconnection in ms, or a function of attempt number. @default exponential backoff, max 10s */
  reconnectionDelay?: number | ((attempt: number) => number);
}

Beyond Standard WebSocket

Dynamic URL & Protocols

url and protocols accept functions, invoked on each reconnection:

const ws = new ReconnectingWebSocket(
  () => `wss://example.com?token=${getToken()}`,
  () => ["v2"],
);

Event Lifecycle

Standard open, close, error, and message events fire on every connection cycle — not just the first one. A single ReconnectingWebSocket instance may emit multiple open/close pairs over its lifetime as it reconnects.

ws.addEventListener("open", () => console.log("connected")); // fires on each (re)connection
ws.addEventListener("close", () => console.log("disconnected")); // fires on each disconnection

// use { once: true } if you only need the first occurrence
ws.addEventListener("open", () => init(), { once: true });

Terminate Event

Fires when the connection is permanently closed:

| Code | Description | | -------------------- | ------------------------------------------ | | RECONNECTION_LIMIT | Max retries exceeded | | TERMINATED_BY_USER | close() called | | UNKNOWN_ERROR | Unhandled error in user-provided functions |

ws.addEventListener("terminate", (e) => {
  e.detail.code; // ReconnectingWebSocketErrorCode
  e.detail.cause; // original error, if any
});

ws.isTerminated; // boolean
ws.terminationReason; // ReconnectingWebSocketError | undefined
ws.terminationSignal; // AbortSignal

Closing Behavior

ws.close(); // permanently close (default)
ws.close(code, reason, false); // close current socket only — reconnection continues

License

MIT