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

@nostrwatch/websocket

v0.0.1

Published

Cross-platform WebSocket client with a unified event-driven API for Node.js, browser, and Deno.

Readme

@nostrwatch/websocket

Cross-platform WebSocket client with a unified event-driven API for Node.js, browser, and Deno.

npm version License Status Runtime

Overview

@nostrwatch/websocket wraps platform-specific WebSocket implementations behind the UniversalWebSocket class, providing a consistent on/once/off event API and connection lifecycle management across Node.js, browser, and Deno environments. The class detects the runtime automatically and selects the appropriate underlying implementation (ws in Node.js, native WebSocket in browser/Deno). It is the WebSocket foundation used by the relay check adapters in @nostrwatch/nocap.

A relay in Nostr is a WebSocket server (identified by a wss:// URL) that stores and forwards signed protocol messages (events). UniversalWebSocket connects to these endpoints and handles connection state, message dispatch, and graceful teardown regardless of the JavaScript runtime.

Installation

pnpm add @nostrwatch/websocket

Or with npm:

npm install @nostrwatch/websocket

Quick Start

import {UniversalWebSocket} from '@nostrwatch/websocket'

const ws = new UniversalWebSocket('wss://relay.damus.io')
ws.on('open', () => console.log('connected'))
ws.on('message', (ev) => console.log('received:', ev.data))
await ws.connect()

ws.send(JSON.stringify(['REQ', 'sub1', {kinds: [1], limit: 1}]))
// received: ["EVENT","sub1",{"id":"...","kind":1,...}]

API

UniversalWebSocket

class UniversalWebSocket {
  constructor(relay: string, protocols?: string | string[], options?: UniversalWebSocketOptions)
  static create(relay: string, protocols?: string | string[], options?: UniversalWebSocketOptions): Promise<UniversalWebSocket>
}

Constructor

new UniversalWebSocket(relay: string, protocols?, options?)

Creates a new cross-platform WebSocket instance. By default (autoConnect: true), begins connecting immediately in the background. To control connection timing manually, set autoConnect: false and call connect() when ready.

| Parameter | Type | Description | |-----------|------|-------------| | relay | string | WebSocket URL of the relay (e.g. wss://relay.damus.io) | | protocols | string \| string[] | Optional WebSocket subprotocols | | options | UniversalWebSocketOptions | Optional configuration object |

UniversalWebSocketOptions

| Option | Type | Default | Description | |--------|------|---------|-------------| | autoConnect | boolean | true | Connect automatically on construction | | connectTimeout | number | 10000 | Timeout in milliseconds before connect() rejects | | agent | unknown | undefined | HTTP agent for Node.js proxy support | | wsOptions | Record<string, unknown> | undefined | Additional options forwarded to the underlying ws constructor in Node.js |


UniversalWebSocket.create()

static async create(relay: string, protocols?, options?): Promise<UniversalWebSocket>

Factory method that creates an instance with autoConnect: false, calls connect(), and resolves when the connection is open. Use this when you need to await a fully connected socket before proceeding.


Event methods

on(type, listener)

on<K extends WebSocketEventType>(type: K, listener: WebSocketListener<K>): void

Registers a persistent event listener. Fires on every occurrence of the event.

once(type, listener)

once<K extends WebSocketEventType>(type: K, listener: WebSocketListener<K>): void

Registers a one-shot event listener. Automatically removed after the first invocation.

off(type?, listener?)

off<K extends WebSocketEventType>(type?: K, listener?: WebSocketListener<K>): void

Removes event listeners. With no arguments, clears all listeners for all event types. With only type, clears all listeners for that type. With both arguments, removes the specific listener.

addEventListener(type, listener) / removeEventListener(type, listener)

DOM-compatible aliases for on and off. Useful when passing a UniversalWebSocket to code that expects a native WebSocket.


Lifecycle methods

connect()

async connect(): Promise<boolean>

Initiates the WebSocket connection. Resolves true when the connection opens, false if the connection fails or times out. Safe to call multiple times — concurrent calls share the same promise.

ready()

async ready(): Promise<void>

Awaits a successful connection. Throws if the connection fails. Use this when you want to ensure the socket is open before sending.

closed()

async closed(): Promise<void>

Resolves when the socket transitions to the CLOSED state.

close(code?, reason?)

close(code?: number, reason?: string): void

Initiates a graceful WebSocket close handshake with an optional close code and reason string.

terminate()

terminate(): void

Forcefully destroys the connection without completing the close handshake. In browser environments where terminate() is not available on native WebSocket, falls back to close().


Communication

send(data)

send(data: unknown): void

Sends data over the open WebSocket. Accepts strings, Blob, ArrayBuffer, ArrayBufferView, plain objects (JSON-serialized automatically), or arrays (JSON-serialized automatically). Throws if the socket is not connected.


Properties

| Property | Type | Description | |----------|------|-------------| | readyState | number | Current connection state: 0 CONNECTING, 1 OPEN, 2 CLOSING, 3 CLOSED | | url | string | The relay URL this socket was constructed with | | CONNECTED | boolean | Alias for readyState === 1 | | CONNECTING | boolean | Alias for readyState === 0 | | CLOSING | boolean | Alias for readyState === 2 | | CLOSED | boolean | Alias for readyState === 3 | | BUSY | boolean | True while CONNECTING or CLOSING | | OPEN | boolean | Alias for CONNECTED |

Convenience state-check methods: isConnecting(), isConnected(), isOpen(), isClosing(), isClosed().


Events

| Event | Payload type | Description | |-------|-------------|-------------| | open | Event | Connection established | | message | MessageEvent<string \| Buffer \| ArrayBuffer \| Blob> | Message received from the relay | | close | CloseEvent | Connection closed; inspect ev.code and ev.reason | | error | Event | Connection error occurred |


Types

type WebSocketEventType = 'open' | 'close' | 'error' | 'message'
type Sendable = string | ArrayBufferLike | Blob | ArrayBufferView
type WebSocketData = Sendable | Buffer

interface UniversalWebSocketOptions {
  agent?: unknown
  connectTimeout?: number
  autoConnect?: boolean
  wsOptions?: Record<string, unknown>
}

Known Limitations

No known limitations at this time.

Agent Skills

No agent skills defined yet for this package.

Related Packages

  • @nostrwatch/nocap — relay capability checker; uses @nostrwatch/websocket as its underlying WebSocket transport via the websocket adapter
  • @nostrwatch/route66 — relay aggregation layer; websocket adapter wraps UniversalWebSocket for connection pooling
  • @nostrwatch/memory-relay — in-memory relay for testing; pairs with UniversalWebSocket in integration test scenarios

License

MIT