fix(pdf-compress): bypass middleware body buffering for upload routes

Next.js middleware buffers the entire request body (10MB default limit)
before the route handler runs. middlewareClientMaxBodySize experimental
flag doesn't work reliably with standalone output.

Solution: exclude api/compress-pdf from middleware matcher so the body
streams directly to the route handler. Auth check moved to a shared
helper (auth-check.ts) called at the start of each route.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
AI Assistant
2026-03-13 19:54:28 +02:00
parent 003a2821fd
commit 4b5d3bd498
4 changed files with 34 additions and 1 deletions
+25
View File
@@ -0,0 +1,25 @@
import { NextRequest, NextResponse } from "next/server";
import { getToken } from "next-auth/jwt";
/**
* Check auth for routes excluded from middleware (large upload routes).
* Returns null if authenticated, or a 401 NextResponse if not.
*/
export async function requireAuth(
req: NextRequest,
): Promise<NextResponse | null> {
// Skip in development
if (process.env.NODE_ENV === "development") return null;
const token = await getToken({
req,
secret: process.env.NEXTAUTH_SECRET,
});
if (token) return null;
return NextResponse.json(
{ error: "Authentication required" },
{ status: 401 },
);
}
+4
View File
@@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
import { readFile, unlink } from "fs/promises";
import { join } from "path";
import { parseMultipartUpload } from "../parse-upload";
import { requireAuth } from "../auth-check";
/**
* iLovePDF API integration for PDF compression.
@@ -30,6 +31,9 @@ async function cleanup(dir: string) {
}
export async function POST(req: NextRequest) {
const authError = await requireAuth(req);
if (authError) return authError;
if (!ILOVEPDF_PUBLIC_KEY) {
return NextResponse.json(
{
@@ -6,6 +6,7 @@ import { promisify } from "util";
import { join } from "path";
import { Readable } from "stream";
import { parseMultipartUpload } from "../parse-upload";
import { requireAuth } from "../auth-check";
const execFileAsync = promisify(execFile);
@@ -58,6 +59,9 @@ function streamFileResponse(
}
export async function POST(req: NextRequest) {
const authError = await requireAuth(req);
if (authError) return authError;
let tmpDir = "";
try {
const upload = await parseMultipartUpload(req);
+1 -1
View File
@@ -46,6 +46,6 @@ export const config = {
* - /favicon.ico, /robots.txt, /sitemap.xml
* - Files with extensions (images, fonts, etc.)
*/
"/((?!api/auth|api/notifications/digest|auth/signin|_next|favicon\\.ico|robots\\.txt|sitemap\\.xml|.*\\..*).*)",
"/((?!api/auth|api/notifications/digest|api/compress-pdf|auth/signin|_next|favicon\\.ico|robots\\.txt|sitemap\\.xml|.*\\..*).*)",
],
};