interface ApiConfig { baseURL: string; timeout?: number; } export class ApiService { private static instance: ApiService; private baseURL: string; private timeout: number; private constructor(config: ApiConfig) { this.baseURL = config.baseURL; this.timeout = config.timeout || 10000; } public static getInstance(config?: ApiConfig): ApiService { if (!this.instance && config) { this.instance = new ApiService(config); } return this.instance; } private async getSystemToken(): Promise { const username = import.meta.env.VITE_SYSTEM_USERNAME; const password = import.meta.env.VITE_SYSTEM_PASSWORD; if (!username || !password) { throw new Error( "Failed to obtain the username or password of the front-end system", ); } try { const response = await fetch(`${this.baseURL}/auth/token/system`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ username, password, }), }); if (!response.ok) { throw new Error("Failed to get system token"); } const data = await response.text(); return data; } catch (error) { console.error("Error getting system token:", error); throw error; } } private async getToken(username: string, password: string): Promise { if (username.split(" ").length === 0 || password.split(" ").length === 0) { throw new Error("Username or password cannot be empty"); } try { const response = await fetch(`${this.baseURL}/auth/token`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ username, password, }), }); if (!response.ok) { throw new Error("Failed to get system token"); } const data = await response.text(); return data; } catch (error) { console.error("Error getting system token:", error); throw error; } } public async request( endpoint: string, options: RequestInit = {}, toekn?: string, ): Promise { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), this.timeout); try { const headers = new Headers(options.headers); if (toekn) { headers.set("Authorization", `Bearer ${toekn}`); } const response = await fetch(`${this.baseURL}${endpoint}`, { ...options, headers, signal: controller.signal, }); if (!response.ok) { throw new Error(`API Error: ${response.statusText}`); } const data = await response.json(); return data as T; } catch (error: any) { if (error.name === "AbortError") { throw new Error("Request timeout"); } throw error; } finally { clearTimeout(timeoutId); } } } export default ApiService.getInstance({ baseURL: import.meta.env.VITE_API_BASE_URL, });