@cosyte/mllp 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +60 -0
- package/dist/ack-from-hl7/index.cjs +1 -1
- package/dist/ack-from-hl7/index.cjs.map +1 -1
- package/dist/ack-from-hl7/index.d.cts +4 -5
- package/dist/ack-from-hl7/index.d.ts +4 -5
- package/dist/ack-from-hl7/index.mjs +1 -1
- package/dist/ack-from-hl7/index.mjs.map +1 -1
- package/dist/{index-DAZ4BvJE.d.cts → index-CD8V2Mtk.d.cts} +1 -1
- package/dist/{index-DAZ4BvJE.d.ts → index-CD8V2Mtk.d.ts} +1 -1
- package/dist/index.cjs +92 -103
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +210 -232
- package/dist/index.d.ts +210 -232
- package/dist/index.mjs +92 -103
- package/dist/index.mjs.map +1 -1
- package/dist/testing/index.d.cts +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -28,7 +28,7 @@ var MllpFramingError = class _MllpFramingError extends Error {
|
|
|
28
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
|
|
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
33
|
* `message` already discloses), never a run of payload content bytes. For anomalies
|
|
34
34
|
* whose fault is not a specific byte (`MLLP_FRAME_TOO_LARGE`, the accumulated size),
|
|
@@ -110,9 +110,9 @@ var FrameReader = class {
|
|
|
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
|
|
113
|
+
/** Byte offset where current leading-whitespace run started. */
|
|
114
114
|
_wsStart = 0;
|
|
115
|
-
/** Count of leading whitespace bytes accumulated in current run
|
|
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;
|
|
@@ -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
|
|
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
|
|
@@ -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
|
|
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
|
|
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);
|
|
@@ -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
|
|
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
|
|
568
|
+
/** Ring buffer: last MAX_WARNINGS entries. */
|
|
569
569
|
_warningBuffer = [];
|
|
570
|
-
/** Accurate total counts per code, unaffected by ring buffer truncation
|
|
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
|
|
572
|
+
/** Set to true once the ring buffer overflows. */
|
|
573
573
|
_warningsTruncated = false;
|
|
574
574
|
_onWarningFn = null;
|
|
575
575
|
_drainPromise = null;
|
|
576
576
|
/**
|
|
577
577
|
* beforeClose hook, no-op default that resolves immediately.
|
|
578
578
|
*
|
|
579
|
-
*
|
|
580
|
-
*
|
|
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
|
|
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
|
|
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
|
|
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
|
-
*
|
|
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()
|
|
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()
|
|
733
|
+
* On timeout: `DRAINING → CLOSED` + `transport.destroy()`.
|
|
735
734
|
*/
|
|
736
735
|
async _drainWithTimeout(timeoutMs) {
|
|
737
736
|
const drainPromise = this.beforeClose(timeoutMs);
|
|
@@ -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
|
|
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.
|
|
@@ -1228,10 +1227,10 @@ var MllpServer = class extends EventEmitter {
|
|
|
1228
1227
|
/** `true` when `ServerOptions.tls` is set, `_netServer` is actually a `tls.Server`. */
|
|
1229
1228
|
_isTls;
|
|
1230
1229
|
_listening = false;
|
|
1231
|
-
/**
|
|
1230
|
+
/** Single-flight guard: `true` while a `listen()` call is settling. */
|
|
1232
1231
|
_listenInFlight = false;
|
|
1233
1232
|
/**
|
|
1234
|
-
*
|
|
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
|
-
/**
|
|
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
|
|
@@ -1319,7 +1318,7 @@ var MllpServer = class extends EventEmitter {
|
|
|
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'` (
|
|
1321
|
+
* Default host: `'127.0.0.1'` (bind-safety hardening). Wildcard hosts
|
|
1323
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.
|
|
@@ -1485,7 +1484,7 @@ var MllpServer = class extends EventEmitter {
|
|
|
1485
1484
|
/**
|
|
1486
1485
|
* Stop accepting new connections and gracefully close all active connections.
|
|
1487
1486
|
*
|
|
1488
|
-
* Sequence
|
|
1487
|
+
* Sequence:
|
|
1489
1488
|
* 1. `net.Server.close()`, stops accepting new connections immediately
|
|
1490
1489
|
* 2. If `_connections` is empty: resolves immediately (no drain needed)
|
|
1491
1490
|
* 3. Calls `_drainAll(drainTimeoutMs)`, Promise.all + side-effect setTimeout
|
|
@@ -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
|
|
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
|
|
@@ -1734,8 +1732,8 @@ var MllpServer = class extends EventEmitter {
|
|
|
1734
1732
|
);
|
|
1735
1733
|
}
|
|
1736
1734
|
/**
|
|
1737
|
-
* Extract a minimal, content-free peer-certificate summary (
|
|
1738
|
-
*
|
|
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).
|
|
@@ -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 (
|
|
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
|
|
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
|
|
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
|
-
*
|
|
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,
|
|
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 (
|
|
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
|
-
*
|
|
2011
|
-
* `onUnmatchedAck(controlIdFromAck)`
|
|
2008
|
+
* and returns `null`; otherwise fires
|
|
2009
|
+
* `onUnmatchedAck(controlIdFromAck)` and returns `null`.
|
|
2012
2010
|
*
|
|
2013
|
-
* Triggers lazy graveyard eviction
|
|
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
|
|
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
|
|
2061
|
+
* Fires `onTimeout(entry, elapsedMs)`; entries move to graveyard.
|
|
2064
2062
|
* Driven externally by `MllpClient`'s periodic sweep tick, Correlator
|
|
2065
|
-
* itself owns no timers
|
|
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
|
|
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 (
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2244
|
+
/** Per-message ACK timeout in ms. Resolved at construction. */
|
|
2248
2245
|
_ackTimeoutMs;
|
|
2249
|
-
/** controlId-mode flag
|
|
2246
|
+
/** controlId-mode flag. `false` → FIFO. */
|
|
2250
2247
|
_correlateByControlId;
|
|
2251
|
-
/** Unified ACK correlator
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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
|
|
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;
|
|
@@ -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
|
|
2321
|
+
* at observation time and merged into the snapshot.
|
|
2325
2322
|
*/
|
|
2326
2323
|
_aggregatedWarningsByCode = {};
|
|
2327
2324
|
/**
|
|
@@ -2361,8 +2358,8 @@ var MllpClient = class extends EventEmitter {
|
|
|
2361
2358
|
return this._connection?.state ?? this._state;
|
|
2362
2359
|
}
|
|
2363
2360
|
/**
|
|
2364
|
-
* Open a TCP (or TLS
|
|
2365
|
-
* and attach a
|
|
2361
|
+
* Open a TCP (or TLS) connection to the configured `host:port`
|
|
2362
|
+
* and attach a {@link Connection} to it. Resolves once the FSM
|
|
2366
2363
|
* enters `CONNECTED`, for TLS, on `'secureConnect'` (handshake complete,
|
|
2367
2364
|
* including certificate verification when it is on).
|
|
2368
2365
|
*
|
|
@@ -2470,7 +2467,7 @@ 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
|
|
2470
|
+
* `NetTransport`. TLS: a `tls.TLSSocket` wrapped in
|
|
2474
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
|
|
@@ -2500,7 +2497,7 @@ var MllpClient = class extends EventEmitter {
|
|
|
2500
2497
|
}
|
|
2501
2498
|
/**
|
|
2502
2499
|
* Wrap a connect-phase socket error as `MllpConnectionError`, classifying
|
|
2503
|
-
* TLS failures
|
|
2500
|
+
* TLS failures into the additive `connectionCause`:
|
|
2504
2501
|
*
|
|
2505
2502
|
* - `'tls-verify'`, certificate-verification failures
|
|
2506
2503
|
* ({@link isTlsVerificationErrorCode}).
|
|
@@ -2548,7 +2545,7 @@ var MllpClient = class extends EventEmitter {
|
|
|
2548
2545
|
});
|
|
2549
2546
|
}
|
|
2550
2547
|
/**
|
|
2551
|
-
* Emit the per-connection insecure-TLS warning
|
|
2548
|
+
* Emit the per-connection insecure-TLS warning when
|
|
2552
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
|
|
@@ -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
|
|
2571
|
+
* payload is `Object.freeze`'d before emission, even though the
|
|
2575
2572
|
* Connection layer already freezes, defense-in-depth, harmless on
|
|
2576
2573
|
* already-frozen objects.
|
|
2577
2574
|
*
|
|
2578
|
-
* Builds the unified `Correlator`
|
|
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
|
*
|
|
@@ -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
|
|
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
|
|
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,
|
|
2708
|
+
* Disconnect handler, reconnect FSM core.
|
|
2713
2709
|
*
|
|
2714
2710
|
* Implements:
|
|
2715
|
-
* -
|
|
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
|
-
* -
|
|
2714
|
+
* - Classifier-first: permanent errors
|
|
2719
2715
|
* transition straight to CLOSED without invoking `retryStrategy`.
|
|
2720
|
-
* -
|
|
2716
|
+
* - Backoff-reset on recent success: first disconnect after a
|
|
2721
2717
|
* successful ACK on the prior session resets `_attempt` to 0.
|
|
2722
|
-
* -
|
|
2723
|
-
* -
|
|
2724
|
-
* -
|
|
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
|
-
*
|
|
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
|
|
2823
|
+
* Default retry strategy: `min(maxDelay, initialDelay * multiplier^attempt)`
|
|
2828
2824
|
* with ±jitter applied.
|
|
2829
2825
|
*/
|
|
2830
2826
|
_defaultRetryStrategy = (ctx) => {
|
|
@@ -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
|
|
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
|
|
2950
|
-
*
|
|
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
|
|
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
|
-
*
|
|
2968
|
-
*
|
|
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,7 +2982,7 @@ 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
|
|
2985
|
+
* both configured caps. Called from `_onAckMatched`
|
|
2993
2986
|
* (every successful ACK) and from the Correlator's `onTimeout` callback
|
|
2994
2987
|
* (every expired send), both code paths free a live-store slot.
|
|
2995
2988
|
*/
|
|
@@ -3011,12 +3004,9 @@ var MllpClient = class extends EventEmitter {
|
|
|
3011
3004
|
/**
|
|
3012
3005
|
* Single source-of-truth for Connection FSM transitions.
|
|
3013
3006
|
*
|
|
3014
|
-
*
|
|
3015
|
-
*
|
|
3016
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
*/
|
|
@@ -3319,7 +3308,7 @@ var MllpClient = class extends EventEmitter {
|
|
|
3319
3308
|
conn.destroy(reason);
|
|
3320
3309
|
}
|
|
3321
3310
|
/**
|
|
3322
|
-
* Returns a JSON-serializable observability snapshot
|
|
3311
|
+
* Returns a JSON-serializable observability snapshot.
|
|
3323
3312
|
*
|
|
3324
3313
|
* All fields are plain values, no Buffers, no class instances, no Maps,
|
|
3325
3314
|
* no circular refs. Safe to `JSON.stringify` directly.
|
|
@@ -3421,7 +3410,7 @@ async function createStarterClient(opts) {
|
|
|
3421
3410
|
}
|
|
3422
3411
|
|
|
3423
3412
|
// src/index.ts
|
|
3424
|
-
var VERSION = "0.0.
|
|
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
|