export const LOCAL_DEFAULT_BACKEND_URL = "http://localhost:8000" export type ConfiguredBackendUrl = | { kind: "local" } | { kind: "fixed"; url: string } | { kind: "same-origin" } export function configuredBackendUrl(): ConfiguredBackendUrl { const raw = process.env.NEXT_PUBLIC_BACKEND_URL if (raw === undefined || raw === "local") return { kind: "local" } if (raw === "" || raw === "same-origin") return { kind: "same-origin" } return { kind: "fixed", url: raw.replace(/\/$/, "") } } export function defaultDataSourceMode(): "mock" | "live" { if (!isMockDataSourceAvailable()) return "live" return process.env.NEXT_PUBLIC_DEFAULT_DATA_SOURCE === "live" ? "live" : "mock" } export function isMockDataSourceAvailable(): boolean { return process.env.NEXT_PUBLIC_ALLOW_MOCK_DATA !== "false" } export function isBackendUrlLocked(): boolean { const cfg = configuredBackendUrl() return cfg.kind === "same-origin" || cfg.kind === "fixed" } function isLoopbackHost(hostname: string): boolean { return hostname === "localhost" || hostname === "127.0.0.1" } /** Prefer same-origin when the UI is not on loopback — never point the browser at localhost. */ export function resolveStoredBackendUrl(stored: string | null): string { const cfg = configuredBackendUrl() if (cfg.kind === "fixed") return cfg.url if (cfg.kind === "same-origin") { if (typeof window !== "undefined") return window.location.origin return "" } if (typeof window !== "undefined" && !isLoopbackHost(window.location.hostname)) { return window.location.origin } const trimmed = stored?.trim().replace(/\/$/, "") if (trimmed && /^https?:\/\/(localhost|127\.0\.0\.1)(:\d+)?$/i.test(trimmed)) { if (typeof window !== "undefined" && !isLoopbackHost(window.location.hostname)) { return window.location.origin } } return trimmed || LOCAL_DEFAULT_BACKEND_URL }