import { loadRoleDefaults } from "@capakraken/api"; import { eventBus, permissionAudience, roleAudience, userAudience } from "@capakraken/api/sse"; import { startReminderScheduler } from "@capakraken/api/lib/reminder-scheduler"; import { prisma } from "@capakraken/db"; import { resolvePermissions, SSE_EVENT_TYPES, SystemRole, type PermissionOverrides } from "@capakraken/shared"; import { auth } from "~/server/auth.js"; // Start the reminder scheduler (idempotent — only starts once) startReminderScheduler(); export const dynamic = "force-dynamic"; export const runtime = "nodejs"; export async function GET() { const session = await auth(); if (!session?.user) { return new Response("Unauthorized", { status: 401 }); } const sessionUser = session.user as typeof session.user & { id?: string }; if (!sessionUser.id) { return new Response("Unauthorized", { status: 401 }); } const dbUser = await prisma.user.findUnique({ where: { id: sessionUser.id }, select: { id: true, systemRole: true, permissionOverrides: true, }, }); if (!dbUser) { return new Response("Unauthorized", { status: 401 }); } const roleDefaults = await loadRoleDefaults(); const permissions = resolvePermissions( dbUser.systemRole as SystemRole, dbUser.permissionOverrides as PermissionOverrides | null, roleDefaults, ); const audiences = new Set([ userAudience(dbUser.id), roleAudience(dbUser.systemRole), ]); for (const permission of permissions) { audiences.add(permissionAudience(permission)); } const encoder = new TextEncoder(); const stream = new ReadableStream({ start(controller) { // Send initial connection confirmation controller.enqueue( encoder.encode(`data: ${JSON.stringify({ type: SSE_EVENT_TYPES.PING, timestamp: new Date().toISOString() })}\n\n`), ); // Subscribe to event bus const unsubscribe = eventBus.subscribe( (event) => { try { controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}\n\n`)); } catch { // Client disconnected } }, { audiences, includeUnscoped: false, }, ); // Heartbeat every 30 seconds const heartbeat = setInterval(() => { try { controller.enqueue( encoder.encode(`data: ${JSON.stringify({ type: SSE_EVENT_TYPES.PING, timestamp: new Date().toISOString() })}\n\n`), ); } catch { clearInterval(heartbeat); unsubscribe(); } }, 30000); // Cleanup on close return () => { clearInterval(heartbeat); unsubscribe(); }; }, }); return new Response(stream, { headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache, no-transform", Connection: "keep-alive", "X-Accel-Buffering": "no", }, }); }