#WS-Kit: Type-Safe WebSocket Router for Bun

1 messages · Page 1 of 1 (latest)

orchid karma
#

Ever built a WebSocket API and felt like you were back to writing raw JSON strings? WS-Kit brings TypeScript type-safety to real-time communication on Bun — schemas flow from server to client automatically, and you get full IDE autocompletion everywhere.

What Makes It Cool

  • Type-Safe Routes: Define message schemas once with Zod, get full type inference in handlers
  • No Schema Repetition: Use the same validators client and server — pick Zod or Valibot
  • RPC Built-In: Request/response patterns with automatic correlation and timeouts
  • Fire-and-Forget + Broadcasting: Send to one client or publish to many, all type-checked
  • Bun Native: Runs on Bun's WebSocket implementation — zero overhead

Quick Example

import { z, message, rpc, createRouter } from "@ws-kit/zod";
import { serve } from "@ws-kit/bun";

// Type-safe message schemas
const Ping = message("PING", { text: z.string() });
const Pong = message("PONG", { reply: z.string() });

const router = createRouter();

// Fire-and-forget
router.on(Ping, (ctx) => {
  ctx.send(Pong, { reply: `Got: ${ctx.payload.text}` });
});

// Or request/response (RPC)
const GetData = rpc("GET", {}, "DATA", { value: z.string() });
router.rpc(GetData, (ctx) => {
  ctx.reply({ value: "hello" });
});

serve(router, { port: 3000 });

Connect any WebSocket client and send typed messages — everything is validated automatically.

Docs: https://kriasoft.com/ws-kit/
GitHub: https://github.com/kriasoft/ws-kit <-- give a star 🤩

#

WS-Kit: Type-Safe WebSocket Router for Bun

orchid karma
#

Just published @ws-kit/middleware with rate limiter:

  import { createRouter, message, z } from "@ws-kit/zod";
  import { rateLimit, keyPerUserPerType } from "@ws-kit/middleware";
  import { memoryRateLimiter } from "@ws-kit/adapters/memory";

  // Create router with rate limiting
  const router = createRouter<AppData>();

  // 5 messages per second, burst up to 10
  router.use(rateLimit({
    limiter: memoryRateLimiter({
      capacity: 10,
      tokensPerSecond: 5
    }),
    key: keyPerUserPerType, // Per-user per-message-type
  }));
orchid karma
#

Bun's adding ws.subscriptions! No more manual tracking of which channels a WebSocket is subscribed to. Here's a quick example using @ws-kit:

Quick Start (server):

import { z, message, createRouter, withZod } from "@ws-kit/zod";
import { serve } from "@ws-kit/bun";

const Ping = message("PING", { text: z.string() });
const Pong = message("PONG", { reply: z.string() });

const router = createRouter().plugin(withZod());

router.on(Ping, (ctx) => {
  ctx.send(Pong, { reply: `Got: ${ctx.payload.text}` });
});

serve(router, {
  port: 3000,
  authenticate(req) {
    const token = req.headers.get("authorization");
    return token ? { userId: "u_123" } : undefined;
  },
});

Quick Start (client):

import { rpc, message, wsClient } from "@ws-kit/client/zod";
import { z } from "@ws-kit/zod";

const Hello = rpc("HELLO", { name: z.string() }, "HELLO_OK", {
  text: z.string(),
});
const Broadcast = message("BROADCAST", { data: z.string() });

const client = wsClient({ url: "ws://localhost:3000" });
await client.connect();

const reply = await client.request(Hello, { name: "Ada" });
console.log(reply.payload.text); // typed as string

client.on(Broadcast, (msg) => {
  console.log(msg.payload.data);
});
orchid karma
#

Just pushed v0.8.2 with the new plugin-based architecture.

orchid karma