@cosyte/mllp 0.0.1 → 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.
package/dist/index.mjs CHANGED
@@ -25,13 +25,13 @@ var MllpFramingError = class _MllpFramingError extends Error {
25
25
  /**
26
26
  * Up to 64 bytes copied from around the anomaly.
27
27
  *
28
- * This is a **copied** Buffer — isolated from the source buffer so it remains
28
+ * This is a **copied** Buffer, isolated from the source buffer so it remains
29
29
  * valid after the underlying buffer is reused or overwritten.
30
30
  *
31
- * **PHI contract (MLLP-9):** the decoder only ever populates this with the single
31
+ * **PHI contract:** the decoder only ever populates this with the single
32
32
  * framing-boundary byte that violated the frame structure (whose hex value the
33
- * `message` already discloses) — never a run of payload content bytes. For anomalies
34
- * whose fault is not a specific byte (`MLLP_FRAME_TOO_LARGE` — the accumulated size),
33
+ * `message` already discloses), never a run of payload content bytes. For anomalies
34
+ * whose fault is not a specific byte (`MLLP_FRAME_TOO_LARGE`, the accumulated size),
35
35
  * the snippet is **empty**: a payload slice on a public error field would leak a
36
36
  * field-body slice of clinical content. Callers constructing this directly are
37
37
  * responsible for the same discipline.
@@ -104,19 +104,19 @@ var FrameReader = class {
104
104
  _opts;
105
105
  _maxFrameSize;
106
106
  _state = "SCANNING_FOR_VT";
107
- /** Reusable accumulator buffer — grown by doubling as needed. */
107
+ /** Reusable accumulator buffer, grown by doubling as needed. */
108
108
  _accumulator = Buffer.allocUnsafe(INITIAL_ACCUMULATOR_SIZE);
109
109
  /** Number of payload bytes written to accumulator in current frame. */
110
110
  _writePos = 0;
111
111
  /** Monotonic absolute stream byte offset across the entire connection lifetime. */
112
112
  _byteOffset = 0;
113
- /** Byte offset where current leading-whitespace run started (FRAME-10). */
113
+ /** Byte offset where current leading-whitespace run started. */
114
114
  _wsStart = 0;
115
- /** Count of leading whitespace bytes accumulated in current run (FRAME-10). */
115
+ /** Count of leading whitespace bytes accumulated in current run. */
116
116
  _wsCount = 0;
117
117
  /** Byte offset of the VT byte that started the current frame. */
118
118
  _frameStartOffset = 0;
119
- /** Per-frame warning accumulator — cleared after each _deliverFrame(). */
119
+ /** Per-frame warning accumulator, cleared after each _deliverFrame(). */
120
120
  _frameWarnings = [];
121
121
  /**
122
122
  * Construct a chunked MLLP frame reader.
@@ -147,7 +147,7 @@ var FrameReader = class {
147
147
  /**
148
148
  * Clear internal accumulator state and reset byte offset to 0.
149
149
  *
150
- * Call on reconnect / connection reuse to start fresh without allocating a new reader (D-03).
150
+ * Call on reconnect / connection reuse to start fresh without allocating a new reader.
151
151
  * Pending partial frame state is discarded silently.
152
152
  *
153
153
  * @example
@@ -240,7 +240,7 @@ var FrameReader = class {
240
240
  this._emitWarning(
241
241
  "MLLP_MISSING_LEADING_VT",
242
242
  this._byteOffset,
243
- `Missing leading VT (0x0B) \u2014 treating byte 0x${byte.toString(16).padStart(2, "0")} at offset ${this._byteOffset} as payload start`
243
+ `Missing leading VT (0x0B), treating byte 0x${byte.toString(16).padStart(2, "0")} at offset ${this._byteOffset} as payload start`
244
244
  );
245
245
  this._frameStartOffset = this._byteOffset;
246
246
  this._state = "READING_PAYLOAD";
@@ -388,7 +388,7 @@ var FrameReader = class {
388
388
  }
389
389
  /**
390
390
  * Copy accumulated payload bytes into a new Buffer and deliver via `onFrame`.
391
- * The copy isolates callers from internal accumulator reuse (T-02-03-03).
391
+ * The copy isolates callers from internal accumulator reuse.
392
392
  */
393
393
  _deliverFrame() {
394
394
  const payload = Buffer.from(this._accumulator.subarray(0, this._writePos));
@@ -398,7 +398,7 @@ var FrameReader = class {
398
398
  this._frameWarnings = [];
399
399
  this._opts.onFrame(payload, frameStart, frameWarnings);
400
400
  }
401
- /** Emit a warning via the `onWarning` callback, swallowing any handler exceptions (WARN-06). */
401
+ /** Emit a warning via the `onWarning` callback, swallowing any handler exceptions. */
402
402
  _emitWarning(code, byteOffset, message) {
403
403
  const warning = createWarning(code, byteOffset, message);
404
404
  this._frameWarnings.push(warning);
@@ -485,8 +485,8 @@ var TlsTransport = class {
485
485
  this._socket.on("data", fn);
486
486
  }
487
487
  /**
488
- * See {@link Transport.onConnect}. Armed on `'secureConnect'` — the TLS
489
- * handshake-complete event — not the raw TCP `'connect'` event.
488
+ * See {@link Transport.onConnect}. Armed on `'secureConnect'`, the TLS
489
+ * handshake-complete event, not the raw TCP `'connect'` event.
490
490
  */
491
491
  onConnect(fn) {
492
492
  this._socket.removeAllListeners("secureConnect");
@@ -552,7 +552,7 @@ var LEGAL_TRANSITIONS = /* @__PURE__ */ new Map([
552
552
  ["CLOSED", /* @__PURE__ */ new Set()]
553
553
  ]);
554
554
  var Connection = class extends EventEmitter {
555
- /** Stable UUIDv4 identifier for this connection (D-11). */
555
+ /** Stable UUIDv4 identifier for this connection. */
556
556
  connectionId;
557
557
  _state = "CONNECTING";
558
558
  _transport;
@@ -565,20 +565,19 @@ var Connection = class extends EventEmitter {
565
565
  _bytesOut = 0;
566
566
  _lastByteInAt = null;
567
567
  _lastByteOutAt = null;
568
- /** Ring buffer: last MAX_WARNINGS entries (OBS-05). */
568
+ /** Ring buffer: last MAX_WARNINGS entries. */
569
569
  _warningBuffer = [];
570
- /** Accurate total counts per code — unaffected by ring buffer truncation (OBS-05). */
570
+ /** Accurate total counts per code, unaffected by ring buffer truncation. */
571
571
  _warningsByCode = /* @__PURE__ */ new Map();
572
- /** Set to true once the ring buffer overflows (OBS-05). */
572
+ /** Set to true once the ring buffer overflows. */
573
573
  _warningsTruncated = false;
574
574
  _onWarningFn = null;
575
575
  _drainPromise = null;
576
576
  /**
577
- * beforeClose hook — no-op default that resolves immediately.
577
+ * beforeClose hook, no-op default that resolves immediately.
578
578
  *
579
- * Phase 4 (Server) and Phase 5 (Client) override this instance property to
580
- * register ACK-drain and send-queue drain logic respectively (D-07/D-08).
581
- * Connection calls this during `close()`, racing against `drainTimeoutMs`.
579
+ * An owner may replace this instance property to run work before the socket
580
+ * closes. Connection calls it during `close()`, racing against `drainTimeoutMs`.
582
581
  */
583
582
  beforeClose = () => Promise.resolve();
584
583
  /**
@@ -625,7 +624,7 @@ var Connection = class extends EventEmitter {
625
624
  });
626
625
  }
627
626
  /**
628
- * Current FSM state. One of the 6 `ConnectionState` values (LIFE-01).
627
+ * Current FSM state. One of the 6 `ConnectionState` values.
629
628
  *
630
629
  * Subscribe to `'stateChange'` events for reactive state monitoring.
631
630
  */
@@ -633,10 +632,10 @@ var Connection = class extends EventEmitter {
633
632
  return this._state;
634
633
  }
635
634
  /**
636
- * Register or replace the per-connection warning subscriber (WARN-10).
635
+ * Register or replace the per-connection warning subscriber.
637
636
  *
638
637
  * Subsequent calls replace the previous handler (set-once semantics prevent leaks).
639
- * The handler is called synchronously and any exception it throws is swallowed (WARN-06).
638
+ * The handler is called synchronously and any exception it throws is swallowed.
640
639
  *
641
640
  * @example
642
641
  * ```typescript
@@ -674,7 +673,7 @@ var Connection = class extends EventEmitter {
674
673
  /**
675
674
  * Write raw bytes to the transport (no framing applied).
676
675
  *
677
- * Phase 4 (Server) and Phase 5 (Client) wrap this with `encodeFrame()` to add MLLP framing.
676
+ * The server and the client wrap this with `encodeFrame()` to add MLLP framing.
678
677
  * Returns `false` if the connection is CLOSED or DISCONNECTED (no bytes written).
679
678
  *
680
679
  * @returns `true` if bytes flushed immediately; `false` if buffered (backpressure) or not writable.
@@ -696,7 +695,7 @@ var Connection = class extends EventEmitter {
696
695
  * Initiate graceful close of the connection.
697
696
  *
698
697
  * - If `CONNECTING` or `RECONNECTING`: cancels the pending attempt, transitions
699
- * directly to `CLOSED`, and calls `transport.destroy()` (LIFE-05).
698
+ * directly to `CLOSED`, and calls `transport.destroy()`.
700
699
  * - If `CONNECTED`: transitions to `DRAINING`, calls `beforeClose(drainTimeoutMs)`,
701
700
  * then `DRAINING → DISCONNECTED` once the hook resolves, or `DRAINING → CLOSED`
702
701
  * if the drain timeout elapses first.
@@ -731,7 +730,7 @@ var Connection = class extends EventEmitter {
731
730
  * Race `beforeClose()` against the drain timeout.
732
731
  *
733
732
  * On normal completion: `DRAINING → DISCONNECTED` + `transport.close()`.
734
- * On timeout: `DRAINING → CLOSED` + `transport.destroy()` (T-03-04-01).
733
+ * On timeout: `DRAINING → CLOSED` + `transport.destroy()`.
735
734
  */
736
735
  async _drainWithTimeout(timeoutMs) {
737
736
  const drainPromise = this.beforeClose(timeoutMs);
@@ -758,7 +757,7 @@ var Connection = class extends EventEmitter {
758
757
  * Abruptly destroy the connection, discarding any pending writes.
759
758
  *
760
759
  * Transitions from any non-terminal state directly to `CLOSED` and calls
761
- * `transport.destroy(reason)`. Emits `'close'` event. Idempotent — safe to
760
+ * `transport.destroy(reason)`. Emits `'close'` event. Idempotent, safe to
762
761
  * call multiple times.
763
762
  *
764
763
  * @param reason - Optional error to propagate to the transport.
@@ -774,7 +773,7 @@ var Connection = class extends EventEmitter {
774
773
  this._transport.destroy(reason);
775
774
  }
776
775
  /**
777
- * Return a JSON-serializable observability snapshot (OBS-03/04/05).
776
+ * Return a JSON-serializable observability snapshot.
778
777
  *
779
778
  * All timestamp fields are `Date | null` (not epoch milliseconds). `JSON.stringify()`
780
779
  * serialises them to ISO 8601 strings with no information loss.
@@ -858,12 +857,12 @@ var Connection = class extends EventEmitter {
858
857
  * Node throws `ERR_UNHANDLED_ERROR` when `'error'` is emitted on an `EventEmitter` with no
859
858
  * listener. Every `'error'` emission in this class is reached from inside a transport callback
860
859
  * (the socket's `'data'`/`'error'` listener), so an unguarded emit would become an **uncaught
861
- * exception that kills the process** — the exact failure the containment above exists to
860
+ * exception that kills the process**, the exact failure the containment above exists to
862
861
  * prevent, merely relocated one frame up the stack.
863
862
  *
864
863
  * `Connection` is a public export and can legitimately be driven with no `'error'` listener
865
864
  * (`MllpServer` and `MllpClient` each attach one; a bare `Connection` need not). The connection
866
- * is still torn down and `'stateChange'`/`'close'` still fire, so a caller is never blind —
865
+ * is still torn down and `'stateChange'`/`'close'` still fire, so a caller is never blind,
867
866
  * they simply do not get the typed error object they never asked for. Mirrors
868
867
  * `MllpServer._emitErrorIfListened`.
869
868
  */
@@ -882,7 +881,7 @@ var Connection = class extends EventEmitter {
882
881
  * consumers keep the stable `code` and `byteOffset`), then **destroy this connection only**.
883
882
  *
884
883
  * Why destroy rather than resynchronize: once `push` has thrown, the reader's position within
885
- * the byte stream is no longer trustworthy — the next bytes could be the middle of a message.
884
+ * the byte stream is no longer trustworthy, the next bytes could be the middle of a message.
886
885
  * Guessing where the next frame starts is how a clinical message gets silently mis-split, so
887
886
  * the connection is dropped instead. A server drops that one peer and keeps serving everyone
888
887
  * else.
@@ -894,7 +893,7 @@ var Connection = class extends EventEmitter {
894
893
  * engine that is already unwell. A compatibility failure is not a network blip.
895
894
  *
896
895
  * If a peer's quirk is *expected* (trailing junk, keepalive bytes, a missing leading VT), the
897
- * decoder's tolerance opt-ins are the supported answer — they turn the throw into a warning.
896
+ * decoder's tolerance opt-ins are the supported answer, they turn the throw into a warning.
898
897
  */
899
898
  _onFatalFramingError(err) {
900
899
  if (this._state === "CLOSED") return;
@@ -908,13 +907,13 @@ var Connection = class extends EventEmitter {
908
907
  this.destroy(err);
909
908
  }
910
909
  /**
911
- * Backstop for a NON-framing throw escaping `FrameReader.push` — i.e. our own bug, or a
910
+ * Backstop for a NON-framing throw escaping `FrameReader.push`, i.e. our own bug, or a
912
911
  * subscriber's, rather than the peer's bytes.
913
912
  *
914
913
  * `_onFrameDecoded` already contains subscriber throws at the dispatch site, so this should be
915
914
  * unreachable. It exists because "unreachable" and "cannot kill the process from inside a
916
915
  * socket `'data'` handler" are different claims, and only the second one is safe to bet a
917
- * clinical interface on. Reported honestly as an internal receive error — never dressed up as
916
+ * clinical interface on. Reported honestly as an internal receive error, never dressed up as
918
917
  * a peer framing fault.
919
918
  */
920
919
  _onInternalReceiveError(err) {
@@ -990,9 +989,9 @@ var UNSAFE_FIELD_SEPARATORS = /* @__PURE__ */ new Set([
990
989
  SEGMENT_SEPARATOR_CR,
991
990
  SEGMENT_SEPARATOR_LF,
992
991
  11,
993
- // VT — MLLP start block
992
+ // VT, MLLP start block
994
993
  28
995
- // FS — MLLP end block
994
+ // FS, MLLP end block
996
995
  ]);
997
996
  function isMshSegmentAt(buf, i) {
998
997
  return i + 3 < buf.length && buf[i] === ASCII_M && buf[i + 1] === ASCII_S && buf[i + 2] === ASCII_H && !UNSAFE_FIELD_SEPARATORS.has(buf[i + 3]);
@@ -1225,13 +1224,13 @@ var MllpServer = class extends EventEmitter {
1225
1224
  _netServer;
1226
1225
  _connections = /* @__PURE__ */ new Set();
1227
1226
  _opts;
1228
- /** `true` when `ServerOptions.tls` is set — `_netServer` is actually a `tls.Server`. */
1227
+ /** `true` when `ServerOptions.tls` is set, `_netServer` is actually a `tls.Server`. */
1229
1228
  _isTls;
1230
1229
  _listening = false;
1231
- /** Phase 8 — single-flight guard: `true` while a `listen()` call is settling. */
1230
+ /** Single-flight guard: `true` while a `listen()` call is settling. */
1232
1231
  _listenInFlight = false;
1233
1232
  /**
1234
- * Phase 8 — settle hook for an in-flight `listen()`. Non-null only while a
1233
+ * Settle hook for an in-flight `listen()`. Non-null only while a
1235
1234
  * `listen()` is in flight; invoked by `close()` so a close racing startup
1236
1235
  * rejects the pending `listen()` (typed) instead of leaving it hung with
1237
1236
  * the single-flight guard stuck. Cleared on every settle path.
@@ -1241,7 +1240,7 @@ var MllpServer = class extends EventEmitter {
1241
1240
  _host = null;
1242
1241
  _acceptedTotal = 0;
1243
1242
  _closedTotal = 0;
1244
- /** Phase 8 — count of `'tlsClientError'` events since listen(). */
1243
+ /** Count of `'tlsClientError'` events since listen(). */
1245
1244
  _tlsClientErrorsTotal = 0;
1246
1245
  /**
1247
1246
  * Construct an MLLP server. Created idle; call `listen()` (or use
@@ -1304,23 +1303,23 @@ var MllpServer = class extends EventEmitter {
1304
1303
  * `Object.freeze({ port: actualPort, host: actualHost })`.
1305
1304
  *
1306
1305
  * **Single-flight:** one `listen()` per server lifecycle at a time. A call
1307
- * while the server is already listening — or while another `listen()` is
1308
- * still in flight — rejects with a typed `MllpConnectionError` (concurrent
1306
+ * while the server is already listening, or while another `listen()` is
1307
+ * still in flight, rejects with a typed `MllpConnectionError` (concurrent
1309
1308
  * binds raced each other's post-bind safety checks). Call `close()` before
1310
1309
  * re-listening; sequential `listen()` → `close()` → `listen()` is fine.
1311
1310
  *
1312
1311
  * **`close()` during an in-flight `listen()`** rejects that `listen()` with
1313
1312
  * a typed `MllpConnectionError` (never a hang) and clears the single-flight
1314
- * guard — a subsequent `listen()` on the same server works. This makes
1313
+ * guard, a subsequent `listen()` on the same server works. This makes
1315
1314
  * `Symbol.asyncDispose` (which delegates to `close()`) safe even before a
1316
1315
  * `listen()` has settled. (Exception: `close({ signal })` with an
1317
- * already-aborted signal is a no-op AbortError rejection — the in-flight
1316
+ * already-aborted signal is a no-op AbortError rejection, the in-flight
1318
1317
  * `listen()` is left to settle on its own bind outcome; see `close()`.)
1319
1318
  *
1320
1319
  * @param port - TCP port to bind. Use `0` to let the OS assign an ephemeral port.
1321
1320
  * @param hostOrOpts - Host string or object with `host` and optional `signal`.
1322
- * Default host: `'127.0.0.1'` (Phase 8 bind-safety hardening). Wildcard hosts
1323
- * are rejected unless `ServerOptions.allowWildcardBind: true` — literal
1321
+ * Default host: `'127.0.0.1'` (bind-safety hardening). Wildcard hosts
1322
+ * are rejected unless `ServerOptions.allowWildcardBind: true`, literal
1324
1323
  * spellings pre-bind, resolver-only shorthands post-bind via the
1325
1324
  * OS-normalized bound address.
1326
1325
  *
@@ -1340,7 +1339,7 @@ var MllpServer = class extends EventEmitter {
1340
1339
  if (this._listening || this._listenInFlight) {
1341
1340
  return Promise.reject(
1342
1341
  new MllpConnectionError(
1343
- this._listening ? "listen() rejected: server is already listening \u2014 call close() before re-listening" : "listen() rejected: another listen() is already in flight on this server",
1342
+ this._listening ? "listen() rejected: server is already listening, call close() before re-listening" : "listen() rejected: another listen() is already in flight on this server",
1344
1343
  {
1345
1344
  cause: new Error("listen already listening or in flight"),
1346
1345
  phase: "connect"
@@ -1351,7 +1350,7 @@ var MllpServer = class extends EventEmitter {
1351
1350
  if (isWildcardHost(host) && this._opts.allowWildcardBind !== true) {
1352
1351
  return Promise.reject(
1353
1352
  new MllpConnectionError(
1354
- `refusing to bind wildcard host '${host}' \u2014 set ServerOptions.allowWildcardBind: true to bind all interfaces`,
1353
+ `refusing to bind wildcard host '${host}', set ServerOptions.allowWildcardBind: true to bind all interfaces`,
1355
1354
  {
1356
1355
  cause: new Error("wildcard bind requires allowWildcardBind"),
1357
1356
  phase: "connect"
@@ -1430,7 +1429,7 @@ var MllpServer = class extends EventEmitter {
1430
1429
  {
1431
1430
  ok: false,
1432
1431
  error: new MllpConnectionError(
1433
- `refusing to bind wildcard host '${host}' (bound address '${actualHost}') \u2014 set ServerOptions.allowWildcardBind: true to bind all interfaces`,
1432
+ `refusing to bind wildcard host '${host}' (bound address '${actualHost}'), set ServerOptions.allowWildcardBind: true to bind all interfaces`,
1434
1433
  {
1435
1434
  cause: new Error("wildcard bind requires allowWildcardBind"),
1436
1435
  phase: "connect"
@@ -1457,7 +1456,7 @@ var MllpServer = class extends EventEmitter {
1457
1456
  }
1458
1457
  };
1459
1458
  const wildcardBound = isWildcardHost(actualHost);
1460
- const wildcardMessage = `MLLP server is bound to ALL network interfaces (host='${actualHost}') \u2014 set a specific bind address unless this is intentional.`;
1459
+ const wildcardMessage = `MLLP server is bound to ALL network interfaces (host='${actualHost}'), set a specific bind address unless this is intentional.`;
1461
1460
  if (wildcardBound) {
1462
1461
  process.emitWarning(wildcardMessage, { code: MLLP_BIND_ALL_INTERFACES });
1463
1462
  }
@@ -1485,19 +1484,19 @@ var MllpServer = class extends EventEmitter {
1485
1484
  /**
1486
1485
  * Stop accepting new connections and gracefully close all active connections.
1487
1486
  *
1488
- * Sequence (D-06):
1489
- * 1. `net.Server.close()` — stops accepting new connections immediately
1487
+ * Sequence:
1488
+ * 1. `net.Server.close()`, stops accepting new connections immediately
1490
1489
  * 2. If `_connections` is empty: resolves immediately (no drain needed)
1491
- * 3. Calls `_drainAll(drainTimeoutMs)` — Promise.all + side-effect setTimeout
1490
+ * 3. Calls `_drainAll(drainTimeoutMs)`, Promise.all + side-effect setTimeout
1492
1491
  * that force-destroys stragglers after the drain window
1493
1492
  *
1494
1493
  * Calling `close()` while a `listen()` is still in flight proactively
1495
1494
  * settles that `listen()` with a typed `MllpConnectionError` rejection
1496
- * and clears the single-flight guard — the server is immediately
1495
+ * and clears the single-flight guard, the server is immediately
1497
1496
  * re-listenable. `Symbol.asyncDispose` (which delegates here) is
1498
1497
  * therefore safe before `listen()` settles. **Qualification:** a
1499
1498
  * `close({ signal })` whose signal is **already aborted** rejects
1500
- * immediately with `AbortError` and performs no work — it does NOT close
1499
+ * immediately with `AbortError` and performs no work, it does NOT close
1501
1500
  * the server and does NOT settle the in-flight `listen()`, which simply
1502
1501
  * continues and settles on its own bind outcome.
1503
1502
  *
@@ -1549,7 +1548,7 @@ var MllpServer = class extends EventEmitter {
1549
1548
  /**
1550
1549
  * Drain all active connections with a shared timeout.
1551
1550
  *
1552
- * Uses Promise.all (not Promise.race) for coordination — the timeout is a
1551
+ * Uses Promise.all (not Promise.race) for coordination, the timeout is a
1553
1552
  * side effect that calls `conn.destroy()` on stragglers after `drainTimeoutMs`.
1554
1553
  * Promise.all resolves when all `conn.close()` promises settle (which happens
1555
1554
  * because `conn.destroy()` transitions connections to CLOSED).
@@ -1572,7 +1571,7 @@ var MllpServer = class extends EventEmitter {
1572
1571
  }
1573
1572
  }
1574
1573
  /**
1575
- * Async disposal — delegates to `close()` for `await using` support.
1574
+ * Async disposal, delegates to `close()` for `await using` support.
1576
1575
  *
1577
1576
  * @example
1578
1577
  * ```typescript
@@ -1585,10 +1584,9 @@ var MllpServer = class extends EventEmitter {
1585
1584
  return this.close();
1586
1585
  }
1587
1586
  /**
1588
- * Return a JSON-serializable observability snapshot (OBS-02).
1587
+ * Return a JSON-serializable observability snapshot.
1589
1588
  *
1590
1589
  * `totalBytesIn` and `totalBytesOut` aggregate from live connections at call time.
1591
- * Plan 04 adds full aggregation; at Plan 01 scope they return 0.
1592
1590
  *
1593
1591
  * @example
1594
1592
  * ```typescript
@@ -1619,7 +1617,7 @@ var MllpServer = class extends EventEmitter {
1619
1617
  };
1620
1618
  }
1621
1619
  /**
1622
- * Emit on `'error'` only when a listener is attached — an unlistened
1620
+ * Emit on `'error'` only when a listener is attached, an unlistened
1623
1621
  * `EventEmitter` `'error'` emission throws (see the class JSDoc error
1624
1622
  * contract). The single guard shared by the optional-tap forwarding sites
1625
1623
  * in this class; the constructor's net.Server forwarder deliberately does
@@ -1629,7 +1627,7 @@ var MllpServer = class extends EventEmitter {
1629
1627
  /**
1630
1628
  * Emit a server event, containing a throwing subscriber.
1631
1629
  *
1632
- * Every event this server emits is reachable from a callback we do not own — the `net.Server`
1630
+ * Every event this server emits is reachable from a callback we do not own, the `net.Server`
1633
1631
  * `'connection'` listener, the `tls.Server` `'tlsClientError'` listener, a socket's `'data'`
1634
1632
  * listener (via `Connection`), or the `catch` block of a `void`-ed async ACK task. A throwing
1635
1633
  * subscriber would therefore unwind into that callback and kill the process (or reject a void-ed
@@ -1734,8 +1732,8 @@ var MllpServer = class extends EventEmitter {
1734
1732
  );
1735
1733
  }
1736
1734
  /**
1737
- * Extract a minimal, content-free peer-certificate summary (Phase 8, ATNA
1738
- * ITI-19 mutual authentication) — CN strings, expiry, and the verification
1735
+ * Extract a minimal, content-free peer-certificate summary (ATNA ITI-19
1736
+ * mutual authentication), CN strings, expiry, and the verification
1739
1737
  * outcome (`authorized`) only; never the full certificate object. Returns
1740
1738
  * `null` when no peer certificate was presented (e.g. `clientAuth: 'WANT'`
1741
1739
  * with no client cert).
@@ -1753,7 +1751,7 @@ var MllpServer = class extends EventEmitter {
1753
1751
  subjectCN: asCn(cert.subject?.CN),
1754
1752
  issuerCN: asCn(cert.issuer?.CN),
1755
1753
  validTo: cert.valid_to ?? null,
1756
- // Verification outcome — under 'WANT' a certificate can be present yet
1754
+ // Verification outcome, under 'WANT' a certificate can be present yet
1757
1755
  // UNVERIFIED (see PeerCertificateSummary.authorized JSDoc).
1758
1756
  authorized: socket.authorized === true
1759
1757
  });
@@ -1765,12 +1763,12 @@ var MllpServer = class extends EventEmitter {
1765
1763
  * then dispatches: resolve ⇒ `AA`; throw/reject ⇒ a negative ACK (`AE` by default,
1766
1764
  * `AR` via {@link MllpAckError}). A positive ACK can never precede a successful commit.
1767
1765
  *
1768
- * Without an `onMessage` handler, `'AA'` degrades to a **transport-accept** — `AA`
1766
+ * Without an `onMessage` handler, `'AA'` degrades to a **transport-accept**, `AA`
1769
1767
  * meaning "bytes received and framed", not "application-processed".
1770
1768
  *
1771
1769
  * A handler failure is **expected flow**, not a server error: it produces a negative
1772
1770
  * ACK and a `'nack'` event. The thrown error's message is never placed on the wire or
1773
- * in the event (it may carry PHI) — only the static `ackCode` and the inbound control
1771
+ * in the event (it may carry PHI), only the static `ackCode` and the inbound control
1774
1772
  * metadata reach the peer.
1775
1773
  */
1776
1774
  async _sendCommitAck(payload, meta, conn) {
@@ -1802,18 +1800,18 @@ var MllpServer = class extends EventEmitter {
1802
1800
  }
1803
1801
  /**
1804
1802
  * Resolve the auto-ACK code for a message the server would otherwise acknowledge
1805
- * **positively** (`AA`) — the no-handler transport-accept and the post-commit success
1803
+ * **positively** (`AA`), the no-handler transport-accept and the post-commit success
1806
1804
  * paths. Fail-safe: downgrade to `AE` and emit a PHI-safe `'nack'` whenever the message
1807
1805
  * cannot carry a correlatable positive ACK, so `AA` never names a control ID the sender
1808
1806
  * cannot match (→ timeout → resend → **duplicate clinical message**).
1809
1807
  *
1810
1808
  * Two independent disqualifiers, one from the bytes and one from the frame:
1811
1809
  *
1812
- * - **`rawAckUncorrelatable(payload)`** — no readable `MSH`, an empty MSH-10, or a
1810
+ * - **`rawAckUncorrelatable(payload)`**, no readable `MSH`, an empty MSH-10, or a
1813
1811
  * batch/concatenated-message shape. This is the SAME predicate `buildRawAck` enforces
1814
1812
  * on the wire; it is re-checked here so the downgrade is **observable** (a `'nack'`
1815
1813
  * event) rather than a silent code change inside the builder.
1816
- * - **`MLLP_TRAILING_BYTES`** in the frame's warnings — a mid-payload `VT` made the
1814
+ * - **`MLLP_TRAILING_BYTES`** in the frame's warnings, a mid-payload `VT` made the
1817
1815
  * decoder discard accumulated bytes and deliver only the fragment after it. The
1818
1816
  * clinical message was destroyed in transit, so even a fragment that happens to carry
1819
1817
  * a readable MSH must not be positively acknowledged. This condition is invisible to
@@ -1822,7 +1820,7 @@ var MllpServer = class extends EventEmitter {
1822
1820
  * accumulating the delivered frame, so it is frame-scoped: it names *this* payload's own
1823
1821
  * discard, never a neighbouring frame's trailing junk.
1824
1822
  *
1825
- * `'discarded-bytes'` takes precedence in the reason when both hold — it is the root cause.
1823
+ * `'discarded-bytes'` takes precedence in the reason when both hold, it is the root cause.
1826
1824
  */
1827
1825
  _resolveAutoAckPositive(payload, meta, conn) {
1828
1826
  const discarded = meta.warnings.some((w) => w.code === "MLLP_TRAILING_BYTES");
@@ -1843,7 +1841,7 @@ var MllpServer = class extends EventEmitter {
1843
1841
  * Run `onMessage` for its side effects only (custom-ACK and manual modes), guarding
1844
1842
  * against a synchronous throw or a rejected promise. In these modes the handler does
1845
1843
  * **not** gate the ACK, so a failure is re-emitted as a PHI-safe `'error'` on the
1846
- * connection (D-04: a handler error never crashes the server) rather than escaping as
1844
+ * connection (a handler error never crashes the server) rather than escaping as
1847
1845
  * an unhandled rejection. The error text is never placed on the wire.
1848
1846
  */
1849
1847
  _observeMessage(payload, meta, conn) {
@@ -1857,7 +1855,7 @@ var MllpServer = class extends EventEmitter {
1857
1855
  /**
1858
1856
  * The custom-builder path for `autoAck: fn`. Awaits the builder and dispatches its
1859
1857
  * Buffer as the ACK; the caller owns MSA-1. A builder error is re-emitted as `'error'`
1860
- * on the connection — the server never crashes (D-04).
1858
+ * on the connection, the server never crashes.
1861
1859
  */
1862
1860
  async _sendCustomAck(fn, payload, meta, conn) {
1863
1861
  try {
@@ -1871,7 +1869,7 @@ var MllpServer = class extends EventEmitter {
1871
1869
  /**
1872
1870
  * Frame an ACK payload and write it to the connection. `Connection.send()` returns
1873
1871
  * `false` under backpressure (socket write buffer full); that drops the ACK and emits
1874
- * a `MllpConnectionError({ phase: 'send' })` on the connection (D-04) — the peer will
1872
+ * a `MllpConnectionError({ phase: 'send' })` on the connection, the peer will
1875
1873
  * time out waiting and may retry. The server never crashes.
1876
1874
  */
1877
1875
  _dispatchAck(conn, ackPayload) {
@@ -1936,7 +1934,7 @@ var Correlator = class {
1936
1934
  _sendSeq = 0;
1937
1935
  _queueBytes = 0;
1938
1936
  /**
1939
- * PLAN-06 — count of pending entries with `sentAt !== null` (D-26 / B-01).
1937
+ * Count of pending entries with `sentAt !== null`.
1940
1938
  * Maintained at every site that mutates `entry.sentAt` or removes a
1941
1939
  * flushed entry: `markFlushed`, `remove`, `matchAck`, `expireDue`, `clear`.
1942
1940
  */
@@ -1972,7 +1970,7 @@ var Correlator = class {
1972
1970
  /**
1973
1971
  * Enqueue a new send awaiting its ACK. Returns the assigned
1974
1972
  * `correlationKey`, or `null` if `maxInFlight` is reached (caller awaits
1975
- * drain — PLAN-05's `pipeline:false`).
1973
+ * drain, `pipeline:false`).
1976
1974
  */
1977
1975
  enqueue(frame, controlIdOrNull, resolve, reject) {
1978
1976
  if (this._pending.size >= this._opts.maxInFlight) return null;
@@ -1991,7 +1989,7 @@ var Correlator = class {
1991
1989
  return key;
1992
1990
  }
1993
1991
  /**
1994
- * Record write-flush timestamp (CLIENT-04 — clock starts at flush, NOT
1992
+ * Record write-flush timestamp (the clock starts at flush, NOT
1995
1993
  * at `send()` call). No-op if key is unknown (e.g. removed by abort).
1996
1994
  */
1997
1995
  markFlushed(key, now) {
@@ -2007,16 +2005,16 @@ var Correlator = class {
2007
2005
  * removed from live store. Caller calls `entry.resolve(ackPayload)`.
2008
2006
  * - controlId: keyed lookup by `controlIdFromAck`. Live-store hit returns
2009
2007
  * the entry; graveyard hit fires `MLLP_ACK_AFTER_TIMEOUT` warning
2010
- * (CLIENT-16, D-04) and returns `null`; otherwise fires
2011
- * `onUnmatchedAck(controlIdFromAck)` (CLIENT-15, D-05) and returns `null`.
2008
+ * and returns `null`; otherwise fires
2009
+ * `onUnmatchedAck(controlIdFromAck)` and returns `null`.
2012
2010
  *
2013
- * Triggers lazy graveyard eviction (D-04).
2011
+ * Triggers lazy graveyard eviction.
2014
2012
  *
2015
2013
  * @param _payload Inbound ACK bytes (framing stripped). MSA-2 extraction
2016
2014
  * happens at MllpClient's `_onAckPayload` hook; this method takes the
2017
2015
  * already-extracted control ID as a parameter.
2018
2016
  * @param controlIdFromAck MSA-2 extracted from ACK (controlId mode only).
2019
- * @param byteOffsetFromAck Stream offset; forwarded to `onWarning` (W-05).
2017
+ * @param byteOffsetFromAck Stream offset; forwarded to `onWarning`.
2020
2018
  */
2021
2019
  matchAck(_payload, controlIdFromAck = null, byteOffsetFromAck = 0) {
2022
2020
  this._evictGraveyardDue(this._opts.now());
@@ -2060,9 +2058,9 @@ var Correlator = class {
2060
2058
  }
2061
2059
  /**
2062
2060
  * Sweep live entries; expire those past `sentAt + ackTimeoutMs`.
2063
- * Fires `onTimeout(entry, elapsedMs)`; entries move to graveyard (D-04).
2064
- * Driven externally by `MllpClient`'s periodic sweep tick — Correlator
2065
- * itself owns no timers (D-03).
2061
+ * Fires `onTimeout(entry, elapsedMs)`; entries move to graveyard.
2062
+ * Driven externally by `MllpClient`'s periodic sweep tick, Correlator
2063
+ * itself owns no timers.
2066
2064
  */
2067
2065
  expireDue(now) {
2068
2066
  const t = now ?? this._opts.now();
@@ -2084,8 +2082,7 @@ var Correlator = class {
2084
2082
  /**
2085
2083
  * Reject every live entry with `reason` (insertion order) and clear
2086
2084
  * the live store. Graveyard is left intact (ages out via lazy eviction).
2087
- * Used by FIFO reconnect-reject (D-07 — PLAN-04 wraps in MllpConnectionError)
2088
- * and `MllpClient.close()` to cancel pending sends.
2085
+ * Used by `MllpClient`'s correlator teardown to cancel pending sends.
2089
2086
  */
2090
2087
  clear(reason) {
2091
2088
  for (const entry of this._pending.values()) entry.reject(reason);
@@ -2093,14 +2090,14 @@ var Correlator = class {
2093
2090
  this._queueBytes = 0;
2094
2091
  this._inFlight = 0;
2095
2092
  }
2096
- /** Iterate live entries in insertion order (PLAN-04 reconnect-resend, D-07). */
2093
+ /** Iterate live entries in insertion order (reconnect-resend). */
2097
2094
  *liveEntries() {
2098
2095
  for (const entry of this._pending.values()) yield entry;
2099
2096
  }
2100
2097
  /**
2101
2098
  * Remove a live entry by key WITHOUT resolving/rejecting. Returns the
2102
2099
  * removed entry, or `null` if no entry with that key exists.
2103
- * Used by `MllpClient.send()` for AbortSignal cleanup and PLAN-04's
2100
+ * Used by `MllpClient.send()` for AbortSignal cleanup and by the
2104
2101
  * reconnect-reject FSM walk.
2105
2102
  */
2106
2103
  remove(key) {
@@ -2121,7 +2118,7 @@ var Correlator = class {
2121
2118
  inFlight: this._inFlight
2122
2119
  };
2123
2120
  }
2124
- /** Lazy graveyard eviction (D-04): drop entries past `timedOutAt + 2 * ackTimeoutMs`. */
2121
+ /** Lazy graveyard eviction: drop entries past `timedOutAt + 2 * ackTimeoutMs`. */
2125
2122
  _evictGraveyardDue(now) {
2126
2123
  const threshold = 2 * this._opts.ackTimeoutMs;
2127
2124
  for (const [key, entry] of this._graveyard) {
@@ -2214,7 +2211,7 @@ var MllpBackpressureError = class _MllpBackpressureError extends Error {
2214
2211
  queueDepth;
2215
2212
  /** Total bytes of in-flight + queued frames at the moment of rejection. */
2216
2213
  queueBytes;
2217
- /** The high-water-mark configuration that was triggered (D-23). */
2214
+ /** The high-water-mark configuration that was triggered. */
2218
2215
  highWaterMark;
2219
2216
  /**
2220
2217
  * Construct an MLLP backpressure error.
@@ -2244,15 +2241,15 @@ var MllpClient = class extends EventEmitter {
2244
2241
  * is attached, `state` mirrors `_connection.state`.
2245
2242
  */
2246
2243
  _state = "DISCONNECTED";
2247
- /** Per-message ACK timeout in ms (CLIENT-04). Resolved at construction. */
2244
+ /** Per-message ACK timeout in ms. Resolved at construction. */
2248
2245
  _ackTimeoutMs;
2249
- /** controlId-mode flag (CLIENT-03 branch). `false` → FIFO. */
2246
+ /** controlId-mode flag. `false` → FIFO. */
2250
2247
  _correlateByControlId;
2251
- /** Unified ACK correlator (D-03/A1). Built during `_attachConnection`. */
2248
+ /** Unified ACK correlator. Built during `_attachConnection`. */
2252
2249
  _correlator = null;
2253
2250
  /**
2254
2251
  * Periodic ACK-timeout sweep timer. Drives `_correlator.expireDue()` because
2255
- * the Correlator is timer-free per D-03. Cleared on close/destroy.
2252
+ * the Correlator is timer-free. Cleared on close/destroy.
2256
2253
  */
2257
2254
  _ackSweepTimer = null;
2258
2255
  // ── Reconnect state (Plan 04, CLIENT-05/06/12/17/18) ─────────────────────
@@ -2265,12 +2262,12 @@ var MllpClient = class extends EventEmitter {
2265
2262
  /** 0-indexed attempt counter for the current reconnect cycle. */
2266
2263
  _attempt = 0;
2267
2264
  /**
2268
- * W-02 — total reconnect attempts since construction. Read by PLAN-06 for
2265
+ * Total reconnect attempts since construction, surfaced as
2269
2266
  * `getStats().reconnectAttempts`. Incremented at the entry of every
2270
2267
  * `_handleDisconnect` invocation that proceeds to schedule a backoff.
2271
2268
  */
2272
2269
  _reconnectAttempts = 0;
2273
- /** Epoch ms of the last successful ACK. Drives W-01 backoff-reset. */
2270
+ /** Epoch ms of the last successful ACK. Drives backoff-reset. */
2274
2271
  _lastSuccessAt = null;
2275
2272
  /** Epoch ms when the current reconnect cycle began. `null` outside a cycle. */
2276
2273
  _reconnectCycleStartedAt = null;
@@ -2287,12 +2284,12 @@ var MllpClient = class extends EventEmitter {
2287
2284
  _onBackpressure;
2288
2285
  /** Pipeline flag; default `true` (parallel up to highWaterMark). */
2289
2286
  _pipeline;
2290
- /** Dead-peer idle timer (Plan 05 — D-11). `null` when not armed. */
2287
+ /** Dead-peer idle timer. `null` when not armed. */
2291
2288
  _deadPeerTimer = null;
2292
2289
  /** True once the self-'ack' listener that resets the dead-peer timer
2293
2290
  * has been attached. Guards against duplicate listeners on reconnect. */
2294
2291
  _ackResetWired = false;
2295
- /** Most recently bound `connect()` signal. Reread on every RetryContext build (W-07). */
2292
+ /** Most recently bound `connect()` signal. Reread on every RetryContext build. */
2296
2293
  _connectSignal;
2297
2294
  /** Set when close()/destroy()/abort fires; reconnect handler short-circuits. */
2298
2295
  _userClosed = false;
@@ -2301,13 +2298,13 @@ var MllpClient = class extends EventEmitter {
2301
2298
  /** Listener-removal handle for the abort listener bound in connect(). */
2302
2299
  _abortListener = null;
2303
2300
  /**
2304
- * Test-only seam — when set, `_beginReconnectAttempt` builds the new
2301
+ * Test-only seam, when set, `_beginReconnectAttempt` builds the new
2305
2302
  * Connection through this factory instead of opening a real net.Socket.
2306
2303
  *
2307
2304
  * @internal
2308
2305
  */
2309
2306
  _reconnectFactory = null;
2310
- // ── PLAN-06 — observability counters for getStats (OBS-01, D-26) ─────────
2307
+ // ── PLAN-06, observability counters for getStats (OBS-01, D-26) ─────────
2311
2308
  /** Total successful `conn.send()` flushes since construction. */
2312
2309
  _sentTotal = 0;
2313
2310
  /** Total ACKs resolved since construction. */
@@ -2321,7 +2318,7 @@ var MllpClient = class extends EventEmitter {
2321
2318
  /**
2322
2319
  * Aggregated Correlator-emitted warning counts (MLLP_ACK_*). Connection-level
2323
2320
  * warnings are read directly from `_connection.getStats().warningsByCode`
2324
- * at observation time and merged into the snapshot (D-26).
2321
+ * at observation time and merged into the snapshot.
2325
2322
  */
2326
2323
  _aggregatedWarningsByCode = {};
2327
2324
  /**
@@ -2361,9 +2358,9 @@ var MllpClient = class extends EventEmitter {
2361
2358
  return this._connection?.state ?? this._state;
2362
2359
  }
2363
2360
  /**
2364
- * Open a TCP (or TLS — Phase 8) connection to the configured `host:port`
2365
- * and attach a Phase 3 {@link Connection} to it. Resolves once the FSM
2366
- * enters `CONNECTED` — for TLS, on `'secureConnect'` (handshake complete,
2361
+ * Open a TCP (or TLS) connection to the configured `host:port`
2362
+ * and attach a {@link Connection} to it. Resolves once the FSM
2363
+ * enters `CONNECTED`, for TLS, on `'secureConnect'` (handshake complete,
2367
2364
  * including certificate verification when it is on).
2368
2365
  *
2369
2366
  * Rejects with:
@@ -2383,11 +2380,11 @@ var MllpClient = class extends EventEmitter {
2383
2380
  *
2384
2381
  * **TLS 1.3 + mutual TLS caveat (RFC 8446 §4.4.2):** `connect()` resolving
2385
2382
  * does NOT guarantee that a `clientAuth: 'MUST'` server accepted your
2386
- * client certificate. Under TLS 1.3 the client's handshake — and its
2387
- * `'secureConnect'` — can complete before the server finishes validating
2383
+ * client certificate. Under TLS 1.3 the client's handshake, and its
2384
+ * `'secureConnect'`, can complete before the server finishes validating
2388
2385
  * the certificate; a rejection then surfaces moments later as a typed
2389
2386
  * post-connect error (`'error'` event with an `ERR_SSL_*`/alert cause,
2390
- * classified **permanent** — no auto-reconnect loop). ACK correlation via
2387
+ * classified **permanent**, no auto-reconnect loop). ACK correlation via
2391
2388
  * {@link MllpClient.send} remains the delivery guarantee: no send resolves
2392
2389
  * without its ACK, so a rejected session can never silently "deliver".
2393
2390
  *
@@ -2470,8 +2467,8 @@ var MllpClient = class extends EventEmitter {
2470
2467
  * Build the raw socket + `Transport` pair for a connect / reconnect attempt.
2471
2468
  *
2472
2469
  * Plaintext (`ClientOptions.tls` unset): a `net.Socket` wrapped in
2473
- * `NetTransport`. TLS (Phase 8): a `tls.TLSSocket` wrapped in
2474
- * `TlsTransport` — verification defaults **on**
2470
+ * `NetTransport`. TLS: a `tls.TLSSocket` wrapped in
2471
+ * `TlsTransport`, verification defaults **on**
2475
2472
  * (`rejectUnauthorized: !allowUnverified`), floor `minVersion: 'TLSv1.2'`
2476
2473
  * (the IHE ATNA ITI-19 BCP195 floor), `servername` defaulting to
2477
2474
  * `ClientOptions.host`.
@@ -2500,14 +2497,14 @@ var MllpClient = class extends EventEmitter {
2500
2497
  }
2501
2498
  /**
2502
2499
  * Wrap a connect-phase socket error as `MllpConnectionError`, classifying
2503
- * TLS failures (Phase 8) into the additive `connectionCause`:
2500
+ * TLS failures into the additive `connectionCause`:
2504
2501
  *
2505
- * - `'tls-verify'` — certificate-verification failures
2502
+ * - `'tls-verify'`, certificate-verification failures
2506
2503
  * ({@link isTlsVerificationErrorCode}).
2507
- * - `'tls-handshake'` — TLS-**protocol**-shaped failures only
2504
+ * - `'tls-handshake'`, TLS-**protocol**-shaped failures only
2508
2505
  * ({@link isTlsProtocolError}): `ERR_SSL_*`, `EPROTO`, OpenSSL
2509
2506
  * alert-bearing errors.
2510
- * - **No `connectionCause`** — pure TCP-level failures (`ECONNREFUSED`,
2507
+ * - **No `connectionCause`**, pure TCP-level failures (`ECONNREFUSED`,
2511
2508
  * `ETIMEDOUT`, …) even on a TLS-configured connection; these carry the
2512
2509
  * same shape as plaintext connect failures.
2513
2510
  */
@@ -2535,7 +2532,7 @@ var MllpClient = class extends EventEmitter {
2535
2532
  /**
2536
2533
  * Emit a client event, containing a throwing subscriber.
2537
2534
  *
2538
- * Every event this client emits is reached from a callback we do not own — a socket's
2535
+ * Every event this client emits is reached from a callback we do not own, a socket's
2539
2536
  * `'connect'`/`'secureConnect'`/`'data'`/`'error'` listener, or a backoff timer. A throwing
2540
2537
  * subscriber would unwind into it and kill the process, and on several paths it would also skip
2541
2538
  * the work queued after the emit (the `resolve()` of `connect()`, the backoff scheduling).
@@ -2548,8 +2545,8 @@ var MllpClient = class extends EventEmitter {
2548
2545
  });
2549
2546
  }
2550
2547
  /**
2551
- * Emit the per-connection insecure-TLS warning (Phase 8) when
2552
- * `tls.allowUnverified === true` — fires on EVERY successful
2548
+ * Emit the per-connection insecure-TLS warning when
2549
+ * `tls.allowUnverified === true`, fires on EVERY successful
2553
2550
  * `secureConnect`, initial connect and every reconnect. Emits both a frozen
2554
2551
  * `'securityWarning'` event and `process.emitWarning`. No-op for plaintext
2555
2552
  * connections or when verification is on.
@@ -2558,7 +2555,7 @@ var MllpClient = class extends EventEmitter {
2558
2555
  const tlsOpt = this._opts.tls;
2559
2556
  if (tlsOpt === void 0 || tlsOpt === true) return;
2560
2557
  if (tlsOpt.allowUnverified !== true) return;
2561
- const message = "MLLP TLS certificate verification is DISABLED (allowUnverified: true) \u2014 this connection does not authenticate the peer.";
2558
+ const message = "MLLP TLS certificate verification is DISABLED (allowUnverified: true), this connection does not authenticate the peer.";
2562
2559
  const warning = Object.freeze({
2563
2560
  code: MLLP_TLS_VERIFY_DISABLED,
2564
2561
  message,
@@ -2571,11 +2568,11 @@ var MllpClient = class extends EventEmitter {
2571
2568
  }
2572
2569
  /**
2573
2570
  * Wire a Connection's events through to this MllpClient. Every re-emitted
2574
- * payload is `Object.freeze`'d before emission (D-25), even though the
2575
- * Connection layer already freezes — defense-in-depth, harmless on
2571
+ * payload is `Object.freeze`'d before emission, even though the
2572
+ * Connection layer already freezes, defense-in-depth, harmless on
2576
2573
  * already-frozen objects.
2577
2574
  *
2578
- * Builds the unified `Correlator` (D-03/A1) bound to this Connection and
2575
+ * Builds the unified `Correlator` bound to this Connection and
2579
2576
  * arms the periodic ACK-timeout sweep. The Correlator is teardown-aware:
2580
2577
  * `close()` / `destroy()` clear the sweep timer and reject pending sends.
2581
2578
  *
@@ -2586,7 +2583,7 @@ var MllpClient = class extends EventEmitter {
2586
2583
  this._correlator = new Correlator({
2587
2584
  mode: this._correlateByControlId ? "controlId" : "fifo",
2588
2585
  ackTimeoutMs: this._ackTimeoutMs,
2589
- // Plan 05 — pipeline:false collapses the in-flight set to ≤1 (D-06).
2586
+ // Plan 05, pipeline:false collapses the in-flight set to ≤1 (D-06).
2590
2587
  maxInFlight: this._pipeline ? Number.POSITIVE_INFINITY : 1,
2591
2588
  onWarning: (code, ctx) => {
2592
2589
  this._aggregatedWarningsByCode[code] = (this._aggregatedWarningsByCode[code] ?? 0) + 1;
@@ -2685,7 +2682,7 @@ var MllpClient = class extends EventEmitter {
2685
2682
  }
2686
2683
  }
2687
2684
  /**
2688
- * Arm (or re-arm) the dead-peer idle timer (Plan 05 — CLIENT-08, D-11).
2685
+ * Arm (or re-arm) the dead-peer idle timer.
2689
2686
  * No-op when `deadPeerTimeoutMs` is unset.
2690
2687
  */
2691
2688
  _armDeadPeerTimer() {
@@ -2699,8 +2696,7 @@ var MllpClient = class extends EventEmitter {
2699
2696
  this._deadPeerTimer.unref();
2700
2697
  }
2701
2698
  /**
2702
- * Clear the dead-peer idle timer (Plan 05 — D-14 timer cleanup on
2703
- * every transition out of CONNECTED).
2699
+ * Clear the dead-peer idle timer on every transition out of CONNECTED.
2704
2700
  */
2705
2701
  _clearDeadPeerTimer() {
2706
2702
  if (this._deadPeerTimer !== null) {
@@ -2709,22 +2705,22 @@ var MllpClient = class extends EventEmitter {
2709
2705
  }
2710
2706
  }
2711
2707
  /**
2712
- * Disconnect handler — Plan 04 reconnect FSM core.
2708
+ * Disconnect handler, reconnect FSM core.
2713
2709
  *
2714
2710
  * Implements:
2715
- * - CLIENT-17 hybrid in-flight handling (D-08): controlId mode preserves
2711
+ * - Hybrid in-flight handling: controlId mode preserves
2716
2712
  * pending sends for resend; FIFO mode rejects in-flight with
2717
2713
  * `connectionCause: 'in-flight-orphan'` and queued with `'fifo-unsafe'`.
2718
- * - CLIENT-18 classifier-first (Composition A — D-16): permanent errors
2714
+ * - Classifier-first: permanent errors
2719
2715
  * transition straight to CLOSED without invoking `retryStrategy`.
2720
- * - W-01 backoff-reset on recent success: first disconnect after a
2716
+ * - Backoff-reset on recent success: first disconnect after a
2721
2717
  * successful ACK on the prior session resets `_attempt` to 0.
2722
- * - W-02 `_reconnectAttempts` counter increment.
2723
- * - D-15 frozen RetryContext + D-17 null-return halts.
2724
- * - D-19 default exponential strategy.
2718
+ * - `_reconnectAttempts` counter increment.
2719
+ * - Frozen RetryContext; a `null` return from the strategy halts reconnection.
2720
+ * - Default exponential strategy.
2725
2721
  *
2726
- * Invoked from the SINGLE `_onStateChange` hook — no parallel listener
2727
- * (B-04). Idempotent across same-cycle re-entry: cycle-start flag
2722
+ * Invoked from the SINGLE `_onStateChange` hook, no parallel listener.
2723
+ * Idempotent across same-cycle re-entry: cycle-start flag
2728
2724
  * coordinates first-disconnect vs subsequent-within-cycle behavior.
2729
2725
  */
2730
2726
  _handleDisconnect(err) {
@@ -2824,7 +2820,7 @@ var MllpClient = class extends EventEmitter {
2824
2820
  this._backoffTimer.unref();
2825
2821
  }
2826
2822
  /**
2827
- * Default retry strategy (D-19): `min(maxDelay, initialDelay * multiplier^attempt)`
2823
+ * Default retry strategy: `min(maxDelay, initialDelay * multiplier^attempt)`
2828
2824
  * with ±jitter applied.
2829
2825
  */
2830
2826
  _defaultRetryStrategy = (ctx) => {
@@ -2912,7 +2908,7 @@ var MllpClient = class extends EventEmitter {
2912
2908
  this._reconnectCycleStartedAt = null;
2913
2909
  }
2914
2910
  /**
2915
- * Test seam — install a factory that produces the next reconnect Connection.
2911
+ * Test seam, install a factory that produces the next reconnect Connection.
2916
2912
  *
2917
2913
  * @internal
2918
2914
  */
@@ -2920,7 +2916,7 @@ var MllpClient = class extends EventEmitter {
2920
2916
  this._reconnectFactory = factory;
2921
2917
  }
2922
2918
  /**
2923
- * Test seam — capture or rebind the connect-signal mid-flight (W-07).
2919
+ * Test seam, capture or rebind the connect-signal mid-flight.
2924
2920
  *
2925
2921
  * @internal
2926
2922
  */
@@ -2946,12 +2942,11 @@ var MllpClient = class extends EventEmitter {
2946
2942
  *
2947
2943
  * - FIFO mode: passes `null` controlId so `matchAck` returns the head of
2948
2944
  * the live store.
2949
- * - controlId mode: extracts MSA-2 at the `HOOK_EXTENSION_POINT: ack-payload`
2950
- * anchor and passes it to `matchAck` for keyed lookup.
2945
+ * - controlId mode: extracts MSA-2 and passes it to `matchAck` for keyed
2946
+ * lookup.
2951
2947
  *
2952
2948
  * Called from the SINGLE `'message'` listener registered in `_attachConnection`.
2953
- * No parallel listener is registered — downstream plans extend at the named
2954
- * anchor (B-04).
2949
+ * No parallel listener is registered.
2955
2950
  */
2956
2951
  _onAckPayload(ackPayload, byteOffset) {
2957
2952
  if (this._correlator === null) return;
@@ -2964,10 +2959,8 @@ var MllpClient = class extends EventEmitter {
2964
2959
  /**
2965
2960
  * Single source-of-truth for a successfully matched ACK (live-store hit).
2966
2961
  *
2967
- * PLAN-02: emit frozen 'ack' event, call matched.resolve().
2968
- * Plan 04 extends at HOOK_EXTENSION_POINT: ack-matched to update _lastSuccessAt.
2969
- * PLAN-06 extends at HOOK_EXTENSION_POINT: ack-matched to bump _ackedTotal and
2970
- * set _lastAckAt.
2962
+ * Emits the frozen 'ack' event and resolves the pending send. Updates
2963
+ * `_lastSuccessAt`, `_ackedTotal` and `_lastAckAt`.
2971
2964
  *
2972
2965
  * Called from _onAckPayload when matchAck() returns a non-null PendingAck.
2973
2966
  */
@@ -2989,9 +2982,9 @@ var MllpClient = class extends EventEmitter {
2989
2982
  }
2990
2983
  /**
2991
2984
  * Emit a frozen `'drain'` event when the queue depth and bytes fall below
2992
- * both configured caps (Plan 05 — D-24). Called from `_onAckMatched`
2985
+ * both configured caps. Called from `_onAckMatched`
2993
2986
  * (every successful ACK) and from the Correlator's `onTimeout` callback
2994
- * (every expired send) — both code paths free a live-store slot.
2987
+ * (every expired send), both code paths free a live-store slot.
2995
2988
  */
2996
2989
  _maybeEmitDrain() {
2997
2990
  const corr = this._correlator;
@@ -3011,12 +3004,9 @@ var MllpClient = class extends EventEmitter {
3011
3004
  /**
3012
3005
  * Single source-of-truth for Connection FSM transitions.
3013
3006
  *
3014
- * PLAN-02: re-emit frozen 'stateChange' (was inline in PLAN-01; centralized
3015
- * here so Plan 04 / Plan 05 can extend at named anchors).
3016
- * Plan 04 extends at HOOK_EXTENSION_POINT: state-change to detect
3017
- * CONNECTED → DISCONNECTED|RECONNECTING and trigger _handleDisconnect.
3018
- * Plan 05 extends at HOOK_EXTENSION_POINT: state-change to clear/arm
3019
- * dead-peer timer on transitions out of / into CONNECTED.
3007
+ * Re-emits a frozen 'stateChange' event, detects
3008
+ * CONNECTED → DISCONNECTED|RECONNECTING to trigger `_handleDisconnect`, and
3009
+ * clears or arms the dead-peer timer on transitions out of / into CONNECTED.
3020
3010
  *
3021
3011
  * Called from the SINGLE 'stateChange' listener registered in _attachConnection.
3022
3012
  */
@@ -3047,17 +3037,16 @@ var MllpClient = class extends EventEmitter {
3047
3037
  }
3048
3038
  }
3049
3039
  /**
3050
- * Send an MLLP-framed payload and await the inbound ACK (CLIENT-02).
3040
+ * Send an MLLP-framed payload and await the inbound ACK.
3051
3041
  *
3052
3042
  * Resolves with the ACK Buffer (framing stripped). Rejects with:
3053
- * - `DOMException('Aborted', 'AbortError')` if `signal` aborts before ACK
3054
- * (CLIENT-11 send branch).
3055
- * - `MllpTimeoutError` if no ACK arrives within `ackTimeoutMs` (ERR-02).
3043
+ * - `DOMException('Aborted', 'AbortError')` if `signal` aborts before the ACK.
3044
+ * - `MllpTimeoutError` if no ACK arrives within `ackTimeoutMs`.
3056
3045
  * The clock starts at the underlying `write()` flush callback, NOT at
3057
- * the `send()` call (CLIENT-04, D-19).
3046
+ * the `send()` call.
3058
3047
  * - `MllpConnectionError({ phase: 'send' })` if the client is not connected.
3059
3048
  *
3060
- * Emits a frozen `'ack'` event on every successful match (D-25 + Specifics).
3049
+ * Emits a frozen `'ack'` event on every successful match.
3061
3050
  *
3062
3051
  * @example
3063
3052
  * ```typescript
@@ -3066,7 +3055,7 @@ var MllpClient = class extends EventEmitter {
3066
3055
  * ```
3067
3056
  *
3068
3057
  * @param payload Raw bytes; MLLP framing is added internally via `encodeFrame`.
3069
- * @param opts.signal AbortSignal — aborting cancels the ACK wait (CLIENT-11).
3058
+ * @param opts.signal AbortSignal, aborting cancels the ACK wait.
3070
3059
  */
3071
3060
  send(payload, opts) {
3072
3061
  const signal = opts?.signal;
@@ -3154,12 +3143,12 @@ var MllpClient = class extends EventEmitter {
3154
3143
  });
3155
3144
  }
3156
3145
  /**
3157
- * 'wait'-mode backpressure handler (Plan 05 — CLIENT-07/CLIENT-11).
3146
+ * 'wait'-mode backpressure handler.
3158
3147
  *
3159
3148
  * Awaits one of three terminating signals, in order:
3160
3149
  * - `'drain'` event → re-enter `send()` (the gate will now pass).
3161
3150
  * - `ackTimeoutMs` elapses → reject with `MllpTimeoutError`.
3162
- * - Caller's `signal` aborts → reject with `AbortError` (B-06). Cleanup
3151
+ * - Caller's `signal` aborts → reject with `AbortError`. Cleanup
3163
3152
  * removes the drain listener AND the abort listener AND clears the
3164
3153
  * timer to prevent leaks.
3165
3154
  */
@@ -3216,7 +3205,7 @@ var MllpClient = class extends EventEmitter {
3216
3205
  this._clearDeadPeerTimer();
3217
3206
  }
3218
3207
  /**
3219
- * **Test seam** — attach an externally-built {@link Connection} directly,
3208
+ * **Test seam**, attach an externally-built {@link Connection} directly,
3220
3209
  * bypassing the `net.createConnection` + `NetTransport` path. Used by
3221
3210
  * lifecycle tests driving `InMemoryTransport.pair()` for determinism.
3222
3211
  *
@@ -3295,7 +3284,7 @@ var MllpClient = class extends EventEmitter {
3295
3284
  }
3296
3285
  }
3297
3286
  /**
3298
- * Abruptly destroy the client — force-transitions the underlying Connection
3287
+ * Abruptly destroy the client, force-transitions the underlying Connection
3299
3288
  * to `CLOSED` immediately. No-op if no Connection is attached. Idempotent.
3300
3289
  *
3301
3290
  * @example
@@ -3319,9 +3308,9 @@ var MllpClient = class extends EventEmitter {
3319
3308
  conn.destroy(reason);
3320
3309
  }
3321
3310
  /**
3322
- * Returns a JSON-serializable observability snapshot (OBS-01, D-26).
3311
+ * Returns a JSON-serializable observability snapshot.
3323
3312
  *
3324
- * All fields are plain values — no Buffers, no class instances, no Maps,
3313
+ * All fields are plain values, no Buffers, no class instances, no Maps,
3325
3314
  * no circular refs. Safe to `JSON.stringify` directly.
3326
3315
  *
3327
3316
  * `inFlight` is the count of correlator entries with `sentAt !== null`
@@ -3365,7 +3354,7 @@ var MllpClient = class extends EventEmitter {
3365
3354
  };
3366
3355
  }
3367
3356
  /**
3368
- * Async disposal — delegates to {@link MllpClient.close} for `await using` support.
3357
+ * Async disposal, delegates to {@link MllpClient.close} for `await using` support.
3369
3358
  *
3370
3359
  * @example
3371
3360
  * ```typescript
@@ -3421,7 +3410,7 @@ async function createStarterClient(opts) {
3421
3410
  }
3422
3411
 
3423
3412
  // src/index.ts
3424
- var VERSION = "0.0.1";
3413
+ var VERSION = "0.0.3";
3425
3414
 
3426
3415
  export { Connection, FrameReader, MLLP_BIND_ALL_INTERFACES, MLLP_TLS_VERIFY_DISABLED, MllpAckError, MllpBackpressureError, MllpClient, MllpConnectionError, MllpFramingError, MllpServer, MllpTimeoutError, NetTransport, TlsTransport, VERSION, buildRawAck, createClient, createServer, createStarterClient, createStarterServer, createWarning, encodeFrame, isTlsProtocolError, isTlsVerificationErrorCode, isTransientConnectionError, rawAckUncorrelatable, resolveNackCode };
3427
3416
  //# sourceMappingURL=index.mjs.map