import { NextResponse } from "next/server"; import { createSupabaseRouteClient } from "@/lib/supabase/server"; import { promises as fs } from "fs"; import path from "path"; import { getDocumentsBaseDir, getLegacyMindmapsBaseDir } from "@/lib/server/local-paths"; import { isConvexEnabled } from "@/lib/convex/enabled"; import { getAuthedConvexClient } from "@/lib/convex/route"; import { api } from "@/lib/convex/api"; const defaultMindmapData = { data: { text: "中心主题" }, children: [], }; // 新版:与页面文件夹(index.md 所在处)对齐,放在 public/documents//mindmap.json // 旧版遗留:public/mindmaps//mindmap.json const preferredBaseDir = getDocumentsBaseDir(); const legacyBaseDir = getLegacyMindmapsBaseDir(); async function ensureDir(dir: string) { await fs.mkdir(dir, { recursive: true }); } async function removeFileSafe(file: string) { try { await fs.rm(file, { force: true }); } catch { // 忽略删除失败(例如文件不存在) } } async function ensureIndexFile(folder: string, title = "无标题") { const indexFile = path.join(folder, "index.md"); try { await fs.access(indexFile); } catch { await fs.writeFile(indexFile, `# ${title}\n`, "utf8"); } } export async function GET( _req: Request, { params }: { params: Promise<{ docId: string }> }, ) { const { docId: id } = await params; if (isConvexEnabled()) { const { auth, client } = getAuthedConvexClient(); const mindmapId = `legacy-${id}`; const res = await client.query(api.mindmaps.get, { userId: auth.userId, docId: id, mindmapId, }); return NextResponse.json({ data: res?.data ?? defaultMindmapData, source: "convex" }); } const supabase = await createSupabaseRouteClient(); const { data: { session }, } = await supabase.auth.getSession(); if (!session) { return NextResponse.json({ error: "未登录" }, { status: 401 }); } const preferredFolder = path.join(preferredBaseDir, id); const preferredFile = path.join(preferredFolder, "mindmap.json"); const legacyFolder = path.join(legacyBaseDir, id); const legacyFile = path.join(legacyFolder, "mindmap.json"); const tryRead = async (file: string) => { try { const content = await fs.readFile(file, "utf8"); return JSON.parse(content); } catch { return null; } }; const localData = (await tryRead(preferredFile)) ?? (await tryRead(legacyFile)); if (localData) { return NextResponse.json({ data: localData, source: "local" }); } // fallback Supabase const { data, error } = await supabase .from("documents") .select("mindmap_data") .eq("id", id) .eq("user_id", session.user.id) .maybeSingle(); if (error) { return NextResponse.json({ error: error.message }, { status: 400 }); } const payload = data?.mindmap_data ?? defaultMindmapData; return NextResponse.json({ data: payload, source: "supabase" }); } export async function POST( request: Request, { params }: { params: Promise<{ docId: string }> }, ) { const { docId: id } = await params; if (isConvexEnabled()) { const { auth, client } = getAuthedConvexClient(); const mindmapId = `legacy-${id}`; const { data } = await request.json(); const result = await client.mutation(api.mindmaps.put, { userId: auth.userId, docId: id, mindmapId, data: data ?? defaultMindmapData, }); return NextResponse.json({ ok: true, ...(result ?? {}) }); } const supabase = await createSupabaseRouteClient(); const { data: { session }, } = await supabase.auth.getSession(); if (!session) { return NextResponse.json({ error: "未登录" }, { status: 401 }); } const { data } = await request.json(); const folder = path.join(preferredBaseDir, id); const file = path.join(folder, "mindmap.json"); try { await ensureDir(folder); await ensureIndexFile(folder); await fs.writeFile( file, JSON.stringify(data ?? defaultMindmapData, null, 2), "utf8", ); } catch (error) { return NextResponse.json({ error: String(error) }, { status: 500 }); } const { error } = await supabase .from("documents") .update({ mindmap_data: data ?? defaultMindmapData }) .eq("id", id) .eq("user_id", session.user.id); if (error) { return NextResponse.json({ error: error.message }, { status: 400 }); } return NextResponse.json({ ok: true }); } export async function DELETE( _req: Request, { params }: { params: Promise<{ docId: string }> }, ) { const { docId: id } = await params; if (isConvexEnabled()) { const { auth, client } = getAuthedConvexClient(); const mindmapId = `legacy-${id}`; const result = await client.mutation(api.mindmaps.softDelete, { userId: auth.userId, docId: id, mindmapId, }); return NextResponse.json({ ok: true, ...(result ?? {}) }); } const supabase = await createSupabaseRouteClient(); const { data: { session }, } = await supabase.auth.getSession(); if (!session) { return NextResponse.json({ error: "未登录" }, { status: 401 }); } const preferredFolder = path.join(preferredBaseDir, id); const preferredFile = path.join(preferredFolder, "mindmap.json"); const legacyFolder = path.join(legacyBaseDir, id); const legacyFile = path.join(legacyFolder, "mindmap.json"); await Promise.all([removeFileSafe(preferredFile), removeFileSafe(legacyFile)]); const { error } = await supabase .from("documents") .update({ mindmap_data: null }) .eq("id", id) .eq("user_id", session.user.id); if (error) { return NextResponse.json({ error: error.message }, { status: 500 }); } return NextResponse.json({ ok: true }); }