gdc-common-utils-ts 2.8.7 → 2.9.0
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 +7 -2
- package/dist/constants/communication.d.ts +25 -0
- package/dist/constants/communication.js +21 -1
- package/dist/constants/fhir-code-systems.d.ts +1 -0
- package/dist/constants/fhir-code-systems.js +1 -0
- package/dist/constants/healthcare.d.ts +36 -0
- package/dist/constants/healthcare.js +62 -1
- package/dist/constants/identity-identifiers.d.ts +25 -0
- package/dist/constants/identity-identifiers.js +13 -0
- package/dist/constants/sectors.d.ts +3 -0
- package/dist/constants/sectors.js +3 -0
- package/dist/examples/license.d.ts +3 -0
- package/dist/examples/license.js +3 -0
- package/dist/examples/shared.d.ts +8 -0
- package/dist/examples/shared.js +26 -2
- package/dist/models/organization-employee-lifecycle.d.ts +6 -0
- package/dist/utils/did.d.ts +62 -15
- package/dist/utils/did.js +151 -15
- package/dist/utils/organization-employee-lifecycle.js +24 -5
- package/dist/utils/service-act-reasons.d.ts +1 -1
- package/dist/utils/service-act-reasons.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -417,6 +417,9 @@ The canonical API contract should live in JSDoc on exported code. The README act
|
|
|
417
417
|
- Use instead of inline resource type strings.
|
|
418
418
|
- [`CommunicationCategoryCodes`](src/constants/communication.ts)
|
|
419
419
|
- Canonical `Communication.category` coding descriptors and `<system>|<code>` claims.
|
|
420
|
+
- Exactly the four FHIR R4 categories; use `CommunicationTopicCodes.BreakTheGlass`
|
|
421
|
+
for the HL7 v3 ActReason `BTG` topic and LOINC catalogs for clinical
|
|
422
|
+
section/document topics. See [Communication Layering 101](docs/101-COMMUNICATION_LAYERING.md).
|
|
420
423
|
- [`ObservationCategoryCodes`, `VitalSignsCodes`, `VitalSignsUnits`](src/constants/vital-signs.ts)
|
|
421
424
|
- Canonical Vital Signs category, code, and UCUM unit descriptors for `Observation`.
|
|
422
425
|
- [`HealthcareSummarySections`, `HealthcareCoreSections`, `HealthcareAllSections`](src/constants/healthcare.ts)
|
|
@@ -424,7 +427,9 @@ The canonical API contract should live in JSDoc on exported code. The README act
|
|
|
424
427
|
sections after six extensions, and the complete 82-section/classification
|
|
425
428
|
catalog. The IPS document type lives separately in `HealthcareDocumentTypes`.
|
|
426
429
|
- [`HealthcareConsentPurposes`, `HealthcareConsentActions`, `HealthcareActorRoles`, `HealthcareActorRoleCodes`](src/constants/healthcare.ts)
|
|
427
|
-
- Shared healthcare authorization and role constants
|
|
430
|
+
- Shared healthcare authorization and role constants, including the
|
|
431
|
+
`health-lab`, `animal-lab`, and `onehealth-lab` sector catalogs. See
|
|
432
|
+
[Healthcare Roles and i18n 101](docs/101-HEALTHCARE_ROLES_I18N.md).
|
|
428
433
|
- [`EXAMPLE_PROFESSIONAL_ACCESS_SCENARIOS`](src/examples/professional.ts)
|
|
429
434
|
- Reusable professional role/permission examples tying actor role, consent action, SMART scope, and expected FHIR resource types together.
|
|
430
435
|
- [`DeviceUserClasses`, `DeviceAppTypes`](src/constants/device.ts)
|
|
@@ -451,7 +456,7 @@ The canonical API contract should live in JSDoc on exported code. The README act
|
|
|
451
456
|
- do not teach its `entityId` as if it were the legal organization id
|
|
452
457
|
- Derives the technical ML-DSA/ML-KEM communication identity for a device, portal, or app profile and returns JOSE header templates for `meta.jws.protected` and `meta.jwe.header`.
|
|
453
458
|
- Uses explicit `seedMaterial` for deterministic derivation. Without `seedMaterial`, it defaults to random generation. `mode = deterministic` requires `seedMaterial`.
|
|
454
|
-
- [`buildOrganizationDidWeb(...)`, `buildProfessionalDidWeb(...)`, `buildIndividualDidWeb(...)`](src/utils/did.ts)
|
|
459
|
+
- [`buildOrganizationDidWeb(...)`, `buildProfessionalDidWeb(...)`, `buildIndividualDidWeb(...)`, `buildIndividualMemberDidWebFromPrivateIdentifiers(...)`](src/utils/did.ts)
|
|
455
460
|
- Build canonical data-space `did:web` identifiers for hosted organizations, professionals, and individuals/family actors.
|
|
456
461
|
- [`buildSmartCompositionReadScope(...)`](src/utils/smart-scope.ts)
|
|
457
462
|
- Builds the current CORE GW pinned SMART root scope for `organization/Composition...` token requests.
|
|
@@ -10,6 +10,11 @@ export type CommunicationCategoryDescriptor = Readonly<{
|
|
|
10
10
|
*/
|
|
11
11
|
claim: string;
|
|
12
12
|
}>;
|
|
13
|
+
/**
|
|
14
|
+
* The complete FHIR R4 Communication category value set.
|
|
15
|
+
*
|
|
16
|
+
* @see https://www.hl7.org/fhir/valueset-communication-category.html
|
|
17
|
+
*/
|
|
13
18
|
export declare const CommunicationCategoryCodes: Readonly<{
|
|
14
19
|
readonly Alert: Readonly<{
|
|
15
20
|
system: typeof HL7_COMMUNICATION_CATEGORY_SYSTEM;
|
|
@@ -56,3 +61,23 @@ export declare const CommunicationCategoryCodes: Readonly<{
|
|
|
56
61
|
claim: string;
|
|
57
62
|
}>;
|
|
58
63
|
}>;
|
|
64
|
+
export type CommunicationTopicDescriptor = Readonly<{
|
|
65
|
+
system: string;
|
|
66
|
+
code: string;
|
|
67
|
+
attributeValue: string;
|
|
68
|
+
}>;
|
|
69
|
+
/**
|
|
70
|
+
* Non-LOINC Communication topics explicitly governed by an HL7 code system.
|
|
71
|
+
* Clinical section and document topics continue to use the LOINC catalogs.
|
|
72
|
+
*
|
|
73
|
+
* `BTG` is the HL7 v3 ActReason override purpose used for break-glass alerts.
|
|
74
|
+
* @see http://terminology.hl7.org/CodeSystem/v3-ActReason#v3-ActReason-BTG
|
|
75
|
+
* @see https://profiles.ihe.net/ITI/PCF/Consent-ex-consent-advanced-normal-break-glass-restricted.json.html
|
|
76
|
+
*/
|
|
77
|
+
export declare const CommunicationTopicCodes: Readonly<{
|
|
78
|
+
readonly BreakTheGlass: Readonly<{
|
|
79
|
+
system: string;
|
|
80
|
+
code: string;
|
|
81
|
+
attributeValue: string;
|
|
82
|
+
}>;
|
|
83
|
+
}>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { FhirCodeSystems } from './fhir-code-systems.js';
|
|
2
|
+
export const HL7_COMMUNICATION_CATEGORY_SYSTEM = FhirCodeSystems.CommunicationCategory;
|
|
2
3
|
function defineCommunicationCategory(code) {
|
|
3
4
|
const attributeValue = `${HL7_COMMUNICATION_CATEGORY_SYSTEM}|${code}`;
|
|
4
5
|
return Object.freeze({
|
|
@@ -8,9 +9,28 @@ function defineCommunicationCategory(code) {
|
|
|
8
9
|
claim: attributeValue,
|
|
9
10
|
});
|
|
10
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* The complete FHIR R4 Communication category value set.
|
|
14
|
+
*
|
|
15
|
+
* @see https://www.hl7.org/fhir/valueset-communication-category.html
|
|
16
|
+
*/
|
|
11
17
|
export const CommunicationCategoryCodes = Object.freeze({
|
|
12
18
|
Alert: defineCommunicationCategory('alert'),
|
|
13
19
|
Notification: defineCommunicationCategory('notification'),
|
|
14
20
|
Reminder: defineCommunicationCategory('reminder'),
|
|
15
21
|
Instruction: defineCommunicationCategory('instruction'),
|
|
16
22
|
});
|
|
23
|
+
function defineCommunicationTopic(system, code) {
|
|
24
|
+
return Object.freeze({ system, code, attributeValue: `${system}|${code}` });
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Non-LOINC Communication topics explicitly governed by an HL7 code system.
|
|
28
|
+
* Clinical section and document topics continue to use the LOINC catalogs.
|
|
29
|
+
*
|
|
30
|
+
* `BTG` is the HL7 v3 ActReason override purpose used for break-glass alerts.
|
|
31
|
+
* @see http://terminology.hl7.org/CodeSystem/v3-ActReason#v3-ActReason-BTG
|
|
32
|
+
* @see https://profiles.ihe.net/ITI/PCF/Consent-ex-consent-advanced-normal-break-glass-restricted.json.html
|
|
33
|
+
*/
|
|
34
|
+
export const CommunicationTopicCodes = Object.freeze({
|
|
35
|
+
BreakTheGlass: defineCommunicationTopic(FhirCodeSystems.ActReason, 'BTG'),
|
|
36
|
+
});
|
|
@@ -9,6 +9,7 @@ export declare const FhirCodeSystems: Readonly<{
|
|
|
9
9
|
readonly SnomedCt: "http://snomed.info/sct";
|
|
10
10
|
readonly Ucum: "http://unitsofmeasure.org";
|
|
11
11
|
readonly CommunicationCategory: "http://terminology.hl7.org/CodeSystem/communication-category";
|
|
12
|
+
readonly ActReason: "http://terminology.hl7.org/CodeSystem/v3-ActReason";
|
|
12
13
|
readonly ObservationCategory: "http://terminology.hl7.org/CodeSystem/observation-category";
|
|
13
14
|
readonly EventTiming: "http://hl7.org/fhir/event-timing";
|
|
14
15
|
}>;
|
|
@@ -9,6 +9,7 @@ export const FhirCodeSystems = Object.freeze({
|
|
|
9
9
|
SnomedCt: 'http://snomed.info/sct',
|
|
10
10
|
Ucum: 'http://unitsofmeasure.org',
|
|
11
11
|
CommunicationCategory: 'http://terminology.hl7.org/CodeSystem/communication-category',
|
|
12
|
+
ActReason: 'http://terminology.hl7.org/CodeSystem/v3-ActReason',
|
|
12
13
|
ObservationCategory: 'http://terminology.hl7.org/CodeSystem/observation-category',
|
|
13
14
|
EventTiming: 'http://hl7.org/fhir/event-timing',
|
|
14
15
|
});
|
|
@@ -1727,6 +1727,10 @@ 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
|
+
/** ISCO-08 laboratory occupation for non-medical life-science work. */
|
|
1731
|
+
readonly LifeScienceTechnician: "ISCO-08|3141";
|
|
1732
|
+
/** ISCO-08 laboratory occupation for human medical/pathology work. */
|
|
1733
|
+
readonly MedicalAndPathologyLaboratoryTechnician: "ISCO-08|3212";
|
|
1730
1734
|
readonly VeterinaryTechnicianOrAssistant: "ISCO-08|3240";
|
|
1731
1735
|
/** Administrative health occupation; it does not imply clinical authority. */
|
|
1732
1736
|
readonly MedicalSecretary: "ISCO-08|3344";
|
|
@@ -1750,6 +1754,8 @@ export declare const HealthcareActorRoleCodes: Readonly<{
|
|
|
1750
1754
|
readonly MidwiferyProfessional: "2222";
|
|
1751
1755
|
readonly Paramedic: "2240";
|
|
1752
1756
|
readonly Veterinarian: "2250";
|
|
1757
|
+
readonly LifeScienceTechnician: "3141";
|
|
1758
|
+
readonly MedicalAndPathologyLaboratoryTechnician: "3212";
|
|
1753
1759
|
readonly VeterinaryTechnicianOrAssistant: "3240";
|
|
1754
1760
|
readonly MedicalSecretary: "3344";
|
|
1755
1761
|
}>;
|
|
@@ -1786,13 +1792,16 @@ export declare const HealthcareAllRolesByClaim: Readonly<Record<string, Healthca
|
|
|
1786
1792
|
export declare const HealthcareProfessionalRoleCodesBySector: Readonly<{
|
|
1787
1793
|
readonly "health-care": readonly ("RESPRSN" | "221" | "2211" | "2212" | "2221" | "2222" | "2240" | "3344")[];
|
|
1788
1794
|
readonly "health-research": readonly ("RESPRSN" | "221" | "2211" | "2212" | "3344")[];
|
|
1795
|
+
readonly "health-lab": readonly ("RESPRSN" | "221" | "2212" | "3212" | "3344")[];
|
|
1789
1796
|
readonly "health-tech": readonly "RESPRSN"[];
|
|
1790
1797
|
readonly "health-insurance": readonly "RESPRSN"[];
|
|
1791
1798
|
readonly "animal-care": readonly ("RESPRSN" | "2250" | "3240")[];
|
|
1792
1799
|
readonly "animal-research": readonly ("RESPRSN" | "2250" | "3240")[];
|
|
1800
|
+
readonly "animal-lab": readonly ("RESPRSN" | "2250" | "3141" | "3240")[];
|
|
1793
1801
|
readonly "animal-insurance": readonly "RESPRSN"[];
|
|
1794
1802
|
readonly "animal-tech": readonly "RESPRSN"[];
|
|
1795
1803
|
readonly "onehealth-research": readonly ("RESPRSN" | "221" | "2211" | "2212" | "2250" | "3240" | "3344")[];
|
|
1804
|
+
readonly "onehealth-lab": readonly ("RESPRSN" | "221" | "2212" | "2250" | "3141" | "3212" | "3240" | "3344")[];
|
|
1796
1805
|
readonly "onehealth-tech": readonly "RESPRSN"[];
|
|
1797
1806
|
}>;
|
|
1798
1807
|
export declare const HealthcareProfessionalRolesBySector: Readonly<{
|
|
@@ -1814,6 +1823,15 @@ export declare const HealthcareProfessionalRolesBySector: Readonly<{
|
|
|
1814
1823
|
titleEn: string;
|
|
1815
1824
|
definition?: string;
|
|
1816
1825
|
}>>>;
|
|
1826
|
+
readonly "health-lab": Readonly<Record<string, Readonly<{
|
|
1827
|
+
family: HealthcareRoleFamily;
|
|
1828
|
+
codingSystem: string;
|
|
1829
|
+
code: string;
|
|
1830
|
+
claim: string;
|
|
1831
|
+
i18nKey: `org.ilo.isco-08.${string}` | `org.isco08.${string}` | `org.hl7.terminology.CodeSystem.v3-RoleCode.${string}`;
|
|
1832
|
+
titleEn: string;
|
|
1833
|
+
definition?: string;
|
|
1834
|
+
}>>>;
|
|
1817
1835
|
readonly "health-tech": Readonly<Record<string, Readonly<{
|
|
1818
1836
|
family: HealthcareRoleFamily;
|
|
1819
1837
|
codingSystem: string;
|
|
@@ -1850,6 +1868,15 @@ export declare const HealthcareProfessionalRolesBySector: Readonly<{
|
|
|
1850
1868
|
titleEn: string;
|
|
1851
1869
|
definition?: string;
|
|
1852
1870
|
}>>>;
|
|
1871
|
+
readonly "animal-lab": Readonly<Record<string, Readonly<{
|
|
1872
|
+
family: HealthcareRoleFamily;
|
|
1873
|
+
codingSystem: string;
|
|
1874
|
+
code: string;
|
|
1875
|
+
claim: string;
|
|
1876
|
+
i18nKey: `org.ilo.isco-08.${string}` | `org.isco08.${string}` | `org.hl7.terminology.CodeSystem.v3-RoleCode.${string}`;
|
|
1877
|
+
titleEn: string;
|
|
1878
|
+
definition?: string;
|
|
1879
|
+
}>>>;
|
|
1853
1880
|
readonly "animal-insurance": Readonly<Record<string, Readonly<{
|
|
1854
1881
|
family: HealthcareRoleFamily;
|
|
1855
1882
|
codingSystem: string;
|
|
@@ -1877,6 +1904,15 @@ export declare const HealthcareProfessionalRolesBySector: Readonly<{
|
|
|
1877
1904
|
titleEn: string;
|
|
1878
1905
|
definition?: string;
|
|
1879
1906
|
}>>>;
|
|
1907
|
+
readonly "onehealth-lab": Readonly<Record<string, Readonly<{
|
|
1908
|
+
family: HealthcareRoleFamily;
|
|
1909
|
+
codingSystem: string;
|
|
1910
|
+
code: string;
|
|
1911
|
+
claim: string;
|
|
1912
|
+
i18nKey: `org.ilo.isco-08.${string}` | `org.isco08.${string}` | `org.hl7.terminology.CodeSystem.v3-RoleCode.${string}`;
|
|
1913
|
+
titleEn: string;
|
|
1914
|
+
definition?: string;
|
|
1915
|
+
}>>>;
|
|
1880
1916
|
readonly "onehealth-tech": Readonly<Record<string, Readonly<{
|
|
1881
1917
|
family: HealthcareRoleFamily;
|
|
1882
1918
|
codingSystem: string;
|
|
@@ -359,6 +359,10 @@ export const HealthcareActorRoles = Object.freeze({
|
|
|
359
359
|
MidwiferyProfessional: 'ISCO-08|2222',
|
|
360
360
|
Paramedic: 'ISCO-08|2240',
|
|
361
361
|
Veterinarian: 'ISCO-08|2250',
|
|
362
|
+
/** ISCO-08 laboratory occupation for non-medical life-science work. */
|
|
363
|
+
LifeScienceTechnician: 'ISCO-08|3141',
|
|
364
|
+
/** ISCO-08 laboratory occupation for human medical/pathology work. */
|
|
365
|
+
MedicalAndPathologyLaboratoryTechnician: 'ISCO-08|3212',
|
|
362
366
|
VeterinaryTechnicianOrAssistant: 'ISCO-08|3240',
|
|
363
367
|
/** Administrative health occupation; it does not imply clinical authority. */
|
|
364
368
|
MedicalSecretary: 'ISCO-08|3344',
|
|
@@ -382,6 +386,8 @@ export const HealthcareActorRoleCodes = Object.freeze({
|
|
|
382
386
|
MidwiferyProfessional: '2222',
|
|
383
387
|
Paramedic: '2240',
|
|
384
388
|
Veterinarian: '2250',
|
|
389
|
+
LifeScienceTechnician: '3141',
|
|
390
|
+
MedicalAndPathologyLaboratoryTechnician: '3212',
|
|
385
391
|
VeterinaryTechnicianOrAssistant: '3240',
|
|
386
392
|
MedicalSecretary: '3344',
|
|
387
393
|
});
|
|
@@ -464,6 +470,28 @@ function buildProfessionalIscoRoles() {
|
|
|
464
470
|
titleEn: 'Veterinarian',
|
|
465
471
|
}),
|
|
466
472
|
],
|
|
473
|
+
[
|
|
474
|
+
HealthcareActorRoleCodes.LifeScienceTechnician,
|
|
475
|
+
Object.freeze({
|
|
476
|
+
family: HealthcareRoleFamilies.ProfessionalOccupationIsco08,
|
|
477
|
+
codingSystem: ISCO08_CODING_SYSTEM,
|
|
478
|
+
code: HealthcareActorRoleCodes.LifeScienceTechnician,
|
|
479
|
+
claim: HealthcareActorRoles.LifeScienceTechnician,
|
|
480
|
+
i18nKey: `${ISCO08_I18N_NAMESPACE}.${HealthcareActorRoleCodes.LifeScienceTechnician}`,
|
|
481
|
+
titleEn: 'Life science technician (excluding medical)',
|
|
482
|
+
}),
|
|
483
|
+
],
|
|
484
|
+
[
|
|
485
|
+
HealthcareActorRoleCodes.MedicalAndPathologyLaboratoryTechnician,
|
|
486
|
+
Object.freeze({
|
|
487
|
+
family: HealthcareRoleFamilies.ProfessionalOccupationIsco08,
|
|
488
|
+
codingSystem: ISCO08_CODING_SYSTEM,
|
|
489
|
+
code: HealthcareActorRoleCodes.MedicalAndPathologyLaboratoryTechnician,
|
|
490
|
+
claim: HealthcareActorRoles.MedicalAndPathologyLaboratoryTechnician,
|
|
491
|
+
i18nKey: `${ISCO08_I18N_NAMESPACE}.${HealthcareActorRoleCodes.MedicalAndPathologyLaboratoryTechnician}`,
|
|
492
|
+
titleEn: 'Medical and pathology laboratory technician',
|
|
493
|
+
}),
|
|
494
|
+
],
|
|
467
495
|
[
|
|
468
496
|
HealthcareActorRoleCodes.VeterinaryTechnicianOrAssistant,
|
|
469
497
|
Object.freeze({
|
|
@@ -561,6 +589,13 @@ export const HealthcareProfessionalRoleCodesBySector = Object.freeze({
|
|
|
561
589
|
HealthcareActorRoleCodes.SpecialistMedicalPractitioner,
|
|
562
590
|
HealthcareActorRoleCodes.MedicalSecretary,
|
|
563
591
|
]),
|
|
592
|
+
[DataspaceSectors.HealthLab]: Object.freeze([
|
|
593
|
+
HealthcareActorRoleCodes.Controller,
|
|
594
|
+
HealthcareActorRoleCodes.MedicalDoctors,
|
|
595
|
+
HealthcareActorRoleCodes.SpecialistMedicalPractitioner,
|
|
596
|
+
HealthcareActorRoleCodes.MedicalAndPathologyLaboratoryTechnician,
|
|
597
|
+
HealthcareActorRoleCodes.MedicalSecretary,
|
|
598
|
+
]),
|
|
564
599
|
[DataspaceSectors.HealthTech]: Object.freeze([HealthcareActorRoleCodes.Controller]),
|
|
565
600
|
[DataspaceSectors.HealthInsurance]: Object.freeze([HealthcareActorRoleCodes.Controller]),
|
|
566
601
|
[DataspaceSectors.AnimalCare]: Object.freeze([
|
|
@@ -573,6 +608,12 @@ export const HealthcareProfessionalRoleCodesBySector = Object.freeze({
|
|
|
573
608
|
HealthcareActorRoleCodes.Veterinarian,
|
|
574
609
|
HealthcareActorRoleCodes.VeterinaryTechnicianOrAssistant,
|
|
575
610
|
]),
|
|
611
|
+
[DataspaceSectors.AnimalLab]: Object.freeze([
|
|
612
|
+
HealthcareActorRoleCodes.Controller,
|
|
613
|
+
HealthcareActorRoleCodes.Veterinarian,
|
|
614
|
+
HealthcareActorRoleCodes.LifeScienceTechnician,
|
|
615
|
+
HealthcareActorRoleCodes.VeterinaryTechnicianOrAssistant,
|
|
616
|
+
]),
|
|
576
617
|
[DataspaceSectors.AnimalInsurance]: Object.freeze([HealthcareActorRoleCodes.Controller]),
|
|
577
618
|
[DataspaceSectors.AnimalTech]: Object.freeze([HealthcareActorRoleCodes.Controller]),
|
|
578
619
|
[DataspaceSectors.OneHealthResearch]: Object.freeze([
|
|
@@ -584,18 +625,31 @@ export const HealthcareProfessionalRoleCodesBySector = Object.freeze({
|
|
|
584
625
|
HealthcareActorRoleCodes.VeterinaryTechnicianOrAssistant,
|
|
585
626
|
HealthcareActorRoleCodes.MedicalSecretary,
|
|
586
627
|
]),
|
|
628
|
+
[DataspaceSectors.OneHealthLab]: Object.freeze([
|
|
629
|
+
HealthcareActorRoleCodes.Controller,
|
|
630
|
+
HealthcareActorRoleCodes.MedicalDoctors,
|
|
631
|
+
HealthcareActorRoleCodes.SpecialistMedicalPractitioner,
|
|
632
|
+
HealthcareActorRoleCodes.Veterinarian,
|
|
633
|
+
HealthcareActorRoleCodes.LifeScienceTechnician,
|
|
634
|
+
HealthcareActorRoleCodes.MedicalAndPathologyLaboratoryTechnician,
|
|
635
|
+
HealthcareActorRoleCodes.VeterinaryTechnicianOrAssistant,
|
|
636
|
+
HealthcareActorRoleCodes.MedicalSecretary,
|
|
637
|
+
]),
|
|
587
638
|
[DataspaceSectors.OneHealthTech]: Object.freeze([HealthcareActorRoleCodes.Controller]),
|
|
588
639
|
});
|
|
589
640
|
export const HealthcareProfessionalRolesBySector = Object.freeze({
|
|
590
641
|
[DataspaceSectors.HealthCare]: pickRoleCatalogByCodes(HealthcareProfessionalAndControllerRoles, HealthcareProfessionalRoleCodesBySector[DataspaceSectors.HealthCare]),
|
|
591
642
|
[DataspaceSectors.HealthResearch]: pickRoleCatalogByCodes(HealthcareProfessionalAndControllerRoles, HealthcareProfessionalRoleCodesBySector[DataspaceSectors.HealthResearch]),
|
|
643
|
+
[DataspaceSectors.HealthLab]: pickRoleCatalogByCodes(HealthcareProfessionalAndControllerRoles, HealthcareProfessionalRoleCodesBySector[DataspaceSectors.HealthLab]),
|
|
592
644
|
[DataspaceSectors.HealthTech]: pickRoleCatalogByCodes(HealthcareProfessionalAndControllerRoles, HealthcareProfessionalRoleCodesBySector[DataspaceSectors.HealthTech]),
|
|
593
645
|
[DataspaceSectors.HealthInsurance]: pickRoleCatalogByCodes(HealthcareProfessionalAndControllerRoles, HealthcareProfessionalRoleCodesBySector[DataspaceSectors.HealthInsurance]),
|
|
594
646
|
[DataspaceSectors.AnimalCare]: pickRoleCatalogByCodes(HealthcareProfessionalAndControllerRoles, HealthcareProfessionalRoleCodesBySector[DataspaceSectors.AnimalCare]),
|
|
595
647
|
[DataspaceSectors.AnimalResearch]: pickRoleCatalogByCodes(HealthcareProfessionalAndControllerRoles, HealthcareProfessionalRoleCodesBySector[DataspaceSectors.AnimalResearch]),
|
|
648
|
+
[DataspaceSectors.AnimalLab]: pickRoleCatalogByCodes(HealthcareProfessionalAndControllerRoles, HealthcareProfessionalRoleCodesBySector[DataspaceSectors.AnimalLab]),
|
|
596
649
|
[DataspaceSectors.AnimalInsurance]: pickRoleCatalogByCodes(HealthcareProfessionalAndControllerRoles, HealthcareProfessionalRoleCodesBySector[DataspaceSectors.AnimalInsurance]),
|
|
597
650
|
[DataspaceSectors.AnimalTech]: pickRoleCatalogByCodes(HealthcareProfessionalAndControllerRoles, HealthcareProfessionalRoleCodesBySector[DataspaceSectors.AnimalTech]),
|
|
598
651
|
[DataspaceSectors.OneHealthResearch]: pickRoleCatalogByCodes(HealthcareProfessionalAndControllerRoles, HealthcareProfessionalRoleCodesBySector[DataspaceSectors.OneHealthResearch]),
|
|
652
|
+
[DataspaceSectors.OneHealthLab]: pickRoleCatalogByCodes(HealthcareProfessionalAndControllerRoles, HealthcareProfessionalRoleCodesBySector[DataspaceSectors.OneHealthLab]),
|
|
599
653
|
[DataspaceSectors.OneHealthTech]: pickRoleCatalogByCodes(HealthcareProfessionalAndControllerRoles, HealthcareProfessionalRoleCodesBySector[DataspaceSectors.OneHealthTech]),
|
|
600
654
|
});
|
|
601
655
|
export const HealthcareProfessionalRolesBySectorAndClaim = Object.freeze(Object.fromEntries(Object.values(DataspaceSectors).map((sector) => [
|
|
@@ -614,7 +668,14 @@ export function getHealthcareRolesByFamily(family) {
|
|
|
614
668
|
return HealthcareRolesByFamily[family];
|
|
615
669
|
}
|
|
616
670
|
export function getHealthcareRoleByClaim(claim) {
|
|
617
|
-
|
|
671
|
+
const normalized = String(claim || '').trim();
|
|
672
|
+
const direct = HealthcareAllRolesByClaim[normalized];
|
|
673
|
+
if (direct)
|
|
674
|
+
return direct;
|
|
675
|
+
const fullHl7Prefix = `${HL7_CODING_SYSTEM_V3_ROLE_CODE}|`;
|
|
676
|
+
return normalized.startsWith(fullHl7Prefix)
|
|
677
|
+
? HealthcareAllRolesByClaim[`v3-RoleCode|${normalized.slice(fullHl7Prefix.length)}`]
|
|
678
|
+
: undefined;
|
|
618
679
|
}
|
|
619
680
|
export function getHealthcareProfessionalRolesBySector(sector) {
|
|
620
681
|
return HealthcareProfessionalRolesBySector[sector] || {};
|
|
@@ -32,6 +32,31 @@ export declare const HL7_V2_0203_IDENTIFIER_CODES: Readonly<{
|
|
|
32
32
|
readonly PatientIdentifier: "PI";
|
|
33
33
|
}>;
|
|
34
34
|
export type Hl7V20203IdentifierCode = typeof HL7_V2_0203_IDENTIFIER_CODES[keyof typeof HL7_V2_0203_IDENTIFIER_CODES];
|
|
35
|
+
/**
|
|
36
|
+
* Identifier type tokens accepted by the hosted individual DID builders.
|
|
37
|
+
*
|
|
38
|
+
* `DL`, `PPN`, `NN`, and the other clinical identifier codes retain their
|
|
39
|
+
* HL7 v2-0203 meaning. `UUID`, `EMAIL`, and `PHONE` are GDC index identifier
|
|
40
|
+
* types and must not be described as HL7 codes.
|
|
41
|
+
*/
|
|
42
|
+
export declare const SecureIdTypesIndividual: Readonly<{
|
|
43
|
+
readonly DriverLicense: "DL";
|
|
44
|
+
readonly CitizenshipCard: "CZ";
|
|
45
|
+
readonly NationalNumber: "NN";
|
|
46
|
+
readonly PassportNumber: "PPN";
|
|
47
|
+
readonly JurisdictionalHealthNumber: "JHN";
|
|
48
|
+
readonly WorkPermit: "WP";
|
|
49
|
+
readonly StudyPermit: "SP";
|
|
50
|
+
readonly HealthCard: "HC";
|
|
51
|
+
readonly MemberNumber: "MB";
|
|
52
|
+
readonly SubscriberNumber: "SN";
|
|
53
|
+
readonly DonorRecord: "DR";
|
|
54
|
+
readonly PatientIdentifier: "PI";
|
|
55
|
+
readonly Uuid: "UUID";
|
|
56
|
+
readonly Email: "EMAIL";
|
|
57
|
+
readonly Phone: "PHONE";
|
|
58
|
+
}>;
|
|
59
|
+
export type SecureIdTypeIndividual = typeof SecureIdTypesIndividual[keyof typeof SecureIdTypesIndividual];
|
|
35
60
|
/** Product-neutral document kinds used by subject identifier forms. */
|
|
36
61
|
export declare const INDIVIDUAL_IDENTIFIER_KINDS: Readonly<{
|
|
37
62
|
readonly NationalPerson: "national-person";
|
|
@@ -31,6 +31,19 @@ export const HL7_V2_0203_IDENTIFIER_CODES = Object.freeze({
|
|
|
31
31
|
DonorRecord: 'DR',
|
|
32
32
|
PatientIdentifier: 'PI',
|
|
33
33
|
});
|
|
34
|
+
/**
|
|
35
|
+
* Identifier type tokens accepted by the hosted individual DID builders.
|
|
36
|
+
*
|
|
37
|
+
* `DL`, `PPN`, `NN`, and the other clinical identifier codes retain their
|
|
38
|
+
* HL7 v2-0203 meaning. `UUID`, `EMAIL`, and `PHONE` are GDC index identifier
|
|
39
|
+
* types and must not be described as HL7 codes.
|
|
40
|
+
*/
|
|
41
|
+
export const SecureIdTypesIndividual = Object.freeze({
|
|
42
|
+
Uuid: 'UUID',
|
|
43
|
+
Email: 'EMAIL',
|
|
44
|
+
Phone: 'PHONE',
|
|
45
|
+
...HL7_V2_0203_IDENTIFIER_CODES,
|
|
46
|
+
});
|
|
34
47
|
/** Product-neutral document kinds used by subject identifier forms. */
|
|
35
48
|
export const INDIVIDUAL_IDENTIFIER_KINDS = Object.freeze({
|
|
36
49
|
NationalPerson: 'national-person',
|
|
@@ -11,14 +11,17 @@
|
|
|
11
11
|
*/
|
|
12
12
|
export declare const DataspaceSectors: Readonly<{
|
|
13
13
|
readonly HealthCare: "health-care";
|
|
14
|
+
readonly HealthLab: "health-lab";
|
|
14
15
|
readonly HealthResearch: "health-research";
|
|
15
16
|
readonly HealthTech: "health-tech";
|
|
16
17
|
readonly HealthInsurance: "health-insurance";
|
|
17
18
|
readonly AnimalCare: "animal-care";
|
|
19
|
+
readonly AnimalLab: "animal-lab";
|
|
18
20
|
readonly AnimalResearch: "animal-research";
|
|
19
21
|
readonly AnimalInsurance: "animal-insurance";
|
|
20
22
|
readonly AnimalTech: "animal-tech";
|
|
21
23
|
readonly OneHealthResearch: "onehealth-research";
|
|
24
|
+
readonly OneHealthLab: "onehealth-lab";
|
|
22
25
|
readonly OneHealthTech: "onehealth-tech";
|
|
23
26
|
}>;
|
|
24
27
|
export type DataspaceSector = typeof DataspaceSectors[keyof typeof DataspaceSectors];
|
|
@@ -12,13 +12,16 @@
|
|
|
12
12
|
*/
|
|
13
13
|
export const DataspaceSectors = Object.freeze({
|
|
14
14
|
HealthCare: 'health-care',
|
|
15
|
+
HealthLab: 'health-lab',
|
|
15
16
|
HealthResearch: 'health-research',
|
|
16
17
|
HealthTech: 'health-tech',
|
|
17
18
|
HealthInsurance: 'health-insurance',
|
|
18
19
|
AnimalCare: 'animal-care',
|
|
20
|
+
AnimalLab: 'animal-lab',
|
|
19
21
|
AnimalResearch: 'animal-research',
|
|
20
22
|
AnimalInsurance: 'animal-insurance',
|
|
21
23
|
AnimalTech: 'animal-tech',
|
|
22
24
|
OneHealthResearch: 'onehealth-research',
|
|
25
|
+
OneHealthLab: 'onehealth-lab',
|
|
23
26
|
OneHealthTech: 'onehealth-tech',
|
|
24
27
|
});
|
|
@@ -237,6 +237,9 @@ export declare const EXAMPLE_EMPLOYEE_LIFECYCLE_RECORD: Readonly<{
|
|
|
237
237
|
clientId: "client-employee-primary" | "client-employee-secondary";
|
|
238
238
|
name: "installation-employee-primary" | "installation-employee-secondary" | "Shared browser profile";
|
|
239
239
|
status: "active" | "revoked";
|
|
240
|
+
ownerContact: string;
|
|
241
|
+
ownerContactKind: "email";
|
|
242
|
+
activatedAt: 1786570800 | 1786570900;
|
|
240
243
|
}>[];
|
|
241
244
|
}>;
|
|
242
245
|
}>;
|
package/dist/examples/license.js
CHANGED
|
@@ -171,6 +171,9 @@ export const EXAMPLE_EMPLOYEE_LIFECYCLE_RECORD = Object.freeze({
|
|
|
171
171
|
|| binding.deviceInfo.clientInstanceId
|
|
172
172
|
|| binding.clientId,
|
|
173
173
|
status: binding.status,
|
|
174
|
+
ownerContact: EXAMPLE_EMPLOYEE_CONTROLLER_ACTIVE.email,
|
|
175
|
+
ownerContactKind: 'email',
|
|
176
|
+
activatedAt: binding.activatedAt,
|
|
174
177
|
}))),
|
|
175
178
|
}),
|
|
176
179
|
});
|
|
@@ -149,6 +149,8 @@ export declare const EXAMPLE_PROVIDER_DOMAIN: "health-care.provider.example.org"
|
|
|
149
149
|
/** Synthetic public portal domain used to derive organization path DIDs. */
|
|
150
150
|
export declare const EXAMPLE_PUBLIC_PORTAL_DOMAIN: "portal.example.org";
|
|
151
151
|
export declare const EXAMPLE_INDIVIDUAL_MULTIBASE_ID: string;
|
|
152
|
+
/** Synthetic private UUID used to prove one-way hosted individual DID construction. */
|
|
153
|
+
export declare const EXAMPLE_PRIVATE_INDIVIDUAL_UUID: "a87e5b15-aea4-4475-9c7c-40aa88354b6f";
|
|
152
154
|
export declare const EXAMPLE_INDIVIDUAL_MULTIBASE_ID_SECONDARY: string;
|
|
153
155
|
export declare const EXAMPLE_INDIVIDUAL_MULTIBASE_ID_TERTIARY: string;
|
|
154
156
|
export declare const EXAMPLE_INDIVIDUAL_MULTIBASE_ID_CONDITION: string;
|
|
@@ -212,7 +214,13 @@ export declare const EXAMPLE_HEALTHCARE_ACTOR_ROLE_PHYSICIAN: "ISCO-08|2211";
|
|
|
212
214
|
export declare const EXAMPLE_HEALTHCARE_ACTOR_ROLE_GENERALIST_MEDICAL_PRACTITIONER: "ISCO-08|2211";
|
|
213
215
|
export declare const EXAMPLE_HEALTHCARE_ACTOR_ROLE_RECEPTIONIST: "ISCO-08|4226";
|
|
214
216
|
export declare const EXAMPLE_HEALTHCARE_ROLE_PHYSICIAN_TEXT: "physician";
|
|
217
|
+
export declare const EXAMPLE_INDIVIDUAL_CONTROLLER_ROLE_TYPE = "http://terminology.hl7.org/CodeSystem/v3-RoleCode";
|
|
218
|
+
export declare const EXAMPLE_INDIVIDUAL_CONTROLLER_ROLE_VALUE: "RESPRSN";
|
|
215
219
|
export declare const EXAMPLE_RELATED_PERSON_ROLE: "v3-RoleCode|RESPRSN";
|
|
220
|
+
export declare const EXAMPLE_SECURE_ID_VALUE_INDIVIDUAL: string;
|
|
221
|
+
export declare const EXAMPLE_SECURE_ID_VALUE_INDIVIDUAL_CONTROLLER: string;
|
|
222
|
+
export declare const EXAMPLE_HOSTED_INDIVIDUAL_DID: string;
|
|
223
|
+
export declare const EXAMPLE_HOSTED_INDIVIDUAL_CONTROLLER_DID: string;
|
|
216
224
|
export declare const EXAMPLE_RELATED_PERSON_MEMBER_DID: string;
|
|
217
225
|
export declare const EXAMPLE_CLINICAL_SECTION_RESULTS: "LOINC|30954-2";
|
|
218
226
|
export declare const EXAMPLE_CLINICAL_SECTION_PATIENT_SUMMARY: "LOINC|60591-5";
|
package/dist/examples/shared.js
CHANGED
|
@@ -6,12 +6,13 @@ import { FhirCodeSystems } from '../constants/fhir-code-systems.js';
|
|
|
6
6
|
import { Format } from '../constants/Schemas.js';
|
|
7
7
|
import { ResourceTypesFhirR4 } from '../constants/fhir-resource-types.js';
|
|
8
8
|
import { BirthSex, GenderIdentity } from '../constants/identity-gender.js';
|
|
9
|
-
import { IdKind } from '../constants/identity-identifiers.js';
|
|
9
|
+
import { IdKind, SecureIdTypesIndividual } from '../constants/identity-identifiers.js';
|
|
10
|
+
import { HL7_CODING_SYSTEM_V3_ROLE_CODE } from '../constants/hl7-roles.js';
|
|
10
11
|
import { HealthcareActorRoles, HealthcareBasicSections, HealthcareConsentPurposes, HealthcareDocumentTypes, } from '../constants/healthcare.js';
|
|
11
12
|
import { CommunicationCategoryCodes } from '../constants/communication.js';
|
|
12
13
|
import { LOINC_SYSTEM_URL } from '../models/clinical-sections.js';
|
|
13
14
|
import { CommunicationClaim } from '../models/interoperable-claims/communication-claims.js';
|
|
14
|
-
import { buildHostedProviderDidWeb, buildIndividualDidWeb, buildIndividualMemberDidWeb, buildProfessionalDidWeb, buildProviderSectorDidWeb, } from '../utils/did.js';
|
|
15
|
+
import { buildHostedProviderDidWeb, buildIndividualDidWeb, buildIndividualMemberDidWeb, buildSecureIdValueIndividual, buildSecureIdValueMember, buildProfessionalDidWeb, buildProviderSectorDidWeb, } from '../utils/did.js';
|
|
15
16
|
import { encodeHexToMultibase58btc } from '../utils/multibase58.js';
|
|
16
17
|
import { MedicationStatementClaim, MedicationStatementClaimsFhirApiExtended, } from '../models/interoperable-claims/medication-statement-claims.js';
|
|
17
18
|
import { medicationStatementFlatToFhirR4 } from '../utils/clinical-resource-converters.js';
|
|
@@ -167,6 +168,8 @@ export const EXAMPLE_PROVIDER_DOMAIN = 'health-care.provider.example.org';
|
|
|
167
168
|
/** Synthetic public portal domain used to derive organization path DIDs. */
|
|
168
169
|
export const EXAMPLE_PUBLIC_PORTAL_DOMAIN = 'portal.example.org';
|
|
169
170
|
export const EXAMPLE_INDIVIDUAL_MULTIBASE_ID = encodeHexToMultibase58btc('a87e5b15aea444759c7c40aa88354b6f');
|
|
171
|
+
/** Synthetic private UUID used to prove one-way hosted individual DID construction. */
|
|
172
|
+
export const EXAMPLE_PRIVATE_INDIVIDUAL_UUID = 'a87e5b15-aea4-4475-9c7c-40aa88354b6f';
|
|
170
173
|
export const EXAMPLE_INDIVIDUAL_MULTIBASE_ID_SECONDARY = encodeHexToMultibase58btc('b98f6c24bfb545849d8d51bb99465c7e');
|
|
171
174
|
export const EXAMPLE_INDIVIDUAL_MULTIBASE_ID_TERTIARY = encodeHexToMultibase58btc('c39f7d35c0c65695ae9e62cca0576d8f');
|
|
172
175
|
export const EXAMPLE_INDIVIDUAL_MULTIBASE_ID_CONDITION = encodeHexToMultibase58btc('d4a08e46d1d767a6bfaf73ddb1687ea0');
|
|
@@ -251,7 +254,28 @@ export const EXAMPLE_HEALTHCARE_ACTOR_ROLE_PHYSICIAN = HealthcareActorRoles.Phys
|
|
|
251
254
|
export const EXAMPLE_HEALTHCARE_ACTOR_ROLE_GENERALIST_MEDICAL_PRACTITIONER = HealthcareActorRoles.GeneralistMedicalPractitioner;
|
|
252
255
|
export const EXAMPLE_HEALTHCARE_ACTOR_ROLE_RECEPTIONIST = 'ISCO-08|4226';
|
|
253
256
|
export const EXAMPLE_HEALTHCARE_ROLE_PHYSICIAN_TEXT = 'physician';
|
|
257
|
+
export const EXAMPLE_INDIVIDUAL_CONTROLLER_ROLE_TYPE = HL7_CODING_SYSTEM_V3_ROLE_CODE;
|
|
258
|
+
export const EXAMPLE_INDIVIDUAL_CONTROLLER_ROLE_VALUE = EXAMPLE_ORGANIZATION_CONTROLLER_ROLE;
|
|
254
259
|
export const EXAMPLE_RELATED_PERSON_ROLE = 'v3-RoleCode|RESPRSN';
|
|
260
|
+
export const EXAMPLE_SECURE_ID_VALUE_INDIVIDUAL = buildSecureIdValueIndividual({
|
|
261
|
+
secureIdTypeIndividual: SecureIdTypesIndividual.Uuid,
|
|
262
|
+
privateIdValueIndividual: EXAMPLE_PRIVATE_INDIVIDUAL_UUID,
|
|
263
|
+
});
|
|
264
|
+
export const EXAMPLE_SECURE_ID_VALUE_INDIVIDUAL_CONTROLLER = buildSecureIdValueMember({
|
|
265
|
+
secureIdTypeMember: SecureIdTypesIndividual.Email,
|
|
266
|
+
privateIdValueMember: EXAMPLE_EMAIL_CONTROLLER_INDIVIDUAL,
|
|
267
|
+
});
|
|
268
|
+
export const EXAMPLE_HOSTED_INDIVIDUAL_DID = buildIndividualDidWeb({
|
|
269
|
+
providerDidWeb: EXAMPLE_HOSTED_PROVIDER_DID,
|
|
270
|
+
secureIdTypeIndividual: SecureIdTypesIndividual.Uuid,
|
|
271
|
+
secureIdValueIndividual: EXAMPLE_SECURE_ID_VALUE_INDIVIDUAL,
|
|
272
|
+
});
|
|
273
|
+
export const EXAMPLE_HOSTED_INDIVIDUAL_CONTROLLER_DID = buildIndividualMemberDidWeb({
|
|
274
|
+
individualDidWeb: EXAMPLE_HOSTED_INDIVIDUAL_DID,
|
|
275
|
+
memberId: EXAMPLE_SECURE_ID_VALUE_INDIVIDUAL_CONTROLLER,
|
|
276
|
+
roleType: EXAMPLE_INDIVIDUAL_CONTROLLER_ROLE_TYPE,
|
|
277
|
+
roleValue: EXAMPLE_INDIVIDUAL_CONTROLLER_ROLE_VALUE,
|
|
278
|
+
});
|
|
255
279
|
export const EXAMPLE_RELATED_PERSON_MEMBER_DID = buildIndividualMemberDidWeb({
|
|
256
280
|
individualDidWeb: EXAMPLE_SUBJECT_DID,
|
|
257
281
|
role: EXAMPLE_RELATED_PERSON_ROLE,
|
|
@@ -5,6 +5,12 @@ export type OrganizationEmployeeDeviceRecord = Readonly<{
|
|
|
5
5
|
clientId: string;
|
|
6
6
|
name: string;
|
|
7
7
|
status: DeviceBindingStatus;
|
|
8
|
+
/** Verified licensed contact that owns this installation. */
|
|
9
|
+
ownerContact?: string;
|
|
10
|
+
/** Contact channel represented by `ownerContact`. */
|
|
11
|
+
ownerContactKind?: 'email' | 'phone';
|
|
12
|
+
/** DCR activation time as Unix epoch seconds. */
|
|
13
|
+
activatedAt?: number;
|
|
8
14
|
}>;
|
|
9
15
|
/** License state attached to one employee directory entry. */
|
|
10
16
|
export type OrganizationEmployeeLicenseRecord = Readonly<{
|
package/dist/utils/did.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ServiceEndpointSelector } from "../models/did";
|
|
2
|
+
import { type SecureIdTypeIndividual } from '../constants/identity-identifiers';
|
|
2
3
|
/**
|
|
3
4
|
* Canonical DID path markers for hosted/provider individual identities.
|
|
4
5
|
*
|
|
@@ -11,6 +12,19 @@ export declare const IndividualDidMarkers: {
|
|
|
11
12
|
readonly Member: "member";
|
|
12
13
|
readonly Role: "role";
|
|
13
14
|
};
|
|
15
|
+
export declare function buildSecureIdValueIndividual(input: {
|
|
16
|
+
secureIdTypeIndividual: SecureIdTypeIndividual | string;
|
|
17
|
+
privateIdValueIndividual: string;
|
|
18
|
+
}): string;
|
|
19
|
+
/**
|
|
20
|
+
* Builds the same SHA3-384 multihash path value for the private identifier of
|
|
21
|
+
* an individual member/controller. The member and represented individual
|
|
22
|
+
* remain distinct inputs even when both refer to the same natural person.
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildSecureIdValueMember(input: {
|
|
25
|
+
secureIdTypeMember: SecureIdTypeIndividual | string;
|
|
26
|
+
privateIdValueMember: string;
|
|
27
|
+
}): string;
|
|
14
28
|
/**
|
|
15
29
|
* Removes any coding-system prefix from a role claim when building a member DID.
|
|
16
30
|
*
|
|
@@ -189,38 +203,71 @@ export declare function buildProfessionalDidWeb(input: {
|
|
|
189
203
|
* Builds the canonical individual DID under either a hosted-provider DID root
|
|
190
204
|
* or an external provider-sector DID root.
|
|
191
205
|
*
|
|
192
|
-
* Canonical
|
|
193
|
-
* -
|
|
194
|
-
* `did:web:<host.domain>:<sector>:organization:taxid:<provider-tax-id>:individual:multibase:<individualId>`
|
|
195
|
-
* - external/provider-domain:
|
|
196
|
-
* `did:web:<sector.provider.domain>:individual:multibase:<individualId>`
|
|
206
|
+
* Canonical hosted form:
|
|
207
|
+
* `did:web:<provider-path>:individual:<secureIdTypeIndividual>:<secureIdValueIndividual>`
|
|
197
208
|
*
|
|
198
209
|
* Important semantics:
|
|
199
|
-
* -
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
210
|
+
* - the type remains an explicit upper-case path token such as `UUID`, `DL`,
|
|
211
|
+
* `PPN`, `EMAIL`, or `PHONE`;
|
|
212
|
+
* - the value is always the one-way SHA3-384 multihash built by
|
|
213
|
+
* `buildSecureIdValueIndividual`, never the private identifier in plain text;
|
|
214
|
+
* - role is not part of the individual DID.
|
|
204
215
|
*
|
|
205
216
|
* Backward-compatibility:
|
|
206
217
|
* - `subjectId` is accepted as a legacy alias for `individualId`
|
|
207
218
|
*/
|
|
208
219
|
export declare function buildIndividualDidWeb(input: {
|
|
209
220
|
providerDidWeb: string;
|
|
221
|
+
secureIdTypeIndividual?: SecureIdTypeIndividual | string;
|
|
222
|
+
secureIdValueIndividual?: string;
|
|
223
|
+
/** @deprecated Use `secureIdTypeIndividual` plus `secureIdValueIndividual`. */
|
|
210
224
|
individualId?: string;
|
|
225
|
+
/** @deprecated Use `secureIdTypeIndividual` plus `secureIdValueIndividual`. */
|
|
211
226
|
subjectId?: string;
|
|
212
227
|
}): string;
|
|
213
228
|
/**
|
|
214
229
|
* Builds the canonical member DID under an individual DID.
|
|
215
230
|
*
|
|
216
231
|
* Canonical form:
|
|
217
|
-
* `did:web:...:individual
|
|
232
|
+
* `did:web:...:individual:<type>:<secure-value>:member:<secure-member-value>:<role-value>`
|
|
218
233
|
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
* the claims layer.
|
|
234
|
+
* `roleType` is mandatory input so callers cannot accidentally lose the coded
|
|
235
|
+
* role semantics. Only `roleValue` is serialized in the DID because the full
|
|
236
|
+
* FHIR token (`system|value`) remains in the protected claims/licence layer.
|
|
222
237
|
*/
|
|
223
238
|
export declare function buildIndividualMemberDidWeb(input: {
|
|
224
239
|
individualDidWeb: string;
|
|
225
|
-
|
|
240
|
+
memberId?: string;
|
|
241
|
+
roleType?: string;
|
|
242
|
+
roleValue?: string;
|
|
243
|
+
/** @deprecated Use `roleType` plus `roleValue`. */
|
|
244
|
+
role?: string;
|
|
245
|
+
}): string;
|
|
246
|
+
/**
|
|
247
|
+
* Builds a complete hosted individual-member DID directly from the private
|
|
248
|
+
* identifiers already held by an authorized BFF.
|
|
249
|
+
*
|
|
250
|
+
* This is the integration helper for portals: the provider DID returned by GW,
|
|
251
|
+
* the individual's private UUID or other governed identifier, the logged-in
|
|
252
|
+
* member's email/phone/private identifier, and the protected role type/value
|
|
253
|
+
* are sufficient. Neither private identifier is serialized in the result.
|
|
254
|
+
*/
|
|
255
|
+
export declare function buildIndividualMemberDidWebFromPrivateIdentifiers(input: {
|
|
256
|
+
providerDidWeb: string;
|
|
257
|
+
secureIdTypeIndividual: SecureIdTypeIndividual | string;
|
|
258
|
+
privateIdValueIndividual: string;
|
|
259
|
+
secureIdTypeMember: SecureIdTypeIndividual | string;
|
|
260
|
+
privateIdValueMember: string;
|
|
261
|
+
roleType: string;
|
|
262
|
+
roleValue: string;
|
|
226
263
|
}): string;
|
|
264
|
+
/**
|
|
265
|
+
* Parses one hosted individual-member DID without interpreting its role value
|
|
266
|
+
* as authorization. The complete role system and value must still be checked
|
|
267
|
+
* against the protected licence or credential by the consuming gateway.
|
|
268
|
+
*/
|
|
269
|
+
export declare function parseIndividualMemberDidWeb(didWeb: string): {
|
|
270
|
+
individualDidWeb: string;
|
|
271
|
+
memberId: string;
|
|
272
|
+
roleValue: string;
|
|
273
|
+
};
|
package/dist/utils/did.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
// crypto-ts/utils/did.ts
|
|
2
2
|
// Copyright 2025 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
3
3
|
import { multibase58MultihashSha3_256 } from './same-as.js';
|
|
4
|
+
import { SecureIdTypesIndividual, } from '../constants/identity-identifiers.js';
|
|
5
|
+
import { normalizePhone } from './consent.js';
|
|
6
|
+
import { encodeMultibaseSha3 } from './multibasehash.js';
|
|
4
7
|
/**
|
|
5
8
|
* Canonical DID path markers for hosted/provider individual identities.
|
|
6
9
|
*
|
|
@@ -13,6 +16,63 @@ export const IndividualDidMarkers = {
|
|
|
13
16
|
Member: 'member',
|
|
14
17
|
Role: 'role',
|
|
15
18
|
};
|
|
19
|
+
const UUID_VALUE_PATTERN = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i;
|
|
20
|
+
const MULTIBASE_SHA3_384_PATTERN = /^z[1-9A-HJ-NP-Za-km-z]+$/;
|
|
21
|
+
/**
|
|
22
|
+
* Builds the privacy-preserving value used by a hosted individual DID.
|
|
23
|
+
*
|
|
24
|
+
* Wire profile: `multibase(base58btc(multihash(SHA3-384, canonical-bytes)))`.
|
|
25
|
+
* The returned value is the bare `z...` path token, not an
|
|
26
|
+
* `urn:multibase:...` value and not a CID.
|
|
27
|
+
*
|
|
28
|
+
* Canonical inputs:
|
|
29
|
+
* - `UUID`: remove hyphens, interpret the 32 hexadecimal digits as the UUID's
|
|
30
|
+
* canonical 16 bytes, then hash those bytes;
|
|
31
|
+
* - `EMAIL`: remove `mailto:`, whitespace and letter-case differences;
|
|
32
|
+
* - `PHONE`: remove `tel:` and normalize the number through the shared phone
|
|
33
|
+
* normalizer (including its E.164 leading `+` when supplied);
|
|
34
|
+
* - HL7 v2-0203 and other governed private identifiers: NFKC-normalized,
|
|
35
|
+
* trimmed, upper-case UTF-8 text. Their type and jurisdiction remain
|
|
36
|
+
* separate governed fields and are never inferred from the value.
|
|
37
|
+
*/
|
|
38
|
+
function buildSecureIdValue(typeInput, valueInput, context) {
|
|
39
|
+
const type = String(typeInput || '').trim().toUpperCase();
|
|
40
|
+
const rawValue = String(valueInput || '').trim();
|
|
41
|
+
if (!type)
|
|
42
|
+
throw new Error(`${context} requires a secure identifier type.`);
|
|
43
|
+
if (!rawValue)
|
|
44
|
+
throw new Error(`${context} requires a private identifier value.`);
|
|
45
|
+
if (type === SecureIdTypesIndividual.Uuid) {
|
|
46
|
+
if (!UUID_VALUE_PATTERN.test(rawValue)) {
|
|
47
|
+
throw new Error(`${context} requires a hexadecimal UUID value.`);
|
|
48
|
+
}
|
|
49
|
+
const hex = rawValue.replace(/-/g, '').toLowerCase();
|
|
50
|
+
const bytes = new Uint8Array(16);
|
|
51
|
+
for (let index = 0; index < bytes.length; index += 1) {
|
|
52
|
+
bytes[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);
|
|
53
|
+
}
|
|
54
|
+
return encodeMultibaseSha3(bytes, 384);
|
|
55
|
+
}
|
|
56
|
+
const canonicalText = type === SecureIdTypesIndividual.Email
|
|
57
|
+
? rawValue.replace(/^mailto:/i, '').replace(/\s+/g, '').toLowerCase()
|
|
58
|
+
: type === SecureIdTypesIndividual.Phone
|
|
59
|
+
? normalizePhone(rawValue.replace(/^tel:/i, ''))
|
|
60
|
+
: rawValue.normalize('NFKC').toUpperCase();
|
|
61
|
+
if (!canonicalText)
|
|
62
|
+
throw new Error(`${context} requires a valid ${type} value.`);
|
|
63
|
+
return encodeMultibaseSha3(canonicalText, 384);
|
|
64
|
+
}
|
|
65
|
+
export function buildSecureIdValueIndividual(input) {
|
|
66
|
+
return buildSecureIdValue(input.secureIdTypeIndividual, input.privateIdValueIndividual, 'buildSecureIdValueIndividual');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Builds the same SHA3-384 multihash path value for the private identifier of
|
|
70
|
+
* an individual member/controller. The member and represented individual
|
|
71
|
+
* remain distinct inputs even when both refer to the same natural person.
|
|
72
|
+
*/
|
|
73
|
+
export function buildSecureIdValueMember(input) {
|
|
74
|
+
return buildSecureIdValue(input.secureIdTypeMember, input.privateIdValueMember, 'buildSecureIdValueMember');
|
|
75
|
+
}
|
|
16
76
|
/**
|
|
17
77
|
* Removes any coding-system prefix from a role claim when building a member DID.
|
|
18
78
|
*
|
|
@@ -334,27 +394,40 @@ export function buildProfessionalDidWeb(input) {
|
|
|
334
394
|
* Builds the canonical individual DID under either a hosted-provider DID root
|
|
335
395
|
* or an external provider-sector DID root.
|
|
336
396
|
*
|
|
337
|
-
* Canonical
|
|
338
|
-
* -
|
|
339
|
-
* `did:web:<host.domain>:<sector>:organization:taxid:<provider-tax-id>:individual:multibase:<individualId>`
|
|
340
|
-
* - external/provider-domain:
|
|
341
|
-
* `did:web:<sector.provider.domain>:individual:multibase:<individualId>`
|
|
397
|
+
* Canonical hosted form:
|
|
398
|
+
* `did:web:<provider-path>:individual:<secureIdTypeIndividual>:<secureIdValueIndividual>`
|
|
342
399
|
*
|
|
343
400
|
* Important semantics:
|
|
344
|
-
* -
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
*
|
|
401
|
+
* - the type remains an explicit upper-case path token such as `UUID`, `DL`,
|
|
402
|
+
* `PPN`, `EMAIL`, or `PHONE`;
|
|
403
|
+
* - the value is always the one-way SHA3-384 multihash built by
|
|
404
|
+
* `buildSecureIdValueIndividual`, never the private identifier in plain text;
|
|
405
|
+
* - role is not part of the individual DID.
|
|
349
406
|
*
|
|
350
407
|
* Backward-compatibility:
|
|
351
408
|
* - `subjectId` is accepted as a legacy alias for `individualId`
|
|
352
409
|
*/
|
|
353
410
|
export function buildIndividualDidWeb(input) {
|
|
354
411
|
const providerDidWeb = String(input.providerDidWeb || '').trim();
|
|
412
|
+
const secureIdTypeIndividual = String(input.secureIdTypeIndividual || '').trim().toUpperCase();
|
|
413
|
+
const secureIdValueIndividual = String(input.secureIdValueIndividual || '').trim();
|
|
355
414
|
const individualId = String(input.individualId || input.subjectId || '').trim();
|
|
356
415
|
if (!providerDidWeb)
|
|
357
416
|
throw new Error('buildIndividualDidWeb requires providerDidWeb.');
|
|
417
|
+
if (secureIdTypeIndividual || secureIdValueIndividual) {
|
|
418
|
+
if (!secureIdTypeIndividual || !secureIdValueIndividual) {
|
|
419
|
+
throw new Error('buildIndividualDidWeb requires both secure individual id type and value.');
|
|
420
|
+
}
|
|
421
|
+
if (!MULTIBASE_SHA3_384_PATTERN.test(secureIdValueIndividual)) {
|
|
422
|
+
throw new Error('buildIndividualDidWeb requires secureIdValueIndividual as bare multibase base58btc.');
|
|
423
|
+
}
|
|
424
|
+
return [
|
|
425
|
+
providerDidWeb,
|
|
426
|
+
IndividualDidMarkers.Individual,
|
|
427
|
+
secureIdTypeIndividual,
|
|
428
|
+
secureIdValueIndividual,
|
|
429
|
+
].join(':');
|
|
430
|
+
}
|
|
358
431
|
if (!individualId)
|
|
359
432
|
throw new Error('buildIndividualDidWeb requires individualId.');
|
|
360
433
|
return [
|
|
@@ -368,20 +441,83 @@ export function buildIndividualDidWeb(input) {
|
|
|
368
441
|
* Builds the canonical member DID under an individual DID.
|
|
369
442
|
*
|
|
370
443
|
* Canonical form:
|
|
371
|
-
* `did:web:...:individual
|
|
444
|
+
* `did:web:...:individual:<type>:<secure-value>:member:<secure-member-value>:<role-value>`
|
|
372
445
|
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
* the claims layer.
|
|
446
|
+
* `roleType` is mandatory input so callers cannot accidentally lose the coded
|
|
447
|
+
* role semantics. Only `roleValue` is serialized in the DID because the full
|
|
448
|
+
* FHIR token (`system|value`) remains in the protected claims/licence layer.
|
|
376
449
|
*/
|
|
377
450
|
export function buildIndividualMemberDidWeb(input) {
|
|
378
451
|
const individualDidWeb = String(input.individualDidWeb || '').trim();
|
|
379
452
|
if (!individualDidWeb)
|
|
380
453
|
throw new Error('buildIndividualMemberDidWeb requires individualDidWeb.');
|
|
454
|
+
const memberId = String(input.memberId || '').trim();
|
|
455
|
+
const roleType = String(input.roleType || '').trim();
|
|
456
|
+
const roleValue = String(input.roleValue || '').trim();
|
|
457
|
+
if (memberId || roleType || roleValue) {
|
|
458
|
+
if (!MULTIBASE_SHA3_384_PATTERN.test(memberId)) {
|
|
459
|
+
throw new Error('buildIndividualMemberDidWeb requires memberId as bare multibase base58btc.');
|
|
460
|
+
}
|
|
461
|
+
if (!roleType || !roleValue) {
|
|
462
|
+
throw new Error('buildIndividualMemberDidWeb requires both roleType and roleValue.');
|
|
463
|
+
}
|
|
464
|
+
return [individualDidWeb, IndividualDidMarkers.Member, memberId, roleValue].join(':');
|
|
465
|
+
}
|
|
381
466
|
return [
|
|
382
467
|
individualDidWeb,
|
|
383
468
|
IndividualDidMarkers.Member,
|
|
384
469
|
IndividualDidMarkers.Role,
|
|
385
|
-
toDidMemberRoleCode(input.role),
|
|
470
|
+
toDidMemberRoleCode(String(input.role || '')),
|
|
386
471
|
].join(':');
|
|
387
472
|
}
|
|
473
|
+
/**
|
|
474
|
+
* Builds a complete hosted individual-member DID directly from the private
|
|
475
|
+
* identifiers already held by an authorized BFF.
|
|
476
|
+
*
|
|
477
|
+
* This is the integration helper for portals: the provider DID returned by GW,
|
|
478
|
+
* the individual's private UUID or other governed identifier, the logged-in
|
|
479
|
+
* member's email/phone/private identifier, and the protected role type/value
|
|
480
|
+
* are sufficient. Neither private identifier is serialized in the result.
|
|
481
|
+
*/
|
|
482
|
+
export function buildIndividualMemberDidWebFromPrivateIdentifiers(input) {
|
|
483
|
+
const individualDidWeb = buildIndividualDidWeb({
|
|
484
|
+
providerDidWeb: input.providerDidWeb,
|
|
485
|
+
secureIdTypeIndividual: input.secureIdTypeIndividual,
|
|
486
|
+
secureIdValueIndividual: buildSecureIdValueIndividual({
|
|
487
|
+
secureIdTypeIndividual: input.secureIdTypeIndividual,
|
|
488
|
+
privateIdValueIndividual: input.privateIdValueIndividual,
|
|
489
|
+
}),
|
|
490
|
+
});
|
|
491
|
+
return buildIndividualMemberDidWeb({
|
|
492
|
+
individualDidWeb,
|
|
493
|
+
memberId: buildSecureIdValueMember({
|
|
494
|
+
secureIdTypeMember: input.secureIdTypeMember,
|
|
495
|
+
privateIdValueMember: input.privateIdValueMember,
|
|
496
|
+
}),
|
|
497
|
+
roleType: input.roleType,
|
|
498
|
+
roleValue: input.roleValue,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Parses one hosted individual-member DID without interpreting its role value
|
|
503
|
+
* as authorization. The complete role system and value must still be checked
|
|
504
|
+
* against the protected licence or credential by the consuming gateway.
|
|
505
|
+
*/
|
|
506
|
+
export function parseIndividualMemberDidWeb(didWeb) {
|
|
507
|
+
const candidate = String(didWeb || '').trim();
|
|
508
|
+
const marker = `:${IndividualDidMarkers.Member}:`;
|
|
509
|
+
const markerOffset = candidate.lastIndexOf(marker);
|
|
510
|
+
if (!candidate.startsWith('did:web:') || markerOffset < 0) {
|
|
511
|
+
throw new Error('Invalid hosted individual member DID.');
|
|
512
|
+
}
|
|
513
|
+
const individualDidWeb = candidate.slice(0, markerOffset);
|
|
514
|
+
const suffix = candidate.slice(markerOffset + marker.length).split(':');
|
|
515
|
+
const [memberId, roleValue, ...unexpected] = suffix;
|
|
516
|
+
if (!individualDidWeb.includes(`:${IndividualDidMarkers.Individual}:`)
|
|
517
|
+
|| unexpected.length > 0
|
|
518
|
+
|| !MULTIBASE_SHA3_384_PATTERN.test(String(memberId || ''))
|
|
519
|
+
|| !String(roleValue || '').trim()) {
|
|
520
|
+
throw new Error('Invalid hosted individual member DID.');
|
|
521
|
+
}
|
|
522
|
+
return { individualDidWeb, memberId, roleValue };
|
|
523
|
+
}
|
|
@@ -74,21 +74,33 @@ export function projectOrganizationEmployeeLifecycle(input) {
|
|
|
74
74
|
const claims = record(employee.claims) || record(record(employee.meta)?.claims) || {};
|
|
75
75
|
const resourceId = text(employee.id);
|
|
76
76
|
const employeeDid = text(claims[ClaimsPersonSchemaorg.identifier]);
|
|
77
|
+
const employeeEmail = text(claims[ClaimsPersonSchemaorg.email]);
|
|
78
|
+
const employeeRole = text(claims[ClaimsPersonSchemaorg.hasOccupationalRoleValue]);
|
|
77
79
|
const license = licenses.find((candidate) => {
|
|
78
80
|
const meta = record(candidate.meta) || {};
|
|
79
81
|
const subjectId = text(meta.subjectId);
|
|
80
|
-
|
|
82
|
+
if (subjectId === resourceId || subjectId === employeeDid)
|
|
83
|
+
return true;
|
|
84
|
+
const licenseClaims = record(meta.claims) || record(candidate.claims) || {};
|
|
85
|
+
return Boolean(employeeEmail && employeeRole
|
|
86
|
+
&& text(licenseClaims[ClaimsPersonSchemaorg.email]).toLowerCase() === employeeEmail.toLowerCase()
|
|
87
|
+
&& text(licenseClaims[ClaimsPersonSchemaorg.hasOccupationalRoleValue]) === employeeRole);
|
|
81
88
|
});
|
|
82
89
|
const status = normalizeEmployeeDirectoryStatus(text(employee.status) || text(record(employee.meta)?.status));
|
|
83
90
|
if (!license)
|
|
84
91
|
return {
|
|
85
92
|
resourceId,
|
|
86
|
-
email:
|
|
87
|
-
roleCode:
|
|
93
|
+
email: employeeEmail,
|
|
94
|
+
roleCode: employeeRole,
|
|
88
95
|
employeeDid,
|
|
89
96
|
status,
|
|
90
97
|
};
|
|
91
98
|
const meta = record(license.meta) || {};
|
|
99
|
+
const licenseClaims = record(meta.claims) || record(license.claims) || {};
|
|
100
|
+
const licensedEmail = text(licenseClaims[ClaimsPersonSchemaorg.email]) || employeeEmail;
|
|
101
|
+
const licensedPhone = text(licenseClaims[ClaimsPersonSchemaorg.telephone]);
|
|
102
|
+
const ownerContact = licensedEmail || licensedPhone;
|
|
103
|
+
const ownerContactKind = licensedEmail ? 'email' : licensedPhone ? 'phone' : undefined;
|
|
92
104
|
const bindings = Array.isArray(meta.deviceBindings) ? meta.deviceBindings.map(record).filter(isRecord) : [];
|
|
93
105
|
const devices = bindings.map((binding) => {
|
|
94
106
|
const info = record(binding.deviceInfo) || {};
|
|
@@ -99,12 +111,15 @@ export function projectOrganizationEmployeeLifecycle(input) {
|
|
|
99
111
|
status: binding.status === DeviceBindingStatuses.Revoked
|
|
100
112
|
? DeviceBindingStatuses.Revoked
|
|
101
113
|
: DeviceBindingStatuses.Active,
|
|
114
|
+
...(ownerContact ? { ownerContact } : {}),
|
|
115
|
+
...(ownerContactKind ? { ownerContactKind } : {}),
|
|
116
|
+
...(positiveNumber(binding.activatedAt) ? { activatedAt: positiveNumber(binding.activatedAt) } : {}),
|
|
102
117
|
};
|
|
103
118
|
}).filter((device) => Boolean(device.clientId));
|
|
104
119
|
return {
|
|
105
120
|
resourceId,
|
|
106
|
-
email:
|
|
107
|
-
roleCode:
|
|
121
|
+
email: employeeEmail,
|
|
122
|
+
roleCode: employeeRole,
|
|
108
123
|
employeeDid,
|
|
109
124
|
status,
|
|
110
125
|
license: {
|
|
@@ -156,3 +171,7 @@ function positiveInteger(value) {
|
|
|
156
171
|
const parsed = Number(value);
|
|
157
172
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
|
|
158
173
|
}
|
|
174
|
+
function positiveNumber(value) {
|
|
175
|
+
const parsed = Number(value);
|
|
176
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
177
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const HL7_ACT_REASON_CODE_SYSTEM
|
|
1
|
+
export declare const HL7_ACT_REASON_CODE_SYSTEM: "http://terminology.hl7.org/CodeSystem/v3-ActReason";
|
|
2
2
|
export type ServiceActReasonCoding = Readonly<{
|
|
3
3
|
system: string;
|
|
4
4
|
code: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
-
|
|
2
|
+
import { FhirCodeSystems } from '../constants/fhir-code-systems.js';
|
|
3
|
+
export const HL7_ACT_REASON_CODE_SYSTEM = FhirCodeSystems.ActReason;
|
|
3
4
|
function normalizeText(value) {
|
|
4
5
|
return typeof value === 'string' ? value.trim() : '';
|
|
5
6
|
}
|