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