@globalart/nestjs-fastify 1.0.12 → 1.0.13

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,27 @@
1
+ import { NestInterceptor, Type } from "@nestjs/common";
2
+ import { MultipartFile } from "@fastify/multipart";
3
+
4
+ //#region src/decorators/index.d.ts
5
+ declare const UploadedFiles: (...dataOrPipes: unknown[]) => ParameterDecorator;
6
+ declare const UploadedFile: (...dataOrPipes: unknown[]) => ParameterDecorator;
7
+ //#endregion
8
+ //#region src/types/index.d.ts
9
+ type MultiPartFile = Storage.MultipartFile;
10
+ type MultiPartFiles = Storage.MultipartFile[];
11
+ //#endregion
12
+ //#region src/model/index.d.ts
13
+ declare class MultipartOptions {
14
+ maxFileSize?: number | undefined;
15
+ fileType?: (string | RegExp) | undefined;
16
+ constructor(maxFileSize?: number | undefined, fileType?: (string | RegExp) | undefined);
17
+ }
18
+ //#endregion
19
+ //#region src/interceptors/index.d.ts
20
+ declare function MultipartInterceptor(options?: MultipartOptions): Type<NestInterceptor>;
21
+ //#endregion
22
+ //#region src/utils/index.d.ts
23
+ declare const getFileFromPart: (part: MultipartFile) => Promise<Storage.MultipartFile>;
24
+ declare const validateFile: (file: Storage.MultipartFile, options: MultipartOptions) => string | void;
25
+ //#endregion
26
+ export { MultiPartFile, MultiPartFiles, MultipartInterceptor, MultipartOptions, UploadedFile, UploadedFiles, getFileFromPart, validateFile };
27
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/decorators/index.ts","../src/types/index.ts","../src/model/index.ts","../src/interceptors/index.ts","../src/utils/index.ts"],"sourcesContent":[],"mappings":";;;;cAGa,8CAAa;cAWb,6CAAY;;;KCdb,aAAA,GAAgB,OAAA,CAAQ;KACxB,cAAA,GAAiB,OAAA,CAAQ;;;cCDxB,gBAAA;;uBAGkB;qEAAA;AFA/B;;;iBGYgB,oBAAA,WACL,mBACR,KAAK;;;cCTK,wBACL,kBACL,QAAQ,OAAA,CAAQ;cAWN,qBACL,OAAA,CAAQ,wBACL"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,27 @@
1
- export * from "./decorators";
2
- export * from "./types";
3
- export * from "./interceptors";
4
- export * from "./model";
5
- export * from "./utils";
1
+ import { NestInterceptor, Type } from "@nestjs/common";
2
+ import { MultipartFile } from "@fastify/multipart";
3
+
4
+ //#region src/decorators/index.d.ts
5
+ declare const UploadedFiles: (...dataOrPipes: unknown[]) => ParameterDecorator;
6
+ declare const UploadedFile: (...dataOrPipes: unknown[]) => ParameterDecorator;
7
+ //#endregion
8
+ //#region src/types/index.d.ts
9
+ type MultiPartFile = Storage.MultipartFile;
10
+ type MultiPartFiles = Storage.MultipartFile[];
11
+ //#endregion
12
+ //#region src/model/index.d.ts
13
+ declare class MultipartOptions {
14
+ maxFileSize?: number | undefined;
15
+ fileType?: (string | RegExp) | undefined;
16
+ constructor(maxFileSize?: number | undefined, fileType?: (string | RegExp) | undefined);
17
+ }
18
+ //#endregion
19
+ //#region src/interceptors/index.d.ts
20
+ declare function MultipartInterceptor(options?: MultipartOptions): Type<NestInterceptor>;
21
+ //#endregion
22
+ //#region src/utils/index.d.ts
23
+ declare const getFileFromPart: (part: MultipartFile) => Promise<Storage.MultipartFile>;
24
+ declare const validateFile: (file: Storage.MultipartFile, options: MultipartOptions) => string | void;
25
+ //#endregion
26
+ export { MultiPartFile, MultiPartFiles, MultipartInterceptor, MultipartOptions, UploadedFile, UploadedFiles, getFileFromPart, validateFile };
6
27
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/decorators/index.ts","../src/types/index.ts","../src/model/index.ts","../src/interceptors/index.ts","../src/utils/index.ts"],"sourcesContent":[],"mappings":";;;;cAGa,8CAAa;cAWb,6CAAY;;;KCdb,aAAA,GAAgB,OAAA,CAAQ;KACxB,cAAA,GAAiB,OAAA,CAAQ;;;cCDxB,gBAAA;;uBAGkB;qEAAA;AFA/B;;;iBGYgB,oBAAA,WACL,mBACR,KAAK;;;cCTK,wBACL,kBACL,QAAQ,OAAA,CAAQ;cAWN,qBACL,OAAA,CAAQ,wBACL"}
package/dist/index.js CHANGED
@@ -1,22 +1,111 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
15
17
  };
16
- Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./decorators"), exports);
18
- __exportStar(require("./types"), exports);
19
- __exportStar(require("./interceptors"), exports);
20
- __exportStar(require("./model"), exports);
21
- __exportStar(require("./utils"), exports);
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ let __nestjs_common = require("@nestjs/common");
25
+ __nestjs_common = __toESM(__nestjs_common);
26
+
27
+ //#region src/decorators/index.ts
28
+ const UploadedFiles = (0, __nestjs_common.createParamDecorator)((_data, ctx) => {
29
+ const req = ctx.switchToHttp().getRequest();
30
+ const allFiles = [];
31
+ Object.values(req.storedFiles).forEach((files) => {
32
+ allFiles.push(...files);
33
+ });
34
+ return allFiles;
35
+ });
36
+ const UploadedFile = (0, __nestjs_common.createParamDecorator)((fieldName, ctx) => {
37
+ const req = ctx.switchToHttp().getRequest();
38
+ if (typeof fieldName === "string") {
39
+ const files = req.storedFiles[fieldName];
40
+ return files && files.length > 0 ? files[0] : null;
41
+ }
42
+ return req.storedFiles;
43
+ });
44
+
45
+ //#endregion
46
+ //#region src/utils/index.ts
47
+ const getFileFromPart = async (part) => {
48
+ const buffer = await part.toBuffer();
49
+ return {
50
+ buffer,
51
+ size: buffer.byteLength,
52
+ filename: part.filename,
53
+ mimetype: part.mimetype,
54
+ fieldname: part.fieldname
55
+ };
56
+ };
57
+ const validateFile = (file, options) => {
58
+ const validators = [];
59
+ if (options.maxFileSize) validators.push(new __nestjs_common.MaxFileSizeValidator({ maxSize: options.maxFileSize }));
60
+ if (options.fileType) validators.push(new __nestjs_common.FileTypeValidator({ fileType: options.fileType }));
61
+ for (const validator of validators) {
62
+ if (validator.isValid(file)) continue;
63
+ return validator.buildErrorMessage(file);
64
+ }
65
+ };
66
+
67
+ //#endregion
68
+ //#region src/interceptors/index.ts
69
+ function MultipartInterceptor(options = {}) {
70
+ class MixinInterceptor {
71
+ async intercept(context, next) {
72
+ const req = context.switchToHttp().getRequest();
73
+ if (!req.isMultipart()) throw new __nestjs_common.HttpException("The request should be a form-data", __nestjs_common.HttpStatus.BAD_REQUEST);
74
+ const files = {};
75
+ const body = {};
76
+ for await (const part of req.parts()) {
77
+ if (part.type !== "file") {
78
+ body[part.fieldname] = part.value;
79
+ continue;
80
+ }
81
+ const file = await getFileFromPart(part);
82
+ const validationResult = validateFile(file, options);
83
+ if (validationResult) throw new __nestjs_common.HttpException(validationResult, __nestjs_common.HttpStatus.UNPROCESSABLE_ENTITY);
84
+ files[part.fieldname] = files[part.fieldname] || [];
85
+ files[part.fieldname].push(file);
86
+ }
87
+ req.storedFiles = files;
88
+ req.body = body;
89
+ return next.handle();
90
+ }
91
+ }
92
+ return (0, __nestjs_common.mixin)(MixinInterceptor);
93
+ }
94
+
95
+ //#endregion
96
+ //#region src/model/index.ts
97
+ var MultipartOptions = class {
98
+ constructor(maxFileSize, fileType) {
99
+ this.maxFileSize = maxFileSize;
100
+ this.fileType = fileType;
101
+ }
102
+ };
103
+
104
+ //#endregion
105
+ exports.MultipartInterceptor = MultipartInterceptor;
106
+ exports.MultipartOptions = MultipartOptions;
107
+ exports.UploadedFile = UploadedFile;
108
+ exports.UploadedFiles = UploadedFiles;
109
+ exports.getFileFromPart = getFileFromPart;
110
+ exports.validateFile = validateFile;
22
111
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,0CAAwB;AACxB,iDAA+B;AAC/B,0CAAwB;AACxB,0CAAwB"}
1
+ {"version":3,"file":"index.js","names":["allFiles: Storage.MultipartFile[]","validators: FileValidator[]","MaxFileSizeValidator","FileTypeValidator","HttpException","HttpStatus","files: Record<string, any[]>","body: Record<string, any>","maxFileSize?: number","fileType?: string | RegExp"],"sources":["../src/decorators/index.ts","../src/utils/index.ts","../src/interceptors/index.ts","../src/model/index.ts"],"sourcesContent":["import { createParamDecorator, ExecutionContext } from \"@nestjs/common\";\nimport * as fastify from \"fastify\";\n\nexport const UploadedFiles = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext) => {\n const req = ctx.switchToHttp().getRequest() as fastify.FastifyRequest;\n const allFiles: Storage.MultipartFile[] = [];\n Object.values(req.storedFiles).forEach((files) => {\n allFiles.push(...files);\n });\n return allFiles;\n }\n);\n\nexport const UploadedFile = createParamDecorator(\n (fieldName: string | unknown, ctx: ExecutionContext) => {\n const req = ctx.switchToHttp().getRequest() as fastify.FastifyRequest;\n\n if (typeof fieldName === \"string\") {\n const files = req.storedFiles[fieldName];\n return files && files.length > 0 ? files[0] : null;\n }\n\n return req.storedFiles;\n }\n);\n","import { MultipartFile } from \"@fastify/multipart\";\nimport {\n FileTypeValidator,\n FileValidator,\n MaxFileSizeValidator,\n} from \"@nestjs/common\";\nimport { MultipartOptions } from \"../model\";\n\nexport const getFileFromPart = async (\n part: MultipartFile,\n): Promise<Storage.MultipartFile> => {\n const buffer = await part.toBuffer();\n return {\n buffer,\n size: buffer.byteLength,\n filename: part.filename,\n mimetype: part.mimetype,\n fieldname: part.fieldname,\n };\n};\n\nexport const validateFile = (\n file: Storage.MultipartFile,\n options: MultipartOptions,\n): string | void => {\n const validators: FileValidator[] = [];\n\n if (options.maxFileSize)\n validators.push(new MaxFileSizeValidator({ maxSize: options.maxFileSize }));\n if (options.fileType)\n validators.push(new FileTypeValidator({ fileType: options.fileType }));\n\n for (const validator of validators) {\n if (validator.isValid(file)) continue;\n\n return validator.buildErrorMessage(file);\n }\n};\n","import { Observable } from \"rxjs\";\nimport {\n CallHandler,\n ExecutionContext,\n HttpException,\n HttpStatus,\n mixin,\n NestInterceptor,\n Type,\n} from \"@nestjs/common\";\nimport * as fastify from \"fastify\";\nimport { MultipartValue } from \"@fastify/multipart\";\nimport { MultipartOptions } from \"../model\";\nimport { getFileFromPart, validateFile } from \"../utils\";\n\nexport function MultipartInterceptor(\n options: MultipartOptions = {},\n): Type<NestInterceptor> {\n class MixinInterceptor implements NestInterceptor {\n async intercept(\n context: ExecutionContext,\n next: CallHandler,\n ): Promise<Observable<any>> {\n const req = context.switchToHttp().getRequest() as fastify.FastifyRequest;\n\n if (!req.isMultipart())\n throw new HttpException(\n \"The request should be a form-data\",\n HttpStatus.BAD_REQUEST,\n );\n\n const files: Record<string, any[]> = {};\n const body: Record<string, any> = {};\n for await (const part of req.parts()) {\n if (part.type !== \"file\") {\n body[part.fieldname] = (part as MultipartValue).value;\n continue;\n }\n const file = await getFileFromPart(part);\n const validationResult = validateFile(file, options);\n\n if (validationResult)\n throw new HttpException(\n validationResult,\n HttpStatus.UNPROCESSABLE_ENTITY,\n );\n\n files[part.fieldname] = files[part.fieldname] || [];\n files[part.fieldname].push(file);\n }\n req.storedFiles = files;\n req.body = body;\n\n return next.handle();\n }\n }\n\n return mixin(MixinInterceptor);\n}\n","export class MultipartOptions {\n constructor(\n public maxFileSize?: number,\n public fileType?: string | RegExp,\n ) {}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,MAAa,2DACV,OAAgB,QAA0B;CACzC,MAAM,MAAM,IAAI,eAAe;CAC/B,MAAMA,WAAoC;AAC1C,QAAO,OAAO,IAAI,aAAa,SAAS,UAAU;AAChD,WAAS,KAAK,GAAG;;AAEnB,QAAO;;AAIX,MAAa,0DACV,WAA6B,QAA0B;CACtD,MAAM,MAAM,IAAI,eAAe;AAE/B,KAAI,OAAO,cAAc,UAAU;EACjC,MAAM,QAAQ,IAAI,YAAY;AAC9B,SAAO,SAAS,MAAM,SAAS,IAAI,MAAM,KAAK;;AAGhD,QAAO,IAAI;;;;;ACff,MAAa,kBAAkB,OAC7B,SACmC;CACnC,MAAM,SAAS,MAAM,KAAK;AAC1B,QAAO;EACL;EACA,MAAM,OAAO;EACb,UAAU,KAAK;EACf,UAAU,KAAK;EACf,WAAW,KAAK;;;AAIpB,MAAa,gBACX,MACA,YACkB;CAClB,MAAMC,aAA8B;AAEpC,KAAI,QAAQ,YACV,YAAW,KAAK,IAAIC,qCAAqB,EAAE,SAAS,QAAQ;AAC9D,KAAI,QAAQ,SACV,YAAW,KAAK,IAAIC,kCAAkB,EAAE,UAAU,QAAQ;AAE5D,MAAK,MAAM,aAAa,YAAY;AAClC,MAAI,UAAU,QAAQ,MAAO;AAE7B,SAAO,UAAU,kBAAkB;;;;;;ACpBvC,SAAgB,qBACd,UAA4B,IACL;CACvB,MAAM,iBAA4C;EAChD,MAAM,UACJ,SACA,MAC0B;GAC1B,MAAM,MAAM,QAAQ,eAAe;AAEnC,OAAI,CAAC,IAAI,cACP,OAAM,IAAIC,8BACR,qCACAC,2BAAW;GAGf,MAAMC,QAA+B;GACrC,MAAMC,OAA4B;AAClC,cAAW,MAAM,QAAQ,IAAI,SAAS;AACpC,QAAI,KAAK,SAAS,QAAQ;AACxB,UAAK,KAAK,aAAc,KAAwB;AAChD;;IAEF,MAAM,OAAO,MAAM,gBAAgB;IACnC,MAAM,mBAAmB,aAAa,MAAM;AAE5C,QAAI,iBACF,OAAM,IAAIH,8BACR,kBACAC,2BAAW;AAGf,UAAM,KAAK,aAAa,MAAM,KAAK,cAAc;AACjD,UAAM,KAAK,WAAW,KAAK;;AAE7B,OAAI,cAAc;AAClB,OAAI,OAAO;AAEX,UAAO,KAAK;;;AAIhB,mCAAa;;;;;ACzDf,IAAa,mBAAb,MAA8B;CAC5B,YACE,AAAOG,aACP,AAAOC,UACP;EAFO;EACA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,82 @@
1
+ import { FileTypeValidator, HttpException, HttpStatus, MaxFileSizeValidator, createParamDecorator, mixin } from "@nestjs/common";
2
+
3
+ //#region src/decorators/index.ts
4
+ const UploadedFiles = createParamDecorator((_data, ctx) => {
5
+ const req = ctx.switchToHttp().getRequest();
6
+ const allFiles = [];
7
+ Object.values(req.storedFiles).forEach((files) => {
8
+ allFiles.push(...files);
9
+ });
10
+ return allFiles;
11
+ });
12
+ const UploadedFile = createParamDecorator((fieldName, ctx) => {
13
+ const req = ctx.switchToHttp().getRequest();
14
+ if (typeof fieldName === "string") {
15
+ const files = req.storedFiles[fieldName];
16
+ return files && files.length > 0 ? files[0] : null;
17
+ }
18
+ return req.storedFiles;
19
+ });
20
+
21
+ //#endregion
22
+ //#region src/utils/index.ts
23
+ const getFileFromPart = async (part) => {
24
+ const buffer = await part.toBuffer();
25
+ return {
26
+ buffer,
27
+ size: buffer.byteLength,
28
+ filename: part.filename,
29
+ mimetype: part.mimetype,
30
+ fieldname: part.fieldname
31
+ };
32
+ };
33
+ const validateFile = (file, options) => {
34
+ const validators = [];
35
+ if (options.maxFileSize) validators.push(new MaxFileSizeValidator({ maxSize: options.maxFileSize }));
36
+ if (options.fileType) validators.push(new FileTypeValidator({ fileType: options.fileType }));
37
+ for (const validator of validators) {
38
+ if (validator.isValid(file)) continue;
39
+ return validator.buildErrorMessage(file);
40
+ }
41
+ };
42
+
43
+ //#endregion
44
+ //#region src/interceptors/index.ts
45
+ function MultipartInterceptor(options = {}) {
46
+ class MixinInterceptor {
47
+ async intercept(context, next) {
48
+ const req = context.switchToHttp().getRequest();
49
+ if (!req.isMultipart()) throw new HttpException("The request should be a form-data", HttpStatus.BAD_REQUEST);
50
+ const files = {};
51
+ const body = {};
52
+ for await (const part of req.parts()) {
53
+ if (part.type !== "file") {
54
+ body[part.fieldname] = part.value;
55
+ continue;
56
+ }
57
+ const file = await getFileFromPart(part);
58
+ const validationResult = validateFile(file, options);
59
+ if (validationResult) throw new HttpException(validationResult, HttpStatus.UNPROCESSABLE_ENTITY);
60
+ files[part.fieldname] = files[part.fieldname] || [];
61
+ files[part.fieldname].push(file);
62
+ }
63
+ req.storedFiles = files;
64
+ req.body = body;
65
+ return next.handle();
66
+ }
67
+ }
68
+ return mixin(MixinInterceptor);
69
+ }
70
+
71
+ //#endregion
72
+ //#region src/model/index.ts
73
+ var MultipartOptions = class {
74
+ constructor(maxFileSize, fileType) {
75
+ this.maxFileSize = maxFileSize;
76
+ this.fileType = fileType;
77
+ }
78
+ };
79
+
80
+ //#endregion
81
+ export { MultipartInterceptor, MultipartOptions, UploadedFile, UploadedFiles, getFileFromPart, validateFile };
82
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["allFiles: Storage.MultipartFile[]","validators: FileValidator[]","files: Record<string, any[]>","body: Record<string, any>","maxFileSize?: number","fileType?: string | RegExp"],"sources":["../src/decorators/index.ts","../src/utils/index.ts","../src/interceptors/index.ts","../src/model/index.ts"],"sourcesContent":["import { createParamDecorator, ExecutionContext } from \"@nestjs/common\";\nimport * as fastify from \"fastify\";\n\nexport const UploadedFiles = createParamDecorator(\n (_data: unknown, ctx: ExecutionContext) => {\n const req = ctx.switchToHttp().getRequest() as fastify.FastifyRequest;\n const allFiles: Storage.MultipartFile[] = [];\n Object.values(req.storedFiles).forEach((files) => {\n allFiles.push(...files);\n });\n return allFiles;\n }\n);\n\nexport const UploadedFile = createParamDecorator(\n (fieldName: string | unknown, ctx: ExecutionContext) => {\n const req = ctx.switchToHttp().getRequest() as fastify.FastifyRequest;\n\n if (typeof fieldName === \"string\") {\n const files = req.storedFiles[fieldName];\n return files && files.length > 0 ? files[0] : null;\n }\n\n return req.storedFiles;\n }\n);\n","import { MultipartFile } from \"@fastify/multipart\";\nimport {\n FileTypeValidator,\n FileValidator,\n MaxFileSizeValidator,\n} from \"@nestjs/common\";\nimport { MultipartOptions } from \"../model\";\n\nexport const getFileFromPart = async (\n part: MultipartFile,\n): Promise<Storage.MultipartFile> => {\n const buffer = await part.toBuffer();\n return {\n buffer,\n size: buffer.byteLength,\n filename: part.filename,\n mimetype: part.mimetype,\n fieldname: part.fieldname,\n };\n};\n\nexport const validateFile = (\n file: Storage.MultipartFile,\n options: MultipartOptions,\n): string | void => {\n const validators: FileValidator[] = [];\n\n if (options.maxFileSize)\n validators.push(new MaxFileSizeValidator({ maxSize: options.maxFileSize }));\n if (options.fileType)\n validators.push(new FileTypeValidator({ fileType: options.fileType }));\n\n for (const validator of validators) {\n if (validator.isValid(file)) continue;\n\n return validator.buildErrorMessage(file);\n }\n};\n","import { Observable } from \"rxjs\";\nimport {\n CallHandler,\n ExecutionContext,\n HttpException,\n HttpStatus,\n mixin,\n NestInterceptor,\n Type,\n} from \"@nestjs/common\";\nimport * as fastify from \"fastify\";\nimport { MultipartValue } from \"@fastify/multipart\";\nimport { MultipartOptions } from \"../model\";\nimport { getFileFromPart, validateFile } from \"../utils\";\n\nexport function MultipartInterceptor(\n options: MultipartOptions = {},\n): Type<NestInterceptor> {\n class MixinInterceptor implements NestInterceptor {\n async intercept(\n context: ExecutionContext,\n next: CallHandler,\n ): Promise<Observable<any>> {\n const req = context.switchToHttp().getRequest() as fastify.FastifyRequest;\n\n if (!req.isMultipart())\n throw new HttpException(\n \"The request should be a form-data\",\n HttpStatus.BAD_REQUEST,\n );\n\n const files: Record<string, any[]> = {};\n const body: Record<string, any> = {};\n for await (const part of req.parts()) {\n if (part.type !== \"file\") {\n body[part.fieldname] = (part as MultipartValue).value;\n continue;\n }\n const file = await getFileFromPart(part);\n const validationResult = validateFile(file, options);\n\n if (validationResult)\n throw new HttpException(\n validationResult,\n HttpStatus.UNPROCESSABLE_ENTITY,\n );\n\n files[part.fieldname] = files[part.fieldname] || [];\n files[part.fieldname].push(file);\n }\n req.storedFiles = files;\n req.body = body;\n\n return next.handle();\n }\n }\n\n return mixin(MixinInterceptor);\n}\n","export class MultipartOptions {\n constructor(\n public maxFileSize?: number,\n public fileType?: string | RegExp,\n ) {}\n}\n"],"mappings":";;;AAGA,MAAa,gBAAgB,sBAC1B,OAAgB,QAA0B;CACzC,MAAM,MAAM,IAAI,eAAe;CAC/B,MAAMA,WAAoC;AAC1C,QAAO,OAAO,IAAI,aAAa,SAAS,UAAU;AAChD,WAAS,KAAK,GAAG;;AAEnB,QAAO;;AAIX,MAAa,eAAe,sBACzB,WAA6B,QAA0B;CACtD,MAAM,MAAM,IAAI,eAAe;AAE/B,KAAI,OAAO,cAAc,UAAU;EACjC,MAAM,QAAQ,IAAI,YAAY;AAC9B,SAAO,SAAS,MAAM,SAAS,IAAI,MAAM,KAAK;;AAGhD,QAAO,IAAI;;;;;ACff,MAAa,kBAAkB,OAC7B,SACmC;CACnC,MAAM,SAAS,MAAM,KAAK;AAC1B,QAAO;EACL;EACA,MAAM,OAAO;EACb,UAAU,KAAK;EACf,UAAU,KAAK;EACf,WAAW,KAAK;;;AAIpB,MAAa,gBACX,MACA,YACkB;CAClB,MAAMC,aAA8B;AAEpC,KAAI,QAAQ,YACV,YAAW,KAAK,IAAI,qBAAqB,EAAE,SAAS,QAAQ;AAC9D,KAAI,QAAQ,SACV,YAAW,KAAK,IAAI,kBAAkB,EAAE,UAAU,QAAQ;AAE5D,MAAK,MAAM,aAAa,YAAY;AAClC,MAAI,UAAU,QAAQ,MAAO;AAE7B,SAAO,UAAU,kBAAkB;;;;;;ACpBvC,SAAgB,qBACd,UAA4B,IACL;CACvB,MAAM,iBAA4C;EAChD,MAAM,UACJ,SACA,MAC0B;GAC1B,MAAM,MAAM,QAAQ,eAAe;AAEnC,OAAI,CAAC,IAAI,cACP,OAAM,IAAI,cACR,qCACA,WAAW;GAGf,MAAMC,QAA+B;GACrC,MAAMC,OAA4B;AAClC,cAAW,MAAM,QAAQ,IAAI,SAAS;AACpC,QAAI,KAAK,SAAS,QAAQ;AACxB,UAAK,KAAK,aAAc,KAAwB;AAChD;;IAEF,MAAM,OAAO,MAAM,gBAAgB;IACnC,MAAM,mBAAmB,aAAa,MAAM;AAE5C,QAAI,iBACF,OAAM,IAAI,cACR,kBACA,WAAW;AAGf,UAAM,KAAK,aAAa,MAAM,KAAK,cAAc;AACjD,UAAM,KAAK,WAAW,KAAK;;AAE7B,OAAI,cAAc;AAClB,OAAI,OAAO;AAEX,UAAO,KAAK;;;AAIhB,QAAO,MAAM;;;;;ACzDf,IAAa,mBAAb,MAA8B;CAC5B,YACE,AAAOC,aACP,AAAOC,UACP;EAFO;EACA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@globalart/nestjs-fastify",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "A fastify for NestJS",
5
5
  "author": {
6
6
  "name": "GlobalArt, Inc"
@@ -33,15 +33,15 @@
33
33
  "test": "jest --runInBand --passWithNoTests",
34
34
  "test:cov": "jest --coverage --passWithNoTests",
35
35
  "coveralls": "yarn run test:cov --coverageReporters=text-lcov | coveralls",
36
- "build": "rm -rf ./dist && tsc && cp src/globals.d.ts dist/",
37
- "build:watch": "tsc --watch",
36
+ "build": "rm -rf ./dist && tsdown && cp src/globals.d.ts dist/",
37
+ "build:watch": "tsdown --watch",
38
38
  "prepublishOnly": "npm run build",
39
39
  "publish:dev": "npm publish --access public --tag dev",
40
40
  "publish:npm": "release-it"
41
41
  },
42
42
  "dependencies": {
43
43
  "@fastify/cookie": "11.0.2",
44
- "@fastify/multipart": "9.0.3",
44
+ "@fastify/multipart": "9.2.1",
45
45
  "@nestjs/common": "^11.1.6",
46
46
  "@nestjs/core": "^11.1.6",
47
47
  "@nestjs/microservices": "11.1.6",
@@ -62,6 +62,7 @@
62
62
  "rxjs": "^7.8.2",
63
63
  "ts-jest": "^29.4.0",
64
64
  "ts-node": "^10.9.2",
65
+ "tsdown": "0.14.2",
65
66
  "typescript": "^5.9.2"
66
67
  },
67
68
  "publishConfig": {
@@ -1,3 +0,0 @@
1
- export declare const UploadedFiles: (...dataOrPipes: unknown[]) => ParameterDecorator;
2
- export declare const UploadedFile: (...dataOrPipes: unknown[]) => ParameterDecorator;
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,aAAa,mDASzB,CAAC;AAEF,eAAO,MAAM,YAAY,mDAWxB,CAAC"}
@@ -1,21 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.UploadedFile = exports.UploadedFiles = void 0;
4
- const common_1 = require("@nestjs/common");
5
- exports.UploadedFiles = (0, common_1.createParamDecorator)((_data, ctx) => {
6
- const req = ctx.switchToHttp().getRequest();
7
- const allFiles = [];
8
- Object.values(req.storedFiles).forEach((files) => {
9
- allFiles.push(...files);
10
- });
11
- return allFiles;
12
- });
13
- exports.UploadedFile = (0, common_1.createParamDecorator)((fieldName, ctx) => {
14
- const req = ctx.switchToHttp().getRequest();
15
- if (typeof fieldName === "string") {
16
- const files = req.storedFiles[fieldName];
17
- return files && files.length > 0 ? files[0] : null;
18
- }
19
- return req.storedFiles;
20
- });
21
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":";;;AAAA,2CAAwE;AAG3D,QAAA,aAAa,GAAG,IAAA,6BAAoB,EAC/C,CAAC,KAAc,EAAE,GAAqB,EAAE,EAAE;IACxC,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC,UAAU,EAA4B,CAAC;IACtE,MAAM,QAAQ,GAA4B,EAAE,CAAC;IAC7C,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC/C,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC;AAClB,CAAC,CACF,CAAC;AAEW,QAAA,YAAY,GAAG,IAAA,6BAAoB,EAC9C,CAAC,SAA2B,EAAE,GAAqB,EAAE,EAAE;IACrD,MAAM,GAAG,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC,UAAU,EAA4B,CAAC;IAEtE,IAAI,OAAO,SAAS,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;QACzC,OAAO,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACrD,CAAC;IAED,OAAO,GAAG,CAAC,WAAW,CAAC;AACzB,CAAC,CACF,CAAC"}
@@ -1,4 +0,0 @@
1
- import { NestInterceptor, Type } from "@nestjs/common";
2
- import { MultipartOptions } from "../model";
3
- export declare function MultipartInterceptor(options?: MultipartOptions): Type<NestInterceptor>;
4
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/interceptors/index.ts"],"names":[],"mappings":"AACA,OAAO,EAML,eAAe,EACf,IAAI,EACL,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAG5C,wBAAgB,oBAAoB,CAClC,OAAO,GAAE,gBAAqB,GAC7B,IAAI,CAAC,eAAe,CAAC,CAyCvB"}
@@ -1,33 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MultipartInterceptor = MultipartInterceptor;
4
- const common_1 = require("@nestjs/common");
5
- const utils_1 = require("../utils");
6
- function MultipartInterceptor(options = {}) {
7
- class MixinInterceptor {
8
- async intercept(context, next) {
9
- const req = context.switchToHttp().getRequest();
10
- if (!req.isMultipart())
11
- throw new common_1.HttpException("The request should be a form-data", common_1.HttpStatus.BAD_REQUEST);
12
- const files = {};
13
- const body = {};
14
- for await (const part of req.parts()) {
15
- if (part.type !== "file") {
16
- body[part.fieldname] = part.value;
17
- continue;
18
- }
19
- const file = await (0, utils_1.getFileFromPart)(part);
20
- const validationResult = (0, utils_1.validateFile)(file, options);
21
- if (validationResult)
22
- throw new common_1.HttpException(validationResult, common_1.HttpStatus.UNPROCESSABLE_ENTITY);
23
- files[part.fieldname] = files[part.fieldname] || [];
24
- files[part.fieldname].push(file);
25
- }
26
- req.storedFiles = files;
27
- req.body = body;
28
- return next.handle();
29
- }
30
- }
31
- return (0, common_1.mixin)(MixinInterceptor);
32
- }
33
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/interceptors/index.ts"],"names":[],"mappings":";;AAeA,oDA2CC;AAzDD,2CAQwB;AAIxB,oCAAyD;AAEzD,SAAgB,oBAAoB,CAClC,UAA4B,EAAE;IAE9B,MAAM,gBAAgB;QACpB,KAAK,CAAC,SAAS,CACb,OAAyB,EACzB,IAAiB;YAEjB,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAA4B,CAAC;YAE1E,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE;gBACpB,MAAM,IAAI,sBAAa,CACrB,mCAAmC,EACnC,mBAAU,CAAC,WAAW,CACvB,CAAC;YAEJ,MAAM,KAAK,GAA0B,EAAE,CAAC;YACxC,MAAM,IAAI,GAAwB,EAAE,CAAC;YACrC,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC;gBACrC,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oBACzB,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAI,IAAuB,CAAC,KAAK,CAAC;oBACtD,SAAS;gBACX,CAAC;gBACD,MAAM,IAAI,GAAG,MAAM,IAAA,uBAAe,EAAC,IAAI,CAAC,CAAC;gBACzC,MAAM,gBAAgB,GAAG,IAAA,oBAAY,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBAErD,IAAI,gBAAgB;oBAClB,MAAM,IAAI,sBAAa,CACrB,gBAAgB,EAChB,mBAAU,CAAC,oBAAoB,CAChC,CAAC;gBAEJ,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;gBACpD,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnC,CAAC;YACD,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC;YACxB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;YAEhB,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;QACvB,CAAC;KACF;IAED,OAAO,IAAA,cAAK,EAAC,gBAAgB,CAAC,CAAC;AACjC,CAAC"}
@@ -1,6 +0,0 @@
1
- export declare class MultipartOptions {
2
- maxFileSize?: number | undefined;
3
- fileType?: (string | RegExp) | undefined;
4
- constructor(maxFileSize?: number | undefined, fileType?: (string | RegExp) | undefined);
5
- }
6
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/model/index.ts"],"names":[],"mappings":"AAAA,qBAAa,gBAAgB;IAElB,WAAW,CAAC,EAAE,MAAM;IACpB,QAAQ,CAAC,GAAE,MAAM,GAAG,MAAM;gBAD1B,WAAW,CAAC,EAAE,MAAM,YAAA,EACpB,QAAQ,CAAC,GAAE,MAAM,GAAG,MAAM,aAAA;CAEpC"}
@@ -1,11 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MultipartOptions = void 0;
4
- class MultipartOptions {
5
- constructor(maxFileSize, fileType) {
6
- this.maxFileSize = maxFileSize;
7
- this.fileType = fileType;
8
- }
9
- }
10
- exports.MultipartOptions = MultipartOptions;
11
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/model/index.ts"],"names":[],"mappings":";;;AAAA,MAAa,gBAAgB;IAC3B,YACS,WAAoB,EACpB,QAA0B;QAD1B,gBAAW,GAAX,WAAW,CAAS;QACpB,aAAQ,GAAR,QAAQ,CAAkB;IAChC,CAAC;CACL;AALD,4CAKC"}
@@ -1,3 +0,0 @@
1
- export type MultiPartFile = Storage.MultipartFile;
2
- export type MultiPartFiles = Storage.MultipartFile[];
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC;AAClD,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC"}
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
@@ -1,5 +0,0 @@
1
- import { MultipartFile } from "@fastify/multipart";
2
- import { MultipartOptions } from "../model";
3
- export declare const getFileFromPart: (part: MultipartFile) => Promise<Storage.MultipartFile>;
4
- export declare const validateFile: (file: Storage.MultipartFile, options: MultipartOptions) => string | void;
5
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAMnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C,eAAO,MAAM,eAAe,GAC1B,MAAM,aAAa,KAClB,OAAO,CAAC,OAAO,CAAC,aAAa,CAS/B,CAAC;AAEF,eAAO,MAAM,YAAY,GACvB,MAAM,OAAO,CAAC,aAAa,EAC3B,SAAS,gBAAgB,KACxB,MAAM,GAAG,IAaX,CAAC"}
@@ -1,29 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validateFile = exports.getFileFromPart = void 0;
4
- const common_1 = require("@nestjs/common");
5
- const getFileFromPart = async (part) => {
6
- const buffer = await part.toBuffer();
7
- return {
8
- buffer,
9
- size: buffer.byteLength,
10
- filename: part.filename,
11
- mimetype: part.mimetype,
12
- fieldname: part.fieldname,
13
- };
14
- };
15
- exports.getFileFromPart = getFileFromPart;
16
- const validateFile = (file, options) => {
17
- const validators = [];
18
- if (options.maxFileSize)
19
- validators.push(new common_1.MaxFileSizeValidator({ maxSize: options.maxFileSize }));
20
- if (options.fileType)
21
- validators.push(new common_1.FileTypeValidator({ fileType: options.fileType }));
22
- for (const validator of validators) {
23
- if (validator.isValid(file))
24
- continue;
25
- return validator.buildErrorMessage(file);
26
- }
27
- };
28
- exports.validateFile = validateFile;
29
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":";;;AACA,2CAIwB;AAGjB,MAAM,eAAe,GAAG,KAAK,EAClC,IAAmB,EACa,EAAE;IAClC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;IACrC,OAAO;QACL,MAAM;QACN,IAAI,EAAE,MAAM,CAAC,UAAU;QACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC;AACJ,CAAC,CAAC;AAXW,QAAA,eAAe,mBAW1B;AAEK,MAAM,YAAY,GAAG,CAC1B,IAA2B,EAC3B,OAAyB,EACV,EAAE;IACjB,MAAM,UAAU,GAAoB,EAAE,CAAC;IAEvC,IAAI,OAAO,CAAC,WAAW;QACrB,UAAU,CAAC,IAAI,CAAC,IAAI,6BAAoB,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAC9E,IAAI,OAAO,CAAC,QAAQ;QAClB,UAAU,CAAC,IAAI,CAAC,IAAI,0BAAiB,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAEzE,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;YAAE,SAAS;QAEtC,OAAO,SAAS,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC,CAAC;AAhBW,QAAA,YAAY,gBAgBvB"}