export interface LogEntry { sequence: number timestamp_ms: number text: string } export interface TimelineBucket { start_ms: number count: number } export interface Stats { log_count: number first_sequence: number | null last_sequence: number | null first_timestamp_ms: number | null last_timestamp_ms: number | null } async function getJson(path: string): Promise { const res = await fetch(path) if (!res.ok) { throw new Error(`${path} failed: ${res.status}`) } return res.json() as Promise } export function fetchLogs(params: { sinceSequence?: number startMs?: number endMs?: number limit?: number }): Promise { const search = new URLSearchParams() if (params.sinceSequence !== undefined) search.set('since_sequence', String(params.sinceSequence)) if (params.startMs !== undefined) search.set('start_ms', String(params.startMs)) if (params.endMs !== undefined) search.set('end_ms', String(params.endMs)) if (params.limit !== undefined) search.set('limit', String(params.limit)) return getJson(`/api/logs?${search.toString()}`) } export function fetchTimeline(params: { startMs?: number endMs?: number bucketMs?: number }): Promise { const search = new URLSearchParams() if (params.startMs !== undefined) search.set('start_ms', String(params.startMs)) if (params.endMs !== undefined) search.set('end_ms', String(params.endMs)) if (params.bucketMs !== undefined) search.set('bucket_ms', String(params.bucketMs)) return getJson(`/api/timeline?${search.toString()}`) } export function fetchStats(): Promise { return getJson('/api/stats') }