🐛 fix: response body double-read regression + updater JSON safety

- hosters.js apiGet(): fixed regression from v2.3.8 where res.json()
  consumed the body, making res.text() return empty on parse failure.
  Now reads as text first, then parses JSON (matching VOE fix pattern).
- updater.js fetchJson(): same fix — read text first, parse JSON,
  show actual server response in error message on failure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Administrator 2026-03-21 15:35:18 +01:00
parent 0fd8dd0634
commit 9c04426950
2 changed files with 8 additions and 3 deletions

View File

@ -281,11 +281,11 @@ async function apiGet(url, signal) {
signal: controller.signal, signal: controller.signal,
redirect: 'follow' redirect: 'follow'
}); });
const text = await res.text();
let data; let data;
try { try {
data = await res.json(); data = JSON.parse(text);
} catch { } catch {
const text = await res.text().catch(() => '');
throw new Error(`API-Antwort war kein JSON (HTTP ${res.status}): ${(text || '').slice(0, 200)}`); throw new Error(`API-Antwort war kein JSON (HTTP ${res.status}): ${(text || '').slice(0, 200)}`);
} }

View File

@ -65,7 +65,12 @@ async function fetchJson(url, signal) {
signal: controller.signal, signal: controller.signal,
redirect: 'follow' redirect: 'follow'
}); });
return await res.json(); const text = await res.text();
try {
return JSON.parse(text);
} catch {
throw new Error(`Update-Server Antwort war kein JSON (HTTP ${res.status}): ${text.slice(0, 200)}`);
}
} finally { } finally {
clearTimeout(timeout); clearTimeout(timeout);
if (signal) signal.removeEventListener('abort', onAbort); if (signal) signal.removeEventListener('abort', onAbort);