@cosyte/mllp 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * All transports implement this callback-bag contract. Implementations:
5
5
  * - `NetTransport`, wraps `net.Socket` (production TCP)
6
- * - `TlsTransport`, wraps `tls.TLSSocket` (Phase 8, MLLPS / TLS hardening)
6
+ * - `TlsTransport`, wraps `tls.TLSSocket` (MLLPS / TLS hardening)
7
7
  * - `InMemoryTransport`, deterministic test double (`@cosyte/mllp/testing`)
8
8
  *
9
9
  * @example
package/dist/index.cjs CHANGED
@@ -30,7 +30,7 @@ var MllpFramingError = class _MllpFramingError extends Error {
30
30
  * This is a **copied** Buffer, isolated from the source buffer so it remains
31
31
  * valid after the underlying buffer is reused or overwritten.
32
32
  *
33
- * **PHI contract (MLLP-9):** the decoder only ever populates this with the single
33
+ * **PHI contract:** the decoder only ever populates this with the single
34
34
  * framing-boundary byte that violated the frame structure (whose hex value the
35
35
  * `message` already discloses), never a run of payload content bytes. For anomalies
36
36
  * whose fault is not a specific byte (`MLLP_FRAME_TOO_LARGE`, the accumulated size),
@@ -112,9 +112,9 @@ var FrameReader = class {
112
112
  _writePos = 0;
113
113
  /** Monotonic absolute stream byte offset across the entire connection lifetime. */
114
114
  _byteOffset = 0;
115
- /** Byte offset where current leading-whitespace run started (FRAME-10). */
115
+ /** Byte offset where current leading-whitespace run started. */
116
116
  _wsStart = 0;
117
- /** Count of leading whitespace bytes accumulated in current run (FRAME-10). */
117
+ /** Count of leading whitespace bytes accumulated in current run. */
118
118
  _wsCount = 0;
119
119
  /** Byte offset of the VT byte that started the current frame. */
120
120
  _frameStartOffset = 0;
@@ -149,7 +149,7 @@ var FrameReader = class {
149
149
  /**
150
150
  * Clear internal accumulator state and reset byte offset to 0.
151
151
  *
152
- * Call on reconnect / connection reuse to start fresh without allocating a new reader (D-03).
152
+ * Call on reconnect / connection reuse to start fresh without allocating a new reader.
153
153
  * Pending partial frame state is discarded silently.
154
154
  *
155
155
  * @example
@@ -390,7 +390,7 @@ var FrameReader = class {
390
390
  }
391
391
  /**
392
392
  * Copy accumulated payload bytes into a new Buffer and deliver via `onFrame`.
393
- * The copy isolates callers from internal accumulator reuse (T-02-03-03).
393
+ * The copy isolates callers from internal accumulator reuse.
394
394
  */
395
395
  _deliverFrame() {
396
396
  const payload = Buffer.from(this._accumulator.subarray(0, this._writePos));
@@ -400,7 +400,7 @@ var FrameReader = class {
400
400
  this._frameWarnings = [];
401
401
  this._opts.onFrame(payload, frameStart, frameWarnings);
402
402
  }
403
- /** Emit a warning via the `onWarning` callback, swallowing any handler exceptions (WARN-06). */
403
+ /** Emit a warning via the `onWarning` callback, swallowing any handler exceptions. */
404
404
  _emitWarning(code, byteOffset, message) {
405
405
  const warning = createWarning(code, byteOffset, message);
406
406
  this._frameWarnings.push(warning);
@@ -554,7 +554,7 @@ var LEGAL_TRANSITIONS = /* @__PURE__ */ new Map([
554
554
  ["CLOSED", /* @__PURE__ */ new Set()]
555
555
  ]);
556
556
  var Connection = class extends events.EventEmitter {
557
- /** Stable UUIDv4 identifier for this connection (D-11). */
557
+ /** Stable UUIDv4 identifier for this connection. */
558
558
  connectionId;
559
559
  _state = "CONNECTING";
560
560
  _transport;
@@ -567,20 +567,19 @@ var Connection = class extends events.EventEmitter {
567
567
  _bytesOut = 0;
568
568
  _lastByteInAt = null;
569
569
  _lastByteOutAt = null;
570
- /** Ring buffer: last MAX_WARNINGS entries (OBS-05). */
570
+ /** Ring buffer: last MAX_WARNINGS entries. */
571
571
  _warningBuffer = [];
572
- /** Accurate total counts per code, unaffected by ring buffer truncation (OBS-05). */
572
+ /** Accurate total counts per code, unaffected by ring buffer truncation. */
573
573
  _warningsByCode = /* @__PURE__ */ new Map();
574
- /** Set to true once the ring buffer overflows (OBS-05). */
574
+ /** Set to true once the ring buffer overflows. */
575
575
  _warningsTruncated = false;
576
576
  _onWarningFn = null;
577
577
  _drainPromise = null;
578
578
  /**
579
579
  * beforeClose hook, no-op default that resolves immediately.
580
580
  *
581
- * Phase 4 (Server) and Phase 5 (Client) override this instance property to
582
- * register ACK-drain and send-queue drain logic respectively (D-07/D-08).
583
- * Connection calls this during `close()`, racing against `drainTimeoutMs`.
581
+ * An owner may replace this instance property to run work before the socket
582
+ * closes. Connection calls it during `close()`, racing against `drainTimeoutMs`.
584
583
  */
585
584
  beforeClose = () => Promise.resolve();
586
585
  /**
@@ -627,7 +626,7 @@ var Connection = class extends events.EventEmitter {
627
626
  });
628
627
  }
629
628
  /**
630
- * Current FSM state. One of the 6 `ConnectionState` values (LIFE-01).
629
+ * Current FSM state. One of the 6 `ConnectionState` values.
631
630
  *
632
631
  * Subscribe to `'stateChange'` events for reactive state monitoring.
633
632
  */
@@ -635,10 +634,10 @@ var Connection = class extends events.EventEmitter {
635
634
  return this._state;
636
635
  }
637
636
  /**
638
- * Register or replace the per-connection warning subscriber (WARN-10).
637
+ * Register or replace the per-connection warning subscriber.
639
638
  *
640
639
  * Subsequent calls replace the previous handler (set-once semantics prevent leaks).
641
- * The handler is called synchronously and any exception it throws is swallowed (WARN-06).
640
+ * The handler is called synchronously and any exception it throws is swallowed.
642
641
  *
643
642
  * @example
644
643
  * ```typescript
@@ -676,7 +675,7 @@ var Connection = class extends events.EventEmitter {
676
675
  /**
677
676
  * Write raw bytes to the transport (no framing applied).
678
677
  *
679
- * Phase 4 (Server) and Phase 5 (Client) wrap this with `encodeFrame()` to add MLLP framing.
678
+ * The server and the client wrap this with `encodeFrame()` to add MLLP framing.
680
679
  * Returns `false` if the connection is CLOSED or DISCONNECTED (no bytes written).
681
680
  *
682
681
  * @returns `true` if bytes flushed immediately; `false` if buffered (backpressure) or not writable.
@@ -698,7 +697,7 @@ var Connection = class extends events.EventEmitter {
698
697
  * Initiate graceful close of the connection.
699
698
  *
700
699
  * - If `CONNECTING` or `RECONNECTING`: cancels the pending attempt, transitions
701
- * directly to `CLOSED`, and calls `transport.destroy()` (LIFE-05).
700
+ * directly to `CLOSED`, and calls `transport.destroy()`.
702
701
  * - If `CONNECTED`: transitions to `DRAINING`, calls `beforeClose(drainTimeoutMs)`,
703
702
  * then `DRAINING → DISCONNECTED` once the hook resolves, or `DRAINING → CLOSED`
704
703
  * if the drain timeout elapses first.
@@ -733,7 +732,7 @@ var Connection = class extends events.EventEmitter {
733
732
  * Race `beforeClose()` against the drain timeout.
734
733
  *
735
734
  * On normal completion: `DRAINING → DISCONNECTED` + `transport.close()`.
736
- * On timeout: `DRAINING → CLOSED` + `transport.destroy()` (T-03-04-01).
735
+ * On timeout: `DRAINING → CLOSED` + `transport.destroy()`.
737
736
  */
738
737
  async _drainWithTimeout(timeoutMs) {
739
738
  const drainPromise = this.beforeClose(timeoutMs);
@@ -776,7 +775,7 @@ var Connection = class extends events.EventEmitter {
776
775
  this._transport.destroy(reason);
777
776
  }
778
777
  /**
779
- * Return a JSON-serializable observability snapshot (OBS-03/04/05).
778
+ * Return a JSON-serializable observability snapshot.
780
779
  *
781
780
  * All timestamp fields are `Date | null` (not epoch milliseconds). `JSON.stringify()`
782
781
  * serialises them to ISO 8601 strings with no information loss.
@@ -1230,10 +1229,10 @@ var MllpServer = class extends events.EventEmitter {
1230
1229
  /** `true` when `ServerOptions.tls` is set, `_netServer` is actually a `tls.Server`. */
1231
1230
  _isTls;
1232
1231
  _listening = false;
1233
- /** Phase 8, single-flight guard: `true` while a `listen()` call is settling. */
1232
+ /** Single-flight guard: `true` while a `listen()` call is settling. */
1234
1233
  _listenInFlight = false;
1235
1234
  /**
1236
- * Phase 8, settle hook for an in-flight `listen()`. Non-null only while a
1235
+ * Settle hook for an in-flight `listen()`. Non-null only while a
1237
1236
  * `listen()` is in flight; invoked by `close()` so a close racing startup
1238
1237
  * rejects the pending `listen()` (typed) instead of leaving it hung with
1239
1238
  * the single-flight guard stuck. Cleared on every settle path.
@@ -1243,7 +1242,7 @@ var MllpServer = class extends events.EventEmitter {
1243
1242
  _host = null;
1244
1243
  _acceptedTotal = 0;
1245
1244
  _closedTotal = 0;
1246
- /** Phase 8, count of `'tlsClientError'` events since listen(). */
1245
+ /** Count of `'tlsClientError'` events since listen(). */
1247
1246
  _tlsClientErrorsTotal = 0;
1248
1247
  /**
1249
1248
  * Construct an MLLP server. Created idle; call `listen()` (or use
@@ -1321,7 +1320,7 @@ var MllpServer = class extends events.EventEmitter {
1321
1320
  *
1322
1321
  * @param port - TCP port to bind. Use `0` to let the OS assign an ephemeral port.
1323
1322
  * @param hostOrOpts - Host string or object with `host` and optional `signal`.
1324
- * Default host: `'127.0.0.1'` (Phase 8 bind-safety hardening). Wildcard hosts
1323
+ * Default host: `'127.0.0.1'` (bind-safety hardening). Wildcard hosts
1325
1324
  * are rejected unless `ServerOptions.allowWildcardBind: true`, literal
1326
1325
  * spellings pre-bind, resolver-only shorthands post-bind via the
1327
1326
  * OS-normalized bound address.
@@ -1487,7 +1486,7 @@ var MllpServer = class extends events.EventEmitter {
1487
1486
  /**
1488
1487
  * Stop accepting new connections and gracefully close all active connections.
1489
1488
  *
1490
- * Sequence (D-06):
1489
+ * Sequence:
1491
1490
  * 1. `net.Server.close()`, stops accepting new connections immediately
1492
1491
  * 2. If `_connections` is empty: resolves immediately (no drain needed)
1493
1492
  * 3. Calls `_drainAll(drainTimeoutMs)`, Promise.all + side-effect setTimeout
@@ -1587,10 +1586,9 @@ var MllpServer = class extends events.EventEmitter {
1587
1586
  return this.close();
1588
1587
  }
1589
1588
  /**
1590
- * Return a JSON-serializable observability snapshot (OBS-02).
1589
+ * Return a JSON-serializable observability snapshot.
1591
1590
  *
1592
1591
  * `totalBytesIn` and `totalBytesOut` aggregate from live connections at call time.
1593
- * Plan 04 adds full aggregation; at Plan 01 scope they return 0.
1594
1592
  *
1595
1593
  * @example
1596
1594
  * ```typescript
@@ -1736,8 +1734,8 @@ var MllpServer = class extends events.EventEmitter {
1736
1734
  );
1737
1735
  }
1738
1736
  /**
1739
- * Extract a minimal, content-free peer-certificate summary (Phase 8, ATNA
1740
- * ITI-19 mutual authentication), CN strings, expiry, and the verification
1737
+ * Extract a minimal, content-free peer-certificate summary (ATNA ITI-19
1738
+ * mutual authentication), CN strings, expiry, and the verification
1741
1739
  * outcome (`authorized`) only; never the full certificate object. Returns
1742
1740
  * `null` when no peer certificate was presented (e.g. `clientAuth: 'WANT'`
1743
1741
  * with no client cert).
@@ -1845,7 +1843,7 @@ var MllpServer = class extends events.EventEmitter {
1845
1843
  * Run `onMessage` for its side effects only (custom-ACK and manual modes), guarding
1846
1844
  * against a synchronous throw or a rejected promise. In these modes the handler does
1847
1845
  * **not** gate the ACK, so a failure is re-emitted as a PHI-safe `'error'` on the
1848
- * connection (D-04: a handler error never crashes the server) rather than escaping as
1846
+ * connection (a handler error never crashes the server) rather than escaping as
1849
1847
  * an unhandled rejection. The error text is never placed on the wire.
1850
1848
  */
1851
1849
  _observeMessage(payload, meta, conn) {
@@ -1859,7 +1857,7 @@ var MllpServer = class extends events.EventEmitter {
1859
1857
  /**
1860
1858
  * The custom-builder path for `autoAck: fn`. Awaits the builder and dispatches its
1861
1859
  * Buffer as the ACK; the caller owns MSA-1. A builder error is re-emitted as `'error'`
1862
- * on the connection, the server never crashes (D-04).
1860
+ * on the connection, the server never crashes.
1863
1861
  */
1864
1862
  async _sendCustomAck(fn, payload, meta, conn) {
1865
1863
  try {
@@ -1873,7 +1871,7 @@ var MllpServer = class extends events.EventEmitter {
1873
1871
  /**
1874
1872
  * Frame an ACK payload and write it to the connection. `Connection.send()` returns
1875
1873
  * `false` under backpressure (socket write buffer full); that drops the ACK and emits
1876
- * a `MllpConnectionError({ phase: 'send' })` on the connection (D-04), the peer will
1874
+ * a `MllpConnectionError({ phase: 'send' })` on the connection, the peer will
1877
1875
  * time out waiting and may retry. The server never crashes.
1878
1876
  */
1879
1877
  _dispatchAck(conn, ackPayload) {
@@ -1938,7 +1936,7 @@ var Correlator = class {
1938
1936
  _sendSeq = 0;
1939
1937
  _queueBytes = 0;
1940
1938
  /**
1941
- * PLAN-06, count of pending entries with `sentAt !== null` (D-26 / B-01).
1939
+ * Count of pending entries with `sentAt !== null`.
1942
1940
  * Maintained at every site that mutates `entry.sentAt` or removes a
1943
1941
  * flushed entry: `markFlushed`, `remove`, `matchAck`, `expireDue`, `clear`.
1944
1942
  */
@@ -1974,7 +1972,7 @@ var Correlator = class {
1974
1972
  /**
1975
1973
  * Enqueue a new send awaiting its ACK. Returns the assigned
1976
1974
  * `correlationKey`, or `null` if `maxInFlight` is reached (caller awaits
1977
- * drain, PLAN-05's `pipeline:false`).
1975
+ * drain, `pipeline:false`).
1978
1976
  */
1979
1977
  enqueue(frame, controlIdOrNull, resolve, reject) {
1980
1978
  if (this._pending.size >= this._opts.maxInFlight) return null;
@@ -1993,7 +1991,7 @@ var Correlator = class {
1993
1991
  return key;
1994
1992
  }
1995
1993
  /**
1996
- * Record write-flush timestamp (CLIENT-04, clock starts at flush, NOT
1994
+ * Record write-flush timestamp (the clock starts at flush, NOT
1997
1995
  * at `send()` call). No-op if key is unknown (e.g. removed by abort).
1998
1996
  */
1999
1997
  markFlushed(key, now) {
@@ -2009,16 +2007,16 @@ var Correlator = class {
2009
2007
  * removed from live store. Caller calls `entry.resolve(ackPayload)`.
2010
2008
  * - controlId: keyed lookup by `controlIdFromAck`. Live-store hit returns
2011
2009
  * the entry; graveyard hit fires `MLLP_ACK_AFTER_TIMEOUT` warning
2012
- * (CLIENT-16, D-04) and returns `null`; otherwise fires
2013
- * `onUnmatchedAck(controlIdFromAck)` (CLIENT-15, D-05) and returns `null`.
2010
+ * and returns `null`; otherwise fires
2011
+ * `onUnmatchedAck(controlIdFromAck)` and returns `null`.
2014
2012
  *
2015
- * Triggers lazy graveyard eviction (D-04).
2013
+ * Triggers lazy graveyard eviction.
2016
2014
  *
2017
2015
  * @param _payload Inbound ACK bytes (framing stripped). MSA-2 extraction
2018
2016
  * happens at MllpClient's `_onAckPayload` hook; this method takes the
2019
2017
  * already-extracted control ID as a parameter.
2020
2018
  * @param controlIdFromAck MSA-2 extracted from ACK (controlId mode only).
2021
- * @param byteOffsetFromAck Stream offset; forwarded to `onWarning` (W-05).
2019
+ * @param byteOffsetFromAck Stream offset; forwarded to `onWarning`.
2022
2020
  */
2023
2021
  matchAck(_payload, controlIdFromAck = null, byteOffsetFromAck = 0) {
2024
2022
  this._evictGraveyardDue(this._opts.now());
@@ -2062,9 +2060,9 @@ var Correlator = class {
2062
2060
  }
2063
2061
  /**
2064
2062
  * Sweep live entries; expire those past `sentAt + ackTimeoutMs`.
2065
- * Fires `onTimeout(entry, elapsedMs)`; entries move to graveyard (D-04).
2063
+ * Fires `onTimeout(entry, elapsedMs)`; entries move to graveyard.
2066
2064
  * Driven externally by `MllpClient`'s periodic sweep tick, Correlator
2067
- * itself owns no timers (D-03).
2065
+ * itself owns no timers.
2068
2066
  */
2069
2067
  expireDue(now) {
2070
2068
  const t = now ?? this._opts.now();
@@ -2086,8 +2084,7 @@ var Correlator = class {
2086
2084
  /**
2087
2085
  * Reject every live entry with `reason` (insertion order) and clear
2088
2086
  * the live store. Graveyard is left intact (ages out via lazy eviction).
2089
- * Used by FIFO reconnect-reject (D-07, PLAN-04 wraps in MllpConnectionError)
2090
- * and `MllpClient.close()` to cancel pending sends.
2087
+ * Used by `MllpClient`'s correlator teardown to cancel pending sends.
2091
2088
  */
2092
2089
  clear(reason) {
2093
2090
  for (const entry of this._pending.values()) entry.reject(reason);
@@ -2095,14 +2092,14 @@ var Correlator = class {
2095
2092
  this._queueBytes = 0;
2096
2093
  this._inFlight = 0;
2097
2094
  }
2098
- /** Iterate live entries in insertion order (PLAN-04 reconnect-resend, D-07). */
2095
+ /** Iterate live entries in insertion order (reconnect-resend). */
2099
2096
  *liveEntries() {
2100
2097
  for (const entry of this._pending.values()) yield entry;
2101
2098
  }
2102
2099
  /**
2103
2100
  * Remove a live entry by key WITHOUT resolving/rejecting. Returns the
2104
2101
  * removed entry, or `null` if no entry with that key exists.
2105
- * Used by `MllpClient.send()` for AbortSignal cleanup and PLAN-04's
2102
+ * Used by `MllpClient.send()` for AbortSignal cleanup and by the
2106
2103
  * reconnect-reject FSM walk.
2107
2104
  */
2108
2105
  remove(key) {
@@ -2123,7 +2120,7 @@ var Correlator = class {
2123
2120
  inFlight: this._inFlight
2124
2121
  };
2125
2122
  }
2126
- /** Lazy graveyard eviction (D-04): drop entries past `timedOutAt + 2 * ackTimeoutMs`. */
2123
+ /** Lazy graveyard eviction: drop entries past `timedOutAt + 2 * ackTimeoutMs`. */
2127
2124
  _evictGraveyardDue(now) {
2128
2125
  const threshold = 2 * this._opts.ackTimeoutMs;
2129
2126
  for (const [key, entry] of this._graveyard) {
@@ -2216,7 +2213,7 @@ var MllpBackpressureError = class _MllpBackpressureError extends Error {
2216
2213
  queueDepth;
2217
2214
  /** Total bytes of in-flight + queued frames at the moment of rejection. */
2218
2215
  queueBytes;
2219
- /** The high-water-mark configuration that was triggered (D-23). */
2216
+ /** The high-water-mark configuration that was triggered. */
2220
2217
  highWaterMark;
2221
2218
  /**
2222
2219
  * Construct an MLLP backpressure error.
@@ -2246,15 +2243,15 @@ var MllpClient = class extends events.EventEmitter {
2246
2243
  * is attached, `state` mirrors `_connection.state`.
2247
2244
  */
2248
2245
  _state = "DISCONNECTED";
2249
- /** Per-message ACK timeout in ms (CLIENT-04). Resolved at construction. */
2246
+ /** Per-message ACK timeout in ms. Resolved at construction. */
2250
2247
  _ackTimeoutMs;
2251
- /** controlId-mode flag (CLIENT-03 branch). `false` → FIFO. */
2248
+ /** controlId-mode flag. `false` → FIFO. */
2252
2249
  _correlateByControlId;
2253
- /** Unified ACK correlator (D-03/A1). Built during `_attachConnection`. */
2250
+ /** Unified ACK correlator. Built during `_attachConnection`. */
2254
2251
  _correlator = null;
2255
2252
  /**
2256
2253
  * Periodic ACK-timeout sweep timer. Drives `_correlator.expireDue()` because
2257
- * the Correlator is timer-free per D-03. Cleared on close/destroy.
2254
+ * the Correlator is timer-free. Cleared on close/destroy.
2258
2255
  */
2259
2256
  _ackSweepTimer = null;
2260
2257
  // ── Reconnect state (Plan 04, CLIENT-05/06/12/17/18) ─────────────────────
@@ -2267,12 +2264,12 @@ var MllpClient = class extends events.EventEmitter {
2267
2264
  /** 0-indexed attempt counter for the current reconnect cycle. */
2268
2265
  _attempt = 0;
2269
2266
  /**
2270
- * W-02, total reconnect attempts since construction. Read by PLAN-06 for
2267
+ * Total reconnect attempts since construction, surfaced as
2271
2268
  * `getStats().reconnectAttempts`. Incremented at the entry of every
2272
2269
  * `_handleDisconnect` invocation that proceeds to schedule a backoff.
2273
2270
  */
2274
2271
  _reconnectAttempts = 0;
2275
- /** Epoch ms of the last successful ACK. Drives W-01 backoff-reset. */
2272
+ /** Epoch ms of the last successful ACK. Drives backoff-reset. */
2276
2273
  _lastSuccessAt = null;
2277
2274
  /** Epoch ms when the current reconnect cycle began. `null` outside a cycle. */
2278
2275
  _reconnectCycleStartedAt = null;
@@ -2289,12 +2286,12 @@ var MllpClient = class extends events.EventEmitter {
2289
2286
  _onBackpressure;
2290
2287
  /** Pipeline flag; default `true` (parallel up to highWaterMark). */
2291
2288
  _pipeline;
2292
- /** Dead-peer idle timer (Plan 05, D-11). `null` when not armed. */
2289
+ /** Dead-peer idle timer. `null` when not armed. */
2293
2290
  _deadPeerTimer = null;
2294
2291
  /** True once the self-'ack' listener that resets the dead-peer timer
2295
2292
  * has been attached. Guards against duplicate listeners on reconnect. */
2296
2293
  _ackResetWired = false;
2297
- /** Most recently bound `connect()` signal. Reread on every RetryContext build (W-07). */
2294
+ /** Most recently bound `connect()` signal. Reread on every RetryContext build. */
2298
2295
  _connectSignal;
2299
2296
  /** Set when close()/destroy()/abort fires; reconnect handler short-circuits. */
2300
2297
  _userClosed = false;
@@ -2323,7 +2320,7 @@ var MllpClient = class extends events.EventEmitter {
2323
2320
  /**
2324
2321
  * Aggregated Correlator-emitted warning counts (MLLP_ACK_*). Connection-level
2325
2322
  * warnings are read directly from `_connection.getStats().warningsByCode`
2326
- * at observation time and merged into the snapshot (D-26).
2323
+ * at observation time and merged into the snapshot.
2327
2324
  */
2328
2325
  _aggregatedWarningsByCode = {};
2329
2326
  /**
@@ -2363,8 +2360,8 @@ var MllpClient = class extends events.EventEmitter {
2363
2360
  return this._connection?.state ?? this._state;
2364
2361
  }
2365
2362
  /**
2366
- * Open a TCP (or TLS, Phase 8) connection to the configured `host:port`
2367
- * and attach a Phase 3 {@link Connection} to it. Resolves once the FSM
2363
+ * Open a TCP (or TLS) connection to the configured `host:port`
2364
+ * and attach a {@link Connection} to it. Resolves once the FSM
2368
2365
  * enters `CONNECTED`, for TLS, on `'secureConnect'` (handshake complete,
2369
2366
  * including certificate verification when it is on).
2370
2367
  *
@@ -2472,7 +2469,7 @@ var MllpClient = class extends events.EventEmitter {
2472
2469
  * Build the raw socket + `Transport` pair for a connect / reconnect attempt.
2473
2470
  *
2474
2471
  * Plaintext (`ClientOptions.tls` unset): a `net.Socket` wrapped in
2475
- * `NetTransport`. TLS (Phase 8): a `tls.TLSSocket` wrapped in
2472
+ * `NetTransport`. TLS: a `tls.TLSSocket` wrapped in
2476
2473
  * `TlsTransport`, verification defaults **on**
2477
2474
  * (`rejectUnauthorized: !allowUnverified`), floor `minVersion: 'TLSv1.2'`
2478
2475
  * (the IHE ATNA ITI-19 BCP195 floor), `servername` defaulting to
@@ -2502,7 +2499,7 @@ var MllpClient = class extends events.EventEmitter {
2502
2499
  }
2503
2500
  /**
2504
2501
  * Wrap a connect-phase socket error as `MllpConnectionError`, classifying
2505
- * TLS failures (Phase 8) into the additive `connectionCause`:
2502
+ * TLS failures into the additive `connectionCause`:
2506
2503
  *
2507
2504
  * - `'tls-verify'`, certificate-verification failures
2508
2505
  * ({@link isTlsVerificationErrorCode}).
@@ -2550,7 +2547,7 @@ var MllpClient = class extends events.EventEmitter {
2550
2547
  });
2551
2548
  }
2552
2549
  /**
2553
- * Emit the per-connection insecure-TLS warning (Phase 8) when
2550
+ * Emit the per-connection insecure-TLS warning when
2554
2551
  * `tls.allowUnverified === true`, fires on EVERY successful
2555
2552
  * `secureConnect`, initial connect and every reconnect. Emits both a frozen
2556
2553
  * `'securityWarning'` event and `process.emitWarning`. No-op for plaintext
@@ -2573,11 +2570,11 @@ var MllpClient = class extends events.EventEmitter {
2573
2570
  }
2574
2571
  /**
2575
2572
  * Wire a Connection's events through to this MllpClient. Every re-emitted
2576
- * payload is `Object.freeze`'d before emission (D-25), even though the
2573
+ * payload is `Object.freeze`'d before emission, even though the
2577
2574
  * Connection layer already freezes, defense-in-depth, harmless on
2578
2575
  * already-frozen objects.
2579
2576
  *
2580
- * Builds the unified `Correlator` (D-03/A1) bound to this Connection and
2577
+ * Builds the unified `Correlator` bound to this Connection and
2581
2578
  * arms the periodic ACK-timeout sweep. The Correlator is teardown-aware:
2582
2579
  * `close()` / `destroy()` clear the sweep timer and reject pending sends.
2583
2580
  *
@@ -2687,7 +2684,7 @@ var MllpClient = class extends events.EventEmitter {
2687
2684
  }
2688
2685
  }
2689
2686
  /**
2690
- * Arm (or re-arm) the dead-peer idle timer (Plan 05, CLIENT-08, D-11).
2687
+ * Arm (or re-arm) the dead-peer idle timer.
2691
2688
  * No-op when `deadPeerTimeoutMs` is unset.
2692
2689
  */
2693
2690
  _armDeadPeerTimer() {
@@ -2701,8 +2698,7 @@ var MllpClient = class extends events.EventEmitter {
2701
2698
  this._deadPeerTimer.unref();
2702
2699
  }
2703
2700
  /**
2704
- * Clear the dead-peer idle timer (Plan 05, D-14 timer cleanup on
2705
- * every transition out of CONNECTED).
2701
+ * Clear the dead-peer idle timer on every transition out of CONNECTED.
2706
2702
  */
2707
2703
  _clearDeadPeerTimer() {
2708
2704
  if (this._deadPeerTimer !== null) {
@@ -2711,22 +2707,22 @@ var MllpClient = class extends events.EventEmitter {
2711
2707
  }
2712
2708
  }
2713
2709
  /**
2714
- * Disconnect handler, Plan 04 reconnect FSM core.
2710
+ * Disconnect handler, reconnect FSM core.
2715
2711
  *
2716
2712
  * Implements:
2717
- * - CLIENT-17 hybrid in-flight handling (D-08): controlId mode preserves
2713
+ * - Hybrid in-flight handling: controlId mode preserves
2718
2714
  * pending sends for resend; FIFO mode rejects in-flight with
2719
2715
  * `connectionCause: 'in-flight-orphan'` and queued with `'fifo-unsafe'`.
2720
- * - CLIENT-18 classifier-first (Composition A, D-16): permanent errors
2716
+ * - Classifier-first: permanent errors
2721
2717
  * transition straight to CLOSED without invoking `retryStrategy`.
2722
- * - W-01 backoff-reset on recent success: first disconnect after a
2718
+ * - Backoff-reset on recent success: first disconnect after a
2723
2719
  * successful ACK on the prior session resets `_attempt` to 0.
2724
- * - W-02 `_reconnectAttempts` counter increment.
2725
- * - D-15 frozen RetryContext + D-17 null-return halts.
2726
- * - D-19 default exponential strategy.
2720
+ * - `_reconnectAttempts` counter increment.
2721
+ * - Frozen RetryContext; a `null` return from the strategy halts reconnection.
2722
+ * - Default exponential strategy.
2727
2723
  *
2728
- * Invoked from the SINGLE `_onStateChange` hook, no parallel listener
2729
- * (B-04). Idempotent across same-cycle re-entry: cycle-start flag
2724
+ * Invoked from the SINGLE `_onStateChange` hook, no parallel listener.
2725
+ * Idempotent across same-cycle re-entry: cycle-start flag
2730
2726
  * coordinates first-disconnect vs subsequent-within-cycle behavior.
2731
2727
  */
2732
2728
  _handleDisconnect(err) {
@@ -2826,7 +2822,7 @@ var MllpClient = class extends events.EventEmitter {
2826
2822
  this._backoffTimer.unref();
2827
2823
  }
2828
2824
  /**
2829
- * Default retry strategy (D-19): `min(maxDelay, initialDelay * multiplier^attempt)`
2825
+ * Default retry strategy: `min(maxDelay, initialDelay * multiplier^attempt)`
2830
2826
  * with ±jitter applied.
2831
2827
  */
2832
2828
  _defaultRetryStrategy = (ctx) => {
@@ -2922,7 +2918,7 @@ var MllpClient = class extends events.EventEmitter {
2922
2918
  this._reconnectFactory = factory;
2923
2919
  }
2924
2920
  /**
2925
- * Test seam, capture or rebind the connect-signal mid-flight (W-07).
2921
+ * Test seam, capture or rebind the connect-signal mid-flight.
2926
2922
  *
2927
2923
  * @internal
2928
2924
  */
@@ -2948,12 +2944,11 @@ var MllpClient = class extends events.EventEmitter {
2948
2944
  *
2949
2945
  * - FIFO mode: passes `null` controlId so `matchAck` returns the head of
2950
2946
  * the live store.
2951
- * - controlId mode: extracts MSA-2 at the `HOOK_EXTENSION_POINT: ack-payload`
2952
- * anchor and passes it to `matchAck` for keyed lookup.
2947
+ * - controlId mode: extracts MSA-2 and passes it to `matchAck` for keyed
2948
+ * lookup.
2953
2949
  *
2954
2950
  * Called from the SINGLE `'message'` listener registered in `_attachConnection`.
2955
- * No parallel listener is registered, downstream plans extend at the named
2956
- * anchor (B-04).
2951
+ * No parallel listener is registered.
2957
2952
  */
2958
2953
  _onAckPayload(ackPayload, byteOffset) {
2959
2954
  if (this._correlator === null) return;
@@ -2966,10 +2961,8 @@ var MllpClient = class extends events.EventEmitter {
2966
2961
  /**
2967
2962
  * Single source-of-truth for a successfully matched ACK (live-store hit).
2968
2963
  *
2969
- * PLAN-02: emit frozen 'ack' event, call matched.resolve().
2970
- * Plan 04 extends at HOOK_EXTENSION_POINT: ack-matched to update _lastSuccessAt.
2971
- * PLAN-06 extends at HOOK_EXTENSION_POINT: ack-matched to bump _ackedTotal and
2972
- * set _lastAckAt.
2964
+ * Emits the frozen 'ack' event and resolves the pending send. Updates
2965
+ * `_lastSuccessAt`, `_ackedTotal` and `_lastAckAt`.
2973
2966
  *
2974
2967
  * Called from _onAckPayload when matchAck() returns a non-null PendingAck.
2975
2968
  */
@@ -2991,7 +2984,7 @@ var MllpClient = class extends events.EventEmitter {
2991
2984
  }
2992
2985
  /**
2993
2986
  * Emit a frozen `'drain'` event when the queue depth and bytes fall below
2994
- * both configured caps (Plan 05, D-24). Called from `_onAckMatched`
2987
+ * both configured caps. Called from `_onAckMatched`
2995
2988
  * (every successful ACK) and from the Correlator's `onTimeout` callback
2996
2989
  * (every expired send), both code paths free a live-store slot.
2997
2990
  */
@@ -3013,12 +3006,9 @@ var MllpClient = class extends events.EventEmitter {
3013
3006
  /**
3014
3007
  * Single source-of-truth for Connection FSM transitions.
3015
3008
  *
3016
- * PLAN-02: re-emit frozen 'stateChange' (was inline in PLAN-01; centralized
3017
- * here so Plan 04 / Plan 05 can extend at named anchors).
3018
- * Plan 04 extends at HOOK_EXTENSION_POINT: state-change to detect
3019
- * CONNECTED → DISCONNECTED|RECONNECTING and trigger _handleDisconnect.
3020
- * Plan 05 extends at HOOK_EXTENSION_POINT: state-change to clear/arm
3021
- * dead-peer timer on transitions out of / into CONNECTED.
3009
+ * Re-emits a frozen 'stateChange' event, detects
3010
+ * CONNECTED → DISCONNECTED|RECONNECTING to trigger `_handleDisconnect`, and
3011
+ * clears or arms the dead-peer timer on transitions out of / into CONNECTED.
3022
3012
  *
3023
3013
  * Called from the SINGLE 'stateChange' listener registered in _attachConnection.
3024
3014
  */
@@ -3049,17 +3039,16 @@ var MllpClient = class extends events.EventEmitter {
3049
3039
  }
3050
3040
  }
3051
3041
  /**
3052
- * Send an MLLP-framed payload and await the inbound ACK (CLIENT-02).
3042
+ * Send an MLLP-framed payload and await the inbound ACK.
3053
3043
  *
3054
3044
  * Resolves with the ACK Buffer (framing stripped). Rejects with:
3055
- * - `DOMException('Aborted', 'AbortError')` if `signal` aborts before ACK
3056
- * (CLIENT-11 send branch).
3057
- * - `MllpTimeoutError` if no ACK arrives within `ackTimeoutMs` (ERR-02).
3045
+ * - `DOMException('Aborted', 'AbortError')` if `signal` aborts before the ACK.
3046
+ * - `MllpTimeoutError` if no ACK arrives within `ackTimeoutMs`.
3058
3047
  * The clock starts at the underlying `write()` flush callback, NOT at
3059
- * the `send()` call (CLIENT-04, D-19).
3048
+ * the `send()` call.
3060
3049
  * - `MllpConnectionError({ phase: 'send' })` if the client is not connected.
3061
3050
  *
3062
- * Emits a frozen `'ack'` event on every successful match (D-25 + Specifics).
3051
+ * Emits a frozen `'ack'` event on every successful match.
3063
3052
  *
3064
3053
  * @example
3065
3054
  * ```typescript
@@ -3068,7 +3057,7 @@ var MllpClient = class extends events.EventEmitter {
3068
3057
  * ```
3069
3058
  *
3070
3059
  * @param payload Raw bytes; MLLP framing is added internally via `encodeFrame`.
3071
- * @param opts.signal AbortSignal, aborting cancels the ACK wait (CLIENT-11).
3060
+ * @param opts.signal AbortSignal, aborting cancels the ACK wait.
3072
3061
  */
3073
3062
  send(payload, opts) {
3074
3063
  const signal = opts?.signal;
@@ -3156,12 +3145,12 @@ var MllpClient = class extends events.EventEmitter {
3156
3145
  });
3157
3146
  }
3158
3147
  /**
3159
- * 'wait'-mode backpressure handler (Plan 05, CLIENT-07/CLIENT-11).
3148
+ * 'wait'-mode backpressure handler.
3160
3149
  *
3161
3150
  * Awaits one of three terminating signals, in order:
3162
3151
  * - `'drain'` event → re-enter `send()` (the gate will now pass).
3163
3152
  * - `ackTimeoutMs` elapses → reject with `MllpTimeoutError`.
3164
- * - Caller's `signal` aborts → reject with `AbortError` (B-06). Cleanup
3153
+ * - Caller's `signal` aborts → reject with `AbortError`. Cleanup
3165
3154
  * removes the drain listener AND the abort listener AND clears the
3166
3155
  * timer to prevent leaks.
3167
3156
  */
@@ -3321,7 +3310,7 @@ var MllpClient = class extends events.EventEmitter {
3321
3310
  conn.destroy(reason);
3322
3311
  }
3323
3312
  /**
3324
- * Returns a JSON-serializable observability snapshot (OBS-01, D-26).
3313
+ * Returns a JSON-serializable observability snapshot.
3325
3314
  *
3326
3315
  * All fields are plain values, no Buffers, no class instances, no Maps,
3327
3316
  * no circular refs. Safe to `JSON.stringify` directly.
@@ -3423,7 +3412,7 @@ async function createStarterClient(opts) {
3423
3412
  }
3424
3413
 
3425
3414
  // src/index.ts
3426
- var VERSION = "0.0.2";
3415
+ var VERSION = "0.0.3";
3427
3416
 
3428
3417
  exports.Connection = Connection;
3429
3418
  exports.FrameReader = FrameReader;