fhir-test-data 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Daniel Veronez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,225 @@
1
+ # fhir-test-data
2
+
3
+ [![CI](https://github.com/dnlbox/fhir-test-data/actions/workflows/ci.yml/badge.svg)](https://github.com/dnlbox/fhir-test-data/actions/workflows/ci.yml)
4
+ [![CodeQL](https://github.com/dnlbox/fhir-test-data/actions/workflows/codeql.yml/badge.svg)](https://github.com/dnlbox/fhir-test-data/actions/workflows/codeql.yml)
5
+ [![npm](https://img.shields.io/npm/v/fhir-test-data)](https://www.npmjs.com/package/fhir-test-data)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
7
+
8
+ Generate valid FHIR R4 / R4B / R5 test resources with country-aware identifiers — from the CLI, a TypeScript library, or any tool that reads from a pipe.
9
+
10
+ ---
11
+
12
+ ## Why this exists
13
+
14
+ FHIR development requires realistic test data, but building it by hand is tedious and error-prone. Most teams either copy production data (a compliance risk) or write custom generators that hardcode US-centric identifiers — useless if your system needs to handle UK NHS numbers, Dutch BSNs, Korean RRNs, or Brazilian CPFs.
15
+
16
+ **fhir-test-data** generates structurally valid FHIR resources across 14 locales, with identifiers that pass each country's official check-digit algorithm. Clinical resources use real LOINC codes with values in realistic clinical ranges and HL7-consistent units of measurement, and SNOMED CT codes for conditions — so the data makes sense medically, not just structurally. All output is seeded and deterministic — the same seed always produces the same data, anywhere it runs.
17
+
18
+ ---
19
+
20
+ ## Quick start
21
+
22
+ ### CLI
23
+
24
+ No install required — run directly with `npx`:
25
+
26
+ ```bash
27
+ npx fhir-test-data generate patient --locale uk --count 5 --seed 42
28
+ ```
29
+
30
+ Or install globally for repeated use:
31
+
32
+ ```bash
33
+ pnpm add -g fhir-test-data
34
+ # or
35
+ npm install -g fhir-test-data
36
+
37
+ # Generate 5 UK patients to stdout
38
+ fhir-test-data generate patient --locale uk --count 5 --seed 42
39
+
40
+ # Generate a full bundle to a fixtures directory
41
+ fhir-test-data generate bundle --locale au --seed 1 --output ./fixtures/
42
+ ```
43
+
44
+ ### Library
45
+
46
+ ```bash
47
+ pnpm add fhir-test-data
48
+ ```
49
+
50
+ ```typescript
51
+ import { createPatientBuilder, createBundleBuilder } from "fhir-test-data";
52
+
53
+ const [patient] = createPatientBuilder().locale("uk").seed(42).build();
54
+
55
+ const [bundle] = createBundleBuilder()
56
+ .locale("us")
57
+ .seed(42)
58
+ .type("transaction")
59
+ .clinicalResourcesPerPatient(5)
60
+ .build();
61
+ ```
62
+
63
+ ---
64
+
65
+ ## CLI-first, pipe-friendly, AI-friendly
66
+
67
+ The CLI writes to stdout by default — making it a natural fit for shell pipelines, scripting, and AI-assisted workflows. Combine it with `jq`, FHIR validators, load testing tools, or large language models without any glue code.
68
+
69
+ ```bash
70
+ # Inspect a generated resource with jq
71
+ fhir-test-data generate patient --locale uk --seed 42 | jq '.identifier[0]'
72
+
73
+ # Stream NDJSON into a validator or ingest tool
74
+ fhir-test-data generate patient --count 100 --format ndjson | your-fhir-validator --stream
75
+
76
+ # POST to a FHIR server
77
+ fhir-test-data generate patient --locale nl --seed 1 | \
78
+ curl -s -X POST https://your-fhir-server/Patient \
79
+ -H "Content-Type: application/fhir+json" -d @-
80
+
81
+ # Ask an AI assistant to explore or explain a generated bundle
82
+ fhir-test-data generate bundle --locale kr --seed 5 | \
83
+ llm "summarise the clinical findings in this FHIR bundle"
84
+
85
+ # Generate NDJSON for bulk load testing
86
+ fhir-test-data generate patient --locale us --count 1000 --format ndjson --no-pretty \
87
+ > patients.ndjson
88
+
89
+ # Loop across locales in a CI step
90
+ for locale in us uk au de fr nl; do
91
+ fhir-test-data generate bundle --locale $locale --seed 1 --output "./fixtures/$locale/"
92
+ done
93
+ ```
94
+
95
+ Because output goes to stdout by default, there is nothing to configure — drop it into any pipeline that reads JSON or NDJSON.
96
+
97
+ ---
98
+
99
+ ## Supported locales
100
+
101
+ 14 locales with check-digit-validated identifiers and locale-appropriate names, addresses, and phone formats:
102
+
103
+ | Country | Code | Patient identifiers | Algorithm | Practitioner identifiers |
104
+ |---------|------|--------------------|-----------|-----------------------|
105
+ | United States | `us` | SSN, MRN | Format validation | NPI (Luhn) |
106
+ | United Kingdom | `uk` | NHS Number | Modulus 11 | GMC Number, GMP Number |
107
+ | Australia | `au` | IHI, Medicare | Luhn | HPI-I (Luhn) |
108
+ | Canada | `ca` | Ontario HCN | Format validation | — |
109
+ | Germany | `de` | KVID-10 | Format validation | LANR (Modulus 10) |
110
+ | France | `fr` | NIR | Modulus 97 | RPPS (Luhn) |
111
+ | Netherlands | `nl` | BSN | 11-proef | UZI Number |
112
+ | India | `in` | Aadhaar, ABHA | Verhoeff | — |
113
+ | Japan | `jp` | Hospital MRN | Format validation | Doctor License |
114
+ | South Korea | `kr` | RRN | Format + gender encoding | MOHW Doctor License |
115
+ | Mexico | `mx` | CURP | Format validation | Cédula Profesional |
116
+ | Brazil | `br` | CPF | Modulus 11 variant | CRM |
117
+ | Singapore | `sg` | NRIC / FIN | Check letter | SMC Registration |
118
+ | South Africa | `za` | SA ID Number | Luhn | HPCSA Registration |
119
+
120
+ Identifier validation is baked in — generated values always pass the official algorithm for their country. The library also includes tools like [fhir-resource-diff](https://github.com/dnlbox/fhir-resource-diff) for structural comparison and validation of generated fixtures.
121
+
122
+ ---
123
+
124
+ ## Clinical code quality
125
+
126
+ Observations use real LOINC codes with `valueQuantity` in clinically plausible ranges and HL7-consistent units of measurement (e.g. `mm[Hg]` for blood pressure, `kg/m2` for BMI). Conditions use SNOMED CT codes. AllergyIntolerance resources include coded substances. The goal is data that makes sense to a clinician, not just data that passes a schema validator.
127
+
128
+ ---
129
+
130
+ ## Seeded determinism
131
+
132
+ The same seed produces identical output on any machine, any Node version, any CI environment:
133
+
134
+ ```bash
135
+ fhir-test-data generate patient --locale uk --seed 42 > a.json
136
+ fhir-test-data generate patient --locale uk --seed 42 > b.json
137
+ diff a.json b.json # empty — identical output
138
+ ```
139
+
140
+ Reliable for snapshot tests, golden file comparison, and regression test fixtures.
141
+
142
+ ---
143
+
144
+ ## Multi-version FHIR support
145
+
146
+ All builders target R4 (default), R4B, or R5. R5 structural adaptations are applied automatically — `MedicationStatement` becomes `MedicationUsage`, and `AllergyIntolerance.type` becomes a `CodeableConcept`.
147
+
148
+ ```bash
149
+ fhir-test-data generate bundle --locale us --seed 1 --fhir-version R5
150
+ ```
151
+
152
+ ---
153
+
154
+ ## Bundle builder
155
+
156
+ The Bundle builder composes all resource types into a single FHIR Bundle with automatic reference wiring using `urn:uuid:` format:
157
+
158
+ ```typescript
159
+ const [bundle] = createBundleBuilder()
160
+ .locale("uk")
161
+ .seed(1)
162
+ .type("transaction")
163
+ .clinicalResourcesPerPatient(5)
164
+ .build();
165
+ ```
166
+
167
+ Each bundle includes: Patient, Organization, Practitioner, PractitionerRole, and N clinical resources (Observations, Conditions, AllergyIntolerance, MedicationStatement). All internal references are consistent — `Observation.subject` → Patient, `Observation.performer[0]` → Practitioner, `Patient.managingOrganization` → Organization.
168
+
169
+ ---
170
+
171
+ ## Fault injection
172
+
173
+ Generate intentionally invalid resources for testing validation pipelines and error handlers:
174
+
175
+ ```typescript
176
+ import { withFault } from "fhir-test-data/faults";
177
+
178
+ const [invalid] = withFault(
179
+ createPatientBuilder().locale("uk").seed(42),
180
+ "missing-resource-type"
181
+ ).build();
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Comparison with Synthea
187
+
188
+ [Synthea](https://github.com/synthetichealth/synthea) is a fantastic open-source patient generator that produces clinically realistic longitudinal patient histories — disease progression, care pathways, medication histories — and has been hugely valuable for healthcare research and simulation work.
189
+
190
+ fhir-test-data serves a different need: TypeScript-native, internationally correct, deterministic fixtures for developer testing workflows.
191
+
192
+ | | fhir-test-data | Synthea |
193
+ |---|---|---|
194
+ | Language | TypeScript | Java |
195
+ | Usage | Library + CLI | Standalone tool |
196
+ | International identifiers | 14 locales | US-only |
197
+ | Deterministic output | Yes (seeded PRNG) | Partial |
198
+ | TypeScript integration | Native types | JSON only |
199
+ | Clinical realism | Coded LOINC/SNOMED values | High (disease progression) |
200
+ | Browser-safe core | Yes | No |
201
+ | Pipe-friendly CLI | Yes | No |
202
+
203
+ Use **fhir-test-data** when you need TypeScript-native, internationally correct, deterministic fixtures for unit tests, integration tests, CI pipelines, or FHIR server load testing. Use **Synthea** when you need clinically realistic patient histories with disease progression for research or simulation.
204
+
205
+ ---
206
+
207
+ ## Related resources
208
+
209
+ **[fhir-resource-diff](https://github.com/dnlbox/fhir-resource-diff)** — compare FHIR resources structurally, ignoring irrelevant differences like IDs and timestamps. A natural companion for validating that generated fixtures stay stable across library upgrades:
210
+
211
+ ```bash
212
+ # Generate fixtures
213
+ fhir-test-data generate bundle --locale uk --seed 1 --output ./fixtures/
214
+
215
+ # Compare against a committed baseline
216
+ fhir-resource-diff compare ./fixtures/Bundle-001.json ./baseline/Bundle-001.json
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Documentation
222
+
223
+ Full API reference, locale details, fault injection guide, and VitePress documentation at [dnlbox.github.io/fhir-test-data](https://dnlbox.github.io/fhir-test-data).
224
+
225
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines and [CHANGELOG.md](CHANGELOG.md) for version history.
@@ -0,0 +1,121 @@
1
+ import {
2
+ pickRandom
3
+ } from "./chunk-U2QJNKBG.js";
4
+
5
+ // src/core/faults/registry.ts
6
+ var missingResourceType = (r) => {
7
+ const { resourceType: _dropped, ...rest } = r;
8
+ return rest;
9
+ };
10
+ var invalidResourceType = (r) => ({
11
+ ...r,
12
+ resourceType: "InvalidResourceXYZ"
13
+ });
14
+ var missingId = (r) => {
15
+ const { id: _dropped, ...rest } = r;
16
+ return rest;
17
+ };
18
+ var invalidGender = (r) => {
19
+ if (!("gender" in r)) return r;
20
+ return { ...r, gender: "INVALID_GENDER" };
21
+ };
22
+ var PRIMARY_DATE_FIELD = {
23
+ Patient: "birthDate",
24
+ Observation: "effectiveDateTime",
25
+ Condition: "onsetDateTime",
26
+ AllergyIntolerance: "recordedDate",
27
+ MedicationStatement: "effectiveDateTime",
28
+ MedicationUsage: "effectiveDateTime",
29
+ // R5 rename of MedicationStatement
30
+ Immunization: "occurrenceDateTime"
31
+ };
32
+ var DATE_FIELD_SUFFIX_PATTERN = /(?:Date|DateTime)$/;
33
+ var malformedDate = (r) => {
34
+ const resourceType = r["resourceType"];
35
+ const primaryField = resourceType ? PRIMARY_DATE_FIELD[resourceType] : void 0;
36
+ if (primaryField !== void 0 && primaryField in r) {
37
+ return { ...r, [primaryField]: "not-a-date" };
38
+ }
39
+ for (const key of Object.keys(r)) {
40
+ if (DATE_FIELD_SUFFIX_PATTERN.test(key)) {
41
+ return { ...r, [key]: "not-a-date" };
42
+ }
43
+ if (key.endsWith("Period")) {
44
+ const period = r[key];
45
+ if (period !== null && typeof period === "object" && "start" in period) {
46
+ return { ...r, [key]: { ...period, start: "not-a-date" } };
47
+ }
48
+ }
49
+ }
50
+ return r;
51
+ };
52
+ var emptyName = (r) => {
53
+ if (!("name" in r)) return r;
54
+ return { ...r, name: [] };
55
+ };
56
+ var wrongTypeOnField = (r) => {
57
+ if (!("birthDate" in r)) return r;
58
+ return { ...r, birthDate: 19850315 };
59
+ };
60
+ var duplicateIdentifier = (r) => {
61
+ const identifiers = r["identifier"];
62
+ if (!Array.isArray(identifiers) || identifiers.length === 0) return r;
63
+ return { ...r, identifier: [...identifiers, identifiers[0]] };
64
+ };
65
+ var invalidTelecomSystem = (r) => {
66
+ const telecom = r["telecom"];
67
+ if (!Array.isArray(telecom) || telecom.length === 0) return r;
68
+ const first = telecom[0];
69
+ return {
70
+ ...r,
71
+ telecom: [{ ...first, system: "fax-machine" }, ...telecom.slice(1)]
72
+ };
73
+ };
74
+ var FAULT_REGISTRY = {
75
+ "missing-resource-type": missingResourceType,
76
+ "invalid-resource-type": invalidResourceType,
77
+ "missing-id": missingId,
78
+ "invalid-gender": invalidGender,
79
+ "malformed-date": malformedDate,
80
+ "empty-name": emptyName,
81
+ "wrong-type-on-field": wrongTypeOnField,
82
+ "duplicate-identifier": duplicateIdentifier,
83
+ "invalid-telecom-system": invalidTelecomSystem
84
+ };
85
+ var CONCRETE_FAULT_TYPES = Object.keys(
86
+ FAULT_REGISTRY
87
+ );
88
+
89
+ // src/core/faults/inject.ts
90
+ function injectFaults(resource, faults, rng) {
91
+ const expanded = faults.map(
92
+ (f) => f === "random" ? pickRandom(CONCRETE_FAULT_TYPES, rng) : f
93
+ );
94
+ const unique = [...new Set(expanded)];
95
+ return unique.reduce(
96
+ (r, fault) => FAULT_REGISTRY[fault](r, rng),
97
+ resource
98
+ );
99
+ }
100
+
101
+ // src/core/faults/types.ts
102
+ var FAULT_TYPES = [
103
+ "missing-resource-type",
104
+ "invalid-resource-type",
105
+ "missing-id",
106
+ "invalid-gender",
107
+ "malformed-date",
108
+ "empty-name",
109
+ "wrong-type-on-field",
110
+ "duplicate-identifier",
111
+ "invalid-telecom-system",
112
+ "random"
113
+ ];
114
+
115
+ export {
116
+ FAULT_REGISTRY,
117
+ CONCRETE_FAULT_TYPES,
118
+ injectFaults,
119
+ FAULT_TYPES
120
+ };
121
+ //# sourceMappingURL=chunk-CBIPVWLL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/faults/registry.ts","../src/core/faults/inject.ts","../src/core/faults/types.ts"],"sourcesContent":["import type { ConcreteFaultType, FaultStrategy } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Individual fault strategies\n// ---------------------------------------------------------------------------\n\nconst missingResourceType: FaultStrategy = (r) => {\n const { resourceType: _dropped, ...rest } = r;\n return rest;\n};\n\nconst invalidResourceType: FaultStrategy = (r) => ({\n ...r,\n resourceType: \"InvalidResourceXYZ\",\n});\n\nconst missingId: FaultStrategy = (r) => {\n const { id: _dropped, ...rest } = r;\n return rest;\n};\n\nconst invalidGender: FaultStrategy = (r) => {\n if (!(\"gender\" in r)) return r;\n return { ...r, gender: \"INVALID_GENDER\" };\n};\n\n// Maps each resource type to its primary date field.\nconst PRIMARY_DATE_FIELD: Record<string, string> = {\n Patient: \"birthDate\",\n Observation: \"effectiveDateTime\",\n Condition: \"onsetDateTime\",\n AllergyIntolerance: \"recordedDate\",\n MedicationStatement: \"effectiveDateTime\",\n MedicationUsage: \"effectiveDateTime\", // R5 rename of MedicationStatement\n Immunization: \"occurrenceDateTime\",\n};\n\nconst DATE_FIELD_SUFFIX_PATTERN = /(?:Date|DateTime)$/;\n\nconst malformedDate: FaultStrategy = (r) => {\n const resourceType = r[\"resourceType\"] as string | undefined;\n const primaryField = resourceType ? PRIMARY_DATE_FIELD[resourceType] : undefined;\n\n // 1. Primary field lookup: if field exists on the resource, corrupt it.\n if (primaryField !== undefined && primaryField in r) {\n return { ...r, [primaryField]: \"not-a-date\" };\n }\n\n // 2. Fallback scan: find first field ending in Date or DateTime and corrupt it.\n for (const key of Object.keys(r)) {\n if (DATE_FIELD_SUFFIX_PATTERN.test(key)) {\n return { ...r, [key]: \"not-a-date\" };\n }\n // Handle Period fields — corrupt .start if present.\n if (key.endsWith(\"Period\")) {\n const period = r[key] as Record<string, unknown> | null | undefined;\n if (period !== null && typeof period === \"object\" && \"start\" in period) {\n return { ...r, [key]: { ...period, start: \"not-a-date\" } };\n }\n }\n }\n\n // 3. No recognised date field — silent no-op.\n return r;\n};\n\nconst emptyName: FaultStrategy = (r) => {\n if (!(\"name\" in r)) return r;\n return { ...r, name: [] };\n};\n\nconst wrongTypeOnField: FaultStrategy = (r) => {\n if (!(\"birthDate\" in r)) return r;\n // Integer instead of ISO string — wrong JSON type for FHIR date field.\n return { ...r, birthDate: 19850315 };\n};\n\nconst duplicateIdentifier: FaultStrategy = (r) => {\n const identifiers = r[\"identifier\"];\n if (!Array.isArray(identifiers) || identifiers.length === 0) return r;\n return { ...r, identifier: [...identifiers, identifiers[0]] };\n};\n\nconst invalidTelecomSystem: FaultStrategy = (r) => {\n const telecom = r[\"telecom\"];\n if (!Array.isArray(telecom) || telecom.length === 0) return r;\n const first = telecom[0] as Record<string, unknown>;\n return {\n ...r,\n telecom: [{ ...first, system: \"fax-machine\" }, ...telecom.slice(1)],\n };\n};\n\n// ---------------------------------------------------------------------------\n// Registry\n// ---------------------------------------------------------------------------\n\nexport const FAULT_REGISTRY: Record<ConcreteFaultType, FaultStrategy> = {\n \"missing-resource-type\": missingResourceType,\n \"invalid-resource-type\": invalidResourceType,\n \"missing-id\": missingId,\n \"invalid-gender\": invalidGender,\n \"malformed-date\": malformedDate,\n \"empty-name\": emptyName,\n \"wrong-type-on-field\": wrongTypeOnField,\n \"duplicate-identifier\": duplicateIdentifier,\n \"invalid-telecom-system\": invalidTelecomSystem,\n};\n\nexport const CONCRETE_FAULT_TYPES = Object.keys(\n FAULT_REGISTRY,\n) as ConcreteFaultType[];\n","import type { FhirResource, RandomFn, FaultType } from \"./types.js\";\nimport { FAULT_REGISTRY, CONCRETE_FAULT_TYPES } from \"./registry.js\";\nimport { pickRandom } from \"@/core/generators/rng.js\";\n\n/**\n * Apply a list of fault types to a FHIR resource.\n *\n * - \"random\" expands to one concrete fault chosen by the seeded RNG.\n * - Duplicate fault types in the list are applied once each (deduped by type).\n * - Faults targeting fields not present on the resource are silent no-ops.\n * - The original resource is never mutated; a new object is returned.\n */\nexport function injectFaults(\n resource: FhirResource,\n faults: FaultType[],\n rng: RandomFn,\n): FhirResource {\n const expanded = faults.map((f) =>\n f === \"random\" ? pickRandom(CONCRETE_FAULT_TYPES, rng) : f,\n );\n\n // Deduplicate while preserving first-occurrence order.\n const unique = [...new Set(expanded)];\n\n return unique.reduce<Record<string, unknown>>(\n (r, fault) => FAULT_REGISTRY[fault](r, rng),\n resource as Record<string, unknown>,\n ) as FhirResource;\n}\n","import type { FhirResource, RandomFn } from \"@/core/types.js\";\n\n/**\n * Concrete fault types — each maps to a specific FHIR violation.\n */\nexport type ConcreteFaultType =\n | \"missing-resource-type\" // remove resourceType entirely\n | \"invalid-resource-type\" // set resourceType to a non-existent value\n | \"missing-id\" // remove id field\n | \"invalid-gender\" // set gender to a value not in the FHIR ValueSet\n | \"malformed-date\" // set birthDate to a non-ISO-8601 value\n | \"empty-name\" // set name to an empty array\n | \"wrong-type-on-field\" // set birthDate to an integer instead of a string\n | \"duplicate-identifier\" // repeat identifier[0] in the identifier array\n | \"invalid-telecom-system\"; // set telecom[0].system to an unrecognised value\n\n/**\n * Full fault type including the \"random\" convenience alias.\n * \"random\" expands to one concrete fault chosen by the seeded RNG.\n */\nexport type FaultType = ConcreteFaultType | \"random\";\n\n/** All valid fault type strings, for CLI validation. */\nexport const FAULT_TYPES: FaultType[] = [\n \"missing-resource-type\",\n \"invalid-resource-type\",\n \"missing-id\",\n \"invalid-gender\",\n \"malformed-date\",\n \"empty-name\",\n \"wrong-type-on-field\",\n \"duplicate-identifier\",\n \"invalid-telecom-system\",\n \"random\",\n];\n\n/**\n * A fault strategy receives a resource as a plain object and an RNG,\n * and returns a new object with the fault applied. Never mutates the input.\n */\nexport type FaultStrategy = (\n resource: Record<string, unknown>,\n rng: RandomFn,\n) => Record<string, unknown>;\n\n// Re-export FhirResource so callers only need one import.\nexport type { FhirResource, RandomFn };\n"],"mappings":"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","names":[]}