const IMAGE_PROXY_PATH = "/api/image-proxy"; type ImageProxyFormat = "webp" | "avif" | "jpeg" | "png"; export type ImageProxyOptions = { width?: number; quality?: number; format?: ImageProxyFormat; }; function clamp(value: number, min: number, max: number): number { return Math.max(min, Math.min(max, value)); } function normalizeWidth(width?: number): number | undefined { if (!Number.isFinite(width) || !width) return undefined; return clamp(Math.round(width), 64, 4096); } function normalizeQuality(quality?: number): number | undefined { if (!Number.isFinite(quality) || !quality) return undefined; return clamp(Math.round(quality), 40, 100); } function isAbsoluteHttpUrl(url: string): boolean { return /^https?:\/\//i.test(url); } function isBypassUrl(url: string): boolean { return ( !url || url.startsWith("data:") || url.startsWith("blob:") || url.startsWith(IMAGE_PROXY_PATH) || !isAbsoluteHttpUrl(url) ); } export function buildImageProxyUrl(url: string, options: ImageProxyOptions = {}): string { const source = String(url || "").trim(); if (isBypassUrl(source)) { return source; } const width = normalizeWidth(options.width); const quality = normalizeQuality(options.quality); const format = options.format; const params = new URLSearchParams(); params.set("url", source); if (width) params.set("w", String(width)); if (quality) params.set("q", String(quality)); if (format) params.set("f", format); return `${IMAGE_PROXY_PATH}?${params.toString()}`; }