
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@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
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
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.