@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.mjs
CHANGED
|
@@ -14,29 +14,6 @@ import { URL as URL$1, URLSearchParams } from 'url';
|
|
|
14
14
|
import express from 'express';
|
|
15
15
|
import https from 'https';
|
|
16
16
|
|
|
17
|
-
/*
|
|
18
|
-
* The MIT License
|
|
19
|
-
*
|
|
20
|
-
* Copyright (c) 2025 Catbee Technologies. https://catbee.npm.hprasath.com/license
|
|
21
|
-
*
|
|
22
|
-
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
23
|
-
* of this software and associated documentation files (the "Software"), to deal
|
|
24
|
-
* in the Software without restriction, including without limitation the rights
|
|
25
|
-
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
26
|
-
* copies of the Software, and to permit persons to whom the Software is
|
|
27
|
-
* furnished to do so, subject to the following conditions:
|
|
28
|
-
*
|
|
29
|
-
* The above copyright notice and this permission notice shall be included in all
|
|
30
|
-
* copies or substantial portions of the Software.
|
|
31
|
-
*
|
|
32
|
-
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
33
|
-
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
34
|
-
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
35
|
-
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
36
|
-
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
37
|
-
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
38
|
-
* SOFTWARE.
|
|
39
|
-
*/
|
|
40
17
|
var __defProp = Object.defineProperty;
|
|
41
18
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
42
19
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
@@ -960,16 +937,30 @@ function setValueByPath(obj, path3, value) {
|
|
|
960
937
|
if (!obj || typeof obj !== "object") return obj;
|
|
961
938
|
const parts = path3.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
962
939
|
if (parts.length === 0) return obj;
|
|
940
|
+
const forbiddenKeys = /* @__PURE__ */ new Set([
|
|
941
|
+
"__proto__",
|
|
942
|
+
"prototype",
|
|
943
|
+
"constructor"
|
|
944
|
+
]);
|
|
963
945
|
let current = obj;
|
|
964
946
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
965
947
|
const key = parts[i];
|
|
966
|
-
|
|
948
|
+
if (forbiddenKeys.has(key)) {
|
|
949
|
+
return obj;
|
|
950
|
+
}
|
|
951
|
+
const nextKey = parts[i + 1];
|
|
952
|
+
const isArrayIndex = !isNaN(Number(nextKey));
|
|
967
953
|
if (current[key] === void 0) {
|
|
968
|
-
current[key] = isArrayIndex ? [] :
|
|
954
|
+
current[key] = isArrayIndex ? [] : /* @__PURE__ */ Object.create(null);
|
|
955
|
+
} else if (typeof current[key] !== "object" || current[key] === null) {
|
|
956
|
+
current[key] = isArrayIndex ? [] : /* @__PURE__ */ Object.create(null);
|
|
969
957
|
}
|
|
970
958
|
current = current[key];
|
|
971
959
|
}
|
|
972
960
|
const finalKey = parts[parts.length - 1];
|
|
961
|
+
if (forbiddenKeys.has(finalKey)) {
|
|
962
|
+
return obj;
|
|
963
|
+
}
|
|
973
964
|
current[finalKey] = value;
|
|
974
965
|
return obj;
|
|
975
966
|
}
|
|
@@ -1045,48 +1036,21 @@ function getAllPaths(obj, parentPath = "") {
|
|
|
1045
1036
|
__name(getAllPaths, "getAllPaths");
|
|
1046
1037
|
|
|
1047
1038
|
// src/config.ts
|
|
1048
|
-
var
|
|
1039
|
+
var defaultCatbeeConfig = {
|
|
1049
1040
|
logger: {
|
|
1050
|
-
|
|
1051
|
-
* Logging level (e.g., 'info', 'debug', 'warn', 'error').
|
|
1052
|
-
*/
|
|
1053
|
-
level: Env.get("LOGGER_LEVEL", "info"),
|
|
1054
|
-
/**
|
|
1055
|
-
* Name of the logger instance (defaults to npm package name).
|
|
1056
|
-
*/
|
|
1041
|
+
level: Env.get("LOGGER_LEVEL", Env.isDev() ? "debug" : "info"),
|
|
1057
1042
|
name: Env.get("LOGGER_NAME", Env.get("npm_package_name", "@catbee/utils")),
|
|
1058
|
-
/**
|
|
1059
|
-
* Enables pretty-print logging in development.
|
|
1060
|
-
* Has no effect in production.
|
|
1061
|
-
*/
|
|
1062
1043
|
pretty: Env.getBoolean("LOGGER_PRETTY", true),
|
|
1063
|
-
/**
|
|
1064
|
-
* Enables colorized output for pretty-print (default: true)
|
|
1065
|
-
*/
|
|
1066
1044
|
colorize: Env.getBoolean("LOGGER_PRETTY_COLORIZE", true),
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1045
|
+
singleLine: Env.getBoolean("LOGGER_PRETTY_SINGLE_LINE", false),
|
|
1046
|
+
dir: Env.getPath("LOGGER_DIR", "", {
|
|
1047
|
+
mustExist: false
|
|
1048
|
+
})
|
|
1071
1049
|
},
|
|
1072
1050
|
cache: {
|
|
1073
|
-
/**
|
|
1074
|
-
* Default TTL (time to live) for cache entries in seconds
|
|
1075
|
-
*/
|
|
1076
1051
|
defaultTtl: Env.getNumber("CACHE_DEFAULT_TTL_SECONDS", 3600) * 1e3
|
|
1077
1052
|
},
|
|
1078
1053
|
server: {
|
|
1079
|
-
/**
|
|
1080
|
-
* Skip healthz endpoint even if health checks are configured
|
|
1081
|
-
* Default: false
|
|
1082
|
-
* Set to true to return 200 OK for /healthz without checks
|
|
1083
|
-
* Useful in environments where a simple liveness probe is needed
|
|
1084
|
-
* without performing actual health checks
|
|
1085
|
-
* Example: Kubernetes liveness probe
|
|
1086
|
-
* Note: This does not disable the health check functionality itself
|
|
1087
|
-
* Health checks can still be performed programmatically
|
|
1088
|
-
* or via other endpoints if needed
|
|
1089
|
-
*/
|
|
1090
1054
|
skipHealthz: Env.getBoolean("SERVER_SKIP_HEALTHZ", false)
|
|
1091
1055
|
}
|
|
1092
1056
|
};
|
|
@@ -1164,11 +1128,11 @@ var defaultServerConfig = {
|
|
|
1164
1128
|
}
|
|
1165
1129
|
};
|
|
1166
1130
|
function setConfig(value) {
|
|
1167
|
-
deepObjMerge(
|
|
1131
|
+
deepObjMerge(defaultCatbeeConfig, value);
|
|
1168
1132
|
}
|
|
1169
1133
|
__name(setConfig, "setConfig");
|
|
1170
1134
|
function getConfig() {
|
|
1171
|
-
return
|
|
1135
|
+
return defaultCatbeeConfig;
|
|
1172
1136
|
}
|
|
1173
1137
|
__name(getConfig, "getConfig");
|
|
1174
1138
|
|
|
@@ -1605,27 +1569,66 @@ var defaultSensitiveFields = [
|
|
|
1605
1569
|
"password",
|
|
1606
1570
|
"secret",
|
|
1607
1571
|
"token",
|
|
1608
|
-
"apiKey",
|
|
1609
1572
|
"api_key",
|
|
1610
1573
|
"auth",
|
|
1574
|
+
"private_key",
|
|
1575
|
+
"public_key",
|
|
1611
1576
|
"jwt",
|
|
1612
1577
|
"access_token",
|
|
1613
|
-
"
|
|
1578
|
+
"refresh_token",
|
|
1614
1579
|
"session_token",
|
|
1615
|
-
"
|
|
1580
|
+
"csrf_token",
|
|
1581
|
+
"authorization",
|
|
1582
|
+
"bearer",
|
|
1583
|
+
"x-api-key",
|
|
1584
|
+
"x-auth-token",
|
|
1585
|
+
"x-access-token",
|
|
1586
|
+
"client_secret",
|
|
1587
|
+
"passphrase",
|
|
1588
|
+
"otp",
|
|
1589
|
+
"api_secret",
|
|
1590
|
+
"token_secret"
|
|
1616
1591
|
];
|
|
1617
|
-
var
|
|
1592
|
+
var defaultRedactPaths = [
|
|
1593
|
+
"req.authorization",
|
|
1594
|
+
"req.headers.authorization",
|
|
1595
|
+
"req.headers.cookie",
|
|
1596
|
+
'req.headers["x-api-key"]',
|
|
1597
|
+
'req.headers["x-auth-token"]',
|
|
1598
|
+
'req.headers["x-access-token"]',
|
|
1599
|
+
"req.body.password",
|
|
1600
|
+
"req.body.token",
|
|
1601
|
+
"req.body.secret",
|
|
1602
|
+
"req.query.token",
|
|
1603
|
+
"req.query.api_key",
|
|
1604
|
+
"req.query.apiKey",
|
|
1605
|
+
"res.authorization",
|
|
1606
|
+
"res.headers.authorization",
|
|
1607
|
+
'res.headers["set-cookie"]',
|
|
1608
|
+
"headers.authorization",
|
|
1609
|
+
"headers.cookies",
|
|
1610
|
+
'headers["set-cookie"]',
|
|
1611
|
+
'headers["x-api-key"]',
|
|
1612
|
+
'headers["x-auth-token"]',
|
|
1613
|
+
'headers["x-access-token"]',
|
|
1614
|
+
"url",
|
|
1615
|
+
"uri",
|
|
1616
|
+
"href",
|
|
1617
|
+
"redirect_uri",
|
|
1618
|
+
"redirectUri"
|
|
1619
|
+
];
|
|
1620
|
+
var globalRedactCensor = /* @__PURE__ */ __name((value, path3, sensitiveFields = getExpandedSensitiveFields()) => {
|
|
1618
1621
|
if (typeof value !== "string") return "***";
|
|
1619
|
-
const lowerPath = path3.map((p) => p.toLowerCase());
|
|
1622
|
+
const lowerPath = path3.filter((p) => typeof p === "string").map((p) => p.toLowerCase());
|
|
1620
1623
|
const lowerSensitiveFields = sensitiveFields.map((f) => f.toLowerCase());
|
|
1621
1624
|
if (lowerPath.some((p) => lowerSensitiveFields.includes(p))) return "***";
|
|
1622
|
-
if (lowerPath[0] === "url") {
|
|
1625
|
+
if (lowerPath[0] === "url" || lowerPath[0] === "uri" || lowerPath[0] === "href" || lowerPath.includes("redirect_uri") || lowerPath.includes("redirecturi")) {
|
|
1623
1626
|
return value.replace(new RegExp(`([?&](${lowerSensitiveFields.join("|")})=)[^&#]*`, "gi"), "$1***");
|
|
1624
1627
|
}
|
|
1625
1628
|
if (lowerPath.some((p) => p.includes("authorization") || p.includes("auth"))) {
|
|
1626
1629
|
return value.replace(/^(\S+)\s+.+$/, "$1 ***") || "***";
|
|
1627
1630
|
}
|
|
1628
|
-
if (lowerPath.some((
|
|
1631
|
+
if (lowerPath.some((p) => lowerSensitiveFields.some((f) => p.includes(f)))) {
|
|
1629
1632
|
return "***";
|
|
1630
1633
|
}
|
|
1631
1634
|
if (path3.length > 0 && ![
|
|
@@ -1651,34 +1654,44 @@ function redact(value, path3, sensitiveFields) {
|
|
|
1651
1654
|
__name(redact, "redact");
|
|
1652
1655
|
function addRedactFields(fields) {
|
|
1653
1656
|
const prev = globalRedactCensor;
|
|
1654
|
-
globalRedactCensor = /* @__PURE__ */ __name((value, path3, sensitiveFields =
|
|
1657
|
+
globalRedactCensor = /* @__PURE__ */ __name((value, path3, sensitiveFields = getExpandedSensitiveFields()) => prev(value, path3, [
|
|
1655
1658
|
...sensitiveFields || [],
|
|
1656
1659
|
...fields
|
|
1657
1660
|
]), "globalRedactCensor");
|
|
1661
|
+
cachedExpandedFields = null;
|
|
1658
1662
|
}
|
|
1659
1663
|
__name(addRedactFields, "addRedactFields");
|
|
1664
|
+
var cachedExpandedFields = null;
|
|
1665
|
+
function getExpandedSensitiveFields() {
|
|
1666
|
+
if (!cachedExpandedFields) {
|
|
1667
|
+
cachedExpandedFields = expandSensitiveFields(defaultSensitiveFields);
|
|
1668
|
+
}
|
|
1669
|
+
return cachedExpandedFields;
|
|
1670
|
+
}
|
|
1671
|
+
__name(getExpandedSensitiveFields, "getExpandedSensitiveFields");
|
|
1660
1672
|
function setSensitiveFields(fields) {
|
|
1661
1673
|
defaultSensitiveFields.splice(0, defaultSensitiveFields.length, ...fields);
|
|
1674
|
+
cachedExpandedFields = null;
|
|
1662
1675
|
}
|
|
1663
1676
|
__name(setSensitiveFields, "setSensitiveFields");
|
|
1664
1677
|
function addSensitiveFields(fields) {
|
|
1665
1678
|
defaultSensitiveFields.push(...fields);
|
|
1679
|
+
cachedExpandedFields = null;
|
|
1666
1680
|
}
|
|
1667
1681
|
__name(addSensitiveFields, "addSensitiveFields");
|
|
1668
1682
|
var _globalThis = typeof globalThis === "object" ? globalThis : global;
|
|
1669
1683
|
var _global = _globalThis;
|
|
1670
1684
|
function setupLogger(isGlobal = true) {
|
|
1685
|
+
const sensitiveFields = getExpandedSensitiveFields();
|
|
1686
|
+
const paths = /* @__PURE__ */ new Set([
|
|
1687
|
+
...defaultRedactPaths,
|
|
1688
|
+
...sensitiveFields.flatMap((field) => generateDeepPaths(field, 2))
|
|
1689
|
+
]);
|
|
1671
1690
|
const logParams = {
|
|
1672
|
-
name:
|
|
1673
|
-
level:
|
|
1691
|
+
name: defaultCatbeeConfig.logger?.name || "@catbee/utils",
|
|
1692
|
+
level: defaultCatbeeConfig.logger?.level || "info",
|
|
1674
1693
|
redact: {
|
|
1675
|
-
paths:
|
|
1676
|
-
"req.authorization",
|
|
1677
|
-
"res.authorization",
|
|
1678
|
-
"url",
|
|
1679
|
-
"headers.authorization",
|
|
1680
|
-
"headers.cookies"
|
|
1681
|
-
],
|
|
1694
|
+
paths: Array.from(paths),
|
|
1682
1695
|
censor: /* @__PURE__ */ __name((value, path3) => redact(value, path3), "censor")
|
|
1683
1696
|
},
|
|
1684
1697
|
serializers: {
|
|
@@ -1691,64 +1704,147 @@ function setupLogger(isGlobal = true) {
|
|
|
1691
1704
|
},
|
|
1692
1705
|
timestamp: stdTimeFunctions.isoTime
|
|
1693
1706
|
};
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1707
|
+
let logger;
|
|
1708
|
+
const logDir = defaultCatbeeConfig.logger?.dir?.trim();
|
|
1709
|
+
const hasFileLogging = Boolean(logDir);
|
|
1710
|
+
if (hasFileLogging && defaultCatbeeConfig.logger?.pretty) {
|
|
1711
|
+
logger = pino(logParams, pino.transport({
|
|
1712
|
+
targets: [
|
|
1713
|
+
{
|
|
1714
|
+
target: "pino-pretty",
|
|
1715
|
+
level: defaultCatbeeConfig.logger?.level ?? "info",
|
|
1716
|
+
options: {
|
|
1717
|
+
colorize: defaultCatbeeConfig.logger?.colorize,
|
|
1718
|
+
translateTime: "SYS:standard",
|
|
1719
|
+
ignore: "pid,hostname",
|
|
1720
|
+
singleLine: defaultCatbeeConfig.logger?.singleLine,
|
|
1721
|
+
levelFirst: true
|
|
1722
|
+
}
|
|
1723
|
+
},
|
|
1724
|
+
{
|
|
1725
|
+
target: "pino/file",
|
|
1726
|
+
level: defaultCatbeeConfig.logger?.level ?? "info",
|
|
1727
|
+
options: {
|
|
1728
|
+
destination: `${logDir}/app.log`,
|
|
1729
|
+
mkdir: true
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
]
|
|
1733
|
+
}));
|
|
1734
|
+
} else if (hasFileLogging) {
|
|
1735
|
+
logger = pino(logParams, pino.transport({
|
|
1736
|
+
target: "pino/file",
|
|
1737
|
+
options: {
|
|
1738
|
+
destination: `${logDir}/app.log`,
|
|
1739
|
+
mkdir: true
|
|
1740
|
+
}
|
|
1741
|
+
}));
|
|
1742
|
+
} else if (defaultCatbeeConfig.logger?.pretty) {
|
|
1743
|
+
logger = pino(logParams, pino.transport({
|
|
1744
|
+
target: "pino-pretty",
|
|
1745
|
+
options: {
|
|
1746
|
+
colorize: defaultCatbeeConfig.logger?.colorize,
|
|
1747
|
+
translateTime: "SYS:standard",
|
|
1748
|
+
ignore: "pid,hostname",
|
|
1749
|
+
singleLine: defaultCatbeeConfig.logger?.singleLine,
|
|
1750
|
+
levelFirst: true
|
|
1751
|
+
}
|
|
1752
|
+
}));
|
|
1753
|
+
} else {
|
|
1754
|
+
logger = pino(logParams);
|
|
1755
|
+
}
|
|
1704
1756
|
if (isGlobal) {
|
|
1705
|
-
_global[GLOBAL_LOGGER_KEY] =
|
|
1706
|
-
_global[GLOBAL_LOGGER_KEY]?.debug(
|
|
1757
|
+
_global[GLOBAL_LOGGER_KEY] = logger;
|
|
1758
|
+
_global[GLOBAL_LOGGER_KEY]?.debug({
|
|
1759
|
+
logDir: logDir || "none"
|
|
1760
|
+
}, "Logger initialized");
|
|
1707
1761
|
}
|
|
1708
|
-
return
|
|
1762
|
+
return logger;
|
|
1709
1763
|
}
|
|
1710
1764
|
__name(setupLogger, "setupLogger");
|
|
1711
1765
|
function getLogger(newInstance = false) {
|
|
1712
1766
|
if (newInstance) {
|
|
1713
1767
|
return setupLogger(false);
|
|
1714
1768
|
}
|
|
1715
|
-
const
|
|
1716
|
-
if (
|
|
1769
|
+
const logger = ContextStore.get(StoreKeys.LOGGER);
|
|
1770
|
+
if (logger) return logger;
|
|
1717
1771
|
if (!_global[GLOBAL_LOGGER_KEY]) {
|
|
1718
1772
|
setupLogger();
|
|
1719
1773
|
}
|
|
1720
1774
|
return _global[GLOBAL_LOGGER_KEY];
|
|
1721
1775
|
}
|
|
1722
1776
|
__name(getLogger, "getLogger");
|
|
1723
|
-
var logger = getLogger(false);
|
|
1724
1777
|
function createChildLogger(bindings, parentLogger) {
|
|
1725
|
-
const
|
|
1726
|
-
return
|
|
1778
|
+
const logger = parentLogger || getLogger();
|
|
1779
|
+
return logger.child(bindings);
|
|
1727
1780
|
}
|
|
1728
1781
|
__name(createChildLogger, "createChildLogger");
|
|
1729
1782
|
function createRequestLogger(requestId2, additionalContext = {}) {
|
|
1730
|
-
const
|
|
1783
|
+
const logger = createChildLogger({
|
|
1731
1784
|
requestId: requestId2,
|
|
1732
1785
|
...additionalContext
|
|
1733
1786
|
});
|
|
1734
1787
|
try {
|
|
1735
|
-
ContextStore.set(StoreKeys.LOGGER,
|
|
1788
|
+
ContextStore.set(StoreKeys.LOGGER, logger);
|
|
1736
1789
|
} catch {
|
|
1737
|
-
|
|
1790
|
+
logger.debug("Failed to store logger in context - AsyncLocalStorage not initialized");
|
|
1738
1791
|
}
|
|
1739
|
-
return
|
|
1792
|
+
return logger;
|
|
1740
1793
|
}
|
|
1741
1794
|
__name(createRequestLogger, "createRequestLogger");
|
|
1742
1795
|
function logError(error, message, context) {
|
|
1743
|
-
const
|
|
1796
|
+
const logger = getLogger();
|
|
1744
1797
|
const errObj = error instanceof Error ? error : new Error(String(error));
|
|
1745
1798
|
const logContext = {
|
|
1746
1799
|
...context,
|
|
1747
1800
|
error: errObj
|
|
1748
1801
|
};
|
|
1749
|
-
|
|
1802
|
+
logger.error(logContext, message || errObj.message);
|
|
1750
1803
|
}
|
|
1751
1804
|
__name(logError, "logError");
|
|
1805
|
+
function expandSensitiveFields(fields) {
|
|
1806
|
+
const set = /* @__PURE__ */ new Set();
|
|
1807
|
+
for (const field of fields) {
|
|
1808
|
+
for (const v of expandSensitiveField(field)) {
|
|
1809
|
+
set.add(v);
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
return Array.from(set);
|
|
1813
|
+
}
|
|
1814
|
+
__name(expandSensitiveFields, "expandSensitiveFields");
|
|
1815
|
+
function expandSensitiveField(field) {
|
|
1816
|
+
const parts = field.split(/[_-]/g).filter(Boolean);
|
|
1817
|
+
const camel = parts[0].toLowerCase() + parts.slice(1).map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase()).join("");
|
|
1818
|
+
const mergedLower = parts.join("").toLowerCase();
|
|
1819
|
+
const mergedUpper = parts.join("").toUpperCase();
|
|
1820
|
+
const kebab = parts.map((p) => p.toLowerCase()).join("-");
|
|
1821
|
+
const snakeLower = parts.map((p) => p.toLowerCase()).join("_");
|
|
1822
|
+
const snakeUpper = parts.map((p) => p.toUpperCase()).join("_");
|
|
1823
|
+
return Array.from(/* @__PURE__ */ new Set([
|
|
1824
|
+
field,
|
|
1825
|
+
camel,
|
|
1826
|
+
mergedLower,
|
|
1827
|
+
mergedUpper,
|
|
1828
|
+
kebab,
|
|
1829
|
+
snakeLower,
|
|
1830
|
+
snakeUpper
|
|
1831
|
+
]));
|
|
1832
|
+
}
|
|
1833
|
+
__name(expandSensitiveField, "expandSensitiveField");
|
|
1834
|
+
function generateDeepPaths(field, depth) {
|
|
1835
|
+
const set = /* @__PURE__ */ new Set([
|
|
1836
|
+
field
|
|
1837
|
+
]);
|
|
1838
|
+
let prefix = "";
|
|
1839
|
+
for (let i = 1; i <= depth; i++) {
|
|
1840
|
+
prefix = prefix ? `${prefix}.*` : "*";
|
|
1841
|
+
set.add(`${prefix}.${field}`);
|
|
1842
|
+
}
|
|
1843
|
+
return [
|
|
1844
|
+
...set
|
|
1845
|
+
];
|
|
1846
|
+
}
|
|
1847
|
+
__name(generateDeepPaths, "generateDeepPaths");
|
|
1752
1848
|
|
|
1753
1849
|
// src/utils/async.utils.ts
|
|
1754
1850
|
function sleep(ms) {
|
|
@@ -2128,7 +2224,7 @@ var TTLCache = class {
|
|
|
2128
2224
|
* @param options - Configuration options for the cache
|
|
2129
2225
|
*/
|
|
2130
2226
|
constructor(options = {}) {
|
|
2131
|
-
this.ttlMs = options.ttlMs ??
|
|
2227
|
+
this.ttlMs = options.ttlMs ?? defaultCatbeeConfig.cache.defaultTtl;
|
|
2132
2228
|
this.maxSize = options.maxSize;
|
|
2133
2229
|
const autoCleanupMs = options.autoCleanupMs;
|
|
2134
2230
|
if (autoCleanupMs && autoCleanupMs > 0) {
|
|
@@ -3739,7 +3835,7 @@ function Timeout(ms) {
|
|
|
3739
3835
|
__name(Timeout, "Timeout");
|
|
3740
3836
|
function Log(options) {
|
|
3741
3837
|
return (target, propertyKey, _descriptor) => {
|
|
3742
|
-
const
|
|
3838
|
+
const config = {
|
|
3743
3839
|
logEntry: true,
|
|
3744
3840
|
logExit: true,
|
|
3745
3841
|
logBody: false,
|
|
@@ -3748,9 +3844,9 @@ function Log(options) {
|
|
|
3748
3844
|
...options
|
|
3749
3845
|
};
|
|
3750
3846
|
if (typeof propertyKey === "undefined") {
|
|
3751
|
-
Reflect.defineMetadata(LOG_KEY,
|
|
3847
|
+
Reflect.defineMetadata(LOG_KEY, config, target);
|
|
3752
3848
|
} else {
|
|
3753
|
-
Reflect.defineMetadata(LOG_KEY,
|
|
3849
|
+
Reflect.defineMetadata(LOG_KEY, config, target, propertyKey);
|
|
3754
3850
|
}
|
|
3755
3851
|
};
|
|
3756
3852
|
}
|
|
@@ -3860,7 +3956,7 @@ function registerControllers(router, controllers) {
|
|
|
3860
3956
|
res.setHeader("Cache-Control", `public, max-age=${cache.ttlSeconds}`);
|
|
3861
3957
|
}
|
|
3862
3958
|
if (logConfig?.logEntry) {
|
|
3863
|
-
const
|
|
3959
|
+
const logger = getLogger();
|
|
3864
3960
|
const logData = {
|
|
3865
3961
|
method: req.method,
|
|
3866
3962
|
url: req.originalUrl || req.url,
|
|
@@ -3871,7 +3967,7 @@ function registerControllers(router, controllers) {
|
|
|
3871
3967
|
logData.query = req.query;
|
|
3872
3968
|
}
|
|
3873
3969
|
if (logConfig.logBody) logData.body = req.body;
|
|
3874
|
-
|
|
3970
|
+
logger.info({
|
|
3875
3971
|
entry: logData
|
|
3876
3972
|
}, "Route Entry:");
|
|
3877
3973
|
}
|
|
@@ -3949,7 +4045,7 @@ function registerControllers(router, controllers) {
|
|
|
3949
4045
|
res.json(awaited);
|
|
3950
4046
|
}
|
|
3951
4047
|
if (logConfig?.logExit) {
|
|
3952
|
-
const
|
|
4048
|
+
const logger = getLogger();
|
|
3953
4049
|
const logData = {
|
|
3954
4050
|
method: req.method,
|
|
3955
4051
|
url: req.originalUrl || req.url,
|
|
@@ -3957,7 +4053,7 @@ function registerControllers(router, controllers) {
|
|
|
3957
4053
|
duration: `${Date.now() - req.startTime}ms`
|
|
3958
4054
|
};
|
|
3959
4055
|
if (logConfig.logResponse) logData.response = awaited;
|
|
3960
|
-
|
|
4056
|
+
logger.info({
|
|
3961
4057
|
exit: logData
|
|
3962
4058
|
}, "Route Exit:");
|
|
3963
4059
|
}
|
|
@@ -4828,36 +4924,36 @@ function timeSync(fn, options = {}) {
|
|
|
4828
4924
|
label
|
|
4829
4925
|
};
|
|
4830
4926
|
if (log) {
|
|
4831
|
-
const
|
|
4927
|
+
const logger = getLogger();
|
|
4832
4928
|
const message = `${label} completed in ${durationMs.toFixed(2)}ms`;
|
|
4833
4929
|
switch (logLevel) {
|
|
4834
4930
|
case "trace":
|
|
4835
|
-
|
|
4931
|
+
logger.trace({
|
|
4836
4932
|
timing
|
|
4837
4933
|
}, message);
|
|
4838
4934
|
break;
|
|
4839
4935
|
case "debug":
|
|
4840
|
-
|
|
4936
|
+
logger.debug({
|
|
4841
4937
|
timing
|
|
4842
4938
|
}, message);
|
|
4843
4939
|
break;
|
|
4844
4940
|
case "info":
|
|
4845
|
-
|
|
4941
|
+
logger.info({
|
|
4846
4942
|
timing
|
|
4847
4943
|
}, message);
|
|
4848
4944
|
break;
|
|
4849
4945
|
case "warn":
|
|
4850
|
-
|
|
4946
|
+
logger.warn({
|
|
4851
4947
|
timing
|
|
4852
4948
|
}, message);
|
|
4853
4949
|
break;
|
|
4854
4950
|
case "error":
|
|
4855
|
-
|
|
4951
|
+
logger.error({
|
|
4856
4952
|
timing
|
|
4857
4953
|
}, message);
|
|
4858
4954
|
break;
|
|
4859
4955
|
default:
|
|
4860
|
-
|
|
4956
|
+
logger.debug({
|
|
4861
4957
|
timing
|
|
4862
4958
|
}, message);
|
|
4863
4959
|
break;
|
|
@@ -4884,36 +4980,36 @@ async function timeAsync(fn, options = {}) {
|
|
|
4884
4980
|
label
|
|
4885
4981
|
};
|
|
4886
4982
|
if (log) {
|
|
4887
|
-
const
|
|
4983
|
+
const logger = getLogger();
|
|
4888
4984
|
const message = `${label} completed in ${durationMs.toFixed(2)}ms`;
|
|
4889
4985
|
switch (logLevel) {
|
|
4890
4986
|
case "trace":
|
|
4891
|
-
|
|
4987
|
+
logger.trace({
|
|
4892
4988
|
timing
|
|
4893
4989
|
}, message);
|
|
4894
4990
|
break;
|
|
4895
4991
|
case "debug":
|
|
4896
|
-
|
|
4992
|
+
logger.debug({
|
|
4897
4993
|
timing
|
|
4898
4994
|
}, message);
|
|
4899
4995
|
break;
|
|
4900
4996
|
case "info":
|
|
4901
|
-
|
|
4997
|
+
logger.info({
|
|
4902
4998
|
timing
|
|
4903
4999
|
}, message);
|
|
4904
5000
|
break;
|
|
4905
5001
|
case "warn":
|
|
4906
|
-
|
|
5002
|
+
logger.warn({
|
|
4907
5003
|
timing
|
|
4908
5004
|
}, message);
|
|
4909
5005
|
break;
|
|
4910
5006
|
case "error":
|
|
4911
|
-
|
|
5007
|
+
logger.error({
|
|
4912
5008
|
timing
|
|
4913
5009
|
}, message);
|
|
4914
5010
|
break;
|
|
4915
5011
|
default:
|
|
4916
|
-
|
|
5012
|
+
logger.debug({
|
|
4917
5013
|
timing
|
|
4918
5014
|
}, message);
|
|
4919
5015
|
break;
|
|
@@ -5584,10 +5680,26 @@ function isPort(value) {
|
|
|
5584
5680
|
}
|
|
5585
5681
|
__name(isPort, "isPort");
|
|
5586
5682
|
function isEmail(str) {
|
|
5587
|
-
if (
|
|
5588
|
-
const
|
|
5683
|
+
if (typeof str !== "string" || str.length > 254) return false;
|
|
5684
|
+
const atIndex = str.indexOf("@");
|
|
5685
|
+
if (atIndex === -1 || atIndex !== str.lastIndexOf("@")) return false;
|
|
5686
|
+
const local = str.slice(0, atIndex);
|
|
5687
|
+
const domain = str.slice(atIndex + 1);
|
|
5589
5688
|
if (!local || !domain) return false;
|
|
5590
|
-
|
|
5689
|
+
const dotAtom = /^[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*$/;
|
|
5690
|
+
const quotedLocal = /^"([\s\x21\x23-\x5B\x5D-\x7E]|\\[\x20-\x7E])*"$/;
|
|
5691
|
+
if (!dotAtom.test(local) && !quotedLocal.test(local)) return false;
|
|
5692
|
+
if (domain.includes("..")) return false;
|
|
5693
|
+
const labels = domain.split(".");
|
|
5694
|
+
if (labels.some((l) => !l.length)) return false;
|
|
5695
|
+
if (labels.length < 2) return false;
|
|
5696
|
+
const labelRegex = /^[A-Za-z0-9-]{1,63}$/;
|
|
5697
|
+
for (const label of labels) {
|
|
5698
|
+
if (!labelRegex.test(label)) return false;
|
|
5699
|
+
if (label.startsWith("-") || label.endsWith("-")) return false;
|
|
5700
|
+
}
|
|
5701
|
+
const tld = labels[labels.length - 1];
|
|
5702
|
+
if (!/^[A-Za-z]{2,63}$/.test(tld)) return false;
|
|
5591
5703
|
return true;
|
|
5592
5704
|
}
|
|
5593
5705
|
__name(isEmail, "isEmail");
|
|
@@ -6331,12 +6443,12 @@ var ServerConfigBuilder = class {
|
|
|
6331
6443
|
* ```
|
|
6332
6444
|
*/
|
|
6333
6445
|
build() {
|
|
6334
|
-
const
|
|
6335
|
-
if (
|
|
6446
|
+
const config = deepObjMerge({}, defaultServerConfig, this.config);
|
|
6447
|
+
if (config.openApi?.enable && !config.openApi.filePath) {
|
|
6336
6448
|
throw new Error("OpenAPI is enabled but no filePath is specified");
|
|
6337
6449
|
}
|
|
6338
6450
|
return Object.freeze({
|
|
6339
|
-
...
|
|
6451
|
+
...config,
|
|
6340
6452
|
[BUILD_MARKER]: true
|
|
6341
6453
|
});
|
|
6342
6454
|
}
|
|
@@ -6407,11 +6519,11 @@ var ExpressServer = class _ExpressServer {
|
|
|
6407
6519
|
* - Health checks
|
|
6408
6520
|
* - Request tracing
|
|
6409
6521
|
*/
|
|
6410
|
-
constructor(
|
|
6411
|
-
if (_ExpressServer.isBuiltServerConfig(
|
|
6412
|
-
this.config =
|
|
6522
|
+
constructor(config, hooks = {}) {
|
|
6523
|
+
if (_ExpressServer.isBuiltServerConfig(config)) {
|
|
6524
|
+
this.config = config;
|
|
6413
6525
|
} else {
|
|
6414
|
-
this.config = deepObjMerge({}, defaultServerConfig,
|
|
6526
|
+
this.config = deepObjMerge({}, defaultServerConfig, config);
|
|
6415
6527
|
}
|
|
6416
6528
|
if (!isPort(this.config.port)) {
|
|
6417
6529
|
getLogger().error(`Port must be a valid number between 1 and 65535, got: ${this.config.port}`);
|
|
@@ -6496,8 +6608,8 @@ var ExpressServer = class _ExpressServer {
|
|
|
6496
6608
|
prefix: `${safeAppName}_`
|
|
6497
6609
|
});
|
|
6498
6610
|
}
|
|
6499
|
-
if (
|
|
6500
|
-
this.healthChecks.push(...
|
|
6611
|
+
if (config.healthCheck?.checks) {
|
|
6612
|
+
this.healthChecks.push(...config.healthCheck.checks);
|
|
6501
6613
|
}
|
|
6502
6614
|
this.globalPrefix = this.normalizePath(this.config.globalPrefix ?? "", false);
|
|
6503
6615
|
this.hooks = hooks;
|
|
@@ -6654,14 +6766,14 @@ var ExpressServer = class _ExpressServer {
|
|
|
6654
6766
|
const skip = this.config.requestLogging?.ignorePaths?.some((path3) => req.path.startsWith(path3));
|
|
6655
6767
|
if (skip) return next();
|
|
6656
6768
|
}
|
|
6657
|
-
const
|
|
6769
|
+
const logger = getLogger();
|
|
6658
6770
|
const incomingRequestMetaData = {
|
|
6659
6771
|
requestId: req.id,
|
|
6660
6772
|
method: req.method,
|
|
6661
6773
|
url: req.originalUrl || req.url,
|
|
6662
6774
|
ip: req.ip
|
|
6663
6775
|
};
|
|
6664
|
-
|
|
6776
|
+
logger.info(incomingRequestMetaData, "Incoming Request");
|
|
6665
6777
|
next();
|
|
6666
6778
|
});
|
|
6667
6779
|
}
|
|
@@ -6806,7 +6918,7 @@ var ExpressServer = class _ExpressServer {
|
|
|
6806
6918
|
const healthCheckPath = this.normalizePath(this.config.healthCheck?.path || "/healthz", this.config.healthCheck?.withGlobalPrefix);
|
|
6807
6919
|
this.app.get(healthCheckPath, async (_req, res) => {
|
|
6808
6920
|
try {
|
|
6809
|
-
if (!this.healthChecks.length ||
|
|
6921
|
+
if (!this.healthChecks.length || defaultCatbeeConfig.server.skipHealthz) {
|
|
6810
6922
|
return res.status(HttpStatusCodes.OK).json(new SuccessResponse("OK"));
|
|
6811
6923
|
}
|
|
6812
6924
|
const checkResults = await Promise.allSettled(this.healthChecks.map(async ({ name, check }) => {
|
|
@@ -7256,8 +7368,8 @@ var ExpressServer = class _ExpressServer {
|
|
|
7256
7368
|
process.exit(1);
|
|
7257
7369
|
}
|
|
7258
7370
|
}
|
|
7259
|
-
static isBuiltServerConfig(
|
|
7260
|
-
if (
|
|
7371
|
+
static isBuiltServerConfig(config) {
|
|
7372
|
+
if (config[BUILD_MARKER]) {
|
|
7261
7373
|
return true;
|
|
7262
7374
|
}
|
|
7263
7375
|
return false;
|
|
@@ -7271,4 +7383,4 @@ var ExpressServer = class _ExpressServer {
|
|
|
7271
7383
|
}
|
|
7272
7384
|
};
|
|
7273
7385
|
|
|
7274
|
-
export { After, BUILD_MARKER, BadGatewayException, BadRequestException, Before, Body, Cache, CircuitBreakerOpenError, CircuitBreakerState, ConflictException, Connect, ContentType, ContextStore, Controller, DIContainer, Delete, Env, Environment, ErrorResponse, ExpressServer, ForbiddenException, GatewayTimeoutException, Get, Head, Header, Headers, HttpCode, HttpError, HttpStatusCodes, Inject, Injectable, InsufficientStorageException, InternalServerErrorException, Log, MethodNotAllowedException, NoContentResponse, NotAcceptableException, NotFoundException, Options, PaginatedResponse, Param, Patch, PayloadTooLargeException, Post, Put, Query, RateLimit, Redirect, RedirectResponse, Req, ReqCookie, ReqHeader, ReqId, ReqLogger, RequestTimeoutException, Res, Roles, ServerConfigBuilder, ServiceUnavailableException, SortDirection, StoreKeys, SuccessResponse, TTLCache, Timeout, TooManyRequestsException, Trace, TypedContextKey, UnauthorizedException, UnprocessableEntityException, UnsupportedMediaTypeException, Use, Version, _globalThis, abortable, addRedactFields, addSensitiveFields, addToDate, appendQueryParams, appendTextFile, bufferToStream, capitalize, chunk, circuitBreaker, compact, copyDir, copyFile, countBy, countOccurrences, createBatchStream, createChildLogger, createDeferred, createDirectory, createErrorResponse, createFinalErrorResponse, createHttpError, createLineStream, createPaginatedResponse, createParamDecorator, createParamDecoratorWithoutParam, createRequestLogger, createSignedToken, createSuccessResponse, createTaskQueue, createTempDir, createTempFile, createThrottleStream, createUrlBuilder, dateDiff, daysInMonth, debounce, decrypt, deepFreeze, deepObjMerge, defaultSensitiveFields, deleteDirRecursive, deleteFileIfExists, difference, emptyDir, encrypt, endOf, ensureDir, ensureEmptyDir, ensureType, equalsIgnoreCase, errorHandler, extractFilterParams, extractPaginationParams, extractQueryParams, extractSortParams, fileExists, filterObject, findFilesByPattern, findInDir, findNewestFile, findOldestFile, flattenDeep, flattenObject, formatDate, formatRelativeTime, generateApiKey, generateRandomBytes, generateRandomBytesAsString, getAllPaths, getConfig, getDirSize, getDirStats, getDomain, getErrorMessage, getExtension, getFileSize, getFileStats, getFromContext, getLogger, getPaginationParams, getRedactCensor, getRequestId, getSubdirectories, getTypeOf, getValueByPath, groupBy, hasErrorShape, hasRequiredProps, hash, healthCheck, hmac, inject, intersect, isAlpha, isAlphanumeric, isArray, isArrayOf, isBase64, isBetween, isCreditCard, isDateInRange, isDirectory, isEmail, isEqual, isFile, isHexColor, isHttpError, isIPv4, isIPv6, isISODate, isLeapYear, isLengthBetween, isNumberBetween, isNumeric, isObjEmpty, isObject, isPhone, isPlainObject, isPort, isPrimitiveType, isStrongPassword, isURL, isUUID, isValidJSON, isValidUrl, joinPaths, listFiles, logError,
|
|
7386
|
+
export { After, BUILD_MARKER, BadGatewayException, BadRequestException, Before, Body, Cache, CircuitBreakerOpenError, CircuitBreakerState, ConflictException, Connect, ContentType, ContextStore, Controller, DIContainer, Delete, Env, Environment, ErrorResponse, ExpressServer, ForbiddenException, GatewayTimeoutException, Get, Head, Header, Headers, HttpCode, HttpError, HttpStatusCodes, Inject, Injectable, InsufficientStorageException, InternalServerErrorException, Log, MethodNotAllowedException, NoContentResponse, NotAcceptableException, NotFoundException, Options, PaginatedResponse, Param, Patch, PayloadTooLargeException, Post, Put, Query, RateLimit, Redirect, RedirectResponse, Req, ReqCookie, ReqHeader, ReqId, ReqLogger, RequestTimeoutException, Res, Roles, ServerConfigBuilder, ServiceUnavailableException, SortDirection, StoreKeys, SuccessResponse, TTLCache, Timeout, TooManyRequestsException, Trace, TypedContextKey, UnauthorizedException, UnprocessableEntityException, UnsupportedMediaTypeException, Use, Version, _globalThis, abortable, addRedactFields, addSensitiveFields, addToDate, appendQueryParams, appendTextFile, bufferToStream, capitalize, chunk, circuitBreaker, compact, copyDir, copyFile, countBy, countOccurrences, createBatchStream, createChildLogger, createDeferred, createDirectory, createErrorResponse, createFinalErrorResponse, createHttpError, createLineStream, createPaginatedResponse, createParamDecorator, createParamDecoratorWithoutParam, createRequestLogger, createSignedToken, createSuccessResponse, createTaskQueue, createTempDir, createTempFile, createThrottleStream, createUrlBuilder, dateDiff, daysInMonth, debounce, decrypt, deepFreeze, deepObjMerge, defaultSensitiveFields, deleteDirRecursive, deleteFileIfExists, difference, emptyDir, encrypt, endOf, ensureDir, ensureEmptyDir, ensureType, equalsIgnoreCase, errorHandler, expandSensitiveField, expandSensitiveFields, extractFilterParams, extractPaginationParams, extractQueryParams, extractSortParams, fileExists, filterObject, findFilesByPattern, findInDir, findNewestFile, findOldestFile, flattenDeep, flattenObject, formatDate, formatRelativeTime, generateApiKey, generateDeepPaths, generateRandomBytes, generateRandomBytesAsString, getAllPaths, getConfig, getDirSize, getDirStats, getDomain, getErrorMessage, getExpandedSensitiveFields, getExtension, getFileSize, getFileStats, getFromContext, getLogger, getPaginationParams, getRedactCensor, getRequestId, getSubdirectories, getTypeOf, getValueByPath, groupBy, hasErrorShape, hasRequiredProps, hash, healthCheck, hmac, inject, intersect, isAlpha, isAlphanumeric, isArray, isArrayOf, isBase64, isBetween, isCreditCard, isDateInRange, isDirectory, isEmail, isEqual, isFile, isHexColor, isHttpError, isIPv4, isIPv6, isISODate, isLeapYear, isLengthBetween, isNumberBetween, isNumeric, isObjEmpty, isObject, isPhone, isPlainObject, isPort, isPrimitiveType, isStrongPassword, isURL, isUUID, isValidJSON, isValidUrl, joinPaths, listFiles, logError, mapObject, mask, matchesPattern, md5, memoize, memoizeAsync, mergeSort, moveDir, moveFile, nanoId, normalizeUrl, omit, parseBooleanParam, parseDate, parseNumberParam, parseQueryString, parseTypedQueryParams, partition, pick, pluck, random, randomBase64, randomHex, randomInt, randomString, range, rateLimit, readDirectory, readFileBuffer, readJsonFile, readTextFile, redact, registerControllers, removeQueryParams, requestId, responseTime, retry, reverse, runInBatches, runInSeries, runWithConcurrency, safeCompare, safeReadJsonFile, sendResponse, setConfig, setRedactCensor, setSensitiveFields, setValueByPath, settleAll, setupRequestContext, sha1, sha256, sha256Hmac, shuffle, singletonAsync, sleep, slugify, startOf, streamFile, streamToBuffer, streamToString, stripHtml, take, takeWhile, throttle, timeAsync, timeSync, timed, timeout, toBool, toCamelCase, toKebabCase, toNum, toPascalCase, toSnakeCase, toStr, trackMemoryUsage, truncate, unique, uuid, validateAll, verifySignedToken, walkDir, watchDir, watchDirRecursive, waterfall, withErrorHandling, withTimeout, writeJsonFile, writeTextFile, zip };
|