import { Hono } from 'hono' import { sessionAuth } from '../../auth/middleware' import { config } from '../../config' import { listActiveEnvironmentsResponse } from '../../services/environment' import { listWebSessionsByOwnerUuid } from '../../services/session' import { storeListActiveEnvironments } from '../../store' import { getDb } from '../../db/sqlite' const app = new Hono() /** GET /web/environments — List active environments. * Admin sees all (bypass). Non-admin sees only environments they own * (owner_user_id = me) OR environments linked to teams they belong to. * Optional ?team_id= narrows to one team (server-side scope, mirrors * GET /web/sessions). Unowned personal envs (no owner, no team) are * invisible — they're in claim flow pending state. */ app.get('/environments', sessionAuth, async c => { const userId = c.get('userId') as string const isAdmin = c.get('isAdmin') as boolean const allEnvs = listActiveEnvironmentsResponse() if (isAdmin) { return c.json(allEnvs, 200) } // Resolve the user's team memberships so we can filter environments. const db = getDb() const teamRows = db .query('SELECT team_id FROM team_members WHERE user_id = $userId') .all({ $userId: userId }) as Array<{ team_id: string }> const teamIds = new Set(teamRows.map(r => r.team_id)) // Visible if: env.owner_user_id is me OR env.team_id is one of my teams. const visible = allEnvs.filter( env => env.owner_user_id === userId || (env.team_id !== null && teamIds.has(env.team_id)), ) // Optional server-side team scope narrows to one team. const teamId = c.req.query('team_id') if (teamId) { return c.json( visible.filter(env => env.team_id === teamId), 200, ) } return c.json(visible, 200) }) /** GET /web/server-info — Aggregate server status for Web UI identity panel */ app.get('/server-info', sessionAuth, async c => { const uuid = c.get('userId')! const envs = storeListActiveEnvironments() const sessions = listWebSessionsByOwnerUuid(uuid) return c.json( { version: config.version, uptime_seconds: Math.floor(process.uptime()), workers_active: envs.filter(e => e.status === 'active').length, workers_total: envs.length, sessions_owned: sessions.length, sessions_active: sessions.length, }, 200, ) }) export default app