@medplum/core 0.9.9 → 0.9.12
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/cody-pdf-test.js +1 -1
- package/dist/cjs/index.js +229 -340
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/index.min.js +1 -1
- package/dist/cjs/index.min.js.map +1 -1
- package/dist/esm/index.js +229 -340
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/index.min.js +1 -1
- package/dist/esm/index.min.js.map +1 -1
- package/dist/types/client.d.ts +61 -31
- package/package.json +2 -2
- package/dist/types/pdf.d.ts +0 -5
- package/document.pdf +0 -0
- package/test.pdf +0 -1
- package/test2.pdf +0 -1
- package/test3.pdf.txt +0 -1
- package/test4.pdf +0 -1
- package/test5.pdf +0 -0
- package/test7-2.pdf +0 -1
- package/test7.pdf +0 -1
- package/test8-2.pdf +0 -0
- package/test8.pdf +0 -0
- package/test9-2.pdf +0 -0
- package/test9-3.pdf +0 -0
- package/test9-4.pdf +0 -0
- package/test9.pdf +0 -0
package/dist/esm/index.js
CHANGED
|
@@ -804,109 +804,6 @@ class OperationOutcomeError extends Error {
|
|
|
804
804
|
}
|
|
805
805
|
}
|
|
806
806
|
|
|
807
|
-
/*
|
|
808
|
-
* This file attempts a unified "generatePdf" function that works both client-side and server-side.
|
|
809
|
-
* On client-side, it checks for a global "pdfMake" variable.
|
|
810
|
-
* On server-side, it dynamically loads "pdfmake" from the node_modules.
|
|
811
|
-
*/
|
|
812
|
-
function generatePdf(docDefinition, tableLayouts, fonts) {
|
|
813
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
814
|
-
// Setup sane defaults
|
|
815
|
-
// See: https://pdfmake.github.io/docs/0.1/document-definition-object/styling/
|
|
816
|
-
docDefinition.pageSize = docDefinition.pageSize || 'LETTER';
|
|
817
|
-
docDefinition.pageMargins = docDefinition.pageMargins || [60, 60, 60, 60];
|
|
818
|
-
docDefinition.pageOrientation = docDefinition.pageOrientation || 'portrait';
|
|
819
|
-
docDefinition.defaultStyle = docDefinition.defaultStyle || {};
|
|
820
|
-
docDefinition.defaultStyle.font = docDefinition.defaultStyle.font || 'Helvetica';
|
|
821
|
-
docDefinition.defaultStyle.fontSize = docDefinition.defaultStyle.fontSize || 11;
|
|
822
|
-
docDefinition.defaultStyle.lineHeight = docDefinition.defaultStyle.lineHeight || 2.0;
|
|
823
|
-
if (typeof pdfMake === 'undefined') {
|
|
824
|
-
return generatePdfServerSide(docDefinition, tableLayouts, fonts);
|
|
825
|
-
}
|
|
826
|
-
else {
|
|
827
|
-
return generatePdfClientSide(docDefinition, tableLayouts, fonts);
|
|
828
|
-
}
|
|
829
|
-
});
|
|
830
|
-
}
|
|
831
|
-
function generatePdfServerSide(docDefinition, tableLayouts, fonts) {
|
|
832
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
833
|
-
if (!fonts) {
|
|
834
|
-
fonts = {
|
|
835
|
-
Helvetica: {
|
|
836
|
-
normal: 'Helvetica',
|
|
837
|
-
bold: 'Helvetica-Bold',
|
|
838
|
-
italics: 'Helvetica-Oblique',
|
|
839
|
-
bolditalics: 'Helvetica-BoldOblique',
|
|
840
|
-
},
|
|
841
|
-
Roboto: {
|
|
842
|
-
normal: 'https://static.medplum.com/fonts/Roboto-Regular.ttf',
|
|
843
|
-
bold: 'https://static.medplum.com/fonts/Roboto-Medium.ttf',
|
|
844
|
-
italics: 'https://static.medplum.com/fonts/Roboto-Italic.ttf',
|
|
845
|
-
bolditalics: 'https://static.medplum.com/fonts/Roboto-MediumItalic.ttf',
|
|
846
|
-
},
|
|
847
|
-
Avenir: {
|
|
848
|
-
normal: 'https://static.medplum.com/fonts/avenir.ttf',
|
|
849
|
-
},
|
|
850
|
-
};
|
|
851
|
-
}
|
|
852
|
-
return new Promise((resolve, reject) => {
|
|
853
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
854
|
-
const PdfPrinter = require('pdfmake');
|
|
855
|
-
const printer = new PdfPrinter(fonts);
|
|
856
|
-
const pdfDoc = printer.createPdfKitDocument(docDefinition, { tableLayouts });
|
|
857
|
-
const chunks = [];
|
|
858
|
-
pdfDoc.on('data', (chunk) => chunks.push(chunk));
|
|
859
|
-
pdfDoc.on('end', () => resolve(concat(chunks)));
|
|
860
|
-
pdfDoc.on('error', reject);
|
|
861
|
-
pdfDoc.end();
|
|
862
|
-
});
|
|
863
|
-
});
|
|
864
|
-
}
|
|
865
|
-
function generatePdfClientSide(docDefinition, tableLayouts, fonts) {
|
|
866
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
867
|
-
if (!fonts) {
|
|
868
|
-
fonts = {
|
|
869
|
-
Helvetica: {
|
|
870
|
-
normal: 'https://static.medplum.com/fonts/Helvetica.ttf',
|
|
871
|
-
bold: 'https://static.medplum.com/fonts/Helvetica-bold.ttf',
|
|
872
|
-
italics: 'https://static.medplum.com/fonts/Helvetica-italic.ttf',
|
|
873
|
-
bolditalics: 'https://static.medplum.com/fonts/Helvetica-bold-italic.ttf',
|
|
874
|
-
},
|
|
875
|
-
Roboto: {
|
|
876
|
-
normal: 'https://static.medplum.com/fonts/Roboto-Regular.ttf',
|
|
877
|
-
bold: 'https://static.medplum.com/fonts/Roboto-Medium.ttf',
|
|
878
|
-
italics: 'https://static.medplum.com/fonts/Roboto-Italic.ttf',
|
|
879
|
-
bolditalics: 'https://static.medplum.com/fonts/Roboto-MediumItalic.ttf',
|
|
880
|
-
},
|
|
881
|
-
Avenir: {
|
|
882
|
-
normal: 'https://static.medplum.com/fonts/avenir.ttf',
|
|
883
|
-
},
|
|
884
|
-
};
|
|
885
|
-
}
|
|
886
|
-
return new Promise((resolve) => {
|
|
887
|
-
pdfMake.createPdf(docDefinition, tableLayouts, fonts).getBlob(resolve);
|
|
888
|
-
});
|
|
889
|
-
});
|
|
890
|
-
}
|
|
891
|
-
/**
|
|
892
|
-
* Concatenates an array of Uint8Arrays into a single Uint8Array.
|
|
893
|
-
* @param arrays An array of arrays of bytes.
|
|
894
|
-
* @returns A single array of bytes.
|
|
895
|
-
*/
|
|
896
|
-
function concat(arrays) {
|
|
897
|
-
let len = 0;
|
|
898
|
-
for (const array of arrays) {
|
|
899
|
-
len += array.length;
|
|
900
|
-
}
|
|
901
|
-
const result = new Uint8Array(len);
|
|
902
|
-
let index = 0;
|
|
903
|
-
for (const array of arrays) {
|
|
904
|
-
result.set(array, index);
|
|
905
|
-
index += array.length;
|
|
906
|
-
}
|
|
907
|
-
return result;
|
|
908
|
-
}
|
|
909
|
-
|
|
910
807
|
var _ReadablePromise_suspender, _ReadablePromise_status, _ReadablePromise_response, _ReadablePromise_error, _a;
|
|
911
808
|
/**
|
|
912
809
|
* The ReadablePromise class wraps a request promise suitable for React Suspense.
|
|
@@ -983,206 +880,6 @@ class ReadablePromise {
|
|
|
983
880
|
}
|
|
984
881
|
_ReadablePromise_suspender = new WeakMap(), _ReadablePromise_status = new WeakMap(), _ReadablePromise_response = new WeakMap(), _ReadablePromise_error = new WeakMap(), _a = Symbol.toStringTag;
|
|
985
882
|
|
|
986
|
-
const DEFAULT_SEARCH_COUNT = 20;
|
|
987
|
-
/**
|
|
988
|
-
* Search operators.
|
|
989
|
-
* These operators represent "modifiers" and "prefixes" in FHIR search.
|
|
990
|
-
* See: https://www.hl7.org/fhir/search.html
|
|
991
|
-
*/
|
|
992
|
-
var Operator;
|
|
993
|
-
(function (Operator) {
|
|
994
|
-
Operator["EQUALS"] = "eq";
|
|
995
|
-
Operator["NOT_EQUALS"] = "ne";
|
|
996
|
-
// Numbers
|
|
997
|
-
Operator["GREATER_THAN"] = "gt";
|
|
998
|
-
Operator["LESS_THAN"] = "lt";
|
|
999
|
-
Operator["GREATER_THAN_OR_EQUALS"] = "ge";
|
|
1000
|
-
Operator["LESS_THAN_OR_EQUALS"] = "le";
|
|
1001
|
-
// Dates
|
|
1002
|
-
Operator["STARTS_AFTER"] = "sa";
|
|
1003
|
-
Operator["ENDS_BEFORE"] = "eb";
|
|
1004
|
-
Operator["APPROXIMATELY"] = "ap";
|
|
1005
|
-
// String
|
|
1006
|
-
Operator["CONTAINS"] = "contains";
|
|
1007
|
-
Operator["EXACT"] = "exact";
|
|
1008
|
-
// Token
|
|
1009
|
-
Operator["TEXT"] = "text";
|
|
1010
|
-
Operator["ABOVE"] = "above";
|
|
1011
|
-
Operator["BELOW"] = "below";
|
|
1012
|
-
Operator["IN"] = "in";
|
|
1013
|
-
Operator["NOT_IN"] = "not-in";
|
|
1014
|
-
Operator["OF_TYPE"] = "of-type";
|
|
1015
|
-
})(Operator || (Operator = {}));
|
|
1016
|
-
const MODIFIER_OPERATORS = [
|
|
1017
|
-
Operator.CONTAINS,
|
|
1018
|
-
Operator.EXACT,
|
|
1019
|
-
Operator.TEXT,
|
|
1020
|
-
Operator.ABOVE,
|
|
1021
|
-
Operator.BELOW,
|
|
1022
|
-
Operator.IN,
|
|
1023
|
-
Operator.NOT_IN,
|
|
1024
|
-
Operator.OF_TYPE,
|
|
1025
|
-
];
|
|
1026
|
-
const PREFIX_OPERATORS = [
|
|
1027
|
-
Operator.NOT_EQUALS,
|
|
1028
|
-
Operator.GREATER_THAN,
|
|
1029
|
-
Operator.LESS_THAN,
|
|
1030
|
-
Operator.GREATER_THAN_OR_EQUALS,
|
|
1031
|
-
Operator.LESS_THAN_OR_EQUALS,
|
|
1032
|
-
Operator.STARTS_AFTER,
|
|
1033
|
-
Operator.ENDS_BEFORE,
|
|
1034
|
-
Operator.APPROXIMATELY,
|
|
1035
|
-
];
|
|
1036
|
-
/**
|
|
1037
|
-
* Parses a URL into a SearchRequest.
|
|
1038
|
-
*
|
|
1039
|
-
* See the FHIR search spec: http://hl7.org/fhir/r4/search.html
|
|
1040
|
-
*
|
|
1041
|
-
* @param url The URL to parse.
|
|
1042
|
-
* @returns Parsed search definition.
|
|
1043
|
-
*/
|
|
1044
|
-
function parseSearchDefinition(url) {
|
|
1045
|
-
const location = new URL(url, 'https://example.com/');
|
|
1046
|
-
const resourceType = location.pathname
|
|
1047
|
-
.replace(/(^\/)|(\/$)/g, '') // Remove leading and trailing slashes
|
|
1048
|
-
.split('/')
|
|
1049
|
-
.pop();
|
|
1050
|
-
const params = new URLSearchParams(location.search);
|
|
1051
|
-
let filters = undefined;
|
|
1052
|
-
let sortRules = undefined;
|
|
1053
|
-
let fields = undefined;
|
|
1054
|
-
let offset = undefined;
|
|
1055
|
-
let count = undefined;
|
|
1056
|
-
let total = undefined;
|
|
1057
|
-
params.forEach((value, key) => {
|
|
1058
|
-
if (key === '_fields') {
|
|
1059
|
-
fields = value.split(',');
|
|
1060
|
-
}
|
|
1061
|
-
else if (key === '_offset') {
|
|
1062
|
-
offset = parseInt(value);
|
|
1063
|
-
}
|
|
1064
|
-
else if (key === '_count') {
|
|
1065
|
-
count = parseInt(value);
|
|
1066
|
-
}
|
|
1067
|
-
else if (key === '_total') {
|
|
1068
|
-
total = value;
|
|
1069
|
-
}
|
|
1070
|
-
else if (key === '_sort') {
|
|
1071
|
-
sortRules = sortRules || [];
|
|
1072
|
-
sortRules.push(parseSortRule(value));
|
|
1073
|
-
}
|
|
1074
|
-
else {
|
|
1075
|
-
filters = filters || [];
|
|
1076
|
-
filters.push(parseSearchFilter(key, value));
|
|
1077
|
-
}
|
|
1078
|
-
});
|
|
1079
|
-
return {
|
|
1080
|
-
resourceType,
|
|
1081
|
-
filters,
|
|
1082
|
-
fields,
|
|
1083
|
-
offset,
|
|
1084
|
-
count,
|
|
1085
|
-
total,
|
|
1086
|
-
sortRules,
|
|
1087
|
-
};
|
|
1088
|
-
}
|
|
1089
|
-
/**
|
|
1090
|
-
* Parses a URL query parameter into a sort rule.
|
|
1091
|
-
*
|
|
1092
|
-
* By default, the sort rule is the field name.
|
|
1093
|
-
*
|
|
1094
|
-
* Sort rules can be reversed into descending order by prefixing the field name with a minus sign.
|
|
1095
|
-
*
|
|
1096
|
-
* See sorting: http://hl7.org/fhir/r4/search.html#_sort
|
|
1097
|
-
*
|
|
1098
|
-
* @param value The URL parameter value.
|
|
1099
|
-
* @returns The parsed sort rule.
|
|
1100
|
-
*/
|
|
1101
|
-
function parseSortRule(value) {
|
|
1102
|
-
if (value.startsWith('-')) {
|
|
1103
|
-
return { code: value.substring(1), descending: true };
|
|
1104
|
-
}
|
|
1105
|
-
else {
|
|
1106
|
-
return { code: value };
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
/**
|
|
1110
|
-
* Parses a URL query parameter into a search filter.
|
|
1111
|
-
*
|
|
1112
|
-
* FHIR search filters can be specified as modifiers or prefixes.
|
|
1113
|
-
*
|
|
1114
|
-
* For string properties, modifiers are appended to the key, e.g. "name:contains=eve".
|
|
1115
|
-
*
|
|
1116
|
-
* For date and numeric properties, prefixes are prepended to the value, e.g. "birthdate=gt2000".
|
|
1117
|
-
*
|
|
1118
|
-
* See the FHIR search spec: http://hl7.org/fhir/r4/search.html
|
|
1119
|
-
*
|
|
1120
|
-
* @param key The URL parameter key.
|
|
1121
|
-
* @param value The URL parameter value.
|
|
1122
|
-
* @returns The parsed search filter.
|
|
1123
|
-
*/
|
|
1124
|
-
function parseSearchFilter(key, value) {
|
|
1125
|
-
let code = key;
|
|
1126
|
-
let operator = Operator.EQUALS;
|
|
1127
|
-
for (const modifier of MODIFIER_OPERATORS) {
|
|
1128
|
-
const modifierIndex = code.indexOf(':' + modifier);
|
|
1129
|
-
if (modifierIndex !== -1) {
|
|
1130
|
-
operator = modifier;
|
|
1131
|
-
code = code.substring(0, modifierIndex);
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
for (const prefix of PREFIX_OPERATORS) {
|
|
1135
|
-
if (value.match(new RegExp('^' + prefix + '\\d'))) {
|
|
1136
|
-
operator = prefix;
|
|
1137
|
-
value = value.substring(prefix.length);
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
|
-
return { code, operator, value };
|
|
1141
|
-
}
|
|
1142
|
-
/**
|
|
1143
|
-
* Formats a search definition object into a query string.
|
|
1144
|
-
* Note: The return value does not include the resource type.
|
|
1145
|
-
* @param {!SearchRequest} definition The search definition.
|
|
1146
|
-
* @returns Formatted URL.
|
|
1147
|
-
*/
|
|
1148
|
-
function formatSearchQuery(definition) {
|
|
1149
|
-
const params = [];
|
|
1150
|
-
if (definition.fields) {
|
|
1151
|
-
params.push('_fields=' + definition.fields.join(','));
|
|
1152
|
-
}
|
|
1153
|
-
if (definition.filters) {
|
|
1154
|
-
definition.filters.forEach((filter) => params.push(formatFilter(filter)));
|
|
1155
|
-
}
|
|
1156
|
-
if (definition.sortRules && definition.sortRules.length > 0) {
|
|
1157
|
-
params.push(formatSortRules(definition.sortRules));
|
|
1158
|
-
}
|
|
1159
|
-
if (definition.offset !== undefined) {
|
|
1160
|
-
params.push('_offset=' + definition.offset);
|
|
1161
|
-
}
|
|
1162
|
-
if (definition.count !== undefined) {
|
|
1163
|
-
params.push('_count=' + definition.count);
|
|
1164
|
-
}
|
|
1165
|
-
if (definition.total !== undefined) {
|
|
1166
|
-
params.push('_total=' + definition.total);
|
|
1167
|
-
}
|
|
1168
|
-
if (params.length === 0) {
|
|
1169
|
-
return '';
|
|
1170
|
-
}
|
|
1171
|
-
params.sort();
|
|
1172
|
-
return '?' + params.join('&');
|
|
1173
|
-
}
|
|
1174
|
-
function formatFilter(filter) {
|
|
1175
|
-
const modifier = MODIFIER_OPERATORS.includes(filter.operator) ? ':' + filter.operator : '';
|
|
1176
|
-
const prefix = PREFIX_OPERATORS.includes(filter.operator) ? filter.operator : '';
|
|
1177
|
-
return `${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`;
|
|
1178
|
-
}
|
|
1179
|
-
function formatSortRules(sortRules) {
|
|
1180
|
-
if (!sortRules || sortRules.length === 0) {
|
|
1181
|
-
return '';
|
|
1182
|
-
}
|
|
1183
|
-
return '_sort=' + sortRules.map((sr) => (sr.descending ? '-' + sr.code : sr.code)).join(',');
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
883
|
var _ClientStorage_storage, _MemoryStorage_data;
|
|
1187
884
|
/**
|
|
1188
885
|
* The ClientStorage class is a utility class for storing strings and objects.
|
|
@@ -1471,7 +1168,7 @@ function getPropertyDisplayName(property) {
|
|
|
1471
1168
|
|
|
1472
1169
|
// PKCE auth ased on:
|
|
1473
1170
|
// https://aws.amazon.com/blogs/security/how-to-add-authentication-single-page-web-application-with-amazon-cognito-oauth2-implementation/
|
|
1474
|
-
var _MedplumClient_instances, _MedplumClient_fetch, _MedplumClient_storage, _MedplumClient_schema, _MedplumClient_requestCache, _MedplumClient_baseUrl, _MedplumClient_clientId, _MedplumClient_authorizeUrl, _MedplumClient_tokenUrl, _MedplumClient_logoutUrl, _MedplumClient_onUnauthenticated, _MedplumClient_accessToken, _MedplumClient_refreshToken, _MedplumClient_refreshPromise, _MedplumClient_profilePromise, _MedplumClient_profile, _MedplumClient_config, _MedplumClient_addLogin, _MedplumClient_refreshProfile, _MedplumClient_request, _MedplumClient_addFetchOptionsDefaults, _MedplumClient_setRequestContentType, _MedplumClient_setRequestBody, _MedplumClient_handleUnauthenticated, _MedplumClient_startPkce, _MedplumClient_requestAuthorization, _MedplumClient_refresh, _MedplumClient_fetchTokens, _MedplumClient_verifyTokens, _MedplumClient_setupStorageListener;
|
|
1171
|
+
var _MedplumClient_instances, _MedplumClient_fetch, _MedplumClient_createPdf, _MedplumClient_storage, _MedplumClient_schema, _MedplumClient_requestCache, _MedplumClient_baseUrl, _MedplumClient_clientId, _MedplumClient_authorizeUrl, _MedplumClient_tokenUrl, _MedplumClient_logoutUrl, _MedplumClient_onUnauthenticated, _MedplumClient_accessToken, _MedplumClient_refreshToken, _MedplumClient_refreshPromise, _MedplumClient_profilePromise, _MedplumClient_profile, _MedplumClient_config, _MedplumClient_addLogin, _MedplumClient_refreshProfile, _MedplumClient_request, _MedplumClient_addFetchOptionsDefaults, _MedplumClient_setRequestContentType, _MedplumClient_setRequestBody, _MedplumClient_handleUnauthenticated, _MedplumClient_startPkce, _MedplumClient_requestAuthorization, _MedplumClient_refresh, _MedplumClient_fetchTokens, _MedplumClient_verifyTokens, _MedplumClient_setupStorageListener;
|
|
1475
1172
|
const DEFAULT_BASE_URL = 'https://api.medplum.com/';
|
|
1476
1173
|
const DEFAULT_SCOPE = 'launch/patient openid fhirUser offline_access user/*.*';
|
|
1477
1174
|
const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
|
|
@@ -1521,7 +1218,7 @@ const PATCH_CONTENT_TYPE = 'application/json-patch+json';
|
|
|
1521
1218
|
* Search for a `Patient` by name:
|
|
1522
1219
|
*
|
|
1523
1220
|
* ```typescript
|
|
1524
|
-
* const bundle = await medplum.search('Patient
|
|
1221
|
+
* const bundle = await medplum.search('Patient', 'name=Alice');
|
|
1525
1222
|
* console.log(bundle.total);
|
|
1526
1223
|
* ```
|
|
1527
1224
|
*/
|
|
@@ -1531,6 +1228,7 @@ class MedplumClient extends EventTarget {
|
|
|
1531
1228
|
super();
|
|
1532
1229
|
_MedplumClient_instances.add(this);
|
|
1533
1230
|
_MedplumClient_fetch.set(this, void 0);
|
|
1231
|
+
_MedplumClient_createPdf.set(this, void 0);
|
|
1534
1232
|
_MedplumClient_storage.set(this, void 0);
|
|
1535
1233
|
_MedplumClient_schema.set(this, void 0);
|
|
1536
1234
|
_MedplumClient_requestCache.set(this, void 0);
|
|
@@ -1555,6 +1253,7 @@ class MedplumClient extends EventTarget {
|
|
|
1555
1253
|
}
|
|
1556
1254
|
}
|
|
1557
1255
|
__classPrivateFieldSet(this, _MedplumClient_fetch, (options === null || options === void 0 ? void 0 : options.fetch) || window.fetch.bind(window), "f");
|
|
1256
|
+
__classPrivateFieldSet(this, _MedplumClient_createPdf, options === null || options === void 0 ? void 0 : options.createPdf, "f");
|
|
1558
1257
|
__classPrivateFieldSet(this, _MedplumClient_storage, new ClientStorage(), "f");
|
|
1559
1258
|
__classPrivateFieldSet(this, _MedplumClient_schema, createSchema(), "f");
|
|
1560
1259
|
__classPrivateFieldSet(this, _MedplumClient_requestCache, new LRUCache((_a = options === null || options === void 0 ? void 0 : options.resourceCacheSize) !== null && _a !== void 0 ? _a : DEFAULT_RESOURCE_CACHE_SIZE), "f");
|
|
@@ -1799,12 +1498,11 @@ class MedplumClient extends EventTarget {
|
|
|
1799
1498
|
* @param query The FHIR search query or structured query object.
|
|
1800
1499
|
* @returns The well-formed FHIR URL.
|
|
1801
1500
|
*/
|
|
1802
|
-
fhirSearchUrl(query) {
|
|
1803
|
-
|
|
1804
|
-
|
|
1501
|
+
fhirSearchUrl(resourceType, query) {
|
|
1502
|
+
const url = this.fhirUrl(resourceType);
|
|
1503
|
+
if (query) {
|
|
1504
|
+
url.search = query.toString();
|
|
1805
1505
|
}
|
|
1806
|
-
const url = this.fhirUrl(query.resourceType);
|
|
1807
|
-
url.search = formatSearchQuery(query);
|
|
1808
1506
|
return url;
|
|
1809
1507
|
}
|
|
1810
1508
|
/**
|
|
@@ -1813,21 +1511,7 @@ class MedplumClient extends EventTarget {
|
|
|
1813
1511
|
* Example using a FHIR search string:
|
|
1814
1512
|
*
|
|
1815
1513
|
* ```typescript
|
|
1816
|
-
* const bundle = await client.search('Patient
|
|
1817
|
-
* console.log(bundle);
|
|
1818
|
-
* ```
|
|
1819
|
-
*
|
|
1820
|
-
* Example using a structured search:
|
|
1821
|
-
*
|
|
1822
|
-
* ```typescript
|
|
1823
|
-
* const bundle = await client.search({
|
|
1824
|
-
* resourceType: 'Patient',
|
|
1825
|
-
* filters: [{
|
|
1826
|
-
* code: 'name',
|
|
1827
|
-
* operator: 'eq',
|
|
1828
|
-
* value: 'Alice',
|
|
1829
|
-
* }]
|
|
1830
|
-
* });
|
|
1514
|
+
* const bundle = await client.search('Patient', 'name=Alice');
|
|
1831
1515
|
* console.log(bundle);
|
|
1832
1516
|
* ```
|
|
1833
1517
|
*
|
|
@@ -1861,8 +1545,8 @@ class MedplumClient extends EventTarget {
|
|
|
1861
1545
|
* @param query The search query as either a string or a structured search object.
|
|
1862
1546
|
* @returns Promise to the search result bundle.
|
|
1863
1547
|
*/
|
|
1864
|
-
search(query, options = {}) {
|
|
1865
|
-
return this.get(this.fhirSearchUrl(query), options);
|
|
1548
|
+
search(resourceType, query, options = {}) {
|
|
1549
|
+
return this.get(this.fhirSearchUrl(resourceType, query), options);
|
|
1866
1550
|
}
|
|
1867
1551
|
/**
|
|
1868
1552
|
* Sends a FHIR search request for a single resource.
|
|
@@ -1872,7 +1556,7 @@ class MedplumClient extends EventTarget {
|
|
|
1872
1556
|
* Example using a FHIR search string:
|
|
1873
1557
|
*
|
|
1874
1558
|
* ```typescript
|
|
1875
|
-
* const patient = await client.searchOne('Patient
|
|
1559
|
+
* const patient = await client.searchOne('Patient', 'identifier=123');
|
|
1876
1560
|
* console.log(patient);
|
|
1877
1561
|
* ```
|
|
1878
1562
|
*
|
|
@@ -1883,17 +1567,18 @@ class MedplumClient extends EventTarget {
|
|
|
1883
1567
|
* @param query The search query as either a string or a structured search object.
|
|
1884
1568
|
* @returns Promise to the search result bundle.
|
|
1885
1569
|
*/
|
|
1886
|
-
searchOne(query, options = {}) {
|
|
1887
|
-
const
|
|
1888
|
-
|
|
1889
|
-
|
|
1570
|
+
searchOne(resourceType, query, options = {}) {
|
|
1571
|
+
const url = this.fhirSearchUrl(resourceType, query);
|
|
1572
|
+
url.searchParams.set('_count', '1');
|
|
1573
|
+
url.searchParams.sort();
|
|
1574
|
+
const cacheKey = url.toString() + '-searchOne';
|
|
1890
1575
|
if (!(options === null || options === void 0 ? void 0 : options.cache)) {
|
|
1891
1576
|
const cached = __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").get(cacheKey);
|
|
1892
1577
|
if (cached) {
|
|
1893
1578
|
return cached;
|
|
1894
1579
|
}
|
|
1895
1580
|
}
|
|
1896
|
-
const promise = new ReadablePromise(this.search(
|
|
1581
|
+
const promise = new ReadablePromise(this.search(resourceType, url.searchParams, options).then((b) => { var _a, _b; return (_b = (_a = b.entry) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.resource; }));
|
|
1897
1582
|
__classPrivateFieldGet(this, _MedplumClient_requestCache, "f").set(cacheKey, promise);
|
|
1898
1583
|
return promise;
|
|
1899
1584
|
}
|
|
@@ -1905,7 +1590,7 @@ class MedplumClient extends EventTarget {
|
|
|
1905
1590
|
* Example using a FHIR search string:
|
|
1906
1591
|
*
|
|
1907
1592
|
* ```typescript
|
|
1908
|
-
* const patients = await client.searchResources('Patient
|
|
1593
|
+
* const patients = await client.searchResources('Patient', 'name=Alice');
|
|
1909
1594
|
* console.log(patients);
|
|
1910
1595
|
* ```
|
|
1911
1596
|
*
|
|
@@ -1916,15 +1601,16 @@ class MedplumClient extends EventTarget {
|
|
|
1916
1601
|
* @param query The search query as either a string or a structured search object.
|
|
1917
1602
|
* @returns Promise to the search result bundle.
|
|
1918
1603
|
*/
|
|
1919
|
-
searchResources(query, options = {}) {
|
|
1920
|
-
const
|
|
1604
|
+
searchResources(resourceType, query, options = {}) {
|
|
1605
|
+
const url = this.fhirSearchUrl(resourceType, query);
|
|
1606
|
+
const cacheKey = url.toString() + '-searchResources';
|
|
1921
1607
|
if (!(options === null || options === void 0 ? void 0 : options.cache)) {
|
|
1922
1608
|
const cached = __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").get(cacheKey);
|
|
1923
1609
|
if (cached) {
|
|
1924
1610
|
return cached;
|
|
1925
1611
|
}
|
|
1926
1612
|
}
|
|
1927
|
-
const promise = new ReadablePromise(this.search(query, options).then((b) => { var _a, _b; return (_b = (_a = b.entry) === null || _a === void 0 ? void 0 : _a.map((e) => e.resource)) !== null && _b !== void 0 ? _b : []; }));
|
|
1613
|
+
const promise = new ReadablePromise(this.search(resourceType, query, options).then((b) => { var _a, _b; return (_b = (_a = b.entry) === null || _a === void 0 ? void 0 : _a.map((e) => e.resource)) !== null && _b !== void 0 ? _b : []; }));
|
|
1928
1614
|
__classPrivateFieldGet(this, _MedplumClient_requestCache, "f").set(cacheKey, promise);
|
|
1929
1615
|
return promise;
|
|
1930
1616
|
}
|
|
@@ -2181,7 +1867,7 @@ class MedplumClient extends EventTarget {
|
|
|
2181
1867
|
createResourceIfNoneExist(resource, query) {
|
|
2182
1868
|
var _a;
|
|
2183
1869
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2184
|
-
return (_a = (yield this.searchOne(
|
|
1870
|
+
return ((_a = (yield this.searchOne(resource.resourceType, query))) !== null && _a !== void 0 ? _a : this.createResource(resource));
|
|
2185
1871
|
});
|
|
2186
1872
|
}
|
|
2187
1873
|
/**
|
|
@@ -2237,7 +1923,10 @@ class MedplumClient extends EventTarget {
|
|
|
2237
1923
|
*/
|
|
2238
1924
|
createPdf(docDefinition, filename, tableLayouts, fonts) {
|
|
2239
1925
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2240
|
-
|
|
1926
|
+
if (!__classPrivateFieldGet(this, _MedplumClient_createPdf, "f")) {
|
|
1927
|
+
throw new Error('PDF creation not enabled');
|
|
1928
|
+
}
|
|
1929
|
+
const blob = yield __classPrivateFieldGet(this, _MedplumClient_createPdf, "f").call(this, docDefinition, tableLayouts, fonts);
|
|
2241
1930
|
return this.createBinary(blob, filename, 'application/pdf');
|
|
2242
1931
|
});
|
|
2243
1932
|
}
|
|
@@ -2500,7 +2189,7 @@ class MedplumClient extends EventTarget {
|
|
|
2500
2189
|
});
|
|
2501
2190
|
}
|
|
2502
2191
|
}
|
|
2503
|
-
_MedplumClient_fetch = new WeakMap(), _MedplumClient_storage = new WeakMap(), _MedplumClient_schema = new WeakMap(), _MedplumClient_requestCache = new WeakMap(), _MedplumClient_baseUrl = new WeakMap(), _MedplumClient_clientId = new WeakMap(), _MedplumClient_authorizeUrl = new WeakMap(), _MedplumClient_tokenUrl = new WeakMap(), _MedplumClient_logoutUrl = new WeakMap(), _MedplumClient_onUnauthenticated = new WeakMap(), _MedplumClient_accessToken = new WeakMap(), _MedplumClient_refreshToken = new WeakMap(), _MedplumClient_refreshPromise = new WeakMap(), _MedplumClient_profilePromise = new WeakMap(), _MedplumClient_profile = new WeakMap(), _MedplumClient_config = new WeakMap(), _MedplumClient_instances = new WeakSet(), _MedplumClient_addLogin = function _MedplumClient_addLogin(newLogin) {
|
|
2192
|
+
_MedplumClient_fetch = new WeakMap(), _MedplumClient_createPdf = new WeakMap(), _MedplumClient_storage = new WeakMap(), _MedplumClient_schema = new WeakMap(), _MedplumClient_requestCache = new WeakMap(), _MedplumClient_baseUrl = new WeakMap(), _MedplumClient_clientId = new WeakMap(), _MedplumClient_authorizeUrl = new WeakMap(), _MedplumClient_tokenUrl = new WeakMap(), _MedplumClient_logoutUrl = new WeakMap(), _MedplumClient_onUnauthenticated = new WeakMap(), _MedplumClient_accessToken = new WeakMap(), _MedplumClient_refreshToken = new WeakMap(), _MedplumClient_refreshPromise = new WeakMap(), _MedplumClient_profilePromise = new WeakMap(), _MedplumClient_profile = new WeakMap(), _MedplumClient_config = new WeakMap(), _MedplumClient_instances = new WeakSet(), _MedplumClient_addLogin = function _MedplumClient_addLogin(newLogin) {
|
|
2504
2193
|
const logins = this.getLogins().filter((login) => { var _a, _b; return ((_a = login.profile) === null || _a === void 0 ? void 0 : _a.reference) !== ((_b = newLogin.profile) === null || _b === void 0 ? void 0 : _b.reference); });
|
|
2505
2194
|
logins.push(newLogin);
|
|
2506
2195
|
__classPrivateFieldGet(this, _MedplumClient_storage, "f").setObject('logins', logins);
|
|
@@ -5329,6 +5018,206 @@ class Hl7Field {
|
|
|
5329
5018
|
}
|
|
5330
5019
|
}
|
|
5331
5020
|
|
|
5021
|
+
const DEFAULT_SEARCH_COUNT = 20;
|
|
5022
|
+
/**
|
|
5023
|
+
* Search operators.
|
|
5024
|
+
* These operators represent "modifiers" and "prefixes" in FHIR search.
|
|
5025
|
+
* See: https://www.hl7.org/fhir/search.html
|
|
5026
|
+
*/
|
|
5027
|
+
var Operator;
|
|
5028
|
+
(function (Operator) {
|
|
5029
|
+
Operator["EQUALS"] = "eq";
|
|
5030
|
+
Operator["NOT_EQUALS"] = "ne";
|
|
5031
|
+
// Numbers
|
|
5032
|
+
Operator["GREATER_THAN"] = "gt";
|
|
5033
|
+
Operator["LESS_THAN"] = "lt";
|
|
5034
|
+
Operator["GREATER_THAN_OR_EQUALS"] = "ge";
|
|
5035
|
+
Operator["LESS_THAN_OR_EQUALS"] = "le";
|
|
5036
|
+
// Dates
|
|
5037
|
+
Operator["STARTS_AFTER"] = "sa";
|
|
5038
|
+
Operator["ENDS_BEFORE"] = "eb";
|
|
5039
|
+
Operator["APPROXIMATELY"] = "ap";
|
|
5040
|
+
// String
|
|
5041
|
+
Operator["CONTAINS"] = "contains";
|
|
5042
|
+
Operator["EXACT"] = "exact";
|
|
5043
|
+
// Token
|
|
5044
|
+
Operator["TEXT"] = "text";
|
|
5045
|
+
Operator["ABOVE"] = "above";
|
|
5046
|
+
Operator["BELOW"] = "below";
|
|
5047
|
+
Operator["IN"] = "in";
|
|
5048
|
+
Operator["NOT_IN"] = "not-in";
|
|
5049
|
+
Operator["OF_TYPE"] = "of-type";
|
|
5050
|
+
})(Operator || (Operator = {}));
|
|
5051
|
+
const MODIFIER_OPERATORS = [
|
|
5052
|
+
Operator.CONTAINS,
|
|
5053
|
+
Operator.EXACT,
|
|
5054
|
+
Operator.TEXT,
|
|
5055
|
+
Operator.ABOVE,
|
|
5056
|
+
Operator.BELOW,
|
|
5057
|
+
Operator.IN,
|
|
5058
|
+
Operator.NOT_IN,
|
|
5059
|
+
Operator.OF_TYPE,
|
|
5060
|
+
];
|
|
5061
|
+
const PREFIX_OPERATORS = [
|
|
5062
|
+
Operator.NOT_EQUALS,
|
|
5063
|
+
Operator.GREATER_THAN,
|
|
5064
|
+
Operator.LESS_THAN,
|
|
5065
|
+
Operator.GREATER_THAN_OR_EQUALS,
|
|
5066
|
+
Operator.LESS_THAN_OR_EQUALS,
|
|
5067
|
+
Operator.STARTS_AFTER,
|
|
5068
|
+
Operator.ENDS_BEFORE,
|
|
5069
|
+
Operator.APPROXIMATELY,
|
|
5070
|
+
];
|
|
5071
|
+
/**
|
|
5072
|
+
* Parses a URL into a SearchRequest.
|
|
5073
|
+
*
|
|
5074
|
+
* See the FHIR search spec: http://hl7.org/fhir/r4/search.html
|
|
5075
|
+
*
|
|
5076
|
+
* @param url The URL to parse.
|
|
5077
|
+
* @returns Parsed search definition.
|
|
5078
|
+
*/
|
|
5079
|
+
function parseSearchDefinition(url) {
|
|
5080
|
+
const location = new URL(url, 'https://example.com/');
|
|
5081
|
+
const resourceType = location.pathname
|
|
5082
|
+
.replace(/(^\/)|(\/$)/g, '') // Remove leading and trailing slashes
|
|
5083
|
+
.split('/')
|
|
5084
|
+
.pop();
|
|
5085
|
+
const params = new URLSearchParams(location.search);
|
|
5086
|
+
let filters = undefined;
|
|
5087
|
+
let sortRules = undefined;
|
|
5088
|
+
let fields = undefined;
|
|
5089
|
+
let offset = undefined;
|
|
5090
|
+
let count = undefined;
|
|
5091
|
+
let total = undefined;
|
|
5092
|
+
params.forEach((value, key) => {
|
|
5093
|
+
if (key === '_fields') {
|
|
5094
|
+
fields = value.split(',');
|
|
5095
|
+
}
|
|
5096
|
+
else if (key === '_offset') {
|
|
5097
|
+
offset = parseInt(value);
|
|
5098
|
+
}
|
|
5099
|
+
else if (key === '_count') {
|
|
5100
|
+
count = parseInt(value);
|
|
5101
|
+
}
|
|
5102
|
+
else if (key === '_total') {
|
|
5103
|
+
total = value;
|
|
5104
|
+
}
|
|
5105
|
+
else if (key === '_sort') {
|
|
5106
|
+
sortRules = sortRules || [];
|
|
5107
|
+
sortRules.push(parseSortRule(value));
|
|
5108
|
+
}
|
|
5109
|
+
else {
|
|
5110
|
+
filters = filters || [];
|
|
5111
|
+
filters.push(parseSearchFilter(key, value));
|
|
5112
|
+
}
|
|
5113
|
+
});
|
|
5114
|
+
return {
|
|
5115
|
+
resourceType,
|
|
5116
|
+
filters,
|
|
5117
|
+
fields,
|
|
5118
|
+
offset,
|
|
5119
|
+
count,
|
|
5120
|
+
total,
|
|
5121
|
+
sortRules,
|
|
5122
|
+
};
|
|
5123
|
+
}
|
|
5124
|
+
/**
|
|
5125
|
+
* Parses a URL query parameter into a sort rule.
|
|
5126
|
+
*
|
|
5127
|
+
* By default, the sort rule is the field name.
|
|
5128
|
+
*
|
|
5129
|
+
* Sort rules can be reversed into descending order by prefixing the field name with a minus sign.
|
|
5130
|
+
*
|
|
5131
|
+
* See sorting: http://hl7.org/fhir/r4/search.html#_sort
|
|
5132
|
+
*
|
|
5133
|
+
* @param value The URL parameter value.
|
|
5134
|
+
* @returns The parsed sort rule.
|
|
5135
|
+
*/
|
|
5136
|
+
function parseSortRule(value) {
|
|
5137
|
+
if (value.startsWith('-')) {
|
|
5138
|
+
return { code: value.substring(1), descending: true };
|
|
5139
|
+
}
|
|
5140
|
+
else {
|
|
5141
|
+
return { code: value };
|
|
5142
|
+
}
|
|
5143
|
+
}
|
|
5144
|
+
/**
|
|
5145
|
+
* Parses a URL query parameter into a search filter.
|
|
5146
|
+
*
|
|
5147
|
+
* FHIR search filters can be specified as modifiers or prefixes.
|
|
5148
|
+
*
|
|
5149
|
+
* For string properties, modifiers are appended to the key, e.g. "name:contains=eve".
|
|
5150
|
+
*
|
|
5151
|
+
* For date and numeric properties, prefixes are prepended to the value, e.g. "birthdate=gt2000".
|
|
5152
|
+
*
|
|
5153
|
+
* See the FHIR search spec: http://hl7.org/fhir/r4/search.html
|
|
5154
|
+
*
|
|
5155
|
+
* @param key The URL parameter key.
|
|
5156
|
+
* @param value The URL parameter value.
|
|
5157
|
+
* @returns The parsed search filter.
|
|
5158
|
+
*/
|
|
5159
|
+
function parseSearchFilter(key, value) {
|
|
5160
|
+
let code = key;
|
|
5161
|
+
let operator = Operator.EQUALS;
|
|
5162
|
+
for (const modifier of MODIFIER_OPERATORS) {
|
|
5163
|
+
const modifierIndex = code.indexOf(':' + modifier);
|
|
5164
|
+
if (modifierIndex !== -1) {
|
|
5165
|
+
operator = modifier;
|
|
5166
|
+
code = code.substring(0, modifierIndex);
|
|
5167
|
+
}
|
|
5168
|
+
}
|
|
5169
|
+
for (const prefix of PREFIX_OPERATORS) {
|
|
5170
|
+
if (value.match(new RegExp('^' + prefix + '\\d'))) {
|
|
5171
|
+
operator = prefix;
|
|
5172
|
+
value = value.substring(prefix.length);
|
|
5173
|
+
}
|
|
5174
|
+
}
|
|
5175
|
+
return { code, operator, value };
|
|
5176
|
+
}
|
|
5177
|
+
/**
|
|
5178
|
+
* Formats a search definition object into a query string.
|
|
5179
|
+
* Note: The return value does not include the resource type.
|
|
5180
|
+
* @param {!SearchRequest} definition The search definition.
|
|
5181
|
+
* @returns Formatted URL.
|
|
5182
|
+
*/
|
|
5183
|
+
function formatSearchQuery(definition) {
|
|
5184
|
+
const params = [];
|
|
5185
|
+
if (definition.fields) {
|
|
5186
|
+
params.push('_fields=' + definition.fields.join(','));
|
|
5187
|
+
}
|
|
5188
|
+
if (definition.filters) {
|
|
5189
|
+
definition.filters.forEach((filter) => params.push(formatFilter(filter)));
|
|
5190
|
+
}
|
|
5191
|
+
if (definition.sortRules && definition.sortRules.length > 0) {
|
|
5192
|
+
params.push(formatSortRules(definition.sortRules));
|
|
5193
|
+
}
|
|
5194
|
+
if (definition.offset !== undefined) {
|
|
5195
|
+
params.push('_offset=' + definition.offset);
|
|
5196
|
+
}
|
|
5197
|
+
if (definition.count !== undefined) {
|
|
5198
|
+
params.push('_count=' + definition.count);
|
|
5199
|
+
}
|
|
5200
|
+
if (definition.total !== undefined) {
|
|
5201
|
+
params.push('_total=' + definition.total);
|
|
5202
|
+
}
|
|
5203
|
+
if (params.length === 0) {
|
|
5204
|
+
return '';
|
|
5205
|
+
}
|
|
5206
|
+
params.sort();
|
|
5207
|
+
return '?' + params.join('&');
|
|
5208
|
+
}
|
|
5209
|
+
function formatFilter(filter) {
|
|
5210
|
+
const modifier = MODIFIER_OPERATORS.includes(filter.operator) ? ':' + filter.operator : '';
|
|
5211
|
+
const prefix = PREFIX_OPERATORS.includes(filter.operator) ? filter.operator : '';
|
|
5212
|
+
return `${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`;
|
|
5213
|
+
}
|
|
5214
|
+
function formatSortRules(sortRules) {
|
|
5215
|
+
if (!sortRules || sortRules.length === 0) {
|
|
5216
|
+
return '';
|
|
5217
|
+
}
|
|
5218
|
+
return '_sort=' + sortRules.map((sr) => (sr.descending ? '-' + sr.code : sr.code)).join(',');
|
|
5219
|
+
}
|
|
5220
|
+
|
|
5332
5221
|
var SearchParameterType;
|
|
5333
5222
|
(function (SearchParameterType) {
|
|
5334
5223
|
SearchParameterType["BOOLEAN"] = "BOOLEAN";
|