@claudebernard/web-component-fhir-utils 1.0.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.
Files changed (31) hide show
  1. package/LICENSE.md +1 -0
  2. package/README.md +118 -0
  3. package/dist/bundle/apply-transaction-bundle.d.ts +19 -0
  4. package/dist/bundle/apply-transaction-bundle.d.ts.map +1 -0
  5. package/dist/bundle/apply-transaction-bundle.js +46 -0
  6. package/dist/bundle/apply-transaction-bundle.js.map +1 -0
  7. package/dist/bundle/create-collection-bundle.d.ts +14 -0
  8. package/dist/bundle/create-collection-bundle.d.ts.map +1 -0
  9. package/dist/bundle/create-collection-bundle.js +17 -0
  10. package/dist/bundle/create-collection-bundle.js.map +1 -0
  11. package/dist/bundle/create-transaction-bundle.d.ts +14 -0
  12. package/dist/bundle/create-transaction-bundle.d.ts.map +1 -0
  13. package/dist/bundle/create-transaction-bundle.js +32 -0
  14. package/dist/bundle/create-transaction-bundle.js.map +1 -0
  15. package/dist/bundle/find-resource-in-bundle.d.ts +7 -0
  16. package/dist/bundle/find-resource-in-bundle.d.ts.map +1 -0
  17. package/dist/bundle/find-resource-in-bundle.js +11 -0
  18. package/dist/bundle/find-resource-in-bundle.js.map +1 -0
  19. package/dist/bundle/supersede-resource.d.ts +19 -0
  20. package/dist/bundle/supersede-resource.d.ts.map +1 -0
  21. package/dist/bundle/supersede-resource.js +41 -0
  22. package/dist/bundle/supersede-resource.js.map +1 -0
  23. package/dist/constants/prior-prescription.const.d.ts +8 -0
  24. package/dist/constants/prior-prescription.const.d.ts.map +1 -0
  25. package/dist/constants/prior-prescription.const.js +7 -0
  26. package/dist/constants/prior-prescription.const.js.map +1 -0
  27. package/dist/index.d.ts +7 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +7 -0
  30. package/dist/index.js.map +1 -0
  31. package/package.json +108 -0
package/LICENSE.md ADDED
@@ -0,0 +1 @@
1
+ # License
package/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # @claudebernard/web-component-fhir-utils
2
+
3
+ Shared FHIR `Bundle` helpers for Claude Bernard medication web components (`bcb-medication-request-editor`, `bcb-therapeutic-alternative`) and the applications that embed them.
4
+
5
+ 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:
6
+
7
+ - **Integrating an app?** Build the input Bundle, then apply the output Bundle back onto your own state.
8
+ - **Building a component?** Use the same helpers to produce standards-compliant transaction diffs.
9
+
10
+ See the full guide on the [Claude Bernard Developer Portal](https://platform.claudebernard.fr/doc) for the wider FHIR model.
11
+
12
+ > **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 `integration` doc for its current API.
13
+
14
+ ## Installation
15
+
16
+ ```
17
+ npm install @claudebernard/web-component-fhir-utils
18
+ ```
19
+
20
+ ## Integrating an app
21
+
22
+ Build the input Bundle, pushing whatever resources the component needs:
23
+
24
+ ```ts
25
+ import { createCollectionBundle } from "@claudebernard/web-component-fhir-utils";
26
+
27
+ const bundle = createCollectionBundle();
28
+ bundle.entry.push({ resource: medication });
29
+ bundle.entry.push({ resource: medicationRequest });
30
+ ```
31
+
32
+ ```html
33
+ <bcb-medication-request-editor .medication="${bundle}"></bcb-medication-request-editor>
34
+ ```
35
+
36
+ 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:
37
+
38
+ ```ts
39
+ import { applyTransactionBundle } from "@claudebernard/web-component-fhir-utils";
40
+
41
+ editor.addEventListener("fhir-changes", ({ detail }) => {
42
+ myPrescriptionBundle = applyTransactionBundle(myPrescriptionBundle, detail.bundle);
43
+ });
44
+ ```
45
+
46
+ `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.
47
+
48
+ ## Building a component
49
+
50
+ Produce diff entries with `createBundleEntry` / `createTransactionBundle`:
51
+
52
+ ```ts
53
+ import { createBundleEntry, createTransactionBundle } from "@claudebernard/web-component-fhir-utils";
54
+
55
+ const bundle = createTransactionBundle([
56
+ createBundleEntry(updatedResource, "PUT"),
57
+ createBundleEntry(newResource, "POST"),
58
+ ]);
59
+ ```
60
+
61
+ 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:
62
+
63
+ ```ts
64
+ import { PriorPrescriptionReason, supersedeMedicationRequest } from "@claudebernard/web-component-fhir-utils";
65
+
66
+ const entries = supersedeMedicationRequest(
67
+ originalMedicationRequest,
68
+ { dosageInstruction: newDosage },
69
+ PriorPrescriptionReason.DOSAGE_OVERRIDE,
70
+ );
71
+ ```
72
+
73
+ 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`:
74
+
75
+ ```json
76
+ {
77
+ "resourceType": "Bundle",
78
+ "type": "transaction",
79
+ "entry": [
80
+ {
81
+ "resource": { "resourceType": "MedicationRequest", "id": "mr-123", "status": "on-hold", "...": "..." },
82
+ "request": { "method": "PUT", "url": "MedicationRequest/mr-123" }
83
+ },
84
+ {
85
+ "resource": {
86
+ "resourceType": "MedicationRequest",
87
+ "id": "mr-456",
88
+ "status": "active",
89
+ "dosageInstruction": ["..."],
90
+ "priorPrescription": {
91
+ "reference": "MedicationRequest/mr-123",
92
+ "extension": [{ "url": "https://platform.claudebernard.fr/fhir/StructureDefinition/prior-prescription-reason", "valueCode": "dosage-override" }]
93
+ }
94
+ },
95
+ "request": { "method": "POST", "url": "MedicationRequest" }
96
+ }
97
+ ]
98
+ }
99
+ ```
100
+
101
+ More worked examples (including the therapeutic-alternative case) are in the [Developer Portal](https://platform.claudebernard.fr/doc) guide.
102
+
103
+ ## API
104
+
105
+ | Export | Purpose |
106
+ |---|---|
107
+ | `createCollectionBundle(resources?)` | Build the input `collection` Bundle |
108
+ | `createBundleEntry(resource, method, url?)` | Build one transaction entry (`POST`/`PUT`/`DELETE`) |
109
+ | `createTransactionBundle(entries)` | Wrap entries into the output `transaction` Bundle |
110
+ | `applyTransactionBundle(target, transaction, options?)` | Apply a transaction Bundle onto a Bundle you hold |
111
+ | `findResourceInBundle(bundle, resourceType, id)` | Look up a resource by type + id |
112
+ | `supersedeMedicationRequest(original, changes, reason)` | Build the on-hold/`priorPrescription`/extension pair for a supersession |
113
+ | `hasPriorPrescriptionReason(medicationRequest, reason)` | Check why a `MedicationRequest` supersedes another |
114
+ | `PriorPrescriptionReason`, `PRIOR_PRESCRIPTION_REASON_URL`, `BCB_CODE_SYSTEM` | Shared constants |
115
+
116
+ ## License
117
+
118
+ Copyright of Cegedim. See [LICENSE](LICENSE.md) for details.
@@ -0,0 +1,19 @@
1
+ import type { Bundle } from "fhir/r5";
2
+ export interface ApplyTransactionBundleOptions {
3
+ /**
4
+ * What to do when a PUT/DELETE entry targets a resource that isn't found
5
+ * in the target Bundle. "append" (default) turns a missing PUT into an
6
+ * insert and silently ignores a missing DELETE; "throw" surfaces it as an
7
+ * error, useful when the caller wants to catch a sync bug between its own
8
+ * state and the Bundle the component was given.
9
+ */
10
+ onMissingTarget?: "append" | "throw";
11
+ }
12
+ /**
13
+ * Applies a transaction Bundle (as emitted by a component) onto a Bundle an
14
+ * integrator already holds, following standard FHIR
15
+ * `Bundle.entry.request.method` semantics. This is the one generic function
16
+ * integrators need — it never needs to change per component or per feature.
17
+ */
18
+ export declare function applyTransactionBundle(target: Bundle, transaction: Bundle, options?: ApplyTransactionBundleOptions): Bundle;
19
+ //# sourceMappingURL=apply-transaction-bundle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-transaction-bundle.d.ts","sourceRoot":"","sources":["../../src/bundle/apply-transaction-bundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAA6B,MAAM,SAAS,CAAC;AAEjE,MAAM,WAAW,6BAA6B;IAC5C;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;CACtC;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,6BAAkC,GAC1C,MAAM,CAyCR"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Applies a transaction Bundle (as emitted by a component) onto a Bundle an
3
+ * integrator already holds, following standard FHIR
4
+ * `Bundle.entry.request.method` semantics. This is the one generic function
5
+ * integrators need — it never needs to change per component or per feature.
6
+ */
7
+ export function applyTransactionBundle(target, transaction, options = {}) {
8
+ const { onMissingTarget = "append" } = options;
9
+ const entries = [...(target.entry ?? [])];
10
+ for (const txEntry of transaction.entry ?? []) {
11
+ const resource = txEntry.resource;
12
+ const method = txEntry.request?.method;
13
+ if (!resource || !method) {
14
+ continue;
15
+ }
16
+ const index = entries.findIndex(entry => entry.resource?.resourceType === resource.resourceType && entry.resource?.id === resource.id);
17
+ switch (method) {
18
+ case "POST":
19
+ entries.push({ resource, fullUrl: `urn:uuid:${resource.id}` });
20
+ break;
21
+ case "PUT":
22
+ if (index >= 0) {
23
+ entries[index] = { ...entries[index], resource };
24
+ }
25
+ else if (onMissingTarget === "append") {
26
+ entries.push({ resource });
27
+ }
28
+ else {
29
+ throw new Error(`applyTransactionBundle: cannot PUT ${resource.resourceType}/${resource.id}, not found in target bundle`);
30
+ }
31
+ break;
32
+ case "DELETE":
33
+ if (index >= 0) {
34
+ entries.splice(index, 1);
35
+ }
36
+ else if (onMissingTarget === "throw") {
37
+ throw new Error(`applyTransactionBundle: cannot DELETE ${resource.resourceType}/${resource.id}, not found in target bundle`);
38
+ }
39
+ break;
40
+ default:
41
+ break;
42
+ }
43
+ }
44
+ return { ...target, entry: entries };
45
+ }
46
+ //# sourceMappingURL=apply-transaction-bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-transaction-bundle.js","sourceRoot":"","sources":["../../src/bundle/apply-transaction-bundle.ts"],"names":[],"mappings":"AAaA;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,MAAc,EACd,WAAmB,EACnB,UAAyC,EAAE;IAE3C,MAAM,EAAE,eAAe,GAAG,QAAQ,EAAE,GAAG,OAAO,CAAC;IAC/C,MAAM,OAAO,GAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC;IAEzD,KAAK,MAAM,OAAO,IAAI,WAAW,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;QAC9C,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAoC,CAAC;QAC9D,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC;QACvC,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;YACzB,SAAS;QACX,CAAC;QAED,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAC7B,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,YAAY,KAAK,QAAQ,CAAC,YAAY,IAAI,KAAK,CAAC,QAAQ,EAAE,EAAE,KAAK,QAAQ,CAAC,EAAE,CACtG,CAAC;QAEF,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,MAAM;gBACT,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBAC/D,MAAM;YACR,KAAK,KAAK;gBACR,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAC;gBACnD,CAAC;qBAAM,IAAI,eAAe,KAAK,QAAQ,EAAE,CAAC;oBACxC,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;gBAC7B,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,KAAK,CAAC,sCAAsC,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,EAAE,8BAA8B,CAAC,CAAC;gBAC5H,CAAC;gBACD,MAAM;YACR,KAAK,QAAQ;gBACX,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;oBACf,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBAC3B,CAAC;qBAAM,IAAI,eAAe,KAAK,OAAO,EAAE,CAAC;oBACvC,MAAM,IAAI,KAAK,CAAC,yCAAyC,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,EAAE,8BAA8B,CAAC,CAAC;gBAC/H,CAAC;gBACD,MAAM;YACR;gBACE,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACvC,CAAC","sourcesContent":["import type { Bundle, BundleEntry, FhirResource } from \"fhir/r5\";\n\nexport interface ApplyTransactionBundleOptions {\n /**\n * What to do when a PUT/DELETE entry targets a resource that isn't found\n * in the target Bundle. \"append\" (default) turns a missing PUT into an\n * insert and silently ignores a missing DELETE; \"throw\" surfaces it as an\n * error, useful when the caller wants to catch a sync bug between its own\n * state and the Bundle the component was given.\n */\n onMissingTarget?: \"append\" | \"throw\";\n}\n\n/**\n * Applies a transaction Bundle (as emitted by a component) onto a Bundle an\n * integrator already holds, following standard FHIR\n * `Bundle.entry.request.method` semantics. This is the one generic function\n * integrators need — it never needs to change per component or per feature.\n */\nexport function applyTransactionBundle(\n target: Bundle,\n transaction: Bundle,\n options: ApplyTransactionBundleOptions = {},\n): Bundle {\n const { onMissingTarget = \"append\" } = options;\n const entries: BundleEntry[] = [...(target.entry ?? [])];\n\n for (const txEntry of transaction.entry ?? []) {\n const resource = txEntry.resource as FhirResource | undefined;\n const method = txEntry.request?.method;\n if (!resource || !method) {\n continue;\n }\n\n const index = entries.findIndex(\n entry => entry.resource?.resourceType === resource.resourceType && entry.resource?.id === resource.id,\n );\n\n switch (method) {\n case \"POST\":\n entries.push({ resource, fullUrl: `urn:uuid:${resource.id}` });\n break;\n case \"PUT\":\n if (index >= 0) {\n entries[index] = { ...entries[index], resource };\n } else if (onMissingTarget === \"append\") {\n entries.push({ resource });\n } else {\n throw new Error(`applyTransactionBundle: cannot PUT ${resource.resourceType}/${resource.id}, not found in target bundle`);\n }\n break;\n case \"DELETE\":\n if (index >= 0) {\n entries.splice(index, 1);\n } else if (onMissingTarget === \"throw\") {\n throw new Error(`applyTransactionBundle: cannot DELETE ${resource.resourceType}/${resource.id}, not found in target bundle`);\n }\n break;\n default:\n break;\n }\n }\n\n return { ...target, entry: entries };\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import type { Bundle, FhirResource } from "fhir/r5";
2
+ /**
3
+ * Builds the small FHIR `collection` Bundle a component expects as input:
4
+ * integrators create it once, then push whatever resources are relevant
5
+ * to the edit onto `.entry`, or pass them up front.
6
+ *
7
+ * const bundle = createCollectionBundle();
8
+ * bundle.entry.push({ resource: medication });
9
+ * bundle.entry.push({ resource: medicationRequest });
10
+ */
11
+ export declare function createCollectionBundle(resources?: FhirResource[]): Bundle & {
12
+ entry: NonNullable<Bundle["entry"]>;
13
+ };
14
+ //# sourceMappingURL=create-collection-bundle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-collection-bundle.d.ts","sourceRoot":"","sources":["../../src/bundle/create-collection-bundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEpD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,GAAE,YAAY,EAAO,GAAG,MAAM,GAAG;IAAE,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAA;CAAE,CAMvH"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Builds the small FHIR `collection` Bundle a component expects as input:
3
+ * integrators create it once, then push whatever resources are relevant
4
+ * to the edit onto `.entry`, or pass them up front.
5
+ *
6
+ * const bundle = createCollectionBundle();
7
+ * bundle.entry.push({ resource: medication });
8
+ * bundle.entry.push({ resource: medicationRequest });
9
+ */
10
+ export function createCollectionBundle(resources = []) {
11
+ return {
12
+ resourceType: "Bundle",
13
+ type: "collection",
14
+ entry: resources.map(resource => ({ resource })),
15
+ };
16
+ }
17
+ //# sourceMappingURL=create-collection-bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-collection-bundle.js","sourceRoot":"","sources":["../../src/bundle/create-collection-bundle.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CAAC,YAA4B,EAAE;IACnE,OAAO;QACL,YAAY,EAAE,QAAQ;QACtB,IAAI,EAAE,YAAY;QAClB,KAAK,EAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;KACjD,CAAC;AACJ,CAAC","sourcesContent":["import type { Bundle, FhirResource } from \"fhir/r5\";\n\n/**\n * Builds the small FHIR `collection` Bundle a component expects as input:\n * integrators create it once, then push whatever resources are relevant\n * to the edit onto `.entry`, or pass them up front.\n *\n * const bundle = createCollectionBundle();\n * bundle.entry.push({ resource: medication });\n * bundle.entry.push({ resource: medicationRequest });\n */\nexport function createCollectionBundle(resources: FhirResource[] = []): Bundle & { entry: NonNullable<Bundle[\"entry\"]> } {\n return {\n resourceType: \"Bundle\",\n type: \"collection\",\n entry: resources.map(resource => ({ resource })),\n };\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import type { Bundle, BundleEntry, FhirResource } from "fhir/r5";
2
+ export type TransactionMethod = "POST" | "PUT" | "DELETE";
3
+ /**
4
+ * Builds a single transaction Bundle entry with standard FHIR
5
+ * `Bundle.entry.request` semantics (method + url).
6
+ */
7
+ export declare function createBundleEntry(resource: FhirResource, method: TransactionMethod, url?: string): BundleEntry;
8
+ /**
9
+ * Wraps a list of entries (built with `createBundleEntry`, or one of the
10
+ * higher-level helpers such as `supersedeMedicationRequest`) into the
11
+ * `transaction`-type Bundle a component emits as its output.
12
+ */
13
+ export declare function createTransactionBundle(entries: BundleEntry[]): Bundle;
14
+ //# sourceMappingURL=create-transaction-bundle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-transaction-bundle.d.ts","sourceRoot":"","sources":["../../src/bundle/create-transaction-bundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEjE,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;AAS1D;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,iBAAiB,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,WAAW,CAQ9G;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAMtE"}
@@ -0,0 +1,32 @@
1
+ function defaultUrlFor(resource, method) {
2
+ if (method === "POST") {
3
+ return resource.resourceType;
4
+ }
5
+ return `${resource.resourceType}/${resource.id}`;
6
+ }
7
+ /**
8
+ * Builds a single transaction Bundle entry with standard FHIR
9
+ * `Bundle.entry.request` semantics (method + url).
10
+ */
11
+ export function createBundleEntry(resource, method, url) {
12
+ return {
13
+ resource,
14
+ request: {
15
+ method,
16
+ url: url ?? defaultUrlFor(resource, method),
17
+ },
18
+ };
19
+ }
20
+ /**
21
+ * Wraps a list of entries (built with `createBundleEntry`, or one of the
22
+ * higher-level helpers such as `supersedeMedicationRequest`) into the
23
+ * `transaction`-type Bundle a component emits as its output.
24
+ */
25
+ export function createTransactionBundle(entries) {
26
+ return {
27
+ resourceType: "Bundle",
28
+ type: "transaction",
29
+ entry: entries,
30
+ };
31
+ }
32
+ //# sourceMappingURL=create-transaction-bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-transaction-bundle.js","sourceRoot":"","sources":["../../src/bundle/create-transaction-bundle.ts"],"names":[],"mappings":"AAIA,SAAS,aAAa,CAAC,QAAsB,EAAE,MAAyB;IACtE,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,QAAQ,CAAC,YAAY,CAAC;IAC/B,CAAC;IACD,OAAO,GAAG,QAAQ,CAAC,YAAY,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAsB,EAAE,MAAyB,EAAE,GAAY;IAC/F,OAAO;QACL,QAAQ;QACR,OAAO,EAAE;YACP,MAAM;YACN,GAAG,EAAE,GAAG,IAAI,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC;SAC5C;KACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAsB;IAC5D,OAAO;QACL,YAAY,EAAE,QAAQ;QACtB,IAAI,EAAE,aAAa;QACnB,KAAK,EAAE,OAAO;KACf,CAAC;AACJ,CAAC","sourcesContent":["import type { Bundle, BundleEntry, FhirResource } from \"fhir/r5\";\n\nexport type TransactionMethod = \"POST\" | \"PUT\" | \"DELETE\";\n\nfunction defaultUrlFor(resource: FhirResource, method: TransactionMethod): string {\n if (method === \"POST\") {\n return resource.resourceType;\n }\n return `${resource.resourceType}/${resource.id}`;\n}\n\n/**\n * Builds a single transaction Bundle entry with standard FHIR\n * `Bundle.entry.request` semantics (method + url).\n */\nexport function createBundleEntry(resource: FhirResource, method: TransactionMethod, url?: string): BundleEntry {\n return {\n resource,\n request: {\n method,\n url: url ?? defaultUrlFor(resource, method),\n },\n };\n}\n\n/**\n * Wraps a list of entries (built with `createBundleEntry`, or one of the\n * higher-level helpers such as `supersedeMedicationRequest`) into the\n * `transaction`-type Bundle a component emits as its output.\n */\nexport function createTransactionBundle(entries: BundleEntry[]): Bundle {\n return {\n resourceType: \"Bundle\",\n type: \"transaction\",\n entry: entries,\n };\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import type { Bundle, FhirResource } from "fhir/r5";
2
+ /**
3
+ * Finds a resource of a given type/id inside a Bundle's entries.
4
+ * Used both to build transaction diffs and to apply them.
5
+ */
6
+ export declare function findResourceInBundle<T extends FhirResource = FhirResource>(bundle: Bundle | null | undefined, resourceType: T["resourceType"], id: string | undefined): T | undefined;
7
+ //# sourceMappingURL=find-resource-in-bundle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-resource-in-bundle.d.ts","sourceRoot":"","sources":["../../src/bundle/find-resource-in-bundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEpD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,EACxE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACjC,YAAY,EAAE,CAAC,CAAC,cAAc,CAAC,EAC/B,EAAE,EAAE,MAAM,GAAG,SAAS,GACrB,CAAC,GAAG,SAAS,CAOf"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Finds a resource of a given type/id inside a Bundle's entries.
3
+ * Used both to build transaction diffs and to apply them.
4
+ */
5
+ export function findResourceInBundle(bundle, resourceType, id) {
6
+ if (!id) {
7
+ return undefined;
8
+ }
9
+ return bundle?.entry?.find(entry => entry.resource?.resourceType === resourceType && entry.resource?.id === id)?.resource;
10
+ }
11
+ //# sourceMappingURL=find-resource-in-bundle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-resource-in-bundle.js","sourceRoot":"","sources":["../../src/bundle/find-resource-in-bundle.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAiC,EACjC,YAA+B,EAC/B,EAAsB;IAEtB,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,MAAM,EAAE,KAAK,EAAE,IAAI,CACxB,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,YAAY,KAAK,YAAY,IAAI,KAAK,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,CACpF,EAAE,QAAyB,CAAC;AAC/B,CAAC","sourcesContent":["import type { Bundle, FhirResource } from \"fhir/r5\";\n\n/**\n * Finds a resource of a given type/id inside a Bundle's entries.\n * Used both to build transaction diffs and to apply them.\n */\nexport function findResourceInBundle<T extends FhirResource = FhirResource>(\n bundle: Bundle | null | undefined,\n resourceType: T[\"resourceType\"],\n id: string | undefined,\n): T | undefined {\n if (!id) {\n return undefined;\n }\n return bundle?.entry?.find(\n entry => entry.resource?.resourceType === resourceType && entry.resource?.id === id,\n )?.resource as T | undefined;\n}\n"]}
@@ -0,0 +1,19 @@
1
+ import type { BundleEntry, MedicationRequest } from "fhir/r5";
2
+ import { PriorPrescriptionReason } from "../constants/prior-prescription.const";
3
+ /**
4
+ * Checks whether a MedicationRequest is the result of a supersession for a
5
+ * given reason (e.g. a dosage override, or a therapeutic-alternative swap),
6
+ * as tagged by `supersedeMedicationRequest`.
7
+ */
8
+ export declare function hasPriorPrescriptionReason(medicationRequest: MedicationRequest | null | undefined, reason: PriorPrescriptionReason): boolean;
9
+ /**
10
+ * Standard house pattern for representing "this MedicationRequest replaces
11
+ * that one" as a transaction Bundle diff: the original is put `on-hold` via
12
+ * PUT, and a new `active` MedicationRequest is created via POST, linked back
13
+ * through `priorPrescription` and tagged with why via the
14
+ * `prior-prescription-reason` extension.
15
+ *
16
+ * Returns the two entries ready to hand to `createTransactionBundle`.
17
+ */
18
+ export declare function supersedeMedicationRequest(original: MedicationRequest, changes: Partial<MedicationRequest>, reason: PriorPrescriptionReason): BundleEntry[];
19
+ //# sourceMappingURL=supersede-resource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supersede-resource.d.ts","sourceRoot":"","sources":["../../src/bundle/supersede-resource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAiC,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAG/G;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,iBAAiB,EAAE,iBAAiB,GAAG,IAAI,GAAG,SAAS,EACvD,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAKT;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,EAAE,OAAO,CAAC,iBAAiB,CAAC,EACnC,MAAM,EAAE,uBAAuB,GAC9B,WAAW,EAAE,CAsBf"}
@@ -0,0 +1,41 @@
1
+ import { PRIOR_PRESCRIPTION_REASON_URL } from "../constants/prior-prescription.const";
2
+ import { createBundleEntry } from "./create-transaction-bundle";
3
+ /**
4
+ * Checks whether a MedicationRequest is the result of a supersession for a
5
+ * given reason (e.g. a dosage override, or a therapeutic-alternative swap),
6
+ * as tagged by `supersedeMedicationRequest`.
7
+ */
8
+ export function hasPriorPrescriptionReason(medicationRequest, reason) {
9
+ const extension = medicationRequest?.priorPrescription?.extension?.find(ext => ext.url === PRIOR_PRESCRIPTION_REASON_URL);
10
+ return extension?.valueCode === reason;
11
+ }
12
+ /**
13
+ * Standard house pattern for representing "this MedicationRequest replaces
14
+ * that one" as a transaction Bundle diff: the original is put `on-hold` via
15
+ * PUT, and a new `active` MedicationRequest is created via POST, linked back
16
+ * through `priorPrescription` and tagged with why via the
17
+ * `prior-prescription-reason` extension.
18
+ *
19
+ * Returns the two entries ready to hand to `createTransactionBundle`.
20
+ */
21
+ export function supersedeMedicationRequest(original, changes, reason) {
22
+ if (!original.id) {
23
+ throw new Error("supersedeMedicationRequest: original MedicationRequest must have an id");
24
+ }
25
+ const onHoldOriginal = { ...original, status: "on-hold" };
26
+ const superseding = {
27
+ ...structuredClone(original),
28
+ ...changes,
29
+ id: crypto.randomUUID(),
30
+ status: "active",
31
+ priorPrescription: {
32
+ reference: `MedicationRequest/${original.id}`,
33
+ extension: [{ url: PRIOR_PRESCRIPTION_REASON_URL, valueCode: reason }],
34
+ },
35
+ };
36
+ return [
37
+ createBundleEntry(onHoldOriginal, "PUT"),
38
+ createBundleEntry(superseding, "POST"),
39
+ ];
40
+ }
41
+ //# sourceMappingURL=supersede-resource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supersede-resource.js","sourceRoot":"","sources":["../../src/bundle/supersede-resource.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,6BAA6B,EAA2B,MAAM,uCAAuC,CAAC;AAC/G,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAEhE;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,iBAAuD,EACvD,MAA+B;IAE/B,MAAM,SAAS,GAAG,iBAAiB,EAAE,iBAAiB,EAAE,SAAS,EAAE,IAAI,CACrE,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK,6BAA6B,CACjD,CAAC;IACF,OAAO,SAAS,EAAE,SAAS,KAAK,MAAM,CAAC;AACzC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CACxC,QAA2B,EAC3B,OAAmC,EACnC,MAA+B;IAE/B,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,wEAAwE,CAAC,CAAC;IAC5F,CAAC;IAED,MAAM,cAAc,GAAsB,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAE7E,MAAM,WAAW,GAAsB;QACrC,GAAG,eAAe,CAAC,QAAQ,CAAC;QAC5B,GAAG,OAAO;QACV,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;QACvB,MAAM,EAAE,QAAQ;QAChB,iBAAiB,EAAE;YACjB,SAAS,EAAE,qBAAqB,QAAQ,CAAC,EAAE,EAAE;YAC7C,SAAS,EAAE,CAAC,EAAE,GAAG,EAAE,6BAA6B,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;SACvE;KACF,CAAC;IAEF,OAAO;QACL,iBAAiB,CAAC,cAAc,EAAE,KAAK,CAAC;QACxC,iBAAiB,CAAC,WAAW,EAAE,MAAM,CAAC;KACvC,CAAC;AACJ,CAAC","sourcesContent":["import type { BundleEntry, MedicationRequest } from \"fhir/r5\";\nimport { PRIOR_PRESCRIPTION_REASON_URL, PriorPrescriptionReason } from \"../constants/prior-prescription.const\";\nimport { createBundleEntry } from \"./create-transaction-bundle\";\n\n/**\n * Checks whether a MedicationRequest is the result of a supersession for a\n * given reason (e.g. a dosage override, or a therapeutic-alternative swap),\n * as tagged by `supersedeMedicationRequest`.\n */\nexport function hasPriorPrescriptionReason(\n medicationRequest: MedicationRequest | null | undefined,\n reason: PriorPrescriptionReason,\n): boolean {\n const extension = medicationRequest?.priorPrescription?.extension?.find(\n ext => ext.url === PRIOR_PRESCRIPTION_REASON_URL,\n );\n return extension?.valueCode === reason;\n}\n\n/**\n * Standard house pattern for representing \"this MedicationRequest replaces\n * that one\" as a transaction Bundle diff: the original is put `on-hold` via\n * PUT, and a new `active` MedicationRequest is created via POST, linked back\n * through `priorPrescription` and tagged with why via the\n * `prior-prescription-reason` extension.\n *\n * Returns the two entries ready to hand to `createTransactionBundle`.\n */\nexport function supersedeMedicationRequest(\n original: MedicationRequest,\n changes: Partial<MedicationRequest>,\n reason: PriorPrescriptionReason,\n): BundleEntry[] {\n if (!original.id) {\n throw new Error(\"supersedeMedicationRequest: original MedicationRequest must have an id\");\n }\n\n const onHoldOriginal: MedicationRequest = { ...original, status: \"on-hold\" };\n\n const superseding: MedicationRequest = {\n ...structuredClone(original),\n ...changes,\n id: crypto.randomUUID(),\n status: \"active\",\n priorPrescription: {\n reference: `MedicationRequest/${original.id}`,\n extension: [{ url: PRIOR_PRESCRIPTION_REASON_URL, valueCode: reason }],\n },\n };\n\n return [\n createBundleEntry(onHoldOriginal, \"PUT\"),\n createBundleEntry(superseding, \"POST\"),\n ];\n}\n"]}
@@ -0,0 +1,8 @@
1
+ export declare const BCB_CODE_SYSTEM = "https://platform.claudebernard.fr/fhir/CodeSystem/bcb-code";
2
+ export declare const PRIOR_PRESCRIPTION_REASON_URL = "https://platform.claudebernard.fr/fhir/StructureDefinition/prior-prescription-reason";
3
+ export declare const PriorPrescriptionReason: {
4
+ readonly DOSAGE_OVERRIDE: "dosage-override";
5
+ readonly THERAPEUTIC_ALTERNATIVE: "therapeutic-alternative";
6
+ };
7
+ export type PriorPrescriptionReason = typeof PriorPrescriptionReason[keyof typeof PriorPrescriptionReason];
8
+ //# sourceMappingURL=prior-prescription.const.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prior-prescription.const.d.ts","sourceRoot":"","sources":["../../src/constants/prior-prescription.const.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,+DAA+D,CAAC;AAE5F,eAAO,MAAM,6BAA6B,yFAAyF,CAAC;AAEpI,eAAO,MAAM,uBAAuB;;;CAG1B,CAAC;AAEX,MAAM,MAAM,uBAAuB,GAAG,OAAO,uBAAuB,CAAC,MAAM,OAAO,uBAAuB,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ export const BCB_CODE_SYSTEM = "https://platform.claudebernard.fr/fhir/CodeSystem/bcb-code";
2
+ export const PRIOR_PRESCRIPTION_REASON_URL = "https://platform.claudebernard.fr/fhir/StructureDefinition/prior-prescription-reason";
3
+ export const PriorPrescriptionReason = {
4
+ DOSAGE_OVERRIDE: "dosage-override",
5
+ THERAPEUTIC_ALTERNATIVE: "therapeutic-alternative",
6
+ };
7
+ //# sourceMappingURL=prior-prescription.const.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prior-prescription.const.js","sourceRoot":"","sources":["../../src/constants/prior-prescription.const.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,4DAA4D,CAAC;AAE5F,MAAM,CAAC,MAAM,6BAA6B,GAAG,sFAAsF,CAAC;AAEpI,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,eAAe,EAAE,iBAAiB;IAClC,uBAAuB,EAAE,yBAAyB;CAC1C,CAAC","sourcesContent":["export const BCB_CODE_SYSTEM = \"https://platform.claudebernard.fr/fhir/CodeSystem/bcb-code\";\n\nexport const PRIOR_PRESCRIPTION_REASON_URL = \"https://platform.claudebernard.fr/fhir/StructureDefinition/prior-prescription-reason\";\n\nexport const PriorPrescriptionReason = {\n DOSAGE_OVERRIDE: \"dosage-override\",\n THERAPEUTIC_ALTERNATIVE: \"therapeutic-alternative\",\n} as const;\n\nexport type PriorPrescriptionReason = typeof PriorPrescriptionReason[keyof typeof PriorPrescriptionReason];\n"]}
@@ -0,0 +1,7 @@
1
+ export * from "./constants/prior-prescription.const";
2
+ export * from "./bundle/create-collection-bundle";
3
+ export * from "./bundle/create-transaction-bundle";
4
+ export * from "./bundle/apply-transaction-bundle";
5
+ export * from "./bundle/find-resource-in-bundle";
6
+ export * from "./bundle/supersede-resource";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export * from "./constants/prior-prescription.const";
2
+ export * from "./bundle/create-collection-bundle";
3
+ export * from "./bundle/create-transaction-bundle";
4
+ export * from "./bundle/apply-transaction-bundle";
5
+ export * from "./bundle/find-resource-in-bundle";
6
+ export * from "./bundle/supersede-resource";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,sCAAsC,CAAC;AACrD,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,mCAAmC,CAAC;AAClD,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC","sourcesContent":["export * from \"./constants/prior-prescription.const\";\nexport * from \"./bundle/create-collection-bundle\";\nexport * from \"./bundle/create-transaction-bundle\";\nexport * from \"./bundle/apply-transaction-bundle\";\nexport * from \"./bundle/find-resource-in-bundle\";\nexport * from \"./bundle/supersede-resource\";\n"]}
package/package.json ADDED
@@ -0,0 +1,108 @@
1
+ {
2
+ "name": "@claudebernard/web-component-fhir-utils",
3
+ "version": "1.0.0",
4
+ "description": "Shared FHIR Bundle utilities (collection/transaction bundles, prior-prescription linking) for Claude Bernard web components and their integrators.",
5
+ "type": "module",
6
+ "types": "dist/index.d.ts",
7
+ "module": "dist/index.js",
8
+ "main": "dist/index.js",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ },
17
+ "./constants/prior-prescription": {
18
+ "types": "./dist/constants/prior-prescription.const.d.ts",
19
+ "import": "./dist/constants/prior-prescription.const.js"
20
+ },
21
+ "./bundle/create-collection-bundle": {
22
+ "types": "./dist/bundle/create-collection-bundle.d.ts",
23
+ "import": "./dist/bundle/create-collection-bundle.js"
24
+ },
25
+ "./bundle/create-transaction-bundle": {
26
+ "types": "./dist/bundle/create-transaction-bundle.d.ts",
27
+ "import": "./dist/bundle/create-transaction-bundle.js"
28
+ },
29
+ "./bundle/apply-transaction-bundle": {
30
+ "types": "./dist/bundle/apply-transaction-bundle.d.ts",
31
+ "import": "./dist/bundle/apply-transaction-bundle.js"
32
+ },
33
+ "./bundle/find-resource-in-bundle": {
34
+ "types": "./dist/bundle/find-resource-in-bundle.d.ts",
35
+ "import": "./dist/bundle/find-resource-in-bundle.js"
36
+ },
37
+ "./bundle/supersede-resource": {
38
+ "types": "./dist/bundle/supersede-resource.d.ts",
39
+ "import": "./dist/bundle/supersede-resource.js"
40
+ }
41
+ },
42
+ "scripts": {
43
+ "build": "tsc",
44
+ "lint": "eslint .",
45
+ "test": "vitest run",
46
+ "test:watch": "vitest"
47
+ },
48
+ "keywords": [
49
+ "claude-bernard",
50
+ "fhir",
51
+ "typescript",
52
+ "web-components"
53
+ ],
54
+ "author": "Claude Bernard",
55
+ "publishConfig": {
56
+ "access": "public"
57
+ },
58
+ "peerDependencies": {
59
+ "@types/fhir": "^0.0.41"
60
+ },
61
+ "devDependencies": {
62
+ "@stylistic/eslint-plugin": "^5.9.0",
63
+ "@types/fhir": "^0.0.41",
64
+ "@types/node": "^25.3.0",
65
+ "@typescript-eslint/eslint-plugin": "8.65.0",
66
+ "@typescript-eslint/parser": "8.65.0",
67
+ "@vitest/coverage-v8": "^4.1.10",
68
+ "eslint": "^9.38.0",
69
+ "eslint-plugin-import": "2.32.0",
70
+ "typescript": "~5.9.3",
71
+ "vitest": "^4.0.18"
72
+ },
73
+ "release": {
74
+ "tagFormat": "${version}",
75
+ "branches": ["master"],
76
+ "plugins": [
77
+ "@semantic-release/commit-analyzer",
78
+ "@semantic-release/release-notes-generator",
79
+ "@semantic-release/changelog",
80
+ [
81
+ "semantic-release-replace-plugin",
82
+ {
83
+ "replacements": [
84
+ {
85
+ "files": ["package.json"],
86
+ "from": "\"version\": \"\\d+\\.\\d+\\.\\d+\"",
87
+ "to": "\"version\": \"${nextRelease.version}\"",
88
+ "results": [
89
+ {
90
+ "file": "package.json",
91
+ "hasChanged": true
92
+ }
93
+ ]
94
+ }
95
+ ]
96
+ }
97
+ ],
98
+ [
99
+ "@semantic-release/git",
100
+ {
101
+ "message": "chore(release): ${nextRelease.version} [skip ci on prod]",
102
+ "assets": ["package.json", "CHANGELOG.md"]
103
+ }
104
+ ],
105
+ "@semantic-release/gitlab"
106
+ ]
107
+ }
108
+ }