/** * API fetch wrapper for Scenar Creator. */ const API = { async post(url, body, isJson = true) { const opts = { method: 'POST' }; if (isJson) { opts.headers = { 'Content-Type': 'application/json' }; opts.body = JSON.stringify(body); } else { opts.body = body; // FormData } const res = await fetch(url, opts); return res; }, async postJson(url, body) { const res = await this.post(url, body, true); if (!res.ok) { const err = await res.json().catch(() => ({ detail: res.statusText })); throw new Error(err.detail || 'API error'); } return res.json(); }, async postBlob(url, body) { const res = await this.post(url, body, true); if (!res.ok) { const err = await res.json().catch(() => ({ detail: res.statusText })); throw new Error(err.detail || 'API error'); } return res.blob(); }, async postFormData(url, formData) { const res = await this.post(url, formData, false); if (!res.ok) { const err = await res.json().catch(() => ({ detail: res.statusText })); throw new Error(err.detail || 'API error'); } return res.json(); }, async get(url) { const res = await fetch(url); if (!res.ok) throw new Error(res.statusText); return res.json(); }, downloadBlob(blob, filename) { const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } };