@cosyte/fhir 0.0.10 → 0.1.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/README.md CHANGED
@@ -1,16 +1,183 @@
1
+ <a href="https://cosyte.com">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://cosyte.com/tile/cosyte-lockup-tile-on-dark-1200x300.png">
4
+ <img alt="Cosyte: a plus mark set in two overlapping rounded squares, one solid and one outlined, beside the Cosyte wordmark" src="https://cosyte.com/tile/cosyte-lockup-tile-on-light-1200x300.png">
5
+ </picture>
6
+ </a>
7
+
1
8
  # @cosyte/fhir
2
9
 
3
- Developer-focused FHIR toolkit for Node.js and TypeScript. An R4-first resource model, a JSON and
4
- XML codec, and layered validation.
10
+ > Read real-world FHIR R4, keep every value exactly as it was written, and validate it against your
11
+ > profiles.
12
+
13
+ [![npm version](https://img.shields.io/npm/v/@cosyte/fhir.svg)](https://www.npmjs.com/package/@cosyte/fhir)
14
+ [![CI](https://img.shields.io/github/actions/workflow/status/cosyte/fhir/ci.yml?branch=main&label=CI)](https://github.com/cosyte/fhir/actions/workflows/ci.yml)
15
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
16
+ [![Node](https://img.shields.io/badge/node-%3E%3D22-brightgreen.svg)](https://nodejs.org)
17
+
18
+ FHIR R4 for Node.js and TypeScript: a resource model that keeps every value exactly as written, JSON and XML codecs, layered validation, and a safety readout for status and negation.
19
+
20
+ ## Why this exists
21
+
22
+ Reading FHIR correctly takes more than a JSON parse: a `decimal` written `0.010` has to stay
23
+ `0.010`, an `integer64` has to keep every digit, and a status, a modifier or a negation must never be
24
+ skipped, because a missed `refuted` reads as its opposite. We built `@cosyte/fhir` for the engineer
25
+ who reads FHIR R4 from a server or an EHR (the format ONC HTI-1 binds §170.315(g)(10) to, with US
26
+ Core and SMART on FHIR) and has to get those values right without reading the specification first.
27
+ Type definitions alone describe a resource's shape and check nothing at run time, and `JSON.parse`
28
+ turns `0.010` into the number `0.01` and knows nothing about modifiers. This library reads, writes
29
+ and validates FHIR R4 with zero runtime dependencies, and tells you with a coded reason what it could
30
+ not read safely.
31
+
32
+ ## Status
33
+
34
+ **The 0.1 line.** From 0.1 the public API is settled: the exported names, options, result shapes and
35
+ issue codes are the surface we keep stable. While the package is below 1.0, a breaking change ships
36
+ in a minor version and is called out in the
37
+ [changelog](https://github.com/cosyte/fhir/blob/main/CHANGELOG.md). Upgrading from 0.0.10 changes
38
+ verdicts: R4's own constraints are now evaluated with no profile supplied, so a document that read
39
+ valid can read invalid. The changelog sets out each change.
40
+
41
+ What it covers, against FHIR R4 (`4.0.1`): reading and writing JSON and XML into one immutable
42
+ model; validation in layers (structure, cardinality, value domains, R4's own constraints on the
43
+ eight modeled resource types, Quantity and UCUM, binding strength, and profiles you supply or author
44
+ with `defineProfile`, including their FHIRPath invariants); the `readSafety` and
45
+ `assertSafeToSummarize` safety readout; and Bundles, references and streaming Bulk Data NDJSON. R5
46
+ and DSTU2 documents can be read, since the model is schema-free, but they are not validated against
47
+ their own definitions.
5
48
 
6
- Status: pre-alpha.
49
+ Not covered yet: typed per-resource models (the built-in structural schemas cover the base elements
50
+ plus `Patient`), `type` and `profile` slicing discriminators and reslicing (reported
51
+ `PROFILE_SLICE_UNCHECKED`), FHIRPath outside the supported subset (reported `INVARIANT_UNCHECKED`,
52
+ never passed), bundled terminology or US Core content, spec-clean JSON written from a model read out
53
+ of XML, unit conversion, and executing a transaction Bundle.
7
54
 
8
55
  ## Install
9
56
 
10
- ```sh
11
- npm install @cosyte/fhir
57
+ ```bash
58
+ # pnpm (recommended). Also works with: npm install @cosyte/fhir | yarn add @cosyte/fhir
59
+ pnpm add @cosyte/fhir
60
+ ```
61
+
62
+ Requires Node `>=22.0.0`. The package ships dual ESM and CommonJS builds with type declarations for
63
+ both, so `import` and `require` both work and neither needs a compatibility shim. There are zero
64
+ runtime dependencies, and it imports no Node built-in.
65
+
66
+ ## Usage
67
+
68
+ Read a document, keep its exact values, and get a verdict. The Observation below is synthetic: every
69
+ value in it is fabricated, and the same document is committed as a test fixture in this repository.
70
+
71
+ ```ts runnable
72
+ import { parseResource, readObservationValue, validateResource } from "@cosyte/fhir";
73
+
74
+ const document = `{
75
+ "resourceType": "Observation",
76
+ "id": "syn-0001",
77
+ "status": "final",
78
+ "code": { "coding": [{ "system": "http://loinc.org", "code": "8480-6" }] },
79
+ "subject": { "reference": "Patient/syn-0001" },
80
+ "effectiveDateTime": "2026-01-05",
81
+ "valueQuantity": {
82
+ "value": 120.0,
83
+ "unit": "mmHg",
84
+ "system": "http://unitsofmeasure.org",
85
+ "code": "mm[Hg]"
86
+ }
87
+ }`;
88
+
89
+ const { resource, issues } = parseResource(document);
90
+
91
+ // The magnitude was written 120.0: the read keeps that exact form and says the protection mattered.
92
+ issues.map((issue) => issue.code); // => ["DECIMAL_PRECISION_AT_RISK"]
93
+
94
+ // Branch on the value[x] type before touching a magnitude, and compare on the UCUM code.
95
+ const reading = readObservationValue(resource);
96
+ reading?.type; // => "Quantity"
97
+ reading?.quantity?.value?.raw; // => "120.0"
98
+ reading?.quantity?.code; // => "mm[Hg]"
99
+
100
+ validateResource(resource).valid; // => true
101
+ ```
102
+
103
+ The quickstart on [docs.cosyte.com/fhir](https://docs.cosyte.com/fhir) walks the same document step
104
+ by step, and [`examples/`](https://github.com/cosyte/fhir/tree/main/examples) holds four runnable
105
+ programs: read and validate, the safety readout, JSON and XML, and Bundles with Bulk Data NDJSON.
106
+
107
+ ## API
108
+
109
+ Everything ships from one entry point; there are no subpath imports.
110
+
111
+ - **Read and write.** `parseResource` and `serializeResource` for JSON, `parseResourceXml` and
112
+ `serializeResourceXml` for XML, over one schema-free model, and `nodesEquivalent` to compare a
113
+ model read from one format with a model read from the other. A `decimal` or an `integer64` keeps
114
+ its exact text (`FhirDecimal`, `FhirInteger64`) and never passes through a JavaScript number.
115
+ - **Validate.** `validateResource` returns `valid`, the issues, and `toOperationOutcome()` to render
116
+ them as an `OperationOutcome`. Pass the `profiles` you load with `loadStructureDefinition` or
117
+ author with `defineProfile`, and a `terminology` service of your own for code validity.
118
+ - **Read status and negation.** `readSafety` surfaces status, modifiers and negations.
119
+ `assertSafeToSummarize` throws `FhirSafetyError`, carrying locations only, when a resource holds
120
+ something it cannot summarize honestly, such as a `modifierExtension` it does not understand.
121
+ - **Read measured values.** `readObservationValue` branches on the `value[x]` type and keeps the
122
+ UCUM `code`, and `readMedicationDoses` reads dose quantities. No unit is ever converted.
123
+ - **Bundles and NDJSON.** `readBundle` tells a transaction (all or nothing) from a batch and
124
+ executes neither, `resolveReference` resolves relative, absolute, logical and `#fragment`
125
+ references, and `streamNdjson` reads a Bulk Data export line by line, reporting a malformed line
126
+ and carrying on.
127
+
128
+ ## PHI and safety
129
+
130
+ FHIR resources carry protected health information, so treat every document you hand this library
131
+ as PHI.
132
+
133
+ - **It works in memory.** It reads, validates and writes in memory and nothing else. It opens no
134
+ socket, writes nothing to disk and fetches nothing at run time; it has zero runtime dependencies,
135
+ imports no Node built-in, and calls no terminology service unless you pass one in.
136
+ - **Diagnostics carry no values.** An issue is a code and a FHIRPath location, never the value it
137
+ was raised over. A location can repeat an element name the document supplied when that name has
138
+ the published form of a FHIR name, so treat a location as derived from the document.
139
+ - **The XML reader accepts plain XML only.** Anything else is refused with a typed `FhirXmlError`
140
+ that carries a code and a byte offset, never a slice of the document. The reader performs no I/O
141
+ and resolves no URI. The troubleshooting pages on
142
+ [docs.cosyte.com/fhir](https://docs.cosyte.com/fhir) list each refusal and its code.
143
+ - **Nesting is bounded.** Both readers stop at a fixed depth with a typed error, so a deeply nested
144
+ document fails cleanly rather than exhausting the stack.
145
+ - **A status or a negation is not skipped silently.** `assertSafeToSummarize` refuses a resource
146
+ carrying a `modifierExtension` it does not understand, and each other shape it cannot summarize
147
+ honestly, rather than letting a summary walk past it.
148
+ - **What you still own.** Transport, storage, retention, access control, audit logging, and every
149
+ log line your own code writes. This library makes no compliance claim on your behalf.
150
+
151
+ ## Documentation
152
+
153
+ - [docs.cosyte.com/fhir](https://docs.cosyte.com/fhir): installation, the quickstart, core
154
+ concepts, guides, current limits and troubleshooting.
155
+ - [`documentation/capabilities.md`](https://github.com/cosyte/fhir/blob/main/documentation/capabilities.md):
156
+ the full capability readout, layer by layer, with what each one checks and what it leaves open.
157
+ - [`documentation/`](https://github.com/cosyte/fhir/tree/main/documentation) in the repository: the
158
+ capability readout, the FHIRPath coverage measured against the shared R4 conformance suite, and
159
+ the architecture decisions.
160
+ - [`CHANGELOG.md`](https://github.com/cosyte/fhir/blob/main/CHANGELOG.md): every change, with the
161
+ breaking ones called out.
162
+
163
+ ## Contributing
164
+
165
+ Questions, bug reports and FHIR quirks from the servers and EHRs you connect to all belong in
166
+ [GitHub issues](https://github.com/cosyte/fhir/issues). Pull requests are welcome; every fixture
167
+ must be synthetic, never a real patient's data.
168
+
169
+ ```bash
170
+ pnpm install
171
+ pnpm build # dual ESM + CJS + .d.ts
172
+ pnpm typecheck
173
+ pnpm lint
174
+ pnpm test
12
175
  ```
13
176
 
177
+ Every meaningful change gets a Changeset (`pnpm changeset`: `minor` for new capability or a breaking
178
+ change while the version is below 1.0, `patch` for a fix) and a `CHANGELOG.md` `[Unreleased]`
179
+ entry. See [`CONTRIBUTING.md`](https://github.com/cosyte/fhir/blob/main/CONTRIBUTING.md).
180
+
14
181
  ## License
15
182
 
16
- MIT
183
+ MIT, copyright Cosyte. See [LICENSE](./LICENSE).