/** * API utilities for fetching celestial data */ import axios from 'axios'; import type { CelestialDataResponse, BodyInfo } from '../types'; import { auth } from './auth'; // Dynamically determine the API base URL const getApiBaseUrl = () => { if (import.meta.env.VITE_API_BASE_URL) { return import.meta.env.VITE_API_BASE_URL; } // In production, use relative path /api (proxied by Nginx) // This works for both internal IP and external domain access if (import.meta.env.PROD) { return '/api'; } // In development, proxy is configured in vite.config.ts return '/api'; }; const API_BASE_URL = getApiBaseUrl(); export const api = axios.create({ baseURL: API_BASE_URL, timeout: 120000, // Increase timeout to 120 seconds for historical data queries }); // Add request interceptor for auth api.interceptors.request.use( (config) => { // Add token if available const token = auth.getToken(); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => { return Promise.reject(error); } ); // Add response interceptor for error handling api.interceptors.response.use( (response) => { return response; }, (error) => { // Only log errors in development if (import.meta.env.DEV) { console.error('[API Error]', error.config?.url, error.message); if (error.response) { console.error('[API Error Response]', error.response.status, error.response.data); } else if (error.request) { console.error('[API Error Request]', error.request); } } return Promise.reject(error); } ); /** * Fetch celestial positions */ export async function fetchCelestialPositions( startTime?: string, endTime?: string, step: string = '1d' ): Promise { const params: Record = { step }; if (startTime) params.start_time = startTime; if (endTime) params.end_time = endTime; const response = await api.get('/celestial/positions', { params, }); return response.data; } /** * Fetch body information */ export async function fetchBodyInfo(bodyId: string): Promise { const response = await api.get(`/celestial/info/${bodyId}`); return response.data; } /** * List all bodies */ export async function fetchAllBodies(): Promise<{ bodies: BodyInfo[] }> { const response = await api.get('/celestial/list'); return response.data; } /** * Fetch static data by category (constellation, galaxy, nebula, star, cluster) */ export async function fetchStaticData(category: string): Promise<{ category: string; items: Array<{ id: number; name: string; name_zh: string; data: any; }>; }> { const response = await api.get(`/celestial/static/${category}`); return response.data; } /** * Get resource URL from backend */ export function getResourceUrl(type: 'texture' | 'model' | 'icon' | 'thumbnail' | 'data', filename: string): string { const protocol = window.location.protocol; const hostname = window.location.hostname; const port = import.meta.env.VITE_API_BASE_URL ? '' : ':8000'; return `${protocol}//${hostname}${port}/upload/${type}/${filename}`; } /** * Fetch resources for a celestial body */ export async function fetchBodyResources(bodyId: string, resourceType?: string): Promise<{ body_id: string; resources: Array<{ id: number; resource_type: string; file_path: string; file_size: number; mime_type: string; created_at: string; extra_data?: Record; }>; }> { const params: Record = {}; if (resourceType) params.resource_type = resourceType; const response = await api.get(`/celestial/resources/${bodyId}`, { params }); return response.data; } /** * Auth API methods */ export async function login(username: string, password: string): Promise { const response = await api.post('/auth/login', { username, password }); return response.data; } export async function register(username: string, password: string, email?: string, full_name?: string): Promise { const response = await api.post('/auth/register', { username, password, email, full_name }); return response.data; }