@catbee/utils 1.0.5 → 2.0.0-next.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 (121) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +27 -27
  3. package/array/array.utils.d.ts +191 -0
  4. package/array/index.cjs +246 -0
  5. package/array/index.d.ts +25 -0
  6. package/array/index.mjs +228 -0
  7. package/async/async.utils.d.ts +296 -0
  8. package/async/index.cjs +428 -0
  9. package/async/index.d.ts +25 -0
  10. package/async/index.mjs +407 -0
  11. package/cache/cache.utils.d.ts +176 -0
  12. package/cache/index.cjs +292 -0
  13. package/cache/index.d.ts +25 -0
  14. package/cache/index.mjs +290 -0
  15. package/config/config.d.ts +57 -0
  16. package/config/index.cjs +136 -0
  17. package/config/index.d.ts +26 -0
  18. package/config/index.mjs +131 -0
  19. package/context-store/context-store.utils.d.ts +212 -0
  20. package/context-store/index.cjs +267 -0
  21. package/context-store/index.d.ts +25 -0
  22. package/context-store/index.mjs +261 -0
  23. package/crypto/crypto.utils.d.ts +183 -0
  24. package/crypto/index.cjs +182 -0
  25. package/crypto/index.d.ts +25 -0
  26. package/crypto/index.mjs +166 -0
  27. package/date/date.utils.d.ts +190 -0
  28. package/date/index.cjs +295 -0
  29. package/date/index.d.ts +25 -0
  30. package/date/index.mjs +283 -0
  31. package/decorators/decorators.utils.d.ts +705 -0
  32. package/decorators/index.cjs +913 -0
  33. package/decorators/index.d.ts +25 -0
  34. package/decorators/index.mjs +872 -0
  35. package/dir/dir.utils.d.ts +216 -0
  36. package/dir/index.cjs +416 -0
  37. package/dir/index.d.ts +25 -0
  38. package/dir/index.mjs +389 -0
  39. package/env/env.utils.d.ts +400 -0
  40. package/env/index.cjs +761 -0
  41. package/env/index.d.ts +25 -0
  42. package/env/index.mjs +758 -0
  43. package/exception/exception.utils.d.ts +253 -0
  44. package/exception/index.cjs +362 -0
  45. package/exception/index.d.ts +25 -0
  46. package/exception/index.mjs +338 -0
  47. package/fs/fs.utils.d.ts +196 -0
  48. package/fs/index.cjs +253 -0
  49. package/fs/index.d.ts +25 -0
  50. package/fs/index.mjs +228 -0
  51. package/http-status-codes/http-status-codes.d.ts +289 -0
  52. package/http-status-codes/index.cjs +96 -0
  53. package/http-status-codes/index.d.ts +25 -0
  54. package/http-status-codes/index.mjs +94 -0
  55. package/id/id.utils.d.ts +59 -0
  56. package/id/index.cjs +62 -0
  57. package/id/index.d.ts +25 -0
  58. package/id/index.mjs +56 -0
  59. package/index.cjs +218 -0
  60. package/index.d.ts +51 -0
  61. package/index.mjs +51 -0
  62. package/logger/index.cjs +334 -0
  63. package/logger/index.d.ts +25 -0
  64. package/logger/index.mjs +313 -0
  65. package/logger/logger.utils.d.ts +210 -0
  66. package/middleware/index.cjs +177 -0
  67. package/middleware/index.d.ts +25 -0
  68. package/middleware/index.mjs +170 -0
  69. package/middleware/middleware.utils.d.ts +123 -0
  70. package/obj/index.cjs +317 -0
  71. package/obj/index.d.ts +25 -0
  72. package/obj/index.mjs +301 -0
  73. package/obj/obj.utils.d.ts +156 -0
  74. package/package.json +172 -20
  75. package/performance/index.cjs +231 -0
  76. package/performance/index.d.ts +25 -0
  77. package/performance/index.mjs +225 -0
  78. package/performance/performance.utils.d.ts +159 -0
  79. package/request/index.cjs +202 -0
  80. package/request/index.d.ts +26 -0
  81. package/request/index.mjs +194 -0
  82. package/request/request.utils.d.ts +109 -0
  83. package/response/index.cjs +234 -0
  84. package/response/index.d.ts +26 -0
  85. package/response/index.mjs +222 -0
  86. package/response/response.utils.d.ts +186 -0
  87. package/server/index.cjs +1627 -0
  88. package/server/index.d.ts +28 -0
  89. package/server/index.mjs +1617 -0
  90. package/server/server.builder.d.ts +531 -0
  91. package/server/server.d.ts +303 -0
  92. package/stream/index.cjs +151 -0
  93. package/stream/index.d.ts +25 -0
  94. package/stream/index.mjs +144 -0
  95. package/stream/stream.utils.d.ts +111 -0
  96. package/string/index.cjs +109 -0
  97. package/string/index.d.ts +25 -0
  98. package/string/index.mjs +95 -0
  99. package/string/string.utils.d.ts +124 -0
  100. package/type/index.cjs +129 -0
  101. package/type/index.d.ts +25 -0
  102. package/type/index.mjs +119 -0
  103. package/type/type.utils.d.ts +129 -0
  104. package/types/api-response.d.ts +175 -0
  105. package/types/common.d.ts +148 -0
  106. package/types/config.d.ts +88 -0
  107. package/types/index.cjs +34 -0
  108. package/types/index.d.ts +28 -0
  109. package/types/index.mjs +32 -0
  110. package/types/server.d.ts +291 -0
  111. package/url/index.cjs +201 -0
  112. package/url/index.d.ts +25 -0
  113. package/url/index.mjs +189 -0
  114. package/url/url.utils.d.ts +164 -0
  115. package/validate/index.cjs +212 -0
  116. package/validate/index.d.ts +25 -0
  117. package/validate/index.mjs +188 -0
  118. package/validate/validate.utils.d.ts +200 -0
  119. package/build/index.cjs +0 -7579
  120. package/build/index.d.ts +0 -5774
  121. package/build/index.mjs +0 -7274
@@ -0,0 +1,872 @@
1
+ /*
2
+ * The MIT License
3
+ *
4
+ * Copyright (c) 2025 Catbee Technologies. https://catbee.in/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
+
25
+ import 'reflect-metadata';
26
+ import { getLogger } from '@catbee/utils/logger';
27
+ import { createFinalErrorResponse } from '@catbee/utils/response';
28
+ import { HttpStatusCodes } from '@catbee/utils/http-status-codes';
29
+ import { TTLCache } from '@catbee/utils/cache';
30
+ import { BadRequestException } from '@catbee/utils/exception';
31
+ import { optionalRequire } from '@catbee/utils/async';
32
+ import { DependencyErrors } from '@catbee/utils/server';
33
+
34
+ var __defProp = Object.defineProperty;
35
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
36
+ var ROUTES_KEY = Symbol("routes");
37
+ var MIDDLEWARE_KEY = Symbol("middlewares");
38
+ var PARAMS_KEY = Symbol("params");
39
+ var HTTP_CODE_KEY = Symbol("httpCode");
40
+ var HEADER_KEY = Symbol("headers");
41
+ var BEFORE_KEY = Symbol("before");
42
+ var AFTER_KEY = Symbol("after");
43
+ var ROLES_KEY = Symbol("roles");
44
+ var REDIRECT_KEY = Symbol("redirect");
45
+ var CACHE_KEY = Symbol("cache");
46
+ var RATE_LIMIT_KEY = Symbol("rateLimit");
47
+ var CONTENT_TYPE_KEY = Symbol("contentType");
48
+ var VERSION_KEY = Symbol("version");
49
+ var TIMEOUT_KEY = Symbol("timeout");
50
+ var LOG_KEY = Symbol("log");
51
+ var RateLimiterCache = class RateLimiterCache2 {
52
+ static {
53
+ __name(this, "RateLimiterCache");
54
+ }
55
+ rateLimit;
56
+ cache;
57
+ constructor(maxSize = 100, ttlMs = 5 * 60 * 1e3) {
58
+ this.cache = new TTLCache({
59
+ maxSize,
60
+ ttlMs
61
+ });
62
+ const rateLimitModule = optionalRequire("express-rate-limit");
63
+ if (rateLimitModule) this.rateLimit = rateLimitModule.rateLimit;
64
+ }
65
+ generateKey(options) {
66
+ return `${options.max}:${options.windowMs}:${options.standardHeaders}:${options.legacyHeaders}`;
67
+ }
68
+ get(options) {
69
+ const key = this.generateKey(options);
70
+ const cached = this.cache.get(key);
71
+ if (cached) {
72
+ return cached.limiter;
73
+ }
74
+ if (!this.rateLimit) {
75
+ throw new Error(DependencyErrors["express-rate-limit"]);
76
+ }
77
+ const limiter = this.rateLimit({
78
+ ...options,
79
+ handler: /* @__PURE__ */ __name((req, res) => {
80
+ const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.TOO_MANY_REQUESTS, "Too Many Requests");
81
+ res.status(HttpStatusCodes.TOO_MANY_REQUESTS).json(errorResponse);
82
+ }, "handler")
83
+ });
84
+ this.cache.set(key, {
85
+ limiter,
86
+ config: key
87
+ });
88
+ return limiter;
89
+ }
90
+ clear() {
91
+ this.cache.clear();
92
+ }
93
+ size() {
94
+ return this.cache.size();
95
+ }
96
+ destroy() {
97
+ this.cache.destroy();
98
+ }
99
+ };
100
+ var rateLimiterCache = new RateLimiterCache();
101
+ var DIContainer = class {
102
+ static {
103
+ __name(this, "DIContainer");
104
+ }
105
+ instances = /* @__PURE__ */ new Map();
106
+ constructing = /* @__PURE__ */ new Map();
107
+ propertyInjections = /* @__PURE__ */ new Map();
108
+ register(target) {
109
+ if (!this.instances.has(target) && !this.constructing.has(target)) ;
110
+ }
111
+ /**
112
+ * Register a property injection to be resolved when the target class is instantiated
113
+ */
114
+ registerPropertyInjection(target, propertyKey, injectClass) {
115
+ const targetClass = target.constructor;
116
+ if (!this.propertyInjections.has(targetClass)) {
117
+ this.propertyInjections.set(targetClass, []);
118
+ }
119
+ this.propertyInjections.get(targetClass).push({
120
+ targetClass: injectClass,
121
+ propertyKey
122
+ });
123
+ }
124
+ get(target) {
125
+ if (this.instances.has(target)) {
126
+ return this.instances.get(target);
127
+ }
128
+ if (this.constructing.has(target)) {
129
+ return this.constructing.get(target);
130
+ }
131
+ let proxy = {};
132
+ this.constructing.set(target, proxy);
133
+ const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
134
+ const dependencies = paramTypes.map((dep) => this.get(dep));
135
+ const instance = new target(...dependencies);
136
+ this.applyPropertyInjections(target, instance);
137
+ Object.assign(proxy, instance);
138
+ this.instances.set(target, proxy);
139
+ this.constructing.delete(target);
140
+ Object.setPrototypeOf(proxy, target.prototype);
141
+ return proxy;
142
+ }
143
+ applyPropertyInjections(targetClass, instance) {
144
+ const injections = this.propertyInjections.get(targetClass) || [];
145
+ for (const injection of injections) {
146
+ const dependency = this.get(injection.targetClass);
147
+ instance[injection.propertyKey] = dependency;
148
+ }
149
+ }
150
+ clear() {
151
+ this.instances.clear();
152
+ this.constructing.clear();
153
+ this.propertyInjections.clear();
154
+ }
155
+ };
156
+ var diContainer = new DIContainer();
157
+ function normalizeHeaderValue(value) {
158
+ if (typeof value === "undefined") return void 0;
159
+ if (typeof value === "string") return value;
160
+ if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
161
+ return value;
162
+ }
163
+ return String(value);
164
+ }
165
+ __name(normalizeHeaderValue, "normalizeHeaderValue");
166
+ function Injectable() {
167
+ return (target) => {
168
+ Reflect.defineMetadata("injectable", true, target);
169
+ diContainer.register(target);
170
+ };
171
+ }
172
+ __name(Injectable, "Injectable");
173
+ function Inject(targetClass) {
174
+ return (target, propertyKey) => {
175
+ diContainer.registerPropertyInjection(target, propertyKey, targetClass);
176
+ Object.defineProperty(target, propertyKey, {
177
+ configurable: true,
178
+ get: /* @__PURE__ */ __name(function() {
179
+ const value = Object.getOwnPropertyDescriptor(this, propertyKey)?.value;
180
+ if (value !== void 0) return value;
181
+ const injectedValue = diContainer.get(targetClass);
182
+ Object.defineProperty(this, propertyKey, {
183
+ value: injectedValue,
184
+ writable: true,
185
+ configurable: true
186
+ });
187
+ return injectedValue;
188
+ }, "get"),
189
+ set: /* @__PURE__ */ __name(function(value) {
190
+ Object.defineProperty(this, propertyKey, {
191
+ value,
192
+ writable: true,
193
+ configurable: true
194
+ });
195
+ }, "set")
196
+ });
197
+ };
198
+ }
199
+ __name(Inject, "Inject");
200
+ function inject(targetClass) {
201
+ return diContainer.get(targetClass);
202
+ }
203
+ __name(inject, "inject");
204
+ function createRouteDecorator(method) {
205
+ return (path) => {
206
+ return (target, propertyKey, _descriptor) => {
207
+ const routes = Reflect.getMetadata(ROUTES_KEY, target.constructor) || [];
208
+ routes.push({
209
+ path,
210
+ method,
211
+ handlerName: propertyKey
212
+ });
213
+ Reflect.defineMetadata(ROUTES_KEY, routes, target.constructor);
214
+ };
215
+ };
216
+ }
217
+ __name(createRouteDecorator, "createRouteDecorator");
218
+ var Get = createRouteDecorator("get");
219
+ var Post = createRouteDecorator("post");
220
+ var Put = createRouteDecorator("put");
221
+ var Patch = createRouteDecorator("patch");
222
+ var Delete = createRouteDecorator("delete");
223
+ var Options = createRouteDecorator("options");
224
+ var Head = createRouteDecorator("head");
225
+ var Trace = createRouteDecorator("trace");
226
+ var Connect = createRouteDecorator("connect");
227
+ function Controller(basePath) {
228
+ return (target) => {
229
+ Reflect.defineMetadata("basePath", basePath, target);
230
+ };
231
+ }
232
+ __name(Controller, "Controller");
233
+ function Use(...middlewares) {
234
+ return (target, propertyKey, _descriptor) => {
235
+ if (typeof propertyKey === "undefined") {
236
+ const existing = Reflect.getMetadata(MIDDLEWARE_KEY, target) || [];
237
+ Reflect.defineMetadata(MIDDLEWARE_KEY, [
238
+ ...existing,
239
+ ...middlewares
240
+ ], target);
241
+ } else {
242
+ const existing = Reflect.getMetadata(MIDDLEWARE_KEY, target, propertyKey) || [];
243
+ Reflect.defineMetadata(MIDDLEWARE_KEY, [
244
+ ...existing,
245
+ ...middlewares
246
+ ], target, propertyKey);
247
+ }
248
+ };
249
+ }
250
+ __name(Use, "Use");
251
+ function defineParamMetadata(target, propertyKey, parameterIndex, type, key) {
252
+ const params = Reflect.getMetadata(PARAMS_KEY, target, propertyKey) || [];
253
+ params.push({
254
+ index: parameterIndex,
255
+ type,
256
+ key
257
+ });
258
+ params.sort((a, b) => a.index - b.index);
259
+ Reflect.defineMetadata(PARAMS_KEY, params, target, propertyKey);
260
+ }
261
+ __name(defineParamMetadata, "defineParamMetadata");
262
+ function createParamDecorator(type, key) {
263
+ return (paramKey) => {
264
+ return (target, propertyKey, parameterIndex) => {
265
+ defineParamMetadata(target, propertyKey, parameterIndex, type, paramKey ?? key);
266
+ };
267
+ };
268
+ }
269
+ __name(createParamDecorator, "createParamDecorator");
270
+ function createParamDecoratorWithoutParam(type) {
271
+ return () => {
272
+ return (target, propertyKey, parameterIndex) => {
273
+ defineParamMetadata(target, propertyKey, parameterIndex, type, void 0);
274
+ };
275
+ };
276
+ }
277
+ __name(createParamDecoratorWithoutParam, "createParamDecoratorWithoutParam");
278
+ function createApiUrlParamDecorator(type, key) {
279
+ return (paramKey, options) => {
280
+ return (target, propertyKey, parameterIndex) => {
281
+ const params = Reflect.getMetadata(PARAMS_KEY, target, propertyKey) || [];
282
+ let paramOptions = void 0;
283
+ if (typeof options === "object") {
284
+ paramOptions = {};
285
+ paramOptions.type = "string";
286
+ paramOptions.dataType = "single";
287
+ paramOptions.delimiter = ",";
288
+ paramOptions.required = false;
289
+ paramOptions.throwError = true;
290
+ paramOptions = {
291
+ ...paramOptions,
292
+ ...options
293
+ };
294
+ }
295
+ params.push({
296
+ index: parameterIndex,
297
+ type,
298
+ key: paramKey || key,
299
+ options: paramOptions
300
+ });
301
+ params.sort((a, b) => a.index - b.index);
302
+ Reflect.defineMetadata(PARAMS_KEY, params, target, propertyKey);
303
+ };
304
+ };
305
+ }
306
+ __name(createApiUrlParamDecorator, "createApiUrlParamDecorator");
307
+ var Query = createApiUrlParamDecorator("query");
308
+ var Param = createApiUrlParamDecorator("param");
309
+ var Body = createParamDecorator("body");
310
+ var ReqLogger = createParamDecoratorWithoutParam("logger");
311
+ var ReqId = createParamDecoratorWithoutParam("reqId");
312
+ var ReqHeader = createParamDecorator("reqHeader");
313
+ var ReqCookie = createParamDecorator("cookie");
314
+ var Req = createParamDecoratorWithoutParam("req");
315
+ var Res = createParamDecoratorWithoutParam("res");
316
+ function HttpCode(status) {
317
+ return (target, propertyKey, _descriptor) => {
318
+ Reflect.defineMetadata(HTTP_CODE_KEY, status, target, propertyKey);
319
+ };
320
+ }
321
+ __name(HttpCode, "HttpCode");
322
+ function Header(name, value) {
323
+ return Headers(name, value);
324
+ }
325
+ __name(Header, "Header");
326
+ function Headers(headers, value) {
327
+ return (target, propertyKey) => {
328
+ if (typeof propertyKey === "undefined") {
329
+ const existing = Reflect.getMetadata(HEADER_KEY, target) || {};
330
+ const newHeaders = typeof headers === "string" ? {
331
+ [headers]: value
332
+ } : headers;
333
+ Reflect.defineMetadata(HEADER_KEY, {
334
+ ...existing,
335
+ ...newHeaders
336
+ }, target);
337
+ } else {
338
+ const existing = Reflect.getMetadata(HEADER_KEY, target, propertyKey) || {};
339
+ const newHeaders = typeof headers === "string" ? {
340
+ [headers]: value
341
+ } : headers;
342
+ Reflect.defineMetadata(HEADER_KEY, {
343
+ ...existing,
344
+ ...newHeaders
345
+ }, target, propertyKey);
346
+ }
347
+ };
348
+ }
349
+ __name(Headers, "Headers");
350
+ function Before(fn) {
351
+ return (target, propertyKey, _descriptor) => {
352
+ if (typeof propertyKey === "undefined") {
353
+ const hooks = Reflect.getMetadata(BEFORE_KEY, target) || [];
354
+ hooks.push(fn);
355
+ Reflect.defineMetadata(BEFORE_KEY, hooks, target);
356
+ } else {
357
+ const hooks = Reflect.getMetadata(BEFORE_KEY, target, propertyKey) || [];
358
+ hooks.push(fn);
359
+ Reflect.defineMetadata(BEFORE_KEY, hooks, target, propertyKey);
360
+ }
361
+ };
362
+ }
363
+ __name(Before, "Before");
364
+ function After(fn) {
365
+ return (target, propertyKey, _descriptor) => {
366
+ if (typeof propertyKey === "undefined") {
367
+ const hooks = Reflect.getMetadata(AFTER_KEY, target) || [];
368
+ hooks.push(fn);
369
+ Reflect.defineMetadata(AFTER_KEY, hooks, target);
370
+ } else {
371
+ const hooks = Reflect.getMetadata(AFTER_KEY, target, propertyKey) || [];
372
+ hooks.push(fn);
373
+ Reflect.defineMetadata(AFTER_KEY, hooks, target, propertyKey);
374
+ }
375
+ };
376
+ }
377
+ __name(After, "After");
378
+ function Roles(...roles) {
379
+ return (target, propertyKey, _descriptor) => {
380
+ if (typeof propertyKey === "undefined") {
381
+ Reflect.defineMetadata(ROLES_KEY, roles, target);
382
+ } else {
383
+ Reflect.defineMetadata(ROLES_KEY, roles, target, propertyKey);
384
+ }
385
+ };
386
+ }
387
+ __name(Roles, "Roles");
388
+ function Redirect(url, statusCode = 302) {
389
+ return (target, propertyKey, descriptor) => {
390
+ Reflect.defineMetadata(REDIRECT_KEY, {
391
+ url,
392
+ statusCode
393
+ }, target, propertyKey);
394
+ return descriptor;
395
+ };
396
+ }
397
+ __name(Redirect, "Redirect");
398
+ function Cache(ttlSeconds) {
399
+ return (target, propertyKey, _descriptor) => {
400
+ if (typeof propertyKey === "undefined") {
401
+ Reflect.defineMetadata(CACHE_KEY, {
402
+ ttlSeconds
403
+ }, target);
404
+ } else {
405
+ Reflect.defineMetadata(CACHE_KEY, {
406
+ ttlSeconds
407
+ }, target, propertyKey);
408
+ }
409
+ };
410
+ }
411
+ __name(Cache, "Cache");
412
+ function RateLimit(options) {
413
+ const opts = {
414
+ standardHeaders: true,
415
+ legacyHeaders: false,
416
+ ...options
417
+ };
418
+ return (target, propertyKey, _descriptor) => {
419
+ if (typeof propertyKey === "undefined") {
420
+ Reflect.defineMetadata(RATE_LIMIT_KEY, opts, target);
421
+ } else {
422
+ Reflect.defineMetadata(RATE_LIMIT_KEY, opts, target, propertyKey);
423
+ }
424
+ };
425
+ }
426
+ __name(RateLimit, "RateLimit");
427
+ function ContentType(type) {
428
+ return (target, propertyKey, _descriptor) => {
429
+ if (typeof propertyKey === "undefined") {
430
+ Reflect.defineMetadata(CONTENT_TYPE_KEY, {
431
+ type
432
+ }, target);
433
+ } else {
434
+ Reflect.defineMetadata(CONTENT_TYPE_KEY, {
435
+ type
436
+ }, target, propertyKey);
437
+ }
438
+ };
439
+ }
440
+ __name(ContentType, "ContentType");
441
+ function Version(version, options) {
442
+ const opts = {
443
+ addPrefix: true,
444
+ addHeader: true,
445
+ headerName: "X-API-Version",
446
+ ...options
447
+ };
448
+ return (target, propertyKey, _descriptor) => {
449
+ if (typeof propertyKey === "undefined") {
450
+ Reflect.defineMetadata(VERSION_KEY, {
451
+ version,
452
+ options: opts
453
+ }, target);
454
+ } else {
455
+ Reflect.defineMetadata(VERSION_KEY, {
456
+ version,
457
+ options: opts
458
+ }, target, propertyKey);
459
+ }
460
+ };
461
+ }
462
+ __name(Version, "Version");
463
+ function Timeout(ms) {
464
+ return (target, propertyKey, _descriptor) => {
465
+ if (typeof propertyKey === "undefined") {
466
+ Reflect.defineMetadata(TIMEOUT_KEY, {
467
+ ms
468
+ }, target);
469
+ } else {
470
+ Reflect.defineMetadata(TIMEOUT_KEY, {
471
+ ms
472
+ }, target, propertyKey);
473
+ }
474
+ };
475
+ }
476
+ __name(Timeout, "Timeout");
477
+ function Log(options) {
478
+ return (target, propertyKey, _descriptor) => {
479
+ const config = {
480
+ logEntry: true,
481
+ logExit: true,
482
+ logBody: false,
483
+ logParams: false,
484
+ logResponse: false,
485
+ ...options
486
+ };
487
+ if (typeof propertyKey === "undefined") {
488
+ Reflect.defineMetadata(LOG_KEY, config, target);
489
+ } else {
490
+ Reflect.defineMetadata(LOG_KEY, config, target, propertyKey);
491
+ }
492
+ };
493
+ }
494
+ __name(Log, "Log");
495
+ function registerControllers(router, controllers) {
496
+ controllers.forEach((ControllerClass) => {
497
+ if (!Reflect.getMetadata("injectable", ControllerClass)) {
498
+ Reflect.defineMetadata("injectable", true, ControllerClass);
499
+ diContainer.register(ControllerClass);
500
+ }
501
+ const instance = diContainer.get(ControllerClass);
502
+ let basePath = Reflect.getMetadata("basePath", ControllerClass) || "";
503
+ const routes = Reflect.getMetadata(ROUTES_KEY, ControllerClass) || [];
504
+ const controllerRateLimit = Reflect.getMetadata(RATE_LIMIT_KEY, ControllerClass);
505
+ const controllerCache = Reflect.getMetadata(CACHE_KEY, ControllerClass);
506
+ const controllerTimeout = Reflect.getMetadata(TIMEOUT_KEY, ControllerClass);
507
+ const controllerVersion = Reflect.getMetadata(VERSION_KEY, ControllerClass);
508
+ const controllerRoles = Reflect.getMetadata(ROLES_KEY, ControllerClass);
509
+ const controllerLogConfig = Reflect.getMetadata(LOG_KEY, ControllerClass);
510
+ const controllerHeaders = Reflect.getMetadata(HEADER_KEY, ControllerClass) || {};
511
+ const controllerMiddlewares = Reflect.getMetadata(MIDDLEWARE_KEY, ControllerClass) || [];
512
+ const controllerBeforeHooks = Reflect.getMetadata(BEFORE_KEY, ControllerClass) || [];
513
+ const controllerAfterHooks = Reflect.getMetadata(AFTER_KEY, ControllerClass) || [];
514
+ const controllerContentType = Reflect.getMetadata(CONTENT_TYPE_KEY, ControllerClass);
515
+ if (controllerVersion?.options?.addPrefix) {
516
+ basePath = `/${controllerVersion.version}${basePath || ""}`;
517
+ }
518
+ routes.forEach(({ path, method, handlerName }) => {
519
+ const methodMiddlewares = Reflect.getMetadata(MIDDLEWARE_KEY, instance, handlerName) || [];
520
+ const params = Reflect.getMetadata(PARAMS_KEY, instance, handlerName) || [];
521
+ const httpCode = Reflect.getMetadata(HTTP_CODE_KEY, instance, handlerName);
522
+ const methodHeaders = Reflect.getMetadata(HEADER_KEY, instance, handlerName) || {};
523
+ const headers = {
524
+ ...controllerHeaders,
525
+ ...methodHeaders
526
+ };
527
+ const middlewares = [
528
+ ...controllerMiddlewares,
529
+ ...methodMiddlewares
530
+ ];
531
+ const methodBeforeHooks = Reflect.getMetadata(BEFORE_KEY, instance, handlerName) || [];
532
+ const methodAfterHooks = Reflect.getMetadata(AFTER_KEY, instance, handlerName) || [];
533
+ const beforeHooks = [
534
+ ...controllerBeforeHooks,
535
+ ...methodBeforeHooks
536
+ ];
537
+ const afterHooks = [
538
+ ...methodAfterHooks,
539
+ ...controllerAfterHooks
540
+ ];
541
+ const redirect = Reflect.getMetadata(REDIRECT_KEY, instance, handlerName);
542
+ const methodContentType = Reflect.getMetadata(CONTENT_TYPE_KEY, instance, handlerName);
543
+ const contentType = methodContentType || controllerContentType;
544
+ const roles = Reflect.getMetadata(ROLES_KEY, instance, handlerName) || controllerRoles || [];
545
+ const cache = Reflect.getMetadata(CACHE_KEY, instance, handlerName) || controllerCache;
546
+ const rateLimitOptions = Reflect.getMetadata(RATE_LIMIT_KEY, instance, handlerName) || controllerRateLimit;
547
+ const methodVersion = Reflect.getMetadata(VERSION_KEY, instance, handlerName);
548
+ const version = methodVersion || controllerVersion;
549
+ const timeout = Reflect.getMetadata(TIMEOUT_KEY, instance, handlerName) || controllerTimeout;
550
+ const logConfig = Reflect.getMetadata(LOG_KEY, instance, handlerName) || controllerLogConfig;
551
+ let rateLimiter = null;
552
+ if (rateLimitOptions) {
553
+ try {
554
+ rateLimiter = rateLimiterCache.get(rateLimitOptions);
555
+ } catch (err) {
556
+ getLogger().warn({
557
+ err
558
+ }, "express-rate-limit not available, skipping rate limiting for this route");
559
+ }
560
+ }
561
+ let finalPath = path;
562
+ if (methodVersion?.options?.addPrefix && methodVersion.version !== controllerVersion?.version) {
563
+ finalPath = `/${methodVersion.version}${path}`;
564
+ }
565
+ const handler = /* @__PURE__ */ __name(async (req, res, next) => {
566
+ req["startTime"] = Date.now();
567
+ let timeoutId;
568
+ let timedOut = false;
569
+ try {
570
+ if (timeout) {
571
+ timeoutId = setTimeout(() => {
572
+ if (!res.headersSent && !timedOut) {
573
+ timedOut = true;
574
+ const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.REQUEST_TIMEOUT, "Request timed out");
575
+ res.status(HttpStatusCodes.REQUEST_TIMEOUT).json(errorResponse);
576
+ }
577
+ }, timeout.ms);
578
+ }
579
+ if (timedOut) return;
580
+ if (rateLimiter) {
581
+ await new Promise((resolve, reject) => {
582
+ rateLimiter(req, res, (err) => {
583
+ if (err) reject(err);
584
+ else resolve();
585
+ });
586
+ });
587
+ }
588
+ if (!res.headersSent && contentType) {
589
+ res.setHeader("Content-Type", contentType.type);
590
+ }
591
+ if (version?.options?.addHeader && version?.options?.headerName && version?.version) {
592
+ if (!res.headersSent) {
593
+ res.setHeader(version.options.headerName, version.version);
594
+ }
595
+ }
596
+ if (cache && !res.headersSent) {
597
+ res.setHeader("Cache-Control", `public, max-age=${cache.ttlSeconds}`);
598
+ }
599
+ if (logConfig?.logEntry) {
600
+ const logger = getLogger();
601
+ const logData = {
602
+ method: req.method,
603
+ url: req.originalUrl || req.url,
604
+ userAgent: req.get("User-Agent")
605
+ };
606
+ if (logConfig.logParams) {
607
+ logData.params = req.params;
608
+ logData.query = req.query;
609
+ }
610
+ if (logConfig.logBody) logData.body = req.body;
611
+ logger.info({
612
+ entry: logData
613
+ }, "Route Entry:");
614
+ }
615
+ if (roles.length && !req?.user?.roles?.some((role) => roles.includes(role))) {
616
+ const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.FORBIDDEN, "Forbidden Insufficient Roles");
617
+ res.status(HttpStatusCodes.FORBIDDEN).json(errorResponse);
618
+ if (timeoutId) {
619
+ clearTimeout(timeoutId);
620
+ }
621
+ return;
622
+ }
623
+ if (redirect && redirect.url) {
624
+ if (timeoutId) {
625
+ clearTimeout(timeoutId);
626
+ }
627
+ return res.redirect(redirect.statusCode, redirect.url);
628
+ }
629
+ for (const fn of beforeHooks) await fn(req, res);
630
+ const args = [];
631
+ if (params.length) {
632
+ params.forEach(({ index, type, key, options }) => {
633
+ let rawValue;
634
+ switch (type) {
635
+ case "query":
636
+ rawValue = key ? req.query[key] : req.query;
637
+ args[index] = options ? applyParamOptions(rawValue, options, key) : rawValue;
638
+ break;
639
+ case "param":
640
+ rawValue = key ? req.params[key] : req.params;
641
+ args[index] = options ? applyParamOptions(rawValue, options, key) : rawValue;
642
+ break;
643
+ case "body":
644
+ args[index] = key ? req.body?.[key] : req.body;
645
+ break;
646
+ case "req":
647
+ args[index] = req;
648
+ break;
649
+ case "res":
650
+ args[index] = res;
651
+ break;
652
+ case "logger":
653
+ args[index] = getLogger();
654
+ break;
655
+ case "reqHeader":
656
+ args[index] = key ? req.headers[key.toLowerCase()] : req.headers;
657
+ break;
658
+ case "reqId":
659
+ args[index] = req.headers["x-request-id"] || req?.id || void 0;
660
+ break;
661
+ case "cookie":
662
+ args[index] = key ? req.cookies?.[key] : req.cookies;
663
+ break;
664
+ }
665
+ });
666
+ }
667
+ const result = instance[handlerName](...args);
668
+ const awaited = result instanceof Promise ? await result : result;
669
+ if (timeoutId) {
670
+ clearTimeout(timeoutId);
671
+ }
672
+ if (timedOut) return;
673
+ if (redirect && awaited && typeof awaited === "object" && "url" in awaited) {
674
+ const redirectUrl = awaited.url;
675
+ const redirectStatus = awaited.statusCode || redirect.statusCode;
676
+ return res.redirect(redirectStatus, redirectUrl);
677
+ }
678
+ if (!res.headersSent && typeof awaited !== "undefined") {
679
+ if (httpCode) res.status(httpCode);
680
+ for (const [k, v] of Object.entries(headers)) {
681
+ const normalized = normalizeHeaderValue(v);
682
+ if (typeof normalized !== "undefined") {
683
+ res.set(k, normalized);
684
+ }
685
+ }
686
+ res.json(awaited);
687
+ }
688
+ if (logConfig?.logExit) {
689
+ const logger = getLogger();
690
+ const logData = {
691
+ method: req.method,
692
+ url: req.originalUrl || req.url,
693
+ statusCode: res.statusCode,
694
+ duration: `${Date.now() - req.startTime}ms`
695
+ };
696
+ if (logConfig.logResponse) logData.response = awaited;
697
+ logger.info({
698
+ exit: logData
699
+ }, "Route Exit:");
700
+ }
701
+ for (const fn of afterHooks) await fn(req, res, awaited);
702
+ } catch (err) {
703
+ if (timeoutId) {
704
+ clearTimeout(timeoutId);
705
+ }
706
+ next(err);
707
+ }
708
+ }, "handler");
709
+ router[method](basePath + finalPath, ...middlewares, handler);
710
+ });
711
+ });
712
+ }
713
+ __name(registerControllers, "registerControllers");
714
+ function applyParamOptions(rawValue, options, key) {
715
+ if (!options) return rawValue;
716
+ let value = rawValue;
717
+ const paramName = key ? `: ${key}` : "";
718
+ if (value === void 0 || value === null || value === "") {
719
+ if ("default" in options) {
720
+ value = options.default;
721
+ }
722
+ }
723
+ if (options.required && (value === void 0 || value === null || value === "")) {
724
+ throw new BadRequestException(`Required parameter missing${paramName}`);
725
+ }
726
+ if (value !== void 0 && value !== null) {
727
+ if (options.dataType === "array") {
728
+ const delimiter = options.delimiter || ",";
729
+ if (typeof value === "string") {
730
+ value = value.split(delimiter).map((v) => v.trim());
731
+ } else if (!Array.isArray(value)) {
732
+ value = [
733
+ value
734
+ ];
735
+ }
736
+ if (options.type === "string" && options.pattern) {
737
+ const hasInvalidPattern = value.some((v) => !options.pattern.test(v));
738
+ if (hasInvalidPattern) {
739
+ throw new BadRequestException(`Parameter '${key}' array contains values that do not match pattern: ${options.patternName || options.pattern}`);
740
+ }
741
+ }
742
+ if (options.type === "number" && options.pattern) {
743
+ const hasInvalidPattern = value.some((v) => !options.pattern.test(String(v)));
744
+ if (hasInvalidPattern) {
745
+ throw new BadRequestException(`Parameter '${key}' array contains values that do not match pattern: ${options.patternName || options.pattern}`);
746
+ }
747
+ }
748
+ if (options.type === "number" && options.throwError !== false) {
749
+ const hasInvalidNumber = value.some((v) => isNaN(Number(v)));
750
+ if (hasInvalidNumber) {
751
+ throw new BadRequestException(`Type error: expected number array${paramName}`);
752
+ }
753
+ if (options.min !== void 0) {
754
+ const hasBelowMin = value.some((v) => Number(v) < options.min);
755
+ if (hasBelowMin) {
756
+ throw new BadRequestException(`Validation error: number array values must be >= ${options.min}${paramName}`);
757
+ }
758
+ }
759
+ if (options.max !== void 0) {
760
+ const hasAboveMax = value.some((v) => Number(v) > options.max);
761
+ if (hasAboveMax) {
762
+ throw new BadRequestException(`Validation error: number array values must be <= ${options.max}${paramName}`);
763
+ }
764
+ }
765
+ }
766
+ if (options.type === "boolean" && options.throwError !== false) {
767
+ const hasInvalidBoolean = value.some((v) => !isValidBooleanInput(v));
768
+ if (hasInvalidBoolean) {
769
+ throw new BadRequestException(`Type error: expected boolean array${paramName}`);
770
+ }
771
+ }
772
+ if (options.type) {
773
+ value = value.map((v) => convertType(v, options.type || "string"));
774
+ }
775
+ } else if (options.dataType === "object") {
776
+ if (typeof value === "string") {
777
+ try {
778
+ value = JSON.parse(value);
779
+ } catch (_e) {
780
+ if (options.throwError !== false) {
781
+ throw new BadRequestException(`Invalid JSON object${paramName}`);
782
+ }
783
+ }
784
+ }
785
+ } else if (options.type) {
786
+ const originalValue = value;
787
+ value = convertType(value, options.type);
788
+ if (options.throwError === false) {
789
+ if (options.type === "number" && typeof value === "number") {
790
+ if (options.min !== void 0 && value < options.min) {
791
+ value = void 0;
792
+ }
793
+ if (options.max !== void 0 && value > options.max) {
794
+ value = void 0;
795
+ }
796
+ }
797
+ }
798
+ if (options.type === "string" && options.pattern && typeof value === "string" && !options.pattern.test(value)) {
799
+ throw new BadRequestException(`Parameter '${key}' does not match pattern: ${options.patternName || options.pattern}`);
800
+ } else if (options.type === "number" && options.pattern && typeof value === "number" && !options.pattern.test(String(value))) {
801
+ throw new BadRequestException(`Parameter '${key}' does not match pattern: ${options.patternName || options.pattern}`);
802
+ }
803
+ if (options.throwError !== false) {
804
+ if (options.type === "number" && typeof value === "number" && isNaN(value)) {
805
+ throw new BadRequestException(`Type error: expected number${paramName}`);
806
+ }
807
+ if (options.type === "number" && typeof value === "number") {
808
+ if (options.min !== void 0 && value < options.min) {
809
+ throw new BadRequestException(`Validation error: number must be >= ${options.min}${paramName}`);
810
+ }
811
+ if (options.max !== void 0 && value > options.max) {
812
+ throw new BadRequestException(`Validation error: number must be <= ${options.max}${paramName}`);
813
+ }
814
+ }
815
+ if (options.type === "boolean" && !isValidBooleanInput(originalValue)) {
816
+ throw new BadRequestException(`Type error: expected boolean${paramName}`);
817
+ }
818
+ }
819
+ }
820
+ }
821
+ if (options.transform && typeof options.transform === "function") {
822
+ value = options.transform(value);
823
+ }
824
+ if (options.validate && typeof options.validate === "function") {
825
+ if (!options.validate(value)) {
826
+ if (options.throwError !== false) {
827
+ throw new BadRequestException(`Parameter validation failed${paramName}`);
828
+ }
829
+ return void 0;
830
+ }
831
+ }
832
+ return value;
833
+ }
834
+ __name(applyParamOptions, "applyParamOptions");
835
+ function isValidBooleanInput(value) {
836
+ if (typeof value === "boolean") return true;
837
+ if (typeof value === "number") return value === 0 || value === 1;
838
+ if (typeof value === "string") {
839
+ const normalizedValue = value.toLowerCase().trim();
840
+ return [
841
+ "true",
842
+ "false",
843
+ "0",
844
+ "1",
845
+ "yes",
846
+ "no"
847
+ ].includes(normalizedValue);
848
+ }
849
+ return false;
850
+ }
851
+ __name(isValidBooleanInput, "isValidBooleanInput");
852
+ function convertType(value, type) {
853
+ if (value === void 0 || value === null) {
854
+ return value;
855
+ }
856
+ switch (type) {
857
+ case "number":
858
+ return Number(value);
859
+ case "boolean":
860
+ if (typeof value === "string") {
861
+ const normalizedValue = value.toLowerCase().trim();
862
+ return normalizedValue === "true" || normalizedValue === "1" || normalizedValue === "yes";
863
+ }
864
+ return value === true || value === 1;
865
+ case "string":
866
+ default:
867
+ return String(value);
868
+ }
869
+ }
870
+ __name(convertType, "convertType");
871
+
872
+ export { After, Before, Body, Cache, Connect, ContentType, Controller, DIContainer, Delete, Get, Head, Header, Headers, HttpCode, Inject, Injectable, Log, Options, Param, Patch, Post, Put, Query, RateLimit, Redirect, Req, ReqCookie, ReqHeader, ReqId, ReqLogger, Res, Roles, Timeout, Trace, Use, Version, createParamDecorator, createParamDecoratorWithoutParam, inject, registerControllers };