@navios/core 1.0.0-alpha.2 → 1.0.0-alpha.4

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 (93) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/lib/{index-BJjk2X1S.d.mts → index-6S7veHKD.d.mts} +845 -294
  3. package/lib/index-6S7veHKD.d.mts.map +1 -0
  4. package/lib/{index-DZ6NU03y.d.cts → index-r0i2txmg.d.cts} +845 -294
  5. package/lib/index-r0i2txmg.d.cts.map +1 -0
  6. package/lib/index.cjs +4420 -84
  7. package/lib/index.cjs.map +1 -0
  8. package/lib/index.d.cts +2 -2
  9. package/lib/index.d.mts +2 -2
  10. package/lib/index.mjs +4328 -3
  11. package/lib/index.mjs.map +1 -0
  12. package/lib/legacy-compat/index.cjs +41 -126
  13. package/lib/legacy-compat/index.cjs.map +1 -1
  14. package/lib/legacy-compat/index.d.cts +4 -60
  15. package/lib/legacy-compat/index.d.cts.map +1 -1
  16. package/lib/legacy-compat/index.d.mts +4 -60
  17. package/lib/legacy-compat/index.d.mts.map +1 -1
  18. package/lib/legacy-compat/index.mjs +14 -119
  19. package/lib/legacy-compat/index.mjs.map +1 -1
  20. package/lib/navios.factory-BanZIvtR.cjs +4134 -0
  21. package/lib/navios.factory-BanZIvtR.cjs.map +1 -0
  22. package/lib/navios.factory-C75yZCoD.mjs +3831 -0
  23. package/lib/navios.factory-C75yZCoD.mjs.map +1 -0
  24. package/lib/testing/index.cjs +3 -3
  25. package/lib/testing/index.cjs.map +1 -1
  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/tokens-4J9sredA.mjs +100 -0
  30. package/lib/tokens-4J9sredA.mjs.map +1 -0
  31. package/lib/tokens-BuXXB01L.cjs +196 -0
  32. package/lib/tokens-BuXXB01L.cjs.map +1 -0
  33. package/lib/{use-guards.decorator-Be_QUx6b.mjs → use-guards.decorator-BecoQSmE.mjs} +3 -70
  34. package/lib/use-guards.decorator-BecoQSmE.mjs.map +1 -0
  35. package/lib/{use-guards.decorator-B6tghdxM.cjs → use-guards.decorator-DgD-kxF5.cjs} +7 -158
  36. package/lib/use-guards.decorator-DgD-kxF5.cjs.map +1 -0
  37. package/package.json +4 -4
  38. package/src/__tests__/attribute.factory.spec.mts +300 -0
  39. package/src/__tests__/console-logger.service.spec.mts +312 -0
  40. package/src/__tests__/guard-runner.service.spec.mts +399 -0
  41. package/src/__tests__/logger.service.spec.mts +147 -0
  42. package/src/__tests__/responders.spec.mts +6 -5
  43. package/src/factories/adapter.factory.mts +20 -0
  44. package/src/factories/endpoint-adapter.factory.mts +1 -1
  45. package/src/factories/http-adapter.factory.mts +1 -1
  46. package/src/factories/index.mts +1 -0
  47. package/src/factories/multipart-adapter.factory.mts +1 -1
  48. package/src/factories/reply.factory.mts +1 -1
  49. package/src/factories/request.factory.mts +1 -1
  50. package/src/factories/stream-adapter.factory.mts +1 -1
  51. package/src/factories/xml-stream-adapter.factory.mts +1 -1
  52. package/src/index.mts +1 -0
  53. package/src/interfaces/abstract-adapter.interface.mts +32 -0
  54. package/src/interfaces/abstract-http-adapter.interface.mts +27 -20
  55. package/src/interfaces/abstract-http-handler-adapter.interface.mts +86 -2
  56. package/src/interfaces/adapter-environment.interface.mts +74 -0
  57. package/src/interfaces/index.mts +2 -0
  58. package/src/interfaces/plugin.interface.mts +50 -16
  59. package/src/legacy-compat/attribute.factory.mts +2 -2
  60. package/src/legacy-compat/decorators/controller.decorator.mts +1 -1
  61. package/src/legacy-compat/decorators/endpoint.decorator.mts +1 -1
  62. package/src/legacy-compat/decorators/header.decorator.mts +2 -1
  63. package/src/legacy-compat/decorators/http-code.decorator.mts +2 -1
  64. package/src/legacy-compat/decorators/index.mts +2 -2
  65. package/src/legacy-compat/decorators/module.decorator.mts +1 -1
  66. package/src/legacy-compat/decorators/multipart.decorator.mts +1 -1
  67. package/src/legacy-compat/decorators/stream.decorator.mts +1 -1
  68. package/src/legacy-compat/decorators/use-guards.decorator.mts +1 -1
  69. package/src/legacy-compat/index.mts +10 -5
  70. package/src/logger/console-logger.service.mts +97 -7
  71. package/src/metadata/module.metadata.mts +43 -0
  72. package/src/navios.application.mts +172 -60
  73. package/src/navios.environment.mts +22 -12
  74. package/src/navios.factory.mts +31 -10
  75. package/src/services/abstract-handler-adapter.service.mts +366 -0
  76. package/src/services/index.mts +1 -0
  77. package/src/services/module-loader.service.mts +1 -0
  78. package/src/tokens/adapter.token.mts +6 -0
  79. package/src/tokens/http-adapter.token.mts +1 -1
  80. package/src/tokens/index.mts +1 -0
  81. package/src/utils/adapter-supports.util.mts +47 -0
  82. package/src/utils/index.mts +1 -0
  83. package/lib/index-BJjk2X1S.d.mts.map +0 -1
  84. package/lib/index-DZ6NU03y.d.cts.map +0 -1
  85. package/lib/src-C46ePe3d.cjs +0 -8022
  86. package/lib/src-C46ePe3d.cjs.map +0 -1
  87. package/lib/src-K2k0riYJ.mjs +0 -7587
  88. package/lib/src-K2k0riYJ.mjs.map +0 -1
  89. package/lib/use-guards.decorator-B6tghdxM.cjs.map +0 -1
  90. package/lib/use-guards.decorator-Be_QUx6b.mjs.map +0 -1
  91. package/src/legacy-compat/context-compat.mts +0 -95
  92. package/src/legacy-compat/decorators/factory.decorator.mts +0 -37
  93. package/src/legacy-compat/decorators/injectable.decorator.mts +0 -41
@@ -0,0 +1,399 @@
1
+ import type { ScopedContainer } from '@navios/di'
2
+
3
+ import { Container, Injectable, InjectionToken } from '@navios/di'
4
+
5
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
6
+
7
+ import type {
8
+ AbstractExecutionContext,
9
+ CanActivate,
10
+ } from '../interfaces/index.mjs'
11
+ import type {
12
+ ControllerMetadata,
13
+ HandlerMetadata,
14
+ ModuleMetadata,
15
+ } from '../metadata/index.mjs'
16
+
17
+ import { HttpException } from '../exceptions/index.mjs'
18
+ import { LoggerOutput } from '../logger/logger.tokens.mjs'
19
+ import {
20
+ ForbiddenResponderToken,
21
+ InternalServerErrorResponderToken,
22
+ NotFoundResponderToken,
23
+ ValidationErrorResponderToken,
24
+ } from '../responders/tokens/responder.tokens.mjs'
25
+ import { GuardRunnerService } from '../services/guard-runner.service.mjs'
26
+
27
+ // Mock responders
28
+ const createMockResponder = (statusCode: number, message: string) => ({
29
+ getResponse: vi.fn().mockReturnValue({
30
+ statusCode,
31
+ payload: { message },
32
+ headers: { 'content-type': 'application/problem+json' },
33
+ }),
34
+ })
35
+
36
+ // Mock logger output
37
+ const mockLoggerOutput = {
38
+ log: vi.fn(),
39
+ error: vi.fn(),
40
+ warn: vi.fn(),
41
+ debug: vi.fn(),
42
+ verbose: vi.fn(),
43
+ fatal: vi.fn(),
44
+ }
45
+
46
+ // Mock execution context
47
+ const createMockExecutionContext = (): AbstractExecutionContext => {
48
+ const mockReply = {
49
+ status: vi.fn().mockReturnThis(),
50
+ send: vi.fn().mockReturnThis(),
51
+ }
52
+ return {
53
+ getRequest: vi.fn().mockReturnValue({}),
54
+ getReply: vi.fn().mockReturnValue(mockReply),
55
+ getHandler: vi.fn(),
56
+ getModule: vi.fn(),
57
+ getController: vi.fn(),
58
+ }
59
+ }
60
+
61
+ // Mock guard
62
+ const createMockGuard = (
63
+ canActivateResult: boolean | Promise<boolean>,
64
+ ): CanActivate => ({
65
+ canActivate: vi.fn().mockImplementation(() => canActivateResult),
66
+ })
67
+
68
+ describe('GuardRunnerService', () => {
69
+ let container: Container
70
+ let mockForbiddenResponder: ReturnType<typeof createMockResponder>
71
+ let mockInternalErrorResponder: ReturnType<typeof createMockResponder>
72
+ let mockNotFoundResponder: ReturnType<typeof createMockResponder>
73
+ let mockValidationErrorResponder: ReturnType<typeof createMockResponder>
74
+
75
+ beforeEach(() => {
76
+ container = new Container()
77
+ vi.clearAllMocks()
78
+
79
+ // Create mock responders
80
+ mockForbiddenResponder = createMockResponder(403, 'Forbidden')
81
+ mockInternalErrorResponder = createMockResponder(
82
+ 500,
83
+ 'Internal Server Error',
84
+ )
85
+ mockNotFoundResponder = createMockResponder(404, 'Not Found')
86
+ mockValidationErrorResponder = createMockResponder(400, 'Validation Error')
87
+
88
+ // Register all required dependencies
89
+ container.addInstance(ForbiddenResponderToken, mockForbiddenResponder)
90
+ container.addInstance(
91
+ InternalServerErrorResponderToken,
92
+ mockInternalErrorResponder,
93
+ )
94
+ container.addInstance(NotFoundResponderToken, mockNotFoundResponder)
95
+ container.addInstance(
96
+ ValidationErrorResponderToken,
97
+ mockValidationErrorResponder,
98
+ )
99
+ container.addInstance(LoggerOutput, mockLoggerOutput)
100
+ })
101
+
102
+ afterEach(async () => {
103
+ await container.dispose()
104
+ })
105
+
106
+ describe('runGuardsStatic', () => {
107
+ it('should return true when all guards pass', async () => {
108
+ const service = await container.get(GuardRunnerService)
109
+ const guards = [createMockGuard(true), createMockGuard(true)]
110
+ const context = createMockExecutionContext()
111
+
112
+ const result = await service.runGuardsStatic(guards, context)
113
+
114
+ expect(result).toBe(true)
115
+ expect(guards[0].canActivate).toHaveBeenCalledWith(context)
116
+ expect(guards[1].canActivate).toHaveBeenCalledWith(context)
117
+ })
118
+
119
+ it('should return false when a guard returns false', async () => {
120
+ const service = await container.get(GuardRunnerService)
121
+ const guards = [createMockGuard(true), createMockGuard(false)]
122
+ const context = createMockExecutionContext()
123
+
124
+ const result = await service.runGuardsStatic(guards, context)
125
+
126
+ expect(result).toBe(false)
127
+ expect(context.getReply().status).toHaveBeenCalledWith(403)
128
+ })
129
+
130
+ it('should stop execution when a guard fails', async () => {
131
+ const service = await container.get(GuardRunnerService)
132
+ const firstGuard = createMockGuard(false)
133
+ const secondGuard = createMockGuard(true)
134
+ const guards = [firstGuard, secondGuard]
135
+ const context = createMockExecutionContext()
136
+
137
+ await service.runGuardsStatic(guards, context)
138
+
139
+ expect(firstGuard.canActivate).toHaveBeenCalled()
140
+ expect(secondGuard.canActivate).not.toHaveBeenCalled()
141
+ })
142
+
143
+ it('should handle HttpException from guard', async () => {
144
+ const service = await container.get(GuardRunnerService)
145
+ const httpException = new HttpException(401, 'Unauthorized')
146
+ const guard = {
147
+ canActivate: vi.fn().mockRejectedValue(httpException),
148
+ }
149
+ const context = createMockExecutionContext()
150
+
151
+ const result = await service.runGuardsStatic([guard], context)
152
+
153
+ expect(result).toBe(false)
154
+ expect(context.getReply().status).toHaveBeenCalledWith(401)
155
+ expect(context.getReply().send).toHaveBeenCalledWith('Unauthorized')
156
+ })
157
+
158
+ it('should handle unknown errors from guard', async () => {
159
+ const service = await container.get(GuardRunnerService)
160
+ const guard = {
161
+ canActivate: vi.fn().mockRejectedValue(new Error('Unknown error')),
162
+ }
163
+ const context = createMockExecutionContext()
164
+
165
+ const result = await service.runGuardsStatic([guard], context)
166
+
167
+ expect(result).toBe(false)
168
+ expect(mockLoggerOutput.error).toHaveBeenCalled()
169
+ expect(context.getReply().status).toHaveBeenCalledWith(500)
170
+ })
171
+
172
+ it('should handle async guards', async () => {
173
+ const service = await container.get(GuardRunnerService)
174
+ const asyncGuard = createMockGuard(Promise.resolve(true))
175
+ const context = createMockExecutionContext()
176
+
177
+ const result = await service.runGuardsStatic([asyncGuard], context)
178
+
179
+ expect(result).toBe(true)
180
+ })
181
+
182
+ it('should work with empty guard array', async () => {
183
+ const service = await container.get(GuardRunnerService)
184
+ const context = createMockExecutionContext()
185
+
186
+ const result = await service.runGuardsStatic([], context)
187
+
188
+ expect(result).toBe(true)
189
+ })
190
+ })
191
+
192
+ describe('runGuards', () => {
193
+ it('should resolve guards from scoped container', async () => {
194
+ @Injectable()
195
+ class TestGuard implements CanActivate {
196
+ canActivate = vi.fn().mockReturnValue(true)
197
+ }
198
+
199
+ const service = await container.get(GuardRunnerService)
200
+ const testGuardInstance = new TestGuard()
201
+
202
+ const mockScopedContainer = {
203
+ get: vi.fn().mockResolvedValue(testGuardInstance),
204
+ } as unknown as ScopedContainer
205
+
206
+ const guards = new Set([TestGuard])
207
+ const context = createMockExecutionContext()
208
+
209
+ const result = await service.runGuards(
210
+ guards,
211
+ context,
212
+ mockScopedContainer,
213
+ )
214
+
215
+ expect(result).toBe(true)
216
+ expect(mockScopedContainer.get).toHaveBeenCalled()
217
+ expect(testGuardInstance.canActivate).toHaveBeenCalledWith(context)
218
+ })
219
+
220
+ it('should throw error for guard without canActivate', async () => {
221
+ @Injectable()
222
+ class InvalidGuard {
223
+ // Missing canActivate
224
+ }
225
+
226
+ const service = await container.get(GuardRunnerService)
227
+ const mockScopedContainer = {
228
+ get: vi.fn().mockResolvedValue(new InvalidGuard()),
229
+ } as unknown as ScopedContainer
230
+
231
+ const guards = new Set([InvalidGuard as any])
232
+ const context = createMockExecutionContext()
233
+
234
+ await expect(
235
+ service.runGuards(guards, context, mockScopedContainer),
236
+ ).rejects.toThrow('does not implement canActivate')
237
+ })
238
+
239
+ it('should reverse guard order (module -> controller -> endpoint)', async () => {
240
+ const callOrder: string[] = []
241
+
242
+ @Injectable()
243
+ class Guard1 implements CanActivate {
244
+ canActivate() {
245
+ callOrder.push('guard1')
246
+ return true
247
+ }
248
+ }
249
+
250
+ @Injectable()
251
+ class Guard2 implements CanActivate {
252
+ canActivate() {
253
+ callOrder.push('guard2')
254
+ return true
255
+ }
256
+ }
257
+
258
+ @Injectable()
259
+ class Guard3 implements CanActivate {
260
+ canActivate() {
261
+ callOrder.push('guard3')
262
+ return true
263
+ }
264
+ }
265
+
266
+ const service = await container.get(GuardRunnerService)
267
+
268
+ const mockScopedContainer = {
269
+ get: vi.fn().mockImplementation((token) => {
270
+ if (token === Guard1) return new Guard1()
271
+ if (token === Guard2) return new Guard2()
272
+ if (token === Guard3) return new Guard3()
273
+ }),
274
+ } as unknown as ScopedContainer
275
+
276
+ // Order in Set: Guard1, Guard2, Guard3
277
+ // Should execute in reverse: Guard3, Guard2, Guard1
278
+ const guards = new Set([Guard1, Guard2, Guard3])
279
+ const context = createMockExecutionContext()
280
+
281
+ await service.runGuards(guards, context, mockScopedContainer)
282
+
283
+ expect(callOrder).toEqual(['guard3', 'guard2', 'guard1'])
284
+ })
285
+ })
286
+
287
+ describe('makeContext', () => {
288
+ it('should merge guards from module, controller, and endpoint', async () => {
289
+ const service = await container.get(GuardRunnerService)
290
+
291
+ class ModuleGuard {}
292
+ class ControllerGuard {}
293
+ class EndpointGuard {}
294
+
295
+ const moduleMetadata = {
296
+ guards: new Set([ModuleGuard]),
297
+ } as unknown as ModuleMetadata
298
+
299
+ const controllerMetadata = {
300
+ guards: new Set([ControllerGuard]),
301
+ } as unknown as ControllerMetadata
302
+
303
+ const endpointMetadata = {
304
+ guards: new Set([EndpointGuard]),
305
+ } as unknown as HandlerMetadata<any>
306
+
307
+ const result = service.makeContext(
308
+ moduleMetadata,
309
+ controllerMetadata,
310
+ endpointMetadata,
311
+ )
312
+
313
+ expect(result.size).toBe(3)
314
+ expect(result.has(ModuleGuard as any)).toBe(true)
315
+ expect(result.has(ControllerGuard as any)).toBe(true)
316
+ expect(result.has(EndpointGuard as any)).toBe(true)
317
+ })
318
+
319
+ it('should handle empty guards at each level', async () => {
320
+ const service = await container.get(GuardRunnerService)
321
+
322
+ const moduleMetadata = {
323
+ guards: new Set(),
324
+ } as unknown as ModuleMetadata
325
+
326
+ const controllerMetadata = {
327
+ guards: new Set(),
328
+ } as unknown as ControllerMetadata
329
+
330
+ const endpointMetadata = {
331
+ guards: new Set(),
332
+ } as unknown as HandlerMetadata<any>
333
+
334
+ const result = service.makeContext(
335
+ moduleMetadata,
336
+ controllerMetadata,
337
+ endpointMetadata,
338
+ )
339
+
340
+ expect(result.size).toBe(0)
341
+ })
342
+
343
+ it('should deduplicate guards', async () => {
344
+ const service = await container.get(GuardRunnerService)
345
+
346
+ class SharedGuard {}
347
+
348
+ const moduleMetadata = {
349
+ guards: new Set([SharedGuard]),
350
+ } as unknown as ModuleMetadata
351
+
352
+ const controllerMetadata = {
353
+ guards: new Set([SharedGuard]), // Same guard
354
+ } as unknown as ControllerMetadata
355
+
356
+ const endpointMetadata = {
357
+ guards: new Set([SharedGuard]), // Same guard
358
+ } as unknown as HandlerMetadata<any>
359
+
360
+ const result = service.makeContext(
361
+ moduleMetadata,
362
+ controllerMetadata,
363
+ endpointMetadata,
364
+ )
365
+
366
+ // Set deduplicates automatically
367
+ expect(result.size).toBe(1)
368
+ })
369
+
370
+ it('should handle injection tokens as guards', async () => {
371
+ const service = await container.get(GuardRunnerService)
372
+
373
+ const GuardToken = InjectionToken.create<CanActivate>(
374
+ Symbol.for('GuardToken'),
375
+ )
376
+
377
+ const moduleMetadata = {
378
+ guards: new Set([GuardToken]),
379
+ } as unknown as ModuleMetadata
380
+
381
+ const controllerMetadata = {
382
+ guards: new Set(),
383
+ } as unknown as ControllerMetadata
384
+
385
+ const endpointMetadata = {
386
+ guards: new Set(),
387
+ } as unknown as HandlerMetadata<any>
388
+
389
+ const result = service.makeContext(
390
+ moduleMetadata,
391
+ controllerMetadata,
392
+ endpointMetadata,
393
+ )
394
+
395
+ expect(result.size).toBe(1)
396
+ expect(result.has(GuardToken)).toBe(true)
397
+ })
398
+ })
399
+ })
@@ -0,0 +1,147 @@
1
+ import { Container } from '@navios/di'
2
+
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
4
+
5
+ import type { LoggerService } from '../index.mjs'
6
+
7
+ import { LoggerInstance } from '../logger/logger.service.mjs'
8
+ import { LoggerOutput } from '../logger/logger.tokens.mjs'
9
+
10
+ describe('LoggerInstance', () => {
11
+ let container: Container
12
+ let mockLoggerOutput: {
13
+ log: ReturnType<typeof vi.fn>
14
+ error: ReturnType<typeof vi.fn>
15
+ warn: ReturnType<typeof vi.fn>
16
+ debug: ReturnType<typeof vi.fn>
17
+ verbose: ReturnType<typeof vi.fn>
18
+ fatal: ReturnType<typeof vi.fn>
19
+ }
20
+
21
+ beforeEach(() => {
22
+ container = new Container()
23
+ mockLoggerOutput = {
24
+ log: vi.fn(),
25
+ error: vi.fn(),
26
+ warn: vi.fn(),
27
+ debug: vi.fn(),
28
+ verbose: vi.fn(),
29
+ fatal: vi.fn(),
30
+ }
31
+ })
32
+
33
+ afterEach(async () => {
34
+ await container.dispose()
35
+ })
36
+
37
+ describe('log', () => {
38
+ it('should call localInstance.log with message', async () => {
39
+ container.addInstance(LoggerOutput, mockLoggerOutput as LoggerService)
40
+ const logger = await container.get(LoggerInstance)
41
+
42
+ logger.log('Test message')
43
+
44
+ expect(mockLoggerOutput.log).toHaveBeenCalledWith('Test message')
45
+ })
46
+ })
47
+
48
+ describe('error', () => {
49
+ it('should call localInstance.error with message', async () => {
50
+ container.addInstance(LoggerOutput, mockLoggerOutput as LoggerService)
51
+ const logger = await container.get(LoggerInstance)
52
+
53
+ logger.error('Error message')
54
+
55
+ expect(mockLoggerOutput.error).toHaveBeenCalledWith('Error message')
56
+ })
57
+ })
58
+
59
+ describe('warn', () => {
60
+ it('should call localInstance.warn with message', async () => {
61
+ container.addInstance(LoggerOutput, mockLoggerOutput as LoggerService)
62
+ const logger = await container.get(LoggerInstance)
63
+
64
+ logger.warn('Warning message')
65
+
66
+ expect(mockLoggerOutput.warn).toHaveBeenCalledWith('Warning message')
67
+ })
68
+ })
69
+
70
+ describe('debug', () => {
71
+ it('should call localInstance.debug with message', async () => {
72
+ container.addInstance(LoggerOutput, mockLoggerOutput as LoggerService)
73
+ const logger = await container.get(LoggerInstance)
74
+
75
+ logger.debug('Debug message')
76
+
77
+ expect(mockLoggerOutput.debug).toHaveBeenCalledWith('Debug message')
78
+ })
79
+
80
+ it('should handle missing debug method gracefully', async () => {
81
+ const loggerWithoutDebug = {
82
+ log: vi.fn(),
83
+ error: vi.fn(),
84
+ warn: vi.fn(),
85
+ // No debug method
86
+ }
87
+
88
+ container.addInstance(LoggerOutput, loggerWithoutDebug as LoggerService)
89
+ const logger = await container.get(LoggerInstance)
90
+
91
+ // Should not throw
92
+ expect(() => logger.debug('Debug message')).not.toThrow()
93
+ })
94
+ })
95
+
96
+ describe('verbose', () => {
97
+ it('should call localInstance.verbose with message', async () => {
98
+ container.addInstance(LoggerOutput, mockLoggerOutput as LoggerService)
99
+ const logger = await container.get(LoggerInstance)
100
+
101
+ logger.verbose('Verbose message')
102
+
103
+ expect(mockLoggerOutput.verbose).toHaveBeenCalledWith('Verbose message')
104
+ })
105
+
106
+ it('should handle missing verbose method gracefully', async () => {
107
+ const loggerWithoutVerbose = {
108
+ log: vi.fn(),
109
+ error: vi.fn(),
110
+ warn: vi.fn(),
111
+ // No verbose method
112
+ }
113
+
114
+ container.addInstance(LoggerOutput, loggerWithoutVerbose as LoggerService)
115
+ const logger = await container.get(LoggerInstance)
116
+
117
+ // Should not throw
118
+ expect(() => logger.verbose('Verbose message')).not.toThrow()
119
+ })
120
+ })
121
+
122
+ describe('fatal', () => {
123
+ it('should call localInstance.fatal with message', async () => {
124
+ container.addInstance(LoggerOutput, mockLoggerOutput as LoggerService)
125
+ const logger = await container.get(LoggerInstance)
126
+
127
+ logger.fatal('Fatal message')
128
+
129
+ expect(mockLoggerOutput.fatal).toHaveBeenCalledWith('Fatal message')
130
+ })
131
+
132
+ it('should handle missing fatal method gracefully', async () => {
133
+ const loggerWithoutFatal = {
134
+ log: vi.fn(),
135
+ error: vi.fn(),
136
+ warn: vi.fn(),
137
+ // No fatal method
138
+ }
139
+
140
+ container.addInstance(LoggerOutput, loggerWithoutFatal as LoggerService)
141
+ const logger = await container.get(LoggerInstance)
142
+
143
+ // Should not throw
144
+ expect(() => logger.fatal('Fatal message')).not.toThrow()
145
+ })
146
+ })
147
+ })
@@ -9,10 +9,11 @@ import type { ErrorResponse } from '../responders/interfaces/error-response.inte
9
9
  import { NotFoundException } from '../exceptions/not-found.exception.mjs'
10
10
  import { FrameworkError } from '../responders/enums/framework-error.enum.mjs'
11
11
  import { ErrorResponseProducerService } from '../responders/services/error-response-producer.service.mjs'
12
- import { ForbiddenResponderService } from '../responders/services/forbidden-responder.service.mjs'
13
- import { InternalServerErrorResponderService } from '../responders/services/internal-server-error-responder.service.mjs'
14
- import { NotFoundResponderService } from '../responders/services/not-found-responder.service.mjs'
15
- import { ValidationErrorResponderService } from '../responders/services/validation-error-responder.service.mjs'
12
+ // Import services for side-effects (registers @Injectable decorators)
13
+ import '../responders/services/forbidden-responder.service.mjs'
14
+ import '../responders/services/internal-server-error-responder.service.mjs'
15
+ import '../responders/services/not-found-responder.service.mjs'
16
+ import '../responders/services/validation-error-responder.service.mjs'
16
17
  import {
17
18
  ForbiddenResponderToken,
18
19
  InternalServerErrorResponderToken,
@@ -309,7 +310,7 @@ describe('Responders', () => {
309
310
  token: NotFoundResponderToken,
310
311
  priority: 0, // Higher than default -10
311
312
  })
312
- class CustomNotFoundResponder implements ErrorResponder {
313
+ class _CustomNotFoundResponder implements ErrorResponder {
313
314
  getResponse(_error: unknown, description?: string): ErrorResponse {
314
315
  return {
315
316
  statusCode: 404,
@@ -0,0 +1,20 @@
1
+ import type { FactoryContext } from '@navios/di'
2
+
3
+ import { Factory, inject, InjectionToken } from '@navios/di'
4
+
5
+ import { NaviosEnvironment } from '../navios.environment.mjs'
6
+ import { AdapterToken } from '../tokens/index.mjs'
7
+
8
+ @Factory({
9
+ token: AdapterToken,
10
+ })
11
+ export class AdapterFactory {
12
+ private readonly environment = inject(NaviosEnvironment)
13
+ create(ctx: FactoryContext) {
14
+ const service = this.environment.getToken(AdapterToken)
15
+ if (!service) {
16
+ throw new Error('AdapterToken service not found in environment')
17
+ }
18
+ return ctx.inject(service as InjectionToken<any, undefined>)
19
+ }
20
+ }
@@ -12,7 +12,7 @@ export class EndpointAdapterFactory {
12
12
  private readonly environment = inject(NaviosEnvironment)
13
13
 
14
14
  create(ctx: FactoryContext) {
15
- const service = this.environment.getHttpToken(EndpointAdapterToken)
15
+ const service = this.environment.getToken(EndpointAdapterToken)
16
16
  if (!service) {
17
17
  throw new Error('EndpointAdapterToken service not found in environment')
18
18
  }
@@ -11,7 +11,7 @@ import { HttpAdapterToken } from '../tokens/index.mjs'
11
11
  export class HttpAdapterFactory {
12
12
  private readonly environment = inject(NaviosEnvironment)
13
13
  create(ctx: FactoryContext) {
14
- const service = this.environment.getHttpToken(HttpAdapterToken)
14
+ const service = this.environment.getToken(HttpAdapterToken)
15
15
  if (!service) {
16
16
  throw new Error('HttpAdapterToken service not found in environment')
17
17
  }
@@ -1,3 +1,4 @@
1
+ export * from './adapter.factory.mjs'
1
2
  export * from './endpoint-adapter.factory.mjs'
2
3
  export * from './http-adapter.factory.mjs'
3
4
  export * from './multipart-adapter.factory.mjs'
@@ -12,7 +12,7 @@ export class MultipartAdapterFactory {
12
12
  private readonly environment = inject(NaviosEnvironment)
13
13
 
14
14
  create(ctx: FactoryContext) {
15
- const service = this.environment.getHttpToken(MultipartAdapterToken)
15
+ const service = this.environment.getToken(MultipartAdapterToken)
16
16
  if (!service) {
17
17
  throw new Error('MultipartAdapterToken service not found in environment')
18
18
  }
@@ -12,7 +12,7 @@ import { Reply } from '../tokens/index.mjs'
12
12
  export class ReplyFactory {
13
13
  private readonly environment = inject(NaviosEnvironment)
14
14
  create(ctx: FactoryContext) {
15
- const service = this.environment.getHttpToken(Reply)
15
+ const service = this.environment.getToken(Reply)
16
16
  if (!service) {
17
17
  throw new Error('ReplyToken service not found in environment')
18
18
  }
@@ -12,7 +12,7 @@ import { Request } from '../tokens/index.mjs'
12
12
  export class RequestFactory {
13
13
  private readonly environment = inject(NaviosEnvironment)
14
14
  create(ctx: FactoryContext) {
15
- const service = this.environment.getHttpToken(Request)
15
+ const service = this.environment.getToken(Request)
16
16
  if (!service) {
17
17
  throw new Error('RequestToken service not found in environment')
18
18
  }
@@ -11,7 +11,7 @@ import { StreamAdapterToken } from '../tokens/index.mjs'
11
11
  export class StreamAdapterFactory {
12
12
  private readonly environment = inject(NaviosEnvironment)
13
13
  create(ctx: FactoryContext) {
14
- const service = this.environment.getHttpToken(StreamAdapterToken)
14
+ const service = this.environment.getToken(StreamAdapterToken)
15
15
  if (!service) {
16
16
  throw new Error('StreamAdapterToken service not found in environment')
17
17
  }
@@ -11,7 +11,7 @@ import { XmlStreamAdapterToken } from '../tokens/index.mjs'
11
11
  export class XmlStreamAdapterFactory {
12
12
  private readonly environment = inject(NaviosEnvironment)
13
13
  create(ctx: FactoryContext) {
14
- const service = this.environment.getHttpToken(XmlStreamAdapterToken)
14
+ const service = this.environment.getToken(XmlStreamAdapterToken)
15
15
  if (!service) {
16
16
  throw new Error('XmlStreamAdapterToken service not found in environment')
17
17
  }
package/src/index.mts CHANGED
@@ -9,6 +9,7 @@ export * from './responders/index.mjs'
9
9
  export * from './services/index.mjs'
10
10
  export * from './stores/index.mjs'
11
11
  export * from './tokens/index.mjs'
12
+ export * from './utils/index.mjs'
12
13
  export * from './attribute.factory.mjs'
13
14
  export * from './factories/index.mjs'
14
15
  export * from './navios.application.mjs'