Build WebSocket servers for real-time bidirectional communication
Generates production-ready WebSocket servers with Socket.IO for real-time bidirectional communication.
/plugin marketplace add jeremylongshore/claude-code-plugins-plus/plugin install websocket-server-builder@claude-code-plugins-plusAutomatically generate production-ready WebSocket servers with Socket.IO or native WebSocket implementations featuring room management, authentication, broadcasting, presence tracking, and resilient connection handling for real-time applications.
Use /build-websocket-server when you need to:
DON'T use this when:
This command implements Socket.IO as the primary approach because:
Alternative considered: Native WebSocket (ws)
Alternative considered: Server-Sent Events (SSE)
Before running this command:
Set up Socket.IO or ws server with proper configuration.
Add middleware for connection authentication and authorization.
Create handlers for all client events and server broadcasts.
Implement room joining, leaving, and broadcasting logic.
Set up reconnection, heartbeat, and error handling.
The command generates:
websocket/server.js - Main WebSocket server setupwebsocket/handlers/ - Event handler moduleswebsocket/middleware/ - Auth and validation middlewarewebsocket/rooms/ - Room management logicwebsocket/presence/ - User presence trackingwebsocket/client.js - Client SDK/libraryconfig/websocket.json - Server configurationtests/websocket/ - Integration tests// websocket/server.js - Socket.IO server with all features
const { Server } = require('socket.io');
const { createAdapter } = require('@socket.io/redis-adapter');
const { instrument } = require('@socket.io/admin-ui');
const jwt = require('jsonwebtoken');
const Redis = require('ioredis');
const crypto = require('crypto');
class WebSocketServer {
constructor(httpServer, config = {}) {
this.config = {
cors: {
origin: config.corsOrigin || ['http://localhost:3000'],
credentials: true
},
pingTimeout: config.pingTimeout || 60000,
pingInterval: config.pingInterval || 25000,
transports: config.transports || ['websocket', 'polling'],
maxHttpBufferSize: config.maxHttpBufferSize || 1e6, // 1MB
...config
};
this.io = new Server(httpServer, this.config);
this.redis = new Redis(config.redisUrl);
this.pubClient = this.redis;
this.subClient = this.redis.duplicate();
this.rooms = new Map();
this.users = new Map();
this.presence = new Map();
this.setupRedisAdapter();
this.setupMiddleware();
this.setupEventHandlers();
this.setupAdminUI();
this.startPresenceTracking();
}
setupRedisAdapter() {
// Enable horizontal scaling with Redis
this.io.adapter(createAdapter(this.pubClient, this.subClient));
}
setupMiddleware() {
// Authentication middleware
this.io.use(async (socket, next) => {
try {
const token = socket.handshake.auth.token;
if (!token) {
return next(new Error('Authentication required'));
}
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const user = await this.validateUser(decoded.userId);
if (!user) {
return next(new Error('Invalid user'));
}
// Attach user data to socket
socket.userId = user.id;
socket.user = user;
socket.sessionId = crypto.randomBytes(8).toString('hex');
// Rate limiting per user
const rateLimitKey = `ratelimit:${user.id}`;
const requests = await this.redis.incr(rateLimitKey);
if (requests === 1) {
await this.redis.expire(rateLimitKey, 60); // 1 minute window
}
if (requests > 100) { // 100 messages per minute
return next(new Error('Rate limit exceeded'));
}
next();
} catch (error) {
next(new Error('Authentication failed: ' + error.message));
}
});
// Connection logging middleware
this.io.use((socket, next) => {
console.log(`New connection from ${socket.handshake.address}`);
socket.on('error', (error) => {
console.error(`Socket error for ${socket.userId}:`, error);
});
next();
});
}
setupEventHandlers() {
this.io.on('connection', (socket) => {
this.handleConnection(socket);
// Room management
socket.on('join-room', (roomId, callback) =>
this.handleJoinRoom(socket, roomId, callback)
);
socket.on('leave-room', (roomId, callback) =>
this.handleLeaveRoom(socket, roomId, callback)
);
// Messaging
socket.on('message', (data, callback) =>
this.handleMessage(socket, data, callback)
);
socket.on('typing', (data) =>
this.handleTyping(socket, data)
);
socket.on('stop-typing', (data) =>
this.handleStopTyping(socket, data)
);
// Presence
socket.on('update-status', (status) =>
this.handleStatusUpdate(socket, status)
);
// Private messaging
socket.on('private-message', (data, callback) =>
this.handlePrivateMessage(socket, data, callback)
);
// File sharing
socket.on('upload-start', (data, callback) =>
this.handleUploadStart(socket, data, callback)
);
socket.on('upload-chunk', (data, callback) =>
this.handleUploadChunk(socket, data, callback)
);
// Voice/Video calls
socket.on('call-user', (data, callback) =>
this.handleCallUser(socket, data, callback)
);
socket.on('call-answer', (data) =>
this.handleCallAnswer(socket, data)
);
socket.on('ice-candidate', (data) =>
this.handleIceCandidate(socket, data)
);
// Disconnection
socket.on('disconnect', (reason) =>
this.handleDisconnection(socket, reason)
);
});
}
async handleConnection(socket) {
console.log(`User ${socket.userId} connected (${socket.sessionId})`);
// Track user connection
if (!this.users.has(socket.userId)) {
this.users.set(socket.userId, new Set());
}
this.users.get(socket.userId).add(socket.id);
// Update presence
await this.updatePresence(socket.userId, 'online');
// Send connection success with user data
socket.emit('connected', {
sessionId: socket.sessionId,
userId: socket.userId,
serverTime: Date.now()
});
// Rejoin previous rooms from session
const previousRooms = await this.getUserRooms(socket.userId);
for (const roomId of previousRooms) {
socket.join(roomId);
socket.to(roomId).emit('user-joined', {
userId: socket.userId,
user: socket.user,
roomId
});
}
// Send pending messages
const pendingMessages = await this.getPendingMessages(socket.userId);
if (pendingMessages.length > 0) {
socket.emit('pending-messages', pendingMessages);
}
}
async handleJoinRoom(socket, roomId, callback) {
try {
// Validate room access
const hasAccess = await this.validateRoomAccess(socket.userId, roomId);
if (!hasAccess) {
return callback({ error: 'Access denied' });
}
// Join the room
socket.join(roomId);
// Track room membership
if (!this.rooms.has(roomId)) {
this.rooms.set(roomId, new Set());
}
this.rooms.get(roomId).add(socket.userId);
// Get room info
const roomInfo = await this.getRoomInfo(roomId);
const members = await this.getRoomMembers(roomId);
// Notify others in room
socket.to(roomId).emit('user-joined', {
userId: socket.userId,
user: socket.user,
roomId
});
// Send room state to joiner
callback({
success: true,
room: roomInfo,
members: members,
recentMessages: await this.getRecentMessages(roomId)
});
// Update user's room list
await this.addUserRoom(socket.userId, roomId);
} catch (error) {
console.error('Join room error:', error);
callback({ error: error.message });
}
}
async handleMessage(socket, data, callback) {
try {
// Validate message
if (!data.roomId || !data.content) {
return callback({ error: 'Invalid message format' });
}
// Check room membership
if (!socket.rooms.has(data.roomId)) {
return callback({ error: 'Not in room' });
}
// Create message object
const message = {
id: crypto.randomBytes(16).toString('hex'),
roomId: data.roomId,
userId: socket.userId,
user: socket.user,
content: data.content,
type: data.type || 'text',
timestamp: Date.now(),
edited: false,
deleted: false
};
// Store message
await this.storeMessage(message);
// Broadcast to room
this.io.to(data.roomId).emit('new-message', message);
// Send acknowledgment
callback({
success: true,
messageId: message.id,
timestamp: message.timestamp
});
// Update room activity
await this.updateRoomActivity(data.roomId);
// Send push notifications to offline users
await this.sendPushNotifications(data.roomId, message, socket.userId);
} catch (error) {
console.error('Message error:', error);
callback({ error: error.message });
}
}
async handleTyping(socket, data) {
if (data.roomId && socket.rooms.has(data.roomId)) {
socket.to(data.roomId).emit('user-typing', {
userId: socket.userId,
user: socket.user,
roomId: data.roomId
});
// Auto-stop typing after 3 seconds
setTimeout(() => {
socket.to(data.roomId).emit('user-stopped-typing', {
userId: socket.userId,
roomId: data.roomId
});
}, 3000);
}
}
async handlePrivateMessage(socket, data, callback) {
try {
const targetUserId = data.targetUserId;
const targetSockets = this.users.get(targetUserId);
const message = {
id: crypto.randomBytes(16).toString('hex'),
fromUserId: socket.userId,
fromUser: socket.user,
toUserId: targetUserId,
content: data.content,
timestamp: Date.now(),
read: false
};
// Store private message
await this.storePrivateMessage(message);
if (targetSockets && targetSockets.size > 0) {
// User is online, deliver to all their connections
for (const socketId of targetSockets) {
this.io.to(socketId).emit('private-message', message);
}
message.delivered = true;
} else {
// User is offline, queue for later
await this.queueMessage(targetUserId, message);
message.delivered = false;
}
callback({
success: true,
messageId: message.id,
delivered: message.delivered
});
} catch (error) {
console.error('Private message error:', error);
callback({ error: error.message });
}
}
async handleDisconnection(socket, reason) {
console.log(`User ${socket.userId} disconnected: ${reason}`);
// Remove socket from user's connections
const userSockets = this.users.get(socket.userId);
if (userSockets) {
userSockets.delete(socket.id);
// If no more connections, mark as offline
if (userSockets.size === 0) {
this.users.delete(socket.userId);
await this.updatePresence(socket.userId, 'offline');
// Notify rooms user was in
for (const roomId of socket.rooms) {
if (roomId !== socket.id) { // Skip default room
socket.to(roomId).emit('user-left', {
userId: socket.userId,
roomId
});
}
}
}
}
// Clean up room memberships
for (const [roomId, members] of this.rooms.entries()) {
members.delete(socket.userId);
if (members.size === 0) {
this.rooms.delete(roomId);
}
}
}
// Presence tracking
startPresenceTracking() {
setInterval(async () => {
for (const [userId, status] of this.presence.entries()) {
// Check if user has active connections
if (!this.users.has(userId)) {
this.presence.set(userId, 'offline');
await this.broadcastPresenceUpdate(userId, 'offline');
}
}
}, 30000); // Check every 30 seconds
}
async updatePresence(userId, status) {
this.presence.set(userId, status);
await this.redis.setex(`presence:${userId}`, 120, status);
await this.broadcastPresenceUpdate(userId, status);
}
async broadcastPresenceUpdate(userId, status) {
// Get all rooms user is in
const userRooms = await this.getUserRooms(userId);
for (const roomId of userRooms) {
this.io.to(roomId).emit('presence-update', {
userId,
status,
timestamp: Date.now()
});
}
}
// Helper methods
async validateUser(userId) {
// Implement user validation
return { id: userId, name: `User ${userId}` };
}
async validateRoomAccess(userId, roomId) {
// Implement room access validation
return true;
}
async getRoomInfo(roomId) {
// Implement room info retrieval
return { id: roomId, name: `Room ${roomId}` };
}
async getRoomMembers(roomId) {
// Implement member list retrieval
return Array.from(this.rooms.get(roomId) || []);
}
async getRecentMessages(roomId, limit = 50) {
// Implement message history retrieval
return [];
}
async storeMessage(message) {
// Implement message storage
await this.redis.lpush(
`messages:${message.roomId}`,
JSON.stringify(message)
);
await this.redis.ltrim(`messages:${message.roomId}`, 0, 999);
}
async getUserRooms(userId) {
// Implement user room list retrieval
return [];
}
async getPendingMessages(userId) {
// Implement pending message retrieval
return [];
}
setupAdminUI() {
// Enable admin UI for monitoring
instrument(this.io, {
auth: {
type: 'basic',
username: process.env.SOCKETIO_ADMIN_USER || 'admin',
password: process.env.SOCKETIO_ADMIN_PASSWORD || 'admin'
},
readonly: false
});
}
// Public methods for external use
async broadcast(event, data) {
this.io.emit(event, data);
}
async broadcastToRoom(roomId, event, data) {
this.io.to(roomId).emit(event, data);
}
async sendToUser(userId, event, data) {
const userSockets = this.users.get(userId);
if (userSockets) {
for (const socketId of userSockets) {
this.io.to(socketId).emit(event, data);
}
}
}
getOnlineUsers() {
return Array.from(this.users.keys());
}
getRoomMembers(roomId) {
return Array.from(this.rooms.get(roomId) || []);
}
}
// Initialize server
const http = require('http');
const express = require('express');
const app = express();
const server = http.createServer(app);
const wsServer = new WebSocketServer(server, {
corsOrigin: process.env.CORS_ORIGIN?.split(',') || ['http://localhost:3000'],
redisUrl: process.env.REDIS_URL || 'redis://localhost:6379'
});
// REST endpoints for WebSocket management
app.get('/ws/stats', (req, res) => {
res.json({
onlineUsers: wsServer.getOnlineUsers().length,
rooms: wsServer.rooms.size,
connections: wsServer.io.engine.clientsCount
});
});
app.post('/ws/broadcast', express.json(), async (req, res) => {
const { event, data } = req.body;
await wsServer.broadcast(event, data);
res.json({ success: true });
});
server.listen(3000, () => {
console.log('WebSocket server running on port 3000');
});
module.exports = { WebSocketServer };
// websocket/native-server.js - Pure WebSocket with advanced features
const WebSocket = require('ws');
const http = require('http');
const crypto = require('crypto');
const EventEmitter = require('events');
class NativeWebSocketServer extends EventEmitter {
constructor(server, options = {}) {
super();
this.wss = new WebSocket.Server({
server,
perMessageDeflate: options.compression !== false,
maxPayload: options.maxPayload || 10 * 1024 * 1024, // 10MB
clientTracking: true,
...options
});
this.clients = new Map();
this.rooms = new Map();
this.messageHandlers = new Map();
this.heartbeatInterval = options.heartbeatInterval || 30000;
this.setupEventHandlers();
this.startHeartbeat();
}
setupEventHandlers() {
this.wss.on('connection', (ws, req) => {
this.handleConnection(ws, req);
});
this.wss.on('error', (error) => {
console.error('WebSocket server error:', error);
this.emit('error', error);
});
}
handleConnection(ws, req) {
// Generate client ID
const clientId = crypto.randomBytes(16).toString('hex');
// Parse authentication from URL or headers
const token = this.extractToken(req);
const user = this.authenticateToken(token);
if (!user) {
ws.close(1008, 'Unauthorized');
return;
}
// Setup client
const client = {
id: clientId,
ws: ws,
user: user,
rooms: new Set(),
isAlive: true,
joinedAt: Date.now(),
lastActivity: Date.now(),
messageCount: 0
};
this.clients.set(clientId, client);
// Send connection acknowledgment
this.send(client, {
type: 'connected',
clientId: clientId,
timestamp: Date.now()
});
// Setup client event handlers
ws.on('message', (data) => this.handleMessage(client, data));
ws.on('pong', () => this.handlePong(client));
ws.on('close', (code, reason) => this.handleClose(client, code, reason));
ws.on('error', (error) => this.handleError(client, error));
this.emit('connection', client);
}
handleMessage(client, data) {
try {
// Update activity
client.lastActivity = Date.now();
client.messageCount++;
// Parse message
let message;
if (typeof data === 'string') {
message = JSON.parse(data);
} else {
// Handle binary data
message = this.parseBinaryMessage(data);
}
// Rate limiting
if (client.messageCount > 100) {
const timeDiff = Date.now() - client.joinedAt;
if (timeDiff < 60000) { // Less than 1 minute
this.send(client, {
type: 'error',
error: 'Rate limit exceeded'
});
client.ws.close(1008, 'Rate limit exceeded');
return;
}
client.messageCount = 0;
client.joinedAt = Date.now();
}
// Route message to handler
const handler = this.messageHandlers.get(message.type);
if (handler) {
handler(client, message);
} else {
this.handleDefaultMessage(client, message);
}
this.emit('message', client, message);
} catch (error) {
console.error('Message handling error:', error);
this.send(client, {
type: 'error',
error: 'Invalid message format'
});
}
}
handleDefaultMessage(client, message) {
switch (message.type) {
case 'join':
this.joinRoom(client, message.room);
break;
case 'leave':
this.leaveRoom(client, message.room);
break;
case 'broadcast':
this.broadcastToRoom(message.room, message.data, client);
break;
case 'ping':
this.send(client, { type: 'pong', timestamp: Date.now() });
break;
default:
this.emit('custom-message', client, message);
}
}
joinRoom(client, roomId) {
if (!roomId) return;
// Add client to room
if (!this.rooms.has(roomId)) {
this.rooms.set(roomId, new Set());
}
this.rooms.get(roomId).add(client.id);
client.rooms.add(roomId);
// Notify room members
this.broadcastToRoom(roomId, {
type: 'user-joined',
userId: client.user.id,
roomId: roomId,
timestamp: Date.now()
}, client);
// Send confirmation
this.send(client, {
type: 'joined',
roomId: roomId,
members: this.getRoomMembers(roomId)
});
this.emit('room-joined', client, roomId);
}
leaveRoom(client, roomId) {
if (!roomId || !client.rooms.has(roomId)) return;
// Remove client from room
const room = this.rooms.get(roomId);
if (room) {
room.delete(client.id);
if (room.size === 0) {
this.rooms.delete(roomId);
}
}
client.rooms.delete(roomId);
// Notify room members
this.broadcastToRoom(roomId, {
type: 'user-left',
userId: client.user.id,
roomId: roomId,
timestamp: Date.now()
});
// Send confirmation
this.send(client, {
type: 'left',
roomId: roomId
});
this.emit('room-left', client, roomId);
}
broadcastToRoom(roomId, data, excludeClient = null) {
const room = this.rooms.get(roomId);
if (!room) return;
const message = typeof data === 'object' ? JSON.stringify(data) : data;
for (const clientId of room) {
if (excludeClient && clientId === excludeClient.id) continue;
const client = this.clients.get(clientId);
if (client && client.ws.readyState === WebSocket.OPEN) {
client.ws.send(message);
}
}
}
broadcast(data, excludeClient = null) {
const message = typeof data === 'object' ? JSON.stringify(data) : data;
this.clients.forEach((client) => {
if (excludeClient && client.id === excludeClient.id) return;
if (client.ws.readyState === WebSocket.OPEN) {
client.ws.send(message);
}
});
}
send(client, data) {
if (client.ws.readyState === WebSocket.OPEN) {
const message = typeof data === 'object' ? JSON.stringify(data) : data;
client.ws.send(message);
}
}
handlePong(client) {
client.isAlive = true;
}
handleClose(client, code, reason) {
console.log(`Client ${client.id} disconnected: ${code} - ${reason}`);
// Leave all rooms
for (const roomId of client.rooms) {
this.leaveRoom(client, roomId);
}
// Remove client
this.clients.delete(client.id);
this.emit('disconnection', client, code, reason);
}
handleError(client, error) {
console.error(`Client ${client.id} error:`, error);
this.emit('client-error', client, error);
}
startHeartbeat() {
setInterval(() => {
this.clients.forEach((client) => {
if (!client.isAlive) {
console.log(`Terminating inactive client ${client.id}`);
client.ws.terminate();
this.clients.delete(client.id);
return;
}
client.isAlive = false;
client.ws.ping();
});
}, this.heartbeatInterval);
}
// Utility methods
extractToken(req) {
// Extract from query string or authorization header
const url = new URL(req.url, `http://${req.headers.host}`);
return url.searchParams.get('token') ||
req.headers.authorization?.replace('Bearer ', '');
}
authenticateToken(token) {
// Implement token validation
if (!token) return null;
return { id: 'user123', name: 'Test User' };
}
getRoomMembers(roomId) {
const room = this.rooms.get(roomId);
if (!room) return [];
return Array.from(room).map(clientId => {
const client = this.clients.get(clientId);
return client ? client.user : null;
}).filter(Boolean);
}
// Public API
registerHandler(type, handler) {
this.messageHandlers.set(type, handler);
}
getClient(clientId) {
return this.clients.get(clientId);
}
getClients() {
return Array.from(this.clients.values());
}
getRooms() {
return Array.from(this.rooms.keys());
}
close() {
clearInterval(this.heartbeatTimer);
this.wss.close();
}
}
// Usage
const server = http.createServer();
const wsServer = new NativeWebSocketServer(server, {
compression: true,
heartbeatInterval: 30000
});
// Register custom message handlers
wsServer.registerHandler('chat', (client, message) => {
wsServer.broadcastToRoom(message.room, {
type: 'chat',
from: client.user.name,
content: message.content,
timestamp: Date.now()
});
});
wsServer.registerHandler('file-upload', (client, message) => {
// Handle file upload
console.log(`File upload from ${client.user.name}:`, message.filename);
});
// Event listeners
wsServer.on('connection', (client) => {
console.log(`New connection: ${client.user.name}`);
});
wsServer.on('room-joined', (client, roomId) => {
console.log(`${client.user.name} joined room ${roomId}`);
});
server.listen(3000, () => {
console.log('Native WebSocket server running on port 3000');
});
// websocket/client.js - Browser/Node.js client
class WebSocketClient {
constructor(url, options = {}) {
this.url = url;
this.options = options;
this.ws = null;
this.messageHandlers = new Map();
this.messageQueue = [];
this.reconnectAttempts = 0;
this.maxReconnectAttempts = options.maxReconnectAttempts || 5;
this.reconnectDelay = options.reconnectDelay || 1000;
this.isConnected = false;
}
connect() {
return new Promise((resolve, reject) => {
try {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log('WebSocket connected');
this.isConnected = true;
this.reconnectAttempts = 0;
// Send queued messages
while (this.messageQueue.length > 0) {
const message = this.messageQueue.shift();
this.send(message);
}
resolve();
};
this.ws.onmessage = (event) => {
this.handleMessage(event.data);
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
reject(error);
};
this.ws.onclose = (event) => {
console.log('WebSocket closed:', event.code, event.reason);
this.isConnected = false;
this.handleReconnect();
};
} catch (error) {
reject(error);
}
});
}
handleMessage(data) {
try {
const message = JSON.parse(data);
const handler = this.messageHandlers.get(message.type);
if (handler) {
handler(message);
} else {
console.log('Unhandled message:', message);
}
} catch (error) {
console.error('Message parsing error:', error);
}
}
on(type, handler) {
this.messageHandlers.set(type, handler);
}
send(data) {
const message = typeof data === 'object' ? JSON.stringify(data) : data;
if (this.isConnected && this.ws.readyState === WebSocket.OPEN) {
this.ws.send(message);
} else {
// Queue message for later
this.messageQueue.push(data);
}
}
handleReconnect() {
if (this.reconnectAttempts >= this.maxReconnectAttempts) {
console.error('Max reconnection attempts reached');
return;
}
this.reconnectAttempts++;
const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);
console.log(`Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
setTimeout(() => {
this.connect().catch(console.error);
}, delay);
}
close() {
if (this.ws) {
this.ws.close();
}
}
}
// tests/websocket.test.js
const { WebSocketServer } = require('../websocket/server');
const WebSocketClient = require('../websocket/client');
describe('WebSocket Server Tests', () => {
let server;
let client;
beforeEach(async () => {
server = new WebSocketServer(3001);
await server.start();
client = new WebSocketClient('ws://localhost:3001', {
token: 'test-token'
});
});
afterEach(async () => {
client.close();
await server.close();
});
test('should connect successfully', async () => {
await client.connect();
expect(client.isConnected).toBe(true);
});
test('should join room', async () => {
await client.connect();
const joined = new Promise((resolve) => {
client.on('joined', resolve);
});
client.send({ type: 'join', room: 'test-room' });
const result = await joined;
expect(result.roomId).toBe('test-room');
});
test('should broadcast messages', async () => {
const client2 = new WebSocketClient('ws://localhost:3001');
await client.connect();
await client2.connect();
// Both join same room
client.send({ type: 'join', room: 'test-room' });
client2.send({ type: 'join', room: 'test-room' });
// Set up message listener
const messageReceived = new Promise((resolve) => {
client2.on('chat', resolve);
});
// Send message
client.send({
type: 'chat',
room: 'test-room',
content: 'Hello World'
});
const message = await messageReceived;
expect(message.content).toBe('Hello World');
});
test('should handle reconnection', async () => {
await client.connect();
// Force disconnect
server.disconnectClient(client.id);
// Wait for reconnection
await new Promise(resolve => setTimeout(resolve, 2000));
expect(client.isConnected).toBe(true);
expect(client.reconnectAttempts).toBeGreaterThan(0);
});
});
| Error | Cause | Solution |
|---|---|---|
| "WebSocket connection failed" | Network issues or wrong URL | Check network and WebSocket URL |
| "Authentication required" | Missing or invalid token | Include valid auth token |
| "Rate limit exceeded" | Too many messages | Implement client-side throttling |
| "Maximum payload size exceeded" | Message too large | Split large messages or use chunking |
| "Connection timeout" | No heartbeat response | Check network stability |
Server Options
perMessageDeflate: Enable compressionmaxPayload: Maximum message sizepingInterval: Heartbeat frequencypingTimeout: Heartbeat timeouttransports: Allowed transports (Socket.IO)Client Options
reconnection: Enable auto-reconnectionreconnectionAttempts: Max reconnect triesreconnectionDelay: Initial reconnect delaytimeout: Connection timeoutauth: Authentication dataDO:
DON'T:
/webhook-handler-creator - Handle webhooks/real-time-sync - Implement data synchronization/message-queue-setup - Configure message queues/pubsub-system - Build pub/sub architecture/notification-service - Push notifications