@cosyte/mllp 0.0.1 → 0.0.2
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 +269 -108
- package/README.md +23 -18
- package/TRADEMARKS.md +30 -0
- package/dist/ack-from-hl7/index.cjs +54 -14
- package/dist/ack-from-hl7/index.cjs.map +1 -1
- package/dist/ack-from-hl7/index.d.cts +113 -38
- package/dist/ack-from-hl7/index.d.ts +113 -38
- package/dist/ack-from-hl7/index.mjs +53 -14
- package/dist/ack-from-hl7/index.mjs.map +1 -1
- package/dist/{index-DjGQJtYE.d.cts → index-DAZ4BvJE.d.cts} +5 -5
- package/dist/{index-DjGQJtYE.d.ts → index-DAZ4BvJE.d.ts} +5 -5
- package/dist/index.cjs +90 -90
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +239 -239
- package/dist/index.d.ts +239 -239
- package/dist/index.mjs +90 -90
- package/dist/index.mjs.map +1 -1
- package/dist/testing/index.cjs +3 -3
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +8 -8
- package/dist/testing/index.d.ts +8 -8
- package/dist/testing/index.mjs +3 -3
- package/dist/testing/index.mjs.map +1 -1
- package/package.json +15 -7
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @cosyte/mllp
|
|
2
2
|
|
|
3
|
-
> Send and receive HL7 v2 over a production-grade MLLP connection in a few lines
|
|
3
|
+
> Send and receive HL7 v2 over a production-grade MLLP connection in a few lines, with framing, ACK correlation, auto-reconnect, and backpressure handled for you.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@cosyte/mllp)
|
|
6
6
|
[](https://github.com/cosyte/mllp/actions/workflows/ci.yml)
|
|
@@ -16,7 +16,7 @@ A developer-focused MLLP (Minimal Lower Layer Protocol) client and server for No
|
|
|
16
16
|
## Quickstart
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
# pnpm (recommended)
|
|
19
|
+
# pnpm (recommended), also works with: npm install @cosyte/mllp | yarn add @cosyte/mllp
|
|
20
20
|
pnpm add @cosyte/mllp
|
|
21
21
|
```
|
|
22
22
|
|
|
@@ -34,20 +34,20 @@ const client = await createStarterClient({ host: "localhost", port: 2575 });
|
|
|
34
34
|
const ack = await client.send(Buffer.from("MSH|^~\\&|..."));
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
The payload API is **Buffer-first** everywhere
|
|
37
|
+
The payload API is **Buffer-first** everywhere. HL7 v2 messages are raw bytes with caller-managed charset decoding.
|
|
38
38
|
|
|
39
39
|
## MLLPS / TLS
|
|
40
40
|
|
|
41
|
-
TLS is built on `node:tls
|
|
41
|
+
TLS is built on `node:tls`: no bundled TLS, no extra dependency. Certificate verification is **on
|
|
42
42
|
by default**; the server binds `127.0.0.1` by default and requires an explicit opt-in
|
|
43
43
|
(`allowWildcardBind: true`) to bind all interfaces.
|
|
44
44
|
|
|
45
45
|
```ts
|
|
46
|
-
// Server
|
|
46
|
+
// Server: plain TLS
|
|
47
47
|
const server = createServer({ tls: { cert: certPem, key: keyPem } });
|
|
48
48
|
await server.listen(2575, "127.0.0.1");
|
|
49
49
|
|
|
50
|
-
// Server
|
|
50
|
+
// Server: mutual TLS (ATNA ITI-19)
|
|
51
51
|
const server = createServer({
|
|
52
52
|
tls: { cert: certPem, key: keyPem, ca: clientCaPem, clientAuth: "MUST" },
|
|
53
53
|
});
|
|
@@ -57,7 +57,7 @@ const server = createServer({
|
|
|
57
57
|
// Client
|
|
58
58
|
const client = createClient({ host: "mllp.example.com", port: 2575, tls: { ca: caPem } });
|
|
59
59
|
|
|
60
|
-
// Client
|
|
60
|
+
// Client: mutual TLS
|
|
61
61
|
const client = createClient({
|
|
62
62
|
host: "mllp.example.com",
|
|
63
63
|
port: 2575,
|
|
@@ -68,9 +68,9 @@ const client = createClient({
|
|
|
68
68
|
See the **MLLPS / TLS** doc for the `ClientAuth` table, the TLS 1.2 floor (IHE ATNA ITI-19), typed
|
|
69
69
|
failure modes (`tls-verify` vs `tls-handshake`), and bind-safety details.
|
|
70
70
|
|
|
71
|
-
## Fail-safe ACKs
|
|
71
|
+
## Fail-safe ACKs: the commit contract
|
|
72
72
|
|
|
73
|
-
A positive acknowledgement (`AA`) tells the sender *"you may forget this message
|
|
73
|
+
A positive acknowledgement (`AA`) tells the sender *"you may forget this message. I have it."* So a
|
|
74
74
|
receiver must never send one before the message is durably handled, or the message is silently lost.
|
|
75
75
|
`@cosyte/mllp` makes that structural: pair `autoAck: 'AA'` with an `onMessage` handler and the server
|
|
76
76
|
**awaits your handler (the durable-commit step) and only then ACKs**.
|
|
@@ -86,28 +86,33 @@ const server = createServer({
|
|
|
86
86
|
|
|
87
87
|
Handler resolves ⇒ `AA`. Handler throws ⇒ `AE` (or `AR` via `MllpAckError`). **A positive ACK cannot
|
|
88
88
|
precede a successful commit.** `autoAck: 'AA'` *without* a handler is documented as a
|
|
89
|
-
transport-accept
|
|
89
|
+
transport-accept: "received and framed", not "processed".
|
|
90
90
|
|
|
91
91
|
## What's in the box
|
|
92
92
|
|
|
93
93
|
- **Client + server** with strict MLLP framing (`VT + payload + FS + CR`), ACK correlation, auto-reconnect with backoff, and backpressure.
|
|
94
|
-
- **The commit contract
|
|
95
|
-
- **Explicit 6-state connection machine** (`CONNECTING | CONNECTED | DRAINING | RECONNECTING | DISCONNECTED | CLOSED`) with `stateChange` events
|
|
94
|
+
- **The commit contract**: a positive ACK can never precede a durable commit; an unparseable inbound can never yield a positive ACK.
|
|
95
|
+
- **Explicit 6-state connection machine** (`CONNECTING | CONNECTED | DRAINING | RECONNECTING | DISCONNECTED | CLOSED`) with `stateChange` events, never socket flags.
|
|
96
96
|
- **Lenient decoder, strict encoder** (Postel's Law) with **11 stable warning codes** carrying byte offsets. Tolerance is opt-in per flag; the server ships tolerant defaults.
|
|
97
|
-
- **TLS (MLLPS)
|
|
98
|
-
- **PHI-safe diagnostics
|
|
99
|
-
- **In-memory transport** (`@cosyte/mllp/testing`)
|
|
100
|
-
- **`@cosyte/hl7` as an optional peer
|
|
97
|
+
- **TLS (MLLPS)**: verification on by default, mutual TLS (`clientAuth: 'NONE' | 'WANT' | 'MUST'`), a TLS 1.2 floor per IHE ATNA ITI-19, and bind-safety guardrails (`127.0.0.1` default, wildcard binds require opt-in). `AbortSignal` on every awaitable and `Symbol.asyncDispose` on every closeable.
|
|
98
|
+
- **PHI-safe diagnostics**: no error, warning, event payload, or stats object ever echoes a *run* of message content; a framing error carries at most the single byte at the structural violation.
|
|
99
|
+
- **In-memory transport** (`@cosyte/mllp/testing`): a deterministic, socket-free test double for fast, reliable tests.
|
|
100
|
+
- **`@cosyte/hl7` as an optional peer**: the `@cosyte/mllp/ack-from-hl7` subpath builds ACKs from parsed messages when it's installed.
|
|
101
101
|
- **Zero runtime dependencies.** Node stdlib only.
|
|
102
102
|
|
|
103
103
|
## What it deliberately does not do
|
|
104
104
|
|
|
105
|
-
MLLP + ACK is **at-least-once at best
|
|
105
|
+
MLLP + ACK is **at-least-once at best**. Your application owns idempotency and de-duplication
|
|
106
106
|
(`MSH-10` + `MSH-7`). This package does not parse HL7 (use `@cosyte/hl7`), does not queue or replay
|
|
107
107
|
unacked messages, does not decide clinical acceptance, does not speak MLLP **Release 2**, and ships
|
|
108
|
-
no PKI. The full list is in the **Known limitations & non-goals** doc
|
|
108
|
+
no PKI. The full list is in the **Known limitations & non-goals** doc. Read it before you depend on
|
|
109
109
|
this.
|
|
110
110
|
|
|
111
|
+
## Trademarks
|
|
112
|
+
|
|
113
|
+
Epic, Cerner, Mirth Connect, NextGen, and Google Cloud Healthcare are trademarks of their respective owners. cosyte is not affiliated with, endorsed by, or
|
|
114
|
+
sponsored by any of them. The names identify the engines this package is tested against, and those it is not. See [TRADEMARKS.md](./TRADEMARKS.md).
|
|
115
|
+
|
|
111
116
|
## License
|
|
112
117
|
|
|
113
118
|
MIT
|
package/TRADEMARKS.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Trademarks
|
|
2
|
+
|
|
3
|
+
`@cosyte/mllp` is an independent open-source project. cosyte is **not affiliated with, endorsed by,
|
|
4
|
+
or sponsored by** any company named in this repository or its documentation.
|
|
5
|
+
|
|
6
|
+
## Why these names appear
|
|
7
|
+
|
|
8
|
+
This package names other systems in two places: to identify the engines its differential test
|
|
9
|
+
harness runs against, and to state plainly which engines it has **not** been verified against.
|
|
10
|
+
|
|
11
|
+
Every reference is **descriptive**: it identifies whose engine was tested against, or whose behaviour is explicitly not covered. Naming a system is the only way to say
|
|
12
|
+
whether a library works with it.
|
|
13
|
+
|
|
14
|
+
## How these names are used
|
|
15
|
+
|
|
16
|
+
This package has no vendor profile system. The names identify freely available software used for
|
|
17
|
+
interoperability testing, or appear in documentation recording the limits of that testing,
|
|
18
|
+
including an explicit statement that Epic and Cerner are **not** part of the harness.
|
|
19
|
+
|
|
20
|
+
## Names referenced
|
|
21
|
+
|
|
22
|
+
| Name | Where it appears |
|
|
23
|
+
| ---- | ---------------- |
|
|
24
|
+
| Mirth Connect, NextGen | Named as an engine in the differential test harness. |
|
|
25
|
+
| Google Cloud Healthcare | Named as an engine in the differential test harness (the MLLP adapter). |
|
|
26
|
+
| Epic, Cerner | Named in `docs-content/limitations.md` to record that this package is **not** differentially verified against them. |
|
|
27
|
+
|
|
28
|
+
All product names, logos, and brands are the property of their respective owners. Use of a name here
|
|
29
|
+
does not imply any affiliation with, or endorsement by, its owner. If you own one of these marks and
|
|
30
|
+
would like a reference changed, please open an issue.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var module$1 = require('module');
|
|
4
4
|
|
|
5
|
-
// node_modules/.pnpm/tsup@8.5.1_postcss@8.5.
|
|
5
|
+
// node_modules/.pnpm/tsup@8.5.1_postcss@8.5.10_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js
|
|
6
6
|
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
7
7
|
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
8
8
|
|
|
@@ -22,13 +22,13 @@ var MllpFramingError = class _MllpFramingError extends Error {
|
|
|
22
22
|
/**
|
|
23
23
|
* Up to 64 bytes copied from around the anomaly.
|
|
24
24
|
*
|
|
25
|
-
* This is a **copied** Buffer
|
|
25
|
+
* This is a **copied** Buffer, isolated from the source buffer so it remains
|
|
26
26
|
* valid after the underlying buffer is reused or overwritten.
|
|
27
27
|
*
|
|
28
28
|
* **PHI contract (MLLP-9):** the decoder only ever populates this with the single
|
|
29
29
|
* framing-boundary byte that violated the frame structure (whose hex value the
|
|
30
|
-
* `message` already discloses)
|
|
31
|
-
* whose fault is not a specific byte (`MLLP_FRAME_TOO_LARGE
|
|
30
|
+
* `message` already discloses), never a run of payload content bytes. For anomalies
|
|
31
|
+
* whose fault is not a specific byte (`MLLP_FRAME_TOO_LARGE`, the accumulated size),
|
|
32
32
|
* the snippet is **empty**: a payload slice on a public error field would leak a
|
|
33
33
|
* field-body slice of clinical content. Callers constructing this directly are
|
|
34
34
|
* responsible for the same discipline.
|
|
@@ -110,9 +110,9 @@ var UNSAFE_FIELD_SEPARATORS = /* @__PURE__ */ new Set([
|
|
|
110
110
|
SEGMENT_SEPARATOR_CR,
|
|
111
111
|
SEGMENT_SEPARATOR_LF,
|
|
112
112
|
11,
|
|
113
|
-
// VT
|
|
113
|
+
// VT, MLLP start block
|
|
114
114
|
28
|
|
115
|
-
// FS
|
|
115
|
+
// FS, MLLP end block
|
|
116
116
|
]);
|
|
117
117
|
function isMshSegmentAt(buf, i) {
|
|
118
118
|
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]);
|
|
@@ -211,7 +211,7 @@ var MllpPeerMissingError = class _MllpPeerMissingError extends Error {
|
|
|
211
211
|
*/
|
|
212
212
|
constructor(cause) {
|
|
213
213
|
super(
|
|
214
|
-
`${PEER_PACKAGE_NAME} is required by ${SUBPATH_NAME} but is not installed. ${PEER_PACKAGE_NAME} is an optional peer dependency of @cosyte/mllp
|
|
214
|
+
`${PEER_PACKAGE_NAME} is required by ${SUBPATH_NAME} but is not installed. ${PEER_PACKAGE_NAME} is an optional peer dependency of @cosyte/mllp, install it alongside @cosyte/mllp to use ${SUBPATH_NAME}: \`npm install ${PEER_PACKAGE_NAME}\` (or the equivalent for your package manager).`,
|
|
215
215
|
{ cause }
|
|
216
216
|
);
|
|
217
217
|
if (Error.captureStackTrace) {
|
|
@@ -252,8 +252,16 @@ function loadHl7Peer(requireFn) {
|
|
|
252
252
|
// src/ack-from-hl7/build.ts
|
|
253
253
|
var MLLP_ACK_INBOUND_UNPARSEABLE = "MLLP_ACK_INBOUND_UNPARSEABLE";
|
|
254
254
|
var MLLP_ACK_CONTROL_ID_NOT_VERBATIM = "MLLP_ACK_CONTROL_ID_NOT_VERBATIM";
|
|
255
|
+
var MLLP_ACK_CONTROL_ID_UNVERIFIABLE = "MLLP_ACK_CONTROL_ID_UNVERIFIABLE";
|
|
255
256
|
var BYTES_INBOUND_ENCODING = "latin1";
|
|
256
257
|
var TEXT_INBOUND_ENCODING = "utf8";
|
|
258
|
+
var SERIALIZABLE_ACK_ENCODINGS = /* @__PURE__ */ new Set([
|
|
259
|
+
"utf8",
|
|
260
|
+
"utf-8",
|
|
261
|
+
"ascii",
|
|
262
|
+
"latin1",
|
|
263
|
+
"binary"
|
|
264
|
+
]);
|
|
257
265
|
function assertKnownAckCode(peer, code) {
|
|
258
266
|
const known = Object.values(peer.ACK_CODES);
|
|
259
267
|
if (typeof code !== "string" || !known.includes(code)) {
|
|
@@ -266,6 +274,12 @@ function resolveEncoding(inbound, options) {
|
|
|
266
274
|
if (options.encoding !== void 0) return options.encoding;
|
|
267
275
|
return Buffer.isBuffer(inbound) ? BYTES_INBOUND_ENCODING : TEXT_INBOUND_ENCODING;
|
|
268
276
|
}
|
|
277
|
+
function assertSerializableAckEncoding(encoding) {
|
|
278
|
+
if (SERIALIZABLE_ACK_ENCODINGS.has(encoding.toLowerCase())) return;
|
|
279
|
+
throw new TypeError(
|
|
280
|
+
`buildMllpAck: encoding ${JSON.stringify(encoding)} is not a serializable ACK codec. Serializing an ACK to a non-text codec (base64/base64url/hex/utf16le/ucs2) produces a wholesale-garbage frame the receiver cannot parse, on a Buffer inbound it also garbles the inbound decode, so it can never correlate. Use a text codec ("utf8", "ascii", or "latin1"); on a Buffer, "latin1" is byte-verbatim and is the default.`
|
|
281
|
+
);
|
|
282
|
+
}
|
|
269
283
|
function inboundBytes(inbound, encoding) {
|
|
270
284
|
if (Buffer.isBuffer(inbound)) return inbound;
|
|
271
285
|
if (typeof inbound === "string") return Buffer.from(inbound, encoding);
|
|
@@ -281,7 +295,23 @@ function verifyVerbatimEcho(ackPayload, inboundRaw) {
|
|
|
281
295
|
const echoed = echoedId === null ? "absent" : `${String(echoedId.length)} bytes`;
|
|
282
296
|
return {
|
|
283
297
|
code: MLLP_ACK_CONTROL_ID_NOT_VERBATIM,
|
|
284
|
-
message: `ACK does not echo the inbound MSH-10 verbatim (HL7 v2.5.1 \xA72.9.2.2): inbound MSH-10 is ${inboundLen} bytes, emitted MSA-2 is ${echoed}, and they differ. The sender keys its in-flight store on the inbound bytes, so it will NOT match this ACK (ACK timeout -> resend -> duplicate message). Field values are withheld
|
|
298
|
+
message: `ACK does not echo the inbound MSH-10 verbatim (HL7 v2.5.1 \xA72.9.2.2): inbound MSH-10 is ${inboundLen} bytes, emitted MSA-2 is ${echoed}, and they differ. The sender keys its in-flight store on the inbound bytes, so it will NOT match this ACK (ACK timeout -> resend -> duplicate message). Field values are withheld, MSH-10 is inbound payload content and this warning goes to a log; compare your inbound payload against MllpAck.payload to see the bytes.`
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function verifyTextInboundEcho(controlId, inbound) {
|
|
302
|
+
if (Buffer.isBuffer(inbound)) return null;
|
|
303
|
+
if (controlId === "") return null;
|
|
304
|
+
let hasNonAscii = false;
|
|
305
|
+
for (let i = 0; i < controlId.length; i++) {
|
|
306
|
+
if (controlId.charCodeAt(i) > 127) {
|
|
307
|
+
hasNonAscii = true;
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (!hasNonAscii) return null;
|
|
312
|
+
return {
|
|
313
|
+
code: MLLP_ACK_CONTROL_ID_UNVERIFIABLE,
|
|
314
|
+
message: `ACK's byte-verbatim echo of MSH-10 (HL7 v2.5.1 \xA72.9.2.2) cannot be verified: the inbound was decoded text (a string or Hl7Message), not raw bytes, so its wire bytes are gone and the ${String(controlId.length)}-code-unit MSA-2 control ID holds a non-ASCII code unit the decode/encode codec could have altered (a lossy override such as ascii can even mask it into the ASCII byte range). It may not correlate at the sender (ACK timeout -> resend -> duplicate message). Pass the raw payload Buffer to get the byte-level guarantee. Field values are withheld, MSH-10 is inbound payload content and this warning goes to a log.`
|
|
285
315
|
};
|
|
286
316
|
}
|
|
287
317
|
function toMllpAck(params) {
|
|
@@ -291,7 +321,13 @@ function toMllpAck(params) {
|
|
|
291
321
|
allowDelimiterBytesInPayload: options.allowDelimiterBytesInPayload ?? false
|
|
292
322
|
});
|
|
293
323
|
const echoWarning = verifyVerbatimEcho(payload, params.verifyAgainst);
|
|
294
|
-
const
|
|
324
|
+
const echoedControlId = ack.segments("MSA")[0]?.field(2).text ?? "";
|
|
325
|
+
const unverifiableWarning = params.inbound === void 0 ? null : verifyTextInboundEcho(echoedControlId, params.inbound);
|
|
326
|
+
const allWarnings = [
|
|
327
|
+
...warnings,
|
|
328
|
+
...echoWarning === null ? [] : [echoWarning],
|
|
329
|
+
...unverifiableWarning === null ? [] : [unverifiableWarning]
|
|
330
|
+
];
|
|
295
331
|
const result = {
|
|
296
332
|
frame,
|
|
297
333
|
payload,
|
|
@@ -322,11 +358,12 @@ function buildUnparseableFallback(peer, requestedCode, fatalCode, options, encod
|
|
|
322
358
|
warnings,
|
|
323
359
|
options,
|
|
324
360
|
encoding,
|
|
325
|
-
// MSA-2 is INTENTIONALLY empty here
|
|
326
|
-
// control id to echo and we refuse to fabricate one. Running
|
|
327
|
-
// report that deliberate choice as a
|
|
361
|
+
// MSA-2 is INTENTIONALLY empty here, the inbound could not be parsed, so there is no
|
|
362
|
+
// control id to echo and we refuse to fabricate one. Running either echo check would
|
|
363
|
+
// report that deliberate choice as a problem; `MLLP_ACK_INBOUND_UNPARSEABLE` (above)
|
|
328
364
|
// is the accurate warning for this case, and it is already attached.
|
|
329
|
-
verifyAgainst: void 0
|
|
365
|
+
verifyAgainst: void 0,
|
|
366
|
+
inbound: void 0
|
|
330
367
|
});
|
|
331
368
|
}
|
|
332
369
|
function resolveInbound(peer, inbound, encoding) {
|
|
@@ -343,6 +380,7 @@ function buildMllpAck(inbound, options) {
|
|
|
343
380
|
const peer = loadHl7Peer();
|
|
344
381
|
assertKnownAckCode(peer, options.code);
|
|
345
382
|
const encoding = resolveEncoding(inbound, options);
|
|
383
|
+
assertSerializableAckEncoding(encoding);
|
|
346
384
|
let msg;
|
|
347
385
|
try {
|
|
348
386
|
msg = resolveInbound(peer, inbound, encoding);
|
|
@@ -374,7 +412,8 @@ function buildMllpAck(inbound, options) {
|
|
|
374
412
|
warnings,
|
|
375
413
|
options,
|
|
376
414
|
encoding,
|
|
377
|
-
verifyAgainst: inboundBytes(inbound, encoding)
|
|
415
|
+
verifyAgainst: inboundBytes(inbound, encoding),
|
|
416
|
+
inbound
|
|
378
417
|
});
|
|
379
418
|
}
|
|
380
419
|
function buildAckAA(inbound, options) {
|
|
@@ -402,6 +441,7 @@ function detectMode(inbound) {
|
|
|
402
441
|
}
|
|
403
442
|
|
|
404
443
|
exports.MLLP_ACK_CONTROL_ID_NOT_VERBATIM = MLLP_ACK_CONTROL_ID_NOT_VERBATIM;
|
|
444
|
+
exports.MLLP_ACK_CONTROL_ID_UNVERIFIABLE = MLLP_ACK_CONTROL_ID_UNVERIFIABLE;
|
|
405
445
|
exports.MLLP_ACK_INBOUND_UNPARSEABLE = MLLP_ACK_INBOUND_UNPARSEABLE;
|
|
406
446
|
exports.MllpPeerMissingError = MllpPeerMissingError;
|
|
407
447
|
exports.buildAckAA = buildAckAA;
|