import type { ZodType } from 'zod'; import { botStatsSchema, controlResponseSchema, timersSchema, type BotStats, type ControlResponse, type Timers, } from './contracts.js'; import { createDashboardRequest } from './request.js'; export class ApiError extends Error { constructor( message: string, readonly status: number, ) { super(message); this.name = 'ApiError'; } } interface ErrorPayload { error?: unknown; } async function parseResponse(response: Response, schema: ZodType): Promise { const payload: unknown = await response.json(); if (!response.ok) { const errorPayload = payload as ErrorPayload; const message = typeof errorPayload.error === 'string' ? errorPayload.error : `Request failed (${response.status})`; throw new ApiError(message, response.status); } return schema.parse(payload); } export interface DashboardApi { getStats(): Promise; getTimers(): Promise; setRunning(isRunning: boolean): Promise; } export function createDashboardApi(fetchImplementation?: typeof fetch): DashboardApi { const request = createDashboardRequest(fetchImplementation); return { async getStats() { return parseResponse(await request('/api/stats'), botStatsSchema); }, async getTimers() { return parseResponse(await request('/api/timers'), timersSchema); }, async setRunning(isRunning) { const endpoint = isRunning ? '/api/start' : '/api/stop'; return parseResponse(await request(endpoint, { method: 'POST' }), controlResponseSchema); }, }; } export const dashboardApi = createDashboardApi();