@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.
@@ -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
- return this.fhirRequest(`/${resourceType}`, 'POST')(tagged as unknown as Record<string, unknown>, request);
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
- return this.fhirRequest(`/${resourceType}/${id}`, 'PUT')(tagged as unknown as Record<string, unknown>, {
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
- return this.fhirRequest(`/${resourceType}/${id}`, 'PATCH')(taggedOperations, {
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
- return this.fhirRequest(`/${resourceType}/${id}`, 'DELETE')({}, request);
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?: OystehrClientRequest
364
- ): Promise<FhirFetcherResponse<Bundle<T>>>;
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?: OystehrClientRequest
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 resp = await this.fhirRequest('/', 'POST')(
555
- {
556
- resourceType: 'Bundle',
557
- type: 'batch',
558
- entry: input.requests.map((req) => batchInputRequestToBundleEntryItem(req, this.config)),
559
- },
560
- request
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 resp = await this.fhirRequest('/', 'POST')(
610
- {
611
- resourceType: 'Bundle',
612
- type: 'transaction',
613
- entry: input.requests.map((req) => batchInputRequestToBundleEntryItem(req, this.config)),
614
- },
615
- request
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
+ }