@metriport/fhir-sdk 0.30.0-alpha.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.
- package/LICENSE +21 -0
- package/README.md +564 -0
- package/dist/__tests__/careplan.test.d.ts +2 -0
- package/dist/__tests__/careplan.test.d.ts.map +1 -0
- package/dist/__tests__/careplan.test.js +544 -0
- package/dist/__tests__/careplan.test.js.map +1 -0
- package/dist/__tests__/clinical-dates.test.d.ts +2 -0
- package/dist/__tests__/clinical-dates.test.d.ts.map +1 -0
- package/dist/__tests__/clinical-dates.test.js +341 -0
- package/dist/__tests__/clinical-dates.test.js.map +1 -0
- package/dist/__tests__/coding-utilities.test.d.ts +2 -0
- package/dist/__tests__/coding-utilities.test.d.ts.map +1 -0
- package/dist/__tests__/coding-utilities.test.js +482 -0
- package/dist/__tests__/coding-utilities.test.js.map +1 -0
- package/dist/__tests__/date-range-performance.test.d.ts +2 -0
- package/dist/__tests__/date-range-performance.test.d.ts.map +1 -0
- package/dist/__tests__/date-range-performance.test.js +218 -0
- package/dist/__tests__/date-range-performance.test.js.map +1 -0
- package/dist/__tests__/date-range-search.test.d.ts +2 -0
- package/dist/__tests__/date-range-search.test.d.ts.map +1 -0
- package/dist/__tests__/date-range-search.test.js +215 -0
- package/dist/__tests__/date-range-search.test.js.map +1 -0
- package/dist/__tests__/env-setup.d.ts +2 -0
- package/dist/__tests__/env-setup.d.ts.map +1 -0
- package/dist/__tests__/env-setup.js +37 -0
- package/dist/__tests__/env-setup.js.map +1 -0
- package/dist/__tests__/fhir-bundle-sdk-basic.test.d.ts +2 -0
- package/dist/__tests__/fhir-bundle-sdk-basic.test.d.ts.map +1 -0
- package/dist/__tests__/fhir-bundle-sdk-basic.test.js +19 -0
- package/dist/__tests__/fhir-bundle-sdk-basic.test.js.map +1 -0
- package/dist/__tests__/fhir-bundle-sdk.test.d.ts +2 -0
- package/dist/__tests__/fhir-bundle-sdk.test.d.ts.map +1 -0
- package/dist/__tests__/fhir-bundle-sdk.test.js +953 -0
- package/dist/__tests__/fhir-bundle-sdk.test.js.map +1 -0
- package/dist/__tests__/fixtures/fhir-bundles.d.ts +31 -0
- package/dist/__tests__/fixtures/fhir-bundles.d.ts.map +1 -0
- package/dist/__tests__/fixtures/fhir-bundles.js +487 -0
- package/dist/__tests__/fixtures/fhir-bundles.js.map +1 -0
- package/dist/__tests__/phase1-verification.test.d.ts +2 -0
- package/dist/__tests__/phase1-verification.test.d.ts.map +1 -0
- package/dist/__tests__/phase1-verification.test.js +141 -0
- package/dist/__tests__/phase1-verification.test.js.map +1 -0
- package/dist/__tests__/phase2-verification.test.d.ts +2 -0
- package/dist/__tests__/phase2-verification.test.d.ts.map +1 -0
- package/dist/__tests__/phase2-verification.test.js +234 -0
- package/dist/__tests__/phase2-verification.test.js.map +1 -0
- package/dist/__tests__/phase3-verification.test.d.ts +2 -0
- package/dist/__tests__/phase3-verification.test.d.ts.map +1 -0
- package/dist/__tests__/phase3-verification.test.js +121 -0
- package/dist/__tests__/phase3-verification.test.js.map +1 -0
- package/dist/__tests__/phase4-verification.test.d.ts +2 -0
- package/dist/__tests__/phase4-verification.test.d.ts.map +1 -0
- package/dist/__tests__/phase4-verification.test.js +168 -0
- package/dist/__tests__/phase4-verification.test.js.map +1 -0
- package/dist/__tests__/phase5-verification.test.d.ts +2 -0
- package/dist/__tests__/phase5-verification.test.d.ts.map +1 -0
- package/dist/__tests__/phase5-verification.test.js +397 -0
- package/dist/__tests__/phase5-verification.test.js.map +1 -0
- package/dist/__tests__/reverse-references.test.d.ts +2 -0
- package/dist/__tests__/reverse-references.test.d.ts.map +1 -0
- package/dist/__tests__/reverse-references.test.js +294 -0
- package/dist/__tests__/reverse-references.test.js.map +1 -0
- package/dist/__tests__/type-guards.test.d.ts +2 -0
- package/dist/__tests__/type-guards.test.d.ts.map +1 -0
- package/dist/__tests__/type-guards.test.js +163 -0
- package/dist/__tests__/type-guards.test.js.map +1 -0
- package/dist/clinical-dates.d.ts +26 -0
- package/dist/clinical-dates.d.ts.map +1 -0
- package/dist/clinical-dates.js +571 -0
- package/dist/clinical-dates.js.map +1 -0
- package/dist/fhir-bundle-sdk.d.ts +233 -0
- package/dist/fhir-bundle-sdk.d.ts.map +1 -0
- package/dist/fhir-bundle-sdk.js +545 -0
- package/dist/fhir-bundle-sdk.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/bundle-operations.d.ts +14 -0
- package/dist/internal/bundle-operations.d.ts.map +1 -0
- package/dist/internal/bundle-operations.js +55 -0
- package/dist/internal/bundle-operations.js.map +1 -0
- package/dist/internal/coding-systems.d.ts +48 -0
- package/dist/internal/coding-systems.d.ts.map +1 -0
- package/dist/internal/coding-systems.js +55 -0
- package/dist/internal/coding-systems.js.map +1 -0
- package/dist/internal/coding-utilities.d.ts +27 -0
- package/dist/internal/coding-utilities.d.ts.map +1 -0
- package/dist/internal/coding-utilities.js +297 -0
- package/dist/internal/coding-utilities.js.map +1 -0
- package/dist/internal/date-extraction.d.ts +12 -0
- package/dist/internal/date-extraction.d.ts.map +1 -0
- package/dist/internal/date-extraction.js +629 -0
- package/dist/internal/date-extraction.js.map +1 -0
- package/dist/internal/graph-traversal.d.ts +13 -0
- package/dist/internal/graph-traversal.d.ts.map +1 -0
- package/dist/internal/graph-traversal.js +89 -0
- package/dist/internal/graph-traversal.js.map +1 -0
- package/dist/internal/indexing.d.ts +17 -0
- package/dist/internal/indexing.d.ts.map +1 -0
- package/dist/internal/indexing.js +129 -0
- package/dist/internal/indexing.js.map +1 -0
- package/dist/internal/llm-context.d.ts +40 -0
- package/dist/internal/llm-context.d.ts.map +1 -0
- package/dist/internal/llm-context.js +214 -0
- package/dist/internal/llm-context.js.map +1 -0
- package/dist/internal/reference-resolution.d.ts +29 -0
- package/dist/internal/reference-resolution.d.ts.map +1 -0
- package/dist/internal/reference-resolution.js +338 -0
- package/dist/internal/reference-resolution.js.map +1 -0
- package/dist/internal/reference-utils.d.ts +26 -0
- package/dist/internal/reference-utils.d.ts.map +1 -0
- package/dist/internal/reference-utils.js +89 -0
- package/dist/internal/reference-utils.js.map +1 -0
- package/dist/internal/transparent-proxy.d.ts +12 -0
- package/dist/internal/transparent-proxy.d.ts.map +1 -0
- package/dist/internal/transparent-proxy.js +81 -0
- package/dist/internal/transparent-proxy.js.map +1 -0
- package/dist/internal/validation.d.ts +16 -0
- package/dist/internal/validation.d.ts.map +1 -0
- package/dist/internal/validation.js +45 -0
- package/dist/internal/validation.js.map +1 -0
- package/dist/type-guards.d.ts +212 -0
- package/dist/type-guards.d.ts.map +1 -0
- package/dist/type-guards.js +375 -0
- package/dist/type-guards.js.map +1 -0
- package/dist/types/coding-fields.d.ts +311 -0
- package/dist/types/coding-fields.d.ts.map +1 -0
- package/dist/types/coding-fields.js +3 -0
- package/dist/types/coding-fields.js.map +1 -0
- package/dist/types/sdk-types.d.ts +107 -0
- package/dist/types/sdk-types.d.ts.map +1 -0
- package/dist/types/sdk-types.js +17 -0
- package/dist/types/sdk-types.js.map +1 -0
- package/dist/types/smart-resources.d.ts +470 -0
- package/dist/types/smart-resources.d.ts.map +1 -0
- package/dist/types/smart-resources.js +249 -0
- package/dist/types/smart-resources.js.map +1 -0
- package/dist/utils/interval-tree/index.d.ts +87 -0
- package/dist/utils/interval-tree/index.d.ts.map +1 -0
- package/dist/utils/interval-tree/index.js +774 -0
- package/dist/utils/interval-tree/index.js.map +1 -0
- package/dist/utils/interval-tree/shallowequal/arrays.d.ts +3 -0
- package/dist/utils/interval-tree/shallowequal/arrays.d.ts.map +1 -0
- package/dist/utils/interval-tree/shallowequal/arrays.js +25 -0
- package/dist/utils/interval-tree/shallowequal/arrays.js.map +1 -0
- package/dist/utils/interval-tree/shallowequal/index.d.ts +6 -0
- package/dist/utils/interval-tree/shallowequal/index.d.ts.map +1 -0
- package/dist/utils/interval-tree/shallowequal/index.js +28 -0
- package/dist/utils/interval-tree/shallowequal/index.js.map +1 -0
- package/dist/utils/interval-tree/shallowequal/objects.d.ts +3 -0
- package/dist/utils/interval-tree/shallowequal/objects.d.ts.map +1 -0
- package/dist/utils/interval-tree/shallowequal/objects.js +28 -0
- package/dist/utils/interval-tree/shallowequal/objects.js.map +1 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Metriport Inc.
|
|
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,564 @@
|
|
|
1
|
+
# @metriport/fhir-sdk
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for parsing, querying, and manipulating FHIR R4 bundles with smart reference resolution.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { FhirBundleSdk } from "@metriport/fhir-sdk";
|
|
9
|
+
|
|
10
|
+
// Create an SDK instance
|
|
11
|
+
const sdk = await FhirBundleSdk.create(fhirBundle);
|
|
12
|
+
|
|
13
|
+
// Access static methods directly on the class
|
|
14
|
+
const cleaned = FhirBundleSdk.stripNonClinicalData(patient);
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Core Functionality
|
|
18
|
+
|
|
19
|
+
### 1. Resource Retrieval
|
|
20
|
+
|
|
21
|
+
#### By ID
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// Generic
|
|
25
|
+
const resource = sdk.getResourceById<Patient>("patient-123");
|
|
26
|
+
|
|
27
|
+
// Type-specific
|
|
28
|
+
const patient = sdk.getPatientById("patient-123");
|
|
29
|
+
const observation = sdk.getObservationById("obs-456");
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
#### By Type
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
const patients = sdk.getPatients();
|
|
36
|
+
const observations = sdk.getObservations();
|
|
37
|
+
const encounters = sdk.getEncounters();
|
|
38
|
+
const conditions = sdk.getConditions();
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 2. Coding System Utilities
|
|
42
|
+
|
|
43
|
+
All resources with CodeableConcept fields automatically have enhanced coding utilities for working with standard medical coding systems (LOINC, ICD-10, SNOMED, RxNorm, NDC).
|
|
44
|
+
|
|
45
|
+
**Important:** Use the specific Smart type aliases (`SmartObservation`, `SmartCondition`, etc.) instead of the generic `Smart<T>` pattern to get full TypeScript support for coding utilities.
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { SmartObservation, SmartCondition } from "@metriport/fhir-sdk";
|
|
49
|
+
|
|
50
|
+
// ✅ GOOD - Use specific Smart type for full TypeScript support
|
|
51
|
+
const obs: SmartObservation = sdk.getObservationById("obs-123")!;
|
|
52
|
+
|
|
53
|
+
// Check if the observation uses LOINC coding
|
|
54
|
+
if (obs.code?.hasLoinc()) {
|
|
55
|
+
const loincCode = obs.code.getLoincCode(); // Get first LOINC code
|
|
56
|
+
console.log("LOINC code:", loincCode);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Check for specific codes
|
|
60
|
+
if (obs.code?.hasLoincCode("2339-0")) {
|
|
61
|
+
console.log("Found glucose measurement!");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Work with ICD-10 codes in conditions
|
|
65
|
+
const condition: SmartCondition = sdk.getConditionById("cond-456")!;
|
|
66
|
+
const icd10Code = condition.code?.getIcd10Code();
|
|
67
|
+
const allIcd10 = condition.code?.getIcd10Codes(); // Get all ICD-10 codes
|
|
68
|
+
|
|
69
|
+
// Check if condition has specific ICD-10 codes
|
|
70
|
+
if (condition.code?.hasSomeIcd10(["E11.9", "E10.9"])) {
|
|
71
|
+
console.log("Patient has diabetes");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Find specific coding with custom logic
|
|
75
|
+
const diabetesCoding = condition.code?.findIcd10Coding(
|
|
76
|
+
code => code.startsWith("E11") || code.startsWith("E10")
|
|
77
|
+
);
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Available Coding Systems:**
|
|
81
|
+
|
|
82
|
+
Each `SmartCodeableConcept` provides methods for these coding systems:
|
|
83
|
+
|
|
84
|
+
- **LOINC**: `hasLoinc()`, `getLoinc()`, `getLoincCode()`, `getLoincCodes()`, `hasLoincCode()`, `hasSomeLoinc()`, `findLoincCoding()`
|
|
85
|
+
- **ICD-10**: `hasIcd10()`, `getIcd10()`, `getIcd10Code()`, `getIcd10Codes()`, `hasIcd10Code()`, `hasSomeIcd10()`, `findIcd10Coding()`
|
|
86
|
+
- **SNOMED**: `hasSnomed()`, `getSnomed()`, `getSnomedCode()`, `getSnomedCodes()`, `hasSnomedCode()`, `hasSomeSnomed()`, `findSnomedCoding()`
|
|
87
|
+
- **RxNorm**: `hasRxNorm()`, `getRxNorm()`, `getRxNormCode()`, `getRxNormCodes()`, `hasRxNormCode()`, `hasSomeRxNorm()`, `findRxNormCoding()`
|
|
88
|
+
- **NDC**: `hasNdc()`, `getNdc()`, `getNdcCode()`, `getNdcCodes()`, `hasNdcCode()`, `hasSomeNdc()`, `findNdcCoding()`
|
|
89
|
+
|
|
90
|
+
**Smart Resource Types with Coding Utilities:**
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import {
|
|
94
|
+
SmartObservation,
|
|
95
|
+
SmartCondition,
|
|
96
|
+
SmartProcedure,
|
|
97
|
+
SmartAllergyIntolerance,
|
|
98
|
+
SmartEncounter,
|
|
99
|
+
SmartDiagnosticReport,
|
|
100
|
+
SmartImmunization,
|
|
101
|
+
SmartMedication,
|
|
102
|
+
SmartMedicationRequest,
|
|
103
|
+
SmartMedicationAdministration,
|
|
104
|
+
SmartMedicationDispense,
|
|
105
|
+
SmartMedicationStatement,
|
|
106
|
+
SmartFamilyMemberHistory,
|
|
107
|
+
SmartRelatedPerson,
|
|
108
|
+
SmartRiskAssessment,
|
|
109
|
+
SmartServiceRequest,
|
|
110
|
+
SmartCarePlan,
|
|
111
|
+
SmartPatient,
|
|
112
|
+
SmartPractitioner,
|
|
113
|
+
SmartOrganization,
|
|
114
|
+
SmartLocation,
|
|
115
|
+
SmartComposition,
|
|
116
|
+
SmartCoverage,
|
|
117
|
+
SmartDocumentReference,
|
|
118
|
+
} from "@metriport/fhir-sdk";
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
All SDK getter methods return the appropriate Smart type automatically:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
// These all return the specific Smart types with coding utilities
|
|
125
|
+
const observations: SmartObservation[] = sdk.getObservations();
|
|
126
|
+
const conditions: SmartCondition[] = sdk.getConditions();
|
|
127
|
+
const procedures: SmartProcedure[] = sdk.getProcedures();
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 3. Smart Reference Resolution
|
|
131
|
+
|
|
132
|
+
Resources include typed getter methods for convenient and type-safe reference traversal:
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
const observation = sdk.getObservationById("obs-123");
|
|
136
|
+
|
|
137
|
+
// Direct access to referenced resources
|
|
138
|
+
const patient = observation.getSubject<Patient>();
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Smart Resource Methods:**
|
|
142
|
+
|
|
143
|
+
All smart resources include these utility methods:
|
|
144
|
+
|
|
145
|
+
**Automatic console.log formatting** - Resources automatically render nicely when printed:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
const patient = sdk.getPatientById("patient-123");
|
|
149
|
+
|
|
150
|
+
// Just use console.log directly - no need to call toString()!
|
|
151
|
+
console.log(patient);
|
|
152
|
+
// Output:
|
|
153
|
+
// {
|
|
154
|
+
// resourceType: 'Patient',
|
|
155
|
+
// id: 'patient-123',
|
|
156
|
+
// name: [ { family: 'Doe', given: [Array] } ],
|
|
157
|
+
// ...
|
|
158
|
+
// }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**toString()** - Manual formatting with custom spacing:
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// Use toString() if you need custom spacing
|
|
165
|
+
console.log(patient.toString(4)); // 4 spaces
|
|
166
|
+
const jsonString = patient.toString(0); // Compact JSON
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
This is useful for debugging and inspecting deeply nested structures. The output automatically excludes smart resource methods and shows the raw FHIR resource data.
|
|
170
|
+
|
|
171
|
+
**getReferencingResources()** - Find all resources that reference this resource:
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
const patient = sdk.getPatientById("patient-123");
|
|
175
|
+
|
|
176
|
+
// Find all resources referencing this patient
|
|
177
|
+
const references = patient.getReferencingResources();
|
|
178
|
+
|
|
179
|
+
// Filter by resource type
|
|
180
|
+
const observations = patient.getReferencingResources({ resourceType: "Observation" });
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**getReferencedResources()** - Find all resources referenced by this resource:
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
const observation = sdk.getObservationById("obs-123");
|
|
187
|
+
|
|
188
|
+
// Get all resources this observation references
|
|
189
|
+
const referencedResources = observation.getReferencedResources();
|
|
190
|
+
// Returns: [Patient, Encounter, Practitioner, etc.] based on REFERENCE_METHOD_MAPPING
|
|
191
|
+
|
|
192
|
+
// SDK-level method also available
|
|
193
|
+
const refs = sdk.getResourcesReferencedBy(observation);
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
This method automatically discovers and returns all resources referenced by the current resource based on the configured reference methods in `REFERENCE_METHOD_MAPPING`. It handles both single references and array references.
|
|
197
|
+
|
|
198
|
+
### 4. Bundle Export
|
|
199
|
+
|
|
200
|
+
You can export subsets of your bundle or export by resource type to quickly create custom bundles.
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
// Export by resource IDs - great for diff bundles!
|
|
204
|
+
const subset = sdk.exportSubset(["patient-uuid-1", "obs-uuid-1"]);
|
|
205
|
+
|
|
206
|
+
// Export by resource type - great for resource type bundles!
|
|
207
|
+
const observationBundle = sdk.exportByType("Observation");
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### 5. Validation
|
|
211
|
+
|
|
212
|
+
Validate your bundle to ensure there are no broken references. A broken reference is a reference that points to a resource that does not exist in the bundle.
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
const result = sdk.lookForBrokenReferences();
|
|
216
|
+
console.log(result.hasBrokenReferences); // true if at least one broken reference is found, false otherwise
|
|
217
|
+
console.log(result.brokenReferences); // All broken references in bundle
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### 6. Reverse Reference Lookup
|
|
221
|
+
|
|
222
|
+
Find all resources that reference a given resource (reverse lookup). This is useful for discovering what refers to a specific resource.
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
const patient = sdk.getPatientById("patient-123");
|
|
226
|
+
|
|
227
|
+
// Find all resources that reference this patient
|
|
228
|
+
const referencingResources = sdk.getResourcesReferencingId("patient-123");
|
|
229
|
+
console.log(referencingResources); // [Observation, Encounter, DiagnosticReport, ...]
|
|
230
|
+
|
|
231
|
+
// Filter by resource type
|
|
232
|
+
const observations = sdk.getResourcesReferencingId("patient-123", {
|
|
233
|
+
resourceType: "Observation",
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Filter by reference field
|
|
237
|
+
const subjectReferences = sdk.getResourcesReferencingId("patient-123", {
|
|
238
|
+
referenceField: "subject",
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Use smart resource method
|
|
242
|
+
const backRefs = patient.getReferencingResources();
|
|
243
|
+
const encounteredObs = patient.getReferencingResources({
|
|
244
|
+
resourceType: "Observation",
|
|
245
|
+
referenceField: "subject",
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**Key Features:**
|
|
250
|
+
|
|
251
|
+
- **O(1) lookup** - constant time performance
|
|
252
|
+
- **Flexible filtering** - by resource type and/or reference field
|
|
253
|
+
- **Smart resources** - returns fully functional Smart resources
|
|
254
|
+
- **Bi-directional** - complements forward reference navigation
|
|
255
|
+
|
|
256
|
+
### 7. Date Range Search
|
|
257
|
+
|
|
258
|
+
Search for resources by date range using an interval tree index. This is useful for filtering resources by clinical dates efficiently.
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
const sdk = await FhirBundleSdk.create(bundle);
|
|
262
|
+
|
|
263
|
+
// Basic date range search
|
|
264
|
+
const results = sdk.searchByDateRange({
|
|
265
|
+
dateFrom: "2024-01-01",
|
|
266
|
+
dateTo: "2024-01-31",
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// Filter by resource type
|
|
270
|
+
const observations = sdk.searchByDateRange({
|
|
271
|
+
dateFrom: "2024-01-01",
|
|
272
|
+
dateTo: "2024-12-31",
|
|
273
|
+
resourceTypes: ["Observation", "Condition"],
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Filter by specific date field
|
|
277
|
+
const recordedConditions = sdk.searchByDateRange({
|
|
278
|
+
dateFrom: "2024-01-01",
|
|
279
|
+
dateTo: "2024-12-31",
|
|
280
|
+
dateFields: ["recordedDate"],
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// Use Date objects
|
|
284
|
+
const recentResources = sdk.searchByDateRange({
|
|
285
|
+
dateFrom: new Date("2024-01-01"),
|
|
286
|
+
dateTo: new Date(),
|
|
287
|
+
});
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Key Features:**
|
|
291
|
+
|
|
292
|
+
- **O(log n + k) search** - efficient interval tree-based search where k is the number of matching resources
|
|
293
|
+
- **Multiple date fields** - indexes primary clinical dates (effectiveDateTime, onset, performed) and recorded dates
|
|
294
|
+
- **Flexible filtering** - by resource type and/or specific date fields
|
|
295
|
+
- **Smart resources** - returns fully functional Smart resources
|
|
296
|
+
- **Period support** - handles both single date fields and date periods/ranges
|
|
297
|
+
|
|
298
|
+
**Indexed Resource Types:**
|
|
299
|
+
|
|
300
|
+
The following resource types and date fields are automatically indexed:
|
|
301
|
+
|
|
302
|
+
- **Observation**: effectiveDateTime, effectivePeriod, effectiveInstant, issued
|
|
303
|
+
- **Condition**: onsetDateTime, onsetPeriod, abatementDateTime, abatementPeriod, recordedDate
|
|
304
|
+
- **Encounter**: period
|
|
305
|
+
- **Procedure**: performedDateTime, performedPeriod
|
|
306
|
+
- **Immunization**: occurrenceDateTime, recorded
|
|
307
|
+
- **DiagnosticReport**: effectiveDateTime, effectivePeriod, issued
|
|
308
|
+
- **MedicationRequest**: authoredOn
|
|
309
|
+
- **MedicationAdministration**: effectiveDateTime, effectivePeriod
|
|
310
|
+
- **MedicationStatement**: effectiveDateTime, effectivePeriod
|
|
311
|
+
- **MedicationDispense**: whenHandedOver, whenPrepared
|
|
312
|
+
- **DocumentReference**: date, context.period
|
|
313
|
+
- **Composition**: date
|
|
314
|
+
- **Coverage**: period
|
|
315
|
+
- **AllergyIntolerance**: onsetDateTime, onsetPeriod, lastOccurrence, recordedDate
|
|
316
|
+
|
|
317
|
+
### 8. Reference Walking (BFS Traversal)
|
|
318
|
+
|
|
319
|
+
Walk the reference graph starting from any resource using breadth-first search (BFS). This is useful for discovering all resources connected to a specific resource.
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
const observation = sdk.getObservationById("obs-123");
|
|
323
|
+
|
|
324
|
+
// Walk all reachable resources
|
|
325
|
+
const result = sdk.walkReferences(observation);
|
|
326
|
+
console.log(result.allResources); // All resources reachable from observation
|
|
327
|
+
console.log(result.resourcesByDepth); // Resources organized by depth level
|
|
328
|
+
console.log(result.depthReached); // Maximum depth traversed
|
|
329
|
+
|
|
330
|
+
// Limit traversal depth
|
|
331
|
+
const limitedResult = sdk.walkReferences(observation, { maxDepth: 2 });
|
|
332
|
+
|
|
333
|
+
// Exclude the start resource from results
|
|
334
|
+
const withoutStart = sdk.walkReferences(observation, { includeStartResource: false });
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### 9. LLM Context Generation
|
|
338
|
+
|
|
339
|
+
Generate comprehensive, LLM-friendly context from a resource and its related resources. This automatically performs BFS traversal, strips non-clinical metadata, and formats the output for optimal LLM consumption.
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
const observation = sdk.getObservationById("obs-123");
|
|
343
|
+
|
|
344
|
+
// Generate structured text context (default, best for LLMs)
|
|
345
|
+
const llmContext = sdk.generateLLMContext(observation, {
|
|
346
|
+
maxDepth: 2, // Default: 2
|
|
347
|
+
format: "structured-text", // Default: 'structured-text'
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
// Send to your LLM
|
|
351
|
+
await llm.chat({
|
|
352
|
+
messages: [
|
|
353
|
+
{ role: "system", content: "You are a medical data analyst." },
|
|
354
|
+
{ role: "user", content: `Analyze this patient data:\n\n${llmContext}` },
|
|
355
|
+
],
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// Alternative: JSON format
|
|
359
|
+
const jsonContext = sdk.generateLLMContext(observation, {
|
|
360
|
+
format: "json",
|
|
361
|
+
});
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**Features:**
|
|
365
|
+
|
|
366
|
+
- Automatically discovers all related resources via BFS traversal
|
|
367
|
+
- Strips non-clinical metadata (`meta`, `extension`, `text`) to reduce tokens by ~30-40%
|
|
368
|
+
- Organizes resources hierarchically (primary → directly referenced → indirectly referenced)
|
|
369
|
+
- Groups resources by type within each depth level
|
|
370
|
+
- Logs resource counts for debugging (not included in output)
|
|
371
|
+
|
|
372
|
+
**Static Methods:**
|
|
373
|
+
|
|
374
|
+
The `FhirBundleSdk` class provides static utility methods that don't require an SDK instance:
|
|
375
|
+
|
|
376
|
+
```typescript
|
|
377
|
+
import { FhirBundleSdk } from "@metriport/fhir-sdk";
|
|
378
|
+
|
|
379
|
+
// Strip non-clinical data from any resource
|
|
380
|
+
const cleanedPatient = FhirBundleSdk.stripNonClinicalData(patient);
|
|
381
|
+
// Removes: meta, extension, modifierExtension, text, id, identifier, and all reference fields
|
|
382
|
+
// Returns immutable copy
|
|
383
|
+
|
|
384
|
+
// Create SDK instances
|
|
385
|
+
const sdk = await FhirBundleSdk.create(bundle); // Async (for backwards compatibility)
|
|
386
|
+
const sdk2 = FhirBundleSdk.createSync(bundle); // Synchronous
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
This is especially useful in REPL sessions where you want quick access to utility functions without creating a full SDK instance.
|
|
390
|
+
|
|
391
|
+
### 10. Type Guards
|
|
392
|
+
|
|
393
|
+
Filter mixed arrays of FHIR resources to specific types with full TypeScript type safety:
|
|
394
|
+
|
|
395
|
+
```typescript
|
|
396
|
+
import { Resource } from "@medplum/fhirtypes";
|
|
397
|
+
import { isPatient, isObservation, isDiagnosticReport } from "@metriport/fhir-sdk";
|
|
398
|
+
|
|
399
|
+
// Filter mixed resource arrays
|
|
400
|
+
const resources: Resource[] = [
|
|
401
|
+
{ resourceType: "Patient", id: "patient-1" },
|
|
402
|
+
{ resourceType: "Observation", id: "obs-1", status: "final", code: { text: "test" } },
|
|
403
|
+
{ resourceType: "DiagnosticReport", id: "report-1", status: "final", code: { text: "lab" } },
|
|
404
|
+
];
|
|
405
|
+
|
|
406
|
+
const patients = resources.filter(isPatient); // Patient[]
|
|
407
|
+
const observations = resources.filter(isObservation); // Observation[]
|
|
408
|
+
|
|
409
|
+
// TypeScript knows the exact type after filtering
|
|
410
|
+
patients.forEach(patient => {
|
|
411
|
+
const name = patient.name; // ✅ Type-safe access to Patient fields
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// Works with Smart resources too
|
|
415
|
+
const allObs = sdk.getObservations();
|
|
416
|
+
allObs.forEach(obs => {
|
|
417
|
+
if (isObservation(obs)) {
|
|
418
|
+
const subject = obs.getSubject(); // ✅ Smart methods available
|
|
419
|
+
const status = obs.status; // ✅ Observation fields available
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
**Available type guards:**
|
|
425
|
+
Use the `is<ResourceType>` type guard to check if a resource is of a specific type. There is one for every fhir resource type. Use them whenever possible over writing your own type guards.
|
|
426
|
+
|
|
427
|
+
## Example Use Cases
|
|
428
|
+
|
|
429
|
+
### Filter by Medical Codes
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
import { SmartObservation, SmartCondition } from "@metriport/fhir-sdk";
|
|
433
|
+
|
|
434
|
+
// Find all glucose observations using LOINC codes
|
|
435
|
+
const glucoseObs = sdk.getObservations().filter(
|
|
436
|
+
obs =>
|
|
437
|
+
obs.code?.hasLoincCode("2339-0") || // Glucose [Mass/volume] in Blood
|
|
438
|
+
obs.code?.hasLoincCode("2345-7") // Glucose [Mass/volume] in Serum or Plasma
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
// Find all diabetes conditions using ICD-10 codes
|
|
442
|
+
const diabetesConditions = sdk.getConditions().filter(cond =>
|
|
443
|
+
cond.code?.findIcd10Coding(
|
|
444
|
+
code =>
|
|
445
|
+
code.startsWith("E10") || // Type 1 diabetes
|
|
446
|
+
code.startsWith("E11") // Type 2 diabetes
|
|
447
|
+
)
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
// Find medications by RxNorm code
|
|
451
|
+
const metforminMeds = sdk
|
|
452
|
+
.getMedicationRequests()
|
|
453
|
+
.filter(medReq => medReq.medicationCodeableConcept?.hasRxNormCode("6809"));
|
|
454
|
+
|
|
455
|
+
// Complex filtering with multiple coding systems
|
|
456
|
+
const labResults = sdk.getObservations().filter(obs => {
|
|
457
|
+
if (obs.code?.hasLoinc()) {
|
|
458
|
+
const loincCode = obs.code.getLoincCode();
|
|
459
|
+
// Filter for specific lab panels
|
|
460
|
+
return (
|
|
461
|
+
loincCode?.startsWith("24331") || // Lipid panel
|
|
462
|
+
loincCode?.startsWith("24362")
|
|
463
|
+
); // Complete blood count
|
|
464
|
+
}
|
|
465
|
+
return false;
|
|
466
|
+
});
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Patient Summary
|
|
470
|
+
|
|
471
|
+
```typescript
|
|
472
|
+
const buildPatientSummary = (patientId: string) => {
|
|
473
|
+
const patient = sdk.getPatientById(patientId);
|
|
474
|
+
const observations = sdk.getObservations().filter(obs => obs.getSubject()?.id === patientId);
|
|
475
|
+
|
|
476
|
+
return {
|
|
477
|
+
name: patient?.name?.[0]?.family,
|
|
478
|
+
observationCount: observations.length,
|
|
479
|
+
recentObs: observations.slice(0, 5),
|
|
480
|
+
};
|
|
481
|
+
};
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Reference Traversal
|
|
485
|
+
|
|
486
|
+
```typescript
|
|
487
|
+
// Traverse multiple references in sequence
|
|
488
|
+
const orgName = sdk.getPatients()[0]?.getManagingOrganization()?.name;
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### Extract Related Resources
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
// Get all resources related to a specific observation
|
|
495
|
+
const extractRelatedResources = (observationId: string) => {
|
|
496
|
+
const observation = sdk.getObservationById(observationId);
|
|
497
|
+
if (!observation) return null;
|
|
498
|
+
|
|
499
|
+
// Walk the graph to find all related resources up to 2 levels deep
|
|
500
|
+
const result = sdk.walkReferences(observation, { maxDepth: 2 });
|
|
501
|
+
|
|
502
|
+
return {
|
|
503
|
+
observation,
|
|
504
|
+
relatedResourceCount: result.allResources.length,
|
|
505
|
+
resourcesByType: result.allResources.reduce((acc, resource) => {
|
|
506
|
+
acc[resource.resourceType] = (acc[resource.resourceType] || 0) + 1;
|
|
507
|
+
return acc;
|
|
508
|
+
}, {} as Record<string, number>),
|
|
509
|
+
};
|
|
510
|
+
};
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### Example Use Case: Processing a bundle
|
|
514
|
+
|
|
515
|
+
```typescript
|
|
516
|
+
const processBundle = async (bundle: Bundle) => {
|
|
517
|
+
const sdk = await FhirBundleSdk.create(bundle);
|
|
518
|
+
|
|
519
|
+
const { hasBrokenReferences, brokenReferences } = sdk.lookForBrokenReferences();
|
|
520
|
+
|
|
521
|
+
if (hasBrokenReferences) {
|
|
522
|
+
throw new MetriportError("Broken references found in bundle", {
|
|
523
|
+
brokenReferences,
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Process
|
|
528
|
+
const patients = sdk.getPatients();
|
|
529
|
+
const summaries = patients.map(p => ({
|
|
530
|
+
id: p.id,
|
|
531
|
+
name: p.name?.[0]?.family,
|
|
532
|
+
obsCount: sdk.getObservations().filter(obs => obs.getSubject()?.id === p.id).length,
|
|
533
|
+
}));
|
|
534
|
+
|
|
535
|
+
return summaries;
|
|
536
|
+
};
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
## Performance
|
|
540
|
+
|
|
541
|
+
- **getById**: O(1) lookup
|
|
542
|
+
- **getByType**: O(n) where n = resources of that type
|
|
543
|
+
- **Reference resolution**: O(1) traversal
|
|
544
|
+
- **Reverse reference lookup**: O(1) lookup
|
|
545
|
+
|
|
546
|
+
## Demo
|
|
547
|
+
|
|
548
|
+
To see reverse reference functionality in action, run:
|
|
549
|
+
|
|
550
|
+
```bash
|
|
551
|
+
# From the utils package
|
|
552
|
+
cd packages/utils
|
|
553
|
+
npx ts-node src/fhir-sdk/demo-reverse-references.ts --bundle-path /path/to/your/bundle.json
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
The demo will:
|
|
557
|
+
|
|
558
|
+
- Automatically find the first patient in your bundle
|
|
559
|
+
- Showcase all reverse reference capabilities:
|
|
560
|
+
- Finding all resources that reference a specific resource
|
|
561
|
+
- Filtering by resource type and reference field
|
|
562
|
+
- Using smart resource methods
|
|
563
|
+
- Bi-directional navigation
|
|
564
|
+
- Performance characteristics
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"careplan.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/careplan.test.ts"],"names":[],"mappings":""}
|