Spaces:
Paused
Paused
| /** | |
| * 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<typeof setInterval> | 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<VizPollResponse>( | |
| `/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; | |
| } | |