From ad6de291150d76ad57ec09d4e68d98b4afba962e Mon Sep 17 00:00:00 2001 From: kovakmedya Date: Thu, 21 May 2026 21:15:36 +0300 Subject: [PATCH] fix(upload): use correct experimental.proxyClientMaxBodySize key + client-side size guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous attempt put 'middlewareClientMaxBodySize' at the top level of NextConfig — Next 16.1 rejected it as an unrecognised key. Inspecting the shipped config schema (node_modules/next/dist/server/config-schema.js) revealed the option lives under experimental and was renamed to 'proxyClientMaxBodySize' when middleware.ts → proxy.ts; the old name is still accepted but deprecated. Switched to the new name and confirmed Next now lists it in the Experiments banner at boot. While we were at it the cap was bumped to 500MB (was 100MB) so batch uploads have headroom over the 30MB-per-file bucket limit. Added a client-side pre-flight in JobFilesPanel: rejects individual files >30MB and total batches >400MB *before* hitting the server, with inline error messaging instead of a cryptic 'Unexpected end of form' bounce. Also raised serverActions.bodySizeLimit to 500mb to match. --- next.config.ts | 55 ++++++------------- .../[jobId]/components/job-files-panel.tsx | 30 ++++++++-- 2 files changed, 42 insertions(+), 43 deletions(-) diff --git a/next.config.ts b/next.config.ts index 10eb7a6..a113923 100644 --- a/next.config.ts +++ b/next.config.ts @@ -4,67 +4,44 @@ const nextConfig: NextConfig = { experimental: { optimizePackageImports: ["lucide-react", "@radix-ui/react-icons"], serverActions: { - // Job files bucket caps individual files at 30MB; raise overall body - // limit to allow batch uploads. - bodySizeLimit: "100mb", + // Job files bucket caps individual files at 30MB; allow batch uploads + // (multipart overhead + ~16 files of 30MB worst case). + bodySizeLimit: "500mb", }, + // Next 16 renamed `middlewareClientMaxBodySize` to `proxyClientMaxBodySize` + // (middleware.ts → proxy.ts). Default 10MB gates every body that flows + // through our auth proxy — without this override multipart uploads exceed + // the cap and the parser dies with "Unexpected end of form". + proxyClientMaxBodySize: "500mb", }, turbopack: {}, - // Image optimization images: { remotePatterns: [ - { - protocol: 'https', - hostname: 'ui.shadcn.com', - }, - { - protocol: 'https', - hostname: 'images.unsplash.com', - }, + { protocol: "https", hostname: "ui.shadcn.com" }, + { protocol: "https", hostname: "images.unsplash.com" }, ], - formats: ['image/webp', 'image/avif'], + formats: ["image/webp", "image/avif"], }, - // Headers for better security and performance async headers() { return [ { - source: '/(.*)', + source: "/(.*)", headers: [ - { - key: 'X-Frame-Options', - value: 'DENY', - }, - { - key: 'X-Content-Type-Options', - value: 'nosniff', - }, - { - key: 'Referrer-Policy', - value: 'origin-when-cross-origin', - }, + { key: "X-Frame-Options", value: "DENY" }, + { key: "X-Content-Type-Options", value: "nosniff" }, + { key: "Referrer-Policy", value: "origin-when-cross-origin" }, ], }, ]; }, - // Redirects for better SEO async redirects() { return [ - { - source: '/home', - destination: '/dashboard', - permanent: true, - }, + { source: "/home", destination: "/dashboard", permanent: true }, ]; }, }; -// Next 16 caps middleware-passed request bodies at 10MB by default. Our auth -// middleware sees every request including job-file uploads — without this -// override, multipart uploads larger than 10MB return "Unexpected end of -// form". The key isn't in NextConfig's TS types yet (Next 16.1). -(nextConfig as NextConfig & { middlewareClientMaxBodySize?: string }).middlewareClientMaxBodySize = "100mb"; - export default nextConfig; diff --git a/src/app/(dashboard)/jobs/[jobId]/components/job-files-panel.tsx b/src/app/(dashboard)/jobs/[jobId]/components/job-files-panel.tsx index 01e98d0..933eebe 100644 --- a/src/app/(dashboard)/jobs/[jobId]/components/job-files-panel.tsx +++ b/src/app/(dashboard)/jobs/[jobId]/components/job-files-panel.tsx @@ -63,6 +63,9 @@ export function JobFilesPanel({ ); } +const MAX_FILE_BYTES = 30 * 1024 * 1024; +const MAX_BATCH_BYTES = 400 * 1024 * 1024; // leaves headroom under the 500MB proxy cap + function UploadForm({ jobId }: { jobId: string }) { const [state, action, pending] = useActionState( uploadJobFilesAction, @@ -82,6 +85,11 @@ function UploadForm({ jobId }: { jobId: string }) { } }, [state]); + const totalBytes = selected.reduce((s, f) => s + f.size, 0); + const overSize = selected.find((f) => f.size > MAX_FILE_BYTES); + const overBatch = totalBytes > MAX_BATCH_BYTES; + const blocked = Boolean(overSize) || overBatch; + return (
- {selected.length > 0 - ? `${selected.length} dosya seçildi (${formatSize(selected.reduce((s, f) => s + f.size, 0))})` - : "Tarama (STL/OBJ), görsel veya PDF — max 30MB / dosya"} + {selected.length > 0 ? ( + overSize ? ( + + {overSize.name} 30MB'tan büyük (her dosya maksimum 30MB). + + ) : overBatch ? ( + + Toplam {formatSize(totalBytes)} — 400MB sınırını aşıyor. Daha az dosya seçin. + + ) : ( + <> + {selected.length} dosya seçildi ({formatSize(totalBytes)}) + + ) + ) : ( + "Tarama (STL/OBJ), görsel veya PDF — max 30MB / dosya" + )} -