1.8 KB56 lines
Blame
1import { NextRequest, NextResponse } from "next/server";
2import { extractToken, verifyToken } from "@/server/collab-auth";
3import { canAccessRepo, loadRoom, safeId } from "@/server/collab-rooms";
4
5export const dynamic = "force-dynamic";
6
7export async function GET(
8 req: NextRequest,
9 { params }: { params: Promise<{ owner: string; repo: string }> }
10) {
11 const { owner, repo } = await params;
12 const token = extractToken(req);
13
14 if (!token) {
15 return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
16 }
17
18 try {
19 verifyToken(token);
20 } catch {
21 return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
22 }
23
24 if (!(await canAccessRepo(owner, repo, token))) {
25 return NextResponse.json({ error: "Not found" }, { status: 404 });
26 }
27
28 const notes = loadRoom(owner, repo);
29 const timestamp = new Date().toISOString();
30 let output = `# Diagram Review Notes\n# Repo: ${owner}/${repo}\n# Exported: ${timestamp}\n\n`;
31
32 for (const [diagramId, diagramNotes] of Object.entries(notes)) {
33 if (diagramNotes.length === 0) continue;
34 const diagramTitle = diagramNotes[0]?.diagramTitle || diagramId;
35 output += `## ${diagramTitle} (${diagramId})\n\n`;
36 for (const note of diagramNotes) {
37 const location = note.targetNode
38 ? ` [on: ${note.targetNode}]`
39 : note.x != null
40 ? ` [pinned at (${Math.round(note.x!)}, ${Math.round(note.y!)})]`
41 : "";
42 output += `- **${note.author}** (${note.timestamp})${location}: ${note.text}\n`;
43 }
44 output += "\n";
45 }
46
47 const filename = `collab-notes-${safeId(owner)}-${safeId(repo)}-${timestamp.slice(0, 10)}.md`;
48
49 return new NextResponse(output, {
50 headers: {
51 "Content-Type": "text/markdown",
52 "Content-Disposition": `attachment; filename="${filename}"`,
53 },
54 });
55}
56