import { MAX_SHARE_BYTES, putShare, takeShare, type SharedFile } from "@/lib/share-inbox"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; function asString(value: FormDataEntryValue | null): string | undefined { return typeof value === "string" && value.trim() ? value.trim().slice(0, 20_000) : undefined; } /** GET /share?id=… — read (and consume) a payload that was POSTed in. */ export async function GET(request: Request) { const id = new URL(request.url).searchParams.get("id"); if (!id) return Response.json({ error: "missing id" }, { status: 400 }); const payload = takeShare(id); if (!payload) return Response.json({ error: "expired" }, { status: 404 }); return Response.json(payload); } /** * POST /share — the Web Share Target. Text/URL arrive as form fields, files * as multipart uploads; both are stashed briefly and the browser is redirected * to the chooser page with an opaque id. */ export async function POST(request: Request) { let form: FormData; try { form = await request.formData(); } catch { return Response.redirect(new URL("/share?error=bad", request.url), 303); } const uploads = form.getAll("files").filter((entry): entry is File => entry instanceof File); const total = uploads.reduce((sum, file) => sum + file.size, 0); if (total > MAX_SHARE_BYTES) { return Response.redirect(new URL("/share?error=large", request.url), 303); } const files: SharedFile[] = []; for (const file of uploads.slice(0, 6)) { files.push({ name: file.name || "shared", type: file.type || "application/octet-stream", data: Buffer.from(await file.arrayBuffer()).toString("base64"), }); } const id = crypto.randomUUID(); putShare(id, { title: asString(form.get("title")), text: asString(form.get("text")), url: asString(form.get("url")), files, }); return Response.redirect(new URL(`/share?id=${id}`, request.url), 303); }