import { Router } from "express"; import { createSession, getSession, findSessionByDiagram, syncEntities, addMessage, clearHistory, deleteSession, getStats } from "../services/sessionStore.js"; import { getSessionUsage, getGlobalUsage, formatCost } from "../services/usageTracker.js"; const router = Router(); /** * GET /api/session/debug/stats * Get session statistics (for debugging) * Query params: * - details=true: Include full entity and conversation data * NOTE: Must be before /:id routes to avoid matching "debug" as an id */ router.get("/debug/stats", (req, res) => { const includeDetails = req.query.details === 'true'; const stats = getStats(includeDetails); console.log('[Session Debug] Stats requested:', JSON.stringify(stats, null, 2)); res.json(stats); }); /** * GET /api/session/usage/global * Get global token usage and cost statistics * NOTE: Must be before /:id routes */ router.get("/usage/global", (req, res) => { const usage = getGlobalUsage(); res.json({ ...usage, totalCostFormatted: formatCost(usage.totalCost), uptimeFormatted: `${Math.round(usage.uptime / 1000 / 60)} minutes` }); }); /** * GET /api/session/:id/usage * Get token usage and cost for a specific session */ router.get("/:id/usage", (req, res) => { const usage = getSessionUsage(req.params.id); if (!usage) { return res.status(404).json({ error: "No usage data for session" }); } res.json({ ...usage, totalCostFormatted: formatCost(usage.totalCost) }); }); /** * POST /api/session/create * Create a new session or return existing one for a diagram */ router.post("/create", (req, res) => { const { diagramId } = req.body; if (!diagramId) { return res.status(400).json({ error: "diagramId is required" }); } // Check for existing session let session = findSessionByDiagram(diagramId); if (session) { console.log(`[Session] Resuming existing session ${session.id} for diagram ${diagramId} (${session.conversationHistory.length} messages, ${session.entities.length} entities)`); return res.json({ session, isNew: false }); } // Create new session session = createSession(diagramId); console.log(`[Session] Created new session ${session.id} for diagram ${diagramId}`); res.json({ session, isNew: true }); }); /** * GET /api/session/:id * Get session details including history */ router.get("/:id", (req, res) => { const session = getSession(req.params.id); if (!session) { return res.status(404).json({ error: "Session not found" }); } res.json({ session }); }); /** * PUT /api/session/:id/sync * Sync entities from client to server */ router.put("/:id/sync", (req, res) => { const { entities } = req.body; if (!entities || !Array.isArray(entities)) { return res.status(400).json({ error: "entities array is required" }); } const session = syncEntities(req.params.id, entities); if (!session) { return res.status(404).json({ error: "Session not found" }); } console.log(`[Session ${req.params.id}] Synced ${entities.length} entities:`, entities.map(e => `${e.text || '(no label)'} (${e.template})`).join(', ') || 'none'); res.json({ success: true, entityCount: entities.length }); }); /** * POST /api/session/:id/message * Add a message to history (used after successful Claude response) */ router.post("/:id/message", (req, res) => { const { role, content, toolResults } = req.body; if (!role || !content) { return res.status(400).json({ error: "role and content are required" }); } const session = addMessage(req.params.id, { role, content, toolResults }); if (!session) { return res.status(404).json({ error: "Session not found" }); } res.json({ success: true, messageCount: session.conversationHistory.length }); }); /** * DELETE /api/session/:id/history * Clear conversation history */ router.delete("/:id/history", (req, res) => { const session = clearHistory(req.params.id); if (!session) { return res.status(404).json({ error: "Session not found" }); } res.json({ success: true }); }); /** * DELETE /api/session/:id * Delete a session entirely */ router.delete("/:id", (req, res) => { const deleted = deleteSession(req.params.id); if (!deleted) { return res.status(404).json({ error: "Session not found" }); } res.json({ success: true }); }); export default router;