/** * ───────────────────────────────────────────── * SPB Drive — Personal Cloud Drive * ───────────────────────────────────────────── * Author : Simon-Pierre Boucher * Contact : contact@spboucher.ai * File : src/web/assets/js/api.js * Purpose : JSON API client — CSRF header, error normalization * License : MIT © Simon-Pierre Boucher * ───────────────────────────────────────────── */ /** Perform an API call; throws Error with .code on failure. */ export async function api(path, { method = 'GET', body, raw = false } = {}) { const headers = {}; if (method !== 'GET' && method !== 'HEAD') headers['x-spbdrive-csrf'] = '1'; if (body !== undefined) headers['content-type'] = 'application/json'; const res = await fetch(path, { method, headers, body: body !== undefined ? JSON.stringify(body) : undefined, credentials: 'same-origin', }); if (res.status === 401) { location.href = `/login?next=${encodeURIComponent(location.pathname)}`; throw new Error('unauthorized'); } if (raw) return res; const data = res.headers.get('content-type')?.includes('json') ? await res.json() : null; if (!res.ok) { const err = new Error(data?.error?.message ?? `HTTP ${res.status}`); err.code = data?.error?.code ?? 'http_error'; err.status = res.status; throw err; } return data; } export const getJSON = (path) => api(path); export const post = (path, body) => api(path, { method: 'POST', body }); export const patch = (path, body) => api(path, { method: 'PATCH', body }); export const del = (path) => api(path, { method: 'DELETE' });