WebSocket API Reference
Complete API reference for the PXL Framework WebSocket module.
Table of Contents
- WebSocketServer
- WebSocketClient
- WebSocketService
- WebSocketClientManager
- WebSocketRoomManager
- Controllers
- Configuration Interfaces
WebSocketServer
Server-side WebSocket management with room support and multi-worker coordination.
Properties
clientManager
public clientManager: WebSocketClientManagerManages connected clients and their metadata.
rooms
public get rooms(): Map<string, Set<string>>Map of room names to sets of client IDs in each room.
type
public get type(): WebSocketType // Returns 'server'Identifies this as a server-type WebSocket instance.
Methods
load()
public async load(): Promise<void>Load and configure WebSocket routes and controllers. Must be called before start().
start()
public async start({ fastifyServer }: { fastifyServer: FastifyInstance }): Promise<{ server: WS }>Start the WebSocket server and attach to Fastify HTTP server.
Parameters:
fastifyServer: Fastify instance to attach WebSocket upgrade handler
Returns: Object containing the WebSocket server instance
Example:
const { server } = await app.websocket.server.start({
fastifyServer: app.webserver.server,
});stop()
public async stop(): Promise<void>Gracefully stop the WebSocket server:
- Abort ongoing operations
- Clean up Redis subscribers
- Close all client connections
- Reset managers
joinRoom()
public async joinRoom({
ws,
userId,
userType,
username,
roomName,
}: {
ws: WebSocket;
userId?: number;
userType?: string;
username?: string;
roomName: string;
}): Promise<boolean>Add a client to a room with optional user data.
Parameters:
ws: WebSocket connectionuserId: Optional user ID (will fetch user data from database)userType: Optional user type/roleusername: Optional display nameroomName: Name of room to join
Returns: true on success
Example:
await websocket.joinRoom({
ws: clientSocket,
userId: 123,
username: 'Alice',
userType: 'member',
roomName: 'chat:general',
});leaveRoom()
public leaveRoom({ ws, roomName }: { ws: WebSocket; roomName: string }): voidRemove a client from a room.
Parameters:
ws: WebSocket connectionroomName: Name of room to leave
sendClientMessage()
public sendClientMessage(ws: WebSocket, data: unknown, binary?: boolean): voidSend a message to a specific client.
Parameters:
ws: WebSocket connectiondata: Message data (will be JSON stringified)binary: Optional, send as binary (default: false)
Example:
websocket.sendClientMessage(ws, {
type: 'notification',
action: 'alert',
data: { message: 'Welcome!' },
});sendMessage()
public sendMessage({ data }: { data: unknown }): voidSend a message via Redis pub/sub (for cross-worker messaging).
Parameters:
data: Message data to publish
sendMessageToAll()
public sendMessageToAll({ data }: { data: unknown }): voidBroadcast a message to all connected clients across all workers.
Parameters:
data: Message data to broadcast
Example:
websocket.sendMessageToAll({
data: {
type: 'announcement',
action: 'new',
data: { text: 'System maintenance in 10 minutes' },
},
});sendCustomMessage()
public sendCustomMessage({ data }: { data: unknown }): voidSend a custom message via Redis pub/sub for application-specific cross-worker communication.
Parameters:
data: Custom message data
broadcastToAllClients()
public broadcastToAllClients({
data,
excludeClientId,
}: {
data: { [key: string]: any };
excludeClientId?: string;
}): voidBroadcast to all clients connected to this worker instance.
Parameters:
data: Message dataexcludeClientId: Optional client ID to exclude from broadcast
sendMessageError()
public sendMessageError({
webSocketClientId,
error,
}: {
webSocketClientId: string;
error: string;
}): voidSend an error message to a specific client (works across workers via Redis).
Parameters:
webSocketClientId: Target client IDerror: Error message
getClients()
public getClients({ userType }: { userType?: string }): any[]Get list of clients, optionally filtered by user type.
Parameters:
userType: Optional user type filter
Returns: Array of client objects
WebSocketClient
Client-side WebSocket connection manager.
Properties
type
public get type(): WebSocketType // Returns 'client'Identifies this as a client-type WebSocket instance.
Methods
load()
public async load(): Promise<void>Load and configure client-side routes and controllers.
connectToServer()
public async connectToServer(): Promise<void>Establish connection to WebSocket server.
Example:
const client = new WebSocketClient(config);
await client.load();
await client.connectToServer();disconnect()
public disconnect(): voidDisconnect from server and clean up resources.
isClientConnected()
public isClientConnected(): booleanCheck if client is currently connected.
Returns: true if connected and ready
sendClientMessage()
public sendClientMessage(data: unknown, binary?: boolean): voidSend a message to the server.
Parameters:
data: Message data (will be JSON stringified)binary: Optional, send as binary (default: false)
Example:
client.sendClientMessage({
type: 'chat',
action: 'send',
data: { text: 'Hello server!' },
});sendMessage()
public sendMessage(data: unknown): voidAlias for sendClientMessage().
WebSocketService
High-level service for simplified WebSocket messaging.
Constructor
constructor(options: WebSocketServiceOptions)Options:
interface WebSocketServiceOptions {
webSocketServer?: WebSocketServer;
redisInstance?: RedisInstance;
workerId?: string;
}Methods
broadcast()
async broadcast(message: WebSocketMessage): Promise<void>Broadcast a message to all connected clients.
Parameters:
message: Message object withtype,action, and optionaldata
Example:
const service = new WebSocketService({
webSocketServer: app.websocket.server,
redisInstance: app.redis.instance,
workerId: String(process.pid),
});
await service.broadcast({
type: 'notification',
action: 'update',
data: { message: 'New version available' },
});sendToClients()
async sendToClients(
clientIds: string[],
message: WebSocketMessage
): Promise<void>Send a message to specific clients by ID.
Parameters:
clientIds: Array of client IDsmessage: Message to send
Note: Currently broadcasts to all clients. Room-specific sending is available via sendToRooms().
sendToRooms()
async sendToRooms(
roomNames: string[],
message: WebSocketMessage
): Promise<void>Send a message to all clients in specified rooms.
Parameters:
roomNames: Array of room namesmessage: Message to send
Example:
await service.sendToRooms(['vip', 'moderators'], {
type: 'admin',
action: 'alert',
data: { message: 'Review pending content' },
});sendUserMessage()
async sendUserMessage(action: string, data: any): Promise<void>Convenience method for user-type messages.
Parameters:
action: Message actiondata: Message data
Example:
await service.sendUserMessage('profileUpdated', {
userId: 123,
changes: ['avatar', 'bio'],
});sendSystemMessage()
async sendSystemMessage(action: string, data: any): Promise<void>Convenience method for system-type messages.
Parameters:
action: Message actiondata: Message data
sendErrorMessage()
async sendErrorMessage(action: string, error: any): Promise<void>Convenience method for error messages.
Parameters:
action: Error actionerror: Error object or details
WebSocketClientManager
Manages connected WebSocket clients and their metadata.
Methods
addClient()
public addClient({
clientId,
ws,
lastActivity,
user,
}: {
clientId: string;
ws: WebSocket | null;
lastActivity: number;
user?: { userId: number; payload: any } | null;
}): voidAdd a client to the registry.
Parameters:
clientId: Unique client identifierws: WebSocket connection (null if on different worker)lastActivity: Timestamp of last activityuser: Optional authenticated user data
removeClient()
public removeClient(clientId: string): voidRemove a client from the registry.
getClient()
public getClient({
clientId,
requireWs,
}: {
clientId: string;
requireWs?: boolean;
}): WebSocketClient | undefinedGet a client by ID.
Parameters:
clientId: Client identifierrequireWs: If true, only return if WebSocket connection is available
Returns: Client object or undefined
getClientId()
public getClientId({ ws }: { ws: WebSocket }): string | undefinedGet client ID from WebSocket connection.
Returns: Client ID or undefined
getClients()
public getClients({ userType }: { userType?: string } = {}): WebSocketClient[]Get all clients, optionally filtered by user type.
Parameters:
userType: Optional user type filter
Returns: Array of client objects
updateClient()
public updateClient({
clientId,
key,
data,
}: {
clientId: string;
key: string;
data: any;
}): voidUpdate client metadata.
Parameters:
clientId: Client identifierkey: Metadata key to updatedata: New value
Example:
clientManager.updateClient({
clientId: 'abc123',
key: 'preferences',
data: { theme: 'dark', notifications: true },
});disconnectClient()
public disconnectClient({
clientId,
code,
reason,
}: {
clientId: string;
code?: number;
reason?: string;
}): voidDisconnect a client.
Parameters:
clientId: Client to disconnectcode: Optional WebSocket close codereason: Optional close reason
broadcastClientList()
public broadcastClientList(event?: string): voidBroadcast updated client list to all clients (internal use).
cleanup()
public cleanup(): voidClean up all clients and reset state.
WebSocketRoomManager
Manages WebSocket rooms and client membership.
Properties
rooms
public rooms: Map<string, Set<string>>Map of room names to sets of client IDs.
Methods
addClientToRoom()
public addClientToRoom({
clientId,
user,
roomName,
broadcast,
}: {
clientId: string;
user: any;
roomName: string;
broadcast?: boolean;
}): voidAdd a client to a room.
Parameters:
clientId: Client identifieruser: User dataroomName: Room to joinbroadcast: Whether to broadcast client list update (default: true)
removeClientFromRoom()
public removeClientFromRoom({
roomName,
clientId,
broadcast,
}: {
roomName: string;
clientId: string;
broadcast?: boolean;
}): voidRemove a client from a room.
Parameters:
roomName: Room to leaveclientId: Client identifierbroadcast: Whether to broadcast client list update (default: true)
removeClientFromAllRooms()
public removeClientFromAllRooms({ clientId }: { clientId: string }): voidRemove a client from all rooms.
isClientInRoom()
public isClientInRoom({
clientId,
roomName,
}: {
clientId: string;
roomName: string;
}): booleanCheck if a client is in a specific room.
Returns: true if client is in room
getRoomClients()
public getRoomClients({ roomName }: { roomName: string }): string[]Get all client IDs in a room.
Returns: Array of client IDs
printRooms()
public printRooms(): voidPrint room information to console (for debugging).
cleanup()
public cleanup(): voidClean up all rooms and reset state.
Controllers
WebSocketServerBaseController
Base class for server-side WebSocket controllers.
export default abstract class WebSocketServerBaseController {
protected webSocketServer: WebSocketServer;
protected redisInstance: RedisInstance;
protected queueManager: QueueManager;
protected databaseInstance: DatabaseInstance;
constructor(params: WebSocketServerBaseControllerConstructorParams);
}Properties:
webSocketServer: Access to WebSocket serverredisInstance: Redis clientqueueManager: Queue managementdatabaseInstance: Database access
Example:
import { WebSocketServerBaseController } from '@scpxl/nodejs-framework/websocket';
export default class ChatController extends WebSocketServerBaseController {
public send = (ws: WebSocket, clientId: string, data: any) => {
// Access injected dependencies
const userId = this.getUserId(clientId);
this.webSocketServer.sendMessageToAll({
data: {
type: 'chat',
action: 'message',
data: { userId, text: data.text },
},
});
return { success: true };
};
private getUserId(clientId: string): number | undefined {
const client = this.webSocketServer.clientManager.getClient({ clientId });
return client?.user?.userId;
}
}WebSocketClientBaseController
Base class for client-side WebSocket controllers.
export default abstract class WebSocketClientBaseController {
protected sendMessage: (data: unknown) => void;
protected redisInstance: RedisInstance;
protected queueManager: QueueManager;
protected databaseInstance: DatabaseInstance;
constructor(params: WebSocketClientBaseControllerConstructorParams);
}Properties:
sendMessage: Function to send messages to serverredisInstance: Redis clientqueueManager: Queue managementdatabaseInstance: Database access
Configuration Interfaces
WebSocketOptions
interface WebSocketOptions {
enabled: boolean;
type: 'server' | 'client';
host?: string;
url: string;
controllersDirectory: string;
routes?: WebSocketRoute[];
debug?: {
printRoutes?: boolean;
};
rooms?: {
clientCanJoinMultipleRooms?: boolean;
};
disconnectInactiveClients?: {
enabled: boolean;
inactiveTime?: number; // milliseconds
intervalCheckTime?: number; // milliseconds
log?: boolean;
};
events?: {
onServerStarted?: (params: { webSocketServer: WS }) => void;
onConnected?: (params: {
ws: WebSocket;
clientId: string;
joinRoom?: (params: { userId?: string; userType?: string; username: string; roomName: string }) => void;
}) => void;
onDisconnected?: (params: { clientId?: string }) => void;
onMessage?: (params: {
ws: WebSocket;
clientId: string;
data: { type: string; action: string; data: unknown };
redisInstance: RedisInstance;
queueManager: QueueManager;
databaseInstance: DatabaseInstance;
}) => void;
onError?: (params: { error: Error }) => void;
};
subscriberHandlers?: {
directory?: string; // Directory that exports subscriber handlers
handlers?: WebSocketSubscriberDefinition[]; // Optional inline handlers
};
}WebSocketRoute
interface WebSocketRoute {
type: string; // Message type (e.g., 'chat', 'notification')
action: string; // Message action (e.g., 'send', 'update')
controllerName: string; // Controller file name (without extension)
controller?: any; // Optional: direct controller class reference
}WebSocketMessage
interface WebSocketMessage {
type: string; // Message type/category
action: string; // Specific action
data?: any; // Optional payload
}WebSocketRedisSubscriberEvent
Enum of Redis pub/sub event names for cross-worker coordination:
enum WebSocketRedisSubscriberEvent {
ClientConnected = 'clientConnected',
ClientDisconnected = 'clientDisconnected',
ClientJoinedRoom = 'clientJoinedRoom',
ClientLeftRoom = 'clientLeftRoom',
DisconnectClient = 'disconnectClient',
SendMessage = 'sendMessage',
SendMessageToAll = 'sendMessageToAll',
MessageError = 'messageError',
QueueJobCompleted = 'queueJobCompleted',
QueueJobError = 'queueJobError',
Custom = 'custom',
}
### WebSocketSubscriberDefinition
```typescript
interface WebSocketSubscriberDefinition {
name?: string; // Optional identifier for logging
description?: string;
priority?: number; // Higher numbers run first
channels?: string[]; // Explicit channels to listen to
matchers?: (string | RegExp | ((context: WebSocketSubscriberHandlerContext) => boolean))[];
handle: (context: WebSocketSubscriberHandlerContext) => unknown | Promise<unknown>;
}Use defineWebSocketSubscriber to get type inference when authoring handlers:
defineWebSocketSubscriber({
name: 'customRelay',
description: 'Forward custom events to connected clients',
channel: 'custom',
priority: 10,
handle: ({ channel, message, webSocketServer }) => {
// ...
},
});
defineWebSocketSubscriber({
name: 'segmentEnrichment',
match: [/^analytics:/, ({ message }) => message?.segment === 'vip'],
handle: ({ queueManager, message }) => {
queueManager.add('analytics', message);
},
});
interface WebSocketSubscriberHandlerContext {
channel: string;
message: any;
webSocketServer: WebSocketServer;
databaseInstance: DatabaseInstance;
redisInstance: RedisInstance;
queueManager: QueueManager;
}
## Type Definitions
### WebSocketClient
```typescript
interface WebSocketClient {
clientId: string;
ws: WebSocket | null;
lastActivity: number;
user?: {
userId: number;
payload: Record<string, unknown>;
} | null;
roomName?: string | null;
[key: string]: any; // Custom metadata
}WebSocketType
type WebSocketType = 'server' | 'client';Usage Examples
Basic Server Setup
import { WebApplication } from '@scpxl/nodejs-framework';
const app = new WebApplication({
name: 'my-app',
webSocket: {
enabled: true,
type: 'server',
url: 'ws://localhost:3000/ws',
controllersDirectory: './src/websocket/controllers',
routes: [
{
type: 'chat',
action: 'send',
controllerName: 'chat',
},
],
},
redis: { host: '127.0.0.1', port: 6379 },
});
await app.start();Using WebSocketService
import { WebSocketService } from '@scpxl/nodejs-framework/websocket';
const wsService = new WebSocketService({
webSocketServer: app.websocket.server,
redisInstance: app.redis.instance,
workerId: String(process.pid),
});
// Broadcast to all
await wsService.broadcast({
type: 'notification',
action: 'alert',
data: { message: 'Server restart in 5 minutes' },
});
// Send to specific rooms
await wsService.sendToRooms(['vip', 'admin'], {
type: 'announcement',
action: 'new',
data: { text: 'Early access to new features!' },
});
// Convenience methods
await wsService.sendUserMessage('statusChanged', { userId: 123, status: 'online' });
await wsService.sendSystemMessage('maintenance', { minutes: 5 });
await wsService.sendErrorMessage('invalidAction', new Error('Action not allowed'));Custom Controller
import { WebSocketServerBaseController } from '@scpxl/nodejs-framework/websocket';
import type { WebSocket } from 'ws';
export default class GameController extends WebSocketServerBaseController {
public move = async (ws: WebSocket, clientId: string, data: any) => {
// Validate move
const isValid = await this.validateMove(data);
if (!isValid) {
return { error: 'Invalid move' };
}
// Update game state in database
await this.updateGameState(data);
// Broadcast to room
const client = this.webSocketServer.clientManager.getClient({ clientId });
const roomName = client?.roomName;
if (roomName) {
const roomClients = this.webSocketServer.rooms.get(roomName);
roomClients?.forEach(id => {
const c = this.webSocketServer.clientManager.getClient({ clientId: id });
if (c?.ws) {
this.webSocketServer.sendClientMessage(c.ws, {
type: 'game',
action: 'moveMade',
data: { playerId: clientId, move: data },
});
}
});
}
return { success: true };
};
private async validateMove(data: any): Promise<boolean> {
// Validation logic
return true;
}
private async updateGameState(data: any): Promise<void> {
// Database update
}
}Related Documentation
- WebSocket Guide - Comprehensive implementation guide
- WebSocket Concepts - Architecture and design patterns
- Configuration Guide - Application configuration
- Hello World Example - Working example