export function normalizeApiBase(value: string): string { const base = value.replace(/\/+$/, '') if (/\/api$/.test(base)) return `${base}/v1` return /\/api\/v1$/.test(base) ? base : `${base}/api/v1` } export function resolveApiBase(): string { const value = typeof window === 'undefined' ? (process.env.API_INTERNAL_URL || 'http://localhost:4000/api/v1') : (process.env.NEXT_PUBLIC_API_URL || '/dashboard/api/v1') return normalizeApiBase(value) } export const API_BASE = resolveApiBase() export const EMPLOYEE_PROFILE_KEY = 'employee_profile' export async function apiFetch(path: string, options?: RequestInit): Promise { const isFormData = typeof FormData !== 'undefined' && options?.body instanceof FormData const headers: Record = { ...(options?.headers as Record ?? {}), } if (!isFormData) { headers['Content-Type'] = 'application/json' } const res = await fetch(`${resolveApiBase()}${path}`, { ...options, headers, credentials: 'include', }) let json: any try { json = await res.json() } catch { throw new Error(`HTTP ${res.status}: ${res.statusText}`) } if (!res.ok) { const err = new Error(json?.message ?? json?.error ?? `Request failed with status ${res.status}`) as any err.code = json?.error err.statusCode = res.status throw err } return (json?.data ?? json) as T } export async function apiFetchServer(path: string, token: string, options?: RequestInit): Promise { const isFormData = typeof FormData !== 'undefined' && options?.body instanceof FormData const res = await fetch(`${resolveApiBase()}${path}`, { ...options, headers: { ...(isFormData ? {} : { 'Content-Type': 'application/json' }), 'Authorization': `Bearer ${token}`, ...(options?.headers as Record ?? {}), }, cache: 'no-store', }) let json: any try { json = await res.json() } catch { throw new Error(`HTTP ${res.status}: ${res.statusText}`) } if (!res.ok) { const err = new Error(json?.message ?? `Request failed with status ${res.status}`) as any err.statusCode = res.status throw err } return (json?.data ?? json) as T }