The WebSocket server provides real-time bidirectional communication between clients and the server.
WebSocket server runs on port 3001 (configurable via WS_PORT environment variable).
npm run ws:serverimport { WebSocketClient } from '@/lib/websocket/client';
const client = new WebSocketClient('ws://localhost:3001');
// Subscribe to a channel
client.subscribe('my-channel', (data) => {
console.log('Received message:', data);
});
// Send a message
client.broadcast('my-channel', { message: 'Hello!' });
// Unsubscribe
client.unsubscribe('my-channel');
// Close connection
client.close();# Listen to a channel
npm run cli ws listen demo
# Send a message to a channel
npm run cli ws send demo "Hello, World!"Send:
{
"type": "subscribe",
"channel": "channel-name"
}Response:
{
"type": "subscribed",
"channel": "channel-name"
}Send:
{
"type": "unsubscribe",
"channel": "channel-name"
}Response:
{
"type": "unsubscribed",
"channel": "channel-name"
}Send:
{
"type": "broadcast",
"channel": "channel-name",
"data": { "any": "data" }
}Notification (sent to all channel subscribers):
{
"type": "message",
"channel": "channel-name",
"data": { "any": "data" }
}Send:
{
"type": "ping"
}Response:
{
"type": "pong"
}The WebSocket server uses a channel-based pub/sub model:
- Clients subscribe to channels by name
- Messages broadcast to a channel are sent to all subscribers
- Clients can be subscribed to multiple channels simultaneously
- Each client maintains its own set of subscriptions
'use client';
import { useEffect, useState } from 'react';
import { WebSocketClient } from '@/lib/websocket/client';
export function ChatComponent() {
const [client, setClient] = useState<WebSocketClient | null>(null);
const [messages, setMessages] = useState<string[]>([]);
useEffect(() => {
const ws = new WebSocketClient('ws://localhost:3001');
ws.subscribe('chat', (data) => {
setMessages(prev => [...prev, data.message]);
});
setClient(ws);
return () => ws.close();
}, []);
const sendMessage = (message: string) => {
client?.broadcast('chat', { message });
};
return (
<div>
{messages.map((msg, i) => (
<div key={i}>{msg}</div>
))}
<button onClick={() => sendMessage('Hello!')}>
Send
</button>
</div>
);
}The WebSocket server is implemented in server/websocket.ts. It maintains:
- Connection pool of all connected clients
- Channel subscriptions for each client
- Message routing between clients on the same channel
WS_PORT=3001For production deployments with multiple server instances, consider using Redis Pub/Sub to synchronize messages across WebSocket servers:
// Example pattern
import { createClient } from 'redis';
const redis = createClient({ url: process.env.REDIS_URL });
await redis.subscribe('channel', (message) => {
// Broadcast to local WebSocket clients
});Add authentication to WebSocket connections:
ws.on('connection', (socket, request) => {
const token = new URL(request.url!, 'ws://base').searchParams.get('token');
// Verify token
});