@catbee/utils 2.0.0-next.1 → 2.0.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 (87) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +55 -38
  3. package/array/index.cjs +37 -5
  4. package/array/index.d.ts +59 -8
  5. package/array/index.mjs +32 -4
  6. package/async/index.cjs +24 -3
  7. package/async/index.d.ts +18 -2
  8. package/async/index.mjs +24 -4
  9. package/cache/index.cjs +1 -1
  10. package/cache/index.d.ts +1 -1
  11. package/cache/index.mjs +1 -1
  12. package/config/index.cjs +8 -8
  13. package/config/index.d.ts +1 -1
  14. package/config/index.mjs +4 -4
  15. package/context-store/index.cjs +2 -3
  16. package/context-store/index.d.ts +1 -1
  17. package/context-store/index.mjs +2 -3
  18. package/crypto/index.cjs +55 -5
  19. package/crypto/index.d.ts +63 -2
  20. package/crypto/index.mjs +52 -7
  21. package/date/index.cjs +630 -1
  22. package/date/index.d.ts +487 -2
  23. package/date/index.mjs +621 -2
  24. package/{decorators → decorator}/index.cjs +425 -304
  25. package/{decorators → decorator}/index.d.ts +3 -2
  26. package/{decorators → decorator}/index.mjs +425 -304
  27. package/{dir → directory}/index.cjs +1 -1
  28. package/{dir → directory}/index.d.ts +1 -1
  29. package/{dir → directory}/index.mjs +1 -1
  30. package/env/index.cjs +90 -42
  31. package/env/index.d.ts +12 -1
  32. package/env/index.mjs +90 -42
  33. package/exception/index.cjs +1 -1
  34. package/exception/index.d.ts +1 -1
  35. package/exception/index.mjs +1 -1
  36. package/fs/index.cjs +1 -1
  37. package/fs/index.d.ts +1 -1
  38. package/fs/index.mjs +1 -1
  39. package/http-status-codes/index.cjs +1 -1
  40. package/http-status-codes/index.d.ts +1 -1
  41. package/http-status-codes/index.mjs +1 -1
  42. package/id/index.cjs +1 -1
  43. package/id/index.d.ts +1 -1
  44. package/id/index.mjs +1 -1
  45. package/index.cjs +10 -10
  46. package/index.d.ts +4 -4
  47. package/index.mjs +4 -4
  48. package/logger/index.cjs +2 -4
  49. package/logger/index.d.ts +2 -2
  50. package/logger/index.mjs +2 -4
  51. package/middleware/index.cjs +1 -1
  52. package/middleware/index.d.ts +1 -1
  53. package/middleware/index.mjs +1 -1
  54. package/{obj → object}/index.cjs +182 -108
  55. package/{obj → object}/index.d.ts +38 -2
  56. package/{obj → object}/index.mjs +180 -109
  57. package/package.json +31 -13
  58. package/performance/index.cjs +2 -2
  59. package/performance/index.d.ts +1 -1
  60. package/performance/index.mjs +2 -2
  61. package/request/index.cjs +36 -24
  62. package/request/index.d.ts +1 -1
  63. package/request/index.mjs +36 -24
  64. package/response/index.cjs +1 -1
  65. package/response/index.d.ts +1 -1
  66. package/response/index.mjs +1 -1
  67. package/server/index.cjs +233 -131
  68. package/server/index.d.ts +81 -1
  69. package/server/index.mjs +229 -127
  70. package/stream/index.cjs +1 -1
  71. package/stream/index.d.ts +1 -1
  72. package/stream/index.mjs +1 -1
  73. package/string/index.cjs +34 -1
  74. package/string/index.d.ts +45 -2
  75. package/string/index.mjs +31 -2
  76. package/type/index.cjs +18 -1
  77. package/type/index.d.ts +38 -2
  78. package/type/index.mjs +16 -2
  79. package/types/index.cjs +1 -1
  80. package/types/index.d.ts +10 -3
  81. package/types/index.mjs +1 -1
  82. package/url/index.cjs +61 -1
  83. package/url/index.d.ts +59 -2
  84. package/url/index.mjs +57 -2
  85. package/validation/index.cjs +3 -3
  86. package/validation/index.d.ts +1 -1
  87. package/validation/index.mjs +3 -3
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * The MIT License
3
3
  *
4
- * Copyright (c) 2025 Catbee Technologies. https://catbee.in/license
4
+ * Copyright (c) 2026 Catbee Technologies. https://catbee.in/license
5
5
  *
6
6
  * Permission is hereby granted, free of charge, to any person obtaining a copy
7
7
  * of this software and associated documentation files (the "Software"), to deal
@@ -1150,7 +1150,7 @@ var require_Reflect = __commonJS({
1150
1150
  }
1151
1151
  });
1152
1152
 
1153
- // src/decorators/decorators.utils.ts
1153
+ // src/decorator/decorator.utils.ts
1154
1154
  __toESM(require_Reflect());
1155
1155
  var ROUTES_KEY = Symbol("routes");
1156
1156
  var MIDDLEWARE_KEY = Symbol("middlewares");
@@ -1274,7 +1274,7 @@ var DIContainer = class {
1274
1274
  };
1275
1275
  var diContainer = new DIContainer();
1276
1276
  function normalizeHeaderValue(value) {
1277
- if (typeof value === "undefined") return void 0;
1277
+ if (value === void 0) return void 0;
1278
1278
  if (typeof value === "string") return value;
1279
1279
  if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
1280
1280
  return value;
@@ -1613,223 +1613,309 @@ function Log(options) {
1613
1613
  __name(Log, "Log");
1614
1614
  function registerControllers(router, controllers) {
1615
1615
  controllers.forEach((ControllerClass) => {
1616
- if (!Reflect.getMetadata("injectable", ControllerClass)) {
1617
- Reflect.defineMetadata("injectable", true, ControllerClass);
1618
- diContainer.register(ControllerClass);
1619
- }
1620
- const instance = diContainer.get(ControllerClass);
1621
- let basePath = Reflect.getMetadata("basePath", ControllerClass) || "";
1622
- const routes = Reflect.getMetadata(ROUTES_KEY, ControllerClass) || [];
1623
- const controllerRateLimit = Reflect.getMetadata(RATE_LIMIT_KEY, ControllerClass);
1624
- const controllerCache = Reflect.getMetadata(CACHE_KEY, ControllerClass);
1625
- const controllerTimeout = Reflect.getMetadata(TIMEOUT_KEY, ControllerClass);
1626
- const controllerVersion = Reflect.getMetadata(VERSION_KEY, ControllerClass);
1627
- const controllerRoles = Reflect.getMetadata(ROLES_KEY, ControllerClass);
1628
- const controllerLogConfig = Reflect.getMetadata(LOG_KEY, ControllerClass);
1629
- const controllerHeaders = Reflect.getMetadata(HEADER_KEY, ControllerClass) || {};
1630
- const controllerMiddlewares = Reflect.getMetadata(MIDDLEWARE_KEY, ControllerClass) || [];
1631
- const controllerBeforeHooks = Reflect.getMetadata(BEFORE_KEY, ControllerClass) || [];
1632
- const controllerAfterHooks = Reflect.getMetadata(AFTER_KEY, ControllerClass) || [];
1633
- const controllerContentType = Reflect.getMetadata(CONTENT_TYPE_KEY, ControllerClass);
1634
- if (controllerVersion?.options?.addPrefix) {
1635
- basePath = `/${controllerVersion.version}${basePath || ""}`;
1616
+ registerSingleController(router, ControllerClass);
1617
+ });
1618
+ }
1619
+ __name(registerControllers, "registerControllers");
1620
+ function registerSingleController(router, ControllerClass) {
1621
+ if (!Reflect.getMetadata("injectable", ControllerClass)) {
1622
+ Reflect.defineMetadata("injectable", true, ControllerClass);
1623
+ diContainer.register(ControllerClass);
1624
+ }
1625
+ const instance = diContainer.get(ControllerClass);
1626
+ const controllerMetadata = getControllerMetadata(ControllerClass);
1627
+ const routes = Reflect.getMetadata(ROUTES_KEY, ControllerClass) || [];
1628
+ routes.forEach((routeDef) => {
1629
+ registerRoute(router, instance, controllerMetadata, routeDef);
1630
+ });
1631
+ }
1632
+ __name(registerSingleController, "registerSingleController");
1633
+ function getControllerMetadata(ControllerClass) {
1634
+ let basePath = Reflect.getMetadata("basePath", ControllerClass) || "";
1635
+ const controllerVersion = Reflect.getMetadata(VERSION_KEY, ControllerClass);
1636
+ if (controllerVersion?.options?.addPrefix) {
1637
+ basePath = `/${controllerVersion.version}${basePath || ""}`;
1638
+ }
1639
+ return {
1640
+ basePath,
1641
+ rateLimit: Reflect.getMetadata(RATE_LIMIT_KEY, ControllerClass),
1642
+ cache: Reflect.getMetadata(CACHE_KEY, ControllerClass),
1643
+ timeout: Reflect.getMetadata(TIMEOUT_KEY, ControllerClass),
1644
+ version: controllerVersion,
1645
+ roles: Reflect.getMetadata(ROLES_KEY, ControllerClass),
1646
+ logConfig: Reflect.getMetadata(LOG_KEY, ControllerClass),
1647
+ headers: Reflect.getMetadata(HEADER_KEY, ControllerClass) || {},
1648
+ middlewares: Reflect.getMetadata(MIDDLEWARE_KEY, ControllerClass) || [],
1649
+ beforeHooks: Reflect.getMetadata(BEFORE_KEY, ControllerClass) || [],
1650
+ afterHooks: Reflect.getMetadata(AFTER_KEY, ControllerClass) || [],
1651
+ contentType: Reflect.getMetadata(CONTENT_TYPE_KEY, ControllerClass)
1652
+ };
1653
+ }
1654
+ __name(getControllerMetadata, "getControllerMetadata");
1655
+ function registerRoute(router, instance, controllerMetadata, routeDef) {
1656
+ const { path, method, handlerName } = routeDef;
1657
+ const routeMetadata = getRouteMetadata(instance, handlerName, controllerMetadata);
1658
+ const handler = createRouteHandler(instance, handlerName, routeMetadata);
1659
+ const finalPath = calculateFinalPath(path, routeMetadata, controllerMetadata);
1660
+ router[method](controllerMetadata.basePath + finalPath, ...routeMetadata.middlewares, handler);
1661
+ }
1662
+ __name(registerRoute, "registerRoute");
1663
+ function getRouteMetadata(instance, handlerName, controllerMetadata) {
1664
+ const methodMiddlewares = Reflect.getMetadata(MIDDLEWARE_KEY, instance, handlerName) || [];
1665
+ const params = Reflect.getMetadata(PARAMS_KEY, instance, handlerName) || [];
1666
+ const httpCode = Reflect.getMetadata(HTTP_CODE_KEY, instance, handlerName);
1667
+ const methodHeaders = Reflect.getMetadata(HEADER_KEY, instance, handlerName) || {};
1668
+ const methodBeforeHooks = Reflect.getMetadata(BEFORE_KEY, instance, handlerName) || [];
1669
+ const methodAfterHooks = Reflect.getMetadata(AFTER_KEY, instance, handlerName) || [];
1670
+ const redirect = Reflect.getMetadata(REDIRECT_KEY, instance, handlerName);
1671
+ const methodContentType = Reflect.getMetadata(CONTENT_TYPE_KEY, instance, handlerName);
1672
+ const methodVersion = Reflect.getMetadata(VERSION_KEY, instance, handlerName);
1673
+ const headers = {
1674
+ ...controllerMetadata.headers,
1675
+ ...methodHeaders
1676
+ };
1677
+ const middlewares = [
1678
+ ...controllerMetadata.middlewares,
1679
+ ...methodMiddlewares
1680
+ ];
1681
+ const beforeHooks = [
1682
+ ...controllerMetadata.beforeHooks,
1683
+ ...methodBeforeHooks
1684
+ ];
1685
+ const afterHooks = [
1686
+ ...methodAfterHooks,
1687
+ ...controllerMetadata.afterHooks
1688
+ ];
1689
+ const contentType = methodContentType || controllerMetadata.contentType;
1690
+ const roles = Reflect.getMetadata(ROLES_KEY, instance, handlerName) || controllerMetadata.roles || [];
1691
+ const cache = Reflect.getMetadata(CACHE_KEY, instance, handlerName) || controllerMetadata.cache;
1692
+ const rateLimitOptions = Reflect.getMetadata(RATE_LIMIT_KEY, instance, handlerName) || controllerMetadata.rateLimit;
1693
+ const version = methodVersion || controllerMetadata.version;
1694
+ const timeout = Reflect.getMetadata(TIMEOUT_KEY, instance, handlerName) || controllerMetadata.timeout;
1695
+ const logConfig = Reflect.getMetadata(LOG_KEY, instance, handlerName) || controllerMetadata.logConfig;
1696
+ let rateLimiter = null;
1697
+ if (rateLimitOptions) {
1698
+ try {
1699
+ rateLimiter = rateLimiterCache.get(rateLimitOptions);
1700
+ } catch (err) {
1701
+ getLogger().warn({
1702
+ err
1703
+ }, "express-rate-limit not available, skipping rate limiting for this route");
1636
1704
  }
1637
- routes.forEach(({ path, method, handlerName }) => {
1638
- const methodMiddlewares = Reflect.getMetadata(MIDDLEWARE_KEY, instance, handlerName) || [];
1639
- const params = Reflect.getMetadata(PARAMS_KEY, instance, handlerName) || [];
1640
- const httpCode = Reflect.getMetadata(HTTP_CODE_KEY, instance, handlerName);
1641
- const methodHeaders = Reflect.getMetadata(HEADER_KEY, instance, handlerName) || {};
1642
- const headers = {
1643
- ...controllerHeaders,
1644
- ...methodHeaders
1645
- };
1646
- const middlewares = [
1647
- ...controllerMiddlewares,
1648
- ...methodMiddlewares
1649
- ];
1650
- const methodBeforeHooks = Reflect.getMetadata(BEFORE_KEY, instance, handlerName) || [];
1651
- const methodAfterHooks = Reflect.getMetadata(AFTER_KEY, instance, handlerName) || [];
1652
- const beforeHooks = [
1653
- ...controllerBeforeHooks,
1654
- ...methodBeforeHooks
1655
- ];
1656
- const afterHooks = [
1657
- ...methodAfterHooks,
1658
- ...controllerAfterHooks
1659
- ];
1660
- const redirect = Reflect.getMetadata(REDIRECT_KEY, instance, handlerName);
1661
- const methodContentType = Reflect.getMetadata(CONTENT_TYPE_KEY, instance, handlerName);
1662
- const contentType = methodContentType || controllerContentType;
1663
- const roles = Reflect.getMetadata(ROLES_KEY, instance, handlerName) || controllerRoles || [];
1664
- const cache = Reflect.getMetadata(CACHE_KEY, instance, handlerName) || controllerCache;
1665
- const rateLimitOptions = Reflect.getMetadata(RATE_LIMIT_KEY, instance, handlerName) || controllerRateLimit;
1666
- const methodVersion = Reflect.getMetadata(VERSION_KEY, instance, handlerName);
1667
- const version = methodVersion || controllerVersion;
1668
- const timeout = Reflect.getMetadata(TIMEOUT_KEY, instance, handlerName) || controllerTimeout;
1669
- const logConfig = Reflect.getMetadata(LOG_KEY, instance, handlerName) || controllerLogConfig;
1670
- let rateLimiter = null;
1671
- if (rateLimitOptions) {
1672
- try {
1673
- rateLimiter = rateLimiterCache.get(rateLimitOptions);
1674
- } catch (err) {
1675
- getLogger().warn({
1676
- err
1677
- }, "express-rate-limit not available, skipping rate limiting for this route");
1678
- }
1705
+ }
1706
+ return {
1707
+ params,
1708
+ httpCode,
1709
+ headers,
1710
+ middlewares,
1711
+ beforeHooks,
1712
+ afterHooks,
1713
+ redirect,
1714
+ contentType,
1715
+ roles,
1716
+ cache,
1717
+ rateLimiter,
1718
+ version,
1719
+ methodVersion,
1720
+ timeout,
1721
+ logConfig
1722
+ };
1723
+ }
1724
+ __name(getRouteMetadata, "getRouteMetadata");
1725
+ function calculateFinalPath(path, routeMetadata, controllerMetadata) {
1726
+ let finalPath = path;
1727
+ if (routeMetadata.methodVersion?.options?.addPrefix && routeMetadata.methodVersion.version !== controllerMetadata.version?.version) {
1728
+ finalPath = `/${routeMetadata.methodVersion.version}${path}`;
1729
+ }
1730
+ return finalPath;
1731
+ }
1732
+ __name(calculateFinalPath, "calculateFinalPath");
1733
+ function createRouteHandler(instance, handlerName, routeMetadata) {
1734
+ return async (req, res, next) => {
1735
+ req["startTime"] = Date.now();
1736
+ const timeoutState = setupTimeout(req, res, routeMetadata.timeout);
1737
+ try {
1738
+ if (timeoutState.timedOut) return;
1739
+ if (routeMetadata.rateLimiter) {
1740
+ await applyRateLimiting(req, res, routeMetadata.rateLimiter);
1679
1741
  }
1680
- let finalPath = path;
1681
- if (methodVersion?.options?.addPrefix && methodVersion.version !== controllerVersion?.version) {
1682
- finalPath = `/${methodVersion.version}${path}`;
1742
+ applyResponseHeaders(res, routeMetadata);
1743
+ logRouteEntry(req, routeMetadata.logConfig);
1744
+ if (!checkRoles(req, res, routeMetadata.roles, timeoutState)) {
1745
+ return;
1683
1746
  }
1684
- const handler = /* @__PURE__ */ __name(async (req, res, next) => {
1685
- req["startTime"] = Date.now();
1686
- let timeoutId;
1687
- let timedOut = false;
1688
- try {
1689
- if (timeout) {
1690
- timeoutId = setTimeout(() => {
1691
- if (!res.headersSent && !timedOut) {
1692
- timedOut = true;
1693
- const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.REQUEST_TIMEOUT, "Request timed out");
1694
- res.status(HttpStatusCodes.REQUEST_TIMEOUT).json(errorResponse);
1695
- }
1696
- }, timeout.ms);
1697
- }
1698
- if (timedOut) return;
1699
- if (rateLimiter) {
1700
- await new Promise((resolve, reject) => {
1701
- rateLimiter(req, res, (err) => {
1702
- if (err) reject(err);
1703
- else resolve();
1704
- });
1705
- });
1706
- }
1707
- if (!res.headersSent && contentType) {
1708
- res.setHeader("Content-Type", contentType.type);
1709
- }
1710
- if (version?.options?.addHeader && version?.options?.headerName && version?.version) {
1711
- if (!res.headersSent) {
1712
- res.setHeader(version.options.headerName, version.version);
1713
- }
1714
- }
1715
- if (cache && !res.headersSent) {
1716
- res.setHeader("Cache-Control", `public, max-age=${cache.ttlSeconds}`);
1717
- }
1718
- if (logConfig?.logEntry) {
1719
- const logger = getLogger();
1720
- const logData = {
1721
- method: req.method,
1722
- url: req.originalUrl || req.url,
1723
- userAgent: req.get("User-Agent")
1724
- };
1725
- if (logConfig.logParams) {
1726
- logData.params = req.params;
1727
- logData.query = req.query;
1728
- }
1729
- if (logConfig.logBody) logData.body = req.body;
1730
- logger.info({
1731
- entry: logData
1732
- }, "Route Entry:");
1733
- }
1734
- if (roles.length && !req?.user?.roles?.some((role) => roles.includes(role))) {
1735
- const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.FORBIDDEN, "Forbidden Insufficient Roles");
1736
- res.status(HttpStatusCodes.FORBIDDEN).json(errorResponse);
1737
- if (timeoutId) {
1738
- clearTimeout(timeoutId);
1739
- }
1740
- return;
1741
- }
1742
- if (redirect?.url) {
1743
- if (timeoutId) {
1744
- clearTimeout(timeoutId);
1745
- }
1746
- return res.redirect(redirect.statusCode, redirect.url);
1747
- }
1748
- for (const fn of beforeHooks) await fn(req, res);
1749
- const args = [];
1750
- if (params.length) {
1751
- params.forEach(({ index, type, key, options }) => {
1752
- let rawValue;
1753
- switch (type) {
1754
- case "query":
1755
- rawValue = key ? req.query[key] : req.query;
1756
- args[index] = options ? applyParamOptions(rawValue, options, key) : rawValue;
1757
- break;
1758
- case "param":
1759
- rawValue = key ? req.params[key] : req.params;
1760
- args[index] = options ? applyParamOptions(rawValue, options, key) : rawValue;
1761
- break;
1762
- case "body":
1763
- args[index] = key ? req.body?.[key] : req.body;
1764
- break;
1765
- case "req":
1766
- args[index] = req;
1767
- break;
1768
- case "res":
1769
- args[index] = res;
1770
- break;
1771
- case "logger":
1772
- args[index] = getLogger();
1773
- break;
1774
- case "reqHeader":
1775
- args[index] = key ? req.headers[key.toLowerCase()] : req.headers;
1776
- break;
1777
- case "reqId":
1778
- args[index] = req.headers["x-request-id"] || req?.id || void 0;
1779
- break;
1780
- case "cookie":
1781
- args[index] = key ? req.cookies?.[key] : req.cookies;
1782
- break;
1783
- }
1784
- });
1785
- }
1786
- const result = instance[handlerName](...args);
1787
- const awaited = result instanceof Promise ? await result : result;
1788
- if (timeoutId) {
1789
- clearTimeout(timeoutId);
1790
- }
1791
- if (timedOut) return;
1792
- if (redirect && awaited && typeof awaited === "object" && "url" in awaited) {
1793
- const redirectUrl = awaited.url;
1794
- const redirectStatus = awaited.statusCode || redirect.statusCode;
1795
- return res.redirect(redirectStatus, redirectUrl);
1796
- }
1797
- if (!res.headersSent && typeof awaited !== "undefined") {
1798
- if (httpCode) res.status(httpCode);
1799
- for (const [k, v] of Object.entries(headers)) {
1800
- const normalized = normalizeHeaderValue(v);
1801
- if (typeof normalized !== "undefined") {
1802
- res.set(k, normalized);
1803
- }
1804
- }
1805
- res.json(awaited);
1806
- }
1807
- if (logConfig?.logExit) {
1808
- const logger = getLogger();
1809
- const logData = {
1810
- method: req.method,
1811
- url: req.originalUrl || req.url,
1812
- statusCode: res.statusCode,
1813
- duration: `${Date.now() - req.startTime}ms`
1814
- };
1815
- if (logConfig.logResponse) logData.response = awaited;
1816
- logger.info({
1817
- exit: logData
1818
- }, "Route Exit:");
1819
- }
1820
- for (const fn of afterHooks) await fn(req, res, awaited);
1821
- } catch (err) {
1822
- if (timeoutId) {
1823
- clearTimeout(timeoutId);
1824
- }
1825
- next(err);
1826
- }
1827
- }, "handler");
1828
- router[method](basePath + finalPath, ...middlewares, handler);
1747
+ if (routeMetadata.redirect?.url) {
1748
+ clearTimeout(timeoutState.timeoutId);
1749
+ return res.redirect(routeMetadata.redirect.statusCode, routeMetadata.redirect.url);
1750
+ }
1751
+ for (const fn of routeMetadata.beforeHooks) await fn(req, res);
1752
+ const args = extractHandlerArgs(req, res, routeMetadata.params);
1753
+ const result = instance[handlerName](...args);
1754
+ const awaited = result instanceof Promise ? await result : result;
1755
+ clearTimeout(timeoutState.timeoutId);
1756
+ if (timeoutState.timedOut) return;
1757
+ if (handleDynamicRedirect(res, routeMetadata.redirect, awaited)) {
1758
+ return;
1759
+ }
1760
+ sendResponse(res, awaited, routeMetadata.httpCode, routeMetadata.headers);
1761
+ logRouteExit(req, res, awaited, routeMetadata.logConfig);
1762
+ for (const fn of routeMetadata.afterHooks) await fn(req, res, awaited);
1763
+ } catch (err) {
1764
+ clearTimeout(timeoutState.timeoutId);
1765
+ next(err);
1766
+ }
1767
+ };
1768
+ }
1769
+ __name(createRouteHandler, "createRouteHandler");
1770
+ function setupTimeout(req, res, timeout) {
1771
+ const state = {
1772
+ timeoutId: void 0,
1773
+ timedOut: false
1774
+ };
1775
+ if (timeout) {
1776
+ state.timeoutId = setTimeout(() => {
1777
+ if (!res.headersSent && !state.timedOut) {
1778
+ state.timedOut = true;
1779
+ const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.REQUEST_TIMEOUT, "Request timed out");
1780
+ res.status(HttpStatusCodes.REQUEST_TIMEOUT).json(errorResponse);
1781
+ }
1782
+ }, timeout.ms);
1783
+ }
1784
+ return state;
1785
+ }
1786
+ __name(setupTimeout, "setupTimeout");
1787
+ async function applyRateLimiting(req, res, rateLimiter) {
1788
+ await new Promise((resolve, reject) => {
1789
+ rateLimiter(req, res, (err) => {
1790
+ if (err) reject(err);
1791
+ else resolve();
1829
1792
  });
1830
1793
  });
1831
1794
  }
1832
- __name(registerControllers, "registerControllers");
1795
+ __name(applyRateLimiting, "applyRateLimiting");
1796
+ function applyResponseHeaders(res, routeMetadata) {
1797
+ if (!res.headersSent && routeMetadata.contentType) {
1798
+ res.setHeader("Content-Type", routeMetadata.contentType.type);
1799
+ }
1800
+ if (routeMetadata.version?.options?.addHeader && routeMetadata.version?.options?.headerName && routeMetadata.version?.version) {
1801
+ if (!res.headersSent) {
1802
+ res.setHeader(routeMetadata.version.options.headerName, routeMetadata.version.version);
1803
+ }
1804
+ }
1805
+ if (routeMetadata.cache && !res.headersSent) {
1806
+ res.setHeader("Cache-Control", `public, max-age=${routeMetadata.cache.ttlSeconds}`);
1807
+ }
1808
+ }
1809
+ __name(applyResponseHeaders, "applyResponseHeaders");
1810
+ function logRouteEntry(req, logConfig) {
1811
+ if (logConfig?.logEntry) {
1812
+ const logger = getLogger();
1813
+ const logData = {
1814
+ method: req.method,
1815
+ url: req.originalUrl || req.url,
1816
+ userAgent: req.get("User-Agent")
1817
+ };
1818
+ if (logConfig.logParams) {
1819
+ logData.params = req.params;
1820
+ logData.query = req.query;
1821
+ }
1822
+ if (logConfig.logBody) logData.body = req.body;
1823
+ logger.info({
1824
+ entry: logData
1825
+ }, "Route Entry:");
1826
+ }
1827
+ }
1828
+ __name(logRouteEntry, "logRouteEntry");
1829
+ function logRouteExit(req, res, result, logConfig) {
1830
+ if (logConfig?.logExit) {
1831
+ const logger = getLogger();
1832
+ const logData = {
1833
+ method: req.method,
1834
+ url: req.originalUrl || req.url,
1835
+ statusCode: res.statusCode,
1836
+ duration: `${Date.now() - req.startTime}ms`
1837
+ };
1838
+ if (logConfig.logResponse) logData.response = result;
1839
+ logger.info({
1840
+ exit: logData
1841
+ }, "Route Exit:");
1842
+ }
1843
+ }
1844
+ __name(logRouteExit, "logRouteExit");
1845
+ function checkRoles(req, res, roles, timeoutState) {
1846
+ if (roles.length && !req?.user?.roles?.some((role) => roles.includes(role))) {
1847
+ const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.FORBIDDEN, "Forbidden Insufficient Roles");
1848
+ res.status(HttpStatusCodes.FORBIDDEN).json(errorResponse);
1849
+ clearTimeout(timeoutState.timeoutId);
1850
+ return false;
1851
+ }
1852
+ return true;
1853
+ }
1854
+ __name(checkRoles, "checkRoles");
1855
+ function extractHandlerArgs(req, res, params) {
1856
+ const args = [];
1857
+ if (params.length) {
1858
+ params.forEach(({ index, type, key, options }) => {
1859
+ let rawValue;
1860
+ switch (type) {
1861
+ case "query":
1862
+ rawValue = key ? req.query[key] : req.query;
1863
+ args[index] = options ? applyParamOptions(rawValue, options, key) : rawValue;
1864
+ break;
1865
+ case "param":
1866
+ rawValue = key ? req.params[key] : req.params;
1867
+ args[index] = options ? applyParamOptions(rawValue, options, key) : rawValue;
1868
+ break;
1869
+ case "body":
1870
+ args[index] = key ? req.body?.[key] : req.body;
1871
+ break;
1872
+ case "req":
1873
+ args[index] = req;
1874
+ break;
1875
+ case "res":
1876
+ args[index] = res;
1877
+ break;
1878
+ case "logger":
1879
+ args[index] = getLogger();
1880
+ break;
1881
+ case "reqHeader":
1882
+ args[index] = key ? req.headers[key.toLowerCase()] : req.headers;
1883
+ break;
1884
+ case "reqId":
1885
+ args[index] = req.headers["x-request-id"] || req?.id || void 0;
1886
+ break;
1887
+ case "cookie":
1888
+ args[index] = key ? req.cookies?.[key] : req.cookies;
1889
+ break;
1890
+ }
1891
+ });
1892
+ }
1893
+ return args;
1894
+ }
1895
+ __name(extractHandlerArgs, "extractHandlerArgs");
1896
+ function handleDynamicRedirect(res, redirect, result) {
1897
+ if (redirect && result && typeof result === "object" && "url" in result) {
1898
+ const redirectUrl = result.url;
1899
+ const redirectStatus = result.statusCode || redirect.statusCode;
1900
+ res.redirect(redirectStatus, redirectUrl);
1901
+ return true;
1902
+ }
1903
+ return false;
1904
+ }
1905
+ __name(handleDynamicRedirect, "handleDynamicRedirect");
1906
+ function sendResponse(res, result, httpCode, headers) {
1907
+ if (!res.headersSent && result !== void 0) {
1908
+ if (httpCode) res.status(httpCode);
1909
+ for (const [k, v] of Object.entries(headers)) {
1910
+ const normalized = normalizeHeaderValue(v);
1911
+ if (normalized !== void 0) {
1912
+ res.set(k, normalized);
1913
+ }
1914
+ }
1915
+ res.json(result);
1916
+ }
1917
+ }
1918
+ __name(sendResponse, "sendResponse");
1833
1919
  function applyParamOptions(rawValue, options, key) {
1834
1920
  if (!options) return rawValue;
1835
1921
  let value = rawValue;
@@ -1844,98 +1930,11 @@ function applyParamOptions(rawValue, options, key) {
1844
1930
  }
1845
1931
  if (value !== void 0 && value !== null) {
1846
1932
  if (options.dataType === "array") {
1847
- const delimiter = options.delimiter || ",";
1848
- if (typeof value === "string") {
1849
- value = value.split(delimiter).map((v) => v.trim());
1850
- } else if (!Array.isArray(value)) {
1851
- value = [
1852
- value
1853
- ];
1854
- }
1855
- if (options.type === "string" && options.pattern) {
1856
- const hasInvalidPattern = value.some((v) => !options.pattern.test(v));
1857
- if (hasInvalidPattern) {
1858
- throw new BadRequestException(`Parameter '${key}' array contains values that do not match pattern: ${options.patternName || options.pattern}`);
1859
- }
1860
- }
1861
- if (options.type === "number" && options.pattern) {
1862
- const hasInvalidPattern = value.some((v) => !options.pattern.test(String(v)));
1863
- if (hasInvalidPattern) {
1864
- throw new BadRequestException(`Parameter '${key}' array contains values that do not match pattern: ${options.patternName || options.pattern}`);
1865
- }
1866
- }
1867
- if (options.type === "number" && options.throwError !== false) {
1868
- const hasInvalidNumber = value.some((v) => Number.isNaN(Number(v)));
1869
- if (hasInvalidNumber) {
1870
- throw new BadRequestException(`Type error: expected number array${paramName}`);
1871
- }
1872
- if (options.min !== void 0) {
1873
- const hasBelowMin = value.some((v) => Number(v) < options.min);
1874
- if (hasBelowMin) {
1875
- throw new BadRequestException(`Validation error: number array values must be >= ${options.min}${paramName}`);
1876
- }
1877
- }
1878
- if (options.max !== void 0) {
1879
- const hasAboveMax = value.some((v) => Number(v) > options.max);
1880
- if (hasAboveMax) {
1881
- throw new BadRequestException(`Validation error: number array values must be <= ${options.max}${paramName}`);
1882
- }
1883
- }
1884
- }
1885
- if (options.type === "boolean" && options.throwError !== false) {
1886
- const hasInvalidBoolean = value.some((v) => !isValidBooleanInput(v));
1887
- if (hasInvalidBoolean) {
1888
- throw new BadRequestException(`Type error: expected boolean array${paramName}`);
1889
- }
1890
- }
1891
- if (options.type) {
1892
- value = value.map((v) => convertType(v, options.type || "string"));
1893
- }
1933
+ value = handleArrayParam(value, options, key);
1894
1934
  } else if (options.dataType === "object") {
1895
- if (typeof value === "string") {
1896
- try {
1897
- value = JSON.parse(value);
1898
- } catch (_e) {
1899
- if (options.throwError !== false) {
1900
- throw new BadRequestException(`Invalid JSON object${paramName}`);
1901
- }
1902
- }
1903
- }
1935
+ value = handleObjectParam(value, options, key);
1904
1936
  } else if (options.type) {
1905
- const originalValue = value;
1906
- value = convertType(value, options.type);
1907
- if (options.throwError === false) {
1908
- if (options.type === "number" && typeof value === "number") {
1909
- if (options.min !== void 0 && value < options.min) {
1910
- value = void 0;
1911
- }
1912
- if (options.max !== void 0 && value > options.max) {
1913
- value = void 0;
1914
- }
1915
- }
1916
- }
1917
- const paramNotMatchMsg = `Parameter '${key}' does not match pattern: ${options.patternName || options.pattern}`;
1918
- if (options.type === "string" && options.pattern && typeof value === "string" && !options.pattern.test(value)) {
1919
- throw new BadRequestException(paramNotMatchMsg);
1920
- } else if (options.type === "number" && options.pattern && typeof value === "number" && !options.pattern.test(String(value))) {
1921
- throw new BadRequestException(paramNotMatchMsg);
1922
- }
1923
- if (options.throwError !== false) {
1924
- if (options.type === "number" && typeof value === "number" && Number.isNaN(value)) {
1925
- throw new BadRequestException(`Type error: expected number${paramName}`);
1926
- }
1927
- if (options.type === "number" && typeof value === "number") {
1928
- if (options.min !== void 0 && value < options.min) {
1929
- throw new BadRequestException(`Validation error: number must be >= ${options.min}${paramName}`);
1930
- }
1931
- if (options.max !== void 0 && value > options.max) {
1932
- throw new BadRequestException(`Validation error: number must be <= ${options.max}${paramName}`);
1933
- }
1934
- }
1935
- if (options.type === "boolean" && !isValidBooleanInput(originalValue)) {
1936
- throw new BadRequestException(`Type error: expected boolean${paramName}`);
1937
- }
1938
- }
1937
+ value = handleSingleParam(value, options, key);
1939
1938
  }
1940
1939
  }
1941
1940
  if (options.transform && typeof options.transform === "function") {
@@ -1952,6 +1951,128 @@ function applyParamOptions(rawValue, options, key) {
1952
1951
  return value;
1953
1952
  }
1954
1953
  __name(applyParamOptions, "applyParamOptions");
1954
+ function handleArrayParam(value, options, key) {
1955
+ const delimiter = options.delimiter || ",";
1956
+ if (typeof value === "string") {
1957
+ value = value.split(delimiter).map((v) => v.trim());
1958
+ } else if (!Array.isArray(value)) {
1959
+ value = [
1960
+ value
1961
+ ];
1962
+ }
1963
+ validateArrayPattern(value, options, key);
1964
+ validateArrayElements(value, options, key);
1965
+ if (options.type) {
1966
+ value = value.map((v) => convertType(v, options.type || "string"));
1967
+ }
1968
+ return value;
1969
+ }
1970
+ __name(handleArrayParam, "handleArrayParam");
1971
+ function validateArrayPattern(value, options, key) {
1972
+ if (options.type === "string" && options.pattern) {
1973
+ const hasInvalidPattern = value.some((v) => !options.pattern.test(v));
1974
+ if (hasInvalidPattern) {
1975
+ throw new BadRequestException(`Parameter '${key}' array contains values that do not match pattern: ${options.patternName || options.pattern}`);
1976
+ }
1977
+ }
1978
+ if (options.type === "number" && options.pattern) {
1979
+ const hasInvalidPattern = value.some((v) => !options.pattern.test(String(v)));
1980
+ if (hasInvalidPattern) {
1981
+ throw new BadRequestException(`Parameter '${key}' array contains values that do not match pattern: ${options.patternName || options.pattern}`);
1982
+ }
1983
+ }
1984
+ }
1985
+ __name(validateArrayPattern, "validateArrayPattern");
1986
+ function validateArrayElements(value, options, key) {
1987
+ const paramName = key ? `: ${key}` : "";
1988
+ if (options.type === "number" && options.throwError !== false) {
1989
+ const hasInvalidNumber = value.some((v) => Number.isNaN(Number(v)));
1990
+ if (hasInvalidNumber) {
1991
+ throw new BadRequestException(`Type error: expected number array${paramName}`);
1992
+ }
1993
+ if (options.min !== void 0) {
1994
+ const hasBelowMin = value.some((v) => Number(v) < options.min);
1995
+ if (hasBelowMin) {
1996
+ throw new BadRequestException(`Validation error: number array values must be >= ${options.min}${paramName}`);
1997
+ }
1998
+ }
1999
+ if (options.max !== void 0) {
2000
+ const hasAboveMax = value.some((v) => Number(v) > options.max);
2001
+ if (hasAboveMax) {
2002
+ throw new BadRequestException(`Validation error: number array values must be <= ${options.max}${paramName}`);
2003
+ }
2004
+ }
2005
+ }
2006
+ if (options.type === "boolean" && options.throwError !== false) {
2007
+ const hasInvalidBoolean = value.some((v) => !isValidBooleanInput(v));
2008
+ if (hasInvalidBoolean) {
2009
+ throw new BadRequestException(`Type error: expected boolean array${paramName}`);
2010
+ }
2011
+ }
2012
+ }
2013
+ __name(validateArrayElements, "validateArrayElements");
2014
+ function handleObjectParam(value, options, key) {
2015
+ const paramName = key ? `: ${key}` : "";
2016
+ if (typeof value === "string") {
2017
+ try {
2018
+ value = JSON.parse(value);
2019
+ } catch (_e) {
2020
+ if (options.throwError !== false) {
2021
+ throw new BadRequestException(`Invalid JSON object${paramName}`);
2022
+ }
2023
+ }
2024
+ }
2025
+ return value;
2026
+ }
2027
+ __name(handleObjectParam, "handleObjectParam");
2028
+ function handleSingleParam(value, options, key) {
2029
+ const paramName = key ? `: ${key}` : "";
2030
+ const originalValue = value;
2031
+ const targetType = options.type ?? "string";
2032
+ value = convertType(value, targetType);
2033
+ if (options.throwError === false) {
2034
+ if (options.type === "number" && typeof value === "number") {
2035
+ if (options.min !== void 0 && value < options.min) {
2036
+ value = void 0;
2037
+ }
2038
+ if (options.max !== void 0 && value > options.max) {
2039
+ value = void 0;
2040
+ }
2041
+ }
2042
+ }
2043
+ validateSinglePattern(value, options, key);
2044
+ validateSingleType(value, originalValue, options, paramName);
2045
+ return value;
2046
+ }
2047
+ __name(handleSingleParam, "handleSingleParam");
2048
+ function validateSinglePattern(value, options, key) {
2049
+ const paramNotMatchMsg = `Parameter '${key}' does not match pattern: ${options.patternName || options.pattern}`;
2050
+ if (options.type === "string" && options.pattern && typeof value === "string" && !options.pattern.test(value)) {
2051
+ throw new BadRequestException(paramNotMatchMsg);
2052
+ } else if (options.type === "number" && options.pattern && typeof value === "number" && !options.pattern.test(String(value))) {
2053
+ throw new BadRequestException(paramNotMatchMsg);
2054
+ }
2055
+ }
2056
+ __name(validateSinglePattern, "validateSinglePattern");
2057
+ function validateSingleType(value, originalValue, options, paramName) {
2058
+ if (options.throwError !== false) {
2059
+ if (options.type === "number" && typeof value === "number" && Number.isNaN(value)) {
2060
+ throw new BadRequestException(`Type error: expected number${paramName}`);
2061
+ }
2062
+ if (options.type === "number" && typeof value === "number") {
2063
+ if (options.min !== void 0 && value < options.min) {
2064
+ throw new BadRequestException(`Validation error: number must be >= ${options.min}${paramName}`);
2065
+ }
2066
+ if (options.max !== void 0 && value > options.max) {
2067
+ throw new BadRequestException(`Validation error: number must be <= ${options.max}${paramName}`);
2068
+ }
2069
+ }
2070
+ if (options.type === "boolean" && !isValidBooleanInput(originalValue)) {
2071
+ throw new BadRequestException(`Type error: expected boolean${paramName}`);
2072
+ }
2073
+ }
2074
+ }
2075
+ __name(validateSingleType, "validateSingleType");
1955
2076
  function isValidBooleanInput(value) {
1956
2077
  if (typeof value === "boolean") return true;
1957
2078
  if (typeof value === "number") return value === 0 || value === 1;