gdc-common-utils-ts 2.3.26 → 2.3.28
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/README.md +5 -0
- package/dist/claims/claims-helpers-related-person.js +0 -1
- package/dist/convert/convert-care-plan.js +25 -1
- package/dist/convert/convert-condition.js +12 -0
- package/dist/convert/convert-consent.js +59 -13
- package/dist/convert/convert-device-use-statement.js +3 -1
- package/dist/convert/convert-immunization.js +12 -2
- package/dist/convert/convert-medication-statement.js +35 -1
- package/dist/convert/convert-observation.js +43 -2
- package/dist/convert/convert-practitioner-role.d.ts +1 -1
- package/dist/convert/convert-practitioner-role.js +41 -13
- package/dist/convert/convert-shared.js +1 -1
- package/dist/examples/communication-didcomm-payload.d.ts +2 -2
- package/dist/examples/related-person.d.ts +9 -9
- package/dist/models/consent-rule.d.ts +8 -1
- package/dist/models/consent-rule.js +8 -1
- package/dist/models/indexing.d.ts +5 -5
- package/dist/models/interoperable-claims/appointment-claims.d.ts +57 -57
- package/dist/models/interoperable-claims/appointment-claims.js +31 -32
- package/dist/models/interoperable-claims/appointment-response-claims.d.ts +11 -11
- package/dist/models/interoperable-claims/appointment-response-claims.js +11 -11
- package/dist/models/interoperable-claims/care-plan-claims.d.ts +11 -0
- package/dist/models/interoperable-claims/care-plan-claims.js +11 -0
- package/dist/models/interoperable-claims/clinical-impression-claims.d.ts +1 -1
- package/dist/models/interoperable-claims/clinical-impression-claims.js +1 -1
- package/dist/models/interoperable-claims/condition-claims.d.ts +2 -0
- package/dist/models/interoperable-claims/condition-claims.js +2 -0
- package/dist/models/interoperable-claims/device-use-statement-claims.d.ts +3 -2
- package/dist/models/interoperable-claims/device-use-statement-claims.js +3 -2
- package/dist/models/interoperable-claims/document-reference-claims.d.ts +1 -1
- package/dist/models/interoperable-claims/document-reference-claims.js +1 -1
- package/dist/models/interoperable-claims/immunization-claims.d.ts +4 -0
- package/dist/models/interoperable-claims/immunization-claims.js +4 -0
- package/dist/models/interoperable-claims/medication-statement-claims.d.ts +6 -0
- package/dist/models/interoperable-claims/medication-statement-claims.js +6 -0
- package/dist/models/interoperable-claims/observation-claims.d.ts +12 -4
- package/dist/models/interoperable-claims/observation-claims.js +10 -2
- package/dist/models/interoperable-claims/practitioner-role-claims.d.ts +9 -0
- package/dist/models/interoperable-claims/practitioner-role-claims.js +9 -0
- package/dist/models/interoperable-claims/related-person-claims.d.ts +3 -2
- package/dist/models/interoperable-claims/related-person-claims.js +3 -2
- package/dist/models/params.d.ts +1 -1
- package/dist/utils/bundle-document-builder.js +37 -16
- package/dist/utils/bundle-entry-editor.d.ts +13 -0
- package/dist/utils/bundle-entry-editor.js +18 -0
- package/dist/utils/clinical-resource-converters.js +6 -4
- package/dist/utils/clinical-resource-view.d.ts +55 -0
- package/dist/utils/clinical-resource-view.js +137 -1
- package/dist/utils/communication-bundle-document-request.js +1 -1
- package/dist/utils/communication-fhir-r4.js +1 -1
- package/dist/utils/fhir-api-claim-helpers.d.ts +2 -0
- package/dist/utils/fhir-api-claim-helpers.js +16 -0
- package/dist/utils/ips-bundle-claims.d.ts +3 -4
- package/dist/utils/ips-bundle-claims.js +7 -7
- package/dist/utils/medication-statement-entry-editor.js +10 -10
- package/dist/utils/observation-component-entry-editor.d.ts +2 -2
- package/dist/utils/observation-component-entry-editor.js +2 -2
- package/package.json +1 -1
|
@@ -100,6 +100,14 @@ export declare const ObservationClaim: {
|
|
|
100
100
|
readonly ValueQuantityNumber: "Observation.value-quantity-number";
|
|
101
101
|
/** Human-readable quantity unit. Example: `/min`, `mmHg`, `Cel`. */
|
|
102
102
|
readonly ValueQuantityUnit: "Observation.value-quantity-unit";
|
|
103
|
+
readonly ReferenceRangeLowNumber: "Observation.reference-range-low-number";
|
|
104
|
+
readonly ReferenceRangeHighNumber: "Observation.reference-range-high-number";
|
|
105
|
+
readonly ReferenceRangeUnit: "Observation.reference-range-unit";
|
|
106
|
+
readonly ReferenceRangeText: "Observation.reference-range-text";
|
|
107
|
+
readonly ComponentCode: "Observation.component-code";
|
|
108
|
+
readonly ComponentCodeDisplay: "Observation.component-code-display";
|
|
109
|
+
readonly ComponentValueQuantityNumber: "Observation.component-value-quantity-number";
|
|
110
|
+
readonly ComponentValueQuantityUnit: "Observation.component-value-quantity-unit";
|
|
103
111
|
/** Aggregated score total for composite assessment observations when present. Example: `8`. */
|
|
104
112
|
readonly ScoreTotalNumber: "Observation.score-total-number";
|
|
105
113
|
/** Indexed systolic scalar copied onto the parent blood pressure observation. Example: `120`. */
|
|
@@ -110,8 +118,8 @@ export declare const ObservationClaim: {
|
|
|
110
118
|
readonly ValueString: "Observation.value-string";
|
|
111
119
|
/** User-authored note. Example: `Measured after resting 5 minutes.` */
|
|
112
120
|
readonly Note: "Observation.note";
|
|
113
|
-
/** FHIR-compatible explicit `effectiveDateTime` fallback. Example: `2026-06-01T10:00:00Z`. */
|
|
114
|
-
readonly EffectiveDateTime: "Observation.
|
|
121
|
+
/** FHIR-compatible explicit `effectiveDateTime` fallback using the canonical kebab-case claim name. Example: `2026-06-01T10:00:00Z`. */
|
|
122
|
+
readonly EffectiveDateTime: "Observation.effective-datetime";
|
|
115
123
|
};
|
|
116
124
|
export type ObservationClaimKey = typeof ObservationClaim[keyof typeof ObservationClaim];
|
|
117
125
|
export type SplitCodingClaims = Readonly<{
|
|
@@ -259,14 +267,14 @@ export type ClaimsVitalSign = ClaimsObservationVitalSigns;
|
|
|
259
267
|
* Free-text or UI-only fields may exist here even when they must stay out of
|
|
260
268
|
* blind-query/search indexes.
|
|
261
269
|
*/
|
|
262
|
-
export declare const ObservationGeneralClaimsList: readonly ["Observation.based-on", "Observation.category", "Observation.code-system", "Observation.code-value", "Observation.code-text", "Observation.code-display", "Observation.code", "Observation.date", "Observation.device", "Observation.encounter", "Observation.
|
|
270
|
+
export declare const ObservationGeneralClaimsList: readonly ["Observation.based-on", "Observation.category", "Observation.code-system", "Observation.code-value", "Observation.code-text", "Observation.code-display", "Observation.code", "Observation.date", "Observation.device", "Observation.encounter", "Observation.effective-datetime", "Observation.focus", "Observation.has-member", "Observation.component-tags", "Observation.component-code-values", "Observation.component-names", "Observation.identifier", "Observation.language", "Observation.method", "Observation.note", "Observation.patient", "Observation.performer", "Observation.specimen", "Observation.status", "Observation.subject", "Observation.value-concept-system", "Observation.value-concept-value", "Observation.value-concept-text", "Observation.value-concept-display", "Observation.value-concept", "Observation.value-date", "Observation.value-quantity-comparator", "Observation.value-quantity-number", "Observation.value-quantity-unit", "Observation.score-total-number", "Observation.bp-systolic-number", "Observation.bp-diastolic-number", "Observation.value-string"];
|
|
263
271
|
/**
|
|
264
272
|
* Full persisted claim surface for visible/searchable Vital Signs rows.
|
|
265
273
|
*
|
|
266
274
|
* This keeps the claims-first authoring fields but still avoids introducing
|
|
267
275
|
* fields that only belong to broader Observation families.
|
|
268
276
|
*/
|
|
269
|
-
export declare const ObservationVitalSignsClaimsList: readonly ["Observation.category", "Observation.code-system", "Observation.code-value", "Observation.code-text", "Observation.code-display", "Observation.code", "Observation.date", "Observation.
|
|
277
|
+
export declare const ObservationVitalSignsClaimsList: readonly ["Observation.category", "Observation.code-system", "Observation.code-value", "Observation.code-text", "Observation.code-display", "Observation.code", "Observation.date", "Observation.effective-datetime", "Observation.has-member", "Observation.component-tags", "Observation.component-code-values", "Observation.component-names", "Observation.identifier", "Observation.language", "Observation.method", "Observation.note", "Observation.patient", "Observation.status", "Observation.subject", "Observation.value-concept-system", "Observation.value-concept-value", "Observation.value-concept-text", "Observation.value-concept-display", "Observation.value-concept", "Observation.value-date", "Observation.value-quantity-comparator", "Observation.value-quantity-number", "Observation.value-quantity-unit", "Observation.score-total-number", "Observation.bp-systolic-number", "Observation.bp-diastolic-number", "Observation.value-string"];
|
|
270
278
|
export declare const ObservationClaimSpecs: ClaimSpec[];
|
|
271
279
|
/**
|
|
272
280
|
* Returns `true` when the flat claims represent one visible/searchable vital
|
|
@@ -102,6 +102,14 @@ export const ObservationClaim = {
|
|
|
102
102
|
ValueQuantityNumber: 'Observation.value-quantity-number',
|
|
103
103
|
/** Human-readable quantity unit. Example: `/min`, `mmHg`, `Cel`. */
|
|
104
104
|
ValueQuantityUnit: 'Observation.value-quantity-unit',
|
|
105
|
+
ReferenceRangeLowNumber: 'Observation.reference-range-low-number',
|
|
106
|
+
ReferenceRangeHighNumber: 'Observation.reference-range-high-number',
|
|
107
|
+
ReferenceRangeUnit: 'Observation.reference-range-unit',
|
|
108
|
+
ReferenceRangeText: 'Observation.reference-range-text',
|
|
109
|
+
ComponentCode: 'Observation.component-code',
|
|
110
|
+
ComponentCodeDisplay: 'Observation.component-code-display',
|
|
111
|
+
ComponentValueQuantityNumber: 'Observation.component-value-quantity-number',
|
|
112
|
+
ComponentValueQuantityUnit: 'Observation.component-value-quantity-unit',
|
|
105
113
|
/** Aggregated score total for composite assessment observations when present. Example: `8`. */
|
|
106
114
|
ScoreTotalNumber: 'Observation.score-total-number',
|
|
107
115
|
/** Indexed systolic scalar copied onto the parent blood pressure observation. Example: `120`. */
|
|
@@ -112,8 +120,8 @@ export const ObservationClaim = {
|
|
|
112
120
|
ValueString: 'Observation.value-string',
|
|
113
121
|
/** User-authored note. Example: `Measured after resting 5 minutes.` */
|
|
114
122
|
Note: 'Observation.note',
|
|
115
|
-
/** FHIR-compatible explicit `effectiveDateTime` fallback. Example: `2026-06-01T10:00:00Z`. */
|
|
116
|
-
EffectiveDateTime: 'Observation.
|
|
123
|
+
/** FHIR-compatible explicit `effectiveDateTime` fallback using the canonical kebab-case claim name. Example: `2026-06-01T10:00:00Z`. */
|
|
124
|
+
EffectiveDateTime: 'Observation.effective-datetime',
|
|
117
125
|
};
|
|
118
126
|
/**
|
|
119
127
|
* Builds the legacy compact `system|code` token from split claims.
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import type { ClaimSpec } from './types';
|
|
2
2
|
/** Canonical claims used to preserve the primary coded PractitionerRole label. */
|
|
3
3
|
export declare const PractitionerRoleClaim: {
|
|
4
|
+
readonly Identifier: "PractitionerRole.identifier";
|
|
5
|
+
readonly Active: "PractitionerRole.active";
|
|
6
|
+
readonly Practitioner: "PractitionerRole.practitioner";
|
|
7
|
+
readonly Organization: "PractitionerRole.organization";
|
|
8
|
+
readonly Location: "PractitionerRole.location";
|
|
9
|
+
readonly Service: "PractitionerRole.service";
|
|
10
|
+
readonly Specialty: "PractitionerRole.specialty";
|
|
11
|
+
readonly PeriodStart: "PractitionerRole.period-start";
|
|
12
|
+
readonly PeriodEnd: "PractitionerRole.period-end";
|
|
4
13
|
readonly Code: "PractitionerRole.code";
|
|
5
14
|
readonly CodeText: "PractitionerRole.code-text";
|
|
6
15
|
readonly CodeDisplay: "PractitionerRole.code-display";
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
// Copyright 2026 Conéctate Soluciones y Aplicaciones SL under the Apache License, Version 2.0.
|
|
2
2
|
/** Canonical claims used to preserve the primary coded PractitionerRole label. */
|
|
3
3
|
export const PractitionerRoleClaim = {
|
|
4
|
+
Identifier: 'PractitionerRole.identifier',
|
|
5
|
+
Active: 'PractitionerRole.active',
|
|
6
|
+
Practitioner: 'PractitionerRole.practitioner',
|
|
7
|
+
Organization: 'PractitionerRole.organization',
|
|
8
|
+
Location: 'PractitionerRole.location',
|
|
9
|
+
Service: 'PractitionerRole.service',
|
|
10
|
+
Specialty: 'PractitionerRole.specialty',
|
|
11
|
+
PeriodStart: 'PractitionerRole.period-start',
|
|
12
|
+
PeriodEnd: 'PractitionerRole.period-end',
|
|
4
13
|
Code: 'PractitionerRole.code',
|
|
5
14
|
CodeText: 'PractitionerRole.code-text',
|
|
6
15
|
CodeDisplay: 'PractitionerRole.code-display',
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { ClaimSpec } from './types';
|
|
2
2
|
export declare const RelatedPersonClaim: {
|
|
3
|
-
/**
|
|
3
|
+
/** Canonical FHIR API identifier search parameter. */
|
|
4
4
|
readonly Identifier: "RelatedPerson.identifier";
|
|
5
|
-
|
|
5
|
+
/** @deprecated Use `Identifier`; retained as a source-compatible property alias. */
|
|
6
|
+
readonly IdentifierValue: "RelatedPerson.identifier";
|
|
6
7
|
readonly Active: "RelatedPerson.active";
|
|
7
8
|
readonly Patient: "RelatedPerson.patient";
|
|
8
9
|
readonly Relationship: "RelatedPerson.relationship";
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// Copyright 2026 Conéctate Soluciones y Aplicaciones SL under the Apache License, Version 2.0.
|
|
2
2
|
// File: src/models/interoperable-claims/related-person-claims.ts
|
|
3
3
|
export const RelatedPersonClaim = {
|
|
4
|
-
/**
|
|
4
|
+
/** Canonical FHIR API identifier search parameter. */
|
|
5
5
|
Identifier: 'RelatedPerson.identifier',
|
|
6
|
-
|
|
6
|
+
/** @deprecated Use `Identifier`; retained as a source-compatible property alias. */
|
|
7
|
+
IdentifierValue: 'RelatedPerson.identifier',
|
|
7
8
|
Active: 'RelatedPerson.active',
|
|
8
9
|
Patient: 'RelatedPerson.patient',
|
|
9
10
|
Relationship: 'RelatedPerson.relationship',
|
package/dist/models/params.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export interface ClaimInteroperable {
|
|
5
5
|
/**
|
|
6
|
-
* Key name of the interoperable claim in reverse-DNS (e.g., 'org.hl7.fhir.
|
|
6
|
+
* Key name of the interoperable FHIR API claim in reverse-DNS (e.g., 'org.hl7.fhir.api.Immunization.vaccine-code').
|
|
7
7
|
*/
|
|
8
8
|
name: string;
|
|
9
9
|
/**
|
|
@@ -5,7 +5,9 @@ import { ConditionClaim } from '../models/interoperable-claims/condition-claims.
|
|
|
5
5
|
import { DiagnosticReportClaim } from '../models/interoperable-claims/diagnostic-report-claims.js';
|
|
6
6
|
import { MedicationStatementClaim } from '../models/interoperable-claims/medication-statement-claims.js';
|
|
7
7
|
import { ClaimConsent } from '../models/consent-rule.js';
|
|
8
|
-
import { allergyIntoleranceFlatToFhirR4, appointmentFlatToFhirR4, carePlanFlatToFhirR4, clinicalImpressionFlatToFhirR4, compositionFlatToFhirR4, conditionFlatToFhirR4, consentFlatToFhirR4, convertFhirResourceToClaims, coverageFlatToFhirR4, deviceFlatToFhirR4, documentReferenceFlatToFhirR4, diagnosticReportFlatToFhirR4, encounterFlatToFhirR4, flagFlatToFhirR4, flatClaimsToFhirResource, immunizationFlatToFhirR4, locationFlatToFhirR4, medicationStatementFlatToFhirR4, observationFromFlatToFhirR4, organizationFlatToFhirR4, procedureFlatToFhirR4, practitionerRoleFlatToFhirR4, relatedPersonFlatToFhirR4, } from './clinical-resource-converters.js';
|
|
8
|
+
import { allergyIntoleranceFlatToFhirR4, appointmentResponseFlatToFhirR4, appointmentFlatToFhirR4, carePlanFlatToFhirR4, clinicalImpressionFlatToFhirR4, compositionFlatToFhirR4, conditionFlatToFhirR4, consentFlatToFhirR4, convertFhirResourceToClaims, coverageFlatToFhirR4, deviceFlatToFhirR4, deviceUseStatementFlatToFhirR4, documentReferenceFlatToFhirR4, diagnosticReportFlatToFhirR4, encounterFlatToFhirR4, flagFlatToFhirR4, flatClaimsToFhirResource, immunizationFlatToFhirR4, locationFlatToFhirR4, medicationStatementFlatToFhirR4, observationFromFlatToFhirR4, organizationFlatToFhirR4, procedureFlatToFhirR4, practitionerRoleFlatToFhirR4, relatedPersonFlatToFhirR4, } from './clinical-resource-converters.js';
|
|
9
|
+
/** Version-independent FHIR SearchParameter claim context. */
|
|
10
|
+
const FHIR_API_CLAIMS_CONTEXT = 'org.hl7.fhir.api';
|
|
9
11
|
function asTrimmedString(value) {
|
|
10
12
|
if (value === undefined || value === null)
|
|
11
13
|
return '';
|
|
@@ -22,8 +24,7 @@ export function getSimpleClaimAttributeName(key) {
|
|
|
22
24
|
if (!value)
|
|
23
25
|
return '';
|
|
24
26
|
const knownPrefixes = [
|
|
25
|
-
|
|
26
|
-
'org.hl7.fhir.api.',
|
|
27
|
+
`${FHIR_API_CLAIMS_CONTEXT}.`,
|
|
27
28
|
];
|
|
28
29
|
for (const prefix of knownPrefixes) {
|
|
29
30
|
if (value.startsWith(prefix)) {
|
|
@@ -39,19 +40,13 @@ export function extractFlatClaimValue(record, key) {
|
|
|
39
40
|
const direct = record[normalizedKey];
|
|
40
41
|
if (typeof direct === 'string' && direct.trim())
|
|
41
42
|
return direct.trim();
|
|
42
|
-
const
|
|
43
|
-
if (typeof contextualizedR4 === 'string' && contextualizedR4.trim())
|
|
44
|
-
return contextualizedR4.trim();
|
|
45
|
-
const contextualizedApi = record[`org.hl7.fhir.api.${normalizedKey}`];
|
|
43
|
+
const contextualizedApi = record[`${FHIR_API_CLAIMS_CONTEXT}.${normalizedKey}`];
|
|
46
44
|
if (typeof contextualizedApi === 'string' && contextualizedApi.trim())
|
|
47
45
|
return contextualizedApi.trim();
|
|
48
46
|
const nested = record?.meta?.claims?.[normalizedKey];
|
|
49
47
|
if (typeof nested === 'string' && nested.trim())
|
|
50
48
|
return nested.trim();
|
|
51
|
-
const
|
|
52
|
-
if (typeof nestedR4 === 'string' && nestedR4.trim())
|
|
53
|
-
return nestedR4.trim();
|
|
54
|
-
const nestedApi = record?.meta?.claims?.[`org.hl7.fhir.api.${normalizedKey}`];
|
|
49
|
+
const nestedApi = record?.meta?.claims?.[`${FHIR_API_CLAIMS_CONTEXT}.${normalizedKey}`];
|
|
55
50
|
if (typeof nestedApi === 'string' && nestedApi.trim())
|
|
56
51
|
return nestedApi.trim();
|
|
57
52
|
return '';
|
|
@@ -59,12 +54,33 @@ export function extractFlatClaimValue(record, key) {
|
|
|
59
54
|
function claimsToFlatStrings(claims) {
|
|
60
55
|
const out = {};
|
|
61
56
|
for (const [key, value] of Object.entries(claims || {})) {
|
|
62
|
-
if (value === undefined || value === null)
|
|
57
|
+
if (value === undefined || value === null || key === '@context')
|
|
58
|
+
continue;
|
|
59
|
+
const canonicalKey = getSimpleClaimAttributeName(key);
|
|
60
|
+
if (canonicalKey === key)
|
|
61
|
+
continue;
|
|
62
|
+
out[canonicalKey] = typeof value === 'string' ? value : String(value);
|
|
63
|
+
}
|
|
64
|
+
for (const [key, value] of Object.entries(claims || {})) {
|
|
65
|
+
if (value === undefined || value === null || key === '@context')
|
|
66
|
+
continue;
|
|
67
|
+
const canonicalKey = getSimpleClaimAttributeName(key);
|
|
68
|
+
if (canonicalKey !== key)
|
|
63
69
|
continue;
|
|
64
70
|
out[key] = typeof value === 'string' ? value : String(value);
|
|
65
71
|
}
|
|
66
72
|
return out;
|
|
67
73
|
}
|
|
74
|
+
/** Rejects version-specific FHIR resource contexts from the claims contract. */
|
|
75
|
+
function assertFhirApiClaimsContext(claims) {
|
|
76
|
+
const context = asTrimmedString(claims?.['@context']);
|
|
77
|
+
const hasVersionSpecificContext = context.startsWith('org.hl7.fhir.')
|
|
78
|
+
&& context !== FHIR_API_CLAIMS_CONTEXT;
|
|
79
|
+
const hasVersionSpecificExpandedKey = Object.keys(claims || {}).some((key) => key.startsWith('org.hl7.fhir.') && !key.startsWith(`${FHIR_API_CLAIMS_CONTEXT}.`));
|
|
80
|
+
if (hasVersionSpecificContext || hasVersionSpecificExpandedKey) {
|
|
81
|
+
throw new Error(`FHIR claims require @context ${FHIR_API_CLAIMS_CONTEXT}. Version-specific FHIR resource contexts are not claim namespaces.`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
68
84
|
function ensureClaimsIdentifier(claims, resource) {
|
|
69
85
|
const resourceType = asTrimmedString(resource?.resourceType);
|
|
70
86
|
const identifierKey = resourceType ? `${resourceType}.identifier` : '';
|
|
@@ -202,7 +218,7 @@ export function prepareBundleDocumentForSubject(bundle, subjectDid, options = {}
|
|
|
202
218
|
if (!resource || typeof resource !== 'object')
|
|
203
219
|
continue;
|
|
204
220
|
replacePatientSubjectReference(resource, normalizedSubjectDid);
|
|
205
|
-
const generated = convertFhirResourceToClaims(resource, options.context ||
|
|
221
|
+
const generated = convertFhirResourceToClaims(resource, options.context || FHIR_API_CLAIMS_CONTEXT);
|
|
206
222
|
const existing = resource?.meta?.claims;
|
|
207
223
|
const claims = {
|
|
208
224
|
...generated,
|
|
@@ -324,7 +340,7 @@ export function detectClaimsResourceType(claims) {
|
|
|
324
340
|
return ResourceTypesFhirR4.DocumentReference;
|
|
325
341
|
const firstContextualized = keys
|
|
326
342
|
.map((key) => getSimpleClaimAttributeName(key))
|
|
327
|
-
.find((key) => key.includes('.'));
|
|
343
|
+
.find((key) => key.includes('.') && !key.startsWith(`${ResourceTypesFhirR4.Composition}.`));
|
|
328
344
|
if (firstContextualized) {
|
|
329
345
|
return firstContextualized.split('.')[0];
|
|
330
346
|
}
|
|
@@ -332,10 +348,11 @@ export function detectClaimsResourceType(claims) {
|
|
|
332
348
|
}
|
|
333
349
|
export function convertClaimsToFhirResource(claims, version = 'r4') {
|
|
334
350
|
void version;
|
|
351
|
+
assertFhirApiClaimsContext(claims);
|
|
335
352
|
const flatClaims = claimsToFlatStrings(claims);
|
|
336
353
|
const resourceType = detectClaimsResourceType(claims);
|
|
337
354
|
const resource = convertClaimsToFhirResourceByType(flatClaims, resourceType);
|
|
338
|
-
const language = resourceType ? asTrimmedString(
|
|
355
|
+
const language = resourceType ? asTrimmedString(flatClaims[`${resourceType}.language`]) : '';
|
|
339
356
|
return language ? { ...resource, language } : resource;
|
|
340
357
|
}
|
|
341
358
|
function convertClaimsToFhirResourceByType(flatClaims, resourceType) {
|
|
@@ -348,6 +365,8 @@ function convertClaimsToFhirResourceByType(flatClaims, resourceType) {
|
|
|
348
365
|
return conditionFlatToFhirR4(flatClaims);
|
|
349
366
|
case ResourceTypesFhirR4.DocumentReference:
|
|
350
367
|
return documentReferenceFlatToFhirR4(flatClaims);
|
|
368
|
+
case ResourceTypesFhirR4.DeviceUseStatement:
|
|
369
|
+
return deviceUseStatementFlatToFhirR4(flatClaims);
|
|
351
370
|
case 'Immunization':
|
|
352
371
|
return immunizationFlatToFhirR4(flatClaims);
|
|
353
372
|
case 'Location':
|
|
@@ -370,6 +389,8 @@ function convertClaimsToFhirResourceByType(flatClaims, resourceType) {
|
|
|
370
389
|
return compositionFlatToFhirR4(flatClaims);
|
|
371
390
|
case 'Appointment':
|
|
372
391
|
return appointmentFlatToFhirR4(flatClaims);
|
|
392
|
+
case 'AppointmentResponse':
|
|
393
|
+
return appointmentResponseFlatToFhirR4(flatClaims);
|
|
373
394
|
case 'Encounter':
|
|
374
395
|
return encounterFlatToFhirR4(flatClaims);
|
|
375
396
|
case 'RelatedPerson':
|
|
@@ -397,7 +418,7 @@ function convertClaimsToFhirResourceByType(flatClaims, resourceType) {
|
|
|
397
418
|
* not yet part of the clinical claims-first pipeline:
|
|
398
419
|
* `Composition`, `Patient`, `Practitioner`, `PractitionerRole`.
|
|
399
420
|
*/
|
|
400
|
-
export function extractBundleDocumentClaimsList(bundle, context = 'org.hl7.fhir.
|
|
421
|
+
export function extractBundleDocumentClaimsList(bundle, context = 'org.hl7.fhir.api') {
|
|
401
422
|
const entries = Array.isArray(bundle?.entry) ? bundle.entry : [];
|
|
402
423
|
const ignoredResourceTypes = new Set([
|
|
403
424
|
ResourceTypesFhirR4.Composition,
|
|
@@ -75,6 +75,19 @@ export declare class BundleEntryEditor {
|
|
|
75
75
|
hasClaim(key: string): boolean;
|
|
76
76
|
/** Writes one claim on this entry. */
|
|
77
77
|
setClaim(key: string, value: unknown): this;
|
|
78
|
+
/**
|
|
79
|
+
* Writes one viewer/editor field using the canonical short FHIR API claim.
|
|
80
|
+
* Expanded `org.hl7.fhir.api.*` input is normalized; versioned FHIR claim
|
|
81
|
+
* namespaces and structural/camelCase paths are rejected.
|
|
82
|
+
*/
|
|
83
|
+
setFhirApiClaim(key: string, value: unknown): this;
|
|
84
|
+
/** Reads one short or expanded FHIR API claim through the canonical short key. */
|
|
85
|
+
getFhirApiClaim(key: string): unknown;
|
|
86
|
+
/** Applies a complete field collection returned by a clinical card view. */
|
|
87
|
+
setFhirApiClaimFields(fields: readonly Readonly<{
|
|
88
|
+
claim: string;
|
|
89
|
+
value: unknown;
|
|
90
|
+
}>[]): this;
|
|
78
91
|
/** Appends one claim value on this entry. */
|
|
79
92
|
addClaim(key: string, value: unknown): this;
|
|
80
93
|
/** Removes one claim from this entry. */
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { ResourceTypesFhirR4 } from '../constants/fhir-resource-types.js';
|
|
8
8
|
import { BundleEditableResourceTypes, } from '../models/bundle-editor-types.js';
|
|
9
|
+
import { normalizeFhirApiClaimKey } from './fhir-api-claim-helpers.js';
|
|
9
10
|
import { EmployeeResourceTypes, } from './employee.js';
|
|
10
11
|
import { cloneClaimValue, normalizeOptionalIdentifier } from './bundle-editor-helpers.js';
|
|
11
12
|
import { createRegisteredBundleEntryEditor } from './bundle-editor-registry.js';
|
|
@@ -241,6 +242,23 @@ export class BundleEntryEditor {
|
|
|
241
242
|
};
|
|
242
243
|
return this;
|
|
243
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* Writes one viewer/editor field using the canonical short FHIR API claim.
|
|
247
|
+
* Expanded `org.hl7.fhir.api.*` input is normalized; versioned FHIR claim
|
|
248
|
+
* namespaces and structural/camelCase paths are rejected.
|
|
249
|
+
*/
|
|
250
|
+
setFhirApiClaim(key, value) {
|
|
251
|
+
return this.setClaim(normalizeFhirApiClaimKey(key), value);
|
|
252
|
+
}
|
|
253
|
+
/** Reads one short or expanded FHIR API claim through the canonical short key. */
|
|
254
|
+
getFhirApiClaim(key) {
|
|
255
|
+
return this.getClaim(normalizeFhirApiClaimKey(key));
|
|
256
|
+
}
|
|
257
|
+
/** Applies a complete field collection returned by a clinical card view. */
|
|
258
|
+
setFhirApiClaimFields(fields) {
|
|
259
|
+
fields.forEach((field) => this.setFhirApiClaim(field.claim, field.value));
|
|
260
|
+
return this;
|
|
261
|
+
}
|
|
244
262
|
/** Appends one claim value on this entry. */
|
|
245
263
|
addClaim(key, value) {
|
|
246
264
|
const normalizedKey = String(key).trim();
|
|
@@ -99,12 +99,14 @@ export const practitionerRoleFhirToFlat = practitionerRoleFhirR4ToFlat;
|
|
|
99
99
|
* resource-specific converter exists. Unsupported resources fall back to the
|
|
100
100
|
* generic structural flattening.
|
|
101
101
|
*/
|
|
102
|
-
export function convertFhirResourceToClaims(resource, context = 'org.hl7.fhir.
|
|
102
|
+
export function convertFhirResourceToClaims(resource, context = 'org.hl7.fhir.api') {
|
|
103
103
|
const claims = convertFhirResourceToClaimsByType(resource, context);
|
|
104
104
|
const language = typeof resource.language === 'string' ? resource.language.trim() : '';
|
|
105
|
-
return
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
return {
|
|
106
|
+
'@context': context,
|
|
107
|
+
...claims,
|
|
108
|
+
...(language ? { [`${resource.resourceType}.language`]: language } : {}),
|
|
109
|
+
};
|
|
108
110
|
}
|
|
109
111
|
function convertFhirResourceToClaimsByType(resource, context) {
|
|
110
112
|
switch (resource.resourceType) {
|
|
@@ -20,9 +20,54 @@ export type ClinicalResourceCommonView = Readonly<{
|
|
|
20
20
|
export type ClinicalResourceCardView = Readonly<{
|
|
21
21
|
title: string;
|
|
22
22
|
resourceType: string;
|
|
23
|
+
/** Stable business identifier used to reconcile repeated readbacks. */
|
|
24
|
+
identifier?: string;
|
|
23
25
|
date?: string;
|
|
26
|
+
periodStart?: string;
|
|
27
|
+
periodEnd?: string;
|
|
24
28
|
fullUrl?: string;
|
|
25
29
|
actorsCount: number;
|
|
30
|
+
/** Resource status resolved from canonical claims first, then native FHIR. */
|
|
31
|
+
status?: string;
|
|
32
|
+
/** Observation scalar value for result cards. */
|
|
33
|
+
value?: string | number;
|
|
34
|
+
/** Observation quantity unit for result cards. */
|
|
35
|
+
unit?: string;
|
|
36
|
+
/** Immunization lot number. */
|
|
37
|
+
lotNumber?: string;
|
|
38
|
+
/** Immunization dose sequence. */
|
|
39
|
+
doseSequence?: string;
|
|
40
|
+
/** AllergyIntolerance criticality. */
|
|
41
|
+
criticality?: string;
|
|
42
|
+
/** AllergyIntolerance onset date/time. */
|
|
43
|
+
onsetDateTime?: string;
|
|
44
|
+
/** MedicationStatement human-readable dosage instruction. */
|
|
45
|
+
dosageInstruction?: string;
|
|
46
|
+
category?: string;
|
|
47
|
+
severity?: string;
|
|
48
|
+
recordedDate?: string;
|
|
49
|
+
source?: string;
|
|
50
|
+
route?: string;
|
|
51
|
+
site?: string;
|
|
52
|
+
doseQuantityValue?: number;
|
|
53
|
+
doseQuantityUnit?: string;
|
|
54
|
+
referenceRangeText?: string;
|
|
55
|
+
description?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Complete editable field surface resolved from `resource.meta.claims`.
|
|
58
|
+
*
|
|
59
|
+
* `claim` always uses the short, version-independent FHIR API form
|
|
60
|
+
* (`<ResourceType>.<search-param>`). Consumers can therefore render and
|
|
61
|
+
* hydrate fields that do not yet have a dedicated card convenience member.
|
|
62
|
+
*/
|
|
63
|
+
fields: readonly ClinicalResourceClaimFieldView[];
|
|
64
|
+
}>;
|
|
65
|
+
export type ClinicalResourceClaimFieldView = Readonly<{
|
|
66
|
+
/** Canonical short FHIR API claim, for example `Immunization.lot-number`. */
|
|
67
|
+
claim: string;
|
|
68
|
+
/** Concrete FHIR API SearchParameter name, for example `lot-number`. */
|
|
69
|
+
parameter: string;
|
|
70
|
+
value: unknown;
|
|
26
71
|
}>;
|
|
27
72
|
export type ClinicalTerminologyTranslationInput = Readonly<{
|
|
28
73
|
resourceType: string;
|
|
@@ -110,6 +155,16 @@ export declare function toClinicalResourceCommonViews(bundle: ClinicalResourceBu
|
|
|
110
155
|
* Maps one bundle entry to a minimal card view for section counters/list cards.
|
|
111
156
|
*/
|
|
112
157
|
export declare function toClinicalResourceCardView(entry: ClinicalResourceEntryLike, options?: ClinicalResourceDisplayOptions): ClinicalResourceCardView;
|
|
158
|
+
/**
|
|
159
|
+
* Normalizes all clinical `meta.claims` into the short FHIR API vocabulary
|
|
160
|
+
* consumed by generic clinical viewers and editors.
|
|
161
|
+
*
|
|
162
|
+
* Short claims take precedence over their expanded
|
|
163
|
+
* `org.hl7.fhir.api.<ResourceType>.<search-param>` equivalent. Versioned
|
|
164
|
+
* `org.hl7.fhir.<version>.*` namespaces are rejected because they are native
|
|
165
|
+
* FHIR representation namespaces, never claims vocabularies.
|
|
166
|
+
*/
|
|
167
|
+
export declare function toClinicalResourceClaimFieldViews(claims: ClinicalViewClaims): ClinicalResourceClaimFieldView[];
|
|
113
168
|
/**
|
|
114
169
|
* Maps all entries from a Bundle into minimal card views.
|
|
115
170
|
*/
|
|
@@ -14,6 +14,7 @@ import { MedicationStatementClaim, MedicationStatementClaimsFhirApi, MedicationS
|
|
|
14
14
|
import { ObservationClaim } from '../models/interoperable-claims/observation-claims.js';
|
|
15
15
|
import { PractitionerRoleClaim } from '../models/interoperable-claims/practitioner-role-claims.js';
|
|
16
16
|
import { ProcedureClaim } from '../models/interoperable-claims/procedure-claims.js';
|
|
17
|
+
import { normalizeFhirApiClaimKey } from './fhir-api-claim-helpers.js';
|
|
17
18
|
const CONSENT_ACTOR_REFERENCE_CLAIM = 'Consent.actor-reference';
|
|
18
19
|
const GENERIC_CREATOR_CLAIM_SUFFIX = '.creator';
|
|
19
20
|
const GENERIC_PERFORMER_CLAIM_SUFFIX = '.performer';
|
|
@@ -49,14 +50,112 @@ export function toClinicalResourceCommonViews(bundle, options = {}) {
|
|
|
49
50
|
*/
|
|
50
51
|
export function toClinicalResourceCardView(entry, options = {}) {
|
|
51
52
|
const common = toClinicalResourceCommonView(entry, options);
|
|
53
|
+
const resource = entry.resource;
|
|
54
|
+
const status = resolveCardStatus(common.resourceType, common.claims, resource);
|
|
55
|
+
const value = resolveCardValue(common.resourceType, common.claims, resource);
|
|
56
|
+
const unit = resolveCardUnit(common.resourceType, common.claims, resource);
|
|
57
|
+
const lotNumber = readCanonicalClaimValue(common.claims, ImmunizationClaim.LotNumber)
|
|
58
|
+
|| trimValue(resource?.lotNumber);
|
|
59
|
+
const doseSequence = readCanonicalClaimValue(common.claims, ImmunizationClaim.DoseSequence)
|
|
60
|
+
|| trimValue(asRecord(asArray(resource?.protocolApplied)[0]).doseNumberString);
|
|
61
|
+
const criticality = readCanonicalClaimValue(common.claims, AllergyIntoleranceClaim.Criticality)
|
|
62
|
+
|| trimValue(resource?.criticality);
|
|
63
|
+
const onsetDateTime = readCanonicalClaimValue(common.claims, AllergyIntoleranceClaim.OnsetDateTime)
|
|
64
|
+
|| trimValue(resource?.onsetDateTime);
|
|
65
|
+
const dosageInstruction = readCanonicalClaimValue(common.claims, MedicationStatementClaim.DosageInstruction)
|
|
66
|
+
|| trimValue(asRecord(asArray(resource?.dosage)[0]).text);
|
|
67
|
+
const fields = toClinicalResourceClaimFieldViews(common.claims);
|
|
68
|
+
const category = readCanonicalClaimValue(common.claims, `${common.resourceType}.category`);
|
|
69
|
+
const severity = readCanonicalClaimValue(common.claims, `${common.resourceType}.severity`);
|
|
70
|
+
const recordedDate = readCanonicalClaimValue(common.claims, ConditionClaim.RecordedDate);
|
|
71
|
+
const source = readCanonicalClaimValue(common.claims, MedicationStatementClaim.Source);
|
|
72
|
+
const route = readCanonicalClaimValue(common.claims, ImmunizationClaim.Route);
|
|
73
|
+
const site = readCanonicalClaimValue(common.claims, ImmunizationClaim.Site);
|
|
74
|
+
const doseQuantityValueRaw = readCanonicalClaimValue(common.claims, MedicationStatementClaim.DoseQuantityValue);
|
|
75
|
+
const doseQuantityValue = doseQuantityValueRaw === undefined ? undefined : Number(doseQuantityValueRaw);
|
|
76
|
+
const doseQuantityUnit = readCanonicalClaimValue(common.claims, MedicationStatementClaim.DoseQuantityUnit);
|
|
77
|
+
const referenceRangeText = readCanonicalClaimValue(common.claims, ObservationClaim.ReferenceRangeText);
|
|
78
|
+
const description = readCanonicalClaimValue(common.claims, CarePlanClaim.Description);
|
|
52
79
|
return {
|
|
53
80
|
title: common.title,
|
|
54
81
|
resourceType: common.resourceType,
|
|
82
|
+
...(common.identifier ? { identifier: common.identifier } : {}),
|
|
55
83
|
date: common.date,
|
|
84
|
+
...(common.periodStart ? { periodStart: common.periodStart } : {}),
|
|
85
|
+
...(common.periodEnd ? { periodEnd: common.periodEnd } : {}),
|
|
56
86
|
fullUrl: common.fullUrl,
|
|
57
87
|
actorsCount: common.actors.length,
|
|
88
|
+
fields,
|
|
89
|
+
...(status ? { status } : {}),
|
|
90
|
+
...(value !== undefined ? { value } : {}),
|
|
91
|
+
...(unit ? { unit } : {}),
|
|
92
|
+
...(lotNumber ? { lotNumber } : {}),
|
|
93
|
+
...(doseSequence ? { doseSequence } : {}),
|
|
94
|
+
...(criticality ? { criticality } : {}),
|
|
95
|
+
...(onsetDateTime ? { onsetDateTime } : {}),
|
|
96
|
+
...(dosageInstruction ? { dosageInstruction } : {}),
|
|
97
|
+
...(category ? { category } : {}),
|
|
98
|
+
...(severity ? { severity } : {}),
|
|
99
|
+
...(recordedDate ? { recordedDate } : {}),
|
|
100
|
+
...(source ? { source } : {}),
|
|
101
|
+
...(route ? { route } : {}),
|
|
102
|
+
...(site ? { site } : {}),
|
|
103
|
+
...(doseQuantityValue !== undefined && Number.isFinite(doseQuantityValue) ? { doseQuantityValue } : {}),
|
|
104
|
+
...(doseQuantityUnit ? { doseQuantityUnit } : {}),
|
|
105
|
+
...(referenceRangeText ? { referenceRangeText } : {}),
|
|
106
|
+
...(description ? { description } : {}),
|
|
58
107
|
};
|
|
59
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Normalizes all clinical `meta.claims` into the short FHIR API vocabulary
|
|
111
|
+
* consumed by generic clinical viewers and editors.
|
|
112
|
+
*
|
|
113
|
+
* Short claims take precedence over their expanded
|
|
114
|
+
* `org.hl7.fhir.api.<ResourceType>.<search-param>` equivalent. Versioned
|
|
115
|
+
* `org.hl7.fhir.<version>.*` namespaces are rejected because they are native
|
|
116
|
+
* FHIR representation namespaces, never claims vocabularies.
|
|
117
|
+
*/
|
|
118
|
+
export function toClinicalResourceClaimFieldViews(claims) {
|
|
119
|
+
const fields = new Map();
|
|
120
|
+
const entries = Object.entries(claims || {});
|
|
121
|
+
for (const [rawClaim, value] of entries) {
|
|
122
|
+
if (rawClaim.startsWith('@') || value === undefined)
|
|
123
|
+
continue;
|
|
124
|
+
if (rawClaim.startsWith('org.hl7.fhir.') && !rawClaim.startsWith('org.hl7.fhir.api.')) {
|
|
125
|
+
throw new Error(`FHIR meta.claims must use org.hl7.fhir.api, not version-specific key: ${rawClaim}`);
|
|
126
|
+
}
|
|
127
|
+
if (!rawClaim.startsWith('org.hl7.fhir.api.') && !/^[A-Z][A-Za-z0-9]+\./.test(rawClaim))
|
|
128
|
+
continue;
|
|
129
|
+
const claim = normalizeFhirApiClaimKey(rawClaim);
|
|
130
|
+
const separator = claim.indexOf('.');
|
|
131
|
+
if (separator <= 0 || separator === claim.length - 1)
|
|
132
|
+
continue;
|
|
133
|
+
if (!fields.has(claim)) {
|
|
134
|
+
fields.set(claim, {
|
|
135
|
+
claim,
|
|
136
|
+
parameter: claim.slice(separator + 1),
|
|
137
|
+
value,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Apply canonical short keys last so they win over expanded aliases even
|
|
142
|
+
// when the expanded property appeared later in insertion order.
|
|
143
|
+
for (const [claim, value] of entries) {
|
|
144
|
+
if (claim.startsWith('@') || claim.startsWith('org.hl7.fhir.') || value === undefined)
|
|
145
|
+
continue;
|
|
146
|
+
if (!/^[A-Z][A-Za-z0-9]+\./.test(claim))
|
|
147
|
+
continue;
|
|
148
|
+
const separator = claim.indexOf('.');
|
|
149
|
+
if (separator <= 0 || separator === claim.length - 1)
|
|
150
|
+
continue;
|
|
151
|
+
fields.set(claim, {
|
|
152
|
+
claim,
|
|
153
|
+
parameter: claim.slice(separator + 1),
|
|
154
|
+
value,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return [...fields.values()].sort((left, right) => left.claim.localeCompare(right.claim));
|
|
158
|
+
}
|
|
60
159
|
/**
|
|
61
160
|
* Maps all entries from a Bundle into minimal card views.
|
|
62
161
|
*/
|
|
@@ -196,6 +295,42 @@ export function getNarrative(resource) {
|
|
|
196
295
|
source: 'derived-from-claims',
|
|
197
296
|
};
|
|
198
297
|
}
|
|
298
|
+
function resolveCardStatus(resourceType, claims, resource) {
|
|
299
|
+
const claimsStatus = resourceType === ResourceTypesFhirR4.AllergyIntolerance
|
|
300
|
+
? readCanonicalClaimValue(claims, AllergyIntoleranceClaim.ClinicalStatus)
|
|
301
|
+
: readCanonicalClaimValue(claims, `${resourceType}.status`);
|
|
302
|
+
if (claimsStatus)
|
|
303
|
+
return claimsStatus;
|
|
304
|
+
const nativeStatus = trimValue(resource?.status);
|
|
305
|
+
if (nativeStatus)
|
|
306
|
+
return nativeStatus;
|
|
307
|
+
return trimValue(asRecord(asArray(asRecord(resource?.clinicalStatus).coding)[0]).code) || undefined;
|
|
308
|
+
}
|
|
309
|
+
function resolveCardValue(resourceType, claims, resource) {
|
|
310
|
+
if (resourceType !== ResourceTypesFhirR4.Observation)
|
|
311
|
+
return undefined;
|
|
312
|
+
const claimNumber = readCanonicalClaimValue(claims, ObservationClaim.ValueQuantityNumber);
|
|
313
|
+
if (claimNumber !== undefined) {
|
|
314
|
+
const numeric = Number(claimNumber);
|
|
315
|
+
if (Number.isFinite(numeric))
|
|
316
|
+
return numeric;
|
|
317
|
+
}
|
|
318
|
+
const claimString = readCanonicalClaimValue(claims, ObservationClaim.ValueString);
|
|
319
|
+
if (claimString)
|
|
320
|
+
return claimString;
|
|
321
|
+
const nativeNumber = asRecord(resource?.valueQuantity).value;
|
|
322
|
+
if (typeof nativeNumber === 'number' && Number.isFinite(nativeNumber))
|
|
323
|
+
return nativeNumber;
|
|
324
|
+
return trimValue(resource?.valueString) || undefined;
|
|
325
|
+
}
|
|
326
|
+
function resolveCardUnit(resourceType, claims, resource) {
|
|
327
|
+
if (resourceType !== ResourceTypesFhirR4.Observation)
|
|
328
|
+
return undefined;
|
|
329
|
+
return readCanonicalClaimValue(claims, ObservationClaim.ValueQuantityUnit)
|
|
330
|
+
|| trimValue(asRecord(resource?.valueQuantity).unit)
|
|
331
|
+
|| trimValue(asRecord(resource?.valueQuantity).code)
|
|
332
|
+
|| undefined;
|
|
333
|
+
}
|
|
199
334
|
function readClaims(entry) {
|
|
200
335
|
const resourceClaims = asRecord(entry?.resource?.meta?.claims);
|
|
201
336
|
const legacyClaims = asRecord(entry?.meta?.claims);
|
|
@@ -397,7 +532,8 @@ function resolveIdentifier(resourceType, claims, resource) {
|
|
|
397
532
|
AllergyIntoleranceClaimsFhirApi.Identifier,
|
|
398
533
|
]) || resolveFhirIdentifier(resource);
|
|
399
534
|
}
|
|
400
|
-
return
|
|
535
|
+
return readCanonicalClaimValue(claims, `${resourceType}.identifier`)
|
|
536
|
+
|| resolveFhirIdentifier(resource);
|
|
401
537
|
}
|
|
402
538
|
function resolveDate(resourceType, claims, resource) {
|
|
403
539
|
if (resourceType === ResourceTypesFhirR4.Communication) {
|
|
@@ -67,7 +67,7 @@ export function buildBundleDocumentRequestCommunicationClaims(input) {
|
|
|
67
67
|
: `Request ${documentTypeDescriptor.id} Bundle search with sections: ${sections.join(', ')}`)).trim();
|
|
68
68
|
const noteText = String(input.noteText || text).trim();
|
|
69
69
|
const claims = {
|
|
70
|
-
'@context': 'org.hl7.fhir.
|
|
70
|
+
'@context': 'org.hl7.fhir.api',
|
|
71
71
|
[CommunicationClaim.Identifier]: communicationIdentifier,
|
|
72
72
|
[CommunicationClaim.Status]: String(input.status || 'completed').trim(),
|
|
73
73
|
[CommunicationClaim.Category]: CommunicationCategoryCodes.Notification.claim,
|
|
@@ -121,7 +121,7 @@ export function extractCommunicationClaimsFromResourceFhirR4(resource, options =
|
|
|
121
121
|
return { ...existingClaims };
|
|
122
122
|
}
|
|
123
123
|
const claims = {};
|
|
124
|
-
claims['@context'] = 'org.hl7.fhir.
|
|
124
|
+
claims['@context'] = 'org.hl7.fhir.api';
|
|
125
125
|
const identifierValue = resource?.identifier?.[0]?.value;
|
|
126
126
|
const status = resource?.status;
|
|
127
127
|
const sent = resource?.sent;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
const FHIR_API_PREFIX = 'org.hl7.fhir.api.';
|
|
3
|
+
const FHIR_VERSIONED_PREFIX = 'org.hl7.fhir.';
|
|
4
|
+
const SHORT_FHIR_API_CLAIM = /^[A-Z][A-Za-z0-9]+\.[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
5
|
+
/** Returns the canonical short FHIR API claim or throws for another vocabulary. */
|
|
6
|
+
export function normalizeFhirApiClaimKey(claimKey) {
|
|
7
|
+
const raw = String(claimKey || '').trim();
|
|
8
|
+
if (raw.startsWith(FHIR_VERSIONED_PREFIX) && !raw.startsWith(FHIR_API_PREFIX)) {
|
|
9
|
+
throw new Error(`FHIR claims must use org.hl7.fhir.api, not version-specific key: ${raw}`);
|
|
10
|
+
}
|
|
11
|
+
const normalized = raw.startsWith(FHIR_API_PREFIX) ? raw.slice(FHIR_API_PREFIX.length) : raw;
|
|
12
|
+
if (!SHORT_FHIR_API_CLAIM.test(normalized)) {
|
|
13
|
+
throw new Error(`Invalid FHIR API claim key: ${raw}`);
|
|
14
|
+
}
|
|
15
|
+
return normalized;
|
|
16
|
+
}
|