@frank-auth/react
Version:
Flexible and customizable React UI components for Frank Authentication
355 lines (354 loc) • 9.94 kB
JavaScript
'use client';
import { jsx as c } from "react/jsx-runtime";
import { useReducer as I, useMemo as w, useEffect as g, useCallback as l, createContext as k, useContext as _ } from "react";
import { createFrankAuthConfig as L, ConfigManager as N } from "../config/index.js";
import { DEFAULT_FRANK_AUTH_CONFIG as p } from "../config/defaults.js";
import { validateFrankAuthConfig as U } from "../config/validators.js";
const f = k(null);
function P(e, a) {
switch (a.type) {
case "SET_LOADED":
return { ...e, isLoaded: a.payload };
case "SET_CONFIG":
return {
...e,
config: a.payload,
publishableKey: a.payload.publishableKey,
secretKey: a.payload.secretKey,
projectId: a.payload.projectId,
userType: a.payload.userType,
apiUrl: a.payload.apiUrl || e.apiUrl,
theme: a.payload.theme || e.theme,
appearance: a.payload.appearance || e.appearance,
localization: a.payload.localization || e.localization,
components: a.payload.components || e.components,
linksPath: { ...e.linksPath ?? {}, ...a.payload.linksPath },
features: a.payload.features || e.features,
debug: a.payload.debug || e.debug,
frontendUrl: a.payload.frontendUrl || e.frontendUrl
};
case "UPDATE_CONFIG":
const t = { ...e.config, ...a.payload };
return {
...e,
config: t,
// secretKey: action.payload.secretKey,
// projectId: action.payload.projectId,
theme: a.payload.theme || e.theme,
appearance: a.payload.appearance || e.appearance,
localization: a.payload.localization || e.localization,
components: a.payload.components || e.components,
linksPath: { ...e.linksPath ?? {}, ...a.payload.linksPath },
features: a.payload.features || e.features,
debug: a.payload.debug !== void 0 ? a.payload.debug : e.debug,
frontendUrl: a.payload.frontendUrl || e.frontendUrl
};
case "SET_ORGANIZATION":
return {
...e,
organizationConfig: a.payload,
config: {
...e.config,
organization: a.payload,
projectId: a.payload.id
}
};
case "SET_ORGANIZATION_SETTINGS":
return {
...e,
organizationSettings: a.payload
};
case "SET_THEME":
return {
...e,
theme: a.payload,
config: {
...e.config,
theme: a.payload
}
};
case "SET_APPEARANCE":
return {
...e,
appearance: a.payload,
config: {
...e.config,
appearance: a.payload
}
};
case "SET_LOCALIZATION":
return {
...e,
localization: a.payload,
config: {
...e.config,
localization: a.payload
}
};
case "SET_COMPONENTS":
return {
...e,
components: a.payload,
config: {
...e.config,
components: a.payload
}
};
case "SET_FEATURES":
return {
...e,
features: a.payload,
config: {
...e.config,
features: a.payload
}
};
case "SET_DEBUG":
return {
...e,
debug: a.payload,
config: {
...e.config,
debug: a.payload
}
};
case "RESET_CONFIG":
return {
...y,
publishableKey: e.publishableKey,
secretKey: e.secretKey,
projectId: e.projectId,
userType: e.userType,
apiUrl: e.apiUrl,
isLoaded: !0
};
default:
return e;
}
}
const y = {
isLoaded: !1,
config: p,
publishableKey: "",
userType: "external",
apiUrl: "https://api.frankauth.com",
theme: p.theme,
appearance: p.appearance,
localization: p.localization,
components: {},
linksPath: {
signUp: "/auth/sign-up",
magicLink: "/auth/magic-link",
verify: "/auth/verify",
signIn: "/auth/sign-in",
resetPassword: "/auth/reset-password",
forgotPassword: "/auth/forgot-password",
signOut: "/auth/sign-out"
},
features: {
signUp: !0,
signIn: !0,
passwordReset: !0,
mfa: !1,
passkeys: !1,
oauth: !1,
magicLink: !1,
sso: !1,
organizationManagement: !1,
userProfile: !0,
sessionManagement: !0
},
debug: !1
};
function x({
children: e,
config: a,
onConfigChange: t
}) {
const [s, i] = I(P, y), o = w(() => {
try {
const r = L(a);
return new N(r);
} catch (r) {
throw console.error("[FrankAuth] Invalid configuration:", r), r;
}
}, [a]);
g(() => {
const r = o.getConfig();
i({ type: "SET_CONFIG", payload: r }), i({ type: "SET_LOADED", payload: !0 });
}, [o]), g(() => o.subscribe((n) => {
i({ type: "SET_CONFIG", payload: n }), t?.(n);
}), [o, t]), g(() => {
typeof window < "u" && s.isLoaded && o.applyToDOM();
}, [o, s.isLoaded, s.theme, s.appearance]);
const h = l((r) => {
try {
const n = U({ ...s.config, ...r });
if (!n.isValid) {
const d = n.errors.map((F) => F.message).join(", ");
throw new Error(`Configuration validation failed: ${d}`);
}
o.updateConfig(r), i({ type: "UPDATE_CONFIG", payload: r });
} catch (n) {
throw console.error("[FrankAuth] Configuration update failed:", n), n;
}
}, [o, s.config]), m = l((r) => {
try {
const n = {
id: r.id,
name: r.name,
slug: r.slug || "",
settings: r.settings || {},
features: {
sso: r.ssoEnabled || !1,
mfa: r.settings?.mfaSettings?.enabled || !1,
auditLogs: r.settings?.auditSettings?.enabled || !1,
customBranding: !!r.settings?.branding,
apiAccess: r.apiEnabled || !1
},
limits: {
maxUsers: r.userLimit || 100,
maxSessions: r.sessionLimit || 10,
apiRequestLimit: r.apiRequestLimit || 1e3
}
};
o.setOrganization(n), i({ type: "SET_ORGANIZATION", payload: n });
const d = S(n);
i({ type: "SET_FEATURES", payload: d });
} catch (n) {
throw console.error("[FrankAuth] Failed to set organization:", n), n;
}
}, [o]), E = l((r) => {
try {
o.getThemeManager().setTheme(r), i({ type: "SET_THEME", payload: o.getThemeManager().getTheme() });
} catch (n) {
throw console.error("[FrankAuth] Failed to set theme:", n), n;
}
}, [o]), T = l((r) => {
try {
o.getAppearanceManager().updateConfig(r), i({ type: "SET_APPEARANCE", payload: o.getAppearanceManager().getConfig() });
} catch (n) {
throw console.error("[FrankAuth] Failed to set appearance:", n), n;
}
}, [o]), b = l((r) => {
try {
o.getLocalizationManager().setLocale(r), i({
type: "SET_LOCALIZATION",
payload: {
...s.localization,
defaultLocale: r
}
});
} catch (n) {
throw console.error("[FrankAuth] Failed to set locale:", n), n;
}
}, [o, s.localization]), C = l((r) => {
try {
if (r.settings?.branding) {
const n = {
logo: {
url: r.logoUrl,
alt: r.name
},
colors: {
primary: r.settings.branding.primaryColor || "#3b82f6",
secondary: r.settings.branding.secondaryColor || "#64748b"
},
fonts: {
primary: "Inter, ui-sans-serif, system-ui, sans-serif"
},
customCSS: r.settings.branding.customCSS
};
o.getThemeManager().applyBranding(n), o.getAppearanceManager().applyOrganizationBranding(r);
}
} catch (n) {
throw console.error("[FrankAuth] Failed to apply organization branding:", n), n;
}
}, [o]), A = l(() => {
try {
o.reset(), i({ type: "RESET_CONFIG" });
} catch (r) {
throw console.error("[FrankAuth] Failed to reset configuration:", r), r;
}
}, [o]), S = (r) => {
const n = r.settings;
return {
signUp: n.allowPublicSignup || !1,
signIn: !0,
passwordReset: !0,
mfa: r.features.mfa,
passkeys: n.authConfig?.passkeysEnabled || !1,
oauth: n.authConfig?.oauthEnabled || !1,
magicLink: n.authConfig?.magicLinkEnabled || !1,
sso: r.features.sso,
organizationManagement: !0,
userProfile: !0,
sessionManagement: !0
};
}, O = {
// State
...s,
// Methods
updateConfig: h,
setOrganization: m,
setTheme: E,
setAppearance: T,
setLocale: b,
applyOrganizationBranding: C,
resetToDefaults: A
};
return /* @__PURE__ */ c(f.Provider, { value: O, children: e });
}
function u() {
const e = _(f);
if (!e)
throw new Error("useConfig must be used within a ConfigProvider");
return e;
}
function D() {
const { features: e } = u();
return {
...e,
hasFeature: (a) => e[a],
requireFeature: (a) => {
if (!e[a])
throw new Error(`Feature ${a} is not enabled`);
}
};
}
function K() {
const { organizationConfig: e, organizationSettings: a, setOrganization: t, applyOrganizationBranding: s } = u();
return {
organization: e,
settings: a,
setOrganization: t,
applyBranding: s,
hasOrganization: !!e,
isMultiTenant: !!e
};
}
function j() {
const { components: e } = u(), a = l((t, s) => e[t] || s, [e]);
return {
components: e,
getComponent: a,
hasOverride: (t) => !!e[t]
};
}
function B(e) {
const a = (t) => {
const s = u();
return /* @__PURE__ */ c(e, { ...t, config: s });
};
return a.displayName = `withConfig(${e.displayName || e.name})`, a;
}
export {
f as ConfigContext,
x as ConfigProvider,
j as useComponentOverrides,
u as useConfig,
D as useFeatures,
K as useOrganizationConfig,
B as withConfig
};
//# sourceMappingURL=config-provider.js.map