import { configuredBackendUrl } from "@/lib/backend-url" import { getToken, isAuthEnabled, redirectToPortalLogin, redirectToPortalLoginInteractive, } from "@/lib/auth" export class ApiClientError extends Error { constructor( message: string, public readonly status: number, public readonly payload?: unknown, ) { super(message) this.name = "ApiClientError" } } function trimBaseUrl(baseUrl: string): string { return baseUrl.replace(/\/$/, "") } function resolveRequestUrl(baseUrl: string, path: string): string { if (path.startsWith("/") && configuredBackendUrl().kind === "same-origin") { return path } return trimBaseUrl(baseUrl) + path } export async function requestJson( baseUrl: string, path: string, init?: RequestInit, ): Promise { const hasBody = init?.body != null const headers = new Headers(init?.headers) if (hasBody && !headers.has("Content-Type")) { headers.set("Content-Type", "application/json") } const token = typeof window !== "undefined" ? getToken() : null if (token && !headers.has("Authorization")) { headers.set("Authorization", `Bearer ${token}`) } const res = await fetch(resolveRequestUrl(baseUrl, path), { ...init, headers, }) if (res.status === 401 && typeof window !== "undefined" && isAuthEnabled()) { const ok = redirectToPortalLogin() if (!ok) redirectToPortalLoginInteractive() throw new ApiClientError("Unauthorized", 401) } if (res.status === 204) return undefined as T const payload = await res.json().catch(() => undefined) if (!res.ok) { const msg = typeof payload === "object" && payload !== null && "error" in payload && typeof (payload as { error?: unknown }).error === "string" ? (payload as { error: string }).error : res.statusText throw new ApiClientError(msg, res.status, payload) } return payload as T }