/** * GET /api/workspaces — list workspaces the caller can access * * Auth: * - NextAuth session: returns the user's owned + member workspaces * - vibn_sk_... API key: returns just the one workspace the key is bound to */ import { NextResponse } from 'next/server'; import { authSession } from '@/lib/auth/session-server'; import { queryOne } from '@/lib/db-postgres'; import { ensureWorkspaceForUser, listWorkspacesForUser } from '@/lib/workspaces'; import { requireWorkspacePrincipal } from '@/lib/auth/workspace-auth'; export async function GET(request: Request) { if (request.headers.get('authorization')?.toLowerCase().startsWith('bearer vibn_sk_')) { const principal = await requireWorkspacePrincipal(request); if (principal instanceof NextResponse) return principal; return NextResponse.json({ workspaces: [serializeWorkspace(principal.workspace)] }); } const session = await authSession(); if (!session?.user?.email) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const userRow = await queryOne<{ id: string }>( `SELECT id FROM fs_users WHERE data->>'email' = $1 LIMIT 1`, [session.user.email] ); if (!userRow) { return NextResponse.json({ workspaces: [] }); } // Migration path: users who signed in before the signIn hook was // added (or before vibn_workspaces existed) have no row yet. Create // one on first list so the UI never shows an empty state for them. let list = await listWorkspacesForUser(userRow.id); if (list.length === 0) { try { await ensureWorkspaceForUser({ userId: userRow.id, email: session.user.email, displayName: session.user.name ?? null, }); list = await listWorkspacesForUser(userRow.id); } catch (err) { console.error('[api/workspaces] lazy ensure failed', err); } } return NextResponse.json({ workspaces: list.map(serializeWorkspace) }); } function serializeWorkspace(w: import('@/lib/workspaces').VibnWorkspace) { return { id: w.id, slug: w.slug, name: w.name, coolifyProjectUuid: w.coolify_project_uuid, giteaOrg: w.gitea_org, provisionStatus: w.provision_status, provisionError: w.provision_error, createdAt: w.created_at, updatedAt: w.updated_at, }; }