import { randomUUID } from "crypto"; import { NextResponse } from "next/server"; import { createSupabaseRouteClient } from "@/lib/supabase/server"; import { isConvexEnabled } from "@/lib/convex/enabled"; import { requireAuthContext } from "@/lib/auth/authContext"; import { getConvexHttpClient } from "@/lib/convex/server"; import { api } from "@/lib/convex/api"; import { getBlocksFromDocumentContent, findBlockInTree, withBlocksWrittenBack } from "@/lib/blocks"; type EmbedBlockPayload = { sourceDocumentId: string; blockId: string; targetDocumentId: string; position?: "end"; }; export async function POST(request: Request) { const { sourceDocumentId, blockId, targetDocumentId }: EmbedBlockPayload = await request.json(); if (!sourceDocumentId || !blockId || !targetDocumentId) { return NextResponse.json({ error: "缺少参数" }, { status: 400 }); } if (sourceDocumentId === targetDocumentId) { return NextResponse.json({ error: "禁止嵌入到当前页面" }, { status: 400 }); } if (isConvexEnabled()) { const auth = await requireAuthContext(); const client = getConvexHttpClient(); const source = await client.query(api.documents.getContent, { userId: auth.userId, id: sourceDocumentId }); if (!source) return NextResponse.json({ error: "源页面不存在或无权限" }, { status: 404 }); const sourceBlocks = getBlocksFromDocumentContent(source.content); const hit = findBlockInTree(sourceBlocks, blockId); if (!hit) return NextResponse.json({ error: "源块不存在或无权限" }, { status: 404 }); const target = await client.query(api.documents.getContent, { userId: auth.userId, id: targetDocumentId }); if (!target) return NextResponse.json({ error: "目标页面不存在或无权限" }, { status: 404 }); const targetBlocks = getBlocksFromDocumentContent(target.content); const referenceBlock = { id: randomUUID(), type: "blockReference", props: { sourceDocumentId, targetBlockId: blockId, display: "embed", }, content: [], children: [], }; const nextBlocks = [...targetBlocks, referenceBlock]; const payload = withBlocksWrittenBack(target.content, nextBlocks); await client.mutation(api.documents.updateContent, { userId: auth.userId, id: targetDocumentId, content: payload }); return NextResponse.json({ ok: true }); } const supabase = await createSupabaseRouteClient(); const { data: { session }, } = await supabase.auth.getSession(); if (!session) { return NextResponse.json({ error: "未登录" }, { status: 401 }); } const { data: sourceDoc } = await supabase .from("documents") .select("id,content,user_id") .eq("id", sourceDocumentId) .eq("user_id", session.user.id) .single(); if (!sourceDoc) return NextResponse.json({ error: "源页面不存在或无权限" }, { status: 404 }); const sourceBlocks = getBlocksFromDocumentContent(sourceDoc.content); if (!findBlockInTree(sourceBlocks, blockId)) { return NextResponse.json({ error: "源块不存在或无权限" }, { status: 404 }); } const { data: targetDoc } = await supabase .from("documents") .select("id,content,user_id") .eq("id", targetDocumentId) .eq("user_id", session.user.id) .single(); if (!targetDoc) return NextResponse.json({ error: "目标页面不存在或无权限" }, { status: 404 }); const targetBlocks = getBlocksFromDocumentContent(targetDoc.content); const referenceBlock = { id: randomUUID(), type: "blockReference", props: { sourceDocumentId, targetBlockId: blockId, display: "embed", }, content: [], children: [], }; const nextBlocks = [...targetBlocks, referenceBlock]; const payload = withBlocksWrittenBack(targetDoc.content, nextBlocks); const { error } = await supabase .from("documents") .update({ content: payload }) .eq("id", targetDocumentId) .eq("user_id", session.user.id); if (error) return NextResponse.json({ error: error.message }, { status: 500 }); return NextResponse.json({ ok: true }); }