/** * static/js/api.js * Thin fetch wrappers for all HTTP API endpoints. * Supports optional Bearer-token authentication. */ const BASE = ''; const TOKEN_KEY = 'local-mcp-token'; // Callback invoked when a 401 is received — set by app.js let _onUnauthorized = null; export function setUnauthorizedHandler(fn) { _onUnauthorized = fn; } export function getStoredToken() { return sessionStorage.getItem(TOKEN_KEY) || ''; } export function setStoredToken(token) { if (token) { sessionStorage.setItem(TOKEN_KEY, token); } else { sessionStorage.removeItem(TOKEN_KEY); } } async function request(method, path, body) { const opts = { method, headers: { 'Content-Type': 'application/json' }, }; const token = getStoredToken(); if (token) { opts.headers['Authorization'] = `Bearer ${token}`; } if (body !== undefined) opts.body = JSON.stringify(body); const res = await fetch(BASE + path, opts); if (res.status === 204) return null; if (res.status === 401) { if (_onUnauthorized) _onUnauthorized(); throw new Error('Unauthorized'); } const data = await res.json(); if (!res.ok) { const msg = data?.detail || `HTTP ${res.status}`; throw new Error(msg); } return data; } export const api = { // Health health: () => request('GET', '/healthz'), // Auth check (public — no token needed) authCheck: () => fetch('/auth-check').then(r => r.json()), // Status status: () => request('GET', '/api/status'), // Instructions listInstructions: (status='all') => request('GET', `/api/instructions?status=${status}`), createInstruction: (content) => request('POST', '/api/instructions', { content }), updateInstruction: (id, content) => request('PATCH', `/api/instructions/${id}`, { content }), deleteInstruction: (id) => request('DELETE', `/api/instructions/${id}`), clearConsumed: () => request('DELETE', '/api/instructions/consumed'), // Config getConfig: () => request('GET', '/api/config'), updateConfig: (patch) => request('PATCH', '/api/config', patch), };