UNPKG

bun-ws-router

Version:

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

52 lines (48 loc) 2.19 kB
// SPDX-FileCopyrightText: 2025-present Kriasoft // SPDX-License-Identifier: MIT import { WebSocketRouter as BaseWebSocketRouter } from "../shared/router"; import { ValibotValidatorAdapter } from "./adapter"; import type { MessageHandler as ValibotMessageHandler, MessageSchemaType as ValibotMessageSchemaType, WebSocketData, } from "./types"; /** * WebSocket router for Bun that provides type-safe message routing with Valibot validation. * Routes incoming messages to handlers based on message type. * * ARCHITECTURE: This is a thin wrapper that binds the Valibot validator adapter to the * shared router implementation. The adapter pattern allows swapping between Zod and * Valibot without duplicating routing logic. * * @template T - Application-specific data to store with each WebSocket connection. * Always includes a clientId property generated automatically. * Example: { userId: string, roles: string[] } */ export class WebSocketRouter< T extends Record<string, unknown> = Record<string, never>, > extends BaseWebSocketRouter<T> { constructor() { // NOTE: ValibotValidatorAdapter handles schema validation and error formatting // specific to Valibot. The base router handles all routing and connection logic. super(new ValibotValidatorAdapter()); } /** * Registers a message handler with Valibot-specific type inference. * * This override provides validator-specific types for better IDE experience, * but creates a Liskov Substitution Principle variance issue. The more specific * handler signature means this class can't be used everywhere the base class is expected. * This is an intentional trade-off for better developer experience. * * @see specs/adrs.md#ADR-001 - Type override solution for IDE inference */ // @ts-expect-error - Intentional override with more specific types for better DX onMessage<Schema extends ValibotMessageSchemaType>( schema: Schema, handler: ValibotMessageHandler<Schema, WebSocketData<T>>, ): this { // eslint-disable-next-line @typescript-eslint/no-explicit-any return super.onMessage(schema as any, handler as any); } }