import { resolveEndpoints } from '@/config/endpoints' import { useSessionState } from '@/stores/session-state' let ws: WebSocket | null = null let reconnectTimer: ReturnType | null = null let reconnectDelay = 1000 const MAX_RECONNECT_DELAY = 15000 function connect() { const store = useSessionState() // Connect to terminal server (4103) — same base as terminal WS const url = resolveEndpoints().terminal console.log('[SessionStateWS] Connecting to', url) ws = new WebSocket(url) ws.onopen = () => { console.log('[SessionStateWS] Connected') store.setConnected(true) reconnectDelay = 1000 } ws.onmessage = (event) => { try { const msg = JSON.parse(event.data) if (msg.type === 'session-state-snapshot' || msg.type === 'session-state-patch' || msg.type === 'terminal-registry-change') { store.handleMessage(msg) } // Ignore other message types (terminal output, legacy broadcasts, etc.) } catch { // Non-JSON or malformed — ignore } } ws.onclose = () => { console.log('[SessionStateWS] Disconnected, reconnecting in', reconnectDelay, 'ms') store.setConnected(false) ws = null scheduleReconnect() } ws.onerror = () => { // onclose will fire after onerror } } function scheduleReconnect() { if (reconnectTimer) clearTimeout(reconnectTimer) reconnectTimer = setTimeout(() => { reconnectTimer = null connect() // Exponential backoff reconnectDelay = Math.min(reconnectDelay * 1.5, MAX_RECONNECT_DELAY) }, reconnectDelay) } /** Initialize the session state WebSocket. Call once on app mount. */ export function initSessionStateWS() { if (ws) return // Already connected connect() } /** Disconnect and stop reconnecting. */ export function destroySessionStateWS() { if (reconnectTimer) { clearTimeout(reconnectTimer) reconnectTimer = null } if (ws) { ws.onclose = null // Prevent reconnect ws.close() ws = null } useSessionState().setConnected(false) }