import type { ApiErrorBody, ApiErrorCode } from '@akrababul/shared'; export class ApiError extends Error { constructor(public readonly code: ApiErrorCode, message: string, public readonly status: number, public readonly details?: Record) { super(message); this.name = 'ApiError'; } } async function call(method: string, path: string, body?: unknown, headers: Record = {}): Promise { let res: Response; try { const isForm = body instanceof FormData; // FormData'da content-type elle verilmez; tarayıcı multipart sınırını kendisi ekler. const init: RequestInit = { method, credentials: 'same-origin', headers: { ...(body !== undefined && !isForm ? { 'content-type': 'application/json' } : {}), ...headers } }; if (body !== undefined) init.body = isForm ? body : JSON.stringify(body); res = await fetch(path, init); } catch { throw new ApiError('INTERNAL', 'Sunucuya ulaşılamadı. İnternet bağlantınızı kontrol edip tekrar deneyin.', 0); } if (res.status === 204) return undefined as T; const text = await res.text(); let data: unknown = null; try { data = text ? JSON.parse(text) : null; } catch { /* json değil */ } if (!res.ok) { const e = (data ?? {}) as Partial; // Emniyet ağı: sayfa denetimi atlanmış olsa bile rızasız kullanıcı onay ekranına gider. if (e.code === 'CONSENT_REQUIRED' && !location.pathname.startsWith('/onay')) { location.href = '/onay.html?next=' + encodeURIComponent(location.pathname); } throw new ApiError(e.code ?? 'INTERNAL', e.message ?? `Sunucu hatası (${res.status})`, res.status, e.details); } return data as T; } export const apiGet = (path: string) => call('GET', path); export const apiPost = (path: string, body: unknown, headers?: Record) => call('POST', path, body, headers); export const apiPatch = (path: string, body: unknown) => call('PATCH', path, body); export const apiDelete = (path: string, body?: unknown) => call('DELETE', path, body); export const apiUpload = (path: string, fd: FormData) => call('POST', path, fd);