
Security News
Axios Supply Chain Attack Reaches OpenAI macOS Signing Pipeline, Forces Certificate Rotation
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.
@hazeljs/websocket
Advanced tools
Real-time, the HazelJS way.
WebSockets and SSE. Rooms, broadcasting, decorator-based handlers. @WebSocketGateway, @OnMessage, @Subscribe. Chat, notifications, live dashboards — without the socket.io complexity.
@WebSocketGateway, @OnMessage, @Subscribenpm install @hazeljs/websocket
import { Injectable } from '@hazeljs/core';
import {
WebSocketGateway,
OnConnect,
OnDisconnect,
OnMessage,
WebSocketClient,
Data,
} from '@hazeljs/websocket';
@Injectable()
@WebSocketGateway({ path: '/ws' })
export class ChatGateway {
@OnConnect()
handleConnection(client: WebSocketClient) {
console.log('Client connected:', client.id);
client.emit('welcome', { message: 'Welcome to the chat!' });
}
@OnDisconnect()
handleDisconnect(client: WebSocketClient) {
console.log('Client disconnected:', client.id);
}
@OnMessage('message')
handleMessage(client: WebSocketClient, @Data() data: { text: string }) {
console.log('Received message:', data.text);
// Broadcast to all clients
client.broadcast('message', {
from: client.id,
text: data.text,
timestamp: new Date(),
});
}
}
import { HazelModule } from '@hazeljs/core';
import { WebSocketModule } from '@hazeljs/websocket';
import { ChatGateway } from './chat.gateway';
@HazelModule({
imports: [WebSocketModule],
providers: [ChatGateway],
})
export class AppModule {}
// Browser client
const ws = new WebSocket('ws://localhost:3000/ws');
ws.onopen = () => {
console.log('Connected');
ws.send(JSON.stringify({ event: 'message', data: { text: 'Hello!' } }));
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
console.log('Received:', message);
};
Define a WebSocket gateway:
@WebSocketGateway({
path: '/chat',
namespace: '/chat',
cors: {
origin: '*',
credentials: true,
},
})
export class ChatGateway {}
Handle client connections:
@OnConnect()
handleConnection(client: WebSocketClient) {
console.log('New client:', client.id);
// Send welcome message
client.emit('welcome', { message: 'Hello!' });
// Store client data
client.data.username = 'Guest';
}
Handle client disconnections:
@OnDisconnect()
handleDisconnect(client: WebSocketClient) {
console.log('Client left:', client.id);
// Notify others
client.broadcast('user-left', {
userId: client.id,
username: client.data.username,
});
}
Handle specific messages:
@OnMessage('chat-message')
handleChatMessage(client: WebSocketClient, @Data() data: ChatMessage) {
console.log('Chat message from', client.id, ':', data.text);
// Broadcast to all
client.broadcast('chat-message', {
from: client.data.username,
text: data.text,
timestamp: new Date(),
});
}
Subscribe to events:
@Subscribe('join-room')
handleJoinRoom(client: WebSocketClient, @Data() data: { room: string }) {
client.join(data.room);
// Notify room members
client.to(data.room).emit('user-joined', {
userId: client.id,
username: client.data.username,
});
}
@Subscribe('join-room')
handleJoinRoom(client: WebSocketClient, @Data() data: { room: string }) {
client.join(data.room);
client.emit('joined', { room: data.room });
}
@Subscribe('leave-room')
handleLeaveRoom(client: WebSocketClient, @Data() data: { room: string }) {
client.leave(data.room);
client.emit('left', { room: data.room });
}
@Subscribe('room-message')
handleRoomMessage(
client: WebSocketClient,
@Data() data: { room: string; text: string }
) {
// Send to all clients in room except sender
client.to(data.room).emit('room-message', {
from: client.id,
text: data.text,
});
}
@Subscribe('room-announcement')
handleAnnouncement(
client: WebSocketClient,
@Data() data: { room: string; text: string }
) {
// Send to all clients in room including sender
client.in(data.room).emit('announcement', {
text: data.text,
});
}
@OnMessage('global-message')
handleGlobalMessage(client: WebSocketClient, @Data() data: any) {
// Send to all connected clients except sender
client.broadcast('global-message', data);
}
@OnMessage('system-message')
handleSystemMessage(client: WebSocketClient, @Data() data: any) {
// Send to all connected clients including sender
this.server.emit('system-message', data);
}
@Subscribe('private-message')
handlePrivateMessage(
client: WebSocketClient,
@Data() data: { to: string; text: string }
) {
const targetClient = this.server.getClient(data.to);
if (targetClient) {
targetClient.emit('private-message', {
from: client.id,
text: data.text,
});
}
}
import { UseGuard } from '@hazeljs/core';
import { AuthGuard } from '@hazeljs/auth';
@WebSocketGateway({ path: '/secure' })
@UseGuard(AuthGuard)
export class SecureGateway {
@OnConnect()
handleConnection(client: WebSocketClient) {
// Only authenticated clients reach here
console.log('Authenticated user:', client.data.user);
}
}
@WebSocketGateway({ path: '/chat' })
export class ChatGateway {
@OnConnect()
async handleConnection(client: WebSocketClient) {
const token = client.handshake.query.token;
try {
const user = await this.authService.verifyToken(token);
client.data.user = user;
client.emit('authenticated', { user });
} catch (error) {
client.disconnect();
}
}
}
import { Injectable } from '@hazeljs/core';
import {
WebSocketGateway,
OnConnect,
OnDisconnect,
Subscribe,
WebSocketClient,
Data,
WebSocketServer,
} from '@hazeljs/websocket';
interface ChatMessage {
text: string;
room?: string;
}
interface JoinRoomData {
room: string;
username: string;
}
@Injectable()
@WebSocketGateway({ path: '/chat' })
export class ChatGateway {
@WebSocketServer()
server: WebSocketServer;
@OnConnect()
handleConnection(client: WebSocketClient) {
console.log(`Client connected: ${client.id}`);
client.emit('connected', {
clientId: client.id,
message: 'Welcome to the chat!',
});
}
@OnDisconnect()
handleDisconnect(client: WebSocketClient) {
console.log(`Client disconnected: ${client.id}`);
// Notify rooms
const rooms = client.rooms;
rooms.forEach((room) => {
client.to(room).emit('user-left', {
userId: client.id,
username: client.data.username,
});
});
}
@Subscribe('join-room')
handleJoinRoom(client: WebSocketClient, @Data() data: JoinRoomData) {
client.join(data.room);
client.data.username = data.username;
// Notify room members
client.to(data.room).emit('user-joined', {
userId: client.id,
username: data.username,
room: data.room,
});
// Confirm to sender
client.emit('joined-room', {
room: data.room,
members: this.getRoomMembers(data.room),
});
}
@Subscribe('leave-room')
handleLeaveRoom(client: WebSocketClient, @Data() data: { room: string }) {
client.leave(data.room);
// Notify room
client.to(data.room).emit('user-left', {
userId: client.id,
username: client.data.username,
});
}
@Subscribe('chat-message')
handleMessage(client: WebSocketClient, @Data() data: ChatMessage) {
const message = {
from: client.id,
username: client.data.username,
text: data.text,
timestamp: new Date(),
};
if (data.room) {
// Send to specific room
client.to(data.room).emit('chat-message', message);
} else {
// Broadcast to all
client.broadcast('chat-message', message);
}
}
@Subscribe('typing')
handleTyping(client: WebSocketClient, @Data() data: { room?: string }) {
const typingData = {
userId: client.id,
username: client.data.username,
};
if (data.room) {
client.to(data.room).emit('typing', typingData);
} else {
client.broadcast('typing', typingData);
}
}
private getRoomMembers(room: string): any[] {
const clients = this.server.getClientsInRoom(room);
return clients.map((c) => ({
id: c.id,
username: c.data.username,
}));
}
}
Store per-client data:
@OnConnect()
handleConnection(client: WebSocketClient) {
// Store custom data
client.data.username = 'Guest';
client.data.score = 0;
client.data.joinedAt = new Date();
}
@Subscribe('update-profile')
handleUpdateProfile(client: WebSocketClient, @Data() data: any) {
client.data.username = data.username;
client.data.avatar = data.avatar;
}
import { Controller, Get, Res } from '@hazeljs/core';
import { Response } from 'express';
@Controller('/events')
export class EventsController {
@Get('/stream')
streamEvents(@Res() res: Response) {
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
// Send event every second
const interval = setInterval(() => {
res.write(`data: ${JSON.stringify({ time: new Date() })}\n\n`);
}, 1000);
// Cleanup on close
res.on('close', () => {
clearInterval(interval);
res.end();
});
}
}
@OnDisconnect()See the examples directory for complete working examples.
npm test
Contributions are welcome! Please read our Contributing Guide for details.
Apache 2.0 © HazelJS
FAQs
WebSocket and Server-Sent Events module for HazelJS framework
The npm package @hazeljs/websocket receives a total of 1,486 weekly downloads. As such, @hazeljs/websocket popularity was classified as popular.
We found that @hazeljs/websocket demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
OpenAI rotated macOS signing certificates after a malicious Axios package reached its CI pipeline in a broader software supply chain attack.

Security News
Open source is under attack because of how much value it creates. It has been the foundation of every major software innovation for the last three decades. This is not the time to walk away from it.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.