/* api.js — Camada de acesso à API do dashboard. Todas as requisições mutantes (POST) enviam o cabeçalho X-AI-Dashboard, exigido pelo backend (proteção CSRF junto do cookie SameSite=strict). */ const API = (() => { const CSRF_HEADER = "X-AI-Dashboard"; async function request(method, path, body) { const opts = { method, headers: { "Accept": "application/json" }, credentials: "same-origin", }; if (method !== "GET") { opts.headers[CSRF_HEADER] = "1"; } if (body !== undefined) { opts.headers["Content-Type"] = "application/json"; opts.body = JSON.stringify(body); } const resp = await fetch(path, opts); let data = null; const text = await resp.text(); if (text) { try { data = JSON.parse(text); } catch { data = { detail: text }; } } if (resp.status === 401) { // Sessão expirada / não autenticado: deixa o app tratar. const err = new Error((data && data.detail) || "Não autenticado."); err.status = 401; throw err; } if (!resp.ok) { const err = new Error((data && data.detail) || `Erro HTTP ${resp.status}`); err.status = resp.status; err.data = data; throw err; } return data; } return { get: (p) => request("GET", p), post: (p, b) => request("POST", p, b), put: (p, b) => request("PUT", p, b), del: (p) => request("DELETE", p), // Auth me: () => request("GET", "/api/auth/me"), login: (username, password) => request("POST", "/api/auth/login", { username, password }), changePassword: (current_password, new_password) => request("POST", "/api/auth/change-password", { current_password, new_password }), logout: () => request("POST", "/api/auth/logout"), // Páginas overview: () => request("GET", "/api/overview"), services: () => request("GET", "/api/services"), serviceControl: (name, action) => request("POST", `/api/services/${name}/${action}`), serviceLogs: (name, lines) => request("GET", `/api/services/${name}/logs?lines=${lines || 200}`), llmChatToken: () => request("POST", "/api/llm-ui/token"), remote: () => request("GET", "/api/remote"), vpsStats: () => request("GET", "/api/remote/vps"), docs: () => request("GET", "/api/docs"), doc: (name) => request("GET", `/api/docs/${encodeURIComponent(name)}`), adminDisk: () => request("GET", "/api/admin/disk"), adminHealth: () => request("GET", "/api/admin/health"), adminVersion: () => request("GET", "/api/admin/version"), adminUpdate: () => request("POST", "/api/admin/update"), adminReboot: () => request("POST", "/api/admin/reboot"), ramMonitorStatus: () => request("GET", "/api/admin/ram-monitor"), ramMonitorStart: () => request("POST", "/api/admin/ram-monitor/start"), ramMonitorStop: () => request("POST", "/api/admin/ram-monitor/stop"), ramMonitorInterval: (minutes) => request("POST", "/api/admin/ram-monitor/interval", { minutes }), adminStatus: () => request("GET", "/api/admin/services/status"), // Perfis profiles: () => request("GET", "/api/profiles"), profile: (id) => request("GET", `/api/profiles/${encodeURIComponent(id)}`), profileEnums: () => request("GET", "/api/profiles/meta/enums"), profileAudit: (limit) => request("GET", `/api/profiles/meta/audit?limit=${limit || 50}`), profileAutoPrompt: (body) => request("POST", "/api/profiles/auto/prompt", body), profileCreate: (body) => request("POST", "/api/profiles", body), profileUpdate: (id, body) => request("PUT", `/api/profiles/${encodeURIComponent(id)}`, body), profileDelete: (id, force) => request("DELETE", `/api/profiles/${encodeURIComponent(id)}?force=${force ? "true" : "false"}`), profileDuplicate: (id, newName) => request("POST", `/api/profiles/${encodeURIComponent(id)}/duplicate`, { newName }), profileToggle: (id, enabled) => request("POST", `/api/profiles/${encodeURIComponent(id)}/toggle`, { enabled }), profileServiceAction: (id, action) => request("POST", `/api/profiles/${encodeURIComponent(id)}/service/${encodeURIComponent(action)}`), profileActivate: (id) => request("POST", `/api/profiles/${encodeURIComponent(id)}/activate`), profileDeactivate: (id) => request("POST", `/api/profiles/${encodeURIComponent(id)}/deactivate`), profilesActive: () => request("GET", "/api/profiles/meta/active"), profileModelStatus: (id) => request("GET", `/api/profiles/${encodeURIComponent(id)}/model/status`), profileModelDownload: (id) => request("POST", `/api/profiles/${encodeURIComponent(id)}/model/download`), profileModelDelete: (id) => request("DELETE", `/api/profiles/${encodeURIComponent(id)}/model`), profileMmprojStatus: (id) => request("GET", `/api/profiles/${encodeURIComponent(id)}/mmproj/status`), profileMmprojDownload: (id) => request("POST", `/api/profiles/${encodeURIComponent(id)}/mmproj/download`), profileMmprojDelete: (id) => request("DELETE", `/api/profiles/${encodeURIComponent(id)}/mmproj`), // Benchmarks benchmarks: () => request("GET", "/api/benchmarks"), benchmarkTypes: () => request("GET", "/api/benchmarks/types"), benchmark: (id) => request("GET", `/api/benchmarks/${encodeURIComponent(id)}`), benchmarkCreate: (profileId, typeId) => request("POST", "/api/benchmarks", { profileId, typeId }), benchmarkCancel: (id) => request("POST", `/api/benchmarks/${encodeURIComponent(id)}/cancel`), benchmarkDelete: (id) => request("DELETE", `/api/benchmarks/${encodeURIComponent(id)}`), benchmarkReportUrl: (id) => `/api/benchmarks/${encodeURIComponent(id)}/report`, // Relatórios (comparação de benchmarks) reports: () => request("GET", "/api/reports"), report: (id) => request("GET", `/api/reports/${encodeURIComponent(id)}`), reportPreview: (jobIds) => request("POST", "/api/reports/preview", { jobIds }), reportCreate: (jobIds, title) => request("POST", "/api/reports", { jobIds, title }), reportDelete: (id) => request("DELETE", `/api/reports/${encodeURIComponent(id)}`), reportPdfUrl: (id) => `/api/reports/${encodeURIComponent(id)}/pdf`, // Usuarios (admin only) users: () => request("GET", "/api/users"), user: (id) => request("GET", `/api/users/${encodeURIComponent(id)}`), userCreate: (body) => request("POST", "/api/users", body), userUpdate: (id, body) => request("PUT", `/api/users/${encodeURIComponent(id)}`, body), userDeactivate: (id) => request("DELETE", `/api/users/${encodeURIComponent(id)}`), userRotateKey: (id) => request("POST", `/api/users/${encodeURIComponent(id)}/rotate-key`), userInvite: (id, baseUrl) => request("POST", `/api/users/${encodeURIComponent(id)}/invite`, { base_url: baseUrl }), accessLog: (params) => request("GET", `/api/access-log?${new URLSearchParams(params)}`), accessLogSummary: () => request("GET", "/api/access-log/summary"), }; })();