Minor, fully additive release — no breaking changes, drop-in over 6.0.0. Four new configuration file formats, Kubernetes ConfigMap / Secret support, and a provider hardening pass.
✨ New file-format providers
All four sit on a shared, reusable FileBackedProvider base, so they get the same reactive file-watching, path-traversal protection, and per-file debounce as the JSON file provider.
YAML — new opt-in package Cocoar.Configuration.Yaml (YamlDotNet). Plain scalars map to their JSON types (true→bool, 42→number, null/~→null); quoted/block scalars stay strings.
rules.For<AppSettings>().FromYamlFile("appsettings.yaml")TOML — new opt-in package Cocoar.Configuration.Toml (Tomlyn). TOML is strongly typed, so values map unambiguously to JSON (incl. arrays-of-tables → arrays of objects; dates → ISO-8601 strings).
rules.For<AppSettings>().FromTomlFile("appsettings.toml")dotenv and INI — built into the core package, no extra dependency:
rules.For<AppSettings>().FromDotEnv() // .env: KEY=value, # comments, export, quotes, :/__ nesting
rules.For<AppSettings>().FromIniFile("app.ini") // [section] headers, ;/# comments, ./: nestingINI keeps inline
;/#inside values intact (only whole-line comments are stripped), so connection strings survive.
☸️ Kubernetes ConfigMap / Secret support
A ConfigMap/Secret-mounted file is a symlink whose content is updated by an atomic swap of a sibling ..data symlink — not by rewriting the file. Opt in with followSymlinks (default off) on any file provider:
rules.For<AppSettings>().FromFile("/etc/config/appsettings.json", followSymlinks: true)
// also on FromYamlFile / FromTomlFile / FromDotEnv / FromIniFile- Reads the symlinked file — the resolved final target must still resolve within the configured directory, so an escaping symlink is rejected (the path-traversal protection holds).
- Hot-reloads on the atomic
..dataswap (viaCocoar.FileSystem2.3.0 symlink-target tracking), even though the watched file's name and timestamp never change. Detection rides on the directory watcher's periodic re-scan — expect propagation within roughly a minute, in line with how Kubernetes itself rolls ConfigMap updates.
Default behaviour is unchanged: symlinks remain rejected as defense in depth.
🛠️ Provider hardening & internals
- Observable provider: fetch no longer hangs on a cold / complete-without-emit source, and no longer leaks its one-shot subscription.
- HTTP provider: the
HttpResponseMessageis disposed after fetch; opt-inSseReadIdleTimeoutreconnects a half-open SSE stream. - Extracted the reusable
FileBackedProviderbase (watch / path+symlink security / debounce / dispose) shared by all file formats;FileSourceProvideris now a thin subclass. - Documented the provider-contract invariants; parameterless
FromCommandLine();FileSourceProvider.Disposemade race-safe; removed deadMicrosoftConfigurationSource*code (theFromMicrosoftSourceAPI was dropped in 6.0.0).
📦 Packages
All packages release as 6.1.0.
- New:
Cocoar.Configuration.Yaml(YamlDotNet),Cocoar.Configuration.Toml(Tomlyn). - dotenv and INI ship inside the core
Cocoar.Configurationpackage (no new dependency). Cocoar.FileSystemdependency bumped 2.2.0 → 2.3.0 (adds opt-in symlink-target tracking).