import { NextRequest, NextResponse } from 'next/server' import { getDatabase } from '@/lib/db' import { requireRole } from '@/lib/auth' import { logger } from '@/lib/logger' import { pullFromGitHub } from '@/lib/github-sync-engine' import { getSyncPollerStatus } from '@/lib/github-sync-poller' /** * GET /api/github/sync — sync status for all GitHub-linked projects. */ export async function GET(request: NextRequest) { const auth = requireRole(request, 'operator') if ('error' in auth) return NextResponse.json({ error: auth.error }, { status: auth.status }) try { const db = getDatabase() const workspaceId = auth.user.workspace_id ?? 1 const syncs = db.prepare(` SELECT gs.project_id, p.name as project_name, p.github_repo, MAX(gs.last_synced_at) as last_synced_at, SUM(gs.changes_pushed) as total_pushed, SUM(gs.changes_pulled) as total_pulled, COUNT(*) as sync_count FROM github_syncs gs LEFT JOIN projects p ON p.id = gs.project_id AND p.workspace_id = gs.workspace_id WHERE gs.workspace_id = ? AND gs.project_id IS NOT NULL GROUP BY gs.project_id ORDER BY last_synced_at DESC `).all(workspaceId) const poller = getSyncPollerStatus() return NextResponse.json({ syncs, poller }) } catch (error) { logger.error({ err: error }, 'GET /api/github/sync error') return NextResponse.json({ error: 'Failed to fetch sync status' }, { status: 500 }) } } /** * POST /api/github/sync — trigger sync manually. * Body: { action: 'trigger', project_id: number } or { action: 'trigger-all' } */ export async function POST(request: NextRequest) { const auth = requireRole(request, 'operator') if ('error' in auth) return NextResponse.json({ error: auth.error }, { status: auth.status }) try { const body = await request.json() const { action, project_id } = body const db = getDatabase() const workspaceId = auth.user.workspace_id ?? 1 if (action === 'trigger' && typeof project_id === 'number') { const project = db.prepare(` SELECT id, github_repo, github_sync_enabled, github_default_branch FROM projects WHERE id = ? AND workspace_id = ? AND status = 'active' `).get(project_id, workspaceId) as any | undefined if (!project) { return NextResponse.json({ error: 'Project not found' }, { status: 404 }) } if (!project.github_repo || !project.github_sync_enabled) { return NextResponse.json({ error: 'GitHub sync not enabled for this project' }, { status: 400 }) } const result = await pullFromGitHub(project, workspaceId) return NextResponse.json({ ok: true, ...result }) } if (action === 'trigger-all') { const projects = db.prepare(` SELECT id, github_repo, github_sync_enabled, github_default_branch FROM projects WHERE github_sync_enabled = 1 AND github_repo IS NOT NULL AND workspace_id = ? AND status = 'active' `).all(workspaceId) as any[] let totalPulled = 0 let totalPushed = 0 for (const project of projects) { try { const result = await pullFromGitHub(project, workspaceId) totalPulled += result.pulled totalPushed += result.pushed } catch (err) { logger.error({ err, projectId: project.id }, 'Trigger-all: project sync failed') } } return NextResponse.json({ ok: true, projects_synced: projects.length, pulled: totalPulled, pushed: totalPushed, }) } return NextResponse.json({ error: 'Unknown action. Use trigger or trigger-all' }, { status: 400 }) } catch (error) { logger.error({ err: error }, 'POST /api/github/sync error') return NextResponse.json({ error: 'Sync trigger failed' }, { status: 500 }) } }