@cosyte/synth 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +414 -0
  2. package/LICENSE +21 -0
  3. package/README.md +325 -0
  4. package/dist/astm/index.cjs +847 -0
  5. package/dist/astm/index.cjs.map +1 -0
  6. package/dist/astm/index.d.cts +418 -0
  7. package/dist/astm/index.d.ts +418 -0
  8. package/dist/astm/index.mjs +828 -0
  9. package/dist/astm/index.mjs.map +1 -0
  10. package/dist/ccda/index.cjs +1103 -0
  11. package/dist/ccda/index.cjs.map +1 -0
  12. package/dist/ccda/index.d.cts +380 -0
  13. package/dist/ccda/index.d.ts +380 -0
  14. package/dist/ccda/index.mjs +1077 -0
  15. package/dist/ccda/index.mjs.map +1 -0
  16. package/dist/deid/index.cjs +2809 -0
  17. package/dist/deid/index.cjs.map +1 -0
  18. package/dist/deid/index.d.cts +464 -0
  19. package/dist/deid/index.d.ts +464 -0
  20. package/dist/deid/index.mjs +2793 -0
  21. package/dist/deid/index.mjs.map +1 -0
  22. package/dist/example-codes-DeXcnCSK.d.cts +105 -0
  23. package/dist/example-codes-DeXcnCSK.d.ts +105 -0
  24. package/dist/fhir/index.cjs +1429 -0
  25. package/dist/fhir/index.cjs.map +1 -0
  26. package/dist/fhir/index.d.cts +772 -0
  27. package/dist/fhir/index.d.ts +772 -0
  28. package/dist/fhir/index.mjs +1384 -0
  29. package/dist/fhir/index.mjs.map +1 -0
  30. package/dist/hl7/index.cjs +1012 -0
  31. package/dist/hl7/index.cjs.map +1 -0
  32. package/dist/hl7/index.d.cts +548 -0
  33. package/dist/hl7/index.d.ts +548 -0
  34. package/dist/hl7/index.mjs +990 -0
  35. package/dist/hl7/index.mjs.map +1 -0
  36. package/dist/index.cjs +535 -0
  37. package/dist/index.cjs.map +1 -0
  38. package/dist/index.d.cts +407 -0
  39. package/dist/index.d.ts +407 -0
  40. package/dist/index.mjs +488 -0
  41. package/dist/index.mjs.map +1 -0
  42. package/dist/ncpdp/index.cjs +714 -0
  43. package/dist/ncpdp/index.cjs.map +1 -0
  44. package/dist/ncpdp/index.d.cts +432 -0
  45. package/dist/ncpdp/index.d.ts +432 -0
  46. package/dist/ncpdp/index.mjs +695 -0
  47. package/dist/ncpdp/index.mjs.map +1 -0
  48. package/dist/providers-OLz3zAc-.d.cts +343 -0
  49. package/dist/providers-OLz3zAc-.d.ts +343 -0
  50. package/dist/quirk-DmkgoZdh.d.cts +239 -0
  51. package/dist/quirk-JLyO1Ncj.d.ts +239 -0
  52. package/dist/x12/index.cjs +920 -0
  53. package/dist/x12/index.cjs.map +1 -0
  54. package/dist/x12/index.d.cts +484 -0
  55. package/dist/x12/index.d.ts +484 -0
  56. package/dist/x12/index.mjs +892 -0
  57. package/dist/x12/index.mjs.map +1 -0
  58. package/package.json +210 -0
@@ -0,0 +1,2809 @@
1
+ 'use strict';
2
+
3
+ var hl7 = require('@cosyte/deid/hl7');
4
+ var fhir$1 = require('@cosyte/deid/fhir');
5
+ var x12$1 = require('@cosyte/deid/x12');
6
+ var ncpdp = require('@cosyte/deid/ncpdp');
7
+ var ccda$1 = require('@cosyte/deid/ccda');
8
+ var fhir = require('@cosyte/fhir');
9
+ var x12 = require('@cosyte/x12');
10
+ var ccda = require('@cosyte/ccda');
11
+ var telecom = require('@cosyte/ncpdp/telecom');
12
+ var hl7$1 = require('@cosyte/hl7');
13
+ var deid = require('@cosyte/deid');
14
+
15
+ // src/deid/index.ts
16
+
17
+ // src/rng/splitmix32.ts
18
+ function splitmix32(seed) {
19
+ let a = seed | 0;
20
+ return function next() {
21
+ a = a + 2654435769 | 0;
22
+ let t = a ^ a >>> 16;
23
+ t = Math.imul(t, 569420461);
24
+ t = t ^ t >>> 15;
25
+ t = Math.imul(t, 1935289751);
26
+ t = t ^ t >>> 15;
27
+ return t >>> 0;
28
+ };
29
+ }
30
+
31
+ // src/rng/sfc32.ts
32
+ function sfc32Next(s) {
33
+ s.a |= 0;
34
+ s.b |= 0;
35
+ s.c |= 0;
36
+ s.d |= 0;
37
+ const t = (s.a + s.b | 0) + s.d | 0;
38
+ s.d = s.d + 1 | 0;
39
+ s.a = s.b ^ s.b >>> 9;
40
+ s.b = s.c + (s.c << 3) | 0;
41
+ s.c = s.c << 21 | s.c >>> 11;
42
+ s.c = s.c + t | 0;
43
+ return t >>> 0;
44
+ }
45
+
46
+ // src/rng/rng.ts
47
+ var Sfc32Rng = class {
48
+ seed;
49
+ #state;
50
+ constructor(seed) {
51
+ this.seed = seed | 0;
52
+ const mix = splitmix32(this.seed);
53
+ this.#state = { a: mix(), b: mix(), c: mix(), d: mix() };
54
+ for (let i = 0; i < 8; i += 1) sfc32Next(this.#state);
55
+ }
56
+ nextUint32() {
57
+ return sfc32Next(this.#state);
58
+ }
59
+ float() {
60
+ return this.nextUint32() / 4294967296;
61
+ }
62
+ int(min, max) {
63
+ if (max < min) throw new RangeError(`Rng.int: max (${String(max)}) < min (${String(min)})`);
64
+ const span = max - min + 1;
65
+ return min + Math.floor(this.float() * span);
66
+ }
67
+ bool(p = 0.5) {
68
+ return this.float() < p;
69
+ }
70
+ pick(items) {
71
+ if (items.length === 0) throw new RangeError("Rng.pick: empty array");
72
+ return items[this.int(0, items.length - 1)];
73
+ }
74
+ digits(n) {
75
+ let out = "";
76
+ for (let i = 0; i < n; i += 1) out += String(this.int(0, 9));
77
+ return out;
78
+ }
79
+ };
80
+ function createRng(seed) {
81
+ return new Sfc32Rng(seed);
82
+ }
83
+
84
+ // src/hl7/field.ts
85
+ function componentsField(components) {
86
+ return {
87
+ repetitions: [{ components: components.map((c) => ({ subcomponents: [c] })) }],
88
+ isNull: false
89
+ };
90
+ }
91
+
92
+ // src/safe/reserved.ts
93
+ var SYNTHETIC_ASSIGNING_AUTHORITY = Object.freeze({
94
+ /** The human-readable assigning-authority namespace id (HL7 HD.1). */
95
+ namespaceId: "COSYTE-SYNTH",
96
+ /** The universal id — an OID under HL7's example arc `2.16.840.1.113883.19` (HD.2). */
97
+ universalId: "2.16.840.1.113883.19.999",
98
+ /** The universal id type (HD.3). */
99
+ universalIdType: "ISO"
100
+ });
101
+ var RESERVED_EMAIL_DOMAINS = Object.freeze([
102
+ "example.com",
103
+ "example.org",
104
+ "example.net"
105
+ ]);
106
+ var TEST_NET_V4_PREFIXES = Object.freeze([
107
+ "192.0.2",
108
+ // TEST-NET-1
109
+ "198.51.100",
110
+ // TEST-NET-2
111
+ "203.0.113"
112
+ // TEST-NET-3
113
+ ]);
114
+ var DOC_V6_PREFIX = "2001:db8";
115
+ var NPI_LUHN_PREFIX = "80840";
116
+ function luhnMod10(digits) {
117
+ let sum = 0;
118
+ let double = false;
119
+ for (let i = digits.length - 1; i >= 0; i -= 1) {
120
+ let d = digits.charCodeAt(i) - 48;
121
+ if (d < 0 || d > 9) continue;
122
+ if (double) {
123
+ d *= 2;
124
+ if (d > 9) d -= 9;
125
+ }
126
+ sum += d;
127
+ double = !double;
128
+ }
129
+ return sum % 10;
130
+ }
131
+ function npiCheckDigit(base9) {
132
+ const partial = luhnMod10(`${NPI_LUHN_PREFIX}${base9}0`);
133
+ return (10 - partial) % 10;
134
+ }
135
+ var DEA_REGISTRANT_TYPES = Object.freeze([
136
+ "A",
137
+ "B",
138
+ "F",
139
+ "G",
140
+ "M",
141
+ "P",
142
+ "R",
143
+ "X"
144
+ ]);
145
+ function deaCheckDigit(base6) {
146
+ let odd = 0;
147
+ let even = 0;
148
+ for (let i = 0; i < 6; i += 1) {
149
+ const digit = base6.charCodeAt(i) - 48;
150
+ if (i % 2 === 0) odd += digit;
151
+ else even += digit;
152
+ }
153
+ return (odd + 2 * even) % 10;
154
+ }
155
+
156
+ // src/safe/names-pool.ts
157
+ var SYNTHETIC_GIVEN_NAMES = Object.freeze([
158
+ "Testina",
159
+ "Fixtura",
160
+ "Synthos",
161
+ "Placeholda",
162
+ "Sampleton",
163
+ "Prototius",
164
+ "Stubbina",
165
+ "Exampla",
166
+ "Quilliam",
167
+ "Fabrica",
168
+ "Simula",
169
+ "Testry",
170
+ "Seedwin",
171
+ "Corpora",
172
+ "Reprodo",
173
+ "Mocktavia",
174
+ "Dummett",
175
+ "Voidwin",
176
+ "Deteria",
177
+ "Randomir"
178
+ ]);
179
+ var SYNTHETIC_FAMILY_NAMES = Object.freeze([
180
+ "Testerson",
181
+ "Fauxman",
182
+ "Placeholt",
183
+ "Mockridge",
184
+ "Fixtingham",
185
+ "Synthwell",
186
+ "Dummerton",
187
+ "Examplewood",
188
+ "Fabricant",
189
+ "Simulacre",
190
+ "Nonesuch",
191
+ "Seedman",
192
+ "Corpusworth",
193
+ "Reprodus",
194
+ "Voidmark",
195
+ "Deterwood",
196
+ "Randomson",
197
+ "Quillfeather",
198
+ "Notreal",
199
+ "Genfield"
200
+ ]);
201
+ var SYNTHETIC_STREET_NAMES = Object.freeze([
202
+ "Fixture Lane",
203
+ "Sample Street",
204
+ "Placeholder Avenue",
205
+ "Synthetic Way",
206
+ "Example Boulevard",
207
+ "Testing Terrace",
208
+ "Mock Road",
209
+ "Prototype Court"
210
+ ]);
211
+ var SYNTHETIC_CITY_NAMES = Object.freeze([
212
+ "Faketon",
213
+ "Synthville",
214
+ "Exampleburg",
215
+ "Testford",
216
+ "Mockhaven",
217
+ "Fixtureton"
218
+ ]);
219
+
220
+ // src/safe/providers.ts
221
+ function ssn(rng, block = "never-issued") {
222
+ if (block === "advertising") {
223
+ return `987-65-432${String(rng.int(0, 9))}`;
224
+ }
225
+ const area = rng.int(900, 999);
226
+ const group = rng.digits(2);
227
+ const serial = rng.digits(4);
228
+ return `${String(area)}-${group}-${serial}`;
229
+ }
230
+ function phone(rng) {
231
+ const area = `${String(rng.int(2, 9))}${rng.digits(2)}`;
232
+ const line = `01${rng.digits(2)}`;
233
+ return `(${area}) 555-${line}`;
234
+ }
235
+ function name(rng) {
236
+ return { given: rng.pick(SYNTHETIC_GIVEN_NAMES), family: rng.pick(SYNTHETIC_FAMILY_NAMES) };
237
+ }
238
+ function email(rng, person) {
239
+ const domain = rng.pick(RESERVED_EMAIL_DOMAINS);
240
+ const slug = person ? `${person.given}.${person.family}`.toLowerCase() : `synth${rng.digits(6)}`;
241
+ return `${slug}@${domain}`;
242
+ }
243
+ function ipv4(rng) {
244
+ return `${rng.pick(TEST_NET_V4_PREFIXES)}.${String(rng.int(1, 254))}`;
245
+ }
246
+ function ipv6(rng) {
247
+ const tail = rng.nextUint32().toString(16).padStart(4, "0").slice(-4);
248
+ return `${DOC_V6_PREFIX}::${tail}`;
249
+ }
250
+ function uuid(rng) {
251
+ const bytes = new Uint8Array(16);
252
+ for (let i = 0; i < 16; i += 1) bytes[i] = rng.int(0, 255);
253
+ bytes[6] = (bytes[6] ?? 0) & 15 | 64;
254
+ bytes[8] = (bytes[8] ?? 0) & 63 | 128;
255
+ const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0"));
256
+ return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10, 16).join("")}`;
257
+ }
258
+ function npi(rng) {
259
+ const base9 = rng.digits(9);
260
+ const wrongCheck = (npiCheckDigit(base9) + 1) % 10;
261
+ return `${base9}${String(wrongCheck)}`;
262
+ }
263
+ function dea(rng, person) {
264
+ const type = rng.pick(DEA_REGISTRANT_TYPES);
265
+ const initialSource = person?.family ?? rng.pick(SYNTHETIC_FAMILY_NAMES);
266
+ const initial = initialSource.slice(0, 1).toUpperCase();
267
+ const base6 = rng.digits(6);
268
+ const wrongCheck = (deaCheckDigit(base6) + 1) % 10;
269
+ return `${type}${initial}${base6}${String(wrongCheck)}`;
270
+ }
271
+ function identifier(rng, typeCode = "MR") {
272
+ return {
273
+ value: rng.digits(8),
274
+ typeCode,
275
+ assigningAuthority: SYNTHETIC_ASSIGNING_AUTHORITY.namespaceId,
276
+ assigningAuthorityOid: SYNTHETIC_ASSIGNING_AUTHORITY.universalId
277
+ };
278
+ }
279
+ function address(rng) {
280
+ const number = rng.int(1, 9999);
281
+ return {
282
+ street: `${String(number)} ${rng.pick(SYNTHETIC_STREET_NAMES)}`,
283
+ city: rng.pick(SYNTHETIC_CITY_NAMES),
284
+ state: rng.pick(US_STATES),
285
+ zip: "00000"
286
+ };
287
+ }
288
+ function dateYmd(rng, minYear = 1930, maxYear = 2010) {
289
+ const year = rng.int(minYear, maxYear);
290
+ const month = rng.int(1, 12);
291
+ const daysInMonth = new Date(Date.UTC(year, month, 0)).getUTCDate();
292
+ const day = rng.int(1, daysInMonth);
293
+ return `${String(year).padStart(4, "0")}${String(month).padStart(2, "0")}${String(day).padStart(2, "0")}`;
294
+ }
295
+ var US_STATES = Object.freeze([
296
+ "AL",
297
+ "AK",
298
+ "AZ",
299
+ "AR",
300
+ "CA",
301
+ "CO",
302
+ "CT",
303
+ "DE",
304
+ "FL",
305
+ "GA",
306
+ "HI",
307
+ "ID",
308
+ "IL",
309
+ "IN",
310
+ "IA",
311
+ "KS",
312
+ "KY",
313
+ "LA",
314
+ "ME",
315
+ "MD",
316
+ "MA",
317
+ "MI",
318
+ "MN",
319
+ "MS",
320
+ "MO",
321
+ "MT",
322
+ "NE",
323
+ "NV",
324
+ "NH",
325
+ "NJ",
326
+ "NM",
327
+ "NY",
328
+ "NC",
329
+ "ND",
330
+ "OH",
331
+ "OK",
332
+ "OR",
333
+ "PA",
334
+ "RI",
335
+ "SC",
336
+ "SD",
337
+ "TN",
338
+ "TX",
339
+ "UT",
340
+ "VT",
341
+ "VA",
342
+ "WA",
343
+ "WV",
344
+ "WI",
345
+ "WY"
346
+ ]);
347
+
348
+ // src/safe/index.ts
349
+ var safe = Object.freeze({
350
+ ssn,
351
+ phone,
352
+ name,
353
+ email,
354
+ ipv4,
355
+ ipv6,
356
+ uuid,
357
+ identifier,
358
+ address,
359
+ dateYmd,
360
+ npi,
361
+ dea
362
+ });
363
+
364
+ // src/hl7/common.ts
365
+ function seededTimestamp(rng) {
366
+ const date = safe.dateYmd(rng, 2020, 2025);
367
+ const hh = String(rng.int(0, 23)).padStart(2, "0");
368
+ const mm = String(rng.int(0, 59)).padStart(2, "0");
369
+ const ss = String(rng.int(0, 59)).padStart(2, "0");
370
+ return `${date}${hh}${mm}${ss}`;
371
+ }
372
+ function mshScaffold(rng, type) {
373
+ const timestamp = seededTimestamp(rng);
374
+ const controlId = `SYNTH${rng.digits(10)}`;
375
+ const message = hl7$1.buildMessage({
376
+ type,
377
+ sendingApp: "COSYTE-SYNTH",
378
+ sendingFacility: "SYNTH-FAC",
379
+ receivingApp: "RECEIVER",
380
+ receivingFacility: "RECV-FAC",
381
+ controlId,
382
+ timestamp,
383
+ version: "2.5",
384
+ processingId: "P"
385
+ });
386
+ return { message, timestamp, controlId };
387
+ }
388
+ function patientIdentity(rng) {
389
+ const person = safe.name(rng);
390
+ const mrn = safe.identifier(rng, "MR");
391
+ const dob = safe.dateYmd(rng, 1930, 2010);
392
+ const sex = rng.pick(["M", "F"]);
393
+ const address2 = safe.address(rng);
394
+ const phone2 = safe.phone(rng);
395
+ const ssnDigits = safe.ssn(rng).replace(/-/g, "");
396
+ return { person, mrn, dob, sex, address: address2, phone: phone2, ssnDigits };
397
+ }
398
+ function pidSegment(id) {
399
+ return [
400
+ "1",
401
+ // PID-1 set id
402
+ "",
403
+ // PID-2 (legacy, absent)
404
+ componentsField([id.mrn.value, "", "", id.mrn.assigningAuthority, id.mrn.typeCode]),
405
+ // PID-3 CX
406
+ "",
407
+ // PID-4
408
+ componentsField([id.person.family, id.person.given]),
409
+ // PID-5 XPN
410
+ "",
411
+ // PID-6
412
+ id.dob,
413
+ // PID-7 DOB
414
+ id.sex,
415
+ // PID-8 sex
416
+ "",
417
+ // PID-9
418
+ "",
419
+ // PID-10
420
+ componentsField([id.address.street, "", id.address.city, id.address.state, id.address.zip]),
421
+ // PID-11 XAD
422
+ "",
423
+ // PID-12
424
+ id.phone,
425
+ // PID-13 phone
426
+ "",
427
+ // PID-14
428
+ "",
429
+ // PID-15
430
+ "",
431
+ // PID-16
432
+ "",
433
+ // PID-17
434
+ "",
435
+ // PID-18
436
+ id.ssnDigits
437
+ // PID-19 SSN (digits)
438
+ ];
439
+ }
440
+
441
+ // src/hl7/adt.ts
442
+ function generateAdt(options = {}) {
443
+ const seed = options.seed ?? 0;
444
+ const trigger = options.trigger ?? "A01";
445
+ const rng = createRng(seed);
446
+ const { message, timestamp } = mshScaffold(rng, `ADT^${trigger}`);
447
+ message.addSegment("EVN", [trigger, timestamp]);
448
+ message.addSegment("PID", pidSegment(patientIdentity(rng)));
449
+ const patientClass = rng.pick(["I", "O", "E"]);
450
+ message.addSegment("PV1", [
451
+ "1",
452
+ // PV1-1 set id
453
+ patientClass,
454
+ // PV1-2 patient class
455
+ componentsField(["SYNTHWARD", String(rng.int(1, 999)).padStart(3, "0"), "01"])
456
+ // PV1-3 PL
457
+ ]);
458
+ return message;
459
+ }
460
+
461
+ // src/hl7/example-codes.ts
462
+ var EXAMPLE_LAB_OBSERVATIONS = Object.freeze([
463
+ Object.freeze({ code: "4548-4", text: "Hemoglobin A1c", system: "LN", units: "%" }),
464
+ Object.freeze({ code: "718-7", text: "Hemoglobin", system: "LN", units: "g/dL" }),
465
+ Object.freeze({ code: "2345-7", text: "Glucose", system: "LN", units: "mg/dL" }),
466
+ Object.freeze({ code: "2951-2", text: "Sodium", system: "LN", units: "mmol/L" }),
467
+ Object.freeze({ code: "2823-3", text: "Potassium", system: "LN", units: "mmol/L" }),
468
+ Object.freeze({ code: "789-8", text: "Erythrocytes", system: "LN", units: "10*6/uL" })
469
+ ]);
470
+ var EXAMPLE_ORDER_SERVICES = Object.freeze([
471
+ Object.freeze({ code: "24323-8", text: "Comprehensive metabolic panel", system: "LN" }),
472
+ Object.freeze({ code: "58410-2", text: "CBC panel", system: "LN" }),
473
+ Object.freeze({ code: "24356-8", text: "Urinalysis panel", system: "LN" }),
474
+ Object.freeze({ code: "24331-1", text: "Lipid panel", system: "LN" })
475
+ ]);
476
+ var EXAMPLE_VACCINES = Object.freeze([
477
+ Object.freeze({ code: "08", text: "Hep B, adolescent or pediatric", system: "CVX" }),
478
+ Object.freeze({ code: "20", text: "DTaP", system: "CVX" }),
479
+ Object.freeze({ code: "03", text: "MMR", system: "CVX" }),
480
+ Object.freeze({ code: "10", text: "IPV", system: "CVX" }),
481
+ Object.freeze({ code: "141", text: "Influenza, seasonal, injectable", system: "CVX" }),
482
+ Object.freeze({ code: "21", text: "Varicella", system: "CVX" })
483
+ ]);
484
+
485
+ // src/hl7/oru.ts
486
+ function obxSegment(rng, setId) {
487
+ const obs = rng.pick(EXAMPLE_LAB_OBSERVATIONS);
488
+ const value = `${String(rng.int(1, 300))}.${String(rng.int(0, 9))}`;
489
+ const observedAt = seededTimestamp(rng);
490
+ return [
491
+ String(setId),
492
+ // OBX-1 set id
493
+ "NM",
494
+ // OBX-2 value type (numeric)
495
+ componentsField([obs.code, obs.text, obs.system]),
496
+ // OBX-3 observation identifier (CE)
497
+ "",
498
+ // OBX-4 observation sub-id
499
+ value,
500
+ // OBX-5 observation value
501
+ obs.units ?? "",
502
+ // OBX-6 units
503
+ "",
504
+ // OBX-7 reference range
505
+ "N",
506
+ // OBX-8 abnormal flags (normal)
507
+ "",
508
+ // OBX-9
509
+ "",
510
+ // OBX-10
511
+ "F",
512
+ // OBX-11 observation result status (final)
513
+ "",
514
+ // OBX-12
515
+ "",
516
+ // OBX-13
517
+ observedAt
518
+ // OBX-14 date/time of the observation
519
+ ];
520
+ }
521
+ function generateOru(options = {}) {
522
+ const seed = options.seed ?? 0;
523
+ const rng = createRng(seed);
524
+ const { message } = mshScaffold(rng, "ORU^R01");
525
+ message.addSegment("PID", pidSegment(patientIdentity(rng)));
526
+ const service = rng.pick(EXAMPLE_ORDER_SERVICES);
527
+ const placer = rng.digits(8);
528
+ const filler = rng.digits(8);
529
+ message.addSegment("OBR", [
530
+ "1",
531
+ // OBR-1 set id
532
+ placer,
533
+ // OBR-2 placer order number
534
+ filler,
535
+ // OBR-3 filler order number
536
+ componentsField([service.code, service.text, service.system]),
537
+ // OBR-4 universal service id (CE)
538
+ "",
539
+ // OBR-5
540
+ "",
541
+ // OBR-6
542
+ seededTimestamp(rng)
543
+ // OBR-7 observation date/time
544
+ ]);
545
+ const obxCount = rng.int(1, 3);
546
+ for (let i = 1; i <= obxCount; i += 1) {
547
+ message.addSegment("OBX", obxSegment(rng, i));
548
+ }
549
+ return message;
550
+ }
551
+
552
+ // src/hl7/orm.ts
553
+ function generateOrm(options = {}) {
554
+ const seed = options.seed ?? 0;
555
+ const rng = createRng(seed);
556
+ const { message } = mshScaffold(rng, "ORM^O01");
557
+ message.addSegment("PID", pidSegment(patientIdentity(rng)));
558
+ const service = rng.pick(EXAMPLE_ORDER_SERVICES);
559
+ const placer = rng.digits(8);
560
+ const filler = rng.digits(8);
561
+ const orderedAt = seededTimestamp(rng);
562
+ message.addSegment("ORC", [
563
+ "NW",
564
+ // ORC-1 order control (new order)
565
+ placer,
566
+ // ORC-2 placer order number
567
+ filler,
568
+ // ORC-3 filler order number
569
+ "",
570
+ // ORC-4 placer group number
571
+ "",
572
+ // ORC-5 order status
573
+ "",
574
+ // ORC-6
575
+ "",
576
+ // ORC-7 quantity/timing
577
+ "",
578
+ // ORC-8
579
+ orderedAt
580
+ // ORC-9 date/time of transaction
581
+ ]);
582
+ message.addSegment("OBR", [
583
+ "1",
584
+ // OBR-1 set id
585
+ placer,
586
+ // OBR-2 placer order number (matches ORC)
587
+ filler,
588
+ // OBR-3 filler order number (matches ORC)
589
+ componentsField([service.code, service.text, service.system])
590
+ // OBR-4 universal service id (CE)
591
+ ]);
592
+ return message;
593
+ }
594
+
595
+ // src/hl7/siu.ts
596
+ function generateSiu(options = {}) {
597
+ const seed = options.seed ?? 0;
598
+ const rng = createRng(seed);
599
+ const { message } = mshScaffold(rng, "SIU^S12");
600
+ const placerAppt = rng.digits(8);
601
+ const fillerAppt = rng.digits(8);
602
+ const startAt = seededTimestamp(rng);
603
+ const durationMinutes = String(rng.int(15, 90));
604
+ message.addSegment("SCH", [
605
+ placerAppt,
606
+ // SCH-1 placer appointment id
607
+ fillerAppt,
608
+ // SCH-2 filler appointment id
609
+ "",
610
+ // SCH-3 occurrence number
611
+ "",
612
+ // SCH-4 placer group number
613
+ "",
614
+ // SCH-5 schedule id
615
+ "",
616
+ // SCH-6 event reason
617
+ componentsField(["ROUTINE", "Routine appointment", "L"]),
618
+ // SCH-7 appointment reason (CE)
619
+ "",
620
+ // SCH-8 appointment type
621
+ durationMinutes,
622
+ // SCH-9 appointment duration
623
+ componentsField(["min", "minutes", "UCUM"]),
624
+ // SCH-10 appointment duration units (CE)
625
+ componentsField(["1", "", startAt, "", "", "", durationMinutes])
626
+ // SCH-11 appointment timing quantity (TQ)
627
+ ]);
628
+ message.addSegment("PID", pidSegment(patientIdentity(rng)));
629
+ message.addSegment("RGS", [
630
+ "1",
631
+ // RGS-1 set id
632
+ "A"
633
+ // RGS-2 segment action code (add)
634
+ ]);
635
+ message.addSegment("AIL", [
636
+ "1",
637
+ // AIL-1 set id
638
+ "A",
639
+ // AIL-2 segment action code
640
+ componentsField(["SYNTHCLINIC", "Synthetic Clinic", "COSYTE-SYNTH"])
641
+ // AIL-3 location resource id
642
+ ]);
643
+ return message;
644
+ }
645
+
646
+ // src/hl7/vxu.ts
647
+ function generateVxu(options = {}) {
648
+ const seed = options.seed ?? 0;
649
+ const rng = createRng(seed);
650
+ const { message } = mshScaffold(rng, "VXU^V04");
651
+ message.addSegment("PID", pidSegment(patientIdentity(rng)));
652
+ const placer = rng.digits(8);
653
+ const filler = rng.digits(8);
654
+ message.addSegment("ORC", [
655
+ "RE",
656
+ // ORC-1 order control (observation to follow / record)
657
+ placer,
658
+ // ORC-2 placer order number
659
+ filler
660
+ // ORC-3 filler order number
661
+ ]);
662
+ const vaccine = rng.pick(EXAMPLE_VACCINES);
663
+ const administeredAt = seededTimestamp(rng);
664
+ const doseAmount = String(rng.int(1, 5) / 10);
665
+ message.addSegment("RXA", [
666
+ "0",
667
+ // RXA-1 give sub-id counter
668
+ "1",
669
+ // RXA-2 administration sub-id counter
670
+ administeredAt,
671
+ // RXA-3 date/time start of administration
672
+ administeredAt,
673
+ // RXA-4 date/time end of administration
674
+ componentsField([vaccine.code, vaccine.text, vaccine.system]),
675
+ // RXA-5 administered code (CE)
676
+ doseAmount,
677
+ // RXA-6 administered amount
678
+ componentsField(["mL", "milliliters", "UCUM"]),
679
+ // RXA-7 administered units (CE)
680
+ "",
681
+ // RXA-8
682
+ "",
683
+ // RXA-9 administration notes
684
+ "",
685
+ // RXA-10
686
+ "",
687
+ // RXA-11
688
+ "",
689
+ // RXA-12
690
+ "",
691
+ // RXA-13
692
+ "",
693
+ // RXA-14
694
+ "",
695
+ // RXA-15 substance lot number
696
+ "",
697
+ // RXA-16
698
+ "",
699
+ // RXA-17
700
+ "",
701
+ // RXA-18
702
+ "",
703
+ // RXA-19
704
+ "CP"
705
+ // RXA-20 completion status (complete)
706
+ ]);
707
+ message.addSegment("RXR", [
708
+ componentsField(["IM", "Intramuscular", "HL70162"]),
709
+ // RXR-1 route (CE)
710
+ componentsField(["LD", "Left Deltoid", "HL70163"])
711
+ // RXR-2 administration site (CE)
712
+ ]);
713
+ return message;
714
+ }
715
+ function generateHl7(kind, seed) {
716
+ switch (kind) {
717
+ case "ADT^A01":
718
+ return generateAdt({ seed, trigger: "A01" });
719
+ case "ADT^A04":
720
+ return generateAdt({ seed, trigger: "A04" });
721
+ case "ADT^A08":
722
+ return generateAdt({ seed, trigger: "A08" });
723
+ case "ORU^R01":
724
+ return generateOru({ seed });
725
+ case "ORM^O01":
726
+ return generateOrm({ seed });
727
+ case "SIU^S12":
728
+ return generateSiu({ seed });
729
+ case "VXU^V04":
730
+ return generateVxu({ seed });
731
+ }
732
+ }
733
+
734
+ // src/fhir/us-core.ts
735
+ var US_CORE_PROFILE = Object.freeze({
736
+ /** US Core Patient. */
737
+ PATIENT: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient",
738
+ /** US Core Condition (Problems and Health Concerns). */
739
+ CONDITION: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-condition-problems-health-concerns",
740
+ /** US Core Laboratory Result Observation. */
741
+ OBSERVATION_LAB: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-lab",
742
+ /** US Core Vital Signs (derived from the base FHIR vital-signs profile). */
743
+ VITAL_SIGNS: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-vital-signs",
744
+ /** US Core MedicationRequest. */
745
+ MEDICATION_REQUEST: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-medicationrequest",
746
+ /** US Core Encounter. */
747
+ ENCOUNTER: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-encounter",
748
+ /** US Core DiagnosticReport Profile for Laboratory Results Reporting. */
749
+ DIAGNOSTIC_REPORT_LAB: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-diagnosticreport-lab",
750
+ /** US Core Immunization. */
751
+ IMMUNIZATION: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-immunization",
752
+ /** US Core AllergyIntolerance. */
753
+ ALLERGY_INTOLERANCE: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-allergyintolerance",
754
+ /** US Core Procedure. */
755
+ PROCEDURE: "http://hl7.org/fhir/us/core/StructureDefinition/us-core-procedure"
756
+ });
757
+ var US_CORE_RACE_EXTENSION = "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race";
758
+ var US_CORE_ETHNICITY_EXTENSION = "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity";
759
+ var US_CORE_BIRTHSEX_EXTENSION = "http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex";
760
+ var SYSTEM = Object.freeze({
761
+ /** FHIR `administrative-gender` (`Patient.gender`). */
762
+ ADMINISTRATIVE_GENDER: "http://hl7.org/fhir/administrative-gender",
763
+ /** HL7 Terminology `observation-category`. */
764
+ OBSERVATION_CATEGORY: "http://terminology.hl7.org/CodeSystem/observation-category",
765
+ /** HL7 Terminology `condition-category`. */
766
+ CONDITION_CATEGORY: "http://terminology.hl7.org/CodeSystem/condition-category",
767
+ /** HL7 Terminology `condition-clinical`. */
768
+ CONDITION_CLINICAL: "http://terminology.hl7.org/CodeSystem/condition-clinical",
769
+ /** HL7 Terminology `condition-ver-status`. */
770
+ CONDITION_VER_STATUS: "http://terminology.hl7.org/CodeSystem/condition-ver-status",
771
+ /** HL7 v2 `0203` identifier-type (`Identifier.type.coding.code` = `MR`). */
772
+ IDENTIFIER_TYPE: "http://terminology.hl7.org/CodeSystem/v2-0203",
773
+ /** OMB race & ethnicity category system (US Core race/ethnicity `ombCategory`). */
774
+ OMB_RACE_ETHNICITY: "urn:oid:2.16.840.1.113883.6.238",
775
+ /** LOINC — `Observation.code` (lab + vital-signs). */
776
+ LOINC: "http://loinc.org",
777
+ /** SNOMED CT — `Condition.code`. */
778
+ SNOMED: "http://snomed.info/sct",
779
+ /** RxNorm — `MedicationRequest.medicationCodeableConcept` + an allergen substance. */
780
+ RXNORM: "http://www.nlm.nih.gov/research/umls/rxnorm",
781
+ /** UCUM — `Quantity.system` for units of measure. */
782
+ UCUM: "http://unitsofmeasure.org",
783
+ /** CVX (CDC vaccine administered) — `Immunization.vaccineCode`. */
784
+ CVX: "http://hl7.org/fhir/sid/cvx",
785
+ /** HL7 v3 `ActCode` — `Encounter.class`. */
786
+ V3_ACT_CODE: "http://terminology.hl7.org/CodeSystem/v3-ActCode",
787
+ /** HL7 v2 `0074` diagnostic-service-section — `DiagnosticReport.category` (`LAB`). */
788
+ DIAGNOSTIC_SERVICE_SECTION: "http://terminology.hl7.org/CodeSystem/v2-0074",
789
+ /** HL7 Terminology `allergyintolerance-clinical` — `AllergyIntolerance.clinicalStatus`. */
790
+ ALLERGY_CLINICAL: "http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical",
791
+ /** HL7 Terminology `allergyintolerance-verification` — `AllergyIntolerance.verificationStatus`. */
792
+ ALLERGY_VERIFICATION: "http://terminology.hl7.org/CodeSystem/allergyintolerance-verification"
793
+ });
794
+
795
+ // src/fhir/builder.ts
796
+ function prop(name2, value) {
797
+ return { name: name2, value };
798
+ }
799
+ function str(value) {
800
+ return fhir.primitive(value);
801
+ }
802
+ function dec(raw) {
803
+ return fhir.primitive(fhir.decimal(raw));
804
+ }
805
+ function bool(value) {
806
+ return fhir.primitive(value);
807
+ }
808
+ function coding(concept) {
809
+ return fhir.complex([
810
+ prop("system", str(concept.system)),
811
+ prop("code", str(concept.code)),
812
+ prop("display", str(concept.display))
813
+ ]);
814
+ }
815
+ function codeableConcept(concept) {
816
+ return fhir.complex([prop("coding", fhir.list([coding(concept)]))]);
817
+ }
818
+ function reference(ref) {
819
+ return fhir.complex([prop("reference", str(ref))]);
820
+ }
821
+ function narrative(text) {
822
+ const escaped = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
823
+ return fhir.complex([
824
+ prop("status", str("generated")),
825
+ prop("div", str(`<div xmlns="http://www.w3.org/1999/xhtml"><p>${escaped}</p></div>`))
826
+ ]);
827
+ }
828
+ function meta(profiles) {
829
+ return fhir.complex([prop("profile", fhir.list(profiles.map((p) => str(p))))]);
830
+ }
831
+ function toFhirDate(ymd) {
832
+ return `${ymd.slice(0, 4)}-${ymd.slice(4, 6)}-${ymd.slice(6, 8)}`;
833
+ }
834
+ function fhirPatientIdentity(rng) {
835
+ const id = safe.uuid(rng);
836
+ const person = safe.name(rng);
837
+ const mrn = safe.identifier(rng, "MR");
838
+ const birthDate = toFhirDate(safe.dateYmd(rng, 1930, 2010));
839
+ const gender = rng.pick(["male", "female"]);
840
+ const address2 = safe.address(rng);
841
+ const phone2 = safe.phone(rng);
842
+ const email2 = safe.email(rng, person);
843
+ return { id, person, mrn, birthDate, gender, address: address2, phone: phone2, email: email2 };
844
+ }
845
+ function mrnIdentifier(mrn) {
846
+ return fhir.complex([
847
+ prop(
848
+ "type",
849
+ fhir.complex([
850
+ prop(
851
+ "coding",
852
+ fhir.list([
853
+ coding({
854
+ system: SYSTEM.IDENTIFIER_TYPE,
855
+ code: "MR",
856
+ display: "Medical Record Number"
857
+ })
858
+ ])
859
+ )
860
+ ])
861
+ ),
862
+ prop("system", str(`urn:oid:${mrn.assigningAuthorityOid}`)),
863
+ prop("value", str(mrn.value))
864
+ ]);
865
+ }
866
+
867
+ // src/fhir/example-codes.ts
868
+ var EXAMPLE_LAB_OBSERVATIONS2 = Object.freeze([
869
+ Object.freeze({
870
+ system: SYSTEM.LOINC,
871
+ code: "2345-7",
872
+ display: "Glucose [Mass/volume] in Serum or Plasma",
873
+ unit: "mg/dL",
874
+ low: 70,
875
+ high: 140,
876
+ decimals: 0
877
+ }),
878
+ Object.freeze({
879
+ system: SYSTEM.LOINC,
880
+ code: "718-7",
881
+ display: "Hemoglobin [Mass/volume] in Blood",
882
+ unit: "g/dL",
883
+ low: 12,
884
+ high: 17,
885
+ decimals: 1
886
+ }),
887
+ Object.freeze({
888
+ system: SYSTEM.LOINC,
889
+ code: "2951-2",
890
+ display: "Sodium [Moles/volume] in Serum or Plasma",
891
+ unit: "mmol/L",
892
+ low: 135,
893
+ high: 145,
894
+ decimals: 0
895
+ }),
896
+ Object.freeze({
897
+ system: SYSTEM.LOINC,
898
+ code: "2823-3",
899
+ display: "Potassium [Moles/volume] in Serum or Plasma",
900
+ unit: "mmol/L",
901
+ low: 4,
902
+ high: 5,
903
+ decimals: 1
904
+ }),
905
+ Object.freeze({
906
+ system: SYSTEM.LOINC,
907
+ code: "4548-4",
908
+ display: "Hemoglobin A1c/Hemoglobin.total in Blood",
909
+ unit: "%",
910
+ low: 4,
911
+ high: 9,
912
+ decimals: 1
913
+ })
914
+ ]);
915
+ var EXAMPLE_VITAL_SIGNS = Object.freeze([
916
+ Object.freeze({
917
+ system: SYSTEM.LOINC,
918
+ code: "8867-4",
919
+ display: "Heart rate",
920
+ unit: "/min",
921
+ low: 55,
922
+ high: 100,
923
+ decimals: 0
924
+ }),
925
+ Object.freeze({
926
+ system: SYSTEM.LOINC,
927
+ code: "9279-1",
928
+ display: "Respiratory rate",
929
+ unit: "/min",
930
+ low: 12,
931
+ high: 20,
932
+ decimals: 0
933
+ }),
934
+ Object.freeze({
935
+ system: SYSTEM.LOINC,
936
+ code: "8310-5",
937
+ display: "Body temperature",
938
+ unit: "Cel",
939
+ low: 36,
940
+ high: 38,
941
+ decimals: 1
942
+ }),
943
+ Object.freeze({
944
+ system: SYSTEM.LOINC,
945
+ code: "29463-7",
946
+ display: "Body weight",
947
+ unit: "kg",
948
+ low: 50,
949
+ high: 100,
950
+ decimals: 1
951
+ }),
952
+ Object.freeze({
953
+ system: SYSTEM.LOINC,
954
+ code: "8302-2",
955
+ display: "Body height",
956
+ unit: "cm",
957
+ low: 150,
958
+ high: 190,
959
+ decimals: 0
960
+ })
961
+ ]);
962
+ var EXAMPLE_CONDITIONS = Object.freeze([
963
+ Object.freeze({ system: SYSTEM.SNOMED, code: "59621000", display: "Essential hypertension" }),
964
+ Object.freeze({ system: SYSTEM.SNOMED, code: "44054006", display: "Type 2 diabetes mellitus" }),
965
+ Object.freeze({ system: SYSTEM.SNOMED, code: "195967001", display: "Asthma" }),
966
+ Object.freeze({
967
+ system: SYSTEM.SNOMED,
968
+ code: "13645005",
969
+ display: "Chronic obstructive lung disease"
970
+ }),
971
+ Object.freeze({ system: SYSTEM.SNOMED, code: "38341003", display: "Hypertensive disorder" })
972
+ ]);
973
+ var EXAMPLE_MEDICATIONS = Object.freeze([
974
+ Object.freeze({
975
+ system: SYSTEM.RXNORM,
976
+ code: "1049221",
977
+ display: "Acetaminophen 325 MG Oral Tablet"
978
+ }),
979
+ Object.freeze({ system: SYSTEM.RXNORM, code: "197361", display: "Amlodipine 5 MG Oral Tablet" }),
980
+ Object.freeze({
981
+ system: SYSTEM.RXNORM,
982
+ code: "860975",
983
+ display: "24 HR Metformin hydrochloride 500 MG Extended Release Oral Tablet"
984
+ }),
985
+ Object.freeze({
986
+ system: SYSTEM.RXNORM,
987
+ code: "308136",
988
+ display: "Amoxicillin 250 MG Oral Capsule"
989
+ }),
990
+ Object.freeze({
991
+ system: SYSTEM.RXNORM,
992
+ code: "617314",
993
+ display: "Atorvastatin 40 MG Oral Tablet"
994
+ })
995
+ ]);
996
+ var EXAMPLE_RACE_CATEGORIES = Object.freeze([
997
+ Object.freeze({ system: SYSTEM.OMB_RACE_ETHNICITY, code: "2106-3", display: "White" }),
998
+ Object.freeze({
999
+ system: SYSTEM.OMB_RACE_ETHNICITY,
1000
+ code: "2054-5",
1001
+ display: "Black or African American"
1002
+ }),
1003
+ Object.freeze({ system: SYSTEM.OMB_RACE_ETHNICITY, code: "2028-9", display: "Asian" }),
1004
+ Object.freeze({
1005
+ system: SYSTEM.OMB_RACE_ETHNICITY,
1006
+ code: "1002-5",
1007
+ display: "American Indian or Alaska Native"
1008
+ }),
1009
+ Object.freeze({
1010
+ system: SYSTEM.OMB_RACE_ETHNICITY,
1011
+ code: "2076-8",
1012
+ display: "Native Hawaiian or Other Pacific Islander"
1013
+ })
1014
+ ]);
1015
+ var EXAMPLE_ETHNICITY_CATEGORIES = Object.freeze([
1016
+ Object.freeze({
1017
+ system: SYSTEM.OMB_RACE_ETHNICITY,
1018
+ code: "2135-2",
1019
+ display: "Hispanic or Latino"
1020
+ }),
1021
+ Object.freeze({
1022
+ system: SYSTEM.OMB_RACE_ETHNICITY,
1023
+ code: "2186-5",
1024
+ display: "Not Hispanic or Latino"
1025
+ })
1026
+ ]);
1027
+ var EXAMPLE_VACCINES2 = Object.freeze([
1028
+ Object.freeze({
1029
+ system: SYSTEM.CVX,
1030
+ code: "140",
1031
+ display: "Influenza, seasonal, injectable, preservative free"
1032
+ }),
1033
+ Object.freeze({ system: SYSTEM.CVX, code: "03", display: "MMR" }),
1034
+ Object.freeze({ system: SYSTEM.CVX, code: "20", display: "DTaP" }),
1035
+ Object.freeze({ system: SYSTEM.CVX, code: "133", display: "Pneumococcal conjugate PCV 13" }),
1036
+ Object.freeze({
1037
+ system: SYSTEM.CVX,
1038
+ code: "208",
1039
+ display: "COVID-19, mRNA, LNP-S, PF, 30 mcg/0.3 mL dose"
1040
+ })
1041
+ ]);
1042
+ var EXAMPLE_ALLERGENS = Object.freeze([
1043
+ Object.freeze({ system: SYSTEM.RXNORM, code: "7980", display: "Penicillin G" }),
1044
+ Object.freeze({ system: SYSTEM.RXNORM, code: "2670", display: "Codeine" }),
1045
+ Object.freeze({ system: SYSTEM.SNOMED, code: "762952008", display: "Peanut (substance)" }),
1046
+ Object.freeze({ system: SYSTEM.SNOMED, code: "227493005", display: "Cashew nuts (substance)" }),
1047
+ Object.freeze({ system: SYSTEM.SNOMED, code: "3718001", display: "Cow's milk (substance)" })
1048
+ ]);
1049
+ var EXAMPLE_ALLERGY_MANIFESTATIONS = Object.freeze([
1050
+ Object.freeze({ system: SYSTEM.SNOMED, code: "247472004", display: "Wheal (finding)" }),
1051
+ Object.freeze({ system: SYSTEM.SNOMED, code: "126485001", display: "Urticaria (disorder)" }),
1052
+ Object.freeze({
1053
+ system: SYSTEM.SNOMED,
1054
+ code: "271807003",
1055
+ display: "Eruption of skin (disorder)"
1056
+ }),
1057
+ Object.freeze({ system: SYSTEM.SNOMED, code: "267036007", display: "Dyspnea (finding)" }),
1058
+ Object.freeze({ system: SYSTEM.SNOMED, code: "422587007", display: "Nausea (finding)" })
1059
+ ]);
1060
+ var EXAMPLE_PROCEDURES = Object.freeze([
1061
+ Object.freeze({
1062
+ system: SYSTEM.SNOMED,
1063
+ code: "80146002",
1064
+ display: "Excision of appendix (procedure)"
1065
+ }),
1066
+ Object.freeze({ system: SYSTEM.SNOMED, code: "73761001", display: "Colonoscopy (procedure)" }),
1067
+ Object.freeze({
1068
+ system: SYSTEM.SNOMED,
1069
+ code: "5880005",
1070
+ display: "Physical examination procedure (procedure)"
1071
+ }),
1072
+ Object.freeze({
1073
+ system: SYSTEM.SNOMED,
1074
+ code: "108252007",
1075
+ display: "Laboratory procedure (procedure)"
1076
+ }),
1077
+ Object.freeze({ system: SYSTEM.SNOMED, code: "71651007", display: "Mammography (procedure)" })
1078
+ ]);
1079
+ var EXAMPLE_DIAGNOSTIC_REPORTS = Object.freeze([
1080
+ Object.freeze({
1081
+ system: SYSTEM.LOINC,
1082
+ code: "24323-8",
1083
+ display: "Comprehensive metabolic 2000 panel - Serum or Plasma"
1084
+ }),
1085
+ Object.freeze({
1086
+ system: SYSTEM.LOINC,
1087
+ code: "58410-2",
1088
+ display: "CBC panel - Blood by Automated count"
1089
+ }),
1090
+ Object.freeze({
1091
+ system: SYSTEM.LOINC,
1092
+ code: "24357-6",
1093
+ display: "Urinalysis complete panel - Urine"
1094
+ }),
1095
+ Object.freeze({
1096
+ system: SYSTEM.LOINC,
1097
+ code: "24331-1",
1098
+ display: "Lipid 1996 panel - Serum or Plasma"
1099
+ }),
1100
+ Object.freeze({
1101
+ system: SYSTEM.LOINC,
1102
+ code: "24321-2",
1103
+ display: "Basic metabolic 1998 panel - Serum or Plasma"
1104
+ })
1105
+ ]);
1106
+ var EXAMPLE_ENCOUNTER_TYPES = Object.freeze([
1107
+ Object.freeze({
1108
+ system: SYSTEM.SNOMED,
1109
+ code: "308335008",
1110
+ display: "Patient encounter procedure (procedure)"
1111
+ }),
1112
+ Object.freeze({
1113
+ system: SYSTEM.SNOMED,
1114
+ code: "185349003",
1115
+ display: "Encounter for check up (procedure)"
1116
+ }),
1117
+ Object.freeze({
1118
+ system: SYSTEM.SNOMED,
1119
+ code: "185347001",
1120
+ display: "Encounter for problem (procedure)"
1121
+ }),
1122
+ Object.freeze({
1123
+ system: SYSTEM.SNOMED,
1124
+ code: "390906007",
1125
+ display: "Follow-up encounter (procedure)"
1126
+ })
1127
+ ]);
1128
+ var EXAMPLE_ENCOUNTER_CLASSES = Object.freeze([
1129
+ Object.freeze({ system: SYSTEM.V3_ACT_CODE, code: "AMB", display: "ambulatory" }),
1130
+ Object.freeze({ system: SYSTEM.V3_ACT_CODE, code: "EMER", display: "emergency" }),
1131
+ Object.freeze({ system: SYSTEM.V3_ACT_CODE, code: "IMP", display: "inpatient encounter" })
1132
+ ]);
1133
+
1134
+ // src/fhir/patient.ts
1135
+ function ombExtension(url, category) {
1136
+ return fhir.complex([
1137
+ prop("url", str(url)),
1138
+ prop(
1139
+ "extension",
1140
+ fhir.list([
1141
+ fhir.complex([prop("url", str("ombCategory")), prop("valueCoding", coding(category))]),
1142
+ fhir.complex([prop("url", str("text")), prop("valueString", str(category.display))])
1143
+ ])
1144
+ )
1145
+ ]);
1146
+ }
1147
+ function generatePatient(options = {}) {
1148
+ const { seed = 0, profile = "base" } = options;
1149
+ const rng = createRng(seed);
1150
+ const id = fhirPatientIdentity(rng);
1151
+ const usCore = profile === "us-core";
1152
+ const props = [
1153
+ prop("resourceType", str("Patient")),
1154
+ prop("id", str(`syn-patient-${id.id}`))
1155
+ ];
1156
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.PATIENT])));
1157
+ props.push(
1158
+ prop(
1159
+ "text",
1160
+ narrative(
1161
+ `Synthetic patient ${id.person.given} ${id.person.family} (${id.gender}, born ${id.birthDate}).`
1162
+ )
1163
+ )
1164
+ );
1165
+ if (usCore) {
1166
+ const race = rng.pick(EXAMPLE_RACE_CATEGORIES);
1167
+ const ethnicity = rng.pick(EXAMPLE_ETHNICITY_CATEGORIES);
1168
+ const birthsex = id.gender === "male" ? "M" : "F";
1169
+ props.push(
1170
+ prop(
1171
+ "extension",
1172
+ fhir.list([
1173
+ ombExtension(US_CORE_RACE_EXTENSION, race),
1174
+ ombExtension(US_CORE_ETHNICITY_EXTENSION, ethnicity),
1175
+ fhir.complex([prop("url", str(US_CORE_BIRTHSEX_EXTENSION)), prop("valueCode", str(birthsex))])
1176
+ ])
1177
+ )
1178
+ );
1179
+ }
1180
+ props.push(prop("identifier", fhir.list([mrnIdentifier(id.mrn)])));
1181
+ props.push(prop("active", bool(true)));
1182
+ props.push(
1183
+ prop(
1184
+ "name",
1185
+ fhir.list([
1186
+ fhir.complex([
1187
+ prop("use", str("official")),
1188
+ prop("family", str(id.person.family)),
1189
+ prop("given", fhir.list([str(id.person.given)]))
1190
+ ])
1191
+ ])
1192
+ )
1193
+ );
1194
+ props.push(
1195
+ prop(
1196
+ "telecom",
1197
+ fhir.list([
1198
+ fhir.complex([
1199
+ prop("system", str("phone")),
1200
+ prop("value", str(id.phone)),
1201
+ prop("use", str("home"))
1202
+ ]),
1203
+ fhir.complex([prop("system", str("email")), prop("value", str(id.email))])
1204
+ ])
1205
+ )
1206
+ );
1207
+ props.push(prop("gender", str(id.gender)));
1208
+ props.push(prop("birthDate", str(id.birthDate)));
1209
+ props.push(
1210
+ prop(
1211
+ "address",
1212
+ fhir.list([
1213
+ fhir.complex([
1214
+ prop("use", str("home")),
1215
+ prop("line", fhir.list([str(id.address.street)])),
1216
+ prop("city", str(id.address.city)),
1217
+ prop("state", str(id.address.state)),
1218
+ prop("postalCode", str(id.address.zip))
1219
+ ])
1220
+ ])
1221
+ )
1222
+ );
1223
+ return fhir.complex(props);
1224
+ }
1225
+ function generateCondition(options = {}) {
1226
+ const { seed = 0, subject = "Patient/syn-patient-1", usCore = true } = options;
1227
+ const rng = createRng(seed);
1228
+ const code = rng.pick(EXAMPLE_CONDITIONS);
1229
+ const props = [
1230
+ prop("resourceType", str("Condition")),
1231
+ prop("id", str(`syn-cond-${rng.digits(8)}`))
1232
+ ];
1233
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.CONDITION])));
1234
+ props.push(prop("text", narrative(`Synthetic condition: ${code.display}.`)));
1235
+ props.push(
1236
+ prop(
1237
+ "clinicalStatus",
1238
+ codeableConcept({ system: SYSTEM.CONDITION_CLINICAL, code: "active", display: "Active" })
1239
+ )
1240
+ );
1241
+ props.push(
1242
+ prop(
1243
+ "verificationStatus",
1244
+ codeableConcept({
1245
+ system: SYSTEM.CONDITION_VER_STATUS,
1246
+ code: "confirmed",
1247
+ display: "Confirmed"
1248
+ })
1249
+ )
1250
+ );
1251
+ props.push(
1252
+ prop(
1253
+ "category",
1254
+ fhir.list([
1255
+ codeableConcept({
1256
+ system: SYSTEM.CONDITION_CATEGORY,
1257
+ code: "problem-list-item",
1258
+ display: "Problem List Item"
1259
+ })
1260
+ ])
1261
+ )
1262
+ );
1263
+ props.push(prop("code", codeableConcept(code)));
1264
+ props.push(prop("subject", reference(subject)));
1265
+ return fhir.complex(props);
1266
+ }
1267
+ function drawValue(rng, concept) {
1268
+ const span = concept.high - concept.low;
1269
+ const raw = concept.low + rng.float() * span;
1270
+ return raw.toFixed(concept.decimals);
1271
+ }
1272
+ function valueQuantity(rng, concept) {
1273
+ return fhir.complex([
1274
+ prop("value", dec(drawValue(rng, concept))),
1275
+ prop("unit", str(concept.unit)),
1276
+ prop("system", str(SYSTEM.UCUM)),
1277
+ prop("code", str(concept.unit))
1278
+ ]);
1279
+ }
1280
+ function buildObservation(seed, subject, usCore, profileUrl, category, pool, effective) {
1281
+ const rng = createRng(seed);
1282
+ const concept = rng.pick(pool);
1283
+ const props = [
1284
+ prop("resourceType", str("Observation")),
1285
+ prop("id", str(`syn-obs-${rng.digits(8)}`))
1286
+ ];
1287
+ if (usCore) props.push(prop("meta", meta([profileUrl])));
1288
+ props.push(
1289
+ prop("text", narrative(`Synthetic ${category.display.toLowerCase()}: ${concept.display}.`))
1290
+ );
1291
+ props.push(prop("status", str("final")));
1292
+ props.push(
1293
+ prop(
1294
+ "category",
1295
+ fhir.list([
1296
+ codeableConcept({
1297
+ system: SYSTEM.OBSERVATION_CATEGORY,
1298
+ code: category.code,
1299
+ display: category.display
1300
+ })
1301
+ ])
1302
+ )
1303
+ );
1304
+ props.push(prop("code", codeableConcept(concept)));
1305
+ props.push(prop("subject", reference(subject)));
1306
+ const y = rng.int(2020, 2025);
1307
+ const m = String(rng.int(1, 12)).padStart(2, "0");
1308
+ const d = String(rng.int(1, 28)).padStart(2, "0");
1309
+ if (effective) props.push(prop("effectiveDateTime", str(`${String(y)}-${m}-${d}`)));
1310
+ props.push(prop("valueQuantity", valueQuantity(rng, concept)));
1311
+ return fhir.complex(props);
1312
+ }
1313
+ function generateObservationLab(options = {}) {
1314
+ const { seed = 0, subject = "Patient/syn-patient-1", usCore = true } = options;
1315
+ return buildObservation(
1316
+ seed,
1317
+ subject,
1318
+ usCore,
1319
+ US_CORE_PROFILE.OBSERVATION_LAB,
1320
+ { code: "laboratory", display: "Laboratory" },
1321
+ EXAMPLE_LAB_OBSERVATIONS2,
1322
+ false
1323
+ );
1324
+ }
1325
+ function generateVitalSign(options = {}) {
1326
+ const { seed = 0, subject = "Patient/syn-patient-1", usCore = true } = options;
1327
+ return buildObservation(
1328
+ seed,
1329
+ subject,
1330
+ usCore,
1331
+ US_CORE_PROFILE.VITAL_SIGNS,
1332
+ { code: "vital-signs", display: "Vital Signs" },
1333
+ EXAMPLE_VITAL_SIGNS,
1334
+ true
1335
+ );
1336
+ }
1337
+ function generateMedicationRequest(options = {}) {
1338
+ const {
1339
+ seed = 0,
1340
+ subject = "Patient/syn-patient-1",
1341
+ requester = "Practitioner/syn-practitioner-1",
1342
+ usCore = true
1343
+ } = options;
1344
+ const rng = createRng(seed);
1345
+ const med = rng.pick(EXAMPLE_MEDICATIONS);
1346
+ const y = rng.int(2020, 2025);
1347
+ const m = String(rng.int(1, 12)).padStart(2, "0");
1348
+ const d = String(rng.int(1, 28)).padStart(2, "0");
1349
+ const props = [
1350
+ prop("resourceType", str("MedicationRequest")),
1351
+ prop("id", str(`syn-medreq-${rng.digits(8)}`))
1352
+ ];
1353
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.MEDICATION_REQUEST])));
1354
+ props.push(prop("text", narrative(`Synthetic medication order: ${med.display}.`)));
1355
+ props.push(prop("status", str("active")));
1356
+ props.push(prop("intent", str("order")));
1357
+ props.push(prop("medicationCodeableConcept", codeableConcept(med)));
1358
+ props.push(prop("subject", reference(subject)));
1359
+ props.push(prop("authoredOn", str(`${String(y)}-${m}-${d}`)));
1360
+ props.push(prop("requester", reference(requester)));
1361
+ return fhir.complex(props);
1362
+ }
1363
+ function generateEncounter(options = {}) {
1364
+ const { seed = 0, subject = "Patient/syn-patient-1", usCore = true } = options;
1365
+ const rng = createRng(seed);
1366
+ const cls = rng.pick(EXAMPLE_ENCOUNTER_CLASSES);
1367
+ const type = rng.pick(EXAMPLE_ENCOUNTER_TYPES);
1368
+ const id = safe.identifier(rng, "AN");
1369
+ const start = toFhirDate(safe.dateYmd(rng, 2018, 2024));
1370
+ const props = [
1371
+ prop("resourceType", str("Encounter")),
1372
+ prop("id", str(`syn-enc-${rng.digits(8)}`))
1373
+ ];
1374
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.ENCOUNTER])));
1375
+ props.push(prop("text", narrative(`Synthetic encounter: ${type.display}.`)));
1376
+ props.push(
1377
+ prop(
1378
+ "identifier",
1379
+ fhir.list([
1380
+ fhir.complex([
1381
+ prop("system", str(`urn:oid:${id.assigningAuthorityOid}`)),
1382
+ prop("value", str(id.value))
1383
+ ])
1384
+ ])
1385
+ )
1386
+ );
1387
+ props.push(prop("status", str("finished")));
1388
+ props.push(prop("class", coding(cls)));
1389
+ props.push(prop("type", fhir.list([codeableConcept(type)])));
1390
+ props.push(prop("subject", reference(subject)));
1391
+ props.push(prop("period", fhir.complex([prop("start", str(`${start}T09:00:00Z`))])));
1392
+ return fhir.complex(props);
1393
+ }
1394
+ function generateImmunization(options = {}) {
1395
+ const { seed = 0, patient = "Patient/syn-patient-1", usCore = true } = options;
1396
+ const rng = createRng(seed);
1397
+ const vaccine = rng.pick(EXAMPLE_VACCINES2);
1398
+ const occurrence = toFhirDate(safe.dateYmd(rng, 2015, 2024));
1399
+ const props = [
1400
+ prop("resourceType", str("Immunization")),
1401
+ prop("id", str(`syn-imm-${rng.digits(8)}`))
1402
+ ];
1403
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.IMMUNIZATION])));
1404
+ props.push(prop("text", narrative(`Synthetic immunization: ${vaccine.display}.`)));
1405
+ props.push(prop("status", str("completed")));
1406
+ props.push(prop("vaccineCode", codeableConcept(vaccine)));
1407
+ props.push(prop("patient", reference(patient)));
1408
+ props.push(prop("occurrenceDateTime", str(occurrence)));
1409
+ props.push(prop("primarySource", bool(true)));
1410
+ return fhir.complex(props);
1411
+ }
1412
+ function generateAllergyIntolerance(options = {}) {
1413
+ const { seed = 0, patient = "Patient/syn-patient-1", usCore = true } = options;
1414
+ const rng = createRng(seed);
1415
+ const allergen = rng.pick(EXAMPLE_ALLERGENS);
1416
+ const manifestation = rng.pick(EXAMPLE_ALLERGY_MANIFESTATIONS);
1417
+ const props = [
1418
+ prop("resourceType", str("AllergyIntolerance")),
1419
+ prop("id", str(`syn-allergy-${rng.digits(8)}`))
1420
+ ];
1421
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.ALLERGY_INTOLERANCE])));
1422
+ props.push(prop("text", narrative(`Synthetic allergy: ${allergen.display}.`)));
1423
+ props.push(
1424
+ prop(
1425
+ "clinicalStatus",
1426
+ codeableConcept({ system: SYSTEM.ALLERGY_CLINICAL, code: "active", display: "Active" })
1427
+ )
1428
+ );
1429
+ props.push(
1430
+ prop(
1431
+ "verificationStatus",
1432
+ codeableConcept({
1433
+ system: SYSTEM.ALLERGY_VERIFICATION,
1434
+ code: "confirmed",
1435
+ display: "Confirmed"
1436
+ })
1437
+ )
1438
+ );
1439
+ props.push(prop("code", codeableConcept(allergen)));
1440
+ props.push(prop("patient", reference(patient)));
1441
+ props.push(
1442
+ prop(
1443
+ "reaction",
1444
+ fhir.list([fhir.complex([prop("manifestation", fhir.list([codeableConcept(manifestation)]))])])
1445
+ )
1446
+ );
1447
+ return fhir.complex(props);
1448
+ }
1449
+ function generateProcedure(options = {}) {
1450
+ const { seed = 0, subject = "Patient/syn-patient-1", usCore = true } = options;
1451
+ const rng = createRng(seed);
1452
+ const code = rng.pick(EXAMPLE_PROCEDURES);
1453
+ const performed = toFhirDate(safe.dateYmd(rng, 2018, 2024));
1454
+ const props = [
1455
+ prop("resourceType", str("Procedure")),
1456
+ prop("id", str(`syn-proc-${rng.digits(8)}`))
1457
+ ];
1458
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.PROCEDURE])));
1459
+ props.push(prop("text", narrative(`Synthetic procedure: ${code.display}.`)));
1460
+ props.push(prop("status", str("completed")));
1461
+ props.push(prop("code", codeableConcept(code)));
1462
+ props.push(prop("subject", reference(subject)));
1463
+ props.push(prop("performedDateTime", str(`${performed}T10:00:00Z`)));
1464
+ return fhir.complex(props);
1465
+ }
1466
+ function generateDiagnosticReport(options = {}) {
1467
+ const { seed = 0, subject = "Patient/syn-patient-1", results = [], usCore = true } = options;
1468
+ const rng = createRng(seed);
1469
+ const code = rng.pick(EXAMPLE_DIAGNOSTIC_REPORTS);
1470
+ const day = toFhirDate(safe.dateYmd(rng, 2018, 2024));
1471
+ const props = [
1472
+ prop("resourceType", str("DiagnosticReport")),
1473
+ prop("id", str(`syn-dr-${rng.digits(8)}`))
1474
+ ];
1475
+ if (usCore) props.push(prop("meta", meta([US_CORE_PROFILE.DIAGNOSTIC_REPORT_LAB])));
1476
+ props.push(prop("text", narrative(`Synthetic laboratory report: ${code.display}.`)));
1477
+ props.push(prop("status", str("final")));
1478
+ props.push(
1479
+ prop(
1480
+ "category",
1481
+ fhir.list([
1482
+ codeableConcept({
1483
+ system: SYSTEM.DIAGNOSTIC_SERVICE_SECTION,
1484
+ code: "LAB",
1485
+ display: "Laboratory"
1486
+ })
1487
+ ])
1488
+ )
1489
+ );
1490
+ props.push(prop("code", codeableConcept(code)));
1491
+ props.push(prop("subject", reference(subject)));
1492
+ props.push(prop("effectiveDateTime", str(`${day}T08:30:00Z`)));
1493
+ props.push(prop("issued", str(`${day}T09:00:00.000Z`)));
1494
+ if (results.length > 0) {
1495
+ props.push(prop("result", fhir.list(results.map((r) => reference(r)))));
1496
+ }
1497
+ return fhir.complex(props);
1498
+ }
1499
+ function section(sec) {
1500
+ return fhir.complex([
1501
+ prop("title", str(sec.title)),
1502
+ prop("code", codeableConcept({ system: SYSTEM.LOINC, code: sec.code, display: sec.title })),
1503
+ prop("entry", fhir.list(sec.entries.map((e) => reference(e))))
1504
+ ]);
1505
+ }
1506
+ function buildComposition(rng, input) {
1507
+ const props = [
1508
+ prop("resourceType", str("Composition")),
1509
+ prop("id", str(`syn-comp-${rng.digits(8)}`)),
1510
+ prop("text", narrative("Synthetic continuity-of-care document summary.")),
1511
+ prop("status", str("final")),
1512
+ prop(
1513
+ "type",
1514
+ codeableConcept({
1515
+ system: SYSTEM.LOINC,
1516
+ code: "34133-9",
1517
+ display: "Summarization of Episode Note"
1518
+ })
1519
+ ),
1520
+ prop("subject", reference(input.subject)),
1521
+ prop("date", str(`${input.date}T09:00:00Z`)),
1522
+ prop("author", fhir.list([reference(input.organization)])),
1523
+ prop("title", str("Synthetic Continuity of Care Document")),
1524
+ prop("custodian", reference(input.organization)),
1525
+ prop("section", fhir.list(input.sections.map((s) => section(s))))
1526
+ ];
1527
+ return fhir.complex(props);
1528
+ }
1529
+
1530
+ // src/fhir/bundle.ts
1531
+ function resourceTypeOf(resource) {
1532
+ const rt = resource.properties.find((p) => p.name === "resourceType");
1533
+ return rt !== void 0 && rt.value.kind === "primitive" ? String(rt.value.value) : "Resource";
1534
+ }
1535
+ function buildOrganization(rng) {
1536
+ const id = safe.identifier(rng, "AN");
1537
+ return fhir.complex([
1538
+ prop("resourceType", str("Organization")),
1539
+ prop("id", str(`syn-org-${rng.digits(8)}`)),
1540
+ prop("text", narrative("Synthetic health organization.")),
1541
+ prop(
1542
+ "identifier",
1543
+ fhir.list([
1544
+ fhir.complex([
1545
+ prop("system", str(`urn:oid:${id.assigningAuthorityOid}`)),
1546
+ prop("value", str(id.value))
1547
+ ])
1548
+ ])
1549
+ ),
1550
+ prop("active", bool(true)),
1551
+ prop("name", str("Synthetic Health Organization"))
1552
+ ]);
1553
+ }
1554
+ function buildSpine(rng) {
1555
+ const patientUrl = `urn:uuid:${safe.uuid(rng)}`;
1556
+ const orgUrl = `urn:uuid:${safe.uuid(rng)}`;
1557
+ const date = toFhirDate(safe.dateYmd(rng, 2018, 2024));
1558
+ const patient = {
1559
+ fullUrl: patientUrl,
1560
+ resource: generatePatient({ seed: rng.nextUint32(), profile: "us-core" })
1561
+ };
1562
+ const org = { fullUrl: orgUrl, resource: buildOrganization(rng) };
1563
+ const condUrl = `urn:uuid:${safe.uuid(rng)}`;
1564
+ const cond = generateCondition({ seed: rng.nextUint32(), subject: patientUrl });
1565
+ const labUrl = `urn:uuid:${safe.uuid(rng)}`;
1566
+ const lab = generateObservationLab({ seed: rng.nextUint32(), subject: patientUrl });
1567
+ const vitalUrl = `urn:uuid:${safe.uuid(rng)}`;
1568
+ const vital = generateVitalSign({ seed: rng.nextUint32(), subject: patientUrl });
1569
+ const medUrl = `urn:uuid:${safe.uuid(rng)}`;
1570
+ const med = generateMedicationRequest({
1571
+ seed: rng.nextUint32(),
1572
+ subject: patientUrl,
1573
+ requester: orgUrl
1574
+ });
1575
+ const encUrl = `urn:uuid:${safe.uuid(rng)}`;
1576
+ const enc = generateEncounter({ seed: rng.nextUint32(), subject: patientUrl });
1577
+ const immUrl = `urn:uuid:${safe.uuid(rng)}`;
1578
+ const imm = generateImmunization({ seed: rng.nextUint32(), patient: patientUrl });
1579
+ const allergyUrl = `urn:uuid:${safe.uuid(rng)}`;
1580
+ const allergy = generateAllergyIntolerance({ seed: rng.nextUint32(), patient: patientUrl });
1581
+ const procUrl = `urn:uuid:${safe.uuid(rng)}`;
1582
+ const proc = generateProcedure({ seed: rng.nextUint32(), subject: patientUrl });
1583
+ const drUrl = `urn:uuid:${safe.uuid(rng)}`;
1584
+ const dr = generateDiagnosticReport({
1585
+ seed: rng.nextUint32(),
1586
+ subject: patientUrl,
1587
+ results: [labUrl]
1588
+ });
1589
+ const entries = [
1590
+ patient,
1591
+ org,
1592
+ { fullUrl: condUrl, resource: cond },
1593
+ { fullUrl: labUrl, resource: lab },
1594
+ { fullUrl: vitalUrl, resource: vital },
1595
+ { fullUrl: medUrl, resource: med },
1596
+ { fullUrl: encUrl, resource: enc },
1597
+ { fullUrl: immUrl, resource: imm },
1598
+ { fullUrl: allergyUrl, resource: allergy },
1599
+ { fullUrl: procUrl, resource: proc },
1600
+ { fullUrl: drUrl, resource: dr }
1601
+ ];
1602
+ const urls = {
1603
+ condition: condUrl,
1604
+ lab: labUrl,
1605
+ vital: vitalUrl,
1606
+ medication: medUrl,
1607
+ encounter: encUrl,
1608
+ immunization: immUrl,
1609
+ allergy: allergyUrl,
1610
+ procedure: procUrl,
1611
+ diagnosticReport: drUrl
1612
+ };
1613
+ return { patientUrl, orgUrl, date, urls, entries };
1614
+ }
1615
+ function documentSections(urls) {
1616
+ const at = (k) => urls[k] !== void 0 ? [urls[k]] : [];
1617
+ return [
1618
+ { code: "11450-4", title: "Problem List", entries: at("condition") },
1619
+ {
1620
+ code: "30954-2",
1621
+ title: "Relevant Diagnostic Tests/Laboratory Data",
1622
+ entries: [...at("diagnosticReport"), ...at("lab"), ...at("vital")]
1623
+ },
1624
+ { code: "10160-0", title: "History of Medication Use", entries: at("medication") },
1625
+ { code: "48765-2", title: "Allergies and Adverse Reactions", entries: at("allergy") },
1626
+ { code: "11369-6", title: "History of Immunizations", entries: at("immunization") },
1627
+ { code: "47519-4", title: "History of Procedures", entries: at("procedure") },
1628
+ { code: "46240-8", title: "History of Encounters", entries: at("encounter") }
1629
+ ];
1630
+ }
1631
+ function generateBundle(options = {}) {
1632
+ const { seed = 0, type = "collection" } = options;
1633
+ const rng = createRng(seed);
1634
+ const spine = buildSpine(rng);
1635
+ const members = type === "document" ? [
1636
+ {
1637
+ fullUrl: `urn:uuid:${safe.uuid(rng)}`,
1638
+ resource: buildComposition(rng, {
1639
+ subject: spine.patientUrl,
1640
+ organization: spine.orgUrl,
1641
+ date: spine.date,
1642
+ sections: documentSections(spine.urls)
1643
+ })
1644
+ },
1645
+ ...spine.entries
1646
+ ] : [...spine.entries];
1647
+ const entries = members.map((member) => {
1648
+ const entryProps = [
1649
+ prop("fullUrl", str(member.fullUrl)),
1650
+ prop("resource", member.resource)
1651
+ ];
1652
+ if (type === "transaction") {
1653
+ entryProps.push(
1654
+ prop(
1655
+ "request",
1656
+ fhir.complex([prop("method", str("POST")), prop("url", str(resourceTypeOf(member.resource)))])
1657
+ )
1658
+ );
1659
+ }
1660
+ return fhir.complex(entryProps);
1661
+ });
1662
+ const props = [
1663
+ prop("resourceType", str("Bundle")),
1664
+ prop("id", str(`syn-bundle-${rng.digits(8)}`))
1665
+ ];
1666
+ if (type === "document") {
1667
+ const id = safe.identifier(rng, "AN");
1668
+ props.push(
1669
+ prop(
1670
+ "identifier",
1671
+ fhir.complex([
1672
+ prop("system", str(`urn:oid:${id.assigningAuthorityOid}`)),
1673
+ prop("value", str(`urn:uuid:${safe.uuid(rng)}`))
1674
+ ])
1675
+ )
1676
+ );
1677
+ }
1678
+ props.push(prop("type", str(type)));
1679
+ if (type === "document") props.push(prop("timestamp", str(`${spine.date}T09:00:00.000Z`)));
1680
+ props.push(prop("entry", fhir.list(entries)));
1681
+ return fhir.complex(props);
1682
+ }
1683
+ function dec2(value) {
1684
+ const d = x12.X12Decimal.fromString(value);
1685
+ if (d === void 0) throw new Error(`invalid synthetic decimal: ${value}`);
1686
+ return d;
1687
+ }
1688
+ function money(n) {
1689
+ return `${String(n)}.00`;
1690
+ }
1691
+
1692
+ // src/x12/identity.ts
1693
+ var SYNTHETIC_ORG_NAMES = Object.freeze([
1694
+ "SYNTH BILLING GROUP",
1695
+ "FIXTURE CLINIC INC",
1696
+ "PLACEHOLDER MEDICAL CTR",
1697
+ "SAMPLE HEALTH PARTNERS",
1698
+ "MOCK CARE ASSOCIATES",
1699
+ "PROTOTYPE PHYSICIANS LLC"
1700
+ ]);
1701
+ var SYNTHETIC_PAYER_NAMES = Object.freeze([
1702
+ "SYNTHCARE HEALTH PLAN",
1703
+ "FIXTURE MUTUAL INSURANCE",
1704
+ "PLACEHOLDER BENEFIT ADMIN",
1705
+ "SAMPLE STATE MEDICAID",
1706
+ "MOCK NATIONAL INSURER"
1707
+ ]);
1708
+ function x12Person(rng) {
1709
+ const person = safe.name(rng);
1710
+ const memberId = `MBR${safe.identifier(rng, "MB").value}`;
1711
+ const dob = safe.dateYmd(rng, 1935, 2010);
1712
+ const sex = rng.pick(["M", "F"]);
1713
+ const address2 = safe.address(rng);
1714
+ return { person, memberId, dob, sex, address: address2 };
1715
+ }
1716
+ function x12Organization(rng) {
1717
+ const name2 = rng.pick(SYNTHETIC_ORG_NAMES);
1718
+ const npiValue = safe.npi(rng);
1719
+ const taxIdSsn = safe.ssn(rng).replace(/\D/g, "");
1720
+ const address2 = safe.address(rng);
1721
+ return { name: name2, npi: npiValue, taxIdSsn, address: address2 };
1722
+ }
1723
+ function x12ProviderPerson(rng) {
1724
+ const person = safe.name(rng);
1725
+ const npiValue = safe.npi(rng);
1726
+ return { person, npi: npiValue };
1727
+ }
1728
+ function x12Payer(rng) {
1729
+ const name2 = rng.pick(SYNTHETIC_PAYER_NAMES);
1730
+ const payerId = `SYN${rng.digits(5)}`;
1731
+ return { name: name2, payerId };
1732
+ }
1733
+ function x12TradingPartners(rng) {
1734
+ return { senderId: `SYNSUB${rng.digits(3)}`, receiverId: `SYNRCV${rng.digits(3)}` };
1735
+ }
1736
+ function x12EnvelopeTiming(rng) {
1737
+ const serviceDate2 = safe.dateYmd(rng, 2024, 2026);
1738
+ const yy = serviceDate2.slice(2, 4);
1739
+ const mmdd = serviceDate2.slice(4, 8);
1740
+ const hh = String(rng.int(0, 23)).padStart(2, "0");
1741
+ const mi = String(rng.int(0, 59)).padStart(2, "0");
1742
+ return {
1743
+ interchangeDate: `${yy}${mmdd}`,
1744
+ interchangeTime: `${hh}${mi}`,
1745
+ interchangeControlNumber: rng.digits(9),
1746
+ groupControlNumber: String(rng.int(1, 99999)),
1747
+ transactionSetControlNumber: rng.digits(4),
1748
+ serviceDate: serviceDate2
1749
+ };
1750
+ }
1751
+
1752
+ // src/x12/example-codes.ts
1753
+ var PROFESSIONAL_PROCEDURES = Object.freeze([
1754
+ { code: "99213", label: "office/outpatient visit, established patient" },
1755
+ { code: "99214", label: "office/outpatient visit, established patient, moderate" },
1756
+ { code: "99203", label: "office/outpatient visit, new patient" },
1757
+ { code: "85025", label: "complete blood count with differential" },
1758
+ { code: "80053", label: "comprehensive metabolic panel" },
1759
+ { code: "93000", label: "electrocardiogram, routine" }
1760
+ ]);
1761
+ var PROCEDURE_MODIFIERS = Object.freeze(["25", "59", "76", "GT"]);
1762
+ var PLACES_OF_SERVICE = Object.freeze(["11", "22", "21", "12", "49"]);
1763
+ var DIAGNOSES = Object.freeze([
1764
+ { code: "J20.9", label: "acute bronchitis, unspecified" },
1765
+ { code: "E11.9", label: "type 2 diabetes mellitus without complications" },
1766
+ { code: "I10", label: "essential (primary) hypertension" },
1767
+ { code: "M54.5", label: "low back pain" },
1768
+ { code: "R07.9", label: "chest pain, unspecified" },
1769
+ { code: "Z00.00", label: "general adult medical exam without abnormal findings" }
1770
+ ]);
1771
+ var REVENUE_CODES = Object.freeze([
1772
+ { code: "0120", label: "room & board, semi-private" },
1773
+ { code: "0300", label: "laboratory, general" },
1774
+ { code: "0450", label: "emergency room, general" },
1775
+ { code: "0636", label: "drugs requiring detailed coding" }
1776
+ ]);
1777
+ var INSTITUTIONAL_PROCEDURES = Object.freeze([
1778
+ { code: "99221", label: "initial hospital care, per day" },
1779
+ { code: "99231", label: "subsequent hospital care, per day" }
1780
+ ]);
1781
+ var DENTAL_PROCEDURES = Object.freeze([
1782
+ { code: "D2391", label: "resin-based composite, one surface, posterior" },
1783
+ { code: "D1110", label: "prophylaxis, adult" },
1784
+ { code: "D0120", label: "periodic oral evaluation" }
1785
+ ]);
1786
+ var TOOTH_CODES = Object.freeze(["14", "3", "19", "30"]);
1787
+ var TOOTH_SURFACES = Object.freeze(["M", "O", "D", "B", "L"]);
1788
+ var SERVICE_TYPE_CODES = Object.freeze(["30", "1", "35", "88", "98"]);
1789
+
1790
+ // src/x12/claim-837.ts
1791
+ function serviceDtp(serviceDate2) {
1792
+ return { qualifier: "472", formatQualifier: "D8", value: serviceDate2 };
1793
+ }
1794
+ function envelopeOf(partners, timing) {
1795
+ return {
1796
+ senderId: partners.senderId,
1797
+ receiverId: partners.receiverId,
1798
+ interchangeDate: timing.interchangeDate,
1799
+ interchangeTime: timing.interchangeTime,
1800
+ interchangeControlNumber: timing.interchangeControlNumber,
1801
+ groupControlNumber: timing.groupControlNumber,
1802
+ transactionSetControlNumber: timing.transactionSetControlNumber,
1803
+ usageIndicator: "T"
1804
+ };
1805
+ }
1806
+ function professionalLine(rng, serviceDate2) {
1807
+ const charge = dec2(`${String(rng.int(75, 400))}.00`);
1808
+ const line = {
1809
+ variant: "P",
1810
+ procedureQualifier: "HC",
1811
+ procedureCode: rng.pick(PROFESSIONAL_PROCEDURES).code,
1812
+ ...rng.bool(0.4) ? { modifiers: [rng.pick(PROCEDURE_MODIFIERS)] } : {},
1813
+ charge,
1814
+ unitOfMeasure: "UN",
1815
+ units: dec2("1"),
1816
+ placeOfServiceCode: rng.pick(PLACES_OF_SERVICE),
1817
+ diagnosisPointers: ["1"],
1818
+ dates: [serviceDtp(serviceDate2)]
1819
+ };
1820
+ return { line, charge };
1821
+ }
1822
+ function institutionalLine(rng, serviceDate2) {
1823
+ const charge = dec2(`${String(rng.int(500, 5e3))}.00`);
1824
+ const line = {
1825
+ variant: "I",
1826
+ revenueCode: rng.pick(REVENUE_CODES).code,
1827
+ procedureQualifier: "HC",
1828
+ procedureCode: rng.pick(INSTITUTIONAL_PROCEDURES).code,
1829
+ charge,
1830
+ unitOfMeasure: "UN",
1831
+ units: dec2("1"),
1832
+ dates: [serviceDtp(serviceDate2)]
1833
+ };
1834
+ return { line, charge };
1835
+ }
1836
+ function dentalLine(rng, serviceDate2) {
1837
+ const charge = dec2(`${String(rng.int(80, 900))}.00`);
1838
+ const line = {
1839
+ variant: "D",
1840
+ procedureQualifier: "AD",
1841
+ procedureCode: rng.pick(DENTAL_PROCEDURES).code,
1842
+ charge,
1843
+ units: dec2("1"),
1844
+ placeOfServiceCode: "11",
1845
+ toothInformation: [
1846
+ { qualifier: "JP", toothCode: rng.pick(TOOTH_CODES), surfaces: [rng.pick(TOOTH_SURFACES)] }
1847
+ ],
1848
+ dates: [serviceDtp(serviceDate2)]
1849
+ };
1850
+ return { line, charge };
1851
+ }
1852
+ function claimOf(rng, variant, serviceDate2) {
1853
+ const lineCount = rng.int(1, 2);
1854
+ const built = Array.from({ length: lineCount }, () => {
1855
+ if (variant === "P") return professionalLine(rng, serviceDate2);
1856
+ if (variant === "I") return institutionalLine(rng, serviceDate2);
1857
+ return dentalLine(rng, serviceDate2);
1858
+ });
1859
+ const total = built.reduce((acc, b) => acc.add(b.charge), dec2("0"));
1860
+ const diagnosis = rng.pick(DIAGNOSES).code;
1861
+ const secondary = rng.pick(DIAGNOSES).code;
1862
+ return {
1863
+ claimId: `PTACCT${rng.digits(6)}`,
1864
+ totalCharge: total,
1865
+ placeOfServiceCode: variant === "P" ? rng.pick(PLACES_OF_SERVICE) : "11",
1866
+ facilityCodeQualifier: "B",
1867
+ claimFrequencyCode: "1",
1868
+ providerSignatureOnFile: "Y",
1869
+ providerAcceptAssignment: "A",
1870
+ benefitsAssignment: "Y",
1871
+ releaseOfInformationCode: "Y",
1872
+ diagnoses: [
1873
+ { qualifier: "ABK", code: diagnosis },
1874
+ { qualifier: "ABF", code: secondary }
1875
+ ],
1876
+ dates: [{ qualifier: "431", formatQualifier: "D8", value: serviceDate2 }],
1877
+ serviceLines: built.map((b) => b.line)
1878
+ };
1879
+ }
1880
+ function specOf(rng, variant) {
1881
+ const partners = x12TradingPartners(rng);
1882
+ const timing = x12EnvelopeTiming(rng);
1883
+ const envelope = envelopeOf(partners, timing);
1884
+ const org = x12Organization(rng);
1885
+ const subscriberPerson = x12Person(rng);
1886
+ const rendering = x12ProviderPerson(rng);
1887
+ const payer = x12Payer(rng);
1888
+ const claim = claimOf(rng, variant, timing.serviceDate);
1889
+ const subscriber = {
1890
+ info: {
1891
+ payerResponsibilityCode: "P",
1892
+ individualRelationshipCode: "18",
1893
+ // self
1894
+ groupNumber: `GRP${rng.digits(5)}`,
1895
+ claimFilingIndicator: "MB"
1896
+ },
1897
+ subscriber: {
1898
+ entityIdentifierCode: "IL",
1899
+ entityTypeQualifier: "1",
1900
+ name: subscriberPerson.person.family,
1901
+ firstName: subscriberPerson.person.given,
1902
+ idQualifier: "MI",
1903
+ idCode: subscriberPerson.memberId,
1904
+ address: {
1905
+ lines: [subscriberPerson.address.street],
1906
+ city: subscriberPerson.address.city,
1907
+ state: subscriberPerson.address.state,
1908
+ postalCode: subscriberPerson.address.zip
1909
+ }
1910
+ },
1911
+ payer: {
1912
+ entityIdentifierCode: "PR",
1913
+ entityTypeQualifier: "2",
1914
+ name: payer.name,
1915
+ idQualifier: "PI",
1916
+ idCode: payer.payerId
1917
+ },
1918
+ claims: [
1919
+ {
1920
+ ...claim,
1921
+ // Rendering provider (Loop 2310B, NM1 fields round-trip) — a person with an invalid-Luhn NPI.
1922
+ providers: [
1923
+ {
1924
+ entityIdentifierCode: "82",
1925
+ entityTypeQualifier: "1",
1926
+ name: rendering.person.family,
1927
+ firstName: rendering.person.given,
1928
+ idQualifier: "XX",
1929
+ idCode: rendering.npi
1930
+ }
1931
+ ]
1932
+ }
1933
+ ]
1934
+ };
1935
+ const billingProvider = {
1936
+ provider: {
1937
+ entityIdentifierCode: "85",
1938
+ entityTypeQualifier: "2",
1939
+ name: org.name,
1940
+ idQualifier: "XX",
1941
+ idCode: org.npi,
1942
+ address: {
1943
+ lines: [org.address.street],
1944
+ city: org.address.city,
1945
+ state: org.address.state,
1946
+ postalCode: org.address.zip
1947
+ },
1948
+ // Provider tax id as a never-issued (900-range) SSN at REF*SY — provably synthetic (roadmap §4.1).
1949
+ references: [{ qualifier: "SY", value: org.taxIdSsn }]
1950
+ },
1951
+ subscribers: [subscriber]
1952
+ };
1953
+ return {
1954
+ envelope,
1955
+ submitter: {
1956
+ entityIdentifierCode: "41",
1957
+ entityTypeQualifier: "2",
1958
+ name: org.name,
1959
+ idQualifier: "46",
1960
+ idCode: envelope.senderId
1961
+ },
1962
+ receiver: {
1963
+ entityIdentifierCode: "40",
1964
+ entityTypeQualifier: "2",
1965
+ name: payer.name,
1966
+ idQualifier: "46",
1967
+ idCode: envelope.receiverId
1968
+ },
1969
+ billingProviders: [billingProvider]
1970
+ };
1971
+ }
1972
+ function generate837(variant, options) {
1973
+ const rng = createRng(options.seed);
1974
+ const spec = specOf(rng, variant);
1975
+ if (variant === "P") return x12.build837P(spec);
1976
+ if (variant === "I") return x12.build837I(spec);
1977
+ return x12.build837D(spec);
1978
+ }
1979
+ function generate837P(options) {
1980
+ return generate837("P", options);
1981
+ }
1982
+ function generate837I(options) {
1983
+ return generate837("I", options);
1984
+ }
1985
+ function generate837D(options) {
1986
+ return generate837("D", options);
1987
+ }
1988
+ function generate835(options) {
1989
+ const rng = createRng(options.seed);
1990
+ const partners = x12TradingPartners(rng);
1991
+ const timing = x12EnvelopeTiming(rng);
1992
+ const patient = x12Person(rng);
1993
+ const org = x12Organization(rng);
1994
+ const payer = x12Payer(rng);
1995
+ const chargeN = rng.int(200, 2e3);
1996
+ const patientRespN = rng.int(10, Math.min(chargeN - 1, 150));
1997
+ const paymentN = chargeN - patientRespN;
1998
+ const casReason = rng.pick(["1", "2", "3"]);
1999
+ const line = {
2000
+ productServiceIdQualifier: "HC",
2001
+ productServiceId: rng.pick(PROFESSIONAL_PROCEDURES).code,
2002
+ ...rng.bool(0.4) ? { modifiers: [rng.pick(PROCEDURE_MODIFIERS)] } : {},
2003
+ chargeAmount: dec2(money(chargeN)),
2004
+ paymentAmount: dec2(money(paymentN)),
2005
+ serviceDateStart: timing.serviceDate,
2006
+ serviceDateEnd: timing.serviceDate,
2007
+ adjustments: [{ groupCode: "PR", reasonCode: casReason, amount: dec2(money(patientRespN)) }],
2008
+ amounts: [{ qualifier: "B6", amount: dec2(money(paymentN)) }]
2009
+ };
2010
+ const claim = {
2011
+ patientControlNumber: `PTACCT${rng.digits(6)}`,
2012
+ claimStatusCode: "1",
2013
+ // processed as primary
2014
+ totalChargeAmount: dec2(money(chargeN)),
2015
+ totalPaymentAmount: dec2(money(paymentN)),
2016
+ patientResponsibilityAmount: dec2(money(patientRespN)),
2017
+ claimFilingIndicatorCode: "MB",
2018
+ payerClaimControlNumber: `ICN${rng.digits(9)}`,
2019
+ facilityTypeCode: "11",
2020
+ claimFrequencyCode: "1",
2021
+ patient: {
2022
+ entityIdentifierCode: "QC",
2023
+ lastName: patient.person.family,
2024
+ firstName: patient.person.given,
2025
+ idQualifier: "MI",
2026
+ idCode: patient.memberId
2027
+ },
2028
+ serviceProvider: {
2029
+ entityIdentifierCode: "82",
2030
+ name: org.name,
2031
+ idQualifier: "XX",
2032
+ idCode: org.npi
2033
+ },
2034
+ servicePeriodStart: timing.serviceDate,
2035
+ servicePeriodEnd: timing.serviceDate,
2036
+ serviceLines: [line]
2037
+ };
2038
+ const spec = {
2039
+ envelope: {
2040
+ senderId: partners.senderId,
2041
+ receiverId: partners.receiverId,
2042
+ interchangeDate: timing.interchangeDate,
2043
+ interchangeTime: timing.interchangeTime,
2044
+ interchangeControlNumber: timing.interchangeControlNumber,
2045
+ groupControlNumber: timing.groupControlNumber,
2046
+ transactionSetControlNumber: timing.transactionSetControlNumber,
2047
+ usageIndicator: "T"
2048
+ },
2049
+ payment: {
2050
+ transactionHandlingCode: "I",
2051
+ totalActualPayment: dec2(money(paymentN)),
2052
+ creditDebitFlag: "C",
2053
+ method: "ACH",
2054
+ paymentDate: timing.serviceDate
2055
+ },
2056
+ traces: [
2057
+ {
2058
+ traceTypeCode: "1",
2059
+ referenceId: rng.digits(7),
2060
+ originatingCompanyId: `1${rng.digits(9)}`
2061
+ }
2062
+ ],
2063
+ payer: {
2064
+ entityIdentifierCode: "PR",
2065
+ name: payer.name,
2066
+ address: {
2067
+ lines: [org.address.street],
2068
+ city: org.address.city,
2069
+ state: org.address.state,
2070
+ postalCode: org.address.zip
2071
+ },
2072
+ additionalIdentifiers: [{ qualifier: "2U", value: payer.payerId }]
2073
+ },
2074
+ payee: {
2075
+ entityIdentifierCode: "PE",
2076
+ name: org.name,
2077
+ idQualifier: "XX",
2078
+ idCode: org.npi,
2079
+ address: {
2080
+ lines: [org.address.street],
2081
+ city: org.address.city,
2082
+ state: org.address.state,
2083
+ postalCode: org.address.zip
2084
+ }
2085
+ },
2086
+ claims: [claim]
2087
+ };
2088
+ return x12.build835(spec);
2089
+ }
2090
+ function generate271(options) {
2091
+ const rng = createRng(options.seed);
2092
+ const partners = x12TradingPartners(rng);
2093
+ const timing = x12EnvelopeTiming(rng);
2094
+ const subscriber = x12Person(rng);
2095
+ const providerOrg = x12Organization(rng);
2096
+ const payer = x12Payer(rng);
2097
+ const serviceTypes = [
2098
+ { code: rng.pick(SERVICE_TYPE_CODES) },
2099
+ { code: rng.pick(SERVICE_TYPE_CODES) }
2100
+ ];
2101
+ const spec = {
2102
+ envelope: {
2103
+ senderId: partners.senderId,
2104
+ receiverId: partners.receiverId,
2105
+ interchangeDate: timing.interchangeDate,
2106
+ interchangeTime: timing.interchangeTime,
2107
+ interchangeControlNumber: timing.interchangeControlNumber,
2108
+ groupControlNumber: timing.groupControlNumber,
2109
+ transactionSetControlNumber: timing.transactionSetControlNumber,
2110
+ usageIndicator: "T"
2111
+ },
2112
+ informationSources: [
2113
+ {
2114
+ entity: {
2115
+ entityIdentifierCode: "PR",
2116
+ entityTypeQualifier: "2",
2117
+ name: payer.name,
2118
+ idQualifier: "PI",
2119
+ idCode: payer.payerId
2120
+ },
2121
+ receivers: [
2122
+ {
2123
+ entity: {
2124
+ entityIdentifierCode: "1P",
2125
+ entityTypeQualifier: "2",
2126
+ name: providerOrg.name,
2127
+ idQualifier: "XX",
2128
+ idCode: providerOrg.npi
2129
+ },
2130
+ subscribers: [
2131
+ {
2132
+ traces: [{ traceTypeCode: "2", referenceId: `ELIG${rng.digits(10)}` }],
2133
+ name: {
2134
+ entityIdentifierCode: "IL",
2135
+ entityTypeQualifier: "1",
2136
+ lastName: subscriber.person.family,
2137
+ firstName: subscriber.person.given,
2138
+ idQualifier: "MI",
2139
+ idCode: subscriber.memberId,
2140
+ address: {
2141
+ lines: [subscriber.address.street],
2142
+ city: subscriber.address.city,
2143
+ state: subscriber.address.state,
2144
+ postalCode: subscriber.address.zip
2145
+ },
2146
+ dateOfBirth: subscriber.dob,
2147
+ genderCode: subscriber.sex
2148
+ },
2149
+ references: [{ qualifier: "6P", value: `GRP${rng.digits(5)}` }],
2150
+ dates: [{ qualifier: "307", formatQualifier: "D8", value: timing.serviceDate }],
2151
+ benefits: [
2152
+ {
2153
+ eligibilityCode: "1",
2154
+ // active coverage
2155
+ coverageLevelCode: "IND",
2156
+ serviceTypeCodes: serviceTypes,
2157
+ inPlanNetwork: "Y",
2158
+ monetaryAmount: dec2(money(rng.int(500, 5e3))),
2159
+ percent: dec2(String(rng.pick([80, 90, 100])))
2160
+ }
2161
+ ]
2162
+ }
2163
+ ]
2164
+ }
2165
+ ]
2166
+ }
2167
+ ]
2168
+ };
2169
+ return x12.build271(spec);
2170
+ }
2171
+
2172
+ // src/ncpdp/identity.ts
2173
+ var SYNTHETIC_PHARMACY_NAMES = Object.freeze([
2174
+ "SYNTH COMMUNITY PHARMACY",
2175
+ "FIXTURE DRUG MART",
2176
+ "PLACEHOLDER RX SERVICES",
2177
+ "SAMPLE APOTHECARY LLC",
2178
+ "MOCK PHARMACY GROUP"
2179
+ ]);
2180
+ function ncpdpPatient(rng) {
2181
+ const person = safe.name(rng);
2182
+ const dob = safe.dateYmd(rng, 1935, 2010);
2183
+ const gender = rng.pick(["1", "2"]);
2184
+ const patientId = `MBR${safe.identifier(rng, "MR").value}`;
2185
+ const phone2 = safe.phone(rng);
2186
+ const address2 = safe.address(rng);
2187
+ return { person, dob, gender, patientId, phone: phone2, address: address2 };
2188
+ }
2189
+ function ncpdpPrescriber(rng) {
2190
+ const person = safe.name(rng);
2191
+ const npi2 = safe.npi(rng);
2192
+ const dea2 = safe.dea(rng, person);
2193
+ return { person, npi: npi2, dea: dea2 };
2194
+ }
2195
+ function ncpdpPharmacy(rng) {
2196
+ const businessName = rng.pick(SYNTHETIC_PHARMACY_NAMES);
2197
+ const npi2 = safe.npi(rng);
2198
+ const ncpdpId = rng.digits(7);
2199
+ return { businessName, npi: npi2, ncpdpId };
2200
+ }
2201
+ function ncpdpCardholder(rng) {
2202
+ const person = safe.name(rng);
2203
+ const cardholderId = `MBR${safe.identifier(rng, "MB").value}`;
2204
+ const groupId = `GRP${rng.digits(5)}`;
2205
+ const personCode = rng.pick(["01", "02", "03"]);
2206
+ return { person, cardholderId, groupId, personCode };
2207
+ }
2208
+
2209
+ // src/ncpdp/example-codes.ts
2210
+ var EXAMPLE_DRUGS = Object.freeze([
2211
+ { description: "Amoxicillin 500 MG Oral Capsule", ndc: "00000010101", form: "EA" },
2212
+ { description: "Lisinopril 10 MG Oral Tablet", ndc: "00000020202", form: "EA" },
2213
+ { description: "Atorvastatin 20 MG Oral Tablet", ndc: "00000030303", form: "EA" },
2214
+ { description: "Metformin 500 MG Oral Tablet", ndc: "00000040404", form: "EA" },
2215
+ { description: "Amlodipine 5 MG Oral Tablet", ndc: "00000050505", form: "EA" },
2216
+ { description: "Omeprazole 20 MG Delayed Release Capsule", ndc: "00000060606", form: "EA" },
2217
+ { description: "Levothyroxine 50 MCG Oral Tablet", ndc: "00000070707", form: "EA" },
2218
+ { description: "Azithromycin 250 MG Oral Tablet", ndc: "00000080808", form: "EA" },
2219
+ { description: "Sertraline 50 MG Oral Tablet", ndc: "00000090909", form: "EA" },
2220
+ { description: "Albuterol 90 MCG Metered Dose Inhaler", ndc: "00000101010", form: "EA" }
2221
+ ]);
2222
+ var DAW_CODES = Object.freeze(["0", "1", "2"]);
2223
+ var SYNTHETIC_BIN = "999999";
2224
+ function digitsOnly(value) {
2225
+ return value.replace(/\D/g, "");
2226
+ }
2227
+ function header(rng, transactionCode, pharmacyNpi) {
2228
+ const date = serviceDate(rng);
2229
+ return {
2230
+ binNumber: SYNTHETIC_BIN,
2231
+ versionRelease: "D0",
2232
+ transactionCode,
2233
+ processorControlNumber: `SYN${rng.digits(4)}`,
2234
+ transactionCount: "1",
2235
+ serviceProviderIdQualifier: "01",
2236
+ // 01 = NPI
2237
+ serviceProviderId: pharmacyNpi,
2238
+ dateOfService: date,
2239
+ softwareCertificationId: `SW${rng.digits(6)}`
2240
+ };
2241
+ }
2242
+ function serviceDate(rng) {
2243
+ const year = rng.int(2024, 2026);
2244
+ const month = rng.int(1, 12);
2245
+ const day = rng.int(1, 28);
2246
+ return `${String(year)}${String(month).padStart(2, "0")}${String(day).padStart(2, "0")}`;
2247
+ }
2248
+ function field(id, value) {
2249
+ return { id, value };
2250
+ }
2251
+ function patientSegment(rng) {
2252
+ const p = ncpdpPatient(rng);
2253
+ return {
2254
+ segmentId: "01",
2255
+ fields: [
2256
+ field("C4", p.dob),
2257
+ field("C5", p.gender),
2258
+ field("CA", p.person.given),
2259
+ field("CB", p.person.family),
2260
+ field("CM", p.address.street),
2261
+ field("CQ", digitsOnly(p.phone)),
2262
+ field("CY", p.patientId)
2263
+ ]
2264
+ };
2265
+ }
2266
+ function insuranceSegment(rng) {
2267
+ const c = ncpdpCardholder(rng);
2268
+ return {
2269
+ segmentId: "04",
2270
+ fields: [
2271
+ field("C2", c.cardholderId),
2272
+ field("C1", c.groupId),
2273
+ field("C3", c.personCode),
2274
+ field("CC", c.person.given),
2275
+ field("CD", c.person.family)
2276
+ ]
2277
+ };
2278
+ }
2279
+ function prescriberSegment(rng) {
2280
+ const dr = ncpdpPrescriber(rng);
2281
+ return {
2282
+ segmentId: "03",
2283
+ fields: [field("EZ", "01"), field("DB", dr.npi)]
2284
+ };
2285
+ }
2286
+ function claimSegment(rng, minimal) {
2287
+ const drug = rng.pick(EXAMPLE_DRUGS);
2288
+ const rxRef = `RX${rng.digits(7)}`;
2289
+ const fill = String(rng.int(0, 5));
2290
+ if (minimal) {
2291
+ return {
2292
+ segmentId: "07",
2293
+ fields: [field("EM", "1"), field("D2", rxRef), field("D3", fill)]
2294
+ };
2295
+ }
2296
+ return {
2297
+ segmentId: "07",
2298
+ fields: [
2299
+ field("EM", "1"),
2300
+ // 1 = Rx Billing
2301
+ field("D2", rxRef),
2302
+ field("D3", fill),
2303
+ field("E1", "03"),
2304
+ // 03 = NDC
2305
+ field("D7", drug.ndc),
2306
+ field("E7", String(rng.int(30, 90))),
2307
+ field("D5", String(rng.pick([30, 60, 90]))),
2308
+ field("D8", rng.pick(DAW_CODES))
2309
+ ]
2310
+ };
2311
+ }
2312
+ function generateTelecom(code, options) {
2313
+ const rng = createRng(options.seed);
2314
+ const pharmacy = ncpdpPharmacy(rng);
2315
+ const head = header(rng, code, pharmacy.npi);
2316
+ const segments = code === "B2" ? [insuranceSegment(rng), claimSegment(rng, true)] : [
2317
+ patientSegment(rng),
2318
+ insuranceSegment(rng),
2319
+ prescriberSegment(rng),
2320
+ claimSegment(rng, false)
2321
+ ];
2322
+ return telecom.serializeTelecom(telecom.buildTelecomRequest({ header: head, segments }));
2323
+ }
2324
+ function generateB1(options) {
2325
+ return generateTelecom("B1", options);
2326
+ }
2327
+ function generateB2(options) {
2328
+ return generateTelecom("B2", options);
2329
+ }
2330
+ function generateB3(options) {
2331
+ return generateTelecom("B3", options);
2332
+ }
2333
+ var URI_TO_OID = Object.freeze({
2334
+ "http://loinc.org": ccda.LOINC,
2335
+ "http://snomed.info/sct": ccda.SNOMED_CT,
2336
+ "http://www.nlm.nih.gov/research/umls/rxnorm": ccda.RXNORM,
2337
+ "http://hl7.org/fhir/sid/cvx": ccda.CVX
2338
+ });
2339
+ function toBuildCode(concept) {
2340
+ const codeSystem = URI_TO_OID[concept.system];
2341
+ if (codeSystem === void 0) {
2342
+ throw new Error(`ccda example-codes: no OID mapping for code system "${concept.system}"`);
2343
+ }
2344
+ return { code: concept.code, codeSystem, displayName: concept.display };
2345
+ }
2346
+ function quantityFor(rng, concept) {
2347
+ const scale = 10 ** concept.decimals;
2348
+ const value = rng.int(concept.low * scale, concept.high * scale) / scale;
2349
+ return { value, unit: concept.unit };
2350
+ }
2351
+ var PROBLEMS = EXAMPLE_CONDITIONS;
2352
+ var ALLERGENS = EXAMPLE_ALLERGENS;
2353
+ var ALLERGY_REACTIONS = EXAMPLE_ALLERGY_MANIFESTATIONS;
2354
+ var MEDICATIONS = EXAMPLE_MEDICATIONS;
2355
+ var LAB_RESULTS = EXAMPLE_LAB_OBSERVATIONS2;
2356
+ var RESULT_PANELS = EXAMPLE_DIAGNOSTIC_REPORTS;
2357
+ var VITAL_SIGNS = EXAMPLE_VITAL_SIGNS;
2358
+ var VACCINES = EXAMPLE_VACCINES2;
2359
+ var PROCEDURES = EXAMPLE_PROCEDURES;
2360
+ var SMOKING_STATUSES = Object.freeze([
2361
+ Object.freeze({ code: "266919005", codeSystem: ccda.SNOMED_CT, displayName: "Never smoker" }),
2362
+ Object.freeze({ code: "8517006", codeSystem: ccda.SNOMED_CT, displayName: "Former smoker" }),
2363
+ Object.freeze({
2364
+ code: "449868002",
2365
+ codeSystem: ccda.SNOMED_CT,
2366
+ displayName: "Current every day smoker"
2367
+ }),
2368
+ Object.freeze({
2369
+ code: "428041000124106",
2370
+ codeSystem: ccda.SNOMED_CT,
2371
+ displayName: "Current some day smoker"
2372
+ })
2373
+ ]);
2374
+ var ROUTES = Object.freeze([
2375
+ Object.freeze({ code: "C38288", codeSystem: ccda.NCI_ROUTE, displayName: "Oral" }),
2376
+ Object.freeze({ code: "C28161", codeSystem: ccda.NCI_ROUTE, displayName: "Intramuscular" }),
2377
+ Object.freeze({ code: "C38276", codeSystem: ccda.NCI_ROUTE, displayName: "Intravenous" }),
2378
+ Object.freeze({ code: "C38299", codeSystem: ccda.NCI_ROUTE, displayName: "Subcutaneous" })
2379
+ ]);
2380
+
2381
+ // src/ccda/identity.ts
2382
+ function ccdaPatientIdentity(rng) {
2383
+ const person = safe.name(rng);
2384
+ const mrn = safe.identifier(rng, "MR");
2385
+ const birthTime = safe.dateYmd(rng, 1930, 2010);
2386
+ const gender = rng.pick(["M", "F"]);
2387
+ const patient = {
2388
+ mrn: mrn.value,
2389
+ mrnRoot: mrn.assigningAuthorityOid,
2390
+ mrnAssigningAuthority: mrn.assigningAuthority,
2391
+ given: [person.given],
2392
+ family: person.family,
2393
+ gender,
2394
+ birthTime
2395
+ };
2396
+ return { patient, person, mrn };
2397
+ }
2398
+
2399
+ // src/ccda/ccd.ts
2400
+ function pickN(rng, pool, n) {
2401
+ const take = Math.min(n, pool.length);
2402
+ const indices = pool.map((_v, i) => i);
2403
+ const out = [];
2404
+ for (let i = 0; i < take; i += 1) {
2405
+ const j = rng.int(0, indices.length - 1);
2406
+ const idx = indices[j];
2407
+ indices.splice(j, 1);
2408
+ out.push(pool[idx]);
2409
+ }
2410
+ return out;
2411
+ }
2412
+ function buildInit(rng, documentType) {
2413
+ const effectiveTime = safe.dateYmd(rng, 2020, 2025);
2414
+ const { patient, person } = ccdaPatientIdentity(rng);
2415
+ const problems = pickN(rng, PROBLEMS, rng.int(1, 3)).map((c) => ({
2416
+ problem: toBuildCode(c),
2417
+ status: "active",
2418
+ onset: safe.dateYmd(rng, 2010, 2019)
2419
+ }));
2420
+ const allergen = rng.pick(ALLERGENS);
2421
+ const reaction = rng.pick(ALLERGY_REACTIONS);
2422
+ const allergies = [{ allergen: toBuildCode(allergen), reaction: toBuildCode(reaction) }];
2423
+ const medications = pickN(rng, MEDICATIONS, rng.int(1, 2)).map((c) => ({
2424
+ drug: toBuildCode(c),
2425
+ dose: { value: 1, unit: "{tablet}" },
2426
+ route: rng.pick(ROUTES),
2427
+ frequency: { value: rng.pick([8, 12, 24]), unit: "h" }
2428
+ }));
2429
+ const panel = rng.pick(RESULT_PANELS);
2430
+ const resultMembers = pickN(rng, LAB_RESULTS, 2).map((q) => ({
2431
+ test: toBuildCode(q),
2432
+ quantity: quantityFor(rng, q),
2433
+ effectiveTime
2434
+ }));
2435
+ const results = [{ code: toBuildCode(panel), effectiveTime, results: resultMembers }];
2436
+ const vitalMembers = pickN(rng, VITAL_SIGNS, 2).map((q) => ({
2437
+ code: toBuildCode(q),
2438
+ quantity: quantityFor(rng, q)
2439
+ }));
2440
+ const vitalSigns = [{ effectiveTime, vitals: vitalMembers }];
2441
+ const vaccine = rng.pick(VACCINES);
2442
+ const immunizations = [
2443
+ {
2444
+ vaccine: toBuildCode(vaccine),
2445
+ dose: { value: 0.5, unit: "mL" },
2446
+ route: rng.pick(ROUTES),
2447
+ effectiveTime: safe.dateYmd(rng, 2018, 2024)
2448
+ }
2449
+ ];
2450
+ const procedure = rng.pick(PROCEDURES);
2451
+ const procedures = [
2452
+ {
2453
+ code: toBuildCode(procedure),
2454
+ disposition: "performed",
2455
+ effectiveTime: safe.dateYmd(rng, 2015, 2023)
2456
+ }
2457
+ ];
2458
+ const smokingStatus = [{ value: rng.pick(SMOKING_STATUSES), effectiveTime }];
2459
+ const base = {
2460
+ documentType,
2461
+ effectiveTime,
2462
+ patient,
2463
+ problems,
2464
+ allergies,
2465
+ medications,
2466
+ results,
2467
+ vitalSigns,
2468
+ immunizations,
2469
+ procedures,
2470
+ smokingStatus
2471
+ };
2472
+ if (documentType === "referralNote") {
2473
+ return {
2474
+ ...base,
2475
+ reasonForReferral: `Synthetic referral for evaluation of ${person.given} ${person.family}.`,
2476
+ assessment: "Synthetic assessment narrative. Not a real clinical assessment."
2477
+ };
2478
+ }
2479
+ return base;
2480
+ }
2481
+ function generateCcda(options = {}) {
2482
+ const { seed = 0, documentType = "ccd" } = options;
2483
+ const rng = createRng(seed);
2484
+ return ccda.buildCcda(buildInit(rng, documentType));
2485
+ }
2486
+ var DEID_LOOP_POLICY_NAME = "synth-deid-loop-removal";
2487
+ function deidLoopPolicy() {
2488
+ return deid.defineDeidPolicy({
2489
+ name: DEID_LOOP_POLICY_NAME,
2490
+ transforms: {
2491
+ [deid.SAFE_HARBOR_CATEGORIES.MRN]: "redact",
2492
+ [deid.SAFE_HARBOR_CATEGORIES.HEALTH_PLAN_BENEFICIARY]: "redact",
2493
+ [deid.SAFE_HARBOR_CATEGORIES.ACCOUNT]: "redact"
2494
+ }
2495
+ });
2496
+ }
2497
+ var STOPWORDS = /* @__PURE__ */ new Set([
2498
+ "official",
2499
+ "usual",
2500
+ "temp",
2501
+ "old",
2502
+ "anonymous",
2503
+ "maiden",
2504
+ "nickname",
2505
+ "home",
2506
+ "work",
2507
+ "mobile",
2508
+ "phone",
2509
+ "email",
2510
+ "fax",
2511
+ "sms",
2512
+ "pager",
2513
+ "other",
2514
+ "use",
2515
+ "street",
2516
+ "road",
2517
+ "avenue",
2518
+ "court",
2519
+ "lane",
2520
+ "drive",
2521
+ "boulevard",
2522
+ "place",
2523
+ "way",
2524
+ "suite",
2525
+ "apt",
2526
+ "unit",
2527
+ "null",
2528
+ "undefined"
2529
+ ]);
2530
+ function tokenize(value) {
2531
+ return value.split(/[\s^~&|,()/\\]+/).map((t) => t.trim()).filter((t) => t.length > 0);
2532
+ }
2533
+ function isDistinctive(token) {
2534
+ if (token.length < 4) return false;
2535
+ if (STOPWORDS.has(token.toLowerCase())) return false;
2536
+ if (/^\d+$/.test(token) && token.length < 5) return false;
2537
+ return true;
2538
+ }
2539
+ function identifierSentinels(loci, original) {
2540
+ const out = [];
2541
+ const seen = /* @__PURE__ */ new Set();
2542
+ for (const locus of loci) {
2543
+ if (locus.kind !== "identifier" || locus.value.length === 0) continue;
2544
+ for (const token of tokenize(locus.value)) {
2545
+ if (!isDistinctive(token)) continue;
2546
+ if (!original.includes(token)) continue;
2547
+ if (seen.has(token)) continue;
2548
+ seen.add(token);
2549
+ out.push({
2550
+ token,
2551
+ locus: locus.path,
2552
+ ...locus.category !== void 0 ? { category: locus.category } : {}
2553
+ });
2554
+ }
2555
+ }
2556
+ return out;
2557
+ }
2558
+ function recordTargetSentinels(xml) {
2559
+ const block = /<recordTarget[\s\S]*?<\/recordTarget>/i.exec(xml);
2560
+ if (block === null) return [];
2561
+ const scope = block[0];
2562
+ const out = [];
2563
+ const seen = /* @__PURE__ */ new Set();
2564
+ const add = (token, locus) => {
2565
+ const trimmed = token.trim();
2566
+ if (!isDistinctive(trimmed) || seen.has(trimmed)) return;
2567
+ seen.add(trimmed);
2568
+ out.push({ token: trimmed, locus, category: "names" });
2569
+ };
2570
+ for (const m of scope.matchAll(/<given>([^<]+)<\/given>/g)) add(m[1] ?? "", "recordTarget/given");
2571
+ for (const m of scope.matchAll(/<family>([^<]+)<\/family>/g))
2572
+ add(m[1] ?? "", "recordTarget/family");
2573
+ for (const m of scope.matchAll(/<id\b[^>]*\bextension="([^"]+)"/g))
2574
+ add(m[1] ?? "", "recordTarget/id");
2575
+ return out;
2576
+ }
2577
+ function sweepSurvivors(phiResidue, sentinels) {
2578
+ return sentinels.filter((s) => phiResidue.includes(s.token));
2579
+ }
2580
+ function clinicalRetention(original, deidentified, clinicalCodes) {
2581
+ const probed = [...new Set(clinicalCodes.filter((c) => c.length >= 4 && original.includes(c)))];
2582
+ const scrubbed = probed.filter((c) => !deidentified.includes(c));
2583
+ return { probed, scrubbed };
2584
+ }
2585
+ function assembleVerdict(parts) {
2586
+ const survivors = sweepSurvivors(parts.phiResidue ?? parts.deidentified, parts.planted);
2587
+ const { probed, scrubbed } = clinicalRetention(
2588
+ parts.original,
2589
+ parts.deidentified,
2590
+ parts.clinicalCodes
2591
+ );
2592
+ const pass = parts.planted.length > 0 && survivors.length === 0 && scrubbed.length === 0;
2593
+ return Object.freeze({
2594
+ format: parts.format,
2595
+ artifact: parts.artifact,
2596
+ seed: parts.seed,
2597
+ planted: Object.freeze([...parts.planted]),
2598
+ survivors: Object.freeze(survivors),
2599
+ clinicalProbed: Object.freeze(probed),
2600
+ clinicalScrubbed: Object.freeze(scrubbed),
2601
+ original: parts.original,
2602
+ deidentified: parts.deidentified,
2603
+ pass
2604
+ });
2605
+ }
2606
+
2607
+ // src/deid/index.ts
2608
+ var DEID_LOOP_COVERED_FORMATS = Object.freeze([
2609
+ "hl7",
2610
+ "fhir",
2611
+ "ccda",
2612
+ "x12",
2613
+ "ncpdp-telecom"
2614
+ ]);
2615
+ var DEID_LOOP_SKIPPED = Object.freeze([
2616
+ Object.freeze({
2617
+ format: "ncpdp-script",
2618
+ reason: "@cosyte/deid ships no NCPDP SCRIPT locus map; synth generates SCRIPT but the loop cannot pair it."
2619
+ }),
2620
+ Object.freeze({
2621
+ format: "astm",
2622
+ reason: "@cosyte/deid ships no ASTM adapter; synth generates ASTM but the loop cannot pair it."
2623
+ }),
2624
+ Object.freeze({
2625
+ format: "dicom",
2626
+ reason: "@cosyte/synth does not generate DICOM, so there is nothing to pair."
2627
+ })
2628
+ ]);
2629
+ var POLICY = deidLoopPolicy();
2630
+ function residue(loci) {
2631
+ return loci.map((l) => l.value).join("\n");
2632
+ }
2633
+ function recordTargetResidue(xml) {
2634
+ return /<recordTarget[\s\S]*?<\/recordTarget>/i.exec(xml)?.[0] ?? "";
2635
+ }
2636
+ var HL7_CLINICAL = [...EXAMPLE_LAB_OBSERVATIONS, ...EXAMPLE_ORDER_SERVICES, ...EXAMPLE_VACCINES].map(
2637
+ (c) => c.code
2638
+ );
2639
+ var FHIR_CLINICAL = [
2640
+ ...EXAMPLE_LAB_OBSERVATIONS2,
2641
+ ...EXAMPLE_VITAL_SIGNS,
2642
+ ...EXAMPLE_CONDITIONS,
2643
+ ...EXAMPLE_MEDICATIONS
2644
+ ].map((c) => c.code);
2645
+ var X12_CLINICAL = [...PROFESSIONAL_PROCEDURES, ...INSTITUTIONAL_PROCEDURES, ...DIAGNOSES].map(
2646
+ (c) => c.code
2647
+ );
2648
+ var NCPDP_CLINICAL = EXAMPLE_DRUGS.map((d) => d.ndc);
2649
+ function hl7DeidLoop(options = {}) {
2650
+ const seed = options.seed ?? 0;
2651
+ const kind = options.kind ?? "ORU^R01";
2652
+ const message = generateHl7(kind, seed);
2653
+ const original = message.toString();
2654
+ const planted = identifierSentinels(hl7.extractHl7Loci(message).loci, original);
2655
+ const deidDoc = hl7.deidentifyHl7(message, { policy: POLICY }).document;
2656
+ const deidentified = deidDoc.toString();
2657
+ return assembleVerdict({
2658
+ format: "hl7",
2659
+ artifact: kind,
2660
+ seed,
2661
+ planted,
2662
+ original,
2663
+ deidentified,
2664
+ phiResidue: residue(hl7.extractHl7Loci(deidDoc).loci),
2665
+ clinicalCodes: HL7_CLINICAL
2666
+ });
2667
+ }
2668
+ function fhirDeidLoop(options = {}) {
2669
+ const seed = options.seed ?? 0;
2670
+ const bundle = generateBundle({ seed });
2671
+ const original = fhir.serializeResource(bundle);
2672
+ const planted = identifierSentinels(fhir$1.extractFhirLoci(bundle).loci, original);
2673
+ const deidDoc = fhir$1.deidentifyFhir(bundle, { policy: POLICY }).document;
2674
+ const deidentified = fhir.serializeResource(deidDoc);
2675
+ return assembleVerdict({
2676
+ format: "fhir",
2677
+ artifact: "Bundle",
2678
+ seed,
2679
+ planted,
2680
+ original,
2681
+ deidentified,
2682
+ phiResidue: residue(fhir$1.extractFhirLoci(deidDoc).loci),
2683
+ clinicalCodes: FHIR_CLINICAL
2684
+ });
2685
+ }
2686
+ function generateX12(variant, seed) {
2687
+ switch (variant) {
2688
+ case "837P":
2689
+ return generate837P({ seed });
2690
+ case "837I":
2691
+ return generate837I({ seed });
2692
+ case "837D":
2693
+ return generate837D({ seed });
2694
+ case "271":
2695
+ return generate271({ seed });
2696
+ case "835":
2697
+ return generate835({ seed });
2698
+ }
2699
+ }
2700
+ function x12DeidLoop(options = {}) {
2701
+ const seed = options.seed ?? 0;
2702
+ const variant = options.variant ?? "837P";
2703
+ const interchange = generateX12(variant, seed);
2704
+ const original = x12.serializeX12(interchange);
2705
+ const planted = identifierSentinels(x12$1.extractX12Loci(interchange).loci, original);
2706
+ const deidentified = x12$1.deidentifyX12(interchange, { policy: POLICY }).x12;
2707
+ return assembleVerdict({
2708
+ format: "x12",
2709
+ artifact: variant,
2710
+ seed,
2711
+ planted,
2712
+ original,
2713
+ deidentified,
2714
+ phiResidue: residue(x12$1.extractX12Loci(x12.parseX12(deidentified)).loci),
2715
+ clinicalCodes: X12_CLINICAL
2716
+ });
2717
+ }
2718
+ function generateTelecomWire(transaction, seed) {
2719
+ switch (transaction) {
2720
+ case "B1":
2721
+ return generateB1({ seed });
2722
+ case "B2":
2723
+ return generateB2({ seed });
2724
+ case "B3":
2725
+ return generateB3({ seed });
2726
+ }
2727
+ }
2728
+ function ncpdpTelecomDeidLoop(options = {}) {
2729
+ const seed = options.seed ?? 0;
2730
+ const transaction = options.transaction ?? "B1";
2731
+ const original = generateTelecomWire(transaction, seed);
2732
+ const tx = telecom.parseTelecom(original);
2733
+ const planted = identifierSentinels(ncpdp.extractTelecomLoci(tx).loci, original);
2734
+ const deidentified = ncpdp.deidentifyTelecom(tx, { policy: POLICY }).telecom;
2735
+ return assembleVerdict({
2736
+ format: "ncpdp-telecom",
2737
+ artifact: transaction,
2738
+ seed,
2739
+ planted,
2740
+ original,
2741
+ deidentified,
2742
+ phiResidue: residue(ncpdp.extractTelecomLoci(telecom.parseTelecom(deidentified)).loci),
2743
+ clinicalCodes: NCPDP_CLINICAL
2744
+ });
2745
+ }
2746
+ function ccdaDeidLoop(options = {}) {
2747
+ const seed = options.seed ?? 0;
2748
+ const documentType = options.documentType ?? "ccd";
2749
+ const doc = generateCcda({ seed, documentType: documentType === "ccd" ? "ccd" : "referralNote" });
2750
+ const original = ccda.serializeCcda(doc);
2751
+ const planted = recordTargetSentinels(original);
2752
+ const deidentified = ccda$1.deidentifyCcda(doc, { policy: POLICY }).document.toString();
2753
+ return assembleVerdict({
2754
+ format: "ccda",
2755
+ artifact: documentType === "ccd" ? "CCD" : "ReferralNote",
2756
+ seed,
2757
+ planted,
2758
+ original,
2759
+ deidentified,
2760
+ phiResidue: recordTargetResidue(deidentified),
2761
+ clinicalCodes: [...EXAMPLE_CONDITIONS, ...EXAMPLE_MEDICATIONS].map((c) => c.code)
2762
+ });
2763
+ }
2764
+ function summarizeDeidCoverage(results) {
2765
+ const byFormatMap = /* @__PURE__ */ new Map();
2766
+ for (const r of results) {
2767
+ const list10 = byFormatMap.get(r.format) ?? [];
2768
+ list10.push(r);
2769
+ byFormatMap.set(r.format, list10);
2770
+ }
2771
+ const byFormat = [];
2772
+ for (const [format, runs] of byFormatMap) {
2773
+ byFormat.push({
2774
+ format,
2775
+ artifacts: runs.map((r) => r.artifact),
2776
+ planted: runs.reduce((n, r) => n + r.planted.length, 0),
2777
+ survivors: runs.reduce((n, r) => n + r.survivors.length, 0),
2778
+ clinicalProbed: runs.reduce((n, r) => n + r.clinicalProbed.length, 0),
2779
+ clinicalScrubbed: runs.reduce((n, r) => n + r.clinicalScrubbed.length, 0),
2780
+ pass: runs.every((r) => r.pass)
2781
+ });
2782
+ }
2783
+ return {
2784
+ byFormat,
2785
+ totalPlanted: results.reduce((n, r) => n + r.planted.length, 0),
2786
+ totalSurvivors: results.reduce((n, r) => n + r.survivors.length, 0),
2787
+ totalClinicalScrubbed: results.reduce((n, r) => n + r.clinicalScrubbed.length, 0),
2788
+ allPass: results.every((r) => r.pass),
2789
+ skipped: DEID_LOOP_SKIPPED
2790
+ };
2791
+ }
2792
+
2793
+ exports.DEID_LOOP_COVERED_FORMATS = DEID_LOOP_COVERED_FORMATS;
2794
+ exports.DEID_LOOP_POLICY_NAME = DEID_LOOP_POLICY_NAME;
2795
+ exports.DEID_LOOP_SKIPPED = DEID_LOOP_SKIPPED;
2796
+ exports.assembleVerdict = assembleVerdict;
2797
+ exports.ccdaDeidLoop = ccdaDeidLoop;
2798
+ exports.clinicalRetention = clinicalRetention;
2799
+ exports.deidLoopPolicy = deidLoopPolicy;
2800
+ exports.fhirDeidLoop = fhirDeidLoop;
2801
+ exports.hl7DeidLoop = hl7DeidLoop;
2802
+ exports.identifierSentinels = identifierSentinels;
2803
+ exports.ncpdpTelecomDeidLoop = ncpdpTelecomDeidLoop;
2804
+ exports.recordTargetSentinels = recordTargetSentinels;
2805
+ exports.summarizeDeidCoverage = summarizeDeidCoverage;
2806
+ exports.sweepSurvivors = sweepSurvivors;
2807
+ exports.x12DeidLoop = x12DeidLoop;
2808
+ //# sourceMappingURL=index.cjs.map
2809
+ //# sourceMappingURL=index.cjs.map