@lenne.tech/nest-server 11.7.1 → 11.7.3

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 (68) hide show
  1. package/dist/core/common/interfaces/server-options.interface.d.ts +18 -15
  2. package/dist/core/modules/auth/core-auth.controller.js +2 -2
  3. package/dist/core/modules/auth/core-auth.controller.js.map +1 -1
  4. package/dist/core/modules/auth/core-auth.resolver.js +2 -2
  5. package/dist/core/modules/auth/core-auth.resolver.js.map +1 -1
  6. package/dist/core/modules/auth/guards/roles.guard.d.ts +12 -2
  7. package/dist/core/modules/auth/guards/roles.guard.js +192 -5
  8. package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
  9. package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.js +1 -1
  10. package/dist/core/modules/auth/services/legacy-auth-rate-limiter.service.js.map +1 -1
  11. package/dist/core/modules/better-auth/better-auth-rate-limiter.service.js +1 -1
  12. package/dist/core/modules/better-auth/better-auth-rate-limiter.service.js.map +1 -1
  13. package/dist/core/modules/better-auth/better-auth-user.mapper.js +7 -55
  14. package/dist/core/modules/better-auth/better-auth-user.mapper.js.map +1 -1
  15. package/dist/core/modules/better-auth/better-auth.config.js +29 -10
  16. package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
  17. package/dist/core/modules/better-auth/better-auth.middleware.d.ts +1 -0
  18. package/dist/core/modules/better-auth/better-auth.middleware.js +55 -1
  19. package/dist/core/modules/better-auth/better-auth.middleware.js.map +1 -1
  20. package/dist/core/modules/better-auth/better-auth.module.d.ts +1 -1
  21. package/dist/core/modules/better-auth/better-auth.module.js +46 -18
  22. package/dist/core/modules/better-auth/better-auth.module.js.map +1 -1
  23. package/dist/core/modules/better-auth/better-auth.resolver.js +0 -11
  24. package/dist/core/modules/better-auth/better-auth.resolver.js.map +1 -1
  25. package/dist/core/modules/better-auth/better-auth.service.d.ts +22 -1
  26. package/dist/core/modules/better-auth/better-auth.service.js +209 -8
  27. package/dist/core/modules/better-auth/better-auth.service.js.map +1 -1
  28. package/dist/core/modules/better-auth/better-auth.types.d.ts +2 -0
  29. package/dist/core/modules/better-auth/better-auth.types.js.map +1 -1
  30. package/dist/core/modules/better-auth/core-better-auth.resolver.d.ts +5 -0
  31. package/dist/core/modules/better-auth/core-better-auth.resolver.js +58 -12
  32. package/dist/core/modules/better-auth/core-better-auth.resolver.js.map +1 -1
  33. package/dist/core/modules/user/core-user.service.d.ts +1 -0
  34. package/dist/core/modules/user/core-user.service.js +12 -0
  35. package/dist/core/modules/user/core-user.service.js.map +1 -1
  36. package/dist/core.module.js +6 -3
  37. package/dist/core.module.js.map +1 -1
  38. package/dist/server/modules/better-auth/better-auth.module.d.ts +1 -1
  39. package/dist/server/modules/better-auth/better-auth.module.js +2 -1
  40. package/dist/server/modules/better-auth/better-auth.module.js.map +1 -1
  41. package/dist/server/modules/better-auth/better-auth.resolver.d.ts +3 -0
  42. package/dist/server/modules/better-auth/better-auth.resolver.js +14 -11
  43. package/dist/server/modules/better-auth/better-auth.resolver.js.map +1 -1
  44. package/dist/server/modules/user/user.controller.js +0 -8
  45. package/dist/server/modules/user/user.controller.js.map +1 -1
  46. package/dist/tsconfig.build.tsbuildinfo +1 -1
  47. package/package.json +1 -1
  48. package/src/core/common/interfaces/server-options.interface.ts +129 -58
  49. package/src/core/modules/auth/core-auth.controller.ts +2 -2
  50. package/src/core/modules/auth/core-auth.resolver.ts +2 -2
  51. package/src/core/modules/auth/guards/roles.guard.ts +298 -5
  52. package/src/core/modules/auth/services/legacy-auth-rate-limiter.service.ts +1 -1
  53. package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +12 -11
  54. package/src/core/modules/better-auth/README.md +82 -43
  55. package/src/core/modules/better-auth/better-auth-rate-limiter.service.ts +1 -1
  56. package/src/core/modules/better-auth/better-auth-user.mapper.ts +9 -77
  57. package/src/core/modules/better-auth/better-auth.config.ts +45 -15
  58. package/src/core/modules/better-auth/better-auth.middleware.ts +85 -2
  59. package/src/core/modules/better-auth/better-auth.module.ts +83 -27
  60. package/src/core/modules/better-auth/better-auth.resolver.ts +0 -11
  61. package/src/core/modules/better-auth/better-auth.service.ts +367 -12
  62. package/src/core/modules/better-auth/better-auth.types.ts +16 -0
  63. package/src/core/modules/better-auth/core-better-auth.resolver.ts +111 -16
  64. package/src/core/modules/user/core-user.service.ts +27 -0
  65. package/src/core.module.ts +9 -3
  66. package/src/server/modules/better-auth/better-auth.module.ts +9 -3
  67. package/src/server/modules/better-auth/better-auth.resolver.ts +9 -11
  68. package/src/server/modules/user/user.controller.ts +1 -9
@@ -91,6 +91,33 @@ export abstract class CoreUserService<
91
91
  return this.process(async () => dbObject, { dbObject, serviceOptions });
92
92
  }
93
93
 
94
+ /**
95
+ * Get user by MongoDB ID or BetterAuth IAM ID
96
+ *
97
+ * This method is used by RolesGuard to resolve users from BetterAuth JWT tokens.
98
+ * The sub claim in BetterAuth JWTs can contain either:
99
+ * - The MongoDB _id of the user
100
+ * - The BetterAuth iamId
101
+ *
102
+ * @param idOrIamId - MongoDB _id or BetterAuth iamId
103
+ * @returns User object or null if not found
104
+ */
105
+ async getByIdOrIamId(idOrIamId: string): Promise<null | TUser> {
106
+ try {
107
+ // First, try to find by MongoDB _id
108
+ const byId = await this.mainDbModel.findById(idOrIamId).exec();
109
+ if (byId) {
110
+ return byId as TUser;
111
+ }
112
+ } catch {
113
+ // Invalid ObjectId format - try iamId instead
114
+ }
115
+
116
+ // Try to find by iamId
117
+ const byIamId = await this.mainDbModel.findOne({ iamId: idOrIamId }).exec();
118
+ return byIamId as null | TUser;
119
+ }
120
+
94
121
  /**
95
122
  * Get verified state of user by token
96
123
  */
@@ -233,11 +233,17 @@ export class CoreModule implements NestModule {
233
233
  // Add BetterAuthModule based on mode
234
234
  // IAM-only mode: Always register BetterAuthModule (required for subscription auth)
235
235
  // Legacy mode: Only register if autoRegister is explicitly true
236
- if (config.betterAuth?.enabled !== false) {
237
- if (isIamOnlyMode || config.betterAuth?.autoRegister === true) {
236
+ // betterAuth can be: boolean | IBetterAuth | undefined
237
+ const betterAuthConfig = config.betterAuth;
238
+ const isBetterAuthEnabled =
239
+ betterAuthConfig === true || (typeof betterAuthConfig === 'object' && betterAuthConfig?.enabled !== false);
240
+ const isAutoRegister = typeof betterAuthConfig === 'object' && betterAuthConfig?.autoRegister === true;
241
+
242
+ if (isBetterAuthEnabled) {
243
+ if (isIamOnlyMode || isAutoRegister) {
238
244
  imports.push(
239
245
  BetterAuthModule.forRoot({
240
- config: config.betterAuth || {},
246
+ config: betterAuthConfig === true ? {} : betterAuthConfig || {},
241
247
  // Pass JWT secrets for backwards compatibility fallback
242
248
  fallbackSecrets: [config.jwt?.secret, config.jwt?.refresh?.secret],
243
249
  }),
@@ -10,9 +10,13 @@ import { BetterAuthResolver } from './better-auth.resolver';
10
10
  */
11
11
  export interface ServerBetterAuthModuleOptions {
12
12
  /**
13
- * Better-auth configuration from environment
13
+ * Better-auth configuration.
14
+ * Accepts:
15
+ * - `true`: Enable with all defaults (including JWT)
16
+ * - `false`: Disable BetterAuth
17
+ * - `{ ... }`: Enable with custom configuration
14
18
  */
15
- config: IBetterAuth;
19
+ config: boolean | IBetterAuth;
16
20
 
17
21
  /**
18
22
  * Fallback secrets for backwards compatibility with JWT config.
@@ -63,7 +67,9 @@ export class BetterAuthModule {
63
67
  const { config, fallbackSecrets } = options;
64
68
 
65
69
  // If better-auth is explicitly disabled, return minimal module
66
- if (config?.enabled === false) {
70
+ // Supports: false, { enabled: false }, or undefined/null
71
+ const isDisabled = config === false || (typeof config === 'object' && config?.enabled === false);
72
+ if (isDisabled) {
67
73
  return {
68
74
  exports: [],
69
75
  module: BetterAuthModule,
@@ -1,11 +1,8 @@
1
- import { UseGuards } from '@nestjs/common';
2
1
  import { Args, Context, Mutation, Query, Resolver } from '@nestjs/graphql';
3
2
  import { Request, Response } from 'express';
4
3
 
5
4
  import { Roles } from '../../../core/common/decorators/roles.decorator';
6
5
  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
6
  import { BetterAuthAuthModel } from '../../../core/modules/better-auth/better-auth-auth.model';
10
7
  import { BetterAuthMigrationStatusModel } from '../../../core/modules/better-auth/better-auth-migration-status.model';
11
8
  import {
@@ -62,7 +59,6 @@ export class BetterAuthResolver extends CoreBetterAuthResolver {
62
59
  nullable: true,
63
60
  })
64
61
  @Roles(RoleEnum.S_USER)
65
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
66
62
  override async betterAuthSession(@Context() ctx: { req: Request }): Promise<BetterAuthSessionModel | null> {
67
63
  return super.betterAuthSession(ctx);
68
64
  }
@@ -87,12 +83,20 @@ export class BetterAuthResolver extends CoreBetterAuthResolver {
87
83
  return super.betterAuthMigrationStatus();
88
84
  }
89
85
 
86
+ @Query(() => String, {
87
+ description: 'Get fresh JWT token for the current session (requires valid session)',
88
+ nullable: true,
89
+ })
90
+ @Roles(RoleEnum.S_USER)
91
+ override async betterAuthToken(@Context() ctx: { req: Request }): Promise<null | string> {
92
+ return super.betterAuthToken(ctx);
93
+ }
94
+
90
95
  @Query(() => [BetterAuthPasskeyModel], {
91
96
  description: 'List passkeys for the current user',
92
97
  nullable: true,
93
98
  })
94
99
  @Roles(RoleEnum.S_USER)
95
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
96
100
  override async betterAuthListPasskeys(@Context() ctx: { req: Request }): Promise<BetterAuthPasskeyModel[] | null> {
97
101
  return super.betterAuthListPasskeys(ctx);
98
102
  }
@@ -127,7 +131,6 @@ export class BetterAuthResolver extends CoreBetterAuthResolver {
127
131
 
128
132
  @Mutation(() => Boolean, { description: 'Sign out via Better-Auth' })
129
133
  @Roles(RoleEnum.S_USER)
130
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
131
134
  override async betterAuthSignOut(@Context() ctx: { req: Request }): Promise<boolean> {
132
135
  return super.betterAuthSignOut(ctx);
133
136
  }
@@ -151,7 +154,6 @@ export class BetterAuthResolver extends CoreBetterAuthResolver {
151
154
  description: 'Enable 2FA for the current user',
152
155
  })
153
156
  @Roles(RoleEnum.S_USER)
154
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
155
157
  override async betterAuthEnable2FA(
156
158
  @Args('password') password: string,
157
159
  @Context() ctx: { req: Request },
@@ -163,7 +165,6 @@ export class BetterAuthResolver extends CoreBetterAuthResolver {
163
165
  description: 'Disable 2FA for the current user',
164
166
  })
165
167
  @Roles(RoleEnum.S_USER)
166
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
167
168
  override async betterAuthDisable2FA(
168
169
  @Args('password') password: string,
169
170
  @Context() ctx: { req: Request },
@@ -176,7 +177,6 @@ export class BetterAuthResolver extends CoreBetterAuthResolver {
176
177
  nullable: true,
177
178
  })
178
179
  @Roles(RoleEnum.S_USER)
179
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
180
180
  override async betterAuthGenerateBackupCodes(@Context() ctx: { req: Request }): Promise<null | string[]> {
181
181
  return super.betterAuthGenerateBackupCodes(ctx);
182
182
  }
@@ -189,7 +189,6 @@ export class BetterAuthResolver extends CoreBetterAuthResolver {
189
189
  description: 'Get passkey registration challenge for WebAuthn',
190
190
  })
191
191
  @Roles(RoleEnum.S_USER)
192
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
193
192
  override async betterAuthGetPasskeyChallenge(
194
193
  @Context() ctx: { req: Request },
195
194
  ): Promise<BetterAuthPasskeyChallengeModel> {
@@ -200,7 +199,6 @@ export class BetterAuthResolver extends CoreBetterAuthResolver {
200
199
  description: 'Delete a passkey by ID',
201
200
  })
202
201
  @Roles(RoleEnum.S_USER)
203
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
204
202
  override async betterAuthDeletePasskey(
205
203
  @Args('passkeyId') passkeyId: string,
206
204
  @Context() ctx: { req: Request },
@@ -1,4 +1,4 @@
1
- import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common';
1
+ import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from '@nestjs/common';
2
2
  import {
3
3
  ApiBearerAuth,
4
4
  ApiBody,
@@ -15,8 +15,6 @@ import { CurrentUser } from '../../../core/common/decorators/current-user.decora
15
15
  import { Roles } from '../../../core/common/decorators/roles.decorator';
16
16
  import { RoleEnum } from '../../../core/common/enums/role.enum';
17
17
  import { ServiceOptions } from '../../../core/common/interfaces/service-options.interface';
18
- import { AuthGuardStrategy } from '../../../core/modules/auth/auth-guard-strategy.enum';
19
- import { AuthGuard } from '../../../core/modules/auth/guards/auth.guard';
20
18
  import { UserCreateInput } from './inputs/user-create.input';
21
19
  import { UserInput } from './inputs/user.input';
22
20
  import { FindAndCountUsersResult } from './outputs/find-and-count-users-result.output';
@@ -48,7 +46,6 @@ export class UserController {
48
46
  @ApiOperation({ description: 'Find users (via filter)', summary: 'Get all users' })
49
47
  @Get()
50
48
  @Roles(RoleEnum.ADMIN)
51
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
52
49
  async findUsers(@CurrentUser() currentUser: User): Promise<User[]> {
53
50
  const serviceOptions: ServiceOptions = {
54
51
  currentUser,
@@ -67,7 +64,6 @@ export class UserController {
67
64
  })
68
65
  @Get('count')
69
66
  @Roles(RoleEnum.ADMIN)
70
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
71
67
  async findAndCountUsers(@CurrentUser() currentUser: User): Promise<FindAndCountUsersResult> {
72
68
  const serviceOptions: ServiceOptions = {
73
69
  currentUser,
@@ -99,7 +95,6 @@ export class UserController {
99
95
  @ApiParam({ description: 'User ID', name: 'id', type: String })
100
96
  @Get(':id')
101
97
  @Roles(RoleEnum.S_USER)
102
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
103
98
  async getUser(@CurrentUser() currentUser: User, @Param('id') id: string): Promise<User> {
104
99
  const serviceOptions: ServiceOptions = {
105
100
  currentUser,
@@ -121,7 +116,6 @@ export class UserController {
121
116
  @ApiOperation({ description: 'Create a new user', summary: 'Create user' })
122
117
  @Post()
123
118
  @Roles(RoleEnum.ADMIN)
124
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
125
119
  async createUser(@CurrentUser() currentUser: User, @Body() input: UserCreateInput): Promise<User> {
126
120
  const serviceOptions: ServiceOptions = {
127
121
  currentUser,
@@ -208,7 +202,6 @@ export class UserController {
208
202
  @ApiParam({ description: 'User ID', name: 'id', type: String })
209
203
  @Patch(':id')
210
204
  @Roles(RoleEnum.S_USER)
211
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
212
205
  async updateUser(@CurrentUser() currentUser: User, @Param('id') id: string, @Body() input: UserInput): Promise<User> {
213
206
  const serviceOptions: ServiceOptions = {
214
207
  currentUser,
@@ -231,7 +224,6 @@ export class UserController {
231
224
  @ApiParam({ description: 'User ID', name: 'id', type: String })
232
225
  @Delete(':id')
233
226
  @Roles(RoleEnum.S_USER)
234
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
235
227
  async deleteUser(@CurrentUser() currentUser: User, @Param('id') id: string): Promise<User> {
236
228
  const serviceOptions: ServiceOptions = {
237
229
  currentUser,