@navios/core 0.5.1 → 0.7.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 (277) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.md +18 -1
  3. package/docs/README.md +1 -0
  4. package/docs/legacy-compat.md +320 -0
  5. package/docs/testing.md +140 -17
  6. package/lib/index-BFwNx9WQ.d.cts +1951 -0
  7. package/lib/index-BFwNx9WQ.d.cts.map +1 -0
  8. package/lib/index-D657ijFO.d.mts +1951 -0
  9. package/lib/index-D657ijFO.d.mts.map +1 -0
  10. package/lib/index.cjs +157 -0
  11. package/lib/index.d.cts +3 -0
  12. package/lib/index.d.mts +3 -188
  13. package/lib/index.mjs +4 -1439
  14. package/lib/legacy-compat/index.cjs +315 -0
  15. package/lib/legacy-compat/index.cjs.map +1 -0
  16. package/lib/legacy-compat/index.d.cts +219 -0
  17. package/lib/legacy-compat/index.d.cts.map +1 -0
  18. package/lib/legacy-compat/index.d.mts +219 -0
  19. package/lib/legacy-compat/index.d.mts.map +1 -0
  20. package/lib/legacy-compat/index.mjs +308 -0
  21. package/lib/legacy-compat/index.mjs.map +1 -0
  22. package/lib/src-Cb1aTjl0.cjs +5710 -0
  23. package/lib/src-Cb1aTjl0.cjs.map +1 -0
  24. package/lib/src-DzPY5s6d.mjs +5353 -0
  25. package/lib/src-DzPY5s6d.mjs.map +1 -0
  26. package/lib/testing/index.cjs +106 -0
  27. package/lib/testing/index.cjs.map +1 -0
  28. package/lib/testing/index.d.cts +156 -0
  29. package/lib/testing/index.d.cts.map +1 -0
  30. package/lib/testing/index.d.mts +156 -0
  31. package/lib/testing/index.d.mts.map +1 -0
  32. package/lib/testing/index.mjs +100 -0
  33. package/lib/testing/index.mjs.map +1 -0
  34. package/lib/use-guards.decorator-DdvUhB03.cjs +622 -0
  35. package/lib/use-guards.decorator-DdvUhB03.cjs.map +1 -0
  36. package/lib/use-guards.decorator-kZ3lNK8v.mjs +454 -0
  37. package/lib/use-guards.decorator-kZ3lNK8v.mjs.map +1 -0
  38. package/package.json +26 -6
  39. package/project.json +2 -2
  40. package/src/attribute.factory.d.mts +175 -0
  41. package/src/attribute.factory.d.mts.map +1 -0
  42. package/src/attribute.factory.mts +154 -0
  43. package/src/config/config-service.interface.d.mts +39 -0
  44. package/src/config/config-service.interface.d.mts.map +1 -0
  45. package/src/config/config-service.interface.mts +31 -0
  46. package/src/config/config.provider.d.mts +46 -0
  47. package/src/config/config.provider.d.mts.map +1 -0
  48. package/src/config/config.provider.mts +36 -0
  49. package/src/config/config.service.d.mts +108 -0
  50. package/src/config/config.service.d.mts.map +1 -0
  51. package/src/config/config.service.mts +94 -4
  52. package/src/config/index.d.mts +6 -0
  53. package/src/config/index.d.mts.map +1 -0
  54. package/src/config/types.d.mts +13 -0
  55. package/src/config/types.d.mts.map +1 -0
  56. package/src/config/utils/helpers.d.mts +3 -0
  57. package/src/config/utils/helpers.d.mts.map +1 -0
  58. package/src/config/utils/index.d.mts +2 -0
  59. package/src/config/utils/index.d.mts.map +1 -0
  60. package/src/decorators/controller.decorator.d.mts +33 -0
  61. package/src/decorators/controller.decorator.d.mts.map +1 -0
  62. package/src/decorators/controller.decorator.mts +28 -0
  63. package/src/decorators/endpoint.decorator.d.mts +89 -0
  64. package/src/decorators/endpoint.decorator.d.mts.map +1 -0
  65. package/src/decorators/endpoint.decorator.mts +76 -0
  66. package/src/decorators/header.decorator.d.mts +22 -0
  67. package/src/decorators/header.decorator.d.mts.map +1 -0
  68. package/src/decorators/header.decorator.mts +19 -0
  69. package/src/decorators/http-code.decorator.d.mts +22 -0
  70. package/src/decorators/http-code.decorator.d.mts.map +1 -0
  71. package/src/decorators/http-code.decorator.mts +20 -0
  72. package/src/decorators/index.d.mts +9 -0
  73. package/src/decorators/index.d.mts.map +1 -0
  74. package/src/decorators/module.decorator.d.mts +42 -0
  75. package/src/decorators/module.decorator.d.mts.map +1 -0
  76. package/src/decorators/module.decorator.mts +34 -0
  77. package/src/decorators/multipart.decorator.d.mts +54 -0
  78. package/src/decorators/multipart.decorator.d.mts.map +1 -0
  79. package/src/decorators/multipart.decorator.mts +41 -0
  80. package/src/decorators/stream.decorator.d.mts +42 -0
  81. package/src/decorators/stream.decorator.d.mts.map +1 -0
  82. package/src/decorators/stream.decorator.mts +33 -0
  83. package/src/decorators/use-guards.decorator.d.mts +33 -0
  84. package/src/decorators/use-guards.decorator.d.mts.map +1 -0
  85. package/src/decorators/use-guards.decorator.mts +29 -0
  86. package/src/exceptions/bad-request.exception.d.mts +26 -0
  87. package/src/exceptions/bad-request.exception.d.mts.map +1 -0
  88. package/src/exceptions/bad-request.exception.mts +21 -0
  89. package/src/exceptions/conflict.exception.d.mts +29 -0
  90. package/src/exceptions/conflict.exception.d.mts.map +1 -0
  91. package/src/exceptions/conflict.exception.mts +24 -0
  92. package/src/exceptions/forbidden.exception.d.mts +28 -0
  93. package/src/exceptions/forbidden.exception.d.mts.map +1 -0
  94. package/src/exceptions/forbidden.exception.mts +23 -0
  95. package/src/exceptions/http.exception.d.mts +33 -0
  96. package/src/exceptions/http.exception.d.mts.map +1 -0
  97. package/src/exceptions/http.exception.mts +26 -0
  98. package/src/exceptions/index.d.mts +8 -0
  99. package/src/exceptions/index.d.mts.map +1 -0
  100. package/src/exceptions/internal-server-error.exception.d.mts +31 -0
  101. package/src/exceptions/internal-server-error.exception.d.mts.map +1 -0
  102. package/src/exceptions/internal-server-error.exception.mts +26 -0
  103. package/src/exceptions/not-found.exception.d.mts +30 -0
  104. package/src/exceptions/not-found.exception.d.mts.map +1 -0
  105. package/src/exceptions/not-found.exception.mts +23 -0
  106. package/src/exceptions/unauthorized.exception.d.mts +28 -0
  107. package/src/exceptions/unauthorized.exception.d.mts.map +1 -0
  108. package/src/exceptions/unauthorized.exception.mts +23 -0
  109. package/src/factories/endpoint-adapter.factory.d.mts +6 -0
  110. package/src/factories/endpoint-adapter.factory.d.mts.map +1 -0
  111. package/src/factories/http-adapter.factory.d.mts +6 -0
  112. package/src/factories/http-adapter.factory.d.mts.map +1 -0
  113. package/src/factories/index.d.mts +8 -0
  114. package/src/factories/index.d.mts.map +1 -0
  115. package/src/factories/index.mts +1 -0
  116. package/src/factories/multipart-adapter.factory.d.mts +6 -0
  117. package/src/factories/multipart-adapter.factory.d.mts.map +1 -0
  118. package/src/factories/reply.factory.d.mts +6 -0
  119. package/src/factories/reply.factory.d.mts.map +1 -0
  120. package/src/factories/request.factory.d.mts +6 -0
  121. package/src/factories/request.factory.d.mts.map +1 -0
  122. package/src/factories/stream-adapter.factory.d.mts +6 -0
  123. package/src/factories/stream-adapter.factory.d.mts.map +1 -0
  124. package/src/factories/xml-stream-adapter.factory.d.mts +6 -0
  125. package/src/factories/xml-stream-adapter.factory.d.mts.map +1 -0
  126. package/src/factories/xml-stream-adapter.factory.mts +20 -0
  127. package/src/index.d.mts +15 -0
  128. package/src/index.d.mts.map +1 -0
  129. package/src/index.mts +1 -0
  130. package/src/interfaces/abstract-execution-context.inteface.d.mts +44 -0
  131. package/src/interfaces/abstract-execution-context.inteface.d.mts.map +1 -0
  132. package/src/interfaces/abstract-execution-context.inteface.mts +35 -0
  133. package/src/interfaces/abstract-http-adapter.interface.d.mts +15 -0
  134. package/src/interfaces/abstract-http-adapter.interface.d.mts.map +1 -0
  135. package/src/interfaces/abstract-http-cors-options.interface.d.mts +58 -0
  136. package/src/interfaces/abstract-http-cors-options.interface.d.mts.map +1 -0
  137. package/src/interfaces/abstract-http-handler-adapter.interface.d.mts +7 -0
  138. package/src/interfaces/abstract-http-handler-adapter.interface.d.mts.map +1 -0
  139. package/src/interfaces/abstract-http-handler-adapter.interface.mts +2 -2
  140. package/src/interfaces/abstract-http-listen-options.interface.d.mts +5 -0
  141. package/src/interfaces/abstract-http-listen-options.interface.d.mts.map +1 -0
  142. package/src/interfaces/can-activate.d.mts +36 -0
  143. package/src/interfaces/can-activate.d.mts.map +1 -0
  144. package/src/interfaces/can-activate.mts +31 -0
  145. package/src/interfaces/http-header.d.mts +10 -0
  146. package/src/interfaces/http-header.d.mts.map +1 -0
  147. package/src/interfaces/index.d.mts +9 -0
  148. package/src/interfaces/index.d.mts.map +1 -0
  149. package/src/interfaces/navios-module.d.mts +29 -0
  150. package/src/interfaces/navios-module.d.mts.map +1 -0
  151. package/src/interfaces/navios-module.mts +25 -0
  152. package/src/legacy-compat/__type-tests__/legacy-decorators.spec-d.mts +420 -0
  153. package/src/legacy-compat/__type-tests__/tsconfig.json +15 -0
  154. package/src/legacy-compat/context-compat.d.mts +19 -0
  155. package/src/legacy-compat/context-compat.d.mts.map +1 -0
  156. package/src/legacy-compat/context-compat.mts +93 -0
  157. package/src/legacy-compat/decorators/controller.decorator.d.mts +21 -0
  158. package/src/legacy-compat/decorators/controller.decorator.d.mts.map +1 -0
  159. package/src/legacy-compat/decorators/controller.decorator.mts +31 -0
  160. package/src/legacy-compat/decorators/endpoint.decorator.d.mts +33 -0
  161. package/src/legacy-compat/decorators/endpoint.decorator.d.mts.map +1 -0
  162. package/src/legacy-compat/decorators/endpoint.decorator.mts +99 -0
  163. package/src/legacy-compat/decorators/header.decorator.d.mts +24 -0
  164. package/src/legacy-compat/decorators/header.decorator.d.mts.map +1 -0
  165. package/src/legacy-compat/decorators/header.decorator.mts +42 -0
  166. package/src/legacy-compat/decorators/http-code.decorator.d.mts +22 -0
  167. package/src/legacy-compat/decorators/http-code.decorator.d.mts.map +1 -0
  168. package/src/legacy-compat/decorators/http-code.decorator.mts +38 -0
  169. package/src/legacy-compat/decorators/index.d.mts +9 -0
  170. package/src/legacy-compat/decorators/index.d.mts.map +1 -0
  171. package/src/legacy-compat/decorators/index.mts +9 -0
  172. package/src/legacy-compat/decorators/module.decorator.d.mts +22 -0
  173. package/src/legacy-compat/decorators/module.decorator.d.mts.map +1 -0
  174. package/src/legacy-compat/decorators/module.decorator.mts +37 -0
  175. package/src/legacy-compat/decorators/multipart.decorator.d.mts +34 -0
  176. package/src/legacy-compat/decorators/multipart.decorator.d.mts.map +1 -0
  177. package/src/legacy-compat/decorators/multipart.decorator.mts +93 -0
  178. package/src/legacy-compat/decorators/stream.decorator.d.mts +34 -0
  179. package/src/legacy-compat/decorators/stream.decorator.d.mts.map +1 -0
  180. package/src/legacy-compat/decorators/stream.decorator.mts +76 -0
  181. package/src/legacy-compat/decorators/use-guards.decorator.d.mts +29 -0
  182. package/src/legacy-compat/decorators/use-guards.decorator.d.mts.map +1 -0
  183. package/src/legacy-compat/decorators/use-guards.decorator.mts +80 -0
  184. package/src/legacy-compat/index.d.mts +19 -0
  185. package/src/legacy-compat/index.d.mts.map +1 -0
  186. package/src/legacy-compat/index.mts +40 -0
  187. package/src/logger/console-logger.service.d.mts +196 -0
  188. package/src/logger/console-logger.service.d.mts.map +1 -0
  189. package/src/logger/console-logger.service.mts +15 -2
  190. package/src/logger/index.d.mts +7 -0
  191. package/src/logger/index.d.mts.map +1 -0
  192. package/src/logger/log-levels.d.mts +14 -0
  193. package/src/logger/log-levels.d.mts.map +1 -0
  194. package/src/logger/log-levels.mts +9 -0
  195. package/src/logger/logger-service.interface.d.mts +36 -0
  196. package/src/logger/logger-service.interface.d.mts.map +1 -0
  197. package/src/logger/logger.service.d.mts +57 -0
  198. package/src/logger/logger.service.d.mts.map +1 -0
  199. package/src/logger/logger.service.mts +19 -0
  200. package/src/logger/logger.tokens.d.mts +36 -0
  201. package/src/logger/logger.tokens.d.mts.map +1 -0
  202. package/src/logger/logger.tokens.mts +23 -0
  203. package/src/logger/utils/cli-colors.util.d.mts +10 -0
  204. package/src/logger/utils/cli-colors.util.d.mts.map +1 -0
  205. package/src/logger/utils/filter-log-levelts.util.d.mts +6 -0
  206. package/src/logger/utils/filter-log-levelts.util.d.mts.map +1 -0
  207. package/src/logger/utils/index.d.mts +6 -0
  208. package/src/logger/utils/index.d.mts.map +1 -0
  209. package/src/logger/utils/is-log-level-enabled.d.mts +8 -0
  210. package/src/logger/utils/is-log-level-enabled.d.mts.map +1 -0
  211. package/src/logger/utils/is-log-level.util.d.mts +6 -0
  212. package/src/logger/utils/is-log-level.util.d.mts.map +1 -0
  213. package/src/logger/utils/shared.utils.d.mts +14 -0
  214. package/src/logger/utils/shared.utils.d.mts.map +1 -0
  215. package/src/metadata/controller.metadata.d.mts +13 -0
  216. package/src/metadata/controller.metadata.d.mts.map +1 -0
  217. package/src/metadata/handler.metadata.d.mts +18 -0
  218. package/src/metadata/handler.metadata.d.mts.map +1 -0
  219. package/src/metadata/index.d.mts +4 -0
  220. package/src/metadata/index.d.mts.map +1 -0
  221. package/src/metadata/module.metadata.d.mts +13 -0
  222. package/src/metadata/module.metadata.d.mts.map +1 -0
  223. package/src/navios.application.d.mts +210 -0
  224. package/src/navios.application.d.mts.map +1 -0
  225. package/src/navios.application.mts +176 -2
  226. package/src/navios.environment.d.mts +11 -0
  227. package/src/navios.environment.d.mts.map +1 -0
  228. package/src/navios.factory.d.mts +68 -0
  229. package/src/navios.factory.d.mts.map +1 -0
  230. package/src/navios.factory.mts +59 -1
  231. package/src/services/guard-runner.service.d.mts +10 -0
  232. package/src/services/guard-runner.service.d.mts.map +1 -0
  233. package/src/services/guard-runner.service.mts +12 -11
  234. package/src/services/index.d.mts +3 -0
  235. package/src/services/index.d.mts.map +1 -0
  236. package/src/services/module-loader.service.d.mts +17 -0
  237. package/src/services/module-loader.service.d.mts.map +1 -0
  238. package/src/services/module-loader.service.mts +16 -11
  239. package/src/stores/index.d.mts +2 -0
  240. package/src/stores/index.d.mts.map +1 -0
  241. package/src/stores/index.mts +1 -0
  242. package/src/stores/request-id.store.d.mts +37 -0
  243. package/src/stores/request-id.store.d.mts.map +1 -0
  244. package/src/stores/request-id.store.mts +43 -0
  245. package/src/testing/index.mts +2 -0
  246. package/src/testing/testing-module.mts +231 -0
  247. package/src/tokens/endpoint-adapter.token.d.mts +4 -0
  248. package/src/tokens/endpoint-adapter.token.d.mts.map +1 -0
  249. package/src/tokens/execution-context.token.d.mts +5 -0
  250. package/src/tokens/execution-context.token.d.mts.map +1 -0
  251. package/src/tokens/http-adapter.token.d.mts +4 -0
  252. package/src/tokens/http-adapter.token.d.mts.map +1 -0
  253. package/src/tokens/index.d.mts +9 -0
  254. package/src/tokens/index.d.mts.map +1 -0
  255. package/src/tokens/index.mts +1 -0
  256. package/src/tokens/multipart-adapter.token.d.mts +4 -0
  257. package/src/tokens/multipart-adapter.token.d.mts.map +1 -0
  258. package/src/tokens/reply.token.d.mts +3 -0
  259. package/src/tokens/reply.token.d.mts.map +1 -0
  260. package/src/tokens/request.token.d.mts +3 -0
  261. package/src/tokens/request.token.d.mts.map +1 -0
  262. package/src/tokens/stream-adapter.token.d.mts +4 -0
  263. package/src/tokens/stream-adapter.token.d.mts.map +1 -0
  264. package/src/tokens/xml-stream-adapter.token.d.mts +4 -0
  265. package/src/tokens/xml-stream-adapter.token.d.mts.map +1 -0
  266. package/src/tokens/xml-stream-adapter.token.mts +8 -0
  267. package/tsconfig.lib.json +1 -1
  268. package/tsconfig.spec.json +3 -0
  269. package/tsdown.config.mts +35 -0
  270. package/vitest.config.mts +6 -0
  271. package/lib/_tsup-dts-rollup.d.mts +0 -1352
  272. package/lib/_tsup-dts-rollup.d.ts +0 -1352
  273. package/lib/index.d.ts +0 -188
  274. package/lib/index.js +0 -1519
  275. package/lib/index.js.map +0 -1
  276. package/lib/index.mjs.map +0 -1
  277. package/tsup.config.mts +0 -13
@@ -0,0 +1,420 @@
1
+ // oxlint-disable no-unused-vars
2
+ import { builder } from '@navios/builder'
3
+
4
+ import { describe, expectTypeOf, test } from 'vitest'
5
+ import { z } from 'zod/v4'
6
+
7
+ import type {
8
+ EndpointParams,
9
+ EndpointResult,
10
+ MultipartParams,
11
+ MultipartResult,
12
+ StreamParams,
13
+ } from '../index.mjs'
14
+
15
+ import {
16
+ Controller,
17
+ Endpoint,
18
+ Header,
19
+ HttpCode,
20
+ Module,
21
+ Multipart,
22
+ Stream,
23
+ UseGuards,
24
+ } from '../index.mjs'
25
+
26
+ // Create a test API builder
27
+ const api = builder()
28
+
29
+ // Test schemas
30
+ const responseSchema = z.object({
31
+ id: z.string(),
32
+ name: z.string(),
33
+ })
34
+
35
+ const querySchema = z.object({
36
+ page: z.number(),
37
+ limit: z.number(),
38
+ })
39
+
40
+ const requestSchema = z.object({
41
+ name: z.string(),
42
+ email: z.string(),
43
+ })
44
+
45
+ const multipartRequestSchema = z.object({
46
+ file: z.instanceof(File),
47
+ description: z.string(),
48
+ })
49
+
50
+ // Test endpoint declarations
51
+ const getUserEndpoint = api.declareEndpoint({
52
+ method: 'GET',
53
+ url: '/users/$userId',
54
+ querySchema,
55
+ responseSchema,
56
+ })
57
+
58
+ const createUserEndpoint = api.declareEndpoint({
59
+ method: 'POST',
60
+ url: '/users',
61
+ requestSchema,
62
+ responseSchema,
63
+ })
64
+
65
+ const uploadFileEndpoint = api.declareMultipart({
66
+ method: 'POST',
67
+ url: '/upload',
68
+ requestSchema: multipartRequestSchema,
69
+ responseSchema,
70
+ })
71
+
72
+ const downloadFileEndpoint = api.declareStream({
73
+ method: 'GET',
74
+ url: '/files/$fileId',
75
+ querySchema,
76
+ })
77
+
78
+ // Mock guard for testing
79
+ class AuthGuard {
80
+ canActivate() {
81
+ return true
82
+ }
83
+ }
84
+
85
+ describe('Legacy Decorators Type Safety', () => {
86
+ describe('Module decorator', () => {
87
+ test('should accept valid module options', () => {
88
+ @Module({
89
+ controllers: [],
90
+ imports: [],
91
+ guards: [],
92
+ })
93
+ class TestModule {}
94
+
95
+ expectTypeOf(TestModule).toBeConstructibleWith()
96
+ })
97
+
98
+ test('should accept controllers in module', () => {
99
+ @Controller()
100
+ class TestController {}
101
+
102
+ @Module({
103
+ controllers: [TestController],
104
+ })
105
+ class TestModule {}
106
+
107
+ expectTypeOf(TestModule).toBeConstructibleWith()
108
+ })
109
+ })
110
+
111
+ describe('Controller decorator', () => {
112
+ test('should accept valid controller options', () => {
113
+ @Controller()
114
+ class TestController {}
115
+
116
+ expectTypeOf(TestController).toBeConstructibleWith()
117
+ })
118
+
119
+ test('should accept guards in controller', () => {
120
+ @Controller({
121
+ guards: [AuthGuard],
122
+ })
123
+ class TestController {}
124
+
125
+ expectTypeOf(TestController).toBeConstructibleWith()
126
+ })
127
+ })
128
+
129
+ describe('Endpoint decorator', () => {
130
+ test('should enforce correct parameter type', () => {
131
+ @Controller()
132
+ class UserController {
133
+ @Endpoint(getUserEndpoint)
134
+ async getUser(
135
+ request: EndpointParams<typeof getUserEndpoint>,
136
+ ): EndpointResult<typeof getUserEndpoint> {
137
+ // TypeScript should infer:
138
+ // - request.urlParams.userId: string | number
139
+ // - request.params.page: number
140
+ // - request.params.limit: number
141
+ expectTypeOf(request.urlParams.userId).toEqualTypeOf<
142
+ string | number
143
+ >()
144
+ expectTypeOf(request.params.page).toEqualTypeOf<number>()
145
+ expectTypeOf(request.params.limit).toEqualTypeOf<number>()
146
+ return {
147
+ id: request.urlParams.userId.toString(),
148
+ name: 'Test',
149
+ }
150
+ }
151
+ }
152
+
153
+ expectTypeOf(UserController).toBeConstructibleWith()
154
+ })
155
+
156
+ test('should enforce correct return type', () => {
157
+ @Controller()
158
+ class UserController {
159
+ @Endpoint(getUserEndpoint)
160
+ async getUser(
161
+ request: EndpointParams<typeof getUserEndpoint>,
162
+ ): EndpointResult<typeof getUserEndpoint> {
163
+ // Return type should match responseSchema
164
+ return {
165
+ id: '1',
166
+ name: 'John',
167
+ }
168
+ }
169
+ }
170
+
171
+ expectTypeOf(UserController).toBeConstructibleWith()
172
+ })
173
+
174
+ test('should reject incorrect parameter type', () => {
175
+ @Controller()
176
+ class UserController {
177
+ // @ts-expect-error - wrong parameter type
178
+ @Endpoint(getUserEndpoint)
179
+ async getUser(request: {
180
+ wrong: string
181
+ }): EndpointResult<typeof getUserEndpoint> {
182
+ return { id: '1', name: 'John' }
183
+ }
184
+ }
185
+ })
186
+
187
+ test('should reject incorrect return type', () => {
188
+ @Controller()
189
+ class UserController {
190
+ @Endpoint(getUserEndpoint)
191
+ async getUser(
192
+ request: EndpointParams<typeof getUserEndpoint>,
193
+ ): EndpointResult<typeof getUserEndpoint> {
194
+ // @ts-expect-error - wrong return type
195
+ return { wrong: 'value' }
196
+ }
197
+ }
198
+ })
199
+
200
+ test('should work with POST endpoint with request body', () => {
201
+ @Controller()
202
+ class UserController {
203
+ @Endpoint(createUserEndpoint)
204
+ async createUser(
205
+ request: EndpointParams<typeof createUserEndpoint>,
206
+ ): EndpointResult<typeof createUserEndpoint> {
207
+ // TypeScript should infer:
208
+ // - request.data.name: string
209
+ // - request.data.email: string
210
+ expectTypeOf(request.data.name).toEqualTypeOf<string>()
211
+ expectTypeOf(request.data.email).toEqualTypeOf<string>()
212
+ return {
213
+ id: '1',
214
+ name: request.data.name,
215
+ }
216
+ }
217
+ }
218
+
219
+ expectTypeOf(UserController).toBeConstructibleWith()
220
+ })
221
+ })
222
+
223
+ describe('Multipart decorator', () => {
224
+ test('should enforce correct parameter type', () => {
225
+ @Controller()
226
+ class FileController {
227
+ @Multipart(uploadFileEndpoint)
228
+ async uploadFile(
229
+ request: MultipartParams<typeof uploadFileEndpoint>,
230
+ ): MultipartResult<typeof uploadFileEndpoint> {
231
+ // TypeScript should infer:
232
+ // - request.data.file: File
233
+ // - request.data.description: string
234
+ expectTypeOf(request.data.file).toEqualTypeOf<File>()
235
+ expectTypeOf(request.data.description).toEqualTypeOf<string>()
236
+ return {
237
+ id: '1',
238
+ name: 'uploaded.jpg',
239
+ }
240
+ }
241
+ }
242
+
243
+ expectTypeOf(FileController).toBeConstructibleWith()
244
+ })
245
+
246
+ test('should reject incorrect parameter type', () => {
247
+ @Controller()
248
+ class FileController {
249
+ // @ts-expect-error - wrong parameter type
250
+ @Multipart(uploadFileEndpoint)
251
+ async uploadFile(request: {
252
+ wrong: string
253
+ }): MultipartResult<typeof uploadFileEndpoint> {
254
+ return { id: '1', name: 'test.jpg' }
255
+ }
256
+ }
257
+ })
258
+ })
259
+
260
+ describe('Stream decorator', () => {
261
+ test('should enforce correct parameter type', () => {
262
+ @Controller()
263
+ class FileController {
264
+ @Stream(downloadFileEndpoint)
265
+ async downloadFile(
266
+ request: StreamParams<typeof downloadFileEndpoint>,
267
+ reply: any,
268
+ ): Promise<void> {
269
+ // TypeScript should infer:
270
+ // - request.urlParams.fileId: string | number
271
+ // - request.params.page: number
272
+ // - request.params.limit: number
273
+ expectTypeOf(request.urlParams.fileId).toEqualTypeOf<
274
+ string | number
275
+ >()
276
+ expectTypeOf(request.params.page).toEqualTypeOf<number>()
277
+ expectTypeOf(request.params.limit).toEqualTypeOf<number>()
278
+ }
279
+ }
280
+
281
+ expectTypeOf(FileController).toBeConstructibleWith()
282
+ })
283
+
284
+ test('should require reply parameter', () => {
285
+ @Controller()
286
+ class FileController {
287
+ // @ts-expect-error - missing reply parameter
288
+ @Stream(downloadFileEndpoint)
289
+ async downloadFile(
290
+ request: StreamParams<typeof downloadFileEndpoint>,
291
+ ): Promise<void> {
292
+ // Stream methods must have reply parameter
293
+ }
294
+ }
295
+ })
296
+ })
297
+
298
+ describe('UseGuards decorator', () => {
299
+ test('should work on class level', () => {
300
+ @Controller()
301
+ @UseGuards(AuthGuard)
302
+ class ProtectedController {
303
+ @Endpoint(getUserEndpoint)
304
+ async getUser(
305
+ request: EndpointParams<typeof getUserEndpoint>,
306
+ ): EndpointResult<typeof getUserEndpoint> {
307
+ return { id: '1', name: 'John' }
308
+ }
309
+ }
310
+
311
+ expectTypeOf(ProtectedController).toBeConstructibleWith()
312
+ })
313
+
314
+ test('should work on method level', () => {
315
+ @Controller()
316
+ class UserController {
317
+ @Endpoint(getUserEndpoint)
318
+ @UseGuards(AuthGuard)
319
+ async getUser(
320
+ request: EndpointParams<typeof getUserEndpoint>,
321
+ ): EndpointResult<typeof getUserEndpoint> {
322
+ return { id: '1', name: 'John' }
323
+ }
324
+ }
325
+
326
+ expectTypeOf(UserController).toBeConstructibleWith()
327
+ })
328
+ })
329
+
330
+ describe('Header decorator', () => {
331
+ test('should work with string value', () => {
332
+ @Controller()
333
+ class UserController {
334
+ @Endpoint(getUserEndpoint)
335
+ @Header('Cache-Control', 'max-age=3600')
336
+ async getUser(
337
+ request: EndpointParams<typeof getUserEndpoint>,
338
+ ): EndpointResult<typeof getUserEndpoint> {
339
+ return { id: '1', name: 'John' }
340
+ }
341
+ }
342
+
343
+ expectTypeOf(UserController).toBeConstructibleWith()
344
+ })
345
+
346
+ test('should work with number value', () => {
347
+ @Controller()
348
+ class UserController {
349
+ @Endpoint(getUserEndpoint)
350
+ @Header('Content-Length', 100)
351
+ async getUser(
352
+ request: EndpointParams<typeof getUserEndpoint>,
353
+ ): EndpointResult<typeof getUserEndpoint> {
354
+ return { id: '1', name: 'John' }
355
+ }
356
+ }
357
+
358
+ expectTypeOf(UserController).toBeConstructibleWith()
359
+ })
360
+ })
361
+
362
+ describe('HttpCode decorator', () => {
363
+ test('should accept valid status codes', () => {
364
+ @Controller()
365
+ class UserController {
366
+ @Endpoint(createUserEndpoint)
367
+ @HttpCode(201)
368
+ async createUser(
369
+ request: EndpointParams<typeof createUserEndpoint>,
370
+ ): EndpointResult<typeof createUserEndpoint> {
371
+ return { id: '1', name: request.data.name }
372
+ }
373
+ }
374
+
375
+ expectTypeOf(UserController).toBeConstructibleWith()
376
+ })
377
+ })
378
+
379
+ describe('Integration test - full controller', () => {
380
+ test('should work with all decorators together', () => {
381
+ @Controller({
382
+ guards: [AuthGuard],
383
+ })
384
+ @UseGuards(AuthGuard)
385
+ class UserController {
386
+ @Endpoint(getUserEndpoint)
387
+ @UseGuards(AuthGuard)
388
+ @Header('Cache-Control', 'max-age=3600')
389
+ @HttpCode(200)
390
+ async getUser(
391
+ request: EndpointParams<typeof getUserEndpoint>,
392
+ ): EndpointResult<typeof getUserEndpoint> {
393
+ return {
394
+ id: request.urlParams.userId.toString(),
395
+ name: 'John',
396
+ }
397
+ }
398
+
399
+ @Endpoint(createUserEndpoint)
400
+ @HttpCode(201)
401
+ async createUser(
402
+ request: EndpointParams<typeof createUserEndpoint>,
403
+ ): EndpointResult<typeof createUserEndpoint> {
404
+ return {
405
+ id: '1',
406
+ name: request.data.name,
407
+ }
408
+ }
409
+ }
410
+
411
+ @Module({
412
+ controllers: [UserController],
413
+ })
414
+ class AppModule {}
415
+
416
+ expectTypeOf(UserController).toBeConstructibleWith()
417
+ expectTypeOf(AppModule).toBeConstructibleWith()
418
+ })
419
+ })
420
+ })
@@ -0,0 +1,15 @@
1
+ {
2
+ "extends": "../../../../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "experimentalDecorators": true,
5
+ "emitDecoratorMetadata": false,
6
+ "outDir": "../../../dist/legacy-compat/__type-tests__"
7
+ },
8
+ "include": ["**/*.spec-d.mts"],
9
+ "exclude": [],
10
+ "references": [
11
+ {
12
+ "path": "../../../tsconfig.lib.json"
13
+ }
14
+ ]
15
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Compatibility layer for converting legacy decorator signatures to Stage 3 format.
3
+ *
4
+ * This module provides utilities to create mock Stage 3 decorator contexts
5
+ * from legacy decorator arguments, and manages metadata storage using WeakMap.
6
+ */
7
+ import type { ClassType } from '@navios/di';
8
+ /**
9
+ * Creates a mock ClassDecoratorContext for legacy class decorators.
10
+ */
11
+ export declare function createClassContext(target: ClassType): ClassDecoratorContext;
12
+ /**
13
+ * Creates a mock ClassMethodDecoratorContext for legacy method decorators.
14
+ *
15
+ * Note: Method decorators need to share metadata with the class context
16
+ * because endpoint metadata is stored at the class level.
17
+ */
18
+ export declare function createMethodContext(target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor): ClassMethodDecoratorContext;
19
+ //# sourceMappingURL=context-compat.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-compat.d.mts","sourceRoot":"","sources":["context-compat.mts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAuB3C;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,qBAAqB,CAe3E;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,GAAG,EACX,WAAW,EAAE,MAAM,GAAG,MAAM,EAC5B,UAAU,EAAE,kBAAkB,GAC7B,2BAA2B,CAgC7B"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Compatibility layer for converting legacy decorator signatures to Stage 3 format.
3
+ *
4
+ * This module provides utilities to create mock Stage 3 decorator contexts
5
+ * from legacy decorator arguments, and manages metadata storage using WeakMap.
6
+ */
7
+
8
+ import type { ClassType } from '@navios/di'
9
+
10
+ // WeakMap to store metadata for legacy decorators
11
+ // Keyed by class constructor for class decorators
12
+ // For method decorators, we use the class constructor (extracted from the prototype)
13
+ const classMetadataMap = new WeakMap<ClassType, Record<string | symbol, any>>()
14
+
15
+ /**
16
+ * Gets the constructor from a prototype (for method decorators).
17
+ */
18
+ function getConstructor(prototype: any): ClassType | null {
19
+ if (!prototype || typeof prototype !== 'object') {
20
+ return null
21
+ }
22
+ // In legacy decorators, target is the prototype
23
+ // The constructor is typically available via prototype.constructor
24
+ const constructor = prototype.constructor
25
+ if (constructor && typeof constructor === 'function') {
26
+ return constructor as ClassType
27
+ }
28
+ return null
29
+ }
30
+
31
+ /**
32
+ * Creates a mock ClassDecoratorContext for legacy class decorators.
33
+ */
34
+ export function createClassContext(target: ClassType): ClassDecoratorContext {
35
+ // Get or create metadata storage for this class
36
+ if (!classMetadataMap.has(target)) {
37
+ classMetadataMap.set(target, {})
38
+ }
39
+ const metadata = classMetadataMap.get(target)!
40
+
41
+ return {
42
+ kind: 'class',
43
+ name: target.name,
44
+ metadata,
45
+ addInitializer() {
46
+ // Legacy decorators don't support initializers
47
+ },
48
+ } as ClassDecoratorContext
49
+ }
50
+
51
+ /**
52
+ * Creates a mock ClassMethodDecoratorContext for legacy method decorators.
53
+ *
54
+ * Note: Method decorators need to share metadata with the class context
55
+ * because endpoint metadata is stored at the class level.
56
+ */
57
+ export function createMethodContext(
58
+ target: any,
59
+ propertyKey: string | symbol,
60
+ descriptor: PropertyDescriptor,
61
+ ): ClassMethodDecoratorContext {
62
+ // For method decorators, target is the prototype
63
+ // We need to get the class constructor to access class-level metadata
64
+ const constructor = getConstructor(target)
65
+ if (!constructor) {
66
+ throw new Error(
67
+ '[Navios] Could not determine class constructor from method decorator target.',
68
+ )
69
+ }
70
+
71
+ // Get or create metadata storage for the class
72
+ // Method decorators share metadata with the class
73
+ if (!classMetadataMap.has(constructor)) {
74
+ classMetadataMap.set(constructor, {})
75
+ }
76
+ const metadata = classMetadataMap.get(constructor)!
77
+
78
+ return {
79
+ kind: 'method',
80
+ name: propertyKey,
81
+ metadata,
82
+ static: false, // We can't determine this from legacy decorators
83
+ private: false, // We can't determine this from legacy decorators
84
+ access: {
85
+ has: () => true,
86
+ get: () => descriptor.value,
87
+ set: () => {},
88
+ },
89
+ addInitializer() {
90
+ // Legacy decorators don't support initializers
91
+ },
92
+ } as ClassMethodDecoratorContext
93
+ }
@@ -0,0 +1,21 @@
1
+ import type { ClassType } from '@navios/di';
2
+ import type { ControllerOptions } from '../../decorators/controller.decorator.mjs';
3
+ /**
4
+ * Legacy-compatible Controller decorator.
5
+ *
6
+ * Works with TypeScript experimental decorators (legacy API).
7
+ *
8
+ * @param options - Controller configuration options
9
+ * @returns A class decorator compatible with legacy decorator API
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * @Controller({ guards: [AuthGuard] })
14
+ * export class UserController {
15
+ * @Endpoint(getUserEndpoint)
16
+ * async getUser() { }
17
+ * }
18
+ * ```
19
+ */
20
+ export declare function Controller(options?: ControllerOptions): (target: ClassType) => ClassType;
21
+ //# sourceMappingURL=controller.decorator.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controller.decorator.d.mts","sourceRoot":"","sources":["controller.decorator.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE3C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2CAA2C,CAAA;AAKlF;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,IACvC,QAAQ,SAAS,eAKnC"}
@@ -0,0 +1,31 @@
1
+ import type { ClassType } from '@navios/di'
2
+
3
+ import type { ControllerOptions } from '../../decorators/controller.decorator.mjs'
4
+
5
+ import { Controller as OriginalController } from '../../decorators/controller.decorator.mjs'
6
+ import { createClassContext } from '../context-compat.mjs'
7
+
8
+ /**
9
+ * Legacy-compatible Controller decorator.
10
+ *
11
+ * Works with TypeScript experimental decorators (legacy API).
12
+ *
13
+ * @param options - Controller configuration options
14
+ * @returns A class decorator compatible with legacy decorator API
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * @Controller({ guards: [AuthGuard] })
19
+ * export class UserController {
20
+ * @Endpoint(getUserEndpoint)
21
+ * async getUser() { }
22
+ * }
23
+ * ```
24
+ */
25
+ export function Controller(options: ControllerOptions = {}) {
26
+ return function (target: ClassType) {
27
+ const context = createClassContext(target)
28
+ const originalDecorator = OriginalController(options)
29
+ return originalDecorator(target, context)
30
+ }
31
+ }
@@ -0,0 +1,33 @@
1
+ import type { BaseEndpointConfig, EndpointFunctionArgs, HttpMethod } from '@navios/builder';
2
+ import type { z, ZodType } from 'zod/v4';
3
+ /**
4
+ * Type helper to constrain a PropertyDescriptor's value to match an endpoint signature.
5
+ * Note: In legacy decorators, type constraints are checked when the decorator is applied,
6
+ * but may not be preserved perfectly when decorators are stacked.
7
+ */
8
+ type EndpointMethodDescriptor<Url extends string, QuerySchema, RequestSchema, ResponseSchema extends ZodType> = TypedPropertyDescriptor<(params: QuerySchema extends ZodType ? RequestSchema extends ZodType ? EndpointFunctionArgs<Url, QuerySchema, RequestSchema, true> : EndpointFunctionArgs<Url, QuerySchema, undefined, true> : RequestSchema extends ZodType ? EndpointFunctionArgs<Url, undefined, RequestSchema, true> : EndpointFunctionArgs<Url, undefined, undefined, true>) => Promise<z.input<ResponseSchema>>>;
9
+ /**
10
+ * Legacy-compatible Endpoint decorator.
11
+ *
12
+ * Works with TypeScript experimental decorators (legacy API).
13
+ * Provides type safety by ensuring method signatures match the endpoint configuration.
14
+ *
15
+ * @param endpoint - The endpoint declaration from @navios/builder
16
+ * @returns A method decorator compatible with legacy decorator API
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * @Controller()
21
+ * export class UserController {
22
+ * @Endpoint(getUserEndpoint)
23
+ * async getUser(request: EndpointParams<typeof getUserEndpoint>): EndpointResult<typeof getUserEndpoint> {
24
+ * return { id: '1', name: 'John' }
25
+ * }
26
+ * }
27
+ * ```
28
+ */
29
+ export declare function Endpoint<Method extends HttpMethod = HttpMethod, Url extends string = string, QuerySchema = undefined, ResponseSchema extends ZodType = ZodType, RequestSchema = ZodType>(endpoint: {
30
+ config: BaseEndpointConfig<Method, Url, QuerySchema, ResponseSchema, RequestSchema>;
31
+ }): (target: any, propertyKey: string | symbol, descriptor: EndpointMethodDescriptor<Url, QuerySchema, RequestSchema, ResponseSchema>) => PropertyDescriptor | void;
32
+
33
+ //# sourceMappingURL=endpoint.decorator.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"endpoint.decorator.d.mts","sourceRoot":"","sources":["endpoint.decorator.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,oBAAoB,EACpB,UAAU,EACX,MAAM,iBAAiB,CAAA;AACxB,OAAO,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAA;AAKxC;;;;GAIG;AACH,KAAK,wBAAwB,CAC3B,GAAG,SAAS,MAAM,EAClB,WAAW,EACX,aAAa,EACb,cAAc,SAAS,OAAO,IAC5B,uBAAuB,CACzB,CACE,MAAM,EAAE,WAAW,SAAS,OAAO,GAC/B,aAAa,SAAS,OAAO,GAC3B,oBAAoB,CAAC,GAAG,EAAE,WAAW,EAAE,aAAa,EAAE,IAAI,CAAC,GAC3D,oBAAoB,CAAC,GAAG,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,CAAC,GACzD,aAAa,SAAS,OAAO,GAC3B,oBAAoB,CAAC,GAAG,EAAE,SAAS,EAAE,aAAa,EAAE,IAAI,CAAC,GACzD,oBAAoB,CAAC,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,KACxD,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CACtC,CAAA;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,QAAQ,CACtB,MAAM,SAAS,UAAU,GAAG,UAAU,EACtC,GAAG,SAAS,MAAM,GAAG,MAAM,EAC3B,WAAW,GAAG,SAAS,EACvB,cAAc,SAAS,OAAO,GAAG,OAAO,EACxC,aAAa,GAAG,OAAO,EACvB,QAAQ,EAAE;IACV,MAAM,EAAE,kBAAkB,CACxB,MAAM,EACN,GAAG,EACH,WAAW,EACX,cAAc,EACd,aAAa,CACd,CAAA;CACF,IAEG,QAAQ,GAAG,EACX,aAAa,MAAM,GAAG,MAAM,EAC5B,YAAY,wBAAwB,CAClC,GAAG,EACH,WAAW,EACX,aAAa,EACb,cAAc,CACf,KACA,kBAAkB,GAAG,IAAI,CAsB7B"}