const API_URL = process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:8000"; export type Song = { id: string; user_id: string; owner_display_name: string | null; title: string; prompt: string; lyrics: string | null; mode: "instrumental" | "vocals"; status: "pending" | "processing" | "completed" | "failed"; error_message: string | null; duration_seconds: number | null; cover_seed: number; is_public: boolean; like_count: number; liked_by_me: boolean; audio_url: string | null; created_at: string; }; export type User = { id: string; email: string; display_name: string; created_at: string; }; class ApiError extends Error { status: number; constructor(status: number, message: string) { super(message); this.status = status; } } function getToken(): string | null { if (typeof window === "undefined") return null; return window.localStorage.getItem("aurora_token"); } export function setToken(token: string | null) { if (typeof window === "undefined") return; if (token) window.localStorage.setItem("aurora_token", token); else window.localStorage.removeItem("aurora_token"); } async function request(path: string, options: RequestInit = {}): Promise { const token = getToken(); const headers: Record = { "Content-Type": "application/json", ...(options.headers as Record | undefined), }; if (token) headers["Authorization"] = `Bearer ${token}`; const res = await fetch(`${API_URL}${path}`, { ...options, headers }); if (!res.ok) { let detail = res.statusText; try { const body = await res.json(); detail = body.detail ?? detail; } catch { // ignore } throw new ApiError(res.status, typeof detail === "string" ? detail : JSON.stringify(detail)); } if (res.status === 204) return undefined as T; return res.json() as Promise; } export function mediaUrl(audioUrl: string | null): string | null { if (!audioUrl) return null; return `${API_URL}${audioUrl}`; } export const api = { signup: (email: string, password: string, display_name: string) => request<{ access_token: string }>("/auth/signup", { method: "POST", body: JSON.stringify({ email, password, display_name }), }), login: (email: string, password: string) => request<{ access_token: string }>("/auth/login", { method: "POST", body: JSON.stringify({ email, password }), }), me: () => request("/auth/me"), createSong: (payload: { title: string; prompt: string; mode: "instrumental" | "vocals"; lyrics?: string | null; is_public: boolean; }) => request("/songs", { method: "POST", body: JSON.stringify(payload) }), mySongs: () => request<{ items: Song[]; total: number }>("/songs/mine"), feed: () => request<{ items: Song[]; total: number }>("/songs/feed"), getSong: (id: string) => request(`/songs/${id}`), updateSong: (id: string, payload: { title?: string; is_public?: boolean }) => request(`/songs/${id}`, { method: "PATCH", body: JSON.stringify(payload) }), deleteSong: (id: string) => request(`/songs/${id}`, { method: "DELETE" }), likeSong: (id: string) => request(`/songs/${id}/like`, { method: "POST" }), unlikeSong: (id: string) => request(`/songs/${id}/like`, { method: "DELETE" }), }; export { ApiError };