/** * Polling client for the visualization endpoint. * * Polls GET /api/v1/query/{queryId}/visualization every 2 seconds. * Stops polling on: result received, error, or 180s timeout. */ import api from "./client"; import type { VizPollResponse } from "../types"; const POLL_INTERVAL_MS = 2000; const POLL_TIMEOUT_MS = 180000; export function pollVisualization( queryId: string, onResult: (response: VizPollResponse) => void, onError: (err: string) => void, ): () => void { const startTime = Date.now(); let intervalId: ReturnType | null = null; function stop() { if (intervalId !== null) { clearInterval(intervalId); intervalId = null; } } intervalId = setInterval(async () => { if (Date.now() - startTime > POLL_TIMEOUT_MS) { stop(); onError("Visualization timed out after 3 minutes"); return; } try { const { data } = await api.get( `/query/${queryId}/visualization`, ); if (data.status === "complete") { stop(); onResult(data); } else if (data.status === "error") { stop(); onError(data.error ?? "Visualization generation failed"); } // "pending" → keep polling } catch (err: unknown) { // 404 means viz was never requested for this id — stop silently const status = (err as { response?: { status?: number } })?.response?.status; if (status === 404) { stop(); } else { stop(); onError("Failed to fetch visualization status"); } } }, POLL_INTERVAL_MS); return stop; }