@medplum/core 2.0.20 → 2.0.21

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.
@@ -6417,7 +6417,7 @@
6417
6417
 
6418
6418
  // PKCE auth based on:
6419
6419
  // https://aws.amazon.com/blogs/security/how-to-add-authentication-single-page-web-application-with-amazon-cognito-oauth2-implementation/
6420
- const MEDPLUM_VERSION = "2.0.20-effeb76c" ;
6420
+ const MEDPLUM_VERSION = "2.0.21-87271fa1" ;
6421
6421
  const DEFAULT_BASE_URL = 'https://api.medplum.com/';
6422
6422
  const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
6423
6423
  const DEFAULT_CACHE_TIME = 60000; // 60 seconds
@@ -7713,10 +7713,11 @@
7713
7713
  * See The FHIR "batch/transaction" section for full details: https://hl7.org/fhir/http.html#transaction
7714
7714
  * @category Batch
7715
7715
  * @param bundle The FHIR batch/transaction bundle.
7716
+ * @param options Optional fetch options.
7716
7717
  * @returns The FHIR batch/transaction response bundle.
7717
7718
  */
7718
- executeBatch(bundle) {
7719
- return this.post(this.fhirBaseUrl.slice(0, -1), bundle);
7719
+ executeBatch(bundle, options = {}) {
7720
+ return this.post(this.fhirBaseUrl.slice(0, -1), bundle, undefined, options);
7720
7721
  }
7721
7722
  /**
7722
7723
  * Sends an email using the Medplum Email API.
@@ -7946,6 +7947,37 @@
7946
7947
  },
7947
7948
  });
7948
7949
  }
7950
+ /**
7951
+ * Performs Bulk Data Export operation request flow. See The FHIR "Bulk Data Export" for full details: https://build.fhir.org/ig/HL7/bulk-data/export.html#bulk-data-export
7952
+ *
7953
+ * @param exportLevel Optional export level. Defaults to system level export. 'Group/:id' - Group of Patients, 'Patient' - All Patients.
7954
+ * @param resourceTypes A string of comma-delimited FHIR resource types.
7955
+ * @param since Resources will be included in the response if their state has changed after the supplied time (e.g. if Resource.meta.lastUpdated is later than the supplied _since time).
7956
+ * @param options Optional fetch options.
7957
+ * @returns Bulk Data Response containing links to Bulk Data files. See "Response - Complete Status" for full details: https://build.fhir.org/ig/HL7/bulk-data/export.html#response---complete-status
7958
+ */
7959
+ async bulkExport(exportLevel = '', resourceTypes, since, options = {}) {
7960
+ const fhirPath = exportLevel ? `${exportLevel}/` : exportLevel;
7961
+ const url = this.fhirUrl(`${fhirPath}$export`);
7962
+ if (resourceTypes) {
7963
+ url.searchParams.set('_type', resourceTypes);
7964
+ }
7965
+ if (since) {
7966
+ url.searchParams.set('_since', since);
7967
+ }
7968
+ options.method = exportLevel ? 'GET' : 'POST';
7969
+ this.addFetchOptionsDefaults(options);
7970
+ const headers = options.headers;
7971
+ headers['Prefer'] = 'respond-async';
7972
+ const response = await this.fetchWithRetry(url.toString(), options);
7973
+ if (response.status === 202) {
7974
+ const contentLocation = response.headers.get('content-location');
7975
+ if (contentLocation) {
7976
+ return await this.pollStatus(contentLocation);
7977
+ }
7978
+ }
7979
+ return await this.parseResponse(response, 'POST', url.toString());
7980
+ }
7949
7981
  //
7950
7982
  // Private helpers
7951
7983
  //
@@ -8012,6 +8044,9 @@
8012
8044
  options.method = method;
8013
8045
  this.addFetchOptionsDefaults(options);
8014
8046
  const response = await this.fetchWithRetry(url, options);
8047
+ return await this.parseResponse(response, method, url, options);
8048
+ }
8049
+ async parseResponse(response, method, url, options = {}) {
8015
8050
  if (response.status === 401) {
8016
8051
  // Refresh and try again
8017
8052
  return this.handleUnauthenticated(method, url, options);
@@ -8044,14 +8079,37 @@
8044
8079
  const retryDelay = 200;
8045
8080
  let response = undefined;
8046
8081
  for (let retry = 0; retry < maxRetries; retry++) {
8047
- response = (await this.fetch(url, options));
8048
- if (response.status < 500) {
8049
- return response;
8082
+ try {
8083
+ response = (await this.fetch(url, options));
8084
+ if (response.status < 500) {
8085
+ return response;
8086
+ }
8087
+ }
8088
+ catch (err) {
8089
+ this.retryCatch(retry, maxRetries, err);
8050
8090
  }
8051
8091
  await new Promise((resolve) => setTimeout(resolve, retryDelay));
8052
8092
  }
8053
8093
  return response;
8054
8094
  }
8095
+ async pollStatus(statusUrl) {
8096
+ let checkStatus = true;
8097
+ let resultResponse;
8098
+ const retryDelay = 200;
8099
+ while (checkStatus) {
8100
+ const fetchOptions = {
8101
+ method: 'GET',
8102
+ };
8103
+ this.addFetchOptionsDefaults(fetchOptions);
8104
+ const statusResponse = await this.fetchWithRetry(statusUrl, fetchOptions);
8105
+ if (statusResponse.status !== 202) {
8106
+ checkStatus = false;
8107
+ resultResponse = statusResponse;
8108
+ }
8109
+ await new Promise((resolve) => setTimeout(resolve, retryDelay));
8110
+ }
8111
+ return await this.parseResponse(resultResponse, 'POST', statusUrl);
8112
+ }
8055
8113
  /**
8056
8114
  * Executes a batch of requests that were automatically batched together.
8057
8115
  */
@@ -8109,6 +8167,7 @@
8109
8167
  headers = {};
8110
8168
  options.headers = headers;
8111
8169
  }
8170
+ headers['Accept'] = FHIR_CONTENT_TYPE;
8112
8171
  headers['X-Medplum'] = 'extended';
8113
8172
  if (options.body && !headers['Content-Type']) {
8114
8173
  headers['Content-Type'] = FHIR_CONTENT_TYPE;
@@ -8365,6 +8424,15 @@
8365
8424
  // Silently ignore if this environment does not support storage events
8366
8425
  }
8367
8426
  }
8427
+ retryCatch(retryNumber, maxRetries, err) {
8428
+ // This is for the 1st retry to avoid multiple notifications
8429
+ if (err.message === 'Failed to fetch' && retryNumber === 1) {
8430
+ this.dispatchEvent({ type: 'offline' });
8431
+ }
8432
+ if (retryNumber >= maxRetries - 1) {
8433
+ throw err;
8434
+ }
8435
+ }
8368
8436
  }
8369
8437
  /**
8370
8438
  * Returns the default fetch method.
@@ -11582,7 +11650,7 @@
11582
11650
  searchRequest.total = value;
11583
11651
  break;
11584
11652
  case '_summary':
11585
- searchRequest.total = 'estimate';
11653
+ searchRequest.total = 'accurate';
11586
11654
  searchRequest.count = 0;
11587
11655
  break;
11588
11656
  case '_include': {
@@ -12910,7 +12978,6 @@
12910
12978
  return new Promise((resolve, reject) => {
12911
12979
  stream.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
12912
12980
  stream.on('error', (err) => {
12913
- console.error(err.message);
12914
12981
  stream.destroy();
12915
12982
  reject(err);
12916
12983
  });