JAAvila.FluentOperations 1.5.2

dotnet add package JAAvila.FluentOperations --version 1.5.2
                    
NuGet\Install-Package JAAvila.FluentOperations -Version 1.5.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="JAAvila.FluentOperations" Version="1.5.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="JAAvila.FluentOperations" Version="1.5.2" />
                    
Directory.Packages.props
<PackageReference Include="JAAvila.FluentOperations" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add JAAvila.FluentOperations --version 1.5.2
                    
#r "nuget: JAAvila.FluentOperations, 1.5.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package JAAvila.FluentOperations@1.5.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=JAAvila.FluentOperations&version=1.5.2
                    
Install as a Cake Addin
#tool nuget:?package=JAAvila.FluentOperations&version=1.5.2
                    
Install as a Cake Tool

JAAvila.FluentOperations

Tests .NET C# License

A fluent validation and testing library for .NET that unifies inline assertions and model validation through Quality Blueprints with automatic scenario inference.

Packages

Package Description
JAAvila.FluentOperations Core library — inline .Test() assertions and Quality Blueprints
JAAvila.FluentOperations.DependencyInjection DI extensions for blueprint registration
JAAvila.FluentOperations.AspNetCore ASP.NET Core action filters for automatic validation
JAAvila.FluentOperations.MediatR MediatR pipeline behavior for request validation
JAAvila.FluentOperations.MinimalApi Minimal API endpoint filters for automatic validation
JAAvila.FluentOperations.Analyzers Roslyn analyzers for compile-time usage checks (FO001, FO003)
JAAvila.FluentOperations.OpenApi Swashbuckle schema filter that enriches OpenAPI schemas with blueprint constraints
JAAvila.FluentOperations.Grpc gRPC server interceptor for automatic request validation
JAAvila.FluentOperations.DataAnnotations DataAnnotations bridge — generate blueprint rules from attributes
JAAvila.FluentOperations.Architecture Deep dependency detection via Mono.Cecil (opt-in IL-level scanning for architecture tests)
dotnet add package JAAvila.FluentOperations

Quick Start

Inline Assertions

using JAAvila.FluentOperations;

// Strings
"user@example.com".Test().NotBeNull().NotBeEmpty().Contain("@").BeEmail();

// Numerics
42.Test().BePositive().BeLessThan(100).BeEven();
3.14m.Test().BeInRange(0m, 10m).HavePrecision(2);

// Date/Time
DateTime.Now.Test().BeToday().BeWeekday();

// Collections
new[] { 1, 2, 3 }.Test().HaveCount(3).Contain(2).BeInAscendingOrder();

// Exceptions
Action act = () => throw new InvalidOperationException("fail");
act.Test().Throw<InvalidOperationException>().WithMessage("*fail*");

// Assertion Scope (batch failures)
using (new AssertionScope())
{
    "".Test().NotBeEmpty();
    0.Test().BePositive();
}
// Throws single exception with all failures combined

Quality Blueprints (Model Validation)

public class UserBlueprint : QualityBlueprint<User>
{
    public UserBlueprint()
    {
        using (Define())
        {
            For(x => x.Email).Test().NotBeNull().NotBeEmpty().BeEmail();
            For(x => x.Name).Test().NotBeNull().HaveMinLength(2);
            For(x => x.Age).Test().BeInRange(18, 120);
        }
    }
}

var blueprint = new UserBlueprint();
var report = blueprint.Check(new User { Email = "", Name = "J", Age = 15 });

if (!report.IsValid)
{
    foreach (var failure in report.Failures)
        Console.WriteLine($"{failure.PropertyName}: {failure.Message}");
}

Supported Types

Category Types Operations
String string? 45+ ops: Be, NotBe, BeEmpty, NotBeNullOrEmpty, Contain, NotContain, Match (regex), BeEmail, BeUrl, BeJson, BeXml, BeSemVer, BeIPAddress, BeCreditCard, MatchWildcard, ContainAll, ContainAny, HaveLengthGreaterThan, HaveLengthLessThan, BeOneOf, NotBeOneOf...
Boolean bool, bool? Be, BeTrue, BeFalse, BeAllTrue, BeAllFalse, Imply, HaveValue
Numeric int, long, decimal, double, float (+ nullable) Be, BePositive, BeNegative, BeZero, BeGreaterThan, BeLessThan, BeInRange, BeOneOf, BeDivisibleBy, BeEven, BeOdd, BeApproximately (decimal, double, float), HavePrecision, BeNaN, BeInfinity, BeFinite...
Date/Time DateTime, DateOnly, TimeOnly, TimeSpan, DateTimeOffset (+ nullable) Be, BeAfter, BeBefore, BeInRange, BeToday, BeInThePast, BeInTheFuture, BeWeekday, BeCloseTo, NotBeCloseTo, HaveYear...
Collections IEnumerable<T>, T[], Dictionary<TKey,TValue> HaveCount, Contain, ContainAll, ContainInOrder, OnlyContain, BeSubsetOf, BeInAscendingOrder, BeInAscendingOrder(keySelector), AllSatisfy, BeUnique, HaveElementAt, SatisfyRespectively, HaveMinCount, Inspect, ExtractSingle, Extract (by index, predicate, or key), Evaluate (dictionary), ContainEquivalentOf, NotContainEquivalentOf, NotContainNull, HaveCountBetween, ContainKeys (dictionary)...
Special Guid, Guid?, Enum<T>, Uri? Be, BeEmpty, BeDefined, HaveFlag, HaveScheme, BeAbsolute...
Object object? BeNull, NotBeNull, BeSameAs, BeOfType, BeAssignableTo, BeEquivalentTo (with builder options)
Action Action, Func<Task> Throw, ThrowExactly, NotThrow, NotThrowAfter, CompleteWithinAsync
Type Type 77 ops: BeClass, BeInterface, BeAbstract, BeSealed, BeStatic, BePublic, BeInternal, BeGeneric, BeRecord, BeValueType, BeEnum, BeNested, BeImmutable, BeInNamespace, ImplementInterface, DeriveFrom, HaveAttribute, HaveConstructorWithParameters, HavePropertyOfType, HaveMethodReturning, HaveMethodOverride, HaveMaxPublicMethods, HaveMaxFields, NotHaveAsyncVoidMethods, HaveDependencyOn, OnlyHaveDependenciesOn, HaveDependencyOnType, MatchName, MatchNamespace...
Assembly Assembly 8 ops: ContainType, ContainTypeMatching, ReferenceAssembly, NotReferenceAssembly, HaveVersion, HaveMinimumVersion, HavePublicKey

Blueprint Features

Scenario-Based Validation

// Define your own marker interfaces — Scenario<T> works with any interface
public interface ICreateOrder { }
public interface IUpdateOrder { }

public class OrderBlueprint : QualityBlueprint<Order>
{
    public OrderBlueprint()
    {
        using (Define())
        {
            For(x => x.OrderId).Test().NotBeNull(); // Always applied

            Scenario<ICreateOrder>(() =>
            {
                For(x => x.CustomerId).Test().NotBeNull();
            });

            Scenario<IUpdateOrder>(() =>
            {
                For(x => x.Status).Test().NotBe("Closed");
            });
        }
    }
}

// Automatic scenario inference from interfaces
public class OrderForCreate : Order, ICreateOrder { }
var report = blueprint.Check(new OrderForCreate { ... }); // global + create rules

Severity, Error Codes, Custom Messages

using (Define())
{
    For(x => x.Email, new RuleConfig
    {
        Severity = Severity.Error,
        ErrorCode = "EMAIL_REQUIRED",
        CustomMessage = "A valid email is required"
    }).Test().NotBeNull().BeEmail();

    For(x => x.Nickname, new RuleConfig { Severity = Severity.Warning })
        .Test().HaveMinLength(3);
}

var report = blueprint.Check(model);
report.HasErrors;    // Only Severity.Error
report.HasWarnings;  // Only Severity.Warning
report.Errors;       // Filtered list

Dynamic Error Messages (MessageFactory)

Use MessageFactory in RuleConfig to generate error messages with access to the root model instance:

using (Define())
{
    For(x => x.Items, new RuleConfig
    {
        MessageFactory = model =>
        {
            var order = (Order)model;
            return $"Order #{order.Id} for '{order.CustomerName}' exceeds the maximum of {order.MaxItems} items.";
        }
    }).Test().HaveLengthLessThanOrEqualTo(10);

    For(x => x.Email, new RuleConfig
    {
        Severity = Severity.Warning,
        ErrorCode = "EMAIL_FORMAT",
        MessageFactory = model =>
        {
            var user = (User)model;
            return $"Email format for user '{user.Name}' (role: {user.Role}) is non-standard.";
        }
    }).Test().BeEmail();
}

MessageFactory receives the model as object — cast to your model type inside the lambda. It takes precedence over CustomMessage and the auto-generated template. It is only invoked during Blueprint Check()/CheckAsync() evaluation when the rule fails.

Async Validation

using (Define())
{
    ForAsync(x => x.Email, async email =>
    {
        return await emailService.IsAvailableAsync(email);
    }, "Email is already taken");
}

var report = await blueprint.CheckAsync(model);

Cross-Property Comparison

using (Define())
{
    ForCompare(x => x.StartDate, x => x.EndDate).BeLessThan();
    ForCompare(x => x.Password, x => x.ConfirmPassword).Be();
}

Conditional Validation

using (Define())
{
    When(
        condition: x => x.IsInternational,
        then: () =>
        {
            For(x => x.PassportNumber).Test().NotBeNull();
        },
        otherwise: () =>
        {
            For(x => x.NationalId).Test().NotBeNull();
        }
    );
}

Nested Objects, ForEach, Include

using (Define())
{
    // Nested object validation
    ForNested(x => x.Address, new AddressBlueprint());

    // Per-item collection validation (sub-blueprint)
    ForEach(x => x.Items, new OrderItemBlueprint());

    // Per-item collection validation (captured-rules with optional RuleConfig)
    ForEach(x => x.Tags, new RuleConfig { CascadeMode = CascadeMode.StopOnFirstFailure })
        .Test().NotBeNull().HaveMinLength(3);

    // Compose blueprints
    Include(new BaseEntityBlueprint());
}

CompositeBlueprint<T>

Compose N independent blueprints at runtime and merge their results into a single QualityReport. Each blueprint runs independently — unlike Include() (static rule copy), composites keep blueprints fully decoupled.

var composite = new CompositeBlueprint<User>(
    new NameBlueprint(),
    new EmailBlueprint(),
    new AgeBlueprint());

// Sequential
QualityReport report = composite.Check(user);

// Parallel (Task.WhenAll)
QualityReport report = await composite.CheckAsync(user);

Console.WriteLine(report.IsValid);         // false if any sub-blueprint has Error failures
Console.WriteLine(report.RulesEvaluated);  // sum across all blueprints
Console.WriteLine(report.Failures.Count);  // all failures from all blueprints

DI registration (with JAAvila.FluentOperations.DependencyInjection):

// Only the composite is registered as IBlueprintValidator — NOT the individual blueprints.
services.AddCompositeBlueprint<User>(
    typeof(NameBlueprint),
    typeof(EmailBlueprint));

CascadeMode

public class StrictBlueprint : QualityBlueprint<Order>
{
    public StrictBlueprint()
    {
        CascadeMode = CascadeMode.StopOnFirstFailure;

        using (Define())
        {
            For(x => x.Email).Test().NotBeNull().BeEmail();
        }
    }
}

Transformation Rules

using (Define())
{
    // Validate a transformed value (same-type: trim whitespace)
    ForTransform(x => x.Email, email => email?.Trim())
        .Test().NotBeNull().NotBeEmpty();

    // Cross-type: transform DateTime → int, then validate as integer
    ForTransform(x => x.BirthDate, (DateTime d) => DateTime.Now.Year - d.Year)
        .Test().BeGreaterThanOrEqualTo(18);
}

Custom Validators

public class LuhnValidator : ICustomValidator<string?>
{
    public bool Validate(string? value) => /* Luhn algorithm */;
    public string FailureMessage => "Invalid card number";
}

using (Define())
{
    ForCustom(x => x.CardNumber, new LuhnValidator());
}

Reusable Rules

Define domain rules as extension methods on concrete managers — they work in inline, blueprint, and AssertionScope modes without any library changes:

public static StringOperationsManager MustBeValidIban(this StringOperationsManager m)
    => m.NotBeNull().HaveLengthBetween(15, 34)
        .Match(@"^[A-Z]{2}\d{2}[A-Z0-9]{4}\d{7}([A-Z0-9]?){0,16}$");

public static DecimalOperationsManager MustBeValidAmount(this DecimalOperationsManager m)
    => m.BePositive().BeInRange(0.01m, 999_999_999.99m).HaveMaxDecimalPlaces(2);

// Inline
iban.Test().MustBeValidIban();

// Blueprint
For(x => x.Iban).Test().MustBeValidIban();
For(x => x.Amount).Test().MustBeValidAmount();

// AssertionScope
using (new AssertionScope())
{
    iban.Test().MustBeValidIban();
    amount.Test().MustBeValidAmount();
}

Rules with parameters, ForTransform, Scenarios, and RuleConfig all work transparently. See Reusable Rule Builders Guide for the full guide.

Blueprint Assertions (Test-to-Production Bridge)

// Use blueprints as direct assertions in tests
var blueprint = new UserBlueprint();
blueprint.Assert(user);           // Throws if invalid
await blueprint.AssertAsync(user); // Async version

// Works with AssertionScope
using (new AssertionScope())
{
    blueprint.Assert(user1);  // Failures accumulate
    blueprint.Assert(user2);  // All reported together
}

// In production: returns report (unchanged)
var report = blueprint.Check(user);

Architecture Testing

Validate code structure, naming conventions, dependency rules, and design constraints at test time.

Type Assertions

using JAAvila.FluentOperations;

// Structural rules
typeof(MyService).Test()
    .BeClass()
    .BePublic()
    .NotBeAbstract()
    .ImplementInterface<IMyService>()
    .NotHaveAsyncVoidMethods();

// Naming conventions
typeof(UserRepository).Test()
    .HaveNameEndingWith("Repository")
    .BeInNamespaceStartingWith("MyApp.Infrastructure");

// Dependency rules
typeof(DomainEntity).Test()
    .NotHaveDependencyOn("MyApp.Infrastructure")
    .NotHaveDependencyOn("Microsoft.EntityFrameworkCore")
    .OnlyHaveDependenciesOn("MyApp.Domain", "MyApp.Shared");

// Constructor and member rules
typeof(MyController).Test()
    .HavePublicConstructor()
    .HaveMaxPublicMethods(10)
    .HaveMaxFields(5);

Assembly Assertions

typeof(MyService).Assembly.Test()
    .ContainType<MyService>()
    .ContainTypeMatching(@".*Controller$")
    .NotReferenceAssembly("Newtonsoft.Json")
    .HaveMinimumVersion(new Version(1, 0));

Batch Type Selection

Use the Types utility to select and filter types, then validate each one:

using JAAvila.FluentOperations.Architecture;

// All services in an assembly must implement their interface
var serviceTypes = Types.InAssembly(typeof(MyService).Assembly)
    .That(t => t.IsClass && t.Name.EndsWith("Service"));

foreach (var type in serviceTypes)
    type.Test().ImplementInterface<IService>();

// Domain types must not depend on infrastructure
var domainTypes = Types.InNamespace("MyApp.Domain");

foreach (var type in domainTypes)
    type.Test().NotHaveDependencyOn("MyApp.Infrastructure");

Deep Dependency Scanning (Optional)

For IL-level dependency detection (method bodies, lambdas, async state machines), install the optional package:

dotnet add package JAAvila.FluentOperations.Architecture
using JAAvila.FluentOperations.Architecture;

[OneTimeSetUp]
public void SetUp() => ArchitectureScannerConfig.UseCecilDependencyScanning();

[OneTimeTearDown]
public void TearDown() => ArchitectureScannerConfig.Reset();

See API Reference — Architecture Testing for the complete list of 85+ operations.

Framework Integration

ASP.NET Core

dotnet add package JAAvila.FluentOperations.AspNetCore
builder.Services.AddControllers(options =>
{
    options.AddBlueprintValidation();
});
builder.Services.AddBlueprintValidationFilter();
builder.Services.AddSingleton<OrderBlueprint>();

MediatR

dotnet add package JAAvila.FluentOperations.MediatR
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(assembly));
builder.Services.AddBlueprintValidation();
builder.Services.AddSingleton<CreateOrderCommandBlueprint>();

Minimal API

dotnet add package JAAvila.FluentOperations.MinimalApi
builder.Services.AddSingleton<CreateOrderBlueprint>();

app.MapPost("/orders", (CreateOrderRequest request) => Results.Ok(request))
    .WithBlueprint<CreateOrderRequest, CreateOrderBlueprint>();
// Returns RFC 7807 ValidationProblem on failure

gRPC

dotnet add package JAAvila.FluentOperations.Grpc
builder.Services.AddGrpcBlueprintValidation();
builder.Services.AddGrpc(o => o.Interceptors.Add<GrpcBlueprintInterceptor>());
builder.Services.AddBlueprints(typeof(Program).Assembly);

When validation fails, the interceptor throws an RpcException with StatusCode.InvalidArgument and per-property validation errors in gRPC trailers.

See Integration Guide for full examples.

OpenAPI Schema Generation

dotnet add package JAAvila.FluentOperations.OpenApi

Automatically enrich Swashbuckle OpenAPI schemas with validation constraints derived from registered blueprints:

builder.Services.AddSwaggerGen(options =>
{
    options.AddFluentOperationsValidation(
        app.Services.GetRequiredService<IEnumerable<IBlueprintValidator>>());
});

JSON Schema Generation

Generate a JSON Schema document or string directly from any blueprint — no additional package required:

var blueprint = new UserBlueprint();

// Returns JsonDocument
JsonDocument schema = blueprint.ToJsonSchema();

// Returns formatted JSON string
string schemaJson = blueprint.ToJsonSchemaString();

Validation Telemetry

Emit metrics via System.Diagnostics.Metrics (OpenTelemetry-compatible, zero external dependencies):

FluentOperationsConfig.Configure(c =>
{
    c.Telemetry.Enabled = true;
    c.Telemetry.TrackBlueprintExecutionTime = true;
    c.Telemetry.TrackRuleExecutionTime = true;
    c.Telemetry.TrackFailureRates = true;
});
Instrument Kind Description
fo.rules.evaluated Counter Total rules evaluated
fo.rules.failed Counter Total rules that failed (requires TrackFailureRates = true)
fo.rule.duration Histogram (ms) Duration of individual eager rule execution
fo.blueprint.duration Histogram (ms) Duration of a full Check() / CheckAsync() call

Metrics are tagged with blueprint, model, is_valid, passed, and severity dimensions.

Snapshot Validation

Compare QualityReport results against stored JSON snapshots for regression testing:

var report = blueprint.Check(model);

// First run: creates the snapshot file
report.UpdateSnapshot("UserBlueprint_CreateUser");

// Subsequent runs: assert the report matches the stored snapshot
report.ShouldMatchSnapshot("UserBlueprint_CreateUser");

DataAnnotations Bridge

dotnet add package JAAvila.FluentOperations.DataAnnotations

Generate blueprint rules automatically from System.ComponentModel.DataAnnotations attributes:

// Auto-generate from annotations only
var blueprint = DataAnnotationsBlueprint<User>.FromAnnotations();
var report = blueprint.Check(user);

// Or subclass to combine with custom rules
public class UserBlueprint : DataAnnotationsBlueprint<User>
{
    public UserBlueprint()
    {
        using (Define())
        {
            IncludeAnnotations(); // maps [Required], [EmailAddress], [StringLength], [Range], etc.
            For(x => x.Name).Test().NotBeEmpty(); // additional custom rules
        }
    }
}

Blueprint Introspection

Inspect the rules registered in any blueprint at runtime:

var blueprint = new UserBlueprint();
IReadOnlyList<BlueprintRuleInfo> rules = blueprint.GetRuleDescriptors();

foreach (var rule in rules)
{
    Console.WriteLine($"{rule.PropertyName}: {rule.OperationName} ({rule.Severity})");
}

BlueprintRuleInfo exposes PropertyName, OperationName, PropertyType, Parameters, Severity, ErrorCode, and Scenario.

Localization

Configure localized validation messages for any culture:

FluentOperationsConfig.Configure(c =>
{
    c.Localization.Provider = new DictionaryMessageProvider()
        .AddMessage("String.BeEmail", "es-ES", "Se esperaba un correo electronico valido.");
    c.Localization.Culture = new CultureInfo("es-ES");
});

Built-in providers: DictionaryMessageProvider (in-memory) and ResourceManagerProvider (.resx files).

Roslyn Analyzers

dotnet add package JAAvila.FluentOperations.Analyzers

Compile-time detection of common mistakes:

Diagnostic Description
FO001 .Test() called without chaining an assertion operation
FO003 Define() in Blueprint without using statement

Test Framework Configuration

FluentOperations auto-detects your test framework (NUnit, xUnit, MSTest, TUnit). Override explicitly:

FluentOperationsConfig.Configure(c =>
    c.TestFramework.Framework = TestFramework.None); // Production mode

Documentation

Project Stats

  • 6528+ tests across NUnit test projects
  • 800+ validators covering 20+ data types including architecture testing
  • 39+ operation managers with fluent chaining
  • 10 NuGet packages (core + integrations + analyzers + architecture + tooling)
  • Performance optimized with lazy initialization, caching, and zero-allocation patterns

License

This project is licensed under the Apache License 2.0 — see the LICENSE file for details.

The names "JAAvila.FluentOperations", "FluentOperations", and "Quality Blueprint" are trademarks of Jose Angel Avila. See the NOTICE file and TRADEMARK.md for attribution requirements and naming restrictions for derivative works.

Author

Created and maintained by JAAvila (Jose Angel Avila)

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (8)

Showing the top 5 NuGet packages that depend on JAAvila.FluentOperations:

Package Downloads
JAAvila.FluentOperations.MediatR

MediatR integration for JAAvila.FluentOperations Quality Blueprints. Provides pipeline behaviors for automatic request validation.

JAAvila.FluentOperations.DependencyInjection

Dependency Injection extensions for JAAvila.FluentOperations Quality Blueprints.

JAAvila.FluentOperations.AspNetCore

ASP.NET Core integration for JAAvila.FluentOperations Quality Blueprints. Provides action filters for automatic model validation.

JAAvila.FluentOperations.MinimalApi

Minimal API integration for JAAvila.FluentOperations Quality Blueprints. Provides endpoint filters for automatic model validation with RFC 7807 Problem Details.

JAAvila.FluentOperations.Grpc

gRPC server interceptor integration for JAAvila.FluentOperations Quality Blueprints. Provides automatic request validation with structured error metadata in gRPC trailers.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.5.2 97 4/3/2026
1.5.1 100 3/29/2026
1.5.0 215 3/29/2026
1.3.0 202 3/26/2026
1.2.0 85 3/21/2026
1.1.0 209 3/21/2026
1.0.3-alpha.0.2 41 3/18/2026
1.0.3-alpha.0.1 40 3/18/2026
1.0.2 93 3/17/2026
1.0.2-alpha.0.4 49 3/14/2026
1.0.2-alpha.0.3 111 3/14/2026
1.0.2-alpha.0.2 47 3/14/2026
1.0.2-alpha.0.1 45 3/14/2026
1.0.1 137 3/9/2026
1.0.0 138 3/8/2026