@nestjs/platform-express 12.1.2 → 12.1.3
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.
|
@@ -5,7 +5,7 @@ import * as http from 'http';
|
|
|
5
5
|
import * as https from 'https';
|
|
6
6
|
import { NestExpressBodyParserOptionsFor, NestExpressBodyParserType } from '../interfaces/nest-express-body-parser.interface.js';
|
|
7
7
|
import { ServeStaticOptions } from '../interfaces/serve-static-options.interface.js';
|
|
8
|
-
import { type CorsOptions, type CorsOptionsDelegate, type VersionValue } from '@nestjs/common/internal';
|
|
8
|
+
import { type CorsOptions, type CorsOptionsDelegate, type RouteInfo, type VersionValue } from '@nestjs/common/internal';
|
|
9
9
|
import type { NestApplicationOptions } from '@nestjs/common';
|
|
10
10
|
import { AbstractHttpAdapter } from '@nestjs/core';
|
|
11
11
|
type VersionedRoute = <TRequest extends Record<string, any> = any, TResponse = any>(req: TRequest, res: TResponse, next: () => void) => any;
|
|
@@ -21,7 +21,18 @@ export declare class ExpressAdapter extends AbstractHttpAdapter<http.Server | ht
|
|
|
21
21
|
private onRequestHook?;
|
|
22
22
|
private onResponseHook?;
|
|
23
23
|
constructor(instance?: any);
|
|
24
|
-
|
|
24
|
+
private runRequestHook;
|
|
25
|
+
/**
|
|
26
|
+
* Registers a request hook. Call `done()` to continue processing the request;
|
|
27
|
+
* resolving the returned promise does not continue it. Only the first
|
|
28
|
+
* completion is forwarded to Express. Errors after `done()` are logged
|
|
29
|
+
* without advancing the request again.
|
|
30
|
+
*/
|
|
31
|
+
setOnRequestHook(onRequestHook: (req: express.Request, res: express.Response, done: (err?: Error) => void) => Promise<void> | void): void;
|
|
32
|
+
/**
|
|
33
|
+
* Registers a hook to run after the response has been sent.
|
|
34
|
+
* Thrown errors and rejected promises are logged.
|
|
35
|
+
*/
|
|
25
36
|
setOnResponseHook(onResponseHook: (req: express.Request, res: express.Response) => Promise<void> | void): void;
|
|
26
37
|
reply(response: any, body: any, statusCode?: number): any;
|
|
27
38
|
status(response: any, statusCode: number): any;
|
|
@@ -29,7 +40,7 @@ export declare class ExpressAdapter extends AbstractHttpAdapter<http.Server | ht
|
|
|
29
40
|
render(response: any, view: string, options: any): any;
|
|
30
41
|
redirect(response: any, statusCode: number, url: string): any;
|
|
31
42
|
setErrorHandler(handler: Function, prefix?: string): any;
|
|
32
|
-
setNotFoundHandler(handler: Function, prefix?: string): any;
|
|
43
|
+
setNotFoundHandler(handler: Function, prefix?: string, excludedRoutes?: RouteInfo[]): any;
|
|
33
44
|
isHeadersSent(response: any): boolean;
|
|
34
45
|
getHeader(response: any, name: string): any;
|
|
35
46
|
setHeader(response: any, name: string, value: string): any;
|
|
@@ -4,6 +4,7 @@ import express from 'express';
|
|
|
4
4
|
import * as http from 'http';
|
|
5
5
|
import * as https from 'https';
|
|
6
6
|
import { pathToRegexp } from 'path-to-regexp';
|
|
7
|
+
import { finished } from 'stream';
|
|
7
8
|
import { getBodyParserOptions } from './utils/get-body-parser-options.util.js';
|
|
8
9
|
import { getMediaTypeVersion } from './utils/get-media-type-version.util.js';
|
|
9
10
|
import { addLeadingSlash, isFunction, isNil, isObject, isString, isUndefined, stripEndSlash, } from '@nestjs/common/internal';
|
|
@@ -30,21 +31,59 @@ export class ExpressAdapter extends AbstractHttpAdapter {
|
|
|
30
31
|
super(instance || express());
|
|
31
32
|
this.instance.use((req, res, next) => {
|
|
32
33
|
if (this.onResponseHook) {
|
|
33
|
-
res.on('finish', () => {
|
|
34
|
-
|
|
34
|
+
res.on('finish', async () => {
|
|
35
|
+
try {
|
|
36
|
+
await this.onResponseHook.apply(this, [req, res]);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
this.logger.error(err);
|
|
40
|
+
}
|
|
35
41
|
});
|
|
36
42
|
}
|
|
37
43
|
if (this.onRequestHook) {
|
|
38
|
-
|
|
44
|
+
this.runRequestHook(req, res, next);
|
|
39
45
|
}
|
|
40
46
|
else {
|
|
41
47
|
next();
|
|
42
48
|
}
|
|
43
49
|
});
|
|
44
50
|
}
|
|
51
|
+
runRequestHook(req, res, next) {
|
|
52
|
+
let completed = false;
|
|
53
|
+
const doneOnce = (err) => {
|
|
54
|
+
if (completed) {
|
|
55
|
+
if (err) {
|
|
56
|
+
this.logger.error(err);
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
completed = true;
|
|
61
|
+
next(err);
|
|
62
|
+
};
|
|
63
|
+
try {
|
|
64
|
+
// Not returned to Express: rejections share the once-guard with done()
|
|
65
|
+
const result = this.onRequestHook.call(this, req, res, doneOnce);
|
|
66
|
+
if (result && typeof result.then === 'function') {
|
|
67
|
+
result.then(undefined, err => doneOnce(err || new Error('Request hook failed')));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
doneOnce(err || new Error('Request hook failed'));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Registers a request hook. Call `done()` to continue processing the request;
|
|
76
|
+
* resolving the returned promise does not continue it. Only the first
|
|
77
|
+
* completion is forwarded to Express. Errors after `done()` are logged
|
|
78
|
+
* without advancing the request again.
|
|
79
|
+
*/
|
|
45
80
|
setOnRequestHook(onRequestHook) {
|
|
46
81
|
this.onRequestHook = onRequestHook;
|
|
47
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Registers a hook to run after the response has been sent.
|
|
85
|
+
* Thrown errors and rejected promises are logged.
|
|
86
|
+
*/
|
|
48
87
|
setOnResponseHook(onResponseHook) {
|
|
49
88
|
this.onResponseHook = onResponseHook;
|
|
50
89
|
}
|
|
@@ -61,6 +100,13 @@ export class ExpressAdapter extends AbstractHttpAdapter {
|
|
|
61
100
|
stream.once('error', err => {
|
|
62
101
|
body.errorHandler(err, response);
|
|
63
102
|
});
|
|
103
|
+
// pipe() leaves the source open when the client disconnects early,
|
|
104
|
+
// also before reply() runs ("close" has already fired by then)
|
|
105
|
+
finished(response, () => {
|
|
106
|
+
if (!stream.readableEnded) {
|
|
107
|
+
stream.destroy();
|
|
108
|
+
}
|
|
109
|
+
});
|
|
64
110
|
return stream
|
|
65
111
|
.pipe(response)
|
|
66
112
|
.on('error', (err) => body.errorLogger(err));
|
|
@@ -98,13 +144,23 @@ export class ExpressAdapter extends AbstractHttpAdapter {
|
|
|
98
144
|
// root-mounted routes) still pass through the exception layer.
|
|
99
145
|
return this.use(handler);
|
|
100
146
|
}
|
|
101
|
-
setNotFoundHandler(handler, prefix) {
|
|
147
|
+
setNotFoundHandler(handler, prefix, excludedRoutes) {
|
|
102
148
|
const normalizedPrefix = this.normalizePrefix(prefix);
|
|
103
149
|
if (normalizedPrefix) {
|
|
104
150
|
this.registeredPrefixes.add(normalizedPrefix);
|
|
105
151
|
const router = express.Router();
|
|
106
152
|
router.all('*path', handler);
|
|
107
|
-
|
|
153
|
+
this.use(normalizedPrefix, router);
|
|
154
|
+
// Excluded routes live at the root, out of the prefix router's reach.
|
|
155
|
+
// Mount the handler on each exact path, for every method, so a method
|
|
156
|
+
// miss there (`POST /hello` with only `GET /hello`) still reaches the
|
|
157
|
+
// exception layer. Not `use(path, router)`: a subtree mount would claim
|
|
158
|
+
// a raw `/hello/live` added after `init()`; a wildcard exclusion covers
|
|
159
|
+
// its subtree through its own pattern.
|
|
160
|
+
for (const route of excludedRoutes ?? []) {
|
|
161
|
+
this.instance.all(addLeadingSlash(route.path), handler);
|
|
162
|
+
}
|
|
163
|
+
return;
|
|
108
164
|
}
|
|
109
165
|
return this.use((req, res, next) => {
|
|
110
166
|
// When multiple apps share this adapter, a non-prefixed app's 404
|
|
@@ -202,10 +258,22 @@ export class ExpressAdapter extends AbstractHttpAdapter {
|
|
|
202
258
|
createMiddlewareFactory(requestMethod) {
|
|
203
259
|
return (path, callback) => {
|
|
204
260
|
try {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
261
|
+
// The core marks an exact-match path with a trailing "$" (e.g. "/api$").
|
|
262
|
+
// Express 5 reads "$" literally and "use()" matches by prefix, so strip
|
|
263
|
+
// the marker and register the path as an exact "all()" route instead.
|
|
264
|
+
const isExactPath = path.endsWith('$');
|
|
265
|
+
const convertedPath = LegacyRouteConverter.tryConvert(isExactPath ? path.slice(0, -1) : path);
|
|
266
|
+
let router = this.routerMethodFactory.get(this.instance, requestMethod);
|
|
267
|
+
if (isExactPath && router === this.instance.use) {
|
|
268
|
+
router = this.instance.all;
|
|
269
|
+
}
|
|
270
|
+
// Express routes are not strict, so "/api" also matches "/api/". That
|
|
271
|
+
// path is left to the wildcard entry registered next to it (an optional
|
|
272
|
+
// "{*path}" matches it), so the middleware doesn't run twice.
|
|
273
|
+
const handler = isExactPath
|
|
274
|
+
? (req, res, next) => req.path.endsWith('/') ? next() : callback(req, res, next)
|
|
275
|
+
: callback;
|
|
276
|
+
return router.call(this.instance, convertedPath, handler);
|
|
209
277
|
}
|
|
210
278
|
catch (e) {
|
|
211
279
|
if (e instanceof TypeError) {
|
|
@@ -16,6 +16,10 @@ export interface MulterLimits {
|
|
|
16
16
|
parts?: number;
|
|
17
17
|
/** For multipart forms, the max number of header key=> value pairs to parse Default: 2000(same as node's http). */
|
|
18
18
|
headerPairs?: number;
|
|
19
|
+
/** Max nesting depth of field names; `a[b][c]` has 2 levels (Default: Infinity) */
|
|
20
|
+
fieldNestingDepth?: number;
|
|
21
|
+
/** Max numeric array index accepted in field names; `a[3]` uses index 3 (Default: Infinity) */
|
|
22
|
+
fieldArrayIndexLimit?: number;
|
|
19
23
|
}
|
|
20
24
|
/**
|
|
21
25
|
* @see https://github.com/expressjs/multer
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nestjs/platform-express",
|
|
3
|
-
"version": "12.1.
|
|
3
|
+
"version": "12.1.3",
|
|
4
4
|
"description": "Nest - modern, fast, powerful node.js web framework (@platform-express)",
|
|
5
5
|
"author": "Kamil Mysliwiec",
|
|
6
6
|
"license": "MIT",
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
"tslib": "2.8.1"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@nestjs/common": "12.1.
|
|
36
|
-
"@nestjs/core": "12.1.
|
|
35
|
+
"@nestjs/common": "12.1.3",
|
|
36
|
+
"@nestjs/core": "12.1.3"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@nestjs/common": "^12.0.0",
|
|
40
40
|
"@nestjs/core": "^12.0.0"
|
|
41
41
|
},
|
|
42
|
-
"gitHead": "
|
|
42
|
+
"gitHead": "4514623279f6087808e3c8f08fbf9f37d3c17482"
|
|
43
43
|
}
|