@lenne.tech/nest-server 11.6.1 → 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 (120) hide show
  1. package/dist/config.env.js +132 -0
  2. package/dist/config.env.js.map +1 -1
  3. package/dist/core/common/decorators/graphql-populate.decorator.d.ts +2 -2
  4. package/dist/core/common/decorators/restricted.decorator.d.ts +1 -0
  5. package/dist/core/common/decorators/restricted.decorator.js +1 -1
  6. package/dist/core/common/decorators/restricted.decorator.js.map +1 -1
  7. package/dist/core/common/helpers/filter.helper.d.ts +9 -9
  8. package/dist/core/common/helpers/filter.helper.js +2 -4
  9. package/dist/core/common/helpers/filter.helper.js.map +1 -1
  10. package/dist/core/common/helpers/gridfs.helper.js +3 -3
  11. package/dist/core/common/helpers/gridfs.helper.js.map +1 -1
  12. package/dist/core/common/helpers/input.helper.d.ts +1 -0
  13. package/dist/core/common/helpers/input.helper.js +1 -1
  14. package/dist/core/common/helpers/input.helper.js.map +1 -1
  15. package/dist/core/common/interfaces/server-options.interface.d.ts +51 -0
  16. package/dist/core/common/services/crud.service.d.ts +16 -16
  17. package/dist/core/common/services/crud.service.js +1 -1
  18. package/dist/core/common/services/crud.service.js.map +1 -1
  19. package/dist/core/modules/auth/auth-guard-strategy.enum.d.ts +1 -0
  20. package/dist/core/modules/auth/auth-guard-strategy.enum.js +1 -0
  21. package/dist/core/modules/auth/auth-guard-strategy.enum.js.map +1 -1
  22. package/dist/core/modules/auth/guards/auth.guard.js +11 -5
  23. package/dist/core/modules/auth/guards/auth.guard.js.map +1 -1
  24. package/dist/core/modules/auth/tokens.decorator.d.ts +1 -1
  25. package/dist/core/modules/better-auth/better-auth-auth.model.d.ts +9 -0
  26. package/dist/core/modules/better-auth/better-auth-auth.model.js +63 -0
  27. package/dist/core/modules/better-auth/better-auth-auth.model.js.map +1 -0
  28. package/dist/core/modules/better-auth/better-auth-models.d.ts +43 -0
  29. package/dist/core/modules/better-auth/better-auth-models.js +181 -0
  30. package/dist/core/modules/better-auth/better-auth-models.js.map +1 -0
  31. package/dist/core/modules/better-auth/better-auth-rate-limit.middleware.d.ts +12 -0
  32. package/dist/core/modules/better-auth/better-auth-rate-limit.middleware.js +70 -0
  33. package/dist/core/modules/better-auth/better-auth-rate-limit.middleware.js.map +1 -0
  34. package/dist/core/modules/better-auth/better-auth-rate-limiter.service.d.ts +32 -0
  35. package/dist/core/modules/better-auth/better-auth-rate-limiter.service.js +173 -0
  36. package/dist/core/modules/better-auth/better-auth-rate-limiter.service.js.map +1 -0
  37. package/dist/core/modules/better-auth/better-auth-user.mapper.d.ts +43 -0
  38. package/dist/core/modules/better-auth/better-auth-user.mapper.js +159 -0
  39. package/dist/core/modules/better-auth/better-auth-user.mapper.js.map +1 -0
  40. package/dist/core/modules/better-auth/better-auth.config.d.ts +9 -0
  41. package/dist/core/modules/better-auth/better-auth.config.js +254 -0
  42. package/dist/core/modules/better-auth/better-auth.config.js.map +1 -0
  43. package/dist/core/modules/better-auth/better-auth.middleware.d.ts +20 -0
  44. package/dist/core/modules/better-auth/better-auth.middleware.js +79 -0
  45. package/dist/core/modules/better-auth/better-auth.middleware.js.map +1 -0
  46. package/dist/core/modules/better-auth/better-auth.module.d.ts +38 -0
  47. package/dist/core/modules/better-auth/better-auth.module.js +253 -0
  48. package/dist/core/modules/better-auth/better-auth.module.js.map +1 -0
  49. package/dist/core/modules/better-auth/better-auth.resolver.d.ts +45 -0
  50. package/dist/core/modules/better-auth/better-auth.resolver.js +221 -0
  51. package/dist/core/modules/better-auth/better-auth.resolver.js.map +1 -0
  52. package/dist/core/modules/better-auth/better-auth.service.d.ts +37 -0
  53. package/dist/core/modules/better-auth/better-auth.service.js +148 -0
  54. package/dist/core/modules/better-auth/better-auth.service.js.map +1 -0
  55. package/dist/core/modules/better-auth/better-auth.types.d.ts +39 -0
  56. package/dist/core/modules/better-auth/better-auth.types.js +26 -0
  57. package/dist/core/modules/better-auth/better-auth.types.js.map +1 -0
  58. package/dist/core/modules/better-auth/core-better-auth.controller.d.ts +66 -0
  59. package/dist/core/modules/better-auth/core-better-auth.controller.js +491 -0
  60. package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -0
  61. package/dist/core/modules/better-auth/core-better-auth.resolver.d.ts +59 -0
  62. package/dist/core/modules/better-auth/core-better-auth.resolver.js +538 -0
  63. package/dist/core/modules/better-auth/core-better-auth.resolver.js.map +1 -0
  64. package/dist/core/modules/better-auth/index.d.ts +13 -0
  65. package/dist/core/modules/better-auth/index.js +30 -0
  66. package/dist/core/modules/better-auth/index.js.map +1 -0
  67. package/dist/core/modules/user/core-user.model.d.ts +2 -0
  68. package/dist/core/modules/user/core-user.model.js +21 -0
  69. package/dist/core/modules/user/core-user.model.js.map +1 -1
  70. package/dist/core.module.js +7 -0
  71. package/dist/core.module.js.map +1 -1
  72. package/dist/index.d.ts +1 -0
  73. package/dist/index.js +1 -0
  74. package/dist/index.js.map +1 -1
  75. package/dist/server/modules/better-auth/better-auth.controller.d.ts +10 -0
  76. package/dist/server/modules/better-auth/better-auth.controller.js +36 -0
  77. package/dist/server/modules/better-auth/better-auth.controller.js.map +1 -0
  78. package/dist/server/modules/better-auth/better-auth.module.d.ts +9 -0
  79. package/dist/server/modules/better-auth/better-auth.module.js +44 -0
  80. package/dist/server/modules/better-auth/better-auth.module.js.map +1 -0
  81. package/dist/server/modules/better-auth/better-auth.resolver.d.ts +45 -0
  82. package/dist/server/modules/better-auth/better-auth.resolver.js +221 -0
  83. package/dist/server/modules/better-auth/better-auth.resolver.js.map +1 -0
  84. package/dist/server/modules/file/file-info.model.d.ts +71 -3
  85. package/dist/server/modules/user/user.model.d.ts +169 -3
  86. package/dist/server/server.module.js +6 -1
  87. package/dist/server/server.module.js.map +1 -1
  88. package/dist/tsconfig.build.tsbuildinfo +1 -1
  89. package/package.json +21 -22
  90. package/src/config.env.ts +139 -1
  91. package/src/core/common/decorators/restricted.decorator.ts +2 -2
  92. package/src/core/common/helpers/filter.helper.ts +15 -17
  93. package/src/core/common/helpers/gridfs.helper.ts +5 -5
  94. package/src/core/common/helpers/input.helper.ts +2 -2
  95. package/src/core/common/interfaces/server-options.interface.ts +377 -20
  96. package/src/core/common/services/crud.service.ts +22 -22
  97. package/src/core/modules/auth/auth-guard-strategy.enum.ts +1 -0
  98. package/src/core/modules/auth/guards/auth.guard.ts +20 -6
  99. package/src/core/modules/better-auth/README.md +1422 -0
  100. package/src/core/modules/better-auth/better-auth-auth.model.ts +69 -0
  101. package/src/core/modules/better-auth/better-auth-models.ts +140 -0
  102. package/src/core/modules/better-auth/better-auth-rate-limit.middleware.ts +113 -0
  103. package/src/core/modules/better-auth/better-auth-rate-limiter.service.ts +326 -0
  104. package/src/core/modules/better-auth/better-auth-user.mapper.ts +269 -0
  105. package/src/core/modules/better-auth/better-auth.config.ts +488 -0
  106. package/src/core/modules/better-auth/better-auth.middleware.ts +111 -0
  107. package/src/core/modules/better-auth/better-auth.module.ts +474 -0
  108. package/src/core/modules/better-auth/better-auth.resolver.ts +213 -0
  109. package/src/core/modules/better-auth/better-auth.service.ts +314 -0
  110. package/src/core/modules/better-auth/better-auth.types.ts +90 -0
  111. package/src/core/modules/better-auth/core-better-auth.controller.ts +605 -0
  112. package/src/core/modules/better-auth/core-better-auth.resolver.ts +705 -0
  113. package/src/core/modules/better-auth/index.ts +32 -0
  114. package/src/core/modules/user/core-user.model.ts +29 -0
  115. package/src/core.module.ts +13 -0
  116. package/src/index.ts +6 -0
  117. package/src/server/modules/better-auth/better-auth.controller.ts +41 -0
  118. package/src/server/modules/better-auth/better-auth.module.ts +88 -0
  119. package/src/server/modules/better-auth/better-auth.resolver.ts +201 -0
  120. package/src/server/server.module.ts +10 -1
@@ -16,6 +16,357 @@ import { CronJobConfigWithTimeZone } from './cron-job-config-with-time-zone.inte
16
16
  import { CronJobConfigWithUtcOffset } from './cron-job-config-with-utc-offset.interface';
17
17
  import { MailjetOptions } from './mailjet-options.interface';
18
18
 
19
+ /**
20
+ * Better-Auth field type definition
21
+ * Matches the DBFieldType from better-auth
22
+ */
23
+ export type BetterAuthFieldType = 'boolean' | 'date' | 'json' | 'number' | 'number[]' | 'string' | 'string[]';
24
+
25
+ /**
26
+ * Interface for better-auth configuration
27
+ */
28
+ export interface IBetterAuth {
29
+ /**
30
+ * Additional user fields beyond the core fields (firstName, lastName, etc.)
31
+ * These fields will be merged with the default user fields.
32
+ * @see https://www.better-auth.com/docs/concepts/users-accounts#additional-fields
33
+ * @example
34
+ * ```typescript
35
+ * additionalUserFields: {
36
+ * phoneNumber: { type: 'string', defaultValue: null },
37
+ * department: { type: 'string', required: true },
38
+ * preferences: { type: 'string', defaultValue: '{}' },
39
+ * }
40
+ * ```
41
+ */
42
+ additionalUserFields?: Record<string, IBetterAuthUserField>;
43
+
44
+ /**
45
+ * Whether BetterAuthModule should be auto-registered in CoreModule.
46
+ *
47
+ * When false (default), projects integrate BetterAuth via an extended module
48
+ * in their project (e.g., `src/server/modules/better-auth/better-auth.module.ts`).
49
+ * This follows the same pattern as Legacy Auth and allows for custom resolvers,
50
+ * controllers, and project-specific authentication logic.
51
+ *
52
+ * Set to true only for simple projects that don't need customization.
53
+ *
54
+ * @default false
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * // Recommended: Extend BetterAuthModule in your project
59
+ * // src/server/modules/better-auth/better-auth.module.ts
60
+ * import { BetterAuthModule as CoreBetterAuthModule } from '@lenne.tech/nest-server';
61
+ *
62
+ * @Module({})
63
+ * export class BetterAuthModule {
64
+ * static forRoot(options) {
65
+ * return {
66
+ * imports: [CoreBetterAuthModule.forRoot(options)],
67
+ * // Add custom providers, controllers, etc.
68
+ * };
69
+ * }
70
+ * }
71
+ *
72
+ * // Then import in ServerModule
73
+ * import { BetterAuthModule } from './modules/better-auth/better-auth.module';
74
+ * ```
75
+ */
76
+ autoRegister?: boolean;
77
+
78
+ /**
79
+ * Base path for better-auth endpoints
80
+ * default: '/iam'
81
+ */
82
+ basePath?: string;
83
+
84
+ /**
85
+ * Base URL of the application
86
+ * e.g. 'http://localhost:3000'
87
+ */
88
+ baseUrl?: string;
89
+
90
+ /**
91
+ * Email/password authentication configuration.
92
+ * Enabled by default.
93
+ * Set `enabled: false` to explicitly disable email/password auth.
94
+ */
95
+ emailAndPassword?: {
96
+ /**
97
+ * Whether email/password authentication is enabled.
98
+ * @default true
99
+ */
100
+ enabled?: boolean;
101
+ };
102
+
103
+ /**
104
+ * Whether better-auth is enabled.
105
+ * BetterAuth is enabled by default (zero-config philosophy).
106
+ * Set to false to explicitly disable it.
107
+ * @default true
108
+ */
109
+ enabled?: boolean;
110
+
111
+ /**
112
+ * JWT plugin configuration for API clients.
113
+ * Enabled by default when this config block is present.
114
+ * Set `enabled: false` to explicitly disable.
115
+ */
116
+ jwt?: {
117
+ /**
118
+ * Whether JWT plugin is enabled.
119
+ * @default true (when jwt config block is present)
120
+ */
121
+ enabled?: boolean;
122
+
123
+ /**
124
+ * JWT expiration time
125
+ * @default '15m'
126
+ */
127
+ expiresIn?: string;
128
+ };
129
+
130
+ /**
131
+ * Advanced Better-Auth options passthrough.
132
+ * These options are passed directly to Better-Auth, allowing full customization.
133
+ * Use this for any Better-Auth options not explicitly defined in this interface.
134
+ * @see https://www.better-auth.com/docs/reference/options
135
+ * @example
136
+ * ```typescript
137
+ * options: {
138
+ * emailAndPassword: {
139
+ * enabled: true,
140
+ * requireEmailVerification: true,
141
+ * sendResetPassword: async ({ user, url }) => { ... },
142
+ * },
143
+ * account: {
144
+ * accountLinking: { enabled: true },
145
+ * },
146
+ * session: {
147
+ * expiresIn: 60 * 60 * 24 * 7, // 7 days
148
+ * updateAge: 60 * 60 * 24, // 1 day
149
+ * },
150
+ * advanced: {
151
+ * cookiePrefix: 'my-app',
152
+ * useSecureCookies: true,
153
+ * },
154
+ * }
155
+ * ```
156
+ */
157
+ options?: Record<string, unknown>;
158
+
159
+ /**
160
+ * Passkey/WebAuthn configuration.
161
+ * Enabled by default when this config block is present.
162
+ * Set `enabled: false` to explicitly disable.
163
+ */
164
+ passkey?: {
165
+ /**
166
+ * Whether passkey authentication is enabled.
167
+ * @default true (when passkey config block is present)
168
+ */
169
+ enabled?: boolean;
170
+
171
+ /**
172
+ * Origin URL for WebAuthn
173
+ * e.g. 'http://localhost:3000'
174
+ */
175
+ origin?: string;
176
+
177
+ /**
178
+ * Relying Party ID (usually the domain)
179
+ * e.g. 'localhost' or 'example.com'
180
+ */
181
+ rpId?: string;
182
+
183
+ /**
184
+ * Relying Party Name (displayed to users)
185
+ * e.g. 'My Application'
186
+ */
187
+ rpName?: string;
188
+ };
189
+
190
+ /**
191
+ * Additional Better-Auth plugins to include.
192
+ * These will be merged with the built-in plugins (jwt, twoFactor, passkey).
193
+ * @see https://www.better-auth.com/docs/plugins
194
+ * @example
195
+ * ```typescript
196
+ * import { organization } from 'better-auth/plugins';
197
+ * import { magicLink } from 'better-auth/plugins';
198
+ *
199
+ * plugins: [
200
+ * organization({ ... }),
201
+ * magicLink({ ... }),
202
+ * ]
203
+ * ```
204
+ */
205
+ plugins?: unknown[];
206
+
207
+ /**
208
+ * Rate limiting configuration for Better-Auth endpoints
209
+ * Protects against brute-force attacks
210
+ */
211
+ rateLimit?: IBetterAuthRateLimit;
212
+
213
+ /**
214
+ * Secret for better-auth (min 32 characters)
215
+ * Used for session encryption
216
+ */
217
+ secret?: string;
218
+
219
+ /**
220
+ * Social login providers configuration
221
+ * Supports all Better-Auth providers dynamically (google, github, apple, discord, etc.)
222
+ *
223
+ * **Enabled by default:** Providers are automatically enabled when credentials
224
+ * are configured. Set `enabled: false` to explicitly disable a provider.
225
+ *
226
+ * @see https://www.better-auth.com/docs/authentication/social-sign-in
227
+ * @example
228
+ * ```typescript
229
+ * socialProviders: {
230
+ * // These providers are enabled (no need for enabled: true)
231
+ * google: { clientId: '...', clientSecret: '...' },
232
+ * github: { clientId: '...', clientSecret: '...' },
233
+ * // This provider is explicitly disabled
234
+ * discord: { clientId: '...', clientSecret: '...', enabled: false },
235
+ * }
236
+ * ```
237
+ */
238
+ socialProviders?: Record<string, IBetterAuthSocialProvider>;
239
+
240
+ /**
241
+ * Trusted origins for CORS and OAuth callbacks
242
+ * If not specified, defaults to [baseUrl]
243
+ * e.g. ['https://example.com', 'https://app.example.com']
244
+ */
245
+ trustedOrigins?: string[];
246
+
247
+ /**
248
+ * Two-factor authentication configuration.
249
+ * Enabled by default when this config block is present.
250
+ * Set `enabled: false` to explicitly disable.
251
+ */
252
+ twoFactor?: {
253
+ /**
254
+ * App name shown in authenticator apps
255
+ * e.g. 'My Application'
256
+ */
257
+ appName?: string;
258
+
259
+ /**
260
+ * Whether 2FA is enabled.
261
+ * @default true (when twoFactor config block is present)
262
+ */
263
+ enabled?: boolean;
264
+ };
265
+ }
266
+
267
+ /**
268
+ * Interface for Better-Auth rate limiting configuration
269
+ */
270
+ export interface IBetterAuthRateLimit {
271
+ /**
272
+ * Whether rate limiting is enabled
273
+ * default: false
274
+ */
275
+ enabled?: boolean;
276
+
277
+ /**
278
+ * Maximum number of requests within the time window
279
+ * default: 10
280
+ */
281
+ max?: number;
282
+
283
+ /**
284
+ * Custom message when rate limit is exceeded
285
+ * default: 'Too many requests, please try again later.'
286
+ */
287
+ message?: string;
288
+
289
+ /**
290
+ * Endpoints to skip rate limiting entirely
291
+ * e.g., ['/iam/session'] for session checks
292
+ */
293
+ skipEndpoints?: string[];
294
+
295
+ /**
296
+ * Endpoints to apply stricter rate limiting (e.g., sign-in, sign-up)
297
+ * These endpoints will have half the max requests
298
+ */
299
+ strictEndpoints?: string[];
300
+
301
+ /**
302
+ * Time window in seconds
303
+ * default: 60 (1 minute)
304
+ */
305
+ windowSeconds?: number;
306
+ }
307
+
308
+ /**
309
+ * Interface for better-auth social provider configuration
310
+ *
311
+ * **Enabled by default:** A social provider is automatically enabled when
312
+ * both `clientId` and `clientSecret` are provided. You only need to set
313
+ * `enabled: false` to explicitly disable a configured provider.
314
+ *
315
+ * @example
316
+ * ```typescript
317
+ * // Provider is enabled (has credentials, no explicit enabled flag needed)
318
+ * google: { clientId: '...', clientSecret: '...' }
319
+ *
320
+ * // Provider is explicitly disabled despite having credentials
321
+ * github: { clientId: '...', clientSecret: '...', enabled: false }
322
+ * ```
323
+ */
324
+ export interface IBetterAuthSocialProvider {
325
+ /**
326
+ * OAuth client ID
327
+ */
328
+ clientId: string;
329
+
330
+ /**
331
+ * OAuth client secret
332
+ */
333
+ clientSecret: string;
334
+
335
+ /**
336
+ * Whether this provider is enabled.
337
+ * Defaults to true when clientId and clientSecret are provided.
338
+ * Set to false to explicitly disable this provider.
339
+ * @default true (when credentials are configured)
340
+ */
341
+ enabled?: boolean;
342
+ }
343
+
344
+ /**
345
+ * Interface for additional user fields in Better-Auth
346
+ * @see https://www.better-auth.com/docs/concepts/users-accounts#additional-fields
347
+ */
348
+ export interface IBetterAuthUserField {
349
+ /**
350
+ * Default value for the field
351
+ */
352
+ defaultValue?: unknown;
353
+
354
+ /**
355
+ * Database field name (if different from key)
356
+ */
357
+ fieldName?: string;
358
+
359
+ /**
360
+ * Whether this field is required
361
+ */
362
+ required?: boolean;
363
+
364
+ /**
365
+ * Field type
366
+ */
367
+ type: BetterAuthFieldType;
368
+ }
369
+
19
370
  /**
20
371
  * Interface for JWT configuration (main and refresh)
21
372
  */
@@ -71,6 +422,12 @@ export interface IServerOptions {
71
422
  */
72
423
  automaticObjectIdFiltering?: boolean;
73
424
 
425
+ /**
426
+ * Configuration for better-auth authentication framework
427
+ * See: https://better-auth.com
428
+ */
429
+ betterAuth?: IBetterAuth;
430
+
74
431
  /**
75
432
  * Configuration for Brevo
76
433
  * See: https://developers.brevo.com/
@@ -324,29 +681,29 @@ export interface IServerOptions {
324
681
  * Hint: The secrets of the different environments should be different, otherwise a JWT can be used in different
325
682
  * environments, which can lead to security vulnerabilities.
326
683
  */
327
- jwt?: IJwt & JwtModuleOptions &
328
- {
329
- /**
330
- * Configuration for refresh Token (JWT)
331
- * Hint: The secret of the JWT and the Refresh Token should be different, otherwise a new RefreshToken can also be
332
- * requested with the JWT, which can lead to a security vulnerability.
333
- */
334
- refresh?: IJwt & {
684
+ jwt?: IJwt &
685
+ JwtModuleOptions & {
335
686
  /**
336
- * Whether renewal of the refresh token is permitted
337
- * If falsy (default): during refresh only a new token, the refresh token retains its original term
338
- * If true: during refresh not only a new token but also a new refresh token is created
687
+ * Configuration for refresh Token (JWT)
688
+ * Hint: The secret of the JWT and the Refresh Token should be different, otherwise a new RefreshToken can also be
689
+ * requested with the JWT, which can lead to a security vulnerability.
339
690
  */
340
- renewal?: boolean;
341
- };
691
+ refresh?: IJwt & {
692
+ /**
693
+ * Whether renewal of the refresh token is permitted
694
+ * If falsy (default): during refresh only a new token, the refresh token retains its original term
695
+ * If true: during refresh not only a new token but also a new refresh token is created
696
+ */
697
+ renewal?: boolean;
698
+ };
342
699
 
343
- /**
344
- * Time period in milliseconds
345
- * in which the same token ID is used so that all parallel token refresh requests of a device can be generated.
346
- * default: 0 (every token includes a new token ID, all parallel token refresh requests must be prevented by the client or processed accordingly)
347
- */
348
- sameTokenIdPeriod?: number;
349
- };
700
+ /**
701
+ * Time period in milliseconds
702
+ * in which the same token ID is used so that all parallel token refresh requests of a device can be generated.
703
+ * default: 0 (every token includes a new token ID, all parallel token refresh requests must be prevented by the client or processed accordingly)
704
+ */
705
+ sameTokenIdPeriod?: number;
706
+ };
350
707
 
351
708
  /**
352
709
  * Load local configuration
@@ -2,10 +2,10 @@ import { NotFoundException } from '@nestjs/common';
2
2
  import {
3
3
  AggregateOptions,
4
4
  Document,
5
- FilterQuery,
6
5
  Model as MongooseModel,
7
6
  PipelineStage,
8
7
  Query,
8
+ QueryFilter,
9
9
  QueryOptions,
10
10
  } from 'mongoose';
11
11
 
@@ -147,7 +147,7 @@ export abstract class CrudService<
147
147
  * Get items via filter
148
148
  */
149
149
  async find(
150
- filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
150
+ filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
151
151
  serviceOptions?: ServiceOptions,
152
152
  ): Promise<Model[]> {
153
153
  // If filter is not instance of FilterArgs a simple form with filterQuery and queryOptions is set
@@ -191,7 +191,7 @@ export abstract class CrudService<
191
191
  * Warning: Disables the handling of rights and restrictions!
192
192
  */
193
193
  async findForce(
194
- filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
194
+ filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
195
195
  serviceOptions: ServiceOptions = {},
196
196
  ): Promise<Model[]> {
197
197
  serviceOptions = serviceOptions || {};
@@ -204,7 +204,7 @@ export abstract class CrudService<
204
204
  * Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
205
205
  */
206
206
  async findRaw(
207
- filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
207
+ filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
208
208
  serviceOptions: ServiceOptions = {},
209
209
  ): Promise<Model[]> {
210
210
  serviceOptions = serviceOptions || {};
@@ -216,7 +216,7 @@ export abstract class CrudService<
216
216
  * Get items and total count via filter
217
217
  */
218
218
  async findAndCount(
219
- filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
219
+ filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
220
220
  serviceOptions?: ServiceOptions,
221
221
  ): Promise<{ items: Model[]; totalCount: number }> {
222
222
  // If filter is not instance of FilterArgs a simple form with filterQuery and queryOptions is set
@@ -280,10 +280,10 @@ export abstract class CrudService<
280
280
 
281
281
  // Find and process db items
282
282
  const collation = serviceOptions?.collation || ConfigService.get('mongoose.collation');
283
- const dbResult
284
- = (await this.mainDbModel.aggregate(aggregation, collation ? { collation } : {}).exec())[0] || {};
283
+ const dbResult =
284
+ (await this.mainDbModel.aggregate(aggregation, collation ? { collation } : {}).exec())[0] || {};
285
285
  dbResult.totalCount = dbResult.totalCount?.[0]?.total || 0;
286
- dbResult.items = dbResult.items?.map(item => this.mainDbModel.hydrate(item)) || [];
286
+ dbResult.items = dbResult.items?.map((item) => this.mainDbModel.hydrate(item)) || [];
287
287
  return dbResult;
288
288
  },
289
289
  { input: filter, outputPath: 'items', serviceOptions },
@@ -295,7 +295,7 @@ export abstract class CrudService<
295
295
  * Warning: Disables the handling of rights and restrictions!
296
296
  */
297
297
  async findAndCountForce(
298
- filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
298
+ filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
299
299
  serviceOptions: ServiceOptions = {},
300
300
  ): Promise<{ items: Model[]; totalCount: number }> {
301
301
  serviceOptions.raw = true;
@@ -307,7 +307,7 @@ export abstract class CrudService<
307
307
  * Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
308
308
  */
309
309
  async findAndCountRaw(
310
- filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
310
+ filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
311
311
  serviceOptions: ServiceOptions = {},
312
312
  ): Promise<{ items: Model[]; totalCount: number }> {
313
313
  serviceOptions = serviceOptions || {};
@@ -319,7 +319,7 @@ export abstract class CrudService<
319
319
  * Find and update
320
320
  */
321
321
  async findAndUpdate(
322
- filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
322
+ filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
323
323
  update: PlainObject<UpdateInput>,
324
324
  serviceOptions?: ServiceOptions,
325
325
  ): Promise<Model[]> {
@@ -348,7 +348,7 @@ export abstract class CrudService<
348
348
  * Warning: Disables the handling of rights and restrictions!
349
349
  */
350
350
  async findAndUpdateForce(
351
- filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
351
+ filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
352
352
  update: PlainObject<UpdateInput>,
353
353
  serviceOptions: ServiceOptions = {},
354
354
  ): Promise<Model[]> {
@@ -362,7 +362,7 @@ export abstract class CrudService<
362
362
  * Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
363
363
  */
364
364
  async findAndUpdateRaw(
365
- filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
365
+ filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
366
366
  update: PlainObject<UpdateInput>,
367
367
  serviceOptions: ServiceOptions = {},
368
368
  ): Promise<Model[]> {
@@ -375,7 +375,7 @@ export abstract class CrudService<
375
375
  * Find one item via filter
376
376
  */
377
377
  async findOne(
378
- filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
378
+ filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
379
379
  serviceOptions?: ServiceOptions,
380
380
  ): Promise<Model> {
381
381
  // If filter is not instance of FilterArgs a simple form with filterQuery and queryOptions is set
@@ -414,7 +414,7 @@ export abstract class CrudService<
414
414
  * Warning: Disables the handling of rights and restrictions!
415
415
  */
416
416
  async findOneForce(
417
- filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
417
+ filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
418
418
  serviceOptions: ServiceOptions = {},
419
419
  ): Promise<Model> {
420
420
  serviceOptions = serviceOptions || {};
@@ -427,7 +427,7 @@ export abstract class CrudService<
427
427
  * Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
428
428
  */
429
429
  async findOneRaw(
430
- filter?: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions; samples?: number },
430
+ filter?: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions; samples?: number },
431
431
  serviceOptions: ServiceOptions = {},
432
432
  ): Promise<Model> {
433
433
  serviceOptions = serviceOptions || {};
@@ -452,7 +452,7 @@ export abstract class CrudService<
452
452
  * CRUD alias for find
453
453
  */
454
454
  async read(
455
- filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
455
+ filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
456
456
  serviceOptions?: ServiceOptions,
457
457
  ): Promise<Model[]>;
458
458
 
@@ -460,7 +460,7 @@ export abstract class CrudService<
460
460
  * CRUD alias for get or find
461
461
  */
462
462
  async read(
463
- input: FilterArgs | string | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
463
+ input: FilterArgs | string | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
464
464
  serviceOptions?: ServiceOptions,
465
465
  ): Promise<Model | Model[]> {
466
466
  if (typeof input === 'string') {
@@ -481,7 +481,7 @@ export abstract class CrudService<
481
481
  * Warning: Disables the handling of rights and restrictions!
482
482
  */
483
483
  async readForce(
484
- filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
484
+ filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
485
485
  serviceOptions?: ServiceOptions,
486
486
  ): Promise<Model[]>;
487
487
 
@@ -490,7 +490,7 @@ export abstract class CrudService<
490
490
  * Warning: Disables the handling of rights and restrictions!
491
491
  */
492
492
  async readForce(
493
- input: FilterArgs | string | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
493
+ input: FilterArgs | string | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
494
494
  serviceOptions?: ServiceOptions,
495
495
  ): Promise<Model | Model[]> {
496
496
  if (typeof input === 'string') {
@@ -511,7 +511,7 @@ export abstract class CrudService<
511
511
  * Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
512
512
  */
513
513
  async readRaw(
514
- filter: FilterArgs | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
514
+ filter: FilterArgs | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
515
515
  serviceOptions?: ServiceOptions,
516
516
  ): Promise<Model[]>;
517
517
 
@@ -520,7 +520,7 @@ export abstract class CrudService<
520
520
  * Warning: Disables the handling of rights and restrictions! The raw data may contain secrets (such as passwords).
521
521
  */
522
522
  async readRaw(
523
- input: FilterArgs | string | { filterQuery?: FilterQuery<any>; queryOptions?: QueryOptions },
523
+ input: FilterArgs | string | { filterQuery?: QueryFilter<any>; queryOptions?: QueryOptions },
524
524
  serviceOptions?: ServiceOptions,
525
525
  ): Promise<Model | Model[]> {
526
526
  if (typeof input === 'string') {
@@ -1,4 +1,5 @@
1
1
  export enum AuthGuardStrategy {
2
+ BETTER_AUTH = 'better-auth',
2
3
  JWT = 'jwt',
3
4
  JWT_REFRESH = 'jwt-refresh',
4
5
  }
@@ -13,9 +13,9 @@ import { InvalidTokenException } from '../exceptions/invalid-token.exception';
13
13
  /**
14
14
  * Missing strategy error
15
15
  */
16
- const NO_STRATEGY_ERROR
17
- = 'In order to use "defaultStrategy", please, ensure to import PassportModule in each '
18
- + 'place where AuthGuard() is being used. Otherwise, passport won\'t work correctly.';
16
+ const NO_STRATEGY_ERROR =
17
+ 'In order to use "defaultStrategy", please, ensure to import PassportModule in each ' +
18
+ "place where AuthGuard() is being used. Otherwise, passport won't work correctly.";
19
19
 
20
20
  /**
21
21
  * Interface for auth guard
@@ -38,7 +38,7 @@ const createPassportContext = (request, response) => (type, options, callback: (
38
38
  } catch (err) {
39
39
  reject(err);
40
40
  }
41
- })(request, response, err => (err ? reject(err) : resolve)),
41
+ })(request, response, (err) => (err ? reject(err) : resolve)),
42
42
  );
43
43
 
44
44
  /**
@@ -70,8 +70,22 @@ function createAuthGuard(type?: AuthGuardStrategy | string | string[]): Type<IAu
70
70
  }
71
71
 
72
72
  const options = { ...defaultOptions, ...this.options };
73
- const response = context?.switchToHttp()?.getResponse();
74
73
  const request = this.getRequest(context);
74
+
75
+ // Check if user is already authenticated via Better-Auth middleware
76
+ // Only skip Passport for Better-Auth users (marked with _authenticatedViaBetterAuth)
77
+ // This ensures JWT_REFRESH guard still validates refresh tokens properly
78
+ const existingUser = request?.[options.property || defaultOptions.property];
79
+ if (existingUser && existingUser._authenticatedViaBetterAuth === true) {
80
+ // User is authenticated via Better-Auth - skip Passport authentication
81
+ // Validate through handleRequest to ensure role checks work
82
+ const validatedUser = this.handleRequest(null, existingUser, null, context);
83
+ request[options.property || defaultOptions.property] = validatedUser;
84
+ return true;
85
+ }
86
+
87
+ // Proceed with Passport authentication
88
+ const response = context?.switchToHttp()?.getResponse();
75
89
  const passportFn = createPassportContext(request, response);
76
90
  const user = await passportFn(type || this.options.defaultStrategy, options, (err, currentUser, info) =>
77
91
  this.handleRequest(err, currentUser, info, context),
@@ -101,7 +115,7 @@ function createAuthGuard(type?: AuthGuardStrategy | string | string[]): Type<IAu
101
115
  */
102
116
  async logIn<TRequest extends { logIn: (...params) => any } = any>(request: TRequest) {
103
117
  const user = request[this.options.property || defaultOptions.property];
104
- await new Promise<void>((resolve, reject) => request.logIn(user, err => (err ? reject(err) : resolve())));
118
+ await new Promise<void>((resolve, reject) => request.logIn(user, (err) => (err ? reject(err) : resolve())));
105
119
  }
106
120
 
107
121
  /**