@lenne.tech/nest-server 11.8.0 → 11.9.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 (65) hide show
  1. package/dist/config.env.js +3 -0
  2. package/dist/config.env.js.map +1 -1
  3. package/dist/core/common/interfaces/server-options.interface.d.ts +13 -0
  4. package/dist/core/modules/auth/guards/roles.guard.js +4 -3
  5. package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
  6. package/dist/core/modules/auth/services/core-auth.service.js +5 -4
  7. package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
  8. package/dist/core/modules/error-code/core-error-code.controller.d.ts +7 -0
  9. package/dist/core/modules/error-code/core-error-code.controller.js +45 -0
  10. package/dist/core/modules/error-code/core-error-code.controller.js.map +1 -0
  11. package/dist/core/modules/error-code/core-error-code.service.d.ts +16 -0
  12. package/dist/core/modules/error-code/core-error-code.service.js +65 -0
  13. package/dist/core/modules/error-code/core-error-code.service.js.map +1 -0
  14. package/dist/core/modules/error-code/error-code.module.d.ts +7 -0
  15. package/dist/core/modules/error-code/error-code.module.js +64 -0
  16. package/dist/core/modules/error-code/error-code.module.js.map +1 -0
  17. package/dist/core/modules/error-code/error-codes.d.ts +219 -0
  18. package/dist/core/modules/error-code/error-codes.js +204 -0
  19. package/dist/core/modules/error-code/error-codes.js.map +1 -0
  20. package/dist/core/modules/error-code/index.d.ts +5 -0
  21. package/dist/core/modules/error-code/index.js +22 -0
  22. package/dist/core/modules/error-code/index.js.map +1 -0
  23. package/dist/core/modules/error-code/interfaces/error-code.interfaces.d.ts +12 -0
  24. package/dist/core/modules/error-code/interfaces/error-code.interfaces.js +3 -0
  25. package/dist/core/modules/error-code/interfaces/error-code.interfaces.js.map +1 -0
  26. package/dist/core.module.js +8 -0
  27. package/dist/core.module.js.map +1 -1
  28. package/dist/index.d.ts +1 -0
  29. package/dist/index.js +1 -0
  30. package/dist/index.js.map +1 -1
  31. package/dist/server/modules/error-code/error-code.controller.d.ts +8 -0
  32. package/dist/server/modules/error-code/error-code.controller.js +55 -0
  33. package/dist/server/modules/error-code/error-code.controller.js.map +1 -0
  34. package/dist/server/modules/error-code/error-code.service.d.ts +4 -0
  35. package/dist/server/modules/error-code/error-code.service.js +27 -0
  36. package/dist/server/modules/error-code/error-code.service.js.map +1 -0
  37. package/dist/server/modules/error-code/error-codes.d.ts +45 -0
  38. package/dist/server/modules/error-code/error-codes.js +24 -0
  39. package/dist/server/modules/error-code/error-codes.js.map +1 -0
  40. package/dist/server/modules/error-code/index.d.ts +3 -0
  41. package/dist/server/modules/error-code/index.js +20 -0
  42. package/dist/server/modules/error-code/index.js.map +1 -0
  43. package/dist/server/server.module.js +7 -0
  44. package/dist/server/server.module.js.map +1 -1
  45. package/dist/tsconfig.build.tsbuildinfo +1 -1
  46. package/package.json +2 -2
  47. package/src/config.env.ts +4 -0
  48. package/src/core/common/interfaces/server-options.interface.ts +89 -0
  49. package/src/core/modules/auth/guards/roles.guard.ts +5 -4
  50. package/src/core/modules/auth/services/core-auth.service.ts +5 -4
  51. package/src/core/modules/error-code/INTEGRATION-CHECKLIST.md +288 -0
  52. package/src/core/modules/error-code/core-error-code.controller.ts +54 -0
  53. package/src/core/modules/error-code/core-error-code.service.ts +135 -0
  54. package/src/core/modules/error-code/error-code.module.ts +119 -0
  55. package/src/core/modules/error-code/error-codes.ts +405 -0
  56. package/src/core/modules/error-code/index.ts +14 -0
  57. package/src/core/modules/error-code/interfaces/error-code.interfaces.ts +99 -0
  58. package/src/core.module.ts +16 -0
  59. package/src/index.ts +6 -0
  60. package/src/server/modules/error-code/README.md +131 -0
  61. package/src/server/modules/error-code/error-code.controller.ts +91 -0
  62. package/src/server/modules/error-code/error-code.service.ts +42 -0
  63. package/src/server/modules/error-code/error-codes.ts +65 -0
  64. package/src/server/modules/error-code/index.ts +8 -0
  65. package/src/server/server.module.ts +10 -0
@@ -0,0 +1,119 @@
1
+ import { DynamicModule, Global, Module, Type } from '@nestjs/common';
2
+
3
+ import { CoreErrorCodeController } from './core-error-code.controller';
4
+ import { CoreErrorCodeService } from './core-error-code.service';
5
+ import { IErrorCodeModuleConfig } from './interfaces/error-code.interfaces';
6
+
7
+ /**
8
+ * Error Code Module
9
+ *
10
+ * Provides error code translations via REST endpoint.
11
+ * Translations are defined in the error registry (Single Source of Truth).
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * // Basic usage (auto-register in CoreModule)
16
+ * // No explicit import needed - included in CoreModule
17
+ *
18
+ * // Extended usage (with custom error registry - RECOMMENDED)
19
+ * const ProjectErrors = {
20
+ * ORDER_NOT_FOUND: {
21
+ * code: 'PROJ_0001',
22
+ * message: 'Order not found',
23
+ * translations: { de: 'Bestellung nicht gefunden.', en: 'Order not found.' }
24
+ * }
25
+ * } as const satisfies IErrorRegistry;
26
+ *
27
+ * ErrorCodeModule.forRoot({ additionalErrorRegistry: ProjectErrors })
28
+ *
29
+ * // Extended usage (with custom controller and service)
30
+ * ErrorCodeModule.forRoot({
31
+ * additionalErrorRegistry: ProjectErrors,
32
+ * controller: ErrorCodeController,
33
+ * service: ErrorCodeService,
34
+ * })
35
+ * ```
36
+ */
37
+ @Global()
38
+ @Module({
39
+ // IMPORTANT: Controllers are NOT registered here - they are registered via forRoot()
40
+ // This prevents duplicate controller registration when using custom controllers,
41
+ // which would cause route conflicts (e.g., :locale intercepting /codes)
42
+ exports: [CoreErrorCodeService],
43
+ providers: [CoreErrorCodeService],
44
+ })
45
+ export class ErrorCodeModule {
46
+ /**
47
+ * Gets the controller class to use (custom or default)
48
+ */
49
+ private static getControllerClass(config?: IErrorCodeModuleConfig): Type<any> {
50
+ return config?.controller || CoreErrorCodeController;
51
+ }
52
+
53
+ /**
54
+ * Gets the service class to use (custom or default)
55
+ */
56
+ private static getServiceClass(config?: IErrorCodeModuleConfig): Type<CoreErrorCodeService> {
57
+ return config?.service || CoreErrorCodeService;
58
+ }
59
+
60
+ /**
61
+ * Register the module with configuration
62
+ *
63
+ * Supports the following patterns:
64
+ * 1. **No config**: Uses CoreErrorCodeService and CoreErrorCodeController with core errors only
65
+ * 2. **additionalErrorRegistry only**: Adds project errors to core errors
66
+ * 3. **service only**: Uses custom service class (should register its own errors in constructor)
67
+ * 4. **controller only**: Uses custom controller class with CoreErrorCodeService
68
+ * 5. **Full config**: Uses custom service and controller
69
+ *
70
+ * @param config - Module configuration
71
+ * @returns Dynamic module
72
+ */
73
+ static forRoot(config?: IErrorCodeModuleConfig): DynamicModule {
74
+ const ControllerClass = this.getControllerClass(config);
75
+ const ServiceClass = this.getServiceClass(config);
76
+
77
+ // Build providers array
78
+ const providers: any[] = [];
79
+
80
+ if (config?.service) {
81
+ // If a custom service is provided, register it under both tokens:
82
+ // 1. Its own class (for direct injection in custom controllers)
83
+ // 2. CoreErrorCodeService (for backward compatibility)
84
+ providers.push(ServiceClass);
85
+ providers.push({
86
+ provide: CoreErrorCodeService,
87
+ useExisting: ServiceClass,
88
+ });
89
+ } else {
90
+ // Use factory to register additional errors
91
+ providers.push({
92
+ provide: CoreErrorCodeService,
93
+ useFactory: () => {
94
+ const service = new CoreErrorCodeService();
95
+
96
+ // Add additional error registry
97
+ if (config?.additionalErrorRegistry) {
98
+ service.registerErrorRegistry(config.additionalErrorRegistry);
99
+ }
100
+
101
+ return service;
102
+ },
103
+ });
104
+ }
105
+
106
+ // Export both the base class and custom service class (if provided)
107
+ const exports: any[] = [CoreErrorCodeService];
108
+ if (config?.service && ServiceClass !== CoreErrorCodeService) {
109
+ exports.push(ServiceClass);
110
+ }
111
+
112
+ return {
113
+ controllers: [ControllerClass],
114
+ exports,
115
+ module: ErrorCodeModule,
116
+ providers,
117
+ };
118
+ }
119
+ }
@@ -0,0 +1,405 @@
1
+ /**
2
+ * Lenne Tech Nest Server Error Codes - Structured Registry
3
+ *
4
+ * Single Source of Truth for all error codes, messages, and translations.
5
+ * This file serves as the central registry that:
6
+ * - Defines error codes with human-readable messages
7
+ * - Provides translations for multiple languages
8
+ * - Generates the i18n JSON endpoint automatically
9
+ *
10
+ * API Response Format: #PREFIX_XXXX: Short technical description
11
+ * - # = Marker for machine parsing
12
+ * - PREFIX = LTNS (Lenne Tech Nest Server) or project-specific
13
+ * - XXXX = Unique number within range
14
+ * - : = Separator
15
+ * - Description = English developer-friendly message
16
+ *
17
+ * Error code ranges:
18
+ * - LTNS_0001-LTNS_0099: Authentication errors
19
+ * - LTNS_0100-LTNS_0199: Authorization errors
20
+ * - LTNS_0200-LTNS_0299: User errors
21
+ * - LTNS_0300-LTNS_0399: Validation errors
22
+ * - LTNS_0400-LTNS_0499: Resource errors
23
+ * - LTNS_0500-LTNS_0599: File errors
24
+ * - LTNS_0900-LTNS_0999: Internal errors
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * import { UnauthorizedException } from '@nestjs/common';
29
+ * import { ErrorCode } from '@lenne.tech/nest-server';
30
+ *
31
+ * throw new UnauthorizedException(ErrorCode.UNAUTHORIZED);
32
+ * // Response: { statusCode: 401, message: "#LTNS_0100: Unauthorized - User is not logged in" }
33
+ * ```
34
+ */
35
+
36
+ // =====================================================
37
+ // Type Definitions
38
+ // =====================================================
39
+
40
+ /**
41
+ * Structure for a single error definition
42
+ */
43
+ export interface IErrorDefinition {
44
+ /** Unique error code (e.g., LTNS_0100) */
45
+ code: string;
46
+ /** English developer message */
47
+ message: string;
48
+ /** Translations for end users */
49
+ translations: {
50
+ [locale: string]: string;
51
+ de: string;
52
+ en: string;
53
+ };
54
+ }
55
+
56
+ /**
57
+ * Registry type for error definitions
58
+ */
59
+ export type IErrorRegistry = Record<string, IErrorDefinition>;
60
+
61
+ // =====================================================
62
+ // Core Error Registry (Single Source of Truth)
63
+ // =====================================================
64
+
65
+ /**
66
+ * LTNS Error Registry - Contains all core error definitions
67
+ *
68
+ * Each entry includes:
69
+ * - code: The unique identifier
70
+ * - message: English technical description for developers
71
+ * - translations: Localized messages for end users
72
+ *
73
+ * NOTE: Entries are grouped by error code range for maintainability.
74
+ * Do not sort alphabetically - the numeric grouping is intentional.
75
+ */
76
+ /* eslint-disable perfectionist/sort-objects */
77
+ export const LtnsErrors = {
78
+ // =====================================================
79
+ // Authentication Errors (LTNS_0001-LTNS_0099)
80
+ // =====================================================
81
+
82
+ USER_NOT_FOUND: {
83
+ code: 'LTNS_0001',
84
+ message: 'User not found',
85
+ translations: {
86
+ de: 'Benutzer wurde nicht gefunden.',
87
+ en: 'User not found.',
88
+ },
89
+ },
90
+
91
+ INVALID_PASSWORD: {
92
+ code: 'LTNS_0002',
93
+ message: 'Invalid password',
94
+ translations: {
95
+ de: 'Das eingegebene Passwort ist ungültig.',
96
+ en: 'The provided password is invalid.',
97
+ },
98
+ },
99
+
100
+ INVALID_TOKEN: {
101
+ code: 'LTNS_0003',
102
+ message: 'Invalid or malformed token',
103
+ translations: {
104
+ de: 'Der Token ist ungültig oder fehlerhaft.',
105
+ en: 'The token is invalid or malformed.',
106
+ },
107
+ },
108
+
109
+ TOKEN_EXPIRED: {
110
+ code: 'LTNS_0004',
111
+ message: 'Token has expired',
112
+ translations: {
113
+ de: 'Der Token ist abgelaufen. Bitte melden Sie sich erneut an.',
114
+ en: 'The token has expired. Please sign in again.',
115
+ },
116
+ },
117
+
118
+ REFRESH_TOKEN_REQUIRED: {
119
+ code: 'LTNS_0005',
120
+ message: 'Refresh token required',
121
+ translations: {
122
+ de: 'Ein Refresh-Token wird benötigt.',
123
+ en: 'A refresh token is required.',
124
+ },
125
+ },
126
+
127
+ USER_NOT_VERIFIED: {
128
+ code: 'LTNS_0006',
129
+ message: 'User email not verified',
130
+ translations: {
131
+ de: 'Ihre E-Mail-Adresse wurde noch nicht verifiziert.',
132
+ en: 'Your email address has not been verified yet.',
133
+ },
134
+ },
135
+
136
+ // =====================================================
137
+ // Authorization Errors (LTNS_0100-LTNS_0199)
138
+ // =====================================================
139
+
140
+ UNAUTHORIZED: {
141
+ code: 'LTNS_0100',
142
+ message: 'Unauthorized - User is not logged in',
143
+ translations: {
144
+ de: 'Sie sind nicht angemeldet.',
145
+ en: 'You are not logged in.',
146
+ },
147
+ },
148
+
149
+ ACCESS_DENIED: {
150
+ code: 'LTNS_0101',
151
+ message: 'Access denied - Insufficient permissions',
152
+ translations: {
153
+ de: 'Zugriff verweigert. Sie haben nicht die erforderlichen Berechtigungen.',
154
+ en: 'Access denied. You do not have the required permissions.',
155
+ },
156
+ },
157
+
158
+ RESOURCE_FORBIDDEN: {
159
+ code: 'LTNS_0102',
160
+ message: 'Resource access forbidden',
161
+ translations: {
162
+ de: 'Der Zugriff auf diese Ressource ist nicht erlaubt.',
163
+ en: 'Access to this resource is forbidden.',
164
+ },
165
+ },
166
+
167
+ // =====================================================
168
+ // User Errors (LTNS_0200-LTNS_0299)
169
+ // =====================================================
170
+
171
+ EMAIL_ALREADY_EXISTS: {
172
+ code: 'LTNS_0200',
173
+ message: 'Email already registered',
174
+ translations: {
175
+ de: 'Diese E-Mail-Adresse ist bereits registriert.',
176
+ en: 'This email address is already registered.',
177
+ },
178
+ },
179
+
180
+ USERNAME_ALREADY_EXISTS: {
181
+ code: 'LTNS_0201',
182
+ message: 'Username already taken',
183
+ translations: {
184
+ de: 'Dieser Benutzername ist bereits vergeben.',
185
+ en: 'This username is already taken.',
186
+ },
187
+ },
188
+
189
+ // =====================================================
190
+ // Validation Errors (LTNS_0300-LTNS_0399)
191
+ // =====================================================
192
+
193
+ VALIDATION_FAILED: {
194
+ code: 'LTNS_0300',
195
+ message: 'Validation failed',
196
+ translations: {
197
+ de: 'Die Validierung ist fehlgeschlagen.',
198
+ en: 'Validation failed.',
199
+ },
200
+ },
201
+
202
+ REQUIRED_FIELD_MISSING: {
203
+ code: 'LTNS_0301',
204
+ message: 'Required field missing',
205
+ translations: {
206
+ de: 'Ein erforderliches Feld fehlt.',
207
+ en: 'A required field is missing.',
208
+ },
209
+ },
210
+
211
+ INVALID_FIELD_FORMAT: {
212
+ code: 'LTNS_0302',
213
+ message: 'Invalid field format',
214
+ translations: {
215
+ de: 'Das Feldformat ist ungültig.',
216
+ en: 'The field format is invalid.',
217
+ },
218
+ },
219
+
220
+ // =====================================================
221
+ // Resource Errors (LTNS_0400-LTNS_0499)
222
+ // =====================================================
223
+
224
+ RESOURCE_NOT_FOUND: {
225
+ code: 'LTNS_0400',
226
+ message: 'Resource not found',
227
+ translations: {
228
+ de: 'Die angeforderte Ressource wurde nicht gefunden.',
229
+ en: 'The requested resource was not found.',
230
+ },
231
+ },
232
+
233
+ RESOURCE_ALREADY_EXISTS: {
234
+ code: 'LTNS_0401',
235
+ message: 'Resource already exists',
236
+ translations: {
237
+ de: 'Diese Ressource existiert bereits.',
238
+ en: 'This resource already exists.',
239
+ },
240
+ },
241
+
242
+ // =====================================================
243
+ // File Errors (LTNS_0500-LTNS_0599)
244
+ // =====================================================
245
+
246
+ FILE_NOT_FOUND: {
247
+ code: 'LTNS_0500',
248
+ message: 'File not found',
249
+ translations: {
250
+ de: 'Die Datei wurde nicht gefunden.',
251
+ en: 'The file was not found.',
252
+ },
253
+ },
254
+
255
+ FILE_UPLOAD_FAILED: {
256
+ code: 'LTNS_0501',
257
+ message: 'File upload failed',
258
+ translations: {
259
+ de: 'Der Datei-Upload ist fehlgeschlagen.',
260
+ en: 'The file upload failed.',
261
+ },
262
+ },
263
+
264
+ FILE_TYPE_NOT_ALLOWED: {
265
+ code: 'LTNS_0502',
266
+ message: 'File type not allowed',
267
+ translations: {
268
+ de: 'Dieser Dateityp ist nicht erlaubt.',
269
+ en: 'This file type is not allowed.',
270
+ },
271
+ },
272
+
273
+ // =====================================================
274
+ // Internal Errors (LTNS_0900-LTNS_0999)
275
+ // =====================================================
276
+
277
+ INTERNAL_ERROR: {
278
+ code: 'LTNS_0900',
279
+ message: 'Internal server error',
280
+ translations: {
281
+ de: 'Ein interner Serverfehler ist aufgetreten.',
282
+ en: 'An internal server error occurred.',
283
+ },
284
+ },
285
+
286
+ SERVICE_UNAVAILABLE: {
287
+ code: 'LTNS_0901',
288
+ message: 'Service temporarily unavailable',
289
+ translations: {
290
+ de: 'Der Dienst ist vorübergehend nicht verfügbar.',
291
+ en: 'The service is temporarily unavailable.',
292
+ },
293
+ },
294
+
295
+ LEGACY_AUTH_DISABLED: {
296
+ code: 'LTNS_0902',
297
+ message: 'Legacy authentication is disabled',
298
+ translations: {
299
+ de: 'Die Legacy-Authentifizierung ist deaktiviert. Bitte nutzen Sie die neue Authentifizierung.',
300
+ en: 'Legacy authentication is disabled. Please use the new authentication.',
301
+ },
302
+ },
303
+ } as const satisfies IErrorRegistry;
304
+ /* eslint-enable perfectionist/sort-objects */
305
+
306
+ // =====================================================
307
+ // Generated ErrorCode Object
308
+ // =====================================================
309
+
310
+ /**
311
+ * Generate formatted error message from definition
312
+ * Format: #CODE: Message
313
+ */
314
+ function formatErrorMessage(def: IErrorDefinition): string {
315
+ return `#${def.code}: ${def.message}`;
316
+ }
317
+
318
+ /**
319
+ * Generate ErrorCode object from registry
320
+ * Maps each key to its formatted error string
321
+ */
322
+ function generateErrorCodes<T extends IErrorRegistry>(registry: T): { [K in keyof T]: string } {
323
+ const result = {} as { [K in keyof T]: string };
324
+ for (const key of Object.keys(registry) as Array<keyof T>) {
325
+ result[key] = formatErrorMessage(registry[key]);
326
+ }
327
+ return result;
328
+ }
329
+
330
+ /**
331
+ * ErrorCode - Use this in your code with NestJS exceptions
332
+ *
333
+ * @example
334
+ * ```typescript
335
+ * throw new UnauthorizedException(ErrorCode.UNAUTHORIZED);
336
+ * // Response: { statusCode: 401, message: "#LTNS_0100: Unauthorized - User is not logged in" }
337
+ * ```
338
+ */
339
+ export const ErrorCode = generateErrorCodes(LtnsErrors);
340
+
341
+ // =====================================================
342
+ // Type Exports
343
+ // =====================================================
344
+
345
+ /**
346
+ * Type for error code keys (readable names like USER_NOT_FOUND)
347
+ */
348
+ export type ErrorCodeKey = keyof typeof ErrorCode;
349
+
350
+ /**
351
+ * Type for all error code formatted strings
352
+ */
353
+ export type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];
354
+
355
+ /**
356
+ * Type for raw error codes (like LTNS_0100)
357
+ */
358
+ export type RawErrorCode = (typeof LtnsErrors)[keyof typeof LtnsErrors]['code'];
359
+
360
+ // =====================================================
361
+ // Helper Functions
362
+ // =====================================================
363
+
364
+ /**
365
+ * Get all error definitions (for i18n endpoint)
366
+ *
367
+ * @returns All error definitions from the registry
368
+ */
369
+ export function getAllErrorDefinitions(): typeof LtnsErrors {
370
+ return LtnsErrors;
371
+ }
372
+
373
+ // =====================================================
374
+ // Extension Support
375
+ // =====================================================
376
+
377
+ /**
378
+ * Merge project-specific errors with core errors
379
+ *
380
+ * @param projectErrors - Project-specific error registry
381
+ * @returns Merged error codes object
382
+ *
383
+ * @example
384
+ * ```typescript
385
+ * // In your project
386
+ * const ProjectErrors = {
387
+ * ORDER_NOT_FOUND: {
388
+ * code: 'PROJ_0001',
389
+ * message: 'Order not found',
390
+ * translations: { de: 'Bestellung nicht gefunden.', en: 'Order not found.' }
391
+ * }
392
+ * } as const satisfies IErrorRegistry;
393
+ *
394
+ * export const ErrorCode = mergeErrorCodes(ProjectErrors);
395
+ * // Contains both LTNS_* and PROJ_* errors
396
+ * ```
397
+ */
398
+ export function mergeErrorCodes<T extends IErrorRegistry>(
399
+ projectErrors: T,
400
+ ): { [K in keyof T | keyof typeof LtnsErrors]: string } {
401
+ return {
402
+ ...ErrorCode,
403
+ ...generateErrorCodes(projectErrors),
404
+ } as { [K in keyof T | keyof typeof LtnsErrors]: string };
405
+ }
@@ -0,0 +1,14 @@
1
+ // Controller
2
+ export * from './core-error-code.controller';
3
+
4
+ // Service
5
+ export * from './core-error-code.service';
6
+
7
+ // Module
8
+ export * from './error-code.module';
9
+
10
+ // Error Codes
11
+ export * from './error-codes';
12
+
13
+ // Interfaces
14
+ export * from './interfaces/error-code.interfaces';
@@ -0,0 +1,99 @@
1
+ import { Type } from '@nestjs/common';
2
+
3
+ import { CoreErrorCodeService } from '../core-error-code.service';
4
+ import { IErrorRegistry } from '../error-codes';
5
+
6
+ /**
7
+ * Configuration for the error code module
8
+ */
9
+ export interface IErrorCodeModuleConfig {
10
+ /**
11
+ * Additional error registry to merge with core errors
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * const ProjectErrors = {
16
+ * ORDER_NOT_FOUND: {
17
+ * code: 'PROJ_0001',
18
+ * message: 'Order not found',
19
+ * translations: { de: 'Bestellung nicht gefunden.', en: 'Order not found.' }
20
+ * }
21
+ * } as const satisfies IErrorRegistry;
22
+ *
23
+ * ErrorCodeModule.forRoot({ additionalErrorRegistry: ProjectErrors })
24
+ * ```
25
+ */
26
+ additionalErrorRegistry?: IErrorRegistry;
27
+
28
+ /**
29
+ * Custom controller class to use instead of CoreErrorCodeController.
30
+ *
31
+ * **Note:** Use a standalone controller (not extending CoreErrorCodeController)
32
+ * to ensure correct route registration order when adding new routes.
33
+ * NestJS registers parent routes first, which can cause parameterized routes
34
+ * to intercept static routes.
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * // Standalone controller (RECOMMENDED)
39
+ * @Controller('api/i18n/errors')
40
+ * export class ErrorCodeController {
41
+ * constructor(protected readonly errorCodeService: ErrorCodeService) {}
42
+ *
43
+ * @Get('codes') // Must be defined BEFORE :locale
44
+ * @Roles(RoleEnum.S_EVERYONE)
45
+ * getAllCodes(): string[] {
46
+ * return this.errorCodeService.getErrorCodes();
47
+ * }
48
+ *
49
+ * @Get(':locale')
50
+ * @Roles(RoleEnum.S_EVERYONE)
51
+ * getTranslations(@Param('locale') locale: string) { ... }
52
+ * }
53
+ *
54
+ * // In your module
55
+ * ErrorCodeModule.forRoot({
56
+ * controller: ErrorCodeController,
57
+ * service: ErrorCodeService,
58
+ * })
59
+ * ```
60
+ */
61
+ controller?: Type<any>;
62
+
63
+ /**
64
+ * Custom service class to use instead of CoreErrorCodeService.
65
+ * The class must extend CoreErrorCodeService.
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * // Your custom service with additional locales
70
+ * @Injectable()
71
+ * export class ErrorCodeService extends CoreErrorCodeService {
72
+ * protected override supportedLocales: SupportedLocale[] = ['de', 'en', 'fr', 'es'];
73
+ *
74
+ * constructor() {
75
+ * super();
76
+ * this.registerErrorRegistry(ProjectErrors);
77
+ * }
78
+ * }
79
+ *
80
+ * // In your module
81
+ * ErrorCodeModule.forRoot({
82
+ * service: ErrorCodeService,
83
+ * })
84
+ * ```
85
+ */
86
+ service?: Type<CoreErrorCodeService>;
87
+ }
88
+
89
+ /**
90
+ * Response format for the translation endpoint
91
+ */
92
+ export interface IErrorTranslationResponse {
93
+ errors: Record<string, string>;
94
+ }
95
+
96
+ /**
97
+ * Supported locales for error translations
98
+ */
99
+ export type SupportedLocale = 'de' | 'en';
@@ -22,6 +22,7 @@ import { TemplateService } from './core/common/services/template.service';
22
22
  import { BetterAuthUserMapper } from './core/modules/better-auth/better-auth-user.mapper';
23
23
  import { BetterAuthModule } from './core/modules/better-auth/better-auth.module';
24
24
  import { BetterAuthService } from './core/modules/better-auth/better-auth.service';
25
+ import { ErrorCodeModule } from './core/modules/error-code/error-code.module';
25
26
  import { CoreHealthCheckModule } from './core/modules/health-check/core-health-check.module';
26
27
 
27
28
  /**
@@ -226,6 +227,21 @@ export class CoreModule implements NestModule {
226
227
  Object.assign({ driver: ApolloDriver }, config.graphQl.driver, config.graphQl.options),
227
228
  ),
228
229
  ];
230
+
231
+ // Add ErrorCodeModule based on configuration
232
+ // autoRegister defaults to true (backward compatible)
233
+ const errorCodeConfig = config.errorCode;
234
+ const isErrorCodeAutoRegister = errorCodeConfig?.autoRegister !== false;
235
+
236
+ if (isErrorCodeAutoRegister) {
237
+ // Always use forRoot() - it registers the controller and handles configuration
238
+ imports.push(
239
+ ErrorCodeModule.forRoot({
240
+ additionalErrorRegistry: errorCodeConfig?.additionalErrorRegistry,
241
+ }),
242
+ );
243
+ }
244
+
229
245
  if (config.healthCheck) {
230
246
  imports.push(CoreHealthCheckModule);
231
247
  }
package/src/index.ts CHANGED
@@ -131,6 +131,12 @@ export * from './core/modules/auth/tokens.decorator';
131
131
 
132
132
  export * from './core/modules/better-auth';
133
133
 
134
+ // =====================================================================================================================
135
+ // Core - Modules - ErrorCode
136
+ // =====================================================================================================================
137
+
138
+ export * from './core/modules/error-code';
139
+
134
140
  // =====================================================================================================================
135
141
  // Core - Modules - File
136
142
  // =====================================================================================================================