"use client"; import { useEffect, useRef, useCallback, useState } from "react"; export interface SSEEvent { type: string; data: Record; } interface UseSSEOptions { url: string; onEvent?: (event: SSEEvent) => void; enabled?: boolean; } export function useSSE({ url, onEvent, enabled = true }: UseSSEOptions) { const [isConnected, setIsConnected] = useState(false); const [lastEvent, setLastEvent] = useState(null); const eventSourceRef = useRef(null); const onEventRef = useRef(onEvent); // Keep callback ref updated onEventRef.current = onEvent; const connect = useCallback(() => { if (eventSourceRef.current) { eventSourceRef.current.close(); } const es = new EventSource(url); eventSourceRef.current = es; es.onopen = () => setIsConnected(true); es.onerror = () => { setIsConnected(false); // Auto-reconnect is built into EventSource }; // Listen for all event types const eventTypes = ["heartbeat", "task", "stats", "online", "offline", "connected", "registered"]; eventTypes.forEach((type) => { es.addEventListener(type, (e: MessageEvent) => { try { const data = JSON.parse(e.data); const event: SSEEvent = { type, data }; setLastEvent(event); onEventRef.current?.(event); } catch { // skip malformed events } }); }); return es; }, [url]); useEffect(() => { if (!enabled) return; const es = connect(); return () => { es.close(); setIsConnected(false); }; }, [connect, enabled]); return { isConnected, lastEvent }; }