import { writable } from 'svelte/store' import { sseUrl } from '$lib/config' export interface OikosEvent { id: number ts: string type: string entity_id?: string | null severity: 'info' | 'warning' | 'critical' source: string data?: unknown correlation_id?: string | null } const MAX_BUFFERED = 200 export const liveEvents = writable([]) let source: EventSource | null = null let subscriberCount = 0 async function connect() { if (source) return // The browser's EventSource sends Last-event-ID automatically on reconnect. // sseUrl is async so the OIDC access token is refreshed if expired. source = new EventSource(await sseUrl('/api/v1/events/stream')) source.onmessage = (ev) => { try { const parsed: OikosEvent = JSON.parse(ev.data) liveEvents.update((events) => [parsed, ...events].slice(0, MAX_BUFFERED)) } catch { // skip malformed } } source.onerror = () => { // browser will auto-reconnect; nothing to surface here } } function disconnect() { source?.close() source = null } // Reference-counted: the stream stays open as long as at least one page subscribes. export function subscribeEvents(): () => void { subscriberCount++ if (subscriberCount === 1) connect() return () => { subscriberCount-- if (subscriberCount === 0) disconnect() } }