Skip to content

Changelog

All notable changes to SignalARRR will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

[Unreleased]


[4.3.2]

Security

  • MessagePack downgraded from 3.1.4 to 2.5.301 to patch CVE-2026-48109 / GHSA-hv8m-jj95-wg3x (high-severity LZ4 decompression out-of-bounds read / DoS), which was failing the build via NuGet audit. 2.5.x is the MessagePack line that Microsoft.AspNetCore.SignalR.Protocols.MessagePack runs on (through .NET 10), so consumers using the SignalR MessagePack hub protocol are no longer forced onto a cross-major MessagePack version. No functional change — only basic serialization APIs are used.

[4.3.1]

Fixed

  • Fire-and-forget send server methods silently did nothing (e.g. group joins): HARRR.SendMessage ran the target method in a detached Task.Run after SignalR had already disposed the Hub, so any access to the hub-injected Context/Clients/Groups (such as Groups.AddToGroupAsync) silently failed and the method body never took effect. The method is now awaited within the hub invocation, keeping the Hub alive for its duration. Affects every client — the typed proxy routes any void/Task-returning server method through this send path, so this was hit without explicitly choosing send.
  • (Swift) Negotiate/WebSocket URL broke when the hub URL carried a query string: both the negotiate URL and the WebSocket transport URL were built by string concatenation, producing a broken URL like .../hub/sync?user=x?id=... (HTTP 400 on negotiate). Rebuilt with URLComponents so existing query parameters are preserved and /negotiate is inserted into the path.
  • (Swift) Connection hung ~30s against localhost/IPv6: when localhost resolved to IPv6 (::1) against an IPv4-only server there was no Happy-Eyeballs fallback for the WebSocket upgrade. Negotiate now fast-fails on a configurable timeout instead of waiting on the OS connect timeout, and the 127.0.0.1 workaround is documented.

Changed

  • (Swift) Undispatched server→client calls now log instead of failing silently: mirrors the .NET client. When a server→client call arrives for which no handler is registered, the client logs a warning pointing to onServerMethod(...) — the most common cause is registering a SignalARRR contract with on(...) (which only handles raw SignalR events). The on(...) vs onServerMethod(...) distinction is now documented on both APIs.

Added

  • Regression tests: a .NET integration test proving a send-routed server method joins a group against a live Hub (fails on the old fire-and-forget behaviour), and Swift unit tests covering query-string-safe transport URL construction.

[4.3.0]

Added

  • Redis-compatible cluster backplane: multi-node SignalARRR deployments can now route typed server-to-client traffic through Redis-compatible infrastructure such as Redis, Valkey, or Garnet.
  • Distributed query support: cluster-wide broadcast, user targeting, attribute targeting, remote group management, and cross-node InvokeAllAsync / InvokeOneAsync.
  • Cluster presence snapshots: ClientManager can now report cluster-wide connections, groups, attributes, and online users.
  • Crash cleanup + hardening tests: added active stale-node cleanup and new multi-node tests for reconnect, remote group leave, ordered cross-node push delivery, and crash recovery.

Documentation

  • Added backplane and cluster semantics documentation for server deployments.

[4.2.2]

Fixed

  • Server-to-Client push crash with null arguments: null arguments for reference type parameters (e.g., string?) crashed the client's message dispatcher silently — the root cause of server-to-client push failures when using typed proxies.
  • Silent error swallowing in client message handler: Replaced catch { // ignored } with ILogger.LogError() so developers can diagnose failed server-to-client pushes.

Added

  • 4 new server-to-client push integration tests: Cross-assembly tests covering fire-and-forget push, invoke with return value, null parameter handling, and multi-client broadcast.

[4.2.1]

Fixed

  • Source Generator not included in NuGet packages: The generator DLL was never bundled in NuGet packages — it only worked with local project references. Fixed by shipping it in the Server and Client packages.
  • Source Generator now ships in Server and Client packages: Consumer projects get proxy generation automatically by referencing Server or Client — no extra package reference needed. Contracts remains attribute-only (no generator).

[4.2.0]

Added

  • Transport-Level Authentication: Support for client certificates (mTLS), cookies, and Windows/Negotiate authentication alongside existing token-based auth. The server auto-detects the authentication mode per client and re-validates transport credentials server-side when the auth cache expires — no challenge round-trip needed.
  • AuthenticationMode enum: None, MessageLevel, TransportLevel — exposed on ClientContext.AuthMode for per-client auth mode inspection
  • ClientContext.ClientCertificate: Stores the client certificate from the TLS handshake for server-side re-validation
  • ITransportAuthRevalidationService: Pluggable interface for custom transport-auth re-validation logic (e.g., custom CRL endpoints, OCSP stapling, session store checks)
  • DefaultTransportAuthRevalidationService: Built-in implementation with certificate expiry checks, X509 chain validation (CRL/OCSP), and custom validator callback support
  • Certificate validation options: WithCertificateRevocationCheck(bool), WithCertificateRevocationMode(X509RevocationMode), WithCustomCertificateValidator(Func<X509Certificate2, bool>) on SignalARRRServerOptionsBuilder
  • Mixed-mode authentication: A single hub can serve both token-based and certificate-based clients simultaneously
  • Certificate refresh on reconnect: ClientContext updates transport credentials (cert + principal) when a client reconnects with a new certificate
  • 9 new integration tests for transport-level auth: cert auth, auto-detection, cache expiry with server-side re-validation, expired cert rejection, AllowAnonymous bypass, and mixed-mode scenarios

Fixed

  • Source Generator cross-assembly discovery: The Source Generator now discovers [SignalARRRContract] interfaces in referenced assemblies (not just in the current compilation's source code). This fixes the common scenario where contract interfaces are defined in a shared library and referenced by server/client projects. The generator only scans assemblies that reference Cocoar.SignalARRR.Contracts, avoiding unnecessary work.

[4.1.0]

Added

  • Multi-targeting: All library packages now support net8.0, net9.0, and net10.0
  • Cocoar.SignalARRR.Client.FullFramework: New client package targeting netstandard2.0 for .NET Framework 4.6.2+ — typed proxies via DispatchProxy, streaming (via polyfills), server-to-client RPC, cancellation, file transfer, and optional MessagePack
  • Framework-conditional package versions: ASP.NET Core packages resolve to the correct version per target framework, preventing transitive version conflicts
  • CI matrix testing: PR validation now tests on .NET 8, 9, and 10 across all platforms
  • Typed broadcasts: WithHub<T>().WithGroup().SendAsync<T>() — chainable LINQ-style API for typed fire-and-forget sends to groups, filtered clients, and all clients. Groups tracked in ClientContext.Groups and synced with SignalR.
  • Typed multi-client invoke: InvokeAllAsync<T, TResult>() (parallel, all results) and InvokeOneAsync<T, TResult>() (first responder wins) on IEnumerable<ClientContext>

Changed

  • MessagePack is now optional: Install Microsoft.AspNetCore.SignalR.Protocols.MessagePack separately and call .AddMessagePackProtocol() when needed
  • Cocoar.SignalARRR.Common now also targets netstandard2.0

Fixed

  • SignalR 10.0.5 compatibility: InvokeServerMessage handler now properly awaits async operations
  • npm version in CI: Added --allow-same-version flag

[4.0.0]

Breaking Changes

  • Target framework changed from netstandard2.0 to net10.0
  • ImpromptuInterface removed — replaced by source-generated proxies and opt-in DispatchProxy fallback
  • Proxy creation now requires [SignalARRRContract] attribute on interfaces (or reference Cocoar.SignalARRR.DynamicProxy for runtime fallback)
  • Custom IAuthenticator interface removed — use ASP.NET Core authentication handlers and [Authorize] policies instead
  • HTTP Proxy pass-through feature removed (deferred to Phase 2)
  • netstandard2.0 target dropped — all packages now target net10.0 (except SourceGenerator which targets netstandard2.0 per Roslyn requirements)
  • Hub-level [Authorize] inheritance restored: if the Hub class has [Authorize], ServerMethods classes inherit it automatically (behavior change from v2.x where this was disabled)

Added

  • Source Generator: Compile-time proxy generation from [SignalARRRContract] interfaces — zero reflection, AOT-friendly
  • Cocoar.SignalARRR.Contracts: Single-reference meta-package for shared interface projects (attribute + generator + ProxyGenerator)
  • Cocoar.SignalARRR.DynamicProxy: Opt-in DispatchProxy-based runtime fallback for plugin/dynamic scenarios
  • CancellationToken server-to-client propagation: Server can pass CancellationToken to client methods and cancel remotely
  • ServerProxyCreatorHelper.StreamAsync<T>: Server can request IAsyncEnumerable<T> streams from client methods
  • ServerStreamManager: Channel-based stream correlation for server-initiated client streams
  • StreamItemToServer / StreamCompleteToServer hub methods for client-to-server stream item delivery
  • ClientManager typed extensions: GetTypedMethods<T>(connectionId) for server-to-client RPC from outside hub context
  • Authorization integration tests: Tests for authenticated calls, unauthenticated rejection, and hub-level auth inheritance
  • TreatWarningsAsErrors: Enabled globally via Directory.Build.props

Removed

  • ImpromptuInterface dependency
  • netstandard2.0 target / polyfill packages (Microsoft.Bcl.AsyncInterfaces, System.Threading.Channels, etc.)
  • SignalARRRDynamicProxy.cs and StreamingType.cs from ProxyGenerator (replaced by DispatchProxy package)
  • Non-generic Invoke(Type returnType, ...) overloads from ClientProxyCreatorHelper and ServerProxyCreatorHelper
  • Old RegisterMethods client-side registration API (replaced by RegisterInterface)
  • Custom IAuthenticator interface and TryAuthenticate/SetAuthData on ClientContext

[2.1.2] - Previous Release

Features

  • Split hub methods across multiple classes via ServerMethods<T>
  • Method-level authorization with [Authorize] attribute
  • Continuous token validation with automatic challenge/refresh
  • Server-to-client RPC with response awaiting
  • Support for IObservable<T>, IAsyncEnumerable<T>, and ChannelReader<T> streaming
  • Type-safe client proxies from interfaces
  • Multi-platform support (Server, .NET Client, TypeScript Client)

Released under the Apache-2.0 License.