@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.
Files changed (155) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +564 -0
  3. package/dist/__tests__/careplan.test.d.ts +2 -0
  4. package/dist/__tests__/careplan.test.d.ts.map +1 -0
  5. package/dist/__tests__/careplan.test.js +544 -0
  6. package/dist/__tests__/careplan.test.js.map +1 -0
  7. package/dist/__tests__/clinical-dates.test.d.ts +2 -0
  8. package/dist/__tests__/clinical-dates.test.d.ts.map +1 -0
  9. package/dist/__tests__/clinical-dates.test.js +341 -0
  10. package/dist/__tests__/clinical-dates.test.js.map +1 -0
  11. package/dist/__tests__/coding-utilities.test.d.ts +2 -0
  12. package/dist/__tests__/coding-utilities.test.d.ts.map +1 -0
  13. package/dist/__tests__/coding-utilities.test.js +482 -0
  14. package/dist/__tests__/coding-utilities.test.js.map +1 -0
  15. package/dist/__tests__/date-range-performance.test.d.ts +2 -0
  16. package/dist/__tests__/date-range-performance.test.d.ts.map +1 -0
  17. package/dist/__tests__/date-range-performance.test.js +218 -0
  18. package/dist/__tests__/date-range-performance.test.js.map +1 -0
  19. package/dist/__tests__/date-range-search.test.d.ts +2 -0
  20. package/dist/__tests__/date-range-search.test.d.ts.map +1 -0
  21. package/dist/__tests__/date-range-search.test.js +215 -0
  22. package/dist/__tests__/date-range-search.test.js.map +1 -0
  23. package/dist/__tests__/env-setup.d.ts +2 -0
  24. package/dist/__tests__/env-setup.d.ts.map +1 -0
  25. package/dist/__tests__/env-setup.js +37 -0
  26. package/dist/__tests__/env-setup.js.map +1 -0
  27. package/dist/__tests__/fhir-bundle-sdk-basic.test.d.ts +2 -0
  28. package/dist/__tests__/fhir-bundle-sdk-basic.test.d.ts.map +1 -0
  29. package/dist/__tests__/fhir-bundle-sdk-basic.test.js +19 -0
  30. package/dist/__tests__/fhir-bundle-sdk-basic.test.js.map +1 -0
  31. package/dist/__tests__/fhir-bundle-sdk.test.d.ts +2 -0
  32. package/dist/__tests__/fhir-bundle-sdk.test.d.ts.map +1 -0
  33. package/dist/__tests__/fhir-bundle-sdk.test.js +953 -0
  34. package/dist/__tests__/fhir-bundle-sdk.test.js.map +1 -0
  35. package/dist/__tests__/fixtures/fhir-bundles.d.ts +31 -0
  36. package/dist/__tests__/fixtures/fhir-bundles.d.ts.map +1 -0
  37. package/dist/__tests__/fixtures/fhir-bundles.js +487 -0
  38. package/dist/__tests__/fixtures/fhir-bundles.js.map +1 -0
  39. package/dist/__tests__/phase1-verification.test.d.ts +2 -0
  40. package/dist/__tests__/phase1-verification.test.d.ts.map +1 -0
  41. package/dist/__tests__/phase1-verification.test.js +141 -0
  42. package/dist/__tests__/phase1-verification.test.js.map +1 -0
  43. package/dist/__tests__/phase2-verification.test.d.ts +2 -0
  44. package/dist/__tests__/phase2-verification.test.d.ts.map +1 -0
  45. package/dist/__tests__/phase2-verification.test.js +234 -0
  46. package/dist/__tests__/phase2-verification.test.js.map +1 -0
  47. package/dist/__tests__/phase3-verification.test.d.ts +2 -0
  48. package/dist/__tests__/phase3-verification.test.d.ts.map +1 -0
  49. package/dist/__tests__/phase3-verification.test.js +121 -0
  50. package/dist/__tests__/phase3-verification.test.js.map +1 -0
  51. package/dist/__tests__/phase4-verification.test.d.ts +2 -0
  52. package/dist/__tests__/phase4-verification.test.d.ts.map +1 -0
  53. package/dist/__tests__/phase4-verification.test.js +168 -0
  54. package/dist/__tests__/phase4-verification.test.js.map +1 -0
  55. package/dist/__tests__/phase5-verification.test.d.ts +2 -0
  56. package/dist/__tests__/phase5-verification.test.d.ts.map +1 -0
  57. package/dist/__tests__/phase5-verification.test.js +397 -0
  58. package/dist/__tests__/phase5-verification.test.js.map +1 -0
  59. package/dist/__tests__/reverse-references.test.d.ts +2 -0
  60. package/dist/__tests__/reverse-references.test.d.ts.map +1 -0
  61. package/dist/__tests__/reverse-references.test.js +294 -0
  62. package/dist/__tests__/reverse-references.test.js.map +1 -0
  63. package/dist/__tests__/type-guards.test.d.ts +2 -0
  64. package/dist/__tests__/type-guards.test.d.ts.map +1 -0
  65. package/dist/__tests__/type-guards.test.js +163 -0
  66. package/dist/__tests__/type-guards.test.js.map +1 -0
  67. package/dist/clinical-dates.d.ts +26 -0
  68. package/dist/clinical-dates.d.ts.map +1 -0
  69. package/dist/clinical-dates.js +571 -0
  70. package/dist/clinical-dates.js.map +1 -0
  71. package/dist/fhir-bundle-sdk.d.ts +233 -0
  72. package/dist/fhir-bundle-sdk.d.ts.map +1 -0
  73. package/dist/fhir-bundle-sdk.js +545 -0
  74. package/dist/fhir-bundle-sdk.js.map +1 -0
  75. package/dist/index.d.ts +8 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +23 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/internal/bundle-operations.d.ts +14 -0
  80. package/dist/internal/bundle-operations.d.ts.map +1 -0
  81. package/dist/internal/bundle-operations.js +55 -0
  82. package/dist/internal/bundle-operations.js.map +1 -0
  83. package/dist/internal/coding-systems.d.ts +48 -0
  84. package/dist/internal/coding-systems.d.ts.map +1 -0
  85. package/dist/internal/coding-systems.js +55 -0
  86. package/dist/internal/coding-systems.js.map +1 -0
  87. package/dist/internal/coding-utilities.d.ts +27 -0
  88. package/dist/internal/coding-utilities.d.ts.map +1 -0
  89. package/dist/internal/coding-utilities.js +297 -0
  90. package/dist/internal/coding-utilities.js.map +1 -0
  91. package/dist/internal/date-extraction.d.ts +12 -0
  92. package/dist/internal/date-extraction.d.ts.map +1 -0
  93. package/dist/internal/date-extraction.js +629 -0
  94. package/dist/internal/date-extraction.js.map +1 -0
  95. package/dist/internal/graph-traversal.d.ts +13 -0
  96. package/dist/internal/graph-traversal.d.ts.map +1 -0
  97. package/dist/internal/graph-traversal.js +89 -0
  98. package/dist/internal/graph-traversal.js.map +1 -0
  99. package/dist/internal/indexing.d.ts +17 -0
  100. package/dist/internal/indexing.d.ts.map +1 -0
  101. package/dist/internal/indexing.js +129 -0
  102. package/dist/internal/indexing.js.map +1 -0
  103. package/dist/internal/llm-context.d.ts +40 -0
  104. package/dist/internal/llm-context.d.ts.map +1 -0
  105. package/dist/internal/llm-context.js +214 -0
  106. package/dist/internal/llm-context.js.map +1 -0
  107. package/dist/internal/reference-resolution.d.ts +29 -0
  108. package/dist/internal/reference-resolution.d.ts.map +1 -0
  109. package/dist/internal/reference-resolution.js +338 -0
  110. package/dist/internal/reference-resolution.js.map +1 -0
  111. package/dist/internal/reference-utils.d.ts +26 -0
  112. package/dist/internal/reference-utils.d.ts.map +1 -0
  113. package/dist/internal/reference-utils.js +89 -0
  114. package/dist/internal/reference-utils.js.map +1 -0
  115. package/dist/internal/transparent-proxy.d.ts +12 -0
  116. package/dist/internal/transparent-proxy.d.ts.map +1 -0
  117. package/dist/internal/transparent-proxy.js +81 -0
  118. package/dist/internal/transparent-proxy.js.map +1 -0
  119. package/dist/internal/validation.d.ts +16 -0
  120. package/dist/internal/validation.d.ts.map +1 -0
  121. package/dist/internal/validation.js +45 -0
  122. package/dist/internal/validation.js.map +1 -0
  123. package/dist/type-guards.d.ts +212 -0
  124. package/dist/type-guards.d.ts.map +1 -0
  125. package/dist/type-guards.js +375 -0
  126. package/dist/type-guards.js.map +1 -0
  127. package/dist/types/coding-fields.d.ts +311 -0
  128. package/dist/types/coding-fields.d.ts.map +1 -0
  129. package/dist/types/coding-fields.js +3 -0
  130. package/dist/types/coding-fields.js.map +1 -0
  131. package/dist/types/sdk-types.d.ts +107 -0
  132. package/dist/types/sdk-types.d.ts.map +1 -0
  133. package/dist/types/sdk-types.js +17 -0
  134. package/dist/types/sdk-types.js.map +1 -0
  135. package/dist/types/smart-resources.d.ts +470 -0
  136. package/dist/types/smart-resources.d.ts.map +1 -0
  137. package/dist/types/smart-resources.js +249 -0
  138. package/dist/types/smart-resources.js.map +1 -0
  139. package/dist/utils/interval-tree/index.d.ts +87 -0
  140. package/dist/utils/interval-tree/index.d.ts.map +1 -0
  141. package/dist/utils/interval-tree/index.js +774 -0
  142. package/dist/utils/interval-tree/index.js.map +1 -0
  143. package/dist/utils/interval-tree/shallowequal/arrays.d.ts +3 -0
  144. package/dist/utils/interval-tree/shallowequal/arrays.d.ts.map +1 -0
  145. package/dist/utils/interval-tree/shallowequal/arrays.js +25 -0
  146. package/dist/utils/interval-tree/shallowequal/arrays.js.map +1 -0
  147. package/dist/utils/interval-tree/shallowequal/index.d.ts +6 -0
  148. package/dist/utils/interval-tree/shallowequal/index.d.ts.map +1 -0
  149. package/dist/utils/interval-tree/shallowequal/index.js +28 -0
  150. package/dist/utils/interval-tree/shallowequal/index.js.map +1 -0
  151. package/dist/utils/interval-tree/shallowequal/objects.d.ts +3 -0
  152. package/dist/utils/interval-tree/shallowequal/objects.d.ts.map +1 -0
  153. package/dist/utils/interval-tree/shallowequal/objects.js +28 -0
  154. package/dist/utils/interval-tree/shallowequal/objects.js.map +1 -0
  155. 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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=careplan.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"careplan.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/careplan.test.ts"],"names":[],"mappings":""}