2026-02-06 23:01:30 -05:00

121 lines
3.5 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { auth } from '@clerk/nextjs/server';
import { db, projects, users } from '@mcpengine/db';
import { eq, desc, and, count } from 'drizzle-orm';
// ── GET /api/projects — list user's projects with pagination ────────────────
export async function GET(req: NextRequest) {
try {
const { userId: clerkId } = await auth();
if (!clerkId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const user = await db.query.users.findFirst({
where: eq(users.clerkId, clerkId),
});
if (!user) {
return NextResponse.json({ error: 'User not found' }, { status: 404 });
}
const url = new URL(req.url);
const page = Math.max(1, parseInt(url.searchParams.get('page') || '1', 10));
const limit = Math.min(50, Math.max(1, parseInt(url.searchParams.get('limit') || '20', 10)));
const offset = (page - 1) * limit;
const [rows, totalResult] = await Promise.all([
db.query.projects.findMany({
where: eq(projects.userId, user.id),
orderBy: [desc(projects.updatedAt)],
limit,
offset,
with: {
tools: { columns: { id: true, name: true, enabled: true } },
apps: { columns: { id: true, name: true, pattern: true } },
},
}),
db.select({ count: count() }).from(projects).where(eq(projects.userId, user.id)),
]);
const total = totalResult[0]?.count ?? 0;
return NextResponse.json({
data: rows,
meta: {
page,
limit,
total,
totalPages: Math.ceil(total / limit),
},
});
} catch (error) {
console.error('[GET /api/projects]', error);
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 },
);
}
}
// ── POST /api/projects — create a new project ──────────────────────────────
export async function POST(req: NextRequest) {
try {
const { userId: clerkId } = await auth();
if (!clerkId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const user = await db.query.users.findFirst({
where: eq(users.clerkId, clerkId),
});
if (!user) {
return NextResponse.json({ error: 'User not found' }, { status: 404 });
}
const body = await req.json();
const { name, slug, description, specUrl, templateId } = body;
if (!name || !slug) {
return NextResponse.json(
{ error: 'name and slug are required' },
{ status: 400 },
);
}
// Check for duplicate slug under same user
const existing = await db.query.projects.findFirst({
where: and(eq(projects.userId, user.id), eq(projects.slug, slug)),
});
if (existing) {
return NextResponse.json(
{ error: 'A project with this slug already exists' },
{ status: 409 },
);
}
const [project] = (await db
.insert(projects)
.values({
userId: user.id,
teamId: user.teamId,
name,
slug,
description: description || null,
specUrl: specUrl || null,
templateId: templateId || null,
status: 'draft',
})
.returning()) as any[];
return NextResponse.json({ data: project }, { status: 201 });
} catch (error) {
console.error('[POST /api/projects]', error);
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 },
);
}
}