node-server-engine 1.4.9 → 1.5.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/.commitlintrc.js +27 -0
- package/.releaserc.js +56 -0
- package/README.md +154 -2
- package/dist/const/tokenIssuer.js +1 -0
- package/dist/const/tokenIssuer.js.map +1 -1
- package/dist/db/models/SequelizeMeta.js +3 -1
- package/dist/db/models/SequelizeMeta.js.map +1 -1
- package/dist/entities/ElasticSearch/ElasticSearch.js +1 -2
- package/dist/entities/ElasticSearch/ElasticSearch.js.map +1 -1
- package/dist/entities/SocketClient/SocketClient.js +1 -0
- package/dist/entities/SocketClient/SocketClient.js.map +1 -1
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/middleware/checkPermission/checkPermission.d.ts +1 -1
- package/dist/middleware/checkPermission/checkPermission.js +4 -2
- package/dist/middleware/checkPermission/checkPermission.js.map +1 -1
- package/dist/utils/jwt/jwt.js +1 -1
- package/dist/utils/jwt/jwt.js.map +1 -1
- package/dist/utils/semverCompare/semverCompare.js +1 -5
- package/dist/utils/semverCompare/semverCompare.js.map +1 -1
- package/package.json +30 -19
- package/.env.example +0 -186
- package/.github/workflows/publish.yml +0 -41
- package/.prettierrc +0 -7
- package/Dockerfile +0 -31
- package/babel.config.json +0 -34
- package/eslint.config.mjs +0 -11
- package/src/const/DebeziumEvent.ts +0 -6
- package/src/const/LogSeverity.ts +0 -7
- package/src/const/index.ts +0 -5
- package/src/const/metrics.ts +0 -6
- package/src/const/mime.ts +0 -37
- package/src/const/tokenIssuer.ts +0 -7
- package/src/db/migrations/20241030121500-create-sequelize-meta-table.ts +0 -29
- package/src/db/models/SequelizeMeta.ts +0 -16
- package/src/db/models/index.ts +0 -2
- package/src/entities/ElasticSearch/ElasticSearch.ts +0 -103
- package/src/entities/ElasticSearch/ElasticSearch.types.ts +0 -7
- package/src/entities/ElasticSearch/index.ts +0 -2
- package/src/entities/Endpoint/Endpoint.test.ts +0 -248
- package/src/entities/Endpoint/Endpoint.ts +0 -221
- package/src/entities/Endpoint/Endpoint.types.ts +0 -181
- package/src/entities/Endpoint/index.ts +0 -2
- package/src/entities/EngineError/EngineError.ts +0 -28
- package/src/entities/EngineError/EngineError.types.ts +0 -15
- package/src/entities/EngineError/index.ts +0 -2
- package/src/entities/KeySet/KeySet.test.ts +0 -126
- package/src/entities/KeySet/KeySet.ts +0 -172
- package/src/entities/KeySet/KeySet.types.ts +0 -28
- package/src/entities/KeySet/index.ts +0 -2
- package/src/entities/LifecycleController/LifecycleController.test.ts +0 -48
- package/src/entities/LifecycleController/LifecycleController.ts +0 -24
- package/src/entities/LifecycleController/LifecycleController.types.ts +0 -5
- package/src/entities/LifecycleController/index.ts +0 -2
- package/src/entities/Localizator/Localizator.ts +0 -139
- package/src/entities/Localizator/Localizator.types.ts +0 -52
- package/src/entities/Localizator/guessNamingConvention/guessNamingConvention.test.ts +0 -165
- package/src/entities/Localizator/guessNamingConvention/guessNamingConvention.ts +0 -58
- package/src/entities/Localizator/guessNamingConvention/index.ts +0 -1
- package/src/entities/Localizator/index.ts +0 -2
- package/src/entities/MessageHandler/MessageHandler.test.ts +0 -130
- package/src/entities/MessageHandler/MessageHandler.ts +0 -72
- package/src/entities/MessageHandler/MessageHandler.types.ts +0 -15
- package/src/entities/MessageHandler/index.ts +0 -2
- package/src/entities/PubSub/PubSub.test.ts +0 -297
- package/src/entities/PubSub/PubSub.ts +0 -202
- package/src/entities/PubSub/PubSub.types.ts +0 -76
- package/src/entities/PubSub/handleMessage/handleMessage.test.ts +0 -102
- package/src/entities/PubSub/handleMessage/handleMessage.ts +0 -65
- package/src/entities/PubSub/handleMessage/index.ts +0 -1
- package/src/entities/PubSub/index.ts +0 -2
- package/src/entities/PushNotification/PushNotification.test.ts +0 -35
- package/src/entities/PushNotification/PushNotification.ts +0 -44
- package/src/entities/PushNotification/PushNotification.types.ts +0 -25
- package/src/entities/PushNotification/index.ts +0 -2
- package/src/entities/Redis/Redis.ts +0 -71
- package/src/entities/Redis/Redis.types.ts +0 -19
- package/src/entities/Redis/Redis.validate.ts +0 -17
- package/src/entities/Redis/index.ts +0 -2
- package/src/entities/Sequelize/Sequelize.config.ts +0 -59
- package/src/entities/Sequelize/Sequelize.test.ts +0 -21
- package/src/entities/Sequelize/Sequelize.ts +0 -75
- package/src/entities/Sequelize/Sequelize.types.ts +0 -10
- package/src/entities/Sequelize/Sequelize.validate.ts +0 -15
- package/src/entities/Sequelize/index.ts +0 -2
- package/src/entities/Server/Server.const.ts +0 -56
- package/src/entities/Server/Server.test.ts +0 -272
- package/src/entities/Server/Server.ts +0 -471
- package/src/entities/Server/Server.types.ts +0 -88
- package/src/entities/Server/index.ts +0 -2
- package/src/entities/SocketClient/SocketClient.test.ts +0 -392
- package/src/entities/SocketClient/SocketClient.ts +0 -401
- package/src/entities/SocketClient/SocketClient.types.ts +0 -62
- package/src/entities/SocketClient/index.ts +0 -2
- package/src/entities/SocketClient/parseMessage/index.ts +0 -1
- package/src/entities/SocketClient/parseMessage/parseMessage.test.ts +0 -20
- package/src/entities/SocketClient/parseMessage/parseMessage.ts +0 -26
- package/src/entities/Storage/Storage.test.ts +0 -58
- package/src/entities/Storage/Storage.ts +0 -219
- package/src/entities/Storage/Storage.types.ts +0 -57
- package/src/entities/Storage/index.ts +0 -2
- package/src/entities/ValidationError/ValidationError.ts +0 -34
- package/src/entities/ValidationError/index.ts +0 -1
- package/src/entities/WebError/WebError.test.ts +0 -18
- package/src/entities/WebError/WebError.ts +0 -23
- package/src/entities/WebError/WebError.types.ts +0 -9
- package/src/entities/WebError/index.ts +0 -2
- package/src/entities/index.ts +0 -16
- package/src/index.ts +0 -6
- package/src/metrics/debug.ts +0 -10
- package/src/metrics/index.ts +0 -2
- package/src/metrics/request.ts +0 -17
- package/src/middleware/authHmac/authHmac.test.ts +0 -86
- package/src/middleware/authHmac/authHmac.ts +0 -56
- package/src/middleware/authHmac/authHmac.types.ts +0 -7
- package/src/middleware/authHmac/index.ts +0 -2
- package/src/middleware/authJwt/authJwt.test.ts +0 -54
- package/src/middleware/authJwt/authJwt.ts +0 -55
- package/src/middleware/authJwt/authJwt.types.ts +0 -14
- package/src/middleware/authJwt/index.ts +0 -2
- package/src/middleware/authStatic/authStatic.test.ts +0 -36
- package/src/middleware/authStatic/authStatic.ts +0 -45
- package/src/middleware/authStatic/index.ts +0 -1
- package/src/middleware/authTls/authTls.test.ts +0 -138
- package/src/middleware/authTls/authTls.ts +0 -119
- package/src/middleware/authTls/authTls.types.ts +0 -13
- package/src/middleware/authTls/index.ts +0 -2
- package/src/middleware/checkPermission/checkPermission.ts +0 -33
- package/src/middleware/checkPermission/index.ts +0 -1
- package/src/middleware/error/error.test.ts +0 -60
- package/src/middleware/error/error.ts +0 -25
- package/src/middleware/error/index.ts +0 -1
- package/src/middleware/fileUploader/fileUploader.ts +0 -154
- package/src/middleware/fileUploader/fileUploader.types.ts +0 -35
- package/src/middleware/fileUploader/index.ts +0 -2
- package/src/middleware/fileUploader/isMultiPart/index.ts +0 -1
- package/src/middleware/fileUploader/isMultiPart/isMultipart.ts +0 -9
- package/src/middleware/fileUploader/validate/index.ts +0 -1
- package/src/middleware/fileUploader/validate/validate.ts +0 -27
- package/src/middleware/fourOhFour/fourOhFour.test.ts +0 -14
- package/src/middleware/fourOhFour/fourOhFour.ts +0 -13
- package/src/middleware/fourOhFour/index.ts +0 -1
- package/src/middleware/geminiFileUploader/geminiFileUploader.ts +0 -68
- package/src/middleware/geminiFileUploader/index.ts +0 -1
- package/src/middleware/healthCheck/healthCheck.test.ts +0 -12
- package/src/middleware/healthCheck/healthCheck.ts +0 -14
- package/src/middleware/healthCheck/index.ts +0 -1
- package/src/middleware/index.ts +0 -17
- package/src/middleware/metrics/index.ts +0 -1
- package/src/middleware/metrics/metrics.test.ts +0 -46
- package/src/middleware/metrics/metrics.ts +0 -24
- package/src/middleware/multiPartFileUploader/index.ts +0 -2
- package/src/middleware/multiPartFileUploader/multiPartFileUploader.ts +0 -249
- package/src/middleware/multiPartFileUploader/multiPartFileUploader.types.ts +0 -23
- package/src/middleware/multiPartFileUploader/validate/index.ts +0 -1
- package/src/middleware/multiPartFileUploader/validate/validate.ts +0 -27
- package/src/middleware/requestMetrics/index.ts +0 -1
- package/src/middleware/requestMetrics/requestMetrics.test.ts +0 -77
- package/src/middleware/requestMetrics/requestMetrics.ts +0 -20
- package/src/middleware/swaggerDocs/index.ts +0 -2
- package/src/middleware/swaggerDocs/swaggerDocs.ts +0 -114
- package/src/middleware/swaggerDocs/swaggerDocs.types.ts +0 -41
- package/src/middleware/userResolver/index.ts +0 -1
- package/src/middleware/userResolver/userResolver.ts +0 -53
- package/src/middleware/validate/index.ts +0 -1
- package/src/middleware/validate/validate.test.ts +0 -43
- package/src/middleware/validate/validate.ts +0 -25
- package/src/middleware/version/index.ts +0 -1
- package/src/middleware/version/version.test.ts +0 -23
- package/src/middleware/version/version.ts +0 -12
- package/src/utils/checkEnvironment/index.ts +0 -49
- package/src/utils/createHttpServer/createHttpServer.test.ts +0 -24
- package/src/utils/createHttpServer/createHttpServer.ts +0 -34
- package/src/utils/createHttpServer/createHttpServer.validate.ts +0 -17
- package/src/utils/createHttpServer/index.ts +0 -1
- package/src/utils/createSortedObject/createSortedObject.ts +0 -20
- package/src/utils/createSortedObject/createSortedObjet.test.ts +0 -47
- package/src/utils/createSortedObject/index.ts +0 -1
- package/src/utils/dbMigration/dbMigration.test.ts +0 -209
- package/src/utils/dbMigration/dbMigration.ts +0 -199
- package/src/utils/dbMigration/dbMigration.types.ts +0 -11
- package/src/utils/dbMigration/index.ts +0 -2
- package/src/utils/dbMigration/migrateMetadataTable/index.ts +0 -1
- package/src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.test.ts +0 -59
- package/src/utils/dbMigration/migrateMetadataTable/migrateMetadataTable.ts +0 -102
- package/src/utils/envAssert/envAssert.ts +0 -31
- package/src/utils/envAssert/index.ts +0 -1
- package/src/utils/envAssert/validators/hostList.ts +0 -17
- package/src/utils/envAssert/validators/index.ts +0 -5
- package/src/utils/envAssert/validators/ipList.ts +0 -13
- package/src/utils/envAssert/validators/path.ts +0 -13
- package/src/utils/envAssert/validators/string.ts +0 -9
- package/src/utils/envAssert/validators/stringList.ts +0 -13
- package/src/utils/filter/filter.ts +0 -17
- package/src/utils/filter/index.ts +0 -1
- package/src/utils/geminiFileUpload/geminiFileUpload.ts +0 -93
- package/src/utils/geminiFileUpload/index.ts +0 -1
- package/src/utils/hmac/checkEnv/checkEnv.test.ts +0 -18
- package/src/utils/hmac/checkEnv/checkEnv.ts +0 -9
- package/src/utils/hmac/checkEnv/index.ts +0 -1
- package/src/utils/hmac/createHmac/createHmac.ts +0 -33
- package/src/utils/hmac/createHmac/index.ts +0 -1
- package/src/utils/hmac/index.ts +0 -4
- package/src/utils/hmac/index.types.ts +0 -13
- package/src/utils/hmac/signPayload/index.ts +0 -1
- package/src/utils/hmac/signPayload/signPayload.ts +0 -16
- package/src/utils/hmac/verifySignature/index.ts +0 -1
- package/src/utils/hmac/verifySignature/verifySignature.ts +0 -24
- package/src/utils/index.ts +0 -29
- package/src/utils/jwt/index.ts +0 -2
- package/src/utils/jwt/jwt.test.ts +0 -28
- package/src/utils/jwt/jwt.ts +0 -182
- package/src/utils/jwt/jwt.types.ts +0 -21
- package/src/utils/report/index.ts +0 -3
- package/src/utils/report/output.ts +0 -45
- package/src/utils/report/output.types.ts +0 -70
- package/src/utils/report/report.test.ts +0 -133
- package/src/utils/report/report.ts +0 -133
- package/src/utils/report/report.types.ts +0 -13
- package/src/utils/request/index.ts +0 -1
- package/src/utils/request/request.test.ts +0 -26
- package/src/utils/request/request.ts +0 -48
- package/src/utils/secretManager/index.ts +0 -2
- package/src/utils/secretManager/secretLoader.ts +0 -62
- package/src/utils/secretManager/secretResolver.ts +0 -35
- package/src/utils/semverCompare/index.ts +0 -1
- package/src/utils/semverCompare/semverCompare.test.ts +0 -49
- package/src/utils/semverCompare/semverCompare.ts +0 -60
- package/src/utils/sendEmail/index.ts +0 -2
- package/src/utils/sendEmail/sendEmail.ts +0 -61
- package/src/utils/sendEmail/sendEmail.types.ts +0 -61
- package/src/utils/sendPush/index.ts +0 -2
- package/src/utils/sendPush/sendPush.ts +0 -20
- package/src/utils/sendPush/sendPush.types.ts +0 -25
- package/src/utils/tlsConfig/index.ts +0 -2
- package/src/utils/tlsConfig/tlsConfig.test.ts +0 -32
- package/src/utils/tlsConfig/tlsConfig.ts +0 -47
- package/src/utils/tlsConfig/tlsConfig.types.ts +0 -11
- package/src/utils/tlsConfig/tlsConfig.validate.ts +0 -25
- package/src/utils/tlsRequest/index.ts +0 -1
- package/src/utils/tlsRequest/tlsRequest.test.ts +0 -63
- package/src/utils/tlsRequest/tlsRequest.ts +0 -12
- package/src/utils/trimPathSlash/index.ts +0 -1
- package/src/utils/trimPathSlash/trimPathSlash.test.ts +0 -26
- package/src/utils/trimPathSlash/trimPathSlash.ts +0 -8
- package/test/env.ts +0 -53
- package/test/factory/index.ts +0 -8
- package/test/factory/sequelizeMeta.ts +0 -12
- package/test/hooks.ts +0 -35
- package/test/index.ts +0 -3
- package/test/stub/index.ts +0 -3
- package/test/stub/stubLocales.ts +0 -68
- package/test/stub/stubPubSub.ts +0 -7
- package/test/stub/stubStorage.ts +0 -77
- package/test/stub/stubStorage.types.ts +0 -11
- package/test/utils/app.ts +0 -31
- package/test/utils/index.ts +0 -1
- package/tsconfig.build.json +0 -5
- package/tsconfig.json +0 -32
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from 'express';
|
|
2
|
-
import multer from 'multer';
|
|
3
|
-
import fs from 'fs-extra';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import { Schema } from 'express-validator';
|
|
6
|
-
import { reportDebug, reportError } from 'utils';
|
|
7
|
-
import { WebError } from 'entities/WebError';
|
|
8
|
-
import { validate } from './validate';
|
|
9
|
-
import { MultiPartFileUploaderConfig } from './multiPartFileUploader.types';
|
|
10
|
-
|
|
11
|
-
const namespace = 'engine:middleware:multiPartFileUploader';
|
|
12
|
-
|
|
13
|
-
const TEMP_DIR: string = path.join(
|
|
14
|
-
process.env.FILE_STORAGE_FOLDER || './uploads',
|
|
15
|
-
'temp_chunks'
|
|
16
|
-
);
|
|
17
|
-
const FILE_DIR: string = path.join(
|
|
18
|
-
process.env.FILE_STORAGE_FOLDER || './uploads',
|
|
19
|
-
'completed_files'
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
fs.ensureDirSync(FILE_DIR);
|
|
23
|
-
fs.ensureDirSync(TEMP_DIR);
|
|
24
|
-
|
|
25
|
-
const storage = multer.memoryStorage();
|
|
26
|
-
|
|
27
|
-
export function multiPartFileUploader(
|
|
28
|
-
filesOption: MultiPartFileUploaderConfig,
|
|
29
|
-
validator: Schema
|
|
30
|
-
) {
|
|
31
|
-
return async (
|
|
32
|
-
req: Request,
|
|
33
|
-
res: Response,
|
|
34
|
-
next: NextFunction
|
|
35
|
-
): Promise<void> => {
|
|
36
|
-
try {
|
|
37
|
-
reportDebug({ namespace, message: 'Starting file upload middleware' });
|
|
38
|
-
|
|
39
|
-
const uploadSingle = multer({ storage }).single('file');
|
|
40
|
-
uploadSingle(req, res, async (err) => {
|
|
41
|
-
if (err) {
|
|
42
|
-
reportError('Error uploading chunk');
|
|
43
|
-
return next(
|
|
44
|
-
new WebError({
|
|
45
|
-
statusCode: 500,
|
|
46
|
-
errorCode: 'upload-failed',
|
|
47
|
-
message: 'Error uploading file chunk',
|
|
48
|
-
data: { error: err.message }
|
|
49
|
-
})
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
try {
|
|
54
|
-
reportDebug({ namespace, message: 'Validating request' });
|
|
55
|
-
await validate(req, validator);
|
|
56
|
-
} catch (error) {
|
|
57
|
-
reportDebug({
|
|
58
|
-
namespace,
|
|
59
|
-
message: 'Validation failed',
|
|
60
|
-
data: { error }
|
|
61
|
-
});
|
|
62
|
-
return next(
|
|
63
|
-
new WebError({
|
|
64
|
-
statusCode: 400,
|
|
65
|
-
errorCode: 'validation-failed',
|
|
66
|
-
message: 'Validation failed for file upload',
|
|
67
|
-
data: { error: (error as Error).message }
|
|
68
|
-
})
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const { filename, totalChunks, chunkIndex, uniqueID } = req.body;
|
|
73
|
-
reportDebug({
|
|
74
|
-
namespace,
|
|
75
|
-
message: 'Received chunk data',
|
|
76
|
-
data: { filename, totalChunks, chunkIndex, uniqueID }
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
if (
|
|
80
|
-
!filename ||
|
|
81
|
-
!totalChunks ||
|
|
82
|
-
chunkIndex === undefined ||
|
|
83
|
-
!uniqueID ||
|
|
84
|
-
!req.file
|
|
85
|
-
) {
|
|
86
|
-
return next(
|
|
87
|
-
new WebError({
|
|
88
|
-
statusCode: 400,
|
|
89
|
-
errorCode: 'missing-field',
|
|
90
|
-
message: 'Missing required fields',
|
|
91
|
-
data: {
|
|
92
|
-
filename,
|
|
93
|
-
totalChunks,
|
|
94
|
-
chunkIndex,
|
|
95
|
-
uniqueID,
|
|
96
|
-
receivedChunk: !!req.file
|
|
97
|
-
}
|
|
98
|
-
})
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (
|
|
103
|
-
filesOption?.maxSize &&
|
|
104
|
-
req.file.size > parseInt(filesOption?.maxSize, 10)
|
|
105
|
-
) {
|
|
106
|
-
return next(
|
|
107
|
-
new WebError({
|
|
108
|
-
statusCode: 400,
|
|
109
|
-
errorCode: 'chunk-too-large',
|
|
110
|
-
message: 'Uploaded chunk exceeds the maximum allowed size',
|
|
111
|
-
data: {
|
|
112
|
-
maxSize: filesOption.maxSize,
|
|
113
|
-
receivedSize: req.file.size
|
|
114
|
-
}
|
|
115
|
-
})
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
const sessionFolder = path.join(TEMP_DIR, uniqueID);
|
|
120
|
-
fs.ensureDirSync(sessionFolder);
|
|
121
|
-
const chunkPath = path.join(
|
|
122
|
-
sessionFolder,
|
|
123
|
-
`${filename}.part${chunkIndex}`
|
|
124
|
-
);
|
|
125
|
-
|
|
126
|
-
try {
|
|
127
|
-
reportDebug({
|
|
128
|
-
namespace,
|
|
129
|
-
message: 'Writing chunk to disk',
|
|
130
|
-
data: { chunkPath }
|
|
131
|
-
});
|
|
132
|
-
await fs.writeFile(chunkPath, req.file.buffer);
|
|
133
|
-
} catch (writeErr) {
|
|
134
|
-
return next(
|
|
135
|
-
new WebError({
|
|
136
|
-
statusCode: 500,
|
|
137
|
-
errorCode: 'chunk-write-failed',
|
|
138
|
-
message: 'Failed to write chunk',
|
|
139
|
-
data: { chunkIndex, error: (writeErr as Error).message }
|
|
140
|
-
})
|
|
141
|
-
);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const uploadedChunks = await fs.readdir(sessionFolder);
|
|
145
|
-
reportDebug({
|
|
146
|
-
namespace,
|
|
147
|
-
message: 'Uploaded chunk count',
|
|
148
|
-
data: { uploadedChunks: uploadedChunks.length, totalChunks }
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
if (uploadedChunks.length === parseInt(totalChunks, 10)) {
|
|
152
|
-
try {
|
|
153
|
-
const finalFilePath = path.join(
|
|
154
|
-
FILE_DIR,
|
|
155
|
-
`${uniqueID}_${filename}`
|
|
156
|
-
);
|
|
157
|
-
await mergeChunks(
|
|
158
|
-
filename,
|
|
159
|
-
totalChunks,
|
|
160
|
-
sessionFolder,
|
|
161
|
-
finalFilePath
|
|
162
|
-
);
|
|
163
|
-
req.multipartFile = {
|
|
164
|
-
isPending: false,
|
|
165
|
-
originalname: filename,
|
|
166
|
-
uniqueID,
|
|
167
|
-
filePath: finalFilePath
|
|
168
|
-
};
|
|
169
|
-
} catch (mergeErr) {
|
|
170
|
-
return next(
|
|
171
|
-
new WebError({
|
|
172
|
-
statusCode: 500,
|
|
173
|
-
errorCode: 'file-merge-failed',
|
|
174
|
-
message: 'Error merging file chunks',
|
|
175
|
-
data: { error: (mergeErr as Error).message }
|
|
176
|
-
})
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
return next();
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
req.multipartFile = {
|
|
183
|
-
isPending: true,
|
|
184
|
-
originalname: filename,
|
|
185
|
-
uniqueID,
|
|
186
|
-
chunkIndex,
|
|
187
|
-
totalChunks
|
|
188
|
-
};
|
|
189
|
-
next();
|
|
190
|
-
});
|
|
191
|
-
} catch (error) {
|
|
192
|
-
next(
|
|
193
|
-
new WebError({
|
|
194
|
-
statusCode: 500,
|
|
195
|
-
errorCode: 'unexpected-error',
|
|
196
|
-
message: 'Unexpected error in file upload',
|
|
197
|
-
data: { error: (error as Error).message }
|
|
198
|
-
})
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
async function mergeChunks(
|
|
205
|
-
filename: string,
|
|
206
|
-
totalChunks: string | number,
|
|
207
|
-
sessionFolder: string,
|
|
208
|
-
finalFilePath: string
|
|
209
|
-
): Promise<void> {
|
|
210
|
-
const writeStream = fs.createWriteStream(finalFilePath);
|
|
211
|
-
reportDebug({
|
|
212
|
-
namespace,
|
|
213
|
-
message: 'Merging file chunks',
|
|
214
|
-
data: { finalFilePath }
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
for (let i = 0; i < parseInt(totalChunks as string, 10); i++) {
|
|
218
|
-
const partPath = path.join(sessionFolder, `${filename}.part${i}`);
|
|
219
|
-
try {
|
|
220
|
-
const chunkData = await fs.readFile(partPath);
|
|
221
|
-
writeStream.write(chunkData);
|
|
222
|
-
} catch (error) {
|
|
223
|
-
throw new WebError({
|
|
224
|
-
statusCode: 500,
|
|
225
|
-
errorCode: 'chunk-read-failed',
|
|
226
|
-
message: `Error reading chunk ${i}`,
|
|
227
|
-
data: { error: (error as Error).message }
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
fs.remove(partPath).catch((err: Error) =>
|
|
231
|
-
reportError(`Error removing part ${partPath}: ${err.message}`)
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
writeStream.end();
|
|
236
|
-
return new Promise<void>((resolve, reject) => {
|
|
237
|
-
writeStream.on('finish', () => resolve(undefined));
|
|
238
|
-
writeStream.on('error', (error) =>
|
|
239
|
-
reject(
|
|
240
|
-
new WebError({
|
|
241
|
-
statusCode: 500,
|
|
242
|
-
errorCode: 'file-merge-error',
|
|
243
|
-
message: 'Error merging file chunks',
|
|
244
|
-
data: { error: (error as Error).message }
|
|
245
|
-
})
|
|
246
|
-
)
|
|
247
|
-
);
|
|
248
|
-
});
|
|
249
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
// Extend Express request object to include `files`
|
|
2
|
-
declare global {
|
|
3
|
-
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
4
|
-
namespace Express {
|
|
5
|
-
interface Request {
|
|
6
|
-
/** Uploaded files mapped by field name */
|
|
7
|
-
multipartFile?: {
|
|
8
|
-
isPending: boolean;
|
|
9
|
-
originalname: string;
|
|
10
|
-
uniqueID: string;
|
|
11
|
-
filePath?: string;
|
|
12
|
-
chunkIndex?: number;
|
|
13
|
-
totalChunks?: number;
|
|
14
|
-
};
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** Configuration for Multi part file upload */
|
|
20
|
-
export interface MultiPartFileUploaderConfig {
|
|
21
|
-
required?: boolean;
|
|
22
|
-
maxSize?: string;
|
|
23
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './validate';
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { Request } from 'express';
|
|
2
|
-
import { Schema } from 'express-validator';
|
|
3
|
-
import { validate as validateMiddleware } from 'middleware/validate';
|
|
4
|
-
|
|
5
|
-
/** Validate a schema against a request using our validation middleware */
|
|
6
|
-
export async function validate(
|
|
7
|
-
request: Request,
|
|
8
|
-
schema: Schema
|
|
9
|
-
): Promise<void> {
|
|
10
|
-
return new Promise((resolve, reject) => {
|
|
11
|
-
// Generate a validation chain using our middleware
|
|
12
|
-
const validationChain = validateMiddleware(schema).flat();
|
|
13
|
-
if (!validationChain.length) resolve();
|
|
14
|
-
// Recursively go through each middleware by imitating the next function from express
|
|
15
|
-
let position = -1;
|
|
16
|
-
const next = (error?: unknown): void => {
|
|
17
|
-
if (error) reject(error);
|
|
18
|
-
position++;
|
|
19
|
-
if (position === validationChain.length) {
|
|
20
|
-
resolve();
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
validationChain[position](request, undefined, next);
|
|
24
|
-
};
|
|
25
|
-
next();
|
|
26
|
-
});
|
|
27
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './requestMetrics';
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { expect } from 'chai';
|
|
2
|
-
import express from 'express';
|
|
3
|
-
import { faker } from '@faker-js/faker';
|
|
4
|
-
import { stub, match, SinonStub } from 'sinon';
|
|
5
|
-
import request from 'supertest';
|
|
6
|
-
import { requestMetrics } from './requestMetrics';
|
|
7
|
-
import { httpRequestCount, httpRequestDuration } from 'metrics/request';
|
|
8
|
-
|
|
9
|
-
describe('Middleware - requestMetrics', function () {
|
|
10
|
-
let requestCountStub: SinonStub;
|
|
11
|
-
let requestDurationStub: SinonStub;
|
|
12
|
-
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
requestCountStub = stub(httpRequestCount, 'inc').returns();
|
|
15
|
-
requestDurationStub = stub(httpRequestDuration, 'observe').returns();
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
it('should handle metrics for the requests', async () => {
|
|
19
|
-
const service = faker.lorem.word();
|
|
20
|
-
process.env.CHART = service;
|
|
21
|
-
|
|
22
|
-
const app = express();
|
|
23
|
-
app.use(requestMetrics);
|
|
24
|
-
app.get('/test', function (req, res) {
|
|
25
|
-
res.sendStatus(200);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
await request(app).get('/test').expect(200);
|
|
29
|
-
|
|
30
|
-
const labels = { service, path: '/test', method: 'GET', status: '2XX' };
|
|
31
|
-
expect(requestCountStub).to.have.been.calledOnceWithExactly(labels);
|
|
32
|
-
expect(requestDurationStub).to.have.been.calledOnceWithExactly(
|
|
33
|
-
labels,
|
|
34
|
-
match.number
|
|
35
|
-
);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should not keep query parameters in path', async () => {
|
|
39
|
-
const service = faker.lorem.word();
|
|
40
|
-
process.env.CHART = service;
|
|
41
|
-
|
|
42
|
-
const app = express();
|
|
43
|
-
app.use(requestMetrics);
|
|
44
|
-
app.get('/test', function (req, res) {
|
|
45
|
-
res.sendStatus(200);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
await request(app).get('/test?param=value').expect(200);
|
|
49
|
-
|
|
50
|
-
const labels = { service, path: '/test', method: 'GET', status: '2XX' };
|
|
51
|
-
expect(requestCountStub).to.have.been.calledOnceWithExactly(labels);
|
|
52
|
-
expect(requestDurationStub).to.have.been.calledOnceWithExactly(
|
|
53
|
-
labels,
|
|
54
|
-
match.number
|
|
55
|
-
);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('should not keep anchor in path', async () => {
|
|
59
|
-
const service = faker.lorem.word();
|
|
60
|
-
process.env.CHART = service;
|
|
61
|
-
|
|
62
|
-
const app = express();
|
|
63
|
-
app.use(requestMetrics);
|
|
64
|
-
app.get('/test', function (req, res) {
|
|
65
|
-
res.sendStatus(200);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
await request(app).get('/test#place').expect(200);
|
|
69
|
-
|
|
70
|
-
const labels = { service, path: '/test', method: 'GET', status: '2XX' };
|
|
71
|
-
expect(requestCountStub).to.have.been.calledOnceWithExactly(labels);
|
|
72
|
-
expect(requestDurationStub).to.have.been.calledOnceWithExactly(
|
|
73
|
-
labels,
|
|
74
|
-
match.number
|
|
75
|
-
);
|
|
76
|
-
});
|
|
77
|
-
});
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Request, Response } from 'express';
|
|
2
|
-
import responseTime from 'response-time';
|
|
3
|
-
import { httpRequestCount, httpRequestDuration } from 'metrics';
|
|
4
|
-
|
|
5
|
-
/** Middleware that gets metrics on each request */
|
|
6
|
-
export const requestMetrics = responseTime(
|
|
7
|
-
(request: Request, response: Response, time: number) => {
|
|
8
|
-
const labels = {
|
|
9
|
-
path: (request.route?.path ?? request.path) as string,
|
|
10
|
-
method: request.method,
|
|
11
|
-
status: response.statusCode
|
|
12
|
-
? `${response.statusCode.toString().substring(0, 1)}XX`
|
|
13
|
-
: '',
|
|
14
|
-
service: process.env.CHART
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
httpRequestCount.inc(labels);
|
|
18
|
-
httpRequestDuration.observe(labels, time / 1000);
|
|
19
|
-
}
|
|
20
|
-
);
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import { Router } from 'express';
|
|
3
|
-
import { glob } from 'glob';
|
|
4
|
-
import YAML from 'yamljs';
|
|
5
|
-
import swaggerUi from 'swagger-ui-express';
|
|
6
|
-
import {
|
|
7
|
-
EndpointDocumentation,
|
|
8
|
-
IndexDocumentation,
|
|
9
|
-
ResponsesConfig,
|
|
10
|
-
EndpointConfig,
|
|
11
|
-
SchemasConfig,
|
|
12
|
-
SwaggerConfig
|
|
13
|
-
} from './swaggerDocs.types';
|
|
14
|
-
|
|
15
|
-
/** Get the paths of all the endpoint documentation files */
|
|
16
|
-
function getEndpointDocPaths(): Array<string> {
|
|
17
|
-
return [
|
|
18
|
-
...glob.sync(`${process.cwd()}/src/**/*.docs.yaml`),
|
|
19
|
-
...glob.sync(`${process.cwd()}/dist/**/*.docs.yaml`)
|
|
20
|
-
];
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/** Get the paths of all the schema files */
|
|
24
|
-
function getSchemaPaths(): Array<string> {
|
|
25
|
-
return [
|
|
26
|
-
...glob.sync(`${process.cwd()}/src/docs/schemas/*.yaml`),
|
|
27
|
-
...glob.sync(`${process.cwd()}/dist/docs/schemas/*.yaml`)
|
|
28
|
-
];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** Get the paths of all the response files */
|
|
32
|
-
function getResponsePaths(): Array<string> {
|
|
33
|
-
return [
|
|
34
|
-
...glob.sync(`${process.cwd()}/src/docs/responses/*.yaml`),
|
|
35
|
-
...glob.sync(`${process.cwd()}/dist/docs/responses/*.yaml`)
|
|
36
|
-
];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Load all data files and merge them in a single object
|
|
41
|
-
* @param files
|
|
42
|
-
* @return {Object}
|
|
43
|
-
*/
|
|
44
|
-
function loadAndMergeData(files: Array<string>): EndpointDocumentation {
|
|
45
|
-
return files
|
|
46
|
-
.map((file) => YAML.load(file) as EndpointDocumentation)
|
|
47
|
-
.reduce((result, endpoint) => {
|
|
48
|
-
for (const path of Object.keys(endpoint)) {
|
|
49
|
-
if (!(path in result)) result[path] = {};
|
|
50
|
-
result[path] = { ...result[path], ...endpoint[path] };
|
|
51
|
-
}
|
|
52
|
-
return result;
|
|
53
|
-
}, {});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Load documentation files of all the endpoints */
|
|
57
|
-
function loadEndpoints(): EndpointConfig {
|
|
58
|
-
const paths = getEndpointDocPaths();
|
|
59
|
-
const endpoints = loadAndMergeData(paths);
|
|
60
|
-
return {
|
|
61
|
-
paths: endpoints
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/** Load documentation files of all the schemas */
|
|
66
|
-
function loadSchemas(): SchemasConfig {
|
|
67
|
-
const paths = getSchemaPaths();
|
|
68
|
-
const schemas = loadAndMergeData(paths);
|
|
69
|
-
return { schemas };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/** Load documentation files of all the responses */
|
|
73
|
-
function loadResponses(): ResponsesConfig {
|
|
74
|
-
const paths = getResponsePaths();
|
|
75
|
-
const responses = loadAndMergeData(paths);
|
|
76
|
-
return { responses };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** Load the whole Swagger config */
|
|
80
|
-
function loadConfig(): SwaggerConfig {
|
|
81
|
-
const indexPath = `${process.cwd()}/src/docs/index.yaml`;
|
|
82
|
-
const config = (
|
|
83
|
-
fs.existsSync(indexPath) ? YAML.load(indexPath) : {}
|
|
84
|
-
) as IndexDocumentation;
|
|
85
|
-
const schemaConfig = loadSchemas();
|
|
86
|
-
const responseConfig = loadResponses();
|
|
87
|
-
const endpointConfig = loadEndpoints();
|
|
88
|
-
return {
|
|
89
|
-
...config,
|
|
90
|
-
...endpointConfig,
|
|
91
|
-
components: {
|
|
92
|
-
...config.components,
|
|
93
|
-
...schemaConfig,
|
|
94
|
-
...responseConfig
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Get a middleware that serves the documentation
|
|
101
|
-
* @return {Router}
|
|
102
|
-
*/
|
|
103
|
-
export function swaggerDocs(): Router {
|
|
104
|
-
// Stringify the result and replace any environment variable, then turn it again to an object
|
|
105
|
-
const stringifiedDocumentation = JSON.stringify(loadConfig());
|
|
106
|
-
const placeholderRegex = /##(.+?)##/g;
|
|
107
|
-
const overwrittenDocumentation = stringifiedDocumentation.replace(
|
|
108
|
-
placeholderRegex,
|
|
109
|
-
(match: string, p1: string): string => process.env[p1] ?? ''
|
|
110
|
-
);
|
|
111
|
-
const config = JSON.parse(overwrittenDocumentation) as EndpointDocumentation;
|
|
112
|
-
|
|
113
|
-
return Router().use('/docs', swaggerUi.serve, swaggerUi.setup(config));
|
|
114
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
/** Documentation content */
|
|
2
|
-
export interface EndpointDocumentation {
|
|
3
|
-
[path: string]: { [key: string]: unknown };
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
/** Documentation content */
|
|
7
|
-
interface ComponentDocumentation {
|
|
8
|
-
[name: string]: { [key: string]: unknown };
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/** root documentation config */
|
|
12
|
-
export interface IndexDocumentation extends EndpointDocumentation {
|
|
13
|
-
/** Global components to be documented */
|
|
14
|
-
components: ComponentDocumentation;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** Documentation config for endpoints */
|
|
18
|
-
export interface EndpointConfig {
|
|
19
|
-
/** Documentation content */
|
|
20
|
-
paths: EndpointDocumentation;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/** Documentation config for responses */
|
|
24
|
-
export interface ResponsesConfig {
|
|
25
|
-
/** Documentation content */
|
|
26
|
-
responses: ComponentDocumentation;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** Documentation config for schemas */
|
|
30
|
-
export interface SchemasConfig {
|
|
31
|
-
/** Documentation content */
|
|
32
|
-
schemas: ComponentDocumentation;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export type SwaggerConfig = IndexDocumentation &
|
|
36
|
-
EndpointConfig & {
|
|
37
|
-
/** Shared components documentation */
|
|
38
|
-
components: IndexDocumentation['components'] &
|
|
39
|
-
ResponsesConfig &
|
|
40
|
-
SchemasConfig;
|
|
41
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './userResolver';
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from 'express';
|
|
2
|
-
import { EngineError } from 'entities/EngineError';
|
|
3
|
-
import { reportDebug } from 'utils';
|
|
4
|
-
import { tlsRequest } from 'utils/tlsRequest';
|
|
5
|
-
|
|
6
|
-
const namespace = 'engine:middleware:userResolver';
|
|
7
|
-
|
|
8
|
-
/** Fetch the user previously identified by a JWT and adds his data to the request.user object */
|
|
9
|
-
export async function userResolver(
|
|
10
|
-
request: Request,
|
|
11
|
-
response: Response,
|
|
12
|
-
next: NextFunction
|
|
13
|
-
): Promise<void> {
|
|
14
|
-
const id = request.user?.id;
|
|
15
|
-
if (!id)
|
|
16
|
-
throw new EngineError({
|
|
17
|
-
message: 'Could not resolve user as the request is missing his ID'
|
|
18
|
-
});
|
|
19
|
-
const user = await getUserById(id);
|
|
20
|
-
if (!user)
|
|
21
|
-
throw new EngineError({
|
|
22
|
-
message: 'Could not resolve user as it could not be fetched',
|
|
23
|
-
data: { id }
|
|
24
|
-
});
|
|
25
|
-
reportDebug({
|
|
26
|
-
namespace,
|
|
27
|
-
message: 'Resolved user based on his token',
|
|
28
|
-
data: { user, request: request.user }
|
|
29
|
-
});
|
|
30
|
-
request.user = {
|
|
31
|
-
...request?.user,
|
|
32
|
-
...user
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
next();
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Call the GET /user/{id} endpoint using TLS
|
|
40
|
-
*/
|
|
41
|
-
export async function getUserById(userId: number): Promise<unknown> {
|
|
42
|
-
const userServiceUrl = process.env.USER_SERVICE_URL;
|
|
43
|
-
if (!userServiceUrl) {
|
|
44
|
-
throw new Error('USER_SERVICE_URL is not defined in environment variables');
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const response = await tlsRequest<unknown>({
|
|
48
|
-
method: 'GET',
|
|
49
|
-
url: `${userServiceUrl}/${userId}`
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
return response.data;
|
|
53
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './validate';
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { expect } from 'chai';
|
|
2
|
-
import express, { Response, Request, NextFunction } from 'express';
|
|
3
|
-
import request from 'supertest';
|
|
4
|
-
import { validate } from './validate';
|
|
5
|
-
import { ValidationError } from 'entities/ValidationError';
|
|
6
|
-
|
|
7
|
-
describe('Middleware - validate', () => {
|
|
8
|
-
it('should validate according to the schema', async () => {
|
|
9
|
-
const app = express();
|
|
10
|
-
const middleware = validate({
|
|
11
|
-
size: {
|
|
12
|
-
in: 'query',
|
|
13
|
-
isInt: true
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
app.get('/example', ...middleware, (req: any, res: any) =>
|
|
18
|
-
res.sendStatus(200)
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
app.use(
|
|
22
|
-
(
|
|
23
|
-
error: ValidationError,
|
|
24
|
-
req: Request,
|
|
25
|
-
res: Response,
|
|
26
|
-
next: NextFunction
|
|
27
|
-
) => {
|
|
28
|
-
expect(error.errorCode).to.equal('invalid-request');
|
|
29
|
-
expect((error.data as Record<string, string>).size).to.deep.equal(
|
|
30
|
-
'Invalid value'
|
|
31
|
-
);
|
|
32
|
-
res.sendStatus(error.statusCode);
|
|
33
|
-
}
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
await request(app).get('/example').query({ size: 4000 }).expect(200);
|
|
37
|
-
|
|
38
|
-
// await request(app)
|
|
39
|
-
// .get('/example')
|
|
40
|
-
// .query({ size: 'not number' })
|
|
41
|
-
// .expect(400);
|
|
42
|
-
});
|
|
43
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from 'express';
|
|
2
|
-
import {
|
|
3
|
-
checkSchema,
|
|
4
|
-
validationResult,
|
|
5
|
-
Schema,
|
|
6
|
-
ValidationChain
|
|
7
|
-
} from 'express-validator';
|
|
8
|
-
import { ValidationError } from 'entities/ValidationError';
|
|
9
|
-
|
|
10
|
-
/** Validate the express-validator results */
|
|
11
|
-
export const validate = (
|
|
12
|
-
config: Schema
|
|
13
|
-
): Array<
|
|
14
|
-
ValidationChain | ((req: Request, res: Response, next: NextFunction) => void)
|
|
15
|
-
> => [
|
|
16
|
-
...checkSchema(config),
|
|
17
|
-
(req: Request, res: Response, next: NextFunction): void => {
|
|
18
|
-
const result = validationResult(req);
|
|
19
|
-
if (result.isEmpty()) {
|
|
20
|
-
next();
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
next(new ValidationError(result));
|
|
24
|
-
}
|
|
25
|
-
];
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './version';
|