# @hsuite/smart-config - Configuration Management

> ⚙️ **Dynamic configuration management for HSuite applications**

Advanced configuration management module providing environment-based settings, secure credential management, and dynamic configuration updates for distributed blockchain applications.

***

## Table of Contents

* [Quick Start](#quick-start)
* [Architecture](#architecture)
* [API Reference](#api-reference)
* [Guides](#guides)
* [Examples](#examples)
* [Integration](#integration)

***

## Quick Start

### Installation

```bash
npm install @hsuite/smart-config
```

### Basic Setup

```typescript
import { SmartConfigModule } from '@hsuite/smart-config';

@Module({
  imports: [
    SmartConfigModule.forRoot({
      envFilePath: ['.env.local', '.env'],
      isGlobal: true,
      expandVariables: true
    })
  ]
})
export class AppModule {}
```

### Basic Usage

```typescript
@Injectable()
export class ConfigService {
  constructor(private smartConfig: SmartConfigService) {}

  getApiKey(): string {
    return this.smartConfig.get('API_KEY');
  }

  getDatabaseConfig(): DatabaseConfig {
    return this.smartConfig.getDatabaseConfig();
  }
}
```

***

## Architecture

### Core Components

#### ⚙️ **Configuration Management**

* **`SmartConfigService`** - Core configuration service with type safety
* **Environment Loading** - Multi-environment configuration support
* **Dynamic Updates** - Runtime configuration updates

#### 🔒 **Security Features**

* **Credential Encryption** - Automatic encryption for sensitive values
* **Secret Management** - Secure handling of API keys and passwords
* **Environment Isolation** - Separate configs for different environments

#### 🔄 **Dynamic Configuration**

* **Hot Reloading** - Configuration updates without restart
* **Validation** - Schema-based configuration validation
* **Type Safety** - Full TypeScript support for configuration objects

### Module Structure

```
src/
├── interfaces/            # Configuration interfaces
├── services/             # Configuration services
├── decorators/           # Configuration decorators
├── validators/           # Configuration validators
├── smart-config.service.ts # Core configuration service
├── smart-config.module.ts  # Module configuration
└── index.ts             # Public API exports
```

***

## API Reference

### SmartConfigModule

#### Static Methods

**`forRoot(options: SmartConfigOptions): DynamicModule`**

Configures the smart config module with static options.

```typescript
interface SmartConfigOptions {
  envFilePath?: string | string[];
  isGlobal?: boolean;
  expandVariables?: boolean;
  validationSchema?: any;
  cache?: boolean;
}
```

**`forRootAsync(options: SmartConfigAsyncOptions): DynamicModule`**

Configures the smart config module with async dependency injection.

### SmartConfigService

#### Core Methods

**`get<T = any>(key: string, defaultValue?: T): T`**

* Retrieves configuration value by key
* **Parameters**: `key` - Configuration key, `defaultValue` - Fallback value
* **Returns**: Configuration value or default

**`getOrThrow<T = any>(key: string): T`**

* Gets configuration value or throws error if not found
* **Parameters**: `key` - Configuration key
* **Throws**: `Error` if key not found

**`getDatabaseConfig(): DatabaseConfig`**

* Returns typed database configuration
* **Returns**: Complete database configuration object

**`getAuthConfig(): AuthConfig`**

* Returns authentication configuration
* **Returns**: Authentication settings with type safety

**`getNetworkConfig(): NetworkConfig`**

* Returns network and blockchain configuration
* **Returns**: Network configuration for all supported chains

***

## Guides

### Environment Configuration Guide

Learn how to set up environment-specific configurations and secrets. Configure validation schemas, environment variable management, and secure credential handling.

### Dynamic Updates Guide

Implement runtime configuration updates and hot reloading. Set up configuration watchers, event-driven updates, and real-time configuration management.

### Validation Guide

Set up configuration validation schemas and type safety. Implement Joi validation, custom validators, and configuration error handling.

***

## Examples

### Complete Module Configuration

```typescript
import { SmartConfigModule } from '@hsuite/smart-config';
import * as Joi from 'joi';

@Module({
  imports: [
    SmartConfigModule.forRoot({
      envFilePath: ['.env.local', '.env', '.env.production'],
      isGlobal: true,
      expandVariables: true,
      cache: true,
      validationSchema: Joi.object({
        NODE_ENV: Joi.string()
          .valid('development', 'production', 'test')
          .default('development'),
        PORT: Joi.number().default(3000),
        DATABASE_URL: Joi.string().required(),
        JWT_SECRET: Joi.string().required().min(32),
        HEDERA_ACCOUNT_ID: Joi.string().pattern(/^0\.0\.\d+$/),
        HEDERA_PRIVATE_KEY: Joi.string().required(),
        API_RATE_LIMIT: Joi.number().default(100),
        ENABLE_CORS: Joi.boolean().default(true)
      })
    })
  ]
})
export class AppModule {}
```

### Environment-Specific Configuration

```typescript
import { Injectable } from '@nestjs/common';
import { SmartConfigService } from '@hsuite/smart-config';

@Injectable()
export class EnvironmentConfigService {
  constructor(private config: SmartConfigService) {}

  // Database Configuration
  getDatabaseConfig() {
    return {
      type: 'postgres',
      host: this.config.get('DB_HOST', 'localhost'),
      port: this.config.get('DB_PORT', 5432),
      username: this.config.get('DB_USERNAME'),
      password: this.config.get('DB_PASSWORD'),
      database: this.config.get('DB_DATABASE'),
      ssl: this.config.get('DB_SSL', false),
      synchronize: this.config.get('DB_SYNCHRONIZE', false),
      logging: this.config.get('DB_LOGGING', false),
      entities: ['dist/**/*.entity{.ts,.js}'],
      migrations: ['dist/migrations/*{.ts,.js}']
    };
  }

  // JWT Configuration
  getJwtConfig() {
    return {
      secret: this.config.getOrThrow('JWT_SECRET'),
      signOptions: {
        expiresIn: this.config.get('JWT_EXPIRES_IN', '24h'),
        issuer: this.config.get('JWT_ISSUER', 'hsuite'),
        audience: this.config.get('JWT_AUDIENCE', 'hsuite-users')
      },
      refreshTokenExpiresIn: this.config.get('JWT_REFRESH_EXPIRES_IN', '7d')
    };
  }

  // Hedera Configuration
  getHederaConfig() {
    return {
      network: this.config.get('HEDERA_NETWORK', 'testnet'),
      accountId: this.config.getOrThrow('HEDERA_ACCOUNT_ID'),
      privateKey: this.config.getOrThrow('HEDERA_PRIVATE_KEY'),
      publicKey: this.config.get('HEDERA_PUBLIC_KEY'),
      mirrorNodeUrl: this.config.get(
        'HEDERA_MIRROR_NODE_URL', 
        'https://testnet.mirrornode.hedera.com'
      ),
      consensusNodeUrl: this.config.get(
        'HEDERA_CONSENSUS_NODE_URL',
        'https://testnet.hedera.com'
      )
    };
  }

  // Redis Configuration
  getRedisConfig() {
    return {
      host: this.config.get('REDIS_HOST', 'localhost'),
      port: this.config.get('REDIS_PORT', 6379),
      password: this.config.get('REDIS_PASSWORD'),
      db: this.config.get('REDIS_DB', 0),
      keyPrefix: this.config.get('REDIS_KEY_PREFIX', 'hsuite:'),
      ttl: this.config.get('REDIS_TTL', 3600),
      maxRetriesPerRequest: this.config.get('REDIS_MAX_RETRIES', 3)
    };
  }

  // API Configuration
  getApiConfig() {
    return {
      port: this.config.get('PORT', 3000),
      host: this.config.get('HOST', '0.0.0.0'),
      globalPrefix: this.config.get('API_PREFIX', 'api'),
      version: this.config.get('API_VERSION', 'v1'),
      documentation: {
        enabled: this.config.get('API_DOCS_ENABLED', true),
        path: this.config.get('API_DOCS_PATH', 'docs')
      },
      rateLimit: {
        windowMs: this.config.get('RATE_LIMIT_WINDOW', 15 * 60 * 1000), // 15 minutes
        max: this.config.get('RATE_LIMIT_MAX', 100),
        message: 'Too many requests from this IP'
      },
      cors: {
        enabled: this.config.get('ENABLE_CORS', true),
        origin: this.config.get('CORS_ORIGIN', '*'),
        credentials: this.config.get('CORS_CREDENTIALS', true)
      }
    };
  }

  // Mail Configuration
  getMailConfig() {
    return {
      transport: {
        host: this.config.get('SMTP_HOST'),
        port: this.config.get('SMTP_PORT', 587),
        secure: this.config.get('SMTP_SECURE', false),
        auth: {
          user: this.config.get('SMTP_USER'),
          pass: this.config.get('SMTP_PASS')
        }
      },
      defaults: {
        from: this.config.get('SMTP_FROM', 'noreply@hsuite.com')
      },
      template: {
        dir: this.config.get('MAIL_TEMPLATE_DIR', './templates'),
        adapter: 'handlebars',
        options: {
          strict: true
        }
      }
    };
  }
}
```

### Dynamic Configuration Updates

```typescript
import { Injectable, OnModuleInit } from '@nestjs/common';
import { SmartConfigService } from '@hsuite/smart-config';
import { EventEmitter2 } from '@nestjs/event-emitter';

@Injectable()
export class DynamicConfigService implements OnModuleInit {
  private configCache = new Map<string, any>();

  constructor(
    private config: SmartConfigService,
    private eventEmitter: EventEmitter2
  ) {}

  onModuleInit() {
    this.setupConfigWatchers();
  }

  async updateConfiguration(key: string, value: any) {
    // Validate new configuration value
    await this.validateConfigUpdate(key, value);

    // Update in cache
    this.configCache.set(key, value);

    // Emit configuration change event
    this.eventEmitter.emit('config.updated', { key, value, timestamp: new Date() });

    // Persist to external config store if needed
    await this.persistConfigChange(key, value);

    return {
      success: true,
      key,
      newValue: value,
      updatedAt: new Date()
    };
  }

  getConfigWithFallback<T>(key: string, fallback: T): T {
    // Check cache first
    if (this.configCache.has(key)) {
      return this.configCache.get(key);
    }

    // Fall back to environment variables
    const envValue = this.config.get(key);
    if (envValue !== undefined) {
      this.configCache.set(key, envValue);
      return envValue;
    }

    // Use provided fallback
    this.configCache.set(key, fallback);
    return fallback;
  }

  async reloadConfiguration() {
    try {
      // Clear cache
      this.configCache.clear();

      // Reload environment variables
      await this.config.reload();

      // Emit reload event
      this.eventEmitter.emit('config.reloaded', { timestamp: new Date() });

      return {
        success: true,
        message: 'Configuration reloaded successfully',
        reloadedAt: new Date()
      };
    } catch (error) {
      throw new Error(`Failed to reload configuration: ${error.message}`);
    }
  }

  getFeatureFlags() {
    return {
      enableNewUI: this.getConfigWithFallback('FEATURE_NEW_UI', false),
      enableBetaFeatures: this.getConfigWithFallback('FEATURE_BETA', false),
      enableAnalytics: this.getConfigWithFallback('FEATURE_ANALYTICS', true),
      enableCaching: this.getConfigWithFallback('FEATURE_CACHING', true),
      maintenanceMode: this.getConfigWithFallback('MAINTENANCE_MODE', false)
    };
  }

  private setupConfigWatchers() {
    // Watch for configuration file changes
    if (this.config.get('ENABLE_CONFIG_WATCHING', false)) {
      // Implementation for file system watching
      console.log('Configuration watching enabled');
    }
  }

  private async validateConfigUpdate(key: string, value: any) {
    // Define validation rules for different config keys
    const validationRules = {
      'API_RATE_LIMIT': (val: any) => Number.isInteger(val) && val > 0,
      'JWT_EXPIRES_IN': (val: any) => typeof val === 'string' && /^\d+[smhd]$/.test(val),
      'HEDERA_ACCOUNT_ID': (val: any) => typeof val === 'string' && /^0\.0\.\d+$/.test(val)
    };

    const validator = validationRules[key];
    if (validator && !validator(value)) {
      throw new Error(`Invalid value for configuration key: ${key}`);
    }
  }

  private async persistConfigChange(key: string, value: any) {
    // Implementation for persisting config changes
    // Could be database, external config service, etc.
    console.log(`Persisting config change: ${key} = ${value}`);
  }
}
```

### Configuration Validation Service

```typescript
import { Injectable } from '@nestjs/common';
import { SmartConfigService } from '@hsuite/smart-config';
import * as Joi from 'joi';

@Injectable()
export class ConfigValidationService {
  constructor(private config: SmartConfigService) {}

  validateAllConfigurations(): ValidationResult {
    const errors: string[] = [];
    const warnings: string[] = [];

    // Validate required environment variables
    const requiredConfigs = [
      'JWT_SECRET',
      'DATABASE_URL',
      'HEDERA_ACCOUNT_ID',
      'HEDERA_PRIVATE_KEY'
    ];

    for (const configKey of requiredConfigs) {
      if (!this.config.get(configKey)) {
        errors.push(`Missing required configuration: ${configKey}`);
      }
    }

    // Validate configuration formats
    this.validateJwtSecret(errors);
    this.validateDatabaseUrl(errors);
    this.validateHederaConfig(errors, warnings);
    this.validateApiConfig(warnings);

    return {
      isValid: errors.length === 0,
      errors,
      warnings,
      validatedAt: new Date()
    };
  }

  private validateJwtSecret(errors: string[]) {
    const jwtSecret = this.config.get('JWT_SECRET');
    if (jwtSecret && jwtSecret.length < 32) {
      errors.push('JWT_SECRET must be at least 32 characters long');
    }
  }

  private validateDatabaseUrl(errors: string[]) {
    const dbUrl = this.config.get('DATABASE_URL');
    if (dbUrl && !dbUrl.startsWith('postgresql://')) {
      errors.push('DATABASE_URL must be a valid PostgreSQL connection string');
    }
  }

  private validateHederaConfig(errors: string[], warnings: string[]) {
    const accountId = this.config.get('HEDERA_ACCOUNT_ID');
    if (accountId && !/^0\.0\.\d+$/.test(accountId)) {
      errors.push('HEDERA_ACCOUNT_ID must be in format 0.0.xxx');
    }

    const network = this.config.get('HEDERA_NETWORK', 'testnet');
    if (network === 'mainnet') {
      warnings.push('Using Hedera mainnet - ensure this is intentional');
    }
  }

  private validateApiConfig(warnings: string[]) {
    const port = this.config.get('PORT', 3000);
    if (port < 1024) {
      warnings.push('API port is below 1024 - may require elevated privileges');
    }

    if (this.config.get('ENABLE_CORS', true) && this.config.get('CORS_ORIGIN') === '*') {
      warnings.push('CORS is enabled for all origins - consider restricting in production');
    }
  }
}

interface ValidationResult {
  isValid: boolean;
  errors: string[];
  warnings: string[];
  validatedAt: Date;
}
```

***

## Integration

### Required Dependencies

```json
{
  "@nestjs/config": "^3.0.0",
  "joi": "^17.0.0",
  "dotenv": "^16.0.0"
}
```

### Environment File Structure

```env
# .env.local (development)
NODE_ENV=development
PORT=3000
LOG_LEVEL=debug

# Database
DATABASE_URL=postgresql://user:pass@localhost:5432/hsuite_dev
DB_SYNCHRONIZE=true
DB_LOGGING=true

# JWT
JWT_SECRET=your-super-secret-jwt-key-minimum-32-characters
JWT_EXPIRES_IN=24h

# Hedera Testnet
HEDERA_NETWORK=testnet
HEDERA_ACCOUNT_ID=0.0.123456
HEDERA_PRIVATE_KEY=302e020100300506032b657004220420...

# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=

# Feature Flags
FEATURE_NEW_UI=true
FEATURE_BETA=true
ENABLE_CONFIG_WATCHING=true
```

### Production Environment

```env
# .env.production
NODE_ENV=production
PORT=8080
LOG_LEVEL=info

# Database
DATABASE_URL=postgresql://user:securepass@prod-db:5432/hsuite
DB_SYNCHRONIZE=false
DB_LOGGING=false

# JWT
JWT_SECRET=production-jwt-secret-very-long-and-secure
JWT_EXPIRES_IN=1h

# Hedera Mainnet
HEDERA_NETWORK=mainnet
HEDERA_ACCOUNT_ID=0.0.987654
HEDERA_PRIVATE_KEY=encrypted_private_key_here

# Redis
REDIS_HOST=redis-cluster
REDIS_PORT=6379
REDIS_PASSWORD=secure_redis_password

# Security
ENABLE_CORS=false
API_RATE_LIMIT=50
```

***

**⚙️ Type Safety**: Full TypeScript support with configuration interfaces and validation.

**🔒 Security**: Encrypted credential storage and environment-based configuration isolation.

## **🔄 Dynamic**: Runtime configuration updates with validation and event emission.

<p align="center">Built with ❤️ by the HSuite Team<br>Copyright © 2025 HSuite. All rights reserved.</p>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.hsuite.network/developers/libs/smart-config.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
