@medplum/core 0.5.1 → 0.9.1

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/dist/esm/index.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! *****************************************************************************
1
+ /******************************************************************************
2
2
  Copyright (c) Microsoft Corporation.
3
3
 
4
4
  Permission to use, copy, modify, and/or distribute this software for any
@@ -167,6 +167,7 @@ function isProfileResource(resource) {
167
167
  * @return Human friendly display string.
168
168
  */
169
169
  function getDisplayString(resource) {
170
+ var _a, _b;
170
171
  if (isProfileResource(resource)) {
171
172
  const profileName = getProfileResourceDisplayString(resource);
172
173
  if (profileName) {
@@ -179,6 +180,11 @@ function getDisplayString(resource) {
179
180
  return deviceName;
180
181
  }
181
182
  }
183
+ if (resource.resourceType === 'Observation') {
184
+ if ('code' in resource && ((_a = resource.code) === null || _a === void 0 ? void 0 : _a.text)) {
185
+ return (_b = resource.code) === null || _b === void 0 ? void 0 : _b.text;
186
+ }
187
+ }
182
188
  if (resource.resourceType === 'User') {
183
189
  if (resource.email) {
184
190
  return resource.email;
@@ -223,12 +229,25 @@ function getImageSrc(resource) {
223
229
  const photos = resource.photo;
224
230
  if (photos) {
225
231
  for (const photo of photos) {
226
- if (photo.url && photo.contentType && photo.contentType.startsWith('image/')) {
227
- return photo.url;
232
+ const url = getPhotoImageSrc(photo);
233
+ if (url) {
234
+ return url;
228
235
  }
229
236
  }
230
237
  }
231
238
  }
239
+ if (resource.resourceType === 'Bot' && resource.photo) {
240
+ const url = getPhotoImageSrc(resource.photo);
241
+ if (url) {
242
+ return url;
243
+ }
244
+ }
245
+ return undefined;
246
+ }
247
+ function getPhotoImageSrc(photo) {
248
+ if (photo.url && photo.contentType && photo.contentType.startsWith('image/')) {
249
+ return photo.url;
250
+ }
232
251
  return undefined;
233
252
  }
234
253
  /**
@@ -241,6 +260,96 @@ function getImageSrc(resource) {
241
260
  function getDateProperty(date) {
242
261
  return date ? new Date(date) : undefined;
243
262
  }
263
+ /**
264
+ * Calculates the age in years from the birth date.
265
+ * @param birthDateStr The birth date or start date in ISO-8601 format YYYY-MM-DD.
266
+ * @param endDateStr Optional end date in ISO-8601 format YYYY-MM-DD. Default value is today.
267
+ * @returns The age in years, months, and days.
268
+ */
269
+ function calculateAge(birthDateStr, endDateStr) {
270
+ const startDate = new Date(birthDateStr);
271
+ startDate.setUTCHours(0, 0, 0, 0);
272
+ const endDate = endDateStr ? new Date(endDateStr) : new Date();
273
+ endDate.setUTCHours(0, 0, 0, 0);
274
+ const startYear = startDate.getUTCFullYear();
275
+ const startMonth = startDate.getUTCMonth();
276
+ const startDay = startDate.getUTCDate();
277
+ const endYear = endDate.getUTCFullYear();
278
+ const endMonth = endDate.getUTCMonth();
279
+ const endDay = endDate.getUTCDate();
280
+ let years = endYear - startYear;
281
+ if (endMonth < startMonth || (endMonth === startMonth && endDay < startDay)) {
282
+ years--;
283
+ }
284
+ let months = endYear * 12 + endMonth - (startYear * 12 + startMonth);
285
+ if (endDay < startDay) {
286
+ months--;
287
+ }
288
+ const days = Math.floor((endDate.getTime() - startDate.getTime()) / (1000 * 60 * 60 * 24));
289
+ return { years, months, days };
290
+ }
291
+ /**
292
+ * Calculates the age string for display using the age appropriate units.
293
+ * If the age is greater than or equal to 2 years, then the age is displayed in years.
294
+ * If the age is greater than or equal to 1 month, then the age is displayed in months.
295
+ * Otherwise, the age is displayed in days.
296
+ * @param birthDateStr The birth date or start date in ISO-8601 format YYYY-MM-DD.
297
+ * @param endDateStr Optional end date in ISO-8601 format YYYY-MM-DD. Default value is today.
298
+ * @returns The age string.
299
+ */
300
+ function calculateAgeString(birthDateStr, endDateStr) {
301
+ const { years, months, days } = calculateAge(birthDateStr, endDateStr);
302
+ if (years >= 2) {
303
+ return years.toString().padStart(3, '0') + 'Y';
304
+ }
305
+ else if (months >= 1) {
306
+ return months.toString().padStart(3, '0') + 'M';
307
+ }
308
+ else {
309
+ return days.toString().padStart(3, '0') + 'D';
310
+ }
311
+ }
312
+ /**
313
+ * Returns all questionnaire answers as a map by link ID.
314
+ * @param response The questionnaire response resource.
315
+ * @returns Questionnaire answers mapped by link ID.
316
+ */
317
+ function getQuestionnaireAnswers(response) {
318
+ const result = {};
319
+ buildQuestionnaireAnswerItems(response.item, result);
320
+ return result;
321
+ }
322
+ /**
323
+ * Recursively builds the questionnaire answer items map.
324
+ * @param item The current questionnaire response item.
325
+ * @param result The cumulative result map.
326
+ */
327
+ function buildQuestionnaireAnswerItems(items, result) {
328
+ if (items) {
329
+ for (const item of items) {
330
+ if (item.linkId && item.answer && item.answer.length > 0) {
331
+ result[item.linkId] = item.answer[0];
332
+ }
333
+ buildQuestionnaireAnswerItems(item.item, result);
334
+ }
335
+ }
336
+ }
337
+ /**
338
+ * Returns an extension value by extension URLs.
339
+ * @param resource The base resource.
340
+ * @param urls Array of extension URLs. Each entry represents a nested extension.
341
+ * @returns The extension value if found; undefined otherwise.
342
+ */
343
+ function getExtensionValue(resource, ...urls) {
344
+ var _a;
345
+ // Let curr be the current resource or extension. Extensions can be nested.
346
+ let curr = resource;
347
+ // For each of the urls, try to find a matching nested extension.
348
+ for (let i = 0; i < urls.length && curr; i++) {
349
+ curr = (_a = curr === null || curr === void 0 ? void 0 : curr.extension) === null || _a === void 0 ? void 0 : _a.find((e) => e.url === urls[i]);
350
+ }
351
+ return curr === null || curr === void 0 ? void 0 : curr.valueString;
352
+ }
244
353
  /**
245
354
  * FHIR JSON stringify.
246
355
  * Removes properties with empty string values.
@@ -261,7 +370,15 @@ function stringify(value, pretty) {
261
370
  * @param {*} v Property value.
262
371
  */
263
372
  function stringifyReplacer(k, v) {
264
- return isEmpty(v) ? undefined : v;
373
+ return !isArrayKey(k) && isEmpty(v) ? undefined : v;
374
+ }
375
+ /**
376
+ * Returns true if the key is an array key.
377
+ * @param k The property key.
378
+ * @returns True if the key is an array key.
379
+ */
380
+ function isArrayKey(k) {
381
+ return !!k.match(/\d+$/);
265
382
  }
266
383
  /**
267
384
  * Returns true if the value is empty (null, undefined, empty string, or empty object).
@@ -309,8 +426,21 @@ function deepEquals(object1, object2, path) {
309
426
  }
310
427
  return true;
311
428
  }
312
- function isObject(object) {
313
- return object !== null && typeof object === 'object';
429
+ /**
430
+ * Returns true if the input is an object.
431
+ * @param object The candidate object.
432
+ * @returns True if the input is a non-null non-undefined object.
433
+ */
434
+ function isObject(obj) {
435
+ return obj !== null && typeof obj === 'object';
436
+ }
437
+ /**
438
+ * Returns true if the input array is an array of strings.
439
+ * @param arr Input array.
440
+ * @returns True if the input array is an array of strings.
441
+ */
442
+ function isStringArray(arr) {
443
+ return arr.every((e) => typeof e === 'string');
314
444
  }
315
445
  // Precompute hex octets
316
446
  // See: https://stackoverflow.com/a/55200387
@@ -414,7 +544,7 @@ _EventTarget_listeners = new WeakMap();
414
544
  */
415
545
  function decodePayload(payload) {
416
546
  const cleanedPayload = payload.replace(/-/g, '+').replace(/_/g, '/');
417
- const decodedPayload = window.atob(cleanedPayload);
547
+ const decodedPayload = decodeBase64(cleanedPayload);
418
548
  const uriEncodedPayload = Array.from(decodedPayload).reduce((acc, char) => {
419
549
  const uriEncodedChar = ('00' + char.charCodeAt(0).toString(16)).slice(-2);
420
550
  return `${acc}%${uriEncodedChar}`;
@@ -422,6 +552,15 @@ function decodePayload(payload) {
422
552
  const jsonPayload = decodeURIComponent(uriEncodedPayload);
423
553
  return JSON.parse(jsonPayload);
424
554
  }
555
+ function decodeBase64(data) {
556
+ if (typeof window !== 'undefined') {
557
+ return window.atob(data);
558
+ }
559
+ if (typeof Buffer !== 'undefined') {
560
+ return Buffer.from(data, 'base64').toString('binary');
561
+ }
562
+ throw new Error('Unable to decode base64');
563
+ }
425
564
  /**
426
565
  * Parses the JWT payload.
427
566
  * @param token JWT token
@@ -634,10 +773,11 @@ const PREFIX_OPERATORS = [
634
773
  *
635
774
  * See the FHIR search spec: http://hl7.org/fhir/r4/search.html
636
775
  *
637
- * @param location The URL to parse.
776
+ * @param url The URL to parse.
638
777
  * @returns Parsed search definition.
639
778
  */
640
- function parseSearchDefinition(location) {
779
+ function parseSearchDefinition(url) {
780
+ const location = new URL(url, 'https://example.com/');
641
781
  const resourceType = location.pathname
642
782
  .replace(/(^\/)|(\/$)/g, '') // Remove leading and trailing slashes
643
783
  .split('/')
@@ -1066,13 +1206,61 @@ function getPropertyDisplayName(property) {
1066
1206
 
1067
1207
  // PKCE auth ased on:
1068
1208
  // https://aws.amazon.com/blogs/security/how-to-add-authentication-single-page-web-application-with-amazon-cognito-oauth2-implementation/
1069
- var _MedplumClient_instances, _MedplumClient_fetch, _MedplumClient_storage, _MedplumClient_schema, _MedplumClient_resourceCache, _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_buildFetchOptions, _MedplumClient_handleUnauthenticated, _MedplumClient_startPkce, _MedplumClient_requestAuthorization, _MedplumClient_refresh, _MedplumClient_fetchTokens, _MedplumClient_verifyTokens, _MedplumClient_setupStorageListener;
1209
+ var _MedplumClient_instances, _MedplumClient_fetch, _MedplumClient_storage, _MedplumClient_schema, _MedplumClient_resourceCache, _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;
1070
1210
  const DEFAULT_BASE_URL = 'https://api.medplum.com/';
1071
1211
  const DEFAULT_SCOPE = 'launch/patient openid fhirUser offline_access user/*.*';
1072
1212
  const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
1073
1213
  const JSON_CONTENT_TYPE = 'application/json';
1074
1214
  const FHIR_CONTENT_TYPE = 'application/fhir+json';
1075
1215
  const PATCH_CONTENT_TYPE = 'application/json-patch+json';
1216
+ /**
1217
+ * The MedplumClient class provides a client for the Medplum FHIR server.
1218
+ *
1219
+ * The client can be used in the browser, in a NodeJS application, or in a Medplum Bot.
1220
+ *
1221
+ * The client provides helpful methods for common operations such as:
1222
+ * 1) Authenticating
1223
+ * 2) Creating resources
1224
+ * 2) Reading resources
1225
+ * 3) Updating resources
1226
+ * 5) Deleting resources
1227
+ * 6) Searching
1228
+ * 7) Making GraphQL queries
1229
+ *
1230
+ * Here is a quick example of how to use the client:
1231
+ *
1232
+ * ```typescript
1233
+ * import { MedplumClient } from '@medplum/core';
1234
+ * const medplum = new MedplumClient();
1235
+ * ```
1236
+ *
1237
+ * Create a `Patient`:
1238
+ *
1239
+ * ```typescript
1240
+ * const patient = await medplum.createResource({
1241
+ * resourceType: 'Patient',
1242
+ * name: [{
1243
+ * given: ['Alice'],
1244
+ * family: 'Smith'
1245
+ * }]
1246
+ * });
1247
+ * ```
1248
+ *
1249
+ * Read a `Patient` by ID:
1250
+ *
1251
+ * ```typescript
1252
+ * const patient = await medplum.readResource('Patient', '123');
1253
+ * console.log(patient.name[0].given[0]);
1254
+ * ```
1255
+ *
1256
+ * Search for a `Patient` by name:
1257
+ *
1258
+ * ```typescript
1259
+ * const bundle = await medplum.search('Patient?name=Alice');
1260
+ * console.log(bundle.total);
1261
+ * ```
1262
+ *
1263
+ */
1076
1264
  class MedplumClient extends EventTarget {
1077
1265
  constructor(options) {
1078
1266
  var _a;
@@ -1132,17 +1320,94 @@ class MedplumClient extends EventTarget {
1132
1320
  __classPrivateFieldSet(this, _MedplumClient_config, undefined, "f");
1133
1321
  this.dispatchEvent({ type: 'change' });
1134
1322
  }
1135
- get(url) {
1136
- return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'GET', url);
1323
+ /**
1324
+ * Makes an HTTP GET request to the specified URL.
1325
+ *
1326
+ * This is a lower level method for custom requests.
1327
+ * For common operations, we recommend using higher level methods
1328
+ * such as `readResource()`, `search()`, etc.
1329
+ *
1330
+ * @param url The target URL.
1331
+ * @param options Optional fetch options.
1332
+ * @returns Promise to the response content.
1333
+ */
1334
+ get(url, options = {}) {
1335
+ return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'GET', url, options);
1137
1336
  }
1138
- post(url, body, contentType) {
1139
- return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'POST', url, contentType, body);
1337
+ /**
1338
+ * Makes an HTTP POST request to the specified URL.
1339
+ *
1340
+ * This is a lower level method for custom requests.
1341
+ * For common operations, we recommend using higher level methods
1342
+ * such as `createResource()`.
1343
+ *
1344
+ * @param url The target URL.
1345
+ * @param body The content body. Strings and `File` objects are passed directly. Other objects are converted to JSON.
1346
+ * @param contentType The content type to be included in the "Content-Type" header.
1347
+ * @param options Optional fetch options.
1348
+ * @returns Promise to the response content.
1349
+ */
1350
+ post(url, body, contentType, options = {}) {
1351
+ if (body) {
1352
+ __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_setRequestBody).call(this, options, body);
1353
+ }
1354
+ if (contentType) {
1355
+ __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_setRequestContentType).call(this, options, contentType);
1356
+ }
1357
+ return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'POST', url, options);
1140
1358
  }
1141
- put(url, body, contentType) {
1142
- return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'PUT', url, contentType, body);
1359
+ /**
1360
+ * Makes an HTTP PUT request to the specified URL.
1361
+ *
1362
+ * This is a lower level method for custom requests.
1363
+ * For common operations, we recommend using higher level methods
1364
+ * such as `updateResource()`.
1365
+ *
1366
+ * @param url The target URL.
1367
+ * @param body The content body. Strings and `File` objects are passed directly. Other objects are converted to JSON.
1368
+ * @param contentType The content type to be included in the "Content-Type" header.
1369
+ * @param options Optional fetch options.
1370
+ * @returns Promise to the response content.
1371
+ */
1372
+ put(url, body, contentType, options = {}) {
1373
+ if (body) {
1374
+ __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_setRequestBody).call(this, options, body);
1375
+ }
1376
+ if (contentType) {
1377
+ __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_setRequestContentType).call(this, options, contentType);
1378
+ }
1379
+ return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'PUT', url, options);
1143
1380
  }
1144
- delete(url) {
1145
- return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'DELETE', url);
1381
+ /**
1382
+ * Makes an HTTP PATCH request to the specified URL.
1383
+ *
1384
+ * This is a lower level method for custom requests.
1385
+ * For common operations, we recommend using higher level methods
1386
+ * such as `patchResource()`.
1387
+ *
1388
+ * @param url The target URL.
1389
+ * @param operations Array of JSONPatch operations.
1390
+ * @param options Optional fetch options.
1391
+ * @returns Promise to the response content.
1392
+ */
1393
+ patch(url, operations, options = {}) {
1394
+ __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_setRequestBody).call(this, options, operations);
1395
+ __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_setRequestContentType).call(this, options, PATCH_CONTENT_TYPE);
1396
+ return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'PATCH', url, options);
1397
+ }
1398
+ /**
1399
+ * Makes an HTTP DELETE request to the specified URL.
1400
+ *
1401
+ * This is a lower level method for custom requests.
1402
+ * For common operations, we recommend using higher level methods
1403
+ * such as `deleteResource()`.
1404
+ *
1405
+ * @param url The target URL.
1406
+ * @param options Optional fetch options.
1407
+ * @returns Promise to the response content.
1408
+ */
1409
+ delete(url, options = {}) {
1410
+ return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'DELETE', url, options);
1146
1411
  }
1147
1412
  /**
1148
1413
  * Tries to register a new user.
@@ -1233,11 +1498,114 @@ class MedplumClient extends EventTarget {
1233
1498
  }
1234
1499
  /**
1235
1500
  * Sends a FHIR search request.
1236
- * @param search The search query.
1501
+ *
1502
+ * Example using a FHIR search string:
1503
+ *
1504
+ * ```typescript
1505
+ * const bundle = await client.search('Patient?name=Alice');
1506
+ * console.log(bundle);
1507
+ * ```
1508
+ *
1509
+ * Example using a structured search:
1510
+ *
1511
+ * ```typescript
1512
+ * const bundle = await client.search({
1513
+ * resourceType: 'Patient',
1514
+ * filters: [{
1515
+ * code: 'name',
1516
+ * operator: 'eq',
1517
+ * value: 'Alice',
1518
+ * }]
1519
+ * });
1520
+ * console.log(bundle);
1521
+ * ```
1522
+ *
1523
+ * The return value is a FHIR bundle:
1524
+ *
1525
+ * ```json
1526
+ * {
1527
+ * "resourceType": "Bundle",
1528
+ * "type": "searchest",
1529
+ * "total": 1,
1530
+ * "entry": [
1531
+ * {
1532
+ * "resource": {
1533
+ * "resourceType": "Patient",
1534
+ * "name": [
1535
+ * {
1536
+ * "given": [
1537
+ * "George"
1538
+ * ],
1539
+ * "family": "Washington"
1540
+ * }
1541
+ * ],
1542
+ * }
1543
+ * }
1544
+ * ]
1545
+ * }
1546
+ * ```
1547
+ *
1548
+ * See FHIR search for full details: https://www.hl7.org/fhir/search.html
1549
+ *
1550
+ * @param query The search query as either a string or a structured search object.
1551
+ * @returns Promise to the search result bundle.
1552
+ */
1553
+ search(query, options = {}) {
1554
+ return this.get(typeof query === 'string' ? 'fhir/R4/' + query : this.fhirUrl(query.resourceType) + formatSearchQuery(query), options);
1555
+ }
1556
+ /**
1557
+ * Sends a FHIR search request for a single resource.
1558
+ *
1559
+ * This is a convenience method for `search()` that returns the first resource rather than a `Bundle`.
1560
+ *
1561
+ * Example using a FHIR search string:
1562
+ *
1563
+ * ```typescript
1564
+ * const patient = await client.searchOne('Patient?identifier=123');
1565
+ * console.log(patient);
1566
+ * ```
1567
+ *
1568
+ * The return value is the resource, if available; otherwise, undefined.
1569
+ *
1570
+ * See FHIR search for full details: https://www.hl7.org/fhir/search.html
1571
+ *
1572
+ * @param query The search query as either a string or a structured search object.
1237
1573
  * @returns Promise to the search result bundle.
1238
1574
  */
1239
- search(search) {
1240
- return this.get(this.fhirUrl(search.resourceType) + formatSearchQuery(search));
1575
+ searchOne(query, options = {}) {
1576
+ var _a, _b;
1577
+ return __awaiter(this, void 0, void 0, function* () {
1578
+ const search = typeof query === 'string' ? parseSearchDefinition(query) : query;
1579
+ search.count = 1;
1580
+ const bundle = yield this.search(search, options);
1581
+ return (_b = (_a = bundle.entry) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.resource;
1582
+ });
1583
+ }
1584
+ /**
1585
+ * Sends a FHIR search request for an array of resources.
1586
+ *
1587
+ * This is a convenience method for `search()` that returns the resources as an array rather than a `Bundle`.
1588
+ *
1589
+ * Example using a FHIR search string:
1590
+ *
1591
+ * ```typescript
1592
+ * const patients = await client.searchResources('Patient?name=Alice');
1593
+ * console.log(patients);
1594
+ * ```
1595
+ *
1596
+ * The return value is an array of resources.
1597
+ *
1598
+ * See FHIR search for full details: https://www.hl7.org/fhir/search.html
1599
+ *
1600
+ * @param query The search query as either a string or a structured search object.
1601
+ * @returns Promise to the search result bundle.
1602
+ */
1603
+ searchResources(query, options = {}) {
1604
+ var _a, _b;
1605
+ return __awaiter(this, void 0, void 0, function* () {
1606
+ const bundle = yield this.search(query, options);
1607
+ return (_b = (_a = bundle.entry) === null || _a === void 0 ? void 0 : _a.map((entry) => entry.resource)) !== null && _b !== void 0 ? _b : [];
1608
+ });
1241
1609
  }
1242
1610
  /**
1243
1611
  * Searches a ValueSet resource using the "expand" operation.
@@ -1246,10 +1614,10 @@ class MedplumClient extends EventTarget {
1246
1614
  * @param filter The search string.
1247
1615
  * @returns Promise to expanded ValueSet.
1248
1616
  */
1249
- searchValueSet(system, filter) {
1617
+ searchValueSet(system, filter, options = {}) {
1250
1618
  return this.get(this.fhirUrl('ValueSet', '$expand') +
1251
1619
  `?url=${encodeURIComponent(system)}` +
1252
- `&filter=${encodeURIComponent(filter)}`);
1620
+ `&filter=${encodeURIComponent(filter)}`, options);
1253
1621
  }
1254
1622
  /**
1255
1623
  * Returns a cached resource if it is available.
@@ -1277,7 +1645,23 @@ class MedplumClient extends EventTarget {
1277
1645
  }
1278
1646
  return undefined;
1279
1647
  }
1280
- read(resourceType, id) {
1648
+ /**
1649
+ * Reads a resource by resource type and ID.
1650
+ *
1651
+ * Example:
1652
+ *
1653
+ * ```typescript
1654
+ * const patient = await medplum.readResource('Patient', '123');
1655
+ * console.log(patient);
1656
+ * ```
1657
+ *
1658
+ * See the FHIR "read" operation for full details: https://www.hl7.org/fhir/http.html#read
1659
+ *
1660
+ * @param resourceType The FHIR resource type.
1661
+ * @param id The resource ID.
1662
+ * @returns The resource if available; undefined otherwise.
1663
+ */
1664
+ readResource(resourceType, id) {
1281
1665
  const cacheKey = resourceType + '/' + id;
1282
1666
  const promise = this.get(this.fhirUrl(resourceType, id)).then((resource) => {
1283
1667
  __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").set(cacheKey, resource);
@@ -1286,18 +1670,74 @@ class MedplumClient extends EventTarget {
1286
1670
  __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").set(cacheKey, promise);
1287
1671
  return promise;
1288
1672
  }
1673
+ /**
1674
+ * Reads a resource by resource type and ID using the in-memory resource cache.
1675
+ *
1676
+ * If the resource is not available in the cache, it will be read from the server.
1677
+ *
1678
+ * Example:
1679
+ *
1680
+ * ```typescript
1681
+ * const patient = await medplum.readCached('Patient', '123');
1682
+ * console.log(patient);
1683
+ * ```
1684
+ *
1685
+ * See the FHIR "read" operation for full details: https://www.hl7.org/fhir/http.html#read
1686
+ *
1687
+ * @param resourceType The FHIR resource type.
1688
+ * @param id The resource ID.
1689
+ * @returns The resource if available; undefined otherwise.
1690
+ */
1289
1691
  readCached(resourceType, id) {
1290
1692
  const cached = __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").get(resourceType + '/' + id);
1291
- return cached ? Promise.resolve(cached) : this.read(resourceType, id);
1693
+ return cached ? Promise.resolve(cached) : this.readResource(resourceType, id);
1292
1694
  }
1695
+ /**
1696
+ * Reads a resource by `Reference`.
1697
+ *
1698
+ * This is a convenience method for `readResource()` that accepts a `Reference` object.
1699
+ *
1700
+ * Example:
1701
+ *
1702
+ * ```typescript
1703
+ * const serviceRequest = await medplum.readResource('ServiceRequest', '123');
1704
+ * const patient = await medplum.readReference(serviceRequest.subject);
1705
+ * console.log(patient);
1706
+ * ```
1707
+ *
1708
+ * See the FHIR "read" operation for full details: https://www.hl7.org/fhir/http.html#read
1709
+ *
1710
+ * @param reference The FHIR reference object.
1711
+ * @returns The resource if available; undefined otherwise.
1712
+ */
1293
1713
  readReference(reference) {
1294
1714
  const refString = reference === null || reference === void 0 ? void 0 : reference.reference;
1295
1715
  if (!refString) {
1296
1716
  return Promise.reject('Missing reference');
1297
1717
  }
1298
1718
  const [resourceType, id] = refString.split('/');
1299
- return this.read(resourceType, id);
1719
+ return this.readResource(resourceType, id);
1300
1720
  }
1721
+ /**
1722
+ * Reads a resource by `Reference` using the in-memory resource cache.
1723
+ *
1724
+ * This is a convenience method for `readResource()` that accepts a `Reference` object.
1725
+ *
1726
+ * If the resource is not available in the cache, it will be read from the server.
1727
+ *
1728
+ * Example:
1729
+ *
1730
+ * ```typescript
1731
+ * const serviceRequest = await medplum.readResource('ServiceRequest', '123');
1732
+ * const patient = await medplum.readCachedReference(serviceRequest.subject);
1733
+ * console.log(patient);
1734
+ * ```
1735
+ *
1736
+ * See the FHIR "read" operation for full details: https://www.hl7.org/fhir/http.html#read
1737
+ *
1738
+ * @param reference The FHIR reference object.
1739
+ * @returns The resource if available; undefined otherwise.
1740
+ */
1301
1741
  readCachedReference(reference) {
1302
1742
  const refString = reference === null || reference === void 0 ? void 0 : reference.reference;
1303
1743
  if (!refString) {
@@ -1366,38 +1806,181 @@ class MedplumClient extends EventTarget {
1366
1806
  return __classPrivateFieldGet(this, _MedplumClient_schema, "f");
1367
1807
  });
1368
1808
  }
1809
+ /**
1810
+ * Reads resource history by resource type and ID.
1811
+ *
1812
+ * The return value is a bundle of all versions of the resource.
1813
+ *
1814
+ * Example:
1815
+ *
1816
+ * ```typescript
1817
+ * const history = await medplum.readHistory('Patient', '123');
1818
+ * console.log(history);
1819
+ * ```
1820
+ *
1821
+ * See the FHIR "history" operation for full details: https://www.hl7.org/fhir/http.html#history
1822
+ *
1823
+ * @param resourceType The FHIR resource type.
1824
+ * @param id The resource ID.
1825
+ * @returns The resource if available; undefined otherwise.
1826
+ */
1369
1827
  readHistory(resourceType, id) {
1370
1828
  return this.get(this.fhirUrl(resourceType, id, '_history'));
1371
1829
  }
1830
+ /**
1831
+ * Reads a specific version of a resource by resource type, ID, and version ID.
1832
+ *
1833
+ * Example:
1834
+ *
1835
+ * ```typescript
1836
+ * const version = await medplum.readVersion('Patient', '123', '456');
1837
+ * console.log(version);
1838
+ * ```
1839
+ *
1840
+ * See the FHIR "vread" operation for full details: https://www.hl7.org/fhir/http.html#vread
1841
+ *
1842
+ * @param resourceType The FHIR resource type.
1843
+ * @param id The resource ID.
1844
+ * @returns The resource if available; undefined otherwise.
1845
+ */
1846
+ readVersion(resourceType, id, vid) {
1847
+ return this.get(this.fhirUrl(resourceType, id, '_history', vid));
1848
+ }
1372
1849
  readPatientEverything(id) {
1373
1850
  return this.get(this.fhirUrl('Patient', id, '$everything'));
1374
1851
  }
1375
- create(resource) {
1852
+ /**
1853
+ * Creates a new FHIR resource.
1854
+ *
1855
+ * The return value is the newly created resource, including the ID and meta.
1856
+ *
1857
+ * Example:
1858
+ *
1859
+ * ```typescript
1860
+ * const result = await medplum.createResource({
1861
+ * resourceType: 'Patient',
1862
+ * name: [{
1863
+ * family: 'Smith',
1864
+ * given: ['John']
1865
+ * }]
1866
+ * });
1867
+ * console.log(result.id);
1868
+ * ```
1869
+ *
1870
+ * See the FHIR "create" operation for full details: https://www.hl7.org/fhir/http.html#create
1871
+ *
1872
+ * @param resource The FHIR resource to create.
1873
+ * @returns The result of the create operation.
1874
+ */
1875
+ createResource(resource) {
1376
1876
  if (!resource.resourceType) {
1377
- throw new Error('Missing resourceType');
1877
+ return Promise.reject('Missing resourceType');
1378
1878
  }
1379
1879
  return this.post(this.fhirUrl(resource.resourceType), resource);
1380
1880
  }
1881
+ /**
1882
+ * Creates a FHIR `Binary` resource with the provided data content.
1883
+ *
1884
+ * The return value is the newly created resource, including the ID and meta.
1885
+ *
1886
+ * The `data` parameter can be a string or a `File` object.
1887
+ *
1888
+ * A `File` object often comes from a `<input type="file">` element.
1889
+ *
1890
+ * Example:
1891
+ *
1892
+ * ```typescript
1893
+ * const result = await medplum.createBinary(myFile, 'test.jpg', 'image/jpeg');
1894
+ * console.log(result.id);
1895
+ * ```
1896
+ *
1897
+ * See the FHIR "create" operation for full details: https://www.hl7.org/fhir/http.html#create
1898
+ *
1899
+ * @param resource The FHIR resource to create.
1900
+ * @returns The result of the create operation.
1901
+ */
1381
1902
  createBinary(data, filename, contentType) {
1382
1903
  return this.post(this.fhirUrl('Binary') + '?_filename=' + encodeURIComponent(filename), data, contentType);
1383
1904
  }
1384
- update(resource) {
1905
+ /**
1906
+ * Updates a FHIR resource.
1907
+ *
1908
+ * The return value is the updated resource, including the ID and meta.
1909
+ *
1910
+ * Example:
1911
+ *
1912
+ * ```typescript
1913
+ * const result = await medplum.updateResource({
1914
+ * resourceType: 'Patient',
1915
+ * id: '123',
1916
+ * name: [{
1917
+ * family: 'Smith',
1918
+ * given: ['John']
1919
+ * }]
1920
+ * });
1921
+ * console.log(result.meta.versionId);
1922
+ * ```
1923
+ *
1924
+ * See the FHIR "update" operation for full details: https://www.hl7.org/fhir/http.html#update
1925
+ *
1926
+ * @param resource The FHIR resource to update.
1927
+ * @returns The result of the update operation.
1928
+ */
1929
+ updateResource(resource) {
1385
1930
  if (!resource.resourceType) {
1386
- throw new Error('Missing resourceType');
1931
+ return Promise.reject('Missing resourceType');
1387
1932
  }
1388
1933
  if (!resource.id) {
1389
- throw new Error('Missing id');
1934
+ return Promise.reject('Missing id');
1390
1935
  }
1391
1936
  return this.put(this.fhirUrl(resource.resourceType, resource.id), resource);
1392
1937
  }
1393
- patch(resourceType, id, operations) {
1394
- return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'PATCH', this.fhirUrl(resourceType, id), PATCH_CONTENT_TYPE, operations);
1938
+ /**
1939
+ * Updates a FHIR resource using JSONPatch operations.
1940
+ *
1941
+ * The return value is the updated resource, including the ID and meta.
1942
+ *
1943
+ * Example:
1944
+ *
1945
+ * ```typescript
1946
+ * const result = await medplum.patchResource('Patient', '123', [
1947
+ * {op: 'replace', path: '/name/0/family', value: 'Smith'},
1948
+ * ]);
1949
+ * console.log(result.meta.versionId);
1950
+ * ```
1951
+ *
1952
+ * See the FHIR "update" operation for full details: https://www.hl7.org/fhir/http.html#patch
1953
+ *
1954
+ * See the JSONPatch specification for full details: https://tools.ietf.org/html/rfc6902
1955
+ *
1956
+ * @param resourceType The FHIR resource type.
1957
+ * @param id The resource ID.
1958
+ * @param operations The JSONPatch operations.
1959
+ * @returns The result of the patch operations.
1960
+ */
1961
+ patchResource(resourceType, id, operations) {
1962
+ return this.patch(this.fhirUrl(resourceType, id), operations);
1395
1963
  }
1964
+ /**
1965
+ * Deletes a FHIR resource by resource type and ID.
1966
+ *
1967
+ * Example:
1968
+ *
1969
+ * ```typescript
1970
+ * await medplum.deleteResource('Patient', '123');
1971
+ * ```
1972
+ *
1973
+ * See the FHIR "delete" operation for full details: https://www.hl7.org/fhir/http.html#delete
1974
+ *
1975
+ * @param resourceType The FHIR resource type.
1976
+ * @param id The resource ID.
1977
+ * @returns The result of the delete operation.
1978
+ */
1396
1979
  deleteResource(resourceType, id) {
1397
1980
  return this.delete(this.fhirUrl(resourceType, id));
1398
1981
  }
1399
- graphql(query) {
1400
- return this.post(this.fhirUrl('$graphql'), { query }, JSON_CONTENT_TYPE);
1982
+ graphql(query, options) {
1983
+ return this.post(this.fhirUrl('$graphql'), { query }, JSON_CONTENT_TYPE, options);
1401
1984
  }
1402
1985
  getActiveLogin() {
1403
1986
  return __classPrivateFieldGet(this, _MedplumClient_storage, "f").getObject('activeLogin');
@@ -1415,6 +1998,12 @@ class MedplumClient extends EventTarget {
1415
1998
  yield __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_refreshProfile).call(this);
1416
1999
  });
1417
2000
  }
2001
+ setAccessToken(accessToken) {
2002
+ __classPrivateFieldSet(this, _MedplumClient_accessToken, accessToken, "f");
2003
+ __classPrivateFieldSet(this, _MedplumClient_refreshToken, undefined, "f");
2004
+ __classPrivateFieldSet(this, _MedplumClient_profile, undefined, "f");
2005
+ __classPrivateFieldSet(this, _MedplumClient_config, undefined, "f");
2006
+ }
1418
2007
  getLogins() {
1419
2008
  var _a;
1420
2009
  return (_a = __classPrivateFieldGet(this, _MedplumClient_storage, "f").getObject('logins')) !== null && _a !== void 0 ? _a : [];
@@ -1441,12 +2030,12 @@ class MedplumClient extends EventTarget {
1441
2030
  * @param url The URL to request.
1442
2031
  * @returns Promise to the response body as a blob.
1443
2032
  */
1444
- download(url) {
2033
+ download(url, options = {}) {
1445
2034
  return __awaiter(this, void 0, void 0, function* () {
1446
2035
  if (__classPrivateFieldGet(this, _MedplumClient_refreshPromise, "f")) {
1447
2036
  yield __classPrivateFieldGet(this, _MedplumClient_refreshPromise, "f");
1448
2037
  }
1449
- const options = __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_buildFetchOptions).call(this, 'GET');
2038
+ __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_addFetchOptionsDefaults).call(this, options);
1450
2039
  const response = yield __classPrivateFieldGet(this, _MedplumClient_fetch, "f").call(this, url, options);
1451
2040
  return response.blob();
1452
2041
  });
@@ -1460,12 +2049,12 @@ class MedplumClient extends EventTarget {
1460
2049
  const pkceState = __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('pkceState');
1461
2050
  if (!pkceState) {
1462
2051
  this.clear();
1463
- throw new Error('Invalid PCKE state');
2052
+ return Promise.reject('Invalid PCKE state');
1464
2053
  }
1465
2054
  const codeVerifier = __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('codeVerifier');
1466
2055
  if (!codeVerifier) {
1467
2056
  this.clear();
1468
- throw new Error('Invalid PCKE code verifier');
2057
+ return Promise.reject('Invalid PCKE code verifier');
1469
2058
  }
1470
2059
  return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_fetchTokens).call(this, 'grant_type=authorization_code' +
1471
2060
  (__classPrivateFieldGet(this, _MedplumClient_clientId, "f") ? '&client_id=' + encodeURIComponent(__classPrivateFieldGet(this, _MedplumClient_clientId, "f")) : '') +
@@ -1476,6 +2065,15 @@ class MedplumClient extends EventTarget {
1476
2065
  '&code=' +
1477
2066
  encodeURIComponent(code));
1478
2067
  }
2068
+ clientCredentials(clientId, clientSecret) {
2069
+ return __awaiter(this, void 0, void 0, function* () {
2070
+ return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_fetchTokens).call(this, 'grant_type=client_credentials' +
2071
+ '&client_id=' +
2072
+ encodeURIComponent(clientId) +
2073
+ '&client_secret=' +
2074
+ encodeURIComponent(clientSecret));
2075
+ });
2076
+ }
1479
2077
  }
1480
2078
  _MedplumClient_fetch = new WeakMap(), _MedplumClient_storage = new WeakMap(), _MedplumClient_schema = new WeakMap(), _MedplumClient_resourceCache = 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) {
1481
2079
  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); });
@@ -1496,7 +2094,7 @@ _MedplumClient_fetch = new WeakMap(), _MedplumClient_storage = new WeakMap(), _M
1496
2094
  }), "f");
1497
2095
  return __classPrivateFieldGet(this, _MedplumClient_profilePromise, "f");
1498
2096
  });
1499
- }, _MedplumClient_request = function _MedplumClient_request(method, url, contentType, body) {
2097
+ }, _MedplumClient_request = function _MedplumClient_request(method, url, options = {}) {
1500
2098
  return __awaiter(this, void 0, void 0, function* () {
1501
2099
  if (__classPrivateFieldGet(this, _MedplumClient_refreshPromise, "f")) {
1502
2100
  yield __classPrivateFieldGet(this, _MedplumClient_refreshPromise, "f");
@@ -1504,11 +2102,12 @@ _MedplumClient_fetch = new WeakMap(), _MedplumClient_storage = new WeakMap(), _M
1504
2102
  if (!url.startsWith('http')) {
1505
2103
  url = __classPrivateFieldGet(this, _MedplumClient_baseUrl, "f") + url;
1506
2104
  }
1507
- const options = __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_buildFetchOptions).call(this, method, contentType, body);
2105
+ options.method = method;
2106
+ __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_addFetchOptionsDefaults).call(this, options);
1508
2107
  const response = yield __classPrivateFieldGet(this, _MedplumClient_fetch, "f").call(this, url, options);
1509
2108
  if (response.status === 401) {
1510
2109
  // Refresh and try again
1511
- return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_handleUnauthenticated).call(this, method, url, contentType, body);
2110
+ return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_handleUnauthenticated).call(this, method, url, options);
1512
2111
  }
1513
2112
  if (response.status === 204 || response.status === 304) {
1514
2113
  // No content or change
@@ -1520,32 +2119,40 @@ _MedplumClient_fetch = new WeakMap(), _MedplumClient_storage = new WeakMap(), _M
1520
2119
  }
1521
2120
  return obj;
1522
2121
  });
1523
- }, _MedplumClient_buildFetchOptions = function _MedplumClient_buildFetchOptions(method, contentType, body) {
1524
- const headers = {
1525
- 'Content-Type': contentType || FHIR_CONTENT_TYPE,
1526
- };
2122
+ }, _MedplumClient_addFetchOptionsDefaults = function _MedplumClient_addFetchOptionsDefaults(options) {
2123
+ if (!options.headers) {
2124
+ options.headers = {};
2125
+ }
2126
+ const headers = options.headers;
2127
+ if (!headers['Content-Type']) {
2128
+ headers['Content-Type'] = FHIR_CONTENT_TYPE;
2129
+ }
1527
2130
  if (__classPrivateFieldGet(this, _MedplumClient_accessToken, "f")) {
1528
2131
  headers['Authorization'] = 'Bearer ' + __classPrivateFieldGet(this, _MedplumClient_accessToken, "f");
1529
2132
  }
1530
- const options = {
1531
- method: method,
1532
- cache: 'no-cache',
1533
- credentials: 'include',
1534
- headers,
1535
- };
1536
- if (body) {
1537
- if (typeof body === 'string' || (typeof File !== 'undefined' && body instanceof File)) {
1538
- options.body = body;
1539
- }
1540
- else {
1541
- options.body = stringify(body);
1542
- }
2133
+ if (!options.cache) {
2134
+ options.cache = 'no-cache';
2135
+ }
2136
+ if (!options.credentials) {
2137
+ options.credentials = 'include';
2138
+ }
2139
+ }, _MedplumClient_setRequestContentType = function _MedplumClient_setRequestContentType(options, contentType) {
2140
+ if (!options.headers) {
2141
+ options.headers = {};
1543
2142
  }
1544
- return options;
1545
- }, _MedplumClient_handleUnauthenticated = function _MedplumClient_handleUnauthenticated(method, url, contentType, body) {
2143
+ const headers = options.headers;
2144
+ headers['Content-Type'] = contentType;
2145
+ }, _MedplumClient_setRequestBody = function _MedplumClient_setRequestBody(options, data) {
2146
+ if (typeof data === 'string' || (typeof File !== 'undefined' && data instanceof File)) {
2147
+ options.body = data;
2148
+ }
2149
+ else if (data) {
2150
+ options.body = stringify(data);
2151
+ }
2152
+ }, _MedplumClient_handleUnauthenticated = function _MedplumClient_handleUnauthenticated(method, url, options) {
1546
2153
  return __awaiter(this, void 0, void 0, function* () {
1547
2154
  return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_refresh).call(this)
1548
- .then(() => __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, method, url, contentType, body))
2155
+ .then(() => __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, method, url, options))
1549
2156
  .catch((error) => {
1550
2157
  this.clear();
1551
2158
  if (__classPrivateFieldGet(this, _MedplumClient_onUnauthenticated, "f")) {
@@ -1567,7 +2174,7 @@ _MedplumClient_fetch = new WeakMap(), _MedplumClient_storage = new WeakMap(), _M
1567
2174
  }, _MedplumClient_requestAuthorization = function _MedplumClient_requestAuthorization() {
1568
2175
  return __awaiter(this, void 0, void 0, function* () {
1569
2176
  if (!__classPrivateFieldGet(this, _MedplumClient_authorizeUrl, "f")) {
1570
- throw new Error('Missing authorize URL');
2177
+ return Promise.reject('Missing authorize URL');
1571
2178
  }
1572
2179
  __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_startPkce).call(this);
1573
2180
  window.location.assign(__classPrivateFieldGet(this, _MedplumClient_authorizeUrl, "f") +
@@ -1662,6 +2269,316 @@ function getBaseUrl() {
1662
2269
  return window.location.protocol + '//' + window.location.host + '/';
1663
2270
  }
1664
2271
 
2272
+ const SEGMENT_SEPARATOR = '\r';
2273
+ const FIELD_SEPARATOR = '|';
2274
+ const COMPONENT_SEPARATOR = '^';
2275
+ /**
2276
+ * The Hl7Message class represents one HL7 message.
2277
+ * A message is a collection of segments.
2278
+ * Note that we do not strictly parse messages, and only use default delimeters.
2279
+ */
2280
+ class Hl7Message {
2281
+ constructor(segments) {
2282
+ this.segments = segments;
2283
+ }
2284
+ get(index) {
2285
+ if (typeof index === 'number') {
2286
+ return this.segments[index];
2287
+ }
2288
+ return this.segments.find((s) => s.name === index);
2289
+ }
2290
+ getAll(name) {
2291
+ return this.segments.filter((s) => s.name === name);
2292
+ }
2293
+ toString() {
2294
+ return this.segments.map((s) => s.toString()).join(SEGMENT_SEPARATOR);
2295
+ }
2296
+ buildAck() {
2297
+ var _a, _b, _c, _d, _e, _f;
2298
+ const now = new Date();
2299
+ const msh = this.get('MSH');
2300
+ const sendingApp = ((_a = msh === null || msh === void 0 ? void 0 : msh.get(2)) === null || _a === void 0 ? void 0 : _a.toString()) || '';
2301
+ const sendingFacility = ((_b = msh === null || msh === void 0 ? void 0 : msh.get(3)) === null || _b === void 0 ? void 0 : _b.toString()) || '';
2302
+ const receivingApp = ((_c = msh === null || msh === void 0 ? void 0 : msh.get(4)) === null || _c === void 0 ? void 0 : _c.toString()) || '';
2303
+ const receivingFacility = ((_d = msh === null || msh === void 0 ? void 0 : msh.get(5)) === null || _d === void 0 ? void 0 : _d.toString()) || '';
2304
+ const controlId = ((_e = msh === null || msh === void 0 ? void 0 : msh.get(9)) === null || _e === void 0 ? void 0 : _e.toString()) || '';
2305
+ const versionId = ((_f = msh === null || msh === void 0 ? void 0 : msh.get(12)) === null || _f === void 0 ? void 0 : _f.toString()) || '2.5.1';
2306
+ return new Hl7Message([
2307
+ new Hl7Segment([
2308
+ 'MSH',
2309
+ '^~\\&',
2310
+ receivingApp,
2311
+ receivingFacility,
2312
+ sendingApp,
2313
+ sendingFacility,
2314
+ now.toISOString(),
2315
+ '',
2316
+ 'ACK',
2317
+ now.getTime().toString(),
2318
+ 'P',
2319
+ versionId,
2320
+ ]),
2321
+ new Hl7Segment(['MSA', 'AA', controlId, 'OK']),
2322
+ ]);
2323
+ }
2324
+ static parse(text) {
2325
+ if (!text.startsWith('MSH|^~\\&')) {
2326
+ const err = new Error('Invalid HL7 message');
2327
+ err.type = 'entity.parse.failed';
2328
+ throw err;
2329
+ }
2330
+ return new Hl7Message(text.split(/[\r\n]+/).map((line) => Hl7Segment.parse(line)));
2331
+ }
2332
+ }
2333
+ /**
2334
+ * The Hl7Segment class represents one HL7 segment.
2335
+ * A segment is a collection of fields.
2336
+ * The name field is the first field.
2337
+ * Note that we do not strictly parse messages, and only use default delimeters.
2338
+ */
2339
+ class Hl7Segment {
2340
+ constructor(fields) {
2341
+ if (isStringArray(fields)) {
2342
+ this.fields = fields.map((f) => Hl7Field.parse(f));
2343
+ }
2344
+ else {
2345
+ this.fields = fields;
2346
+ }
2347
+ this.name = this.fields[0].components[0];
2348
+ }
2349
+ get(index) {
2350
+ return this.fields[index];
2351
+ }
2352
+ toString() {
2353
+ return this.fields.map((f) => f.toString()).join(FIELD_SEPARATOR);
2354
+ }
2355
+ static parse(text) {
2356
+ return new Hl7Segment(text.split(FIELD_SEPARATOR).map((f) => Hl7Field.parse(f)));
2357
+ }
2358
+ }
2359
+ /**
2360
+ * The Hl7Field class represents one HL7 field.
2361
+ * A field is a collection of components.
2362
+ * Note that we do not strictly parse messages, and only use default delimeters.
2363
+ */
2364
+ class Hl7Field {
2365
+ constructor(components) {
2366
+ this.components = components;
2367
+ }
2368
+ get(index) {
2369
+ return this.components[index];
2370
+ }
2371
+ toString() {
2372
+ return this.components.join(COMPONENT_SEPARATOR);
2373
+ }
2374
+ static parse(text) {
2375
+ return new Hl7Field(text.split(COMPONENT_SEPARATOR));
2376
+ }
2377
+ }
2378
+
2379
+ var _LegacyRepositoryClient_client;
2380
+ /**
2381
+ * The LegacyRepositoryClient is a supplementary API client that matches the legacy "Repository" API.
2382
+ * The "Repository" API is deprecated and will be removed in a future release.
2383
+ * This LegacyRepositoryClient is also deprecated and will be removed in a future release.
2384
+ * @deprecated
2385
+ */
2386
+ class LegacyRepositoryClient {
2387
+ constructor(client) {
2388
+ _LegacyRepositoryClient_client.set(this, void 0);
2389
+ __classPrivateFieldSet(this, _LegacyRepositoryClient_client, client, "f");
2390
+ }
2391
+ /**
2392
+ * Creates a resource.
2393
+ *
2394
+ * See: https://www.hl7.org/fhir/http.html#create
2395
+ *
2396
+ * @param resource The resource to create.
2397
+ * @returns Operation outcome and the new resource.
2398
+ * @deprecated
2399
+ */
2400
+ createResource(resource) {
2401
+ return __awaiter(this, void 0, void 0, function* () {
2402
+ try {
2403
+ const result = yield __classPrivateFieldGet(this, _LegacyRepositoryClient_client, "f").createResource(resource);
2404
+ return [created, result];
2405
+ }
2406
+ catch (error) {
2407
+ return [error, undefined];
2408
+ }
2409
+ });
2410
+ }
2411
+ /**
2412
+ * Returns a resource.
2413
+ *
2414
+ * See: https://www.hl7.org/fhir/http.html#read
2415
+ *
2416
+ * @param resourceType The FHIR resource type.
2417
+ * @param id The FHIR resource ID.
2418
+ * @returns Operation outcome and a resource.
2419
+ * @deprecated
2420
+ */
2421
+ readResource(resourceType, id) {
2422
+ return __awaiter(this, void 0, void 0, function* () {
2423
+ try {
2424
+ const resource = yield __classPrivateFieldGet(this, _LegacyRepositoryClient_client, "f").readResource(resourceType, id);
2425
+ return [allOk, resource];
2426
+ }
2427
+ catch (error) {
2428
+ return [error, undefined];
2429
+ }
2430
+ });
2431
+ }
2432
+ /**
2433
+ * Returns a resource by FHIR reference.
2434
+ *
2435
+ * See: https://www.hl7.org/fhir/http.html#read
2436
+ *
2437
+ * @param reference The FHIR reference.
2438
+ * @returns Operation outcome and a resource.
2439
+ * @deprecated
2440
+ */
2441
+ readReference(reference) {
2442
+ return __awaiter(this, void 0, void 0, function* () {
2443
+ try {
2444
+ const resource = yield __classPrivateFieldGet(this, _LegacyRepositoryClient_client, "f").readReference(reference);
2445
+ return [allOk, resource];
2446
+ }
2447
+ catch (error) {
2448
+ return [error, undefined];
2449
+ }
2450
+ });
2451
+ }
2452
+ /**
2453
+ * Returns resource history.
2454
+ *
2455
+ * See: https://www.hl7.org/fhir/http.html#history
2456
+ *
2457
+ * @param resourceType The FHIR resource type.
2458
+ * @param id The FHIR resource ID.
2459
+ * @returns Operation outcome and a history bundle.
2460
+ * @deprecated
2461
+ */
2462
+ readHistory(resourceType, id) {
2463
+ return __awaiter(this, void 0, void 0, function* () {
2464
+ try {
2465
+ const resource = yield __classPrivateFieldGet(this, _LegacyRepositoryClient_client, "f").readHistory(resourceType, id);
2466
+ return [allOk, resource];
2467
+ }
2468
+ catch (error) {
2469
+ return [error, undefined];
2470
+ }
2471
+ });
2472
+ }
2473
+ /**
2474
+ * Returns a resource version.
2475
+ *
2476
+ * See: https://www.hl7.org/fhir/http.html#vread
2477
+ *
2478
+ * @param resourceType The FHIR resource type.
2479
+ * @param id The FHIR resource ID.
2480
+ * @param vid The version ID.
2481
+ * @returns Operation outcome and a resource.
2482
+ * @deprecated
2483
+ */
2484
+ readVersion(resourceType, id, vid) {
2485
+ return __awaiter(this, void 0, void 0, function* () {
2486
+ try {
2487
+ const resource = yield __classPrivateFieldGet(this, _LegacyRepositoryClient_client, "f").readVersion(resourceType, id, vid);
2488
+ return [allOk, resource];
2489
+ }
2490
+ catch (error) {
2491
+ return [error, undefined];
2492
+ }
2493
+ });
2494
+ }
2495
+ /**
2496
+ * Updates a resource.
2497
+ *
2498
+ * See: https://www.hl7.org/fhir/http.html#update
2499
+ *
2500
+ * @param resource The resource to update.
2501
+ * @returns Operation outcome and the updated resource.
2502
+ * @deprecated
2503
+ */
2504
+ updateResource(resource) {
2505
+ return __awaiter(this, void 0, void 0, function* () {
2506
+ try {
2507
+ const updated = yield __classPrivateFieldGet(this, _LegacyRepositoryClient_client, "f").updateResource(resource);
2508
+ return [allOk, updated];
2509
+ }
2510
+ catch (error) {
2511
+ return [error, undefined];
2512
+ }
2513
+ });
2514
+ }
2515
+ /**
2516
+ * Deletes a resource.
2517
+ *
2518
+ * See: https://www.hl7.org/fhir/http.html#delete
2519
+ *
2520
+ * @param resourceType The FHIR resource type.
2521
+ * @param id The resource ID.
2522
+ * @returns Operation outcome.
2523
+ * @deprecated
2524
+ */
2525
+ deleteResource(resourceType, id) {
2526
+ return __awaiter(this, void 0, void 0, function* () {
2527
+ try {
2528
+ yield __classPrivateFieldGet(this, _LegacyRepositoryClient_client, "f").deleteResource(resourceType, id);
2529
+ return [allOk, undefined];
2530
+ }
2531
+ catch (error) {
2532
+ return [error, undefined];
2533
+ }
2534
+ });
2535
+ }
2536
+ /**
2537
+ * Patches a resource.
2538
+ *
2539
+ * See: https://www.hl7.org/fhir/http.html#patch
2540
+ *
2541
+ * @param resourceType The FHIR resource type.
2542
+ * @param id The resource ID.
2543
+ * @param patch Array of JSONPatch operations.
2544
+ * @returns Operation outcome and the resource.
2545
+ * @deprecated
2546
+ */
2547
+ patchResource(resourceType, id, patch) {
2548
+ return __awaiter(this, void 0, void 0, function* () {
2549
+ try {
2550
+ const resource = yield __classPrivateFieldGet(this, _LegacyRepositoryClient_client, "f").patchResource(resourceType, id, patch);
2551
+ return [allOk, resource];
2552
+ }
2553
+ catch (error) {
2554
+ return [error, undefined];
2555
+ }
2556
+ });
2557
+ }
2558
+ /**
2559
+ * Searches for resources.
2560
+ *
2561
+ * See: https://www.hl7.org/fhir/http.html#search
2562
+ *
2563
+ * @param searchRequest The search request.
2564
+ * @returns The search result bundle.
2565
+ * @deprecated
2566
+ */
2567
+ search(query) {
2568
+ return __awaiter(this, void 0, void 0, function* () {
2569
+ const searchRequest = typeof query === 'string' ? parseSearchDefinition(query) : query;
2570
+ try {
2571
+ const bundle = yield __classPrivateFieldGet(this, _LegacyRepositoryClient_client, "f").search(searchRequest);
2572
+ return [allOk, bundle];
2573
+ }
2574
+ catch (error) {
2575
+ return [error, undefined];
2576
+ }
2577
+ });
2578
+ }
2579
+ }
2580
+ _LegacyRepositoryClient_client = new WeakMap();
2581
+
1665
2582
  var SearchParameterType;
1666
2583
  (function (SearchParameterType) {
1667
2584
  SearchParameterType["BOOLEAN"] = "BOOLEAN";
@@ -1788,5 +2705,5 @@ function simplifyExpression(input) {
1788
2705
  return result;
1789
2706
  }
1790
2707
 
1791
- export { MedplumClient, OperationOutcomeError, Operator, PropertyType, SearchParameterType, accessDenied, allOk, arrayBufferToBase64, arrayBufferToHex, assertOk, badRequest, buildTypeName, capitalize, createReference, createSchema, createTypeSchema, created, deepEquals, formatAddress, formatFamilyName, formatGivenName, formatHumanName, formatSearchQuery, getDateProperty, getDisplayString, getExpressionForResourceType, getImageSrc, getPropertyDisplayName, getReferenceString, getSearchParameterDetails, getStatus, gone, indexSearchParameter, indexStructureDefinition, isGone, isLowerCase, isNotFound, isOk, isProfileResource, notFound, notModified, parseSearchDefinition, resolveId, stringify };
2708
+ export { COMPONENT_SEPARATOR, FIELD_SEPARATOR, Hl7Field, Hl7Message, Hl7Segment, LegacyRepositoryClient, MedplumClient, OperationOutcomeError, Operator, PropertyType, SEGMENT_SEPARATOR, SearchParameterType, accessDenied, allOk, arrayBufferToBase64, arrayBufferToHex, assertOk, badRequest, buildTypeName, calculateAge, calculateAgeString, capitalize, createReference, createSchema, createTypeSchema, created, deepEquals, formatAddress, formatFamilyName, formatGivenName, formatHumanName, formatSearchQuery, getDateProperty, getDisplayString, getExpressionForResourceType, getExtensionValue, getImageSrc, getPropertyDisplayName, getQuestionnaireAnswers, getReferenceString, getSearchParameterDetails, getStatus, gone, indexSearchParameter, indexStructureDefinition, isGone, isLowerCase, isNotFound, isObject, isOk, isProfileResource, isStringArray, notFound, notModified, parseSearchDefinition, resolveId, stringify };
1792
2709
  //# sourceMappingURL=index.js.map