spb/countryatlas
Public
TypeScript 57%
Python 38.6%
JavaScript 3.6%
CSS 0.6%
1'use client';2import { ClientApiError } from './client-api';3import type { MultiSeriesResponse } from './types';45/**6 * Browser-side helpers for the platform widgets (download builder estimate, API explorer). Same-origin `/api/v1`.7 */8export async function getJson<T>(path: string, signal?: AbortSignal): Promise<T> {9 const res = await fetch(`/api/v1${path}`, { headers: { accept: 'application/json' }, signal });10 if (!res.ok) throw new ClientApiError(res.status, `API ${res.status}`);11 return (await res.json()) as T;12}1314/** Raw request for the API explorer: returns status, elapsed ms, byte size and the parsed/pretty body. */15export async function rawRequest(path: string, signal?: AbortSignal): Promise<{ status: number; ms: number; bytes: number; text: string; json: unknown | null; contentType: string | null }> {16 const t0 = performance.now();17 const res = await fetch(path, { headers: { accept: 'application/json' }, signal });18 const text = await res.text();19 const ms = Math.round(performance.now() - t0);20 let json: unknown | null = null;21 try {22 json = JSON.parse(text);23 } catch {24 json = null;25 }26 return { status: res.status, ms, bytes: new TextEncoder().encode(text).length, text, json, contentType: res.headers.get('content-type') };27}2829export const clientPlatform = {30 /** Series bundle for row estimates (≤ 20 countries × 12 indicators). */31 seriesBundle: (countries: string[], indicators: string[], q: { from?: number | null; to?: number | null } = {}, signal?: AbortSignal) => {32 const p = new URLSearchParams({ country: countries.join(','), indicator: indicators.join(',') });33 if (q.from != null) p.set('from', String(q.from));34 if (q.to != null) p.set('to', String(q.to));35 return getJson<MultiSeriesResponse>(`/series?${p.toString()}`, signal);36 },37};38