Class: MllpClient
MLLP client, composes a single Connection over a NetTransport
(production) or any other Transport (testing via InMemoryTransport).
Public events, every payload Object.freeze'd before emission:
'stateChange',{ from, to, reason? }from the underlying Connection FSM'connect',{ connectionId }once the FSM entersCONNECTED'disconnect',{ connectionId }once the FSM entersDISCONNECTED'reconnecting',{ connectionId, attempt?, delayMs? }'close',{ connectionId }once the FSM enters terminalCLOSED'message',{ payload, connectionId, byteOffset, warnings }for every inbound frame'warning',MllpWarningenriched withconnectionIdfrom the Connection layer'securityWarning',SecurityWarning. Emitted on every successfulsecureConnect(initial + every reconnect) whentls.allowUnverifiedistruewith codeMLLP_TLS_VERIFY_DISABLED. Also mirrored toprocess.emitWarning.'error', re-emitted from Connection. Guarded bylistenerCount('error') > 0so absence of a listener does NOT crash the process (server precedent).
Example
const client = createClient({ host: 'localhost', port: 2575 });
client.on('stateChange', ({ from, to }) => logger.info({ from, to }));
client.on('message', ({ payload }) => logger.info({ bytes: payload.length }));
await client.connect();
const ack = await client.send(payloadBuffer);
await client.close();
Extends
EventEmitter
Constructors
Constructor
new MllpClient(
opts):MllpClient
Construct an MLLP client. Created idle; call connect() (or use
createClient/createStarterClient) to open the connection.
Parameters
opts
Client options (host/port, ACK timeout, reconnect/backpressure policy, …).
Returns
MllpClient
Overrides
EventEmitter.constructor
Accessors
state
Get Signature
get state():
ConnectionState
Current FSM state. Mirrors the underlying Connection's state once attached;
before connect() (or after a CLOSED Connection is dropped) reports
the client-level baseline ('DISCONNECTED').
Returns
Methods
_attachExistingConnection()
_attachExistingConnection(
conn):void
Internal
Test seam, attach an externally-built Connection directly,
bypassing the net.createConnection + NetTransport path. Used by
lifecycle tests driving InMemoryTransport.pair() for determinism.
Parameters
conn
Returns
void
_captureConnectSignal()
_captureConnectSignal(
signal):void
Internal
Test seam, capture or rebind the connect-signal mid-flight.
Parameters
signal
AbortSignal
Returns
void
_setReconnectFactory()
_setReconnectFactory(
factory):void
Internal
Test seam, install a factory that produces the next reconnect Connection.
Parameters
factory
() => object
Returns
void
[asyncDispose]()
[asyncDispose]():
Promise<void>
Async disposal, delegates to MllpClient.close for await using support.
Returns
Promise<void>
Example
await using client = createClient({ host: 'localhost', port: 2575 });
await client.connect();
// client.close() is called automatically at end of block
close()
close(
opts?):Promise<void>
Gracefully close the client.
Delegates to Connection.close, which transitions CONNECTED → DRAINING → DISCONNECTED (or CLOSED on drain timeout). No-op if no Connection is
attached.
Rejects with DOMException('Aborted', 'AbortError') if signal aborts mid-drain;
on abort, the underlying Connection is force-destroyed.
Parameters
opts?
drainTimeoutMs?
number
signal?
AbortSignal
Returns
Promise<void>
Example
await client.close({ drainTimeoutMs: 5_000 });
connect()
connect(
opts?):Promise<void>
Open a TCP (or TLS) connection to the configured host:port
and attach a Connection to it. Resolves once the FSM
enters CONNECTED, for TLS, on 'secureConnect' (handshake complete,
including certificate verification when it is on).
Rejects with:
DOMException('Aborted', 'AbortError')ifsignalis provided and aborts before the connect resolves.MllpConnectionError({ phase: 'connect' })if the underlying socket emitserrorbefore connecting, OR if the client is already connecting/connected. TLS failures carry aconnectionCause:'tls-verify'for certificate verification failures,'tls-handshake'for TLS-protocol-shaped failures (isTlsProtocolError); pure TCP failures carry none.
Dual failure signal on initial connect: the Connection's transport
error handler is attached before this promise's own error listener, so a
pre-connect socket error produces BOTH the promise rejection AND a
client 'error' event (when an 'error' listener is attached). Handle
whichever fits your flow; they describe the same underlying failure.
TLS 1.3 + mutual TLS caveat (RFC 8446 §4.4.2): connect() resolving
does NOT guarantee that a clientAuth: 'MUST' server accepted your
client certificate. Under TLS 1.3 the client's handshake, and its
'secureConnect', can complete before the server finishes validating
the certificate; a rejection then surfaces moments later as a typed
post-connect error ('error' event with an ERR_SSL_*/alert cause,
classified permanent, no auto-reconnect loop). ACK correlation via
MllpClient.send remains the delivery guarantee: no send resolves
without its ACK, so a rejected session can never silently "deliver".
Parameters
opts?
signal?
AbortSignal
Returns
Promise<void>
Example
const ac = new AbortController();
setTimeout(() => ac.abort(), 5_000);
await client.connect({ signal: ac.signal });
destroy()
destroy(
reason?):void
Abruptly destroy the client, force-transitions the underlying Connection
to CLOSED immediately. No-op if no Connection is attached. Idempotent.
Parameters
reason?
Error
Returns
void
Example
client.destroy(new Error('shutting down'));
getStats()
getStats():
ClientStats
Returns a JSON-serializable observability snapshot.
All fields are plain values, no Buffers, no class instances, no Maps,
no circular refs. Safe to JSON.stringify directly.
inFlight is the count of correlator entries with sentAt !== null
(entries actually written to the wire and awaiting ACK), distinct from
queueDepth which counts ALL live correlator entries (including
pre-flush and serialization-queued sends).
Returns
Example
setInterval(() => logger.info(JSON.stringify(client.getStats())), 60_000);
send()
send(
payload,opts?):Promise<Buffer<ArrayBufferLike>>
Send an MLLP-framed payload and await the inbound ACK.
Resolves with the ACK Buffer (framing stripped). Rejects with:
DOMException('Aborted', 'AbortError')ifsignalaborts before the ACK.MllpTimeoutErrorif no ACK arrives withinackTimeoutMs. The clock starts at the underlyingwrite()flush callback, NOT at thesend()call.MllpConnectionError({ phase: 'send' })if the client is not connected.
Emits a frozen 'ack' event on every successful match.
Parameters
payload
Buffer
Raw bytes; MLLP framing is added internally via encodeFrame.
opts?
ackTimeoutMs?
number
signal?
AbortSignal
AbortSignal, aborting cancels the ACK wait.
Returns
Promise<Buffer<ArrayBufferLike>>
Example
const ack = await client.send(payloadBuffer);
logger.info({ ack: ack.toString('utf8') });