import { cookies } from 'next/headers'; import { redirect } from 'next/navigation'; /** * Gets the base URL for server API requests with proper fallbacks */ function getBaseUrl() { // Check if we're running in Tor mode const torMode = process.env.NEXT_PUBLIC_TOR_MODE === 'true'; // First check for the specific server API URL environment variable if (process.env.SERVER_API_URL) { console.log(`Using SERVER_API_URL: ${process.env.SERVER_API_URL}`); // If we're in Tor mode and the SERVER_API_URL is set to a relative path, use it directly if (torMode && process.env.SERVER_API_URL.startsWith('/')) { return process.env.SERVER_API_URL; } return process.env.SERVER_API_URL; } // For server components, we normally would use environment variables // But we need to be careful with how they're accessed // Try to get the API URL from environment variables const apiUrl = process.env.NEXT_PUBLIC_API_URL; // Check if we're running in a container/production environment const inContainer = process.env.NODE_ENV === 'production'; // If in Tor mode, prefer relative URLs if (torMode && apiUrl && apiUrl.startsWith('/')) { return apiUrl; } // We need to get the host from somewhere to construct the URL // In production, we can rely on the VERCEL_URL or similar if (process.env.VERCEL_URL) { return `https://${process.env.VERCEL_URL}/api`; } // If we have a configured API URL, use that if (apiUrl) { // If it's already an absolute URL, use it if (apiUrl.startsWith('http')) { return apiUrl; } // For container environments, use the internal port const port = process.env.INTERNAL_API_PORT || '3000'; const protocol = (process.env.USE_HTTPS === 'false') ? 'http' : 'https'; // If in Tor mode, prefer relative URLs if (torMode) { return apiUrl.startsWith('/') ? apiUrl : `/${apiUrl}`; } // Otherwise, it's likely a relative path like /api // Use localhost with the correct port for container environments return `${protocol}://localhost:${port}${apiUrl.startsWith('/') ? apiUrl : `/${apiUrl}`}`; } // Last resort fallback - if in Tor mode, use a relative URL if (torMode) { return '/api'; } // For regular container environments const protocol = (process.env.USE_HTTPS === 'false') ? 'http' : 'https'; const port = process.env.INTERNAL_API_PORT || '3000'; return `${protocol}://localhost:${port}/api`; } /** * Server-side fetch wrapper with authentication. */ export async function fetchServer( endpoint: string, options: RequestInit = {} ): Promise { const cookieStore = cookies(); const authToken = cookieStore.get('Authorization')?.value; if (!authToken) redirect('/login'); try { const baseUrl = getBaseUrl(); const torMode = process.env.NEXT_PUBLIC_TOR_MODE === 'true'; // Special handling for Tor mode if (torMode) { // For Tor, we need to be extra careful with URL construction // Remove leading slash from endpoint if present const normalizedEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint; // If baseUrl is a relative path (starts with /) if (baseUrl.startsWith('/')) { // Combine paths carefully to create a relative URL const url = `${baseUrl}${baseUrl.endsWith('/') ? '' : '/'}${normalizedEndpoint}`; console.log(`Tor mode: Using relative URL for server fetch: ${url}`); const res = await fetch(url, { ...options, headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${authToken}`, ...options.headers, }, cache: 'no-store', }); if (res.status === 401) redirect('/login'); if (!res.ok) throw new Error(`Request failed: ${res.statusText}`); return res.json(); } } // Regular URL construction for non-Tor environments // Ensure endpoint doesn't start with a slash if baseUrl ends with one const normalizedEndpoint = endpoint.startsWith('/') ? endpoint.substring(1) : endpoint; // Ensure baseUrl ends with a slash if it doesn't already const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`; // Combine them to get a complete URL const url = `${normalizedBaseUrl}${normalizedEndpoint}`; console.log(`Server fetch to: ${url}`); const res = await fetch(url, { ...options, headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${authToken}`, ...options.headers, }, cache: 'no-store', }); if (res.status === 401) redirect('/login'); if (!res.ok) throw new Error(`Request failed: ${res.statusText}`); return res.json(); } catch (error) { console.error(`Server request to ${endpoint} failed:`, error); throw error; } }