first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,184 @@
# @suaveplan/config - Layered configuration management: defaults, file, object, env, CLI layers merged in priority order with deep-merge, Zod validation, OTel instrumentation, and event-bus watch support.
## Summary
Layered configuration management for Suaveplan. Resolves an ordered set of typed layers (defaults, file, object, env, CLI) in priority order, deep-merges the results, applies per-environment overrides, validates via a caller-supplied Zod schema or custom function, and exposes an immutable `ConfigStore` with live reload and event-bus change propagation.
<!-- begin:auto-docs -->
## Documentation tree
- [config-builder](./src/core/config-builder/config-builder.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [config-builder](./src/core/config-builder/config-builder.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [config-store](./src/core/config-store/config-store.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [config-store](./src/core/config-store/config-store.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [cli-layer](./src/layers/cli-layer/cli-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [cli-layer](./src/layers/cli-layer/cli-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [defaults-layer](./src/layers/defaults-layer/defaults-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [defaults-layer](./src/layers/defaults-layer/defaults-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [env-layer](./src/layers/env-layer/env-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [env-layer](./src/layers/env-layer/env-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [file-layer](./src/layers/file-layer/file-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [file-layer](./src/layers/file-layer/file-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [object-layer](./src/layers/object-layer/object-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [object-layer](./src/layers/object-layer/object-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
- [common](./src/types/common.md) — This module defines every public TypeScript interface and type alias used across the `@suaveplan/config` package. It is…
- [schemas](./src/types/schemas.md) — This module exposes Zod schemas for every public options interface in `@suaveplan/config`. Using these schemas, callers…
- [mask](./src/utils/mask.md) — This module provides low-level dot-notation path traversal utilities (`getByPath`, `setByPath`, `hasByPath`) and the `m…
- [merge](./src/utils/merge.md) — This module provides two functions that form the merge backbone of the config pipeline: `deepMerge` performs a structur…
<!-- end:auto-docs --> - [config-builder](./src/core/config-builder/config-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [config-store](./src/core/config-store/config-store.md) — <!-- begin:auto-docs --> _(no submodules)_- [config-store](./src/core/config-store/config-store.md) — <!-- begin:auto-docs --> _(no submodules)_- [cli-layer](./src/layers/cli-layer/cli-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [cli-layer](./src/layers/cli-layer/cli-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [defaults-layer](./src/layers/defaults-layer/defaults-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [defaults-layer](./src/layers/defaults-layer/defaults-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [env-layer](./src/layers/env-layer/env-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [env-layer](./src/layers/env-layer/env-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [file-layer](./src/layers/file-layer/file-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [file-layer](./src/layers/file-layer/file-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [object-layer](./src/layers/object-layer/object-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [object-layer](./src/layers/object-layer/object-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [common](./src/types/common.md) — This module defines every public TypeScript interface and type alias used across the `@suaveplan/config` package. It is…
- [schemas](./src/types/schemas.md) — This module exposes Zod schemas for every public options interface in `@suaveplan/config`. Using these schemas, callers…
- [mask](./src/utils/mask.md) — This module provides low-level dot-notation path traversal utilities (`getByPath`, `setByPath`, `hasByPath`) and the `m…
- [merge](./src/utils/merge.md) — This module provides two functions that form the merge backbone of the config pipeline: `deepMerge` performs a structur…
- [config-builder](./src/core/config-builder/config-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [config-store](./src/core/config-store/config-store.md) — <!-- begin:auto-docs --> _(no submodules)_- [config-store](./src/core/config-store/config-store.md) — <!-- begin:auto-docs --> _(no submodules)_- [cli-layer](./src/layers/cli-layer/cli-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [cli-layer](./src/layers/cli-layer/cli-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [defaults-layer](./src/layers/defaults-layer/defaults-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [defaults-layer](./src/layers/defaults-layer/defaults-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [env-layer](./src/layers/env-layer/env-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [env-layer](./src/layers/env-layer/env-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [file-layer](./src/layers/file-layer/file-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [file-layer](./src/layers/file-layer/file-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [object-layer](./src/layers/object-layer/object-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [object-layer](./src/layers/object-layer/object-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [common](./src/types/common.md) — This module defines every public TypeScript interface and type alias used across the `@suaveplan/config` package. It is…
- [schemas](./src/types/schemas.md) — This module exposes Zod schemas for every public options interface in `@suaveplan/config`. Using these schemas, callers…
- [mask](./src/utils/mask.md) — This module provides low-level dot-notation path traversal utilities (`getByPath`, `setByPath`, `hasByPath`) and the `m…
- [merge](./src/utils/merge.md) — This module provides two functions that form the merge backbone of the config pipeline: `deepMerge` performs a structur…
- [config-builder](./src/core/config-builder/config-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [config-store](./src/core/config-store/config-store.md) — <!-- begin:auto-docs --> _(no submodules)_- [config-store](./src/core/config-store/config-store.md) — <!-- begin:auto-docs --> _(no submodules)_- [cli-layer](./src/layers/cli-layer/cli-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [cli-layer](./src/layers/cli-layer/cli-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [defaults-layer](./src/layers/defaults-layer/defaults-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [defaults-layer](./src/layers/defaults-layer/defaults-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [env-layer](./src/layers/env-layer/env-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [env-layer](./src/layers/env-layer/env-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [file-layer](./src/layers/file-layer/file-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [file-layer](./src/layers/file-layer/file-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [object-layer](./src/layers/object-layer/object-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [object-layer](./src/layers/object-layer/object-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [common](./src/types/common.md) — This module defines every public TypeScript interface and type alias used across the `@suaveplan/config` package. It is…
- [schemas](./src/types/schemas.md) — This module exposes Zod schemas for every public options interface in `@suaveplan/config`. Using these schemas, callers…
- [mask](./src/utils/mask.md) — This module provides low-level dot-notation path traversal utilities (`getByPath`, `setByPath`, `hasByPath`) and the `m…
- [merge](./src/utils/merge.md) — This module provides two functions that form the merge backbone of the config pipeline: `deepMerge` performs a structur…
- [config-builder](./src/core/config-builder/config-builder.md) — <!-- begin:auto-docs --> _(no submodules)_- [config-store](./src/core/config-store/config-store.md) — <!-- begin:auto-docs --> _(no submodules)_ - [config-store](./src/core/config-store/config-store.md) — <!-- begin:auto-docs --> _(no submodules)_- [cli-layer](./src/layers/cli-layer/cli-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ - [cli-layer](./src/layers/cli-layer/cli-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [defaults-layer](./src/layers/defaults-layer/defaults-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ - [defaults-layer](./src/layers/defaults-layer/defaults-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [env-layer](./src/layers/env-layer/env-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ - [env-layer](./src/layers/env-layer/env-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [file-layer](./src/layers/file-layer/file-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ - [file-layer](./src/layers/file-layer/file-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [object-layer](./src/layers/object-layer/object-layer.md) — <!-- begin:auto-docs --> _(no submodules)_ - [object-layer](./src/layers/object-layer/object-layer.md) — <!-- begin:auto-docs --> _(no submodules)_- [common](./src/types/common.md) — This module defines every public TypeScript interface and type alias used across the `@suaveplan/config` package. It is…
- [schemas](./src/types/schemas.md) — This module exposes Zod schemas for every public options interface in `@suaveplan/config`. Using these schemas, callers…
- [mask](./src/utils/mask.md) — This module provides low-level dot-notation path traversal utilities (`getByPath`, `setByPath`, `hasByPath`) and the `m…
- [merge](./src/utils/merge.md) — This module provides two functions that form the merge backbone of the config pipeline: `deepMerge` performs a structur…
## Installation
```bash
bun add @suaveplan/config
```
## Quick Start
```ts
import { createConfig, defaultsLayer, fileLayer, envLayer, cliLayer } from '@suaveplan/config';
import { readFileSync } from 'node:fs';
import z from 'zod';
const Schema = z.object({
server: z.object({ port: z.number(), host: z.string() }),
db: z.object({ url: z.string(), pool: z.number(), password: z.string() }),
log: z.object({ level: z.string() }),
});
type AppConfig = z.infer<typeof Schema>;
const store = createConfig<AppConfig>({
layers: [
defaultsLayer({ server: { port: 3000, host: '0.0.0.0' }, db: { pool: 5, password: '' }, log: { level: 'info' } }),
fileLayer({ content: JSON.parse(readFileSync('./config.json', 'utf-8')) }),
envLayer({ prefix: 'APP_', mapping: { PORT: 'server.port', DB_URL: 'db.url', DB_PASS: 'db.password' } }),
cliLayer({ args: process.argv.slice(2), mapping: { port: 'server.port' } }),
],
validate: (raw) => Schema.parse(raw),
sensitive: ['db.password', 'db.url'],
environments: { production: { log: { level: 'warn' } }, development: { log: { level: 'debug' } } },
environment: process.env.NODE_ENV ?? 'development',
});
console.log(store.get('server.port')); // number
console.log(store.toMasked()); // db.password = '****'
// Live reload
await store.reload();
// Subscribe to changes
const unsub = store.subscribe((next) => console.log('Config updated:', next));
```
## Module Documentation
| Module | Description |
|--------|-------------|
| [`src/types/common.md`](src/types/common.md) | All public TypeScript interfaces and type aliases |
| [`src/types/schemas.md`](src/types/schemas.md) | Zod option schemas for runtime validation |
| [`src/core/config-builder/config-builder.md`](src/core/config-builder/config-builder.md) | `createConfig` orchestrator |
| [`src/core/config-store/config-store.md`](src/core/config-store/config-store.md) | `createConfigStore` static store factory |
| [`src/layers/defaults-layer/defaults-layer.md`](src/layers/defaults-layer/defaults-layer.md) | Static default values layer |
| [`src/layers/object-layer/object-layer.md`](src/layers/object-layer/object-layer.md) | In-memory config object layer |
| [`src/layers/env-layer/env-layer.md`](src/layers/env-layer/env-layer.md) | Environment variable layer + `coerceValue` |
| [`src/layers/file-layer/file-layer.md`](src/layers/file-layer/file-layer.md) | Pre-parsed file content layer with watch mode |
| [`src/layers/cli-layer/cli-layer.md`](src/layers/cli-layer/cli-layer.md) | CLI argument layer + `parseArgs` |
| [`src/utils/merge.md`](src/utils/merge.md) | `deepMerge` and `mergeLayers` utilities |
| [`src/utils/mask.md`](src/utils/mask.md) | Path utilities and `maskSensitive` |
## Layer Priorities
| Layer | Priority | Description |
|-------|----------|-------------|
| `defaultsLayer` | 0 | Static baseline — always overridden |
| `fileLayer` | 10 | Pre-parsed file content |
| `objectLayer` | 20 | In-memory programmatic overrides |
| `envLayer` | 30 | Environment variables |
| `cliLayer` | 40 | CLI arguments — highest priority |
## API
### Core
| Export | Description |
|--------|-------------|
| `createConfig(options)` | Resolves layers, merges, validates, returns live store |
| `createConfigStore(options)` | Low-level static store factory |
### Layers
| Export | Description |
|--------|-------------|
| `defaultsLayer(defaults)` | Static defaults at priority 0 |
| `fileLayer(options)` | Pre-parsed file content at priority 10 |
| `objectLayer(data, priority?)` | In-memory object at priority 20 |
| `envLayer(options)` | Environment variables at priority 30 |
| `cliLayer(options)` | CLI arguments at priority 40 |
| `parseArgs(args, mapping)` | Parse raw argv into flag→value map |
### Utilities
| Export | Description |
|--------|-------------|
| `deepMerge(base, override)` | Recursive object merge |
| `mergeLayers(layers)` | Fold ordered layers with deepMerge |
| `getByPath(obj, path)` | Read dot-notation path |
| `setByPath(obj, path, value)` | Write dot-notation path |
| `hasByPath(obj, path)` | Check dot-notation path existence |
| `maskSensitive(data, paths, mask?)` | Replace sensitive paths |
| `coerceValue(raw)` | Convert env-var string to typed value |
### Error Codes
| Code | Description |
|------|-------------|
| `CONFIG.MISSING` | Required config key not found |
| `CONFIG.INVALID_TYPE` | Value has wrong type |
| `CONFIG.PARSE_FAILED` | Layer resolution threw |
| `CONFIG.FILE_NOT_FOUND` | File layer file not found |
| `CONFIG.ENV_NOT_SET` | Required env var not set |
| `CONFIG.RELOAD_FAILED` | Reload aborted or layer threw |
| `CONFIG.VALIDATION_FAILED` | Validator threw |
## Dependencies
| Package | Role |
|---------|------|
| `@suaveplan/error` | `SuaveplanError` base, `defineCodes` |
| `@suaveplan/types` | `LoggerLike`, `EventBusLike` |
| `@suaveplan/events` | `EventBus` for file-layer watch mode |
| `@suaveplan/env` | Coercion functions for env-var values |
| `zod` | Option schemas |
| `@opentelemetry/api` | Spans, counters, histograms |
| `tslib` | TypeScript runtime helpers |
## Benchmarks
Run with `bun run bench`.
| Benchmark | Operations / sec (approx.) |
|-----------|---------------------------|
| `createConfig` 5 layers (cold) | TBD |
| `store.get` 100x deeply nested key | TBD |
| `mergeLayers` 2 layers | TBD |
| `mergeLayers` 5 layers | TBD |
| `mergeLayers` 10 layers | TBD |
| `mergeLayers` 20 layers | TBD |
_Run `bun run bench` to populate these numbers on your hardware._