Lyo.Config
1.0.11
dotnet add package Lyo.Config --version 1.0.11
NuGet\Install-Package Lyo.Config -Version 1.0.11
<PackageReference Include="Lyo.Config" Version="1.0.11" />
<PackageVersion Include="Lyo.Config" Version="1.0.11" />
<PackageReference Include="Lyo.Config" />
paket add Lyo.Config --version 1.0.11
#r "nuget: Lyo.Config, 1.0.11"
#:package Lyo.Config@1.0.11
#addin nuget:?package=Lyo.Config&version=1.0.11
#tool nuget:?package=Lyo.Config&version=1.0.11
Lyo.Config
Typed, definition-driven configuration for per-entity values (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. |
IsEncrypted |
On the definition. Clients send plaintext JSON plus this flag. The API host encrypts at rest; Web.Components, TestGateway, and CLI never call IEncryptionService. |
ConfigDefinitionRevisionRecord |
Append-only snapshot of key metadata (type, required, default, encrypted flag). Separate from binding value history. |
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
Two 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 setVersionto 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 value 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).
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. Adding a definition does not create a value revision — value history starts at the first binding save.
Versioning. 4. Definition metadata history (revert)
PostgreSQL stores append-only definition revisions in config.config_definition_revision: primary key is (definition_id, revision). Every SaveDefinitionAsync appends a snapshot (type, required, description, default, encrypted flag) with no unchanged-JSON skip.
GetDefinitionRevisionsAsync/GetDefinitionRevisionAsync.RevertDefinitionToRevisionAsync. Copies the snapshot onto the definition and appends a new revision so revert stays auditable.
IConfigStore at a glance
SaveDefinitionAsync(ConfigDefinitionRecord)upserts and always appends a definition revision.GetDefinitionByIdAsync(Guid)/GetDefinitionAsync(string forEntityType, string key)look up one definition.GetDefinitionsAsync(string forEntityType)enumerates definitions for a type.DeleteDefinitionAsync(Guid)deletes. Postgres cascades toconfig_bindingrows.GetDefinitionRevisionsAsync/GetDefinitionRevisionAsync/RevertDefinitionToRevisionAsyncfor metadata history.GetBindingRevisionsAsync/RevertBindingToRevisionAsyncfor per-entity value history.
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)Lyo.Validation(direct, lyo)System.Text.Json10.0.5(direct, microsoft, netstandard2.0)Lyo.Cache(transitive, lyo)Lyo.Compression(transitive, lyo)Lyo.Encryption(transitive, lyo)Lyo.Exceptions(transitive, lyo)Lyo.Hashing(transitive, lyo)Lyo.Health(transitive, lyo)Lyo.KeyStore(transitive, lyo)Lyo.Metrics(transitive, lyo)Lyo.Query(transitive, lyo)Lyo.Query.Models(transitive, lyo)Lyo.Result(transitive, lyo)Lyo.Streams(transitive, lyo)BouncyCastle.Cryptography2.6.2(transitive, third-party, netstandard2.0)EasyCompressor2.1.0(transitive, third-party)Konscious.Security.Cryptography.Argon21.3.1(transitive, third-party)Microsoft.Bcl.AsyncInterfaces10.0.5(transitive, microsoft, netstandard2.0)Microsoft.Extensions.Caching.Memory10.0.5(transitive, microsoft)Microsoft.Extensions.Configuration.Binder10.0.5(transitive, microsoft)Microsoft.Extensions.DependencyInjection10.0.5(transitive, microsoft)Microsoft.Extensions.DependencyInjection.Abstractions10.0.5(transitive, microsoft, net10.0, netstandard2.0)Microsoft.Extensions.Logging.Abstractions10.0.5(transitive, microsoft)Microsoft.Extensions.Options.ConfigurationExtensions10.0.5(transitive, microsoft)System.Buffers4.6.1(transitive, microsoft, netstandard2.0)System.ComponentModel.Annotations5.0.0(transitive, microsoft)System.IO.Hashing10.0.5(transitive, microsoft, net10.0)System.Memory4.6.3(transitive, microsoft, netstandard2.0)System.Threading.Tasks.Extensions4.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.11)
- Lyo.EntityReference.Models (>= 1.0.11)
- Lyo.Validation (>= 1.0.11)
- System.Text.Json (>= 10.0.5)
-
net10.0
- Lyo.Common (>= 1.0.11)
- Lyo.EntityReference.Models (>= 1.0.11)
- Lyo.Validation (>= 1.0.11)
NuGet packages (6)
Showing the top 5 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.Api.Client
HTTP client for the Lyo central Config API (conditional resolve, ETags, HTTP IConfigStore over manage routes). |
|
|
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.