Lyo.Config
1.0.1
dotnet add package Lyo.Config --version 1.0.1
NuGet\Install-Package Lyo.Config -Version 1.0.1
<PackageReference Include="Lyo.Config" Version="1.0.1" />
<PackageVersion Include="Lyo.Config" Version="1.0.1" />
<PackageReference Include="Lyo.Config" />
paket add Lyo.Config --version 1.0.1
#r "nuget: Lyo.Config, 1.0.1"
#:package Lyo.Config@1.0.1
#addin nuget:?package=Lyo.Config&version=1.0.1
#tool nuget:?package=Lyo.Config&version=1.0.1
Lyo.Config
Typed, definition-driven configuration for per-entity values (e.g. a Discord guild, a tenant). The abstract API lives here; PostgreSQL persistence is in Lyo.Config.Postgres.
Concepts
| Piece | Role |
|---|---|
ConfigDefinitionRecord |
Declares an allowed key for an ForEntityType (CLR type name string), the CLR value type, optional default, IsRequired, and metadata. |
ConfigBindingRecord |
Stores the actual value for one entity instance (EntityRef: type + id) under a definition. |
ConfigValue |
Wrapper: CLR type name + JSON payload. Serialize/deserialize with ConfigJsonSerializerOptions.Default when you do not pass custom JsonSerializerOptions. |
ResolvedConfigRecord |
Produced by LoadConfigAsync: every definition for that entity type, each with optional binding; Value is binding ?? default. |
Definitions are unique per (ForEntityType, Key). Bindings are unique per (DefinitionId, ForEntityType, ForEntityId). In PostgreSQL, config_binding has a value_type column (
same CLR type name as config_definition.for_value_type, denormalized for querying and exports).
JSON
ConfigJsonSerializerOptions.Default is used whenever ConfigValue callers pass null for options: camelCase property names, case-insensitive deserialization, omit nulls when writing. Keeps API JSON and stored value_json aligned.
IsRequired
If IsRequired is true and the definition has no default (DefaultValue null), each entity must have a binding for that key. - LoadConfigAsync calls ResolvedConfigRecord.ValidateRequired() and throws if any required key has no resolved value. - DeleteBindingAsync / DeleteBindingsAsync refuse to remove a binding that would violate that rule. If IsRequired is true and a default exists, the default supplies the resolved value when no binding exists (deleting the binding is allowed).
Deleting definitions
DeleteDefinitionAsync removes the definition row. In PostgreSQL, config_binding rows referencing that definition are removed by foreign-key ON DELETE CASCADE.
Versioning
There are two different “version” stories:
Versioning — 1. CLR / definition type changes
Each definition’s ForValueType is the CLR type name for the stored JSON, same convention as ForEntityType: Type.FullName (same form as ConfigValue.TypeName; use ConfigValue.GetTypeName(typeof(T)) when seeding). If you rename types, split types, or change the JSON shape incompatibly: - Update the definition (and seeders) so ForValueType matches the new type. - Migrate existing value_json (or delete bindings and recreate), or introduce a new key and deprecate the old one. The Lyo.Config layer does not auto-migrate arbitrary payloads.
Versioning — 2. Document schema version inside the JSON (optional pattern)
For a single JSON document stored as one binding (e.g. DiscordGuildSettings), use an integer Version field and a CurrentSchemaVersion constant on the model:
NormalizeForRead()— AfterGetValue<T>(), fix legacy documents (e.g.Version <= 0or older version numbers): set defaults for new properties, rewrite fields, then set *Version* to the version you’ve upgraded to.NormalizeForPersistence()— BeforeConfigValue.From, call this so every save writesVersion == CurrentSchemaVersion.
When you add a breaking or additive shape change: bump CurrentSchemaVersion, extend NormalizeForRead() with if (Version == n) { …; Version = n + 1; } (or jump
straight to current), and deploy readers before or with writers.
This is application-level migration inside one binding value; it does not replace backups or one-off SQL migrations when you need them.
Versioning — 3. Binding value history (revert)
PostgreSQL stores append-only revisions in config.config_binding_revision: primary key is (binding_id, revision) (no separate row id). Each successful *
SaveBindingAsync* writes a new row with a monotonic revision number (1-based per binding). The current value still lives on config_binding for fast reads.
GetBindingRevisionsAsync/GetBindingRevisionAsync— inspect history (newest first in the list overload).RevertBindingToRevisionAsync— copies the snapshot atrevisiononto the binding and appends a new revision (so the timeline stays linear and “revert” is auditable).
Deleting a binding (or its definition) cascades and removes revision rows. The initial migration seeds revision 1 from each existing binding’s current value so history starts at deploy time.
IConfigStore at a glance
SaveDefinitionAsync(ConfigDefinitionRecord)— upsert.GetDefinitionByIdAsync(Guid)/GetDefinitionAsync(string forEntityType, string key)— single lookups.GetDefinitionsAsync(string forEntityType)— enumerate definitions for a type.DeleteDefinitionAsync(Guid)— Postgres cascades toconfig_bindingrows.
API routing helper — AppConfigEntity
AppEntityType = "App"(the storedEntityRef.EntityTypefor app-scoped definitions and bindings).ToEntityRef(string appKind, string appId)/TryCreate(...)— URI-decode each segment, lowercase, validate the slug character set (a-z,0-9,-,_,., length ≤ 128), and producenew EntityRef("App", $"{kindNorm}:{idNorm}"). This is the compound-id shape thatConfigBindingRecord.ForEntityIdis sized for (string, notGuid).
See also
Lyo.Config.Postgres— EF Core schema (configschema),PostgresConfigStore, migrations.Lyo.EntityReference.Models—EntityRefused throughout the binding APIs.
Dependencies
Generated from ProjectReference / PackageReference (same model as docs/Lyo.ProjectGraph.html).
Lyo.Common— (direct, lyo)Lyo.EntityReference.Models— (direct, lyo)System.Text.Json10.0.5— (direct, microsoft, netstandard2.0)Lyo.Exceptions— (transitive, lyo)Microsoft.Extensions.Logging.Abstractions10.0.5— (transitive, microsoft)System.Memory4.6.3— (transitive, microsoft, netstandard2.0)
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Lyo.Common (>= 1.0.1)
- Lyo.EntityReference.Models (>= 1.0.1)
- System.Text.Json (>= 10.0.5)
-
net10.0
- Lyo.Common (>= 1.0.1)
- Lyo.EntityReference.Models (>= 1.0.1)
NuGet packages (4)
Showing the top 4 NuGet packages that depend on Lyo.Config:
| Package | Downloads |
|---|---|
|
Lyo.Config.Api.Models
Shared contracts for the Lyo central Config API (resolve outcomes). |
|
|
Lyo.Config.Postgres
PostgreSQL implementation of Lyo.Config using Entity Framework Core and jsonb-backed typed values. |
|
|
Lyo.Discord.Postgres
PostgreSQL persistence for Discord entities (EF Core, schema discord). |
|
|
Lyo.Config.Api
Central HTTP API exposing Lyo.Config PostgreSQL-backed IConfigStore for microservices (polling-friendly ETags). Embed via AddConfigApi / MapConfigApiEndpoints. |
GitHub repositories
This package is not used by any popular GitHub repositories.