const BASE = ""; export async function api(path, opts = {}) { const res = await fetch(BASE + path, opts); if (!res.ok) throw new Error(`${res.status} ${await res.text()}`); const ct = res.headers.get("content-type") || ""; return ct.includes("json") ? res.json() : res; } export const listAssets = () => api("/api/assets"); export const listOperators = () => api("/api/operators"); export const listJobs = () => api("/api/jobs"); export const deleteAsset = (id) => api(`/api/assets/${id}`, { method: "DELETE" }); export async function uploadFile(file) { const form = new FormData(); form.append("file", file, file.name || "pasted.png"); return api("/api/assets", { method: "POST", body: form }); } export const runJob = (operator, asset_id, params) => api("/api/jobs", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ operator, asset_id, params }), }); export const cancelJob = (id) => api(`/api/jobs/${id}/cancel`, { method: "POST" }); export const retryJob = (id) => api(`/api/jobs/${id}/retry`, { method: "POST" }); export const deleteJob = (id) => api(`/api/jobs/${id}`, { method: "DELETE" }); export const getSettings = () => api("/api/settings"); export const putSettings = (updates) => api("/api/settings", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(updates), }); export function connectWS(onMessage) { const proto = location.protocol === "https:" ? "wss" : "ws"; const ws = new WebSocket(`${proto}://${location.host}/ws`); ws.onmessage = (e) => onMessage(JSON.parse(e.data)); const ping = setInterval(() => ws.readyState === 1 && ws.send("ping"), 20000); ws.onclose = () => { clearInterval(ping); setTimeout(() => connectWS(onMessage), 2000); }; return ws; } export const assetFileURL = (id, member) => `/api/assets/${id}/file` + (member ? `?member=${encodeURIComponent(member)}` : "");