From 687764102ae09b316ba42c7b362745dc651b3e85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20=22Thebys=22=20Biheler?= Date: Tue, 1 Sep 2026 21:34:39 +0200 Subject: [PATCH 1/2] Fix space status widget SpaceAPI 0.13 returns state as an object ({"open": bool, "lastchange": ts}), not a boolean, so `data.state` was always truthy and the widget reported the space as open regardless of its real state. Read `data.state.open`. Fetch /api/spaceapi same-origin through the nginx proxy, and drop the hand-written Cache-Control/Pragma request headers: they make the request non-simple, and HA answers the resulting CORS preflight with 403 because its allowed-header list is hardcoded. The ?t= cache buster already does the job. Co-Authored-By: Claude Opus 5 --- js/main.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/js/main.js b/js/main.js index ee24319..7d7c764 100644 --- a/js/main.js +++ b/js/main.js @@ -483,17 +483,15 @@ document.addEventListener('DOMContentLoaded', function () { }; const lang = isCzech ? 'czech' : 'english'; - // Note on how to obtain the following JSON file, CURL example: - // curl -k -H https://ha.base48.cz/api/spaceapi -o api/base_status.json + // nginx proxies /api/spaceapi to Home Assistant, so this is same-origin. + // curl https://base48.cz/api/spaceapi // Try to fetch the base status (with cache busting) const cacheBuster = Date.now(); - fetch(`https://ha.base48.cz/api/spaceapi?t=${cacheBuster}`, { - cache: 'no-cache', - headers: { - 'Cache-Control': 'no-cache, no-store, must-revalidate', - 'Pragma': 'no-cache' - } + // No custom headers: they would trigger a CORS preflight, which HA + // answers with 403. The ?t= above is enough to bust the cache. + fetch(`/api/spaceapi?t=${cacheBuster}`, { + cache: 'no-cache' }) .then(response => { if (!response.ok) { @@ -503,8 +501,8 @@ document.addEventListener('DOMContentLoaded', function () { }) .then(data => { // Check if the base is open based on the state field - // New API format: true/false - const isOpen = data.state; + // SpaceAPI 0.13: state is {"open": bool, "lastchange": ts} + const isOpen = data.state.open; statusElement.textContent = isOpen ? texts[lang].open : texts[lang].closed; statusElement.className = `base-status ${isOpen ? 'open' : 'closed'}`; From 27bfbb01d5de4e1d40a8f3a1f6adb2a06626fc6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Thebys=20Biheler?= Date: Sat, 12 Sep 2026 22:14:55 +0200 Subject: [PATCH 2/2] Read the status from the static SpaceAPI feed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /api/spaceapi proxies to Home Assistant, which serves SpaceAPI 0.13 and fails validation against the current 15.json on api_compatibility. That field is a hardcoded constant in the integration (SPACEAPI_VERSION), so no amount of YAML reaches it. /api/base_status_spaceapi.json is regenerated every minute from the same Home Assistant sensor, validates clean against 15.json, and is already what the external directories read — mapall.space, HackerspacesGlobe, MapsOfMaking and MakersMap, ~2800 requests a day against 3 for the proxy. Both carry state.open, so this is a URL change and nothing else. It also drops the request-time dependency on Home Assistant: the file keeps serving the last known state if HA or the tunnel is down, where the proxy would fail the request. HA's own endpoint reports the space as open whenever the sensor is unavailable, which is the wrong direction for a door status. --- js/main.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/js/main.js b/js/main.js index 7d7c764..69406d8 100644 --- a/js/main.js +++ b/js/main.js @@ -483,14 +483,14 @@ document.addEventListener('DOMContentLoaded', function () { }; const lang = isCzech ? 'czech' : 'english'; - // nginx proxies /api/spaceapi to Home Assistant, so this is same-origin. - // curl https://base48.cz/api/spaceapi + // Same-origin SpaceAPI 15 feed, regenerated every minute from the same + // Home Assistant sensor. curl https://base48.cz/api/base_status_spaceapi.json // Try to fetch the base status (with cache busting) const cacheBuster = Date.now(); - // No custom headers: they would trigger a CORS preflight, which HA - // answers with 403. The ?t= above is enough to bust the cache. - fetch(`/api/spaceapi?t=${cacheBuster}`, { + // No custom headers: they would make this non-simple and trigger a + // CORS preflight. The ?t= above is enough to bust the cache. + fetch(`/api/base_status_spaceapi.json?t=${cacheBuster}`, { cache: 'no-cache' }) .then(response => { @@ -501,7 +501,7 @@ document.addEventListener('DOMContentLoaded', function () { }) .then(data => { // Check if the base is open based on the state field - // SpaceAPI 0.13: state is {"open": bool, "lastchange": ts} + // SpaceAPI: state is {"open": bool, "lastchange": ts} const isOpen = data.state.open; statusElement.textContent = isOpen ? texts[lang].open : texts[lang].closed;