@nestjs/common
Advanced tools
| /** | ||
| * Options for configuring shutdown hooks behavior. | ||
| * | ||
| * @publicApi | ||
| */ | ||
| export interface ShutdownHooksOptions { | ||
| /** | ||
| * If true, uses `process.exit()` instead of `process.kill(process.pid, signal)` | ||
| * after shutdown hooks complete. This ensures the 'exit' event is properly | ||
| * triggered, which is required for async loggers (like Pino with transports) | ||
| * to flush their buffers before the process terminates. | ||
| * | ||
| * Note: Using `process.exit()` will: | ||
| * - Change the exit code (e.g., SIGTERM: 143 → 0) | ||
| * - May not trigger other signal handlers from third-party libraries | ||
| * - May affect orchestrator (Kubernetes, Docker) behavior | ||
| * | ||
| * @default false | ||
| */ | ||
| useProcessExit?: boolean; | ||
| } |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); |
| import { IFile } from './interfaces'; | ||
| export type FileValidatorContext<TConfig> = { | ||
| file?: IFile; | ||
| config: TConfig; | ||
| }; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); |
@@ -27,4 +27,5 @@ export * from './abstract.interface'; | ||
| export * from './scope-options.interface'; | ||
| export * from './shutdown-hooks-options.interface'; | ||
| export * from './type.interface'; | ||
| export * from './version-options.interface'; | ||
| export * from './websockets/web-socket-adapter.interface'; |
@@ -30,4 +30,5 @@ "use strict"; | ||
| tslib_1.__exportStar(require("./scope-options.interface"), exports); | ||
| tslib_1.__exportStar(require("./shutdown-hooks-options.interface"), exports); | ||
| tslib_1.__exportStar(require("./type.interface"), exports); | ||
| tslib_1.__exportStar(require("./version-options.interface"), exports); | ||
| tslib_1.__exportStar(require("./websockets/web-socket-adapter.interface"), exports); |
@@ -5,2 +5,3 @@ import { ShutdownSignal } from '../enums/shutdown-signal.enum'; | ||
| import { NestApplicationContextOptions } from './nest-application-context-options.interface'; | ||
| import { ShutdownHooksOptions } from './shutdown-hooks-options.interface'; | ||
| import { Type } from './type.interface'; | ||
@@ -125,5 +126,8 @@ export type SelectOptions = Pick<NestApplicationContextOptions, 'abortOnError'>; | ||
| * | ||
| * @param {ShutdownSignal[] | string[]} [signals] The system signals to listen to | ||
| * @param {ShutdownHooksOptions} [options] Options for configuring shutdown hooks behavior | ||
| * | ||
| * @returns {this} The Nest application context instance | ||
| */ | ||
| enableShutdownHooks(signals?: ShutdownSignal[] | string[]): this; | ||
| enableShutdownHooks(signals?: ShutdownSignal[] | string[], options?: ShutdownHooksOptions): this; | ||
| /** | ||
@@ -130,0 +134,0 @@ * Initializes the Nest application. |
+4
-3
| { | ||
| "name": "@nestjs/common", | ||
| "version": "11.1.9", | ||
| "version": "11.1.10", | ||
| "description": "Nest - modern, fast, powerful node.js web framework (@common)", | ||
@@ -21,3 +21,3 @@ "author": "Kamil Mysliwiec", | ||
| "dependencies": { | ||
| "file-type": "21.1.0", | ||
| "file-type": "21.1.1", | ||
| "iterare": "1.2.1", | ||
@@ -41,3 +41,4 @@ "load-esm": "1.0.3", | ||
| } | ||
| } | ||
| }, | ||
| "gitHead": "8ea5aaef561c87065bf0b358771de8c8b62e7835" | ||
| } |
@@ -0,6 +1,38 @@ | ||
| import { FileValidatorContext } from './file-validator-context.interface'; | ||
| import { FileValidator } from './file-validator.interface'; | ||
| import { IFile } from './interfaces'; | ||
| type FileTypeValidatorContext = FileValidatorContext<Omit<FileTypeValidatorOptions, 'errorMessage'>>; | ||
| export type FileTypeValidatorOptions = { | ||
| /** | ||
| * Expected file type(s) for validation. Can be a string (MIME type) | ||
| * or a regular expression to match multiple types. | ||
| * | ||
| * @example | ||
| * // Match a single MIME type | ||
| * fileType: 'image/png' | ||
| * | ||
| * @example | ||
| * // Match multiple types using RegExp | ||
| * fileType: /^image\/(png|jpeg)$/ | ||
| */ | ||
| fileType: string | RegExp; | ||
| /** | ||
| * Custom error message displayed when file type validation fails | ||
| * Can be provided as a static string, or as a factory function | ||
| * that receives the validation context (file and validator configuration) | ||
| * and returns a dynamic error message. | ||
| * | ||
| * @example | ||
| * // Static message | ||
| * new FileTypeValidator({ fileType: 'image/png', errorMessage: 'Only PNG allowed' }) | ||
| * | ||
| * @example | ||
| * // Dynamic message based on file object and validator configuration | ||
| * new FileTypeValidator({ | ||
| * fileType: 'image/png', | ||
| * errorMessage: ctx => `Received file type '${ctx.file?.mimetype}', but expected '${ctx.config.fileType}'` | ||
| * }) | ||
| */ | ||
| errorMessage?: string | ((ctx: FileTypeValidatorContext) => string); | ||
| /** | ||
| * If `true`, the validator will skip the magic numbers validation. | ||
@@ -30,1 +62,2 @@ * This can be useful when you can't identify some files as there are no common magic numbers available for some file types. | ||
| } | ||
| export {}; |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.FileTypeValidator = void 0; | ||
| const logger_service_1 = require("../../services/logger.service"); | ||
| const file_validator_interface_1 = require("./file-validator.interface"); | ||
| const load_esm_1 = require("load-esm"); | ||
| const logger = new logger_service_1.Logger('FileTypeValidator'); | ||
| /** | ||
@@ -17,5 +19,10 @@ * Defines the built-in FileTypeValidator. It validates incoming files by examining | ||
| buildErrorMessage(file) { | ||
| const expected = this.validationOptions.fileType; | ||
| const { errorMessage, ...config } = this.validationOptions; | ||
| if (errorMessage) { | ||
| return typeof errorMessage === 'function' | ||
| ? errorMessage({ file, config }) | ||
| : errorMessage; | ||
| } | ||
| if (file?.mimetype) { | ||
| const baseMessage = `Validation failed (current file type is ${file.mimetype}, expected type is ${expected})`; | ||
| const baseMessage = `Validation failed (current file type is ${file.mimetype}, expected type is ${this.validationOptions.fileType})`; | ||
| /** | ||
@@ -33,3 +40,3 @@ * If fallbackToMimetype is enabled, this means the validator failed to detect the file type | ||
| } | ||
| return `Validation failed (expected type is ${expected})`; | ||
| return `Validation failed (expected type is ${this.validationOptions.fileType})`; | ||
| } | ||
@@ -45,6 +52,19 @@ async isValid(file) { | ||
| } | ||
| if (!isFileValid || !file.buffer) | ||
| if (!isFileValid) | ||
| return false; | ||
| if (!file.buffer) { | ||
| if (this.validationOptions.fallbackToMimetype) { | ||
| return !!file.mimetype.match(this.validationOptions.fileType); | ||
| } | ||
| return false; | ||
| } | ||
| try { | ||
| const { fileTypeFromBuffer } = await (0, load_esm_1.loadEsm)('file-type'); | ||
| let fileTypePath; | ||
| try { | ||
| fileTypePath = require.resolve('file-type'); | ||
| } | ||
| catch { | ||
| fileTypePath = 'file-type'; | ||
| } | ||
| const { fileTypeFromBuffer } = await (0, load_esm_1.loadEsm)(fileTypePath); | ||
| const fileType = await fileTypeFromBuffer(file.buffer); | ||
@@ -65,3 +85,16 @@ if (fileType) { | ||
| } | ||
| catch { | ||
| catch (error) { | ||
| const errorMessage = error instanceof Error ? error.message : String(error); | ||
| // Check for common ESM loading issues | ||
| if (errorMessage.includes('ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING') || | ||
| errorMessage.includes('Cannot find module') || | ||
| errorMessage.includes('ERR_MODULE_NOT_FOUND')) { | ||
| logger.warn(`Failed to load the "file-type" package for magic number validation. ` + | ||
| `If you are using Jest, run it with NODE_OPTIONS="--experimental-vm-modules". ` + | ||
| `Error: ${errorMessage}`); | ||
| } | ||
| // Fallback to mimetype if enabled | ||
| if (this.validationOptions.fallbackToMimetype) { | ||
| return !!file.mimetype.match(this.validationOptions.fileType); | ||
| } | ||
| return false; | ||
@@ -68,0 +101,0 @@ } |
@@ -0,6 +1,32 @@ | ||
| import { FileValidatorContext } from './file-validator-context.interface'; | ||
| import { FileValidator } from './file-validator.interface'; | ||
| import { IFile } from './interfaces'; | ||
| type MaxFileSizeValidatorContext = FileValidatorContext<Omit<MaxFileSizeValidatorOptions, 'errorMessage' | 'message'>>; | ||
| export type MaxFileSizeValidatorOptions = { | ||
| /** | ||
| * Maximum allowed file size in bytes. | ||
| */ | ||
| maxSize: number; | ||
| /** | ||
| * @deprecated Use `errorMessage` instead. | ||
| */ | ||
| message?: string | ((maxSize: number) => string); | ||
| /** | ||
| * Custom error message returned when file size validation fails. | ||
| * Can be provided as a static string, or as a factory function | ||
| * that receives the validation context (file and validator configuration) | ||
| * and returns a dynamic error message. | ||
| * | ||
| * @example | ||
| * // Static message | ||
| * new MaxFileSizeValidator({ maxSize: 1000, errorMessage: 'File size exceeds the limit' }) | ||
| * | ||
| * @example | ||
| * // Dynamic message based on file object and validator configuration | ||
| * new MaxFileSizeValidator({ | ||
| * maxSize: 1000, | ||
| * errorMessage: ctx => `Received file size is ${ctx.file?.size}, but it must be smaller than ${ctx.config.maxSize}.` | ||
| * }) | ||
| */ | ||
| errorMessage?: string | ((ctx: MaxFileSizeValidatorContext) => string); | ||
| }; | ||
@@ -18,1 +44,2 @@ /** | ||
| } | ||
| export {}; |
@@ -14,8 +14,13 @@ "use strict"; | ||
| buildErrorMessage(file) { | ||
| if ('message' in this.validationOptions) { | ||
| if (typeof this.validationOptions.message === 'function') { | ||
| return this.validationOptions.message(this.validationOptions.maxSize); | ||
| } | ||
| return this.validationOptions.message; | ||
| const { errorMessage, message, ...config } = this.validationOptions; | ||
| if (errorMessage) { | ||
| return typeof errorMessage === 'function' | ||
| ? errorMessage({ file, config }) | ||
| : errorMessage; | ||
| } | ||
| if (message) { | ||
| return typeof message === 'function' | ||
| ? message(this.validationOptions.maxSize) | ||
| : message; | ||
| } | ||
| if (file?.size) { | ||
@@ -22,0 +27,0 @@ return `Validation failed (current file size is ${file.size}, expected size is less than ${this.validationOptions.maxSize})`; |
@@ -178,2 +178,4 @@ "use strict"; | ||
| delete value.__proto__; | ||
| delete value.constructor; | ||
| delete value.prototype; | ||
| for (const key in value) { | ||
@@ -180,0 +182,0 @@ this.stripProtoKeys(value[key]); |
@@ -24,7 +24,10 @@ "use strict"; | ||
| } | ||
| const highestLogLevelValue = logLevels | ||
| .map(level => LOG_LEVEL_VALUES[level]) | ||
| .sort((a, b) => b - a)?.[0]; | ||
| let highestLogLevelValue = -Infinity; | ||
| for (const level of logLevels) { | ||
| const v = LOG_LEVEL_VALUES[level]; | ||
| if (v > highestLogLevelValue) | ||
| highestLogLevelValue = v; | ||
| } | ||
| const targetLevelValue = LOG_LEVEL_VALUES[targetLevel]; | ||
| return targetLevelValue >= highestLogLevelValue; | ||
| } |
466363
1.26%405
1%10941
1.29%+ Added
+ Added
- Removed
- Removed
- Removed
Updated