@lenne.tech/nest-server 11.32.4 → 11.33.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.
Files changed (260) hide show
  1. package/.claude/rules/architecture.md +16 -0
  2. package/.claude/rules/configurable-features.md +11 -3
  3. package/.claude/rules/testing.md +101 -1
  4. package/CLAUDE.md +5 -0
  5. package/FRAMEWORK-API.md +58 -3
  6. package/dist/core/common/helpers/content-disposition.helper.d.ts +1 -0
  7. package/dist/core/common/helpers/content-disposition.helper.js +14 -0
  8. package/dist/core/common/helpers/content-disposition.helper.js.map +1 -0
  9. package/dist/core/common/helpers/file.helper.d.ts +7 -0
  10. package/dist/core/common/helpers/file.helper.js +21 -4
  11. package/dist/core/common/helpers/file.helper.js.map +1 -1
  12. package/dist/core/common/helpers/graceful-shutdown.helper.d.ts +2 -0
  13. package/dist/core/common/helpers/graceful-shutdown.helper.js +55 -0
  14. package/dist/core/common/helpers/graceful-shutdown.helper.js.map +1 -0
  15. package/dist/core/common/helpers/project-name.helper.d.ts +2 -0
  16. package/dist/core/common/helpers/project-name.helper.js +38 -0
  17. package/dist/core/common/helpers/project-name.helper.js.map +1 -0
  18. package/dist/core/common/interfaces/cron-job-config.interface.d.ts +1 -0
  19. package/dist/core/common/interfaces/server-options.interface.d.ts +39 -0
  20. package/dist/core/common/services/core-cron-jobs.initializer.d.ts +10 -0
  21. package/dist/core/common/services/core-cron-jobs.initializer.js +46 -0
  22. package/dist/core/common/services/core-cron-jobs.initializer.js.map +1 -0
  23. package/dist/core/common/services/core-cron-jobs.registry.d.ts +8 -0
  24. package/dist/core/common/services/core-cron-jobs.registry.js +12 -0
  25. package/dist/core/common/services/core-cron-jobs.registry.js.map +1 -0
  26. package/dist/core/common/services/core-cron-jobs.service.d.ts +37 -7
  27. package/dist/core/common/services/core-cron-jobs.service.js +278 -27
  28. package/dist/core/common/services/core-cron-jobs.service.js.map +1 -1
  29. package/dist/core/common/services/core-redis-pubsub.d.ts +20 -0
  30. package/dist/core/common/services/core-redis-pubsub.js +112 -0
  31. package/dist/core/common/services/core-redis-pubsub.js.map +1 -0
  32. package/dist/core/common/services/core-redis.service.d.ts +25 -0
  33. package/dist/core/common/services/core-redis.service.js +154 -0
  34. package/dist/core/common/services/core-redis.service.js.map +1 -0
  35. package/dist/core/common/services/core-s3.service.d.ts +51 -0
  36. package/dist/core/common/services/core-s3.service.js +261 -0
  37. package/dist/core/common/services/core-s3.service.js.map +1 -0
  38. package/dist/core/common/services/core-trust-proxy.initializer.d.ts +16 -0
  39. package/dist/core/common/services/core-trust-proxy.initializer.js +77 -0
  40. package/dist/core/common/services/core-trust-proxy.initializer.js.map +1 -0
  41. package/dist/core/common/services/rate-limit-store.d.ts +61 -0
  42. package/dist/core/common/services/rate-limit-store.js +235 -0
  43. package/dist/core/common/services/rate-limit-store.js.map +1 -0
  44. package/dist/core/modules/ai/core-ai-mcp.controller.d.ts +19 -3
  45. package/dist/core/modules/ai/core-ai-mcp.controller.js +148 -18
  46. package/dist/core/modules/ai/core-ai-mcp.controller.js.map +1 -1
  47. package/dist/core/modules/ai/services/core-ai.service.d.ts +7 -2
  48. package/dist/core/modules/ai/services/core-ai.service.js +24 -20
  49. package/dist/core/modules/ai/services/core-ai.service.js.map +1 -1
  50. package/dist/core/modules/auth/core-auth.module.js +4 -1
  51. package/dist/core/modules/auth/core-auth.module.js.map +1 -1
  52. package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.d.ts +1 -1
  53. package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js +3 -14
  54. package/dist/core/modules/auth/guards/legacy-auth-rate-limit.guard.js.map +1 -1
  55. package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.d.ts +12 -10
  56. package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.js +30 -59
  57. package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.js.map +1 -1
  58. package/dist/core/modules/better-auth/core-better-auth-email-verification.service.d.ts +8 -2
  59. package/dist/core/modules/better-auth/core-better-auth-email-verification.service.js +118 -45
  60. package/dist/core/modules/better-auth/core-better-auth-email-verification.service.js.map +1 -1
  61. package/dist/core/modules/better-auth/core-better-auth-rate-limit.middleware.d.ts +1 -1
  62. package/dist/core/modules/better-auth/core-better-auth-rate-limit.middleware.js +2 -11
  63. package/dist/core/modules/better-auth/core-better-auth-rate-limit.middleware.js.map +1 -1
  64. package/dist/core/modules/better-auth/core-better-auth-rate-limiter.service.d.ts +12 -10
  65. package/dist/core/modules/better-auth/core-better-auth-rate-limiter.service.js +30 -85
  66. package/dist/core/modules/better-auth/core-better-auth-rate-limiter.service.js.map +1 -1
  67. package/dist/core/modules/better-auth/core-better-auth-user.mapper.js +0 -1
  68. package/dist/core/modules/better-auth/core-better-auth-user.mapper.js.map +1 -1
  69. package/dist/core/modules/file/core-file.controller.d.ts +11 -2
  70. package/dist/core/modules/file/core-file.controller.js +52 -15
  71. package/dist/core/modules/file/core-file.controller.js.map +1 -1
  72. package/dist/core/modules/file/core-file.resolver.d.ts +4 -4
  73. package/dist/core/modules/file/core-file.resolver.js +23 -16
  74. package/dist/core/modules/file/core-file.resolver.js.map +1 -1
  75. package/dist/core/modules/file/core-file.service.d.ts +41 -7
  76. package/dist/core/modules/file/core-file.service.js +227 -7
  77. package/dist/core/modules/file/core-file.service.js.map +1 -1
  78. package/dist/core/modules/file/file-metadata.helper.d.ts +16 -0
  79. package/dist/core/modules/file/file-metadata.helper.js +33 -0
  80. package/dist/core/modules/file/file-metadata.helper.js.map +1 -0
  81. package/dist/core/modules/file/file-roles.helper.d.ts +4 -0
  82. package/dist/core/modules/file/file-roles.helper.js +53 -0
  83. package/dist/core/modules/file/file-roles.helper.js.map +1 -0
  84. package/dist/core/modules/file/file-storage.helper.d.ts +13 -0
  85. package/dist/core/modules/file/file-storage.helper.js +65 -0
  86. package/dist/core/modules/file/file-storage.helper.js.map +1 -0
  87. package/dist/core/modules/file/filesystem-file.helper.d.ts +22 -0
  88. package/dist/core/modules/file/filesystem-file.helper.js +77 -0
  89. package/dist/core/modules/file/filesystem-file.helper.js.map +1 -0
  90. package/dist/core/modules/file/interfaces/file-service-options.interface.d.ts +1 -0
  91. package/dist/core/modules/file/interfaces/file-upload.interface.d.ts +7 -1
  92. package/dist/core/modules/file/s3-file.helper.d.ts +37 -0
  93. package/dist/core/modules/file/s3-file.helper.js +81 -0
  94. package/dist/core/modules/file/s3-file.helper.js.map +1 -0
  95. package/dist/core/modules/hub/core-hub.controller.d.ts +8 -8
  96. package/dist/core/modules/hub/core-hub.controller.js +24 -22
  97. package/dist/core/modules/hub/core-hub.controller.js.map +1 -1
  98. package/dist/core/modules/hub/helpers/hub-mask.helper.js +2 -2
  99. package/dist/core/modules/hub/helpers/hub-mask.helper.js.map +1 -1
  100. package/dist/core/modules/hub/hub-buffer.d.ts +23 -0
  101. package/dist/core/modules/hub/hub-buffer.js +101 -0
  102. package/dist/core/modules/hub/hub-buffer.js.map +1 -0
  103. package/dist/core/modules/hub/services/core-hub-mailbox.service.d.ts +7 -5
  104. package/dist/core/modules/hub/services/core-hub-mailbox.service.js +14 -10
  105. package/dist/core/modules/hub/services/core-hub-mailbox.service.js.map +1 -1
  106. package/dist/core/modules/hub/services/hub-log-buffer.service.d.ts +5 -2
  107. package/dist/core/modules/hub/services/hub-log-buffer.service.js +17 -8
  108. package/dist/core/modules/hub/services/hub-log-buffer.service.js.map +1 -1
  109. package/dist/core/modules/hub/services/hub-query-profiler.service.d.ts +4 -2
  110. package/dist/core/modules/hub/services/hub-query-profiler.service.js +13 -7
  111. package/dist/core/modules/hub/services/hub-query-profiler.service.js.map +1 -1
  112. package/dist/core/modules/hub/services/hub-trace-buffer.service.d.ts +4 -2
  113. package/dist/core/modules/hub/services/hub-trace-buffer.service.js +13 -8
  114. package/dist/core/modules/hub/services/hub-trace-buffer.service.js.map +1 -1
  115. package/dist/core/modules/migrate/helpers/migration.helper.d.ts +2 -6
  116. package/dist/core/modules/migrate/helpers/migration.helper.js +4 -4
  117. package/dist/core/modules/migrate/helpers/migration.helper.js.map +1 -1
  118. package/dist/core/modules/migrate/migration-runner.d.ts +1 -0
  119. package/dist/core/modules/migrate/migration-runner.js +4 -0
  120. package/dist/core/modules/migrate/migration-runner.js.map +1 -1
  121. package/dist/core/modules/migrate/mongo-state-store.d.ts +1 -0
  122. package/dist/core/modules/migrate/mongo-state-store.js +98 -9
  123. package/dist/core/modules/migrate/mongo-state-store.js.map +1 -1
  124. package/dist/core/modules/system-setup/core-system-setup.service.d.ts +2 -0
  125. package/dist/core/modules/system-setup/core-system-setup.service.js +31 -1
  126. package/dist/core/modules/system-setup/core-system-setup.service.js.map +1 -1
  127. package/dist/core/modules/tenant/core-tenant.guard.d.ts +17 -3
  128. package/dist/core/modules/tenant/core-tenant.guard.js +92 -15
  129. package/dist/core/modules/tenant/core-tenant.guard.js.map +1 -1
  130. package/dist/core/modules/tenant/core-tenant.module.js +3 -4
  131. package/dist/core/modules/tenant/core-tenant.module.js.map +1 -1
  132. package/dist/core/modules/tus/core-tus.controller.d.ts +2 -0
  133. package/dist/core/modules/tus/core-tus.controller.js +29 -3
  134. package/dist/core/modules/tus/core-tus.controller.js.map +1 -1
  135. package/dist/core/modules/tus/core-tus.service.d.ts +24 -1
  136. package/dist/core/modules/tus/core-tus.service.js +182 -28
  137. package/dist/core/modules/tus/core-tus.service.js.map +1 -1
  138. package/dist/core/modules/tus/interfaces/tus-config.interface.js +3 -0
  139. package/dist/core/modules/tus/interfaces/tus-config.interface.js.map +1 -1
  140. package/dist/core/modules/tus/tus-redis-locker.d.ts +25 -0
  141. package/dist/core/modules/tus/tus-redis-locker.js +87 -0
  142. package/dist/core/modules/tus/tus-redis-locker.js.map +1 -0
  143. package/dist/core/modules/tus/tus.module.d.ts +1 -0
  144. package/dist/core/modules/tus/tus.module.js +30 -4
  145. package/dist/core/modules/tus/tus.module.js.map +1 -1
  146. package/dist/core.module.js +18 -1
  147. package/dist/core.module.js.map +1 -1
  148. package/dist/index.d.ts +10 -0
  149. package/dist/index.js +10 -0
  150. package/dist/index.js.map +1 -1
  151. package/dist/main.js +2 -1
  152. package/dist/main.js.map +1 -1
  153. package/dist/server/modules/file/file.controller.js.map +1 -1
  154. package/dist/server/modules/file/file.resolver.js +1 -12
  155. package/dist/server/modules/file/file.resolver.js.map +1 -1
  156. package/dist/server/modules/file/file.service.d.ts +5 -1
  157. package/dist/server/modules/file/file.service.js +12 -3
  158. package/dist/server/modules/file/file.service.js.map +1 -1
  159. package/dist/server/modules/user/avatar.controller.d.ts +5 -1
  160. package/dist/server/modules/user/avatar.controller.js +26 -10
  161. package/dist/server/modules/user/avatar.controller.js.map +1 -1
  162. package/dist/server/modules/user/user.model.js +3 -2
  163. package/dist/server/modules/user/user.model.js.map +1 -1
  164. package/dist/server/modules/user/user.module.js +6 -2
  165. package/dist/server/modules/user/user.module.js.map +1 -1
  166. package/dist/server/modules/user/user.service.d.ts +1 -1
  167. package/dist/server/modules/user/user.service.js +6 -13
  168. package/dist/server/modules/user/user.service.js.map +1 -1
  169. package/dist/tsconfig.build.tsbuildinfo +1 -1
  170. package/docs/REQUEST-LIFECYCLE.md +57 -8
  171. package/docs/security-overrides.md +21 -3
  172. package/migration-guides/11.32.3-to-11.32.4.md +15 -3
  173. package/migration-guides/11.32.x-to-11.33.x.md +1551 -0
  174. package/package.json +74 -42
  175. package/src/core/common/helpers/content-disposition.helper.ts +90 -0
  176. package/src/core/common/helpers/file.helper.ts +53 -10
  177. package/src/core/common/helpers/graceful-shutdown.helper.ts +116 -0
  178. package/src/core/common/helpers/project-name.helper.ts +71 -0
  179. package/src/core/common/interfaces/cron-job-config.interface.ts +16 -0
  180. package/src/core/common/interfaces/server-options.interface.ts +439 -2
  181. package/src/core/common/services/core-cron-jobs.initializer.ts +39 -0
  182. package/src/core/common/services/core-cron-jobs.registry.ts +45 -0
  183. package/src/core/common/services/core-cron-jobs.service.ts +589 -47
  184. package/src/core/common/services/core-redis-pubsub.ts +183 -0
  185. package/src/core/common/services/core-redis.service.ts +249 -0
  186. package/src/core/common/services/core-s3.service.ts +465 -0
  187. package/src/core/common/services/core-trust-proxy.initializer.ts +112 -0
  188. package/src/core/common/services/rate-limit-store.ts +492 -0
  189. package/src/core/modules/ai/README.md +25 -0
  190. package/src/core/modules/ai/core-ai-mcp.controller.ts +253 -22
  191. package/src/core/modules/ai/services/core-ai.service.ts +33 -24
  192. package/src/core/modules/auth/core-auth.module.ts +7 -1
  193. package/src/core/modules/auth/guards/legacy-auth-rate-limit.guard.ts +12 -21
  194. package/src/core/modules/auth/services/legacy-auth-rate-limiter.service.ts +49 -93
  195. package/src/core/modules/better-auth/core-better-auth-email-verification.service.ts +202 -66
  196. package/src/core/modules/better-auth/core-better-auth-rate-limit.middleware.ts +11 -18
  197. package/src/core/modules/better-auth/core-better-auth-rate-limiter.service.ts +51 -132
  198. package/src/core/modules/better-auth/core-better-auth-user.mapper.ts +7 -1
  199. package/src/core/modules/file/INTEGRATION-CHECKLIST.md +108 -0
  200. package/src/core/modules/file/README.md +277 -53
  201. package/src/core/modules/file/core-file.controller.ts +168 -12
  202. package/src/core/modules/file/core-file.resolver.ts +46 -12
  203. package/src/core/modules/file/core-file.service.ts +482 -16
  204. package/src/core/modules/file/file-metadata.helper.ts +142 -0
  205. package/src/core/modules/file/file-roles.helper.ts +110 -0
  206. package/src/core/modules/file/file-storage.helper.ts +163 -0
  207. package/src/core/modules/file/filesystem-file.helper.ts +184 -0
  208. package/src/core/modules/file/interfaces/file-service-options.interface.ts +14 -0
  209. package/src/core/modules/file/interfaces/file-upload.interface.ts +17 -1
  210. package/src/core/modules/file/s3-file.helper.ts +209 -0
  211. package/src/core/modules/hub/README.md +48 -0
  212. package/src/core/modules/hub/core-hub.controller.ts +18 -16
  213. package/src/core/modules/hub/helpers/hub-mask.helper.ts +21 -4
  214. package/src/core/modules/hub/hub-buffer.ts +198 -0
  215. package/src/core/modules/hub/services/core-hub-mailbox.service.ts +22 -12
  216. package/src/core/modules/hub/services/hub-log-buffer.service.ts +24 -8
  217. package/src/core/modules/hub/services/hub-query-profiler.service.ts +9 -6
  218. package/src/core/modules/hub/services/hub-trace-buffer.service.ts +14 -9
  219. package/src/core/modules/migrate/README.md +33 -6
  220. package/src/core/modules/migrate/helpers/migration.helper.ts +13 -6
  221. package/src/core/modules/migrate/migration-runner.ts +10 -1
  222. package/src/core/modules/migrate/mongo-state-store.ts +179 -11
  223. package/src/core/modules/system-setup/README.md +7 -2
  224. package/src/core/modules/system-setup/core-system-setup.service.ts +95 -1
  225. package/src/core/modules/tenant/README.md +21 -1
  226. package/src/core/modules/tenant/core-tenant.guard.ts +135 -14
  227. package/src/core/modules/tenant/core-tenant.module.ts +8 -4
  228. package/src/core/modules/tus/INTEGRATION-CHECKLIST.md +93 -21
  229. package/src/core/modules/tus/README.md +35 -2
  230. package/src/core/modules/tus/core-tus.controller.ts +64 -12
  231. package/src/core/modules/tus/core-tus.service.ts +358 -34
  232. package/src/core/modules/tus/interfaces/tus-config.interface.ts +9 -0
  233. package/src/core/modules/tus/tus-redis-locker.ts +139 -0
  234. package/src/core/modules/tus/tus.module.ts +78 -6
  235. package/src/core.module.ts +26 -1
  236. package/src/index.ts +10 -0
  237. package/src/main.ts +7 -1
  238. package/src/server/modules/file/file.controller.ts +7 -3
  239. package/src/server/modules/file/file.resolver.ts +5 -17
  240. package/src/server/modules/file/file.service.ts +42 -3
  241. package/src/server/modules/user/avatar.controller.ts +39 -9
  242. package/src/server/modules/user/user.model.ts +9 -3
  243. package/src/server/modules/user/user.module.ts +12 -3
  244. package/src/server/modules/user/user.service.ts +20 -17
  245. package/src/test/README.md +7 -2
  246. package/src/core/common/helpers/file.helper.spec.ts +0 -145
  247. package/src/core/common/helpers/logging.helper.spec.ts +0 -61
  248. package/src/core/common/helpers/process-diagnostics.helper.spec.ts +0 -310
  249. package/src/core/common/services/brevo.service.spec.ts +0 -266
  250. package/src/core/modules/file/core-file.controller.spec.ts +0 -164
  251. package/src/core/modules/hub/core-hub.module.spec.ts +0 -108
  252. package/src/core/modules/hub/helpers/hub-command-shape.helper.spec.ts +0 -48
  253. package/src/core/modules/hub/helpers/hub-mask.helper.spec.ts +0 -67
  254. package/src/core/modules/hub/helpers/hub-mermaid.helper.spec.ts +0 -61
  255. package/src/core/modules/hub/helpers/hub-shell.helper.spec.ts +0 -106
  256. package/src/core/modules/hub/hub-config.helper.spec.ts +0 -108
  257. package/src/core/modules/hub/hub-ring-buffer.spec.ts +0 -95
  258. package/src/core/modules/hub/services/core-hub-mailbox.service.spec.ts +0 -116
  259. package/src/core/modules/hub/services/hub-trace-buffer.service.spec.ts +0 -112
  260. package/src/core/modules/migrate/helpers/migration.helper.spec.ts +0 -85
@@ -40,7 +40,9 @@ The `CoreModule` is a dynamic module that bootstraps the entire framework:
40
40
  | **Dual API Support** | GraphQL and REST in the same application |
41
41
  | **Security Pipeline** | 4 global interceptors, global validation pipe, middleware stack |
42
42
  | **Mongoose Plugins** | Auto-registration of ID, password, audit, and role guard plugins |
43
- | **GraphQL Subscriptions** | WebSocket support with JWT/session authentication |
43
+ | **GraphQL Subscriptions** | WebSocket support with JWT/session authentication (cluster-wide when `redis` is configured — see the Subscriptions row under GraphQL Features) |
44
+ | **Central Redis (optional)** | `CoreRedisService` — globally provided **and exported** by `CoreModule`, always present but **inert unless `redis` is configured** ("presence implies enabled"). Injected with `@Optional()`; every consumer keeps a process-local fallback. One service serves all features: shared client (`getClient()`), one cached subscriber (`getSubscriber()` — a subscribing client cannot run commands), dedicated connections (`createClient(label)`); all tracked and quit on shutdown. Keys are namespaced by the framework per key via `key(...)`, **not** through ioredis's own `keyPrefix` (that would collide with BullMQ's prefix). Requires the OPTIONAL peer `ioredis` — configured but missing **fails the boot**. Switches on: exact cross-replica rate limits, cron deduplication, `CoreRedisPubSub` as `PUB_SUB`, tenant-cache invalidation broadcast, Hub collector mirroring, MCP session registry |
45
+ | **Central S3 (optional)** | `CoreS3Service` — globally provided **and exported** by `CoreModule`, inert unless `s3` is configured *and* names a `bucket` (a bucket-less block is ignored with a warning). Backs `file.storage: 's3'` and TUS staging (`tus.s3Staging`). Requires the OPTIONAL peers `@aws-sdk/client-s3` (+ `@aws-sdk/s3-request-presigner` for `presignedDownloads`) — configured but missing **fails the boot** |
44
46
  | **Configuration System** | `config.env.ts` with ENV variables, `NEST_SERVER_CONFIG` JSON, `NSC__*` prefixes |
45
47
  | **Cookie Handling** | Enabled by default (`cookies: true`), configurable via `ICookiesConfig` with `exposeTokenInBody` option |
46
48
  | **Unified CORS** | Single `cors` config propagates to GraphQL, REST, and BetterAuth layers |
@@ -61,7 +63,7 @@ Modern OAuth-compatible authentication with plugin architecture:
61
63
  | **Social Login** | OAuth providers: Google, GitHub, Apple, Discord, etc. (plugin) |
62
64
  | **Email Verification** | Configurable email verification flow |
63
65
  | **Sign-Up Validation** | Custom validation hooks for registration |
64
- | **Rate Limiting** | Per-endpoint rate limits (configurable) |
66
+ | **Rate Limiting** | Per-endpoint rate limits (`betterAuth.rateLimit`, configurable). Counters live behind a `RateLimitStore`: `RedisRateLimitStore` when `redis` is configured, so `max` is enforced **exactly across replicas** instead of `max × replicas`; otherwise the process-local `InMemoryRateLimitStore` as before. `check()` / `reset()` / `clear()` are **async** since 11.33.0. On a Redis outage it degrades to the in-memory counter and logs once per transition — never a 500, never "allowed". Counters are keyed on `request.ip`, which Express derives from `X-Forwarded-For` only as far as `trust proxy` allows — set `trustProxy` (§ServerOptions) behind a reverse proxy or every client resolves to the proxy and shares ONE bucket; unset with a limiter enabled logs a boot warning |
65
67
  | **Cross-Subdomain Cookies** | Automatic cookie domain configuration |
66
68
  | **Organization / Multi-Tenant** | Teams and organization management (plugin) |
67
69
  | **3 Registration Patterns** | Zero-config, overrides parameter, or manual (`autoRegister: false`) |
@@ -75,7 +77,7 @@ JWT-based authentication for existing projects:
75
77
  | **JWT Authentication** | Bearer token auth with Passport strategies |
76
78
  | **Refresh Tokens** | Automatic token renewal |
77
79
  | **Sign In / Sign Up / Logout** | GraphQL mutations + REST endpoints |
78
- | **Rate Limiting** | Configurable per-endpoint rate limits |
80
+ | **Rate Limiting** | Configurable per-endpoint rate limits (`auth.rateLimit`). Same `RateLimitStore` selection, async signatures and Redis-outage degradation as the BetterAuth row above (namespace `legacy-auth`) |
79
81
  | **Legacy Endpoint Controls** | Disable legacy endpoints after migration (`auth.legacyEndpoints`) |
80
82
  | **Migration Tracking** | `betterAuthMigrationStatus` query for monitoring |
81
83
 
@@ -158,9 +160,10 @@ JWT-based authentication for existing projects:
158
160
  | Feature | Description |
159
161
  |---------|-------------|
160
162
  | **File Module** | Upload/download with MongoDB GridFS storage |
161
- | **REST Endpoints** | `GET /files/:id`, `POST /files/upload`, `DELETE /files/:id` |
162
- | **GraphQL Endpoints** | `uploadFile`, `file`, `fileByFilename`, `deleteFile` |
163
- | **TUS Module** | Resumable uploads via tus.io protocol (creation, termination, expiration) |
163
+ | **REST Endpoints** | `GET /files/id/:id`, `GET /files/:filename` (core, gated by `file.downloadRoles`, default ADMIN); `POST /files/upload`, `DELETE /files/:id` (project-specific) |
164
+ | **GraphQL Endpoints** | `getFileInfo` (`file.downloadRoles`), `uploadFile` / `uploadFiles` (`file.uploadRoles`), `deleteFile` (`file.deleteRoles`) — all default ADMIN |
165
+ | **File access control** | Roles are the coarse filter; per-file rules go in `CoreFileService.checkRights()` using metadata written at upload time. Both file classes carry `@SkipTenantCheck()` — GridFS is not tenant-scoped |
166
+ | **TUS Module** | Resumable uploads via tus.io protocol (creation, termination, expiration), gated by `tus.roles` (default `S_USER`); `OPTIONS` stays public for the CORS preflight |
164
167
  | **GridFS Migration** | Completed TUS uploads auto-migrate to GridFS |
165
168
  | **CORS Support** | Automatic CORS headers for browser uploads |
166
169
 
@@ -201,7 +204,7 @@ JWT-based authentication for existing projects:
201
204
  |---------|-------------|
202
205
  | **Apollo Server** | Full GraphQL server with schema-first or code-first |
203
206
  | **Custom Scalars** | `Date`, `DateTime` (timestamp), `JSON`, `Any` |
204
- | **Subscriptions** | WebSocket support via `graphql-ws` with auth |
207
+ | **Subscriptions** | WebSocket support via `graphql-ws` with auth. The `PUB_SUB` provider is built from a factory: `CoreRedisPubSub` when `redis` is configured (delivery is then cluster-wide), the in-memory `PubSub` otherwise (delivery only to clients connected to the publishing replica). **Constraint once Redis is in play: every published payload must be JSON-serializable** — it crosses the wire as JSON, so `Date`, class instances, `Map`/`Set` and `undefined` do not survive the round trip. An in-process `PubSub` never had this constraint, so a payload that worked on one replica can silently lose fields on a cluster. Publish plain objects and ISO strings |
205
208
  | **Complexity Analysis** | Query cost calculation to prevent DoS attacks |
206
209
  | **Enum Registration** | `registerEnum()` helper for GraphQL enum types |
207
210
  | **Upload Support** | `graphqlUploadExpress()` for multipart file uploads |
@@ -214,7 +217,8 @@ JWT-based authentication for existing projects:
214
217
  | **Error Code Module** | Centralized error registry with unique IDs |
215
218
  | **Permissions Report** | Interactive HTML dashboard, JSON, and Markdown reports |
216
219
  | **Hub (Operator Cockpit)** | Build-free ADMIN-gated dashboard at `/hub` (config-gated per environment). Adds an optional HTTP trace middleware (registered by `CoreHubModule.configure()` only when traces are enabled), a chaining `Logger.overrideLogger()` delegate for the log buffer, an optional `EmailService` capture hook (`HUB_EMAIL_CAPTURE` token) for the mailbox, and — when the query profiler is enabled — opts the MongoDB driver into `monitorCommands` from `core.module.ts`. See `src/core/modules/hub/README.md`. |
217
- | **Process Diagnostics** | Opt-in process-level exit diagnostics (`installProcessDiagnostics()` + `handleFatalBootstrapError`, `src/core/common/helpers/process-diagnostics.helper.ts`). Wired into `main.ts` — **NOT** into `CoreModule.forRoot()`, because it must run before `NestFactory.create()` and installs a `process.exit(1)` path that must never arm inside `Test.createTestingModule()`. Logs unhandled rejections without crashing (configurable), uncaught exceptions before the exit, non-zero exit codes, and labels SIGTERM/SIGINT/SIGHUP/SIGQUIT as external terminations. Pair with `server.enableShutdownHooks()` see the helper docblock |
220
+ | **Process Diagnostics** | Opt-in process-level exit diagnostics (`installProcessDiagnostics()` + `handleFatalBootstrapError`, `src/core/common/helpers/process-diagnostics.helper.ts`). Wired into `main.ts` — **NOT** into `CoreModule.forRoot()`, because it must run before `NestFactory.create()` and installs a `process.exit(1)` path that must never arm inside `Test.createTestingModule()`. Logs unhandled rejections without crashing (configurable), uncaught exceptions before the exit, non-zero exit codes, and labels SIGTERM/SIGINT/SIGHUP/SIGQUIT as external terminations. Pair with `installGracefulShutdown(server)` — **not** with `server.enableShutdownHooks()`, see the Graceful Shutdown row below |
221
+ | **Graceful Shutdown** | `installGracefulShutdown(app)` (`src/core/common/helpers/graceful-shutdown.helper.ts`), wired in `main.ts`. It **REPLACES** `server.enableShutdownHooks()` and must not be used alongside it: with `shutdownDelayMs` set, Nest would register its own listener for the same signals and close the app in parallel with the wait, so the delay silently never happens. At `shutdownDelayMs: 0` (the default) the helper simply *is* `enableShutdownHooks()`, so the single call is correct either way. With a delay it waits **inside the SIGTERM/SIGINT handler, before `close()` is entered** — a NestJS lifecycle hook cannot do this, because `close()` runs `onModuleDestroy` → `beforeApplicationShutdown` → dispose → `onApplicationShutdown`, i.e. a delay in a hook would wait with every module already torn down while the socket still accepts. A second signal cancels the pending wait and closes immediately. Warns above 10 000 ms, capped at 60 000 ms — keep it below the orchestrator grace period (Compose 10 s, Kubernetes 30 s) and below `installProcessDiagnostics()`'s 30 s force-exit |
218
222
  | **System Setup Module** | Initial admin creation for fresh deployments |
219
223
  | **Cron Jobs** | `CoreCronJobsService` with timezone/UTC offset support |
220
224
  | **Model Documentation** | Auto-generated model docs via `ModelDocService` |
@@ -425,6 +429,51 @@ The following diagram shows the exact order of execution from HTTP request to re
425
429
  +---------------------+
426
430
  ```
427
431
 
432
+ ### Shutdown Flow (SIGTERM / SIGINT)
433
+
434
+ The mirror image of the request flow, and the one place where an ordering mistake is invisible until
435
+ a rolling deploy drops requests. Installed in `main.ts` by `installGracefulShutdown(server)` — which
436
+ **replaces** `server.enableShutdownHooks()`, never accompanies it.
437
+
438
+ ```
439
+ SIGTERM / SIGINT
440
+ |
441
+ v
442
+ +-------------------------------------------------------------+
443
+ | installGracefulShutdown() signal handler |
444
+ | |
445
+ | shutdownDelayMs === 0 (default) |
446
+ | -> this IS app.enableShutdownHooks(): close() immediately |
447
+ | |
448
+ | shutdownDelayMs > 0 |
449
+ | -> stay FULLY HEALTHY for N ms (routes still served), |
450
+ | so the load balancer can finish deregistering |
451
+ | -> a second signal cancels the wait and closes now |
452
+ +----------------------------+---------------------------------+
453
+ | (only after the wait)
454
+ v
455
+ +-------------------------------------------------------------+
456
+ | app.close() |
457
+ | 1. onModuleDestroy |
458
+ | 2. beforeApplicationShutdown |
459
+ | 3. dispose (HTTP server socket closes HERE) |
460
+ | 4. onApplicationShutdown |
461
+ | - CoreRedisService quits every tracked connection |
462
+ +-------------------------------------------------------------+
463
+ ```
464
+
465
+ **Why the wait cannot be a lifecycle hook:** the socket only closes at step 3, so a delay placed in
466
+ `beforeApplicationShutdown` (step 2) would keep accepting traffic with every module already torn
467
+ down — strictly worse than not waiting at all.
468
+
469
+ **Why both together is a bug:** with `enableShutdownHooks()` also installed, Nest registers its own
470
+ listener for the same signals and enters `close()` in parallel with the wait. Nothing errors; the
471
+ delay simply never happens.
472
+
473
+ | Knob | Default | Notes |
474
+ |------|---------|-------|
475
+ | `shutdownDelayMs` | `0` (no delay, no log) | Warns above `10000`, capped at `60000`. Keep it below the orchestrator grace period (Compose `stop_grace_period` 10 s, Kubernetes `terminationGracePeriodSeconds` 30 s) **and** below `installProcessDiagnostics()`'s 30 s force-exit — exceed any and the process is SIGKILLed mid-wait with no hook running. Non-numeric/negative behaves like `0` |
476
+
428
477
  ---
429
478
 
430
479
  ## Phase 1: Incoming Request
@@ -33,8 +33,9 @@ Add this to your project's `pnpm-workspace.yaml` (pnpm 11+; in pnpm 10 and earli
33
33
  overrides:
34
34
  # @nestjs/graphql exact-pins ws@8.20.1 (GHSA-96hv-2xvq-fx4p, high, patched >=8.21.0).
35
35
  # An exact pin cannot resolve forward — the override is the only fix.
36
+ # Keep the target in LOCKSTEP with your direct `ws` dependency (see the note below).
36
37
  # Remove once @nestjs/graphql stops pinning it.
37
- 'ws@>=8.0.0 <8.21.0': '8.21.1'
38
+ 'ws@>=8.0.0 <8.21.0': '8.21.3'
38
39
 
39
40
  # @modelcontextprotocol/sdk declares @hono/node-server ^1.19.9 with no 1.x fix line
40
41
  # (GHSA-frvp-7c67-39w9, GHSA-9mqv-5hh9-4cgg). Deliberately a CROSS-MAJOR override.
@@ -49,6 +50,23 @@ overrides:
49
50
  'js-yaml@>=5.0.0 <5.2.2': '5.2.2'
50
51
  ```
51
52
 
53
+ ### The `ws` target must stay in lockstep with the declared `ws` version
54
+
55
+ `8.21.3` is not an arbitrary "latest patch" — it is the version `@lenne.tech/nest-server` declares as
56
+ an ordinary **dependency**, so it is already in your tree whether or not you list `ws` yourself.
57
+ The override target has to equal it.
58
+
59
+ Under `nodeLinker: hoisted` (what this framework and the starters use), a lower target does not
60
+ merely leave you one patch behind: it puts a **second, older `ws` copy** in the tree next to the
61
+ declared one. The transitive consumers resolve to the override target, the declared dependency stays
62
+ where its `package.json` pins it, and you now carry two `ws` versions — of which only one is visible
63
+ when you read a manifest. The target was raised `8.21.1` → `8.21.3` on 2026-08-10 for exactly this
64
+ reason.
65
+
66
+ **Rule:** whenever the `ws` version declared by `@lenne.tech/nest-server` (or by your own
67
+ `package.json`, if you list it) moves, move this override target with it in the same commit. The
68
+ same applies to any other override whose package also appears as a declared dependency.
69
+
52
70
  Then:
53
71
 
54
72
  ```bash
@@ -59,8 +77,8 @@ pnpm test # nothing should regress
59
77
 
60
78
  Commit `package.json`/`pnpm-workspace.yaml` **and** `pnpm-lock.yaml` together.
61
79
 
62
- > Projects generated from `nest-server-starter` or `lt-monorepo` already carry both entries. This
63
- > page is for projects that predate that, or that were assembled by hand.
80
+ > Projects generated from `nest-server-starter` or `lt-monorepo` already carry all three entries.
81
+ > This page is for projects that predate that, or that were assembled by hand.
64
82
 
65
83
  ## Rules for writing your own overrides
66
84
 
@@ -39,10 +39,22 @@ It now verifies chunk completeness before resolving, and **rejects** when the fi
39
39
  (removing the incomplete file so retries do not accumulate orphans).
40
40
 
41
41
  **What you may notice:** a seed migration that previously "succeeded" while silently storing a broken
42
- asset now fails. Since `docker-entrypoint.sh` defaults to `MIGRATE_FAILURE_POLICY=abort`, that failure
43
- keeps the container from starting.
42
+ asset now fails.
44
43
 
45
- **This is intentional** finding exactly this is why migrations run before the server. To recover:
44
+ **What that does to a deployment depends on the `docker-entrypoint.sh` your project copied check
45
+ yours, and check its default.**
46
+
47
+ | Your entrypoint | A failed migration |
48
+ |-----------------|--------------------|
49
+ | The one shipped with this framework | Refuses the start (`MIGRATE_FAILURE_POLICY` defaults to `abort`) |
50
+ | From `nest-server-starter` 11.32.4 or newer | Starts the server anyway — the same variable exists, but it defaults to `warn`. Set `MIGRATE_FAILURE_POLICY=abort` per stage to refuse the start |
51
+ | Older, without that variable | Starts the server anyway, with no way to change it short of updating the file |
52
+
53
+ In the two lower rows the failure is visible only in the container log, and the broken asset still
54
+ ships — so if you deploy from a starter-derived project, decide on `abort` explicitly rather than
55
+ assuming this release stops a bad boot for you.
56
+
57
+ **Failing is intentional** — finding exactly this is why migrations run before the server. To recover:
46
58
 
47
59
  ```bash
48
60
  # 1. Identify the incomplete file from the migration error, which names it: