import Cookies from "js-cookie"; // .env'deki NEXT_PUBLIC_API_BASE kullanılır (örn: http://127.0.0.1:8080). /v1 prefix'i burada eklenir. const getBaseUrl = () => { const base = process.env.NEXT_PUBLIC_API_BASE || "http://localhost:8080"; const normalized = base.replace(/\/$/, ""); return `${normalized}/v1`; }; const BASE_URL = getBaseUrl(); interface FetchOptions extends RequestInit { headers?: Record; } interface AuthResponse { access_token: string; refresh_token: string; } export const fetchClient = async (endpoint: string, options: FetchOptions = {}) => { const getAccessToken = () => Cookies.get("access_token"); const getRefreshToken = () => Cookies.get("refresh_token"); const setTokens = (access: string, refresh: string) => { Cookies.set("access_token", access, { secure: true, sameSite: 'strict' }); Cookies.set("refresh_token", refresh, { secure: true, sameSite: 'strict' }); // Dispatch event for other tabs or parts of the app to know (optional) if (typeof window !== "undefined") { window.dispatchEvent(new Event("storage")); } }; const clearTokens = () => { Cookies.remove("access_token"); Cookies.remove("refresh_token"); if (typeof window !== "undefined") { try { localStorage.removeItem("user"); } catch (e) { } window.location.href = "/login"; } }; const headers: Record = { ...options.headers, }; if (!(options.body instanceof FormData)) { headers["Content-Type"] = "application/json"; } const token = getAccessToken(); if (token) { headers["Authorization"] = `Bearer ${token}`; } const config: RequestInit = { ...options, headers, }; let response = await fetch(`${BASE_URL}${endpoint}`, config); // Handle 401 - Token Expired if (response.status === 401) { const refreshToken = getRefreshToken(); if (!refreshToken) { clearTokens(); throw new Error("Session expired"); } try { // Attempt to refresh token const refreshResponse = await fetch(`${BASE_URL}/auth/refresh`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ refresh_token: refreshToken }), }); if (!refreshResponse.ok) { throw new Error("Refresh failed"); } const data: AuthResponse = await refreshResponse.json(); setTokens(data.access_token, data.refresh_token); // Retry original request with new token headers["Authorization"] = `Bearer ${data.access_token}`; response = await fetch(`${BASE_URL}${endpoint}`, { ...options, headers }); } catch (error) { clearTokens(); throw new Error("Session expired. Please login again."); } } // Handle other errors if (!response.ok) { const errorData = await response.json().catch(() => ({})); const errorMessage = errorData.error || errorData.message || response.statusText; throw new Error(errorMessage); } // Return json if content type is json, otherwise text or null const contentType = response.headers.get("content-type"); if (contentType && contentType.includes("application/json")) { return response.json(); } return response.text(); };