// api.js — Frontend ↔ Backend API Bridge const API_BASE = 'http://localhost:8000/api'; class GameAPI { constructor() { this.cache = new Map(); this.cacheTimeout = 30000; // 30s cache for dialogues } async getPlayer() { try { const res = await fetch(`${API_BASE}/player`); return await res.json(); } catch (e) { console.warn('[API] getPlayer failed:', e); return null; } } async savePlayer(state) { try { await fetch(`${API_BASE}/player/save`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(state) }); } catch (e) { console.warn('[API] savePlayer failed:', e); } } async getEvents(mapId) { try { const res = await fetch(`${API_BASE}/events/${mapId}`); const data = await res.json(); return data.events || []; } catch (e) { console.warn('[API] getEvents failed:', e); return []; } } async generateEvent(mapId, playerLevel) { try { const res = await fetch(`${API_BASE}/llm/event?map_id=${mapId}&player_level=${playerLevel}`, { method: 'POST' }); const data = await res.json(); return data.event; } catch (e) { console.warn('[API] generateEvent failed:', e); return null; } } async getNPCDialogue(npcId, playerClass, playerLevel, mood) { const cacheKey = `${npcId}_${mood}`; if (this.cache.has(cacheKey)) { const cached = this.cache.get(cacheKey); if (Date.now() - cached.time < this.cacheTimeout) { return cached.dialogue; } } try { const res = await fetch(`${API_BASE}/llm/dialogue?npc_id=${npcId}&player_class=${playerClass}&player_level=${playerLevel}&mood=${mood}`, { method: 'POST' }); const data = await res.json(); if (data.dialogue) { this.cache.set(cacheKey, { dialogue: data.dialogue, time: Date.now() }); return data.dialogue; } } catch (e) { console.warn('[API] getNPCDialogue failed:', e); } return null; } async health() { try { const res = await fetch(`${API_BASE}/health`); return await res.json(); } catch (e) { return { status: 'offline' }; } } }