export const API_BASE = process.env.NEXT_PUBLIC_WATCH_FINISHED_API || "/api"; function buildUrl(path: string, params?: any) { const url = new URL(path, API_BASE); if (params && typeof params === "object") { Object.entries(params).forEach(([k, v]) => { if (v !== undefined && v !== null) url.searchParams.append(k, String(v)); }); } return url.toString(); } export async function get(path: string, params?: any): Promise { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 second timeout try { const res = await fetch(buildUrl(path, params), { method: "GET", credentials: "same-origin", headers: { Accept: "application/json" }, signal: controller.signal }); clearTimeout(timeoutId); if (!res.ok) throw new Error(await res.text()); return res.json(); } catch (error) { clearTimeout(timeoutId); if (error instanceof Error && error.name === "AbortError") { throw new Error("Request timeout"); } throw error; } } export async function post(path: string, data?: any): Promise { // const controller = new AbortController(); // const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 second timeout try { const res = await fetch(buildUrl(path), { method: "POST", credentials: "same-origin", headers: { "Content-Type": "application/json", Accept: "application/json" }, body: data ? JSON.stringify(data) : undefined // signal: controller.signal }); // clearTimeout(timeoutId); if (!res.ok) throw new Error(await res.text()); return res.json(); } catch (error) { // clearTimeout(timeoutId); // if (error.name === "AbortError") { // throw new Error("Request timeout"); // } throw error; } } export async function put(path: string, data?: any): Promise { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 second timeout try { const res = await fetch(buildUrl(path), { method: "PUT", credentials: "same-origin", headers: { "Content-Type": "application/json", Accept: "application/json" }, body: data ? JSON.stringify(data) : undefined, signal: controller.signal }); clearTimeout(timeoutId); if (!res.ok) throw new Error(await res.text()); return res.json(); } catch (error) { clearTimeout(timeoutId); if (error instanceof Error && error.name === "AbortError") { throw new Error("Request timeout"); } throw error; } } export async function del(path: string, params?: any): Promise { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 second timeout try { const res = await fetch(buildUrl(path, params), { method: "DELETE", credentials: "same-origin", headers: { Accept: "application/json" }, signal: controller.signal }); clearTimeout(timeoutId); if (!res.ok) throw new Error(await res.text()); // Handle empty response body (common for DELETE operations) const contentLength = res.headers.get("content-length"); const contentType = res.headers.get("content-type"); if ( contentLength === "0" || res.status === 204 || !contentType?.includes("application/json") ) { return {} as T; } const text = await res.text(); if (!text.trim()) { return {} as T; } return JSON.parse(text); } catch (error) { clearTimeout(timeoutId); if (error instanceof Error && error.name === "AbortError") { throw new Error("Request timeout"); } throw error; } }