@medplum/core 0.9.1 → 0.9.4

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
@@ -75,6 +75,9 @@
75
75
  }
76
76
  __classPrivateFieldGet(this, _LRUCache_cache, "f").set(key, val);
77
77
  }
78
+ delete(key) {
79
+ __classPrivateFieldGet(this, _LRUCache_cache, "f").delete(key);
80
+ }
78
81
  }
79
82
  _LRUCache_max = new WeakMap(), _LRUCache_cache = new WeakMap(), _LRUCache_instances = new WeakSet(), _LRUCache_first = function _LRUCache_first() {
80
83
  // This works because the Map class maintains ordered keys.
@@ -401,37 +404,71 @@
401
404
  /**
402
405
  * Resource equality.
403
406
  * Ignores meta.versionId and meta.lastUpdated.
404
- * See: https://dmitripavlutin.com/how-to-compare-objects-in-javascript/#4-deep-equality
405
407
  * @param object1 The first object.
406
408
  * @param object2 The second object.
407
409
  * @returns True if the objects are equal.
408
410
  */
409
411
  function deepEquals(object1, object2, path) {
410
- let keys1 = Object.keys(object1);
411
- let keys2 = Object.keys(object2);
412
- if (path === 'meta') {
413
- keys1 = keys1.filter((k) => k !== 'versionId' && k !== 'lastUpdated' && k !== 'author');
414
- keys2 = keys2.filter((k) => k !== 'versionId' && k !== 'lastUpdated' && k !== 'author');
412
+ if (object1 === object2) {
413
+ return true;
414
+ }
415
+ if (isEmpty(object1) && isEmpty(object2)) {
416
+ return true;
417
+ }
418
+ if (isEmpty(object1) || isEmpty(object2)) {
419
+ return false;
420
+ }
421
+ if (Array.isArray(object1) && Array.isArray(object2)) {
422
+ return deepEqualsArray(object1, object2);
423
+ }
424
+ if (Array.isArray(object1) || Array.isArray(object2)) {
425
+ return false;
426
+ }
427
+ if (isObject(object1) && isObject(object2)) {
428
+ return deepEqualsObject(object1, object2, path);
429
+ }
430
+ if (isObject(object1) || isObject(object2)) {
431
+ return false;
415
432
  }
416
- if (keys1.length !== keys2.length) {
433
+ return false;
434
+ }
435
+ function deepEqualsArray(array1, array2) {
436
+ if (array1.length !== array2.length) {
417
437
  return false;
418
438
  }
419
- for (const key of keys1) {
439
+ for (let i = 0; i < array1.length; i++) {
440
+ if (!deepEquals(array1[i], array2[i])) {
441
+ return false;
442
+ }
443
+ }
444
+ return true;
445
+ }
446
+ function deepEqualsObject(object1, object2, path) {
447
+ const keySet = new Set();
448
+ Object.keys(object1).forEach((k) => keySet.add(k));
449
+ Object.keys(object2).forEach((k) => keySet.add(k));
450
+ if (path === 'meta') {
451
+ keySet.delete('versionId');
452
+ keySet.delete('lastUpdated');
453
+ keySet.delete('author');
454
+ }
455
+ for (const key of keySet) {
420
456
  const val1 = object1[key];
421
457
  const val2 = object2[key];
422
- if (isObject(val1) && isObject(val2)) {
423
- if (!deepEquals(val1, val2, key)) {
424
- return false;
425
- }
426
- }
427
- else {
428
- if (val1 !== val2) {
429
- return false;
430
- }
458
+ if (!deepEquals(val1, val2, key)) {
459
+ return false;
431
460
  }
432
461
  }
433
462
  return true;
434
463
  }
464
+ /**
465
+ * Returns true if the input string is a UUID.
466
+ * @param input The input string.
467
+ * @returns True if the input string matches the UUID format.
468
+ */
469
+ function isUUID(input) {
470
+ return !!input.match(/^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$/i);
471
+ }
435
472
  /**
436
473
  * Returns true if the input is an object.
437
474
  * @param object The candidate object.
@@ -482,7 +519,7 @@
482
519
  return window.btoa(result.join(''));
483
520
  }
484
521
  function capitalize(word) {
485
- return word.charAt(0).toUpperCase() + word.substr(1);
522
+ return word.charAt(0).toUpperCase() + word.substring(1);
486
523
  }
487
524
  function isLowerCase(c) {
488
525
  return c === c.toLowerCase();
@@ -725,6 +762,83 @@
725
762
  }
726
763
  }
727
764
 
765
+ var _ReadablePromise_suspender, _ReadablePromise_status, _ReadablePromise_response, _ReadablePromise_error, _a;
766
+ /**
767
+ * The ReadablePromise class wraps a request promise suitable for React Suspense.
768
+ * See: https://blog.logrocket.com/react-suspense-data-fetching/#wrappromise-js
769
+ * See: https://github.com/ovieokeh/suspense-data-fetching/blob/master/lib/api/wrapPromise.js
770
+ */
771
+ class ReadablePromise {
772
+ constructor(requestPromise) {
773
+ this[_a] = 'ReadablePromise';
774
+ _ReadablePromise_suspender.set(this, void 0);
775
+ _ReadablePromise_status.set(this, 'pending');
776
+ _ReadablePromise_response.set(this, void 0);
777
+ _ReadablePromise_error.set(this, void 0);
778
+ __classPrivateFieldSet(this, _ReadablePromise_suspender, requestPromise.then((res) => {
779
+ __classPrivateFieldSet(this, _ReadablePromise_status, 'success', "f");
780
+ __classPrivateFieldSet(this, _ReadablePromise_response, res, "f");
781
+ return res;
782
+ }, (err) => {
783
+ __classPrivateFieldSet(this, _ReadablePromise_status, 'error', "f");
784
+ __classPrivateFieldSet(this, _ReadablePromise_error, err, "f");
785
+ throw err;
786
+ }), "f");
787
+ }
788
+ /**
789
+ * Returns true if the promise is pending.
790
+ * @returns True if the Promise is pending.
791
+ */
792
+ isPending() {
793
+ return __classPrivateFieldGet(this, _ReadablePromise_status, "f") === 'pending';
794
+ }
795
+ /**
796
+ * Attempts to read the value of the promise.
797
+ * If the promise is pending, this method will throw a promise.
798
+ * If the promise rejected, this method will throw the rejection reason.
799
+ * If the promise resolved, this method will return the resolved value.
800
+ * @returns The resolved value of the Promise.
801
+ */
802
+ read() {
803
+ switch (__classPrivateFieldGet(this, _ReadablePromise_status, "f")) {
804
+ case 'pending':
805
+ throw __classPrivateFieldGet(this, _ReadablePromise_suspender, "f");
806
+ case 'error':
807
+ throw __classPrivateFieldGet(this, _ReadablePromise_error, "f");
808
+ default:
809
+ return __classPrivateFieldGet(this, _ReadablePromise_response, "f");
810
+ }
811
+ }
812
+ /**
813
+ * Attaches callbacks for the resolution and/or rejection of the Promise.
814
+ * @param onfulfilled The callback to execute when the Promise is resolved.
815
+ * @param onrejected The callback to execute when the Promise is rejected.
816
+ * @returns A Promise for the completion of which ever callback is executed.
817
+ */
818
+ then(onfulfilled, onrejected) {
819
+ return __classPrivateFieldGet(this, _ReadablePromise_suspender, "f").then(onfulfilled, onrejected);
820
+ }
821
+ /**
822
+ * Attaches a callback for only the rejection of the Promise.
823
+ * @param onrejected The callback to execute when the Promise is rejected.
824
+ * @returns A Promise for the completion of the callback.
825
+ */
826
+ catch(onrejected) {
827
+ return __classPrivateFieldGet(this, _ReadablePromise_suspender, "f").catch(onrejected);
828
+ }
829
+ /**
830
+ * Attaches a callback that is invoked when the Promise is settled (fulfilled or rejected). The
831
+ * resolved value cannot be modified from the callback.
832
+ * @param onfinally The callback to execute when the Promise is settled (fulfilled or rejected).
833
+ * @returns A Promise for the completion of the callback.
834
+ */
835
+ finally(onfinally) {
836
+ return __classPrivateFieldGet(this, _ReadablePromise_suspender, "f").finally(onfinally);
837
+ }
838
+ }
839
+ _ReadablePromise_suspender = new WeakMap(), _ReadablePromise_status = new WeakMap(), _ReadablePromise_response = new WeakMap(), _ReadablePromise_error = new WeakMap(), _a = Symbol.toStringTag;
840
+
841
+ const DEFAULT_SEARCH_COUNT = 20;
728
842
  /**
729
843
  * Search operators.
730
844
  * These operators represent "modifiers" and "prefixes" in FHIR search.
@@ -792,15 +906,15 @@
792
906
  let filters = undefined;
793
907
  let sortRules = undefined;
794
908
  let fields = undefined;
795
- let page = undefined;
909
+ let offset = undefined;
796
910
  let count = undefined;
797
911
  let total = undefined;
798
912
  params.forEach((value, key) => {
799
913
  if (key === '_fields') {
800
914
  fields = value.split(',');
801
915
  }
802
- else if (key === '_page') {
803
- page = parseInt(value);
916
+ else if (key === '_offset') {
917
+ offset = parseInt(value);
804
918
  }
805
919
  else if (key === '_count') {
806
920
  count = parseInt(value);
@@ -821,7 +935,7 @@
821
935
  resourceType,
822
936
  filters,
823
937
  fields,
824
- page,
938
+ offset,
825
939
  count,
826
940
  total,
827
941
  sortRules,
@@ -897,13 +1011,13 @@
897
1011
  if (definition.sortRules && definition.sortRules.length > 0) {
898
1012
  params.push(formatSortRules(definition.sortRules));
899
1013
  }
900
- if (definition.page && definition.page > 0) {
901
- params.push('_page=' + definition.page);
1014
+ if (definition.offset !== undefined) {
1015
+ params.push('_offset=' + definition.offset);
902
1016
  }
903
- if (definition.count && definition.count > 0) {
1017
+ if (definition.count !== undefined) {
904
1018
  params.push('_count=' + definition.count);
905
1019
  }
906
- if (definition.total) {
1020
+ if (definition.total !== undefined) {
907
1021
  params.push('_total=' + encodeURIComponent(definition.total));
908
1022
  }
909
1023
  if (params.length === 0) {
@@ -1212,7 +1326,7 @@
1212
1326
 
1213
1327
  // PKCE auth ased on:
1214
1328
  // https://aws.amazon.com/blogs/security/how-to-add-authentication-single-page-web-application-with-amazon-cognito-oauth2-implementation/
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;
1329
+ var _MedplumClient_instances, _MedplumClient_fetch, _MedplumClient_storage, _MedplumClient_schema, _MedplumClient_requestCache, _MedplumClient_baseUrl, _MedplumClient_clientId, _MedplumClient_authorizeUrl, _MedplumClient_tokenUrl, _MedplumClient_logoutUrl, _MedplumClient_onUnauthenticated, _MedplumClient_accessToken, _MedplumClient_refreshToken, _MedplumClient_refreshPromise, _MedplumClient_profilePromise, _MedplumClient_profile, _MedplumClient_config, _MedplumClient_addLogin, _MedplumClient_refreshProfile, _MedplumClient_request, _MedplumClient_addFetchOptionsDefaults, _MedplumClient_setRequestContentType, _MedplumClient_setRequestBody, _MedplumClient_handleUnauthenticated, _MedplumClient_startPkce, _MedplumClient_requestAuthorization, _MedplumClient_refresh, _MedplumClient_fetchTokens, _MedplumClient_verifyTokens, _MedplumClient_setupStorageListener;
1216
1330
  const DEFAULT_BASE_URL = 'https://api.medplum.com/';
1217
1331
  const DEFAULT_SCOPE = 'launch/patient openid fhirUser offline_access user/*.*';
1218
1332
  const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
@@ -1275,7 +1389,7 @@
1275
1389
  _MedplumClient_fetch.set(this, void 0);
1276
1390
  _MedplumClient_storage.set(this, void 0);
1277
1391
  _MedplumClient_schema.set(this, void 0);
1278
- _MedplumClient_resourceCache.set(this, void 0);
1392
+ _MedplumClient_requestCache.set(this, void 0);
1279
1393
  _MedplumClient_baseUrl.set(this, void 0);
1280
1394
  _MedplumClient_clientId.set(this, void 0);
1281
1395
  _MedplumClient_authorizeUrl.set(this, void 0);
@@ -1299,7 +1413,7 @@
1299
1413
  __classPrivateFieldSet(this, _MedplumClient_fetch, (options === null || options === void 0 ? void 0 : options.fetch) || window.fetch.bind(window), "f");
1300
1414
  __classPrivateFieldSet(this, _MedplumClient_storage, new ClientStorage(), "f");
1301
1415
  __classPrivateFieldSet(this, _MedplumClient_schema, createSchema(), "f");
1302
- __classPrivateFieldSet(this, _MedplumClient_resourceCache, new LRUCache((_a = options === null || options === void 0 ? void 0 : options.resourceCacheSize) !== null && _a !== void 0 ? _a : DEFAULT_RESOURCE_CACHE_SIZE), "f");
1416
+ __classPrivateFieldSet(this, _MedplumClient_requestCache, new LRUCache((_a = options === null || options === void 0 ? void 0 : options.resourceCacheSize) !== null && _a !== void 0 ? _a : DEFAULT_RESOURCE_CACHE_SIZE), "f");
1303
1417
  __classPrivateFieldSet(this, _MedplumClient_baseUrl, (options === null || options === void 0 ? void 0 : options.baseUrl) || DEFAULT_BASE_URL, "f");
1304
1418
  __classPrivateFieldSet(this, _MedplumClient_clientId, (options === null || options === void 0 ? void 0 : options.clientId) || '', "f");
1305
1419
  __classPrivateFieldSet(this, _MedplumClient_authorizeUrl, (options === null || options === void 0 ? void 0 : options.authorizeUrl) || __classPrivateFieldGet(this, _MedplumClient_baseUrl, "f") + 'oauth2/authorize', "f");
@@ -1319,7 +1433,7 @@
1319
1433
  */
1320
1434
  clear() {
1321
1435
  __classPrivateFieldGet(this, _MedplumClient_storage, "f").clear();
1322
- __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").clear();
1436
+ __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").clear();
1323
1437
  __classPrivateFieldSet(this, _MedplumClient_accessToken, undefined, "f");
1324
1438
  __classPrivateFieldSet(this, _MedplumClient_refreshToken, undefined, "f");
1325
1439
  __classPrivateFieldSet(this, _MedplumClient_profile, undefined, "f");
@@ -1338,7 +1452,15 @@
1338
1452
  * @returns Promise to the response content.
1339
1453
  */
1340
1454
  get(url, options = {}) {
1341
- return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'GET', url, options);
1455
+ if (!(options === null || options === void 0 ? void 0 : options.cache)) {
1456
+ const cached = __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").get(url);
1457
+ if (cached) {
1458
+ return cached;
1459
+ }
1460
+ }
1461
+ const promise = new ReadablePromise(__classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'GET', url, options));
1462
+ __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").set(url, promise);
1463
+ return promise;
1342
1464
  }
1343
1465
  /**
1344
1466
  * Makes an HTTP POST request to the specified URL.
@@ -1360,6 +1482,7 @@
1360
1482
  if (contentType) {
1361
1483
  __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_setRequestContentType).call(this, options, contentType);
1362
1484
  }
1485
+ __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").delete(url);
1363
1486
  return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'POST', url, options);
1364
1487
  }
1365
1488
  /**
@@ -1382,6 +1505,7 @@
1382
1505
  if (contentType) {
1383
1506
  __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_setRequestContentType).call(this, options, contentType);
1384
1507
  }
1508
+ __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").delete(url);
1385
1509
  return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'PUT', url, options);
1386
1510
  }
1387
1511
  /**
@@ -1399,6 +1523,7 @@
1399
1523
  patch(url, operations, options = {}) {
1400
1524
  __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_setRequestBody).call(this, options, operations);
1401
1525
  __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_setRequestContentType).call(this, options, PATCH_CONTENT_TYPE);
1526
+ __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").delete(url);
1402
1527
  return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'PATCH', url, options);
1403
1528
  }
1404
1529
  /**
@@ -1413,6 +1538,7 @@
1413
1538
  * @returns Promise to the response content.
1414
1539
  */
1415
1540
  delete(url, options = {}) {
1541
+ __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").delete(url);
1416
1542
  return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'DELETE', url, options);
1417
1543
  }
1418
1544
  /**
@@ -1632,11 +1758,8 @@
1632
1758
  * @returns The resource if it is available in the cache; undefined otherwise.
1633
1759
  */
1634
1760
  getCached(resourceType, id) {
1635
- const cached = __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").get(resourceType + '/' + id);
1636
- if (cached && !('then' in cached)) {
1637
- return cached;
1638
- }
1639
- return undefined;
1761
+ const cached = __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").get(this.fhirUrl(resourceType, id));
1762
+ return cached && !cached.isPending() ? cached.read() : undefined;
1640
1763
  }
1641
1764
  /**
1642
1765
  * Returns a cached resource if it is available.
@@ -1645,11 +1768,9 @@
1645
1768
  * @returns The resource if it is available in the cache; undefined otherwise.
1646
1769
  */
1647
1770
  getCachedReference(reference) {
1648
- const cached = __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").get(reference.reference);
1649
- if (cached && !('then' in cached)) {
1650
- return cached;
1651
- }
1652
- return undefined;
1771
+ const refString = reference.reference;
1772
+ const [resourceType, id] = refString.split('/');
1773
+ return this.getCached(resourceType, id);
1653
1774
  }
1654
1775
  /**
1655
1776
  * Reads a resource by resource type and ID.
@@ -1668,13 +1789,7 @@
1668
1789
  * @returns The resource if available; undefined otherwise.
1669
1790
  */
1670
1791
  readResource(resourceType, id) {
1671
- const cacheKey = resourceType + '/' + id;
1672
- const promise = this.get(this.fhirUrl(resourceType, id)).then((resource) => {
1673
- __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").set(cacheKey, resource);
1674
- return resource;
1675
- });
1676
- __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").set(cacheKey, promise);
1677
- return promise;
1792
+ return this.get(this.fhirUrl(resourceType, id));
1678
1793
  }
1679
1794
  /**
1680
1795
  * Reads a resource by resource type and ID using the in-memory resource cache.
@@ -1695,8 +1810,7 @@
1695
1810
  * @returns The resource if available; undefined otherwise.
1696
1811
  */
1697
1812
  readCached(resourceType, id) {
1698
- const cached = __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").get(resourceType + '/' + id);
1699
- return cached ? Promise.resolve(cached) : this.readResource(resourceType, id);
1813
+ return this.get(this.fhirUrl(resourceType, id));
1700
1814
  }
1701
1815
  /**
1702
1816
  * Reads a resource by `Reference`.
@@ -1719,7 +1833,7 @@
1719
1833
  readReference(reference) {
1720
1834
  const refString = reference === null || reference === void 0 ? void 0 : reference.reference;
1721
1835
  if (!refString) {
1722
- return Promise.reject('Missing reference');
1836
+ return new ReadablePromise(Promise.reject('Missing reference'));
1723
1837
  }
1724
1838
  const [resourceType, id] = refString.split('/');
1725
1839
  return this.readResource(resourceType, id);
@@ -1747,7 +1861,7 @@
1747
1861
  readCachedReference(reference) {
1748
1862
  const refString = reference === null || reference === void 0 ? void 0 : reference.reference;
1749
1863
  if (!refString) {
1750
- return Promise.reject('Missing reference');
1864
+ return new ReadablePromise(Promise.reject('Missing reference'));
1751
1865
  }
1752
1866
  const [resourceType, id] = refString.split('/');
1753
1867
  return this.readCached(resourceType, id);
@@ -1794,7 +1908,7 @@
1794
1908
  }
1795
1909
  }
1796
1910
  }
1797
- SearchParameterList(base: "${encodeURIComponent(resourceType)}") {
1911
+ SearchParameterList(base: "${encodeURIComponent(resourceType)}", _count: 100) {
1798
1912
  base,
1799
1913
  code,
1800
1914
  type,
@@ -1884,6 +1998,50 @@
1884
1998
  }
1885
1999
  return this.post(this.fhirUrl(resource.resourceType), resource);
1886
2000
  }
2001
+ /**
2002
+ * Conditionally create a new FHIR resource only if some equivalent resource does not already exist on the server.
2003
+ *
2004
+ * The return value is the existing resource or the newly created resource, including the ID and meta.
2005
+ *
2006
+ * Example:
2007
+ *
2008
+ * ```typescript
2009
+ * const result = await medplum.createResourceIfNoneExist(
2010
+ * 'Patient?identifier=123',
2011
+ * {
2012
+ * resourceType: 'Patient',
2013
+ * identifier: [{
2014
+ * system: 'http://example.com/mrn',
2015
+ * value: '123'
2016
+ * }]
2017
+ * name: [{
2018
+ * family: 'Smith',
2019
+ * given: ['John']
2020
+ * }]
2021
+ * });
2022
+ * console.log(result.id);
2023
+ * ```
2024
+ *
2025
+ * This method is syntactic sugar for:
2026
+ *
2027
+ * ```typescript
2028
+ * return searchOne(query) ?? createResource(resource);
2029
+ * ```
2030
+ *
2031
+ * The query parameter only contains the search parameters (what would be in the URL following the "?").
2032
+ *
2033
+ * See the FHIR "conditional create" operation for full details: https://www.hl7.org/fhir/http.html#ccreate
2034
+ *
2035
+ * @param resource The FHIR resource to create.
2036
+ * @param query The search query for an equivalent resource.
2037
+ * @returns The result of the create operation.
2038
+ */
2039
+ createResourceIfNoneExist(resource, query) {
2040
+ var _a;
2041
+ return __awaiter(this, void 0, void 0, function* () {
2042
+ return (_a = (yield this.searchOne(`${resource.resourceType}?${query}`))) !== null && _a !== void 0 ? _a : this.createResource(resource);
2043
+ });
2044
+ }
1887
2045
  /**
1888
2046
  * Creates a FHIR `Binary` resource with the provided data content.
1889
2047
  *
@@ -1902,11 +2060,45 @@
1902
2060
  *
1903
2061
  * See the FHIR "create" operation for full details: https://www.hl7.org/fhir/http.html#create
1904
2062
  *
1905
- * @param resource The FHIR resource to create.
2063
+ * @param data The binary data to upload.
2064
+ * @param filename Optional filename for the binary.
2065
+ * @param contentType Content type for the binary.
1906
2066
  * @returns The result of the create operation.
1907
2067
  */
1908
2068
  createBinary(data, filename, contentType) {
1909
- return this.post(this.fhirUrl('Binary') + '?_filename=' + encodeURIComponent(filename), data, contentType);
2069
+ let url = this.fhirUrl('Binary');
2070
+ if (filename) {
2071
+ url += '?_filename=' + encodeURIComponent(filename);
2072
+ }
2073
+ return this.post(url, data, contentType);
2074
+ }
2075
+ /**
2076
+ * Creates a PDF as a FHIR `Binary` resource based on pdfmake document definition.
2077
+ *
2078
+ * The return value is the newly created resource, including the ID and meta.
2079
+ *
2080
+ * The `docDefinition` parameter is a pdfmake document definition.
2081
+ *
2082
+ * Example:
2083
+ *
2084
+ * ```typescript
2085
+ * const result = await medplum.createPdf({
2086
+ * content: ['Hello world']
2087
+ * });
2088
+ * console.log(result.id);
2089
+ * ```
2090
+ *
2091
+ * See the pdfmake document definition for full details: https://pdfmake.github.io/docs/0.1/document-definition-object/
2092
+ *
2093
+ * @param docDefinition The FHIR resource to create.
2094
+ * @returns The result of the create operation.
2095
+ */
2096
+ createPdf(docDefinition, filename) {
2097
+ let url = this.fhirUrl('Binary') + '/$pdf';
2098
+ if (filename) {
2099
+ url += '?_filename=' + encodeURIComponent(filename);
2100
+ }
2101
+ return this.post(url, docDefinition, 'application/json');
1910
2102
  }
1911
2103
  /**
1912
2104
  * Updates a FHIR resource.
@@ -1999,7 +2191,7 @@
1999
2191
  __classPrivateFieldSet(this, _MedplumClient_config, undefined, "f");
2000
2192
  __classPrivateFieldGet(this, _MedplumClient_storage, "f").setObject('activeLogin', login);
2001
2193
  __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_addLogin).call(this, login);
2002
- __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").clear();
2194
+ __classPrivateFieldGet(this, _MedplumClient_requestCache, "f").clear();
2003
2195
  __classPrivateFieldSet(this, _MedplumClient_refreshPromise, undefined, "f");
2004
2196
  yield __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_refreshProfile).call(this);
2005
2197
  });
@@ -2081,7 +2273,7 @@
2081
2273
  });
2082
2274
  }
2083
2275
  }
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) {
2276
+ _MedplumClient_fetch = new WeakMap(), _MedplumClient_storage = new WeakMap(), _MedplumClient_schema = new WeakMap(), _MedplumClient_requestCache = new WeakMap(), _MedplumClient_baseUrl = new WeakMap(), _MedplumClient_clientId = new WeakMap(), _MedplumClient_authorizeUrl = new WeakMap(), _MedplumClient_tokenUrl = new WeakMap(), _MedplumClient_logoutUrl = new WeakMap(), _MedplumClient_onUnauthenticated = new WeakMap(), _MedplumClient_accessToken = new WeakMap(), _MedplumClient_refreshToken = new WeakMap(), _MedplumClient_refreshPromise = new WeakMap(), _MedplumClient_profilePromise = new WeakMap(), _MedplumClient_profile = new WeakMap(), _MedplumClient_config = new WeakMap(), _MedplumClient_instances = new WeakSet(), _MedplumClient_addLogin = function _MedplumClient_addLogin(newLogin) {
2085
2277
  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); });
2086
2278
  logins.push(newLogin);
2087
2279
  __classPrivateFieldGet(this, _MedplumClient_storage, "f").setObject('logins', logins);
@@ -2120,7 +2312,7 @@
2120
2312
  return undefined;
2121
2313
  }
2122
2314
  const obj = yield response.json();
2123
- if (obj.resourceType === 'OperationOutcome' && !isOk(obj)) {
2315
+ if ((obj === null || obj === void 0 ? void 0 : obj.resourceType) === 'OperationOutcome' && !isOk(obj)) {
2124
2316
  return Promise.reject(obj);
2125
2317
  }
2126
2318
  return obj;
@@ -2382,209 +2574,6 @@
2382
2574
  }
2383
2575
  }
2384
2576
 
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
-
2588
2577
  exports.SearchParameterType = void 0;
2589
2578
  (function (SearchParameterType) {
2590
2579
  SearchParameterType["BOOLEAN"] = "BOOLEAN";
@@ -2712,13 +2701,15 @@
2712
2701
  }
2713
2702
 
2714
2703
  exports.COMPONENT_SEPARATOR = COMPONENT_SEPARATOR;
2704
+ exports.DEFAULT_SEARCH_COUNT = DEFAULT_SEARCH_COUNT;
2715
2705
  exports.FIELD_SEPARATOR = FIELD_SEPARATOR;
2716
2706
  exports.Hl7Field = Hl7Field;
2717
2707
  exports.Hl7Message = Hl7Message;
2718
2708
  exports.Hl7Segment = Hl7Segment;
2719
- exports.LegacyRepositoryClient = LegacyRepositoryClient;
2709
+ exports.LRUCache = LRUCache;
2720
2710
  exports.MedplumClient = MedplumClient;
2721
2711
  exports.OperationOutcomeError = OperationOutcomeError;
2712
+ exports.ReadablePromise = ReadablePromise;
2722
2713
  exports.SEGMENT_SEPARATOR = SEGMENT_SEPARATOR;
2723
2714
  exports.accessDenied = accessDenied;
2724
2715
  exports.allOk = allOk;
@@ -2760,6 +2751,7 @@
2760
2751
  exports.isOk = isOk;
2761
2752
  exports.isProfileResource = isProfileResource;
2762
2753
  exports.isStringArray = isStringArray;
2754
+ exports.isUUID = isUUID;
2763
2755
  exports.notFound = notFound;
2764
2756
  exports.notModified = notModified;
2765
2757
  exports.parseSearchDefinition = parseSearchDefinition;