Commit Graph

313 Commits

Author SHA1 Message Date
Joseph Doherty
7468401bd0 feat(client): add write timeout recovery with per-kind policies
Add WriteTimeoutPolicy enum, FlushResult record struct, and
GetWriteTimeoutPolicy static method as nested types in NatsClient.
Models Go's client.go per-kind timeout handling: CLIENT kind closes
on timeout, ROUTER/GATEWAY/LEAF use TCP-level flush recovery.
2026-02-25 02:37:48 -05:00
Joseph Doherty
494d327282 feat(client): add stall gate backpressure for slow consumers
Adds StallGate nested class inside NatsClient that blocks producers when
the outbound buffer exceeds 75% of maxPending capacity, modelling Go's
stc channel and stalledRoute handling in server/client.go.
2026-02-25 02:35:57 -05:00
Joseph Doherty
36e23fa31d feat(client): add flush coalescing to reduce write syscalls
Adds MaxFlushPending constant (10), SignalFlushPending/ResetFlushPending
helpers, and ShouldCoalesceFlush property to NatsClient, matching Go's
maxFlushPending / fsp flush-signal coalescing in server/client.go.
2026-02-25 02:33:44 -05:00
Joseph Doherty
8fa16d59d2 feat(mirror): add exponential backoff retry, gap detection, and error tracking
Exposes public RecordFailure/RecordSuccess/GetRetryDelay (no-jitter, deterministic)
on MirrorCoordinator, plus RecordSourceSeq with HasGap/GapStart/GapEnd properties
and SetError/ClearError/HasError/ErrorMessage for error state. Makes IsDuplicate
and RecordMsgId public on SourceCoordinator and adds PruneDedupWindow(DateTimeOffset)
for explicit-cutoff dedup window pruning. Adds 5 unit tests in MirrorSourceRetryTests.
2026-02-25 02:30:55 -05:00
Joseph Doherty
955d568423 feat(stream): add InterestRetentionPolicy for per-consumer ack tracking
Implements Interest retention policy logic that tracks which consumers
are interested in each message subject and whether they have acknowledged
delivery, retaining messages until all interested consumers have acked.
Go reference: stream.go checkInterestState/noInterest.
2026-02-25 02:25:39 -05:00
Joseph Doherty
2eaa736b21 feat(consumer): add priority group pin ID management
Add AssignPinId, ValidatePinId, and UnassignPinId to PriorityGroupManager,
plus CurrentPinId tracking on PriorityGroup, porting Go consumer.go
(setPinnedTimer, assignNewPinId) pin ID semantics. Covered by 7 new tests.
2026-02-25 02:23:02 -05:00
Joseph Doherty
dcc3e4460e feat(consumer): add pause/resume with auto-resume timer
Adds PauseUntilUtc to ConsumerHandle, a new Pause(DateTime) overload,
Resume, IsPaused, and GetPauseUntil to ConsumerManager. A System.Threading.Timer
fires when the deadline passes and calls AutoResume, raising OnAutoResumed so
tests can synchronise via SemaphoreSlim instead of Task.Delay. ConsumerManager
now implements IDisposable to clean up outstanding timers. Timer is also
cancelled on explicit Resume and Delete.

Go reference: consumer.go (pauseConsumer / resumeConsumer / isPaused).
2026-02-25 02:21:08 -05:00
Joseph Doherty
8fb80acafe feat(consumer): add WaitingRequestQueue with expiry and batch/maxBytes tracking
Implements a FIFO pull-request queue (WaitingRequestQueue) with per-request
mutable batch countdown and byte budget tracking, plus RemoveExpired cleanup.
Complements the existing priority-based PullRequestWaitQueue for pull consumer delivery.
Go reference: consumer.go waitQueue / processNextMsgRequest (lines 4276-4450).
2026-02-25 02:18:01 -05:00
Joseph Doherty
3183fd2dc7 feat(consumer): enhance AckProcessor with NAK delay, TERM, WPI, and maxAckPending
Add RedeliveryTracker constructor overload, Register(ulong, string) for
tracker-based ack-wait, ProcessAck(ulong) payload-free overload, GetDeadline,
CanRegister for maxAckPending enforcement, ParseAckType static parser, and
AckType enum. All existing API signatures are preserved; 9 new tests added in
AckProcessorEnhancedTests.cs with no regressions to existing 10 tests.
2026-02-25 02:15:46 -05:00
Joseph Doherty
55de052009 feat(consumer): add PriorityQueue-based RedeliveryTracker overloads
Add new constructor, Schedule(DateTimeOffset), GetDue(DateTimeOffset),
IncrementDeliveryCount, IsMaxDeliveries(), and GetBackoffDelay() to
RedeliveryTracker without breaking existing API. Uses PriorityQueue<ulong,
DateTimeOffset> for deadline-ordered dispatch mirroring Go consumer.go rdq.
2026-02-25 02:12:37 -05:00
Joseph Doherty
7e4a23a0b7 feat(cluster): implement leadership transition with inflight cleanup
Add ProcessLeaderChange(bool) method and OnLeaderChange event to JetStreamMetaGroup.
Refactor StepDown() to delegate inflight clearing through ProcessLeaderChange,
enabling subscribers to react to leadership transitions.
Go reference: jetstream_cluster.go:7001-7074 processLeaderChange.
2026-02-25 02:08:37 -05:00
Joseph Doherty
63d4e43178 feat(cluster): add structured inflight proposal tracking with ops counting
Replace the simple string-keyed inflight dictionaries with account-scoped
ConcurrentDictionary<string, Dictionary<string, InflightInfo>> structures.
Adds InflightInfo record with OpsCount for duplicate proposal tracking,
TrackInflight/RemoveInflight/IsInflight methods for streams and consumers,
and ClearAllInflight(). Updates existing Propose* methods to use $G account.
Go reference: jetstream_cluster.go:1193-1278.
2026-02-25 02:05:53 -05:00
Joseph Doherty
1a9b6a9175 feat(cluster): add stream/consumer assignment processing with validation
Add 5 validated Process* methods to JetStreamMetaGroup for stream and
consumer assignment processing: ProcessStreamAssignment, ProcessUpdateStreamAssignment,
ProcessStreamRemoval, ProcessConsumerAssignment, and ProcessConsumerRemoval.
Each returns a bool indicating success, with validation guards matching
Go reference jetstream_cluster.go:4541-5925. Includes 12 new unit tests.
2026-02-25 01:57:43 -05:00
Joseph Doherty
7f9ee493b6 feat(cluster): add JetStreamClusterMonitor for meta RAFT entry processing
Implements the background loop (Go: monitorCluster) that reads RaftLogEntry
items from a channel and dispatches assignStream, removeStream, assignConsumer,
removeConsumer, and snapshot operations to JetStreamMetaGroup.

- Add five public mutation helpers to JetStreamMetaGroup (AddStreamAssignment,
  RemoveStreamAssignment, AddConsumerAssignment, RemoveConsumerAssignment,
  ReplaceAllAssignments) used by the monitor path
- JetStreamClusterMonitor: async loop over ChannelReader<RaftLogEntry>, JSON
  dispatch, ILogger injection with NullLogger default, malformed entries logged
  and skipped rather than aborting the loop
- WaitForProcessedAsync uses Monitor.PulseAll for race-free test synchronisation
  with no Task.Delay — satisfies slopwatch SW003/SW004 rules
- 10 new targeted tests all pass; 1101 cluster regression tests unchanged
2026-02-25 01:54:04 -05:00
Joseph Doherty
9fdc931ff5 feat(cluster): add MetaSnapshotCodec with S2 compression and versioned format
Implements binary codec for meta-group snapshots: 2-byte little-endian version
header followed by S2-compressed JSON of the stream assignment map. Adds
[JsonObjectCreationHandling(Populate)] to StreamAssignment.Consumers so the
getter-only dictionary is populated in-place during deserialization. 8 tests
covering round-trip, compression ratio, field fidelity, multi-consumer restore,
version rejection, and truncation guard.

Go reference: jetstream_cluster.go:2075-2145 (encodeMetaSnapshot/decodeMetaSnapshot)
2026-02-25 01:46:32 -05:00
Joseph Doherty
e0f5fe7150 feat(raft): implement joint consensus for safe two-phase membership changes
Adds BeginJointConsensus, CommitJointConsensus, and CalculateJointQuorum to
RaftNode per Raft paper Section 4. During a joint configuration transition
quorum requires majority from BOTH Cold and Cnew; CommitJointConsensus
finalizes Cnew as the sole active configuration. The existing single-phase
ProposeAddPeerAsync/ProposeRemovePeerAsync are unchanged. Includes 16 new
tests covering flag behaviour, quorum boundaries, idempotent commit, and
backward-compatibility with the existing membership API.
2026-02-25 01:40:56 -05:00
Joseph Doherty
a0894e7321 fix(raft): address WAL code quality issues — CRC perf, DRY, safety, assertions
- SyncAsync: remove redundant FlushAsync, use single Flush(flushToDisk:true)
- ComputeCrc: use incremental Crc32.Append to avoid contiguous buffer heap allocation
- Load: cast pos+length to long to guard against int overflow in bounds check
- AppendAsync: delegate to WriteEntryTo (DRY — eliminates duplicated record-building logic)
- Load: extract ParseEntries static helper to eliminate goto pattern with early returns
- Entries: change return type from IEnumerable to IReadOnlyList for index access and Count property
- RaftNode.PersistAsync: remove redundant term.txt write (meta.json now owns term+votedFor)
- RaftWalTests: tighten ShouldBeGreaterThanOrEqualTo(1) -> ShouldBe(1) in truncation/CRC tests;
  use .Count property directly on IReadOnlyList instead of .Count() LINQ extension
2026-02-25 01:36:41 -05:00
Joseph Doherty
c9ac4b9918 feat(raft): add binary WAL and VotedFor persistence
Implements a binary write-ahead log (RaftWal) for durable RAFT entry
storage, replacing in-memory-only semantics. The WAL uses a magic header
("NWAL" + version), length-prefixed records with per-record CRC32
integrity checking, and CompactAsync with atomic temp-file rename.
Load() tolerates truncated or corrupt tail records for crash safety.

Also fixes RaftNode to persist and reload TermState.VotedFor via a
meta.json file alongside term.txt, ensuring vote durability across
restarts. Falls back gracefully to legacy term.txt when meta.json is
absent.

6 new tests in RaftWalTests: persist/recover, compact, truncation
tolerance, VotedFor round-trip, empty WAL, and CRC corruption.
All 458 Raft tests pass.
2026-02-25 01:31:23 -05:00
Joseph Doherty
3ab683489e feat(filestore): implement EncodedStreamState, UpdateConfig, ResetState, fix Delete signature
Complete IStreamStore Batch 2 — all remaining interface methods now have
FileStore implementations:
- EncodedStreamState: placeholder returning empty (full codec in Task 9)
- UpdateConfig: no-op placeholder for config hot-reload
- ResetState: no-op (state derived from blocks on construction)
- Delete(bool): now calls Stop() first and matches interface signature
2026-02-25 01:22:43 -05:00
Joseph Doherty
be432c3224 feat(filestore): implement StoreRawMsg, LoadPrevMsg, Type, Stop on FileStore
Complete IStreamStore Batch 1 — all core operations now have FileStore
implementations instead of throwing NotSupportedException:
- StoreRawMsg: caller-specified seq/ts for replication/mirroring
- LoadPrevMsg: backward scan for message before given sequence
- Type: returns StorageType.File
- Stop: flush + dispose blocks, reject further writes

14 new tests in FileStoreStreamStoreTests.
2026-02-25 01:20:03 -05:00
Joseph Doherty
f402fd364f feat(filestore): implement FlushAllPending with atomic stream state writes
Add FlushAllPending() to FileStore — flushes active MsgBlock to disk and
writes a stream.state checkpoint atomically (write-to-temp + rename).
Go ref: filestore.go:5783 (flushPendingWritesUnlocked / writeFullState).

5 new tests in FileStoreCrashRecoveryTests: flush, state file, idempotent,
TTL recovery, truncated block handling.
2026-02-25 01:14:34 -05:00
Joseph Doherty
f031edb97e feat(filestore): implement FlushAllPending with atomic stream state writes
Add FlushAllPending() to FileStore, fulfilling the IStreamStore interface
contract. The method flushes the active MsgBlock to disk and atomically
writes a stream.state checkpoint using write-to-temp + rename, matching
Go's flushPendingWritesUnlocked / writeFullState pattern.

Add FileStoreCrashRecoveryTests with 5 tests covering:
- FlushAllPending flushes block data to .blk file
- FlushAllPending writes a valid atomic stream.state JSON checkpoint
- FlushAllPending is idempotent (second call overwrites with latest state)
- Recovery prunes messages backdated past the MaxAgeMs cutoff
- Recovery handles a tail-truncated block without throwing

Reference: golang/nats-server/server/filestore.go:5783-5842
2026-02-25 01:07:32 -05:00
Joseph Doherty
f143295392 feat(filestore): wire AeadEncryptor into MsgBlock for at-rest encryption
Add FileStoreEncryptionTests covering ChaCha20-Poly1305 and AES-GCM
round-trips and wrong-key rejection for the FSV2 AEAD path. Fix
RestorePayload to wrap CryptographicException from AEAD decryption as
InvalidDataException so RecoverBlocks correctly propagates key-mismatch
failures instead of silently swallowing them.
2026-02-25 00:43:57 -05:00
Joseph Doherty
51ebded300 fix: correct MaxBytes enforcement and consumer start sequence after purge
StreamManager.Capture now accounts for full message size (subject +
payload + 16-byte overhead) when checking MaxBytes, matching Go's
memStoreMsgSize. PullConsumerEngine uses stream FirstSeq instead of
hardcoded 1 for DeliverAll after purge. Fix 6 tests with Go parity
assertions and updated MaxBytes values.
2026-02-24 23:59:37 -05:00
Joseph Doherty
13a3f81d7e fix: resolve MemStore timestamp overflow causing immediate message expiry
DateTime.UtcNow.Ticks * 100L overflows long (Ticks ~6.38e17, x100 =
6.38e19 > long.MaxValue 9.22e18), producing corrupted timestamps that
cause PruneExpiredMessages to immediately expire all messages when
MaxAgeMs is set. Use Unix epoch offset to match Go's time.Now().UnixNano().
2026-02-24 23:08:39 -05:00
Joseph Doherty
b80316a42f feat: add atomic batch publish engine & versioning support (Tasks 9-10)
- AtomicBatchPublishEngine: stage/commit/rollback semantics for batch publish
- JsVersioning: API level negotiation and stream/consumer metadata
- Fix NormalizeConfig missing AllowAtomicPublish, Metadata, PersistMode copy
- 46 batch publish tests + 67 versioning tests, all passing
2026-02-24 22:05:07 -05:00
Joseph Doherty
79b5f1cc7d feat: add PROXY protocol parser & SubList Go-parity tests (Task 26)
Add ProxyProtocol.cs implementing PROXY v1/v2 header parsing (Go ref:
server/proxy_proto.go). Port 29 PROXY protocol tests and 120 SubList
Go-parity tests covering ReverseMatch, HasInterest, NumInterest,
SubjectsCollide, cache hit rate, empty tokens, and overlapping subs.

Go refs: TestProtoParseProxyV1, TestSublistReverseMatch,
TestSublistHasInterest, TestSublistNumInterest, and 25+ more.
2026-02-24 20:58:23 -05:00
Joseph Doherty
e37058d5bb feat: add JetStream storage recovery & encryption tests (Task 6)
Port Go jetstream_test.go storage/recovery/encryption tests. Add stream
recovery stubs, encryption key management, direct-get with time queries,
and subject delete marker handling.

23 new tests ported from jetstream_test.go.
2026-02-24 20:38:13 -05:00
Joseph Doherty
f45c76543a feat: add store interface contract tests & fix Compact dmap cleanup (Task 4)
Port Go store_test.go contract tests for IStreamStore interface using
MemStore. Fix CompactInternal to correctly walk forward to find new
FirstSeq before backward cleanup (matching Go behavior).

21 new tests ported from store_test.go.
2026-02-24 20:38:09 -05:00
Joseph Doherty
1a3fe91611 feat: enhance ConfigProcessor & add 110 Go-parity opts tests (Task 22)
Port configuration parsing for NKey users, gateway remotes, leaf node
remotes, auth timeout, write_deadline, websocket ping_interval, and
token+users conflict validation. Add RemoteGatewayOptions, enhanced
LeafNodeOptions with remotes support.

110 new tests ported from opts_test.go.
2026-02-24 20:17:48 -05:00
Joseph Doherty
f35961abea feat: add MemStore Go-parity methods & 25 new tests (Task 3)
Port Go memstore sync interface: Compact, Truncate, PurgeEx, SkipMsgs,
LoadNextMsg, NumPending, MultiLastSeqs, AllLastSeqs, SubjectsTotals,
SubjectsState, GetSeqFromTime, NextWildcardMatch, NextLiteralMatch,
MessageTTL, UpdateConfig. Fix RestoreSnapshotAsync to handle gapped
sequences, update MsgSize to include subject length + 16 overhead
(Go parity).

25 new tests ported from memstore_test.go.
2026-02-24 20:17:42 -05:00
Joseph Doherty
7eb06c8ac5 feat: add FileStore tombstone, TTL & consumer state persistence (Task 2)
Port Go filestore tombstone/deletion tests, consumer state encode/decode,
consumer file store persistence, and message TTL enforcement. Adds
ConsumerStateCodec and ConsumerFileStore implementations.

17 new tests ported from filestore_test.go.
2026-02-24 20:17:35 -05:00
Joseph Doherty
a9967d3077 test(parity): port consumer pull queue & filter tests (T14) + DB update
Port 48 Go parity tests from TestJetStreamConsumerPull* and related
functions in jetstream_consumer_test.go to unit-level .NET tests.

Enhancements to PullConsumerEngine:
- MaxBytes enforcement in FetchAsync loop (stops delivery when budget exceeded)
- PullRequestWaitQueue with priority-ordered stable enqueue and popAndRequeue
  round-robin semantics within same-priority groups
- PullWaitingRequest record with Priority, RemainingBatch, Reply fields

Enhancements to ConsumerConfig:
- MaxWaiting, MaxRequestBatch, MaxRequestMaxBytes, MaxRequestExpiresMs

New tests (51 total in ConsumerPullQueueTests.cs):
- Pull MaxAckPending enforcement, FIFO delivery, one-shot semantics
- Pull timeout (ExpiresMs), NoWait behavior, MaxBytes byte budget
- Three-filter and multi-filter subject filtering, filter update
- WaitQueue priority ordering and popAndRequeue round-robin
- Pending count tracking, ack floor advancement, redelivery
- DeliverPolicy Last/LastPerSubject/ByStartTime with filters
- ConsumerIsFiltered detection, overlapping subject filters

DB: 37 Go tests mapped → ConsumerPullQueueTests.cs (1,386 total mapped)
2026-02-24 19:53:25 -05:00
Joseph Doherty
b4ad71012f test(parity): port FileStore recovery & compaction tests (T1) + DB update
Ports 34 Go FileStore tests from filestore_test.go to
FileStoreRecovery2Tests.cs (31 pass, 4 skipped). Tests cover block
recovery, compaction, PSIM indexing, skip-msg handling, TTL expiry,
corrupt index/state detection, and read-only permission checks.

Updates docs/test_parity.db with mapped/skipped status for all 34 tests.
2026-02-24 19:39:40 -05:00
Joseph Doherty
d286349262 fix: re-enable leader check in API router and fix stepdown simulation
Re-enabled the leader check in JetStreamApiRouter.Route() that was
commented out during B8 agent work. Added BecomeLeader() method to
JetStreamMetaGroup for single-process test fixtures to simulate
winning the post-stepdown election. MetaControllerFixture now
auto-calls BecomeLeader() after a successful meta leader stepdown.
2026-02-24 18:02:54 -05:00
Joseph Doherty
1257a5ca19 feat(cluster): rewrite meta-group, enhance stream RAFT, add Go parity tests (B7+B8+B9+B10)
- JetStreamMetaGroup: validated proposals, inflight tracking, consumer counting, ApplyEntry dispatch
- StreamReplicaGroup: ProposeMessageAsync, LeaderChanged event, message/sequence tracking, GetStatus
- PlacementEngine tests: cluster affinity, tag filtering, storage ordering (16 tests)
- Assignment serialization tests: quorum calc, has-quorum, property defaults (16 tests)
- MetaGroup proposal tests: stream/consumer CRUD, leader validation, inflight (30 tests)
- StreamRaftGroup tests: message proposals, step-down events, status (10 tests)
- RAFT Go parity tests + JetStream cluster Go parity tests (partial B11 pre-work)
2026-02-24 17:23:57 -05:00
Joseph Doherty
a323715495 feat(cluster): add stream/consumer assignments, placement engine, and meta proposal workflow (B7+B8+B9)
- RaftGroup, StreamAssignment, ConsumerAssignment types matching Go structs
  (jetstream_cluster.go:154-266)
- PlacementEngine.SelectPeerGroup: topology-aware peer selection with cluster
  affinity, tag filtering, exclude tags, and storage-weighted sorting
  (Go ref: selectPeerGroup at line 7212)
- JetStreamMetaGroup: backward-compatible rewrite with full assignment tracking,
  consumer proposal workflow, and delete operations
- 41 new tests in ClusterAssignmentAndPlacementTests
2026-02-24 17:13:28 -05:00
Joseph Doherty
a41d0f453c feat(cluster): add placement engine with topology-aware peer selection (B9-prep) 2026-02-24 17:09:32 -05:00
Joseph Doherty
824e0b3607 feat(raft): add membership proposals, snapshot checkpoints, and log compaction (B4+B5+B6)
- ProposeAddPeerAsync/ProposeRemovePeerAsync: single-change-at-a-time membership
  changes through RAFT consensus (Go ref: raft.go:961-1019)
- RaftLog.Compact: removes entries up to given index for log compaction
- CreateSnapshotCheckpointAsync: creates snapshot and compacts log in one operation
- DrainAndReplaySnapshotAsync: drains commit queue, installs snapshot, resets indices
- Pre-vote protocol skipped (Go NATS doesn't implement it either)
- 23 new tests in RaftMembershipAndSnapshotTests
2026-02-24 17:08:59 -05:00
Joseph Doherty
5b706c969d feat(raft): add commit queue, election timers, and peer health tracking (B1+B2+B3)
- CommitQueue<T>: channel-based queue for committed entries awaiting state machine application
- RaftPeerState: tracks replication and health state (nextIndex, matchIndex, lastContact)
- RaftNode: CommitIndex/ProcessedIndex tracking, election timer with randomized 150-300ms interval,
  peer state integration with heartbeat and replication updates
- 52 new tests across RaftApplyQueueTests, RaftElectionTimerTests, RaftHealthTests
2026-02-24 17:01:00 -05:00
Joseph Doherty
579063dabd test(parity): port 373 Go tests across protocol and services subsystems (C11+E15)
Protocol (C11):
- ClientProtocolGoParityTests: 45 tests (header stripping, tracing, limits, NRG)
- ConsumerGoParityTests: 60 tests (filters, actions, pinned, priority groups)
- JetStreamGoParityTests: 38 tests (stream CRUD, purge, mirror, retention)

Services (E15):
- MqttGoParityTests: 65 tests (packet parsing, QoS, retained, sessions)
- WsGoParityTests: 58 tests (compression, JWT auth, frame encoding)
- EventGoParityTests: 56 tests (event DTOs, serialization, health checks)
- AccountGoParityTests: 28 tests (route mapping, system account, limits)
- MonitorGoParityTests: 23 tests (connz filtering, pagination, sort)

DB: 1,148/2,937 mapped (39.1%), up from 1,012 (34.5%)
2026-02-24 16:52:15 -05:00
Joseph Doherty
94878d3dcc feat(monitoring+events): add connz filtering, event payloads, and message trace context (E12+E13+E14)
- Add ConnzHandler with sorting, filtering, pagination, CID lookup, and closed connection ring buffer
- Add full Go events.go parity types (ConnectEventMsg, DisconnectEventMsg, ServerStatsMsg, etc.)
- Add MessageTraceContext for per-message trace propagation with header parsing
- 74 new tests (17 ConnzFilter + 16 EventPayload + 41 MessageTraceContext)
2026-02-24 16:17:21 -05:00
Joseph Doherty
37d3cc29ea feat(networking): add leaf subject filtering and port networking Go tests (D6+D7)
D6: Add ExportSubjects/ImportSubjects allow-lists to LeafHubSpokeMapper alongside
existing DenyExports/DenyImports deny-lists. When an allow-list is non-empty, subjects
must match at least one allow pattern; deny always takes precedence. Updated
LeafNodeOptions, LeafHubSpokeMapper (5-arg constructor), and LeafNodeManager to wire
through the new allow-lists. Added 13 new unit + integration tests covering allow-list
semantics, deny precedence, bidirectional filtering, and wire-level propagation.

D7: Existing NetworkingGoParityTests.cs (50 tests) covers gateway interest mode,
route pool accounting, and leaf node connections. Parity DB already up to date.
2026-02-24 16:07:33 -05:00
Joseph Doherty
02531dda58 feat(config+ws): add TLS cert reload, WS compression negotiation, WS JWT auth (E9+E10+E11)
E9: TLS Certificate Reload
- Add TlsCertificateProvider with Interlocked-swappable cert field
- New connections get current cert, existing connections keep theirs
- ConfigReloader.ReloadTlsCertificate rebuilds SslServerAuthenticationOptions
- NatsServer.ApplyConfigChanges triggers TLS reload on TLS config changes
- 11 tests covering cert swap, versioning, thread safety, config diff

E10: WebSocket Compression Negotiation (RFC 7692)
- Add WsDeflateNegotiator to parse Sec-WebSocket-Extensions parameters
- Parse server_no_context_takeover, client_no_context_takeover,
  server_max_window_bits, client_max_window_bits
- WsDeflateParams record struct with ToResponseHeaderValue()
- NATS always enforces no_context_takeover (matching Go server)
- WsUpgrade returns negotiated WsDeflateParams in upgrade result
- 22 tests covering parameter parsing, clamping, response headers

E11: WebSocket JWT Authentication
- Extract JWT from Authorization header (Bearer token), cookie, or ?jwt= query param
- Priority: Authorization header > cookie > query parameter
- WsUpgrade.TryUpgradeAsync now parses query string from request URI
- Add FailUnauthorizedAsync for 401 responses
- 24 tests covering all JWT extraction sources and priority ordering
2026-02-24 16:03:46 -05:00
Joseph Doherty
c6ecbbfbcc feat(config): add system account, SIGHUP reload, and auth change propagation (E6+E7+E8)
E6: Add IsSystemAccount property to Account, mark $SYS account as system,
add IsSystemSubject/IsSubscriptionAllowed/GetSubListForSubject helpers to
route $SYS.> subjects to the system account's SubList and block non-system
accounts from subscribing.

E7: Add ConfigReloader.ReloadAsync and ApplyDiff for structured async reload,
add ConfigReloadResult/ConfigApplyResult types. SIGHUP handler already wired
via PosixSignalRegistration in HandleSignals.

E8: Add PropagateAuthChanges to re-evaluate connected clients after auth
config reload, disconnecting clients whose credentials no longer pass
authentication with -ERR 'Authorization Violation'.
2026-02-24 15:48:48 -05:00
Joseph Doherty
18acd6f4e2 feat(jetstream): add mirror sync loop and source coordination with filtering (C9+C10) 2026-02-24 15:41:35 -05:00
Joseph Doherty
235971ddcc feat(auth): add account import/export cycle detection and JetStream limits (E4+E5)
E4: AccountImportExport with DFS cycle detection for service imports,
RemoveServiceImport/RemoveStreamImport, and ValidateImport authorization.
E5: AccountLimits record with MaxStorage/MaxConsumers/MaxAckPending,
TryReserveConsumer/ReleaseConsumer, TrackStorageDelta on Account.
20 new tests, all passing.
2026-02-24 15:25:12 -05:00
Joseph Doherty
efd053ba60 feat(networking): expand gateway reply mapper and add leaf solicited connections (D4+D5)
D4: Add hash segment support to ReplyMapper (_GR_.{cluster}.{hash}.{reply}),
FNV-1a ComputeReplyHash, TryExtractClusterId/Hash, legacy format compat.
D5: Add ConnectSolicitedAsync with exponential backoff (1s-60s cap),
JetStreamDomain propagation in LEAF handshake, LeafNodeOptions.JetStreamDomain.
2026-02-24 15:22:24 -05:00
Joseph Doherty
7116988d03 feat(jetstream): add API leader forwarding and stream purge options (C7+C8)
C7: JetStreamApiRouter now checks leadership before mutating operations.
Non-leader nodes return error code 10003 with a leader_hint field.
JetStreamMetaGroup gains IsLeader() and Leader for cluster-aware routing.

C8: StreamApiHandlers.HandlePurge accepts PurgeRequest options (filter,
seq, keep). StreamManager.PurgeEx implements subject-filtered purge,
sequence-based purge, keep-last-N, and filter+keep combinations.
2026-02-24 15:22:22 -05:00
Joseph Doherty
e49e5895c1 feat(mqtt): add session persistence, QoS 2 state machine, and retained store (E2+E3)
Add MqttSessionStore with save/load/delete/list operations, flapper
detection (backoff on rapid reconnects), and TimeProvider-based testing.
Add MqttRetainedStore for per-topic retained messages with MQTT wildcard
matching (+/# filters). Add MqttQos2StateMachine tracking the full
PUBREC/PUBREL/PUBCOMP flow with duplicate rejection and timeout detection.

19 new tests: 9 session persistence, 10 QoS/retained message tests.
2026-02-24 15:13:34 -05:00