@medplum/core 2.0.19 → 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.
- package/README.md +1 -1
- package/dist/cjs/index.cjs +92 -19
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.min.cjs +1 -1
- package/dist/esm/client.mjs +81 -6
- package/dist/esm/client.mjs.map +1 -1
- package/dist/esm/index.min.mjs +1 -1
- package/dist/esm/search/details.mjs +10 -11
- package/dist/esm/search/details.mjs.map +1 -1
- package/dist/esm/search/search.mjs +1 -1
- package/dist/esm/search/search.mjs.map +1 -1
- package/dist/esm/sftp.mjs +0 -1
- package/dist/esm/sftp.mjs.map +1 -1
- package/dist/types/client.d.ts +21 -2
- package/dist/types/config.d.ts +49 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/typeschema/types.d.ts +56 -0
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/cjs/index.cjs
CHANGED
|
@@ -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.
|
|
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
|
|
@@ -6588,6 +6588,13 @@
|
|
|
6588
6588
|
url = url.toString();
|
|
6589
6589
|
this.requestCache?.delete(url);
|
|
6590
6590
|
}
|
|
6591
|
+
/**
|
|
6592
|
+
* Invalidates all cached values and flushes the cache.
|
|
6593
|
+
* @category Caching
|
|
6594
|
+
*/
|
|
6595
|
+
invalidateAll() {
|
|
6596
|
+
this.requestCache?.clear();
|
|
6597
|
+
}
|
|
6591
6598
|
/**
|
|
6592
6599
|
* Invalidates all cached search results or cached requests for the given resourceType.
|
|
6593
6600
|
* @category Caching
|
|
@@ -7706,10 +7713,11 @@
|
|
|
7706
7713
|
* See The FHIR "batch/transaction" section for full details: https://hl7.org/fhir/http.html#transaction
|
|
7707
7714
|
* @category Batch
|
|
7708
7715
|
* @param bundle The FHIR batch/transaction bundle.
|
|
7716
|
+
* @param options Optional fetch options.
|
|
7709
7717
|
* @returns The FHIR batch/transaction response bundle.
|
|
7710
7718
|
*/
|
|
7711
|
-
executeBatch(bundle) {
|
|
7712
|
-
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);
|
|
7713
7721
|
}
|
|
7714
7722
|
/**
|
|
7715
7723
|
* Sends an email using the Medplum Email API.
|
|
@@ -7939,6 +7947,37 @@
|
|
|
7939
7947
|
},
|
|
7940
7948
|
});
|
|
7941
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
|
+
}
|
|
7942
7981
|
//
|
|
7943
7982
|
// Private helpers
|
|
7944
7983
|
//
|
|
@@ -8005,6 +8044,9 @@
|
|
|
8005
8044
|
options.method = method;
|
|
8006
8045
|
this.addFetchOptionsDefaults(options);
|
|
8007
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 = {}) {
|
|
8008
8050
|
if (response.status === 401) {
|
|
8009
8051
|
// Refresh and try again
|
|
8010
8052
|
return this.handleUnauthenticated(method, url, options);
|
|
@@ -8037,14 +8079,37 @@
|
|
|
8037
8079
|
const retryDelay = 200;
|
|
8038
8080
|
let response = undefined;
|
|
8039
8081
|
for (let retry = 0; retry < maxRetries; retry++) {
|
|
8040
|
-
|
|
8041
|
-
|
|
8042
|
-
|
|
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);
|
|
8043
8090
|
}
|
|
8044
8091
|
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
8045
8092
|
}
|
|
8046
8093
|
return response;
|
|
8047
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
|
+
}
|
|
8048
8113
|
/**
|
|
8049
8114
|
* Executes a batch of requests that were automatically batched together.
|
|
8050
8115
|
*/
|
|
@@ -8102,6 +8167,7 @@
|
|
|
8102
8167
|
headers = {};
|
|
8103
8168
|
options.headers = headers;
|
|
8104
8169
|
}
|
|
8170
|
+
headers['Accept'] = FHIR_CONTENT_TYPE;
|
|
8105
8171
|
headers['X-Medplum'] = 'extended';
|
|
8106
8172
|
if (options.body && !headers['Content-Type']) {
|
|
8107
8173
|
headers['Content-Type'] = FHIR_CONTENT_TYPE;
|
|
@@ -8358,6 +8424,15 @@
|
|
|
8358
8424
|
// Silently ignore if this environment does not support storage events
|
|
8359
8425
|
}
|
|
8360
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
|
+
}
|
|
8361
8436
|
}
|
|
8362
8437
|
/**
|
|
8363
8438
|
* Returns the default fetch method.
|
|
@@ -11575,7 +11650,7 @@
|
|
|
11575
11650
|
searchRequest.total = value;
|
|
11576
11651
|
break;
|
|
11577
11652
|
case '_summary':
|
|
11578
|
-
searchRequest.total = '
|
|
11653
|
+
searchRequest.total = 'accurate';
|
|
11579
11654
|
searchRequest.count = 0;
|
|
11580
11655
|
break;
|
|
11581
11656
|
case '_include': {
|
|
@@ -12628,26 +12703,28 @@
|
|
|
12628
12703
|
// In the future, explore returning multiple column definitions
|
|
12629
12704
|
return { columnName, type: exports.SearchParameterType.TEXT };
|
|
12630
12705
|
}
|
|
12631
|
-
const defaultType = getSearchParameterType(searchParam);
|
|
12632
12706
|
let baseType = resourceType;
|
|
12633
12707
|
let elementDefinition = undefined;
|
|
12634
12708
|
let propertyType = undefined;
|
|
12635
12709
|
let array = false;
|
|
12636
12710
|
for (let i = 1; i < expression.length; i++) {
|
|
12637
|
-
|
|
12711
|
+
let propertyName = expression[i];
|
|
12712
|
+
let hasArrayIndex = false;
|
|
12713
|
+
const arrayIndexMatch = /\[\d+\]$/.exec(propertyName);
|
|
12714
|
+
if (arrayIndexMatch) {
|
|
12715
|
+
propertyName = propertyName.substring(0, propertyName.length - arrayIndexMatch[0].length);
|
|
12716
|
+
hasArrayIndex = true;
|
|
12717
|
+
}
|
|
12638
12718
|
elementDefinition = getElementDefinition(baseType, propertyName);
|
|
12639
12719
|
if (!elementDefinition) {
|
|
12640
12720
|
throw new Error(`Element definition not found for ${resourceType} ${searchParam.code}`);
|
|
12641
12721
|
}
|
|
12642
|
-
if (elementDefinition.max !== '0' && elementDefinition.max !== '1') {
|
|
12722
|
+
if (elementDefinition.max !== '0' && elementDefinition.max !== '1' && !hasArrayIndex) {
|
|
12643
12723
|
array = true;
|
|
12644
12724
|
}
|
|
12725
|
+
// "code" is only missing when using "contentReference"
|
|
12726
|
+
// "contentReference" is handled above in "getElementDefinition"
|
|
12645
12727
|
propertyType = elementDefinition.type?.[0].code;
|
|
12646
|
-
if (!propertyType) {
|
|
12647
|
-
// This happens when one of parent properties uses contentReference
|
|
12648
|
-
// In the future, explore following the reference
|
|
12649
|
-
return { columnName, type: defaultType, array };
|
|
12650
|
-
}
|
|
12651
12728
|
if (i < expression.length - 1) {
|
|
12652
12729
|
if (isBackboneElement(propertyType)) {
|
|
12653
12730
|
baseType = buildTypeName(elementDefinition.path?.split('.'));
|
|
@@ -12727,9 +12804,6 @@
|
|
|
12727
12804
|
if (result.startsWith('(') && result.endsWith(')')) {
|
|
12728
12805
|
result = result.substring(1, result.length - 1);
|
|
12729
12806
|
}
|
|
12730
|
-
if (result.includes('[0]')) {
|
|
12731
|
-
result = result.replaceAll('[0]', '');
|
|
12732
|
-
}
|
|
12733
12807
|
const stopStrings = [' != ', ' as ', '.as(', '.exists(', '.resolve(', '.where('];
|
|
12734
12808
|
for (const stopString of stopStrings) {
|
|
12735
12809
|
if (result.includes(stopString)) {
|
|
@@ -12904,7 +12978,6 @@
|
|
|
12904
12978
|
return new Promise((resolve, reject) => {
|
|
12905
12979
|
stream.on('data', (chunk) => chunks.push(Buffer.from(chunk)));
|
|
12906
12980
|
stream.on('error', (err) => {
|
|
12907
|
-
console.error(err.message);
|
|
12908
12981
|
stream.destroy();
|
|
12909
12982
|
reject(err);
|
|
12910
12983
|
});
|