fhir-data-utils-ts 0.4.0 → 0.6.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 (82) hide show
  1. package/.codex/skills/govern-fhir-data-utilities/SKILL.md +35 -0
  2. package/CHANGELOG.md +61 -0
  3. package/README.md +35 -0
  4. package/dist/appointment-communication-test-data.d.ts +63 -0
  5. package/dist/appointment-communication-test-data.js +77 -0
  6. package/dist/builders/department-service-graph.d.ts +32 -0
  7. package/dist/builders/department-service-graph.js +102 -0
  8. package/dist/builders/device-compliance-graph.d.ts +51 -0
  9. package/dist/builders/device-compliance-graph.js +115 -0
  10. package/dist/builders/index.d.ts +3 -0
  11. package/dist/builders/index.js +3 -0
  12. package/dist/builders/service-schedule-graph.d.ts +58 -0
  13. package/dist/builders/service-schedule-graph.js +149 -0
  14. package/dist/care-emergency-alert.d.ts +18 -0
  15. package/dist/care-emergency-alert.js +29 -1
  16. package/dist/claims/appointment-claims.d.ts +6 -0
  17. package/dist/claims/appointment-claims.js +6 -0
  18. package/dist/claims/device-metric-claims.d.ts +16 -0
  19. package/dist/claims/device-metric-claims.js +25 -0
  20. package/dist/claims/encounter-claims.d.ts +15 -0
  21. package/dist/claims/encounter-claims.js +19 -0
  22. package/dist/claims/encounter-history-claims.d.ts +20 -0
  23. package/dist/claims/encounter-history-claims.js +34 -0
  24. package/dist/claims/healthcare-service-claims.d.ts +32 -0
  25. package/dist/claims/healthcare-service-claims.js +54 -0
  26. package/dist/claims/index.d.ts +5 -0
  27. package/dist/claims/index.js +5 -0
  28. package/dist/claims/location-claims.d.ts +3 -0
  29. package/dist/claims/location-claims.js +6 -0
  30. package/dist/claims/organization-claims.d.ts +3 -1
  31. package/dist/claims/organization-claims.js +4 -1
  32. package/dist/claims/procedure-claims.d.ts +2 -0
  33. package/dist/claims/procedure-claims.js +4 -0
  34. package/dist/claims/regulated-authorization-claims.d.ts +17 -0
  35. package/dist/claims/regulated-authorization-claims.js +27 -0
  36. package/dist/claims/schedule-slot-claims.d.ts +45 -0
  37. package/dist/claims/schedule-slot-claims.js +70 -0
  38. package/dist/constants/fhir-resource-types.d.ts +10 -0
  39. package/dist/constants/fhir-resource-types.js +4 -0
  40. package/dist/converters/convert-appointment-communication.d.ts +14 -0
  41. package/dist/converters/convert-appointment-communication.js +97 -0
  42. package/dist/converters/convert-appointment.js +16 -7
  43. package/dist/converters/convert-device-metric.d.ts +3 -0
  44. package/dist/converters/convert-device-metric.js +37 -0
  45. package/dist/converters/convert-document-reference.js +5 -0
  46. package/dist/converters/convert-encounter-history.d.ts +5 -0
  47. package/dist/converters/convert-encounter-history.js +83 -0
  48. package/dist/converters/convert-encounter.d.ts +4 -0
  49. package/dist/converters/convert-encounter.js +73 -1
  50. package/dist/converters/convert-healthcare-service.d.ts +7 -0
  51. package/dist/converters/convert-healthcare-service.js +60 -0
  52. package/dist/converters/convert-location.d.ts +4 -0
  53. package/dist/converters/convert-location.js +41 -3
  54. package/dist/converters/convert-organization.d.ts +2 -0
  55. package/dist/converters/convert-organization.js +20 -3
  56. package/dist/converters/convert-procedure.d.ts +2 -0
  57. package/dist/converters/convert-procedure.js +21 -0
  58. package/dist/converters/convert-regulated-authorization.d.ts +3 -0
  59. package/dist/converters/convert-regulated-authorization.js +34 -0
  60. package/dist/converters/convert-schedule-slot.d.ts +9 -0
  61. package/dist/converters/convert-schedule-slot.js +96 -0
  62. package/dist/converters/convert-shared.d.ts +10 -0
  63. package/dist/converters/convert-shared.js +19 -0
  64. package/dist/converters/index.d.ts +7 -0
  65. package/dist/converters/index.js +7 -0
  66. package/dist/converters/materialize-claims-first-resource.d.ts +16 -0
  67. package/dist/converters/materialize-claims-first-resource.js +65 -0
  68. package/dist/encounter-transfer-test-data.d.ts +40 -0
  69. package/dist/encounter-transfer-test-data.js +37 -0
  70. package/dist/fhir-bundle.d.ts +21 -0
  71. package/dist/fhir-bundle.js +74 -0
  72. package/dist/group-r5.d.ts +12 -0
  73. package/dist/group-r5.js +20 -0
  74. package/dist/healthcare-service-specialty-map.d.ts +32 -0
  75. package/dist/healthcare-service-specialty-map.js +151 -0
  76. package/dist/index.d.ts +3 -0
  77. package/dist/index.js +3 -0
  78. package/docs/CLINICAL_TYPED_ACCESSOR_BOUNDARY.md +44 -0
  79. package/docs/COMMUNICATION_BUNDLE_CONTRACT.md +61 -0
  80. package/docs/HEALTHCARE_SERVICE_DEPARTMENT_CATALOG.md +190 -0
  81. package/docs/UHC_FHIR_UTILS_MIGRATION.md +20 -1
  82. package/package.json +5 -1
@@ -18,6 +18,9 @@ export const LocationClaim = {
18
18
  PhysicalType: 'Location.physical-type',
19
19
  ManagingOrganization: 'Location.managing-organization',
20
20
  PartOf: 'Location.part-of',
21
+ PositionLongitude: 'Location.position-longitude',
22
+ PositionLatitude: 'Location.position-latitude',
23
+ PositionAltitude: 'Location.position-altitude',
21
24
  };
22
25
  export const LocationClaimSpecs = [
23
26
  { key: LocationClaim.Identifier, meaning: 'Business identifier.', example: 'room-201' },
@@ -31,4 +34,7 @@ export const LocationClaimSpecs = [
31
34
  { key: LocationClaim.PhysicalType, meaning: 'Physical type token.', example: 'http://terminology.hl7.org/CodeSystem/location-physical-type|ro' },
32
35
  { key: LocationClaim.ManagingOrganization, meaning: 'Managing organization reference.', example: 'Organization/dept-cardiology-001' },
33
36
  { key: LocationClaim.PartOf, meaning: 'Parent location reference.', example: 'Location/building-a' },
37
+ { key: LocationClaim.PositionLongitude, meaning: 'WGS84 longitude in decimal degrees.', example: '-123.1207' },
38
+ { key: LocationClaim.PositionLatitude, meaning: 'WGS84 latitude in decimal degrees.', example: '49.2827' },
39
+ { key: LocationClaim.PositionAltitude, meaning: 'Altitude in metres.', example: '12.5' },
34
40
  ];
@@ -2,13 +2,15 @@ import type { ClaimSpec } from './claim-types.js';
2
2
  /**
3
3
  * Flat claim keys for `Organization`.
4
4
  *
5
- * Use this resource for departments, services, clinics, or legal entities.
5
+ * Use this resource for legal entities, suborganizations and departments.
6
+ * A service offered by one of them is a separate `HealthcareService`.
6
7
  */
7
8
  export declare const OrganizationClaim: {
8
9
  readonly Identifier: "Organization.identifier";
9
10
  readonly Active: "Organization.active";
10
11
  readonly Type: "Organization.type";
11
12
  readonly Name: "Organization.name";
13
+ readonly Description: "Organization.description";
12
14
  readonly Alias: "Organization.alias";
13
15
  readonly PartOf: "Organization.part-of";
14
16
  readonly Telecom: "Organization.telecom";
@@ -3,13 +3,15 @@
3
3
  /**
4
4
  * Flat claim keys for `Organization`.
5
5
  *
6
- * Use this resource for departments, services, clinics, or legal entities.
6
+ * Use this resource for legal entities, suborganizations and departments.
7
+ * A service offered by one of them is a separate `HealthcareService`.
7
8
  */
8
9
  export const OrganizationClaim = {
9
10
  Identifier: 'Organization.identifier',
10
11
  Active: 'Organization.active',
11
12
  Type: 'Organization.type',
12
13
  Name: 'Organization.name',
14
+ Description: 'Organization.description',
13
15
  Alias: 'Organization.alias',
14
16
  PartOf: 'Organization.part-of',
15
17
  Telecom: 'Organization.telecom',
@@ -20,6 +22,7 @@ export const OrganizationClaimSpecs = [
20
22
  { key: OrganizationClaim.Active, meaning: 'Active flag.', example: 'true' },
21
23
  { key: OrganizationClaim.Type, meaning: 'Organization type token.', example: 'http://terminology.hl7.org/CodeSystem/organization-type|dept' },
22
24
  { key: OrganizationClaim.Name, meaning: 'Display name.', example: 'Cardiology Department' },
25
+ { key: OrganizationClaim.Description, meaning: 'Consumer-facing department description materialized in FHIR R5.', example: 'Specialist cardiovascular care.' },
23
26
  { key: OrganizationClaim.Alias, meaning: 'Alternate names as CSV.', example: 'Cardiology,Heart Clinic' },
24
27
  { key: OrganizationClaim.PartOf, meaning: 'Parent organization reference.', example: 'Organization/hospital-1' },
25
28
  { key: OrganizationClaim.Telecom, meaning: 'Contact values as CSV.', example: 'tel:+16045550101,mailto:cardiology@example.org' },
@@ -7,6 +7,7 @@ export declare const ProcedureClaim: {
7
7
  readonly CodeDisplay: "Procedure.code-display";
8
8
  readonly Date: "Procedure.date";
9
9
  readonly Encounter: "Procedure.encounter";
10
+ readonly FocalDevice: "Procedure.focal-device";
10
11
  readonly Identifier: "Procedure.identifier";
11
12
  readonly InstantiatesCanonical: "Procedure.instantiates-canonical";
12
13
  readonly InstantiatesUri: "Procedure.instantiates-uri";
@@ -16,6 +17,7 @@ export declare const ProcedureClaim: {
16
17
  readonly Performer: "Procedure.performer";
17
18
  readonly ReasonCode: "Procedure.reason-code";
18
19
  readonly ReasonReference: "Procedure.reason-reference";
20
+ readonly Report: "Procedure.report";
19
21
  readonly Status: "Procedure.status";
20
22
  readonly Subject: "Procedure.subject";
21
23
  readonly Note: "Procedure.note";
@@ -8,6 +8,7 @@ export const ProcedureClaim = {
8
8
  CodeDisplay: 'Procedure.code-display',
9
9
  Date: 'Procedure.date',
10
10
  Encounter: 'Procedure.encounter',
11
+ FocalDevice: 'Procedure.focal-device',
11
12
  Identifier: 'Procedure.identifier',
12
13
  InstantiatesCanonical: 'Procedure.instantiates-canonical',
13
14
  InstantiatesUri: 'Procedure.instantiates-uri',
@@ -17,6 +18,7 @@ export const ProcedureClaim = {
17
18
  Performer: 'Procedure.performer',
18
19
  ReasonCode: 'Procedure.reason-code',
19
20
  ReasonReference: 'Procedure.reason-reference',
21
+ Report: 'Procedure.report',
20
22
  Status: 'Procedure.status',
21
23
  Subject: 'Procedure.subject',
22
24
  Note: 'Procedure.note',
@@ -29,6 +31,7 @@ export const ProcedureClaimSpecs = [
29
31
  { key: ProcedureClaim.CodeDisplay, meaning: 'Canonical/international procedure display label.', example: 'Appendectomy' },
30
32
  { key: ProcedureClaim.Date, meaning: 'Performed date/time.', example: '2026-06-01T10:00:00Z' },
31
33
  { key: ProcedureClaim.Encounter, meaning: 'Encounter reference.', example: 'Encounter/enc-1' },
34
+ { key: ProcedureClaim.FocalDevice, meaning: 'Device manipulated, calibrated, installed or otherwise changed by the procedure.', example: 'Device/device-1' },
32
35
  { key: ProcedureClaim.Identifier, meaning: 'Business identifier.', example: 'procedure-001' },
33
36
  { key: ProcedureClaim.InstantiatesCanonical, meaning: 'Instantiated canonical plan/protocol.', example: 'http://example.org/PlanDefinition/appendectomy' },
34
37
  { key: ProcedureClaim.InstantiatesUri, meaning: 'Instantiated URI.', example: 'urn:procedure-protocol:appendectomy' },
@@ -38,6 +41,7 @@ export const ProcedureClaimSpecs = [
38
41
  { key: ProcedureClaim.Performer, meaning: 'Performer references (CSV).', example: 'Practitioner/prac-1' },
39
42
  { key: ProcedureClaim.ReasonCode, meaning: 'Reason code token.', example: 'http://snomed.info/sct|233604007' },
40
43
  { key: ProcedureClaim.ReasonReference, meaning: 'Reason reference.', example: 'Condition/cond-1' },
44
+ { key: ProcedureClaim.Report, meaning: 'Resulting report or evidence references.', example: 'DocumentReference/report-1' },
41
45
  { key: ProcedureClaim.Status, meaning: 'Procedure status.', example: 'completed' },
42
46
  { key: ProcedureClaim.Subject, meaning: 'Canonical subject reference.', example: 'did:web:patient.example.org' },
43
47
  { key: ProcedureClaim.Note, meaning: 'Clinical note text.', example: 'Procedure tolerated well.' },
@@ -0,0 +1,17 @@
1
+ import type { ClaimSpec } from './claim-types.js';
2
+ /** Canonical flat claims for the FHIR R5 RegulatedAuthorization resource. */
3
+ export declare const RegulatedAuthorizationClaim: {
4
+ readonly Identifier: "RegulatedAuthorization.identifier";
5
+ readonly Subject: "RegulatedAuthorization.subject";
6
+ readonly Type: "RegulatedAuthorization.type";
7
+ readonly Region: "RegulatedAuthorization.region";
8
+ readonly Status: "RegulatedAuthorization.status";
9
+ readonly StatusDate: "RegulatedAuthorization.status-date";
10
+ readonly ValidityStart: "RegulatedAuthorization.validity-start";
11
+ readonly ValidityEnd: "RegulatedAuthorization.validity-end";
12
+ readonly Basis: "RegulatedAuthorization.basis";
13
+ readonly Holder: "RegulatedAuthorization.holder";
14
+ readonly Regulator: "RegulatedAuthorization.regulator";
15
+ };
16
+ export type RegulatedAuthorizationClaimKey = typeof RegulatedAuthorizationClaim[keyof typeof RegulatedAuthorizationClaim];
17
+ export declare const RegulatedAuthorizationClaimSpecs: readonly ClaimSpec[];
@@ -0,0 +1,27 @@
1
+ /** Canonical flat claims for the FHIR R5 RegulatedAuthorization resource. */
2
+ export const RegulatedAuthorizationClaim = {
3
+ Identifier: 'RegulatedAuthorization.identifier',
4
+ Subject: 'RegulatedAuthorization.subject',
5
+ Type: 'RegulatedAuthorization.type',
6
+ Region: 'RegulatedAuthorization.region',
7
+ Status: 'RegulatedAuthorization.status',
8
+ StatusDate: 'RegulatedAuthorization.status-date',
9
+ ValidityStart: 'RegulatedAuthorization.validity-start',
10
+ ValidityEnd: 'RegulatedAuthorization.validity-end',
11
+ Basis: 'RegulatedAuthorization.basis',
12
+ Holder: 'RegulatedAuthorization.holder',
13
+ Regulator: 'RegulatedAuthorization.regulator',
14
+ };
15
+ export const RegulatedAuthorizationClaimSpecs = Object.freeze([
16
+ { key: RegulatedAuthorizationClaim.Identifier, meaning: 'Identifier assigned by the authorizing body.', example: 'authorization-1' },
17
+ { key: RegulatedAuthorizationClaim.Subject, meaning: 'Authorized product type, facility or activity reference.', example: 'Location/location-1' },
18
+ { key: RegulatedAuthorizationClaim.Type, meaning: 'Authorization type coding token.', example: 'https://example.invalid/codes|operation' },
19
+ { key: RegulatedAuthorizationClaim.Region, meaning: 'Jurisdiction coding token.', example: 'urn:iso:std:iso:3166|CA' },
20
+ { key: RegulatedAuthorizationClaim.Status, meaning: 'Authorization publication status.', example: 'active' },
21
+ { key: RegulatedAuthorizationClaim.StatusDate, meaning: 'Date the status was assigned.', example: '2026-09-29T16:00:00Z' },
22
+ { key: RegulatedAuthorizationClaim.ValidityStart, meaning: 'Authorization validity start.', example: '2026-09-29' },
23
+ { key: RegulatedAuthorizationClaim.ValidityEnd, meaning: 'Authorization validity end.', example: '2027-09-29' },
24
+ { key: RegulatedAuthorizationClaim.Basis, meaning: 'Regulatory basis coding token.', example: 'https://example.invalid/codes|installed-device' },
25
+ { key: RegulatedAuthorizationClaim.Holder, meaning: 'Organization granted the authorization.', example: 'Organization/holder-1' },
26
+ { key: RegulatedAuthorizationClaim.Regulator, meaning: 'Regulatory authority granting the authorization.', example: 'Organization/regulator-1' },
27
+ ]);
@@ -0,0 +1,45 @@
1
+ import type { ClaimSpec } from './claim-types.js';
2
+ /** Canonical flat claims for the official FHIR R5 Schedule search surface. */
3
+ export declare const ScheduleClaim: Readonly<{
4
+ readonly Active: "Schedule.active";
5
+ readonly Actor: "Schedule.actor";
6
+ readonly Date: "Schedule.date";
7
+ readonly Identifier: "Schedule.identifier";
8
+ readonly Name: "Schedule.name";
9
+ readonly ServiceCategory: "Schedule.service-category";
10
+ readonly ServiceType: "Schedule.service-type";
11
+ readonly ServiceTypeReference: "Schedule.service-type-reference";
12
+ readonly Specialty: "Schedule.specialty";
13
+ readonly PlanningHorizonStart: "Schedule.planning-horizon-start";
14
+ readonly PlanningHorizonEnd: "Schedule.planning-horizon-end";
15
+ readonly Comment: "Schedule.comment";
16
+ }>;
17
+ /** Canonical flat claims for the official FHIR R5 Slot search surface. */
18
+ export declare const SlotClaim: Readonly<{
19
+ readonly AppointmentType: "Slot.appointment-type";
20
+ readonly Identifier: "Slot.identifier";
21
+ readonly Schedule: "Slot.schedule";
22
+ readonly ServiceCategory: "Slot.service-category";
23
+ readonly ServiceType: "Slot.service-type";
24
+ readonly ServiceTypeReference: "Slot.service-type-reference";
25
+ readonly Specialty: "Slot.specialty";
26
+ readonly Start: "Slot.start";
27
+ readonly Status: "Slot.status";
28
+ readonly End: "Slot.end";
29
+ readonly Overbooked: "Slot.overbooked";
30
+ readonly Comment: "Slot.comment";
31
+ }>;
32
+ export declare const ScheduleR5SearchParameterCatalog: readonly Readonly<{
33
+ claim: `${string}.${string}`;
34
+ resourceType: string;
35
+ elementPath: string;
36
+ type: import("../search-parameters.js").FlatSearchParameterType;
37
+ }>[];
38
+ export declare const SlotR5SearchParameterCatalog: readonly Readonly<{
39
+ claim: `${string}.${string}`;
40
+ resourceType: string;
41
+ elementPath: string;
42
+ type: import("../search-parameters.js").FlatSearchParameterType;
43
+ }>[];
44
+ export declare const ScheduleClaimSpecs: readonly ClaimSpec[];
45
+ export declare const SlotClaimSpecs: readonly ClaimSpec[];
@@ -0,0 +1,70 @@
1
+ // Copyright 2026 Conéctate Soluciones y Aplicaciones SL under the Apache License, Version 2.0.
2
+ import { defineFlatSearchParameter } from '../search-parameters.js';
3
+ /** Canonical flat claims for the official FHIR R5 Schedule search surface. */
4
+ export const ScheduleClaim = Object.freeze({
5
+ Active: 'Schedule.active',
6
+ Actor: 'Schedule.actor',
7
+ Date: 'Schedule.date',
8
+ Identifier: 'Schedule.identifier',
9
+ Name: 'Schedule.name',
10
+ ServiceCategory: 'Schedule.service-category',
11
+ ServiceType: 'Schedule.service-type',
12
+ ServiceTypeReference: 'Schedule.service-type-reference',
13
+ Specialty: 'Schedule.specialty',
14
+ PlanningHorizonStart: 'Schedule.planning-horizon-start',
15
+ PlanningHorizonEnd: 'Schedule.planning-horizon-end',
16
+ Comment: 'Schedule.comment',
17
+ });
18
+ /** Canonical flat claims for the official FHIR R5 Slot search surface. */
19
+ export const SlotClaim = Object.freeze({
20
+ AppointmentType: 'Slot.appointment-type',
21
+ Identifier: 'Slot.identifier',
22
+ Schedule: 'Slot.schedule',
23
+ ServiceCategory: 'Slot.service-category',
24
+ ServiceType: 'Slot.service-type',
25
+ ServiceTypeReference: 'Slot.service-type-reference',
26
+ Specialty: 'Slot.specialty',
27
+ Start: 'Slot.start',
28
+ Status: 'Slot.status',
29
+ End: 'Slot.end',
30
+ Overbooked: 'Slot.overbooked',
31
+ Comment: 'Slot.comment',
32
+ });
33
+ export const ScheduleR5SearchParameterCatalog = Object.freeze([
34
+ defineFlatSearchParameter({ claim: ScheduleClaim.Active, resourceType: 'Schedule', elementPath: 'Schedule.active', type: 'token' }),
35
+ defineFlatSearchParameter({ claim: ScheduleClaim.Actor, resourceType: 'Schedule', elementPath: 'Schedule.actor', type: 'reference' }),
36
+ defineFlatSearchParameter({ claim: ScheduleClaim.Date, resourceType: 'Schedule', elementPath: 'Schedule.planningHorizon', type: 'date' }),
37
+ defineFlatSearchParameter({ claim: ScheduleClaim.Identifier, resourceType: 'Schedule', elementPath: 'Schedule.identifier', type: 'token' }),
38
+ defineFlatSearchParameter({ claim: ScheduleClaim.Name, resourceType: 'Schedule', elementPath: 'Schedule.name', type: 'string' }),
39
+ defineFlatSearchParameter({ claim: ScheduleClaim.ServiceCategory, resourceType: 'Schedule', elementPath: 'Schedule.serviceCategory', type: 'token' }),
40
+ defineFlatSearchParameter({ claim: ScheduleClaim.ServiceType, resourceType: 'Schedule', elementPath: 'Schedule.serviceType.concept', type: 'token' }),
41
+ defineFlatSearchParameter({ claim: ScheduleClaim.ServiceTypeReference, resourceType: 'Schedule', elementPath: 'Schedule.serviceType.reference', type: 'reference' }),
42
+ defineFlatSearchParameter({ claim: ScheduleClaim.Specialty, resourceType: 'Schedule', elementPath: 'Schedule.specialty', type: 'token' }),
43
+ ]);
44
+ export const SlotR5SearchParameterCatalog = Object.freeze([
45
+ defineFlatSearchParameter({ claim: SlotClaim.AppointmentType, resourceType: 'Slot', elementPath: 'Slot.appointmentType', type: 'token' }),
46
+ defineFlatSearchParameter({ claim: SlotClaim.Identifier, resourceType: 'Slot', elementPath: 'Slot.identifier', type: 'token' }),
47
+ defineFlatSearchParameter({ claim: SlotClaim.Schedule, resourceType: 'Slot', elementPath: 'Slot.schedule', type: 'reference' }),
48
+ defineFlatSearchParameter({ claim: SlotClaim.ServiceCategory, resourceType: 'Slot', elementPath: 'Slot.serviceCategory', type: 'token' }),
49
+ defineFlatSearchParameter({ claim: SlotClaim.ServiceType, resourceType: 'Slot', elementPath: 'Slot.serviceType.concept', type: 'token' }),
50
+ defineFlatSearchParameter({ claim: SlotClaim.ServiceTypeReference, resourceType: 'Slot', elementPath: 'Slot.serviceType.reference', type: 'reference' }),
51
+ defineFlatSearchParameter({ claim: SlotClaim.Specialty, resourceType: 'Slot', elementPath: 'Slot.specialty', type: 'token' }),
52
+ defineFlatSearchParameter({ claim: SlotClaim.Start, resourceType: 'Slot', elementPath: 'Slot.start', type: 'date' }),
53
+ defineFlatSearchParameter({ claim: SlotClaim.Status, resourceType: 'Slot', elementPath: 'Slot.status', type: 'token' }),
54
+ ]);
55
+ export const ScheduleClaimSpecs = Object.freeze([
56
+ { key: ScheduleClaim.Identifier, meaning: 'Logical schedule identifier.', example: 'urn:uuid:blood-donation-weekday' },
57
+ { key: ScheduleClaim.Active, meaning: 'Whether this schedule is in active use.', example: 'true' },
58
+ { key: ScheduleClaim.Actor, meaning: 'Repeatable independently schedulable actors as CSV references.', example: 'HealthcareService/blood-donation,Location/blood-donation-room' },
59
+ { key: ScheduleClaim.ServiceType, meaning: 'Repeatable service-type concept tokens as CSV.', example: 'http://terminology.hl7.org/CodeSystem/service-type|117' },
60
+ { key: ScheduleClaim.ServiceTypeReference, meaning: 'Repeatable HealthcareService references corresponding to service-type concepts.', example: 'HealthcareService/blood-donation' },
61
+ { key: ScheduleClaim.PlanningHorizonStart, meaning: 'Start of the period covered by this schedule.', example: '2026-10-01' },
62
+ { key: ScheduleClaim.PlanningHorizonEnd, meaning: 'End of the period covered by this schedule.', example: '2026-10-31' },
63
+ ]);
64
+ export const SlotClaimSpecs = Object.freeze([
65
+ { key: SlotClaim.Identifier, meaning: 'Logical slot identifier.', example: 'urn:uuid:blood-20261001-0900' },
66
+ { key: SlotClaim.Schedule, meaning: 'The Schedule that owns this independent slot.', example: 'Schedule/blood-donation-weekday' },
67
+ { key: SlotClaim.Status, meaning: 'FHIR Slot status.', example: 'free' },
68
+ { key: SlotClaim.Start, meaning: 'Start instant.', example: '2026-10-01T09:00:00Z' },
69
+ { key: SlotClaim.End, meaning: 'End instant; duration is derived from start and end.', example: '2026-10-01T09:15:00Z' },
70
+ ]);
@@ -25,6 +25,7 @@ export declare const ResourceTypesFhirR4: Readonly<{
25
25
  readonly Encounter: "Encounter";
26
26
  readonly Flag: "Flag";
27
27
  readonly Group: "Group";
28
+ readonly HealthcareService: "HealthcareService";
28
29
  readonly ImagingStudy: "ImagingStudy";
29
30
  readonly Immunization: "Immunization";
30
31
  readonly ImmunizationRecommendation: "ImmunizationRecommendation";
@@ -47,7 +48,9 @@ export declare const ResourceTypesFhirR4: Readonly<{
47
48
  readonly RelatedPerson: "RelatedPerson";
48
49
  readonly ResearchStudy: "ResearchStudy";
49
50
  readonly ResearchSubject: "ResearchSubject";
51
+ readonly Schedule: "Schedule";
50
52
  readonly Specimen: "Specimen";
53
+ readonly Slot: "Slot";
51
54
  readonly ServiceRequest: "ServiceRequest";
52
55
  readonly Task: "Task";
53
56
  readonly DetectedIssue: "DetectedIssue";
@@ -81,6 +84,7 @@ export declare const FhirResourceTypes: Readonly<{
81
84
  readonly Encounter: "Encounter";
82
85
  readonly Flag: "Flag";
83
86
  readonly Group: "Group";
87
+ readonly HealthcareService: "HealthcareService";
84
88
  readonly ImagingStudy: "ImagingStudy";
85
89
  readonly Immunization: "Immunization";
86
90
  readonly ImmunizationRecommendation: "ImmunizationRecommendation";
@@ -103,13 +107,16 @@ export declare const FhirResourceTypes: Readonly<{
103
107
  readonly RelatedPerson: "RelatedPerson";
104
108
  readonly ResearchStudy: "ResearchStudy";
105
109
  readonly ResearchSubject: "ResearchSubject";
110
+ readonly Schedule: "Schedule";
106
111
  readonly Specimen: "Specimen";
112
+ readonly Slot: "Slot";
107
113
  readonly ServiceRequest: "ServiceRequest";
108
114
  readonly Task: "Task";
109
115
  readonly DetectedIssue: "DetectedIssue";
110
116
  }>;
111
117
  /** FHIR R5-only resources currently emitted by shared subscription contracts. */
112
118
  export declare const ResourceTypesFhirR5: Readonly<{
119
+ readonly EncounterHistory: "EncounterHistory";
113
120
  readonly Subscription: "Subscription";
114
121
  readonly SubscriptionTopic: "SubscriptionTopic";
115
122
  readonly SubscriptionStatus: "SubscriptionStatus";
@@ -133,6 +140,7 @@ export declare const ResourceTypesFhirR5: Readonly<{
133
140
  readonly Encounter: "Encounter";
134
141
  readonly Flag: "Flag";
135
142
  readonly Group: "Group";
143
+ readonly HealthcareService: "HealthcareService";
136
144
  readonly ImagingStudy: "ImagingStudy";
137
145
  readonly Immunization: "Immunization";
138
146
  readonly ImmunizationRecommendation: "ImmunizationRecommendation";
@@ -155,7 +163,9 @@ export declare const ResourceTypesFhirR5: Readonly<{
155
163
  readonly RelatedPerson: "RelatedPerson";
156
164
  readonly ResearchStudy: "ResearchStudy";
157
165
  readonly ResearchSubject: "ResearchSubject";
166
+ readonly Schedule: "Schedule";
158
167
  readonly Specimen: "Specimen";
168
+ readonly Slot: "Slot";
159
169
  readonly ServiceRequest: "ServiceRequest";
160
170
  readonly Task: "Task";
161
171
  readonly DetectedIssue: "DetectedIssue";
@@ -25,6 +25,7 @@ export const ResourceTypesFhirR4 = Object.freeze({
25
25
  Encounter: 'Encounter',
26
26
  Flag: 'Flag',
27
27
  Group: 'Group',
28
+ HealthcareService: 'HealthcareService',
28
29
  ImagingStudy: 'ImagingStudy',
29
30
  Immunization: 'Immunization',
30
31
  ImmunizationRecommendation: 'ImmunizationRecommendation',
@@ -47,7 +48,9 @@ export const ResourceTypesFhirR4 = Object.freeze({
47
48
  RelatedPerson: 'RelatedPerson',
48
49
  ResearchStudy: 'ResearchStudy',
49
50
  ResearchSubject: 'ResearchSubject',
51
+ Schedule: 'Schedule',
50
52
  Specimen: 'Specimen',
53
+ Slot: 'Slot',
51
54
  ServiceRequest: 'ServiceRequest',
52
55
  Task: 'Task',
53
56
  DetectedIssue: 'DetectedIssue',
@@ -62,6 +65,7 @@ export const FhirResourceTypes = ResourceTypesFhirR4;
62
65
  /** FHIR R5-only resources currently emitted by shared subscription contracts. */
63
66
  export const ResourceTypesFhirR5 = Object.freeze({
64
67
  ...ResourceTypesFhirR4,
68
+ EncounterHistory: 'EncounterHistory',
65
69
  Subscription: 'Subscription',
66
70
  SubscriptionTopic: 'SubscriptionTopic',
67
71
  SubscriptionStatus: 'SubscriptionStatus',
@@ -0,0 +1,14 @@
1
+ import { type FlatClaimResourceEntry } from '../flat-claim-resource-graph.js';
2
+ export type SupportedAppointmentFhirRelease = 'r4' | 'r5';
3
+ export type AppointmentCommunicationFlatGraph = Readonly<{
4
+ communications: readonly FlatClaimResourceEntry[];
5
+ appointments: readonly FlatClaimResourceEntry[];
6
+ documentReferences: readonly FlatClaimResourceEntry[];
7
+ entries: readonly FlatClaimResourceEntry[];
8
+ }>;
9
+ /**
10
+ * Projects a validated appointment exchange into independently persisted flat
11
+ * claim resources. Transport parsing is delegated to the shared Bundle Reader;
12
+ * native FHIR remains an adapter input and is never persisted beside claims.
13
+ */
14
+ export declare function projectAppointmentCommunicationBatchToFlatGraph(input: unknown, release: SupportedAppointmentFhirRelease): AppointmentCommunicationFlatGraph;
@@ -0,0 +1,97 @@
1
+ import { AppointmentClaim } from '../claims/appointment-claims.js';
2
+ import { CommunicationClaim } from '../claims/communication-claims.js';
3
+ import { DocumentReferenceClaim } from '../claims/document-reference-claims.js';
4
+ import { readBundleResources, readCommunicationBundlePayloads } from '../fhir-bundle.js';
5
+ import { buildFlatClaimResourceEntry } from '../flat-claim-resource-graph.js';
6
+ import { appointmentFhirR4ToFlat } from './convert-appointment.js';
7
+ import { documentReferenceFhirR4ToFlat } from './convert-document-reference.js';
8
+ /**
9
+ * Projects a validated appointment exchange into independently persisted flat
10
+ * claim resources. Transport parsing is delegated to the shared Bundle Reader;
11
+ * native FHIR remains an adapter input and is never persisted beside claims.
12
+ */
13
+ export function projectAppointmentCommunicationBatchToFlatGraph(input, release) {
14
+ if (release !== 'r4' && release !== 'r5')
15
+ throw new TypeError('fhir_release_unsupported');
16
+ const communications = [];
17
+ const appointments = [];
18
+ const documentReferences = [];
19
+ for (const { communication, attachment, bundle } of readCommunicationBundlePayloads(input)) {
20
+ const communicationId = resourceId(communication, 'communication_identifier_required');
21
+ communications.push(buildFlatClaimResourceEntry({
22
+ entryId: communicationId,
23
+ resourceType: 'Communication',
24
+ claims: compactClaims({
25
+ [CommunicationClaim.Identifier]: communicationId,
26
+ [CommunicationClaim.Status]: stringValue(communication.status),
27
+ [CommunicationClaim.Subject]: referenceValue(communication.subject),
28
+ [CommunicationClaim.Recipient]: referenceList(communication.recipient),
29
+ [CommunicationClaim.Sender]: referenceValue(communication.sender),
30
+ [CommunicationClaim.Sent]: stringValue(communication.sent),
31
+ [CommunicationClaim.ContentAttachmentType]: attachment.contentType,
32
+ [CommunicationClaim.ContentAttachmentData]: attachment.data,
33
+ [CommunicationClaim.ContentAttachmentTitle]: attachment.title,
34
+ }),
35
+ }));
36
+ for (const child of readBundleResources(bundle)) {
37
+ if (child.resourceType === 'Appointment') {
38
+ const entryId = resourceId(child, 'appointment_identifier_required');
39
+ const structural = appointmentFhirR4ToFlat(child);
40
+ appointments.push(buildFlatClaimResourceEntry({
41
+ entryId,
42
+ resourceType: 'Appointment',
43
+ claims: compactClaims({
44
+ ...structural,
45
+ [AppointmentClaim.Identifier]: structural[AppointmentClaim.Identifier] || entryId,
46
+ }),
47
+ }));
48
+ }
49
+ else if (child.resourceType === 'DocumentReference') {
50
+ const entryId = resourceId(child, 'document_reference_identifier_required');
51
+ const structural = documentReferenceFhirR4ToFlat(child);
52
+ documentReferences.push(buildFlatClaimResourceEntry({
53
+ entryId,
54
+ resourceType: 'DocumentReference',
55
+ claims: compactClaims({
56
+ ...structural,
57
+ [DocumentReferenceClaim.Identifier]: structural[DocumentReferenceClaim.Identifier] || entryId,
58
+ }),
59
+ }));
60
+ }
61
+ }
62
+ }
63
+ return Object.freeze({
64
+ communications: Object.freeze(communications),
65
+ appointments: Object.freeze(appointments),
66
+ documentReferences: Object.freeze(documentReferences),
67
+ entries: Object.freeze([...communications, ...appointments, ...documentReferences]),
68
+ });
69
+ }
70
+ function resourceId(resource, error) {
71
+ const identifier = Array.isArray(resource.identifier)
72
+ ? resource.identifier.find(item => typeof item?.value === 'string')?.value
73
+ : undefined;
74
+ const value = String(resource.id || identifier || '').trim();
75
+ if (!value)
76
+ throw new TypeError(error);
77
+ return value;
78
+ }
79
+ function compactClaims(input) {
80
+ return Object.freeze(Object.fromEntries(Object.entries(input)
81
+ .filter((entry) => entry[1] !== undefined && entry[1] !== null && String(entry[1]).trim() !== '')
82
+ .map(([name, value]) => [name, String(value).trim()])));
83
+ }
84
+ function stringValue(value) {
85
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
86
+ }
87
+ function referenceValue(value) {
88
+ if (!value || typeof value !== 'object' || Array.isArray(value))
89
+ return undefined;
90
+ return stringValue(value.reference);
91
+ }
92
+ function referenceList(value) {
93
+ if (!Array.isArray(value))
94
+ return undefined;
95
+ const references = value.map(referenceValue).filter((item) => Boolean(item));
96
+ return references.length ? [...new Set(references)].join(',') : undefined;
97
+ }
@@ -21,6 +21,8 @@ export function appointmentFlatToFhirR4(claims) {
21
21
  note: claims[AppointmentClaim.NoteText] ? [{ text: claims[AppointmentClaim.NoteText] }] : undefined,
22
22
  patientInstruction: claims[AppointmentClaim.PatientInstruction],
23
23
  basedOn: claims[AppointmentClaim.BasedOn] ? claims[AppointmentClaim.BasedOn].split(',').map((reference) => ({ reference: reference.trim() })) : undefined,
24
+ slot: claims[AppointmentClaim.Slot] ? claims[AppointmentClaim.Slot].split(',').map((reference) => ({ reference: reference.trim() })) : undefined,
25
+ supportingInformation: claims[AppointmentClaim.SupportingInfo] ? claims[AppointmentClaim.SupportingInfo].split(',').map((reference) => ({ reference: reference.trim() })) : undefined,
24
26
  participant: claims[AppointmentClaim.ParticipantActor]
25
27
  ? claims[AppointmentClaim.ParticipantActor].split(',').map((reference) => ({
26
28
  actor: { reference: reference.trim() },
@@ -32,11 +34,17 @@ export function appointmentFlatToFhirR4(claims) {
32
34
  }
33
35
  export function appointmentFhirR4ToFlat(resource) {
34
36
  const participant = Array.isArray(resource.participant) ? resource.participant[0] : undefined;
37
+ const actorReferences = Array.isArray(resource.participant)
38
+ ? resource.participant
39
+ .map((item) => referenceToValue(item?.actor))
40
+ .filter((item) => Boolean(item))
41
+ : [];
42
+ const serviceType = resource.serviceType?.[0];
35
43
  return {
36
44
  [AppointmentClaim.Identifier]: resource.identifier?.[0]?.value,
37
45
  [AppointmentClaim.Status]: resource.status,
38
46
  [AppointmentClaim.ServiceCategory]: codingToValue(resource.serviceCategory?.[0]?.coding?.[0]),
39
- [AppointmentClaim.ServiceType]: codingToValue(resource.serviceType?.[0]?.coding?.[0]),
47
+ [AppointmentClaim.ServiceType]: codingToValue(serviceType?.concept?.coding?.[0] ?? serviceType?.coding?.[0]),
40
48
  [AppointmentClaim.Specialty]: codingToValue(resource.specialty?.[0]?.coding?.[0]),
41
49
  [AppointmentClaim.AppointmentType]: codingToValue(resource.appointmentType?.coding?.[0]),
42
50
  [AppointmentClaim.ReasonCode]: codingToValue(resource.reasonCode?.[0]?.coding?.[0]),
@@ -49,13 +57,14 @@ export function appointmentFhirR4ToFlat(resource) {
49
57
  [AppointmentClaim.NoteText]: resource.note?.[0]?.text,
50
58
  [AppointmentClaim.PatientInstruction]: resource.patientInstruction,
51
59
  [AppointmentClaim.BasedOn]: referenceListToCsv(resource.basedOn),
52
- [AppointmentClaim.ParticipantActor]: Array.isArray(resource.participant)
53
- ? resource.participant
54
- .map((item) => referenceToValue(item?.actor))
55
- .filter((item) => Boolean(item))
56
- .join(',')
57
- : undefined,
60
+ [AppointmentClaim.ParticipantActor]: actorReferences.length ? actorReferences.join(',') : undefined,
58
61
  [AppointmentClaim.ParticipantStatus]: participant?.status,
59
62
  [AppointmentClaim.ParticipantType]: codingToValue(participant?.type?.[0]?.coding?.[0]),
63
+ [AppointmentClaim.Date]: resource.start,
64
+ [AppointmentClaim.Location]: actorReferences.filter(reference => reference.startsWith('Location/')).join(',') || undefined,
65
+ [AppointmentClaim.Patient]: actorReferences.filter(reference => reference.startsWith('Patient/')).join(',') || undefined,
66
+ [AppointmentClaim.Practitioner]: actorReferences.filter(reference => reference.startsWith('Practitioner/') || reference.startsWith('PractitionerRole/')).join(',') || undefined,
67
+ [AppointmentClaim.Slot]: referenceListToCsv(resource.slot),
68
+ [AppointmentClaim.SupportingInfo]: referenceListToCsv(resource.supportingInformation),
60
69
  };
61
70
  }
@@ -0,0 +1,3 @@
1
+ import type { FhirResource, FlatClaims } from './convert-shared.js';
2
+ export declare function deviceMetricFlatToFhirR5(claims: FlatClaims): FhirResource;
3
+ export declare function deviceMetricFhirR5ToFlat(resource: FhirResource): FlatClaims;
@@ -0,0 +1,37 @@
1
+ import { DeviceMetricClaim } from '../claims/device-metric-claims.js';
2
+ import { codingFromValue, codingToValue, referenceToValue } from './convert-shared.js';
3
+ export function deviceMetricFlatToFhirR5(claims) {
4
+ const calibration = claims[DeviceMetricClaim.CalibrationType]
5
+ || claims[DeviceMetricClaim.CalibrationState]
6
+ || claims[DeviceMetricClaim.CalibrationTime]
7
+ ? [{
8
+ type: claims[DeviceMetricClaim.CalibrationType],
9
+ state: claims[DeviceMetricClaim.CalibrationState],
10
+ time: claims[DeviceMetricClaim.CalibrationTime],
11
+ }]
12
+ : undefined;
13
+ return {
14
+ resourceType: 'DeviceMetric',
15
+ identifier: claims[DeviceMetricClaim.Identifier] ? [{ value: claims[DeviceMetricClaim.Identifier] }] : undefined,
16
+ type: { coding: codingFromValue(claims[DeviceMetricClaim.Type]) },
17
+ unit: claims[DeviceMetricClaim.Unit] ? { coding: codingFromValue(claims[DeviceMetricClaim.Unit]) } : undefined,
18
+ device: claims[DeviceMetricClaim.Device] ? { reference: claims[DeviceMetricClaim.Device] } : undefined,
19
+ operationalStatus: claims[DeviceMetricClaim.OperationalStatus],
20
+ category: claims[DeviceMetricClaim.Category],
21
+ calibration,
22
+ };
23
+ }
24
+ export function deviceMetricFhirR5ToFlat(resource) {
25
+ const calibration = resource.calibration?.[0];
26
+ return {
27
+ [DeviceMetricClaim.Identifier]: resource.identifier?.[0]?.value,
28
+ [DeviceMetricClaim.Type]: codingToValue(resource.type?.coding?.[0]),
29
+ [DeviceMetricClaim.Unit]: codingToValue(resource.unit?.coding?.[0]),
30
+ [DeviceMetricClaim.Device]: referenceToValue(resource.device),
31
+ [DeviceMetricClaim.OperationalStatus]: resource.operationalStatus,
32
+ [DeviceMetricClaim.Category]: resource.category,
33
+ [DeviceMetricClaim.CalibrationType]: calibration?.type,
34
+ [DeviceMetricClaim.CalibrationState]: calibration?.state,
35
+ [DeviceMetricClaim.CalibrationTime]: calibration?.time,
36
+ };
37
+ }
@@ -25,6 +25,9 @@ export function documentReferenceFlatToFhirR4(claims) {
25
25
  }
26
26
  : undefined,
27
27
  date: claims[DocumentReferenceClaim.Date],
28
+ context: claims[DocumentReferenceClaim.EventReference]
29
+ ? { related: claims[DocumentReferenceClaim.EventReference].split(',').map((reference) => ({ reference: reference.trim() })) }
30
+ : undefined,
28
31
  content: [{ attachment: {
29
32
  contentType: claims[DocumentReferenceClaim.ContentType],
30
33
  data: claims[DocumentReferenceClaim.ContentData],
@@ -45,6 +48,8 @@ export function documentReferenceFhirR4ToFlat(resource) {
45
48
  [DocumentReferenceClaim.TypeText]: resource.type?.text,
46
49
  [DocumentReferenceClaim.TypeDisplay]: resource.type?.coding?.[0]?.display,
47
50
  [DocumentReferenceClaim.Date]: resource.date,
51
+ [DocumentReferenceClaim.EventReference]: resource.context
52
+ ?.related?.map((related) => related.reference).filter((reference) => Boolean(reference)).join(',') || undefined,
48
53
  [DocumentReferenceClaim.ContentType]: attachment?.contentType,
49
54
  [DocumentReferenceClaim.ContentData]: attachment?.data,
50
55
  [DocumentReferenceClaim.Location]: attachment?.url,
@@ -0,0 +1,5 @@
1
+ import type { FhirResource, FlatClaims } from './convert-shared.js';
2
+ /** Materializes canonical EncounterHistory claims as native FHIR R5. */
3
+ export declare function encounterHistoryFlatToFhirR5(claims: FlatClaims): FhirResource;
4
+ /** Extracts supported native FHIR R5 EncounterHistory fields into flat claims. */
5
+ export declare function encounterHistoryFhirR5ToFlat(resource: FhirResource): FlatClaims;