@medplum/core 2.0.15 → 2.0.16

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.
@@ -10,7 +10,7 @@ import { createReference, arrayBufferToBase64 } from './utils.mjs';
10
10
  import { encodeBase64 } from './base64.mjs';
11
11
 
12
12
  // PKCE auth based on:
13
- const MEDPLUM_VERSION = "2.0.15-025c3c04";
13
+ const MEDPLUM_VERSION = "2.0.16-816ad9bf";
14
14
  const DEFAULT_BASE_URL = 'https://api.medplum.com/';
15
15
  const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
16
16
  const DEFAULT_CACHE_TIME = 60000; // 60 seconds
@@ -18,6 +18,35 @@ const JSON_CONTENT_TYPE = 'application/json';
18
18
  const FHIR_CONTENT_TYPE = 'application/fhir+json';
19
19
  const PATCH_CONTENT_TYPE = 'application/json-patch+json';
20
20
  const system = { resourceType: 'Device', id: 'system', deviceName: [{ name: 'System' }] };
21
+ /**
22
+ * OAuth 2.0 Grant Type Identifiers
23
+ * Standard identifiers defined here: https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-07#name-grant-types
24
+ * Token exchange extension defined here: https://datatracker.ietf.org/doc/html/rfc8693
25
+ */
26
+ var OAuthGrantType;
27
+ (function (OAuthGrantType) {
28
+ OAuthGrantType["ClientCredentials"] = "client_credentials";
29
+ OAuthGrantType["AuthorizationCode"] = "authorization_code";
30
+ OAuthGrantType["RefreshToken"] = "refresh_token";
31
+ OAuthGrantType["TokenExchange"] = "urn:ietf:params:oauth:grant-type:token-exchange";
32
+ })(OAuthGrantType || (OAuthGrantType = {}));
33
+ /**
34
+ * OAuth 2.0 Token Type Identifiers
35
+ * See: https://datatracker.ietf.org/doc/html/rfc8693#name-token-type-identifiers
36
+ */
37
+ var OAuthTokenType;
38
+ (function (OAuthTokenType) {
39
+ /** Indicates that the token is an OAuth 2.0 access token issued by the given authorization server. */
40
+ OAuthTokenType["AccessToken"] = "urn:ietf:params:oauth:token-type:access_token";
41
+ /** Indicates that the token is an OAuth 2.0 refresh token issued by the given authorization server. */
42
+ OAuthTokenType["RefreshToken"] = "urn:ietf:params:oauth:token-type:refresh_token";
43
+ /** Indicates that the token is an ID Token as defined in Section 2 of [OpenID.Core]. */
44
+ OAuthTokenType["IdToken"] = "urn:ietf:params:oauth:token-type:id_token";
45
+ /** Indicates that the token is a base64url-encoded SAML 1.1 [OASIS.saml-core-1.1] assertion. */
46
+ OAuthTokenType["Saml1Token"] = "urn:ietf:params:oauth:token-type:saml1";
47
+ /** Indicates that the token is a base64url-encoded SAML 2.0 [OASIS.saml-core-2.0-os] assertion. */
48
+ OAuthTokenType["Saml2Token"] = "urn:ietf:params:oauth:token-type:saml2";
49
+ })(OAuthTokenType || (OAuthTokenType = {}));
21
50
  /**
22
51
  * The MedplumClient class provides a client for the Medplum FHIR server.
23
52
  *
@@ -87,7 +116,6 @@ class MedplumClient extends EventTarget {
87
116
  this.authorizeUrl = options?.authorizeUrl || this.baseUrl + 'oauth2/authorize';
88
117
  this.tokenUrl = options?.tokenUrl || this.baseUrl + 'oauth2/token';
89
118
  this.logoutUrl = options?.logoutUrl || this.baseUrl + 'oauth2/logout';
90
- this.exchangeUrl = this.baseUrl + 'auth/exchange';
91
119
  this.onUnauthenticated = options?.onUnauthenticated;
92
120
  this.cacheTime = options?.cacheTime ?? DEFAULT_CACHE_TIME;
93
121
  if (this.cacheTime > 0) {
@@ -159,7 +187,7 @@ class MedplumClient extends EventTarget {
159
187
  * @param resourceType The resource type to invalidate.
160
188
  */
161
189
  invalidateSearches(resourceType) {
162
- const url = 'fhir/R4/' + resourceType;
190
+ const url = this.fhirBaseUrl + resourceType;
163
191
  if (this.requestCache) {
164
192
  for (const key of this.requestCache.keys()) {
165
193
  if (key.endsWith(url) || key.includes(url + '?')) {
@@ -437,22 +465,12 @@ class MedplumClient extends EventTarget {
437
465
  if (!clientId) {
438
466
  throw new Error('MedplumClient is missing clientId');
439
467
  }
440
- const response = await this.fetch(this.exchangeUrl, {
441
- method: 'POST',
442
- headers: { 'Content-Type': 'application/json' },
443
- body: JSON.stringify({
444
- clientId: this.clientId,
445
- externalAccessToken: token,
446
- }),
447
- credentials: 'include',
448
- });
449
- if (!response.ok) {
450
- this.clearActiveLogin();
451
- throw new Error('Failed to fetch tokens');
452
- }
453
- const tokens = await response.json();
454
- await this.verifyTokens(tokens);
455
- return this.getProfile();
468
+ const formBody = new URLSearchParams();
469
+ formBody.set('grant_type', OAuthGrantType.TokenExchange);
470
+ formBody.set('subject_token_type', OAuthTokenType.AccessToken);
471
+ formBody.set('client_id', clientId);
472
+ formBody.set('subject_token', token);
473
+ return this.fetchTokens(formBody);
456
474
  }
457
475
  /**
458
476
  * Builds the external identity provider redirect URI.
@@ -1284,7 +1302,7 @@ class MedplumClient extends EventTarget {
1284
1302
  * @returns The FHIR batch/transaction response bundle.
1285
1303
  */
1286
1304
  executeBatch(bundle) {
1287
- return this.post('fhir/R4', bundle);
1305
+ return this.post(this.fhirBaseUrl.slice(0, -1), bundle);
1288
1306
  }
1289
1307
  /**
1290
1308
  * Sends an email using the Medplum Email API.
@@ -1628,7 +1646,7 @@ class MedplumClient extends EventTarget {
1628
1646
  })),
1629
1647
  };
1630
1648
  // Execute the batch request
1631
- const response = (await this.post('fhir/R4', batch));
1649
+ const response = (await this.post(this.fhirBaseUrl.slice(0, -1), batch));
1632
1650
  // Process the response
1633
1651
  for (let i = 0; i < entries.length; i++) {
1634
1652
  const entry = entries[i];
@@ -1756,7 +1774,7 @@ class MedplumClient extends EventTarget {
1756
1774
  */
1757
1775
  processCode(code, loginParams) {
1758
1776
  const formBody = new URLSearchParams();
1759
- formBody.set('grant_type', 'authorization_code');
1777
+ formBody.set('grant_type', OAuthGrantType.AuthorizationCode);
1760
1778
  formBody.set('code', code);
1761
1779
  formBody.set('client_id', loginParams?.clientId || this.clientId);
1762
1780
  formBody.set('redirect_uri', loginParams?.redirectUri || getWindowOrigin());
@@ -1778,7 +1796,7 @@ class MedplumClient extends EventTarget {
1778
1796
  }
1779
1797
  if (this.refreshToken) {
1780
1798
  const formBody = new URLSearchParams();
1781
- formBody.set('grant_type', 'refresh_token');
1799
+ formBody.set('grant_type', OAuthGrantType.RefreshToken);
1782
1800
  formBody.set('client_id', this.clientId);
1783
1801
  formBody.set('refresh_token', this.refreshToken);
1784
1802
  this.refreshPromise = this.fetchTokens(formBody);
@@ -1802,7 +1820,7 @@ class MedplumClient extends EventTarget {
1802
1820
  this.clientId = clientId;
1803
1821
  this.clientSecret = clientSecret;
1804
1822
  const formBody = new URLSearchParams();
1805
- formBody.set('grant_type', 'client_credentials');
1823
+ formBody.set('grant_type', OAuthGrantType.ClientCredentials);
1806
1824
  formBody.set('client_id', clientId);
1807
1825
  formBody.set('client_secret', clientSecret);
1808
1826
  return this.fetchTokens(formBody);
@@ -1922,5 +1940,5 @@ function ensureTrailingSlash(url) {
1922
1940
  return url.endsWith('/') ? url : url + '/';
1923
1941
  }
1924
1942
 
1925
- export { MEDPLUM_VERSION, MedplumClient };
1943
+ export { MEDPLUM_VERSION, MedplumClient, OAuthGrantType, OAuthTokenType };
1926
1944
  //# sourceMappingURL=client.mjs.map