@health-samurai/aidbox-client 0.0.0-alpha.2 → 0.0.0-alpha.3

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 (36) hide show
  1. package/README.md +234 -68
  2. package/dist/src/auth-providers.d.ts +13 -0
  3. package/dist/src/auth-providers.d.ts.map +1 -1
  4. package/dist/src/auth-providers.js +13 -4
  5. package/dist/src/client.d.ts +504 -31
  6. package/dist/src/client.d.ts.map +1 -1
  7. package/dist/src/client.js +1455 -934
  8. package/dist/src/fhir-types/hl7-fhir-r4-core/Address.d.ts +26 -0
  9. package/dist/src/fhir-types/hl7-fhir-r4-core/Address.d.ts.map +1 -0
  10. package/dist/src/fhir-types/hl7-fhir-r4-core/Address.js +5 -0
  11. package/dist/src/fhir-types/hl7-fhir-r4-core/ContactPoint.d.ts +16 -0
  12. package/dist/src/fhir-types/hl7-fhir-r4-core/ContactPoint.d.ts.map +1 -0
  13. package/dist/src/fhir-types/hl7-fhir-r4-core/ContactPoint.js +5 -0
  14. package/dist/src/fhir-types/hl7-fhir-r4-core/DomainResource.d.ts +1 -1
  15. package/dist/src/fhir-types/hl7-fhir-r4-core/DomainResource.d.ts.map +1 -1
  16. package/dist/src/fhir-types/hl7-fhir-r4-core/HumanName.d.ts +20 -0
  17. package/dist/src/fhir-types/hl7-fhir-r4-core/HumanName.d.ts.map +1 -0
  18. package/dist/src/fhir-types/hl7-fhir-r4-core/HumanName.js +5 -0
  19. package/dist/src/fhir-types/hl7-fhir-r4-core/Patient.d.ts +58 -0
  20. package/dist/src/fhir-types/hl7-fhir-r4-core/Patient.d.ts.map +1 -0
  21. package/dist/src/fhir-types/hl7-fhir-r4-core/Patient.js +10 -0
  22. package/dist/src/fhir-types/hl7-fhir-r4-core/Resource.d.ts +1 -1
  23. package/dist/src/fhir-types/hl7-fhir-r4-core/Resource.d.ts.map +1 -1
  24. package/dist/src/fhir-types/hl7-fhir-r4-core/index.d.ts +5 -0
  25. package/dist/src/fhir-types/hl7-fhir-r4-core/index.d.ts.map +1 -1
  26. package/dist/src/fhir-types/hl7-fhir-r4-core/index.js +1 -0
  27. package/dist/src/result.d.ts +114 -3
  28. package/dist/src/result.d.ts.map +1 -1
  29. package/dist/src/result.js +6 -2
  30. package/dist/src/types.d.ts +104 -70
  31. package/dist/src/types.d.ts.map +1 -1
  32. package/dist/src/types.js +10 -2
  33. package/package.json +2 -1
  34. package/dist/src/fhir-http.d.ts +0 -96
  35. package/dist/src/fhir-http.d.ts.map +0 -1
  36. package/dist/src/fhir-http.js +0 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Typescript FHIR client
2
2
 
3
- A typescript client for interacting with a FHIR server.
3
+ A TypeScript client for interacting with a FHIR server.
4
4
 
5
5
  ## Usage
6
6
 
@@ -8,21 +8,207 @@ The client is created with the `makeClient` function:
8
8
 
9
9
  ```typescript
10
10
  const baseUrl = "https://fhir-server.address";
11
- const client = makeClient({
11
+ const client = new AidboxClient(
12
12
  baseUrl,
13
- authProvider: new BrowserAuthProvider(baseUrl);
13
+ new BrowserAuthProvider(baseUrl),
14
+ );
15
+ ```
16
+
17
+ ## Documentation
18
+
19
+ Documentation is generated automatically, and can be found [here](https://healthsamurai.github.io/aidbox-ts-sdk/aidbox-client/).
20
+
21
+ ## Type Generator
22
+
23
+ This project is designed around the type generator that provides FHIR types based on the specified package.
24
+ However, not all types are provided in the client itself, only the necessary ones, like `Bundle`, and `OperationOutcome`.
25
+ If your application requires more types, use [atomic-ehr/codegen](https://github.com/atomic-ehr/codegen) to generate more types.
26
+
27
+ For example, using `atomic-ehr/codegen`, we can generate and import an `Observation` type, and ensure that all fields are provided when creating a resource:
28
+
29
+ ```typescript
30
+ import type { Observation } from "hl7-fhir-r4-core";
31
+
32
+ client.create<Observation>({
33
+ resourceType: "Observation",
34
+ status: "final",
35
+ code: {
36
+ coding: [{
37
+ system: "http://loinc.org",
38
+ code: "59408-5",
39
+ display: "Blood pressure systolic & diastolic"
40
+ }],
41
+ text: "Blood pressure"
42
+ },
43
+ subject: {
44
+ reference: "Patient/pt-1"
45
+ },
46
+ effectiveDateTime: "2025-12-05T00:00:00Z",
47
+ valueString: "minimal"
48
+ })
49
+ ```
50
+
51
+ The default set of types in the client is based on FHIR R4 Core.
52
+ If your application requires a different set of types, it is possible to override that through type parameters when creating a client:
53
+
54
+ ```typescript
55
+ import type * as R5 from "hl7-fhir-r5-core";
56
+ import type { User } from "@health-samurai/aidbox-client";
57
+
58
+ const baseUrl = "https://fhir-server.address";
59
+
60
+ const client = new AidboxClient<R5.Bundle, R5.OperationOutcome, User> (
61
+ baseUrl,
62
+ new BrowserAuthProvider(baseUrl),
63
+ );
64
+ ```
65
+
66
+ ## [FHIR Interactions](https://hl7.org/fhir/http.html)
67
+
68
+ This client provides a set of methods to work with a FHIR server in a more convenient way:
69
+
70
+ - Instance Level Interaction
71
+ - `read` - Read the current state of the resource
72
+ - `vread` - Read the state of a specific version of the resource
73
+ - `update` - Update an existing resource by its id (or create it if it is new)
74
+ - `conditionalUpdate` - Update an existing resource based on some identification criteria (or create it if it is new).
75
+ - `patch` - Update an existing resource by posting a set of changes to it.
76
+ - `conditionalPatch` - Update an existing resource, based on some identification criteria, by posting a set of changes to it.
77
+ - `delete` - Delete a resource.
78
+ - `deleteHistory` - Delete all historical versions of a resource.
79
+ - `deleteHistoryVersion` - Delete a specific version of a resource.
80
+ - `history` - Retrieve the change history for a particular resource.
81
+ - Type Level Interaction
82
+ - `create` - Create a new resource with a server assigned id
83
+ - `conditionalCreate` - Create a new resource with a server assigned id if an equivalent resource does not already exist.
84
+ - `search` - Search the resource type based on some filter criteria.
85
+ - `conditionalDelete` - Conditional delete a single or multiple resources based on some identification criteria.
86
+ - `history` - Retrieve the change history for a particular resource type.
87
+ - Whole System Interaction
88
+ - `capabilities` - Get a capability statement for the system.
89
+ - `batch`/`transaction` - Perform multiple interactions (e.g., create, read, update, delete, patch, and/or [extended operations]) in a single interaction.
90
+ - `delete` - Conditional Delete across all resource types based on some filter criteria.
91
+ - `history` - Retrieve the change history for all resources.
92
+ - `search` - Search across all resource types based on some filter criteria.
93
+ - Compartment Interaction
94
+ - `search` - Search resources associated with a specific compartment instance (see [Search Contexts](https://build.fhir.org/search.html#searchcontexts) and [Compartments](https://build.fhir.org/compartmentdefinition.html))
95
+ - Operations Framework
96
+ - `operation` - Perform an operation as defined by an `OperationDefinition`.
97
+ - `validate` - Perform the Validate Operation.
98
+
99
+ ### Patient CRUD Example
100
+
101
+ Here's an example of
102
+
103
+ ```typescript
104
+ import { AidboxClient, BrowserAuthProvider } from "@health-samurai/aidbox-client";
105
+ import type { Patient } from "hl7-fhir-r4-core";
106
+ import { formatOperationOutcome } from "utils";
107
+
108
+ const client = new AidboxClient(
109
+ "http://localhost:8080",
110
+ new BrowserAuthProvider("http://localhost:8080"),
111
+ );
112
+
113
+ // Create a new Patient resource
114
+ const result = await client.create<Patient>({
115
+ type: "Patient",
116
+ resource: {
117
+ gender: "female",
118
+ resourceType: "Patient",
119
+ },
14
120
  });
121
+
122
+ // Check if interaction was successful
123
+ if (result.isErr())
124
+ throw Error(formatOperationOutcome(result.value.resource), {
125
+ cause: result.value.resource,
126
+ });
127
+
128
+ const patient = result.value.resource;
129
+
130
+ if (!patient.id)
131
+ throw Error(
132
+ "id is optional in FHIR, so we check it to satisfy the type checker",
133
+ );
134
+
135
+ // Updating the patient
136
+
137
+ patient.name = [
138
+ {
139
+ given: ["Jane"],
140
+ family: "Doe",
141
+ },
142
+ ];
143
+
144
+ const updateResult = await client.update<Patient>({
145
+ id: patient.id,
146
+ type: "Patient",
147
+ resource: patient,
148
+ });
149
+
150
+ if (updateResult.isErr())
151
+ throw Error(formatOperationOutcome(updateResult.value.resource), {
152
+ cause: updateResult.value.resource,
153
+ });
154
+
155
+ // Deleting the patient
156
+
157
+ const deleteResult = await client.delete<Patient>({
158
+ id: patient.id,
159
+ type: "Patient",
160
+ });
161
+
162
+ if (deleteResult.isErr())
163
+ throw Error(formatOperationOutcome(deleteResult.value.resource), {
164
+ cause: deleteResult.value.resource,
165
+ });
15
166
  ```
16
167
 
17
- ## Methods
168
+ ### Return data format
18
169
 
19
- The client provides two basic methods of interaction:
170
+ As seen in the example above, most methods return a `Result<T, E>` object.
171
+ This object represents a successful or erroneous state of the response.
20
172
 
21
- - `rawRequest` - send request to the FHIR server and recieve response in a raw format
22
- - `request<T>` - send request to the FHIR server and recieve response with its body parsed to the specified type `T`
173
+ A general usage pattern is as follows:
23
174
 
24
- In successful case, the `rawRequest` returns an object with JavaScript Repsonse, and additional meta information.
25
- When server responds with an error code, this function throws an error:
175
+ ```typescript
176
+ const result = await client.read<Patient>({ type: 'Patient', id: 'patient-id' });
177
+
178
+ if (result.isErr())
179
+ throw new Error("error reading Patient", { cause: result.value.resource })
180
+
181
+ const patient = result.value.resource;
182
+
183
+ // work with patient.
184
+ ```
185
+
186
+ It is also possible to work with resources without unwrapping the `Result` object:
187
+
188
+ ```typescript
189
+ const result = await client.read<Patient>({ type: 'Patient', id: 'patient-id' });
190
+
191
+ return result
192
+ .map(({resource}: {resource: Patient}): Patient => {
193
+ /* work with Patient resource */
194
+ })
195
+ .mapErr(({resource}: {resource: OperationOutcome}): OperationOutcome => {
196
+ /* work with OperationOutcome resource */
197
+ });
198
+ // result is still Result<Patient, OperationOutcome>
199
+ ```
200
+
201
+ See the [documentation](https://healthsamurai.github.io/aidbox-ts-sdk/aidbox-client/) for more info.
202
+
203
+ ## Low-level methods
204
+
205
+ The client provides two basic methods for writing custom interactions:
206
+
207
+ - `rawRequest` - send request to the FHIR server and receive response in a raw format
208
+ - `request<T>` - send request to the FHIR server and receive response with its body parsed to the specified type `T`
209
+
210
+ In a successful case, the `rawRequest` returns an object with JavaScript Response and additional meta information.
211
+ When the server responds with an error code, this function throws an error:
26
212
 
27
213
  ```typescript
28
214
  const result = await client.rawRequest({
@@ -33,7 +219,7 @@ const result = await client.rawRequest({
33
219
  }).then((result) => {
34
220
  const patient: Patient = await result.response.json();
35
221
  // ...
36
- }).catch ((error) => {
222
+ }).catch((error) => {
37
223
  if (error instanceof ErrorResponse) {
38
224
  const outcome = await error.responseWithMeta.response.json
39
225
  // ...
@@ -41,7 +227,7 @@ const result = await client.rawRequest({
41
227
  });
42
228
  ```
43
229
 
44
- Alternatively, a `request` method can be used.
230
+ Alternatively, the `request` method can be used.
45
231
  It returns a `Result<T, OperationOutcome>`, which contains an already parsed result, coerced to the specified type `T`.
46
232
 
47
233
  ```typescript
@@ -63,68 +249,48 @@ if (result.isErr()) {
63
249
  }
64
250
  ```
65
251
 
66
- Both methods can throw `RequestError` class, if the error happened before the request was actually made.
67
-
68
- ### [FHIR HTTP](https://hl7.org/fhir/http.html) methods:
69
-
70
- Additional set of methods is provided to work with FHIR server in a more convinient way:
71
-
72
- - [x] Instance Level Interaction
73
- - [x] `read` - Read the current state of the resource
74
- - [x] `vread` - Read the state of a specific version of the resource
75
- - [x] `update` - Update an existing resource by its id (or create it if it is new)
76
- - [x] `conditionalUpdate` - Update an existing resource based on some identification criteria (or create it if it is new)
77
- - [x] `patch` - Update an existing resource by posting a set of changes to it
78
- - [x] `conditionalPatch` - Update an existing resource, based on some identification criteria, by posting a set of changes to it
79
- - [x] `delete` - Delete a resource
80
- - [x] `deleteHistory` - Delete all historical versions of a resource
81
- - [x] `deleteHistoryVersion` - Delete a specific version of a resource
82
- - [x] `history` - Retrieve the change history for a particular resource
83
- - [x] Type Level Interaction
84
- - [x] `create` - Create a new resource with a server assigned id
85
- - [x] `conditionalCreate` - Create a new resource with a server assigned id if an equivalent resource does not already exist
86
- - [x] `search` - Search the resource type based on some filter criteria
87
- - [x] `conditionalDelete` - Conditional delete a single or multiple resources based on some identification criteria
88
- - [x] `history` - Retrieve the change history for a particular resource type
89
- - [x] Whole System Interaction
90
- - [x] `capabilities` - Get a capability statement for the system
91
- - [x] `batch`/`transaction` - Perform multiple interactions (e.g., create, read, update, delete, patch, and/or [extended operations]) in a single interaction
92
- - [x] `delete` - Conditional Delete across all resource types based on some filter criteria
93
- - [x] `history` - Retrieve the change history for all resources
94
- - [x] `search` - Search across all resource types based on some filter criteria
95
- - [x] Compartment Interaction
96
- - [x] `search` - Search resources associated with a specific compartment instance (see [Search Contexts](https://build.fhir.org/search.html#searchcontexts) and [Compartments](https://build.fhir.org/compartmentdefinition.html))
97
-
98
- <!--
99
- TODO: Operations
100
- https://build.fhir.org/operations.html
101
- -->
102
-
103
- ## Return data format
104
-
105
- Most client methods return a `Result<T, E>` object, with methods to check if the request was successful:
252
+ Both methods can throw the `RequestError` class if the error happened before the request was actually made.
106
253
 
107
- ```typescript
108
- const result = await client.read<Patient>({type: 'Patient', id: 'patient-id'});
109
- if (result.isErr())
110
- throw new Error("error reading Patient", { cause: result.value })
254
+ ## Authentication Providers
111
255
 
112
- const { resource: patient } = result.value;
256
+ Authentication is managed via the `AuthProvider` interface.
113
257
 
114
- // work with patient.
115
- ```
258
+ Currently, the client only provides a `BrowserAuthProvider` class.
259
+ It is suitable for usage in browsers, but other environments may require a different method.
116
260
 
117
- Unwrapping is not required to modify the data in the `Result`:
261
+ Thus, an application can describe its own Auth Provider by implementing a class that implements `AuthProvider`:
118
262
 
119
263
  ```typescript
120
- const result = await client.read<Patient>({type: 'Patient', id: 'patient-id'});
264
+ import type { AuthProvider } from "@health-samurai/aidbox-client";
121
265
 
122
- return result
123
- .map(({resource}: {resource: Patient}): Patient => {
124
- /* work with Patient resource */
125
- })
126
- .mapErr(({resource}: {resource: OperationOutcome}): OperationOutcome => {
127
- /* work with OperationOutcome resource */
128
- });
129
- // result is still Result<Patient, OperationOutcome>
266
+ export class CustomAuthProvider implements AuthProvider {
267
+ public baseUrl: string;
268
+
269
+ constructor(baseUrl: string) {
270
+ this.baseUrl = baseUrl;
271
+ }
272
+
273
+ public async establishSession() {
274
+ /* code to establish a session */
275
+ }
276
+
277
+ public async revokeSession() {
278
+ /* code to revoke the session */
279
+ }
280
+
281
+ public async fetch(
282
+ input: RequestInfo | URL,
283
+ init?: RequestInit,
284
+ ): Promise<Response> {
285
+ /**
286
+ * A wrapper around the `fetch` function, that does all the
287
+ * necessary preparations and argument patching required for the
288
+ * request to go through.
289
+ *
290
+ * Optionally, security checks can be implemented, like verifying
291
+ * that the request indeed goes to the `baseUrl`, and not
292
+ * somewhere else.
293
+ */
294
+ }
295
+ }
130
296
  ```
@@ -1,10 +1,23 @@
1
1
  import type { AuthProvider } from "./types";
2
2
  export declare class BrowserAuthProvider implements AuthProvider {
3
3
  #private;
4
+ /** @ignore */
4
5
  baseUrl: string;
5
6
  constructor(baseUrl: string);
7
+ /**
8
+ * Checks if the session is already authenticated, and if not, redirects to the login page.
9
+ */
6
10
  establishSession(): Promise<void>;
11
+ /**
12
+ * Sends a POST request to `baseurl/auth/logout`.
13
+ */
7
14
  revokeSession(): Promise<void>;
15
+ /**
16
+ * A thin wrapper around `fetch` function.
17
+ * Checks if the client is authorized to perform a request, and redirects to a login page if not.
18
+ *
19
+ * Accepts the same arguments as `fetch`.
20
+ */
8
21
  fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
9
22
  }
10
23
  //# sourceMappingURL=auth-providers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth-providers.d.ts","sourceRoot":"","sources":["../../src/auth-providers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,qBAAa,mBAAoB,YAAW,YAAY;;IAChD,OAAO,EAAE,MAAM,CAAC;gBAEX,OAAO,EAAE,MAAM;IAgBd,gBAAgB;IAQhB,aAAa;IAWb,KAAK,CACjB,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,GAChB,OAAO,CAAC,QAAQ,CAAC;CAsBpB"}
1
+ {"version":3,"file":"auth-providers.d.ts","sourceRoot":"","sources":["../../src/auth-providers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,qBAAa,mBAAoB,YAAW,YAAY;;IACvD,cAAc;IACP,OAAO,EAAE,MAAM,CAAC;gBAEX,OAAO,EAAE,MAAM;IAgB3B;;OAEG;IACU,gBAAgB;IAQ7B;;OAEG;IACU,aAAa;IAW1B;;;;;OAKG;IACU,KAAK,CACjB,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,GAChB,OAAO,CAAC,QAAQ,CAAC;CAsBpB"}
@@ -178,13 +178,15 @@ export var BrowserAuthProvider = /*#__PURE__*/ function() {
178
178
  function BrowserAuthProvider(baseUrl) {
179
179
  _class_call_check(this, BrowserAuthProvider);
180
180
  _class_private_method_init(this, _checkSession);
181
- _define_property(this, "baseUrl", void 0);
181
+ /** @ignore */ _define_property(this, "baseUrl", void 0);
182
182
  this.baseUrl = baseUrl;
183
183
  }
184
184
  _create_class(BrowserAuthProvider, [
185
185
  {
186
186
  key: "establishSession",
187
- value: function establishSession() {
187
+ value: /**
188
+ * Checks if the session is already authenticated, and if not, redirects to the login page.
189
+ */ function establishSession() {
188
190
  return _async_to_generator(function() {
189
191
  var encodedLocation, redirectTo;
190
192
  return _ts_generator(this, function(_state) {
@@ -210,7 +212,9 @@ export var BrowserAuthProvider = /*#__PURE__*/ function() {
210
212
  },
211
213
  {
212
214
  key: "revokeSession",
213
- value: function revokeSession() {
215
+ value: /**
216
+ * Sends a POST request to `baseurl/auth/logout`.
217
+ */ function revokeSession() {
214
218
  return _async_to_generator(function() {
215
219
  return _ts_generator(this, function(_state) {
216
220
  switch(_state.label){
@@ -238,7 +242,12 @@ export var BrowserAuthProvider = /*#__PURE__*/ function() {
238
242
  },
239
243
  {
240
244
  key: "fetch",
241
- value: function fetch1(input, init) {
245
+ value: /**
246
+ * A thin wrapper around `fetch` function.
247
+ * Checks if the client is authorized to perform a request, and redirects to a login page if not.
248
+ *
249
+ * Accepts the same arguments as `fetch`.
250
+ */ function fetch1(input, init) {
242
251
  return _async_to_generator(function() {
243
252
  var url, i, response;
244
253
  return _ts_generator(this, function(_state) {