@cosyte/mllp 0.0.1
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 +529 -0
- package/LICENSE +21 -0
- package/README.md +113 -0
- package/dist/ack-from-hl7/index.cjs +417 -0
- package/dist/ack-from-hl7/index.cjs.map +1 -0
- package/dist/ack-from-hl7/index.d.cts +425 -0
- package/dist/ack-from-hl7/index.d.ts +425 -0
- package/dist/ack-from-hl7/index.mjs +400 -0
- package/dist/ack-from-hl7/index.mjs.map +1 -0
- package/dist/index-DjGQJtYE.d.cts +83 -0
- package/dist/index-DjGQJtYE.d.ts +83 -0
- package/dist/index.cjs +3455 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3112 -0
- package/dist/index.d.ts +3112 -0
- package/dist/index.mjs +3428 -0
- package/dist/index.mjs.map +1 -0
- package/dist/testing/index.cjs +243 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +174 -0
- package/dist/testing/index.d.ts +174 -0
- package/dist/testing/index.mjs +241 -0
- package/dist/testing/index.mjs.map +1 -0
- package/package.json +124 -0
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
import { AckCode, AckErrorDetail, Hl7Message, AckMode, BuildAckOptions, Hl7ParseError, FATAL_CODES, ACK_CODES } from '@cosyte/hl7';
|
|
2
|
+
export { AckCode, AckErrorDetail, AckMode } from '@cosyte/hl7';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `buildMllpAck` — a THIN transport adapter over `@cosyte/hl7`'s `buildAck`.
|
|
6
|
+
*
|
|
7
|
+
* `@cosyte/hl7` owns ACK **content** (MSH/MSA/ERR construction, the fail-safe
|
|
8
|
+
* no-correlation downgrade); this module owns **transport policy**: accepting
|
|
9
|
+
* raw inbound bytes (or an already-parsed message), tolerating an unparseable
|
|
10
|
+
* inbound without ever fabricating a positive disposition, and framing the
|
|
11
|
+
* result into a ready-to-write MLLP `Buffer` via `encodeFrame`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* import { buildAckAA } from '@cosyte/mllp/ack-from-hl7';
|
|
16
|
+
* const { frame } = buildAckAA(inboundBuffer);
|
|
17
|
+
* socket.write(frame);
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @packageDocumentation
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A single ACK-generation warning, surfaced by {@link buildMllpAck}.
|
|
25
|
+
*
|
|
26
|
+
* `code` is either an upstream `@cosyte/hl7` warning code passed through
|
|
27
|
+
* verbatim (e.g. `"ACK_NO_CORRELATION_ID"`) or the one `mllp`-owned code,
|
|
28
|
+
* {@link MLLP_ACK_INBOUND_UNPARSEABLE}.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* import { buildAckAA } from '@cosyte/mllp/ack-from-hl7';
|
|
33
|
+
* const { warnings } = buildAckAA(inbound);
|
|
34
|
+
* for (const w of warnings) console.warn(w.code, w.message);
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
interface MllpAckWarning {
|
|
38
|
+
readonly code: string;
|
|
39
|
+
readonly message: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Warning code emitted when the inbound message could not be parsed at all
|
|
43
|
+
* (a fatal `Hl7ParseError`) and {@link buildMllpAck} fell back to a minimal,
|
|
44
|
+
* uncorrelated ACK rather than fabricating a positive disposition.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```typescript
|
|
48
|
+
* import { MLLP_ACK_INBOUND_UNPARSEABLE, buildAckAA } from '@cosyte/mllp/ack-from-hl7';
|
|
49
|
+
* const { warnings } = buildAckAA("not hl7 at all");
|
|
50
|
+
* warnings.some((w) => w.code === MLLP_ACK_INBOUND_UNPARSEABLE); // true
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
declare const MLLP_ACK_INBOUND_UNPARSEABLE = "MLLP_ACK_INBOUND_UNPARSEABLE";
|
|
54
|
+
/**
|
|
55
|
+
* Warning code emitted when the built ACK's MSA-2 bytes are **not** byte-identical
|
|
56
|
+
* to the inbound MSH-10 bytes — i.e. the ACK does not echo the message control ID
|
|
57
|
+
* verbatim, as HL7 v2.5.1 §2.9.2.2 requires.
|
|
58
|
+
*
|
|
59
|
+
* This is a **correlation failure**, and the reason it is a loud warning rather
|
|
60
|
+
* than a silent success: the sender keys its in-flight store on the MSH-10 bytes
|
|
61
|
+
* it put on the wire. An ACK whose MSA-2 differs by even one byte will not match
|
|
62
|
+
* that key, so the send is never settled → ACK timeout → resend → **duplicate
|
|
63
|
+
* clinical message**. Emitting the ACK anyway (rather than throwing) is the
|
|
64
|
+
* fail-safe choice — a mismatched ACK still tells the peer *something* — but the
|
|
65
|
+
* mismatch must never pass unremarked.
|
|
66
|
+
*
|
|
67
|
+
* `buildMllpAck` verifies this on every build, against the very same byte-level
|
|
68
|
+
* scanners the `@cosyte/mllp` client uses to correlate (`src/internal/control-id.ts`).
|
|
69
|
+
*
|
|
70
|
+
* **The verification is meaningful for a `Buffer` inbound, and only for a `Buffer`.**
|
|
71
|
+
* A `Buffer` *is* the wire bytes, so comparing the ACK to it is a real byte-level check
|
|
72
|
+
* and a clean result means a `@cosyte/mllp` sender will match this ACK. A
|
|
73
|
+
* `string`/`Hl7Message` inbound has **already been decoded** before this module sees it:
|
|
74
|
+
* the only thing left to compare against is that same text, encoded with the same codec,
|
|
75
|
+
* so the codec cancels on both sides and a codec-induced mismatch is **structurally
|
|
76
|
+
* invisible** — it warns about nothing. See {@link BuildMllpAckOptions.encoding}. Pass a
|
|
77
|
+
* `Buffer` if you want this guarantee to mean anything.
|
|
78
|
+
*
|
|
79
|
+
* Two known ways to provoke it, both documented in the package limitations:
|
|
80
|
+
*
|
|
81
|
+
* 1. Overriding {@link BuildMllpAckOptions.encoding} to a codec that cannot
|
|
82
|
+
* round-trip the inbound bytes (`"utf8"`/`"ascii"` against a high-bit,
|
|
83
|
+
* 8859/1-charset control ID). The default never does this.
|
|
84
|
+
* 2. An inbound that declares **non-default encoding characters** (MSH-1/MSH-2).
|
|
85
|
+
* `@cosyte/hl7`'s `buildMessage` always emits the HL7 default `|^~\&`, so an
|
|
86
|
+
* inbound MSH-10 of `ID#X` under a `#` component separator is re-delimited to
|
|
87
|
+
* `ID^X` in MSA-2 — different bytes, unmatchable key. Use `buildRawAck` (root
|
|
88
|
+
* export), which echoes the inbound's own MSH-1/MSH-2, if you must serve such
|
|
89
|
+
* a peer.
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ```typescript
|
|
93
|
+
* import { MLLP_ACK_CONTROL_ID_NOT_VERBATIM, buildAckAA } from '@cosyte/mllp/ack-from-hl7';
|
|
94
|
+
* const { warnings } = buildAckAA(inbound, { encoding: "ascii" });
|
|
95
|
+
* if (warnings.some((w) => w.code === MLLP_ACK_CONTROL_ID_NOT_VERBATIM)) {
|
|
96
|
+
* // this ACK will NOT correlate at the sender — investigate before shipping it
|
|
97
|
+
* }
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
declare const MLLP_ACK_CONTROL_ID_NOT_VERBATIM = "MLLP_ACK_CONTROL_ID_NOT_VERBATIM";
|
|
101
|
+
/**
|
|
102
|
+
* Options for {@link buildMllpAck} and its six convenience wrappers.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* import type { BuildMllpAckOptions } from '@cosyte/mllp/ack-from-hl7';
|
|
107
|
+
* const opts: BuildMllpAckOptions = { code: "AE", error: { conditionCode: "101" } };
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
interface BuildMllpAckOptions {
|
|
111
|
+
/** Required acknowledgment disposition to emit in MSA-1 (HL7 Table 0008). */
|
|
112
|
+
readonly code: AckCode;
|
|
113
|
+
/** Optional error detail; one entry emits one ERR segment. */
|
|
114
|
+
readonly error?: AckErrorDetail | readonly AckErrorDetail[];
|
|
115
|
+
/**
|
|
116
|
+
* The codec used to move the ACK between bytes and text — **both** directions,
|
|
117
|
+
* as a single symmetric choice. It decodes a raw-`Buffer` `inbound` on the way in
|
|
118
|
+
* and encodes the serialized ACK on the way out, so the ACK is emitted in the same
|
|
119
|
+
* codec the inbound was read in.
|
|
120
|
+
*
|
|
121
|
+
* That symmetry is the whole point, and it is what makes MSA-2 echo MSH-10
|
|
122
|
+
* **verbatim** (HL7 v2.5.1 §2.9.2.2). Decoding in one codec and encoding in another
|
|
123
|
+
* corrupts every non-ASCII byte it round-trips: a `latin1`-decoded `0x8B` re-encoded
|
|
124
|
+
* as `utf8` goes out as the two bytes `0xC2 0x8B`, which is a *different control ID*
|
|
125
|
+
* — and the sender, which keyed its in-flight store on `0x8B`, cannot match the ACK.
|
|
126
|
+
*
|
|
127
|
+
* **Defaults, by inbound type:**
|
|
128
|
+
*
|
|
129
|
+
* - `Buffer` → **`"latin1"`**. We own the decode, and `latin1` is the only codec
|
|
130
|
+
* that round-trips arbitrary bytes losslessly, so MSA-2 is byte-verbatim for any
|
|
131
|
+
* charset — including an MSH-18 of `8859/1` with high-bit bytes in the control ID.
|
|
132
|
+
* - `string` / `Hl7Message` → **`"utf8"`**. The caller already decoded; we re-encode
|
|
133
|
+
* with the JS-native codec.
|
|
134
|
+
*
|
|
135
|
+
* **Override with care, and only on a `Buffer`.** Any value other than `"latin1"` on a
|
|
136
|
+
* raw-`Buffer` inbound gives up the verbatim guarantee for non-ASCII bytes (`"ascii"`
|
|
137
|
+
* masks the high bit; `"utf8"` folds invalid sequences onto `U+FFFD`). On a `Buffer`,
|
|
138
|
+
* `buildMllpAck` **checks** the result and emits {@link MLLP_ACK_CONTROL_ID_NOT_VERBATIM}
|
|
139
|
+
* if the echo did not survive, so a bad override there is loud rather than silent — but
|
|
140
|
+
* it is still a broken ACK. Set this only when the receiving system genuinely demands a
|
|
141
|
+
* specific codec.
|
|
142
|
+
*
|
|
143
|
+
* **On a `string` / `Hl7Message` inbound the check cannot see a codec problem at all.**
|
|
144
|
+
* The wire bytes were decoded to text *before* this function saw them, so there is
|
|
145
|
+
* nothing left to compare the ACK against except that same text — the codec cancels on
|
|
146
|
+
* both sides and the comparison is a tautology. Concretely,
|
|
147
|
+
* `buildAckAA(payload.toString("latin1"))` on a high-bit control ID (`0x8B`, legal under
|
|
148
|
+
* an `MSH-18` of `8859/1`) re-encodes it as the two `utf8` bytes `0xC2 0x8B`, emits a
|
|
149
|
+
* **different** control ID, and warns about **nothing** — the sender cannot correlate it.
|
|
150
|
+
* This is not a hole the guard can be grown to cover; the bytes are gone by then.
|
|
151
|
+
*
|
|
152
|
+
* **`Buffer` is the byte-safe path.** Pass the raw payload. It is what the server hands
|
|
153
|
+
* you, it is what the `Buffer`-first API rule exists for, and it is the only input for
|
|
154
|
+
* which the verbatim guarantee — or a warning that it broke — actually means anything.
|
|
155
|
+
*/
|
|
156
|
+
readonly encoding?: BufferEncoding;
|
|
157
|
+
/**
|
|
158
|
+
* Passthrough to `encodeFrame`'s `allowDelimiterBytesInPayload`. Defaults
|
|
159
|
+
* to `false` (strict — throws if the serialized ACK somehow contains a
|
|
160
|
+
* VT/FS byte, which a spec-clean `@cosyte/hl7` emit never does).
|
|
161
|
+
*/
|
|
162
|
+
readonly allowDelimiterBytesInPayload?: boolean;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Result of {@link buildMllpAck} — a ready-to-write MLLP frame plus the
|
|
166
|
+
* metadata needed to log or assert on what was actually emitted. Frozen
|
|
167
|
+
* (including the `warnings` array) so subscribers cannot mutate shared state.
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```typescript
|
|
171
|
+
* import { buildAckAA } from '@cosyte/mllp/ack-from-hl7';
|
|
172
|
+
* const ack = buildAckAA(inbound);
|
|
173
|
+
* socket.write(ack.frame);
|
|
174
|
+
* console.log(ack.code, ack.correlationId);
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
interface MllpAck {
|
|
178
|
+
/** `VT + payload + FS + CR`, ready to write to a socket. */
|
|
179
|
+
readonly frame: Buffer;
|
|
180
|
+
/** The serialized ACK, unframed. */
|
|
181
|
+
readonly payload: Buffer;
|
|
182
|
+
/** The built ACK `Hl7Message`. */
|
|
183
|
+
readonly ack: Hl7Message;
|
|
184
|
+
/** The disposition the caller asked for. */
|
|
185
|
+
readonly requestedCode: AckCode;
|
|
186
|
+
/** The disposition MSA-1 actually carries (post fail-safe downgrade). */
|
|
187
|
+
readonly code: AckCode;
|
|
188
|
+
/** Inbound MSH-10, echoed in MSA-2. `undefined` when unfindable. */
|
|
189
|
+
readonly correlationId: string | undefined;
|
|
190
|
+
/** Detected from inbound MSH-15/16. `undefined` when inbound unparseable. */
|
|
191
|
+
readonly mode: AckMode | undefined;
|
|
192
|
+
/** Warnings collected while building the ACK. */
|
|
193
|
+
readonly warnings: readonly MllpAckWarning[];
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Build a framed MLLP ACK from an inbound HL7 v2 message — the core
|
|
197
|
+
* `ack-from-hl7` adapter. `inbound` may be an already-parsed `Hl7Message`, or
|
|
198
|
+
* raw bytes/text to parse first.
|
|
199
|
+
*
|
|
200
|
+
* Behavior:
|
|
201
|
+
* - **Fatally unparseable inbound** (`Hl7ParseError`) — never emits a
|
|
202
|
+
* positive code: `AA`→`AE`, `CA`→`CE`; other codes pass through. MSA-2 is
|
|
203
|
+
* empty, `correlationId` and `mode` are `undefined`, and `warnings`
|
|
204
|
+
* contains one {@link MLLP_ACK_INBOUND_UNPARSEABLE} entry naming the fatal
|
|
205
|
+
* code — never any inbound payload bytes.
|
|
206
|
+
* - **Normal path** — detects the ack mode from inbound MSH-15/16, delegates
|
|
207
|
+
* to `@cosyte/hl7`'s `buildAck` (which applies its own no-correlation
|
|
208
|
+
* fail-safe), and forwards `buildAck`'s own warnings (mapped to
|
|
209
|
+
* `{ code, message }`). Inbound parse warnings are NOT forwarded — they are
|
|
210
|
+
* the caller's concern if they parsed the inbound themselves.
|
|
211
|
+
*
|
|
212
|
+
* @throws {MllpPeerMissingError} when `@cosyte/hl7` is not installed.
|
|
213
|
+
* @throws {TypeError} when `options.code` is not a known HL7 Table 0008 code.
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* ```typescript
|
|
217
|
+
* import { buildMllpAck } from '@cosyte/mllp/ack-from-hl7';
|
|
218
|
+
* const ack = buildMllpAck(inboundBuffer, { code: "AA" });
|
|
219
|
+
* socket.write(ack.frame);
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
declare function buildMllpAck(inbound: Hl7Message | Buffer | string, options: BuildMllpAckOptions): MllpAck;
|
|
223
|
+
/**
|
|
224
|
+
* Build an `AA` (Application Accept) MLLP ACK.
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```typescript
|
|
228
|
+
* import { buildAckAA } from '@cosyte/mllp/ack-from-hl7';
|
|
229
|
+
* socket.write(buildAckAA(inboundBuffer).frame);
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
declare function buildAckAA(inbound: Hl7Message | Buffer | string, options?: Omit<BuildMllpAckOptions, "code">): MllpAck;
|
|
233
|
+
/**
|
|
234
|
+
* Build an `AE` (Application Error) MLLP ACK.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```typescript
|
|
238
|
+
* import { buildAckAE } from '@cosyte/mllp/ack-from-hl7';
|
|
239
|
+
* socket.write(buildAckAE(inboundBuffer, { error: { conditionCode: "101" } }).frame);
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
declare function buildAckAE(inbound: Hl7Message | Buffer | string, options?: Omit<BuildMllpAckOptions, "code">): MllpAck;
|
|
243
|
+
/**
|
|
244
|
+
* Build an `AR` (Application Reject) MLLP ACK.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* ```typescript
|
|
248
|
+
* import { buildAckAR } from '@cosyte/mllp/ack-from-hl7';
|
|
249
|
+
* socket.write(buildAckAR(inboundBuffer, { error: { conditionCode: "200" } }).frame);
|
|
250
|
+
* ```
|
|
251
|
+
*/
|
|
252
|
+
declare function buildAckAR(inbound: Hl7Message | Buffer | string, options?: Omit<BuildMllpAckOptions, "code">): MllpAck;
|
|
253
|
+
/**
|
|
254
|
+
* Build a `CA` (Commit Accept) MLLP ACK (enhanced mode).
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* ```typescript
|
|
258
|
+
* import { buildAckCA } from '@cosyte/mllp/ack-from-hl7';
|
|
259
|
+
* socket.write(buildAckCA(inboundBuffer).frame);
|
|
260
|
+
* ```
|
|
261
|
+
*/
|
|
262
|
+
declare function buildAckCA(inbound: Hl7Message | Buffer | string, options?: Omit<BuildMllpAckOptions, "code">): MllpAck;
|
|
263
|
+
/**
|
|
264
|
+
* Build a `CE` (Commit Error) MLLP ACK (enhanced mode).
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```typescript
|
|
268
|
+
* import { buildAckCE } from '@cosyte/mllp/ack-from-hl7';
|
|
269
|
+
* socket.write(buildAckCE(inboundBuffer, { error: { conditionCode: "101" } }).frame);
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
declare function buildAckCE(inbound: Hl7Message | Buffer | string, options?: Omit<BuildMllpAckOptions, "code">): MllpAck;
|
|
273
|
+
/**
|
|
274
|
+
* Build a `CR` (Commit Reject) MLLP ACK (enhanced mode).
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```typescript
|
|
278
|
+
* import { buildAckCR } from '@cosyte/mllp/ack-from-hl7';
|
|
279
|
+
* socket.write(buildAckCR(inboundBuffer, { error: { conditionCode: "200" } }).frame);
|
|
280
|
+
* ```
|
|
281
|
+
*/
|
|
282
|
+
declare function buildAckCR(inbound: Hl7Message | Buffer | string, options?: Omit<BuildMllpAckOptions, "code">): MllpAck;
|
|
283
|
+
/**
|
|
284
|
+
* Detect the HL7 acknowledgment mode (`"original"` vs `"enhanced"`) of an
|
|
285
|
+
* inbound message, from MSH-15/16. Named `detectMode` (not `detectAckMode`)
|
|
286
|
+
* to avoid colliding with the peer's own `detectAckMode` export for callers
|
|
287
|
+
* who import both from `@cosyte/hl7` and `@cosyte/mllp/ack-from-hl7`.
|
|
288
|
+
*
|
|
289
|
+
* `inbound` may be an already-parsed `Hl7Message`, or raw bytes/text to parse
|
|
290
|
+
* first. A fatal parse failure rethrows the `Hl7ParseError` as-is — unlike
|
|
291
|
+
* {@link buildMllpAck}, there is no ACK to build here, so there is no
|
|
292
|
+
* fallback to construct.
|
|
293
|
+
*
|
|
294
|
+
* **Module-realm note:** this adapter loads `@cosyte/hl7` lazily via
|
|
295
|
+
* `createRequire` (see `peer.ts`). If your code ALSO does
|
|
296
|
+
* `import { Hl7ParseError } from "@cosyte/hl7"` directly, Node's module
|
|
297
|
+
* resolution can — depending on your bundler/runtime — hand you a distinct
|
|
298
|
+
* module instance than the one this adapter loaded, in which case
|
|
299
|
+
* `caught instanceof Hl7ParseError` (your import) may be `false` even though
|
|
300
|
+
* `caught.name === "Hl7ParseError"` and `caught.code` is a valid HL7 fatal
|
|
301
|
+
* code (`NO_MSH_SEGMENT` / `MSH_TOO_SHORT` / `INVALID_ENCODING_CHARACTERS` /
|
|
302
|
+
* `EMPTY_INPUT`). Prefer narrowing on `.code`/`.name`, or obtain the exact
|
|
303
|
+
* class via this subpath's own `loadHl7Peer().Hl7ParseError`.
|
|
304
|
+
*
|
|
305
|
+
* @throws {MllpPeerMissingError} when `@cosyte/hl7` is not installed.
|
|
306
|
+
* @throws {Hl7ParseError} when `inbound` is raw bytes/text that fails to parse.
|
|
307
|
+
*
|
|
308
|
+
* @example
|
|
309
|
+
* ```typescript
|
|
310
|
+
* import { detectMode } from '@cosyte/mllp/ack-from-hl7';
|
|
311
|
+
* detectMode(inboundBuffer); // "original" | "enhanced"
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
declare function detectMode(inbound: Hl7Message | Buffer | string): AckMode;
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Lazy loader for the optional `@cosyte/hl7` peer dependency.
|
|
318
|
+
*
|
|
319
|
+
* `@cosyte/mllp` ships **zero runtime dependencies**; `@cosyte/hl7` is an
|
|
320
|
+
* optional peer dep referenced only from this `/ack-from-hl7` subpath. To keep
|
|
321
|
+
* the rest of the package fully dependency-free, the peer is required lazily —
|
|
322
|
+
* on first call into `ack-from-hl7` — via `createRequire`, not at module load
|
|
323
|
+
* time. The public API of this subpath stays synchronous throughout.
|
|
324
|
+
*
|
|
325
|
+
* @example
|
|
326
|
+
* ```typescript
|
|
327
|
+
* import { loadHl7Peer } from '@cosyte/mllp/ack-from-hl7';
|
|
328
|
+
* const hl7 = loadHl7Peer(); // throws MllpPeerMissingError if not installed
|
|
329
|
+
* ```
|
|
330
|
+
*
|
|
331
|
+
* @packageDocumentation
|
|
332
|
+
*/
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* The subset of the `@cosyte/hl7` runtime surface the `ack-from-hl7` adapter
|
|
336
|
+
* consumes. Kept narrow and typed via `import type` (erased at compile time)
|
|
337
|
+
* so the runtime dependency stays fully lazy — only the shape is known
|
|
338
|
+
* statically, the values are resolved via `require()` at first call.
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* ```typescript
|
|
342
|
+
* import type { Hl7Peer } from '@cosyte/mllp/ack-from-hl7';
|
|
343
|
+
* function useAck(peer: Hl7Peer) {
|
|
344
|
+
* return peer.buildAck;
|
|
345
|
+
* }
|
|
346
|
+
* ```
|
|
347
|
+
*/
|
|
348
|
+
interface Hl7Peer {
|
|
349
|
+
readonly parseHL7: (raw: string | Buffer) => Hl7Message;
|
|
350
|
+
readonly buildAck: (inbound: Hl7Message, options: BuildAckOptions) => Hl7Message;
|
|
351
|
+
readonly detectAckMode: (inbound: Hl7Message) => "original" | "enhanced";
|
|
352
|
+
readonly buildMessage: (init: {
|
|
353
|
+
readonly type: string;
|
|
354
|
+
}) => Hl7Message;
|
|
355
|
+
/**
|
|
356
|
+
* The peer's own `Hl7Message` class. Exposed (not just used as a type) so
|
|
357
|
+
* callers can detect a cross-realm instance — see the dual-package-hazard
|
|
358
|
+
* note on `resolveInbound` in `build.ts`. Typed as `abstract new` (rather
|
|
359
|
+
* than a concrete constructor signature) purely so TypeScript accepts it as
|
|
360
|
+
* an `instanceof` right-hand side without also implying callers can `new`
|
|
361
|
+
* it directly with arbitrary args.
|
|
362
|
+
*/
|
|
363
|
+
readonly Hl7Message: abstract new (...args: never[]) => Hl7Message;
|
|
364
|
+
readonly Hl7ParseError: typeof Hl7ParseError;
|
|
365
|
+
readonly FATAL_CODES: typeof FATAL_CODES;
|
|
366
|
+
readonly ACK_CODES: typeof ACK_CODES;
|
|
367
|
+
/**
|
|
368
|
+
* The peer's fail-safe downgrade primitive (`AA`→`AE`, `CA`→`CE`, everything
|
|
369
|
+
* else unchanged) — the single upstream source of truth for the pair; this
|
|
370
|
+
* adapter never carries its own copy of the mapping.
|
|
371
|
+
*/
|
|
372
|
+
readonly downgradePositiveAck: (code: AckCode) => AckCode;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Thrown when `@cosyte/hl7` — the optional peer dependency required by
|
|
376
|
+
* `@cosyte/mllp/ack-from-hl7` — cannot be resolved at runtime.
|
|
377
|
+
*
|
|
378
|
+
* `@cosyte/hl7` is declared as an optional peer dependency, so a consumer of
|
|
379
|
+
* the root `@cosyte/mllp` entry point is never forced to install it. Only
|
|
380
|
+
* code that imports from the `/ack-from-hl7` subpath needs it, and only once
|
|
381
|
+
* that code actually runs (the loader is lazy).
|
|
382
|
+
*
|
|
383
|
+
* @example
|
|
384
|
+
* ```typescript
|
|
385
|
+
* import { buildAckAA, MllpPeerMissingError } from '@cosyte/mllp/ack-from-hl7';
|
|
386
|
+
* try {
|
|
387
|
+
* buildAckAA(inboundBuffer);
|
|
388
|
+
* } catch (err) {
|
|
389
|
+
* if (err instanceof MllpPeerMissingError) {
|
|
390
|
+
* console.error(err.message); // explains how to install @cosyte/hl7
|
|
391
|
+
* }
|
|
392
|
+
* }
|
|
393
|
+
* ```
|
|
394
|
+
*/
|
|
395
|
+
declare class MllpPeerMissingError extends Error {
|
|
396
|
+
readonly name: "MllpPeerMissingError";
|
|
397
|
+
/** Stable machine-readable code identifying this error class. */
|
|
398
|
+
readonly code: "MLLP_PEER_MISSING";
|
|
399
|
+
/**
|
|
400
|
+
* Construct an `MllpPeerMissingError`.
|
|
401
|
+
*
|
|
402
|
+
* @param cause - The original module-resolution error, preserved for debugging.
|
|
403
|
+
*/
|
|
404
|
+
constructor(cause: unknown);
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Load the `@cosyte/hl7` peer module, caching the result for subsequent
|
|
408
|
+
* calls. The public adapter functions in `build.ts` call this internally —
|
|
409
|
+
* most consumers never call it directly.
|
|
410
|
+
*
|
|
411
|
+
* @param requireFn - Injectable `require`-like function, used by tests to
|
|
412
|
+
* simulate a missing peer without actually uninstalling it. Defaults to a
|
|
413
|
+
* real `createRequire(import.meta.url)`.
|
|
414
|
+
* @internal
|
|
415
|
+
*
|
|
416
|
+
* @example
|
|
417
|
+
* ```typescript
|
|
418
|
+
* import { loadHl7Peer } from '@cosyte/mllp/ack-from-hl7';
|
|
419
|
+
* const hl7 = loadHl7Peer();
|
|
420
|
+
* const ack = hl7.buildAck(hl7.parseHL7(raw), { code: "AA" });
|
|
421
|
+
* ```
|
|
422
|
+
*/
|
|
423
|
+
declare function loadHl7Peer(requireFn?: (id: string) => unknown): Hl7Peer;
|
|
424
|
+
|
|
425
|
+
export { type BuildMllpAckOptions, type Hl7Peer, MLLP_ACK_CONTROL_ID_NOT_VERBATIM, MLLP_ACK_INBOUND_UNPARSEABLE, type MllpAck, type MllpAckWarning, MllpPeerMissingError, buildAckAA, buildAckAE, buildAckAR, buildAckCA, buildAckCE, buildAckCR, buildMllpAck, detectMode, loadHl7Peer };
|