> ## Documentation Index
> Fetch the complete documentation index at: https://bytekit.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# WebSocketHelper

> Managed WebSocket connections with automatic reconnection, exponential backoff, schema validation, and pong detection.

## Import

```ts theme={null}
import { WebSocketHelper } from "bytekit";
```

## What it does

`WebSocketHelper` wraps the native `WebSocket` API with automatic reconnection, configurable backoff strategies, per-type schema validation, ping/pong heartbeat monitoring, and a typed event system. It handles the full lifecycle — connect, send, validate, reconnect, and graceful disconnect — so you can focus on message handling.

## Constructor

```ts theme={null}
const ws = new WebSocketHelper(url, options?: WebSocketOptions);
```

| Parameter | Type               | Description                                             |
| --------- | ------------------ | ------------------------------------------------------- |
| `url`     | `string`           | WebSocket server URL (e.g. `wss://api.example.com/ws`). |
| `options` | `WebSocketOptions` | Optional configuration.                                 |

### `WebSocketOptions`

| Property               | Type                            | Default    | Description                                                                                           |
| ---------------------- | ------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------- |
| `reconnect`            | `boolean`                       | `true`     | Enable automatic reconnection on close/error.                                                         |
| `maxReconnectAttempts` | `number`                        | `5`        | Maximum reconnection attempts before giving up.                                                       |
| `reconnectDelayMs`     | `number`                        | `3000`     | Base delay for reconnect attempts (ms). Used as the unit for backoff calculations.                    |
| `heartbeatIntervalMs`  | `number`                        | `30000`    | Interval between automatic ping messages (ms).                                                        |
| `messageTimeout`       | `number`                        | `5000`     | Timeout for `request()` calls (ms).                                                                   |
| `backoffStrategy`      | `BackoffStrategy`               | `"linear"` | Delay strategy: `"linear"`, `"exponential"`, or a custom `(attempt) => number` function.              |
| `maxReconnectDelayMs`  | `number`                        | `30000`    | Upper bound for computed reconnect delay (ms). Only applies to `"exponential"`.                       |
| `jitter`               | `boolean`                       | `false`    | Add Full Jitter to exponential backoff (randomises delay in `[0, cap]`).                              |
| `heartbeatTimeoutMs`   | `number`                        | `5000`     | Time to wait for any message after a ping before forcing `close()` (ms).                              |
| `schemas`              | `Record<string, SchemaAdapter>` | `{}`       | Per-message-type validators. Messages that fail validation are dropped and `onValidationError` fires. |

### `BackoffStrategy`

```ts theme={null}
type BackoffStrategy = "linear" | "exponential" | ((attempt: number) => number);
```

| Value                 | Delay formula                                                                     |
| --------------------- | --------------------------------------------------------------------------------- |
| `"linear"`            | `reconnectDelayMs × attempt`                                                      |
| `"exponential"`       | `min(maxReconnectDelayMs, reconnectDelayMs × 2^(attempt−1))`, optionally jittered |
| `(attempt) => number` | Your function — full control                                                      |

## Methods

### `connect()`

```ts theme={null}
await ws.connect();
```

Opens the WebSocket connection. Returns a `Promise` that resolves on `open` or rejects on immediate error.

### `close()`

```ts theme={null}
ws.close();
```

Closes the connection and permanently stops reconnection. Use this for intentional disconnects.

### `send(type, data)`

```ts theme={null}
ws.send("subscribe", { channel: "orderbook" });
```

Sends a JSON message with the shape `{ type, data, timestamp }`.

| Parameter | Type     | Description                       |
| --------- | -------- | --------------------------------- |
| `type`    | `string` | Message type identifier.          |
| `data`    | `T`      | Payload — any serialisable value. |

### `on(type, handler)`

```ts theme={null}
const unsub = ws.on("trade", (data) => {
  console.log("Trade received:", data);
});

// Stop listening:
unsub();
```

Subscribes to messages of a given `type`. Returns an **unsubscribe** function.

### `onError(handler)`

```ts theme={null}
ws.onError((error) => console.error("WS error:", error));
```

Subscribes to connection and handler errors. Returns an unsubscribe function.

### `onReconnect(handler)`

```ts theme={null}
const unsub = ws.onReconnect((attempt, delay) => {
  console.log(`Reconnecting — attempt ${attempt} in ${delay}ms`);
});
```

Fires just before each reconnect delay begins. Receives the 1-based attempt number and the computed delay. Returns an unsubscribe function.

### `onMaxRetriesReached(handler)`

```ts theme={null}
ws.onMaxRetriesReached(() => {
  showError("Connection lost. Please refresh.");
});
```

Fires once when all `maxReconnectAttempts` are exhausted. No further reconnection will be attempted. Returns an unsubscribe function.

### `onValidationError(handler)`

```ts theme={null}
ws.onValidationError((error, message) => {
  console.warn(`Invalid message of type "${message.type}":`, error.message);
});
```

Fires when a message fails schema validation. The message is **dropped** — `on()` handlers are not called. Returns an unsubscribe function.

### `request(type, data, responseType?)`

```ts theme={null}
const response = await ws.request<OrderRequest, OrderConfirmation>(
  "order:create",
  { symbol: "BTC-USD", qty: 1 }
);
```

Sends a message and waits for the matching response type (`${type}:response` by default). Rejects after `messageTimeout` ms.

| Parameter      | Type       | Default            | Description                     |
| -------------- | ---------- | ------------------ | ------------------------------- |
| `type`         | `string`   | —                  | Request message type.           |
| `data`         | `TRequest` | —                  | Request payload.                |
| `responseType` | `string`   | `${type}:response` | Expected response message type. |

### `isConnected()`

```ts theme={null}
if (ws.isConnected()) {
  ws.send("ping", {});
}
```

Returns `true` if the socket is in the `OPEN` state.

### `getState()`

```ts theme={null}
const state = ws.getState(); // WebSocket.readyState number
```

Returns the raw `WebSocket.readyState` value (`0–3`).

## Examples

### Basic connection with typed messages

```ts theme={null}
import { WebSocketHelper } from "bytekit";

interface TradeEvent {
  symbol: string;
  price: number;
  qty: number;
}

const ws = new WebSocketHelper("wss://api.example.com/ws");

await ws.connect();

ws.on<TradeEvent>("trade", (data) => {
  console.log(`${data.symbol} @ ${data.price}`);
});

ws.send("subscribe", { channel: "trades" });
```

### Exponential backoff with reconnect events

```ts theme={null}
import { WebSocketHelper } from "bytekit";

const ws = new WebSocketHelper("wss://api.example.com/ws", {
  backoffStrategy: "exponential",
  reconnectDelayMs: 1000,
  maxReconnectDelayMs: 30000,
  jitter: true,
});

ws.onReconnect((attempt, delay) => {
  console.log(`Reconnect attempt ${attempt} in ${delay}ms`);
});

ws.onMaxRetriesReached(() => {
  showBanner("Connection lost — please refresh the page.");
});

await ws.connect();
```

### Schema validation with Zod

```ts theme={null}
import { WebSocketHelper } from "bytekit";
import { z } from "zod";

const TradeSchema = z.object({
  symbol: z.string(),
  price: z.number().positive(),
  qty: z.number().positive(),
});

const ws = new WebSocketHelper("wss://api.example.com/ws", {
  schemas: {
    trade: TradeSchema, // SchemaAdapter — any object with .parse()
  },
});

ws.onValidationError((error, msg) => {
  console.warn(`Dropped invalid "${msg.type}" message:`, error.message);
});

ws.on("trade", (data) => {
  // data is a validated TradeSchema output — safe to use
  renderTrade(data);
});

await ws.connect();
```

### Pong detection (forced close on silence)

```ts theme={null}
import { WebSocketHelper } from "bytekit";

const ws = new WebSocketHelper("wss://api.example.com/ws", {
  heartbeatIntervalMs: 15000, // send ping every 15s
  heartbeatTimeoutMs: 5000,   // force-close if no message within 5s of ping
  backoffStrategy: "exponential",
});

// Any incoming message resets the pong timer automatically.
// If the server goes silent after a ping, ws.close() fires and
// the reconnect pipeline takes over.

await ws.connect();
```

### Graceful shutdown

```ts theme={null}
window.addEventListener("beforeunload", () => {
  ws.close();
});
```

<Tip>
  All `on*` subscription methods return an unsubscribe function. Store and call it when the component unmounts to avoid memory leaks.
</Tip>

<Warning>
  When `reconnect` is `true`, the helper reconnects on unexpected closures. Call `close()` explicitly to stop reconnection and close the connection cleanly. Calling `close()` also clears any pending pong timeout timer.
</Warning>
