Type-safe WebSocket messaging with Zod validation. A lean, modern library for real-time communication.
on
/off
methodsnpm install @xtr-dev/zodiac zod
import { defineMessage, z } from '@xtr-dev/zodiac';
// Define type-safe messages
const userMessage = defineMessage('user-message', z.object({
name: z.string(),
message: z.string(),
timestamp: z.number().optional()
}));
const chatJoin = defineMessage('chat-join', z.object({
userId: z.string(),
username: z.string()
}));
import { BrowserChannel } from '@xtr-dev/zodiac';
const channel = new BrowserChannel();
// Listen for messages with full type safety
channel.on(userMessage, (data, message) => {
console.log(`${data.name}: ${data.message}`);
// data.name and data.message are fully typed!
});
channel.on(chatJoin, (data) => {
console.log(`${data.username} joined!`);
});
// Connect and send messages
await channel.connect('wss://your-websocket-server.com');
// Send with automatic validation
await channel.sendMessage(userMessage, {
name: 'Alice',
message: 'Hello everyone!',
timestamp: Date.now()
});
import { NodeChannel } from '@xtr-dev/zodiac';
const channel = new NodeChannel();
// Same API as browser
channel.on(userMessage, async (data) => {
console.log(`Received: ${data.message}`);
// Echo back
await channel.sendMessage(userMessage, {
name: 'Server',
message: `Echo: ${data.message}`
});
});
await channel.connect('ws://localhost:8080');
Zodiac also supports WebRTC peer-to-peer communication with PeerChannel
for direct browser-to-browser messaging. See the API documentation for details.
Try the live HTML demo to see Zodiac in action:
git clone <this-repo>
cd zodiac
npm install
npm run example
This starts both a WebSocket todo server and opens an interactive demo where you can:
Zodiac provides both compile-time and runtime safety:
const userMsg = defineMessage('user', z.object({
name: z.string(),
age: z.number()
}));
// ✅ TypeScript knows the exact shape
channel.on(userMsg, (data) => {
console.log(data.name); // string
console.log(data.age); // number
});
// ✅ Runtime validation prevents invalid data
await channel.sendMessage(userMsg, {
name: 'Alice',
age: 'invalid' // ❌ Throws validation error
});
defineMessage(id, schema)
Creates a type-safe message definition with validation schema:
const myMessage = defineMessage('my-message', z.object({
content: z.string(),
priority: z.enum(['low', 'high'])
}));
// Returns: { id: string, schema: ZodSchema, messageSchema: ZodObject }
All channels (BrowserChannel
, NodeChannel
, PeerChannel
) share the same core API:
channel.on(definition, handler)
- Listen for messages with full type safetychannel.off(definition, handler)
- Remove message listenerschannel.sendMessage(definition, data)
- Send validated messageschannel.connect(url)
- Establish connectionchannel.disconnect()
- Close connectionchannel.isOpen()
- Check connection statusSee the full API documentation for complete details.
npm run docs
to generate docs locallyGenerate and serve docs locally:
npm run docs # Generate documentation
npm run docs:serve # Serve docs at http://localhost:8080
UNLICENSED - No rights reserved