/** * Helper functions for API calls * Handles both server-side and client-side URL construction * * IMPORTANT: We cannot import 'next/headers' at top level because it breaks client-side usage. * We use dynamic import only when needed on server-side. */ /** * Get the base URL for API calls * For server-side, we need absolute URLs * For client-side, we can use relative URLs */ export async function getApiBaseUrl(): Promise { // Server-side: need absolute URL if (typeof window === 'undefined') { try { // Dynamically import headers only when server-side (avoids client-side import error) const { headers } = await import('next/headers'); const headersList = await headers(); const host = headersList.get('host'); const protocol = headersList.get('x-forwarded-proto') || 'https'; if (host) { return `${protocol}://${host}`; } } catch (error) { // headers() might not be available in all contexts (e.g., during build) // Fall through to environment variables } // Fallback: try environment variables const spaceUrl = process.env.SPACE_URL || process.env.NEXT_PUBLIC_APP_URL || process.env.VERCEL_URL || process.env.HF_SPACE_URL; if (spaceUrl) { // Ensure it has protocol if (spaceUrl.startsWith('http://') || spaceUrl.startsWith('https://')) { // Remove trailing slash return spaceUrl.endsWith('/') ? spaceUrl.slice(0, -1) : spaceUrl; } return `https://${spaceUrl}`; } // Last resort: use relative URL (Next.js should handle this for same-origin) return ''; } // Client-side: use relative URL (empty string) return ''; } /** * Build proxy URL for Hugging Face requests * Automatically handles server-side vs client-side * Note: This is async because getApiBaseUrl() is async (needed for server-side) */ export async function buildProxyUrl(targetUrl: string): Promise { const apiBase = await getApiBaseUrl(); const encodedUrl = encodeURIComponent(targetUrl); return `${apiBase}/api/hf-proxy?url=${encodedUrl}`; }