@depup/nestjs__common 12.0.1-depup.1 → 12.0.3-depup.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/README.md +3 -9
- package/changes.json +3 -8
- package/decorators/modules/module.decorator.js +1 -1
- package/exceptions/bad-gateway.exception.js +1 -1
- package/exceptions/bad-request.exception.js +1 -1
- package/exceptions/conflict.exception.js +1 -1
- package/exceptions/forbidden.exception.js +1 -1
- package/exceptions/gateway-timeout.exception.js +1 -1
- package/exceptions/gone.exception.js +1 -1
- package/exceptions/http-version-not-supported.exception.js +1 -1
- package/exceptions/im-a-teapot.exception.js +1 -1
- package/exceptions/internal-server-error.exception.js +1 -1
- package/exceptions/method-not-allowed.exception.js +1 -1
- package/exceptions/misdirected.exception.js +1 -1
- package/exceptions/not-acceptable.exception.js +1 -1
- package/exceptions/not-found.exception.js +1 -1
- package/exceptions/not-implemented.exception.js +1 -1
- package/exceptions/payload-too-large.exception.js +1 -1
- package/exceptions/precondition-failed.exception.js +1 -1
- package/exceptions/request-timeout.exception.js +1 -1
- package/exceptions/service-unavailable.exception.js +1 -1
- package/exceptions/unauthorized.exception.js +1 -1
- package/exceptions/unprocessable-entity.exception.js +1 -1
- package/exceptions/unsupported-media-type.exception.js +1 -1
- package/interfaces/http/http-server.interface.d.ts +504 -0
- package/package.json +7 -12
- package/pipes/file/parse-file.pipe.js +2 -2
- package/pipes/parse-array.pipe.js +1 -1
- package/pipes/parse-enum.pipe.d.ts +9 -0
- package/pipes/parse-enum.pipe.js +22 -3
- package/pipes/parse-uuid.pipe.js +3 -2
- package/pipes/standard-schema-validation.pipe.d.ts +0 -3
- package/pipes/standard-schema-validation.pipe.js +7 -33
- package/pipes/validation.pipe.d.ts +1 -1
- package/pipes/validation.pipe.js +4 -34
- package/utils/index.d.ts +1 -0
- package/utils/index.js +1 -0
- package/utils/shared.utils.js +2 -6
- package/utils/strip-proto-keys.util.d.ts +5 -0
- package/utils/strip-proto-keys.util.js +36 -0
package/README.md
CHANGED
|
@@ -13,16 +13,10 @@ npm install @depup/nestjs__common
|
|
|
13
13
|
|
|
14
14
|
| Field | Value |
|
|
15
15
|
|-------|-------|
|
|
16
|
-
| Original | [@nestjs/common](https://www.npmjs.com/package/@nestjs/common) @ 12.0.
|
|
17
|
-
| Processed | 2026-09-
|
|
16
|
+
| Original | [@nestjs/common](https://www.npmjs.com/package/@nestjs/common) @ 12.0.3 |
|
|
17
|
+
| Processed | 2026-09-15 |
|
|
18
18
|
| Smoke test | passed |
|
|
19
|
-
| Deps updated |
|
|
20
|
-
|
|
21
|
-
## Dependency Changes
|
|
22
|
-
|
|
23
|
-
| Dependency | From | To |
|
|
24
|
-
|------------|------|-----|
|
|
25
|
-
| file-type | 22.0.2 | ^22.1.0 |
|
|
19
|
+
| Deps updated | 0 |
|
|
26
20
|
|
|
27
21
|
---
|
|
28
22
|
|
package/changes.json
CHANGED
|
@@ -18,7 +18,7 @@ export function Module(metadata) {
|
|
|
18
18
|
validateModuleKeys(propsKeys);
|
|
19
19
|
return (target) => {
|
|
20
20
|
for (const property in metadata) {
|
|
21
|
-
if (Object.
|
|
21
|
+
if (Object.hasOwn(metadata, property)) {
|
|
22
22
|
Reflect.defineMetadata(property, metadata[property], target);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -34,6 +34,6 @@ export class BadGatewayException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Bad Gateway') {
|
|
36
36
|
const { description = 'Bad Gateway', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.BAD_GATEWAY), HttpStatus.BAD_GATEWAY, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.BAD_GATEWAY, httpExceptionOptions?.errorCode), HttpStatus.BAD_GATEWAY, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class BadRequestException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Bad Request') {
|
|
36
36
|
const { description = 'Bad Request', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.BAD_REQUEST), HttpStatus.BAD_REQUEST, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.BAD_REQUEST, httpExceptionOptions?.errorCode), HttpStatus.BAD_REQUEST, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class ConflictException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Conflict') {
|
|
36
36
|
const { description = 'Conflict', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.CONFLICT), HttpStatus.CONFLICT, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.CONFLICT, httpExceptionOptions?.errorCode), HttpStatus.CONFLICT, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class ForbiddenException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Forbidden') {
|
|
36
36
|
const { description = 'Forbidden', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.FORBIDDEN), HttpStatus.FORBIDDEN, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.FORBIDDEN, httpExceptionOptions?.errorCode), HttpStatus.FORBIDDEN, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class GatewayTimeoutException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Gateway Timeout') {
|
|
36
36
|
const { description = 'Gateway Timeout', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.GATEWAY_TIMEOUT), HttpStatus.GATEWAY_TIMEOUT, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.GATEWAY_TIMEOUT, httpExceptionOptions?.errorCode), HttpStatus.GATEWAY_TIMEOUT, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class GoneException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Gone') {
|
|
36
36
|
const { description = 'Gone', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.GONE), HttpStatus.GONE, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.GONE, httpExceptionOptions?.errorCode), HttpStatus.GONE, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class HttpVersionNotSupportedException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'HTTP Version Not Supported') {
|
|
36
36
|
const { description = 'HTTP Version Not Supported', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.HTTP_VERSION_NOT_SUPPORTED), HttpStatus.HTTP_VERSION_NOT_SUPPORTED, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.HTTP_VERSION_NOT_SUPPORTED, httpExceptionOptions?.errorCode), HttpStatus.HTTP_VERSION_NOT_SUPPORTED, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -37,6 +37,6 @@ export class ImATeapotException extends HttpException {
|
|
|
37
37
|
*/
|
|
38
38
|
constructor(objectOrError, descriptionOrOptions = `I'm a teapot`) {
|
|
39
39
|
const { description = `I'm a teapot`, httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
40
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.I_AM_A_TEAPOT), HttpStatus.I_AM_A_TEAPOT, httpExceptionOptions);
|
|
40
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.I_AM_A_TEAPOT, httpExceptionOptions?.errorCode), HttpStatus.I_AM_A_TEAPOT, httpExceptionOptions);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -34,6 +34,6 @@ export class InternalServerErrorException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Internal Server Error') {
|
|
36
36
|
const { description = 'Internal Server Error', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.INTERNAL_SERVER_ERROR), HttpStatus.INTERNAL_SERVER_ERROR, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.INTERNAL_SERVER_ERROR, httpExceptionOptions?.errorCode), HttpStatus.INTERNAL_SERVER_ERROR, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class MethodNotAllowedException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Method Not Allowed') {
|
|
36
36
|
const { description = 'Method Not Allowed', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.METHOD_NOT_ALLOWED), HttpStatus.METHOD_NOT_ALLOWED, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.METHOD_NOT_ALLOWED, httpExceptionOptions?.errorCode), HttpStatus.METHOD_NOT_ALLOWED, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class MisdirectedException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Misdirected') {
|
|
36
36
|
const { description = 'Misdirected', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.MISDIRECTED), HttpStatus.MISDIRECTED, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.MISDIRECTED, httpExceptionOptions?.errorCode), HttpStatus.MISDIRECTED, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class NotAcceptableException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Not Acceptable') {
|
|
36
36
|
const { description = 'Not Acceptable', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.NOT_ACCEPTABLE), HttpStatus.NOT_ACCEPTABLE, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.NOT_ACCEPTABLE, httpExceptionOptions?.errorCode), HttpStatus.NOT_ACCEPTABLE, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class NotFoundException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Not Found') {
|
|
36
36
|
const { description = 'Not Found', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.NOT_FOUND), HttpStatus.NOT_FOUND, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.NOT_FOUND, httpExceptionOptions?.errorCode), HttpStatus.NOT_FOUND, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class NotImplementedException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Not Implemented') {
|
|
36
36
|
const { description = 'Not Implemented', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.NOT_IMPLEMENTED), HttpStatus.NOT_IMPLEMENTED, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.NOT_IMPLEMENTED, httpExceptionOptions?.errorCode), HttpStatus.NOT_IMPLEMENTED, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class PayloadTooLargeException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Payload Too Large') {
|
|
36
36
|
const { description = 'Payload Too Large', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.PAYLOAD_TOO_LARGE), HttpStatus.PAYLOAD_TOO_LARGE, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.PAYLOAD_TOO_LARGE, httpExceptionOptions?.errorCode), HttpStatus.PAYLOAD_TOO_LARGE, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class PreconditionFailedException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Precondition Failed') {
|
|
36
36
|
const { description = 'Precondition Failed', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.PRECONDITION_FAILED), HttpStatus.PRECONDITION_FAILED, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.PRECONDITION_FAILED, httpExceptionOptions?.errorCode), HttpStatus.PRECONDITION_FAILED, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class RequestTimeoutException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Request Timeout') {
|
|
36
36
|
const { description = 'Request Timeout', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.REQUEST_TIMEOUT), HttpStatus.REQUEST_TIMEOUT, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.REQUEST_TIMEOUT, httpExceptionOptions?.errorCode), HttpStatus.REQUEST_TIMEOUT, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class ServiceUnavailableException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Service Unavailable') {
|
|
36
36
|
const { description = 'Service Unavailable', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.SERVICE_UNAVAILABLE), HttpStatus.SERVICE_UNAVAILABLE, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.SERVICE_UNAVAILABLE, httpExceptionOptions?.errorCode), HttpStatus.SERVICE_UNAVAILABLE, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class UnauthorizedException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Unauthorized') {
|
|
36
36
|
const { description = 'Unauthorized', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.UNAUTHORIZED), HttpStatus.UNAUTHORIZED, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.UNAUTHORIZED, httpExceptionOptions?.errorCode), HttpStatus.UNAUTHORIZED, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class UnprocessableEntityException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Unprocessable Entity') {
|
|
36
36
|
const { description = 'Unprocessable Entity', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.UNPROCESSABLE_ENTITY), HttpStatus.UNPROCESSABLE_ENTITY, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.UNPROCESSABLE_ENTITY, httpExceptionOptions?.errorCode), HttpStatus.UNPROCESSABLE_ENTITY, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -34,6 +34,6 @@ export class UnsupportedMediaTypeException extends HttpException {
|
|
|
34
34
|
*/
|
|
35
35
|
constructor(objectOrError, descriptionOrOptions = 'Unsupported Media Type') {
|
|
36
36
|
const { description = 'Unsupported Media Type', httpExceptionOptions } = HttpException.extractDescriptionAndOptionsFrom(descriptionOrOptions);
|
|
37
|
-
super(HttpException.createBody(objectOrError, description, HttpStatus.UNSUPPORTED_MEDIA_TYPE), HttpStatus.UNSUPPORTED_MEDIA_TYPE, httpExceptionOptions);
|
|
37
|
+
super(HttpException.createBody(objectOrError, description, HttpStatus.UNSUPPORTED_MEDIA_TYPE, httpExceptionOptions?.errorCode), HttpStatus.UNSUPPORTED_MEDIA_TYPE, httpExceptionOptions);
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -1,74 +1,578 @@
|
|
|
1
1
|
import { RequestMethod } from '../../enums/index.js';
|
|
2
2
|
import { NestApplicationOptions } from '../../interfaces/nest-application-options.interface.js';
|
|
3
3
|
import { VersionValue, VersioningOptions } from '../version-options.interface.js';
|
|
4
|
+
/**
|
|
5
|
+
* Shape of the error-layer callback that Nest hands to
|
|
6
|
+
* {@link HttpServer.setErrorHandler}.
|
|
7
|
+
*
|
|
8
|
+
* The adapter invokes it with the error as the first argument. It is the
|
|
9
|
+
* safety net for errors that never went through Nest: route handlers and
|
|
10
|
+
* middleware registered by Nest already run their errors through the
|
|
11
|
+
* exception filters, so this callback receives what is left, such as failures
|
|
12
|
+
* of middleware registered directly on the framework (e.g. with `app.use()`),
|
|
13
|
+
* body-parser errors, and values passed to `next(err)`. `next` may be omitted
|
|
14
|
+
* when the underlying framework has no notion of an error-continuation
|
|
15
|
+
* callback.
|
|
16
|
+
*
|
|
17
|
+
* @publicApi
|
|
18
|
+
*/
|
|
4
19
|
export type ErrorHandler<TRequest = any, TResponse = any> = (error: any, req: TRequest, res: TResponse, next?: Function) => any;
|
|
20
|
+
/**
|
|
21
|
+
* Shape of every callback Nest registers through the adapter: route handlers,
|
|
22
|
+
* middleware, and the not-found handler.
|
|
23
|
+
*
|
|
24
|
+
* The adapter must invoke them as `(req, res, next)`, where `next` continues
|
|
25
|
+
* with the next matching middleware or route. Nest relies on it: middleware
|
|
26
|
+
* calls it to continue the chain, routes of a `@Controller({ host })` call it
|
|
27
|
+
* when the request host does not match (and the core throws
|
|
28
|
+
* `InternalServerErrorException` when it is missing), and the handlers
|
|
29
|
+
* returned by {@link HttpServer.applyVersionFilter} typically call it when the
|
|
30
|
+
* requested version does not match.
|
|
31
|
+
*
|
|
32
|
+
* The callbacks may return a promise. For route handlers it settles once
|
|
33
|
+
* {@link HttpServer.reply} (or `render`/`redirect`) has been called, so an
|
|
34
|
+
* adapter for a framework that expects the response to be ready when its
|
|
35
|
+
* handler returns must await it.
|
|
36
|
+
*
|
|
37
|
+
* @publicApi
|
|
38
|
+
*/
|
|
5
39
|
export type RequestHandler<TRequest = any, TResponse = any> = (req: TRequest, res: TResponse, next?: Function) => any;
|
|
40
|
+
/**
|
|
41
|
+
* Contract between the Nest core (`NestApplication`, the router, the
|
|
42
|
+
* middleware module and the exception layer) and an HTTP platform such as
|
|
43
|
+
* Express or Fastify.
|
|
44
|
+
*
|
|
45
|
+
* Implementations normally extend `AbstractHttpAdapter` from `@nestjs/core`,
|
|
46
|
+
* which supplies defaults for the methods that can simply delegate to the
|
|
47
|
+
* underlying framework instance. This interface is the source of truth for
|
|
48
|
+
* *when* the core calls each method and *what* it expects back; the class
|
|
49
|
+
* documents only what it adds on top.
|
|
50
|
+
*
|
|
51
|
+
* ### Lifecycle
|
|
52
|
+
*
|
|
53
|
+
* 1. `NestFactory.create()` awaits {@link HttpServer.init} before scanning the
|
|
54
|
+
* module graph, then constructs the application, which calls
|
|
55
|
+
* {@link HttpServer.initHttpServer} so that
|
|
56
|
+
* {@link HttpServer.getHttpServer} returns a native server before
|
|
57
|
+
* `app.init()` runs. `TestingModule.createNestApplication()` only
|
|
58
|
+
* constructs the application, so it skips that first `init()` call.
|
|
59
|
+
* 2. `app.init()` applies the `cors` option through
|
|
60
|
+
* {@link HttpServer.enableCors}, awaits {@link HttpServer.init} again and
|
|
61
|
+
* calls {@link HttpServer.registerParserMiddleware} (unless
|
|
62
|
+
* `bodyParser: false`). It then connects the WebSocket gateways (which
|
|
63
|
+
* share the native server unless they set their own port), registers
|
|
64
|
+
* middleware through {@link HttpServer.createMiddlewareFactory} and routes
|
|
65
|
+
* through the verb methods, and runs the `OnModuleInit` hooks. Only then
|
|
66
|
+
* does it call {@link HttpServer.setNotFoundHandler} and
|
|
67
|
+
* {@link HttpServer.setErrorHandler}, before the `OnApplicationBootstrap`
|
|
68
|
+
* hooks run.
|
|
69
|
+
* 3. `app.listen()` runs `app.init()` if that has not happened yet, then calls
|
|
70
|
+
* {@link HttpServer.listen}.
|
|
71
|
+
* 4. `app.close()` awaits {@link HttpServer.beforeClose}, runs the
|
|
72
|
+
* `OnModuleDestroy` and `BeforeApplicationShutdown` hooks, closes the
|
|
73
|
+
* WebSocket gateways and the microservice clients, awaits
|
|
74
|
+
* {@link HttpServer.close}, closes the connected microservices, and
|
|
75
|
+
* finally runs the `OnApplicationShutdown` hooks.
|
|
76
|
+
*
|
|
77
|
+
* ### Requirements on the request, response and server objects
|
|
78
|
+
*
|
|
79
|
+
* Responses are written through the adapter, but the core also accesses the
|
|
80
|
+
* framework objects directly:
|
|
81
|
+
*
|
|
82
|
+
* - The route parameter decorators read properties of `TRequest`, so the
|
|
83
|
+
* adapter must make sure they are set by the time a route handler runs
|
|
84
|
+
* when the framework does not provide them: `body` (`@Body()`), `params`
|
|
85
|
+
* (`@Param()`), `query` (`@Query()`), `headers` keyed by lower-case name
|
|
86
|
+
* (`@Headers()`), `ip` (`@Ip()`) and, with the `rawBody` option, `rawBody`
|
|
87
|
+
* (`@RawBody()`). `session`, `file` and `files` (`@Session()`,
|
|
88
|
+
* `@UploadedFile()`, `@UploadedFiles()`) are usually set by third-party
|
|
89
|
+
* middleware.
|
|
90
|
+
* - The core attaches its own properties to `TRequest`: `hosts` for
|
|
91
|
+
* `@HostParam()`, the context id of request-scoped providers, and the abort
|
|
92
|
+
* controller of `@Sse()` routes, so the request has to be an extensible
|
|
93
|
+
* object. Request-scoped providers share one context between middleware
|
|
94
|
+
* and the route handler only if both receive the same request object, or if
|
|
95
|
+
* the handler's request exposes the middleware's one as `raw`.
|
|
96
|
+
* - Server-Sent Events (`@Sse()`) write straight to the Node.js response as a
|
|
97
|
+
* writable stream (`writeHead`, `write`, `end`, `writableEnded`) and watch
|
|
98
|
+
* `request.socket` to detect client disconnects. The core uses `res.raw`
|
|
99
|
+
* and `req.raw` when present, and the objects themselves otherwise, so they
|
|
100
|
+
* must be or expose a Node.js `ServerResponse` and `IncomingMessage`.
|
|
101
|
+
* - The value returned by {@link HttpServer.getHttpServer} must behave like a
|
|
102
|
+
* Node.js `net.Server`: `app.listen()` subscribes to its `'error'` event and
|
|
103
|
+
* reads `address()`, and the WebSocket adapters attach to it.
|
|
104
|
+
*
|
|
105
|
+
* ### Optional members
|
|
106
|
+
*
|
|
107
|
+
* Most members marked optional are checked for presence before being called,
|
|
108
|
+
* and the fallback behavior is described on each one. The exceptions are
|
|
109
|
+
* {@link HttpServer.getRequestHostname}, {@link HttpServer.getRequestMethod}
|
|
110
|
+
* and {@link HttpServer.getRequestUrl}, which the core calls unconditionally
|
|
111
|
+
* in some code paths, so treat them as required. Note that
|
|
112
|
+
* `AbstractHttpAdapter` declares several optional members abstract, so a
|
|
113
|
+
* class-based adapter has to implement them anyway.
|
|
114
|
+
*
|
|
115
|
+
* ### Synchronous and asynchronous members
|
|
116
|
+
*
|
|
117
|
+
* The core awaits only {@link HttpServer.init},
|
|
118
|
+
* {@link HttpServer.createMiddlewareFactory}, {@link HttpServer.beforeClose}
|
|
119
|
+
* and {@link HttpServer.close}, as well as {@link HttpServer.reply} and
|
|
120
|
+
* {@link HttpServer.render} when the router calls them. Every other member is
|
|
121
|
+
* called synchronously and a returned promise is ignored. In particular, the
|
|
122
|
+
* registration methods (`use()`, the verb methods, the parser and CORS
|
|
123
|
+
* methods, ...) must take effect before they return, or the registration
|
|
124
|
+
* order the core relies on is lost.
|
|
125
|
+
*
|
|
126
|
+
* @typeParam TRequest - Type of the framework request object handed to
|
|
127
|
+
* handlers and to the `getRequest*` helpers.
|
|
128
|
+
* @typeParam TResponse - Type of the framework response object handed to
|
|
129
|
+
* handlers and to the `reply`/`status`/`setHeader` family.
|
|
130
|
+
* @typeParam ServerInstance - Type of the framework application instance
|
|
131
|
+
* returned by {@link HttpServer.getInstance} (e.g. the Express `Application`),
|
|
132
|
+
* as opposed to the native HTTP server returned by
|
|
133
|
+
* {@link HttpServer.getHttpServer}.
|
|
134
|
+
*
|
|
135
|
+
* @see [HTTP adapter](https://docs.nestjs.com/faq/http-adapter)
|
|
136
|
+
*
|
|
137
|
+
* @publicApi
|
|
138
|
+
*/
|
|
6
139
|
export interface HttpServer<TRequest = any, TResponse = any, ServerInstance = any> {
|
|
140
|
+
/**
|
|
141
|
+
* Registers a global middleware, optionally mounted under `path`.
|
|
142
|
+
*
|
|
143
|
+
* Called by `app.use()`, by the core when registering the parser and
|
|
144
|
+
* exception layers, and as the fallback route registrar when an optional
|
|
145
|
+
* HTTP-verb method (e.g. `propfind`) is not implemented, in which case the
|
|
146
|
+
* route matches every method.
|
|
147
|
+
*
|
|
148
|
+
* The handler may be a {@link RequestHandler} or an {@link ErrorHandler};
|
|
149
|
+
* Express-style adapters distinguish them by arity.
|
|
150
|
+
*/
|
|
7
151
|
use(handler: RequestHandler<TRequest, TResponse> | ErrorHandler<TRequest, TResponse>): any;
|
|
8
152
|
use(path: string, handler: RequestHandler<TRequest, TResponse> | ErrorHandler<TRequest, TResponse>): any;
|
|
153
|
+
/**
|
|
154
|
+
* Registers an additional body parser, called by `app.useBodyParser()`.
|
|
155
|
+
*
|
|
156
|
+
* The core inserts the application's `rawBody` option as the **second**
|
|
157
|
+
* argument, so the effective call is
|
|
158
|
+
* `useBodyParser(type, rawBody, ...userArgs)`. When `rawBody` is `true` the
|
|
159
|
+
* parser must expose the unparsed payload as `req.rawBody` (see
|
|
160
|
+
* `RawBodyRequest`).
|
|
161
|
+
*
|
|
162
|
+
* When not implemented, `app.useBodyParser()` logs a warning and does
|
|
163
|
+
* nothing.
|
|
164
|
+
*/
|
|
9
165
|
useBodyParser?(...args: any[]): any;
|
|
166
|
+
/**
|
|
167
|
+
* Registers a `GET` route.
|
|
168
|
+
*
|
|
169
|
+
* Every verb method receives the already normalized path (see
|
|
170
|
+
* {@link HttpServer.normalizePath}) and a {@link RequestHandler} that the
|
|
171
|
+
* adapter must invoke as `(req, res, next)`. Routes are registered in the
|
|
172
|
+
* order the core resolves them; see
|
|
173
|
+
* {@link HttpServer.isRouteOrderSensitive}.
|
|
174
|
+
*/
|
|
10
175
|
get(handler: RequestHandler<TRequest, TResponse>): any;
|
|
11
176
|
get(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
177
|
+
/**
|
|
178
|
+
* Registers a `POST` route. See {@link HttpServer.get} for the handler
|
|
179
|
+
* contract.
|
|
180
|
+
*/
|
|
12
181
|
post(handler: RequestHandler<TRequest, TResponse>): any;
|
|
13
182
|
post(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
183
|
+
/**
|
|
184
|
+
* Registers a `HEAD` route. See {@link HttpServer.get} for the handler
|
|
185
|
+
* contract.
|
|
186
|
+
*/
|
|
14
187
|
head(handler: RequestHandler<TRequest, TResponse>): any;
|
|
15
188
|
head(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
189
|
+
/**
|
|
190
|
+
* Registers a `DELETE` route. See {@link HttpServer.get} for the handler
|
|
191
|
+
* contract.
|
|
192
|
+
*/
|
|
16
193
|
delete(handler: RequestHandler<TRequest, TResponse>): any;
|
|
17
194
|
delete(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
195
|
+
/**
|
|
196
|
+
* Registers a `PUT` route. See {@link HttpServer.get} for the handler
|
|
197
|
+
* contract.
|
|
198
|
+
*/
|
|
18
199
|
put(handler: RequestHandler<TRequest, TResponse>): any;
|
|
19
200
|
put(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
201
|
+
/**
|
|
202
|
+
* Registers a `PATCH` route. See {@link HttpServer.get} for the handler
|
|
203
|
+
* contract.
|
|
204
|
+
*/
|
|
20
205
|
patch(handler: RequestHandler<TRequest, TResponse>): any;
|
|
21
206
|
patch(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
207
|
+
/**
|
|
208
|
+
* Registers a WebDAV `PROPFIND` route. Optional: when not implemented the
|
|
209
|
+
* core falls back to {@link HttpServer.use}, which matches every method.
|
|
210
|
+
*/
|
|
22
211
|
propfind?(handler: RequestHandler<TRequest, TResponse>): any;
|
|
23
212
|
propfind?(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
213
|
+
/**
|
|
214
|
+
* Registers a WebDAV `PROPPATCH` route. Optional: when not implemented the
|
|
215
|
+
* core falls back to {@link HttpServer.use}, which matches every method.
|
|
216
|
+
*/
|
|
24
217
|
proppatch?(handler: RequestHandler<TRequest, TResponse>): any;
|
|
25
218
|
proppatch?(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
219
|
+
/**
|
|
220
|
+
* Registers a WebDAV `MKCOL` route. Optional: when not implemented the
|
|
221
|
+
* core falls back to {@link HttpServer.use}, which matches every method.
|
|
222
|
+
*/
|
|
26
223
|
mkcol?(handler: RequestHandler<TRequest, TResponse>): any;
|
|
27
224
|
mkcol?(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
225
|
+
/**
|
|
226
|
+
* Registers a WebDAV `COPY` route. Optional: when not implemented the
|
|
227
|
+
* core falls back to {@link HttpServer.use}, which matches every method.
|
|
228
|
+
*/
|
|
28
229
|
copy?(handler: RequestHandler<TRequest, TResponse>): any;
|
|
29
230
|
copy?(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
231
|
+
/**
|
|
232
|
+
* Registers a WebDAV `MOVE` route. Optional: when not implemented the
|
|
233
|
+
* core falls back to {@link HttpServer.use}, which matches every method.
|
|
234
|
+
*/
|
|
30
235
|
move?(handler: RequestHandler<TRequest, TResponse>): any;
|
|
31
236
|
move?(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
237
|
+
/**
|
|
238
|
+
* Registers a WebDAV `LOCK` route. Optional: when not implemented the
|
|
239
|
+
* core falls back to {@link HttpServer.use}, which matches every method.
|
|
240
|
+
*/
|
|
32
241
|
lock?(handler: RequestHandler<TRequest, TResponse>): any;
|
|
33
242
|
lock?(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
243
|
+
/**
|
|
244
|
+
* Registers a WebDAV `UNLOCK` route. Optional: when not implemented the
|
|
245
|
+
* core falls back to {@link HttpServer.use}, which matches every method.
|
|
246
|
+
*/
|
|
34
247
|
unlock?(handler: RequestHandler<TRequest, TResponse>): any;
|
|
35
248
|
unlock?(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
249
|
+
/**
|
|
250
|
+
* Registers a route for every HTTP method (`@All()`). See
|
|
251
|
+
* {@link HttpServer.get} for the handler contract.
|
|
252
|
+
*/
|
|
36
253
|
all(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
37
254
|
all(handler: RequestHandler<TRequest, TResponse>): any;
|
|
255
|
+
/**
|
|
256
|
+
* Registers an `OPTIONS` route. See {@link HttpServer.get} for the handler
|
|
257
|
+
* contract.
|
|
258
|
+
*/
|
|
38
259
|
options(handler: RequestHandler<TRequest, TResponse>): any;
|
|
39
260
|
options(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
261
|
+
/**
|
|
262
|
+
* Registers a `SEARCH` route. Optional: when not implemented the core falls
|
|
263
|
+
* back to {@link HttpServer.use}, which matches every method.
|
|
264
|
+
*/
|
|
40
265
|
search?(handler: RequestHandler<TRequest, TResponse>): any;
|
|
41
266
|
search?(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
267
|
+
/**
|
|
268
|
+
* Registers a `QUERY` route. Optional: when not implemented the core falls
|
|
269
|
+
* back to {@link HttpServer.use}, which matches every method.
|
|
270
|
+
*/
|
|
42
271
|
query?(handler: RequestHandler<TRequest, TResponse>): any;
|
|
43
272
|
query?(path: string, handler: RequestHandler<TRequest, TResponse>): any;
|
|
273
|
+
/**
|
|
274
|
+
* Starts accepting connections; called by `app.listen()` once the
|
|
275
|
+
* application has been initialized.
|
|
276
|
+
*
|
|
277
|
+
* The core always appends its own callback as the **last** argument, and
|
|
278
|
+
* strips any callback the user passed to `app.listen()`. The adapter must
|
|
279
|
+
* invoke that callback once the server is listening, or with an `Error` as
|
|
280
|
+
* first argument when it failed to bind; the core rejects the `listen()`
|
|
281
|
+
* promise in that case. The core additionally subscribes to the `'error'`
|
|
282
|
+
* event of {@link HttpServer.getHttpServer} while binding.
|
|
283
|
+
*
|
|
284
|
+
* On success, the `app.listen()` promise only resolves if
|
|
285
|
+
* `getHttpServer().address()` returns a non-null value when the callback
|
|
286
|
+
* runs; otherwise it stays pending.
|
|
287
|
+
*
|
|
288
|
+
* @param port Port number, or a string such as a pipe/socket path.
|
|
289
|
+
* @param hostname Optional host to bind to.
|
|
290
|
+
* @param callback Invoked as `(err?)` once listening or on failure.
|
|
291
|
+
*/
|
|
44
292
|
listen(port: number | string, callback?: () => void): any;
|
|
45
293
|
listen(port: number | string, hostname: string, callback?: () => void): any;
|
|
294
|
+
/**
|
|
295
|
+
* Sends the final response body. The router calls it for every handler
|
|
296
|
+
* that does not take over the response with `@Res()` (without
|
|
297
|
+
* `passthrough: true`) or `@Next()`, except for `@Render()`, `@Redirect()`
|
|
298
|
+
* and `@Sse()` handlers, which go through {@link HttpServer.render},
|
|
299
|
+
* {@link HttpServer.redirect} and the raw response respectively. The
|
|
300
|
+
* built-in exception filter uses it as well, so it has to cover the
|
|
301
|
+
* following cases:
|
|
302
|
+
*
|
|
303
|
+
* - `statusCode` provided: apply it before sending.
|
|
304
|
+
* - `body` is `null`/`undefined`: end the response with an empty body.
|
|
305
|
+
* - `body` is a `StreamableFile`: set `Content-Type`, `Content-Disposition`
|
|
306
|
+
* and `Content-Length` from `body.getHeaders()` unless already present,
|
|
307
|
+
* pipe `body.getStream()` into the response, route stream errors to
|
|
308
|
+
* `body.errorHandler(err, response)` and log write errors through
|
|
309
|
+
* `body.errorLogger(err)`.
|
|
310
|
+
* - `body` is an object or array: serialize as JSON.
|
|
311
|
+
* - anything else: send `String(body)`.
|
|
312
|
+
*
|
|
313
|
+
* The router awaits a returned promise, but the exception filter does not,
|
|
314
|
+
* so an asynchronous implementation must handle its own errors.
|
|
315
|
+
*
|
|
316
|
+
* @param response Framework response object.
|
|
317
|
+
* @param body Value returned by the route handler (after interceptors).
|
|
318
|
+
* @param statusCode Status to apply, when the router determined one.
|
|
319
|
+
*/
|
|
46
320
|
reply(response: any, body: any, statusCode?: number): any;
|
|
321
|
+
/**
|
|
322
|
+
* Sets the status code without sending the response. Called for every
|
|
323
|
+
* route once the guards have passed, before the interceptors and the
|
|
324
|
+
* handler run, with the status derived from `@HttpCode()` or the method
|
|
325
|
+
* default (`201` for `POST`, `200` otherwise). Not awaited.
|
|
326
|
+
*/
|
|
47
327
|
status(response: any, statusCode: number): any;
|
|
328
|
+
/**
|
|
329
|
+
* Terminates the response, optionally writing `message` first. The
|
|
330
|
+
* exception layer uses it when {@link HttpServer.isHeadersSent} reports that
|
|
331
|
+
* a reply already started, so the adapter must not attempt to set headers
|
|
332
|
+
* or a status here.
|
|
333
|
+
*/
|
|
48
334
|
end(response: any, message?: string): any;
|
|
335
|
+
/**
|
|
336
|
+
* Renders a view template; called for handlers decorated with `@Render()`
|
|
337
|
+
* with the (awaited) handler result as `options`.
|
|
338
|
+
*/
|
|
49
339
|
render(response: any, view: string, options: any): any;
|
|
340
|
+
/**
|
|
341
|
+
* Issues a redirect; called for handlers decorated with `@Redirect()`.
|
|
342
|
+
* `statusCode` is always provided (defaults to `302`), and `url` may come
|
|
343
|
+
* from the handler result `{ url, statusCode }` overriding the decorator.
|
|
344
|
+
*/
|
|
50
345
|
redirect(response: any, statusCode: number, url: string): any;
|
|
346
|
+
/**
|
|
347
|
+
* Reports whether the response headers have already been flushed. The
|
|
348
|
+
* exception layer checks it to decide between {@link HttpServer.reply} and
|
|
349
|
+
* {@link HttpServer.end}. It must return a boolean synchronously: the result
|
|
350
|
+
* is not awaited, and a promise is truthy, so every error response would be
|
|
351
|
+
* cut short through {@link HttpServer.end}.
|
|
352
|
+
*/
|
|
51
353
|
isHeadersSent(response: any): boolean;
|
|
354
|
+
/**
|
|
355
|
+
* Sets (replaces) a response header; called once per `@Header()` decorator,
|
|
356
|
+
* right after {@link HttpServer.status}. Not awaited.
|
|
357
|
+
*/
|
|
52
358
|
setHeader(response: any, name: string, value: string): any;
|
|
359
|
+
/**
|
|
360
|
+
* Installs the global exception layer: an {@link ErrorHandler} that
|
|
361
|
+
* forwards errors to the registered exception filters. The core calls it
|
|
362
|
+
* once, after every route has been registered, and skips it when not
|
|
363
|
+
* implemented.
|
|
364
|
+
*
|
|
365
|
+
* Errors thrown by the route handlers and middleware that Nest registers
|
|
366
|
+
* normally don't reach it, because the core already runs them through the
|
|
367
|
+
* exception filters. The adapter must route every other error to it:
|
|
368
|
+
* failures of middleware registered directly on the framework (e.g. with
|
|
369
|
+
* `app.use()`), body-parser errors, and values passed to `next(err)`. The
|
|
370
|
+
* handler first passes the error to the adapter's `mapException()` so
|
|
371
|
+
* framework-native errors can be translated to `HttpException`s; that method
|
|
372
|
+
* is defined by `AbstractHttpAdapter`, so an adapter implementing this
|
|
373
|
+
* interface directly must provide it too.
|
|
374
|
+
*
|
|
375
|
+
* @param handler The `(err, req, res, next)` callback.
|
|
376
|
+
* @param prefix The global prefix (`app.setGlobalPrefix()`), when set.
|
|
377
|
+
* Routes excluded from the prefix still live at the root, so an adapter that
|
|
378
|
+
* scopes error handlers by path must cover both.
|
|
379
|
+
*/
|
|
53
380
|
setErrorHandler?(handler: Function, prefix?: string): any;
|
|
381
|
+
/**
|
|
382
|
+
* Installs the catch-all handler for unmatched requests. The core calls it
|
|
383
|
+
* once, after every route has been registered, and skips it when not
|
|
384
|
+
* implemented.
|
|
385
|
+
*
|
|
386
|
+
* The handler is a {@link RequestHandler} that throws `NotFoundException`
|
|
387
|
+
* through the exception filters, so the adapter only has to make sure it
|
|
388
|
+
* runs after all routes and middleware, and only for requests no route
|
|
389
|
+
* matched. It builds its message with {@link HttpServer.getRequestMethod}
|
|
390
|
+
* and {@link HttpServer.getRequestUrl}, so both must be implemented.
|
|
391
|
+
*
|
|
392
|
+
* @param handler The `(req, res, next)` callback.
|
|
393
|
+
* @param prefix The global prefix (`app.setGlobalPrefix()`), when set.
|
|
394
|
+
*/
|
|
54
395
|
setNotFoundHandler?(handler: Function, prefix?: string): any;
|
|
396
|
+
/**
|
|
397
|
+
* Serves static files; pass-through for `app.useStaticAssets()`. The
|
|
398
|
+
* arguments are platform-specific. When not implemented,
|
|
399
|
+
* `app.useStaticAssets()` silently does nothing.
|
|
400
|
+
*/
|
|
55
401
|
useStaticAssets?(...args: any[]): this;
|
|
402
|
+
/**
|
|
403
|
+
* Sets the directory (or directories) where view templates live;
|
|
404
|
+
* pass-through for `app.setBaseViewsDir()`. When not implemented,
|
|
405
|
+
* `app.setBaseViewsDir()` silently does nothing.
|
|
406
|
+
*/
|
|
56
407
|
setBaseViewsDir?(path: string | string[]): this;
|
|
408
|
+
/**
|
|
409
|
+
* Configures the template engine used by {@link HttpServer.render};
|
|
410
|
+
* pass-through for `app.setViewEngine()`. The argument is
|
|
411
|
+
* platform-specific (an engine name for Express, an options object for
|
|
412
|
+
* Fastify). When not implemented, `app.setViewEngine()` silently does
|
|
413
|
+
* nothing.
|
|
414
|
+
*/
|
|
57
415
|
setViewEngine?(engineOrOptions: any): this;
|
|
416
|
+
/**
|
|
417
|
+
* Returns a function the middleware module uses to mount Nest middleware
|
|
418
|
+
* (`MiddlewareConsumer`) for one HTTP method.
|
|
419
|
+
*
|
|
420
|
+
* The returned function is called as `(path, callback)` once per route
|
|
421
|
+
* path the middleware applies to, where `callback` is a
|
|
422
|
+
* {@link RequestHandler} that calls `next()` to continue the chain. The core
|
|
423
|
+
* passes `/` for empty or root paths. When `method` is not
|
|
424
|
+
* `RequestMethod.ALL`, the core already wraps `callback` to skip requests
|
|
425
|
+
* whose {@link HttpServer.getRequestMethod} does not match (treating `HEAD`
|
|
426
|
+
* as `GET`), so a framework that cannot register method-specific middleware
|
|
427
|
+
* may mount it for every method. Without
|
|
428
|
+
* {@link HttpServer.getRequestMethod}, that check never matches and such
|
|
429
|
+
* middleware silently never runs.
|
|
430
|
+
*
|
|
431
|
+
* May return a promise (e.g. when a middleware plugin has to be loaded
|
|
432
|
+
* first); the core awaits it.
|
|
433
|
+
*/
|
|
58
434
|
createMiddlewareFactory(method: RequestMethod): ((path: string, callback: Function) => any) | Promise<(path: string, callback: Function) => any>;
|
|
435
|
+
/**
|
|
436
|
+
* Returns the request host name (without port), used to match
|
|
437
|
+
* `@Controller({ host })`. The core calls it without checking for its
|
|
438
|
+
* presence, so it is required whenever host filtering is used.
|
|
439
|
+
*/
|
|
59
440
|
getRequestHostname?(request: TRequest): string;
|
|
441
|
+
/**
|
|
442
|
+
* Returns the request method as the upper-case verb (`'GET'`, `'HEAD'`,
|
|
443
|
+
* ...), i.e. a key of the `RequestMethod` enum. Effectively required: the
|
|
444
|
+
* not-found handler and `MiddlewareConsumer.exclude()` call it without
|
|
445
|
+
* checking for its presence, and without it middleware bound to a specific
|
|
446
|
+
* method silently never runs.
|
|
447
|
+
*/
|
|
60
448
|
getRequestMethod?(request: TRequest): string;
|
|
449
|
+
/**
|
|
450
|
+
* Returns the original request URL, including the query string and
|
|
451
|
+
* independent of any router mount point (Express `req.originalUrl`, not
|
|
452
|
+
* `req.url`). The core strips the query string itself when it needs the
|
|
453
|
+
* pathname, e.g. to evaluate `MiddlewareConsumer.exclude()`. Effectively
|
|
454
|
+
* required: the not-found handler and `exclude()` call it without checking
|
|
455
|
+
* for its presence.
|
|
456
|
+
*/
|
|
61
457
|
getRequestUrl?(request: TRequest): string;
|
|
458
|
+
/**
|
|
459
|
+
* Returns the framework application instance (e.g. the Express
|
|
460
|
+
* `Application`) that the adapter delegates to. Exposed to users through
|
|
461
|
+
* `app.getHttpAdapter().getInstance()`.
|
|
462
|
+
*/
|
|
62
463
|
getInstance(): ServerInstance;
|
|
464
|
+
/**
|
|
465
|
+
* Registers the default body parsers. Called once during `app.init()`
|
|
466
|
+
* unless the application was created with `bodyParser: false`, as
|
|
467
|
+
* `registerParserMiddleware(globalPrefix, rawBody)`.
|
|
468
|
+
*
|
|
469
|
+
* Implementations should register JSON and URL-encoded parsers, and, when
|
|
470
|
+
* `rawBody` is `true`, expose the unparsed payload as `req.rawBody` (see
|
|
471
|
+
* `RawBodyRequest`). Because users may register the same parsers
|
|
472
|
+
* beforehand, this should be idempotent.
|
|
473
|
+
*/
|
|
63
474
|
registerParserMiddleware(...args: any[]): any;
|
|
475
|
+
/**
|
|
476
|
+
* Enables CORS. Called by `app.enableCors(options)` and during
|
|
477
|
+
* `app.init()` when the `cors` application option is set; `options` is
|
|
478
|
+
* then either the `CorsOptions`/delegate the user provided, or `undefined`
|
|
479
|
+
* for `cors: true`.
|
|
480
|
+
*/
|
|
64
481
|
enableCors(options: any): any;
|
|
482
|
+
/**
|
|
483
|
+
* Returns the native HTTP server created by
|
|
484
|
+
* {@link HttpServer.initHttpServer}. It must behave like a Node.js
|
|
485
|
+
* `net.Server` (`listen`, `close`, `address`, `on('error')`), since
|
|
486
|
+
* `app.listen()` and the WebSocket adapters use it directly.
|
|
487
|
+
*/
|
|
65
488
|
getHttpServer(): any;
|
|
489
|
+
/**
|
|
490
|
+
* Creates the native HTTP(S) server so that {@link HttpServer.getHttpServer}
|
|
491
|
+
* can return it. Called once, synchronously, when the application is
|
|
492
|
+
* constructed (by `NestFactory.create()` or
|
|
493
|
+
* `TestingModule.createNestApplication()`), before `app.init()`.
|
|
494
|
+
*
|
|
495
|
+
* The adapter is responsible for honoring the relevant application
|
|
496
|
+
* options: `httpsOptions` (create an HTTPS server),
|
|
497
|
+
* `forceCloseConnections` (track sockets so {@link HttpServer.close} can
|
|
498
|
+
* destroy them) and `return503OnClosing` (reject requests once
|
|
499
|
+
* {@link HttpServer.beforeClose} ran).
|
|
500
|
+
*/
|
|
66
501
|
initHttpServer(options: NestApplicationOptions): void;
|
|
502
|
+
/**
|
|
503
|
+
* Stops the server and releases its resources. Called by `app.close()`
|
|
504
|
+
* after the `OnModuleDestroy` and `BeforeApplicationShutdown` hooks and
|
|
505
|
+
* after the WebSocket gateways and microservice clients have been closed,
|
|
506
|
+
* but before connected microservices are closed and the
|
|
507
|
+
* `OnApplicationShutdown` hooks run. May return a promise; the core awaits
|
|
508
|
+
* it.
|
|
509
|
+
*/
|
|
67
510
|
close(): any;
|
|
511
|
+
/**
|
|
512
|
+
* Called by `app.close()` **before** any shutdown hook (`OnModuleDestroy`,
|
|
513
|
+
* `BeforeApplicationShutdown`, `OnApplicationShutdown`) runs, so the
|
|
514
|
+
* adapter can flip into a "shutting down" state, e.g. start answering `503`
|
|
515
|
+
* when `return503OnClosing` is enabled. May return a promise; the core
|
|
516
|
+
* awaits it.
|
|
517
|
+
*/
|
|
68
518
|
beforeClose?(): any;
|
|
519
|
+
/**
|
|
520
|
+
* Returns a stable identifier for the platform (`'express'`, `'fastify'`).
|
|
521
|
+
* The core does not read it, but ecosystem packages (e.g. `@nestjs/swagger`,
|
|
522
|
+
* `@nestjs/serve-static`) branch on it to pick platform-specific code
|
|
523
|
+
* paths, so custom adapters wrapping one of the built-in frameworks should
|
|
524
|
+
* return the matching value.
|
|
525
|
+
*/
|
|
69
526
|
getType(): string;
|
|
527
|
+
/**
|
|
528
|
+
* Asynchronous setup hook for work that cannot happen in the constructor,
|
|
529
|
+
* such as loading a plugin. It can run twice: `NestFactory.create()` awaits
|
|
530
|
+
* it before the module graph is scanned (and before
|
|
531
|
+
* {@link HttpServer.initHttpServer}), and `app.init()` awaits it again after
|
|
532
|
+
* the `cors` option has been applied and before the parsers, middleware and
|
|
533
|
+
* routes are registered. `TestingModule.createNestApplication()` only
|
|
534
|
+
* triggers the second call. Implementations must therefore be idempotent,
|
|
535
|
+
* e.g. by guarding the work with a flag as `FastifyAdapter` does.
|
|
536
|
+
*/
|
|
70
537
|
init?(): Promise<void>;
|
|
538
|
+
/**
|
|
539
|
+
* Wraps a route handler so that it only runs for requests carrying a
|
|
540
|
+
* matching version. Called once per versioned route for the `HEADER`,
|
|
541
|
+
* `MEDIA_TYPE` and `CUSTOM` versioning types; URI versioning is expressed
|
|
542
|
+
* in the path and never reaches this method.
|
|
543
|
+
*
|
|
544
|
+
* Two strategies are valid:
|
|
545
|
+
* - return a `(req, res, next)` function that extracts the requested
|
|
546
|
+
* version, invokes `handler` when it matches and calls `next()` otherwise
|
|
547
|
+
* (Express), or
|
|
548
|
+
* - return `handler` itself, annotated so the framework's own routing can
|
|
549
|
+
* apply the constraint (Fastify).
|
|
550
|
+
*
|
|
551
|
+
* @param handler The route handler to guard.
|
|
552
|
+
* @param version Version(s) the route serves: a string, an array of
|
|
553
|
+
* strings, or `VERSION_NEUTRAL`. An array may include `VERSION_NEUTRAL`,
|
|
554
|
+
* meaning the route also serves requests that carry no version.
|
|
555
|
+
* @param versioningOptions The options passed to `app.enableVersioning()`.
|
|
556
|
+
*/
|
|
71
557
|
applyVersionFilter(handler: Function, version: VersionValue, versioningOptions: VersioningOptions): (req: TRequest, res: TResponse, next: () => void) => Function;
|
|
558
|
+
/**
|
|
559
|
+
* Converts a Nest route path into the syntax the underlying router
|
|
560
|
+
* expects, and validates it. Called once per route path (already prefixed
|
|
561
|
+
* and versioned) before it is handed to a verb method; should throw when
|
|
562
|
+
* the path is invalid so misconfigured routes fail at startup. When not
|
|
563
|
+
* implemented the path is used verbatim.
|
|
564
|
+
*/
|
|
72
565
|
normalizePath?(path: string): string;
|
|
566
|
+
/**
|
|
567
|
+
* Tells the core whether the underlying router picks the **first**
|
|
568
|
+
* registered route that matches (`true`, e.g. Express) or the most specific
|
|
569
|
+
* one regardless of order (`false`, e.g. Fastify). Defaults to `true` when
|
|
570
|
+
* not implemented.
|
|
571
|
+
*
|
|
572
|
+
* When `true` and the `specificity` route resolution strategy is enabled,
|
|
573
|
+
* the core sorts routes before registering them. A `false` value is
|
|
574
|
+
* currently also taken to mean that the router rejects duplicate
|
|
575
|
+
* `(method, path)` registrations itself.
|
|
576
|
+
*/
|
|
73
577
|
isRouteOrderSensitive?(): boolean;
|
|
74
578
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@depup/nestjs__common",
|
|
3
|
-
"version": "12.0.
|
|
3
|
+
"version": "12.0.3-depup.0",
|
|
4
4
|
"description": "Nest - modern, fast, powerful node.js web framework (@common) (with updated dependencies)",
|
|
5
5
|
"author": "Kamil Mysliwiec",
|
|
6
6
|
"homepage": "https://nestjs.com",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@standard-schema/spec": "1.1.0",
|
|
27
|
-
"file-type": "
|
|
27
|
+
"file-type": "22.1.0",
|
|
28
28
|
"iterare": "1.2.1",
|
|
29
29
|
"load-esm": "1.0.3",
|
|
30
30
|
"tslib": "2.8.1",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"optional": true
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "14151790e1abe870abc3bbf00f88786fc3ebe509",
|
|
48
48
|
"keywords": [
|
|
49
49
|
"@nestjs/common",
|
|
50
50
|
"depup",
|
|
@@ -54,16 +54,11 @@
|
|
|
54
54
|
"patched"
|
|
55
55
|
],
|
|
56
56
|
"depup": {
|
|
57
|
-
"changes": {
|
|
58
|
-
|
|
59
|
-
"from": "22.0.2",
|
|
60
|
-
"to": "^22.1.0"
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
"depsUpdated": 1,
|
|
57
|
+
"changes": {},
|
|
58
|
+
"depsUpdated": 0,
|
|
64
59
|
"originalPackage": "@nestjs/common",
|
|
65
|
-
"originalVersion": "12.0.
|
|
66
|
-
"processedAt": "2026-09-
|
|
60
|
+
"originalVersion": "12.0.3",
|
|
61
|
+
"processedAt": "2026-09-15T08:12:01.047Z",
|
|
67
62
|
"smokeTest": "passed"
|
|
68
63
|
}
|
|
69
64
|
}
|
|
@@ -2,7 +2,7 @@ import { __decorate, __metadata, __param } from "tslib";
|
|
|
2
2
|
import { Injectable, Optional } from '../../decorators/core/index.js';
|
|
3
3
|
import { HttpStatus } from '../../enums/index.js';
|
|
4
4
|
import { HttpErrorByCode } from '../../utils/http-error-by-code.util.js';
|
|
5
|
-
import { isEmptyArray,
|
|
5
|
+
import { isEmptyArray, isNil, isObject } from '../../utils/shared.utils.js';
|
|
6
6
|
/**
|
|
7
7
|
* Defines the built-in ParseFile Pipe. This pipe can be used to validate incoming files
|
|
8
8
|
* with `@UploadedFile()` decorator. You can use either other specific built-in validators
|
|
@@ -45,7 +45,7 @@ let ParseFilePipe = class ParseFilePipe {
|
|
|
45
45
|
}
|
|
46
46
|
thereAreNoFilesIn(value) {
|
|
47
47
|
const isEmptyObject = isObject(value) && isEmptyArray(Object.keys(value));
|
|
48
|
-
return
|
|
48
|
+
return isNil(value) || isEmptyArray(value) || isEmptyObject;
|
|
49
49
|
}
|
|
50
50
|
async validate(file) {
|
|
51
51
|
for (const validator of this.validators) {
|
|
@@ -38,7 +38,7 @@ let ParseArrayPipe = class ParseArrayPipe {
|
|
|
38
38
|
* @param metadata contains metadata about the currently processed route argument
|
|
39
39
|
*/
|
|
40
40
|
async transform(value, metadata) {
|
|
41
|
-
if (
|
|
41
|
+
if (isNil(value) && !this.options.optional) {
|
|
42
42
|
throw this.exceptionFactory(VALIDATION_ERROR_MESSAGE);
|
|
43
43
|
}
|
|
44
44
|
else if (isNil(value) && this.options.optional) {
|
|
@@ -33,6 +33,7 @@ export declare class ParseEnumPipe<T = any> implements PipeTransform<T> {
|
|
|
33
33
|
protected readonly enumType: T;
|
|
34
34
|
protected readonly options?: ParseEnumPipeOptions | undefined;
|
|
35
35
|
protected exceptionFactory: (error: string) => any;
|
|
36
|
+
private cachedEnumValues?;
|
|
36
37
|
constructor(enumType: T, options?: ParseEnumPipeOptions | undefined);
|
|
37
38
|
/**
|
|
38
39
|
* Method that accesses and performs optional transformation on argument for
|
|
@@ -43,4 +44,12 @@ export declare class ParseEnumPipe<T = any> implements PipeTransform<T> {
|
|
|
43
44
|
*/
|
|
44
45
|
transform(value: unknown, metadata: ArgumentMetadata): Promise<T | undefined | null>;
|
|
45
46
|
protected isEnum(value: unknown): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Returns the enum member that `value` refers to, or `undefined` if there is none.
|
|
49
|
+
* Numeric members also match their string representation (e.g. `'1'` for `1`),
|
|
50
|
+
* since HTTP route and query params always arrive as strings.
|
|
51
|
+
*/
|
|
52
|
+
protected toEnumValue(value: unknown): string | number | undefined;
|
|
53
|
+
protected getEnumValues(): (string | number)[];
|
|
54
|
+
private computeEnumValues;
|
|
46
55
|
}
|
package/pipes/parse-enum.pipe.js
CHANGED
|
@@ -14,6 +14,7 @@ let ParseEnumPipe = class ParseEnumPipe {
|
|
|
14
14
|
enumType;
|
|
15
15
|
options;
|
|
16
16
|
exceptionFactory;
|
|
17
|
+
cachedEnumValues;
|
|
17
18
|
constructor(enumType, options) {
|
|
18
19
|
this.enumType = enumType;
|
|
19
20
|
this.options = options;
|
|
@@ -40,17 +41,35 @@ let ParseEnumPipe = class ParseEnumPipe {
|
|
|
40
41
|
if (!this.isEnum(value)) {
|
|
41
42
|
throw this.exceptionFactory('Validation failed (enum string is expected)');
|
|
42
43
|
}
|
|
43
|
-
return value;
|
|
44
|
+
return (this.toEnumValue(value) ?? value);
|
|
44
45
|
}
|
|
45
46
|
isEnum(value) {
|
|
46
|
-
|
|
47
|
+
return this.toEnumValue(value) !== undefined;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Returns the enum member that `value` refers to, or `undefined` if there is none.
|
|
51
|
+
* Numeric members also match their string representation (e.g. `'1'` for `1`),
|
|
52
|
+
* since HTTP route and query params always arrive as strings.
|
|
53
|
+
*/
|
|
54
|
+
toEnumValue(value) {
|
|
55
|
+
return this.getEnumValues().find(enumValue => enumValue === value ||
|
|
56
|
+
(typeof enumValue === 'number' &&
|
|
57
|
+
typeof value === 'string' &&
|
|
58
|
+
String(enumValue) === value));
|
|
59
|
+
}
|
|
60
|
+
getEnumValues() {
|
|
61
|
+
// The enum object never changes after construction, so the values are
|
|
62
|
+
// computed once and reused on every request.
|
|
63
|
+
return (this.cachedEnumValues ??= this.computeEnumValues());
|
|
64
|
+
}
|
|
65
|
+
computeEnumValues() {
|
|
66
|
+
return Object.keys(this.enumType)
|
|
47
67
|
.filter(key => {
|
|
48
68
|
const enumValue = this.enumType[key];
|
|
49
69
|
return !(typeof enumValue === 'string' &&
|
|
50
70
|
typeof this.enumType[enumValue] === 'number');
|
|
51
71
|
})
|
|
52
72
|
.map(key => this.enumType[key]);
|
|
53
|
-
return enumValues.includes(value);
|
|
54
73
|
}
|
|
55
74
|
};
|
|
56
75
|
ParseEnumPipe = __decorate([
|
package/pipes/parse-uuid.pipe.js
CHANGED
|
@@ -16,11 +16,12 @@ let ParseUUIDPipe = class ParseUUIDPipe {
|
|
|
16
16
|
static { ParseUUIDPipe_1 = this; }
|
|
17
17
|
options;
|
|
18
18
|
static uuidRegExps = {
|
|
19
|
-
3: /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[0-9A-F]{
|
|
19
|
+
3: /^[0-9A-F]{8}-[0-9A-F]{4}-3[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
|
|
20
20
|
4: /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
|
|
21
21
|
5: /^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
|
|
22
22
|
7: /^[0-9A-F]{8}-[0-9A-F]{4}-7[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i,
|
|
23
|
-
|
|
23
|
+
// Versions 1-8 with the RFC variant, or the Nil and Max UUIDs (RFC 9562, sections 5.9, 5.10)
|
|
24
|
+
all: /^(?:[0-9A-F]{8}-[0-9A-F]{4}-[1-8][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}|00000000-0000-0000-0000-000000000000|FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF)$/i,
|
|
24
25
|
};
|
|
25
26
|
version;
|
|
26
27
|
exceptionFactory;
|
|
@@ -84,8 +84,5 @@ export declare class StandardSchemaValidationPipe implements PipeTransform {
|
|
|
84
84
|
* @returns The validation result
|
|
85
85
|
*/
|
|
86
86
|
protected validate<T = unknown>(value: unknown, schema: StandardSchemaV1, options?: Record<string, unknown>): Promise<StandardSchemaV1.Result<T>> | StandardSchemaV1.Result<T>;
|
|
87
|
-
/**
|
|
88
|
-
* Strips dangerous prototype pollution keys from an object.
|
|
89
|
-
*/
|
|
90
87
|
protected stripProtoKeys(value: any): void;
|
|
91
88
|
}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import { __decorate, __metadata, __param } from "tslib";
|
|
2
|
-
import { types } from 'util';
|
|
3
2
|
import { Injectable } from '../decorators/core/injectable.decorator.js';
|
|
4
3
|
import { Optional } from '../decorators/core/optional.decorator.js';
|
|
5
4
|
import { HttpStatus } from '../enums/http-status.enum.js';
|
|
6
5
|
import { HttpErrorByCode, } from '../utils/http-error-by-code.util.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* to avoid conflicts with test frameworks like Jest's useFakeTimers
|
|
10
|
-
*/
|
|
11
|
-
const BUILT_IN_TYPES = [Date, RegExp, Error, Map, Set, WeakMap, WeakSet];
|
|
6
|
+
import { isObject } from '../utils/shared.utils.js';
|
|
7
|
+
import { stripProtoKeys } from '../utils/strip-proto-keys.util.js';
|
|
12
8
|
/**
|
|
13
9
|
* Defines the built-in StandardSchemaValidation Pipe.
|
|
14
10
|
*
|
|
@@ -45,7 +41,10 @@ let StandardSchemaValidationPipe = class StandardSchemaValidationPipe {
|
|
|
45
41
|
formatIssueMessages(issues) {
|
|
46
42
|
return issues.map(issue => {
|
|
47
43
|
if (issue.path?.length) {
|
|
48
|
-
|
|
44
|
+
const stringPath = issue.path
|
|
45
|
+
.map(segment => String(isObject(segment) ? segment.key : segment))
|
|
46
|
+
.join('.');
|
|
47
|
+
return `${stringPath}: ${issue.message}`;
|
|
49
48
|
}
|
|
50
49
|
return issue.message;
|
|
51
50
|
});
|
|
@@ -95,33 +94,8 @@ let StandardSchemaValidationPipe = class StandardSchemaValidationPipe {
|
|
|
95
94
|
validate(value, schema, options) {
|
|
96
95
|
return schema['~standard'].validate(value, options);
|
|
97
96
|
}
|
|
98
|
-
/**
|
|
99
|
-
* Strips dangerous prototype pollution keys from an object.
|
|
100
|
-
*/
|
|
101
97
|
stripProtoKeys(value) {
|
|
102
|
-
|
|
103
|
-
typeof value !== 'object' ||
|
|
104
|
-
types.isTypedArray(value)) {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
if (BUILT_IN_TYPES.some(type => value instanceof type)) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
if (Array.isArray(value)) {
|
|
111
|
-
for (const v of value) {
|
|
112
|
-
this.stripProtoKeys(v);
|
|
113
|
-
}
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
delete value.__proto__;
|
|
117
|
-
delete value.prototype;
|
|
118
|
-
const constructorType = value?.constructor;
|
|
119
|
-
if (constructorType && !BUILT_IN_TYPES.includes(constructorType)) {
|
|
120
|
-
delete value.constructor;
|
|
121
|
-
}
|
|
122
|
-
for (const key in value) {
|
|
123
|
-
this.stripProtoKeys(value[key]);
|
|
124
|
-
}
|
|
98
|
+
stripProtoKeys(value);
|
|
125
99
|
}
|
|
126
100
|
};
|
|
127
101
|
StandardSchemaValidationPipe = __decorate([
|
|
@@ -59,8 +59,8 @@ export declare class ValidationPipe implements PipeTransform {
|
|
|
59
59
|
protected toValidate(metadata: ArgumentMetadata): boolean;
|
|
60
60
|
protected transformPrimitive(value: unknown, metadata: ArgumentMetadata): unknown;
|
|
61
61
|
protected toEmptyIfNil<T = any, R = T>(value: unknown, metatype: Type<unknown> | object): R | object | string;
|
|
62
|
-
protected stripProtoKeys(value: any): void;
|
|
63
62
|
protected isPrimitive(value: unknown): boolean;
|
|
63
|
+
protected stripProtoKeys(value: any): void;
|
|
64
64
|
protected validate(object: object, validatorOptions?: ValidatorOptions): Promise<ValidationError[]> | ValidationError[];
|
|
65
65
|
protected flattenValidationErrors(validationErrors: ValidationError[]): string[];
|
|
66
66
|
protected groupValidationErrors(validationErrors: ValidationError[], parentPath?: string): Record<string, string[]>;
|
package/pipes/validation.pipe.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import { __decorate, __metadata, __param } from "tslib";
|
|
2
2
|
import { iterate } from 'iterare';
|
|
3
|
-
import { types } from 'util';
|
|
4
3
|
import { Injectable } from '../decorators/core/index.js';
|
|
5
4
|
import { Optional } from '../decorators/index.js';
|
|
6
5
|
import { HttpStatus } from '../enums/http-status.enum.js';
|
|
7
6
|
import { HttpErrorByCode, } from '../utils/http-error-by-code.util.js';
|
|
8
7
|
import { loadPackage } from '../utils/load-package.util.js';
|
|
9
8
|
import { isNil, isUndefined } from '../utils/shared.utils.js';
|
|
9
|
+
import { stripProtoKeys } from '../utils/strip-proto-keys.util.js';
|
|
10
10
|
let classValidator = {};
|
|
11
11
|
let classTransformer = {};
|
|
12
|
-
/**
|
|
13
|
-
* Built-in JavaScript types that should be excluded from prototype stripping
|
|
14
|
-
* to avoid conflicts with test frameworks like Jest's useFakeTimers
|
|
15
|
-
*/
|
|
16
|
-
const BUILT_IN_TYPES = [Date, RegExp, Error, Map, Set, WeakMap, WeakSet];
|
|
17
12
|
/**
|
|
18
13
|
* @see [Validation](https://docs.nestjs.com/techniques/validation)
|
|
19
14
|
*
|
|
@@ -187,37 +182,12 @@ let ValidationPipe = class ValidationPipe {
|
|
|
187
182
|
// @see [https://github.com/nestjs/nest/issues/12680](https://github.com/nestjs/nest/issues/12680)
|
|
188
183
|
return '';
|
|
189
184
|
}
|
|
190
|
-
stripProtoKeys(value) {
|
|
191
|
-
if (value == null ||
|
|
192
|
-
typeof value !== 'object' ||
|
|
193
|
-
types.isTypedArray(value)) {
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
// Skip built-in JavaScript primitives to avoid Jest useFakeTimers conflicts
|
|
197
|
-
if (BUILT_IN_TYPES.some(type => value instanceof type)) {
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
if (Array.isArray(value)) {
|
|
201
|
-
for (const v of value) {
|
|
202
|
-
this.stripProtoKeys(v);
|
|
203
|
-
}
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
// Delete dangerous prototype pollution keys
|
|
207
|
-
delete value.__proto__;
|
|
208
|
-
delete value.prototype;
|
|
209
|
-
// Only delete constructor if it's NOT a built-in type
|
|
210
|
-
const constructorType = value?.constructor;
|
|
211
|
-
if (constructorType && !BUILT_IN_TYPES.includes(constructorType)) {
|
|
212
|
-
delete value.constructor;
|
|
213
|
-
}
|
|
214
|
-
for (const key in value) {
|
|
215
|
-
this.stripProtoKeys(value[key]);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
185
|
isPrimitive(value) {
|
|
219
186
|
return ['number', 'boolean', 'string'].includes(typeof value);
|
|
220
187
|
}
|
|
188
|
+
stripProtoKeys(value) {
|
|
189
|
+
stripProtoKeys(value);
|
|
190
|
+
}
|
|
221
191
|
validate(object, validatorOptions) {
|
|
222
192
|
return classValidator.validate(object, validatorOptions);
|
|
223
193
|
}
|
package/utils/index.d.ts
CHANGED
package/utils/index.js
CHANGED
package/utils/shared.utils.js
CHANGED
|
@@ -8,7 +8,7 @@ export const isPlainObject = (fn) => {
|
|
|
8
8
|
if (proto === null) {
|
|
9
9
|
return true;
|
|
10
10
|
}
|
|
11
|
-
const ctor = Object.
|
|
11
|
+
const ctor = Object.hasOwn(proto, 'constructor') &&
|
|
12
12
|
proto.constructor;
|
|
13
13
|
return (typeof ctor === 'function' &&
|
|
14
14
|
ctor instanceof ctor &&
|
|
@@ -20,11 +20,7 @@ export const addLeadingSlash = (path) => path && typeof path === 'string'
|
|
|
20
20
|
? '/' + path
|
|
21
21
|
: path
|
|
22
22
|
: '';
|
|
23
|
-
export const normalizePath = (path) => path
|
|
24
|
-
? path.startsWith('/')
|
|
25
|
-
? ('/' + path.replace(/\/+$/, '')).replace(/\/+/g, '/')
|
|
26
|
-
: '/' + path.replace(/\/+$/, '')
|
|
27
|
-
: '/';
|
|
23
|
+
export const normalizePath = (path) => path ? ('/' + path.replace(/\/+$/, '')).replace(/\/+/g, '/') : '/';
|
|
28
24
|
export const stripEndSlash = (path) => path.endsWith('/') ? path.slice(0, -1) : path;
|
|
29
25
|
export const isFunction = (val) => typeof val === 'function';
|
|
30
26
|
export const isString = (val) => typeof val === 'string';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { types } from 'util';
|
|
2
|
+
/**
|
|
3
|
+
* Built-in JavaScript types that should be excluded from prototype stripping
|
|
4
|
+
* to avoid conflicts with test frameworks like Jest's useFakeTimers
|
|
5
|
+
*/
|
|
6
|
+
const BUILT_IN_TYPES = [Date, RegExp, Error, Map, Set, WeakMap, WeakSet];
|
|
7
|
+
/**
|
|
8
|
+
* Strips dangerous prototype pollution keys (__proto__, prototype, constructor)
|
|
9
|
+
* from an object recursively.
|
|
10
|
+
*/
|
|
11
|
+
export function stripProtoKeys(value) {
|
|
12
|
+
if (value == null || typeof value !== 'object' || types.isTypedArray(value)) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
// Skip built-in JavaScript primitives to avoid Jest useFakeTimers conflicts
|
|
16
|
+
if (BUILT_IN_TYPES.some(type => value instanceof type)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (Array.isArray(value)) {
|
|
20
|
+
for (const v of value) {
|
|
21
|
+
stripProtoKeys(v);
|
|
22
|
+
}
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
// Delete dangerous prototype pollution keys
|
|
26
|
+
delete value.__proto__;
|
|
27
|
+
delete value.prototype;
|
|
28
|
+
// Only delete constructor if it's NOT a built-in type
|
|
29
|
+
const constructorType = value?.constructor;
|
|
30
|
+
if (constructorType && !BUILT_IN_TYPES.includes(constructorType)) {
|
|
31
|
+
delete value.constructor;
|
|
32
|
+
}
|
|
33
|
+
for (const key in value) {
|
|
34
|
+
stripProtoKeys(value[key]);
|
|
35
|
+
}
|
|
36
|
+
}
|