UNPKG

@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
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