fhir-data-utils-ts 0.2.4 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex/skills/govern-fhir-data-utilities/SKILL.md +58 -0
- package/.codex/skills/govern-fhir-data-utilities/agents/openai.yaml +4 -0
- package/.codex/skills/govern-fhir-observation-components/SKILL.md +18 -0
- package/CHANGELOG.md +30 -0
- package/README.md +39 -0
- package/dist/builders/immunization-graph.d.ts +36 -0
- package/dist/builders/immunization-graph.js +115 -0
- package/dist/builders/immunization-reminders.d.ts +35 -0
- package/dist/builders/immunization-reminders.js +104 -0
- package/dist/builders/index.d.ts +2 -0
- package/dist/builders/index.js +2 -0
- package/dist/claim-helpers/claim-list-helpers.d.ts +21 -0
- package/dist/claim-helpers/claim-list-helpers.js +54 -0
- package/dist/claim-helpers/claims-helpers-allergy-intolerance.d.ts +18 -0
- package/dist/claim-helpers/claims-helpers-allergy-intolerance.js +65 -0
- package/dist/claim-helpers/claims-helpers-appointment-response.d.ts +8 -0
- package/dist/claim-helpers/claims-helpers-appointment-response.js +20 -0
- package/dist/claim-helpers/claims-helpers-appointment.d.ts +10 -0
- package/dist/claim-helpers/claims-helpers-appointment.js +26 -0
- package/dist/claim-helpers/claims-helpers-care-plan.d.ts +8 -0
- package/dist/claim-helpers/claims-helpers-care-plan.js +20 -0
- package/dist/claim-helpers/claims-helpers-clinical-impression.d.ts +10 -0
- package/dist/claim-helpers/claims-helpers-clinical-impression.js +26 -0
- package/dist/claim-helpers/claims-helpers-communication.d.ts +19 -0
- package/dist/claim-helpers/claims-helpers-communication.js +63 -0
- package/dist/claim-helpers/claims-helpers-composition.d.ts +12 -0
- package/dist/claim-helpers/claims-helpers-composition.js +32 -0
- package/dist/claim-helpers/claims-helpers-condition.d.ts +18 -0
- package/dist/claim-helpers/claims-helpers-condition.js +65 -0
- package/dist/claim-helpers/claims-helpers-coverage.d.ts +10 -0
- package/dist/claim-helpers/claims-helpers-coverage.js +26 -0
- package/dist/claim-helpers/claims-helpers-device-use-statement.d.ts +8 -0
- package/dist/claim-helpers/claims-helpers-device-use-statement.js +20 -0
- package/dist/claim-helpers/claims-helpers-device.d.ts +8 -0
- package/dist/claim-helpers/claims-helpers-device.js +20 -0
- package/dist/claim-helpers/claims-helpers-diagnostic-report.d.ts +16 -0
- package/dist/claim-helpers/claims-helpers-diagnostic-report.js +47 -0
- package/dist/claim-helpers/claims-helpers-document-reference.d.ts +8 -0
- package/dist/claim-helpers/claims-helpers-document-reference.js +20 -0
- package/dist/claim-helpers/claims-helpers-encounter.d.ts +10 -0
- package/dist/claim-helpers/claims-helpers-encounter.js +26 -0
- package/dist/claim-helpers/claims-helpers-flag.d.ts +8 -0
- package/dist/claim-helpers/claims-helpers-flag.js +20 -0
- package/dist/claim-helpers/claims-helpers-immunization.d.ts +8 -0
- package/dist/claim-helpers/claims-helpers-immunization.js +20 -0
- package/dist/claim-helpers/claims-helpers-location.d.ts +10 -0
- package/dist/claim-helpers/claims-helpers-location.js +26 -0
- package/dist/claim-helpers/claims-helpers-medication-statement.d.ts +96 -0
- package/dist/claim-helpers/claims-helpers-medication-statement.js +278 -0
- package/dist/claim-helpers/claims-helpers-observation.d.ts +8 -0
- package/dist/claim-helpers/claims-helpers-observation.js +20 -0
- package/dist/claim-helpers/claims-helpers-organization.d.ts +12 -0
- package/dist/claim-helpers/claims-helpers-organization.js +32 -0
- package/dist/claim-helpers/claims-helpers-procedure.d.ts +8 -0
- package/dist/claim-helpers/claims-helpers-procedure.js +20 -0
- package/dist/claim-helpers/claims-helpers-related-person.d.ts +22 -0
- package/dist/claim-helpers/claims-helpers-related-person.js +53 -0
- package/dist/claim-helpers/index.d.ts +23 -0
- package/dist/claim-helpers/index.js +23 -0
- package/dist/claims/allergy-intolerance-claims.d.ts +153 -0
- package/dist/claims/allergy-intolerance-claims.js +194 -0
- package/dist/claims/appointment-claims.d.ts +226 -0
- package/dist/claims/appointment-claims.js +218 -0
- package/dist/claims/appointment-response-claims.d.ts +63 -0
- package/dist/claims/appointment-response-claims.js +58 -0
- package/dist/claims/care-plan-claims.d.ts +37 -0
- package/dist/claims/care-plan-claims.js +59 -0
- package/dist/claims/claim-types.d.ts +9 -0
- package/dist/claims/claim-types.js +3 -0
- package/dist/claims/clinical-impression-claims.d.ts +17 -0
- package/dist/claims/clinical-impression-claims.js +30 -0
- package/dist/claims/communication-claims.d.ts +55 -0
- package/dist/claims/communication-claims.js +57 -0
- package/dist/claims/composition-claims.d.ts +27 -0
- package/dist/claims/composition-claims.js +27 -0
- package/dist/claims/condition-claims.d.ts +79 -0
- package/dist/claims/condition-claims.js +104 -0
- package/dist/claims/consent-claims.d.ts +195 -0
- package/dist/claims/consent-claims.js +74 -0
- package/dist/claims/coverage-claims.d.ts +16 -0
- package/dist/claims/coverage-claims.js +28 -0
- package/dist/claims/device-claims.d.ts +20 -0
- package/dist/claims/device-claims.js +36 -0
- package/dist/claims/device-use-statement-claims.d.ts +17 -0
- package/dist/claims/device-use-statement-claims.js +28 -0
- package/dist/claims/diagnostic-report-claims.d.ts +109 -0
- package/dist/claims/diagnostic-report-claims.js +120 -0
- package/dist/claims/document-reference-claims.d.ts +39 -0
- package/dist/claims/document-reference-claims.js +96 -0
- package/dist/claims/encounter-claims.d.ts +18 -0
- package/dist/claims/encounter-claims.js +32 -0
- package/dist/claims/flag-claims.d.ts +19 -0
- package/dist/claims/flag-claims.js +33 -0
- package/dist/claims/immunization-claims.d.ts +31 -0
- package/dist/claims/immunization-claims.js +54 -0
- package/dist/claims/immunization-recommendation-claims.d.ts +19 -0
- package/dist/claims/immunization-recommendation-claims.js +26 -0
- package/dist/claims/index.d.ts +29 -0
- package/dist/claims/index.js +29 -0
- package/dist/claims/invoice-claims.d.ts +277 -0
- package/dist/claims/invoice-claims.js +357 -0
- package/dist/claims/location-claims.d.ts +22 -0
- package/dist/claims/location-claims.js +34 -0
- package/dist/claims/medication-claims.d.ts +15 -0
- package/dist/claims/medication-claims.js +23 -0
- package/dist/claims/medication-statement-claims.d.ts +539 -0
- package/dist/claims/medication-statement-claims.js +469 -0
- package/dist/claims/organization-claims.d.ts +18 -0
- package/dist/claims/organization-claims.js +27 -0
- package/dist/claims/practitioner-role-claims.d.ts +18 -0
- package/dist/claims/practitioner-role-claims.js +33 -0
- package/dist/claims/procedure-claims.d.ts +24 -0
- package/dist/claims/procedure-claims.js +44 -0
- package/dist/claims/related-person-claims.d.ts +30 -0
- package/dist/claims/related-person-claims.js +44 -0
- package/dist/claims/research-subject-claims.d.ts +4 -0
- package/dist/claims/research-subject-claims.js +4 -0
- package/dist/claims/task-claims.d.ts +61 -0
- package/dist/claims/task-claims.js +64 -0
- package/dist/clinical-terminology.d.ts +73 -0
- package/dist/clinical-terminology.js +77 -0
- package/dist/constants/clinical-statuses.d.ts +102 -0
- package/dist/constants/clinical-statuses.js +93 -0
- package/dist/constants/fhir-code-systems.d.ts +15 -0
- package/dist/constants/fhir-code-systems.js +15 -0
- package/dist/constants/fhir-resource-types.d.ts +162 -0
- package/dist/constants/fhir-resource-types.js +70 -0
- package/dist/constants/fhir-versions.d.ts +10 -0
- package/dist/constants/fhir-versions.js +10 -0
- package/dist/constants/index.d.ts +4 -0
- package/dist/constants/index.js +4 -0
- package/dist/converters/convert-allergy-intolerance.d.ts +3 -0
- package/dist/converters/convert-allergy-intolerance.js +85 -0
- package/dist/converters/convert-appointment-response.d.ts +3 -0
- package/dist/converters/convert-appointment-response.js +32 -0
- package/dist/converters/convert-appointment.d.ts +3 -0
- package/dist/converters/convert-appointment.js +61 -0
- package/dist/converters/convert-care-plan.d.ts +3 -0
- package/dist/converters/convert-care-plan.js +93 -0
- package/dist/converters/convert-clinical-impression.d.ts +3 -0
- package/dist/converters/convert-clinical-impression.js +42 -0
- package/dist/converters/convert-composition.d.ts +3 -0
- package/dist/converters/convert-composition.js +70 -0
- package/dist/converters/convert-condition.d.ts +3 -0
- package/dist/converters/convert-condition.js +51 -0
- package/dist/converters/convert-consent.d.ts +9 -0
- package/dist/converters/convert-consent.js +174 -0
- package/dist/converters/convert-coverage.d.ts +3 -0
- package/dist/converters/convert-coverage.js +51 -0
- package/dist/converters/convert-device-use-statement.d.ts +3 -0
- package/dist/converters/convert-device-use-statement.js +36 -0
- package/dist/converters/convert-device.d.ts +3 -0
- package/dist/converters/convert-device.js +48 -0
- package/dist/converters/convert-diagnostic-report.d.ts +3 -0
- package/dist/converters/convert-diagnostic-report.js +63 -0
- package/dist/converters/convert-document-reference.d.ts +3 -0
- package/dist/converters/convert-document-reference.js +54 -0
- package/dist/converters/convert-encounter.d.ts +3 -0
- package/dist/converters/convert-encounter.js +68 -0
- package/dist/converters/convert-flag.d.ts +3 -0
- package/dist/converters/convert-flag.js +42 -0
- package/dist/converters/convert-immunization.d.ts +3 -0
- package/dist/converters/convert-immunization.js +80 -0
- package/dist/converters/convert-location.d.ts +3 -0
- package/dist/converters/convert-location.js +44 -0
- package/dist/converters/convert-medication-statement.d.ts +3 -0
- package/dist/converters/convert-medication-statement.js +130 -0
- package/dist/converters/convert-observation.d.ts +33 -0
- package/dist/converters/convert-observation.js +246 -0
- package/dist/converters/convert-organization.d.ts +3 -0
- package/dist/converters/convert-organization.js +39 -0
- package/dist/converters/convert-practitioner-role.d.ts +3 -0
- package/dist/converters/convert-practitioner-role.js +62 -0
- package/dist/converters/convert-procedure.d.ts +3 -0
- package/dist/converters/convert-procedure.js +64 -0
- package/dist/converters/convert-related-person.d.ts +3 -0
- package/dist/converters/convert-related-person.js +31 -0
- package/dist/converters/convert-shared.d.ts +33 -0
- package/dist/converters/convert-shared.js +181 -0
- package/dist/converters/index.d.ts +24 -0
- package/dist/converters/index.js +24 -0
- package/dist/fhir-bundle.d.ts +9 -0
- package/dist/fhir-bundle.js +43 -0
- package/dist/fhir-search-parameters.d.ts +18 -0
- package/dist/fhir-search-parameters.js +52 -0
- package/dist/fhir-tokens.d.ts +11 -0
- package/dist/fhir-tokens.js +26 -0
- package/dist/fhir-types.d.ts +77 -0
- package/dist/fhir-types.js +1 -0
- package/dist/fhir-values.d.ts +13 -0
- package/dist/fhir-values.js +53 -0
- package/dist/group-r5.d.ts +121 -0
- package/dist/group-r5.js +301 -0
- package/dist/imaging-types.d.ts +30 -0
- package/dist/imaging-types.js +1 -0
- package/dist/immunization-flat-claims.d.ts +2 -0
- package/dist/immunization-flat-claims.js +2 -0
- package/dist/immunization-reminder-plan.d.ts +2 -0
- package/dist/immunization-reminder-plan.js +2 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +19 -0
- package/dist/observation-claims.d.ts +170 -0
- package/dist/observation-claims.js +184 -0
- package/dist/related-person.d.ts +16 -0
- package/dist/related-person.js +14 -0
- package/dist/research-study-r5.d.ts +163 -0
- package/dist/research-study-r5.js +490 -0
- package/dist/search-models/index.d.ts +7 -0
- package/dist/search-models/index.js +7 -0
- package/dist/search-models/params/AdverseEvent.params.model.d.ts +14 -0
- package/dist/search-models/params/AdverseEvent.params.model.js +16 -0
- package/dist/search-models/params/AllergyIntolerance.params.model.d.ts +24 -0
- package/dist/search-models/params/AllergyIntolerance.params.model.js +27 -0
- package/dist/search-models/params/Appointment.params.model.d.ts +12 -0
- package/dist/search-models/params/Appointment.params.model.js +14 -0
- package/dist/search-models/params/ClinicalImpression.params.model.d.ts +14 -0
- package/dist/search-models/params/ClinicalImpression.params.model.js +15 -0
- package/dist/search-models/params/Condition.params.model.d.ts +16 -0
- package/dist/search-models/params/Condition.params.model.js +17 -0
- package/dist/search-models/params/DetectedIssue.params.model.d.ts +9 -0
- package/dist/search-models/params/DetectedIssue.params.model.js +11 -0
- package/dist/search-models/params/DiagnosticReport.params.model.d.ts +13 -0
- package/dist/search-models/params/DiagnosticReport.params.model.js +14 -0
- package/dist/search-models/params/Encounter.params.model.d.ts +15 -0
- package/dist/search-models/params/Encounter.params.model.js +17 -0
- package/dist/search-models/params/Immunization.params.model.d.ts +14 -0
- package/dist/search-models/params/Immunization.params.model.js +16 -0
- package/dist/search-models/params/Medication.params.model.d.ts +35 -0
- package/dist/search-models/params/Medication.params.model.js +45 -0
- package/dist/search-models/params/Observation.params.model.d.ts +326 -0
- package/dist/search-models/params/Observation.params.model.js +244 -0
- package/dist/search-models/params/Procedure.params.model.d.ts +15 -0
- package/dist/search-models/params/Procedure.params.model.js +17 -0
- package/dist/search-models/params/Search.params.model.d.ts +75 -0
- package/dist/search-models/params/Search.params.model.js +69 -0
- package/dist/search-models/params/ServiceRequest.params.model.d.ts +14 -0
- package/dist/search-models/params/ServiceRequest.params.model.js +16 -0
- package/dist/search-models/params/Specimen.params.model.d.ts +10 -0
- package/dist/search-models/params/Specimen.params.model.js +12 -0
- package/dist/search-models/params/index.d.ts +15 -0
- package/dist/search-models/params/index.js +15 -0
- package/dist/search-models/templates/AdverseEvent.template.model.d.ts +16 -0
- package/dist/search-models/templates/AdverseEvent.template.model.js +2 -0
- package/dist/search-models/templates/AllergyIntolerance.template.model.d.ts +24 -0
- package/dist/search-models/templates/AllergyIntolerance.template.model.js +1 -0
- package/dist/search-models/templates/Appointment.template.model.d.ts +13 -0
- package/dist/search-models/templates/Appointment.template.model.js +1 -0
- package/dist/search-models/templates/ClinicalImpression.template.model.d.ts +16 -0
- package/dist/search-models/templates/ClinicalImpression.template.model.js +1 -0
- package/dist/search-models/templates/Condition.template.model.d.ts +18 -0
- package/dist/search-models/templates/Condition.template.model.js +1 -0
- package/dist/search-models/templates/DetectedIssue.template.model.d.ts +11 -0
- package/dist/search-models/templates/DetectedIssue.template.model.js +1 -0
- package/dist/search-models/templates/DiagnosticReport.template.model.d.ts +15 -0
- package/dist/search-models/templates/DiagnosticReport.template.model.js +1 -0
- package/dist/search-models/templates/Encounter.template.model.d.ts +17 -0
- package/dist/search-models/templates/Encounter.template.model.js +1 -0
- package/dist/search-models/templates/Immunization.template.model.d.ts +18 -0
- package/dist/search-models/templates/Immunization.template.model.js +2 -0
- package/dist/search-models/templates/Medication.template.model.d.ts +37 -0
- package/dist/search-models/templates/Medication.template.model.js +1 -0
- package/dist/search-models/templates/Observation.template.model.d.ts +18 -0
- package/dist/search-models/templates/Observation.template.model.js +1 -0
- package/dist/search-models/templates/Procedure.template.model.d.ts +17 -0
- package/dist/search-models/templates/Procedure.template.model.js +1 -0
- package/dist/search-models/templates/ServiceRequest.template.model.d.ts +16 -0
- package/dist/search-models/templates/ServiceRequest.template.model.js +1 -0
- package/dist/search-models/templates/Specimen.template.model.d.ts +12 -0
- package/dist/search-models/templates/Specimen.template.model.js +1 -0
- package/dist/search-models/templates/index.d.ts +14 -0
- package/dist/search-models/templates/index.js +14 -0
- package/dist/terminology-models/AtcModel.d.ts +15 -0
- package/dist/terminology-models/AtcModel.js +2 -0
- package/dist/terminology-models/CommonModels.d.ts +70 -0
- package/dist/terminology-models/CommonModels.js +55 -0
- package/dist/terminology-models/FhirModels.d.ts +60 -0
- package/dist/terminology-models/FhirModels.js +34 -0
- package/dist/terminology-models/LoincModels.d.ts +24 -0
- package/dist/terminology-models/LoincModels.js +2 -0
- package/dist/terminology-models/SnomedModels.d.ts +13 -0
- package/dist/terminology-models/SnomedModels.js +2 -0
- package/dist/terminology-models/index.d.ts +6 -0
- package/dist/terminology-models/index.js +6 -0
- package/docs/UHC_FHIR_UTILS_MIGRATION.md +51 -8
- package/package.json +83 -2
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: govern-fhir-data-utilities
|
|
3
|
+
description: Complete or audit migrations, claim catalogs, converters, builders, tests and releases in fhir-data-utils-ts. Use for shared FHIR types or utilities copied from frozen gdc-common-utils, former UHC utilities, SOS, Vet or UHC packages; raw flat-claim literals; duplicate root and family modules; Observation components; Immunization graphs; Group or ResearchStudy projections; package exports; coverage gates; or downstream promotion.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Govern FHIR Data Utilities
|
|
7
|
+
|
|
8
|
+
## Keep ownership explicit
|
|
9
|
+
|
|
10
|
+
1. Read `docs/UHC_FHIR_UTILS_MIGRATION.md` and inventory every relevant source
|
|
11
|
+
family before declaring a migration complete.
|
|
12
|
+
2. Treat `gdc-*` repositories as read-only evidence unless the user explicitly
|
|
13
|
+
changes that scope. Never patch them as part of this migration.
|
|
14
|
+
3. Keep neutral FHIR data semantics here. Keep HTTP, SMART, DIDComm, storage,
|
|
15
|
+
authorization and product policy in their owning services or sector packages.
|
|
16
|
+
4. Define every flat key once in its owning named catalog. Import that symbol in
|
|
17
|
+
converters, builders, tests and examples; never repeat a claim-path literal.
|
|
18
|
+
|
|
19
|
+
## Separate catalogs, adapters and builders
|
|
20
|
+
|
|
21
|
+
- Put claim names and specs under `src/claims/`.
|
|
22
|
+
- Put native FHIR R4/R5 projection at `src/converters/`; persistence remains
|
|
23
|
+
flat claims and native FHIR exists only at an explicit adapter boundary.
|
|
24
|
+
- Put multi-resource authoring under `src/builders/`. A root historical module
|
|
25
|
+
may remain only as a deprecated re-export shim so implementation is unique.
|
|
26
|
+
- Preserve correlations by creating one claims-first row per member, party or
|
|
27
|
+
component when parallel arrays would lose identity.
|
|
28
|
+
- Reconstruct native arrays such as `Observation.component[]` only during FHIR
|
|
29
|
+
projection. Do not invent resource-specific scalar aliases for indexing.
|
|
30
|
+
- Keep Group membership and ResearchStudy associated parties descriptive;
|
|
31
|
+
neither is a Consent, SMART scope or authorization grant.
|
|
32
|
+
|
|
33
|
+
## Change with executable contracts
|
|
34
|
+
|
|
35
|
+
1. Use Node 24 and run `npm ci` before trusting failures.
|
|
36
|
+
2. Begin every new or modified test file with the repository flow-contract
|
|
37
|
+
comment.
|
|
38
|
+
3. Write and run the smallest failing test first. Cover success, malformed
|
|
39
|
+
input, lossless round trip, catalog ownership and packed public exports.
|
|
40
|
+
4. Add data-rich converter fixtures that exercise meaningful optional fields;
|
|
41
|
+
a single happy-path assertion is not adequate migration evidence.
|
|
42
|
+
5. Run `npm run check`. Preserve the built-in coverage floors for converters,
|
|
43
|
+
builders and core FHIR utilities; raise them when practical, never lower them
|
|
44
|
+
to make a branch green.
|
|
45
|
+
6. Run `npm pack --dry-run`, then install the produced tarball in an isolated
|
|
46
|
+
temporary consumer and resolve every documented subpath.
|
|
47
|
+
|
|
48
|
+
## Release without partial promotion
|
|
49
|
+
|
|
50
|
+
1. Update JSDoc, tests, README, migration inventory, changelog and this skill in
|
|
51
|
+
the same behavior branch.
|
|
52
|
+
2. Use one patch release for one branch closure. Commit and push the branch,
|
|
53
|
+
create an explicit merge commit, push `main`, and verify matching remote refs
|
|
54
|
+
and a clean worktree.
|
|
55
|
+
3. Publish this lowest shared package before changing consumers. Verify the
|
|
56
|
+
exact registry version exists before pinning it downstream.
|
|
57
|
+
4. Never commit `file:`, Git, workspace or vendored tarball dependencies.
|
|
58
|
+
5. Report local green, merged, published and deployed as separate states.
|
|
@@ -36,6 +36,10 @@ description: Implement or audit neutral FHIR Observation claim catalogs, vital-s
|
|
|
36
36
|
composite observations.
|
|
37
37
|
- Reconstruct native `Observation.component[]` only at the explicit R4/R5
|
|
38
38
|
adapter boundary by resolving the primary entry's governed member graph.
|
|
39
|
+
- Use `observationFhirR4ToFlatGraph` for native component imports and
|
|
40
|
+
`observationFlatGraphToFhirR4` for export. The scalar
|
|
41
|
+
`observationFhirR4ToFlat` adapter must fail with
|
|
42
|
+
`observation_component_graph_required` when `component[]` is present.
|
|
39
43
|
|
|
40
44
|
## Reuse governed names
|
|
41
45
|
|
|
@@ -62,6 +66,20 @@ description: Implement or audit neutral FHIR Observation claim catalogs, vital-s
|
|
|
62
66
|
catalog and against child-owned containment markers.
|
|
63
67
|
5. Run Node 24, `npm ci`, `npm run check` and `npm pack --dry-run`.
|
|
64
68
|
|
|
69
|
+
## Audit migrations completely
|
|
70
|
+
|
|
71
|
+
- Inventory the old UHC package, `gdc-common-utils-ts`, `sos-data-utils-ts`,
|
|
72
|
+
`vet-data-utils-ts`, and the UHC/Vet/SOS SDKs before calling a migration
|
|
73
|
+
complete.
|
|
74
|
+
- Move only neutral FHIR data types, claim catalogs, conversion rules and pure
|
|
75
|
+
helpers here. Keep transport clients and sector authorization/policy in
|
|
76
|
+
their owning package.
|
|
77
|
+
- Record every migrated, retired or intentionally retained family in
|
|
78
|
+
`docs/UHC_FHIR_UTILS_MIGRATION.md`; an unmentioned file is an incomplete
|
|
79
|
+
audit.
|
|
80
|
+
- Expose each supported family through a stable package subpath and prove the
|
|
81
|
+
packed artifact, not only root source imports.
|
|
82
|
+
|
|
65
83
|
## Promote consumers
|
|
66
84
|
|
|
67
85
|
Release bottom-up. Publish this package first, install its exact registry
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.1 - 2026-09-21
|
|
4
|
+
|
|
5
|
+
- Separate canonical claim catalogs from graph builders and move Immunization
|
|
6
|
+
graph/reminder implementations under the stable `builders` subpaths, leaving
|
|
7
|
+
their historical root paths as deprecated compatibility re-exports.
|
|
8
|
+
- Add missing Medication and ImmunizationRecommendation catalogs, Group and
|
|
9
|
+
ResearchStudy named claim constants, legacy-read aliases and missing neutral
|
|
10
|
+
FHIR resource type constants; remove duplicated flat-claim literals from
|
|
11
|
+
builders and converters.
|
|
12
|
+
- Correct impossible calendar-date acceptance, empty list persistence and
|
|
13
|
+
nested `meta.claims` leakage through generic fallback flattening.
|
|
14
|
+
- Expand executable contracts to the complete converter/helper matrix, rich
|
|
15
|
+
optional resource fields, FHIR primitives/search/Bundle behavior,
|
|
16
|
+
Immunization graphs and Group/ResearchStudy row boundaries.
|
|
17
|
+
- Enforce coverage and packed-subpath gates as part of the release contract.
|
|
18
|
+
|
|
19
|
+
## 0.3.0 - 2026-09-21
|
|
20
|
+
|
|
21
|
+
- Consolidate the complete product-neutral claim catalogs, claim helpers and
|
|
22
|
+
R4/R5 converters previously exposed from `gdc-common-utils-ts`, without
|
|
23
|
+
modifying that frozen source repository.
|
|
24
|
+
- Recover strict FHIR primitives, value/search/token utilities, Bundle readers,
|
|
25
|
+
resource search/template types, terminology model types, RelatedPerson and
|
|
26
|
+
telecom helpers, and DICOMDIR structural types from the retired UHC package.
|
|
27
|
+
- Move cross-sector terminology, Immunization graph/reminder, Group R5 and
|
|
28
|
+
ResearchStudy R5 contracts that existed only in SOS or Vet data packages.
|
|
29
|
+
- Require component Observations to use independently indexable graph entries;
|
|
30
|
+
deprecated JSON-array component claims remain read-only compatibility input.
|
|
31
|
+
- Add stable package subpaths for every migrated contract family.
|
|
32
|
+
|
|
3
33
|
## 0.2.4 - 2026-09-21
|
|
4
34
|
|
|
5
35
|
- Restore the canonical composite-Observation resource graph: the primary
|
package/README.md
CHANGED
|
@@ -29,6 +29,32 @@ through `<ResourceType>.contained-reference-list`; children do not carry
|
|
|
29
29
|
as `<ResourceType>.language`, `.narrative-status` and `.xhtml`. Native FHIR is
|
|
30
30
|
materialized only by an explicit R4/R5/R6 import or export adapter.
|
|
31
31
|
|
|
32
|
+
## Public contract
|
|
33
|
+
|
|
34
|
+
The root export and stable subpaths provide:
|
|
35
|
+
|
|
36
|
+
- strict version-neutral FHIR datatypes, value/token helpers, Bundle traversal
|
|
37
|
+
and typed search parsing/building;
|
|
38
|
+
- complete flat-claim catalogs and claim helpers for the resource families
|
|
39
|
+
formerly scattered through `gdc-common-utils-ts`;
|
|
40
|
+
- explicit R4/R5 conversion adapters, including Consent and PractitionerRole;
|
|
41
|
+
- the recovered UHC resource search/template types, terminology model types,
|
|
42
|
+
RelatedPerson/telecom helpers and type-only DICOMDIR tree contract;
|
|
43
|
+
- cross-sector terminology, Immunization graphs/reminders, and FHIR R5 Group
|
|
44
|
+
and ResearchStudy contracts previously located only in SOS or Vet packages.
|
|
45
|
+
|
|
46
|
+
Claim catalogs and graph builders are deliberately different surfaces.
|
|
47
|
+
`fhir-data-utils-ts/claims` owns canonical storage names and their specs;
|
|
48
|
+
`fhir-data-utils-ts/builders` authors correlated multi-resource graphs using
|
|
49
|
+
those catalogs. The old `/immunization-flat-claims` and
|
|
50
|
+
`/immunization-reminder-plan` paths are deprecated compatibility re-exports;
|
|
51
|
+
new code imports `/builders` or `/builders/immunization`.
|
|
52
|
+
|
|
53
|
+
No consumer should copy claim paths or rebuild these structures with literals.
|
|
54
|
+
Use `fhir-data-utils-ts/claims`, `/converters`, `/fhir-bundle`,
|
|
55
|
+
`/fhir-search-parameters`, `/clinical-terminology`, `/group-r5` or
|
|
56
|
+
`/research-study-r5` as appropriate.
|
|
57
|
+
|
|
32
58
|
## Observation components
|
|
33
59
|
|
|
34
60
|
Composite observations use a claims-first resource graph. The primary
|
|
@@ -44,6 +70,12 @@ aliases are read-only compatibility inputs. Current writers emit none of them.
|
|
|
44
70
|
Components never use `is-contained`, `contained-parent-reference` or the
|
|
45
71
|
generic contained-resource link.
|
|
46
72
|
|
|
73
|
+
This is why blood pressure does not have writable `bp-*` claims. Systolic and
|
|
74
|
+
diastolic are independently indexed reduced Observation rows linked by the
|
|
75
|
+
parent's `Observation.has-member`; the R4/R5 adapter alone reconstructs native
|
|
76
|
+
`component[]`. The same representation works for future assessment scales
|
|
77
|
+
without inventing a new flat-claim family for each scale.
|
|
78
|
+
|
|
47
79
|
`buildVitalSignObservation` owns the graph, canonical displays and optional
|
|
48
80
|
`Observation.user-selected` provenance flag. Consumers submit its `entries`
|
|
49
81
|
without reconstructing component claims or relationships.
|
|
@@ -70,3 +102,10 @@ DataConv, Vet and UHC share one neutral review contract from
|
|
|
70
102
|
The package exports builders, traversal/confirmation helpers and
|
|
71
103
|
`CODING_REVIEW_EXAMPLES`. Tests and consumers reuse them instead of duplicating
|
|
72
104
|
claim strings, terminology identifiers, codes or UUIDs.
|
|
105
|
+
|
|
106
|
+
## Verification gate
|
|
107
|
+
|
|
108
|
+
`npm run check` runs strict type checking, all contract tests and built-in
|
|
109
|
+
coverage over converters, builders and core FHIR utilities. The package also
|
|
110
|
+
tests every stable export subpath. Release validation additionally inspects the
|
|
111
|
+
packed artifact and installs it in an isolated consumer before publication.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type FlatClaimResourceEntry } from '../flat-claim-resource-graph.js';
|
|
2
|
+
import { type ImmunizationReminderChannel } from './immunization-reminders.js';
|
|
3
|
+
export type ImmunizationCoding = Readonly<{
|
|
4
|
+
system: string;
|
|
5
|
+
code: string;
|
|
6
|
+
display?: string;
|
|
7
|
+
text?: string;
|
|
8
|
+
}>;
|
|
9
|
+
export type ImmunizationFlatInput = Readonly<{
|
|
10
|
+
entryId: string;
|
|
11
|
+
identifier?: string;
|
|
12
|
+
subjectReference: string;
|
|
13
|
+
administrationDate: string;
|
|
14
|
+
vaccineCode: ImmunizationCoding;
|
|
15
|
+
performerReference?: string;
|
|
16
|
+
targetDiseases?: readonly ImmunizationCoding[];
|
|
17
|
+
nextDoseDate?: string;
|
|
18
|
+
/** FHIR dateTime when the recommendation was created; required with nextDoseDate. */
|
|
19
|
+
recommendationDate?: string;
|
|
20
|
+
reminderChannels?: readonly ImmunizationReminderChannel[];
|
|
21
|
+
medication?: Readonly<{
|
|
22
|
+
entryId: string;
|
|
23
|
+
productName: string;
|
|
24
|
+
identifiers?: readonly Readonly<{
|
|
25
|
+
system: string;
|
|
26
|
+
value: string;
|
|
27
|
+
}>[];
|
|
28
|
+
manufacturer?: string;
|
|
29
|
+
lotNumber?: string;
|
|
30
|
+
expirationDate?: string;
|
|
31
|
+
barcode?: string;
|
|
32
|
+
}>;
|
|
33
|
+
attachments?: readonly FlatClaimResourceEntry[];
|
|
34
|
+
}>;
|
|
35
|
+
/** Builds the shared claims-first human/animal immunization resource graph. */
|
|
36
|
+
export declare function buildImmunizationFlatGraph(input: ImmunizationFlatInput): readonly FlatClaimResourceEntry[];
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// Copyright 2026 ConnectHealth.info (Connecting Solution & Applications Ltd.) under the Apache License, Version 2.0.
|
|
2
|
+
import { buildFlatClaimResourceEntry, linkFlatClaimResourceEntries, } from '../flat-claim-resource-graph.js';
|
|
3
|
+
import { buildImmunizationReminderTasks, ImmunizationReminderChannels, } from './immunization-reminders.js';
|
|
4
|
+
import { ImmunizationClaim } from '../claims/immunization-claims.js';
|
|
5
|
+
import { ImmunizationRecommendationClaim, ImmunizationRecommendationCodes, } from '../claims/immunization-recommendation-claims.js';
|
|
6
|
+
import { MedicationClaim } from '../claims/medication-claims.js';
|
|
7
|
+
import { ResourceTypesFhirR4 } from '../constants/fhir-resource-types.js';
|
|
8
|
+
/** Builds the shared claims-first human/animal immunization resource graph. */
|
|
9
|
+
export function buildImmunizationFlatGraph(input) {
|
|
10
|
+
const vaccineCode = codingToken(input.vaccineCode);
|
|
11
|
+
const claims = {
|
|
12
|
+
[ImmunizationClaim.Status]: 'completed',
|
|
13
|
+
[ImmunizationClaim.Patient]: required(input.subjectReference, 'immunization_subject_required'),
|
|
14
|
+
[ImmunizationClaim.Date]: isoDate(input.administrationDate, 'immunization_date_invalid'),
|
|
15
|
+
[ImmunizationClaim.VaccineCode]: vaccineCode,
|
|
16
|
+
};
|
|
17
|
+
if (input.identifier)
|
|
18
|
+
claims[ImmunizationClaim.Identifier] = required(input.identifier, 'immunization_identifier_invalid');
|
|
19
|
+
if (input.vaccineCode.display?.trim())
|
|
20
|
+
claims[ImmunizationClaim.VaccineCodeDisplay] = input.vaccineCode.display.trim();
|
|
21
|
+
if (input.vaccineCode.text?.trim())
|
|
22
|
+
claims[ImmunizationClaim.VaccineCodeText] = input.vaccineCode.text.trim();
|
|
23
|
+
if (input.performerReference)
|
|
24
|
+
claims[ImmunizationClaim.Performer] = required(input.performerReference, 'immunization_performer_invalid');
|
|
25
|
+
if (input.targetDiseases?.length) {
|
|
26
|
+
claims[ImmunizationClaim.TargetDisease] = input.targetDiseases.map(codingToken).join(',');
|
|
27
|
+
claims[ImmunizationClaim.TargetDiseaseDisplay] = input.targetDiseases.map(value => value.display?.trim() ?? '').join(',');
|
|
28
|
+
claims[ImmunizationClaim.TargetDiseaseText] = input.targetDiseases.map(value => value.text?.trim() ?? '').join(',');
|
|
29
|
+
}
|
|
30
|
+
const immunization = buildFlatClaimResourceEntry({ entryId: input.entryId, resourceType: ResourceTypesFhirR4.Immunization, claims });
|
|
31
|
+
const children = [];
|
|
32
|
+
if (input.medication)
|
|
33
|
+
children.push(buildMedicationEntry(input.medication));
|
|
34
|
+
if (input.nextDoseDate) {
|
|
35
|
+
const recommendationId = `${input.entryId}-recommendation`;
|
|
36
|
+
const recommendation = buildFlatClaimResourceEntry({
|
|
37
|
+
entryId: recommendationId,
|
|
38
|
+
resourceType: ResourceTypesFhirR4.ImmunizationRecommendation,
|
|
39
|
+
claims: {
|
|
40
|
+
[ImmunizationRecommendationClaim.Patient]: input.subjectReference,
|
|
41
|
+
[ImmunizationRecommendationClaim.Date]: isoDate(required(input.recommendationDate, 'immunization_recommendation_date_required'), 'immunization_recommendation_date_invalid'),
|
|
42
|
+
[ImmunizationRecommendationClaim.VaccineCode]: vaccineCode,
|
|
43
|
+
[ImmunizationRecommendationClaim.ForecastStatus]: ImmunizationRecommendationCodes.ForecastDue,
|
|
44
|
+
[ImmunizationRecommendationClaim.DateCriterionCode]: ImmunizationRecommendationCodes.RecommendedDate,
|
|
45
|
+
[ImmunizationRecommendationClaim.DateCriterionValue]: isoDate(input.nextDoseDate, 'immunization_next_dose_date_invalid'),
|
|
46
|
+
[ImmunizationRecommendationClaim.SupportingImmunization]: `${ResourceTypesFhirR4.Immunization}/${input.entryId}`,
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
const tasks = buildImmunizationReminderTasks({
|
|
50
|
+
entryIdPrefix: recommendationId,
|
|
51
|
+
recommendationReference: recommendation.reference,
|
|
52
|
+
subjectReference: input.subjectReference,
|
|
53
|
+
coverageEndDate: input.nextDoseDate,
|
|
54
|
+
channelCandidates: input.reminderChannels ?? ImmunizationReminderChannels,
|
|
55
|
+
});
|
|
56
|
+
children.push(recommendation, ...tasks);
|
|
57
|
+
}
|
|
58
|
+
for (const attachment of input.attachments ?? []) {
|
|
59
|
+
if (attachment.resourceType !== ResourceTypesFhirR4.DocumentReference)
|
|
60
|
+
throw new TypeError('immunization_attachment_invalid');
|
|
61
|
+
children.push(attachment);
|
|
62
|
+
}
|
|
63
|
+
const graph = [immunization, ...children];
|
|
64
|
+
const linkedToImmunization = children.length
|
|
65
|
+
? linkFlatClaimResourceEntries(graph, {
|
|
66
|
+
parentEntryId: input.entryId,
|
|
67
|
+
childEntryIds: children.filter(entry => entry.resourceType !== ResourceTypesFhirR4.Task).map(entry => entry.entryId),
|
|
68
|
+
})
|
|
69
|
+
: graph;
|
|
70
|
+
const recommendation = linkedToImmunization.find(entry => entry.resourceType === ResourceTypesFhirR4.ImmunizationRecommendation);
|
|
71
|
+
const tasks = linkedToImmunization.filter(entry => entry.resourceType === ResourceTypesFhirR4.Task);
|
|
72
|
+
return recommendation && tasks.length
|
|
73
|
+
? linkFlatClaimResourceEntries(linkedToImmunization, {
|
|
74
|
+
parentEntryId: recommendation.entryId,
|
|
75
|
+
childEntryIds: tasks.map(entry => entry.entryId),
|
|
76
|
+
})
|
|
77
|
+
: linkedToImmunization;
|
|
78
|
+
}
|
|
79
|
+
function buildMedicationEntry(input) {
|
|
80
|
+
const claims = {
|
|
81
|
+
[MedicationClaim.Code]: required(input.productName, 'medication_product_required'),
|
|
82
|
+
[MedicationClaim.CodeText]: required(input.productName, 'medication_product_required'),
|
|
83
|
+
};
|
|
84
|
+
if (input.identifiers?.length)
|
|
85
|
+
claims[MedicationClaim.Identifier] = input.identifiers
|
|
86
|
+
.map(({ system, value }) => `${required(system, 'medication_identifier_invalid')}|${required(value, 'medication_identifier_invalid')}`)
|
|
87
|
+
.join(',');
|
|
88
|
+
if (input.manufacturer?.trim())
|
|
89
|
+
claims[MedicationClaim.Manufacturer] = input.manufacturer.trim();
|
|
90
|
+
if (input.lotNumber?.trim())
|
|
91
|
+
claims[MedicationClaim.LotNumber] = input.lotNumber.trim();
|
|
92
|
+
if (input.expirationDate)
|
|
93
|
+
claims[MedicationClaim.ExpirationDate] = isoDate(input.expirationDate, 'medication_expiration_date_invalid');
|
|
94
|
+
if (input.barcode?.trim())
|
|
95
|
+
claims[MedicationClaim.SerialNumber] = input.barcode.trim();
|
|
96
|
+
return buildFlatClaimResourceEntry({ entryId: input.entryId, resourceType: ResourceTypesFhirR4.Medication, claims });
|
|
97
|
+
}
|
|
98
|
+
function codingToken(value) {
|
|
99
|
+
return `${required(value.system, 'immunization_coding_system_required')}|${required(value.code, 'immunization_coding_code_required')}`;
|
|
100
|
+
}
|
|
101
|
+
function isoDate(value, error) {
|
|
102
|
+
const normalized = required(value, error);
|
|
103
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})(?:T.*)?$/.exec(normalized);
|
|
104
|
+
if (!match || Number.isNaN(Date.parse(normalized)))
|
|
105
|
+
throw new TypeError(error);
|
|
106
|
+
const calendarDate = new Date(Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3])));
|
|
107
|
+
if (calendarDate.toISOString().slice(0, 10) !== `${match[1]}-${match[2]}-${match[3]}`)
|
|
108
|
+
throw new TypeError(error);
|
|
109
|
+
return normalized;
|
|
110
|
+
}
|
|
111
|
+
function required(value, error) {
|
|
112
|
+
if (typeof value !== 'string' || !value.trim())
|
|
113
|
+
throw new TypeError(error);
|
|
114
|
+
return value.trim();
|
|
115
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type FlatClaimResourceEntry } from '../flat-claim-resource-graph.js';
|
|
2
|
+
export declare const ImmunizationReminderTaskValues: Readonly<{
|
|
3
|
+
readonly Status: "requested";
|
|
4
|
+
readonly Intent: "order";
|
|
5
|
+
readonly Code: "immunization-reminder";
|
|
6
|
+
readonly TriggerType: "scheduled";
|
|
7
|
+
}>;
|
|
8
|
+
export declare const ImmunizationReminderChannels: readonly ["push", "email", "sms", "whatsapp", "telephone"];
|
|
9
|
+
export type ImmunizationReminderChannel = (typeof ImmunizationReminderChannels)[number];
|
|
10
|
+
export type ImmunizationReminderPlanInput = Readonly<{
|
|
11
|
+
entryIdPrefix: string;
|
|
12
|
+
recommendationReference: string;
|
|
13
|
+
subjectReference: string;
|
|
14
|
+
coverageEndDate: string;
|
|
15
|
+
/** Ordered delivery candidates; dispatch must filter them by current preferences and Consent. */
|
|
16
|
+
channelCandidates: readonly ImmunizationReminderChannel[];
|
|
17
|
+
}>;
|
|
18
|
+
export type ImmunizationReminderDispatchState = Readonly<{
|
|
19
|
+
channelCandidates: readonly ImmunizationReminderChannel[];
|
|
20
|
+
attemptedChannels: readonly ImmunizationReminderChannel[];
|
|
21
|
+
enabledPreferences: readonly ImmunizationReminderChannel[];
|
|
22
|
+
consentedChannels: readonly ImmunizationReminderChannel[];
|
|
23
|
+
acknowledged: boolean;
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* Builds the three notification Tasks attached to an ImmunizationRecommendation.
|
|
27
|
+
* Task creation is automatic; actual delivery is a separate runtime decision
|
|
28
|
+
* that rechecks channel preference, Consent and prior acknowledgement.
|
|
29
|
+
*/
|
|
30
|
+
export declare function buildImmunizationReminderTasks(input: ImmunizationReminderPlanInput): readonly FlatClaimResourceEntry[];
|
|
31
|
+
/**
|
|
32
|
+
* Selects one next delivery channel without bypassing the subject's current
|
|
33
|
+
* preferences or Consent. Acknowledgement ends escalation immediately.
|
|
34
|
+
*/
|
|
35
|
+
export declare function selectNextImmunizationReminderChannel(state: ImmunizationReminderDispatchState): ImmunizationReminderChannel | undefined;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Copyright 2026 ConnectHealth.info (Connecting Solution & Applications Ltd.) under the Apache License, Version 2.0.
|
|
2
|
+
import { buildFlatClaimResourceEntry } from '../flat-claim-resource-graph.js';
|
|
3
|
+
import { TaskClaim } from '../claims/task-claims.js';
|
|
4
|
+
import { ResourceTypesFhirR4 } from '../constants/fhir-resource-types.js';
|
|
5
|
+
export const ImmunizationReminderTaskValues = Object.freeze({
|
|
6
|
+
Status: 'requested',
|
|
7
|
+
Intent: 'order',
|
|
8
|
+
Code: 'immunization-reminder',
|
|
9
|
+
TriggerType: 'scheduled',
|
|
10
|
+
});
|
|
11
|
+
export const ImmunizationReminderChannels = Object.freeze([
|
|
12
|
+
'push',
|
|
13
|
+
'email',
|
|
14
|
+
'sms',
|
|
15
|
+
'whatsapp',
|
|
16
|
+
'telephone',
|
|
17
|
+
]);
|
|
18
|
+
const OFFSETS = Object.freeze([
|
|
19
|
+
Object.freeze({ suffix: '1m', subtract: subtractOneCalendarMonth }),
|
|
20
|
+
Object.freeze({ suffix: '1w', subtract: (date) => subtractUtcDays(date, 7) }),
|
|
21
|
+
Object.freeze({ suffix: '1d', subtract: (date) => subtractUtcDays(date, 1) }),
|
|
22
|
+
]);
|
|
23
|
+
/**
|
|
24
|
+
* Builds the three notification Tasks attached to an ImmunizationRecommendation.
|
|
25
|
+
* Task creation is automatic; actual delivery is a separate runtime decision
|
|
26
|
+
* that rechecks channel preference, Consent and prior acknowledgement.
|
|
27
|
+
*/
|
|
28
|
+
export function buildImmunizationReminderTasks(input) {
|
|
29
|
+
const prefix = required(input.entryIdPrefix, 'immunization_reminder_entry_id_required');
|
|
30
|
+
const recommendation = required(input.recommendationReference, 'immunization_recommendation_reference_required');
|
|
31
|
+
const subject = required(input.subjectReference, 'immunization_reminder_subject_required');
|
|
32
|
+
const coverageEnd = parseIsoDate(input.coverageEndDate);
|
|
33
|
+
const channels = [...new Set(input.channelCandidates)].filter((channel) => ImmunizationReminderChannels.includes(channel));
|
|
34
|
+
if (channels.length === 0)
|
|
35
|
+
throw new TypeError('immunization_reminder_channels_required');
|
|
36
|
+
return Object.freeze(OFFSETS.map(({ suffix, subtract }) => {
|
|
37
|
+
const entryId = `${prefix}-reminder-${suffix}`;
|
|
38
|
+
return buildFlatClaimResourceEntry({
|
|
39
|
+
entryId,
|
|
40
|
+
resourceType: ResourceTypesFhirR4.Task,
|
|
41
|
+
claims: {
|
|
42
|
+
[TaskClaim.Identifier]: `urn:uuid:${entryId}`,
|
|
43
|
+
[TaskClaim.GroupIdentifier]: recommendation,
|
|
44
|
+
[TaskClaim.Status]: ImmunizationReminderTaskValues.Status,
|
|
45
|
+
[TaskClaim.Intent]: ImmunizationReminderTaskValues.Intent,
|
|
46
|
+
[TaskClaim.Code]: ImmunizationReminderTaskValues.Code,
|
|
47
|
+
[TaskClaim.For]: subject,
|
|
48
|
+
[TaskClaim.Focus]: recommendation,
|
|
49
|
+
[TaskClaim.BasedOn]: recommendation,
|
|
50
|
+
[TaskClaim.ScheduledAt]: formatIsoDate(subtract(coverageEnd)),
|
|
51
|
+
[TaskClaim.TriggerType]: ImmunizationReminderTaskValues.TriggerType,
|
|
52
|
+
[TaskClaim.Channel]: channels.join(','),
|
|
53
|
+
[TaskClaim.Attempt]: '0',
|
|
54
|
+
[TaskClaim.MaxAttempts]: String(channels.length),
|
|
55
|
+
[TaskClaim.Confirmed]: 'false',
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Selects one next delivery channel without bypassing the subject's current
|
|
62
|
+
* preferences or Consent. Acknowledgement ends escalation immediately.
|
|
63
|
+
*/
|
|
64
|
+
export function selectNextImmunizationReminderChannel(state) {
|
|
65
|
+
if (state.acknowledged)
|
|
66
|
+
return undefined;
|
|
67
|
+
const attempted = new Set(state.attemptedChannels);
|
|
68
|
+
const preferred = new Set(state.enabledPreferences);
|
|
69
|
+
const consented = new Set(state.consentedChannels);
|
|
70
|
+
return state.channelCandidates.find((channel) => ImmunizationReminderChannels.includes(channel)
|
|
71
|
+
&& !attempted.has(channel)
|
|
72
|
+
&& preferred.has(channel)
|
|
73
|
+
&& consented.has(channel));
|
|
74
|
+
}
|
|
75
|
+
function parseIsoDate(value) {
|
|
76
|
+
const normalized = required(value, 'immunization_coverage_end_date_invalid');
|
|
77
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(normalized);
|
|
78
|
+
if (!match)
|
|
79
|
+
throw new TypeError('immunization_coverage_end_date_invalid');
|
|
80
|
+
const date = new Date(Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3])));
|
|
81
|
+
if (formatIsoDate(date) !== normalized)
|
|
82
|
+
throw new TypeError('immunization_coverage_end_date_invalid');
|
|
83
|
+
return date;
|
|
84
|
+
}
|
|
85
|
+
function subtractOneCalendarMonth(date) {
|
|
86
|
+
const year = date.getUTCFullYear();
|
|
87
|
+
const month = date.getUTCMonth();
|
|
88
|
+
const targetMonth = month === 0 ? 11 : month - 1;
|
|
89
|
+
const targetYear = month === 0 ? year - 1 : year;
|
|
90
|
+
const lastDay = new Date(Date.UTC(targetYear, targetMonth + 1, 0)).getUTCDate();
|
|
91
|
+
return new Date(Date.UTC(targetYear, targetMonth, Math.min(date.getUTCDate(), lastDay)));
|
|
92
|
+
}
|
|
93
|
+
function subtractUtcDays(date, days) {
|
|
94
|
+
return new Date(date.getTime() - days * 86_400_000);
|
|
95
|
+
}
|
|
96
|
+
function formatIsoDate(date) {
|
|
97
|
+
return date.toISOString().slice(0, 10);
|
|
98
|
+
}
|
|
99
|
+
function required(value, error) {
|
|
100
|
+
const normalized = String(value ?? '').trim();
|
|
101
|
+
if (!normalized)
|
|
102
|
+
throw new TypeError(error);
|
|
103
|
+
return normalized;
|
|
104
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type GenericInteroperableClaims = Record<string, unknown>;
|
|
2
|
+
export declare function splitClaimCsv(value: unknown): string[];
|
|
3
|
+
export declare function normalizeClaimTokens(values: readonly string[]): string[];
|
|
4
|
+
export declare function normalizeClaimInput(values: string | readonly string[]): string[];
|
|
5
|
+
export declare function normalizeClaimScalar(value: unknown): string;
|
|
6
|
+
/**
|
|
7
|
+
* Returns the tokenized values for a claims field stored as CSV.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getClaimValues(claims: GenericInteroperableClaims, claimKey: string): string[];
|
|
10
|
+
/**
|
|
11
|
+
* Replaces a claims CSV field with the provided values.
|
|
12
|
+
*/
|
|
13
|
+
export declare function setClaimValues(claims: GenericInteroperableClaims, claimKey: string, values: string | readonly string[]): GenericInteroperableClaims;
|
|
14
|
+
/**
|
|
15
|
+
* Adds one or many values into a claims CSV field while preserving uniqueness.
|
|
16
|
+
*/
|
|
17
|
+
export declare function addClaimValues(claims: GenericInteroperableClaims, claimKey: string, values: string | readonly string[]): GenericInteroperableClaims;
|
|
18
|
+
/**
|
|
19
|
+
* Removes one or many values from a claims CSV field while preserving uniqueness.
|
|
20
|
+
*/
|
|
21
|
+
export declare function removeClaimValues(claims: GenericInteroperableClaims, claimKey: string, values: string | readonly string[]): GenericInteroperableClaims;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
export function splitClaimCsv(value) {
|
|
3
|
+
return String(value || '')
|
|
4
|
+
.split(',')
|
|
5
|
+
.map((item) => item.trim())
|
|
6
|
+
.filter(Boolean);
|
|
7
|
+
}
|
|
8
|
+
export function normalizeClaimTokens(values) {
|
|
9
|
+
return [...new Set(values.map((value) => String(value || '').trim()).filter(Boolean))];
|
|
10
|
+
}
|
|
11
|
+
export function normalizeClaimInput(values) {
|
|
12
|
+
return Array.isArray(values)
|
|
13
|
+
? normalizeClaimTokens(values)
|
|
14
|
+
: normalizeClaimTokens(splitClaimCsv(values));
|
|
15
|
+
}
|
|
16
|
+
export function normalizeClaimScalar(value) {
|
|
17
|
+
return String(value || '').trim();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Returns the tokenized values for a claims field stored as CSV.
|
|
21
|
+
*/
|
|
22
|
+
export function getClaimValues(claims, claimKey) {
|
|
23
|
+
return normalizeClaimTokens(splitClaimCsv(claims[claimKey]));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Replaces a claims CSV field with the provided values.
|
|
27
|
+
*/
|
|
28
|
+
export function setClaimValues(claims, claimKey, values) {
|
|
29
|
+
const nextValues = normalizeClaimInput(values);
|
|
30
|
+
if (nextValues.length === 0) {
|
|
31
|
+
const { [claimKey]: _removed, ...remaining } = claims;
|
|
32
|
+
return remaining;
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
...claims,
|
|
36
|
+
[claimKey]: nextValues.join(','),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Adds one or many values into a claims CSV field while preserving uniqueness.
|
|
41
|
+
*/
|
|
42
|
+
export function addClaimValues(claims, claimKey, values) {
|
|
43
|
+
const current = getClaimValues(claims, claimKey);
|
|
44
|
+
const additions = normalizeClaimInput(values);
|
|
45
|
+
return setClaimValues(claims, claimKey, [...current, ...additions]);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Removes one or many values from a claims CSV field while preserving uniqueness.
|
|
49
|
+
*/
|
|
50
|
+
export function removeClaimValues(claims, claimKey, values) {
|
|
51
|
+
const removals = new Set(normalizeClaimInput(values));
|
|
52
|
+
const nextValues = getClaimValues(claims, claimKey).filter((value) => !removals.has(value));
|
|
53
|
+
return setClaimValues(claims, claimKey, nextValues);
|
|
54
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type GenericInteroperableClaims } from './claim-list-helpers.js';
|
|
2
|
+
export type AllergyIntoleranceInteroperableClaims = GenericInteroperableClaims;
|
|
3
|
+
export declare function getAllergyIntoleranceClaimList(claims: AllergyIntoleranceInteroperableClaims, claimKey: string): string[];
|
|
4
|
+
export declare function setAllergyIntoleranceClaimList(claims: AllergyIntoleranceInteroperableClaims, claimKey: string, values: string | readonly string[]): AllergyIntoleranceInteroperableClaims;
|
|
5
|
+
export declare function addAllergyIntoleranceClaimList(claims: AllergyIntoleranceInteroperableClaims, claimKey: string, values: string | readonly string[]): AllergyIntoleranceInteroperableClaims;
|
|
6
|
+
export declare function removeAllergyIntoleranceClaimList(claims: AllergyIntoleranceInteroperableClaims, claimKey: string, values: string | readonly string[]): AllergyIntoleranceInteroperableClaims;
|
|
7
|
+
export declare function getAllergyIntoleranceContainedResourceReferenceList(claims: AllergyIntoleranceInteroperableClaims): string[];
|
|
8
|
+
export declare function setAllergyIntoleranceContainedResourceReferenceList(claims: AllergyIntoleranceInteroperableClaims, values: string | readonly string[]): AllergyIntoleranceInteroperableClaims;
|
|
9
|
+
export declare function addAllergyIntoleranceContainedResourceReferenceList(claims: AllergyIntoleranceInteroperableClaims, values: string | readonly string[]): AllergyIntoleranceInteroperableClaims;
|
|
10
|
+
export declare function removeAllergyIntoleranceContainedResourceReferenceList(claims: AllergyIntoleranceInteroperableClaims, values: string | readonly string[]): AllergyIntoleranceInteroperableClaims;
|
|
11
|
+
/** @deprecated Use `getAllergyIntoleranceContainedResourceReferenceList`. */
|
|
12
|
+
export declare function getAllergyIntoleranceContainedDocumentIdentifierList(claims: AllergyIntoleranceInteroperableClaims): string[];
|
|
13
|
+
/** @deprecated Use `setAllergyIntoleranceContainedResourceReferenceList`. */
|
|
14
|
+
export declare function setAllergyIntoleranceContainedDocumentIdentifierList(claims: AllergyIntoleranceInteroperableClaims, values: string | readonly string[]): AllergyIntoleranceInteroperableClaims;
|
|
15
|
+
/** @deprecated Use `addAllergyIntoleranceContainedResourceReferenceList`. */
|
|
16
|
+
export declare function addAllergyIntoleranceContainedDocumentIdentifierList(claims: AllergyIntoleranceInteroperableClaims, values: string | readonly string[]): AllergyIntoleranceInteroperableClaims;
|
|
17
|
+
/** @deprecated Use `removeAllergyIntoleranceContainedResourceReferenceList`. */
|
|
18
|
+
export declare function removeAllergyIntoleranceContainedDocumentIdentifierList(claims: AllergyIntoleranceInteroperableClaims, values: string | readonly string[]): AllergyIntoleranceInteroperableClaims;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Copyright 2026 Antifraud Services Inc. under the Apache License, Version 2.0.
|
|
2
|
+
import { AllergyIntoleranceClaim } from '../claims/allergy-intolerance-claims.js';
|
|
3
|
+
import { addClaimValues, getClaimValues, removeClaimValues, setClaimValues, } from './claim-list-helpers.js';
|
|
4
|
+
export function getAllergyIntoleranceClaimList(claims, claimKey) {
|
|
5
|
+
return getClaimValues(claims, claimKey);
|
|
6
|
+
}
|
|
7
|
+
export function setAllergyIntoleranceClaimList(claims, claimKey, values) {
|
|
8
|
+
return setClaimValues(claims, claimKey, values);
|
|
9
|
+
}
|
|
10
|
+
export function addAllergyIntoleranceClaimList(claims, claimKey, values) {
|
|
11
|
+
return addClaimValues(claims, claimKey, values);
|
|
12
|
+
}
|
|
13
|
+
export function removeAllergyIntoleranceClaimList(claims, claimKey, values) {
|
|
14
|
+
return removeClaimValues(claims, claimKey, values);
|
|
15
|
+
}
|
|
16
|
+
export function getAllergyIntoleranceContainedResourceReferenceList(claims) {
|
|
17
|
+
return uniqueCsvLists([
|
|
18
|
+
getAllergyIntoleranceClaimList(claims, AllergyIntoleranceClaim.ContainedReferenceList),
|
|
19
|
+
getAllergyIntoleranceClaimList(claims, AllergyIntoleranceClaim.ContainedDocuments),
|
|
20
|
+
getAllergyIntoleranceClaimList(claims, AllergyIntoleranceClaim.AttachmentContentIds),
|
|
21
|
+
]);
|
|
22
|
+
}
|
|
23
|
+
export function setAllergyIntoleranceContainedResourceReferenceList(claims, values) {
|
|
24
|
+
return setContainedResources(claims, values);
|
|
25
|
+
}
|
|
26
|
+
export function addAllergyIntoleranceContainedResourceReferenceList(claims, values) {
|
|
27
|
+
return setContainedResources(claims, uniqueCsvLists([
|
|
28
|
+
getAllergyIntoleranceContainedResourceReferenceList(claims),
|
|
29
|
+
Array.isArray(values) ? [...values] : getAllergyIntoleranceClaimList({ [AllergyIntoleranceClaim.ContainedReferenceList]: values }, AllergyIntoleranceClaim.ContainedReferenceList),
|
|
30
|
+
]));
|
|
31
|
+
}
|
|
32
|
+
export function removeAllergyIntoleranceContainedResourceReferenceList(claims, values) {
|
|
33
|
+
const toRemove = new Set((Array.isArray(values) ? values : getAllergyIntoleranceClaimList({ [AllergyIntoleranceClaim.ContainedReferenceList]: values }, AllergyIntoleranceClaim.ContainedReferenceList))
|
|
34
|
+
.map((item) => String(item || '').trim())
|
|
35
|
+
.filter(Boolean));
|
|
36
|
+
return setContainedResources(claims, getAllergyIntoleranceContainedResourceReferenceList(claims).filter((item) => !toRemove.has(item)));
|
|
37
|
+
}
|
|
38
|
+
/** @deprecated Use `getAllergyIntoleranceContainedResourceReferenceList`. */
|
|
39
|
+
export function getAllergyIntoleranceContainedDocumentIdentifierList(claims) {
|
|
40
|
+
return getAllergyIntoleranceContainedResourceReferenceList(claims);
|
|
41
|
+
}
|
|
42
|
+
/** @deprecated Use `setAllergyIntoleranceContainedResourceReferenceList`. */
|
|
43
|
+
export function setAllergyIntoleranceContainedDocumentIdentifierList(claims, values) {
|
|
44
|
+
return setAllergyIntoleranceContainedResourceReferenceList(claims, values);
|
|
45
|
+
}
|
|
46
|
+
/** @deprecated Use `addAllergyIntoleranceContainedResourceReferenceList`. */
|
|
47
|
+
export function addAllergyIntoleranceContainedDocumentIdentifierList(claims, values) {
|
|
48
|
+
return addAllergyIntoleranceContainedResourceReferenceList(claims, values);
|
|
49
|
+
}
|
|
50
|
+
/** @deprecated Use `removeAllergyIntoleranceContainedResourceReferenceList`. */
|
|
51
|
+
export function removeAllergyIntoleranceContainedDocumentIdentifierList(claims, values) {
|
|
52
|
+
return removeAllergyIntoleranceContainedResourceReferenceList(claims, values);
|
|
53
|
+
}
|
|
54
|
+
function setContainedResources(claims, values) {
|
|
55
|
+
const next = setAllergyIntoleranceClaimList(claims, AllergyIntoleranceClaim.ContainedReferenceList, values);
|
|
56
|
+
const cleaned = {
|
|
57
|
+
...next,
|
|
58
|
+
};
|
|
59
|
+
delete cleaned[AllergyIntoleranceClaim.ContainedDocuments];
|
|
60
|
+
delete cleaned[AllergyIntoleranceClaim.AttachmentContentIds];
|
|
61
|
+
return cleaned;
|
|
62
|
+
}
|
|
63
|
+
function uniqueCsvLists(lists) {
|
|
64
|
+
return [...new Set(lists.flatMap((list) => list.map((item) => String(item || '').trim()).filter(Boolean)))];
|
|
65
|
+
}
|