diff --git a/server/src/api/middleware/handleErrors.ts b/server/src/api/middleware/handleErrors.ts index ff591484f..2f817b2af 100755 --- a/server/src/api/middleware/handleErrors.ts +++ b/server/src/api/middleware/handleErrors.ts @@ -1,11 +1,16 @@ import type { NextFunction, Request, Response } from "express"; +import { MulterError } from "multer"; import { logger } from "@/utils/logger.js"; import { AppError } from "@/utils/AppError.js"; +// Multer throws MulterError, send 413 Payload Too Large / 400 +const multerErrorStatus = (error: MulterError): number => (error.code === "LIMIT_FILE_SIZE" ? 413 : 400); + const handleErrors = (error: unknown, req: Request, res: Response, _next: NextFunction) => { - const status = error instanceof AppError ? error.status || 500 : 500; + const status = + error instanceof MulterError ? multerErrorStatus(error) : error instanceof AppError ? error.status || 500 : 500; const message = error instanceof AppError ? error.message : error instanceof Error ? error.message : "Server error"; - const service = error instanceof AppError ? error.service : "unknownService"; + const service = error instanceof AppError ? error.service : error instanceof MulterError ? "uploadMiddleware" : "unknownService"; const method = error instanceof AppError ? error.method : "unknownMethod"; logger.error({ message: message, diff --git a/server/src/api/middleware/upload.ts b/server/src/api/middleware/upload.ts new file mode 100644 index 000000000..c3f257884 --- /dev/null +++ b/server/src/api/middleware/upload.ts @@ -0,0 +1,27 @@ +import multer from "multer"; +import { AppError } from "@/utils/AppError.js"; +import { ImageMimeTypes, MAX_IMAGE_SIZE_BYTES } from "@/types/upload.js"; + +// Reusable multer instance for handling image uploads +const imageUpload = multer({ + limits: { + fileSize: MAX_IMAGE_SIZE_BYTES, + files: 1, + }, + fileFilter: (_req, file, cb) => { + if (!(ImageMimeTypes as readonly string[]).includes(file.mimetype)) { + cb( + new AppError({ + status: 415, + message: "File must be a valid image (jpeg, jpg, or png)", + service: "uploadMiddleware", + method: "fileFilter", + }) + ); + return; + } + cb(null, true); + }, +}); + +export { imageUpload };