2026-03-20 09:37:02 +00:00
|
|
|
import { z } from "zod";
|
|
|
|
|
import { auth } from "@/app/(auth)/auth";
|
|
|
|
|
import type { ArtifactKind } from "@/components/chat/artifact";
|
2024-10-30 16:01:24 +05:30
|
|
|
import {
|
|
|
|
|
deleteDocumentsByIdAfterTimestamp,
|
|
|
|
|
getDocumentsById,
|
|
|
|
|
saveDocument,
|
2026-03-20 09:37:02 +00:00
|
|
|
updateDocumentContent,
|
2025-09-21 11:02:31 -07:00
|
|
|
} from "@/lib/db/queries";
|
2026-02-23 17:24:17 -08:00
|
|
|
import { ChatbotError } from "@/lib/errors";
|
2024-10-30 16:01:24 +05:30
|
|
|
|
2026-03-20 09:37:02 +00:00
|
|
|
const documentSchema = z.object({
|
|
|
|
|
content: z.string(),
|
|
|
|
|
title: z.string(),
|
|
|
|
|
kind: z.enum(["text", "code", "image", "sheet"]),
|
|
|
|
|
isManualEdit: z.boolean().optional(),
|
|
|
|
|
});
|
|
|
|
|
|
2024-10-30 16:01:24 +05:30
|
|
|
export async function GET(request: Request) {
|
|
|
|
|
const { searchParams } = new URL(request.url);
|
2025-09-21 11:02:31 -07:00
|
|
|
const id = searchParams.get("id");
|
2024-10-30 16:01:24 +05:30
|
|
|
|
|
|
|
|
if (!id) {
|
2026-02-23 17:24:17 -08:00
|
|
|
return new ChatbotError(
|
2025-09-21 11:02:31 -07:00
|
|
|
"bad_request:api",
|
|
|
|
|
"Parameter id is missing"
|
2025-05-13 19:01:28 -07:00
|
|
|
).toResponse();
|
2024-10-30 16:01:24 +05:30
|
|
|
}
|
|
|
|
|
|
2026-03-20 09:37:02 +00:00
|
|
|
const session = await auth();
|
2024-10-30 16:01:24 +05:30
|
|
|
|
2025-05-13 19:01:28 -07:00
|
|
|
if (!session?.user) {
|
2026-02-23 17:24:17 -08:00
|
|
|
return new ChatbotError("unauthorized:document").toResponse();
|
2024-10-30 16:01:24 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const documents = await getDocumentsById({ id });
|
|
|
|
|
|
|
|
|
|
const [document] = documents;
|
|
|
|
|
|
|
|
|
|
if (!document) {
|
2026-02-23 17:24:17 -08:00
|
|
|
return new ChatbotError("not_found:document").toResponse();
|
2024-10-30 16:01:24 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (document.userId !== session.user.id) {
|
2026-02-23 17:24:17 -08:00
|
|
|
return new ChatbotError("forbidden:document").toResponse();
|
2024-10-30 16:01:24 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Response.json(documents, { status: 200 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function POST(request: Request) {
|
|
|
|
|
const { searchParams } = new URL(request.url);
|
2025-09-21 11:02:31 -07:00
|
|
|
const id = searchParams.get("id");
|
2024-10-30 16:01:24 +05:30
|
|
|
|
|
|
|
|
if (!id) {
|
2026-02-23 17:24:17 -08:00
|
|
|
return new ChatbotError(
|
2025-09-21 11:02:31 -07:00
|
|
|
"bad_request:api",
|
|
|
|
|
"Parameter id is required."
|
2025-05-13 19:01:28 -07:00
|
|
|
).toResponse();
|
2024-10-30 16:01:24 +05:30
|
|
|
}
|
|
|
|
|
|
2026-03-20 09:37:02 +00:00
|
|
|
const session = await auth();
|
2024-10-30 16:01:24 +05:30
|
|
|
|
2025-05-13 19:01:28 -07:00
|
|
|
if (!session?.user) {
|
2026-02-23 17:24:17 -08:00
|
|
|
return new ChatbotError("not_found:document").toResponse();
|
2024-10-30 16:01:24 +05:30
|
|
|
}
|
|
|
|
|
|
2026-03-20 09:37:02 +00:00
|
|
|
let content: string;
|
|
|
|
|
let title: string;
|
|
|
|
|
let kind: ArtifactKind;
|
|
|
|
|
let isManualEdit: boolean | undefined;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const parsed = documentSchema.parse(await request.json());
|
|
|
|
|
content = parsed.content;
|
|
|
|
|
title = parsed.title;
|
|
|
|
|
kind = parsed.kind;
|
|
|
|
|
isManualEdit = parsed.isManualEdit;
|
|
|
|
|
} catch {
|
|
|
|
|
return new ChatbotError(
|
|
|
|
|
"bad_request:api",
|
|
|
|
|
"Invalid request body."
|
|
|
|
|
).toResponse();
|
|
|
|
|
}
|
2024-10-30 16:01:24 +05:30
|
|
|
|
2025-04-14 10:34:11 -07:00
|
|
|
const documents = await getDocumentsById({ id });
|
2024-10-30 16:01:24 +05:30
|
|
|
|
2025-04-13 23:36:41 -07:00
|
|
|
if (documents.length > 0) {
|
2025-09-21 11:02:31 -07:00
|
|
|
const [doc] = documents;
|
2025-04-13 23:36:41 -07:00
|
|
|
|
2025-09-21 11:02:31 -07:00
|
|
|
if (doc.userId !== session.user.id) {
|
2026-02-23 17:24:17 -08:00
|
|
|
return new ChatbotError("forbidden:document").toResponse();
|
2025-04-13 23:36:41 -07:00
|
|
|
}
|
2024-10-30 16:01:24 +05:30
|
|
|
}
|
2025-03-05 10:03:17 -08:00
|
|
|
|
2026-03-20 09:37:02 +00:00
|
|
|
if (isManualEdit && documents.length > 0) {
|
|
|
|
|
const result = await updateDocumentContent({ id, content });
|
|
|
|
|
return Response.json(result, { status: 200 });
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-13 23:36:41 -07:00
|
|
|
const document = await saveDocument({
|
|
|
|
|
id,
|
|
|
|
|
content,
|
|
|
|
|
title,
|
|
|
|
|
kind,
|
|
|
|
|
userId: session.user.id,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return Response.json(document, { status: 200 });
|
2024-10-30 16:01:24 +05:30
|
|
|
}
|
|
|
|
|
|
2025-04-14 00:11:44 -07:00
|
|
|
export async function DELETE(request: Request) {
|
2024-10-30 16:01:24 +05:30
|
|
|
const { searchParams } = new URL(request.url);
|
2025-09-21 11:02:31 -07:00
|
|
|
const id = searchParams.get("id");
|
|
|
|
|
const timestamp = searchParams.get("timestamp");
|
2024-10-30 16:01:24 +05:30
|
|
|
|
|
|
|
|
if (!id) {
|
2026-02-23 17:24:17 -08:00
|
|
|
return new ChatbotError(
|
2025-09-21 11:02:31 -07:00
|
|
|
"bad_request:api",
|
|
|
|
|
"Parameter id is required."
|
2025-05-13 19:01:28 -07:00
|
|
|
).toResponse();
|
2024-10-30 16:01:24 +05:30
|
|
|
}
|
|
|
|
|
|
2025-04-14 00:11:44 -07:00
|
|
|
if (!timestamp) {
|
2026-02-23 17:24:17 -08:00
|
|
|
return new ChatbotError(
|
2025-09-21 11:02:31 -07:00
|
|
|
"bad_request:api",
|
|
|
|
|
"Parameter timestamp is required."
|
2025-05-13 19:01:28 -07:00
|
|
|
).toResponse();
|
2025-04-14 00:11:44 -07:00
|
|
|
}
|
|
|
|
|
|
2026-03-20 09:37:02 +00:00
|
|
|
const session = await auth();
|
2024-10-30 16:01:24 +05:30
|
|
|
|
2025-05-13 19:01:28 -07:00
|
|
|
if (!session?.user) {
|
2026-02-23 17:24:17 -08:00
|
|
|
return new ChatbotError("unauthorized:document").toResponse();
|
2024-10-30 16:01:24 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const documents = await getDocumentsById({ id });
|
|
|
|
|
|
|
|
|
|
const [document] = documents;
|
|
|
|
|
|
|
|
|
|
if (document.userId !== session.user.id) {
|
2026-02-23 17:24:17 -08:00
|
|
|
return new ChatbotError("forbidden:document").toResponse();
|
2024-10-30 16:01:24 +05:30
|
|
|
}
|
|
|
|
|
|
2026-03-20 09:37:02 +00:00
|
|
|
const parsedTimestamp = new Date(timestamp);
|
|
|
|
|
|
|
|
|
|
if (Number.isNaN(parsedTimestamp.getTime())) {
|
|
|
|
|
return new ChatbotError(
|
|
|
|
|
"bad_request:api",
|
|
|
|
|
"Invalid timestamp."
|
|
|
|
|
).toResponse();
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 10:34:11 -07:00
|
|
|
const documentsDeleted = await deleteDocumentsByIdAfterTimestamp({
|
2024-10-30 16:01:24 +05:30
|
|
|
id,
|
2026-03-20 09:37:02 +00:00
|
|
|
timestamp: parsedTimestamp,
|
2024-10-30 16:01:24 +05:30
|
|
|
});
|
|
|
|
|
|
2025-04-14 10:34:11 -07:00
|
|
|
return Response.json(documentsDeleted, { status: 200 });
|
2024-10-30 16:01:24 +05:30
|
|
|
}
|