From 3e0923fc4a1da8564d9f6a06a1d466e2b44d366c Mon Sep 17 00:00:00 2001 From: Ajax Davis Date: Sat, 17 Jan 2026 04:27:46 +1000 Subject: [PATCH] feat(api): add GET endpoint for collection tools --- .../app/api/collections/[id]/tools/route.ts | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/apps/web/src/app/api/collections/[id]/tools/route.ts b/apps/web/src/app/api/collections/[id]/tools/route.ts index 402ba11..3d305d5 100644 --- a/apps/web/src/app/api/collections/[id]/tools/route.ts +++ b/apps/web/src/app/api/collections/[id]/tools/route.ts @@ -30,6 +30,102 @@ interface RouteContext { params: Promise<{ id: string }>; } +/** + * GET /api/collections/[id]/tools + * List all tools in a collection + */ +export async function GET( + _request: NextRequest, + context: RouteContext +): Promise> { + const requestId = crypto.randomUUID(); + const { id: collectionId } = await context.params; + + try { + // Check if collection exists and is accessible + const collection = await prisma.collection.findUnique({ + where: { id: collectionId }, + select: { id: true, isPublic: true, userId: true }, + }); + + if (!collection) { + return NextResponse.json( + { + success: false, + error: { code: 'NOT_FOUND', message: 'Collection not found' }, + meta: { version: API_VERSION, timestamp: new Date().toISOString(), requestId }, + }, + { status: 404 } + ); + } + + // For private collections, check ownership + if (!collection.isPublic) { + const session = await auth.api.getSession({ + headers: await headers(), + }); + + if (!session || collection.userId !== session.user.id) { + return NextResponse.json( + { + success: false, + error: { code: 'FORBIDDEN', message: 'Access denied' }, + meta: { version: API_VERSION, timestamp: new Date().toISOString(), requestId }, + }, + { status: 403 } + ); + } + } + + // Fetch tools in the collection + const collectionTools = await prisma.collectionTool.findMany({ + where: { collectionId }, + include: { + tool: { + select: { + id: true, + name: true, + description: true, + package: { + select: { + npmPackageName: true, + category: true, + }, + }, + }, + }, + }, + orderBy: { position: 'asc' }, + }); + + return NextResponse.json( + { + success: true, + data: collectionTools.map((ct) => ({ + id: ct.id, + toolId: ct.toolId, + position: ct.position, + note: ct.note, + addedAt: ct.addedAt, + tool: ct.tool, + })), + meta: { version: API_VERSION, timestamp: new Date().toISOString(), requestId }, + }, + { status: 200 } + ); + } catch (error) { + console.error('[API Error] GET /api/collections/[id]/tools:', error); + return NextResponse.json( + { + success: false, + error: { code: 'INTERNAL_ERROR', message: 'Failed to fetch collection tools' }, + meta: { version: API_VERSION, timestamp: new Date().toISOString(), requestId }, + }, + { status: 500 } + ); + } +} + /** * POST /api/collections/[id]/tools * Add a tool to a collection