@catbee/utils 1.0.5 → 1.1.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.
- package/build/index.cjs +256 -141
- package/build/index.d.ts +4254 -4236
- package/build/index.mjs +253 -141
- package/package.json +5 -5
package/build/index.cjs
CHANGED
|
@@ -26,29 +26,6 @@ var fsp__default = /*#__PURE__*/_interopDefault(fsp);
|
|
|
26
26
|
var express__default = /*#__PURE__*/_interopDefault(express);
|
|
27
27
|
var https__default = /*#__PURE__*/_interopDefault(https);
|
|
28
28
|
|
|
29
|
-
/*
|
|
30
|
-
* The MIT License
|
|
31
|
-
*
|
|
32
|
-
* Copyright (c) 2025 Catbee Technologies. https://catbee.npm.hprasath.com/license
|
|
33
|
-
*
|
|
34
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
35
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
36
|
-
* in the Software without restriction, including without limitation the rights
|
|
37
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
38
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
39
|
-
* furnished to do so, subject to the following conditions:
|
|
40
|
-
*
|
|
41
|
-
* The above copyright notice and this permission notice shall be included in all
|
|
42
|
-
* copies or substantial portions of the Software.
|
|
43
|
-
*
|
|
44
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
45
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
46
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
47
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
48
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
49
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
50
|
-
* SOFTWARE.
|
|
51
|
-
*/
|
|
52
29
|
var __defProp = Object.defineProperty;
|
|
53
30
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
54
31
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
@@ -972,16 +949,30 @@ function setValueByPath(obj, path3, value) {
|
|
|
972
949
|
if (!obj || typeof obj !== "object") return obj;
|
|
973
950
|
const parts = path3.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
974
951
|
if (parts.length === 0) return obj;
|
|
952
|
+
const forbiddenKeys = /* @__PURE__ */ new Set([
|
|
953
|
+
"__proto__",
|
|
954
|
+
"prototype",
|
|
955
|
+
"constructor"
|
|
956
|
+
]);
|
|
975
957
|
let current = obj;
|
|
976
958
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
977
959
|
const key = parts[i];
|
|
978
|
-
|
|
960
|
+
if (forbiddenKeys.has(key)) {
|
|
961
|
+
return obj;
|
|
962
|
+
}
|
|
963
|
+
const nextKey = parts[i + 1];
|
|
964
|
+
const isArrayIndex = !isNaN(Number(nextKey));
|
|
979
965
|
if (current[key] === void 0) {
|
|
980
|
-
current[key] = isArrayIndex ? [] :
|
|
966
|
+
current[key] = isArrayIndex ? [] : /* @__PURE__ */ Object.create(null);
|
|
967
|
+
} else if (typeof current[key] !== "object" || current[key] === null) {
|
|
968
|
+
current[key] = isArrayIndex ? [] : /* @__PURE__ */ Object.create(null);
|
|
981
969
|
}
|
|
982
970
|
current = current[key];
|
|
983
971
|
}
|
|
984
972
|
const finalKey = parts[parts.length - 1];
|
|
973
|
+
if (forbiddenKeys.has(finalKey)) {
|
|
974
|
+
return obj;
|
|
975
|
+
}
|
|
985
976
|
current[finalKey] = value;
|
|
986
977
|
return obj;
|
|
987
978
|
}
|
|
@@ -1057,48 +1048,21 @@ function getAllPaths(obj, parentPath = "") {
|
|
|
1057
1048
|
__name(getAllPaths, "getAllPaths");
|
|
1058
1049
|
|
|
1059
1050
|
// src/config.ts
|
|
1060
|
-
var
|
|
1051
|
+
var defaultCatbeeConfig = {
|
|
1061
1052
|
logger: {
|
|
1062
|
-
|
|
1063
|
-
* Logging level (e.g., 'info', 'debug', 'warn', 'error').
|
|
1064
|
-
*/
|
|
1065
|
-
level: Env.get("LOGGER_LEVEL", "info"),
|
|
1066
|
-
/**
|
|
1067
|
-
* Name of the logger instance (defaults to npm package name).
|
|
1068
|
-
*/
|
|
1053
|
+
level: Env.get("LOGGER_LEVEL", Env.isDev() ? "debug" : "info"),
|
|
1069
1054
|
name: Env.get("LOGGER_NAME", Env.get("npm_package_name", "@catbee/utils")),
|
|
1070
|
-
/**
|
|
1071
|
-
* Enables pretty-print logging in development.
|
|
1072
|
-
* Has no effect in production.
|
|
1073
|
-
*/
|
|
1074
1055
|
pretty: Env.getBoolean("LOGGER_PRETTY", true),
|
|
1075
|
-
/**
|
|
1076
|
-
* Enables colorized output for pretty-print (default: true)
|
|
1077
|
-
*/
|
|
1078
1056
|
colorize: Env.getBoolean("LOGGER_PRETTY_COLORIZE", true),
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1057
|
+
singleLine: Env.getBoolean("LOGGER_PRETTY_SINGLE_LINE", false),
|
|
1058
|
+
dir: Env.getPath("LOGGER_DIR", "", {
|
|
1059
|
+
mustExist: false
|
|
1060
|
+
})
|
|
1083
1061
|
},
|
|
1084
1062
|
cache: {
|
|
1085
|
-
/**
|
|
1086
|
-
* Default TTL (time to live) for cache entries in seconds
|
|
1087
|
-
*/
|
|
1088
1063
|
defaultTtl: Env.getNumber("CACHE_DEFAULT_TTL_SECONDS", 3600) * 1e3
|
|
1089
1064
|
},
|
|
1090
1065
|
server: {
|
|
1091
|
-
/**
|
|
1092
|
-
* Skip healthz endpoint even if health checks are configured
|
|
1093
|
-
* Default: false
|
|
1094
|
-
* Set to true to return 200 OK for /healthz without checks
|
|
1095
|
-
* Useful in environments where a simple liveness probe is needed
|
|
1096
|
-
* without performing actual health checks
|
|
1097
|
-
* Example: Kubernetes liveness probe
|
|
1098
|
-
* Note: This does not disable the health check functionality itself
|
|
1099
|
-
* Health checks can still be performed programmatically
|
|
1100
|
-
* or via other endpoints if needed
|
|
1101
|
-
*/
|
|
1102
1066
|
skipHealthz: Env.getBoolean("SERVER_SKIP_HEALTHZ", false)
|
|
1103
1067
|
}
|
|
1104
1068
|
};
|
|
@@ -1176,11 +1140,11 @@ var defaultServerConfig = {
|
|
|
1176
1140
|
}
|
|
1177
1141
|
};
|
|
1178
1142
|
function setConfig(value) {
|
|
1179
|
-
deepObjMerge(
|
|
1143
|
+
deepObjMerge(defaultCatbeeConfig, value);
|
|
1180
1144
|
}
|
|
1181
1145
|
__name(setConfig, "setConfig");
|
|
1182
1146
|
function getConfig() {
|
|
1183
|
-
return
|
|
1147
|
+
return defaultCatbeeConfig;
|
|
1184
1148
|
}
|
|
1185
1149
|
__name(getConfig, "getConfig");
|
|
1186
1150
|
|
|
@@ -1617,27 +1581,66 @@ var defaultSensitiveFields = [
|
|
|
1617
1581
|
"password",
|
|
1618
1582
|
"secret",
|
|
1619
1583
|
"token",
|
|
1620
|
-
"apiKey",
|
|
1621
1584
|
"api_key",
|
|
1622
1585
|
"auth",
|
|
1586
|
+
"private_key",
|
|
1587
|
+
"public_key",
|
|
1623
1588
|
"jwt",
|
|
1624
1589
|
"access_token",
|
|
1625
|
-
"
|
|
1590
|
+
"refresh_token",
|
|
1626
1591
|
"session_token",
|
|
1627
|
-
"
|
|
1592
|
+
"csrf_token",
|
|
1593
|
+
"authorization",
|
|
1594
|
+
"bearer",
|
|
1595
|
+
"x-api-key",
|
|
1596
|
+
"x-auth-token",
|
|
1597
|
+
"x-access-token",
|
|
1598
|
+
"client_secret",
|
|
1599
|
+
"passphrase",
|
|
1600
|
+
"otp",
|
|
1601
|
+
"api_secret",
|
|
1602
|
+
"token_secret"
|
|
1628
1603
|
];
|
|
1629
|
-
var
|
|
1604
|
+
var defaultRedactPaths = [
|
|
1605
|
+
"req.authorization",
|
|
1606
|
+
"req.headers.authorization",
|
|
1607
|
+
"req.headers.cookie",
|
|
1608
|
+
'req.headers["x-api-key"]',
|
|
1609
|
+
'req.headers["x-auth-token"]',
|
|
1610
|
+
'req.headers["x-access-token"]',
|
|
1611
|
+
"req.body.password",
|
|
1612
|
+
"req.body.token",
|
|
1613
|
+
"req.body.secret",
|
|
1614
|
+
"req.query.token",
|
|
1615
|
+
"req.query.api_key",
|
|
1616
|
+
"req.query.apiKey",
|
|
1617
|
+
"res.authorization",
|
|
1618
|
+
"res.headers.authorization",
|
|
1619
|
+
'res.headers["set-cookie"]',
|
|
1620
|
+
"headers.authorization",
|
|
1621
|
+
"headers.cookies",
|
|
1622
|
+
'headers["set-cookie"]',
|
|
1623
|
+
'headers["x-api-key"]',
|
|
1624
|
+
'headers["x-auth-token"]',
|
|
1625
|
+
'headers["x-access-token"]',
|
|
1626
|
+
"url",
|
|
1627
|
+
"uri",
|
|
1628
|
+
"href",
|
|
1629
|
+
"redirect_uri",
|
|
1630
|
+
"redirectUri"
|
|
1631
|
+
];
|
|
1632
|
+
var globalRedactCensor = /* @__PURE__ */ __name((value, path3, sensitiveFields = getExpandedSensitiveFields()) => {
|
|
1630
1633
|
if (typeof value !== "string") return "***";
|
|
1631
|
-
const lowerPath = path3.map((p) => p.toLowerCase());
|
|
1634
|
+
const lowerPath = path3.filter((p) => typeof p === "string").map((p) => p.toLowerCase());
|
|
1632
1635
|
const lowerSensitiveFields = sensitiveFields.map((f) => f.toLowerCase());
|
|
1633
1636
|
if (lowerPath.some((p) => lowerSensitiveFields.includes(p))) return "***";
|
|
1634
|
-
if (lowerPath[0] === "url") {
|
|
1637
|
+
if (lowerPath[0] === "url" || lowerPath[0] === "uri" || lowerPath[0] === "href" || lowerPath.includes("redirect_uri") || lowerPath.includes("redirecturi")) {
|
|
1635
1638
|
return value.replace(new RegExp(`([?&](${lowerSensitiveFields.join("|")})=)[^&#]*`, "gi"), "$1***");
|
|
1636
1639
|
}
|
|
1637
1640
|
if (lowerPath.some((p) => p.includes("authorization") || p.includes("auth"))) {
|
|
1638
1641
|
return value.replace(/^(\S+)\s+.+$/, "$1 ***") || "***";
|
|
1639
1642
|
}
|
|
1640
|
-
if (lowerPath.some((
|
|
1643
|
+
if (lowerPath.some((p) => lowerSensitiveFields.some((f) => p.includes(f)))) {
|
|
1641
1644
|
return "***";
|
|
1642
1645
|
}
|
|
1643
1646
|
if (path3.length > 0 && ![
|
|
@@ -1663,34 +1666,44 @@ function redact(value, path3, sensitiveFields) {
|
|
|
1663
1666
|
__name(redact, "redact");
|
|
1664
1667
|
function addRedactFields(fields) {
|
|
1665
1668
|
const prev = globalRedactCensor;
|
|
1666
|
-
globalRedactCensor = /* @__PURE__ */ __name((value, path3, sensitiveFields =
|
|
1669
|
+
globalRedactCensor = /* @__PURE__ */ __name((value, path3, sensitiveFields = getExpandedSensitiveFields()) => prev(value, path3, [
|
|
1667
1670
|
...sensitiveFields || [],
|
|
1668
1671
|
...fields
|
|
1669
1672
|
]), "globalRedactCensor");
|
|
1673
|
+
cachedExpandedFields = null;
|
|
1670
1674
|
}
|
|
1671
1675
|
__name(addRedactFields, "addRedactFields");
|
|
1676
|
+
var cachedExpandedFields = null;
|
|
1677
|
+
function getExpandedSensitiveFields() {
|
|
1678
|
+
if (!cachedExpandedFields) {
|
|
1679
|
+
cachedExpandedFields = expandSensitiveFields(defaultSensitiveFields);
|
|
1680
|
+
}
|
|
1681
|
+
return cachedExpandedFields;
|
|
1682
|
+
}
|
|
1683
|
+
__name(getExpandedSensitiveFields, "getExpandedSensitiveFields");
|
|
1672
1684
|
function setSensitiveFields(fields) {
|
|
1673
1685
|
defaultSensitiveFields.splice(0, defaultSensitiveFields.length, ...fields);
|
|
1686
|
+
cachedExpandedFields = null;
|
|
1674
1687
|
}
|
|
1675
1688
|
__name(setSensitiveFields, "setSensitiveFields");
|
|
1676
1689
|
function addSensitiveFields(fields) {
|
|
1677
1690
|
defaultSensitiveFields.push(...fields);
|
|
1691
|
+
cachedExpandedFields = null;
|
|
1678
1692
|
}
|
|
1679
1693
|
__name(addSensitiveFields, "addSensitiveFields");
|
|
1680
1694
|
var _globalThis = typeof globalThis === "object" ? globalThis : global;
|
|
1681
1695
|
var _global = _globalThis;
|
|
1682
1696
|
function setupLogger(isGlobal = true) {
|
|
1697
|
+
const sensitiveFields = getExpandedSensitiveFields();
|
|
1698
|
+
const paths = /* @__PURE__ */ new Set([
|
|
1699
|
+
...defaultRedactPaths,
|
|
1700
|
+
...sensitiveFields.flatMap((field) => generateDeepPaths(field, 2))
|
|
1701
|
+
]);
|
|
1683
1702
|
const logParams = {
|
|
1684
|
-
name:
|
|
1685
|
-
level:
|
|
1703
|
+
name: defaultCatbeeConfig.logger?.name || "@catbee/utils",
|
|
1704
|
+
level: defaultCatbeeConfig.logger?.level || "info",
|
|
1686
1705
|
redact: {
|
|
1687
|
-
paths:
|
|
1688
|
-
"req.authorization",
|
|
1689
|
-
"res.authorization",
|
|
1690
|
-
"url",
|
|
1691
|
-
"headers.authorization",
|
|
1692
|
-
"headers.cookies"
|
|
1693
|
-
],
|
|
1706
|
+
paths: Array.from(paths),
|
|
1694
1707
|
censor: /* @__PURE__ */ __name((value, path3) => redact(value, path3), "censor")
|
|
1695
1708
|
},
|
|
1696
1709
|
serializers: {
|
|
@@ -1703,64 +1716,147 @@ function setupLogger(isGlobal = true) {
|
|
|
1703
1716
|
},
|
|
1704
1717
|
timestamp: pino.stdTimeFunctions.isoTime
|
|
1705
1718
|
};
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1719
|
+
let logger;
|
|
1720
|
+
const logDir = defaultCatbeeConfig.logger?.dir?.trim();
|
|
1721
|
+
const hasFileLogging = Boolean(logDir);
|
|
1722
|
+
if (hasFileLogging && defaultCatbeeConfig.logger?.pretty) {
|
|
1723
|
+
logger = pino__default.default(logParams, pino__default.default.transport({
|
|
1724
|
+
targets: [
|
|
1725
|
+
{
|
|
1726
|
+
target: "pino-pretty",
|
|
1727
|
+
level: defaultCatbeeConfig.logger?.level ?? "info",
|
|
1728
|
+
options: {
|
|
1729
|
+
colorize: defaultCatbeeConfig.logger?.colorize,
|
|
1730
|
+
translateTime: "SYS:standard",
|
|
1731
|
+
ignore: "pid,hostname",
|
|
1732
|
+
singleLine: defaultCatbeeConfig.logger?.singleLine,
|
|
1733
|
+
levelFirst: true
|
|
1734
|
+
}
|
|
1735
|
+
},
|
|
1736
|
+
{
|
|
1737
|
+
target: "pino/file",
|
|
1738
|
+
level: defaultCatbeeConfig.logger?.level ?? "info",
|
|
1739
|
+
options: {
|
|
1740
|
+
destination: `${logDir}/app.log`,
|
|
1741
|
+
mkdir: true
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
]
|
|
1745
|
+
}));
|
|
1746
|
+
} else if (hasFileLogging) {
|
|
1747
|
+
logger = pino__default.default(logParams, pino__default.default.transport({
|
|
1748
|
+
target: "pino/file",
|
|
1749
|
+
options: {
|
|
1750
|
+
destination: `${logDir}/app.log`,
|
|
1751
|
+
mkdir: true
|
|
1752
|
+
}
|
|
1753
|
+
}));
|
|
1754
|
+
} else if (defaultCatbeeConfig.logger?.pretty) {
|
|
1755
|
+
logger = pino__default.default(logParams, pino__default.default.transport({
|
|
1756
|
+
target: "pino-pretty",
|
|
1757
|
+
options: {
|
|
1758
|
+
colorize: defaultCatbeeConfig.logger?.colorize,
|
|
1759
|
+
translateTime: "SYS:standard",
|
|
1760
|
+
ignore: "pid,hostname",
|
|
1761
|
+
singleLine: defaultCatbeeConfig.logger?.singleLine,
|
|
1762
|
+
levelFirst: true
|
|
1763
|
+
}
|
|
1764
|
+
}));
|
|
1765
|
+
} else {
|
|
1766
|
+
logger = pino__default.default(logParams);
|
|
1767
|
+
}
|
|
1716
1768
|
if (isGlobal) {
|
|
1717
|
-
_global[GLOBAL_LOGGER_KEY] =
|
|
1718
|
-
_global[GLOBAL_LOGGER_KEY]?.debug(
|
|
1769
|
+
_global[GLOBAL_LOGGER_KEY] = logger;
|
|
1770
|
+
_global[GLOBAL_LOGGER_KEY]?.debug({
|
|
1771
|
+
logDir: logDir || "none"
|
|
1772
|
+
}, "Logger initialized");
|
|
1719
1773
|
}
|
|
1720
|
-
return
|
|
1774
|
+
return logger;
|
|
1721
1775
|
}
|
|
1722
1776
|
__name(setupLogger, "setupLogger");
|
|
1723
1777
|
function getLogger(newInstance = false) {
|
|
1724
1778
|
if (newInstance) {
|
|
1725
1779
|
return setupLogger(false);
|
|
1726
1780
|
}
|
|
1727
|
-
const
|
|
1728
|
-
if (
|
|
1781
|
+
const logger = ContextStore.get(StoreKeys.LOGGER);
|
|
1782
|
+
if (logger) return logger;
|
|
1729
1783
|
if (!_global[GLOBAL_LOGGER_KEY]) {
|
|
1730
1784
|
setupLogger();
|
|
1731
1785
|
}
|
|
1732
1786
|
return _global[GLOBAL_LOGGER_KEY];
|
|
1733
1787
|
}
|
|
1734
1788
|
__name(getLogger, "getLogger");
|
|
1735
|
-
var logger = getLogger(false);
|
|
1736
1789
|
function createChildLogger(bindings, parentLogger) {
|
|
1737
|
-
const
|
|
1738
|
-
return
|
|
1790
|
+
const logger = parentLogger || getLogger();
|
|
1791
|
+
return logger.child(bindings);
|
|
1739
1792
|
}
|
|
1740
1793
|
__name(createChildLogger, "createChildLogger");
|
|
1741
1794
|
function createRequestLogger(requestId2, additionalContext = {}) {
|
|
1742
|
-
const
|
|
1795
|
+
const logger = createChildLogger({
|
|
1743
1796
|
requestId: requestId2,
|
|
1744
1797
|
...additionalContext
|
|
1745
1798
|
});
|
|
1746
1799
|
try {
|
|
1747
|
-
ContextStore.set(StoreKeys.LOGGER,
|
|
1800
|
+
ContextStore.set(StoreKeys.LOGGER, logger);
|
|
1748
1801
|
} catch {
|
|
1749
|
-
|
|
1802
|
+
logger.debug("Failed to store logger in context - AsyncLocalStorage not initialized");
|
|
1750
1803
|
}
|
|
1751
|
-
return
|
|
1804
|
+
return logger;
|
|
1752
1805
|
}
|
|
1753
1806
|
__name(createRequestLogger, "createRequestLogger");
|
|
1754
1807
|
function logError(error, message, context) {
|
|
1755
|
-
const
|
|
1808
|
+
const logger = getLogger();
|
|
1756
1809
|
const errObj = error instanceof Error ? error : new Error(String(error));
|
|
1757
1810
|
const logContext = {
|
|
1758
1811
|
...context,
|
|
1759
1812
|
error: errObj
|
|
1760
1813
|
};
|
|
1761
|
-
|
|
1814
|
+
logger.error(logContext, message || errObj.message);
|
|
1762
1815
|
}
|
|
1763
1816
|
__name(logError, "logError");
|
|
1817
|
+
function expandSensitiveFields(fields) {
|
|
1818
|
+
const set = /* @__PURE__ */ new Set();
|
|
1819
|
+
for (const field of fields) {
|
|
1820
|
+
for (const v of expandSensitiveField(field)) {
|
|
1821
|
+
set.add(v);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
return Array.from(set);
|
|
1825
|
+
}
|
|
1826
|
+
__name(expandSensitiveFields, "expandSensitiveFields");
|
|
1827
|
+
function expandSensitiveField(field) {
|
|
1828
|
+
const parts = field.split(/[_-]/g).filter(Boolean);
|
|
1829
|
+
const camel = parts[0].toLowerCase() + parts.slice(1).map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase()).join("");
|
|
1830
|
+
const mergedLower = parts.join("").toLowerCase();
|
|
1831
|
+
const mergedUpper = parts.join("").toUpperCase();
|
|
1832
|
+
const kebab = parts.map((p) => p.toLowerCase()).join("-");
|
|
1833
|
+
const snakeLower = parts.map((p) => p.toLowerCase()).join("_");
|
|
1834
|
+
const snakeUpper = parts.map((p) => p.toUpperCase()).join("_");
|
|
1835
|
+
return Array.from(/* @__PURE__ */ new Set([
|
|
1836
|
+
field,
|
|
1837
|
+
camel,
|
|
1838
|
+
mergedLower,
|
|
1839
|
+
mergedUpper,
|
|
1840
|
+
kebab,
|
|
1841
|
+
snakeLower,
|
|
1842
|
+
snakeUpper
|
|
1843
|
+
]));
|
|
1844
|
+
}
|
|
1845
|
+
__name(expandSensitiveField, "expandSensitiveField");
|
|
1846
|
+
function generateDeepPaths(field, depth) {
|
|
1847
|
+
const set = /* @__PURE__ */ new Set([
|
|
1848
|
+
field
|
|
1849
|
+
]);
|
|
1850
|
+
let prefix = "";
|
|
1851
|
+
for (let i = 1; i <= depth; i++) {
|
|
1852
|
+
prefix = prefix ? `${prefix}.*` : "*";
|
|
1853
|
+
set.add(`${prefix}.${field}`);
|
|
1854
|
+
}
|
|
1855
|
+
return [
|
|
1856
|
+
...set
|
|
1857
|
+
];
|
|
1858
|
+
}
|
|
1859
|
+
__name(generateDeepPaths, "generateDeepPaths");
|
|
1764
1860
|
|
|
1765
1861
|
// src/utils/async.utils.ts
|
|
1766
1862
|
function sleep(ms) {
|
|
@@ -2140,7 +2236,7 @@ var TTLCache = class {
|
|
|
2140
2236
|
* @param options - Configuration options for the cache
|
|
2141
2237
|
*/
|
|
2142
2238
|
constructor(options = {}) {
|
|
2143
|
-
this.ttlMs = options.ttlMs ??
|
|
2239
|
+
this.ttlMs = options.ttlMs ?? defaultCatbeeConfig.cache.defaultTtl;
|
|
2144
2240
|
this.maxSize = options.maxSize;
|
|
2145
2241
|
const autoCleanupMs = options.autoCleanupMs;
|
|
2146
2242
|
if (autoCleanupMs && autoCleanupMs > 0) {
|
|
@@ -3751,7 +3847,7 @@ function Timeout(ms) {
|
|
|
3751
3847
|
__name(Timeout, "Timeout");
|
|
3752
3848
|
function Log(options) {
|
|
3753
3849
|
return (target, propertyKey, _descriptor) => {
|
|
3754
|
-
const
|
|
3850
|
+
const config = {
|
|
3755
3851
|
logEntry: true,
|
|
3756
3852
|
logExit: true,
|
|
3757
3853
|
logBody: false,
|
|
@@ -3760,9 +3856,9 @@ function Log(options) {
|
|
|
3760
3856
|
...options
|
|
3761
3857
|
};
|
|
3762
3858
|
if (typeof propertyKey === "undefined") {
|
|
3763
|
-
Reflect.defineMetadata(LOG_KEY,
|
|
3859
|
+
Reflect.defineMetadata(LOG_KEY, config, target);
|
|
3764
3860
|
} else {
|
|
3765
|
-
Reflect.defineMetadata(LOG_KEY,
|
|
3861
|
+
Reflect.defineMetadata(LOG_KEY, config, target, propertyKey);
|
|
3766
3862
|
}
|
|
3767
3863
|
};
|
|
3768
3864
|
}
|
|
@@ -3872,7 +3968,7 @@ function registerControllers(router, controllers) {
|
|
|
3872
3968
|
res.setHeader("Cache-Control", `public, max-age=${cache.ttlSeconds}`);
|
|
3873
3969
|
}
|
|
3874
3970
|
if (logConfig?.logEntry) {
|
|
3875
|
-
const
|
|
3971
|
+
const logger = getLogger();
|
|
3876
3972
|
const logData = {
|
|
3877
3973
|
method: req.method,
|
|
3878
3974
|
url: req.originalUrl || req.url,
|
|
@@ -3883,7 +3979,7 @@ function registerControllers(router, controllers) {
|
|
|
3883
3979
|
logData.query = req.query;
|
|
3884
3980
|
}
|
|
3885
3981
|
if (logConfig.logBody) logData.body = req.body;
|
|
3886
|
-
|
|
3982
|
+
logger.info({
|
|
3887
3983
|
entry: logData
|
|
3888
3984
|
}, "Route Entry:");
|
|
3889
3985
|
}
|
|
@@ -3961,7 +4057,7 @@ function registerControllers(router, controllers) {
|
|
|
3961
4057
|
res.json(awaited);
|
|
3962
4058
|
}
|
|
3963
4059
|
if (logConfig?.logExit) {
|
|
3964
|
-
const
|
|
4060
|
+
const logger = getLogger();
|
|
3965
4061
|
const logData = {
|
|
3966
4062
|
method: req.method,
|
|
3967
4063
|
url: req.originalUrl || req.url,
|
|
@@ -3969,7 +4065,7 @@ function registerControllers(router, controllers) {
|
|
|
3969
4065
|
duration: `${Date.now() - req.startTime}ms`
|
|
3970
4066
|
};
|
|
3971
4067
|
if (logConfig.logResponse) logData.response = awaited;
|
|
3972
|
-
|
|
4068
|
+
logger.info({
|
|
3973
4069
|
exit: logData
|
|
3974
4070
|
}, "Route Exit:");
|
|
3975
4071
|
}
|
|
@@ -4840,36 +4936,36 @@ function timeSync(fn, options = {}) {
|
|
|
4840
4936
|
label
|
|
4841
4937
|
};
|
|
4842
4938
|
if (log) {
|
|
4843
|
-
const
|
|
4939
|
+
const logger = getLogger();
|
|
4844
4940
|
const message = `${label} completed in ${durationMs.toFixed(2)}ms`;
|
|
4845
4941
|
switch (logLevel) {
|
|
4846
4942
|
case "trace":
|
|
4847
|
-
|
|
4943
|
+
logger.trace({
|
|
4848
4944
|
timing
|
|
4849
4945
|
}, message);
|
|
4850
4946
|
break;
|
|
4851
4947
|
case "debug":
|
|
4852
|
-
|
|
4948
|
+
logger.debug({
|
|
4853
4949
|
timing
|
|
4854
4950
|
}, message);
|
|
4855
4951
|
break;
|
|
4856
4952
|
case "info":
|
|
4857
|
-
|
|
4953
|
+
logger.info({
|
|
4858
4954
|
timing
|
|
4859
4955
|
}, message);
|
|
4860
4956
|
break;
|
|
4861
4957
|
case "warn":
|
|
4862
|
-
|
|
4958
|
+
logger.warn({
|
|
4863
4959
|
timing
|
|
4864
4960
|
}, message);
|
|
4865
4961
|
break;
|
|
4866
4962
|
case "error":
|
|
4867
|
-
|
|
4963
|
+
logger.error({
|
|
4868
4964
|
timing
|
|
4869
4965
|
}, message);
|
|
4870
4966
|
break;
|
|
4871
4967
|
default:
|
|
4872
|
-
|
|
4968
|
+
logger.debug({
|
|
4873
4969
|
timing
|
|
4874
4970
|
}, message);
|
|
4875
4971
|
break;
|
|
@@ -4896,36 +4992,36 @@ async function timeAsync(fn, options = {}) {
|
|
|
4896
4992
|
label
|
|
4897
4993
|
};
|
|
4898
4994
|
if (log) {
|
|
4899
|
-
const
|
|
4995
|
+
const logger = getLogger();
|
|
4900
4996
|
const message = `${label} completed in ${durationMs.toFixed(2)}ms`;
|
|
4901
4997
|
switch (logLevel) {
|
|
4902
4998
|
case "trace":
|
|
4903
|
-
|
|
4999
|
+
logger.trace({
|
|
4904
5000
|
timing
|
|
4905
5001
|
}, message);
|
|
4906
5002
|
break;
|
|
4907
5003
|
case "debug":
|
|
4908
|
-
|
|
5004
|
+
logger.debug({
|
|
4909
5005
|
timing
|
|
4910
5006
|
}, message);
|
|
4911
5007
|
break;
|
|
4912
5008
|
case "info":
|
|
4913
|
-
|
|
5009
|
+
logger.info({
|
|
4914
5010
|
timing
|
|
4915
5011
|
}, message);
|
|
4916
5012
|
break;
|
|
4917
5013
|
case "warn":
|
|
4918
|
-
|
|
5014
|
+
logger.warn({
|
|
4919
5015
|
timing
|
|
4920
5016
|
}, message);
|
|
4921
5017
|
break;
|
|
4922
5018
|
case "error":
|
|
4923
|
-
|
|
5019
|
+
logger.error({
|
|
4924
5020
|
timing
|
|
4925
5021
|
}, message);
|
|
4926
5022
|
break;
|
|
4927
5023
|
default:
|
|
4928
|
-
|
|
5024
|
+
logger.debug({
|
|
4929
5025
|
timing
|
|
4930
5026
|
}, message);
|
|
4931
5027
|
break;
|
|
@@ -5596,10 +5692,26 @@ function isPort(value) {
|
|
|
5596
5692
|
}
|
|
5597
5693
|
__name(isPort, "isPort");
|
|
5598
5694
|
function isEmail(str) {
|
|
5599
|
-
if (
|
|
5600
|
-
const
|
|
5695
|
+
if (typeof str !== "string" || str.length > 254) return false;
|
|
5696
|
+
const atIndex = str.indexOf("@");
|
|
5697
|
+
if (atIndex === -1 || atIndex !== str.lastIndexOf("@")) return false;
|
|
5698
|
+
const local = str.slice(0, atIndex);
|
|
5699
|
+
const domain = str.slice(atIndex + 1);
|
|
5601
5700
|
if (!local || !domain) return false;
|
|
5602
|
-
|
|
5701
|
+
const dotAtom = /^[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*$/;
|
|
5702
|
+
const quotedLocal = /^"([\s\x21\x23-\x5B\x5D-\x7E]|\\[\x20-\x7E])*"$/;
|
|
5703
|
+
if (!dotAtom.test(local) && !quotedLocal.test(local)) return false;
|
|
5704
|
+
if (domain.includes("..")) return false;
|
|
5705
|
+
const labels = domain.split(".");
|
|
5706
|
+
if (labels.some((l) => !l.length)) return false;
|
|
5707
|
+
if (labels.length < 2) return false;
|
|
5708
|
+
const labelRegex = /^[A-Za-z0-9-]{1,63}$/;
|
|
5709
|
+
for (const label of labels) {
|
|
5710
|
+
if (!labelRegex.test(label)) return false;
|
|
5711
|
+
if (label.startsWith("-") || label.endsWith("-")) return false;
|
|
5712
|
+
}
|
|
5713
|
+
const tld = labels[labels.length - 1];
|
|
5714
|
+
if (!/^[A-Za-z]{2,63}$/.test(tld)) return false;
|
|
5603
5715
|
return true;
|
|
5604
5716
|
}
|
|
5605
5717
|
__name(isEmail, "isEmail");
|
|
@@ -6343,12 +6455,12 @@ var ServerConfigBuilder = class {
|
|
|
6343
6455
|
* ```
|
|
6344
6456
|
*/
|
|
6345
6457
|
build() {
|
|
6346
|
-
const
|
|
6347
|
-
if (
|
|
6458
|
+
const config = deepObjMerge({}, defaultServerConfig, this.config);
|
|
6459
|
+
if (config.openApi?.enable && !config.openApi.filePath) {
|
|
6348
6460
|
throw new Error("OpenAPI is enabled but no filePath is specified");
|
|
6349
6461
|
}
|
|
6350
6462
|
return Object.freeze({
|
|
6351
|
-
...
|
|
6463
|
+
...config,
|
|
6352
6464
|
[BUILD_MARKER]: true
|
|
6353
6465
|
});
|
|
6354
6466
|
}
|
|
@@ -6419,11 +6531,11 @@ var ExpressServer = class _ExpressServer {
|
|
|
6419
6531
|
* - Health checks
|
|
6420
6532
|
* - Request tracing
|
|
6421
6533
|
*/
|
|
6422
|
-
constructor(
|
|
6423
|
-
if (_ExpressServer.isBuiltServerConfig(
|
|
6424
|
-
this.config =
|
|
6534
|
+
constructor(config, hooks = {}) {
|
|
6535
|
+
if (_ExpressServer.isBuiltServerConfig(config)) {
|
|
6536
|
+
this.config = config;
|
|
6425
6537
|
} else {
|
|
6426
|
-
this.config = deepObjMerge({}, defaultServerConfig,
|
|
6538
|
+
this.config = deepObjMerge({}, defaultServerConfig, config);
|
|
6427
6539
|
}
|
|
6428
6540
|
if (!isPort(this.config.port)) {
|
|
6429
6541
|
getLogger().error(`Port must be a valid number between 1 and 65535, got: ${this.config.port}`);
|
|
@@ -6508,8 +6620,8 @@ var ExpressServer = class _ExpressServer {
|
|
|
6508
6620
|
prefix: `${safeAppName}_`
|
|
6509
6621
|
});
|
|
6510
6622
|
}
|
|
6511
|
-
if (
|
|
6512
|
-
this.healthChecks.push(...
|
|
6623
|
+
if (config.healthCheck?.checks) {
|
|
6624
|
+
this.healthChecks.push(...config.healthCheck.checks);
|
|
6513
6625
|
}
|
|
6514
6626
|
this.globalPrefix = this.normalizePath(this.config.globalPrefix ?? "", false);
|
|
6515
6627
|
this.hooks = hooks;
|
|
@@ -6666,14 +6778,14 @@ var ExpressServer = class _ExpressServer {
|
|
|
6666
6778
|
const skip = this.config.requestLogging?.ignorePaths?.some((path3) => req.path.startsWith(path3));
|
|
6667
6779
|
if (skip) return next();
|
|
6668
6780
|
}
|
|
6669
|
-
const
|
|
6781
|
+
const logger = getLogger();
|
|
6670
6782
|
const incomingRequestMetaData = {
|
|
6671
6783
|
requestId: req.id,
|
|
6672
6784
|
method: req.method,
|
|
6673
6785
|
url: req.originalUrl || req.url,
|
|
6674
6786
|
ip: req.ip
|
|
6675
6787
|
};
|
|
6676
|
-
|
|
6788
|
+
logger.info(incomingRequestMetaData, "Incoming Request");
|
|
6677
6789
|
next();
|
|
6678
6790
|
});
|
|
6679
6791
|
}
|
|
@@ -6818,7 +6930,7 @@ var ExpressServer = class _ExpressServer {
|
|
|
6818
6930
|
const healthCheckPath = this.normalizePath(this.config.healthCheck?.path || "/healthz", this.config.healthCheck?.withGlobalPrefix);
|
|
6819
6931
|
this.app.get(healthCheckPath, async (_req, res) => {
|
|
6820
6932
|
try {
|
|
6821
|
-
if (!this.healthChecks.length ||
|
|
6933
|
+
if (!this.healthChecks.length || defaultCatbeeConfig.server.skipHealthz) {
|
|
6822
6934
|
return res.status(HttpStatusCodes.OK).json(new SuccessResponse("OK"));
|
|
6823
6935
|
}
|
|
6824
6936
|
const checkResults = await Promise.allSettled(this.healthChecks.map(async ({ name, check }) => {
|
|
@@ -7268,8 +7380,8 @@ var ExpressServer = class _ExpressServer {
|
|
|
7268
7380
|
process.exit(1);
|
|
7269
7381
|
}
|
|
7270
7382
|
}
|
|
7271
|
-
static isBuiltServerConfig(
|
|
7272
|
-
if (
|
|
7383
|
+
static isBuiltServerConfig(config) {
|
|
7384
|
+
if (config[BUILD_MARKER]) {
|
|
7273
7385
|
return true;
|
|
7274
7386
|
}
|
|
7275
7387
|
return false;
|
|
@@ -7408,6 +7520,8 @@ exports.ensureEmptyDir = ensureEmptyDir;
|
|
|
7408
7520
|
exports.ensureType = ensureType;
|
|
7409
7521
|
exports.equalsIgnoreCase = equalsIgnoreCase;
|
|
7410
7522
|
exports.errorHandler = errorHandler;
|
|
7523
|
+
exports.expandSensitiveField = expandSensitiveField;
|
|
7524
|
+
exports.expandSensitiveFields = expandSensitiveFields;
|
|
7411
7525
|
exports.extractFilterParams = extractFilterParams;
|
|
7412
7526
|
exports.extractPaginationParams = extractPaginationParams;
|
|
7413
7527
|
exports.extractQueryParams = extractQueryParams;
|
|
@@ -7423,6 +7537,7 @@ exports.flattenObject = flattenObject;
|
|
|
7423
7537
|
exports.formatDate = formatDate;
|
|
7424
7538
|
exports.formatRelativeTime = formatRelativeTime;
|
|
7425
7539
|
exports.generateApiKey = generateApiKey;
|
|
7540
|
+
exports.generateDeepPaths = generateDeepPaths;
|
|
7426
7541
|
exports.generateRandomBytes = generateRandomBytes;
|
|
7427
7542
|
exports.generateRandomBytesAsString = generateRandomBytesAsString;
|
|
7428
7543
|
exports.getAllPaths = getAllPaths;
|
|
@@ -7431,6 +7546,7 @@ exports.getDirSize = getDirSize;
|
|
|
7431
7546
|
exports.getDirStats = getDirStats;
|
|
7432
7547
|
exports.getDomain = getDomain;
|
|
7433
7548
|
exports.getErrorMessage = getErrorMessage;
|
|
7549
|
+
exports.getExpandedSensitiveFields = getExpandedSensitiveFields;
|
|
7434
7550
|
exports.getExtension = getExtension;
|
|
7435
7551
|
exports.getFileSize = getFileSize;
|
|
7436
7552
|
exports.getFileStats = getFileStats;
|
|
@@ -7485,7 +7601,6 @@ exports.isValidUrl = isValidUrl;
|
|
|
7485
7601
|
exports.joinPaths = joinPaths;
|
|
7486
7602
|
exports.listFiles = listFiles;
|
|
7487
7603
|
exports.logError = logError;
|
|
7488
|
-
exports.logger = logger;
|
|
7489
7604
|
exports.mapObject = mapObject;
|
|
7490
7605
|
exports.mask = mask;
|
|
7491
7606
|
exports.matchesPattern = matchesPattern;
|