gdc-common-utils-ts 2.8.2 → 2.8.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants/healthcare.d.ts +5 -3
- package/dist/constants/healthcare.js +16 -0
- package/dist/utils/clinical-resource-replacement.d.ts +34 -0
- package/dist/utils/clinical-resource-replacement.js +83 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +1 -1
|
@@ -1727,6 +1727,7 @@ export declare const HealthcareActorRoles: Readonly<{
|
|
|
1727
1727
|
readonly MidwiferyProfessional: "ISCO-08|2222";
|
|
1728
1728
|
readonly Paramedic: "ISCO-08|2240";
|
|
1729
1729
|
readonly Veterinarian: "ISCO-08|2250";
|
|
1730
|
+
readonly VeterinaryTechnicianOrAssistant: "ISCO-08|3240";
|
|
1730
1731
|
/** Administrative health occupation; it does not imply clinical authority. */
|
|
1731
1732
|
readonly MedicalSecretary: "ISCO-08|3344";
|
|
1732
1733
|
}>;
|
|
@@ -1749,6 +1750,7 @@ export declare const HealthcareActorRoleCodes: Readonly<{
|
|
|
1749
1750
|
readonly MidwiferyProfessional: "2222";
|
|
1750
1751
|
readonly Paramedic: "2240";
|
|
1751
1752
|
readonly Veterinarian: "2250";
|
|
1753
|
+
readonly VeterinaryTechnicianOrAssistant: "3240";
|
|
1752
1754
|
readonly MedicalSecretary: "3344";
|
|
1753
1755
|
}>;
|
|
1754
1756
|
export declare const HealthcareRolesByFamily: Readonly<{
|
|
@@ -1786,11 +1788,11 @@ export declare const HealthcareProfessionalRoleCodesBySector: Readonly<{
|
|
|
1786
1788
|
readonly "health-research": readonly ("RESPRSN" | "221" | "2211" | "2212" | "3344")[];
|
|
1787
1789
|
readonly "health-tech": readonly "RESPRSN"[];
|
|
1788
1790
|
readonly "health-insurance": readonly "RESPRSN"[];
|
|
1789
|
-
readonly "animal-care": readonly ("RESPRSN" | "2250")[];
|
|
1790
|
-
readonly "animal-research": readonly ("RESPRSN" | "2250")[];
|
|
1791
|
+
readonly "animal-care": readonly ("RESPRSN" | "2250" | "3240")[];
|
|
1792
|
+
readonly "animal-research": readonly ("RESPRSN" | "2250" | "3240")[];
|
|
1791
1793
|
readonly "animal-insurance": readonly "RESPRSN"[];
|
|
1792
1794
|
readonly "animal-tech": readonly "RESPRSN"[];
|
|
1793
|
-
readonly "onehealth-research": readonly ("RESPRSN" | "221" | "2211" | "2212" | "2250" | "3344")[];
|
|
1795
|
+
readonly "onehealth-research": readonly ("RESPRSN" | "221" | "2211" | "2212" | "2250" | "3240" | "3344")[];
|
|
1794
1796
|
readonly "onehealth-tech": readonly "RESPRSN"[];
|
|
1795
1797
|
}>;
|
|
1796
1798
|
export declare const HealthcareProfessionalRolesBySector: Readonly<{
|
|
@@ -359,6 +359,7 @@ export const HealthcareActorRoles = Object.freeze({
|
|
|
359
359
|
MidwiferyProfessional: 'ISCO-08|2222',
|
|
360
360
|
Paramedic: 'ISCO-08|2240',
|
|
361
361
|
Veterinarian: 'ISCO-08|2250',
|
|
362
|
+
VeterinaryTechnicianOrAssistant: 'ISCO-08|3240',
|
|
362
363
|
/** Administrative health occupation; it does not imply clinical authority. */
|
|
363
364
|
MedicalSecretary: 'ISCO-08|3344',
|
|
364
365
|
});
|
|
@@ -381,6 +382,7 @@ export const HealthcareActorRoleCodes = Object.freeze({
|
|
|
381
382
|
MidwiferyProfessional: '2222',
|
|
382
383
|
Paramedic: '2240',
|
|
383
384
|
Veterinarian: '2250',
|
|
385
|
+
VeterinaryTechnicianOrAssistant: '3240',
|
|
384
386
|
MedicalSecretary: '3344',
|
|
385
387
|
});
|
|
386
388
|
function buildProfessionalIscoRoles() {
|
|
@@ -462,6 +464,17 @@ function buildProfessionalIscoRoles() {
|
|
|
462
464
|
titleEn: 'Veterinarian',
|
|
463
465
|
}),
|
|
464
466
|
],
|
|
467
|
+
[
|
|
468
|
+
HealthcareActorRoleCodes.VeterinaryTechnicianOrAssistant,
|
|
469
|
+
Object.freeze({
|
|
470
|
+
family: HealthcareRoleFamilies.ProfessionalOccupationIsco08,
|
|
471
|
+
codingSystem: ISCO08_CODING_SYSTEM,
|
|
472
|
+
code: HealthcareActorRoleCodes.VeterinaryTechnicianOrAssistant,
|
|
473
|
+
claim: HealthcareActorRoles.VeterinaryTechnicianOrAssistant,
|
|
474
|
+
i18nKey: `${ISCO08_I18N_NAMESPACE}.${HealthcareActorRoleCodes.VeterinaryTechnicianOrAssistant}`,
|
|
475
|
+
titleEn: 'Veterinary technician or assistant',
|
|
476
|
+
}),
|
|
477
|
+
],
|
|
465
478
|
[
|
|
466
479
|
HealthcareActorRoleCodes.MedicalSecretary,
|
|
467
480
|
Object.freeze({
|
|
@@ -553,10 +566,12 @@ export const HealthcareProfessionalRoleCodesBySector = Object.freeze({
|
|
|
553
566
|
[DataspaceSectors.AnimalCare]: Object.freeze([
|
|
554
567
|
HealthcareActorRoleCodes.Controller,
|
|
555
568
|
HealthcareActorRoleCodes.Veterinarian,
|
|
569
|
+
HealthcareActorRoleCodes.VeterinaryTechnicianOrAssistant,
|
|
556
570
|
]),
|
|
557
571
|
[DataspaceSectors.AnimalResearch]: Object.freeze([
|
|
558
572
|
HealthcareActorRoleCodes.Controller,
|
|
559
573
|
HealthcareActorRoleCodes.Veterinarian,
|
|
574
|
+
HealthcareActorRoleCodes.VeterinaryTechnicianOrAssistant,
|
|
560
575
|
]),
|
|
561
576
|
[DataspaceSectors.AnimalInsurance]: Object.freeze([HealthcareActorRoleCodes.Controller]),
|
|
562
577
|
[DataspaceSectors.AnimalTech]: Object.freeze([HealthcareActorRoleCodes.Controller]),
|
|
@@ -566,6 +581,7 @@ export const HealthcareProfessionalRoleCodesBySector = Object.freeze({
|
|
|
566
581
|
HealthcareActorRoleCodes.GeneralistMedicalPractitioner,
|
|
567
582
|
HealthcareActorRoleCodes.SpecialistMedicalPractitioner,
|
|
568
583
|
HealthcareActorRoleCodes.Veterinarian,
|
|
584
|
+
HealthcareActorRoleCodes.VeterinaryTechnicianOrAssistant,
|
|
569
585
|
HealthcareActorRoleCodes.MedicalSecretary,
|
|
570
586
|
]),
|
|
571
587
|
[DataspaceSectors.OneHealthTech]: Object.freeze([HealthcareActorRoleCodes.Controller]),
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export declare const ClinicalResourceReplacementDecision: Readonly<{
|
|
2
|
+
readonly AllowOrganizationSuccessor: "allow-organization-successor";
|
|
3
|
+
readonly Deny: "deny";
|
|
4
|
+
}>;
|
|
5
|
+
export type ClinicalResourceReplacementDecisionValue = typeof ClinicalResourceReplacementDecision[keyof typeof ClinicalResourceReplacementDecision];
|
|
6
|
+
export type ClinicalResourceVersionIdentity = Readonly<{
|
|
7
|
+
resourceId: string;
|
|
8
|
+
authorOwnerIdentifier: string;
|
|
9
|
+
documentDate: string;
|
|
10
|
+
}>;
|
|
11
|
+
export type ClinicalDocumentAuthorOrganization = Readonly<{
|
|
12
|
+
authorReference: string;
|
|
13
|
+
organizationReference: string;
|
|
14
|
+
documentDate: string;
|
|
15
|
+
}>;
|
|
16
|
+
/**
|
|
17
|
+
* Resolves document ownership from the FHIR graph carried by an IPS Bundle.
|
|
18
|
+
* A Composition may name its Organization directly or name a PractitionerRole
|
|
19
|
+
* whose `organization` reference names it. Custodian is a compatibility
|
|
20
|
+
* fallback only when the author is a Practitioner represented without a
|
|
21
|
+
* PractitionerRole organization link.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveClinicalDocumentAuthorOrganization(bundle: unknown): ClinicalDocumentAuthorOrganization | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Evaluates the narrow provenance-preserving replacement exception.
|
|
26
|
+
*
|
|
27
|
+
* This does not authorize an actor or a delete. Gateways call it only after
|
|
28
|
+
* authenticating the sender and resolving both document authors to their
|
|
29
|
+
* registered owning organizations.
|
|
30
|
+
*/
|
|
31
|
+
export declare function evaluateClinicalResourceReplacement(input: Readonly<{
|
|
32
|
+
existing: ClinicalResourceVersionIdentity;
|
|
33
|
+
incoming: ClinicalResourceVersionIdentity;
|
|
34
|
+
}>): ClinicalResourceReplacementDecisionValue;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
export const ClinicalResourceReplacementDecision = Object.freeze({
|
|
2
|
+
AllowOrganizationSuccessor: 'allow-organization-successor',
|
|
3
|
+
Deny: 'deny',
|
|
4
|
+
});
|
|
5
|
+
function cleanReference(value) {
|
|
6
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
7
|
+
}
|
|
8
|
+
function resourceReference(resource) {
|
|
9
|
+
const resourceType = cleanReference(resource?.resourceType);
|
|
10
|
+
const id = cleanReference(resource?.id);
|
|
11
|
+
return resourceType && id ? `${resourceType}/${id}` : '';
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolves document ownership from the FHIR graph carried by an IPS Bundle.
|
|
15
|
+
* A Composition may name its Organization directly or name a PractitionerRole
|
|
16
|
+
* whose `organization` reference names it. Custodian is a compatibility
|
|
17
|
+
* fallback only when the author is a Practitioner represented without a
|
|
18
|
+
* PractitionerRole organization link.
|
|
19
|
+
*/
|
|
20
|
+
export function resolveClinicalDocumentAuthorOrganization(bundle) {
|
|
21
|
+
const entries = Array.isArray(bundle?.entry)
|
|
22
|
+
? bundle.entry
|
|
23
|
+
: [];
|
|
24
|
+
const composition = entries.find(({ resource }) => resource?.resourceType === 'Composition')?.resource;
|
|
25
|
+
const authorReference = cleanReference(composition?.author?.[0]?.reference);
|
|
26
|
+
const documentDate = cleanReference(composition?.date);
|
|
27
|
+
if (!composition || !authorReference || !documentDate || !Number.isFinite(Date.parse(documentDate))) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const findResource = (reference) => entries.find((entry) => {
|
|
31
|
+
const fullUrl = cleanReference(entry.fullUrl);
|
|
32
|
+
const relativeReference = resourceReference(entry.resource);
|
|
33
|
+
return reference === fullUrl
|
|
34
|
+
|| reference === relativeReference
|
|
35
|
+
|| (fullUrl && relativeReference && reference === `${fullUrl.replace(/\/$/, '')}/${relativeReference}`);
|
|
36
|
+
})?.resource;
|
|
37
|
+
const author = findResource(authorReference);
|
|
38
|
+
let organizationReference = '';
|
|
39
|
+
if (author?.resourceType === 'Organization') {
|
|
40
|
+
organizationReference = authorReference;
|
|
41
|
+
}
|
|
42
|
+
else if (author?.resourceType === 'PractitionerRole') {
|
|
43
|
+
organizationReference = cleanReference(author.organization?.reference);
|
|
44
|
+
}
|
|
45
|
+
else if (author?.resourceType === 'Practitioner') {
|
|
46
|
+
const role = entries.find(({ resource }) => resource?.resourceType === 'PractitionerRole'
|
|
47
|
+
&& cleanReference(resource.practitioner?.reference) === authorReference)?.resource;
|
|
48
|
+
organizationReference = cleanReference(role?.organization?.reference);
|
|
49
|
+
}
|
|
50
|
+
if (!organizationReference) {
|
|
51
|
+
organizationReference = cleanReference(composition.custodian?.reference);
|
|
52
|
+
}
|
|
53
|
+
const organization = findResource(organizationReference);
|
|
54
|
+
if (!organizationReference || organization?.resourceType !== 'Organization') {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
return { authorReference, organizationReference, documentDate };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Evaluates the narrow provenance-preserving replacement exception.
|
|
61
|
+
*
|
|
62
|
+
* This does not authorize an actor or a delete. Gateways call it only after
|
|
63
|
+
* authenticating the sender and resolving both document authors to their
|
|
64
|
+
* registered owning organizations.
|
|
65
|
+
*/
|
|
66
|
+
export function evaluateClinicalResourceReplacement(input) {
|
|
67
|
+
const existingResourceId = String(input.existing.resourceId || '').trim();
|
|
68
|
+
const incomingResourceId = String(input.incoming.resourceId || '').trim();
|
|
69
|
+
const existingOwner = String(input.existing.authorOwnerIdentifier || '').trim();
|
|
70
|
+
const incomingOwner = String(input.incoming.authorOwnerIdentifier || '').trim();
|
|
71
|
+
const existingDate = Date.parse(String(input.existing.documentDate || '').trim());
|
|
72
|
+
const incomingDate = Date.parse(String(input.incoming.documentDate || '').trim());
|
|
73
|
+
if (!existingResourceId
|
|
74
|
+
|| incomingResourceId !== existingResourceId
|
|
75
|
+
|| !existingOwner
|
|
76
|
+
|| incomingOwner !== existingOwner
|
|
77
|
+
|| !Number.isFinite(existingDate)
|
|
78
|
+
|| !Number.isFinite(incomingDate)
|
|
79
|
+
|| incomingDate <= existingDate) {
|
|
80
|
+
return ClinicalResourceReplacementDecision.Deny;
|
|
81
|
+
}
|
|
82
|
+
return ClinicalResourceReplacementDecision.AllowOrganizationSuccessor;
|
|
83
|
+
}
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -59,6 +59,7 @@ export * from './related-person-list';
|
|
|
59
59
|
export * from './clinical-resource-converters';
|
|
60
60
|
export * from './clinical-bundle-summary';
|
|
61
61
|
export * from './clinical-resource-view';
|
|
62
|
+
export * from './clinical-resource-replacement';
|
|
62
63
|
export * from './fhir-validator';
|
|
63
64
|
export * from './family-registration-test-data';
|
|
64
65
|
export * from './individual-form-pdf';
|
package/dist/utils/index.js
CHANGED
|
@@ -59,6 +59,7 @@ export * from './related-person-list.js';
|
|
|
59
59
|
export * from './clinical-resource-converters.js';
|
|
60
60
|
export * from './clinical-bundle-summary.js';
|
|
61
61
|
export * from './clinical-resource-view.js';
|
|
62
|
+
export * from './clinical-resource-replacement.js';
|
|
62
63
|
export * from './fhir-validator.js';
|
|
63
64
|
export * from './family-registration-test-data.js';
|
|
64
65
|
export * from './individual-form-pdf.js';
|