import * as z from "zod/mini"; const absoluteUrlSchema = z.string().check(z.trim(), z.url()); export const runtimeEndpointsSchema = z.strictObject({ apiUrl: z.optional(absoluteUrlSchema), coreUrl: z.optional(absoluteUrlSchema), realtimeUrl: z.optional(absoluteUrlSchema), }); export type RuntimeEndpoints = z.output; const parseAbsoluteUrl = (value: string | undefined): URL | null => { if (!value) { return null; } try { return new URL(value); } catch { return null; } }; const normalizeOrigin = (value: string | undefined): string | null => { const parsed = parseAbsoluteUrl(value); if (!parsed) { return null; } return parsed.origin; }; export const resolveCoreUrl = ( runtimeEndpoints: RuntimeEndpoints | undefined, ): URL | null => { return parseAbsoluteUrl(runtimeEndpoints?.coreUrl); }; export const resolveRealtimeUrl = ( runtimeEndpoints: RuntimeEndpoints | undefined, ): URL | null => { return parseAbsoluteUrl(runtimeEndpoints?.realtimeUrl); }; export const resolveApiBaseUrl = ( runtimeEndpoints: RuntimeEndpoints | undefined, ): URL | null => { const apiUrl = runtimeEndpoints?.apiUrl; const parsed = parseAbsoluteUrl(apiUrl); if (!parsed) { return null; } if (!parsed.pathname || parsed.pathname === "/") { return null; } if (!parsed.pathname.endsWith("/")) { parsed.pathname = `${parsed.pathname}/`; } return parsed; }; export const resolveTrpcBaseUrl = ( runtimeEndpoints: RuntimeEndpoints | undefined, ): URL | null => { const apiBaseUrl = resolveApiBaseUrl(runtimeEndpoints); if (!apiBaseUrl) { return null; } const normalizedApiPath = apiBaseUrl.pathname.endsWith("/") ? apiBaseUrl.pathname.slice(0, -1) : apiBaseUrl.pathname; if (!normalizedApiPath.endsWith("/v1")) { return null; } const trpcPath = normalizedApiPath.slice(0, -"/v1".length) || "/"; return new URL(trpcPath, `${normalizeOrigin(apiBaseUrl.toString()) ?? ""}/`); };