@medplum/core 0.4.0 → 0.5.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
@@ -27,42 +27,59 @@
27
27
  function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
28
28
  step((generator = generator.apply(thisArg, _arguments || [])).next());
29
29
  });
30
+ }
31
+
32
+ function __classPrivateFieldGet(receiver, state, kind, f) {
33
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
34
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
35
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
36
+ }
37
+
38
+ function __classPrivateFieldSet(receiver, state, value, kind, f) {
39
+ if (kind === "m") throw new TypeError("Private method is not writable");
40
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
41
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
42
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
30
43
  }
31
44
 
45
+ var _LRUCache_instances, _LRUCache_max, _LRUCache_cache, _LRUCache_first;
32
46
  /**
33
47
  * LRU cache (least recently used)
34
48
  * Source: https://stackoverflow.com/a/46432113
35
49
  */
36
50
  class LRUCache {
37
51
  constructor(max = 10) {
38
- this.max = max;
39
- this.cache = new Map();
52
+ _LRUCache_instances.add(this);
53
+ _LRUCache_max.set(this, void 0);
54
+ _LRUCache_cache.set(this, void 0);
55
+ __classPrivateFieldSet(this, _LRUCache_max, max, "f");
56
+ __classPrivateFieldSet(this, _LRUCache_cache, new Map(), "f");
40
57
  }
41
58
  clear() {
42
- this.cache.clear();
59
+ __classPrivateFieldGet(this, _LRUCache_cache, "f").clear();
43
60
  }
44
61
  get(key) {
45
- const item = this.cache.get(key);
62
+ const item = __classPrivateFieldGet(this, _LRUCache_cache, "f").get(key);
46
63
  if (item) {
47
- this.cache.delete(key);
48
- this.cache.set(key, item);
64
+ __classPrivateFieldGet(this, _LRUCache_cache, "f").delete(key);
65
+ __classPrivateFieldGet(this, _LRUCache_cache, "f").set(key, item);
49
66
  }
50
67
  return item;
51
68
  }
52
69
  set(key, val) {
53
- if (this.cache.has(key)) {
54
- this.cache.delete(key);
70
+ if (__classPrivateFieldGet(this, _LRUCache_cache, "f").has(key)) {
71
+ __classPrivateFieldGet(this, _LRUCache_cache, "f").delete(key);
55
72
  }
56
- else if (this.cache.size >= this.max) {
57
- this.cache.delete(this.first());
73
+ else if (__classPrivateFieldGet(this, _LRUCache_cache, "f").size >= __classPrivateFieldGet(this, _LRUCache_max, "f")) {
74
+ __classPrivateFieldGet(this, _LRUCache_cache, "f").delete(__classPrivateFieldGet(this, _LRUCache_instances, "m", _LRUCache_first).call(this));
58
75
  }
59
- this.cache.set(key, val);
60
- }
61
- first() {
62
- // This works because the Map class maintains ordered keys.
63
- return this.cache.keys().next().value;
76
+ __classPrivateFieldGet(this, _LRUCache_cache, "f").set(key, val);
64
77
  }
65
- }
78
+ }
79
+ _LRUCache_max = new WeakMap(), _LRUCache_cache = new WeakMap(), _LRUCache_instances = new WeakSet(), _LRUCache_first = function _LRUCache_first() {
80
+ // This works because the Map class maintains ordered keys.
81
+ return __classPrivateFieldGet(this, _LRUCache_cache, "f").keys().next().value;
82
+ };
66
83
 
67
84
  function formatAddress(address, options) {
68
85
  const builder = [];
@@ -131,6 +148,15 @@
131
148
  function getReferenceString(resource) {
132
149
  return resource.resourceType + '/' + resource.id;
133
150
  }
151
+ /**
152
+ * Returns the ID portion of a reference.
153
+ * @param reference A FHIR reference.
154
+ * @returns The ID portion of a reference.
155
+ */
156
+ function resolveId(reference) {
157
+ var _a;
158
+ return (_a = reference === null || reference === void 0 ? void 0 : reference.reference) === null || _a === void 0 ? void 0 : _a.split('/')[1];
159
+ }
134
160
  /**
135
161
  * Returns true if the resource is a "ProfileResource".
136
162
  * @param resource The FHIR resource.
@@ -353,18 +379,20 @@
353
379
  /*
354
380
  * Based on: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget
355
381
  */
382
+ var _EventTarget_listeners;
356
383
  class EventTarget {
357
384
  constructor() {
358
- this.listeners = {};
385
+ _EventTarget_listeners.set(this, void 0);
386
+ __classPrivateFieldSet(this, _EventTarget_listeners, {}, "f");
359
387
  }
360
388
  addEventListener(type, callback) {
361
- if (!this.listeners[type]) {
362
- this.listeners[type] = [];
389
+ if (!__classPrivateFieldGet(this, _EventTarget_listeners, "f")[type]) {
390
+ __classPrivateFieldGet(this, _EventTarget_listeners, "f")[type] = [];
363
391
  }
364
- this.listeners[type].push(callback);
392
+ __classPrivateFieldGet(this, _EventTarget_listeners, "f")[type].push(callback);
365
393
  }
366
394
  removeEventListeneer(type, callback) {
367
- const array = this.listeners[type];
395
+ const array = __classPrivateFieldGet(this, _EventTarget_listeners, "f")[type];
368
396
  if (!array) {
369
397
  return;
370
398
  }
@@ -376,13 +404,14 @@
376
404
  }
377
405
  }
378
406
  dispatchEvent(event) {
379
- const array = this.listeners[event.type];
407
+ const array = __classPrivateFieldGet(this, _EventTarget_listeners, "f")[event.type];
380
408
  if (array) {
381
409
  array.forEach((listener) => listener.call(this, event));
382
410
  }
383
411
  return !event.defaultPrevented;
384
412
  }
385
- }
413
+ }
414
+ _EventTarget_listeners = new WeakMap();
386
415
 
387
416
  /**
388
417
  * Decodes a section of a JWT.
@@ -615,13 +644,17 @@
615
644
  * @returns Parsed search definition.
616
645
  */
617
646
  function parseSearchDefinition(location) {
618
- const resourceType = location.pathname.split('/').pop();
647
+ const resourceType = location.pathname
648
+ .replace(/(^\/)|(\/$)/g, '') // Remove leading and trailing slashes
649
+ .split('/')
650
+ .pop();
619
651
  const params = new URLSearchParams(location.search);
620
- const filters = [];
621
- const sortRules = [];
622
- let fields;
623
- let page = 0;
624
- let count = 10;
652
+ let filters = undefined;
653
+ let sortRules = undefined;
654
+ let fields = undefined;
655
+ let page = undefined;
656
+ let count = undefined;
657
+ let total = undefined;
625
658
  params.forEach((value, key) => {
626
659
  if (key === '_fields') {
627
660
  fields = value.split(',');
@@ -632,10 +665,15 @@
632
665
  else if (key === '_count') {
633
666
  count = parseInt(value);
634
667
  }
668
+ else if (key === '_total') {
669
+ total = value;
670
+ }
635
671
  else if (key === '_sort') {
672
+ sortRules = sortRules || [];
636
673
  sortRules.push(parseSortRule(value));
637
674
  }
638
675
  else {
676
+ filters = filters || [];
639
677
  filters.push(parseSearchFilter(key, value));
640
678
  }
641
679
  });
@@ -645,6 +683,7 @@
645
683
  fields,
646
684
  page,
647
685
  count,
686
+ total,
648
687
  sortRules,
649
688
  };
650
689
  }
@@ -713,13 +752,9 @@
713
752
  params.push('_fields=' + definition.fields.join(','));
714
753
  }
715
754
  if (definition.filters) {
716
- definition.filters.forEach((filter) => {
717
- const modifier = MODIFIER_OPERATORS.includes(filter.operator) ? ':' + filter.operator : '';
718
- const prefix = PREFIX_OPERATORS.includes(filter.operator) ? filter.operator : '';
719
- params.push(`${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`);
720
- });
755
+ definition.filters.forEach((filter) => params.push(formatFilter(filter)));
721
756
  }
722
- if (definition.sortRules) {
757
+ if (definition.sortRules && definition.sortRules.length > 0) {
723
758
  params.push(formatSortRules(definition.sortRules));
724
759
  }
725
760
  if (definition.page && definition.page > 0) {
@@ -728,12 +763,20 @@
728
763
  if (definition.count && definition.count > 0) {
729
764
  params.push('_count=' + definition.count);
730
765
  }
766
+ if (definition.total) {
767
+ params.push('_total=' + encodeURIComponent(definition.total));
768
+ }
731
769
  if (params.length === 0) {
732
770
  return '';
733
771
  }
734
772
  params.sort();
735
773
  return '?' + params.join('&');
736
774
  }
775
+ function formatFilter(filter) {
776
+ const modifier = MODIFIER_OPERATORS.includes(filter.operator) ? ':' + filter.operator : '';
777
+ const prefix = PREFIX_OPERATORS.includes(filter.operator) ? filter.operator : '';
778
+ return `${filter.code}${modifier}=${prefix}${encodeURIComponent(filter.value)}`;
779
+ }
737
780
  function formatSortRules(sortRules) {
738
781
  if (!sortRules || sortRules.length === 0) {
739
782
  return '';
@@ -741,6 +784,7 @@
741
784
  return '_sort=' + sortRules.map((sr) => (sr.descending ? '-' + sr.code : sr.code)).join(',');
742
785
  }
743
786
 
787
+ var _ClientStorage_storage, _MemoryStorage_data;
744
788
  /**
745
789
  * The ClientStorage class is a utility class for storing strings and objects.
746
790
  *
@@ -750,20 +794,21 @@
750
794
  */
751
795
  class ClientStorage {
752
796
  constructor() {
753
- this.storage = typeof localStorage !== 'undefined' ? localStorage : new MemoryStorage();
797
+ _ClientStorage_storage.set(this, void 0);
798
+ __classPrivateFieldSet(this, _ClientStorage_storage, typeof localStorage !== 'undefined' ? localStorage : new MemoryStorage(), "f");
754
799
  }
755
800
  clear() {
756
- this.storage.clear();
801
+ __classPrivateFieldGet(this, _ClientStorage_storage, "f").clear();
757
802
  }
758
803
  getString(key) {
759
- return this.storage.getItem(key) || undefined;
804
+ return __classPrivateFieldGet(this, _ClientStorage_storage, "f").getItem(key) || undefined;
760
805
  }
761
806
  setString(key, value) {
762
807
  if (value) {
763
- this.storage.setItem(key, value);
808
+ __classPrivateFieldGet(this, _ClientStorage_storage, "f").setItem(key, value);
764
809
  }
765
810
  else {
766
- this.storage.removeItem(key);
811
+ __classPrivateFieldGet(this, _ClientStorage_storage, "f").removeItem(key);
767
812
  }
768
813
  }
769
814
  getObject(key) {
@@ -774,56 +819,59 @@
774
819
  this.setString(key, value ? stringify(value) : undefined);
775
820
  }
776
821
  }
822
+ _ClientStorage_storage = new WeakMap();
777
823
  /**
778
824
  * The MemoryStorage class is a minimal in-memory implementation of the Storage interface.
779
825
  */
780
826
  class MemoryStorage {
781
827
  constructor() {
782
- this.data = new Map();
828
+ _MemoryStorage_data.set(this, void 0);
829
+ __classPrivateFieldSet(this, _MemoryStorage_data, new Map(), "f");
783
830
  }
784
831
  /**
785
832
  * Returns the number of key/value pairs.
786
833
  */
787
834
  get length() {
788
- return this.data.size;
835
+ return __classPrivateFieldGet(this, _MemoryStorage_data, "f").size;
789
836
  }
790
837
  /**
791
838
  * Removes all key/value pairs, if there are any.
792
839
  */
793
840
  clear() {
794
- this.data.clear();
841
+ __classPrivateFieldGet(this, _MemoryStorage_data, "f").clear();
795
842
  }
796
843
  /**
797
844
  * Returns the current value associated with the given key, or null if the given key does not exist.
798
845
  */
799
846
  getItem(key) {
800
847
  var _a;
801
- return (_a = this.data.get(key)) !== null && _a !== void 0 ? _a : null;
848
+ return (_a = __classPrivateFieldGet(this, _MemoryStorage_data, "f").get(key)) !== null && _a !== void 0 ? _a : null;
802
849
  }
803
850
  /**
804
851
  * Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
805
852
  */
806
853
  setItem(key, value) {
807
854
  if (value) {
808
- this.data.set(key, value);
855
+ __classPrivateFieldGet(this, _MemoryStorage_data, "f").set(key, value);
809
856
  }
810
857
  else {
811
- this.data.delete(key);
858
+ __classPrivateFieldGet(this, _MemoryStorage_data, "f").delete(key);
812
859
  }
813
860
  }
814
861
  /**
815
862
  * Removes the key/value pair with the given key, if a key/value pair with the given key exists.
816
863
  */
817
864
  removeItem(key) {
818
- this.data.delete(key);
865
+ __classPrivateFieldGet(this, _MemoryStorage_data, "f").delete(key);
819
866
  }
820
867
  /**
821
868
  * Returns the name of the nth key, or null if n is greater than or equal to the number of key/value pairs.
822
869
  */
823
870
  key(index) {
824
- return Array.from(this.data.keys())[index];
871
+ return Array.from(__classPrivateFieldGet(this, _MemoryStorage_data, "f").keys())[index];
825
872
  }
826
- }
873
+ }
874
+ _MemoryStorage_data = new WeakMap();
827
875
 
828
876
  /**
829
877
  * List of property types.
@@ -900,6 +948,21 @@
900
948
  function createSchema() {
901
949
  return { types: {} };
902
950
  }
951
+ function createTypeSchema(typeName, description) {
952
+ return {
953
+ display: typeName,
954
+ description,
955
+ properties: {},
956
+ searchParams: {
957
+ _lastUpdated: {
958
+ base: [typeName],
959
+ code: '_lastUpdated',
960
+ type: 'date',
961
+ expression: typeName + '.meta.lastUpdated',
962
+ },
963
+ },
964
+ };
965
+ }
903
966
  /**
904
967
  * Indexes a StructureDefinition for fast lookup.
905
968
  * See comments on IndexedStructureDefinition for more details.
@@ -912,11 +975,7 @@
912
975
  if (!typeName) {
913
976
  return;
914
977
  }
915
- schema.types[typeName] = {
916
- display: typeName,
917
- description: structureDefinition.description,
918
- properties: {},
919
- };
978
+ schema.types[typeName] = createTypeSchema(typeName, structureDefinition.description);
920
979
  const elements = (_a = structureDefinition.snapshot) === null || _a === void 0 ? void 0 : _a.element;
921
980
  if (elements) {
922
981
  // Filter out any elements missing path or type
@@ -944,12 +1003,8 @@
944
1003
  const parts = path.split('.');
945
1004
  const typeName = buildTypeName(parts);
946
1005
  if (!(typeName in schema.types)) {
947
- schema.types[typeName] = {
948
- display: typeName,
949
- description: element.definition,
950
- parentType: buildTypeName(parts.slice(0, parts.length - 1)),
951
- properties: {},
952
- };
1006
+ schema.types[typeName] = createTypeSchema(typeName, element.definition);
1007
+ schema.types[typeName].parentType = buildTypeName(parts.slice(0, parts.length - 1));
953
1008
  }
954
1009
  }
955
1010
  /**
@@ -997,6 +1052,10 @@
997
1052
  // For example, for path "Patient.birthDate"
998
1053
  // the property name is "birthDate"
999
1054
  const propertyName = property.path.replaceAll('[x]', '').split('.').pop();
1055
+ // Special case for ID
1056
+ if (propertyName === 'id') {
1057
+ return 'ID';
1058
+ }
1000
1059
  // Split by capital letters
1001
1060
  // Capitalize the first letter of each word
1002
1061
  // Join together with spaces in between
@@ -1012,6 +1071,8 @@
1012
1071
  }
1013
1072
 
1014
1073
  // PKCE auth ased on:
1074
+ // 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;
1015
1076
  const DEFAULT_BASE_URL = 'https://api.medplum.com/';
1016
1077
  const DEFAULT_SCOPE = 'launch/patient openid fhirUser offline_access user/*.*';
1017
1078
  const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
@@ -1022,6 +1083,23 @@
1022
1083
  constructor(options) {
1023
1084
  var _a;
1024
1085
  super();
1086
+ _MedplumClient_instances.add(this);
1087
+ _MedplumClient_fetch.set(this, void 0);
1088
+ _MedplumClient_storage.set(this, void 0);
1089
+ _MedplumClient_schema.set(this, void 0);
1090
+ _MedplumClient_resourceCache.set(this, void 0);
1091
+ _MedplumClient_baseUrl.set(this, void 0);
1092
+ _MedplumClient_clientId.set(this, void 0);
1093
+ _MedplumClient_authorizeUrl.set(this, void 0);
1094
+ _MedplumClient_tokenUrl.set(this, void 0);
1095
+ _MedplumClient_logoutUrl.set(this, void 0);
1096
+ _MedplumClient_onUnauthenticated.set(this, void 0);
1097
+ _MedplumClient_accessToken.set(this, void 0);
1098
+ _MedplumClient_refreshToken.set(this, void 0);
1099
+ _MedplumClient_refreshPromise.set(this, void 0);
1100
+ _MedplumClient_profilePromise.set(this, void 0);
1101
+ _MedplumClient_profile.set(this, void 0);
1102
+ _MedplumClient_config.set(this, void 0);
1025
1103
  if (options === null || options === void 0 ? void 0 : options.baseUrl) {
1026
1104
  if (!options.baseUrl.startsWith('http')) {
1027
1105
  throw new Error('Base URL must start with http or https');
@@ -1030,39 +1108,47 @@
1030
1108
  throw new Error('Base URL must end with a trailing slash');
1031
1109
  }
1032
1110
  }
1033
- this.fetch = (options === null || options === void 0 ? void 0 : options.fetch) || window.fetch.bind(window);
1034
- this.storage = new ClientStorage();
1035
- this.schema = createSchema();
1036
- this.resourceCache = new LRUCache((_a = options === null || options === void 0 ? void 0 : options.resourceCacheSize) !== null && _a !== void 0 ? _a : DEFAULT_RESOURCE_CACHE_SIZE);
1037
- this.baseUrl = (options === null || options === void 0 ? void 0 : options.baseUrl) || DEFAULT_BASE_URL;
1038
- this.clientId = (options === null || options === void 0 ? void 0 : options.clientId) || '';
1039
- this.authorizeUrl = (options === null || options === void 0 ? void 0 : options.authorizeUrl) || this.baseUrl + 'oauth2/authorize';
1040
- this.tokenUrl = (options === null || options === void 0 ? void 0 : options.tokenUrl) || this.baseUrl + 'oauth2/token';
1041
- this.logoutUrl = (options === null || options === void 0 ? void 0 : options.logoutUrl) || this.baseUrl + 'oauth2/logout';
1042
- this.onUnauthenticated = options === null || options === void 0 ? void 0 : options.onUnauthenticated;
1043
- this.loading = false;
1044
- this.refreshProfile().catch(console.log);
1045
- this.setupStorageListener();
1111
+ __classPrivateFieldSet(this, _MedplumClient_fetch, (options === null || options === void 0 ? void 0 : options.fetch) || window.fetch.bind(window), "f");
1112
+ __classPrivateFieldSet(this, _MedplumClient_storage, new ClientStorage(), "f");
1113
+ __classPrivateFieldSet(this, _MedplumClient_schema, createSchema(), "f");
1114
+ __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");
1115
+ __classPrivateFieldSet(this, _MedplumClient_baseUrl, (options === null || options === void 0 ? void 0 : options.baseUrl) || DEFAULT_BASE_URL, "f");
1116
+ __classPrivateFieldSet(this, _MedplumClient_clientId, (options === null || options === void 0 ? void 0 : options.clientId) || '', "f");
1117
+ __classPrivateFieldSet(this, _MedplumClient_authorizeUrl, (options === null || options === void 0 ? void 0 : options.authorizeUrl) || __classPrivateFieldGet(this, _MedplumClient_baseUrl, "f") + 'oauth2/authorize', "f");
1118
+ __classPrivateFieldSet(this, _MedplumClient_tokenUrl, (options === null || options === void 0 ? void 0 : options.tokenUrl) || __classPrivateFieldGet(this, _MedplumClient_baseUrl, "f") + 'oauth2/token', "f");
1119
+ __classPrivateFieldSet(this, _MedplumClient_logoutUrl, (options === null || options === void 0 ? void 0 : options.logoutUrl) || __classPrivateFieldGet(this, _MedplumClient_baseUrl, "f") + 'oauth2/logout', "f");
1120
+ __classPrivateFieldSet(this, _MedplumClient_onUnauthenticated, options === null || options === void 0 ? void 0 : options.onUnauthenticated, "f");
1121
+ const activeLogin = this.getActiveLogin();
1122
+ if (activeLogin) {
1123
+ __classPrivateFieldSet(this, _MedplumClient_accessToken, activeLogin.accessToken, "f");
1124
+ __classPrivateFieldSet(this, _MedplumClient_refreshToken, activeLogin.refreshToken, "f");
1125
+ __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_refreshProfile).call(this).catch(console.log);
1126
+ }
1127
+ __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_setupStorageListener).call(this);
1046
1128
  }
1047
1129
  /**
1048
1130
  * Clears all auth state including local storage and session storage.
1049
1131
  */
1050
1132
  clear() {
1051
- this.storage.clear();
1052
- this.resourceCache.clear();
1133
+ __classPrivateFieldGet(this, _MedplumClient_storage, "f").clear();
1134
+ __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").clear();
1135
+ __classPrivateFieldSet(this, _MedplumClient_accessToken, undefined, "f");
1136
+ __classPrivateFieldSet(this, _MedplumClient_refreshToken, undefined, "f");
1137
+ __classPrivateFieldSet(this, _MedplumClient_profile, undefined, "f");
1138
+ __classPrivateFieldSet(this, _MedplumClient_config, undefined, "f");
1053
1139
  this.dispatchEvent({ type: 'change' });
1054
1140
  }
1055
1141
  get(url) {
1056
- return this.request('GET', url);
1142
+ return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'GET', url);
1057
1143
  }
1058
1144
  post(url, body, contentType) {
1059
- return this.request('POST', url, contentType, body);
1145
+ return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'POST', url, contentType, body);
1060
1146
  }
1061
1147
  put(url, body, contentType) {
1062
- return this.request('PUT', url, contentType, body);
1148
+ return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'PUT', url, contentType, body);
1063
1149
  }
1064
1150
  delete(url) {
1065
- return this.request('DELETE', url);
1151
+ return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'DELETE', url);
1066
1152
  }
1067
1153
  /**
1068
1154
  * Tries to register a new user.
@@ -1084,12 +1170,12 @@
1084
1170
  */
1085
1171
  startLogin(email, password, remember) {
1086
1172
  return __awaiter(this, void 0, void 0, function* () {
1087
- yield this.startPkce();
1173
+ yield __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_startPkce).call(this);
1088
1174
  return this.post('auth/login', {
1089
- clientId: this.clientId,
1175
+ clientId: __classPrivateFieldGet(this, _MedplumClient_clientId, "f"),
1090
1176
  scope: DEFAULT_SCOPE,
1091
1177
  codeChallengeMethod: 'S256',
1092
- codeChallenge: this.storage.getString('codeChallenge'),
1178
+ codeChallenge: __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('codeChallenge'),
1093
1179
  email,
1094
1180
  password,
1095
1181
  remember: !!remember,
@@ -1105,7 +1191,7 @@
1105
1191
  */
1106
1192
  startGoogleLogin(googleResponse) {
1107
1193
  return __awaiter(this, void 0, void 0, function* () {
1108
- yield this.startPkce();
1194
+ yield __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_startPkce).call(this);
1109
1195
  return this.post('auth/google', googleResponse);
1110
1196
  });
1111
1197
  }
@@ -1126,7 +1212,7 @@
1126
1212
  const urlParams = new URLSearchParams(window.location.search);
1127
1213
  const code = urlParams.get('code');
1128
1214
  if (!code) {
1129
- this.requestAuthorization();
1215
+ __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_requestAuthorization).call(this);
1130
1216
  return undefined;
1131
1217
  }
1132
1218
  else {
@@ -1138,7 +1224,7 @@
1138
1224
  * See: https://docs.aws.amazon.com/cognito/latest/developerguide/logout-endpoint.html
1139
1225
  */
1140
1226
  signOutWithRedirect() {
1141
- window.location.assign(this.logoutUrl);
1227
+ window.location.assign(__classPrivateFieldGet(this, _MedplumClient_logoutUrl, "f"));
1142
1228
  }
1143
1229
  /**
1144
1230
  * Builds a FHIR URL from a collection of URL path components.
@@ -1147,7 +1233,7 @@
1147
1233
  * @returns The well-formed FHIR URL.
1148
1234
  */
1149
1235
  fhirUrl(...path) {
1150
- const builder = [this.baseUrl, 'fhir/R4'];
1236
+ const builder = [__classPrivateFieldGet(this, _MedplumClient_baseUrl, "f"), 'fhir/R4'];
1151
1237
  path.forEach((p) => builder.push('/', encodeURIComponent(p)));
1152
1238
  return builder.join('');
1153
1239
  }
@@ -1178,7 +1264,7 @@
1178
1264
  * @returns The resource if it is available in the cache; undefined otherwise.
1179
1265
  */
1180
1266
  getCached(resourceType, id) {
1181
- const cached = this.resourceCache.get(resourceType + '/' + id);
1267
+ const cached = __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").get(resourceType + '/' + id);
1182
1268
  if (cached && !('then' in cached)) {
1183
1269
  return cached;
1184
1270
  }
@@ -1191,7 +1277,7 @@
1191
1277
  * @returns The resource if it is available in the cache; undefined otherwise.
1192
1278
  */
1193
1279
  getCachedReference(reference) {
1194
- const cached = this.resourceCache.get(reference.reference);
1280
+ const cached = __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").get(reference.reference);
1195
1281
  if (cached && !('then' in cached)) {
1196
1282
  return cached;
1197
1283
  }
@@ -1200,14 +1286,14 @@
1200
1286
  read(resourceType, id) {
1201
1287
  const cacheKey = resourceType + '/' + id;
1202
1288
  const promise = this.get(this.fhirUrl(resourceType, id)).then((resource) => {
1203
- this.resourceCache.set(cacheKey, resource);
1289
+ __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").set(cacheKey, resource);
1204
1290
  return resource;
1205
1291
  });
1206
- this.resourceCache.set(cacheKey, promise);
1292
+ __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").set(cacheKey, promise);
1207
1293
  return promise;
1208
1294
  }
1209
1295
  readCached(resourceType, id) {
1210
- const cached = this.resourceCache.get(resourceType + '/' + id);
1296
+ const cached = __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").get(resourceType + '/' + id);
1211
1297
  return cached ? Promise.resolve(cached) : this.read(resourceType, id);
1212
1298
  }
1213
1299
  readReference(reference) {
@@ -1234,7 +1320,7 @@
1234
1320
  * @returns The schema if immediately available, undefined otherwise.
1235
1321
  */
1236
1322
  getSchema() {
1237
- return this.schema;
1323
+ return __classPrivateFieldGet(this, _MedplumClient_schema, "f");
1238
1324
  }
1239
1325
  /**
1240
1326
  * Requests the schema for a resource type.
@@ -1244,8 +1330,8 @@
1244
1330
  */
1245
1331
  requestSchema(resourceType) {
1246
1332
  return __awaiter(this, void 0, void 0, function* () {
1247
- if (resourceType in this.schema.types) {
1248
- return Promise.resolve(this.schema);
1333
+ if (resourceType in __classPrivateFieldGet(this, _MedplumClient_schema, "f").types) {
1334
+ return Promise.resolve(__classPrivateFieldGet(this, _MedplumClient_schema, "f"));
1249
1335
  }
1250
1336
  const query = `{
1251
1337
  StructureDefinitionList(name: "${encodeURIComponent(resourceType)}") {
@@ -1271,17 +1357,19 @@
1271
1357
  SearchParameterList(base: "${encodeURIComponent(resourceType)}") {
1272
1358
  base,
1273
1359
  code,
1274
- type
1360
+ type,
1361
+ expression,
1362
+ target
1275
1363
  }
1276
1364
  }`.replace(/\s+/g, ' ');
1277
1365
  const response = (yield this.graphql(query));
1278
1366
  for (const structureDefinition of response.data.StructureDefinitionList) {
1279
- indexStructureDefinition(this.schema, structureDefinition);
1367
+ indexStructureDefinition(__classPrivateFieldGet(this, _MedplumClient_schema, "f"), structureDefinition);
1280
1368
  }
1281
1369
  for (const searchParameter of response.data.SearchParameterList) {
1282
- indexSearchParameter(this.schema, searchParameter);
1370
+ indexSearchParameter(__classPrivateFieldGet(this, _MedplumClient_schema, "f"), searchParameter);
1283
1371
  }
1284
- return this.schema;
1372
+ return __classPrivateFieldGet(this, _MedplumClient_schema, "f");
1285
1373
  });
1286
1374
  }
1287
1375
  readHistory(resourceType, id) {
@@ -1309,7 +1397,7 @@
1309
1397
  return this.put(this.fhirUrl(resource.resourceType, resource.id), resource);
1310
1398
  }
1311
1399
  patch(resourceType, id, operations) {
1312
- return this.request('PATCH', this.fhirUrl(resourceType, id), PATCH_CONTENT_TYPE, operations);
1400
+ return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, 'PATCH', this.fhirUrl(resourceType, id), PATCH_CONTENT_TYPE, operations);
1313
1401
  }
1314
1402
  deleteResource(resourceType, id) {
1315
1403
  return this.delete(this.fhirUrl(resourceType, id));
@@ -1318,159 +1406,55 @@
1318
1406
  return this.post(this.fhirUrl('$graphql'), { query }, JSON_CONTENT_TYPE);
1319
1407
  }
1320
1408
  getActiveLogin() {
1321
- return this.storage.getObject('activeLogin');
1409
+ return __classPrivateFieldGet(this, _MedplumClient_storage, "f").getObject('activeLogin');
1322
1410
  }
1323
1411
  setActiveLogin(login) {
1324
1412
  return __awaiter(this, void 0, void 0, function* () {
1325
- this.storage.setObject('activeLogin', login);
1326
- this.addLogin(login);
1327
- this.resourceCache.clear();
1328
- this.refreshPromise = undefined;
1329
- yield this.refreshProfile();
1413
+ __classPrivateFieldSet(this, _MedplumClient_accessToken, login.accessToken, "f");
1414
+ __classPrivateFieldSet(this, _MedplumClient_refreshToken, login.refreshToken, "f");
1415
+ __classPrivateFieldSet(this, _MedplumClient_profile, undefined, "f");
1416
+ __classPrivateFieldSet(this, _MedplumClient_config, undefined, "f");
1417
+ __classPrivateFieldGet(this, _MedplumClient_storage, "f").setObject('activeLogin', login);
1418
+ __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_addLogin).call(this, login);
1419
+ __classPrivateFieldGet(this, _MedplumClient_resourceCache, "f").clear();
1420
+ __classPrivateFieldSet(this, _MedplumClient_refreshPromise, undefined, "f");
1421
+ yield __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_refreshProfile).call(this);
1330
1422
  });
1331
1423
  }
1332
1424
  getLogins() {
1333
1425
  var _a;
1334
- return (_a = this.storage.getObject('logins')) !== null && _a !== void 0 ? _a : [];
1335
- }
1336
- addLogin(newLogin) {
1337
- 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); });
1338
- logins.push(newLogin);
1339
- this.storage.setObject('logins', logins);
1426
+ return (_a = __classPrivateFieldGet(this, _MedplumClient_storage, "f").getObject('logins')) !== null && _a !== void 0 ? _a : [];
1340
1427
  }
1341
- refreshProfile() {
1342
- var _a;
1343
- return __awaiter(this, void 0, void 0, function* () {
1344
- const reference = (_a = this.getActiveLogin()) === null || _a === void 0 ? void 0 : _a.profile;
1345
- if (reference === null || reference === void 0 ? void 0 : reference.reference) {
1346
- this.loading = true;
1347
- this.storage.setObject('profile', yield this.readCachedReference(reference));
1348
- this.loading = false;
1349
- this.dispatchEvent({ type: 'change' });
1350
- }
1351
- return this.getProfile();
1352
- });
1428
+ isLoading() {
1429
+ return !!__classPrivateFieldGet(this, _MedplumClient_profilePromise, "f");
1353
1430
  }
1354
1431
  getProfile() {
1355
- return this.storage.getObject('profile');
1432
+ return __classPrivateFieldGet(this, _MedplumClient_profile, "f");
1356
1433
  }
1357
- isLoading() {
1358
- return this.loading;
1359
- }
1360
- /**
1361
- * Makes an HTTP request.
1362
- * @param {string} method
1363
- * @param {string} url
1364
- * @param {string=} contentType
1365
- * @param {Object=} body
1366
- */
1367
- request(method, url, contentType, body) {
1368
- var _a;
1434
+ getProfileAsync() {
1369
1435
  return __awaiter(this, void 0, void 0, function* () {
1370
- if (this.refreshPromise) {
1371
- yield this.refreshPromise;
1372
- }
1373
- if (!url.startsWith('http')) {
1374
- url = this.baseUrl + url;
1375
- }
1376
- const headers = {
1377
- 'Content-Type': contentType || FHIR_CONTENT_TYPE,
1378
- };
1379
- const accessToken = (_a = this.getActiveLogin()) === null || _a === void 0 ? void 0 : _a.accessToken;
1380
- if (accessToken) {
1381
- headers['Authorization'] = 'Bearer ' + accessToken;
1382
- }
1383
- const options = {
1384
- method: method,
1385
- cache: 'no-cache',
1386
- credentials: 'include',
1387
- headers,
1388
- };
1389
- if (body) {
1390
- if (typeof body === 'string' || (typeof File !== 'undefined' && body instanceof File)) {
1391
- options.body = body;
1392
- }
1393
- else {
1394
- options.body = stringify(body);
1395
- }
1396
- }
1397
- const response = yield this.fetch(url, options);
1398
- if (response.status === 401) {
1399
- // Refresh and try again
1400
- return this.handleUnauthenticated(method, url, contentType, body);
1401
- }
1402
- if (response.status === 204 || response.status === 304) {
1403
- // No content or change
1404
- return undefined;
1436
+ if (__classPrivateFieldGet(this, _MedplumClient_profilePromise, "f")) {
1437
+ yield __classPrivateFieldGet(this, _MedplumClient_profilePromise, "f");
1405
1438
  }
1406
- const obj = yield response.json();
1407
- if (obj.resourceType === 'OperationOutcome' && !isOk(obj)) {
1408
- return Promise.reject(obj);
1409
- }
1410
- return obj;
1439
+ return this.getProfile();
1411
1440
  });
1412
1441
  }
1413
- /**
1414
- * Handles an unauthenticated response from the server.
1415
- * First, tries to refresh the access token and retry the request.
1416
- * Otherwise, calls unauthenticated callbacks and rejects.
1417
- * @param method The HTTP method of the original request.
1418
- * @param url The URL of the original request.
1419
- * @param contentType The content type of the original request.
1420
- * @param body The body of the original request.
1421
- */
1422
- handleUnauthenticated(method, url, contentType, body) {
1423
- return __awaiter(this, void 0, void 0, function* () {
1424
- return this.refresh()
1425
- .then(() => this.request(method, url, contentType, body))
1426
- .catch((error) => {
1427
- this.clear();
1428
- if (this.onUnauthenticated) {
1429
- this.onUnauthenticated();
1430
- }
1431
- return Promise.reject(error);
1432
- });
1433
- });
1442
+ getUserConfiguration() {
1443
+ return __classPrivateFieldGet(this, _MedplumClient_config, "f");
1434
1444
  }
1435
1445
  /**
1436
- * Starts a new PKCE flow.
1437
- * These PKCE values are stateful, and must survive redirects and page refreshes.
1446
+ * Downloads the URL as a blob.
1447
+ * @param url The URL to request.
1448
+ * @returns Promise to the response body as a blob.
1438
1449
  */
1439
- startPkce() {
1450
+ download(url) {
1440
1451
  return __awaiter(this, void 0, void 0, function* () {
1441
- const pkceState = getRandomString();
1442
- this.storage.setString('pkceState', pkceState);
1443
- const codeVerifier = getRandomString();
1444
- this.storage.setString('codeVerifier', codeVerifier);
1445
- const arrayHash = yield encryptSHA256(codeVerifier);
1446
- const codeChallenge = arrayBufferToBase64(arrayHash).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
1447
- this.storage.setString('codeChallenge', codeChallenge);
1448
- });
1449
- }
1450
- /**
1451
- * Redirects the user to the login screen for authorization.
1452
- * Clears all auth state including local storage and session storage.
1453
- * See: https://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint
1454
- */
1455
- requestAuthorization() {
1456
- return __awaiter(this, void 0, void 0, function* () {
1457
- if (!this.authorizeUrl) {
1458
- throw new Error('Missing authorize URL');
1452
+ if (__classPrivateFieldGet(this, _MedplumClient_refreshPromise, "f")) {
1453
+ yield __classPrivateFieldGet(this, _MedplumClient_refreshPromise, "f");
1459
1454
  }
1460
- this.startPkce();
1461
- window.location.assign(this.authorizeUrl +
1462
- '?response_type=code' +
1463
- '&state=' +
1464
- encodeURIComponent(this.storage.getString('pkceState')) +
1465
- '&client_id=' +
1466
- encodeURIComponent(this.clientId) +
1467
- '&redirect_uri=' +
1468
- encodeURIComponent(getBaseUrl()) +
1469
- '&scope=' +
1470
- encodeURIComponent(DEFAULT_SCOPE) +
1471
- '&code_challenge_method=S256' +
1472
- '&code_challenge=' +
1473
- encodeURIComponent(this.storage.getString('codeChallenge')));
1455
+ const options = __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_buildFetchOptions).call(this, 'GET');
1456
+ const response = yield __classPrivateFieldGet(this, _MedplumClient_fetch, "f").call(this, url, options);
1457
+ return response.blob();
1474
1458
  });
1475
1459
  }
1476
1460
  /**
@@ -1479,18 +1463,18 @@
1479
1463
  * @param code The authorization code received by URL parameter.
1480
1464
  */
1481
1465
  processCode(code) {
1482
- const pkceState = this.storage.getString('pkceState');
1466
+ const pkceState = __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('pkceState');
1483
1467
  if (!pkceState) {
1484
1468
  this.clear();
1485
1469
  throw new Error('Invalid PCKE state');
1486
1470
  }
1487
- const codeVerifier = this.storage.getString('codeVerifier');
1471
+ const codeVerifier = __classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('codeVerifier');
1488
1472
  if (!codeVerifier) {
1489
1473
  this.clear();
1490
1474
  throw new Error('Invalid PCKE code verifier');
1491
1475
  }
1492
- return this.fetchTokens('grant_type=authorization_code' +
1493
- (this.clientId ? '&client_id=' + encodeURIComponent(this.clientId) : '') +
1476
+ return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_fetchTokens).call(this, 'grant_type=authorization_code' +
1477
+ (__classPrivateFieldGet(this, _MedplumClient_clientId, "f") ? '&client_id=' + encodeURIComponent(__classPrivateFieldGet(this, _MedplumClient_clientId, "f")) : '') +
1494
1478
  '&code_verifier=' +
1495
1479
  encodeURIComponent(codeVerifier) +
1496
1480
  '&redirect_uri=' +
@@ -1498,102 +1482,185 @@
1498
1482
  '&code=' +
1499
1483
  encodeURIComponent(code));
1500
1484
  }
1501
- /**
1502
- * Tries to refresh the auth tokens.
1503
- * See: https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokens
1504
- */
1505
- refresh() {
1506
- var _a;
1507
- return __awaiter(this, void 0, void 0, function* () {
1508
- if (this.refreshPromise) {
1509
- return this.refreshPromise;
1510
- }
1511
- const refreshToken = (_a = this.getActiveLogin()) === null || _a === void 0 ? void 0 : _a.refreshToken;
1512
- if (!refreshToken) {
1513
- this.clear();
1514
- return Promise.reject('Invalid refresh token');
1515
- }
1516
- this.refreshPromise = this.fetchTokens('grant_type=refresh_token' +
1517
- '&client_id=' +
1518
- encodeURIComponent(this.clientId) +
1519
- '&refresh_token=' +
1520
- encodeURIComponent(refreshToken));
1521
- yield this.refreshPromise;
1522
- });
1485
+ }
1486
+ _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
+ 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); });
1488
+ logins.push(newLogin);
1489
+ __classPrivateFieldGet(this, _MedplumClient_storage, "f").setObject('logins', logins);
1490
+ }, _MedplumClient_refreshProfile = function _MedplumClient_refreshProfile() {
1491
+ return __awaiter(this, void 0, void 0, function* () {
1492
+ __classPrivateFieldSet(this, _MedplumClient_profilePromise, new Promise((resolve, reject) => {
1493
+ this.get('auth/me')
1494
+ .then((result) => {
1495
+ __classPrivateFieldSet(this, _MedplumClient_profilePromise, undefined, "f");
1496
+ __classPrivateFieldSet(this, _MedplumClient_profile, result.profile, "f");
1497
+ __classPrivateFieldSet(this, _MedplumClient_config, result.config, "f");
1498
+ this.dispatchEvent({ type: 'change' });
1499
+ resolve(__classPrivateFieldGet(this, _MedplumClient_profile, "f"));
1500
+ })
1501
+ .catch(reject);
1502
+ }), "f");
1503
+ return __classPrivateFieldGet(this, _MedplumClient_profilePromise, "f");
1504
+ });
1505
+ }, _MedplumClient_request = function _MedplumClient_request(method, url, contentType, body) {
1506
+ return __awaiter(this, void 0, void 0, function* () {
1507
+ if (__classPrivateFieldGet(this, _MedplumClient_refreshPromise, "f")) {
1508
+ yield __classPrivateFieldGet(this, _MedplumClient_refreshPromise, "f");
1509
+ }
1510
+ if (!url.startsWith('http')) {
1511
+ url = __classPrivateFieldGet(this, _MedplumClient_baseUrl, "f") + url;
1512
+ }
1513
+ const options = __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_buildFetchOptions).call(this, method, contentType, body);
1514
+ const response = yield __classPrivateFieldGet(this, _MedplumClient_fetch, "f").call(this, url, options);
1515
+ if (response.status === 401) {
1516
+ // Refresh and try again
1517
+ return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_handleUnauthenticated).call(this, method, url, contentType, body);
1518
+ }
1519
+ if (response.status === 204 || response.status === 304) {
1520
+ // No content or change
1521
+ return undefined;
1522
+ }
1523
+ const obj = yield response.json();
1524
+ if (obj.resourceType === 'OperationOutcome' && !isOk(obj)) {
1525
+ return Promise.reject(obj);
1526
+ }
1527
+ return obj;
1528
+ });
1529
+ }, _MedplumClient_buildFetchOptions = function _MedplumClient_buildFetchOptions(method, contentType, body) {
1530
+ const headers = {
1531
+ 'Content-Type': contentType || FHIR_CONTENT_TYPE,
1532
+ };
1533
+ if (__classPrivateFieldGet(this, _MedplumClient_accessToken, "f")) {
1534
+ headers['Authorization'] = 'Bearer ' + __classPrivateFieldGet(this, _MedplumClient_accessToken, "f");
1535
+ }
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
+ }
1523
1549
  }
1524
- /**
1525
- * Makes a POST request to the tokens endpoint.
1526
- * See: https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
1527
- * @param formBody Token parameters in URL encoded format.
1528
- */
1529
- fetchTokens(formBody) {
1530
- return __awaiter(this, void 0, void 0, function* () {
1531
- if (!this.tokenUrl) {
1532
- return Promise.reject('Missing token URL');
1550
+ return options;
1551
+ }, _MedplumClient_handleUnauthenticated = function _MedplumClient_handleUnauthenticated(method, url, contentType, body) {
1552
+ return __awaiter(this, void 0, void 0, function* () {
1553
+ 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))
1555
+ .catch((error) => {
1556
+ this.clear();
1557
+ if (__classPrivateFieldGet(this, _MedplumClient_onUnauthenticated, "f")) {
1558
+ __classPrivateFieldGet(this, _MedplumClient_onUnauthenticated, "f").call(this);
1533
1559
  }
1534
- return this.fetch(this.tokenUrl, {
1535
- method: 'POST',
1536
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
1537
- body: formBody,
1538
- })
1539
- .then((response) => {
1540
- if (!response.ok) {
1541
- return Promise.reject('Failed to fetch tokens');
1542
- }
1543
- return response.json();
1544
- })
1545
- .then((tokens) => this.verifyTokens(tokens))
1546
- .then(() => this.getProfile());
1560
+ return Promise.reject(error);
1547
1561
  });
1548
- }
1549
- /**
1550
- * Verifies the tokens received from the auth server.
1551
- * Validates the JWT against the JWKS.
1552
- * See: https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
1553
- * @param tokens
1554
- */
1555
- verifyTokens(tokens) {
1556
- return __awaiter(this, void 0, void 0, function* () {
1557
- const token = tokens.access_token;
1558
- // Verify token has not expired
1559
- const tokenPayload = parseJWTPayload(token);
1560
- if (Date.now() >= tokenPayload.exp * 1000) {
1561
- this.clear();
1562
- return Promise.reject('Token expired');
1562
+ });
1563
+ }, _MedplumClient_startPkce = function _MedplumClient_startPkce() {
1564
+ return __awaiter(this, void 0, void 0, function* () {
1565
+ const pkceState = getRandomString();
1566
+ __classPrivateFieldGet(this, _MedplumClient_storage, "f").setString('pkceState', pkceState);
1567
+ const codeVerifier = getRandomString();
1568
+ __classPrivateFieldGet(this, _MedplumClient_storage, "f").setString('codeVerifier', codeVerifier);
1569
+ const arrayHash = yield encryptSHA256(codeVerifier);
1570
+ const codeChallenge = arrayBufferToBase64(arrayHash).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
1571
+ __classPrivateFieldGet(this, _MedplumClient_storage, "f").setString('codeChallenge', codeChallenge);
1572
+ });
1573
+ }, _MedplumClient_requestAuthorization = function _MedplumClient_requestAuthorization() {
1574
+ return __awaiter(this, void 0, void 0, function* () {
1575
+ if (!__classPrivateFieldGet(this, _MedplumClient_authorizeUrl, "f")) {
1576
+ throw new Error('Missing authorize URL');
1577
+ }
1578
+ __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_startPkce).call(this);
1579
+ window.location.assign(__classPrivateFieldGet(this, _MedplumClient_authorizeUrl, "f") +
1580
+ '?response_type=code' +
1581
+ '&state=' +
1582
+ encodeURIComponent(__classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('pkceState')) +
1583
+ '&client_id=' +
1584
+ encodeURIComponent(__classPrivateFieldGet(this, _MedplumClient_clientId, "f")) +
1585
+ '&redirect_uri=' +
1586
+ encodeURIComponent(getBaseUrl()) +
1587
+ '&scope=' +
1588
+ encodeURIComponent(DEFAULT_SCOPE) +
1589
+ '&code_challenge_method=S256' +
1590
+ '&code_challenge=' +
1591
+ encodeURIComponent(__classPrivateFieldGet(this, _MedplumClient_storage, "f").getString('codeChallenge')));
1592
+ });
1593
+ }, _MedplumClient_refresh = function _MedplumClient_refresh() {
1594
+ return __awaiter(this, void 0, void 0, function* () {
1595
+ if (__classPrivateFieldGet(this, _MedplumClient_refreshPromise, "f")) {
1596
+ return __classPrivateFieldGet(this, _MedplumClient_refreshPromise, "f");
1597
+ }
1598
+ if (!__classPrivateFieldGet(this, _MedplumClient_refreshToken, "f")) {
1599
+ this.clear();
1600
+ return Promise.reject('Invalid refresh token');
1601
+ }
1602
+ __classPrivateFieldSet(this, _MedplumClient_refreshPromise, __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_fetchTokens).call(this, 'grant_type=refresh_token' +
1603
+ '&client_id=' +
1604
+ encodeURIComponent(__classPrivateFieldGet(this, _MedplumClient_clientId, "f")) +
1605
+ '&refresh_token=' +
1606
+ encodeURIComponent(__classPrivateFieldGet(this, _MedplumClient_refreshToken, "f"))), "f");
1607
+ yield __classPrivateFieldGet(this, _MedplumClient_refreshPromise, "f");
1608
+ });
1609
+ }, _MedplumClient_fetchTokens = function _MedplumClient_fetchTokens(formBody) {
1610
+ return __awaiter(this, void 0, void 0, function* () {
1611
+ if (!__classPrivateFieldGet(this, _MedplumClient_tokenUrl, "f")) {
1612
+ return Promise.reject('Missing token URL');
1613
+ }
1614
+ return __classPrivateFieldGet(this, _MedplumClient_fetch, "f").call(this, __classPrivateFieldGet(this, _MedplumClient_tokenUrl, "f"), {
1615
+ method: 'POST',
1616
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
1617
+ body: formBody,
1618
+ })
1619
+ .then((response) => {
1620
+ if (!response.ok) {
1621
+ return Promise.reject('Failed to fetch tokens');
1563
1622
  }
1564
- // Verify app_client_id
1565
- if (this.clientId && tokenPayload.client_id !== this.clientId) {
1566
- this.clear();
1567
- return Promise.reject('Token was not issued for this audience');
1623
+ return response.json();
1624
+ })
1625
+ .then((tokens) => __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_verifyTokens).call(this, tokens))
1626
+ .then(() => this.getProfile());
1627
+ });
1628
+ }, _MedplumClient_verifyTokens = function _MedplumClient_verifyTokens(tokens) {
1629
+ return __awaiter(this, void 0, void 0, function* () {
1630
+ const token = tokens.access_token;
1631
+ // Verify token has not expired
1632
+ const tokenPayload = parseJWTPayload(token);
1633
+ if (Date.now() >= tokenPayload.exp * 1000) {
1634
+ this.clear();
1635
+ return Promise.reject('Token expired');
1636
+ }
1637
+ // Verify app_client_id
1638
+ if (__classPrivateFieldGet(this, _MedplumClient_clientId, "f") && tokenPayload.client_id !== __classPrivateFieldGet(this, _MedplumClient_clientId, "f")) {
1639
+ this.clear();
1640
+ return Promise.reject('Token was not issued for this audience');
1641
+ }
1642
+ yield this.setActiveLogin({
1643
+ accessToken: token,
1644
+ refreshToken: tokens.refresh_token,
1645
+ project: tokens.project,
1646
+ profile: tokens.profile,
1647
+ });
1648
+ });
1649
+ }, _MedplumClient_setupStorageListener = function _MedplumClient_setupStorageListener() {
1650
+ try {
1651
+ window.addEventListener('storage', (e) => {
1652
+ if (e.key === null || e.key === 'activeLogin') {
1653
+ // Storage events fire when different tabs make changes.
1654
+ // On storage clear (key === null) or activeLogin change (key === 'activeLogin')
1655
+ // Refresh the page to ensure the active login is up to date.
1656
+ window.location.reload();
1568
1657
  }
1569
- yield this.setActiveLogin({
1570
- accessToken: token,
1571
- refreshToken: tokens.refresh_token,
1572
- project: tokens.project,
1573
- profile: tokens.profile,
1574
- });
1575
1658
  });
1576
1659
  }
1577
- /**
1578
- * Sets up a listener for window storage events.
1579
- * This synchronizes state across browser windows and browser tabs.
1580
- */
1581
- setupStorageListener() {
1582
- try {
1583
- window.addEventListener('storage', (e) => {
1584
- if (e.key === null || e.key === 'activeLogin') {
1585
- // Storage events fire when different tabs make changes.
1586
- // On storage clear (key === null) or activeLogin change (key === 'activeLogin')
1587
- // Refresh the page to ensure the active login is up to date.
1588
- window.location.reload();
1589
- }
1590
- });
1591
- }
1592
- catch (err) {
1593
- // Silently ignore if this environment does not support storage events
1594
- }
1660
+ catch (err) {
1661
+ // Silently ignore if this environment does not support storage events
1595
1662
  }
1596
- }
1663
+ };
1597
1664
  /**
1598
1665
  * Returns the base URL for the current page.
1599
1666
  */
@@ -1629,6 +1696,9 @@
1629
1696
  */
1630
1697
  function getSearchParameterDetails(structureDefinitions, resourceType, searchParam) {
1631
1698
  var _a, _b, _c, _d;
1699
+ if (searchParam.code === '_lastUpdated') {
1700
+ return { columnName: 'lastUpdated', type: exports.SearchParameterType.DATETIME };
1701
+ }
1632
1702
  const columnName = convertCodeToColumnName(searchParam.code);
1633
1703
  const expression = (_a = getExpressionForResourceType(resourceType, searchParam.expression)) === null || _a === void 0 ? void 0 : _a.split('.');
1634
1704
  if (!expression) {
@@ -1637,20 +1707,21 @@
1637
1707
  return { columnName, type: exports.SearchParameterType.TEXT };
1638
1708
  }
1639
1709
  let baseType = resourceType;
1710
+ let elementDefinition = undefined;
1640
1711
  let propertyType = undefined;
1641
1712
  let array = false;
1642
1713
  for (let i = 1; i < expression.length; i++) {
1643
1714
  const propertyName = expression[i];
1644
- const propertyDef = (_c = (_b = structureDefinitions.types[baseType]) === null || _b === void 0 ? void 0 : _b.properties) === null || _c === void 0 ? void 0 : _c[propertyName];
1645
- if (!propertyDef) {
1715
+ elementDefinition = (_c = (_b = structureDefinitions.types[baseType]) === null || _b === void 0 ? void 0 : _b.properties) === null || _c === void 0 ? void 0 : _c[propertyName];
1716
+ if (!elementDefinition) {
1646
1717
  // This happens on complex properties such as "collected[x]"/"collectedDateTime"/"collectedPeriod"
1647
1718
  // In the future, explore returning multiple column definitions
1648
1719
  return { columnName, type: exports.SearchParameterType.TEXT, array };
1649
1720
  }
1650
- if (propertyDef.max === '*') {
1721
+ if (elementDefinition.max === '*') {
1651
1722
  array = true;
1652
1723
  }
1653
- propertyType = (_d = propertyDef.type) === null || _d === void 0 ? void 0 : _d[0].code;
1724
+ propertyType = (_d = elementDefinition.type) === null || _d === void 0 ? void 0 : _d[0].code;
1654
1725
  if (!propertyType) {
1655
1726
  // This happens when one of parent properties uses contentReference
1656
1727
  // In the future, explore following the reference
@@ -1666,7 +1737,7 @@
1666
1737
  }
1667
1738
  }
1668
1739
  const type = getSearchParameterType(searchParam, propertyType);
1669
- return { columnName, type, array };
1740
+ return { columnName, type, elementDefinition, array };
1670
1741
  }
1671
1742
  /**
1672
1743
  * Converts a hyphen-delimited code to camelCase string.
@@ -1735,6 +1806,7 @@
1735
1806
  exports.capitalize = capitalize;
1736
1807
  exports.createReference = createReference;
1737
1808
  exports.createSchema = createSchema;
1809
+ exports.createTypeSchema = createTypeSchema;
1738
1810
  exports.created = created;
1739
1811
  exports.deepEquals = deepEquals;
1740
1812
  exports.formatAddress = formatAddress;
@@ -1761,6 +1833,7 @@
1761
1833
  exports.notFound = notFound;
1762
1834
  exports.notModified = notModified;
1763
1835
  exports.parseSearchDefinition = parseSearchDefinition;
1836
+ exports.resolveId = resolveId;
1764
1837
  exports.stringify = stringify;
1765
1838
 
1766
1839
  Object.defineProperty(exports, '__esModule', { value: true });