@abdokouta/react-config 1.0.0 → 1.0.2
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/LICENSE +21 -0
- package/README.md +2 -1
- package/config/config.config.ts +9 -9
- package/dist/{index.d.mts → index.d.cts} +34 -2
- package/dist/index.d.ts +34 -2
- package/dist/index.js +28 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +28 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +55 -25
- package/.examples/01-basic-usage.ts +0 -289
- package/.examples/02-env-helper.ts +0 -282
- package/.examples/README.md +0 -285
- package/.prettierrc.js +0 -1
- package/__tests__/config.module.test.ts +0 -244
- package/__tests__/drivers/env.driver.test.ts +0 -259
- package/__tests__/services/config.service.test.ts +0 -328
- package/__tests__/setup.d.ts +0 -11
- package/__tests__/vitest.setup.ts +0 -30
- package/eslint.config.js +0 -13
- package/src/config.module.ts +0 -154
- package/src/constants/index.ts +0 -5
- package/src/constants/tokens.constant.ts +0 -38
- package/src/drivers/env.driver.ts +0 -194
- package/src/drivers/file.driver.ts +0 -81
- package/src/drivers/index.ts +0 -6
- package/src/index.ts +0 -92
- package/src/interfaces/config-driver.interface.ts +0 -30
- package/src/interfaces/config-module-options.interface.ts +0 -84
- package/src/interfaces/config-service.interface.ts +0 -71
- package/src/interfaces/index.ts +0 -8
- package/src/interfaces/vite-config-plugin-options.interface.ts +0 -56
- package/src/plugins/index.ts +0 -5
- package/src/plugins/vite.plugin.ts +0 -115
- package/src/services/config.service.ts +0 -172
- package/src/services/index.ts +0 -5
- package/src/utils/get-nested-value.util.ts +0 -56
- package/src/utils/index.ts +0 -6
- package/src/utils/load-config-file.util.ts +0 -37
- package/src/utils/scan-config-files.util.ts +0 -40
- package/tsconfig.json +0 -28
- package/tsup.config.ts +0 -105
- package/vitest.config.ts +0 -66
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.module.ts","../src/utils/get-nested-value.util.ts","../src/drivers/env.driver.ts","../src/drivers/file.driver.ts","../src/services/config.service.ts","../src/constants/tokens.constant.ts","../src/utils/load-config-file.util.ts"],"sourcesContent":["import { Module, DynamicModule } from '@abdokouta/react-di';\n\nimport { EnvDriver } from './drivers/env.driver';\nimport { FileDriver } from './drivers/file.driver';\nimport { ConfigService } from './services/config.service';\nimport type { ConfigDriver } from './interfaces/config-driver.interface';\nimport type { ConfigModuleOptions } from './interfaces/config-module-options.interface';\nimport { CONFIG_DRIVER, CONFIG_OPTIONS, CONFIG_SERVICE } from './constants/tokens.constant';\n\n/**\n * Configuration Module\n * \n * Provides configuration management with multiple drivers.\n * Similar to NestJS ConfigModule.\n * \n * @example\n * ```typescript\n * // Using environment variables (default)\n * @Module({\n * imports: [\n * ConfigModule.forRoot({\n * envFilePath: '.env',\n * isGlobal: true,\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n * \n * @example\n * ```typescript\n * // Using file-based configuration\n * @Module({\n * imports: [\n * ConfigModule.forRoot({\n * driver: 'file',\n * filePattern: 'config/**\\/*.config.ts',\n * isGlobal: true,\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\n@Module({})\nexport class ConfigModule {\n /**\n * Register configuration module with options\n * \n * @param options - Configuration options\n * @returns Dynamic module\n */\n static forRoot(options: ConfigModuleOptions = {}): DynamicModule {\n const driver = this.createDriver(options);\n \n const isGlobal = options.isGlobal ?? false;\n \n const providers = [\n {\n provide: CONFIG_OPTIONS,\n useValue: options,\n isGlobal,\n },\n {\n provide: CONFIG_DRIVER,\n useValue: driver,\n isGlobal,\n },\n ConfigService,\n {\n provide: CONFIG_SERVICE,\n useExisting: ConfigService,\n isGlobal,\n },\n ];\n\n return {\n module: ConfigModule,\n providers: providers as any,\n exports: [ConfigService],\n };\n }\n\n /**\n * Register configuration module asynchronously\n * \n * @param options - Async configuration options\n * @returns Dynamic module\n */\n static async forRootAsync(\n options: ConfigModuleOptions & {\n useFactory?: () => Promise<ConfigModuleOptions> | ConfigModuleOptions;\n }\n ): Promise<DynamicModule> {\n const resolvedOptions = options.useFactory\n ? await options.useFactory()\n : options;\n\n return this.forRoot(resolvedOptions);\n }\n\n /**\n * Create configuration driver based on options\n */\n private static createDriver(options: ConfigModuleOptions): ConfigDriver {\n const driverType = options.driver || 'env';\n\n switch (driverType) {\n case 'env':\n const envDriver = new EnvDriver({\n envFilePath: options.envFilePath,\n ignoreEnvFile: options.ignoreEnvFile,\n expandVariables: options.expandVariables,\n envPrefix: options.envPrefix,\n globalName: options.globalName,\n });\n envDriver.load();\n \n // Merge custom load function if provided\n if (options.load) {\n this.mergeCustomConfig(envDriver, options.load);\n }\n \n return envDriver;\n\n case 'file':\n const fileDriver = new FileDriver({\n config: typeof options.load === 'object' ? options.load : undefined,\n });\n return fileDriver;\n\n default:\n throw new Error(`Unknown configuration driver: ${driverType}`);\n }\n }\n\n /**\n * Merge custom configuration into driver\n */\n private static mergeCustomConfig(\n driver: ConfigDriver,\n load: Record<string, any> | (() => Record<string, any> | Promise<Record<string, any>>)\n ): void {\n const customConfig = typeof load === 'function' ? load() : load;\n \n if (customConfig instanceof Promise) {\n customConfig.then(config => {\n Object.assign(driver.all(), config);\n });\n } else {\n Object.assign(driver.all(), customConfig);\n }\n }\n}\n","/**\n * Get nested value from object using dot notation\n * \n * @param obj - Source object\n * @param path - Dot-notated path (e.g., 'database.host')\n * @param defaultValue - Default value if path not found\n * @returns Value at path or default value\n * \n * @example\n * ```typescript\n * const config = { database: { host: 'localhost' } };\n * getNestedValue(config, 'database.host'); // 'localhost'\n * getNestedValue(config, 'database.port', 5432); // 5432\n * ```\n */\nexport function getNestedValue<T = any>(\n obj: Record<string, any>,\n path: string,\n defaultValue?: T\n): T | undefined {\n const keys = path.split('.');\n let current: any = obj;\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return defaultValue;\n }\n current = current[key];\n }\n\n return current !== undefined ? current : defaultValue;\n}\n\n/**\n * Check if nested path exists in object\n * \n * @param obj - Source object\n * @param path - Dot-notated path\n * @returns True if path exists\n */\nexport function hasNestedValue(\n obj: Record<string, any>,\n path: string\n): boolean {\n const keys = path.split('.');\n let current: any = obj;\n\n for (const key of keys) {\n if (current === null || current === undefined || !(key in current)) {\n return false;\n }\n current = current[key];\n }\n\n return true;\n}\n","import type { ConfigDriver } from '../interfaces/config-driver.interface';\nimport { getNestedValue, hasNestedValue } from '../utils/get-nested-value.util';\n\n/**\n * Environment Variable Configuration Driver\n * \n * Loads configuration from environment variables (process.env).\n * Supports .env files via dotenv.\n */\nexport class EnvDriver implements ConfigDriver {\n private config: Record<string, any> = {};\n private loaded = false;\n\n constructor(\n private options: {\n envFilePath?: string | string[];\n ignoreEnvFile?: boolean;\n expandVariables?: boolean;\n envPrefix?: string | false;\n globalName?: string; // Custom global variable name\n } = {}\n ) {}\n\n /**\n * Load environment variables\n */\n load(): Record<string, any> {\n if (this.loaded) {\n console.log('[EnvDriver] Already loaded, returning cached config');\n return this.config;\n }\n\n console.log('[EnvDriver] Loading environment variables...');\n console.log('[EnvDriver] Options:', { ...this.options });\n\n // Load .env file if not ignored\n if (!this.options.ignoreEnvFile) {\n this.loadDotEnv();\n }\n\n // Get global config name (default: __APP_CONFIG__)\n const globalName = this.options.globalName || '__APP_CONFIG__';\n\n // Try to load from custom global variable first (browser environment)\n if (typeof window !== 'undefined' && (window as any)[globalName]) {\n this.config = { ...(window as any)[globalName] };\n console.log(`[EnvDriver] Loaded config from window.${globalName}:`, Object.keys(this.config).length, 'keys');\n }\n // Fallback to process.env (Node.js environment or backward compatibility)\n else if (typeof process !== 'undefined' && process.env) {\n this.config = { ...process.env };\n console.log('[EnvDriver] Loaded config from process.env:', Object.keys(this.config).length, 'keys');\n }\n // No config source available\n else {\n console.warn('[EnvDriver] No config source available (neither window.' + globalName + ' nor process.env)');\n this.config = {};\n }\n\n console.log('[EnvDriver] Initial config keys:', [...Object.keys(this.config).filter(k => k.includes('APP') || k.includes('VITE'))]);\n\n // Strip prefix if configured\n if (this.options.envPrefix !== false) {\n console.log('[EnvDriver] Stripping prefix...');\n this.stripPrefix();\n console.log('[EnvDriver] After stripPrefix, config keys:', [...Object.keys(this.config).filter(k => k.includes('APP') || k.includes('VITE'))]);\n }\n\n // Expand variables if enabled\n if (this.options.expandVariables) {\n this.expandEnvVariables();\n }\n\n this.loaded = true;\n console.log('[EnvDriver] Load complete. Sample values:', {\n APP_NAME: this.config.APP_NAME,\n VITE_APP_NAME: this.config.VITE_APP_NAME,\n });\n return this.config;\n }\n\n /**\n * Get configuration value\n */\n get<T = any>(key: string, defaultValue?: T): T | undefined {\n if (!this.loaded) {\n this.load();\n }\n const value = getNestedValue(this.config, key, defaultValue);\n console.log(`[EnvDriver] get(\"${key}\", \"${defaultValue}\") = \"${value}\"`);\n return value;\n }\n\n /**\n * Check if key exists\n */\n has(key: string): boolean {\n if (!this.loaded) {\n this.load();\n }\n return hasNestedValue(this.config, key);\n }\n\n /**\n * Get all configuration\n */\n all(): Record<string, any> {\n if (!this.loaded) {\n this.load();\n }\n return { ...this.config };\n }\n\n /**\n * Load .env file using dotenv\n */\n private loadDotEnv(): void {\n try {\n // Try to load dotenv\n const dotenv = require('dotenv');\n const paths = Array.isArray(this.options.envFilePath)\n ? this.options.envFilePath\n : [this.options.envFilePath || '.env'];\n\n for (const path of paths) {\n dotenv.config({ path });\n }\n } catch (error) {\n // dotenv not installed, skip\n }\n }\n\n /**\n * Expand environment variables (e.g., ${VAR_NAME})\n */\n private expandEnvVariables(): void {\n const regex = /\\$\\{([^}]+)\\}/g;\n\n const expand = (value: string): string => {\n return value.replace(regex, (_, key) => {\n return this.config[key] || '';\n });\n };\n\n for (const [key, value] of Object.entries(this.config)) {\n if (typeof value === 'string' && value.includes('${')) {\n this.config[key] = expand(value);\n }\n }\n }\n\n /**\n * Strip environment variable prefix\n * Auto-detects framework (Vite, Next.js) or uses custom prefix\n */\n private stripPrefix(): void {\n let prefix = this.options.envPrefix;\n\n // Auto-detect framework prefix\n if (prefix === 'auto' || prefix === undefined) {\n // Check for Vite (import.meta.env exists or VITE_ variables present)\n const hasViteVars = Object.keys(this.config).some(key => key.startsWith('VITE_'));\n if (hasViteVars || typeof import.meta !== 'undefined') {\n prefix = 'VITE_';\n }\n // Check for Next.js (NEXT_PUBLIC_ variables present)\n else if (Object.keys(this.config).some(key => key.startsWith('NEXT_PUBLIC_'))) {\n prefix = 'NEXT_PUBLIC_';\n }\n // No framework detected, don't strip\n else {\n return;\n }\n }\n\n // Strip the prefix from all matching keys\n if (typeof prefix === 'string' && prefix.length > 0) {\n const newConfig: Record<string, any> = {};\n \n for (const [key, value] of Object.entries(this.config)) {\n if (key.startsWith(prefix)) {\n // Add both prefixed and unprefixed versions\n const unprefixedKey = key.substring(prefix.length);\n newConfig[unprefixedKey] = value;\n newConfig[key] = value; // Keep original too\n } else {\n newConfig[key] = value;\n }\n }\n \n this.config = newConfig;\n }\n }\n}\n","import type { ConfigDriver } from '@/interfaces/config-driver.interface';\nimport { getNestedValue, hasNestedValue } from '@/utils/get-nested-value.util';\n\n/**\n * File-based Configuration Driver\n * \n * Loads configuration from TypeScript/JavaScript files.\n * This is a server-side only driver. For client-side, use the Vite plugin.\n * \n * @see packages/pixielity/config/src/plugins/vite-config.plugin.ts\n */\nexport class FileDriver implements ConfigDriver {\n private config: Record<string, any> = {};\n private loaded = false;\n\n constructor(\n options: {\n config?: Record<string, any>;\n } = {}\n ) {\n // Pre-loaded config from Vite plugin or server\n if (options.config) {\n this.config = options.config;\n this.loaded = true;\n }\n }\n\n /**\n * Load configuration\n * Config should be pre-loaded via Vite plugin or passed in constructor\n */\n async load(): Promise<Record<string, any>> {\n if (this.loaded) {\n return this.config;\n }\n\n // If running on server (Node.js), throw error\n const isServer = typeof globalThis !== 'undefined' && \n typeof (globalThis as typeof globalThis & { window?: any }).window === 'undefined';\n \n if (isServer) {\n throw new Error(\n 'FileDriver requires pre-loaded configuration. ' +\n 'Use Vite plugin for client-side or pass config in constructor for server-side.'\n );\n }\n\n this.loaded = true;\n return this.config;\n }\n\n /**\n * Get configuration value\n */\n get<T = any>(key: string, defaultValue?: T): T | undefined {\n if (!this.loaded) {\n throw new Error('Configuration not loaded. Call load() first or use async initialization.');\n }\n return getNestedValue(this.config, key, defaultValue);\n }\n\n /**\n * Check if key exists\n */\n has(key: string): boolean {\n if (!this.loaded) {\n throw new Error('Configuration not loaded. Call load() first or use async initialization.');\n }\n return hasNestedValue(this.config, key);\n }\n\n /**\n * Get all configuration\n */\n all(): Record<string, any> {\n if (!this.loaded) {\n throw new Error('Configuration not loaded. Call load() first or use async initialization.');\n }\n return { ...this.config };\n }\n}\n","import { Inject, Injectable } from \"@abdokouta/react-di\";\n\nimport { CONFIG_DRIVER } from \"@/constants/tokens.constant\";\nimport type { ConfigDriver } from \"@/interfaces/config-driver.interface\";\nimport type { ConfigServiceInterface } from \"@/interfaces/config-service.interface\";\n\n/**\n * Configuration Service\n *\n * Provides type-safe access to configuration values with various getter methods.\n * Similar to NestJS ConfigService.\n *\n * @example\n * ```typescript\n * class MyService {\n * constructor(private config: ConfigService) {}\n *\n * getDbConfig() {\n * return {\n * host: this.config.getString('DB_HOST', 'localhost'),\n * port: this.config.getNumber('DB_PORT', 5432),\n * ssl: this.config.getBool('DB_SSL', false),\n * };\n * }\n * }\n * ```\n */\n@Injectable()\nexport class ConfigService implements ConfigServiceInterface {\n constructor(\n @Inject(CONFIG_DRIVER)\n private driver: ConfigDriver,\n ) {}\n\n /**\n * Get configuration value\n */\n get<T = any>(key: string, defaultValue?: T): T | undefined {\n return this.driver.get<T>(key, defaultValue);\n }\n\n /**\n * Get configuration value or throw if not found\n */\n getOrThrow<T = any>(key: string): T {\n const value = this.get<T>(key);\n if (value === undefined) {\n throw new Error(`Configuration key \"${key}\" is required but not set`);\n }\n return value;\n }\n\n /**\n * Get string value\n */\n getString(key: string, defaultValue?: string): string | undefined {\n const value = this.get(key, defaultValue);\n return value !== undefined ? String(value) : undefined;\n }\n\n /**\n * Get string value or throw\n */\n getStringOrThrow(key: string): string {\n return String(this.getOrThrow(key));\n }\n\n /**\n * Get number value\n */\n getNumber(key: string, defaultValue?: number): number | undefined {\n const value = this.get(key, defaultValue);\n if (value === undefined) {\n return undefined;\n }\n const parsed = Number(value);\n return isNaN(parsed) ? defaultValue : parsed;\n }\n\n /**\n * Get number value or throw\n */\n getNumberOrThrow(key: string): number {\n const value = this.getNumber(key);\n if (value === undefined) {\n throw new Error(`Configuration key \"${key}\" is required but not set`);\n }\n return value;\n }\n\n /**\n * Get boolean value\n * Treats 'true', '1', 'yes', 'on' as true\n */\n getBool(key: string, defaultValue?: boolean): boolean | undefined {\n const value = this.get(key, defaultValue);\n if (value === undefined) {\n return undefined;\n }\n if (typeof value === \"boolean\") {\n return value;\n }\n return [\"true\", \"1\", \"yes\", \"on\"].includes(String(value).toLowerCase());\n }\n\n /**\n * Get boolean value or throw\n */\n getBoolOrThrow(key: string): boolean {\n const value = this.getBool(key);\n if (value === undefined) {\n throw new Error(`Configuration key \"${key}\" is required but not set`);\n }\n return value;\n }\n\n /**\n * Get array value (comma-separated string or actual array)\n */\n getArray(key: string, defaultValue?: string[]): string[] | undefined {\n const value = this.get(key, defaultValue);\n if (value === undefined) {\n return undefined;\n }\n if (Array.isArray(value)) {\n return value.map(String);\n }\n return String(value)\n .split(\",\")\n .map((v) => v.trim())\n .filter(Boolean);\n }\n\n /**\n * Get JSON value\n */\n getJson<T = any>(key: string, defaultValue?: T): T | undefined {\n const value = this.get(key, defaultValue);\n if (value === undefined) {\n return undefined;\n }\n if (typeof value === \"object\") {\n return value as T;\n }\n try {\n return JSON.parse(String(value)) as T;\n } catch {\n return defaultValue;\n }\n }\n\n /**\n * Check if configuration key exists\n */\n has(key: string): boolean {\n return this.driver.has(key);\n }\n\n /**\n * Get all configuration values\n */\n all(): Record<string, any> {\n return this.driver.all();\n }\n\n /**\n * Clear cache (no-op since we don't cache in ConfigService)\n */\n clearCache(): void {\n // No-op - caching should be done at a higher level if needed\n }\n}\n","/**\n * Dependency Injection Tokens\n * \n * Used for injecting configuration dependencies.\n */\n\n/**\n * Configuration driver token\n * \n * @example\n * ```typescript\n * @Inject(CONFIG_DRIVER)\n * private driver: ConfigDriver\n * ```\n */\nexport const CONFIG_DRIVER = Symbol('CONFIG_DRIVER');\n\n/**\n * Configuration options token\n * \n * @example\n * ```typescript\n * @Inject(CONFIG_OPTIONS)\n * private options: ConfigModuleOptions\n * ```\n */\nexport const CONFIG_OPTIONS = Symbol('CONFIG_OPTIONS');\n\n/**\n * Configuration service token\n * \n * @example\n * ```typescript\n * @Inject(CONFIG_SERVICE)\n * private config: ConfigService\n * ```\n */\nexport const CONFIG_SERVICE = Symbol('CONFIG_SERVICE');\n","/**\n * Load Config File Utility\n *\n * Dynamically loads and parses a config file.\n */\n\n/**\n * Load and parse config file\n *\n * @param filePath - Absolute path to the config file\n * @returns Parsed config object\n */\nexport async function loadConfigFile(\n filePath: string\n): Promise<Record<string, any>> {\n try {\n // Dynamic import of the config file\n // @ts-ignore - Dynamic import path\n const module = await import(/* @vite-ignore */ filePath);\n\n // Extract config object (could be default export or named export)\n const config = module.default || module;\n\n // If it's a function, call it\n if (typeof config === 'function') {\n return await config();\n }\n\n return config;\n } catch (error) {\n console.warn(\n `[vite-plugin-config] Failed to load config file: ${filePath}`,\n error\n );\n return {};\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/config.module.ts","../src/utils/get-nested-value.util.ts","../src/drivers/env.driver.ts","../src/drivers/file.driver.ts","../src/services/config.service.ts","../src/constants/tokens.constant.ts","../src/utils/define-config.util.ts","../src/utils/load-config-file.util.ts"],"sourcesContent":["import { Module, DynamicModule } from '@abdokouta/react-di';\n\nimport { EnvDriver } from './drivers/env.driver';\nimport { FileDriver } from './drivers/file.driver';\nimport { ConfigService } from './services/config.service';\nimport type { ConfigDriver } from './interfaces/config-driver.interface';\nimport type { ConfigModuleOptions } from './interfaces/config-module-options.interface';\nimport { CONFIG_DRIVER, CONFIG_OPTIONS, CONFIG_SERVICE } from './constants/tokens.constant';\n\n/**\n * Configuration Module\n *\n * Provides configuration management with multiple drivers.\n * Similar to NestJS ConfigModule.\n *\n * @example\n * ```typescript\n * // Using environment variables (default)\n * @Module({\n * imports: [\n * ConfigModule.forRoot({\n * envFilePath: '.env',\n * isGlobal: true,\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n *\n * @example\n * ```typescript\n * // Using file-based configuration\n * @Module({\n * imports: [\n * ConfigModule.forRoot({\n * driver: 'file',\n * filePattern: 'config/**\\/*.config.ts',\n * isGlobal: true,\n * }),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\n@Module({})\nexport class ConfigModule {\n /**\n * Register configuration module with options\n *\n * @param options - Configuration options\n * @returns Dynamic module\n */\n static forRoot(options: ConfigModuleOptions = {}): DynamicModule {\n const driver = this.createDriver(options);\n\n const isGlobal = options.isGlobal ?? false;\n\n const providers = [\n {\n provide: CONFIG_OPTIONS,\n useValue: options,\n isGlobal,\n },\n {\n provide: CONFIG_DRIVER,\n useValue: driver,\n isGlobal,\n },\n ConfigService,\n {\n provide: CONFIG_SERVICE,\n useExisting: ConfigService,\n isGlobal,\n },\n ];\n\n return {\n module: ConfigModule,\n providers: providers as any,\n exports: [ConfigService],\n };\n }\n\n /**\n * Register configuration module asynchronously\n *\n * @param options - Async configuration options\n * @returns Dynamic module\n */\n static async forRootAsync(\n options: ConfigModuleOptions & {\n useFactory?: () => Promise<ConfigModuleOptions> | ConfigModuleOptions;\n }\n ): Promise<DynamicModule> {\n const resolvedOptions = options.useFactory ? await options.useFactory() : options;\n\n return this.forRoot(resolvedOptions);\n }\n\n /**\n * Create configuration driver based on options\n */\n private static createDriver(options: ConfigModuleOptions): ConfigDriver {\n const driverType = options.driver || 'env';\n\n switch (driverType) {\n case 'env':\n const envDriver = new EnvDriver({\n envFilePath: options.envFilePath,\n ignoreEnvFile: options.ignoreEnvFile,\n expandVariables: options.expandVariables,\n envPrefix: options.envPrefix,\n globalName: options.globalName,\n });\n envDriver.load();\n\n // Merge custom load function if provided\n if (options.load) {\n this.mergeCustomConfig(envDriver, options.load);\n }\n\n return envDriver;\n\n case 'file':\n const fileDriver = new FileDriver({\n config: typeof options.load === 'object' ? options.load : undefined,\n });\n return fileDriver;\n\n default:\n throw new Error(`Unknown configuration driver: ${driverType}`);\n }\n }\n\n /**\n * Merge custom configuration into driver\n */\n private static mergeCustomConfig(\n driver: ConfigDriver,\n load: Record<string, any> | (() => Record<string, any> | Promise<Record<string, any>>)\n ): void {\n const customConfig = typeof load === 'function' ? load() : load;\n\n if (customConfig instanceof Promise) {\n customConfig.then((config) => {\n Object.assign(driver.all(), config);\n });\n } else {\n Object.assign(driver.all(), customConfig);\n }\n }\n}\n","/**\n * Get nested value from object using dot notation\n *\n * @param obj - Source object\n * @param path - Dot-notated path (e.g., 'database.host')\n * @param defaultValue - Default value if path not found\n * @returns Value at path or default value\n *\n * @example\n * ```typescript\n * const config = { database: { host: 'localhost' } };\n * getNestedValue(config, 'database.host'); // 'localhost'\n * getNestedValue(config, 'database.port', 5432); // 5432\n * ```\n */\nexport function getNestedValue<T = any>(\n obj: Record<string, any>,\n path: string,\n defaultValue?: T\n): T | undefined {\n const keys = path.split('.');\n let current: any = obj;\n\n for (const key of keys) {\n if (current === null || current === undefined) {\n return defaultValue;\n }\n current = current[key];\n }\n\n return current !== undefined ? current : defaultValue;\n}\n\n/**\n * Check if nested path exists in object\n *\n * @param obj - Source object\n * @param path - Dot-notated path\n * @returns True if path exists\n */\nexport function hasNestedValue(obj: Record<string, any>, path: string): boolean {\n const keys = path.split('.');\n let current: any = obj;\n\n for (const key of keys) {\n if (current === null || current === undefined || !(key in current)) {\n return false;\n }\n current = current[key];\n }\n\n return true;\n}\n","import type { ConfigDriver } from '../interfaces/config-driver.interface';\nimport { getNestedValue, hasNestedValue } from '../utils/get-nested-value.util';\n\n/**\n * Environment Variable Configuration Driver\n *\n * Loads configuration from environment variables (process.env).\n * Supports .env files via dotenv.\n */\nexport class EnvDriver implements ConfigDriver {\n private config: Record<string, any> = {};\n private loaded = false;\n\n constructor(\n private options: {\n envFilePath?: string | string[];\n ignoreEnvFile?: boolean;\n expandVariables?: boolean;\n envPrefix?: string | false;\n globalName?: string; // Custom global variable name\n } = {}\n ) {}\n\n /**\n * Load environment variables\n */\n load(): Record<string, any> {\n if (this.loaded) {\n console.log('[EnvDriver] Already loaded, returning cached config');\n return this.config;\n }\n\n console.log('[EnvDriver] Loading environment variables...');\n console.log('[EnvDriver] Options:', { ...this.options });\n\n // Load .env file if not ignored\n if (!this.options.ignoreEnvFile) {\n this.loadDotEnv();\n }\n\n // Get global config name (default: __APP_CONFIG__)\n const globalName = this.options.globalName || '__APP_CONFIG__';\n\n // Try to load from custom global variable first (browser environment)\n if (typeof window !== 'undefined' && (window as any)[globalName]) {\n this.config = { ...(window as any)[globalName] };\n console.log(\n `[EnvDriver] Loaded config from window.${globalName}:`,\n Object.keys(this.config).length,\n 'keys'\n );\n }\n // Fallback to process.env (Node.js environment or backward compatibility)\n else if (typeof process !== 'undefined' && process.env) {\n this.config = { ...process.env };\n console.log(\n '[EnvDriver] Loaded config from process.env:',\n Object.keys(this.config).length,\n 'keys'\n );\n }\n // No config source available\n else {\n console.warn(\n '[EnvDriver] No config source available (neither window.' + globalName + ' nor process.env)'\n );\n this.config = {};\n }\n\n console.log('[EnvDriver] Initial config keys:', [\n ...Object.keys(this.config).filter((k) => k.includes('APP') || k.includes('VITE')),\n ]);\n\n // Strip prefix if configured\n if (this.options.envPrefix !== false) {\n console.log('[EnvDriver] Stripping prefix...');\n this.stripPrefix();\n console.log('[EnvDriver] After stripPrefix, config keys:', [\n ...Object.keys(this.config).filter((k) => k.includes('APP') || k.includes('VITE')),\n ]);\n }\n\n // Expand variables if enabled\n if (this.options.expandVariables) {\n this.expandEnvVariables();\n }\n\n this.loaded = true;\n console.log('[EnvDriver] Load complete. Sample values:', {\n APP_NAME: this.config.APP_NAME,\n VITE_APP_NAME: this.config.VITE_APP_NAME,\n });\n return this.config;\n }\n\n /**\n * Get configuration value\n */\n get<T = any>(key: string, defaultValue?: T): T | undefined {\n if (!this.loaded) {\n this.load();\n }\n const value = getNestedValue(this.config, key, defaultValue);\n console.log(`[EnvDriver] get(\"${key}\", \"${defaultValue}\") = \"${value}\"`);\n return value;\n }\n\n /**\n * Check if key exists\n */\n has(key: string): boolean {\n if (!this.loaded) {\n this.load();\n }\n return hasNestedValue(this.config, key);\n }\n\n /**\n * Get all configuration\n */\n all(): Record<string, any> {\n if (!this.loaded) {\n this.load();\n }\n return { ...this.config };\n }\n\n /**\n * Load .env file using dotenv\n */\n private loadDotEnv(): void {\n try {\n // Try to load dotenv\n const dotenv = require('dotenv');\n const paths = Array.isArray(this.options.envFilePath)\n ? this.options.envFilePath\n : [this.options.envFilePath || '.env'];\n\n for (const path of paths) {\n dotenv.config({ path });\n }\n } catch (error) {\n // dotenv not installed, skip\n }\n }\n\n /**\n * Expand environment variables (e.g., ${VAR_NAME})\n */\n private expandEnvVariables(): void {\n const regex = /\\$\\{([^}]+)\\}/g;\n\n const expand = (value: string): string => {\n return value.replace(regex, (_, key) => {\n return this.config[key] || '';\n });\n };\n\n for (const [key, value] of Object.entries(this.config)) {\n if (typeof value === 'string' && value.includes('${')) {\n this.config[key] = expand(value);\n }\n }\n }\n\n /**\n * Strip environment variable prefix\n * Auto-detects framework (Vite, Next.js) or uses custom prefix\n */\n private stripPrefix(): void {\n let prefix = this.options.envPrefix;\n\n // Auto-detect framework prefix\n if (prefix === 'auto' || prefix === undefined) {\n // Check for Vite (import.meta.env exists or VITE_ variables present)\n const hasViteVars = Object.keys(this.config).some((key) => key.startsWith('VITE_'));\n if (hasViteVars || typeof import.meta !== 'undefined') {\n prefix = 'VITE_';\n }\n // Check for Next.js (NEXT_PUBLIC_ variables present)\n else if (Object.keys(this.config).some((key) => key.startsWith('NEXT_PUBLIC_'))) {\n prefix = 'NEXT_PUBLIC_';\n }\n // No framework detected, don't strip\n else {\n return;\n }\n }\n\n // Strip the prefix from all matching keys\n if (typeof prefix === 'string' && prefix.length > 0) {\n const newConfig: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(this.config)) {\n if (key.startsWith(prefix)) {\n // Add both prefixed and unprefixed versions\n const unprefixedKey = key.substring(prefix.length);\n newConfig[unprefixedKey] = value;\n newConfig[key] = value; // Keep original too\n } else {\n newConfig[key] = value;\n }\n }\n\n this.config = newConfig;\n }\n }\n}\n","import type { ConfigDriver } from '@/interfaces/config-driver.interface';\nimport { getNestedValue, hasNestedValue } from '@/utils/get-nested-value.util';\n\n/**\n * File-based Configuration Driver\n *\n * Loads configuration from TypeScript/JavaScript files.\n * This is a server-side only driver. For client-side, use the Vite plugin.\n *\n * @see packages/abdokouta/config/src/plugins/vite-config.plugin.ts\n */\nexport class FileDriver implements ConfigDriver {\n private config: Record<string, any> = {};\n private loaded = false;\n\n constructor(\n options: {\n config?: Record<string, any>;\n } = {}\n ) {\n // Pre-loaded config from Vite plugin or server\n if (options.config) {\n this.config = options.config;\n this.loaded = true;\n }\n }\n\n /**\n * Load configuration\n * Config should be pre-loaded via Vite plugin or passed in constructor\n */\n async load(): Promise<Record<string, any>> {\n if (this.loaded) {\n return this.config;\n }\n\n // If running on server (Node.js), throw error\n const isServer =\n typeof globalThis !== 'undefined' &&\n typeof (globalThis as typeof globalThis & { window?: any }).window === 'undefined';\n\n if (isServer) {\n throw new Error(\n 'FileDriver requires pre-loaded configuration. ' +\n 'Use Vite plugin for client-side or pass config in constructor for server-side.'\n );\n }\n\n this.loaded = true;\n return this.config;\n }\n\n /**\n * Get configuration value\n */\n get<T = any>(key: string, defaultValue?: T): T | undefined {\n if (!this.loaded) {\n throw new Error('Configuration not loaded. Call load() first or use async initialization.');\n }\n return getNestedValue(this.config, key, defaultValue);\n }\n\n /**\n * Check if key exists\n */\n has(key: string): boolean {\n if (!this.loaded) {\n throw new Error('Configuration not loaded. Call load() first or use async initialization.');\n }\n return hasNestedValue(this.config, key);\n }\n\n /**\n * Get all configuration\n */\n all(): Record<string, any> {\n if (!this.loaded) {\n throw new Error('Configuration not loaded. Call load() first or use async initialization.');\n }\n return { ...this.config };\n }\n}\n","import { Inject, Injectable } from '@abdokouta/react-di';\n\nimport { CONFIG_DRIVER } from '@/constants/tokens.constant';\nimport type { ConfigDriver } from '@/interfaces/config-driver.interface';\nimport type { ConfigServiceInterface } from '@/interfaces/config-service.interface';\n\n/**\n * Configuration Service\n *\n * Provides type-safe access to configuration values with various getter methods.\n * Similar to NestJS ConfigService.\n *\n * @example\n * ```typescript\n * class MyService {\n * constructor(private config: ConfigService) {}\n *\n * getDbConfig() {\n * return {\n * host: this.config.getString('DB_HOST', 'localhost'),\n * port: this.config.getNumber('DB_PORT', 5432),\n * ssl: this.config.getBool('DB_SSL', false),\n * };\n * }\n * }\n * ```\n */\n@Injectable()\nexport class ConfigService implements ConfigServiceInterface {\n constructor(\n @Inject(CONFIG_DRIVER)\n private driver: ConfigDriver\n ) {}\n\n /**\n * Get configuration value\n */\n get<T = any>(key: string, defaultValue?: T): T | undefined {\n return this.driver.get<T>(key, defaultValue);\n }\n\n /**\n * Get configuration value or throw if not found\n */\n getOrThrow<T = any>(key: string): T {\n const value = this.get<T>(key);\n if (value === undefined) {\n throw new Error(`Configuration key \"${key}\" is required but not set`);\n }\n return value;\n }\n\n /**\n * Get string value\n */\n getString(key: string, defaultValue?: string): string | undefined {\n const value = this.get(key, defaultValue);\n return value !== undefined ? String(value) : undefined;\n }\n\n /**\n * Get string value or throw\n */\n getStringOrThrow(key: string): string {\n return String(this.getOrThrow(key));\n }\n\n /**\n * Get number value\n */\n getNumber(key: string, defaultValue?: number): number | undefined {\n const value = this.get(key, defaultValue);\n if (value === undefined) {\n return undefined;\n }\n const parsed = Number(value);\n return isNaN(parsed) ? defaultValue : parsed;\n }\n\n /**\n * Get number value or throw\n */\n getNumberOrThrow(key: string): number {\n const value = this.getNumber(key);\n if (value === undefined) {\n throw new Error(`Configuration key \"${key}\" is required but not set`);\n }\n return value;\n }\n\n /**\n * Get boolean value\n * Treats 'true', '1', 'yes', 'on' as true\n */\n getBool(key: string, defaultValue?: boolean): boolean | undefined {\n const value = this.get(key, defaultValue);\n if (value === undefined) {\n return undefined;\n }\n if (typeof value === 'boolean') {\n return value;\n }\n return ['true', '1', 'yes', 'on'].includes(String(value).toLowerCase());\n }\n\n /**\n * Get boolean value or throw\n */\n getBoolOrThrow(key: string): boolean {\n const value = this.getBool(key);\n if (value === undefined) {\n throw new Error(`Configuration key \"${key}\" is required but not set`);\n }\n return value;\n }\n\n /**\n * Get array value (comma-separated string or actual array)\n */\n getArray(key: string, defaultValue?: string[]): string[] | undefined {\n const value = this.get(key, defaultValue);\n if (value === undefined) {\n return undefined;\n }\n if (Array.isArray(value)) {\n return value.map(String);\n }\n return String(value)\n .split(',')\n .map((v) => v.trim())\n .filter(Boolean);\n }\n\n /**\n * Get JSON value\n */\n getJson<T = any>(key: string, defaultValue?: T): T | undefined {\n const value = this.get(key, defaultValue);\n if (value === undefined) {\n return undefined;\n }\n if (typeof value === 'object') {\n return value as T;\n }\n try {\n return JSON.parse(String(value)) as T;\n } catch {\n return defaultValue;\n }\n }\n\n /**\n * Check if configuration key exists\n */\n has(key: string): boolean {\n return this.driver.has(key);\n }\n\n /**\n * Get all configuration values\n */\n all(): Record<string, any> {\n return this.driver.all();\n }\n\n /**\n * Clear cache (no-op since we don't cache in ConfigService)\n */\n clearCache(): void {\n // No-op - caching should be done at a higher level if needed\n }\n}\n","/**\n * Dependency Injection Tokens\n *\n * Used for injecting configuration dependencies.\n */\n\n/**\n * Configuration driver token\n *\n * @example\n * ```typescript\n * @Inject(CONFIG_DRIVER)\n * private driver: ConfigDriver\n * ```\n */\nexport const CONFIG_DRIVER = Symbol('CONFIG_DRIVER');\n\n/**\n * Configuration options token\n *\n * @example\n * ```typescript\n * @Inject(CONFIG_OPTIONS)\n * private options: ConfigModuleOptions\n * ```\n */\nexport const CONFIG_OPTIONS = Symbol('CONFIG_OPTIONS');\n\n/**\n * Configuration service token\n *\n * @example\n * ```typescript\n * @Inject(CONFIG_SERVICE)\n * private config: ConfigService\n * ```\n */\nexport const CONFIG_SERVICE = Symbol('CONFIG_SERVICE');\n","/**\n * Define Config Utility\n *\n * Helper function to define config module options with type safety.\n *\n * @module @abdokouta/config\n */\n\nimport type { ConfigModuleOptions } from '../interfaces/config-module-options.interface';\n\n/**\n * Helper function to define config module options with type safety\n *\n * Provides IDE autocomplete and type checking for configuration objects.\n * This pattern is consistent with modern tooling (Vite, Vitest, etc.).\n *\n * @param config - The config module options object\n * @returns The same configuration object with proper typing\n *\n * @example\n * ```typescript\n * // config.config.ts\n * import { defineConfig } from '@abdokouta/config';\n *\n * export default defineConfig({\n * driver: 'env',\n * ignoreEnvFile: true,\n * isGlobal: true,\n * envPrefix: 'auto',\n * });\n * ```\n */\nexport function defineConfig(config: ConfigModuleOptions): ConfigModuleOptions {\n return config;\n}\n","/**\n * Load Config File Utility\n *\n * Dynamically loads and parses a config file.\n */\n\n/**\n * Load and parse config file\n *\n * @param filePath - Absolute path to the config file\n * @returns Parsed config object\n */\nexport async function loadConfigFile(filePath: string): Promise<Record<string, any>> {\n try {\n // Dynamic import of the config file\n // @ts-ignore - Dynamic import path\n const module = await import(/* @vite-ignore */ filePath);\n\n // Extract config object (could be default export or named export)\n const config = module.default || module;\n\n // If it's a function, call it\n if (typeof config === 'function') {\n return await config();\n }\n\n return config;\n } catch (error) {\n console.warn(`[vite-plugin-config] Failed to load config file: ${filePath}`, error);\n return {};\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abdokouta/react-config",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "NestJS-inspired configuration management with multiple drivers (Env, File, Firebase) for React",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Abdelrhman Kouta",
|
|
8
|
+
"email": "abdelrhman@pixielity.com",
|
|
9
|
+
"url": "https://github.com/abdokouta"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/abdokouta/config.git",
|
|
14
|
+
"directory": "packages/config"
|
|
15
|
+
},
|
|
16
|
+
"bugs": {
|
|
17
|
+
"url": "https://github.com/abdokouta/config/issues"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/abdokouta/config#readme",
|
|
5
20
|
"keywords": [
|
|
6
21
|
"react",
|
|
7
22
|
"config",
|
|
@@ -9,17 +24,11 @@
|
|
|
9
24
|
"environment",
|
|
10
25
|
"nestjs",
|
|
11
26
|
"env",
|
|
12
|
-
"dotenv"
|
|
27
|
+
"dotenv",
|
|
28
|
+
"dependency-injection",
|
|
29
|
+
"di"
|
|
13
30
|
],
|
|
14
|
-
"
|
|
15
|
-
"type": "git",
|
|
16
|
-
"url": "https://github.com/pixielity-inc/react-config.git"
|
|
17
|
-
},
|
|
18
|
-
"license": "MIT",
|
|
19
|
-
"author": "Refine",
|
|
20
|
-
"main": "dist/index.js",
|
|
21
|
-
"module": "dist/index.mjs",
|
|
22
|
-
"types": "dist/index.d.ts",
|
|
31
|
+
"type": "module",
|
|
23
32
|
"exports": {
|
|
24
33
|
".": {
|
|
25
34
|
"types": "./dist/index.d.ts",
|
|
@@ -32,22 +41,22 @@
|
|
|
32
41
|
"require": "./dist/vite-plugin.js"
|
|
33
42
|
}
|
|
34
43
|
},
|
|
35
|
-
"
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
+
"main": "./dist/index.js",
|
|
45
|
+
"module": "./dist/index.mjs",
|
|
46
|
+
"types": "./dist/index.d.ts",
|
|
47
|
+
"files": [
|
|
48
|
+
"dist",
|
|
49
|
+
"config",
|
|
50
|
+
"README.md",
|
|
51
|
+
"LICENSE"
|
|
52
|
+
],
|
|
44
53
|
"dependencies": {
|
|
45
|
-
"@abdokouta/react-
|
|
46
|
-
"@abdokouta/react-
|
|
54
|
+
"@abdokouta/react-di": "^2.0.0",
|
|
55
|
+
"@abdokouta/react-support": "^1.0.0"
|
|
47
56
|
},
|
|
48
57
|
"peerDependencies": {
|
|
49
58
|
"dotenv": "^16.0.0",
|
|
50
|
-
"vite": "^5.0.0"
|
|
59
|
+
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
|
|
51
60
|
},
|
|
52
61
|
"peerDependenciesMeta": {
|
|
53
62
|
"dotenv": {
|
|
@@ -65,6 +74,7 @@
|
|
|
65
74
|
"@types/node": "^25.5.0",
|
|
66
75
|
"@vitest/ui": "^4.1.2",
|
|
67
76
|
"dotenv": "^17.3.1",
|
|
77
|
+
"jsdom": "^29.0.1",
|
|
68
78
|
"prettier": "^3.8.1",
|
|
69
79
|
"tsup": "^8.5.1",
|
|
70
80
|
"typescript": "^6.0.2",
|
|
@@ -72,6 +82,26 @@
|
|
|
72
82
|
"vitest": "^4.1.2"
|
|
73
83
|
},
|
|
74
84
|
"publishConfig": {
|
|
75
|
-
"access": "public"
|
|
85
|
+
"access": "public",
|
|
86
|
+
"registry": "https://registry.npmjs.org/"
|
|
87
|
+
},
|
|
88
|
+
"engines": {
|
|
89
|
+
"node": ">=18.0.0",
|
|
90
|
+
"pnpm": ">=9.0.0"
|
|
91
|
+
},
|
|
92
|
+
"sideEffects": false,
|
|
93
|
+
"scripts": {
|
|
94
|
+
"build": "tsup",
|
|
95
|
+
"dev": "tsup --watch",
|
|
96
|
+
"clean": "rm -rf dist node_modules/.cache",
|
|
97
|
+
"typecheck": "tsc --noEmit",
|
|
98
|
+
"lint": "eslint . --max-warnings 0",
|
|
99
|
+
"lint:fix": "eslint . --fix",
|
|
100
|
+
"format": "prettier --write .",
|
|
101
|
+
"format:check": "prettier --check .",
|
|
102
|
+
"test": "vitest run",
|
|
103
|
+
"test:watch": "vitest",
|
|
104
|
+
"test:coverage": "vitest run --coverage",
|
|
105
|
+
"release": "pnpm publish --access public --no-git-checks"
|
|
76
106
|
}
|
|
77
|
-
}
|
|
107
|
+
}
|
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Basic Config Usage Example
|
|
3
|
-
*
|
|
4
|
-
* This example demonstrates the fundamental configuration operations:
|
|
5
|
-
* - Environment variable access
|
|
6
|
-
* - Type-safe getters
|
|
7
|
-
* - Default values
|
|
8
|
-
* - Nested configuration
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* Run this example:
|
|
12
|
-
* ```bash
|
|
13
|
-
* ts-node examples/01-basic-usage.ts
|
|
14
|
-
* ```
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { ConfigModule, ConfigService } from '@abdokouta/config';
|
|
18
|
-
import { Inversiland } from '@abdokouta/react-di';
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Initialize the config module
|
|
22
|
-
*/
|
|
23
|
-
async function setupConfig() {
|
|
24
|
-
// Set some example environment variables
|
|
25
|
-
process.env.APP_NAME = 'My Application';
|
|
26
|
-
process.env.APP_PORT = '3000';
|
|
27
|
-
process.env.APP_DEBUG = 'true';
|
|
28
|
-
process.env.APP_URL = 'http://localhost:3000';
|
|
29
|
-
process.env.ALLOWED_HOSTS = 'localhost,127.0.0.1,example.com';
|
|
30
|
-
process.env.DATABASE_CONFIG = JSON.stringify({
|
|
31
|
-
host: 'localhost',
|
|
32
|
-
port: 5432,
|
|
33
|
-
database: 'myapp',
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// Create the application module with config
|
|
37
|
-
const app = await Inversiland.run({
|
|
38
|
-
module: class AppModule {},
|
|
39
|
-
imports: [
|
|
40
|
-
ConfigModule.forRoot({
|
|
41
|
-
driver: 'env',
|
|
42
|
-
ignoreEnvFile: true, // Use process.env directly for this example
|
|
43
|
-
isGlobal: true,
|
|
44
|
-
}),
|
|
45
|
-
],
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
return app.get(ConfigService);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Example 1: Basic string values
|
|
53
|
-
*/
|
|
54
|
-
function stringValues(config: ConfigService) {
|
|
55
|
-
console.log('\n=== Example 1: String Values ===\n');
|
|
56
|
-
|
|
57
|
-
// Get string value
|
|
58
|
-
const appName = config.getString('APP_NAME');
|
|
59
|
-
console.log(`✓ APP_NAME: "${appName}"`);
|
|
60
|
-
|
|
61
|
-
// Get string with default
|
|
62
|
-
const appEnv = config.getString('APP_ENV', 'development');
|
|
63
|
-
console.log(`✓ APP_ENV: "${appEnv}" (using default)`);
|
|
64
|
-
|
|
65
|
-
// Get URL
|
|
66
|
-
const appUrl = config.getString('APP_URL');
|
|
67
|
-
console.log(`✓ APP_URL: "${appUrl}"`);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Example 2: Number values
|
|
72
|
-
*/
|
|
73
|
-
function numberValues(config: ConfigService) {
|
|
74
|
-
console.log('\n=== Example 2: Number Values ===\n');
|
|
75
|
-
|
|
76
|
-
// Get number value
|
|
77
|
-
const port = config.getNumber('APP_PORT');
|
|
78
|
-
console.log(`✓ APP_PORT: ${port} (type: ${typeof port})`);
|
|
79
|
-
|
|
80
|
-
// Get number with default
|
|
81
|
-
const timeout = config.getNumber('APP_TIMEOUT', 5000);
|
|
82
|
-
console.log(`✓ APP_TIMEOUT: ${timeout} (using default)`);
|
|
83
|
-
|
|
84
|
-
// Get number that doesn't exist
|
|
85
|
-
const maxConnections = config.getNumber('MAX_CONNECTIONS', 100);
|
|
86
|
-
console.log(`✓ MAX_CONNECTIONS: ${maxConnections} (using default)`);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Example 3: Boolean values
|
|
91
|
-
*/
|
|
92
|
-
function booleanValues(config: ConfigService) {
|
|
93
|
-
console.log('\n=== Example 3: Boolean Values ===\n');
|
|
94
|
-
|
|
95
|
-
// Get boolean value (true)
|
|
96
|
-
const debug = config.getBool('APP_DEBUG');
|
|
97
|
-
console.log(`✓ APP_DEBUG: ${debug} (type: ${typeof debug})`);
|
|
98
|
-
|
|
99
|
-
// Get boolean with default
|
|
100
|
-
const enableCache = config.getBool('ENABLE_CACHE', true);
|
|
101
|
-
console.log(`✓ ENABLE_CACHE: ${enableCache} (using default)`);
|
|
102
|
-
|
|
103
|
-
// Test various boolean formats
|
|
104
|
-
process.env.TEST_TRUE_1 = 'true';
|
|
105
|
-
process.env.TEST_TRUE_2 = '1';
|
|
106
|
-
process.env.TEST_TRUE_3 = 'yes';
|
|
107
|
-
process.env.TEST_TRUE_4 = 'on';
|
|
108
|
-
process.env.TEST_FALSE = 'false';
|
|
109
|
-
|
|
110
|
-
console.log(`✓ "true" → ${config.getBool('TEST_TRUE_1')}`);
|
|
111
|
-
console.log(`✓ "1" → ${config.getBool('TEST_TRUE_2')}`);
|
|
112
|
-
console.log(`✓ "yes" → ${config.getBool('TEST_TRUE_3')}`);
|
|
113
|
-
console.log(`✓ "on" → ${config.getBool('TEST_TRUE_4')}`);
|
|
114
|
-
console.log(`✓ "false" → ${config.getBool('TEST_FALSE')}`);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Example 4: Array values
|
|
119
|
-
*/
|
|
120
|
-
function arrayValues(config: ConfigService) {
|
|
121
|
-
console.log('\n=== Example 4: Array Values ===\n');
|
|
122
|
-
|
|
123
|
-
// Get array from comma-separated string
|
|
124
|
-
const allowedHosts = config.getArray('ALLOWED_HOSTS');
|
|
125
|
-
console.log(`✓ ALLOWED_HOSTS:`, allowedHosts);
|
|
126
|
-
|
|
127
|
-
// Get array with default
|
|
128
|
-
const corsOrigins = config.getArray('CORS_ORIGINS', ['http://localhost:3000']);
|
|
129
|
-
console.log(`✓ CORS_ORIGINS:`, corsOrigins, '(using default)');
|
|
130
|
-
|
|
131
|
-
// Empty array
|
|
132
|
-
const emptyArray = config.getArray('EMPTY_ARRAY', []);
|
|
133
|
-
console.log(`✓ EMPTY_ARRAY:`, emptyArray, '(using default)');
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Example 5: JSON values
|
|
138
|
-
*/
|
|
139
|
-
function jsonValues(config: ConfigService) {
|
|
140
|
-
console.log('\n=== Example 5: JSON Values ===\n');
|
|
141
|
-
|
|
142
|
-
// Get JSON object
|
|
143
|
-
const dbConfig = config.getJson('DATABASE_CONFIG');
|
|
144
|
-
console.log(`✓ DATABASE_CONFIG:`, dbConfig);
|
|
145
|
-
|
|
146
|
-
// Get JSON with default
|
|
147
|
-
const apiConfig = config.getJson('API_CONFIG', {
|
|
148
|
-
url: 'http://localhost:3000',
|
|
149
|
-
timeout: 5000,
|
|
150
|
-
});
|
|
151
|
-
console.log(`✓ API_CONFIG:`, apiConfig, '(using default)');
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Example 6: Check if keys exist
|
|
156
|
-
*/
|
|
157
|
-
function checkExistence(config: ConfigService) {
|
|
158
|
-
console.log('\n=== Example 6: Check Existence ===\n');
|
|
159
|
-
|
|
160
|
-
// Check existing key
|
|
161
|
-
const hasAppName = config.has('APP_NAME');
|
|
162
|
-
console.log(`✓ has('APP_NAME'): ${hasAppName}`);
|
|
163
|
-
|
|
164
|
-
// Check non-existent key
|
|
165
|
-
const hasApiKey = config.has('API_KEY');
|
|
166
|
-
console.log(`✓ has('API_KEY'): ${hasApiKey}`);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Example 7: Required values (OrThrow)
|
|
171
|
-
*/
|
|
172
|
-
function requiredValues(config: ConfigService) {
|
|
173
|
-
console.log('\n=== Example 7: Required Values ===\n');
|
|
174
|
-
|
|
175
|
-
try {
|
|
176
|
-
// Get required value that exists
|
|
177
|
-
const appName = config.getStringOrThrow('APP_NAME');
|
|
178
|
-
console.log(`✓ getStringOrThrow('APP_NAME'): "${appName}"`);
|
|
179
|
-
|
|
180
|
-
// Try to get required value that doesn't exist
|
|
181
|
-
const apiKey = config.getStringOrThrow('API_KEY');
|
|
182
|
-
console.log(`✓ getStringOrThrow('API_KEY'): "${apiKey}"`);
|
|
183
|
-
} catch (error) {
|
|
184
|
-
console.log(`✗ Error: ${(error as Error).message}`);
|
|
185
|
-
console.log(` 💡 Use OrThrow methods for required configuration`);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Example 8: Get all configuration
|
|
191
|
-
*/
|
|
192
|
-
function getAllConfig(config: ConfigService) {
|
|
193
|
-
console.log('\n=== Example 8: Get All Configuration ===\n');
|
|
194
|
-
|
|
195
|
-
const allConfig = config.all();
|
|
196
|
-
const keys = Object.keys(allConfig).filter(k => k.startsWith('APP_') || k.startsWith('ALLOWED_'));
|
|
197
|
-
|
|
198
|
-
console.log('✓ All APP_* and ALLOWED_* configuration:');
|
|
199
|
-
keys.forEach(key => {
|
|
200
|
-
console.log(` - ${key}: ${allConfig[key]}`);
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Example 9: Practical use case - Database configuration
|
|
206
|
-
*/
|
|
207
|
-
function databaseConfig(config: ConfigService) {
|
|
208
|
-
console.log('\n=== Example 9: Database Configuration ===\n');
|
|
209
|
-
|
|
210
|
-
// Set database environment variables
|
|
211
|
-
process.env.DB_HOST = 'localhost';
|
|
212
|
-
process.env.DB_PORT = '5432';
|
|
213
|
-
process.env.DB_NAME = 'myapp';
|
|
214
|
-
process.env.DB_USER = 'admin';
|
|
215
|
-
process.env.DB_PASSWORD = 'secret123';
|
|
216
|
-
process.env.DB_SSL = 'true';
|
|
217
|
-
process.env.DB_POOL_MIN = '2';
|
|
218
|
-
process.env.DB_POOL_MAX = '10';
|
|
219
|
-
|
|
220
|
-
// Build database configuration object
|
|
221
|
-
const dbConfig = {
|
|
222
|
-
host: config.getString('DB_HOST', 'localhost'),
|
|
223
|
-
port: config.getNumber('DB_PORT', 5432),
|
|
224
|
-
database: config.getString('DB_NAME', 'myapp'),
|
|
225
|
-
username: config.getString('DB_USER'),
|
|
226
|
-
password: config.getString('DB_PASSWORD'),
|
|
227
|
-
ssl: config.getBool('DB_SSL', false),
|
|
228
|
-
pool: {
|
|
229
|
-
min: config.getNumber('DB_POOL_MIN', 2),
|
|
230
|
-
max: config.getNumber('DB_POOL_MAX', 10),
|
|
231
|
-
},
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
console.log('✓ Database configuration:');
|
|
235
|
-
console.log(JSON.stringify(dbConfig, null, 2));
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Example 10: Practical use case - Feature flags
|
|
240
|
-
*/
|
|
241
|
-
function featureFlags(config: ConfigService) {
|
|
242
|
-
console.log('\n=== Example 10: Feature Flags ===\n');
|
|
243
|
-
|
|
244
|
-
// Set feature flags
|
|
245
|
-
process.env.FEATURE_CACHE = 'true';
|
|
246
|
-
process.env.FEATURE_LOGGING = 'true';
|
|
247
|
-
process.env.FEATURE_METRICS = 'false';
|
|
248
|
-
process.env.FEATURE_ANALYTICS = '1';
|
|
249
|
-
|
|
250
|
-
// Read feature flags
|
|
251
|
-
const features = {
|
|
252
|
-
cache: config.getBool('FEATURE_CACHE', false),
|
|
253
|
-
logging: config.getBool('FEATURE_LOGGING', false),
|
|
254
|
-
metrics: config.getBool('FEATURE_METRICS', false),
|
|
255
|
-
analytics: config.getBool('FEATURE_ANALYTICS', false),
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
console.log('✓ Feature flags:');
|
|
259
|
-
Object.entries(features).forEach(([name, enabled]) => {
|
|
260
|
-
console.log(` - ${name}: ${enabled ? '✅ enabled' : '❌ disabled'}`);
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Run all examples
|
|
266
|
-
*/
|
|
267
|
-
async function main() {
|
|
268
|
-
console.log('╔════════════════════════════════════════╗');
|
|
269
|
-
console.log('║ Config Basic Usage Examples ║');
|
|
270
|
-
console.log('╚════════════════════════════════════════╝');
|
|
271
|
-
|
|
272
|
-
const config = await setupConfig();
|
|
273
|
-
|
|
274
|
-
stringValues(config);
|
|
275
|
-
numberValues(config);
|
|
276
|
-
booleanValues(config);
|
|
277
|
-
arrayValues(config);
|
|
278
|
-
jsonValues(config);
|
|
279
|
-
checkExistence(config);
|
|
280
|
-
requiredValues(config);
|
|
281
|
-
getAllConfig(config);
|
|
282
|
-
databaseConfig(config);
|
|
283
|
-
featureFlags(config);
|
|
284
|
-
|
|
285
|
-
console.log('\n✅ All examples completed successfully!\n');
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// Run the examples
|
|
289
|
-
main().catch(console.error);
|