@imranq2/fhirpatientsummary 1.0.16 → 1.0.17

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/dist/index.js CHANGED
@@ -82,33 +82,21 @@ var BLOOD_PRESSURE_LOINC_CODES = {
82
82
  };
83
83
 
84
84
  // src/structures/ips_section_resource_map.ts
85
- var IPSSectionResourceMap = {
86
- ["Patient" /* PATIENT */]: ["Patient"],
87
- ["AllergyIntoleranceSection" /* ALLERGIES */]: ["AllergyIntolerance"],
88
- ["MedicationSummarySection" /* MEDICATIONS */]: ["MedicationRequest", "MedicationStatement", "Medication"],
89
- // Medication resource is needed for identifying name of medication
90
- ["ProblemSection" /* PROBLEMS */]: ["Condition"],
91
- ["ImmunizationSection" /* IMMUNIZATIONS */]: ["Immunization", "Organization"],
92
- // Immunization can include Organization as a related resource
93
- ["VitalSignsSection" /* VITAL_SIGNS */]: ["Observation"],
94
- ["MedicalDeviceSection" /* MEDICAL_DEVICES */]: ["DeviceUseStatement", "Device"],
95
- // Device resource is used for medical devices name
96
- ["ResultsSection" /* DIAGNOSTIC_REPORTS */]: ["DiagnosticReport", "Observation"],
97
- ["HistoryOfProceduresSection" /* PROCEDURES */]: ["Procedure"],
98
- ["SocialHistorySection" /* SOCIAL_HISTORY */]: ["Observation"],
99
- ["HistoryOfPregnancySection" /* PREGNANCY_HISTORY */]: ["Observation"],
100
- ["FunctionalStatusSection" /* FUNCTIONAL_STATUS */]: ["Condition", "ClinicalImpression"],
101
- ["HistoryOfPastIllnessSection" /* MEDICAL_HISTORY */]: ["Condition"],
102
- ["PlanOfCareSection" /* CARE_PLAN */]: ["CarePlan"],
103
- ["AdvanceDirectivesSection" /* ADVANCE_DIRECTIVES */]: ["Consent"]
104
- };
105
85
  var IPSSectionResourceFilters = {
86
+ // Patient section: only Patient resource
87
+ ["Patient" /* PATIENT */]: (resource) => resource.resourceType === "Patient",
88
+ // Only include allergies
89
+ ["AllergyIntoleranceSection" /* ALLERGIES */]: (resource) => resource.resourceType === "AllergyIntolerance",
90
+ // includes MedicationRequest, MedicationStatement. Medication is needed for medication names
91
+ ["MedicationSummarySection" /* MEDICATIONS */]: (resource) => ["MedicationRequest", "MedicationStatement", "Medication"].includes(resource.resourceType),
106
92
  // Only include active conditions
107
93
  ["ProblemSection" /* PROBLEMS */]: (resource) => resource.resourceType === "Condition" && resource.clinicalStatus?.coding?.some((c) => !["inactive", "resolved"].includes(c.code)),
108
94
  // Only include completed immunizations
109
95
  ["ImmunizationSection" /* IMMUNIZATIONS */]: (resource) => resource.resourceType === "Immunization" && resource.status === "completed" || resource.resourceType === "Organization",
110
96
  // Only include vital sign Observations (category.coding contains 'vital-signs')
111
97
  ["VitalSignsSection" /* VITAL_SIGNS */]: (resource) => resource.resourceType === "Observation" && resource.category?.some((cat) => cat.coding?.some((c) => c.code === "vital-signs")),
98
+ // Includes DeviceUseStatement. Device is needed for linked device details
99
+ ["MedicalDeviceSection" /* MEDICAL_DEVICES */]: (resource) => ["DeviceUseStatement", "Device"].includes(resource.resourceType),
112
100
  // Only include finalized diagnostic reports
113
101
  ["ResultsSection" /* DIAGNOSTIC_REPORTS */]: (resource) => ["DiagnosticReport", "Observation"].includes(resource.resourceType) && resource.status === "final",
114
102
  // Only include completed procedures
@@ -124,14 +112,9 @@ var IPSSectionResourceFilters = {
124
112
  // Only include active care plans
125
113
  ["PlanOfCareSection" /* CARE_PLAN */]: (resource) => resource.resourceType === "CarePlan" && resource.status === "active",
126
114
  // Only include active advance directives (Consent resources)
127
- ["AdvanceDirectivesSection" /* ADVANCE_DIRECTIVES */]: (resource) => resource.resourceType === "Consent" && resource.status === "active",
128
- // Patient section: only Patient resource
129
- ["Patient" /* PATIENT */]: (resource) => resource.resourceType === "Patient"
115
+ ["AdvanceDirectivesSection" /* ADVANCE_DIRECTIVES */]: (resource) => resource.resourceType === "Consent" && resource.status === "active"
130
116
  };
131
117
  var IPSSectionResourceHelper = class {
132
- static getResourceTypesForSection(section) {
133
- return IPSSectionResourceMap[section] || [];
134
- }
135
118
  static getResourceFilterForSection(section) {
136
119
  return IPSSectionResourceFilters[section];
137
120
  }
@@ -141,11 +124,11 @@ var IPSSectionResourceHelper = class {
141
124
  import { DateTime } from "luxon";
142
125
  var TemplateUtilities = class {
143
126
  /**
144
- * Constructor to initialize the TemplateUtilities with a FHIR Bundle
145
- * @param bundle - FHIR Bundle containing resources
127
+ * Constructor to initialize the TemplateUtilities with a FHIR resources
128
+ * @param resources - FHIR resources
146
129
  */
147
- constructor(bundle) {
148
- this.bundle = bundle;
130
+ constructor(resources) {
131
+ this.resources = resources;
149
132
  }
150
133
  /**
151
134
  * Formats a CodeableConcept object
@@ -176,7 +159,7 @@ var TemplateUtilities = class {
176
159
  return "";
177
160
  }
178
161
  resolveReference(ref) {
179
- if (!ref || !this.bundle || !this.bundle.entry) {
162
+ if (!ref || !this.resources) {
180
163
  return null;
181
164
  }
182
165
  const referenceParts = ref.reference?.split("/");
@@ -185,10 +168,10 @@ var TemplateUtilities = class {
185
168
  }
186
169
  const referenceResourceType = referenceParts[0];
187
170
  const referenceResourceId = referenceParts[1];
188
- const resource = this.bundle.entry.find((entry) => {
189
- return entry.resource && entry.resource.resourceType === referenceResourceType && entry.resource.id === referenceResourceId;
171
+ const resource = this.resources.find((entry) => {
172
+ return entry.resourceType === referenceResourceType && entry.id === referenceResourceId;
190
173
  });
191
- return resource ? resource.resource : null;
174
+ return resource ? resource : null;
192
175
  }
193
176
  /**
194
177
  * Renders a Device reference
@@ -759,7 +742,7 @@ var TemplateUtilities = class {
759
742
  if (parts.length === 2) {
760
743
  const resourceType = parts[0];
761
744
  const resourceId = parts[1];
762
- const resource = this.bundle.entry?.find((entry) => entry.resource?.resourceType === resourceType && entry.resource?.id === resourceId);
745
+ const resource = this.resources?.find((resource2) => resource2.resourceType === resourceType && resource2.id === resourceId);
763
746
  if (resource) {
764
747
  return `${resourceType}/${resourceId}`;
765
748
  }
@@ -799,48 +782,96 @@ var TemplateUtilities = class {
799
782
  // src/narratives/templates/typescript/PatientTemplate.ts
800
783
  var PatientTemplate = class _PatientTemplate {
801
784
  /**
802
- * Generate HTML narrative for Patient resource
803
- * @param resource - FHIR Bundle containing Patient resource
785
+ * Generate HTML narrative for Patient resources
786
+ * @param resources - FHIR Patient resources
804
787
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
805
788
  * @returns HTML string for rendering
806
789
  */
807
- generateNarrative(resource, timezone) {
808
- return _PatientTemplate.generateStaticNarrative(resource, timezone);
790
+ generateNarrative(resources, timezone) {
791
+ return _PatientTemplate.generateStaticNarrative(resources, timezone);
809
792
  }
810
793
  /**
811
794
  * Internal static implementation that actually generates the narrative
812
- * @param resource - FHIR Bundle containing Patient resource
795
+ * @param resources - FHIR Patient resources
813
796
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
814
797
  * @returns HTML string for rendering
815
798
  */
816
799
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
817
- static generateStaticNarrative(resource, timezone) {
818
- const templateUtilities = new TemplateUtilities(resource);
819
- let html = "";
820
- for (const entry of resource.entry || []) {
821
- if (entry.resource?.resourceType === "Patient") {
822
- const patient = entry.resource;
823
- html += `
824
- <div>
825
- <ul>
826
- <li><strong>Name(s):</strong>${this.renderNames(patient)}</li>
827
- <li><strong>Gender:</strong>${patient.gender ? this.capitalize(patient.gender) : ""}</li>
828
- <li><strong>Date of Birth:</strong>${patient.birthDate || ""}</li>
829
- <li><strong>Identifier(s):</strong>${this.renderIdentifiers(patient)}</li>
830
- <li><strong>Telecom:</strong><ul>${this.renderTelecom(patient)}</ul></li>
831
- <li><strong>Address(es):</strong>${this.renderAddresses(patient)}</li>
832
- <li><strong>Marital Status:</strong> ${patient.maritalStatus?.text || ""}</li>
833
- <li><strong>Deceased:</strong>${this.renderDeceased(patient)}</li>
834
- <li><strong>Language(s):</strong>${this.renderCommunication(templateUtilities, patient)}</li>
835
- </ul>
836
- </div>`;
800
+ static generateStaticNarrative(resources, timezone) {
801
+ const templateUtilities = new TemplateUtilities(resources);
802
+ const combinedPatient = this.combinePatients(resources);
803
+ return `<div>
804
+ <ul>
805
+ <li><strong>Name(s):</strong>${this.renderNames(combinedPatient)}</li>
806
+ <li><strong>Gender:</strong>${combinedPatient.gender ? this.capitalize(combinedPatient.gender) : ""}</li>
807
+ <li><strong>Date of Birth:</strong>${combinedPatient.birthDate || ""}</li>
808
+ <li><strong>Identifier(s):</strong>${this.renderIdentifiers(combinedPatient)}</li>
809
+ <li><strong>Telecom:</strong><ul>${this.renderTelecom(combinedPatient)}</ul></li>
810
+ <li><strong>Address(es):</strong>${this.renderAddresses(combinedPatient)}</li>
811
+ <li><strong>Marital Status:</strong> ${combinedPatient.maritalStatus?.text || ""}</li>
812
+ <li><strong>Deceased:</strong>${this.renderDeceased(combinedPatient)}</li>
813
+ <li><strong>Language(s):</strong>${this.renderCommunication(templateUtilities, combinedPatient)}</li>
814
+ </ul>
815
+ </div>`;
816
+ }
817
+ /**
818
+ * Combines multiple patient resources into a single patient object
819
+ * Merges fields, preferring non-empty values
820
+ * @param patients - Array of patient resources
821
+ * @returns Combined patient resource
822
+ */
823
+ static combinePatients(patients) {
824
+ if (patients.length === 1) {
825
+ return patients[0];
826
+ }
827
+ const combined = patients[0];
828
+ const allNames = [];
829
+ const allIdentifiers = [];
830
+ const allTelecom = [];
831
+ const allAddresses = [];
832
+ const allCommunication = [];
833
+ patients.forEach((patient) => {
834
+ if (patient.name) {
835
+ allNames.push(...patient.name);
837
836
  }
838
- }
839
- return html;
837
+ if (patient.identifier) {
838
+ allIdentifiers.push(...patient.identifier);
839
+ }
840
+ if (patient.telecom) {
841
+ allTelecom.push(...patient.telecom);
842
+ }
843
+ if (patient.address) {
844
+ allAddresses.push(...patient.address);
845
+ }
846
+ if (patient.communication) {
847
+ allCommunication.push(...patient.communication);
848
+ }
849
+ if (!combined.gender && patient.gender) {
850
+ combined.gender = patient.gender;
851
+ }
852
+ if (!combined.birthDate && patient.birthDate) {
853
+ combined.birthDate = patient.birthDate;
854
+ }
855
+ if (!combined.maritalStatus && patient.maritalStatus) {
856
+ combined.maritalStatus = patient.maritalStatus;
857
+ }
858
+ if (!combined.deceasedBoolean && patient.deceasedBoolean !== void 0) {
859
+ combined.deceasedBoolean = patient.deceasedBoolean;
860
+ }
861
+ if (!combined.deceasedDateTime && patient.deceasedDateTime) {
862
+ combined.deceasedDateTime = patient.deceasedDateTime;
863
+ }
864
+ });
865
+ combined.name = allNames;
866
+ combined.identifier = allIdentifiers;
867
+ combined.telecom = allTelecom;
868
+ combined.address = allAddresses;
869
+ combined.communication = allCommunication;
870
+ return combined;
840
871
  }
841
872
  /**
842
873
  * Renders patient names as HTML list items
843
- * @param patient - Patient resource
874
+ * @param patient - Patient resources
844
875
  * @returns HTML string of list items
845
876
  */
846
877
  static renderNames(patient) {
@@ -860,7 +891,7 @@ var PatientTemplate = class _PatientTemplate {
860
891
  }
861
892
  /**
862
893
  * Renders patient identifiers as HTML list items
863
- * @param patient - Patient resource
894
+ * @param patient - Patient resources
864
895
  * @returns HTML string of list items
865
896
  */
866
897
  static renderIdentifiers(patient) {
@@ -875,7 +906,7 @@ var PatientTemplate = class _PatientTemplate {
875
906
  }
876
907
  /**
877
908
  * Renders patient telecom information grouped by system
878
- * @param patient - Patient resource
909
+ * @param patient - Patient resources
879
910
  * @returns HTML string grouped by system
880
911
  */
881
912
  static renderTelecom(patient) {
@@ -934,7 +965,7 @@ var PatientTemplate = class _PatientTemplate {
934
965
  }
935
966
  /**
936
967
  * Renders patient addresses as HTML list items
937
- * @param patient - Patient resource
968
+ * @param patient - Patient resources
938
969
  * @returns HTML string of list items
939
970
  */
940
971
  static renderAddresses(patient) {
@@ -956,9 +987,18 @@ var PatientTemplate = class _PatientTemplate {
956
987
  if (address.city) {
957
988
  addressArray.push(address.city);
958
989
  }
990
+ if (address.district) {
991
+ addressArray.push(address.district);
992
+ }
993
+ if (address.state) {
994
+ addressArray.push(address.state);
995
+ }
959
996
  if (address.country) {
960
997
  addressArray.push(address.country);
961
998
  }
999
+ if (address.postalCode) {
1000
+ addressArray.push(address.postalCode);
1001
+ }
962
1002
  }
963
1003
  const addressText = addressArray.join(", ").trim();
964
1004
  if (addressText) {
@@ -969,7 +1009,7 @@ var PatientTemplate = class _PatientTemplate {
969
1009
  }
970
1010
  /**
971
1011
  * Renders patient deceased status
972
- * @param patient - Patient resource
1012
+ * @param patient - Patient resources
973
1013
  * @returns HTML string for deceased status
974
1014
  */
975
1015
  static renderDeceased(patient) {
@@ -984,7 +1024,7 @@ var PatientTemplate = class _PatientTemplate {
984
1024
  /**
985
1025
  * Renders patient communication preferences as HTML list items
986
1026
  * @param templateUtilities - Instance of TemplateUtilities for utility functions
987
- * @param patient - Patient resource
1027
+ * @param patient - Patient resources
988
1028
  * @returns HTML string of list items
989
1029
  */
990
1030
  static renderCommunication(templateUtilities, patient) {
@@ -1019,32 +1059,30 @@ var PatientTemplate = class _PatientTemplate {
1019
1059
  var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1020
1060
  /**
1021
1061
  * Generate HTML narrative for AllergyIntolerance resources
1022
- * @param resource - FHIR Bundle containing AllergyIntolerance resources
1062
+ * @param resources - FHIR resources array containing AllergyIntolerance resources
1023
1063
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1024
1064
  * @returns HTML string for rendering
1025
1065
  */
1026
- generateNarrative(resource, timezone) {
1027
- return _AllergyIntoleranceTemplate.generateStaticNarrative(resource, timezone);
1066
+ generateNarrative(resources, timezone) {
1067
+ return _AllergyIntoleranceTemplate.generateStaticNarrative(resources, timezone);
1028
1068
  }
1029
1069
  /**
1030
1070
  * Internal static implementation that actually generates the narrative
1031
- * @param resource - FHIR Bundle containing AllergyIntolerance resources
1071
+ * @param resources - FHIR resources array containing AllergyIntolerance resources
1032
1072
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1033
1073
  * @returns HTML string for rendering
1034
1074
  */
1035
- static generateStaticNarrative(resource, timezone) {
1036
- const templateUtilities = new TemplateUtilities(resource);
1075
+ static generateStaticNarrative(resources, timezone) {
1076
+ const templateUtilities = new TemplateUtilities(resources);
1037
1077
  const activeAllergies = [];
1038
1078
  const resolvedAllergies = [];
1039
- if (resource.entry && Array.isArray(resource.entry)) {
1040
- for (const entry of resource.entry) {
1041
- const allergy = entry.resource;
1042
- const isResolved = allergy.clinicalStatus?.coding?.some((c) => ["inactive", "resolved"].includes(c.code));
1043
- if (isResolved) {
1044
- resolvedAllergies.push(allergy);
1045
- } else {
1046
- activeAllergies.push(allergy);
1047
- }
1079
+ for (const resourceItem of resources) {
1080
+ const allergy = resourceItem;
1081
+ const isResolved = allergy.clinicalStatus?.coding?.some((c) => ["inactive", "resolved"].includes(c.code));
1082
+ if (isResolved) {
1083
+ resolvedAllergies.push(allergy);
1084
+ } else {
1085
+ activeAllergies.push(allergy);
1048
1086
  }
1049
1087
  }
1050
1088
  activeAllergies.sort((a, b) => {
@@ -1157,12 +1195,12 @@ var AllergyIntoleranceTemplate = class _AllergyIntoleranceTemplate {
1157
1195
  var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1158
1196
  /**
1159
1197
  * Generate HTML narrative for Medication resources
1160
- * @param resource - FHIR Bundle containing Medication resources
1198
+ * @param resources - FHIR Medication resources
1161
1199
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1162
1200
  * @returns HTML string for rendering
1163
1201
  */
1164
- generateNarrative(resource, timezone) {
1165
- return _MedicationSummaryTemplate.generateStaticNarrative(resource, timezone);
1202
+ generateNarrative(resources, timezone) {
1203
+ return _MedicationSummaryTemplate.generateStaticNarrative(resources, timezone);
1166
1204
  }
1167
1205
  /**
1168
1206
  * Safely parse a date string and return a valid Date object or null
@@ -1227,16 +1265,16 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1227
1265
  }
1228
1266
  /**
1229
1267
  * Internal static implementation that actually generates the narrative
1230
- * @param resource - FHIR Bundle containing Medication resources
1268
+ * @param resources - FHIR Medication resources
1231
1269
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1232
1270
  * @returns HTML string for rendering
1233
1271
  */
1234
1272
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
1235
- static generateStaticNarrative(resource, timezone) {
1236
- const templateUtilities = new TemplateUtilities(resource);
1273
+ static generateStaticNarrative(resources, timezone) {
1274
+ const templateUtilities = new TemplateUtilities(resources);
1237
1275
  let html = "";
1238
- const medicationRequests = this.getMedicationRequests(templateUtilities, resource);
1239
- const medicationStatements = this.getMedicationStatements(templateUtilities, resource);
1276
+ const medicationRequests = this.getMedicationRequests(templateUtilities, resources);
1277
+ const medicationStatements = this.getMedicationStatements(templateUtilities, resources);
1240
1278
  const allActiveMedications = [];
1241
1279
  const allInactiveMedications = [];
1242
1280
  medicationRequests.forEach((mr) => {
@@ -1290,33 +1328,33 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1290
1328
  return html;
1291
1329
  }
1292
1330
  /**
1293
- * Extract MedicationRequest resources from the bundle
1331
+ * Extract MedicationRequest resources
1294
1332
  * @param templateUtilities - Instance of TemplateUtilities for utility functions
1295
- * @param resource - FHIR Bundle
1333
+ * @param resources - FHIR Medication resources
1296
1334
  * @returns Array of MedicationRequest resources
1297
1335
  */
1298
- static getMedicationRequests(templateUtilities, resource) {
1299
- if (!resource.entry || !Array.isArray(resource.entry)) {
1336
+ static getMedicationRequests(templateUtilities, resources) {
1337
+ if (resources.length === 0) {
1300
1338
  return [];
1301
1339
  }
1302
- return resource.entry.filter((entry) => entry.resource?.resourceType === "MedicationRequest").map((entry) => ({
1303
- resource: entry.resource,
1304
- extension: templateUtilities.narrativeLinkExtension(entry.resource)
1340
+ return resources.filter((entry) => entry.resourceType === "MedicationRequest").map((entry) => ({
1341
+ resource: entry,
1342
+ extension: templateUtilities.narrativeLinkExtension(entry)
1305
1343
  }));
1306
1344
  }
1307
1345
  /**
1308
- * Extract MedicationStatement resources from the bundle
1346
+ * Extract MedicationStatement resources
1309
1347
  * @param templateUtilities - Instance of TemplateUtilities for utility functions
1310
- * @param resource - FHIR Bundle
1348
+ * @param resources - FHIR Medication resources
1311
1349
  * @returns Array of MedicationStatement resources
1312
1350
  */
1313
- static getMedicationStatements(templateUtilities, resource) {
1314
- if (!resource.entry || !Array.isArray(resource.entry)) {
1351
+ static getMedicationStatements(templateUtilities, resources) {
1352
+ if (resources.length === 0) {
1315
1353
  return [];
1316
1354
  }
1317
- return resource.entry.filter((entry) => entry.resource?.resourceType === "MedicationStatement").map((entry) => ({
1318
- resource: entry.resource,
1319
- extension: templateUtilities.narrativeLinkExtension(entry.resource)
1355
+ return resources.filter((entry) => entry.resourceType === "MedicationStatement").map((entry) => ({
1356
+ resource: entry,
1357
+ extension: templateUtilities.narrativeLinkExtension(entry)
1320
1358
  }));
1321
1359
  }
1322
1360
  /**
@@ -1412,28 +1450,26 @@ var MedicationSummaryTemplate = class _MedicationSummaryTemplate {
1412
1450
  var ImmunizationsTemplate = class _ImmunizationsTemplate {
1413
1451
  /**
1414
1452
  * Generate HTML narrative for Immunization resources
1415
- * @param resource - FHIR Bundle containing Immunization resources
1453
+ * @param resources - FHIR resources array containing Immunization resources
1416
1454
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1417
1455
  * @returns HTML string for rendering
1418
1456
  */
1419
- generateNarrative(resource, timezone) {
1420
- if (resource.entry && Array.isArray(resource.entry)) {
1421
- resource.entry.sort((a, b) => {
1422
- const dateA = a.resource?.occurrenceDateTime;
1423
- const dateB = b.resource?.occurrenceDateTime;
1424
- return typeof dateA === "string" && typeof dateB === "string" ? new Date(dateB).getTime() - new Date(dateA).getTime() : 0;
1425
- });
1426
- }
1427
- return _ImmunizationsTemplate.generateStaticNarrative(resource, timezone);
1457
+ generateNarrative(resources, timezone) {
1458
+ resources.sort((a, b) => {
1459
+ const dateA = a.occurrenceDateTime;
1460
+ const dateB = b.occurrenceDateTime;
1461
+ return typeof dateA === "string" && typeof dateB === "string" ? new Date(dateB).getTime() - new Date(dateA).getTime() : 0;
1462
+ });
1463
+ return _ImmunizationsTemplate.generateStaticNarrative(resources, timezone);
1428
1464
  }
1429
1465
  /**
1430
1466
  * Internal static implementation that actually generates the narrative
1431
- * @param resource - FHIR Bundle containing Immunization resources
1467
+ * @param resources - FHIR resources array containing Immunization resources
1432
1468
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1433
1469
  * @returns HTML string for rendering
1434
1470
  */
1435
- static generateStaticNarrative(resource, timezone) {
1436
- const templateUtilities = new TemplateUtilities(resource);
1471
+ static generateStaticNarrative(resources, timezone) {
1472
+ const templateUtilities = new TemplateUtilities(resources);
1437
1473
  let html = `
1438
1474
  <table>
1439
1475
  <thead>
@@ -1448,21 +1484,20 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
1448
1484
  </tr>
1449
1485
  </thead>
1450
1486
  <tbody>`;
1451
- if (resource.entry && Array.isArray(resource.entry)) {
1452
- for (const entry of resource.entry) {
1453
- if (entry.resource?.resourceType === "Immunization") {
1454
- const imm = entry.resource;
1455
- html += `
1456
- <tr id="${templateUtilities.narrativeLinkId(imm)}">
1457
- <td>${templateUtilities.codeableConcept(imm.vaccineCode)}</td>
1458
- <td>${imm.status || ""}</td>
1459
- <td>${templateUtilities.concatDoseNumber(imm.protocolApplied)}</td>
1460
- <td>${templateUtilities.renderVaccineManufacturer(imm)}</td>
1461
- <td>${imm.lotNumber || ""}</td>
1462
- <td>${templateUtilities.renderNotes(imm.note, timezone)}</td>
1463
- <td>${templateUtilities.renderTime(imm.occurrenceDateTime, timezone)}</td>
1464
- </tr>`;
1465
- }
1487
+ const immunizations = resources.filter((resourceItem) => resourceItem.resourceType === "Immunization");
1488
+ if (immunizations.length > 0) {
1489
+ for (const resourceItem of immunizations) {
1490
+ const imm = resourceItem;
1491
+ html += `
1492
+ <tr id="${templateUtilities.narrativeLinkId(imm)}">
1493
+ <td>${templateUtilities.codeableConcept(imm.vaccineCode)}</td>
1494
+ <td>${imm.status || ""}</td>
1495
+ <td>${templateUtilities.concatDoseNumber(imm.protocolApplied)}</td>
1496
+ <td>${templateUtilities.renderVaccineManufacturer(imm)}</td>
1497
+ <td>${imm.lotNumber || ""}</td>
1498
+ <td>${templateUtilities.renderNotes(imm.note, timezone)}</td>
1499
+ <td>${templateUtilities.renderTime(imm.occurrenceDateTime, timezone)}</td>
1500
+ </tr>`;
1466
1501
  }
1467
1502
  }
1468
1503
  html += `
@@ -1476,23 +1511,23 @@ var ImmunizationsTemplate = class _ImmunizationsTemplate {
1476
1511
  var ProblemListTemplate = class _ProblemListTemplate {
1477
1512
  /**
1478
1513
  * Generate HTML narrative for Problem List
1479
- * @param resource - FHIR Bundle containing Condition resources
1514
+ * @param resources - FHIR Condition resources
1480
1515
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1481
1516
  * @returns HTML string for rendering
1482
1517
  */
1483
- generateNarrative(resource, timezone) {
1484
- return _ProblemListTemplate.generateStaticNarrative(resource, timezone);
1518
+ generateNarrative(resources, timezone) {
1519
+ return _ProblemListTemplate.generateStaticNarrative(resources, timezone);
1485
1520
  }
1486
1521
  /**
1487
1522
  * Internal static implementation that actually generates the narrative
1488
- * @param resource - FHIR Bundle containing Condition resources
1523
+ * @param resources - FHIR Condition resources
1489
1524
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1490
1525
  * @returns HTML string for rendering
1491
1526
  */
1492
- static generateStaticNarrative(resource, timezone) {
1493
- const templateUtilities = new TemplateUtilities(resource);
1527
+ static generateStaticNarrative(resources, timezone) {
1528
+ const templateUtilities = new TemplateUtilities(resources);
1494
1529
  let html = ``;
1495
- const activeConditions = resource.entry?.map((entry) => entry.resource) || [];
1530
+ const activeConditions = resources.map((entry) => entry) || [];
1496
1531
  activeConditions.sort((a, b) => {
1497
1532
  const dateA = a.onsetDateTime ? new Date(a.onsetDateTime).getTime() : 0;
1498
1533
  const dateB = b.onsetDateTime ? new Date(b.onsetDateTime).getTime() : 0;
@@ -1527,22 +1562,22 @@ var ProblemListTemplate = class _ProblemListTemplate {
1527
1562
  var VitalSignsTemplate = class _VitalSignsTemplate {
1528
1563
  /**
1529
1564
  * Generate HTML narrative for Vital Signs
1530
- * @param resource - FHIR Bundle containing Observation resources
1565
+ * @param resources - FHIR Observation resources
1531
1566
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1532
1567
  * @returns HTML string for rendering
1533
1568
  */
1534
- generateNarrative(resource, timezone) {
1535
- return _VitalSignsTemplate.generateStaticNarrative(resource, timezone);
1569
+ generateNarrative(resources, timezone) {
1570
+ return _VitalSignsTemplate.generateStaticNarrative(resources, timezone);
1536
1571
  }
1537
1572
  /**
1538
1573
  * Internal static implementation that actually generates the narrative
1539
- * @param resource - FHIR Bundle containing Observation resources
1574
+ * @param resources - FHIR Observation resources
1540
1575
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1541
1576
  * @returns HTML string for rendering
1542
1577
  */
1543
- static generateStaticNarrative(resource, timezone) {
1544
- const templateUtilities = new TemplateUtilities(resource);
1545
- const observations = resource.entry?.map((entry) => entry.resource) || [];
1578
+ static generateStaticNarrative(resources, timezone) {
1579
+ const templateUtilities = new TemplateUtilities(resources);
1580
+ const observations = resources.map((entry) => entry) || [];
1546
1581
  observations.sort((a, b) => {
1547
1582
  const dateA = a.effectiveDateTime || a.effectivePeriod?.start;
1548
1583
  const dateB = b.effectiveDateTime || b.effectivePeriod?.start;
@@ -1585,28 +1620,21 @@ var VitalSignsTemplate = class _VitalSignsTemplate {
1585
1620
  var MedicalDevicesTemplate = class _MedicalDevicesTemplate {
1586
1621
  /**
1587
1622
  * Generate HTML narrative for Medical Device resources
1588
- * @param resource - FHIR Bundle containing Device resources
1623
+ * @param resources - FHIR resources array containing Device resources
1589
1624
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1590
1625
  * @returns HTML string for rendering
1591
1626
  */
1592
- generateNarrative(resource, timezone) {
1593
- if (resource.entry && Array.isArray(resource.entry)) {
1594
- resource.entry.sort((a, b) => {
1595
- const dateA = a.resource?.recordedOn;
1596
- const dateB = b.resource?.recordedOn;
1597
- return typeof dateA === "string" && typeof dateB === "string" ? new Date(dateB).getTime() - new Date(dateA).getTime() : 0;
1598
- });
1599
- }
1600
- return _MedicalDevicesTemplate.generateStaticNarrative(resource, timezone);
1627
+ generateNarrative(resources, timezone) {
1628
+ return _MedicalDevicesTemplate.generateStaticNarrative(resources, timezone);
1601
1629
  }
1602
1630
  /**
1603
1631
  * Internal static implementation that actually generates the narrative
1604
- * @param resource - FHIR Bundle containing Device resources
1632
+ * @param resources - FHIR resources array containing Device resources
1605
1633
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1606
1634
  * @returns HTML string for rendering
1607
1635
  */
1608
- static generateStaticNarrative(resource, timezone) {
1609
- const templateUtilities = new TemplateUtilities(resource);
1636
+ static generateStaticNarrative(resources, timezone) {
1637
+ const templateUtilities = new TemplateUtilities(resources);
1610
1638
  let html = `
1611
1639
  <table>
1612
1640
  <thead>
@@ -1618,19 +1646,19 @@ var MedicalDevicesTemplate = class _MedicalDevicesTemplate {
1618
1646
  </tr>
1619
1647
  </thead>
1620
1648
  <tbody>`;
1621
- if (resource.entry && Array.isArray(resource.entry)) {
1622
- for (const entry of resource.entry) {
1623
- if (entry.resource?.resourceType === "DeviceUseStatement") {
1624
- const dus = entry.resource;
1625
- html += `
1626
- <tr id="${templateUtilities.narrativeLinkId(dus)}">
1627
- <td>${templateUtilities.renderDevice(dus.device)}</td>
1628
- <td>${dus.status || ""}</td>
1629
- <td>${templateUtilities.renderNotes(dus.note, timezone)}</td>
1630
- <td>${templateUtilities.renderRecorded(dus.recordedOn, timezone)}</td>
1631
- </tr>`;
1632
- }
1633
- }
1649
+ const deviceStatements = resources.filter((resourceItem) => resourceItem.resourceType === "DeviceUseStatement").map((resourceItem) => resourceItem).sort((a, b) => {
1650
+ const dateA = a.recordedOn;
1651
+ const dateB = b.recordedOn;
1652
+ return typeof dateA === "string" && typeof dateB === "string" ? new Date(dateB).getTime() - new Date(dateA).getTime() : 0;
1653
+ });
1654
+ for (const dus of deviceStatements) {
1655
+ html += `
1656
+ <tr id="${templateUtilities.narrativeLinkId(dus)}">
1657
+ <td>${templateUtilities.renderDevice(dus.device)}</td>
1658
+ <td>${dus.status || ""}</td>
1659
+ <td>${templateUtilities.renderNotes(dus.note, timezone)}</td>
1660
+ <td>${templateUtilities.renderRecorded(dus.recordedOn, timezone)}</td>
1661
+ </tr>`;
1634
1662
  }
1635
1663
  html += `
1636
1664
  </tbody>
@@ -1643,23 +1671,23 @@ var MedicalDevicesTemplate = class _MedicalDevicesTemplate {
1643
1671
  var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
1644
1672
  /**
1645
1673
  * Generate HTML narrative for Diagnostic Results
1646
- * @param resource - FHIR Bundle containing Observation and DiagnosticReport resources
1674
+ * @param resources - FHIR resources array containing Observation and DiagnosticReport resources
1647
1675
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1648
1676
  * @returns HTML string for rendering
1649
1677
  */
1650
- generateNarrative(resource, timezone) {
1651
- return _DiagnosticResultsTemplate.generateStaticNarrative(resource, timezone);
1678
+ generateNarrative(resources, timezone) {
1679
+ return _DiagnosticResultsTemplate.generateStaticNarrative(resources, timezone);
1652
1680
  }
1653
1681
  /**
1654
1682
  * Internal static implementation that actually generates the narrative
1655
- * @param resource - FHIR Bundle containing Observation and DiagnosticReport resources
1683
+ * @param resources - FHIR resources array containing Observation and DiagnosticReport resources
1656
1684
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1657
1685
  * @returns HTML string for rendering
1658
1686
  */
1659
- static generateStaticNarrative(resource, timezone) {
1660
- const templateUtilities = new TemplateUtilities(resource);
1687
+ static generateStaticNarrative(resources, timezone) {
1688
+ const templateUtilities = new TemplateUtilities(resources);
1661
1689
  let html = "";
1662
- const observations = this.getObservations(resource);
1690
+ const observations = this.getObservations(resources);
1663
1691
  if (observations.length > 0) {
1664
1692
  observations.sort((a, b) => {
1665
1693
  const dateA = a.effectiveDateTime || a.effectivePeriod?.start;
@@ -1668,7 +1696,7 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
1668
1696
  });
1669
1697
  html += this.renderObservations(templateUtilities, observations, timezone);
1670
1698
  }
1671
- const diagnosticReports = this.getDiagnosticReports(resource);
1699
+ const diagnosticReports = this.getDiagnosticReports(resources);
1672
1700
  if (diagnosticReports.length > 0) {
1673
1701
  diagnosticReports.sort((a, b) => {
1674
1702
  const dateA = a.issued;
@@ -1680,26 +1708,20 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
1680
1708
  return html;
1681
1709
  }
1682
1710
  /**
1683
- * Extract Observation resources from the bundle
1684
- * @param resource - FHIR Bundle
1685
- * @returns Array of Observation resources
1686
- */
1687
- static getObservations(resource) {
1688
- if (!resource.entry || !Array.isArray(resource.entry)) {
1689
- return [];
1690
- }
1691
- return resource.entry.filter((entry) => entry.resource?.resourceType === "Observation").map((entry) => entry.resource);
1711
+ * Get all Observation resources from the resource array
1712
+ * @param resources - FHIR resources array
1713
+ * @returns Array of Observation resources
1714
+ */
1715
+ static getObservations(resources) {
1716
+ return resources.filter((resourceItem) => resourceItem.resourceType === "Observation").map((resourceItem) => resourceItem);
1692
1717
  }
1693
1718
  /**
1694
- * Extract DiagnosticReport resources from the bundle
1695
- * @param resource - FHIR Bundle
1719
+ * Get all DiagnosticReport resources from the resource array
1720
+ * @param resources - FHIR resources array
1696
1721
  * @returns Array of DiagnosticReport resources
1697
1722
  */
1698
- static getDiagnosticReports(resource) {
1699
- if (!resource.entry || !Array.isArray(resource.entry)) {
1700
- return [];
1701
- }
1702
- return resource.entry.filter((entry) => entry.resource?.resourceType === "DiagnosticReport").map((entry) => entry.resource);
1723
+ static getDiagnosticReports(resources) {
1724
+ return resources.filter((resourceItem) => resourceItem.resourceType === "DiagnosticReport").map((resourceItem) => resourceItem);
1703
1725
  }
1704
1726
  /**
1705
1727
  * Render HTML table for Observation resources
@@ -1785,26 +1807,26 @@ var DiagnosticResultsTemplate = class _DiagnosticResultsTemplate {
1785
1807
  var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
1786
1808
  /**
1787
1809
  * Generate HTML narrative for Procedure resources
1788
- * @param resource - FHIR Bundle containing Procedure resources
1810
+ * @param resources - FHIR Procedure resources
1789
1811
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1790
1812
  * @returns HTML string for rendering
1791
1813
  */
1792
- generateNarrative(resource, timezone) {
1793
- resource.entry?.sort((a, b) => {
1794
- const dateA = a.resource.performedDateTime || a.resource.performedPeriod?.start;
1795
- const dateB = b.resource.performedDateTime || b.resource.performedPeriod?.start;
1814
+ generateNarrative(resources, timezone) {
1815
+ resources.sort((a, b) => {
1816
+ const dateA = a.performedDateTime || a.performedPeriod?.start;
1817
+ const dateB = b.performedDateTime || b.performedPeriod?.start;
1796
1818
  return dateA && dateB ? new Date(dateB).getTime() - new Date(dateA).getTime() : 0;
1797
1819
  });
1798
- return _HistoryOfProceduresTemplate.generateStaticNarrative(resource, timezone);
1820
+ return _HistoryOfProceduresTemplate.generateStaticNarrative(resources, timezone);
1799
1821
  }
1800
1822
  /**
1801
1823
  * Internal static implementation that actually generates the narrative
1802
- * @param resource - FHIR Bundle containing Procedure resources
1824
+ * @param resources - FHIR Procedure resources
1803
1825
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1804
1826
  * @returns HTML string for rendering
1805
1827
  */
1806
- static generateStaticNarrative(resource, timezone) {
1807
- const templateUtilities = new TemplateUtilities(resource);
1828
+ static generateStaticNarrative(resources, timezone) {
1829
+ const templateUtilities = new TemplateUtilities(resources);
1808
1830
  let html = `
1809
1831
  <table>
1810
1832
  <thead>
@@ -1815,16 +1837,14 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
1815
1837
  </tr>
1816
1838
  </thead>
1817
1839
  <tbody>`;
1818
- if (resource.entry && Array.isArray(resource.entry)) {
1819
- for (const entry of resource.entry) {
1820
- const proc = entry.resource;
1821
- html += `
1822
- <tr id="${templateUtilities.narrativeLinkId(proc)}">
1823
- <td>${templateUtilities.codeableConcept(proc.code, "display")}</td>
1824
- <td>${templateUtilities.renderNotes(proc.note, timezone)}</td>
1825
- <td>${proc.performedDateTime ? templateUtilities.renderTime(proc.performedDateTime, timezone) : proc.performedPeriod ? templateUtilities.renderPeriod(proc.performedPeriod, timezone) : ""}</td>
1826
- </tr>`;
1827
- }
1840
+ for (const resourceItem of resources) {
1841
+ const proc = resourceItem;
1842
+ html += `
1843
+ <tr id="${templateUtilities.narrativeLinkId(proc)}">
1844
+ <td>${templateUtilities.codeableConcept(proc.code, "display")}</td>
1845
+ <td>${templateUtilities.renderNotes(proc.note, timezone)}</td>
1846
+ <td>${proc.performedDateTime ? templateUtilities.renderTime(proc.performedDateTime, timezone) : proc.performedPeriod ? templateUtilities.renderPeriod(proc.performedPeriod, timezone) : ""}</td>
1847
+ </tr>`;
1828
1848
  }
1829
1849
  html += `
1830
1850
  </tbody>
@@ -1837,22 +1857,22 @@ var HistoryOfProceduresTemplate = class _HistoryOfProceduresTemplate {
1837
1857
  var SocialHistoryTemplate = class _SocialHistoryTemplate {
1838
1858
  /**
1839
1859
  * Generate HTML narrative for Social History
1840
- * @param resource - FHIR Bundle containing Observation resources
1860
+ * @param resources - FHIR Observation resources
1841
1861
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1842
1862
  * @returns HTML string for rendering
1843
1863
  */
1844
- generateNarrative(resource, timezone) {
1845
- return _SocialHistoryTemplate.generateStaticNarrative(resource, timezone);
1864
+ generateNarrative(resources, timezone) {
1865
+ return _SocialHistoryTemplate.generateStaticNarrative(resources, timezone);
1846
1866
  }
1847
1867
  /**
1848
1868
  * Internal static implementation that actually generates the narrative
1849
- * @param resource - FHIR Bundle containing Observation resources
1869
+ * @param resources - FHIR Observation resources
1850
1870
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1851
1871
  * @returns HTML string for rendering
1852
1872
  */
1853
- static generateStaticNarrative(resource, timezone) {
1854
- const templateUtilities = new TemplateUtilities(resource);
1855
- const observations = resource.entry?.map((entry) => entry.resource) || [];
1873
+ static generateStaticNarrative(resources, timezone) {
1874
+ const templateUtilities = new TemplateUtilities(resources);
1875
+ const observations = resources.map((entry) => entry) || [];
1856
1876
  observations.sort((a, b) => {
1857
1877
  const dateA = a.effectiveDateTime || a.effectivePeriod?.start;
1858
1878
  const dateB = b.effectiveDateTime || b.effectivePeriod?.start;
@@ -1891,14 +1911,14 @@ var SocialHistoryTemplate = class _SocialHistoryTemplate {
1891
1911
  var PastHistoryOfIllnessTemplate = class {
1892
1912
  /**
1893
1913
  * Generate HTML narrative for Past History of Illnesses
1894
- * @param resource - FHIR Bundle containing Condition resources
1914
+ * @param resources - FHIR Condition resources
1895
1915
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1896
1916
  * @returns HTML string for rendering
1897
1917
  */
1898
- generateNarrative(resource, timezone) {
1899
- const templateUtilities = new TemplateUtilities(resource);
1918
+ generateNarrative(resources, timezone) {
1919
+ const templateUtilities = new TemplateUtilities(resources);
1900
1920
  let html = ``;
1901
- const resolvedConditions = resource.entry?.map((entry) => entry.resource) || [];
1921
+ const resolvedConditions = resources.map((entry) => entry) || [];
1902
1922
  resolvedConditions.sort((a, b) => {
1903
1923
  const dateA = a.onsetDateTime ? new Date(a.onsetDateTime).getTime() : 0;
1904
1924
  const dateB = b.onsetDateTime ? new Date(b.onsetDateTime).getTime() : 0;
@@ -1935,13 +1955,13 @@ var PastHistoryOfIllnessTemplate = class {
1935
1955
  var PlanOfCareTemplate = class {
1936
1956
  /**
1937
1957
  * Generate HTML narrative for Plan of Care
1938
- * @param resource - FHIR Bundle containing CarePlan resources
1958
+ * @param resources - FHIR CarePlan resources
1939
1959
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1940
1960
  * @returns HTML string for rendering
1941
1961
  */
1942
- generateNarrative(resource, timezone) {
1943
- const templateUtilities = new TemplateUtilities(resource);
1944
- const carePlans = resource.entry?.map((entry) => entry.resource) || [];
1962
+ generateNarrative(resources, timezone) {
1963
+ const templateUtilities = new TemplateUtilities(resources);
1964
+ const carePlans = resources.map((entry) => entry) || [];
1945
1965
  carePlans.sort((a, b) => {
1946
1966
  const endA = a.period?.end ? new Date(a.period?.end).getTime() : 0;
1947
1967
  const endB = b.period?.end ? new Date(b.period?.end).getTime() : 0;
@@ -1980,37 +2000,35 @@ var PlanOfCareTemplate = class {
1980
2000
  var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
1981
2001
  /**
1982
2002
  * Generate HTML narrative for Functional Status
1983
- * @param resource - FHIR Bundle containing Observation resources
2003
+ * @param resources - FHIR resources array containing Observation resources
1984
2004
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1985
2005
  * @returns HTML string for rendering
1986
2006
  */
1987
- generateNarrative(resource, timezone) {
1988
- return _FunctionalStatusTemplate.generateStaticNarrative(resource, timezone);
2007
+ generateNarrative(resources, timezone) {
2008
+ return _FunctionalStatusTemplate.generateStaticNarrative(resources, timezone);
1989
2009
  }
1990
2010
  /**
1991
2011
  * Internal static implementation that actually generates the narrative
1992
- * @param resource - FHIR Bundle containing Observation resources
2012
+ * @param resources - FHIR resources array containing Observation resources
1993
2013
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
1994
2014
  * @returns HTML string for rendering
1995
2015
  */
1996
- static generateStaticNarrative(resource, timezone) {
1997
- const templateUtilities = new TemplateUtilities(resource);
2016
+ static generateStaticNarrative(resources, timezone) {
2017
+ const templateUtilities = new TemplateUtilities(resources);
1998
2018
  let html = ``;
1999
2019
  const activeConditions = [];
2000
2020
  const clinicalImpressions = [];
2001
- if (resource.entry && Array.isArray(resource.entry)) {
2002
- for (const entry of resource.entry) {
2003
- if (entry.resource?.resourceType === "Condition") {
2004
- const cond = entry.resource;
2005
- const isResolved = cond.clinicalStatus?.coding?.some(
2006
- (c) => c.code === "resolved" || c.code === "inactive" || c.display?.toLowerCase().includes("resolved")
2007
- );
2008
- if (!isResolved) {
2009
- activeConditions.push(cond);
2010
- }
2011
- } else if (entry.resource?.resourceType === "ClinicalImpression") {
2012
- clinicalImpressions.push(entry.resource);
2021
+ for (const resourceItem of resources) {
2022
+ if (resourceItem.resourceType === "Condition") {
2023
+ const cond = resourceItem;
2024
+ const isResolved = cond.clinicalStatus?.coding?.some(
2025
+ (c) => c.code === "resolved" || c.code === "inactive" || c.display?.toLowerCase().includes("resolved")
2026
+ );
2027
+ if (!isResolved) {
2028
+ activeConditions.push(cond);
2013
2029
  }
2030
+ } else if (resourceItem.resourceType === "ClinicalImpression") {
2031
+ clinicalImpressions.push(resourceItem);
2014
2032
  }
2015
2033
  }
2016
2034
  activeConditions.sort((a, b) => {
@@ -2107,22 +2125,22 @@ var FunctionalStatusTemplate = class _FunctionalStatusTemplate {
2107
2125
  var PregnancyTemplate = class _PregnancyTemplate {
2108
2126
  /**
2109
2127
  * Generate HTML narrative for Pregnancy
2110
- * @param resource - FHIR Bundle containing Observation resources
2128
+ * @param resources - FHIR Observation resources
2111
2129
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
2112
2130
  * @returns HTML string for rendering
2113
2131
  */
2114
- generateNarrative(resource, timezone) {
2115
- return _PregnancyTemplate.generateStaticNarrative(resource, timezone);
2132
+ generateNarrative(resources, timezone) {
2133
+ return _PregnancyTemplate.generateStaticNarrative(resources, timezone);
2116
2134
  }
2117
2135
  /**
2118
2136
  * Internal static implementation that actually generates the narrative
2119
- * @param resource - FHIR Bundle containing Observation resources
2137
+ * @param resources - FHIR Observation resources
2120
2138
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
2121
2139
  * @returns HTML string for rendering
2122
2140
  */
2123
- static generateStaticNarrative(resource, timezone) {
2124
- const templateUtilities = new TemplateUtilities(resource);
2125
- const observations = resource.entry?.map((entry) => entry.resource) || [];
2141
+ static generateStaticNarrative(resources, timezone) {
2142
+ const templateUtilities = new TemplateUtilities(resources);
2143
+ const observations = resources.map((entry) => entry) || [];
2126
2144
  observations.sort((a, b) => {
2127
2145
  const dateA = a.effectiveDateTime || a.effectivePeriod?.start;
2128
2146
  const dateB = b.effectiveDateTime || b.effectivePeriod?.start;
@@ -2138,8 +2156,8 @@ var PregnancyTemplate = class _PregnancyTemplate {
2138
2156
  </tr>
2139
2157
  </thead>
2140
2158
  <tbody>`;
2141
- for (const resource2 of observations) {
2142
- const obs = resource2;
2159
+ for (const resource of observations) {
2160
+ const obs = resource;
2143
2161
  html += `
2144
2162
  <tr id="${templateUtilities.narrativeLinkId(obs)}">
2145
2163
  <td>${templateUtilities.extractPregnancyStatus(obs)}</td>
@@ -2158,29 +2176,27 @@ var PregnancyTemplate = class _PregnancyTemplate {
2158
2176
  var AdvanceDirectivesTemplate = class _AdvanceDirectivesTemplate {
2159
2177
  /**
2160
2178
  * Generate HTML narrative for Advance Directives
2161
- * @param resource - FHIR Bundle containing Advance Directive resources
2179
+ * @param resources - FHIR Consent resources
2162
2180
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
2163
2181
  * @returns HTML string for rendering
2164
2182
  */
2165
- generateNarrative(resource, timezone) {
2166
- if (resource.entry && Array.isArray(resource.entry)) {
2167
- resource.entry.sort((a, b) => {
2168
- const dateA = new Date(a.resource.dateTime || 0);
2169
- const dateB = new Date(b.resource.dateTime || 0);
2170
- return dateB.getTime() - dateA.getTime();
2171
- });
2172
- }
2173
- return _AdvanceDirectivesTemplate.generateStaticNarrative(resource, timezone);
2183
+ generateNarrative(resources, timezone) {
2184
+ resources.sort((a, b) => {
2185
+ const dateA = new Date(a.dateTime || 0);
2186
+ const dateB = new Date(b.dateTime || 0);
2187
+ return dateB.getTime() - dateA.getTime();
2188
+ });
2189
+ return _AdvanceDirectivesTemplate.generateStaticNarrative(resources, timezone);
2174
2190
  }
2175
2191
  /**
2176
2192
  * Internal static implementation that actually generates the narrative
2177
- * @param resource - FHIR Bundle containing Advance Directive resources
2193
+ * @param resources - FHIR Consent resources
2178
2194
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
2179
2195
  * @returns HTML string for rendering
2180
2196
  */
2181
2197
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
2182
- static generateStaticNarrative(resource, timezone) {
2183
- const templateUtilities = new TemplateUtilities(resource);
2198
+ static generateStaticNarrative(resources, timezone) {
2199
+ const templateUtilities = new TemplateUtilities(resources);
2184
2200
  let html = `
2185
2201
  <table>
2186
2202
  <thead>
@@ -2192,17 +2208,15 @@ var AdvanceDirectivesTemplate = class _AdvanceDirectivesTemplate {
2192
2208
  </tr>
2193
2209
  </thead>
2194
2210
  <tbody>`;
2195
- if (resource.entry && Array.isArray(resource.entry)) {
2196
- for (const entry of resource.entry) {
2197
- const consent = entry.resource;
2198
- html += `
2199
- <tr id="${templateUtilities.narrativeLinkId(consent)}">
2200
- <td>${templateUtilities.codeableConcept(consent.scope, "display")}</td>
2201
- <td>${consent.status || ""}</td>
2202
- <td>${consent.provision?.action ? templateUtilities.concatCodeableConcept(consent.provision.action) : ""}</td>
2203
- <td>${consent.dateTime || ""}</td>
2204
- </tr>`;
2205
- }
2211
+ for (const resourceItem of resources) {
2212
+ const consent = resourceItem;
2213
+ html += `
2214
+ <tr id="${templateUtilities.narrativeLinkId(consent)}">
2215
+ <td>${templateUtilities.codeableConcept(consent.scope, "display")}</td>
2216
+ <td>${consent.status || ""}</td>
2217
+ <td>${consent.provision?.action ? templateUtilities.concatCodeableConcept(consent.provision.action) : ""}</td>
2218
+ <td>${consent.dateTime || ""}</td>
2219
+ </tr>`;
2206
2220
  }
2207
2221
  html += `
2208
2222
  </tbody>
@@ -2216,16 +2230,16 @@ var TypeScriptTemplateMapper = class {
2216
2230
  /**
2217
2231
  * Generates HTML narrative for a specific IPS section
2218
2232
  * @param section - The IPS section
2219
- * @param resource - FHIR Bundle containing resources
2233
+ * @param resources - FHIR resources
2220
2234
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
2221
2235
  * @returns HTML string for rendering
2222
2236
  */
2223
- static generateNarrative(section, resource, timezone) {
2237
+ static generateNarrative(section, resources, timezone) {
2224
2238
  const templateClass = this.sectionToTemplate[section];
2225
2239
  if (!templateClass) {
2226
2240
  throw new Error(`No template found for section: ${section}`);
2227
2241
  }
2228
- return templateClass.generateNarrative(resource, timezone);
2242
+ return templateClass.generateNarrative(resources, timezone);
2229
2243
  }
2230
2244
  };
2231
2245
  // Map of section types to their template classes
@@ -2288,14 +2302,7 @@ var NarrativeGenerator = class {
2288
2302
  return void 0;
2289
2303
  }
2290
2304
  try {
2291
- const bundle = {
2292
- resourceType: "Bundle",
2293
- type: "collection",
2294
- entry: resources.map((resource) => ({
2295
- resource
2296
- }))
2297
- };
2298
- const content = TypeScriptTemplateMapper.generateNarrative(section, bundle, timezone);
2305
+ const content = TypeScriptTemplateMapper.generateNarrative(section, resources, timezone);
2299
2306
  if (!content) {
2300
2307
  return void 0;
2301
2308
  }
@@ -2380,13 +2387,16 @@ var ComprehensiveIPSCompositionBuilder = class {
2380
2387
  /**
2381
2388
  * sets the patient resource for the IPS Composition.
2382
2389
  * This is not needed if you are calling read_bundle, but can be used to set the patient resource directly.
2383
- * @param patient - FHIR Patient resource to set
2390
+ * @param patients - FHIR Patient resource to set
2384
2391
  */
2385
- setPatient(patient) {
2386
- if (!patient || patient.resourceType !== "Patient") {
2392
+ setPatient(patients) {
2393
+ if (!Array.isArray(patients)) {
2394
+ patients = [patients];
2395
+ }
2396
+ if (patients.length === 0 || !patients.every((patient) => patient.resourceType === "Patient")) {
2387
2397
  throw new Error("Invalid Patient resource");
2388
2398
  }
2389
- this.patient = patient;
2399
+ this.patients = patients;
2390
2400
  return this;
2391
2401
  }
2392
2402
  /**
@@ -2444,21 +2454,26 @@ var ComprehensiveIPSCompositionBuilder = class {
2444
2454
  if (!bundle.entry) {
2445
2455
  return this;
2446
2456
  }
2447
- const patientEntry = bundle.entry.find((e) => e.resource?.resourceType === "Patient");
2448
- if (!patientEntry || !patientEntry.resource) {
2457
+ const patientEntries = [];
2458
+ const resources = [];
2459
+ bundle.entry.forEach((e) => {
2460
+ if (e.resource?.resourceType === "Patient") {
2461
+ patientEntries.push(e.resource);
2462
+ this.resources.add(e.resource);
2463
+ } else if (e.resource) {
2464
+ resources.push(e.resource);
2465
+ }
2466
+ });
2467
+ if (patientEntries.length === 0) {
2449
2468
  throw new Error("Patient resource not found in the bundle");
2450
2469
  }
2451
- this.patient = patientEntry.resource;
2452
- const resources = bundle.entry.map((e) => e.resource);
2470
+ this.patients = patientEntries;
2453
2471
  for (const sectionType of Object.values(IPSSections)) {
2454
- const resourceTypesForSection = IPSSectionResourceHelper.getResourceTypesForSection(sectionType);
2455
- const customFilter = IPSSectionResourceHelper.getResourceFilterForSection(sectionType);
2456
- let sectionResources = resources.filter(
2457
- (r) => r && typeof r.resourceType === "string" && resourceTypesForSection.includes(r.resourceType)
2458
- );
2459
- if (customFilter) {
2460
- sectionResources = sectionResources.filter((resource) => resource && customFilter(resource));
2472
+ if (sectionType === "Patient" /* PATIENT */) {
2473
+ continue;
2461
2474
  }
2475
+ const sectionFilter = IPSSectionResourceHelper.getResourceFilterForSection(sectionType);
2476
+ const sectionResources = resources.filter((resource) => sectionFilter(resource));
2462
2477
  await this.addSectionAsync(sectionType, sectionResources, timezone);
2463
2478
  }
2464
2479
  return this;
@@ -2469,16 +2484,18 @@ var ComprehensiveIPSCompositionBuilder = class {
2469
2484
  * @param authorOrganizationName - Name of the authoring organization
2470
2485
  * @param baseUrl - Base URL for the FHIR server (e.g., 'https://example.com/fhir')
2471
2486
  * @param timezone - Optional timezone to use for date formatting (e.g., 'America/New_York', 'Europe/London')
2487
+ * @param patientId - Optional patient ID to use as primary patient for composition reference
2472
2488
  */
2473
- async buildBundleAsync(authorOrganizationId, authorOrganizationName, baseUrl, timezone) {
2489
+ async buildBundleAsync(authorOrganizationId, authorOrganizationName, baseUrl, timezone, patientId) {
2474
2490
  if (baseUrl.endsWith("/")) {
2475
2491
  baseUrl = baseUrl.slice(0, -1);
2476
2492
  }
2477
- if (!this.patient) {
2493
+ if (!this.patients) {
2478
2494
  throw new Error("Patient resource must be set before building the bundle");
2479
2495
  }
2496
+ const primaryPatientId = patientId ?? this.patients[0].id;
2480
2497
  const composition = {
2481
- id: `Composition-${this.patient.id}`,
2498
+ id: `Composition-${primaryPatientId}`,
2482
2499
  resourceType: "Composition",
2483
2500
  status: "final",
2484
2501
  type: {
@@ -2489,7 +2506,7 @@ var ComprehensiveIPSCompositionBuilder = class {
2489
2506
  }]
2490
2507
  },
2491
2508
  subject: {
2492
- reference: `Patient/${this.patient.id}`
2509
+ reference: `Patient/${primaryPatientId}`
2493
2510
  },
2494
2511
  author: [{
2495
2512
  reference: `Organization/${authorOrganizationId}`,
@@ -2501,7 +2518,7 @@ var ComprehensiveIPSCompositionBuilder = class {
2501
2518
  section: this.sections,
2502
2519
  text: await NarrativeGenerator.generateNarrativeAsync(
2503
2520
  "Patient" /* PATIENT */,
2504
- [this.patient],
2521
+ this.patients,
2505
2522
  timezone,
2506
2523
  true
2507
2524
  )
@@ -2520,9 +2537,11 @@ var ComprehensiveIPSCompositionBuilder = class {
2520
2537
  fullUrl: `${baseUrl}/Composition/${composition.id}`,
2521
2538
  resource: composition
2522
2539
  });
2523
- bundle.entry?.push({
2524
- fullUrl: `${baseUrl}/Patient/${this.patient.id}`,
2525
- resource: this.patient
2540
+ this.patients.forEach((patient) => {
2541
+ bundle.entry?.push({
2542
+ fullUrl: `${baseUrl}/Patient/${patient.id}`,
2543
+ resource: patient
2544
+ });
2526
2545
  });
2527
2546
  this.resources.forEach((resource) => {
2528
2547
  if (resource.resourceType !== "Patient") {