@cosyte/synth 0.1.9 → 0.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +39 -19
  3. package/dist/animal-code-Bdl_9Jma.d.cts +30 -0
  4. package/dist/animal-code-Bdl_9Jma.d.ts +30 -0
  5. package/dist/astm/index.cjs +147 -17
  6. package/dist/astm/index.cjs.map +1 -1
  7. package/dist/astm/index.d.cts +22 -9
  8. package/dist/astm/index.d.ts +22 -9
  9. package/dist/astm/index.mjs +147 -17
  10. package/dist/astm/index.mjs.map +1 -1
  11. package/dist/ccda/index.cjs +147 -17
  12. package/dist/ccda/index.cjs.map +1 -1
  13. package/dist/ccda/index.d.cts +12 -3
  14. package/dist/ccda/index.d.ts +12 -3
  15. package/dist/ccda/index.mjs +147 -17
  16. package/dist/ccda/index.mjs.map +1 -1
  17. package/dist/deid/index.cjs +537 -30
  18. package/dist/deid/index.cjs.map +1 -1
  19. package/dist/deid/index.d.cts +2 -1
  20. package/dist/deid/index.d.ts +2 -1
  21. package/dist/deid/index.mjs +537 -30
  22. package/dist/deid/index.mjs.map +1 -1
  23. package/dist/fhir/index.cjs +142 -14
  24. package/dist/fhir/index.cjs.map +1 -1
  25. package/dist/fhir/index.d.cts +4 -1
  26. package/dist/fhir/index.d.ts +4 -1
  27. package/dist/fhir/index.mjs +142 -14
  28. package/dist/fhir/index.mjs.map +1 -1
  29. package/dist/hl7/index.cjs +566 -39
  30. package/dist/hl7/index.cjs.map +1 -1
  31. package/dist/hl7/index.d.cts +416 -116
  32. package/dist/hl7/index.d.ts +416 -116
  33. package/dist/hl7/index.mjs +557 -40
  34. package/dist/hl7/index.mjs.map +1 -1
  35. package/dist/index.cjs +124 -13
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.d.cts +183 -10
  38. package/dist/index.d.ts +183 -10
  39. package/dist/index.mjs +115 -14
  40. package/dist/index.mjs.map +1 -1
  41. package/dist/ncpdp/index.cjs +142 -14
  42. package/dist/ncpdp/index.cjs.map +1 -1
  43. package/dist/ncpdp/index.d.cts +4 -1
  44. package/dist/ncpdp/index.d.ts +4 -1
  45. package/dist/ncpdp/index.mjs +142 -14
  46. package/dist/ncpdp/index.mjs.map +1 -1
  47. package/dist/{quirk-BfObsiWV.d.ts → quirk-CzknuYUo.d.ts} +16 -5
  48. package/dist/{quirk-BCSs1jPt.d.cts → quirk-Q5AxzHSC.d.cts} +16 -5
  49. package/dist/x12/index.cjs +142 -14
  50. package/dist/x12/index.cjs.map +1 -1
  51. package/dist/x12/index.d.cts +4 -1
  52. package/dist/x12/index.d.ts +4 -1
  53. package/dist/x12/index.mjs +142 -14
  54. package/dist/x12/index.mjs.map +1 -1
  55. package/package.json +9 -5
@@ -1,27 +1,224 @@
1
1
  import { Hl7Message, RawField } from '@cosyte/hl7';
2
- import { SyntheticName, SyntheticIdentifier, SyntheticAddress, Rng, Corpus } from '../index.js';
2
+ import { SyntheticIdentifier, SyntheticName, SyntheticAddress, Rng, Corpus } from '../index.js';
3
+ import { AnimalCode } from '../index.js';
3
4
  import { QuirkDescriptor, SynthProfile, QuirkArtifact, QuirkRoundTripResult } from '../index.js';
4
5
 
6
+ /**
7
+ * Shared HL7 v2 building blocks for every message family `@cosyte/synth` generates: the MSH scaffold,
8
+ * the seeded timestamp, and the patient-identity bundle + its `PID` segment. Factored out so `ADT`,
9
+ * `ORU`, `ORM`, `SIU`, and `VXU` all mint identity from the **same** synthetic-safety providers in the
10
+ * **same** draw order, and all emit through `@cosyte/hl7`'s conservative serializer. Nothing here draws a
11
+ * value that is not sourced from `../safe`: the synthetic-by-construction
12
+ * invariant holds by construction for every family.
13
+ *
14
+ * @module
15
+ */
16
+
17
+ /**
18
+ * A seeded HL7 `YYYYMMDDHHMMSS` timestamp (message/event time; recent-year range). Strict HL7 DTM, so
19
+ * `@cosyte/hl7` parses it back with no `TIMESTAMP_FALLBACK_FORMAT` warning.
20
+ *
21
+ * @param rng - The seeded generator.
22
+ * @returns A 14-digit `YYYYMMDDHHMMSS` timestamp string.
23
+ * @example
24
+ * ```ts
25
+ * import { createRng } from "@cosyte/synth";
26
+ * // "20230714…"
27
+ * ```
28
+ */
29
+ declare function seededTimestamp(rng: Rng): string;
30
+ /** The MSH scaffold shared by every generated message: the built message plus its seeded MSH values. */
31
+ interface MessageScaffold {
32
+ /** The `Hl7Message` with a complete MSH: chain `.addSegment(...)` to append the payload. */
33
+ readonly message: Hl7Message;
34
+ /** The seeded `YYYYMMDDHHMMSS` message timestamp (MSH-7), reused for event/observation times. */
35
+ readonly timestamp: string;
36
+ /** The seeded message control id (MSH-10). */
37
+ readonly controlId: string;
38
+ }
39
+ /**
40
+ * Build the MSH scaffold for a message of the given `MSH-9` type through `@cosyte/hl7`'s `buildMessage`,
41
+ * so the delimiters, control id, and header layout are the parser's own conservative emit. Draws the
42
+ * timestamp then the control id from `rng` (a fixed order: the reproducibility contract).
43
+ *
44
+ * @param rng - The seeded generator.
45
+ * @param type - The `MSH-9` message type, e.g. `"ORU^R01"`.
46
+ * @returns The {@link MessageScaffold}.
47
+ * @example
48
+ * ```ts
49
+ * import { createRng } from "@cosyte/synth";
50
+ * // mshScaffold(createRng(1), "ORU^R01").message.addSegment("PID", […]);
51
+ * ```
52
+ */
53
+ declare function mshScaffold(rng: Rng, type: string): MessageScaffold;
54
+ /** A complete synthetic patient identity: every field drawn from `../safe`. */
55
+ interface PatientIdentity {
56
+ /** Name from the shipped fake-name pool. */
57
+ readonly person: SyntheticName;
58
+ /** Medical-record identifier scoped to the synthetic assigning authority. */
59
+ readonly mrn: SyntheticIdentifier;
60
+ /** Date of birth (`YYYYMMDD`) from the seeded generator. */
61
+ readonly dob: string;
62
+ /** Administrative sex. */
63
+ readonly sex: "M" | "F";
64
+ /** Synthetic postal address (reserved non-real ZIP). */
65
+ readonly address: SyntheticAddress;
66
+ /** Reserved `555-01xx` phone number. */
67
+ readonly phone: string;
68
+ /** Never-issued SSN as 9 digits (no dashes), for `PID-19`. */
69
+ readonly ssnDigits: string;
70
+ }
71
+ /**
72
+ * Mint a complete synthetic {@link PatientIdentity}. Every value comes from a synthetic-safety provider,
73
+ * so no code path here can return a real or plausibly-real identifier. The draw order is
74
+ * fixed (name → MRN → DOB → sex → address → phone → SSN) so the same seed yields the same identity.
75
+ *
76
+ * @param rng - The seeded generator.
77
+ * @returns A synthetic {@link PatientIdentity}.
78
+ * @example
79
+ * ```ts
80
+ * import { createRng } from "@cosyte/synth";
81
+ * // const id = patientIdentity(createRng(1)); // id.person, id.mrn, …
82
+ * ```
83
+ */
84
+ declare function patientIdentity(rng: Rng): PatientIdentity;
85
+ /**
86
+ * Lay out a fully-populated `PID` segment from a {@link PatientIdentity} as `addSegment` fields: the
87
+ * PHI-dense segment shared by every family. Components go through {@link componentsField} so the parser
88
+ * lays out the `^` separators (building *through* the parser).
89
+ *
90
+ * @param id - The synthetic identity to render.
91
+ * @returns The `PID` field list for `Hl7Message.addSegment("PID", …)`.
92
+ * @example
93
+ * ```ts
94
+ * // msg.addSegment("PID", pidSegment(patientIdentity(createRng(1))));
95
+ * ```
96
+ */
97
+ declare function pidSegment(id: PatientIdentity): readonly (string | RawField)[];
98
+ /**
99
+ * Who a message is about. `"person"`, the default, is the human patient every generator has always
100
+ * written. `"animal"` writes a veterinary patient instead: see {@link AnimalIdentity}.
101
+ */
102
+ type Hl7Subject = "person" | "animal";
103
+ /** An animal's owner: every value drawn from `../safe`. */
104
+ interface AnimalOwner {
105
+ /** The owner's name, from the shipped fake-name pool. */
106
+ readonly person: SyntheticName;
107
+ /** The owner's synthetic postal address (reserved non-real ZIP), which is also the animal's. */
108
+ readonly address: SyntheticAddress;
109
+ /** The owner's reserved `555-01xx` phone number. */
110
+ readonly phone: string;
111
+ }
112
+ /** A complete synthetic animal patient: every value drawn from `../safe`. */
113
+ interface AnimalIdentity {
114
+ /** The pet's name, from the shipped fake pet-name pool. */
115
+ readonly petName: string;
116
+ /** The record number, scoped to the synthetic assigning authority. */
117
+ readonly record: SyntheticIdentifier;
118
+ /** A 15-digit microchip that begins `999`. */
119
+ readonly microchip: string;
120
+ /** The species, from our own short list. */
121
+ readonly species: AnimalCode;
122
+ /** The breed, one of the species' breeds. */
123
+ readonly breed: AnimalCode;
124
+ /** Birth date (`YYYYMMDD`), 0 to 20 years before the message date. */
125
+ readonly dob: string;
126
+ /** Administrative sex. */
127
+ readonly sex: "M" | "F";
128
+ /** The owner. */
129
+ readonly owner: AnimalOwner;
130
+ }
131
+ /**
132
+ * The identifier type the animal subject writes for a microchip in PID-3 (CX.5): `MCN`, which we
133
+ * use for microchip number. We have not verified it against HL7 table 0203 (identifier type) in any
134
+ * version. Not verified.
135
+ */
136
+ declare const MICROCHIP_IDENTIFIER_TYPE = "MCN";
137
+ /**
138
+ * The owner relationship the animal subject writes in NK1-3: `OWN^Owner^HL70063`. We have not
139
+ * verified that `OWN` is a value of HL7 table 0063 (relationship). Not verified.
140
+ */
141
+ declare const OWNER_RELATIONSHIP: Readonly<{
142
+ code: "OWN";
143
+ text: "Owner";
144
+ system: "HL70063";
145
+ }>;
146
+ /**
147
+ * Mint a complete synthetic {@link AnimalIdentity}. The draw order is fixed (owner name, pet name,
148
+ * record number, microchip, species and breed, birth date, sex, address, phone) so the same seed and
149
+ * date yield the same animal.
150
+ *
151
+ * @param rng - The seeded generator.
152
+ * @param onDate - The message date, `YYYYMMDD` or a longer timestamp: the birth date falls from 0
153
+ * to 20 years before it.
154
+ * @returns A synthetic {@link AnimalIdentity}.
155
+ * @example
156
+ * ```ts
157
+ * import { createRng } from "@cosyte/synth";
158
+ * import { animalIdentity } from "@cosyte/synth/hl7";
159
+ * const pet = animalIdentity(createRng(1), "20250101");
160
+ * pet.species.text; // e.g. "Dog"
161
+ * ```
162
+ */
163
+ declare function animalIdentity(rng: Rng, onDate: string): AnimalIdentity;
164
+ /**
165
+ * Lay out the `PID` segment of an {@link AnimalIdentity}: the record number and the microchip as two
166
+ * PID-3 repetitions, the owner's family name and the pet's name in PID-5, the owner's address and
167
+ * phone, and the species in PID-35 and breed in PID-36. PID-19 (SSN) stays empty.
168
+ *
169
+ * @param id - The synthetic animal to render.
170
+ * @returns The `PID` field list for `Hl7Message.addSegment("PID", …)`.
171
+ * @example
172
+ * ```ts
173
+ * // msg.addSegment("PID", animalPidSegment(animalIdentity(createRng(1), "20250101")));
174
+ * ```
175
+ */
176
+ declare function animalPidSegment(id: AnimalIdentity): readonly (string | RawField)[];
177
+ /**
178
+ * Lay out the owner's `NK1` segment: the owner's name, relationship {@link OWNER_RELATIONSHIP}
179
+ * (`OWN`, not verified against HL7 table 0063), address and phone.
180
+ *
181
+ * @param id - The synthetic animal whose owner to render.
182
+ * @returns The `NK1` field list for `Hl7Message.addSegment("NK1", …)`.
183
+ * @example
184
+ * ```ts
185
+ * // msg.addSegment("NK1", ownerNk1Segment(animalIdentity(createRng(1), "20250101")));
186
+ * ```
187
+ */
188
+ declare function ownerNk1Segment(id: AnimalIdentity): readonly (string | RawField)[];
189
+
5
190
  /**
6
191
  * Spec-clean HL7 v2 `ADT` generation, built **through `@cosyte/hl7`'s `buildMessage`** so MSH
7
192
  * delimiters, segment layout, and escaping are the parser's own conservative emit: spec-clean *by
8
193
  * construction*. Every PHI-bearing field (name, DOB, SSN, MRN,
9
194
  * address, phone) is drawn from the synthetic-safety providers (`../safe`), so no value can be real.
10
195
  *
11
- * `ADT^A01/A04/A08` all require the `PID` (patient) + `PV1` (visit) groups the parser's structure net
12
- * checks for, so a generated message round-trips through `@cosyte/hl7` with **zero warnings**.
196
+ * Every trigger here requires the `EVN`, `PID` (patient) and `PV1` (visit) segments the parser's
197
+ * structure net checks for, so a generated message round-trips through `@cosyte/hl7` with **zero
198
+ * warnings**. The triggers and the structures they share (HL7 v2 chapter 3):
199
+ *
200
+ * - `A01` admit, `A04` register, `A08` update patient information, `A13` cancel discharge: `ADT_A01`.
201
+ * - `A02` transfer a patient: `ADT_A02`. `A03` discharge or end visit: `ADT_A03`.
202
+ * - `A11` cancel admit or visit notification: `ADT_A09`.
203
+ * - `A28` add person or patient information, `A31` update person information: `ADT_A05`.
13
204
  *
14
205
  * @module
15
206
  */
16
207
 
17
- /** The ADT trigger events this generator produces (all require the PID + PV1 groups). */
18
- type AdtTrigger = "A01" | "A04" | "A08";
208
+ /** The ADT trigger events this generator produces (all require the EVN, PID and PV1 segments). */
209
+ type AdtTrigger = "A01" | "A04" | "A08" | "A02" | "A03" | "A11" | "A13" | "A28" | "A31";
19
210
  /** Options for {@link generateAdt}. */
20
211
  interface GenerateAdtOptions {
21
212
  /** The seed: the same seed yields a byte-identical message. Defaults to `0`. */
22
213
  readonly seed?: number;
23
214
  /** The ADT trigger event. Defaults to `"A01"`. */
24
215
  readonly trigger?: AdtTrigger;
216
+ /**
217
+ * Who the message is about. Defaults to `"person"`, whose bytes for a seed are what they always
218
+ * were. `"animal"` writes a veterinary patient: the pet's name in PID-5, a microchip in PID-3, the
219
+ * species in PID-35 and breed in PID-36, and the owner in an `NK1` after the `PID`.
220
+ */
221
+ readonly subject?: Hl7Subject;
25
222
  }
26
223
  /**
27
224
  * Generate a spec-clean `ADT` {@link Hl7Message} through `@cosyte/hl7`. Deterministic in `seed`.
@@ -29,14 +226,19 @@ interface GenerateAdtOptions {
29
226
  * The message carries a complete MSH (seeded control id + timestamp, so the bytes are reproducible),
30
227
  * `EVN`, a fully-populated `PID` (identity from the synthetic providers), and `PV1` (the visit group),
31
228
  * so it parses back through `@cosyte/hl7` with **zero warnings** (proven by {@link ./round-trip}).
229
+ * A trigger added after `A01`, `A04` and `A08` also names its published structure in MSH-9.3 and
230
+ * fills the `PV1` fields its event is about (a transfer's prior location, a discharge's times).
32
231
  *
33
- * @param options - Seed + trigger. See {@link GenerateAdtOptions}.
232
+ * With `subject: "animal"` the patient is an animal and its owner follows the `PID` in an `NK1`.
233
+ *
234
+ * @param options - Seed, trigger and subject. See {@link GenerateAdtOptions}.
34
235
  * @returns A spec-clean `ADT` `Hl7Message`.
35
236
  * @example
36
237
  * ```ts
37
238
  * import { generateAdt } from "@cosyte/synth/hl7";
38
239
  * const msg = generateAdt({ seed: 12345, trigger: "A01" });
39
- * console.log(msg.toString());
240
+ * const wire = msg.toString(); // the whole message, synthetic: assert on it, never log it
241
+ * console.log(wire.split("\r")[0]?.split("|")[8]); // "ADT^A01", the type in MSH-9
40
242
  * ```
41
243
  */
42
244
  declare function generateAdt(options?: GenerateAdtOptions): Hl7Message;
@@ -56,6 +258,12 @@ declare function generateAdt(options?: GenerateAdtOptions): Hl7Message;
56
258
  interface GenerateOruOptions {
57
259
  /** The seed: the same seed yields a byte-identical message. Defaults to `0`. */
58
260
  readonly seed?: number;
261
+ /**
262
+ * Who the result is about. Defaults to `"person"`, whose bytes for a seed are what they always
263
+ * were. `"animal"` writes a veterinary patient: the pet's name in PID-5, a microchip in PID-3, the
264
+ * species in PID-35 and breed in PID-36, and the owner in an `NK1` after the `PID`.
265
+ */
266
+ readonly subject?: Hl7Subject;
59
267
  }
60
268
  /**
61
269
  * Generate a spec-clean `ORU^R01` {@link Hl7Message} through `@cosyte/hl7`. Deterministic in `seed`.
@@ -64,13 +272,16 @@ interface GenerateOruOptions {
64
272
  * rows. The `OBR`/`OBX` result group satisfies the parser's `ORU^R01` structure net, so the message
65
273
  * re-parses with **zero warnings** (proven by {@link ./round-trip}).
66
274
  *
67
- * @param options - Seed. See {@link GenerateOruOptions}.
275
+ * With `subject: "animal"` the patient is an animal and its owner follows the `PID` in an `NK1`.
276
+ *
277
+ * @param options - Seed and subject. See {@link GenerateOruOptions}.
68
278
  * @returns A spec-clean `ORU^R01` `Hl7Message`.
69
279
  * @example
70
280
  * ```ts
71
281
  * import { generateOru } from "@cosyte/synth/hl7";
72
282
  * const msg = generateOru({ seed: 12345 });
73
- * console.log(msg.toString());
283
+ * const wire = msg.toString(); // the whole message, synthetic: assert on it, never log it
284
+ * console.log(wire.split("\r")[0]?.split("|")[8]); // "ORU^R01", the type in MSH-9
74
285
  * ```
75
286
  */
76
287
  declare function generateOru(options?: GenerateOruOptions): Hl7Message;
@@ -103,7 +314,8 @@ interface GenerateOrmOptions {
103
314
  * ```ts
104
315
  * import { generateOrm } from "@cosyte/synth/hl7";
105
316
  * const msg = generateOrm({ seed: 12345 });
106
- * console.log(msg.toString());
317
+ * const wire = msg.toString(); // the whole message, synthetic: assert on it, never log it
318
+ * console.log(wire.split("\r")[0]?.split("|")[8]); // "ORM^O01", the type in MSH-9
107
319
  * ```
108
320
  */
109
321
  declare function generateOrm(options?: GenerateOrmOptions): Hl7Message;
@@ -135,7 +347,8 @@ interface GenerateSiuOptions {
135
347
  * ```ts
136
348
  * import { generateSiu } from "@cosyte/synth/hl7";
137
349
  * const msg = generateSiu({ seed: 12345 });
138
- * console.log(msg.toString());
350
+ * const wire = msg.toString(); // the whole message, synthetic: assert on it, never log it
351
+ * console.log(wire.split("\r")[0]?.split("|")[8]); // "SIU^S12", the type in MSH-9
139
352
  * ```
140
353
  */
141
354
  declare function generateSiu(options?: GenerateSiuOptions): Hl7Message;
@@ -168,11 +381,170 @@ interface GenerateVxuOptions {
168
381
  * ```ts
169
382
  * import { generateVxu } from "@cosyte/synth/hl7";
170
383
  * const msg = generateVxu({ seed: 12345 });
171
- * console.log(msg.toString());
384
+ * const wire = msg.toString(); // the whole message, synthetic: assert on it, never log it
385
+ * console.log(wire.split("\r")[0]?.split("|")[8]); // "VXU^V04", the type in MSH-9
172
386
  * ```
173
387
  */
174
388
  declare function generateVxu(options?: GenerateVxuOptions): Hl7Message;
175
389
 
390
+ /**
391
+ * Spec-clean HL7 v2 `MDM^T02` (original document notification and content) generation, built
392
+ * **through `@cosyte/hl7`'s `buildMessage`**. The published `MDM_T02` structure requires `EVN`, `PID`,
393
+ * `PV1`, `TXA` (the document header) and at least one `OBX` (the document body); this generator emits
394
+ * each of them, so the message round-trips with **zero warnings**. Identity comes from `../safe`; the
395
+ * document body is a fixed set of sentences that say they are synthetic.
396
+ *
397
+ * @module
398
+ */
399
+
400
+ /** Options for {@link generateMdm}. */
401
+ interface GenerateMdmOptions {
402
+ /** The seed: the same seed yields a byte-identical message. Defaults to `0`. */
403
+ readonly seed?: number;
404
+ }
405
+ /**
406
+ * Generate a spec-clean `MDM^T02` {@link Hl7Message} through `@cosyte/hl7`. Deterministic in `seed`.
407
+ *
408
+ * Layout: MSH (`MDM^T02^MDM_T02`), `EVN`, `PID` (synthetic identity), `PV1`, `TXA` (document type
409
+ * from HL7 table 0270, content presentation `TX`, a `SYNTHDOC` unique document number, completion
410
+ * status `DO`, documented) and one to three `OBX` lines of `TX` text, each final (`F`).
411
+ *
412
+ * @param options - Seed. See {@link GenerateMdmOptions}.
413
+ * @returns A spec-clean `MDM^T02` `Hl7Message`.
414
+ * @example
415
+ * ```ts
416
+ * import { generateMdm } from "@cosyte/synth/hl7";
417
+ * const msg = generateMdm({ seed: 12345 });
418
+ * const wire = msg.toString(); // the whole message, synthetic: assert on it, never log it
419
+ * console.log(wire.split("\r")[0]?.split("|")[8]); // "MDM^T02^MDM_T02", the type in MSH-9
420
+ * ```
421
+ */
422
+ declare function generateMdm(options?: GenerateMdmOptions): Hl7Message;
423
+
424
+ /**
425
+ * Spec-clean HL7 v2 `DFT^P03` (post detail financial transactions) generation, built **through
426
+ * `@cosyte/hl7`'s `buildMessage`**. The published `DFT_P03` structure requires `EVN`, `PID` and at
427
+ * least one `FT1` (the financial transaction); this generator emits them and a `PV1`, so the message
428
+ * round-trips with **zero warnings**. Identity comes from `../safe`; the charge code is a local code
429
+ * that says it is synthetic, never a real chargemaster or procedure code.
430
+ *
431
+ * @module
432
+ */
433
+
434
+ /** Options for {@link generateDft}. */
435
+ interface GenerateDftOptions {
436
+ /** The seed: the same seed yields a byte-identical message. Defaults to `0`. */
437
+ readonly seed?: number;
438
+ }
439
+ /**
440
+ * Generate a spec-clean `DFT^P03` {@link Hl7Message} through `@cosyte/hl7`. Deterministic in `seed`.
441
+ *
442
+ * Layout: MSH (`DFT^P03^DFT_P03`), `EVN`, `PID` (synthetic identity), `PV1`, and one `FT1`: a
443
+ * `SYNTHTXN` transaction id, the transaction date, type `CG` (charge, HL7 table 0017), a local
444
+ * `SYNTHCHG` charge code and a quantity of one to three.
445
+ *
446
+ * @param options - Seed. See {@link GenerateDftOptions}.
447
+ * @returns A spec-clean `DFT^P03` `Hl7Message`.
448
+ * @example
449
+ * ```ts
450
+ * import { generateDft } from "@cosyte/synth/hl7";
451
+ * const msg = generateDft({ seed: 12345 });
452
+ * const wire = msg.toString(); // the whole message, synthetic: assert on it, never log it
453
+ * console.log(wire.split("\r")[0]?.split("|")[8]); // "DFT^P03^DFT_P03", the type in MSH-9
454
+ * ```
455
+ */
456
+ declare function generateDft(options?: GenerateDftOptions): Hl7Message;
457
+
458
+ /**
459
+ * Spec-clean HL7 v2 `OML^O21` (laboratory order) generation, built **through `@cosyte/hl7`'s
460
+ * `buildMessage`**. The published `OML_O21` structure requires the common order (`ORC`); this
461
+ * generator emits `PID`, `ORC` and a matching `OBR`, so the message round-trips with **zero
462
+ * warnings**. Identity comes from `../safe`; the ordered service comes from the license-clean example
463
+ * pool, never bundled terminology.
464
+ *
465
+ * @module
466
+ */
467
+
468
+ /** Options for {@link generateOml}. */
469
+ interface GenerateOmlOptions {
470
+ /** The seed: the same seed yields a byte-identical message. Defaults to `0`. */
471
+ readonly seed?: number;
472
+ }
473
+ /**
474
+ * Generate a spec-clean `OML^O21` {@link Hl7Message} through `@cosyte/hl7`. Deterministic in `seed`.
475
+ *
476
+ * Layout: MSH (`OML^O21^OML_O21`), `PID` (synthetic identity), `ORC` (order control `NW`, a new
477
+ * order) and an `OBR` carrying the same placer and filler numbers and a laboratory service.
478
+ *
479
+ * @param options - Seed. See {@link GenerateOmlOptions}.
480
+ * @returns A spec-clean `OML^O21` `Hl7Message`.
481
+ * @example
482
+ * ```ts
483
+ * import { generateOml } from "@cosyte/synth/hl7";
484
+ * const msg = generateOml({ seed: 12345 });
485
+ * const wire = msg.toString(); // the whole message, synthetic: assert on it, never log it
486
+ * console.log(wire.split("\r")[0]?.split("|")[8]); // "OML^O21^OML_O21", the type in MSH-9
487
+ * ```
488
+ */
489
+ declare function generateOml(options?: GenerateOmlOptions): Hl7Message;
490
+
491
+ /**
492
+ * Spec-clean HL7 v2 `ACK` (general acknowledgment) generation, for any message: built **through
493
+ * `@cosyte/hl7`'s `buildMessage`** like every other kind. The published `ACK` structure requires
494
+ * `MSH` and `MSA`; an error acknowledgment adds one `ERR`. The message round-trips with **zero
495
+ * warnings**.
496
+ *
497
+ * `@cosyte/hl7`'s own `buildAck` stamps the current time and a fresh control id, which is right for a
498
+ * live interface and wrong for a fixture. This generator draws both from the seed instead, so the
499
+ * same seed and the same inbound message give the same bytes.
500
+ *
501
+ * @module
502
+ */
503
+
504
+ /**
505
+ * An original-mode acknowledgment code (HL7 table 0008, MSA-1): `AA` application accept, `AE`
506
+ * application error, `AR` application reject.
507
+ */
508
+ type Hl7AckCode = "AA" | "AE" | "AR";
509
+ /** Options for {@link generateAck}. */
510
+ interface GenerateAckOptions {
511
+ /** The seed: the same seed and inbound message yield a byte-identical ACK. Defaults to `0`. */
512
+ readonly seed?: number;
513
+ /**
514
+ * The message being acknowledged. Defaults to the `ADT^A01` {@link generateAdt} makes from the same
515
+ * seed. It must carry an MSH-10 message control id.
516
+ */
517
+ readonly inbound?: Hl7Message;
518
+ /** The acknowledgment code in MSA-1. Defaults to `"AA"`. */
519
+ readonly code?: Hl7AckCode;
520
+ }
521
+ /**
522
+ * Generate a spec-clean `ACK` {@link Hl7Message} answering `inbound`. Deterministic in `seed` and
523
+ * `inbound`.
524
+ *
525
+ * - **MSH**: the inbound receiver (MSH-5, MSH-6) becomes the sender (MSH-3, MSH-4) and the inbound
526
+ * sender the receiver. MSH-7 is one to fifty-nine seconds after the inbound MSH-7, or a seeded time
527
+ * when that is not a full `YYYYMMDDHHMMSS`. MSH-9 is `ACK^<inbound trigger>^ACK`, or `ACK` when
528
+ * the inbound names no trigger. MSH-10 is a seeded `SYNTHACK` control id. MSH-11 is always `T`, test
529
+ * data, whatever the inbound says. MSH-12 echoes the inbound version, `2.5` when it names none.
530
+ * - **MSA**: MSA-1 is `code`, MSA-2 the inbound MSH-10.
531
+ * - **ERR**, for `AE` and `AR` only: ERR-3 is condition `207`, application internal error (HL7 table
532
+ * 0357), and ERR-4 severity `E`, error.
533
+ *
534
+ * @param options - Seed, inbound message and code. See {@link GenerateAckOptions}.
535
+ * @returns A spec-clean `ACK` `Hl7Message`.
536
+ * @throws SynthError `SYNTH_ACK_UNCORRELATED` when the inbound message has no MSH-10, and
537
+ * `SYNTH_UNSUPPORTED_KIND` when `code` is not `AA`, `AE` or `AR`.
538
+ * @example
539
+ * ```ts
540
+ * import { generateAck, generateOru } from "@cosyte/synth/hl7";
541
+ * const ack = generateAck({ seed: 7, inbound: generateOru({ seed: 7 }) });
542
+ * const [msh, msa] = ack.toString().split("\r"); // synthetic segments: assert on them, never log them
543
+ * console.log(msh?.split("|")[8], msa?.split("|")[1]); // "ACK^R01^ACK" "AA", the type and the code
544
+ * ```
545
+ */
546
+ declare function generateAck(options?: GenerateAckOptions): Hl7Message;
547
+
176
548
  /**
177
549
  * The **round-trip-through-the-parser harness**: the headline gate for the synthetic-fixture
178
550
  * generator. A generated artifact is "spec-clean" only if `@cosyte/hl7`, not
@@ -236,99 +608,6 @@ declare function roundTrip(message: Hl7Message): RoundTripResult;
236
608
  */
237
609
  declare function componentsField(components: readonly string[]): RawField;
238
610
 
239
- /**
240
- * Shared HL7 v2 building blocks for every message family `@cosyte/synth` generates: the MSH scaffold,
241
- * the seeded timestamp, and the patient-identity bundle + its `PID` segment. Factored out so `ADT`,
242
- * `ORU`, `ORM`, `SIU`, and `VXU` all mint identity from the **same** synthetic-safety providers in the
243
- * **same** draw order, and all emit through `@cosyte/hl7`'s conservative serializer. Nothing here draws a
244
- * value that is not sourced from `../safe`: the synthetic-by-construction
245
- * invariant holds by construction for every family.
246
- *
247
- * @module
248
- */
249
-
250
- /**
251
- * A seeded HL7 `YYYYMMDDHHMMSS` timestamp (message/event time; recent-year range). Strict HL7 DTM, so
252
- * `@cosyte/hl7` parses it back with no `TIMESTAMP_FALLBACK_FORMAT` warning.
253
- *
254
- * @param rng - The seeded generator.
255
- * @returns A 14-digit `YYYYMMDDHHMMSS` timestamp string.
256
- * @example
257
- * ```ts
258
- * import { createRng } from "@cosyte/synth";
259
- * // "20230714…"
260
- * ```
261
- */
262
- declare function seededTimestamp(rng: Rng): string;
263
- /** The MSH scaffold shared by every generated message: the built message plus its seeded MSH values. */
264
- interface MessageScaffold {
265
- /** The `Hl7Message` with a complete MSH: chain `.addSegment(...)` to append the payload. */
266
- readonly message: Hl7Message;
267
- /** The seeded `YYYYMMDDHHMMSS` message timestamp (MSH-7), reused for event/observation times. */
268
- readonly timestamp: string;
269
- /** The seeded message control id (MSH-10). */
270
- readonly controlId: string;
271
- }
272
- /**
273
- * Build the MSH scaffold for a message of the given `MSH-9` type through `@cosyte/hl7`'s `buildMessage`,
274
- * so the delimiters, control id, and header layout are the parser's own conservative emit. Draws the
275
- * timestamp then the control id from `rng` (a fixed order: the reproducibility contract).
276
- *
277
- * @param rng - The seeded generator.
278
- * @param type - The `MSH-9` message type, e.g. `"ORU^R01"`.
279
- * @returns The {@link MessageScaffold}.
280
- * @example
281
- * ```ts
282
- * import { createRng } from "@cosyte/synth";
283
- * // mshScaffold(createRng(1), "ORU^R01").message.addSegment("PID", […]);
284
- * ```
285
- */
286
- declare function mshScaffold(rng: Rng, type: string): MessageScaffold;
287
- /** A complete synthetic patient identity: every field drawn from `../safe`. */
288
- interface PatientIdentity {
289
- /** Name from the shipped fake-name pool. */
290
- readonly person: SyntheticName;
291
- /** Medical-record identifier scoped to the synthetic assigning authority. */
292
- readonly mrn: SyntheticIdentifier;
293
- /** Date of birth (`YYYYMMDD`) from the seeded generator. */
294
- readonly dob: string;
295
- /** Administrative sex. */
296
- readonly sex: "M" | "F";
297
- /** Synthetic postal address (reserved non-real ZIP). */
298
- readonly address: SyntheticAddress;
299
- /** Reserved `555-01xx` phone number. */
300
- readonly phone: string;
301
- /** Never-issued SSN as 9 digits (no dashes), for `PID-19`. */
302
- readonly ssnDigits: string;
303
- }
304
- /**
305
- * Mint a complete synthetic {@link PatientIdentity}. Every value comes from a synthetic-safety provider,
306
- * so no code path here can return a real or plausibly-real identifier. The draw order is
307
- * fixed (name → MRN → DOB → sex → address → phone → SSN) so the same seed yields the same identity.
308
- *
309
- * @param rng - The seeded generator.
310
- * @returns A synthetic {@link PatientIdentity}.
311
- * @example
312
- * ```ts
313
- * import { createRng } from "@cosyte/synth";
314
- * // const id = patientIdentity(createRng(1)); // id.person, id.mrn, …
315
- * ```
316
- */
317
- declare function patientIdentity(rng: Rng): PatientIdentity;
318
- /**
319
- * Lay out a fully-populated `PID` segment from a {@link PatientIdentity} as `addSegment` fields: the
320
- * PHI-dense segment shared by every family. Components go through {@link componentsField} so the parser
321
- * lays out the `^` separators (building *through* the parser).
322
- *
323
- * @param id - The synthetic identity to render.
324
- * @returns The `PID` field list for `Hl7Message.addSegment("PID", …)`.
325
- * @example
326
- * ```ts
327
- * // msg.addSegment("PID", pidSegment(patientIdentity(createRng(1))));
328
- * ```
329
- */
330
- declare function pidSegment(id: PatientIdentity): readonly (string | RawField)[];
331
-
332
611
  /**
333
612
  * A tiny, curated, **license-clean** pool of example codes used to fill coded fields in generated HL7
334
613
  * messages (`OBR`/`OBX` observations, `ORC`/`OBR` orders, `RXA` vaccines). These are **public code
@@ -445,9 +724,15 @@ interface Hl7QuirkCorpusOptions {
445
724
  readonly seed: number;
446
725
  /** How many quirk artifacts to generate. Defaults to the number of quirks. */
447
726
  readonly count?: number;
448
- /** The quirk names to cycle through. Defaults to every HL7 quirk. Validated; unsupported ⇒ fatal. */
727
+ /**
728
+ * The quirk names to cycle through. Defaults to every HL7 quirk. Validated; unsupported ⇒ fatal.
729
+ * An empty list, or a `profile` whose `quirks` is an empty list, throws `SYNTH_EMPTY_POOL`.
730
+ */
449
731
  readonly quirks?: readonly Hl7QuirkName[];
450
- /** A {@link SynthProfile} whose `quirks` drive the corpus (validated). Takes precedence over `quirks`. */
732
+ /**
733
+ * A {@link SynthProfile} whose `quirks` drive the corpus (validated). Its `quirks`, when set, take
734
+ * precedence over `quirks`; a profile that leaves `quirks` out leaves the selection to `quirks`.
735
+ */
451
736
  readonly profile?: SynthProfile;
452
737
  /** The base message family each quirk is injected into. Defaults to `"ORU^R01"`. */
453
738
  readonly kind?: Hl7QuirkKind;
@@ -486,17 +771,30 @@ declare const hl7QuirkProfile: SynthProfile;
486
771
  * never loads a parser.
487
772
  * `@cosyte/hl7` is an **optional peer dependency**, present only for this subpath.
488
773
  *
489
- * The HL7 v2 message set is complete: `ADT` (A01/A04/A08), `ORU^R01`, `ORM^O01`, `SIU^S12`, and
490
- * `VXU^V04`, each built through `@cosyte/hl7`'s `buildMessage` and round-tripping with zero warnings.
774
+ * The HL7 v2 message set: `ADT` (A01, A02, A03, A04, A08, A11, A13, A28, A31), `ORU^R01`, `ORM^O01`,
775
+ * `SIU^S12`, `VXU^V04`, `MDM^T02`, `DFT^P03`, `OML^O21`, and an `ACK` for any of them, each built
776
+ * through `@cosyte/hl7`'s `buildMessage`, stamped HL7 v2.5, and round-tripping with zero warnings.
491
777
  *
492
778
  * @module
493
779
  */
494
780
 
495
781
  /**
496
782
  * Every HL7 v2 message kind this subpath generates: the `MSH-9` label used as the corpus `kind`. `ADT`
497
- * carries its trigger; the other families have a single generated trigger each.
783
+ * carries its trigger; the other families have a single generated trigger each. `ACK` acknowledges
784
+ * an `ADT^A01` generated from the same seed (see {@link generateAck} to acknowledge any message).
785
+ */
786
+ type Hl7MessageKind = "ADT^A01" | "ADT^A04" | "ADT^A08" | "ORU^R01" | "ORM^O01" | "SIU^S12" | "VXU^V04" | "ACK" | "ADT^A02" | "ADT^A03" | "ADT^A11" | "ADT^A13" | "ADT^A28" | "ADT^A31" | "MDM^T02" | "DFT^P03" | "OML^O21";
787
+ /**
788
+ * Every kind {@link generateHl7} and {@link hl7Corpus} accept, in a fixed order: the first seven
789
+ * kinds, then each kind added since. Pass it as a corpus `mix` to cycle through all of them.
790
+ *
791
+ * @example
792
+ * ```ts
793
+ * import { HL7_MESSAGE_KINDS, hl7Corpus } from "@cosyte/synth/hl7";
794
+ * hl7Corpus({ seed: 1, count: HL7_MESSAGE_KINDS.length, mix: HL7_MESSAGE_KINDS });
795
+ * ```
498
796
  */
499
- type Hl7MessageKind = "ADT^A01" | "ADT^A04" | "ADT^A08" | "ORU^R01" | "ORM^O01" | "SIU^S12" | "VXU^V04";
797
+ declare const HL7_MESSAGE_KINDS: readonly Hl7MessageKind[];
500
798
  /**
501
799
  * Generate one message of the given {@link Hl7MessageKind} from a seed, dispatching to the right
502
800
  * family generator. Every kind builds through `@cosyte/hl7` and is deterministic in `seed`.
@@ -518,13 +816,15 @@ interface Hl7CorpusOptions {
518
816
  /** How many messages to generate. Defaults to `1`. */
519
817
  readonly count?: number;
520
818
  /**
521
- * The message kinds to cycle through. Defaults to one of every family
522
- * (`ADT^A01/A04/A08`, `ORU^R01`, `ORM^O01`, `SIU^S12`, `VXU^V04`).
819
+ * The message kinds to cycle through, any of {@link HL7_MESSAGE_KINDS}. Defaults to one each of
820
+ * the first seven kinds (`ADT^A01/A04/A08`, `ORU^R01`, `ORM^O01`, `SIU^S12`, `VXU^V04`), so a seed's
821
+ * default corpus is unchanged as kinds are added. An empty list throws `SYNTH_EMPTY_POOL`.
523
822
  */
524
823
  readonly mix?: readonly Hl7MessageKind[];
525
824
  /**
526
825
  * ADT-only convenience: the triggers to cycle through, kept for back-compat. When
527
- * supplied it takes precedence over `mix` and restricts the corpus to `ADT` messages.
826
+ * supplied it takes precedence over `mix` and restricts the corpus to `ADT` messages. An empty
827
+ * list throws `SYNTH_EMPTY_POOL`.
528
828
  */
529
829
  readonly triggers?: readonly AdtTrigger[];
530
830
  /**
@@ -551,5 +851,5 @@ interface Hl7CorpusOptions {
551
851
  */
552
852
  declare function hl7Corpus(options: Hl7CorpusOptions): Corpus;
553
853
 
554
- export { EXAMPLE_LAB_OBSERVATIONS, EXAMPLE_ORDER_SERVICES, EXAMPLE_VACCINES, HL7_QUIRKS, componentsField, generateAdt, generateHl7, generateHl7Quirk, generateOrm, generateOru, generateSiu, generateVxu, hl7Corpus, hl7QuirkCorpus, hl7QuirkProfile, hl7QuirkRoundTrip, mshScaffold, patientIdentity, pidSegment, roundTrip, seededTimestamp };
555
- export type { AdtTrigger, ExampleCode, GenerateAdtOptions, GenerateHl7QuirkOptions, GenerateOrmOptions, GenerateOruOptions, GenerateSiuOptions, GenerateVxuOptions, Hl7CorpusOptions, Hl7MessageKind, Hl7QuirkCorpusOptions, Hl7QuirkKind, Hl7QuirkName, MessageScaffold, PatientIdentity, RoundTripResult };
854
+ export { EXAMPLE_LAB_OBSERVATIONS, EXAMPLE_ORDER_SERVICES, EXAMPLE_VACCINES, HL7_MESSAGE_KINDS, HL7_QUIRKS, MICROCHIP_IDENTIFIER_TYPE, OWNER_RELATIONSHIP, animalIdentity, animalPidSegment, componentsField, generateAck, generateAdt, generateDft, generateHl7, generateHl7Quirk, generateMdm, generateOml, generateOrm, generateOru, generateSiu, generateVxu, hl7Corpus, hl7QuirkCorpus, hl7QuirkProfile, hl7QuirkRoundTrip, mshScaffold, ownerNk1Segment, patientIdentity, pidSegment, roundTrip, seededTimestamp };
855
+ export type { AdtTrigger, AnimalIdentity, AnimalOwner, ExampleCode, GenerateAckOptions, GenerateAdtOptions, GenerateDftOptions, GenerateHl7QuirkOptions, GenerateMdmOptions, GenerateOmlOptions, GenerateOrmOptions, GenerateOruOptions, GenerateSiuOptions, GenerateVxuOptions, Hl7AckCode, Hl7CorpusOptions, Hl7MessageKind, Hl7QuirkCorpusOptions, Hl7QuirkKind, Hl7QuirkName, Hl7Subject, MessageScaffold, PatientIdentity, RoundTripResult };