4.9 KiB
4.9 KiB
config
Category: universal
Path: universal/config/config
Archived from: openspec/archive/2026-04-24-enterprise-config/
Purpose
Layered configuration management for the Suaveplan monorepo. Five typed layers (defaults, file, object, env, CLI) are resolved in priority order, deep-merged, optionally validated via a caller-supplied Zod-compatible schema, and exposed through an immutable ConfigStore with hot-reload and subscription support.
Requirements
Constants
LAYER_PRIORITIES: { DEFAULTS: 0; FILE: 10; OBJECT: 20; ENV: 30; CLI: 40 }
MASK_STRING: "****"
TRUTHY_STRINGS: string[]
FALSY_STRINGS: string[]
Error Codes
| Code | Severity | Retryable | Trigger |
|---|---|---|---|
CONFIG_MISSING |
error |
false |
Required config key not present |
CONFIG_INVALID_TYPE |
error |
false |
Value has wrong type |
CONFIG_PARSE_FAILED |
error |
false |
Layer resolution threw |
CONFIG_FILE_NOT_FOUND |
error |
false |
File layer content unavailable |
CONFIG_ENV_NOT_SET |
error |
false |
Required env var absent |
CONFIG_RELOAD_FAILED |
error |
true |
Reload aborted or layer re-resolution threw |
CONFIG_VALIDATION_FAILED |
fatal |
false |
Validator threw |
Core API
class ConfigError extends SuaveplanError<ConfigPackageErrorCode>
function createConfig<T extends ConfigData>(options: CreateConfigOptions<T>): ConfigStore<T>
interface ConfigErrorDetail { path?: string; message: string }
interface MergeResult { data: ConfigData; layers: ResolvedLayer[] }
interface ResolvedLayer { name: string; priority: number; data: ConfigData }
Store
function createConfigStore<T extends ConfigData>(options: ConfigStoreOptions<T>): ConfigStore<T>
interface ConfigStoreOptions<T extends ConfigData = ConfigData> {
data: T
sensitive: string[]
}
interface ConfigStore<T extends ConfigData = ConfigData> {
get<K extends string>(key: K): unknown
has(key: string): boolean
toJSON(): Readonly<T>
toMasked(): Readonly<T>
reload(signal?: AbortSignal): Promise<void>
subscribe(listener: (next: Readonly<T>) => void): () => void
}
Layers
function defaultsLayer<T extends ConfigData>(defaults: T): ConfigLayer
function objectLayer(data: ConfigData, priority?: number): ConfigLayer
function envLayer(options: EnvLayerOptions): ConfigLayer
function fileLayer(options: FileLayerOptions): ConfigLayer
function cliLayer(options: CliLayerOptions): ConfigLayer
function parseArgs(args: string[], mapping: Record<string, string>): Record<string, string>
Types
type ConfigData = Record<string, unknown>
interface ConfigLayer {
readonly name: string
readonly priority: number
resolve(): ConfigData
teardown?(): void
}
type ConfigValidator<T extends ConfigData = ConfigData> = (data: ConfigData) => T
type EnvironmentOverrides<T extends ConfigData = ConfigData> = Record<string, Partial<T>>
interface CreateConfigOptions<T extends ConfigData = ConfigData> {
layers: ConfigLayer[]
validate?: ConfigValidator<T>
sensitive?: string[]
environments?: EnvironmentOverrides<T>
environment?: string
logger?: LoggerLike
}
interface EnvLayerOptions {
prefix?: string
mapping: Record<string, string>
source?: Record<string, string | undefined>
}
interface CliLayerOptions {
args: string[]
mapping: Record<string, string>
}
interface FileLayerOptions {
content: ConfigData
watchBus?: EventBusLike
watchEvent?: string
}
Utils
function deepMerge<T extends ConfigData>(base: T, override: Partial<T>): T
function mergeLayers(layers: Array<{ name: string; data: ConfigData }>): ConfigData
function getByPath(obj: ConfigData, path: string): unknown
function hasByPath(obj: ConfigData, path: string): boolean
function setByPath(obj: ConfigData, path: string, value: unknown): ConfigData
function maskSensitive(data: ConfigData, sensitive: string[], mask?: string): ConfigData
function coerceValue(raw: string): unknown
Zod Schemas
EnvLayerOptionsSchemaCliLayerOptionsSchemaFileLayerOptionsSchemaConfigStoreOptionsSchemaCreateConfigOptionsSchema
OTel Instrumentation
| Signal | Name | Attributes |
|---|---|---|
| Span | config.create |
config.layer_count, config.environment |
| Counter | config.get_total |
config.hit (bool) |
| Counter | config.reload_total |
— |
| Histogram | config.reload_duration_ms |
— |
| Histogram | config.merge_duration_ms |
config.layer_count |
Dependencies
| Package | Role |
|---|---|
@suaveplan/error |
SuaveplanError base class, defineCodes |
@suaveplan/types |
LoggerLike, EventBusLike |
@suaveplan/events |
EventBus for file-layer watch mode |
@suaveplan/env |
coerceValue boolean/numeric token reference |
@opentelemetry/api |
OTel spans, counters, histograms |
zod |
Zod schemas for all public option types |
tslib |
TS runtime helpers |