multermate 1.1.0 → 2.1.0

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