Files
DashDescomplicar/api/routes/sessions.ts

66 lines
2.2 KiB
TypeScript

/**
* Rota /api/sessions — lista e detalhe de sessões Claude Code.
* Validação Zod em query params; detalhe carrega eventos via parseSessionFile.
* @author Descomplicar® | Projecto Observabilidade (Espelho)
*/
import { Router } from 'express'
import { z } from 'zod'
import type { SessionsDb } from '../services/sessions/db.js'
import { parseSessionFile } from '../services/sessions/parser.js'
const ListQuerySchema = z.object({
days: z.coerce.number().int().min(1).max(3650).optional(),
project: z.string().min(1).max(200).optional(),
tool: z.string().min(1).max(100).optional(),
skill: z.string().min(1).max(200).optional(),
q: z.string().max(500).optional(),
limit: z.coerce.number().int().min(1).max(200).default(50),
offset: z.coerce.number().int().min(0).default(0),
})
const IdParamSchema = z.object({ id: z.string().min(1).max(200) })
export function createSessionsRouter(db: SessionsDb): Router {
const router = Router()
router.get('/', (req, res) => {
const parsed = ListQuerySchema.safeParse(req.query)
if (!parsed.success) {
return res.status(400).json({ error: 'Invalid query', details: parsed.error.format() })
}
const filters = parsed.data
const items = db.listSessions(filters)
const total = db.countSessions(filters)
return res.json({ total, items })
})
router.get('/:id', async (req, res) => {
const parsed = IdParamSchema.safeParse(req.params)
if (!parsed.success) {
return res.status(400).json({ error: 'Invalid id' })
}
const session = db.getSession(parsed.data.id)
if (!session) return res.status(404).json({ error: 'Session not found' })
try {
const { events } = await parseSessionFile(session.jsonl_path)
return res.json({ meta: session, events })
} catch (err) {
const e = err as NodeJS.ErrnoException
if (e.code === 'ENOENT') {
return res.status(410).json({
error: 'Session file missing (stale index)',
session_id: parsed.data.id,
})
}
const isProduction = process.env.NODE_ENV === 'production'
return res.status(500).json({
error: 'Failed to parse session',
...(isProduction ? {} : { message: e.message }),
})
}
})
return router
}