@nestjs/core 12.0.0-alpha.6 → 12.0.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/helpers/safe-instance-decorator.d.ts +10 -0
- package/helpers/safe-instance-decorator.js +20 -0
- package/injector/injector.js +14 -2
- package/injector/module.js +4 -1
- package/internal.d.ts +10 -6
- package/internal.js +10 -6
- package/nest-application.js +18 -10
- package/package.json +3 -3
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type InstanceDecorator = (target: unknown) => unknown;
|
|
2
|
+
/**
|
|
3
|
+
* Wraps an `instrument.instanceDecorator` so that a decorator throwing on a
|
|
4
|
+
* given instance (e.g. when inspecting a Proxy whose traps throw outside of
|
|
5
|
+
* their intended context, such as `nestjs-cls` proxy providers) does not
|
|
6
|
+
* crash the application bootstrap. The original, undecorated instance is
|
|
7
|
+
* used instead and a warning is logged.
|
|
8
|
+
*/
|
|
9
|
+
export declare function makeSafeInstanceDecorator(decorator: InstanceDecorator): InstanceDecorator;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Logger } from '@nestjs/common';
|
|
2
|
+
const logger = new Logger('InstrumentLogger');
|
|
3
|
+
/**
|
|
4
|
+
* Wraps an `instrument.instanceDecorator` so that a decorator throwing on a
|
|
5
|
+
* given instance (e.g. when inspecting a Proxy whose traps throw outside of
|
|
6
|
+
* their intended context, such as `nestjs-cls` proxy providers) does not
|
|
7
|
+
* crash the application bootstrap. The original, undecorated instance is
|
|
8
|
+
* used instead and a warning is logged.
|
|
9
|
+
*/
|
|
10
|
+
export function makeSafeInstanceDecorator(decorator) {
|
|
11
|
+
return (target) => {
|
|
12
|
+
try {
|
|
13
|
+
return decorator(target);
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
logger.warn(`The "instanceDecorator" function threw an error while decorating an instance (${err?.message ?? err}). The undecorated instance will be used instead.`);
|
|
17
|
+
return target;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
package/injector/injector.js
CHANGED
|
@@ -7,6 +7,7 @@ import { RuntimeException } from '../errors/exceptions/runtime.exception.js';
|
|
|
7
7
|
import { UndefinedDependencyException } from '../errors/exceptions/undefined-dependency.exception.js';
|
|
8
8
|
import { UnknownDependenciesException } from '../errors/exceptions/unknown-dependencies.exception.js';
|
|
9
9
|
import { Barrier } from '../helpers/barrier.js';
|
|
10
|
+
import { makeSafeInstanceDecorator } from '../helpers/safe-instance-decorator.js';
|
|
10
11
|
import { STATIC_CONTEXT } from './constants.js';
|
|
11
12
|
import { INQUIRER } from './inquirer/index.js';
|
|
12
13
|
import { InstanceWrapper, } from './instance-wrapper.js';
|
|
@@ -18,7 +19,7 @@ export class Injector {
|
|
|
18
19
|
constructor(options) {
|
|
19
20
|
this.options = options;
|
|
20
21
|
if (options?.instanceDecorator) {
|
|
21
|
-
this.instanceDecorator = options.instanceDecorator;
|
|
22
|
+
this.instanceDecorator = makeSafeInstanceDecorator(options.instanceDecorator);
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
loadPrototype({ token }, collection, contextId = STATIC_CONTEXT) {
|
|
@@ -267,12 +268,23 @@ export class Injector {
|
|
|
267
268
|
* that eventual lazily created instance will be merged with the prototype
|
|
268
269
|
* instantiated beforehand.
|
|
269
270
|
*/
|
|
270
|
-
instanceHost.donePromise
|
|
271
|
+
if (instanceHost.donePromise) {
|
|
271
272
|
void instanceHost.donePromise
|
|
272
273
|
.then(() => this.loadProvider(instanceWrapper, moduleRef, resolutionContext))
|
|
273
274
|
.catch(err => {
|
|
274
275
|
instanceWrapper.settlementSignal?.error(err);
|
|
275
276
|
});
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
/**
|
|
280
|
+
* No load has ever been scheduled for this context (e.g., request-scoped
|
|
281
|
+
* providers are no longer instantiated during static bootstrap, so a fresh
|
|
282
|
+
* durable/request sub-tree host has no inherited `donePromise`).
|
|
283
|
+
* Load it now; if a circular dependency is truly in-flight, the nested
|
|
284
|
+
* lookup will find this host pending and defer through its `donePromise`.
|
|
285
|
+
*/
|
|
286
|
+
await this.loadProvider(instanceWrapper, instanceWrapper.host ?? moduleRef, resolutionContext);
|
|
287
|
+
}
|
|
276
288
|
}
|
|
277
289
|
if (instanceWrapper.async) {
|
|
278
290
|
const host = instanceWrapper.getInstanceByContextId(this.getContextId(resolutionContext.contextId, instanceWrapper), inquirerId);
|
package/injector/module.js
CHANGED
|
@@ -4,6 +4,7 @@ import { InvalidClassException, RuntimeException, UnknownExportException, } from
|
|
|
4
4
|
import { createContextId } from '../helpers/context-id-factory.js';
|
|
5
5
|
import { getClassScope } from '../helpers/get-class-scope.js';
|
|
6
6
|
import { isDurable } from '../helpers/is-durable.js';
|
|
7
|
+
import { makeSafeInstanceDecorator } from '../helpers/safe-instance-decorator.js';
|
|
7
8
|
import { UuidFactory } from '../inspector/uuid-factory.js';
|
|
8
9
|
import { CONTROLLER_ID_KEY } from './constants.js';
|
|
9
10
|
import { InstanceWrapper } from './instance-wrapper.js';
|
|
@@ -251,7 +252,9 @@ export class Module {
|
|
|
251
252
|
token: providerToken,
|
|
252
253
|
name: providerToken?.name || providerToken,
|
|
253
254
|
metatype: null,
|
|
254
|
-
instance: instanceDecorator
|
|
255
|
+
instance: instanceDecorator
|
|
256
|
+
? makeSafeInstanceDecorator(instanceDecorator)(value)
|
|
257
|
+
: value,
|
|
255
258
|
isResolved: true,
|
|
256
259
|
async: value instanceof Promise,
|
|
257
260
|
host: this,
|
package/internal.d.ts
CHANGED
|
@@ -5,28 +5,32 @@
|
|
|
5
5
|
* @internal
|
|
6
6
|
* @module
|
|
7
7
|
*/
|
|
8
|
-
export
|
|
8
|
+
export * from './errors/exceptions/index.js';
|
|
9
9
|
export { InvalidExceptionFilterException } from './errors/exceptions/invalid-exception-filter.exception.js';
|
|
10
|
+
export { RuntimeException } from './errors/exceptions/runtime.exception.js';
|
|
10
11
|
export { MESSAGES } from './constants.js';
|
|
11
12
|
export { DependenciesScanner } from './scanner.js';
|
|
13
|
+
export { STATIC_CONTEXT } from './injector/constants.js';
|
|
12
14
|
export { Injector, InjectorDependencyContext } from './injector/injector.js';
|
|
13
15
|
export { InstanceLoader } from './injector/instance-loader.js';
|
|
14
16
|
export { InstanceWrapper } from './injector/instance-wrapper.js';
|
|
17
|
+
export { InternalCoreModule } from './injector/internal-core-module/index.js';
|
|
15
18
|
export { Module } from './injector/module.js';
|
|
16
|
-
export
|
|
17
|
-
export { ExecutionContextHost } from './helpers/execution-context-host.js';
|
|
19
|
+
export * from './inspector/index.js';
|
|
18
20
|
export { ContextUtils, ParamProperties } from './helpers/context-utils.js';
|
|
21
|
+
export { ExecutionContextHost } from './helpers/execution-context-host.js';
|
|
19
22
|
export { HandlerMetadataStorage } from './helpers/handler-metadata-storage.js';
|
|
20
|
-
export { RouterMethodFactory } from './helpers/router-method-factory.js';
|
|
21
23
|
export { loadAdapter } from './helpers/load-adapter.js';
|
|
22
24
|
export { optionalRequire } from './helpers/optional-require.js';
|
|
25
|
+
export { RouterMethodFactory } from './helpers/router-method-factory.js';
|
|
26
|
+
export { makeSafeInstanceDecorator } from './helpers/safe-instance-decorator.js';
|
|
23
27
|
export { ParamsMetadata } from './helpers/interfaces/index.js';
|
|
28
|
+
export { FORBIDDEN_MESSAGE } from './guards/constants.js';
|
|
24
29
|
export { GuardsConsumer } from './guards/guards-consumer.js';
|
|
25
30
|
export { GuardsContextCreator } from './guards/guards-context-creator.js';
|
|
26
|
-
export {
|
|
31
|
+
export { ParamsTokenFactory } from './pipes/params-token-factory.js';
|
|
27
32
|
export { PipesConsumer } from './pipes/pipes-consumer.js';
|
|
28
33
|
export { PipesContextCreator } from './pipes/pipes-context-creator.js';
|
|
29
|
-
export { ParamsTokenFactory } from './pipes/params-token-factory.js';
|
|
30
34
|
export { InterceptorsConsumer } from './interceptors/interceptors-consumer.js';
|
|
31
35
|
export { InterceptorsContextCreator } from './interceptors/interceptors-context-creator.js';
|
|
32
36
|
export { BaseExceptionFilterContext } from './exceptions/base-exception-filter-context.js';
|
package/internal.js
CHANGED
|
@@ -6,33 +6,37 @@
|
|
|
6
6
|
* @module
|
|
7
7
|
*/
|
|
8
8
|
// Errors
|
|
9
|
-
export
|
|
9
|
+
export * from './errors/exceptions/index.js';
|
|
10
10
|
export { InvalidExceptionFilterException } from './errors/exceptions/invalid-exception-filter.exception.js';
|
|
11
|
+
export { RuntimeException } from './errors/exceptions/runtime.exception.js';
|
|
11
12
|
// Constants
|
|
12
13
|
export { MESSAGES } from './constants.js';
|
|
13
14
|
// Scanner
|
|
14
15
|
export { DependenciesScanner } from './scanner.js';
|
|
15
16
|
// Injector
|
|
17
|
+
export { STATIC_CONTEXT } from './injector/constants.js';
|
|
16
18
|
export { Injector } from './injector/injector.js';
|
|
17
19
|
export { InstanceLoader } from './injector/instance-loader.js';
|
|
18
20
|
export { InstanceWrapper } from './injector/instance-wrapper.js';
|
|
21
|
+
export { InternalCoreModule } from './injector/internal-core-module/index.js';
|
|
19
22
|
export { Module } from './injector/module.js';
|
|
20
|
-
export
|
|
23
|
+
export * from './inspector/index.js';
|
|
21
24
|
// Helpers
|
|
22
|
-
export { ExecutionContextHost } from './helpers/execution-context-host.js';
|
|
23
25
|
export { ContextUtils } from './helpers/context-utils.js';
|
|
26
|
+
export { ExecutionContextHost } from './helpers/execution-context-host.js';
|
|
24
27
|
export { HandlerMetadataStorage } from './helpers/handler-metadata-storage.js';
|
|
25
|
-
export { RouterMethodFactory } from './helpers/router-method-factory.js';
|
|
26
28
|
export { loadAdapter } from './helpers/load-adapter.js';
|
|
27
29
|
export { optionalRequire } from './helpers/optional-require.js';
|
|
30
|
+
export { RouterMethodFactory } from './helpers/router-method-factory.js';
|
|
31
|
+
export { makeSafeInstanceDecorator } from './helpers/safe-instance-decorator.js';
|
|
28
32
|
// Guards
|
|
33
|
+
export { FORBIDDEN_MESSAGE } from './guards/constants.js';
|
|
29
34
|
export { GuardsConsumer } from './guards/guards-consumer.js';
|
|
30
35
|
export { GuardsContextCreator } from './guards/guards-context-creator.js';
|
|
31
|
-
export { FORBIDDEN_MESSAGE } from './guards/constants.js';
|
|
32
36
|
// Pipes
|
|
37
|
+
export { ParamsTokenFactory } from './pipes/params-token-factory.js';
|
|
33
38
|
export { PipesConsumer } from './pipes/pipes-consumer.js';
|
|
34
39
|
export { PipesContextCreator } from './pipes/pipes-context-creator.js';
|
|
35
|
-
export { ParamsTokenFactory } from './pipes/params-token-factory.js';
|
|
36
40
|
// Interceptors
|
|
37
41
|
export { InterceptorsConsumer } from './interceptors/interceptors-consumer.js';
|
|
38
42
|
export { InterceptorsContextCreator } from './interceptors/interceptors-context-creator.js';
|
package/nest-application.js
CHANGED
|
@@ -4,6 +4,7 @@ import { platform } from 'os';
|
|
|
4
4
|
import { ApplicationConfig } from './application-config.js';
|
|
5
5
|
import { MESSAGES } from './constants.js';
|
|
6
6
|
import { optionalRequire } from './helpers/optional-require.js';
|
|
7
|
+
import { makeSafeInstanceDecorator } from './helpers/safe-instance-decorator.js';
|
|
7
8
|
import { Injector } from './injector/injector.js';
|
|
8
9
|
import { MiddlewareContainer } from './middleware/container.js';
|
|
9
10
|
import { MiddlewareModule } from './middleware/middleware-module.js';
|
|
@@ -411,7 +412,8 @@ export class NestApplication extends NestApplicationContext {
|
|
|
411
412
|
}
|
|
412
413
|
applyInstanceDecoratorIfRegistered(...instances) {
|
|
413
414
|
if (this.appOptions.instrument?.instanceDecorator) {
|
|
414
|
-
|
|
415
|
+
const decorate = makeSafeInstanceDecorator(this.appOptions.instrument.instanceDecorator);
|
|
416
|
+
return instances.map(instance => decorate(instance));
|
|
415
417
|
}
|
|
416
418
|
return instances;
|
|
417
419
|
}
|
|
@@ -419,15 +421,21 @@ export class NestApplication extends NestApplicationContext {
|
|
|
419
421
|
if (!this.appOptions.instrument?.instanceDecorator) {
|
|
420
422
|
return args;
|
|
421
423
|
}
|
|
422
|
-
const
|
|
423
|
-
return
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
isFunction(
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
424
|
+
const decorate = makeSafeInstanceDecorator(this.appOptions.instrument.instanceDecorator);
|
|
425
|
+
// Decorators may return a non-function value for plain middleware
|
|
426
|
+
// functions; fall back to the original argument so the HTTP adapter
|
|
427
|
+
// always receives a valid handler.
|
|
428
|
+
const decorateFunction = (arg) => {
|
|
429
|
+
if (!isFunction(arg)) {
|
|
430
|
+
return arg;
|
|
431
|
+
}
|
|
432
|
+
const decorated = decorate(arg);
|
|
433
|
+
return isFunction(decorated) ? decorated : arg;
|
|
434
|
+
};
|
|
435
|
+
// Map over the original arguments to preserve arity: appending a trailing
|
|
436
|
+
// `undefined` to a single-argument `use(fn)` call would make Express 5's
|
|
437
|
+
// router throw "argument handler must be a function".
|
|
438
|
+
return args.map(decorateFunction);
|
|
431
439
|
}
|
|
432
440
|
async loadSocketModule() {
|
|
433
441
|
if (!this.socketModule) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nestjs/core",
|
|
3
|
-
"version": "12.0.0
|
|
3
|
+
"version": "12.0.0",
|
|
4
4
|
"description": "Nest - modern, fast, powerful node.js web framework (@core)",
|
|
5
5
|
"author": "Kamil Mysliwiec",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"uid": "2.0.2"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@nestjs/common": "
|
|
39
|
+
"@nestjs/common": "12.0.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@nestjs/common": "^11.0.0",
|
|
@@ -57,5 +57,5 @@
|
|
|
57
57
|
"optional": true
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "6494a6c27400547ea6cd9b78da07b2e9c2547ca0"
|
|
61
61
|
}
|