"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; var NotificationsGateway_1; Object.defineProperty(exports, "__esModule", { value: true }); exports.NotificationsGateway = void 0; const websockets_1 = require("@nestjs/websockets"); const socket_io_1 = require("socket.io"); const common_1 = require("@nestjs/common"); let NotificationsGateway = NotificationsGateway_1 = class NotificationsGateway { constructor() { this.logger = new common_1.Logger(NotificationsGateway_1.name); this.userSockets = new Map(); this.socketUsers = new Map(); } handleConnection(client) { try { const userId = this.extractUserId(client); const tenantId = this.extractTenantId(client); if (!userId || !tenantId) { this.logger.warn(`Client ${client.id} connected without auth, disconnecting`); client.disconnect(); return; } client.userId = userId; client.tenantId = tenantId; const userKey = `${tenantId}:${userId}`; if (!this.userSockets.has(userKey)) { this.userSockets.set(userKey, new Set()); } this.userSockets.get(userKey).add(client.id); this.socketUsers.set(client.id, userKey); client.join(`tenant:${tenantId}`); client.join(`user:${userId}`); this.logger.debug(`User ${userId} connected from tenant ${tenantId} (socket: ${client.id})`); client.emit('connected', { socketId: client.id, userId, tenantId, }); } catch (error) { this.logger.error(`Connection error: ${error.message}`); client.disconnect(); } } handleDisconnect(client) { const userKey = this.socketUsers.get(client.id); if (userKey) { const sockets = this.userSockets.get(userKey); if (sockets) { sockets.delete(client.id); if (sockets.size === 0) { this.userSockets.delete(userKey); } } this.socketUsers.delete(client.id); } this.logger.debug(`Client ${client.id} disconnected`); } async emitToUser(tenantId, userId, notification) { const userKey = `${tenantId}:${userId}`; const socketIds = this.userSockets.get(userKey); if (!socketIds || socketIds.size === 0) { this.logger.debug(`No active sockets for user ${userId}`); return 0; } for (const socketId of socketIds) { this.server.to(socketId).emit('notification:created', notification); } this.logger.debug(`Emitted notification to user ${userId} (${socketIds.size} sockets)`); return socketIds.size; } async emitToTenant(tenantId, event, data) { this.server.to(`tenant:${tenantId}`).emit(event, data); this.logger.debug(`Emitted ${event} to tenant ${tenantId}`); } handleMarkAsRead(client, payload) { if (!client.userId || !client.tenantId) { return; } const userKey = `${client.tenantId}:${client.userId}`; const socketIds = this.userSockets.get(userKey); if (socketIds) { for (const socketId of socketIds) { if (socketId !== client.id) { this.server.to(socketId).emit('notification:read', payload); } } } this.logger.debug(`User ${client.userId} marked notification ${payload.notificationId} as read`); } handleMarkAllAsRead(client) { if (!client.userId || !client.tenantId) { return; } const userKey = `${client.tenantId}:${client.userId}`; const socketIds = this.userSockets.get(userKey); if (socketIds) { for (const socketId of socketIds) { if (socketId !== client.id) { this.server.to(socketId).emit('notification:read-all', {}); } } } this.logger.debug(`User ${client.userId} marked all notifications as read`); } handleGetUnreadCount(client) { return { event: 'notification:unread-count-requested' }; } async emitUnreadCount(tenantId, userId, count) { const userKey = `${tenantId}:${userId}`; const socketIds = this.userSockets.get(userKey); if (socketIds) { for (const socketId of socketIds) { this.server.to(socketId).emit('notification:unread-count', { count }); } } } async emitNotificationDeleted(tenantId, userId, notificationId) { const userKey = `${tenantId}:${userId}`; const socketIds = this.userSockets.get(userKey); if (socketIds) { for (const socketId of socketIds) { this.server .to(socketId) .emit('notification:deleted', { notificationId }); } } } getConnectedUsersCount() { return this.userSockets.size; } getTotalConnections() { return this.socketUsers.size; } isUserOnline(tenantId, userId) { const userKey = `${tenantId}:${userId}`; const sockets = this.userSockets.get(userKey); return sockets !== undefined && sockets.size > 0; } extractUserId(client) { return (client.handshake.auth?.userId || client.handshake.query?.userId || null); } extractTenantId(client) { return (client.handshake.auth?.tenantId || client.handshake.query?.tenantId || null); } }; exports.NotificationsGateway = NotificationsGateway; __decorate([ (0, websockets_1.WebSocketServer)(), __metadata("design:type", socket_io_1.Server) ], NotificationsGateway.prototype, "server", void 0); __decorate([ (0, websockets_1.SubscribeMessage)('notification:read'), __param(0, (0, websockets_1.ConnectedSocket)()), __param(1, (0, websockets_1.MessageBody)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object, Object]), __metadata("design:returntype", void 0) ], NotificationsGateway.prototype, "handleMarkAsRead", null); __decorate([ (0, websockets_1.SubscribeMessage)('notification:read-all'), __param(0, (0, websockets_1.ConnectedSocket)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", void 0) ], NotificationsGateway.prototype, "handleMarkAllAsRead", null); __decorate([ (0, websockets_1.SubscribeMessage)('notification:get-unread-count'), __param(0, (0, websockets_1.ConnectedSocket)()), __metadata("design:type", Function), __metadata("design:paramtypes", [Object]), __metadata("design:returntype", Object) ], NotificationsGateway.prototype, "handleGetUnreadCount", null); exports.NotificationsGateway = NotificationsGateway = NotificationsGateway_1 = __decorate([ (0, websockets_1.WebSocketGateway)({ namespace: '/notifications', cors: { origin: process.env.FRONTEND_URL || '*', credentials: true, }, }) ], NotificationsGateway); //# sourceMappingURL=notifications.gateway.js.map