Releases: Cratis/Arc
Release v20.12.0
Added
IInterceptReadModel<TReadModel>interface for implementing cross-cutting read model interceptors (decryption, masking, etc.) (#2152)IReadModelInterceptorsapplied consistently across model-bound queries, controller-based queries (QueryActionFilter), and all observable streaming paths (ClientObservable,ClientObservableSSE,ClientEnumerableObservable,ClientEnumerableObservableSSE) (#2152)- Interceptors are discovered via
ITypesat startup and resolved fromIServiceProviderper request, supporting scoped and transient lifetimes (#2152)
Release v20.11.1
No release notes
Release v20.11.0
Changed
- Proxy generator now emits
ValueMap<K, V>(with@field(ValueMap)and the corresponding@cratis/fundamentalsimport) forIDictionaryproperties with non-string keys, replacing the previousMap<K, V>.ValueMapuses value-based key equality, which is required when key instances are reconstructed across serialization boundaries.
Added
- Package upgrades:
Cratis.Fundamentals/Cratis.Metrics.Roslyn7.7.6 → 7.8.0,Cratis.Chronicle15.18.17 → 15.18.20,@cratis/fundamentals7.7.1 → 7.8.0, plus routine bumps for TypeScript, Vite, Vitest, ESLint, React, and several NuGet packages.
Release v20.10.10
Reverts all NativeAOT-specific changes introduced in #2180, restoring IInstancesOf<T> throughout Arc.Core. Retains only the fix for using the correct type name when constructing ModelBoundQueryPerformer.FullyQualifiedName from generated metadata.
Changed
- Restored
IInstancesOf<T>inAuthentication,AuthorizationEvaluator,CommandContextValuesBuilder,CommandFilters,CommandHandlerProviders,CommandResponseValueHandlers,QueryFilters, andQueryPerformerProviders - Reverted spec files back to
KnownInstancesOf<T>construction instead of plain array literals
Removed
- Explicit
TryAddSingleton/AddSingletonregistrations for Arc.Core-owned services fromCommandServiceCollectionExtensions,QueryServiceCollectionExtensions, andHostBuilderExtensions [DynamicDependency]attributes fromQueryMetadataGeneratorgenerated initializer andIntrospectionEndpointMapper- AOT project properties (
PublishAot,TreatAsLocalProperty,GlobalPropertiesToRemove,IlcArgitems) fromArc.Core.CodeAnalysis.csproj,Arc.Core.Generators.csproj,Arc.Core.csproj, andArcCore.csproj publish:aot:mangledscript fromTestApps/ArcCore/package.jsonand the accompanyingREADME.md
Release v20.10.9
Reverts all NativeAOT-specific changes introduced in #2180, restoring IInstancesOf<T> throughout Arc.Core. Retains only the fix for using the correct type name when constructing ModelBoundQueryPerformer.FullyQualifiedName from generated metadata.
Changed
- Restored
IInstancesOf<T>inAuthentication,AuthorizationEvaluator,CommandContextValuesBuilder,CommandFilters,CommandHandlerProviders,CommandResponseValueHandlers,QueryFilters, andQueryPerformerProviders - Reverted spec files back to
KnownInstancesOf<T>construction instead of plain array literals
Removed
- Explicit
TryAddSingleton/AddSingletonregistrations for Arc.Core-owned services fromCommandServiceCollectionExtensions,QueryServiceCollectionExtensions, andHostBuilderExtensions [DynamicDependency]attributes fromQueryMetadataGeneratorgenerated initializer andIntrospectionEndpointMapper- AOT project properties (
PublishAot,TreatAsLocalProperty,GlobalPropertiesToRemove,IlcArgitems) fromArc.Core.CodeAnalysis.csproj,Arc.Core.Generators.csproj,Arc.Core.csproj, andArcCore.csproj publish:aot:mangledscript fromTestApps/ArcCore/package.jsonand the accompanyingREADME.md
Release v20.10.8
Summary
Fixes /.cratis/queries (and other introspection endpoints) returning empty arrays under NativeAOT.
Root cause: Under NativeAOT, DependencyContext.Load(entryAssembly) returns null, causing Types.Instance.All to be empty. IInstancesOf<T> resolves to an empty collection, so no Arc.Core services were properly wired.
Changes
- Replaced
IInstancesOf<T>withIEnumerable<T>in all Arc.Core service constructors (Authentication,AuthorizationEvaluator,CommandContextValuesBuilder,CommandFilters,CommandHandlerProviders,CommandResponseValueHandlers,QueryFilters,QueryPerformerProviders) — standard DI works correctly under NativeAOT - Added explicit
TryAddSingleton/AddSingletonregistrations for all Arc.Core-owned service implementations inAddCratisArcCore(),AddCratisCommands(), andAddCratisQueries()so the framework self-registers without relying on convention scanning - Added
[DynamicDependency]attributes to the[ModuleInitializer]emitted byQueryMetadataGeneratorto preserve read model types from NativeAOT trimming - Added
[DynamicDependency]attributes toIntrospectionEndpointMapperforCommandIntrospectionMetadata,QueryIntrospectionMetadata, andQueryResult - Cleaned up
TestApps/ArcCore/Program.cs— all manual workaround registrations removed; app is now clean - Updated specs to use array literals instead of
KnownInstancesOf<T>
Release v20.10.7
Fixed
- Fix model-bound queries created from generated metadata so they keep the generated fully qualified query name.
- Add NativeAOT mangled publish support for the ArcCore test app.
Release v20.10.6
Fixed
- Fixing removal of items identified by
Guidfor delta versions of observable queries. The removal was issued from the backend, but the frontend never removed them.
Release v20.10.5
Fixed
- Observable query response data is now properly deserialized for all transfer modes, fixing Guid fields and other strongly-typed fields losing their methods (#2173)
Summary
The initial fix (PR #2176) only addressed delta mode changeSet deserialization, but the root cause affects all observable query responses, not just delta updates.
The Problem
When observable query responses arrive from the server, the data is transmitted as plain JSON objects. The code was never deserializing this data into model instances with their @field decorators applied. This caused:
- Guid fields to lose their
.equals()method - DateTime fields to be plain strings instead of Date instances
- Other strongly-typed fields to lack their methods
- Downstream components (like ChecklistValidation) to crash when calling methods
Root Cause
The issue exists in ALL response paths:
- Initial response with full data array —
QueryResultWithState.fromQueryResult()just passes data through without deserializing - Subsequent full-data responses (non-delta mode) — Same issue
- Delta mode with changeSet items — The changeSet items were deserialized in PR #2176, but...
- Delta mode fallback (no previous result) — Falls back to un-deserialized data
The Fix
Added deserializeResponseData() function that:
- Checks if data is an array and modelType is available
- Calls
JsonSerializer.deserializeArrayFromInstance()to instantiate all items with proper types - Covers all response paths in the subscription callback
Now all response data, regardless of transfer mode, is properly instantiated with @field decorators applied and methods available.
Testing
- Existing regression test from PR #2176 still passes
- All adjacent observable query tests pass
- Full Release build succeeds without warnings
Release v20.10.4
Fixed
- Guid fields in observable query items now retain their methods (like
.equals()) when reconstructed from change sets in delta mode (#2173)
Summary
Commit b52ecba introduced delta change-set optimization to reduce bandwidth by only sending items that were added, replaced, or removed since the last update. However, the change-set items were not being deserialized into typed model instances, causing Guid fields (and other strongly-typed fields) to remain as plain JSON objects and lose their methods.
This fix adds deserialization of all change-set items (added, replaced, removed) using JsonSerializer.deserializeArrayFromInstance before applying delta reconstruction in useObservableQuery, ensuring Guid fields are properly instantiated and methods like .equals() work correctly.
The fix includes a regression test that reproduces the exact failure scenario and ensures this issue doesn't regress in the future.