@navios/core 0.9.3 → 1.0.0-alpha.2

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 (67) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +4 -2
  3. package/docs/README.md +3 -1
  4. package/docs/exceptions.md +37 -1
  5. package/lib/{index-B2ulzZIr.d.cts → index-BJjk2X1S.d.mts} +478 -33
  6. package/lib/index-BJjk2X1S.d.mts.map +1 -0
  7. package/lib/{index-C8lUQePd.d.mts → index-DZ6NU03y.d.cts} +478 -33
  8. package/lib/index-DZ6NU03y.d.cts.map +1 -0
  9. package/lib/index.cjs +37 -2
  10. package/lib/index.d.cts +2 -2
  11. package/lib/index.d.mts +2 -2
  12. package/lib/index.mjs +3 -3
  13. package/lib/legacy-compat/index.cjs +8 -6
  14. package/lib/legacy-compat/index.cjs.map +1 -1
  15. package/lib/legacy-compat/index.d.cts +11 -16
  16. package/lib/legacy-compat/index.d.cts.map +1 -1
  17. package/lib/legacy-compat/index.d.mts +11 -16
  18. package/lib/legacy-compat/index.d.mts.map +1 -1
  19. package/lib/legacy-compat/index.mjs +7 -5
  20. package/lib/legacy-compat/index.mjs.map +1 -1
  21. package/lib/{src-Cu9OAnfp.cjs → src-C46ePe3d.cjs} +1970 -171
  22. package/lib/src-C46ePe3d.cjs.map +1 -0
  23. package/lib/{src-Baabu2R8.mjs → src-K2k0riYJ.mjs} +1941 -202
  24. package/lib/src-K2k0riYJ.mjs.map +1 -0
  25. package/lib/testing/index.cjs +2 -2
  26. package/lib/testing/index.d.cts +1 -1
  27. package/lib/testing/index.d.mts +1 -1
  28. package/lib/testing/index.mjs +2 -2
  29. package/lib/{use-guards.decorator-EvI2m2DK.cjs → use-guards.decorator-B6tghdxM.cjs} +7 -4
  30. package/lib/use-guards.decorator-B6tghdxM.cjs.map +1 -0
  31. package/lib/{use-guards.decorator-ChJVzYLW.mjs → use-guards.decorator-Be_QUx6b.mjs} +6 -3
  32. package/lib/use-guards.decorator-Be_QUx6b.mjs.map +1 -0
  33. package/package.json +3 -3
  34. package/src/__tests__/responders.spec.mts +339 -0
  35. package/src/decorators/endpoint.decorator.mts +49 -97
  36. package/src/decorators/module.decorator.mts +12 -0
  37. package/src/decorators/multipart.decorator.mts +62 -87
  38. package/src/decorators/stream.decorator.mts +66 -76
  39. package/src/index.mts +1 -0
  40. package/src/legacy-compat/__type-tests__/legacy-decorators.spec-d.mts +0 -2
  41. package/src/legacy-compat/decorators/endpoint.decorator.mts +21 -47
  42. package/src/legacy-compat/decorators/multipart.decorator.mts +20 -41
  43. package/src/legacy-compat/decorators/stream.decorator.mts +48 -42
  44. package/src/metadata/module.metadata.mts +2 -0
  45. package/src/responders/enums/framework-error.enum.mts +38 -0
  46. package/src/responders/enums/index.mts +1 -0
  47. package/src/responders/index.mts +4 -0
  48. package/src/responders/interfaces/error-responder.interface.mts +42 -0
  49. package/src/responders/interfaces/error-response.interface.mts +22 -0
  50. package/src/responders/interfaces/index.mts +3 -0
  51. package/src/responders/interfaces/problem-details.interface.mts +34 -0
  52. package/src/responders/services/error-response-producer.service.mts +143 -0
  53. package/src/responders/services/forbidden-responder.service.mts +77 -0
  54. package/src/responders/services/index.mts +5 -0
  55. package/src/responders/services/internal-server-error-responder.service.mts +57 -0
  56. package/src/responders/services/not-found-responder.service.mts +76 -0
  57. package/src/responders/services/validation-error-responder.service.mts +78 -0
  58. package/src/responders/tokens/index.mts +1 -0
  59. package/src/responders/tokens/responder.tokens.mts +84 -0
  60. package/src/services/guard-runner.service.mts +19 -6
  61. package/src/services/module-loader.service.mts +63 -0
  62. package/lib/index-B2ulzZIr.d.cts.map +0 -1
  63. package/lib/index-C8lUQePd.d.mts.map +0 -1
  64. package/lib/src-Baabu2R8.mjs.map +0 -1
  65. package/lib/src-Cu9OAnfp.cjs.map +0 -1
  66. package/lib/use-guards.decorator-ChJVzYLW.mjs.map +0 -1
  67. package/lib/use-guards.decorator-EvI2m2DK.cjs.map +0 -1
@@ -1,9 +1,9 @@
1
1
  import type {
2
- BaseEndpointConfig,
3
- EndpointFunctionArgs,
4
- HttpMethod,
2
+ EndpointHandler,
3
+ EndpointOptions,
4
+ RequestArgs,
5
5
  } from '@navios/builder'
6
- import type { z, ZodType } from 'zod/v4'
6
+ import type { z } from 'zod/v4'
7
7
 
8
8
  import { Endpoint as OriginalEndpoint } from '../../decorators/endpoint.decorator.mjs'
9
9
  import { createMethodContext } from '../context-compat.mjs'
@@ -13,22 +13,18 @@ import { createMethodContext } from '../context-compat.mjs'
13
13
  * Note: In legacy decorators, type constraints are checked when the decorator is applied,
14
14
  * but may not be preserved perfectly when decorators are stacked.
15
15
  */
16
- type EndpointMethodDescriptor<
17
- Url extends string,
18
- QuerySchema,
19
- RequestSchema,
20
- ResponseSchema extends ZodType,
21
- > = TypedPropertyDescriptor<
22
- (
23
- params: QuerySchema extends ZodType
24
- ? RequestSchema extends ZodType
25
- ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema, true>
26
- : EndpointFunctionArgs<Url, QuerySchema, undefined, true>
27
- : RequestSchema extends ZodType
28
- ? EndpointFunctionArgs<Url, undefined, RequestSchema, true>
29
- : EndpointFunctionArgs<Url, undefined, undefined, true>,
30
- ) => Promise<z.input<ResponseSchema>>
31
- >
16
+ type EndpointMethodDescriptor<Config extends EndpointOptions> =
17
+ TypedPropertyDescriptor<
18
+ (
19
+ params: RequestArgs<
20
+ Config['url'],
21
+ Config['querySchema'],
22
+ Config['requestSchema'],
23
+ Config['urlParamsSchema'],
24
+ true
25
+ >,
26
+ ) => Promise<z.input<Config['responseSchema']>>
27
+ >
32
28
 
33
29
  /**
34
30
  * Legacy-compatible Endpoint decorator.
@@ -50,30 +46,13 @@ type EndpointMethodDescriptor<
50
46
  * }
51
47
  * ```
52
48
  */
53
- export function Endpoint<
54
- Method extends HttpMethod = HttpMethod,
55
- Url extends string = string,
56
- QuerySchema = undefined,
57
- ResponseSchema extends ZodType = ZodType,
58
- RequestSchema = ZodType,
59
- >(endpoint: {
60
- config: BaseEndpointConfig<
61
- Method,
62
- Url,
63
- QuerySchema,
64
- ResponseSchema,
65
- RequestSchema
66
- >
67
- }) {
49
+ export function Endpoint<const Config extends EndpointOptions>(
50
+ endpoint: EndpointHandler<Config, false>,
51
+ ) {
68
52
  return function (
69
53
  target: any,
70
54
  propertyKey: string | symbol,
71
- descriptor: EndpointMethodDescriptor<
72
- Url,
73
- QuerySchema,
74
- RequestSchema,
75
- ResponseSchema
76
- >,
55
+ descriptor: EndpointMethodDescriptor<Config>,
77
56
  ): PropertyDescriptor | void {
78
57
  if (!descriptor) {
79
58
  throw new Error(
@@ -81,12 +60,7 @@ export function Endpoint<
81
60
  )
82
61
  }
83
62
  // Type check the descriptor value matches expected signature
84
- const typedDescriptor = descriptor as EndpointMethodDescriptor<
85
- Url,
86
- QuerySchema,
87
- RequestSchema,
88
- ResponseSchema
89
- >
63
+ const typedDescriptor = descriptor as EndpointMethodDescriptor<Config>
90
64
  const context = createMethodContext(target, propertyKey, typedDescriptor)
91
65
  const originalDecorator = OriginalEndpoint(endpoint)
92
66
  // @ts-expect-error - we don't need to type the value
@@ -1,9 +1,9 @@
1
1
  import type {
2
- BaseEndpointConfig,
3
- EndpointFunctionArgs,
4
- HttpMethod,
2
+ EndpointHandler,
3
+ EndpointOptions,
4
+ RequestArgs,
5
5
  } from '@navios/builder'
6
- import type { z, ZodObject, ZodType } from 'zod/v4'
6
+ import type { z } from 'zod/v4'
7
7
 
8
8
  import { Multipart as OriginalMultipart } from '../../decorators/multipart.decorator.mjs'
9
9
  import { createMethodContext } from '../context-compat.mjs'
@@ -13,22 +13,18 @@ import { createMethodContext } from '../context-compat.mjs'
13
13
  * Note: In legacy decorators, type constraints are checked when the decorator is applied,
14
14
  * but may not be preserved perfectly when decorators are stacked.
15
15
  */
16
- type MultipartMethodDescriptor<
17
- Url extends string,
18
- QuerySchema,
19
- RequestSchema,
20
- ResponseSchema extends ZodType,
21
- > = TypedPropertyDescriptor<
22
- (
23
- params: QuerySchema extends ZodObject
24
- ? RequestSchema extends ZodType
25
- ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema, true>
26
- : EndpointFunctionArgs<Url, QuerySchema, undefined, true>
27
- : RequestSchema extends ZodType
28
- ? EndpointFunctionArgs<Url, undefined, RequestSchema, true>
29
- : EndpointFunctionArgs<Url, undefined, undefined, true>,
30
- ) => Promise<z.input<ResponseSchema>>
31
- >
16
+ type MultipartMethodDescriptor<Config extends EndpointOptions> =
17
+ TypedPropertyDescriptor<
18
+ (
19
+ params: RequestArgs<
20
+ Config['url'],
21
+ Config['querySchema'],
22
+ Config['requestSchema'],
23
+ Config['urlParamsSchema'],
24
+ true
25
+ >,
26
+ ) => Promise<z.input<Config['responseSchema']>>
27
+ >
32
28
 
33
29
  /**
34
30
  * Legacy-compatible Multipart decorator.
@@ -51,30 +47,13 @@ type MultipartMethodDescriptor<
51
47
  * }
52
48
  * ```
53
49
  */
54
- export function Multipart<
55
- Method extends HttpMethod = HttpMethod,
56
- Url extends string = string,
57
- QuerySchema = undefined,
58
- ResponseSchema extends ZodType = ZodType,
59
- RequestSchema = ZodType,
60
- >(endpoint: {
61
- config: BaseEndpointConfig<
62
- Method,
63
- Url,
64
- QuerySchema,
65
- ResponseSchema,
66
- RequestSchema
67
- >
68
- }) {
50
+ export function Multipart<const Config extends EndpointOptions>(
51
+ endpoint: EndpointHandler<Config, false>,
52
+ ) {
69
53
  return function <T extends object>(
70
54
  target: T,
71
55
  propertyKey: string | symbol,
72
- descriptor: MultipartMethodDescriptor<
73
- Url,
74
- QuerySchema,
75
- RequestSchema,
76
- ResponseSchema
77
- >,
56
+ descriptor: MultipartMethodDescriptor<Config>,
78
57
  ): PropertyDescriptor | void {
79
58
  if (!descriptor) {
80
59
  throw new Error(
@@ -1,41 +1,42 @@
1
1
  import type {
2
- BaseStreamConfig,
3
- EndpointFunctionArgs,
4
- HttpMethod,
2
+ BaseEndpointOptions,
3
+ RequestArgs,
4
+ StreamHandler,
5
5
  } from '@navios/builder'
6
- import type { ZodObject, ZodType } from 'zod/v4'
7
6
 
8
7
  import { Stream as OriginalStream } from '../../decorators/stream.decorator.mjs'
9
8
  import { createMethodContext } from '../context-compat.mjs'
10
9
 
11
- type StreamParams<
12
- Url extends string,
13
- QuerySchema,
14
- RequestSchema,
15
- > = QuerySchema extends ZodObject
16
- ? RequestSchema extends ZodType
17
- ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema, true>
18
- : EndpointFunctionArgs<Url, QuerySchema, undefined, true>
19
- : RequestSchema extends ZodType
20
- ? EndpointFunctionArgs<Url, undefined, RequestSchema, true>
21
- : EndpointFunctionArgs<Url, undefined, undefined, true>
22
-
23
10
  /**
24
11
  * Type helper to constrain a PropertyDescriptor's value to match a stream endpoint signature.
25
12
  * Supports both with and without reply parameter (Bun doesn't use reply parameter).
13
+ * Note: In legacy decorators, type constraints are checked when the decorator is applied,
14
+ * but may not be preserved perfectly when decorators are stacked.
26
15
  */
27
- type StreamMethodDescriptor<
28
- Url extends string,
29
- QuerySchema,
30
- RequestSchema,
31
- > =
16
+ type StreamMethodDescriptor<Config extends BaseEndpointOptions> =
32
17
  | TypedPropertyDescriptor<
33
- (params: StreamParams<Url, QuerySchema, RequestSchema>, reply: any) => any
18
+ (
19
+ params: RequestArgs<
20
+ Config['url'],
21
+ Config['querySchema'],
22
+ Config['requestSchema'],
23
+ Config['urlParamsSchema'],
24
+ true
25
+ >,
26
+ reply: any,
27
+ ) => any
34
28
  >
35
29
  | TypedPropertyDescriptor<
36
- (params: StreamParams<Url, QuerySchema, RequestSchema>) => any
30
+ (
31
+ params: RequestArgs<
32
+ Config['url'],
33
+ Config['querySchema'],
34
+ Config['requestSchema'],
35
+ Config['urlParamsSchema'],
36
+ true
37
+ >,
38
+ ) => any
37
39
  >
38
- | TypedPropertyDescriptor<() => any>
39
40
 
40
41
  /**
41
42
  * Legacy-compatible Stream decorator.
@@ -58,26 +59,31 @@ type StreamMethodDescriptor<
58
59
  * }
59
60
  * ```
60
61
  */
61
- export function Stream<
62
- Method extends HttpMethod = HttpMethod,
63
- Url extends string = string,
64
- QuerySchema = undefined,
65
- RequestSchema = ZodType,
66
- >(endpoint: {
67
- config: BaseStreamConfig<Method, Url, QuerySchema, RequestSchema>
68
- }) {
69
- return function <T extends object>(
70
- target: T,
62
+ export function Stream<const Config extends BaseEndpointOptions>(
63
+ endpoint: StreamHandler<Config, false>,
64
+ ) {
65
+ return function (
66
+ target: any,
71
67
  propertyKey: string | symbol,
72
- descriptor: StreamMethodDescriptor<Url, QuerySchema, RequestSchema>,
73
- ) {
74
- const context = createMethodContext(target, propertyKey, descriptor)
68
+ descriptor: StreamMethodDescriptor<Config>,
69
+ ): PropertyDescriptor | void {
70
+ if (!descriptor || !descriptor.value) {
71
+ throw new Error(
72
+ '[Navios] @Stream decorator requires a method descriptor. Make sure experimentalDecorators is enabled.',
73
+ )
74
+ }
75
+ // Type check the descriptor value matches expected signature
76
+ const typedDescriptor = descriptor as StreamMethodDescriptor<Config>
77
+ const context = createMethodContext(target, propertyKey, typedDescriptor)
75
78
  const originalDecorator = OriginalStream(endpoint)
76
- // @ts-expect-error - we don't need to type the value
77
- const result = originalDecorator(descriptor.value, context)
78
- if (result !== descriptor.value) {
79
- descriptor.value = result as any
79
+ // Stage3 decorator returns void in type signature but actually returns the function
80
+ // We know value is defined because we checked above
81
+ const result = originalDecorator(typedDescriptor.value!, context) as
82
+ | typeof typedDescriptor.value
83
+ | void
84
+ if (result && result !== typedDescriptor.value) {
85
+ typedDescriptor.value = result as any
80
86
  }
81
- return descriptor
87
+ return typedDescriptor
82
88
  }
83
89
  }
@@ -14,6 +14,7 @@ export interface ModuleMetadata {
14
14
  guards: Set<
15
15
  ClassTypeWithInstance<CanActivate> | InjectionToken<CanActivate, undefined>
16
16
  >
17
+ overrides: Set<ClassType>
17
18
  customAttributes: Map<string | symbol, any>
18
19
  }
19
20
 
@@ -35,6 +36,7 @@ export function getModuleMetadata(
35
36
  | ClassTypeWithInstance<CanActivate>
36
37
  | InjectionToken<CanActivate, undefined>
37
38
  >(),
39
+ overrides: new Set<ClassType>(),
38
40
  customAttributes: new Map<string | symbol, any>(),
39
41
  }
40
42
  context.metadata[ModuleMetadataKey] = newMetadata
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Enumeration of framework-level error types.
3
+ * Used to explicitly specify which error responder should handle an error.
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * // In adapter error handling
8
+ * if (error instanceof ZodError) {
9
+ * return errorProducer.respond(FrameworkError.ValidationError, error)
10
+ * }
11
+ * return errorProducer.handleUnknown(error)
12
+ * ```
13
+ */
14
+ export enum FrameworkError {
15
+ /**
16
+ * Resource not found (HTTP 404).
17
+ * Use when a requested resource does not exist.
18
+ */
19
+ NotFound = 'NotFound',
20
+
21
+ /**
22
+ * Forbidden (HTTP 403).
23
+ * Use when access to a resource is denied (e.g., guard rejection).
24
+ */
25
+ Forbidden = 'Forbidden',
26
+
27
+ /**
28
+ * Internal server error (HTTP 500).
29
+ * Use for unexpected errors that don't fit other categories.
30
+ */
31
+ InternalServerError = 'InternalServerError',
32
+
33
+ /**
34
+ * Validation error (HTTP 400).
35
+ * Use when request data fails validation (e.g., Zod errors).
36
+ */
37
+ ValidationError = 'ValidationError',
38
+ }
@@ -0,0 +1 @@
1
+ export * from './framework-error.enum.mjs'
@@ -0,0 +1,4 @@
1
+ export * from './enums/index.mjs'
2
+ export * from './interfaces/index.mjs'
3
+ export * from './services/index.mjs'
4
+ export * from './tokens/index.mjs'
@@ -0,0 +1,42 @@
1
+ import type { ErrorResponse } from './error-response.interface.mjs'
2
+
3
+ /**
4
+ * Interface for error responders that convert errors to HTTP responses.
5
+ * Each responder handles a specific type of framework error and produces
6
+ * an RFC 7807 compliant response.
7
+ *
8
+ * Implementations are registered with low priority (-10) so they can be
9
+ * easily overridden by consumers.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * @Injectable({
14
+ * token: InternalServerErrorResponderToken,
15
+ * priority: 0, // Override default implementation
16
+ * })
17
+ * export class CustomInternalErrorResponder implements ErrorResponder {
18
+ * getResponse(error: unknown, description?: string): ErrorResponse {
19
+ * return {
20
+ * statusCode: 500,
21
+ * payload: {
22
+ * type: 'https://api.myapp.com/errors/server-error',
23
+ * title: 'Server Error',
24
+ * status: 500,
25
+ * detail: description ?? 'An unexpected error occurred',
26
+ * },
27
+ * headers: { 'Content-Type': 'application/problem+json' },
28
+ * }
29
+ * }
30
+ * }
31
+ * ```
32
+ */
33
+ export interface ErrorResponder {
34
+ /**
35
+ * Converts an error to an ErrorResponse with RFC 7807 Problem Details.
36
+ *
37
+ * @param error - The original error that was thrown
38
+ * @param description - Optional custom description to include in the response
39
+ * @returns ErrorResponse with status code, payload, and headers
40
+ */
41
+ getResponse(error: unknown, description?: string): ErrorResponse
42
+ }
@@ -0,0 +1,22 @@
1
+ import type { ProblemDetails } from './problem-details.interface.mjs'
2
+
3
+ /**
4
+ * Represents a complete error response that can be sent to the client.
5
+ * Includes the status code, payload (RFC 7807 Problem Details), and headers.
6
+ */
7
+ export interface ErrorResponse {
8
+ /**
9
+ * HTTP status code for the response.
10
+ */
11
+ statusCode: number
12
+
13
+ /**
14
+ * RFC 7807 Problem Details payload.
15
+ */
16
+ payload: ProblemDetails
17
+
18
+ /**
19
+ * HTTP headers to include in the response.
20
+ */
21
+ headers: Record<string, string>
22
+ }
@@ -0,0 +1,3 @@
1
+ export * from './error-responder.interface.mjs'
2
+ export * from './error-response.interface.mjs'
3
+ export * from './problem-details.interface.mjs'
@@ -0,0 +1,34 @@
1
+ /**
2
+ * RFC 7807 Problem Details for HTTP APIs
3
+ * @see https://tools.ietf.org/html/rfc7807
4
+ */
5
+ export interface ProblemDetails {
6
+ /**
7
+ * A URI reference that identifies the problem type.
8
+ * When dereferenced, it should provide human-readable documentation.
9
+ * @default 'about:blank'
10
+ */
11
+ type?: string
12
+
13
+ /**
14
+ * A short, human-readable summary of the problem type.
15
+ * It should not change from occurrence to occurrence.
16
+ */
17
+ title: string
18
+
19
+ /**
20
+ * The HTTP status code for this occurrence of the problem.
21
+ */
22
+ status: number
23
+
24
+ /**
25
+ * A human-readable explanation specific to this occurrence of the problem.
26
+ */
27
+ detail?: string
28
+
29
+ /**
30
+ * Additional extension members.
31
+ * Custom properties can be added to provide more context.
32
+ */
33
+ [key: string]: unknown
34
+ }
@@ -0,0 +1,143 @@
1
+ import { inject, Injectable } from '@navios/di'
2
+
3
+ import { FrameworkError } from '../enums/framework-error.enum.mjs'
4
+ import type { ErrorResponse } from '../interfaces/error-response.interface.mjs'
5
+ import {
6
+ ForbiddenResponderToken,
7
+ InternalServerErrorResponderToken,
8
+ NotFoundResponderToken,
9
+ ValidationErrorResponderToken,
10
+ } from '../tokens/responder.tokens.mjs'
11
+
12
+ /**
13
+ * Service for producing standardized error responses.
14
+ *
15
+ * This service coordinates error responders to produce RFC 7807 compliant
16
+ * Problem Details responses. Adapters use this service to convert errors
17
+ * into standardized HTTP responses.
18
+ *
19
+ * The caller explicitly specifies which type of error response to produce
20
+ * via the FrameworkError enum, giving full control to the adapter.
21
+ *
22
+ * @example Usage in an adapter:
23
+ * ```typescript
24
+ * @Injectable()
25
+ * class MyAdapter {
26
+ * private errorProducer = inject(ErrorResponseProducerService)
27
+ *
28
+ * handleError(error: unknown): Response {
29
+ * if (error instanceof ZodError) {
30
+ * const response = this.errorProducer.respond(
31
+ * FrameworkError.ValidationError,
32
+ * error,
33
+ * )
34
+ * return new Response(JSON.stringify(response.payload), {
35
+ * status: response.statusCode,
36
+ * headers: response.headers,
37
+ * })
38
+ * }
39
+ *
40
+ * // Fallback for unknown errors
41
+ * const response = this.errorProducer.handleUnknown(error)
42
+ * return new Response(JSON.stringify(response.payload), {
43
+ * status: response.statusCode,
44
+ * headers: response.headers,
45
+ * })
46
+ * }
47
+ * }
48
+ * ```
49
+ */
50
+ @Injectable()
51
+ export class ErrorResponseProducerService {
52
+ private readonly forbiddenResponder = inject(ForbiddenResponderToken)
53
+ private readonly internalServerErrorResponder = inject(
54
+ InternalServerErrorResponderToken,
55
+ )
56
+ private readonly notFoundResponder = inject(NotFoundResponderToken)
57
+ private readonly validationErrorResponder = inject(
58
+ ValidationErrorResponderToken,
59
+ )
60
+
61
+ /**
62
+ * Produces an error response for a specific framework error type.
63
+ *
64
+ * @param type - The type of framework error (from FrameworkError enum)
65
+ * @param error - The original error that was thrown
66
+ * @param description - Optional custom description to include in the response
67
+ * @returns ErrorResponse with status code, RFC 7807 payload, and headers
68
+ */
69
+ respond(
70
+ type: FrameworkError,
71
+ error: unknown,
72
+ description?: string,
73
+ ): ErrorResponse {
74
+ switch (type) {
75
+ case FrameworkError.NotFound:
76
+ return this.notFoundResponder.getResponse(error, description)
77
+ case FrameworkError.Forbidden:
78
+ return this.forbiddenResponder.getResponse(error, description)
79
+ case FrameworkError.InternalServerError:
80
+ return this.internalServerErrorResponder.getResponse(error, description)
81
+ case FrameworkError.ValidationError:
82
+ return this.validationErrorResponder.getResponse(error, description)
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Handles unknown errors by producing an Internal Server Error response.
88
+ *
89
+ * Use this as a fallback when the error type is not known or doesn't
90
+ * match any specific framework error type.
91
+ *
92
+ * @param error - The original error that was thrown
93
+ * @param description - Optional custom description to include in the response
94
+ * @returns ErrorResponse with 500 status code
95
+ */
96
+ handleUnknown(error: unknown, description?: string): ErrorResponse {
97
+ return this.internalServerErrorResponder.getResponse(error, description)
98
+ }
99
+
100
+ /**
101
+ * Convenience method to produce a Not Found error response.
102
+ *
103
+ * @param error - The original error that was thrown
104
+ * @param description - Optional custom description
105
+ * @returns ErrorResponse with 404 status code
106
+ */
107
+ notFound(error: unknown, description?: string): ErrorResponse {
108
+ return this.notFoundResponder.getResponse(error, description)
109
+ }
110
+
111
+ /**
112
+ * Convenience method to produce a Validation Error response.
113
+ *
114
+ * @param error - The original error (typically a ZodError)
115
+ * @param description - Optional custom description
116
+ * @returns ErrorResponse with 400 status code
117
+ */
118
+ validationError(error: unknown, description?: string): ErrorResponse {
119
+ return this.validationErrorResponder.getResponse(error, description)
120
+ }
121
+
122
+ /**
123
+ * Convenience method to produce an Internal Server Error response.
124
+ *
125
+ * @param error - The original error
126
+ * @param description - Optional custom description
127
+ * @returns ErrorResponse with 500 status code
128
+ */
129
+ internalServerError(error: unknown, description?: string): ErrorResponse {
130
+ return this.internalServerErrorResponder.getResponse(error, description)
131
+ }
132
+
133
+ /**
134
+ * Convenience method to produce a Forbidden error response.
135
+ *
136
+ * @param error - The original error
137
+ * @param description - Optional custom description
138
+ * @returns ErrorResponse with 403 status code
139
+ */
140
+ forbidden(error: unknown, description?: string): ErrorResponse {
141
+ return this.forbiddenResponder.getResponse(error, description)
142
+ }
143
+ }