Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .docfx/Dockerfile.docfx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG NGINX_VERSION=1.31.0-alpine
ARG NGINX_VERSION=1.31.2-alpine

FROM --platform=$BUILDPLATFORM nginx:${NGINX_VERSION} AS base
RUN rm -rf /usr/share/nginx/html/*
Expand Down
15 changes: 15 additions & 0 deletions .docfx/api/namespaces/Savvyio.Commands.Messaging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
uid: Savvyio.Commands.Messaging
summary: *content
---
Unlike in-process command dispatch through `CommandDispatcher`, commands sent to external services need a transport envelope. `CommandExtensions.ToMessage<T>` wraps any `ICommand` in an `IMessage<T>` envelope, and `InMemoryCommandQueue` replays that envelope in unit tests without a real broker.

Start with `CommandExtensions.ToMessage<T>`, hand the `IMessage<T>` to a queue from one of the transport extension packages (NATS, RabbitMQ, Azure Queue Storage, Amazon SQS), and swap in `InMemoryCommandQueue` when you need to test the dispatch pipeline without infrastructure.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|T|⬇️|`ToMessage<T>`|
10 changes: 9 additions & 1 deletion .docfx/api/namespaces/Savvyio.Commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
uid: Savvyio.Commands
summary: *content
---
The `Savvyio.Commands` namespace holds all the abstractions and core types related to commands (C in Cqrs).
Use the `Savvyio.Commands` namespace to model and dispatch write-side operations in a CQRS application. A command represents intent to change state — implement `Command` as your base class when you want a concrete, serializable command payload, then register a `CommandHandler` to process it.

Start with `Command` for your command payload classes. Register a handler that extends `CommandHandler<TCommand>`, and use `SavvyioOptions.AddCommandDispatcher` and `SavvyioOptions.AddCommandHandler` to wire them into the DI container. Route commands through `CommandDispatcher` or use the higher-level `Mediator` from `Savvyio.Extensions`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|SavvyioOptions|⬇️|`AddCommandHandler<TImplementation>`, `AddCommandDispatcher`|
4 changes: 3 additions & 1 deletion .docfx/api/namespaces/Savvyio.Data.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
uid: Savvyio.Data
summary: *content
---
The `Savvyio.Data` namespace holds all the abstractions and core types related to data.
Use the `Savvyio.Data` namespace to define infrastructure-agnostic data access contracts. The interfaces here describe what your repositories and data stores must be able to do — read, write, delete, search, and persist — without tying your domain model to a specific database or ORM.

Start with `IPersistentDataStore<T, TOptions>` for a full-lifecycle data store, or compose narrower contracts: `IReadableDataStore<T>`, `IWritableDataStore<T>`, `IDeletableDataStore<T>`, and `ISearchableDataStore<T>`. Implementations for Entity Framework Core and Dapper are available in their respective extension packages.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]
9 changes: 9 additions & 0 deletions .docfx/api/namespaces/Savvyio.Diagnostics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
uid: Savvyio.Diagnostics
summary: *content
---
Use the `Savvyio.Diagnostics` namespace to add health monitoring to a Savvy I/O application. `IHealthCheckProvider` and `IAsyncHealthCheckProvider` define synchronous and asynchronous health-check contracts that infrastructure components can implement to report their operational status.

Start with `IAsyncHealthCheckProvider` when the health check involves I/O — for example, verifying that a database connection is available or that a message broker is reachable. Use `IHealthCheckProvider` for lightweight, synchronous checks. Both interfaces integrate with standard health check pipelines.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]
4 changes: 3 additions & 1 deletion .docfx/api/namespaces/Savvyio.Dispatchers.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
uid: Savvyio.Dispatchers
summary: *content
---
The `Savvyio.Dispatchers` namespace holds all the abstractions and core types related to dispatchers.
Use the `Savvyio.Dispatchers` namespace to route commands, queries, and events to their registered handlers. The dispatcher layer decouples the caller from the handler — the caller sends a request to the dispatcher and the framework locates the correct handler.

Start with `FireForgetDispatcher` for commands and domain events (no return value expected) and `RequestReplyDispatcher` for queries that return a result. Both extend the base `Dispatcher` and use a `ServiceLocator` to resolve handlers from the DI container. For a unified entry point that routes all request types, use `Mediator` from the `Savvyio.Extensions` namespace.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]
15 changes: 15 additions & 0 deletions .docfx/api/namespaces/Savvyio.Domain.EventSourcing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
uid: Savvyio.Domain.EventSourcing
summary: *content
---
Instead of storing current aggregate state, event sourcing records every state-changing event and reconstructs the aggregate by replaying them. The `Savvyio.Domain.EventSourcing` namespace provides the base types that make this possible.

Start with `TracedAggregateRoot` as the base class for aggregates whose history must be persisted. Each state change produces a `TracedDomainEvent` that carries the aggregate ID, version, member type, and the delta. Use the extension methods on `ITracedDomainEvent` to read and write aggregate version metadata. Persistence is provided by `Savvyio.Extensions.EFCore.Domain.EventSourcing`; DI registration is in `Savvyio.Extensions.DependencyInjection.Domain.EventSourcing`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|T|⬇️|`SetAggregateVersion<T>`, `GetAggregateVersion<T>`, `GetMemberType<T>`|
12 changes: 11 additions & 1 deletion .docfx/api/namespaces/Savvyio.Domain.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@
uid: Savvyio.Domain
summary: *content
---
The `Savvyio.Domain` namespace holds all the abstractions and core types related to DDD.
Use the `Savvyio.Domain` namespace to model the core business domain using Domain-Driven Design: aggregate roots with encapsulated domain events, value objects with structural equality, entities with identity, and single-value objects for type-safe primitives.

Start with `AggregateRoot` when your domain concept has a lifecycle and raises events. Use `Entity` for objects with identity that are governed by an aggregate, `ValueObject` for immutable equality by value, and `SingleValueObject` for primitives like identifiers or money amounts. Register a `DomainEventHandler` and configure dispatching with `SavvyioOptions.AddDomainEventDispatcher` and `AddDomainEventHandler`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|T|⬇️|`GetEventId<T>`, `GetTimestamp<T>`|
|IDomainEventDispatcher|⬇️|`RaiseMany<T>`, `RaiseManyAsync<T>`|
|SavvyioOptions|⬇️|`AddDomainEventHandler<TImplementation>`, `AddDomainEventDispatcher`|
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
uid: Savvyio.EventDriven.Messaging.CloudEvents.Cryptography
summary: *content
---
Receivers of CloudEvents need cryptographic proof that the event has not been altered in transit. The `Savvyio.EventDriven.Messaging.CloudEvents.Cryptography` namespace provides signing and verification for `ICloudEvent<T>` through `SignedCloudEvent<T>`.

Start with `CloudEventExtensions.SignCloudEvent<T>` to produce a `SignedCloudEvent<T>` with an attached signature. On the consumer side, call `SignedCloudEventExtensions.CheckCloudEventSignature<T>` to verify authenticity before processing. Use this namespace alongside `Savvyio.EventDriven.Messaging.CloudEvents`; for plain message signing without CloudEvents, see `Savvyio.Messaging.Cryptography`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|ICloudEvent<T>|⬇️|`SignCloudEvent<T>`|
|ISignedCloudEvent<T>|⬇️|`CheckCloudEventSignature<T>`|
15 changes: 15 additions & 0 deletions .docfx/api/namespaces/Savvyio.EventDriven.Messaging.CloudEvents.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
uid: Savvyio.EventDriven.Messaging.CloudEvents
summary: *content
---
[CloudEvents](https://cloudevents.io/) is a CNCF standard for describing event data in a portable way. The `Savvyio.EventDriven.Messaging.CloudEvents` namespace adapts `IMessage<T>` envelopes to this format, enabling interoperability with CloudEvents-aware brokers and consumers.

Start with `MessageExtensions.ToCloudEvent<T>` to convert an `IMessage<T>` into a `CloudEvent<T>`. Use this namespace when the receiving service expects the CloudEvents schema rather than the native Savvy I/O message format. To add a cryptographic signature to the cloud event, see `Savvyio.EventDriven.Messaging.CloudEvents.Cryptography`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|IMessage<T>|⬇️|`ToCloudEvent<T>`|
15 changes: 15 additions & 0 deletions .docfx/api/namespaces/Savvyio.EventDriven.Messaging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
uid: Savvyio.EventDriven.Messaging
summary: *content
---
Publishers wrap an integration event in an `IMessage<T>` envelope using `IntegrationEventExtensions.ToMessage<T>` before routing it to a broker. Subscribers unwrap the payload and dispatch the domain event. Start with `IntegrationEventExtensions.ToMessage<T>` to produce the envelope from any `IIntegrationEvent`.

Pass the `IMessage<T>` to an event bus from one of the transport extension packages (NATS, RabbitMQ, Azure Queue Storage, Amazon SNS/SQS). `InMemoryEventBus` stands in during unit tests for any broker. Brokerless in-process dispatch goes through `IntegrationEventDispatcher` from `Savvyio.EventDriven`, which does not use a message envelope.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|T|⬇️|`ToMessage<T>`|
11 changes: 10 additions & 1 deletion .docfx/api/namespaces/Savvyio.EventDriven.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@
uid: Savvyio.EventDriven
summary: *content
---
The `Savvyio.EventDriven` namespace holds all the abstractions and core types related to integration events.
Use the `Savvyio.EventDriven` namespace to define and dispatch integration events — messages that cross service boundaries and enable eventual consistency in a distributed system. An integration event announces that something has happened in one service so that other services can react.

Start with `IntegrationEvent` as the base class for your cross-service event payloads. Register an `IntegrationEventHandler` and connect it to the DI container with `SavvyioOptions.AddIntegrationEventDispatcher` and `AddIntegrationEventHandler`. Use the extension methods on `IIntegrationEvent` to read the event ID, timestamp, and member type from the event's metadata.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|T|⬇️|`GetEventId<T>`, `GetTimestamp<T>`, `GetMemberType<T>`|
|SavvyioOptions|⬇️|`AddIntegrationEventHandler<TImplementation>`, `AddIntegrationEventDispatcher`|
9 changes: 9 additions & 0 deletions .docfx/api/namespaces/Savvyio.Extensions.Dapper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
uid: Savvyio.Extensions.Dapper
summary: *content
---
Use the `Savvyio.Extensions.Dapper` namespace to access data using Dapper — a lightweight micro-ORM that executes raw SQL and maps results to your domain objects. It provides `DapperDataSource` as the connection factory and `DapperDataStore` as the base class for Dapper-backed read and write data stores.

Start with `DapperDataSource<TContext>` to wrap a database connection factory that implements `IDapperDataSource`. Extend `DapperDataStore<T, TContext>` to write your repository logic using Dapper's `Execute`, `Query`, and `QueryAsync` methods. Configure query options through `DapperQueryOptions`. Register with `Savvyio.Extensions.DependencyInjection.Dapper`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]
9 changes: 9 additions & 0 deletions .docfx/api/namespaces/Savvyio.Extensions.DapperExtensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
uid: Savvyio.Extensions.DapperExtensions
summary: *content
---
DapperExtensions adds automatic CRUD mapping on top of Dapper. The `Savvyio.Extensions.DapperExtensions` namespace provides `DapperExtensionsDataStore` as the base class and `DapperExtensionsQueryOptions` for configuring query execution.

Start with `DapperExtensionsDataStore<T, TContext>` when you want auto-mapped CRUD without writing SQL for each operation. Configure query behavior through `DapperExtensionsQueryOptions`. Register with `Savvyio.Extensions.DependencyInjection.DapperExtensions`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
uid: Savvyio.Extensions.DependencyInjection.Dapper
summary: *content
---
Dapper persistence needs both a connection factory and a data store. The `Savvyio.Extensions.DependencyInjection.Dapper` namespace provides `AddDapperDataSource<TMarker>` for the connection factory and `AddDapperDataStore<TService, T>` for each data store, combining both concerns in one namespace.

Start with `AddDapperDataSource<TMarker>` to configure the connection and register `IDapperDataSource`. Then add `AddDapperDataStore<TService, T>` for each data store your application needs. Choose this namespace when you want lightweight, handwritten SQL via Dapper without an ORM; for convention-based automatic CRUD instead, prefer `Savvyio.Extensions.DependencyInjection.DapperExtensions`, and for EF Core, use `Savvyio.Extensions.DependencyInjection.EFCore`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|IServiceCollection|⬇️|`AddDapperDataSource`, `AddDapperDataSource<TMarker>`, `AddDapperDataSource<TService>`, `AddDapperDataStore<TService, T>`|
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
uid: Savvyio.Extensions.DependencyInjection.DapperExtensions
summary: *content
---
DapperExtensions adds automatic CRUD on top of Dapper. The `Savvyio.Extensions.DependencyInjection.DapperExtensions` namespace provides `AddDapperExtensionsDataStore<T>` and `AddDapperExtensionsDataStore<T, TMarker>` to register the `DapperExtensionsDataStore` implementation from `Savvyio.Extensions.DapperExtensions`.

Start with `AddDapperExtensionsDataStore<T>` to bind a data store interface to its DapperExtensions implementation. Choose this namespace when you want automatic CRUD without writing SQL statements — DapperExtensions infers INSERT/UPDATE/DELETE/SELECT from class mapping conventions. For handwritten SQL, use `Savvyio.Extensions.DependencyInjection.Dapper` instead. Combine with `Savvyio.Extensions.DependencyInjection.Dapper` for the shared connection factory.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|IServiceCollection|⬇️|`AddDapperExtensionsDataStore<T>`, `AddDapperExtensionsDataStore<T, TMarker>`|
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
uid: Savvyio.Extensions.DependencyInjection.Data
summary: *content
---
Registering data stores without tying to a technology keeps the domain model portable. The `Savvyio.Extensions.DependencyInjection.Data` namespace provides `AddDataStore<TService, T>` and `AddDataStore<TService, T, TOptions>` for this purpose.

Start with `AddDataStore<TService, T>` to bind an `IDataStore` interface to its implementation. Choose this namespace when your domain layer depends only on the abstract `IDataStore` interface family and you want the concrete implementation resolved by DI without referencing a specific ORM or data-access library. For technology-specific registrations that also configure a connection or context, see `Savvyio.Extensions.DependencyInjection.EFCore`, `Savvyio.Extensions.DependencyInjection.Dapper`, or `Savvyio.Extensions.DependencyInjection.DapperExtensions`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|IServiceCollection|⬇️|`AddDataStore<TService, T>`, `AddDataStore<TService, T, TOptions>`|
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
uid: Savvyio.Extensions.DependencyInjection.Domain.EventSourcing
summary: *content
---
Event-sourced aggregates require a specialized repository that stores and replays traced domain events rather than current state. The `Savvyio.Extensions.DependencyInjection.Domain.EventSourcing` namespace provides `AddTracedAggregateRepository<TService, TEntity, TKey>` and the `ITracedAggregateRepository` marker interface.

Start with `AddTracedAggregateRepository<TService, TEntity, TKey>` to bind an `ITracedAggregateRepository` to its implementation. For the EF Core–backed implementation, use `Savvyio.Extensions.DependencyInjection.EFCore.Domain.EventSourcing`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|IServiceCollection|⬇️|`AddTracedAggregateRepository<TService, TEntity, TKey>`|
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
uid: Savvyio.Extensions.DependencyInjection.Domain
summary: *content
---
Registering DDD aggregate repositories in the DI container is done through this namespace. It provides `AddAggregateRepository<TService, TEntity, TKey>`, `AddRepository<TService, TEntity, TKey>`, and `AddUnitOfWork<TService>` for binding aggregate and read-model repository contracts to their implementations.

Start with `AddAggregateRepository<TService, TEntity, TKey>` to register the primary aggregate repository. Use `AddUnitOfWork<TService>` when your domain layer requires a unit-of-work coordinator. For event-sourced aggregates, add `Savvyio.Extensions.DependencyInjection.Domain.EventSourcing`. For EF Core–backed implementations, prefer `Savvyio.Extensions.DependencyInjection.EFCore.Domain`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|IServiceCollection|⬇️|`AddAggregateRepository<TService, TEntity, TKey>`, `AddRepository<TService, TEntity, TKey>`, `AddUnitOfWork<TService>`|
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
uid: Savvyio.Extensions.DependencyInjection.EFCore.Domain.EventSourcing
summary: *content
---
Event sourcing with EF Core requires a dedicated repository that writes traced domain events. The `Savvyio.Extensions.DependencyInjection.EFCore.Domain.EventSourcing` namespace provides `AddEfCoreTracedAggregateRepository<TEntity, TKey>` and `AddEfCoreTracedAggregateRepository<TEntity, TKey, TMarker>` to register this repository.

Start with `AddEfCoreTracedAggregateRepository<TEntity, TKey>` to bind `ITracedAggregateRepository` to `EfCoreTracedAggregateRepository`. Choose this namespace when your domain uses event sourcing and stores aggregate history as a sequence of immutable traced events in a relational database; for standard non-event-sourced aggregates with EF Core, use `Savvyio.Extensions.DependencyInjection.EFCore.Domain` instead. Pair with `Savvyio.Extensions.EFCore.Domain.EventSourcing` which provides the `ModelBuilder` extension to create the event-store schema in `OnModelCreating`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|IServiceCollection|⬇️|`AddEfCoreTracedAggregateRepository<TEntity, TKey>`, `AddEfCoreTracedAggregateRepository<TEntity, TKey, TMarker>`|
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
uid: Savvyio.Extensions.DependencyInjection.EFCore.Domain
summary: *content
---
Aggregate roots require their own context boundary. The `Savvyio.Extensions.DependencyInjection.EFCore.Domain` namespace provides `AddEfCoreAggregateDataSource<TMarker>` and `AddEfCoreAggregateRepository<TEntity, TKey>` to register EF Core persistence for aggregate roots.

Start with `AddEfCoreAggregateDataSource<TMarker>` to configure the `DbContext` as a domain data source. Then add `AddEfCoreAggregateRepository<TEntity, TKey>` for each aggregate root type. For event-sourced aggregates, use `Savvyio.Extensions.DependencyInjection.EFCore.Domain.EventSourcing`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]

### Extension Members

|Type|Ext|Methods|
|--:|:-:|---|
|IServiceCollection|⬇️|`AddEfCoreAggregateDataSource`, `AddEfCoreAggregateDataSource<TMarker>`, `AddEfCoreAggregateRepository<TEntity, TKey>`, `AddEfCoreAggregateRepository<TEntity, TKey, TMarker>`|
Loading
Loading