@catbee/utils 2.0.0-next.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +102 -52
  3. package/array/index.cjs +215 -74
  4. package/array/index.d.ts +345 -2
  5. package/array/index.mjs +201 -74
  6. package/async/index.cjs +116 -39
  7. package/async/index.d.ts +292 -2
  8. package/async/index.mjs +116 -40
  9. package/cache/index.cjs +2 -2
  10. package/cache/index.d.ts +156 -2
  11. package/cache/index.mjs +3 -3
  12. package/config/index.cjs +80 -66
  13. package/config/index.d.ts +65 -3
  14. package/config/index.mjs +77 -65
  15. package/context-store/index.cjs +2 -3
  16. package/context-store/index.d.ts +193 -2
  17. package/context-store/index.mjs +2 -3
  18. package/crypto/index.cjs +55 -5
  19. package/crypto/index.d.ts +225 -2
  20. package/crypto/index.mjs +52 -7
  21. package/date/index.cjs +676 -2
  22. package/date/index.d.ts +676 -2
  23. package/date/index.mjs +665 -3
  24. package/decorator/index.cjs +2172 -0
  25. package/{decorators/decorators.utils.d.ts → decorator/index.d.ts} +58 -54
  26. package/decorator/index.mjs +2131 -0
  27. package/{dir → directory}/index.cjs +5 -4
  28. package/{dir/dir.utils.d.ts → directory/index.d.ts} +24 -21
  29. package/{dir → directory}/index.mjs +5 -4
  30. package/env/index.cjs +100 -68
  31. package/env/index.d.ts +391 -2
  32. package/env/index.mjs +100 -68
  33. package/exception/index.cjs +1 -1
  34. package/exception/index.d.ts +233 -2
  35. package/exception/index.mjs +1 -1
  36. package/fs/index.cjs +71 -37
  37. package/fs/index.d.ts +206 -2
  38. package/fs/index.mjs +65 -35
  39. package/http-status-codes/index.cjs +1 -1
  40. package/http-status-codes/index.d.ts +268 -2
  41. package/http-status-codes/index.mjs +1 -1
  42. package/id/index.cjs +1 -1
  43. package/id/index.d.ts +38 -2
  44. package/id/index.mjs +1 -1
  45. package/index.cjs +13 -13
  46. package/index.d.ts +5 -5
  47. package/index.mjs +5 -5
  48. package/logger/index.cjs +13 -15
  49. package/logger/index.d.ts +190 -2
  50. package/logger/index.mjs +14 -16
  51. package/middleware/index.cjs +1 -1
  52. package/middleware/index.d.ts +104 -2
  53. package/middleware/index.mjs +1 -1
  54. package/object/index.cjs +379 -0
  55. package/{obj/obj.utils.d.ts → object/index.d.ts} +73 -33
  56. package/object/index.mjs +360 -0
  57. package/package.json +41 -23
  58. package/performance/index.cjs +4 -4
  59. package/performance/index.d.ts +139 -2
  60. package/performance/index.mjs +4 -4
  61. package/request/index.cjs +37 -25
  62. package/request/index.d.ts +242 -3
  63. package/request/index.mjs +37 -25
  64. package/response/index.cjs +1 -1
  65. package/response/index.d.ts +319 -3
  66. package/response/index.mjs +1 -1
  67. package/server/index.cjs +249 -146
  68. package/server/index.d.ts +866 -5
  69. package/server/index.mjs +248 -144
  70. package/stream/index.cjs +1 -1
  71. package/stream/index.d.ts +91 -2
  72. package/stream/index.mjs +1 -1
  73. package/string/index.cjs +34 -1
  74. package/string/index.d.ts +146 -2
  75. package/string/index.mjs +31 -2
  76. package/type/index.cjs +19 -2
  77. package/type/index.d.ts +144 -2
  78. package/type/index.mjs +17 -3
  79. package/types/index.cjs +1 -1
  80. package/types/index.d.ts +775 -5
  81. package/types/index.mjs +1 -1
  82. package/url/index.cjs +63 -5
  83. package/url/index.d.ts +200 -2
  84. package/url/index.mjs +59 -6
  85. package/{validate → validation}/index.cjs +91 -44
  86. package/{validate/validate.utils.d.ts → validation/index.d.ts} +33 -24
  87. package/{validate → validation}/index.mjs +87 -44
  88. package/array/array.utils.d.ts +0 -191
  89. package/async/async.utils.d.ts +0 -296
  90. package/cache/cache.utils.d.ts +0 -176
  91. package/config/config.d.ts +0 -57
  92. package/context-store/context-store.utils.d.ts +0 -212
  93. package/crypto/crypto.utils.d.ts +0 -183
  94. package/date/date.utils.d.ts +0 -190
  95. package/decorators/index.cjs +0 -913
  96. package/decorators/index.d.ts +0 -25
  97. package/decorators/index.mjs +0 -872
  98. package/dir/index.d.ts +0 -25
  99. package/env/env.utils.d.ts +0 -400
  100. package/exception/exception.utils.d.ts +0 -253
  101. package/fs/fs.utils.d.ts +0 -196
  102. package/http-status-codes/http-status-codes.d.ts +0 -289
  103. package/id/id.utils.d.ts +0 -59
  104. package/logger/logger.utils.d.ts +0 -210
  105. package/middleware/middleware.utils.d.ts +0 -123
  106. package/obj/index.cjs +0 -317
  107. package/obj/index.d.ts +0 -25
  108. package/obj/index.mjs +0 -301
  109. package/performance/performance.utils.d.ts +0 -159
  110. package/request/request.utils.d.ts +0 -109
  111. package/response/response.utils.d.ts +0 -186
  112. package/server/server.builder.d.ts +0 -531
  113. package/server/server.d.ts +0 -303
  114. package/stream/stream.utils.d.ts +0 -111
  115. package/string/string.utils.d.ts +0 -124
  116. package/type/type.utils.d.ts +0 -129
  117. package/types/api-response.d.ts +0 -175
  118. package/types/common.d.ts +0 -148
  119. package/types/config.d.ts +0 -88
  120. package/types/server.d.ts +0 -291
  121. package/url/url.utils.d.ts +0 -164
  122. package/validate/index.d.ts +0 -25
package/server/index.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * The MIT License
3
3
  *
4
- * Copyright (c) 2025 Catbee Technologies. https://catbee.in/license
4
+ * Copyright (c) 2026 Catbee Technologies. https://catbee.in/license
5
5
  *
6
6
  * Permission is hereby granted, free of charge, to any person obtaining a copy
7
7
  * of this software and associated documentation files (the "Software"), to deal
@@ -32,18 +32,17 @@ var middleware = require('@catbee/utils/middleware');
32
32
  var env = require('@catbee/utils/env');
33
33
  var logger = require('@catbee/utils/logger');
34
34
  var exception = require('@catbee/utils/exception');
35
- var fs$1 = require('fs');
36
35
  var config = require('@catbee/utils/config');
37
- var obj = require('@catbee/utils/obj');
36
+ var object = require('@catbee/utils/object');
38
37
  var fs = require('@catbee/utils/fs');
39
- var validate = require('@catbee/utils/validate');
38
+ var validation = require('@catbee/utils/validation');
40
39
  var async = require('@catbee/utils/async');
40
+ var id = require('@catbee/utils/id');
41
41
 
42
42
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
43
43
 
44
44
  var express__default = /*#__PURE__*/_interopDefault(express);
45
45
  var https__default = /*#__PURE__*/_interopDefault(https);
46
- var fs__default = /*#__PURE__*/_interopDefault(fs$1);
47
46
 
48
47
  var __defProp = Object.defineProperty;
49
48
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
@@ -61,7 +60,7 @@ var ServerConfigBuilder = class {
61
60
  * @throws {Error} If port is not an integer or is outside the valid range (1-65535)
62
61
  */
63
62
  validatePort(port) {
64
- if (!validate.isPort(port)) {
63
+ if (!validation.isPort(port)) {
65
64
  throw new Error(`Port must be a valid number between 1 and 65535, got: ${port}`);
66
65
  }
67
66
  }
@@ -506,7 +505,10 @@ var ServerConfigBuilder = class {
506
505
  * ```
507
506
  */
508
507
  withBodyParser(opts) {
509
- this.config.bodyParser = obj.deepObjMerge({}, this.config.bodyParser ?? {}, opts);
508
+ this.config.bodyParser = {
509
+ ...this.config.bodyParser,
510
+ ...opts
511
+ };
510
512
  return this;
511
513
  }
512
514
  /**
@@ -609,7 +611,7 @@ var ServerConfigBuilder = class {
609
611
  * ```
610
612
  */
611
613
  withCustom(overrides) {
612
- this.config = obj.deepObjMerge({}, this.config, overrides);
614
+ this.config = object.deepObjMerge({}, this.config, overrides);
613
615
  return this;
614
616
  }
615
617
  /**
@@ -649,7 +651,7 @@ var ServerConfigBuilder = class {
649
651
  * ```
650
652
  */
651
653
  build() {
652
- const config$1 = obj.deepObjMerge({}, config.defaultServerConfig, this.config);
654
+ const config$1 = object.deepObjMerge({}, config.getCatbeeServerGlobalConfig(), this.config);
653
655
  if (config$1.openApi?.enable && !config$1.openApi.filePath) {
654
656
  throw new Error("OpenAPI is enabled but no filePath is specified");
655
657
  }
@@ -659,8 +661,8 @@ var ServerConfigBuilder = class {
659
661
  });
660
662
  }
661
663
  mergeConfig(key, value) {
662
- const current = typeof this.config[key] === "object" && this.config[key] !== null ? this.config[key] : {};
663
- this.config[key] = obj.deepObjMerge({}, current, value);
664
+ const current = this.config[key] && typeof this.config[key] === "object" ? object.deepClone(this.config[key]) : {};
665
+ this.config[key] = object.deepObjMerge({}, current, value);
664
666
  }
665
667
  setEnabled(key, enable, overrides = {}) {
666
668
  this.mergeConfig(key, {
@@ -670,9 +672,11 @@ var ServerConfigBuilder = class {
670
672
  return this;
671
673
  }
672
674
  };
673
-
674
- // src/server/server.ts
675
- var getDependencyErrorMessage = /* @__PURE__ */ __name((packageName, x) => `Missing required dependency ${x ? `for ${x}` : ""}: ${packageName}. Please install it to proceed.`, "getDependencyErrorMessage");
675
+ var getDependencyErrorMessage = /* @__PURE__ */ __name((packageName, context) => {
676
+ const ctxPart = context ? `for ${context}` : "";
677
+ const spacer = ctxPart ? ` ${ctxPart}` : "";
678
+ return `Missing required dependency${spacer}: ${packageName}. Please install it to proceed.`;
679
+ }, "getDependencyErrorMessage");
676
680
  var DependencyErrors = {
677
681
  express: getDependencyErrorMessage("express"),
678
682
  helmet: getDependencyErrorMessage("helmet"),
@@ -737,12 +741,12 @@ var ExpressServer = class {
737
741
  * - Request tracing
738
742
  */
739
743
  constructor(config$1, hooks = {}) {
740
- if (this.isBuiltServerConfig(config$1)) {
744
+ if (this.hasBuildMarker(config$1)) {
741
745
  this.config = config$1;
742
746
  } else {
743
- this.config = obj.deepObjMerge({}, config.defaultServerConfig, config$1);
747
+ this.config = object.deepObjMerge({}, config.getCatbeeServerGlobalConfig(), config$1);
744
748
  }
745
- if (!validate.isPort(this.config.port)) {
749
+ if (!validation.isPort(this.config.port)) {
746
750
  const msg = `Port must be a valid number between 1 and 65535, got: ${this.config.port}`;
747
751
  logger.getLogger().error(msg);
748
752
  throw new Error(msg);
@@ -842,7 +846,7 @@ var ExpressServer = class {
842
846
  async runHook(hook, ...args) {
843
847
  try {
844
848
  const fn = this.hooks[hook];
845
- if (fn) await fn.apply(null, args);
849
+ if (fn) await fn(...args);
846
850
  } catch (err) {
847
851
  logger.getLogger().error({
848
852
  err,
@@ -882,6 +886,24 @@ var ExpressServer = class {
882
886
  if (this.config.https) {
883
887
  await this.validateHttpsFiles();
884
888
  }
889
+ this.setupBasicMiddleware();
890
+ this.setupSecurityMiddleware();
891
+ this.setupGlobalHeaders();
892
+ this.setupTimeoutMiddleware();
893
+ this.setupResponseTimeMiddleware();
894
+ this.setupRateLimitingMiddleware();
895
+ this.setupRequestLoggingMiddleware();
896
+ this.setupCompressionMiddleware();
897
+ this.setupStaticFilesMiddleware();
898
+ this.setupBodyParsingMiddleware();
899
+ this.setupCookieParsingMiddleware();
900
+ await this.setupOpenApiMiddleware();
901
+ this.setupMetricsMiddleware();
902
+ }
903
+ /**
904
+ * Set up basic middleware (trust proxy, request ID, context).
905
+ */
906
+ setupBasicMiddleware() {
885
907
  this.app.disable("x-powered-by");
886
908
  if (this.config.trustProxy) {
887
909
  this.app.set("trust proxy", true);
@@ -889,7 +911,7 @@ var ExpressServer = class {
889
911
  this.app.use(middleware.requestId({
890
912
  headerName: this.config.requestId?.headerName,
891
913
  exposeHeader: this.config.requestId?.exposeHeader,
892
- generator: this.config.requestId?.generator
914
+ generator: this.config.requestId?.generator || id.uuid
893
915
  }));
894
916
  this.app.use(middleware.setupRequestContext({
895
917
  headerName: this.config.requestId?.headerName,
@@ -898,11 +920,15 @@ var ExpressServer = class {
898
920
  this.app.use((_req, res, next) => {
899
921
  if (this.isShuttingDown) {
900
922
  res.setHeader("Connection", "close");
901
- return res.status(httpStatusCodes.HttpStatusCodes.SERVICE_UNAVAILABLE).json(new exception.ServiceUnavailableException("Server is shutting down"));
923
+ res.status(httpStatusCodes.HttpStatusCodes.SERVICE_UNAVAILABLE).json(new exception.ServiceUnavailableException("Server is shutting down"));
902
924
  }
903
925
  next();
904
- return;
905
926
  });
927
+ }
928
+ /**
929
+ * Set up security middleware (Helmet, CORS).
930
+ */
931
+ setupSecurityMiddleware() {
906
932
  if (this.config.helmet) {
907
933
  const helmet = async.optionalRequire("helmet");
908
934
  if (!helmet) {
@@ -921,6 +947,11 @@ var ExpressServer = class {
921
947
  }
922
948
  this.app.use(cors(this.config.cors === true ? {} : this.config.cors));
923
949
  }
950
+ }
951
+ /**
952
+ * Set up global headers middleware.
953
+ */
954
+ setupGlobalHeaders() {
924
955
  this.app.use((_req, res, next) => {
925
956
  if (this.config.globalHeaders) {
926
957
  for (const key in this.config.globalHeaders) {
@@ -937,15 +968,30 @@ var ExpressServer = class {
937
968
  }
938
969
  next();
939
970
  });
971
+ }
972
+ /**
973
+ * Set up request timeout middleware.
974
+ */
975
+ setupTimeoutMiddleware() {
940
976
  if (this.config.requestTimeout) {
941
977
  this.app.use(middleware.timeout(this.config.requestTimeout));
942
978
  }
979
+ }
980
+ /**
981
+ * Set up response time tracking middleware.
982
+ */
983
+ setupResponseTimeMiddleware() {
943
984
  if (this.config.responseTime?.enable) {
944
985
  this.app.use(middleware.responseTime({
945
986
  addHeader: this.config.responseTime.addHeader,
946
987
  logOnComplete: this.config.responseTime.logOnComplete
947
988
  }));
948
989
  }
990
+ }
991
+ /**
992
+ * Set up rate limiting middleware.
993
+ */
994
+ setupRateLimitingMiddleware() {
949
995
  if (this.config.rateLimit?.enable) {
950
996
  const rateLimit = async.optionalRequire("express-rate-limit");
951
997
  if (!rateLimit) {
@@ -963,6 +1009,11 @@ var ExpressServer = class {
963
1009
  legacyHeaders: this.config.rateLimit.legacyHeaders ?? false
964
1010
  }));
965
1011
  }
1012
+ }
1013
+ /**
1014
+ * Set up request logging middleware.
1015
+ */
1016
+ setupRequestLoggingMiddleware() {
966
1017
  if (this.config.requestLogging?.enable) {
967
1018
  this.app.use((req, res, next) => {
968
1019
  if (typeof this.config.requestLogging?.ignorePaths === "function") {
@@ -986,6 +1037,11 @@ var ExpressServer = class {
986
1037
  if (this.hooks.onRequest) {
987
1038
  this.app.use(this.hooks.onRequest);
988
1039
  }
1040
+ }
1041
+ /**
1042
+ * Set up response compression middleware.
1043
+ */
1044
+ setupCompressionMiddleware() {
989
1045
  if (this.config.compression) {
990
1046
  const compression = async.optionalRequire("compression");
991
1047
  if (!compression) {
@@ -997,6 +1053,11 @@ var ExpressServer = class {
997
1053
  this.app.use(compression());
998
1054
  }
999
1055
  }
1056
+ }
1057
+ /**
1058
+ * Set up static file serving middleware.
1059
+ */
1060
+ setupStaticFilesMiddleware() {
1000
1061
  if (this.config.staticFolders) {
1001
1062
  this.config.staticFolders.forEach((folder) => {
1002
1063
  this.app.use(this.normalizePath(folder.path ?? "/"), express__default.default.static(folder.directory, {
@@ -1009,6 +1070,11 @@ var ExpressServer = class {
1009
1070
  logger.getLogger().info(`Serving static folder: ${folder.directory} at path ${folder.path || "/"}`);
1010
1071
  });
1011
1072
  }
1073
+ }
1074
+ /**
1075
+ * Set up body parsing middleware.
1076
+ */
1077
+ setupBodyParsingMiddleware() {
1012
1078
  if (this.config.bodyParser) {
1013
1079
  if (this.config.bodyParser.json) {
1014
1080
  this.app.use(express__default.default.json(this.config.bodyParser.json));
@@ -1017,6 +1083,11 @@ var ExpressServer = class {
1017
1083
  this.app.use(express__default.default.urlencoded(this.config.bodyParser.urlencoded));
1018
1084
  }
1019
1085
  }
1086
+ }
1087
+ /**
1088
+ * Set up cookie parsing middleware.
1089
+ */
1090
+ setupCookieParsingMiddleware() {
1020
1091
  if (this.config.cookieParser) {
1021
1092
  const cookieParser = async.optionalRequire("cookie-parser");
1022
1093
  if (!cookieParser) {
@@ -1028,6 +1099,11 @@ var ExpressServer = class {
1028
1099
  this.app.use(cookieParser());
1029
1100
  }
1030
1101
  }
1102
+ }
1103
+ /**
1104
+ * Set up OpenAPI documentation middleware.
1105
+ */
1106
+ async setupOpenApiMiddleware() {
1031
1107
  if (this.config.openApi?.enable) {
1032
1108
  try {
1033
1109
  const openApiMountPath = this.normalizePath(this.config.openApi.mountPath ?? "/docs", this.config.openApi.withGlobalPrefix);
@@ -1053,7 +1129,7 @@ var ExpressServer = class {
1053
1129
  }
1054
1130
  this.app.use(openApiMountPath, apiReference({
1055
1131
  spec: {
1056
- content: await fs__default.default.promises.readFile(openApiFilePath, "utf8")
1132
+ content: await fs.readFile(openApiFilePath, "utf8")
1057
1133
  }
1058
1134
  }));
1059
1135
  if (this.config.openApi?.verbose) {
@@ -1068,6 +1144,11 @@ var ExpressServer = class {
1068
1144
  if (this.hooks.onResponse) {
1069
1145
  this.app.use(this.globalPrefix, this.hooks.onResponse);
1070
1146
  }
1147
+ }
1148
+ /**
1149
+ * Set up metrics tracking middleware.
1150
+ */
1151
+ setupMetricsMiddleware() {
1071
1152
  if (this.config.metrics?.enable) {
1072
1153
  this.app.use((req, res, next) => {
1073
1154
  const start = process.hrtime();
@@ -1116,45 +1197,7 @@ var ExpressServer = class {
1116
1197
  async setupRoutes() {
1117
1198
  const healthCheckPath = this.normalizePath(this.config.healthCheck?.path || "/healthz", this.config.healthCheck?.withGlobalPrefix);
1118
1199
  this.app.get(healthCheckPath, async (_req, res) => {
1119
- try {
1120
- if (!this.healthChecks.length || config.defaultCatbeeConfig.server.skipHealthz) {
1121
- return res.status(httpStatusCodes.HttpStatusCodes.OK).json(new response.SuccessResponse("OK"));
1122
- }
1123
- const checkResults = await Promise.allSettled(this.healthChecks.map(async ({ name, check }) => {
1124
- try {
1125
- const status2 = await Promise.resolve(check());
1126
- return {
1127
- name,
1128
- status: status2,
1129
- error: null
1130
- };
1131
- } catch (error) {
1132
- return {
1133
- name,
1134
- status: false,
1135
- error: error.message
1136
- };
1137
- }
1138
- }));
1139
- const results = checkResults.map((result) => {
1140
- if (result.status === "fulfilled") return result.value;
1141
- return {
1142
- name: "unknown",
1143
- status: false,
1144
- error: result.reason
1145
- };
1146
- });
1147
- const allOk = results.every((r) => r.status);
1148
- const status = allOk ? httpStatusCodes.HttpStatusCodes.OK : httpStatusCodes.HttpStatusCodes.SERVICE_UNAVAILABLE;
1149
- const response$1 = new response.SuccessResponse(allOk ? "OK" : "Service unavailable");
1150
- if (!allOk) response$1.error = true;
1151
- if (this.config.healthCheck?.detailed) response$1.data = {
1152
- checks: results
1153
- };
1154
- return res.status(status).json(response$1);
1155
- } catch {
1156
- return res.status(httpStatusCodes.HttpStatusCodes.INTERNAL_SERVER_ERROR).json(new exception.InternalServerErrorException("Health check failed"));
1157
- }
1200
+ return this.handleHealthCheckRequest(res);
1158
1201
  });
1159
1202
  if (this.config.metrics?.enable) {
1160
1203
  const metricsPath = this.normalizePath(this.config.metrics.path ?? "/metrics", this.config.metrics?.withGlobalPrefix);
@@ -1186,6 +1229,56 @@ var ExpressServer = class {
1186
1229
  });
1187
1230
  }
1188
1231
  /**
1232
+ * Execute health check and return response.
1233
+ */
1234
+ async handleHealthCheckRequest(res) {
1235
+ try {
1236
+ if (!this.healthChecks.length || config.getCatbeeServerGlobalConfig().skipHealthzChecksValidation) {
1237
+ return res.status(httpStatusCodes.HttpStatusCodes.OK).json(new response.SuccessResponse("OK"));
1238
+ }
1239
+ const results = await this.executeHealthChecks();
1240
+ const allOk = results.every((r) => r.status);
1241
+ const status = allOk ? httpStatusCodes.HttpStatusCodes.OK : httpStatusCodes.HttpStatusCodes.SERVICE_UNAVAILABLE;
1242
+ const response$1 = new response.SuccessResponse(allOk ? "OK" : "Service unavailable");
1243
+ if (!allOk) response$1.error = true;
1244
+ if (this.config.healthCheck?.detailed) response$1.data = {
1245
+ checks: results
1246
+ };
1247
+ return res.status(status).json(response$1);
1248
+ } catch {
1249
+ return res.status(httpStatusCodes.HttpStatusCodes.INTERNAL_SERVER_ERROR).json(new exception.InternalServerErrorException("Health check failed"));
1250
+ }
1251
+ }
1252
+ /**
1253
+ * Execute all registered health checks and return results.
1254
+ */
1255
+ async executeHealthChecks() {
1256
+ const checkResults = await Promise.allSettled(this.healthChecks.map(async ({ name, check }) => {
1257
+ try {
1258
+ const status = await Promise.resolve(check());
1259
+ return {
1260
+ name,
1261
+ status,
1262
+ error: null
1263
+ };
1264
+ } catch (error) {
1265
+ return {
1266
+ name,
1267
+ status: false,
1268
+ error: error.message
1269
+ };
1270
+ }
1271
+ }));
1272
+ return checkResults.map((result) => {
1273
+ if (result.status === "fulfilled") return result.value;
1274
+ return {
1275
+ name: "unknown",
1276
+ status: false,
1277
+ error: result.reason
1278
+ };
1279
+ });
1280
+ }
1281
+ /**
1189
1282
  * Register a new health check function for monitoring service dependencies.
1190
1283
  *
1191
1284
  * Health checks are executed when the health endpoint is accessed and
@@ -1216,28 +1309,8 @@ var ExpressServer = class {
1216
1309
  */
1217
1310
  async ready() {
1218
1311
  try {
1219
- if (!this.healthChecks.length || config.defaultCatbeeConfig.server.skipHealthz) return true;
1220
- const checkResults = await Promise.allSettled(this.healthChecks.map(async ({ name, check }) => {
1221
- try {
1222
- const status = await Promise.resolve(check());
1223
- return {
1224
- name,
1225
- status,
1226
- error: null
1227
- };
1228
- } catch (error) {
1229
- return {
1230
- name,
1231
- status: false,
1232
- error: error.message
1233
- };
1234
- }
1235
- }));
1236
- const results = checkResults.map((result) => result.status === "fulfilled" ? result.value : {
1237
- name: "unknown",
1238
- status: false,
1239
- error: result.reason
1240
- });
1312
+ if (!this.healthChecks.length || config.getCatbeeServerGlobalConfig().skipHealthzChecksValidation) return true;
1313
+ const results = await this.executeHealthChecks();
1241
1314
  return results.every((r) => r.status === true);
1242
1315
  } catch (err) {
1243
1316
  logger.getLogger().error({
@@ -1282,58 +1355,82 @@ var ExpressServer = class {
1282
1355
  await this.runHook("beforeStart", this.app);
1283
1356
  return new Promise((resolve, reject) => {
1284
1357
  try {
1285
- const listenArgs = [
1286
- this.config.port,
1287
- this.config.host,
1288
- async () => {
1289
- const protocol = this.config.https ? "https" : "http";
1290
- const url = `${protocol}://${this.config.host}:${this.config.port}`;
1291
- logger.getLogger().info(`Server running on ${url}`);
1292
- if (this.config.healthCheck?.path) {
1293
- logger.getLogger().info(`Health check available at ${url}${this.normalizePath(this.config.healthCheck.path, this.config.healthCheck.withGlobalPrefix)}`);
1294
- }
1295
- if (this.config.metrics?.enable && this.config.metrics.path) {
1296
- logger.getLogger().info(`Metrics available at ${url}${this.normalizePath(this.config.metrics.path, this.config.metrics.withGlobalPrefix)}`);
1297
- }
1298
- if (this.config.openApi?.enable) {
1299
- logger.getLogger().info(`API docs available at ${url}${this.normalizePath(this.config.openApi.mountPath, this.config.openApi.withGlobalPrefix)}`);
1300
- }
1301
- if (this.server) await this.runHook("afterStart", this.server);
1302
- resolve(this.server);
1303
- }
1304
- ];
1305
- if (this.config.https) {
1306
- const httpsOptions = {
1307
- ...this.config.https,
1308
- key: fs__default.default.readFileSync(this.config.https.key),
1309
- cert: fs__default.default.readFileSync(this.config.https.cert)
1310
- };
1311
- if (this.config.https.ca) {
1312
- httpsOptions.ca = fs__default.default.readFileSync(this.config.https.ca);
1313
- }
1314
- if (this.config.https.passphrase) {
1315
- httpsOptions.passphrase = this.config.https.passphrase;
1316
- }
1317
- this.server = https__default.default.createServer(httpsOptions, this.app).listen(...listenArgs);
1318
- } else {
1319
- this.server = this.app.listen(...listenArgs);
1320
- }
1321
- this.server.on("connection", (conn) => {
1322
- this.connections.add(conn);
1323
- conn.on("close", () => this.connections.delete(conn));
1324
- });
1325
- this.server.on("error", (err) => {
1326
- logger.getLogger().error({
1327
- err
1328
- }, "Server failed to start");
1329
- reject(err);
1330
- });
1358
+ const onListening = /* @__PURE__ */ __name(async () => {
1359
+ this.logServerStartInfo();
1360
+ if (this.server) await this.runHook("afterStart", this.server);
1361
+ resolve(this.server);
1362
+ }, "onListening");
1363
+ this.server = this.createServerInstance(onListening);
1364
+ this.setupConnectionTracking();
1365
+ this.setupServerErrorHandling(reject);
1331
1366
  } catch (error) {
1332
1367
  reject(error);
1333
1368
  }
1334
1369
  });
1335
1370
  }
1336
1371
  /**
1372
+ * Create HTTP or HTTPS server instance.
1373
+ */
1374
+ createServerInstance(onListening) {
1375
+ const listenArgs = [
1376
+ this.config.port,
1377
+ this.config.host,
1378
+ onListening
1379
+ ];
1380
+ if (this.config.https) {
1381
+ const httpsOptions = {
1382
+ ...this.config.https,
1383
+ key: fs.readFileSync(this.config.https.key),
1384
+ cert: fs.readFileSync(this.config.https.cert)
1385
+ };
1386
+ if (this.config.https.ca) {
1387
+ httpsOptions.ca = fs.readFileSync(this.config.https.ca);
1388
+ }
1389
+ if (this.config.https.passphrase) {
1390
+ httpsOptions.passphrase = this.config.https.passphrase;
1391
+ }
1392
+ return https__default.default.createServer(httpsOptions, this.app).listen(...listenArgs);
1393
+ }
1394
+ return this.app.listen(...listenArgs);
1395
+ }
1396
+ /**
1397
+ * Set up connection tracking for graceful shutdown.
1398
+ */
1399
+ setupConnectionTracking() {
1400
+ this.server.on("connection", (conn) => {
1401
+ this.connections.add(conn);
1402
+ conn.on("close", () => this.connections.delete(conn));
1403
+ });
1404
+ }
1405
+ /**
1406
+ * Set up error handling for server startup.
1407
+ */
1408
+ setupServerErrorHandling(reject) {
1409
+ this.server.on("error", (err) => {
1410
+ logger.getLogger().error({
1411
+ err
1412
+ }, "Server failed to start");
1413
+ reject(err);
1414
+ });
1415
+ }
1416
+ /**
1417
+ * Log server startup information.
1418
+ */
1419
+ logServerStartInfo() {
1420
+ const protocol = this.config.https ? "https" : "http";
1421
+ const url = `${protocol}://${this.config.host}:${this.config.port}`;
1422
+ logger.getLogger().info(`Server running on ${url}`);
1423
+ if (this.config.healthCheck?.path) {
1424
+ logger.getLogger().info(`Health check available at ${url}${this.normalizePath(this.config.healthCheck.path, this.config.healthCheck.withGlobalPrefix)}`);
1425
+ }
1426
+ if (this.config.metrics?.enable && this.config.metrics.path) {
1427
+ logger.getLogger().info(`Metrics available at ${url}${this.normalizePath(this.config.metrics.path, this.config.metrics.withGlobalPrefix)}`);
1428
+ }
1429
+ if (this.config.openApi?.enable) {
1430
+ logger.getLogger().info(`API docs available at ${url}${this.normalizePath(this.config.openApi.mountPath, this.config.openApi.withGlobalPrefix)}`);
1431
+ }
1432
+ }
1433
+ /**
1337
1434
  * Stop the HTTP server gracefully.
1338
1435
  *
1339
1436
  * This method:
@@ -1360,6 +1457,23 @@ var ExpressServer = class {
1360
1457
  }
1361
1458
  this.isShuttingDown = true;
1362
1459
  await this.runHook("beforeStop", this.server);
1460
+ try {
1461
+ await this.gracefulShutdown();
1462
+ } catch (err) {
1463
+ logger.getLogger().error({
1464
+ err
1465
+ }, "Graceful shutdown timed out");
1466
+ if (force) {
1467
+ logger.getLogger().warn("Forcing connection destroy due to shutdown timeout");
1468
+ }
1469
+ } finally {
1470
+ await this.destroyConnections();
1471
+ }
1472
+ }
1473
+ /**
1474
+ * Perform graceful server shutdown with timeout.
1475
+ */
1476
+ async gracefulShutdown() {
1363
1477
  const shutdownTimeout = 1e4;
1364
1478
  const serverClosePromise = new Promise((resolve, reject) => {
1365
1479
  this.server.close(async (err) => {
@@ -1378,21 +1492,10 @@ var ExpressServer = class {
1378
1492
  });
1379
1493
  });
1380
1494
  const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error("Shutdown timeout")), shutdownTimeout));
1381
- try {
1382
- await Promise.race([
1383
- serverClosePromise,
1384
- timeoutPromise
1385
- ]);
1386
- } catch (err) {
1387
- logger.getLogger().error({
1388
- err
1389
- }, "Graceful shutdown timed out");
1390
- if (force) {
1391
- logger.getLogger().warn("Forcing connection destroy due to shutdown timeout");
1392
- }
1393
- } finally {
1394
- await this.destroyConnections();
1395
- }
1495
+ await Promise.race([
1496
+ serverClosePromise,
1497
+ timeoutPromise
1498
+ ]);
1396
1499
  }
1397
1500
  /**
1398
1501
  * Enable graceful shutdown on OS signals for production deployment.
@@ -1534,7 +1637,7 @@ var ExpressServer = class {
1534
1637
  /**
1535
1638
  * Get server configuration
1536
1639
  *
1537
- * @return {*} {ServerConfig}
1640
+ * @return {*} {CatbeeServerConfig}
1538
1641
  */
1539
1642
  getConfig() {
1540
1643
  return this.config;
@@ -1608,7 +1711,7 @@ var ExpressServer = class {
1608
1711
  throw new Error(msg);
1609
1712
  }
1610
1713
  }
1611
- isBuiltServerConfig(config) {
1714
+ hasBuildMarker(config) {
1612
1715
  if (config?.[BUILD_MARKER]) {
1613
1716
  return true;
1614
1717
  }