@nestjs/core 11.1.9 → 11.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/injector/abstract-instance-resolver.js +1 -1
- package/injector/instance-wrapper.js +20 -5
- package/nest-application-context.d.ts +5 -3
- package/nest-application-context.js +14 -4
- package/package.json +4 -3
- package/router/router-execution-context.js +2 -2
- package/router/router-response-controller.d.ts +2 -2
- package/router/router-response-controller.js +10 -4
- package/router/sse-stream.d.ts +1 -0
- package/router/sse-stream.js +2 -1
|
@@ -31,7 +31,7 @@ class AbstractInstanceResolver {
|
|
|
31
31
|
const pluckInstance = async (instanceLink) => {
|
|
32
32
|
const { wrapperRef, collection } = instanceLink;
|
|
33
33
|
if (wrapperRef.isDependencyTreeStatic() && !wrapperRef.isTransient) {
|
|
34
|
-
return
|
|
34
|
+
return wrapperRef.instance;
|
|
35
35
|
}
|
|
36
36
|
const ctorHost = wrapperRef.instance || { constructor: typeOrToken };
|
|
37
37
|
const instance = await this.injector.loadPerContext(ctorHost, wrapperRef.host, collection, contextId, wrapperRef);
|
|
@@ -240,14 +240,29 @@ class InstanceWrapper {
|
|
|
240
240
|
(isSelfRequested || !!(inquirer && inquirer.scope === common_1.Scope.TRANSIENT)));
|
|
241
241
|
}
|
|
242
242
|
isStatic(contextId, inquirer) {
|
|
243
|
+
if (!this.isDependencyTreeStatic() || contextId !== constants_1.STATIC_CONTEXT) {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
// Non-transient provider in static context
|
|
247
|
+
if (!this.isTransient) {
|
|
248
|
+
return true;
|
|
249
|
+
}
|
|
243
250
|
const isInquirerRequestScoped = inquirer && !inquirer.isDependencyTreeStatic();
|
|
244
251
|
const isStaticTransient = this.isTransient && !isInquirerRequestScoped;
|
|
245
252
|
const rootInquirer = inquirer?.getRootInquirer();
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
253
|
+
// Transient provider inquired by non-transient (e.g., DEFAULT -> TRANSIENT)
|
|
254
|
+
if (isStaticTransient && inquirer && !inquirer.isTransient) {
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
// Nested transient with non-transient root (e.g., DEFAULT -> TRANSIENT -> TRANSIENT)
|
|
258
|
+
if (isStaticTransient && rootInquirer && !rootInquirer.isTransient) {
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
// Nested transient during initial instantiation (rootInquirer not yet set)
|
|
262
|
+
if (isStaticTransient && inquirer?.isTransient && !rootInquirer) {
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
return false;
|
|
251
266
|
}
|
|
252
267
|
attachRootInquirer(inquirer) {
|
|
253
268
|
if (!this.isTransient) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { INestApplicationContext, Logger, LoggerService, LogLevel, ShutdownSignal } from '@nestjs/common';
|
|
2
|
-
import { DynamicModule, SelectOptions, Type } from '@nestjs/common/interfaces';
|
|
2
|
+
import { DynamicModule, SelectOptions, ShutdownHooksOptions, Type } from '@nestjs/common/interfaces';
|
|
3
3
|
import { NestApplicationContextOptions } from '@nestjs/common/interfaces/nest-application-context-options.interface';
|
|
4
4
|
import { AbstractInstanceResolver } from './injector/abstract-instance-resolver';
|
|
5
5
|
import { NestContainer } from './injector/container';
|
|
@@ -124,18 +124,20 @@ export declare class NestApplicationContext<TOptions extends NestApplicationCont
|
|
|
124
124
|
* process receives a shutdown signal.
|
|
125
125
|
*
|
|
126
126
|
* @param {ShutdownSignal[]} [signals=[]] The system signals it should listen to
|
|
127
|
+
* @param {ShutdownHooksOptions} [options={}] Options for configuring shutdown hooks behavior
|
|
127
128
|
*
|
|
128
129
|
* @returns {this} The Nest application context instance
|
|
129
130
|
*/
|
|
130
|
-
enableShutdownHooks(signals?: (ShutdownSignal | string)[]): this;
|
|
131
|
+
enableShutdownHooks(signals?: (ShutdownSignal | string)[], options?: ShutdownHooksOptions): this;
|
|
131
132
|
protected dispose(): Promise<void>;
|
|
132
133
|
/**
|
|
133
134
|
* Listens to shutdown signals by listening to
|
|
134
135
|
* process events
|
|
135
136
|
*
|
|
136
137
|
* @param {string[]} signals The system signals it should listen to
|
|
138
|
+
* @param {ShutdownHooksOptions} options Options for configuring shutdown hooks behavior
|
|
137
139
|
*/
|
|
138
|
-
protected listenToShutdownSignals(signals: string[]): void;
|
|
140
|
+
protected listenToShutdownSignals(signals: string[], options?: ShutdownHooksOptions): void;
|
|
139
141
|
/**
|
|
140
142
|
* Unsubscribes from shutdown signals (process events)
|
|
141
143
|
*/
|
|
@@ -161,10 +161,11 @@ class NestApplicationContext extends abstract_instance_resolver_1.AbstractInstan
|
|
|
161
161
|
* process receives a shutdown signal.
|
|
162
162
|
*
|
|
163
163
|
* @param {ShutdownSignal[]} [signals=[]] The system signals it should listen to
|
|
164
|
+
* @param {ShutdownHooksOptions} [options={}] Options for configuring shutdown hooks behavior
|
|
164
165
|
*
|
|
165
166
|
* @returns {this} The Nest application context instance
|
|
166
167
|
*/
|
|
167
|
-
enableShutdownHooks(signals = []) {
|
|
168
|
+
enableShutdownHooks(signals = [], options = {}) {
|
|
168
169
|
if ((0, shared_utils_1.isEmpty)(signals)) {
|
|
169
170
|
signals = Object.keys(common_1.ShutdownSignal).map((key) => common_1.ShutdownSignal[key]);
|
|
170
171
|
}
|
|
@@ -178,7 +179,7 @@ class NestApplicationContext extends abstract_instance_resolver_1.AbstractInstan
|
|
|
178
179
|
// filter out the signals which is already listening to
|
|
179
180
|
.filter(signal => !this.activeShutdownSignals.includes(signal))
|
|
180
181
|
.toArray();
|
|
181
|
-
this.listenToShutdownSignals(signals);
|
|
182
|
+
this.listenToShutdownSignals(signals, options);
|
|
182
183
|
return this;
|
|
183
184
|
}
|
|
184
185
|
async dispose() {
|
|
@@ -191,8 +192,9 @@ class NestApplicationContext extends abstract_instance_resolver_1.AbstractInstan
|
|
|
191
192
|
* process events
|
|
192
193
|
*
|
|
193
194
|
* @param {string[]} signals The system signals it should listen to
|
|
195
|
+
* @param {ShutdownHooksOptions} options Options for configuring shutdown hooks behavior
|
|
194
196
|
*/
|
|
195
|
-
listenToShutdownSignals(signals) {
|
|
197
|
+
listenToShutdownSignals(signals, options = {}) {
|
|
196
198
|
let receivedSignal = false;
|
|
197
199
|
const cleanup = async (signal) => {
|
|
198
200
|
try {
|
|
@@ -208,7 +210,15 @@ class NestApplicationContext extends abstract_instance_resolver_1.AbstractInstan
|
|
|
208
210
|
await this.dispose();
|
|
209
211
|
await this.callShutdownHook(signal);
|
|
210
212
|
signals.forEach(sig => process.removeListener(sig, cleanup));
|
|
211
|
-
|
|
213
|
+
if (options.useProcessExit) {
|
|
214
|
+
// Use process.exit() to ensure the 'exit' event is properly triggered.
|
|
215
|
+
// This is required for async loggers (like Pino with transports)
|
|
216
|
+
// to flush their buffers before the process terminates.
|
|
217
|
+
process.exit(0);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
process.kill(process.pid, signal);
|
|
221
|
+
}
|
|
212
222
|
}
|
|
213
223
|
catch (err) {
|
|
214
224
|
common_1.Logger.error(constants_1.MESSAGES.ERROR_DURING_SHUTDOWN, err?.stack, NestApplicationContext.name);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nestjs/core",
|
|
3
|
-
"version": "11.1.
|
|
3
|
+
"version": "11.1.10",
|
|
4
4
|
"description": "Nest - modern, fast, powerful node.js web framework (@core)",
|
|
5
5
|
"author": "Kamil Mysliwiec",
|
|
6
6
|
"license": "MIT",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"uid": "2.0.2"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@nestjs/common": "11.1.
|
|
42
|
+
"@nestjs/common": "11.1.10"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@nestjs/common": "^11.0.0",
|
|
@@ -59,5 +59,6 @@
|
|
|
59
59
|
"@nestjs/platform-express": {
|
|
60
60
|
"optional": true
|
|
61
61
|
}
|
|
62
|
-
}
|
|
62
|
+
},
|
|
63
|
+
"gitHead": "8ea5aaef561c87065bf0b358771de8c8b62e7835"
|
|
63
64
|
}
|
|
@@ -166,8 +166,8 @@ class RouterExecutionContext {
|
|
|
166
166
|
}
|
|
167
167
|
const isSseHandler = !!this.reflectSse(callback);
|
|
168
168
|
if (isSseHandler) {
|
|
169
|
-
return (result, res, req) => {
|
|
170
|
-
this.responseController.sse(result, res.raw || res, req.raw || req, { additionalHeaders: res.getHeaders?.() });
|
|
169
|
+
return async (result, res, req) => {
|
|
170
|
+
await this.responseController.sse(result, res.raw || res, req.raw || req, { additionalHeaders: res.getHeaders?.() });
|
|
171
171
|
};
|
|
172
172
|
}
|
|
173
173
|
return async (result, res) => {
|
|
@@ -21,8 +21,8 @@ export declare class RouterResponseController {
|
|
|
21
21
|
getStatusByMethod(requestMethod: RequestMethod): number;
|
|
22
22
|
setHeaders<TResponse = unknown>(response: TResponse, headers: CustomHeader[]): void;
|
|
23
23
|
setStatus<TResponse = unknown>(response: TResponse, statusCode: number): void;
|
|
24
|
-
sse<TInput extends Observable<unknown> = any, TResponse extends WritableHeaderStream = any, TRequest extends IncomingMessage = any>(result: TInput
|
|
24
|
+
sse<TInput extends Observable<unknown> = any, TResponse extends WritableHeaderStream = any, TRequest extends IncomingMessage = any>(result: TInput | Promise<TInput>, response: TResponse, request: TRequest, options?: {
|
|
25
25
|
additionalHeaders: AdditionalHeaders;
|
|
26
|
-
}): void
|
|
26
|
+
}): Promise<void>;
|
|
27
27
|
private assertObservable;
|
|
28
28
|
}
|
|
@@ -48,15 +48,21 @@ class RouterResponseController {
|
|
|
48
48
|
setStatus(response, statusCode) {
|
|
49
49
|
this.applicationRef.status(response, statusCode);
|
|
50
50
|
}
|
|
51
|
-
sse(result, response, request, options) {
|
|
51
|
+
async sse(result, response, request, options) {
|
|
52
52
|
// It's possible that we sent headers already so don't use a stream
|
|
53
53
|
if (response.writableEnded) {
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
|
-
|
|
56
|
+
const observableResult = await Promise.resolve(result);
|
|
57
|
+
this.assertObservable(observableResult);
|
|
57
58
|
const stream = new sse_stream_1.SseStream(request);
|
|
58
|
-
|
|
59
|
-
const
|
|
59
|
+
// Extract custom status code from response if it was set
|
|
60
|
+
const customStatusCode = response.statusCode;
|
|
61
|
+
const pipeOptions = typeof customStatusCode !== 'undefined'
|
|
62
|
+
? { ...options, statusCode: customStatusCode }
|
|
63
|
+
: options;
|
|
64
|
+
stream.pipe(response, pipeOptions);
|
|
65
|
+
const subscription = observableResult
|
|
60
66
|
.pipe((0, operators_1.map)((message) => {
|
|
61
67
|
if ((0, shared_utils_1.isObject)(message)) {
|
|
62
68
|
return message;
|
package/router/sse-stream.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export declare class SseStream extends Transform {
|
|
|
31
31
|
constructor(req?: IncomingMessage);
|
|
32
32
|
pipe<T extends WritableHeaderStream>(destination: T, options?: {
|
|
33
33
|
additionalHeaders?: AdditionalHeaders;
|
|
34
|
+
statusCode?: number;
|
|
34
35
|
end?: boolean;
|
|
35
36
|
}): T;
|
|
36
37
|
_transform(message: MessageEvent, encoding: string, callback: (error?: Error | null, data?: any) => void): void;
|
package/router/sse-stream.js
CHANGED
|
@@ -37,7 +37,8 @@ class SseStream extends stream_1.Transform {
|
|
|
37
37
|
}
|
|
38
38
|
pipe(destination, options) {
|
|
39
39
|
if (destination.writeHead) {
|
|
40
|
-
|
|
40
|
+
const statusCode = options?.statusCode ?? 200;
|
|
41
|
+
destination.writeHead(statusCode, {
|
|
41
42
|
...options?.additionalHeaders,
|
|
42
43
|
// See https://github.com/dunglas/mercure/blob/master/hub/subscribe.go#L124-L130
|
|
43
44
|
'Content-Type': 'text/event-stream',
|