File size: 1,867 Bytes
5e77d76 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | /**
* JSON-safe fetch for HomePilot Settings API routes.
*
* Fetches a HomePilot API route and returns its parsed JSON, failing with an
* actionable message instead of a raw ``Unexpected token '<', "<!doctype "…``
* when a deployment serves the SPA ``index.html`` fallback where JSON was
* expected.
*
* On ``homepilot.ruslanmv.com`` the frontend is served same-origin with the
* backend, so a Settings API path that isn't forwarded to FastAPI (or a
* relative request produced by an empty backend URL) resolves to the SPA
* document. Parsing that as JSON is exactly what surfaced the confusing
* ``Unexpected token '<'`` error in Settings → Providers. Checking the
* content type first turns that into a clear deployment-routing message.
*/
export async function fetchApiJson(url: string): Promise<any> {
const res = await fetch(url);
const ctype = res.headers.get("content-type") || "";
if (!ctype.includes("application/json")) {
let path = url;
try {
const origin = typeof window !== "undefined" ? window.location.origin : "http://localhost";
path = new URL(url, origin).pathname;
} catch {
/* keep the raw url */
}
throw new Error(
`The HomePilot providers API is unavailable on this deployment ` +
`(HTTP ${res.status}). The request for ${path} returned ` +
`${ctype || "an unknown content type"} instead of JSON — check that ` +
`this route is forwarded to the backend and not the SPA fallback.`,
);
}
if (!res.ok) {
// A proper JSON error body — surface its message rather than a bare status.
let detail = `HTTP ${res.status}`;
try {
const body = await res.json();
detail = body?.message || body?.detail || detail;
} catch {
/* fall back to the HTTP status */
}
throw new Error(detail);
}
return res.json();
}
|