UNPKG

bun-ws-router

Version:

Lightweight client/server WebSocket router for Bun with type-safe Zod/Valibot validation.

109 lines (88 loc) 2.99 kB
// SPDX-FileCopyrightText: 2025-present Kriasoft // SPDX-License-Identifier: MIT /** * TypeScript types for browser WebSocket client. * See @specs/client.md for full API documentation. */ export type ClientState = | "closed" // No connection; initial state or post-disconnect | "connecting" // Connection attempt in progress | "open" // WebSocket connected, messages flow | "closing" // Graceful disconnect initiated | "reconnecting"; // Waiting during backoff delay before retry export interface ClientOptions { url: string | URL; protocols?: string | string[]; reconnect?: { enabled?: boolean; // default: true maxAttempts?: number; // default: Infinity initialDelayMs?: number; // default: 300 maxDelayMs?: number; // default: 10_000 jitter?: "full" | "none"; // default: "full" }; queue?: "drop-oldest" | "drop-newest" | "off"; // default: "drop-newest" queueSize?: number; // default: 1000 autoConnect?: boolean; // default: false pendingRequestsLimit?: number; // default: 1000 auth?: { getToken?: () => | string | null | undefined | Promise<string | null | undefined>; attach?: "query" | "protocol"; // default: "query" queryParam?: string; // default: "access_token" protocolPrefix?: string; // default: "bearer." protocolPosition?: "append" | "prepend"; // default: "append" }; wsFactory?: (url: string | URL, protocols?: string | string[]) => WebSocket; } // Type helpers for schema-based operations // eslint-disable-next-line @typescript-eslint/no-explicit-any export type AnyMessageSchema = any; // Must use any to support both Zod and Valibot schemas export interface AnyInboundMessage { type: string; meta?: Record<string, unknown>; payload?: unknown; } // Handler type for typed message handlers export type MessageHandler = (msg: unknown) => void; export interface WebSocketClient { readonly state: ClientState; readonly isConnected: boolean; readonly protocol: string; connect(): Promise<void>; close(opts?: { code?: number; reason?: string }): Promise<void>; onState(cb: (state: ClientState) => void): () => void; onceOpen(): Promise<void>; on<S extends AnyMessageSchema>( schema: S, handler: MessageHandler, ): () => void; send<S extends AnyMessageSchema>( schema: S, payload: unknown, opts?: { meta?: Record<string, unknown>; correlationId?: string }, ): boolean; request<S extends AnyMessageSchema, R extends AnyMessageSchema>( schema: S, payload: unknown, reply: R, opts?: { timeoutMs?: number; meta?: Record<string, unknown>; correlationId?: string; signal?: AbortSignal; }, ): Promise<unknown>; onUnhandled(cb: (msg: AnyInboundMessage) => void): () => void; onError( cb: ( error: Error, context: { type: "parse" | "validation" | "overflow" | "unknown"; details?: unknown; }, ) => void, ): () => void; }