import { ApiResponse } from "@/types/api"; const BASE_URL = process.env.NEXT_PUBLIC_API_URL || "https://sid385-fill-the-frames.hf.space/api/v1"; export class ApiError extends Error { status: number; constructor(message: string, status: number) { super(message); this.name = "ApiError"; this.status = status; } } interface RequestOptions { params?: Record; headers?: Record; } async function request( path: string, options: RequestOptions & { method: string; body?: string | FormData } = { method: "GET" } ): Promise { const { params, ...fetchOptions } = options; let url = `${BASE_URL}${path}`; if (params) { const searchParams = new URLSearchParams(); for (const [key, value] of Object.entries(params)) { if (value !== undefined) { searchParams.append(key, String(value)); } } const qs = searchParams.toString(); if (qs) url += `?${qs}`; } const response = await fetch(url, fetchOptions); if (!response.ok) { throw new ApiError( `Request failed with status ${response.status}`, response.status ); } return response.json() as Promise; } export const api = { get: (path: string, options?: RequestOptions) => request(path, { ...options, method: "GET" }), post: (path: string, body?: unknown, options?: RequestOptions) => request(path, { ...options, method: "POST", headers: { "Content-Type": "application/json", ...options?.headers }, body: body ? JSON.stringify(body) : undefined, }), postFormData: (path: string, formData: FormData, options?: RequestOptions) => request(path, { ...options, method: "POST", body: formData }), delete: (path: string, options?: RequestOptions) => request(path, { ...options, method: "DELETE" }), }; export { BASE_URL }; export type { ApiResponse };