Files
ArchiTools/src/app/api/compress-pdf/route.ts
T
AI Assistant 9e73dc3cb9 fix(pdf-compress): use arrayBuffer() instead of formData() for large files
formData() fails with "Failed to parse body as FormData" on large PDFs
in Next.js route handlers. Switch to req.arrayBuffer() which reliably
reads the full body, then manually extract the PDF from multipart.

Extreme mode: arrayBuffer + multipart extraction + GS + qpdf pipeline.
Stirling mode: arrayBuffer forwarding to Stirling with proper headers.

Revert serverActions.bodySizeLimit (doesn't apply to route handlers).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 16:32:05 +02:00

57 lines
1.9 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
const STIRLING_PDF_URL =
process.env.STIRLING_PDF_URL ?? "http://10.10.10.166:8087";
const STIRLING_PDF_API_KEY =
process.env.STIRLING_PDF_API_KEY ?? "cd829f62-6eef-43eb-a64d-c91af727b53a";
export async function POST(req: NextRequest) {
try {
// Buffer the full body then forward to Stirling — streaming passthrough
// (req.body + duplex:half) is unreliable for large files in Next.js.
const bodyBytes = await req.arrayBuffer();
const contentType = req.headers.get("content-type") || "";
// Extract original file size from the multipart body for the response header
// (rough estimate — the overhead of multipart framing is negligible for large PDFs)
const originalSize = bodyBytes.byteLength;
const res = await fetch(`${STIRLING_PDF_URL}/api/v1/misc/compress-pdf`, {
method: "POST",
headers: {
"X-API-KEY": STIRLING_PDF_API_KEY,
"Content-Type": contentType,
},
body: bodyBytes,
signal: AbortSignal.timeout(300_000), // 5 min for large files
});
if (!res.ok) {
const text = await res.text().catch(() => res.statusText);
return NextResponse.json(
{ error: `Stirling PDF error: ${res.status}${text}` },
{ status: res.status },
);
}
const blob = await res.blob();
const buffer = Buffer.from(await blob.arrayBuffer());
return new NextResponse(new Uint8Array(buffer), {
status: 200,
headers: {
"Content-Type": "application/pdf",
"Content-Disposition": 'attachment; filename="compressed.pdf"',
"X-Original-Size": String(originalSize),
"X-Compressed-Size": String(buffer.length),
},
});
} catch (err) {
const message = err instanceof Error ? err.message : "Unknown error";
return NextResponse.json(
{ error: `Nu s-a putut contacta Stirling PDF: ${message}` },
{ status: 502 },
);
}
}