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.
- package/.codex/skills/govern-fhir-data-utilities/SKILL.md +35 -0
- package/CHANGELOG.md +61 -0
- package/README.md +35 -0
- package/dist/appointment-communication-test-data.d.ts +63 -0
- package/dist/appointment-communication-test-data.js +77 -0
- package/dist/builders/department-service-graph.d.ts +32 -0
- package/dist/builders/department-service-graph.js +102 -0
- package/dist/builders/device-compliance-graph.d.ts +51 -0
- package/dist/builders/device-compliance-graph.js +115 -0
- package/dist/builders/index.d.ts +3 -0
- package/dist/builders/index.js +3 -0
- package/dist/builders/service-schedule-graph.d.ts +58 -0
- package/dist/builders/service-schedule-graph.js +149 -0
- package/dist/care-emergency-alert.d.ts +18 -0
- package/dist/care-emergency-alert.js +29 -1
- package/dist/claims/appointment-claims.d.ts +6 -0
- package/dist/claims/appointment-claims.js +6 -0
- package/dist/claims/device-metric-claims.d.ts +16 -0
- package/dist/claims/device-metric-claims.js +25 -0
- package/dist/claims/encounter-claims.d.ts +15 -0
- package/dist/claims/encounter-claims.js +19 -0
- package/dist/claims/encounter-history-claims.d.ts +20 -0
- package/dist/claims/encounter-history-claims.js +34 -0
- package/dist/claims/healthcare-service-claims.d.ts +32 -0
- package/dist/claims/healthcare-service-claims.js +54 -0
- package/dist/claims/index.d.ts +5 -0
- package/dist/claims/index.js +5 -0
- package/dist/claims/location-claims.d.ts +3 -0
- package/dist/claims/location-claims.js +6 -0
- package/dist/claims/organization-claims.d.ts +3 -1
- package/dist/claims/organization-claims.js +4 -1
- package/dist/claims/procedure-claims.d.ts +2 -0
- package/dist/claims/procedure-claims.js +4 -0
- package/dist/claims/regulated-authorization-claims.d.ts +17 -0
- package/dist/claims/regulated-authorization-claims.js +27 -0
- package/dist/claims/schedule-slot-claims.d.ts +45 -0
- package/dist/claims/schedule-slot-claims.js +70 -0
- package/dist/constants/fhir-resource-types.d.ts +10 -0
- package/dist/constants/fhir-resource-types.js +4 -0
- package/dist/converters/convert-appointment-communication.d.ts +14 -0
- package/dist/converters/convert-appointment-communication.js +97 -0
- package/dist/converters/convert-appointment.js +16 -7
- package/dist/converters/convert-device-metric.d.ts +3 -0
- package/dist/converters/convert-device-metric.js +37 -0
- package/dist/converters/convert-document-reference.js +5 -0
- package/dist/converters/convert-encounter-history.d.ts +5 -0
- package/dist/converters/convert-encounter-history.js +83 -0
- package/dist/converters/convert-encounter.d.ts +4 -0
- package/dist/converters/convert-encounter.js +73 -1
- package/dist/converters/convert-healthcare-service.d.ts +7 -0
- package/dist/converters/convert-healthcare-service.js +60 -0
- package/dist/converters/convert-location.d.ts +4 -0
- package/dist/converters/convert-location.js +41 -3
- package/dist/converters/convert-organization.d.ts +2 -0
- package/dist/converters/convert-organization.js +20 -3
- package/dist/converters/convert-procedure.d.ts +2 -0
- package/dist/converters/convert-procedure.js +21 -0
- package/dist/converters/convert-regulated-authorization.d.ts +3 -0
- package/dist/converters/convert-regulated-authorization.js +34 -0
- package/dist/converters/convert-schedule-slot.d.ts +9 -0
- package/dist/converters/convert-schedule-slot.js +96 -0
- package/dist/converters/convert-shared.d.ts +10 -0
- package/dist/converters/convert-shared.js +19 -0
- package/dist/converters/index.d.ts +7 -0
- package/dist/converters/index.js +7 -0
- package/dist/converters/materialize-claims-first-resource.d.ts +16 -0
- package/dist/converters/materialize-claims-first-resource.js +65 -0
- package/dist/encounter-transfer-test-data.d.ts +40 -0
- package/dist/encounter-transfer-test-data.js +37 -0
- package/dist/fhir-bundle.d.ts +21 -0
- package/dist/fhir-bundle.js +74 -0
- package/dist/group-r5.d.ts +12 -0
- package/dist/group-r5.js +20 -0
- package/dist/healthcare-service-specialty-map.d.ts +32 -0
- package/dist/healthcare-service-specialty-map.js +151 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/docs/CLINICAL_TYPED_ACCESSOR_BOUNDARY.md +44 -0
- package/docs/COMMUNICATION_BUNDLE_CONTRACT.md +61 -0
- package/docs/HEALTHCARE_SERVICE_DEPARTMENT_CATALOG.md +190 -0
- package/docs/UHC_FHIR_UTILS_MIGRATION.md +20 -1
- package/package.json +5 -1
package/dist/converters/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export * from './convert-shared.js';
|
|
|
2
2
|
export * from './convert-allergy-intolerance.js';
|
|
3
3
|
export * from './convert-appointment-response.js';
|
|
4
4
|
export * from './convert-appointment.js';
|
|
5
|
+
export * from './convert-appointment-communication.js';
|
|
5
6
|
export * from './convert-care-plan.js';
|
|
6
7
|
export * from './convert-clinical-impression.js';
|
|
7
8
|
export * from './convert-communication-request.js';
|
|
@@ -11,17 +12,23 @@ export * from './convert-condition.js';
|
|
|
11
12
|
export * from './convert-coverage.js';
|
|
12
13
|
export * from './convert-device-use-statement.js';
|
|
13
14
|
export * from './convert-device.js';
|
|
15
|
+
export * from './convert-device-metric.js';
|
|
14
16
|
export * from './convert-diagnostic-report.js';
|
|
15
17
|
export * from './convert-document-reference.js';
|
|
16
18
|
export * from './convert-encounter.js';
|
|
19
|
+
export * from './convert-encounter-history.js';
|
|
17
20
|
export * from './convert-flag.js';
|
|
18
21
|
export * from './convert-immunization.js';
|
|
19
22
|
export * from './convert-imaging-study.js';
|
|
20
23
|
export * from './convert-location.js';
|
|
24
|
+
export * from './convert-healthcare-service.js';
|
|
21
25
|
export * from './convert-medication-statement.js';
|
|
22
26
|
export * from './convert-observation.js';
|
|
23
27
|
export * from './convert-organization.js';
|
|
24
28
|
export * from './convert-practitioner-role.js';
|
|
25
29
|
export * from './convert-procedure.js';
|
|
30
|
+
export * from './convert-regulated-authorization.js';
|
|
26
31
|
export * from './convert-related-person.js';
|
|
27
32
|
export * from './convert-service-request.js';
|
|
33
|
+
export * from './convert-schedule-slot.js';
|
|
34
|
+
export * from './materialize-claims-first-resource.js';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { FhirResource } from '../fhir-types.js';
|
|
2
|
+
export type ClaimsFirstFhirResource = Readonly<{
|
|
3
|
+
resourceType: 'Organization' | 'HealthcareService' | 'Location' | 'Schedule' | 'Slot' | 'DeviceMetric' | 'Procedure' | 'RegulatedAuthorization' | 'DocumentReference' | 'Encounter' | 'EncounterHistory';
|
|
4
|
+
id: string;
|
|
5
|
+
meta: Readonly<{
|
|
6
|
+
claims: Readonly<Record<string, unknown>>;
|
|
7
|
+
}>;
|
|
8
|
+
}>;
|
|
9
|
+
/**
|
|
10
|
+
* Materializes native FHIR R5 only at an explicit adapter boundary.
|
|
11
|
+
*
|
|
12
|
+
* Canonical persistence remains `{ resourceType, id, meta: { claims } }`.
|
|
13
|
+
* Nested native fields are rejected so a materialized representation can never
|
|
14
|
+
* silently become a second business source of truth.
|
|
15
|
+
*/
|
|
16
|
+
export declare function materializeClaimsFirstResourceToFhirR5(input: unknown): FhirResource;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { healthcareServiceFlatToFhirR5 } from './convert-healthcare-service.js';
|
|
2
|
+
import { locationFlatToFhirR5 } from './convert-location.js';
|
|
3
|
+
import { organizationFlatToFhirR5 } from './convert-organization.js';
|
|
4
|
+
import { scheduleFlatToFhirR5, slotFlatToFhirR5 } from './convert-schedule-slot.js';
|
|
5
|
+
import { deviceMetricFlatToFhirR5 } from './convert-device-metric.js';
|
|
6
|
+
import { procedureFlatToFhirR5 } from './convert-procedure.js';
|
|
7
|
+
import { regulatedAuthorizationFlatToFhirR5 } from './convert-regulated-authorization.js';
|
|
8
|
+
import { documentReferenceFlatToFhirR4 } from './convert-document-reference.js';
|
|
9
|
+
import { encounterFlatToFhirR5 } from './convert-encounter.js';
|
|
10
|
+
import { encounterHistoryFlatToFhirR5 } from './convert-encounter-history.js';
|
|
11
|
+
const materializers = Object.freeze({
|
|
12
|
+
Organization: organizationFlatToFhirR5,
|
|
13
|
+
HealthcareService: healthcareServiceFlatToFhirR5,
|
|
14
|
+
Location: locationFlatToFhirR5,
|
|
15
|
+
Schedule: scheduleFlatToFhirR5,
|
|
16
|
+
Slot: slotFlatToFhirR5,
|
|
17
|
+
DeviceMetric: deviceMetricFlatToFhirR5,
|
|
18
|
+
Procedure: procedureFlatToFhirR5,
|
|
19
|
+
RegulatedAuthorization: regulatedAuthorizationFlatToFhirR5,
|
|
20
|
+
DocumentReference: documentReferenceFlatToFhirR4,
|
|
21
|
+
Encounter: encounterFlatToFhirR5,
|
|
22
|
+
EncounterHistory: encounterHistoryFlatToFhirR5,
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* Materializes native FHIR R5 only at an explicit adapter boundary.
|
|
26
|
+
*
|
|
27
|
+
* Canonical persistence remains `{ resourceType, id, meta: { claims } }`.
|
|
28
|
+
* Nested native fields are rejected so a materialized representation can never
|
|
29
|
+
* silently become a second business source of truth.
|
|
30
|
+
*/
|
|
31
|
+
export function materializeClaimsFirstResourceToFhirR5(input) {
|
|
32
|
+
if (!input || typeof input !== 'object' || Array.isArray(input)) {
|
|
33
|
+
throw new TypeError('claims_first_resource_invalid');
|
|
34
|
+
}
|
|
35
|
+
const resource = input;
|
|
36
|
+
if (Object.keys(resource).some(key => !['resourceType', 'id', 'meta'].includes(key))) {
|
|
37
|
+
throw new TypeError('claims_first_resource_nested_fhir_forbidden');
|
|
38
|
+
}
|
|
39
|
+
const resourceType = String(resource.resourceType || '');
|
|
40
|
+
const materializer = materializers[resourceType];
|
|
41
|
+
if (!materializer)
|
|
42
|
+
throw new TypeError('claims_first_resource_type_unsupported');
|
|
43
|
+
const id = String(resource.id || '').trim();
|
|
44
|
+
if (!id)
|
|
45
|
+
throw new TypeError('claims_first_resource_id_required');
|
|
46
|
+
const meta = resource.meta;
|
|
47
|
+
if (!meta || typeof meta !== 'object' || Array.isArray(meta))
|
|
48
|
+
throw new TypeError('claims_first_resource_claims_required');
|
|
49
|
+
if (Object.keys(meta).some(key => key !== 'claims'))
|
|
50
|
+
throw new TypeError('claims_first_resource_nested_fhir_forbidden');
|
|
51
|
+
const rawClaims = meta.claims;
|
|
52
|
+
if (!rawClaims || typeof rawClaims !== 'object' || Array.isArray(rawClaims)) {
|
|
53
|
+
throw new TypeError('claims_first_resource_claims_required');
|
|
54
|
+
}
|
|
55
|
+
const claims = {};
|
|
56
|
+
for (const [claim, rawValue] of Object.entries(rawClaims)) {
|
|
57
|
+
const values = (Array.isArray(rawValue) ? rawValue : [rawValue])
|
|
58
|
+
.map(value => String(value).trim())
|
|
59
|
+
.filter(Boolean);
|
|
60
|
+
if (!values.length)
|
|
61
|
+
throw new TypeError('claims_first_resource_claim_value_invalid');
|
|
62
|
+
claims[claim] = values.join(',');
|
|
63
|
+
}
|
|
64
|
+
return Object.freeze({ ...materializer(claims), id });
|
|
65
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { EncounterStatusR5 } from './claims/encounter-claims.js';
|
|
2
|
+
/** Product-neutral identifiers and references for cross-package Encounter transfer contract tests. */
|
|
3
|
+
export declare const FHIR_ENCOUNTER_TRANSFER_TEST_DATA: Readonly<{
|
|
4
|
+
communicationIdentifier: "urn:uuid:00000000-0000-4000-8000-000000000401";
|
|
5
|
+
subjectReference: "Patient/00000000-0000-4000-8000-000000000402";
|
|
6
|
+
senderReference: "Organization/00000000-0000-4000-8000-000000000403";
|
|
7
|
+
indexRecipientReference: "Organization/00000000-0000-4000-8000-000000000404";
|
|
8
|
+
occurredAt: "2026-09-30T10:10:00Z";
|
|
9
|
+
class: Readonly<{
|
|
10
|
+
system: "http://terminology.hl7.org/CodeSystem/v3-ActCode";
|
|
11
|
+
code: "EMER";
|
|
12
|
+
}>;
|
|
13
|
+
source: Readonly<{
|
|
14
|
+
id: "00000000-0000-4000-8000-000000000405";
|
|
15
|
+
reference: "Encounter/00000000-0000-4000-8000-000000000405";
|
|
16
|
+
identifier: "urn:uuid:00000000-0000-4000-8000-000000000405";
|
|
17
|
+
serviceReference: "HealthcareService/00000000-0000-4000-8000-000000000406";
|
|
18
|
+
locationReference: "Location/00000000-0000-4000-8000-000000000407";
|
|
19
|
+
statusWhenReturning: EncounterStatusR5.OnHold;
|
|
20
|
+
statusWhenNotReturning: EncounterStatusR5.Completed;
|
|
21
|
+
}>;
|
|
22
|
+
destination: Readonly<{
|
|
23
|
+
id: "00000000-0000-4000-8000-000000000408";
|
|
24
|
+
reference: "Encounter/00000000-0000-4000-8000-000000000408";
|
|
25
|
+
identifier: "urn:uuid:00000000-0000-4000-8000-000000000408";
|
|
26
|
+
serviceReference: "HealthcareService/00000000-0000-4000-8000-000000000409";
|
|
27
|
+
locationReference: "Location/00000000-0000-4000-8000-000000000410";
|
|
28
|
+
statusOnArrival: EncounterStatusR5.InProgress;
|
|
29
|
+
}>;
|
|
30
|
+
sourceHistory: Readonly<{
|
|
31
|
+
id: "00000000-0000-4000-8000-000000000411";
|
|
32
|
+
identifier: "urn:uuid:00000000-0000-4000-8000-000000000411";
|
|
33
|
+
encounterReference: "Encounter/00000000-0000-4000-8000-000000000405";
|
|
34
|
+
}>;
|
|
35
|
+
destinationHistory: Readonly<{
|
|
36
|
+
id: "00000000-0000-4000-8000-000000000412";
|
|
37
|
+
identifier: "urn:uuid:00000000-0000-4000-8000-000000000412";
|
|
38
|
+
encounterReference: "Encounter/00000000-0000-4000-8000-000000000408";
|
|
39
|
+
}>;
|
|
40
|
+
}>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { EncounterStatusR5 } from './claims/encounter-claims.js';
|
|
2
|
+
/** Product-neutral identifiers and references for cross-package Encounter transfer contract tests. */
|
|
3
|
+
export const FHIR_ENCOUNTER_TRANSFER_TEST_DATA = Object.freeze({
|
|
4
|
+
communicationIdentifier: 'urn:uuid:00000000-0000-4000-8000-000000000401',
|
|
5
|
+
subjectReference: 'Patient/00000000-0000-4000-8000-000000000402',
|
|
6
|
+
senderReference: 'Organization/00000000-0000-4000-8000-000000000403',
|
|
7
|
+
indexRecipientReference: 'Organization/00000000-0000-4000-8000-000000000404',
|
|
8
|
+
occurredAt: '2026-09-30T10:10:00Z',
|
|
9
|
+
class: Object.freeze({ system: 'http://terminology.hl7.org/CodeSystem/v3-ActCode', code: 'EMER' }),
|
|
10
|
+
source: Object.freeze({
|
|
11
|
+
id: '00000000-0000-4000-8000-000000000405',
|
|
12
|
+
reference: 'Encounter/00000000-0000-4000-8000-000000000405',
|
|
13
|
+
identifier: 'urn:uuid:00000000-0000-4000-8000-000000000405',
|
|
14
|
+
serviceReference: 'HealthcareService/00000000-0000-4000-8000-000000000406',
|
|
15
|
+
locationReference: 'Location/00000000-0000-4000-8000-000000000407',
|
|
16
|
+
statusWhenReturning: EncounterStatusR5.OnHold,
|
|
17
|
+
statusWhenNotReturning: EncounterStatusR5.Completed,
|
|
18
|
+
}),
|
|
19
|
+
destination: Object.freeze({
|
|
20
|
+
id: '00000000-0000-4000-8000-000000000408',
|
|
21
|
+
reference: 'Encounter/00000000-0000-4000-8000-000000000408',
|
|
22
|
+
identifier: 'urn:uuid:00000000-0000-4000-8000-000000000408',
|
|
23
|
+
serviceReference: 'HealthcareService/00000000-0000-4000-8000-000000000409',
|
|
24
|
+
locationReference: 'Location/00000000-0000-4000-8000-000000000410',
|
|
25
|
+
statusOnArrival: EncounterStatusR5.InProgress,
|
|
26
|
+
}),
|
|
27
|
+
sourceHistory: Object.freeze({
|
|
28
|
+
id: '00000000-0000-4000-8000-000000000411',
|
|
29
|
+
identifier: 'urn:uuid:00000000-0000-4000-8000-000000000411',
|
|
30
|
+
encounterReference: 'Encounter/00000000-0000-4000-8000-000000000405',
|
|
31
|
+
}),
|
|
32
|
+
destinationHistory: Object.freeze({
|
|
33
|
+
id: '00000000-0000-4000-8000-000000000412',
|
|
34
|
+
identifier: 'urn:uuid:00000000-0000-4000-8000-000000000412',
|
|
35
|
+
encounterReference: 'Encounter/00000000-0000-4000-8000-000000000408',
|
|
36
|
+
}),
|
|
37
|
+
});
|
package/dist/fhir-bundle.d.ts
CHANGED
|
@@ -7,3 +7,24 @@ export declare function walkBundleResources(bundle: FhirBundle): readonly FhirRe
|
|
|
7
7
|
export declare function classifyBundleResources(bundle: FhirBundle): ReadonlyMap<string, readonly FhirResource[]>;
|
|
8
8
|
/** Resolves `ResourceType/id`, `urn:uuid:*`, an entry fullUrl, or a bare resource id. */
|
|
9
9
|
export declare function findBundleResourceByReference(bundle: FhirBundle, reference: string): FhirResource | undefined;
|
|
10
|
+
export type CommunicationInnerBundleType = 'document' | 'batch' | 'collection';
|
|
11
|
+
export type CommunicationBundlePayload = Readonly<{
|
|
12
|
+
communication: FhirResource;
|
|
13
|
+
attachment: Readonly<{
|
|
14
|
+
contentType: 'application/fhir+json';
|
|
15
|
+
data: string;
|
|
16
|
+
title?: string;
|
|
17
|
+
}>;
|
|
18
|
+
bundle: FhirBundle;
|
|
19
|
+
}>;
|
|
20
|
+
/**
|
|
21
|
+
* Bundle Reader boundary used by every secure Communication flow.
|
|
22
|
+
*
|
|
23
|
+
* The outer operational payload is always a batch Bundle containing
|
|
24
|
+
* Communication entries. Each Communication carries exactly one FHIR JSON
|
|
25
|
+
* attachment whose decoded resource is an inner document, batch or collection
|
|
26
|
+
* Bundle. Individual clinical resources and arbitrary file MIME types are not
|
|
27
|
+
* accepted directly at this boundary; files belong to DocumentReference
|
|
28
|
+
* entries inside the inner Bundle and must be edited through Bundle Editor.
|
|
29
|
+
*/
|
|
30
|
+
export declare function readCommunicationBundlePayloads(input: unknown): readonly CommunicationBundlePayload[];
|
package/dist/fhir-bundle.js
CHANGED
|
@@ -41,3 +41,77 @@ export function findBundleResourceByReference(bundle, reference) {
|
|
|
41
41
|
: [undefined, target.startsWith('urn:uuid:') ? target.slice('urn:uuid:'.length) : target];
|
|
42
42
|
return readBundleResources(bundle).find(resource => resource.id === id && (!resourceType || resource.resourceType === resourceType));
|
|
43
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Bundle Reader boundary used by every secure Communication flow.
|
|
46
|
+
*
|
|
47
|
+
* The outer operational payload is always a batch Bundle containing
|
|
48
|
+
* Communication entries. Each Communication carries exactly one FHIR JSON
|
|
49
|
+
* attachment whose decoded resource is an inner document, batch or collection
|
|
50
|
+
* Bundle. Individual clinical resources and arbitrary file MIME types are not
|
|
51
|
+
* accepted directly at this boundary; files belong to DocumentReference
|
|
52
|
+
* entries inside the inner Bundle and must be edited through Bundle Editor.
|
|
53
|
+
*/
|
|
54
|
+
export function readCommunicationBundlePayloads(input) {
|
|
55
|
+
const outerBatch = requireBundle(input);
|
|
56
|
+
if (outerBatch.type !== 'batch')
|
|
57
|
+
throw new TypeError('fhir_batch_bundle_required');
|
|
58
|
+
validateBatchRequests(outerBatch);
|
|
59
|
+
const payloads = readBundleResources(outerBatch)
|
|
60
|
+
.filter(resource => resource.resourceType === 'Communication')
|
|
61
|
+
.map(communication => {
|
|
62
|
+
const attachment = firstFhirBundleAttachment(communication);
|
|
63
|
+
let decoded;
|
|
64
|
+
try {
|
|
65
|
+
decoded = JSON.parse(decodeBase64Utf8(attachment.data));
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
throw new TypeError('fhir_bundle_attachment_invalid');
|
|
69
|
+
}
|
|
70
|
+
const bundle = requireBundle(decoded);
|
|
71
|
+
if (!['document', 'batch', 'collection'].includes(String(bundle.type)))
|
|
72
|
+
throw new TypeError('fhir_inner_bundle_type_invalid');
|
|
73
|
+
validateInnerBundle(bundle);
|
|
74
|
+
return Object.freeze({ communication, attachment, bundle });
|
|
75
|
+
});
|
|
76
|
+
if (!payloads.length)
|
|
77
|
+
throw new TypeError('fhir_communication_required');
|
|
78
|
+
return Object.freeze(payloads);
|
|
79
|
+
}
|
|
80
|
+
function requireBundle(value) {
|
|
81
|
+
if (!value || typeof value !== 'object' || Array.isArray(value) || value.resourceType !== 'Bundle')
|
|
82
|
+
throw new TypeError('fhir_bundle_required');
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
function firstFhirBundleAttachment(resource) {
|
|
86
|
+
const payload = Array.isArray(resource.payload) ? resource.payload : [];
|
|
87
|
+
if (payload.length !== 1)
|
|
88
|
+
throw new TypeError('fhir_single_bundle_attachment_required');
|
|
89
|
+
const item = payload[0];
|
|
90
|
+
if (!item || typeof item !== 'object' || Array.isArray(item))
|
|
91
|
+
throw new TypeError('fhir_bundle_attachment_required');
|
|
92
|
+
const attachment = item.contentAttachment;
|
|
93
|
+
if (!attachment || typeof attachment !== 'object' || Array.isArray(attachment))
|
|
94
|
+
throw new TypeError('fhir_bundle_attachment_required');
|
|
95
|
+
const candidate = attachment;
|
|
96
|
+
if (candidate.contentType !== 'application/fhir+json' || typeof candidate.data !== 'string' || !candidate.data) {
|
|
97
|
+
throw new TypeError('fhir_bundle_attachment_required');
|
|
98
|
+
}
|
|
99
|
+
return Object.freeze({ contentType: candidate.contentType, data: candidate.data, ...(typeof candidate.title === 'string' ? { title: candidate.title } : {}) });
|
|
100
|
+
}
|
|
101
|
+
function decodeBase64Utf8(value) {
|
|
102
|
+
const binary = globalThis.atob(value);
|
|
103
|
+
return new TextDecoder().decode(Uint8Array.from(binary, character => character.charCodeAt(0)));
|
|
104
|
+
}
|
|
105
|
+
function validateInnerBundle(bundle) {
|
|
106
|
+
if (bundle.type === 'document' && readBundleResources(bundle)[0]?.resourceType !== 'Composition') {
|
|
107
|
+
throw new TypeError('fhir_document_composition_first_required');
|
|
108
|
+
}
|
|
109
|
+
if (bundle.type === 'batch')
|
|
110
|
+
validateBatchRequests(bundle);
|
|
111
|
+
}
|
|
112
|
+
function validateBatchRequests(bundle) {
|
|
113
|
+
for (const entry of bundle.entry ?? []) {
|
|
114
|
+
if (!entry.request?.method || !entry.request.url)
|
|
115
|
+
throw new TypeError('fhir_batch_request_required');
|
|
116
|
+
}
|
|
117
|
+
}
|
package/dist/group-r5.d.ts
CHANGED
|
@@ -89,6 +89,12 @@ export type GroupR5ResearchTeam = Readonly<Record<string, unknown> & {
|
|
|
89
89
|
membership: 'enumerated';
|
|
90
90
|
member: readonly GroupPractitionerRoleMember[];
|
|
91
91
|
}>;
|
|
92
|
+
export type GroupR5ProfessionalServiceTeam = GroupR5ResearchTeam & Readonly<{
|
|
93
|
+
managingEntity: Readonly<{
|
|
94
|
+
reference: `Organization/${string}`;
|
|
95
|
+
type: 'Organization';
|
|
96
|
+
}>;
|
|
97
|
+
}>;
|
|
92
98
|
/**
|
|
93
99
|
* Normalizes the members used by an enumerated professional research team.
|
|
94
100
|
* Every entity is a native PractitionerRole reference; a Practitioner or an
|
|
@@ -101,6 +107,12 @@ export declare function normalizeGroupPractitionerRoleMembers(input: unknown): r
|
|
|
101
107
|
* properties are rejected at every depth.
|
|
102
108
|
*/
|
|
103
109
|
export declare function normalizeGroupR5ResearchTeam(input: unknown): GroupR5ResearchTeam;
|
|
110
|
+
/**
|
|
111
|
+
* Normalizes a professional team assigned to one Organization department.
|
|
112
|
+
* `managingEntity` is singular in FHIR R5, so one Group cannot span several
|
|
113
|
+
* departments. Membership remains descriptive and grants no permission.
|
|
114
|
+
*/
|
|
115
|
+
export declare function normalizeGroupR5ProfessionalServiceTeam(input: unknown): GroupR5ProfessionalServiceTeam;
|
|
104
116
|
/**
|
|
105
117
|
* Projects all populated official resource-specific R5 Group SearchParameters
|
|
106
118
|
* into flat `resource.meta.claims`. A referenced characteristic is indexed by
|
package/dist/group-r5.js
CHANGED
|
@@ -131,6 +131,26 @@ export function normalizeGroupR5ResearchTeam(input) {
|
|
|
131
131
|
const member = normalizeGroupPractitionerRoleMembers(input.member);
|
|
132
132
|
return Object.freeze({ ...input, type: 'practitioner', membership: 'enumerated', member });
|
|
133
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Normalizes a professional team assigned to one Organization department.
|
|
136
|
+
* `managingEntity` is singular in FHIR R5, so one Group cannot span several
|
|
137
|
+
* departments. Membership remains descriptive and grants no permission.
|
|
138
|
+
*/
|
|
139
|
+
export function normalizeGroupR5ProfessionalServiceTeam(input) {
|
|
140
|
+
const team = normalizeGroupR5ResearchTeam(input);
|
|
141
|
+
const managingEntity = team.managingEntity;
|
|
142
|
+
if (!isRecord(managingEntity))
|
|
143
|
+
throw new TypeError('group_professional_service_managing_organization_invalid');
|
|
144
|
+
const reference = optionalString(managingEntity.reference);
|
|
145
|
+
const declaredType = optionalString(managingEntity.type);
|
|
146
|
+
if (!reference || !/^Organization\/[A-Za-z0-9.-]{1,64}$/.test(reference) || (declaredType && declaredType !== 'Organization')) {
|
|
147
|
+
throw new TypeError('group_professional_service_managing_organization_invalid');
|
|
148
|
+
}
|
|
149
|
+
return Object.freeze({
|
|
150
|
+
...team,
|
|
151
|
+
managingEntity: Object.freeze({ reference: reference, type: 'Organization' }),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
134
154
|
/**
|
|
135
155
|
* Projects all populated official resource-specific R5 Group SearchParameters
|
|
136
156
|
* into flat `resource.meta.claims`. A referenced characteristic is indexed by
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Candidate SNOMED CT C80 to LOINC specialty map supplied for review.
|
|
3
|
+
*
|
|
4
|
+
* This is not an official SNOMED or LOINC map. The declared relationship is
|
|
5
|
+
* preserved so consumers can automate only strict equivalence and present
|
|
6
|
+
* wider, related, inexact or unmatched rows for professional governance.
|
|
7
|
+
*/
|
|
8
|
+
export declare const ClinicalSpecialtyMappingEquivalence: Readonly<{
|
|
9
|
+
readonly Equivalent: "equivalent";
|
|
10
|
+
readonly Wider: "wider";
|
|
11
|
+
readonly RelatedTo: "relatedto";
|
|
12
|
+
readonly Inexact: "inexact";
|
|
13
|
+
readonly Unmatched: "unmatched";
|
|
14
|
+
}>;
|
|
15
|
+
export type ClinicalSpecialtyMappingEquivalenceCode = typeof ClinicalSpecialtyMappingEquivalence[keyof typeof ClinicalSpecialtyMappingEquivalence];
|
|
16
|
+
export type ClinicalSpecialtyMapping = Readonly<{
|
|
17
|
+
snomedSystem: 'http://snomed.info/sct';
|
|
18
|
+
snomedCode: string;
|
|
19
|
+
snomedDisplay: string;
|
|
20
|
+
loincSystem?: 'http://loinc.org';
|
|
21
|
+
loincCode?: string;
|
|
22
|
+
loincDisplay?: string;
|
|
23
|
+
equivalence: ClinicalSpecialtyMappingEquivalenceCode;
|
|
24
|
+
automatic: boolean;
|
|
25
|
+
}>;
|
|
26
|
+
export declare const SnomedC80ToLoincSpecialtyConceptMap: readonly ClinicalSpecialtyMapping[];
|
|
27
|
+
/** Returns a portable LOINC specialty only for a strict reviewed equivalence. */
|
|
28
|
+
export declare function findAutomaticLoincSpecialty(snomedCode: string): Readonly<{
|
|
29
|
+
system: 'http://loinc.org';
|
|
30
|
+
code: string;
|
|
31
|
+
display: string;
|
|
32
|
+
}> | undefined;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Candidate SNOMED CT C80 to LOINC specialty map supplied for review.
|
|
3
|
+
*
|
|
4
|
+
* This is not an official SNOMED or LOINC map. The declared relationship is
|
|
5
|
+
* preserved so consumers can automate only strict equivalence and present
|
|
6
|
+
* wider, related, inexact or unmatched rows for professional governance.
|
|
7
|
+
*/
|
|
8
|
+
export const ClinicalSpecialtyMappingEquivalence = Object.freeze({
|
|
9
|
+
Equivalent: 'equivalent',
|
|
10
|
+
Wider: 'wider',
|
|
11
|
+
RelatedTo: 'relatedto',
|
|
12
|
+
Inexact: 'inexact',
|
|
13
|
+
Unmatched: 'unmatched',
|
|
14
|
+
});
|
|
15
|
+
const E = ClinicalSpecialtyMappingEquivalence.Equivalent;
|
|
16
|
+
const W = ClinicalSpecialtyMappingEquivalence.Wider;
|
|
17
|
+
const R = ClinicalSpecialtyMappingEquivalence.RelatedTo;
|
|
18
|
+
const I = ClinicalSpecialtyMappingEquivalence.Inexact;
|
|
19
|
+
const U = ClinicalSpecialtyMappingEquivalence.Unmatched;
|
|
20
|
+
const suppliedRows = Object.freeze([
|
|
21
|
+
['408467006', 'Adult mental illness', 'LP172958-3', 'Mental health', W],
|
|
22
|
+
['394577000', 'Anesthetics', 'LP172918-7', 'Anesthesiology', E],
|
|
23
|
+
['394578005', 'Audiological medicine', 'LP172919-5', 'Audiology', I],
|
|
24
|
+
['421661004', 'Blood banking and transfusion medicine', 'LP172920-3', 'Blood banking and transfusion medicine', E],
|
|
25
|
+
['408462000', 'Burns care', 'LP268363-1', 'Burn management', I],
|
|
26
|
+
['394579002', 'Cardiology', 'LA7179-0', 'Medicine.cardiology', E],
|
|
27
|
+
['394804000', 'Clinical cytogenetics and molecular genetics', 'LP172929-4', 'Clinical genetics', W],
|
|
28
|
+
['394580004', 'Clinical genetics', 'LP172929-4', 'Clinical genetics', E],
|
|
29
|
+
['394803006', 'Clinical hematology', 'LP175685-9', 'Hematology', I],
|
|
30
|
+
['408480009', 'Clinical immunology', 'LP345043-6', 'Immunology', W],
|
|
31
|
+
['408454008', 'Clinical microbiology', 'LP208903-7', 'Pathology - Medical microbiology', I],
|
|
32
|
+
['394809005', 'Clinical neuro-physiology', 'LP172931-0', 'Clinical neurophysiology', E],
|
|
33
|
+
['394592004', 'Clinical oncology', 'LP172901-3', 'Oncology', I],
|
|
34
|
+
['394600006', 'Clinical pharmacology', 'LP220238-2', 'Clinical pharmacology', E],
|
|
35
|
+
['394601005', 'Clinical physiology', undefined, undefined, U],
|
|
36
|
+
['394581000', 'Community medicine', 'LP204156-6', 'Community health care', I],
|
|
37
|
+
['408478003', 'Critical care medicine', 'LP172933-6', 'Critical care medicine', E],
|
|
38
|
+
['394812008', 'Dental medicine specialties', 'LP172934-4', 'Dentistry', W],
|
|
39
|
+
['408444009', 'Dental-General dental practice', 'LP172934-4', 'Dentistry', W],
|
|
40
|
+
['394582007', 'Dermatology', 'LP172935-1', 'Dermatology', E],
|
|
41
|
+
['408475000', 'Diabetic medicine', 'LP172938-5', 'Diabetology', E],
|
|
42
|
+
['410005002', 'Dive medicine', 'LP173035-9', 'Undersea and hyperbaric medicine', I],
|
|
43
|
+
['394583002', 'Endocrinology', 'LP172941-9', 'Endocrinology', E],
|
|
44
|
+
['419772000', 'Family practice', 'LP172943-5', 'Family medicine', E],
|
|
45
|
+
['394584008', 'Gastroenterology', 'LP172945-0', 'Gastroenterology', E],
|
|
46
|
+
['408443003', 'General medical practice', 'LP173010-2', 'Primary care', I],
|
|
47
|
+
['394802001', 'General medicine', 'LP172946-8', 'General medicine', E],
|
|
48
|
+
['394915009', 'General pathology', 'LP172984-9', 'Pathology', I],
|
|
49
|
+
['394814009', 'General practice', 'LP173010-2', 'Primary care', I],
|
|
50
|
+
['394808002', 'Genito-urinary medicine', 'LP173036-7', 'Urology', W],
|
|
51
|
+
['394811001', 'Geriatric medicine', 'LP172947-6', 'Geriatric medicine', E],
|
|
52
|
+
['408446006', 'Gynecological oncology', 'LP202989-2', 'Gynecologic oncology', E],
|
|
53
|
+
['394586005', 'Gynecology', 'LP221284-5', 'Gynecology', E],
|
|
54
|
+
['394916005', 'Hematopathology', 'LP172984-9', 'Pathology', W],
|
|
55
|
+
['408472002', 'Hepatology', 'LP172950-0', 'Hepatology', E],
|
|
56
|
+
['394597005', 'Histopathology', 'LP208907-8', 'Anatomic pathology', W],
|
|
57
|
+
['394598000', 'Immunopathology', 'LP345043-6', 'Immunology', W],
|
|
58
|
+
['394807007', 'Infectious diseases', 'LP172951-8', 'Infectious disease', E],
|
|
59
|
+
['419192003', 'Internal medicine', 'LP172952-6', 'Internal medicine', E],
|
|
60
|
+
['408468001', 'Learning disability', undefined, undefined, U],
|
|
61
|
+
['394593009', 'Medical oncology', 'LP175686-7', 'Medical Oncology', E],
|
|
62
|
+
['394813003', 'Medical ophthalmology', 'LP172974-0', 'Ophthalmology', W],
|
|
63
|
+
['410001006', 'Military medicine', undefined, undefined, U],
|
|
64
|
+
['394589003', 'Nephrology', 'LP172962-5', 'Nephrology', E],
|
|
65
|
+
['394591006', 'Neurology', 'LP172964-1', 'Neurology', E],
|
|
66
|
+
['394599008', 'Neuropathology', 'LP208907-8', 'Anatomic pathology', W],
|
|
67
|
+
['394649004', 'Nuclear medicine', 'LP172968-2', 'Nuclear medicine', E],
|
|
68
|
+
['408470005', 'Obstetrics', 'LP221283-7', 'Obstetrics', E],
|
|
69
|
+
['394585009', 'Obstetrics and gynecology', 'LP172971-6', 'Obstetrics and gynecology', E],
|
|
70
|
+
['394821009', 'Occupational medicine', 'LP172972-4', 'Occupational medicine', E],
|
|
71
|
+
['422191005', 'Ophthalmic surgery', 'LP172974-0', 'Ophthalmology', W],
|
|
72
|
+
['394594003', 'Ophthalmology', 'LP172974-0', 'Ophthalmology', E],
|
|
73
|
+
['416304004', 'Osteopathic manipulative medicine', 'LP434767-2', 'Osteopathic medicine', I],
|
|
74
|
+
['418960008', 'Otolaryngology', 'LP172980-7', 'Otolaryngology', E],
|
|
75
|
+
['394882004', 'Pain management', 'LP172981-5', 'Pain medicine', I],
|
|
76
|
+
['394806003', 'Palliative medicine', 'LP172982-3', 'Palliative care', I],
|
|
77
|
+
['394588006', 'Pediatric (Child and adolescent) psychiatry', 'LP172922-9', 'Child and adolescent psychiatry', E],
|
|
78
|
+
['408459003', 'Pediatric cardiology', 'LP172985-6', 'Pediatric cardiology', E],
|
|
79
|
+
['394607009', 'Pediatric dentistry', 'LP172934-4', 'Dentistry', W],
|
|
80
|
+
['419610006', 'Pediatric endocrinology', 'LP172989-8', 'Pediatric endocrinology', E],
|
|
81
|
+
['418058008', 'Pediatric gastroenterology', 'LP172990-6', 'Pediatric gastroenterology', E],
|
|
82
|
+
['420208008', 'Pediatric genetics', 'LP172956-7', 'Medical genetics', W],
|
|
83
|
+
['418652005', 'Pediatric hematology', 'LP172991-4', 'Pediatric hematology-oncology', W],
|
|
84
|
+
['418535003', 'Pediatric immunology', 'LP345043-6', 'Immunology', W],
|
|
85
|
+
['418862001', 'Pediatric infectious diseases', 'LP172992-2', 'Pediatric infectious diseases', E],
|
|
86
|
+
['419365004', 'Pediatric nephrology', 'LP172993-0', 'Pediatric nephrology', E],
|
|
87
|
+
['418002000', 'Pediatric oncology', 'LP172991-4', 'Pediatric hematology-oncology', I],
|
|
88
|
+
['419983000', 'Pediatric ophthalmology', 'LP172974-0', 'Ophthalmology', W],
|
|
89
|
+
['419170002', 'Pediatric pulmonology', 'LP172995-5', 'Pediatric pulmonology', E],
|
|
90
|
+
['419472004', 'Pediatric rheumatology', 'LP172998-9', 'Pediatric rheumatology', E],
|
|
91
|
+
['394539006', 'Pediatric surgery', 'LP172999-7', 'Pediatric surgery', E],
|
|
92
|
+
['420112009', 'Pediatric surgery-bone marrow transplantation', 'LP417851-5', 'Bone Marrow Transplant', I],
|
|
93
|
+
['409968004', 'Preventive medicine', 'LP173009-4', 'Preventive medicine', E],
|
|
94
|
+
['394587001', 'Psychiatry', 'LP173011-0', 'Psychiatry', E],
|
|
95
|
+
['394913002', 'Psychotherapy', 'LP173012-8', 'Psychology', R],
|
|
96
|
+
['408440000', 'Public health medicine', 'LP173014-4', 'Public health', I],
|
|
97
|
+
['418112009', 'Pulmonary medicine', 'LP173015-1', 'Pulmonary disease', I],
|
|
98
|
+
['419815003', 'Radiation oncology', 'LP173016-9', 'Radiation oncology', E],
|
|
99
|
+
['394914008', 'Radiology', 'LP173018-5', 'Radiology', E],
|
|
100
|
+
['408455009', 'Radiology-Interventional radiology', 'LP172896-5', 'Interventional radiology', E],
|
|
101
|
+
['394602003', 'Rehabilitation', 'LP173004-5', 'Physical medicine and rehabilitation', I],
|
|
102
|
+
['408447002', 'Respite care', 'LP173240-5', 'Respite', R],
|
|
103
|
+
['394810000', 'Rheumatology', 'LP173023-5', 'Rheumatology', E],
|
|
104
|
+
['408450004', 'Sleep studies', 'LP248728-0', 'Sleep medicine', I],
|
|
105
|
+
['408476004', 'Surgery-Bone and marrow transplantation', 'LP417851-5', 'Bone Marrow Transplant', I],
|
|
106
|
+
['408469009', 'Surgery-Breast surgery', 'LA7201-2', 'Surgery.breast', E],
|
|
107
|
+
['408466002', 'Surgery-Cardiac surgery', 'LP207300-7', 'Cardiac surgery', E],
|
|
108
|
+
['408471009', 'Surgery-Cardiothoracic transplantation', 'LP173033-4', 'Transplant surgery', W],
|
|
109
|
+
['408464004', 'Surgery-Colorectal surgery', 'LP172932-8', 'Colon and rectal surgery', E],
|
|
110
|
+
['408441001', 'Surgery-Dental-Endodontics', 'LP172934-4', 'Dentistry', W],
|
|
111
|
+
['408465003', 'Surgery-Dental-Oral and maxillofacial surgery', 'LP172902-1', 'Oral and maxillofacial surgery', E],
|
|
112
|
+
['394605001', 'Surgery-Dental-Oral surgery', 'LP172902-1', 'Oral and maxillofacial surgery', I],
|
|
113
|
+
['394608004', 'Surgery-Dental-Orthodontics / Dentistry-surgical-Orthodontics', 'LP172934-4', 'Dentistry', W],
|
|
114
|
+
['408461007', 'Surgery-Dental-Periodontal surgery', 'LP172934-4', 'Dentistry', W],
|
|
115
|
+
['408460008', 'Prosthodontics / surgical-Prosthodontics', 'LP172934-4', 'Dentistry', W],
|
|
116
|
+
['394606000', 'Surgery-Dentistry-Restorative dentistry', 'LP172934-4', 'Dentistry', W],
|
|
117
|
+
['408449004', 'Surgery-Dentistry--surgical', 'LP172934-4', 'Dentistry', W],
|
|
118
|
+
['418018006', 'Surgery-Dermatologic surgery', 'LP172935-1', 'Dermatology', W],
|
|
119
|
+
['394604002', 'Surgery-Ear, nose and throat surgery', 'LP172980-7', 'Otolaryngology', I],
|
|
120
|
+
['394609007', 'Surgery-general', 'LA7205-3', 'Surgery.general', E],
|
|
121
|
+
['408474001', 'Surgery-Hepatobiliary and pancreatic surgery', 'LP172950-0', 'Hepatology', W],
|
|
122
|
+
['394610002', 'Surgery-Neurosurgery', 'LP172963-3', 'Neurological surgery', E],
|
|
123
|
+
['394611003', 'Surgery-Plastic surgery', 'LP173006-0', 'Plastic surgery', E],
|
|
124
|
+
['408477008', 'Surgery-Transplantation surgery', 'LP173033-4', 'Transplant surgery', E],
|
|
125
|
+
['394801008', 'Surgery-Trauma and orthopedics', 'LP434806-8', 'Orthopaedic surgery', I],
|
|
126
|
+
['408463005', 'Surgery-Vascular', 'LP173039-1', 'Vascular surgery', E],
|
|
127
|
+
['419321007', 'Surgical oncology', 'LP207940-0', 'Surgical oncology', E],
|
|
128
|
+
['394576009', 'Surgical-Accident & emergency', 'LP172940-1', 'Emergency medicine', I],
|
|
129
|
+
['394590007', 'Thoracic medicine', 'LP173031-8', 'Thoracic and cardiac surgery', R],
|
|
130
|
+
['409967009', 'Toxicology', 'LP172957-5', 'Medical toxicology', I],
|
|
131
|
+
['408448007', 'Tropical medicine', undefined, undefined, U],
|
|
132
|
+
['419043006', 'Urological oncology', 'LP173036-7', 'Urology', W],
|
|
133
|
+
['394612005', 'Urology', 'LP173036-7', 'Urology', E],
|
|
134
|
+
['394733009', 'Medical specialty--OTHER--NOT LISTED', 'LA46-8', 'Other', I],
|
|
135
|
+
['394732004', 'Surgical specialty--OTHER-NOT LISTED', 'LA46-8', 'Other', I],
|
|
136
|
+
]);
|
|
137
|
+
export const SnomedC80ToLoincSpecialtyConceptMap = Object.freeze(suppliedRows.map(([snomedCode, snomedDisplay, loincCode, loincDisplay, equivalence = U]) => Object.freeze({
|
|
138
|
+
snomedSystem: 'http://snomed.info/sct',
|
|
139
|
+
snomedCode,
|
|
140
|
+
snomedDisplay,
|
|
141
|
+
...(loincCode ? { loincSystem: 'http://loinc.org', loincCode, loincDisplay } : {}),
|
|
142
|
+
equivalence,
|
|
143
|
+
automatic: equivalence === E,
|
|
144
|
+
})));
|
|
145
|
+
/** Returns a portable LOINC specialty only for a strict reviewed equivalence. */
|
|
146
|
+
export function findAutomaticLoincSpecialty(snomedCode) {
|
|
147
|
+
const mapping = SnomedC80ToLoincSpecialtyConceptMap.find(item => item.snomedCode === snomedCode);
|
|
148
|
+
if (!mapping?.automatic || !mapping.loincCode || !mapping.loincDisplay)
|
|
149
|
+
return undefined;
|
|
150
|
+
return Object.freeze({ system: 'http://loinc.org', code: mapping.loincCode, display: mapping.loincDisplay });
|
|
151
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -24,3 +24,6 @@ export * from './fhir-tokens.js';
|
|
|
24
24
|
export * from './related-person.js';
|
|
25
25
|
export * from './imaging-types.js';
|
|
26
26
|
export * from './subscription-r5.js';
|
|
27
|
+
export * from './healthcare-service-specialty-map.js';
|
|
28
|
+
export * from './appointment-communication-test-data.js';
|
|
29
|
+
export * from './encounter-transfer-test-data.js';
|
package/dist/index.js
CHANGED
|
@@ -24,3 +24,6 @@ export * from './fhir-tokens.js';
|
|
|
24
24
|
export * from './related-person.js';
|
|
25
25
|
export * from './imaging-types.js';
|
|
26
26
|
export * from './subscription-r5.js';
|
|
27
|
+
export * from './healthcare-service-specialty-map.js';
|
|
28
|
+
export * from './appointment-communication-test-data.js';
|
|
29
|
+
export * from './encounter-transfer-test-data.js';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Clinical Typed Accessor Boundary
|
|
2
|
+
|
|
3
|
+
This package owns the FHIR-neutral claim and projection layer. It does not own
|
|
4
|
+
the mutable SDK `BundleReader` / `BundleEditor` session API.
|
|
5
|
+
|
|
6
|
+
The clinical fields required by the current GDC typed editors are already
|
|
7
|
+
canonical here and survive the native FHIR R4 boundary:
|
|
8
|
+
|
|
9
|
+
| Clinical field | Canonical flat claim | Native FHIR R4 projection |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Observed allergy reaction severity | `AllergyIntolerance.severity` | `AllergyIntolerance.reaction[].severity` |
|
|
12
|
+
| Medication treatment end | `MedicationStatement.effective-period-end` | `MedicationStatement.effectivePeriod.end` |
|
|
13
|
+
| Immunization administration route | `Immunization.route` | `Immunization.route` |
|
|
14
|
+
| Immunization administration site | `Immunization.site` | `Immunization.site` |
|
|
15
|
+
| Observation reference-range text | `Observation.reference-range-text` | `Observation.referenceRange[].text` |
|
|
16
|
+
|
|
17
|
+
`fhir-data-utils-ts` therefore must preserve these fields in claim catalogs,
|
|
18
|
+
FHIR converters and resource graphs. It must not copy the GDC SDK's mutable
|
|
19
|
+
editor classes or transport-aware Bundle session behavior.
|
|
20
|
+
|
|
21
|
+
The layer split is:
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
fhir-data-utils-ts
|
|
25
|
+
canonical claims + R4/R5/R6 import/export
|
|
26
|
+
↓
|
|
27
|
+
sos-data-utils-ts
|
|
28
|
+
product-neutral multichannel field schemas
|
|
29
|
+
↓
|
|
30
|
+
sos-sdk-core-ts / sos-sdk-node-ts
|
|
31
|
+
shared orchestration and runtime adapters
|
|
32
|
+
↓
|
|
33
|
+
vet-* / uhc-*
|
|
34
|
+
product forms, portal editors and telephone/chat dialogue
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
When Vet or UHC adds a visual, chat or telephone editor for one of these
|
|
38
|
+
fields, it must consume the canonical claim key from this package. It must not
|
|
39
|
+
maintain a second literal, converter or incompatible getter/setter model.
|
|
40
|
+
|
|
41
|
+
The mutable GDC Bundle API remains documented separately in
|
|
42
|
+
[`gdc-common-utils-ts`](https://github.com/Global-DataCare/gdc-common-utils-ts/blob/main/docs/101-CLINICAL-ENTRY-GETTERS-SETTERS.md)
|
|
43
|
+
and exposed to Node applications by
|
|
44
|
+
[`gdc-sdk-node-ts`](https://github.com/Global-DataCare/gdc-sdk-node-ts/blob/main/docs/101-CLINICAL-ENTRY-GETTERS-SETTERS.md).
|