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