@catbee/utils 0.0.8-next.0 → 0.0.8-rc.1

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 (284) hide show
  1. package/README.md +1 -2
  2. package/build/esm/config.d.ts +122 -0
  3. package/build/esm/config.js +133 -0
  4. package/build/esm/config.js.map +1 -0
  5. package/build/esm/index.d.ts +27 -0
  6. package/build/esm/index.js +50 -0
  7. package/build/esm/index.js.map +1 -0
  8. package/build/esm/servers/server.builder.d.ts +508 -0
  9. package/build/esm/servers/server.builder.js +702 -0
  10. package/build/esm/servers/server.builder.js.map +1 -0
  11. package/build/esm/servers/server.d.ts +256 -0
  12. package/build/esm/servers/server.js +1248 -0
  13. package/build/esm/servers/server.js.map +1 -0
  14. package/build/esm/types/api-response.d.ts +152 -0
  15. package/build/esm/types/api-response.js +34 -0
  16. package/build/esm/types/api-response.js.map +1 -0
  17. package/build/esm/types/index.d.ts +125 -0
  18. package/build/esm/types/index.js +25 -0
  19. package/build/esm/types/index.js.map +1 -0
  20. package/build/esm/types/server.d.ts +268 -0
  21. package/build/esm/types/server.js +25 -0
  22. package/build/esm/types/server.js.map +1 -0
  23. package/build/esm/utils/array.utils.d.ts +168 -0
  24. package/build/esm/utils/array.utils.js +382 -0
  25. package/build/esm/utils/array.utils.js.map +1 -0
  26. package/build/esm/utils/async.utils.d.ts +265 -0
  27. package/build/esm/utils/async.utils.js +896 -0
  28. package/build/esm/utils/async.utils.js.map +1 -0
  29. package/build/esm/utils/cache.utils.d.ts +153 -0
  30. package/build/esm/utils/cache.utils.js +499 -0
  31. package/build/esm/utils/cache.utils.js.map +1 -0
  32. package/build/esm/utils/context-store.utils.d.ts +189 -0
  33. package/build/esm/utils/context-store.utils.js +307 -0
  34. package/build/esm/utils/context-store.utils.js.map +1 -0
  35. package/build/esm/utils/crypto.utils.d.ts +160 -0
  36. package/build/esm/utils/crypto.utils.js +375 -0
  37. package/build/esm/utils/crypto.utils.js.map +1 -0
  38. package/build/esm/utils/date.utils.d.ts +159 -0
  39. package/build/esm/utils/date.utils.js +389 -0
  40. package/build/esm/utils/date.utils.js.map +1 -0
  41. package/build/esm/utils/decorators.utils.d.ts +508 -0
  42. package/build/esm/utils/decorators.utils.js +1057 -0
  43. package/build/esm/utils/decorators.utils.js.map +1 -0
  44. package/build/esm/utils/dir.utils.d.ts +196 -0
  45. package/build/esm/utils/dir.utils.js +998 -0
  46. package/build/esm/utils/dir.utils.js.map +1 -0
  47. package/build/esm/utils/env.utils.d.ts +377 -0
  48. package/build/esm/utils/env.utils.js +873 -0
  49. package/build/esm/utils/env.utils.js.map +1 -0
  50. package/build/esm/utils/exception.utils.d.ts +230 -0
  51. package/build/esm/utils/exception.utils.js +559 -0
  52. package/build/esm/utils/exception.utils.js.map +1 -0
  53. package/build/esm/utils/fs.utils.d.ts +164 -0
  54. package/build/esm/utils/fs.utils.js +580 -0
  55. package/build/esm/utils/fs.utils.js.map +1 -0
  56. package/build/esm/utils/http-status-codes.d.ts +266 -0
  57. package/build/esm/utils/http-status-codes.js +295 -0
  58. package/build/esm/utils/http-status-codes.js.map +1 -0
  59. package/build/esm/utils/id.utils.d.ts +36 -0
  60. package/build/esm/utils/id.utils.js +87 -0
  61. package/build/esm/utils/id.utils.js.map +1 -0
  62. package/build/esm/utils/logger.utils.d.ts +160 -0
  63. package/build/esm/utils/logger.utils.js +341 -0
  64. package/build/esm/utils/logger.utils.js.map +1 -0
  65. package/build/esm/utils/middleware.utils.d.ts +100 -0
  66. package/build/esm/utils/middleware.utils.js +325 -0
  67. package/build/esm/utils/middleware.utils.js.map +1 -0
  68. package/build/esm/utils/obj.utils.d.ts +124 -0
  69. package/build/esm/utils/obj.utils.js +519 -0
  70. package/build/esm/utils/obj.utils.js.map +1 -0
  71. package/build/esm/utils/performance.utils.d.ts +136 -0
  72. package/build/esm/utils/performance.utils.js +376 -0
  73. package/build/esm/utils/performance.utils.js.map +1 -0
  74. package/build/esm/utils/request.utils.d.ts +86 -0
  75. package/build/esm/utils/request.utils.js +223 -0
  76. package/build/esm/utils/request.utils.js.map +1 -0
  77. package/build/esm/utils/response.utils.d.ts +163 -0
  78. package/build/esm/utils/response.utils.js +284 -0
  79. package/build/esm/utils/response.utils.js.map +1 -0
  80. package/build/esm/utils/stream.utils.d.ts +88 -0
  81. package/build/esm/utils/stream.utils.js +284 -0
  82. package/build/esm/utils/stream.utils.js.map +1 -0
  83. package/build/esm/utils/string.utils.d.ts +93 -0
  84. package/build/esm/utils/string.utils.js +169 -0
  85. package/build/esm/utils/string.utils.js.map +1 -0
  86. package/build/esm/utils/type.utils.d.ts +90 -0
  87. package/build/esm/utils/type.utils.js +190 -0
  88. package/build/esm/utils/type.utils.js.map +1 -0
  89. package/build/esm/utils/url.utils.d.ts +141 -0
  90. package/build/esm/utils/url.utils.js +381 -0
  91. package/build/esm/utils/url.utils.js.map +1 -0
  92. package/build/esm/utils/validate.utils.d.ts +177 -0
  93. package/build/esm/utils/validate.utils.js +336 -0
  94. package/build/esm/utils/validate.utils.js.map +1 -0
  95. package/build/esnext/config.d.ts +122 -0
  96. package/build/esnext/config.js +133 -0
  97. package/build/esnext/config.js.map +1 -0
  98. package/build/esnext/index.d.ts +27 -0
  99. package/build/esnext/index.js +50 -0
  100. package/build/esnext/index.js.map +1 -0
  101. package/build/esnext/servers/server.builder.d.ts +508 -0
  102. package/build/esnext/servers/server.builder.js +657 -0
  103. package/build/esnext/servers/server.builder.js.map +1 -0
  104. package/build/esnext/servers/server.d.ts +256 -0
  105. package/build/esnext/servers/server.js +955 -0
  106. package/build/esnext/servers/server.js.map +1 -0
  107. package/build/esnext/types/api-response.d.ts +152 -0
  108. package/build/esnext/types/api-response.js +34 -0
  109. package/build/esnext/types/api-response.js.map +1 -0
  110. package/build/esnext/types/index.d.ts +125 -0
  111. package/build/esnext/types/index.js +25 -0
  112. package/build/esnext/types/index.js.map +1 -0
  113. package/build/esnext/types/server.d.ts +268 -0
  114. package/build/esnext/types/server.js +25 -0
  115. package/build/esnext/types/server.js.map +1 -0
  116. package/build/esnext/utils/array.utils.d.ts +168 -0
  117. package/build/esnext/utils/array.utils.js +345 -0
  118. package/build/esnext/utils/array.utils.js.map +1 -0
  119. package/build/esnext/utils/async.utils.d.ts +265 -0
  120. package/build/esnext/utils/async.utils.js +620 -0
  121. package/build/esnext/utils/async.utils.js.map +1 -0
  122. package/build/esnext/utils/cache.utils.d.ts +153 -0
  123. package/build/esnext/utils/cache.utils.js +293 -0
  124. package/build/esnext/utils/cache.utils.js.map +1 -0
  125. package/build/esnext/utils/context-store.utils.d.ts +189 -0
  126. package/build/esnext/utils/context-store.utils.js +289 -0
  127. package/build/esnext/utils/context-store.utils.js.map +1 -0
  128. package/build/esnext/utils/crypto.utils.d.ts +160 -0
  129. package/build/esnext/utils/crypto.utils.js +276 -0
  130. package/build/esnext/utils/crypto.utils.js.map +1 -0
  131. package/build/esnext/utils/date.utils.d.ts +159 -0
  132. package/build/esnext/utils/date.utils.js +384 -0
  133. package/build/esnext/utils/date.utils.js.map +1 -0
  134. package/build/esnext/utils/decorators.utils.d.ts +508 -0
  135. package/build/esnext/utils/decorators.utils.js +877 -0
  136. package/build/esnext/utils/decorators.utils.js.map +1 -0
  137. package/build/esnext/utils/dir.utils.d.ts +196 -0
  138. package/build/esnext/utils/dir.utils.js +477 -0
  139. package/build/esnext/utils/dir.utils.js.map +1 -0
  140. package/build/esnext/utils/env.utils.d.ts +377 -0
  141. package/build/esnext/utils/env.utils.js +785 -0
  142. package/build/esnext/utils/env.utils.js.map +1 -0
  143. package/build/esnext/utils/exception.utils.d.ts +230 -0
  144. package/build/esnext/utils/exception.utils.js +381 -0
  145. package/build/esnext/utils/exception.utils.js.map +1 -0
  146. package/build/esnext/utils/fs.utils.d.ts +164 -0
  147. package/build/esnext/utils/fs.utils.js +349 -0
  148. package/build/esnext/utils/fs.utils.js.map +1 -0
  149. package/build/esnext/utils/http-status-codes.d.ts +266 -0
  150. package/build/esnext/utils/http-status-codes.js +295 -0
  151. package/build/esnext/utils/http-status-codes.js.map +1 -0
  152. package/build/esnext/utils/id.utils.d.ts +36 -0
  153. package/build/esnext/utils/id.utils.js +84 -0
  154. package/build/esnext/utils/id.utils.js.map +1 -0
  155. package/build/esnext/utils/logger.utils.d.ts +160 -0
  156. package/build/esnext/utils/logger.utils.js +300 -0
  157. package/build/esnext/utils/logger.utils.js.map +1 -0
  158. package/build/esnext/utils/middleware.utils.d.ts +100 -0
  159. package/build/esnext/utils/middleware.utils.js +236 -0
  160. package/build/esnext/utils/middleware.utils.js.map +1 -0
  161. package/build/esnext/utils/obj.utils.d.ts +124 -0
  162. package/build/esnext/utils/obj.utils.js +413 -0
  163. package/build/esnext/utils/obj.utils.js.map +1 -0
  164. package/build/esnext/utils/performance.utils.d.ts +136 -0
  165. package/build/esnext/utils/performance.utils.js +271 -0
  166. package/build/esnext/utils/performance.utils.js.map +1 -0
  167. package/build/esnext/utils/request.utils.d.ts +86 -0
  168. package/build/esnext/utils/request.utils.js +186 -0
  169. package/build/esnext/utils/request.utils.js.map +1 -0
  170. package/build/esnext/utils/response.utils.d.ts +163 -0
  171. package/build/esnext/utils/response.utils.js +247 -0
  172. package/build/esnext/utils/response.utils.js.map +1 -0
  173. package/build/esnext/utils/stream.utils.d.ts +88 -0
  174. package/build/esnext/utils/stream.utils.js +210 -0
  175. package/build/esnext/utils/stream.utils.js.map +1 -0
  176. package/build/esnext/utils/string.utils.d.ts +93 -0
  177. package/build/esnext/utils/string.utils.js +165 -0
  178. package/build/esnext/utils/string.utils.js.map +1 -0
  179. package/build/esnext/utils/type.utils.d.ts +90 -0
  180. package/build/esnext/utils/type.utils.js +187 -0
  181. package/build/esnext/utils/type.utils.js.map +1 -0
  182. package/build/esnext/utils/url.utils.d.ts +141 -0
  183. package/build/esnext/utils/url.utils.js +304 -0
  184. package/build/esnext/utils/url.utils.js.map +1 -0
  185. package/build/esnext/utils/validate.utils.d.ts +177 -0
  186. package/build/esnext/utils/validate.utils.js +320 -0
  187. package/build/esnext/utils/validate.utils.js.map +1 -0
  188. package/build/src/config.d.ts +122 -0
  189. package/build/src/config.js +138 -0
  190. package/build/src/config.js.map +1 -0
  191. package/build/src/index.d.ts +27 -0
  192. package/build/src/index.js +69 -0
  193. package/build/src/index.js.map +1 -0
  194. package/build/src/servers/server.builder.d.ts +508 -0
  195. package/build/src/servers/server.builder.js +661 -0
  196. package/build/src/servers/server.builder.js.map +1 -0
  197. package/build/src/servers/server.d.ts +256 -0
  198. package/build/src/servers/server.js +962 -0
  199. package/build/src/servers/server.js.map +1 -0
  200. package/build/src/types/api-response.d.ts +152 -0
  201. package/build/src/types/api-response.js +37 -0
  202. package/build/src/types/api-response.js.map +1 -0
  203. package/build/src/types/index.d.ts +125 -0
  204. package/build/src/types/index.js +26 -0
  205. package/build/src/types/index.js.map +1 -0
  206. package/build/src/types/server.d.ts +268 -0
  207. package/build/src/types/server.js +26 -0
  208. package/build/src/types/server.js.map +1 -0
  209. package/build/src/utils/array.utils.d.ts +168 -0
  210. package/build/src/utils/array.utils.js +364 -0
  211. package/build/src/utils/array.utils.js.map +1 -0
  212. package/build/src/utils/async.utils.d.ts +265 -0
  213. package/build/src/utils/async.utils.js +641 -0
  214. package/build/src/utils/async.utils.js.map +1 -0
  215. package/build/src/utils/cache.utils.d.ts +153 -0
  216. package/build/src/utils/cache.utils.js +297 -0
  217. package/build/src/utils/cache.utils.js.map +1 -0
  218. package/build/src/utils/context-store.utils.d.ts +189 -0
  219. package/build/src/utils/context-store.utils.js +296 -0
  220. package/build/src/utils/context-store.utils.js.map +1 -0
  221. package/build/src/utils/crypto.utils.d.ts +160 -0
  222. package/build/src/utils/crypto.utils.js +293 -0
  223. package/build/src/utils/crypto.utils.js.map +1 -0
  224. package/build/src/utils/date.utils.d.ts +159 -0
  225. package/build/src/utils/date.utils.js +396 -0
  226. package/build/src/utils/date.utils.js.map +1 -0
  227. package/build/src/utils/decorators.utils.d.ts +508 -0
  228. package/build/src/utils/decorators.utils.js +896 -0
  229. package/build/src/utils/decorators.utils.js.map +1 -0
  230. package/build/src/utils/dir.utils.d.ts +196 -0
  231. package/build/src/utils/dir.utils.js +501 -0
  232. package/build/src/utils/dir.utils.js.map +1 -0
  233. package/build/src/utils/env.utils.d.ts +377 -0
  234. package/build/src/utils/env.utils.js +789 -0
  235. package/build/src/utils/env.utils.js.map +1 -0
  236. package/build/src/utils/exception.utils.d.ts +230 -0
  237. package/build/src/utils/exception.utils.js +407 -0
  238. package/build/src/utils/exception.utils.js.map +1 -0
  239. package/build/src/utils/fs.utils.d.ts +164 -0
  240. package/build/src/utils/fs.utils.js +372 -0
  241. package/build/src/utils/fs.utils.js.map +1 -0
  242. package/build/src/utils/http-status-codes.d.ts +266 -0
  243. package/build/src/utils/http-status-codes.js +298 -0
  244. package/build/src/utils/http-status-codes.js.map +1 -0
  245. package/build/src/utils/id.utils.d.ts +36 -0
  246. package/build/src/utils/id.utils.js +91 -0
  247. package/build/src/utils/id.utils.js.map +1 -0
  248. package/build/src/utils/logger.utils.d.ts +160 -0
  249. package/build/src/utils/logger.utils.js +346 -0
  250. package/build/src/utils/logger.utils.js.map +1 -0
  251. package/build/src/utils/middleware.utils.d.ts +100 -0
  252. package/build/src/utils/middleware.utils.js +244 -0
  253. package/build/src/utils/middleware.utils.js.map +1 -0
  254. package/build/src/utils/obj.utils.d.ts +124 -0
  255. package/build/src/utils/obj.utils.js +429 -0
  256. package/build/src/utils/obj.utils.js.map +1 -0
  257. package/build/src/utils/performance.utils.d.ts +136 -0
  258. package/build/src/utils/performance.utils.js +278 -0
  259. package/build/src/utils/performance.utils.js.map +1 -0
  260. package/build/src/utils/request.utils.d.ts +86 -0
  261. package/build/src/utils/request.utils.js +195 -0
  262. package/build/src/utils/request.utils.js.map +1 -0
  263. package/build/src/utils/response.utils.d.ts +163 -0
  264. package/build/src/utils/response.utils.js +260 -0
  265. package/build/src/utils/response.utils.js.map +1 -0
  266. package/build/src/utils/stream.utils.d.ts +88 -0
  267. package/build/src/utils/stream.utils.js +218 -0
  268. package/build/src/utils/stream.utils.js.map +1 -0
  269. package/build/src/utils/string.utils.d.ts +93 -0
  270. package/build/src/utils/string.utils.js +179 -0
  271. package/build/src/utils/string.utils.js.map +1 -0
  272. package/build/src/utils/type.utils.d.ts +90 -0
  273. package/build/src/utils/type.utils.js +196 -0
  274. package/build/src/utils/type.utils.js.map +1 -0
  275. package/build/src/utils/url.utils.d.ts +141 -0
  276. package/build/src/utils/url.utils.js +317 -0
  277. package/build/src/utils/url.utils.js.map +1 -0
  278. package/build/src/utils/validate.utils.d.ts +177 -0
  279. package/build/src/utils/validate.utils.js +345 -0
  280. package/build/src/utils/validate.utils.js.map +1 -0
  281. package/package.json +66 -12
  282. package/build/index.cjs +0 -6888
  283. package/build/index.d.ts +0 -5242
  284. package/build/index.mjs +0 -6615
@@ -0,0 +1,877 @@
1
+ /*
2
+ * The MIT License
3
+ *
4
+ * Copyright (c) 2025 Catbee Technologies. https://catbee-utils.npm.hprasath.com/license
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ * of this software and associated documentation files (the "Software"), to deal
8
+ * in the Software without restriction, including without limitation the rights
9
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ * copies of the Software, and to permit persons to whom the Software is
11
+ * furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in all
14
+ * copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ * SOFTWARE.
23
+ */
24
+ import 'reflect-metadata';
25
+ import { getLogger } from './logger.utils';
26
+ import { createFinalErrorResponse } from './response.utils';
27
+ import { HttpStatusCodes } from './http-status-codes';
28
+ import { rateLimit } from 'express-rate-limit';
29
+ import { TTLCache } from './cache.utils';
30
+ // Metadata keys
31
+ const ROUTES_KEY = Symbol('routes');
32
+ const MIDDLEWARE_KEY = Symbol('middlewares');
33
+ const PARAMS_KEY = Symbol('params');
34
+ const HTTP_CODE_KEY = Symbol('httpCode');
35
+ const HEADER_KEY = Symbol('headers');
36
+ const BEFORE_KEY = Symbol('before');
37
+ const AFTER_KEY = Symbol('after');
38
+ const ROLES_KEY = Symbol('roles');
39
+ const REDIRECT_KEY = Symbol('redirect');
40
+ const CACHE_KEY = Symbol('cache');
41
+ const RATE_LIMIT_KEY = Symbol('rateLimit');
42
+ const CONTENT_TYPE_KEY = Symbol('contentType');
43
+ const VERSION_KEY = Symbol('version');
44
+ const TIMEOUT_KEY = Symbol('timeout');
45
+ const LOG_KEY = Symbol('log');
46
+ /**
47
+ * RateLimiter cache that uses TTLCache for automatic TTL and LRU handling.
48
+ */
49
+ export class RateLimiterCache {
50
+ constructor(maxSize = 100, ttlMs = 5 * 60 * 1000) {
51
+ this.cache = new TTLCache({
52
+ maxSize,
53
+ ttlMs
54
+ });
55
+ }
56
+ generateKey(options) {
57
+ return `${options.max}:${options.windowMs}:${options.standardHeaders}:${options.legacyHeaders}`;
58
+ }
59
+ get(options) {
60
+ const key = this.generateKey(options);
61
+ const cached = this.cache.get(key);
62
+ if (cached) {
63
+ return cached.limiter;
64
+ }
65
+ // Create new limiter
66
+ const limiter = rateLimit(Object.assign(Object.assign({}, options), { handler: (req, res) => {
67
+ const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.TOO_MANY_REQUESTS, 'Too Many Requests');
68
+ res.status(HttpStatusCodes.TOO_MANY_REQUESTS).json(errorResponse);
69
+ } }));
70
+ // Store in cache
71
+ this.cache.set(key, {
72
+ limiter,
73
+ config: key
74
+ });
75
+ return limiter;
76
+ }
77
+ clear() {
78
+ this.cache.clear();
79
+ }
80
+ size() {
81
+ return this.cache.size();
82
+ }
83
+ destroy() {
84
+ this.cache.destroy();
85
+ }
86
+ }
87
+ // Global cache instance
88
+ const rateLimiterCache = new RateLimiterCache();
89
+ function normalizeHeaderValue(value) {
90
+ if (typeof value === 'undefined')
91
+ return undefined;
92
+ if (typeof value === 'string')
93
+ return value;
94
+ if (Array.isArray(value) && value.every(item => typeof item === 'string')) {
95
+ return value;
96
+ }
97
+ return String(value);
98
+ }
99
+ /**
100
+ * Factory function that creates HTTP method decorators.
101
+ *
102
+ * @param method - HTTP method to create decorator for
103
+ * @returns A method decorator function
104
+ */
105
+ function createRouteDecorator(method) {
106
+ return (path) => {
107
+ return (target, propertyKey, descriptor) => {
108
+ const routes = Reflect.getMetadata(ROUTES_KEY, target.constructor) || [];
109
+ routes.push({
110
+ path,
111
+ method,
112
+ handlerName: propertyKey
113
+ });
114
+ Reflect.defineMetadata(ROUTES_KEY, routes, target.constructor);
115
+ };
116
+ };
117
+ }
118
+ /**
119
+ * Decorator for GET HTTP method routes.
120
+ *
121
+ * @param path - URL path for the route
122
+ * @returns Method decorator
123
+ *
124
+ * @example
125
+ * ```ts
126
+ * @Get('/users')
127
+ * getUsers() {
128
+ * return this.userService.findAll();
129
+ * }
130
+ * ```
131
+ */
132
+ export const Get = createRouteDecorator('get');
133
+ /**
134
+ * Decorator for POST HTTP method routes.
135
+ *
136
+ * @param path - URL path for the route
137
+ * @returns Method decorator
138
+ *
139
+ * @example
140
+ * ```ts
141
+ * @Post('/users')
142
+ * createUser(@Body() userData: any) {
143
+ * return this.userService.create(userData);
144
+ * }
145
+ * ```
146
+ */
147
+ export const Post = createRouteDecorator('post');
148
+ /**
149
+ * Decorator for PUT HTTP method routes.
150
+ *
151
+ * @param path - URL path for the route
152
+ * @returns Method decorator
153
+ */
154
+ export const Put = createRouteDecorator('put');
155
+ /**
156
+ * Decorator for PATCH HTTP method routes.
157
+ *
158
+ * @param path - URL path for the route
159
+ * @returns Method decorator
160
+ */
161
+ export const Patch = createRouteDecorator('patch');
162
+ /**
163
+ * Decorator for DELETE HTTP method routes.
164
+ *
165
+ * @param path - URL path for the route
166
+ * @returns Method decorator
167
+ */
168
+ export const Delete = createRouteDecorator('delete');
169
+ /**
170
+ * Decorator for OPTIONS HTTP method routes.
171
+ *
172
+ * @param path - URL path for the route
173
+ * @returns Method decorator
174
+ */
175
+ export const Options = createRouteDecorator('options');
176
+ /**
177
+ * Decorator for HEAD HTTP method routes.
178
+ *
179
+ * @param path - URL path for the route
180
+ * @returns Method decorator
181
+ */
182
+ export const Head = createRouteDecorator('head');
183
+ /**
184
+ * Decorator for TRACE HTTP method routes.
185
+ *
186
+ * @param path - URL path for the route
187
+ * @returns Method decorator
188
+ */
189
+ export const Trace = createRouteDecorator('trace');
190
+ /**
191
+ * Decorator for CONNECT HTTP method routes.
192
+ *
193
+ * @param path - URL path for the route
194
+ * @returns Method decorator
195
+ */
196
+ export const Connect = createRouteDecorator('connect');
197
+ /**
198
+ * Decorator that marks a class as a controller with a base path.
199
+ * Used as the entry point for routing configuration.
200
+ *
201
+ * @param basePath - Base URL path for all routes in this controller
202
+ * @returns Class decorator
203
+ *
204
+ * @example
205
+ * ```ts
206
+ * @Controller('/api/users')
207
+ * class UserController {
208
+ * // Controller methods...
209
+ * }
210
+ * ```
211
+ */
212
+ export function Controller(basePath) {
213
+ return target => {
214
+ Reflect.defineMetadata('basePath', basePath, target);
215
+ };
216
+ }
217
+ /**
218
+ * Decorator that applies middleware to a controller method.
219
+ * Multiple middlewares can be applied and will execute in order.
220
+ *
221
+ * @param middlewares - Express middleware functions to apply
222
+ * @returns Method decorator
223
+ *
224
+ * @example
225
+ * ```ts
226
+ * @Get('/protected')
227
+ * @Use(authMiddleware, loggingMiddleware)
228
+ * getProtectedResource() {
229
+ * // This route is protected by auth middleware
230
+ * }
231
+ * ```
232
+ */
233
+ export function Use(...middlewares) {
234
+ return (target, propertyKey, _descriptor) => {
235
+ const existing = Reflect.getMetadata(MIDDLEWARE_KEY, target, propertyKey) || [];
236
+ Reflect.defineMetadata(MIDDLEWARE_KEY, [...existing, ...middlewares], target, propertyKey);
237
+ };
238
+ }
239
+ /**
240
+ * Factory function that creates parameter decorators.
241
+ *
242
+ * @param type - Parameter type to extract from request
243
+ * @param key - Optional fixed key for extraction
244
+ * @returns Parameter decorator function
245
+ */
246
+ function createParamDecorator(type, key) {
247
+ return (paramKey) => {
248
+ return (target, propertyKey, parameterIndex) => {
249
+ const params = Reflect.getMetadata(PARAMS_KEY, target, propertyKey) || [];
250
+ // Ensure parameters are ordered by index
251
+ params.push({ index: parameterIndex, type, key: paramKey || key });
252
+ params.sort((a, b) => a.index - b.index);
253
+ Reflect.defineMetadata(PARAMS_KEY, params, target, propertyKey);
254
+ };
255
+ };
256
+ }
257
+ /**
258
+ * Decorator that extracts query parameters from request.
259
+ *
260
+ * @param paramKey - Optional key to extract specific query parameter
261
+ * @returns Parameter decorator
262
+ *
263
+ * @example
264
+ * ```ts
265
+ * @Get('/search')
266
+ * search(@Query('term') searchTerm: string) {
267
+ * // searchTerm will contain the value of req.query.term
268
+ * }
269
+ * ```
270
+ */
271
+ export const Query = createParamDecorator('query');
272
+ /**
273
+ * Decorator that extracts route parameters from request.
274
+ *
275
+ * @param paramKey - Optional key to extract specific route parameter
276
+ * @returns Parameter decorator
277
+ *
278
+ * @example
279
+ * ```ts
280
+ * @Get('/users/:id')
281
+ * getUser(@Param('id') userId: string) {
282
+ * // userId will contain the value of req.params.id
283
+ * }
284
+ * ```
285
+ */
286
+ export const Param = createParamDecorator('param');
287
+ /**
288
+ * Decorator that extracts body or body property from request.
289
+ *
290
+ * @param paramKey - Optional key to extract specific body property
291
+ * @returns Parameter decorator
292
+ *
293
+ * @example
294
+ * ```ts
295
+ * @Post('/users')
296
+ * createUser(@Body() userData: any) {
297
+ * // userData will contain the entire req.body
298
+ * }
299
+ *
300
+ * @Post('/update')
301
+ * updateName(@Body('name') name: string) {
302
+ * // name will contain the value of req.body.name
303
+ * }
304
+ * ```
305
+ */
306
+ export const Body = createParamDecorator('body');
307
+ /**
308
+ * Decorator that injects the entire request object.
309
+ *
310
+ * @returns Parameter decorator
311
+ *
312
+ * @example
313
+ * ```ts
314
+ * @Get('/complex')
315
+ * complex(@Req() req: Request) {
316
+ * // Access the full request object
317
+ * console.log(req.headers);
318
+ * }
319
+ * ```
320
+ */
321
+ export const Req = createParamDecorator('req');
322
+ /**
323
+ * Decorator that injects the response object.
324
+ *
325
+ * @returns Parameter decorator
326
+ *
327
+ * @example
328
+ * ```ts
329
+ * @Get('/custom')
330
+ * custom(@Res() res: Response) {
331
+ * // Direct access to response object
332
+ * return res.status(201).send('Created');
333
+ * }
334
+ * ```
335
+ */
336
+ export const Res = createParamDecorator('res');
337
+ /**
338
+ * Decorator that sets a custom HTTP status code for a response.
339
+ *
340
+ * @param status - HTTP status code to use
341
+ * @returns Method decorator
342
+ *
343
+ * @example
344
+ * ```ts
345
+ * @Post('/users')
346
+ * @HttpCode(201)
347
+ * createUser(@Body() userData: any) {
348
+ * // Response will have 201 Created status code
349
+ * return { id: '123', ...userData };
350
+ * }
351
+ * ```
352
+ */
353
+ export function HttpCode(status) {
354
+ return (target, propertyKey, _descriptor) => {
355
+ Reflect.defineMetadata(HTTP_CODE_KEY, status, target, propertyKey);
356
+ };
357
+ }
358
+ /**
359
+ * Decorator that adds a custom HTTP header to the response.
360
+ *
361
+ * @param header - Header name-value pairs or a single header name and value
362
+ * @param value - Header value if a single header name is provided
363
+ * @returns Method decorator
364
+ *
365
+ * @example
366
+ * ```ts
367
+ * @Get('/data')
368
+ * @Header('Cache-Control', 'max-age=60')
369
+ * getData() {
370
+ * // Response will include the Cache-Control header
371
+ * return { data: '...' };
372
+ * }
373
+ */
374
+ export function Header(name, value) {
375
+ return Headers(name, value);
376
+ }
377
+ /**
378
+ * Decorator that adds a custom HTTP headers to the response.
379
+ *
380
+ * @param headers - Header name-value pairs or a single header name and value
381
+ * @param value - Header value if a single header name is provided
382
+ * @returns Method decorator
383
+ *
384
+ * @example
385
+ * ```ts
386
+ * @Get('/data')
387
+ * @Headers('Cache-Control', 'max-age=60')
388
+ * getData() {
389
+ * // Response will include the Cache-Control header
390
+ * return { data: '...' };
391
+ * }
392
+ *
393
+ * @Get('/data/:id')
394
+ * @Headers({
395
+ * 'Cache-Control': 'max-age=60',
396
+ * 'X-Custom-Header': 'custom-value',
397
+ * 'Content-Security-Policy': "default-src 'self'"
398
+ * })
399
+ * getData() {
400
+ * // Response will include all specified headers
401
+ * return { data: '...' };
402
+ * }
403
+ *
404
+ * ```
405
+ */
406
+ export function Headers(headers, value) {
407
+ return (target, propertyKey) => {
408
+ const existing = Reflect.getMetadata(HEADER_KEY, target, propertyKey) || {};
409
+ const newHeaders = typeof headers === 'string' ? { [headers]: value } : headers;
410
+ Reflect.defineMetadata(HEADER_KEY, Object.assign(Object.assign({}, existing), newHeaders), target, propertyKey);
411
+ };
412
+ }
413
+ /**
414
+ * Decorator that registers a function to run before route handler execution.
415
+ * Useful for pre-processing or logging.
416
+ *
417
+ * @param fn - Function to execute before the handler
418
+ * @returns Method decorator
419
+ *
420
+ * @example
421
+ * ```ts
422
+ * @Get('/users/:id')
423
+ * @Before((req, res) => console.log(`Accessing user ${req.params.id}`))
424
+ * getUser(@Param('id') id: string) {
425
+ * // Function will log before this handler runs
426
+ * }
427
+ * ```
428
+ */
429
+ export function Before(fn) {
430
+ return (target, propertyKey, _descriptor) => {
431
+ const hooks = Reflect.getMetadata(BEFORE_KEY, target, propertyKey) || [];
432
+ hooks.push(fn);
433
+ Reflect.defineMetadata(BEFORE_KEY, hooks, target, propertyKey);
434
+ };
435
+ }
436
+ /**
437
+ * Decorator that registers a function to run after route handler execution.
438
+ * Can access the handler's result.
439
+ *
440
+ * @param fn - Function to execute after the handler
441
+ * @returns Method decorator
442
+ *
443
+ * @example
444
+ * ```ts
445
+ * @Get('/users/:id')
446
+ * @After((req, res, result) => console.log(`User data sent: ${JSON.stringify(result)}`))
447
+ * getUser(@Param('id') id: string) {
448
+ * // After this handler, the function will log the returned data
449
+ * return { id, name: 'Example' };
450
+ * }
451
+ * ```
452
+ */
453
+ export function After(fn) {
454
+ return (target, propertyKey, _descriptor) => {
455
+ const hooks = Reflect.getMetadata(AFTER_KEY, target, propertyKey) || [];
456
+ hooks.push(fn);
457
+ Reflect.defineMetadata(AFTER_KEY, hooks, target, propertyKey);
458
+ };
459
+ }
460
+ /**
461
+ * Decorator that requires specific roles for accessing a route.
462
+ * Must be used with authentication middleware.
463
+ *
464
+ * @param roles - List of roles that can access this route
465
+ * @returns Method decorator
466
+ *
467
+ * @example
468
+ * ```ts
469
+ * @Get('/admin/settings')
470
+ * @Roles('admin', 'superuser')
471
+ * getSettings() {
472
+ * // Only admins and superusers can access
473
+ * return { settings: [...] };
474
+ * }
475
+ * ```
476
+ */
477
+ export function Roles(...roles) {
478
+ return (target, propertyKey, _descriptor) => {
479
+ Reflect.defineMetadata(ROLES_KEY, roles, target, propertyKey);
480
+ };
481
+ }
482
+ /**
483
+ * Decorator that redirects to another URL.
484
+ *
485
+ * @param url - URL to redirect to (can be absolute or relative)
486
+ * @param statusCode - HTTP status code for redirect (default: 302)
487
+ * @returns Method decorator
488
+ *
489
+ * @example
490
+ * ```ts
491
+ * @Get('/old-path')
492
+ * @Redirect('/new-path', 301)
493
+ * redirectToNewPath() {
494
+ * // This method won't be executed; automatic redirect happens
495
+ * }
496
+ *
497
+ * @Get('/dynamic-redirect')
498
+ * @Redirect()
499
+ * getDynamicRedirect() {
500
+ * // Return an object with url and optionally statusCode
501
+ * return { url: '/calculated-path', statusCode: 307 };
502
+ * }
503
+ * ```
504
+ */
505
+ export function Redirect(url, statusCode = 302) {
506
+ return (target, propertyKey, descriptor) => {
507
+ // Store the redirect information in metadata
508
+ Reflect.defineMetadata(REDIRECT_KEY, { url, statusCode }, target, propertyKey);
509
+ return descriptor;
510
+ };
511
+ }
512
+ /**
513
+ * Decorator that adds caching to a route response.
514
+ *
515
+ * @param ttlSeconds - Time to live in seconds for the cache
516
+ * @returns Method decorator
517
+ *
518
+ * @example
519
+ * ```ts
520
+ * @Get('/data')
521
+ * @Cache(300) // Cache for 5 minutes
522
+ * getData() {
523
+ * return { data: 'expensive operation result' };
524
+ * }
525
+ * ```
526
+ */
527
+ export function Cache(ttlSeconds) {
528
+ return (target, propertyKey, _descriptor) => {
529
+ Reflect.defineMetadata(CACHE_KEY, { ttlSeconds }, target, propertyKey);
530
+ };
531
+ }
532
+ /**
533
+ * Decorator that applies rate limiting to a route.
534
+ * Note: Requires 'express-rate-limit' package to be installed.
535
+ *
536
+ * @param limit - Maximum number of requests allowed in the window
537
+ * @param windowMs - Time window in milliseconds
538
+ * @returns Method decorator
539
+ *
540
+ * Default Options:
541
+ * - standardHeaders: true
542
+ * - legacyHeaders: false
543
+ *
544
+ * @example
545
+ * ```ts
546
+ * @Post('/login')
547
+ * @RateLimit({ max: 5, windowMs: 60000, standardHeaders: true, legacyHeaders: false }) // 5 requests per minute
548
+ * login(@Body() credentials: LoginDto) {
549
+ * return this.authService.login(credentials);
550
+ * }
551
+ * ```
552
+ */
553
+ export function RateLimit(options) {
554
+ const opts = Object.assign({ standardHeaders: true, legacyHeaders: false }, options);
555
+ return (target, propertyKey, _descriptor) => {
556
+ Reflect.defineMetadata(RATE_LIMIT_KEY, opts, target, propertyKey);
557
+ };
558
+ }
559
+ /**
560
+ * Decorator that sets the content type for the response.
561
+ *
562
+ * @param type - MIME type for the response
563
+ * @returns Method decorator
564
+ *
565
+ * @example
566
+ * ```ts
567
+ * @Get('/download')
568
+ * @ContentType('application/pdf')
569
+ * downloadPdf() {
570
+ * return this.fileService.generatePdf();
571
+ * }
572
+ * ```
573
+ */
574
+ export function ContentType(type) {
575
+ return (target, propertyKey, _descriptor) => {
576
+ Reflect.defineMetadata(CONTENT_TYPE_KEY, { type }, target, propertyKey);
577
+ };
578
+ }
579
+ /**
580
+ * Decorator that adds API versioning to a route.
581
+ *
582
+ * @param version - Version string for the API endpoint
583
+ * @param options - Versioning options
584
+ * @returns Method decorator
585
+ *
586
+ * Default Options:
587
+ * - addPrefix: true
588
+ * - addHeader: true
589
+ * - headerName: 'X-API-Version'
590
+ *
591
+ * @example
592
+ * ```ts
593
+ *
594
+ * @Get('/users')
595
+ * @Version('v2')
596
+ * getUsersV2() {
597
+ * return this.userService.findAllV2();
598
+ * }
599
+ *
600
+ * @Get('/users')
601
+ * @Version('v2', { addPrefix: true, addHeader: true, headerName: 'X-API-Version' })
602
+ * getUsersV2() {
603
+ * // Route becomes /v2/users
604
+ * return this.userService.findAllV2();
605
+ * }
606
+ * ```
607
+ */
608
+ export function Version(version, options) {
609
+ const opts = Object.assign({ addPrefix: true, addHeader: true, headerName: 'X-API-Version' }, options);
610
+ return (target, propertyKey, _descriptor) => {
611
+ Reflect.defineMetadata(VERSION_KEY, { version, options: opts }, target, propertyKey);
612
+ };
613
+ }
614
+ /**
615
+ * Decorator that sets a timeout for route execution.
616
+ *
617
+ * @param ms - Timeout in milliseconds
618
+ * @returns Method decorator
619
+ *
620
+ * @example
621
+ * ```ts
622
+ * @Get('/slow-operation')
623
+ * @Timeout(30000) // 30 second timeout
624
+ * slowOperation() {
625
+ * return this.heavyService.processData();
626
+ * }
627
+ * ```
628
+ */
629
+ export function Timeout(ms) {
630
+ return (target, propertyKey, _descriptor) => {
631
+ Reflect.defineMetadata(TIMEOUT_KEY, { ms }, target, propertyKey);
632
+ };
633
+ }
634
+ /**
635
+ * Decorator that adds comprehensive logging to a route.
636
+ *
637
+ * @param options - Logging configuration options
638
+ * @returns Method decorator
639
+ *
640
+ * Default Options:
641
+ * - logEntry: true
642
+ * - logExit: true
643
+ * - logBody: false
644
+ * - logParams: false
645
+ * - logResponse: false
646
+ *
647
+ * @example
648
+ * ```ts
649
+ * @Post('/users')
650
+ * @Log({
651
+ * logEntry: true,
652
+ * logExit: true,
653
+ * logBody: true,
654
+ * logParams: true,
655
+ * logResponse: false
656
+ * })
657
+ * createUser(@Body() userData: any) {
658
+ * return this.userService.create(userData);
659
+ * }
660
+ * ```
661
+ */
662
+ export function Log(options) {
663
+ return (target, propertyKey, _descriptor) => {
664
+ const config = Object.assign({ logEntry: true, logExit: true, logBody: false, logParams: false, logResponse: false }, options);
665
+ Reflect.defineMetadata(LOG_KEY, config, target, propertyKey);
666
+ };
667
+ }
668
+ /**
669
+ * Registers all controller classes with the provided router.
670
+ * This function processes all decorators and sets up the Express routes.
671
+ *
672
+ * @param router - Express router instance
673
+ * @param controllers - Array of controller classes
674
+ */
675
+ export function registerControllers(router, controllers) {
676
+ controllers.forEach(ControllerClass => {
677
+ const instance = new ControllerClass();
678
+ const basePath = Reflect.getMetadata('basePath', ControllerClass) || '';
679
+ const routes = Reflect.getMetadata(ROUTES_KEY, ControllerClass) || [];
680
+ // Get controller-level decorators (fallback values)
681
+ const controllerRateLimit = Reflect.getMetadata(RATE_LIMIT_KEY, ControllerClass);
682
+ const controllerCache = Reflect.getMetadata(CACHE_KEY, ControllerClass);
683
+ const controllerTimeout = Reflect.getMetadata(TIMEOUT_KEY, ControllerClass);
684
+ const controllerVersion = Reflect.getMetadata(VERSION_KEY, ControllerClass);
685
+ const controllerRoles = Reflect.getMetadata(ROLES_KEY, ControllerClass);
686
+ const controllerLogConfig = Reflect.getMetadata(LOG_KEY, ControllerClass);
687
+ const controllerHeaders = Reflect.getMetadata(HEADER_KEY, ControllerClass) || {};
688
+ routes.forEach(({ path, method, handlerName }) => {
689
+ var _a;
690
+ const middlewares = Reflect.getMetadata(MIDDLEWARE_KEY, instance, handlerName) || [];
691
+ const params = Reflect.getMetadata(PARAMS_KEY, instance, handlerName) || [];
692
+ const httpCode = Reflect.getMetadata(HTTP_CODE_KEY, instance, handlerName);
693
+ // Merge controller-level and method-level headers
694
+ const methodHeaders = Reflect.getMetadata(HEADER_KEY, instance, handlerName) || {};
695
+ const headers = Object.assign(Object.assign({}, controllerHeaders), methodHeaders);
696
+ const beforeHooks = Reflect.getMetadata(BEFORE_KEY, instance, handlerName) || [];
697
+ const afterHooks = Reflect.getMetadata(AFTER_KEY, instance, handlerName) || [];
698
+ const redirect = Reflect.getMetadata(REDIRECT_KEY, instance, handlerName);
699
+ const contentType = Reflect.getMetadata(CONTENT_TYPE_KEY, instance, handlerName);
700
+ // Use method-level decorators if present, otherwise fall back to controller-level
701
+ const roles = Reflect.getMetadata(ROLES_KEY, instance, handlerName) || controllerRoles || [];
702
+ const cache = Reflect.getMetadata(CACHE_KEY, instance, handlerName) || controllerCache;
703
+ const rateLimitOptions = Reflect.getMetadata(RATE_LIMIT_KEY, instance, handlerName) || controllerRateLimit;
704
+ const version = Reflect.getMetadata(VERSION_KEY, instance, handlerName) || controllerVersion;
705
+ const timeout = Reflect.getMetadata(TIMEOUT_KEY, instance, handlerName) || controllerTimeout;
706
+ const logConfig = Reflect.getMetadata(LOG_KEY, instance, handlerName) || controllerLogConfig;
707
+ // Create rate limiter for this specific route if needed
708
+ let rateLimiter = null;
709
+ if (rateLimitOptions) {
710
+ try {
711
+ rateLimiter = rateLimiterCache.get(rateLimitOptions);
712
+ }
713
+ catch (err) {
714
+ getLogger().warn({ err }, 'express-rate-limit not available, skipping rate limiting for this route');
715
+ }
716
+ }
717
+ let finalPath = path;
718
+ if ((_a = version === null || version === void 0 ? void 0 : version.options) === null || _a === void 0 ? void 0 : _a.addPrefix) {
719
+ finalPath = `/${version.version}${path}`;
720
+ }
721
+ const handler = async (req, res, next) => {
722
+ var _a, _b, _c, _d;
723
+ // Set start time for duration tracking
724
+ req['startTime'] = Date.now();
725
+ let timeoutId;
726
+ let timedOut = false;
727
+ try {
728
+ // Handle timeout setup
729
+ if (timeout) {
730
+ timeoutId = setTimeout(() => {
731
+ if (!res.headersSent && !timedOut) {
732
+ timedOut = true;
733
+ const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.REQUEST_TIMEOUT, 'Request timed out');
734
+ res.status(HttpStatusCodes.REQUEST_TIMEOUT).json(errorResponse);
735
+ }
736
+ }, timeout.ms);
737
+ }
738
+ if (timedOut)
739
+ return;
740
+ // Handle rate limiting
741
+ if (rateLimiter) {
742
+ await new Promise((resolve, reject) => {
743
+ rateLimiter(req, res, (err) => {
744
+ if (err)
745
+ reject(err);
746
+ else
747
+ resolve();
748
+ });
749
+ });
750
+ }
751
+ // Handle content type
752
+ if (!res.headersSent && contentType) {
753
+ res.setHeader('Content-Type', contentType.type);
754
+ }
755
+ // Handle versioning header
756
+ if (((_a = version === null || version === void 0 ? void 0 : version.options) === null || _a === void 0 ? void 0 : _a.addHeader) && ((_b = version === null || version === void 0 ? void 0 : version.options) === null || _b === void 0 ? void 0 : _b.headerName) && (version === null || version === void 0 ? void 0 : version.version)) {
757
+ if (!res.headersSent) {
758
+ res.setHeader(version.options.headerName, version.version);
759
+ }
760
+ }
761
+ // Handle caching
762
+ if (cache && !res.headersSent) {
763
+ res.setHeader('Cache-Control', `public, max-age=${cache.ttlSeconds}`);
764
+ }
765
+ // Handle logging - entry
766
+ if (logConfig === null || logConfig === void 0 ? void 0 : logConfig.logEntry) {
767
+ const logger = getLogger();
768
+ const logData = {
769
+ method: req.method,
770
+ url: req.originalUrl || req.url,
771
+ userAgent: req.get('User-Agent')
772
+ };
773
+ if (logConfig.logParams) {
774
+ logData.params = req.params;
775
+ logData.query = req.query;
776
+ }
777
+ if (logConfig.logBody)
778
+ logData.body = req.body;
779
+ logger.info({ entry: logData }, 'Route Entry:');
780
+ }
781
+ // Handle roles-based access control
782
+ if (roles.length && !((_d = (_c = req === null || req === void 0 ? void 0 : req.user) === null || _c === void 0 ? void 0 : _c.roles) === null || _d === void 0 ? void 0 : _d.some((role) => roles.includes(role)))) {
783
+ const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.FORBIDDEN, 'Forbidden Insufficient Roles');
784
+ res.status(HttpStatusCodes.FORBIDDEN).json(errorResponse);
785
+ if (timeoutId) {
786
+ clearTimeout(timeoutId);
787
+ }
788
+ return;
789
+ }
790
+ // Process static redirect if configured
791
+ if (redirect && redirect.url) {
792
+ if (timeoutId) {
793
+ clearTimeout(timeoutId);
794
+ }
795
+ return res.redirect(redirect.statusCode, redirect.url);
796
+ }
797
+ for (const fn of beforeHooks)
798
+ await fn(req, res);
799
+ const args = [];
800
+ if (params.length) {
801
+ params.forEach(({ index, type, key }) => {
802
+ var _a;
803
+ switch (type) {
804
+ case 'query':
805
+ args[index] = key ? req.query[key] : req.query;
806
+ break;
807
+ case 'param':
808
+ args[index] = key ? req.params[key] : req.params;
809
+ break;
810
+ case 'body':
811
+ args[index] = key ? (_a = req.body) === null || _a === void 0 ? void 0 : _a[key] : req.body;
812
+ break;
813
+ case 'req':
814
+ args[index] = req;
815
+ break;
816
+ case 'res':
817
+ args[index] = res;
818
+ break;
819
+ }
820
+ });
821
+ }
822
+ const result = instance[handlerName](...args);
823
+ // Support both sync and async handlers
824
+ const awaited = result instanceof Promise ? await result : result;
825
+ // Clear timeout if operation completed
826
+ if (timeoutId) {
827
+ clearTimeout(timeoutId);
828
+ }
829
+ if (timedOut)
830
+ return;
831
+ // Handle dynamic redirects
832
+ if (redirect && awaited && typeof awaited === 'object' && 'url' in awaited) {
833
+ const redirectUrl = awaited.url;
834
+ const redirectStatus = awaited.statusCode || redirect.statusCode;
835
+ return res.redirect(redirectStatus, redirectUrl);
836
+ }
837
+ if (!res.headersSent && typeof awaited !== 'undefined') {
838
+ if (httpCode)
839
+ res.status(httpCode);
840
+ for (const [k, v] of Object.entries(headers)) {
841
+ const normalized = normalizeHeaderValue(v);
842
+ if (typeof normalized !== 'undefined') {
843
+ res.set(k, normalized);
844
+ }
845
+ }
846
+ res.json(awaited);
847
+ }
848
+ // Handle logging - exit
849
+ if (logConfig === null || logConfig === void 0 ? void 0 : logConfig.logExit) {
850
+ const logger = getLogger();
851
+ const logData = {
852
+ method: req.method,
853
+ url: req.originalUrl || req.url,
854
+ statusCode: res.statusCode,
855
+ duration: `${Date.now() - req.startTime}ms`
856
+ };
857
+ if (logConfig.logResponse)
858
+ logData.response = awaited;
859
+ logger.info({ exit: logData }, 'Route Exit:');
860
+ }
861
+ for (const fn of afterHooks)
862
+ await fn(req, res, awaited);
863
+ }
864
+ catch (err) {
865
+ if (timeoutId) {
866
+ clearTimeout(timeoutId);
867
+ }
868
+ next(err);
869
+ }
870
+ };
871
+ router[method](basePath + finalPath, ...middlewares, handler);
872
+ });
873
+ });
874
+ }
875
+ // Export for testing purposes
876
+ export { rateLimiterCache };
877
+ //# sourceMappingURL=decorators.utils.js.map