@lenne.tech/nest-server 11.6.2 → 11.7.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 (74) hide show
  1. package/dist/config.env.js +2 -11
  2. package/dist/config.env.js.map +1 -1
  3. package/dist/core/common/helpers/filter.helper.d.ts +9 -9
  4. package/dist/core/common/helpers/filter.helper.js +2 -4
  5. package/dist/core/common/helpers/filter.helper.js.map +1 -1
  6. package/dist/core/common/helpers/gridfs.helper.js +3 -3
  7. package/dist/core/common/helpers/gridfs.helper.js.map +1 -1
  8. package/dist/core/common/interfaces/server-options.interface.d.ts +4 -3
  9. package/dist/core/common/services/crud.service.d.ts +16 -16
  10. package/dist/core/common/services/crud.service.js +1 -1
  11. package/dist/core/common/services/crud.service.js.map +1 -1
  12. package/dist/core/modules/better-auth/better-auth-models.d.ts +0 -1
  13. package/dist/core/modules/better-auth/better-auth-models.js +0 -4
  14. package/dist/core/modules/better-auth/better-auth-models.js.map +1 -1
  15. package/dist/core/modules/better-auth/better-auth.config.js +3 -0
  16. package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
  17. package/dist/core/modules/better-auth/better-auth.module.d.ts +10 -2
  18. package/dist/core/modules/better-auth/better-auth.module.js +40 -52
  19. package/dist/core/modules/better-auth/better-auth.module.js.map +1 -1
  20. package/dist/core/modules/better-auth/better-auth.resolver.d.ts +8 -12
  21. package/dist/core/modules/better-auth/better-auth.resolver.js +33 -351
  22. package/dist/core/modules/better-auth/better-auth.resolver.js.map +1 -1
  23. package/dist/core/modules/better-auth/better-auth.service.d.ts +0 -1
  24. package/dist/core/modules/better-auth/better-auth.service.js +0 -3
  25. package/dist/core/modules/better-auth/better-auth.service.js.map +1 -1
  26. package/dist/core/modules/better-auth/better-auth.types.d.ts +9 -8
  27. package/dist/core/modules/better-auth/better-auth.types.js +14 -3
  28. package/dist/core/modules/better-auth/better-auth.types.js.map +1 -1
  29. package/dist/core/modules/better-auth/core-better-auth.controller.d.ts +66 -0
  30. package/dist/core/modules/better-auth/core-better-auth.controller.js +491 -0
  31. package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -0
  32. package/dist/core/modules/better-auth/core-better-auth.resolver.d.ts +59 -0
  33. package/dist/core/modules/better-auth/core-better-auth.resolver.js +538 -0
  34. package/dist/core/modules/better-auth/core-better-auth.resolver.js.map +1 -0
  35. package/dist/core/modules/better-auth/index.d.ts +2 -0
  36. package/dist/core/modules/better-auth/index.js +2 -0
  37. package/dist/core/modules/better-auth/index.js.map +1 -1
  38. package/dist/core.module.js +1 -1
  39. package/dist/core.module.js.map +1 -1
  40. package/dist/server/modules/better-auth/better-auth.controller.d.ts +10 -0
  41. package/dist/server/modules/better-auth/better-auth.controller.js +36 -0
  42. package/dist/server/modules/better-auth/better-auth.controller.js.map +1 -0
  43. package/dist/server/modules/better-auth/better-auth.module.d.ts +9 -0
  44. package/dist/server/modules/better-auth/better-auth.module.js +44 -0
  45. package/dist/server/modules/better-auth/better-auth.module.js.map +1 -0
  46. package/dist/server/modules/better-auth/better-auth.resolver.d.ts +45 -0
  47. package/dist/server/modules/better-auth/better-auth.resolver.js +221 -0
  48. package/dist/server/modules/better-auth/better-auth.resolver.js.map +1 -0
  49. package/dist/server/modules/file/file-info.model.d.ts +71 -3
  50. package/dist/server/modules/user/user.model.d.ts +169 -3
  51. package/dist/server/server.module.js +6 -1
  52. package/dist/server/server.module.js.map +1 -1
  53. package/dist/tsconfig.build.tsbuildinfo +1 -1
  54. package/package.json +20 -29
  55. package/src/config.env.ts +2 -11
  56. package/src/core/common/helpers/filter.helper.ts +15 -17
  57. package/src/core/common/helpers/gridfs.helper.ts +5 -5
  58. package/src/core/common/interfaces/server-options.interface.ts +47 -14
  59. package/src/core/common/services/crud.service.ts +22 -22
  60. package/src/core/modules/better-auth/README.md +365 -39
  61. package/src/core/modules/better-auth/better-auth-models.ts +0 -3
  62. package/src/core/modules/better-auth/better-auth.config.ts +5 -0
  63. package/src/core/modules/better-auth/better-auth.module.ts +107 -66
  64. package/src/core/modules/better-auth/better-auth.resolver.ts +88 -553
  65. package/src/core/modules/better-auth/better-auth.service.ts +0 -9
  66. package/src/core/modules/better-auth/better-auth.types.ts +25 -10
  67. package/src/core/modules/better-auth/core-better-auth.controller.ts +605 -0
  68. package/src/core/modules/better-auth/core-better-auth.resolver.ts +705 -0
  69. package/src/core/modules/better-auth/index.ts +8 -1
  70. package/src/core.module.ts +3 -2
  71. package/src/server/modules/better-auth/better-auth.controller.ts +41 -0
  72. package/src/server/modules/better-auth/better-auth.module.ts +88 -0
  73. package/src/server/modules/better-auth/better-auth.resolver.ts +201 -0
  74. package/src/server/server.module.ts +10 -1
@@ -8,8 +8,13 @@
8
8
  * - Two-Factor Authentication (TOTP)
9
9
  * - Passkey/WebAuthn authentication
10
10
  * - Social Login (Google, GitHub, Apple)
11
- * - Legacy password handling for migration
12
11
  * - Rate limiting for brute-force protection
12
+ * - Parallel operation with Legacy Auth (bcrypt compatible)
13
+ *
14
+ * Extension points:
15
+ * - CoreBetterAuthController: Abstract controller for REST extension
16
+ * - CoreBetterAuthResolver: Abstract resolver for GraphQL extension (isAbstract: true)
17
+ * - BetterAuthController/BetterAuthResolver: Default implementations
13
18
  */
14
19
 
15
20
  export * from './better-auth-auth.model';
@@ -23,3 +28,5 @@ export * from './better-auth.module';
23
28
  export * from './better-auth.resolver';
24
29
  export * from './better-auth.service';
25
30
  export * from './better-auth.types';
31
+ export * from './core-better-auth.controller';
32
+ export * from './core-better-auth.resolver';
@@ -229,8 +229,9 @@ export class CoreModule implements NestModule {
229
229
  imports.push(CoreHealthCheckModule);
230
230
  }
231
231
 
232
- // Add BetterAuthModule - enabled by default unless explicitly disabled
233
- if (config.betterAuth?.enabled !== false) {
232
+ // Add BetterAuthModule only if autoRegister is explicitly true
233
+ // By default (autoRegister: false), projects integrate via an extended module in their project
234
+ if (config.betterAuth?.enabled !== false && config.betterAuth?.autoRegister === true) {
234
235
  imports.push(
235
236
  BetterAuthModule.forRoot({
236
237
  config: config.betterAuth || {},
@@ -0,0 +1,41 @@
1
+ import { Controller } from '@nestjs/common';
2
+
3
+ import { Roles } from '../../../core/common/decorators/roles.decorator';
4
+ import { RoleEnum } from '../../../core/common/enums/role.enum';
5
+ import { ConfigService } from '../../../core/common/services/config.service';
6
+ import { BetterAuthUserMapper } from '../../../core/modules/better-auth/better-auth-user.mapper';
7
+ import { BetterAuthService } from '../../../core/modules/better-auth/better-auth.service';
8
+ import { CoreBetterAuthController } from '../../../core/modules/better-auth/core-better-auth.controller';
9
+
10
+ /**
11
+ * Server BetterAuth REST Controller
12
+ *
13
+ * This controller extends CoreBetterAuthController and can be customized
14
+ * for project-specific requirements (e.g., sending welcome emails,
15
+ * custom validation, audit logging).
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * // Add custom behavior after sign-up
20
+ * override async signUp(res: Response, input: BetterAuthSignUpInput) {
21
+ * const result = await super.signUp(res, input);
22
+ *
23
+ * if (result.success && result.user) {
24
+ * await this.emailService.sendWelcomeEmail(result.user.email);
25
+ * }
26
+ *
27
+ * return result;
28
+ * }
29
+ * ```
30
+ */
31
+ @Controller('iam')
32
+ @Roles(RoleEnum.ADMIN)
33
+ export class BetterAuthController extends CoreBetterAuthController {
34
+ constructor(
35
+ protected override readonly betterAuthService: BetterAuthService,
36
+ protected override readonly userMapper: BetterAuthUserMapper,
37
+ protected override readonly configService: ConfigService,
38
+ ) {
39
+ super(betterAuthService, userMapper, configService);
40
+ }
41
+ }
@@ -0,0 +1,88 @@
1
+ import { DynamicModule, Module } from '@nestjs/common';
2
+
3
+ import { IBetterAuth } from '../../../core/common/interfaces/server-options.interface';
4
+ import { BetterAuthModule as CoreBetterAuthModule } from '../../../core/modules/better-auth/better-auth.module';
5
+ import { BetterAuthController } from './better-auth.controller';
6
+ import { BetterAuthResolver } from './better-auth.resolver';
7
+
8
+ /**
9
+ * Options for BetterAuthModule.forRoot()
10
+ */
11
+ export interface ServerBetterAuthModuleOptions {
12
+ /**
13
+ * Better-auth configuration from environment
14
+ */
15
+ config: IBetterAuth;
16
+
17
+ /**
18
+ * Fallback secrets for backwards compatibility with JWT config.
19
+ * If no betterAuth.secret is configured, these secrets are tried in order.
20
+ */
21
+ fallbackSecrets?: (string | undefined)[];
22
+ }
23
+
24
+ /**
25
+ * Server BetterAuthModule - Project-specific Better-Auth integration
26
+ *
27
+ * This module wraps the core BetterAuthModule and provides project-specific
28
+ * customization through the BetterAuthController and BetterAuthResolver.
29
+ *
30
+ * Following the same pattern as src/server/modules/auth/auth.module.ts:
31
+ * - Core module provides abstract/base functionality
32
+ * - Server module provides project-specific implementations
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * // In server.module.ts
37
+ * import { BetterAuthModule } from './modules/better-auth/better-auth.module';
38
+ *
39
+ * @Module({
40
+ * imports: [
41
+ * CoreModule.forRoot(CoreAuthService, AuthModule.forRoot(envConfig.jwt), {
42
+ * ...envConfig,
43
+ * betterAuth: { ...envConfig.betterAuth, autoRegister: false },
44
+ * }),
45
+ * BetterAuthModule.forRoot({
46
+ * config: envConfig.betterAuth,
47
+ * fallbackSecrets: [envConfig.jwt?.secret, envConfig.jwt?.refresh?.secret],
48
+ * }),
49
+ * ],
50
+ * })
51
+ * export class ServerModule {}
52
+ * ```
53
+ */
54
+ @Module({})
55
+ export class BetterAuthModule {
56
+ /**
57
+ * Creates a dynamic module with project-specific Better-Auth configuration
58
+ *
59
+ * @param options - Configuration options
60
+ * @returns Dynamic module configuration
61
+ */
62
+ static forRoot(options: ServerBetterAuthModuleOptions): DynamicModule {
63
+ const { config, fallbackSecrets } = options;
64
+
65
+ // If better-auth is explicitly disabled, return minimal module
66
+ if (config?.enabled === false) {
67
+ return {
68
+ exports: [],
69
+ module: BetterAuthModule,
70
+ providers: [],
71
+ };
72
+ }
73
+
74
+ return {
75
+ exports: [CoreBetterAuthModule],
76
+ imports: [
77
+ CoreBetterAuthModule.forRoot({
78
+ config,
79
+ controller: BetterAuthController,
80
+ fallbackSecrets,
81
+ resolver: BetterAuthResolver,
82
+ }),
83
+ ],
84
+ module: BetterAuthModule,
85
+ providers: [],
86
+ };
87
+ }
88
+ }
@@ -0,0 +1,201 @@
1
+ import { UseGuards } from '@nestjs/common';
2
+ import { Args, Context, Mutation, Query, Resolver } from '@nestjs/graphql';
3
+ import { Request, Response } from 'express';
4
+
5
+ import { Roles } from '../../../core/common/decorators/roles.decorator';
6
+ import { RoleEnum } from '../../../core/common/enums/role.enum';
7
+ import { AuthGuardStrategy } from '../../../core/modules/auth/auth-guard-strategy.enum';
8
+ import { AuthGuard } from '../../../core/modules/auth/guards/auth.guard';
9
+ import { BetterAuthAuthModel } from '../../../core/modules/better-auth/better-auth-auth.model';
10
+ import {
11
+ BetterAuth2FASetupModel,
12
+ BetterAuthFeaturesModel,
13
+ BetterAuthPasskeyChallengeModel,
14
+ BetterAuthPasskeyModel,
15
+ BetterAuthSessionModel,
16
+ } from '../../../core/modules/better-auth/better-auth-models';
17
+ import { BetterAuthUserMapper } from '../../../core/modules/better-auth/better-auth-user.mapper';
18
+ import { BetterAuthService } from '../../../core/modules/better-auth/better-auth.service';
19
+ import { CoreBetterAuthResolver } from '../../../core/modules/better-auth/core-better-auth.resolver';
20
+
21
+ /**
22
+ * Server BetterAuth GraphQL Resolver
23
+ *
24
+ * This resolver extends CoreBetterAuthResolver and exposes all GraphQL operations.
25
+ * The `isAbstract: true` pattern in NestJS GraphQL requires concrete classes to
26
+ * explicitly override and decorate methods for them to be registered in the schema.
27
+ *
28
+ * Each method delegates to the parent implementation via `super.methodName()`.
29
+ * Override any method to add custom behavior (e.g., sending welcome emails after signup).
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * // Add custom behavior after sign-up
34
+ * override async betterAuthSignUp(email: string, password: string, name?: string) {
35
+ * const result = await super.betterAuthSignUp(email, password, name);
36
+ *
37
+ * if (result.success && result.user) {
38
+ * await this.emailService.sendWelcomeEmail(result.user.email);
39
+ * }
40
+ *
41
+ * return result;
42
+ * }
43
+ * ```
44
+ */
45
+ @Resolver(() => BetterAuthAuthModel)
46
+ @Roles(RoleEnum.ADMIN)
47
+ export class BetterAuthResolver extends CoreBetterAuthResolver {
48
+ constructor(
49
+ protected override readonly betterAuthService: BetterAuthService,
50
+ protected override readonly userMapper: BetterAuthUserMapper,
51
+ ) {
52
+ super(betterAuthService, userMapper);
53
+ }
54
+
55
+ // ===========================================================================
56
+ // Queries
57
+ // ===========================================================================
58
+
59
+ @Query(() => BetterAuthSessionModel, {
60
+ description: 'Get current Better-Auth session',
61
+ nullable: true,
62
+ })
63
+ @Roles(RoleEnum.S_USER)
64
+ @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
65
+ override async betterAuthSession(@Context() ctx: { req: Request }): Promise<BetterAuthSessionModel | null> {
66
+ return super.betterAuthSession(ctx);
67
+ }
68
+
69
+ @Query(() => Boolean, { description: 'Check if Better-Auth is enabled' })
70
+ @Roles(RoleEnum.S_EVERYONE)
71
+ override betterAuthEnabled(): boolean {
72
+ return super.betterAuthEnabled();
73
+ }
74
+
75
+ @Query(() => BetterAuthFeaturesModel, { description: 'Get enabled Better-Auth features' })
76
+ @Roles(RoleEnum.S_EVERYONE)
77
+ override betterAuthFeatures(): BetterAuthFeaturesModel {
78
+ return super.betterAuthFeatures();
79
+ }
80
+
81
+ @Query(() => [BetterAuthPasskeyModel], {
82
+ description: 'List passkeys for the current user',
83
+ nullable: true,
84
+ })
85
+ @Roles(RoleEnum.S_USER)
86
+ @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
87
+ override async betterAuthListPasskeys(@Context() ctx: { req: Request }): Promise<BetterAuthPasskeyModel[] | null> {
88
+ return super.betterAuthListPasskeys(ctx);
89
+ }
90
+
91
+ // ===========================================================================
92
+ // Authentication Mutations
93
+ // ===========================================================================
94
+
95
+ @Mutation(() => BetterAuthAuthModel, {
96
+ description: 'Sign in via Better-Auth (email/password)',
97
+ })
98
+ @Roles(RoleEnum.S_EVERYONE)
99
+ override async betterAuthSignIn(
100
+ @Args('email') email: string,
101
+ @Args('password') password: string,
102
+ @Context() ctx: { req: Request; res: Response },
103
+ ): Promise<BetterAuthAuthModel> {
104
+ return super.betterAuthSignIn(email, password, ctx);
105
+ }
106
+
107
+ @Mutation(() => BetterAuthAuthModel, {
108
+ description: 'Sign up via Better-Auth (email/password)',
109
+ })
110
+ @Roles(RoleEnum.S_EVERYONE)
111
+ override async betterAuthSignUp(
112
+ @Args('email') email: string,
113
+ @Args('password') password: string,
114
+ @Args('name', { nullable: true }) name?: string,
115
+ ): Promise<BetterAuthAuthModel> {
116
+ return super.betterAuthSignUp(email, password, name);
117
+ }
118
+
119
+ @Mutation(() => Boolean, { description: 'Sign out via Better-Auth' })
120
+ @Roles(RoleEnum.S_USER)
121
+ @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
122
+ override async betterAuthSignOut(@Context() ctx: { req: Request }): Promise<boolean> {
123
+ return super.betterAuthSignOut(ctx);
124
+ }
125
+
126
+ // ===========================================================================
127
+ // 2FA Mutations
128
+ // ===========================================================================
129
+
130
+ @Mutation(() => BetterAuthAuthModel, {
131
+ description: 'Verify 2FA code during sign-in',
132
+ })
133
+ @Roles(RoleEnum.S_EVERYONE)
134
+ override async betterAuthVerify2FA(
135
+ @Args('code') code: string,
136
+ @Context() ctx: { req: Request },
137
+ ): Promise<BetterAuthAuthModel> {
138
+ return super.betterAuthVerify2FA(code, ctx);
139
+ }
140
+
141
+ @Mutation(() => BetterAuth2FASetupModel, {
142
+ description: 'Enable 2FA for the current user',
143
+ })
144
+ @Roles(RoleEnum.S_USER)
145
+ @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
146
+ override async betterAuthEnable2FA(
147
+ @Args('password') password: string,
148
+ @Context() ctx: { req: Request },
149
+ ): Promise<BetterAuth2FASetupModel> {
150
+ return super.betterAuthEnable2FA(password, ctx);
151
+ }
152
+
153
+ @Mutation(() => Boolean, {
154
+ description: 'Disable 2FA for the current user',
155
+ })
156
+ @Roles(RoleEnum.S_USER)
157
+ @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
158
+ override async betterAuthDisable2FA(
159
+ @Args('password') password: string,
160
+ @Context() ctx: { req: Request },
161
+ ): Promise<boolean> {
162
+ return super.betterAuthDisable2FA(password, ctx);
163
+ }
164
+
165
+ @Mutation(() => [String], {
166
+ description: 'Generate new backup codes for 2FA',
167
+ nullable: true,
168
+ })
169
+ @Roles(RoleEnum.S_USER)
170
+ @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
171
+ override async betterAuthGenerateBackupCodes(@Context() ctx: { req: Request }): Promise<null | string[]> {
172
+ return super.betterAuthGenerateBackupCodes(ctx);
173
+ }
174
+
175
+ // ===========================================================================
176
+ // Passkey Mutations
177
+ // ===========================================================================
178
+
179
+ @Mutation(() => BetterAuthPasskeyChallengeModel, {
180
+ description: 'Get passkey registration challenge for WebAuthn',
181
+ })
182
+ @Roles(RoleEnum.S_USER)
183
+ @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
184
+ override async betterAuthGetPasskeyChallenge(
185
+ @Context() ctx: { req: Request },
186
+ ): Promise<BetterAuthPasskeyChallengeModel> {
187
+ return super.betterAuthGetPasskeyChallenge(ctx);
188
+ }
189
+
190
+ @Mutation(() => Boolean, {
191
+ description: 'Delete a passkey by ID',
192
+ })
193
+ @Roles(RoleEnum.S_USER)
194
+ @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
195
+ override async betterAuthDeletePasskey(
196
+ @Args('passkeyId') passkeyId: string,
197
+ @Context() ctx: { req: Request },
198
+ ): Promise<boolean> {
199
+ return super.betterAuthDeletePasskey(passkeyId, ctx);
200
+ }
201
+ }
@@ -10,6 +10,7 @@ import { CoreAuthService } from '../core/modules/auth/services/core-auth.service
10
10
  import { CronJobs } from './common/services/cron-jobs.service';
11
11
  import { AuthController } from './modules/auth/auth.controller';
12
12
  import { AuthModule } from './modules/auth/auth.module';
13
+ import { BetterAuthModule } from './modules/better-auth/better-auth.module';
13
14
  import { FileModule } from './modules/file/file.module';
14
15
  import { ServerController } from './server.controller';
15
16
 
@@ -24,11 +25,12 @@ import { ServerController } from './server.controller';
24
25
  controllers: [ServerController, AuthController],
25
26
 
26
27
  // Export modules for reuse in other modules
27
- exports: [CoreModule, AuthModule, FileModule],
28
+ exports: [CoreModule, AuthModule, BetterAuthModule, FileModule],
28
29
 
29
30
  // Include modules
30
31
  imports: [
31
32
  // Include CoreModule for standard processes
33
+ // Note: BetterAuthModule is imported manually below (autoRegister defaults to false)
32
34
  CoreModule.forRoot(CoreAuthService, AuthModule.forRoot(envConfig.jwt), envConfig),
33
35
 
34
36
  // Include cron job handling
@@ -38,6 +40,13 @@ import { ServerController } from './server.controller';
38
40
  // which will also include UserModule
39
41
  AuthModule.forRoot(envConfig.jwt),
40
42
 
43
+ // Include BetterAuthModule for better-auth integration
44
+ // This allows project-specific customization via BetterAuthResolver
45
+ BetterAuthModule.forRoot({
46
+ config: envConfig.betterAuth,
47
+ fallbackSecrets: [envConfig.jwt?.secret, envConfig.jwt?.refresh?.secret],
48
+ }),
49
+
41
50
  // Include FileModule for file handling
42
51
  FileModule,
43
52
  ],