@depup/nestjs__common 12.0.1-depup.1 → 12.0.2-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.
Files changed (40) hide show
  1. package/README.md +2 -2
  2. package/changes.json +1 -1
  3. package/decorators/modules/module.decorator.js +1 -1
  4. package/exceptions/bad-gateway.exception.js +1 -1
  5. package/exceptions/bad-request.exception.js +1 -1
  6. package/exceptions/conflict.exception.js +1 -1
  7. package/exceptions/forbidden.exception.js +1 -1
  8. package/exceptions/gateway-timeout.exception.js +1 -1
  9. package/exceptions/gone.exception.js +1 -1
  10. package/exceptions/http-version-not-supported.exception.js +1 -1
  11. package/exceptions/im-a-teapot.exception.js +1 -1
  12. package/exceptions/internal-server-error.exception.js +1 -1
  13. package/exceptions/method-not-allowed.exception.js +1 -1
  14. package/exceptions/misdirected.exception.js +1 -1
  15. package/exceptions/not-acceptable.exception.js +1 -1
  16. package/exceptions/not-found.exception.js +1 -1
  17. package/exceptions/not-implemented.exception.js +1 -1
  18. package/exceptions/payload-too-large.exception.js +1 -1
  19. package/exceptions/precondition-failed.exception.js +1 -1
  20. package/exceptions/request-timeout.exception.js +1 -1
  21. package/exceptions/service-unavailable.exception.js +1 -1
  22. package/exceptions/unauthorized.exception.js +1 -1
  23. package/exceptions/unprocessable-entity.exception.js +1 -1
  24. package/exceptions/unsupported-media-type.exception.js +1 -1
  25. package/interfaces/http/http-server.interface.d.ts +504 -0
  26. package/package.json +4 -4
  27. package/pipes/file/parse-file.pipe.js +2 -2
  28. package/pipes/parse-array.pipe.js +1 -1
  29. package/pipes/parse-enum.pipe.d.ts +9 -0
  30. package/pipes/parse-enum.pipe.js +22 -3
  31. package/pipes/parse-uuid.pipe.js +1 -1
  32. package/pipes/standard-schema-validation.pipe.d.ts +0 -3
  33. package/pipes/standard-schema-validation.pipe.js +8 -34
  34. package/pipes/validation.pipe.d.ts +1 -1
  35. package/pipes/validation.pipe.js +5 -35
  36. package/utils/index.d.ts +1 -0
  37. package/utils/index.js +1 -0
  38. package/utils/shared.utils.js +2 -6
  39. package/utils/strip-proto-keys.util.d.ts +5 -0
  40. package/utils/strip-proto-keys.util.js +36 -0
package/README.md CHANGED
@@ -13,8 +13,8 @@ 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.1 |
17
- | Processed | 2026-09-11 |
16
+ | Original | [@nestjs/common](https://www.npmjs.com/package/@nestjs/common) @ 12.0.2 |
17
+ | Processed | 2026-09-14 |
18
18
  | Smoke test | passed |
19
19
  | Deps updated | 1 |
20
20
 
package/changes.json CHANGED
@@ -5,6 +5,6 @@
5
5
  "to": "^22.1.0"
6
6
  }
7
7
  },
8
- "timestamp": "2026-09-11T16:09:53.836Z",
8
+ "timestamp": "2026-09-14T16:09:21.200Z",
9
9
  "totalUpdated": 1
10
10
  }
@@ -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.hasOwnProperty.call(metadata, property)) {
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.1-depup.1",
3
+ "version": "12.0.2-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",
@@ -44,7 +44,7 @@
44
44
  "optional": true
45
45
  }
46
46
  },
47
- "gitHead": "4c751c503bc753095f4b4f052e106f95218cc33f",
47
+ "gitHead": "ee168a569d30e600d301ed38abb14d2171a6f315",
48
48
  "keywords": [
49
49
  "@nestjs/common",
50
50
  "depup",
@@ -62,8 +62,8 @@
62
62
  },
63
63
  "depsUpdated": 1,
64
64
  "originalPackage": "@nestjs/common",
65
- "originalVersion": "12.0.1",
66
- "processedAt": "2026-09-11T16:09:57.020Z",
65
+ "originalVersion": "12.0.2",
66
+ "processedAt": "2026-09-14T16:09:24.325Z",
67
67
  "smokeTest": "passed"
68
68
  }
69
69
  }
@@ -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, isObject, isUndefined, } from '../../utils/shared.utils.js';
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 isUndefined(value) || isEmptyArray(value) || isEmptyObject;
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 (!value && !this.options.optional) {
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
  }
@@ -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
- const enumValues = Object.keys(this.enumType)
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([
@@ -16,7 +16,7 @@ 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]{4}-[0-9A-F]{12}$/i,
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,
@@ -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
- * Built-in JavaScript types that should be excluded from prototype stripping
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
- return `${issue.path.map(String).join('.')}: ${issue.message}`;
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
  });
@@ -62,7 +61,7 @@ let StandardSchemaValidationPipe = class StandardSchemaValidationPipe {
62
61
  if (!schema || !this.toValidate(metadata)) {
63
62
  return value;
64
63
  }
65
- this.stripProtoKeys(value);
64
+ stripProtoKeys(value);
66
65
  const result = await this.validate(value, schema, this.validateOptions);
67
66
  if (result.issues) {
68
67
  throw this.exceptionFactory(result.issues);
@@ -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
- if (value == null ||
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[]>;
@@ -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
  *
@@ -69,7 +64,7 @@ let ValidationPipe = class ValidationPipe {
69
64
  value = this.toEmptyIfNil(value, metatype);
70
65
  const isNil = value !== originalValue;
71
66
  const isPrimitive = this.isPrimitive(value);
72
- this.stripProtoKeys(value);
67
+ stripProtoKeys(value);
73
68
  let entity = classTransformer.plainToInstance(metatype, value, this.transformOptions);
74
69
  const originalEntity = entity;
75
70
  const isCtorNotEqual = entity.constructor !== metatype;
@@ -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
@@ -1 +1,2 @@
1
1
  export * from './forward-ref.util.js';
2
+ export * from './strip-proto-keys.util.js';
package/utils/index.js CHANGED
@@ -1 +1,2 @@
1
1
  export * from './forward-ref.util.js';
2
+ export * from './strip-proto-keys.util.js';
@@ -8,7 +8,7 @@ export const isPlainObject = (fn) => {
8
8
  if (proto === null) {
9
9
  return true;
10
10
  }
11
- const ctor = Object.prototype.hasOwnProperty.call(proto, 'constructor') &&
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,5 @@
1
+ /**
2
+ * Strips dangerous prototype pollution keys (__proto__, prototype, constructor)
3
+ * from an object recursively.
4
+ */
5
+ export declare function stripProtoKeys(value: any): void;
@@ -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
+ }