import { MaterialUploadRequestError, MaterialUploadRequestLimiter, } from '@/lib/material-upload-request-guard' import { MultipartRequestError } from '@/lib/multipart-request-guard' const MEBIBYTE = 1024 * 1024 /** * requestBytes intentionally include multipart framing headroom. File limits * remain the business boundary and must be rechecked after formData parsing. */ export const MULTIPART_ROUTE_LIMITS = Object.freeze({ legacyS3RequestBytes: 102 * MEBIBYTE, legacyS3FileBytes: 100 * MEBIBYTE, previewRequestBytes: 52 * MEBIBYTE, previewFileBytes: 50 * MEBIBYTE, skuArchiveRequestBytes: 130 * MEBIBYTE, skuArchiveFileBytes: 128 * MEBIBYTE, avatarRequestBytes: 6 * MEBIBYTE, avatarFileBytes: 5 * MEBIBYTE, materialUpdateRequestBytes: 10 * MEBIBYTE, materialUpdatePreviewBytes: 8 * MEBIBYTE, logoRequestBytes: 6 * MEBIBYTE, logoFileBytes: 5 * MEBIBYTE, psdRequestBytes: 130 * MEBIBYTE, whiteBackgroundRequestBytes: 105 * MEBIBYTE, }) // This limiter starts before formData(), so at most two large parsed multipart // bodies can coexist. CPU-heavy image/PDF work still has its own single slot. export const boundedMultipartRequestLimiter = new MaterialUploadRequestLimiter(2, 16) export function getBoundedMultipartFailure(error: unknown): { message: string status: number code: string retryAfterSeconds?: number } | null { if (error instanceof MultipartRequestError || error instanceof MaterialUploadRequestError) { return { message: error.message, status: error.status, code: error.code, ...('retryAfterSeconds' in error && error.retryAfterSeconds ? { retryAfterSeconds: error.retryAfterSeconds } : {}), } } return null }