@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/cjs/index.js
CHANGED
|
@@ -810,109 +810,6 @@
|
|
|
810
810
|
}
|
|
811
811
|
}
|
|
812
812
|
|
|
813
|
-
/*
|
|
814
|
-
* This file attempts a unified "generatePdf" function that works both client-side and server-side.
|
|
815
|
-
* On client-side, it checks for a global "pdfMake" variable.
|
|
816
|
-
* On server-side, it dynamically loads "pdfmake" from the node_modules.
|
|
817
|
-
*/
|
|
818
|
-
function generatePdf(docDefinition, tableLayouts, fonts) {
|
|
819
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
820
|
-
// Setup sane defaults
|
|
821
|
-
// See: https://pdfmake.github.io/docs/0.1/document-definition-object/styling/
|
|
822
|
-
docDefinition.pageSize = docDefinition.pageSize || 'LETTER';
|
|
823
|
-
docDefinition.pageMargins = docDefinition.pageMargins || [60, 60, 60, 60];
|
|
824
|
-
docDefinition.pageOrientation = docDefinition.pageOrientation || 'portrait';
|
|
825
|
-
docDefinition.defaultStyle = docDefinition.defaultStyle || {};
|
|
826
|
-
docDefinition.defaultStyle.font = docDefinition.defaultStyle.font || 'Helvetica';
|
|
827
|
-
docDefinition.defaultStyle.fontSize = docDefinition.defaultStyle.fontSize || 11;
|
|
828
|
-
docDefinition.defaultStyle.lineHeight = docDefinition.defaultStyle.lineHeight || 2.0;
|
|
829
|
-
if (typeof pdfMake === 'undefined') {
|
|
830
|
-
return generatePdfServerSide(docDefinition, tableLayouts, fonts);
|
|
831
|
-
}
|
|
832
|
-
else {
|
|
833
|
-
return generatePdfClientSide(docDefinition, tableLayouts, fonts);
|
|
834
|
-
}
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
function generatePdfServerSide(docDefinition, tableLayouts, fonts) {
|
|
838
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
839
|
-
if (!fonts) {
|
|
840
|
-
fonts = {
|
|
841
|
-
Helvetica: {
|
|
842
|
-
normal: 'Helvetica',
|
|
843
|
-
bold: 'Helvetica-Bold',
|
|
844
|
-
italics: 'Helvetica-Oblique',
|
|
845
|
-
bolditalics: 'Helvetica-BoldOblique',
|
|
846
|
-
},
|
|
847
|
-
Roboto: {
|
|
848
|
-
normal: 'https://static.medplum.com/fonts/Roboto-Regular.ttf',
|
|
849
|
-
bold: 'https://static.medplum.com/fonts/Roboto-Medium.ttf',
|
|
850
|
-
italics: 'https://static.medplum.com/fonts/Roboto-Italic.ttf',
|
|
851
|
-
bolditalics: 'https://static.medplum.com/fonts/Roboto-MediumItalic.ttf',
|
|
852
|
-
},
|
|
853
|
-
Avenir: {
|
|
854
|
-
normal: 'https://static.medplum.com/fonts/avenir.ttf',
|
|
855
|
-
},
|
|
856
|
-
};
|
|
857
|
-
}
|
|
858
|
-
return new Promise((resolve, reject) => {
|
|
859
|
-
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
860
|
-
const PdfPrinter = require('pdfmake');
|
|
861
|
-
const printer = new PdfPrinter(fonts);
|
|
862
|
-
const pdfDoc = printer.createPdfKitDocument(docDefinition, { tableLayouts });
|
|
863
|
-
const chunks = [];
|
|
864
|
-
pdfDoc.on('data', (chunk) => chunks.push(chunk));
|
|
865
|
-
pdfDoc.on('end', () => resolve(concat(chunks)));
|
|
866
|
-
pdfDoc.on('error', reject);
|
|
867
|
-
pdfDoc.end();
|
|
868
|
-
});
|
|
869
|
-
});
|
|
870
|
-
}
|
|
871
|
-
function generatePdfClientSide(docDefinition, tableLayouts, fonts) {
|
|
872
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
873
|
-
if (!fonts) {
|
|
874
|
-
fonts = {
|
|
875
|
-
Helvetica: {
|
|
876
|
-
normal: 'https://static.medplum.com/fonts/Helvetica.ttf',
|
|
877
|
-
bold: 'https://static.medplum.com/fonts/Helvetica-bold.ttf',
|
|
878
|
-
italics: 'https://static.medplum.com/fonts/Helvetica-italic.ttf',
|
|
879
|
-
bolditalics: 'https://static.medplum.com/fonts/Helvetica-bold-italic.ttf',
|
|
880
|
-
},
|
|
881
|
-
Roboto: {
|
|
882
|
-
normal: 'https://static.medplum.com/fonts/Roboto-Regular.ttf',
|
|
883
|
-
bold: 'https://static.medplum.com/fonts/Roboto-Medium.ttf',
|
|
884
|
-
italics: 'https://static.medplum.com/fonts/Roboto-Italic.ttf',
|
|
885
|
-
bolditalics: 'https://static.medplum.com/fonts/Roboto-MediumItalic.ttf',
|
|
886
|
-
},
|
|
887
|
-
Avenir: {
|
|
888
|
-
normal: 'https://static.medplum.com/fonts/avenir.ttf',
|
|
889
|
-
},
|
|
890
|
-
};
|
|
891
|
-
}
|
|
892
|
-
return new Promise((resolve) => {
|
|
893
|
-
pdfMake.createPdf(docDefinition, tableLayouts, fonts).getBlob(resolve);
|
|
894
|
-
});
|
|
895
|
-
});
|
|
896
|
-
}
|
|
897
|
-
/**
|
|
898
|
-
* Concatenates an array of Uint8Arrays into a single Uint8Array.
|
|
899
|
-
* @param arrays An array of arrays of bytes.
|
|
900
|
-
* @returns A single array of bytes.
|
|
901
|
-
*/
|
|
902
|
-
function concat(arrays) {
|
|
903
|
-
let len = 0;
|
|
904
|
-
for (const array of arrays) {
|
|
905
|
-
len += array.length;
|
|
906
|
-
}
|
|
907
|
-
const result = new Uint8Array(len);
|
|
908
|
-
let index = 0;
|
|
909
|
-
for (const array of arrays) {
|
|
910
|
-
result.set(array, index);
|
|
911
|
-
index += array.length;
|
|
912
|
-
}
|
|
913
|
-
return result;
|
|
914
|
-
}
|
|
915
|
-
|
|
916
813
|
var _ReadablePromise_suspender, _ReadablePromise_status, _ReadablePromise_response, _ReadablePromise_error, _a;
|
|
917
814
|
/**
|
|
918
815
|
* The ReadablePromise class wraps a request promise suitable for React Suspense.
|
|
@@ -989,206 +886,6 @@
|
|
|
989
886
|
}
|
|
990
887
|
_ReadablePromise_suspender = new WeakMap(), _ReadablePromise_status = new WeakMap(), _ReadablePromise_response = new WeakMap(), _ReadablePromise_error = new WeakMap(), _a = Symbol.toStringTag;
|
|
991
888
|
|
|
992
|
-
const DEFAULT_SEARCH_COUNT = 20;
|
|
993
|
-
/**
|
|
994
|
-
* Search operators.
|
|
995
|
-
* These operators represent "modifiers" and "prefixes" in FHIR search.
|
|
996
|
-
* See: https://www.hl7.org/fhir/search.html
|
|
997
|
-
*/
|
|
998
|
-
exports.Operator = void 0;
|
|
999
|
-
(function (Operator) {
|
|
1000
|
-
Operator["EQUALS"] = "eq";
|
|
1001
|
-
Operator["NOT_EQUALS"] = "ne";
|
|
1002
|
-
// Numbers
|
|
1003
|
-
Operator["GREATER_THAN"] = "gt";
|
|
1004
|
-
Operator["LESS_THAN"] = "lt";
|
|
1005
|
-
Operator["GREATER_THAN_OR_EQUALS"] = "ge";
|
|
1006
|
-
Operator["LESS_THAN_OR_EQUALS"] = "le";
|
|
1007
|
-
// Dates
|
|
1008
|
-
Operator["STARTS_AFTER"] = "sa";
|
|
1009
|
-
Operator["ENDS_BEFORE"] = "eb";
|
|
1010
|
-
Operator["APPROXIMATELY"] = "ap";
|
|
1011
|
-
// String
|
|
1012
|
-
Operator["CONTAINS"] = "contains";
|
|
1013
|
-
Operator["EXACT"] = "exact";
|
|
1014
|
-
// Token
|
|
1015
|
-
Operator["TEXT"] = "text";
|
|
1016
|
-
Operator["ABOVE"] = "above";
|
|
1017
|
-
Operator["BELOW"] = "below";
|
|
1018
|
-
Operator["IN"] = "in";
|
|
1019
|
-
Operator["NOT_IN"] = "not-in";
|
|
1020
|
-
Operator["OF_TYPE"] = "of-type";
|
|
1021
|
-
})(exports.Operator || (exports.Operator = {}));
|
|
1022
|
-
const MODIFIER_OPERATORS = [
|
|
1023
|
-
exports.Operator.CONTAINS,
|
|
1024
|
-
exports.Operator.EXACT,
|
|
1025
|
-
exports.Operator.TEXT,
|
|
1026
|
-
exports.Operator.ABOVE,
|
|
1027
|
-
exports.Operator.BELOW,
|
|
1028
|
-
exports.Operator.IN,
|
|
1029
|
-
exports.Operator.NOT_IN,
|
|
1030
|
-
exports.Operator.OF_TYPE,
|
|
1031
|
-
];
|
|
1032
|
-
const PREFIX_OPERATORS = [
|
|
1033
|
-
exports.Operator.NOT_EQUALS,
|
|
1034
|
-
exports.Operator.GREATER_THAN,
|
|
1035
|
-
exports.Operator.LESS_THAN,
|
|
1036
|
-
exports.Operator.GREATER_THAN_OR_EQUALS,
|
|
1037
|
-
exports.Operator.LESS_THAN_OR_EQUALS,
|
|
1038
|
-
exports.Operator.STARTS_AFTER,
|
|
1039
|
-
exports.Operator.ENDS_BEFORE,
|
|
1040
|
-
exports.Operator.APPROXIMATELY,
|
|
1041
|
-
];
|
|
1042
|
-
/**
|
|
1043
|
-
* Parses a URL into a SearchRequest.
|
|
1044
|
-
*
|
|
1045
|
-
* See the FHIR search spec: http://hl7.org/fhir/r4/search.html
|
|
1046
|
-
*
|
|
1047
|
-
* @param url The URL to parse.
|
|
1048
|
-
* @returns Parsed search definition.
|
|
1049
|
-
*/
|
|
1050
|
-
function parseSearchDefinition(url) {
|
|
1051
|
-
const location = new URL(url, 'https://example.com/');
|
|
1052
|
-
const resourceType = location.pathname
|
|
1053
|
-
.replace(/(^\/)|(\/$)/g, '') // Remove leading and trailing slashes
|
|
1054
|
-
.split('/')
|
|
1055
|
-
.pop();
|
|
1056
|
-
const params = new URLSearchParams(location.search);
|
|
1057
|
-
let filters = undefined;
|
|
1058
|
-
let sortRules = undefined;
|
|
1059
|
-
let fields = undefined;
|
|
1060
|
-
let offset = undefined;
|
|
1061
|
-
let count = undefined;
|
|
1062
|
-
let total = undefined;
|
|
1063
|
-
params.forEach((value, key) => {
|
|
1064
|
-
if (key === '_fields') {
|
|
1065
|
-
fields = value.split(',');
|
|
1066
|
-
}
|
|
1067
|
-
else if (key === '_offset') {
|
|
1068
|
-
offset = parseInt(value);
|
|
1069
|
-
}
|
|
1070
|
-
else if (key === '_count') {
|
|
1071
|
-
count = parseInt(value);
|
|
1072
|
-
}
|
|
1073
|
-
else if (key === '_total') {
|
|
1074
|
-
total = value;
|
|
1075
|
-
}
|
|
1076
|
-
else if (key === '_sort') {
|
|
1077
|
-
sortRules = sortRules || [];
|
|
1078
|
-
sortRules.push(parseSortRule(value));
|
|
1079
|
-
}
|
|
1080
|
-
else {
|
|
1081
|
-
filters = filters || [];
|
|
1082
|
-
filters.push(parseSearchFilter(key, value));
|
|
1083
|
-
}
|
|
1084
|
-
});
|
|
1085
|
-
return {
|
|
1086
|
-
resourceType,
|
|
1087
|
-
filters,
|
|
1088
|
-
fields,
|
|
1089
|
-
offset,
|
|
1090
|
-
count,
|
|
1091
|
-
total,
|
|
1092
|
-
sortRules,
|
|
1093
|
-
};
|
|
1094
|
-
}
|
|
1095
|
-
/**
|
|
1096
|
-
* Parses a URL query parameter into a sort rule.
|
|
1097
|
-
*
|
|
1098
|
-
* By default, the sort rule is the field name.
|
|
1099
|
-
*
|
|
1100
|
-
* Sort rules can be reversed into descending order by prefixing the field name with a minus sign.
|
|
1101
|
-
*
|
|
1102
|
-
* See sorting: http://hl7.org/fhir/r4/search.html#_sort
|
|
1103
|
-
*
|
|
1104
|
-
* @param value The URL parameter value.
|
|
1105
|
-
* @returns The parsed sort rule.
|
|
1106
|
-
*/
|
|
1107
|
-
function parseSortRule(value) {
|
|
1108
|
-
if (value.startsWith('-')) {
|
|
1109
|
-
return { code: value.substring(1), descending: true };
|
|
1110
|
-
}
|
|
1111
|
-
else {
|
|
1112
|
-
return { code: value };
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
/**
|
|
1116
|
-
* Parses a URL query parameter into a search filter.
|
|
1117
|
-
*
|
|
1118
|
-
* FHIR search filters can be specified as modifiers or prefixes.
|
|
1119
|
-
*
|
|
1120
|
-
* For string properties, modifiers are appended to the key, e.g. "name:contains=eve".
|
|
1121
|
-
*
|
|
1122
|
-
* For date and numeric properties, prefixes are prepended to the value, e.g. "birthdate=gt2000".
|
|
1123
|
-
*
|
|
1124
|
-
* See the FHIR search spec: http://hl7.org/fhir/r4/search.html
|
|
1125
|
-
*
|
|
1126
|
-
* @param key The URL parameter key.
|
|
1127
|
-
* @param value The URL parameter value.
|
|
1128
|
-
* @returns The parsed search filter.
|
|
1129
|
-
*/
|
|
1130
|
-
function parseSearchFilter(key, value) {
|
|
1131
|
-
let code = key;
|
|
1132
|
-
let operator = exports.Operator.EQUALS;
|
|
1133
|
-
for (const modifier of MODIFIER_OPERATORS) {
|
|
1134
|
-
const modifierIndex = code.indexOf(':' + modifier);
|
|
1135
|
-
if (modifierIndex !== -1) {
|
|
1136
|
-
operator = modifier;
|
|
1137
|
-
code = code.substring(0, modifierIndex);
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
|
-
for (const prefix of PREFIX_OPERATORS) {
|
|
1141
|
-
if (value.match(new RegExp('^' + prefix + '\\d'))) {
|
|
1142
|
-
operator = prefix;
|
|
1143
|
-
value = value.substring(prefix.length);
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
return { code, operator, value };
|
|
1147
|
-
}
|
|
1148
|
-
/**
|
|
1149
|
-
* Formats a search definition object into a query string.
|
|
1150
|
-
* Note: The return value does not include the resource type.
|
|
1151
|
-
* @param {!SearchRequest} definition The search definition.
|
|
1152
|
-
* @returns Formatted URL.
|
|
1153
|
-
*/
|
|
1154
|
-
function formatSearchQuery(definition) {
|
|
1155
|
-
const params = [];
|
|
1156
|
-
if (definition.fields) {
|
|
1157
|
-
params.push('_fields=' + definition.fields.join(','));
|
|
1158
|
-
}
|
|
1159
|
-
if (definition.filters) {
|
|
1160
|
-
definition.filters.forEach((filter) => params.push(formatFilter(filter)));
|
|
1161
|
-
}
|
|
1162
|
-
if (definition.sortRules && definition.sortRules.length > 0) {
|
|
1163
|
-
params.push(formatSortRules(definition.sortRules));
|
|
1164
|
-
}
|
|
1165
|
-
if (definition.offset !== undefined) {
|
|
1166
|
-
params.push('_offset=' + definition.offset);
|
|
1167
|
-
}
|
|
1168
|
-
if (definition.count !== undefined) {
|
|
1169
|
-
params.push('_count=' + definition.count);
|
|
1170
|
-
}
|
|
1171
|
-
if (definition.total !== undefined) {
|
|
1172
|
-
params.push('_total=' + definition.total);
|
|
1173
|
-
}
|
|
1174
|
-
if (params.length === 0) {
|
|
1175
|
-
return '';
|
|
1176
|
-
}
|
|
1177
|
-
params.sort();
|
|
1178
|
-
return '?' + params.join('&');
|
|
1179
|
-
}
|
|
1180
|
-
function formatFilter(filter) {
|
|
1181
|
-
const modifier = MODIFIER_OPERATORS.includes(filter.operator) ? ':' + filter.operator : '';
|
|
1182
|
-
const prefix = PREFIX_OPERATORS.includes(filter.operator) ? filter.operator : '';
|
|
1183
|
-
return `${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`;
|
|
1184
|
-
}
|
|
1185
|
-
function formatSortRules(sortRules) {
|
|
1186
|
-
if (!sortRules || sortRules.length === 0) {
|
|
1187
|
-
return '';
|
|
1188
|
-
}
|
|
1189
|
-
return '_sort=' + sortRules.map((sr) => (sr.descending ? '-' + sr.code : sr.code)).join(',');
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
889
|
var _ClientStorage_storage, _MemoryStorage_data;
|
|
1193
890
|
/**
|
|
1194
891
|
* The ClientStorage class is a utility class for storing strings and objects.
|
|
@@ -1477,7 +1174,7 @@
|
|
|
1477
1174
|
|
|
1478
1175
|
// PKCE auth ased on:
|
|
1479
1176
|
// https://aws.amazon.com/blogs/security/how-to-add-authentication-single-page-web-application-with-amazon-cognito-oauth2-implementation/
|
|
1480
|
-
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;
|
|
1177
|
+
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;
|
|
1481
1178
|
const DEFAULT_BASE_URL = 'https://api.medplum.com/';
|
|
1482
1179
|
const DEFAULT_SCOPE = 'launch/patient openid fhirUser offline_access user/*.*';
|
|
1483
1180
|
const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
|
|
@@ -1527,7 +1224,7 @@
|
|
|
1527
1224
|
* Search for a `Patient` by name:
|
|
1528
1225
|
*
|
|
1529
1226
|
* ```typescript
|
|
1530
|
-
* const bundle = await medplum.search('Patient
|
|
1227
|
+
* const bundle = await medplum.search('Patient', 'name=Alice');
|
|
1531
1228
|
* console.log(bundle.total);
|
|
1532
1229
|
* ```
|
|
1533
1230
|
*/
|
|
@@ -1537,6 +1234,7 @@
|
|
|
1537
1234
|
super();
|
|
1538
1235
|
_MedplumClient_instances.add(this);
|
|
1539
1236
|
_MedplumClient_fetch.set(this, void 0);
|
|
1237
|
+
_MedplumClient_createPdf.set(this, void 0);
|
|
1540
1238
|
_MedplumClient_storage.set(this, void 0);
|
|
1541
1239
|
_MedplumClient_schema.set(this, void 0);
|
|
1542
1240
|
_MedplumClient_requestCache.set(this, void 0);
|
|
@@ -1561,6 +1259,7 @@
|
|
|
1561
1259
|
}
|
|
1562
1260
|
}
|
|
1563
1261
|
__classPrivateFieldSet(this, _MedplumClient_fetch, (options === null || options === void 0 ? void 0 : options.fetch) || window.fetch.bind(window), "f");
|
|
1262
|
+
__classPrivateFieldSet(this, _MedplumClient_createPdf, options === null || options === void 0 ? void 0 : options.createPdf, "f");
|
|
1564
1263
|
__classPrivateFieldSet(this, _MedplumClient_storage, new ClientStorage(), "f");
|
|
1565
1264
|
__classPrivateFieldSet(this, _MedplumClient_schema, createSchema(), "f");
|
|
1566
1265
|
__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");
|
|
@@ -1805,12 +1504,11 @@
|
|
|
1805
1504
|
* @param query The FHIR search query or structured query object.
|
|
1806
1505
|
* @returns The well-formed FHIR URL.
|
|
1807
1506
|
*/
|
|
1808
|
-
fhirSearchUrl(query) {
|
|
1809
|
-
|
|
1810
|
-
|
|
1507
|
+
fhirSearchUrl(resourceType, query) {
|
|
1508
|
+
const url = this.fhirUrl(resourceType);
|
|
1509
|
+
if (query) {
|
|
1510
|
+
url.search = query.toString();
|
|
1811
1511
|
}
|
|
1812
|
-
const url = this.fhirUrl(query.resourceType);
|
|
1813
|
-
url.search = formatSearchQuery(query);
|
|
1814
1512
|
return url;
|
|
1815
1513
|
}
|
|
1816
1514
|
/**
|
|
@@ -1819,21 +1517,7 @@
|
|
|
1819
1517
|
* Example using a FHIR search string:
|
|
1820
1518
|
*
|
|
1821
1519
|
* ```typescript
|
|
1822
|
-
* const bundle = await client.search('Patient
|
|
1823
|
-
* console.log(bundle);
|
|
1824
|
-
* ```
|
|
1825
|
-
*
|
|
1826
|
-
* Example using a structured search:
|
|
1827
|
-
*
|
|
1828
|
-
* ```typescript
|
|
1829
|
-
* const bundle = await client.search({
|
|
1830
|
-
* resourceType: 'Patient',
|
|
1831
|
-
* filters: [{
|
|
1832
|
-
* code: 'name',
|
|
1833
|
-
* operator: 'eq',
|
|
1834
|
-
* value: 'Alice',
|
|
1835
|
-
* }]
|
|
1836
|
-
* });
|
|
1520
|
+
* const bundle = await client.search('Patient', 'name=Alice');
|
|
1837
1521
|
* console.log(bundle);
|
|
1838
1522
|
* ```
|
|
1839
1523
|
*
|
|
@@ -1867,8 +1551,8 @@
|
|
|
1867
1551
|
* @param query The search query as either a string or a structured search object.
|
|
1868
1552
|
* @returns Promise to the search result bundle.
|
|
1869
1553
|
*/
|
|
1870
|
-
search(query, options = {}) {
|
|
1871
|
-
return this.get(this.fhirSearchUrl(query), options);
|
|
1554
|
+
search(resourceType, query, options = {}) {
|
|
1555
|
+
return this.get(this.fhirSearchUrl(resourceType, query), options);
|
|
1872
1556
|
}
|
|
1873
1557
|
/**
|
|
1874
1558
|
* Sends a FHIR search request for a single resource.
|
|
@@ -1878,7 +1562,7 @@
|
|
|
1878
1562
|
* Example using a FHIR search string:
|
|
1879
1563
|
*
|
|
1880
1564
|
* ```typescript
|
|
1881
|
-
* const patient = await client.searchOne('Patient
|
|
1565
|
+
* const patient = await client.searchOne('Patient', 'identifier=123');
|
|
1882
1566
|
* console.log(patient);
|
|
1883
1567
|
* ```
|
|
1884
1568
|
*
|
|
@@ -1889,17 +1573,18 @@
|
|
|
1889
1573
|
* @param query The search query as either a string or a structured search object.
|
|
1890
1574
|
* @returns Promise to the search result bundle.
|
|
1891
1575
|
*/
|
|
1892
|
-
searchOne(query, options = {}) {
|
|
1893
|
-
const
|
|
1894
|
-
|
|
1895
|
-
|
|
1576
|
+
searchOne(resourceType, query, options = {}) {
|
|
1577
|
+
const url = this.fhirSearchUrl(resourceType, query);
|
|
1578
|
+
url.searchParams.set('_count', '1');
|
|
1579
|
+
url.searchParams.sort();
|
|
1580
|
+
const cacheKey = url.toString() + '-searchOne';
|
|
1896
1581
|
if (!(options === null || options === void 0 ? void 0 : options.cache)) {
|
|
1897
1582
|
const cached = __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").get(cacheKey);
|
|
1898
1583
|
if (cached) {
|
|
1899
1584
|
return cached;
|
|
1900
1585
|
}
|
|
1901
1586
|
}
|
|
1902
|
-
const promise = new ReadablePromise(this.search(
|
|
1587
|
+
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; }));
|
|
1903
1588
|
__classPrivateFieldGet(this, _MedplumClient_requestCache, "f").set(cacheKey, promise);
|
|
1904
1589
|
return promise;
|
|
1905
1590
|
}
|
|
@@ -1911,7 +1596,7 @@
|
|
|
1911
1596
|
* Example using a FHIR search string:
|
|
1912
1597
|
*
|
|
1913
1598
|
* ```typescript
|
|
1914
|
-
* const patients = await client.searchResources('Patient
|
|
1599
|
+
* const patients = await client.searchResources('Patient', 'name=Alice');
|
|
1915
1600
|
* console.log(patients);
|
|
1916
1601
|
* ```
|
|
1917
1602
|
*
|
|
@@ -1922,15 +1607,16 @@
|
|
|
1922
1607
|
* @param query The search query as either a string or a structured search object.
|
|
1923
1608
|
* @returns Promise to the search result bundle.
|
|
1924
1609
|
*/
|
|
1925
|
-
searchResources(query, options = {}) {
|
|
1926
|
-
const
|
|
1610
|
+
searchResources(resourceType, query, options = {}) {
|
|
1611
|
+
const url = this.fhirSearchUrl(resourceType, query);
|
|
1612
|
+
const cacheKey = url.toString() + '-searchResources';
|
|
1927
1613
|
if (!(options === null || options === void 0 ? void 0 : options.cache)) {
|
|
1928
1614
|
const cached = __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").get(cacheKey);
|
|
1929
1615
|
if (cached) {
|
|
1930
1616
|
return cached;
|
|
1931
1617
|
}
|
|
1932
1618
|
}
|
|
1933
|
-
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 : []; }));
|
|
1619
|
+
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 : []; }));
|
|
1934
1620
|
__classPrivateFieldGet(this, _MedplumClient_requestCache, "f").set(cacheKey, promise);
|
|
1935
1621
|
return promise;
|
|
1936
1622
|
}
|
|
@@ -2187,7 +1873,7 @@
|
|
|
2187
1873
|
createResourceIfNoneExist(resource, query) {
|
|
2188
1874
|
var _a;
|
|
2189
1875
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2190
|
-
return (_a = (yield this.searchOne(
|
|
1876
|
+
return ((_a = (yield this.searchOne(resource.resourceType, query))) !== null && _a !== void 0 ? _a : this.createResource(resource));
|
|
2191
1877
|
});
|
|
2192
1878
|
}
|
|
2193
1879
|
/**
|
|
@@ -2243,7 +1929,10 @@
|
|
|
2243
1929
|
*/
|
|
2244
1930
|
createPdf(docDefinition, filename, tableLayouts, fonts) {
|
|
2245
1931
|
return __awaiter(this, void 0, void 0, function* () {
|
|
2246
|
-
|
|
1932
|
+
if (!__classPrivateFieldGet(this, _MedplumClient_createPdf, "f")) {
|
|
1933
|
+
throw new Error('PDF creation not enabled');
|
|
1934
|
+
}
|
|
1935
|
+
const blob = yield __classPrivateFieldGet(this, _MedplumClient_createPdf, "f").call(this, docDefinition, tableLayouts, fonts);
|
|
2247
1936
|
return this.createBinary(blob, filename, 'application/pdf');
|
|
2248
1937
|
});
|
|
2249
1938
|
}
|
|
@@ -2506,7 +2195,7 @@
|
|
|
2506
2195
|
});
|
|
2507
2196
|
}
|
|
2508
2197
|
}
|
|
2509
|
-
_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) {
|
|
2198
|
+
_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) {
|
|
2510
2199
|
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); });
|
|
2511
2200
|
logins.push(newLogin);
|
|
2512
2201
|
__classPrivateFieldGet(this, _MedplumClient_storage, "f").setObject('logins', logins);
|
|
@@ -5335,6 +5024,206 @@
|
|
|
5335
5024
|
}
|
|
5336
5025
|
}
|
|
5337
5026
|
|
|
5027
|
+
const DEFAULT_SEARCH_COUNT = 20;
|
|
5028
|
+
/**
|
|
5029
|
+
* Search operators.
|
|
5030
|
+
* These operators represent "modifiers" and "prefixes" in FHIR search.
|
|
5031
|
+
* See: https://www.hl7.org/fhir/search.html
|
|
5032
|
+
*/
|
|
5033
|
+
exports.Operator = void 0;
|
|
5034
|
+
(function (Operator) {
|
|
5035
|
+
Operator["EQUALS"] = "eq";
|
|
5036
|
+
Operator["NOT_EQUALS"] = "ne";
|
|
5037
|
+
// Numbers
|
|
5038
|
+
Operator["GREATER_THAN"] = "gt";
|
|
5039
|
+
Operator["LESS_THAN"] = "lt";
|
|
5040
|
+
Operator["GREATER_THAN_OR_EQUALS"] = "ge";
|
|
5041
|
+
Operator["LESS_THAN_OR_EQUALS"] = "le";
|
|
5042
|
+
// Dates
|
|
5043
|
+
Operator["STARTS_AFTER"] = "sa";
|
|
5044
|
+
Operator["ENDS_BEFORE"] = "eb";
|
|
5045
|
+
Operator["APPROXIMATELY"] = "ap";
|
|
5046
|
+
// String
|
|
5047
|
+
Operator["CONTAINS"] = "contains";
|
|
5048
|
+
Operator["EXACT"] = "exact";
|
|
5049
|
+
// Token
|
|
5050
|
+
Operator["TEXT"] = "text";
|
|
5051
|
+
Operator["ABOVE"] = "above";
|
|
5052
|
+
Operator["BELOW"] = "below";
|
|
5053
|
+
Operator["IN"] = "in";
|
|
5054
|
+
Operator["NOT_IN"] = "not-in";
|
|
5055
|
+
Operator["OF_TYPE"] = "of-type";
|
|
5056
|
+
})(exports.Operator || (exports.Operator = {}));
|
|
5057
|
+
const MODIFIER_OPERATORS = [
|
|
5058
|
+
exports.Operator.CONTAINS,
|
|
5059
|
+
exports.Operator.EXACT,
|
|
5060
|
+
exports.Operator.TEXT,
|
|
5061
|
+
exports.Operator.ABOVE,
|
|
5062
|
+
exports.Operator.BELOW,
|
|
5063
|
+
exports.Operator.IN,
|
|
5064
|
+
exports.Operator.NOT_IN,
|
|
5065
|
+
exports.Operator.OF_TYPE,
|
|
5066
|
+
];
|
|
5067
|
+
const PREFIX_OPERATORS = [
|
|
5068
|
+
exports.Operator.NOT_EQUALS,
|
|
5069
|
+
exports.Operator.GREATER_THAN,
|
|
5070
|
+
exports.Operator.LESS_THAN,
|
|
5071
|
+
exports.Operator.GREATER_THAN_OR_EQUALS,
|
|
5072
|
+
exports.Operator.LESS_THAN_OR_EQUALS,
|
|
5073
|
+
exports.Operator.STARTS_AFTER,
|
|
5074
|
+
exports.Operator.ENDS_BEFORE,
|
|
5075
|
+
exports.Operator.APPROXIMATELY,
|
|
5076
|
+
];
|
|
5077
|
+
/**
|
|
5078
|
+
* Parses a URL into a SearchRequest.
|
|
5079
|
+
*
|
|
5080
|
+
* See the FHIR search spec: http://hl7.org/fhir/r4/search.html
|
|
5081
|
+
*
|
|
5082
|
+
* @param url The URL to parse.
|
|
5083
|
+
* @returns Parsed search definition.
|
|
5084
|
+
*/
|
|
5085
|
+
function parseSearchDefinition(url) {
|
|
5086
|
+
const location = new URL(url, 'https://example.com/');
|
|
5087
|
+
const resourceType = location.pathname
|
|
5088
|
+
.replace(/(^\/)|(\/$)/g, '') // Remove leading and trailing slashes
|
|
5089
|
+
.split('/')
|
|
5090
|
+
.pop();
|
|
5091
|
+
const params = new URLSearchParams(location.search);
|
|
5092
|
+
let filters = undefined;
|
|
5093
|
+
let sortRules = undefined;
|
|
5094
|
+
let fields = undefined;
|
|
5095
|
+
let offset = undefined;
|
|
5096
|
+
let count = undefined;
|
|
5097
|
+
let total = undefined;
|
|
5098
|
+
params.forEach((value, key) => {
|
|
5099
|
+
if (key === '_fields') {
|
|
5100
|
+
fields = value.split(',');
|
|
5101
|
+
}
|
|
5102
|
+
else if (key === '_offset') {
|
|
5103
|
+
offset = parseInt(value);
|
|
5104
|
+
}
|
|
5105
|
+
else if (key === '_count') {
|
|
5106
|
+
count = parseInt(value);
|
|
5107
|
+
}
|
|
5108
|
+
else if (key === '_total') {
|
|
5109
|
+
total = value;
|
|
5110
|
+
}
|
|
5111
|
+
else if (key === '_sort') {
|
|
5112
|
+
sortRules = sortRules || [];
|
|
5113
|
+
sortRules.push(parseSortRule(value));
|
|
5114
|
+
}
|
|
5115
|
+
else {
|
|
5116
|
+
filters = filters || [];
|
|
5117
|
+
filters.push(parseSearchFilter(key, value));
|
|
5118
|
+
}
|
|
5119
|
+
});
|
|
5120
|
+
return {
|
|
5121
|
+
resourceType,
|
|
5122
|
+
filters,
|
|
5123
|
+
fields,
|
|
5124
|
+
offset,
|
|
5125
|
+
count,
|
|
5126
|
+
total,
|
|
5127
|
+
sortRules,
|
|
5128
|
+
};
|
|
5129
|
+
}
|
|
5130
|
+
/**
|
|
5131
|
+
* Parses a URL query parameter into a sort rule.
|
|
5132
|
+
*
|
|
5133
|
+
* By default, the sort rule is the field name.
|
|
5134
|
+
*
|
|
5135
|
+
* Sort rules can be reversed into descending order by prefixing the field name with a minus sign.
|
|
5136
|
+
*
|
|
5137
|
+
* See sorting: http://hl7.org/fhir/r4/search.html#_sort
|
|
5138
|
+
*
|
|
5139
|
+
* @param value The URL parameter value.
|
|
5140
|
+
* @returns The parsed sort rule.
|
|
5141
|
+
*/
|
|
5142
|
+
function parseSortRule(value) {
|
|
5143
|
+
if (value.startsWith('-')) {
|
|
5144
|
+
return { code: value.substring(1), descending: true };
|
|
5145
|
+
}
|
|
5146
|
+
else {
|
|
5147
|
+
return { code: value };
|
|
5148
|
+
}
|
|
5149
|
+
}
|
|
5150
|
+
/**
|
|
5151
|
+
* Parses a URL query parameter into a search filter.
|
|
5152
|
+
*
|
|
5153
|
+
* FHIR search filters can be specified as modifiers or prefixes.
|
|
5154
|
+
*
|
|
5155
|
+
* For string properties, modifiers are appended to the key, e.g. "name:contains=eve".
|
|
5156
|
+
*
|
|
5157
|
+
* For date and numeric properties, prefixes are prepended to the value, e.g. "birthdate=gt2000".
|
|
5158
|
+
*
|
|
5159
|
+
* See the FHIR search spec: http://hl7.org/fhir/r4/search.html
|
|
5160
|
+
*
|
|
5161
|
+
* @param key The URL parameter key.
|
|
5162
|
+
* @param value The URL parameter value.
|
|
5163
|
+
* @returns The parsed search filter.
|
|
5164
|
+
*/
|
|
5165
|
+
function parseSearchFilter(key, value) {
|
|
5166
|
+
let code = key;
|
|
5167
|
+
let operator = exports.Operator.EQUALS;
|
|
5168
|
+
for (const modifier of MODIFIER_OPERATORS) {
|
|
5169
|
+
const modifierIndex = code.indexOf(':' + modifier);
|
|
5170
|
+
if (modifierIndex !== -1) {
|
|
5171
|
+
operator = modifier;
|
|
5172
|
+
code = code.substring(0, modifierIndex);
|
|
5173
|
+
}
|
|
5174
|
+
}
|
|
5175
|
+
for (const prefix of PREFIX_OPERATORS) {
|
|
5176
|
+
if (value.match(new RegExp('^' + prefix + '\\d'))) {
|
|
5177
|
+
operator = prefix;
|
|
5178
|
+
value = value.substring(prefix.length);
|
|
5179
|
+
}
|
|
5180
|
+
}
|
|
5181
|
+
return { code, operator, value };
|
|
5182
|
+
}
|
|
5183
|
+
/**
|
|
5184
|
+
* Formats a search definition object into a query string.
|
|
5185
|
+
* Note: The return value does not include the resource type.
|
|
5186
|
+
* @param {!SearchRequest} definition The search definition.
|
|
5187
|
+
* @returns Formatted URL.
|
|
5188
|
+
*/
|
|
5189
|
+
function formatSearchQuery(definition) {
|
|
5190
|
+
const params = [];
|
|
5191
|
+
if (definition.fields) {
|
|
5192
|
+
params.push('_fields=' + definition.fields.join(','));
|
|
5193
|
+
}
|
|
5194
|
+
if (definition.filters) {
|
|
5195
|
+
definition.filters.forEach((filter) => params.push(formatFilter(filter)));
|
|
5196
|
+
}
|
|
5197
|
+
if (definition.sortRules && definition.sortRules.length > 0) {
|
|
5198
|
+
params.push(formatSortRules(definition.sortRules));
|
|
5199
|
+
}
|
|
5200
|
+
if (definition.offset !== undefined) {
|
|
5201
|
+
params.push('_offset=' + definition.offset);
|
|
5202
|
+
}
|
|
5203
|
+
if (definition.count !== undefined) {
|
|
5204
|
+
params.push('_count=' + definition.count);
|
|
5205
|
+
}
|
|
5206
|
+
if (definition.total !== undefined) {
|
|
5207
|
+
params.push('_total=' + definition.total);
|
|
5208
|
+
}
|
|
5209
|
+
if (params.length === 0) {
|
|
5210
|
+
return '';
|
|
5211
|
+
}
|
|
5212
|
+
params.sort();
|
|
5213
|
+
return '?' + params.join('&');
|
|
5214
|
+
}
|
|
5215
|
+
function formatFilter(filter) {
|
|
5216
|
+
const modifier = MODIFIER_OPERATORS.includes(filter.operator) ? ':' + filter.operator : '';
|
|
5217
|
+
const prefix = PREFIX_OPERATORS.includes(filter.operator) ? filter.operator : '';
|
|
5218
|
+
return `${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`;
|
|
5219
|
+
}
|
|
5220
|
+
function formatSortRules(sortRules) {
|
|
5221
|
+
if (!sortRules || sortRules.length === 0) {
|
|
5222
|
+
return '';
|
|
5223
|
+
}
|
|
5224
|
+
return '_sort=' + sortRules.map((sr) => (sr.descending ? '-' + sr.code : sr.code)).join(',');
|
|
5225
|
+
}
|
|
5226
|
+
|
|
5338
5227
|
exports.SearchParameterType = void 0;
|
|
5339
5228
|
(function (SearchParameterType) {
|
|
5340
5229
|
SearchParameterType["BOOLEAN"] = "BOOLEAN";
|