59 lines
1.9 KiB
JavaScript
Executable file
59 lines
1.9 KiB
JavaScript
Executable file
// Request wrapper — all calls go through the Express proxy at /syncro-api/
|
|
// The Authorization header is injected server-side; never sent from the browser.
|
|
// Session cookie is attached automatically by the browser (same-origin, httpOnly).
|
|
|
|
export async function apiRequest(method, path, body = null, params = {}, { base = '/syncro-api' } = {}) {
|
|
const url = new URL(base + path, window.location.origin);
|
|
|
|
for (const [k, v] of Object.entries(params)) {
|
|
if (v !== null && v !== undefined && v !== '') {
|
|
url.searchParams.set(k, v);
|
|
}
|
|
}
|
|
|
|
const options = {
|
|
method,
|
|
credentials: 'same-origin',
|
|
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
|
|
};
|
|
|
|
if (body && (method === 'PUT' || method === 'POST')) {
|
|
options.body = JSON.stringify(body);
|
|
}
|
|
|
|
let response;
|
|
try {
|
|
response = await fetch(url.toString(), options);
|
|
} catch (err) {
|
|
throw new Error('Network error — check connection. ' + err.message);
|
|
}
|
|
|
|
// Session expired — redirect to login only if the 401 came from our own auth
|
|
// wall (code: SESSION_EXPIRED), not from an upstream Syncro API auth error.
|
|
if (response.status === 401) {
|
|
let body = {};
|
|
try { body = await response.clone().json(); } catch { /* ignore */ }
|
|
if (body.code === 'SESSION_EXPIRED') {
|
|
window.location.href = '/login.html?expired=1';
|
|
throw new Error('Session expired.');
|
|
}
|
|
throw new Error('Upstream authorization error (HTTP 401).');
|
|
}
|
|
|
|
// Syncro returns 204 No Content on successful PUT
|
|
if (response.status === 204) return {};
|
|
|
|
let data;
|
|
try {
|
|
data = await response.json();
|
|
} catch {
|
|
throw new Error(`Non-JSON response (HTTP ${response.status})`);
|
|
}
|
|
|
|
if (!response.ok) {
|
|
const msg = data?.error || data?.message || data?.errors?.join?.(', ') || `HTTP ${response.status}`;
|
|
throw new Error(msg);
|
|
}
|
|
|
|
return data;
|
|
}
|