@lenne.tech/nest-server 11.42.5 → 11.42.7

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 (29) hide show
  1. package/.claude/rules/configurable-features.md +2 -1
  2. package/.claude/rules/testing.md +3 -3
  3. package/FRAMEWORK-API.md +1 -1
  4. package/dist/core/common/helpers/swagger.helper.d.ts +11 -0
  5. package/dist/core/common/helpers/swagger.helper.js +362 -0
  6. package/dist/core/common/helpers/swagger.helper.js.map +1 -0
  7. package/dist/core/common/interfaces/swagger-setup-options.interface.d.ts +33 -0
  8. package/dist/core/common/interfaces/swagger-setup-options.interface.js +3 -0
  9. package/dist/core/common/interfaces/swagger-setup-options.interface.js.map +1 -0
  10. package/dist/core/common/services/core-body-parser.initializer.d.ts +2 -0
  11. package/dist/core/common/services/core-body-parser.initializer.js +23 -3
  12. package/dist/core/common/services/core-body-parser.initializer.js.map +1 -1
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.js +2 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/main.js +8 -14
  17. package/dist/main.js.map +1 -1
  18. package/dist/tsconfig.build.tsbuildinfo +1 -1
  19. package/docs/REQUEST-LIFECYCLE.md +1 -1
  20. package/migration-guides/11.42.3-to-11.42.4.md +10 -1
  21. package/migration-guides/11.42.5-to-11.42.6.md +113 -0
  22. package/migration-guides/11.42.6-to-11.42.7.md +115 -0
  23. package/package.json +4 -4
  24. package/src/core/common/helpers/swagger.helper.ts +529 -0
  25. package/src/core/common/interfaces/server-options.interface.ts +5 -0
  26. package/src/core/common/interfaces/swagger-setup-options.interface.ts +131 -0
  27. package/src/core/common/services/core-body-parser.initializer.ts +47 -5
  28. package/src/index.ts +2 -0
  29. package/src/main.ts +9 -15
@@ -90,11 +90,8 @@ export class CoreBodyParserInitializer implements OnModuleInit {
90
90
  const limit = this.resolveLimit(type, config?.[type]?.limit);
91
91
  const layers = stack.filter((layer) => this.isGlobalParserLayer(layer, type));
92
92
 
93
- if (limit !== undefined && !layers.length) {
94
- this.logger.warn(
95
- `bodyParser.${type}.limit is configured, but no global ${type} body parser is registered ` +
96
- '(was the app created with `bodyParser: false`?) — the limit has no effect.',
97
- );
93
+ if (!layers.length) {
94
+ this.warnMissingGlobalParser(type, stack, limit);
98
95
  continue;
99
96
  }
100
97
 
@@ -147,6 +144,18 @@ export class CoreBodyParserInitializer implements OnModuleInit {
147
144
  return layer?.slash === true && typeof layer.handle === 'function' && layer.handle.name === PARSER_NAMES[type];
148
145
  }
149
146
 
147
+ /**
148
+ * Whether the application was created without `bodyParser: false`.
149
+ *
150
+ * Read from the same container options as `rawBody`. Under `Test.createTestingModule()` those
151
+ * options never reach the container, so the answer there is always "enabled".
152
+ */
153
+ protected isBodyParserEnabled(): boolean {
154
+ const container = (this.moduleRef as unknown as { container?: { contextOptions?: { bodyParser?: boolean } } })
155
+ ?.container;
156
+ return container?.contextOptions?.bodyParser !== false;
157
+ }
158
+
150
159
  /**
151
160
  * Whether the application was created with `rawBody: true`.
152
161
  *
@@ -210,6 +219,39 @@ export class CoreBodyParserInitializer implements OnModuleInit {
210
219
  );
211
220
  }
212
221
 
222
+ /**
223
+ * Explain why there is no global parser of this type, when there should be one.
224
+ *
225
+ * NestJS registers its own parsers inside `app.init()` only if no layer with the parser's function
226
+ * name exists yet (`ExpressAdapter.isMiddlewareApplied()` compares the NAME and nothing else). A
227
+ * path-scoped `server.use('/upload', json({ limit }))` in `main.ts` therefore counts as "applied",
228
+ * NestJS skips its global parser, and every request outside that path reaches its handler with an
229
+ * empty body — a sign-in fails with a validation error, and nothing says why. Restoring the parser
230
+ * from here is not safe: NestJS would have placed it after everything `main.ts` registered, and that
231
+ * position is no longer knowable during module init (a raw-body webhook or a proxy registered after
232
+ * the path-scoped parser must keep seeing the unread stream). So this reports, with the remedy.
233
+ */
234
+ protected warnMissingGlobalParser(type: CoreBodyParserType, stack: ExpressLayer[], limit: number | undefined): void {
235
+ const name = PARSER_NAMES[type];
236
+ const shadowed = stack.some((layer) => layer?.slash !== true && layer?.handle?.name === name);
237
+ if (shadowed && this.isBodyParserEnabled()) {
238
+ this.logger.warn(
239
+ `No global ${type} body parser is registered: NestJS skips its own when a layer named \`${name}\` ` +
240
+ `already exists, and a path-scoped \`${type}()\` parser registered before \`app.init()\` counts as one. ` +
241
+ `Every request outside that path reaches its handler with an EMPTY body. Register the global parser ` +
242
+ `in main.ts as well — \`server.useBodyParser('${type}')\` — a configured \`bodyParser.${type}.limit\` ` +
243
+ 'is applied to it.',
244
+ );
245
+ return;
246
+ }
247
+ if (limit !== undefined) {
248
+ this.logger.warn(
249
+ `bodyParser.${type}.limit is configured, but no global ${type} body parser is registered ` +
250
+ '(was the app created with `bodyParser: false`?) — the limit has no effect.',
251
+ );
252
+ }
253
+ }
254
+
213
255
  /**
214
256
  * Wrap a parser so its 413 is translated, keeping the name NestJS identifies the layer by.
215
257
  *
package/src/index.ts CHANGED
@@ -53,6 +53,7 @@ export * from './core/common/helpers/process-diagnostics.helper';
53
53
  export * from './core/common/helpers/register-enum.helper';
54
54
  export * from './core/common/helpers/scim.helper';
55
55
  export * from './core/common/helpers/service.helper';
56
+ export * from './core/common/helpers/swagger.helper';
56
57
  export * from './core/common/helpers/table.helper';
57
58
  export * from './core/common/inputs/combined-filter.input';
58
59
  export * from './core/common/inputs/core-input.input';
@@ -73,6 +74,7 @@ export * from './core/common/interfaces/prepare-output-options.interface';
73
74
  export * from './core/common/interfaces/resolve-selector.interface';
74
75
  export * from './core/common/interfaces/server-options.interface';
75
76
  export * from './core/common/interfaces/service-options.interface';
77
+ export * from './core/common/interfaces/swagger-setup-options.interface';
76
78
  export * from './core/common/middleware/request-context.middleware';
77
79
  export * from './core/common/middlewares/to-lower-case.middleware';
78
80
  export * from './core/common/middlewares/security-headers.middleware';
package/src/main.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { NestFactory } from '@nestjs/core';
2
2
  import { NestExpressApplication } from '@nestjs/platform-express';
3
- import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
4
3
  import { exec } from 'child_process';
5
4
  import compression = require('compression');
6
5
  import cookieParser = require('cookie-parser');
@@ -11,6 +10,7 @@ import { buildCorsConfig, isCookiesEnabled, isCorsDisabled } from './core/common
11
10
  import { HttpExceptionLogFilter } from './core/common/filters/http-exception-log.filter';
12
11
  import { installGracefulShutdown } from './core/common/helpers/graceful-shutdown.helper';
13
12
  import { handleFatalBootstrapError, installProcessDiagnostics } from './core/common/helpers/process-diagnostics.helper';
13
+ import { setupSwagger } from './core/common/helpers/swagger.helper';
14
14
  import { CorePersistenceModel } from './core/common/models/core-persistence.model';
15
15
  import { CoreAuthModel } from './core/modules/auth/core-auth.model';
16
16
  import { CoreUserModel } from './core/modules/user/core-user.model';
@@ -96,21 +96,15 @@ async function bootstrap() {
96
96
  // to avoid open CORS with credentials). Callers should configure appUrl/baseUrl/allowedOrigins.
97
97
  }
98
98
 
99
- // Swagger documentation
100
- const config = new DocumentBuilder()
101
- .setTitle('Nest Server API')
102
- .setDescription('API lenne.Tech Nest Server')
103
- .setVersion('1.0.0')
104
- .addBearerAuth()
105
- .build();
106
- const documentFactory = () =>
107
- SwaggerModule.createDocument(server, config, {
108
- autoTagControllers: true,
109
- deepScanRoutes: true,
99
+ // Swagger documentation: security, API-token scopes and the tenant header are read from the same
100
+ // decorators the guards read (see setupSwagger), so "Authorize" applies to every route.
101
+ setupSwagger(server, {
102
+ description: 'API lenne.Tech Nest Server',
103
+ documentOptions: {
110
104
  extraModels: [CoreUserModel, CoreAuthModel, Auth, User, PersistenceModel, CorePersistenceModel, FilterArgs],
111
- });
112
- SwaggerModule.setup('swagger', server, documentFactory, {
113
- jsonDocumentUrl: '/api-docs-json',
105
+ },
106
+ title: 'Nest Server API',
107
+ version: '1.0.0',
114
108
  });
115
109
 
116
110
  // Drain the event loop on SIGTERM/SIGINT so the process actually exits.