// Thin fetch wrapper. Owner token in localStorage.void_token. On 401 we // prompt for a token via a modal in modal-root. The wrapper is intentionally // minimal — no retries, no auto-refresh; the owner-only auth model doesn't // need them. import { el, mount, clear } from './dom.js'; const TOKEN_KEY = 'void_token'; function token() { return localStorage.getItem(TOKEN_KEY) || ''; } async function call(method, path, body) { const headers = { 'Authorization': 'Bearer ' + token() }; if (body !== undefined) headers['Content-Type'] = 'application/json'; const res = await fetch(path, { method, headers, body: body === undefined ? undefined : JSON.stringify(body) }); if (res.status === 401) { await promptForToken(); return call(method, path, body); } if (res.status === 204) return null; const ct = res.headers.get('content-type') || ''; const data = ct.includes('application/json') ? await res.json() : await res.text(); if (!res.ok) { const err = new Error(data?.error?.message || res.statusText); err.status = res.status; err.body = data; throw err; } return data; } function promptForToken() { return new Promise((resolve) => { const root = document.getElementById('modal-root'); const input = el('input', { type: 'password', style: { width: '100%' }, autofocus: true }); const save = () => { const v = input.value.trim(); if (!v) return; localStorage.setItem(TOKEN_KEY, v); clear(root); resolve(); }; input.addEventListener('keydown', (e) => { if (e.key === 'Enter') save(); }); mount(root, el('div', { class: 'modal-backdrop' }, el('div', { class: 'modal' }, el('h2', {}, 'Owner Token'), el('p', { class: 'muted' }, 'Paste the OWNER_TOKEN configured for the server. It will be stored in localStorage on this device only.' ), input, el('div', { class: 'actions' }, el('button', { class: 'primary', onclick: save }, 'Save') ) ) ) ); input.focus(); }); } export const api = { get: (p) => call('GET', p), post: (p, body) => call('POST', p, body ?? {}), patch: (p, body) => call('PATCH', p, body ?? {}), del: (p) => call('DELETE', p), setToken: (v) => localStorage.setItem(TOKEN_KEY, v), hasToken: () => !!token() };