@tsed/platform-multer 8.7.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.
- package/.barrelsby.json +5 -0
- package/lib/esm/adapters/express/MulterModule.js +30 -0
- package/lib/esm/adapters/express/MulterModule.js.map +1 -0
- package/lib/esm/adapters/koa/MulterModule.js +57 -0
- package/lib/esm/adapters/koa/MulterModule.js.map +1 -0
- package/lib/esm/common/constants/constants.js +3 -0
- package/lib/esm/common/constants/constants.js.map +1 -0
- package/lib/esm/common/decorators/multerFileSize.js +32 -0
- package/lib/esm/common/decorators/multerFileSize.js.map +1 -0
- package/lib/esm/common/decorators/multerOptions.js +50 -0
- package/lib/esm/common/decorators/multerOptions.js.map +1 -0
- package/lib/esm/common/decorators/multipartFile.js +77 -0
- package/lib/esm/common/decorators/multipartFile.js.map +1 -0
- package/lib/esm/common/errors/MulterException.js +17 -0
- package/lib/esm/common/errors/MulterException.js.map +1 -0
- package/lib/esm/common/index.js +11 -0
- package/lib/esm/common/index.js.map +1 -0
- package/lib/esm/common/interfaces/PlatformMulterSettings.js +2 -0
- package/lib/esm/common/interfaces/PlatformMulterSettings.js.map +1 -0
- package/lib/esm/common/middlewares/PlatformMulterMiddleware.js +40 -0
- package/lib/esm/common/middlewares/PlatformMulterMiddleware.js.map +1 -0
- package/lib/esm/index.js +2 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/types/adapters/express/MulterModule.d.ts +1 -0
- package/lib/types/adapters/koa/MulterModule.d.ts +1 -0
- package/lib/types/common/constants/constants.d.ts +7 -0
- package/lib/types/common/decorators/multerFileSize.d.ts +28 -0
- package/lib/types/common/decorators/multerOptions.d.ts +43 -0
- package/lib/types/common/decorators/multipartFile.d.ts +48 -0
- package/lib/types/common/errors/MulterException.d.ts +14 -0
- package/lib/types/common/index.d.ts +10 -0
- package/lib/types/common/interfaces/PlatformMulterSettings.d.ts +44 -0
- package/lib/types/common/middlewares/PlatformMulterMiddleware.d.ts +11 -0
- package/lib/types/index.d.ts +1 -0
- package/package.json +102 -0
- package/src/adapters/express/MulterModule.ts +40 -0
- package/src/adapters/koa/MulterModule.ts +73 -0
- package/src/common/constants/constants.ts +10 -0
- package/src/common/decorators/multerFileSize.spec.ts +22 -0
- package/src/common/decorators/multerFileSize.ts +32 -0
- package/src/common/decorators/multerOptions.spec.ts +21 -0
- package/src/common/decorators/multerOptions.ts +53 -0
- package/src/common/decorators/multipartFile.spec.ts +260 -0
- package/src/common/decorators/multipartFile.ts +91 -0
- package/src/common/errors/MulterException.ts +20 -0
- package/src/common/index.ts +10 -0
- package/src/common/interfaces/PlatformMulterSettings.ts +45 -0
- package/src/common/middlewares/PlatformMulterMiddleware.spec.ts +98 -0
- package/src/common/middlewares/PlatformMulterMiddleware.ts +46 -0
- package/src/index.ts +1 -0
- package/vitest.config.mts +21 -0
package/package.json
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tsed/platform-multer",
|
|
3
|
+
"description": "Multer adapter package for Ts.ED framework",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"version": "8.7.0",
|
|
6
|
+
"source": "./src/index.ts",
|
|
7
|
+
"main": "./lib/esm/index.js",
|
|
8
|
+
"module": "./lib/esm/index.js",
|
|
9
|
+
"typings": "./lib/types/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"tsed-source": "./src/index.ts",
|
|
13
|
+
"types": "./lib/types/index.d.ts",
|
|
14
|
+
"import": "./lib/esm/index.js",
|
|
15
|
+
"default": "./lib/esm/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./express": {
|
|
18
|
+
"tsed-source": "./src/adapters/express/MulterModule.ts",
|
|
19
|
+
"types": "./lib/types/adapters/express/MulterModule.d.ts",
|
|
20
|
+
"import": "./lib/esm/adapters/express/MulterModule.js",
|
|
21
|
+
"default": "./lib/esm/adapters/express/MulterModule.js"
|
|
22
|
+
},
|
|
23
|
+
"./koa": {
|
|
24
|
+
"tsed-source": "./src/adapters/koa/MulterModule.ts",
|
|
25
|
+
"types": "./lib/types/adapters/koa/MulterModule.d.ts",
|
|
26
|
+
"import": "./lib/esm/adapters/koa/MulterModule.js",
|
|
27
|
+
"default": "./lib/esm/adapters/koa/MulterModule.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "yarn barrels && yarn build:ts",
|
|
32
|
+
"barrels": "barrels",
|
|
33
|
+
"test": "vitest run",
|
|
34
|
+
"build:ts": "tsc --build tsconfig.esm.json",
|
|
35
|
+
"test:ci": "vitest run --coverage.thresholds.autoUpdate=true"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"Multer",
|
|
39
|
+
"TypeScript",
|
|
40
|
+
"typescript",
|
|
41
|
+
"Decorator",
|
|
42
|
+
"decorators",
|
|
43
|
+
"decorator",
|
|
44
|
+
"ESM",
|
|
45
|
+
"multipartfile",
|
|
46
|
+
"Ts.ED"
|
|
47
|
+
],
|
|
48
|
+
"author": "Romain Lenzotti",
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/tsedio/tsed/issues"
|
|
52
|
+
},
|
|
53
|
+
"homepage": "https://github.com/tsedio/tsed/tree/production/packages/platform/platform-multer",
|
|
54
|
+
"repository": "https://github.com/tsedio/tsed",
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@tsed/barrels": "8.7.0",
|
|
57
|
+
"@tsed/core": "8.7.0",
|
|
58
|
+
"@tsed/di": "8.7.0",
|
|
59
|
+
"@tsed/platform-middlewares": "8.7.0",
|
|
60
|
+
"@tsed/typescript": "8.7.0",
|
|
61
|
+
"eslint": "9.12.0",
|
|
62
|
+
"typescript": "5.4.5",
|
|
63
|
+
"vitest": "3.0.9"
|
|
64
|
+
},
|
|
65
|
+
"dependencies": {
|
|
66
|
+
"multer": "^1.4.5-lts.1",
|
|
67
|
+
"tslib": "2.7.0"
|
|
68
|
+
},
|
|
69
|
+
"peerDependencies": {
|
|
70
|
+
"@tsed/core": ">=8.7.0",
|
|
71
|
+
"@tsed/di": ">=8.7.0",
|
|
72
|
+
"@tsed/json-mapper": ">=8.7.0",
|
|
73
|
+
"@tsed/logger": ">=7.0.1",
|
|
74
|
+
"@tsed/openspec": ">=8.7.0",
|
|
75
|
+
"@tsed/platform-middlewares": ">=8.7.0",
|
|
76
|
+
"@tsed/schema": ">=8.7.0",
|
|
77
|
+
"cross-env": "7.0.3"
|
|
78
|
+
},
|
|
79
|
+
"peerDependenciesMeta": {
|
|
80
|
+
"@tsed/core": {
|
|
81
|
+
"optional": false
|
|
82
|
+
},
|
|
83
|
+
"@tsed/di": {
|
|
84
|
+
"optional": false
|
|
85
|
+
},
|
|
86
|
+
"@tsed/json-mapper": {
|
|
87
|
+
"optional": false
|
|
88
|
+
},
|
|
89
|
+
"@tsed/logger": {
|
|
90
|
+
"optional": false
|
|
91
|
+
},
|
|
92
|
+
"@tsed/openspec": {
|
|
93
|
+
"optional": false
|
|
94
|
+
},
|
|
95
|
+
"@tsed/platform-middlewares": {
|
|
96
|
+
"optional": false
|
|
97
|
+
},
|
|
98
|
+
"@tsed/schema": {
|
|
99
|
+
"optional": false
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {promisify} from "node:util";
|
|
2
|
+
|
|
3
|
+
import {injectable} from "@tsed/di";
|
|
4
|
+
import type {Options} from "multer";
|
|
5
|
+
|
|
6
|
+
import {MULTER_MODULE} from "../../common/index.js";
|
|
7
|
+
|
|
8
|
+
async function factory() {
|
|
9
|
+
const {default: multer} = await import("multer");
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
multer,
|
|
13
|
+
get(options: Options) {
|
|
14
|
+
const instance = multer(options);
|
|
15
|
+
|
|
16
|
+
const makePromise = (multer: any, name: string) => {
|
|
17
|
+
// istanbul ignore next
|
|
18
|
+
if (!multer[name]) return;
|
|
19
|
+
|
|
20
|
+
const fn = multer[name];
|
|
21
|
+
|
|
22
|
+
multer[name] = function apply(...args: any[]) {
|
|
23
|
+
const middleware: any = Reflect.apply(fn, this, args);
|
|
24
|
+
|
|
25
|
+
return (req: any, res: any) => promisify(middleware)(req, res);
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
makePromise(instance, "any");
|
|
30
|
+
makePromise(instance, "array");
|
|
31
|
+
makePromise(instance, "fields");
|
|
32
|
+
makePromise(instance, "none");
|
|
33
|
+
makePromise(instance, "single");
|
|
34
|
+
|
|
35
|
+
return instance;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
injectable(MULTER_MODULE).asyncFactory(factory).token();
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {promisify} from "node:util";
|
|
2
|
+
|
|
3
|
+
import {injectable} from "@tsed/di";
|
|
4
|
+
import Koa from "koa";
|
|
5
|
+
import type {Options} from "multer";
|
|
6
|
+
|
|
7
|
+
import {MULTER_MODULE} from "../../common/index.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @ignore
|
|
11
|
+
*/
|
|
12
|
+
function createRawMiddleware(middleware: any) {
|
|
13
|
+
return async (request: Koa.Request) => {
|
|
14
|
+
const ctx: any = request.ctx;
|
|
15
|
+
|
|
16
|
+
await middleware(ctx.req, ctx.res);
|
|
17
|
+
|
|
18
|
+
const forwardKey = (key: string) => {
|
|
19
|
+
if (ctx.req[key]) {
|
|
20
|
+
ctx.request[key] = ctx.req[key];
|
|
21
|
+
ctx[key] = ctx.req[key];
|
|
22
|
+
delete ctx.req[key];
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
if ("request" in ctx) {
|
|
27
|
+
if (ctx.req.body) {
|
|
28
|
+
ctx.request.body = ctx.req.body;
|
|
29
|
+
delete ctx.req.body;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
forwardKey("file");
|
|
33
|
+
forwardKey("files");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @ignore
|
|
40
|
+
*/
|
|
41
|
+
function makePromise(multer: any, name: string) {
|
|
42
|
+
// istanbul ignore next
|
|
43
|
+
if (!multer[name]) return;
|
|
44
|
+
|
|
45
|
+
const fn = multer[name];
|
|
46
|
+
|
|
47
|
+
multer[name] = function apply(...args: any[]) {
|
|
48
|
+
const middleware: any = Reflect.apply(fn, this, args);
|
|
49
|
+
|
|
50
|
+
return createRawMiddleware(promisify(middleware));
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function factory() {
|
|
55
|
+
const {default: multer} = await import("multer");
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
multer,
|
|
59
|
+
get(options: Options) {
|
|
60
|
+
const instance = multer(options);
|
|
61
|
+
|
|
62
|
+
makePromise(instance, "any");
|
|
63
|
+
makePromise(instance, "array");
|
|
64
|
+
makePromise(instance, "fields");
|
|
65
|
+
makePromise(instance, "none");
|
|
66
|
+
makePromise(instance, "single");
|
|
67
|
+
|
|
68
|
+
return instance;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
injectable(MULTER_MODULE).asyncFactory(factory).token();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type {Multer, Options} from "multer";
|
|
2
|
+
|
|
3
|
+
export interface MULTER_MODULE {
|
|
4
|
+
multer: Multer;
|
|
5
|
+
|
|
6
|
+
get(options: Options): Multer;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const MULTER_MODULE = Symbol.for("MULTER_MODULE");
|
|
10
|
+
export const PLATFORM_MULTER_OPTIONS = Symbol.for("PLATFORM_MULTER_OPTIONS");
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {Store} from "@tsed/core";
|
|
2
|
+
|
|
3
|
+
import {PLATFORM_MULTER_OPTIONS} from "../constants/constants.js";
|
|
4
|
+
import {MulterFileSize} from "./multerFileSize.js";
|
|
5
|
+
|
|
6
|
+
describe("MulterFileSize", () => {
|
|
7
|
+
it("should set the file size", () => {
|
|
8
|
+
class Test {
|
|
9
|
+
@MulterFileSize(100)
|
|
10
|
+
file() {}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const store = Store.fromMethod(Test, "file");
|
|
14
|
+
expect(store.get(PLATFORM_MULTER_OPTIONS)).toEqual({
|
|
15
|
+
options: {
|
|
16
|
+
limits: {
|
|
17
|
+
fileSize: 100
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import {MulterOptions} from "./multerOptions.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Define file size limit.
|
|
5
|
+
*
|
|
6
|
+
* ```typescript
|
|
7
|
+
* import {Post} from "@tsed/schema";
|
|
8
|
+
* import {MulterOptions, MultipartFile} from "@tsed/platform-multer";
|
|
9
|
+
* import {Controller} from "@tsed/di";
|
|
10
|
+
* import {Multer} from "@types/multer";
|
|
11
|
+
*
|
|
12
|
+
* type MulterFile = Express.Multer.File;
|
|
13
|
+
*
|
|
14
|
+
* @Controller('/')
|
|
15
|
+
* class MyCtrl {
|
|
16
|
+
* @Post('/file2')
|
|
17
|
+
* @MulterFileSize(1024) // (Ko). Applied for all fields
|
|
18
|
+
* private uploadFile(@MultipartFile("file1") file: MulterFile, @MultipartFile("file2") file2: MulterFile) {
|
|
19
|
+
*
|
|
20
|
+
* }
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* > See the tutorial on the [multer configuration](/docs/upload-files.md).
|
|
25
|
+
* @param fileSize
|
|
26
|
+
* @returns {(target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor}
|
|
27
|
+
* @decorator
|
|
28
|
+
* @multer
|
|
29
|
+
*/
|
|
30
|
+
export function MulterFileSize(fileSize: number): MethodDecorator {
|
|
31
|
+
return MulterOptions({limits: {fileSize}});
|
|
32
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {Store} from "@tsed/core";
|
|
2
|
+
|
|
3
|
+
import {PLATFORM_MULTER_OPTIONS} from "../constants/constants.js";
|
|
4
|
+
import {MulterOptions} from "./multerOptions.js";
|
|
5
|
+
|
|
6
|
+
describe("@MulterOptions()", () => {
|
|
7
|
+
it("should store metadata", () => {
|
|
8
|
+
class Test {
|
|
9
|
+
@MulterOptions({dest: "/"})
|
|
10
|
+
test() {}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const store = Store.fromMethod(Test.prototype, "test");
|
|
14
|
+
|
|
15
|
+
expect(store.get(PLATFORM_MULTER_OPTIONS)).toEqual({
|
|
16
|
+
options: {
|
|
17
|
+
dest: "/"
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {StoreMerge} from "@tsed/core";
|
|
2
|
+
import type {Options} from "multer";
|
|
3
|
+
|
|
4
|
+
import {PLATFORM_MULTER_OPTIONS} from "../constants/constants.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Define multer option for all MultipartFile
|
|
8
|
+
*
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import {PlatformMulterFile, MultipartFile, MulterOptions} from "@tsed/platform-multer";
|
|
11
|
+
* import {Controller} from "@tsed/di";
|
|
12
|
+
* import {Post} from "@tsed/schema";
|
|
13
|
+
*
|
|
14
|
+
* @Controller('/')
|
|
15
|
+
* class MyCtrl {
|
|
16
|
+
* @Post('/file')
|
|
17
|
+
* private uploadFile(@MultipartFile("file1") file: PlatformMulterFile) {
|
|
18
|
+
*
|
|
19
|
+
* }
|
|
20
|
+
*
|
|
21
|
+
* @Post('/file')
|
|
22
|
+
* @MulterOptions({dest: "/other-dir"})
|
|
23
|
+
* private uploadFile(@MultipartFile("file1") file: PlatformMulterFile) {
|
|
24
|
+
*
|
|
25
|
+
* }
|
|
26
|
+
*
|
|
27
|
+
* @Post('/file2')
|
|
28
|
+
* @MulterOptions({dest: "/other-dir"})
|
|
29
|
+
* private uploadFile(@MultipartFile("file1") file: PlatformMulterFile, @MultipartFile("file2") file2: PlatformMulterFile) {
|
|
30
|
+
*
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* @Post('/files')
|
|
34
|
+
* private uploadFile(@MultipartFile("file1") files: PlatformMulterFile[]) {
|
|
35
|
+
*
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* See the tutorial on the [multer configuration](/docs/upload-files.md).
|
|
41
|
+
*
|
|
42
|
+
* @param {multer.Options} options
|
|
43
|
+
* @returns {(target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor}
|
|
44
|
+
* @decorator
|
|
45
|
+
* @multer
|
|
46
|
+
*/
|
|
47
|
+
export function MulterOptions(options: Options): MethodDecorator {
|
|
48
|
+
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
|
|
49
|
+
StoreMerge(PLATFORM_MULTER_OPTIONS, {options})(target, propertyKey, descriptor);
|
|
50
|
+
|
|
51
|
+
return descriptor;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import "@tsed/exceptions";
|
|
2
|
+
import "@tsed/platform-exceptions";
|
|
3
|
+
|
|
4
|
+
import {descriptorOf, Metadata, Store} from "@tsed/core";
|
|
5
|
+
import {ParamTypes} from "@tsed/platform-params";
|
|
6
|
+
import {getSpec, JsonParameterStore, Post, SpecTypes} from "@tsed/schema";
|
|
7
|
+
|
|
8
|
+
import {PLATFORM_MULTER_OPTIONS} from "../constants/constants.js";
|
|
9
|
+
import {MultipartFile} from "./multipartFile.js";
|
|
10
|
+
|
|
11
|
+
class Test {
|
|
12
|
+
test() {}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
describe("@MultipartFile()", () => {
|
|
16
|
+
describe("one file", () => {
|
|
17
|
+
// WHEN
|
|
18
|
+
class TestController {
|
|
19
|
+
@Post("/")
|
|
20
|
+
test(@MultipartFile("file1", 1) file: any) {}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// THEN
|
|
24
|
+
const store = Store.fromMethod(TestController, "test");
|
|
25
|
+
const param = JsonParameterStore.get(TestController, "test", 0);
|
|
26
|
+
|
|
27
|
+
it("should set params properly", () => {
|
|
28
|
+
expect(store.get(PLATFORM_MULTER_OPTIONS)).toEqual({
|
|
29
|
+
fields: [
|
|
30
|
+
{
|
|
31
|
+
maxCount: 1,
|
|
32
|
+
name: "file1"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
});
|
|
36
|
+
expect(param.expression).toEqual("file1.0");
|
|
37
|
+
expect(param.paramType).toEqual(ParamTypes.FILES);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("should set endpoint metadata - OS3", () => {
|
|
41
|
+
expect(getSpec(TestController, {specType: SpecTypes.OPENAPI})).toEqual({
|
|
42
|
+
paths: {
|
|
43
|
+
"/": {
|
|
44
|
+
post: {
|
|
45
|
+
operationId: "testControllerTest",
|
|
46
|
+
parameters: [],
|
|
47
|
+
responses: {
|
|
48
|
+
"400": {
|
|
49
|
+
content: {"application/json": {schema: {$ref: "#/components/schemas/BadRequest"}}},
|
|
50
|
+
description:
|
|
51
|
+
"<File too long | Too many parts | Too many files | Field name too long | Field value too long | Too many fields | Unexpected field> [fieldName] Example: File too long file1"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
requestBody: {
|
|
55
|
+
required: false,
|
|
56
|
+
content: {
|
|
57
|
+
"multipart/form-data": {
|
|
58
|
+
schema: {
|
|
59
|
+
properties: {file1: {type: "string", format: "binary"}},
|
|
60
|
+
type: "object"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
tags: ["TestController"]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
tags: [{name: "TestController"}],
|
|
70
|
+
components: {
|
|
71
|
+
schemas: {
|
|
72
|
+
GenericError: {
|
|
73
|
+
additionalProperties: true,
|
|
74
|
+
properties: {
|
|
75
|
+
message: {
|
|
76
|
+
description: "An error message",
|
|
77
|
+
minLength: 1,
|
|
78
|
+
type: "string"
|
|
79
|
+
},
|
|
80
|
+
name: {
|
|
81
|
+
description: "The error name",
|
|
82
|
+
minLength: 1,
|
|
83
|
+
type: "string"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
required: ["name", "message"],
|
|
87
|
+
type: "object"
|
|
88
|
+
},
|
|
89
|
+
BadRequest: {
|
|
90
|
+
type: "object",
|
|
91
|
+
properties: {
|
|
92
|
+
name: {
|
|
93
|
+
type: "string",
|
|
94
|
+
minLength: 1,
|
|
95
|
+
description: "The error name",
|
|
96
|
+
example: "BAD_REQUEST",
|
|
97
|
+
default: "BAD_REQUEST"
|
|
98
|
+
},
|
|
99
|
+
message: {type: "string", minLength: 1, description: "An error message"},
|
|
100
|
+
status: {type: "number", description: "The status code of the exception", example: 400, default: 400},
|
|
101
|
+
errors: {
|
|
102
|
+
type: "array",
|
|
103
|
+
items: {
|
|
104
|
+
$ref: "#/components/schemas/GenericError"
|
|
105
|
+
},
|
|
106
|
+
description: "A list of related errors"
|
|
107
|
+
},
|
|
108
|
+
stack: {
|
|
109
|
+
type: "string",
|
|
110
|
+
description: "The stack trace (only in development mode)"
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
required: ["name", "message", "status"]
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe("multiple file schema", () => {
|
|
122
|
+
// WHEN
|
|
123
|
+
class TestController {
|
|
124
|
+
@Post("/")
|
|
125
|
+
test(@MultipartFile("file1", 4) file: any[]) {}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// THEN
|
|
129
|
+
const store = Store.fromMethod(TestController, "test");
|
|
130
|
+
const param = JsonParameterStore.get(TestController, "test", 0);
|
|
131
|
+
|
|
132
|
+
it("should set params properly", () => {
|
|
133
|
+
expect(store.get(PLATFORM_MULTER_OPTIONS)).toEqual({
|
|
134
|
+
fields: [
|
|
135
|
+
{
|
|
136
|
+
maxCount: 4,
|
|
137
|
+
name: "file1"
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
});
|
|
141
|
+
expect(param.expression).toEqual("file1");
|
|
142
|
+
expect(param.paramType).toEqual(ParamTypes.FILES);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("should set endpoint metadata - OS3", () => {
|
|
146
|
+
expect(getSpec(TestController, {specType: SpecTypes.OPENAPI})).toEqual({
|
|
147
|
+
paths: {
|
|
148
|
+
"/": {
|
|
149
|
+
post: {
|
|
150
|
+
operationId: "testControllerTest",
|
|
151
|
+
parameters: [],
|
|
152
|
+
responses: {
|
|
153
|
+
"400": {
|
|
154
|
+
content: {"application/json": {schema: {$ref: "#/components/schemas/BadRequest"}}},
|
|
155
|
+
description:
|
|
156
|
+
"<File too long | Too many parts | Too many files | Field name too long | Field value too long | Too many fields | Unexpected field> [fieldName] Example: File too long file1"
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
requestBody: {
|
|
160
|
+
required: false,
|
|
161
|
+
content: {
|
|
162
|
+
"multipart/form-data": {
|
|
163
|
+
schema: {
|
|
164
|
+
properties: {file1: {type: "array", items: {type: "string", format: "binary"}}},
|
|
165
|
+
type: "object"
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
tags: ["TestController"]
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
tags: [{name: "TestController"}],
|
|
175
|
+
components: {
|
|
176
|
+
schemas: {
|
|
177
|
+
GenericError: {
|
|
178
|
+
additionalProperties: true,
|
|
179
|
+
properties: {
|
|
180
|
+
message: {
|
|
181
|
+
description: "An error message",
|
|
182
|
+
minLength: 1,
|
|
183
|
+
type: "string"
|
|
184
|
+
},
|
|
185
|
+
name: {
|
|
186
|
+
description: "The error name",
|
|
187
|
+
minLength: 1,
|
|
188
|
+
type: "string"
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
required: ["name", "message"],
|
|
192
|
+
type: "object"
|
|
193
|
+
},
|
|
194
|
+
BadRequest: {
|
|
195
|
+
type: "object",
|
|
196
|
+
properties: {
|
|
197
|
+
name: {
|
|
198
|
+
type: "string",
|
|
199
|
+
minLength: 1,
|
|
200
|
+
description: "The error name",
|
|
201
|
+
example: "BAD_REQUEST",
|
|
202
|
+
default: "BAD_REQUEST"
|
|
203
|
+
},
|
|
204
|
+
message: {
|
|
205
|
+
type: "string",
|
|
206
|
+
minLength: 1,
|
|
207
|
+
description: "An error message"
|
|
208
|
+
},
|
|
209
|
+
status: {type: "number", description: "The status code of the exception", example: 400, default: 400},
|
|
210
|
+
errors: {
|
|
211
|
+
type: "array",
|
|
212
|
+
items: {
|
|
213
|
+
$ref: "#/components/schemas/GenericError"
|
|
214
|
+
},
|
|
215
|
+
description: "A list of related errors"
|
|
216
|
+
},
|
|
217
|
+
stack: {
|
|
218
|
+
type: "string",
|
|
219
|
+
description: "The stack trace (only in development mode)"
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
required: ["name", "message", "status"]
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe("multiple files", () => {
|
|
231
|
+
afterAll(() => {
|
|
232
|
+
vi.clearAllMocks();
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it("should set params metadata", () => {
|
|
236
|
+
const store = Store.from(Test.prototype, "test", descriptorOf(Test.prototype, "test"));
|
|
237
|
+
store.delete("multipartAdded");
|
|
238
|
+
|
|
239
|
+
// @ts-ignore
|
|
240
|
+
store.delete(PLATFORM_MULTER_OPTIONS);
|
|
241
|
+
vi.spyOn(Store, "fromMethod").mockReturnValue(store);
|
|
242
|
+
vi.spyOn(Metadata, "getParamTypes").mockReturnValue([Array]);
|
|
243
|
+
|
|
244
|
+
MultipartFile("file1", 8)(Test.prototype, "test", 0);
|
|
245
|
+
|
|
246
|
+
expect(store.get(PLATFORM_MULTER_OPTIONS)).toEqual({
|
|
247
|
+
fields: [
|
|
248
|
+
{
|
|
249
|
+
maxCount: 8,
|
|
250
|
+
name: "file1"
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
const param = JsonParameterStore.get(Test, "test", 0);
|
|
256
|
+
expect(param.expression).toEqual("file1");
|
|
257
|
+
expect(param.paramType).toEqual(ParamTypes.FILES);
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
});
|