@navios/core 0.4.0 → 0.5.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 (92) hide show
  1. package/README.md +95 -2
  2. package/docs/README.md +310 -3
  3. package/docs/adapters.md +308 -0
  4. package/docs/application-setup.md +524 -0
  5. package/docs/attributes.md +689 -0
  6. package/docs/controllers.md +373 -0
  7. package/docs/endpoints.md +444 -0
  8. package/docs/exceptions.md +316 -0
  9. package/docs/guards.md +550 -0
  10. package/docs/modules.md +251 -0
  11. package/docs/quick-start.md +295 -0
  12. package/docs/services.md +428 -0
  13. package/docs/testing.md +704 -0
  14. package/lib/_tsup-dts-rollup.d.mts +300 -235
  15. package/lib/_tsup-dts-rollup.d.ts +300 -235
  16. package/lib/index.d.mts +47 -26
  17. package/lib/index.d.ts +47 -26
  18. package/lib/index.js +633 -1072
  19. package/lib/index.js.map +1 -1
  20. package/lib/index.mjs +631 -1064
  21. package/lib/index.mjs.map +1 -1
  22. package/package.json +4 -7
  23. package/project.json +9 -1
  24. package/src/__tests__/config.service.spec.mts +11 -9
  25. package/src/__tests__/controller.spec.mts +0 -1
  26. package/src/config/config.service.mts +2 -2
  27. package/src/decorators/controller.decorator.mts +1 -1
  28. package/src/decorators/endpoint.decorator.mts +2 -2
  29. package/src/decorators/header.decorator.mts +1 -1
  30. package/src/decorators/multipart.decorator.mts +1 -1
  31. package/src/decorators/stream.decorator.mts +2 -3
  32. package/src/factories/endpoint-adapter.factory.mts +21 -0
  33. package/src/factories/http-adapter.factory.mts +20 -0
  34. package/src/factories/index.mts +6 -0
  35. package/src/factories/multipart-adapter.factory.mts +21 -0
  36. package/src/factories/reply.factory.mts +21 -0
  37. package/src/factories/request.factory.mts +21 -0
  38. package/src/factories/stream-adapter.factory.mts +20 -0
  39. package/src/index.mts +1 -1
  40. package/src/interfaces/abstract-execution-context.inteface.mts +13 -0
  41. package/src/interfaces/abstract-http-adapter.interface.mts +20 -0
  42. package/src/interfaces/abstract-http-cors-options.interface.mts +59 -0
  43. package/src/interfaces/abstract-http-handler-adapter.interface.mts +13 -0
  44. package/src/interfaces/abstract-http-listen-options.interface.mts +4 -0
  45. package/src/interfaces/can-activate.mts +4 -2
  46. package/src/interfaces/http-header.mts +18 -0
  47. package/src/interfaces/index.mts +6 -0
  48. package/src/logger/console-logger.service.mts +28 -44
  49. package/src/logger/index.mts +1 -2
  50. package/src/logger/logger.service.mts +9 -128
  51. package/src/logger/logger.tokens.mts +21 -0
  52. package/src/metadata/handler.metadata.mts +7 -5
  53. package/src/navios.application.mts +65 -172
  54. package/src/navios.environment.mts +30 -0
  55. package/src/navios.factory.mts +53 -12
  56. package/src/services/guard-runner.service.mts +19 -9
  57. package/src/services/index.mts +0 -2
  58. package/src/services/module-loader.service.mts +4 -3
  59. package/src/tokens/endpoint-adapter.token.mts +8 -0
  60. package/src/tokens/execution-context.token.mts +2 -2
  61. package/src/tokens/http-adapter.token.mts +8 -0
  62. package/src/tokens/index.mts +4 -1
  63. package/src/tokens/multipart-adapter.token.mts +8 -0
  64. package/src/tokens/reply.token.mts +1 -5
  65. package/src/tokens/request.token.mts +1 -7
  66. package/src/tokens/stream-adapter.token.mts +8 -0
  67. package/docs/recipes/prisma.md +0 -60
  68. package/e2e/endpoints/get.spec.mts +0 -97
  69. package/e2e/endpoints/post.spec.mts +0 -113
  70. package/examples/simple-test/api/index.mts +0 -64
  71. package/examples/simple-test/config/config.service.mts +0 -14
  72. package/examples/simple-test/config/configuration.mts +0 -7
  73. package/examples/simple-test/index.mts +0 -16
  74. package/examples/simple-test/src/acl/acl-modern.guard.mts +0 -15
  75. package/examples/simple-test/src/acl/acl.guard.mts +0 -14
  76. package/examples/simple-test/src/acl/app.guard.mts +0 -27
  77. package/examples/simple-test/src/acl/one-more.guard.mts +0 -15
  78. package/examples/simple-test/src/acl/public.attribute.mts +0 -21
  79. package/examples/simple-test/src/app.module.mts +0 -9
  80. package/examples/simple-test/src/user/user.controller.mts +0 -72
  81. package/examples/simple-test/src/user/user.module.mts +0 -14
  82. package/examples/simple-test/src/user/user.service.mts +0 -14
  83. package/src/adapters/endpoint-adapter.service.mts +0 -72
  84. package/src/adapters/handler-adapter.interface.mts +0 -21
  85. package/src/adapters/index.mts +0 -4
  86. package/src/adapters/multipart-adapter.service.mts +0 -135
  87. package/src/adapters/stream-adapter.service.mts +0 -91
  88. package/src/logger/logger.factory.mts +0 -36
  89. package/src/logger/pino-wrapper.mts +0 -64
  90. package/src/services/controller-adapter.service.mts +0 -124
  91. package/src/services/execution-context.mts +0 -54
  92. package/src/tokens/application.token.mts +0 -9
@@ -0,0 +1,316 @@
1
+ # Exception Handling
2
+
3
+ Navios provides a comprehensive exception handling system that allows you to throw HTTP exceptions and handle errors in a consistent manner across your application.
4
+
5
+ ## Built-in HTTP Exceptions
6
+
7
+ Navios includes several built-in HTTP exception classes that correspond to common HTTP status codes:
8
+
9
+ ### BadRequestException (400)
10
+
11
+ ### UnauthorizedException (401)
12
+
13
+ ### ForbiddenException (403)
14
+
15
+ ### NotFoundException (404)
16
+
17
+ ### ConflictException (409)
18
+
19
+ ### InternalServerErrorException (500)
20
+
21
+ ## Base HttpException
22
+
23
+ All HTTP exceptions extend the base `HttpException` class:
24
+
25
+ ```typescript
26
+ import { HttpException } from '@navios/core'
27
+
28
+ // Create custom exception
29
+ export class CustomException extends HttpException {
30
+ constructor(message: string) {
31
+ super(message, 418) // I'm a teapot
32
+ }
33
+ }
34
+
35
+ // Or throw HttpException directly
36
+ @Controller()
37
+ export class UserController {
38
+ @Endpoint(getUserByIdEndpoint)
39
+ async getUserById({ params }: { params: { id: string } }) {
40
+ if (!this.isValidId(params.id)) {
41
+ throw new HttpException('Invalid user ID format', 422)
42
+ }
43
+
44
+ return this.userService.findById(params.id)
45
+ }
46
+ }
47
+ ```
48
+
49
+ ## Exception with Additional Data
50
+
51
+ You can include additional data in exceptions:
52
+
53
+ ```typescript
54
+ import { BadRequestException } from '@navios/core'
55
+
56
+ @Controller()
57
+ export class UserController {
58
+ @Endpoint(createUserEndpoint)
59
+ async createUser({ body }: { body: CreateUserDto }) {
60
+ const validationErrors = await this.validateUser(body)
61
+
62
+ if (validationErrors.length > 0) {
63
+ throw new BadRequestException({
64
+ message: 'Validation failed',
65
+ errors: validationErrors,
66
+ timestamp: new Date().toISOString(),
67
+ })
68
+ }
69
+
70
+ return this.userService.create(body)
71
+ }
72
+
73
+ private async validateUser(user: CreateUserDto) {
74
+ const errors: string[] = []
75
+
76
+ if (!user.email) {
77
+ errors.push('Email is required')
78
+ } else if (!this.isValidEmail(user.email)) {
79
+ errors.push('Invalid email format')
80
+ }
81
+
82
+ if (!user.password || user.password.length < 8) {
83
+ errors.push('Password must be at least 8 characters')
84
+ }
85
+
86
+ return errors
87
+ }
88
+ }
89
+ ```
90
+
91
+ ## Custom Exceptions
92
+
93
+ Create domain-specific exceptions by extending HTTP exceptions:
94
+
95
+ ```typescript
96
+ import {
97
+ BadRequestException,
98
+ ConflictException,
99
+ NotFoundException,
100
+ } from '@navios/core'
101
+
102
+ // Domain-specific exceptions
103
+ export class UserNotFoundException extends NotFoundException {
104
+ constructor(userId: string) {
105
+ super(`User with ID ${userId} not found`)
106
+ }
107
+ }
108
+
109
+ export class InvalidEmailException extends BadRequestException {
110
+ constructor(email: string) {
111
+ super({
112
+ message: 'Invalid email address',
113
+ email,
114
+ code: 'INVALID_EMAIL',
115
+ })
116
+ }
117
+ }
118
+
119
+ export class EmailAlreadyExistsException extends ConflictException {
120
+ constructor(email: string) {
121
+ super({
122
+ message: 'Email address already exists',
123
+ email,
124
+ code: 'EMAIL_EXISTS',
125
+ })
126
+ }
127
+ }
128
+ ```
129
+
130
+ ## Async Exception Handling
131
+
132
+ Handle exceptions in async operations:
133
+
134
+ ```typescript
135
+ @Controller()
136
+ export class UserController {
137
+ private logger = inject(Logger, { context: 'UserController' })
138
+
139
+ @Endpoint(sendEmailEndpoint)
140
+ async sendEmail({ params }: { params: { id: string } }) {
141
+ try {
142
+ const user = await this.userService.findById(params.id)
143
+
144
+ if (!user) {
145
+ throw new NotFoundException(`User with ID ${params.id} not found`)
146
+ }
147
+
148
+ await this.emailService.sendWelcomeEmail(user.email)
149
+
150
+ return { message: 'Email sent successfully' }
151
+ } catch (error) {
152
+ if (error instanceof HttpException) {
153
+ throw error // Re-throw HTTP exceptions
154
+ }
155
+
156
+ // Log unexpected errors
157
+ this.logger.error('Failed to send email', {
158
+ userId: params.id,
159
+ error: error.message,
160
+ stack: error.stack,
161
+ })
162
+
163
+ throw new InternalServerErrorException('Failed to send email')
164
+ }
165
+ }
166
+ }
167
+ ```
168
+
169
+ ## Exception Response Format
170
+
171
+ By default, Navios returns exceptions in this format:
172
+
173
+ ```json
174
+ {
175
+ "statusCode": 404,
176
+ "message": "User with ID 123 not found",
177
+ "timestamp": "2023-10-01T12:00:00.000Z",
178
+ "path": "/users/123"
179
+ }
180
+ ```
181
+
182
+ For exceptions with additional data:
183
+
184
+ ```json
185
+ {
186
+ "statusCode": 400,
187
+ "message": "Validation failed",
188
+ "errors": [
189
+ {
190
+ "field": "email",
191
+ "message": "Invalid email format",
192
+ "code": "INVALID_EMAIL"
193
+ }
194
+ ],
195
+ "timestamp": "2023-10-01T12:00:00.000Z",
196
+ "path": "/users"
197
+ }
198
+ ```
199
+
200
+ ## Best Practices
201
+
202
+ ### 1. Use Specific Exceptions
203
+
204
+ Use the most specific exception type for better error handling:
205
+
206
+ ```typescript
207
+ // ✅ Good - Specific exception
208
+ if (!user) {
209
+ throw new NotFoundException(`User with ID ${id} not found`)
210
+ }
211
+
212
+ // ❌ Avoid - Generic exception
213
+ if (!user) {
214
+ throw new HttpException('User not found', 404)
215
+ }
216
+ ```
217
+
218
+ ### 2. Include Context
219
+
220
+ Provide helpful context in exception messages:
221
+
222
+ ```typescript
223
+ // ✅ Good - Includes context
224
+ throw new BadRequestException({
225
+ message: 'Invalid user data',
226
+ field: 'email',
227
+ value: email,
228
+ reason: 'Email format is invalid',
229
+ })
230
+
231
+ // ❌ Avoid - Vague message
232
+ throw new BadRequestException('Invalid data')
233
+ ```
234
+
235
+ ### 3. Log Appropriately
236
+
237
+ Log exceptions at appropriate levels:
238
+
239
+ ```typescript
240
+ @Controller()
241
+ export class UserController {
242
+ private logger = inject(Logger, { context: 'UserController' })
243
+
244
+ async getUser(id: string) {
245
+ try {
246
+ return await this.userService.findById(id)
247
+ } catch (error) {
248
+ if (error instanceof NotFoundException) {
249
+ // Don't log client errors as errors
250
+ this.logger.debug(`User not found: ${id}`)
251
+ throw error
252
+ }
253
+
254
+ // Log server errors
255
+ this.logger.error('Failed to get user', {
256
+ userId: id,
257
+ error: error.message,
258
+ stack: error.stack,
259
+ })
260
+
261
+ throw new InternalServerErrorException('Failed to retrieve user')
262
+ }
263
+ }
264
+ }
265
+ ```
266
+
267
+ ### 4. Don't Expose Internal Details
268
+
269
+ Don't expose sensitive information in exception messages:
270
+
271
+ ```typescript
272
+ // ✅ Good - Safe message
273
+ throw new InternalServerErrorException('Database connection failed')
274
+
275
+ // ❌ Avoid - Exposes sensitive info
276
+ throw new InternalServerErrorException(
277
+ `Database connection failed: ${databaseUrl} with credentials ${username}:${password}`,
278
+ )
279
+ ```
280
+
281
+ ### 5. Create Domain-Specific Exceptions
282
+
283
+ Create exceptions that match your domain:
284
+
285
+ ```typescript
286
+ // User domain exceptions
287
+ export class UserNotFoundException extends NotFoundException {
288
+ constructor(userId: string) {
289
+ super(`User with ID ${userId} not found`)
290
+ }
291
+ }
292
+
293
+ export class UserEmailAlreadyExistsException extends ConflictException {
294
+ constructor(email: string) {
295
+ super(`User with email ${email} already exists`)
296
+ }
297
+ }
298
+
299
+ // Order domain exceptions
300
+ export class OrderNotFoundException extends NotFoundException {
301
+ constructor(orderId: string) {
302
+ super(`Order with ID ${orderId} not found`)
303
+ }
304
+ }
305
+
306
+ export class InsufficientInventoryException extends ConflictException {
307
+ constructor(productId: string, requested: number, available: number) {
308
+ super({
309
+ message: 'Insufficient inventory',
310
+ productId,
311
+ requested,
312
+ available,
313
+ })
314
+ }
315
+ }
316
+ ```