// SvxPortal — web front-end for SvxReflector // Copyright (C) 2026 SA7AUX (Björn) // SPDX-License-Identifier: AGPL-3.0-or-later // // This program is free software: you can redistribute it and/or modify it under // the terms of the GNU Affero General Public License as published by the Free // Software Foundation, either version 3 of the License, or (at your option) any // later version. See the LICENSE file for details. // api.js — shared HTTP helpers for every web (dmr-web, svx-web, svxlink-web). // Canonical copy: /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; })();