@frank-auth/react
Version:
Flexible and customizable React UI components for Frank Authentication
518 lines (517 loc) • 13.7 kB
JavaScript
'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