"use client"; import { useEffect, useRef, useState } from "react"; type UseEventSourceOptions = { onMessage?: (data: unknown) => void; onError?: (event: Event) => void; enabled?: boolean; }; /** * Subscribe to a Server-Sent Events (SSE) endpoint. * Reconnects automatically on connection loss. */ export function useEventSource( url: string | null, options?: UseEventSourceOptions, ) { const { onMessage, onError, enabled = true } = options ?? {}; const [data, setData] = useState(null); const [connected, setConnected] = useState(false); const onMessageRef = useRef(onMessage); const onErrorRef = useRef(onError); onMessageRef.current = onMessage; onErrorRef.current = onError; useEffect(() => { if (!url || !enabled) return; const endpoint: string = url; let es: EventSource | null = null; let reconnectTimer: ReturnType; function connect() { es = new EventSource(endpoint); es.onopen = () => setConnected(true); es.onmessage = (event) => { try { const parsed = JSON.parse(event.data) as T; setData(parsed); onMessageRef.current?.(parsed); } catch { // ignore malformed messages } }; es.onerror = (event) => { es?.close(); setConnected(false); onErrorRef.current?.(event); reconnectTimer = setTimeout(connect, 3000); }; } connect(); return () => { clearTimeout(reconnectTimer); es?.close(); setConnected(false); }; }, [url, enabled]); return { data, connected }; }