From da440735d40c9a9b5c208592f2f13a2322a215a5 Mon Sep 17 00:00:00 2001 From: kumarabhirup Date: Wed, 4 Mar 2026 11:14:14 -0800 Subject: [PATCH] feat(web): add workspace binary write API endpoint --- .../app/api/workspace/write-binary/route.ts | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 apps/web/app/api/workspace/write-binary/route.ts diff --git a/apps/web/app/api/workspace/write-binary/route.ts b/apps/web/app/api/workspace/write-binary/route.ts new file mode 100644 index 00000000000..6d74c5e2271 --- /dev/null +++ b/apps/web/app/api/workspace/write-binary/route.ts @@ -0,0 +1,54 @@ +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 }, + ); + } +}