@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.cjs CHANGED
@@ -27,13 +27,13 @@ var MllpFramingError = class _MllpFramingError extends Error {
27
27
  /**
28
28
  * Up to 64 bytes copied from around the anomaly.
29
29
  *
30
- * This is a **copied** Buffer — isolated from the source buffer so it remains
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
- * `message` already discloses) — never a run of payload content bytes. For anomalies
36
- * whose fault is not a specific byte (`MLLP_FRAME_TOO_LARGE` — the accumulated size),
35
+ * `message` already discloses), never a run of payload content bytes. For anomalies
36
+ * whose fault is not a specific byte (`MLLP_FRAME_TOO_LARGE`, the accumulated size),
37
37
  * the snippet is **empty**: a payload slice on a public error field would leak a
38
38
  * field-body slice of clinical content. Callers constructing this directly are
39
39
  * responsible for the same discipline.
@@ -106,19 +106,19 @@ var FrameReader = class {
106
106
  _opts;
107
107
  _maxFrameSize;
108
108
  _state = "SCANNING_FOR_VT";
109
- /** Reusable accumulator buffer — grown by doubling as needed. */
109
+ /** Reusable accumulator buffer, grown by doubling as needed. */
110
110
  _accumulator = Buffer.allocUnsafe(INITIAL_ACCUMULATOR_SIZE);
111
111
  /** Number of payload bytes written to accumulator in current frame. */
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;
121
- /** Per-frame warning accumulator — cleared after each _deliverFrame(). */
121
+ /** Per-frame warning accumulator, cleared after each _deliverFrame(). */
122
122
  _frameWarnings = [];
123
123
  /**
124
124
  * Construct a chunked MLLP frame reader.
@@ -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
@@ -242,7 +242,7 @@ var FrameReader = class {
242
242
  this._emitWarning(
243
243
  "MLLP_MISSING_LEADING_VT",
244
244
  this._byteOffset,
245
- `Missing leading VT (0x0B) \u2014 treating byte 0x${byte.toString(16).padStart(2, "0")} at offset ${this._byteOffset} as payload start`
245
+ `Missing leading VT (0x0B), treating byte 0x${byte.toString(16).padStart(2, "0")} at offset ${this._byteOffset} as payload start`
246
246
  );
247
247
  this._frameStartOffset = this._byteOffset;
248
248
  this._state = "READING_PAYLOAD";
@@ -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);
@@ -487,8 +487,8 @@ var TlsTransport = class {
487
487
  this._socket.on("data", fn);
488
488
  }
489
489
  /**
490
- * See {@link Transport.onConnect}. Armed on `'secureConnect'` — the TLS
491
- * handshake-complete event — not the raw TCP `'connect'` event.
490
+ * See {@link Transport.onConnect}. Armed on `'secureConnect'`, the TLS
491
+ * handshake-complete event, not the raw TCP `'connect'` event.
492
492
  */
493
493
  onConnect(fn) {
494
494
  this._socket.removeAllListeners("secureConnect");
@@ -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
- * beforeClose hook — no-op default that resolves immediately.
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);
@@ -760,7 +759,7 @@ var Connection = class extends events.EventEmitter {
760
759
  * Abruptly destroy the connection, discarding any pending writes.
761
760
  *
762
761
  * Transitions from any non-terminal state directly to `CLOSED` and calls
763
- * `transport.destroy(reason)`. Emits `'close'` event. Idempotent — safe to
762
+ * `transport.destroy(reason)`. Emits `'close'` event. Idempotent, safe to
764
763
  * call multiple times.
765
764
  *
766
765
  * @param reason - Optional error to propagate to the transport.
@@ -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.
@@ -860,12 +859,12 @@ var Connection = class extends events.EventEmitter {
860
859
  * Node throws `ERR_UNHANDLED_ERROR` when `'error'` is emitted on an `EventEmitter` with no
861
860
  * listener. Every `'error'` emission in this class is reached from inside a transport callback
862
861
  * (the socket's `'data'`/`'error'` listener), so an unguarded emit would become an **uncaught
863
- * exception that kills the process** — the exact failure the containment above exists to
862
+ * exception that kills the process**, the exact failure the containment above exists to
864
863
  * prevent, merely relocated one frame up the stack.
865
864
  *
866
865
  * `Connection` is a public export and can legitimately be driven with no `'error'` listener
867
866
  * (`MllpServer` and `MllpClient` each attach one; a bare `Connection` need not). The connection
868
- * is still torn down and `'stateChange'`/`'close'` still fire, so a caller is never blind —
867
+ * is still torn down and `'stateChange'`/`'close'` still fire, so a caller is never blind,
869
868
  * they simply do not get the typed error object they never asked for. Mirrors
870
869
  * `MllpServer._emitErrorIfListened`.
871
870
  */
@@ -884,7 +883,7 @@ var Connection = class extends events.EventEmitter {
884
883
  * consumers keep the stable `code` and `byteOffset`), then **destroy this connection only**.
885
884
  *
886
885
  * Why destroy rather than resynchronize: once `push` has thrown, the reader's position within
887
- * the byte stream is no longer trustworthy — the next bytes could be the middle of a message.
886
+ * the byte stream is no longer trustworthy, the next bytes could be the middle of a message.
888
887
  * Guessing where the next frame starts is how a clinical message gets silently mis-split, so
889
888
  * the connection is dropped instead. A server drops that one peer and keeps serving everyone
890
889
  * else.
@@ -896,7 +895,7 @@ var Connection = class extends events.EventEmitter {
896
895
  * engine that is already unwell. A compatibility failure is not a network blip.
897
896
  *
898
897
  * If a peer's quirk is *expected* (trailing junk, keepalive bytes, a missing leading VT), the
899
- * decoder's tolerance opt-ins are the supported answer — they turn the throw into a warning.
898
+ * decoder's tolerance opt-ins are the supported answer, they turn the throw into a warning.
900
899
  */
901
900
  _onFatalFramingError(err) {
902
901
  if (this._state === "CLOSED") return;
@@ -910,13 +909,13 @@ var Connection = class extends events.EventEmitter {
910
909
  this.destroy(err);
911
910
  }
912
911
  /**
913
- * Backstop for a NON-framing throw escaping `FrameReader.push` — i.e. our own bug, or a
912
+ * Backstop for a NON-framing throw escaping `FrameReader.push`, i.e. our own bug, or a
914
913
  * subscriber's, rather than the peer's bytes.
915
914
  *
916
915
  * `_onFrameDecoded` already contains subscriber throws at the dispatch site, so this should be
917
916
  * unreachable. It exists because "unreachable" and "cannot kill the process from inside a
918
917
  * socket `'data'` handler" are different claims, and only the second one is safe to bet a
919
- * clinical interface on. Reported honestly as an internal receive error — never dressed up as
918
+ * clinical interface on. Reported honestly as an internal receive error, never dressed up as
920
919
  * a peer framing fault.
921
920
  */
922
921
  _onInternalReceiveError(err) {
@@ -992,9 +991,9 @@ var UNSAFE_FIELD_SEPARATORS = /* @__PURE__ */ new Set([
992
991
  SEGMENT_SEPARATOR_CR,
993
992
  SEGMENT_SEPARATOR_LF,
994
993
  11,
995
- // VT — MLLP start block
994
+ // VT, MLLP start block
996
995
  28
997
- // FS — MLLP end block
996
+ // FS, MLLP end block
998
997
  ]);
999
998
  function isMshSegmentAt(buf, i) {
1000
999
  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]);
@@ -1227,13 +1226,13 @@ var MllpServer = class extends events.EventEmitter {
1227
1226
  _netServer;
1228
1227
  _connections = /* @__PURE__ */ new Set();
1229
1228
  _opts;
1230
- /** `true` when `ServerOptions.tls` is set — `_netServer` is actually a `tls.Server`. */
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
@@ -1306,23 +1305,23 @@ var MllpServer = class extends events.EventEmitter {
1306
1305
  * `Object.freeze({ port: actualPort, host: actualHost })`.
1307
1306
  *
1308
1307
  * **Single-flight:** one `listen()` per server lifecycle at a time. A call
1309
- * while the server is already listening — or while another `listen()` is
1310
- * still in flight — rejects with a typed `MllpConnectionError` (concurrent
1308
+ * while the server is already listening, or while another `listen()` is
1309
+ * still in flight, rejects with a typed `MllpConnectionError` (concurrent
1311
1310
  * binds raced each other's post-bind safety checks). Call `close()` before
1312
1311
  * re-listening; sequential `listen()` → `close()` → `listen()` is fine.
1313
1312
  *
1314
1313
  * **`close()` during an in-flight `listen()`** rejects that `listen()` with
1315
1314
  * a typed `MllpConnectionError` (never a hang) and clears the single-flight
1316
- * guard — a subsequent `listen()` on the same server works. This makes
1315
+ * guard, a subsequent `listen()` on the same server works. This makes
1317
1316
  * `Symbol.asyncDispose` (which delegates to `close()`) safe even before a
1318
1317
  * `listen()` has settled. (Exception: `close({ signal })` with an
1319
- * already-aborted signal is a no-op AbortError rejection — the in-flight
1318
+ * already-aborted signal is a no-op AbortError rejection, the in-flight
1320
1319
  * `listen()` is left to settle on its own bind outcome; see `close()`.)
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
1325
- * are rejected unless `ServerOptions.allowWildcardBind: true` — literal
1323
+ * Default host: `'127.0.0.1'` (bind-safety hardening). Wildcard hosts
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.
1328
1327
  *
@@ -1342,7 +1341,7 @@ var MllpServer = class extends events.EventEmitter {
1342
1341
  if (this._listening || this._listenInFlight) {
1343
1342
  return Promise.reject(
1344
1343
  new MllpConnectionError(
1345
- 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",
1344
+ this._listening ? "listen() rejected: server is already listening, call close() before re-listening" : "listen() rejected: another listen() is already in flight on this server",
1346
1345
  {
1347
1346
  cause: new Error("listen already listening or in flight"),
1348
1347
  phase: "connect"
@@ -1353,7 +1352,7 @@ var MllpServer = class extends events.EventEmitter {
1353
1352
  if (isWildcardHost(host) && this._opts.allowWildcardBind !== true) {
1354
1353
  return Promise.reject(
1355
1354
  new MllpConnectionError(
1356
- `refusing to bind wildcard host '${host}' \u2014 set ServerOptions.allowWildcardBind: true to bind all interfaces`,
1355
+ `refusing to bind wildcard host '${host}', set ServerOptions.allowWildcardBind: true to bind all interfaces`,
1357
1356
  {
1358
1357
  cause: new Error("wildcard bind requires allowWildcardBind"),
1359
1358
  phase: "connect"
@@ -1432,7 +1431,7 @@ var MllpServer = class extends events.EventEmitter {
1432
1431
  {
1433
1432
  ok: false,
1434
1433
  error: new MllpConnectionError(
1435
- `refusing to bind wildcard host '${host}' (bound address '${actualHost}') \u2014 set ServerOptions.allowWildcardBind: true to bind all interfaces`,
1434
+ `refusing to bind wildcard host '${host}' (bound address '${actualHost}'), set ServerOptions.allowWildcardBind: true to bind all interfaces`,
1436
1435
  {
1437
1436
  cause: new Error("wildcard bind requires allowWildcardBind"),
1438
1437
  phase: "connect"
@@ -1459,7 +1458,7 @@ var MllpServer = class extends events.EventEmitter {
1459
1458
  }
1460
1459
  };
1461
1460
  const wildcardBound = isWildcardHost(actualHost);
1462
- const wildcardMessage = `MLLP server is bound to ALL network interfaces (host='${actualHost}') \u2014 set a specific bind address unless this is intentional.`;
1461
+ const wildcardMessage = `MLLP server is bound to ALL network interfaces (host='${actualHost}'), set a specific bind address unless this is intentional.`;
1463
1462
  if (wildcardBound) {
1464
1463
  process.emitWarning(wildcardMessage, { code: MLLP_BIND_ALL_INTERFACES });
1465
1464
  }
@@ -1487,19 +1486,19 @@ 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):
1491
- * 1. `net.Server.close()` — stops accepting new connections immediately
1489
+ * Sequence:
1490
+ * 1. `net.Server.close()`, stops accepting new connections immediately
1492
1491
  * 2. If `_connections` is empty: resolves immediately (no drain needed)
1493
- * 3. Calls `_drainAll(drainTimeoutMs)` — Promise.all + side-effect setTimeout
1492
+ * 3. Calls `_drainAll(drainTimeoutMs)`, Promise.all + side-effect setTimeout
1494
1493
  * that force-destroys stragglers after the drain window
1495
1494
  *
1496
1495
  * Calling `close()` while a `listen()` is still in flight proactively
1497
1496
  * settles that `listen()` with a typed `MllpConnectionError` rejection
1498
- * and clears the single-flight guard — the server is immediately
1497
+ * and clears the single-flight guard, the server is immediately
1499
1498
  * re-listenable. `Symbol.asyncDispose` (which delegates here) is
1500
1499
  * therefore safe before `listen()` settles. **Qualification:** a
1501
1500
  * `close({ signal })` whose signal is **already aborted** rejects
1502
- * immediately with `AbortError` and performs no work — it does NOT close
1501
+ * immediately with `AbortError` and performs no work, it does NOT close
1503
1502
  * the server and does NOT settle the in-flight `listen()`, which simply
1504
1503
  * continues and settles on its own bind outcome.
1505
1504
  *
@@ -1551,7 +1550,7 @@ var MllpServer = class extends events.EventEmitter {
1551
1550
  /**
1552
1551
  * Drain all active connections with a shared timeout.
1553
1552
  *
1554
- * Uses Promise.all (not Promise.race) for coordination — the timeout is a
1553
+ * Uses Promise.all (not Promise.race) for coordination, the timeout is a
1555
1554
  * side effect that calls `conn.destroy()` on stragglers after `drainTimeoutMs`.
1556
1555
  * Promise.all resolves when all `conn.close()` promises settle (which happens
1557
1556
  * because `conn.destroy()` transitions connections to CLOSED).
@@ -1574,7 +1573,7 @@ var MllpServer = class extends events.EventEmitter {
1574
1573
  }
1575
1574
  }
1576
1575
  /**
1577
- * Async disposal — delegates to `close()` for `await using` support.
1576
+ * Async disposal, delegates to `close()` for `await using` support.
1578
1577
  *
1579
1578
  * @example
1580
1579
  * ```typescript
@@ -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
@@ -1621,7 +1619,7 @@ var MllpServer = class extends events.EventEmitter {
1621
1619
  };
1622
1620
  }
1623
1621
  /**
1624
- * Emit on `'error'` only when a listener is attached — an unlistened
1622
+ * Emit on `'error'` only when a listener is attached, an unlistened
1625
1623
  * `EventEmitter` `'error'` emission throws (see the class JSDoc error
1626
1624
  * contract). The single guard shared by the optional-tap forwarding sites
1627
1625
  * in this class; the constructor's net.Server forwarder deliberately does
@@ -1631,7 +1629,7 @@ var MllpServer = class extends events.EventEmitter {
1631
1629
  /**
1632
1630
  * Emit a server event, containing a throwing subscriber.
1633
1631
  *
1634
- * Every event this server emits is reachable from a callback we do not own — the `net.Server`
1632
+ * Every event this server emits is reachable from a callback we do not own, the `net.Server`
1635
1633
  * `'connection'` listener, the `tls.Server` `'tlsClientError'` listener, a socket's `'data'`
1636
1634
  * listener (via `Connection`), or the `catch` block of a `void`-ed async ACK task. A throwing
1637
1635
  * subscriber would therefore unwind into that callback and kill the process (or reject a void-ed
@@ -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).
@@ -1755,7 +1753,7 @@ var MllpServer = class extends events.EventEmitter {
1755
1753
  subjectCN: asCn(cert.subject?.CN),
1756
1754
  issuerCN: asCn(cert.issuer?.CN),
1757
1755
  validTo: cert.valid_to ?? null,
1758
- // Verification outcome — under 'WANT' a certificate can be present yet
1756
+ // Verification outcome, under 'WANT' a certificate can be present yet
1759
1757
  // UNVERIFIED (see PeerCertificateSummary.authorized JSDoc).
1760
1758
  authorized: socket.authorized === true
1761
1759
  });
@@ -1767,12 +1765,12 @@ var MllpServer = class extends events.EventEmitter {
1767
1765
  * then dispatches: resolve ⇒ `AA`; throw/reject ⇒ a negative ACK (`AE` by default,
1768
1766
  * `AR` via {@link MllpAckError}). A positive ACK can never precede a successful commit.
1769
1767
  *
1770
- * Without an `onMessage` handler, `'AA'` degrades to a **transport-accept** — `AA`
1768
+ * Without an `onMessage` handler, `'AA'` degrades to a **transport-accept**, `AA`
1771
1769
  * meaning "bytes received and framed", not "application-processed".
1772
1770
  *
1773
1771
  * A handler failure is **expected flow**, not a server error: it produces a negative
1774
1772
  * ACK and a `'nack'` event. The thrown error's message is never placed on the wire or
1775
- * in the event (it may carry PHI) — only the static `ackCode` and the inbound control
1773
+ * in the event (it may carry PHI), only the static `ackCode` and the inbound control
1776
1774
  * metadata reach the peer.
1777
1775
  */
1778
1776
  async _sendCommitAck(payload, meta, conn) {
@@ -1804,18 +1802,18 @@ var MllpServer = class extends events.EventEmitter {
1804
1802
  }
1805
1803
  /**
1806
1804
  * Resolve the auto-ACK code for a message the server would otherwise acknowledge
1807
- * **positively** (`AA`) — the no-handler transport-accept and the post-commit success
1805
+ * **positively** (`AA`), the no-handler transport-accept and the post-commit success
1808
1806
  * paths. Fail-safe: downgrade to `AE` and emit a PHI-safe `'nack'` whenever the message
1809
1807
  * cannot carry a correlatable positive ACK, so `AA` never names a control ID the sender
1810
1808
  * cannot match (→ timeout → resend → **duplicate clinical message**).
1811
1809
  *
1812
1810
  * Two independent disqualifiers, one from the bytes and one from the frame:
1813
1811
  *
1814
- * - **`rawAckUncorrelatable(payload)`** — no readable `MSH`, an empty MSH-10, or a
1812
+ * - **`rawAckUncorrelatable(payload)`**, no readable `MSH`, an empty MSH-10, or a
1815
1813
  * batch/concatenated-message shape. This is the SAME predicate `buildRawAck` enforces
1816
1814
  * on the wire; it is re-checked here so the downgrade is **observable** (a `'nack'`
1817
1815
  * event) rather than a silent code change inside the builder.
1818
- * - **`MLLP_TRAILING_BYTES`** in the frame's warnings — a mid-payload `VT` made the
1816
+ * - **`MLLP_TRAILING_BYTES`** in the frame's warnings, a mid-payload `VT` made the
1819
1817
  * decoder discard accumulated bytes and deliver only the fragment after it. The
1820
1818
  * clinical message was destroyed in transit, so even a fragment that happens to carry
1821
1819
  * a readable MSH must not be positively acknowledged. This condition is invisible to
@@ -1824,7 +1822,7 @@ var MllpServer = class extends events.EventEmitter {
1824
1822
  * accumulating the delivered frame, so it is frame-scoped: it names *this* payload's own
1825
1823
  * discard, never a neighbouring frame's trailing junk.
1826
1824
  *
1827
- * `'discarded-bytes'` takes precedence in the reason when both hold — it is the root cause.
1825
+ * `'discarded-bytes'` takes precedence in the reason when both hold, it is the root cause.
1828
1826
  */
1829
1827
  _resolveAutoAckPositive(payload, meta, conn) {
1830
1828
  const discarded = meta.warnings.some((w) => w.code === "MLLP_TRAILING_BYTES");
@@ -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).
2066
- * Driven externally by `MllpClient`'s periodic sweep tick — Correlator
2067
- * itself owns no timers (D-03).
2063
+ * Fires `onTimeout(entry, elapsedMs)`; entries move to graveyard.
2064
+ * Driven externally by `MllpClient`'s periodic sweep tick, Correlator
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;
@@ -2303,13 +2300,13 @@ var MllpClient = class extends events.EventEmitter {
2303
2300
  /** Listener-removal handle for the abort listener bound in connect(). */
2304
2301
  _abortListener = null;
2305
2302
  /**
2306
- * Test-only seam — when set, `_beginReconnectAttempt` builds the new
2303
+ * Test-only seam, when set, `_beginReconnectAttempt` builds the new
2307
2304
  * Connection through this factory instead of opening a real net.Socket.
2308
2305
  *
2309
2306
  * @internal
2310
2307
  */
2311
2308
  _reconnectFactory = null;
2312
- // ── PLAN-06 — observability counters for getStats (OBS-01, D-26) ─────────
2309
+ // ── PLAN-06, observability counters for getStats (OBS-01, D-26) ─────────
2313
2310
  /** Total successful `conn.send()` flushes since construction. */
2314
2311
  _sentTotal = 0;
2315
2312
  /** Total ACKs resolved since construction. */
@@ -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,9 +2360,9 @@ 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
2368
- * enters `CONNECTED` — for TLS, on `'secureConnect'` (handshake complete,
2363
+ * Open a TCP (or TLS) connection to the configured `host:port`
2364
+ * and attach a {@link Connection} to it. Resolves once the FSM
2365
+ * enters `CONNECTED`, for TLS, on `'secureConnect'` (handshake complete,
2369
2366
  * including certificate verification when it is on).
2370
2367
  *
2371
2368
  * Rejects with:
@@ -2385,11 +2382,11 @@ var MllpClient = class extends events.EventEmitter {
2385
2382
  *
2386
2383
  * **TLS 1.3 + mutual TLS caveat (RFC 8446 §4.4.2):** `connect()` resolving
2387
2384
  * does NOT guarantee that a `clientAuth: 'MUST'` server accepted your
2388
- * client certificate. Under TLS 1.3 the client's handshake — and its
2389
- * `'secureConnect'` — can complete before the server finishes validating
2385
+ * client certificate. Under TLS 1.3 the client's handshake, and its
2386
+ * `'secureConnect'`, can complete before the server finishes validating
2390
2387
  * the certificate; a rejection then surfaces moments later as a typed
2391
2388
  * post-connect error (`'error'` event with an `ERR_SSL_*`/alert cause,
2392
- * classified **permanent** — no auto-reconnect loop). ACK correlation via
2389
+ * classified **permanent**, no auto-reconnect loop). ACK correlation via
2393
2390
  * {@link MllpClient.send} remains the delivery guarantee: no send resolves
2394
2391
  * without its ACK, so a rejected session can never silently "deliver".
2395
2392
  *
@@ -2472,8 +2469,8 @@ 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
2476
- * `TlsTransport` — verification defaults **on**
2472
+ * `NetTransport`. TLS: a `tls.TLSSocket` wrapped in
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
2479
2476
  * `ClientOptions.host`.
@@ -2502,14 +2499,14 @@ 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
- * - `'tls-verify'` — certificate-verification failures
2504
+ * - `'tls-verify'`, certificate-verification failures
2508
2505
  * ({@link isTlsVerificationErrorCode}).
2509
- * - `'tls-handshake'` — TLS-**protocol**-shaped failures only
2506
+ * - `'tls-handshake'`, TLS-**protocol**-shaped failures only
2510
2507
  * ({@link isTlsProtocolError}): `ERR_SSL_*`, `EPROTO`, OpenSSL
2511
2508
  * alert-bearing errors.
2512
- * - **No `connectionCause`** — pure TCP-level failures (`ECONNREFUSED`,
2509
+ * - **No `connectionCause`**, pure TCP-level failures (`ECONNREFUSED`,
2513
2510
  * `ETIMEDOUT`, …) even on a TLS-configured connection; these carry the
2514
2511
  * same shape as plaintext connect failures.
2515
2512
  */
@@ -2537,7 +2534,7 @@ var MllpClient = class extends events.EventEmitter {
2537
2534
  /**
2538
2535
  * Emit a client event, containing a throwing subscriber.
2539
2536
  *
2540
- * Every event this client emits is reached from a callback we do not own — a socket's
2537
+ * Every event this client emits is reached from a callback we do not own, a socket's
2541
2538
  * `'connect'`/`'secureConnect'`/`'data'`/`'error'` listener, or a backoff timer. A throwing
2542
2539
  * subscriber would unwind into it and kill the process, and on several paths it would also skip
2543
2540
  * the work queued after the emit (the `resolve()` of `connect()`, the backoff scheduling).
@@ -2550,8 +2547,8 @@ var MllpClient = class extends events.EventEmitter {
2550
2547
  });
2551
2548
  }
2552
2549
  /**
2553
- * Emit the per-connection insecure-TLS warning (Phase 8) when
2554
- * `tls.allowUnverified === true` — fires on EVERY successful
2550
+ * Emit the per-connection insecure-TLS warning when
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
2557
2554
  * connections or when verification is on.
@@ -2560,7 +2557,7 @@ var MllpClient = class extends events.EventEmitter {
2560
2557
  const tlsOpt = this._opts.tls;
2561
2558
  if (tlsOpt === void 0 || tlsOpt === true) return;
2562
2559
  if (tlsOpt.allowUnverified !== true) return;
2563
- const message = "MLLP TLS certificate verification is DISABLED (allowUnverified: true) \u2014 this connection does not authenticate the peer.";
2560
+ const message = "MLLP TLS certificate verification is DISABLED (allowUnverified: true), this connection does not authenticate the peer.";
2564
2561
  const warning = Object.freeze({
2565
2562
  code: MLLP_TLS_VERIFY_DISABLED,
2566
2563
  message,
@@ -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
2577
- * Connection layer already freezes — defense-in-depth, harmless on
2573
+ * payload is `Object.freeze`'d before emission, even though the
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
  *
@@ -2588,7 +2585,7 @@ var MllpClient = class extends events.EventEmitter {
2588
2585
  this._correlator = new Correlator({
2589
2586
  mode: this._correlateByControlId ? "controlId" : "fifo",
2590
2587
  ackTimeoutMs: this._ackTimeoutMs,
2591
- // Plan 05 — pipeline:false collapses the in-flight set to ≤1 (D-06).
2588
+ // Plan 05, pipeline:false collapses the in-flight set to ≤1 (D-06).
2592
2589
  maxInFlight: this._pipeline ? Number.POSITIVE_INFINITY : 1,
2593
2590
  onWarning: (code, ctx) => {
2594
2591
  this._aggregatedWarningsByCode[code] = (this._aggregatedWarningsByCode[code] ?? 0) + 1;
@@ -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) => {
@@ -2914,7 +2910,7 @@ var MllpClient = class extends events.EventEmitter {
2914
2910
  this._reconnectCycleStartedAt = null;
2915
2911
  }
2916
2912
  /**
2917
- * Test seam — install a factory that produces the next reconnect Connection.
2913
+ * Test seam, install a factory that produces the next reconnect Connection.
2918
2914
  *
2919
2915
  * @internal
2920
2916
  */
@@ -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,9 +2984,9 @@ 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
- * (every expired send) — both code paths free a live-store slot.
2989
+ * (every expired send), both code paths free a live-store slot.
2997
2990
  */
2998
2991
  _maybeEmitDrain() {
2999
2992
  const corr = this._correlator;
@@ -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
  */
@@ -3218,7 +3207,7 @@ var MllpClient = class extends events.EventEmitter {
3218
3207
  this._clearDeadPeerTimer();
3219
3208
  }
3220
3209
  /**
3221
- * **Test seam** — attach an externally-built {@link Connection} directly,
3210
+ * **Test seam**, attach an externally-built {@link Connection} directly,
3222
3211
  * bypassing the `net.createConnection` + `NetTransport` path. Used by
3223
3212
  * lifecycle tests driving `InMemoryTransport.pair()` for determinism.
3224
3213
  *
@@ -3297,7 +3286,7 @@ var MllpClient = class extends events.EventEmitter {
3297
3286
  }
3298
3287
  }
3299
3288
  /**
3300
- * Abruptly destroy the client — force-transitions the underlying Connection
3289
+ * Abruptly destroy the client, force-transitions the underlying Connection
3301
3290
  * to `CLOSED` immediately. No-op if no Connection is attached. Idempotent.
3302
3291
  *
3303
3292
  * @example
@@ -3321,9 +3310,9 @@ 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
- * All fields are plain values — no Buffers, no class instances, no Maps,
3315
+ * All fields are plain values, no Buffers, no class instances, no Maps,
3327
3316
  * no circular refs. Safe to `JSON.stringify` directly.
3328
3317
  *
3329
3318
  * `inFlight` is the count of correlator entries with `sentAt !== null`
@@ -3367,7 +3356,7 @@ var MllpClient = class extends events.EventEmitter {
3367
3356
  };
3368
3357
  }
3369
3358
  /**
3370
- * Async disposal — delegates to {@link MllpClient.close} for `await using` support.
3359
+ * Async disposal, delegates to {@link MllpClient.close} for `await using` support.
3371
3360
  *
3372
3361
  * @example
3373
3362
  * ```typescript
@@ -3423,7 +3412,7 @@ async function createStarterClient(opts) {
3423
3412
  }
3424
3413
 
3425
3414
  // src/index.ts
3426
- var VERSION = "0.0.1";
3415
+ var VERSION = "0.0.3";
3427
3416
 
3428
3417
  exports.Connection = Connection;
3429
3418
  exports.FrameReader = FrameReader;