@oystehr/sdk 4.3.8 → 4.3.10
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 +105 -41
- package/dist/cjs/client/client.cjs +137 -5
- package/dist/cjs/client/client.cjs.map +1 -1
- package/dist/cjs/client/client.d.ts +28 -3
- package/dist/cjs/index.min.cjs +1 -1
- package/dist/cjs/index.min.cjs.map +1 -1
- package/dist/cjs/resources/classes/fhir-ext.cjs +277 -17
- package/dist/cjs/resources/classes/fhir-ext.cjs.map +1 -1
- package/dist/cjs/resources/classes/fhir-ext.d.ts +114 -12
- package/dist/cjs/resources/classes/fhir.cjs +14 -0
- package/dist/cjs/resources/classes/fhir.cjs.map +1 -1
- package/dist/cjs/resources/classes/fhir.d.ts +14 -0
- package/dist/cjs/resources/types/FaxSendParams.d.ts +1 -1
- package/dist/cjs/resources/types/ZambdaCreateParams.d.ts +1 -1
- package/dist/cjs/resources/types/ZambdaUpdateParams.d.ts +1 -1
- package/dist/cjs/resources/types/fhir.d.ts +74 -0
- package/dist/esm/client/client.d.ts +28 -3
- package/dist/esm/client/client.js +137 -5
- package/dist/esm/client/client.js.map +1 -1
- package/dist/esm/index.min.js +1 -1
- package/dist/esm/index.min.js.map +1 -1
- package/dist/esm/resources/classes/fhir-ext.d.ts +114 -12
- package/dist/esm/resources/classes/fhir-ext.js +273 -19
- package/dist/esm/resources/classes/fhir-ext.js.map +1 -1
- package/dist/esm/resources/classes/fhir.d.ts +14 -0
- package/dist/esm/resources/classes/fhir.js +15 -1
- package/dist/esm/resources/classes/fhir.js.map +1 -1
- package/dist/esm/resources/types/FaxSendParams.d.ts +1 -1
- package/dist/esm/resources/types/ZambdaCreateParams.d.ts +1 -1
- package/dist/esm/resources/types/ZambdaUpdateParams.d.ts +1 -1
- package/dist/esm/resources/types/fhir.d.ts +74 -0
- package/package.json +1 -1
- package/src/client/client.ts +214 -7
- package/src/resources/classes/fhir-ext.ts +483 -38
- package/src/resources/classes/fhir.ts +14 -0
- package/src/resources/types/FaxSendParams.ts +1 -1
- package/src/resources/types/ZambdaCreateParams.ts +1 -1
- package/src/resources/types/ZambdaUpdateParams.ts +1 -1
- package/src/resources/types/fhir.ts +97 -0
package/README.md
CHANGED
|
@@ -22,9 +22,6 @@
|
|
|
22
22
|
[](https://npmjs.com/package/@oystehr/sdk)
|
|
23
23
|
[](https://npmjs.com/package/@oystehr/sdk)
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
25
|
</div>
|
|
29
26
|
|
|
30
27
|
# Oystehr SDK
|
|
@@ -65,9 +62,9 @@ const patient = await oystehr.fhir.create<Patient>({
|
|
|
65
62
|
// Upload a zambda
|
|
66
63
|
try {
|
|
67
64
|
const zambda = await oystehr.zambda.create({ name: 'new zambda', triggerMethod: 'http_open' });
|
|
68
|
-
const fileHandle = await fs.open('./path/to/my/zambda.zip')
|
|
65
|
+
const fileHandle = await fs.open('./path/to/my/zambda.zip');
|
|
69
66
|
const file = new Blob([await fileHandle.readFile()]);
|
|
70
|
-
await oystehr.zambda.uploadFile({ id: createZambda.data.id, file
|
|
67
|
+
await oystehr.zambda.uploadFile({ id: createZambda.data.id, file });
|
|
71
68
|
} catch (err) {
|
|
72
69
|
// Handle error thrown by Oystehr or JS in some way
|
|
73
70
|
}
|
|
@@ -143,9 +140,9 @@ console.log(JSON.stringify(result, null, 2));
|
|
|
143
140
|
|
|
144
141
|
The Oystehr SDK will retry on a variety of errors by default:
|
|
145
142
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
- Common Node.js and Undici networking errors
|
|
144
|
+
- Rate limiting status codes (`408`, `429`)
|
|
145
|
+
- Potentially ephemeral upstream status codes (`500`, `502`, `503`, `504`)
|
|
149
146
|
|
|
150
147
|
Note that the Oystehr FHIR API is eventually consistent, so if you are retrieving or updating a resource immediately after creating it, it's recommended to retry on `404` and `412` status codes as well.
|
|
151
148
|
|
|
@@ -221,7 +218,7 @@ When performing a FHIR search, the resulting type is `Bundle`. The Oystehr SDK h
|
|
|
221
218
|
```typescript
|
|
222
219
|
import Oystehr from '@oystehr/sdk';
|
|
223
220
|
import { Patient } from 'fhir/r4b';
|
|
224
|
-
const patientBundle/*: Bundle<Patient>*/ = await oystehr.fhir.search<Patient>({
|
|
221
|
+
const patientBundle /*: Bundle<Patient>*/ = await oystehr.fhir.search<Patient>({
|
|
225
222
|
resourceType: 'Patient',
|
|
226
223
|
params: [
|
|
227
224
|
{
|
|
@@ -230,7 +227,67 @@ const patientBundle/*: Bundle<Patient>*/ = await oystehr.fhir.search<Patient>({
|
|
|
230
227
|
},
|
|
231
228
|
],
|
|
232
229
|
});
|
|
233
|
-
const patients/*: Patient[]*/ = patientBundle.unbundle();
|
|
230
|
+
const patients /*: Patient[]*/ = patientBundle.unbundle();
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### FHIR Async Operations
|
|
234
|
+
|
|
235
|
+
Async FHIR methods require a mode option.
|
|
236
|
+
|
|
237
|
+
- Use `{ mode: 'async-bundle' }` for async completion bundles.
|
|
238
|
+
- Use `{ mode: 'async-bulk' }` to request async bulk output manifests.
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
import Oystehr from '@oystehr/sdk';
|
|
242
|
+
import { Patient } from 'fhir/r4b';
|
|
243
|
+
|
|
244
|
+
const oystehr = new Oystehr({ accessToken: '<token>' });
|
|
245
|
+
|
|
246
|
+
const handle = await oystehr.fhir.search<Patient>(
|
|
247
|
+
{
|
|
248
|
+
resourceType: 'Patient',
|
|
249
|
+
params: [{ name: 'name', value: 'sam' }],
|
|
250
|
+
},
|
|
251
|
+
{ mode: 'async-bulk' }
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
const status = await oystehr.fhir.waitForAsyncJob(handle.jobId, {
|
|
255
|
+
pollIntervalMs: 1000,
|
|
256
|
+
timeoutMs: 600000,
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
if (status.status === 200 && status.mode === 'bulk') {
|
|
260
|
+
console.log(status.manifest.output);
|
|
261
|
+
|
|
262
|
+
// Fetch NDJSON results from bulk manifest output URLs.
|
|
263
|
+
for (const file of status.manifest.output) {
|
|
264
|
+
const response = await fetch(file.url, {
|
|
265
|
+
headers: status.manifest.requiresAccessToken ? { Authorization: `Bearer ${token}` } : undefined,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
if (!response.ok) {
|
|
269
|
+
throw new Error(`Failed to download bulk output (${file.type}): HTTP ${response.status}`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const ndjson = await response.text();
|
|
273
|
+
console.log(file.type, ndjson.split('\n').filter(Boolean).length);
|
|
274
|
+
|
|
275
|
+
// Minimal example: parse NDJSON and get one Patient resource.
|
|
276
|
+
if (file.type === 'Patient') {
|
|
277
|
+
const patient = ndjson
|
|
278
|
+
.split('\n')
|
|
279
|
+
.filter(Boolean)
|
|
280
|
+
.map((line) => JSON.parse(line))
|
|
281
|
+
.find((resource) => resource.resourceType === 'Patient');
|
|
282
|
+
|
|
283
|
+
console.log('Found Patient:', patient?.id);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (status.status === 200 && status.mode === 'bundle') {
|
|
289
|
+
console.log(status.bundle.entry?.[0]?.response?.status);
|
|
290
|
+
}
|
|
234
291
|
```
|
|
235
292
|
|
|
236
293
|
### Batch Requests
|
|
@@ -250,24 +307,26 @@ const oystehr = new Oystehr({
|
|
|
250
307
|
const patchAppointment: BatchInputPatchRequest = {
|
|
251
308
|
method: 'PATCH',
|
|
252
309
|
url: '/Appointment/some_appointment_id',
|
|
253
|
-
operations: [
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
310
|
+
operations: [
|
|
311
|
+
{
|
|
312
|
+
op: 'replace',
|
|
313
|
+
path: '/start',
|
|
314
|
+
value: dayjs().format('YYYY-MM-DDTHH:mm:ss.SSSZ'),
|
|
315
|
+
},
|
|
316
|
+
],
|
|
258
317
|
};
|
|
259
318
|
const getAppointments: BatchInputGetRequest = {
|
|
260
319
|
method: 'GET',
|
|
261
320
|
url: `/Appointment?date=sa${dayjs().startOf('day').format('YYYY-MM-DDTHH:mm:ss.SSSZ')}`,
|
|
262
321
|
};
|
|
263
|
-
await oystehr.fhir.transaction<Appointment>({ requests: [patchAppointment, getAppointments
|
|
322
|
+
await oystehr.fhir.transaction<Appointment>({ requests: [patchAppointment, getAppointments] });
|
|
264
323
|
```
|
|
265
324
|
|
|
266
325
|
Since the SDK batch functions return `Bundle`s, they also support the `unbundle()` helper:
|
|
267
326
|
|
|
268
327
|
```typescript
|
|
269
|
-
const txBundle = await oystehr.fhir.transaction<Appointment>({ requests: [patchAppointment, getAppointments
|
|
270
|
-
const results/*: Appointment[]*/ = txBundle.unbundle();
|
|
328
|
+
const txBundle = await oystehr.fhir.transaction<Appointment>({ requests: [patchAppointment, getAppointments] });
|
|
329
|
+
const results /*: Appointment[]*/ = txBundle.unbundle();
|
|
271
330
|
```
|
|
272
331
|
|
|
273
332
|
### Batch Request Error Handling
|
|
@@ -276,7 +335,7 @@ Batch and transaction requests produce errors differently. For transactions, if
|
|
|
276
335
|
|
|
277
336
|
```typescript
|
|
278
337
|
try {
|
|
279
|
-
const txBundle = await oystehr.fhir.transaction<Appointment>({ requests: [patchAppointment, getAppointments
|
|
338
|
+
const txBundle = await oystehr.fhir.transaction<Appointment>({ requests: [patchAppointment, getAppointments] });
|
|
280
339
|
// ...
|
|
281
340
|
} catch (err) {
|
|
282
341
|
const error: OperationOutcome = (err as OystehrFHIRError).error;
|
|
@@ -287,9 +346,9 @@ try {
|
|
|
287
346
|
Batch errors are returned in-line with successful responses in the `Bundle`. The SDK has a helper function to pull errors out of the bundle result:
|
|
288
347
|
|
|
289
348
|
```typescript
|
|
290
|
-
const batchBundle = await oystehr.fhir.batch<Appointment>({ requests: [patchAppointment, getAppointments
|
|
291
|
-
const batchResources/*: Appointment[]*/ = batchBundle.unbundle();
|
|
292
|
-
const batchErrors/*: OperationOutcome[]*/ = batchBundle.errors();
|
|
349
|
+
const batchBundle = await oystehr.fhir.batch<Appointment>({ requests: [patchAppointment, getAppointments] });
|
|
350
|
+
const batchResources /*: Appointment[]*/ = batchBundle.unbundle();
|
|
351
|
+
const batchErrors /*: OperationOutcome[]*/ = batchBundle.errors();
|
|
293
352
|
```
|
|
294
353
|
|
|
295
354
|
### FHIR Search and Batch Types
|
|
@@ -300,17 +359,19 @@ When writing complex search and batch requests, you may end up with requests tha
|
|
|
300
359
|
import Oystehr from '@oystehr/sdk';
|
|
301
360
|
import { Encounter, Location } from 'fhir/r4b';
|
|
302
361
|
|
|
303
|
-
const bundle/*: Bundle<Encounter | Location>*/ = await oystehr.fhir.search<Encounter | Location>({
|
|
362
|
+
const bundle /*: Bundle<Encounter | Location>*/ = await oystehr.fhir.search<Encounter | Location>({
|
|
304
363
|
resourceType: 'Encounter',
|
|
305
|
-
params: [
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
364
|
+
params: [
|
|
365
|
+
{
|
|
366
|
+
name: '_include',
|
|
367
|
+
value: 'Encounter.location',
|
|
368
|
+
},
|
|
369
|
+
],
|
|
309
370
|
});
|
|
310
371
|
|
|
311
|
-
const results/*: (Encounter | Location)[]*/ = bundle.unbundle();
|
|
312
|
-
const encounters/*: Encounter[]*/ = results.filter((res): res is Encounter => res.resourceType === 'Encounter');
|
|
313
|
-
const locations/*: Location[]*/ = results.filter((res): res is Location => res.resourceType === 'Location');
|
|
372
|
+
const results /*: (Encounter | Location)[]*/ = bundle.unbundle();
|
|
373
|
+
const encounters /*: Encounter[]*/ = results.filter((res): res is Encounter => res.resourceType === 'Encounter');
|
|
374
|
+
const locations /*: Location[]*/ = results.filter((res): res is Location => res.resourceType === 'Location');
|
|
314
375
|
```
|
|
315
376
|
|
|
316
377
|
### Optimistic Locking
|
|
@@ -350,17 +411,20 @@ Under the hood, uploading and downloading files with [Z3](/oystehr/services/z3)
|
|
|
350
411
|
The SDK provides convenience functions which combine these steps into a single function call to make it a one-liner:
|
|
351
412
|
|
|
352
413
|
```typescript copy filename="Upload a file to Z3 with the SDK"
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
414
|
+
await oystehr.z3.uploadFile({
|
|
415
|
+
bucketName: 'your-bucket-name',
|
|
416
|
+
'objectPath+': 'path/to/your-filename',
|
|
417
|
+
file: someFileBlob,
|
|
418
|
+
});
|
|
356
419
|
```
|
|
357
420
|
|
|
358
421
|
In the example, `someFileBlob` is a [Blob](https://nodejs.org/api/buffer.html#class-blob).
|
|
359
422
|
|
|
360
423
|
```typescript copy filename="Download a file from Z3 with the SDK"
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
424
|
+
const downloadedBuffer = await oystehr.z3.downloadFile({
|
|
425
|
+
bucketName: 'your-bucket-name',
|
|
426
|
+
'objectPath+': 'path/to/your-filename',
|
|
427
|
+
});
|
|
364
428
|
```
|
|
365
429
|
|
|
366
430
|
### Zambda
|
|
@@ -368,11 +432,11 @@ In the example, `someFileBlob` is a [Blob](https://nodejs.org/api/buffer.html#cl
|
|
|
368
432
|
Uploading code for your Zambda Functions is very similar to uploading a file with Z3. After creating your `.zip` archive, use the `uploadFile()` function to deploy your code.
|
|
369
433
|
|
|
370
434
|
```typescript copy filename="Deploy a code zip to a Zambda Function"
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
435
|
+
const zambdaFile = fs.readFileSync('build/your-zambda-code.zip');
|
|
436
|
+
await oystehr.zambda.uploadFile({
|
|
437
|
+
id: yourZambdaId,
|
|
438
|
+
file: new Blob([zambdaFile]),
|
|
439
|
+
});
|
|
376
440
|
```
|
|
377
441
|
|
|
378
442
|
## Migration Guide
|
|
@@ -42,13 +42,13 @@ class SDKResource {
|
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
fhirRequest(path, method) {
|
|
45
|
-
return async (params, request) => {
|
|
45
|
+
return async (params, request, requestMode) => {
|
|
46
46
|
try {
|
|
47
47
|
const baseUrlThunk = () => this.config.services?.fhirApiUrl ?? defaultFhirApiUrl;
|
|
48
48
|
const configThunk = () => this.config;
|
|
49
49
|
const loggerThunk = () => this.logger;
|
|
50
50
|
// must await here to catch
|
|
51
|
-
return await fetcher(baseUrlThunk, configThunk, loggerThunk, path, method)(params, request);
|
|
51
|
+
return await fetcher(baseUrlThunk, configThunk, loggerThunk, path, method)(params, request, requestMode);
|
|
52
52
|
}
|
|
53
53
|
catch (err) {
|
|
54
54
|
// FHIR API error messages are JSON strings
|
|
@@ -67,13 +67,133 @@ class SDKResource {
|
|
|
67
67
|
}
|
|
68
68
|
};
|
|
69
69
|
}
|
|
70
|
+
async startAsyncJob(path, method, params, requestMode, request) {
|
|
71
|
+
const mode = requestMode === 'async-bulk' ? 'bulk' : 'bundle';
|
|
72
|
+
const asyncPath = requestMode === 'async-bulk' ? this.appendBulkOutputFormat(path) : path;
|
|
73
|
+
const raw = await this.fhirRequest(asyncPath, method)(params, {
|
|
74
|
+
...request,
|
|
75
|
+
rawResponse: true,
|
|
76
|
+
}, requestMode);
|
|
77
|
+
if (raw.status !== 202) {
|
|
78
|
+
throw new index.OystehrSdkError({
|
|
79
|
+
message: `Expected start async job to return 202 Accepted, received ${raw.status}`,
|
|
80
|
+
code: raw.status,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
const contentLocation = this.readHeader(raw.headers, 'content-location');
|
|
84
|
+
if (!contentLocation) {
|
|
85
|
+
throw new index.OystehrSdkError({
|
|
86
|
+
message: 'Start Async job response missing Content-Location header',
|
|
87
|
+
code: 500,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
const jobId = this.parseAsyncJobId(contentLocation);
|
|
91
|
+
if (!jobId) {
|
|
92
|
+
throw new index.OystehrSdkError({
|
|
93
|
+
message: `Could not parse async job id from Content-Location: ${contentLocation}`,
|
|
94
|
+
code: 500,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
return { jobId, contentLocation, mode };
|
|
98
|
+
}
|
|
99
|
+
async fetchAsyncJobStatus(jobId, request) {
|
|
100
|
+
const raw = await this.fhirRequest(`/async-job/${jobId}`, 'GET')({}, {
|
|
101
|
+
...request,
|
|
102
|
+
rawResponse: true,
|
|
103
|
+
});
|
|
104
|
+
if (raw.status === 202) {
|
|
105
|
+
return {
|
|
106
|
+
status: 202,
|
|
107
|
+
xProgress: this.readHeader(raw.headers, 'x-progress'),
|
|
108
|
+
retryAfter: this.readHeader(raw.headers, 'retry-after'),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (raw.status === 410) {
|
|
112
|
+
return { status: 410 };
|
|
113
|
+
}
|
|
114
|
+
if (raw.status === 404) {
|
|
115
|
+
return { status: 404 };
|
|
116
|
+
}
|
|
117
|
+
if (raw.status === 200) {
|
|
118
|
+
if (this.isBulkManifest(raw.body)) {
|
|
119
|
+
return {
|
|
120
|
+
status: 200,
|
|
121
|
+
mode: 'bulk',
|
|
122
|
+
manifest: raw.body,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
const bundle = raw.body;
|
|
126
|
+
if (bundle?.resourceType === 'Bundle' && bundle?.type === 'batch-response') {
|
|
127
|
+
const entry0 = bundle.entry?.[0];
|
|
128
|
+
const interactionStatus = entry0?.response?.status;
|
|
129
|
+
const resource = entry0?.resource;
|
|
130
|
+
const outcome = entry0?.response?.outcome;
|
|
131
|
+
return {
|
|
132
|
+
status: 200,
|
|
133
|
+
mode: 'bundle',
|
|
134
|
+
bundle,
|
|
135
|
+
interactionStatus,
|
|
136
|
+
resource,
|
|
137
|
+
outcome,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
status: 200,
|
|
142
|
+
body: raw.body,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
status: raw.status,
|
|
147
|
+
body: raw.body,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
readHeader(headers, name) {
|
|
151
|
+
const direct = headers[name];
|
|
152
|
+
if (direct != null) {
|
|
153
|
+
return direct;
|
|
154
|
+
}
|
|
155
|
+
const lower = name.toLowerCase();
|
|
156
|
+
const key = Object.keys(headers).find((h) => h.toLowerCase() === lower);
|
|
157
|
+
return key ? headers[key] : undefined;
|
|
158
|
+
}
|
|
159
|
+
parseAsyncJobId(contentLocation) {
|
|
160
|
+
const segments = contentLocation.split('/').filter(Boolean);
|
|
161
|
+
const asyncJobIndex = segments.lastIndexOf('async-job');
|
|
162
|
+
if (asyncJobIndex < 0 || asyncJobIndex + 1 >= segments.length) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
return segments[asyncJobIndex + 1];
|
|
166
|
+
}
|
|
167
|
+
appendBulkOutputFormat(path) {
|
|
168
|
+
const separator = path.includes('?') ? '&' : '?';
|
|
169
|
+
return `${path}${separator}_outputFormat=${encodeURIComponent('application/fhir+ndjson')}`;
|
|
170
|
+
}
|
|
171
|
+
isBulkManifest(body) {
|
|
172
|
+
if (body == null || typeof body !== 'object') {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
const maybe = body;
|
|
176
|
+
return (typeof maybe.transactionTime === 'string' &&
|
|
177
|
+
typeof maybe.request === 'string' &&
|
|
178
|
+
typeof maybe.requiresAccessToken === 'boolean' &&
|
|
179
|
+
Array.isArray(maybe.output) &&
|
|
180
|
+
Array.isArray(maybe.error));
|
|
181
|
+
}
|
|
70
182
|
}
|
|
71
183
|
function isInternalClientRequest(request) {
|
|
72
184
|
return ('accessToken' in request ||
|
|
73
185
|
('projectId' in request && uuid.validate(request.projectId)) ||
|
|
74
186
|
('contentType' in request && request.contentType?.split('/').length === 2) ||
|
|
75
187
|
'requestId' in request ||
|
|
76
|
-
('ifMatch' in request && request.ifMatch.startsWith('W/"'))
|
|
188
|
+
('ifMatch' in request && request.ifMatch.startsWith('W/"')) ||
|
|
189
|
+
'mode' in request ||
|
|
190
|
+
'rawResponse' in request);
|
|
191
|
+
}
|
|
192
|
+
function getPreferHeaderFromMode(mode) {
|
|
193
|
+
if (mode === 'async-bundle' || mode === 'async-bulk') {
|
|
194
|
+
return 'respond-async';
|
|
195
|
+
}
|
|
196
|
+
return undefined;
|
|
77
197
|
}
|
|
78
198
|
/**
|
|
79
199
|
* Parse XML response in format <response><status>...</status><output>...</output></response>
|
|
@@ -96,7 +216,7 @@ function parseXmlResponse(xmlString) {
|
|
|
96
216
|
}
|
|
97
217
|
}
|
|
98
218
|
function fetcher(baseUrlThunk, configThunk, loggerThunk, path, methodParam) {
|
|
99
|
-
return async (params, request) => {
|
|
219
|
+
return async (params, request, requestMode) => {
|
|
100
220
|
// this function supports multiple signatures. fetcher(baseUrl, path, method)(params, request) or fetcher(baseUrl, path, method)(request)
|
|
101
221
|
// or fetcher(baseUrl, path, method)(params) or fetcher(baseUrl, path, method)(). the types for this are handled by Client<Path, Methods>
|
|
102
222
|
// and this is the backend implementation behind it. the heuristic we're using is that if the first param is an object with an accessToken
|
|
@@ -160,6 +280,7 @@ function fetcher(baseUrlThunk, configThunk, loggerThunk, path, methodParam) {
|
|
|
160
280
|
path,
|
|
161
281
|
requestId: requestCtx?.requestId,
|
|
162
282
|
});
|
|
283
|
+
const preferHeader = getPreferHeaderFromMode(requestMode);
|
|
163
284
|
const headers = Object.assign(projectId
|
|
164
285
|
? {
|
|
165
286
|
'x-zapehr-project-id': projectId,
|
|
@@ -167,7 +288,7 @@ function fetcher(baseUrlThunk, configThunk, loggerThunk, path, methodParam) {
|
|
|
167
288
|
}
|
|
168
289
|
: {}, {
|
|
169
290
|
'content-type': requestCtx?.contentType ?? 'application/json',
|
|
170
|
-
}, accessToken ? { Authorization: `Bearer ${accessToken}` } : {}, requestCtx?.ifMatch ? { 'If-Match': requestCtx.ifMatch } : {}, { 'x-oystehr-request-id': requestCtx?.requestId });
|
|
291
|
+
}, preferHeader ? { Prefer: preferHeader } : {}, accessToken ? { Authorization: `Bearer ${accessToken}` } : {}, requestCtx?.ifMatch ? { 'If-Match': requestCtx.ifMatch } : {}, { 'x-oystehr-request-id': requestCtx?.requestId });
|
|
171
292
|
const retryConfig = {
|
|
172
293
|
retries: config.retry?.retries ?? 3,
|
|
173
294
|
jitter: config.retry?.jitter ?? 20,
|
|
@@ -240,6 +361,17 @@ function fetcher(baseUrlThunk, configThunk, loggerThunk, path, methodParam) {
|
|
|
240
361
|
url,
|
|
241
362
|
requestId: requestCtx?.requestId,
|
|
242
363
|
});
|
|
364
|
+
if (requestCtx?.rawResponse) {
|
|
365
|
+
const headersRecord = {};
|
|
366
|
+
response.headers.forEach((value, key) => {
|
|
367
|
+
headersRecord[key] = value;
|
|
368
|
+
});
|
|
369
|
+
return {
|
|
370
|
+
status: response.status,
|
|
371
|
+
headers: headersRecord,
|
|
372
|
+
body: responseJson ?? responseBody,
|
|
373
|
+
};
|
|
374
|
+
}
|
|
243
375
|
const isError = !response.ok || response.status >= 400;
|
|
244
376
|
if (isError) {
|
|
245
377
|
const errObj = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.cjs","sources":["../../../src/client/client.ts"],"sourcesContent":["import { v4 as uuidv4, validate as uuidValidate } from 'uuid';\nimport { OystehrConfig } from '../config';\nimport { OystehrFHIRError, OystehrSdkError } from '../errors';\nimport { Logger } from '../logger';\nimport { FhirBundle, FhirResource, OperationOutcome } from '../resources/types';\n\ntype HttpMethod = 'get' | 'put' | 'post' | 'delete' | 'options' | 'head' | 'patch' | 'trace';\nexport const defaultProjectApiUrl = 'https://project-api.zapehr.com/v1';\nconst defaultFhirApiUrl = 'https://fhir-api.zapehr.com';\nconst STATUS_CODES_TO_RETRY = [408, 429, 500, 502, 503, 504];\nconst ERROR_CODES_TO_RETRY = [\n 'ECONNRESET',\n 'ECONNREFUSED',\n 'EPIPE',\n 'ETIMEDOUT',\n 'UND_ERR_CONNECT_TIMEOUT',\n 'UND_ERR_HEADERS_TIMEOUT',\n 'UND_ERR_HEADERS_TIMEOUT',\n 'UND_ERR_SOCKET',\n];\n\n/**\n * Optional parameter that can be passed to the client methods. It allows\n * overriding the access token or project ID, and setting various headers,\n * such as 'Content-Type'.\n */\nexport interface OystehrClientRequest {\n /**\n * The access token to use for the request. If not provided, the access token from `oystehr.init()` will be used.\n */\n accessToken?: string;\n /**\n * The project ID to use for the request. If not provided, the project ID from `oystehr.init()` will be used.\n */\n projectId?: string;\n /**\n * The value of the 'Content-Type' header to use for the request.\n */\n contentType?: string;\n /**\n * Unique identifier for this request.\n */\n requestId?: string;\n}\n\ninterface InternalClientRequest extends OystehrClientRequest {\n ifMatch?: string;\n}\n\ntype FhirData<T extends FhirResource> = T | T[] | FhirBundle<T>;\nexport type FhirFetcherResponse<T extends FhirData<FhirResource> = any> = T;\n\nexport class SDKResource {\n protected readonly config: OystehrConfig;\n protected readonly logger: Logger;\n constructor(config: OystehrConfig) {\n this.config = config;\n this.logger = new Logger({\n level: this.config.logLevel,\n });\n }\n\n protected request(path: string, method: string, baseUrlThunk: () => string): FetcherFunction {\n return async (params: any, request?: InternalClientRequest): Promise<FetcherResponse> => {\n const configThunk = (): OystehrConfig => this.config;\n const loggerThunk = (): Logger => this.logger;\n try {\n // must await here to catch\n return await fetcher(baseUrlThunk, configThunk, loggerThunk, path, method)(params, request);\n } catch (err: any) {\n const error = err as { message: string; code: number; cause?: unknown };\n this.logger.error(error.message, { code: error.code, cause: error.cause });\n throw new OystehrSdkError({ message: error.message, code: error.code, cause: error.cause });\n }\n };\n }\n\n protected fhirRequest<T extends FhirResource = any>(path: string, method: string) {\n return async (params: any, request?: InternalClientRequest): Promise<FhirFetcherResponse<T>> => {\n try {\n const baseUrlThunk = (): string => this.config.services?.fhirApiUrl ?? defaultFhirApiUrl;\n const configThunk = (): OystehrConfig => this.config;\n const loggerThunk = (): Logger => this.logger;\n // must await here to catch\n return await fetcher(baseUrlThunk, configThunk, loggerThunk, path, method)(params, request);\n } catch (err: unknown) {\n // FHIR API error messages are JSON strings\n const fullError = err as { message: string | Record<string, any>; code: number; cause?: unknown };\n if (typeof fullError.message === 'string') {\n throw new OystehrSdkError({\n message: fullError.message,\n code: fullError.code,\n cause: fullError.cause,\n });\n }\n throw new OystehrFHIRError({\n error: fullError.message as OperationOutcome,\n code: fullError.code,\n });\n }\n };\n }\n}\n\nexport type FetcherError = { message: string; code: number };\nexport type FetcherResponse = any;\nexport type FetcherFunction = (\n params?: Record<string, any> | [any] | InternalClientRequest,\n request?: InternalClientRequest\n) => Promise<FetcherResponse>;\n\nfunction isInternalClientRequest(request: Record<string, any>): request is InternalClientRequest {\n return (\n 'accessToken' in request ||\n ('projectId' in request && uuidValidate(request.projectId)) ||\n ('contentType' in request && request.contentType?.split('/').length === 2) ||\n 'requestId' in request ||\n ('ifMatch' in request && request.ifMatch.startsWith('W/\"'))\n );\n}\n\n/**\n * Parse XML response in format <response><status>...</status><output>...</output></response>\n */\nfunction parseXmlResponse(xmlString: string): Record<string, unknown> | null {\n try {\n // Extract status\n const statusMatch = xmlString.match(/<status>(\\d+)<\\/status>/);\n const status = statusMatch ? parseInt(statusMatch[1], 10) : null;\n\n // Extract output - everything between <output> and </output>\n const outputMatch = xmlString.match(/<output>([\\s\\S]*?)<\\/output>/);\n const output = outputMatch ? outputMatch[1] : null;\n\n if (status === null || output === null) {\n return null;\n }\n\n return { status, output };\n } catch (_err) {\n return null;\n }\n}\n\nfunction fetcher(\n baseUrlThunk: () => string,\n configThunk: () => OystehrConfig,\n loggerThunk: () => Logger,\n path: string,\n methodParam: string\n): FetcherFunction {\n return async (\n params?: Record<string, unknown> | [any] | InternalClientRequest,\n request?: InternalClientRequest\n ): Promise<FetcherResponse> => {\n // this function supports multiple signatures. fetcher(baseUrl, path, method)(params, request) or fetcher(baseUrl, path, method)(request)\n // or fetcher(baseUrl, path, method)(params) or fetcher(baseUrl, path, method)(). the types for this are handled by Client<Path, Methods>\n // and this is the backend implementation behind it. the heuristic we're using is that if the first param is an object with an accessToken\n // and there is no second param, assume the first one is the request object instead\n // eslint-disable-next-line prefer-const\n let [providedParams, requestCtx] = extractParamsAndRequest(params, request);\n requestCtx ??= {};\n requestCtx.requestId ??= uuidv4();\n const config = configThunk();\n const logger = loggerThunk();\n const method = methodParam.toLowerCase() as HttpMethod;\n logger.debug('Beginning fetch', {\n method,\n path,\n requestId: requestCtx?.requestId,\n });\n const fetchImpl = config.fetch ?? fetch;\n const accessToken = requestCtx?.accessToken ?? config.accessToken;\n const projectId = requestCtx?.projectId ?? config.projectId;\n let finalPath = path;\n let finalParams = providedParams;\n if (!Array.isArray(providedParams)) {\n const [subbedPath, addlParams] = subParamsInPath(path, providedParams);\n finalPath = subbedPath;\n finalParams = addlParams;\n }\n logger.debug('Substituted parameters in path', {\n method,\n path,\n requestId: requestCtx?.requestId,\n });\n finalPath = finalPath.replace(/^\\//, ''); // remove leading slash\n const baseUrlEvaluated = baseUrlThunk();\n const fullBaseUrl = baseUrlEvaluated.endsWith('/') ? baseUrlEvaluated : baseUrlEvaluated + '/';\n const url = new URL(finalPath, fullBaseUrl);\n let body: any;\n\n if (Array.isArray(finalParams)) {\n body = JSON.stringify(finalParams);\n } else if (Object.keys(finalParams).length) {\n if (method === 'get') {\n addParamsToSearch(finalParams, url.searchParams);\n } else if (requestCtx?.contentType === 'application/x-www-form-urlencoded') {\n const search = new URLSearchParams();\n addParamsToSearch(finalParams, search);\n body = search.toString();\n } else {\n body = JSON.stringify(finalParams);\n }\n } else {\n // override for rpc call\n if (requestCtx?.contentType !== 'application/x-www-form-urlencoded' && method === 'post') {\n body = '{}';\n }\n }\n logger.debug('Prepared request body', {\n method,\n path,\n requestId: requestCtx?.requestId,\n });\n\n const headers: Record<string, string> = Object.assign(\n projectId\n ? {\n 'x-zapehr-project-id': projectId,\n 'x-oystehr-project-id': projectId,\n }\n : {},\n {\n 'content-type': requestCtx?.contentType ?? 'application/json',\n },\n accessToken ? { Authorization: `Bearer ${accessToken}` } : {},\n requestCtx?.ifMatch ? { 'If-Match': requestCtx.ifMatch } : {},\n { 'x-oystehr-request-id': requestCtx?.requestId }\n );\n const retryConfig: ConstructedRetryConfig = {\n retries: config.retry?.retries ?? 3,\n jitter: config.retry?.jitter ?? 20,\n delay: config.retry?.delay ?? 100,\n onRetry: config.retry?.onRetry,\n // Using array instead of set because the length is too short for uniqueness to be important\n retryOn: [...(config.retry?.retryOn ?? []), ...STATUS_CODES_TO_RETRY],\n };\n retryConfig.retryOn.push(...STATUS_CODES_TO_RETRY);\n return retry(async () => {\n logger.info('Request start', {\n method,\n url,\n requestId: requestCtx?.requestId,\n });\n const now = Date.now();\n const response = await fetchImpl(\n new Request(url, {\n method: method.toUpperCase(),\n body,\n headers,\n })\n );\n logger.info('Request end', {\n method,\n url,\n duration: Date.now() - now,\n requestId: requestCtx?.requestId,\n });\n const responseBody = response.body ? await response.text() : null;\n let responseJson: Record<string, unknown> | null;\n const contentType = response.headers.get('content-type');\n try {\n if (\n responseBody &&\n (contentType?.includes('application/json') || contentType?.includes('application/fhir+json'))\n ) {\n logger.time('Deserialized JSON response', {\n method,\n url,\n requestId: requestCtx?.requestId,\n });\n responseJson = JSON.parse(responseBody);\n logger.timeEnd('Deserialized JSON response', {\n method,\n url,\n requestId: requestCtx?.requestId,\n });\n } else if (responseBody && (contentType?.includes('application/xml') || contentType?.includes('text/xml'))) {\n // Parse XML response into { status, output } structure\n logger.time('Deserialized XML response', {\n method,\n url,\n requestId: requestCtx?.requestId,\n });\n responseJson = parseXmlResponse(responseBody);\n logger.timeEnd('Deserialized XML response', {\n method,\n url,\n requestId: requestCtx?.requestId,\n });\n } else {\n responseJson = null;\n }\n } catch (_err) {\n // ignore JSON.parse errors\n responseJson = null;\n }\n logger.debug('Deserialized response', {\n method,\n url,\n requestId: requestCtx?.requestId,\n });\n const isError = !response.ok || response.status >= 400;\n if (isError) {\n const errObj = {\n message:\n (typeof responseJson?.output === 'string'\n ? responseJson.output // XML error case - output is XML string\n : (responseJson?.output as Record<string, unknown>)?.message) ?? // official zambda output format (JSON)\n responseJson?.message ?? // normal endpoint output format\n responseJson ?? // parsable json\n responseBody ?? // raw response\n response.statusText, // fallback to status text\n code:\n (responseJson?.output as Record<string, unknown>)?.code ?? // official zambda output format\n responseJson?.code ?? // normal endpoint output format\n response.status, // fallback to status code\n response,\n };\n throw errObj;\n }\n return responseJson;\n }, retryConfig);\n };\n}\n\ntype ConstructedRetryConfig = Omit<NonNullable<OystehrConfig['retry']>, 'retryOn'> & {\n jitter: NonNullable<NonNullable<OystehrConfig['retry']>['jitter']>;\n delay: NonNullable<NonNullable<OystehrConfig['retry']>['delay']>;\n retryOn: NonNullable<NonNullable<OystehrConfig['retry']>['retryOn']>;\n};\nasync function retry<T>(work: (attempt: number) => Promise<T>, config: ConstructedRetryConfig): Promise<T> {\n let lastErr;\n for (const attempt of Array.from({ length: (config.retries ?? 0) + 1 }, (_, index) => index)) {\n try {\n return await work(attempt);\n } catch (e: any) {\n let isRetryable = false;\n if ('response' in e) {\n // error from API\n const err = e as FetcherError;\n isRetryable = config.retryOn.includes(err.code);\n // Removes response\n lastErr = { message: e.message, code: e.code };\n } else {\n lastErr = e;\n // error from fetch\n if ('code' in e && typeof e.code === 'string') {\n const err = e as { code: string };\n isRetryable = ERROR_CODES_TO_RETRY.includes(err.code);\n }\n }\n if (!isRetryable) {\n break;\n }\n const jitter = Math.floor(Math.random() * (config.jitter + 1));\n await new Promise((resolve) => setTimeout(resolve, config.delay + jitter));\n if (config.onRetry && attempt !== (config.retries ?? 0)) {\n config.onRetry(attempt + 1);\n }\n }\n }\n throw lastErr;\n}\n\n/**\n * Substitutes params in a path and returns the path with params substituted and any unused params.\n *\n * Uses the property names in the params object to determine the param to substitute in the path.\n *\n * @param path JSON API resource URI\n * @param params all params provided to the client method\n * @returns resource URI with params substituted and any unused params\n */\nfunction subParamsInPath(path: string, params: Record<string, unknown>): [string, Record<string, string>] {\n const unusedParams = { ...params };\n // capture everything of the form `{paramName}` and replace with the value of `params[paramName]`\n const subbedPath = path.replace(/\\{([^}]+)\\}/g, (_, paramName) => {\n delete unusedParams[paramName];\n // override for path params that are paths, indicated by a `+` at the end\n if (paramName.match(/^.*\\+$/)) {\n return params[paramName] + '';\n }\n // error if param value is empty\n if (!params[paramName] || params[paramName] === '') {\n throw new OystehrSdkError({ message: `Required path parameter is an empty string: ${paramName}`, code: 400 });\n }\n // encode search params\n if (params[paramName]) {\n return encodeURIComponent(params[paramName] + ''); // coerce to string\n }\n return '';\n });\n\n const unusedKeys = Object.keys(unusedParams);\n const addlParams = unusedKeys.length\n ? unusedKeys.reduce((acc, key) => ({ ...acc, [key]: unusedParams[key] }), {})\n : {};\n return [subbedPath, addlParams];\n}\n\n/**\n * Adds params to a URLSearchParams object in such a way as to preserve array values.\n * @param params params\n * @param search URLSearchParams object\n */\nexport function addParamsToSearch(params: Record<string, unknown>, search: URLSearchParams): void {\n for (const [key, value] of Object.entries(params)) {\n if (Array.isArray(value)) {\n value.forEach((v) => v !== null && v !== undefined && search.append(key, v as string));\n continue;\n }\n if (value !== null && value !== undefined) {\n search.append(key, value as string);\n }\n }\n}\n\nexport function extractParamsAndRequest(\n params?: Record<string, unknown> | [any] | InternalClientRequest,\n request?: InternalClientRequest\n): [Record<string, unknown>, InternalClientRequest | undefined] {\n const providedParams: Record<string, unknown> | [any] =\n !!params && !request && !Array.isArray(params) && isInternalClientRequest(params)\n ? {}\n : (params as Record<string, unknown>) ?? {};\n const requestCtx =\n !!params && !request && !Array.isArray(params) && isInternalClientRequest(params)\n ? (params as InternalClientRequest)\n : request;\n return [providedParams, requestCtx];\n}\n"],"names":["Logger","OystehrSdkError","OystehrFHIRError","uuidValidate","uuidv4"],"mappings":";;;;;;AAOO,MAAM,oBAAoB,GAAG;AACpC,MAAM,iBAAiB,GAAG,6BAA6B;AACvD,MAAM,qBAAqB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;AAC5D,MAAM,oBAAoB,GAAG;IAC3B,YAAY;IACZ,cAAc;IACd,OAAO;IACP,WAAW;IACX,yBAAyB;IACzB,yBAAyB;IACzB,yBAAyB;IACzB,gBAAgB;CACjB;MAiCY,WAAW,CAAA;AACH,IAAA,MAAM;AACN,IAAA,MAAM;AACzB,IAAA,WAAA,CAAY,MAAqB,EAAA;AAC/B,QAAA,IAAI,CAAC,MAAM,GAAG,MAAM;AACpB,QAAA,IAAI,CAAC,MAAM,GAAG,IAAIA,aAAM,CAAC;AACvB,YAAA,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;AAC5B,SAAA,CAAC;IACJ;AAEU,IAAA,OAAO,CAAC,IAAY,EAAE,MAAc,EAAE,YAA0B,EAAA;AACxE,QAAA,OAAO,OAAO,MAAW,EAAE,OAA+B,KAA8B;YACtF,MAAM,WAAW,GAAG,MAAqB,IAAI,CAAC,MAAM;YACpD,MAAM,WAAW,GAAG,MAAc,IAAI,CAAC,MAAM;AAC7C,YAAA,IAAI;;AAEF,gBAAA,OAAO,MAAM,OAAO,CAAC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC;YAC7F;YAAE,OAAO,GAAQ,EAAE;gBACjB,MAAM,KAAK,GAAG,GAAyD;gBACvE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;gBAC1E,MAAM,IAAIC,qBAAe,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;YAC7F;AACF,QAAA,CAAC;IACH;IAEU,WAAW,CAA+B,IAAY,EAAE,MAAc,EAAA;AAC9E,QAAA,OAAO,OAAO,MAAW,EAAE,OAA+B,KAAqC;AAC7F,YAAA,IAAI;AACF,gBAAA,MAAM,YAAY,GAAG,MAAc,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,IAAI,iBAAiB;gBACxF,MAAM,WAAW,GAAG,MAAqB,IAAI,CAAC,MAAM;gBACpD,MAAM,WAAW,GAAG,MAAc,IAAI,CAAC,MAAM;;AAE7C,gBAAA,OAAO,MAAM,OAAO,CAAC,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC;YAC7F;YAAE,OAAO,GAAY,EAAE;;gBAErB,MAAM,SAAS,GAAG,GAA+E;AACjG,gBAAA,IAAI,OAAO,SAAS,CAAC,OAAO,KAAK,QAAQ,EAAE;oBACzC,MAAM,IAAIA,qBAAe,CAAC;wBACxB,OAAO,EAAE,SAAS,CAAC,OAAO;wBAC1B,IAAI,EAAE,SAAS,CAAC,IAAI;wBACpB,KAAK,EAAE,SAAS,CAAC,KAAK;AACvB,qBAAA,CAAC;gBACJ;gBACA,MAAM,IAAIC,sBAAgB,CAAC;oBACzB,KAAK,EAAE,SAAS,CAAC,OAA2B;oBAC5C,IAAI,EAAE,SAAS,CAAC,IAAI;AACrB,iBAAA,CAAC;YACJ;AACF,QAAA,CAAC;IACH;AACD;AASD,SAAS,uBAAuB,CAAC,OAA4B,EAAA;IAC3D,QACE,aAAa,IAAI,OAAO;SACvB,WAAW,IAAI,OAAO,IAAIC,aAAY,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAC3D,SAAC,aAAa,IAAI,OAAO,IAAI,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AAC1E,QAAA,WAAW,IAAI,OAAO;AACtB,SAAC,SAAS,IAAI,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AAE/D;AAEA;;AAEG;AACH,SAAS,gBAAgB,CAAC,SAAiB,EAAA;AACzC,IAAA,IAAI;;QAEF,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,yBAAyB,CAAC;AAC9D,QAAA,MAAM,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI;;QAGhE,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,8BAA8B,CAAC;AACnE,QAAA,MAAM,MAAM,GAAG,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI;QAElD,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,IAAI,EAAE;AACtC,YAAA,OAAO,IAAI;QACb;AAEA,QAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE;IAC3B;IAAE,OAAO,IAAI,EAAE;AACb,QAAA,OAAO,IAAI;IACb;AACF;AAEA,SAAS,OAAO,CACd,YAA0B,EAC1B,WAAgC,EAChC,WAAyB,EACzB,IAAY,EACZ,WAAmB,EAAA;AAEnB,IAAA,OAAO,OACL,MAAgE,EAChE,OAA+B,KACH;;;;;;AAM5B,QAAA,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,GAAG,uBAAuB,CAAC,MAAM,EAAE,OAAO,CAAC;QAC3E,UAAU,KAAK,EAAE;AACjB,QAAA,UAAU,CAAC,SAAS,KAAKC,OAAM,EAAE;AACjC,QAAA,MAAM,MAAM,GAAG,WAAW,EAAE;AAC5B,QAAA,MAAM,MAAM,GAAG,WAAW,EAAE;AAC5B,QAAA,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,EAAgB;AACtD,QAAA,MAAM,CAAC,KAAK,CAAC,iBAAiB,EAAE;YAC9B,MAAM;YACN,IAAI;YACJ,SAAS,EAAE,UAAU,EAAE,SAAS;AACjC,SAAA,CAAC;AACF,QAAA,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,IAAI,KAAK;QACvC,MAAM,WAAW,GAAG,UAAU,EAAE,WAAW,IAAI,MAAM,CAAC,WAAW;QACjE,MAAM,SAAS,GAAG,UAAU,EAAE,SAAS,IAAI,MAAM,CAAC,SAAS;QAC3D,IAAI,SAAS,GAAG,IAAI;QACpB,IAAI,WAAW,GAAG,cAAc;QAChC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE;AAClC,YAAA,MAAM,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG,eAAe,CAAC,IAAI,EAAE,cAAc,CAAC;YACtE,SAAS,GAAG,UAAU;YACtB,WAAW,GAAG,UAAU;QAC1B;AACA,QAAA,MAAM,CAAC,KAAK,CAAC,gCAAgC,EAAE;YAC7C,MAAM;YACN,IAAI;YACJ,SAAS,EAAE,UAAU,EAAE,SAAS;AACjC,SAAA,CAAC;QACF,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACzC,QAAA,MAAM,gBAAgB,GAAG,YAAY,EAAE;AACvC,QAAA,MAAM,WAAW,GAAG,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,GAAG;QAC9F,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC;AAC3C,QAAA,IAAI,IAAS;AAEb,QAAA,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE;AAC9B,YAAA,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;QACpC;aAAO,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE;AAC1C,YAAA,IAAI,MAAM,KAAK,KAAK,EAAE;AACpB,gBAAA,iBAAiB,CAAC,WAAW,EAAE,GAAG,CAAC,YAAY,CAAC;YAClD;AAAO,iBAAA,IAAI,UAAU,EAAE,WAAW,KAAK,mCAAmC,EAAE;AAC1E,gBAAA,MAAM,MAAM,GAAG,IAAI,eAAe,EAAE;AACpC,gBAAA,iBAAiB,CAAC,WAAW,EAAE,MAAM,CAAC;AACtC,gBAAA,IAAI,GAAG,MAAM,CAAC,QAAQ,EAAE;YAC1B;iBAAO;AACL,gBAAA,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;YACpC;QACF;aAAO;;YAEL,IAAI,UAAU,EAAE,WAAW,KAAK,mCAAmC,IAAI,MAAM,KAAK,MAAM,EAAE;gBACxF,IAAI,GAAG,IAAI;YACb;QACF;AACA,QAAA,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE;YACpC,MAAM;YACN,IAAI;YACJ,SAAS,EAAE,UAAU,EAAE,SAAS;AACjC,SAAA,CAAC;AAEF,QAAA,MAAM,OAAO,GAA2B,MAAM,CAAC,MAAM,CACnD;AACE,cAAE;AACE,gBAAA,qBAAqB,EAAE,SAAS;AAChC,gBAAA,sBAAsB,EAAE,SAAS;AAClC;cACD,EAAE,EACN;AACE,YAAA,cAAc,EAAE,UAAU,EAAE,WAAW,IAAI,kBAAkB;AAC9D,SAAA,EACD,WAAW,GAAG,EAAE,aAAa,EAAE,CAAA,OAAA,EAAU,WAAW,EAAE,EAAE,GAAG,EAAE,EAC7D,UAAU,EAAE,OAAO,GAAG,EAAE,UAAU,EAAE,UAAU,CAAC,OAAO,EAAE,GAAG,EAAE,EAC7D,EAAE,sBAAsB,EAAE,UAAU,EAAE,SAAS,EAAE,CAClD;AACD,QAAA,MAAM,WAAW,GAA2B;AAC1C,YAAA,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,CAAC;AACnC,YAAA,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,IAAI,EAAE;AAClC,YAAA,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,IAAI,GAAG;AACjC,YAAA,OAAO,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO;;AAE9B,YAAA,OAAO,EAAE,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,EAAE,CAAC,EAAE,GAAG,qBAAqB,CAAC;SACtE;QACD,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,qBAAqB,CAAC;AAClD,QAAA,OAAO,KAAK,CAAC,YAAW;AACtB,YAAA,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE;gBAC3B,MAAM;gBACN,GAAG;gBACH,SAAS,EAAE,UAAU,EAAE,SAAS;AACjC,aAAA,CAAC;AACF,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE;YACtB,MAAM,QAAQ,GAAG,MAAM,SAAS,CAC9B,IAAI,OAAO,CAAC,GAAG,EAAE;AACf,gBAAA,MAAM,EAAE,MAAM,CAAC,WAAW,EAAE;gBAC5B,IAAI;gBACJ,OAAO;AACR,aAAA,CAAC,CACH;AACD,YAAA,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE;gBACzB,MAAM;gBACN,GAAG;AACH,gBAAA,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG;gBAC1B,SAAS,EAAE,UAAU,EAAE,SAAS;AACjC,aAAA,CAAC;AACF,YAAA,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,GAAG,IAAI;AACjE,YAAA,IAAI,YAA4C;YAChD,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AACxD,YAAA,IAAI;AACF,gBAAA,IACE,YAAY;AACZ,qBAAC,WAAW,EAAE,QAAQ,CAAC,kBAAkB,CAAC,IAAI,WAAW,EAAE,QAAQ,CAAC,uBAAuB,CAAC,CAAC,EAC7F;AACA,oBAAA,MAAM,CAAC,IAAI,CAAC,4BAA4B,EAAE;wBACxC,MAAM;wBACN,GAAG;wBACH,SAAS,EAAE,UAAU,EAAE,SAAS;AACjC,qBAAA,CAAC;AACF,oBAAA,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;AACvC,oBAAA,MAAM,CAAC,OAAO,CAAC,4BAA4B,EAAE;wBAC3C,MAAM;wBACN,GAAG;wBACH,SAAS,EAAE,UAAU,EAAE,SAAS;AACjC,qBAAA,CAAC;gBACJ;AAAO,qBAAA,IAAI,YAAY,KAAK,WAAW,EAAE,QAAQ,CAAC,iBAAiB,CAAC,IAAI,WAAW,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAC,EAAE;;AAE1G,oBAAA,MAAM,CAAC,IAAI,CAAC,2BAA2B,EAAE;wBACvC,MAAM;wBACN,GAAG;wBACH,SAAS,EAAE,UAAU,EAAE,SAAS;AACjC,qBAAA,CAAC;AACF,oBAAA,YAAY,GAAG,gBAAgB,CAAC,YAAY,CAAC;AAC7C,oBAAA,MAAM,CAAC,OAAO,CAAC,2BAA2B,EAAE;wBAC1C,MAAM;wBACN,GAAG;wBACH,SAAS,EAAE,UAAU,EAAE,SAAS;AACjC,qBAAA,CAAC;gBACJ;qBAAO;oBACL,YAAY,GAAG,IAAI;gBACrB;YACF;YAAE,OAAO,IAAI,EAAE;;gBAEb,YAAY,GAAG,IAAI;YACrB;AACA,YAAA,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE;gBACpC,MAAM;gBACN,GAAG;gBACH,SAAS,EAAE,UAAU,EAAE,SAAS;AACjC,aAAA,CAAC;AACF,YAAA,MAAM,OAAO,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,MAAM,IAAI,GAAG;YACtD,IAAI,OAAO,EAAE;AACX,gBAAA,MAAM,MAAM,GAAG;AACb,oBAAA,OAAO,EACL,CAAC,OAAO,YAAY,EAAE,MAAM,KAAK;AAC/B,0BAAE,YAAY,CAAC,MAAM;0BAClB,YAAY,EAAE,MAAkC,EAAE,OAAO;wBAC9D,YAAY,EAAE,OAAO;AACrB,wBAAA,YAAY;AACZ,wBAAA,YAAY;wBACZ,QAAQ,CAAC,UAAU;AACrB,oBAAA,IAAI,EACD,YAAY,EAAE,MAAkC,EAAE,IAAI;wBACvD,YAAY,EAAE,IAAI;wBAClB,QAAQ,CAAC,MAAM;oBACjB,QAAQ;iBACT;AACD,gBAAA,MAAM,MAAM;YACd;AACA,YAAA,OAAO,YAAY;QACrB,CAAC,EAAE,WAAW,CAAC;AACjB,IAAA,CAAC;AACH;AAOA,eAAe,KAAK,CAAI,IAAqC,EAAE,MAA8B,EAAA;AAC3F,IAAA,IAAI,OAAO;AACX,IAAA,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,KAAK,CAAC,EAAE;AAC5F,QAAA,IAAI;AACF,YAAA,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC;QAC5B;QAAE,OAAO,CAAM,EAAE;YACf,IAAI,WAAW,GAAG,KAAK;AACvB,YAAA,IAAI,UAAU,IAAI,CAAC,EAAE;;gBAEnB,MAAM,GAAG,GAAG,CAAiB;gBAC7B,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;;AAE/C,gBAAA,OAAO,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;YAChD;iBAAO;gBACL,OAAO,GAAG,CAAC;;gBAEX,IAAI,MAAM,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE;oBAC7C,MAAM,GAAG,GAAG,CAAqB;oBACjC,WAAW,GAAG,oBAAoB,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;gBACvD;YACF;YACA,IAAI,CAAC,WAAW,EAAE;gBAChB;YACF;AACA,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC9D,YAAA,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC;AAC1E,YAAA,IAAI,MAAM,CAAC,OAAO,IAAI,OAAO,MAAM,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC,EAAE;AACvD,gBAAA,MAAM,CAAC,OAAO,CAAC,OAAO,GAAG,CAAC,CAAC;YAC7B;QACF;IACF;AACA,IAAA,MAAM,OAAO;AACf;AAEA;;;;;;;;AAQG;AACH,SAAS,eAAe,CAAC,IAAY,EAAE,MAA+B,EAAA;AACpE,IAAA,MAAM,YAAY,GAAG,EAAE,GAAG,MAAM,EAAE;;AAElC,IAAA,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,SAAS,KAAI;AAC/D,QAAA,OAAO,YAAY,CAAC,SAAS,CAAC;;AAE9B,QAAA,IAAI,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE;AAC7B,YAAA,OAAO,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE;QAC/B;;AAEA,QAAA,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE;AAClD,YAAA,MAAM,IAAIH,qBAAe,CAAC,EAAE,OAAO,EAAE,CAAA,4CAAA,EAA+C,SAAS,CAAA,CAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;QAC/G;;AAEA,QAAA,IAAI,MAAM,CAAC,SAAS,CAAC,EAAE;YACrB,OAAO,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC;QACpD;AACA,QAAA,OAAO,EAAE;AACX,IAAA,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC;AAC5C,IAAA,MAAM,UAAU,GAAG,UAAU,CAAC;AAC5B,UAAE,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE;UAC1E,EAAE;AACN,IAAA,OAAO,CAAC,UAAU,EAAE,UAAU,CAAC;AACjC;AAEA;;;;AAIG;AACG,SAAU,iBAAiB,CAAC,MAA+B,EAAE,MAAuB,EAAA;AACxF,IAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;AACjD,QAAA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACxB,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,CAAW,CAAC,CAAC;YACtF;QACF;QACA,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE;AACzC,YAAA,MAAM,CAAC,MAAM,CAAC,GAAG,EAAE,KAAe,CAAC;QACrC;IACF;AACF;AAEM,SAAU,uBAAuB,CACrC,MAAgE,EAChE,OAA+B,EAAA;IAE/B,MAAM,cAAc,GAClB,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,uBAAuB,CAAC,MAAM;AAC9E,UAAE;AACF,UAAG,MAAkC,IAAI,EAAE;IAC/C,MAAM,UAAU,GACd,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,uBAAuB,CAAC,MAAM;AAC9E,UAAG;UACD,OAAO;AACb,IAAA,OAAO,CAAC,cAAc,EAAE,UAAU,CAAC;AACrC;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"client.cjs","sources":["../../../src/client/client.ts"],"sourcesContent":["import { v4 as uuidv4, validate as uuidValidate } from 'uuid';\nimport { OystehrConfig } from '../config';\nimport { OystehrFHIRError, OystehrSdkError } from '../errors';\nimport { Logger } from '../logger';\nimport {\n FhirAsyncBulkManifest,\n FhirAsyncCompletionBundle,\n FhirAsyncJobHandle,\n FhirAsyncJobStatus,\n FhirBundle,\n FhirResource,\n FhirResponseMode,\n OperationOutcome,\n} from '../resources/types';\n\ntype HttpMethod = 'get' | 'put' | 'post' | 'delete' | 'options' | 'head' | 'patch' | 'trace';\nexport const defaultProjectApiUrl = 'https://project-api.zapehr.com/v1';\nconst defaultFhirApiUrl = 'https://fhir-api.zapehr.com';\nconst STATUS_CODES_TO_RETRY = [408, 429, 500, 502, 503, 504];\nconst ERROR_CODES_TO_RETRY = [\n 'ECONNRESET',\n 'ECONNREFUSED',\n 'EPIPE',\n 'ETIMEDOUT',\n 'UND_ERR_CONNECT_TIMEOUT',\n 'UND_ERR_HEADERS_TIMEOUT',\n 'UND_ERR_HEADERS_TIMEOUT',\n 'UND_ERR_SOCKET',\n];\n\n/**\n * Optional parameter that can be passed to the client methods. It allows\n * overriding the access token or project ID, and setting various headers,\n * such as 'Content-Type'.\n */\nexport interface OystehrClientRequest {\n /**\n * The access token to use for the request. If not provided, the access token from `oystehr.init()` will be used.\n */\n accessToken?: string;\n /**\n * The project ID to use for the request. If not provided, the project ID from `oystehr.init()` will be used.\n */\n projectId?: string;\n /**\n * The value of the 'Content-Type' header to use for the request.\n */\n contentType?: string;\n /**\n * Unique identifier for this request.\n */\n requestId?: string;\n /**\n * Optional execution mode for FHIR requests that support async behavior.\n * Defaults to `sync` when omitted.\n */\n mode?: FhirResponseMode;\n}\n\ninterface InternalClientRequest extends OystehrClientRequest {\n ifMatch?: string;\n /**\n * Internal-only: returns raw response metadata ({ status, headers, body }) instead of throwing on non-2xx statuses.\n */\n rawResponse?: boolean;\n}\n\ntype FhirData<T extends FhirResource> = T | T[] | FhirBundle<T>;\nexport type FhirFetcherResponse<T extends FhirData<FhirResource> = any> = T;\n\nexport class SDKResource {\n protected readonly config: OystehrConfig;\n protected readonly logger: Logger;\n constructor(config: OystehrConfig) {\n this.config = config;\n this.logger = new Logger({\n level: this.config.logLevel,\n });\n }\n\n protected request(path: string, method: string, baseUrlThunk: () => string): FetcherFunction {\n return async (params: any, request?: InternalClientRequest): Promise<FetcherResponse> => {\n const configThunk = (): OystehrConfig => this.config;\n const loggerThunk = (): Logger => this.logger;\n try {\n // must await here to catch\n return await fetcher(baseUrlThunk, configThunk, loggerThunk, path, method)(params, request);\n } catch (err: any) {\n const error = err as { message: string; code: number; cause?: unknown };\n this.logger.error(error.message, { code: error.code, cause: error.cause });\n throw new OystehrSdkError({ message: error.message, code: error.code, cause: error.cause });\n }\n };\n }\n\n protected fhirRequest<T = FhirResource>(\n path: string,\n method: string\n ): {\n (params: any, request: InternalClientRequest & { rawResponse: true }, requestMode?: FhirResponseMode): Promise<\n RawFetcherResponse<T>\n >;\n (params: any, request?: InternalClientRequest, requestMode?: FhirResponseMode): Promise<T>;\n } {\n return async (params: any, request?: InternalClientRequest, requestMode?: FhirResponseMode): Promise<any> => {\n try {\n const baseUrlThunk = (): string => this.config.services?.fhirApiUrl ?? defaultFhirApiUrl;\n const configThunk = (): OystehrConfig => this.config;\n const loggerThunk = (): Logger => this.logger;\n // must await here to catch\n return await fetcher(baseUrlThunk, configThunk, loggerThunk, path, method)(params, request, requestMode);\n } catch (err: unknown) {\n // FHIR API error messages are JSON strings\n const fullError = err as { message: string | Record<string, any>; code: number; cause?: unknown };\n if (typeof fullError.message === 'string') {\n throw new OystehrSdkError({\n message: fullError.message,\n code: fullError.code,\n cause: fullError.cause,\n });\n }\n throw new OystehrFHIRError({\n error: fullError.message as OperationOutcome,\n code: fullError.code,\n });\n }\n };\n }\n\n protected async startAsyncJob(\n path: string,\n method: string,\n params: Record<string, unknown>,\n requestMode: FhirResponseMode,\n request?: InternalClientRequest\n ): Promise<FhirAsyncJobHandle> {\n const mode = requestMode === 'async-bulk' ? 'bulk' : 'bundle';\n const asyncPath = requestMode === 'async-bulk' ? this.appendBulkOutputFormat(path) : path;\n\n const raw = await this.fhirRequest(asyncPath, method)(\n params,\n {\n ...request,\n rawResponse: true,\n },\n requestMode\n );\n\n if (raw.status !== 202) {\n throw new OystehrSdkError({\n message: `Expected start async job to return 202 Accepted, received ${raw.status}`,\n code: raw.status,\n });\n }\n\n const contentLocation = this.readHeader(raw.headers, 'content-location');\n if (!contentLocation) {\n throw new OystehrSdkError({\n message: 'Start Async job response missing Content-Location header',\n code: 500,\n });\n }\n\n const jobId = this.parseAsyncJobId(contentLocation);\n if (!jobId) {\n throw new OystehrSdkError({\n message: `Could not parse async job id from Content-Location: ${contentLocation}`,\n code: 500,\n });\n }\n\n return { jobId, contentLocation, mode };\n }\n\n protected async fetchAsyncJobStatus<T extends FhirResource>(\n jobId: string,\n request?: OystehrClientRequest\n ): Promise<FhirAsyncJobStatus<T>> {\n const raw = await this.fhirRequest(`/async-job/${jobId}`, 'GET')(\n {},\n {\n ...request,\n rawResponse: true,\n }\n );\n\n if (raw.status === 202) {\n return {\n status: 202,\n xProgress: this.readHeader(raw.headers, 'x-progress'),\n retryAfter: this.readHeader(raw.headers, 'retry-after'),\n };\n }\n\n if (raw.status === 410) {\n return { status: 410 };\n }\n\n if (raw.status === 404) {\n return { status: 404 };\n }\n\n if (raw.status === 200) {\n if (this.isBulkManifest(raw.body)) {\n return {\n status: 200,\n mode: 'bulk',\n manifest: raw.body,\n };\n }\n\n const bundle = raw.body as FhirAsyncCompletionBundle<T>;\n if (bundle?.resourceType === 'Bundle' && bundle?.type === 'batch-response') {\n const entry0 = bundle.entry?.[0];\n const interactionStatus = entry0?.response?.status;\n const resource = entry0?.resource;\n const outcome = entry0?.response?.outcome;\n return {\n status: 200,\n mode: 'bundle',\n bundle,\n interactionStatus,\n resource,\n outcome,\n };\n }\n\n return {\n status: 200,\n body: raw.body,\n };\n }\n\n return {\n status: raw.status,\n body: raw.body,\n };\n }\n\n private readHeader(headers: Record<string, string>, name: string): string | undefined {\n const direct = headers[name];\n if (direct != null) {\n return direct;\n }\n\n const lower = name.toLowerCase();\n const key = Object.keys(headers).find((h) => h.toLowerCase() === lower);\n return key ? headers[key] : undefined;\n }\n\n private parseAsyncJobId(contentLocation: string): string | undefined {\n const segments = contentLocation.split('/').filter(Boolean);\n const asyncJobIndex = segments.lastIndexOf('async-job');\n if (asyncJobIndex < 0 || asyncJobIndex + 1 >= segments.length) {\n return undefined;\n }\n\n return segments[asyncJobIndex + 1];\n }\n\n private appendBulkOutputFormat(path: string): string {\n const separator = path.includes('?') ? '&' : '?';\n return `${path}${separator}_outputFormat=${encodeURIComponent('application/fhir+ndjson')}`;\n }\n\n private isBulkManifest(body: unknown): body is FhirAsyncBulkManifest {\n if (body == null || typeof body !== 'object') {\n return false;\n }\n\n const maybe = body as Record<string, unknown>;\n return (\n typeof maybe.transactionTime === 'string' &&\n typeof maybe.request === 'string' &&\n typeof maybe.requiresAccessToken === 'boolean' &&\n Array.isArray(maybe.output) &&\n Array.isArray(maybe.error)\n );\n }\n}\n\nexport type FetcherError = { message: string; code: number };\nexport type FetcherResponse = any;\nexport type RawFetcherResponse<T = unknown> = {\n status: number;\n headers: Record<string, string>;\n body: T | null;\n};\nexport type FetcherFunction = (\n params?: Record<string, any> | [any] | InternalClientRequest,\n request?: InternalClientRequest,\n requestMode?: FhirResponseMode\n) => Promise<FetcherResponse>;\n\nfunction isInternalClientRequest(request: Record<string, any>): request is InternalClientRequest {\n return (\n 'accessToken' in request ||\n ('projectId' in request && uuidValidate(request.projectId)) ||\n ('contentType' in request && request.contentType?.split('/').length === 2) ||\n 'requestId' in request ||\n ('ifMatch' in request && request.ifMatch.startsWith('W/\"')) ||\n 'mode' in request ||\n 'rawResponse' in request\n );\n}\n\nfunction getPreferHeaderFromMode(mode: FhirResponseMode | undefined): string | undefined {\n if (mode === 'async-bundle' || mode === 'async-bulk') {\n return 'respond-async';\n }\n return undefined;\n}\n\n/**\n * Parse XML response in format <response><status>...</status><output>...</output></response>\n */\nfunction parseXmlResponse(xmlString: string): Record<string, unknown> | null {\n try {\n // Extract status\n const statusMatch = xmlString.match(/<status>(\\d+)<\\/status>/);\n const status = statusMatch ? parseInt(statusMatch[1], 10) : null;\n\n // Extract output - everything between <output> and </output>\n const outputMatch = xmlString.match(/<output>([\\s\\S]*?)<\\/output>/);\n const output = outputMatch ? outputMatch[1] : null;\n\n if (status === null || output === null) {\n return null;\n }\n\n return { status, output };\n } catch (_err) {\n return null;\n }\n}\n\nfunction fetcher(\n baseUrlThunk: () => string,\n configThunk: () => OystehrConfig,\n loggerThunk: () => Logger,\n path: string,\n methodParam: string\n): FetcherFunction {\n return async (\n params?: Record<string, unknown> | [any] | InternalClientRequest,\n request?: InternalClientRequest,\n requestMode?: FhirResponseMode\n ): Promise<FetcherResponse> => {\n // this function supports multiple signatures. fetcher(baseUrl, path, method)(params, request) or fetcher(baseUrl, path, method)(request)\n // or fetcher(baseUrl, path, method)(params) or fetcher(baseUrl, path, method)(). the types for this are handled by Client<Path, Methods>\n // and this is the backend implementation behind it. the heuristic we're using is that if the first param is an object with an accessToken\n // and there is no second param, assume the first one is the request object instead\n // eslint-disable-next-line prefer-const\n let [providedParams, requestCtx] = extractParamsAndRequest(params, request);\n requestCtx ??= {};\n requestCtx.requestId ??= uuidv4();\n const config = configThunk();\n const logger = loggerThunk();\n const method = methodParam.toLowerCase() as HttpMethod;\n logger.debug('Beginning fetch', {\n method,\n path,\n requestId: requestCtx?.requestId,\n });\n const fetchImpl = config.fetch ?? fetch;\n const accessToken = requestCtx?.accessToken ?? config.accessToken;\n const projectId = requestCtx?.projectId ?? config.projectId;\n let finalPath = path;\n let finalParams = providedParams;\n if (!Array.isArray(providedParams)) {\n const [subbedPath, addlParams] = subParamsInPath(path, providedParams);\n finalPath = subbedPath;\n finalParams = addlParams;\n }\n logger.debug('Substituted parameters in path', {\n method,\n path,\n requestId: requestCtx?.requestId,\n });\n finalPath = finalPath.replace(/^\\//, ''); // remove leading slash\n const baseUrlEvaluated = baseUrlThunk();\n const fullBaseUrl = baseUrlEvaluated.endsWith('/') ? baseUrlEvaluated : baseUrlEvaluated + '/';\n const url = new URL(finalPath, fullBaseUrl);\n let body: any;\n\n if (Array.isArray(finalParams)) {\n body = JSON.stringify(finalParams);\n } else if (Object.keys(finalParams).length) {\n if (method === 'get') {\n addParamsToSearch(finalParams, url.searchParams);\n } else if (requestCtx?.contentType === 'application/x-www-form-urlencoded') {\n const search = new URLSearchParams();\n addParamsToSearch(finalParams, search);\n body = search.toString();\n } else {\n body = JSON.stringify(finalParams);\n }\n } else {\n // override for rpc call\n if (requestCtx?.contentType !== 'application/x-www-form-urlencoded' && method === 'post') {\n body = '{}';\n }\n }\n logger.debug('Prepared request body', {\n method,\n path,\n requestId: requestCtx?.requestId,\n });\n\n const preferHeader = getPreferHeaderFromMode(requestMode);\n\n const headers: Record<string, string> = Object.assign(\n projectId\n ? {\n 'x-zapehr-project-id': projectId,\n 'x-oystehr-project-id': projectId,\n }\n : {},\n {\n 'content-type': requestCtx?.contentType ?? 'application/json',\n },\n preferHeader ? { Prefer: preferHeader } : {},\n accessToken ? { Authorization: `Bearer ${accessToken}` } : {},\n requestCtx?.ifMatch ? { 'If-Match': requestCtx.ifMatch } : {},\n { 'x-oystehr-request-id': requestCtx?.requestId }\n );\n const retryConfig: ConstructedRetryConfig = {\n retries: config.retry?.retries ?? 3,\n jitter: config.retry?.jitter ?? 20,\n delay: config.retry?.delay ?? 100,\n onRetry: config.retry?.onRetry,\n // Using array instead of set because the length is too short for uniqueness to be important\n retryOn: [...(config.retry?.retryOn ?? []), ...STATUS_CODES_TO_RETRY],\n };\n retryConfig.retryOn.push(...STATUS_CODES_TO_RETRY);\n return retry(async () => {\n logger.info('Request start', {\n method,\n url,\n requestId: requestCtx?.requestId,\n });\n const now = Date.now();\n const response = await fetchImpl(\n new Request(url, {\n method: method.toUpperCase(),\n body,\n headers,\n })\n );\n logger.info('Request end', {\n method,\n url,\n duration: Date.now() - now,\n requestId: requestCtx?.requestId,\n });\n const responseBody = response.body ? await response.text() : null;\n let responseJson: Record<string, unknown> | null;\n const contentType = response.headers.get('content-type');\n try {\n if (\n responseBody &&\n (contentType?.includes('application/json') || contentType?.includes('application/fhir+json'))\n ) {\n logger.time('Deserialized JSON response', {\n method,\n url,\n requestId: requestCtx?.requestId,\n });\n responseJson = JSON.parse(responseBody);\n logger.timeEnd('Deserialized JSON response', {\n method,\n url,\n requestId: requestCtx?.requestId,\n });\n } else if (responseBody && (contentType?.includes('application/xml') || contentType?.includes('text/xml'))) {\n // Parse XML response into { status, output } structure\n logger.time('Deserialized XML response', {\n method,\n url,\n requestId: requestCtx?.requestId,\n });\n responseJson = parseXmlResponse(responseBody);\n logger.timeEnd('Deserialized XML response', {\n method,\n url,\n requestId: requestCtx?.requestId,\n });\n } else {\n responseJson = null;\n }\n } catch (_err) {\n // ignore JSON.parse errors\n responseJson = null;\n }\n logger.debug('Deserialized response', {\n method,\n url,\n requestId: requestCtx?.requestId,\n });\n if (requestCtx?.rawResponse) {\n const headersRecord: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headersRecord[key] = value;\n });\n return {\n status: response.status,\n headers: headersRecord,\n body: responseJson ?? responseBody,\n } as RawFetcherResponse;\n }\n const isError = !response.ok || response.status >= 400;\n if (isError) {\n const errObj = {\n message:\n (typeof responseJson?.output === 'string'\n ? responseJson.output // XML error case - output is XML string\n : (responseJson?.output as Record<string, unknown>)?.message) ?? // official zambda output format (JSON)\n responseJson?.message ?? // normal endpoint output format\n responseJson ?? // parsable json\n responseBody ?? // raw response\n response.statusText, // fallback to status text\n code:\n (responseJson?.output as Record<string, unknown>)?.code ?? // official zambda output format\n responseJson?.code ?? // normal endpoint output format\n response.status, // fallback to status code\n response,\n };\n throw errObj;\n }\n return responseJson;\n }, retryConfig);\n };\n}\n\ntype ConstructedRetryConfig = Omit<NonNullable<OystehrConfig['retry']>, 'retryOn'> & {\n jitter: NonNullable<NonNullable<OystehrConfig['retry']>['jitter']>;\n delay: NonNullable<NonNullable<OystehrConfig['retry']>['delay']>;\n retryOn: NonNullable<NonNullable<OystehrConfig['retry']>['retryOn']>;\n};\nasync function retry<T>(work: (attempt: number) => Promise<T>, config: ConstructedRetryConfig): Promise<T> {\n let lastErr;\n for (const attempt of Array.from({ length: (config.retries ?? 0) + 1 }, (_, index) => index)) {\n try {\n return await work(attempt);\n } catch (e: any) {\n let isRetryable = false;\n if ('response' in e) {\n // error from API\n const err = e as FetcherError;\n isRetryable = config.retryOn.includes(err.code);\n // Removes response\n lastErr = { message: e.message, code: e.code };\n } else {\n lastErr = e;\n // error from fetch\n if ('code' in e && typeof e.code === 'string') {\n const err = e as { code: string };\n isRetryable = ERROR_CODES_TO_RETRY.includes(err.code);\n }\n }\n if (!isRetryable) {\n break;\n }\n const jitter = Math.floor(Math.random() * (config.jitter + 1));\n await new Promise((resolve) => setTimeout(resolve, config.delay + jitter));\n if (config.onRetry && attempt !== (config.retries ?? 0)) {\n config.onRetry(attempt + 1);\n }\n }\n }\n throw lastErr;\n}\n\n/**\n * Substitutes params in a path and returns the path with params substituted and any unused params.\n *\n * Uses the property names in the params object to determine the param to substitute in the path.\n *\n * @param path JSON API resource URI\n * @param params all params provided to the client method\n * @returns resource URI with params substituted and any unused params\n */\nfunction subParamsInPath(path: string, params: Record<string, unknown>): [string, Record<string, string>] {\n const unusedParams = { ...params };\n // capture everything of the form `{paramName}` and replace with the value of `params[paramName]`\n const subbedPath = path.replace(/\\{([^}]+)\\}/g, (_, paramName) => {\n delete unusedParams[paramName];\n // override for path params that are paths, indicated by a `+` at the end\n if (paramName.match(/^.*\\+$/)) {\n return params[paramName] + '';\n }\n // error if param value is empty\n if (!params[paramName] || params[paramName] === '') {\n throw new OystehrSdkError({ message: `Required path parameter is an empty string: ${paramName}`, code: 400 });\n }\n // encode search params\n if (params[paramName]) {\n return encodeURIComponent(params[paramName] + ''); // coerce to string\n }\n return '';\n });\n\n const unusedKeys = Object.keys(unusedParams);\n const addlParams = unusedKeys.length\n ? unusedKeys.reduce((acc, key) => ({ ...acc, [key]: unusedParams[key] }), {})\n : {};\n return [subbedPath, addlParams];\n}\n\n/**\n * Adds params to a URLSearchParams object in such a way as to preserve array values.\n * @param params params\n * @param search URLSearchParams object\n */\nexport function addParamsToSearch(params: Record<string, unknown>, search: URLSearchParams): void {\n for (const [key, value] of Object.entries(params)) {\n if (Array.isArray(value)) {\n value.forEach((v) => v !== null && v !== undefined && search.append(key, v as string));\n continue;\n }\n if (value !== null && value !== undefined) {\n search.append(key, value as string);\n }\n }\n}\n\nexport function extractParamsAndRequest(\n params?: Record<string, unknown> | [any] | InternalClientRequest,\n request?: InternalClientRequest\n): [Record<string, unknown>, InternalClientRequest | undefined] {\n const providedParams: Record<string, unknown> | [any] =\n !!params && !request && !Array.isArray(params) && isInternalClientRequest(params)\n ? {}\n : (params as Record<string, unknown>) ?? {};\n const requestCtx =\n !!params && !request && !Array.isArray(params) && isInternalClientRequest(params)\n ? (params as InternalClientRequest)\n : request;\n return [providedParams, requestCtx];\n}\n"],"names":["Logger","OystehrSdkError","OystehrFHIRError","uuidValidate","uuidv4"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { OystehrConfig } from '../config';
|
|
2
2
|
import { Logger } from '../logger';
|
|
3
|
-
import { FhirBundle, FhirResource } from '../resources/types';
|
|
3
|
+
import { FhirAsyncJobHandle, FhirAsyncJobStatus, FhirBundle, FhirResource, FhirResponseMode } from '../resources/types';
|
|
4
4
|
export declare const defaultProjectApiUrl = "https://project-api.zapehr.com/v1";
|
|
5
5
|
/**
|
|
6
6
|
* Optional parameter that can be passed to the client methods. It allows
|
|
@@ -24,9 +24,18 @@ export interface OystehrClientRequest {
|
|
|
24
24
|
* Unique identifier for this request.
|
|
25
25
|
*/
|
|
26
26
|
requestId?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Optional execution mode for FHIR requests that support async behavior.
|
|
29
|
+
* Defaults to `sync` when omitted.
|
|
30
|
+
*/
|
|
31
|
+
mode?: FhirResponseMode;
|
|
27
32
|
}
|
|
28
33
|
interface InternalClientRequest extends OystehrClientRequest {
|
|
29
34
|
ifMatch?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Internal-only: returns raw response metadata ({ status, headers, body }) instead of throwing on non-2xx statuses.
|
|
37
|
+
*/
|
|
38
|
+
rawResponse?: boolean;
|
|
30
39
|
}
|
|
31
40
|
type FhirData<T extends FhirResource> = T | T[] | FhirBundle<T>;
|
|
32
41
|
export type FhirFetcherResponse<T extends FhirData<FhirResource> = any> = T;
|
|
@@ -35,14 +44,30 @@ export declare class SDKResource {
|
|
|
35
44
|
protected readonly logger: Logger;
|
|
36
45
|
constructor(config: OystehrConfig);
|
|
37
46
|
protected request(path: string, method: string, baseUrlThunk: () => string): FetcherFunction;
|
|
38
|
-
protected fhirRequest<T
|
|
47
|
+
protected fhirRequest<T = FhirResource>(path: string, method: string): {
|
|
48
|
+
(params: any, request: InternalClientRequest & {
|
|
49
|
+
rawResponse: true;
|
|
50
|
+
}, requestMode?: FhirResponseMode): Promise<RawFetcherResponse<T>>;
|
|
51
|
+
(params: any, request?: InternalClientRequest, requestMode?: FhirResponseMode): Promise<T>;
|
|
52
|
+
};
|
|
53
|
+
protected startAsyncJob(path: string, method: string, params: Record<string, unknown>, requestMode: FhirResponseMode, request?: InternalClientRequest): Promise<FhirAsyncJobHandle>;
|
|
54
|
+
protected fetchAsyncJobStatus<T extends FhirResource>(jobId: string, request?: OystehrClientRequest): Promise<FhirAsyncJobStatus<T>>;
|
|
55
|
+
private readHeader;
|
|
56
|
+
private parseAsyncJobId;
|
|
57
|
+
private appendBulkOutputFormat;
|
|
58
|
+
private isBulkManifest;
|
|
39
59
|
}
|
|
40
60
|
export type FetcherError = {
|
|
41
61
|
message: string;
|
|
42
62
|
code: number;
|
|
43
63
|
};
|
|
44
64
|
export type FetcherResponse = any;
|
|
45
|
-
export type
|
|
65
|
+
export type RawFetcherResponse<T = unknown> = {
|
|
66
|
+
status: number;
|
|
67
|
+
headers: Record<string, string>;
|
|
68
|
+
body: T | null;
|
|
69
|
+
};
|
|
70
|
+
export type FetcherFunction = (params?: Record<string, any> | [any] | InternalClientRequest, request?: InternalClientRequest, requestMode?: FhirResponseMode) => Promise<FetcherResponse>;
|
|
46
71
|
/**
|
|
47
72
|
* Adds params to a URLSearchParams object in such a way as to preserve array values.
|
|
48
73
|
* @param params params
|