55 lines
1.5 KiB
TypeScript
Raw Normal View History

import { writeFileSync, mkdirSync } from "node:fs";
import { dirname } from "node:path";
import { safeResolveNewPath, isSystemFile } from "@/lib/workspace";
export const dynamic = "force-dynamic";
export const runtime = "nodejs";
/**
* POST /api/workspace/write-binary
* Accepts FormData with `file` (Blob) and `path` (string).
* Writes the binary data to the workspace path.
*/
export async function POST(req: Request) {
let formData: FormData;
try {
formData = await req.formData();
} catch {
return Response.json({ error: "Invalid form data" }, { status: 400 });
}
const file = formData.get("file");
const relPath = formData.get("path");
if (!relPath || typeof relPath !== "string") {
return Response.json({ error: "Missing 'path' field" }, { status: 400 });
}
if (!(file instanceof Blob)) {
return Response.json({ error: "Missing 'file' field (Blob)" }, { status: 400 });
}
if (isSystemFile(relPath)) {
return Response.json({ error: "Cannot modify system file" }, { status: 403 });
}
const absPath = safeResolveNewPath(relPath);
if (!absPath) {
return Response.json(
{ error: "Invalid path or path traversal rejected" },
{ status: 400 },
);
}
try {
const buffer = Buffer.from(await file.arrayBuffer());
mkdirSync(dirname(absPath), { recursive: true });
writeFileSync(absPath, buffer);
return Response.json({ ok: true, path: relPath });
} catch (err) {
return Response.json(
{ error: err instanceof Error ? err.message : "Write failed" },
{ status: 500 },
);
}
}