@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
TypeScript
/*
* 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 };