@medplum/core 1.0.6 → 2.0.0
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/client.d.ts +22 -6
- package/dist/cjs/index.cjs +67 -50
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.min.cjs +1 -1
- package/dist/cjs/utils.d.ts +8 -1
- package/dist/esm/client.d.ts +22 -6
- package/dist/esm/client.mjs +51 -50
- package/dist/esm/client.mjs.map +1 -1
- package/dist/esm/index.min.mjs +1 -1
- package/dist/esm/index.mjs +1 -1
- package/dist/esm/utils.d.ts +8 -1
- package/dist/esm/utils.mjs +16 -1
- package/dist/esm/utils.mjs.map +1 -1
- package/package.json +1 -1
package/dist/cjs/client.d.ts
CHANGED
|
@@ -146,6 +146,7 @@ export interface BaseLoginRequest {
|
|
|
146
146
|
readonly codeChallengeMethod?: string;
|
|
147
147
|
readonly googleClientId?: string;
|
|
148
148
|
readonly launch?: string;
|
|
149
|
+
readonly redirectUri?: string;
|
|
149
150
|
}
|
|
150
151
|
export interface EmailPasswordLoginRequest extends BaseLoginRequest {
|
|
151
152
|
readonly email: string;
|
|
@@ -338,6 +339,12 @@ export declare class MedplumClient extends EventTarget {
|
|
|
338
339
|
* @category Authentication
|
|
339
340
|
*/
|
|
340
341
|
clear(): void;
|
|
342
|
+
/**
|
|
343
|
+
* Clears the active login from local storage.
|
|
344
|
+
* Does not clear all local storage (such as other logins).
|
|
345
|
+
* @category Authentication
|
|
346
|
+
*/
|
|
347
|
+
clearActiveLogin(): void;
|
|
341
348
|
/**
|
|
342
349
|
* Invalidates any cached values or cached requests for the given URL.
|
|
343
350
|
* @category Caching
|
|
@@ -467,10 +474,15 @@ export declare class MedplumClient extends EventTarget {
|
|
|
467
474
|
* @returns Promise to the authentication response.
|
|
468
475
|
*/
|
|
469
476
|
startGoogleLogin(loginRequest: GoogleLoginRequest): Promise<LoginAuthenticationResponse>;
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
477
|
+
/**
|
|
478
|
+
* Returns the PKCE code challenge and method.
|
|
479
|
+
* If the login request already includes a code challenge, it is returned.
|
|
480
|
+
* Otherwise, a new PKCE code challenge is generated.
|
|
481
|
+
* @category Authentication
|
|
482
|
+
* @param loginRequest The original login request.
|
|
483
|
+
* @returns The PKCE code challenge and method.
|
|
484
|
+
*/
|
|
485
|
+
ensureCodeChallenge<T extends BaseLoginRequest>(loginRequest: T): Promise<T>;
|
|
474
486
|
/**
|
|
475
487
|
* Signs out locally.
|
|
476
488
|
* Does not invalidate tokens with the server.
|
|
@@ -482,8 +494,9 @@ export declare class MedplumClient extends EventTarget {
|
|
|
482
494
|
* Returns true if the user is signed in.
|
|
483
495
|
* This may result in navigating away to the sign in page.
|
|
484
496
|
* @category Authentication
|
|
497
|
+
* @param loginParams Optional login parameters.
|
|
485
498
|
*/
|
|
486
|
-
signInWithRedirect(): Promise<ProfileResource | void>;
|
|
499
|
+
signInWithRedirect(loginParams?: Partial<BaseLoginRequest>): Promise<ProfileResource | void>;
|
|
487
500
|
/**
|
|
488
501
|
* Tries to sign out the user.
|
|
489
502
|
* See: https://docs.aws.amazon.com/cognito/latest/developerguide/logout-endpoint.html
|
|
@@ -1154,7 +1167,10 @@ export declare class MedplumClient extends EventTarget {
|
|
|
1154
1167
|
* Starts a new PKCE flow.
|
|
1155
1168
|
* These PKCE values are stateful, and must survive redirects and page refreshes.
|
|
1156
1169
|
*/
|
|
1157
|
-
startPkce(): Promise<
|
|
1170
|
+
startPkce(): Promise<{
|
|
1171
|
+
codeChallengeMethod: string;
|
|
1172
|
+
codeChallenge: string;
|
|
1173
|
+
}>;
|
|
1158
1174
|
/**
|
|
1159
1175
|
* Processes an OAuth authorization code.
|
|
1160
1176
|
* See: https://openid.net/specs/openid-connect-core-1_0.html#TokenRequest
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -721,6 +721,21 @@
|
|
|
721
721
|
}
|
|
722
722
|
return curr?.valueString;
|
|
723
723
|
}
|
|
724
|
+
/**
|
|
725
|
+
* Returns an extension by extension URLs.
|
|
726
|
+
* @param resource The base resource.
|
|
727
|
+
* @param urls Array of extension URLs. Each entry represents a nested extension.
|
|
728
|
+
* @returns The extension object if found; undefined otherwise.
|
|
729
|
+
*/
|
|
730
|
+
function getExtension(resource, ...urls) {
|
|
731
|
+
// Let curr be the current resource or extension. Extensions can be nested.
|
|
732
|
+
let curr = resource;
|
|
733
|
+
// For each of the urls, try to find a matching nested extension.
|
|
734
|
+
for (let i = 0; i < urls.length && curr; i++) {
|
|
735
|
+
curr = curr?.extension?.find((e) => e.url === urls[i]);
|
|
736
|
+
}
|
|
737
|
+
return curr;
|
|
738
|
+
}
|
|
724
739
|
/**
|
|
725
740
|
* FHIR JSON stringify.
|
|
726
741
|
* Removes properties with empty string values.
|
|
@@ -6468,7 +6483,7 @@
|
|
|
6468
6483
|
// PKCE auth based on:
|
|
6469
6484
|
// https://aws.amazon.com/blogs/security/how-to-add-authentication-single-page-web-application-with-amazon-cognito-oauth2-implementation/
|
|
6470
6485
|
var _MedplumClient_instances, _MedplumClient_fetch, _MedplumClient_createPdf, _MedplumClient_storage, _MedplumClient_requestCache, _MedplumClient_cacheTime, _MedplumClient_baseUrl, _MedplumClient_authorizeUrl, _MedplumClient_tokenUrl, _MedplumClient_logoutUrl, _MedplumClient_onUnauthenticated, _MedplumClient_clientId, _MedplumClient_clientSecret, _MedplumClient_accessToken, _MedplumClient_refreshToken, _MedplumClient_refreshPromise, _MedplumClient_profilePromise, _MedplumClient_profile, _MedplumClient_config, _MedplumClient_addLogin, _MedplumClient_refreshProfile, _MedplumClient_getCacheEntry, _MedplumClient_setCacheEntry, _MedplumClient_request, _MedplumClient_addFetchOptionsDefaults, _MedplumClient_setRequestContentType, _MedplumClient_setRequestBody, _MedplumClient_handleUnauthenticated, _MedplumClient_requestAuthorization, _MedplumClient_refresh, _MedplumClient_fetchTokens, _MedplumClient_verifyTokens, _MedplumClient_setupStorageListener;
|
|
6471
|
-
const MEDPLUM_VERSION = "
|
|
6486
|
+
const MEDPLUM_VERSION = "2.0.0-7fe99080";
|
|
6472
6487
|
const DEFAULT_BASE_URL = 'https://api.medplum.com/';
|
|
6473
6488
|
const DEFAULT_RESOURCE_CACHE_SIZE = 1000;
|
|
6474
6489
|
const DEFAULT_CACHE_TIME = 60000; // 60 seconds
|
|
@@ -6589,6 +6604,15 @@
|
|
|
6589
6604
|
*/
|
|
6590
6605
|
clear() {
|
|
6591
6606
|
__classPrivateFieldGet(this, _MedplumClient_storage, "f").clear();
|
|
6607
|
+
this.clearActiveLogin();
|
|
6608
|
+
}
|
|
6609
|
+
/**
|
|
6610
|
+
* Clears the active login from local storage.
|
|
6611
|
+
* Does not clear all local storage (such as other logins).
|
|
6612
|
+
* @category Authentication
|
|
6613
|
+
*/
|
|
6614
|
+
clearActiveLogin() {
|
|
6615
|
+
__classPrivateFieldGet(this, _MedplumClient_storage, "f").setString('activeLogin', undefined);
|
|
6592
6616
|
__classPrivateFieldGet(this, _MedplumClient_requestCache, "f").clear();
|
|
6593
6617
|
__classPrivateFieldSet(this, _MedplumClient_accessToken, undefined, "f");
|
|
6594
6618
|
__classPrivateFieldSet(this, _MedplumClient_refreshToken, undefined, "f");
|
|
@@ -6740,11 +6764,11 @@
|
|
|
6740
6764
|
* @returns Promise to the authentication response.
|
|
6741
6765
|
*/
|
|
6742
6766
|
async startNewUser(newUserRequest) {
|
|
6743
|
-
await this.startPkce();
|
|
6767
|
+
const { codeChallengeMethod, codeChallenge } = await this.startPkce();
|
|
6744
6768
|
return this.post('auth/newuser', {
|
|
6745
6769
|
...newUserRequest,
|
|
6746
|
-
codeChallengeMethod
|
|
6747
|
-
codeChallenge
|
|
6770
|
+
codeChallengeMethod,
|
|
6771
|
+
codeChallenge,
|
|
6748
6772
|
});
|
|
6749
6773
|
}
|
|
6750
6774
|
/**
|
|
@@ -6776,13 +6800,10 @@
|
|
|
6776
6800
|
* @returns Promise to the authentication response.
|
|
6777
6801
|
*/
|
|
6778
6802
|
async startLogin(loginRequest) {
|
|
6779
|
-
const { codeChallenge, codeChallengeMethod } = this.getCodeChallenge(loginRequest);
|
|
6780
6803
|
return this.post('auth/login', {
|
|
6781
|
-
...loginRequest,
|
|
6804
|
+
...(await this.ensureCodeChallenge(loginRequest)),
|
|
6782
6805
|
clientId: loginRequest.clientId ?? __classPrivateFieldGet(this, _MedplumClient_clientId, "f"),
|
|
6783
6806
|
scope: loginRequest.scope,
|
|
6784
|
-
codeChallengeMethod,
|
|
6785
|
-
codeChallenge,
|
|
6786
6807
|
});
|
|
6787
6808
|
}
|
|
6788
6809
|
/**
|
|
@@ -6794,30 +6815,25 @@
|
|
|
6794
6815
|
* @returns Promise to the authentication response.
|
|
6795
6816
|
*/
|
|
6796
6817
|
async startGoogleLogin(loginRequest) {
|
|
6797
|
-
const { codeChallenge, codeChallengeMethod } = this.getCodeChallenge(loginRequest);
|
|
6798
6818
|
return this.post('auth/google', {
|
|
6799
|
-
...loginRequest,
|
|
6819
|
+
...(await this.ensureCodeChallenge(loginRequest)),
|
|
6800
6820
|
clientId: loginRequest.clientId ?? __classPrivateFieldGet(this, _MedplumClient_clientId, "f"),
|
|
6801
6821
|
scope: loginRequest.scope,
|
|
6802
|
-
codeChallengeMethod,
|
|
6803
|
-
codeChallenge,
|
|
6804
6822
|
});
|
|
6805
6823
|
}
|
|
6806
|
-
|
|
6824
|
+
/**
|
|
6825
|
+
* Returns the PKCE code challenge and method.
|
|
6826
|
+
* If the login request already includes a code challenge, it is returned.
|
|
6827
|
+
* Otherwise, a new PKCE code challenge is generated.
|
|
6828
|
+
* @category Authentication
|
|
6829
|
+
* @param loginRequest The original login request.
|
|
6830
|
+
* @returns The PKCE code challenge and method.
|
|
6831
|
+
*/
|
|
6832
|
+
async ensureCodeChallenge(loginRequest) {
|
|
6807
6833
|
if (loginRequest.codeChallenge) {
|
|
6808
|
-
return
|
|
6809
|
-
codeChallenge: loginRequest.codeChallenge,
|
|
6810
|
-
codeChallengeMethod: loginRequest.codeChallengeMethod,
|
|
6811
|
-
};
|
|
6812
|
-
}
|
|
6813
|
-
const codeChallenge = sessionStorage.getItem('codeChallenge');
|
|
6814
|
-
if (codeChallenge) {
|
|
6815
|
-
return {
|
|
6816
|
-
codeChallenge,
|
|
6817
|
-
codeChallengeMethod: 'S256',
|
|
6818
|
-
};
|
|
6834
|
+
return loginRequest;
|
|
6819
6835
|
}
|
|
6820
|
-
return {};
|
|
6836
|
+
return { ...loginRequest, ...(await this.startPkce()) };
|
|
6821
6837
|
}
|
|
6822
6838
|
/**
|
|
6823
6839
|
* Signs out locally.
|
|
@@ -6832,12 +6848,13 @@
|
|
|
6832
6848
|
* Returns true if the user is signed in.
|
|
6833
6849
|
* This may result in navigating away to the sign in page.
|
|
6834
6850
|
* @category Authentication
|
|
6851
|
+
* @param loginParams Optional login parameters.
|
|
6835
6852
|
*/
|
|
6836
|
-
async signInWithRedirect() {
|
|
6853
|
+
async signInWithRedirect(loginParams) {
|
|
6837
6854
|
const urlParams = new URLSearchParams(window.location.search);
|
|
6838
6855
|
const code = urlParams.get('code');
|
|
6839
6856
|
if (!code) {
|
|
6840
|
-
await __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_requestAuthorization).call(this);
|
|
6857
|
+
await __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_requestAuthorization).call(this, loginParams);
|
|
6841
6858
|
return undefined;
|
|
6842
6859
|
}
|
|
6843
6860
|
else {
|
|
@@ -7690,13 +7707,11 @@
|
|
|
7690
7707
|
* @category Authentication
|
|
7691
7708
|
*/
|
|
7692
7709
|
async setActiveLogin(login) {
|
|
7710
|
+
this.clearActiveLogin();
|
|
7693
7711
|
__classPrivateFieldSet(this, _MedplumClient_accessToken, login.accessToken, "f");
|
|
7694
7712
|
__classPrivateFieldSet(this, _MedplumClient_refreshToken, login.refreshToken, "f");
|
|
7695
|
-
__classPrivateFieldSet(this, _MedplumClient_profile, undefined, "f");
|
|
7696
|
-
__classPrivateFieldSet(this, _MedplumClient_config, undefined, "f");
|
|
7697
7713
|
__classPrivateFieldGet(this, _MedplumClient_storage, "f").setObject('activeLogin', login);
|
|
7698
7714
|
__classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_addLogin).call(this, login);
|
|
7699
|
-
__classPrivateFieldGet(this, _MedplumClient_requestCache, "f").clear();
|
|
7700
7715
|
__classPrivateFieldSet(this, _MedplumClient_refreshPromise, undefined, "f");
|
|
7701
7716
|
await __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_refreshProfile).call(this);
|
|
7702
7717
|
}
|
|
@@ -7775,6 +7790,7 @@
|
|
|
7775
7790
|
const arrayHash = await encryptSHA256(codeVerifier);
|
|
7776
7791
|
const codeChallenge = arrayBufferToBase64(arrayHash).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
|
|
7777
7792
|
sessionStorage.setItem('codeChallenge', codeChallenge);
|
|
7793
|
+
return { codeChallengeMethod: 'S256', codeChallenge };
|
|
7778
7794
|
}
|
|
7779
7795
|
/**
|
|
7780
7796
|
* Processes an OAuth authorization code.
|
|
@@ -7910,7 +7926,7 @@
|
|
|
7910
7926
|
if (__classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_refresh).call(this)) {
|
|
7911
7927
|
return __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_request).call(this, method, url, options);
|
|
7912
7928
|
}
|
|
7913
|
-
this.
|
|
7929
|
+
this.clearActiveLogin();
|
|
7914
7930
|
if (__classPrivateFieldGet(this, _MedplumClient_onUnauthenticated, "f")) {
|
|
7915
7931
|
__classPrivateFieldGet(this, _MedplumClient_onUnauthenticated, "f").call(this);
|
|
7916
7932
|
}
|
|
@@ -7921,15 +7937,16 @@
|
|
|
7921
7937
|
* Clears all auth state including local storage and session storage.
|
|
7922
7938
|
* See: https://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint
|
|
7923
7939
|
*/
|
|
7924
|
-
async function _MedplumClient_requestAuthorization() {
|
|
7925
|
-
await this.
|
|
7940
|
+
async function _MedplumClient_requestAuthorization(loginParams) {
|
|
7941
|
+
const loginRequest = await this.ensureCodeChallenge(loginParams || {});
|
|
7926
7942
|
const url = new URL(__classPrivateFieldGet(this, _MedplumClient_authorizeUrl, "f"));
|
|
7927
7943
|
url.searchParams.set('response_type', 'code');
|
|
7928
7944
|
url.searchParams.set('state', sessionStorage.getItem('pkceState'));
|
|
7929
|
-
url.searchParams.set('client_id', __classPrivateFieldGet(this, _MedplumClient_clientId, "f"));
|
|
7930
|
-
url.searchParams.set('redirect_uri', getBaseUrl());
|
|
7931
|
-
url.searchParams.set('code_challenge_method',
|
|
7932
|
-
url.searchParams.set('code_challenge',
|
|
7945
|
+
url.searchParams.set('client_id', loginRequest.clientId || __classPrivateFieldGet(this, _MedplumClient_clientId, "f"));
|
|
7946
|
+
url.searchParams.set('redirect_uri', loginRequest.redirectUri || getBaseUrl());
|
|
7947
|
+
url.searchParams.set('code_challenge_method', loginRequest.codeChallengeMethod);
|
|
7948
|
+
url.searchParams.set('code_challenge', loginRequest.codeChallenge);
|
|
7949
|
+
url.searchParams.set('scope', loginRequest.scope || 'openid profile');
|
|
7933
7950
|
window.location.assign(url.toString());
|
|
7934
7951
|
}, _MedplumClient_refresh = function _MedplumClient_refresh() {
|
|
7935
7952
|
if (__classPrivateFieldGet(this, _MedplumClient_refreshPromise, "f")) {
|
|
@@ -7955,20 +7972,19 @@
|
|
|
7955
7972
|
* @param formBody Token parameters in URL encoded format.
|
|
7956
7973
|
*/
|
|
7957
7974
|
async function _MedplumClient_fetchTokens(formBody) {
|
|
7958
|
-
|
|
7975
|
+
const response = await __classPrivateFieldGet(this, _MedplumClient_fetch, "f").call(this, __classPrivateFieldGet(this, _MedplumClient_tokenUrl, "f"), {
|
|
7959
7976
|
method: 'POST',
|
|
7960
7977
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
7961
7978
|
body: formBody,
|
|
7962
7979
|
credentials: 'include',
|
|
7963
|
-
})
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
.then(() => this.getProfile());
|
|
7980
|
+
});
|
|
7981
|
+
if (!response.ok) {
|
|
7982
|
+
this.clearActiveLogin();
|
|
7983
|
+
throw new Error('Failed to fetch tokens');
|
|
7984
|
+
}
|
|
7985
|
+
const tokens = await response.json();
|
|
7986
|
+
await __classPrivateFieldGet(this, _MedplumClient_instances, "m", _MedplumClient_verifyTokens).call(this, tokens);
|
|
7987
|
+
return this.getProfile();
|
|
7972
7988
|
}, _MedplumClient_verifyTokens =
|
|
7973
7989
|
/**
|
|
7974
7990
|
* Verifies the tokens received from the auth server.
|
|
@@ -7981,15 +7997,15 @@
|
|
|
7981
7997
|
// Verify token has not expired
|
|
7982
7998
|
const tokenPayload = parseJWTPayload(token);
|
|
7983
7999
|
if (Date.now() >= tokenPayload.exp * 1000) {
|
|
7984
|
-
this.
|
|
8000
|
+
this.clearActiveLogin();
|
|
7985
8001
|
throw new Error('Token expired');
|
|
7986
8002
|
}
|
|
7987
8003
|
// Verify app_client_id
|
|
7988
8004
|
if (__classPrivateFieldGet(this, _MedplumClient_clientId, "f") && tokenPayload.client_id !== __classPrivateFieldGet(this, _MedplumClient_clientId, "f")) {
|
|
7989
|
-
this.
|
|
8005
|
+
this.clearActiveLogin();
|
|
7990
8006
|
throw new Error('Token was not issued for this audience');
|
|
7991
8007
|
}
|
|
7992
|
-
|
|
8008
|
+
return this.setActiveLogin({
|
|
7993
8009
|
accessToken: token,
|
|
7994
8010
|
refreshToken: tokens.refresh_token,
|
|
7995
8011
|
project: tokens.project,
|
|
@@ -11731,6 +11747,7 @@
|
|
|
11731
11747
|
exports.getDisplayString = getDisplayString;
|
|
11732
11748
|
exports.getElementDefinition = getElementDefinition;
|
|
11733
11749
|
exports.getExpressionForResourceType = getExpressionForResourceType;
|
|
11750
|
+
exports.getExtension = getExtension;
|
|
11734
11751
|
exports.getExtensionValue = getExtensionValue;
|
|
11735
11752
|
exports.getIdentifier = getIdentifier;
|
|
11736
11753
|
exports.getImageSrc = getImageSrc;
|