// JSON fetch that fails with a sentence instead of a parser error. // // nginx serves the dashboard with `try_files $uri $uri/ /index.html`, so ANY // path it does not have a proxy rule for answers 200 text/html with the SPA // shell. A caller that does `res.ok && res.json()` on such a path gets // `SyntaxError: Unexpected token '<', "(url: string, init?: RequestInit): Promise { const res = await fetch(url, init); const ct = res.headers.get('content-type') || ''; if (!res.ok) { throw new Error(`${url} → HTTP ${res.status}`); } if (!ct.includes('application/json')) { // The SPA fallback is the overwhelmingly likely cause; say so. throw new Error( `${url} → ${res.status} ${ct || 'no content-type'} (not JSON — the route is ` + `missing and nginx served the dashboard shell instead)` ); } return (await res.json()) as T; }