@vaultix.ai/react 0.3.4 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +12 -1
- package/dist/index.d.ts +12 -1
- package/dist/index.js +76 -24
- package/dist/index.mjs +82 -30
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React$1 from 'react';
|
|
3
3
|
|
|
4
|
+
type AuthMethod = "password" | "magic_link" | "passkey";
|
|
5
|
+
type OAuthProvider = "google" | "github" | "meta" | "linkedin" | "x" | "threads";
|
|
6
|
+
interface AppConfig {
|
|
7
|
+
methods: AuthMethod[];
|
|
8
|
+
providers: OAuthProvider[];
|
|
9
|
+
}
|
|
4
10
|
type RiskLevel = "low" | "medium" | "high" | "critical";
|
|
5
11
|
type ChallengeType = "passkey" | "magic_link" | "password" | "totp" | "sms_otp" | "email_otp";
|
|
6
12
|
interface SessionClaims {
|
|
@@ -76,6 +82,11 @@ interface VaultixContextValue {
|
|
|
76
82
|
isSignedIn: boolean;
|
|
77
83
|
/** Resolved API origin derived from the publishable key. */
|
|
78
84
|
apiOrigin: string;
|
|
85
|
+
/**
|
|
86
|
+
* Per-app auth configuration. Null while loading, then set from /api/v1/app/config.
|
|
87
|
+
* Controls which login methods and OAuth providers are rendered by <SignIn /> and <SignUp />.
|
|
88
|
+
*/
|
|
89
|
+
appConfig: AppConfig | null;
|
|
79
90
|
signOut: (redirectUrl?: string) => Promise<void>;
|
|
80
91
|
/** Update the current user's profile. Resolves with the updated user. */
|
|
81
92
|
updateUser: (params: UpdateUserParams) => Promise<VaultixUser>;
|
|
@@ -240,4 +251,4 @@ declare function getStoredToken(): string | null;
|
|
|
240
251
|
/** Clears the stored session JWT. Call on 401 so the user is prompted to sign in again. */
|
|
241
252
|
declare function clearStoredToken(): void;
|
|
242
253
|
|
|
243
|
-
export { type ChallengeType, type ConnectPlatformOptions, OrganizationSwitcher, type PlatformConnectResult, RedirectToSignIn, RedirectToSignUp, type RiskLevel, type SessionClaims, SignIn, SignUp, SignedIn, SignedOut, type UpdateUserParams, UserButton, type VaultixAppearance, type VaultixAppearanceVariables, type VaultixContextValue, type VaultixOrganization, VaultixProvider, type VaultixProviderProps, type VaultixSession, type VaultixUser, clearStoredToken, getStoredToken, useAuth, useOrganization, usePlatformConnect, useSession, useUser, useVaultix };
|
|
254
|
+
export { type AppConfig, type AuthMethod, type ChallengeType, type ConnectPlatformOptions, type OAuthProvider, OrganizationSwitcher, type PlatformConnectResult, RedirectToSignIn, RedirectToSignUp, type RiskLevel, type SessionClaims, SignIn, SignUp, SignedIn, SignedOut, type UpdateUserParams, UserButton, type VaultixAppearance, type VaultixAppearanceVariables, type VaultixContextValue, type VaultixOrganization, VaultixProvider, type VaultixProviderProps, type VaultixSession, type VaultixUser, clearStoredToken, getStoredToken, useAuth, useOrganization, usePlatformConnect, useSession, useUser, useVaultix };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React$1 from 'react';
|
|
3
3
|
|
|
4
|
+
type AuthMethod = "password" | "magic_link" | "passkey";
|
|
5
|
+
type OAuthProvider = "google" | "github" | "meta" | "linkedin" | "x" | "threads";
|
|
6
|
+
interface AppConfig {
|
|
7
|
+
methods: AuthMethod[];
|
|
8
|
+
providers: OAuthProvider[];
|
|
9
|
+
}
|
|
4
10
|
type RiskLevel = "low" | "medium" | "high" | "critical";
|
|
5
11
|
type ChallengeType = "passkey" | "magic_link" | "password" | "totp" | "sms_otp" | "email_otp";
|
|
6
12
|
interface SessionClaims {
|
|
@@ -76,6 +82,11 @@ interface VaultixContextValue {
|
|
|
76
82
|
isSignedIn: boolean;
|
|
77
83
|
/** Resolved API origin derived from the publishable key. */
|
|
78
84
|
apiOrigin: string;
|
|
85
|
+
/**
|
|
86
|
+
* Per-app auth configuration. Null while loading, then set from /api/v1/app/config.
|
|
87
|
+
* Controls which login methods and OAuth providers are rendered by <SignIn /> and <SignUp />.
|
|
88
|
+
*/
|
|
89
|
+
appConfig: AppConfig | null;
|
|
79
90
|
signOut: (redirectUrl?: string) => Promise<void>;
|
|
80
91
|
/** Update the current user's profile. Resolves with the updated user. */
|
|
81
92
|
updateUser: (params: UpdateUserParams) => Promise<VaultixUser>;
|
|
@@ -240,4 +251,4 @@ declare function getStoredToken(): string | null;
|
|
|
240
251
|
/** Clears the stored session JWT. Call on 401 so the user is prompted to sign in again. */
|
|
241
252
|
declare function clearStoredToken(): void;
|
|
242
253
|
|
|
243
|
-
export { type ChallengeType, type ConnectPlatformOptions, OrganizationSwitcher, type PlatformConnectResult, RedirectToSignIn, RedirectToSignUp, type RiskLevel, type SessionClaims, SignIn, SignUp, SignedIn, SignedOut, type UpdateUserParams, UserButton, type VaultixAppearance, type VaultixAppearanceVariables, type VaultixContextValue, type VaultixOrganization, VaultixProvider, type VaultixProviderProps, type VaultixSession, type VaultixUser, clearStoredToken, getStoredToken, useAuth, useOrganization, usePlatformConnect, useSession, useUser, useVaultix };
|
|
254
|
+
export { type AppConfig, type AuthMethod, type ChallengeType, type ConnectPlatformOptions, type OAuthProvider, OrganizationSwitcher, type PlatformConnectResult, RedirectToSignIn, RedirectToSignUp, type RiskLevel, type SessionClaims, SignIn, SignUp, SignedIn, SignedOut, type UpdateUserParams, UserButton, type VaultixAppearance, type VaultixAppearanceVariables, type VaultixContextValue, type VaultixOrganization, VaultixProvider, type VaultixProviderProps, type VaultixSession, type VaultixUser, clearStoredToken, getStoredToken, useAuth, useOrganization, usePlatformConnect, useSession, useUser, useVaultix };
|
package/dist/index.js
CHANGED
|
@@ -112,6 +112,7 @@ function VaultixProvider({
|
|
|
112
112
|
const [user, setUser] = (0, import_react.useState)(null);
|
|
113
113
|
const [session, setSession] = (0, import_react.useState)(null);
|
|
114
114
|
const [organization, setOrganization] = (0, import_react.useState)(null);
|
|
115
|
+
const [appConfig, setAppConfig] = (0, import_react.useState)(null);
|
|
115
116
|
const jwtRef = (0, import_react.useRef)(null);
|
|
116
117
|
const refreshTimerRef = (0, import_react.useRef)(null);
|
|
117
118
|
const clearAuth = (0, import_react.useCallback)(() => {
|
|
@@ -212,7 +213,21 @@ function VaultixProvider({
|
|
|
212
213
|
if (!cancelled) setIsLoaded(true);
|
|
213
214
|
}
|
|
214
215
|
}
|
|
216
|
+
async function fetchAppConfig() {
|
|
217
|
+
try {
|
|
218
|
+
const res = await fetch(
|
|
219
|
+
`${apiOrigin}/api/v1/app/config?pk=${encodeURIComponent(publishableKey)}`,
|
|
220
|
+
{ credentials: "omit" }
|
|
221
|
+
);
|
|
222
|
+
if (res.ok && !cancelled) {
|
|
223
|
+
const cfg = await res.json();
|
|
224
|
+
setAppConfig(cfg);
|
|
225
|
+
}
|
|
226
|
+
} catch {
|
|
227
|
+
}
|
|
228
|
+
}
|
|
215
229
|
hydrate();
|
|
230
|
+
void fetchAppConfig();
|
|
216
231
|
return () => {
|
|
217
232
|
cancelled = true;
|
|
218
233
|
if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
|
|
@@ -271,6 +286,7 @@ function VaultixProvider({
|
|
|
271
286
|
isLoaded,
|
|
272
287
|
isSignedIn: !!session,
|
|
273
288
|
apiOrigin,
|
|
289
|
+
appConfig,
|
|
274
290
|
signOut,
|
|
275
291
|
updateUser,
|
|
276
292
|
connectPlatform
|
|
@@ -316,7 +332,11 @@ function usePlatformConnect(provider, defaultOptions) {
|
|
|
316
332
|
);
|
|
317
333
|
(0, import_react2.useEffect)(() => {
|
|
318
334
|
if (typeof window === "undefined") return;
|
|
319
|
-
const
|
|
335
|
+
const hashStr = window.location.hash.startsWith("#") ? window.location.hash.slice(1) : "";
|
|
336
|
+
const hashParams = new URLSearchParams(hashStr);
|
|
337
|
+
const queryParams = new URLSearchParams(window.location.search);
|
|
338
|
+
const usingHash = hashParams.has("__vaultix_connect");
|
|
339
|
+
const params = usingHash ? hashParams : queryParams;
|
|
320
340
|
const connectToken = params.get("__vaultix_connect");
|
|
321
341
|
const returnedProvider = params.get("provider");
|
|
322
342
|
if (!connectToken || returnedProvider !== provider) return;
|
|
@@ -335,9 +355,13 @@ function usePlatformConnect(provider, defaultOptions) {
|
|
|
335
355
|
};
|
|
336
356
|
setConnectedAccount(result);
|
|
337
357
|
const clean = new URL(window.location.href);
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
358
|
+
if (usingHash) {
|
|
359
|
+
clean.hash = "";
|
|
360
|
+
} else {
|
|
361
|
+
clean.searchParams.delete("__vaultix_connect");
|
|
362
|
+
clean.searchParams.delete("provider");
|
|
363
|
+
}
|
|
364
|
+
window.history.replaceState({}, "", clean.href.replace(/#$/, ""));
|
|
341
365
|
} catch {
|
|
342
366
|
}
|
|
343
367
|
}, [provider]);
|
|
@@ -413,6 +437,16 @@ function SignIn({
|
|
|
413
437
|
const cardBg = vars.colorBackground ?? "rgba(22,27,45,0.92)";
|
|
414
438
|
const textColor = vars.colorText ?? "rgba(255,255,255,0.9)";
|
|
415
439
|
const mutedColor = vars.colorTextMuted ?? "#475569";
|
|
440
|
+
let appConfig = null;
|
|
441
|
+
try {
|
|
442
|
+
appConfig = useVaultixContext().appConfig;
|
|
443
|
+
} catch {
|
|
444
|
+
}
|
|
445
|
+
const enabledProviders = appConfig?.providers ?? ["google", "github", "meta", "linkedin", "x", "threads"];
|
|
446
|
+
const enabledMethods = appConfig?.methods ?? ["password", "magic_link", "passkey"];
|
|
447
|
+
const hasPassword = enabledMethods.includes("password");
|
|
448
|
+
const hasMagicLink = enabledMethods.includes("magic_link");
|
|
449
|
+
const hasPasskey = enabledMethods.includes("passkey");
|
|
416
450
|
const [step, setStep] = (0, import_react3.useState)("email");
|
|
417
451
|
const [email, setEmail] = (0, import_react3.useState)("");
|
|
418
452
|
const [password, setPassword] = (0, import_react3.useState)("");
|
|
@@ -462,7 +496,15 @@ function SignIn({
|
|
|
462
496
|
setErr(data.error ?? "Could not look up account.");
|
|
463
497
|
return;
|
|
464
498
|
}
|
|
465
|
-
|
|
499
|
+
if (data.preferred_challenge === "passkey" && hasPasskey) {
|
|
500
|
+
setStep("passkey");
|
|
501
|
+
} else if (hasPassword) {
|
|
502
|
+
setStep("password");
|
|
503
|
+
} else if (hasMagicLink) {
|
|
504
|
+
await handleMagicLinkRequest();
|
|
505
|
+
} else if (hasPasskey) {
|
|
506
|
+
setStep("passkey");
|
|
507
|
+
}
|
|
466
508
|
} catch {
|
|
467
509
|
setErr("Network error. Please try again.");
|
|
468
510
|
} finally {
|
|
@@ -695,13 +737,13 @@ function SignIn({
|
|
|
695
737
|
error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "rounded-lg bg-red-500/10 border border-red-500/30 px-3 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-red-400", children: error }) }),
|
|
696
738
|
info && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "rounded-lg bg-blue-500/10 border border-blue-500/30 px-3 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "text-xs text-blue-400", children: info }) }),
|
|
697
739
|
step === "email" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-3", children: [
|
|
698
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GoogleButton, { onClick: handleGoogleSignIn }),
|
|
699
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GitHubButton, { onClick: handleGitHubSignIn }),
|
|
700
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MetaButton, { onClick: handleMetaSignIn }),
|
|
701
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LinkedInButton, { onClick: handleLinkedInSignIn }),
|
|
702
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(XButton, { onClick: handleXSignIn }),
|
|
703
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Divider, { mutedColor }),
|
|
704
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleEmailSubmit, className: "space-y-3", children: [
|
|
740
|
+
enabledProviders.includes("google") && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GoogleButton, { onClick: handleGoogleSignIn }),
|
|
741
|
+
enabledProviders.includes("github") && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GitHubButton, { onClick: handleGitHubSignIn }),
|
|
742
|
+
enabledProviders.includes("meta") && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MetaButton, { onClick: handleMetaSignIn }),
|
|
743
|
+
enabledProviders.includes("linkedin") && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LinkedInButton, { onClick: handleLinkedInSignIn }),
|
|
744
|
+
enabledProviders.includes("x") && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(XButton, { onClick: handleXSignIn }),
|
|
745
|
+
(hasPassword || hasMagicLink || hasPasskey) && enabledProviders.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Divider, { mutedColor }),
|
|
746
|
+
(hasPassword || hasMagicLink || hasPasskey) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleEmailSubmit, className: "space-y-3", children: [
|
|
705
747
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
706
748
|
Input,
|
|
707
749
|
{
|
|
@@ -731,12 +773,14 @@ function SignIn({
|
|
|
731
773
|
}
|
|
732
774
|
),
|
|
733
775
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(PrimaryButton, { loading, primaryColor, children: "Sign in" }),
|
|
734
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
735
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.
|
|
736
|
-
|
|
737
|
-
|
|
776
|
+
hasMagicLink && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
777
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
778
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex-1 h-px bg-white/8" }),
|
|
779
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-[10px]", style: { color: mutedColor }, children: "or" }),
|
|
780
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex-1 h-px bg-white/8" })
|
|
781
|
+
] }),
|
|
782
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GhostButton, { onClick: handleMagicLinkRequest, mutedColor, children: "\u2709 Email me a sign-in link" })
|
|
738
783
|
] }),
|
|
739
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GhostButton, { onClick: handleMagicLinkRequest, mutedColor, children: "\u2709 Email me a sign-in link" }),
|
|
740
784
|
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(GhostButton, { onClick: () => {
|
|
741
785
|
setStep("forgot");
|
|
742
786
|
setError(null);
|
|
@@ -1070,6 +1114,14 @@ function SignUp({
|
|
|
1070
1114
|
const cardBg = vars.colorBackground ?? "rgba(22,27,45,0.92)";
|
|
1071
1115
|
const textColor = vars.colorText ?? "rgba(255,255,255,0.9)";
|
|
1072
1116
|
const mutedColor = vars.colorTextMuted ?? "#475569";
|
|
1117
|
+
let appConfig = null;
|
|
1118
|
+
try {
|
|
1119
|
+
appConfig = useVaultixContext().appConfig;
|
|
1120
|
+
} catch {
|
|
1121
|
+
}
|
|
1122
|
+
const enabledProviders = appConfig?.providers ?? ["google", "github", "meta", "linkedin", "x", "threads"];
|
|
1123
|
+
const enabledMethods = appConfig?.methods ?? ["password", "magic_link", "passkey"];
|
|
1124
|
+
const hasPassword = enabledMethods.includes("password");
|
|
1073
1125
|
const [step, setStep] = (0, import_react4.useState)("email");
|
|
1074
1126
|
const [email, setEmail] = (0, import_react4.useState)("");
|
|
1075
1127
|
const [password, setPassword] = (0, import_react4.useState)("");
|
|
@@ -1181,13 +1233,13 @@ function SignUp({
|
|
|
1181
1233
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "px-8 pb-8 space-y-4", children: [
|
|
1182
1234
|
error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "rounded-lg bg-red-500/10 border border-red-500/30 px-3 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-xs text-red-400", children: error }) }),
|
|
1183
1235
|
step === "email" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "space-y-3", children: [
|
|
1184
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(OAuthButton2, { icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GoogleIcon2, {}), label: "Continue with Google", onClick: () => oauthRedirect("google") }),
|
|
1185
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(OAuthButton2, { icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GitHubIcon2, {}), label: "Continue with GitHub", onClick: () => oauthRedirect("github") }),
|
|
1186
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(OAuthButton2, { icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MetaIcon2, {}), label: "Continue with Facebook", onClick: () => oauthRedirect("meta") }),
|
|
1187
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(OAuthButton2, { icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LinkedInIcon2, {}), label: "Continue with LinkedIn", onClick: () => oauthRedirect("linkedin") }),
|
|
1188
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(OAuthButton2, { icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(XIcon2, {}), label: "Continue with X", onClick: () => oauthRedirect("x") }),
|
|
1189
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Divider2, { mutedColor }),
|
|
1190
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { onSubmit: handleEmailPassword, className: "space-y-3", children: [
|
|
1236
|
+
enabledProviders.includes("google") && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(OAuthButton2, { icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GoogleIcon2, {}), label: "Continue with Google", onClick: () => oauthRedirect("google") }),
|
|
1237
|
+
enabledProviders.includes("github") && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(OAuthButton2, { icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(GitHubIcon2, {}), label: "Continue with GitHub", onClick: () => oauthRedirect("github") }),
|
|
1238
|
+
enabledProviders.includes("meta") && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(OAuthButton2, { icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MetaIcon2, {}), label: "Continue with Facebook", onClick: () => oauthRedirect("meta") }),
|
|
1239
|
+
enabledProviders.includes("linkedin") && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(OAuthButton2, { icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LinkedInIcon2, {}), label: "Continue with LinkedIn", onClick: () => oauthRedirect("linkedin") }),
|
|
1240
|
+
enabledProviders.includes("x") && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(OAuthButton2, { icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(XIcon2, {}), label: "Continue with X", onClick: () => oauthRedirect("x") }),
|
|
1241
|
+
hasPassword && enabledProviders.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Divider2, { mutedColor }),
|
|
1242
|
+
hasPassword && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { onSubmit: handleEmailPassword, className: "space-y-3", children: [
|
|
1191
1243
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1192
1244
|
Input2,
|
|
1193
1245
|
{
|
package/dist/index.mjs
CHANGED
|
@@ -77,6 +77,7 @@ function VaultixProvider({
|
|
|
77
77
|
const [user, setUser] = useState(null);
|
|
78
78
|
const [session, setSession] = useState(null);
|
|
79
79
|
const [organization, setOrganization] = useState(null);
|
|
80
|
+
const [appConfig, setAppConfig] = useState(null);
|
|
80
81
|
const jwtRef = useRef(null);
|
|
81
82
|
const refreshTimerRef = useRef(null);
|
|
82
83
|
const clearAuth = useCallback(() => {
|
|
@@ -177,7 +178,21 @@ function VaultixProvider({
|
|
|
177
178
|
if (!cancelled) setIsLoaded(true);
|
|
178
179
|
}
|
|
179
180
|
}
|
|
181
|
+
async function fetchAppConfig() {
|
|
182
|
+
try {
|
|
183
|
+
const res = await fetch(
|
|
184
|
+
`${apiOrigin}/api/v1/app/config?pk=${encodeURIComponent(publishableKey)}`,
|
|
185
|
+
{ credentials: "omit" }
|
|
186
|
+
);
|
|
187
|
+
if (res.ok && !cancelled) {
|
|
188
|
+
const cfg = await res.json();
|
|
189
|
+
setAppConfig(cfg);
|
|
190
|
+
}
|
|
191
|
+
} catch {
|
|
192
|
+
}
|
|
193
|
+
}
|
|
180
194
|
hydrate();
|
|
195
|
+
void fetchAppConfig();
|
|
181
196
|
return () => {
|
|
182
197
|
cancelled = true;
|
|
183
198
|
if (refreshTimerRef.current) clearTimeout(refreshTimerRef.current);
|
|
@@ -236,6 +251,7 @@ function VaultixProvider({
|
|
|
236
251
|
isLoaded,
|
|
237
252
|
isSignedIn: !!session,
|
|
238
253
|
apiOrigin,
|
|
254
|
+
appConfig,
|
|
239
255
|
signOut,
|
|
240
256
|
updateUser,
|
|
241
257
|
connectPlatform
|
|
@@ -281,7 +297,11 @@ function usePlatformConnect(provider, defaultOptions) {
|
|
|
281
297
|
);
|
|
282
298
|
useEffect2(() => {
|
|
283
299
|
if (typeof window === "undefined") return;
|
|
284
|
-
const
|
|
300
|
+
const hashStr = window.location.hash.startsWith("#") ? window.location.hash.slice(1) : "";
|
|
301
|
+
const hashParams = new URLSearchParams(hashStr);
|
|
302
|
+
const queryParams = new URLSearchParams(window.location.search);
|
|
303
|
+
const usingHash = hashParams.has("__vaultix_connect");
|
|
304
|
+
const params = usingHash ? hashParams : queryParams;
|
|
285
305
|
const connectToken = params.get("__vaultix_connect");
|
|
286
306
|
const returnedProvider = params.get("provider");
|
|
287
307
|
if (!connectToken || returnedProvider !== provider) return;
|
|
@@ -300,9 +320,13 @@ function usePlatformConnect(provider, defaultOptions) {
|
|
|
300
320
|
};
|
|
301
321
|
setConnectedAccount(result);
|
|
302
322
|
const clean = new URL(window.location.href);
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
323
|
+
if (usingHash) {
|
|
324
|
+
clean.hash = "";
|
|
325
|
+
} else {
|
|
326
|
+
clean.searchParams.delete("__vaultix_connect");
|
|
327
|
+
clean.searchParams.delete("provider");
|
|
328
|
+
}
|
|
329
|
+
window.history.replaceState({}, "", clean.href.replace(/#$/, ""));
|
|
306
330
|
} catch {
|
|
307
331
|
}
|
|
308
332
|
}, [provider]);
|
|
@@ -333,7 +357,7 @@ function useAuth() {
|
|
|
333
357
|
// src/components/SignIn.tsx
|
|
334
358
|
import { clsx } from "clsx";
|
|
335
359
|
import { useRef as useRef2, useState as useState3 } from "react";
|
|
336
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
360
|
+
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
337
361
|
function toBase64url(buf) {
|
|
338
362
|
return btoa(String.fromCharCode(...new Uint8Array(buf))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
339
363
|
}
|
|
@@ -378,6 +402,16 @@ function SignIn({
|
|
|
378
402
|
const cardBg = vars.colorBackground ?? "rgba(22,27,45,0.92)";
|
|
379
403
|
const textColor = vars.colorText ?? "rgba(255,255,255,0.9)";
|
|
380
404
|
const mutedColor = vars.colorTextMuted ?? "#475569";
|
|
405
|
+
let appConfig = null;
|
|
406
|
+
try {
|
|
407
|
+
appConfig = useVaultixContext().appConfig;
|
|
408
|
+
} catch {
|
|
409
|
+
}
|
|
410
|
+
const enabledProviders = appConfig?.providers ?? ["google", "github", "meta", "linkedin", "x", "threads"];
|
|
411
|
+
const enabledMethods = appConfig?.methods ?? ["password", "magic_link", "passkey"];
|
|
412
|
+
const hasPassword = enabledMethods.includes("password");
|
|
413
|
+
const hasMagicLink = enabledMethods.includes("magic_link");
|
|
414
|
+
const hasPasskey = enabledMethods.includes("passkey");
|
|
381
415
|
const [step, setStep] = useState3("email");
|
|
382
416
|
const [email, setEmail] = useState3("");
|
|
383
417
|
const [password, setPassword] = useState3("");
|
|
@@ -427,7 +461,15 @@ function SignIn({
|
|
|
427
461
|
setErr(data.error ?? "Could not look up account.");
|
|
428
462
|
return;
|
|
429
463
|
}
|
|
430
|
-
|
|
464
|
+
if (data.preferred_challenge === "passkey" && hasPasskey) {
|
|
465
|
+
setStep("passkey");
|
|
466
|
+
} else if (hasPassword) {
|
|
467
|
+
setStep("password");
|
|
468
|
+
} else if (hasMagicLink) {
|
|
469
|
+
await handleMagicLinkRequest();
|
|
470
|
+
} else if (hasPasskey) {
|
|
471
|
+
setStep("passkey");
|
|
472
|
+
}
|
|
431
473
|
} catch {
|
|
432
474
|
setErr("Network error. Please try again.");
|
|
433
475
|
} finally {
|
|
@@ -660,13 +702,13 @@ function SignIn({
|
|
|
660
702
|
error && /* @__PURE__ */ jsx2("div", { className: "rounded-lg bg-red-500/10 border border-red-500/30 px-3 py-2", children: /* @__PURE__ */ jsx2("p", { className: "text-xs text-red-400", children: error }) }),
|
|
661
703
|
info && /* @__PURE__ */ jsx2("div", { className: "rounded-lg bg-blue-500/10 border border-blue-500/30 px-3 py-2", children: /* @__PURE__ */ jsx2("p", { className: "text-xs text-blue-400", children: info }) }),
|
|
662
704
|
step === "email" && /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
663
|
-
/* @__PURE__ */ jsx2(GoogleButton, { onClick: handleGoogleSignIn }),
|
|
664
|
-
/* @__PURE__ */ jsx2(GitHubButton, { onClick: handleGitHubSignIn }),
|
|
665
|
-
/* @__PURE__ */ jsx2(MetaButton, { onClick: handleMetaSignIn }),
|
|
666
|
-
/* @__PURE__ */ jsx2(LinkedInButton, { onClick: handleLinkedInSignIn }),
|
|
667
|
-
/* @__PURE__ */ jsx2(XButton, { onClick: handleXSignIn }),
|
|
668
|
-
/* @__PURE__ */ jsx2(Divider, { mutedColor }),
|
|
669
|
-
/* @__PURE__ */ jsxs("form", { onSubmit: handleEmailSubmit, className: "space-y-3", children: [
|
|
705
|
+
enabledProviders.includes("google") && /* @__PURE__ */ jsx2(GoogleButton, { onClick: handleGoogleSignIn }),
|
|
706
|
+
enabledProviders.includes("github") && /* @__PURE__ */ jsx2(GitHubButton, { onClick: handleGitHubSignIn }),
|
|
707
|
+
enabledProviders.includes("meta") && /* @__PURE__ */ jsx2(MetaButton, { onClick: handleMetaSignIn }),
|
|
708
|
+
enabledProviders.includes("linkedin") && /* @__PURE__ */ jsx2(LinkedInButton, { onClick: handleLinkedInSignIn }),
|
|
709
|
+
enabledProviders.includes("x") && /* @__PURE__ */ jsx2(XButton, { onClick: handleXSignIn }),
|
|
710
|
+
(hasPassword || hasMagicLink || hasPasskey) && enabledProviders.length > 0 && /* @__PURE__ */ jsx2(Divider, { mutedColor }),
|
|
711
|
+
(hasPassword || hasMagicLink || hasPasskey) && /* @__PURE__ */ jsxs("form", { onSubmit: handleEmailSubmit, className: "space-y-3", children: [
|
|
670
712
|
/* @__PURE__ */ jsx2(
|
|
671
713
|
Input,
|
|
672
714
|
{
|
|
@@ -696,12 +738,14 @@ function SignIn({
|
|
|
696
738
|
}
|
|
697
739
|
),
|
|
698
740
|
/* @__PURE__ */ jsx2(PrimaryButton, { loading, primaryColor, children: "Sign in" }),
|
|
699
|
-
/* @__PURE__ */ jsxs(
|
|
700
|
-
/* @__PURE__ */
|
|
701
|
-
|
|
702
|
-
|
|
741
|
+
hasMagicLink && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
742
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
743
|
+
/* @__PURE__ */ jsx2("div", { className: "flex-1 h-px bg-white/8" }),
|
|
744
|
+
/* @__PURE__ */ jsx2("span", { className: "text-[10px]", style: { color: mutedColor }, children: "or" }),
|
|
745
|
+
/* @__PURE__ */ jsx2("div", { className: "flex-1 h-px bg-white/8" })
|
|
746
|
+
] }),
|
|
747
|
+
/* @__PURE__ */ jsx2(GhostButton, { onClick: handleMagicLinkRequest, mutedColor, children: "\u2709 Email me a sign-in link" })
|
|
703
748
|
] }),
|
|
704
|
-
/* @__PURE__ */ jsx2(GhostButton, { onClick: handleMagicLinkRequest, mutedColor, children: "\u2709 Email me a sign-in link" }),
|
|
705
749
|
/* @__PURE__ */ jsx2(GhostButton, { onClick: () => {
|
|
706
750
|
setStep("forgot");
|
|
707
751
|
setError(null);
|
|
@@ -1035,6 +1079,14 @@ function SignUp({
|
|
|
1035
1079
|
const cardBg = vars.colorBackground ?? "rgba(22,27,45,0.92)";
|
|
1036
1080
|
const textColor = vars.colorText ?? "rgba(255,255,255,0.9)";
|
|
1037
1081
|
const mutedColor = vars.colorTextMuted ?? "#475569";
|
|
1082
|
+
let appConfig = null;
|
|
1083
|
+
try {
|
|
1084
|
+
appConfig = useVaultixContext().appConfig;
|
|
1085
|
+
} catch {
|
|
1086
|
+
}
|
|
1087
|
+
const enabledProviders = appConfig?.providers ?? ["google", "github", "meta", "linkedin", "x", "threads"];
|
|
1088
|
+
const enabledMethods = appConfig?.methods ?? ["password", "magic_link", "passkey"];
|
|
1089
|
+
const hasPassword = enabledMethods.includes("password");
|
|
1038
1090
|
const [step, setStep] = useState4("email");
|
|
1039
1091
|
const [email, setEmail] = useState4("");
|
|
1040
1092
|
const [password, setPassword] = useState4("");
|
|
@@ -1146,13 +1198,13 @@ function SignUp({
|
|
|
1146
1198
|
/* @__PURE__ */ jsxs2("div", { className: "px-8 pb-8 space-y-4", children: [
|
|
1147
1199
|
error && /* @__PURE__ */ jsx3("div", { className: "rounded-lg bg-red-500/10 border border-red-500/30 px-3 py-2", children: /* @__PURE__ */ jsx3("p", { className: "text-xs text-red-400", children: error }) }),
|
|
1148
1200
|
step === "email" && /* @__PURE__ */ jsxs2("div", { className: "space-y-3", children: [
|
|
1149
|
-
/* @__PURE__ */ jsx3(OAuthButton2, { icon: /* @__PURE__ */ jsx3(GoogleIcon2, {}), label: "Continue with Google", onClick: () => oauthRedirect("google") }),
|
|
1150
|
-
/* @__PURE__ */ jsx3(OAuthButton2, { icon: /* @__PURE__ */ jsx3(GitHubIcon2, {}), label: "Continue with GitHub", onClick: () => oauthRedirect("github") }),
|
|
1151
|
-
/* @__PURE__ */ jsx3(OAuthButton2, { icon: /* @__PURE__ */ jsx3(MetaIcon2, {}), label: "Continue with Facebook", onClick: () => oauthRedirect("meta") }),
|
|
1152
|
-
/* @__PURE__ */ jsx3(OAuthButton2, { icon: /* @__PURE__ */ jsx3(LinkedInIcon2, {}), label: "Continue with LinkedIn", onClick: () => oauthRedirect("linkedin") }),
|
|
1153
|
-
/* @__PURE__ */ jsx3(OAuthButton2, { icon: /* @__PURE__ */ jsx3(XIcon2, {}), label: "Continue with X", onClick: () => oauthRedirect("x") }),
|
|
1154
|
-
/* @__PURE__ */ jsx3(Divider2, { mutedColor }),
|
|
1155
|
-
/* @__PURE__ */ jsxs2("form", { onSubmit: handleEmailPassword, className: "space-y-3", children: [
|
|
1201
|
+
enabledProviders.includes("google") && /* @__PURE__ */ jsx3(OAuthButton2, { icon: /* @__PURE__ */ jsx3(GoogleIcon2, {}), label: "Continue with Google", onClick: () => oauthRedirect("google") }),
|
|
1202
|
+
enabledProviders.includes("github") && /* @__PURE__ */ jsx3(OAuthButton2, { icon: /* @__PURE__ */ jsx3(GitHubIcon2, {}), label: "Continue with GitHub", onClick: () => oauthRedirect("github") }),
|
|
1203
|
+
enabledProviders.includes("meta") && /* @__PURE__ */ jsx3(OAuthButton2, { icon: /* @__PURE__ */ jsx3(MetaIcon2, {}), label: "Continue with Facebook", onClick: () => oauthRedirect("meta") }),
|
|
1204
|
+
enabledProviders.includes("linkedin") && /* @__PURE__ */ jsx3(OAuthButton2, { icon: /* @__PURE__ */ jsx3(LinkedInIcon2, {}), label: "Continue with LinkedIn", onClick: () => oauthRedirect("linkedin") }),
|
|
1205
|
+
enabledProviders.includes("x") && /* @__PURE__ */ jsx3(OAuthButton2, { icon: /* @__PURE__ */ jsx3(XIcon2, {}), label: "Continue with X", onClick: () => oauthRedirect("x") }),
|
|
1206
|
+
hasPassword && enabledProviders.length > 0 && /* @__PURE__ */ jsx3(Divider2, { mutedColor }),
|
|
1207
|
+
hasPassword && /* @__PURE__ */ jsxs2("form", { onSubmit: handleEmailPassword, className: "space-y-3", children: [
|
|
1156
1208
|
/* @__PURE__ */ jsx3(
|
|
1157
1209
|
Input2,
|
|
1158
1210
|
{
|
|
@@ -1351,16 +1403,16 @@ function XIcon2() {
|
|
|
1351
1403
|
}
|
|
1352
1404
|
|
|
1353
1405
|
// src/components/SignedIn.tsx
|
|
1354
|
-
import { Fragment, jsx as jsx4 } from "react/jsx-runtime";
|
|
1406
|
+
import { Fragment as Fragment2, jsx as jsx4 } from "react/jsx-runtime";
|
|
1355
1407
|
function SignedIn({ children }) {
|
|
1356
1408
|
const { isLoaded, isSignedIn } = useVaultixContext();
|
|
1357
1409
|
if (!isLoaded || !isSignedIn) return null;
|
|
1358
|
-
return /* @__PURE__ */ jsx4(
|
|
1410
|
+
return /* @__PURE__ */ jsx4(Fragment2, { children });
|
|
1359
1411
|
}
|
|
1360
1412
|
function SignedOut({ children }) {
|
|
1361
1413
|
const { isLoaded, isSignedIn } = useVaultixContext();
|
|
1362
1414
|
if (!isLoaded || isSignedIn) return null;
|
|
1363
|
-
return /* @__PURE__ */ jsx4(
|
|
1415
|
+
return /* @__PURE__ */ jsx4(Fragment2, { children });
|
|
1364
1416
|
}
|
|
1365
1417
|
|
|
1366
1418
|
// src/components/RedirectComponents.tsx
|
|
@@ -1387,7 +1439,7 @@ function RedirectToSignUp({ redirectUrl = "/sign-up" }) {
|
|
|
1387
1439
|
// src/components/UserButton.tsx
|
|
1388
1440
|
import { clsx as clsx3 } from "clsx";
|
|
1389
1441
|
import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef3, useState as useState5 } from "react";
|
|
1390
|
-
import { Fragment as
|
|
1442
|
+
import { Fragment as Fragment3, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1391
1443
|
function UserButton({ showName = false, afterSignOutUrl, className }) {
|
|
1392
1444
|
const { user, session, isLoaded, isSignedIn, signOut } = useVaultixContext();
|
|
1393
1445
|
const [open, setOpen] = useState5(false);
|
|
@@ -1409,7 +1461,7 @@ function UserButton({ showName = false, afterSignOutUrl, className }) {
|
|
|
1409
1461
|
await signOut();
|
|
1410
1462
|
if (afterSignOutUrl) window.location.href = afterSignOutUrl;
|
|
1411
1463
|
}
|
|
1412
|
-
return /* @__PURE__ */ jsxs3(
|
|
1464
|
+
return /* @__PURE__ */ jsxs3(Fragment3, { children: [
|
|
1413
1465
|
/* @__PURE__ */ jsxs3("div", { ref: containerRef, className: clsx3("relative", className), children: [
|
|
1414
1466
|
/* @__PURE__ */ jsxs3(
|
|
1415
1467
|
"button",
|