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.

415 lines (412 loc) 16.4 kB
/* * The MIT License * * Copyright (c) 2026 Catbee Technologies. https://catbee.in/license * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** * Enum representing valid application environments. */ declare enum Environment { PRODUCTION = "production", DEVELOPMENT = "development", STAGING = "staging", TESTING = "testing" } /** * Options for validating URL environment variables */ interface UrlOptions { /** List of allowed protocols (e.g., ['http', 'https']) */ protocols?: string[]; /** Whether a top-level domain is required (default: true) */ requireTld?: boolean; /** Whether to allow IP addresses (default: true) */ allowIp?: boolean; /** Whether to allow localhost (default: true) */ allowLocalhost?: boolean; } /** * Options for validating path environment variables */ interface PathOptions { /** Whether the path must exist on the filesystem (default: false) */ mustExist?: boolean; /** Whether to convert relative paths to absolute (default: true) */ makeAbsolute?: boolean; /** List of allowed file extensions */ allowedExtensions?: string[]; } /** * Utility class for accessing and managing environment variables. * Provides typed getters with fallback defaults and validation. */ declare class Env { private static readonly cache; /** * Checks if the current NODE_ENV is 'development'. * * @returns {boolean} `true` if NODE_ENV is 'development', else `false`. */ static isDev(): boolean; /** * Checks if the current NODE_ENV is 'production'. * * @returns {boolean} `true` if NODE_ENV is 'production', else `false`. */ static isProd(): boolean; /** * Checks if the current NODE_ENV is 'testing'. * * @returns {boolean} `true` if NODE_ENV is 'testing', else `false`. */ static isTest(): boolean; /** * Checks if the current NODE_ENV is 'staging'. * * @returns {boolean} `true` if NODE_ENV is 'staging', else `false`. */ static isStaging(): boolean; /** * Sets an environment variable (only affects runtime memory). * * @param {string} key - The environment variable key. * @param {string} value - The value to set. */ static set(key: string, value: string): void; /** * Returns all environment variables as an object. * * @returns {object} The current `process.env` object. */ static getAll(): object; /** * Retrieves a string environment variable with a fallback default. * Supports variable expansion with ${VAR_NAME} syntax. * * @param {string} key - The environment variable key. * @param {string} [defaultValue] - Value to return if the key is missing. * @returns {string} The env value or the fallback. * * @example * // If DATABASE_URL is "postgres://localhost:5432/${DB_NAME}" * // and DB_NAME is "myapp" * const url = Env.get('DATABASE_URL', ''); // "postgres://localhost:5432/myapp" */ static get(key: string, defaultValue: string): string; /** * 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. */ static getRequired(key: string): string; /** * Retrieves a value using a default generating function if the key doesn't exist. * Useful for expensive default calculations. * * @param {string} key - The environment variable key. * @param {() => string} defaultFn - Function that generates default value. * @returns {string} The environment value or generated default. * * @example * const hostname = Env.getWithDefault('HOSTNAME', () => { * // Only called if HOSTNAME is not set * return require('os').hostname(); * }); */ static getWithDefault(key: string, defaultFn: () => string): string; /** * 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. */ static getNumber(key: string, defaultValue: number): number; /** * 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. */ static getNumberRequired(key: string): number; /** * Retrieves an integer environment variable and validates it. * * @param {string} key - The environment variable key. * @param {number} defaultValue - Fallback number if key is not present. * @param {object} [options] - Validation options. * @param {number} [options.min] - Minimum allowed value. * @param {number} [options.max] - Maximum allowed value. * @returns {number} The parsed integer. * * @example * // Require PORT to be between 1000 and 9999 * const port = Env.getInteger('PORT', 3000, { min: 1000, max: 9999 }); */ static getInteger(key: string, defaultValue: number, options?: { min?: number; max?: number; }): number; /** * 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. * * @example * // If DEBUG=yes * const isDebug = Env.getBoolean('DEBUG', false); // true */ static getBoolean(key: string, defaultValue?: boolean): 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. */ static getBooleanRequired(key: string): boolean; /** * 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. * * @example * // If CONFIG='{"debug":true,"api":{"url":"https://api.example.com"}}' * const config = Env.getJSON('CONFIG', { debug: false }); * // { debug: true, api: { url: "https://api.example.com" }} */ static getJSON<T extends object = object>(key: string, defaultValue: T): T; /** * 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. * @param {(item: string) => T} [transform] - Optional function to transform each item. * @returns {T[]} An array of items. * * @example * // If ALLOWED_IPS=127.0.0.1,192.168.1.1,10.0.0.1 * const ips = Env.getArray('ALLOWED_IPS'); * // ["127.0.0.1", "192.168.1.1", "10.0.0.1"] * * // With transformation function * const ports = Env.getArray('PORTS', [], ',', (p) => parseInt(p, 10)); */ static getArray<T = string>(key: string, defaultValue?: T[], splitter?: string, transform?: (item: string) => T): T[]; /** * Parses a comma-separated list of numbers. * * @param {string} key - The environment variable key. * @param {number[]} [defaultValue=[]] - Default value if not present. * @param {string} [splitter=','] - Delimiter to split on. * @returns {number[]} Array of parsed numbers. * * @example * // If ALLOWED_PORTS=80,443,3000,8080 * const ports = Env.getNumberArray('ALLOWED_PORTS'); * // [80, 443, 3000, 8080] */ static getNumberArray(key: string, defaultValue?: number[], splitter?: string): number[]; /** * 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} [defaultValue] - Optional fallback value. * @param {T[]} allowedValues - Array of accepted string values. * @returns {T} The validated environment value. * @throws {Error} If missing or invalid. * * @example * // If LOG_LEVEL=debug * const level = Env.getEnum('LOG_LEVEL', 'info', ['debug', 'info', 'warn', 'error'] as const); * // 'debug' (typed as 'debug' | 'info' | 'warn' | 'error') */ static getEnum<T extends string>(key: string, defaultValue: T, allowedValues: readonly T[]): T; /** * Retrieves an enum-like numeric environment variable. * * @param {string} key - The environment variable key. * @param {number} defaultValue - Default value if not present. * @param {number[]} allowedValues - Array of accepted values. * @returns {number} The validated value. * * @example * // If NODE_VERSION=16 * const version = Env.getNumberEnum('NODE_VERSION', 16, [14, 16, 18]); */ static getNumberEnum(key: string, defaultValue: number, allowedValues: number[]): number; /** * Retrieves a URL environment variable and validates it. * * @param {string} key - The environment variable key. * @param {string} [defaultValue] - Optional fallback value. * @param {UrlOptions} [options] - Validation options. * @returns {string} The validated URL. * @throws {Error} If URL is invalid. * * @example * // Validate API URL requires HTTPS * const apiUrl = Env.getUrl('API_URL', 'https://api.example.com', { * protocols: ['https'], * requireTld: true, * allowIp: false * }); */ static getUrl(key: string, defaultValue: string, options?: UrlOptions): string; private static parseUrl; private static validateProtocol; private static isIp; private static validateHostname; /** * 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. * * @example * const supportEmail = Env.getEmail('SUPPORT_EMAIL', 'support@example.com'); */ static getEmail(key: string, defaultValue: string): string; /** * Retrieves a path environment variable and validates it exists. * * @param {string} key - The environment variable key. * @param {string} [defaultValue] - Optional fallback value. * @param {PathOptions} [options] - Validation options. * @returns {string} The validated path. * @throws {Error} If path is invalid. * * @example * // Require that the path exists and is a .json file * const configPath = Env.getPath('CONFIG_PATH', './config.json', { * mustExist: true, * allowedExtensions: ['.json', '.yaml'] * }); */ static getPath(key: string, defaultValue: string, options?: PathOptions): string; /** * Retrieves a port environment variable and validates it. * * @param {string} key - The environment variable key. * @param {number} [defaultValue] - Optional fallback value. * @returns {number} The validated port number. * @throws {Error} If port is invalid. * * @example * const serverPort = Env.getPort('PORT', 3000); */ static getPort(key: string, defaultValue: number): number; /** * Retrieves an ISO date string and converts it to a Date object. * * @param {string} key - The environment variable key. * @param {string|Date} [defaultValue] - Optional fallback value. * @returns {Date} The parsed Date object. * * @example * // If EXPIRY_DATE=2023-12-31T23:59:59Z * const expiryDate = Env.getDate('EXPIRY_DATE', new Date()); */ static getDate(key: string, defaultValue?: string | Date): Date; /** * Retrieves a duration string and converts it 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. * * @example * // If CACHE_TTL=2h30m * const cacheTtlMs = Env.getDuration('CACHE_TTL', '1h'); * // 9000000 (2.5 hours in milliseconds) */ static getDuration(key: string, defaultValue?: string | number): number; /** * 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. * * @example * console.log(Env.getSafeEnv(['password', 'secret', 'key'])); * // { DATABASE_URL: "postgres://...", API_KEY: "******", ... } */ static getSafeEnv(sensitiveKeys?: string[]): Record<string, string>; /** * Loads environment variables from a .env file. * Does not override existing variables. * * @param {string} [path='.env'] - Path to the .env file. * @returns {Record<string, string>} Loaded environment variables. * * @example * // Load variables from .env.development * Env.loadFromFile('.env.development'); */ static loadFromFile(path?: string): Record<string, string>; private static parseEnvContent; private static isCommentOrEmpty; private static extractKeyValue; private static isQuoted; private static stripInlineComment; private static parseQuotedValue; private static parseUnquotedMultiline; /** * Checks whether the specified environment variable exists. * * @param {string} key - The environment variable key. * @returns {boolean} `true` if the variable is defined, otherwise `false`. */ static has(key: string): boolean; /** * Deletes the given environment variable (useful in tests). * * @param {string} key - The environment variable key to delete. * @returns {void} */ static delete(key: string): void; /** * Clears the internal cache of parsed environment values. * Useful for testing or when environment variables might change. */ static clearCache(): void; } export { Env, Environment }; export type { PathOptions, UrlOptions };