bmc_hub/static/js/remote-api.js

46 lines
2.1 KiB
JavaScript
Raw Normal View History

export const base = '/api/v1/remote';
let csrf = '';
export async function api(path, data, method = data === undefined ? 'GET' : 'POST') {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 15000);
try {
const response = await fetch(base + path, {method, credentials: 'same-origin', cache: 'no-store', signal: controller.signal,
headers: data === undefined ? {} : {'Content-Type': 'application/json', 'X-Remote-CSRF': csrf},
body: data === undefined ? undefined : JSON.stringify(data)});
if (response.redirected || (response.ok && !response.headers.get('Content-Type')?.includes('application/json'))) {
throw new Error('Hub sendte ikke det forventede svar. Prøver igen…');
}
const result = await response.json();
if (!response.ok) {
const error = new Error(typeof result.detail === 'string' ? result.detail : 'Kontrollér oplysningerne og prøv igen');
error.status = response.status;
error.retry = Number(response.headers.get('Retry-After') || 0);
throw error;
}
return result;
} catch (error) {
if (error.status || error.message?.includes('forventede svar')) throw error;
throw new Error('Forbindelsen til Hub er afbrudt. Prøver igen…');
} finally { clearTimeout(timeout); }
}
export async function bootstrap() {
const result = await api('/bootstrap');
csrf = result.csrf;
return result;
}
export function element(tag, text, className) {
const node = document.createElement(tag);
node.textContent = text;
if (className) node.className = className;
return node;
}
// getRandomValues also works on HTTP local-network origins.
export function requestId() {
const bytes = crypto.getRandomValues(new Uint8Array(16));
bytes[6] = (bytes[6] & 0x0f) | 0x40;
bytes[8] = (bytes[8] & 0x3f) | 0x80;
const hex = Array.from(bytes, b => b.toString(16).padStart(2, '0')).join('');
return `${hex.slice(0,8)}-${hex.slice(8,12)}-${hex.slice(12,16)}-${hex.slice(16,20)}-${hex.slice(20)}`;
}