Skip to content
ibnlanrePublic

Repository files navigation

@ibnlanre/socket

minified size license version downloads

@ibnlanre/socket is a fast, lightweight, type-safe JSON WebSocket client for React — cache-first, pool-aware, and schema-safe. It also ships an EventSourceClient for Server-Sent Events.

Define one client per endpoint, let identical params reuse a single pooled connection across components, and plug in any Standard Schema–compatible validator (Zod, Valibot, ArkType, …) for runtime validation.

📚 Documentation

The full documentation lives at the docs site:

→ https://use-socket.vercel.app

Guides Reference
Introduction · Getting started · Mental model SocketClient · Socket · SocketCache
Validation · Caching · Reconnection · Server-Sent Events EventSourceClient · Options · Types & constants

The docs are a VitePress site in docs/; run them locally with:

pnpm --filter @ibnlanre/socket-docs dev

Features

  • Cache-first state — previously received data surfaces instantly from the Cache API while fresh messages stream in (stale-while-reconnect, no empty flashes).
  • One connection per endpoint — identical params reuse the same pooled Socket, so many components share a single live connection.
  • Runtime-safe messaging — validate params, outgoing payloads, and incoming messages with any Standard Schema validator; asynchronous schemas are supported through the matching async APIs.
  • Predictable lifecycle — distinct status/fetchStatus dimensions, derived flags, and explicit ownership (close vs dispose vs evict).
  • Built-in reconnection — backoff, jitter, custom retry conditions, and recovery on network restore, window focus, and bfcache page restore.
  • Server-Sent Events — native EventSource (GET) and fetch streaming (any method), named events, async iteration.

Installation

# npm
npm install @ibnlanre/socket

# pnpm
pnpm add @ibnlanre/socket

# yarn
yarn add @ibnlanre/socket

Validation is optional — bring your own Standard Schema validator when you want it:

pnpm add @ibnlanre/socket zod    # or valibot, arktype, …

Quick start

The smallest useful setup: create one client, call useSocket, render the selected data.

import { SocketClient } from "@ibnlanre/socket";

const priceClient = new SocketClient<string>({
  baseURL: "wss://example.com",
  url: "/prices",
});

export function PriceTicker() {
  const price = priceClient.useSocket({
    select: (message) => message ?? "Waiting for price…",
  });

  return <div>{price.data}</div>;
}

Need the imperative socket instead?

const socket = await priceClient.get({ symbol: "BTC" });

socket.open();
await socket.waitUntil("open");
await socket.send({ type: "subscribe", symbol: "BTC" });

Key concepts

  • One SocketClient = one endpoint. Schemas, cache, and reconnection live on the client.
  • Same params ⇒ same socket. Connections are pooled by a fully resolved URL; parameters are validated/normalized once and that exact value drives both the pool key and the connection URL.
  • Hook for React, instance for imperative code. useSocket returns a read-only state, selected data, and send; await client.get() returns the managed Socket.
  • Ownership is explicit. socket.close() disconnects but preserves subscriptions (a later open() reconnects); socket.dispose() / await client.evict(params) release the socket permanently.
  • Sends go through an ordered queue. await send() supports sync and async schemas; waiting payloads are bounded by maxQueueSize/queueMaxAge/queueOverflow.
  • Async validation, cancellable. await client.get(input, { signal }) resolves parameters before returning the pooled socket; useSocket owns that same resolution in React and exposes isPreparing and error. Schema input and output types may differ.

See Mental model for the full picture.

Public API at a glance

Export Kind Purpose
SocketClient class Pool + React hooks for one endpoint (useSocket, get, evict, clear, dispose)
Socket class One managed connection — state snapshot + commands (open, close, send, on, waitUntil, dispose)
SocketCache class In-memory mirror + Cache API persistence per origin
EventSourceClient class One-way Server-Sent Events client (native GET + fetch streaming)
SocketCloseCode / SocketCloseReason const WebSocket close-code enums and reasons
Types type SocketState, SocketCommands, UseSocketResult, SocketDiagnostic, SocketQueueOptions, …

Development

Monorepo: app (the library + tests), docs (VitePress site), tests (browser e2e).

pnpm install                # install the workspace

# unit tests + typecheck (app)
pnpm --dir app test

# browser e2e (Playwright; keep port 4173 free — it reuses an existing server)
pnpm test:e2e

# docs
pnpm --filter @ibnlanre/socket-docs dev     # local docs site
pnpm --filter @ibnlanre/socket-docs build   # build docs

License

@ibnlanre/socket is licensed under the BSD-3 License. See the LICENSE file for details.

socket.close() disconnects while preserving subscriptions. socket.dispose() is permanent; client.evict(params) disposes and removes a pooled instance. Queues and pools are bounded. onDiagnostic exposes retry, queue, validation, and cache activity; prepareConnection supports fresh credentials before every transport attempt.

See migration notes for changed encoding, queue, and ownership behavior.

Releases

Packages

Used by

Contributors

Languages