Stripped from the internal repo: per-box deploy trees, Go services (nodelist/astmeta/proxy/svxdr), deploy/sync scripts and all secrets. Config templates for nginx, PHP-FPM, Redis and tmpfiles live in install/ with CHANGEME placeholders. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
54 lines
2.5 KiB
JavaScript
54 lines
2.5 KiB
JavaScript
// api.js — shared HTTP helpers for every web (dmr-web, svx-web, svxlink-web).
|
|
// Canonical copy: callmgr2/www-mumien/lib/api.js; other repos carry a COPY.
|
|
//
|
|
// apiFetch(url, {method, body, form, csrf, headers, quiet}) → {ok, status, json}
|
|
// apiGet(url, opts) → json | null GET, cache: no-store
|
|
// apiJson(url, body, opts) → json | null POST application/json (always POST, CSRF from window._csrfToken)
|
|
// apiForm(url, fields, opts) → json | null POST x-www-form-urlencoded
|
|
//
|
|
// Every call is same-origin, never cached, and returns null (or json:null)
|
|
// when the response is not JSON, so callers test `j && j.ok`. A response
|
|
// carrying persist_error (a save that reached Redis but not callmgr.json) is
|
|
// surfaced with an alert unless opts.quiet — no save path can hide it.
|
|
(function () {
|
|
'use strict';
|
|
|
|
async function apiFetch(url, opts) {
|
|
opts = opts || {};
|
|
const init = {
|
|
method: opts.method || (opts.body !== undefined ? 'POST' : 'GET'),
|
|
cache: 'no-store',
|
|
credentials: opts.credentials || 'same-origin',
|
|
headers: Object.assign({}, opts.headers || {}),
|
|
};
|
|
if (opts.body !== undefined) {
|
|
if (opts.form) {
|
|
init.headers['Content-Type'] = 'application/x-www-form-urlencoded';
|
|
init.body = new URLSearchParams(opts.body);
|
|
} else {
|
|
init.headers['Content-Type'] = 'application/json';
|
|
init.body = JSON.stringify(opts.body);
|
|
}
|
|
}
|
|
const csrf = opts.csrf !== undefined ? opts.csrf : (window._csrfToken || '');
|
|
if (csrf) init.headers['X-CSRF-Token'] = csrf;
|
|
let r;
|
|
try { r = await fetch(url, init); }
|
|
catch (e) { return { ok: false, status: 0, json: null, error: String(e) }; }
|
|
const json = await r.json().catch(function () { return null; });
|
|
if (json && json.ok && json.persist_error && !opts.quiet) {
|
|
alert('Saved to Redis but NOT persisted to callmgr.json: ' + json.persist_error +
|
|
'\n\nThe change reverts on the next restart.');
|
|
}
|
|
return { ok: r.ok, status: r.status, json: json };
|
|
}
|
|
async function apiGet(url, opts) { return (await apiFetch(url, opts)).json; }
|
|
async function apiJson(url, body, opts) { return (await apiFetch(url, Object.assign({ method: 'POST', body: body }, opts || {}))).json; }
|
|
async function apiForm(url, fields, opts) { return (await apiFetch(url, Object.assign({ body: fields, form: true }, opts || {}))).json; }
|
|
|
|
window.apiFetch = apiFetch;
|
|
window.apiGet = apiGet;
|
|
window.apiJson = apiJson;
|
|
window.apiForm = apiForm;
|
|
})();
|