@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
@@ -0,0 +1,424 @@
1
+ import { Injectable, InjectionToken } from '@navios/di'
2
+ import { afterEach, describe, expect, it } from 'vitest'
3
+
4
+ import { UnitTestingModule } from '../testing/unit-testing-module.mjs'
5
+
6
+ describe('UnitTestingModule', () => {
7
+ let unitTestingModule: UnitTestingModule | null = null
8
+
9
+ afterEach(async () => {
10
+ if (unitTestingModule) {
11
+ await unitTestingModule.close()
12
+ unitTestingModule = null
13
+ }
14
+ })
15
+
16
+ describe('create', () => {
17
+ it('should create a unit testing module with providers', async () => {
18
+ @Injectable()
19
+ class TestService {
20
+ getValue() {
21
+ return 'test'
22
+ }
23
+ }
24
+
25
+ unitTestingModule = UnitTestingModule.create({
26
+ providers: [{ token: TestService, useClass: TestService }],
27
+ })
28
+
29
+ expect(unitTestingModule).toBeInstanceOf(UnitTestingModule)
30
+ })
31
+
32
+ it('should create with useValue provider', async () => {
33
+ const TOKEN = InjectionToken.create<string>('test-token')
34
+
35
+ unitTestingModule = UnitTestingModule.create({
36
+ providers: [{ token: TOKEN, useValue: 'test-value' }],
37
+ })
38
+
39
+ const value = await unitTestingModule.get(TOKEN)
40
+ expect(value).toBe('test-value')
41
+ })
42
+
43
+ it('should create with useClass provider', async () => {
44
+ @Injectable()
45
+ class OriginalService {
46
+ getValue() {
47
+ return 'original'
48
+ }
49
+ }
50
+
51
+ @Injectable()
52
+ class MockService {
53
+ getValue() {
54
+ return 'mock'
55
+ }
56
+ }
57
+
58
+ unitTestingModule = UnitTestingModule.create({
59
+ providers: [{ token: OriginalService, useClass: MockService }],
60
+ })
61
+
62
+ const service = await unitTestingModule.get(OriginalService)
63
+ expect(service.getValue()).toBe('mock')
64
+ })
65
+
66
+ it('should create with useFactory provider', async () => {
67
+ const TOKEN = InjectionToken.create<{ value: string }>('factory-token')
68
+
69
+ unitTestingModule = UnitTestingModule.create({
70
+ providers: [
71
+ {
72
+ token: TOKEN,
73
+ useFactory: () => ({ value: 'from-factory' }),
74
+ },
75
+ ],
76
+ })
77
+
78
+ const instance = await unitTestingModule.get(TOKEN)
79
+ expect(instance.value).toBe('from-factory')
80
+ })
81
+ })
82
+
83
+ describe('get', () => {
84
+ it('should resolve registered providers', async () => {
85
+ @Injectable()
86
+ class TestService {
87
+ getValue() {
88
+ return 'test'
89
+ }
90
+ }
91
+
92
+ unitTestingModule = UnitTestingModule.create({
93
+ providers: [{ token: TestService, useClass: TestService }],
94
+ })
95
+
96
+ const service = await unitTestingModule.get(TestService)
97
+ expect(service.getValue()).toBe('test')
98
+ })
99
+
100
+ it('should throw for unregistered providers in strict mode', async () => {
101
+ @Injectable()
102
+ class RegisteredService {}
103
+
104
+ @Injectable()
105
+ class UnregisteredService {}
106
+
107
+ unitTestingModule = UnitTestingModule.create({
108
+ providers: [{ token: RegisteredService, useClass: RegisteredService }],
109
+ allowUnregistered: false,
110
+ })
111
+
112
+ await expect(unitTestingModule.get(UnregisteredService)).rejects.toThrow()
113
+ })
114
+
115
+ it('should auto-mock unregistered providers when allowUnregistered is true', async () => {
116
+ @Injectable()
117
+ class RegisteredService {}
118
+
119
+ @Injectable()
120
+ class UnregisteredService {}
121
+
122
+ unitTestingModule = UnitTestingModule.create({
123
+ providers: [{ token: RegisteredService, useClass: RegisteredService }],
124
+ allowUnregistered: true,
125
+ })
126
+
127
+ const unregistered = await unitTestingModule.get(UnregisteredService)
128
+
129
+ // Auto-mocked service should exist but throw on method access
130
+ expect(unregistered).toBeDefined()
131
+ })
132
+ })
133
+
134
+ describe('auto-mocking', () => {
135
+ it('should enable auto-mocking with enableAutoMocking()', async () => {
136
+ @Injectable()
137
+ class UnregisteredService {}
138
+
139
+ unitTestingModule = UnitTestingModule.create({
140
+ providers: [],
141
+ allowUnregistered: false,
142
+ })
143
+
144
+ unitTestingModule.enableAutoMocking()
145
+
146
+ const service = await unitTestingModule.get(UnregisteredService)
147
+ expect(service).toBeDefined()
148
+ })
149
+
150
+ it('should disable auto-mocking with disableAutoMocking()', async () => {
151
+ @Injectable()
152
+ class UnregisteredService {}
153
+
154
+ unitTestingModule = UnitTestingModule.create({
155
+ providers: [],
156
+ allowUnregistered: true,
157
+ })
158
+
159
+ unitTestingModule.disableAutoMocking()
160
+
161
+ await expect(unitTestingModule.get(UnregisteredService)).rejects.toThrow()
162
+ })
163
+
164
+ it('should track auto-mocked services', async () => {
165
+ @Injectable()
166
+ class UnregisteredService {}
167
+
168
+ unitTestingModule = UnitTestingModule.create({
169
+ providers: [],
170
+ allowUnregistered: true,
171
+ })
172
+
173
+ await unitTestingModule.get(UnregisteredService)
174
+
175
+ expect(() => unitTestingModule!.expectAutoMocked(UnregisteredService)).not.toThrow()
176
+ })
177
+ })
178
+
179
+ describe('automatic method call tracking', () => {
180
+ it('should automatically track method calls via proxy', async () => {
181
+ @Injectable()
182
+ class TestService {
183
+ greet(name: string) {
184
+ return `Hello, ${name}!`
185
+ }
186
+ }
187
+
188
+ unitTestingModule = UnitTestingModule.create({
189
+ providers: [{ token: TestService, useClass: TestService }],
190
+ })
191
+
192
+ const service = await unitTestingModule.get(TestService)
193
+ service.greet('World')
194
+
195
+ expect(() => unitTestingModule!.expectCalled(TestService, 'greet')).not.toThrow()
196
+ expect(() =>
197
+ unitTestingModule!.expectCalledWith(TestService, 'greet', ['World']),
198
+ ).not.toThrow()
199
+ })
200
+
201
+ it('should track multiple method calls', async () => {
202
+ @Injectable()
203
+ class TestService {
204
+ methodA() {
205
+ return 'a'
206
+ }
207
+ methodB(x: number, y: number) {
208
+ return x + y
209
+ }
210
+ }
211
+
212
+ unitTestingModule = UnitTestingModule.create({
213
+ providers: [{ token: TestService, useClass: TestService }],
214
+ })
215
+
216
+ const service = await unitTestingModule.get(TestService)
217
+ service.methodA()
218
+ service.methodB(1, 2)
219
+ service.methodB(3, 4)
220
+
221
+ expect(() => unitTestingModule!.expectCallCount(TestService, 'methodA', 1)).not.toThrow()
222
+ expect(() => unitTestingModule!.expectCallCount(TestService, 'methodB', 2)).not.toThrow()
223
+ })
224
+
225
+ it('should track async method calls', async () => {
226
+ @Injectable()
227
+ class AsyncService {
228
+ async fetchData(id: string) {
229
+ return { id, data: 'fetched' }
230
+ }
231
+ }
232
+
233
+ unitTestingModule = UnitTestingModule.create({
234
+ providers: [{ token: AsyncService, useClass: AsyncService }],
235
+ })
236
+
237
+ const service = await unitTestingModule.get(AsyncService)
238
+ await service.fetchData('123')
239
+
240
+ expect(() => unitTestingModule!.expectCalled(AsyncService, 'fetchData')).not.toThrow()
241
+ expect(() =>
242
+ unitTestingModule!.expectCalledWith(AsyncService, 'fetchData', ['123']),
243
+ ).not.toThrow()
244
+ })
245
+
246
+ it('should expose getMethodCalls for custom assertions', async () => {
247
+ @Injectable()
248
+ class TestService {
249
+ process(value: string) {
250
+ return value.toUpperCase()
251
+ }
252
+ }
253
+
254
+ unitTestingModule = UnitTestingModule.create({
255
+ providers: [{ token: TestService, useClass: TestService }],
256
+ })
257
+
258
+ const service = await unitTestingModule.get(TestService)
259
+ service.process('hello')
260
+ service.process('world')
261
+
262
+ const calls = unitTestingModule.getMethodCalls(TestService)
263
+
264
+ expect(calls).toHaveLength(2)
265
+ expect(calls[0].args).toEqual(['hello'])
266
+ expect(calls[0].result).toBe('HELLO')
267
+ expect(calls[1].args).toEqual(['world'])
268
+ expect(calls[1].result).toBe('WORLD')
269
+ })
270
+ })
271
+
272
+ describe('assertion helpers', () => {
273
+ it('should expose expectResolved', async () => {
274
+ @Injectable()
275
+ class TestService {}
276
+
277
+ unitTestingModule = UnitTestingModule.create({
278
+ providers: [{ token: TestService, useClass: TestService }],
279
+ })
280
+
281
+ await unitTestingModule.get(TestService)
282
+
283
+ expect(() => unitTestingModule!.expectResolved(TestService)).not.toThrow()
284
+ })
285
+
286
+ it('should expose expectNotResolved', async () => {
287
+ @Injectable()
288
+ class TestService {}
289
+
290
+ unitTestingModule = UnitTestingModule.create({
291
+ providers: [{ token: TestService, useClass: TestService }],
292
+ })
293
+
294
+ expect(() => unitTestingModule!.expectNotResolved(TestService)).not.toThrow()
295
+ })
296
+
297
+ it('should expose expectNotCalled', async () => {
298
+ @Injectable()
299
+ class TestService {
300
+ method() {
301
+ return 'test'
302
+ }
303
+ }
304
+
305
+ unitTestingModule = UnitTestingModule.create({
306
+ providers: [{ token: TestService, useClass: TestService }],
307
+ })
308
+
309
+ await unitTestingModule.get(TestService)
310
+ // Method not called
311
+
312
+ expect(() => unitTestingModule!.expectNotCalled(TestService, 'method')).not.toThrow()
313
+ })
314
+ })
315
+
316
+ describe('service stats', () => {
317
+ it('should get service stats', async () => {
318
+ @Injectable()
319
+ class TestService {
320
+ doWork() {
321
+ return 'done'
322
+ }
323
+ }
324
+
325
+ unitTestingModule = UnitTestingModule.create({
326
+ providers: [{ token: TestService, useClass: TestService }],
327
+ })
328
+
329
+ const service = await unitTestingModule.get(TestService)
330
+ service.doWork()
331
+ service.doWork()
332
+
333
+ const stats = unitTestingModule.getServiceStats(TestService)
334
+
335
+ expect(stats.methodCalls).toHaveLength(2)
336
+ expect(stats.methodCalls[0].method).toBe('doWork')
337
+ })
338
+ })
339
+
340
+ describe('clearMethodCalls', () => {
341
+ it('should clear all method calls', async () => {
342
+ @Injectable()
343
+ class TestService {
344
+ method() {
345
+ return 'test'
346
+ }
347
+ }
348
+
349
+ unitTestingModule = UnitTestingModule.create({
350
+ providers: [{ token: TestService, useClass: TestService }],
351
+ })
352
+
353
+ const service = await unitTestingModule.get(TestService)
354
+ service.method()
355
+ service.method()
356
+
357
+ expect(unitTestingModule.getMethodCalls(TestService)).toHaveLength(2)
358
+
359
+ unitTestingModule.clearMethodCalls()
360
+
361
+ expect(unitTestingModule.getMethodCalls(TestService)).toHaveLength(0)
362
+ })
363
+ })
364
+
365
+ describe('registered and auto-mocked token tracking', () => {
366
+ it('should track registered token IDs', async () => {
367
+ @Injectable()
368
+ class ServiceA {}
369
+
370
+ @Injectable()
371
+ class ServiceB {}
372
+
373
+ unitTestingModule = UnitTestingModule.create({
374
+ providers: [
375
+ { token: ServiceA, useClass: ServiceA },
376
+ { token: ServiceB, useClass: ServiceB },
377
+ ],
378
+ })
379
+
380
+ const registeredIds = unitTestingModule.getRegisteredTokenIds()
381
+
382
+ expect(registeredIds.size).toBe(2)
383
+ })
384
+
385
+ it('should track auto-mocked token IDs', async () => {
386
+ @Injectable()
387
+ class UnregisteredA {}
388
+
389
+ @Injectable()
390
+ class UnregisteredB {}
391
+
392
+ unitTestingModule = UnitTestingModule.create({
393
+ providers: [],
394
+ allowUnregistered: true,
395
+ })
396
+
397
+ await unitTestingModule.get(UnregisteredA)
398
+ await unitTestingModule.get(UnregisteredB)
399
+
400
+ const autoMockedIds = unitTestingModule.getAutoMockedTokenIds()
401
+
402
+ expect(autoMockedIds.size).toBe(2)
403
+ })
404
+ })
405
+
406
+ describe('close', () => {
407
+ it('should clean up resources', async () => {
408
+ @Injectable()
409
+ class TestService {}
410
+
411
+ unitTestingModule = UnitTestingModule.create({
412
+ providers: [{ token: TestService, useClass: TestService }],
413
+ })
414
+
415
+ await unitTestingModule.get(TestService)
416
+ await unitTestingModule.close()
417
+
418
+ // After close, method calls should be cleared
419
+ expect(unitTestingModule.getMethodCalls(TestService)).toHaveLength(0)
420
+
421
+ unitTestingModule = null // Prevent afterEach from calling close again
422
+ })
423
+ })
424
+ })
@@ -1,6 +1,6 @@
1
- import type { ClassType } from '@navios/di'
1
+ import type { ClassType, InjectableScope } from '@navios/di'
2
2
 
3
- import { Injectable, InjectableScope, InjectionToken } from '@navios/di'
3
+ import { Injectable, InjectionToken, Registry } from '@navios/di'
4
4
 
5
5
  import { getControllerMetadata } from '../metadata/index.mjs'
6
6
 
@@ -13,17 +13,32 @@ export interface ControllerOptions {
13
13
  * Guards are executed in reverse order (last guard first).
14
14
  */
15
15
  guards?: ClassType[] | Set<ClassType>
16
+ /**
17
+ * Registry to use for the controller.
18
+ * Registry is used to store the controller and its endpoints.
19
+ */
20
+ registry?: Registry
21
+ /**
22
+ * Priority to use for the controller.
23
+ * Priority is used to sort the controller in the registry.
24
+ */
25
+ priority?: number
26
+ /**
27
+ * Scope to use for the controller.
28
+ * Scope is used to determine the scope of the controller.
29
+ */
30
+ scope?: InjectableScope
16
31
  }
17
32
 
18
33
  /**
19
34
  * Decorator that marks a class as a Navios controller.
20
- *
35
+ *
21
36
  * Controllers handle HTTP requests and define endpoints.
22
37
  * They are request-scoped by default, meaning a new instance is created for each request.
23
- *
38
+ *
24
39
  * @param options - Controller configuration options
25
40
  * @returns A class decorator
26
- *
41
+ *
27
42
  * @example
28
43
  * ```typescript
29
44
  * @Controller({ guards: [AuthGuard] })
@@ -35,7 +50,12 @@ export interface ControllerOptions {
35
50
  * }
36
51
  * ```
37
52
  */
38
- export function Controller({ guards }: ControllerOptions = {}) {
53
+ export function Controller({
54
+ guards,
55
+ registry,
56
+ priority,
57
+ scope,
58
+ }: ControllerOptions = {}) {
39
59
  return function (target: ClassType, context: ClassDecoratorContext) {
40
60
  if (context.kind !== 'class') {
41
61
  throw new Error(
@@ -53,7 +73,9 @@ export function Controller({ guards }: ControllerOptions = {}) {
53
73
  }
54
74
  return Injectable({
55
75
  token,
56
- scope: InjectableScope.Request,
76
+ registry,
77
+ priority,
78
+ scope,
57
79
  })(target, context)
58
80
  }
59
81
  }
@@ -126,6 +126,51 @@ export type EndpointResult<
126
126
  * }
127
127
  * ```
128
128
  */
129
+ export function Endpoint<
130
+ Method extends HttpMethod = HttpMethod,
131
+ Url extends string = string,
132
+ QuerySchema = undefined,
133
+ ResponseSchema extends ZodType = ZodType,
134
+ RequestSchema = ZodType,
135
+ Params = QuerySchema extends ZodType
136
+ ? RequestSchema extends ZodType
137
+ ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema, true>
138
+ : EndpointFunctionArgs<Url, QuerySchema, undefined, true>
139
+ : RequestSchema extends ZodType
140
+ ? EndpointFunctionArgs<Url, undefined, RequestSchema, true>
141
+ : EndpointFunctionArgs<Url, undefined, undefined, true>,
142
+ >(endpoint: {
143
+ config: BaseEndpointConfig<
144
+ Method,
145
+ Url,
146
+ QuerySchema,
147
+ ResponseSchema,
148
+ RequestSchema
149
+ >
150
+ }): (
151
+ target: (
152
+ params: Params,
153
+ ) => Promise<z.input<ResponseSchema>> | z.input<ResponseSchema>,
154
+ context: ClassMethodDecoratorContext,
155
+ ) => void
156
+ export function Endpoint<
157
+ Method extends HttpMethod = HttpMethod,
158
+ Url extends string = string,
159
+ QuerySchema = undefined,
160
+ ResponseSchema extends ZodType = ZodType,
161
+ RequestSchema = ZodType,
162
+ >(endpoint: {
163
+ config: BaseEndpointConfig<
164
+ Method,
165
+ Url,
166
+ QuerySchema,
167
+ ResponseSchema,
168
+ RequestSchema
169
+ >
170
+ }): (
171
+ target: () => Promise<z.input<ResponseSchema>> | z.input<ResponseSchema>,
172
+ context: ClassMethodDecoratorContext,
173
+ ) => void
129
174
  export function Endpoint<
130
175
  Method extends HttpMethod = HttpMethod,
131
176
  Url extends string = string,
@@ -141,18 +186,21 @@ export function Endpoint<
141
186
  RequestSchema
142
187
  >
143
188
  }) {
144
- return (
145
- target: (
146
- params: QuerySchema extends ZodType
147
- ? RequestSchema extends ZodType
148
- ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema, true>
149
- : EndpointFunctionArgs<Url, QuerySchema, undefined, true>
150
- : RequestSchema extends ZodType
151
- ? EndpointFunctionArgs<Url, undefined, RequestSchema, true>
152
- : EndpointFunctionArgs<Url, undefined, undefined, true>,
153
- ) => Promise<z.input<ResponseSchema>>,
154
- context: ClassMethodDecoratorContext,
155
- ) => {
189
+ type Params = QuerySchema extends ZodType
190
+ ? RequestSchema extends ZodType
191
+ ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema, true>
192
+ : EndpointFunctionArgs<Url, QuerySchema, undefined, true>
193
+ : RequestSchema extends ZodType
194
+ ? EndpointFunctionArgs<Url, undefined, RequestSchema, true>
195
+ : EndpointFunctionArgs<Url, undefined, undefined, true>
196
+
197
+ type Handler =
198
+ | ((
199
+ params: Params,
200
+ ) => Promise<z.input<ResponseSchema>> | z.input<ResponseSchema>)
201
+ | (() => Promise<z.input<ResponseSchema>> | z.input<ResponseSchema>)
202
+
203
+ return (target: Handler, context: ClassMethodDecoratorContext) => {
156
204
  if (context.kind !== 'method') {
157
205
  throw new Error(
158
206
  '[Navios] Endpoint decorator can only be used on methods.',
@@ -1,4 +1,4 @@
1
- import type { ClassType } from '@navios/di'
1
+ import type { ClassType, Registry } from '@navios/di'
2
2
 
3
3
  import { Injectable, InjectableScope, InjectionToken } from '@navios/di'
4
4
 
@@ -23,17 +23,27 @@ export interface ModuleOptions {
23
23
  * Guards are executed in reverse order (last guard first).
24
24
  */
25
25
  guards?: ClassType[] | Set<ClassType>
26
+ /**
27
+ * Priority to use for the module.
28
+ * Priority is used to sort the module in the registry.
29
+ */
30
+ priority?: number
31
+ /**
32
+ * Registry to use for the module.
33
+ * Registry is used to store the module and its controllers.
34
+ */
35
+ registry?: Registry
26
36
  }
27
37
 
28
38
  /**
29
39
  * Decorator that marks a class as a Navios module.
30
- *
40
+ *
31
41
  * Modules are the basic building blocks of a Navios application.
32
42
  * They organize controllers, services, and other modules into logical units.
33
- *
43
+ *
34
44
  * @param options - Module configuration options
35
45
  * @returns A class decorator
36
- *
46
+ *
37
47
  * @example
38
48
  * ```typescript
39
49
  * @Module({
@@ -45,7 +55,13 @@ export interface ModuleOptions {
45
55
  * ```
46
56
  */
47
57
  export function Module(
48
- { controllers = [], imports = [], guards = [] }: ModuleOptions = {
58
+ {
59
+ controllers = [],
60
+ imports = [],
61
+ guards = [],
62
+ priority,
63
+ registry,
64
+ }: ModuleOptions = {
49
65
  controllers: [],
50
66
  imports: [],
51
67
  guards: [],
@@ -71,6 +87,8 @@ export function Module(
71
87
  return Injectable({
72
88
  token,
73
89
  scope: InjectableScope.Singleton,
90
+ priority,
91
+ registry,
74
92
  })(target, context)
75
93
  }
76
94
  }