NetConduit 3.1.1
dotnet add package NetConduit --version 3.1.1
NuGet\Install-Package NetConduit -Version 3.1.1
<PackageReference Include="NetConduit" Version="3.1.1" />
<PackageVersion Include="NetConduit" Version="3.1.1" />
<PackageReference Include="NetConduit" />
paket add NetConduit --version 3.1.1
#r "nuget: NetConduit, 3.1.1"
#:package NetConduit@3.1.1
#addin nuget:?package=NetConduit&version=3.1.1
#tool nuget:?package=NetConduit&version=3.1.1
NetConduit
Transport-agnostic stream multiplexer for .NET. Run many independent virtual channels over a single bidirectional stream — TCP, WebSocket, UDP, IPC, or QUIC — with credit-based backpressure, priority queuing, keepalive, graceful shutdown, and automatic reconnection with replay.
| Core | NuGet | Description |
|---|---|---|
NetConduit |
Multiplexer, channels, framing, reconnection |
| Transits | NuGet | Description |
|---|---|---|
NetConduit.Transit.Stream |
Simplex Stream over one channel |
|
NetConduit.Transit.DuplexStream |
Bidirectional Stream over a channel pair |
|
NetConduit.Transit.Message |
Length-prefixed typed JSON messages | |
NetConduit.Transit.DeltaMessage |
State sync via JSON deltas |
| Transports | NuGet | Description |
|---|---|---|
NetConduit.Transport.Tcp |
TCP sockets | |
NetConduit.Transport.WebSocket |
WebSocket (ClientWebSocket + ASP.NET) |
|
NetConduit.Transport.Udp |
UDP with a reliability shim | |
NetConduit.Transport.Ipc |
TCP loopback (Windows) / Unix domain sockets (Linux/macOS) | |
NetConduit.Transport.Quic |
QUIC over TLS 1.3 |
Each transport and transit package depends on NetConduit, so installing one pulls in the core.
At a glance
+-----------------------------------------+
| Application |
+-----------------------------------------+
| Transits (optional, layered) |
| Stream DuplexStream Message Delta |
+-----------------------------------------+
| NetConduit (core) |
| framing | channels | flow control | |
| priority | keepalive | reconnect |
+-----------------------------------------+
| Transport (single bidirectional |
| IStreamPair) |
| TCP WS UDP IPC QUIC |
+-----------------------------------------+
One physical stream carries any number of independent virtual channels. Each channel has its own buffer, priority, and lifecycle.
Install
Pick one transport and any transits you need:
dotnet add package NetConduit.Transport.Tcp
dotnet add package NetConduit.Transit.Message
Target frameworks: net8.0, net9.0, net10.0. AOT-compatible.
Quick start
A TCP server and client exchanging typed JSON messages.
using System.Text.Json.Serialization;
using NetConduit;
using NetConduit.Models;
using NetConduit.Transit.Message;
using NetConduit.Transport.Tcp;
public record Hello(string Name, int Count);
[JsonSerializable(typeof(Hello))]
internal partial class AppJson : JsonSerializerContext;
// Server
using var listener = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Loopback, 5000);
listener.Start();
await using var server = StreamMultiplexer.Create(TcpMultiplexer.CreateServerOptions(listener));
server.Start();
await server.WaitForReadyAsync();
await using var inbox = await server.AcceptMessageTransitAsync<Hello>("hello", AppJson.Default.Hello);
await foreach (var msg in inbox.ReceiveAllAsync())
Console.WriteLine($"got: {msg!.Name} x{msg.Count}");
// Client
await using var client = StreamMultiplexer.Create(TcpMultiplexer.CreateOptions("127.0.0.1", 5000));
client.Start();
await client.WaitForReadyAsync();
await using var outbox = await client.OpenMessageTransitAsync<Hello>("hello", AppJson.Default.Hello);
await outbox.SendAsync(new Hello("Alice", 1));
await outbox.SendAsync(new Hello("Alice", 2));
That's it. The server can open additional channels for file transfers, control plane, state sync, etc. — all over the same TCP connection.
What you get
- Many channels per stream. Open and accept named channels at will. Each is independently flow-controlled and prioritized.
- Pluggable transport. Swap TCP for WebSocket, UDP, IPC, or QUIC by changing one factory call.
- Transits. Optional layers that turn a channel pair into a
Stream, a typed message queue, or a state-sync delta channel. - Backpressure. Per-channel slab buffers with credit-based flow control. Slow consumers slow down their producer without blocking other channels.
- Priority queuing. Five priority levels (
Lowest…Highest) control writer ordering when channels compete for the wire. - Heartbeats. Configurable ping/pong with a missed-ping threshold detects dead connections quickly.
- Graceful shutdown.
GoAwayAsyncdrains in-flight data before tearing down. - Reconnection with replay. When configured, the multiplexer rebuilds the connection on transport failure and replays buffered frames so open channels survive.
- AOT and trim safe. Core uses no reflection. Message and delta transits accept source-generated
JsonTypeInfo<T>.
Documentation
- Getting started
- Concepts — multiplexer, channels, transports, transits, backpressure, reconnection, events
- Transports — TCP, WebSocket, UDP, IPC, QUIC
- Transits — Stream, DuplexStream, Message, DeltaMessage
- API reference
- Samples
- Benchmarks
Samples
Each sample is a runnable console app. See its README for usage.
| Sample | Demonstrates |
|---|---|
| SimpleTcpTunnel | Port forwarding through a relay over TCP or WebSocket |
| GroupChatSample | Multi-client chat broker (TCP or WebSocket) |
| PongGame | Real-time game state sync via DeltaMessageTransit |
| FileTransferSample | Parallel file streaming with one channel per file |
| RemoteShellSample | SSH-like shell over a single TCP connection |
| RpcFrameworkSample | Async RPC over a typed message transit |
| ScoreboardSample | Persistent leaderboard with client reconnection |
License
MIT — see LICENSE.
| Product | Versions 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 is compatible. 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 is compatible. 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. |
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (9)
Showing the top 5 NuGet packages that depend on NetConduit:
| Package | Downloads |
|---|---|
|
NetConduit.Transport.WebSocket
WebSocket transport helper for NetConduit stream multiplexer. Provides easy WebSocket client/server connection handling with automatic multiplexer setup. |
|
|
NetConduit.Transport.Quic
QUIC transport helper for NetConduit stream multiplexer (System.Net.Quic). |
|
|
NetConduit.Transport.Ipc
Local IPC transport helper for NetConduit (named pipes on Windows, Unix domain sockets elsewhere). |
|
|
NetConduit.Transport.Tcp
TCP transport helper for NetConduit stream multiplexer. Provides easy TCP client/server connection handling with automatic multiplexer setup. |
|
|
NetConduit.Transit.DeltaMessage
Delta message transit for NetConduit. Synchronizes state by sending only changed fields after an initial full sync, minimizing bandwidth. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.1.1 | 24 | 5/22/2026 |
| 3.1.0 | 2,051 | 5/20/2026 |
| 3.0.1 | 1,806 | 5/14/2026 |
| 2.3.3 | 534 | 5/8/2026 |
| 2.3.2 | 117 | 5/7/2026 |
| 2.3.1 | 27 | 5/6/2026 |
| 2.2.3 | 152 | 5/6/2026 |
| 2.2.1 | 90 | 5/5/2026 |
| 2.1.4 | 46 | 4/27/2026 |
| 2.1.3 | 37 | 4/25/2026 |
| 2.1.2 | 45 | 4/22/2026 |
| 2.1.1 | 558 | 4/22/2026 |
| 2.1.0 | 35 | 4/22/2026 |
| 2.0.3 | 36 | 4/15/2026 |
| 2.0.2 | 447 | 4/14/2026 |
| 2.0.0 | 903 | 3/11/2026 |
| 1.2.6 | 24,275 | 12/6/2025 |
| 1.2.4 | 205 | 12/6/2025 |
| 1.2.3 | 175 | 12/5/2025 |
| 1.2.2 | 128 | 12/5/2025 |
## New Version
* Bump `net_conduit` from `3.0.1` to `3.1.1`. See [changelog](https://github.com/Kiryuumaru/NetConduit/compare/net_conduit/3.0.1...net_conduit/3.1.1)
## What's Changed
* Remove PLAN_MODULAR.md by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/87
* docs: rewrite documentation from scratch by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/89
* Bump NukeBuildHelpers from 9.0.25 to 9.0.26 by @dependabot[bot] in https://github.com/Kiryuumaru/NetConduit/pull/91
* Update .gitignore by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/92
* refactor: standardize -1 as unlimited sentinel for MaxAutoReconnectAttempts by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/93
* Bump coverlet.collector from 10.0.0 to 10.0.1 by @dependabot[bot] in https://github.com/Kiryuumaru/NetConduit/pull/94
* fix(core): handshake retry budget + position-based ACK protocol by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/95
* fix(core): widen ACK position wire field to 64 bits by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/96
* Fix lifecycle heartbeat and reconnect handling by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/98
* Reset one-shot server factory state on cancellation by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/118
* Fix DeltaMessage array delta correctness by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/119
* Validate channel IDs and apply open defaults by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/120
* fix(events,stats): defer ChannelOpened until ready and fix Uptime unit by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/121
* Bump NukeBuildHelpers from 9.0.26 to 9.0.27 by @dependabot[bot] in https://github.com/Kiryuumaru/NetConduit/pull/128
* Add benchmark performance gate to NUKE CI by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/129
* fix(protocol): validate frame length and enforce receiver slab capacity by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/127
* fix(udp): throw TimeoutException when NC_HELLO_ACK is not received by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/126
* fix(goaway): drain channels and abort on timeout by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/124
* fix(channel): raise Ready/ChannelOpened before completing readyTcs by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/130
* fix(transit): deliver EOF on sync Dispose and clean up on async cancellation by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/123
* feat(core): prefix-filtered AcceptChannelsAsync overload by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/97
* fix(channel): harden WriteChannel lifecycle and validate peer ACK by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/131
* docs(mux): correct StreamMultiplexer class summary by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/136
* docs(api): document AcceptChannelsAsync 3-tier dispatch order + contract test by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/137
* fix(transit): reject reserved ">>" "<<" substrings in transit base channel IDs by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/141
* chore(build): centralize NetConduit package version into src/Directory.Build.props by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/144
* docs: add scope page (mux responsibilities, trust model, out-of-scope concerns) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/145
* docs(transports): document reconnectable server-side factories per transport by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/146
* docs(stats): correct MultiplexerStats counters as wire bytes (not payload) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/149
* docs(events): clarify ChannelClosed vs Closed event asymmetry by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/148
* feat(api): validate ChannelOptions.SlabSize against documented bounds by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/150
* refactor(api): remove misplaced `IMessageTransit<,>` interface from core [arch-013] by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/154
* refactor(api): remove dead `MultiplexerOptions.DefaultSlabSize` property [arch-011] by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/151
* feat(api): validate timing/multiplier options at `MultiplexerOptions` boundary [arch-012] by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/153
* feat(api): add atomic TryRegisterChannels primitive (toward #138) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/155
* fix(transit): migrate composite transits to atomic TryRegisterChannels (fixes #138) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/157
* fix(transport/udp): reset one-shot guard on failed accept by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/158
* fix(channels): release prefix subscription when enumerable is discarded by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/159
* fix(channels): prevent pending-accept resurrection on peer INIT by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/160
* fix(ReadChannel): unregister CancellationTokenRegistration on completion (fixes #162) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/170
* fix(WriteChannel): return slab unconditionally on terminal close (fixes #169) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/171
* refactor(NetConduit): extract MuxConnection field container by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/167
* refactor(NetConduit): move transport state into MuxConnection by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/174
* refactor(NetConduit): pass MuxConnection into loop methods as parameter by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/184
* fix(transit/message): parenthesize IsConnected disjunction (fixes #166) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/181
* fix(transit/message): use explicit EOF flag in ReceiveAllAsync so value-type streams terminate by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/188
* fix(streampair): run every dispose step unconditionally and aggregate errors (fixes #218) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/224
* fix(websocket): dispose wrapped WebSocket and send Close frame (fixes #204) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/235
* fix(transport): dispose TcpClient/ClientWebSocket on failed connect in StreamFactory (fixes #216) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/243
* fix(delta): emit Set op when property added with JSON null value (fixes #211) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/246
* fix(transport/udp): drop datagrams whose declared length mismatches payload (fixes #187) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/221
* fix(transport/websocket): reject non-Binary data frames in ReadAsync (fixes #217) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/227
* fix(websocket): dispose orphan pair when HandleAsync fails before mux ownership (fixes #225) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/238
* fix(websocket): preserve baseUri query params on reconnect (fixes #178) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/244
* fix(core): WriteAsync unwinds promptly with ChannelClosedException when closed under back-pressure (fixes #230) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/247
* fix(core): remote-initiated GoAway aborts local channels (fixes #234) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/248
* fix(NetConduit): make event raise multicast-safe and observable by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/249
* fix(transit/message): preserve receive framing across cancellation (fixes #240) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/254
* fix(transit/duplex-stream): IsConnected requires both directions (fixes #210) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/259
* fix(transport/ipc): refuse to overwrite non-socket endpoint path (fixes #189) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/190
* fix(core): ReadChannel.SetClosed returns slab to pool on all close paths (fixes #199) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/245
* fix(transit/message): yield legit JSON null payload in ReceiveAllAsync (fixes #220) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/263
* fix(core): prevent WriteChannel slab use-after-free on close (fixes #258) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/270
* test(transport/websocket): fix shutdown-ordering race in CreateOptions_ConnectsAndTransfersData by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/283
* refactor(core): extract ControlFrameBuilder (arch-011 Option B PR-A) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/284
* fix(transport/tcp): dispose accepted client on post-accept setup failure (fixes #267) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/275
* fix(core): rollback per-index entry when ChannelRegistry id-uniqueness check loses race (fixes #268) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/280
* fix(transit/message): drain over-max payload before throw to preserve framing (fixes #278) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/287
* refactor(core): extract MuxHandshake protocol module (arch-011 Option B PR-B) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/290
* fix(core): route channel-level events through SafeEventRaiser (fixes #286) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/296
* test(core): add missing NotifyEventHandlerException stub to ChannelRegistryTests.NoopOwner by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/307
* fix(transport/websocket): aggregate per-session dispose failures in WebSocketMuxListener (fixes #295) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/301
* fix(transport/udp): discard non-HELLO packets in CreateServerOptions to prevent listener hijack (fixes #303) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/306
* fix(transit/duplexstream): aggregate inner-channel dispose failures (fixes #305) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/308
* refactor(core): split DispatchToChannel into init/dispatch helpers (arch-011 Option C) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/309
* refactor(mux): extract MuxKeepalive subsystem from StreamMultiplexer by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/310
* refactor(mux): extract MuxTransportWriter (writer + flusher loops) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/311
* refactor(mux): extract MuxConnectRetry (connection-attempt loop) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/312
* refactor(mux): extract ChannelBatchRegistrar (TryRegisterChannels guts) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/313
* fix(transport/ipc): dispose client/socket on post-connect and post-accept setup failure (fixes #304) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/314
* fix(transport/udp): filter stale ACKs by current send seq to prevent infinite resend loop (fixes #302) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/316
* fix(channel): make MarkOpen state transition atomic with SetClosed (fixes #163) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/317
* fix(transit/delta-message): defer peer resync to send lock to prevent lost-resync race (fixes #300) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/318
* fix(mux): exchange replay base in reconnect handshake (fixes #161) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/315
* fix(extensions): dispose channel when WaitForReadyAsync throws (fixes #250) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/320
* fix(transit/delta-message): stage SendBatchAsync mutations and only commit _lastSentState after successful send by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/319
* fix(transit/delta-message): clone JsonObject/JsonArray on receive (fixes #241) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/321
* fix(transit): aggregate dispose errors in MessageTransit and DeltaMessageTransit (fixes #292) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/322
* fix(keepalive): correlate Pong to Ping by 8-byte token (fixes #293) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/323
* fix(mux): drain local writes before tearing down on remote GoAway (fixes #165) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/324
* fix(mux): account ReadChannel close exactly once across FIN and Dispose paths (fixes #172) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/325
* fix(transport/websocket): reject unknown sessionId on HandleAsync (fixes #236) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/327
* fix(transport/quic): validate NetConduit preface byte on server (fixes #255) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/328
* fix(transit): make Ready event latching so subscribers added after channels are ready still observe it (fixes #266) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/329
* fix(mux): route channel to accept queue when pending TCS already cancelled (fixes #269) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/330
* fix(transit/delta-message): ReceiveAllAsync survives transient transport disconnects via _receiveEof by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/331
* fix(transit/delta-message): clone-and-swap _lastReceivedState on ApplyDelta failure (fixes #223) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/332
* fix(transit/duplexstream): dedupe Connected and Disconnected events by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/349
* fix(transport/udp): drain duplicate NC_HELLO retransmits and reject non-ACK datagrams in handshake by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/347
* fix(transport/ipc): use ephemeral TCP port + endpoint registry on Windows (fixes #233) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/345
* fix(transit): dispose transit when WaitForReadyAsync throws in *Async extensions (fixes #289) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/340
* fix(mux): make CoalescingSignal dispose race-safe (fixes #281) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/339
* fix(transit/message): drain in-flight Send/Receive before disposing semaphores (fixes #219) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/346
* fix(mux): scope ChannelRegistry.UnregisterChannel _idToIndex removal to (channelId, index) pair (fixes #228) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/344
* fix(transit/delta-message): drain over-max payload before throw, parse length as UInt32 by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/333
* fix(transport/websocket): auto-evict listener sessions on mux Disconnected (fixes #279) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/341
* fix(mux): reassign pre-handshake channel indices to handshake-decided parity (fixes #237) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/326
* fix(backpressure): non-throwing ACK send + retry on control-slab pressure by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/336
* fix(mux): route AcceptChannelAsync delivery through TCS to prevent double-delivery (fixes #179, #229) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/338
* fix(transport/websocket): reject zero-length Binary frames to stop CPU spin by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/350
* fix(mux): advertise per-peer max-recv-payload in handshake (fixes #180) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/335
* fix(transit/delta-message): serialize outgoing resync request under _sendLock (fixes #193) by @Kiryuumaru in https://github.com/Kiryuumaru/NetConduit/pull/352
**Full Changelog**: https://github.com/Kiryuumaru/NetConduit/compare/build.20260514113647.b04936d...build.20260522181957.2c9c9bd