Loading...
Loading...
Steedos Server real-time WebSocket system using Socket.IO. Covers the AppGateway (@WebSocketGateway), connection authentication via cookies, room-based event routing (tenant-scoped rooms), subscribe/unsubscribe events, metadata change notifications, record change events, notification broadcasting, and Moleculer event integration for cross-service real-time communication.
npx skill4agent add steedos/steedos-platform server-websocket@nestjs/websocketsAppGatewayAppGateway@WebSocketGateway({ path: "/socket.io/", cors: true })
export class AppGateway implements OnGatewayConnection, OnGatewayDisconnect/socket.io/HybridAdapter@builder6/corecookiesocket.handshake.headersX-Space-IdX-Auth-TokenAuthService.getUserByToken(token){ user, anonymous, system, portal: { tenantId } }anonymousRoom format: {tenantId}-{roomPart}
Individual: {roomPart}-{userId}// Client-side
socket.emit("subscribe", {
roomParts: ["orders", "notifications"],
individual: false // shared room
});
socket.emit("subscribe", {
roomParts: "notification-change",
individual: true // per-user room: "notification-change-{userId}"
});
socket.emit("unsubscribe", {
roomParts: ["orders"]
});| Event | Payload | Description |
|---|---|---|
| | Join rooms |
| | Leave rooms |
| date | System connection keep-alive |
| Event | Payload | Description |
|---|---|---|
| — | Sent on successful connection |
| UTC date | Response to ping |
| | Metadata change (objects, fields, apps, etc.) |
| | User notification (per-user room) |
| | Record change event |
// Emitted to ALL connected clients (global broadcast)
socket.on("s:metadata:change", ({ type, action, _id, name, objectName }) => {
// type: "apps", "objects", "object_listviews", "object_actions", "object_fields"
// action: "insert", "update", "delete"
// Refresh UI accordingly
});// Client subscribes to a specific record
socket.emit("subscribe", {
roomParts: `record:orders:change-${recordId}`,
individual: false
});
// Server emits when record changes
socket.on(`s:record:orders:change-${recordId}`, ({ _id }) => {
// Reload record
});{tenantId}-record:{objectApiName}:change-{recordId}// Client subscribes
socket.emit("subscribe", {
roomParts: "notification-change",
individual: true // creates room: "notification-change-{userId}"
});
// Server pushes notification
socket.on("s:notification-change", ({ message }) => {
// Show notification
});| Moleculer Event | WebSocket Action |
|---|---|
| → |
| → |
| → Generic socket emit with optional room |
| → |
| Moleculer event emitted when client subscribes |
// Emit to specific room from a Moleculer service
broker.emit("$broadcast.socket.emit", {
data: {
eventName: "custom-event",
eventParams: { key: "value" },
room: "tenantId-room-name" // optional, omit for global
}
});
// Send notification to specific users
broker.emit("$broadcast.$notification.users", {
data: {
tenantId: "space_id",
users: ["user1", "user2"],
message: "You have a new task"
}
});