@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.
- package/CHANGELOG.md +78 -0
- package/lib/{index-DW9EPAE6.d.mts → index-D9MNh6Tx.d.mts} +534 -342
- package/lib/index-D9MNh6Tx.d.mts.map +1 -0
- package/lib/{index-pHp-dIGt.d.cts → index-Db1d3cwD.d.cts} +534 -342
- package/lib/index-Db1d3cwD.d.cts.map +1 -0
- package/lib/index.cjs +12 -3
- package/lib/index.d.cts +2 -2
- package/lib/index.d.mts +2 -2
- package/lib/index.mjs +3 -3
- package/lib/legacy-compat/index.cjs +1 -1
- package/lib/legacy-compat/index.cjs.map +1 -1
- package/lib/legacy-compat/index.d.cts +3 -3
- package/lib/legacy-compat/index.d.cts.map +1 -1
- package/lib/legacy-compat/index.d.mts +3 -3
- package/lib/legacy-compat/index.d.mts.map +1 -1
- package/lib/legacy-compat/index.mjs +1 -1
- package/lib/legacy-compat/index.mjs.map +1 -1
- package/lib/{src-QnxR5b7c.cjs → src-BRPtJ9fG.cjs} +474 -53
- package/lib/src-BRPtJ9fG.cjs.map +1 -0
- package/lib/{src-DyvCDuKO.mjs → src-Bo23RIo-.mjs} +454 -51
- package/lib/src-Bo23RIo-.mjs.map +1 -0
- package/lib/testing/index.cjs +346 -29
- package/lib/testing/index.cjs.map +1 -1
- package/lib/testing/index.d.cts +299 -63
- package/lib/testing/index.d.cts.map +1 -1
- package/lib/testing/index.d.mts +299 -63
- package/lib/testing/index.d.mts.map +1 -1
- package/lib/testing/index.mjs +347 -31
- package/lib/testing/index.mjs.map +1 -1
- package/lib/{use-guards.decorator-B6q_N0sf.cjs → use-guards.decorator-Bs8oDHOi.cjs} +29 -99
- package/lib/use-guards.decorator-Bs8oDHOi.cjs.map +1 -0
- package/lib/{use-guards.decorator-kZ3lNK8v.mjs → use-guards.decorator-CzVXuLkz.mjs} +23 -99
- package/lib/use-guards.decorator-CzVXuLkz.mjs.map +1 -0
- package/package.json +4 -4
- package/src/__tests__/controller-resolver.spec.mts +229 -0
- package/src/__tests__/controller.spec.mts +1 -1
- package/src/__tests__/testing-module.spec.mts +459 -0
- package/src/__tests__/unit-testing-module.spec.mts +424 -0
- package/src/decorators/controller.decorator.mts +29 -7
- package/src/decorators/endpoint.decorator.mts +60 -12
- package/src/decorators/module.decorator.mts +23 -5
- package/src/decorators/multipart.decorator.mts +67 -24
- package/src/decorators/stream.decorator.mts +65 -24
- package/src/interfaces/abstract-http-handler-adapter.interface.mts +31 -1
- package/src/legacy-compat/__type-tests__/legacy-decorators.spec-d.mts +2 -6
- package/src/legacy-compat/decorators/endpoint.decorator.mts +1 -1
- package/src/legacy-compat/decorators/multipart.decorator.mts +5 -5
- package/src/legacy-compat/decorators/stream.decorator.mts +5 -5
- package/src/logger/logger.service.mts +0 -2
- package/src/navios.application.mts +23 -9
- package/src/navios.environment.mts +3 -1
- package/src/navios.factory.mts +19 -18
- package/src/services/guard-runner.service.mts +46 -9
- package/src/services/index.mts +1 -0
- package/src/services/instance-resolver.service.mts +187 -0
- package/src/services/module-loader.service.mts +3 -2
- package/src/stores/request-id.store.mts +45 -3
- package/src/testing/index.mts +1 -0
- package/src/testing/testing-module.mts +255 -93
- package/src/testing/unit-testing-module.mts +298 -0
- package/src/tokens/index.mts +1 -0
- package/src/tokens/navios-options.token.mts +6 -0
- package/lib/index-DW9EPAE6.d.mts.map +0 -1
- package/lib/index-pHp-dIGt.d.cts.map +0 -1
- package/lib/src-DyvCDuKO.mjs.map +0 -1
- package/lib/src-QnxR5b7c.cjs.map +0 -1
- package/lib/use-guards.decorator-B6q_N0sf.cjs.map +0 -1
- 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,
|
|
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({
|
|
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
|
-
|
|
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
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
{
|
|
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
|
}
|