diff --git a/docs/mediator-framework/implementation-plan.md b/docs/mediator-framework/implementation-plan.md index 62ff3619b..6617c55e3 100644 --- a/docs/mediator-framework/implementation-plan.md +++ b/docs/mediator-framework/implementation-plan.md @@ -630,8 +630,9 @@ interceptor, upload adapter, proto export) are in `src/` packages. follows the "Next implementation order" in `tasks.md` (Phase 8 wire-shape and packaging steps before the remaining Phase 7 behavioral steps), with the full-solution build gate on every step. -- **Phase 9** designs the preview follow-ups tracked as Epic 11: Rebus owner - routing, sample STJ source generation, authenticated OpenAPI UIs and gRPCui. +- **Phase 9** implements the first preview follow-up (T11.4 Rebus owner routing); + the remaining Epic 11 work is sample STJ source generation, authenticated + OpenAPI UIs and gRPCui. The first build attempt on a fresh checkout failed because `--no-restore` was used before assets existed. The verified sequence is `dotnet restore @@ -640,7 +641,7 @@ then `dotnet build Ark.Tools.slnx --configuration Debug --no-restore`. ## Phase 9 — Preview follow-ups -### Step 9.1 — Rebus owner routing (T11.4) +### Step 9.1 — Rebus owner routing (T11.4) ✅ 1. Add an optional `OwnerQueue` named argument to `RebusMessageAttribute`; reject null, empty or whitespace values when supplied and document that it identifies @@ -655,7 +656,7 @@ then `dotnet build Ark.Tools.slnx --configuration Debug --no-restore`. 5. Add generator snapshots plus runtime routing tests under `tests/Ark.Tools.MediatorFramework.Tests`; retain only behavioral workflow coverage in the sample tests. -6. Restore locked dependencies, build the full solution, and run all tests. +6. Restore locked dependencies, build the full solution, and run all tests. ✅ ### Step 9.2 — STJ source generation in the sample (T11.2) diff --git a/docs/mediator-framework/tasks.md b/docs/mediator-framework/tasks.md index b2067ace6..0179e2953 100644 --- a/docs/mediator-framework/tasks.md +++ b/docs/mediator-framework/tasks.md @@ -326,7 +326,7 @@ Debug`) before the task is marked complete. can be enabled as a compatibility option; OpenAPI contains tested OAuth2 authorization-code/PKCE and OpenID Connect schemes; no browser client secret is configured. -- [ ] **T11.4** Generate Rebus owner routing. +- [x] **T11.4** Generate Rebus owner routing. - *Accept:* `RebusMessageAttribute` accepts an optional owner queue; the generator emits type-based `Map(queue)` routing configuration; invalid/blank queues and conflicting mappings produce diagnostics; tests @@ -339,10 +339,9 @@ T9.1–T9.6 are complete. Wire-shape and packaging refinements run **before** the behavioral-test epic so the Reqnroll scenarios are written once against the final contracts: -1. **T11.4** Rebus owner routing (public contract and generator first). -2. **T11.2** Sample STJ source-generated metadata. -3. **T11.3** Scalar plus optional Swagger UI with OAuth2/OIDC. -4. **T11.1** gRPCui development tooling. +1. **T11.2** Sample STJ source-generated metadata. +2. **T11.3** Scalar plus optional Swagger UI with OAuth2/OIDC. +3. **T11.1** gRPCui development tooling. ## Status legend diff --git a/samples/Ark.MediatorFramework.Sample/src/Ark.MediatorFramework.Sample.Application/DeadLetterContracts.cs b/samples/Ark.MediatorFramework.Sample/src/Ark.MediatorFramework.Sample.Application/DeadLetterContracts.cs index 389ba1c89..864d24a1a 100644 --- a/samples/Ark.MediatorFramework.Sample/src/Ark.MediatorFramework.Sample.Application/DeadLetterContracts.cs +++ b/samples/Ark.MediatorFramework.Sample/src/Ark.MediatorFramework.Sample.Application/DeadLetterContracts.cs @@ -13,7 +13,7 @@ public sealed record DeadLetterAck; /// demonstrating the Rebus dead-letter behavior: after the delivery attempts are exhausted the message is /// forwarded to the error queue with the exception serialized into its headers. /// -[RebusMessage] +[RebusMessage(OwnerQueue = "ark.mediator.sample")] public sealed record FailingRebusRequest : IRequest { /// Gets the reason surfaced in the thrown exception. diff --git a/samples/Ark.MediatorFramework.Sample/src/Ark.MediatorFramework.Sample.Application/GreetingContracts.cs b/samples/Ark.MediatorFramework.Sample/src/Ark.MediatorFramework.Sample.Application/GreetingContracts.cs index 5469eff12..08be66f79 100644 --- a/samples/Ark.MediatorFramework.Sample/src/Ark.MediatorFramework.Sample.Application/GreetingContracts.cs +++ b/samples/Ark.MediatorFramework.Sample/src/Ark.MediatorFramework.Sample.Application/GreetingContracts.cs @@ -94,7 +94,7 @@ public sealed record ComposeGreetingResponse } /// Rebus-only request completed asynchronously by the composition workflow. -[RebusMessage] +[RebusMessage(OwnerQueue = "ark.mediator.sample")] public sealed record CompleteGreetingCompositionRequest : IRequest { /// Gets the greeting identifier. diff --git a/samples/Ark.MediatorFramework.Sample/src/Ark.MediatorFramework.Sample.WebInterface/SampleComposition.cs b/samples/Ark.MediatorFramework.Sample/src/Ark.MediatorFramework.Sample.WebInterface/SampleComposition.cs index 368bd2645..7bcccb578 100644 --- a/samples/Ark.MediatorFramework.Sample/src/Ark.MediatorFramework.Sample.WebInterface/SampleComposition.cs +++ b/samples/Ark.MediatorFramework.Sample/src/Ark.MediatorFramework.Sample.WebInterface/SampleComposition.cs @@ -60,6 +60,7 @@ public static Container BuildContainer(InMemNetwork network, bool useProtobufReb container.ConfigureRebus(cfg => { cfg.Transport(t => t.UseInMemoryTransport(network, "ark.mediator.sample")); + cfg.Routing(ArkGeneratedEndpoints.ConfigureArkRebusRouting); if (useProtobufRebus) { diff --git a/src/mediator-framework/Ark.Tools.MediatorFramework.Rebus.Generators/RebusEndpointGenerator.cs b/src/mediator-framework/Ark.Tools.MediatorFramework.Rebus.Generators/RebusEndpointGenerator.cs index f02cc15ad..a92ab45aa 100644 --- a/src/mediator-framework/Ark.Tools.MediatorFramework.Rebus.Generators/RebusEndpointGenerator.cs +++ b/src/mediator-framework/Ark.Tools.MediatorFramework.Rebus.Generators/RebusEndpointGenerator.cs @@ -24,7 +24,10 @@ namespace Ark.MediatorFramework.Generators public sealed class ArkRebusEndpointGenerator : IIncrementalGenerator { private const string RebusMessageAttribute = "Ark.MediatorFramework.RebusMessageAttribute"; - + private static readonly DiagnosticDescriptor InvalidOwnerQueue = new( + "ARKMF004", "Invalid Rebus owner queue", + "The Rebus owner queue for '{0}' must not be blank", "Rebus", + DiagnosticSeverity.Error, isEnabledByDefault: true); /// public void Initialize(IncrementalGeneratorInitializationContext context) { @@ -50,11 +53,12 @@ private static ImmutableArray GetEndpoints(Compilation compilatio foreach (var type in _allTypes(assembly.GlobalNamespace)) { var attrs = type.GetAttributes(); - var rebus = attrs.FirstOrDefault(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, rebusAttr)); + var rebus = attrs.FirstOrDefault( + a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, rebusAttr)); if (rebus is null) continue; - var model = Extract(type); + var model = Extract(type, rebus); if (model is not null) builder.Add(model.Value); } @@ -95,7 +99,7 @@ private static IEnumerable _allTypes(INamespaceSymbol ns) } } - private static EndpointModel? Extract(INamedTypeSymbol type) + private static EndpointModel? Extract(INamedTypeSymbol type, AttributeData rebusAttribute) { // Rebus messages are dispatched via IRequestHandler; queries (reads) are not // meaningful as bus messages. @@ -105,21 +109,52 @@ private static IEnumerable _allTypes(INamespaceSymbol ns) if (def == "global::Ark.Tools.Solid.IRequest") { var response = iface.TypeArguments[0].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + var diagnostics = new List(); + var ownerQueue = GetOwnerQueue(rebusAttribute); + if (ownerQueue is null && HasOwnerQueueArgument(rebusAttribute)) + { + diagnostics.Add(new DiagnosticInfo( + InvalidOwnerQueue, + type.Name, + GetLocation(rebusAttribute))); + } + return new EndpointModel( type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), type.Name, - response); + response, + ownerQueue is not null && diagnostics.Count == 0 ? ownerQueue : null, + diagnostics); } } return null; } + private static string? GetOwnerQueue(AttributeData attribute) + { + var argument = attribute.NamedArguments.FirstOrDefault(pair => pair.Key == "OwnerQueue"); + var ownerQueue = argument.Value.Value as string; + return string.IsNullOrWhiteSpace(ownerQueue) ? null : ownerQueue; + } + + private static bool HasOwnerQueueArgument(AttributeData attribute) + => attribute.NamedArguments.Any(pair => pair.Key == "OwnerQueue"); + + private static Location GetLocation(AttributeData attribute) + => attribute.ApplicationSyntaxReference?.GetSyntax().GetLocation() ?? Location.None; + private static void Emit(SourceProductionContext spc, ImmutableArray items) { if (items.IsDefaultOrEmpty) return; + foreach (var item in items) + { + foreach (var diagnostic in item.Diagnostics) + spc.ReportDiagnostic(Diagnostic.Create(diagnostic.Descriptor, diagnostic.Location, diagnostic.Arguments)); + } + var sb = new StringBuilder(); sb.AppendLine("// "); sb.AppendLine("#nullable enable"); @@ -141,6 +176,16 @@ private static void Emit(SourceProductionContext spc, ImmutableArrayRegisters generated owner queues with Rebus type-based routing."); + sb.AppendLine(" public static void ConfigureArkRebusRouting(global::Rebus.Config.StandardConfigurer routing)"); + sb.AppendLine(" {"); + sb.AppendLine(" var typeBased = global::Rebus.Routing.TypeBased.TypeBasedRouterConfigurationExtensions.TypeBased(routing);"); + foreach (var e in items.Where(item => item.OwnerQueue is not null)) + { + sb.AppendLine(" typeBased.Map<" + e.TypeFullName + ">(" + StringLiteral(e.OwnerQueue!) + ");"); + } + sb.AppendLine(" }"); // Generated Rebus IHandleMessages wrappers. if (!items.IsDefaultOrEmpty) @@ -171,16 +216,42 @@ private static void Emit(SourceProductionContext spc, ImmutableArray diagnostics) { TypeFullName = typeFullName; TypeName = typeName; Response = response; + OwnerQueue = ownerQueue; + Diagnostics = diagnostics; } public string TypeFullName { get; } public string TypeName { get; } public string Response { get; } + public string? OwnerQueue { get; } + public IReadOnlyList Diagnostics { get; } + } + + private readonly struct DiagnosticInfo + { + public DiagnosticInfo(DiagnosticDescriptor descriptor, string typeName, Location location, string? queues = null) + { + Descriptor = descriptor; + Location = location; + Arguments = queues is null ? [typeName] : [typeName, queues]; + } + + public DiagnosticDescriptor Descriptor { get; } + public Location Location { get; } + public object[] Arguments { get; } } + + private static string StringLiteral(string value) + => "\"" + value.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\""; } } diff --git a/src/mediator-framework/Ark.Tools.MediatorFramework.Rebus/RebusMessageAttribute.cs b/src/mediator-framework/Ark.Tools.MediatorFramework.Rebus/RebusMessageAttribute.cs index 26120b56d..7cfabd503 100644 --- a/src/mediator-framework/Ark.Tools.MediatorFramework.Rebus/RebusMessageAttribute.cs +++ b/src/mediator-framework/Ark.Tools.MediatorFramework.Rebus/RebusMessageAttribute.cs @@ -9,4 +9,19 @@ namespace Ark.MediatorFramework; [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public sealed class RebusMessageAttribute : Attribute { + private string? _ownerQueue; + + /// Gets or sets the queue that owns this message type. + /// Thrown when the value is blank. + public string? OwnerQueue + { + get => _ownerQueue; + set + { + if (value is not null && string.IsNullOrWhiteSpace(value)) + throw new ArgumentException("The owner queue cannot be blank.", nameof(value)); + + _ownerQueue = value; + } + } } diff --git a/tests/Ark.Tools.MediatorFramework.Tests/Ark.Tools.MediatorFramework.Tests.csproj b/tests/Ark.Tools.MediatorFramework.Tests/Ark.Tools.MediatorFramework.Tests.csproj index e6988748f..12ec48c0b 100644 --- a/tests/Ark.Tools.MediatorFramework.Tests/Ark.Tools.MediatorFramework.Tests.csproj +++ b/tests/Ark.Tools.MediatorFramework.Tests/Ark.Tools.MediatorFramework.Tests.csproj @@ -16,6 +16,8 @@ + + diff --git a/tests/Ark.Tools.MediatorFramework.Tests/GeneratorSnapshotTests.cs b/tests/Ark.Tools.MediatorFramework.Tests/GeneratorSnapshotTests.cs index ea7544369..e4e53cc9e 100644 --- a/tests/Ark.Tools.MediatorFramework.Tests/GeneratorSnapshotTests.cs +++ b/tests/Ark.Tools.MediatorFramework.Tests/GeneratorSnapshotTests.cs @@ -47,6 +47,7 @@ public void MinimalApiGeneratorExpandsVersionedRoutes() public sealed class GetGreeting : IQuery { } + """); generated.Should().Contain("MapGet(\"/api/v1/greetings/{id}\""); @@ -55,6 +56,49 @@ public sealed class GetGreeting : IQuery generated.Should().Contain("WithGroupName(\"v1\")"); } + [TestMethod] + public void RebusGeneratorEmitsOwnerQueueRouting() + { + var generated = RunGenerator( + """ + using Ark.MediatorFramework; + using Ark.Tools.Solid; + [RebusMessage(OwnerQueue = "orders")] + public sealed class CreateOrder : IRequest + { + } + """); + + generated.Should().Contain("ConfigureArkRebusRouting"); + generated.Should().Contain("Map(\"orders\")"); + } + + [TestMethod] + public void RebusMessageAllowsOnlyOneDeclaration() + { + var usage = (AttributeUsageAttribute)typeof(RebusMessageAttribute) + .GetCustomAttributes(typeof(AttributeUsageAttribute), inherit: false) + .Single(); + + usage.AllowMultiple.Should().BeFalse(); + } + + [TestMethod] + public void RebusGeneratorReportsInvalidOwnerQueue() + { + var result = RunGeneratorResult( + """ + using Ark.MediatorFramework; + using Ark.Tools.Solid; + [RebusMessage(OwnerQueue = " ")] + public sealed class CreateOrder : IRequest + { + } + """); + + result.Diagnostics.Should().Contain(diagnostic => diagnostic.Id == "ARKMF004"); + } + [TestMethod] public void GrpcGeneratorEmitsVersionedServiceMethodSets() { @@ -209,6 +253,7 @@ private static (string Generated, ImmutableArray Diagnostics) RunGen .Concat( [ MetadataReference.CreateFromFile(typeof(HttpEndpointAttribute).Assembly.Location), + MetadataReference.CreateFromFile(typeof(RebusMessageAttribute).Assembly.Location), MetadataReference.CreateFromFile(typeof(IRequest<>).Assembly.Location), MetadataReference.CreateFromFile(typeof(ProtoBuf.ProtoContractAttribute).Assembly.Location), ]); diff --git a/tests/Ark.Tools.MediatorFramework.Tests/packages.lock.json b/tests/Ark.Tools.MediatorFramework.Tests/packages.lock.json index 591d9a108..11862c30b 100644 --- a/tests/Ark.Tools.MediatorFramework.Tests/packages.lock.json +++ b/tests/Ark.Tools.MediatorFramework.Tests/packages.lock.json @@ -171,6 +171,46 @@ "resolved": "11.0.1", "contentHash": "9Jqm26Yb5D833BSU6rH3taFB8Y+A67Y3GJRC6XFEBKc2ueQSfd0B4bU3cAGsUNrWUJd1V9Sgm5U7I8SNG5zJvA==" }, + "Azure.Core": { + "type": "Transitive", + "resolved": "1.60.0", + "contentHash": "qCa5DLAq0w14aTl9/bvMZNA/QxPzYj1a4zakrpeudxWd4D4YliRHRfccD3yFECeHkMkvQjMmyWLggb8bzhDVKA==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "10.0.9", + "Microsoft.Extensions.Configuration.Abstractions": "10.0.9", + "Microsoft.Extensions.Hosting.Abstractions": "10.0.9", + "Microsoft.Identity.Client": "4.84.2", + "Microsoft.Identity.Client.Extensions.Msal": "4.84.2", + "System.ClientModel": "1.14.0", + "System.Memory.Data": "10.0.9" + } + }, + "Azure.Core.Amqp": { + "type": "Transitive", + "resolved": "1.3.1", + "contentHash": "AY1ZM4WwLBb9L2WwQoWs7wS2XKYg83tp3yVVdgySdebGN0FuIszuEqCy3Nhv6qHpbkjx/NGuOTsUbF/oNGBgwA==", + "dependencies": { + "Microsoft.Azure.Amqp": "2.6.7", + "System.Memory.Data": "1.0.2" + } + }, + "Azure.Storage.Blobs": { + "type": "Transitive", + "resolved": "12.19.1", + "contentHash": "x43hWFJ4sPQ23TD4piCwT+KlQpZT8pNDAzqj6yUCqh+WJ2qcQa17e1gh6ZOeT2QNFQTTDSuR56fm2bIV7i11/w==", + "dependencies": { + "Azure.Storage.Common": "12.18.1" + } + }, + "Azure.Storage.Common": { + "type": "Transitive", + "resolved": "12.18.1", + "contentHash": "ohCslqP9yDKIn+DVjBEOBuieB1QwsUCz+BwHYNaJ3lcIsTSiI4Evnq81HcKe8CqM8qvdModbipVQKpnxpbdWqA==", + "dependencies": { + "Azure.Core": "1.36.0", + "System.IO.Hashing": "6.0.0" + } + }, "BouncyCastle.Cryptography": { "type": "Transitive", "resolved": "2.6.2", @@ -207,6 +247,16 @@ "resolved": "3.1.8", "contentHash": "Vm4g0cR4YRKRchEOmMJ0uVFU6yxdg7cJa2KHv3SUAHEsdYKvMpHMF5A1hZfsix89ymD5cmuzRnw9a6dKMcvq+Q==" }, + "Microsoft.Azure.Amqp": { + "type": "Transitive", + "resolved": "2.7.0", + "contentHash": "gm/AEakujttMzrDhZ5QpRz3fICVkYDn/oDG9SmxDP+J7R8JDBXYU9WWG7hr6wQy40mY+wjUF0yUGXDPRDRNJwQ==" + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "10.0.9", + "contentHash": "Aq7M8lG6BrHeatqKqncVm9m55ec34k6nnfPRLe/PvGg+b/pAsRM2ejofeKmCLjTXMa+5NGXm382f8CG/D5WDow==" + }, "Microsoft.Bcl.Cryptography": { "type": "Transitive", "resolved": "10.0.2", @@ -462,6 +512,17 @@ "SimpleInjector": "5.4.0" } }, + "System.ClientModel": { + "type": "Transitive", + "resolved": "1.14.0", + "contentHash": "yhIJHDW3Hh5kcvhHv3ww1T8qvya06Nlwo/SR/rke4/fHXtyKiqQV/9b/VDhnVI7QUcMnpfvh4pIEFhNsTDLeKQ==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "10.0.3", + "Microsoft.Extensions.Hosting.Abstractions": "10.0.3", + "Microsoft.Extensions.Logging.Abstractions": "10.0.3", + "System.Memory.Data": "10.0.3" + } + }, "System.Diagnostics.EventLog": { "type": "Transitive", "resolved": "10.0.10", @@ -481,6 +542,16 @@ "resolved": "4.7.0", "contentHash": "vMToiarpU81LR1/KZtnT7VDPvqAZfw9oOS5nY6pPP78nGYz3COLsQH3OfzbR+SjTgltd31R6KmKklz/zDpTmzw==" }, + "System.IO.Hashing": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "Rfm2jYCaUeGysFEZjDe7j1R4x6Z6BzumS/vUT5a1AA/AWJuGX71PoGB0RmpyX3VmrGqVnAwtfMn39OHR8Y/5+g==" + }, + "System.Memory.Data": { + "type": "Transitive", + "resolved": "10.0.9", + "contentHash": "YweovHiLUoEdbr2Xv8eRqCSkTu1vMms4a6xBHaQiMSFVy32PL+hXv6Vhol2NWOmLHjaVgTyhJ3R52U6JxS6w3Q==" + }, "System.Security.Cryptography.Pkcs": { "type": "Transitive", "resolved": "10.0.10", @@ -546,6 +617,17 @@ "ark.tools.mediatorframework.minimalapi.generators": { "type": "Project" }, + "ark.tools.mediatorframework.rebus": { + "type": "Project", + "dependencies": { + "Ark.Tools.MediatorFramework": "[1.0.0, )", + "Ark.Tools.Rebus": "[1.0.0, )", + "Rebus.Protobuf": "[5.0.0, )" + } + }, + "ark.tools.mediatorframework.rebus.generators": { + "type": "Project" + }, "ark.tools.nlog": { "type": "Project", "dependencies": { @@ -576,6 +658,27 @@ "NodaTime.Serialization.SystemTextJson": "[1.4.0, )" } }, + "ark.tools.rebus": { + "type": "Project", + "dependencies": { + "Ark.Tools.ApplicationInsights": "[1.0.0, )", + "Ark.Tools.Core": "[1.0.0, )", + "Ark.Tools.SimpleInjector": "[1.0.0, )", + "Ark.Tools.Solid": "[1.0.0, )", + "Azure.Messaging.ServiceBus": "[7.20.2, )", + "Rebus": "[8.9.2, )", + "Rebus.AzureBlobs": "[1.1.0, )", + "Rebus.AzureServiceBus": "[10.7.0, )", + "Rebus.NLog": "[6.0.0, )", + "Rebus.SqlServer": "[8.4.1, )" + } + }, + "ark.tools.simpleinjector": { + "type": "Project", + "dependencies": { + "SimpleInjector": "[5.6.0, )" + } + }, "ark.tools.solid": { "type": "Project", "dependencies": { @@ -591,6 +694,26 @@ "Macross.Json.Extensions": "[3.0.0, )" } }, + "Azure.Identity": { + "type": "CentralTransitive", + "requested": "[1.21.0, )", + "resolved": "1.21.0", + "contentHash": "GeFv8sGwRKvDKwI2WFy8r0mhmlxEVZg24Sit2NogTjiSO8RVjllWM65OT6e1sKjOvG8V74y7hAbaELUUPjZQSw==", + "dependencies": { + "Azure.Core": "1.53.0" + } + }, + "Azure.Messaging.ServiceBus": { + "type": "CentralTransitive", + "requested": "[7.20.2, )", + "resolved": "7.20.2", + "contentHash": "mwr5c3Qs7FWUtwzlLOtVixYDpUuA+Ln7sNirljTHZR8kDhzdr2grlqx0RRBvGV+IDCRHt1jIRb+hi0MUzjeVmw==", + "dependencies": { + "Azure.Core": "1.60.0", + "Azure.Core.Amqp": "1.3.1", + "Microsoft.Azure.Amqp": "2.7.0" + } + }, "Ben.Demystifier": { "type": "CentralTransitive", "requested": "[0.4.1, )", @@ -799,6 +922,25 @@ "Microsoft.Extensions.Primitives": "10.0.10" } }, + "Microsoft.Identity.Client": { + "type": "CentralTransitive", + "requested": "[4.86.0, )", + "resolved": "4.86.0", + "contentHash": "ZraQwohwmUsoDDN0jukt7l/Wj6kyE1Nh3jOiQKW1DIfXEr3TpgHIxwWinnrjM/D3+4K6jObns+x3Y+EMiv1Odw==", + "dependencies": { + "Microsoft.IdentityModel.Abstractions": "8.14.0" + } + }, + "Microsoft.Identity.Client.Extensions.Msal": { + "type": "CentralTransitive", + "requested": "[4.86.0, )", + "resolved": "4.86.0", + "contentHash": "ecqteI4RSL6PuBA5u19i3bIdCDxShnBuaeJoVBMvBG934bsZTv5VEY72Y3nW90BXJG8jHgpDZyzOIshB2m5A/Q==", + "dependencies": { + "Microsoft.Identity.Client": "4.86.0", + "System.Security.Cryptography.ProtectedData": "4.5.0" + } + }, "Microsoft.IdentityModel.JsonWebTokens": { "type": "CentralTransitive", "requested": "[8.19.2, )", @@ -894,6 +1036,66 @@ "protobuf-net.Grpc": "1.2.2" } }, + "Rebus": { + "type": "CentralTransitive", + "requested": "[8.9.2, )", + "resolved": "8.9.2", + "contentHash": "JyiO5vkH76wxLKcgXle7ewZ7rfIg+/L8/EFJY8npRsI1QwW8YprZTQX7EBbIuBqfeaqUra+2/TEPen4Nx+PU6A==", + "dependencies": { + "Newtonsoft.Json": "13.0.4" + } + }, + "Rebus.AzureBlobs": { + "type": "CentralTransitive", + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "yPkvYzbEcECGEm8vVophhlRvoPT7KlpFpGrSBUDov5r5RDTw7yzHaKMNEYcp3GSaUlXsZfvNZPHSgoXeWQFndA==", + "dependencies": { + "azure.storage.blobs": "12.19.1", + "rebus": "8.0.1" + } + }, + "Rebus.AzureServiceBus": { + "type": "CentralTransitive", + "requested": "[10.7.0, )", + "resolved": "10.7.0", + "contentHash": "NU0vLtgUWFHuB2kT9j5fY4hS1rBtkEMbIoj3VXdmzaxZkjCTR8B8oW3/uO2JgSr5OFSPz5WVnzLMRC/lpN80RA==", + "dependencies": { + "Azure.Messaging.ServiceBus": "7.20.1", + "Rebus": "8.9.2", + "azure.identity": "1.21.0" + } + }, + "Rebus.NLog": { + "type": "CentralTransitive", + "requested": "[6.0.0, )", + "resolved": "6.0.0", + "contentHash": "4cJjk1W0TAgQn1/tEMyca3Xvn4p8Z+Gqku3IYRWFH4RW3Pzdr84daqwDpPB1juIibwTP7HRcTs11OQ6DmPJSuw==", + "dependencies": { + "nlog": "5.2.5", + "rebus": "8.0.1" + } + }, + "Rebus.Protobuf": { + "type": "CentralTransitive", + "requested": "[5.0.0, )", + "resolved": "5.0.0", + "contentHash": "q1W2lTHkZba6dVY7KbpSbf95/g0DDtC45j6tkZYovfJJKuuwoVTsGPioxOTCpuxRi60R0ZkEM9gvdHOvHBfzlw==", + "dependencies": { + "protobuf-net": "3.2.26", + "rebus": "8.0.1" + } + }, + "Rebus.SqlServer": { + "type": "CentralTransitive", + "requested": "[8.4.1, )", + "resolved": "8.4.1", + "contentHash": "Rdq0SoUy8smSYrIFM9KY3r0ygVMZ8PNTrLIQtSvo6zXb5f0jGwtw9cDx8jPbGJI6859jUyNms2eO2PCkIYclRA==", + "dependencies": { + "microsoft.data.sqlclient": "6.1.2", + "rebus": "8.9.0" + } + }, "SimpleInjector": { "type": "CentralTransitive", "requested": "[5.6.0, )",