@oystehr/sdk 4.3.8 → 4.3.9
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 +108 -17
- package/dist/cjs/resources/classes/fhir-ext.cjs.map +1 -1
- package/dist/cjs/resources/classes/fhir-ext.d.ts +67 -12
- package/dist/cjs/resources/classes/fhir.cjs +3 -0
- package/dist/cjs/resources/classes/fhir.cjs.map +1 -1
- package/dist/cjs/resources/classes/fhir.d.ts +3 -0
- package/dist/cjs/resources/types/fhir.d.ts +67 -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 +67 -12
- package/dist/esm/resources/classes/fhir-ext.js +107 -19
- package/dist/esm/resources/classes/fhir-ext.js.map +1 -1
- package/dist/esm/resources/classes/fhir.d.ts +3 -0
- package/dist/esm/resources/classes/fhir.js +4 -1
- package/dist/esm/resources/classes/fhir.js.map +1 -1
- package/dist/esm/resources/types/fhir.d.ts +67 -0
- package/package.json +1 -1
- package/src/client/client.ts +214 -7
- package/src/resources/classes/fhir-ext.ts +278 -38
- package/src/resources/classes/fhir.ts +3 -0
- package/src/resources/types/fhir.ts +88 -0
|
@@ -9,6 +9,9 @@ import {
|
|
|
9
9
|
Bundle,
|
|
10
10
|
BundleEntry,
|
|
11
11
|
Coding,
|
|
12
|
+
FhirAsyncJobHandle,
|
|
13
|
+
FhirAsyncJobStatus,
|
|
14
|
+
FhirAsyncWaitOptions,
|
|
12
15
|
FhirBundle,
|
|
13
16
|
FhirCreateParams,
|
|
14
17
|
FhirDeleteParams,
|
|
@@ -18,6 +21,7 @@ import {
|
|
|
18
21
|
FhirPatchParams,
|
|
19
22
|
FhirResource,
|
|
20
23
|
FhirResourceReturnValue,
|
|
24
|
+
FhirResponseMode,
|
|
21
25
|
FhirSearchParams,
|
|
22
26
|
FhirUpdateParams,
|
|
23
27
|
GenerateFriendlyPatientIdParams,
|
|
@@ -262,6 +266,10 @@ export interface OystehrFHIRUpdateClientRequest extends OystehrClientRequest {
|
|
|
262
266
|
optimisticLockingVersionId?: string;
|
|
263
267
|
}
|
|
264
268
|
|
|
269
|
+
function isAsyncRequestMode(mode: FhirResponseMode | undefined): mode is Exclude<FhirResponseMode, 'sync'> {
|
|
270
|
+
return mode === 'async-bundle' || mode === 'async-bulk';
|
|
271
|
+
}
|
|
272
|
+
|
|
265
273
|
/**
|
|
266
274
|
* Performs a FHIR search and returns the results as a Bundle resource
|
|
267
275
|
*
|
|
@@ -269,11 +277,21 @@ export interface OystehrFHIRUpdateClientRequest extends OystehrClientRequest {
|
|
|
269
277
|
* @param request optional OystehrClientRequest object
|
|
270
278
|
* @returns FHIR Bundle resource
|
|
271
279
|
*/
|
|
280
|
+
export async function search<T extends FhirResource>(
|
|
281
|
+
this: SDKResource,
|
|
282
|
+
params: FhirSearchParams<T>,
|
|
283
|
+
request: OystehrClientRequest & { mode: Exclude<FhirResponseMode, 'sync'> }
|
|
284
|
+
): Promise<FhirAsyncJobHandle>;
|
|
285
|
+
export async function search<T extends FhirResource>(
|
|
286
|
+
this: SDKResource,
|
|
287
|
+
params: FhirSearchParams<T>,
|
|
288
|
+
request?: OystehrClientRequest & { mode?: 'sync' | undefined }
|
|
289
|
+
): Promise<FhirFetcherResponse<Bundle<T>>>;
|
|
272
290
|
export async function search<T extends FhirResource>(
|
|
273
291
|
this: SDKResource,
|
|
274
292
|
params: FhirSearchParams<T>,
|
|
275
293
|
request?: OystehrClientRequest
|
|
276
|
-
): Promise<FhirFetcherResponse<Bundle<T
|
|
294
|
+
): Promise<FhirFetcherResponse<Bundle<T>> | FhirAsyncJobHandle> {
|
|
277
295
|
const { resourceType } = params;
|
|
278
296
|
const taggedParams = applyTagSearchParams(this.config, params.params);
|
|
279
297
|
let paramMap: Record<string, (string | number)[]> | undefined;
|
|
@@ -286,6 +304,15 @@ export async function search<T extends FhirResource>(
|
|
|
286
304
|
return acc;
|
|
287
305
|
}, {} as Record<string, (string | number)[]>);
|
|
288
306
|
}
|
|
307
|
+
|
|
308
|
+
const requestMode = request?.mode;
|
|
309
|
+
if (isAsyncRequestMode(requestMode)) {
|
|
310
|
+
return await this.startAsyncJob(`/${resourceType}/_search`, 'POST', paramMap ?? {}, requestMode, {
|
|
311
|
+
...request,
|
|
312
|
+
contentType: 'application/x-www-form-urlencoded',
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
289
316
|
const requestBundle = await this.fhirRequest<FhirBundle<T>>(`/${resourceType}/_search`, 'POST')(paramMap, {
|
|
290
317
|
...request,
|
|
291
318
|
contentType: 'application/x-www-form-urlencoded',
|
|
@@ -302,76 +329,255 @@ export async function search<T extends FhirResource>(
|
|
|
302
329
|
return bundle;
|
|
303
330
|
}
|
|
304
331
|
|
|
332
|
+
export async function create<T extends FhirResource>(
|
|
333
|
+
this: SDKResource,
|
|
334
|
+
params: FhirCreateParams<T>,
|
|
335
|
+
request: OystehrClientRequest & { mode: Exclude<FhirResponseMode, 'sync'> }
|
|
336
|
+
): Promise<FhirAsyncJobHandle>;
|
|
337
|
+
export async function create<T extends FhirResource>(
|
|
338
|
+
this: SDKResource,
|
|
339
|
+
params: FhirCreateParams<T>,
|
|
340
|
+
request?: OystehrClientRequest & { mode?: 'sync' | undefined }
|
|
341
|
+
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T>>>;
|
|
305
342
|
export async function create<T extends FhirResource>(
|
|
306
343
|
this: SDKResource,
|
|
307
344
|
params: FhirCreateParams<T>,
|
|
308
345
|
request?: OystehrClientRequest
|
|
309
|
-
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T
|
|
346
|
+
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T>> | FhirAsyncJobHandle> {
|
|
310
347
|
const tagged = applyTagToResource(this.config, params);
|
|
311
348
|
const { resourceType } = tagged;
|
|
312
|
-
|
|
349
|
+
const requestMode = request?.mode;
|
|
350
|
+
if (isAsyncRequestMode(requestMode)) {
|
|
351
|
+
return await this.startAsyncJob(
|
|
352
|
+
`/${resourceType}`,
|
|
353
|
+
'POST',
|
|
354
|
+
tagged as unknown as Record<string, unknown>,
|
|
355
|
+
requestMode,
|
|
356
|
+
request
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return await this.fhirRequest<FhirResourceReturnValue<T>>(`/${resourceType}`, 'POST')(
|
|
361
|
+
tagged as unknown as Record<string, unknown>,
|
|
362
|
+
request
|
|
363
|
+
);
|
|
313
364
|
}
|
|
314
365
|
|
|
366
|
+
export async function get<T extends FhirResource>(
|
|
367
|
+
this: SDKResource,
|
|
368
|
+
{ resourceType, id }: FhirGetParams<T>,
|
|
369
|
+
request: OystehrClientRequest & { mode: Exclude<FhirResponseMode, 'sync'> }
|
|
370
|
+
): Promise<FhirAsyncJobHandle>;
|
|
371
|
+
export async function get<T extends FhirResource>(
|
|
372
|
+
this: SDKResource,
|
|
373
|
+
{ resourceType, id }: FhirGetParams<T>,
|
|
374
|
+
request?: OystehrClientRequest & { mode?: 'sync' | undefined }
|
|
375
|
+
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T>>>;
|
|
315
376
|
export async function get<T extends FhirResource>(
|
|
316
377
|
this: SDKResource,
|
|
317
378
|
{ resourceType, id }: FhirGetParams<T>,
|
|
318
379
|
request?: OystehrClientRequest
|
|
319
|
-
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T
|
|
380
|
+
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T>> | FhirAsyncJobHandle> {
|
|
381
|
+
const requestMode = request?.mode;
|
|
382
|
+
if (isAsyncRequestMode(requestMode)) {
|
|
383
|
+
return await this.startAsyncJob(`/${resourceType}/${id}`, 'GET', {}, requestMode, request);
|
|
384
|
+
}
|
|
385
|
+
|
|
320
386
|
const result = await this.fhirRequest<FhirResourceReturnValue<T>>(`/${resourceType}/${id}`, 'GET')({}, request);
|
|
321
387
|
assertRetrievedResource(this.config, result);
|
|
322
388
|
return result;
|
|
323
389
|
}
|
|
324
390
|
|
|
391
|
+
export async function update<T extends FhirResource>(
|
|
392
|
+
this: SDKResource,
|
|
393
|
+
params: FhirUpdateParams<T>,
|
|
394
|
+
request: OystehrFHIRUpdateClientRequest & { mode: Exclude<FhirResponseMode, 'sync'> }
|
|
395
|
+
): Promise<FhirAsyncJobHandle>;
|
|
396
|
+
export async function update<T extends FhirResource>(
|
|
397
|
+
this: SDKResource,
|
|
398
|
+
params: FhirUpdateParams<T>,
|
|
399
|
+
request?: OystehrFHIRUpdateClientRequest & { mode?: 'sync' | undefined }
|
|
400
|
+
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T>>>;
|
|
325
401
|
export async function update<T extends FhirResource>(
|
|
326
402
|
this: SDKResource,
|
|
327
403
|
params: FhirUpdateParams<T>,
|
|
328
404
|
request?: OystehrFHIRUpdateClientRequest
|
|
329
|
-
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T
|
|
405
|
+
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T>> | FhirAsyncJobHandle> {
|
|
330
406
|
const tagged = applyTagToResource(this.config, params);
|
|
331
407
|
const { id, resourceType } = tagged;
|
|
332
|
-
|
|
408
|
+
const requestMode = request?.mode;
|
|
409
|
+
const ifMatchRequest = {
|
|
333
410
|
...request,
|
|
334
411
|
ifMatch: request?.optimisticLockingVersionId ? `W/"${request.optimisticLockingVersionId}"` : undefined,
|
|
335
|
-
}
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
if (isAsyncRequestMode(requestMode)) {
|
|
415
|
+
return await this.startAsyncJob(
|
|
416
|
+
`/${resourceType}/${id}`,
|
|
417
|
+
'PUT',
|
|
418
|
+
tagged as unknown as Record<string, unknown>,
|
|
419
|
+
requestMode,
|
|
420
|
+
ifMatchRequest
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return await this.fhirRequest<FhirResourceReturnValue<T>>(`/${resourceType}/${id}`, 'PUT')(
|
|
425
|
+
tagged as unknown as Record<string, unknown>,
|
|
426
|
+
ifMatchRequest
|
|
427
|
+
);
|
|
336
428
|
}
|
|
337
429
|
|
|
430
|
+
export async function patch<T extends FhirResource>(
|
|
431
|
+
this: SDKResource,
|
|
432
|
+
params: FhirPatchParams<T>,
|
|
433
|
+
request: OystehrFHIRUpdateClientRequest & { mode: Exclude<FhirResponseMode, 'sync'> }
|
|
434
|
+
): Promise<FhirAsyncJobHandle>;
|
|
435
|
+
export async function patch<T extends FhirResource>(
|
|
436
|
+
this: SDKResource,
|
|
437
|
+
params: FhirPatchParams<T>,
|
|
438
|
+
request?: OystehrFHIRUpdateClientRequest & { mode?: 'sync' | undefined }
|
|
439
|
+
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T>>>;
|
|
338
440
|
export async function patch<T extends FhirResource>(
|
|
339
441
|
this: SDKResource,
|
|
340
442
|
{ resourceType, id, operations }: FhirPatchParams<T>,
|
|
341
443
|
request?: OystehrFHIRUpdateClientRequest
|
|
342
|
-
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T
|
|
444
|
+
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T>> | FhirAsyncJobHandle> {
|
|
343
445
|
const taggedOperations = applyTagToPatchOperations(this.config, operations);
|
|
344
|
-
|
|
446
|
+
const requestMode = request?.mode;
|
|
447
|
+
const ifMatchRequest = {
|
|
345
448
|
...request,
|
|
346
|
-
contentType: 'application/json-patch+json',
|
|
347
449
|
ifMatch: request?.optimisticLockingVersionId ? `W/"${request.optimisticLockingVersionId}"` : undefined,
|
|
450
|
+
};
|
|
451
|
+
|
|
452
|
+
if (isAsyncRequestMode(requestMode)) {
|
|
453
|
+
return await this.startAsyncJob(
|
|
454
|
+
`/${resourceType}/${id}`,
|
|
455
|
+
'PATCH',
|
|
456
|
+
taggedOperations as unknown as Record<string, unknown>,
|
|
457
|
+
requestMode,
|
|
458
|
+
{
|
|
459
|
+
...ifMatchRequest,
|
|
460
|
+
contentType: 'application/json-patch+json',
|
|
461
|
+
}
|
|
462
|
+
);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
return this.fhirRequest<FhirResourceReturnValue<T>>(`/${resourceType}/${id}`, 'PATCH')(taggedOperations, {
|
|
466
|
+
...ifMatchRequest,
|
|
467
|
+
contentType: 'application/json-patch+json',
|
|
348
468
|
});
|
|
349
469
|
}
|
|
350
470
|
|
|
471
|
+
async function del<T extends FhirResource>(
|
|
472
|
+
this: SDKResource,
|
|
473
|
+
params: FhirDeleteParams<T>,
|
|
474
|
+
request: OystehrClientRequest & { mode: Exclude<FhirResponseMode, 'sync'> }
|
|
475
|
+
): Promise<FhirAsyncJobHandle>;
|
|
476
|
+
async function del<T extends FhirResource>(
|
|
477
|
+
this: SDKResource,
|
|
478
|
+
params: FhirDeleteParams<T>,
|
|
479
|
+
request?: OystehrClientRequest & { mode?: 'sync' | undefined }
|
|
480
|
+
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T>>>;
|
|
351
481
|
async function del<T extends FhirResource>(
|
|
352
482
|
this: SDKResource,
|
|
353
483
|
{ resourceType, id }: FhirDeleteParams<T>,
|
|
354
484
|
request?: OystehrClientRequest
|
|
355
|
-
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T
|
|
356
|
-
|
|
485
|
+
): Promise<FhirFetcherResponse<FhirResourceReturnValue<T>> | FhirAsyncJobHandle> {
|
|
486
|
+
const requestMode = request?.mode;
|
|
487
|
+
if (isAsyncRequestMode(requestMode)) {
|
|
488
|
+
return await this.startAsyncJob(`/${resourceType}/${id}`, 'DELETE', {}, requestMode, request);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return await this.fhirRequest<FhirResourceReturnValue<T>>(`/${resourceType}/${id}`, 'DELETE')({}, request);
|
|
357
492
|
}
|
|
358
493
|
export { del as delete };
|
|
359
494
|
|
|
495
|
+
function getRetryDelayMs(retryAfter: string | undefined, fallbackMs: number): number {
|
|
496
|
+
if (!retryAfter) {
|
|
497
|
+
return fallbackMs;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const asSeconds = Number(retryAfter);
|
|
501
|
+
if (Number.isFinite(asSeconds) && asSeconds >= 0) {
|
|
502
|
+
return Math.max(0, Math.floor(asSeconds * 1000));
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const asTimestamp = Date.parse(retryAfter);
|
|
506
|
+
if (Number.isFinite(asTimestamp)) {
|
|
507
|
+
return Math.max(0, asTimestamp - Date.now());
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
return fallbackMs;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
export async function getAsyncJob<T extends FhirResource>(
|
|
514
|
+
this: SDKResource,
|
|
515
|
+
jobId: string,
|
|
516
|
+
request?: OystehrClientRequest
|
|
517
|
+
): Promise<FhirAsyncJobStatus<T>> {
|
|
518
|
+
return await this.fetchAsyncJobStatus<T>(jobId, request);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
export async function waitForAsyncJob<T extends FhirResource>(
|
|
522
|
+
this: SDKResource,
|
|
523
|
+
jobId: string,
|
|
524
|
+
options?: FhirAsyncWaitOptions,
|
|
525
|
+
request?: OystehrClientRequest
|
|
526
|
+
): Promise<FhirAsyncJobStatus<T>> {
|
|
527
|
+
// 5 seconds poll interval by default
|
|
528
|
+
const pollIntervalMs = options?.pollIntervalMs ?? 5000;
|
|
529
|
+
// 15 minutes timout by default
|
|
530
|
+
const timeoutMs = options?.timeoutMs ?? 900000;
|
|
531
|
+
const attempts = Math.max(1, Math.ceil(timeoutMs / pollIntervalMs));
|
|
532
|
+
|
|
533
|
+
for (let attempt = 0; attempt < attempts; attempt++) {
|
|
534
|
+
const status = await this.fetchAsyncJobStatus<T>(jobId, request);
|
|
535
|
+
if (status.status !== 202) {
|
|
536
|
+
return status;
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
if (attempt < attempts - 1) {
|
|
540
|
+
const retryAfter = 'retryAfter' in status ? status.retryAfter : undefined;
|
|
541
|
+
await new Promise((resolve) => setTimeout(resolve, getRetryDelayMs(retryAfter, pollIntervalMs)));
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
throw new OystehrSdkError({
|
|
546
|
+
message: `Async job ${jobId} did not complete within ${timeoutMs} ms`,
|
|
547
|
+
code: 408,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export async function cancelAsyncJob(this: SDKResource, jobId: string, request?: OystehrClientRequest): Promise<void> {
|
|
552
|
+
await this.fhirRequest(`/async-job/${jobId}`, 'DELETE')({}, request);
|
|
553
|
+
}
|
|
554
|
+
|
|
360
555
|
export async function history<T extends FhirResource>(
|
|
361
556
|
this: SDKResource,
|
|
362
557
|
{ resourceType, id }: FhirHistorySearchParams<T>,
|
|
363
|
-
request
|
|
364
|
-
): Promise<
|
|
558
|
+
request: OystehrClientRequest & { mode: Exclude<FhirResponseMode, 'sync'> }
|
|
559
|
+
): Promise<FhirAsyncJobHandle>;
|
|
365
560
|
export async function history<T extends FhirResource>(
|
|
366
561
|
this: SDKResource,
|
|
367
562
|
{ resourceType, id, versionId }: FhirHistoryGetParams<T>,
|
|
368
|
-
request
|
|
563
|
+
request: OystehrClientRequest & { mode: Exclude<FhirResponseMode, 'sync'> }
|
|
564
|
+
): Promise<FhirAsyncJobHandle>;
|
|
565
|
+
export async function history<T extends FhirResource>(
|
|
566
|
+
this: SDKResource,
|
|
567
|
+
{ resourceType, id, versionId }: FhirHistoryGetParams<T>,
|
|
568
|
+
request?: OystehrClientRequest & { mode?: 'sync' | undefined }
|
|
369
569
|
): Promise<FhirFetcherResponse<T>>;
|
|
570
|
+
export async function history<T extends FhirResource>(
|
|
571
|
+
this: SDKResource,
|
|
572
|
+
{ resourceType, id }: FhirHistorySearchParams<T>,
|
|
573
|
+
request?: OystehrClientRequest & { mode?: 'sync' | undefined }
|
|
574
|
+
): Promise<FhirFetcherResponse<Bundle<T>>>;
|
|
370
575
|
export async function history<T extends FhirResource>(
|
|
371
576
|
this: SDKResource,
|
|
372
577
|
{ resourceType, id, count, offset }: FhirHistorySearchParams<T>,
|
|
373
|
-
request?: OystehrClientRequest
|
|
578
|
+
request?: OystehrClientRequest & { mode?: 'sync' | undefined }
|
|
374
579
|
): Promise<FhirFetcherResponse<Bundle<T>>>;
|
|
580
|
+
|
|
375
581
|
export async function history<T extends FhirResource>(
|
|
376
582
|
this: SDKResource,
|
|
377
583
|
{
|
|
@@ -382,18 +588,26 @@ export async function history<T extends FhirResource>(
|
|
|
382
588
|
offset,
|
|
383
589
|
}: { resourceType: string; id: string; versionId?: string; count?: number; offset?: number },
|
|
384
590
|
request?: OystehrClientRequest
|
|
385
|
-
): Promise<FhirFetcherResponse<Bundle<T>> | FhirFetcherResponse<T
|
|
591
|
+
): Promise<FhirFetcherResponse<Bundle<T>> | FhirFetcherResponse<T> | FhirAsyncJobHandle> {
|
|
592
|
+
const requestMode = request?.mode;
|
|
593
|
+
if (isAsyncRequestMode(requestMode)) {
|
|
594
|
+
if (versionId) {
|
|
595
|
+
return await this.startAsyncJob(`/${resourceType}/${id}/_history/${versionId}`, 'GET', {}, requestMode, request);
|
|
596
|
+
}
|
|
597
|
+
return await this.startAsyncJob(`/${resourceType}/${id}/_history`, 'GET', {}, requestMode, request);
|
|
598
|
+
}
|
|
599
|
+
|
|
386
600
|
if (versionId) {
|
|
387
|
-
return this.fhirRequest(`/${resourceType}/${id}/_history/${versionId}`, 'GET')({}, request);
|
|
601
|
+
return this.fhirRequest<T>(`/${resourceType}/${id}/_history/${versionId}`, 'GET')({}, request);
|
|
388
602
|
}
|
|
389
603
|
if (count) {
|
|
390
|
-
return this.fhirRequest(
|
|
604
|
+
return this.fhirRequest<Bundle<T>>(
|
|
391
605
|
`/${resourceType}/${id}/_history?_total=accurate&_count=${count}
|
|
392
606
|
${offset ? `&_offset=${offset}` : ''}`,
|
|
393
607
|
'GET'
|
|
394
608
|
)({}, request);
|
|
395
609
|
}
|
|
396
|
-
return this.fhirRequest(`/${resourceType}/${id}/_history?_total=accurate`, 'GET')({}, request);
|
|
610
|
+
return this.fhirRequest<Bundle<T>>(`/${resourceType}/${id}/_history?_total=accurate`, 'GET')({}, request);
|
|
397
611
|
}
|
|
398
612
|
|
|
399
613
|
/**
|
|
@@ -546,19 +760,32 @@ function batchInputRequestToBundleEntryItem<T extends FhirResource>(
|
|
|
546
760
|
throw new Error('Unrecognized method');
|
|
547
761
|
}
|
|
548
762
|
|
|
763
|
+
export async function batch<BundleContentType extends FhirResource>(
|
|
764
|
+
this: SDKResource,
|
|
765
|
+
input: BatchInput<BundleContentType>,
|
|
766
|
+
request: OystehrClientRequest & { mode: Exclude<FhirResponseMode, 'sync'> }
|
|
767
|
+
): Promise<FhirAsyncJobHandle>;
|
|
768
|
+
export async function batch<BundleContentType extends FhirResource>(
|
|
769
|
+
this: SDKResource,
|
|
770
|
+
input: BatchInput<BundleContentType>,
|
|
771
|
+
request?: OystehrClientRequest & { mode?: 'sync' | undefined }
|
|
772
|
+
): Promise<FhirFetcherResponse<BatchBundle<BundleContentType>>>;
|
|
549
773
|
export async function batch<BundleContentType extends FhirResource>(
|
|
550
774
|
this: SDKResource,
|
|
551
775
|
input: BatchInput<BundleContentType>,
|
|
552
776
|
request?: OystehrClientRequest
|
|
553
|
-
): Promise<FhirFetcherResponse<BatchBundle<BundleContentType
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
777
|
+
): Promise<FhirFetcherResponse<BatchBundle<BundleContentType>> | FhirAsyncJobHandle> {
|
|
778
|
+
const requestPayload = {
|
|
779
|
+
resourceType: 'Bundle',
|
|
780
|
+
type: 'batch',
|
|
781
|
+
entry: input.requests.map((req) => batchInputRequestToBundleEntryItem(req, this.config)),
|
|
782
|
+
};
|
|
783
|
+
const requestMode = request?.mode;
|
|
784
|
+
if (isAsyncRequestMode(requestMode)) {
|
|
785
|
+
return await this.startAsyncJob('/', 'POST', requestPayload, requestMode, request);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
const resp = await this.fhirRequest<BatchBundle<BundleContentType>>('/', 'POST')(requestPayload, request);
|
|
562
789
|
// Validate each GET/HEAD retrieval entry against the tag config.
|
|
563
790
|
// Violations are replaced with a synthetic 404 OperationOutcome entry; batch entries are independent.
|
|
564
791
|
const rawEntries = resp.entry as Array<BundleEntry<BundleContentType>> | undefined;
|
|
@@ -601,19 +828,32 @@ export async function batch<BundleContentType extends FhirResource>(
|
|
|
601
828
|
return bundle;
|
|
602
829
|
}
|
|
603
830
|
|
|
831
|
+
export async function transaction<BundleContentType extends FhirResource>(
|
|
832
|
+
this: SDKResource,
|
|
833
|
+
input: BatchInput<BundleContentType>,
|
|
834
|
+
request: OystehrClientRequest & { mode: Exclude<FhirResponseMode, 'sync'> }
|
|
835
|
+
): Promise<FhirAsyncJobHandle>;
|
|
836
|
+
export async function transaction<BundleContentType extends FhirResource>(
|
|
837
|
+
this: SDKResource,
|
|
838
|
+
input: BatchInput<BundleContentType>,
|
|
839
|
+
request?: OystehrClientRequest & { mode?: 'sync' | undefined }
|
|
840
|
+
): Promise<FhirFetcherResponse<TransactionBundle<BundleContentType>>>;
|
|
604
841
|
export async function transaction<BundleContentType extends FhirResource>(
|
|
605
842
|
this: SDKResource,
|
|
606
843
|
input: BatchInput<BundleContentType>,
|
|
607
844
|
request?: OystehrClientRequest
|
|
608
|
-
): Promise<FhirFetcherResponse<TransactionBundle<BundleContentType
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
845
|
+
): Promise<FhirFetcherResponse<TransactionBundle<BundleContentType>> | FhirAsyncJobHandle> {
|
|
846
|
+
const requestPayload = {
|
|
847
|
+
resourceType: 'Bundle',
|
|
848
|
+
type: 'transaction',
|
|
849
|
+
entry: input.requests.map((req) => batchInputRequestToBundleEntryItem(req, this.config)),
|
|
850
|
+
};
|
|
851
|
+
const requestMode = request?.mode;
|
|
852
|
+
if (isAsyncRequestMode(requestMode)) {
|
|
853
|
+
return await this.startAsyncJob('/', 'POST', requestPayload, requestMode, request);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
const resp = await this.fhirRequest<TransactionBundle<BundleContentType>>('/', 'POST')(requestPayload, request);
|
|
617
857
|
// Validate each GET/HEAD retrieval entry against the tag config.
|
|
618
858
|
// A violation throws OystehrFHIRError(404) — transactions are all-or-nothing.
|
|
619
859
|
if (this.config.workspaceTag || this.config.ignoreTags?.length) {
|
|
@@ -20,6 +20,9 @@ export class Fhir extends SDKResource {
|
|
|
20
20
|
search = ext.search;
|
|
21
21
|
create = ext.create;
|
|
22
22
|
get = ext.get;
|
|
23
|
+
getAsyncJob = ext.getAsyncJob;
|
|
24
|
+
waitForAsyncJob = ext.waitForAsyncJob;
|
|
25
|
+
cancelAsyncJob = ext.cancelAsyncJob;
|
|
23
26
|
update = ext.update;
|
|
24
27
|
patch = ext.patch;
|
|
25
28
|
delete = ext.delete;
|
|
@@ -166,3 +166,91 @@ export type BatchInputRequest<F extends FhirResource> =
|
|
|
166
166
|
export interface BatchInput<F extends FhirResource> {
|
|
167
167
|
requests: BatchInputRequest<F>[];
|
|
168
168
|
}
|
|
169
|
+
|
|
170
|
+
export interface FhirAsyncJobHandle {
|
|
171
|
+
jobId: string;
|
|
172
|
+
contentLocation: string;
|
|
173
|
+
mode: FhirAsyncResponseMode;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export type FhirResponseMode = 'sync' | 'async-bundle' | 'async-bulk';
|
|
177
|
+
|
|
178
|
+
export type FhirAsyncResponseMode = 'bundle' | 'bulk';
|
|
179
|
+
|
|
180
|
+
export interface FhirAsyncCompletionBundleEntry<T extends FhirResource> {
|
|
181
|
+
response?: {
|
|
182
|
+
status?: string;
|
|
183
|
+
outcome?: OperationOutcome;
|
|
184
|
+
};
|
|
185
|
+
resource?: T | OperationOutcome;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export type FhirAsyncCompletionBundle<T extends FhirResource> = EntrylessFhirBundle<T | OperationOutcome> & {
|
|
189
|
+
resourceType: 'Bundle';
|
|
190
|
+
type: 'batch-response';
|
|
191
|
+
entry?: Array<FhirAsyncCompletionBundleEntry<T>>;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
export interface FhirAsyncJobInProgress {
|
|
195
|
+
status: 202;
|
|
196
|
+
xProgress?: string;
|
|
197
|
+
retryAfter?: string;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export interface FhirAsyncJobCompletedBundle<T extends FhirResource = FhirResource> {
|
|
201
|
+
status: 200;
|
|
202
|
+
mode: 'bundle';
|
|
203
|
+
bundle: FhirAsyncCompletionBundle<T>;
|
|
204
|
+
interactionStatus?: string;
|
|
205
|
+
resource?: T | OperationOutcome;
|
|
206
|
+
outcome?: OperationOutcome;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export interface FhirAsyncBulkOutputFile {
|
|
210
|
+
type: string;
|
|
211
|
+
url: string;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export interface FhirAsyncBulkManifest {
|
|
215
|
+
transactionTime: string;
|
|
216
|
+
request: string;
|
|
217
|
+
requiresAccessToken: boolean;
|
|
218
|
+
output: FhirAsyncBulkOutputFile[];
|
|
219
|
+
error: FhirAsyncBulkOutputFile[];
|
|
220
|
+
deleted?: FhirAsyncBulkOutputFile[];
|
|
221
|
+
extension?: Record<string, unknown>;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export interface FhirAsyncJobCompletedBulk {
|
|
225
|
+
status: 200;
|
|
226
|
+
mode: 'bulk';
|
|
227
|
+
manifest: FhirAsyncBulkManifest;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface FhirAsyncJobExpired {
|
|
231
|
+
status: 410;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export interface FhirAsyncJobNotFound {
|
|
235
|
+
status: 404;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export interface FhirAsyncJobUnexpected {
|
|
239
|
+
status: Exclude<number, 200 | 202 | 404 | 410>;
|
|
240
|
+
body: unknown;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export type FhirAsyncJobStatus<T extends FhirResource = FhirResource> =
|
|
244
|
+
| FhirAsyncJobInProgress
|
|
245
|
+
| FhirAsyncJobCompletedBundle<T>
|
|
246
|
+
| FhirAsyncJobCompletedBulk
|
|
247
|
+
| FhirAsyncJobExpired
|
|
248
|
+
| FhirAsyncJobNotFound
|
|
249
|
+
| FhirAsyncJobUnexpected;
|
|
250
|
+
|
|
251
|
+
export interface FhirAsyncWaitOptions {
|
|
252
|
+
/** Poll interval in milliseconds. Defaults to 1000 (1 second). */
|
|
253
|
+
pollIntervalMs: number;
|
|
254
|
+
/** Maximum wait time in milliseconds before timing out. Defaults to 900000 (15 minutes). */
|
|
255
|
+
timeoutMs: number;
|
|
256
|
+
}
|