@lenne.tech/nest-server 11.8.0 → 11.10.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 (173) hide show
  1. package/dist/config.env.js +5 -0
  2. package/dist/config.env.js.map +1 -1
  3. package/dist/core/common/helpers/logging.helper.d.ts +6 -0
  4. package/dist/core/common/helpers/logging.helper.js +55 -0
  5. package/dist/core/common/helpers/logging.helper.js.map +1 -0
  6. package/dist/core/common/interfaces/server-options.interface.d.ts +50 -19
  7. package/dist/core/modules/auth/guards/roles.guard.js +37 -5
  8. package/dist/core/modules/auth/guards/roles.guard.js.map +1 -1
  9. package/dist/core/modules/auth/services/core-auth.service.d.ts +5 -5
  10. package/dist/core/modules/auth/services/core-auth.service.js +9 -8
  11. package/dist/core/modules/auth/services/core-auth.service.js.map +1 -1
  12. package/dist/core/modules/auth/tokens.decorator.d.ts +1 -1
  13. package/dist/core/modules/better-auth/better-auth.config.js +32 -10
  14. package/dist/core/modules/better-auth/better-auth.config.js.map +1 -1
  15. package/dist/core/modules/better-auth/better-auth.resolver.d.ts +16 -16
  16. package/dist/core/modules/better-auth/better-auth.resolver.js +34 -34
  17. package/dist/core/modules/better-auth/better-auth.resolver.js.map +1 -1
  18. package/dist/core/modules/better-auth/better-auth.types.d.ts +2 -1
  19. package/dist/core/modules/better-auth/better-auth.types.js.map +1 -1
  20. package/dist/core/modules/better-auth/core-better-auth-api.middleware.d.ts +10 -0
  21. package/dist/core/modules/better-auth/core-better-auth-api.middleware.js +91 -0
  22. package/dist/core/modules/better-auth/core-better-auth-api.middleware.js.map +1 -0
  23. package/dist/core/modules/better-auth/core-better-auth-auth.model.d.ts +9 -0
  24. package/dist/core/modules/better-auth/{better-auth-auth.model.js → core-better-auth-auth.model.js} +17 -17
  25. package/dist/core/modules/better-auth/core-better-auth-auth.model.js.map +1 -0
  26. package/dist/core/modules/better-auth/{better-auth-migration-status.model.d.ts → core-better-auth-migration-status.model.d.ts} +1 -1
  27. package/dist/core/modules/better-auth/{better-auth-migration-status.model.js → core-better-auth-migration-status.model.js} +14 -14
  28. package/dist/core/modules/better-auth/core-better-auth-migration-status.model.js.map +1 -0
  29. package/dist/core/modules/better-auth/{better-auth-models.d.ts → core-better-auth-models.d.ts} +8 -8
  30. package/dist/core/modules/better-auth/{better-auth-models.js → core-better-auth-models.js} +61 -61
  31. package/dist/core/modules/better-auth/core-better-auth-models.js.map +1 -0
  32. package/dist/core/modules/better-auth/core-better-auth-rate-limit.middleware.d.ts +12 -0
  33. package/dist/core/modules/better-auth/{better-auth-rate-limit.middleware.js → core-better-auth-rate-limit.middleware.js} +10 -10
  34. package/dist/core/modules/better-auth/core-better-auth-rate-limit.middleware.js.map +1 -0
  35. package/dist/core/modules/better-auth/{better-auth-rate-limiter.service.d.ts → core-better-auth-rate-limiter.service.d.ts} +1 -1
  36. package/dist/core/modules/better-auth/{better-auth-rate-limiter.service.js → core-better-auth-rate-limiter.service.js} +8 -8
  37. package/dist/core/modules/better-auth/core-better-auth-rate-limiter.service.js.map +1 -0
  38. package/dist/core/modules/better-auth/{better-auth-user.mapper.d.ts → core-better-auth-user.mapper.d.ts} +1 -1
  39. package/dist/core/modules/better-auth/{better-auth-user.mapper.js → core-better-auth-user.mapper.js} +10 -9
  40. package/dist/core/modules/better-auth/core-better-auth-user.mapper.js.map +1 -0
  41. package/dist/core/modules/better-auth/core-better-auth-web.helper.d.ts +19 -0
  42. package/dist/core/modules/better-auth/core-better-auth-web.helper.js +152 -0
  43. package/dist/core/modules/better-auth/core-better-auth-web.helper.js.map +1 -0
  44. package/dist/core/modules/better-auth/core-better-auth.controller.d.ts +23 -32
  45. package/dist/core/modules/better-auth/core-better-auth.controller.js +184 -201
  46. package/dist/core/modules/better-auth/core-better-auth.controller.js.map +1 -1
  47. package/dist/core/modules/better-auth/core-better-auth.middleware.d.ts +22 -0
  48. package/dist/core/modules/better-auth/{better-auth.middleware.js → core-better-auth.middleware.js} +45 -18
  49. package/dist/core/modules/better-auth/core-better-auth.middleware.js.map +1 -0
  50. package/dist/core/modules/better-auth/{better-auth.module.d.ts → core-better-auth.module.d.ts} +6 -6
  51. package/dist/core/modules/better-auth/{better-auth.module.js → core-better-auth.module.js} +65 -60
  52. package/dist/core/modules/better-auth/core-better-auth.module.js.map +1 -0
  53. package/dist/core/modules/better-auth/core-better-auth.resolver.d.ts +19 -19
  54. package/dist/core/modules/better-auth/core-better-auth.resolver.js +18 -18
  55. package/dist/core/modules/better-auth/core-better-auth.resolver.js.map +1 -1
  56. package/dist/core/modules/better-auth/{better-auth.service.d.ts → core-better-auth.service.d.ts} +3 -2
  57. package/dist/core/modules/better-auth/{better-auth.service.js → core-better-auth.service.js} +75 -35
  58. package/dist/core/modules/better-auth/core-better-auth.service.js.map +1 -0
  59. package/dist/core/modules/better-auth/index.d.ts +11 -9
  60. package/dist/core/modules/better-auth/index.js +11 -9
  61. package/dist/core/modules/better-auth/index.js.map +1 -1
  62. package/dist/core/modules/error-code/core-error-code.controller.d.ts +7 -0
  63. package/dist/core/modules/error-code/core-error-code.controller.js +45 -0
  64. package/dist/core/modules/error-code/core-error-code.controller.js.map +1 -0
  65. package/dist/core/modules/error-code/core-error-code.service.d.ts +16 -0
  66. package/dist/core/modules/error-code/core-error-code.service.js +65 -0
  67. package/dist/core/modules/error-code/core-error-code.service.js.map +1 -0
  68. package/dist/core/modules/error-code/error-code.module.d.ts +7 -0
  69. package/dist/core/modules/error-code/error-code.module.js +64 -0
  70. package/dist/core/modules/error-code/error-code.module.js.map +1 -0
  71. package/dist/core/modules/error-code/error-codes.d.ts +219 -0
  72. package/dist/core/modules/error-code/error-codes.js +204 -0
  73. package/dist/core/modules/error-code/error-codes.js.map +1 -0
  74. package/dist/core/modules/error-code/index.d.ts +5 -0
  75. package/dist/core/modules/error-code/index.js +22 -0
  76. package/dist/core/modules/error-code/index.js.map +1 -0
  77. package/dist/core/modules/error-code/interfaces/error-code.interfaces.d.ts +12 -0
  78. package/dist/core/modules/error-code/interfaces/error-code.interfaces.js +3 -0
  79. package/dist/core/modules/error-code/interfaces/error-code.interfaces.js.map +1 -0
  80. package/dist/core/modules/user/interfaces/core-user-service-options.interface.d.ts +2 -2
  81. package/dist/core.module.js +14 -6
  82. package/dist/core.module.js.map +1 -1
  83. package/dist/index.d.ts +2 -0
  84. package/dist/index.js +2 -0
  85. package/dist/index.js.map +1 -1
  86. package/dist/server/modules/better-auth/better-auth.controller.d.ts +5 -5
  87. package/dist/server/modules/better-auth/better-auth.controller.js +4 -4
  88. package/dist/server/modules/better-auth/better-auth.controller.js.map +1 -1
  89. package/dist/server/modules/better-auth/better-auth.module.js +3 -3
  90. package/dist/server/modules/better-auth/better-auth.module.js.map +1 -1
  91. package/dist/server/modules/better-auth/better-auth.resolver.d.ts +17 -17
  92. package/dist/server/modules/better-auth/better-auth.resolver.js +18 -18
  93. package/dist/server/modules/better-auth/better-auth.resolver.js.map +1 -1
  94. package/dist/server/modules/error-code/error-code.controller.d.ts +8 -0
  95. package/dist/server/modules/error-code/error-code.controller.js +55 -0
  96. package/dist/server/modules/error-code/error-code.controller.js.map +1 -0
  97. package/dist/server/modules/error-code/error-code.service.d.ts +4 -0
  98. package/dist/server/modules/error-code/error-code.service.js +27 -0
  99. package/dist/server/modules/error-code/error-code.service.js.map +1 -0
  100. package/dist/server/modules/error-code/error-codes.d.ts +45 -0
  101. package/dist/server/modules/error-code/error-codes.js +24 -0
  102. package/dist/server/modules/error-code/error-codes.js.map +1 -0
  103. package/dist/server/modules/error-code/index.d.ts +3 -0
  104. package/dist/server/modules/error-code/index.js +20 -0
  105. package/dist/server/modules/error-code/index.js.map +1 -0
  106. package/dist/server/modules/user/user.service.d.ts +2 -2
  107. package/dist/server/modules/user/user.service.js +2 -2
  108. package/dist/server/modules/user/user.service.js.map +1 -1
  109. package/dist/server/server.module.js +7 -0
  110. package/dist/server/server.module.js.map +1 -1
  111. package/dist/test/test.helper.d.ts +1 -0
  112. package/dist/test/test.helper.js +5 -1
  113. package/dist/test/test.helper.js.map +1 -1
  114. package/dist/tsconfig.build.tsbuildinfo +1 -1
  115. package/package.json +6 -4
  116. package/src/config.env.ts +19 -0
  117. package/src/core/common/helpers/logging.helper.ts +134 -0
  118. package/src/core/common/interfaces/server-options.interface.ts +511 -237
  119. package/src/core/modules/auth/guards/roles.guard.ts +49 -7
  120. package/src/core/modules/auth/services/core-auth.service.ts +9 -8
  121. package/src/core/modules/better-auth/ARCHITECTURE.md +102 -0
  122. package/src/core/modules/better-auth/INTEGRATION-CHECKLIST.md +277 -8
  123. package/src/core/modules/better-auth/README.md +97 -53
  124. package/src/core/modules/better-auth/better-auth.config.ts +66 -18
  125. package/src/core/modules/better-auth/better-auth.resolver.ts +32 -32
  126. package/src/core/modules/better-auth/better-auth.types.ts +3 -2
  127. package/src/core/modules/better-auth/core-better-auth-api.middleware.ts +134 -0
  128. package/src/core/modules/better-auth/{better-auth-auth.model.ts → core-better-auth-auth.model.ts} +6 -6
  129. package/src/core/modules/better-auth/{better-auth-migration-status.model.ts → core-better-auth-migration-status.model.ts} +1 -1
  130. package/src/core/modules/better-auth/{better-auth-models.ts → core-better-auth-models.ts} +9 -9
  131. package/src/core/modules/better-auth/{better-auth-rate-limit.middleware.ts → core-better-auth-rate-limit.middleware.ts} +5 -5
  132. package/src/core/modules/better-auth/{better-auth-rate-limiter.service.ts → core-better-auth-rate-limiter.service.ts} +2 -2
  133. package/src/core/modules/better-auth/{better-auth-user.mapper.ts → core-better-auth-user.mapper.ts} +4 -3
  134. package/src/core/modules/better-auth/core-better-auth-web.helper.ts +272 -0
  135. package/src/core/modules/better-auth/core-better-auth.controller.ts +386 -230
  136. package/src/core/modules/better-auth/{better-auth.middleware.ts → core-better-auth.middleware.ts} +57 -17
  137. package/src/core/modules/better-auth/{better-auth.module.ts → core-better-auth.module.ts} +77 -66
  138. package/src/core/modules/better-auth/core-better-auth.resolver.ts +42 -42
  139. package/src/core/modules/better-auth/{better-auth.service.ts → core-better-auth.service.ts} +86 -40
  140. package/src/core/modules/better-auth/index.ts +18 -11
  141. package/src/core/modules/error-code/INTEGRATION-CHECKLIST.md +291 -0
  142. package/src/core/modules/error-code/core-error-code.controller.ts +55 -0
  143. package/src/core/modules/error-code/core-error-code.service.ts +135 -0
  144. package/src/core/modules/error-code/error-code.module.ts +119 -0
  145. package/src/core/modules/error-code/error-codes.ts +405 -0
  146. package/src/core/modules/error-code/index.ts +14 -0
  147. package/src/core/modules/error-code/interfaces/error-code.interfaces.ts +99 -0
  148. package/src/core/modules/user/interfaces/core-user-service-options.interface.ts +3 -3
  149. package/src/core.module.ts +28 -12
  150. package/src/index.ts +7 -0
  151. package/src/server/modules/better-auth/better-auth.controller.ts +4 -4
  152. package/src/server/modules/better-auth/better-auth.module.ts +1 -1
  153. package/src/server/modules/better-auth/better-auth.resolver.ts +31 -31
  154. package/src/server/modules/error-code/README.md +131 -0
  155. package/src/server/modules/error-code/error-code.controller.ts +91 -0
  156. package/src/server/modules/error-code/error-code.service.ts +42 -0
  157. package/src/server/modules/error-code/error-codes.ts +65 -0
  158. package/src/server/modules/error-code/index.ts +8 -0
  159. package/src/server/modules/user/user.service.ts +2 -2
  160. package/src/server/server.module.ts +10 -0
  161. package/src/test/test.helper.ts +13 -1
  162. package/dist/core/modules/better-auth/better-auth-auth.model.d.ts +0 -9
  163. package/dist/core/modules/better-auth/better-auth-auth.model.js.map +0 -1
  164. package/dist/core/modules/better-auth/better-auth-migration-status.model.js.map +0 -1
  165. package/dist/core/modules/better-auth/better-auth-models.js.map +0 -1
  166. package/dist/core/modules/better-auth/better-auth-rate-limit.middleware.d.ts +0 -12
  167. package/dist/core/modules/better-auth/better-auth-rate-limit.middleware.js.map +0 -1
  168. package/dist/core/modules/better-auth/better-auth-rate-limiter.service.js.map +0 -1
  169. package/dist/core/modules/better-auth/better-auth-user.mapper.js.map +0 -1
  170. package/dist/core/modules/better-auth/better-auth.middleware.d.ts +0 -21
  171. package/dist/core/modules/better-auth/better-auth.middleware.js.map +0 -1
  172. package/dist/core/modules/better-auth/better-auth.module.js.map +0 -1
  173. package/dist/core/modules/better-auth/better-auth.service.js.map +0 -1
@@ -0,0 +1,291 @@
1
+ # ErrorCode Integration Checklist
2
+
3
+ **For integrating custom error codes into projects using `@lenne.tech/nest-server`.**
4
+
5
+ > **Estimated time:** 5-10 minutes
6
+
7
+ ---
8
+
9
+ ## Choose Your Scenario
10
+
11
+ | Scenario | Use When | Configuration | Complexity |
12
+ |----------|----------|---------------|------------|
13
+ | **A. additionalErrorRegistry** | Simple error code addition | Config in `config.env.ts` | Minimal |
14
+ | **B. Custom Service** | Need custom locales or logic | Service inheritance | Low |
15
+ | **C. Custom Controller** | Need custom controller/routes | Service + Controller | Medium |
16
+
17
+ **Recommendation:** Start with **Scenario A**. Only use B or C if you need customization beyond adding error codes.
18
+
19
+ ---
20
+
21
+ ## Reference Implementation
22
+
23
+ All files are available as reference in the package:
24
+
25
+ **Local (in your node_modules):**
26
+ ```
27
+ node_modules/@lenne.tech/nest-server/src/server/modules/error-code/
28
+ ```
29
+
30
+ **GitHub:**
31
+ https://github.com/lenneTech/nest-server/tree/develop/src/server/modules/error-code
32
+
33
+ ---
34
+
35
+ ## Scenario A: additionalErrorRegistry (Simplest)
36
+
37
+ Use this when you just want to add project-specific error codes.
38
+
39
+ ### 1. Define Error Codes
40
+
41
+ **Create:** `src/server/common/errors/project-errors.ts`
42
+
43
+ ```typescript
44
+ import { IErrorRegistry, mergeErrorCodes } from '@lenne.tech/nest-server';
45
+
46
+ /**
47
+ * Project-specific error codes
48
+ *
49
+ * Format: PREFIX_XXXX (e.g., PROJ_0001, APP_0001)
50
+ * Use a unique prefix to avoid collisions with LTNS_* core errors.
51
+ */
52
+ export const ProjectErrors = {
53
+ ORDER_NOT_FOUND: {
54
+ code: 'PROJ_0001',
55
+ message: 'Order not found',
56
+ translations: {
57
+ de: 'Bestellung mit ID {orderId} wurde nicht gefunden.',
58
+ en: 'Order with ID {orderId} was not found.',
59
+ },
60
+ },
61
+ PAYMENT_FAILED: {
62
+ code: 'PROJ_0002',
63
+ message: 'Payment processing failed',
64
+ translations: {
65
+ de: 'Die Zahlung konnte nicht verarbeitet werden: {reason}',
66
+ en: 'Payment processing failed: {reason}',
67
+ },
68
+ },
69
+ } as const satisfies IErrorRegistry;
70
+
71
+ // Merged error codes for type-safe factory functions
72
+ export const ErrorCode = mergeErrorCodes(ProjectErrors);
73
+ ```
74
+
75
+ ### 2. Add to config.env.ts
76
+
77
+ ```typescript
78
+ import { ProjectErrors } from './server/common/errors/project-errors';
79
+
80
+ const config = {
81
+ // ... other config ...
82
+ errorCode: {
83
+ additionalErrorRegistry: ProjectErrors,
84
+ },
85
+ };
86
+ ```
87
+
88
+ **Done!** Your project errors are now available via `/api/i18n/errors/:locale`.
89
+
90
+ ---
91
+
92
+ ## Scenario B: Custom Service (For Custom Locales)
93
+
94
+ Use this when you need:
95
+ - Additional locales (e.g., French, Spanish)
96
+ - Custom logic in the service
97
+
98
+ ### 1. Define Error Codes
99
+
100
+ Same as Scenario A, Step 1.
101
+
102
+ ### 2. Create Custom Service
103
+
104
+ **Create:** `src/server/modules/error-code/error-code.service.ts`
105
+ **Copy from:** `node_modules/@lenne.tech/nest-server/src/server/modules/error-code/error-code.service.ts`
106
+
107
+ **Optional customization - add locales:**
108
+ ```typescript
109
+ @Injectable()
110
+ export class ErrorCodeService extends CoreErrorCodeService {
111
+ // Override to add more locales
112
+ protected override supportedLocales = ['de', 'en', 'fr', 'es'] as const;
113
+
114
+ constructor() {
115
+ super();
116
+ this.registerErrorRegistry(ProjectErrors);
117
+ }
118
+ }
119
+ ```
120
+
121
+ ### 3. Disable Auto-Registration
122
+
123
+ **Update:** `src/config.env.ts`
124
+
125
+ ```typescript
126
+ const config = {
127
+ // ... other config ...
128
+ errorCode: {
129
+ autoRegister: false, // Required! Prevents CoreModule from registering its own
130
+ },
131
+ };
132
+ ```
133
+
134
+ **WHY is `autoRegister: false` required?**
135
+ NestJS @Global() modules use "first wins" for provider registration. Without this, CoreModule's ErrorCodeModule loads first and your custom service is ignored.
136
+
137
+ ### 4. Register in ServerModule
138
+
139
+ **Update:** `src/server/server.module.ts`
140
+
141
+ ```typescript
142
+ import { ErrorCodeModule as CoreErrorCodeModule } from '@lenne.tech/nest-server';
143
+ import { ErrorCodeService } from './modules/error-code/error-code.service';
144
+
145
+ @Module({
146
+ imports: [
147
+ CoreModule.forRoot(...),
148
+ // Register with custom service
149
+ CoreErrorCodeModule.forRoot({
150
+ service: ErrorCodeService,
151
+ }),
152
+ // ... other modules
153
+ ],
154
+ })
155
+ export class ServerModule {}
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Scenario C: Custom Controller (For Custom Routes)
161
+
162
+ Use this when you need:
163
+ - Custom controller endpoints (e.g., `/codes` listing)
164
+ - Different route paths
165
+ - Additional REST endpoints
166
+
167
+ **No custom module needed!** Use Core `ErrorCodeModule.forRoot()` with your custom controller and service.
168
+
169
+ ### 1. Create Files
170
+
171
+ **Copy from:** `node_modules/@lenne.tech/nest-server/src/server/modules/error-code/`
172
+
173
+ Files needed:
174
+ - `error-codes.ts` - Your error definitions
175
+ - `error-code.service.ts` - Service extending CoreErrorCodeService
176
+ - `error-code.controller.ts` - Controller (**standalone**, not extending)
177
+ - `index.ts` - Exports
178
+
179
+ **No `error-code.module.ts` needed!**
180
+
181
+ ### 2. Disable Auto-Registration
182
+
183
+ Same as Scenario B, Step 3.
184
+
185
+ ### 3. Register via Core ErrorCodeModule
186
+
187
+ **Update:** `src/server/server.module.ts`
188
+
189
+ ```typescript
190
+ import { ErrorCodeModule } from '@lenne.tech/nest-server';
191
+ import { ErrorCodeController } from './modules/error-code/error-code.controller';
192
+ import { ErrorCodeService } from './modules/error-code/error-code.service';
193
+
194
+ @Module({
195
+ imports: [
196
+ CoreModule.forRoot(...),
197
+ // Use Core ErrorCodeModule with custom service and controller
198
+ ErrorCodeModule.forRoot({
199
+ controller: ErrorCodeController,
200
+ service: ErrorCodeService,
201
+ }),
202
+ // ... other modules
203
+ ],
204
+ })
205
+ export class ServerModule {}
206
+ ```
207
+
208
+ **WHY standalone controller instead of extending?**
209
+ NestJS registers routes from parent classes first, regardless of method order in child classes. This causes `:locale` to intercept `/codes`. A standalone controller ensures correct route order: static routes (`/codes`) first, then parameterized routes (`:locale`).
210
+
211
+ ---
212
+
213
+ ## Verification Checklist
214
+
215
+ After integration, verify:
216
+
217
+ - [ ] `npm run build` succeeds without errors
218
+ - [ ] `npm test` passes
219
+ - [ ] `GET /api/i18n/errors/de` returns your project error codes
220
+ - [ ] `GET /api/i18n/errors/en` returns English translations
221
+ - [ ] Error codes follow format `PREFIX_XXXX` (e.g., `PROJ_0001`)
222
+ - [ ] Translations include placeholders where needed (`{param}`)
223
+
224
+ ### For Scenario C only:
225
+ - [ ] `GET /api/i18n/errors/codes` returns all error codes (if implemented)
226
+
227
+ ---
228
+
229
+ ## Common Mistakes
230
+
231
+ | Mistake | Symptom | Fix |
232
+ |---------|---------|-----|
233
+ | Forgot `autoRegister: false` | Project errors not appearing | Add `errorCode: { autoRegister: false }` to config |
234
+ | Wrong error code format | Validation errors | Use `PREFIX_XXXX` format (4 digits) |
235
+ | Missing translations | Runtime errors | Ensure all locales have translations |
236
+ | Controller extends CoreErrorCodeController | `/codes` returns 404 | Use standalone controller |
237
+ | Duplicate error codes | Unpredictable behavior | Ensure unique codes across all registries |
238
+ | Forgot to import module | No error translations | Import ErrorCodeModule in ServerModule |
239
+
240
+ ---
241
+
242
+ ## Using Error Codes in Code
243
+
244
+ ```typescript
245
+ import { ErrorCode, Errors } from '@lenne.tech/nest-server';
246
+
247
+ // Type-safe error code access
248
+ const code = ErrorCode.userNotFound; // Returns '#LTNS_0001: User not found'
249
+
250
+ // Factory functions with parameters
251
+ throw new BadRequestException(Errors.userNotFound({ email: 'test@example.com' }));
252
+ // Throws: '#LTNS_0001: User with email test@example.com was not found.'
253
+
254
+ // Project-specific errors (after registration)
255
+ import { ErrorCode as ProjectErrorCode } from './common/errors/project-errors';
256
+
257
+ const orderCode = ProjectErrorCode.ORDER_NOT_FOUND; // '#PROJ_0001: Order not found'
258
+ ```
259
+
260
+ ---
261
+
262
+ ## API Reference
263
+
264
+ ### REST Endpoints
265
+
266
+ | Endpoint | Method | Description |
267
+ |----------|--------|-------------|
268
+ | `/api/i18n/errors/:locale` | GET | Get translations for locale (de, en, ...) |
269
+ | `/api/i18n/errors/codes` | GET | Get all error codes (Scenario C only) |
270
+
271
+ ### Response Format (Nuxt i18n compatible)
272
+
273
+ ```json
274
+ {
275
+ "errors": {
276
+ "LTNS_0001": "Benutzer wurde nicht gefunden.",
277
+ "LTNS_0100": "Sie sind nicht angemeldet.",
278
+ "PROJ_0001": "Bestellung mit ID {orderId} wurde nicht gefunden."
279
+ }
280
+ }
281
+ ```
282
+
283
+ > **Note:** Core LTNS_* translations are user-friendly messages without placeholders. Project-specific errors (PROJ_*) may include placeholders like `{orderId}` if defined in your `ProjectErrors` registry.
284
+
285
+ ---
286
+
287
+ ## Detailed Documentation
288
+
289
+ For complete API reference and advanced topics:
290
+ - **Core Error Codes:** `node_modules/@lenne.tech/nest-server/src/core/modules/error-code/error-codes.ts`
291
+ - **Interfaces:** `node_modules/@lenne.tech/nest-server/src/core/modules/error-code/interfaces/error-code.interfaces.ts`
@@ -0,0 +1,55 @@
1
+ import { Controller, Get, NotFoundException, Param } from '@nestjs/common';
2
+
3
+ import { Roles } from '../../common/decorators/roles.decorator';
4
+ import { RoleEnum } from '../../common/enums/role.enum';
5
+ import { CoreErrorCodeService } from './core-error-code.service';
6
+ import { IErrorTranslationResponse, SupportedLocale } from './interfaces/error-code.interfaces';
7
+
8
+ /**
9
+ * Core Error Code Controller
10
+ *
11
+ * Provides REST endpoints for error translations.
12
+ * This controller is publicly accessible (no authentication required).
13
+ *
14
+ * @example
15
+ * GET /api/i18n/errors/de - Get German translations
16
+ * GET /api/i18n/errors/en - Get English translations
17
+ */
18
+ @Controller('api/i18n/errors')
19
+ export class CoreErrorCodeController {
20
+ constructor(protected readonly errorCodeService: CoreErrorCodeService) {}
21
+
22
+ /**
23
+ * Get error translations for a specific locale
24
+ *
25
+ * Returns all error codes with their translations in Nuxt i18n compatible format.
26
+ *
27
+ * @param locale - Locale code (e.g., 'de', 'en')
28
+ * @returns Translations object
29
+ * @throws NotFoundException if locale is not supported
30
+ *
31
+ * @example
32
+ * Response:
33
+ * ```json
34
+ * {
35
+ * "errors": {
36
+ * "LTNS_0001": "Benutzer wurde nicht gefunden.",
37
+ * "LTNS_0002": "Das eingegebene Passwort ist ungültig.",
38
+ * "LTNS_0100": "Sie sind nicht angemeldet."
39
+ * }
40
+ * }
41
+ * ```
42
+ */
43
+ @Get(':locale')
44
+ @Roles(RoleEnum.S_EVERYONE)
45
+ getTranslations(@Param('locale') locale: string): IErrorTranslationResponse {
46
+ if (!this.errorCodeService.isLocaleSupported(locale)) {
47
+ throw new NotFoundException(
48
+ `Locale "${locale}" is not supported. ` +
49
+ `Supported locales: ${this.errorCodeService.getSupportedLocales().join(', ')}`,
50
+ );
51
+ }
52
+
53
+ return this.errorCodeService.getTranslations(locale as SupportedLocale);
54
+ }
55
+ }
@@ -0,0 +1,135 @@
1
+ import { Injectable } from '@nestjs/common';
2
+
3
+ import { getAllErrorDefinitions, IErrorRegistry } from './error-codes';
4
+ import { SupportedLocale } from './interfaces/error-code.interfaces';
5
+
6
+ /**
7
+ * Core Error Code Service
8
+ *
9
+ * Serves error code translations from the structured ErrorRegistry.
10
+ * Translations are defined in error-codes.ts as Single Source of Truth.
11
+ *
12
+ * Projects can extend this service to add custom error registries.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * // In consuming project:
17
+ * import { CoreErrorCodeService, IErrorRegistry } from '@lenne.tech/nest-server';
18
+ *
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
+ * @Injectable()
28
+ * export class ErrorCodeService extends CoreErrorCodeService {
29
+ * constructor() {
30
+ * super();
31
+ * this.registerErrorRegistry(ProjectErrors);
32
+ * }
33
+ * }
34
+ * ```
35
+ */
36
+ @Injectable()
37
+ export class CoreErrorCodeService {
38
+ /**
39
+ * Supported locales
40
+ */
41
+ protected supportedLocales: SupportedLocale[] = ['de', 'en'];
42
+
43
+ /**
44
+ * Cached translations per locale
45
+ */
46
+ protected translations: Map<SupportedLocale, Record<string, string>> = new Map();
47
+
48
+ /**
49
+ * Registered error registries
50
+ */
51
+ protected registries: IErrorRegistry[] = [];
52
+
53
+ constructor() {
54
+ // Initialize with core errors
55
+ this.registerErrorRegistry(getAllErrorDefinitions());
56
+ }
57
+
58
+ /**
59
+ * Register an error registry and generate translations
60
+ *
61
+ * @param registry - Error registry to register
62
+ */
63
+ registerErrorRegistry(registry: IErrorRegistry): void {
64
+ this.registries.push(registry);
65
+ this.generateTranslationsFromRegistry(registry);
66
+ }
67
+
68
+ /**
69
+ * Generate translations from error registry
70
+ *
71
+ * @param registry - Error registry to extract translations from
72
+ */
73
+ protected generateTranslationsFromRegistry(registry: IErrorRegistry): void {
74
+ for (const [, definition] of Object.entries(registry)) {
75
+ const { code, translations: defTranslations } = definition;
76
+
77
+ for (const locale of this.supportedLocales) {
78
+ const translation = defTranslations[locale];
79
+ if (translation) {
80
+ const existing = this.translations.get(locale) || {};
81
+ this.translations.set(locale, { ...existing, [code]: translation });
82
+ }
83
+ }
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Check if a locale is supported
89
+ *
90
+ * @param locale - Locale to check
91
+ * @returns True if locale is supported
92
+ */
93
+ isLocaleSupported(locale: string): locale is SupportedLocale {
94
+ return this.supportedLocales.includes(locale as SupportedLocale);
95
+ }
96
+
97
+ /**
98
+ * Get supported locales
99
+ *
100
+ * @returns Array of supported locales
101
+ */
102
+ getSupportedLocales(): SupportedLocale[] {
103
+ return [...this.supportedLocales];
104
+ }
105
+
106
+ /**
107
+ * Get all translations for a locale
108
+ *
109
+ * @param locale - Locale code (e.g., 'de', 'en')
110
+ * @returns Translations object wrapped in { errors: ... } for Nuxt i18n compatibility
111
+ * @throws Error if locale is not supported
112
+ */
113
+ getTranslations(locale: SupportedLocale): { errors: Record<string, string> } {
114
+ if (!this.isLocaleSupported(locale)) {
115
+ throw new Error(`Locale "${locale}" is not supported. Supported: ${this.supportedLocales.join(', ')}`);
116
+ }
117
+
118
+ return { errors: this.translations.get(locale) || {} };
119
+ }
120
+
121
+ /**
122
+ * Get all error codes
123
+ *
124
+ * @returns Array of error codes from all registries
125
+ */
126
+ getErrorCodes(): string[] {
127
+ const codes = new Set<string>();
128
+ for (const translations of this.translations.values()) {
129
+ for (const code of Object.keys(translations)) {
130
+ codes.add(code);
131
+ }
132
+ }
133
+ return Array.from(codes).sort();
134
+ }
135
+ }
@@ -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
+ }