diff --git a/apps/web/src/api/client.ts b/apps/web/src/api/client.ts index 986bed6..af72d79 100644 --- a/apps/web/src/api/client.ts +++ b/apps/web/src/api/client.ts @@ -123,13 +123,11 @@ export const api = { create: (sessionId: string, body: PaneCreateRequest) => request(`/api/sessions/${sessionId}/panes`, { method: 'POST', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }), update: (id: string, body: PaneUpdateRequest) => request(`/api/panes/${id}`, { method: 'PATCH', - headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }), remove: (id: string) => diff --git a/apps/web/src/hooks/useSidebar.ts b/apps/web/src/hooks/useSidebar.ts index 7bbe20d..7d6e976 100644 --- a/apps/web/src/hooks/useSidebar.ts +++ b/apps/web/src/hooks/useSidebar.ts @@ -13,7 +13,7 @@ let sharedError: string | null = null; let sharedLoading: boolean = true; let initialized = false; let fetchInFlight: Promise | null = null; -let activeSessionProjectId: string | null = null; +let activeSession: { session_id: string; project_id: string } | null = null; const subscribers = new Set<() => void>(); function notify(): void { @@ -150,7 +150,7 @@ sessionEvents.subscribe((event) => { // session_loaded updates activeSessionProjectId regardless of whether // sharedData is populated yet — notify so subscribers can re-read. if (event.type === 'session_loaded') { - activeSessionProjectId = event.project_id; + activeSession = { session_id: event.session_id, project_id: event.project_id }; notify(); return; } @@ -165,11 +165,11 @@ interface Snapshot { data: SidebarResponse | null; error: string | null; loading: boolean; - activeSessionProjectId: string | null; + activeSession: { session_id: string; project_id: string } | null; } function snapshot(): Snapshot { - return { data: sharedData, error: sharedError, loading: sharedLoading, activeSessionProjectId }; + return { data: sharedData, error: sharedError, loading: sharedLoading, activeSession }; } export function useSidebar(): { @@ -177,7 +177,7 @@ export function useSidebar(): { error: string | null; loading: boolean; retry: () => void; - activeSessionProjectId: string | null; + activeSession: { session_id: string; project_id: string } | null; } { const [state, setState] = useState(snapshot); @@ -199,5 +199,5 @@ export function useSidebar(): { void load(); }; - return { data: state.data, error: state.error, loading: state.loading, retry, activeSessionProjectId: state.activeSessionProjectId }; + return { data: state.data, error: state.error, loading: state.loading, retry, activeSession: state.activeSession }; } diff --git a/apps/web/src/hooks/useUserEvents.ts b/apps/web/src/hooks/useUserEvents.ts index dce1c99..982626f 100644 --- a/apps/web/src/hooks/useUserEvents.ts +++ b/apps/web/src/hooks/useUserEvents.ts @@ -23,11 +23,10 @@ export function useUserEvents(): void { ws.onmessage = (ev) => { try { - const frame = JSON.parse(ev.data); - // The server emits frames whose `type` matches SessionEvent union members - // (project_created, project_deleted, session_created, session_deleted, session_updated). - // Pass through onto the bus. - sessionEvents.emit(frame); + const parsed: unknown = JSON.parse(ev.data); + if (parsed && typeof (parsed as { type?: unknown }).type === 'string') { + sessionEvents.emit(parsed as import('./sessionEvents').SessionEvent); + } } catch (err) { console.warn('useUserEvents: failed to parse frame', err); } @@ -35,10 +34,9 @@ export function useUserEvents(): void { ws.onclose = () => { if (unmounted) return; - reconnectTimer = setTimeout(() => { - reconnectDelay = Math.min(reconnectDelay * 2, RECONNECT_MAX_MS); - connect(); - }, reconnectDelay); + const delay = reconnectDelay; + reconnectDelay = Math.min(reconnectDelay * 2, RECONNECT_MAX_MS); + reconnectTimer = setTimeout(connect, delay); }; ws.onerror = () => {