@propelauth/react
Advanced tools
Comparing version 1.2.4 to 1.2.5
@@ -394,281 +394,2 @@ 'use strict'; | ||
const AuthContext = /*#__PURE__*/React__default["default"].createContext(undefined); | ||
const initialAuthInfoState = { | ||
loading: true, | ||
authInfo: null | ||
}; | ||
function authInfoStateReducer(_state, action) { | ||
return { | ||
loading: false, | ||
authInfo: action.authInfo | ||
}; | ||
} | ||
const AuthProvider = props => { | ||
const [authInfoState, dispatch] = React.useReducer(authInfoStateReducer, initialAuthInfoState); | ||
const [heartbeatCounter, setHeartbeatCounter] = React.useState(0); | ||
const [userSelectedOrgId, setUserSelectedOrgId] = React.useState(null); | ||
const triggerRefreshAuthentication = () => setHeartbeatCounter(x => x + 1); // Create client and register observer | ||
const client = React.useMemo(() => { | ||
// Disable background token refresh as we will do it within React instead | ||
const client = createClient({ | ||
authUrl: props.authUrl, | ||
enableBackgroundTokenRefresh: false | ||
}); | ||
client.addLoggedInChangeObserver(triggerRefreshAuthentication); | ||
return client; | ||
}, [props.authUrl]); // On unmount, destroy the client | ||
React.useEffect(() => { | ||
return () => { | ||
client.destroy(); | ||
}; | ||
}, []); // Periodically refresh the token. The client will only make requests when the authInfo is stale | ||
// Errors are logged and the token will be invalidated separately | ||
React.useEffect(() => { | ||
let didCancel = false; | ||
async function refreshToken() { | ||
try { | ||
const authInfo = await client.getAuthenticationInfoOrNull(); | ||
if (!didCancel) { | ||
dispatch({ | ||
authInfo | ||
}); | ||
} | ||
} catch (err) { | ||
console.error("Authentication error", err); | ||
} | ||
} | ||
refreshToken(); | ||
return () => { | ||
didCancel = true; | ||
}; | ||
}, [client, heartbeatCounter]); | ||
React.useEffect(() => { | ||
const interval = setInterval(triggerRefreshAuthentication, 60000); | ||
return () => clearInterval(interval); | ||
}, []); // Watchdog timer to make sure that if we hit the expiration we get rid of the token. | ||
// This should only be triggered if we are unable to get a new token due to an unexpected error/network timeouts. | ||
const expiresAtSeconds = authInfoState.authInfo ? authInfoState.authInfo.expiresAtSeconds : 0; | ||
React.useEffect(() => { | ||
if (!authInfoState.authInfo) { | ||
return; | ||
} | ||
const millisUntilTokenExpires = getMillisUntilTokenExpires(authInfoState.authInfo.expiresAtSeconds); | ||
const timeout = setTimeout(() => { | ||
dispatch({ | ||
authInfo: null | ||
}); | ||
}, millisUntilTokenExpires); | ||
return () => clearTimeout(timeout); | ||
}, [expiresAtSeconds]); | ||
const logout = React.useCallback(client.logout, []); | ||
const redirectToLoginPage = React.useCallback(client.redirectToLoginPage, []); | ||
const redirectToSignupPage = React.useCallback(client.redirectToSignupPage, []); | ||
const redirectToAccountPage = React.useCallback(client.redirectToAccountPage, []); | ||
const redirectToOrgPage = React.useCallback(client.redirectToOrgPage, []); | ||
const redirectToCreateOrgPage = React.useCallback(client.redirectToCreateOrgPage, []); | ||
const value = { | ||
loading: authInfoState.loading, | ||
triggerRefreshAuthentication, | ||
authInfo: authInfoState.authInfo, | ||
logout, | ||
userSelectedOrgId, | ||
selectOrgId: setUserSelectedOrgId, | ||
redirectToLoginPage, | ||
redirectToSignupPage, | ||
redirectToAccountPage, | ||
redirectToOrgPage, | ||
redirectToCreateOrgPage | ||
}; | ||
return /*#__PURE__*/React__default["default"].createElement(AuthContext.Provider, { | ||
value: value | ||
}, props.children); | ||
}; | ||
function getMillisUntilTokenExpires(expiresAtSeconds) { | ||
let millisUntilTokenExpires = expiresAtSeconds * 1000 - Date.now(); | ||
return Math.max(0, millisUntilTokenExpires); | ||
} | ||
function getOrgHelper(orgIdToOrgMemberInfo, selectOrgId, userSelectedOrgId) { | ||
return { | ||
getOrg(orgId) { | ||
if (orgIdToOrgMemberInfo.hasOwnProperty(orgId)) { | ||
return orgIdToOrgMemberInfo[orgId]; | ||
} else { | ||
return undefined; | ||
} | ||
}, | ||
getOrgIds() { | ||
return Object.keys(orgIdToOrgMemberInfo); | ||
}, | ||
getOrgs() { | ||
return Object.values(orgIdToOrgMemberInfo); | ||
}, | ||
getSelectedOrg(inferDefault) { | ||
// default for inferDefault is true | ||
inferDefault = inferDefault === undefined ? true : inferDefault; // if the user has selected an org already, return it | ||
if (userSelectedOrgId && orgIdToOrgMemberInfo.hasOwnProperty(userSelectedOrgId)) { | ||
return orgIdToOrgMemberInfo[userSelectedOrgId]; | ||
} else if (!inferDefault) { | ||
return undefined; | ||
} // otherwise, infer it from local storage | ||
const previouslySelectedOrgId = loadOrgSelectionFromLocalStorage(); | ||
if (previouslySelectedOrgId && orgIdToOrgMemberInfo.hasOwnProperty(previouslySelectedOrgId)) { | ||
return orgIdToOrgMemberInfo[previouslySelectedOrgId]; | ||
} // if the user has never selected one before, select one deterministically by name | ||
let alphabeticallyFirstOrgName = undefined; | ||
let alphabeticallyFirstOrg = undefined; | ||
for (let org of this.getOrgs()) { | ||
if (!alphabeticallyFirstOrgName || org.orgName < alphabeticallyFirstOrgName) { | ||
alphabeticallyFirstOrgName = org.orgName; | ||
alphabeticallyFirstOrg = org; | ||
} | ||
} | ||
return alphabeticallyFirstOrg; | ||
}, | ||
selectOrg(orgId) { | ||
selectOrgId(orgId); | ||
saveOrgSelectionToLocalStorage(orgId); | ||
}, | ||
getNotSelectedOrgs(inferDefault) { | ||
const selectedOrg = this.getSelectedOrg(inferDefault); | ||
if (selectedOrg) { | ||
return this.getOrgs().filter(org => org.orgId !== selectedOrg.orgId); | ||
} else { | ||
return this.getOrgs(); | ||
} | ||
} | ||
}; | ||
} | ||
const ORG_SELECTION_LOCAL_STORAGE_KEY = "__last_selected_org"; | ||
function saveOrgSelectionToLocalStorage(orgId) { | ||
if (localStorage) { | ||
localStorage.setItem(ORG_SELECTION_LOCAL_STORAGE_KEY, orgId); | ||
} | ||
} | ||
function loadOrgSelectionFromLocalStorage() { | ||
if (localStorage) { | ||
return localStorage.getItem(ORG_SELECTION_LOCAL_STORAGE_KEY); | ||
} | ||
return null; | ||
} | ||
function useAuthInfo() { | ||
const context = React.useContext(AuthContext); | ||
if (context === undefined) { | ||
throw new Error("useAuthInfo must be used within an AuthProvider"); | ||
} | ||
const { | ||
loading, | ||
authInfo, | ||
selectOrgId, | ||
userSelectedOrgId | ||
} = context; | ||
if (loading) { | ||
return { | ||
loading: true | ||
}; | ||
} else if (authInfo && authInfo.accessToken) { | ||
const orgHelper = getOrgHelper(authInfo.orgIdToOrgMemberInfo || {}, selectOrgId, userSelectedOrgId); | ||
return { | ||
loading: false, | ||
isLoggedIn: true, | ||
accessToken: authInfo.accessToken, | ||
orgHelper: orgHelper, | ||
user: authInfo.user | ||
}; | ||
} | ||
return { | ||
loading: false, | ||
isLoggedIn: false, | ||
accessToken: null, | ||
orgHelper: null, | ||
user: null | ||
}; | ||
} | ||
function useLogoutFunction() { | ||
const context = React.useContext(AuthContext); | ||
if (context === undefined) { | ||
throw new Error("useLogoutFunction must be used within an AuthProvider"); | ||
} | ||
const { | ||
logout | ||
} = context; | ||
return logout; | ||
} | ||
function useRedirectFunctions() { | ||
const context = React.useContext(AuthContext); | ||
if (context === undefined) { | ||
throw new Error("useRedirectFunctions must be used within an AuthProvider"); | ||
} | ||
const { | ||
redirectToAccountPage, | ||
redirectToSignupPage, | ||
redirectToLoginPage, | ||
redirectToOrgPage, | ||
redirectToCreateOrgPage | ||
} = context; | ||
return { | ||
redirectToSignupPage, | ||
redirectToLoginPage, | ||
redirectToAccountPage, | ||
redirectToOrgPage, | ||
redirectToCreateOrgPage | ||
}; | ||
} | ||
function RedirectToSignup(props) { | ||
const { | ||
redirectToSignupPage | ||
} = useRedirectFunctions(); | ||
redirectToSignupPage(); | ||
return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, props.children); | ||
} | ||
function RedirectToLogin(props) { | ||
const { | ||
redirectToLoginPage | ||
} = useRedirectFunctions(); | ||
redirectToLoginPage(); | ||
return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, props.children); | ||
} | ||
function createCommonjsModule(fn) { | ||
@@ -1016,2 +737,345 @@ var module = { exports: {} }; | ||
function getOrgHelper(orgIdToOrgMemberInfo, selectOrgId, userSelectedOrgId) { | ||
return { | ||
getOrg(orgId) { | ||
if (orgIdToOrgMemberInfo.hasOwnProperty(orgId)) { | ||
return orgIdToOrgMemberInfo[orgId]; | ||
} else { | ||
return undefined; | ||
} | ||
}, | ||
getOrgIds() { | ||
return Object.keys(orgIdToOrgMemberInfo); | ||
}, | ||
getOrgs() { | ||
return Object.values(orgIdToOrgMemberInfo); | ||
}, | ||
getSelectedOrg(inferDefault) { | ||
// default for inferDefault is true | ||
inferDefault = inferDefault === undefined ? true : inferDefault; // if the user has selected an org already, return it | ||
if (userSelectedOrgId && orgIdToOrgMemberInfo.hasOwnProperty(userSelectedOrgId)) { | ||
return orgIdToOrgMemberInfo[userSelectedOrgId]; | ||
} else if (!inferDefault) { | ||
return undefined; | ||
} // otherwise, infer it from local storage | ||
const previouslySelectedOrgId = loadOrgSelectionFromLocalStorage(); | ||
if (previouslySelectedOrgId && orgIdToOrgMemberInfo.hasOwnProperty(previouslySelectedOrgId)) { | ||
return orgIdToOrgMemberInfo[previouslySelectedOrgId]; | ||
} // if the user has never selected one before, select one deterministically by name | ||
let alphabeticallyFirstOrgName = undefined; | ||
let alphabeticallyFirstOrg = undefined; | ||
for (let org of this.getOrgs()) { | ||
if (!alphabeticallyFirstOrgName || org.orgName < alphabeticallyFirstOrgName) { | ||
alphabeticallyFirstOrgName = org.orgName; | ||
alphabeticallyFirstOrg = org; | ||
} | ||
} | ||
return alphabeticallyFirstOrg; | ||
}, | ||
selectOrg(orgId) { | ||
selectOrgId(orgId); | ||
saveOrgSelectionToLocalStorage(orgId); | ||
}, | ||
getNotSelectedOrgs(inferDefault) { | ||
const selectedOrg = this.getSelectedOrg(inferDefault); | ||
if (selectedOrg) { | ||
return this.getOrgs().filter(org => org.orgId !== selectedOrg.orgId); | ||
} else { | ||
return this.getOrgs(); | ||
} | ||
} | ||
}; | ||
} | ||
const ORG_SELECTION_LOCAL_STORAGE_KEY = "__last_selected_org"; | ||
function saveOrgSelectionToLocalStorage(orgId) { | ||
if (localStorage) { | ||
localStorage.setItem(ORG_SELECTION_LOCAL_STORAGE_KEY, orgId); | ||
} | ||
} | ||
function loadOrgSelectionFromLocalStorage() { | ||
if (localStorage) { | ||
return localStorage.getItem(ORG_SELECTION_LOCAL_STORAGE_KEY); | ||
} | ||
return null; | ||
} | ||
function useRedirectFunctions() { | ||
const context = React.useContext(AuthContext); | ||
if (context === undefined) { | ||
throw new Error("useRedirectFunctions must be used within an AuthProvider or RequiredAuthProvider"); | ||
} | ||
const { | ||
redirectToAccountPage, | ||
redirectToSignupPage, | ||
redirectToLoginPage, | ||
redirectToOrgPage, | ||
redirectToCreateOrgPage | ||
} = context; | ||
return { | ||
redirectToSignupPage, | ||
redirectToLoginPage, | ||
redirectToAccountPage, | ||
redirectToOrgPage, | ||
redirectToCreateOrgPage | ||
}; | ||
} | ||
function RedirectToSignup(props) { | ||
const { | ||
redirectToSignupPage | ||
} = useRedirectFunctions(); | ||
redirectToSignupPage(); | ||
return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, props.children); | ||
} | ||
function RedirectToLogin(props) { | ||
const { | ||
redirectToLoginPage | ||
} = useRedirectFunctions(); | ||
redirectToLoginPage(); | ||
return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, props.children); | ||
} | ||
function withRequiredAuthInfo(Component, args) { | ||
const displayName = `withRequiredAuthInfo(${Component.displayName || Component.name || "Component"})`; | ||
const WithRequiredAuthInfoWrapper = props => { | ||
const context = React.useContext(AuthContext); | ||
if (context === undefined) { | ||
throw new Error("withRequiredAuthInfo must be used within an AuthProvider or RequiredAuthProvider"); | ||
} | ||
function displayLoading() { | ||
if (args && args.displayWhileLoading) { | ||
return args.displayWhileLoading; | ||
} else { | ||
return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null); | ||
} | ||
} | ||
function displayLoggedOut() { | ||
if (args && args.displayIfLoggedOut) { | ||
return args.displayIfLoggedOut; | ||
} else { | ||
return /*#__PURE__*/React__default["default"].createElement(RedirectToLogin, null); | ||
} | ||
} | ||
const { | ||
loading, | ||
authInfo, | ||
selectOrgId, | ||
userSelectedOrgId | ||
} = context; | ||
if (loading) { | ||
return displayLoading(); | ||
} else if (authInfo) { | ||
const orgHelper = getOrgHelper(authInfo.orgIdToOrgMemberInfo || {}, selectOrgId, userSelectedOrgId); | ||
const loggedInProps = { ...props, | ||
accessToken: authInfo.accessToken, | ||
isLoggedIn: !!authInfo.accessToken, | ||
orgHelper: orgHelper, | ||
user: authInfo.user | ||
}; | ||
return /*#__PURE__*/React__default["default"].createElement(Component, loggedInProps); | ||
} else { | ||
return displayLoggedOut(); | ||
} | ||
}; | ||
WithRequiredAuthInfoWrapper.displayName = displayName; | ||
WithRequiredAuthInfoWrapper.WrappedComponent = Component; | ||
return hoistNonReactStatics_cjs(WithRequiredAuthInfoWrapper, Component); | ||
} | ||
const AuthContext = /*#__PURE__*/React__default["default"].createContext(undefined); | ||
const initialAuthInfoState = { | ||
loading: true, | ||
authInfo: null | ||
}; | ||
function authInfoStateReducer(_state, action) { | ||
return { | ||
loading: false, | ||
authInfo: action.authInfo | ||
}; | ||
} | ||
const AuthProvider = props => { | ||
const [authInfoState, dispatch] = React.useReducer(authInfoStateReducer, initialAuthInfoState); | ||
const [heartbeatCounter, setHeartbeatCounter] = React.useState(0); | ||
const [userSelectedOrgId, setUserSelectedOrgId] = React.useState(null); | ||
const triggerRefreshAuthentication = () => setHeartbeatCounter(x => x + 1); // Create client and register observer | ||
const client = React.useMemo(() => { | ||
// Disable background token refresh as we will do it within React instead | ||
const client = createClient({ | ||
authUrl: props.authUrl, | ||
enableBackgroundTokenRefresh: false | ||
}); | ||
client.addLoggedInChangeObserver(triggerRefreshAuthentication); | ||
return client; | ||
}, [props.authUrl]); // On unmount, destroy the client | ||
React.useEffect(() => { | ||
return () => { | ||
client.destroy(); | ||
}; | ||
}, []); // Periodically refresh the token. The client will only make requests when the authInfo is stale | ||
// Errors are logged and the token will be invalidated separately | ||
React.useEffect(() => { | ||
let didCancel = false; | ||
async function refreshToken() { | ||
try { | ||
const authInfo = await client.getAuthenticationInfoOrNull(); | ||
if (!didCancel) { | ||
dispatch({ | ||
authInfo | ||
}); | ||
} | ||
} catch (_) {// Exceptions are logged in the JS library | ||
} | ||
} | ||
refreshToken(); | ||
return () => { | ||
didCancel = true; | ||
}; | ||
}, [client, heartbeatCounter]); | ||
React.useEffect(() => { | ||
const interval = setInterval(triggerRefreshAuthentication, 60000); | ||
return () => clearInterval(interval); | ||
}, []); // Watchdog timer to make sure that if we hit the expiration we get rid of the token. | ||
// This should only be triggered if we are unable to get a new token due to an unexpected error/network timeouts. | ||
const expiresAtSeconds = authInfoState.authInfo ? authInfoState.authInfo.expiresAtSeconds : 0; | ||
React.useEffect(() => { | ||
if (!authInfoState.authInfo) { | ||
return; | ||
} | ||
const millisUntilTokenExpires = getMillisUntilTokenExpires(authInfoState.authInfo.expiresAtSeconds); | ||
const timeout = setTimeout(() => { | ||
dispatch({ | ||
authInfo: null | ||
}); | ||
}, millisUntilTokenExpires); | ||
return () => clearTimeout(timeout); | ||
}, [expiresAtSeconds]); | ||
const logout = React.useCallback(client.logout, []); | ||
const redirectToLoginPage = React.useCallback(client.redirectToLoginPage, []); | ||
const redirectToSignupPage = React.useCallback(client.redirectToSignupPage, []); | ||
const redirectToAccountPage = React.useCallback(client.redirectToAccountPage, []); | ||
const redirectToOrgPage = React.useCallback(client.redirectToOrgPage, []); | ||
const redirectToCreateOrgPage = React.useCallback(client.redirectToCreateOrgPage, []); | ||
const value = { | ||
loading: authInfoState.loading, | ||
triggerRefreshAuthentication, | ||
authInfo: authInfoState.authInfo, | ||
logout, | ||
userSelectedOrgId, | ||
selectOrgId: setUserSelectedOrgId, | ||
redirectToLoginPage, | ||
redirectToSignupPage, | ||
redirectToAccountPage, | ||
redirectToOrgPage, | ||
redirectToCreateOrgPage | ||
}; | ||
return /*#__PURE__*/React__default["default"].createElement(AuthContext.Provider, { | ||
value: value | ||
}, props.children); | ||
}; | ||
const RequiredAuthProvider = props => { | ||
const WrappedComponent = withRequiredAuthInfo(props => { | ||
return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, props.children); | ||
}, { | ||
displayWhileLoading: props.displayWhileLoading, | ||
displayIfLoggedOut: props.displayIfLoggedOut | ||
}); | ||
return /*#__PURE__*/React__default["default"].createElement(AuthProvider, { | ||
authUrl: props.authUrl | ||
}, /*#__PURE__*/React__default["default"].createElement(WrappedComponent, props)); | ||
}; | ||
function getMillisUntilTokenExpires(expiresAtSeconds) { | ||
let millisUntilTokenExpires = expiresAtSeconds * 1000 - Date.now(); | ||
return Math.max(0, millisUntilTokenExpires); | ||
} | ||
function useAuthInfo() { | ||
const context = React.useContext(AuthContext); | ||
if (context === undefined) { | ||
throw new Error("useAuthInfo must be used within an AuthProvider or RequiredAuthProvider"); | ||
} | ||
const { | ||
loading, | ||
authInfo, | ||
selectOrgId, | ||
userSelectedOrgId | ||
} = context; | ||
if (loading) { | ||
return { | ||
loading: true | ||
}; | ||
} else if (authInfo && authInfo.accessToken) { | ||
const orgHelper = getOrgHelper(authInfo.orgIdToOrgMemberInfo || {}, selectOrgId, userSelectedOrgId); | ||
return { | ||
loading: false, | ||
isLoggedIn: true, | ||
accessToken: authInfo.accessToken, | ||
orgHelper: orgHelper, | ||
user: authInfo.user | ||
}; | ||
} | ||
return { | ||
loading: false, | ||
isLoggedIn: false, | ||
accessToken: null, | ||
orgHelper: null, | ||
user: null | ||
}; | ||
} | ||
function useLogoutFunction() { | ||
const context = React.useContext(AuthContext); | ||
if (context === undefined) { | ||
throw new Error("useLogoutFunction must be used within an AuthProvider or RequiredAuthProvider"); | ||
} | ||
const { | ||
logout | ||
} = context; | ||
return logout; | ||
} | ||
function withAuthInfo(Component, args) { | ||
@@ -1024,3 +1088,3 @@ const displayName = `withAuthInfo(${Component.displayName || Component.name || "Component"})`; | ||
if (context === undefined) { | ||
throw new Error("withAuthInfo must be used within an AuthProvider"); | ||
throw new Error("withAuthInfo must be used within an AuthProvider or RequiredAuthProvider"); | ||
} | ||
@@ -1073,2 +1137,3 @@ | ||
exports.RedirectToSignup = RedirectToSignup; | ||
exports.RequiredAuthProvider = RequiredAuthProvider; | ||
exports.useAuthInfo = useAuthInfo; | ||
@@ -1078,2 +1143,3 @@ exports.useLogoutFunction = useLogoutFunction; | ||
exports.withAuthInfo = withAuthInfo; | ||
exports.withRequiredAuthInfo = withRequiredAuthInfo; | ||
//# sourceMappingURL=index.cjs.js.map |
@@ -1,2 +0,2 @@ | ||
import React, { useReducer, useState, useMemo, useEffect, useCallback, useContext } from 'react'; | ||
import React, { useContext, useReducer, useState, useMemo, useEffect, useCallback } from 'react'; | ||
@@ -386,281 +386,2 @@ let UserRole; | ||
const AuthContext = /*#__PURE__*/React.createContext(undefined); | ||
const initialAuthInfoState = { | ||
loading: true, | ||
authInfo: null | ||
}; | ||
function authInfoStateReducer(_state, action) { | ||
return { | ||
loading: false, | ||
authInfo: action.authInfo | ||
}; | ||
} | ||
const AuthProvider = props => { | ||
const [authInfoState, dispatch] = useReducer(authInfoStateReducer, initialAuthInfoState); | ||
const [heartbeatCounter, setHeartbeatCounter] = useState(0); | ||
const [userSelectedOrgId, setUserSelectedOrgId] = useState(null); | ||
const triggerRefreshAuthentication = () => setHeartbeatCounter(x => x + 1); // Create client and register observer | ||
const client = useMemo(() => { | ||
// Disable background token refresh as we will do it within React instead | ||
const client = createClient({ | ||
authUrl: props.authUrl, | ||
enableBackgroundTokenRefresh: false | ||
}); | ||
client.addLoggedInChangeObserver(triggerRefreshAuthentication); | ||
return client; | ||
}, [props.authUrl]); // On unmount, destroy the client | ||
useEffect(() => { | ||
return () => { | ||
client.destroy(); | ||
}; | ||
}, []); // Periodically refresh the token. The client will only make requests when the authInfo is stale | ||
// Errors are logged and the token will be invalidated separately | ||
useEffect(() => { | ||
let didCancel = false; | ||
async function refreshToken() { | ||
try { | ||
const authInfo = await client.getAuthenticationInfoOrNull(); | ||
if (!didCancel) { | ||
dispatch({ | ||
authInfo | ||
}); | ||
} | ||
} catch (err) { | ||
console.error("Authentication error", err); | ||
} | ||
} | ||
refreshToken(); | ||
return () => { | ||
didCancel = true; | ||
}; | ||
}, [client, heartbeatCounter]); | ||
useEffect(() => { | ||
const interval = setInterval(triggerRefreshAuthentication, 60000); | ||
return () => clearInterval(interval); | ||
}, []); // Watchdog timer to make sure that if we hit the expiration we get rid of the token. | ||
// This should only be triggered if we are unable to get a new token due to an unexpected error/network timeouts. | ||
const expiresAtSeconds = authInfoState.authInfo ? authInfoState.authInfo.expiresAtSeconds : 0; | ||
useEffect(() => { | ||
if (!authInfoState.authInfo) { | ||
return; | ||
} | ||
const millisUntilTokenExpires = getMillisUntilTokenExpires(authInfoState.authInfo.expiresAtSeconds); | ||
const timeout = setTimeout(() => { | ||
dispatch({ | ||
authInfo: null | ||
}); | ||
}, millisUntilTokenExpires); | ||
return () => clearTimeout(timeout); | ||
}, [expiresAtSeconds]); | ||
const logout = useCallback(client.logout, []); | ||
const redirectToLoginPage = useCallback(client.redirectToLoginPage, []); | ||
const redirectToSignupPage = useCallback(client.redirectToSignupPage, []); | ||
const redirectToAccountPage = useCallback(client.redirectToAccountPage, []); | ||
const redirectToOrgPage = useCallback(client.redirectToOrgPage, []); | ||
const redirectToCreateOrgPage = useCallback(client.redirectToCreateOrgPage, []); | ||
const value = { | ||
loading: authInfoState.loading, | ||
triggerRefreshAuthentication, | ||
authInfo: authInfoState.authInfo, | ||
logout, | ||
userSelectedOrgId, | ||
selectOrgId: setUserSelectedOrgId, | ||
redirectToLoginPage, | ||
redirectToSignupPage, | ||
redirectToAccountPage, | ||
redirectToOrgPage, | ||
redirectToCreateOrgPage | ||
}; | ||
return /*#__PURE__*/React.createElement(AuthContext.Provider, { | ||
value: value | ||
}, props.children); | ||
}; | ||
function getMillisUntilTokenExpires(expiresAtSeconds) { | ||
let millisUntilTokenExpires = expiresAtSeconds * 1000 - Date.now(); | ||
return Math.max(0, millisUntilTokenExpires); | ||
} | ||
function getOrgHelper(orgIdToOrgMemberInfo, selectOrgId, userSelectedOrgId) { | ||
return { | ||
getOrg(orgId) { | ||
if (orgIdToOrgMemberInfo.hasOwnProperty(orgId)) { | ||
return orgIdToOrgMemberInfo[orgId]; | ||
} else { | ||
return undefined; | ||
} | ||
}, | ||
getOrgIds() { | ||
return Object.keys(orgIdToOrgMemberInfo); | ||
}, | ||
getOrgs() { | ||
return Object.values(orgIdToOrgMemberInfo); | ||
}, | ||
getSelectedOrg(inferDefault) { | ||
// default for inferDefault is true | ||
inferDefault = inferDefault === undefined ? true : inferDefault; // if the user has selected an org already, return it | ||
if (userSelectedOrgId && orgIdToOrgMemberInfo.hasOwnProperty(userSelectedOrgId)) { | ||
return orgIdToOrgMemberInfo[userSelectedOrgId]; | ||
} else if (!inferDefault) { | ||
return undefined; | ||
} // otherwise, infer it from local storage | ||
const previouslySelectedOrgId = loadOrgSelectionFromLocalStorage(); | ||
if (previouslySelectedOrgId && orgIdToOrgMemberInfo.hasOwnProperty(previouslySelectedOrgId)) { | ||
return orgIdToOrgMemberInfo[previouslySelectedOrgId]; | ||
} // if the user has never selected one before, select one deterministically by name | ||
let alphabeticallyFirstOrgName = undefined; | ||
let alphabeticallyFirstOrg = undefined; | ||
for (let org of this.getOrgs()) { | ||
if (!alphabeticallyFirstOrgName || org.orgName < alphabeticallyFirstOrgName) { | ||
alphabeticallyFirstOrgName = org.orgName; | ||
alphabeticallyFirstOrg = org; | ||
} | ||
} | ||
return alphabeticallyFirstOrg; | ||
}, | ||
selectOrg(orgId) { | ||
selectOrgId(orgId); | ||
saveOrgSelectionToLocalStorage(orgId); | ||
}, | ||
getNotSelectedOrgs(inferDefault) { | ||
const selectedOrg = this.getSelectedOrg(inferDefault); | ||
if (selectedOrg) { | ||
return this.getOrgs().filter(org => org.orgId !== selectedOrg.orgId); | ||
} else { | ||
return this.getOrgs(); | ||
} | ||
} | ||
}; | ||
} | ||
const ORG_SELECTION_LOCAL_STORAGE_KEY = "__last_selected_org"; | ||
function saveOrgSelectionToLocalStorage(orgId) { | ||
if (localStorage) { | ||
localStorage.setItem(ORG_SELECTION_LOCAL_STORAGE_KEY, orgId); | ||
} | ||
} | ||
function loadOrgSelectionFromLocalStorage() { | ||
if (localStorage) { | ||
return localStorage.getItem(ORG_SELECTION_LOCAL_STORAGE_KEY); | ||
} | ||
return null; | ||
} | ||
function useAuthInfo() { | ||
const context = useContext(AuthContext); | ||
if (context === undefined) { | ||
throw new Error("useAuthInfo must be used within an AuthProvider"); | ||
} | ||
const { | ||
loading, | ||
authInfo, | ||
selectOrgId, | ||
userSelectedOrgId | ||
} = context; | ||
if (loading) { | ||
return { | ||
loading: true | ||
}; | ||
} else if (authInfo && authInfo.accessToken) { | ||
const orgHelper = getOrgHelper(authInfo.orgIdToOrgMemberInfo || {}, selectOrgId, userSelectedOrgId); | ||
return { | ||
loading: false, | ||
isLoggedIn: true, | ||
accessToken: authInfo.accessToken, | ||
orgHelper: orgHelper, | ||
user: authInfo.user | ||
}; | ||
} | ||
return { | ||
loading: false, | ||
isLoggedIn: false, | ||
accessToken: null, | ||
orgHelper: null, | ||
user: null | ||
}; | ||
} | ||
function useLogoutFunction() { | ||
const context = useContext(AuthContext); | ||
if (context === undefined) { | ||
throw new Error("useLogoutFunction must be used within an AuthProvider"); | ||
} | ||
const { | ||
logout | ||
} = context; | ||
return logout; | ||
} | ||
function useRedirectFunctions() { | ||
const context = useContext(AuthContext); | ||
if (context === undefined) { | ||
throw new Error("useRedirectFunctions must be used within an AuthProvider"); | ||
} | ||
const { | ||
redirectToAccountPage, | ||
redirectToSignupPage, | ||
redirectToLoginPage, | ||
redirectToOrgPage, | ||
redirectToCreateOrgPage | ||
} = context; | ||
return { | ||
redirectToSignupPage, | ||
redirectToLoginPage, | ||
redirectToAccountPage, | ||
redirectToOrgPage, | ||
redirectToCreateOrgPage | ||
}; | ||
} | ||
function RedirectToSignup(props) { | ||
const { | ||
redirectToSignupPage | ||
} = useRedirectFunctions(); | ||
redirectToSignupPage(); | ||
return /*#__PURE__*/React.createElement(React.Fragment, null, props.children); | ||
} | ||
function RedirectToLogin(props) { | ||
const { | ||
redirectToLoginPage | ||
} = useRedirectFunctions(); | ||
redirectToLoginPage(); | ||
return /*#__PURE__*/React.createElement(React.Fragment, null, props.children); | ||
} | ||
function createCommonjsModule(fn) { | ||
@@ -1008,2 +729,345 @@ var module = { exports: {} }; | ||
function getOrgHelper(orgIdToOrgMemberInfo, selectOrgId, userSelectedOrgId) { | ||
return { | ||
getOrg(orgId) { | ||
if (orgIdToOrgMemberInfo.hasOwnProperty(orgId)) { | ||
return orgIdToOrgMemberInfo[orgId]; | ||
} else { | ||
return undefined; | ||
} | ||
}, | ||
getOrgIds() { | ||
return Object.keys(orgIdToOrgMemberInfo); | ||
}, | ||
getOrgs() { | ||
return Object.values(orgIdToOrgMemberInfo); | ||
}, | ||
getSelectedOrg(inferDefault) { | ||
// default for inferDefault is true | ||
inferDefault = inferDefault === undefined ? true : inferDefault; // if the user has selected an org already, return it | ||
if (userSelectedOrgId && orgIdToOrgMemberInfo.hasOwnProperty(userSelectedOrgId)) { | ||
return orgIdToOrgMemberInfo[userSelectedOrgId]; | ||
} else if (!inferDefault) { | ||
return undefined; | ||
} // otherwise, infer it from local storage | ||
const previouslySelectedOrgId = loadOrgSelectionFromLocalStorage(); | ||
if (previouslySelectedOrgId && orgIdToOrgMemberInfo.hasOwnProperty(previouslySelectedOrgId)) { | ||
return orgIdToOrgMemberInfo[previouslySelectedOrgId]; | ||
} // if the user has never selected one before, select one deterministically by name | ||
let alphabeticallyFirstOrgName = undefined; | ||
let alphabeticallyFirstOrg = undefined; | ||
for (let org of this.getOrgs()) { | ||
if (!alphabeticallyFirstOrgName || org.orgName < alphabeticallyFirstOrgName) { | ||
alphabeticallyFirstOrgName = org.orgName; | ||
alphabeticallyFirstOrg = org; | ||
} | ||
} | ||
return alphabeticallyFirstOrg; | ||
}, | ||
selectOrg(orgId) { | ||
selectOrgId(orgId); | ||
saveOrgSelectionToLocalStorage(orgId); | ||
}, | ||
getNotSelectedOrgs(inferDefault) { | ||
const selectedOrg = this.getSelectedOrg(inferDefault); | ||
if (selectedOrg) { | ||
return this.getOrgs().filter(org => org.orgId !== selectedOrg.orgId); | ||
} else { | ||
return this.getOrgs(); | ||
} | ||
} | ||
}; | ||
} | ||
const ORG_SELECTION_LOCAL_STORAGE_KEY = "__last_selected_org"; | ||
function saveOrgSelectionToLocalStorage(orgId) { | ||
if (localStorage) { | ||
localStorage.setItem(ORG_SELECTION_LOCAL_STORAGE_KEY, orgId); | ||
} | ||
} | ||
function loadOrgSelectionFromLocalStorage() { | ||
if (localStorage) { | ||
return localStorage.getItem(ORG_SELECTION_LOCAL_STORAGE_KEY); | ||
} | ||
return null; | ||
} | ||
function useRedirectFunctions() { | ||
const context = useContext(AuthContext); | ||
if (context === undefined) { | ||
throw new Error("useRedirectFunctions must be used within an AuthProvider or RequiredAuthProvider"); | ||
} | ||
const { | ||
redirectToAccountPage, | ||
redirectToSignupPage, | ||
redirectToLoginPage, | ||
redirectToOrgPage, | ||
redirectToCreateOrgPage | ||
} = context; | ||
return { | ||
redirectToSignupPage, | ||
redirectToLoginPage, | ||
redirectToAccountPage, | ||
redirectToOrgPage, | ||
redirectToCreateOrgPage | ||
}; | ||
} | ||
function RedirectToSignup(props) { | ||
const { | ||
redirectToSignupPage | ||
} = useRedirectFunctions(); | ||
redirectToSignupPage(); | ||
return /*#__PURE__*/React.createElement(React.Fragment, null, props.children); | ||
} | ||
function RedirectToLogin(props) { | ||
const { | ||
redirectToLoginPage | ||
} = useRedirectFunctions(); | ||
redirectToLoginPage(); | ||
return /*#__PURE__*/React.createElement(React.Fragment, null, props.children); | ||
} | ||
function withRequiredAuthInfo(Component, args) { | ||
const displayName = `withRequiredAuthInfo(${Component.displayName || Component.name || "Component"})`; | ||
const WithRequiredAuthInfoWrapper = props => { | ||
const context = useContext(AuthContext); | ||
if (context === undefined) { | ||
throw new Error("withRequiredAuthInfo must be used within an AuthProvider or RequiredAuthProvider"); | ||
} | ||
function displayLoading() { | ||
if (args && args.displayWhileLoading) { | ||
return args.displayWhileLoading; | ||
} else { | ||
return /*#__PURE__*/React.createElement(React.Fragment, null); | ||
} | ||
} | ||
function displayLoggedOut() { | ||
if (args && args.displayIfLoggedOut) { | ||
return args.displayIfLoggedOut; | ||
} else { | ||
return /*#__PURE__*/React.createElement(RedirectToLogin, null); | ||
} | ||
} | ||
const { | ||
loading, | ||
authInfo, | ||
selectOrgId, | ||
userSelectedOrgId | ||
} = context; | ||
if (loading) { | ||
return displayLoading(); | ||
} else if (authInfo) { | ||
const orgHelper = getOrgHelper(authInfo.orgIdToOrgMemberInfo || {}, selectOrgId, userSelectedOrgId); | ||
const loggedInProps = { ...props, | ||
accessToken: authInfo.accessToken, | ||
isLoggedIn: !!authInfo.accessToken, | ||
orgHelper: orgHelper, | ||
user: authInfo.user | ||
}; | ||
return /*#__PURE__*/React.createElement(Component, loggedInProps); | ||
} else { | ||
return displayLoggedOut(); | ||
} | ||
}; | ||
WithRequiredAuthInfoWrapper.displayName = displayName; | ||
WithRequiredAuthInfoWrapper.WrappedComponent = Component; | ||
return hoistNonReactStatics_cjs(WithRequiredAuthInfoWrapper, Component); | ||
} | ||
const AuthContext = /*#__PURE__*/React.createContext(undefined); | ||
const initialAuthInfoState = { | ||
loading: true, | ||
authInfo: null | ||
}; | ||
function authInfoStateReducer(_state, action) { | ||
return { | ||
loading: false, | ||
authInfo: action.authInfo | ||
}; | ||
} | ||
const AuthProvider = props => { | ||
const [authInfoState, dispatch] = useReducer(authInfoStateReducer, initialAuthInfoState); | ||
const [heartbeatCounter, setHeartbeatCounter] = useState(0); | ||
const [userSelectedOrgId, setUserSelectedOrgId] = useState(null); | ||
const triggerRefreshAuthentication = () => setHeartbeatCounter(x => x + 1); // Create client and register observer | ||
const client = useMemo(() => { | ||
// Disable background token refresh as we will do it within React instead | ||
const client = createClient({ | ||
authUrl: props.authUrl, | ||
enableBackgroundTokenRefresh: false | ||
}); | ||
client.addLoggedInChangeObserver(triggerRefreshAuthentication); | ||
return client; | ||
}, [props.authUrl]); // On unmount, destroy the client | ||
useEffect(() => { | ||
return () => { | ||
client.destroy(); | ||
}; | ||
}, []); // Periodically refresh the token. The client will only make requests when the authInfo is stale | ||
// Errors are logged and the token will be invalidated separately | ||
useEffect(() => { | ||
let didCancel = false; | ||
async function refreshToken() { | ||
try { | ||
const authInfo = await client.getAuthenticationInfoOrNull(); | ||
if (!didCancel) { | ||
dispatch({ | ||
authInfo | ||
}); | ||
} | ||
} catch (_) {// Exceptions are logged in the JS library | ||
} | ||
} | ||
refreshToken(); | ||
return () => { | ||
didCancel = true; | ||
}; | ||
}, [client, heartbeatCounter]); | ||
useEffect(() => { | ||
const interval = setInterval(triggerRefreshAuthentication, 60000); | ||
return () => clearInterval(interval); | ||
}, []); // Watchdog timer to make sure that if we hit the expiration we get rid of the token. | ||
// This should only be triggered if we are unable to get a new token due to an unexpected error/network timeouts. | ||
const expiresAtSeconds = authInfoState.authInfo ? authInfoState.authInfo.expiresAtSeconds : 0; | ||
useEffect(() => { | ||
if (!authInfoState.authInfo) { | ||
return; | ||
} | ||
const millisUntilTokenExpires = getMillisUntilTokenExpires(authInfoState.authInfo.expiresAtSeconds); | ||
const timeout = setTimeout(() => { | ||
dispatch({ | ||
authInfo: null | ||
}); | ||
}, millisUntilTokenExpires); | ||
return () => clearTimeout(timeout); | ||
}, [expiresAtSeconds]); | ||
const logout = useCallback(client.logout, []); | ||
const redirectToLoginPage = useCallback(client.redirectToLoginPage, []); | ||
const redirectToSignupPage = useCallback(client.redirectToSignupPage, []); | ||
const redirectToAccountPage = useCallback(client.redirectToAccountPage, []); | ||
const redirectToOrgPage = useCallback(client.redirectToOrgPage, []); | ||
const redirectToCreateOrgPage = useCallback(client.redirectToCreateOrgPage, []); | ||
const value = { | ||
loading: authInfoState.loading, | ||
triggerRefreshAuthentication, | ||
authInfo: authInfoState.authInfo, | ||
logout, | ||
userSelectedOrgId, | ||
selectOrgId: setUserSelectedOrgId, | ||
redirectToLoginPage, | ||
redirectToSignupPage, | ||
redirectToAccountPage, | ||
redirectToOrgPage, | ||
redirectToCreateOrgPage | ||
}; | ||
return /*#__PURE__*/React.createElement(AuthContext.Provider, { | ||
value: value | ||
}, props.children); | ||
}; | ||
const RequiredAuthProvider = props => { | ||
const WrappedComponent = withRequiredAuthInfo(props => { | ||
return /*#__PURE__*/React.createElement(React.Fragment, null, props.children); | ||
}, { | ||
displayWhileLoading: props.displayWhileLoading, | ||
displayIfLoggedOut: props.displayIfLoggedOut | ||
}); | ||
return /*#__PURE__*/React.createElement(AuthProvider, { | ||
authUrl: props.authUrl | ||
}, /*#__PURE__*/React.createElement(WrappedComponent, props)); | ||
}; | ||
function getMillisUntilTokenExpires(expiresAtSeconds) { | ||
let millisUntilTokenExpires = expiresAtSeconds * 1000 - Date.now(); | ||
return Math.max(0, millisUntilTokenExpires); | ||
} | ||
function useAuthInfo() { | ||
const context = useContext(AuthContext); | ||
if (context === undefined) { | ||
throw new Error("useAuthInfo must be used within an AuthProvider or RequiredAuthProvider"); | ||
} | ||
const { | ||
loading, | ||
authInfo, | ||
selectOrgId, | ||
userSelectedOrgId | ||
} = context; | ||
if (loading) { | ||
return { | ||
loading: true | ||
}; | ||
} else if (authInfo && authInfo.accessToken) { | ||
const orgHelper = getOrgHelper(authInfo.orgIdToOrgMemberInfo || {}, selectOrgId, userSelectedOrgId); | ||
return { | ||
loading: false, | ||
isLoggedIn: true, | ||
accessToken: authInfo.accessToken, | ||
orgHelper: orgHelper, | ||
user: authInfo.user | ||
}; | ||
} | ||
return { | ||
loading: false, | ||
isLoggedIn: false, | ||
accessToken: null, | ||
orgHelper: null, | ||
user: null | ||
}; | ||
} | ||
function useLogoutFunction() { | ||
const context = useContext(AuthContext); | ||
if (context === undefined) { | ||
throw new Error("useLogoutFunction must be used within an AuthProvider or RequiredAuthProvider"); | ||
} | ||
const { | ||
logout | ||
} = context; | ||
return logout; | ||
} | ||
function withAuthInfo(Component, args) { | ||
@@ -1016,3 +1080,3 @@ const displayName = `withAuthInfo(${Component.displayName || Component.name || "Component"})`; | ||
if (context === undefined) { | ||
throw new Error("withAuthInfo must be used within an AuthProvider"); | ||
throw new Error("withAuthInfo must be used within an AuthProvider or RequiredAuthProvider"); | ||
} | ||
@@ -1062,3 +1126,3 @@ | ||
export { AuthProvider, RedirectToLogin, RedirectToSignup, UserRole, useAuthInfo, useLogoutFunction, useRedirectFunctions, withAuthInfo }; | ||
export { AuthProvider, RedirectToLogin, RedirectToSignup, RequiredAuthProvider, UserRole, useAuthInfo, useLogoutFunction, useRedirectFunctions, withAuthInfo, withRequiredAuthInfo }; | ||
//# sourceMappingURL=index.esm.js.map |
@@ -20,4 +20,9 @@ import { AuthenticationInfo } from "@propelauth/javascript"; | ||
}; | ||
export interface RequiredAuthProviderProps extends AuthProviderProps { | ||
displayWhileLoading?: React.ReactElement; | ||
displayIfLoggedOut?: React.ReactElement; | ||
} | ||
export declare const AuthContext: React.Context<InternalAuthState | undefined>; | ||
export declare const AuthProvider: (props: AuthProviderProps) => JSX.Element; | ||
export declare const RequiredAuthProvider: (props: RequiredAuthProviderProps) => JSX.Element; | ||
export {}; |
export { UserRole } from "@propelauth/javascript"; | ||
export type { OrgIdToOrgMemberInfo, OrgMemberInfo, User } from "@propelauth/javascript"; | ||
export { AuthProvider } from "./AuthContext"; | ||
export type { AuthProviderProps } from "./AuthContext"; | ||
export { AuthProvider, RequiredAuthProvider } from "./AuthContext"; | ||
export type { AuthProviderProps, RequiredAuthProviderProps } from "./AuthContext"; | ||
export type { OrgHelper } from "./OrgHelper"; | ||
@@ -12,1 +12,3 @@ export { useAuthInfo } from "./useAuthInfo"; | ||
export type { WithAuthInfoArgs, WithAuthInfoProps, WithLoggedInAuthInfoProps, WithNotLoggedInAuthInfoProps, } from "./withAuthInfo"; | ||
export { withRequiredAuthInfo } from "./withRequiredAuthInfo"; | ||
export type { WithRequiredAuthInfoArgs } from "./withRequiredAuthInfo"; |
@@ -8,3 +8,3 @@ { | ||
}, | ||
"version": "1.2.4", | ||
"version": "1.2.5", | ||
"license": "MIT", | ||
@@ -11,0 +11,0 @@ "keywords": [ |
@@ -8,3 +8,3 @@ /** | ||
import { v4 as uuidv4 } from "uuid" | ||
import { AuthProvider } from "./AuthContext" | ||
import { AuthProvider, RequiredAuthProvider } from "./AuthContext" | ||
import { useAuthInfo } from "./useAuthInfo" | ||
@@ -14,2 +14,3 @@ import { useLogoutFunction } from "./useLogoutFunction" | ||
import { withAuthInfo } from "./withAuthInfo" | ||
import { withRequiredAuthInfo } from "./withRequiredAuthInfo" | ||
@@ -135,2 +136,92 @@ // Fake timer setup | ||
it("withAuthInfo passes values from client as props, with RequiredAuthProvider", async () => { | ||
const authenticationInfo = createAuthenticationInfo() | ||
mockClient.getAuthenticationInfoOrNull.mockReturnValue(authenticationInfo) | ||
const Component = (props) => { | ||
expect(props.accessToken).toBe(authenticationInfo.accessToken) | ||
expect(props.user).toStrictEqual(authenticationInfo.user) | ||
expect(props.isLoggedIn).toBe(true) | ||
expect(props.orgHelper.getOrgs().sort()).toEqual(Object.values(authenticationInfo.orgIdToOrgMemberInfo).sort()) | ||
return <div>Finished</div> | ||
} | ||
const WrappedComponent = withAuthInfo(Component) | ||
render( | ||
<RequiredAuthProvider authUrl={AUTH_URL}> | ||
<WrappedComponent /> | ||
</RequiredAuthProvider> | ||
) | ||
await waitFor(() => screen.getByText("Finished")) | ||
expectCreateClientWasCalledCorrectly() | ||
}) | ||
it("withRequiredAuthInfo passes values from client as props, with RequiredAuthProvider", async () => { | ||
const authenticationInfo = createAuthenticationInfo() | ||
mockClient.getAuthenticationInfoOrNull.mockReturnValue(authenticationInfo) | ||
const Component = (props) => { | ||
expect(props.accessToken).toBe(authenticationInfo.accessToken) | ||
expect(props.user).toStrictEqual(authenticationInfo.user) | ||
expect(props.isLoggedIn).toBe(true) | ||
expect(props.orgHelper.getOrgs().sort()).toEqual(Object.values(authenticationInfo.orgIdToOrgMemberInfo).sort()) | ||
return <div>Finished</div> | ||
} | ||
const WrappedComponent = withRequiredAuthInfo(Component) | ||
render( | ||
<RequiredAuthProvider authUrl={AUTH_URL}> | ||
<WrappedComponent /> | ||
</RequiredAuthProvider> | ||
) | ||
await waitFor(() => screen.getByText("Finished")) | ||
expectCreateClientWasCalledCorrectly() | ||
}) | ||
it("RequiredAuthProvider displays logged out value if logged out", async () => { | ||
mockClient.getAuthenticationInfoOrNull.mockReturnValue(null) | ||
const ErrorComponent = () => { | ||
return <div>Error</div> | ||
} | ||
const SuccessComponent = () => { | ||
return <div>Finished</div> | ||
} | ||
const WrappedComponent = withAuthInfo(ErrorComponent) | ||
render( | ||
<RequiredAuthProvider authUrl={AUTH_URL} displayIfLoggedOut={<SuccessComponent />}> | ||
<WrappedComponent /> | ||
</RequiredAuthProvider> | ||
) | ||
await waitFor(() => screen.getByText("Finished")) | ||
expectCreateClientWasCalledCorrectly() | ||
}) | ||
it("withRequiredAuthInfo displays logged out value if logged out", async () => { | ||
mockClient.getAuthenticationInfoOrNull.mockReturnValue(null) | ||
const ErrorComponent = () => { | ||
return <div>Error</div> | ||
} | ||
const SuccessComponent = () => { | ||
return <div>Finished</div> | ||
} | ||
const WrappedComponent = withRequiredAuthInfo(ErrorComponent, { | ||
displayIfLoggedOut: <SuccessComponent />, | ||
}) | ||
render( | ||
<AuthProvider authUrl={AUTH_URL}> | ||
<WrappedComponent /> | ||
</AuthProvider> | ||
) | ||
await waitFor(() => screen.getByText("Finished")) | ||
expectCreateClientWasCalledCorrectly() | ||
}) | ||
it("withAuthInfo passes logged out values from client as props", async () => { | ||
@@ -137,0 +228,0 @@ mockClient.getAuthenticationInfoOrNull.mockReturnValue(null) |
@@ -31,3 +31,3 @@ import { User } from "@propelauth/javascript" | ||
if (context === undefined) { | ||
throw new Error("useAuthInfo must be used within an AuthProvider") | ||
throw new Error("useAuthInfo must be used within an AuthProvider or RequiredAuthProvider") | ||
} | ||
@@ -34,0 +34,0 @@ |
@@ -7,3 +7,3 @@ import { useContext } from "react" | ||
if (context === undefined) { | ||
throw new Error("useLogoutFunction must be used within an AuthProvider") | ||
throw new Error("useLogoutFunction must be used within an AuthProvider or RequiredAuthProvider") | ||
} | ||
@@ -10,0 +10,0 @@ const { logout } = context |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
281856
31
3147