multermate 1.1.1 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -3,30 +3,158 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ALLOWED_FILE_TYPES = void 0;
6
+ exports.MIME_TYPES = exports.ALLOWED_FILE_TYPES = exports.MultermateError = void 0;
7
7
  exports.uploadSingle = uploadSingle;
8
8
  exports.uploadMultiple = uploadMultiple;
9
9
  exports.deleteFile = deleteFile;
10
10
  const promises_1 = __importDefault(require("fs/promises"));
11
+ const fs_1 = require("fs");
11
12
  const multer_1 = __importDefault(require("multer"));
12
13
  const path_1 = __importDefault(require("path"));
13
14
  const uuid_1 = require("uuid");
14
- // Define allowed MIME types
15
+ // Custom error class for MulterMate
16
+ class MultermateError extends Error {
17
+ constructor(message, code, field) {
18
+ super(message);
19
+ this.name = 'MultermateError';
20
+ this.code = code;
21
+ this.field = field;
22
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
23
+ if (Error.captureStackTrace) {
24
+ Error.captureStackTrace(this, MultermateError);
25
+ }
26
+ }
27
+ }
28
+ exports.MultermateError = MultermateError;
29
+ // Define allowed MIME types - comprehensive list including all common file types
15
30
  const ALLOWED_MIME_TYPES = {
16
- images: ["image/jpeg", "image/jpg", "image/png", "image/gif"],
17
- videos: ["video/mp4", "video/mpeg", "video/ogg", "video/webm", "video/avi"],
31
+ // Images (all common image formats)
32
+ images: [
33
+ "image/jpeg", "image/jpg", "image/png", "image/gif", "image/webp",
34
+ "image/svg+xml", "image/bmp", "image/tiff", "image/ico", "image/avif",
35
+ "image/heic", "image/heif", "image/x-icon", "image/vnd.microsoft.icon"
36
+ ],
37
+ // Videos (all common video formats)
38
+ videos: [
39
+ "video/mp4", "video/mpeg", "video/ogg", "video/webm", "video/avi",
40
+ "video/mov", "video/wmv", "video/flv", "video/mkv", "video/m4v", "video/3gp",
41
+ "video/quicktime", "video/x-msvideo", "video/x-ms-wmv", "video/x-flv"
42
+ ],
43
+ // Audio (all common audio formats)
44
+ audio: [
45
+ "audio/mpeg", "audio/wav", "audio/ogg", "audio/aac", "audio/flac",
46
+ "audio/m4a", "audio/wma", "audio/mp3", "audio/webm", "audio/x-wav",
47
+ "audio/x-m4a", "audio/x-aac", "audio/opus", "audio/amr"
48
+ ],
49
+ // Documents (all common document formats)
50
+ documents: [
51
+ "application/pdf", "application/msword",
52
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
53
+ "application/vnd.ms-excel",
54
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
55
+ "application/vnd.ms-powerpoint",
56
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
57
+ "application/rtf", "application/vnd.oasis.opendocument.text",
58
+ "application/vnd.oasis.opendocument.spreadsheet", "application/vnd.oasis.opendocument.presentation",
59
+ "application/vnd.apple.pages", "application/vnd.apple.numbers", "application/vnd.apple.keynote"
60
+ ],
61
+ // Text files (all common text formats)
62
+ text: [
63
+ "text/plain", "text/csv", "text/html", "text/css", "text/javascript",
64
+ "text/xml", "text/markdown", "text/x-python", "text/x-java-source",
65
+ "text/x-c", "text/x-c++", "text/x-php", "text/x-ruby", "text/x-go",
66
+ "text/x-rust", "text/x-typescript", "text/x-swift", "text/x-kotlin",
67
+ "text/x-scala", "text/x-perl", "text/x-shell", "text/x-sh", "text/x-bash",
68
+ "text/x-yaml", "text/yaml", "text/x-toml", "text/x-ini", "text/x-log"
69
+ ],
70
+ // Archives (all common archive formats)
71
+ archives: [
72
+ "application/zip", "application/x-rar-compressed", "application/x-tar",
73
+ "application/gzip", "application/x-7z-compressed", "application/x-bzip2",
74
+ "application/x-xz", "application/x-compress", "application/x-lz4",
75
+ "application/x-lzma", "application/vnd.rar"
76
+ ],
77
+ // Code files (programming language files)
78
+ code: [
79
+ "application/json", "application/xml", "application/javascript",
80
+ "application/typescript", "text/x-python", "text/x-java-source",
81
+ "text/x-c", "text/x-c++", "text/x-php", "text/x-ruby", "text/x-go",
82
+ "text/x-rust", "text/x-swift", "text/x-kotlin", "text/x-scala",
83
+ "text/x-csharp", "text/x-vb", "text/x-sql", "application/sql"
84
+ ],
85
+ // Spreadsheets (separate category)
86
+ spreadsheets: [
87
+ "application/vnd.ms-excel",
88
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
89
+ "text/csv", "application/csv"
90
+ ],
91
+ // Presentations (separate category)
92
+ presentations: [
93
+ "application/vnd.ms-powerpoint",
94
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
95
+ "application/vnd.oasis.opendocument.presentation"
96
+ ],
97
+ // Fonts (font files)
98
+ fonts: [
99
+ "font/woff", "font/woff2", "font/ttf", "font/otf", "font/eot",
100
+ "application/font-woff", "application/font-woff2", "application/x-font-ttf",
101
+ "application/x-font-otf", "application/vnd.ms-fontobject"
102
+ ],
103
+ // CAD files
104
+ cad: [
105
+ "application/dwg", "application/dxf", "model/vnd.dwf",
106
+ "application/acad", "image/vnd.dwg"
107
+ ],
108
+ // 3D models
109
+ models: [
110
+ "model/obj", "model/gltf+json", "model/gltf-binary", "model/x3d+xml",
111
+ "model/stl", "model/ply", "application/x-blender"
112
+ ],
113
+ // PDFs (separate category for backward compatibility)
18
114
  pdfs: ["application/pdf"],
115
+ // All allowed types - comprehensive list (this is for backward compatibility)
19
116
  all: [
20
- "image/jpeg",
21
- "image/jpg",
22
- "image/png",
23
- "image/gif",
24
- "video/mp4",
25
- "video/mpeg",
26
- "video/ogg",
27
- "video/webm",
28
- "video/avi",
29
- "application/pdf",
117
+ // Images
118
+ "image/jpeg", "image/jpg", "image/png", "image/gif", "image/webp",
119
+ "image/svg+xml", "image/bmp", "image/tiff", "image/ico", "image/avif",
120
+ "image/heic", "image/heif", "image/x-icon", "image/vnd.microsoft.icon",
121
+ // Videos
122
+ "video/mp4", "video/mpeg", "video/ogg", "video/webm", "video/avi",
123
+ "video/mov", "video/wmv", "video/flv", "video/mkv", "video/m4v", "video/3gp",
124
+ "video/quicktime", "video/x-msvideo", "video/x-ms-wmv", "video/x-flv",
125
+ // Audio
126
+ "audio/mpeg", "audio/wav", "audio/ogg", "audio/aac", "audio/flac",
127
+ "audio/m4a", "audio/wma", "audio/mp3", "audio/webm", "audio/x-wav",
128
+ "audio/x-m4a", "audio/x-aac", "audio/opus", "audio/amr",
129
+ // Documents
130
+ "application/pdf", "application/msword",
131
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
132
+ "application/vnd.ms-excel",
133
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
134
+ "application/vnd.ms-powerpoint",
135
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
136
+ "application/rtf", "application/vnd.oasis.opendocument.text",
137
+ "application/vnd.oasis.opendocument.spreadsheet", "application/vnd.oasis.opendocument.presentation",
138
+ "application/vnd.apple.pages", "application/vnd.apple.numbers", "application/vnd.apple.keynote",
139
+ // Text files
140
+ "text/plain", "text/csv", "text/html", "text/css", "text/javascript",
141
+ "text/xml", "text/markdown", "text/x-python", "text/x-java-source",
142
+ "text/x-c", "text/x-c++", "text/x-php", "text/x-ruby", "text/x-go",
143
+ "text/x-rust", "text/x-typescript", "text/x-swift", "text/x-kotlin",
144
+ "text/x-scala", "text/x-perl", "text/x-shell", "text/x-sh", "text/x-bash",
145
+ "text/x-yaml", "text/yaml", "text/x-toml", "text/x-ini", "text/x-log",
146
+ // Archives
147
+ "application/zip", "application/x-rar-compressed", "application/x-tar",
148
+ "application/gzip", "application/x-7z-compressed", "application/x-bzip2",
149
+ "application/x-xz", "application/x-compress", "application/x-lz4",
150
+ "application/x-lzma", "application/vnd.rar",
151
+ // Code/Data
152
+ "application/json", "application/xml", "application/javascript",
153
+ "application/typescript", "text/x-csharp", "text/x-vb", "text/x-sql", "application/sql",
154
+ // Fonts
155
+ "font/woff", "font/woff2", "font/ttf", "font/otf", "font/eot",
156
+ "application/font-woff", "application/font-woff2", "application/x-font-ttf",
157
+ "application/x-font-otf", "application/vnd.ms-fontobject"
30
158
  ],
31
159
  };
32
160
  /**
@@ -37,36 +165,65 @@ const ALLOWED_MIME_TYPES = {
37
165
  */
38
166
  const configureStorage = (destination) => {
39
167
  return multer_1.default.diskStorage({
40
- destination: (_req, _file, cb) => {
41
- cb(null, destination || "uploads"); // Default folder is "uploads" if none is provided.
168
+ destination: (req, file, cb) => {
169
+ const dir = destination || "uploads";
170
+ // Create directory synchronously - multer destination callback doesn't support async
171
+ try {
172
+ (0, fs_1.mkdirSync)(dir, { recursive: true });
173
+ cb(null, dir);
174
+ }
175
+ catch (error) {
176
+ // Directory might already exist, that's okay
177
+ if (error.code === 'EEXIST') {
178
+ cb(null, dir);
179
+ }
180
+ else {
181
+ cb(new MultermateError(`Failed to create destination directory: ${dir}. Error: ${error.message}`, 'DESTINATION_ERROR'), '');
182
+ }
183
+ }
42
184
  },
43
185
  filename: (_req, file, cb) => {
44
- const sanitizedFilename = file.originalname.replace(/\\/g, "/");
45
- const extension = path_1.default.extname(sanitizedFilename);
46
- const fieldName = file.fieldname || "file"; // Use the field name as part of the filename.
47
- const uniqueName = (0, uuid_1.v4)(); // Generate a unique name using uuid.
48
- let fileName = `${uniqueName}-${fieldName}${extension}`;
49
- // Replace backslashes with forward slashes in the final filename
50
- fileName = fileName.replace(/\\/g, "/");
51
- cb(null, fileName); // Set the final filename.
186
+ try {
187
+ const sanitizedFilename = file.originalname.replace(/\\/g, "/");
188
+ const extension = path_1.default.extname(sanitizedFilename);
189
+ const fieldName = file.fieldname || "file";
190
+ const uniqueName = (0, uuid_1.v4)();
191
+ let fileName = `${uniqueName}-${fieldName}${extension}`;
192
+ // Replace backslashes with forward slashes in the final filename
193
+ fileName = fileName.replace(/\\/g, "/");
194
+ cb(null, fileName);
195
+ }
196
+ catch (error) {
197
+ cb(new MultermateError('Failed to generate filename', 'FILENAME_ERROR'), '');
198
+ }
52
199
  },
53
200
  });
54
201
  };
55
202
  /**
56
203
  * Function to configure file filter for Multer.
57
204
  *
58
- * @param allowedMimeTypes - Array of allowed MIME types.
205
+ * @param allowedMimeTypes - Array of allowed MIME types. Empty array means allow all file types.
59
206
  * @returns File filter function for Multer.
60
207
  */
61
208
  const configureFileFilter = (allowedMimeTypes) => {
62
209
  return (_req, file, cb) => {
63
- if (allowedMimeTypes.includes(file.mimetype)) {
64
- cb(null, true); // Allow the file if its MIME type is allowed.
210
+ try {
211
+ // If no specific file types are restricted, allow ALL file types
212
+ if (allowedMimeTypes.length === 0) {
213
+ cb(null, true);
214
+ return;
215
+ }
216
+ // Check if the file's MIME type is in the allowed list
217
+ if (allowedMimeTypes.includes(file.mimetype)) {
218
+ cb(null, true);
219
+ }
220
+ else {
221
+ const error = new MultermateError(`Invalid file type: ${file.mimetype}. Allowed types: ${allowedMimeTypes.join(', ')}`, 'INVALID_FILE_TYPE', file.fieldname);
222
+ cb(error);
223
+ }
65
224
  }
66
- else {
67
- const error = new Error("Invalid file type. Only specified file types are allowed.");
68
- error.code = 'INVALID_FILE_TYPE';
69
- cb(error); // Reject the file if its MIME type is not allowed.
225
+ catch (error) {
226
+ cb(new MultermateError('File filter error', 'FILTER_ERROR'));
70
227
  }
71
228
  };
72
229
  };
@@ -77,32 +234,37 @@ const configureFileFilter = (allowedMimeTypes) => {
77
234
  * @returns Multer instance configured with the provided options.
78
235
  */
79
236
  const configureMulter = ({ destination, filename, fileTypes = [], customMimeTypes = [], fileSizeLimit, preservePath = false, }) => {
80
- const storage = configureStorage(destination);
81
- // Combine allowed MIME types based on fileTypes array
82
- let allowedMimeTypes = [];
83
- if (customMimeTypes.length > 0) {
84
- // Use custom MIME types if provided
85
- allowedMimeTypes = customMimeTypes;
86
- }
87
- else {
88
- // Use default MIME types for specified fileTypes
89
- fileTypes.forEach((type) => {
90
- if (ALLOWED_MIME_TYPES[type]) {
91
- allowedMimeTypes = allowedMimeTypes.concat(ALLOWED_MIME_TYPES[type]);
92
- }
93
- });
94
- // If no specific file types are provided, use all allowed MIME types
95
- if (allowedMimeTypes.length === 0) {
96
- allowedMimeTypes = ALLOWED_MIME_TYPES.all;
237
+ try {
238
+ const storage = configureStorage(destination);
239
+ // Combine allowed MIME types based on fileTypes array
240
+ let allowedMimeTypes = [];
241
+ if (customMimeTypes.length > 0) {
242
+ // Use custom MIME types if provided
243
+ allowedMimeTypes = customMimeTypes;
244
+ }
245
+ else if (fileTypes.length > 0) {
246
+ // Use default MIME types for specified fileTypes
247
+ fileTypes.forEach((type) => {
248
+ if (ALLOWED_MIME_TYPES[type]) {
249
+ allowedMimeTypes = allowedMimeTypes.concat(ALLOWED_MIME_TYPES[type]);
250
+ }
251
+ });
97
252
  }
253
+ // If neither customMimeTypes nor fileTypes are provided, allowedMimeTypes remains empty
254
+ // This means ALL file types are allowed (no restrictions)
255
+ // Remove duplicates
256
+ allowedMimeTypes = [...new Set(allowedMimeTypes)];
257
+ const fileFilter = configureFileFilter(allowedMimeTypes);
258
+ return (0, multer_1.default)({
259
+ storage,
260
+ fileFilter,
261
+ limits: { fileSize: fileSizeLimit || 1024 * 1024 * 50 }, // Default 50MB file size limit
262
+ preservePath,
263
+ });
264
+ }
265
+ catch (error) {
266
+ throw new MultermateError('Failed to configure multer', 'CONFIGURATION_ERROR');
98
267
  }
99
- const fileFilter = configureFileFilter(allowedMimeTypes);
100
- return (0, multer_1.default)({
101
- storage,
102
- fileFilter,
103
- limits: { fileSize: fileSizeLimit || 1024 * 1024 * 50 }, // Default 50MB file size limit
104
- preservePath,
105
- });
106
268
  };
107
269
  /**
108
270
  * Function to handle a single file upload.
@@ -111,28 +273,53 @@ const configureMulter = ({ destination, filename, fileTypes = [], customMimeType
111
273
  * @returns Multer middleware configured for single file upload.
112
274
  */
113
275
  function uploadSingle(options = {}) {
114
- // Create destination directory if it doesn't exist
115
- const destination = options.destination || 'uploads';
116
- const multerInstance = configureMulter(options);
117
- const middleware = multerInstance.single(options.filename || "file");
118
- return (req, res, next) => {
119
- // Make sure the destination directory exists
120
- require('fs').mkdirSync(destination, { recursive: true });
121
- middleware(req, res, (err) => {
122
- if (err) {
123
- if (err.code === 'LIMIT_FILE_SIZE') {
124
- req.fileValidationError = 'File size limit exceeded';
125
- }
126
- else if (err.code === 'INVALID_FILE_TYPE') {
127
- req.fileValidationError = 'Invalid file type';
128
- }
129
- else {
130
- req.fileValidationError = err.message;
131
- }
276
+ try {
277
+ const destination = options.destination || 'uploads';
278
+ const multerInstance = configureMulter(options);
279
+ const middleware = multerInstance.single(options.filename || "file");
280
+ return (req, res, next) => {
281
+ // Make sure the destination directory exists
282
+ try {
283
+ (0, fs_1.mkdirSync)(destination, { recursive: true });
132
284
  }
133
- next();
134
- });
135
- };
285
+ catch (error) {
286
+ // Directory might already exist, ignore error
287
+ }
288
+ middleware(req, res, (err) => {
289
+ if (err) {
290
+ let errorMessage = 'Unknown upload error';
291
+ let errorCode = 'UPLOAD_ERROR';
292
+ if (err instanceof MultermateError) {
293
+ // Our custom error
294
+ req.fileValidationError = err.message;
295
+ return next(err);
296
+ }
297
+ else if (err.code === 'LIMIT_FILE_SIZE') {
298
+ errorMessage = `File size limit exceeded. Maximum allowed size: ${options.fileSizeLimit || '50MB'}`;
299
+ errorCode = 'FILE_SIZE_LIMIT_EXCEEDED';
300
+ }
301
+ else if (err.code === 'INVALID_FILE_TYPE') {
302
+ errorMessage = 'Invalid file type. Please check allowed file types.';
303
+ errorCode = 'INVALID_FILE_TYPE';
304
+ }
305
+ else if (err.code === 'LIMIT_UNEXPECTED_FILE') {
306
+ errorMessage = 'Unexpected field';
307
+ errorCode = 'UNEXPECTED_FIELD';
308
+ }
309
+ else {
310
+ errorMessage = err.message || 'Upload failed';
311
+ }
312
+ const multermateError = new MultermateError(errorMessage, errorCode);
313
+ req.fileValidationError = errorMessage;
314
+ return next(multermateError);
315
+ }
316
+ next();
317
+ });
318
+ };
319
+ }
320
+ catch (error) {
321
+ throw new MultermateError('Failed to create upload middleware', 'MIDDLEWARE_CREATION_ERROR');
322
+ }
136
323
  }
137
324
  /**
138
325
  * Function to handle multiple file uploads across multiple fields.
@@ -141,48 +328,86 @@ function uploadSingle(options = {}) {
141
328
  * @returns Multer middleware configured for multiple file uploads.
142
329
  */
143
330
  function uploadMultiple(options) {
144
- const destination = options.destination || 'uploads';
145
- // Map fields configuration to multer format
146
- const fieldConfigs = options.fields.map(field => ({
147
- name: field.name,
148
- maxCount: field.maxCount || 10, // Default maxCount is 10 if not specified.
149
- }));
150
- let allowedFileTypes = [];
151
- options.fields.forEach((field) => {
152
- const types = field.fileTypes || [];
153
- types.forEach((type) => {
154
- if (ALLOWED_MIME_TYPES[type]) {
155
- allowedFileTypes = allowedFileTypes.concat(ALLOWED_MIME_TYPES[type]);
331
+ try {
332
+ const destination = options.destination || 'uploads';
333
+ // Map fields configuration to multer format
334
+ const fieldConfigs = options.fields.map(field => ({
335
+ name: field.name,
336
+ maxCount: field.maxCount || 10, // Default maxCount is 10 if not specified.
337
+ }));
338
+ // Collect all allowed file types from fields
339
+ let allowedFileTypes = [];
340
+ if (options.customMimeTypes && options.customMimeTypes.length > 0) {
341
+ // Use custom MIME types if provided at the global level
342
+ allowedFileTypes = options.customMimeTypes;
343
+ }
344
+ else {
345
+ // Collect file types from individual fields
346
+ options.fields.forEach((field) => {
347
+ const types = field.fileTypes || [];
348
+ types.forEach((type) => {
349
+ if (ALLOWED_MIME_TYPES[type]) {
350
+ allowedFileTypes = allowedFileTypes.concat(ALLOWED_MIME_TYPES[type]);
351
+ }
352
+ });
353
+ });
354
+ }
355
+ const multerConfig = {
356
+ destination,
357
+ fileTypes: [],
358
+ customMimeTypes: allowedFileTypes.length > 0 ? allowedFileTypes : [],
359
+ fileSizeLimit: options.fileSizeLimit,
360
+ preservePath: options.preservePath
361
+ };
362
+ const multerInstance = configureMulter(multerConfig);
363
+ const middleware = multerInstance.fields(fieldConfigs);
364
+ return (req, res, next) => {
365
+ // Make sure the destination directory exists
366
+ try {
367
+ (0, fs_1.mkdirSync)(destination, { recursive: true });
156
368
  }
157
- });
158
- });
159
- const multerConfig = {
160
- destination,
161
- fileTypes: [],
162
- customMimeTypes: options.customMimeTypes || [],
163
- fileSizeLimit: options.fileSizeLimit,
164
- preservePath: options.preservePath
165
- };
166
- const multerInstance = configureMulter(multerConfig);
167
- const middleware = multerInstance.fields(fieldConfigs);
168
- return (req, res, next) => {
169
- // Make sure the destination directory exists
170
- require('fs').mkdirSync(destination, { recursive: true });
171
- middleware(req, res, (err) => {
172
- if (err) {
173
- if (err.code === 'LIMIT_FILE_SIZE') {
174
- req.fileValidationError = 'File size limit exceeded';
175
- }
176
- else if (err.code === 'INVALID_FILE_TYPE') {
177
- req.fileValidationError = 'Invalid file type';
178
- }
179
- else {
180
- req.fileValidationError = err.message;
181
- }
369
+ catch (error) {
370
+ // Directory might already exist, ignore error
182
371
  }
183
- next();
184
- });
185
- };
372
+ middleware(req, res, (err) => {
373
+ if (err) {
374
+ let errorMessage = 'Unknown upload error';
375
+ let errorCode = 'UPLOAD_ERROR';
376
+ if (err instanceof MultermateError) {
377
+ // Our custom error
378
+ req.fileValidationError = err.message;
379
+ return next(err);
380
+ }
381
+ else if (err.code === 'LIMIT_FILE_SIZE') {
382
+ errorMessage = `File size limit exceeded. Maximum allowed size: ${options.fileSizeLimit || '50MB'}`;
383
+ errorCode = 'FILE_SIZE_LIMIT_EXCEEDED';
384
+ }
385
+ else if (err.code === 'INVALID_FILE_TYPE') {
386
+ errorMessage = 'Invalid file type. Please check allowed file types.';
387
+ errorCode = 'INVALID_FILE_TYPE';
388
+ }
389
+ else if (err.code === 'LIMIT_UNEXPECTED_FILE') {
390
+ errorMessage = 'Unexpected field';
391
+ errorCode = 'UNEXPECTED_FIELD';
392
+ }
393
+ else if (err.code === 'LIMIT_FILE_COUNT') {
394
+ errorMessage = 'Too many files';
395
+ errorCode = 'FILE_COUNT_LIMIT_EXCEEDED';
396
+ }
397
+ else {
398
+ errorMessage = err.message || 'Upload failed';
399
+ }
400
+ const multermateError = new MultermateError(errorMessage, errorCode);
401
+ req.fileValidationError = errorMessage;
402
+ return next(multermateError);
403
+ }
404
+ next();
405
+ });
406
+ };
407
+ }
408
+ catch (error) {
409
+ throw new MultermateError('Failed to create multiple upload middleware', 'MIDDLEWARE_CREATION_ERROR');
410
+ }
186
411
  }
187
412
  /**
188
413
  * Utility function to delete a file from the filesystem
@@ -192,20 +417,37 @@ function uploadMultiple(options) {
192
417
  */
193
418
  async function deleteFile(filePath) {
194
419
  try {
420
+ if (!filePath || typeof filePath !== 'string') {
421
+ throw new MultermateError('Invalid file path provided', 'INVALID_PATH');
422
+ }
195
423
  await promises_1.default.unlink(filePath);
196
424
  return true;
197
425
  }
198
426
  catch (error) {
199
- console.error(`Error deleting file: ${error.message}`);
200
- return false;
427
+ if (error instanceof MultermateError) {
428
+ throw error;
429
+ }
430
+ if (error.code === 'ENOENT') {
431
+ throw new MultermateError(`File not found: ${filePath}`, 'FILE_NOT_FOUND');
432
+ }
433
+ else if (error.code === 'EACCES') {
434
+ throw new MultermateError(`Permission denied: ${filePath}`, 'PERMISSION_DENIED');
435
+ }
436
+ else {
437
+ throw new MultermateError(`Failed to delete file: ${error.message}`, 'DELETE_ERROR');
438
+ }
201
439
  }
202
440
  }
203
441
  // Export the allowed file types for reference
204
442
  exports.ALLOWED_FILE_TYPES = Object.keys(ALLOWED_MIME_TYPES);
443
+ // Export MIME types for external use
444
+ exports.MIME_TYPES = ALLOWED_MIME_TYPES;
205
445
  // Export your functions
206
446
  exports.default = {
207
447
  uploadSingle,
208
448
  uploadMultiple,
209
449
  deleteFile,
210
- ALLOWED_FILE_TYPES: exports.ALLOWED_FILE_TYPES
450
+ MultermateError,
451
+ ALLOWED_FILE_TYPES: exports.ALLOWED_FILE_TYPES,
452
+ MIME_TYPES: exports.MIME_TYPES
211
453
  };