@catbee/utils 0.0.8-rc.4 → 1.0.2

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.
package/build/index.cjs CHANGED
@@ -11,6 +11,7 @@ var expressRateLimit = require('express-rate-limit');
11
11
  var os = require('os');
12
12
  var fsp = require('fs/promises');
13
13
  var promises = require('stream/promises');
14
+ var stream = require('stream');
14
15
  var url = require('url');
15
16
  var express = require('express');
16
17
  var https = require('https');
@@ -1660,7 +1661,7 @@ function addSensitiveFields(fields) {
1660
1661
  __name(addSensitiveFields, "addSensitiveFields");
1661
1662
  var _globalThis = typeof globalThis === "object" ? globalThis : global;
1662
1663
  var _global = _globalThis;
1663
- function setupLogger() {
1664
+ function setupLogger(isGlobal = true) {
1664
1665
  const logParams = {
1665
1666
  name: config.logger.name || "@catbee/utils",
1666
1667
  level: config.logger.level || "info",
@@ -1674,14 +1675,14 @@ function setupLogger() {
1674
1675
  ],
1675
1676
  censor: /* @__PURE__ */ __name((value, path3) => redact(value, path3), "censor")
1676
1677
  },
1677
- // serializers: {
1678
- // req: pino.stdSerializers.req,
1679
- // request: pino.stdSerializers.req,
1680
- // res: pino.stdSerializers.res,
1681
- // response: pino.stdSerializers.res,
1682
- // err: pino.stdSerializers.err,
1683
- // error: pino.stdSerializers.err
1684
- // },
1678
+ serializers: {
1679
+ req: pino__default.default.stdSerializers.req,
1680
+ request: pino__default.default.stdSerializers.req,
1681
+ res: pino__default.default.stdSerializers.res,
1682
+ response: pino__default.default.stdSerializers.res,
1683
+ err: pino__default.default.stdSerializers.err,
1684
+ error: pino__default.default.stdSerializers.err
1685
+ },
1685
1686
  timestamp: pino.stdTimeFunctions.isoTime
1686
1687
  };
1687
1688
  const logger2 = config.logger.pretty && Env.isDev() ? pino__default.default(logParams, pino__default.default.transport({
@@ -1694,11 +1695,17 @@ function setupLogger() {
1694
1695
  levelFirst: true
1695
1696
  }
1696
1697
  })) : pino__default.default(logParams);
1697
- _global[GLOBAL_LOGGER_KEY] = logger2;
1698
- _global[GLOBAL_LOGGER_KEY]?.debug("Logger initialized");
1698
+ if (isGlobal) {
1699
+ _global[GLOBAL_LOGGER_KEY] = logger2;
1700
+ _global[GLOBAL_LOGGER_KEY]?.debug("Logger initialized");
1701
+ }
1702
+ return logger2;
1699
1703
  }
1700
1704
  __name(setupLogger, "setupLogger");
1701
- function getLogger() {
1705
+ function getLogger(newInstance = false) {
1706
+ if (newInstance) {
1707
+ return setupLogger(false);
1708
+ }
1702
1709
  const logger2 = ContextStore.get(StoreKeys.LOGGER);
1703
1710
  if (logger2) return logger2;
1704
1711
  if (!_global[GLOBAL_LOGGER_KEY]) {
@@ -1707,7 +1714,7 @@ function getLogger() {
1707
1714
  return _global[GLOBAL_LOGGER_KEY];
1708
1715
  }
1709
1716
  __name(getLogger, "getLogger");
1710
- var logger = getLogger();
1717
+ var logger = getLogger(false);
1711
1718
  function createChildLogger(bindings, parentLogger) {
1712
1719
  const logger2 = parentLogger || getLogger();
1713
1720
  return logger2.child(bindings);
@@ -2498,6 +2505,234 @@ function verifySignedToken(token, secret) {
2498
2505
  }
2499
2506
  __name(verifySignedToken, "verifySignedToken");
2500
2507
 
2508
+ // src/utils/date.utils.ts
2509
+ function formatDate(date, options = {}) {
2510
+ const { format = "yyyy-MM-dd", locale, timeZone } = options;
2511
+ const d = date instanceof Date ? date : new Date(date);
2512
+ if (format === "yyyy-MM-dd") {
2513
+ const yyyy = d.getFullYear();
2514
+ const mm = String(d.getMonth() + 1).padStart(2, "0");
2515
+ const dd = String(d.getDate()).padStart(2, "0");
2516
+ return `${yyyy}-${mm}-${dd}`;
2517
+ }
2518
+ if (format === "yyyy-MM-dd HH:mm:ss") {
2519
+ const yyyy = d.getFullYear();
2520
+ const mm = String(d.getMonth() + 1).padStart(2, "0");
2521
+ const dd = String(d.getDate()).padStart(2, "0");
2522
+ const HH = String(d.getHours()).padStart(2, "0");
2523
+ const MM = String(d.getMinutes()).padStart(2, "0");
2524
+ const SS = String(d.getSeconds()).padStart(2, "0");
2525
+ return `${yyyy}-${mm}-${dd} ${HH}:${MM}:${SS}`;
2526
+ }
2527
+ if (format === "relative") {
2528
+ return formatRelativeTime(date);
2529
+ }
2530
+ return new Intl.DateTimeFormat(locale, {
2531
+ timeZone,
2532
+ year: format.includes("yyyy") || format.includes("y") ? "numeric" : void 0,
2533
+ month: format.includes("MM") || format.includes("M") ? "numeric" : void 0,
2534
+ day: format.includes("dd") || format.includes("d") ? "numeric" : void 0,
2535
+ hour: format.includes("HH") || format.includes("H") ? "numeric" : void 0,
2536
+ minute: format.includes("mm") || format.includes("m") ? "numeric" : void 0,
2537
+ second: format.includes("ss") || format.includes("s") ? "numeric" : void 0,
2538
+ hour12: !format.includes("HH") && !format.includes("H")
2539
+ }).format(d);
2540
+ }
2541
+ __name(formatDate, "formatDate");
2542
+ function formatRelativeTime(date, now = /* @__PURE__ */ new Date(), locale) {
2543
+ const d1 = date instanceof Date ? date : new Date(date);
2544
+ const d2 = now instanceof Date ? now : new Date(now);
2545
+ const diffMs = d1.getTime() - d2.getTime();
2546
+ const diffSecs = Math.round(diffMs / 1e3);
2547
+ const diffMins = Math.round(diffSecs / 60);
2548
+ const diffHours = Math.round(diffMins / 60);
2549
+ const diffDays = Math.round(diffHours / 24);
2550
+ const diffMonths = Math.round(diffDays / 30);
2551
+ const diffYears = Math.round(diffDays / 365);
2552
+ const formatter = new Intl.RelativeTimeFormat(locale, {
2553
+ numeric: "auto"
2554
+ });
2555
+ if (Math.abs(diffSecs) < 60) return formatter.format(diffSecs, "second");
2556
+ if (Math.abs(diffMins) < 60) return formatter.format(diffMins, "minute");
2557
+ if (Math.abs(diffHours) < 24) return formatter.format(diffHours, "hour");
2558
+ if (Math.abs(diffDays) < 30) return formatter.format(diffDays, "day");
2559
+ if (Math.abs(diffMonths) < 12) return formatter.format(diffMonths, "month");
2560
+ return formatter.format(diffYears, "year");
2561
+ }
2562
+ __name(formatRelativeTime, "formatRelativeTime");
2563
+ function parseDate(input, fallback) {
2564
+ if (typeof input === "number") {
2565
+ return new Date(input);
2566
+ }
2567
+ try {
2568
+ const date = new Date(input);
2569
+ if (isNaN(date.getTime())) {
2570
+ return fallback || null;
2571
+ }
2572
+ return date;
2573
+ } catch {
2574
+ return fallback || null;
2575
+ }
2576
+ }
2577
+ __name(parseDate, "parseDate");
2578
+ function dateDiff(date1, date2 = /* @__PURE__ */ new Date(), unit = "days") {
2579
+ const d1 = date1 instanceof Date ? date1 : new Date(date1);
2580
+ const d2 = date2 instanceof Date ? date2 : new Date(date2);
2581
+ const diffMs = d1.getTime() - d2.getTime();
2582
+ switch (unit) {
2583
+ case "milliseconds":
2584
+ return diffMs;
2585
+ case "seconds":
2586
+ return diffMs / 1e3;
2587
+ case "minutes":
2588
+ return diffMs / (1e3 * 60);
2589
+ case "hours":
2590
+ return diffMs / (1e3 * 60 * 60);
2591
+ case "days":
2592
+ return diffMs / (1e3 * 60 * 60 * 24);
2593
+ case "months":
2594
+ return (d1.getFullYear() - d2.getFullYear()) * 12 + d1.getMonth() - d2.getMonth();
2595
+ case "years":
2596
+ return d1.getFullYear() - d2.getFullYear();
2597
+ default:
2598
+ throw new Error(`Unsupported unit: ${unit}`);
2599
+ }
2600
+ }
2601
+ __name(dateDiff, "dateDiff");
2602
+ function addToDate(date, amount, unit) {
2603
+ const d = date instanceof Date ? new Date(date) : new Date(date);
2604
+ switch (unit) {
2605
+ case "milliseconds":
2606
+ d.setMilliseconds(d.getMilliseconds() + amount);
2607
+ break;
2608
+ case "seconds":
2609
+ d.setSeconds(d.getSeconds() + amount);
2610
+ break;
2611
+ case "minutes":
2612
+ d.setMinutes(d.getMinutes() + amount);
2613
+ break;
2614
+ case "hours":
2615
+ d.setHours(d.getHours() + amount);
2616
+ break;
2617
+ case "days":
2618
+ d.setDate(d.getDate() + amount);
2619
+ break;
2620
+ case "months": {
2621
+ const origDate = d.getDate();
2622
+ const origMonth = d.getMonth();
2623
+ d.setDate(1);
2624
+ d.setMonth(origMonth + amount);
2625
+ const lastDay = new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate();
2626
+ d.setDate(Math.min(origDate, lastDay));
2627
+ break;
2628
+ }
2629
+ case "years":
2630
+ d.setFullYear(d.getFullYear() + amount);
2631
+ break;
2632
+ default:
2633
+ throw new Error(`Unsupported unit: ${unit}`);
2634
+ }
2635
+ return d;
2636
+ }
2637
+ __name(addToDate, "addToDate");
2638
+ function startOf(date, unit) {
2639
+ const d = date instanceof Date ? new Date(date) : new Date(date);
2640
+ switch (unit) {
2641
+ case "second":
2642
+ d.setMilliseconds(0);
2643
+ break;
2644
+ case "minute":
2645
+ d.setSeconds(0, 0);
2646
+ break;
2647
+ case "hour":
2648
+ d.setMinutes(0, 0, 0);
2649
+ break;
2650
+ case "day":
2651
+ d.setHours(0, 0, 0, 0);
2652
+ break;
2653
+ case "week":
2654
+ d.setHours(0, 0, 0, 0);
2655
+ d.setDate(d.getDate() - d.getDay());
2656
+ break;
2657
+ case "month":
2658
+ d.setDate(1);
2659
+ d.setHours(0, 0, 0, 0);
2660
+ break;
2661
+ case "quarter":
2662
+ d.setMonth(Math.floor(d.getMonth() / 3) * 3, 1);
2663
+ d.setHours(0, 0, 0, 0);
2664
+ break;
2665
+ case "year":
2666
+ d.setMonth(0, 1);
2667
+ d.setHours(0, 0, 0, 0);
2668
+ break;
2669
+ default:
2670
+ throw new Error(`Unsupported unit: ${unit}`);
2671
+ }
2672
+ return d;
2673
+ }
2674
+ __name(startOf, "startOf");
2675
+ function endOf(date, unit) {
2676
+ const d = date instanceof Date ? new Date(date) : new Date(date);
2677
+ switch (unit) {
2678
+ case "second":
2679
+ d.setMilliseconds(999);
2680
+ break;
2681
+ case "minute":
2682
+ d.setSeconds(59, 999);
2683
+ break;
2684
+ case "hour":
2685
+ d.setMinutes(59, 59, 999);
2686
+ break;
2687
+ case "day":
2688
+ d.setHours(23, 59, 59, 999);
2689
+ break;
2690
+ case "week":
2691
+ d.setDate(d.getDate() - d.getDay() + 6);
2692
+ d.setHours(23, 59, 59, 999);
2693
+ break;
2694
+ case "month":
2695
+ d.setMonth(d.getMonth() + 1, 0);
2696
+ d.setHours(23, 59, 59, 999);
2697
+ break;
2698
+ case "quarter":
2699
+ d.setMonth(Math.floor(d.getMonth() / 3) * 3 + 3, 0);
2700
+ d.setHours(23, 59, 59, 999);
2701
+ break;
2702
+ case "year":
2703
+ d.setMonth(11, 31);
2704
+ d.setHours(23, 59, 59, 999);
2705
+ break;
2706
+ default:
2707
+ throw new Error(`Unsupported unit: ${unit}`);
2708
+ }
2709
+ return d;
2710
+ }
2711
+ __name(endOf, "endOf");
2712
+ function isBetween(date, start, end, inclusive = true) {
2713
+ const d = date instanceof Date ? date.getTime() : date;
2714
+ const s = start instanceof Date ? start.getTime() : start;
2715
+ const e = end instanceof Date ? end.getTime() : end;
2716
+ return inclusive ? d >= s && d <= e : d > s && d < e;
2717
+ }
2718
+ __name(isBetween, "isBetween");
2719
+ function isLeapYear(year) {
2720
+ const y = year instanceof Date ? year.getFullYear() : year;
2721
+ return y % 4 === 0 && y % 100 !== 0 || y % 400 === 0;
2722
+ }
2723
+ __name(isLeapYear, "isLeapYear");
2724
+ function daysInMonth(year, month) {
2725
+ if (year instanceof Date) {
2726
+ month = year.getMonth();
2727
+ year = year.getFullYear();
2728
+ }
2729
+ if (month === void 0) {
2730
+ throw new Error("Month is required when year is a number");
2731
+ }
2732
+ return new Date(year, month + 1, 0).getDate();
2733
+ }
2734
+ __name(daysInMonth, "daysInMonth");
2735
+
2501
2736
  // src/utils/response.utils.ts
2502
2737
  var SuccessResponse = class {
2503
2738
  static {
@@ -2751,1188 +2986,1500 @@ var HttpStatusCodes = /* @__PURE__ */ (function(HttpStatusCodes2) {
2751
2986
  HttpStatusCodes2[HttpStatusCodes2["NETWORK_AUTHENTICATION_REQUIRED"] = 511] = "NETWORK_AUTHENTICATION_REQUIRED";
2752
2987
  return HttpStatusCodes2;
2753
2988
  })({});
2754
- var ROUTES_KEY = Symbol("routes");
2755
- var MIDDLEWARE_KEY = Symbol("middlewares");
2756
- var PARAMS_KEY = Symbol("params");
2757
- var HTTP_CODE_KEY = Symbol("httpCode");
2758
- var HEADER_KEY = Symbol("headers");
2759
- var BEFORE_KEY = Symbol("before");
2760
- var AFTER_KEY = Symbol("after");
2761
- var ROLES_KEY = Symbol("roles");
2762
- var REDIRECT_KEY = Symbol("redirect");
2763
- var CACHE_KEY = Symbol("cache");
2764
- var RATE_LIMIT_KEY = Symbol("rateLimit");
2765
- var CONTENT_TYPE_KEY = Symbol("contentType");
2766
- var VERSION_KEY = Symbol("version");
2767
- var TIMEOUT_KEY = Symbol("timeout");
2768
- var LOG_KEY = Symbol("log");
2769
- var RateLimiterCache = class RateLimiterCache2 {
2989
+
2990
+ // src/utils/exception.utils.ts
2991
+ var HttpError = class extends ErrorResponse {
2770
2992
  static {
2771
- __name(this, "RateLimiterCache");
2993
+ __name(this, "HttpError");
2772
2994
  }
2773
- cache;
2774
- constructor(maxSize = 100, ttlMs = 5 * 60 * 1e3) {
2775
- this.cache = new TTLCache({
2776
- maxSize,
2777
- ttlMs
2778
- });
2995
+ /**
2996
+ * Creates a new HTTP error instance.
2997
+ * @param status - A valid HTTP status code (e.g., 400, 500).
2998
+ * @param message - The error message to return to the client.
2999
+ */
3000
+ constructor(status, message) {
3001
+ super(message);
3002
+ this.status = status;
2779
3003
  }
2780
- generateKey(options) {
2781
- return `${options.max}:${options.windowMs}:${options.standardHeaders}:${options.legacyHeaders}`;
3004
+ };
3005
+ var InternalServerErrorException = class extends ErrorResponse {
3006
+ static {
3007
+ __name(this, "InternalServerErrorException");
2782
3008
  }
2783
- get(options) {
2784
- const key = this.generateKey(options);
2785
- const cached = this.cache.get(key);
2786
- if (cached) {
2787
- return cached.limiter;
2788
- }
2789
- const limiter = expressRateLimit.rateLimit({
2790
- ...options,
2791
- handler: /* @__PURE__ */ __name((req, res) => {
2792
- const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.TOO_MANY_REQUESTS, "Too Many Requests");
2793
- res.status(HttpStatusCodes.TOO_MANY_REQUESTS).json(errorResponse);
2794
- }, "handler")
2795
- });
2796
- this.cache.set(key, {
2797
- limiter,
2798
- config: key
2799
- });
2800
- return limiter;
3009
+ /**
3010
+ * @param message - Optional custom message. Defaults to "Internal server error".
3011
+ */
3012
+ constructor(message = "Internal server error") {
3013
+ super(message);
3014
+ this.status = HttpStatusCodes.INTERNAL_SERVER_ERROR;
2801
3015
  }
2802
- clear() {
2803
- this.cache.clear();
3016
+ };
3017
+ var UnauthorizedException = class extends ErrorResponse {
3018
+ static {
3019
+ __name(this, "UnauthorizedException");
2804
3020
  }
2805
- size() {
2806
- return this.cache.size();
3021
+ /**
3022
+ * @param message - Optional custom message. Defaults to "Unauthorized".
3023
+ */
3024
+ constructor(message = "Unauthorized") {
3025
+ super(message);
3026
+ this.status = HttpStatusCodes.UNAUTHORIZED;
2807
3027
  }
2808
- destroy() {
2809
- this.cache.destroy();
3028
+ };
3029
+ var BadRequestException = class extends ErrorResponse {
3030
+ static {
3031
+ __name(this, "BadRequestException");
3032
+ }
3033
+ /**
3034
+ * @param message - Optional custom message. Defaults to "Bad request".
3035
+ */
3036
+ constructor(message = "Bad request") {
3037
+ super(message);
3038
+ this.status = HttpStatusCodes.BAD_REQUEST;
2810
3039
  }
2811
3040
  };
2812
- var rateLimiterCache = new RateLimiterCache();
2813
- var DIContainer = class {
3041
+ var NotFoundException = class extends ErrorResponse {
2814
3042
  static {
2815
- __name(this, "DIContainer");
3043
+ __name(this, "NotFoundException");
2816
3044
  }
2817
- instances = /* @__PURE__ */ new Map();
2818
- constructing = /* @__PURE__ */ new Map();
2819
- register(target) {
2820
- if (!this.instances.has(target) && !this.constructing.has(target)) ;
3045
+ /**
3046
+ * @param message - Optional custom message. Defaults to "Resource not found".
3047
+ */
3048
+ constructor(message = "Resource not found") {
3049
+ super(message);
3050
+ this.status = HttpStatusCodes.NOT_FOUND;
2821
3051
  }
2822
- get(target) {
2823
- if (this.instances.has(target)) {
2824
- return this.instances.get(target);
2825
- }
2826
- if (this.constructing.has(target)) {
2827
- return this.constructing.get(target);
2828
- }
2829
- let proxy = {};
2830
- this.constructing.set(target, proxy);
2831
- const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
2832
- const dependencies = paramTypes.map((dep) => this.get(dep));
2833
- const instance = new target(...dependencies);
2834
- Object.assign(proxy, instance);
2835
- this.instances.set(target, proxy);
2836
- this.constructing.delete(target);
2837
- Object.setPrototypeOf(proxy, target.prototype);
2838
- return proxy;
3052
+ };
3053
+ var ForbiddenException = class extends ErrorResponse {
3054
+ static {
3055
+ __name(this, "ForbiddenException");
2839
3056
  }
2840
- clear() {
2841
- this.instances.clear();
2842
- this.constructing.clear();
3057
+ /**
3058
+ * @param message - Optional custom message. Defaults to "Forbidden".
3059
+ */
3060
+ constructor(message = "Forbidden") {
3061
+ super(message);
3062
+ this.status = HttpStatusCodes.FORBIDDEN;
2843
3063
  }
2844
3064
  };
2845
- var diContainer = new DIContainer();
2846
- function normalizeHeaderValue(value) {
2847
- if (typeof value === "undefined") return void 0;
2848
- if (typeof value === "string") return value;
2849
- if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
2850
- return value;
3065
+ var ConflictException = class extends ErrorResponse {
3066
+ static {
3067
+ __name(this, "ConflictException");
2851
3068
  }
2852
- return String(value);
2853
- }
2854
- __name(normalizeHeaderValue, "normalizeHeaderValue");
2855
- function Injectable() {
2856
- return (target) => {
2857
- Reflect.defineMetadata("injectable", true, target);
2858
- diContainer.register(target);
2859
- };
2860
- }
2861
- __name(Injectable, "Injectable");
2862
- function Inject(targetClass) {
2863
- return (target, propertyKey) => {
2864
- Object.defineProperty(target, propertyKey, {
2865
- get: /* @__PURE__ */ __name(function() {
2866
- return diContainer.get(targetClass);
2867
- }, "get"),
2868
- enumerable: true,
2869
- configurable: true
2870
- });
2871
- };
2872
- }
2873
- __name(Inject, "Inject");
2874
- function createRouteDecorator(method) {
2875
- return (path3) => {
2876
- return (target, propertyKey, _descriptor) => {
2877
- const routes = Reflect.getMetadata(ROUTES_KEY, target.constructor) || [];
2878
- routes.push({
2879
- path: path3,
2880
- method,
2881
- handlerName: propertyKey
2882
- });
2883
- Reflect.defineMetadata(ROUTES_KEY, routes, target.constructor);
2884
- };
2885
- };
2886
- }
2887
- __name(createRouteDecorator, "createRouteDecorator");
2888
- var Get = createRouteDecorator("get");
2889
- var Post = createRouteDecorator("post");
2890
- var Put = createRouteDecorator("put");
2891
- var Patch = createRouteDecorator("patch");
2892
- var Delete = createRouteDecorator("delete");
2893
- var Options = createRouteDecorator("options");
2894
- var Head = createRouteDecorator("head");
2895
- var Trace = createRouteDecorator("trace");
2896
- var Connect = createRouteDecorator("connect");
2897
- function Controller(basePath) {
2898
- return (target) => {
2899
- Reflect.defineMetadata("basePath", basePath, target);
2900
- };
2901
- }
2902
- __name(Controller, "Controller");
2903
- function Use(...middlewares) {
2904
- return (target, propertyKey, _descriptor) => {
2905
- const existing = Reflect.getMetadata(MIDDLEWARE_KEY, target, propertyKey) || [];
2906
- Reflect.defineMetadata(MIDDLEWARE_KEY, [
2907
- ...existing,
2908
- ...middlewares
2909
- ], target, propertyKey);
2910
- };
2911
- }
2912
- __name(Use, "Use");
2913
- function createParamDecorator(type, key) {
2914
- return (paramKey) => {
2915
- return (target, propertyKey, parameterIndex) => {
2916
- const params = Reflect.getMetadata(PARAMS_KEY, target, propertyKey) || [];
2917
- params.push({
2918
- index: parameterIndex,
2919
- type,
2920
- key: paramKey || key
2921
- });
2922
- params.sort((a, b) => a.index - b.index);
2923
- Reflect.defineMetadata(PARAMS_KEY, params, target, propertyKey);
2924
- };
2925
- };
2926
- }
2927
- __name(createParamDecorator, "createParamDecorator");
2928
- var Query = createParamDecorator("query");
2929
- var Param = createParamDecorator("param");
2930
- var Body = createParamDecorator("body");
2931
- var Req = createParamDecorator("req");
2932
- var Res = createParamDecorator("res");
2933
- function HttpCode(status) {
2934
- return (target, propertyKey, _descriptor) => {
2935
- Reflect.defineMetadata(HTTP_CODE_KEY, status, target, propertyKey);
2936
- };
2937
- }
2938
- __name(HttpCode, "HttpCode");
2939
- function Header(name, value) {
2940
- return Headers(name, value);
2941
- }
2942
- __name(Header, "Header");
2943
- function Headers(headers, value) {
2944
- return (target, propertyKey) => {
2945
- if (typeof propertyKey === "undefined") {
2946
- const existing = Reflect.getMetadata(HEADER_KEY, target) || {};
2947
- const newHeaders = typeof headers === "string" ? {
2948
- [headers]: value
2949
- } : headers;
2950
- Reflect.defineMetadata(HEADER_KEY, {
2951
- ...existing,
2952
- ...newHeaders
2953
- }, target);
2954
- } else {
2955
- const existing = Reflect.getMetadata(HEADER_KEY, target, propertyKey) || {};
2956
- const newHeaders = typeof headers === "string" ? {
2957
- [headers]: value
2958
- } : headers;
2959
- Reflect.defineMetadata(HEADER_KEY, {
2960
- ...existing,
2961
- ...newHeaders
2962
- }, target, propertyKey);
2963
- }
2964
- };
3069
+ /**
3070
+ * @param message - Optional custom message. Defaults to "Conflict".
3071
+ */
3072
+ constructor(message = "Conflict") {
3073
+ super(message);
3074
+ this.status = HttpStatusCodes.CONFLICT;
3075
+ }
3076
+ };
3077
+ var BadGatewayException = class extends ErrorResponse {
3078
+ static {
3079
+ __name(this, "BadGatewayException");
3080
+ }
3081
+ /**
3082
+ * @param message - Optional custom message. Defaults to "Bad Gateway".
3083
+ */
3084
+ constructor(message = "Bad Gateway") {
3085
+ super(message);
3086
+ this.status = HttpStatusCodes.BAD_GATEWAY;
3087
+ }
3088
+ };
3089
+ var TooManyRequestsException = class extends ErrorResponse {
3090
+ static {
3091
+ __name(this, "TooManyRequestsException");
3092
+ }
3093
+ /**
3094
+ * @param message - Optional custom message. Defaults to "Too many requests".
3095
+ */
3096
+ constructor(message = "Too many requests") {
3097
+ super(message);
3098
+ this.status = HttpStatusCodes.TOO_MANY_REQUESTS;
3099
+ }
3100
+ };
3101
+ var ServiceUnavailableException = class extends ErrorResponse {
3102
+ static {
3103
+ __name(this, "ServiceUnavailableException");
3104
+ }
3105
+ /**
3106
+ * @param message - Optional custom message. Defaults to "Service Unavailable".
3107
+ */
3108
+ constructor(message = "Service Unavailable") {
3109
+ super(message);
3110
+ this.status = HttpStatusCodes.SERVICE_UNAVAILABLE;
3111
+ }
3112
+ };
3113
+ var GatewayTimeoutException = class extends ErrorResponse {
3114
+ static {
3115
+ __name(this, "GatewayTimeoutException");
3116
+ }
3117
+ /**
3118
+ * @param message - Optional custom message. Defaults to "Gateway Timeout".
3119
+ */
3120
+ constructor(message = "Gateway Timeout") {
3121
+ super(message);
3122
+ this.status = HttpStatusCodes.GATEWAY_TIMEOUT;
3123
+ }
3124
+ };
3125
+ var UnprocessableEntityException = class extends ErrorResponse {
3126
+ static {
3127
+ __name(this, "UnprocessableEntityException");
3128
+ }
3129
+ details;
3130
+ /**
3131
+ * @param message - Optional custom message. Defaults to "Unprocessable Entity".
3132
+ * @param details - Optional validation details or additional error context.
3133
+ */
3134
+ constructor(message = "Unprocessable Entity", details) {
3135
+ super(message), this.details = details;
3136
+ this.status = HttpStatusCodes.UNPROCESSABLE_ENTITY;
3137
+ }
3138
+ };
3139
+ var MethodNotAllowedException = class extends ErrorResponse {
3140
+ static {
3141
+ __name(this, "MethodNotAllowedException");
3142
+ }
3143
+ allowedMethods;
3144
+ /**
3145
+ * @param message - Optional custom message. Defaults to "Method Not Allowed".
3146
+ * @param allowedMethods - Optional array of allowed HTTP methods.
3147
+ */
3148
+ constructor(message = "Method Not Allowed", allowedMethods) {
3149
+ super(message), this.allowedMethods = allowedMethods;
3150
+ this.status = HttpStatusCodes.METHOD_NOT_ALLOWED;
3151
+ }
3152
+ };
3153
+ var NotAcceptableException = class extends ErrorResponse {
3154
+ static {
3155
+ __name(this, "NotAcceptableException");
3156
+ }
3157
+ /**
3158
+ * @param message - Optional custom message. Defaults to "Not Acceptable".
3159
+ */
3160
+ constructor(message = "Not Acceptable") {
3161
+ super(message);
3162
+ this.status = HttpStatusCodes.NOT_ACCEPTABLE;
3163
+ }
3164
+ };
3165
+ var RequestTimeoutException = class extends ErrorResponse {
3166
+ static {
3167
+ __name(this, "RequestTimeoutException");
3168
+ }
3169
+ /**
3170
+ * @param message - Optional custom message. Defaults to "Request Timeout".
3171
+ */
3172
+ constructor(message = "Request Timeout") {
3173
+ super(message);
3174
+ this.status = HttpStatusCodes.REQUEST_TIMEOUT;
3175
+ }
3176
+ };
3177
+ var UnsupportedMediaTypeException = class extends ErrorResponse {
3178
+ static {
3179
+ __name(this, "UnsupportedMediaTypeException");
3180
+ }
3181
+ /**
3182
+ * @param message - Optional custom message. Defaults to "Unsupported Media Type".
3183
+ */
3184
+ constructor(message = "Unsupported Media Type") {
3185
+ super(message);
3186
+ this.status = HttpStatusCodes.UNSUPPORTED_MEDIA_TYPE;
3187
+ }
3188
+ };
3189
+ var PayloadTooLargeException = class extends ErrorResponse {
3190
+ static {
3191
+ __name(this, "PayloadTooLargeException");
3192
+ }
3193
+ /**
3194
+ * @param message - Optional custom message. Defaults to "Payload Too Large".
3195
+ */
3196
+ constructor(message = "Payload Too Large") {
3197
+ super(message);
3198
+ this.status = HttpStatusCodes.PAYLOAD_TOO_LARGE;
3199
+ }
3200
+ };
3201
+ var InsufficientStorageException = class extends ErrorResponse {
3202
+ static {
3203
+ __name(this, "InsufficientStorageException");
3204
+ }
3205
+ /**
3206
+ * @param message - Optional custom message. Defaults to "Insufficient Storage".
3207
+ */
3208
+ constructor(message = "Insufficient Storage") {
3209
+ super(message);
3210
+ this.status = HttpStatusCodes.INSUFFICIENT_STORAGE;
3211
+ }
3212
+ };
3213
+ function isHttpError(error) {
3214
+ return error instanceof ErrorResponse;
2965
3215
  }
2966
- __name(Headers, "Headers");
2967
- function Before(fn) {
2968
- return (target, propertyKey, _descriptor) => {
2969
- const hooks = Reflect.getMetadata(BEFORE_KEY, target, propertyKey) || [];
2970
- hooks.push(fn);
2971
- Reflect.defineMetadata(BEFORE_KEY, hooks, target, propertyKey);
2972
- };
3216
+ __name(isHttpError, "isHttpError");
3217
+ function createHttpError(status, message) {
3218
+ switch (status) {
3219
+ case HttpStatusCodes.BAD_REQUEST:
3220
+ return new BadRequestException(message);
3221
+ case HttpStatusCodes.UNAUTHORIZED:
3222
+ return new UnauthorizedException(message);
3223
+ case HttpStatusCodes.FORBIDDEN:
3224
+ return new ForbiddenException(message);
3225
+ case HttpStatusCodes.NOT_FOUND:
3226
+ return new NotFoundException(message);
3227
+ case HttpStatusCodes.METHOD_NOT_ALLOWED:
3228
+ return new MethodNotAllowedException(message);
3229
+ case HttpStatusCodes.NOT_ACCEPTABLE:
3230
+ return new NotAcceptableException(message);
3231
+ case HttpStatusCodes.REQUEST_TIMEOUT:
3232
+ return new RequestTimeoutException(message);
3233
+ case HttpStatusCodes.CONFLICT:
3234
+ return new ConflictException(message);
3235
+ case HttpStatusCodes.GONE:
3236
+ return new HttpError(HttpStatusCodes.GONE, message || "Gone");
3237
+ case HttpStatusCodes.PAYLOAD_TOO_LARGE:
3238
+ return new PayloadTooLargeException(message);
3239
+ case HttpStatusCodes.UNSUPPORTED_MEDIA_TYPE:
3240
+ return new UnsupportedMediaTypeException(message);
3241
+ case HttpStatusCodes.UNPROCESSABLE_ENTITY:
3242
+ return new UnprocessableEntityException(message);
3243
+ case HttpStatusCodes.TOO_MANY_REQUESTS:
3244
+ return new TooManyRequestsException(message);
3245
+ case HttpStatusCodes.INTERNAL_SERVER_ERROR:
3246
+ return new InternalServerErrorException(message);
3247
+ case HttpStatusCodes.BAD_GATEWAY:
3248
+ return new BadGatewayException(message);
3249
+ case HttpStatusCodes.SERVICE_UNAVAILABLE:
3250
+ return new ServiceUnavailableException(message);
3251
+ case HttpStatusCodes.GATEWAY_TIMEOUT:
3252
+ return new GatewayTimeoutException(message);
3253
+ case HttpStatusCodes.INSUFFICIENT_STORAGE:
3254
+ return new InsufficientStorageException(message);
3255
+ default:
3256
+ return new HttpError(status, message || `HTTP Error ${status}`);
3257
+ }
2973
3258
  }
2974
- __name(Before, "Before");
2975
- function After(fn) {
2976
- return (target, propertyKey, _descriptor) => {
2977
- const hooks = Reflect.getMetadata(AFTER_KEY, target, propertyKey) || [];
2978
- hooks.push(fn);
2979
- Reflect.defineMetadata(AFTER_KEY, hooks, target, propertyKey);
2980
- };
3259
+ __name(createHttpError, "createHttpError");
3260
+ function hasErrorShape(error) {
3261
+ return typeof error === "object" && error !== null && "message" in error && typeof error.message === "string";
2981
3262
  }
2982
- __name(After, "After");
2983
- function Roles(...roles) {
2984
- return (target, propertyKey, _descriptor) => {
2985
- if (typeof propertyKey === "undefined") {
2986
- Reflect.defineMetadata(ROLES_KEY, roles, target);
2987
- } else {
2988
- Reflect.defineMetadata(ROLES_KEY, roles, target, propertyKey);
3263
+ __name(hasErrorShape, "hasErrorShape");
3264
+ function getErrorMessage(error) {
3265
+ if (typeof error === "string") {
3266
+ return error;
3267
+ }
3268
+ if (error instanceof Error) {
3269
+ return error.message;
3270
+ }
3271
+ if (hasErrorShape(error)) {
3272
+ return error.message;
3273
+ }
3274
+ return "Unknown error occurred";
3275
+ }
3276
+ __name(getErrorMessage, "getErrorMessage");
3277
+ function withErrorHandling(handler) {
3278
+ return async (...args) => {
3279
+ try {
3280
+ return await handler(...args);
3281
+ } catch (err) {
3282
+ if (isHttpError(err)) {
3283
+ throw err;
3284
+ }
3285
+ getLogger().error({
3286
+ err
3287
+ }, "Caught error in handler");
3288
+ let status = HttpStatusCodes.INTERNAL_SERVER_ERROR;
3289
+ if (hasErrorShape(err) && typeof err.status === "number") {
3290
+ status = err.status;
3291
+ }
3292
+ throw createHttpError(status, getErrorMessage(err));
2989
3293
  }
2990
3294
  };
2991
3295
  }
2992
- __name(Roles, "Roles");
2993
- function Redirect(url, statusCode = 302) {
2994
- return (target, propertyKey, descriptor) => {
2995
- Reflect.defineMetadata(REDIRECT_KEY, {
2996
- url,
2997
- statusCode
2998
- }, target, propertyKey);
2999
- return descriptor;
3000
- };
3001
- }
3002
- __name(Redirect, "Redirect");
3003
- function Cache(ttlSeconds) {
3004
- return (target, propertyKey, _descriptor) => {
3005
- if (typeof propertyKey === "undefined") {
3006
- Reflect.defineMetadata(CACHE_KEY, {
3007
- ttlSeconds
3008
- }, target);
3009
- } else {
3010
- Reflect.defineMetadata(CACHE_KEY, {
3011
- ttlSeconds
3012
- }, target, propertyKey);
3013
- }
3014
- };
3015
- }
3016
- __name(Cache, "Cache");
3017
- function RateLimit(options) {
3018
- const opts = {
3019
- standardHeaders: true,
3020
- legacyHeaders: false,
3021
- ...options
3022
- };
3023
- return (target, propertyKey, _descriptor) => {
3024
- if (typeof propertyKey === "undefined") {
3025
- Reflect.defineMetadata(RATE_LIMIT_KEY, opts, target);
3026
- } else {
3027
- Reflect.defineMetadata(RATE_LIMIT_KEY, opts, target, propertyKey);
3028
- }
3029
- };
3030
- }
3031
- __name(RateLimit, "RateLimit");
3032
- function ContentType(type) {
3033
- return (target, propertyKey, _descriptor) => {
3034
- Reflect.defineMetadata(CONTENT_TYPE_KEY, {
3035
- type
3036
- }, target, propertyKey);
3037
- };
3038
- }
3039
- __name(ContentType, "ContentType");
3040
- function Version(version, options) {
3041
- const opts = {
3042
- addPrefix: true,
3043
- addHeader: true,
3044
- headerName: "X-API-Version",
3045
- ...options
3046
- };
3047
- return (target, propertyKey, _descriptor) => {
3048
- if (typeof propertyKey === "undefined") {
3049
- Reflect.defineMetadata(VERSION_KEY, {
3050
- version,
3051
- options: opts
3052
- }, target);
3053
- } else {
3054
- Reflect.defineMetadata(VERSION_KEY, {
3055
- version,
3056
- options: opts
3057
- }, target, propertyKey);
3058
- }
3059
- };
3060
- }
3061
- __name(Version, "Version");
3062
- function Timeout(ms) {
3063
- return (target, propertyKey, _descriptor) => {
3064
- if (typeof propertyKey === "undefined") {
3065
- Reflect.defineMetadata(TIMEOUT_KEY, {
3066
- ms
3067
- }, target);
3068
- } else {
3069
- Reflect.defineMetadata(TIMEOUT_KEY, {
3070
- ms
3071
- }, target, propertyKey);
3072
- }
3073
- };
3074
- }
3075
- __name(Timeout, "Timeout");
3076
- function Log(options) {
3077
- return (target, propertyKey, _descriptor) => {
3078
- const config2 = {
3079
- logEntry: true,
3080
- logExit: true,
3081
- logBody: false,
3082
- logParams: false,
3083
- logResponse: false,
3084
- ...options
3085
- };
3086
- if (typeof propertyKey === "undefined") {
3087
- Reflect.defineMetadata(LOG_KEY, config2, target);
3088
- } else {
3089
- Reflect.defineMetadata(LOG_KEY, config2, target, propertyKey);
3090
- }
3091
- };
3092
- }
3093
- __name(Log, "Log");
3094
- function registerControllers(router, controllers) {
3095
- controllers.forEach((ControllerClass) => {
3096
- const instance = diContainer.get(ControllerClass);
3097
- const basePath = Reflect.getMetadata("basePath", ControllerClass) || "";
3098
- const routes = Reflect.getMetadata(ROUTES_KEY, ControllerClass) || [];
3099
- const controllerRateLimit = Reflect.getMetadata(RATE_LIMIT_KEY, ControllerClass);
3100
- const controllerCache = Reflect.getMetadata(CACHE_KEY, ControllerClass);
3101
- const controllerTimeout = Reflect.getMetadata(TIMEOUT_KEY, ControllerClass);
3102
- const controllerVersion = Reflect.getMetadata(VERSION_KEY, ControllerClass);
3103
- const controllerRoles = Reflect.getMetadata(ROLES_KEY, ControllerClass);
3104
- const controllerLogConfig = Reflect.getMetadata(LOG_KEY, ControllerClass);
3105
- const controllerHeaders = Reflect.getMetadata(HEADER_KEY, ControllerClass) || {};
3106
- routes.forEach(({ path: path3, method, handlerName }) => {
3107
- const middlewares = Reflect.getMetadata(MIDDLEWARE_KEY, instance, handlerName) || [];
3108
- const params = Reflect.getMetadata(PARAMS_KEY, instance, handlerName) || [];
3109
- const httpCode = Reflect.getMetadata(HTTP_CODE_KEY, instance, handlerName);
3110
- const methodHeaders = Reflect.getMetadata(HEADER_KEY, instance, handlerName) || {};
3111
- const headers = {
3112
- ...controllerHeaders,
3113
- ...methodHeaders
3114
- };
3115
- const beforeHooks = Reflect.getMetadata(BEFORE_KEY, instance, handlerName) || [];
3116
- const afterHooks = Reflect.getMetadata(AFTER_KEY, instance, handlerName) || [];
3117
- const redirect = Reflect.getMetadata(REDIRECT_KEY, instance, handlerName);
3118
- const contentType = Reflect.getMetadata(CONTENT_TYPE_KEY, instance, handlerName);
3119
- const roles = Reflect.getMetadata(ROLES_KEY, instance, handlerName) || controllerRoles || [];
3120
- const cache = Reflect.getMetadata(CACHE_KEY, instance, handlerName) || controllerCache;
3121
- const rateLimitOptions = Reflect.getMetadata(RATE_LIMIT_KEY, instance, handlerName) || controllerRateLimit;
3122
- const version = Reflect.getMetadata(VERSION_KEY, instance, handlerName) || controllerVersion;
3123
- const timeout2 = Reflect.getMetadata(TIMEOUT_KEY, instance, handlerName) || controllerTimeout;
3124
- const logConfig = Reflect.getMetadata(LOG_KEY, instance, handlerName) || controllerLogConfig;
3125
- let rateLimiter = null;
3126
- if (rateLimitOptions) {
3127
- try {
3128
- rateLimiter = rateLimiterCache.get(rateLimitOptions);
3129
- } catch (err) {
3130
- getLogger().warn({
3131
- err
3132
- }, "express-rate-limit not available, skipping rate limiting for this route");
3133
- }
3134
- }
3135
- let finalPath = path3;
3136
- if (version?.options?.addPrefix) {
3137
- finalPath = `/${version.version}${path3}`;
3138
- }
3139
- const handler = /* @__PURE__ */ __name(async (req, res, next) => {
3140
- req["startTime"] = Date.now();
3141
- let timeoutId;
3142
- let timedOut = false;
3143
- try {
3144
- if (timeout2) {
3145
- timeoutId = setTimeout(() => {
3146
- if (!res.headersSent && !timedOut) {
3147
- timedOut = true;
3148
- const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.REQUEST_TIMEOUT, "Request timed out");
3149
- res.status(HttpStatusCodes.REQUEST_TIMEOUT).json(errorResponse);
3150
- }
3151
- }, timeout2.ms);
3152
- }
3153
- if (timedOut) return;
3154
- if (rateLimiter) {
3155
- await new Promise((resolve2, reject) => {
3156
- rateLimiter(req, res, (err) => {
3157
- if (err) reject(err);
3158
- else resolve2();
3159
- });
3160
- });
3161
- }
3162
- if (!res.headersSent && contentType) {
3163
- res.setHeader("Content-Type", contentType.type);
3164
- }
3165
- if (version?.options?.addHeader && version?.options?.headerName && version?.version) {
3166
- if (!res.headersSent) {
3167
- res.setHeader(version.options.headerName, version.version);
3168
- }
3169
- }
3170
- if (cache && !res.headersSent) {
3171
- res.setHeader("Cache-Control", `public, max-age=${cache.ttlSeconds}`);
3172
- }
3173
- if (logConfig?.logEntry) {
3174
- const logger2 = getLogger();
3175
- const logData = {
3176
- method: req.method,
3177
- url: req.originalUrl || req.url,
3178
- userAgent: req.get("User-Agent")
3179
- };
3180
- if (logConfig.logParams) {
3181
- logData.params = req.params;
3182
- logData.query = req.query;
3183
- }
3184
- if (logConfig.logBody) logData.body = req.body;
3185
- logger2.info({
3186
- entry: logData
3187
- }, "Route Entry:");
3188
- }
3189
- if (roles.length && !req?.user?.roles?.some((role) => roles.includes(role))) {
3190
- const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.FORBIDDEN, "Forbidden Insufficient Roles");
3191
- res.status(HttpStatusCodes.FORBIDDEN).json(errorResponse);
3192
- if (timeoutId) {
3193
- clearTimeout(timeoutId);
3194
- }
3195
- return;
3196
- }
3197
- if (redirect && redirect.url) {
3198
- if (timeoutId) {
3199
- clearTimeout(timeoutId);
3200
- }
3201
- return res.redirect(redirect.statusCode, redirect.url);
3202
- }
3203
- for (const fn of beforeHooks) await fn(req, res);
3204
- const args = [];
3205
- if (params.length) {
3206
- params.forEach(({ index, type, key }) => {
3207
- switch (type) {
3208
- case "query":
3209
- args[index] = key ? req.query[key] : req.query;
3210
- break;
3211
- case "param":
3212
- args[index] = key ? req.params[key] : req.params;
3213
- break;
3214
- case "body":
3215
- args[index] = key ? req.body?.[key] : req.body;
3216
- break;
3217
- case "req":
3218
- args[index] = req;
3219
- break;
3220
- case "res":
3221
- args[index] = res;
3222
- break;
3223
- }
3224
- });
3225
- }
3226
- const result = instance[handlerName](...args);
3227
- const awaited = result instanceof Promise ? await result : result;
3228
- if (timeoutId) {
3229
- clearTimeout(timeoutId);
3230
- }
3231
- if (timedOut) return;
3232
- if (redirect && awaited && typeof awaited === "object" && "url" in awaited) {
3233
- const redirectUrl = awaited.url;
3234
- const redirectStatus = awaited.statusCode || redirect.statusCode;
3235
- return res.redirect(redirectStatus, redirectUrl);
3236
- }
3237
- if (!res.headersSent && typeof awaited !== "undefined") {
3238
- if (httpCode) res.status(httpCode);
3239
- for (const [k, v] of Object.entries(headers)) {
3240
- const normalized = normalizeHeaderValue(v);
3241
- if (typeof normalized !== "undefined") {
3242
- res.set(k, normalized);
3243
- }
3244
- }
3245
- res.json(awaited);
3246
- }
3247
- if (logConfig?.logExit) {
3248
- const logger2 = getLogger();
3249
- const logData = {
3250
- method: req.method,
3251
- url: req.originalUrl || req.url,
3252
- statusCode: res.statusCode,
3253
- duration: `${Date.now() - req.startTime}ms`
3254
- };
3255
- if (logConfig.logResponse) logData.response = awaited;
3256
- logger2.info({
3257
- exit: logData
3258
- }, "Route Exit:");
3259
- }
3260
- for (const fn of afterHooks) await fn(req, res, awaited);
3261
- } catch (err) {
3262
- if (timeoutId) {
3263
- clearTimeout(timeoutId);
3264
- }
3265
- next(err);
3266
- }
3267
- }, "handler");
3268
- router[method](basePath + finalPath, ...middlewares, handler);
3296
+ __name(withErrorHandling, "withErrorHandling");
3297
+
3298
+ // src/utils/decorators.utils.ts
3299
+ var ROUTES_KEY = Symbol("routes");
3300
+ var MIDDLEWARE_KEY = Symbol("middlewares");
3301
+ var PARAMS_KEY = Symbol("params");
3302
+ var HTTP_CODE_KEY = Symbol("httpCode");
3303
+ var HEADER_KEY = Symbol("headers");
3304
+ var BEFORE_KEY = Symbol("before");
3305
+ var AFTER_KEY = Symbol("after");
3306
+ var ROLES_KEY = Symbol("roles");
3307
+ var REDIRECT_KEY = Symbol("redirect");
3308
+ var CACHE_KEY = Symbol("cache");
3309
+ var RATE_LIMIT_KEY = Symbol("rateLimit");
3310
+ var CONTENT_TYPE_KEY = Symbol("contentType");
3311
+ var VERSION_KEY = Symbol("version");
3312
+ var TIMEOUT_KEY = Symbol("timeout");
3313
+ var LOG_KEY = Symbol("log");
3314
+ var RateLimiterCache = class RateLimiterCache2 {
3315
+ static {
3316
+ __name(this, "RateLimiterCache");
3317
+ }
3318
+ cache;
3319
+ constructor(maxSize = 100, ttlMs = 5 * 60 * 1e3) {
3320
+ this.cache = new TTLCache({
3321
+ maxSize,
3322
+ ttlMs
3323
+ });
3324
+ }
3325
+ generateKey(options) {
3326
+ return `${options.max}:${options.windowMs}:${options.standardHeaders}:${options.legacyHeaders}`;
3327
+ }
3328
+ get(options) {
3329
+ const key = this.generateKey(options);
3330
+ const cached = this.cache.get(key);
3331
+ if (cached) {
3332
+ return cached.limiter;
3333
+ }
3334
+ const limiter = expressRateLimit.rateLimit({
3335
+ ...options,
3336
+ handler: /* @__PURE__ */ __name((req, res) => {
3337
+ const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.TOO_MANY_REQUESTS, "Too Many Requests");
3338
+ res.status(HttpStatusCodes.TOO_MANY_REQUESTS).json(errorResponse);
3339
+ }, "handler")
3269
3340
  });
3270
- });
3271
- }
3272
- __name(registerControllers, "registerControllers");
3273
- async function ensureDir(dirPath) {
3274
- await fsp__default.default.mkdir(dirPath, {
3275
- recursive: true
3276
- });
3277
- }
3278
- __name(ensureDir, "ensureDir");
3279
- async function listFiles(dirPath, recursive = false) {
3280
- const entries = await fsp__default.default.readdir(dirPath, {
3281
- withFileTypes: true
3282
- });
3283
- const files = [];
3284
- for (const entry of entries) {
3285
- const fullPath = path__default.default.join(dirPath, entry.name);
3286
- if (entry.isFile()) {
3287
- files.push(fullPath);
3288
- } else if (recursive && entry.isDirectory()) {
3289
- const nestedFiles = await listFiles(fullPath, true);
3290
- files.push(...nestedFiles);
3341
+ this.cache.set(key, {
3342
+ limiter,
3343
+ config: key
3344
+ });
3345
+ return limiter;
3346
+ }
3347
+ clear() {
3348
+ this.cache.clear();
3349
+ }
3350
+ size() {
3351
+ return this.cache.size();
3352
+ }
3353
+ destroy() {
3354
+ this.cache.destroy();
3355
+ }
3356
+ };
3357
+ var rateLimiterCache = new RateLimiterCache();
3358
+ var DIContainer = class {
3359
+ static {
3360
+ __name(this, "DIContainer");
3361
+ }
3362
+ instances = /* @__PURE__ */ new Map();
3363
+ constructing = /* @__PURE__ */ new Map();
3364
+ propertyInjections = /* @__PURE__ */ new Map();
3365
+ register(target) {
3366
+ if (!this.instances.has(target) && !this.constructing.has(target)) ;
3367
+ }
3368
+ /**
3369
+ * Register a property injection to be resolved when the target class is instantiated
3370
+ */
3371
+ registerPropertyInjection(target, propertyKey, injectClass) {
3372
+ const targetClass = target.constructor;
3373
+ if (!this.propertyInjections.has(targetClass)) {
3374
+ this.propertyInjections.set(targetClass, []);
3291
3375
  }
3376
+ this.propertyInjections.get(targetClass).push({
3377
+ targetClass: injectClass,
3378
+ propertyKey
3379
+ });
3292
3380
  }
3293
- return files;
3294
- }
3295
- __name(listFiles, "listFiles");
3296
- async function deleteDirRecursive(dirPath) {
3297
- await fsp__default.default.rm(dirPath, {
3298
- recursive: true,
3299
- force: true
3300
- });
3301
- }
3302
- __name(deleteDirRecursive, "deleteDirRecursive");
3303
- async function isDirectory(pathStr) {
3304
- try {
3305
- const stat = await fsp__default.default.stat(pathStr);
3306
- return stat.isDirectory();
3307
- } catch {
3308
- return false;
3381
+ get(target) {
3382
+ if (this.instances.has(target)) {
3383
+ return this.instances.get(target);
3384
+ }
3385
+ if (this.constructing.has(target)) {
3386
+ return this.constructing.get(target);
3387
+ }
3388
+ let proxy = {};
3389
+ this.constructing.set(target, proxy);
3390
+ const paramTypes = Reflect.getMetadata("design:paramtypes", target) || [];
3391
+ const dependencies = paramTypes.map((dep) => this.get(dep));
3392
+ const instance = new target(...dependencies);
3393
+ this.applyPropertyInjections(target, instance);
3394
+ Object.assign(proxy, instance);
3395
+ this.instances.set(target, proxy);
3396
+ this.constructing.delete(target);
3397
+ Object.setPrototypeOf(proxy, target.prototype);
3398
+ return proxy;
3309
3399
  }
3310
- }
3311
- __name(isDirectory, "isDirectory");
3312
- async function copyDir(src, dest) {
3313
- await ensureDir(dest);
3314
- const entries = await fsp__default.default.readdir(src, {
3315
- withFileTypes: true
3316
- });
3317
- for (const entry of entries) {
3318
- const srcPath = path__default.default.join(src, entry.name);
3319
- const destPath = path__default.default.join(dest, entry.name);
3320
- if (entry.isDirectory()) {
3321
- await copyDir(srcPath, destPath);
3322
- } else {
3323
- await fsp__default.default.copyFile(srcPath, destPath);
3400
+ applyPropertyInjections(targetClass, instance) {
3401
+ const injections = this.propertyInjections.get(targetClass) || [];
3402
+ for (const injection of injections) {
3403
+ const dependency = this.get(injection.targetClass);
3404
+ instance[injection.propertyKey] = dependency;
3324
3405
  }
3325
3406
  }
3407
+ clear() {
3408
+ this.instances.clear();
3409
+ this.constructing.clear();
3410
+ this.propertyInjections.clear();
3411
+ }
3412
+ };
3413
+ var diContainer = new DIContainer();
3414
+ function normalizeHeaderValue(value) {
3415
+ if (typeof value === "undefined") return void 0;
3416
+ if (typeof value === "string") return value;
3417
+ if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
3418
+ return value;
3419
+ }
3420
+ return String(value);
3326
3421
  }
3327
- __name(copyDir, "copyDir");
3328
- async function moveDir(src, dest) {
3329
- await copyDir(src, dest);
3330
- await deleteDirRecursive(src);
3422
+ __name(normalizeHeaderValue, "normalizeHeaderValue");
3423
+ function Injectable() {
3424
+ return (target) => {
3425
+ Reflect.defineMetadata("injectable", true, target);
3426
+ diContainer.register(target);
3427
+ };
3331
3428
  }
3332
- __name(moveDir, "moveDir");
3333
- async function emptyDir(dirPath) {
3334
- const entries = await fsp__default.default.readdir(dirPath, {
3335
- withFileTypes: true
3336
- });
3337
- for (const entry of entries) {
3338
- const entryPath = path__default.default.join(dirPath, entry.name);
3339
- if (entry.isDirectory()) {
3340
- await fsp__default.default.rm(entryPath, {
3341
- recursive: true,
3342
- force: true
3429
+ __name(Injectable, "Injectable");
3430
+ function Inject(targetClass) {
3431
+ return (target, propertyKey) => {
3432
+ diContainer.registerPropertyInjection(target, propertyKey, targetClass);
3433
+ Object.defineProperty(target, propertyKey, {
3434
+ configurable: true,
3435
+ get: /* @__PURE__ */ __name(function() {
3436
+ const value = Object.getOwnPropertyDescriptor(this, propertyKey)?.value;
3437
+ if (value !== void 0) return value;
3438
+ const injectedValue = diContainer.get(targetClass);
3439
+ Object.defineProperty(this, propertyKey, {
3440
+ value: injectedValue,
3441
+ writable: true,
3442
+ configurable: true
3443
+ });
3444
+ return injectedValue;
3445
+ }, "get"),
3446
+ set: /* @__PURE__ */ __name(function(value) {
3447
+ Object.defineProperty(this, propertyKey, {
3448
+ value,
3449
+ writable: true,
3450
+ configurable: true
3451
+ });
3452
+ }, "set")
3453
+ });
3454
+ };
3455
+ }
3456
+ __name(Inject, "Inject");
3457
+ function inject(targetClass) {
3458
+ return diContainer.get(targetClass);
3459
+ }
3460
+ __name(inject, "inject");
3461
+ function createRouteDecorator(method) {
3462
+ return (path3) => {
3463
+ return (target, propertyKey, _descriptor) => {
3464
+ const routes = Reflect.getMetadata(ROUTES_KEY, target.constructor) || [];
3465
+ routes.push({
3466
+ path: path3,
3467
+ method,
3468
+ handlerName: propertyKey
3343
3469
  });
3344
- } else {
3345
- await fsp__default.default.unlink(entryPath);
3346
- }
3347
- }
3470
+ Reflect.defineMetadata(ROUTES_KEY, routes, target.constructor);
3471
+ };
3472
+ };
3348
3473
  }
3349
- __name(emptyDir, "emptyDir");
3350
- async function getDirSize(dirPath) {
3351
- let total = 0;
3352
- const entries = await fsp__default.default.readdir(dirPath, {
3353
- withFileTypes: true
3354
- });
3355
- for (const entry of entries) {
3356
- const entryPath = path__default.default.join(dirPath, entry.name);
3357
- if (entry.isDirectory()) {
3358
- total += await getDirSize(entryPath);
3474
+ __name(createRouteDecorator, "createRouteDecorator");
3475
+ var Get = createRouteDecorator("get");
3476
+ var Post = createRouteDecorator("post");
3477
+ var Put = createRouteDecorator("put");
3478
+ var Patch = createRouteDecorator("patch");
3479
+ var Delete = createRouteDecorator("delete");
3480
+ var Options = createRouteDecorator("options");
3481
+ var Head = createRouteDecorator("head");
3482
+ var Trace = createRouteDecorator("trace");
3483
+ var Connect = createRouteDecorator("connect");
3484
+ function Controller(basePath) {
3485
+ return (target) => {
3486
+ Reflect.defineMetadata("basePath", basePath, target);
3487
+ };
3488
+ }
3489
+ __name(Controller, "Controller");
3490
+ function Use(...middlewares) {
3491
+ return (target, propertyKey, _descriptor) => {
3492
+ if (typeof propertyKey === "undefined") {
3493
+ const existing = Reflect.getMetadata(MIDDLEWARE_KEY, target) || [];
3494
+ Reflect.defineMetadata(MIDDLEWARE_KEY, [
3495
+ ...existing,
3496
+ ...middlewares
3497
+ ], target);
3359
3498
  } else {
3360
- const stat = await fsp__default.default.stat(entryPath);
3361
- total += stat.size;
3499
+ const existing = Reflect.getMetadata(MIDDLEWARE_KEY, target, propertyKey) || [];
3500
+ Reflect.defineMetadata(MIDDLEWARE_KEY, [
3501
+ ...existing,
3502
+ ...middlewares
3503
+ ], target, propertyKey);
3362
3504
  }
3363
- }
3364
- return total;
3505
+ };
3365
3506
  }
3366
- __name(getDirSize, "getDirSize");
3367
- function watchDir(dirPath, callback) {
3368
- const watcher = fs__default.default.watch(dirPath, (eventType, filename) => {
3369
- callback(eventType, filename);
3507
+ __name(Use, "Use");
3508
+ function defineParamMetadata(target, propertyKey, parameterIndex, type, key) {
3509
+ const params = Reflect.getMetadata(PARAMS_KEY, target, propertyKey) || [];
3510
+ params.push({
3511
+ index: parameterIndex,
3512
+ type,
3513
+ key
3370
3514
  });
3371
- return () => watcher.close();
3515
+ params.sort((a, b) => a.index - b.index);
3516
+ Reflect.defineMetadata(PARAMS_KEY, params, target, propertyKey);
3372
3517
  }
3373
- __name(watchDir, "watchDir");
3374
- async function findFilesByPattern(pattern, options = {}) {
3375
- const matchPattern = /* @__PURE__ */ __name((name, pattern2) => {
3376
- let escaped = pattern2.replaceAll(/[.+^${}()|[\]\\]/g, "\\$&");
3377
- escaped = escaped.replaceAll("*", ".*").replaceAll("?", ".");
3378
- const regex = new RegExp(`^${escaped}$`);
3379
- return regex.test(name);
3380
- }, "matchPattern");
3381
- const { cwd = process.cwd(), dot = false } = options;
3382
- const segments = pattern.split("/");
3383
- async function walk(dir, segIndex) {
3384
- if (segIndex >= segments.length) return [];
3385
- const segment = segments[segIndex];
3386
- const entries = await fs__default.default.promises.readdir(dir, {
3387
- withFileTypes: true
3388
- });
3389
- let matchedFiles = [];
3390
- for (const entry of entries) {
3391
- const entryName = entry.name;
3392
- if (!dot && entryName.startsWith(".")) continue;
3393
- const fullPath = path__default.default.join(dir, entryName);
3394
- const isLastSegment = segIndex === segments.length - 1;
3395
- if (isLastSegment) {
3396
- if (matchPattern(entryName, segment) && entry.isFile()) {
3397
- matchedFiles.push(fullPath);
3398
- }
3399
- } else if (entry.isDirectory()) {
3400
- if (matchPattern(entryName, segment)) {
3401
- matchedFiles.push(...await walk(fullPath, segIndex + 1));
3402
- }
3518
+ __name(defineParamMetadata, "defineParamMetadata");
3519
+ function createParamDecorator(type, key) {
3520
+ return (paramKey) => {
3521
+ return (target, propertyKey, parameterIndex) => {
3522
+ defineParamMetadata(target, propertyKey, parameterIndex, type, paramKey ?? key);
3523
+ };
3524
+ };
3525
+ }
3526
+ __name(createParamDecorator, "createParamDecorator");
3527
+ function createParamDecoratorWithoutParam(type) {
3528
+ return () => {
3529
+ return (target, propertyKey, parameterIndex) => {
3530
+ defineParamMetadata(target, propertyKey, parameterIndex, type, void 0);
3531
+ };
3532
+ };
3533
+ }
3534
+ __name(createParamDecoratorWithoutParam, "createParamDecoratorWithoutParam");
3535
+ function createApiUrlParamDecorator(type, key) {
3536
+ return (paramKey, options) => {
3537
+ return (target, propertyKey, parameterIndex) => {
3538
+ const params = Reflect.getMetadata(PARAMS_KEY, target, propertyKey) || [];
3539
+ let paramOptions = void 0;
3540
+ if (typeof options === "object") {
3541
+ paramOptions = {};
3542
+ paramOptions.type = "string";
3543
+ paramOptions.dataType = "single";
3544
+ paramOptions.delimiter = ",";
3545
+ paramOptions.required = false;
3546
+ paramOptions.throwError = true;
3547
+ paramOptions = {
3548
+ ...paramOptions,
3549
+ ...options
3550
+ };
3403
3551
  }
3404
- }
3405
- return matchedFiles;
3406
- }
3407
- __name(walk, "walk");
3408
- return walk(cwd, 0);
3552
+ params.push({
3553
+ index: parameterIndex,
3554
+ type,
3555
+ key: paramKey || key,
3556
+ options: paramOptions
3557
+ });
3558
+ params.sort((a, b) => a.index - b.index);
3559
+ Reflect.defineMetadata(PARAMS_KEY, params, target, propertyKey);
3560
+ };
3561
+ };
3409
3562
  }
3410
- __name(findFilesByPattern, "findFilesByPattern");
3411
- async function getSubdirectories(dirPath, recursive = false) {
3412
- const entries = await fsp__default.default.readdir(dirPath, {
3413
- withFileTypes: true
3414
- });
3415
- const dirs = entries.filter((entry) => entry.isDirectory()).map((entry) => path__default.default.join(dirPath, entry.name));
3416
- if (recursive && dirs.length > 0) {
3417
- const nestedDirs = await Promise.all(dirs.map((dir) => getSubdirectories(dir, true)));
3418
- return [
3419
- ...dirs,
3420
- ...nestedDirs.flat()
3421
- ];
3422
- }
3423
- return dirs;
3563
+ __name(createApiUrlParamDecorator, "createApiUrlParamDecorator");
3564
+ var Query = createApiUrlParamDecorator("query");
3565
+ var Param = createApiUrlParamDecorator("param");
3566
+ var Body = createParamDecorator("body");
3567
+ var ReqLogger = createParamDecoratorWithoutParam("logger");
3568
+ var ReqId = createParamDecoratorWithoutParam("reqId");
3569
+ var ReqHeader = createParamDecorator("reqHeader");
3570
+ var ReqCookie = createParamDecorator("cookie");
3571
+ var Req = createParamDecoratorWithoutParam("req");
3572
+ var Res = createParamDecoratorWithoutParam("res");
3573
+ function HttpCode(status) {
3574
+ return (target, propertyKey, _descriptor) => {
3575
+ Reflect.defineMetadata(HTTP_CODE_KEY, status, target, propertyKey);
3576
+ };
3424
3577
  }
3425
- __name(getSubdirectories, "getSubdirectories");
3426
- async function ensureEmptyDir(dirPath) {
3427
- if (await isDirectory(dirPath)) {
3428
- await emptyDir(dirPath);
3429
- } else {
3430
- try {
3431
- await fsp__default.default.unlink(dirPath);
3432
- } catch (error) {
3433
- if (error.code !== "ENOENT") {
3434
- throw error;
3435
- }
3578
+ __name(HttpCode, "HttpCode");
3579
+ function Header(name, value) {
3580
+ return Headers(name, value);
3581
+ }
3582
+ __name(Header, "Header");
3583
+ function Headers(headers, value) {
3584
+ return (target, propertyKey) => {
3585
+ if (typeof propertyKey === "undefined") {
3586
+ const existing = Reflect.getMetadata(HEADER_KEY, target) || {};
3587
+ const newHeaders = typeof headers === "string" ? {
3588
+ [headers]: value
3589
+ } : headers;
3590
+ Reflect.defineMetadata(HEADER_KEY, {
3591
+ ...existing,
3592
+ ...newHeaders
3593
+ }, target);
3594
+ } else {
3595
+ const existing = Reflect.getMetadata(HEADER_KEY, target, propertyKey) || {};
3596
+ const newHeaders = typeof headers === "string" ? {
3597
+ [headers]: value
3598
+ } : headers;
3599
+ Reflect.defineMetadata(HEADER_KEY, {
3600
+ ...existing,
3601
+ ...newHeaders
3602
+ }, target, propertyKey);
3436
3603
  }
3437
- await ensureDir(dirPath);
3438
- }
3604
+ };
3439
3605
  }
3440
- __name(ensureEmptyDir, "ensureEmptyDir");
3441
- async function createTempDir(options = {}) {
3442
- const prefix = options.prefix || "tmp-";
3443
- const parentDir = options.parentDir || os__default.default.tmpdir();
3444
- const dirName = `${prefix}${crypto.randomBytes(6).toString("hex")}`;
3445
- const tempDirPath = path__default.default.join(parentDir, dirName);
3446
- await ensureDir(tempDirPath);
3447
- const cleanup = /* @__PURE__ */ __name(async () => {
3448
- try {
3449
- await deleteDirRecursive(tempDirPath);
3450
- } catch {
3606
+ __name(Headers, "Headers");
3607
+ function Before(fn) {
3608
+ return (target, propertyKey, _descriptor) => {
3609
+ if (typeof propertyKey === "undefined") {
3610
+ const hooks = Reflect.getMetadata(BEFORE_KEY, target) || [];
3611
+ hooks.push(fn);
3612
+ Reflect.defineMetadata(BEFORE_KEY, hooks, target);
3613
+ } else {
3614
+ const hooks = Reflect.getMetadata(BEFORE_KEY, target, propertyKey) || [];
3615
+ hooks.push(fn);
3616
+ Reflect.defineMetadata(BEFORE_KEY, hooks, target, propertyKey);
3451
3617
  }
3452
- }, "cleanup");
3453
- if (options.cleanup) {
3454
- process.once("exit", () => {
3455
- try {
3456
- fs__default.default.rmSync(tempDirPath, {
3457
- recursive: true,
3458
- force: true
3459
- });
3460
- } catch {
3461
- }
3462
- });
3463
- const signals = [
3464
- "SIGINT",
3465
- "SIGTERM",
3466
- "SIGUSR1",
3467
- "SIGUSR2"
3468
- ];
3469
- for (const signal of signals) {
3470
- process.once(signal, () => {
3471
- cleanup().then(() => process.exit());
3472
- });
3618
+ };
3619
+ }
3620
+ __name(Before, "Before");
3621
+ function After(fn) {
3622
+ return (target, propertyKey, _descriptor) => {
3623
+ if (typeof propertyKey === "undefined") {
3624
+ const hooks = Reflect.getMetadata(AFTER_KEY, target) || [];
3625
+ hooks.push(fn);
3626
+ Reflect.defineMetadata(AFTER_KEY, hooks, target);
3627
+ } else {
3628
+ const hooks = Reflect.getMetadata(AFTER_KEY, target, propertyKey) || [];
3629
+ hooks.push(fn);
3630
+ Reflect.defineMetadata(AFTER_KEY, hooks, target, propertyKey);
3473
3631
  }
3474
- }
3475
- return {
3476
- path: tempDirPath,
3477
- cleanup
3478
3632
  };
3479
3633
  }
3480
- __name(createTempDir, "createTempDir");
3481
- async function findNewestFile(dirPath, recursive = false) {
3482
- const files = await listFiles(dirPath, recursive);
3483
- if (files.length === 0) return null;
3484
- const stats = await Promise.all(files.map(async (file) => ({
3485
- path: file,
3486
- mtime: (await fsp__default.default.stat(file)).mtime
3487
- })));
3488
- return stats.sort((a, b) => b.mtime.getTime() - a.mtime.getTime())[0].path;
3634
+ __name(After, "After");
3635
+ function Roles(...roles) {
3636
+ return (target, propertyKey, _descriptor) => {
3637
+ if (typeof propertyKey === "undefined") {
3638
+ Reflect.defineMetadata(ROLES_KEY, roles, target);
3639
+ } else {
3640
+ Reflect.defineMetadata(ROLES_KEY, roles, target, propertyKey);
3641
+ }
3642
+ };
3489
3643
  }
3490
- __name(findNewestFile, "findNewestFile");
3491
- async function findOldestFile(dirPath, recursive = false) {
3492
- const files = await listFiles(dirPath, recursive);
3493
- if (files.length === 0) return null;
3494
- const stats = await Promise.all(files.map(async (file) => ({
3495
- path: file,
3496
- mtime: (await fsp__default.default.stat(file)).mtime
3497
- })));
3498
- return stats.sort((a, b) => a.mtime.getTime() - b.mtime.getTime())[0].path;
3644
+ __name(Roles, "Roles");
3645
+ function Redirect(url, statusCode = 302) {
3646
+ return (target, propertyKey, descriptor) => {
3647
+ Reflect.defineMetadata(REDIRECT_KEY, {
3648
+ url,
3649
+ statusCode
3650
+ }, target, propertyKey);
3651
+ return descriptor;
3652
+ };
3499
3653
  }
3500
- __name(findOldestFile, "findOldestFile");
3501
- async function findInDir(dirPath, predicate, recursive = false) {
3502
- const entries = await fsp__default.default.readdir(dirPath, {
3503
- withFileTypes: true
3504
- });
3505
- const results = [];
3506
- for (const entry of entries) {
3507
- const entryPath = path__default.default.join(dirPath, entry.name);
3508
- const stat = await fsp__default.default.stat(entryPath);
3509
- if (await predicate(entryPath, stat)) {
3510
- results.push(entryPath);
3654
+ __name(Redirect, "Redirect");
3655
+ function Cache(ttlSeconds) {
3656
+ return (target, propertyKey, _descriptor) => {
3657
+ if (typeof propertyKey === "undefined") {
3658
+ Reflect.defineMetadata(CACHE_KEY, {
3659
+ ttlSeconds
3660
+ }, target);
3661
+ } else {
3662
+ Reflect.defineMetadata(CACHE_KEY, {
3663
+ ttlSeconds
3664
+ }, target, propertyKey);
3511
3665
  }
3512
- if (recursive && entry.isDirectory()) {
3513
- const nestedResults = await findInDir(entryPath, predicate, true);
3514
- results.push(...nestedResults);
3666
+ };
3667
+ }
3668
+ __name(Cache, "Cache");
3669
+ function RateLimit(options) {
3670
+ const opts = {
3671
+ standardHeaders: true,
3672
+ legacyHeaders: false,
3673
+ ...options
3674
+ };
3675
+ return (target, propertyKey, _descriptor) => {
3676
+ if (typeof propertyKey === "undefined") {
3677
+ Reflect.defineMetadata(RATE_LIMIT_KEY, opts, target);
3678
+ } else {
3679
+ Reflect.defineMetadata(RATE_LIMIT_KEY, opts, target, propertyKey);
3515
3680
  }
3516
- }
3517
- return results;
3681
+ };
3518
3682
  }
3519
- __name(findInDir, "findInDir");
3520
- async function watchDirRecursive(dirPath, callback, includeSubdirs = true) {
3521
- const normalizedBasePath = path__default.default.normalize(dirPath);
3522
- const watchers = [];
3523
- const addWatcher = /* @__PURE__ */ __name((dir) => {
3524
- try {
3525
- const watcher = fs__default.default.watch(dir, (eventType, filename) => {
3526
- if (!filename) return;
3527
- const fullPath = path__default.default.join(dir, filename);
3528
- const relativePath = path__default.default.relative(normalizedBasePath, fullPath);
3529
- callback(eventType, relativePath);
3530
- if (eventType === "rename" && includeSubdirs) {
3531
- setTimeout(async () => {
3532
- try {
3533
- if (await isDirectory(fullPath)) {
3534
- addWatcher(fullPath);
3535
- }
3536
- } catch {
3537
- }
3538
- }, 100);
3539
- }
3540
- });
3541
- watchers.push(watcher);
3542
- } catch {
3683
+ __name(RateLimit, "RateLimit");
3684
+ function ContentType(type) {
3685
+ return (target, propertyKey, _descriptor) => {
3686
+ if (typeof propertyKey === "undefined") {
3687
+ Reflect.defineMetadata(CONTENT_TYPE_KEY, {
3688
+ type
3689
+ }, target);
3690
+ } else {
3691
+ Reflect.defineMetadata(CONTENT_TYPE_KEY, {
3692
+ type
3693
+ }, target, propertyKey);
3543
3694
  }
3544
- }, "addWatcher");
3545
- addWatcher(normalizedBasePath);
3546
- if (includeSubdirs) {
3547
- const subdirs = await getSubdirectories(normalizedBasePath, true);
3548
- for (const subdir of subdirs) {
3549
- addWatcher(subdir);
3695
+ };
3696
+ }
3697
+ __name(ContentType, "ContentType");
3698
+ function Version(version, options) {
3699
+ const opts = {
3700
+ addPrefix: true,
3701
+ addHeader: true,
3702
+ headerName: "X-API-Version",
3703
+ ...options
3704
+ };
3705
+ return (target, propertyKey, _descriptor) => {
3706
+ if (typeof propertyKey === "undefined") {
3707
+ Reflect.defineMetadata(VERSION_KEY, {
3708
+ version,
3709
+ options: opts
3710
+ }, target);
3711
+ } else {
3712
+ Reflect.defineMetadata(VERSION_KEY, {
3713
+ version,
3714
+ options: opts
3715
+ }, target, propertyKey);
3550
3716
  }
3551
- }
3552
- return () => {
3553
- for (const watcher of watchers) {
3554
- watcher.close();
3717
+ };
3718
+ }
3719
+ __name(Version, "Version");
3720
+ function Timeout(ms) {
3721
+ return (target, propertyKey, _descriptor) => {
3722
+ if (typeof propertyKey === "undefined") {
3723
+ Reflect.defineMetadata(TIMEOUT_KEY, {
3724
+ ms
3725
+ }, target);
3726
+ } else {
3727
+ Reflect.defineMetadata(TIMEOUT_KEY, {
3728
+ ms
3729
+ }, target, propertyKey);
3555
3730
  }
3556
3731
  };
3557
3732
  }
3558
- __name(watchDirRecursive, "watchDirRecursive");
3559
- async function getDirStats(dirPath) {
3560
- let fileCount = 0;
3561
- let dirCount = 0;
3562
- let totalSize = 0;
3563
- async function processDir(currentPath) {
3564
- const entries = await fsp__default.default.readdir(currentPath, {
3565
- withFileTypes: true
3566
- });
3567
- for (const entry of entries) {
3568
- const entryPath = path__default.default.join(currentPath, entry.name);
3569
- if (entry.isDirectory()) {
3570
- dirCount++;
3571
- await processDir(entryPath);
3572
- } else if (entry.isFile()) {
3573
- fileCount++;
3574
- const stat = await fsp__default.default.stat(entryPath);
3575
- totalSize += stat.size;
3576
- }
3733
+ __name(Timeout, "Timeout");
3734
+ function Log(options) {
3735
+ return (target, propertyKey, _descriptor) => {
3736
+ const config2 = {
3737
+ logEntry: true,
3738
+ logExit: true,
3739
+ logBody: false,
3740
+ logParams: false,
3741
+ logResponse: false,
3742
+ ...options
3743
+ };
3744
+ if (typeof propertyKey === "undefined") {
3745
+ Reflect.defineMetadata(LOG_KEY, config2, target);
3746
+ } else {
3747
+ Reflect.defineMetadata(LOG_KEY, config2, target, propertyKey);
3577
3748
  }
3578
- }
3579
- __name(processDir, "processDir");
3580
- await processDir(dirPath);
3581
- return {
3582
- fileCount,
3583
- dirCount,
3584
- totalSize
3585
3749
  };
3586
3750
  }
3587
- __name(getDirStats, "getDirStats");
3588
- async function walkDir(dirPath, options) {
3589
- const traversalOrder = options.traversalOrder || "pre";
3590
- const entries = await fsp__default.default.readdir(dirPath, {
3591
- withFileTypes: true
3751
+ __name(Log, "Log");
3752
+ function registerControllers(router, controllers) {
3753
+ controllers.forEach((ControllerClass) => {
3754
+ if (!Reflect.getMetadata("injectable", ControllerClass)) {
3755
+ Reflect.defineMetadata("injectable", true, ControllerClass);
3756
+ diContainer.register(ControllerClass);
3757
+ }
3758
+ const instance = diContainer.get(ControllerClass);
3759
+ let basePath = Reflect.getMetadata("basePath", ControllerClass) || "";
3760
+ const routes = Reflect.getMetadata(ROUTES_KEY, ControllerClass) || [];
3761
+ const controllerRateLimit = Reflect.getMetadata(RATE_LIMIT_KEY, ControllerClass);
3762
+ const controllerCache = Reflect.getMetadata(CACHE_KEY, ControllerClass);
3763
+ const controllerTimeout = Reflect.getMetadata(TIMEOUT_KEY, ControllerClass);
3764
+ const controllerVersion = Reflect.getMetadata(VERSION_KEY, ControllerClass);
3765
+ const controllerRoles = Reflect.getMetadata(ROLES_KEY, ControllerClass);
3766
+ const controllerLogConfig = Reflect.getMetadata(LOG_KEY, ControllerClass);
3767
+ const controllerHeaders = Reflect.getMetadata(HEADER_KEY, ControllerClass) || {};
3768
+ const controllerMiddlewares = Reflect.getMetadata(MIDDLEWARE_KEY, ControllerClass) || [];
3769
+ const controllerBeforeHooks = Reflect.getMetadata(BEFORE_KEY, ControllerClass) || [];
3770
+ const controllerAfterHooks = Reflect.getMetadata(AFTER_KEY, ControllerClass) || [];
3771
+ const controllerContentType = Reflect.getMetadata(CONTENT_TYPE_KEY, ControllerClass);
3772
+ if (controllerVersion?.options?.addPrefix) {
3773
+ basePath = `/${controllerVersion.version}${basePath || ""}`;
3774
+ }
3775
+ routes.forEach(({ path: path3, method, handlerName }) => {
3776
+ const methodMiddlewares = Reflect.getMetadata(MIDDLEWARE_KEY, instance, handlerName) || [];
3777
+ const params = Reflect.getMetadata(PARAMS_KEY, instance, handlerName) || [];
3778
+ const httpCode = Reflect.getMetadata(HTTP_CODE_KEY, instance, handlerName);
3779
+ const methodHeaders = Reflect.getMetadata(HEADER_KEY, instance, handlerName) || {};
3780
+ const headers = {
3781
+ ...controllerHeaders,
3782
+ ...methodHeaders
3783
+ };
3784
+ const middlewares = [
3785
+ ...controllerMiddlewares,
3786
+ ...methodMiddlewares
3787
+ ];
3788
+ const methodBeforeHooks = Reflect.getMetadata(BEFORE_KEY, instance, handlerName) || [];
3789
+ const methodAfterHooks = Reflect.getMetadata(AFTER_KEY, instance, handlerName) || [];
3790
+ const beforeHooks = [
3791
+ ...controllerBeforeHooks,
3792
+ ...methodBeforeHooks
3793
+ ];
3794
+ const afterHooks = [
3795
+ ...methodAfterHooks,
3796
+ ...controllerAfterHooks
3797
+ ];
3798
+ const redirect = Reflect.getMetadata(REDIRECT_KEY, instance, handlerName);
3799
+ const methodContentType = Reflect.getMetadata(CONTENT_TYPE_KEY, instance, handlerName);
3800
+ const contentType = methodContentType || controllerContentType;
3801
+ const roles = Reflect.getMetadata(ROLES_KEY, instance, handlerName) || controllerRoles || [];
3802
+ const cache = Reflect.getMetadata(CACHE_KEY, instance, handlerName) || controllerCache;
3803
+ const rateLimitOptions = Reflect.getMetadata(RATE_LIMIT_KEY, instance, handlerName) || controllerRateLimit;
3804
+ const methodVersion = Reflect.getMetadata(VERSION_KEY, instance, handlerName);
3805
+ const version = methodVersion || controllerVersion;
3806
+ const timeout2 = Reflect.getMetadata(TIMEOUT_KEY, instance, handlerName) || controllerTimeout;
3807
+ const logConfig = Reflect.getMetadata(LOG_KEY, instance, handlerName) || controllerLogConfig;
3808
+ let rateLimiter = null;
3809
+ if (rateLimitOptions) {
3810
+ try {
3811
+ rateLimiter = rateLimiterCache.get(rateLimitOptions);
3812
+ } catch (err) {
3813
+ getLogger().warn({
3814
+ err
3815
+ }, "express-rate-limit not available, skipping rate limiting for this route");
3816
+ }
3817
+ }
3818
+ let finalPath = path3;
3819
+ if (methodVersion?.options?.addPrefix && methodVersion.version !== controllerVersion?.version) {
3820
+ finalPath = `/${methodVersion.version}${path3}`;
3821
+ }
3822
+ const handler = /* @__PURE__ */ __name(async (req, res, next) => {
3823
+ req["startTime"] = Date.now();
3824
+ let timeoutId;
3825
+ let timedOut = false;
3826
+ try {
3827
+ if (timeout2) {
3828
+ timeoutId = setTimeout(() => {
3829
+ if (!res.headersSent && !timedOut) {
3830
+ timedOut = true;
3831
+ const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.REQUEST_TIMEOUT, "Request timed out");
3832
+ res.status(HttpStatusCodes.REQUEST_TIMEOUT).json(errorResponse);
3833
+ }
3834
+ }, timeout2.ms);
3835
+ }
3836
+ if (timedOut) return;
3837
+ if (rateLimiter) {
3838
+ await new Promise((resolve2, reject) => {
3839
+ rateLimiter(req, res, (err) => {
3840
+ if (err) reject(err);
3841
+ else resolve2();
3842
+ });
3843
+ });
3844
+ }
3845
+ if (!res.headersSent && contentType) {
3846
+ res.setHeader("Content-Type", contentType.type);
3847
+ }
3848
+ if (version?.options?.addHeader && version?.options?.headerName && version?.version) {
3849
+ if (!res.headersSent) {
3850
+ res.setHeader(version.options.headerName, version.version);
3851
+ }
3852
+ }
3853
+ if (cache && !res.headersSent) {
3854
+ res.setHeader("Cache-Control", `public, max-age=${cache.ttlSeconds}`);
3855
+ }
3856
+ if (logConfig?.logEntry) {
3857
+ const logger2 = getLogger();
3858
+ const logData = {
3859
+ method: req.method,
3860
+ url: req.originalUrl || req.url,
3861
+ userAgent: req.get("User-Agent")
3862
+ };
3863
+ if (logConfig.logParams) {
3864
+ logData.params = req.params;
3865
+ logData.query = req.query;
3866
+ }
3867
+ if (logConfig.logBody) logData.body = req.body;
3868
+ logger2.info({
3869
+ entry: logData
3870
+ }, "Route Entry:");
3871
+ }
3872
+ if (roles.length && !req?.user?.roles?.some((role) => roles.includes(role))) {
3873
+ const errorResponse = createFinalErrorResponse(req, HttpStatusCodes.FORBIDDEN, "Forbidden Insufficient Roles");
3874
+ res.status(HttpStatusCodes.FORBIDDEN).json(errorResponse);
3875
+ if (timeoutId) {
3876
+ clearTimeout(timeoutId);
3877
+ }
3878
+ return;
3879
+ }
3880
+ if (redirect && redirect.url) {
3881
+ if (timeoutId) {
3882
+ clearTimeout(timeoutId);
3883
+ }
3884
+ return res.redirect(redirect.statusCode, redirect.url);
3885
+ }
3886
+ for (const fn of beforeHooks) await fn(req, res);
3887
+ const args = [];
3888
+ if (params.length) {
3889
+ params.forEach(({ index, type, key, options }) => {
3890
+ let rawValue;
3891
+ switch (type) {
3892
+ case "query":
3893
+ rawValue = key ? req.query[key] : req.query;
3894
+ args[index] = options ? applyParamOptions(rawValue, options, key) : rawValue;
3895
+ break;
3896
+ case "param":
3897
+ rawValue = key ? req.params[key] : req.params;
3898
+ args[index] = options ? applyParamOptions(rawValue, options, key) : rawValue;
3899
+ break;
3900
+ case "body":
3901
+ args[index] = key ? req.body?.[key] : req.body;
3902
+ break;
3903
+ case "req":
3904
+ args[index] = req;
3905
+ break;
3906
+ case "res":
3907
+ args[index] = res;
3908
+ break;
3909
+ case "logger":
3910
+ args[index] = getLogger();
3911
+ break;
3912
+ case "reqHeader":
3913
+ args[index] = key ? req.headers[key.toLowerCase()] : req.headers;
3914
+ break;
3915
+ case "reqId":
3916
+ args[index] = req.headers["x-request-id"] || req?.id || void 0;
3917
+ break;
3918
+ case "cookie":
3919
+ args[index] = key ? req.cookies?.[key] : req.cookies;
3920
+ break;
3921
+ }
3922
+ });
3923
+ }
3924
+ const result = instance[handlerName](...args);
3925
+ const awaited = result instanceof Promise ? await result : result;
3926
+ if (timeoutId) {
3927
+ clearTimeout(timeoutId);
3928
+ }
3929
+ if (timedOut) return;
3930
+ if (redirect && awaited && typeof awaited === "object" && "url" in awaited) {
3931
+ const redirectUrl = awaited.url;
3932
+ const redirectStatus = awaited.statusCode || redirect.statusCode;
3933
+ return res.redirect(redirectStatus, redirectUrl);
3934
+ }
3935
+ if (!res.headersSent && typeof awaited !== "undefined") {
3936
+ if (httpCode) res.status(httpCode);
3937
+ for (const [k, v] of Object.entries(headers)) {
3938
+ const normalized = normalizeHeaderValue(v);
3939
+ if (typeof normalized !== "undefined") {
3940
+ res.set(k, normalized);
3941
+ }
3942
+ }
3943
+ res.json(awaited);
3944
+ }
3945
+ if (logConfig?.logExit) {
3946
+ const logger2 = getLogger();
3947
+ const logData = {
3948
+ method: req.method,
3949
+ url: req.originalUrl || req.url,
3950
+ statusCode: res.statusCode,
3951
+ duration: `${Date.now() - req.startTime}ms`
3952
+ };
3953
+ if (logConfig.logResponse) logData.response = awaited;
3954
+ logger2.info({
3955
+ exit: logData
3956
+ }, "Route Exit:");
3957
+ }
3958
+ for (const fn of afterHooks) await fn(req, res, awaited);
3959
+ } catch (err) {
3960
+ if (timeoutId) {
3961
+ clearTimeout(timeoutId);
3962
+ }
3963
+ next(err);
3964
+ }
3965
+ }, "handler");
3966
+ router[method](basePath + finalPath, ...middlewares, handler);
3967
+ });
3592
3968
  });
3593
- for (const entry of entries) {
3594
- const entryPath = path__default.default.join(dirPath, entry.name);
3595
- const stats = await fsp__default.default.stat(entryPath);
3596
- const entryInfo = {
3597
- path: entryPath,
3598
- name: entry.name,
3599
- isDirectory: entry.isDirectory(),
3600
- stats
3601
- };
3602
- if (entry.isDirectory()) {
3603
- if (traversalOrder === "pre") {
3604
- const shouldContinue = await options.visitorFn(entryInfo);
3605
- if (shouldContinue !== false) {
3606
- await walkDir(entryPath, options);
3969
+ }
3970
+ __name(registerControllers, "registerControllers");
3971
+ function applyParamOptions(rawValue, options, key) {
3972
+ if (!options) return rawValue;
3973
+ let value = rawValue;
3974
+ const paramName = key ? `: ${key}` : "";
3975
+ if (value === void 0 || value === null || value === "") {
3976
+ if ("default" in options) {
3977
+ value = options.default;
3978
+ }
3979
+ }
3980
+ if (options.required && (value === void 0 || value === null || value === "")) {
3981
+ throw new BadRequestException(`Required parameter missing${paramName}`);
3982
+ }
3983
+ if (value !== void 0 && value !== null) {
3984
+ if (options.dataType === "array") {
3985
+ const delimiter = options.delimiter || ",";
3986
+ if (typeof value === "string") {
3987
+ value = value.split(delimiter).map((v) => v.trim());
3988
+ } else if (!Array.isArray(value)) {
3989
+ value = [
3990
+ value
3991
+ ];
3992
+ }
3993
+ if (options.type === "string" && options.pattern) {
3994
+ const hasInvalidPattern = value.some((v) => !options.pattern.test(v));
3995
+ if (hasInvalidPattern) {
3996
+ throw new BadRequestException(`Parameter '${key}' array contains values that do not match pattern: ${options.patternName || options.pattern}`);
3997
+ }
3998
+ }
3999
+ if (options.type === "number" && options.pattern) {
4000
+ const hasInvalidPattern = value.some((v) => !options.pattern.test(String(v)));
4001
+ if (hasInvalidPattern) {
4002
+ throw new BadRequestException(`Parameter '${key}' array contains values that do not match pattern: ${options.patternName || options.pattern}`);
4003
+ }
4004
+ }
4005
+ if (options.type === "number" && options.throwError !== false) {
4006
+ const hasInvalidNumber = value.some((v) => isNaN(Number(v)));
4007
+ if (hasInvalidNumber) {
4008
+ throw new BadRequestException(`Type error: expected number array${paramName}`);
4009
+ }
4010
+ if (options.min !== void 0) {
4011
+ const hasBelowMin = value.some((v) => Number(v) < options.min);
4012
+ if (hasBelowMin) {
4013
+ throw new BadRequestException(`Validation error: number array values must be >= ${options.min}${paramName}`);
4014
+ }
4015
+ }
4016
+ if (options.max !== void 0) {
4017
+ const hasAboveMax = value.some((v) => Number(v) > options.max);
4018
+ if (hasAboveMax) {
4019
+ throw new BadRequestException(`Validation error: number array values must be <= ${options.max}${paramName}`);
4020
+ }
4021
+ }
4022
+ }
4023
+ if (options.type === "boolean" && options.throwError !== false) {
4024
+ const hasInvalidBoolean = value.some((v) => !isValidBooleanInput(v));
4025
+ if (hasInvalidBoolean) {
4026
+ throw new BadRequestException(`Type error: expected boolean array${paramName}`);
4027
+ }
4028
+ }
4029
+ if (options.type) {
4030
+ value = value.map((v) => convertType(v, options.type || "string"));
4031
+ }
4032
+ } else if (options.dataType === "object") {
4033
+ if (typeof value === "string") {
4034
+ try {
4035
+ value = JSON.parse(value);
4036
+ } catch (_e) {
4037
+ if (options.throwError !== false) {
4038
+ throw new BadRequestException(`Invalid JSON object${paramName}`);
4039
+ }
4040
+ }
4041
+ }
4042
+ } else if (options.type) {
4043
+ const originalValue = value;
4044
+ value = convertType(value, options.type);
4045
+ if (options.throwError === false) {
4046
+ if (options.type === "number" && typeof value === "number") {
4047
+ if (options.min !== void 0 && value < options.min) {
4048
+ value = void 0;
4049
+ }
4050
+ if (options.max !== void 0 && value > options.max) {
4051
+ value = void 0;
4052
+ }
4053
+ }
4054
+ }
4055
+ if (options.type === "string" && options.pattern && typeof value === "string" && !options.pattern.test(value)) {
4056
+ throw new BadRequestException(`Parameter '${key}' does not match pattern: ${options.patternName || options.pattern}`);
4057
+ } else if (options.type === "number" && options.pattern && typeof value === "number" && !options.pattern.test(String(value))) {
4058
+ throw new BadRequestException(`Parameter '${key}' does not match pattern: ${options.patternName || options.pattern}`);
4059
+ }
4060
+ if (options.throwError !== false) {
4061
+ if (options.type === "number" && typeof value === "number" && isNaN(value)) {
4062
+ throw new BadRequestException(`Type error: expected number${paramName}`);
4063
+ }
4064
+ if (options.type === "number" && typeof value === "number") {
4065
+ if (options.min !== void 0 && value < options.min) {
4066
+ throw new BadRequestException(`Validation error: number must be >= ${options.min}${paramName}`);
4067
+ }
4068
+ if (options.max !== void 0 && value > options.max) {
4069
+ throw new BadRequestException(`Validation error: number must be <= ${options.max}${paramName}`);
4070
+ }
4071
+ }
4072
+ if (options.type === "boolean" && !isValidBooleanInput(originalValue)) {
4073
+ throw new BadRequestException(`Type error: expected boolean${paramName}`);
3607
4074
  }
3608
- } else {
3609
- await walkDir(entryPath, options);
3610
- await options.visitorFn(entryInfo);
3611
4075
  }
3612
- } else {
3613
- await options.visitorFn(entryInfo);
3614
4076
  }
3615
4077
  }
3616
- if (traversalOrder === "post") {
3617
- const stats = await fsp__default.default.stat(dirPath);
3618
- const entryInfo = {
3619
- path: dirPath,
3620
- name: path__default.default.basename(dirPath),
3621
- isDirectory: true,
3622
- stats
3623
- };
3624
- await options.visitorFn(entryInfo);
3625
- }
3626
- }
3627
- __name(walkDir, "walkDir");
3628
-
3629
- // src/utils/exception.utils.ts
3630
- var HttpError = class extends ErrorResponse {
3631
- static {
3632
- __name(this, "HttpError");
3633
- }
3634
- /**
3635
- * Creates a new HTTP error instance.
3636
- * @param status - A valid HTTP status code (e.g., 400, 500).
3637
- * @param message - The error message to return to the client.
3638
- */
3639
- constructor(status, message) {
3640
- super(message);
3641
- this.status = status;
3642
- }
3643
- };
3644
- var InternalServerErrorException = class extends ErrorResponse {
3645
- static {
3646
- __name(this, "InternalServerErrorException");
3647
- }
3648
- /**
3649
- * @param message - Optional custom message. Defaults to "Internal server error".
3650
- */
3651
- constructor(message = "Internal server error") {
3652
- super(message);
3653
- this.status = HttpStatusCodes.INTERNAL_SERVER_ERROR;
3654
- }
3655
- };
3656
- var UnauthorizedException = class extends ErrorResponse {
3657
- static {
3658
- __name(this, "UnauthorizedException");
3659
- }
3660
- /**
3661
- * @param message - Optional custom message. Defaults to "Unauthorized".
3662
- */
3663
- constructor(message = "Unauthorized") {
3664
- super(message);
3665
- this.status = HttpStatusCodes.UNAUTHORIZED;
3666
- }
3667
- };
3668
- var BadRequestException = class extends ErrorResponse {
3669
- static {
3670
- __name(this, "BadRequestException");
3671
- }
3672
- /**
3673
- * @param message - Optional custom message. Defaults to "Bad request".
3674
- */
3675
- constructor(message = "Bad request") {
3676
- super(message);
3677
- this.status = HttpStatusCodes.BAD_REQUEST;
3678
- }
3679
- };
3680
- var NotFoundException = class extends ErrorResponse {
3681
- static {
3682
- __name(this, "NotFoundException");
3683
- }
3684
- /**
3685
- * @param message - Optional custom message. Defaults to "Resource not found".
3686
- */
3687
- constructor(message = "Resource not found") {
3688
- super(message);
3689
- this.status = HttpStatusCodes.NOT_FOUND;
3690
- }
3691
- };
3692
- var ForbiddenException = class extends ErrorResponse {
3693
- static {
3694
- __name(this, "ForbiddenException");
3695
- }
3696
- /**
3697
- * @param message - Optional custom message. Defaults to "Forbidden".
3698
- */
3699
- constructor(message = "Forbidden") {
3700
- super(message);
3701
- this.status = HttpStatusCodes.FORBIDDEN;
3702
- }
3703
- };
3704
- var ConflictException = class extends ErrorResponse {
3705
- static {
3706
- __name(this, "ConflictException");
3707
- }
3708
- /**
3709
- * @param message - Optional custom message. Defaults to "Conflict".
3710
- */
3711
- constructor(message = "Conflict") {
3712
- super(message);
3713
- this.status = HttpStatusCodes.CONFLICT;
3714
- }
3715
- };
3716
- var BadGatewayException = class extends ErrorResponse {
3717
- static {
3718
- __name(this, "BadGatewayException");
3719
- }
3720
- /**
3721
- * @param message - Optional custom message. Defaults to "Bad Gateway".
3722
- */
3723
- constructor(message = "Bad Gateway") {
3724
- super(message);
3725
- this.status = HttpStatusCodes.BAD_GATEWAY;
3726
- }
3727
- };
3728
- var TooManyRequestsException = class extends ErrorResponse {
3729
- static {
3730
- __name(this, "TooManyRequestsException");
3731
- }
3732
- /**
3733
- * @param message - Optional custom message. Defaults to "Too many requests".
3734
- */
3735
- constructor(message = "Too many requests") {
3736
- super(message);
3737
- this.status = HttpStatusCodes.TOO_MANY_REQUESTS;
3738
- }
3739
- };
3740
- var ServiceUnavailableException = class extends ErrorResponse {
3741
- static {
3742
- __name(this, "ServiceUnavailableException");
3743
- }
3744
- /**
3745
- * @param message - Optional custom message. Defaults to "Service Unavailable".
3746
- */
3747
- constructor(message = "Service Unavailable") {
3748
- super(message);
3749
- this.status = HttpStatusCodes.SERVICE_UNAVAILABLE;
3750
- }
3751
- };
3752
- var GatewayTimeoutException = class extends ErrorResponse {
3753
- static {
3754
- __name(this, "GatewayTimeoutException");
3755
- }
3756
- /**
3757
- * @param message - Optional custom message. Defaults to "Gateway Timeout".
3758
- */
3759
- constructor(message = "Gateway Timeout") {
3760
- super(message);
3761
- this.status = HttpStatusCodes.GATEWAY_TIMEOUT;
3762
- }
3763
- };
3764
- var UnprocessableEntityException = class extends ErrorResponse {
3765
- static {
3766
- __name(this, "UnprocessableEntityException");
3767
- }
3768
- details;
3769
- /**
3770
- * @param message - Optional custom message. Defaults to "Unprocessable Entity".
3771
- * @param details - Optional validation details or additional error context.
3772
- */
3773
- constructor(message = "Unprocessable Entity", details) {
3774
- super(message), this.details = details;
3775
- this.status = HttpStatusCodes.UNPROCESSABLE_ENTITY;
3776
- }
3777
- };
3778
- var MethodNotAllowedException = class extends ErrorResponse {
3779
- static {
3780
- __name(this, "MethodNotAllowedException");
4078
+ if (options.transform && typeof options.transform === "function") {
4079
+ value = options.transform(value);
3781
4080
  }
3782
- allowedMethods;
3783
- /**
3784
- * @param message - Optional custom message. Defaults to "Method Not Allowed".
3785
- * @param allowedMethods - Optional array of allowed HTTP methods.
3786
- */
3787
- constructor(message = "Method Not Allowed", allowedMethods) {
3788
- super(message), this.allowedMethods = allowedMethods;
3789
- this.status = HttpStatusCodes.METHOD_NOT_ALLOWED;
4081
+ if (options.validate && typeof options.validate === "function") {
4082
+ if (!options.validate(value)) {
4083
+ if (options.throwError !== false) {
4084
+ throw new BadRequestException(`Parameter validation failed${paramName}`);
4085
+ }
4086
+ return void 0;
4087
+ }
3790
4088
  }
3791
- };
3792
- var NotAcceptableException = class extends ErrorResponse {
3793
- static {
3794
- __name(this, "NotAcceptableException");
4089
+ return value;
4090
+ }
4091
+ __name(applyParamOptions, "applyParamOptions");
4092
+ function isValidBooleanInput(value) {
4093
+ if (typeof value === "boolean") return true;
4094
+ if (typeof value === "number") return value === 0 || value === 1;
4095
+ if (typeof value === "string") {
4096
+ const normalizedValue = value.toLowerCase().trim();
4097
+ return [
4098
+ "true",
4099
+ "false",
4100
+ "0",
4101
+ "1",
4102
+ "yes",
4103
+ "no"
4104
+ ].includes(normalizedValue);
3795
4105
  }
3796
- /**
3797
- * @param message - Optional custom message. Defaults to "Not Acceptable".
3798
- */
3799
- constructor(message = "Not Acceptable") {
3800
- super(message);
3801
- this.status = HttpStatusCodes.NOT_ACCEPTABLE;
4106
+ return false;
4107
+ }
4108
+ __name(isValidBooleanInput, "isValidBooleanInput");
4109
+ function convertType(value, type) {
4110
+ if (value === void 0 || value === null) {
4111
+ return value;
3802
4112
  }
3803
- };
3804
- var RequestTimeoutException = class extends ErrorResponse {
3805
- static {
3806
- __name(this, "RequestTimeoutException");
4113
+ switch (type) {
4114
+ case "number":
4115
+ return Number(value);
4116
+ case "boolean":
4117
+ if (typeof value === "string") {
4118
+ const normalizedValue = value.toLowerCase().trim();
4119
+ return normalizedValue === "true" || normalizedValue === "1" || normalizedValue === "yes";
4120
+ }
4121
+ return value === true || value === 1;
4122
+ case "string":
4123
+ default:
4124
+ return String(value);
3807
4125
  }
3808
- /**
3809
- * @param message - Optional custom message. Defaults to "Request Timeout".
3810
- */
3811
- constructor(message = "Request Timeout") {
3812
- super(message);
3813
- this.status = HttpStatusCodes.REQUEST_TIMEOUT;
4126
+ }
4127
+ __name(convertType, "convertType");
4128
+ async function ensureDir(dirPath) {
4129
+ await fsp__default.default.mkdir(dirPath, {
4130
+ recursive: true
4131
+ });
4132
+ }
4133
+ __name(ensureDir, "ensureDir");
4134
+ async function listFiles(dirPath, recursive = false) {
4135
+ const entries = await fsp__default.default.readdir(dirPath, {
4136
+ withFileTypes: true
4137
+ });
4138
+ const files = [];
4139
+ for (const entry of entries) {
4140
+ const fullPath = path__default.default.join(dirPath, entry.name);
4141
+ if (entry.isFile()) {
4142
+ files.push(fullPath);
4143
+ } else if (recursive && entry.isDirectory()) {
4144
+ const nestedFiles = await listFiles(fullPath, true);
4145
+ files.push(...nestedFiles);
4146
+ }
3814
4147
  }
3815
- };
3816
- var UnsupportedMediaTypeException = class extends ErrorResponse {
3817
- static {
3818
- __name(this, "UnsupportedMediaTypeException");
4148
+ return files;
4149
+ }
4150
+ __name(listFiles, "listFiles");
4151
+ async function deleteDirRecursive(dirPath) {
4152
+ await fsp__default.default.rm(dirPath, {
4153
+ recursive: true,
4154
+ force: true
4155
+ });
4156
+ }
4157
+ __name(deleteDirRecursive, "deleteDirRecursive");
4158
+ async function isDirectory(pathStr) {
4159
+ try {
4160
+ const stat = await fsp__default.default.stat(pathStr);
4161
+ return stat.isDirectory();
4162
+ } catch {
4163
+ return false;
3819
4164
  }
3820
- /**
3821
- * @param message - Optional custom message. Defaults to "Unsupported Media Type".
3822
- */
3823
- constructor(message = "Unsupported Media Type") {
3824
- super(message);
3825
- this.status = HttpStatusCodes.UNSUPPORTED_MEDIA_TYPE;
4165
+ }
4166
+ __name(isDirectory, "isDirectory");
4167
+ async function copyDir(src, dest) {
4168
+ await ensureDir(dest);
4169
+ const entries = await fsp__default.default.readdir(src, {
4170
+ withFileTypes: true
4171
+ });
4172
+ for (const entry of entries) {
4173
+ const srcPath = path__default.default.join(src, entry.name);
4174
+ const destPath = path__default.default.join(dest, entry.name);
4175
+ if (entry.isDirectory()) {
4176
+ await copyDir(srcPath, destPath);
4177
+ } else {
4178
+ await fsp__default.default.copyFile(srcPath, destPath);
4179
+ }
3826
4180
  }
3827
- };
3828
- var PayloadTooLargeException = class extends ErrorResponse {
3829
- static {
3830
- __name(this, "PayloadTooLargeException");
4181
+ }
4182
+ __name(copyDir, "copyDir");
4183
+ async function moveDir(src, dest) {
4184
+ await copyDir(src, dest);
4185
+ await deleteDirRecursive(src);
4186
+ }
4187
+ __name(moveDir, "moveDir");
4188
+ async function emptyDir(dirPath) {
4189
+ const entries = await fsp__default.default.readdir(dirPath, {
4190
+ withFileTypes: true
4191
+ });
4192
+ for (const entry of entries) {
4193
+ const entryPath = path__default.default.join(dirPath, entry.name);
4194
+ if (entry.isDirectory()) {
4195
+ await fsp__default.default.rm(entryPath, {
4196
+ recursive: true,
4197
+ force: true
4198
+ });
4199
+ } else {
4200
+ await fsp__default.default.unlink(entryPath);
4201
+ }
3831
4202
  }
3832
- /**
3833
- * @param message - Optional custom message. Defaults to "Payload Too Large".
3834
- */
3835
- constructor(message = "Payload Too Large") {
3836
- super(message);
3837
- this.status = HttpStatusCodes.PAYLOAD_TOO_LARGE;
4203
+ }
4204
+ __name(emptyDir, "emptyDir");
4205
+ async function getDirSize(dirPath) {
4206
+ let total = 0;
4207
+ const entries = await fsp__default.default.readdir(dirPath, {
4208
+ withFileTypes: true
4209
+ });
4210
+ for (const entry of entries) {
4211
+ const entryPath = path__default.default.join(dirPath, entry.name);
4212
+ if (entry.isDirectory()) {
4213
+ total += await getDirSize(entryPath);
4214
+ } else {
4215
+ const stat = await fsp__default.default.stat(entryPath);
4216
+ total += stat.size;
4217
+ }
3838
4218
  }
3839
- };
3840
- var InsufficientStorageException = class extends ErrorResponse {
3841
- static {
3842
- __name(this, "InsufficientStorageException");
4219
+ return total;
4220
+ }
4221
+ __name(getDirSize, "getDirSize");
4222
+ function watchDir(dirPath, callback) {
4223
+ const watcher = fs__default.default.watch(dirPath, (eventType, filename) => {
4224
+ callback(eventType, filename);
4225
+ });
4226
+ return () => watcher.close();
4227
+ }
4228
+ __name(watchDir, "watchDir");
4229
+ async function findFilesByPattern(pattern, options = {}) {
4230
+ const matchPattern = /* @__PURE__ */ __name((name, pattern2) => {
4231
+ let escaped = pattern2.replaceAll(/[.+^${}()|[\]\\]/g, "\\$&");
4232
+ escaped = escaped.replaceAll("*", ".*").replaceAll("?", ".");
4233
+ const regex = new RegExp(`^${escaped}$`);
4234
+ return regex.test(name);
4235
+ }, "matchPattern");
4236
+ const { cwd = process.cwd(), dot = false } = options;
4237
+ const segments = pattern.split("/");
4238
+ async function walk(dir, segIndex) {
4239
+ if (segIndex >= segments.length) return [];
4240
+ const segment = segments[segIndex];
4241
+ const entries = await fs__default.default.promises.readdir(dir, {
4242
+ withFileTypes: true
4243
+ });
4244
+ let matchedFiles = [];
4245
+ for (const entry of entries) {
4246
+ const entryName = entry.name;
4247
+ if (!dot && entryName.startsWith(".")) continue;
4248
+ const fullPath = path__default.default.join(dir, entryName);
4249
+ const isLastSegment = segIndex === segments.length - 1;
4250
+ if (isLastSegment) {
4251
+ if (matchPattern(entryName, segment) && entry.isFile()) {
4252
+ matchedFiles.push(fullPath);
4253
+ }
4254
+ } else if (entry.isDirectory()) {
4255
+ if (matchPattern(entryName, segment)) {
4256
+ matchedFiles.push(...await walk(fullPath, segIndex + 1));
4257
+ }
4258
+ }
4259
+ }
4260
+ return matchedFiles;
3843
4261
  }
3844
- /**
3845
- * @param message - Optional custom message. Defaults to "Insufficient Storage".
3846
- */
3847
- constructor(message = "Insufficient Storage") {
3848
- super(message);
3849
- this.status = HttpStatusCodes.INSUFFICIENT_STORAGE;
4262
+ __name(walk, "walk");
4263
+ return walk(cwd, 0);
4264
+ }
4265
+ __name(findFilesByPattern, "findFilesByPattern");
4266
+ async function getSubdirectories(dirPath, recursive = false) {
4267
+ const entries = await fsp__default.default.readdir(dirPath, {
4268
+ withFileTypes: true
4269
+ });
4270
+ const dirs = entries.filter((entry) => entry.isDirectory()).map((entry) => path__default.default.join(dirPath, entry.name));
4271
+ if (recursive && dirs.length > 0) {
4272
+ const nestedDirs = await Promise.all(dirs.map((dir) => getSubdirectories(dir, true)));
4273
+ return [
4274
+ ...dirs,
4275
+ ...nestedDirs.flat()
4276
+ ];
3850
4277
  }
3851
- };
3852
- function isHttpError(error) {
3853
- return error instanceof ErrorResponse;
4278
+ return dirs;
3854
4279
  }
3855
- __name(isHttpError, "isHttpError");
3856
- function createHttpError(status, message) {
3857
- switch (status) {
3858
- case HttpStatusCodes.BAD_REQUEST:
3859
- return new BadRequestException(message);
3860
- case HttpStatusCodes.UNAUTHORIZED:
3861
- return new UnauthorizedException(message);
3862
- case HttpStatusCodes.FORBIDDEN:
3863
- return new ForbiddenException(message);
3864
- case HttpStatusCodes.NOT_FOUND:
3865
- return new NotFoundException(message);
3866
- case HttpStatusCodes.METHOD_NOT_ALLOWED:
3867
- return new MethodNotAllowedException(message);
3868
- case HttpStatusCodes.NOT_ACCEPTABLE:
3869
- return new NotAcceptableException(message);
3870
- case HttpStatusCodes.REQUEST_TIMEOUT:
3871
- return new RequestTimeoutException(message);
3872
- case HttpStatusCodes.CONFLICT:
3873
- return new ConflictException(message);
3874
- case HttpStatusCodes.GONE:
3875
- return new HttpError(HttpStatusCodes.GONE, message || "Gone");
3876
- case HttpStatusCodes.PAYLOAD_TOO_LARGE:
3877
- return new PayloadTooLargeException(message);
3878
- case HttpStatusCodes.UNSUPPORTED_MEDIA_TYPE:
3879
- return new UnsupportedMediaTypeException(message);
3880
- case HttpStatusCodes.UNPROCESSABLE_ENTITY:
3881
- return new UnprocessableEntityException(message);
3882
- case HttpStatusCodes.TOO_MANY_REQUESTS:
3883
- return new TooManyRequestsException(message);
3884
- case HttpStatusCodes.INTERNAL_SERVER_ERROR:
3885
- return new InternalServerErrorException(message);
3886
- case HttpStatusCodes.BAD_GATEWAY:
3887
- return new BadGatewayException(message);
3888
- case HttpStatusCodes.SERVICE_UNAVAILABLE:
3889
- return new ServiceUnavailableException(message);
3890
- case HttpStatusCodes.GATEWAY_TIMEOUT:
3891
- return new GatewayTimeoutException(message);
3892
- case HttpStatusCodes.INSUFFICIENT_STORAGE:
3893
- return new InsufficientStorageException(message);
3894
- default:
3895
- return new HttpError(status, message || `HTTP Error ${status}`);
4280
+ __name(getSubdirectories, "getSubdirectories");
4281
+ async function ensureEmptyDir(dirPath) {
4282
+ if (await isDirectory(dirPath)) {
4283
+ await emptyDir(dirPath);
4284
+ } else {
4285
+ try {
4286
+ await fsp__default.default.unlink(dirPath);
4287
+ } catch (error) {
4288
+ if (error.code !== "ENOENT") {
4289
+ throw error;
4290
+ }
4291
+ }
4292
+ await ensureDir(dirPath);
4293
+ }
4294
+ }
4295
+ __name(ensureEmptyDir, "ensureEmptyDir");
4296
+ async function createTempDir(options = {}) {
4297
+ const prefix = options.prefix || "tmp-";
4298
+ const parentDir = options.parentDir || os__default.default.tmpdir();
4299
+ const dirName = `${prefix}${crypto.randomBytes(6).toString("hex")}`;
4300
+ const tempDirPath = path__default.default.join(parentDir, dirName);
4301
+ await ensureDir(tempDirPath);
4302
+ const cleanup = /* @__PURE__ */ __name(async () => {
4303
+ try {
4304
+ await deleteDirRecursive(tempDirPath);
4305
+ } catch {
4306
+ }
4307
+ }, "cleanup");
4308
+ if (options.cleanup) {
4309
+ process.once("exit", () => {
4310
+ try {
4311
+ fs__default.default.rmSync(tempDirPath, {
4312
+ recursive: true,
4313
+ force: true
4314
+ });
4315
+ } catch {
4316
+ }
4317
+ });
4318
+ const signals = [
4319
+ "SIGINT",
4320
+ "SIGTERM",
4321
+ "SIGUSR1",
4322
+ "SIGUSR2"
4323
+ ];
4324
+ for (const signal of signals) {
4325
+ process.once(signal, () => {
4326
+ cleanup().then(() => process.exit());
4327
+ });
4328
+ }
3896
4329
  }
4330
+ return {
4331
+ path: tempDirPath,
4332
+ cleanup
4333
+ };
3897
4334
  }
3898
- __name(createHttpError, "createHttpError");
3899
- function hasErrorShape(error) {
3900
- return typeof error === "object" && error !== null && "message" in error && typeof error.message === "string";
4335
+ __name(createTempDir, "createTempDir");
4336
+ async function findNewestFile(dirPath, recursive = false) {
4337
+ const files = await listFiles(dirPath, recursive);
4338
+ if (files.length === 0) return null;
4339
+ const stats = await Promise.all(files.map(async (file) => ({
4340
+ path: file,
4341
+ mtime: (await fsp__default.default.stat(file)).mtime
4342
+ })));
4343
+ return stats.sort((a, b) => b.mtime.getTime() - a.mtime.getTime())[0].path;
3901
4344
  }
3902
- __name(hasErrorShape, "hasErrorShape");
3903
- function getErrorMessage(error) {
3904
- if (typeof error === "string") {
3905
- return error;
3906
- }
3907
- if (error instanceof Error) {
3908
- return error.message;
3909
- }
3910
- if (hasErrorShape(error)) {
3911
- return error.message;
4345
+ __name(findNewestFile, "findNewestFile");
4346
+ async function findOldestFile(dirPath, recursive = false) {
4347
+ const files = await listFiles(dirPath, recursive);
4348
+ if (files.length === 0) return null;
4349
+ const stats = await Promise.all(files.map(async (file) => ({
4350
+ path: file,
4351
+ mtime: (await fsp__default.default.stat(file)).mtime
4352
+ })));
4353
+ return stats.sort((a, b) => a.mtime.getTime() - b.mtime.getTime())[0].path;
4354
+ }
4355
+ __name(findOldestFile, "findOldestFile");
4356
+ async function findInDir(dirPath, predicate, recursive = false) {
4357
+ const entries = await fsp__default.default.readdir(dirPath, {
4358
+ withFileTypes: true
4359
+ });
4360
+ const results = [];
4361
+ for (const entry of entries) {
4362
+ const entryPath = path__default.default.join(dirPath, entry.name);
4363
+ const stat = await fsp__default.default.stat(entryPath);
4364
+ if (await predicate(entryPath, stat)) {
4365
+ results.push(entryPath);
4366
+ }
4367
+ if (recursive && entry.isDirectory()) {
4368
+ const nestedResults = await findInDir(entryPath, predicate, true);
4369
+ results.push(...nestedResults);
4370
+ }
3912
4371
  }
3913
- return "Unknown error occurred";
4372
+ return results;
3914
4373
  }
3915
- __name(getErrorMessage, "getErrorMessage");
3916
- function withErrorHandling(handler) {
3917
- return async (...args) => {
4374
+ __name(findInDir, "findInDir");
4375
+ async function watchDirRecursive(dirPath, callback, includeSubdirs = true) {
4376
+ const normalizedBasePath = path__default.default.normalize(dirPath);
4377
+ const watchers = [];
4378
+ const addWatcher = /* @__PURE__ */ __name((dir) => {
3918
4379
  try {
3919
- return await handler(...args);
3920
- } catch (err) {
3921
- if (isHttpError(err)) {
3922
- throw err;
3923
- }
3924
- getLogger().error({
3925
- err
3926
- }, "Caught error in handler");
3927
- let status = HttpStatusCodes.INTERNAL_SERVER_ERROR;
3928
- if (hasErrorShape(err) && typeof err.status === "number") {
3929
- status = err.status;
4380
+ const watcher = fs__default.default.watch(dir, (eventType, filename) => {
4381
+ if (!filename) return;
4382
+ const fullPath = path__default.default.join(dir, filename);
4383
+ const relativePath = path__default.default.relative(normalizedBasePath, fullPath);
4384
+ callback(eventType, relativePath);
4385
+ if (eventType === "rename" && includeSubdirs) {
4386
+ setTimeout(async () => {
4387
+ try {
4388
+ if (await isDirectory(fullPath)) {
4389
+ addWatcher(fullPath);
4390
+ }
4391
+ } catch {
4392
+ }
4393
+ }, 100);
4394
+ }
4395
+ });
4396
+ watchers.push(watcher);
4397
+ } catch {
4398
+ }
4399
+ }, "addWatcher");
4400
+ addWatcher(normalizedBasePath);
4401
+ if (includeSubdirs) {
4402
+ const subdirs = await getSubdirectories(normalizedBasePath, true);
4403
+ for (const subdir of subdirs) {
4404
+ addWatcher(subdir);
4405
+ }
4406
+ }
4407
+ return () => {
4408
+ for (const watcher of watchers) {
4409
+ watcher.close();
4410
+ }
4411
+ };
4412
+ }
4413
+ __name(watchDirRecursive, "watchDirRecursive");
4414
+ async function getDirStats(dirPath) {
4415
+ let fileCount = 0;
4416
+ let dirCount = 0;
4417
+ let totalSize = 0;
4418
+ async function processDir(currentPath) {
4419
+ const entries = await fsp__default.default.readdir(currentPath, {
4420
+ withFileTypes: true
4421
+ });
4422
+ for (const entry of entries) {
4423
+ const entryPath = path__default.default.join(currentPath, entry.name);
4424
+ if (entry.isDirectory()) {
4425
+ dirCount++;
4426
+ await processDir(entryPath);
4427
+ } else if (entry.isFile()) {
4428
+ fileCount++;
4429
+ const stat = await fsp__default.default.stat(entryPath);
4430
+ totalSize += stat.size;
3930
4431
  }
3931
- throw createHttpError(status, getErrorMessage(err));
3932
4432
  }
4433
+ }
4434
+ __name(processDir, "processDir");
4435
+ await processDir(dirPath);
4436
+ return {
4437
+ fileCount,
4438
+ dirCount,
4439
+ totalSize
3933
4440
  };
3934
4441
  }
3935
- __name(withErrorHandling, "withErrorHandling");
4442
+ __name(getDirStats, "getDirStats");
4443
+ async function walkDir(dirPath, options) {
4444
+ const traversalOrder = options.traversalOrder || "pre";
4445
+ const entries = await fsp__default.default.readdir(dirPath, {
4446
+ withFileTypes: true
4447
+ });
4448
+ for (const entry of entries) {
4449
+ const entryPath = path__default.default.join(dirPath, entry.name);
4450
+ const stats = await fsp__default.default.stat(entryPath);
4451
+ const entryInfo = {
4452
+ path: entryPath,
4453
+ name: entry.name,
4454
+ isDirectory: entry.isDirectory(),
4455
+ stats
4456
+ };
4457
+ if (entry.isDirectory()) {
4458
+ if (traversalOrder === "pre") {
4459
+ const shouldContinue = await options.visitorFn(entryInfo);
4460
+ if (shouldContinue !== false) {
4461
+ await walkDir(entryPath, options);
4462
+ }
4463
+ } else {
4464
+ await walkDir(entryPath, options);
4465
+ await options.visitorFn(entryInfo);
4466
+ }
4467
+ } else {
4468
+ await options.visitorFn(entryInfo);
4469
+ }
4470
+ }
4471
+ if (traversalOrder === "post") {
4472
+ const stats = await fsp__default.default.stat(dirPath);
4473
+ const entryInfo = {
4474
+ path: dirPath,
4475
+ name: path__default.default.basename(dirPath),
4476
+ isDirectory: true,
4477
+ stats
4478
+ };
4479
+ await options.visitorFn(entryInfo);
4480
+ }
4481
+ }
4482
+ __name(walkDir, "walkDir");
3936
4483
  async function fileExists(path3) {
3937
4484
  try {
3938
4485
  await fsp__default.default.access(path3);
@@ -4259,6 +4806,202 @@ function healthCheck(options) {
4259
4806
  }
4260
4807
  __name(healthCheck, "healthCheck");
4261
4808
 
4809
+ // src/utils/performance.utils.ts
4810
+ function timeSync(fn, options = {}) {
4811
+ const { label = fn.name || "anonymous function", log = false, logLevel = "debug" } = options;
4812
+ const startTime = performance.now();
4813
+ const result = fn();
4814
+ const endTime = performance.now();
4815
+ const durationMs = endTime - startTime;
4816
+ const durationSec = durationMs / 1e3;
4817
+ const timing = {
4818
+ durationMs,
4819
+ durationSec,
4820
+ startTime,
4821
+ endTime,
4822
+ label
4823
+ };
4824
+ if (log) {
4825
+ const logger2 = getLogger();
4826
+ const message = `${label} completed in ${durationMs.toFixed(2)}ms`;
4827
+ switch (logLevel) {
4828
+ case "trace":
4829
+ logger2.trace({
4830
+ timing
4831
+ }, message);
4832
+ break;
4833
+ case "debug":
4834
+ logger2.debug({
4835
+ timing
4836
+ }, message);
4837
+ break;
4838
+ case "info":
4839
+ logger2.info({
4840
+ timing
4841
+ }, message);
4842
+ break;
4843
+ case "warn":
4844
+ logger2.warn({
4845
+ timing
4846
+ }, message);
4847
+ break;
4848
+ case "error":
4849
+ logger2.error({
4850
+ timing
4851
+ }, message);
4852
+ break;
4853
+ default:
4854
+ logger2.debug({
4855
+ timing
4856
+ }, message);
4857
+ break;
4858
+ }
4859
+ }
4860
+ return {
4861
+ result,
4862
+ timing
4863
+ };
4864
+ }
4865
+ __name(timeSync, "timeSync");
4866
+ async function timeAsync(fn, options = {}) {
4867
+ const { label = fn.name || "anonymous async function", log = false, logLevel = "debug" } = options;
4868
+ const startTime = performance.now();
4869
+ const result = await fn();
4870
+ const endTime = performance.now();
4871
+ const durationMs = endTime - startTime;
4872
+ const durationSec = durationMs / 1e3;
4873
+ const timing = {
4874
+ durationMs,
4875
+ durationSec,
4876
+ startTime,
4877
+ endTime,
4878
+ label
4879
+ };
4880
+ if (log) {
4881
+ const logger2 = getLogger();
4882
+ const message = `${label} completed in ${durationMs.toFixed(2)}ms`;
4883
+ switch (logLevel) {
4884
+ case "trace":
4885
+ logger2.trace({
4886
+ timing
4887
+ }, message);
4888
+ break;
4889
+ case "debug":
4890
+ logger2.debug({
4891
+ timing
4892
+ }, message);
4893
+ break;
4894
+ case "info":
4895
+ logger2.info({
4896
+ timing
4897
+ }, message);
4898
+ break;
4899
+ case "warn":
4900
+ logger2.warn({
4901
+ timing
4902
+ }, message);
4903
+ break;
4904
+ case "error":
4905
+ logger2.error({
4906
+ timing
4907
+ }, message);
4908
+ break;
4909
+ default:
4910
+ logger2.debug({
4911
+ timing
4912
+ }, message);
4913
+ break;
4914
+ }
4915
+ }
4916
+ return {
4917
+ result,
4918
+ timing
4919
+ };
4920
+ }
4921
+ __name(timeAsync, "timeAsync");
4922
+ function timed(options = {}) {
4923
+ return function(target, propertyKeyOrContext, descriptor) {
4924
+ let propertyKey;
4925
+ let actualDescriptor;
4926
+ if (typeof propertyKeyOrContext === "object" && propertyKeyOrContext !== null && "name" in propertyKeyOrContext) {
4927
+ propertyKey = propertyKeyOrContext.name;
4928
+ actualDescriptor = descriptor ?? Object.getOwnPropertyDescriptor(target, propertyKey);
4929
+ } else {
4930
+ propertyKey = propertyKeyOrContext;
4931
+ actualDescriptor = descriptor ?? Object.getOwnPropertyDescriptor(target, propertyKey);
4932
+ }
4933
+ const originalMethod = actualDescriptor.value;
4934
+ actualDescriptor.value = function(...args) {
4935
+ const methodOptions = {
4936
+ ...options,
4937
+ label: options.label || `${target.constructor.name}.${String(propertyKey)}`
4938
+ };
4939
+ if (originalMethod.constructor.name === "AsyncFunction") {
4940
+ return timeAsync(() => originalMethod.apply(this, args), methodOptions).then(({ result }) => result);
4941
+ } else {
4942
+ return timeSync(() => originalMethod.apply(this, args), methodOptions).result;
4943
+ }
4944
+ };
4945
+ if (descriptor) {
4946
+ descriptor.value = actualDescriptor.value;
4947
+ } else {
4948
+ Object.defineProperty(target, propertyKey, actualDescriptor);
4949
+ }
4950
+ };
4951
+ }
4952
+ __name(timed, "timed");
4953
+ function memoize(fn, options = {}) {
4954
+ const { ttl, maxSize, autoCleanupMs, cacheKey = /* @__PURE__ */ __name((...args) => JSON.stringify(args), "cacheKey") } = options;
4955
+ const cache = new TTLCache({
4956
+ ttlMs: ttl,
4957
+ maxSize,
4958
+ autoCleanupMs
4959
+ });
4960
+ return function(...args) {
4961
+ const key = cacheKey(...args);
4962
+ const cachedValue = cache.get(key);
4963
+ if (cachedValue !== void 0) {
4964
+ return cachedValue;
4965
+ }
4966
+ const value = fn(...args);
4967
+ cache.set(key, value);
4968
+ return value;
4969
+ };
4970
+ }
4971
+ __name(memoize, "memoize");
4972
+ function trackMemoryUsage(fn, options = {}) {
4973
+ const { log = false, label = fn.name || "anonymous function" } = options;
4974
+ if (global.gc) {
4975
+ global.gc();
4976
+ }
4977
+ const beforeMemory = process.memoryUsage();
4978
+ const result = fn();
4979
+ const afterMemory = process.memoryUsage();
4980
+ const diff = {};
4981
+ for (const key in afterMemory) {
4982
+ if (Object.prototype.hasOwnProperty.call(afterMemory, key)) {
4983
+ diff[key] = afterMemory[key] - beforeMemory[key];
4984
+ }
4985
+ }
4986
+ if (log) {
4987
+ getLogger().info({
4988
+ label,
4989
+ memoryBefore: beforeMemory,
4990
+ memoryAfter: afterMemory,
4991
+ memoryDiff: diff
4992
+ }, `Memory usage for ${label}`);
4993
+ }
4994
+ return {
4995
+ result,
4996
+ memoryUsage: {
4997
+ before: beforeMemory,
4998
+ after: afterMemory,
4999
+ diff
5000
+ }
5001
+ };
5002
+ }
5003
+ __name(trackMemoryUsage, "trackMemoryUsage");
5004
+
4262
5005
  // src/utils/request.utils.ts
4263
5006
  var getPaginationParams = /* @__PURE__ */ __name((req) => {
4264
5007
  const query = req.query;
@@ -4417,6 +5160,120 @@ function extractFilterParams(query, allowedFilters) {
4417
5160
  return filters;
4418
5161
  }
4419
5162
  __name(extractFilterParams, "extractFilterParams");
5163
+ function bufferToStream(data) {
5164
+ const readable = new stream.Readable();
5165
+ readable.push(data);
5166
+ readable.push(null);
5167
+ return readable;
5168
+ }
5169
+ __name(bufferToStream, "bufferToStream");
5170
+ async function streamToBuffer(stream) {
5171
+ return new Promise((resolve2, reject) => {
5172
+ const chunks = [];
5173
+ stream.on("data", (chunk2) => chunks.push(Buffer.isBuffer(chunk2) ? chunk2 : Buffer.from(chunk2)));
5174
+ stream.on("end", () => resolve2(Buffer.concat(chunks)));
5175
+ stream.on("error", reject);
5176
+ });
5177
+ }
5178
+ __name(streamToBuffer, "streamToBuffer");
5179
+ async function streamToString(stream, encoding = "utf8") {
5180
+ const buffer = await streamToBuffer(stream);
5181
+ return buffer.toString(encoding);
5182
+ }
5183
+ __name(streamToString, "streamToString");
5184
+ function createThrottleStream(bytesPerSecond) {
5185
+ let bytesSent = 0;
5186
+ let startTime = Date.now();
5187
+ return new stream.Transform({
5188
+ transform(chunk2, _encoding, callback) {
5189
+ const elapsedSeconds = (Date.now() - startTime) / 1e3;
5190
+ const targetBytes = bytesPerSecond * elapsedSeconds;
5191
+ const chunkSize = chunk2.length;
5192
+ if (bytesSent + chunkSize <= targetBytes) {
5193
+ bytesSent += chunkSize;
5194
+ callback(null, chunk2);
5195
+ return;
5196
+ }
5197
+ const delay = ((bytesSent + chunkSize) / bytesPerSecond - elapsedSeconds) * 1e3;
5198
+ setTimeout(() => {
5199
+ bytesSent += chunkSize;
5200
+ callback(null, chunk2);
5201
+ }, delay);
5202
+ }
5203
+ });
5204
+ }
5205
+ __name(createThrottleStream, "createThrottleStream");
5206
+ function createBatchStream(size, options = {}) {
5207
+ const objectMode = options.objectMode !== false;
5208
+ let batch = [];
5209
+ let buffers = [];
5210
+ let bufferSize = 0;
5211
+ return new stream.Transform({
5212
+ objectMode,
5213
+ transform(chunk2, _encoding, callback) {
5214
+ if (objectMode) {
5215
+ batch.push(chunk2);
5216
+ if (batch.length >= size) {
5217
+ this.push(batch);
5218
+ batch = [];
5219
+ }
5220
+ } else {
5221
+ const buffer = Buffer.isBuffer(chunk2) ? chunk2 : Buffer.from(chunk2);
5222
+ buffers.push(buffer);
5223
+ bufferSize += buffer.length;
5224
+ let combined = Buffer.concat(buffers, bufferSize);
5225
+ while (combined.length >= size) {
5226
+ this.push(combined.slice(0, size));
5227
+ combined = combined.slice(size);
5228
+ }
5229
+ buffers = combined.length > 0 ? [
5230
+ combined
5231
+ ] : [];
5232
+ bufferSize = combined.length;
5233
+ }
5234
+ callback();
5235
+ },
5236
+ flush(callback) {
5237
+ if (objectMode && batch.length > 0) {
5238
+ this.push(batch);
5239
+ } else if (!objectMode && buffers.length > 0 && bufferSize > 0) {
5240
+ let combined = Buffer.concat(buffers, bufferSize);
5241
+ while (combined.length >= size) {
5242
+ this.push(combined.slice(0, size));
5243
+ combined = combined.slice(size);
5244
+ }
5245
+ if (combined.length > 0) {
5246
+ this.push(combined);
5247
+ }
5248
+ }
5249
+ callback();
5250
+ }
5251
+ });
5252
+ }
5253
+ __name(createBatchStream, "createBatchStream");
5254
+ function createLineStream(options = {}) {
5255
+ const { encoding = "utf8", includeNewlines = false } = options;
5256
+ let buffer = "";
5257
+ return new stream.Transform({
5258
+ objectMode: true,
5259
+ transform(chunk2, _encoding, callback) {
5260
+ const str = buffer + (Buffer.isBuffer(chunk2) ? chunk2.toString(encoding) : chunk2);
5261
+ const lines = str.split(/\r?\n/);
5262
+ buffer = lines.pop() || "";
5263
+ for (const line of lines) {
5264
+ this.push(includeNewlines ? line + "\n" : line);
5265
+ }
5266
+ callback();
5267
+ },
5268
+ flush(callback) {
5269
+ if (buffer) {
5270
+ this.push(buffer);
5271
+ }
5272
+ callback();
5273
+ }
5274
+ });
5275
+ }
5276
+ __name(createLineStream, "createLineStream");
4420
5277
 
4421
5278
  // src/utils/string.utils.ts
4422
5279
  function capitalize(str) {
@@ -4476,6 +5333,84 @@ function countOccurrences(str, substring, caseSensitive = true) {
4476
5333
  return str.split(substring).length - 1;
4477
5334
  }
4478
5335
  __name(countOccurrences, "countOccurrences");
5336
+
5337
+ // src/utils/type.utils.ts
5338
+ function isPrimitiveType(value, type) {
5339
+ if (type === "array") {
5340
+ return Array.isArray(value);
5341
+ }
5342
+ if (type === "null") {
5343
+ return value === null;
5344
+ }
5345
+ if (type === "undefined") {
5346
+ return value === void 0;
5347
+ }
5348
+ if (type === "object") {
5349
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5350
+ }
5351
+ return typeof value === type;
5352
+ }
5353
+ __name(isPrimitiveType, "isPrimitiveType");
5354
+ function getTypeOf(value) {
5355
+ if (value === null) return "null";
5356
+ if (value === void 0) return "undefined";
5357
+ if (Array.isArray(value)) return "array";
5358
+ return typeof value;
5359
+ }
5360
+ __name(getTypeOf, "getTypeOf");
5361
+ function isArrayOf(value, itemTypeGuard) {
5362
+ if (!Array.isArray(value)) return false;
5363
+ return value.every((item) => itemTypeGuard(item));
5364
+ }
5365
+ __name(isArrayOf, "isArrayOf");
5366
+ function toStr(value, defaultValue = "") {
5367
+ if (value === null || value === void 0) return defaultValue;
5368
+ try {
5369
+ if (typeof value === "object") {
5370
+ return JSON.stringify(value);
5371
+ }
5372
+ return String(value);
5373
+ } catch {
5374
+ return defaultValue;
5375
+ }
5376
+ }
5377
+ __name(toStr, "toStr");
5378
+ function toNum(value, defaultValue = 0) {
5379
+ if (value === null || value === void 0) return defaultValue;
5380
+ if (typeof value === "number") return value;
5381
+ try {
5382
+ const num = Number(value);
5383
+ return isNaN(num) ? defaultValue : num;
5384
+ } catch {
5385
+ return defaultValue;
5386
+ }
5387
+ }
5388
+ __name(toNum, "toNum");
5389
+ function toBool(value, defaultValue = false) {
5390
+ if (value === null || value === void 0) return defaultValue;
5391
+ if (typeof value === "boolean") return value;
5392
+ if (typeof value === "string") {
5393
+ const lowercased = value.toLowerCase();
5394
+ if (lowercased === "true" || lowercased === "yes" || lowercased === "y" || lowercased === "1") {
5395
+ return true;
5396
+ }
5397
+ if (lowercased === "false" || lowercased === "no" || lowercased === "n" || lowercased === "0") {
5398
+ return false;
5399
+ }
5400
+ }
5401
+ if (typeof value === "number") {
5402
+ return value !== 0;
5403
+ }
5404
+ return defaultValue;
5405
+ }
5406
+ __name(toBool, "toBool");
5407
+ function ensureType(value, expectedType, defaultValue) {
5408
+ if (getTypeOf(value) === expectedType) {
5409
+ return value;
5410
+ }
5411
+ return defaultValue;
5412
+ }
5413
+ __name(ensureType, "ensureType");
4479
5414
  function appendQueryParams(url$1, params) {
4480
5415
  const urlObj = new url.URL(url$1);
4481
5416
  for (const [key, value] of Object.entries(params)) {
@@ -6380,6 +7315,10 @@ exports.RateLimit = RateLimit;
6380
7315
  exports.Redirect = Redirect;
6381
7316
  exports.RedirectResponse = RedirectResponse;
6382
7317
  exports.Req = Req;
7318
+ exports.ReqCookie = ReqCookie;
7319
+ exports.ReqHeader = ReqHeader;
7320
+ exports.ReqId = ReqId;
7321
+ exports.ReqLogger = ReqLogger;
6383
7322
  exports.RequestTimeoutException = RequestTimeoutException;
6384
7323
  exports.Res = Res;
6385
7324
  exports.Roles = Roles;
@@ -6402,8 +7341,10 @@ exports._globalThis = _globalThis;
6402
7341
  exports.abortable = abortable;
6403
7342
  exports.addRedactFields = addRedactFields;
6404
7343
  exports.addSensitiveFields = addSensitiveFields;
7344
+ exports.addToDate = addToDate;
6405
7345
  exports.appendQueryParams = appendQueryParams;
6406
7346
  exports.appendTextFile = appendTextFile;
7347
+ exports.bufferToStream = bufferToStream;
6407
7348
  exports.capitalize = capitalize;
6408
7349
  exports.chunk = chunk;
6409
7350
  exports.circuitBreaker = circuitBreaker;
@@ -6412,20 +7353,27 @@ exports.copyDir = copyDir;
6412
7353
  exports.copyFile = copyFile;
6413
7354
  exports.countBy = countBy;
6414
7355
  exports.countOccurrences = countOccurrences;
7356
+ exports.createBatchStream = createBatchStream;
6415
7357
  exports.createChildLogger = createChildLogger;
6416
7358
  exports.createDeferred = createDeferred;
6417
7359
  exports.createDirectory = createDirectory;
6418
7360
  exports.createErrorResponse = createErrorResponse;
6419
7361
  exports.createFinalErrorResponse = createFinalErrorResponse;
6420
7362
  exports.createHttpError = createHttpError;
7363
+ exports.createLineStream = createLineStream;
6421
7364
  exports.createPaginatedResponse = createPaginatedResponse;
7365
+ exports.createParamDecorator = createParamDecorator;
7366
+ exports.createParamDecoratorWithoutParam = createParamDecoratorWithoutParam;
6422
7367
  exports.createRequestLogger = createRequestLogger;
6423
7368
  exports.createSignedToken = createSignedToken;
6424
7369
  exports.createSuccessResponse = createSuccessResponse;
6425
7370
  exports.createTaskQueue = createTaskQueue;
6426
7371
  exports.createTempDir = createTempDir;
6427
7372
  exports.createTempFile = createTempFile;
7373
+ exports.createThrottleStream = createThrottleStream;
6428
7374
  exports.createUrlBuilder = createUrlBuilder;
7375
+ exports.dateDiff = dateDiff;
7376
+ exports.daysInMonth = daysInMonth;
6429
7377
  exports.debounce = debounce;
6430
7378
  exports.decrypt = decrypt;
6431
7379
  exports.deepFreeze = deepFreeze;
@@ -6436,8 +7384,10 @@ exports.deleteFileIfExists = deleteFileIfExists;
6436
7384
  exports.difference = difference;
6437
7385
  exports.emptyDir = emptyDir;
6438
7386
  exports.encrypt = encrypt;
7387
+ exports.endOf = endOf;
6439
7388
  exports.ensureDir = ensureDir;
6440
7389
  exports.ensureEmptyDir = ensureEmptyDir;
7390
+ exports.ensureType = ensureType;
6441
7391
  exports.equalsIgnoreCase = equalsIgnoreCase;
6442
7392
  exports.errorHandler = errorHandler;
6443
7393
  exports.extractFilterParams = extractFilterParams;
@@ -6452,6 +7402,8 @@ exports.findNewestFile = findNewestFile;
6452
7402
  exports.findOldestFile = findOldestFile;
6453
7403
  exports.flattenDeep = flattenDeep;
6454
7404
  exports.flattenObject = flattenObject;
7405
+ exports.formatDate = formatDate;
7406
+ exports.formatRelativeTime = formatRelativeTime;
6455
7407
  exports.generateApiKey = generateApiKey;
6456
7408
  exports.generateRandomBytes = generateRandomBytes;
6457
7409
  exports.generateRandomBytesAsString = generateRandomBytesAsString;
@@ -6470,6 +7422,7 @@ exports.getPaginationParams = getPaginationParams;
6470
7422
  exports.getRedactCensor = getRedactCensor;
6471
7423
  exports.getRequestId = getRequestId;
6472
7424
  exports.getSubdirectories = getSubdirectories;
7425
+ exports.getTypeOf = getTypeOf;
6473
7426
  exports.getValueByPath = getValueByPath;
6474
7427
  exports.groupBy = groupBy;
6475
7428
  exports.hasErrorShape = hasErrorShape;
@@ -6477,11 +7430,14 @@ exports.hasRequiredProps = hasRequiredProps;
6477
7430
  exports.hash = hash;
6478
7431
  exports.healthCheck = healthCheck;
6479
7432
  exports.hmac = hmac;
7433
+ exports.inject = inject;
6480
7434
  exports.intersect = intersect;
6481
7435
  exports.isAlpha = isAlpha;
6482
7436
  exports.isAlphanumeric = isAlphanumeric;
6483
7437
  exports.isArray = isArray;
7438
+ exports.isArrayOf = isArrayOf;
6484
7439
  exports.isBase64 = isBase64;
7440
+ exports.isBetween = isBetween;
6485
7441
  exports.isCreditCard = isCreditCard;
6486
7442
  exports.isDateInRange = isDateInRange;
6487
7443
  exports.isDirectory = isDirectory;
@@ -6493,6 +7449,7 @@ exports.isHttpError = isHttpError;
6493
7449
  exports.isIPv4 = isIPv4;
6494
7450
  exports.isIPv6 = isIPv6;
6495
7451
  exports.isISODate = isISODate;
7452
+ exports.isLeapYear = isLeapYear;
6496
7453
  exports.isLengthBetween = isLengthBetween;
6497
7454
  exports.isNumberBetween = isNumberBetween;
6498
7455
  exports.isNumeric = isNumeric;
@@ -6501,6 +7458,7 @@ exports.isObject = isObject;
6501
7458
  exports.isPhone = isPhone;
6502
7459
  exports.isPlainObject = isPlainObject;
6503
7460
  exports.isPort = isPort;
7461
+ exports.isPrimitiveType = isPrimitiveType;
6504
7462
  exports.isStrongPassword = isStrongPassword;
6505
7463
  exports.isURL = isURL;
6506
7464
  exports.isUUID = isUUID;
@@ -6514,6 +7472,7 @@ exports.mapObject = mapObject;
6514
7472
  exports.mask = mask;
6515
7473
  exports.matchesPattern = matchesPattern;
6516
7474
  exports.md5 = md5;
7475
+ exports.memoize = memoize;
6517
7476
  exports.memoizeAsync = memoizeAsync;
6518
7477
  exports.mergeSort = mergeSort;
6519
7478
  exports.moveDir = moveDir;
@@ -6522,6 +7481,7 @@ exports.nanoId = nanoId;
6522
7481
  exports.normalizeUrl = normalizeUrl;
6523
7482
  exports.omit = omit;
6524
7483
  exports.parseBooleanParam = parseBooleanParam;
7484
+ exports.parseDate = parseDate;
6525
7485
  exports.parseNumberParam = parseNumberParam;
6526
7486
  exports.parseQueryString = parseQueryString;
6527
7487
  exports.parseTypedQueryParams = parseTypedQueryParams;
@@ -6565,16 +7525,26 @@ exports.shuffle = shuffle;
6565
7525
  exports.singletonAsync = singletonAsync;
6566
7526
  exports.sleep = sleep;
6567
7527
  exports.slugify = slugify;
7528
+ exports.startOf = startOf;
6568
7529
  exports.streamFile = streamFile;
7530
+ exports.streamToBuffer = streamToBuffer;
7531
+ exports.streamToString = streamToString;
6569
7532
  exports.stripHtml = stripHtml;
6570
7533
  exports.take = take;
6571
7534
  exports.takeWhile = takeWhile;
6572
7535
  exports.throttle = throttle;
7536
+ exports.timeAsync = timeAsync;
7537
+ exports.timeSync = timeSync;
7538
+ exports.timed = timed;
6573
7539
  exports.timeout = timeout;
7540
+ exports.toBool = toBool;
6574
7541
  exports.toCamelCase = toCamelCase;
6575
7542
  exports.toKebabCase = toKebabCase;
7543
+ exports.toNum = toNum;
6576
7544
  exports.toPascalCase = toPascalCase;
6577
7545
  exports.toSnakeCase = toSnakeCase;
7546
+ exports.toStr = toStr;
7547
+ exports.trackMemoryUsage = trackMemoryUsage;
6578
7548
  exports.truncate = truncate;
6579
7549
  exports.unique = unique;
6580
7550
  exports.uuid = uuid;