'use client'; import { ClientApiError } from './client-api'; import type { MultiSeriesResponse } from './types'; /** * Browser-side helpers for the platform widgets (download builder estimate, API explorer). Same-origin `/api/v1`. */ export async function getJson(path: string, signal?: AbortSignal): Promise { const res = await fetch(`/api/v1${path}`, { headers: { accept: 'application/json' }, signal }); if (!res.ok) throw new ClientApiError(res.status, `API ${res.status}`); return (await res.json()) as T; } /** Raw request for the API explorer: returns status, elapsed ms, byte size and the parsed/pretty body. */ export async function rawRequest(path: string, signal?: AbortSignal): Promise<{ status: number; ms: number; bytes: number; text: string; json: unknown | null; contentType: string | null }> { const t0 = performance.now(); const res = await fetch(path, { headers: { accept: 'application/json' }, signal }); const text = await res.text(); const ms = Math.round(performance.now() - t0); let json: unknown | null = null; try { json = JSON.parse(text); } catch { json = null; } return { status: res.status, ms, bytes: new TextEncoder().encode(text).length, text, json, contentType: res.headers.get('content-type') }; } export const clientPlatform = { /** Series bundle for row estimates (≤ 20 countries × 12 indicators). */ seriesBundle: (countries: string[], indicators: string[], q: { from?: number | null; to?: number | null } = {}, signal?: AbortSignal) => { const p = new URLSearchParams({ country: countries.join(','), indicator: indicators.join(',') }); if (q.from != null) p.set('from', String(q.from)); if (q.to != null) p.set('to', String(q.to)); return getJson(`/series?${p.toString()}`, signal); }, };