UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

518 lines (517 loc) 13.7 kB
'use client'; import { jsx as W } from "react/jsx-runtime"; import { createContext as $, useReducer as J, useMemo as p, useCallback as l, useEffect as Q, useContext as X } from "react"; import { AuthSDK as Y, OrganizationSDK as j, SessionSDK as K, UserSDK as ee, FrankAuthError as te } from "@frank-auth/sdk"; const O = $(null); function ae(i, s) { switch (s.type) { case "SET_LOADING": return { ...i, isLoading: s.payload }; case "SET_LOADED": return { ...i, isLoaded: s.payload }; case "SET_USER": return { ...i, user: s.payload, isSignedIn: !!s.payload, error: null }; case "SET_SESSION": return { ...i, session: s.payload, error: null }; case "SET_ORGANIZATION": return { ...i, organization: s.payload, error: null }; case "SET_ACTIVE_ORGANIZATION": return { ...i, activeOrganization: s.payload, error: null }; case "SET_MEMBERSHIPS": return { ...i, organizationMemberships: s.payload, error: null }; case "SET_FEATURES": return { ...i, features: s.payload }; case "SET_ERROR": return { ...i, error: s.payload, isLoading: !1 }; case "RESET_STATE": return { ...N, isLoaded: !0 }; default: return i; } } const N = { isLoaded: !1, isLoading: !1, isSignedIn: !1, user: null, session: null, organization: null, organizationMemberships: [], activeOrganization: null, error: null, features: { signUp: !0, signIn: !0, passwordReset: !0, mfa: !1, passkeys: !1, oauth: !1, magicLink: !1, sso: !1, organizationManagement: !1, userProfile: !0, sessionManagement: !0 }, // @ts-expect-error sdk: void 0 }; function ie({ children: i, publishableKey: s, userType: c = "external", apiUrl: y, secretKey: h, projectId: f, initialState: R, onError: _, onSignIn: A, onSignOut: T, debug: d = !1 }) { const [I, a] = J(ae, { ...N, ...R }), r = p(() => new Y({ publishableKey: s, apiUrl: y, enableDevMode: d, userType: c, projectId: f, secretKey: h }), [s, y, d]), E = p(() => new j({ publishableKey: s, apiUrl: y, enableDevMode: d, userType: c, projectId: f, secretKey: h }), [s, y, d]), S = p(() => new K({ publishableKey: s, apiUrl: y, enableDevMode: d, userType: c, projectId: f, secretKey: h }), [s, y, d]), w = p(() => new ee({ publishableKey: s, apiUrl: y, enableDevMode: d, userType: c, projectId: f, secretKey: h }), [s, y, d]), k = p(() => ({ auth: r, organization: E, session: S, user: w }), [w, r, E, S]), n = l( (t) => { const e = { code: t.code || "UNKNOWN_ERROR", message: t.message || "An unknown error occurred", details: t.details, field: t.field }; a({ type: "SET_ERROR", payload: e }), _?.(e), d && console.error("[FrankAuth] Error:", e); }, [_, d] ), g = l(async () => { try { a({ type: "SET_LOADING", payload: !0 }); const t = await r.getAuthStatus(); if (t.isAuthenticated && t.user) { if (a({ type: "SET_USER", payload: t.user }), a({ type: "SET_SESSION", payload: t.session }), f || t.user.organizationId) try { const o = f || t.user.organizationId || "", u = await E.getOrganization(o); a({ type: "SET_ORGANIZATION", payload: u }), a({ type: "SET_ACTIVE_ORGANIZATION", payload: u }); const H = await E.listMembers(o); a({ type: "SET_MEMBERSHIPS", payload: H.data }); } catch (o) { d && console.warn( "[FrankAuth] Failed to load organization:", o ); } const e = await L( t.user, I.organization, c ); a({ type: "SET_FEATURES", payload: e }); } a({ type: "SET_LOADED", payload: !0 }); } catch (t) { n(t); } finally { a({ type: "SET_LOADING", payload: !1 }); } }, [r, f, c, d, n]), L = async (t, e, o) => { const u = { signUp: !0, signIn: !0, passwordReset: !0, mfa: !1, passkeys: !1, oauth: !1, magicLink: !1, sso: !1, organizationManagement: !1, userProfile: !0, sessionManagement: !0 }; if (!t) return u; switch (o) { case "internal": return { ...u, mfa: !0, passkeys: !0, organizationManagement: !0, sso: !0 }; case "external": return { ...u, mfa: e?.settings?.mfaSettings?.enabled || !1, passkeys: e?.settings?.authConfig?.passkeysEnabled || !1, oauth: e?.settings?.authConfig?.oauthEnabled || !1, sso: e?.settings?.authConfig?.ssoEnabled || !1, organizationManagement: !0 }; case "end_user": return { ...u, mfa: e?.settings?.mfaSettings?.enabled || !1, passkeys: e?.settings?.authConfig?.passkeysEnabled || !1, oauth: e?.settings?.authConfig?.oauthEnabled || !1, organizationManagement: !1 }; default: return u; } }, m = l( async (t) => { try { a({ type: "SET_LOADING", payload: !0 }), a({ type: "SET_ERROR", payload: null }); let e, o = "complete"; switch (t.strategy) { case "password": if (!t.identifier || !t.password) throw new Error("Email/username and password are required"); const u = { email: t.identifier, password: t.password, organizationId: t.organizationId, rememberMe: !0 }; e = await r.signIn(u), e.mfaRequired ? o = "needs_mfa" : e.verificationRequired && (o = "needs_verification"); break; case "oauth": if (!t.provider) throw new Error("OAuth provider is required"); e = await r.initiateOAuthLogin(t.provider, { redirectUrl: t.redirectUrl, organizationId: t.organizationId }); break; case "magic_link": if (!t.identifier) throw new Error("Email is required for magic link"); e = await r.sendMagicLink({ email: t.identifier, redirectUrl: t.redirectUrl // organizationId: params.organizationId, }); break; case "passkey": e = await r.beginPasskeyAuthentication({ // todo fix }), o = "needs_passkey"; break; case "sso": if (!t.organizationId) throw new Error("Organization ID is required for SSO"); e = await r.initiateSSOLogin(t.organizationId, { redirectUrl: t.redirectUrl }); break; default: throw new Error(`Unsupported sign-in strategy: ${t.strategy}`); } return e.user && e.session && (a({ type: "SET_USER", payload: e.user }), a({ type: "SET_SESSION", payload: e.session }), A?.(e.user)), { status: o, user: e.user, session: e.session, verificationId: e.verificationId, mfaToken: e.mfaToken }; } catch (e) { return n(e), { status: "complete", error: { code: "SIGN_IN_FAILED", message: e instanceof te ? e.message : "Sign in failed" } }; } finally { a({ type: "SET_LOADING", payload: !1 }); } }, [r, A, n] ), D = l( async (t) => { try { a({ type: "SET_LOADING", payload: !0 }), a({ type: "SET_ERROR", payload: null }); const e = { email: t.emailAddress, password: t.password, firstName: t.firstName, lastName: t.lastName, username: t.username, userType: c, acceptTerms: t.acceptTerms, marketingConsent: t.marketingConsent, phoneNumber: t.phoneNumber, locale: t.locale ?? "en", organizationId: t.organizationId, invitationToken: t.invitationToken, customAttributes: t.unsafeMetadata }, o = await r.signUp(e); o.user && o.session && (a({ type: "SET_USER", payload: o.user }), a({ type: "SET_SESSION", payload: o.session }), A?.(o.user)); let u = "complete"; return o.verificationRequired && (u = "needs_verification"), { status: u, user: o.user, session: o.session, verificationId: o.verificationToken }; } catch (e) { return n(e), { status: "missing_requirements", error: { code: "SIGN_UP_FAILED", message: e instanceof Error ? e.message : "Sign up failed" } }; } finally { a({ type: "SET_LOADING", payload: !1 }); } }, [r, A, n] ), v = l(async () => { try { a({ type: "SET_LOADING", payload: !0 }), await r.signOut({ logoutAll: !1 }), r.authStorage.clearAll(), a({ type: "RESET_STATE" }), T?.(); } catch (t) { n(t); } finally { a({ type: "SET_LOADING", payload: !1 }); } }, [r, T, n]), z = l( async (t) => { try { S.activeSession = t; const e = await S.getCurrentSession(); return a({ type: "SET_SESSION", payload: e }), e; } catch (e) { throw n(e), e; } }, [r, n] ), G = l( async (t) => { try { if (t.session) { const e = t.session; typeof t.session == "string" && (S.activeSession = t.session, await S.getCurrentSession()), a({ type: "SET_SESSION", payload: e }); } if (t.organization) { const e = typeof t.organization == "string" ? await E.getOrganization(t.organization) : t.organization; a({ type: "SET_ACTIVE_ORGANIZATION", payload: e }); } } catch (e) { n(e); } }, [r, n] ), M = l( async (t) => { try { let e; typeof t == "string" ? e = await E.getOrganization(t) : e = t, a({ type: "SET_ACTIVE_ORGANIZATION", payload: e }); } catch (e) { n(e); } }, [r, n] ), C = l( async (t) => { try { a({ type: "SET_LOADING", payload: !0 }); const e = await r.switchOrganization(t); a({ type: "SET_ACTIVE_ORGANIZATION", payload: e }), await g(); } catch (e) { n(e); } finally { a({ type: "SET_LOADING", payload: !1 }); } }, [r, n, g] ), U = l( async (t) => { try { const e = await r.updateProfile(t); return a({ type: "SET_USER", payload: e }), e; } catch (e) { throw n(e), e; } }, [r, n] ), P = l(async () => { try { await w.deleteUser(), a({ type: "RESET_STATE" }), T?.(); } catch (t) { n(t); } }, [r, n, T]), q = l( async (t) => { try { return a({ type: "SET_LOADING", payload: !0 }), await r.requestPasswordReset(t); } catch (e) { throw n(e), e; } finally { a({ type: "SET_LOADING", payload: !1 }); } }, [r, n] ), F = l( async (t) => { try { return a({ type: "SET_LOADING", payload: !0 }), await r.resetPassword(t); } catch (e) { throw n(e), e; } finally { a({ type: "SET_LOADING", payload: !1 }); } }, [r, n] ), x = l( async (t) => { try { return a({ type: "SET_LOADING", payload: !0 }), await r.resendVerification(t); } catch (e) { throw n(e), e; } finally { a({ type: "SET_LOADING", payload: !1 }); } }, [r, n] ), V = l( async (t, e) => { try { return a({ type: "SET_LOADING", payload: !0 }), t === "phone" ? await r.verifyPhone(e) : await r.verifyEmail(e); } catch (o) { throw n(o), o; } finally { a({ type: "SET_LOADING", payload: !1 }); } }, [r, n] ), Z = l( async (t) => { try { return a({ type: "SET_LOADING", payload: !0 }), await r.validateToken(t); } catch (e) { throw n(e), e; } finally { a({ type: "SET_LOADING", payload: !1 }); } }, [r, n] ), b = l(async () => { await g(); }, [g]); Q(() => { g(); }, [g]); const B = { // State ...I, // Methods signIn: m, signUp: D, signOut: v, createSession: z, setActive: G, setActiveOrganization: M, switchOrganization: C, updateUser: U, deleteUser: P, reload: b, requestPasswordReset: q, resetPassword: F, validateToken: Z, resendVerification: x, verifyIdentity: V, sdk: k }; return /* @__PURE__ */ W(O.Provider, { value: B, children: i }); } function re() { const i = X(O); if (!i) throw new Error("useAuth must be used within an AuthProvider"); return i; } function le() { const { isLoaded: i, isSignedIn: s, user: c } = re(); return { isLoaded: i, isSignedIn: s, user: c, isAuthenticated: i && s, requireAuth: () => { if (!i) throw new Error("Authentication not loaded"); if (!s) throw new Error("Authentication required"); } }; } export { O as AuthContext, ie as AuthProvider, re as useAuth, le as useAuthGuard }; //# sourceMappingURL=auth-provider.js.map