87 lines
2.5 KiB
TypeScript
87 lines
2.5 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { prisma } from "@/lib/db";
|
|
import { getSessionUser } from "@/lib/auth";
|
|
import { uploadToR2 } from "@/lib/r2";
|
|
|
|
const MAX_UPLOAD_SIZE = 10 * 1024 * 1024 * 1024; // 10GB in bytes
|
|
|
|
function serializeFile(file: Awaited<ReturnType<typeof prisma.file.create>>) {
|
|
return {
|
|
id: file.id,
|
|
key: file.key,
|
|
name: file.name,
|
|
relativePath: file.relativePath,
|
|
contentType: file.contentType,
|
|
sizeBytes: Number(file.sizeBytes),
|
|
createdAt: file.createdAt,
|
|
};
|
|
}
|
|
|
|
export async function POST(req: Request) {
|
|
try {
|
|
const session = await getSessionUser();
|
|
if (!session) {
|
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
}
|
|
|
|
const formData = await req.formData();
|
|
const files = formData.getAll("files") as File[];
|
|
|
|
if (!files.length) {
|
|
return NextResponse.json(
|
|
{ error: "No files received in 'files' field." },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
// Check total upload size
|
|
const totalSize = files.reduce((acc, file) => acc + (file instanceof File ? file.size : 0), 0);
|
|
if (totalSize > MAX_UPLOAD_SIZE) {
|
|
return NextResponse.json(
|
|
{ error: "Total upload size exceeds 10GB limit." },
|
|
{ status: 413 }
|
|
);
|
|
}
|
|
|
|
const uploaded = [];
|
|
for (const file of files) {
|
|
if (!(file instanceof File)) continue;
|
|
|
|
const arrayBuffer = await file.arrayBuffer();
|
|
const buffer = Buffer.from(arrayBuffer);
|
|
const fileWithPath = file as File & { webkitRelativePath?: string };
|
|
const relativePath =
|
|
fileWithPath.webkitRelativePath ?? fileWithPath.name ?? "unnamed";
|
|
const normalizedPath = relativePath.replace(/\\/g, "/");
|
|
const name = normalizedPath.split("/").pop() ?? normalizedPath;
|
|
const key = `${session.userId}/${Date.now()}-${normalizedPath}`;
|
|
const contentType = file.type || "application/octet-stream";
|
|
|
|
await uploadToR2({
|
|
key,
|
|
contentType,
|
|
body: buffer,
|
|
});
|
|
|
|
const record = await prisma.file.create({
|
|
data: {
|
|
key,
|
|
name,
|
|
relativePath: normalizedPath,
|
|
contentType,
|
|
sizeBytes: BigInt(file.size),
|
|
userId: session.userId,
|
|
},
|
|
});
|
|
|
|
uploaded.push(serializeFile(record));
|
|
}
|
|
|
|
return NextResponse.json({ ok: true, files: uploaded });
|
|
} catch (error) {
|
|
console.error("Upload error:", error);
|
|
const message = error instanceof Error ? error.message : "Upload failed";
|
|
return NextResponse.json({ error: message }, { status: 500 });
|
|
}
|
|
}
|