Files
vibn-frontend/app/api/sessions/route.ts
Mark Henderson 651ddf1e11 Rip out Theia, ship P5.1 attach E2E + Justine UI work-in-progress
Theia rip-out:
- Delete app/api/theia-auth/route.ts (Traefik ForwardAuth shim)
- Delete app/api/projects/[projectId]/workspace/route.ts and
  app/api/projects/prewarm/route.ts (Cloud Run Theia provisioning)
- Delete lib/cloud-run-workspace.ts and lib/coolify-workspace.ts
- Strip provisionTheiaWorkspace + theiaWorkspaceUrl/theiaAppUuid/
  theiaError from app/api/projects/create/route.ts response
- Remove Theia callbackUrl branch in app/auth/page.tsx
- Drop "Open in Theia" button + xterm/Theia PTY copy in build/page.tsx
- Drop theiaWorkspaceUrl from deployment/page.tsx Project type
- Strip Theia IDE line + theia-code-os from advisor + agent-chat
  context strings
- Scrub Theia mention from lib/auth/workspace-auth.ts comment

P5.1 (custom apex domains + DNS):
- lib/coolify.ts + lib/opensrs.ts: nameserver normalization, OpenSRS
  XML auth, Cloud DNS plumbing
- scripts/smoke-attach-e2e.ts: full prod GCP + sandbox OpenSRS +
  prod Coolify smoke covering register/zone/A/NS/PATCH/cleanup

In-progress (Justine onboarding/build, MVP setup, agent telemetry):
- New (justine)/stories, project (home) layouts, mvp-setup, run, tasks
  routes + supporting components
- Project shell + sidebar + nav refactor for the Stackless palette
- Agent session API hardening (sessions, events, stream, approve,
  retry, stop) + atlas-chat, advisor, design-surfaces refresh
- New scripts/sync-db-url-from-coolify.mjs +
  scripts/prisma-db-push.mjs + docker-compose.local-db.yml for
  local Prisma workflows
- lib/dev-bypass.ts, lib/chat-context-refs.ts, lib/prd-sections.ts
- Misc: stories CSS, debug/prisma route, modal-theme, BuildLivePlanPanel

Made-with: Cursor
2026-04-22 18:05:01 -07:00

75 lines
2.4 KiB
TypeScript

import { NextResponse } from 'next/server';
import { authSession } from "@/lib/auth/session-server";
import { query } from '@/lib/db-postgres';
export async function GET(request: Request) {
try {
const session = await authSession();
if (!session?.user?.email) {
return NextResponse.json([], { status: 200 });
}
const { searchParams } = new URL(request.url);
const projectId = searchParams.get('projectId');
const limit = parseInt(searchParams.get('limit') || '50');
let rows: any[];
if (projectId) {
rows = await query<any>(
`SELECT s.id, s.data, s.created_at
FROM fs_sessions s
JOIN fs_users u ON u.id = s.user_id
WHERE u.data->>'email' = $1 AND s.data->>'projectId' = $2
ORDER BY s.created_at DESC LIMIT $3`,
[session.user.email, projectId, limit]
);
} else {
rows = await query<any>(
`SELECT s.id, s.data, s.created_at
FROM fs_sessions s
JOIN fs_users u ON u.id = s.user_id
WHERE u.data->>'email' = $1
ORDER BY s.created_at DESC LIMIT $2`,
[session.user.email, limit]
);
}
const sessions = rows.map((row: any) => {
const d = row.data ?? {};
return {
id: row.id,
session_id: row.id,
projectId: d.projectId,
userId: d.userId,
workspacePath: d.workspacePath,
workspaceName: d.workspaceName,
startTime: d.startTime,
endTime: d.endTime,
duration: d.duration,
duration_minutes: d.duration ? Math.round(d.duration / 60) : 0,
tokensUsed: d.tokensUsed || 0,
total_tokens: d.tokensUsed || 0,
cost: d.cost || 0,
estimated_cost_usd: d.cost || 0,
model: d.model || 'unknown',
primary_ai_model: d.model || 'unknown',
filesModified: d.filesModified || [],
summary: d.conversationSummary || null,
message_count: d.messageCount || 0,
ide_name: 'Cursor',
github_branch: d.githubBranch || null,
conversation: d.conversation || [],
file_changes: d.fileChanges || [],
createdAt: row.created_at,
last_updated: d.updatedAt || row.created_at,
};
});
console.log(`[API] Found ${sessions.length} sessions from PostgreSQL`);
return NextResponse.json(sessions);
} catch (error) {
console.error('[API] Error fetching sessions:', error);
return NextResponse.json([]);
}
}