import { t } from './i18n.js'; const BASE = '/api'; async function request(method, path, body = null, formEncoded = false) { const token = localStorage.getItem('token'); const headers = {}; if (token) headers['Authorization'] = `Bearer ${token}`; let bodyStr = null; if (body !== null) { if (formEncoded) { headers['Content-Type'] = 'application/x-www-form-urlencoded'; bodyStr = new URLSearchParams(body).toString(); } else { headers['Content-Type'] = 'application/json'; bodyStr = JSON.stringify(body); } } const res = await fetch(`${BASE}${path}`, { method, headers, body: bodyStr }); if (res.status === 401 && !path.startsWith('/auth/login')) { localStorage.removeItem('token'); localStorage.removeItem('user'); window.location.reload(); return null; } if (!res.ok) { const err = await res.json().catch(() => ({ detail: t('unknown_error') })); throw new Error(err.detail || `HTTP ${res.status}`); } if (res.status === 204) return null; return res.json(); } async function uploadRequest(path, formData) { const token = localStorage.getItem('token'); const headers = {}; if (token) headers['Authorization'] = `Bearer ${token}`; const res = await fetch(`${BASE}${path}`, { method: 'POST', headers, body: formData }); if (res.status === 401) { localStorage.removeItem('token'); localStorage.removeItem('user'); window.location.reload(); return null; } if (!res.ok) { const err = await res.json().catch(() => ({ detail: t('unknown_error') })); throw new Error(err.detail || `HTTP ${res.status}`); } if (res.status === 204) return null; return res.json(); } async function downloadRequest(path, fallbackName) { const token = localStorage.getItem('token'); const headers = {}; if (token) headers['Authorization'] = `Bearer ${token}`; const res = await fetch(`${BASE}${path}`, { method: 'GET', headers }); if (res.status === 401) { localStorage.removeItem('token'); localStorage.removeItem('user'); window.location.reload(); return null; } if (!res.ok) { const err = await res.json().catch(() => ({ detail: t('unknown_error') })); throw new Error(err.detail || `HTTP ${res.status}`); } // Derive filename from Content-Disposition if present. let filename = fallbackName || 'calendar.ics'; const cd = res.headers.get('Content-Disposition') || ''; const m = cd.match(/filename="?([^"]+)"?/); if (m) filename = m[1]; const blob = await res.blob(); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url); } export const api = { get: (path) => request('GET', path), post: (path, body) => request('POST', path, body), put: (path, body) => request('PUT', path, body), delete: (path) => request('DELETE', path), upload: (path, form) => uploadRequest(path, form), download: (path, name) => downloadRequest(path, name), login: (username, password, totp_code = null, remember_me = false) => request('POST', '/auth/login', { username, password, totp_code, remember_me }), setupRequired: () => request('GET', '/auth/setup-required'), setup: (data) => request('POST', '/auth/setup', data), };