Files
Mark-VIII/payload/user/remote_access/pager-webui/www/js/api.js
T
bzuccaroandCursor 7d48b7ad06 fix: harden UI actions and daemon calls for reliable control (v1.3.2)
Retry and serialize pineapd/hak5 calls, queue virtual-pager keys, and grey out buttons until the pager finishes. Deploy now installs python3-light after factory firmware. Bump version to 1.3.2.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-20 15:49:10 -05:00

64 lines
2.1 KiB
JavaScript

'use strict';
const PagerAPI = (() => {
let apiBase = '';
let on401 = null;
const GET_TIMEOUT_MS = 20000;
const WRITE_TIMEOUT_MS = 45000;
async function request(method, path, body, attempt) {
attempt = attempt || 0;
const opts = { method, headers: {}, credentials: 'include' };
if (body !== undefined) {
opts.headers['Content-Type'] = 'application/json';
opts.body = JSON.stringify(body);
}
const timeoutMs = method === 'GET' ? GET_TIMEOUT_MS : WRITE_TIMEOUT_MS;
const ctl = new AbortController();
const timer = setTimeout(() => ctl.abort(), timeoutMs);
opts.signal = ctl.signal;
let res;
try {
res = await fetch(apiBase + path, opts);
} catch (e) {
clearTimeout(timer);
if (method === 'GET' && attempt < 1) {
return request(method, path, body, attempt + 1);
}
const error = new Error((e && e.name === 'AbortError') ? 'Request timed out' : (e && e.message) || 'Network error');
error.status = 0;
throw error;
}
clearTimeout(timer);
if (res.status === 401) {
if (on401) on401();
throw new Error('unauthorized');
}
const ct = res.headers.get('Content-Type') || '';
let data;
if (ct.indexOf('json') !== -1) {
try { data = await res.json(); }
catch (e) { data = null; }
} else {
data = await res.text();
}
if (!res.ok) {
const detail = data && typeof data.detail === 'string' ? data.detail : '';
const message = (data && data.error ? data.error : ('HTTP ' + res.status)) +
(detail ? ': ' + detail : '');
const error = new Error(message);
error.status = res.status;
error.data = data;
throw error;
}
return { status: res.status, data };
}
return {
setBase: (b) => { apiBase = b; },
on401: (fn) => { on401 = fn; },
get: (p) => request('GET', p),
post: (p, b) => request('POST', p, b === undefined ? {} : b),
del: (p, b) => request('DELETE', p, b === undefined ? {} : b),
login: async (username, password) => request('POST', '/api/login', { username, password })
};
})();