@claudebernard/web-component-fhir-utils
v2.0.1
Published
Shared FHIR Bundle utilities (collection/transaction bundles, prior-prescription linking) for Claude Bernard web components and their integrators.
Readme
@claudebernard/web-component-fhir-utils
Shared FHIR Bundle helpers for Claude Bernard medication web components (bcb-medication-request-editor, bcb-therapeutic-alternative) and the applications that embed them.
These components take a small FHIR collection Bundle as input and emit a FHIR transaction Bundle describing exactly what changed — standard Bundle.entry.request.method semantics, no custom DTOs. This package gives you the two sides of that contract so you never write bespoke reconciliation code:
- Integrating an app? Build the input Bundle, then apply the output Bundle back onto your own state.
- Building a component? Use the same helpers to produce standards-compliant transaction diffs.
See the full guide on the Claude Bernard Developer Portal for the wider FHIR model.
Status: this package defines the target Bundle-in/Bundle-out contract. Check each component's own changelog for the version that adopts it — until then, refer to that component's
integrationdoc for its current API.
Installation
npm install @claudebernard/web-component-fhir-utilsIntegrating an app
Build the input Bundle, pushing whatever resources the component needs:
import { createCollectionBundle } from "@claudebernard/web-component-fhir-utils";
const bundle = createCollectionBundle();
bundle.entry.push({ resource: medication });
bundle.entry.push({ resource: medicationRequest });<bcb-medication-request-editor .medication="${bundle}"></bcb-medication-request-editor>Apply the transaction Bundle the component emits back onto your own Bundle — this is the only integration code you need, and it never changes per component or per feature:
import { applyTransactionBundle } from "@claudebernard/web-component-fhir-utils";
editor.addEventListener("fhir-changes", ({ detail }) => {
myPrescriptionBundle = applyTransactionBundle(myPrescriptionBundle, detail.bundle);
});applyTransactionBundle understands POST (append), PUT (replace by resourceType + id), and DELETE (remove by resourceType + id). Pass { onMissingTarget: "throw" } if you'd rather fail loudly than silently insert/ignore when a PUT/DELETE targets a resource your Bundle doesn't have.
Building a component
Produce diff entries with createBundleEntry / createTransactionBundle:
import { createBundleEntry, createTransactionBundle } from "@claudebernard/web-component-fhir-utils";
const bundle = createTransactionBundle([
createBundleEntry(updatedResource, "PUT"),
createBundleEntry(newResource, "POST"),
]);For the common "this MedicationRequest replaces that one" case (dosage override, therapeutic alternative, ...), use supersedeMedicationRequest — it produces the on-hold PUT + linked, tagged POST pair as house convention dictates, so every component represents supersession the same way:
import { PriorPrescriptionReason, supersedeMedicationRequest } from "@claudebernard/web-component-fhir-utils";
const entries = supersedeMedicationRequest(
originalMedicationRequest,
{ dosageInstruction: newDosage },
PriorPrescriptionReason.DOSAGE_OVERRIDE,
);Which produces a diff shaped like this — the original request goes on-hold via PUT, the new one is created active via POST and linked back through priorPrescription:
{
"resourceType": "Bundle",
"type": "transaction",
"entry": [
{
"resource": { "resourceType": "MedicationRequest", "id": "mr-123", "status": "on-hold", "...": "..." },
"request": { "method": "PUT", "url": "MedicationRequest/mr-123" }
},
{
"resource": {
"resourceType": "MedicationRequest",
"id": "mr-456",
"status": "active",
"dosageInstruction": ["..."],
"priorPrescription": {
"reference": "MedicationRequest/mr-123",
"extension": [{ "url": "https://platform.claudebernard.fr/fhir/StructureDefinition/prior-prescription-reason", "valueCode": "dosage-override" }]
}
},
"request": { "method": "POST", "url": "MedicationRequest" }
}
]
}Supersession reasons
PriorPrescriptionReason carries why the new request replaces the old one, as a valueCode on the
priorPrescription extension. Pick the one that matches the user's intent — consumers filter on it
with hasPriorPrescriptionReason:
| Value | Code | When |
|---|---|---|
| PriorPrescriptionReason.DOSAGE_OVERRIDE | dosage-override | Same medication, dosage changed |
| PriorPrescriptionReason.MEDICATION_OVERRIDE | medication-override | Different medication, same therapeutic intent |
| PriorPrescriptionReason.THERAPEUTIC_ALTERNATIVE | therapeutic-alternative | Substitution proposed by bcb-therapeutic-alternative |
More worked examples (including the therapeutic-alternative case) are in the Developer Portal guide.
API
| Export | Purpose |
|---|---|
| createCollectionBundle(resources?) | Build the input collection Bundle |
| createBundleEntry(resource, method, url?) | Build one transaction entry (POST/PUT/DELETE) |
| createTransactionBundle(entries) | Wrap entries into the output transaction Bundle |
| applyTransactionBundle(target, transaction, options?) | Apply a transaction Bundle onto a Bundle you hold |
| findResourceInBundle(bundle, resourceType, id) | Look up a resource by type + id |
| supersedeMedicationRequest(original, changes, reason) | Build the on-hold/priorPrescription/extension pair for a supersession |
| hasPriorPrescriptionReason(medicationRequest, reason) | Check why a MedicationRequest supersedes another |
| PriorPrescriptionReason, PRIOR_PRESCRIPTION_REASON_URL, BCB_CODE_SYSTEM | Shared constants |
Versioning
This package carries the version of the fhir-monorepo repository — one version, tag and changelog
for the whole repo. Published versions are therefore sparse: a release only reaches npm when this
package actually changed.
License
Copyright of Cegedim. See LICENSE for details.
