@devshopapp/common 1.0.15 → 1.0.16

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.
@@ -1,16 +1,45 @@
1
- import type { Request } from "express";
2
- import multer, { type FileFilterCallback } from "multer";
3
- export interface UploaderMiddlewareOptionsI {
1
+ import type { RequestHandler } from "express";
2
+ export interface UploadOptions {
4
3
  fieldName?: string;
5
- types?: Array<string>;
4
+ allowedMimeTypes?: string[];
5
+ maxFileSize?: number;
6
+ maxFiles?: number;
7
+ uploadDirectory?: string;
8
+ preserveExtension?: boolean;
9
+ }
10
+ export declare class UploadError extends Error {
11
+ statusCode: number;
12
+ constructor(message: string);
6
13
  }
7
14
  export declare class Uploader {
8
- uploadDirectory?: string | undefined;
9
- defaultUploadDirectory: string;
15
+ private readonly uploadDirectory?;
16
+ private readonly DEFAULT_UPLOAD_DIR;
17
+ private readonly DEFAULT_MAX_FILE_SIZE;
18
+ private readonly DEFAULT_MAX_FILES;
10
19
  constructor(uploadDirectory?: string | undefined);
11
- fileFilter: (types?: Array<string>) => (req: Request, file: Express.Multer.File, cb: FileFilterCallback) => void;
12
- storage: multer.StorageEngine;
13
- uploadMultipleFiles(options?: UploaderMiddlewareOptionsI): import("express").RequestHandler<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
14
- uploadSingleFile(options?: UploaderMiddlewareOptionsI): import("express").RequestHandler<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>;
20
+ /**
21
+ * Ensure upload directory exists
22
+ */
23
+ private ensureDirectoryExists;
24
+ /**
25
+ * Generate cryptographically secure filename
26
+ */
27
+ private generateFilename;
28
+ /**
29
+ * Validate mime type
30
+ */
31
+ private buildFileFilter;
32
+ /**
33
+ * Build storage engine
34
+ */
35
+ private buildStorage;
36
+ /**
37
+ * Upload multiple files
38
+ */
39
+ uploadMultipleFiles(options?: UploadOptions): RequestHandler;
40
+ /**
41
+ * Upload single file
42
+ */
43
+ uploadSingleFile(options?: UploadOptions): RequestHandler;
15
44
  }
16
45
  //# sourceMappingURL=uploader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"uploader.d.ts","sourceRoot":"","sources":["../../../src/middlewares/uploader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,MAAM,EAAE,EAAE,KAAK,kBAAkB,EAAE,MAAM,QAAQ,CAAC;AAEzD,MAAM,WAAW,0BAA0B;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;CACzB;AAED,qBAAa,QAAQ;IAGE,eAAe,CAAC,EAAE,MAAM;IAFpC,sBAAsB,SAAc;gBAExB,eAAe,CAAC,EAAE,MAAM,YAAA;IAEpC,UAAU,GAAI,QAAQ,KAAK,CAAC,MAAM,CAAC,MAC9B,KAAK,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,kBAAkB,UAa1E;IAEM,OAAO,uBAQZ;IAEF,mBAAmB,CAAC,OAAO,CAAC,EAAE,0BAA0B;IAKxD,gBAAgB,CAAC,OAAO,CAAC,EAAE,0BAA0B;CAIxD"}
1
+ {"version":3,"file":"uploader.d.ts","sourceRoot":"","sources":["../../../src/middlewares/uploader.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAW,cAAc,EAAE,MAAM,SAAS,CAAC;AAEvD,MAAM,WAAW,aAAa;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,qBAAa,WAAY,SAAQ,KAAK;IAClC,UAAU,SAAO;gBAEL,OAAO,EAAE,MAAM;CAQ9B;AAED,qBAAa,QAAQ;IAML,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IAJ7C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA2B;IAC9D,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAmB;IACzD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAK;gBAEV,eAAe,CAAC,EAAE,MAAM,YAAA;IAErD;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAQ7B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAUxB;;OAEG;IACH,OAAO,CAAC,eAAe;IAavB;;OAEG;IACH,OAAO,CAAC,YAAY;IAqBpB;;OAEG;IACI,mBAAmB,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,cAAc;IAenE;;OAEG;IACI,gBAAgB,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,cAAc;CAcnE"}
@@ -1,42 +1,104 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import crypto from "crypto";
1
4
  import multer, {} from "multer";
5
+ export class UploadError extends Error {
6
+ statusCode = 400;
7
+ constructor(message) {
8
+ super(message);
9
+ Object.setPrototypeOf(this, UploadError.prototype);
10
+ }
11
+ }
2
12
  export class Uploader {
3
13
  uploadDirectory;
4
- defaultUploadDirectory = '/uploads';
14
+ DEFAULT_UPLOAD_DIR = path.resolve("uploads");
15
+ DEFAULT_MAX_FILE_SIZE = 5 * 1024 * 1024; // 5 MB
16
+ DEFAULT_MAX_FILES = 5;
5
17
  constructor(uploadDirectory) {
6
18
  this.uploadDirectory = uploadDirectory;
7
19
  }
8
- fileFilter = (types) => {
20
+ /**
21
+ * Ensure upload directory exists
22
+ */
23
+ ensureDirectoryExists(directory) {
24
+ if (!fs.existsSync(directory)) {
25
+ fs.mkdirSync(directory, {
26
+ recursive: true
27
+ });
28
+ }
29
+ }
30
+ /**
31
+ * Generate cryptographically secure filename
32
+ */
33
+ generateFilename(originalName, preserveExtension = true) {
34
+ const randomName = crypto.randomBytes(32).toString("hex");
35
+ if (!preserveExtension) {
36
+ return randomName;
37
+ }
38
+ const extension = path.extname(originalName);
39
+ return `${randomName}${extension}`;
40
+ }
41
+ /**
42
+ * Validate mime type
43
+ */
44
+ buildFileFilter(allowedMimeTypes) {
9
45
  return (req, file, cb) => {
10
- const type = file.mimetype;
11
- if (!types)
12
- return cb(null, true);
13
- if (types.length <= 0)
46
+ if (!allowedMimeTypes || allowedMimeTypes.length === 0) {
14
47
  return cb(null, true);
15
- if (types.some((accepted) => accepted === type)) {
16
- cb(null, true);
17
48
  }
18
- else {
19
- req.uploaderError = new Error(`we only accept the following types: ${types.join(', ')}`);
20
- cb(null, false);
49
+ const isAllowed = allowedMimeTypes.includes(file.mimetype);
50
+ if (!isAllowed) {
51
+ return cb(new UploadError(`Unsupported file type: ${file.mimetype}`));
21
52
  }
53
+ cb(null, true);
22
54
  };
23
- };
24
- storage = multer.diskStorage({
25
- destination: (req, file, cb) => {
26
- cb(null, this.uploadDirectory || this.defaultUploadDirectory);
27
- },
28
- filename: (req, file, cb) => {
29
- const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9);
30
- cb(null, `${file.fieldname}${uniqueSuffix}`);
31
- }
32
- });
55
+ }
56
+ /**
57
+ * Build storage engine
58
+ */
59
+ buildStorage(directory, preserveExtension) {
60
+ this.ensureDirectoryExists(directory);
61
+ return multer.diskStorage({
62
+ destination: (req, file, cb) => {
63
+ cb(null, directory);
64
+ },
65
+ filename: (req, file, cb) => {
66
+ try {
67
+ const filename = this.generateFilename(file.originalname, preserveExtension);
68
+ cb(null, filename);
69
+ }
70
+ catch (err) {
71
+ cb(err, "");
72
+ }
73
+ }
74
+ });
75
+ }
76
+ /**
77
+ * Upload multiple files
78
+ */
33
79
  uploadMultipleFiles(options) {
34
- return multer({ storage: this.storage, fileFilter: this.fileFilter(options?.types) })
35
- .array(options?.fieldName || 'file');
80
+ const uploadDir = options?.uploadDirectory || this.uploadDirectory || this.DEFAULT_UPLOAD_DIR;
81
+ return multer({
82
+ storage: this.buildStorage(uploadDir, options?.preserveExtension ?? true),
83
+ fileFilter: this.buildFileFilter(options?.allowedMimeTypes),
84
+ limits: {
85
+ fileSize: options?.maxFileSize || this.DEFAULT_MAX_FILE_SIZE,
86
+ files: options?.maxFiles || this.DEFAULT_MAX_FILES
87
+ }
88
+ }).array(options?.fieldName || "files");
36
89
  }
90
+ /**
91
+ * Upload single file
92
+ */
37
93
  uploadSingleFile(options) {
38
- return multer({ storage: this.storage, fileFilter: this.fileFilter(options?.types) })
39
- .single(options?.fieldName || 'file');
94
+ const uploadDir = options?.uploadDirectory || this.uploadDirectory || this.DEFAULT_UPLOAD_DIR;
95
+ return multer({
96
+ storage: this.buildStorage(uploadDir, options?.preserveExtension ?? true),
97
+ fileFilter: this.buildFileFilter(options?.allowedMimeTypes),
98
+ limits: {
99
+ fileSize: options?.maxFileSize || this.DEFAULT_MAX_FILE_SIZE
100
+ }
101
+ }).single(options?.fieldName || "file");
40
102
  }
41
103
  }
42
104
  //# sourceMappingURL=uploader.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"uploader.js","sourceRoot":"","sources":["../../../src/middlewares/uploader.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,EAAE,EAA2B,MAAM,QAAQ,CAAC;AAOzD,MAAM,OAAO,QAAQ;IAGE;IAFZ,sBAAsB,GAAG,UAAU,CAAC;IAE3C,YAAmB,eAAwB;QAAxB,oBAAe,GAAf,eAAe,CAAS;IAAG,CAAC;IAExC,UAAU,GAAG,CAAC,KAAqB,EAAE,EAAE;QAC1C,OAAO,CAAC,GAAY,EAAE,IAAyB,EAAE,EAAsB,EAAE,EAAE;YACvE,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC;YAE3B,IAAI,CAAC,KAAK;gBAAE,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAClC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC;gBAAE,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAE7C,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,QAAgB,EAAE,EAAE,CAAC,QAAQ,KAAK,IAAI,CAAC,EAAE,CAAC;gBACtD,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACJ,GAAG,CAAC,aAAa,GAAG,IAAI,KAAK,CAAC,uCAAuC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACzF,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACpB,CAAC;QACL,CAAC,CAAA;IACL,CAAC,CAAA;IAEM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC;QAChC,WAAW,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;YAC3B,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,eAAe,IAAE,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAChE,CAAC;QACD,QAAQ,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;YACxB,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;YACxE,EAAE,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,GAAG,YAAY,EAAE,CAAC,CAAC;QACjD,CAAC;KACJ,CAAC,CAAA;IAEF,mBAAmB,CAAC,OAAoC;QACpD,OAAO,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;aAChF,KAAK,CAAC,OAAO,EAAE,SAAS,IAAI,MAAM,CAAC,CAAC;IAC7C,CAAC;IAED,gBAAgB,CAAC,OAAoC;QACjD,OAAO,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;aAChF,MAAM,CAAC,OAAO,EAAE,SAAS,IAAI,MAAM,CAAC,CAAC;IAC9C,CAAC;CACJ"}
1
+ {"version":3,"file":"uploader.js","sourceRoot":"","sources":["../../../src/middlewares/uploader.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devshopapp/common",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "description": "A common utils package for the different services in the shopping application",
5
5
  "type": "module",
6
6
  "types": "./build/src/index.d.ts",