/** * GET /api/chat/sse — Server-Sent Events stream for real-time chat messages */ import { subscribe, authorConnected, authorDisconnected, isAuthorOnline, userConnected, userDisconnected } from "#server/service/chat" import { getCurrentUser } from "#server/utils/context" export default defineEventHandler(async (event) => { const res = event.node.res const user = await getCurrentUser(event) const isAuthor = user?.role === 'admin' const userId = user?.id // Register connection BEFORE sending connected event (so isAuthorOnline is accurate) if (isAuthor) authorConnected() if (userId) userConnected(String(userId)) res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache, no-transform', 'Connection': 'keep-alive', 'X-Accel-Buffering': 'no', }) // Send actual global author online status (not just the connecting user's role) res.write(`data: ${JSON.stringify({ type: 'connected', authorOnline: isAuthorOnline() })}\n\n`) const unsub = subscribe((msg) => { // msg is either a ChatMessage object or a status-string from broadcastStatus if (typeof msg === 'string') { // Status broadcast: send directly (already JSON: {"type":"authorOnline","data":true}) res.write(`data: ${msg}\n\n`) } else { res.write(`data: ${JSON.stringify({ type: 'message', data: msg })}\n\n`) } }) const heartbeat = setInterval(() => { res.write(': heartbeat\n\n') }, 30_000) event.node.req.on('close', () => { unsub() clearInterval(heartbeat) if (isAuthor) authorDisconnected() if (userId) userDisconnected(String(userId)) }) await new Promise((resolve) => { event.node.req.on('close', () => resolve()) }) })