@saas-ui/auth-provider
Version:
Authentication provider primivites
1 lines • 14.7 kB
Source Map (JSON)
{"version":3,"sources":["../src/provider.tsx","../src/use-promise.ts"],"sourcesContent":["import React, {\n createContext,\n useState,\n useContext,\n useEffect,\n useCallback,\n} from 'react'\n\nimport { usePromise } from './use-promise'\n\nexport type AuthTypeEnum = 'magiclink' | 'password'\n\nexport type AuthActionEnum = 'logIn' | 'signUp'\n\nexport type AuthToken = string | null | undefined\n\nexport interface AuthParams {\n email?: string\n password?: string\n provider?: string\n refreshToken?: string\n otp?: string\n [key: string]: any\n}\n\nexport interface ResetPasswordParams {\n email: string\n [key: string]: any\n}\n\nexport interface UpdatePasswordParams {\n password: string\n token?: string\n [key: string]: any\n}\n\nexport interface OtpParams {\n otp: string\n [key: string]: any\n}\n\nexport type ExtraAuthOptions = Record<string, unknown>\nexport type AuthOptions<ExtraOptions extends object = ExtraAuthOptions> = {\n /**\n * The url to redirect to after social or magic link login.\n */\n redirectTo?: string\n} & ExtraOptions\n\n/**\n * The user object\n */\nexport interface User {\n [key: string]: any\n}\n\nexport interface DefaultUser extends User {\n id?: string | null\n email?: string | null\n}\n\ntype UnsubscribeHandler = () => void\n\nexport type AuthStateChangeCallback<TUser extends User = DefaultUser> = (\n user?: TUser | null\n) => void\n\nexport interface AuthProviderProps<TUser extends User = DefaultUser> {\n /**\n * Refetch the user data when the window regains focus\n */\n refetchUserOnWindowFocus?: boolean\n /**\n * Restore the authentication state, eg after redirecting\n */\n onRestoreAuthState?: () => Promise<void>\n /**\n * Loads user data after authentication\n */\n onLoadUser?: () => Promise<TUser | null>\n /**\n * The signup method\n */\n onSignup?: <Params extends AuthParams = AuthParams>(\n params: Params,\n options?: AuthOptions\n ) => Promise<TUser | undefined | null>\n /**\n * The login method\n */\n onLogin?: <Params extends AuthParams = AuthParams>(\n params: Params,\n options?: AuthOptions\n ) => Promise<TUser | undefined | null>\n /**\n * Request to reset a password.\n */\n onResetPassword?: <Params extends ResetPasswordParams = ResetPasswordParams>(\n params: Params,\n options?: AuthOptions\n ) => Promise<any>\n /**\n * Update the password.\n */\n onUpdatePassword?: <\n Params extends UpdatePasswordParams = UpdatePasswordParams,\n >(\n params: Params,\n options?: AuthOptions\n ) => Promise<any>\n /**\n * Verify an one time password (2fa)\n */\n onVerifyOtp?: <Params extends OtpParams = OtpParams>(\n params: Params,\n options?: AuthOptions\n ) => Promise<boolean | undefined | null>\n /**\n * The logout method\n */\n onLogout?: (options?: AuthOptions) => Promise<unknown>\n /**\n * Should trigger whenever the authentication state changes\n */\n onAuthStateChange?: (\n callback: AuthStateChangeCallback<TUser>\n ) => UnsubscribeHandler\n /**\n * Return the session token\n */\n onGetToken?: () => Promise<AuthToken>\n /**\n * The children to render\n */\n children?: React.ReactNode\n}\n\nexport type AuthFunction<\n TParams = AuthParams,\n TExtraOptions extends object = Record<string, unknown>,\n> = (params: TParams, options?: AuthOptions<TExtraOptions>) => Promise<any>\n\nexport interface AuthContextValue<TUser extends User = DefaultUser> {\n isAuthenticated: boolean\n isLoggingIn: boolean\n isLoading: boolean\n user?: TUser | null\n signUp: AuthFunction\n logIn: AuthFunction\n verifyOtp: AuthFunction<OtpParams>\n resetPassword: AuthFunction<ResetPasswordParams>\n updatePassword: AuthFunction<UpdatePasswordParams>\n logOut: (options?: AuthOptions) => Promise<unknown>\n loadUser: () => void\n getToken?: () => Promise<AuthToken>\n error: unknown | null\n}\n\nconst createAuthContext = <TUser extends User = DefaultUser>() => {\n return createContext<AuthContextValue<TUser> | null>(null)\n}\n\nexport const AuthContext = createAuthContext()\n\nexport const AuthProvider = <TUser extends User = DefaultUser>({\n refetchUserOnWindowFocus = true,\n onRestoreAuthState,\n onLoadUser = () => Promise.resolve(null),\n onSignup = () => Promise.resolve(null),\n onLogin = () => Promise.resolve(null),\n onVerifyOtp = () => Promise.resolve(null),\n onLogout = () => Promise.resolve(),\n onAuthStateChange,\n onGetToken,\n onResetPassword,\n onUpdatePassword,\n children,\n}: AuthProviderProps<TUser>) => {\n const [isAuthenticated, setAuthenticated] = useState(false)\n const [user, setUser] = useState<TUser | null>()\n const [isLoading, setLoading] = useState(true)\n const restoreRef = React.useRef(false)\n const isFetchingRef = React.useRef(false)\n const [error, setError] = useState<Error | unknown | null>(null)\n\n useEffect(() => {\n if (onAuthStateChange) {\n const unsubscribe = onAuthStateChange((user) => {\n setAuthenticated(!!user)\n })\n return () => {\n unsubscribe?.()\n }\n }\n }, [])\n\n useEffect(() => {\n const restoreState = async () => {\n restoreRef.current = true\n await onRestoreAuthState?.()\n await loadUser()\n restoreRef.current = false\n }\n\n if (!restoreRef.current) {\n restoreState()\n }\n }, [onRestoreAuthState])\n\n const loadUser = useCallback(async () => {\n try {\n // Prevent multiple calls to loadUser\n if (isFetchingRef.current) {\n return\n }\n\n setError(null)\n\n if (\n (typeof onGetToken === 'undefined' || (await onGetToken())) &&\n !isFetchingRef.current\n ) {\n isFetchingRef.current = true\n const user = await onLoadUser()\n\n if (user) {\n setUser(user)\n setAuthenticated(true)\n } else {\n setAuthenticated(false)\n setUser(null)\n }\n }\n } catch (error: unknown) {\n setError(error)\n setAuthenticated(false)\n setUser(null)\n } finally {\n isFetchingRef.current = false\n setLoading(false)\n }\n }, [onLoadUser, onGetToken])\n\n useEffect(() => {\n if (!refetchUserOnWindowFocus) {\n return\n }\n\n const onWindowFocus = async () => {\n loadUser()\n }\n\n window.addEventListener('focus', onWindowFocus)\n\n return () => {\n if (onWindowFocus) {\n window.removeEventListener('focus', onWindowFocus)\n }\n }\n }, [loadUser, refetchUserOnWindowFocus])\n\n const signUp = useCallback(\n async (params: AuthParams, options?: AuthOptions) => {\n const result = await onSignup(params, options)\n loadUser()\n return result\n },\n [onSignup]\n )\n\n const logIn = useCallback(\n async (params: AuthParams, options?: AuthOptions) => {\n const result = await onLogin(params, options)\n loadUser()\n return result\n },\n [onLogin]\n )\n\n const logOut = useCallback(\n async (options?: AuthOptions) => {\n await onLogout(options)\n setUser(null)\n setAuthenticated(false)\n },\n [onLogout]\n )\n\n const verifyOtp = useCallback(\n async (params: OtpParams, options?: AuthOptions) => {\n const result = await onVerifyOtp(params, options)\n return result\n },\n [onVerifyOtp]\n )\n\n const resetPassword = useCallback(\n async (\n params: Required<Pick<AuthParams, 'email'>>,\n options?: AuthOptions\n ) => {\n return await onResetPassword?.(params, options)\n },\n [onResetPassword]\n )\n\n const updatePassword = useCallback(\n async (\n params: Required<Pick<AuthParams, 'password'>>,\n options?: AuthOptions\n ) => {\n return await onUpdatePassword?.(params, options)\n },\n [onUpdatePassword]\n )\n\n const getToken = useCallback(async () => {\n return onGetToken?.()\n }, [onGetToken])\n\n const value: AuthContextValue<TUser> = {\n isAuthenticated,\n isLoggingIn: isAuthenticated && !user,\n isLoading,\n user,\n signUp,\n logIn,\n logOut,\n verifyOtp,\n loadUser,\n getToken,\n resetPassword,\n updatePassword,\n error,\n }\n\n return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>\n}\n\nexport const useAuth = <\n TUser extends User = DefaultUser,\n>(): AuthContextValue<TUser> => {\n const context = useContext(AuthContext)\n if (context === null) {\n throw new Error(\n 'Auth context missing, did you forget to wrap your app in AuthProvider?'\n )\n }\n\n return context as AuthContextValue<TUser>\n}\n\nexport const useCurrentUser = <TUser extends User = DefaultUser>():\n | TUser\n | null\n | undefined => {\n return useAuth<TUser>().user\n}\n\nexport interface UseLoginProps {\n action?: AuthActionEnum\n}\n\nexport const useLogin = ({ action = 'logIn' }: UseLoginProps = {}) => {\n const auth = useAuth()\n const fn = auth[action] || auth['logIn']\n return usePromise<AuthFunction>(fn)\n}\n\nexport const useSignUp = () => {\n const { signUp } = useAuth()\n return usePromise(signUp)\n}\n\nexport const useOtp = () => {\n const { verifyOtp } = useAuth()\n return usePromise(verifyOtp)\n}\n\nexport const useResetPassword = () => {\n const { resetPassword } = useAuth()\n return usePromise(resetPassword)\n}\n\nexport const useUpdatePassword = () => {\n const { updatePassword } = useAuth()\n return usePromise(updatePassword)\n}\n","import * as React from 'react'\n\nexport interface UsePromise {\n error?: Error | null\n data?: any\n isLoading: boolean\n isResolved: boolean\n isRejected: boolean\n}\n\ntype CallbackFn = (...args: any[]) => Promise<any>\n\n/**\n * @deprecated\n */\nexport function usePromise<C extends CallbackFn>(fn: C): [UsePromise, C] {\n const [isLoading, setLoading] = React.useState(false)\n const [isResolved, setResolved] = React.useState(false)\n const [isRejected, setRejected] = React.useState(false)\n const [error, setError] = React.useState(null)\n const [data, setData] = React.useState(null)\n\n const call: any = (...params: any) => {\n setLoading(true)\n\n return fn(...params)\n .then((data) => {\n setData(data)\n setResolved(true)\n setLoading(false)\n\n return data\n })\n .catch((err) => {\n setError(err)\n setRejected(true)\n setLoading(false)\n\n throw err\n })\n }\n\n return [{ error, data, isLoading, isResolved, isRejected }, call]\n}\n"],"mappings":"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","names":["React","useState","data","useState","React","user","error"]}