@cosyte/synth 0.1.8 → 0.1.10

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 +37 -0
  2. package/README.md +28 -17
  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 +150 -15
  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 +150 -15
  10. package/dist/astm/index.mjs.map +1 -1
  11. package/dist/ccda/index.cjs +150 -15
  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 +150 -15
  16. package/dist/ccda/index.mjs.map +1 -1
  17. package/dist/deid/index.cjs +540 -28
  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 +540 -28
  22. package/dist/deid/index.mjs.map +1 -1
  23. package/dist/fhir/index.cjs +145 -12
  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 +145 -12
  28. package/dist/fhir/index.mjs.map +1 -1
  29. package/dist/hl7/index.cjs +569 -37
  30. package/dist/hl7/index.cjs.map +1 -1
  31. package/dist/hl7/index.d.cts +402 -111
  32. package/dist/hl7/index.d.ts +402 -111
  33. package/dist/hl7/index.mjs +560 -38
  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 +145 -12
  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 +145 -12
  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 +145 -12
  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 +145 -12
  54. package/dist/x12/index.mjs.map +1 -1
  55. package/package.json +17 -6
@@ -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,8 +226,12 @@ 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
@@ -56,6 +257,12 @@ declare function generateAdt(options?: GenerateAdtOptions): Hl7Message;
56
257
  interface GenerateOruOptions {
57
258
  /** The seed: the same seed yields a byte-identical message. Defaults to `0`. */
58
259
  readonly seed?: number;
260
+ /**
261
+ * Who the result is about. Defaults to `"person"`, whose bytes for a seed are what they always
262
+ * were. `"animal"` writes a veterinary patient: the pet's name in PID-5, a microchip in PID-3, the
263
+ * species in PID-35 and breed in PID-36, and the owner in an `NK1` after the `PID`.
264
+ */
265
+ readonly subject?: Hl7Subject;
59
266
  }
60
267
  /**
61
268
  * Generate a spec-clean `ORU^R01` {@link Hl7Message} through `@cosyte/hl7`. Deterministic in `seed`.
@@ -64,7 +271,9 @@ interface GenerateOruOptions {
64
271
  * rows. The `OBR`/`OBX` result group satisfies the parser's `ORU^R01` structure net, so the message
65
272
  * re-parses with **zero warnings** (proven by {@link ./round-trip}).
66
273
  *
67
- * @param options - Seed. See {@link GenerateOruOptions}.
274
+ * With `subject: "animal"` the patient is an animal and its owner follows the `PID` in an `NK1`.
275
+ *
276
+ * @param options - Seed and subject. See {@link GenerateOruOptions}.
68
277
  * @returns A spec-clean `ORU^R01` `Hl7Message`.
69
278
  * @example
70
279
  * ```ts
@@ -173,6 +382,160 @@ interface GenerateVxuOptions {
173
382
  */
174
383
  declare function generateVxu(options?: GenerateVxuOptions): Hl7Message;
175
384
 
385
+ /**
386
+ * Spec-clean HL7 v2 `MDM^T02` (original document notification and content) generation, built
387
+ * **through `@cosyte/hl7`'s `buildMessage`**. The published `MDM_T02` structure requires `EVN`, `PID`,
388
+ * `PV1`, `TXA` (the document header) and at least one `OBX` (the document body); this generator emits
389
+ * each of them, so the message round-trips with **zero warnings**. Identity comes from `../safe`; the
390
+ * document body is a fixed set of sentences that say they are synthetic.
391
+ *
392
+ * @module
393
+ */
394
+
395
+ /** Options for {@link generateMdm}. */
396
+ interface GenerateMdmOptions {
397
+ /** The seed: the same seed yields a byte-identical message. Defaults to `0`. */
398
+ readonly seed?: number;
399
+ }
400
+ /**
401
+ * Generate a spec-clean `MDM^T02` {@link Hl7Message} through `@cosyte/hl7`. Deterministic in `seed`.
402
+ *
403
+ * Layout: MSH (`MDM^T02^MDM_T02`), `EVN`, `PID` (synthetic identity), `PV1`, `TXA` (document type
404
+ * from HL7 table 0270, content presentation `TX`, a `SYNTHDOC` unique document number, completion
405
+ * status `DO`, documented) and one to three `OBX` lines of `TX` text, each final (`F`).
406
+ *
407
+ * @param options - Seed. See {@link GenerateMdmOptions}.
408
+ * @returns A spec-clean `MDM^T02` `Hl7Message`.
409
+ * @example
410
+ * ```ts
411
+ * import { generateMdm } from "@cosyte/synth/hl7";
412
+ * const msg = generateMdm({ seed: 12345 });
413
+ * console.log(msg.toString());
414
+ * ```
415
+ */
416
+ declare function generateMdm(options?: GenerateMdmOptions): Hl7Message;
417
+
418
+ /**
419
+ * Spec-clean HL7 v2 `DFT^P03` (post detail financial transactions) generation, built **through
420
+ * `@cosyte/hl7`'s `buildMessage`**. The published `DFT_P03` structure requires `EVN`, `PID` and at
421
+ * least one `FT1` (the financial transaction); this generator emits them and a `PV1`, so the message
422
+ * round-trips with **zero warnings**. Identity comes from `../safe`; the charge code is a local code
423
+ * that says it is synthetic, never a real chargemaster or procedure code.
424
+ *
425
+ * @module
426
+ */
427
+
428
+ /** Options for {@link generateDft}. */
429
+ interface GenerateDftOptions {
430
+ /** The seed: the same seed yields a byte-identical message. Defaults to `0`. */
431
+ readonly seed?: number;
432
+ }
433
+ /**
434
+ * Generate a spec-clean `DFT^P03` {@link Hl7Message} through `@cosyte/hl7`. Deterministic in `seed`.
435
+ *
436
+ * Layout: MSH (`DFT^P03^DFT_P03`), `EVN`, `PID` (synthetic identity), `PV1`, and one `FT1`: a
437
+ * `SYNTHTXN` transaction id, the transaction date, type `CG` (charge, HL7 table 0017), a local
438
+ * `SYNTHCHG` charge code and a quantity of one to three.
439
+ *
440
+ * @param options - Seed. See {@link GenerateDftOptions}.
441
+ * @returns A spec-clean `DFT^P03` `Hl7Message`.
442
+ * @example
443
+ * ```ts
444
+ * import { generateDft } from "@cosyte/synth/hl7";
445
+ * const msg = generateDft({ seed: 12345 });
446
+ * console.log(msg.toString());
447
+ * ```
448
+ */
449
+ declare function generateDft(options?: GenerateDftOptions): Hl7Message;
450
+
451
+ /**
452
+ * Spec-clean HL7 v2 `OML^O21` (laboratory order) generation, built **through `@cosyte/hl7`'s
453
+ * `buildMessage`**. The published `OML_O21` structure requires the common order (`ORC`); this
454
+ * generator emits `PID`, `ORC` and a matching `OBR`, so the message round-trips with **zero
455
+ * warnings**. Identity comes from `../safe`; the ordered service comes from the license-clean example
456
+ * pool, never bundled terminology.
457
+ *
458
+ * @module
459
+ */
460
+
461
+ /** Options for {@link generateOml}. */
462
+ interface GenerateOmlOptions {
463
+ /** The seed: the same seed yields a byte-identical message. Defaults to `0`. */
464
+ readonly seed?: number;
465
+ }
466
+ /**
467
+ * Generate a spec-clean `OML^O21` {@link Hl7Message} through `@cosyte/hl7`. Deterministic in `seed`.
468
+ *
469
+ * Layout: MSH (`OML^O21^OML_O21`), `PID` (synthetic identity), `ORC` (order control `NW`, a new
470
+ * order) and an `OBR` carrying the same placer and filler numbers and a laboratory service.
471
+ *
472
+ * @param options - Seed. See {@link GenerateOmlOptions}.
473
+ * @returns A spec-clean `OML^O21` `Hl7Message`.
474
+ * @example
475
+ * ```ts
476
+ * import { generateOml } from "@cosyte/synth/hl7";
477
+ * const msg = generateOml({ seed: 12345 });
478
+ * console.log(msg.toString());
479
+ * ```
480
+ */
481
+ declare function generateOml(options?: GenerateOmlOptions): Hl7Message;
482
+
483
+ /**
484
+ * Spec-clean HL7 v2 `ACK` (general acknowledgment) generation, for any message: built **through
485
+ * `@cosyte/hl7`'s `buildMessage`** like every other kind. The published `ACK` structure requires
486
+ * `MSH` and `MSA`; an error acknowledgment adds one `ERR`. The message round-trips with **zero
487
+ * warnings**.
488
+ *
489
+ * `@cosyte/hl7`'s own `buildAck` stamps the current time and a fresh control id, which is right for a
490
+ * live interface and wrong for a fixture. This generator draws both from the seed instead, so the
491
+ * same seed and the same inbound message give the same bytes.
492
+ *
493
+ * @module
494
+ */
495
+
496
+ /**
497
+ * An original-mode acknowledgment code (HL7 table 0008, MSA-1): `AA` application accept, `AE`
498
+ * application error, `AR` application reject.
499
+ */
500
+ type Hl7AckCode = "AA" | "AE" | "AR";
501
+ /** Options for {@link generateAck}. */
502
+ interface GenerateAckOptions {
503
+ /** The seed: the same seed and inbound message yield a byte-identical ACK. Defaults to `0`. */
504
+ readonly seed?: number;
505
+ /**
506
+ * The message being acknowledged. Defaults to the `ADT^A01` {@link generateAdt} makes from the same
507
+ * seed. It must carry an MSH-10 message control id.
508
+ */
509
+ readonly inbound?: Hl7Message;
510
+ /** The acknowledgment code in MSA-1. Defaults to `"AA"`. */
511
+ readonly code?: Hl7AckCode;
512
+ }
513
+ /**
514
+ * Generate a spec-clean `ACK` {@link Hl7Message} answering `inbound`. Deterministic in `seed` and
515
+ * `inbound`.
516
+ *
517
+ * - **MSH**: the inbound receiver (MSH-5, MSH-6) becomes the sender (MSH-3, MSH-4) and the inbound
518
+ * sender the receiver. MSH-7 is one to fifty-nine seconds after the inbound MSH-7, or a seeded time
519
+ * when that is not a full `YYYYMMDDHHMMSS`. MSH-9 is `ACK^<inbound trigger>^ACK`, or `ACK` when
520
+ * the inbound names no trigger. MSH-10 is a seeded `SYNTHACK` control id. MSH-11 is always `T`, test
521
+ * data, whatever the inbound says. MSH-12 echoes the inbound version, `2.5` when it names none.
522
+ * - **MSA**: MSA-1 is `code`, MSA-2 the inbound MSH-10.
523
+ * - **ERR**, for `AE` and `AR` only: ERR-3 is condition `207`, application internal error (HL7 table
524
+ * 0357), and ERR-4 severity `E`, error.
525
+ *
526
+ * @param options - Seed, inbound message and code. See {@link GenerateAckOptions}.
527
+ * @returns A spec-clean `ACK` `Hl7Message`.
528
+ * @throws SynthError `SYNTH_ACK_UNCORRELATED` when the inbound message has no MSH-10, and
529
+ * `SYNTH_UNSUPPORTED_KIND` when `code` is not `AA`, `AE` or `AR`.
530
+ * @example
531
+ * ```ts
532
+ * import { generateAck, generateOru } from "@cosyte/synth/hl7";
533
+ * const ack = generateAck({ seed: 7, inbound: generateOru({ seed: 7 }) });
534
+ * console.log(ack.toString()); // MSH|...|ACK^R01^ACK|SYNTHACK...|T|2.5 then MSA|AA|SYNTH...
535
+ * ```
536
+ */
537
+ declare function generateAck(options?: GenerateAckOptions): Hl7Message;
538
+
176
539
  /**
177
540
  * The **round-trip-through-the-parser harness**: the headline gate for the synthetic-fixture
178
541
  * generator. A generated artifact is "spec-clean" only if `@cosyte/hl7`, not
@@ -236,99 +599,6 @@ declare function roundTrip(message: Hl7Message): RoundTripResult;
236
599
  */
237
600
  declare function componentsField(components: readonly string[]): RawField;
238
601
 
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
602
  /**
333
603
  * A tiny, curated, **license-clean** pool of example codes used to fill coded fields in generated HL7
334
604
  * messages (`OBR`/`OBX` observations, `ORC`/`OBR` orders, `RXA` vaccines). These are **public code
@@ -445,9 +715,15 @@ interface Hl7QuirkCorpusOptions {
445
715
  readonly seed: number;
446
716
  /** How many quirk artifacts to generate. Defaults to the number of quirks. */
447
717
  readonly count?: number;
448
- /** The quirk names to cycle through. Defaults to every HL7 quirk. Validated; unsupported ⇒ fatal. */
718
+ /**
719
+ * The quirk names to cycle through. Defaults to every HL7 quirk. Validated; unsupported ⇒ fatal.
720
+ * An empty list, or a `profile` whose `quirks` is an empty list, throws `SYNTH_EMPTY_POOL`.
721
+ */
449
722
  readonly quirks?: readonly Hl7QuirkName[];
450
- /** A {@link SynthProfile} whose `quirks` drive the corpus (validated). Takes precedence over `quirks`. */
723
+ /**
724
+ * A {@link SynthProfile} whose `quirks` drive the corpus (validated). Its `quirks`, when set, take
725
+ * precedence over `quirks`; a profile that leaves `quirks` out leaves the selection to `quirks`.
726
+ */
451
727
  readonly profile?: SynthProfile;
452
728
  /** The base message family each quirk is injected into. Defaults to `"ORU^R01"`. */
453
729
  readonly kind?: Hl7QuirkKind;
@@ -486,17 +762,30 @@ declare const hl7QuirkProfile: SynthProfile;
486
762
  * never loads a parser.
487
763
  * `@cosyte/hl7` is an **optional peer dependency**, present only for this subpath.
488
764
  *
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.
765
+ * The HL7 v2 message set: `ADT` (A01, A02, A03, A04, A08, A11, A13, A28, A31), `ORU^R01`, `ORM^O01`,
766
+ * `SIU^S12`, `VXU^V04`, `MDM^T02`, `DFT^P03`, `OML^O21`, and an `ACK` for any of them, each built
767
+ * through `@cosyte/hl7`'s `buildMessage`, stamped HL7 v2.5, and round-tripping with zero warnings.
491
768
  *
492
769
  * @module
493
770
  */
494
771
 
495
772
  /**
496
773
  * 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.
774
+ * carries its trigger; the other families have a single generated trigger each. `ACK` acknowledges
775
+ * an `ADT^A01` generated from the same seed (see {@link generateAck} to acknowledge any message).
776
+ */
777
+ 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";
778
+ /**
779
+ * Every kind {@link generateHl7} and {@link hl7Corpus} accept, in a fixed order: the first seven
780
+ * kinds, then each kind added since. Pass it as a corpus `mix` to cycle through all of them.
781
+ *
782
+ * @example
783
+ * ```ts
784
+ * import { HL7_MESSAGE_KINDS, hl7Corpus } from "@cosyte/synth/hl7";
785
+ * hl7Corpus({ seed: 1, count: HL7_MESSAGE_KINDS.length, mix: HL7_MESSAGE_KINDS });
786
+ * ```
498
787
  */
499
- type Hl7MessageKind = "ADT^A01" | "ADT^A04" | "ADT^A08" | "ORU^R01" | "ORM^O01" | "SIU^S12" | "VXU^V04";
788
+ declare const HL7_MESSAGE_KINDS: readonly Hl7MessageKind[];
500
789
  /**
501
790
  * Generate one message of the given {@link Hl7MessageKind} from a seed, dispatching to the right
502
791
  * family generator. Every kind builds through `@cosyte/hl7` and is deterministic in `seed`.
@@ -518,13 +807,15 @@ interface Hl7CorpusOptions {
518
807
  /** How many messages to generate. Defaults to `1`. */
519
808
  readonly count?: number;
520
809
  /**
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`).
810
+ * The message kinds to cycle through, any of {@link HL7_MESSAGE_KINDS}. Defaults to one each of
811
+ * the first seven kinds (`ADT^A01/A04/A08`, `ORU^R01`, `ORM^O01`, `SIU^S12`, `VXU^V04`), so a seed's
812
+ * default corpus is unchanged as kinds are added. An empty list throws `SYNTH_EMPTY_POOL`.
523
813
  */
524
814
  readonly mix?: readonly Hl7MessageKind[];
525
815
  /**
526
816
  * 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.
817
+ * supplied it takes precedence over `mix` and restricts the corpus to `ADT` messages. An empty
818
+ * list throws `SYNTH_EMPTY_POOL`.
528
819
  */
529
820
  readonly triggers?: readonly AdtTrigger[];
530
821
  /**
@@ -551,5 +842,5 @@ interface Hl7CorpusOptions {
551
842
  */
552
843
  declare function hl7Corpus(options: Hl7CorpusOptions): Corpus;
553
844
 
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 };
845
+ 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 };
846
+ 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 };