// LightSync frontend — Phase 1 shell // WebSocket stub + device list loader // Phase 2 expands audio, transport, and WS protocol const WS_URL = `ws://${location.host}/ws`; class LightSyncClient { constructor() { this.ws = null; this.reconnectDelay = 2000; this._reconnectTimer = null; } connect() { if (this._reconnectTimer) { clearTimeout(this._reconnectTimer); this._reconnectTimer = null; } this.ws = new WebSocket(WS_URL); this.ws.onopen = () => { document.getElementById("status-dot").className = "status-dot connected"; document.getElementById("status-text").textContent = "CONNECTED"; }; this.ws.onclose = () => { document.getElementById("status-dot").className = "status-dot"; document.getElementById("status-text").textContent = "OFFLINE"; this._reconnectTimer = setTimeout(() => this.connect(), this.reconnectDelay); }; this.ws.onerror = () => { document.getElementById("status-dot").className = "status-dot error"; }; this.ws.onmessage = (event) => { const msg = JSON.parse(event.data); this.handleMessage(msg); }; } handleMessage(msg) { // Phase 2 will dispatch on msg.type console.debug("[ws]", msg); } send(msg) { if (this.ws?.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify(msg)); } } } const client = new LightSyncClient(); client.connect(); // Load device list on startup async function loadDevices() { try { const res = await fetch("/api/devices"); if (!res.ok) throw new Error(`HTTP ${res.status}`); const devices = await res.json(); const list = document.getElementById("device-list"); if (devices.length === 0) { list.innerHTML = 'no devices registered'; return; } list.innerHTML = devices.map(d => `