import { Signal } from "@preact/signals"; function getCookie(name: string): string | null { let cookieValue = null; if (document.cookie && document.cookie !== "") { const cookies = document.cookie.split(";"); for (let i = 0; i < cookies.length; i++) { const cookie = cookies[i].trim(); if (cookie.substring(0, name.length + 1) === name + "=") { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || "http://localhost:8000"; interface RequestOptions extends RequestInit { needsCsrf?: boolean; isFormData?: boolean; } async function apiClient( endpoint: string, options: RequestOptions = {}, isLoggedInSignal?: Signal ): Promise { const url = `${API_BASE_URL}${endpoint}`; const { needsCsrf = true, isFormData = false, ...fetchOptions } = options; const headers: HeadersInit = { ...(isFormData ? {} : { "Content-Type": "application/json" }), Accept: "application/json", ...fetchOptions.headers, }; const method = options.method?.toUpperCase() || "GET"; if (needsCsrf && ["POST", "PUT", "PATCH", "DELETE"].includes(method)) { const csrfToken = getCookie("csrftoken"); if (csrfToken) { (headers as Record)["X-CSRFToken"] = csrfToken; } else { console.warn("CSRF token not found in cookies."); await fetchCsrfToken(); // Implement this function if needed const newCsrfToken = getCookie("csrftoken"); if (newCsrfToken) { (headers as Record)["X-CSRFToken"] = newCsrfToken; } else { throw new Error("CSRF token is missing"); } } } const config: RequestInit = { ...fetchOptions, headers, credentials: "include", }; try { const response = await fetch(url, config); if (response.status === 401 || response.status === 403) { console.error("Authentication error:", response.status); if (isLoggedInSignal) { isLoggedInSignal.value = false; localStorage.setItem("loggedIn", "false"); } throw new Error(`Authentication failed: ${response.status}`); } if (!response.ok) { const errorData = await response.json().catch(() => ({})); console.error("API Error:", response.status, errorData); throw new Error(`HTTP error ${response.status}: ${JSON.stringify(errorData) || response.statusText}`); } if (response.status === 204) { return {} as T; } return (await response.json()) as T; } catch (error) { console.error("API Client Fetch Error:", error); throw error; } } async function fetchCsrfToken() { try { await apiClient("/api/get-csrf/", { method: "GET", needsCsrf: false }); } catch (error) { console.error("Failed to fetch CSRF token:", error); } } export default apiClient;