// Échappe les valeurs serveur avant injection dans innerHTML function esc(s) { if (s == null) return '—'; return String(s) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } const API = (() => { const BASE = ''; // même origine, proxy Nginx vers le serveur Go async function get(path) { const r = await fetch(BASE + path); if (!r.ok) throw new Error(`GET ${path}: ${r.status}`); return r.json(); } async function put(path, body) { const r = await fetch(BASE + path, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); if (!r.ok) throw new Error(`PUT ${path}: ${r.status}`); } async function del(path) { const r = await fetch(BASE + path, { method: 'DELETE' }); if (!r.ok) throw new Error(`DELETE ${path}: ${r.status}`); } async function postForm(path, formData) { const r = await fetch(BASE + path, { method: 'POST', body: formData }); if (!r.ok) throw new Error(`POST ${path}: ${r.status}`); } return { getAgents: () => get('/api/agents'), getAgentHistory: (id, from, to) => get(`/api/agents/${id}/history?from=${from}&to=${to}`), getAgentConfig: (id) => get(`/api/agents/${id}/config`), putAgentConfig: (id, cfg) => put(`/api/agents/${id}/config`, cfg), getServerConfig: () => get('/api/config'), putServerConfig: (cfg) => put('/api/config', cfg), uploadIcon: (id, file) => { const fd = new FormData(); fd.append('icon', file); return postForm(`/api/agents/${id}/icon`, fd); }, deleteAgent: (id) => del(`/api/agents/${id}`), iconUrl: (id) => `/api/agents/${id}/icon`, }; })();