@devshopapp/common 1.0.14 → 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.
- package/build/src/index.d.ts +1 -0
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +1 -0
- package/build/src/index.js.map +1 -1
- package/build/src/middlewares/current.user.d.ts +1 -0
- package/build/src/middlewares/current.user.d.ts.map +1 -1
- package/build/src/middlewares/current.user.js.map +1 -1
- package/build/src/middlewares/uploader.d.ts +45 -0
- package/build/src/middlewares/uploader.d.ts.map +1 -0
- package/build/src/middlewares/uploader.js +104 -0
- package/build/src/middlewares/uploader.js.map +1 -0
- package/package.json +1 -1
package/build/src/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './middlewares/current.user.js';
|
|
|
2
2
|
export * from './middlewares/require.auth.js';
|
|
3
3
|
export * from './middlewares/error.handler.js';
|
|
4
4
|
export * from './middlewares/validation.request.middleware.js';
|
|
5
|
+
export * from './middlewares/uploader.js';
|
|
5
6
|
export * from './errors/bad.request.error.js';
|
|
6
7
|
export * from './errors/database.connection.error.js';
|
|
7
8
|
export * from './errors/not.authorized.error.js';
|
package/build/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gDAAgD,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gDAAgD,CAAC;AAC/D,cAAc,2BAA2B,CAAC;AAE1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uCAAuC,CAAC;AACtD,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sCAAsC,CAAC;AAErD,cAAc,qCAAqC,CAAC;AACpD,cAAc,0CAA0C,CAAC;AACzD,cAAc,uBAAuB,CAAC;AAEtC,cAAc,sCAAsC,CAAC"}
|
package/build/src/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export * from './middlewares/current.user.js';
|
|
|
2
2
|
export * from './middlewares/require.auth.js';
|
|
3
3
|
export * from './middlewares/error.handler.js';
|
|
4
4
|
export * from './middlewares/validation.request.middleware.js';
|
|
5
|
+
export * from './middlewares/uploader.js';
|
|
5
6
|
export * from './errors/bad.request.error.js';
|
|
6
7
|
export * from './errors/database.connection.error.js';
|
|
7
8
|
export * from './errors/not.authorized.error.js';
|
package/build/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gDAAgD,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gDAAgD,CAAC;AAC/D,cAAc,2BAA2B,CAAC;AAE1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uCAAuC,CAAC;AACtD,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,sCAAsC,CAAC;AAErD,cAAc,qCAAqC,CAAC;AACpD,cAAc,0CAA0C,CAAC;AACzD,cAAc,uBAAuB,CAAC;AAEtC,cAAc,sCAAsC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"current.user.d.ts","sourceRoot":"","sources":["../../../src/middlewares/current.user.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,OAAO,CAAC;QACd,UAAU,OAAO;YACb,OAAO,CAAC,EAAE,GAAG,CAAC;YACd,WAAW,CAAC,EAAE,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"current.user.d.ts","sourceRoot":"","sources":["../../../src/middlewares/current.user.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,CAAC,MAAM,CAAC;IACX,UAAU,OAAO,CAAC;QACd,UAAU,OAAO;YACb,OAAO,CAAC,EAAE,GAAG,CAAC;YACd,WAAW,CAAC,EAAE,UAAU,CAAC;YACzB,aAAa,CAAC,EAAE,KAAK,CAAC;SAEzB;KACJ;CACJ;AAED,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,MAC9B,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,SAgB1D,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"current.user.js","sourceRoot":"","sources":["../../../src/middlewares/current.user.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkD,MAAM,SAAS,CAAC;AACzE,OAAO,GAAG,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"current.user.js","sourceRoot":"","sources":["../../../src/middlewares/current.user.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkD,MAAM,SAAS,CAAC;AACzE,OAAO,GAAG,MAAM,cAAc,CAAC;AAc/B,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAc,EAAE,EAAE;IAC1C,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QACvD,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC;QAE/B,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,OAAO,IAAI,EAAE,CAAC;QAClB,CAAC;QAED,IAAI,CAAC;YACD,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAe,CAAC;YACxD,GAAG,CAAC,WAAW,GAAG,OAAO,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,OAAO,IAAI,EAAE,CAAC;QAClB,CAAC;QAED,IAAI,EAAE,CAAC;IACX,CAAC,CAAC;AACN,CAAC,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { RequestHandler } from "express";
|
|
2
|
+
export interface UploadOptions {
|
|
3
|
+
fieldName?: 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);
|
|
13
|
+
}
|
|
14
|
+
export declare class Uploader {
|
|
15
|
+
private readonly uploadDirectory?;
|
|
16
|
+
private readonly DEFAULT_UPLOAD_DIR;
|
|
17
|
+
private readonly DEFAULT_MAX_FILE_SIZE;
|
|
18
|
+
private readonly DEFAULT_MAX_FILES;
|
|
19
|
+
constructor(uploadDirectory?: string | undefined);
|
|
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;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=uploader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import crypto from "crypto";
|
|
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
|
+
}
|
|
12
|
+
export class Uploader {
|
|
13
|
+
uploadDirectory;
|
|
14
|
+
DEFAULT_UPLOAD_DIR = path.resolve("uploads");
|
|
15
|
+
DEFAULT_MAX_FILE_SIZE = 5 * 1024 * 1024; // 5 MB
|
|
16
|
+
DEFAULT_MAX_FILES = 5;
|
|
17
|
+
constructor(uploadDirectory) {
|
|
18
|
+
this.uploadDirectory = uploadDirectory;
|
|
19
|
+
}
|
|
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) {
|
|
45
|
+
return (req, file, cb) => {
|
|
46
|
+
if (!allowedMimeTypes || allowedMimeTypes.length === 0) {
|
|
47
|
+
return cb(null, true);
|
|
48
|
+
}
|
|
49
|
+
const isAllowed = allowedMimeTypes.includes(file.mimetype);
|
|
50
|
+
if (!isAllowed) {
|
|
51
|
+
return cb(new UploadError(`Unsupported file type: ${file.mimetype}`));
|
|
52
|
+
}
|
|
53
|
+
cb(null, true);
|
|
54
|
+
};
|
|
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
|
+
*/
|
|
79
|
+
uploadMultipleFiles(options) {
|
|
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");
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Upload single file
|
|
92
|
+
*/
|
|
93
|
+
uploadSingleFile(options) {
|
|
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");
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=uploader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uploader.js","sourceRoot":"","sources":["../../../src/middlewares/uploader.ts"],"names":[],"mappings":"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"}
|