using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories; using ZB.MOM.WW.ScadaBridge.Commons.Types.InboundApi; namespace ZB.MOM.WW.ScadaBridge.InboundAPI; /// /// Builds the synchronous JSON-Schema $ref resolution seam the /// InboundAPI RUNTIME validators ( / /// ) consume, backed by the central shared-schema /// library (). /// /// /// Before this fix the runtime validators called the single-arg /// InboundApiSchema.Parse(json) with NO resolver, so a method whose /// parameter/return definition used a {"$ref":"lib:Name"} deployed fine /// (deploy-time validation resolves it) but FAILED at every runtime invocation with /// an opaque HTTP 400 — a deploy-passes/runtime-breaks defect. This helper mirrors how /// the deploy path (FlatteningPipeline) pre-loads the library ONCE into an /// in-memory name→JSON map and exposes a pure synchronous lookup as the seam, avoiding /// sync-over-async inside the validators. /// /// /// /// The pre-load is gated on : a definition /// that uses no $ref at all skips the repository round-trip entirely and returns /// null (no resolver), so a $ref-free method pays NO extra cost beyond /// today's behavior. /// /// internal static class SchemaRefResolver { /// /// Builds a lib:Name → schema-JSON resolution seam for the supplied /// definitions, pre-loading the shared-schema library only when at least one of the /// definitions actually contains a $ref. /// /// /// The shared-schema repository, or null when none is registered (e.g. a bare /// test-double provider) — then no resolver is produced and any $ref dangles. /// /// The schema definition JSON strings to be validated (parameter and/or return). /// Cancellation token for the library load. /// /// A synchronous name → schema JSON? resolver, or null when no definition /// uses a $ref (so the validators take their unchanged no-resolver path). /// public static async Task?> BuildAsync( ISharedSchemaRepository? repository, IEnumerable definitions, CancellationToken ct = default) { // Skip the library round-trip entirely unless some definition uses a $ref. if (repository is null || !definitions.Any(InboundApiSchema.MightContainRef)) { return null; } var library = await repository.ListAsync(ct); var map = library.ToDictionary(s => s.Name, s => s.SchemaJson, StringComparer.Ordinal); return name => map.GetValueOrDefault(name); } }