@lenne.tech/nest-server 11.21.3 → 11.22.1

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 (57) hide show
  1. package/.claude/rules/architecture.md +79 -0
  2. package/.claude/rules/better-auth.md +262 -0
  3. package/.claude/rules/configurable-features.md +308 -0
  4. package/.claude/rules/core-modules.md +205 -0
  5. package/.claude/rules/framework-compatibility.md +79 -0
  6. package/.claude/rules/migration-guides.md +149 -0
  7. package/.claude/rules/module-deprecation.md +214 -0
  8. package/.claude/rules/module-inheritance.md +97 -0
  9. package/.claude/rules/package-management.md +112 -0
  10. package/.claude/rules/role-system.md +146 -0
  11. package/.claude/rules/testing.md +120 -0
  12. package/.claude/rules/versioning.md +53 -0
  13. package/CLAUDE.md +174 -0
  14. package/FRAMEWORK-API.md +231 -0
  15. package/dist/core/common/interfaces/server-options.interface.d.ts +10 -0
  16. package/dist/core/modules/error-code/error-code.module.js.map +1 -1
  17. package/dist/core.module.d.ts +3 -3
  18. package/dist/core.module.js +17 -4
  19. package/dist/core.module.js.map +1 -1
  20. package/dist/server/modules/file/file-info.model.d.ts +1 -5
  21. package/dist/server/modules/user/user.model.d.ts +1 -5
  22. package/dist/server/server.module.js +6 -6
  23. package/dist/server/server.module.js.map +1 -1
  24. package/dist/tsconfig.build.tsbuildinfo +1 -1
  25. package/docs/REQUEST-LIFECYCLE.md +1256 -0
  26. package/docs/error-codes.md +446 -0
  27. package/migration-guides/11.10.x-to-11.11.x.md +266 -0
  28. package/migration-guides/11.11.x-to-11.12.x.md +323 -0
  29. package/migration-guides/11.12.x-to-11.13.0.md +612 -0
  30. package/migration-guides/11.13.x-to-11.14.0.md +348 -0
  31. package/migration-guides/11.14.x-to-11.15.0.md +262 -0
  32. package/migration-guides/11.15.0-to-11.15.3.md +118 -0
  33. package/migration-guides/11.15.x-to-11.16.0.md +497 -0
  34. package/migration-guides/11.16.x-to-11.17.0.md +130 -0
  35. package/migration-guides/11.17.x-to-11.18.0.md +393 -0
  36. package/migration-guides/11.18.x-to-11.19.0.md +151 -0
  37. package/migration-guides/11.19.x-to-11.20.0.md +170 -0
  38. package/migration-guides/11.20.x-to-11.21.0.md +216 -0
  39. package/migration-guides/11.21.0-to-11.21.1.md +194 -0
  40. package/migration-guides/11.21.1-to-11.21.2.md +114 -0
  41. package/migration-guides/11.21.2-to-11.21.3.md +175 -0
  42. package/migration-guides/11.21.x-to-11.22.0.md +224 -0
  43. package/migration-guides/11.22.0-to-11.22.1.md +105 -0
  44. package/migration-guides/11.3.x-to-11.4.x.md +233 -0
  45. package/migration-guides/11.6.x-to-11.7.x.md +394 -0
  46. package/migration-guides/11.7.x-to-11.8.x.md +318 -0
  47. package/migration-guides/11.8.x-to-11.9.x.md +322 -0
  48. package/migration-guides/11.9.x-to-11.10.x.md +571 -0
  49. package/migration-guides/TEMPLATE.md +113 -0
  50. package/package.json +25 -18
  51. package/src/core/common/interfaces/server-options.interface.ts +83 -16
  52. package/src/core/modules/better-auth/CUSTOMIZATION.md +24 -17
  53. package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +5 -5
  54. package/src/core/modules/error-code/INTEGRATION-CHECKLIST.md +42 -12
  55. package/src/core/modules/error-code/error-code.module.ts +4 -9
  56. package/src/core.module.ts +52 -10
  57. package/src/server/server.module.ts +7 -9
@@ -0,0 +1,612 @@
1
+ # Migration Guide: 11.12.x → 11.13.0
2
+
3
+ ## Overview
4
+
5
+ | Category | Details |
6
+ |----------|---------|
7
+ | **Breaking Changes** | Email verification enabled by default, `termsAndPrivacyAccepted` required by default on sign-up |
8
+ | **New Features** | Email Verification service, Sign-Up Checks with `termsAndPrivacyAccepted`, `termsAndPrivacyAcceptedAt` user field, TestHelper cookie support |
9
+ | **Bugfixes** | Passkey login response enrichment, Express Response import fix, JWT mode session fallback, Middleware credential fallback (401 fix), RolesGuard REST controller fix |
10
+ | **Security** | `@apollo/server` 5.3.0 → 5.4.0 (DoS vulnerability fix) |
11
+ | **Removed** | `pm2` and `grunt` devDependencies (does not affect consuming projects) |
12
+ | **Migration Effort** | Low (~10 minutes) - Sign-up flow updates + optional email verification configuration |
13
+
14
+ ---
15
+
16
+ ## Quick Migration
17
+
18
+ ```bash
19
+ # Update package
20
+ npm install @lenne.tech/nest-server@11.13.0
21
+
22
+ # Verify build
23
+ npm run build
24
+
25
+ # Run tests
26
+ npm test
27
+ ```
28
+
29
+ **Note:** Email verification is now **enabled by default** (zero-config). Sign-up requires `termsAndPrivacyAccepted: true`. See Breaking Changes if you need to restore the previous behavior.
30
+
31
+ ---
32
+
33
+ ## What's New in 11.13.0
34
+
35
+ ### 1. Email Verification (enabled by default)
36
+
37
+ Email verification via Better-Auth's `emailVerification` plugin is now **enabled by default** without any configuration needed:
38
+
39
+ - Users receive a verification email after sign-up
40
+ - `verifiedAt` is automatically set when email is verified
41
+ - Templates provided in German (`de`) and English (`en`)
42
+ - Falls back to nest-server's built-in templates if no project templates exist
43
+
44
+ ```typescript
45
+ // Zero-config: email verification is active by default
46
+
47
+ // To customize:
48
+ betterAuth: {
49
+ emailVerification: {
50
+ expiresIn: 86400, // Token expiration in seconds (default: 24h)
51
+ template: 'custom-verify', // Custom template name
52
+ locale: 'en', // Template locale (default: 'en')
53
+ brevoTemplateId: 42, // Send via Brevo transactional API (optional)
54
+ },
55
+ }
56
+
57
+ // To disable email verification:
58
+ betterAuth: {
59
+ emailVerification: false,
60
+ }
61
+ ```
62
+
63
+ **Configuration behavior:**
64
+ - `undefined` / `null` (no config): **enabled** with defaults
65
+ - `true`: **enabled** with defaults
66
+ - `false`: **disabled**
67
+ - `{}`: **enabled** with defaults
68
+ - `{ locale: 'de' }`: **enabled** with custom settings
69
+ - `{ enabled: false }`: **disabled** (allows pre-configuration)
70
+
71
+ **Brevo Integration:** When `brevoTemplateId` is set and Brevo is configured (`config.brevo`), verification emails are sent via Brevo's transactional API instead of SMTP/EJS templates. Template variables: `name`, `link`, `appName`, `expiresIn`.
72
+
73
+ ### 2. Sign-Up Checks (enabled by default)
74
+
75
+ Sign-up validation is now **enabled by default** requiring `termsAndPrivacyAccepted: true`:
76
+
77
+ ```graphql
78
+ # Sign-up now requires termsAndPrivacyAccepted
79
+ mutation {
80
+ betterAuthSignUp(
81
+ email: "user@example.com"
82
+ password: "hashedPassword"
83
+ name: "User"
84
+ termsAndPrivacyAccepted: true # Required by default
85
+ ) {
86
+ success
87
+ user { id email }
88
+ }
89
+ }
90
+ ```
91
+
92
+ When accepted, `termsAndPrivacyAcceptedAt` is stored as a `Date` in the user record.
93
+
94
+ ```typescript
95
+ // To disable sign-up checks:
96
+ betterAuth: {
97
+ signUpChecks: false,
98
+ }
99
+
100
+ // To customize required fields:
101
+ betterAuth: {
102
+ signUpChecks: {
103
+ requiredFields: ['termsAndPrivacyAccepted', 'ageConfirmed'],
104
+ },
105
+ }
106
+ ```
107
+
108
+ ### 3. TestHelper Cookie Support
109
+
110
+ The `TestHelper` now supports cookie-based authentication for REST API testing, making it easy to test BetterAuth session-based endpoints:
111
+
112
+ ```typescript
113
+ // Auto-detection: plain session token -> automatically sets iam.session_token + token cookies
114
+ const result = await testHelper.rest('/protected-endpoint', {
115
+ cookies: sessionToken,
116
+ });
117
+
118
+ // Explicit cookie pairs
119
+ const result = await testHelper.rest('/protected-endpoint', {
120
+ cookies: { 'iam.session_token': token, 'custom': 'value' },
121
+ });
122
+
123
+ // Raw cookie string
124
+ const result = await testHelper.rest('/protected-endpoint', {
125
+ cookies: 'iam.session_token=abc; token=xyz',
126
+ });
127
+ ```
128
+
129
+ **New static helper methods:**
130
+
131
+ ```typescript
132
+ // Build BetterAuth cookie record from session token
133
+ const cookies = TestHelper.buildBetterAuthCookies(sessionToken);
134
+
135
+ // Extract session token from Set-Cookie response headers
136
+ const token = TestHelper.extractSessionToken(response);
137
+
138
+ // Extract all cookies from response
139
+ const allCookies = TestHelper.extractCookies(response);
140
+ ```
141
+
142
+ `token` (Authorization header) and `cookies` (Cookie header) can be used simultaneously without conflict.
143
+
144
+ Full documentation: `src/test/README.md`
145
+
146
+ ### 4. `termsAndPrivacyAcceptedAt` User Field
147
+
148
+ A new `termsAndPrivacyAcceptedAt` field is added to `CoreUserModel`:
149
+
150
+ ```typescript
151
+ // Available on user objects
152
+ user.termsAndPrivacyAcceptedAt // Date | undefined
153
+ ```
154
+
155
+ This field is automatically set when a user signs up with `termsAndPrivacyAccepted: true`.
156
+
157
+ ---
158
+
159
+ ## Breaking Changes
160
+
161
+ ### 1. Email Verification Now Enabled by Default
162
+
163
+ **Before (11.12.x):** Email verification was disabled when no `emailVerification` config was present.
164
+
165
+ **After (11.13.0):** Email verification is enabled by default. Users must verify their email after sign-up.
166
+
167
+ **Impact:** New sign-ups will trigger a verification email. Unverified users may be restricted depending on your role configuration (e.g., `S_VERIFIED`).
168
+
169
+ **To restore old behavior:**
170
+ ```typescript
171
+ // config.env.ts
172
+ betterAuth: {
173
+ emailVerification: false,
174
+ }
175
+ ```
176
+
177
+ ### 2. Sign-Up Now Requires `termsAndPrivacyAccepted`
178
+
179
+ **Impact:** Sign-up via BetterAuth will fail if `termsAndPrivacyAccepted: true` is not provided.
180
+
181
+ **Before (11.12.x):**
182
+ ```graphql
183
+ mutation {
184
+ betterAuthSignUp(email: "user@example.com", password: "pass", name: "User") {
185
+ success
186
+ }
187
+ }
188
+ ```
189
+
190
+ **After (11.13.0):**
191
+ ```graphql
192
+ mutation {
193
+ betterAuthSignUp(
194
+ email: "user@example.com"
195
+ password: "pass"
196
+ name: "User"
197
+ termsAndPrivacyAccepted: true # Now required!
198
+ ) {
199
+ success
200
+ }
201
+ }
202
+ ```
203
+
204
+ **To restore old behavior:**
205
+ ```typescript
206
+ // config.env.ts
207
+ betterAuth: {
208
+ signUpChecks: false,
209
+ }
210
+ ```
211
+
212
+ **For custom resolvers:** Update your `BetterAuthResolver` to include the new parameter and inject `CoreBetterAuthSignUpValidatorService`:
213
+
214
+ ```typescript
215
+ import { CoreBetterAuthSignUpValidatorService } from '@lenne.tech/nest-server';
216
+
217
+ constructor(
218
+ betterAuthService: CoreBetterAuthService,
219
+ userMapper: CoreBetterAuthUserMapper,
220
+ @Optional() signUpValidator?: CoreBetterAuthSignUpValidatorService,
221
+ ) {
222
+ super(betterAuthService, userMapper, signUpValidator);
223
+ }
224
+
225
+ @Mutation(() => CoreBetterAuthAuthModel)
226
+ @Roles(RoleEnum.S_EVERYONE)
227
+ override async betterAuthSignUp(
228
+ @Args('email') email: string,
229
+ @Args('password') password: string,
230
+ @Args('name', { nullable: true }) name?: string,
231
+ @Args('termsAndPrivacyAccepted', { nullable: true }) termsAndPrivacyAccepted?: boolean,
232
+ ): Promise<CoreBetterAuthAuthModel> {
233
+ return super.betterAuthSignUp(email, password, name, termsAndPrivacyAccepted);
234
+ }
235
+ ```
236
+
237
+ ---
238
+
239
+ ## Detailed Migration Steps
240
+
241
+ ### Step 1: Update Package
242
+
243
+ ```bash
244
+ npm install @lenne.tech/nest-server@11.13.0
245
+ ```
246
+
247
+ ### Step 2: Update Sign-Up Calls
248
+
249
+ If you have sign-up forms or API calls, add `termsAndPrivacyAccepted: true`:
250
+
251
+ **GraphQL:**
252
+ ```graphql
253
+ mutation {
254
+ betterAuthSignUp(
255
+ email: "user@example.com"
256
+ password: "hashedPassword"
257
+ name: "User"
258
+ termsAndPrivacyAccepted: true # Add this!
259
+ ) {
260
+ success
261
+ }
262
+ }
263
+ ```
264
+
265
+ **REST API:**
266
+ ```json
267
+ POST /iam/sign-up/email
268
+ {
269
+ "email": "user@example.com",
270
+ "password": "hashedPassword",
271
+ "name": "User",
272
+ "termsAndPrivacyAccepted": true
273
+ }
274
+ ```
275
+
276
+ **Or disable the requirement in config.env.ts:**
277
+ ```typescript
278
+ betterAuth: {
279
+ signUpChecks: false,
280
+ }
281
+ ```
282
+
283
+ ### Step 3: Update Custom Resolvers and Controllers (if applicable)
284
+
285
+ **Custom BetterAuthResolver:** Update to include:
286
+ 1. Import `CoreBetterAuthSignUpValidatorService`
287
+ 2. Add `@Optional() signUpValidator?` to constructor
288
+ 3. Add `termsAndPrivacyAccepted` parameter to `betterAuthSignUp` method
289
+
290
+ See the Breaking Changes section for the code example.
291
+
292
+ **Custom BetterAuthController:** Update to include:
293
+ 1. Import `CoreBetterAuthSignUpValidatorService`
294
+ 2. Add `@Optional() signUpValidator?` to constructor
295
+ 3. Pass it to `super()`:
296
+
297
+ ```typescript
298
+ import { CoreBetterAuthSignUpValidatorService } from '@lenne.tech/nest-server';
299
+
300
+ constructor(
301
+ betterAuthService: CoreBetterAuthService,
302
+ userMapper: CoreBetterAuthUserMapper,
303
+ configService: ConfigService,
304
+ @Optional() signUpValidator?: CoreBetterAuthSignUpValidatorService,
305
+ ) {
306
+ super(betterAuthService, userMapper, configService, signUpValidator);
307
+ }
308
+ ```
309
+
310
+ ### Step 4: Configure Email Verification (optional)
311
+
312
+ If you want to customize email verification behavior:
313
+
314
+ ```typescript
315
+ // config.env.ts
316
+ betterAuth: {
317
+ emailVerification: {
318
+ locale: 'de', // German email templates
319
+ expiresIn: 172800, // 48h instead of default 24h
320
+ template: 'my-verify', // Custom EJS template name
321
+ },
322
+ }
323
+ ```
324
+
325
+ Or create custom templates in your project's templates directory:
326
+ - `templates/email-verification-de.ejs` (German)
327
+ - `templates/email-verification-en.ejs` (English)
328
+ - `templates/email-verification.ejs` (Fallback)
329
+
330
+ Available template variables: `name`, `link`, `expiresIn`, `appName`.
331
+
332
+ ### Step 5: Test Authentication Flows
333
+
334
+ Test the following flows in your application:
335
+ - [ ] Sign-Up with `termsAndPrivacyAccepted: true` succeeds
336
+ - [ ] Sign-Up without `termsAndPrivacyAccepted` returns error `LTNS_0021`
337
+ - [ ] Email verification link appears in console (local/development mode)
338
+ - [ ] `verifiedAt` is set after email verification
339
+ - [ ] `termsAndPrivacyAcceptedAt` is stored in user record
340
+ - [ ] Email/Password Sign-In works for verified users
341
+ - [ ] Existing users (already verified) are not affected
342
+
343
+ ---
344
+
345
+ ## Compatibility Notes
346
+
347
+ ### Existing Users
348
+
349
+ Existing users in your database are **not affected** by the email verification change. Only new sign-ups trigger verification.
350
+
351
+ ### Projects Without BetterAuth
352
+
353
+ If your project does not use BetterAuth (`betterAuth` not configured), these changes have **no impact**.
354
+
355
+ ### Frontend Integration
356
+
357
+ Update your sign-up forms to include the `termsAndPrivacyAccepted` checkbox:
358
+
359
+ ```typescript
360
+ // Example: Nuxt/Vue
361
+ const signUp = async () => {
362
+ await authClient.signUp.email({
363
+ email: form.email,
364
+ password: form.password,
365
+ name: form.name,
366
+ termsAndPrivacyAccepted: form.termsAccepted, // Add this
367
+ });
368
+ };
369
+ ```
370
+
371
+ ---
372
+
373
+ ## Troubleshooting
374
+
375
+ ### Sign-Up Fails with Error LTNS_0021
376
+
377
+ **Cause:** `termsAndPrivacyAccepted` is not provided or is `false`.
378
+
379
+ **Solution:** Ensure your sign-up form sends `termsAndPrivacyAccepted: true`, or disable the check:
380
+ ```typescript
381
+ betterAuth: {
382
+ signUpChecks: false,
383
+ }
384
+ ```
385
+
386
+ ### Sign-In Fails with Error LTNS_0023
387
+
388
+ **Cause:** Email verification is enabled (default) and the user has not verified their email yet. The server rejects sign-in attempts with `#LTNS_0023: Email verification required`.
389
+
390
+ **Solution:**
391
+ 1. Ensure the user clicks the verification link sent via email (check console in local mode)
392
+ 2. Or disable email verification:
393
+ ```typescript
394
+ betterAuth: {
395
+ emailVerification: false,
396
+ }
397
+ ```
398
+
399
+ **Note:** This check also applies to 2FA verification (`verifyTotp`) and REST sign-in (`POST /iam/sign-in/email`). Unverified users are blocked from all authentication paths.
400
+
401
+ ### Users Cannot Sign In After Sign-Up
402
+
403
+ **Cause:** Email verification is enabled, and the user has not verified their email yet.
404
+
405
+ **Solution:** Check your email configuration (SMTP or Brevo). In local/development mode, the verification URL is printed to the console. Users need to click the verification link before signing in with `S_VERIFIED`-protected endpoints.
406
+
407
+ ### Email Verification Emails Not Sent
408
+
409
+ **Cause:** No email service configured (no SMTP and no Brevo).
410
+
411
+ **Solution:** Configure either SMTP or Brevo:
412
+ ```typescript
413
+ // SMTP
414
+ email: {
415
+ smtp: { host: 'smtp.example.com', port: 587 },
416
+ defaultSender: { email: 'no-reply@example.com', name: 'My App' },
417
+ }
418
+
419
+ // Or Brevo
420
+ brevo: {
421
+ apiKey: process.env.BREVO_API_KEY,
422
+ }
423
+ betterAuth: {
424
+ emailVerification: {
425
+ brevoTemplateId: 42,
426
+ },
427
+ }
428
+ ```
429
+
430
+ **Note:** The verification URL is always logged to the console regardless of email configuration.
431
+
432
+ ### 401 Errors After Switching from Cookie to JWT Mode
433
+
434
+ **Cause:** Stale httpOnly session cookies (`iam.session_token`) from a previous cookie-based configuration persist in the browser. These cookies are sent automatically with requests and can interfere with Bearer token authentication, as the server receives conflicting authentication sources.
435
+
436
+ **Solution:** httpOnly cookies cannot be cleared via JavaScript. Use server-side sign-out to clear them:
437
+ ```typescript
438
+ // Call sign-out endpoint with credentials to clear httpOnly cookies
439
+ await fetch('/api/iam/sign-out', { method: 'POST', credentials: 'include' });
440
+
441
+ // Then sign in fresh with the new configuration
442
+ ```
443
+
444
+ **Prevention:** When switching from `cookies: true` to `cookies: false`, ensure all users are signed out first.
445
+
446
+ ### BetterAuth Authentication Fails with `cookies: false`
447
+
448
+ **Cause:** When `cookies: false` is set without `betterAuth.jwt: true`, BetterAuth cannot establish sessions. The server will log a startup warning about this misconfiguration.
449
+
450
+ **Solution:** When using `cookies: false`, always enable the JWT plugin:
451
+ ```typescript
452
+ // config.env.ts
453
+ {
454
+ cookies: false,
455
+ betterAuth: {
456
+ jwt: true, // Required when cookies: false
457
+ },
458
+ }
459
+ ```
460
+
461
+ **Note:** Even with `jwt: true`, the BetterAuth programmatic API returns session tokens (not JWTs). The JWT plugin enriches only native HTTP handler responses. Session tokens work for authentication via `Authorization: Bearer <session-token>` header.
462
+
463
+ ---
464
+
465
+ ## Bugfixes
466
+
467
+ ### 1. Passkey Login Response Enrichment
468
+
469
+ Better Auth's `@better-auth/passkey` plugin returns only `{ session }` in the verify-authentication response, despite its OpenAPI spec declaring both `{ session, user }`. This caused the frontend to not receive user data after passkey login, preventing proper auth state setup and dashboard redirect.
470
+
471
+ **Fix:** The API middleware now enriches passkey verify-authentication responses by fetching user data from the database when the response only contains a session. No action needed from consumers.
472
+
473
+ ### 2. Express Response Import Fix
474
+
475
+ The API middleware imported `Response` from Express, which shadowed the global Web API `Response` constructor. This caused `new Response(...)` calls to fail silently in certain environments (e.g., Vitest SSR). The Express import is now aliased as `ExpressResponse`.
476
+
477
+ ### 3. JWT Mode Session Fallback
478
+
479
+ In JWT mode, the session middleware now resolves database sessions for JWT-authenticated users. This ensures that BetterAuth plugin endpoints (2FA, Passkey) can authenticate via session token, even when the client only sends a JWT.
480
+
481
+ The middleware also supports JWT tokens stored in cookies (`lt-jwt-token`), bridging the gap between cookie-based frontend storage and JWT verification.
482
+
483
+ ### 4. Cookie/JWT Startup Validation
484
+
485
+ The server now validates authentication configuration at startup and logs warnings for common misconfigurations:
486
+ - `cookies: false` without `betterAuth.jwt: true`
487
+ - Missing BetterAuth secret
488
+
489
+ ### 5. Cryptographically Secure ID Generation
490
+
491
+ The `generateId()` method in `CoreBetterAuthUserMapper` now uses `crypto.randomBytes(21)` instead of `Math.random()`. This ensures cryptographically secure random IDs for user mapping and internal token generation.
492
+
493
+ ### 6. Middleware Credential Fallback (401 Fix)
494
+
495
+ When a request included an **invalid Authorization header** alongside a **valid session cookie**, the middleware would return 401 instead of falling back to the cookie. This affected three areas:
496
+
497
+ - **`extractSessionToken()` in `core-better-auth-web.helper.ts`**: `isSessionToken()` returned `true` for non-JWT garbage in the Authorization header, preventing cookie fallback. Fix: Added `skipAuthHeader` option, used by Strategy 3 (cookie fallback) when the Auth header was already tried and failed.
498
+ - **`CoreBetterAuthModule.configure()`**: After `reset()` in tests, the `betterAuthEnabled` static field was `false` because the `createDeferredModule()` factory did not re-set it. This caused middleware to not be registered. Fix: `configure()` now only checks `this.betterAuthService?.isEnabled()` (injected instance) instead of the static field.
499
+ - **`createDeferredModule()` factory**: Now also sets `this.betterAuthEnabled = !!this.authInstance` for consistency with `forRootAsync()`.
500
+
501
+ No action needed from consumers — this is a purely internal fix.
502
+
503
+ ### 7. RolesGuard REST Controller Fix
504
+
505
+ `RolesGuard.getRequest()` failed for REST controllers because `GqlExecutionContext.create(context).getContext()` returns a truthy value (the `next` function) for HTTP contexts, but `.req` on it is `undefined`.
506
+
507
+ **Before:** `ctx.getContext() ? ctx.getContext().req : context.switchToHttp().getRequest()`
508
+ **After:** `ctx.getContext()?.req || context.switchToHttp().getRequest()`
509
+
510
+ No action needed from consumers — REST controllers with `@Roles()` now work correctly.
511
+
512
+ ---
513
+
514
+ ## Security Fix
515
+
516
+ ### `@apollo/server` Updated to 5.4.0
517
+
518
+ Updated from 5.3.0 to 5.4.0 to fix a **high severity DoS vulnerability**. No API changes — drop-in update.
519
+
520
+ **Action:** Run `npm install` after updating `@lenne.tech/nest-server`.
521
+
522
+ ---
523
+
524
+ ## Removed Dependencies
525
+
526
+ ### `pm2` and `grunt` Removed
527
+
528
+ The following devDependencies have been removed from nest-server:
529
+
530
+ | Package | Version | Reason |
531
+ |---------|---------|--------|
532
+ | `pm2` | 6.0.14 | No longer used, had low-severity ReDoS vulnerability |
533
+ | `grunt` | 1.6.1 | Only used for pm2-based production start |
534
+ | `grunt-bg-shell` | 2.3.3 | Grunt plugin |
535
+ | `grunt-contrib-clean` | 2.0.1 | Grunt plugin |
536
+ | `grunt-contrib-watch` | 1.1.0 | Grunt plugin |
537
+ | `grunt-sync` | 0.8.2 | Grunt plugin |
538
+
539
+ The `start:prod` script now uses `NODE_ENV=production node dist/main.js` instead of Grunt.
540
+
541
+ **Impact on consuming projects:** None — these were devDependencies of nest-server and not exposed to consumers. If your project uses pm2 independently, it is not affected.
542
+
543
+ ---
544
+
545
+ ## New Exports
546
+
547
+ The following are newly exported from `@lenne.tech/nest-server`:
548
+
549
+ ```typescript
550
+ // Email Verification Service
551
+ export { CoreBetterAuthEmailVerificationService } from './core/modules/better-auth/core-better-auth-email-verification.service';
552
+
553
+ // Sign-Up Validator Service
554
+ export { CoreBetterAuthSignUpValidatorService } from './core/modules/better-auth/core-better-auth-signup-validator.service';
555
+
556
+ // Configuration Interfaces
557
+ export { IBetterAuthEmailVerificationConfig, IBetterAuthSignUpChecksConfig } from './core/common/interfaces/server-options.interface';
558
+ ```
559
+
560
+ ---
561
+
562
+ ## New Test Files
563
+
564
+ | Test File | Coverage |
565
+ |-----------|----------|
566
+ | `tests/stories/better-auth-email-verification.story.test.ts` | Email verification flow, LTNS_0023 enforcement, sign-up with verification |
567
+ | `tests/stories/better-auth-jwt-middleware.story.test.ts` | JWT-to-session resolution, Authorization header priority over cookies, cookie-less mode session handling |
568
+ | `tests/stories/better-auth-security.e2e-spec.ts` | Cookie/JWT startup validation, security configuration checks |
569
+ | `tests/stories/middleware-credential-fallback.e2e-spec.ts` | Middleware credential fallback: all 3 strategies (Auth header, lt-jwt-token cookie, session cookie), invalid header + valid cookie, parallel auth mode |
570
+
571
+ ## TestHelper Documentation
572
+
573
+ Full reference for REST, GraphQL, and cookie-based testing:
574
+ - **Documentation:** [src/test/README.md](../src/test/README.md)
575
+
576
+ ---
577
+
578
+ ## Module Documentation
579
+
580
+ ### Better-Auth Module
581
+
582
+ - **README:** [src/core/modules/better-auth/README.md](../src/core/modules/better-auth/README.md)
583
+ - **Integration Checklist:** [src/core/modules/better-auth/INTEGRATION-CHECKLIST.md](../src/core/modules/better-auth/INTEGRATION-CHECKLIST.md)
584
+ - **Customization Guide:** [src/core/modules/better-auth/CUSTOMIZATION.md](../src/core/modules/better-auth/CUSTOMIZATION.md)
585
+ - **Reference Implementation:** `src/server/modules/iam/`
586
+ - **Key Files:**
587
+ - `core-better-auth-email-verification.service.ts` - Email verification logic and template resolution
588
+ - `core-better-auth-signup-validator.service.ts` - Sign-up validation with configurable required fields
589
+
590
+ ### Module Registration Patterns
591
+
592
+ When customizing BetterAuth, use the appropriate registration pattern:
593
+
594
+ | Pattern | Use When | Configuration |
595
+ |---------|----------|---------------|
596
+ | **Zero-Config** | No customization | `CoreModule.forRoot(envConfig)` |
597
+ | **Config-based** | Custom Controller/Resolver | `betterAuth: { controller, resolver }` |
598
+ | **Separate Module** | Full control, additional providers | `betterAuth: { autoRegister: false }` |
599
+
600
+ **See [CUSTOMIZATION.md](../src/core/modules/better-auth/CUSTOMIZATION.md) for detailed guidance on:**
601
+ - Customizing Controller, Resolver, and Services
602
+ - Email template customization (EJS and Brevo)
603
+ - Avoiding the "forRoot() called twice" warning
604
+
605
+ ---
606
+
607
+ ## References
608
+
609
+ - [Better-Auth Module](../src/core/modules/better-auth/) - Core module implementation
610
+ - [nest-server-starter](https://github.com/lenneTech/nest-server-starter) - Reference implementation
611
+ - [Better-Auth Documentation](https://www.better-auth.com/) - Official Better-Auth docs
612
+ - [Configurable Features Pattern](../.claude/rules/configurable-features.md) - Configuration patterns used