/** * Configuration API for Brainy 3.0 * Provides configuration storage with optional encryption */ import { SecurityAPI } from './SecurityAPI.js' import { StorageAdapter } from '../coreTypes.js' export interface ConfigOptions { encrypt?: boolean decrypt?: boolean } export interface ConfigEntry { key: string value: any encrypted: boolean createdAt: number updatedAt: number } export class ConfigAPI { private security: SecurityAPI private configCache: Map = new Map() private CONFIG_NOUN_PREFIX = '_config_' constructor(private storage: StorageAdapter) { this.security = new SecurityAPI() } /** * Set a configuration value with optional encryption */ async set(params: { key: string value: any encrypt?: boolean }): Promise { const { key, value, encrypt = false } = params // Serialize and optionally encrypt the value let storedValue: any = value if (typeof value !== 'string') { storedValue = JSON.stringify(value) } if (encrypt) { storedValue = await this.security.encrypt(storedValue) } // Create config entry const entry: ConfigEntry = { key, value: storedValue, encrypted: encrypt, createdAt: this.configCache.get(key)?.createdAt || Date.now(), updatedAt: Date.now() } // Store in cache this.configCache.set(key, entry) // Persist to storage const configId = this.CONFIG_NOUN_PREFIX + key await this.storage.saveMetadata(configId, entry) } /** * Get a configuration value with optional decryption */ async get(params: { key: string decrypt?: boolean defaultValue?: any }): Promise { const { key, decrypt, defaultValue } = params // Check cache first let entry = this.configCache.get(key) // If not in cache, load from storage if (!entry) { const configId = this.CONFIG_NOUN_PREFIX + key const metadata = await this.storage.getMetadata(configId) if (!metadata) { return defaultValue } entry = metadata as ConfigEntry this.configCache.set(key, entry) } let value = entry.value // Decrypt if needed const shouldDecrypt = decrypt !== undefined ? decrypt : entry.encrypted if (shouldDecrypt && entry.encrypted && typeof value === 'string') { value = await this.security.decrypt(value) } // Try to parse JSON if it looks like JSON if (typeof value === 'string' && (value.startsWith('{') || value.startsWith('['))) { try { value = JSON.parse(value) } catch { // Not JSON, return as string } } return value } /** * Delete a configuration value */ async delete(key: string): Promise { // Remove from cache this.configCache.delete(key) // Remove from storage const configId = this.CONFIG_NOUN_PREFIX + key await this.storage.saveMetadata(configId, null as any) } /** * List all configuration keys */ async list(): Promise { // Get all metadata keys from storage const allMetadata = await this.storage.getMetadata('') if (!allMetadata || typeof allMetadata !== 'object') { return [] } // Filter for config keys const configKeys: string[] = [] for (const key of Object.keys(allMetadata)) { if (key.startsWith(this.CONFIG_NOUN_PREFIX)) { configKeys.push(key.substring(this.CONFIG_NOUN_PREFIX.length)) } } return configKeys } /** * Check if a configuration key exists */ async has(key: string): Promise { if (this.configCache.has(key)) { return true } const configId = this.CONFIG_NOUN_PREFIX + key const metadata = await this.storage.getMetadata(configId) return metadata !== null && metadata !== undefined } /** * Clear all configuration */ async clear(): Promise { // Clear cache this.configCache.clear() // Clear from storage const keys = await this.list() for (const key of keys) { await this.delete(key) } } /** * Export all configuration */ async export(): Promise> { const keys = await this.list() const config: Record = {} for (const key of keys) { const entry = await this.getEntry(key) if (entry) { config[key] = entry } } return config } /** * Import configuration */ async import(config: Record): Promise { for (const [key, entry] of Object.entries(config)) { this.configCache.set(key, entry) const configId = this.CONFIG_NOUN_PREFIX + key await this.storage.saveMetadata(configId, entry) } } /** * Get raw config entry (without decryption) */ private async getEntry(key: string): Promise { if (this.configCache.has(key)) { return this.configCache.get(key)! } const configId = this.CONFIG_NOUN_PREFIX + key const metadata = await this.storage.getMetadata(configId) if (!metadata) { return null } const entry = metadata as ConfigEntry this.configCache.set(key, entry) return entry } }