// src/api.js const configuredApiUrl = (import.meta.env.VITE_API_URL || '').trim(); const isLocalhost = typeof window !== 'undefined' && ['localhost', '127.0.0.1'].includes(window.location.hostname); const defaultApiUrl = isLocalhost ? 'http://localhost:4000/api' : '/api'; const API_URL = (configuredApiUrl || defaultApiUrl).replace(/\/$/, ''); const getHeaders = (options = {}) => { const headers = { ...options.headers, }; // Add auth token if exists const token = localStorage.getItem('token'); if (token) { headers['Authorization'] = `Bearer ${token}`; } // Only add Content-Type if we're not sending FormData if (!(options.body instanceof FormData)) { headers['Content-Type'] = 'application/json'; } return headers; }; export const fetchApi = async (endpoint, options = {}) => { try { const url = `${API_URL}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`; // Default fetch options const fetchOptions = { ...options, headers: getHeaders(options), }; // Stringify body if it's an object (and not FormData) if (options.body && typeof options.body === 'object' && !(options.body instanceof FormData)) { fetchOptions.body = JSON.stringify(options.body); } const response = await fetch(url, fetchOptions); let data; const contentType = response.headers.get("content-type"); if (contentType && contentType.indexOf("application/json") !== -1) { data = await response.json(); } else { data = await response.text(); } if (!response.ok) { const errorMessage = data?.error || data?.message || data || 'An error occurred'; throw new Error(errorMessage); } return data; } catch (error) { console.error(`API Error (${endpoint}):`, error); throw error; } }; export const streamApi = async (endpoint, options = {}, onToken) => { const url = `${API_URL}${endpoint.startsWith('/') ? endpoint : `/${endpoint}`}`; const fetchOptions = { ...options, headers: getHeaders(options), }; if (options.body && typeof options.body === 'object' && !(options.body instanceof FormData)) { fetchOptions.body = JSON.stringify(options.body); } const response = await fetch(url, fetchOptions); if (!response.ok) { const data = await response.json().catch(() => ({})); throw new Error(data.error || 'Stream error'); } const reader = response.body.getReader(); const decoder = new TextDecoder(); let done = false; while (!done) { const { value, done: doneReading } = await reader.read(); done = doneReading; const chunkValue = decoder.decode(value); if (chunkValue) { onToken(chunkValue); } } };