"use client"; import { useEffect } from "react"; const MAX_FILES_PER_UPLOAD = 100; /** Keeps Payload's native multi-file picker from accepting an unbounded batch. */ export function UploadLimitGuard() { useEffect(() => { const attached = new WeakSet(); const limitedTransfer = (files: FileList) => { const transfer = new DataTransfer(); Array.from(files) .slice(0, MAX_FILES_PER_UPLOAD) .forEach((file) => transfer.items.add(file)); return transfer; }; const attachToFileInputs = () => { document.querySelectorAll('input[type="file"][multiple]').forEach((input) => { if (attached.has(input)) return; attached.add(input); input.addEventListener("change", () => { if (!input.files || input.files.length <= MAX_FILES_PER_UPLOAD) return; try { input.files = limitedTransfer(input.files).files; } catch { // Older browsers can expose a read-only FileList. Payload still // receives the original selection there and can process it. } }); }); }; const limitDroppedFiles = (event: DragEvent) => { const files = event.dataTransfer?.files; if (!files || files.length <= MAX_FILES_PER_UPLOAD || !(event.target instanceof Element)) return; event.preventDefault(); event.stopPropagation(); try { event.target.dispatchEvent( new DragEvent("drop", { bubbles: true, cancelable: true, dataTransfer: limitedTransfer(files), }), ); } catch { // If a browser cannot construct a replacement drag event, the native // picker still enforces the same limit for normal file selection. } }; attachToFileInputs(); document.addEventListener("drop", limitDroppedFiles, true); const observer = new MutationObserver(attachToFileInputs); observer.observe(document.body, { childList: true, subtree: true }); return () => { document.removeEventListener("drop", limitDroppedFiles, true); observer.disconnect(); }; }, []); return null; }