@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.
@@ -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
+ }
@@ -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);
@@ -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 ? instanceDecorator(value) : value,
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 { RuntimeException } from './errors/exceptions/runtime.exception.js';
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 { STATIC_CONTEXT } from './injector/constants.js';
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 { FORBIDDEN_MESSAGE } from './guards/constants.js';
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 { RuntimeException } from './errors/exceptions/runtime.exception.js';
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 { STATIC_CONTEXT } from './injector/constants.js';
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';
@@ -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
- return instances.map(instance => this.appOptions.instrument.instanceDecorator(instance));
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 [firstArg, secondArg] = args;
423
- return [
424
- isFunction(firstArg)
425
- ? this.appOptions.instrument.instanceDecorator(firstArg)
426
- : firstArg,
427
- isFunction(secondArg)
428
- ? this.appOptions.instrument.instanceDecorator(secondArg)
429
- : secondArg,
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-alpha.6",
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": "^12.0.0-alpha.6"
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": "4c38a5ab100f1d2a0d50602998968a25509525c7"
60
+ "gitHead": "6494a6c27400547ea6cd9b78da07b2e9c2547ca0"
61
61
  }