@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 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 params = new URLSearchParams(window.location.search);
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
- clean.searchParams.delete("__vaultix_connect");
339
- clean.searchParams.delete("provider");
340
- window.history.replaceState({}, "", clean.toString());
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
- setStep(data.preferred_challenge === "passkey" ? "passkey" : "password");
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)("div", { className: "flex items-center gap-2", children: [
735
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex-1 h-px bg-white/8" }),
736
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-[10px]", style: { color: mutedColor }, children: "or" }),
737
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "flex-1 h-px bg-white/8" })
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 params = new URLSearchParams(window.location.search);
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
- clean.searchParams.delete("__vaultix_connect");
304
- clean.searchParams.delete("provider");
305
- window.history.replaceState({}, "", clean.toString());
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
- setStep(data.preferred_challenge === "passkey" ? "passkey" : "password");
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("div", { className: "flex items-center gap-2", children: [
700
- /* @__PURE__ */ jsx2("div", { className: "flex-1 h-px bg-white/8" }),
701
- /* @__PURE__ */ jsx2("span", { className: "text-[10px]", style: { color: mutedColor }, children: "or" }),
702
- /* @__PURE__ */ jsx2("div", { className: "flex-1 h-px bg-white/8" })
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(Fragment, { children });
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(Fragment, { children });
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 Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
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(Fragment2, { children: [
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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaultix.ai/react",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "Vaultix-ID React SDK — drop-in auth components for any React app",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",