@navios/core 0.7.1 → 0.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 (68) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/lib/{index-DW9EPAE6.d.mts → index-D9MNh6Tx.d.mts} +534 -342
  3. package/lib/index-D9MNh6Tx.d.mts.map +1 -0
  4. package/lib/{index-pHp-dIGt.d.cts → index-Db1d3cwD.d.cts} +534 -342
  5. package/lib/index-Db1d3cwD.d.cts.map +1 -0
  6. package/lib/index.cjs +12 -3
  7. package/lib/index.d.cts +2 -2
  8. package/lib/index.d.mts +2 -2
  9. package/lib/index.mjs +3 -3
  10. package/lib/legacy-compat/index.cjs +1 -1
  11. package/lib/legacy-compat/index.cjs.map +1 -1
  12. package/lib/legacy-compat/index.d.cts +3 -3
  13. package/lib/legacy-compat/index.d.cts.map +1 -1
  14. package/lib/legacy-compat/index.d.mts +3 -3
  15. package/lib/legacy-compat/index.d.mts.map +1 -1
  16. package/lib/legacy-compat/index.mjs +1 -1
  17. package/lib/legacy-compat/index.mjs.map +1 -1
  18. package/lib/{src-QnxR5b7c.cjs → src-BRPtJ9fG.cjs} +474 -53
  19. package/lib/src-BRPtJ9fG.cjs.map +1 -0
  20. package/lib/{src-DyvCDuKO.mjs → src-Bo23RIo-.mjs} +454 -51
  21. package/lib/src-Bo23RIo-.mjs.map +1 -0
  22. package/lib/testing/index.cjs +346 -29
  23. package/lib/testing/index.cjs.map +1 -1
  24. package/lib/testing/index.d.cts +299 -63
  25. package/lib/testing/index.d.cts.map +1 -1
  26. package/lib/testing/index.d.mts +299 -63
  27. package/lib/testing/index.d.mts.map +1 -1
  28. package/lib/testing/index.mjs +347 -31
  29. package/lib/testing/index.mjs.map +1 -1
  30. package/lib/{use-guards.decorator-B6q_N0sf.cjs → use-guards.decorator-Bs8oDHOi.cjs} +29 -99
  31. package/lib/use-guards.decorator-Bs8oDHOi.cjs.map +1 -0
  32. package/lib/{use-guards.decorator-kZ3lNK8v.mjs → use-guards.decorator-CzVXuLkz.mjs} +23 -99
  33. package/lib/use-guards.decorator-CzVXuLkz.mjs.map +1 -0
  34. package/package.json +4 -4
  35. package/src/__tests__/controller-resolver.spec.mts +229 -0
  36. package/src/__tests__/controller.spec.mts +1 -1
  37. package/src/__tests__/testing-module.spec.mts +459 -0
  38. package/src/__tests__/unit-testing-module.spec.mts +424 -0
  39. package/src/decorators/controller.decorator.mts +29 -7
  40. package/src/decorators/endpoint.decorator.mts +60 -12
  41. package/src/decorators/module.decorator.mts +23 -5
  42. package/src/decorators/multipart.decorator.mts +67 -24
  43. package/src/decorators/stream.decorator.mts +65 -24
  44. package/src/interfaces/abstract-http-handler-adapter.interface.mts +31 -1
  45. package/src/legacy-compat/__type-tests__/legacy-decorators.spec-d.mts +2 -6
  46. package/src/legacy-compat/decorators/endpoint.decorator.mts +1 -1
  47. package/src/legacy-compat/decorators/multipart.decorator.mts +5 -5
  48. package/src/legacy-compat/decorators/stream.decorator.mts +5 -5
  49. package/src/logger/logger.service.mts +0 -2
  50. package/src/navios.application.mts +23 -9
  51. package/src/navios.environment.mts +3 -1
  52. package/src/navios.factory.mts +19 -18
  53. package/src/services/guard-runner.service.mts +46 -9
  54. package/src/services/index.mts +1 -0
  55. package/src/services/instance-resolver.service.mts +187 -0
  56. package/src/services/module-loader.service.mts +3 -2
  57. package/src/stores/request-id.store.mts +45 -3
  58. package/src/testing/index.mts +1 -0
  59. package/src/testing/testing-module.mts +255 -93
  60. package/src/testing/unit-testing-module.mts +298 -0
  61. package/src/tokens/index.mts +1 -0
  62. package/src/tokens/navios-options.token.mts +6 -0
  63. package/lib/index-DW9EPAE6.d.mts.map +0 -1
  64. package/lib/index-pHp-dIGt.d.cts.map +0 -1
  65. package/lib/src-DyvCDuKO.mjs.map +0 -1
  66. package/lib/src-QnxR5b7c.cjs.map +0 -1
  67. package/lib/use-guards.decorator-B6q_N0sf.cjs.map +0 -1
  68. package/lib/use-guards.decorator-kZ3lNK8v.mjs.map +0 -1
@@ -13,9 +13,9 @@ import { MultipartAdapterToken } from '../tokens/index.mjs'
13
13
 
14
14
  /**
15
15
  * Extracts the typed parameters for a multipart endpoint handler function.
16
- *
16
+ *
17
17
  * Similar to `EndpointParams`, but specifically for multipart/form-data endpoints.
18
- *
18
+ *
19
19
  * @typeParam EndpointDeclaration - The endpoint declaration from @navios/builder
20
20
  */
21
21
  export type MultipartParams<
@@ -48,7 +48,7 @@ export type MultipartParams<
48
48
 
49
49
  /**
50
50
  * Extracts the typed return value for a multipart endpoint handler function.
51
- *
51
+ *
52
52
  * @typeParam EndpointDeclaration - The endpoint declaration from @navios/builder
53
53
  */
54
54
  export type MultipartResult<
@@ -64,13 +64,13 @@ export type MultipartResult<
64
64
 
65
65
  /**
66
66
  * Decorator that marks a method as a multipart/form-data endpoint.
67
- *
67
+ *
68
68
  * Use this decorator for endpoints that handle file uploads or form data.
69
69
  * The endpoint must be defined using @navios/builder's `declareMultipart` method.
70
- *
70
+ *
71
71
  * @param endpoint - The multipart endpoint declaration from @navios/builder
72
72
  * @returns A method decorator
73
- *
73
+ *
74
74
  * @example
75
75
  * ```typescript
76
76
  * const uploadFileEndpoint = api.declareMultipart({
@@ -79,7 +79,7 @@ export type MultipartResult<
79
79
  * requestSchema: z.object({ file: z.instanceof(File) }),
80
80
  * responseSchema: z.object({ url: z.string() }),
81
81
  * })
82
- *
82
+ *
83
83
  * @Controller()
84
84
  * export class FileController {
85
85
  * @Multipart(uploadFileEndpoint)
@@ -91,6 +91,51 @@ export type MultipartResult<
91
91
  * }
92
92
  * ```
93
93
  */
94
+ export function Multipart<
95
+ Method extends HttpMethod = HttpMethod,
96
+ Url extends string = string,
97
+ QuerySchema = undefined,
98
+ ResponseSchema extends ZodType = ZodType,
99
+ RequestSchema = ZodType,
100
+ Params = QuerySchema extends ZodObject
101
+ ? RequestSchema extends ZodType
102
+ ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema, true>
103
+ : EndpointFunctionArgs<Url, QuerySchema, undefined, true>
104
+ : RequestSchema extends ZodType
105
+ ? EndpointFunctionArgs<Url, undefined, RequestSchema, true>
106
+ : EndpointFunctionArgs<Url, undefined, undefined, true>,
107
+ >(endpoint: {
108
+ config: BaseEndpointConfig<
109
+ Method,
110
+ Url,
111
+ QuerySchema,
112
+ ResponseSchema,
113
+ RequestSchema
114
+ >
115
+ }): (
116
+ target: (
117
+ params: Params,
118
+ ) => Promise<z.input<ResponseSchema>> | z.input<ResponseSchema>,
119
+ context: ClassMethodDecoratorContext,
120
+ ) => void
121
+ export function Multipart<
122
+ Method extends HttpMethod = HttpMethod,
123
+ Url extends string = string,
124
+ QuerySchema = undefined,
125
+ ResponseSchema extends ZodType = ZodType,
126
+ RequestSchema = ZodType,
127
+ >(endpoint: {
128
+ config: BaseEndpointConfig<
129
+ Method,
130
+ Url,
131
+ QuerySchema,
132
+ ResponseSchema,
133
+ RequestSchema
134
+ >
135
+ }): (
136
+ target: () => Promise<z.input<ResponseSchema>> | z.input<ResponseSchema>,
137
+ context: ClassMethodDecoratorContext,
138
+ ) => void
94
139
  export function Multipart<
95
140
  Method extends HttpMethod = HttpMethod,
96
141
  Url extends string = string,
@@ -106,23 +151,21 @@ export function Multipart<
106
151
  RequestSchema
107
152
  >
108
153
  }) {
109
- return (
110
- target: (
111
- params: QuerySchema extends ZodObject
112
- ? RequestSchema extends ZodType
113
- ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema>
114
- : EndpointFunctionArgs<Url, QuerySchema, undefined>
115
- : RequestSchema extends ZodType
116
- ? EndpointFunctionArgs<Url, undefined, RequestSchema>
117
- : EndpointFunctionArgs<Url, undefined, undefined>,
118
- ) => Promise<z.input<ResponseSchema>>,
119
- context: ClassMethodDecoratorContext,
120
- ) => {
121
- if (typeof target !== 'function') {
122
- throw new Error(
123
- '[Navios] Endpoint decorator can only be used on functions.',
124
- )
125
- }
154
+ type Params = QuerySchema extends ZodObject
155
+ ? RequestSchema extends ZodType
156
+ ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema, true>
157
+ : EndpointFunctionArgs<Url, QuerySchema, undefined, true>
158
+ : RequestSchema extends ZodType
159
+ ? EndpointFunctionArgs<Url, undefined, RequestSchema, true>
160
+ : EndpointFunctionArgs<Url, undefined, undefined, true>
161
+
162
+ type Handler =
163
+ | ((
164
+ params: Params,
165
+ ) => Promise<z.input<ResponseSchema>> | z.input<ResponseSchema>)
166
+ | (() => Promise<z.input<ResponseSchema>> | z.input<ResponseSchema>)
167
+
168
+ return (target: Handler, context: ClassMethodDecoratorContext) => {
126
169
  if (context.kind !== 'method') {
127
170
  throw new Error(
128
171
  '[Navios] Endpoint decorator can only be used on methods.',
@@ -11,9 +11,9 @@ import { StreamAdapterToken } from '../tokens/index.mjs'
11
11
 
12
12
  /**
13
13
  * Extracts the typed parameters for a stream endpoint handler function.
14
- *
14
+ *
15
15
  * Similar to `EndpointParams`, but specifically for streaming endpoints.
16
- *
16
+ *
17
17
  * @typeParam EndpointDeclaration - The stream endpoint declaration from @navios/builder
18
18
  */
19
19
  export type StreamParams<
@@ -46,20 +46,20 @@ export type StreamParams<
46
46
 
47
47
  /**
48
48
  * Decorator that marks a method as a streaming endpoint.
49
- *
49
+ *
50
50
  * Use this decorator for endpoints that stream data (e.g., file downloads, SSE).
51
51
  * The endpoint must be defined using @navios/builder's `declareStream` method.
52
- *
52
+ *
53
53
  * @param endpoint - The stream endpoint declaration from @navios/builder
54
54
  * @returns A method decorator
55
- *
55
+ *
56
56
  * @example
57
57
  * ```typescript
58
58
  * const downloadFileEndpoint = api.declareStream({
59
59
  * method: 'get',
60
60
  * url: '/files/$fileId',
61
61
  * })
62
- *
62
+ *
63
63
  * @Controller()
64
64
  * export class FileController {
65
65
  * @Stream(downloadFileEndpoint)
@@ -70,6 +70,51 @@ export type StreamParams<
70
70
  * }
71
71
  * ```
72
72
  */
73
+ export function Stream<
74
+ Method extends HttpMethod = HttpMethod,
75
+ Url extends string = string,
76
+ QuerySchema = undefined,
77
+ RequestSchema = ZodType,
78
+ Params = QuerySchema extends ZodObject
79
+ ? RequestSchema extends ZodType
80
+ ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema, true>
81
+ : EndpointFunctionArgs<Url, QuerySchema, undefined, true>
82
+ : RequestSchema extends ZodType
83
+ ? EndpointFunctionArgs<Url, undefined, RequestSchema, true>
84
+ : EndpointFunctionArgs<Url, undefined, undefined, true>,
85
+ >(endpoint: {
86
+ config: BaseStreamConfig<Method, Url, QuerySchema, RequestSchema>
87
+ }): (
88
+ target: (params: Params, reply: any) => any,
89
+ context: ClassMethodDecoratorContext,
90
+ ) => void
91
+ // Bun doesn't support reply parameter
92
+ export function Stream<
93
+ Method extends HttpMethod = HttpMethod,
94
+ Url extends string = string,
95
+ QuerySchema = undefined,
96
+ RequestSchema = ZodType,
97
+ Params = QuerySchema extends ZodObject
98
+ ? RequestSchema extends ZodType
99
+ ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema, true>
100
+ : EndpointFunctionArgs<Url, QuerySchema, undefined, true>
101
+ : RequestSchema extends ZodType
102
+ ? EndpointFunctionArgs<Url, undefined, RequestSchema, true>
103
+ : EndpointFunctionArgs<Url, undefined, undefined, true>,
104
+ >(endpoint: {
105
+ config: BaseStreamConfig<Method, Url, QuerySchema, RequestSchema>
106
+ }): (
107
+ target: (params: Params) => any,
108
+ context: ClassMethodDecoratorContext,
109
+ ) => void
110
+ export function Stream<
111
+ Method extends HttpMethod = HttpMethod,
112
+ Url extends string = string,
113
+ QuerySchema = undefined,
114
+ RequestSchema = ZodType,
115
+ >(endpoint: {
116
+ config: BaseStreamConfig<Method, Url, QuerySchema, RequestSchema>
117
+ }): (target: () => any, context: ClassMethodDecoratorContext) => void
73
118
  export function Stream<
74
119
  Method extends HttpMethod = HttpMethod,
75
120
  Url extends string = string,
@@ -78,24 +123,20 @@ export function Stream<
78
123
  >(endpoint: {
79
124
  config: BaseStreamConfig<Method, Url, QuerySchema, RequestSchema>
80
125
  }) {
81
- return (
82
- target: (
83
- params: QuerySchema extends ZodObject
84
- ? RequestSchema extends ZodType
85
- ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema>
86
- : EndpointFunctionArgs<Url, QuerySchema, undefined>
87
- : RequestSchema extends ZodType
88
- ? EndpointFunctionArgs<Url, undefined, RequestSchema>
89
- : EndpointFunctionArgs<Url, undefined, undefined>,
90
- reply: any,
91
- ) => Promise<void>,
92
- context: ClassMethodDecoratorContext,
93
- ) => {
94
- if (typeof target !== 'function') {
95
- throw new Error(
96
- '[Navios] Endpoint decorator can only be used on functions.',
97
- )
98
- }
126
+ type Params = QuerySchema extends ZodObject
127
+ ? RequestSchema extends ZodType
128
+ ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema, true>
129
+ : EndpointFunctionArgs<Url, QuerySchema, undefined, true>
130
+ : RequestSchema extends ZodType
131
+ ? EndpointFunctionArgs<Url, undefined, RequestSchema, true>
132
+ : EndpointFunctionArgs<Url, undefined, undefined, true>
133
+
134
+ type Handler =
135
+ | ((params: Params, reply: any) => any)
136
+ | ((params: Params) => any)
137
+ | (() => any)
138
+
139
+ return (target: Handler, context: ClassMethodDecoratorContext) => {
99
140
  if (context.kind !== 'method') {
100
141
  throw new Error(
101
142
  '[Navios] Endpoint decorator can only be used on methods.',
@@ -2,6 +2,36 @@ import type { ClassType, ScopedContainer } from '@navios/di'
2
2
 
3
3
  import type { HandlerMetadata } from '../metadata/index.mjs'
4
4
 
5
+ /**
6
+ * Static handler result - handler can be called without a scoped container.
7
+ * Used when the controller and all its dependencies are singletons.
8
+ */
9
+ export type StaticHandler<TRequest = any, TReply = any> = {
10
+ isStatic: true
11
+ handler: (request: TRequest, reply: TReply) => Promise<any>
12
+ }
13
+
14
+ /**
15
+ * Dynamic handler result - handler requires a scoped container for resolution.
16
+ * Used when the controller or its dependencies need per-request resolution.
17
+ */
18
+ export type DynamicHandler<TRequest = any, TReply = any> = {
19
+ isStatic: false
20
+ handler: (
21
+ scoped: ScopedContainer,
22
+ request: TRequest,
23
+ reply: TReply,
24
+ ) => Promise<any>
25
+ }
26
+
27
+ /**
28
+ * Handler result returned by provideHandler.
29
+ * Can be either static (pre-resolved) or dynamic (needs scoped container).
30
+ */
31
+ export type HandlerResult<TRequest = any, TReply = any> =
32
+ | StaticHandler<TRequest, TReply>
33
+ | DynamicHandler<TRequest, TReply>
34
+
5
35
  export interface AbstractHttpHandlerAdapterInterface {
6
36
  prepareArguments?: (
7
37
  handlerMetadata: HandlerMetadata<any>,
@@ -9,5 +39,5 @@ export interface AbstractHttpHandlerAdapterInterface {
9
39
  provideHandler: (
10
40
  controller: ClassType,
11
41
  handlerMetadata: HandlerMetadata<any>,
12
- ) => (context: ScopedContainer, request: any, reply: any) => Promise<any>
42
+ ) => Promise<HandlerResult>
13
43
  }
@@ -138,9 +138,7 @@ describe('Legacy Decorators Type Safety', () => {
138
138
  // - request.urlParams.userId: string | number
139
139
  // - request.params.page: number
140
140
  // - request.params.limit: number
141
- expectTypeOf(request.urlParams.userId).toEqualTypeOf<
142
- string | number
143
- >()
141
+ expectTypeOf(request.urlParams.userId).toEqualTypeOf<string>()
144
142
  expectTypeOf(request.params.page).toEqualTypeOf<number>()
145
143
  expectTypeOf(request.params.limit).toEqualTypeOf<number>()
146
144
  return {
@@ -270,9 +268,7 @@ describe('Legacy Decorators Type Safety', () => {
270
268
  // - request.urlParams.fileId: string | number
271
269
  // - request.params.page: number
272
270
  // - request.params.limit: number
273
- expectTypeOf(request.urlParams.fileId).toEqualTypeOf<
274
- string | number
275
- >()
271
+ expectTypeOf(request.urlParams.fileId).toEqualTypeOf<string>()
276
272
  expectTypeOf(request.params.page).toEqualTypeOf<number>()
277
273
  expectTypeOf(request.params.limit).toEqualTypeOf<number>()
278
274
  }
@@ -92,7 +92,7 @@ export function Endpoint<
92
92
  // @ts-expect-error - we don't need to type the value
93
93
  const result = originalDecorator(typedDescriptor.value, context)
94
94
  if (result !== typedDescriptor.value) {
95
- typedDescriptor.value = result
95
+ typedDescriptor.value = result as any
96
96
  }
97
97
  return typedDescriptor
98
98
  }
@@ -22,11 +22,11 @@ type MultipartMethodDescriptor<
22
22
  (
23
23
  params: QuerySchema extends ZodObject
24
24
  ? RequestSchema extends ZodType
25
- ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema>
26
- : EndpointFunctionArgs<Url, QuerySchema, undefined>
25
+ ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema, true>
26
+ : EndpointFunctionArgs<Url, QuerySchema, undefined, true>
27
27
  : RequestSchema extends ZodType
28
- ? EndpointFunctionArgs<Url, undefined, RequestSchema>
29
- : EndpointFunctionArgs<Url, undefined, undefined>,
28
+ ? EndpointFunctionArgs<Url, undefined, RequestSchema, true>
29
+ : EndpointFunctionArgs<Url, undefined, undefined, true>,
30
30
  ) => Promise<z.input<ResponseSchema>>
31
31
  >
32
32
 
@@ -86,7 +86,7 @@ export function Multipart<
86
86
  // @ts-expect-error - we don't need to type the value
87
87
  const result = originalDecorator(descriptor.value, context)
88
88
  if (result !== descriptor.value) {
89
- descriptor.value = result
89
+ descriptor.value = result as any
90
90
  }
91
91
  return descriptor
92
92
  }
@@ -21,11 +21,11 @@ type StreamMethodDescriptor<
21
21
  (
22
22
  params: QuerySchema extends ZodObject
23
23
  ? RequestSchema extends ZodType
24
- ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema>
25
- : EndpointFunctionArgs<Url, QuerySchema, undefined>
24
+ ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema, true>
25
+ : EndpointFunctionArgs<Url, QuerySchema, undefined, true>
26
26
  : RequestSchema extends ZodType
27
- ? EndpointFunctionArgs<Url, undefined, RequestSchema>
28
- : EndpointFunctionArgs<Url, undefined, undefined>,
27
+ ? EndpointFunctionArgs<Url, undefined, RequestSchema, true>
28
+ : EndpointFunctionArgs<Url, undefined, undefined, true>,
29
29
  reply: any,
30
30
  ) => Promise<void>
31
31
  >
@@ -69,7 +69,7 @@ export function Stream<
69
69
  // @ts-expect-error - we don't need to type the value
70
70
  const result = originalDecorator(descriptor.value, context)
71
71
  if (result !== descriptor.value) {
72
- descriptor.value = result
72
+ descriptor.value = result as any
73
73
  }
74
74
  return descriptor
75
75
  }
@@ -60,8 +60,6 @@ export class LoggerInstance implements LoggerService {
60
60
  optionalParams = this.context
61
61
  ? optionalParams.concat(this.context)
62
62
  : optionalParams
63
- console.log('log', message, optionalParams)
64
- console.log('localInstance', this.localInstance)
65
63
  this.localInstance?.log(message, ...optionalParams)
66
64
  }
67
65
 
@@ -1,4 +1,4 @@
1
- import type { ClassTypeWithInstance } from '@navios/di'
1
+ import type { ClassTypeWithInstance, Registry } from '@navios/di'
2
2
 
3
3
  import { Container, inject, Injectable } from '@navios/di'
4
4
 
@@ -19,9 +19,9 @@ import { ModuleLoaderService } from './services/index.mjs'
19
19
 
20
20
  /**
21
21
  * Options for configuring the Navios application context.
22
- * These options control dependency injection and logging behavior.
22
+ * These options control the application configuration.
23
23
  */
24
- export interface NaviosApplicationContextOptions {
24
+ export interface NaviosApplicationOptions {
25
25
  /**
26
26
  * Specifies the logger to use. Pass `false` to turn off logging.
27
27
  *
@@ -31,18 +31,18 @@ export interface NaviosApplicationContextOptions {
31
31
  */
32
32
  logger?: LoggerService | LogLevel[] | false
33
33
 
34
+ /**
35
+ * Specifies a custom registry to use. Useful for testing.
36
+ * If not provided, a new Registry will be created.
37
+ */
38
+ registry?: Registry
39
+
34
40
  /**
35
41
  * Specifies a custom container to use. Useful for testing.
36
42
  * If not provided, a new Container will be created.
37
43
  */
38
44
  container?: Container
39
- }
40
45
 
41
- /**
42
- * Complete options for creating a Navios application.
43
- * Extends NaviosApplicationContextOptions with adapter configuration.
44
- */
45
- export interface NaviosApplicationOptions extends NaviosApplicationContextOptions {
46
46
  /**
47
47
  * HTTP adapter environment(s) to use for the application.
48
48
  * Can be a single adapter or an array of adapters.
@@ -55,6 +55,20 @@ export interface NaviosApplicationOptions extends NaviosApplicationContextOption
55
55
  * ```
56
56
  */
57
57
  adapter: NaviosEnvironmentOptions | NaviosEnvironmentOptions[]
58
+
59
+ /**
60
+ * Whether to validate response schemas.
61
+ * When `false`, response schema validation is skipped for better performance.
62
+ * @default true
63
+ */
64
+ validateResponses?: boolean
65
+
66
+ /**
67
+ * Whether to enable request ID propagation via AsyncLocalStorage.
68
+ * When `true`, request IDs are available via `getRequestId()` throughout the request.
69
+ * @default false
70
+ */
71
+ enableRequestId?: boolean
58
72
  }
59
73
 
60
74
  /**
@@ -17,7 +17,9 @@ export class NaviosEnvironment {
17
17
  setupHttpEnvironment(
18
18
  tokens: Map<InjectionToken<any, undefined>, AnyInjectableType>,
19
19
  ) {
20
- this.httpTokens = tokens
20
+ for (const [token, value] of tokens) {
21
+ this.httpTokens.set(token, value)
22
+ }
21
23
  }
22
24
 
23
25
  getHttpToken(token: InjectionToken<any, undefined>) {
@@ -4,17 +4,16 @@ import type {
4
4
  InjectionToken,
5
5
  } from '@navios/di'
6
6
 
7
- import { Container, InjectableScope, InjectableType } from '@navios/di'
7
+ import { Container } from '@navios/di'
8
8
 
9
9
  import type { NaviosModule } from './interfaces/index.mjs'
10
- import type {
11
- NaviosApplicationContextOptions,
12
- NaviosApplicationOptions,
13
- } from './navios.application.mjs'
10
+ import type { NaviosApplicationOptions } from './navios.application.mjs'
14
11
 
15
12
  import { ConsoleLogger, isNil, LoggerOutput } from './logger/index.mjs'
16
13
  import { NaviosApplication } from './navios.application.mjs'
17
14
  import { NaviosEnvironment } from './navios.environment.mjs'
15
+ import { setRequestIdEnabled } from './stores/index.mjs'
16
+ import { NaviosOptionsToken } from './tokens/index.mjs'
18
17
 
19
18
  /**
20
19
  * Factory class for creating and configuring Navios applications.
@@ -81,7 +80,16 @@ export class NaviosFactory {
81
80
  adapter: [],
82
81
  },
83
82
  ) {
84
- const container = options.container ?? new Container()
83
+ const container = options.container ?? new Container(options.registry)
84
+
85
+ // Set request ID flag early, before any adapters are registered
86
+ if (options.enableRequestId === true) {
87
+ setRequestIdEnabled(true)
88
+ }
89
+
90
+ // Store options in container for DI access by adapters
91
+ container.addInstance(NaviosOptionsToken, options)
92
+
85
93
  await this.registerLoggerConfiguration(container, options)
86
94
  const adapters = Array.isArray(options.adapter)
87
95
  ? options.adapter
@@ -109,28 +117,21 @@ export class NaviosFactory {
109
117
 
110
118
  private static async registerLoggerConfiguration(
111
119
  container: Container,
112
- options: NaviosApplicationContextOptions,
120
+ options: NaviosApplicationOptions,
113
121
  ) {
114
122
  const { logger } = options
115
- if (Array.isArray(logger) || isNil(logger)) {
123
+ if (Array.isArray(logger) || isNil(logger) || options.enableRequestId) {
116
124
  const loggerInstance = (await container.get(
117
125
  LoggerOutput,
118
126
  )) as ConsoleLogger
119
127
  loggerInstance?.setup({
120
- logLevels: logger,
128
+ logLevels: Array.isArray(logger) ? logger : undefined,
129
+ requestId: options.enableRequestId ?? false,
121
130
  })
122
131
  return
123
132
  }
124
133
  if ((logger as boolean) !== true && !isNil(logger)) {
125
- container
126
- .getServiceLocator()
127
- .getManager()
128
- .storeCreatedHolder(
129
- LoggerOutput.toString(),
130
- logger,
131
- InjectableType.Class,
132
- InjectableScope.Singleton,
133
- )
134
+ container.addInstance(LoggerOutput, logger)
134
135
  }
135
136
  }
136
137
  }
@@ -20,6 +20,11 @@ export class GuardRunnerService {
20
20
  private readonly logger = inject(Logger, {
21
21
  context: GuardRunnerService.name,
22
22
  })
23
+
24
+ /**
25
+ * Runs guards that need to be resolved from a scoped container.
26
+ * Use this when guards have request-scoped dependencies.
27
+ */
23
28
  async runGuards(
24
29
  allGuards: Set<
25
30
  | ClassTypeWithInstance<CanActivate>
@@ -28,16 +33,48 @@ export class GuardRunnerService {
28
33
  executionContext: AbstractExecutionContext,
29
34
  context: ScopedContainer,
30
35
  ) {
31
- let canActivate = true
32
- for (const guard of Array.from(allGuards).reverse()) {
33
- const guardInstance = await context.get(
34
- guard as InjectionToken<CanActivate, undefined>,
35
- )
36
- if (!guardInstance.canActivate) {
37
- throw new Error(
38
- `[Navios] Guard ${guard.name as string} does not implement canActivate()`,
36
+ // Reverse order: module guards run first, then controller, then endpoint
37
+ const guardsArray = Array.from(allGuards).reverse()
38
+
39
+ // Resolve all guards in parallel
40
+ const guardInstances = await Promise.all(
41
+ guardsArray.map(async (guard) => {
42
+ const guardInstance = await context.get(
43
+ guard as InjectionToken<CanActivate, undefined>,
39
44
  )
40
- }
45
+ if (!guardInstance.canActivate) {
46
+ throw new Error(
47
+ `[Navios] Guard ${guard.name as string} does not implement canActivate()`,
48
+ )
49
+ }
50
+ return guardInstance
51
+ }),
52
+ )
53
+
54
+ return this.executeGuards(guardInstances, executionContext)
55
+ }
56
+
57
+ /**
58
+ * Runs pre-resolved guard instances.
59
+ * Use this when all guards are singletons and have been pre-resolved at startup.
60
+ */
61
+ async runGuardsStatic(
62
+ guardInstances: CanActivate[],
63
+ executionContext: AbstractExecutionContext,
64
+ ) {
65
+ return this.executeGuards(guardInstances, executionContext)
66
+ }
67
+
68
+ /**
69
+ * Shared guard execution logic.
70
+ * Iterates through guard instances and calls canActivate on each.
71
+ */
72
+ private async executeGuards(
73
+ guardInstances: CanActivate[],
74
+ executionContext: AbstractExecutionContext,
75
+ ): Promise<boolean> {
76
+ let canActivate = true
77
+ for (const guardInstance of guardInstances) {
41
78
  try {
42
79
  canActivate = await guardInstance.canActivate(executionContext)
43
80
  if (!canActivate) {
@@ -1,2 +1,3 @@
1
+ export * from './instance-resolver.service.mjs'
1
2
  export * from './guard-runner.service.mjs'
2
3
  export * from './module-loader.service.mjs'