@nestjs/common 11.1.9 → 11.1.10
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/interfaces/index.d.ts +1 -0
- package/interfaces/index.js +1 -0
- package/interfaces/nest-application-context.interface.d.ts +5 -1
- package/interfaces/shutdown-hooks-options.interface.d.ts +21 -0
- package/interfaces/shutdown-hooks-options.interface.js +2 -0
- package/package.json +4 -3
- package/pipes/file/file-type.validator.d.ts +33 -0
- package/pipes/file/file-type.validator.js +39 -6
- package/pipes/file/file-validator-context.interface.d.ts +5 -0
- package/pipes/file/file-validator-context.interface.js +2 -0
- package/pipes/file/max-file-size.validator.d.ts +27 -0
- package/pipes/file/max-file-size.validator.js +10 -5
- package/pipes/validation.pipe.js +2 -0
- package/services/utils/is-log-level-enabled.util.js +6 -3
package/interfaces/index.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export * from './nest-application-options.interface';
|
|
|
24
24
|
export * from './nest-application.interface';
|
|
25
25
|
export * from './nest-microservice.interface';
|
|
26
26
|
export * from './scope-options.interface';
|
|
27
|
+
export * from './shutdown-hooks-options.interface';
|
|
27
28
|
export * from './type.interface';
|
|
28
29
|
export * from './version-options.interface';
|
|
29
30
|
export * from './websockets/web-socket-adapter.interface';
|
package/interfaces/index.js
CHANGED
|
@@ -27,6 +27,7 @@ tslib_1.__exportStar(require("./nest-application-options.interface"), exports);
|
|
|
27
27
|
tslib_1.__exportStar(require("./nest-application.interface"), exports);
|
|
28
28
|
tslib_1.__exportStar(require("./nest-microservice.interface"), exports);
|
|
29
29
|
tslib_1.__exportStar(require("./scope-options.interface"), exports);
|
|
30
|
+
tslib_1.__exportStar(require("./shutdown-hooks-options.interface"), exports);
|
|
30
31
|
tslib_1.__exportStar(require("./type.interface"), exports);
|
|
31
32
|
tslib_1.__exportStar(require("./version-options.interface"), exports);
|
|
32
33
|
tslib_1.__exportStar(require("./websockets/web-socket-adapter.interface"), exports);
|
|
@@ -2,6 +2,7 @@ import { ShutdownSignal } from '../enums/shutdown-signal.enum';
|
|
|
2
2
|
import { LoggerService, LogLevel } from '../services/logger.service';
|
|
3
3
|
import { DynamicModule } from './modules';
|
|
4
4
|
import { NestApplicationContextOptions } from './nest-application-context-options.interface';
|
|
5
|
+
import { ShutdownHooksOptions } from './shutdown-hooks-options.interface';
|
|
5
6
|
import { Type } from './type.interface';
|
|
6
7
|
export type SelectOptions = Pick<NestApplicationContextOptions, 'abortOnError'>;
|
|
7
8
|
export interface GetOrResolveOptions {
|
|
@@ -121,9 +122,12 @@ export interface INestApplicationContext {
|
|
|
121
122
|
* `onApplicationShutdown` function of a provider if the
|
|
122
123
|
* process receives a shutdown signal.
|
|
123
124
|
*
|
|
125
|
+
* @param {ShutdownSignal[] | string[]} [signals] The system signals to listen to
|
|
126
|
+
* @param {ShutdownHooksOptions} [options] Options for configuring shutdown hooks behavior
|
|
127
|
+
*
|
|
124
128
|
* @returns {this} The Nest application context instance
|
|
125
129
|
*/
|
|
126
|
-
enableShutdownHooks(signals?: ShutdownSignal[] | string[]): this;
|
|
130
|
+
enableShutdownHooks(signals?: ShutdownSignal[] | string[], options?: ShutdownHooksOptions): this;
|
|
127
131
|
/**
|
|
128
132
|
* Initializes the Nest application.
|
|
129
133
|
* Calls the Nest lifecycle events.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for configuring shutdown hooks behavior.
|
|
3
|
+
*
|
|
4
|
+
* @publicApi
|
|
5
|
+
*/
|
|
6
|
+
export interface ShutdownHooksOptions {
|
|
7
|
+
/**
|
|
8
|
+
* If true, uses `process.exit()` instead of `process.kill(process.pid, signal)`
|
|
9
|
+
* after shutdown hooks complete. This ensures the 'exit' event is properly
|
|
10
|
+
* triggered, which is required for async loggers (like Pino with transports)
|
|
11
|
+
* to flush their buffers before the process terminates.
|
|
12
|
+
*
|
|
13
|
+
* Note: Using `process.exit()` will:
|
|
14
|
+
* - Change the exit code (e.g., SIGTERM: 143 → 0)
|
|
15
|
+
* - May not trigger other signal handlers from third-party libraries
|
|
16
|
+
* - May affect orchestrator (Kubernetes, Docker) behavior
|
|
17
|
+
*
|
|
18
|
+
* @default false
|
|
19
|
+
*/
|
|
20
|
+
useProcessExit?: boolean;
|
|
21
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nestjs/common",
|
|
3
|
-
"version": "11.1.
|
|
3
|
+
"version": "11.1.10",
|
|
4
4
|
"description": "Nest - modern, fast, powerful node.js web framework (@common)",
|
|
5
5
|
"author": "Kamil Mysliwiec",
|
|
6
6
|
"homepage": "https://nestjs.com",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"file-type": "21.1.
|
|
21
|
+
"file-type": "21.1.1",
|
|
22
22
|
"iterare": "1.2.1",
|
|
23
23
|
"load-esm": "1.0.3",
|
|
24
24
|
"tslib": "2.8.1",
|
|
@@ -37,5 +37,6 @@
|
|
|
37
37
|
"class-transformer": {
|
|
38
38
|
"optional": true
|
|
39
39
|
}
|
|
40
|
-
}
|
|
40
|
+
},
|
|
41
|
+
"gitHead": "8ea5aaef561c87065bf0b358771de8c8b62e7835"
|
|
41
42
|
}
|
|
@@ -1,7 +1,39 @@
|
|
|
1
|
+
import { FileValidatorContext } from './file-validator-context.interface';
|
|
1
2
|
import { FileValidator } from './file-validator.interface';
|
|
2
3
|
import { IFile } from './interfaces';
|
|
4
|
+
type FileTypeValidatorContext = FileValidatorContext<Omit<FileTypeValidatorOptions, 'errorMessage'>>;
|
|
3
5
|
export type FileTypeValidatorOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* Expected file type(s) for validation. Can be a string (MIME type)
|
|
8
|
+
* or a regular expression to match multiple types.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // Match a single MIME type
|
|
12
|
+
* fileType: 'image/png'
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // Match multiple types using RegExp
|
|
16
|
+
* fileType: /^image\/(png|jpeg)$/
|
|
17
|
+
*/
|
|
4
18
|
fileType: string | RegExp;
|
|
19
|
+
/**
|
|
20
|
+
* Custom error message displayed when file type validation fails
|
|
21
|
+
* Can be provided as a static string, or as a factory function
|
|
22
|
+
* that receives the validation context (file and validator configuration)
|
|
23
|
+
* and returns a dynamic error message.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // Static message
|
|
27
|
+
* new FileTypeValidator({ fileType: 'image/png', errorMessage: 'Only PNG allowed' })
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* // Dynamic message based on file object and validator configuration
|
|
31
|
+
* new FileTypeValidator({
|
|
32
|
+
* fileType: 'image/png',
|
|
33
|
+
* errorMessage: ctx => `Received file type '${ctx.file?.mimetype}', but expected '${ctx.config.fileType}'`
|
|
34
|
+
* })
|
|
35
|
+
*/
|
|
36
|
+
errorMessage?: string | ((ctx: FileTypeValidatorContext) => string);
|
|
5
37
|
/**
|
|
6
38
|
* If `true`, the validator will skip the magic numbers validation.
|
|
7
39
|
* This can be useful when you can't identify some files as there are no common magic numbers available for some file types.
|
|
@@ -27,3 +59,4 @@ export declare class FileTypeValidator extends FileValidator<FileTypeValidatorOp
|
|
|
27
59
|
buildErrorMessage(file?: IFile): string;
|
|
28
60
|
isValid(file?: IFile): Promise<boolean>;
|
|
29
61
|
}
|
|
62
|
+
export {};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FileTypeValidator = void 0;
|
|
4
|
+
const logger_service_1 = require("../../services/logger.service");
|
|
4
5
|
const file_validator_interface_1 = require("./file-validator.interface");
|
|
5
6
|
const load_esm_1 = require("load-esm");
|
|
7
|
+
const logger = new logger_service_1.Logger('FileTypeValidator');
|
|
6
8
|
/**
|
|
7
9
|
* Defines the built-in FileTypeValidator. It validates incoming files by examining
|
|
8
10
|
* their magic numbers using the file-type package, providing more reliable file type validation
|
|
@@ -14,9 +16,14 @@ const load_esm_1 = require("load-esm");
|
|
|
14
16
|
*/
|
|
15
17
|
class FileTypeValidator extends file_validator_interface_1.FileValidator {
|
|
16
18
|
buildErrorMessage(file) {
|
|
17
|
-
const
|
|
19
|
+
const { errorMessage, ...config } = this.validationOptions;
|
|
20
|
+
if (errorMessage) {
|
|
21
|
+
return typeof errorMessage === 'function'
|
|
22
|
+
? errorMessage({ file, config })
|
|
23
|
+
: errorMessage;
|
|
24
|
+
}
|
|
18
25
|
if (file?.mimetype) {
|
|
19
|
-
const baseMessage = `Validation failed (current file type is ${file.mimetype}, expected type is ${
|
|
26
|
+
const baseMessage = `Validation failed (current file type is ${file.mimetype}, expected type is ${this.validationOptions.fileType})`;
|
|
20
27
|
/**
|
|
21
28
|
* If fallbackToMimetype is enabled, this means the validator failed to detect the file type
|
|
22
29
|
* via magic number inspection (e.g. due to an unknown or too short buffer),
|
|
@@ -29,7 +36,7 @@ class FileTypeValidator extends file_validator_interface_1.FileValidator {
|
|
|
29
36
|
}
|
|
30
37
|
return baseMessage;
|
|
31
38
|
}
|
|
32
|
-
return `Validation failed (expected type is ${
|
|
39
|
+
return `Validation failed (expected type is ${this.validationOptions.fileType})`;
|
|
33
40
|
}
|
|
34
41
|
async isValid(file) {
|
|
35
42
|
if (!this.validationOptions) {
|
|
@@ -40,10 +47,23 @@ class FileTypeValidator extends file_validator_interface_1.FileValidator {
|
|
|
40
47
|
if (this.validationOptions.skipMagicNumbersValidation) {
|
|
41
48
|
return (isFileValid && !!file.mimetype.match(this.validationOptions.fileType));
|
|
42
49
|
}
|
|
43
|
-
if (!isFileValid
|
|
50
|
+
if (!isFileValid)
|
|
51
|
+
return false;
|
|
52
|
+
if (!file.buffer) {
|
|
53
|
+
if (this.validationOptions.fallbackToMimetype) {
|
|
54
|
+
return !!file.mimetype.match(this.validationOptions.fileType);
|
|
55
|
+
}
|
|
44
56
|
return false;
|
|
57
|
+
}
|
|
45
58
|
try {
|
|
46
|
-
|
|
59
|
+
let fileTypePath;
|
|
60
|
+
try {
|
|
61
|
+
fileTypePath = require.resolve('file-type');
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
fileTypePath = 'file-type';
|
|
65
|
+
}
|
|
66
|
+
const { fileTypeFromBuffer } = await (0, load_esm_1.loadEsm)(fileTypePath);
|
|
47
67
|
const fileType = await fileTypeFromBuffer(file.buffer);
|
|
48
68
|
if (fileType) {
|
|
49
69
|
// Match detected mime type against allowed type
|
|
@@ -59,7 +79,20 @@ class FileTypeValidator extends file_validator_interface_1.FileValidator {
|
|
|
59
79
|
}
|
|
60
80
|
return false;
|
|
61
81
|
}
|
|
62
|
-
catch {
|
|
82
|
+
catch (error) {
|
|
83
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
84
|
+
// Check for common ESM loading issues
|
|
85
|
+
if (errorMessage.includes('ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING') ||
|
|
86
|
+
errorMessage.includes('Cannot find module') ||
|
|
87
|
+
errorMessage.includes('ERR_MODULE_NOT_FOUND')) {
|
|
88
|
+
logger.warn(`Failed to load the "file-type" package for magic number validation. ` +
|
|
89
|
+
`If you are using Jest, run it with NODE_OPTIONS="--experimental-vm-modules". ` +
|
|
90
|
+
`Error: ${errorMessage}`);
|
|
91
|
+
}
|
|
92
|
+
// Fallback to mimetype if enabled
|
|
93
|
+
if (this.validationOptions.fallbackToMimetype) {
|
|
94
|
+
return !!file.mimetype.match(this.validationOptions.fileType);
|
|
95
|
+
}
|
|
63
96
|
return false;
|
|
64
97
|
}
|
|
65
98
|
}
|
|
@@ -1,8 +1,34 @@
|
|
|
1
|
+
import { FileValidatorContext } from './file-validator-context.interface';
|
|
1
2
|
import { FileValidator } from './file-validator.interface';
|
|
2
3
|
import { IFile } from './interfaces';
|
|
4
|
+
type MaxFileSizeValidatorContext = FileValidatorContext<Omit<MaxFileSizeValidatorOptions, 'errorMessage' | 'message'>>;
|
|
3
5
|
export type MaxFileSizeValidatorOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* Maximum allowed file size in bytes.
|
|
8
|
+
*/
|
|
4
9
|
maxSize: number;
|
|
10
|
+
/**
|
|
11
|
+
* @deprecated Use `errorMessage` instead.
|
|
12
|
+
*/
|
|
5
13
|
message?: string | ((maxSize: number) => string);
|
|
14
|
+
/**
|
|
15
|
+
* Custom error message returned when file size validation fails.
|
|
16
|
+
* Can be provided as a static string, or as a factory function
|
|
17
|
+
* that receives the validation context (file and validator configuration)
|
|
18
|
+
* and returns a dynamic error message.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* // Static message
|
|
22
|
+
* new MaxFileSizeValidator({ maxSize: 1000, errorMessage: 'File size exceeds the limit' })
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // Dynamic message based on file object and validator configuration
|
|
26
|
+
* new MaxFileSizeValidator({
|
|
27
|
+
* maxSize: 1000,
|
|
28
|
+
* errorMessage: ctx => `Received file size is ${ctx.file?.size}, but it must be smaller than ${ctx.config.maxSize}.`
|
|
29
|
+
* })
|
|
30
|
+
*/
|
|
31
|
+
errorMessage?: string | ((ctx: MaxFileSizeValidatorContext) => string);
|
|
6
32
|
};
|
|
7
33
|
/**
|
|
8
34
|
* Defines the built-in MaxSize File Validator
|
|
@@ -15,3 +41,4 @@ export declare class MaxFileSizeValidator extends FileValidator<MaxFileSizeValid
|
|
|
15
41
|
buildErrorMessage(file?: IFile): string;
|
|
16
42
|
isValid(file?: IFile): boolean;
|
|
17
43
|
}
|
|
44
|
+
export {};
|
|
@@ -11,11 +11,16 @@ const file_validator_interface_1 = require("./file-validator.interface");
|
|
|
11
11
|
*/
|
|
12
12
|
class MaxFileSizeValidator extends file_validator_interface_1.FileValidator {
|
|
13
13
|
buildErrorMessage(file) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
const { errorMessage, message, ...config } = this.validationOptions;
|
|
15
|
+
if (errorMessage) {
|
|
16
|
+
return typeof errorMessage === 'function'
|
|
17
|
+
? errorMessage({ file, config })
|
|
18
|
+
: errorMessage;
|
|
19
|
+
}
|
|
20
|
+
if (message) {
|
|
21
|
+
return typeof message === 'function'
|
|
22
|
+
? message(this.validationOptions.maxSize)
|
|
23
|
+
: message;
|
|
19
24
|
}
|
|
20
25
|
if (file?.size) {
|
|
21
26
|
return `Validation failed (current file size is ${file.size}, expected size is less than ${this.validationOptions.maxSize})`;
|
package/pipes/validation.pipe.js
CHANGED
|
@@ -21,9 +21,12 @@ function isLogLevelEnabled(targetLevel, logLevels) {
|
|
|
21
21
|
if (logLevels.includes(targetLevel)) {
|
|
22
22
|
return true;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
let highestLogLevelValue = -Infinity;
|
|
25
|
+
for (const level of logLevels) {
|
|
26
|
+
const v = LOG_LEVEL_VALUES[level];
|
|
27
|
+
if (v > highestLogLevelValue)
|
|
28
|
+
highestLogLevelValue = v;
|
|
29
|
+
}
|
|
27
30
|
const targetLevelValue = LOG_LEVEL_VALUES[targetLevel];
|
|
28
31
|
return targetLevelValue >= highestLogLevelValue;
|
|
29
32
|
}
|