42 lines
1.5 KiB
TypeScript
42 lines
1.5 KiB
TypeScript
import policy from "./backend-url-policy.json";
|
|
|
|
export interface RuntimeConfig {
|
|
backendBaseUrl?: string;
|
|
}
|
|
|
|
declare global {
|
|
interface Window {
|
|
__THOTHII_CONFIG__?: RuntimeConfig;
|
|
}
|
|
}
|
|
|
|
export function resolveBackendUrl(config: RuntimeConfig | undefined): string {
|
|
const value = config?.backendBaseUrl ?? import.meta.env.VITE_BACKEND_URL ?? "";
|
|
if (policy.relativeBases.includes(value)) return value;
|
|
try {
|
|
if (!new RegExp(policy.absolutePattern).test(value)) throw new Error("syntax");
|
|
const authority = value.replace(/^https?:\/\//, "").split("/", 1)[0];
|
|
const suffix = authority.startsWith("[")
|
|
? authority.slice(authority.indexOf("]") + 1)
|
|
: authority.slice(authority.lastIndexOf(":"));
|
|
const port = suffix.startsWith(":") ? suffix.slice(1) : "";
|
|
if (port && (port.length > 5 || Number(port) > policy.maxPort)) throw new Error("port");
|
|
return value;
|
|
} catch {
|
|
// Fall through to the single actionable runtime error below.
|
|
}
|
|
throw new Error(
|
|
"Invalid BACKEND_BASE_URL: use empty/root, /api, or a valid http(s) base without credentials, query, or fragment",
|
|
);
|
|
}
|
|
|
|
export function joinBackendPath(base: string, path: string): string {
|
|
const normalizedBase = base === "/" ? "" : base.replace(/\/+$/, "");
|
|
const normalizedPath = path.replace(/^\/+/, "");
|
|
return `${normalizedBase}/${normalizedPath}`;
|
|
}
|
|
|
|
export const backendBaseUrl =
|
|
resolveBackendUrl(typeof window === "undefined" ? undefined : window.__THOTHII_CONFIG__) ||
|
|
"http://localhost:8787";
|