@catbee/utils
Version:
A modular, production-grade utility toolkit for Node.js and TypeScript, designed for robust, scalable applications (including Express-based services). All utilities are tree-shakable and can be imported independently.
451 lines • 17.5 kB
JavaScript
var __values = (this && this.__values) || function(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m) return m.call(o);
if (o && typeof o.length === "number") return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
/* eslint-disable n/no-process-env */
import { existsSync } from "fs";
import { isAbsolute, resolve } from "path";
/**
* Enum representing valid application environments.
*/
export var Environment;
(function (Environment) {
Environment["PRODUCTION"] = "production";
Environment["DEVELOPMENT"] = "development";
Environment["STAGING"] = "staging";
Environment["TESTING"] = "testing";
})(Environment || (Environment = {}));
/**
* Utility class for accessing and managing environment variables.
* Provides typed getters with fallback defaults and validation.
*/
var Env = /** @class */ (function () {
function Env() {
}
/**
* Checks if the current NODE_ENV is 'development'.
*
* @returns {boolean} `true` if NODE_ENV is 'development', else `false`.
*/
Env.isDev = function () {
return (Env.get("NODE_ENV", Environment.DEVELOPMENT) === Environment.DEVELOPMENT);
};
/**
* Checks if the current NODE_ENV is 'production'.
*
* @returns {boolean} `true` if NODE_ENV is 'production', else `false`.
*/
Env.isProd = function () {
return Env.get("NODE_ENV") === Environment.PRODUCTION;
};
/**
* Checks if the current NODE_ENV is 'testing'.
*
* @returns {boolean} `true` if NODE_ENV is 'testing', else `false`.
*/
Env.isTest = function () {
return Env.get("NODE_ENV") === Environment.TESTING;
};
/**
* Checks if the current NODE_ENV is 'staging'.
*
* @returns {boolean} `true` if NODE_ENV is 'staging', else `false`.
*/
Env.isStaging = function () {
return Env.get("NODE_ENV") === Environment.STAGING;
};
/**
* Sets an environment variable (only affects runtime memory).
*
* @param {string} key - The environment variable key.
* @param {string} value - The value to set.
*/
Env.set = function (key, value) {
process.env[key] = value;
};
/**
* Returns all environment variables as an object.
*
* @returns {object} The current `process.env` object.
*/
Env.getAll = function () {
return process.env;
};
/**
* Retrieves a string environment variable with a fallback default.
*
* @param {string} key - The environment variable key.
* @param {string} [defaultValue] - Value to return if the key is missing.
* @returns {string | undefined} The env value or the fallback.
*/
Env.get = function (key, defaultValue) {
var _a;
return (_a = process.env[key]) !== null && _a !== void 0 ? _a : defaultValue;
};
/**
* Retrieves a string environment variable and throws if it's missing.
*
* @param {string} key - The environment variable key.
* @returns {string} The environment variable's value.
* @throws {Error} If the variable is not defined.
*/
Env.getRequired = function (key) {
var value = process.env[key];
if (value === undefined) {
throw new Error("Required env ".concat(key, " is missing"));
}
return value;
};
/**
* Retrieves an environment variable as a number, or returns a default.
*
* @param {string} key - The environment variable key.
* @param {number} defaultValue - Fallback number if key is not present.
* @returns {number} Parsed numeric value or default.
* @throws {Error} If the value is not a valid number.
*/
Env.getNumber = function (key, defaultValue) {
var _a;
var value = (_a = process.env[key]) !== null && _a !== void 0 ? _a : defaultValue;
var numberValue = Number(value);
if (isNaN(numberValue)) {
throw new Error("Env ".concat(key, " is not a number"));
}
return numberValue;
};
/**
* Retrieves a required environment variable as a number.
*
* @param {string} key - The environment variable key.
* @returns {number} Parsed number.
* @throws {Error} If the value is missing or not a number.
*/
Env.getNumberRequired = function (key) {
var value = process.env[key];
if (value === undefined) {
throw new Error("Required env ".concat(key, " is missing"));
}
var numberValue = Number(value);
if (isNaN(numberValue)) {
throw new Error("Required env ".concat(key, " is not a number"));
}
return numberValue;
};
/**
* Retrieves an environment variable as a boolean.
* Accepts `true`, `1`, `yes`, `on` as true; `false`, `0`, `no`, `off` as false.
*
* @param {string} key - The environment variable key.
* @param {boolean} [defaultValue=false] - Optional fallback value if key is missing.
* @returns {boolean} Parsed boolean.
* @throws {Error} If the value is not a recognized boolean string.
*/
Env.getBoolean = function (key, defaultValue) {
var _a;
if (defaultValue === void 0) { defaultValue = false; }
var value = ((_a = process.env[key]) !== null && _a !== void 0 ? _a : defaultValue).toString().toLowerCase();
if (["true", "1", "yes", "on"].includes(value))
return true;
if (["false", "0", "no", "off"].includes(value))
return false;
throw new Error("Env variable ".concat(key, " is not a boolean"));
};
/**
* Retrieves a required environment variable as a boolean.
*
* @param {string} key - The environment variable key.
* @returns {boolean} Parsed boolean value.
* @throws {Error} If missing or invalid.
*/
Env.getBooleanRequired = function (key) {
var value = process.env[key];
if (value === undefined) {
throw new Error("Required env ".concat(key, " is missing"));
}
return this.getBoolean(key); // reuse logic
};
/**
* Parses a stringified JSON object from an environment variable.
*
* @typeParam T - The type to parse as (defaults to `object`).
* @param {string} key - The environment variable key.
* @param {T} defaultValue - Value to return if key is missing.
* @returns {T} Parsed object or default.
* @throws {Error} If the value is not valid JSON.
*/
Env.getJSON = function (key, defaultValue) {
var v = process.env[key];
if (v !== undefined) {
try {
return JSON.parse(v);
}
catch (_a) {
throw new Error("Env variable ".concat(key, " is not a valid JSON string"));
}
}
return defaultValue;
};
/**
* Parses a comma-separated string as an array.
*
* @typeParam T - The item type (optional, defaults to string).
* @param {string} key - The environment variable key.
* @param {T[]} [defaultValue=[]] - Array to return if value is empty or missing.
* @param {string} [splitter=','] - Delimiter to split on.
* @returns {string[] | T[]} An array of strings.
*/
Env.getArray = function (key, defaultValue, splitter) {
if (defaultValue === void 0) { defaultValue = []; }
if (splitter === void 0) { splitter = ","; }
var value = process.env[key];
if (!value || value.trim() === "") {
return defaultValue;
}
return value
.split(splitter)
.map(function (item) { return item.trim(); })
.filter(function (item) { return item.length > 0; });
};
/**
* Retrieves an enum-like environment variable value, validating against allowed values.
*
* @typeParam T - The allowed value type (string literal types).
* @param {string} key - The environment variable key.
* @param {T[]} allowedValues - Array of accepted string values.
* @param {T} [defaultValue] - Optional fallback value.
* @returns {T} The validated environment value.
* @throws {Error} If missing or invalid.
*/
Env.getEnum = function (key, allowedValues, defaultValue) {
var _a;
var value = (_a = process.env[key]) !== null && _a !== void 0 ? _a : defaultValue;
if (!value || !allowedValues.includes(value)) {
throw new Error("Env ".concat(key, " must be one of ").concat(allowedValues.join(", "), ". Received: ").concat(value));
}
return value;
};
/**
* Retrieves a URL environment variable and validates it.
*
* @param {string} key - The environment variable key.
* @param {string} [defaultValue] - Optional fallback value.
* @param {object} [options] - Validation options.
* @param {string[]} [options.protocols] - Allowed protocols.
* @param {boolean} [options.requireTld=true] - Whether TLD is required.
* @returns {string} The validated URL.
* @throws {Error} If URL is invalid.
*/
Env.getUrl = function (key, defaultValue, options) {
if (options === void 0) { options = {}; }
var value = Env.get(key, defaultValue);
if (!value) {
throw new Error("Env ".concat(key, " is missing or empty"));
}
var url;
try {
url = new URL(value);
}
catch (_a) {
throw new Error("Env ".concat(key, " is not a valid URL"));
}
if (options.protocols && options.protocols.length > 0) {
var protocol = url.protocol.replace(":", "");
if (!options.protocols.includes(protocol)) {
throw new Error("Env ".concat(key, " must use one of the protocols: ").concat(options.protocols.join(", ")));
}
}
if (options.requireTld === true) {
// Check if hostname has a TLD (contains at least one dot and doesn't end with a dot)
// localhost, 127.0.0.1, etc. don't have TLDs
var hostname = url.hostname;
if (!hostname.includes(".") ||
hostname === "localhost" ||
/^[\d.]+$/.test(hostname) || // IP address
hostname.endsWith(".")) {
throw new Error("Env ".concat(key, " must have a valid host with TLD"));
}
}
return value;
};
/**
* Retrieves an email environment variable and validates it.
*
* @param {string} key - The environment variable key.
* @param {string} [defaultValue] - Optional fallback value.
* @returns {string} The validated email address.
* @throws {Error} If email is invalid.
*/
Env.getEmail = function (key, defaultValue) {
var value = Env.get(key, defaultValue);
if (!value) {
if (defaultValue === undefined) {
throw new Error("Email env ".concat(key, " is missing"));
}
return defaultValue;
}
// Simple email validation regex
var emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (!emailRegex.test(value)) {
throw new Error("Env ".concat(key, " is not a valid email address"));
}
return value;
};
/**
* Retrieves a path environment variable and validates it exists.
*
* @param {string} key - The environment variable key.
* @param {string} [defaultValue] - Optional fallback value.
* @param {object} [options] - Validation options.
* @param {boolean} [options.mustExist=false] - Whether path must exist.
* @param {boolean} [options.makeAbsolute=true] - Convert relative paths to absolute.
* @returns {string} The validated path.
* @throws {Error} If path is invalid.
*/
Env.getPath = function (key, defaultValue, options) {
if (options === void 0) { options = {}; }
var value = Env.get(key, defaultValue);
if (!value) {
if (defaultValue === undefined) {
throw new Error("Path env ".concat(key, " is missing"));
}
return defaultValue;
}
var path = options.makeAbsolute !== false && !isAbsolute(value)
? resolve(process.cwd(), value)
: value;
if (options.mustExist && !existsSync(path)) {
throw new Error("Path in env ".concat(key, " does not exist: ").concat(path));
}
return path;
};
/**
* Retrieves a port environment variable and validates it.
*
* @param {string} key - The environment variable key.
* @param {number} [defaultValue=3000] - Optional fallback value.
* @returns {number} The validated port number.
* @throws {Error} If port is invalid.
*/
Env.getPort = function (key, defaultValue) {
if (defaultValue === void 0) { defaultValue = 3000; }
var port = Env.getNumber(key, defaultValue);
if (port < 0 || port > 65535) {
throw new Error("Env ".concat(key, " must be a valid port number (0-65535)"));
}
return port;
};
/**
* Retrieves a duration string and converts to milliseconds.
* Supports formats like "1d", "2h", "30m", "45s", "100ms" or combinations like "1h30m".
*
* @param {string} key - The environment variable key.
* @param {string|number} [defaultValue='0'] - Optional fallback value.
* @returns {number} The duration in milliseconds.
* @throws {Error} If duration format is invalid.
*/
Env.getDuration = function (key, defaultValue) {
if (defaultValue === void 0) { defaultValue = "0"; }
var value = Env.get(key, String(defaultValue));
if (!value)
return 0;
// Handle plain number input (assume milliseconds)
if (/^\d+$/.test(value)) {
return parseInt(value, 10);
}
// Parse duration string like "1d2h30m15s"
var durationRegex = /(\d+d)?(\d+h)?(\d+m)?(\d+s)?(\d+ms)?/;
var matches = value.match(durationRegex);
if (!matches || matches[0] === "") {
throw new Error("Env ".concat(key, " has invalid duration format. Use 1d, 2h, 30m, 45s, or 100ms."));
}
var ms = 0;
if (matches[1])
ms += parseInt(matches[1], 10) * 86400000; // days
if (matches[2])
ms += parseInt(matches[2], 10) * 3600000; // hours
if (matches[3])
ms += parseInt(matches[3], 10) * 60000; // minutes
if (matches[4])
ms += parseInt(matches[4], 10) * 1000; // seconds
if (matches[5])
ms += parseInt(matches[5], 10); // milliseconds
return ms;
};
/**
* Gets all environment variables with sensitive values masked for safe logging.
*
* @param {string[]} [sensitiveKeys=['password', 'secret', 'key', 'token', 'auth']] - Keys to mask.
* @returns {Record<string, string>} Environment variables with sensitive values masked.
*/
Env.getSafeEnv = function (sensitiveKeys) {
var e_1, _a;
if (sensitiveKeys === void 0) { sensitiveKeys = ["password", "secret", "key", "token", "auth"]; }
var safeEnv = {};
var _loop_1 = function (key, value) {
if (!value)
return "continue";
var isSensitive = sensitiveKeys.some(function (sensitiveKey) {
return key.toLowerCase().includes(sensitiveKey.toLowerCase());
});
safeEnv[key] = isSensitive ? "******" : value;
};
try {
for (var _b = __values(Object.entries(process.env)), _c = _b.next(); !_c.done; _c = _b.next()) {
var _d = __read(_c.value, 2), key = _d[0], value = _d[1];
_loop_1(key, value);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
return safeEnv;
};
/**
* Checks whether the specified environment variable exists.
*
* @param {string} key - The environment variable key.
* @returns {boolean} `true` if the variable is defined, otherwise `false`.
*/
Env.has = function (key) {
return process.env[key] !== undefined;
};
/**
* Deletes the given environment variable (useful in tests).
*
* @param {string} key - The environment variable key to delete.
* @returns {void}
*/
Env.delete = function (key) {
delete process.env[key];
};
return Env;
}());
export { Env };
//# sourceMappingURL=env.utils.js.map