Skip to main content
Version: v0.0.10

@cosyte/hl7

Namespaces​

Classes​

Field​

Wrapper over a RawField exposing HL7 null/empty discrimination (isNull), the repetitions tree, and a decoded value getter. seg.field(3) === seg.field(3): Field instances are referentially stable per segment position (D-12).

Example​

import { parseHL7 } from "@cosyte/hl7";
const msg = parseHL7(raw);
const pid5 = msg.segments("PID")[0]?.field(5);
console.log(pid5?.value); // "Smith": decoded at parse
console.log(pid5?.isNull); // false: HL7 explicit null is "", absent is not
console.log(pid5?.repetitions.length); // 1

Constructors​

Constructor​

new Field(raw, enc, position): Field

Internal

Construct a new Field. Called internally by Segment.field(n); user code should obtain Field instances via msg.segments(type)[i].field(n).

Parameters​
raw​

RawField

enc​

EncodingCharacters

position​

Hl7Position

Returns​

Field

Properties​

enc​

readonly enc: EncodingCharacters

Internal

The 5 encoding characters for this message. Exposed for composite parsers.

isNull​

readonly isNull: boolean

HL7 null indicator: true iff the underlying field was the two-char literal "".

position​

readonly position: Hl7Position

Internal

Position of this field in the parent message: used for position-aware error messages.

raw​

readonly raw: RawField

Internal

The full RawField this wrapper wraps. Exposed for composite parsers.

repetitions​

readonly repetitions: readonly RawRepetition[]

Reference to the underlying RawField.repetitions (no defensive copy).

Accessors​

text​
Get Signature​

get text(): string

The field's canonical wire text: the full field re-serialized with the active delimiters and re-escaped content (repetitions, components, and subcomponents included). Contrast with value, which returns only the first subcomponent of the first component of the first repetition (decoded once at parse: never re-unescaped).

Use this when a field must be compared or echoed as a whole: e.g. correlating an ACK's MSA-2 against the inbound MSH-10, where a vendor-quirk control id containing an unescaped delimiter (ID^X) must not be truncated to its first component.

Byte-verbatim for parsed content. The parse pipeline stores decoded content, but also records the original wire bytes of any escape whose decode is not byte-faithful (RawComponent.rawSubcomponents), so re-serialization preserves the sender's exact escape bytes: hex escapes stay hex (A\X41\B, casing intact), and recognize-and-preserve sequences (\H\, \N, formatting/charset/vendor escapes) re-emit verbatim rather than as escaped literal text. Delimiter/newline escapes and plain content round-trip byte-exact via the re-escape path. The only remaining canonicalization is structural: trailing insignificant empties are stripped (D-02), and a field built by hand (not parsed) re-escapes its decoded value since it has no overlay.

MSH-1/MSH-2 caveat. Like value, calling this on MSH-1 or MSH-2 (the delimiter-definition fields) re-escapes the encoding characters themselves and produces garbage: those two fields are only meaningful through Hl7Message.encodingCharacters.

Example​
import { parseHL7 } from "@cosyte/hl7";
const msg = parseHL7("MSH|^~\\&|A|B|C|D|20260101||ADT^A01|ID^X|P|2.5\r");
msg.segments("MSH")[0]?.field(10).value; // "ID" (first component only)
msg.segments("MSH")[0]?.field(10).text; // "ID^X" (verbatim wire text)
Returns​

string

value​
Get Signature​

get value(): string

First-repetition, first-component, first-subcomponent value as a decoded string: unescaped ONCE by the tokenizer on parse, returned verbatim here (never re-unescaped). Returns "" when the field is empty or HL7 null. Equivalent to msg.get('SEG.N') for a top-level access.

Example​
const pid5 = msg.segments("PID")[0]?.field(5);
// wire "Smith\F\Jr" was decoded at parse → the field separator escape:
console.log(pid5?.value); // "Smith|Jr"
Returns​

string

Methods​

asCe()​

asCe(): CE

Coerce this field's first repetition to a typed CE (Coded Element).

Returns​

CE

Example​
const code = msg.segments("OBX")[0]?.field(3)?.asCe();
console.log(code?.identifier, code?.text);
asCwe()​

asCwe(): CWE

Coerce this field's first repetition to a typed CWE (Coded With Exceptions).

Returns​

CWE

Example​
const code = msg.segments("OBX")[0]?.field(3)?.asCwe();
console.log(code?.identifier, code?.text);
asCx()​

asCx(): CX

Coerce this field's first repetition to a typed CX (Extended Composite ID). assigningAuthority is a nested HD.

Returns​

CX

Example​
const mrn = msg.segments("PID")[0]?.field(3)?.asCx();
console.log(mrn?.idNumber, mrn?.assigningAuthority?.namespaceId);
asHd()​

asHd(): HD

Coerce this field's first repetition to a typed HD (Hierarchic Designator).

Returns​

HD

Example​
const sending = msg.segments("MSH")[0]?.field(3)?.asHd();
console.log(sending?.namespaceId);
asNm()​

asNm(): NM

Coerce this field's first repetition to a typed NM (Numeric). { raw, value }: value is undefined on non-numeric input.

Returns​

NM

Example​
const nm = msg.segments("OBX")[0]?.field(5)?.asNm();
console.log(nm?.value);
asPl()​

asPl(): PL

Coerce this field's first repetition to a typed PL (Person Location). facility is a nested HD.

Returns​

PL

Example​
const loc = msg.segments("PV1")[0]?.field(3)?.asPl();
console.log(loc?.pointOfCare, loc?.room, loc?.facility?.namespaceId);
asSn()​

asSn(): SN | undefined

Coerce this field's first repetition to a typed SN (Structured Numeric), or undefined when the field carries no usable structured-numeric content. Use for an OBX-5 whose OBX-2 value type is SN (a comparator like >90, a range like 100-200, or a ratio like 1:128). num1/num2 are number | undefined (never NaN); the comparator is surfaced only when SN.1 is a recognized operator.

Returns​

SN | undefined

Example​
const sn = msg.segments("OBX")[0]?.field(5)?.asSn();
console.log(sn?.comparator, sn?.num1); // ">" 90
asTs()​

asTs(): DtmParts

Coerce this field's first repetition to a typed TS (Time Stamp): the fidelity DtmParts (raw + parts + precision + timezone). valid is false on unparseable input (no throw). Build an absolute instant only on explicit request via dtmToDate(ts).

Returns​

DtmParts

Example​
const ts = msg.segments("MSH")[0]?.field(7)?.asTs();
console.log(ts?.raw, ts?.precision, ts?.hasTimezone);
asXad()​

asXad(): XAD

Coerce this field's first repetition to a typed XAD (Extended Address).

Returns​

XAD

Example​
const addr = msg.segments("PID")[0]?.field(11)?.asXad();
console.log(addr?.street, addr?.city, addr?.stateOrProvince);
asXcn()​

asXcn(): XCN

Coerce this field's first repetition to a typed XCN (Extended Composite ID Number and Name for Persons). assigningAuthority is a nested HD. Common on OBR-16 (ordering provider), PV1-7 (attending doctor), PV1-8 (referring doctor). Empty field → {} (never throws).

Returns​

XCN

Example​
const orderedBy = msg.segments("OBR")[0]?.field(16)?.asXcn();
console.log(orderedBy?.idNumber, orderedBy?.familyName, orderedBy?.identifierTypeCode);
asXpn()​

asXpn(): XPN

Coerce this field's first repetition to a typed XPN (Extended Person Name). Absent components are OMITTED from the result (exactOptionalPropertyTypes). Not memoized in v1: each call re-parses (D-09).

Returns​

XPN

Example​
const pid5 = msg.segments("PID")[0]?.field(5);
const name = pid5?.asXpn();
console.log(name?.familyName, name?.givenName);
asXtn()​

asXtn(): XTN

Coerce this field's first repetition to a typed XTN (Extended Telecommunication Number).

Returns​

XTN

Example​
const phone = msg.segments("PID")[0]?.field(13)?.asXtn();
console.log(phone?.telephoneNumber);
render()​

render(opts?): RenderedText

Render this field's formatted text (HL7 v2 §2.7 highlight + formatting escapes) into a normalized RenderedText display model: plain text plus highlight-aware runs. A read projection over the field's byte-verbatim wire text: it never mutates the raw value, and it never fabricates (an unrenderable escape is preserved + flagged). Use this to surface a clinical narrative (an NTE / OBX-5 note) to a human without the raw \.br\ / \H sentinels.

Parameters​
opts?​

RenderTextOptions

see RenderTextOptions (e.g. a custom line-break string).

Returns​

RenderedText

the normalized display model.

Example​
const note = msg.segments("OBX")[0]?.field(5);
note?.render().text; // "Specimen received.\nGross exam normal."
empty()​

static empty(_enc): Field

Internal

Return a synthetic empty Field sentinel: used by Segment.field(n) to honor MODEL-05's "never throws on missing" contract. The returned Field has isNull === false, repetitions === [], and value === "". Referentially stable across calls (same instance returned each time).

The enc argument is accepted for API symmetry but ignored: the synthetic field carries no content, so unescape would be a no-op regardless of the active encoding characters.

Parameters​
_enc​

EncodingCharacters

Returns​

Field

Example​
const empty = Field.empty(msg.encodingCharacters);
console.log(empty.value); // ""

Hl7Message​

Parsed HL7 v2 message. Produced by parseHL7. Exposes the raw positional tree (rawSegments), delimiter metadata, warnings, and a typed traversal surface: get(path) for dot-paths, getAll(type) / segments(type) / allSegments() for wrapper-level iteration.

Remarks​

The warnings array is frozen at the model boundary so downstream traversal and helpers cannot mutate parser output. The profile field is populated when a profile is passed, and is undefined otherwise. Segment/Field wrappers are cached per-message and invalidated wholesale by the mutation methods.

Example​

import { parseHL7 } from "@cosyte/hl7";
const msg = parseHL7(raw);
console.log(msg.get("PID.5.1")); // "Smith"
for (const obx of msg.segments("OBX")) {
console.log(obx.field(5).value);
}
for (const w of msg.warnings) console.warn(w.code);

Constructors​

Constructor​

new Hl7Message(init): Hl7Message

Internal

Construct a new Hl7Message. The constructor takes a plain init object and freezes the warnings array so callers cannot mutate parser output after handoff.

Parameters​
init​

Hl7MessageInit

Returns​

Hl7Message

Properties​

dateFormats​

readonly dateFormats: readonly string[]

Merged dateFormats list: options.dateFormats ++ profile.dateFormats deduped first-occurrence per D-21. Empty array when neither source supplied any formats. Exposed publicly so helpers (msg.meta.timestamp) and advanced callers can introspect the active cascade.

encodingCharacters​

readonly encodingCharacters: EncodingCharacters

profile​

readonly profile: { lineage: readonly string[]; name: string; } | undefined

rawSegments​

readonly rawSegments: readonly RawSegment[]

Raw positional tree produced by the parser. 1-indexed per HL7 convention (fields[0] is the segment-name / MSH separator placeholder slot). Use segments(type) / allSegments() for typed wrapper access: this field is exposed for advanced callers that need the raw tree directly.

version​

readonly version: string

HL7 version the model asserts for this message, from MSH-12.1.1, e.g. "2.5" or "2.5.1".

Bounded, and it is "<withheld>" when MSH-12 does not hold a version. Same reasoning as Segment.type: it presents as an identifier and consumers label with it. meta.version keeps MSH-12 exactly as it arrived, and is what version-scoped field selection reads, so this bound changes no parsing behaviour.

warnings​

readonly warnings: readonly Hl7ParseWarning[]

Accessors​

meta​
Get Signature​

get meta(): Meta

MSH-derived message metadata (type, controlId, timestamp, version, etc.). D-01: plain object. D-02: memoized: msg.meta === msg.meta across reads until mutation invalidates. D-03: always defined (MSH absence throws NO_MSH_SEGMENT at parse time).

Example​
console.log(msg.meta.type); // "ADT^A01"
console.log(msg.meta.timestamp?.raw); // fidelity TS
console.log(msg.meta.controlId); // "MSG001"
Returns​

Meta

patient​
Get Signature​

get patient(): Patient | undefined

PID-derived patient view, or undefined when no PID segment exists (D-04). D-02: memoized. HELPERS-07: never throws: absent fields surface as undefined on the returned Patient object.

Example​
console.log(msg.patient?.mrn);
console.log(msg.patient?.fullName);
console.log(msg.patient?.dateOfBirth?.raw); // fidelity TS: e.g. "19800115"
Returns​

Patient | undefined

structure​
Get Signature​

get structure(): MessageStructure

Structural-conformance summary for the common message types: a misroute/truncation safety net, NOT a conformance validator. Reports, per the message's recognized (MSH-9.1, MSH-9.2) type, which Required segment groups are present and which are entirely absent (missingGroups: the same set the parser flags as MISSING_EXPECTED_GROUP warnings). For an unmodelled type, recognized is false and missingGroups is empty. D-02: memoized.

Example​
console.log(msg.structure.recognized); // true for ORU^R01, ADT^A01, …
console.log(msg.structure.missingGroups); // e.g. ["result"] if no OBR/OBX
Returns​

MessageStructure

visit​
Get Signature​

get visit(): Visit | undefined

PV1-derived visit view, or undefined when no PV1 segment exists (HELPERS-03). D-02: memoized. HELPERS-07: never throws.

Example​
console.log(msg.visit?.patientClass); // "I"
console.log(msg.visit?.admitDateTime?.raw); // fidelity TS
console.log(msg.visit?.attendingDoctor?.familyName);
Returns​

Visit | undefined

Methods​

addSegment()​

addSegment(name, fields): this

Append a new segment to the end of the message. name must match /^(?:[A-Z]{3}|Z[A-Z0-9]{2})$/u: throws TypeError otherwise (D-19).

fields is interpreted in HL7 1-indexed terms: addSegment("NTE", [a, b, c]) produces a segment whose NTE-1 = a, NTE-2 = b, NTE-3 = c. The internal RawSegment.fields[0] name/separator placeholder is synthesized by this method.

Each entry may be a plain string (treated as a single-subcomponent single-component single-repetition field) or a full RawField object for advanced callers who need structured content.

Invalidates caches on return; warnings untouched (D-16).

Parameters​
name​

string

fields​

readonly (string | RawField)[]

Returns​

this

Example​
msg.addSegment("NTE", ["", "note text"]);
msg.get("NTE.2"); // "note text"
allergies()​

allergies(): readonly Allergy[]

Every AL1 as an Allergy in document order. D-05: returns [] when no AL1 present.

Returns​

readonly Allergy[]

Example​
for (const al of msg.allergies()) console.log(al.code?.text, al.severity);
allSegments()​

allSegments(): readonly Segment[]

Iterate every Segment in document order (MSH first, then every subsequent segment). Cached per-message; same array reference and same Segment instances on repeat calls (D-11). Invalidated wholesale by the mutation methods.

Returns​

readonly Segment[]

Example​
for (const seg of msg.allSegments()) {
console.log(seg.type);
}
appointments()​

appointments(): readonly Appointment[]

Every SCH of an SIU message as a typed Appointment, with the AIS/AIG/AIL/AIP resource segments that follow it grouped positionally under that SCH. Surfaces the placer/filler appointment ids, SCH-25 filler status (Table 0278), SCH-11 start/end timing, and the resource groups (service / general / location / personnel). D-05: returns [] when no SCH is present. D-06: not memoized. Never throws (HELPERS-07). Not a scheduling-workflow state machine: see the package known-limitations.

Returns​

readonly Appointment[]

Example​
for (const appt of msg.appointments()) {
console.log(appt.fillerAppointmentId, appt.fillerStatusCode?.identifier);
for (const r of appt.resources) console.log(r.kind, r.code?.identifier);
}
charges()​

charges(): readonly Charge[]

Every FT1 of a DFT message as a typed Charge, one per FT1 in document order. Surfaces billing-critical fields (FT1-6 transaction type, FT1-7 code, FT1-11/12 extended/unit amount, FT1-19 diagnosis linkage) with no billing logic and no money-as-float: amounts are the verbatim CP wire text. D-05: returns [] when no FT1 is present. D-06: not memoized. Never throws (HELPERS-07).

Returns​

readonly Charge[]

Example​
for (const charge of msg.charges()) {
console.log(charge.transactionType, charge.transactionCode?.identifier);
console.log(charge.amountExtended); // verbatim, never a number
}
diagnoses()​

diagnoses(): readonly Diagnosis[]

Every DG1 as a Diagnosis in document order. D-05: returns [] when no DG1 present.

Returns​

readonly Diagnosis[]

Example​
for (const dg of msg.diagnoses()) console.log(dg.code?.identifier);
documents()​

documents(): readonly ClinicalDocument[]

Every TXA of an MDM message as a typed ClinicalDocument, with the OBX narrative body grouped positionally under that TXA. The completion status (TXA-17) and availability status (TXA-19) are surfaced as distinct fields and never conflated: a document can be available before it is authenticated, and reading a preliminary document as final is the harm. D-05: returns [] when no TXA is present. D-06: not memoized. Never throws (HELPERS-07).

Returns​

readonly ClinicalDocument[]

Example​
for (const doc of msg.documents()) {
console.log(doc.documentType, doc.completionStatus, doc.availabilityStatus);
for (const obx of doc.observations) console.log(obx.value); // narrative body
}
get()​

get(path): string | undefined

Resolve a dot-path (e.g. PID.5.1, OBX[2].5, PID.3[0].1) to its decoded leaf string (unescaped once at parse: never re-unescaped on read). Returns undefined when the path doesn't resolve: never throws on missing path (MODEL-05). Throws TypeError on malformed path syntax (e.g. "pid.5", empty string).

Parameters​
path​

string

Returns​

string | undefined

Example​
const msg = parseHL7(raw);
msg.get("PID.5.1"); // "Smith"
msg.get("OBX[2].5"); // third OBX's 5th field
msg.get("NOT.9.9"); // undefined
msg.get("MSH.12"); // "2.5": HL7 version string
getAll()​

getAll(segmentType): readonly Segment[]

Return every Segment of segmentType in document order. Returns [] (empty array, NEVER undefined) when no segment of that type exists (MODEL-02). Alias for segments(segmentType): shares the same cache.

Parameters​
segmentType​

string

Returns​

readonly Segment[]

Example​
for (const obx of msg.getAll("OBX")) {
console.log(obx.field(5).value);
}
identityEvents()​

identityEvents(): readonly IdentityEvent[]

Every recognized ADT patient-identity event (merge / move / link / unlink / person add/update), with the MRG-sourced prior and PID/PV1-sourced surviving parties labelled by role and the spec-constant direction: "MRG_TO_PID" on merge/move events. Returns [] when the trigger event is not in the identity family. D-06: not memoized. Never throws; incomplete merge pairs surface a MERGE_MISSING_PRIOR_OR_SURVIVOR warning on the event.

Returns​

readonly IdentityEvent[]

Example​
for (const ev of msg.identityEvents()) {
if (ev.kind === "merge" && ev.prior && ev.surviving) {
// retire ev.prior.identifiers in favour of ev.surviving.identifiers
}
}
immunizations()​

immunizations(): readonly Immunization[]

Every RXA of a VXU^V04 as a typed Immunization, with RXR (route/site) and OBX children grouped positionally under the RXA and orderControl from the preceding ORC of the VXU order group. D-05: returns [] when no RXA present. D-06: not memoized. The vaccine code carries its own provenance; the action code (RXA-21) is surfaced verbatim and recordOrigin (administered vs historical) is derived only from the well-known NIP001 RXA-9.1 codes: never guessed.

Returns​

readonly Immunization[]

Example​
for (const imm of msg.immunizations()) {
console.log(imm.vaccineCode?.identifier, imm.doseAmount, imm.recordOrigin);
console.log(imm.actionCode, imm.completionStatus);
}
insurance()​

insurance(): readonly Insurance[]

Every IN1 as an Insurance entry with positional IN2/IN3 presence flags. D-05: returns [] when no IN1 present.

Returns​

readonly Insurance[]

Example​
for (const ins of msg.insurance()) console.log(ins.planId?.text);
medications()​

medications(): readonly Medication[]

Every RXO/RXE/RXD/RXA as a typed Medication, with RXR (route) and RXC (component) segments grouped positionally under their parent. D-05: returns [] when no RX* parent present. D-06: not memoized. The give amount and give strength are surfaced separately and never reconciled.

Each medication also carries its TQ1 / legacy embedded-TQ (RXE-1) timings (repeat pattern verbatim, never resolved to a schedule).

Returns​

readonly Medication[]

Example​
for (const med of msg.medications()) {
console.log(med.context, med.giveCode?.identifier, med.giveCode?.nameOfCodingSystem);
console.log(med.amount?.minimum, med.strength?.value);
for (const t of med.timings) console.log(t.repeatPattern?.code, t.totalOccurrences);
}
nextOfKin()​

nextOfKin(): readonly NextOfKin[]

Every NK1 as a NextOfKin entry in document order. D-05: returns [] when no NK1 present.

Returns​

readonly NextOfKin[]

Example​
for (const nk of msg.nextOfKin()) {
console.log(nk.name?.familyName, nk.relationship?.text);
}
notes()​

notes(): readonly string[]

Message-level NTE notes: every NTE segment with no recognized preceding parent (not immediately following a PID, ORC, OBR, or OBX), surfaced verbatim in document order so nothing is dropped. Notes that DO attach to a specific patient / order / result are exposed on those helper outputs (msg.patient?.notes, order.notes, observation.notes), not here. D-05: returns [] when there are none. D-06: NOT memoized.

Returns​

readonly string[]

Example​
for (const note of msg.notes()) console.log(note); // message-level narrative
observations()​

observations(): readonly Observation[]

Every OBX segment as a typed Observation in document order. D-05: returns [] when no OBX present. D-06: NOT memoized: each call re-walks rawSegments. Value type is discriminated per D-13.

Returns​

readonly Observation[]

Example​
for (const obs of msg.observations()) {
if (obs.valueType === "NM") console.log(obs.value); // number | undefined
}
orders()​

orders(): readonly Order[]

Every OBR as an Order with its OBX children grouped positionally (D-12) and its TQ1 / legacy embedded-TQ (ORC-7) timings (the repeat pattern is surfaced verbatim, never resolved to a schedule). D-05: returns [] when no OBR present. D-06: not memoized.

Returns​

readonly Order[]

Example​
for (const order of msg.orders()) {
console.log(order.placerOrderNumber, order.observations.length);
for (const t of order.timings) console.log(t.repeatPattern?.code); // e.g. "Q6H": verbatim
}
prettyPrint()​

prettyPrint(): string

Emit this message as a human-readable multi-line string for logs and debugging (SER-04). Single opinionated format (D-22 no options): header line with type / controlId / timestamp / segment count, then one line per segment with labeled [N]=value fields (D-23). Composite values render as their raw HL7 string: depth stops at field level (D-24). Pure: never warns, never throws (D-26).

Field values render as their raw HL7 string representation. Embedded delimiters in user data appear as escape sequences: e.g. a patient family name containing | renders as Smith\F\Jones (NOT Smith|Jones). This preserves round-trip fidelity: copy-pasting prettyPrint output into parseHL7 yields a structurally equivalent message. For un-escaped human display, parse the composite first via typed accessors (e.g. msg.patient?.familyName): those return already-decoded strings.

Returns​

string

Example​
import { parseHL7 } from "@cosyte/hl7";
const msg = parseHL7(raw);
console.log(msg.prettyPrint());
// HL7 ADT^A01 controlId=MSG001 timestamp=2026-04-19T10:15:00Z (5 segments)
// MSH [3]=SENDAPP [4]=SENDFAC ...
// PID [1]=1 [3]=MRN123 [5]=Doe^John
removeSegment()​

removeSegment(segmentType, occurrenceOrOptions?): this

Remove segments by type + occurrence or by type + all. Call shapes:

  • removeSegment("NTE"): remove the FIRST NTE (occurrence 0).
  • removeSegment("OBX", 1): remove the SECOND OBX (0-indexed per D-01).
  • removeSegment("OBX", { all: true }): remove ALL OBX segments.

MSH is protected: removeSegment("MSH") throws TypeError (every HL7 message must retain its MSH segment). Unknown segment types are a no-op (idempotent; no throw). Segment name must match the D-19 shape regex: invalid shapes throw TypeError for symmetry with addSegment.

Invalidates caches on return; warnings untouched (D-16).

Parameters​
segmentType​

string

occurrenceOrOptions?​

number | { all?: boolean; }

Returns​

this

Example​
msg.removeSegment("NTE"); // remove first NTE
msg.removeSegment("OBX", 1); // remove second OBX
msg.removeSegment("OBX", { all: true }); // remove all remaining OBX
segments()​

segments(segmentType): readonly Segment[]

Return the cached array of Segment wrappers for segmentType in document order. The returned array identity and the individual Segment instances are both stable across calls (D-11). Invalidated wholesale by the mutation methods.

Parameters​
segmentType​

string

Returns​

readonly Segment[]

Example​
const pid = msg.segments("PID")[0];
if (pid !== undefined) console.log(pid.field(5).value);
setComposite()​

setComposite<K>(path, kind, value): this

Set a typed composite at a field (or field-repetition) dot-path: the conservative-emit mirror of the typed read accessors (asXpn/asCx/…). The caller passes a structured value (an XPN name, a CX identifier, a TS timestamp, …) by its CompositeKind, and the setter encodes it into a spec-clean field using the encode-safe path: any delimiter embedded in a component value is escaped, never injected, so a familyName of "Smith^Jr" re-parses to exactly that string rather than forging a component boundary. No hand-assembly of ^/&/~.

The path must resolve to a field ("PID.5") or a specific repetition of a field ("PID.11[1]"). A component/subcomponent-level path ("PID.5.1") is rejected with TypeError: a composite occupies a whole field, not a single component. Like setField, the target segment must already exist (addSegment first); the repetition defaults to index 0 and other repetitions of the field are preserved.

Never fabricates: an omitted optional composite field encodes to an empty/absent component, never a defaulted value; an all-empty composite clears the field. Segment/helper caches are invalidated on success; the frozen warnings array is untouched.

Type Parameters​
K​

K extends CompositeKind

Parameters​
path​

string

kind​

K

value​

CompositeValueByKind[K]

Returns​

this

Example​
const msg = buildMessage({ type: "ADT^A01" }).addSegment("PID", [""]);
msg.setComposite("PID.5", "XPN", { familyName: "Smith", givenName: "Ann" });
msg.setComposite("PID.3", "CX", { idNumber: "MRN001", identifierTypeCode: "MR" });
msg.setComposite("PID.7", "TS", "19880705");
msg.get("PID.5.1"); // "Smith"
setField()​

setField(path, value): this

Set the string value at a dot-path. Mutates the underlying tree and returns this for chaining (D-15). Auto-creates missing repetitions, components, and subcomponents WITHIN an existing field, but does NOT auto-create segments: callers must addSegment first (throws TypeError with an actionable message otherwise).

The value is accepted verbatim: unescaped delimiter characters are NOT rejected on input (D-18). Re-escaping is the serializer's concern.

MSH-1 / MSH-2 follow the user-facing HL7 convention: setField("MSH.3", ...) targets MSH-3 (sending application), matching msg.get("MSH.3").

Segment/Field wrapper caches are invalidated wholesale on success (D-17). The frozen warnings array is never touched (D-16).

Parameters​
path​

string

value​

string

Returns​

this

Example​
msg.setField("PID.8", "F"); // patient sex → F
msg.setField("PID.5.1", "Jones"); // family name
msg.setField("PID.4[2].1", "MRN2"); // create third repetition of PID-4
toJSON()​

toJSON(): SerializedMessage

Emit this message as a structured SerializedMessage JSON projection (SER-03). Invoked automatically by JSON.stringify(msg) (D-18). Re-walks rawSegments on every call (D-30 no caching). Mirrors the raw tree one-for-one, preserves isNull, always includes warnings: [], and includes profile: { name, lineage } only when this.profile is truthy (D-19/D-20). Pure: never warns, never throws.

Returns​

SerializedMessage

Example​
import { parseHL7 } from "@cosyte/hl7";
const msg = parseHL7(raw);
const snap = msg.toJSON();
console.log(snap.segments[0]?.name); // "MSH"
console.log(JSON.stringify(msg)); // same content, auto-invokes toJSON
toString()​

toString(): string

Emit this message as spec-clean HL7 (SER-01). Re-walks rawSegments on every call (D-30 no caching). Segments are joined with \r per D-05; MSH-1 and MSH-2 are inlined verbatim from this.encodingCharacters per D-06; every field string passes through reescape per D-04. RawField.isNull === true is preserved as the HL7 literal "" (D-02). Pure: never warns, never throws (D-07).

Returns​

string

Example​
import { parseHL7 } from "@cosyte/hl7";
const msg = parseHL7(raw);
console.log(msg.toString()); // spec-clean, CR-separated HL7

Hl7ParseError​

Thrown by parseHL7 when the input violates one of the 4 unrecoverable Tier-3 structural rules (missing MSH, truncated MSH, invalid encoding characters, or empty input). Carries positional context plus a short snippet of the offending input so consumers can log actionable errors.

Remarks​

snippet may contain PHI when parsing real clinical messages, and the library does not redact it: redact at the call site if required by your compliance posture. It is the only field carrying input verbatim and unfiltered (capped at 40 characters plus an ellipsis, but not shape-checked in any way), so it is the one to redact first.

message is bounded but not absolutely content-free, and the difference is worth stating because message is what a logger prints by default and what stack embeds. A token lifted from the input is echoed only when it matches the form the spec defines for it: a three-character segment identifier, an MSH-9 type, an MSH-12 version, or a charset label the closed Table 0211 actually contains. Anything else becomes <withheld>. So a message cannot carry a field's value, but it can carry a residue of up to three characters when a malformed line happens to look like a segment identifier. The other shapes are narrower in practice than their patterns allow, because the library only ever feeds them registry-matched values, but the patterns themselves admit more (a message type up to 26 characters, a version up to 14), which matters if you construct warnings yourself.

Under { strict: true } an escalated Tier-2 warning is thrown as this error, carrying the warning's own bounded message and a snippet of the first 40 characters of the input. That snippet is the head of the message rather than the deviation's own segment, so it is usually the MSH header; it is deliberately not re-pointed at the offending segment, since doing so would move more clinical content into the unredacted field.

Example​

import { parseHL7, Hl7ParseError } from "@cosyte/hl7";
try {
parseHL7("");
} catch (err) {
if (err instanceof Hl7ParseError && err.code === "EMPTY_INPUT") {
// handle empty input: err.position, err.snippet available
}
}

Extends​

  • Error

Constructors​

Constructor​

new Hl7ParseError(code, message, position, snippet): Hl7ParseError

Internal

Construct a new Hl7ParseError. All four fields are required so every thrower populates full positional context per the TOL-02 requirement.

Parameters​
code​

FatalCode

message​

string

position​

Hl7Position

snippet​

string

Returns​

Hl7ParseError

Overrides​

Error.constructor

Properties​

code​

readonly code: FatalCode

position​

readonly position: Hl7Position

snippet​

readonly snippet: string


ProfileDefinitionError​

Thrown by defineProfile() and profile-validation code when a profile definition is structurally invalid: e.g. references an undefined parent, declares a malformed custom segment, or includes an unsupported date format. Callers may optionally supply the offending profile name for better diagnostics.

Example​

import { ProfileDefinitionError } from "@cosyte/hl7";
throw new ProfileDefinitionError(
"Unknown parent profile: epic-v7",
"my-epic-extension",
);

Extends​

  • Error

Constructors​

Constructor​

new ProfileDefinitionError(message, profileName?): ProfileDefinitionError

Internal

Construct a new ProfileDefinitionError. profileName is optional so callers may omit it when the offending profile cannot be named (e.g. during initial validation before a name is parsed).

Parameters​
message​

string

profileName?​

string

Returns​

ProfileDefinitionError

Overrides​

Error.constructor

Properties​

profileName​

readonly profileName: string | undefined


Segment​

Wrapper over a RawSegment exposing typed per-position Field instances. seg.field(3) === seg.field(3): referential stability is guaranteed per segment instance.

Example​

import { parseHL7 } from "@cosyte/hl7";
const msg = parseHL7(raw);
const pid = msg.segments("PID")[0];
if (pid !== undefined) console.log(pid.field(5).value);

Constructors​

Constructor​

new Segment(raw, enc, absoluteIndex, customFields?): Segment

Internal

Construct a new Segment. Called internally by Hl7Message; user code should obtain Segment instances via msg.segments(type) or msg.allSegments().

The optional customFields parameter is the per-segment portion of the applied profile's merged customSegments map (PROF-07 / D-16). When supplied, get(name) resolves names against it; otherwise get(name) always returns undefined.

Parameters​
raw​

RawSegment

enc​

EncodingCharacters

absoluteIndex​

number

customFields?​

Readonly<Record<string, number>>

Returns​

Segment

Properties​

absoluteIndex​

readonly absoluteIndex: number

Internal

Absolute index of this segment in Hl7Message.rawSegments[]. Used for position tracking.

customFields​

readonly customFields: Readonly<Record<string, number>> | undefined

Internal

Lookup map from profile-declared field name → 1-indexed HL7 position. Absent when no profile was applied to the parent message, or when the applied profile does not declare customSegments for this segment's type. Consumed by get(name) to resolve named-field access (PROF-07).

enc​

readonly enc: EncodingCharacters

Internal

The 5 encoding characters for this message. Exposed for composite parsers.

fields​

readonly fields: readonly RawField[]

Reference to the underlying RawSegment.fields: 1-indexed per HL7 convention.

raw​

readonly raw: RawSegment

Internal

The full RawSegment this wrapper wraps. Exposed for mutation methods.

type​

readonly type: string

Segment identifier: three characters with a leading letter, e.g. "PID", "OBX", "ZPI".

Bounded, and it is "<withheld>" when the raw name is not that shape. A line with no field separator has its whole content read as a segment name, so an unescaped line break inside a narrative field forges a "segment" whose name is clinical text. This field presents itself as a structural identifier and consumers interpolate it into labels, loci and reports, so it never carries that text. "" still means absent, which is a different fact from withheld.

Use Segment.raw.name when you need the verbatim text: it is the unbounded value, and it is what serialization emits, so the byte-verbatim round-trip is unaffected. One consequence worth knowing: a segment whose raw name fails the shape (a 4-character vendor Z-segment, which HL7 v2 Ch. 2 §2.5 does not permit) is not matched by msg.segments(name).

Methods​

field()​

field(n): Field

Return the Field wrapper at HL7 position n. Indexing follows the HL7 1-indexed convention: seg.field(5) on a PID segment maps to PID-5. MSH segments use the same user-facing convention: msh.field(1) returns the field-separator (MSH-1), msh.field(2) returns encoding chars (MSH-2), msh.field(3) returns MSH-3, and so on: the internal fields[N-1] offset for MSH segments is applied here (mirrors the dot-path resolver in dot-path.ts, keeping msg.segments('MSH')[0].field(3) and msg.get('MSH.3') in agreement).

Returns a synthetic empty Field (.isNull === false, .value === "") when n is out of range: never throws (MODEL-05). Successive calls with the same n return the same Field instance (D-12).

Parameters​
n​

number

Returns​

Field

Example​
const pid5 = msg.segments("PID")[0]?.field(5);
console.log(pid5?.value); // "Smith"
const msh3 = msg.segments("MSH")[0]?.field(3);
console.log(msh3?.value); // sending application (HL7 MSH-3)
get()​

get(name): Field | undefined

Return the Field at the profile-declared position for name, or undefined when no custom mapping exists (PROF-07). Unlike field(n), missing names return undefined, NOT a synthetic empty Field, so typos surface instead of silently resolving to an empty string (D-14).

For segments without a profile-declared customSegments slice (most non-Z segments, and any Z-segment whose host message had no profile applied), this method always returns undefined (D-15 defense-in-depth : D-05 already rejects standard-segment overlays at defineProfile() time).

When the declared position is out of range for the underlying RawSegment.fields, get(name) returns undefined (NOT a synthetic-empty Field) so callers can distinguish "name not declared" from "name declared but position missing in the raw message" only at the presence level (both collapse to undefined per D-14).

Parameters​
name​

string

Returns​

Field | undefined

Example​
const zpi = msg.allSegments().find((s) => s.type === "ZPI");
console.log(zpi?.get("encounterId")?.value);

Interfaces​

AckErrorDetail​

One ERR segment's worth of error detail for buildAck. Carries codes and locations only: never echoed PHI values (the phi-redaction-review gate binds this contract).

Example​

import { buildAck } from "@cosyte/hl7";
const ack = buildAck(inbound, {
code: "AE",
error: { conditionCode: "101", severity: "E", location: "PID^1^5" },
});

Properties​

conditionCode?​

readonly optional conditionCode?: string

HL7 Table 0357 message error condition code (ERR-3.1). Defaults to "207" (Application internal error). The standard display text is looked up from Table 0357 and emitted in ERR-3.2; unknown codes emit with empty text (the code is preserved verbatim: never dropped).

location?​

readonly optional location?: string

Error location (ERR-2, an HL7 ERL). A structural path such as "PID^1^5" (segment id ^ segment sequence ^ field position). Must not contain a patient data value: locations point at where, never what.

severity?​

readonly optional severity?: ErrSeverity

HL7 Table 0516 severity (ERR-4). Defaults to "E" (Error).


AckErrorEntry​

One ERR segment interpreted from an ACK. All fields are surfaced verbatim (no table lookup) and OMITTED when the underlying component is absent (exactOptionalPropertyTypes). Codes/locations only: never PHI.

Properties​

conditionCode?​

readonly optional conditionCode?: string

ERR-3.1: HL7 Table 0357 condition code.

conditionCodeSystem?​

readonly optional conditionCodeSystem?: string

ERR-3.3: condition code system name (e.g. HL70357).

conditionText?​

readonly optional conditionText?: string

ERR-3.2: condition code display text.

location?​

readonly optional location?: string

ERR-2: error location (an HL7 ERL), surfaced verbatim.

severity?​

readonly optional severity?: string

ERR-4: HL7 Table 0516 severity (I/W/E).


Acknowledgment​

Typed view of an inbound ACK. accepted / error / rejected are derived from MSA-1 against HL7 Table 0008 and are mutually exclusive; all three are false when MSA-1 is absent or not a recognized code (fail-safe).

Example​

import { interpretAck, parseHL7 } from "@cosyte/hl7";
const ack = interpretAck(parseHL7(rawAck));
if (ack.accepted) {
// safe to consider the message acknowledged
} else if (ack.rejected) {
for (const e of ack.errors) console.error(e.conditionCode, e.severity);
}

Properties​

accepted​

readonly accepted: boolean

True iff MSA-1 is a positive accept (AA/CA).

code?​

readonly optional code?: string

MSA-1 acknowledgment code (HL7 Table 0008), verbatim. Omitted when absent.

controlId?​

readonly optional controlId?: string

MSA-2 message control id (the correlated inbound MSH-10), surfaced as the field's canonical wire text (Field.text): the whole field, delimiters included, never truncated to the first component. Note this is the re-escaped form: a properly-escaped id arrives as its wire bytes (ID\S\X), and an HL7 explicit-null MSA-2 surfaces as the literal two-character "". Omitted when absent/empty.

error​

readonly error: boolean

True iff MSA-1 is an error acknowledgment (AE/CE).

errors​

readonly errors: readonly AckErrorEntry[]

Every ERR segment in document order ( [] when none ).

rejected​

readonly rejected: boolean

True iff MSA-1 is a reject acknowledgment (AR/CR).


AdtEvent​

Typed EVN (event type) content for buildAdt.

Properties​

eventOccurred?​

readonly optional eventOccurred?: string | DtmParts

EVN-6 Event Occurred.

recordedDateTime?​

readonly optional recordedDateTime?: string | DtmParts

EVN-2 Recorded Date/Time.


AdtPatient​

Typed PID (patient identification) content for buildAdt.

Properties​

accountNumber?​

readonly optional accountNumber?: CX

PID-18 Patient Account Number.

address?​

readonly optional address?: XAD | readonly XAD[]

PID-11 Patient Address: one or more XAD addresses.

administrativeSex?​

readonly optional administrativeSex?: string

PID-8 Administrative Sex (e.g. "F", "M", "U").

birthDateTime?​

readonly optional birthDateTime?: string | DtmParts

PID-7 Date/Time of Birth.

identifiers?​

readonly optional identifiers?: CX | readonly CX[]

PID-3 Patient Identifier List: one or more CX identifiers (MRN, SSN, …).

mothersMaidenName?​

readonly optional mothersMaidenName?: XPN

PID-6 Mother's Maiden Name.

name?​

readonly optional name?: XPN | readonly XPN[]

PID-5 Patient Name.

phoneHome?​

readonly optional phoneHome?: XTN | readonly XTN[]

PID-13 Phone Number - Home: one or more XTN telecoms.

setId?​

readonly optional setId?: string

PID-1 Set ID.


AdtVisit​

Typed PV1 (patient visit) content for buildAdt.

Properties​

admitDateTime?​

readonly optional admitDateTime?: string | DtmParts

PV1-44 Admit Date/Time.

assignedLocation?​

readonly optional assignedLocation?: PL

PV1-3 Assigned Patient Location.

attendingDoctor?​

readonly optional attendingDoctor?: XCN | readonly XCN[]

PV1-7 Attending Doctor.

patientClass?​

readonly optional patientClass?: string

PV1-2 Patient Class (e.g. "I" inpatient, "O" outpatient, "E" emergency).

referringDoctor?​

readonly optional referringDoctor?: XCN | readonly XCN[]

PV1-8 Referring Doctor.

setId?​

readonly optional setId?: string

PV1-1 Set ID.

visitNumber?​

readonly optional visitNumber?: CX

PV1-19 Visit Number.


Allergy​

AL1-derived allergy entry (HELPERS-06). onsetDate is the fidelity TS.

Example​

import type { Allergy } from "@cosyte/hl7";
const al: Allergy = {
type: "DA",
code: { identifier: "PEN", text: "Penicillin" },
severity: "SV",
reaction: "Hives",
};

Properties​

code?​

readonly optional code?: CWE

AL1-3 allergen code.

onsetDate?​

readonly optional onsetDate?: DtmParts

AL1-6 onset date as the fidelity TS.

reaction?​

readonly optional reaction?: string

AL1-5 allergy reaction description (first value).

severity?​

readonly optional severity?: string

AL1-4 severity (SV=severe, MO=moderate, MI=mild).

type?​

readonly optional type?: string

AL1-2 allergy type (DA=drug, FA=food, EA=environmental, ...).


Appointment​

SCH-derived appointment entry (SIU scheduling breadth). Surfaces the appointment identifiers, filler status (SCH-25, Table 0278), SCH-11 start/end timing, and the AI* resource groups. NOT a scheduling-workflow state machine.

Example​

import type { Appointment } from "@cosyte/hl7";
const appt: Appointment = {
fillerAppointmentId: "A1001",
fillerStatusCode: { identifier: "Booked" },
resources: [],
};

Properties​

endDateTime?​

readonly optional endDateTime?: DtmParts

Appointment end date/time: SCH-11 TQ.5 (fidelity TS).

fillerAppointmentId?​

readonly optional fillerAppointmentId?: string

SCH-2 filler appointment ID (EI first component, verbatim).

fillerStatusCode?​

readonly optional fillerStatusCode?: CWE

SCH-25 filler status code (HL7 Table 0278): the appointment status, verbatim/provenance-only.

placerAppointmentId?​

readonly optional placerAppointmentId?: string

SCH-1 placer appointment ID (EI first component, verbatim).

resources​

readonly resources: readonly AppointmentResource[]

AIS/AIG/AIL/AIP resources grouped under this SCH. Always present (possibly empty).

startDateTime?​

readonly optional startDateTime?: DtmParts

Appointment start date/time: SCH-11 TQ.4 (fidelity TS).


AppointmentResource​

One appointment resource grouped under a SCH: an AIS (service), AIG (general resource), AIL (location), or AIP (personnel / provider) segment. The resource identifier lives at position 3 of every AI* segment; for the personnel resource (AIP) it is additionally surfaced as a typed person (XCN), while the coded code (first component verbatim) is always available.

Example​

import type { AppointmentResource } from "@cosyte/hl7";
const r: AppointmentResource = { kind: "location", code: { identifier: "OR-1" } };

Properties​

code?​

readonly optional code?: CWE

The AI*-3 resource identifier surfaced as a coded element: code.identifier is the resource id (first component, verbatim). AIS-3 / AIG-3 are coded elements, so code.text / code.nameOfCodingSystem are meaningful there; AIL-3 is a PL (location) rather than a coded element, so only code.identifier (the location id, PL.1) is meaningful and the other CWE fields are positional provenance, not a coding system. Provenance-only.

kind​

readonly kind: "service" | "general" | "location" | "personnel"

Which AI* segment sourced this resource: AIS→service, AIG→general, AIL→location, AIP→personnel.

person?​

readonly optional person?: XCN

AIP-3 personnel resource as a typed XCN (personnel resources only): the appointment provider.


Batch​

One batch within a stream: a run of messages delimited by a BHS header and/or a BTS trailer (both optional in §2.10.3, so a BTS closes a preceding run into a batch even with no BHS). A run of messages with neither a header nor a trailer is not a batch: those messages live in BatchSplitResult.messages only, so they never inflate a batch count. declaredMessageCount is BTS-1 when the trailer declared a usable non-negative integer (it is optional [0..1] in the spec, so it may be absent); actualMessageCount is always the real count.

Example​

import { splitBatch } from "@cosyte/hl7";
const [batch] = splitBatch(raw).batches;
batch?.header?.name; // "BHS" (or undefined for a headerless BTS-closed run)
batch?.actualMessageCount; // messages actually in the batch

Properties​

actualMessageCount​

readonly actualMessageCount: number

The actual number of messages split out of this batch.

declaredMessageCount?​

readonly optional declaredMessageCount?: number

BTS-1 batch message count, when declared as a non-negative integer.

readonly optional header?: BatchEnvelopeSegment

The BHS header, when this batch was opened by one.

messages​

readonly messages: readonly BatchMessageEntry[]

The messages in this batch, in stream order.

trailer?​

readonly optional trailer?: BatchEnvelopeSegment

The BTS trailer, when this batch was closed by one.


BatchEnvelopeSegment​

A raw batch-envelope segment (FHS/BHS/BTS/FTS) surfaced by splitBatch. fields is the segment split on its own field separator with fields[0] holding the segment name: deliberately the raw token array, not a typed model: typed FHS/BHS field helpers beyond the raw fields are not part of this surface. Note the HL7 MSH-family indexing quirk: for FHS/BHS, fields[1] is the encoding-characters field (FHS-2/BHS-2); for BTS/FTS, fields[1] is field 1 (BTS-1 batch message count / FTS-1 file batch count).

Example​

import { splitBatch } from "@cosyte/hl7";
const { fileHeader } = splitBatch("FHS|^~\\&|SENDER\r...");
fileHeader?.name; // "FHS"
fileHeader?.fields[2]; // "SENDER" (FHS-3, the File Sending Application)

Properties​

fields​

readonly fields: readonly string[]

Raw field tokens; fields[0] is the segment name.

name​

readonly name: BatchEnvelopeName

position​

readonly position: Hl7Position

Position of this envelope segment in the split stream.

raw​

readonly raw: string

The verbatim segment string (line-ending normalized).


BatchSplitResult​

The result of splitBatch: the flattened messages (every message across every batch, in stream order: the primary surface), the nested batches, the raw file envelope segments, and the batch-level warnings (count-mismatch / missing-trailer). hadEnvelope is false for a bare passthrough (no FHS/BHS/BTS/FTS seen).

Example​

import { splitBatch } from "@cosyte/hl7";
const result = splitBatch(rawBatchFile);
result.messages.length; // every message, batched or not
result.batches.length; // === result.actualBatchCount
result.warnings; // BATCH_COUNT_MISMATCH / BATCH_MISSING_TRAILER (counts only)

Properties​

actualBatchCount​

readonly actualBatchCount: number

The number of explicit batches split out of the stream.

batches​

readonly batches: readonly Batch[]

The explicit (BHS-delimited) batches, in stream order.

declaredBatchCount?​

readonly optional declaredBatchCount?: number

The last FTS-1 file batch count, when declared as a non-negative integer.

fileHeader?​

readonly optional fileHeader?: BatchEnvelopeSegment

The first FHS file header, when present.

fileTrailer?​

readonly optional fileTrailer?: BatchEnvelopeSegment

The last FTS file trailer, when present.

hadEnvelope​

readonly hadEnvelope: boolean

false when no envelope segment was seen (bare passthrough).

messages​

readonly messages: readonly BatchMessageEntry[]

Every message split out of the stream, in order: the primary surface. This includes messages that belong to no explicit batch (a bare stream, or content outside any BHS/BTS), so it is a superset of the messages reachable via batches.

warnings​

readonly warnings: readonly Hl7ParseWarning[]

Batch-level warnings (count mismatch, missing trailer); counts/positions only, never PHI.


BuildAckOptions​

Options for buildAck.

Example​

buildAck(inbound, { code: "AA" }); // bare accept
buildAck(inbound, { code: "AR", error: { conditionCode: "200" } });

Properties​

code​

readonly code: AckCode

The acknowledgment disposition to emit in MSA-1 (HL7 Table 0008). One of AA/AE/AR (original) or CA/CE/CR (enhanced accept-level). Required: buildAck builds the disposition it is told. An unknown code is a programming error and throws TypeError.

error?​

readonly optional error?: AckErrorDetail | readonly AckErrorDetail[]

Optional error detail. A single AckErrorDetail or an array → one ERR segment each. Typically supplied for AE/AR/CE/CR.

mode?​

readonly optional mode?: AckMode

Optional explicit acknowledgment mode. When omitted it is derived from the inbound MSH-15/16 via detectAckMode. buildAck emits code verbatim regardless of mode: this field is advisory metadata for adapters (e.g. @cosyte/mllp's commit-policy layer) that need the detected mode.


BuildAdtInit​

Input for buildAdt: the MSH envelope plus the typed segment bodies.

Extends​

  • MessageEnvelope

Properties​

controlId?​

readonly optional controlId?: string

Auto-generated via generateControlId() when omitted.

Inherited from​

MessageEnvelope.controlId

event?​

readonly optional event?: AdtEvent

EVN content (EVN-1 is the trigger event; EVN-2/6 optional).

patient​

readonly patient: AdtPatient

PID content. Required: never fabricated.

processingId?​

readonly optional processingId?: string

Defaults to "P" (production).

Inherited from​

MessageEnvelope.processingId

receivingApp?​

readonly optional receivingApp?: string

Inherited from​

MessageEnvelope.receivingApp

receivingFacility?​

readonly optional receivingFacility?: string

Inherited from​

MessageEnvelope.receivingFacility

sendingApp?​

readonly optional sendingApp?: string

Inherited from​

MessageEnvelope.sendingApp

sendingFacility?​

readonly optional sendingFacility?: string

Inherited from​

MessageEnvelope.sendingFacility

timestamp?​

readonly optional timestamp?: string | Date

Date → HL7 YYYYMMDDHHmmss (UTC, seconds); a pre-formatted HL7 TS string passes through verbatim. Defaults to new Date().

Inherited from​

MessageEnvelope.timestamp

version?​

readonly optional version?: string

Defaults to "2.5".

Inherited from​

MessageEnvelope.version

visit?​

readonly optional visit?: AdtVisit

PV1 content. Optional; an (empty) PV1 is emitted regardless so the visit group is present.


BuildMessageInit​

Input shape for buildMessage (SER-06). Mirrors msg.meta 1-for-1 so read and write surfaces share field names (sendingApp, sendingFacility, receivingApp, receivingFacility, controlId, timestamp, version, processingId). type is the only required field.

Empty string vs. undefined semantics: omitting a field and passing an empty string produce IDENTICAL wire output (both emit as an absent positional field). To emit an HL7 explicit null ("") at a specific position in an outbound message, build the message first and then call .setField(path, '""'): the mutation method sets isNull=true on the underlying RawField, and the emitter preserves that as the literal two-char output per D-02.

Example​

import { buildMessage } from "@cosyte/hl7";
const msg = buildMessage({
type: "ADT^A01",
sendingApp: "CLINIC",
sendingFacility: "MAIN",
receivingApp: "LAB",
receivingFacility: "REF",
timestamp: new Date("2026-04-19T10:15:00Z"),
})
.addSegment("PID", ["", "", "MRN123", "", "Doe^John"]);
console.log(msg.toString());

// To emit HL7 explicit null ("") instead of absent:
// msg.setField("PID.2", '""'); // distinct from empty/omitted

Properties​

controlId?​

readonly optional controlId?: string

Auto-generated via generateControlId() when omitted (D-12).

processingId?​

readonly optional processingId?: string

Defaults to "P" (production).

receivingApp?​

readonly optional receivingApp?: string

receivingFacility?​

readonly optional receivingFacility?: string

sendingApp?​

readonly optional sendingApp?: string

sendingFacility?​

readonly optional sendingFacility?: string

timestamp?​

readonly optional timestamp?: string | Date

Date formatted to HL7 YYYYMMDDHHmmss (UTC, seconds) when supplied; pre-formatted HL7 TS string passed through verbatim (D-13). Defaults to new Date().

type​

readonly type: string

HL7 message type, e.g. "ADT^A01" (code + trigger) or "ORU^R01^ORU_R01" (code + trigger + structure). Required (D-16).

The string is split on ^ into MSH-9 components; each component is emitted verbatim. Literal ^ characters in a component are NOT representable via this field: splitting is unconditional. Callers needing that edge case should build the message and then use .setField("MSH.9.1", ...) etc. after construction.

Rejected at runtime (D-16 / WR-04):

  • empty string "" or whitespace-only " ";
  • strings whose every ^-split component is empty/whitespace (e.g. "^", "^^", " ^ ").
version?​

readonly optional version?: string

Defaults to "2.5".


BuildOruInit​

Input for buildOru: the MSH envelope plus the typed segment bodies.

Extends​

  • MessageEnvelope

Properties​

controlId?​

readonly optional controlId?: string

Auto-generated via generateControlId() when omitted.

Inherited from​

MessageEnvelope.controlId

observations​

readonly observations: readonly OruObservation[]

OBX content. Required, non-empty: an ORU with no result is a typed error.

order?​

readonly optional order?: OruOrder

OBR content. Optional; an (empty) OBR is emitted regardless so the result group is well-formed.

patient​

readonly patient: AdtPatient

PID content. Required: never fabricated.

processingId?​

readonly optional processingId?: string

Defaults to "P" (production).

Inherited from​

MessageEnvelope.processingId

receivingApp?​

readonly optional receivingApp?: string

Inherited from​

MessageEnvelope.receivingApp

receivingFacility?​

readonly optional receivingFacility?: string

Inherited from​

MessageEnvelope.receivingFacility

sendingApp?​

readonly optional sendingApp?: string

Inherited from​

MessageEnvelope.sendingApp

sendingFacility?​

readonly optional sendingFacility?: string

Inherited from​

MessageEnvelope.sendingFacility

timestamp?​

readonly optional timestamp?: string | Date

Date → HL7 YYYYMMDDHHmmss (UTC, seconds); a pre-formatted HL7 TS string passes through verbatim. Defaults to new Date().

Inherited from​

MessageEnvelope.timestamp

version?​

readonly optional version?: string

Defaults to "2.5".

Inherited from​

MessageEnvelope.version


Cardinality​

A repetition-count constraint. min / max are inclusive bounds on the number of repetitions (for a field rule) or occurrences (for a segment rule). max may be the literal "*" for "unbounded". Omitted bounds are unconstrained on that side.

Cardinality min is checked only when the element is present. An absent Required element is reported as FINDING_CODES.PROFILE_REQUIRED_ABSENT (a usage finding), not a cardinality finding: so a missing R field with cardinality.min = 1 yields exactly one finding, never two.

Example​

import type { Cardinality } from "@cosyte/hl7";
const once: Cardinality = { min: 1, max: 1 };
const many: Cardinality = { min: 1, max: "*" };

Properties​

max?​

readonly optional max?: number | "*"

min?​

readonly optional min?: number


CE​

HL7 v2 Coded Element (CE): coded element per HL7 Chapter 2. All 6 components are optional. Fields are OMITTED when the underlying component is absent (exactOptionalPropertyTypes).

Component positions (HL7 1-indexed; this interface is 0-indexed by key):

  1. identifier (e.g. "GLU")
  2. text (human-readable, e.g. "Glucose")
  3. nameOfCodingSystem (e.g. "LN" for LOINC)
  4. alternateIdentifier
  5. alternateText
  6. nameOfAlternateCodingSystem

Components 7+ (present when a CWE-shaped value is read through the CE accessor: e.g. version ids, originalText) are surfaced verbatim on extraComponents rather than dropped.

Example​

import type { CE } from "@cosyte/hl7";
const code: CE = { identifier: "GLU", text: "Glucose", nameOfCodingSystem: "LN" };

Properties​

alternateIdentifier?​

readonly optional alternateIdentifier?: string

alternateText?​

readonly optional alternateText?: string

extraComponents?​

readonly optional extraComponents?: readonly string[]

Components beyond the modeled 6 (HL7 component 7 onward), preserved verbatim and in order. Non-empty only when a CWE-shaped value is read through the CE accessor; OMITTED otherwise. An absent interior component is preserved as "" so extraComponents[i] maps to HL7 component 7 + i.

identifier?​

readonly optional identifier?: string

nameOfAlternateCodingSystem?​

readonly optional nameOfAlternateCodingSystem?: string

nameOfCodingSystem?​

readonly optional nameOfCodingSystem?: string

text?​

readonly optional text?: string


Charge​

FT1-derived charge entry (DFT financial breadth). Billing-critical fields surfaced with no billing logic and no money-as-float: the extended/unit amounts are the verbatim CP wire text, never parsed to a number.

Example​

import type { Charge } from "@cosyte/hl7";
const c: Charge = {
transactionType: "CG",
transactionCode: { identifier: "80053", text: "Metabolic panel" },
amountExtended: "150.00^USD",
diagnoses: [{ identifier: "E11.9" }],
};

Properties​

amountExtended?​

readonly optional amountExtended?: string

FT1-11 transaction amount, extended (CP): canonical wire text (e.g. 150.00^USD, byte-exact for a plain amount); never parsed to a number.

amountUnit?​

readonly optional amountUnit?: string

FT1-12 transaction amount, unit (CP): canonical wire text; never parsed to a number.

diagnoses​

readonly diagnoses: readonly CWE[]

FT1-19 diagnosis code(s) linked to this charge (CE, repeating): billing diagnosis linkage. Always present (possibly empty).

quantity?​

readonly optional quantity?: number

FT1-10 transaction quantity (NM; strict-parsed, never NaN).

transactionCode?​

readonly optional transactionCode?: CWE

FT1-7 transaction code: the institution charge/procedure code (CWE, provenance-only, never validated).

transactionDate?​

readonly optional transactionDate?: DtmParts

FT1-4 transaction date (fidelity TS).

transactionType?​

readonly optional transactionType?: string

FT1-6 transaction type (HL7 Table 0017: CG charge, CD credit, PY payment, AJ adjustment). Verbatim.


CharsetResolution​

The outcome of resolving an MSH-18 label (or options.charset override) against Table 0211.

Properties​

canonical​

readonly canonical: string

The canonical Table-0211 code the label resolved to (e.g. "UTF-8", "8859/1", "ISO IR87"). For an unrecognized label this is the input trimmed + upper-cased, so it is still a stable key for comparison.

decoder​

readonly decoder: string

The WHATWG TextDecoder label to decode with when treatment === "decode". Empty when treatment === "verbatim".

recognized​

readonly recognized: boolean

true when the label is a recognized HL7 Table-0211 code (whether or not the parser decodes it); false when the label is not in Table 0211. Drives the warning code on the verbatim path: recognized-but-verbatim → UNSUPPORTED_CHARSET, unrecognized → UNKNOWN_CHARSET.

treatment​

readonly treatment: CharsetTreatment

Whether the parser decodes this set or preserves its bytes verbatim.


ClinicalDocument​

TXA-derived clinical-document entry (MDM document breadth). The load-bearing safety property: completion status (TXA-17) and availability status (TXA-19) are DISTINCT fields and are never conflated: a document can be available before it is authenticated, and reading a preliminary document as final is the clinical harm. Both are verbatim / provenance-only.

Example​

import type { ClinicalDocument } from "@cosyte/hl7";
const doc: ClinicalDocument = {
documentType: "DS",
completionStatus: "IP", // in progress: NOT yet authenticated
availabilityStatus: "AV", // available: a different axis
observations: [],
};

Properties​

activityDateTime?​

readonly optional activityDateTime?: DtmParts

TXA-4 activity date/time (fidelity TS).

availabilityStatus?​

readonly optional availabilityStatus?: string

TXA-19 document availability status (HL7 Table 0273: AV available, CA cancelled, OB obsolete, UN unavailable). Surfaced DISTINCT from completionStatus; verbatim, never validated, never merged.

completionStatus?​

readonly optional completionStatus?: string

TXA-17 document completion status (HL7 Table 0271: e.g. DO documented, IP in progress, AU authenticated, LA legally authenticated, IN incomplete). Surfaced DISTINCT from availabilityStatus; verbatim, never validated, never merged.

documentType?​

readonly optional documentType?: string

TXA-2 document type (HL7 Table 0270), verbatim.

observations​

readonly observations: readonly Observation[]

OBX narrative body grouped under this TXA. Always present (possibly empty).

parentDocumentNumber?​

readonly optional parentDocumentNumber?: string

TXA-13 parent document number (EI first component): addendum / replacement link.

uniqueDocumentNumber?​

readonly optional uniqueDocumentNumber?: string

TXA-12 unique document number (EI first component, verbatim).


CodedSystemFields​

Structural shape of any coded element that carries a primary + alternate coding system: both CWE and CE satisfy it. Kept structural (not a union) so callers can pass a dg.code / obs.code directly.

Properties​

nameOfAlternateCodingSystem?​

readonly optional nameOfAlternateCodingSystem?: string

nameOfCodingSystem?​

readonly optional nameOfCodingSystem?: string


CodingSystemInfo​

A coding-system provenance answer: the system a code CLAIMS, never validated. claimed is always present and verbatim (never dropped); the resolved id / name are present only when the claim maps to a registered Table 0396 entry.

Properties​

claimed​

readonly claimed: string

The coding-system id exactly as it appeared in CWE.3 / CE.3: preserved verbatim (original case and spelling), never altered, never dropped.

id?​

readonly optional id?: string

Registered Table 0396 acronym (alias-normalized). Present only when known.

known​

readonly known: boolean

true when claimed resolved (directly or via alias) to a registered Table 0396 entry.

name?​

readonly optional name?: string

Canonical human-readable name. Present only when known.


CompositeValueByKind​

Maps each CompositeKind to the typed value encodeComposite (and setComposite) accept for it. TS also accepts a pre-formatted HL7 timestamp string; NM also accepts a number or a raw numeric string, both are emitted verbatim (the serializer never re-formats a claimed value).

Properties​

CE​

readonly CE: CE

CWE​

readonly CWE: CWE

CX​

readonly CX: CX

HD​

readonly HD: HD

NM​

readonly NM: string | number | NM

PL​

readonly PL: PL

TS​

readonly TS: string | DtmParts

XAD​

readonly XAD: XAD

XCN​

readonly XCN: XCN

XPN​

readonly XPN: XPN

XTN​

readonly XTN: XTN


ConformanceFinding​

One typed conformance finding. Carries the FindingCode, a FindingSeverity, the structural FindingLocus, and a human-readable message describing the rule that fired.

The message is PHI-safe by construction: it names the locus, the rule, and (for a value-set miss) the SIZE of the value set, but never the offending field value.

Example​

import type { ConformanceFinding } from "@cosyte/hl7";
const f: ConformanceFinding = {
code: "PROFILE_VALUE_NOT_IN_SET",
severity: "error",
locus: { segment: "PID", field: 8, component: 1 },
message: 'PID-8 component 1 value is not in the profile value set (3 permitted codes).',
};

Properties​

code​

readonly code: FindingCode

locus​

readonly locus: FindingLocus

message​

readonly message: string

severity​

readonly severity: FindingSeverity


ConformanceProfile​

A user-authored, declarative conformance profile. The consumer supplies this; hl7 ships none. It is a bounded subset of the HL7 v2 Message-Profile model: usage / cardinality / length / consumer-supplied value set: with no conditional-predicate language, no bundled code set, and no network binding (all deliberate scope boundaries).

Example​

import type { ConformanceProfile } from "@cosyte/hl7";

// A minimal ADT profile the CONSUMER authors: example, NOT an attestation.
const profile: ConformanceProfile = {
name: "example-adt-min",
segments: [
{ segment: "MSH", usage: "R", fields: [{ field: 10, name: "Control ID", usage: "R" }] },
{ segment: "PID", usage: "R", cardinality: { min: 1, max: 1 }, fields: [
{ field: 3, name: "Patient Identifiers", usage: "R", cardinality: { min: 1, max: 1 } },
{ field: 8, name: "Administrative Sex", usage: "RE", valueSet: ["M", "F", "U"] },
] },
{ segment: "ZZZ", usage: "X" },
],
};

Properties​

name​

readonly name: string

A name for provenance: echoed into ConformanceResult.profileName.

segments​

readonly segments: readonly SegmentRule[]

The segment rules, evaluated in array order (stable finding order).


ConformanceResult​

The result of validateAgainstProfile: the profile's name and the ordered list of findings.

findings.length === 0 is NOT a conformance attestation. It means every rule the profile declared was satisfied: nothing about the parts of the message the profile did not cover, and nothing about clinical correctness. Read it as "no declared rule was violated," never as "conformant."

Properties​

findings​

readonly findings: readonly ConformanceFinding[]

profileName​

readonly profileName: string


CustomSegmentDefinition​

Shape of a single custom Z-segment declaration used by profile authoring (defineProfile()). fields maps a caller-visible field NAME to its 1-indexed HL7 position within the segment. Declared here (alongside Profile) to keep the parser's type module the single source of truth; src/profiles/define.ts re-exports this type, so consumers can write import type { CustomSegmentDefinition } from "@cosyte/hl7".

Example​

import type { CustomSegmentDefinition } from "@cosyte/hl7";
const zdp: CustomSegmentDefinition = {
fields: { departmentCode: 3, departmentName: 4 },
};

Properties​

fields​

readonly fields: Readonly<Record<string, number>>


CWE​

HL7 v2 Coded with Exceptions (CWE): coded element per HL7 Chapter 2. All 9 components are optional. Fields are OMITTED when the underlying component is absent (exactOptionalPropertyTypes).

Component positions (HL7 1-indexed; this interface is 0-indexed by key):

  1. identifier (e.g. "GLU")
  2. text (human-readable, e.g. "Glucose")
  3. nameOfCodingSystem (e.g. "LN" for LOINC, "SCT" for SNOMED CT)
  4. alternateIdentifier
  5. alternateText
  6. nameOfAlternateCodingSystem
  7. codingSystemVersionId
  8. alternateCodingSystemVersionId
  9. originalText

Components 10+ (present only on v2.7+ senders) are surfaced verbatim, in order, on extraComponents: never silently truncated.

Example​

import type { CWE } from "@cosyte/hl7";
const code: CWE = { identifier: "GLU", text: "Glucose", nameOfCodingSystem: "LN" };

Properties​

alternateCodingSystemVersionId?​

readonly optional alternateCodingSystemVersionId?: string

alternateIdentifier?​

readonly optional alternateIdentifier?: string

alternateText?​

readonly optional alternateText?: string

codingSystemVersionId?​

readonly optional codingSystemVersionId?: string

extraComponents?​

readonly optional extraComponents?: readonly string[]

Components beyond the modeled 9 (HL7 component 10 onward), preserved verbatim and in order for forward-compatibility with v2.7+ senders that carry the second-alternate triplet or coding-system / value-set OIDs. OMITTED when the element has no components past the 9th. An absent interior component is preserved as "" so extraComponents[i] maps to HL7 component 10 + i.

identifier?​

readonly optional identifier?: string

nameOfAlternateCodingSystem?​

readonly optional nameOfAlternateCodingSystem?: string

nameOfCodingSystem?​

readonly optional nameOfCodingSystem?: string

originalText?​

readonly optional originalText?: string

text?​

readonly optional text?: string


CX​

HL7 v2 Extended Composite ID (CX): structured identifier per HL7 Chapter 2. All 10 components are optional. Fields are OMITTED when the underlying component is absent (exactOptionalPropertyTypes). assigningAuthority uses the nested HD shape; assigningFacility is flattened to a plain string in v1.

Component positions (HL7 1-indexed; this interface is 0-indexed by key):

  1. idNumber
  2. checkDigit
  3. checkDigitScheme (ISO 7064, M10, M11, NPI)
  4. assigningAuthority (nested HD: 3 subcomponents form a HD composite)
  5. identifierTypeCode (MR, SSN, DL, MC, ...)
  6. assigningFacility (v1: flattened to string; spec is HD-shaped)
  7. effectiveDate (raw HL7 TS string)
  8. expirationDate (raw HL7 TS string)
  9. assigningJurisdiction (v1: flattened to string)
  10. assigningAgencyOrDepartment (v1: flattened to string)

Example​

import type { CX } from "@cosyte/hl7";
const mrn: CX = {
idNumber: "123456",
assigningAuthority: { namespaceId: "EPIC", universalId: "1.2.840.114350", universalIdType: "ISO" },
identifierTypeCode: "MR",
};

Properties​

assigningAgencyOrDepartment?​

readonly optional assigningAgencyOrDepartment?: string

assigningAuthority?​

readonly optional assigningAuthority?: HD

assigningFacility?​

readonly optional assigningFacility?: string

assigningJurisdiction?​

readonly optional assigningJurisdiction?: string

checkDigit?​

readonly optional checkDigit?: string

checkDigitScheme?​

readonly optional checkDigitScheme?: string

effectiveDate?​

readonly optional effectiveDate?: string

expirationDate?​

readonly optional expirationDate?: string

identifierTypeCode?​

readonly optional identifierTypeCode?: string

idNumber?​

readonly optional idNumber?: string


DefineProfileOptions​

Options accepted by defineProfile() (D-02). Mirrors the locked Profile shape plus the extends input key. Every field except name is optional.

Example​

import { defineProfile, type DefineProfileOptions } from "@cosyte/hl7";
const opts: DefineProfileOptions = {
name: "my-lab",
dateFormats: ["MM/DD/YYYY"],
customSegments: { ZLB: { fields: { noteText: 3 } } },
};
const profile = defineProfile(opts);

Properties​

customSegments?​

readonly optional customSegments?: Readonly<Record<string, CustomSegmentDefinition>>

dateFormats?​

readonly optional dateFormats?: readonly string[]

description?​

readonly optional description?: string

extends?​

readonly optional extends?: Profile | readonly Profile[]

name​

readonly name: string

onWarning?​

readonly optional onWarning?: OnWarningCallback


Diagnosis​

DG1-derived diagnosis entry (HELPERS-06). dateTime is the fidelity TS.

Example​

import type { Diagnosis } from "@cosyte/hl7";
const dg: Diagnosis = {
code: { identifier: "E11.9", text: "Type 2 diabetes" },
description: "Type 2 diabetes mellitus without complications",
type: "F",
};

Properties​

code?​

readonly optional code?: CWE

DG1-3 diagnosis code.

dateTime?​

readonly optional dateTime?: DtmParts

DG1-5 diagnosis date/time as the fidelity TS.

description?​

readonly optional description?: string

DG1-4 diagnosis description.

type?​

readonly optional type?: string

DG1-6 diagnosis type (A=admitting, W=working, F=final).


DotPath​

Parsed representation of a dot-path string. Produced by parsePath, consumed by resolvePath. All numeric indices are normalized to the internal convention (segmentIndex = 0-based occurrence, fieldIndex = 1-based HL7 field number, repetitionIndex = 0-based rep, componentIndex and subcomponentIndex = 1-based HL7 positions).

Example​

import { parsePath } from "@cosyte/hl7";
parsePath("OBX[2].5.1");
// { segmentType: "OBX", segmentIndex: 2, fieldIndex: 5,
// repetitionIndex: 0, componentIndex: 1 }

Properties​

componentIndex?​

readonly optional componentIndex?: number

1-based HL7 component position (within a repetition).

fieldIndex​

readonly fieldIndex: number

1-based HL7 field number; maps to RawSegment.fields[fieldIndex].

repetitionIndex?​

readonly optional repetitionIndex?: number

0-based repetition index; defaults to 0 when [N] is omitted.

segmentIndex​

readonly segmentIndex: number

0-based occurrence of this segment type in the message.

segmentType​

readonly segmentType: string

3-char segment identifier (e.g. "PID", "OBX", "ZPI").

subcomponentIndex?​

readonly optional subcomponentIndex?: number

1-based HL7 subcomponent position (within a component).


DtmParts​

Parsed HL7 v2 TS/DTM value: the raw string plus its structural parts, with the stated precision and timezone fidelity preserved. This is the shape of the TS composite (field.asTs()) and every helper datetime.

The parts are only populated when valid is true. month/day/… are spec-native (month is 1–12, NOT the JS Date 0–11). offsetMinutes is present iff hasTimezone is true and is signed minutes east of UTC (+0500 → 300, -0430 → -270). A missing offset is flagged (hasTimezone: false), never resolved to UTC: the consumer decides how to localize with dtmToDate.

Example​

import type { DtmParts } from "@cosyte/hl7";
const dob: DtmParts = {
raw: "19880705", valid: true, precision: "day",
year: 1988, month: 7, day: 5, hasTimezone: false,
};

Properties​

day?​

readonly optional day?: number

Day of month, 1–31.

fractionalSeconds?​

readonly optional fractionalSeconds?: string

Fractional-second digits exactly as populated (no leading dot), e.g. "5" (0.5 s), "0500" (0.05 s). Preserved verbatim: never rounded.

hasTimezone​

readonly hasTimezone: boolean

true iff an explicit +/-ZZZZ offset was present.

hour?​

readonly optional hour?: number

Hour, 0–23.

matchedFormat?​

readonly optional matchedFormat?: string

The fallback format that matched (parseDtmCascade only), e.g. "MM/DD/YYYY" or "ISO-8601". Absent for a strict HL7 DTM parse.

minute?​

readonly optional minute?: number

Minute, 0–59.

month?​

readonly optional month?: number

Month, 1–12 (spec-native, NOT JS 0–11).

offsetMinutes?​

readonly optional offsetMinutes?: number

Signed minutes east of UTC; present iff hasTimezone is true.

precision?​

readonly optional precision?: DtmPrecision

Stated precision; absent when valid is false.

raw​

readonly raw: string

The original HL7 string, exactly as it appeared (already unescaped).

second?​

readonly optional second?: number

Second, 0–59.

valid​

readonly valid: boolean

true when raw is a well-formed, in-range HL7 DTM (or a matched fallback format). false for empty, malformed, or calendar-out-of-range input: in which case only raw and hasTimezone: false are meaningful.

year?​

readonly optional year?: number

Four-digit year.


DtmToDateOptions​

Options controlling how dtmToDate resolves a missing timezone.

Example​

import { parseDtm, dtmToDate } from "@cosyte/hl7";
// Treat an offset-less value as UTC (an explicit caller choice):
dtmToDate(parseDtm("20250102"), { assumeOffsetMinutes: 0 });
// ...or as US Eastern standard time (UTC-05:00):
dtmToDate(parseDtm("20250102"), { assumeOffsetMinutes: -300 });

Properties​

assumeOffsetMinutes?​

readonly optional assumeOffsetMinutes?: number

Offset (signed minutes east of UTC) to assume when the value carries no timezone. Without it, an offset-less value resolves to undefined, dtmToDate never guesses a zone. Ignored when the value already has an offset. Pass 0 to explicitly treat a naive value as UTC.


EncodingCharacters​

The HL7 delimiter characters discovered from MSH-1 (field separator) and MSH-2 (encoding characters). The first four: component, repetition, escape, subcomponent: are mandatory across all HL7 v2 versions. The fifth, truncation, is the v2.7+ truncation character (default # per spec §2.5.5.2): only present when MSH-2 actually carries 5 encoding characters, so messages that pre-date v2.7 round-trip with a 4-char MSH-2 unchanged.

Example​

import type { EncodingCharacters } from "@cosyte/hl7";
const v25: EncodingCharacters = {
field: "|",
component: "^",
repetition: "~",
escape: "\\",
subcomponent: "&",
};
const v27: EncodingCharacters = { ...v25, truncation: "#" };

Properties​

component​

readonly component: string

escape​

readonly escape: string

field​

readonly field: string

repetition​

readonly repetition: string

subcomponent​

readonly subcomponent: string

truncation?​

readonly optional truncation?: string


ExpectedSegmentGroup​

One expected segment group for a recognized trigger event. The group is considered present when at least one of its anchorSegments appears in the parsed message; its total absence is what signals a truncated or misrouted message.

Properties​

anchorSegments​

readonly anchorSegments: readonly string[]

The segment name(s) whose presence proves this group is present. Only segments the HL7 v2.5.1 abstract syntax marks Required (R) for the owning trigger event appear here, so a conformant message can never lack all of them.

name​

readonly name: string

Human-readable group label, e.g. "result", "patient", "order".


FieldRule​

A rule for one field position within a segment. Every constraint is optional; a rule with only a field index is a no-op.

Remarks​

field is the 1-indexed HL7 position (MSH offset handled internally, exactly like Segment.field(n): { field: 9 } on MSH targets MSH-9). Length and value-set checks read the value at component (default 1), so a coded field's code (CWE.1 / CE.1) is checked by default; set component to check a different component. Both are applied per present repetition.

Properties​

cardinality?​

readonly optional cardinality?: Cardinality

Repetition-count constraint for this field.

component?​

readonly optional component?: number

1-indexed component whose value the length / valueSet checks read. Defaults to 1 (the first component: a coded element's code).

field​

readonly field: number

1-indexed HL7 field position (e.g. 3 for PID-3, 9 for MSH-9).

length?​

readonly optional length?: number

Maximum character length of the checked component value (inclusive).

name?​

readonly optional name?: string

Optional human label for the field (e.g. "Patient Identifier List"). Structural documentation for the profile author only: findings identify a field by its PHI-free structural locus (segment + index), never by this label, so the label is never echoed into a finding message.

severity?​

readonly optional severity?: FindingSeverity

Severity for findings this rule produces. Defaults to "error". A profile author can downgrade a data-quality rule (e.g. a length or value-set check) to "warning" or "info" without changing the check itself.

usage?​

readonly optional usage?: UsageCode

Usage constraint (see UsageCode). Omitted ⇒ Optional.

valueSet?​

readonly optional valueSet?: readonly string[]

Consumer-supplied permitted-value list. The checked component value must be a member (case-sensitive exact match). hl7 ships no code set: this is BYO terminology; membership is a literal string check, never a LOINC / SNOMED / ICD / RxNorm lookup and never a network call.


FindingLocus​

The structural locus a finding refers to: segment name plus, where applicable, the field position, component, repetition, and segment occurrence. Every member is a name or an index: a locus is inherently PHI-free and never carries a field value.

A finding with no field is segment-level (presence / cardinality of the segment itself); a finding with a field is field-level. For a FINDING_CODES.PROFILE_MALFORMED diagnostic (a defect in the profile, not the message) segment may be the sentinel "(profile)".

Properties​

component?​

readonly optional component?: number

1-indexed component, when a component-scoped check (length / value-set) fired.

field?​

readonly optional field?: number

1-indexed field position, when the finding is field-level.

occurrence?​

readonly optional occurrence?: number

0-indexed segment occurrence, when the segment type repeats.

repetition?​

readonly optional repetition?: number

0-indexed field repetition, when the finding is repetition-scoped.

segment​

readonly segment: string

Segment name (e.g. "PID"), or "(profile)" for a profile-shape defect.


HD​

HL7 v2 Hierarchic Designator (HD): per HL7 Chapter 2 data type. All 3 components are optional. Fields are OMITTED when the underlying component is absent (exactOptionalPropertyTypes).

Component positions (HL7 1-indexed; this interface is 0-indexed by key):

  1. namespaceId: application- or facility-scoped identifier (e.g. "EPIC").
  2. universalId: globally-unique id (e.g. an OID or UUID string).
  3. universalIdType: classifier for universalId (ISO, GUID, UUID, DNS, URI, HL7, HCD, Random, etc.).

Example​

import type { HD } from "@cosyte/hl7";
const authority: HD = { namespaceId: "EPIC", universalId: "1.2.840.114350", universalIdType: "ISO" };

Properties​

namespaceId?​

readonly optional namespaceId?: string

universalId?​

readonly optional universalId?: string

universalIdType?​

readonly optional universalIdType?: string


Hl7ParseWarning​

Data shape for every Tier-2 warning emitted by the parser. Warnings are plain data (distinct from Hl7ParseError, which is a thrown Error subclass) so they can be safely accumulated into Hl7Message.warnings and passed to onWarning callbacks.

Example​

import type { Hl7ParseWarning } from "@cosyte/hl7";
const w: Hl7ParseWarning = {
code: "UNKNOWN_SEGMENT",
message: "Unknown segment: ZZZ",
position: { segmentIndex: 4 },
};

Properties​

code​

readonly code: WarningCode

message​

readonly message: string

position​

readonly position: Hl7Position


Hl7Position​

Positional context attached to every warning and fatal error. Fields are 1-indexed against the HL7 spec convention (see RawSegment.fields for the index 0 slot convention). All fields past segmentIndex are optional, for a top-level fatal like EMPTY_INPUT only segmentIndex: 0 is populated; for a tokenizer warning deep inside a subcomponent all five indices may be set.

Remarks​

With exactOptionalPropertyTypes: true, do not pass fieldIndex: undefined explicitly: omit the key instead.

Example​

import type { Hl7Position } from "@cosyte/hl7";
const pos: Hl7Position = { segmentIndex: 2, fieldIndex: 5 };

Properties​

componentIndex?​

readonly optional componentIndex?: number

fieldIndex?​

readonly optional fieldIndex?: number

repetitionIndex?​

readonly optional repetitionIndex?: number

segmentIndex​

readonly segmentIndex: number

subcomponentIndex?​

readonly optional subcomponentIndex?: number


IdentityEvent​

One recognized patient-identity event. For merge / move kinds the surviving (PID/PV1-sourced) and prior (MRG-sourced) parties are also exposed directly, with the spec-constant direction: "MRG_TO_PID": the prior identifiers are the ones being retired in favour of the surviving ones, never the reverse (HL7 v2 Ch. 3, A18/A39/A40).

parties is the complete role-labelled surface in document order: nothing present in the message is dropped, including a nonconforming MRG in a link/add message (surfaced as a prior-role party).

warnings carries the event's own fail-safe warnings (currently MERGE_MISSING_PRIOR_OR_SURVIVOR); they are scoped to the event and are NOT appended to Hl7Message.warnings (a read-side helper never mutates the message).

Example​

import { parseHL7 } from "@cosyte/hl7";
for (const ev of parseHL7(raw).identityEvents()) {
if (ev.kind === "merge" && ev.prior && ev.surviving) {
// retire ev.prior.identifiers in favour of ev.surviving.identifiers
} else if (ev.warnings.length > 0) {
// incomplete pair: do NOT apply; route for review
}
}

Properties​

direction?​

readonly optional direction?: "MRG_TO_PID"

Spec-constant merge/move direction: the MRG (prior) identifiers merge INTO the PID (surviving) identifiers. Present on merge / move events only; never inferred from content.

eventType​

readonly eventType: string

Trigger event code (MSH-9.2, falling back to EVN-1), e.g. "A40".

kind​

readonly kind: IdentityEventKind

Classification of the trigger event.

parties​

readonly parties: readonly IdentityParty[]

Every party in document order, role-labelled: the complete surface.

prior?​

readonly optional prior?: IdentityParty

The prior (non-surviving) party (merge/move): ONLY ever sourced from MRG.

surviving?​

readonly optional surviving?: IdentityParty

The surviving party (merge/move): ONLY ever sourced from PID/PV1.

warnings​

readonly warnings: readonly Hl7ParseWarning[]

Event-scoped fail-safe warnings (never PHI-bearing).


IdentityParty​

One party (one patient identity) in an identity event, labelled by role with its source segment recorded as provenance. Absent fields are OMITTED (exactOptionalPropertyTypes). All arrays and the object itself are frozen.

Field sources by sourceSegment:

  • "PID": identifiers = PID-3 repetitions, legacyPatientId = PID-2 (pre-v2.7 only), accountNumber = PID-18, visitNumber = PV1-19 (from the group's PV1, when present), name = PID-5 (first repetition).
  • "MRG": identifiers = MRG-1 repetitions, legacyPatientId = MRG-4 (pre-v2.7 only), accountNumber = MRG-3, visitNumber = MRG-5, name = MRG-7 (first repetition).

Example​

import { parseHL7 } from "@cosyte/hl7";
const ev = parseHL7(raw).identityEvents()[0];
if (ev?.prior) {
console.log(ev.prior.role); // "prior"
console.log(ev.prior.sourceSegment); // "MRG"
for (const cx of ev.prior.identifiers) console.log(cx.idNumber);
}

Properties​

accountNumber?​

readonly optional accountNumber?: CX

Patient account number (PID-18 / MRG-3).

identifiers​

readonly identifiers: readonly CX[]

Identifier list (PID-3 / MRG-1), every non-empty CX repetition.

legacyPatientId?​

readonly optional legacyPatientId?: CX

Legacy single patient ID (PID-2 / MRG-4). Backward-compat only; withdrawn as of HL7 v2.7: OMITTED (not read) when MSH-12 declares v2.7 or later.

name?​

readonly optional name?: XPN

Patient name (PID-5 / MRG-7, first repetition).

role​

readonly role: IdentityRole

Role of this party in the event: the safety-critical label.

sourceSegment​

readonly sourceSegment: "PID" | "MRG"

Segment this party was sourced from: provenance for the role label.

visitNumber?​

readonly optional visitNumber?: CX

Visit number (PV1-19 for a PID party / MRG-5 for a prior party).


Immunization​

A vaccine dose extracted from one RXA (Pharmacy/Treatment Administration) segment of a VXU^V04 immunization message, with its RXR (route/site) and OBX (e.g. VFC eligibility / funding source) children grouped positionally under the RXA, and orderControl from the preceding ORC of the VXU order group (ORC→RXA→[RXR]→[{OBX}]).

Safety contract. A wrong vaccine, dose, or mis-keyed action code can harm a patient or corrupt an IIS (Immunization Information System) registry, so this view is deliberately conservative:

  • vaccineCode carries its own coding-system provenance via the CWE (vaccineCode.nameOfCodingSystem: CVX HL7 Table 0292; live IIS feeds frequently dual-code RXA-5 with an alternate CVX/NDC in CWE.4-6, surfaced as vaccineCode.alternateIdentifier/alternateText/nameOfAlternateCodingSystem). The helper reports the claim; it never validates or looks the code up.
  • actionCode (RXA-21, A/D/U) is surfaced verbatim and never defaulted: mis-keying it corrupts a registry's add/delete/update dedup.
  • doseAmount is strict-Number() parsed; the IIS "unknown dose" sentinel 999 is surfaced as the number 999, never specially coerced.
  • recordOrigin (administered vs historical) is derived only from the well-known NIP001 RXA-9.1 codes and OMITTED otherwise: see ImmunizationRecordOrigin.
  • Malformed RXA segments never throw: absent fields are omitted keys.

routes and observations are ALWAYS present (possibly empty). Deferred (not v1): IIS-specific state profile constraints; CVX/MVX validity checks; the 2nd+ repetition of the repeating RXA-15/16/17 lot/expiry/manufacturer fields (only the first repetition is surfaced).

Example​

import type { Immunization } from "@cosyte/hl7";
const imm: Immunization = {
vaccineCode: { identifier: "115", text: "Tdap", nameOfCodingSystem: "CVX" },
doseAmount: 0.5,
doseUnits: { identifier: "mL", nameOfCodingSystem: "UCUM" },
doseUnitsAreUcum: true,
recordOrigin: "administered",
manufacturer: { identifier: "PMC", text: "Sanofi Pasteur", nameOfCodingSystem: "MVX" },
completionStatus: "CP",
actionCode: "A",
routes: [{ route: { identifier: "IM", text: "Intramuscular" } }],
observations: [],
};

Properties​

actionCode?​

readonly optional actionCode?: string

RXA-21 action code (A=add, D=delete, U=update): preserved verbatim, NEVER defaulted.

administeredDateTime?​

readonly optional administeredDateTime?: DtmParts

RXA-3 date/time start of administration as the fidelity TS.

completionStatus?​

readonly optional completionStatus?: string

RXA-20 completion status (CP=complete, RE=refused, NA=not administered, PA=partially administered).

doseAmount?​

readonly optional doseAmount?: number

RXA-6 administered dose amount (strict-parsed; never NaN). 999 = IIS "unknown", surfaced as-is.

doseUnits?​

readonly optional doseUnits?: CWE

RXA-7 administered dose units (UCUM).

doseUnitsAreUcum?​

readonly optional doseUnitsAreUcum?: boolean

true iff RXA-7's coding system (CWE.3) is exactly UCUM (HL7 Table 0396) : i.e. the dose unit is declared UCUM and safe to interpret as computable. false means a unit IS present but is NOT declared UCUM (surfaced as-is, never coerced). OMITTED when RXA-7 is absent. A claim check only: UCUM grammar is not validated here.

expirationDate?​

readonly optional expirationDate?: DtmParts

RXA-16 substance expiration date (first repetition) as the fidelity TS.

informationSource?​

readonly optional informationSource?: CWE

RXA-9 immunization information source (HL7 Table NIP001), preserved verbatim.

lotNumber?​

readonly optional lotNumber?: string

RXA-15 substance lot number (first repetition).

manufacturer?​

readonly optional manufacturer?: CWE

RXA-17 substance manufacturer (MVX, HL7 Table 0227; first repetition).

observations​

readonly observations: readonly Observation[]

OBX children grouped under this RXA (VFC eligibility, funding source, …). Always present (possibly empty).

orderControl?​

readonly optional orderControl?: string

ORC-1 order control when an ORC precedes this RXA in the VXU order group.

recordOrigin?​

readonly optional recordOrigin?: ImmunizationRecordOrigin

Derived administered-vs-historical classification from RXA-9.1. See ImmunizationRecordOrigin.

refusalReason?​

readonly optional refusalReason?: CWE

RXA-18 substance/treatment refusal reason (first repetition).

routes​

readonly routes: readonly MedicationRoute[]

RXR children grouped under this RXA (Table 0162 route / Table 0163 site). Always present (possibly empty).

vaccineCode?​

readonly optional vaccineCode?: CWE

RXA-5 administered vaccine code (CVX, HL7 Table 0292) with provenance + any alternate coding.


Insurance​

IN1-derived insurance entry (HELPERS-06) with positional IN2/IN3 presence flags (D-05 extension). hasIn2 / hasIn3 are ALWAYS present booleans; callers who need the full IN2/IN3 surface can walk msg.segments("IN2").

Example​

import type { Insurance } from "@cosyte/hl7";
const ins: Insurance = {
planId: { identifier: "PLAN1", text: "Aetna PPO" },
policyNumber: "POL123",
groupNumber: "GRP1",
hasIn2: false,
hasIn3: false,
};

Properties​

companyId?​

readonly optional companyId?: CX

IN1-3 insurance company id.

companyName?​

readonly optional companyName?: string

IN1-4 insurance company name (first repetition, first component).

effectiveDate?​

readonly optional effectiveDate?: DtmParts

IN1-12 plan effective date as the fidelity TS.

expirationDate?​

readonly optional expirationDate?: DtmParts

IN1-13 plan expiration date as the fidelity TS.

groupNumber?​

readonly optional groupNumber?: string

IN1-8 group number.

hasIn2​

readonly hasIn2: boolean

true iff an IN2 segment follows this IN1 before the next IN1.

hasIn3​

readonly hasIn3: boolean

true iff an IN3 segment follows this IN1 before the next IN1.

insuredName?​

readonly optional insuredName?: XPN

IN1-16 insured's name.

planId?​

readonly optional planId?: CWE

IN1-2 insurance plan id.

policyNumber?​

readonly optional policyNumber?: string

IN1-36 policy number.


KnownCodingSystem​

One recognized HL7 Table 0396 coding system: its registered acronym (the value expected in CWE.3 / CE.3), a canonical human-readable name, and the widely-used aliases tolerated for it. Aliases are matched case-insensitively.

Properties​

aliases​

readonly aliases: readonly string[]

Widely-used alternative spellings that claim the same system (matched case-insensitively), e.g. "LOINC" for LN. The registered id itself is always recognized and need not be repeated here.

id​

readonly id: string

Registered Table 0396 acronym, e.g. "LN".

name​

readonly name: string

Canonical human-readable name, e.g. "LOINC".


Medication​

A medication extracted from one RXO/RXE/RXD/RXA segment, with its RXR (route) and RXC (component) children grouped positionally. context records which RX* segment this came from (give vs dispense vs administered).

Safety contract. A wrong drug, strength, or route can harm a real patient, so this view is deliberately conservative:

  • giveCode carries its own coding-system provenance via the CWE (giveCode.nameOfCodingSystem: e.g. RXN RxNorm, NDC). The helper surfaces the claim; it never validates or looks the code up.
  • amount (how much) and strength (concentration) are SEPARATE fields and are never reconciled: including against any strength a coded drug implies. A disagreement is preserved for the consumer to see.
  • Malformed RX* segments never throw: absent fields are omitted keys.

routes and components are ALWAYS present (possibly empty). So is timings: empty when no TQ1 / legacy embedded TQ (RXE-1) accompanies the medication; the repeat pattern is surfaced verbatim, never normalized to a schedule. Deferred (not v1): sig/frequency interpretation, dose-range or interaction checking, pharmacologic resolution of compounds.

Example​

import type { Medication } from "@cosyte/hl7";
const med: Medication = {
context: "encoded",
giveCode: { identifier: "1049630", text: "Acetaminophen 325 MG", nameOfCodingSystem: "RXN" },
amount: { minimum: 2, units: { identifier: "TAB" } },
strength: { value: 325, units: { identifier: "mg", nameOfCodingSystem: "UCUM" } },
routes: [{ route: { identifier: "PO", text: "Oral" } }],
components: [],
timings: [{ source: "TQ1", repeatPattern: { code: "Q6H", kind: "parametric", interval: { count: 6, unit: "H" } } }],
};

Properties​

amount?​

readonly optional amount?: MedicationAmount

Give/dispense/administered amount (+ units). See MedicationAmount.

components​

readonly components: readonly MedicationComponent[]

RXC children grouped under this RX* (compound components). Always present (possibly empty).

context​

readonly context: MedicationContext

Which RX* segment this medication came from (give/dispense/administered).

dosageForm?​

readonly optional dosageForm?: CWE

RXO-5 requested dosage form (order context).

giveCode?​

readonly optional giveCode?: CWE

RXO-1 / RXE-2 / RXD-2 / RXA-5 give/dispense/administered drug code, with provenance.

routes​

readonly routes: readonly MedicationRoute[]

RXR children grouped under this RX* (Table 0162 route). Always present (possibly empty).

strength?​

readonly optional strength?: MedicationStrength

RXE-25/26 give strength: ENCODED context only; never reconciled with giveCode.

timings​

readonly timings: readonly OrderTiming[]

TQ1 / legacy embedded-TQ (RXE-1) timing(s) grouped under this medication. Always present: empty when the medication carries no timing. See OrderTiming.


MedicationAmount​

The give / dispense / administered amount of a Medication. Carries the HL7 min/max amount pair and its units.

  • For an order (RXO-2/3) or encoded order (RXE-3/4) the amount is a genuine min..max range: both keys may be present.
  • For a dispense (RXD-4) or administration (RXA-6) there is a SINGLE amount; it is surfaced as minimum with maximum OMITTED. This is a single value, not a range: do not read the absent maximum as "no upper bound on a range".

minimum/maximum are strict-Number() parsed (undefined, never NaN). units is the give/dispense/administered units CWE (RXO-4 / RXE-5 / RXD-5 / RXA-7); check units.nameOfCodingSystem === "UCUM" for computable units.

Example​

import type { MedicationAmount } from "@cosyte/hl7";
const amount: MedicationAmount = { minimum: 250, units: { identifier: "mg", nameOfCodingSystem: "UCUM" } };

Properties​

maximum?​

readonly optional maximum?: number

RXO-3 / RXE-4 maximum. OMITTED for single-amount (dispense/administration) contexts.

minimum?​

readonly optional minimum?: number

RXO-2 / RXE-3 minimum, or the single dispense (RXD-4) / administered (RXA-6) amount.

units?​

readonly optional units?: CWE

RXO-4 / RXE-5 / RXD-5 / RXA-7 give/dispense/administered units.


MedicationComponent​

One RXC (Pharmacy/Treatment Component Order) grouped under its parent RX* segment: a component of a compound/IV. Surfaced STRUCTURALLY (the component list as authored), NOT pharmacologically resolved.

Example​

import type { MedicationComponent } from "@cosyte/hl7";
const c: MedicationComponent = { type: "B", code: { identifier: "D5W", text: "Dextrose 5%" }, amount: 1000 };

Properties​

amount?​

readonly optional amount?: number

RXC-3 component amount (strict-parsed; never NaN).

code?​

readonly optional code?: CWE

RXC-2 component code.

type?​

readonly optional type?: string

RXC-1 component type (e.g. "B"=base, "A"=additive: HL7 Table 0166).

units?​

readonly optional units?: CWE

RXC-4 component units.


MedicationRoute​

One RXR (Pharmacy/Treatment Route) grouped under its parent RX* segment. route is HL7 Table 0162 (CWE); site is Table 0163 (CWE). Provenance travels on the CWE (route.nameOfCodingSystem): a "PO" route is only safe to act on when you know the system it was coded against.

Example​

import type { MedicationRoute } from "@cosyte/hl7";
const r: MedicationRoute = { route: { identifier: "PO", text: "Oral" } };

Properties​

route?​

readonly optional route?: CWE

RXR-1 route of administration (HL7 Table 0162).

site?​

readonly optional site?: CWE

RXR-2 administration site (HL7 Table 0163).


MedicationStrength​

The give strength of an encoded Medication (RXE-25 value + RXE-26 units). Strength is the concentration of active ingredient (e.g. "250 mg"), distinct from the give amount (how much is administered, e.g. "2 tablets"). Only the "encoded" (RXE) context carries strength.

Fail-safe: strength is surfaced exactly as the explicit RXE-25/26 fields declare it, and is NEVER reconciled against any strength implied by the give code (e.g. an NDC that encodes "250 mg"). A consumer that sees both an explicit strength here and a coded drug in giveCode must treat a disagreement as a real signal: the library does not silently pick a winner. value is strict-Number() parsed (undefined, never NaN).

Example​

import type { MedicationStrength } from "@cosyte/hl7";
const strength: MedicationStrength = { value: 250, units: { identifier: "mg", nameOfCodingSystem: "UCUM" } };

Properties​

units?​

readonly optional units?: CWE

RXE-26 give strength units.

value?​

readonly optional value?: number

RXE-25 give strength numeric value (strict-parsed; never NaN).


MessageStructure​

The structure summary for a parsed message: the data behind Hl7Message.structure. For an unrecognized type, recognized is false, expectedGroups is empty, and missingGroups is empty (the safety net is deliberately silent on types it does not model).

Properties​

expectedGroups​

readonly expectedGroups: readonly StructureGroup[]

Per-expected-group presence verdicts (empty when unrecognized).

messageCode​

readonly messageCode: string

MSH-9.1 message code observed on the message. "" when absent, and "<withheld>" when recognized is false and the observed value is not identifier-shaped (MSH-9 can hold a data field on a malformed message).

missingGroups​

readonly missingGroups: readonly string[]

Names of the expected groups that are entirely absent (the warnings).

recognized​

readonly recognized: boolean

true when a MESSAGE_STRUCTURE_DEFINITIONS entry matched the type.

triggerEvent​

readonly triggerEvent: string

MSH-9.2 trigger event observed on the message. "" when absent, and "<withheld>" when recognized is false and the observed value is not identifier-shaped. Note that on the recognized branch this is echoed verbatim, which for a definition matching on message code alone (ACK) means an arbitrary MSH-9.2.


MessageStructureDefinition​

The expected structure of one recognized message type, keyed on the (messageCode, triggerEvent) pair. A definition with an empty triggerEvents list matches on messageCode alone (used for ACK, which carries no trigger event in MSH-9.2).

Properties​

expectedGroups​

readonly expectedGroups: readonly ExpectedSegmentGroup[]

The Required (R) segment groups expected for these events.

messageCode​

readonly messageCode: string

MSH-9.1 message code, e.g. "ORU".

triggerEvents​

readonly triggerEvents: readonly string[]

The MSH-9.2 trigger events this definition applies to, e.g. ["R01"]. An empty list means "match on message code alone" (e.g. ACK).


Meta​

MSH-derived message metadata (HELPERS-01). D-03: always defined on Hl7Message.meta (MSH absence throws NO_MSH_SEGMENT at parse time); individual fields are optional because vendor-quirky messages routinely omit pieces of MSH. timestamp is the fidelity TS (precision + timezone preserved), not an eager UTC-assuming Date.

Example​

import type { Meta } from "@cosyte/hl7";
const meta: Meta = {
type: "ADT^A01",
messageCode: "ADT",
triggerEvent: "A01",
controlId: "MSG001",
version: "2.5",
};
console.log(meta.timestamp?.raw, meta.timestamp?.precision);

Properties​

controlId?​

readonly optional controlId?: string

MSH-10 message control ID: unique per message per sender.

messageCode?​

readonly optional messageCode?: string

MSH-9.1 message code (e.g. "ADT", "ORU").

messageStructure?​

readonly optional messageStructure?: string

MSH-9.3 message structure (e.g. "ADT_A01").

processingId?​

readonly optional processingId?: string

MSH-11.1 processing id (P=production, T=test, D=debug).

receivingApp?​

readonly optional receivingApp?: string

MSH-5.1 receiving application namespace id.

receivingFacility?​

readonly optional receivingFacility?: string

MSH-6.1 receiving facility namespace id.

sendingApp?​

readonly optional sendingApp?: string

MSH-3.1 sending application namespace id.

sendingFacility?​

readonly optional sendingFacility?: string

MSH-4.1 sending facility namespace id.

timestamp?​

readonly optional timestamp?: DtmParts

MSH-7 message date/time as the fidelity TS.

triggerEvent?​

readonly optional triggerEvent?: string

MSH-9.2 trigger event (e.g. "A01", "R01").

type?​

readonly optional type?: string

MSH-9 full message type string, e.g. "ADT^A01" or "ORU^R01^ORU_R01".

version?​

readonly optional version?: string

MSH-12 HL7 version string (e.g. "2.5", "2.5.1").


NextOfKin​

NK1-derived next-of-kin entry (HELPERS-06). Lean subset: callers can reach for msg.segments("NK1") when they need the full NK1 surface.

Example​

import type { NextOfKin } from "@cosyte/hl7";
const nk: NextOfKin = {
name: { familyName: "Doe", givenName: "John" },
relationship: { identifier: "FTH", text: "Father" },
};

Properties​

address?​

readonly optional address?: XAD

NK1-4 address.

contactRole?​

readonly optional contactRole?: CWE

NK1-7 contact role.

name?​

readonly optional name?: XPN

NK1-2 next-of-kin name.

phone?​

readonly optional phone?: XTN

NK1-5 phone (first repetition).

relationship?​

readonly optional relationship?: CWE

NK1-3 relationship to patient (FTH=father, MTH=mother, SPO=spouse, ...).


NM​

HL7 v2 Numeric (NM) composite. Carries both the raw HL7 numeric string and the parsed JS number. .value is undefined when the raw string is empty or not fully numeric: NEVER throws.

Unlike most composites in this phase, both raw and value are ALWAYS-PRESENT keys (not optional): value is explicitly typed as number | undefined so callers can destructure uniformly.

Example​

import type { NM } from "@cosyte/hl7";
const glucose: NM = { raw: "120", value: 120 };
const bad: NM = { raw: "N/A", value: undefined };

Properties​

raw​

readonly raw: string

value​

readonly value: number | undefined


ObservationBase​

Fields shared by every Observation variant, regardless of the OBX-2 value type. Split from the discriminated union to keep the union declaration readable (D-15 locked field list).

Example​

import type { ObservationBase } from "@cosyte/hl7";
const base: ObservationBase = {
setId: "1",
identifier: { identifier: "GLU", text: "Glucose" },
};

Properties​

abnormalFlags?​

readonly optional abnormalFlags?: string

OBX-8 abnormal flags (e.g. "H", "HH", "L", "LL").

identifier​

readonly identifier: CWE

OBX-3 observation identifier. Always present (may be {} if OBX-3 absent).

notes?​

readonly optional notes?: readonly string[]

NTE note lines positionally attached to this OBX: each non-empty NTE-3 (Comment, FT) repetition of every NTE immediately following this observation, HL7-unescaped, in document order. OMITTED when the observation carries no notes. High-PHI-risk clinical narrative.

observedDateTime?​

readonly optional observedDateTime?: DtmParts

OBX-14 date/time of observation as the fidelity TS.

referenceRange?​

readonly optional referenceRange?: string

OBX-7 reference range (e.g. "80-110").

setId?​

readonly optional setId?: string

OBX-1 set id (string: typically sequential "1", "2", ...).

status?​

readonly optional status?: string

OBX-11 observation result status (e.g. "F"=final, "P"=preliminary).

units?​

readonly optional units?: CWE

OBX-6 units.

unitsAreUcum?​

readonly optional unitsAreUcum?: boolean

true iff OBX-6's coding system (CWE.3, "name of coding system") is exactly UCUM (HL7 Table 0396): i.e. the unit is declared UCUM and is safe to interpret as a computable unit. false means a unit IS present but is NOT declared UCUM (e.g. a local code or free text) and is surfaced as-is, never coerced. OMITTED when OBX-6 is absent. This is a claim check only: the library does not validate UCUM grammar or check the alternate coding system (CWE.6).


Order​

OBR-derived order (HELPERS-05, D-16) with positionally-grouped OBX children (D-12). observations is ALWAYS present: empty when no OBX follows this OBR before the next OBR or end-of-message. timings is ALWAYS present, empty when the order carries no TQ1 / legacy embedded TQ.

Example​

import type { Order } from "@cosyte/hl7";
const order: Order = {
placerOrderNumber: "PLACER1",
fillerOrderNumber: "FILLER1",
universalServiceId: { identifier: "GLU", text: "Glucose" },
orderStatus: "F",
observations: [],
timings: [],
};

Properties​

fillerOrderNumber?​

readonly optional fillerOrderNumber?: string

OBR-3 filler order number.

notes?​

readonly optional notes?: readonly string[]

NTE note lines positionally attached to this order: the ORC-region notes (before the OBR) followed by the OBR-region notes, in document order. Several ORCs before one OBR all contribute here; nothing is dropped. OMITTED when the order carries no notes. A note on a trailing or dangling ORC that never opens an order is surfaced at message level (msg.notes()), not here: still never dropped. High-PHI-risk clinical narrative.

observations​

readonly observations: readonly Observation[]

OBX children grouped under this OBR (D-12 positional grouping). Always present.

orderControl?​

readonly optional orderControl?: string

ORC-1 order control when an ORC precedes this OBR.

orderedBy?​

readonly optional orderedBy?: XCN

OBR-16 ordering provider (D-24a XCN).

orderStatus?​

readonly optional orderStatus?: string

OBR-25 result status (HL7 Table 0123, e.g. "F" final, "P" preliminary).

placerOrderNumber?​

readonly optional placerOrderNumber?: string

OBR-2 placer order number.

timings​

readonly timings: readonly OrderTiming[]

TQ1 / legacy embedded-TQ timing(s) grouped under this order. Always present: empty when the order carries no timing. See OrderTiming.

universalServiceId?​

readonly optional universalServiceId?: CWE

OBR-4 universal service identifier (test code + description).


OrderTiming​

The order/medication timing structure: one TQ1 segment (v2.5+) or the legacy embedded TQ in ORC-7 / RXE-1 (pre-v2.5). Attached to Order.timings and Medication.timings.

Safety contract. hl7 surfaces the timing structure; it does not compute administration schedules, resolve "institution-specified times" to clock times, or interpret sig. The load-bearing repeatPattern and totalOccurrences are preserved verbatim (see RepeatPattern); startDateTime/endDateTime keep the TS precision + timezone fidelity. A malformed timing never throws: absent pieces are omitted keys.

Example​

import type { OrderTiming } from "@cosyte/hl7";
const t: OrderTiming = {
source: "TQ1",
quantity: { value: 1 },
repeatPattern: { code: "Q6H", kind: "parametric", interval: { count: 6, unit: "H" } },
totalOccurrences: 20,
};

Properties​

endDateTime?​

readonly optional endDateTime?: DtmParts

TQ1-8 / legacy TQ.5 end date/time as the fidelity TS.

explicitTime?​

readonly optional explicitTime?: string

TQ1-4 / legacy TQ.2 interval RI.2 explicit time(s): surfaced verbatim (first repetition/value).

priority?​

readonly optional priority?: CWE

TQ1-9 priority (CWE) / legacy TQ.6 priority (surfaced as a CWE { identifier }).

quantity?​

readonly optional quantity?: TimingQuantity

TQ1-2 / legacy TQ.1 service quantity (CQ).

repeatPattern?​

readonly optional repeatPattern?: RepeatPattern

TQ1-3 / legacy TQ.2 interval RI.1 repeat pattern (Table 0335): verbatim. See RepeatPattern.

serviceDuration?​

readonly optional serviceDuration?: string

TQ1-6 / legacy TQ.3 service duration: surfaced verbatim.

source​

readonly source: "TQ1" | "legacy"

Which structure this timing was read from: the dedicated TQ1 segment (v2.5+) or the legacy embedded TQ data type in ORC-7 (orders) / RXE-1 (encoded medications, pre-v2.5). The library treats the presence of a TQ1 segment as the v2.5+ signal: the legacy embedded TQ is surfaced only when no TQ1 accompanies the order, so the same timing is never double-counted and a legacy-only timing is never dropped.

startDateTime?​

readonly optional startDateTime?: DtmParts

TQ1-7 / legacy TQ.4 start date/time as the fidelity TS.

totalOccurrences?​

readonly optional totalOccurrences?: number

TQ1-14 / legacy TQ.12 total occurrences (NM): how many times the service is to be performed (strict-parsed; never NaN). TQ1-14, not TQ1-11 (TQ1-11 is Text Instruction). Load-bearing: losing it drops the total administered count.


OruObservation​

Typed OBX (observation / result) content for buildOru.

Properties​

abnormalFlags?​

readonly optional abnormalFlags?: string

OBX-8 Abnormal Flags (e.g. "H", "L", "N").

identifier?​

readonly optional identifier?: CWE

OBX-3 Observation Identifier.

observationDateTime?​

readonly optional observationDateTime?: string | DtmParts

OBX-14 Date/Time of the Observation.

observationResultStatus?​

readonly optional observationResultStatus?: string

OBX-11 Observation Result Status (e.g. "F" final, "P" preliminary).

referenceRange?​

readonly optional referenceRange?: string

OBX-7 References Range.

setId?​

readonly optional setId?: string

OBX-1 Set ID.

units?​

readonly optional units?: CWE

OBX-6 Units.

value?​

readonly optional value?: string

OBX-5 Observation Value (emitted verbatim: the caller owns its formatting).

valueType?​

readonly optional valueType?: string

OBX-2 Value Type (e.g. "NM", "ST", "CE", "TX").


OruOrder​

Typed OBR (observation request / order) content for buildOru.

Properties​

fillerOrderNumber?​

readonly optional fillerOrderNumber?: string

OBR-3 Filler Order Number.

observationDateTime?​

readonly optional observationDateTime?: string | DtmParts

OBR-7 Observation Date/Time.

orderingProvider?​

readonly optional orderingProvider?: XCN | readonly XCN[]

OBR-16 Ordering Provider.

placerOrderNumber?​

readonly optional placerOrderNumber?: string

OBR-2 Placer Order Number.

resultStatus?​

readonly optional resultStatus?: string

OBR-25 Result Status (e.g. "F" final, "P" preliminary, "C" corrected).

setId?​

readonly optional setId?: string

OBR-1 Set ID.

universalServiceId?​

readonly optional universalServiceId?: CWE

OBR-4 Universal Service Identifier.


ParseOptions​

Options accepted by parseHL7 to tune lenient/strict behaviour, inject a profile, and configure optional preprocessing steps. Every field is optional; parseHL7(raw, {}) is valid and produces the library defaults.

Remarks​

With exactOptionalPropertyTypes: true, callers cannot pass { strict: undefined }: either omit the key or pass a boolean. The profile: null form is the explicit opt-out from the process-scoped default profile (PROF-08 semantics); profile omitted means "use the default if one is registered".

Example​

import { parseHL7, type ParseOptions } from "@cosyte/hl7";
const opts: ParseOptions = {
strict: true,
onWarning: (w) => console.warn(w.code),
dateFormats: ["YYYY-MM-DD"],
};
parseHL7(raw, opts);

Properties​

charset?​

readonly optional charset?: string

Override the character set used to decode Buffer input. When supplied this wins over MSH-18 auto-discovery. When both are supplied and they disagree (after alias normalization) the parser emits ENCODING_MISMATCH and honours this override. Ignored for string input.

Example​
import { parseHL7 } from "@cosyte/hl7";
parseHL7(buf, { charset: "ISO-8859-1" });
dateFormats?​

readonly optional dateFormats?: readonly string[]

onWarning?​

readonly optional onWarning?: OnWarningCallback

profile?​

readonly optional profile?: Profile | null

strict?​

readonly optional strict?: boolean

stripMllpFraming?​

readonly optional stripMllpFraming?: boolean

trimFields?​

readonly optional trimFields?: boolean


Patient​

PID-derived patient view (HELPERS-02). msg.patient is undefined (D-04) when no PID segment exists; this interface describes the shape when present. identifiers and phoneNumbers are ALWAYS present as arrays (D-09 / D-20): empty when the underlying field is absent. name is ALWAYS present (D-19) even if {} when PID-5 is empty.

Example​

import type { Patient } from "@cosyte/hl7";
const p: Patient = {
mrn: "MRN123",
identifiers: [{ idNumber: "MRN123", identifierTypeCode: "MR" }],
name: { familyName: "Smith", givenName: "Jane" },
familyName: "Smith",
givenName: "Jane",
fullName: "Jane Smith",
phoneNumbers: [],
};
console.log(p.dateOfBirth?.raw, p.dateOfBirth?.precision);

Properties​

address?​

readonly optional address?: XAD

PID-11 home address parsed as XAD.

dateOfBirth?​

readonly optional dateOfBirth?: DtmParts

PID-7 date of birth as the fidelity TS. A day-only DOB keeps precision: "day": never coerced to a UTC-midnight instant that would read as the previous day in a negative-offset zone.

ethnicity?​

readonly optional ethnicity?: CWE

PID-22 ethnic group.

familyName?​

readonly optional familyName?: string

PID-5.1 flat family name convenience (D-19).

fullName?​

readonly optional fullName?: string

Composed Western-order name "Given Middle Family, Suffix" (D-17).

givenName?​

readonly optional givenName?: string

PID-5.2 flat given name convenience (D-19).

identifiers​

readonly identifiers: readonly CX[]

Full PID-3 identifier list, each parsed as a CX. Always present (D-09).

language?​

readonly optional language?: CE

PID-15 primary language.

middleName?​

readonly optional middleName?: string

PID-5.3 mapped from XPN.secondName (D-19).

mrn?​

readonly optional mrn?: string

Medical record number picked via pickMrn (D-07 / D-08).

name​

readonly name: XPN

Full PID-5 parsed name (first repetition). Always present as {} when empty (D-19).

notes?​

readonly optional notes?: readonly string[]

NTE note lines positionally attached to the (first) PID: notes immediately following the patient's PID segment, HL7-unescaped, in document order. OMITTED when the patient carries no notes. High-PHI-risk clinical narrative.

phoneNumbers​

readonly phoneNumbers: readonly XTN[]

PID-13 (home) + PID-14 (business) repetitions concatenated. Always present (D-20).

race?​

readonly optional race?: CWE

PID-10 race.

sex?​

readonly optional sex?: string

PID-8 administrative sex code.


PL​

HL7 v2 Person Location (PL): structured location per HL7 Chapter 2. All 11 v1 components are optional. Fields are OMITTED when the underlying component is absent (exactOptionalPropertyTypes). facility uses the nested HD shape; assigningAuthorityForLocation is flattened to a plain string in v1 (HL7 spec treats it as HD-shaped).

Component positions (HL7 1-indexed; this interface is 0-indexed by key):

  1. pointOfCare: e.g. "ICU", "ED"
  2. room
  3. bed
  4. facility: nested HD (3 subcomponents form an HD composite)
  5. locationStatus: O=Occupied, U=Unoccupied, K=Contaminated, C=Closed, H=Housekeeping, I=Isolated
  6. personLocationType: C=Clinic, D=Department, H=Home, N=Nursing Unit, O=Office, R=Revenue Location
  7. building
  8. floor
  9. locationDescription: free-text
  10. comprehensiveLocationId
  11. assigningAuthorityForLocation (v1: flattened to string)

Example​

import type { PL } from "@cosyte/hl7";
const bed: PL = {
pointOfCare: "ICU",
room: "101",
bed: "A",
facility: { namespaceId: "HOSP", universalId: "1.2.3", universalIdType: "UUID" },
};

Properties​

assigningAuthorityForLocation?​

readonly optional assigningAuthorityForLocation?: string

bed?​

readonly optional bed?: string

building?​

readonly optional building?: string

comprehensiveLocationId?​

readonly optional comprehensiveLocationId?: string

facility?​

readonly optional facility?: HD

floor?​

readonly optional floor?: string

locationDescription?​

readonly optional locationDescription?: string

locationStatus?​

readonly optional locationStatus?: string

personLocationType?​

readonly optional personLocationType?: string

pointOfCare?​

readonly optional pointOfCare?: string

room?​

readonly optional room?: string


Profile​

Structural placeholder for HL7 profiles. A profile bundles vendor-specific tolerances, date formats, custom segment definitions, and optional callbacks. Profiles are built with the defineProfile() factory.

customSegments is narrowed to the locked CustomSegmentDefinition shape, and Profile carries an optional describe? method so defineProfile()-produced profiles can be introspected without consumers needing to narrow away from the Profile type. The describe method is only populated by defineProfile(): hand-authored Profile objects may omit it.

Example​

import type { Profile } from "@cosyte/hl7";
const epic: Profile = {
name: "epic",
description: "Epic-specific quirks and date formats",
dateFormats: ["YYYYMMDDHHmmss", "YYYYMMDD"],
customSegments: {
ZDP: { fields: { departmentCode: 3, departmentName: 4 } },
},
};

Properties​

customSegments?​

readonly optional customSegments?: Readonly<Record<string, CustomSegmentDefinition>>

dateFormats?​

readonly optional dateFormats?: readonly string[]

describe?​

readonly optional describe?: () => string

Returns​

string

description?​

readonly optional description?: string

lineage?​

readonly optional lineage?: readonly string[]

name​

readonly name: string

onWarning?​

readonly optional onWarning?: OnWarningCallback


RawComponent​

A single component inside a repetition: the most deeply nested data layer in the HL7 positional tree. A component is an ordered list of subcomponent strings (subcomponent separator & by default).

Example​

import type { RawComponent } from "@cosyte/hl7";
const comp: RawComponent = { subcomponents: ["Smith", "John"] };

Properties​

rawSubcomponents?​

readonly optional rawSubcomponents?: readonly (string | undefined)[]

Internal

Escape-fidelity overlay, positionally aligned with subcomponents: for each index, the subcomponent's original wire bytes to emit verbatim instead of re-escaping the decoded form. An entry is present (non-undefined) only when a subcomponent carried an escape whose decoded form does not re-escape back to the exact wire bytes: i.e. a recognize- and-preserve escape (\H\, \Z.., charset/formatting) or a hex escape (\X41\, or non-canonical hex casing). Delimiter escapes (\F→|) round- trip through reescape unchanged and get no overlay. The whole field is absent when no subcomponent needs it (the overwhelming common case), so a plain message's raw tree is byte-for-byte the shape it was before this overlay existed.

Consumed only by the serializer ("src/serialize/emit-field.ts"); never read by the value/coercion surface, so it changes no decoded value.

subcomponents​

readonly subcomponents: readonly string[]

The component's subcomponents, HL7-decoded: the tokenizer expands escape sequences on parse so consumers read literal values (Smith|Jones, not Smith\F\Jones). This is the value surface every reader uses (Field.value, the composite parsers, dot-path, toJSON).


RawField​

A positional field inside a segment. Carries its repetitions plus an isNull discriminant that distinguishes the HL7 explicit null ("", a two-character literal double quote) from an empty field (no content between delimiters).

Example​

import type { RawField } from "@cosyte/hl7";
const nullField: RawField = { repetitions: [], isNull: true };
const emptyField: RawField = { repetitions: [], isNull: false };

Properties​

isNull​

readonly isNull: boolean

repetitions​

readonly repetitions: readonly RawRepetition[]


RawRepetition​

A single repetition inside a field: HL7 fields may repeat using the repetition separator (~ by default). Each repetition is an ordered list of components.

Example​

import type { RawRepetition } from "@cosyte/hl7";
const rep: RawRepetition = { components: [{ subcomponents: ["Smith"] }] };

Properties​

components​

readonly components: readonly RawComponent[]


RawSegment​

A parsed HL7 segment: the top level of the positional tree. The name is the three-character segment identifier (MSH, PID, ZPI, ...) and fields is the 1-indexed positional field array (see the JSDoc on fields for the index 0 slot convention).

Example​

import type { RawSegment } from "@cosyte/hl7";
const pid: RawSegment = {
name: "PID",
fields: [
{ repetitions: [], isNull: false },
],
};

Properties​

fields​

readonly fields: readonly RawField[]

Positional fields array using HL7 1-indexed convention for ALL segments.

  • fields[0] is the segment name / separator placeholder slot (never a data field).
  • fields[N] for N >= 1 is the HL7 N-th field.

Examples:

  • MSH: fields[0] = field-separator char, fields[1] = MSH-2 (encoding chars), fields[2] = MSH-3, ..., fields[11] = MSH-12.
  • PID: fields[0] = "PID" name placeholder, fields[1] = PID-1, fields[2] = PID-2, ....
name​

readonly name: string


RenderedText​

The normalized display model produced by renderText: a flat plain-text string plus the structured highlight-aware runs, plus an honesty list of the escape sequences that were preserved rather than rendered.

Properties​

runs​

readonly runs: readonly TextRun[]

The structured, highlight-aware form: { text, highlighted } runs in document order. Empty runs are elided. Use this to preserve emphasis (bold / reverse-video / etc.) that the flat text drops.

text​

readonly text: string

The full plain-text normalization: formatting commands become whitespace / line breaks and highlight boundaries are dropped. This is the string to show a human or feed a downstream .text. Equal to the concatenation of every runs entry's text.

unrenderedSequences​

readonly unrenderedSequences: readonly string[]

The escape sequences renderText preserved verbatim instead of rendering: vendor \Zdddd…\, charset switches \Cxxyy/\Mxxyyzz, and any malformed / unterminated sequence. Their literal characters ALSO appear in text/runs (never silently dropped); this list exists so a consumer can detect that a non-render decision was made and surface or route those sequences deliberately. Empty when everything rendered cleanly.


RenderTextOptions​

Options for renderText.

Properties​

newline?​

readonly optional newline?: string

The string emitted for each line break (\.br\, \.sp, \.ce\, and a raw CR/LF/CRLF in the input). Defaults to "\n". Set "\r\n" for Windows-style display, or " " to flatten a note to a single line.


RepeatPattern​

An order/medication timing repeat pattern (HL7 Table 0335): the frequency/SIG field (TQ1-3, or the legacy embedded TQ interval RI.1).

Safety contract. code is the decoded field value (HL7 escapes are unescaped as with every field read) and is never resolved to clock times, normalized, or mapped to a different frequency: reading Q6H as "daily" or silently dropping a BID changes the administered dose count, a transcription-class harm. kind/interval are convenience provenance ONLY; code is the authoritative value.

Example​

import type { RepeatPattern } from "@cosyte/hl7";
const q6h: RepeatPattern = { code: "Q6H", kind: "parametric", interval: { count: 6, unit: "H" } };
const bid: RepeatPattern = { code: "BID", kind: "named" };

Properties​

code​

readonly code: string

The Table-0335 repeat-pattern code exactly as authored (e.g. "Q6H", "BID"). Never normalized.

interval?​

readonly optional interval?: object

For a "parametric" Q<integer><unit> template only: the load-bearing integer and its unit letter (S/M/H/D/W/L, or J for day-of-week). OMITTED for "named"/"unknown" patterns. Informational, code remains authoritative.

count​

readonly count: number

unit​

readonly unit: string

kind​

readonly kind: RepeatPatternKind

Provenance classification of code: never used to resolve a schedule. See RepeatPatternKind.


SegmentRule​

A rule for one segment type. usage constrains whether the segment must / must not appear; cardinality constrains how many times; fields are the per-field rules, applied to every occurrence of the segment.

Properties​

cardinality?​

readonly optional cardinality?: Cardinality

Occurrence-count constraint for this segment across the message.

fields?​

readonly optional fields?: readonly FieldRule[]

Per-field rules, applied to each occurrence of this segment.

segment​

readonly segment: string

Segment name: 3 chars, [A-Z][A-Z0-9]{2} (standard or Z… segment).

severity?​

readonly optional severity?: FindingSeverity

Severity for the segment-level presence / cardinality findings. Default "error".

usage?​

readonly optional usage?: UsageCode

Usage for the segment as a whole. R ⇒ at least one occurrence required; X ⇒ none permitted; RE / O ⇒ no presence constraint; C / CE ⇒ presence not evaluated (no predicate language). Omitted ⇒ Optional.


SerializedMessage​

Snapshot-stable JSON projection of an Hl7Message (SER-03). Every field is readonly; segment order is preserved; isNull flags are preserved.

Runtime immutability: the top-level object is Object.freezed (boundary-frozen). Inner arrays are readonly at the TypeScript type level but mutable at runtime: treat as immutable, do not mutate.

Example​

import { parseHL7, type SerializedMessage } from "@cosyte/hl7";
const msg = parseHL7(raw);
const snap: SerializedMessage = msg.toJSON();
console.log(snap.segments[0]?.name); // "MSH"
console.log(snap.warnings.length); // 0 when clean
console.log(JSON.stringify(msg) === JSON.stringify(snap)); // true
console.log(Object.isFrozen(snap)); // true (D-30 boundary freeze)

Properties​

encodingCharacters​

readonly encodingCharacters: EncodingCharacters

profile?​

readonly optional profile?: object

lineage​

readonly lineage: readonly string[]

name​

readonly name: string

segments​

readonly segments: readonly object[]

warnings​

readonly warnings: readonly Hl7ParseWarning[]


SN​

HL7 v2 Structured Numeric (SN) composite. num1 and num2 are ALWAYS-PRESENT keys (typed number | undefined) so callers can destructure uniformly, mirroring NM; comparator and separatorOrSuffix are OMITTED when absent (exactOptionalPropertyTypes).

An absent comparator means the default = relation per HL7 Chapter 2A. This library surfaces the structure only: it does not evaluate the inequality, validate the unit, or convert values.

Example​

import type { SN } from "@cosyte/hl7";
const gfr: SN = { comparator: ">", num1: 90, num2: undefined }; // >90
const range: SN = { num1: 100, separatorOrSuffix: "-", num2: 200 }; // 100-200

Properties​

comparator?​

readonly optional comparator?: string

SN.1 comparator: one of > < >= <= = <>. Omitted ⇒ default =.

num1​

readonly num1: number | undefined

SN.2 first numeric value. undefined when absent or non-numeric (never NaN).

num2​

readonly num2: number | undefined

SN.4 second numeric value. undefined when absent or non-numeric (never NaN).

separatorOrSuffix?​

readonly optional separatorOrSuffix?: string

SN.3 separator/suffix: - (range), :// (ratio), + (suffix), .. Omitted when absent.


StructureGroup​

The presence verdict for one expected group of a recognized message type.

Properties​

anchorSegments​

readonly anchorSegments: readonly string[]

The anchor segment name(s) whose presence would satisfy this group.

name​

readonly name: string

The group label from its ExpectedSegmentGroup, e.g. "result".

present​

readonly present: boolean

true when at least one anchor segment is present in the message.


TextRun​

One contiguous run of rendered display text, tagged with whether it fell inside a \H…\N highlight span. Runs preserve emphasis boundaries that the flat RenderedText.text intentionally drops.

Properties​

highlighted​

readonly highlighted: boolean

true when this run is inside a \H\…\N highlight span.

text​

readonly text: string

The literal display text of this run: escape sentinels already resolved (delimiter/hex decoded, formatting → whitespace/line breaks). Never contains a formatting sentinel; may contain the newline used for breaks.


TimingQuantity​

A composite-quantity (CQ) value on an order/medication timing: the TQ1-2 service quantity. value is strict-Number() parsed (undefined, never NaN); units carries any CQ.2 units. Both keys OMITTED when absent.

Example​

import type { TimingQuantity } from "@cosyte/hl7";
const q: TimingQuantity = { value: 1, units: { identifier: "tablet" } };

Properties​

units?​

readonly optional units?: CWE

CQ.2 units.

value?​

readonly optional value?: number

CQ.1 quantity numeric value (strict-parsed; never NaN).


Visit​

PV1-derived visit view (HELPERS-03). msg.visit is undefined when no PV1 segment exists; this interface describes the shape when present. D-24a: doctor fields use XCN (not flat strings). Date/time fields are the fidelity TS (precision + timezone preserved).

Example​

import type { Visit } from "@cosyte/hl7";
const v: Visit = {
patientClass: "I",
location: { pointOfCare: "ICU", room: "101" },
visitNumber: "VISIT001",
};
console.log(v.attendingDoctor?.familyName);
console.log(v.admitDateTime?.raw);

Properties​

admitDateTime?​

readonly optional admitDateTime?: DtmParts

PV1-44 admit date/time as the fidelity TS.

attendingDoctor?​

readonly optional attendingDoctor?: XCN

PV1-7 attending doctor (D-24a XCN).

dischargeDateTime?​

readonly optional dischargeDateTime?: DtmParts

PV1-45 discharge date/time as the fidelity TS.

location?​

readonly optional location?: PL

PV1-3 assigned patient location (ward / room / bed) as PL.

patientClass?​

readonly optional patientClass?: string

PV1-2 patient class ("I"=inpatient, "O"=outpatient, "E"=ER, ...).

referringDoctor?​

readonly optional referringDoctor?: XCN

PV1-8 referring doctor (D-24a XCN).

visitNumber?​

readonly optional visitNumber?: string

PV1-19 visit number.


XAD​

HL7 v2 Extended Address (XAD): structured postal address per HL7 Chapter 2. All 12 components are optional. Fields are OMITTED when the underlying component is absent (exactOptionalPropertyTypes).

Component positions (HL7 1-indexed; this interface is 0-indexed by key):

  1. street: street address (house number + street name).
  2. otherDesignation: apartment number, suite, floor, etc.
  3. city
  4. stateOrProvince
  5. zipOrPostalCode
  6. country (ISO-3166 3-letter, e.g. "USA", "CAN")
  7. addressType (H=Home, B=Business, M=Mailing, O=Office, P=Permanent, ...)
  8. otherGeographicDesignation
  9. countyParishCode
  10. censusTract
  11. addressRepresentationCode
  12. addressValidityRange

Example​

import type { XAD } from "@cosyte/hl7";
const addr: XAD = { street: "123 Main St", city: "Boston", stateOrProvince: "MA" };

Properties​

addressRepresentationCode?​

readonly optional addressRepresentationCode?: string

addressType?​

readonly optional addressType?: string

addressValidityRange?​

readonly optional addressValidityRange?: string

censusTract?​

readonly optional censusTract?: string

city?​

readonly optional city?: string

country?​

readonly optional country?: string

countyParishCode?​

readonly optional countyParishCode?: string

otherDesignation?​

readonly optional otherDesignation?: string

otherGeographicDesignation?​

readonly optional otherGeographicDesignation?: string

stateOrProvince?​

readonly optional stateOrProvince?: string

street?​

readonly optional street?: string

zipOrPostalCode?​

readonly optional zipOrPostalCode?: string


XCN​

HL7 v2 Extended Composite ID Number and Name for Persons (XCN): per HL7 Chapter 2.A.88. All 13 v1 components are optional. Fields are OMITTED when the underlying component is absent (exactOptionalPropertyTypes).

Component positions (HL7 1-indexed; this interface is 0-indexed by key):

  1. idNumber: e.g. employee ID, NPI digits, DEA number (CX-1 analogue)
  2. familyName (XPN-1)
  3. givenName (XPN-2)
  4. secondName: second and further given names (XPN-3)
  5. suffix: Jr., III, etc. (XPN-4)
  6. prefix: Dr., Mrs., etc. (XPN-5)
  7. degree: MD, PhD, etc. (XPN-6)
  8. sourceTable
  9. assigningAuthority: nested HD (CX-4 analogue)
  10. nameTypeCode: L=Legal, M=Maiden, N=Nickname, ... (XPN-7)
  11. identifierCheckDigit
  12. checkDigitScheme: ISO 7064, M10, M11, NPI
  13. identifierTypeCode: "NPI", "DN" (DEA number), ... (CX-5 analogue)

Example​

import type { XCN } from "@cosyte/hl7";
const orderingProvider: XCN = {
idNumber: "1234567890",
familyName: "Smith",
givenName: "Jane",
identifierTypeCode: "NPI",
};

Properties​

assigningAuthority?​

readonly optional assigningAuthority?: HD

checkDigitScheme?​

readonly optional checkDigitScheme?: string

degree?​

readonly optional degree?: string

familyName?​

readonly optional familyName?: string

givenName?​

readonly optional givenName?: string

identifierCheckDigit?​

readonly optional identifierCheckDigit?: string

identifierTypeCode?​

readonly optional identifierTypeCode?: string

idNumber?​

readonly optional idNumber?: string

nameTypeCode?​

readonly optional nameTypeCode?: string

prefix?​

readonly optional prefix?: string

secondName?​

readonly optional secondName?: string

sourceTable?​

readonly optional sourceTable?: string

suffix?​

readonly optional suffix?: string


XPN​

HL7 v2 Extended Person Name (XPN): structured name per HL7 Chapter 2. All 14 components are optional. Fields are OMITTED when the underlying component is absent (exactOptionalPropertyTypes).

Component positions (HL7 1-indexed; this interface is 0-indexed by key):

  1. familyName
  2. givenName
  3. secondName (or "second and further given names")
  4. suffix (e.g. Jr., III)
  5. prefix (e.g. Dr., Mrs.)
  6. degree (e.g. MD, PhD)
  7. nameTypeCode (L=Legal, M=Maiden, N=Nickname, S=Coded Pseudo-Name, ...)
  8. nameRepresentationCode
  9. nameContext (flattened to string in v1: CWE nesting is out of scope)
  10. nameValidityRange
  11. nameAssemblyOrder (F=family first, G=given first)
  12. effectiveDate (raw HL7 TS string: caller may parse via parseDtm)
  13. expirationDate
  14. professionalSuffix

Example​

import type { XPN } from "@cosyte/hl7";
const name: XPN = { familyName: "Smith", givenName: "Jane", prefix: "Mrs." };

Properties​

degree?​

readonly optional degree?: string

effectiveDate?​

readonly optional effectiveDate?: string

expirationDate?​

readonly optional expirationDate?: string

familyName?​

readonly optional familyName?: string

givenName?​

readonly optional givenName?: string

nameAssemblyOrder?​

readonly optional nameAssemblyOrder?: string

nameContext?​

readonly optional nameContext?: string

nameRepresentationCode?​

readonly optional nameRepresentationCode?: string

nameTypeCode?​

readonly optional nameTypeCode?: string

nameValidityRange?​

readonly optional nameValidityRange?: string

prefix?​

readonly optional prefix?: string

professionalSuffix?​

readonly optional professionalSuffix?: string

secondName?​

readonly optional secondName?: string

suffix?​

readonly optional suffix?: string


XTN​

HL7 v2 Extended Telecommunication Number (XTN): structured telecom per HL7 Chapter 2. All 12 v1 components are optional. Fields are OMITTED when the underlying component is absent (exactOptionalPropertyTypes).

Component positions (HL7 1-indexed; this interface is 0-indexed by key):

  1. telephoneNumber: formatted or unformatted phone number
  2. telecommunicationUseCode: PRN=Primary Residence, WPN=Work, NET=Internet, ORN=Other Residence, BPN=Beeper, VHN=Vacation Home, ASN=Answering Service, EMR=Emergency, ...
  3. telecommunicationEquipmentType: PH=Phone, FX=Fax, MD=Modem, CP=Cellular Phone, BP=Beeper, Internet, X.400, TDD, TTY
  4. emailAddress
  5. countryCode (e.g. "+1")
  6. areaCityCode
  7. localNumber
  8. extension
  9. anyText: free-text note
  10. extensionPrefix (e.g. "x")
  11. speedDialCode
  12. unformattedTelephoneNumber

Example​

import type { XTN } from "@cosyte/hl7";
const phone: XTN = {
telephoneNumber: "(555) 555-1234",
telecommunicationUseCode: "WPN",
telecommunicationEquipmentType: "PH",
};

Properties​

anyText?​

readonly optional anyText?: string

areaCityCode?​

readonly optional areaCityCode?: string

countryCode?​

readonly optional countryCode?: string

emailAddress?​

readonly optional emailAddress?: string

extension?​

readonly optional extension?: string

extensionPrefix?​

readonly optional extensionPrefix?: string

localNumber?​

readonly optional localNumber?: string

speedDialCode?​

readonly optional speedDialCode?: string

telecommunicationEquipmentType?​

readonly optional telecommunicationEquipmentType?: string

telecommunicationUseCode?​

readonly optional telecommunicationUseCode?: string

telephoneNumber?​

readonly optional telephoneNumber?: string

unformattedTelephoneNumber?​

readonly optional unformattedTelephoneNumber?: string

Type Aliases​

AckCode​

AckCode = typeof ACK_CODES[keyof typeof ACK_CODES]

Acknowledgment code union (HL7 Table 0008). Narrow on this to know whether a disposition is accept (AA/CA), error (AE/CE), or reject (AR/CR).


AckCondition​

AckCondition = typeof ACK_CONDITIONS[keyof typeof ACK_CONDITIONS]

Accept/application acknowledgment condition union (HL7 Table 0155).


AckMode​

AckMode = "original" | "enhanced"

The two HL7 acknowledgment modes. original = both MSH-15 and MSH-16 are absent/null; enhanced = either is present (HL7 v2 Chapter 2 §2.9).


BatchEnvelopeName​

BatchEnvelopeName = "FHS" | "BHS" | "BTS" | "FTS"

The four HL7 batch-protocol envelope segment names (Ch. 2 §2.10.3).

Example​

import type { BatchEnvelopeName } from "@cosyte/hl7";
const trailer: BatchEnvelopeName = "BTS";

BatchMessageEntry​

BatchMessageEntry = { message: Hl7Message; ok: true; position: Hl7Position; raw: string; } | { error: Hl7ParseError; ok: false; position: Hl7Position; raw: string; }

One message extracted from a batch stream. Discriminated on ok: a successful parse carries the Hl7Message (whose own .warnings hold any per-message Tier-2 deviations); a message that hit one of the four Tier-3 fatal conditions carries the Hl7ParseError instead: isolated, so the rest of the batch still yields. raw is the message's verbatim source (re-parseable by parseHL7); position is the message's MSH (or, for pre-MSH stray content, its first) segment index in the stream.

Example​

import { splitBatch } from "@cosyte/hl7";
for (const entry of splitBatch(raw).messages) {
if (entry.ok) handle(entry.message);
else quarantine(entry.raw, entry.error.code);
}

CharsetTreatment​

CharsetTreatment = "decode" | "verbatim"

How the parser treats a resolved MSH-18 character set.

  • decode: decode the byte stream to text with CharsetResolution.decoder.
  • verbatim: read the raw bytes as a 1:1 latin1 mapping; do not decode (byte-recoverable for single-byte content: see the module header).

CompositeKind​

CompositeKind = "XPN" | "XAD" | "CX" | "CWE" | "CE" | "XTN" | "PL" | "TS" | "NM" | "HD" | "XCN"

The 11 typed composite kinds this module can encode. Mirrors the read-side composite set (XPN, XAD, CX, CWE, CE, XTN, PL, TS, NM, HD, XCN).


DtmPrecision​

DtmPrecision = "year" | "month" | "day" | "hour" | "minute" | "second" | "fraction"

Stated precision of a parsed HL7 DTM value: the number of populated characters (excluding the timezone offset) determines which level applies. A value's precision is preserved verbatim: |1970| is "year", never silently promoted to a full timestamp.

Example​

import { parseDtm } from "@cosyte/hl7";
console.log(parseDtm("1970").precision); // "year"
console.log(parseDtm("198807050000").precision); // "minute"

ErrSeverity​

ErrSeverity = typeof ERR_SEVERITIES[keyof typeof ERR_SEVERITIES]

Error-severity union (HL7 Table 0516, ERR-4).


FatalCode​

FatalCode = typeof FATAL_CODES[keyof typeof FATAL_CODES]

Discriminant type for Hl7ParseError.code. Narrowing a caught error by this code lets consumers write exhaustive switch blocks (enabled by the switch-exhaustiveness-check lint rule) and guarantees a typo-free comparison against the FATAL_CODES registry.

Example​

import type { FatalCode } from "@cosyte/hl7";
function describe(code: FatalCode): string {
switch (code) {
case "EMPTY_INPUT":
return "input was empty";
case "NO_MSH_SEGMENT":
return "missing MSH";
case "MSH_TOO_SHORT":
return "MSH truncated";
case "INVALID_ENCODING_CHARACTERS":
return "bad MSH-1/MSH-2";
}
}

FindingCode​

FindingCode = typeof FINDING_CODES[keyof typeof FINDING_CODES]

Discriminant union of every ConformanceFinding code. Enables exhaustive switch narrowing (the switch-exhaustiveness-check lint rule).


FindingSeverity​

FindingSeverity = "error" | "warning" | "info"

Severity of a ConformanceFinding. error is a constraint violation; warning / info are author-downgraded advisories (via a rule's severity). FINDING_CODES.PROFILE_MALFORMED is always error.


Hl7StreamSource​

Hl7StreamSource = AsyncIterable<string | Buffer | Uint8Array> | Iterable<string | Buffer | Uint8Array>

A chunked source parseStream can consume: a Node Readable, any async-iterable, or any plain iterable of chunks. Chunks are string (text stream) or Buffer/Uint8Array (binary stream). A real Node stream in binary mode yields Buffers; in text mode it yields strings: a source is expected to be homogeneous (all-text or all-binary), which every real Readable is. A binary chunk is decoded 1:1 via latin1 (a lossless byte↔codepoint mapping) so each message's own MSH-18 charset resolution runs on its original bytes, exactly as splitBatch does.

Example​

import { createReadStream } from "node:fs";
import { parseStream } from "@cosyte/hl7";

const src: Hl7StreamSource = createReadStream("feed.hl7");
for await (const entry of parseStream(src)) {
if (entry.ok) handle(entry.message);
else quarantine(entry.raw, entry.error.code);
}

IdentityEventKind​

IdentityEventKind = "merge" | "move" | "link" | "unlink" | "add" | "update"

Classification of a recognized identity trigger event.

  • merge: A18 / A34 / A35 / A36 / A39 / A40 / A41 / A42 (MRG expected)
  • move: A43 / A44 (MRG expected)
  • link / unlink: A24 / A37 (two PID groups, no MRG)
  • add / update: A28 / A31 (person add/update, no MRG)

Example​

import type { IdentityEventKind } from "@cosyte/hl7";
const kind: IdentityEventKind = "merge";

IdentityRole​

IdentityRole = "surviving" | "prior" | "linked" | "subject"

Role of one party in an identity event. surviving / subject / linked parties are ONLY ever sourced from PID (+ PV1); prior parties are ONLY ever sourced from MRG. That is the role-labelling invariant.

Example​

import type { IdentityRole } from "@cosyte/hl7";
const role: IdentityRole = "surviving";

ImmunizationRecordOrigin​

ImmunizationRecordOrigin = "administered" | "historical"

Whether an Immunization records a dose that was administered by the reporting system or is historical information sourced from elsewhere, derived conservatively from RXA-9.1 against HL7 Table NIP001 (Immunization Information Source, CDC v2.5.1 Immunization Messaging IG):

  • "administered": RXA-9.1 is exactly "00" (New immunization record).
  • "historical": RXA-9.1 is "01".."08" (any "Historical information …" source).

Fail-safe: this is OMITTED (never guessed) when RXA-9 is absent or carries a code outside the NIP001 administered/historical set. The raw RXA-9 claim is always preserved verbatim on Immunization.informationSource, so a consumer can inspect the original code even when recordOrigin is undefined. The distinction matters because an IIS de-duplicates a historical report differently from a dose it believes was administered: guessing corrupts the registry.


MedicationContext​

MedicationContext = "order" | "encoded" | "dispense" | "administration"

Which pharmacy/treatment segment a Medication was extracted from: the clinical "phase" of the medication. Each value maps 1:1 to one RX* parent segment (Ch. 4A):

  • "order": RXO (Pharmacy/Treatment Order): the originally requested give code/amount/dosage-form, before pharmacy encoding.
  • "encoded": RXE (Encoded Order): the pharmacy-encoded give code/amount, plus the give strength (RXE-25/26): the only context that carries a separate strength.
  • "dispense": RXD (Dispense): what was actually dispensed.
  • "administration": RXA (Administration): what was actually given to the patient.

The context is preserved verbatim and never collapsed: an RDE order that carries both an RXO request and an RXE encoded line surfaces as TWO Medication entries with distinct contexts: the helper never reconciles one against the other.


Observation​

Observation = ObservationBase & { value: number | undefined; valueType: "NM"; } | { value: SN | undefined; valueType: "SN"; } | { value: TS | undefined; valueType: "TS" | "DT"; } | { value: CWE | CE | undefined; valueType: "CWE" | "CE"; } | { value: string | undefined; valueType: string; }

One OBX segment as a typed Observation. value is discriminated by valueType (OBX-2) per D-13:

  • "NM" → number | undefined
  • "SN" → SN | undefined (structured numeric: comparator / range / ratio)
  • "TS" | "DT" → TS | undefined (fidelity parts preserved)
  • "CWE" | "CE" → CWE | CE | undefined (full composite per D-14)
  • other ("ST", "TX", "FT", "ID", "IS", "NA", unknown) → string | undefined (decoded, D-23)

D-22: value is undefined when OBX-5 is empty OR malformed for its declared type (never throws, never NaN). A TS/DT value is always the TS structure; check its .valid flag rather than expecting a Date.

Example​

import type { Observation } from "@cosyte/hl7";
const glucose: Observation = {
setId: "1",
identifier: { identifier: "GLU", text: "Glucose" },
valueType: "NM",
value: 120,
units: { identifier: "mg/dL" },
referenceRange: "80-110",
abnormalFlags: "H",
status: "F",
};

OnWarningCallback​

OnWarningCallback = (warning) => void

Callback invoked inline each time the parser emits a Tier-2 warning. Always fires BEFORE the warning is appended to Hl7Message.warnings so consumers observe warnings in the same order the parser discovered them.

Parameters​

warning​

Hl7ParseWarning

Returns​

void

Example​

import { parseHL7, type OnWarningCallback } from "@cosyte/hl7";
const onWarning: OnWarningCallback = (w) => {
console.warn(w.code, w.message);
};
parseHL7(raw, { onWarning });

OruPatient​

OruPatient = AdtPatient

Typed PID content for buildOru. Reuses AdtPatient: the patient-identification shape is identical across message families.


RepeatPatternKind​

RepeatPatternKind = "parametric" | "named" | "unknown"

How an order/medication RepeatPattern code (HL7 Table 0335) is classified, provenance only, never used to resolve a schedule. The code is always authoritative and surfaced verbatim; this flag only tells a consumer what kind of pattern it is looking at so it can decide whether a load-bearing integer is present.

  • "parametric": a Q<integer><unit> template (Q6H, Q30M, Q2D, Q1W, Q3J5) whose integer is load-bearing: Q6H (every 6 hours) is a different dose count from Q8H. The parsed integer + unit ride on RepeatPattern.interval.
  • "named": a recognized fixed Table-0335 mnemonic scheduled at institution-specified times (BID, TID, QID, QOD, QHS, QAM, QPM, QSHIFT, PRN, AC, PC, HS, C). No numeric interval.
  • "unknown": anything else (a local code, free text, an unrecognized mnemonic). Surfaced verbatim, never mapped to a frequency.

StreamMessageEntry​

StreamMessageEntry = { message: Hl7Message; ok: true; position: Hl7Position; raw: string; streamWarnings: readonly Hl7ParseWarning[]; } | { error: Hl7ParseError; ok: false; position: Hl7Position; raw: string; streamWarnings: readonly Hl7ParseWarning[]; }

One message yielded by parseStream. Discriminated on ok, mirroring splitBatch's per-message entry: a successful parse carries the Hl7Message (whose own .warnings hold per-message Tier-2 deviations); a message that hit one of the four Tier-3 fatals carries the Hl7ParseError instead: isolated, so the rest of the stream still yields.

raw is the message's verbatim source (re-parseable by parseHL7); position.segmentIndex is the message's MSH (or, for stray pre-MSH content, its first) segment index in the overall stream: the streaming analogue of splitBatch's message position. streamWarnings holds stream-level diagnostics that are not per-message parse warnings: today only unterminatedStreamMessage on a final message that lacked a terminator. It is kept separate from message.warnings (which stays exactly what a whole-buffer parseHL7 of the same bytes would produce) and is empty for every message but a possibly-truncated final one. Both the entry and streamWarnings are frozen.

Example​

import { parseStream, WARNING_CODES } from "@cosyte/hl7";
for await (const entry of parseStream(source)) {
for (const w of entry.streamWarnings) {
if (w.code === WARNING_CODES.UNTERMINATED_STREAM_MESSAGE) {
// the feed may have been cut off mid-message
}
}
}

TS​

TS = DtmParts

HL7 v2 Time Stamp (TS) / Date Time (DTM) composite: the raw HL7 string plus its parsed parts, preserving the stated precision and timezone fidelity. This is a DtmParts: valid is false (with no parts) for unparseable input: NEVER throws (TYPES-04 no-throw guarantee).

There is deliberately no date field: a day-only value coerced to a JS Date at UTC midnight silently shifts the calendar day in negative-offset zones. To obtain an absolute instant, call dtmToDate(ts) explicitly (and supply assumeOffsetMinutes for an offset-less value).

Example​

import type { TS } from "@cosyte/hl7";
import { dtmToDate } from "@cosyte/hl7";
const dob: TS = { raw: "19880705", valid: true, precision: "day",
year: 1988, month: 7, day: 5, hasTimezone: false };
console.log(dob.precision); // "day": not a full timestamp
console.log(dtmToDate(dob)); // undefined: refuses to guess the zone

UsageCode​

UsageCode = "R" | "RE" | "C" | "CE" | "O" | "X"

The six HL7 v2 conformance usage codes (HL7 Conformance Methodology, Message Profiles; IHE ITI TF Vol.2 Appendix C). They constrain whether an element must, may, or must not appear:

  • R: Required. The element SHALL be present (with a value). Absent → FINDING_CODES.PROFILE_REQUIRED_ABSENT.
  • RE: Required but may be Empty. The element is supported and SHALL be sent when the sender has the data; its absence is never a violation (this engine cannot know whether the sender had the data).
  • C: Conditional. Presence depends on a predicate. This bounded engine ships no predicate language (a documented defer: roadmap §5), so a C element's presence is not evaluated (treated as optional); its length / value-set / cardinality rules still apply when it IS present.
  • CE: Conditional but may be Empty. Same non-evaluation as C.
  • O: Optional. No presence constraint.
  • X: Not supported / not permitted. The element SHALL NOT be present. Present → FINDING_CODES.PROFILE_NOT_PERMITTED.

Example​

import type { UsageCode } from "@cosyte/hl7";
const usage: UsageCode = "R";

WarningCode​

WarningCode = typeof WARNING_CODES[keyof typeof WARNING_CODES]

Discriminant type for Hl7ParseWarning.code. Narrowing a warning by this code lets consumers write exhaustive switch blocks (enabled by the switch-exhaustiveness-check lint rule) and guarantees a typo-free comparison against the WARNING_CODES registry.

Example​

import type { Hl7ParseWarning, WarningCode } from "@cosyte/hl7";
function describe(w: Hl7ParseWarning): string {
const code: WarningCode = w.code;
switch (code) {
case "MLLP_FRAMING_STRIPPED":
return "stripped MLLP framing";
default:
return `warning: ${code}`;
}
}

Variables​

ACK_CODES​

const ACK_CODES: object

HL7 Table 0008: Acknowledgment code (MSA-1). The two acknowledgment vocabularies:

  • original mode: AA Application Accept · AE Application Error · AR Application Reject.
  • enhanced mode accept-level: CA Commit Accept · CE Commit Error · CR Commit Reject (the application-level response in enhanced mode reuses AA/AE/AR).

Type Declaration​

AA​

readonly AA: "AA" = "AA"

AE​

readonly AE: "AE" = "AE"

AR​

readonly AR: "AR" = "AR"

CA​

readonly CA: "CA" = "CA"

CE​

readonly CE: "CE" = "CE"

CR​

readonly CR: "CR" = "CR"

Example​

import { ACK_CODES } from "@cosyte/hl7";
ACK_CODES.AA; // "AA"

ACK_CONDITIONS​

const ACK_CONDITIONS: object

HL7 Table 0155: Accept/application acknowledgment conditions (MSH-15 / MSH-16): AL Always · NE Never · ER Error/reject conditions only · SU Successful completion only. Exposed read-only for adapters that surface the inbound sender's stated acknowledgment expectations.

Type Declaration​

AL​

readonly AL: "AL" = "AL"

ER​

readonly ER: "ER" = "ER"

NE​

readonly NE: "NE" = "NE"

SU​

readonly SU: "SU" = "SU"

Example​

import { ACK_CONDITIONS } from "@cosyte/hl7";
ACK_CONDITIONS.AL; // "AL" (Always)

BUILTIN_DATE_FALLBACKS​

const BUILTIN_DATE_FALLBACKS: readonly string[]

Ordered list of built-in timestamp formats parseDtmCascade falls back to when neither the strict HL7 DTM match nor any user-supplied format succeeds. ISO-8601 is tried first (most constrained); MM/DD/YYYY HH:mm:ss last (it overlaps the date-only form).

Example​

import { BUILTIN_DATE_FALLBACKS } from "@cosyte/hl7";
console.log(BUILTIN_DATE_FALLBACKS);
// ["ISO-8601", "YYYY-MM-DD", "MM/DD/YYYY", "MM/DD/YYYY HH:mm:ss"]

DEFAULT_ENCODING_CHARACTERS​

const DEFAULT_ENCODING_CHARACTERS: EncodingCharacters

The HL7 default 5-tuple of encoding characters used when a message does not override them via MSH-1 / MSH-2. Re-used by downstream stages (the escape map, parseHL7) as a synthetic-message fallback.

Example​

import { DEFAULT_ENCODING_CHARACTERS } from "@cosyte/hl7";
DEFAULT_ENCODING_CHARACTERS.field; // "|"

ERR_CONDITION_CODE_SYSTEM​

const ERR_CONDITION_CODE_SYSTEM: "HL70357" = "HL70357"

Code-system name emitted in ERR-3.3 for Table 0357 condition codes.


ERR_CONDITION_CODES​

const ERR_CONDITION_CODES: Readonly<Record<string, string>>

HL7 Table 0357: Message error condition codes (ERR-3.1 → ERR-3.2 text). Frozen read-only map of code → standard display text. The code system name emitted in ERR-3.3 is ERR_CONDITION_CODE_SYSTEM.

Codes 104 (value too long) and 105 (table value not found) are v2.7+ additions; the rest are present from v2.5. buildAck emits whatever code it is told (it never invents a condition) and looks up the display text here.

Example​

import { ERR_CONDITION_CODES } from "@cosyte/hl7";
ERR_CONDITION_CODES["101"]; // "Required field missing"

ERR_SEVERITIES​

const ERR_SEVERITIES: object

HL7 Table 0516: Error severity (ERR-4). A v2.5+ construct (ERR was structured differently in v2.3.1).

Type Declaration​

E​

readonly E: "E" = "E"

Error.

I​

readonly I: "I" = "I"

Information.

W​

readonly W: "W" = "W"

Warning.

Example​

import { ERR_SEVERITIES } from "@cosyte/hl7";
ERR_SEVERITIES.E; // "E" (Error)

FATAL_CODES​

const FATAL_CODES: object

Stable string codes for every Tier-3 fatal the parser may throw. Locked at four codes: anything else MUST be a Tier-2 warning. Consumers narrow on err.code to react to specific structural failures.

Type Declaration​

EMPTY_INPUT​

readonly EMPTY_INPUT: "EMPTY_INPUT" = "EMPTY_INPUT"

INVALID_ENCODING_CHARACTERS​

readonly INVALID_ENCODING_CHARACTERS: "INVALID_ENCODING_CHARACTERS" = "INVALID_ENCODING_CHARACTERS"

MSH_TOO_SHORT​

readonly MSH_TOO_SHORT: "MSH_TOO_SHORT" = "MSH_TOO_SHORT"

NO_MSH_SEGMENT​

readonly NO_MSH_SEGMENT: "NO_MSH_SEGMENT" = "NO_MSH_SEGMENT"

Example​

import { parseHL7, FATAL_CODES, Hl7ParseError } from "@cosyte/hl7";
try {
parseHL7("");
} catch (err) {
if (err instanceof Hl7ParseError && err.code === FATAL_CODES.EMPTY_INPUT) {
// handle empty input
}
}

FINDING_CODES​

const FINDING_CODES: object

The frozen registry of finding codes. Stable, additive string codes: a consumer compares finding.code === FINDING_CODES.PROFILE_REQUIRED_ABSENT. Segment-level vs field-level is disambiguated by whether the finding's FindingLocus.field is present, not by separate codes.

Type Declaration​

PROFILE_CARDINALITY​

readonly PROFILE_CARDINALITY: "PROFILE_CARDINALITY" = "PROFILE_CARDINALITY"

A segment-occurrence or field-repetition count is outside its cardinality.

PROFILE_LENGTH​

readonly PROFILE_LENGTH: "PROFILE_LENGTH" = "PROFILE_LENGTH"

A checked component value exceeds the declared maximum length.

PROFILE_MALFORMED​

readonly PROFILE_MALFORMED: "PROFILE_MALFORMED" = "PROFILE_MALFORMED"

The profile ITSELF is structurally malformed (a diagnostic, not a message finding).

PROFILE_NOT_PERMITTED​

readonly PROFILE_NOT_PERMITTED: "PROFILE_NOT_PERMITTED" = "PROFILE_NOT_PERMITTED"

A Not-permitted (X) segment or field is present.

PROFILE_REQUIRED_ABSENT​

readonly PROFILE_REQUIRED_ABSENT: "PROFILE_REQUIRED_ABSENT" = "PROFILE_REQUIRED_ABSENT"

A Required (R) segment or field is absent (or present-but-empty).

PROFILE_VALUE_NOT_IN_SET​

readonly PROFILE_VALUE_NOT_IN_SET: "PROFILE_VALUE_NOT_IN_SET" = "PROFILE_VALUE_NOT_IN_SET"

A checked component value is not a member of the consumer-supplied value set.

Example​

import { validateAgainstProfile, FINDING_CODES } from "@cosyte/hl7";
const { findings } = validateAgainstProfile(msg, profile);
const missing = findings.filter((f) => f.code === FINDING_CODES.PROFILE_REQUIRED_ABSENT);

KNOWN_CODING_SYSTEMS​

const KNOWN_CODING_SYSTEMS: readonly KnownCodingSystem[]

The safety-relevant subset of HL7 Table 0396 this library recognizes for provenance. Deliberately small and frozen: it is NOT the full Table 0396 registry. Each entry's source is recorded in docs-content/spec-notes-coding-system.md.

Note on I10: Table 0396 registers I10 as ICD-10 (the WHO base classification). US v2 feeds frequently send I10 when they mean ICD-10-CM, but that clinical-modification specificity is the sender's convention, not what the acronym registers: so this map reports the registered claim ("ICD-10") and does not silently upgrade it to CM.

Example​

import { KNOWN_CODING_SYSTEMS } from "@cosyte/hl7";
console.log(KNOWN_CODING_SYSTEMS.find((s) => s.id === "LN")?.name); // "LOINC"

KNOWN_SEGMENTS​

const KNOWN_SEGMENTS: ReadonlySet<string>

Frozen set of every standard HL7 v2 segment name the library recognises. Consumers parsing any segment whose name is neither in this set nor declared by the active profile will see UNKNOWN_SEGMENT in msg.warnings.

Example​

import { KNOWN_SEGMENTS } from "@cosyte/hl7";
console.log(KNOWN_SEGMENTS.has("PID")); // true
console.log(KNOWN_SEGMENTS.has("ZPI")); // false

MESSAGE_STRUCTURE_DEFINITIONS​

const MESSAGE_STRUCTURE_DEFINITIONS: readonly MessageStructureDefinition[]

The conservative, Required-only expected-group registry. Each entry's spec source is recorded in docs-content/spec-notes-structure.md. Deliberately narrow: it recognizes the common message types' core Required groups only and is NOT a conformance validator. Frozen (data, not config).

Example​

import { MESSAGE_STRUCTURE_DEFINITIONS } from "@cosyte/hl7";
const oru = MESSAGE_STRUCTURE_DEFINITIONS.find((d) => d.messageCode === "ORU");
console.log(oru?.expectedGroups[0]?.name); // "result"

profiles​

const profiles: object

Namespace object exposing the 8 shipped built-in vendor profiles (epic, cerner, meditech, athena, genericLab, visage, philips, va). Each is authored via the public defineProfile() API (BIP-01..09).

Type Declaration​

athena​

readonly athena: Profile

cerner​

readonly cerner: Profile

epic​

readonly epic: Profile

genericLab​

readonly genericLab: Profile

meditech​

readonly meditech: Profile

philips​

readonly philips: Profile

va​

readonly va: Profile

visage​

readonly visage: Profile

Example​

import { parseHL7, profiles } from "@cosyte/hl7";
const msg = parseHL7(raw, profiles.epic);
console.log(msg.profile?.name); // "epic"

SUPPORTED_DATE_TOKENS​

const SUPPORTED_DATE_TOKENS: readonly string[]

Every date-format token the library's format-string matcher and defineProfile() D-08 validator recognize. Re-exported so profile authors can introspect the valid token set. SSSS (fractional seconds) is recognised by the D-08 validator only.

Example​

import { SUPPORTED_DATE_TOKENS } from "@cosyte/hl7";
console.log(SUPPORTED_DATE_TOKENS);
// ["YYYY", "MM", "DD", "HH", "mm", "ss", "SSSS"]

USAGE_CODES​

const USAGE_CODES: readonly UsageCode[]

The frozen set of valid UsageCodes, for runtime validation and introspection. USAGE_CODES.R === "R".

Example​

import { USAGE_CODES } from "@cosyte/hl7";
USAGE_CODES.includes("R" as const); // true

VERSION​

const VERSION: string = "0.0.10"

Library version string, synced with package.json#version at build time by downstream phases. Exported now so consumers (and the type-check pipeline) have at least one symbol to resolve through the exports map.

Example​

import { VERSION } from "@cosyte/hl7";
console.log(VERSION);

WARNING_CODES​

const WARNING_CODES: object

Stable string codes for every Tier-2 warning the parser may emit. The registry is frozen via as const so TypeScript infers the exact string literal union for WarningCode: there is zero runtime cost and no magic-string comparisons for consumers.

Type Declaration​

ACK_NO_CORRELATION_ID​

readonly ACK_NO_CORRELATION_ID: "ACK_NO_CORRELATION_ID" = "ACK_NO_CORRELATION_ID"

BATCH_COUNT_MISMATCH​

readonly BATCH_COUNT_MISMATCH: "BATCH_COUNT_MISMATCH" = "BATCH_COUNT_MISMATCH"

BATCH_MISSING_TRAILER​

readonly BATCH_MISSING_TRAILER: "BATCH_MISSING_TRAILER" = "BATCH_MISSING_TRAILER"

DUPLICATE_REQUIRED_SEGMENT​

readonly DUPLICATE_REQUIRED_SEGMENT: "DUPLICATE_REQUIRED_SEGMENT" = "DUPLICATE_REQUIRED_SEGMENT"

ENCODING_MISMATCH​

readonly ENCODING_MISMATCH: "ENCODING_MISMATCH" = "ENCODING_MISMATCH"

EXTRA_FIELDS​

readonly EXTRA_FIELDS: "EXTRA_FIELDS" = "EXTRA_FIELDS"

FIELD_WHITESPACE_TRIMMED​

readonly FIELD_WHITESPACE_TRIMMED: "FIELD_WHITESPACE_TRIMMED" = "FIELD_WHITESPACE_TRIMMED"

MERGE_MISSING_PRIOR_OR_SURVIVOR​

readonly MERGE_MISSING_PRIOR_OR_SURVIVOR: "MERGE_MISSING_PRIOR_OR_SURVIVOR" = "MERGE_MISSING_PRIOR_OR_SURVIVOR"

MISSING_EXPECTED_GROUP​

readonly MISSING_EXPECTED_GROUP: "MISSING_EXPECTED_GROUP" = "MISSING_EXPECTED_GROUP"

MISSING_REQUIRED_FIELD​

readonly MISSING_REQUIRED_FIELD: "MISSING_REQUIRED_FIELD" = "MISSING_REQUIRED_FIELD"

MLLP_FRAMING_STRIPPED​

readonly MLLP_FRAMING_STRIPPED: "MLLP_FRAMING_STRIPPED" = "MLLP_FRAMING_STRIPPED"

OUT_OF_ORDER_SEGMENT​

readonly OUT_OF_ORDER_SEGMENT: "OUT_OF_ORDER_SEGMENT" = "OUT_OF_ORDER_SEGMENT"

SEGMENT_CASE​

readonly SEGMENT_CASE: "SEGMENT_CASE" = "SEGMENT_CASE"

TIMESTAMP_FALLBACK_FORMAT​

readonly TIMESTAMP_FALLBACK_FORMAT: "TIMESTAMP_FALLBACK_FORMAT" = "TIMESTAMP_FALLBACK_FORMAT"

UNKNOWN_CHARSET​

readonly UNKNOWN_CHARSET: "UNKNOWN_CHARSET" = "UNKNOWN_CHARSET"

UNKNOWN_ESCAPE_SEQUENCE​

readonly UNKNOWN_ESCAPE_SEQUENCE: "UNKNOWN_ESCAPE_SEQUENCE" = "UNKNOWN_ESCAPE_SEQUENCE"

UNKNOWN_SEGMENT​

readonly UNKNOWN_SEGMENT: "UNKNOWN_SEGMENT" = "UNKNOWN_SEGMENT"

UNSUPPORTED_CHARSET​

readonly UNSUPPORTED_CHARSET: "UNSUPPORTED_CHARSET" = "UNSUPPORTED_CHARSET"

UNTERMINATED_STREAM_MESSAGE​

readonly UNTERMINATED_STREAM_MESSAGE: "UNTERMINATED_STREAM_MESSAGE" = "UNTERMINATED_STREAM_MESSAGE"

VERSION_MISMATCH​

readonly VERSION_MISMATCH: "VERSION_MISMATCH" = "VERSION_MISMATCH"

Example​

import { parseHL7, WARNING_CODES } from "@cosyte/hl7";
const msg = parseHL7(raw);
if (msg.warnings.some((w) => w.code === WARNING_CODES.MLLP_FRAMING_STRIPPED)) {
// handle MLLP-wrapped input
}

Functions​

ackNoCorrelationId()​

ackNoCorrelationId(position): Hl7ParseWarning

Build an ACK_NO_CORRELATION_ID warning. Emitted by buildAck, not by the parser: the inbound message carried no MSH-10 message control ID, so the generated ACK leaves MSA-2 empty and, when a positive accept was requested, downgrades it to an error code rather than fabricating an unverifiable AA/CA. The position references the inbound MSH segment. The message NEVER echoes a PHI value: only the structural fact.

Parameters​

position​

Hl7Position

Returns​

Hl7ParseWarning

Example​

import { buildAck, WARNING_CODES } from "@cosyte/hl7";
const ack = buildAck(inbound, { code: "AA" }); // inbound has no MSH-10
ack.warnings.some((w) => w.code === WARNING_CODES.ACK_NO_CORRELATION_ID); // true

alternateCodingSystemOf()​

alternateCodingSystemOf(coded): CodingSystemInfo | undefined

Provenance of a coded element's alternate coding system (CWE.6 / CE.6). Returns undefined when the element claims no alternate system. Useful for dual-coded fields (e.g. a problem carrying both SNOMED CT and ICD-10), where assuming a single coding system would be unsafe.

Parameters​

coded​

CodedSystemFields

Returns​

CodingSystemInfo | undefined

Example​

import { alternateCodingSystemOf } from "@cosyte/hl7";
const alt = alternateCodingSystemOf(dg.code);
if (alt) console.log("also coded in", alt.name ?? alt.claimed);

analyzeMessageStructure()​

analyzeMessageStructure(messageCode, triggerEvent, presentSegmentNames): MessageStructure

Analyze a parsed message's structure against the conservative expected-group registry. Pure: it takes the message code, trigger event, and the set of segment names actually present, and returns a MessageStructure summary. It decides nothing about whether to warn: the caller (parser) emits one MISSING_EXPECTED_GROUP warning per name in missingGroups.

Parameters​

messageCode​

string

MSH-9.1 (e.g. "ORU"); empty string if absent.

triggerEvent​

string

MSH-9.2 (e.g. "R01"); empty string if absent.

presentSegmentNames​

ReadonlySet<string>

the set of segment names present in the message.

Returns​

MessageStructure

Example​

import { analyzeMessageStructure } from "@cosyte/hl7";
const s = analyzeMessageStructure("ORU", "R01", new Set(["MSH", "PID"]));
console.log(s.recognized); // true
console.log(s.missingGroups); // ["result"] (no OBR/OBX)

batchCountMismatch()​

batchCountMismatch(position, unit, declared, actual): Hl7ParseWarning

Build a BATCH_COUNT_MISMATCH warning. Emitted by splitBatch(): attached to the returned BatchSplitResult.warnings, never to Hl7Message.warnings: when a declared envelope count does not equal the count actually split out: a BTS-1 batch message count that differs from the messages found in that batch, or an FTS-1 file batch count that differs from the batches found in the file (HL7 v2 Ch. 2 §2.10.3; BTS-1 / FTS-1 per the BTS / FTS segment definitions in §2.15). The splitter never drops the tail to make the numbers agree: the mismatch is surfaced and every message is still returned; the caller decides whether to reject.

The message carries only the declared-vs-actual integers and the unit (message for BTS-1, batch for FTS-1): NEVER a field value, facility identifier, or any other content, so no PHI is exposed. position references the trailer segment (BTS/FTS) that declared the count.

Parameters​

position​

Hl7Position

unit​

"message" | "batch"

declared​

number

actual​

number

Returns​

Hl7ParseWarning

Example​

import { batchCountMismatch } from "@cosyte/hl7";
const w = batchCountMismatch({ segmentIndex: 4 }, "message", 3, 2);

batchMissingTrailer()​

batchMissingTrailer(position, header, expectedTrailer): Hl7ParseWarning

Build a BATCH_MISSING_TRAILER warning. Emitted by splitBatch() (attached to BatchSplitResult.warnings) when an envelope header opens a scope that is never closed: a BHS batch header with no matching BTS trailer, or an FHS file header with no matching FTS trailer (HL7 v2 Ch. 2 §2.10.3: each envelope segment is optional, but a profile such as an IIS file-submission spec may mandate the full frame). splitBatch does not enforce such a rule: it splits, warns, and leaves the accept/reject decision to the caller; the parse never throws for this.

The message carries only the header/trailer segment names: NEVER a field value, so no PHI is exposed. position references the unmatched header segment (FHS/BHS).

Parameters​

position​

Hl7Position

header​

"FHS" | "BHS"

expectedTrailer​

"BTS" | "FTS"

Returns​

Hl7ParseWarning

Example​

import { batchMissingTrailer } from "@cosyte/hl7";
const w = batchMissingTrailer({ segmentIndex: 0 }, "BHS", "BTS");

buildAck()​

buildAck(inbound, options): Hl7Message

Build a spec-clean ACK (MSH + MSA [+ ERR…]) responding to inbound.

Behavior:

  • MSH: sender/receiver are swapped (inbound MSH-5/6 → ACK MSH-3/4; inbound MSH-3/4 → ACK MSH-5/6); MSH-7 is the current UTC time; MSH-9 is ACK (with the inbound trigger event echoed as ACK^<trigger>^ACK when present); MSH-10 is a freshly generated control id; MSH-11 (processing id) and MSH-12 (version) echo the inbound values.
  • MSA: MSA-1 = code; MSA-2 echoes the full inbound MSH-10 field (the raw field structure is carried over whole: a vendor-quirk id like ID^X is never truncated to its first component). The echo carries the inbound field's escape-fidelity overlay, so an id bearing a hex escape (ID\X41\Q) or a preserved escape (\H\) echoes byte-verbatim, not canonicalized: exactly the bytes the sender put on the wire, which is what MSA-2 correlation compares. The only structural transform is trailing-empty canonicalization (D-02). (A sender that used custom encoding characters is re-delimited spec-cleanly: the overlay carries the sender's raw bytes in the sender's alphabet, so echoing them verbatim under the ACK's default alphabet would corrupt the field's structure and break correlation: the overlay is therefore bypassed and the decoded id is re-escaped under default, which re-parses back to the same control id. Default-delimiter senders, the norm, keep the byte-exact overlay echo.)
  • ERR: one segment per supplied AckErrorDetail: ERR-2 location (when given), ERR-3 the Table 0357 condition code as a CWE (code^text^HL70357), ERR-4 the Table 0516 severity.

Fail-safe. If the inbound message has no MSH-10, the ACK cannot be correlated. buildAck then leaves MSA-2 empty and, if a positive accept (AA/CA) was requested, downgrades it to the matching error code (AE/CE): it never fabricates an unverifiable positive ACK. The returned message carries an ACK_NO_CORRELATION_ID warning. (This is the inbound-side complement to @cosyte/mllp's "no commit ⇒ never AA".)

Pure aside from the generated control id + timestamp; never throws except on a programming error (inbound not an Hl7Message, or an unknown code).

Parameters​

inbound​

Hl7Message

options​

BuildAckOptions

Returns​

Hl7Message

Example​

import { buildAck, parseHL7 } from "@cosyte/hl7";
const inbound = parseHL7(raw);
const ack = buildAck(inbound, { code: "AA" });
console.log(ack.toString()); // MSH|...\rMSA|AA|<inbound MSH-10>
parseHL7(ack.toString()).meta.type; // "ACK" (round-trips clean)

buildAdt()​

buildAdt(event, init): Hl7Message

Build a spec-clean ADT message for event (the MSH-9.2 trigger, e.g. "A01", "A04", "A08") from typed inputs.

The result is a real Hl7Message: msg.toString() serialises it, parseHL7(msg.toString()) round-trips with zero warnings, and msg.patient / msg.visit read back the values supplied.

Parameters​

event​

string

the ADT trigger event (MSH-9.2). Required, non-empty.

init​

BuildAdtInit

the MSH envelope + typed PID/PV1/EVN content (patient required).

Returns​

Hl7Message

Throws​

TypeError when event is empty or init.patient is absent.

Example​

import { buildAdt, parseHL7 } from "@cosyte/hl7";
const msg = buildAdt("A01", {
sendingApp: "CLINIC",
receivingApp: "LAB",
patient: {
identifiers: { idNumber: "MRN001", identifierTypeCode: "MR" },
name: { familyName: "Test", givenName: "Ann" },
birthDateTime: "19880705",
administrativeSex: "F",
},
visit: { patientClass: "I", assignedLocation: { pointOfCare: "ICU", room: "1", bed: "A" } },
});
const round = parseHL7(msg.toString());
round.warnings.length; // 0
round.patient?.familyName; // "Test"
round.structure.missingGroups; // []

buildMessage()​

buildMessage(init): Hl7Message

Construct an outbound Hl7Message from semantic MSH fields (SER-06). Synthesises a complete MSH RawSegment per D-10/D-11 and hands to new Hl7Message({...}). Callers chain .addSegment(name, fields) (mutation method) to append PID, OBX, etc.

Defaults applied when fields are omitted (D-10):

  • controlId → generateControlId() (D-12)
  • timestamp → formatHl7Timestamp(new Date()) (D-13)
  • version → "2.5"
  • processingId → "P"
  • sendingApp/sendingFacility/receivingApp/receivingFacility → empty

Encoding characters are always DEFAULT_ENCODING_CHARACTERS (D-14); no option to customise in v1.

Empty string vs. omitted field (W1): at the HL7 wire level, passing sendingApp: "" and omitting sendingApp produce IDENTICAL output (both emit as absent: || at the MSH-3 position). If you need to emit an HL7 explicit null ("", the two-char literal) at a specific position, build the message first, then use setField:

const msg = buildMessage({ type: "ADT^A01" });
msg.setField("MSH.3", '""'); // sets RawField.isNull = true
// msg.toString() now emits MSH-3 as `""` (2 chars), not as absent.

BuildMessageInit carries the same note on the input shape.

Parameters​

init​

BuildMessageInit

Returns​

Hl7Message

Example​

import { buildMessage, parseHL7 } from "@cosyte/hl7";
const msg = buildMessage({
type: "ADT^A01",
sendingApp: "CLINIC",
sendingFacility: "MAIN",
receivingApp: "LAB",
receivingFacility: "REF",
}).addSegment("PID", ["", "", "MRN123", "", "Doe^John"]);

// Spec-clean HL7 string round-trips through parseHL7:
const round = parseHL7(msg.toString());
console.log(round.meta.type); // "ADT^A01"

buildOru()​

buildOru(init): Hl7Message

Build a spec-clean ORU^R01 observation-result message from typed inputs.

The result is a real Hl7Message: msg.toString() serialises it, parseHL7(msg.toString()) round-trips with zero warnings, and msg.observations() reads back the results supplied.

Parameters​

init​

BuildOruInit

the MSH envelope + typed PID/OBR/OBX content. patient and a non-empty observations list are required.

Returns​

Hl7Message

Throws​

TypeError when patient is absent or observations is empty.

Example​

import { buildOru, parseHL7 } from "@cosyte/hl7";
const msg = buildOru({
sendingApp: "LAB",
receivingApp: "EHR",
patient: { identifiers: { idNumber: "MRN001", identifierTypeCode: "MR" },
name: { familyName: "Test", givenName: "Ann" } },
order: { universalServiceId: { identifier: "CBC", text: "Complete Blood Count", nameOfCodingSystem: "L" },
resultStatus: "F" },
observations: [
{ setId: "1", valueType: "NM",
identifier: { identifier: "WBC", text: "White Blood Cells", nameOfCodingSystem: "LN" },
value: "7.2", units: { identifier: "10*3/uL" }, observationResultStatus: "F" },
],
});
const round = parseHL7(msg.toString());
round.warnings.length; // 0
round.observations()[0]?.value; // "7.2"

canonicalCharset()​

canonicalCharset(raw): string

The canonical Table-0211 code for a label, for equality comparison (e.g. the MSH-18-vs-options.charset ENCODING_MISMATCH check). Synonyms collapse to one canonical string ("UNICODE UTF-8" and "UTF-8" → "UTF-8"), so a synonym pair does not raise a false mismatch; an unrecognized label returns its normalized form so two genuinely different labels still differ.

Parameters​

raw​

string

Returns​

string

Example​

import { canonicalCharset } from "@cosyte/hl7";
canonicalCharset("unicode utf-8") === canonicalCharset("UTF-8"); // true

codingSystem()​

codingSystem(id): CodingSystemInfo | undefined

Resolve a raw coding-system id (a CWE.3 / CE.3 "Name of Coding System" value) to its provenance. Returns undefined when there is no claim to resolve: id is undefined, empty, or whitespace-only.

Matching is case-insensitive and tolerant of surrounding whitespace, and normalizes the well-known aliases in KNOWN_CODING_SYSTEMS (e.g. "LOINC" → LN, "SNOMED" → SCT, "RxNorm" → RXN). An unrecognized id is returned verbatim with known: false: never guessed.

Parameters​

id​

string | undefined

Returns​

CodingSystemInfo | undefined

Example​

import { codingSystem } from "@cosyte/hl7";
codingSystem("LN"); // { claimed: "LN", known: true, id: "LN", name: "LOINC" }
codingSystem("loinc"); // { claimed: "loinc", known: true, id: "LN", name: "LOINC" }
codingSystem("99zL"); // { claimed: "99zL", known: false }
codingSystem(undefined); // undefined

codingSystemOf()​

codingSystemOf(coded): CodingSystemInfo | undefined

Provenance of a coded element's primary coding system (CWE.3 / CE.3). Returns undefined when the element claims no primary system.

Parameters​

coded​

CodedSystemFields

Returns​

CodingSystemInfo | undefined

Example​

import { parseHL7, codingSystemOf } from "@cosyte/hl7";
const msg = parseHL7(raw);
for (const dg of msg.diagnoses()) {
const sys = dg.code && codingSystemOf(dg.code);
console.log(dg.code?.identifier, sys?.name ?? sys?.claimed ?? "(no system)");
}

decodeText()​

decodeText(input, enc?): string

Decode a field's escape-bearing HL7 text to its human value: the five delimiter escapes (\F\ \S\ \T\ \R\ \E\), the truncation escape (\P), \.br\ (→ newline), and hex (\Xdddd…) are resolved; presentational escapes (\H\/\N, formatting, charset, vendor \Z..) are preserved verbatim so nothing is lost. Never throws.

This is the one-call inverse of encodeText for delimiter-bearing content. It does not interpret formatting/highlight: for a normalized display string use renderText.

Parameters​

input​

string

the field's escape-bearing text.

enc?​

EncodingCharacters = DEFAULT_ENCODING_CHARACTERS

encoding characters; defaults to the HL7 standard |^~\&.

Returns​

string

the decoded value string.

Example​

import { decodeText } from "@cosyte/hl7";
decodeText("Doe\\S\\John"); // "Doe^John": \S\ → component separator
decodeText("line1\\.br\\line2"); // "line1\nline2"

defineConformanceProfile()​

defineConformanceProfile(profile): ConformanceProfile

The fail-fast authoring gate for a conformance profile: a malformed profile raises a typed ProfileDefinitionError at build time, before any validation runs. Runs collectProfileDefects; on any defect, throws a single ProfileDefinitionError listing every defect. On success, returns the profile typed as ConformanceProfile.

This is optional: validateAgainstProfile tolerates a raw profile object and never throws: but it lets an author catch a typo when the profile is written rather than when it is run.

Parameters​

profile​

unknown

Returns​

ConformanceProfile

Throws​

when the profile is structurally malformed.

Example​

import { defineConformanceProfile } from "@cosyte/hl7";
const profile = defineConformanceProfile({
name: "example-adt-min",
segments: [{ segment: "PID", usage: "R" }],
});
// A typo throws at authoring time:
// defineConformanceProfile({ name: "x", segments: [{ segment: "pid" }] });
// → ProfileDefinitionError: segments[0].segment must be a valid segment name…

defineProfile()​

defineProfile(opts): Profile

Build a readonly Profile from a validated options object. Invalid input throws ProfileDefinitionError with an actionable message (PROF-02): bad Z-segment names (D-05), malformed date formats (D-08), unknown top-level keys with typo hints (D-07), and missing/empty name.

opts.extends accepts a single parent Profile or an array of them. Parents are merged into the result: lineage is the parents' lineages followed by this profile's own name, dateFormats and customSegments are merged, description inherits when not supplied, and onWarning handlers are composed. With no parent, lineage === [opts.name].

Parameters​

opts​

DefineProfileOptions

Returns​

Profile

Example​

import { defineProfile } from "@cosyte/hl7";
const epic = defineProfile({
name: "epic",
description: "Epic-specific quirks and ADT date formats",
dateFormats: ["MM/DD/YYYY HH:mm:ss", "MM/DD/YYYY"],
customSegments: {
ZDP: { fields: { departmentCode: 3, departmentName: 4 } },
ZRS: { fields: { resultStatus: 1, statusDateTime: 2 } },
},
});
console.log(epic.name); // "epic"
console.log(epic.lineage); // ["epic"]
console.log(epic.describe?.());

detectAckMode()​

detectAckMode(inbound): AckMode

Detect the HL7 acknowledgment mode of an inbound message from MSH-15 (accept acknowledgment type) and MSH-16 (application acknowledgment type), per HL7 v2 Chapter 2 §2.9: original when both are absent/empty; enhanced when either is present. This split is spec-exact (unlike the disposition mapping, which has no single correct model: see the package README).

Parameters​

inbound​

Hl7Message

Returns​

AckMode

Example​

import { detectAckMode, parseHL7 } from "@cosyte/hl7";
detectAckMode(parseHL7(raw)); // "original" | "enhanced"

downgradePositiveAck()​

downgradePositiveAck(code): AckCode

Downgrade a positive acknowledgment code to its matching error code, AA → AE (original mode), CA → CE (enhanced mode). Every other code passes through unchanged.

This is the single upstream source of truth for the fail-safe downgrade pair: buildAck applies it when the inbound carries no MSH-10 correlation id, and @cosyte/mllp's ack-from-hl7 adapter applies it when the inbound cannot be parsed at all: neither ever fabricates an unverifiable positive acknowledgment, and neither carries its own copy of the mapping.

Parameters​

code​

AckCode

Returns​

AckCode

Example​

import { downgradePositiveAck } from "@cosyte/hl7";
downgradePositiveAck("AA"); // "AE"
downgradePositiveAck("CA"); // "CE"
downgradePositiveAck("AR"); // "AR" (unchanged)

dtmToDate()​

dtmToDate(parts, options?): Date | undefined

Materialize an absolute-instant JS Date from DtmParts: only on explicit caller request. Truncated fields fill to their lowest legal value (month → January, day → 1, time → 0) for instant construction only; the value's stated precision still tells the truth.

Timezone resolution is honest:

  • has an offset → the exact instant, using that offset;
  • no offset + assumeOffsetMinutes supplied → that offset is applied;
  • no offset + nothing supplied → undefined (never a silent UTC guess).

Returns undefined for an invalid value or an unresolvable zone; never throws.

Parameters​

parts​

DtmParts

options?​

DtmToDateOptions = {}

Returns​

Date | undefined

Example​

import { parseDtm, dtmToDate } from "@cosyte/hl7";

dtmToDate(parseDtm("20250102153045-0500"))?.toISOString();
// "2025-01-02T20:30:45.000Z": exact, offset-derived

dtmToDate(parseDtm("20250102")); // undefined: refuses to guess the zone
dtmToDate(parseDtm("20250102"), { assumeOffsetMinutes: 0 })?.toISOString();
// "2025-01-02T00:00:00.000Z": caller explicitly assumed UTC

duplicateRequiredSegment()​

duplicateRequiredSegment(position, segmentName): Hl7ParseWarning

Build a DUPLICATE_REQUIRED_SEGMENT warning. Emitted when a segment the profile marks as singleton appears more than once (e.g. two MSH segments). The parser keeps both; the warning alerts the consumer to potential sender bugs.

Parameters​

position​

Hl7Position

segmentName​

string

Returns​

Hl7ParseWarning

Example​

import { duplicateRequiredSegment } from "@cosyte/hl7";
const w = duplicateRequiredSegment({ segmentIndex: 1 }, "MSH");

encodeCe()​

encodeCe(v): RawField

Encode a CE (coded element, 6 modelled + preserved extraComponents).

Parameters​

v​

CE

Returns​

RawField

Example​

import { encodeCe } from "@cosyte/hl7";
encodeCe({ identifier: "GLU", text: "Glucose", nameOfCodingSystem: "L" });

encodeComposite()​

encodeComposite<K>(kind, value): RawField

Encode any typed composite into a spec-clean RawField by its CompositeKind. The single dispatcher setComposite and the typed builders (buildAdt/buildOru) route through.

Encoding takes no encoding-characters argument on purpose: the field it produces carries the decoded component values, and the actual delimiter-escaping happens later in the serializer against the message's own encoding characters: so a composite is delimiter-independent to encode.

Type Parameters​

K​

K extends CompositeKind

Parameters​

kind​

K

value​

CompositeValueByKind[K]

Returns​

RawField

Example​

import { encodeComposite } from "@cosyte/hl7";
// A hostile family name cannot break framing on emit:
const f = encodeComposite("XPN", { familyName: "Smith^Jr", givenName: "Ann" });

encodeCompositeReps()​

encodeCompositeReps<K>(kind, values): RawField

Encode an array of typed composites into a single repeating RawField: one HL7 repetition (~-joined on emit) per array element. Used for repeating fields such as PID-3 (patient identifier list) and PID-11 (addresses). An empty array yields an absent field.

Type Parameters​

K​

K extends CompositeKind

Parameters​

kind​

K

values​

readonly CompositeValueByKind[K][]

Returns​

RawField

Example​

import { encodeCompositeReps } from "@cosyte/hl7";
const ids = encodeCompositeReps("CX", [
{ idNumber: "MRN001", identifierTypeCode: "MR" },
{ idNumber: "9990", identifierTypeCode: "SS" },
]);

encodeCwe()​

encodeCwe(v): RawField

Encode a CWE (coded element, 9 modelled + preserved extraComponents).

Parameters​

v​

CWE

Returns​

RawField

Example​

import { encodeCwe } from "@cosyte/hl7";
encodeCwe({ identifier: "GLU", text: "Glucose", nameOfCodingSystem: "LN" });

encodeCx()​

encodeCx(v): RawField

Encode a CX (identifier): component 4 is a nested HD (assigningAuthority).

Parameters​

v​

CX

Returns​

RawField

Example​

import { encodeCx } from "@cosyte/hl7";
encodeCx({ idNumber: "MRN001", assigningAuthority: { namespaceId: "HOSP" }, identifierTypeCode: "MR" });

encodeHd()​

encodeHd(v): RawField

Encode an HD (hierarchic designator, 3 components) to a spec-clean field.

Parameters​

v​

HD

Returns​

RawField

Example​

import { encodeHd } from "@cosyte/hl7";
encodeHd({ namespaceId: "EPIC", universalId: "1.2.840", universalIdType: "ISO" });

encodeNm()​

encodeNm(v): RawField

Encode an NM numeric. Accepts the typed NM (its raw string emitted verbatim, preserving the sender's precision/formatting), a number, or a raw string. A number is stringified with String(n); the value is never reconciled or rounded.

Parameters​

v​

string | number | NM

Returns​

RawField

Example​

import { encodeNm } from "@cosyte/hl7";
encodeNm("120.50"); // precision preserved verbatim

encodePl()​

encodePl(v): RawField

Encode a PL (person location): component 4 is a nested HD (facility).

Parameters​

v​

PL

Returns​

RawField

Example​

import { encodePl } from "@cosyte/hl7";
encodePl({ pointOfCare: "ICU", room: "101", bed: "A" });

encodeText()​

encodeText(input, enc?): string

Encode-safe direction: escape an arbitrary string so it can be placed in an HL7 field as data without ever breaking framing. Every reserved character : the escape char (escaped first, so decoding is unambiguous), the field, component, subcomponent, and repetition separators, the declared truncation char, and the framing-critical \n/\r: is replaced by its escape sequence, so the value cannot inject a delimiter or forge a component / subcomponent / repetition boundary.

The hard invariant, property-tested over arbitrary strings: decodeText(encodeText(s, enc), enc) === s, and a message field carrying encodeText(s) cannot forge a component / subcomponent / repetition boundary or break framing: the value never escapes its field.

Two caveats are inherent to HL7 field encoding, not to this codec, and apply to whole-field re-parse (they do not weaken the no-injection guarantee): the two-character string "" is HL7's explicit-null token, so a field whose entire value is "" re-parses as null; and the default parser trims field whitespace, so a value with leading/trailing spaces re-parses trimmed. Encode such values into a component/subcomponent position, or parse with trimming off, to preserve them exactly.

Parameters​

input​

string

the arbitrary string to encode.

enc?​

EncodingCharacters = DEFAULT_ENCODING_CHARACTERS

encoding characters; defaults to the HL7 standard |^~\&.

Returns​

string

the spec-clean, delimiter-safe field body.

Example​

import { encodeText, parseHL7 } from "@cosyte/hl7";
// A value full of delimiters cannot break out of its field:
const hostile = "a|b^c~d\\e&f";
const body = encodeText(hostile); // "a\\F\\b\\S\\c\\R\\d\\E\\e\\T\\f"
const msg = parseHL7(`MSH|^~\\&|A|B|C|D|20260101||ADT^A01|1|P|2.5\rNTE|1||${body}`);
msg.segments("NTE")[0]?.field(3).value === hostile; // true: round-trips exactly

encodeTs()​

encodeTs(v): RawField

Encode a TS/DTM timestamp. Accepts either the typed TS (its raw string is emitted verbatim: the serializer never re-derives a timestamp from parts) or a pre-formatted HL7 timestamp string.

Parameters​

v​

string | DtmParts

Returns​

RawField

Example​

import { encodeTs } from "@cosyte/hl7";
encodeTs("20260721101500");

encodeXad()​

encodeXad(v): RawField

Encode an XAD (12 components) to a spec-clean field.

Parameters​

v​

XAD

Returns​

RawField

Example​

import { encodeXad } from "@cosyte/hl7";
encodeXad({ street: "123 Main St", city: "Boston", stateOrProvince: "MA" });

encodeXcn()​

encodeXcn(v): RawField

Encode an XCN: component 9 is a nested HD (assigningAuthority).

Parameters​

v​

XCN

Returns​

RawField

Example​

import { encodeXcn } from "@cosyte/hl7";
encodeXcn({ idNumber: "1234567890", familyName: "Welby", identifierTypeCode: "NPI" });

encodeXpn()​

encodeXpn(v): RawField

Encode an XPN (14 components) to a spec-clean field.

Parameters​

v​

XPN

Returns​

RawField

Example​

import { encodeXpn } from "@cosyte/hl7";
encodeXpn({ familyName: "Doe", givenName: "Jane", prefix: "Dr" });

encodeXtn()​

encodeXtn(v): RawField

Encode an XTN (telecom, 12 components) to a spec-clean field.

Parameters​

v​

XTN

Returns​

RawField

Example​

import { encodeXtn } from "@cosyte/hl7";
encodeXtn({ telephoneNumber: "555-1234", telecommunicationUseCode: "PRN" });

encodingMismatch()​

encodingMismatch(position, detail): Hl7ParseWarning

Build an ENCODING_MISMATCH warning. Emitted when the MSH-2 encoding characters declared by the sender do not match what the parser observed downstream (e.g. the sender declares ^~\& but uses !@#$ as actual separators in later segments).

Parameters​

position​

Hl7Position

detail​

string

Returns​

Hl7ParseWarning

Example​

import { encodingMismatch } from "@cosyte/hl7";
const w = encodingMismatch({ segmentIndex: 0 }, "MSH-2 declares ^~\\& but segment used !@#$");

extraFields()​

extraFields(position, segmentName, extraCount): Hl7ParseWarning

Build an EXTRA_FIELDS warning. Emitted when a segment contains more fields than the profile definition (or HL7 spec) declares: the extras are preserved on RawSegment.fields but flagged for consumers.

Parameters​

position​

Hl7Position

segmentName​

string

extraCount​

number

Returns​

Hl7ParseWarning

Example​

import { extraFields } from "@cosyte/hl7";
const w = extraFields({ segmentIndex: 4 }, "PID", 3);

fieldWhitespaceTrimmed()​

fieldWhitespaceTrimmed(position, leadingCount, trailingCount): Hl7ParseWarning

Build a FIELD_WHITESPACE_TRIMMED warning. Emitted when the parser trims leading or trailing whitespace from a field value (the trimFields option, on by default). The message carries only the leading/trailing character counts: NEVER the field value itself (before or after trimming): so no PHI is exposed; the trimmed value is still preserved verbatim in the parsed output.

Parameters​

position​

Hl7Position

leadingCount​

number

trailingCount​

number

Returns​

Hl7ParseWarning

Example​

import { fieldWhitespaceTrimmed } from "@cosyte/hl7";
const w = fieldWhitespaceTrimmed({ segmentIndex: 1, fieldIndex: 5 }, 2, 1);

formatDtm()​

formatDtm(parts): string

Reconstruct the HL7 DTM string from DtmParts. The inverse of parseDtm for a strict HL7 parse: formatDtm(parseDtm(s)) === s for any well-formed s, including the byte-preserving -0000 (which HL7, unlike RFC 3339, treats as UTC but whose sign we retain for exact round-trip). Returns the raw string unchanged when parts.valid is false.

Emits exactly the populated precision, no zero-fill, so a year-only value re-serializes to four characters, never YYYY0101.

Parameters​

parts​

DtmParts

Returns​

string

Example​

import { parseDtm, formatDtm } from "@cosyte/hl7";
formatDtm(parseDtm("198807050000")); // "198807050000"
formatDtm(parseDtm("1970")); // "1970"

getDefaultProfile()​

getDefaultProfile(): Profile | undefined

Return the current default profile, or undefined if none is registered. Consistent with msg.profile convention: undefined rather than null.

Returns​

Profile | undefined

Example​

import { getDefaultProfile } from "@cosyte/hl7";
const p = getDefaultProfile();
if (p !== undefined) console.log("default profile:", p.name);

interpretAck()​

interpretAck(msg): Acknowledgment

Interpret an Hl7Message as an acknowledgment. Never throws; a message with no MSA segment yields an all-false, empty-errors view. The result is deeply frozen.

Parameters​

msg​

Hl7Message

Returns​

Acknowledgment

Example​

import { interpretAck, parseHL7 } from "@cosyte/hl7";
const view = interpretAck(parseHL7("MSH|^~\\&|...\rMSA|AA|MSG001"));
view.accepted; // true
view.controlId; // "MSG001"

isPositiveAck()​

isPositiveAck(code): boolean

True iff code is a positive accept (AA/CA). Unknown/absent → false.

Parameters​

code​

string | undefined

Returns​

boolean

Example​

isPositiveAck("AA"); // true
isPositiveAck("AE"); // false

mergeMissingPriorOrSurvivor()​

mergeMissingPriorOrSurvivor(position, eventType, missing): Hl7ParseWarning

Build a MERGE_MISSING_PRIOR_OR_SURVIVOR warning. Emitted by identityEvents() (a read-side helper: it attaches to the returned IdentityEvent.warnings, never to Hl7Message.warnings) when a merge/move trigger event (A18/A34/A35/A36/A39/A40/A41/A42/A43/A44) is missing one side of the spec-mandated MRG (prior) → PID (surviving) pair: or when that side carries no usable identity field: no MRG segment in the patient group, no PID for an orphaned MRG, or a PID/MRG whose identifier, account, and visit fields are all empty or version-gated (a v2.7+ MRG whose only content was the withdrawn MRG-4 must not read as "nothing to retire"). The helper surfaces whatever IS present and never guesses the merge direction: this warning is the signal that the pair is incomplete.

The message carries only the structural facts (trigger event code + which role is missing): NEVER an identifier, name, or any other field value, so no PHI is exposed (HL7 v2 Ch. 3: the PID carries surviving and the MRG carries non-surviving identity information).

Parameters​

position​

Hl7Position

eventType​

string

missing​

"prior" | "survivor"

Returns​

Hl7ParseWarning

Example​

import { mergeMissingPriorOrSurvivor } from "@cosyte/hl7";
const w = mergeMissingPriorOrSurvivor({ segmentIndex: 1 }, "A40", "prior");

missingExpectedGroup()​

missingExpectedGroup(position, messageType, groupName, anchorSegments): Hl7ParseWarning

Build a MISSING_EXPECTED_GROUP warning. Emitted once per absent Required segment group when the message's (MSH-9.1, MSH-9.2) type is one the structure safety net recognizes and an expected group is entirely missing: e.g. an ORU^R01 carrying no OBR/OBX result group, the signature of a truncated or misrouted feed. Tier-2 and additive: lenient parse never throws on it, strict mode may promote it. The message carries only the structural fact (message type, group name, anchor segment names), never a field value: the message type is shape-checked before it is interpolated, and withheld if it does not match. position references MSH-9.

Parameters​

position​

Hl7Position

messageType​

string

groupName​

string

anchorSegments​

readonly string[]

Returns​

Hl7ParseWarning

Example​

import { missingExpectedGroup } from "@cosyte/hl7";
const w = missingExpectedGroup(
{ segmentIndex: 0, fieldIndex: 9 },
"ORU^R01",
"result",
["OBR", "OBX"],
);

missingRequiredField()​

missingRequiredField(position, segmentName, fieldIndex): Hl7ParseWarning

Build a MISSING_REQUIRED_FIELD warning. Emitted when a field the active profile marks as required is empty or missing. Distinct from the NO_MSH_SEGMENT fatal, which escalates a missing MSH altogether.

Parameters​

position​

Hl7Position

segmentName​

string

fieldIndex​

number

Returns​

Hl7ParseWarning

Example​

import { missingRequiredField } from "@cosyte/hl7";
const w = missingRequiredField({ segmentIndex: 0, fieldIndex: 3 }, "MSH", 3);

mllpFramingStripped()​

mllpFramingStripped(position): Hl7ParseWarning

Build a MLLP_FRAMING_STRIPPED warning. Emitted once per parse when the preprocessor detects and removes MLLP framing bytes (0x0B / 0x1C / trailing 0x0D) from the input.

Parameters​

position​

Hl7Position

Returns​

Hl7ParseWarning

Example​

import { mllpFramingStripped } from "@cosyte/hl7";
const w = mllpFramingStripped({ segmentIndex: 0 });

outOfOrderSegment()​

outOfOrderSegment(position, segmentName): Hl7ParseWarning

Build an OUT_OF_ORDER_SEGMENT warning. Emitted when a segment appears outside the order the active profile declares (e.g. EVN appearing before MSH in a typical ADT message).

Parameters​

position​

Hl7Position

segmentName​

string

Returns​

Hl7ParseWarning

Example​

import { outOfOrderSegment } from "@cosyte/hl7";
const w = outOfOrderSegment({ segmentIndex: 2 }, "EVN");

parseCe()​

parseCe(rep, enc): CE

Parse an HL7 v2 CE repetition into a structured CE object. Components are returned verbatim (already decoded once by the tokenizer: never re-unescaped). Absent / empty components are OMITTED from the result (exactOptionalPropertyTypes semantics).

Parameters​

rep​

RawRepetition

enc​

EncodingCharacters

Returns​

CE

Example​

import { parseCe, DEFAULT_ENCODING_CHARACTERS } from "@cosyte/hl7";
const rep = { components: [
{ subcomponents: ["GLU"] },
{ subcomponents: ["Glucose"] },
{ subcomponents: ["LN"] },
] };
const ce = parseCe(rep, DEFAULT_ENCODING_CHARACTERS);
console.log(ce.identifier); // "GLU"

parseCwe()​

parseCwe(rep, enc): CWE

Parse an HL7 v2 CWE repetition into a structured CWE object. Components are returned verbatim (already decoded once by the tokenizer: never re-unescaped). Absent / empty components are OMITTED from the result (exactOptionalPropertyTypes semantics).

Parameters​

rep​

RawRepetition

enc​

EncodingCharacters

Returns​

CWE

Example​

import { parseCwe, DEFAULT_ENCODING_CHARACTERS } from "@cosyte/hl7";
const rep = { components: [
{ subcomponents: ["GLU"] },
{ subcomponents: ["Glucose"] },
{ subcomponents: ["LN"] },
] };
const cwe = parseCwe(rep, DEFAULT_ENCODING_CHARACTERS);
console.log(cwe.identifier); // "GLU"

parseCx()​

parseCx(rep, enc): CX

Parse an HL7 v2 CX repetition into a structured CX object. Components are returned verbatim (already decoded once by the tokenizer: never re-unescaped). Absent / empty components are OMITTED from the result (exactOptionalPropertyTypes semantics). Component 4 (assigningAuthority) is parsed as a nested HD; see component table in the CX interface JSDoc for the v1 simplifications on components 6/9/10.

Parameters​

rep​

RawRepetition

enc​

EncodingCharacters

Returns​

CX

Example​

import { parseCx, DEFAULT_ENCODING_CHARACTERS } from "@cosyte/hl7";
const rep = { components: [
{ subcomponents: ["123"] },
{ subcomponents: [""] },
{ subcomponents: [""] },
{ subcomponents: ["EPIC", "1.2.840.114350", "ISO"] },
{ subcomponents: ["MR"] },
] };
const cx = parseCx(rep, DEFAULT_ENCODING_CHARACTERS);
console.log(cx.idNumber); // "123"
console.log(cx.assigningAuthority?.namespaceId); // "EPIC"

parseDtm()​

parseDtm(raw): DtmParts

Parse an HL7 v2 TS/DTM string into typed DtmParts, preserving the stated precision and timezone fidelity. Never zero-fills a truncation, never coerces to a Date, and never assumes UTC for a missing offset.

Returns { raw, valid: false, hasTimezone: false } (no parts) for empty, malformed, or calendar-out-of-range input: never throws. A fractional component is only accepted at full second precision.

Parameters​

raw​

string

Returns​

DtmParts

Example​

import { parseDtm } from "@cosyte/hl7";

parseDtm("1970");
// { raw: "1970", valid: true, precision: "year", year: 1970, hasTimezone: false }

parseDtm("20250102153045.5-0500");
// precision "fraction", fractionalSeconds "5", hasTimezone true, offsetMinutes -300

parseDtm("not-a-date");
// { raw: "not-a-date", valid: false, hasTimezone: false }

parseHd()​

parseHd(rep, enc): HD

Parse an HL7 v2 HD repetition into a structured HD object. Components are returned verbatim (already decoded once by the tokenizer: never re-unescaped). Absent / empty components are OMITTED from the result (exactOptionalPropertyTypes semantics).

Parameters​

rep​

RawRepetition

enc​

EncodingCharacters

Returns​

HD

Example​

import { parseHd, DEFAULT_ENCODING_CHARACTERS } from "@cosyte/hl7";
const rep = { components: [
{ subcomponents: ["EPIC"] },
{ subcomponents: ["1.2.840.114350"] },
{ subcomponents: ["ISO"] },
] };
const hd = parseHd(rep, DEFAULT_ENCODING_CHARACTERS);
console.log(hd.namespaceId); // "EPIC"
console.log(hd.universalIdType); // "ISO"

parseHL7()​

Internal

implementation signature; overload signatures above carry the public JSDoc + @example.

Call Signature​

parseHL7(raw): Hl7Message

Parse a raw HL7 v2 message (string or Buffer) into an Hl7Message. The parser is lenient by default: recoverable deviations from the HL7 spec are reported via msg.warnings and (optionally) options.onWarning but do not throw. Four unrecoverable structural errors throw Hl7ParseError: NO_MSH_SEGMENT, MSH_TOO_SHORT, INVALID_ENCODING_CHARACTERS, EMPTY_INPUT. Opt into strict mode with { strict: true } to escalate every Tier-2 warning into an Hl7ParseError.

Parameters​
raw​

string | Buffer<ArrayBufferLike>

Returns​

Hl7Message

Example​
import { parseHL7, WARNING_CODES } from "@cosyte/hl7";

const msg = parseHL7(
"MSH|^~\\&|APP|FAC|APP|FAC|20250101||ADT^A01|1|P|2.5\rPID|||123",
);
console.log(msg.version); // "2.5"
console.log(msg.warnings.length); // 0
for (const w of msg.warnings) {
if (w.code === WARNING_CODES.MLLP_FRAMING_STRIPPED) {
// handle MLLP-framed sender
}
}

Call Signature​

parseHL7(raw, profile): Hl7Message

Parse a raw HL7 v2 message (string or Buffer) into an Hl7Message. The parser is lenient by default: recoverable deviations from the HL7 spec are reported via msg.warnings and (optionally) options.onWarning but do not throw. Four unrecoverable structural errors throw Hl7ParseError: NO_MSH_SEGMENT, MSH_TOO_SHORT, INVALID_ENCODING_CHARACTERS, EMPTY_INPUT. Opt into strict mode with { strict: true } to escalate every Tier-2 warning into an Hl7ParseError.

Parameters​
raw​

string | Buffer<ArrayBufferLike>

profile​

Profile

Returns​

Hl7Message

Example​
import { parseHL7, WARNING_CODES } from "@cosyte/hl7";

const msg = parseHL7(
"MSH|^~\\&|APP|FAC|APP|FAC|20250101||ADT^A01|1|P|2.5\rPID|||123",
);
console.log(msg.version); // "2.5"
console.log(msg.warnings.length); // 0
for (const w of msg.warnings) {
if (w.code === WARNING_CODES.MLLP_FRAMING_STRIPPED) {
// handle MLLP-framed sender
}
}

Call Signature​

parseHL7(raw, options): Hl7Message

Parse a raw HL7 v2 message (string or Buffer) into an Hl7Message. The parser is lenient by default: recoverable deviations from the HL7 spec are reported via msg.warnings and (optionally) options.onWarning but do not throw. Four unrecoverable structural errors throw Hl7ParseError: NO_MSH_SEGMENT, MSH_TOO_SHORT, INVALID_ENCODING_CHARACTERS, EMPTY_INPUT. Opt into strict mode with { strict: true } to escalate every Tier-2 warning into an Hl7ParseError.

Parameters​
raw​

string | Buffer<ArrayBufferLike>

options​

ParseOptions

Returns​

Hl7Message

Example​
import { parseHL7, WARNING_CODES } from "@cosyte/hl7";

const msg = parseHL7(
"MSH|^~\\&|APP|FAC|APP|FAC|20250101||ADT^A01|1|P|2.5\rPID|||123",
);
console.log(msg.version); // "2.5"
console.log(msg.warnings.length); // 0
for (const w of msg.warnings) {
if (w.code === WARNING_CODES.MLLP_FRAMING_STRIPPED) {
// handle MLLP-framed sender
}
}

parseNm()​

parseNm(rep, _enc): NM

Parse an HL7 v2 NM repetition into { raw, value }. Uses Number(raw) for strict numeric parsing: trailing non-numeric characters produce NaN, normalized to undefined. Empty raw also produces undefined.

Number("") is 0 in JS: which is the wrong answer for an empty HL7 numeric field. The explicit empty-string check below returns { raw: "", value: undefined } so empty inputs match missing inputs.

Parameters​

rep​

RawRepetition

_enc​

EncodingCharacters

Returns​

NM

Example​

import { parseNm, DEFAULT_ENCODING_CHARACTERS } from "@cosyte/hl7";
const rep = { components: [{ subcomponents: ["120.5"] }] };
const nm = parseNm(rep, DEFAULT_ENCODING_CHARACTERS);
console.log(nm.value); // 120.5

parsePath()​

parsePath(path): DotPath

Parse an HL7 dot-path string into a DotPath descriptor. Accepts shapes like SEG, SEG[n], SEG.N, SEG.N[r], SEG.N.C, SEG.N.C.S, and all combinations up to SEG[n].N[r].C.S. Throws TypeError with the offending path string on any malformed input.

Parameters​

path​

string

Returns​

DotPath

Example​

import { parsePath } from "@cosyte/hl7";
parsePath("PID.5.1"); // { segmentType: "PID", segmentIndex: 0, fieldIndex: 5, componentIndex: 1 }
parsePath("OBX[2].5"); // { segmentType: "OBX", segmentIndex: 2, fieldIndex: 5 }
parsePath("PID.3[1].1"); // { segmentType: "PID", segmentIndex: 0, fieldIndex: 3, repetitionIndex: 1, componentIndex: 1 }

parsePl()​

parsePl(rep, enc): PL

Parse an HL7 v2 PL repetition into a structured PL object. Components are returned verbatim (already decoded once by the tokenizer: never re-unescaped). Absent / empty components are OMITTED from the result (exactOptionalPropertyTypes semantics). Component 4 (facility) is parsed as a nested HD; see component table in the PL interface JSDoc for the v1 simplifications.

Parameters​

rep​

RawRepetition

enc​

EncodingCharacters

Returns​

PL

Example​

import { parsePl, DEFAULT_ENCODING_CHARACTERS } from "@cosyte/hl7";
const rep = { components: [
{ subcomponents: ["ICU"] },
{ subcomponents: ["101"] },
{ subcomponents: ["A"] },
{ subcomponents: ["HOSP", "1.2.3", "UUID"] },
] };
const pl = parsePl(rep, DEFAULT_ENCODING_CHARACTERS);
console.log(pl.pointOfCare); // "ICU"
console.log(pl.facility?.namespaceId); // "HOSP"

parseSn()​

parseSn(rep, enc): SN | undefined

Parse an HL7 v2 SN repetition into a structured SN, or undefined when the field carries no usable structured-numeric content (empty, or so malformed that no comparator, number, or separator can be recovered). Components are returned verbatim (already decoded by the tokenizer); num1/num2 use strict Number() parsing.

Fail-safe: a non-operator value in the comparator slot (SN.1) is dropped rather than surfaced as a relation, and a non-numeric SN.2/SN.4 becomes undefined: the parser never emits a confident wrong comparator or number.

Parameters​

rep​

RawRepetition

enc​

EncodingCharacters

Returns​

SN | undefined

Example​

import { parseSn, DEFAULT_ENCODING_CHARACTERS } from "@cosyte/hl7";
const rep = { components: [
{ subcomponents: [">"] },
{ subcomponents: ["90"] },
] };
const sn = parseSn(rep, DEFAULT_ENCODING_CHARACTERS);
console.log(sn?.comparator, sn?.num1); // ">" 90

parseStream()​

Internal

implementation signature; overloads above carry the public JSDoc.

Call Signature​

parseStream(source): AsyncGenerator<StreamMessageEntry, void, void>

Incrementally parse a chunked HL7 v2 byte / text stream, yielding one StreamMessageEntry per MSH-delimited message as its boundary completes, with O(one-message) memory: the whole stream is never retained. Demarcates by MSH boundaries inside the optional [FHS] { [BHS] { MSH… } [BTS] } [FTS] batch frame (HL7 v2 Ch. 2 §2.10.3):

  • a message split across chunk boundaries (mid-segment, mid-field, even mid-MSH|^~\&) is reassembled correctly: feeding the same bytes in 1-byte chunks vs. one chunk yields identical messages;
  • \r, \r\n, and \n segment terminators are all tolerated (a \r\n split across a chunk boundary is not mistaken for a bare \r);
  • each message is parsed by the shipped parseHL7 (no second grammar), ok entries carry the Hl7Message, a Tier-3 fatal is an isolated failure entry; a malformed message never suppresses later messages;
  • batch-envelope segments (FHS/BHS/BTS/FTS) are treated as boundaries and never yielded as messages, so yielded count == MSH count (envelope count reconciliation is splitBatch's job);
  • a final message with no trailing terminator is still yielded, flagged with a stream-level unterminatedStreamMessage warning: never a throw, the tail is never dropped.

The second argument, when given, is forwarded verbatim to parseHL7 for each message (profile, strict, charset, dateFormats, …), exactly as splitBatch forwards it.

Parameters​
source​

Hl7StreamSource

Returns​

AsyncGenerator<StreamMessageEntry, void, void>

Example​
import { parseStream } from "@cosyte/hl7";

async function* chunks() {
yield "MSH|^~\\&|A|F|B|G|20260101||ADT^A01|1|P|2.5\rPID|||1\r";
yield "MSH|^~\\&|A|F|B|G|20260101||ADT^A01|2|P|2.5\rPID|||2\r";
}

let count = 0;
for await (const entry of parseStream(chunks())) {
if (entry.ok) count += 1; // 2: one per MSH, streamed, released each time
}

Call Signature​

parseStream(source, profile): AsyncGenerator<StreamMessageEntry, void, void>

Incrementally parse a chunked HL7 v2 byte / text stream, yielding one StreamMessageEntry per MSH-delimited message as its boundary completes, with O(one-message) memory: the whole stream is never retained. Demarcates by MSH boundaries inside the optional [FHS] { [BHS] { MSH… } [BTS] } [FTS] batch frame (HL7 v2 Ch. 2 §2.10.3):

  • a message split across chunk boundaries (mid-segment, mid-field, even mid-MSH|^~\&) is reassembled correctly: feeding the same bytes in 1-byte chunks vs. one chunk yields identical messages;
  • \r, \r\n, and \n segment terminators are all tolerated (a \r\n split across a chunk boundary is not mistaken for a bare \r);
  • each message is parsed by the shipped parseHL7 (no second grammar), ok entries carry the Hl7Message, a Tier-3 fatal is an isolated failure entry; a malformed message never suppresses later messages;
  • batch-envelope segments (FHS/BHS/BTS/FTS) are treated as boundaries and never yielded as messages, so yielded count == MSH count (envelope count reconciliation is splitBatch's job);
  • a final message with no trailing terminator is still yielded, flagged with a stream-level unterminatedStreamMessage warning: never a throw, the tail is never dropped.

The second argument, when given, is forwarded verbatim to parseHL7 for each message (profile, strict, charset, dateFormats, …), exactly as splitBatch forwards it.

Parameters​
source​

Hl7StreamSource

profile​

Profile

Returns​

AsyncGenerator<StreamMessageEntry, void, void>

Example​
import { parseStream } from "@cosyte/hl7";

async function* chunks() {
yield "MSH|^~\\&|A|F|B|G|20260101||ADT^A01|1|P|2.5\rPID|||1\r";
yield "MSH|^~\\&|A|F|B|G|20260101||ADT^A01|2|P|2.5\rPID|||2\r";
}

let count = 0;
for await (const entry of parseStream(chunks())) {
if (entry.ok) count += 1; // 2: one per MSH, streamed, released each time
}

Call Signature​

parseStream(source, options): AsyncGenerator<StreamMessageEntry, void, void>

Incrementally parse a chunked HL7 v2 byte / text stream, yielding one StreamMessageEntry per MSH-delimited message as its boundary completes, with O(one-message) memory: the whole stream is never retained. Demarcates by MSH boundaries inside the optional [FHS] { [BHS] { MSH… } [BTS] } [FTS] batch frame (HL7 v2 Ch. 2 §2.10.3):

  • a message split across chunk boundaries (mid-segment, mid-field, even mid-MSH|^~\&) is reassembled correctly: feeding the same bytes in 1-byte chunks vs. one chunk yields identical messages;
  • \r, \r\n, and \n segment terminators are all tolerated (a \r\n split across a chunk boundary is not mistaken for a bare \r);
  • each message is parsed by the shipped parseHL7 (no second grammar), ok entries carry the Hl7Message, a Tier-3 fatal is an isolated failure entry; a malformed message never suppresses later messages;
  • batch-envelope segments (FHS/BHS/BTS/FTS) are treated as boundaries and never yielded as messages, so yielded count == MSH count (envelope count reconciliation is splitBatch's job);
  • a final message with no trailing terminator is still yielded, flagged with a stream-level unterminatedStreamMessage warning: never a throw, the tail is never dropped.

The second argument, when given, is forwarded verbatim to parseHL7 for each message (profile, strict, charset, dateFormats, …), exactly as splitBatch forwards it.

Parameters​
source​

Hl7StreamSource

options​

ParseOptions

Returns​

AsyncGenerator<StreamMessageEntry, void, void>

Example​
import { parseStream } from "@cosyte/hl7";

async function* chunks() {
yield "MSH|^~\\&|A|F|B|G|20260101||ADT^A01|1|P|2.5\rPID|||1\r";
yield "MSH|^~\\&|A|F|B|G|20260101||ADT^A01|2|P|2.5\rPID|||2\r";
}

let count = 0;
for await (const entry of parseStream(chunks())) {
if (entry.ok) count += 1; // 2: one per MSH, streamed, released each time
}

parseTs()​

parseTs(rep, _enc): DtmParts

Parse an HL7 v2 TS/DTM repetition into fidelity TS parts. Delegates to parseDtm: the same structural parser that backs every timestamp in the library. No user dateFormats at this layer; non-composite callers (e.g. msg.meta.timestamp) that know ParseOptions.dateFormats use parseDtmCascade directly.

The result is frozen so the immutability guarantee holds for callers that destructure or retain it.

Parameters​

rep​

RawRepetition

_enc​

EncodingCharacters

Returns​

DtmParts

Example​

import { parseTs, DEFAULT_ENCODING_CHARACTERS, dtmToDate } from "@cosyte/hl7";
const rep = { components: [{ subcomponents: ["20250102153045-0500"] }] };
const ts = parseTs(rep, DEFAULT_ENCODING_CHARACTERS);
console.log(ts.raw); // "20250102153045-0500"
console.log(ts.precision, ts.hasTimezone); // "second" true
console.log(dtmToDate(ts)?.toISOString()); // "2025-01-02T20:30:45.000Z"

parseXad()​

parseXad(rep, enc): XAD

Parse an HL7 v2 XAD repetition into a structured XAD object. Components are returned verbatim (already decoded once by the tokenizer: never re-unescaped). Absent / empty components are OMITTED from the result (exactOptionalPropertyTypes semantics).

Parameters​

rep​

RawRepetition

enc​

EncodingCharacters

Returns​

XAD

Example​

import { parseXad, DEFAULT_ENCODING_CHARACTERS } from "@cosyte/hl7";
const rep = { components: [
{ subcomponents: ["123 Main St"] },
{ subcomponents: ["Apt 4"] },
{ subcomponents: ["Boston"] },
{ subcomponents: ["MA"] },
{ subcomponents: ["02101"] },
] };
const addr = parseXad(rep, DEFAULT_ENCODING_CHARACTERS);
console.log(addr.city); // "Boston"

parseXcn()​

parseXcn(rep, enc): XCN

Parse an HL7 v2 XCN repetition into a structured XCN object. Components are returned verbatim (already decoded once by the tokenizer: never re-unescaped). Absent / empty components are OMITTED from the result (exactOptionalPropertyTypes semantics). Component 9 (assigningAuthority) is parsed as a nested HD; see component table in the XCN interface JSDoc for the v1 trimming.

Parameters​

rep​

RawRepetition

enc​

EncodingCharacters

Returns​

XCN

Example​

import { parseXcn, DEFAULT_ENCODING_CHARACTERS } from "@cosyte/hl7";
const rep = { components: [
{ subcomponents: ["1234567890"] },
{ subcomponents: ["Smith"] },
{ subcomponents: ["Jane"] },
{ subcomponents: [""] },
{ subcomponents: [""] },
{ subcomponents: [""] },
{ subcomponents: [""] },
{ subcomponents: [""] },
{ subcomponents: ["HOSP", "1.2.3", "ISO"] },
{ subcomponents: ["L"] },
{ subcomponents: [""] },
{ subcomponents: [""] },
{ subcomponents: ["NPI"] },
] };
const xcn = parseXcn(rep, DEFAULT_ENCODING_CHARACTERS);
console.log(xcn.idNumber); // "1234567890"
console.log(xcn.familyName); // "Smith"
console.log(xcn.assigningAuthority?.namespaceId); // "HOSP"
console.log(xcn.identifierTypeCode); // "NPI"

parseXpn()​

parseXpn(rep, enc): XPN

Parse an HL7 v2 XPN repetition into a structured XPN object. Components are returned verbatim (already decoded once by the tokenizer: never re-unescaped). Absent / empty components are OMITTED from the result (exactOptionalPropertyTypes semantics).

Parameters​

rep​

RawRepetition

enc​

EncodingCharacters

Returns​

XPN

Example​

import { parseXpn, DEFAULT_ENCODING_CHARACTERS } from "@cosyte/hl7";
const rep = { components: [
{ subcomponents: ["Smith"] },
{ subcomponents: ["Jane"] },
] };
const xpn = parseXpn(rep, DEFAULT_ENCODING_CHARACTERS);
console.log(xpn.familyName); // "Smith"
console.log(xpn.givenName); // "Jane"

parseXtn()​

parseXtn(rep, enc): XTN

Parse an HL7 v2 XTN repetition into a structured XTN object. Components are returned verbatim (already decoded once by the tokenizer: never re-unescaped). Absent / empty components are OMITTED from the result (exactOptionalPropertyTypes semantics). Components past position 12 are silently ignored in v1.

Parameters​

rep​

RawRepetition

enc​

EncodingCharacters

Returns​

XTN

Example​

import { parseXtn, DEFAULT_ENCODING_CHARACTERS } from "@cosyte/hl7";
const rep = { components: [
{ subcomponents: ["555-1234"] },
{ subcomponents: ["PRN"] },
{ subcomponents: ["PH"] },
] };
const xtn = parseXtn(rep, DEFAULT_ENCODING_CHARACTERS);
console.log(xtn.telephoneNumber); // "555-1234"

pickMrn()​

pickMrn(identifiers): string | undefined

Pick the Medical Record Number string from a list of PID-3 CX identifiers.

D-07: prefer the first CX whose identifierTypeCode === "MR" (HL7 v2.5+ canonical MRN marker). D-10: the match is case-SENSITIVE: lowercase "mr" does NOT match; spec mandates uppercase.

D-08: when no MR-typed identifier is found, fall back to the first CX's idNumber. Returns undefined when the first CX has no idNumber (even if later CXs do: the fallback is strictly "first CX", not "first CX with idNumber", because we need a deterministic answer).

D-21: no warning emitted. Callers who need strict MR resolution can walk patient.identifiers themselves.

Parameters​

identifiers​

readonly CX[]

Returns​

string | undefined

Example​

import { pickMrn } from "@cosyte/hl7";
pickMrn([
{ idNumber: "X1" },
{ idNumber: "MRN001", identifierTypeCode: "MR" },
]);
// → "MRN001"

pickMrn([{ idNumber: "X1" }]);
// → "X1" (fallback: no MR entry)

pickMrn([]);
// → undefined

reescape()​

reescape(input, enc): string

Re-escape reserved characters back into their \X\ forms so the serializer can emit spec-clean HL7. This is the inverse of unescape for every delimiter-bearing character; round-trip cleanliness (unescape(reescape(x, enc), enc, emit, pos) === x) is a documented property covered by tests.

The characters re-escaped: enc.escape → \E
enc.field → \F
enc.component → \S
enc.subcomponent → \T
enc.repetition → \R
enc.truncation → \P\ (only when MSH-2 declared one, v2.7+) "\n" (LF) → .br
"\r" (CR) → \X0D\ (a decoded CR is the HL7 segment separator; emitting it raw would corrupt wire framing, so it re-encodes to its hex escape: see below)

Lossy by construction for the non-delimiter escape families. reescape only knows about the reserved characters above: it cannot reconstruct a recognize-and-preserve escape (\H\, formatting, charset, \Z..) or the original bytes of a hex escape (\X41\ decoded to A; casing of \X0d), because those decode to ordinary characters that carry no "I was an escape" marker. Byte-verbatim emit for those families is the serializer's job via the RawComponent.rawSubcomponents overlay (see escapeFidelityRaw); reescape is the fallback for content that has no overlay (constructed values, Field-level re-escapes).

Iteration uses for..of, which walks Unicode code points (not UTF-16 code units), so user-supplied content containing non-BMP characters round-trips correctly without special surrogate-pair handling.

Parameters​

input​

string

enc​

EncodingCharacters

Returns​

string

Example​

import { reescape, DEFAULT_ENCODING_CHARACTERS } from "@cosyte/hl7";
reescape("Smith|John", DEFAULT_ENCODING_CHARACTERS); // "Smith\\F\\John"
reescape("line1\nline2", DEFAULT_ENCODING_CHARACTERS); // "line1\\.br\\line2"

renderText()​

renderText(input, enc?, opts?): RenderedText

Render an HL7 v2 escape/formatting-bearing string into a normalized display model (plain text + highlight-aware runs). A read projection: it never mutates the underlying field, and it never fabricates: an escape it cannot render is preserved as literal characters and flagged in RenderedText.unrenderedSequences.

input is the field's escape-bearing text. Pass the wire form (e.g. Field.text, byte-verbatim for parsed content) for the most faithful result: a wire \E\H\E\ (an escaped literal backslash-H-backslash) then renders as the three literal characters \H, never as a highlight. Passing an already-decoded Field.value also works: its \.br\ is already a newline (rendered as one line break) and its \H/formatting sentinels are still recognized.

Never throws for any input.

Parameters​

input​

string

the escape-bearing field text to render.

enc?​

EncodingCharacters = DEFAULT_ENCODING_CHARACTERS

the message's encoding characters (for \F\/\S/… targets); defaults to the HL7 standard |^~\&.

opts?​

RenderTextOptions

see RenderTextOptions.

Returns​

RenderedText

the normalized RenderedText.

Example​

import { renderText } from "@cosyte/hl7";

const r = renderText("Specimen received.\\.br\\Gross exam \\H\\normal\\N\\.");
r.text;
// "Specimen received.\nGross exam normal."
r.runs;
// [ { text: "Specimen received.\nGross exam ", highlighted: false },
// { text: "normal", highlighted: true },
// { text: ".", highlighted: false } ]
r.unrenderedSequences; // []

resolveCharset()​

resolveCharset(raw): CharsetResolution

Resolve an MSH-18 label (or an options.charset override) to a CharsetResolution. A blank / undefined label resolves to the ASCII default. A recognized Table-0211 code returns its registry entry. An unrecognized label resolves to a verbatim, recognized: false outcome so the caller preserves bytes and emits UNKNOWN_CHARSET.

Parameters​

raw​

string | undefined

Returns​

CharsetResolution

Example​

import { resolveCharset } from "@cosyte/hl7";
resolveCharset("UNICODE UTF-8"); // { canonical: "UTF-8", treatment: "decode", ... }
resolveCharset("ISO IR87"); // { canonical: "ISO IR87", treatment: "verbatim", recognized: true }
resolveCharset("WINDOWS-1252"); // { canonical: "WINDOWS-1252", treatment: "verbatim", recognized: false }

resolvePath()​

resolvePath(path, segments, _enc): string | undefined

Resolve a dot-path string against a raw segment tree to its decoded leaf value. Returns undefined whenever the path does not resolve (missing segment, out-of-range field/component/subcomponent/repetition), and never throws on a missing value. Throws TypeError only when path itself is malformed: callers relying on "never throws" should pre-validate or wrap in try/catch.

Parameters​

path​

string

segments​

readonly RawSegment[]

_enc​

EncodingCharacters

Returns​

string | undefined

Example​

import { parseHL7, resolvePath } from "@cosyte/hl7";
const msg = parseHL7(raw);
resolvePath("PID.5.1", msg.rawSegments, msg.encodingCharacters); // "Smith"
resolvePath("NOT.9", msg.rawSegments, msg.encodingCharacters); // undefined

segmentCase()​

segmentCase(position, observed): Hl7ParseWarning

Build a SEGMENT_CASE warning. Emitted when a segment identifier is not all-uppercase (e.g. pid instead of PID). The parser accepts the segment; the warning alerts consumers to non-conforming senders.

Parameters​

position​

Hl7Position

observed​

string

Returns​

Hl7ParseWarning

Example​

import { segmentCase } from "@cosyte/hl7";
const w = segmentCase({ segmentIndex: 3 }, "pid");

setDefaultProfile()​

setDefaultProfile(profile): void

Register a process-scoped default profile. parseHL7(raw) (with no explicit profile arg) consults getDefaultProfile() and applies the returned profile if any. Pass null (or undefined) to clear.

Effects are IDENTICAL to passing the profile explicitly as the second arg of parseHL7 (D-20): customSegments, dateFormats, onWarning chain, and profile attribution all apply the same way.

Explicit args ALWAYS win: parseHL7(raw, myProfile) uses myProfile regardless of the default; parseHL7(raw, { profile: null }) opts out of the default for a single call without changing the registered default.

Test hygiene: This is the ONLY mutable module-scoped state in the library. Tests that call setDefaultProfile MUST clean up in afterEach (setDefaultProfile(null)) or default-profile bleed will infect subsequent tests.

Parameters​

profile​

Profile | null

Returns​

void

Example​

import { setDefaultProfile, profiles, parseHL7 } from "@cosyte/hl7";

// Set once at app startup
setDefaultProfile(profiles.epic);

// Every parseHL7 call in the app now uses profiles.epic unless
// another profile is passed explicitly.
const msg = parseHL7(raw);
console.log(msg.profile?.name); // "epic"

// Clear when done (or in test teardown):
setDefaultProfile(null);

splitBatch()​

Internal

implementation signature; overloads above carry the public JSDoc.

Call Signature​

splitBatch(raw): BatchSplitResult

Split a raw HL7 v2 batch / file stream into its individual messages plus the envelope metadata. Demarcates by MSH boundaries inside the optional [FHS] { [BHS] { MSH… } [BTS] } [FTS] frame (HL7 v2 Ch. 2 §2.10.3):

  • handles a file with multiple batches and a batch with multiple messages;
  • a bare single message (no envelope) passes straight through as one entry;
  • a malformed message mid-batch is isolated (returned as a typed failure entry): its siblings are still returned, the tail is never dropped;
  • reconciles BTS-1 (batch message count) and FTS-1 (file batch count) and emits batchCountMismatch on a mismatch: counts only, never PHI;
  • emits batchMissingTrailer when a BHS/FHS header opens a scope no BTS/FTS closes: a warning, never a throw (the caller decides to reject).

The second argument, when given, is forwarded verbatim to parseHL7 for each message (profile, strict, charset, dateFormats, …). Under strict, a message that would warn surfaces as a failure entry (still isolated). splitBatch itself never throws: an empty stream yields an empty result.

Parameters​
raw​

string | Buffer<ArrayBufferLike>

Returns​

BatchSplitResult

Example​
import { splitBatch } from "@cosyte/hl7";

const { messages, warnings } = splitBatch(
"FHS|^~\\&|SENDER\r" +
"BHS|^~\\&|SENDER\r" +
"MSH|^~\\&|A|F|B|G|20260101||ADT^A01|1|P|2.5\rPID|||1\r" +
"MSH|^~\\&|A|F|B|G|20260101||ADT^A01|2|P|2.5\rPID|||2\r" +
"BTS|2\rFTS|1\r",
);
console.log(messages.length); // 2
for (const entry of messages) {
if (entry.ok) console.log(entry.message.version); // "2.5"
}
console.log(warnings.length); // 0: declared counts match

Call Signature​

splitBatch(raw, profile): BatchSplitResult

Split a raw HL7 v2 batch / file stream into its individual messages plus the envelope metadata. Demarcates by MSH boundaries inside the optional [FHS] { [BHS] { MSH… } [BTS] } [FTS] frame (HL7 v2 Ch. 2 §2.10.3):

  • handles a file with multiple batches and a batch with multiple messages;
  • a bare single message (no envelope) passes straight through as one entry;
  • a malformed message mid-batch is isolated (returned as a typed failure entry): its siblings are still returned, the tail is never dropped;
  • reconciles BTS-1 (batch message count) and FTS-1 (file batch count) and emits batchCountMismatch on a mismatch: counts only, never PHI;
  • emits batchMissingTrailer when a BHS/FHS header opens a scope no BTS/FTS closes: a warning, never a throw (the caller decides to reject).

The second argument, when given, is forwarded verbatim to parseHL7 for each message (profile, strict, charset, dateFormats, …). Under strict, a message that would warn surfaces as a failure entry (still isolated). splitBatch itself never throws: an empty stream yields an empty result.

Parameters​
raw​

string | Buffer<ArrayBufferLike>

profile​

Profile

Returns​

BatchSplitResult

Example​
import { splitBatch } from "@cosyte/hl7";

const { messages, warnings } = splitBatch(
"FHS|^~\\&|SENDER\r" +
"BHS|^~\\&|SENDER\r" +
"MSH|^~\\&|A|F|B|G|20260101||ADT^A01|1|P|2.5\rPID|||1\r" +
"MSH|^~\\&|A|F|B|G|20260101||ADT^A01|2|P|2.5\rPID|||2\r" +
"BTS|2\rFTS|1\r",
);
console.log(messages.length); // 2
for (const entry of messages) {
if (entry.ok) console.log(entry.message.version); // "2.5"
}
console.log(warnings.length); // 0: declared counts match

Call Signature​

splitBatch(raw, options): BatchSplitResult

Split a raw HL7 v2 batch / file stream into its individual messages plus the envelope metadata. Demarcates by MSH boundaries inside the optional [FHS] { [BHS] { MSH… } [BTS] } [FTS] frame (HL7 v2 Ch. 2 §2.10.3):

  • handles a file with multiple batches and a batch with multiple messages;
  • a bare single message (no envelope) passes straight through as one entry;
  • a malformed message mid-batch is isolated (returned as a typed failure entry): its siblings are still returned, the tail is never dropped;
  • reconciles BTS-1 (batch message count) and FTS-1 (file batch count) and emits batchCountMismatch on a mismatch: counts only, never PHI;
  • emits batchMissingTrailer when a BHS/FHS header opens a scope no BTS/FTS closes: a warning, never a throw (the caller decides to reject).

The second argument, when given, is forwarded verbatim to parseHL7 for each message (profile, strict, charset, dateFormats, …). Under strict, a message that would warn surfaces as a failure entry (still isolated). splitBatch itself never throws: an empty stream yields an empty result.

Parameters​
raw​

string | Buffer<ArrayBufferLike>

options​

ParseOptions

Returns​

BatchSplitResult

Example​
import { splitBatch } from "@cosyte/hl7";

const { messages, warnings } = splitBatch(
"FHS|^~\\&|SENDER\r" +
"BHS|^~\\&|SENDER\r" +
"MSH|^~\\&|A|F|B|G|20260101||ADT^A01|1|P|2.5\rPID|||1\r" +
"MSH|^~\\&|A|F|B|G|20260101||ADT^A01|2|P|2.5\rPID|||2\r" +
"BTS|2\rFTS|1\r",
);
console.log(messages.length); // 2
for (const entry of messages) {
if (entry.ok) console.log(entry.message.version); // "2.5"
}
console.log(warnings.length); // 0: declared counts match

timestampFallbackFormat()​

timestampFallbackFormat(position, matchedFormat): Hl7ParseWarning

Build a TIMESTAMP_FALLBACK_FORMAT warning. Emitted when a date/time field could not be parsed with its primary (strict HL7) format but a fallback format from ParseOptions.dateFormats or built-in fallbacks succeeded.

Parameters​

position​

Hl7Position

matchedFormat​

string

Returns​

Hl7ParseWarning

Example​

import { timestampFallbackFormat } from "@cosyte/hl7";
const w = timestampFallbackFormat(
{ segmentIndex: 1, fieldIndex: 7 },
"YYYY-MM-DD",
);

unescape()​

unescape(input, enc, emit, position): string

Expand HL7 escape sequences (\F\, \S, \T\, \R, \E\, \.br, \X..\, vendor-specific \Z..) inside a field, component, or subcomponent string. The escape delimiter comes from enc.escape (default ``), so senders using a non-default escape character are handled transparently.

Unknown or malformed sequences are preserved VERBATIM in the output and emit an UNKNOWN_ESCAPE_SEQUENCE warning via emit. Unterminated escapes (an escape character with no closing partner before end-of-input) are also preserved in full and warn once: the scan is strictly O(n) and cannot infinite-loop on malformed input.

Parameters​

input​

string

enc​

EncodingCharacters

emit​

(w) => void

position​

Hl7Position

Returns​

string

Example​

import { unescape, DEFAULT_ENCODING_CHARACTERS } from "@cosyte/hl7";
const warnings: Array<unknown> = [];
const out = unescape(
"patient\\F\\name\\.br\\DOB",
DEFAULT_ENCODING_CHARACTERS,
(w) => warnings.push(w),
{ segmentIndex: 1, fieldIndex: 5 },
);
// out === "patient|name\nDOB"

unknownCharset()​

unknownCharset(position, requested): Hl7ParseWarning

Build an UNKNOWN_CHARSET warning. Emitted when MSH-18 (or an options.charset override) declares a value that is not a recognized HL7 Table-0211 character set. The parser never guesses an encoding: it reads the raw bytes as latin1 (a 1:1 byte mapping) so single-byte content stays recoverable, rather than corrupting it with replacement characters. The message carries the charset code only, never a decoded field value: the code is shape-checked before it is interpolated, and withheld if it does not match.

Parameters​

position​

Hl7Position

requested​

string

Returns​

Hl7ParseWarning

Example​

import { unknownCharset } from "@cosyte/hl7";
const w = unknownCharset({ segmentIndex: 0, fieldIndex: 18 }, "ISO IR 999");

unknownEscapeSequence()​

unknownEscapeSequence(position, body): Hl7ParseWarning

Build an UNKNOWN_ESCAPE_SEQUENCE warning for a terminated escape sequence (\..\) whose body is not a recognized HL7 escape. The message NEVER embeds the escape body: only its length and, when the body's first character is a recognized HL7 escape-identifier letter (structural HL7 grammar, not PHI: e.g. Z for a vendor escape, . for a formatting escape), that single letter. A body that doesn't start with a known escape letter is untrusted field text and names no character at all. The sequence itself is still preserved verbatim in the parsed output: only the WARNING message is PHI-safe.

Parameters​

position​

Hl7Position

body​

string

Returns​

Hl7ParseWarning

Example​

import { unknownEscapeSequence } from "@cosyte/hl7";
const w = unknownEscapeSequence({ segmentIndex: 2, fieldIndex: 3 }, "Z99");
// message: `Unknown HL7 escape sequence of type "Z" (3 chars) preserved verbatim.`

unknownSegment()​

unknownSegment(position, segmentName): Hl7ParseWarning

Build an UNKNOWN_SEGMENT warning. Emitted when a segment identifier is not in the HL7 spec's standard set and not registered in the active profile's customSegments.

Parameters​

position​

Hl7Position

segmentName​

string

Returns​

Hl7ParseWarning

Example​

import { unknownSegment } from "@cosyte/hl7";
const w = unknownSegment({ segmentIndex: 7 }, "ZZZ");

unsupportedCharset()​

unsupportedCharset(position, code): Hl7ParseWarning

Build an UNSUPPORTED_CHARSET warning. Emitted when a recognized Table-0211 character set is not decoded into text: either because this parser does not decode it (the multibyte / ISO-2022-switched East-Asian sets: JIS, GB 18030, KS X 1001, CNS 11643, BIG-5: and the wide Unicode transforms UTF-16 / UTF-32), or because a strict decode of a decodable set failed (a byte invalid / undefined for the declared set, or an ICU build lacking the label). In every case the raw bytes are read as latin1, never guessed at, so the parser does not emit replacement-char-corrupted text. Single-byte content stays byte-recoverable; multibyte content is best-effort (a content byte can coincide with a structural delimiter: see the parser's known-limitations). The switch escapes (\Cxxyy\ / \Mxxyyzz) are recognized and preserved by the escape layer; full stateful decoding is a documented non-goal. The message carries the charset code only, never a decoded field value: the code is shape-checked before it is interpolated, and withheld if it does not match.

Parameters​

position​

Hl7Position

code​

string

Returns​

Hl7ParseWarning

Example​

import { unsupportedCharset } from "@cosyte/hl7";
const w = unsupportedCharset({ segmentIndex: 0, fieldIndex: 18 }, "ISO IR87");

unterminatedEscapeSequence()​

unterminatedEscapeSequence(position): Hl7ParseWarning

Build an UNKNOWN_ESCAPE_SEQUENCE warning for an unterminated escape (an escape character with no closing partner before end-of-input). The "body" in this case is the entire remainder of the field, so the message carries NEITHER the body NOR its length (the length of a truncated tail is itself derivable field-shape information): just the fact that an unterminated escape was found, and the position. The remainder is still preserved verbatim in the parsed output.

Parameters​

position​

Hl7Position

Returns​

Hl7ParseWarning

Example​

import { unterminatedEscapeSequence } from "@cosyte/hl7";
const w = unterminatedEscapeSequence({ segmentIndex: 2, fieldIndex: 3 });
// message: `Unterminated HL7 escape sequence preserved verbatim.`

unterminatedStreamMessage()​

unterminatedStreamMessage(position): Hl7ParseWarning

Build an UNTERMINATED_STREAM_MESSAGE warning. Emitted by parseStream(): attached to a StreamMessageEntry's streamWarnings, NOT to Hl7Message.warnings: when the final message in a stream ends without a segment terminator (its last segment ran to end-of-stream with no trailing \r/\r\n/\n). The message is still parsed and yielded in full; this is the fail-safe signal that the tail may have been truncated mid-message (a cut-off feed), never a reason to drop it and never a throw. Only the last message can be unterminated: every earlier message is closed by the terminator that precedes the next MSH/envelope boundary.

The message carries only the structural fact, NEVER a field value, so no PHI is exposed. position references the message's MSH segment index.

Parameters​

position​

Hl7Position

Returns​

Hl7ParseWarning

Example​

import { unterminatedStreamMessage } from "@cosyte/hl7";
const w = unterminatedStreamMessage({ segmentIndex: 6 });

validateAgainstProfile()​

validateAgainstProfile(message, profile): ConformanceResult

Validate a parsed HL7 v2 message against a user-authored declarative conformance profile and return typed findings.

Never throws. A well-formed profile is evaluated rule by rule; a malformed profile is reported as PROFILE_MALFORMED findings (the engine does not validate against a profile it cannot trust: never a silent pass). Either way you get a ConformanceResult. For fail-fast authoring, run defineConformanceProfile first: it throws on a malformed profile.

findings.length === 0 is NOT a conformance attestation. It means every rule the profile declared was satisfied: nothing about the parts of the message the profile did not cover, and nothing about clinical correctness.

No PHI in findings: each finding names the structural locus (segment / field / component / repetition) and the rule, never the offending value.

Read-only: the message is never mutated.

Parameters​

message​

Hl7Message

a parsed message from parseHL7.

profile​

ConformanceProfile

the consumer's declarative ConformanceProfile.

Returns​

ConformanceResult

the profile name and the ordered findings (empty ⇒ no declared rule violated).

Example​

import { parseHL7, validateAgainstProfile, type ConformanceProfile } from "@cosyte/hl7";

const profile: ConformanceProfile = {
name: "example-adt-min",
segments: [
{ segment: "PID", usage: "R", fields: [
{ field: 3, name: "Patient Identifiers", usage: "R" },
{ field: 8, name: "Administrative Sex", usage: "RE", valueSet: ["M", "F", "U"] },
] },
],
};

const msg = parseHL7(raw);
const { findings } = validateAgainstProfile(msg, profile);
for (const f of findings) console.log(f.severity, f.code, f.message);
// findings.length === 0 ⇒ no declared rule violated (NOT an attestation)

versionMismatch()​

versionMismatch(position, declared, expected): Hl7ParseWarning

Build a VERSION_MISMATCH warning. Emitted when MSH-12 declares an HL7 version that does not match what the active profile or ParseOptions expected.

Parameters​

position​

Hl7Position

declared​

string

expected​

string

Returns​

Hl7ParseWarning

Example​

import { versionMismatch } from "@cosyte/hl7";
const w = versionMismatch({ segmentIndex: 0, fieldIndex: 12 }, "2.9", "2.5");