import { Body, Controller, Post, Request, Route, Security } from "tsoa"; import { sendWebSocket } from "../services/webSocket"; import { RequestWithUser } from "../middlewares/user"; @Route("/api/v1/org/through-socket") export class SocketController extends Controller { @Post("notify") async notify( @Body() payload: { message: string; userId?: string | string[]; roles?: string | string[]; error?: boolean; }, ) { sendWebSocket( "socket-notification", { success: !payload.error, message: payload.message }, { roles: payload.roles || [], userId: payload.userId || [], }, ); } @Post("notify-from-token") @Security("bearerAuth") async notifyFromToken( @Body() payload: { message: string; targetUserId?: string | string[]; roles?: string | string[]; error?: boolean; }, @Request() req: RequestWithUser, ) { const toArray = (value?: string | string[]) => { if (Array.isArray(value)) return value.filter(Boolean); if (typeof value === "string" && value.trim()) return [value]; return [] as string[]; }; const targetUserIds = toArray(payload.targetUserId); const targetRoles = toArray(payload.roles); // If caller provides explicit user targets, do not combine with role targeting. // This prevents accidental broad notifications when roles include common roles. const recipients = targetUserIds.length > 0 ? { userId: targetUserIds, roles: [] as string[] } : { userId: [req.user.sub], roles: targetRoles }; sendWebSocket( "socket-notification", { success: !payload.error, message: payload.message }, recipients, ); } }