@vaultix.ai/react 0.3.3 → 0.3.4

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.mjs CHANGED
@@ -254,7 +254,7 @@ function VaultixProvider({
254
254
  }
255
255
 
256
256
  // src/hooks/index.ts
257
- import { useCallback as useCallback2 } from "react";
257
+ import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
258
258
  function useVaultix() {
259
259
  return useVaultixContext();
260
260
  }
@@ -270,6 +270,44 @@ function useOrganization() {
270
270
  const { organization, isLoaded } = useVaultixContext();
271
271
  return { organization, isLoaded };
272
272
  }
273
+ function usePlatformConnect(provider, defaultOptions) {
274
+ const { connectPlatform } = useVaultixContext();
275
+ const [connectedAccount, setConnectedAccount] = useState2(null);
276
+ const connect = useCallback2(
277
+ (overrides) => {
278
+ connectPlatform(provider, { ...defaultOptions, ...overrides });
279
+ },
280
+ [connectPlatform, provider, defaultOptions]
281
+ );
282
+ useEffect2(() => {
283
+ if (typeof window === "undefined") return;
284
+ const params = new URLSearchParams(window.location.search);
285
+ const connectToken = params.get("__vaultix_connect");
286
+ const returnedProvider = params.get("provider");
287
+ if (!connectToken || returnedProvider !== provider) return;
288
+ try {
289
+ const segment = connectToken.split(".")[1];
290
+ if (!segment) return;
291
+ const b64 = segment.replace(/-/g, "+").replace(/_/g, "/");
292
+ const payload = JSON.parse(atob(b64));
293
+ const result = {
294
+ provider: returnedProvider,
295
+ raw: payload,
296
+ ...typeof payload["platform_user_id"] === "string" && { platformUserId: payload["platform_user_id"] },
297
+ ...typeof payload["username"] === "string" && { username: payload["username"] },
298
+ ...typeof payload["access_token"] === "string" && { accessToken: payload["access_token"] },
299
+ ...typeof payload["scope"] === "string" && { scope: payload["scope"] }
300
+ };
301
+ setConnectedAccount(result);
302
+ const clean = new URL(window.location.href);
303
+ clean.searchParams.delete("__vaultix_connect");
304
+ clean.searchParams.delete("provider");
305
+ window.history.replaceState({}, "", clean.toString());
306
+ } catch {
307
+ }
308
+ }, [provider]);
309
+ return { connect, connectedAccount };
310
+ }
273
311
  function useAuth() {
274
312
  const { user, session, isLoaded, isSignedIn, signOut } = useVaultixContext();
275
313
  const getToken = useCallback2(async () => {
@@ -294,7 +332,7 @@ function useAuth() {
294
332
 
295
333
  // src/components/SignIn.tsx
296
334
  import { clsx } from "clsx";
297
- import { useRef as useRef2, useState as useState2 } from "react";
335
+ import { useRef as useRef2, useState as useState3 } from "react";
298
336
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
299
337
  function toBase64url(buf) {
300
338
  return btoa(String.fromCharCode(...new Uint8Array(buf))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
@@ -331,18 +369,24 @@ function SignIn({
331
369
  onSuccess,
332
370
  onError,
333
371
  apiOrigin: apiOriginProp,
334
- className
372
+ className,
373
+ appearance
335
374
  }) {
336
375
  const apiOrigin = resolveApiOrigin2(apiOriginProp);
337
- const [step, setStep] = useState2("email");
338
- const [email, setEmail] = useState2("");
339
- const [password, setPassword] = useState2("");
340
- const [totp, setTotp] = useState2("");
341
- const [forgotCode, setForgotCode] = useState2("");
342
- const [newPassword, setNewPassword] = useState2("");
343
- const [error, setError] = useState2(null);
344
- const [loading, setLoading] = useState2(false);
345
- const [info, setInfo] = useState2(null);
376
+ const vars = appearance?.variables ?? {};
377
+ const primaryColor = vars.colorPrimary;
378
+ const cardBg = vars.colorBackground ?? "rgba(22,27,45,0.92)";
379
+ const textColor = vars.colorText ?? "rgba(255,255,255,0.9)";
380
+ const mutedColor = vars.colorTextMuted ?? "#475569";
381
+ const [step, setStep] = useState3("email");
382
+ const [email, setEmail] = useState3("");
383
+ const [password, setPassword] = useState3("");
384
+ const [totp, setTotp] = useState3("");
385
+ const [forgotCode, setForgotCode] = useState3("");
386
+ const [newPassword, setNewPassword] = useState3("");
387
+ const [error, setError] = useState3(null);
388
+ const [loading, setLoading] = useState3(false);
389
+ const [info, setInfo] = useState3(null);
346
390
  const challengeIdRef = useRef2(null);
347
391
  function setErr(msg) {
348
392
  setError(msg);
@@ -598,12 +642,19 @@ function SignIn({
598
642
  "backdrop-blur-[16px]",
599
643
  className
600
644
  ),
601
- style: { background: "rgba(22,27,45,0.92)" },
645
+ style: { background: cardBg },
602
646
  children: [
603
647
  /* @__PURE__ */ jsxs("div", { className: "px-8 pt-8 pb-6 text-center", children: [
604
- /* @__PURE__ */ jsx2("div", { className: "inline-flex items-center justify-center w-10 h-10 rounded-xl bg-gradient-to-br from-purple-600 to-blue-600 shadow-lg shadow-purple-500/30 mb-4", children: /* @__PURE__ */ jsx2(LockIcon, {}) }),
605
- /* @__PURE__ */ jsx2("h1", { className: "text-xl font-semibold text-white/90", children: title[step] }),
606
- /* @__PURE__ */ jsx2("p", { className: "text-sm text-[#475569] mt-1", children: subtitle[step] })
648
+ /* @__PURE__ */ jsx2(
649
+ "div",
650
+ {
651
+ className: "inline-flex items-center justify-center w-10 h-10 rounded-xl shadow-lg mb-4",
652
+ style: primaryColor ? { background: primaryColor, boxShadow: `0 10px 15px -3px ${primaryColor}4d` } : { background: "linear-gradient(to bottom right, #7c3aed, #2563eb)", boxShadow: "0 10px 15px -3px rgba(124,58,237,0.3)" },
653
+ children: /* @__PURE__ */ jsx2(LockIcon, {})
654
+ }
655
+ ),
656
+ /* @__PURE__ */ jsx2("h1", { className: "text-xl font-semibold", style: { color: textColor }, children: title[step] }),
657
+ /* @__PURE__ */ jsx2("p", { className: "text-sm mt-1", style: { color: mutedColor }, children: subtitle[step] })
607
658
  ] }),
608
659
  /* @__PURE__ */ jsxs("div", { className: "px-8 pb-8 space-y-4", children: [
609
660
  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 }) }),
@@ -614,7 +665,7 @@ function SignIn({
614
665
  /* @__PURE__ */ jsx2(MetaButton, { onClick: handleMetaSignIn }),
615
666
  /* @__PURE__ */ jsx2(LinkedInButton, { onClick: handleLinkedInSignIn }),
616
667
  /* @__PURE__ */ jsx2(XButton, { onClick: handleXSignIn }),
617
- /* @__PURE__ */ jsx2(Divider, {}),
668
+ /* @__PURE__ */ jsx2(Divider, { mutedColor }),
618
669
  /* @__PURE__ */ jsxs("form", { onSubmit: handleEmailSubmit, className: "space-y-3", children: [
619
670
  /* @__PURE__ */ jsx2(
620
671
  Input,
@@ -624,10 +675,11 @@ function SignIn({
624
675
  value: email,
625
676
  onChange: setEmail,
626
677
  autoFocus: true,
627
- required: true
678
+ required: true,
679
+ primaryColor
628
680
  }
629
681
  ),
630
- /* @__PURE__ */ jsx2(PrimaryButton, { loading, children: "Continue" })
682
+ /* @__PURE__ */ jsx2(PrimaryButton, { loading, primaryColor, children: "Continue" })
631
683
  ] })
632
684
  ] }),
633
685
  step === "password" && /* @__PURE__ */ jsxs("form", { onSubmit: handlePasswordSubmit, className: "space-y-3", children: [
@@ -639,42 +691,50 @@ function SignIn({
639
691
  value: password,
640
692
  onChange: setPassword,
641
693
  autoFocus: true,
642
- required: true
694
+ required: true,
695
+ primaryColor
643
696
  }
644
697
  ),
645
- /* @__PURE__ */ jsx2(PrimaryButton, { loading, children: "Sign in" }),
698
+ /* @__PURE__ */ jsx2(PrimaryButton, { loading, primaryColor, children: "Sign in" }),
646
699
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
647
700
  /* @__PURE__ */ jsx2("div", { className: "flex-1 h-px bg-white/8" }),
648
- /* @__PURE__ */ jsx2("span", { className: "text-[10px] text-[#475569]", children: "or" }),
701
+ /* @__PURE__ */ jsx2("span", { className: "text-[10px]", style: { color: mutedColor }, children: "or" }),
649
702
  /* @__PURE__ */ jsx2("div", { className: "flex-1 h-px bg-white/8" })
650
703
  ] }),
651
- /* @__PURE__ */ jsx2(GhostButton, { onClick: handleMagicLinkRequest, children: "\u2709 Email me a sign-in link" }),
704
+ /* @__PURE__ */ jsx2(GhostButton, { onClick: handleMagicLinkRequest, mutedColor, children: "\u2709 Email me a sign-in link" }),
652
705
  /* @__PURE__ */ jsx2(GhostButton, { onClick: () => {
653
706
  setStep("forgot");
654
707
  setError(null);
655
- }, children: "Forgot password?" }),
656
- /* @__PURE__ */ jsx2(GhostButton, { onClick: () => setStep("email"), children: "\u2190 Back" })
708
+ }, mutedColor, children: "Forgot password?" }),
709
+ /* @__PURE__ */ jsx2(GhostButton, { onClick: () => setStep("email"), mutedColor, children: "\u2190 Back" })
657
710
  ] }),
658
711
  step === "magic-link-sent" && /* @__PURE__ */ jsxs("div", { className: "space-y-4 text-center", children: [
659
- /* @__PURE__ */ jsx2("div", { className: "w-14 h-14 rounded-2xl bg-purple-500/15 border border-purple-500/30 flex items-center justify-center mx-auto", children: /* @__PURE__ */ jsx2(EnvelopeIcon, {}) }),
660
- /* @__PURE__ */ jsxs("p", { className: "text-sm text-[#94a3b8] leading-relaxed", children: [
712
+ /* @__PURE__ */ jsx2(
713
+ "div",
714
+ {
715
+ className: "w-14 h-14 rounded-2xl flex items-center justify-center mx-auto border",
716
+ style: primaryColor ? { background: `${primaryColor}26`, borderColor: `${primaryColor}4d` } : { background: "rgba(168,85,247,0.15)", borderColor: "rgba(168,85,247,0.3)" },
717
+ children: /* @__PURE__ */ jsx2(EnvelopeIcon, { color: primaryColor ?? "#a78bfa" })
718
+ }
719
+ ),
720
+ /* @__PURE__ */ jsxs("p", { className: "text-sm leading-relaxed", style: { color: mutedColor }, children: [
661
721
  "The link expires in ",
662
- /* @__PURE__ */ jsx2("span", { className: "text-white/80 font-medium", children: "15 minutes" }),
722
+ /* @__PURE__ */ jsx2("span", { style: { color: textColor }, className: "font-medium", children: "15 minutes" }),
663
723
  " and can only be used once."
664
724
  ] }),
665
- /* @__PURE__ */ jsx2(GhostButton, { onClick: handleMagicLinkRequest, children: "Resend link" }),
725
+ /* @__PURE__ */ jsx2(GhostButton, { onClick: handleMagicLinkRequest, mutedColor, children: "Resend link" }),
666
726
  /* @__PURE__ */ jsx2(GhostButton, { onClick: () => {
667
727
  setStep("password");
668
728
  setError(null);
669
- }, children: "Use password instead" })
729
+ }, mutedColor, children: "Use password instead" })
670
730
  ] }),
671
731
  step === "passkey" && /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
672
- /* @__PURE__ */ jsxs(PrimaryButton, { loading, onClick: handlePasskeySignIn, children: [
732
+ /* @__PURE__ */ jsxs(PrimaryButton, { loading, onClick: handlePasskeySignIn, primaryColor, children: [
673
733
  /* @__PURE__ */ jsx2(FingerprintIcon, {}),
674
734
  "Authenticate with passkey"
675
735
  ] }),
676
- /* @__PURE__ */ jsx2(GhostButton, { onClick: () => setStep("password"), children: "Use password instead" }),
677
- /* @__PURE__ */ jsx2(GhostButton, { onClick: () => setStep("email"), children: "\u2190 Back" })
736
+ /* @__PURE__ */ jsx2(GhostButton, { onClick: () => setStep("password"), mutedColor, children: "Use password instead" }),
737
+ /* @__PURE__ */ jsx2(GhostButton, { onClick: () => setStep("email"), mutedColor, children: "\u2190 Back" })
678
738
  ] }),
679
739
  step === "totp" && /* @__PURE__ */ jsxs("form", { onSubmit: handleTotpSubmit, className: "space-y-3", children: [
680
740
  /* @__PURE__ */ jsx2(
@@ -689,11 +749,12 @@ function SignIn({
689
749
  onChange: setTotp,
690
750
  autoFocus: true,
691
751
  required: true,
692
- className: "text-center tracking-[0.4em] text-lg"
752
+ className: "text-center tracking-[0.4em] text-lg",
753
+ primaryColor
693
754
  }
694
755
  ),
695
- /* @__PURE__ */ jsx2(PrimaryButton, { loading, children: "Verify" }),
696
- /* @__PURE__ */ jsx2(GhostButton, { onClick: () => setStep("password"), children: "\u2190 Back" })
756
+ /* @__PURE__ */ jsx2(PrimaryButton, { loading, primaryColor, children: "Verify" }),
757
+ /* @__PURE__ */ jsx2(GhostButton, { onClick: () => setStep("password"), mutedColor, children: "\u2190 Back" })
697
758
  ] }),
698
759
  step === "forgot" && /* @__PURE__ */ jsxs("form", { onSubmit: handleForgotSubmit, className: "space-y-3", children: [
699
760
  /* @__PURE__ */ jsx2(
@@ -704,14 +765,15 @@ function SignIn({
704
765
  value: email,
705
766
  onChange: setEmail,
706
767
  autoFocus: true,
707
- required: true
768
+ required: true,
769
+ primaryColor
708
770
  }
709
771
  ),
710
- /* @__PURE__ */ jsx2(PrimaryButton, { loading, children: "Send reset code" }),
772
+ /* @__PURE__ */ jsx2(PrimaryButton, { loading, primaryColor, children: "Send reset code" }),
711
773
  /* @__PURE__ */ jsx2(GhostButton, { onClick: () => {
712
774
  setStep("password");
713
775
  setError(null);
714
- }, children: "\u2190 Back" })
776
+ }, mutedColor, children: "\u2190 Back" })
715
777
  ] }),
716
778
  step === "forgot-verify" && /* @__PURE__ */ jsxs("form", { onSubmit: handleForgotVerifySubmit, className: "space-y-3", children: [
717
779
  /* @__PURE__ */ jsx2(
@@ -726,10 +788,11 @@ function SignIn({
726
788
  onChange: setForgotCode,
727
789
  autoFocus: true,
728
790
  required: true,
729
- className: "text-center tracking-[0.4em] text-lg"
791
+ className: "text-center tracking-[0.4em] text-lg",
792
+ primaryColor
730
793
  }
731
794
  ),
732
- /* @__PURE__ */ jsx2(PrimaryButton, { loading, children: "Continue" })
795
+ /* @__PURE__ */ jsx2(PrimaryButton, { loading, primaryColor, children: "Continue" })
733
796
  ] }),
734
797
  step === "forgot-reset" && /* @__PURE__ */ jsxs("form", { onSubmit: handleResetPasswordSubmit, className: "space-y-3", children: [
735
798
  /* @__PURE__ */ jsx2(
@@ -741,18 +804,19 @@ function SignIn({
741
804
  onChange: setNewPassword,
742
805
  autoFocus: true,
743
806
  required: true,
744
- minLength: 8
807
+ minLength: 8,
808
+ primaryColor
745
809
  }
746
810
  ),
747
811
  /* @__PURE__ */ jsx2(PasswordStrength, { password: newPassword }),
748
- /* @__PURE__ */ jsx2(PrimaryButton, { loading, children: "Reset password" })
812
+ /* @__PURE__ */ jsx2(PrimaryButton, { loading, primaryColor, children: "Reset password" })
749
813
  ] })
750
814
  ] })
751
815
  ]
752
816
  }
753
817
  );
754
818
  }
755
- function Input({ onChange, className, ...props }) {
819
+ function Input({ onChange, className, primaryColor, ...props }) {
756
820
  return /* @__PURE__ */ jsx2(
757
821
  "input",
758
822
  {
@@ -761,39 +825,48 @@ function Input({ onChange, className, ...props }) {
761
825
  className: clsx(
762
826
  "w-full bg-white/5 border border-white/8 rounded-xl px-4 py-2.5",
763
827
  "text-sm text-white/90 placeholder:text-[#475569]",
764
- "focus:outline-none focus:border-purple-500/60 transition-colors",
828
+ "focus:outline-none transition-colors",
829
+ !primaryColor && "focus:border-purple-500/60",
765
830
  className
766
- )
831
+ ),
832
+ style: primaryColor ? { "--vx-focus": primaryColor } : void 0,
833
+ onFocus: (e) => {
834
+ if (primaryColor) e.currentTarget.style.borderColor = `${primaryColor}99`;
835
+ props.onFocus?.(e);
836
+ },
837
+ onBlur: (e) => {
838
+ if (primaryColor) e.currentTarget.style.borderColor = "";
839
+ props.onBlur?.(e);
840
+ }
767
841
  }
768
842
  );
769
843
  }
770
- function PrimaryButton({ children, loading, onClick }) {
844
+ function PrimaryButton({ children, loading, onClick, primaryColor }) {
771
845
  return /* @__PURE__ */ jsx2(
772
846
  "button",
773
847
  {
774
848
  type: onClick ? "button" : "submit",
775
849
  onClick,
776
850
  disabled: loading,
851
+ style: primaryColor ? { background: primaryColor, boxShadow: `0 10px 15px -3px ${primaryColor}33` } : void 0,
777
852
  className: clsx(
778
853
  "w-full flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl",
779
- "text-sm font-semibold text-white",
780
- "bg-gradient-to-r from-purple-600 to-blue-600",
781
- "hover:from-purple-500 hover:to-blue-500",
782
- "shadow-lg shadow-purple-500/20",
783
- "transition-all duration-150",
784
- "disabled:opacity-60 disabled:cursor-not-allowed"
854
+ "text-sm font-semibold text-white transition-all duration-150",
855
+ "disabled:opacity-60 disabled:cursor-not-allowed",
856
+ !primaryColor && "bg-gradient-to-r from-purple-600 to-blue-600 hover:from-purple-500 hover:to-blue-500 shadow-lg shadow-purple-500/20"
785
857
  ),
786
858
  children: loading ? /* @__PURE__ */ jsx2(Spinner, {}) : children
787
859
  }
788
860
  );
789
861
  }
790
- function GhostButton({ children, onClick }) {
862
+ function GhostButton({ children, onClick, mutedColor }) {
791
863
  return /* @__PURE__ */ jsx2(
792
864
  "button",
793
865
  {
794
866
  type: "button",
795
867
  onClick,
796
- className: "w-full text-xs text-[#475569] hover:text-white/70 transition-colors py-1",
868
+ className: "w-full text-xs transition-colors py-1 hover:opacity-80",
869
+ style: { color: mutedColor ?? "#475569" },
797
870
  children
798
871
  }
799
872
  );
@@ -837,10 +910,10 @@ function GitHubButton({ onClick }) {
837
910
  function XButton({ onClick }) {
838
911
  return /* @__PURE__ */ jsx2(OAuthButton, { icon: /* @__PURE__ */ jsx2(XIcon, {}), label: "Continue with X", onClick });
839
912
  }
840
- function Divider() {
913
+ function Divider({ mutedColor }) {
841
914
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
842
915
  /* @__PURE__ */ jsx2("div", { className: "flex-1 h-px bg-white/8" }),
843
- /* @__PURE__ */ jsx2("span", { className: "text-[10px] text-[#475569] uppercase tracking-wider", children: "or" }),
916
+ /* @__PURE__ */ jsx2("span", { className: "text-[10px] uppercase tracking-wider", style: { color: mutedColor ?? "#475569" }, children: "or" }),
844
917
  /* @__PURE__ */ jsx2("div", { className: "flex-1 h-px bg-white/8" })
845
918
  ] });
846
919
  }
@@ -910,8 +983,8 @@ function GitHubIcon() {
910
983
  function XIcon() {
911
984
  return /* @__PURE__ */ jsx2("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "white", children: /* @__PURE__ */ jsx2("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.744l7.737-8.835L1.254 2.25H8.08l4.253 5.622 5.911-5.622zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) });
912
985
  }
913
- function EnvelopeIcon() {
914
- return /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "#a78bfa", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
986
+ function EnvelopeIcon({ color = "#a78bfa" }) {
987
+ return /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
915
988
  /* @__PURE__ */ jsx2("rect", { x: "2", y: "4", width: "20", height: "16", rx: "2" }),
916
989
  /* @__PURE__ */ jsx2("path", { d: "m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" })
917
990
  ] });
@@ -919,7 +992,7 @@ function EnvelopeIcon() {
919
992
 
920
993
  // src/components/SignUp.tsx
921
994
  import { clsx as clsx2 } from "clsx";
922
- import { useState as useState3 } from "react";
995
+ import { useState as useState4 } from "react";
923
996
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
924
997
  function resolveApiOrigin3(prop) {
925
998
  if (prop) return prop;
@@ -929,6 +1002,13 @@ function resolveApiOrigin3(prop) {
929
1002
  }
930
1003
  return "";
931
1004
  }
1005
+ function resolvePk2() {
1006
+ if (typeof document !== "undefined") {
1007
+ const el = document.querySelector("[data-vaultix-pk]");
1008
+ if (el) return el.getAttribute("data-vaultix-pk") ?? "";
1009
+ }
1010
+ return "";
1011
+ }
932
1012
  function resolveAfterSignUpUrl(redirectUrlProp) {
933
1013
  if (redirectUrlProp) return redirectUrlProp;
934
1014
  if (typeof document !== "undefined") {
@@ -946,16 +1026,22 @@ function SignUp({
946
1026
  onSuccess,
947
1027
  onError,
948
1028
  apiOrigin: apiOriginProp,
949
- className
1029
+ className,
1030
+ appearance
950
1031
  }) {
951
1032
  const apiOrigin = resolveApiOrigin3(apiOriginProp);
952
- const [step, setStep] = useState3("email");
953
- const [email, setEmail] = useState3("");
954
- const [password, setPassword] = useState3("");
955
- const [verificationCode, setVerificationCode] = useState3("");
956
- const [error, setError] = useState3(null);
957
- const [loading, setLoading] = useState3(false);
958
- const [registrationId, setRegistrationId] = useState3(null);
1033
+ const vars = appearance?.variables ?? {};
1034
+ const primaryColor = vars.colorPrimary;
1035
+ const cardBg = vars.colorBackground ?? "rgba(22,27,45,0.92)";
1036
+ const textColor = vars.colorText ?? "rgba(255,255,255,0.9)";
1037
+ const mutedColor = vars.colorTextMuted ?? "#475569";
1038
+ const [step, setStep] = useState4("email");
1039
+ const [email, setEmail] = useState4("");
1040
+ const [password, setPassword] = useState4("");
1041
+ const [verificationCode, setVerificationCode] = useState4("");
1042
+ const [error, setError] = useState4(null);
1043
+ const [loading, setLoading] = useState4(false);
1044
+ const [registrationId, setRegistrationId] = useState4(null);
959
1045
  function setErr(msg) {
960
1046
  setError(msg);
961
1047
  onError?.(msg);
@@ -967,10 +1053,12 @@ function SignUp({
967
1053
  url.searchParams.set("__vaultix_handshake", handshakeToken);
968
1054
  window.location.href = url.toString();
969
1055
  }
970
- function handleGoogleSignUp() {
1056
+ function oauthRedirect(provider) {
971
1057
  const target = resolveAfterSignUpUrl(redirectUrl);
1058
+ const pk = resolvePk2();
972
1059
  const params = new URLSearchParams({ redirect_url: target });
973
- window.location.href = `${apiOrigin}/api/v1/auth/oauth/google?${params}`;
1060
+ if (pk) params.set("pk", pk);
1061
+ window.location.href = `${apiOrigin}/api/v1/auth/oauth/${provider}?${params}`;
974
1062
  }
975
1063
  async function handleEmailPassword(e) {
976
1064
  e.preventDefault();
@@ -1041,48 +1129,61 @@ function SignUp({
1041
1129
  "w-full max-w-sm mx-auto rounded-2xl border border-white/8 shadow-2xl backdrop-blur-[16px]",
1042
1130
  className
1043
1131
  ),
1044
- style: { background: "rgba(22,27,45,0.92)" },
1132
+ style: { background: cardBg },
1045
1133
  children: [
1046
1134
  /* @__PURE__ */ jsxs2("div", { className: "px-8 pt-8 pb-6 text-center", children: [
1047
- /* @__PURE__ */ jsx3("div", { className: "inline-flex items-center justify-center w-10 h-10 rounded-xl bg-gradient-to-br from-emerald-600 to-teal-600 shadow-lg shadow-emerald-500/30 mb-4", children: /* @__PURE__ */ jsx3(SparkleIcon, {}) }),
1048
- /* @__PURE__ */ jsx3("h1", { className: "text-xl font-semibold text-white/90", children: step === "verify" ? "Check your email" : "Create an account" }),
1049
- /* @__PURE__ */ jsx3("p", { className: "text-sm text-[#475569] mt-1", children: step === "verify" ? `We sent a code to ${email}` : "Start your free trial today" })
1135
+ /* @__PURE__ */ jsx3(
1136
+ "div",
1137
+ {
1138
+ className: "inline-flex items-center justify-center w-10 h-10 rounded-xl shadow-lg mb-4",
1139
+ style: primaryColor ? { background: primaryColor, boxShadow: `0 10px 15px -3px ${primaryColor}4d` } : { background: "linear-gradient(to bottom right, #059669, #0d9488)", boxShadow: "0 10px 15px -3px rgba(5,150,105,0.3)" },
1140
+ children: /* @__PURE__ */ jsx3(SparkleIcon, {})
1141
+ }
1142
+ ),
1143
+ /* @__PURE__ */ jsx3("h1", { className: "text-xl font-semibold", style: { color: textColor }, children: step === "verify" ? "Check your email" : "Create an account" }),
1144
+ /* @__PURE__ */ jsx3("p", { className: "text-sm mt-1", style: { color: mutedColor }, children: step === "verify" ? `We sent a code to ${email}` : "Start your free trial today" })
1050
1145
  ] }),
1051
1146
  /* @__PURE__ */ jsxs2("div", { className: "px-8 pb-8 space-y-4", children: [
1052
1147
  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 }) }),
1053
1148
  step === "email" && /* @__PURE__ */ jsxs2("div", { className: "space-y-3", children: [
1054
- /* @__PURE__ */ jsx3(GoogleButton2, { onClick: handleGoogleSignUp }),
1055
- /* @__PURE__ */ jsx3(Divider2, {}),
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 }),
1056
1155
  /* @__PURE__ */ jsxs2("form", { onSubmit: handleEmailPassword, className: "space-y-3", children: [
1057
1156
  /* @__PURE__ */ jsx3(
1058
- SignUpInput,
1157
+ Input2,
1059
1158
  {
1060
1159
  type: "email",
1061
1160
  placeholder: "you@company.com",
1062
1161
  value: email,
1063
1162
  onChange: setEmail,
1064
1163
  autoFocus: true,
1065
- required: true
1164
+ required: true,
1165
+ primaryColor
1066
1166
  }
1067
1167
  ),
1068
1168
  /* @__PURE__ */ jsx3(
1069
- SignUpInput,
1169
+ Input2,
1070
1170
  {
1071
1171
  type: "password",
1072
1172
  placeholder: "Create a password",
1073
1173
  value: password,
1074
1174
  onChange: setPassword,
1075
1175
  required: true,
1076
- minLength: 8
1176
+ minLength: 8,
1177
+ primaryColor
1077
1178
  }
1078
1179
  ),
1079
- /* @__PURE__ */ jsx3(PasswordStrength2, { password }),
1080
- /* @__PURE__ */ jsx3(SignUpPrimaryButton, { loading, children: "Create account" })
1180
+ /* @__PURE__ */ jsx3(PasswordStrength2, { password, primaryColor }),
1181
+ /* @__PURE__ */ jsx3(PrimaryButton2, { loading, primaryColor, children: "Create account" })
1081
1182
  ] })
1082
1183
  ] }),
1083
1184
  step === "verify" && /* @__PURE__ */ jsxs2("form", { onSubmit: handleVerification, className: "space-y-3", children: [
1084
1185
  /* @__PURE__ */ jsx3(
1085
- SignUpInput,
1186
+ Input2,
1086
1187
  {
1087
1188
  type: "text",
1088
1189
  inputMode: "numeric",
@@ -1093,16 +1194,18 @@ function SignUp({
1093
1194
  onChange: setVerificationCode,
1094
1195
  autoFocus: true,
1095
1196
  required: true,
1096
- className: "text-center tracking-[0.4em] text-lg"
1197
+ className: "text-center tracking-[0.4em] text-lg",
1198
+ primaryColor
1097
1199
  }
1098
1200
  ),
1099
- /* @__PURE__ */ jsx3(SignUpPrimaryButton, { loading, children: "Verify email" }),
1201
+ /* @__PURE__ */ jsx3(PrimaryButton2, { loading, primaryColor, children: "Verify email" }),
1100
1202
  /* @__PURE__ */ jsx3(
1101
1203
  "button",
1102
1204
  {
1103
1205
  type: "button",
1104
1206
  onClick: resendCode,
1105
- className: "w-full text-xs text-[#475569] hover:text-white/70 transition-colors py-1",
1207
+ className: "w-full text-xs transition-colors py-1 hover:opacity-80",
1208
+ style: { color: mutedColor },
1106
1209
  children: "Resend code"
1107
1210
  }
1108
1211
  )
@@ -1112,7 +1215,7 @@ function SignUp({
1112
1215
  }
1113
1216
  );
1114
1217
  }
1115
- function SignUpInput({ onChange, className, ...props }) {
1218
+ function Input2({ onChange, className, primaryColor, ...props }) {
1116
1219
  return /* @__PURE__ */ jsx3(
1117
1220
  "input",
1118
1221
  {
@@ -1121,34 +1224,47 @@ function SignUpInput({ onChange, className, ...props }) {
1121
1224
  className: clsx2(
1122
1225
  "w-full bg-white/5 border border-white/8 rounded-xl px-4 py-2.5",
1123
1226
  "text-sm text-white/90 placeholder:text-[#475569]",
1124
- "focus:outline-none focus:border-emerald-500/60 transition-colors",
1227
+ "focus:outline-none transition-colors",
1228
+ !primaryColor && "focus:border-emerald-500/60",
1125
1229
  className
1126
- )
1230
+ ),
1231
+ onFocus: (e) => {
1232
+ if (primaryColor) e.currentTarget.style.borderColor = `${primaryColor}99`;
1233
+ props.onFocus?.(e);
1234
+ },
1235
+ onBlur: (e) => {
1236
+ if (primaryColor) e.currentTarget.style.borderColor = "";
1237
+ props.onBlur?.(e);
1238
+ }
1127
1239
  }
1128
1240
  );
1129
1241
  }
1130
- function SignUpPrimaryButton({
1242
+ function PrimaryButton2({
1131
1243
  children,
1132
- loading
1244
+ loading,
1245
+ primaryColor
1133
1246
  }) {
1134
1247
  return /* @__PURE__ */ jsx3(
1135
1248
  "button",
1136
1249
  {
1137
1250
  type: "submit",
1138
1251
  disabled: loading,
1252
+ style: primaryColor ? { background: primaryColor, boxShadow: `0 10px 15px -3px ${primaryColor}33` } : void 0,
1139
1253
  className: clsx2(
1140
1254
  "w-full flex items-center justify-center gap-2 px-4 py-2.5 rounded-xl",
1141
- "text-sm font-semibold text-white",
1142
- "bg-gradient-to-r from-emerald-600 to-teal-600",
1143
- "hover:from-emerald-500 hover:to-teal-500",
1144
- "shadow-lg shadow-emerald-500/20 transition-all duration-150",
1145
- "disabled:opacity-60 disabled:cursor-not-allowed"
1255
+ "text-sm font-semibold text-white transition-all duration-150",
1256
+ "disabled:opacity-60 disabled:cursor-not-allowed",
1257
+ !primaryColor && "bg-gradient-to-r from-emerald-600 to-teal-600 hover:from-emerald-500 hover:to-teal-500 shadow-lg shadow-emerald-500/20"
1146
1258
  ),
1147
1259
  children: loading ? /* @__PURE__ */ jsx3(Spinner2, {}) : children
1148
1260
  }
1149
1261
  );
1150
1262
  }
1151
- function GoogleButton2({ onClick }) {
1263
+ function OAuthButton2({
1264
+ icon,
1265
+ label,
1266
+ onClick
1267
+ }) {
1152
1268
  return /* @__PURE__ */ jsxs2(
1153
1269
  "button",
1154
1270
  {
@@ -1162,20 +1278,20 @@ function GoogleButton2({ onClick }) {
1162
1278
  "transition-all duration-150"
1163
1279
  ),
1164
1280
  children: [
1165
- /* @__PURE__ */ jsx3(GoogleIcon2, {}),
1166
- "Continue with Google"
1281
+ icon,
1282
+ label
1167
1283
  ]
1168
1284
  }
1169
1285
  );
1170
1286
  }
1171
- function Divider2() {
1287
+ function Divider2({ mutedColor }) {
1172
1288
  return /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-3", children: [
1173
1289
  /* @__PURE__ */ jsx3("div", { className: "flex-1 h-px bg-white/8" }),
1174
- /* @__PURE__ */ jsx3("span", { className: "text-[10px] text-[#475569] uppercase tracking-wider", children: "or" }),
1290
+ /* @__PURE__ */ jsx3("span", { className: "text-[10px] uppercase tracking-wider", style: { color: mutedColor ?? "#475569" }, children: "or" }),
1175
1291
  /* @__PURE__ */ jsx3("div", { className: "flex-1 h-px bg-white/8" })
1176
1292
  ] });
1177
1293
  }
1178
- function PasswordStrength2({ password }) {
1294
+ function PasswordStrength2({ password, primaryColor }) {
1179
1295
  const score = (() => {
1180
1296
  if (password.length === 0) return 0;
1181
1297
  let s = 0;
@@ -1187,15 +1303,17 @@ function PasswordStrength2({ password }) {
1187
1303
  })();
1188
1304
  if (password.length === 0) return null;
1189
1305
  const labels = ["", "Weak", "Fair", "Good", "Strong"];
1190
- const colors = ["", "bg-red-500", "bg-amber-400", "bg-blue-400", "bg-emerald-400"];
1306
+ const tailwindColors = ["", "bg-red-500", "bg-amber-400", "bg-blue-400", "bg-emerald-400"];
1191
1307
  return /* @__PURE__ */ jsxs2("div", { className: "space-y-1", children: [
1192
1308
  /* @__PURE__ */ jsx3("div", { className: "flex gap-1", children: [1, 2, 3, 4].map((i) => /* @__PURE__ */ jsx3(
1193
1309
  "div",
1194
1310
  {
1195
1311
  className: clsx2(
1196
1312
  "flex-1 h-0.5 rounded-full transition-all duration-300",
1197
- i <= score ? colors[score] : "bg-white/10"
1198
- )
1313
+ i <= score && !primaryColor ? tailwindColors[score] : void 0,
1314
+ i > score || !primaryColor && i <= score ? void 0 : void 0
1315
+ ),
1316
+ style: i <= score && primaryColor ? { background: score >= 4 ? primaryColor : void 0 } : { background: i <= score ? void 0 : "rgba(255,255,255,0.1)" }
1199
1317
  },
1200
1318
  i
1201
1319
  )) }),
@@ -1219,6 +1337,18 @@ function GoogleIcon2() {
1219
1337
  /* @__PURE__ */ jsx3("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z", fill: "#EA4335" })
1220
1338
  ] });
1221
1339
  }
1340
+ function MetaIcon2() {
1341
+ return /* @__PURE__ */ jsx3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "#1877F2", children: /* @__PURE__ */ jsx3("path", { d: "M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" }) });
1342
+ }
1343
+ function LinkedInIcon2() {
1344
+ return /* @__PURE__ */ jsx3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "#0A66C2", children: /* @__PURE__ */ jsx3("path", { d: "M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.063 2.063 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" }) });
1345
+ }
1346
+ function GitHubIcon2() {
1347
+ return /* @__PURE__ */ jsx3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "white", children: /* @__PURE__ */ jsx3("path", { d: "M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0 1 12 6.844a9.59 9.59 0 0 1 2.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0 0 22 12.017C22 6.484 17.522 2 12 2z" }) });
1348
+ }
1349
+ function XIcon2() {
1350
+ return /* @__PURE__ */ jsx3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "white", children: /* @__PURE__ */ jsx3("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.744l7.737-8.835L1.254 2.25H8.08l4.253 5.622 5.911-5.622zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) });
1351
+ }
1222
1352
 
1223
1353
  // src/components/SignedIn.tsx
1224
1354
  import { Fragment, jsx as jsx4 } from "react/jsx-runtime";
@@ -1234,10 +1364,10 @@ function SignedOut({ children }) {
1234
1364
  }
1235
1365
 
1236
1366
  // src/components/RedirectComponents.tsx
1237
- import { useEffect as useEffect2 } from "react";
1367
+ import { useEffect as useEffect3 } from "react";
1238
1368
  function RedirectToSignIn({ redirectUrl = "/sign-in" }) {
1239
1369
  const { isLoaded, isSignedIn } = useVaultixContext();
1240
- useEffect2(() => {
1370
+ useEffect3(() => {
1241
1371
  if (isLoaded && !isSignedIn) {
1242
1372
  window.location.href = redirectUrl;
1243
1373
  }
@@ -1246,7 +1376,7 @@ function RedirectToSignIn({ redirectUrl = "/sign-in" }) {
1246
1376
  }
1247
1377
  function RedirectToSignUp({ redirectUrl = "/sign-up" }) {
1248
1378
  const { isLoaded, isSignedIn } = useVaultixContext();
1249
- useEffect2(() => {
1379
+ useEffect3(() => {
1250
1380
  if (isLoaded && !isSignedIn) {
1251
1381
  window.location.href = redirectUrl;
1252
1382
  }
@@ -1256,15 +1386,15 @@ function RedirectToSignUp({ redirectUrl = "/sign-up" }) {
1256
1386
 
1257
1387
  // src/components/UserButton.tsx
1258
1388
  import { clsx as clsx3 } from "clsx";
1259
- import { useCallback as useCallback3, useEffect as useEffect3, useRef as useRef3, useState as useState4 } from "react";
1389
+ import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef3, useState as useState5 } from "react";
1260
1390
  import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1261
1391
  function UserButton({ showName = false, afterSignOutUrl, className }) {
1262
1392
  const { user, session, isLoaded, isSignedIn, signOut } = useVaultixContext();
1263
- const [open, setOpen] = useState4(false);
1264
- const [signingOut, setSigningOut] = useState4(false);
1265
- const [showProfile, setShowProfile] = useState4(false);
1393
+ const [open, setOpen] = useState5(false);
1394
+ const [signingOut, setSigningOut] = useState5(false);
1395
+ const [showProfile, setShowProfile] = useState5(false);
1266
1396
  const containerRef = useRef3(null);
1267
- useEffect3(() => {
1397
+ useEffect4(() => {
1268
1398
  function onPointerDown(e) {
1269
1399
  if (containerRef.current && !containerRef.current.contains(e.target)) setOpen(false);
1270
1400
  }
@@ -1326,17 +1456,17 @@ function UserButton({ showName = false, afterSignOutUrl, className }) {
1326
1456
  }
1327
1457
  function ProfileModal({ onClose }) {
1328
1458
  const { user, updateUser } = useVaultixContext();
1329
- const [tab, setTab] = useState4("profile");
1330
- const [firstName, setFirstName] = useState4(user?.firstName ?? "");
1331
- const [lastName, setLastName] = useState4(user?.lastName ?? "");
1332
- const [imageUrl, setImageUrl] = useState4(user?.imageUrl ?? "");
1333
- const [currentPassword, setCurrentPassword] = useState4("");
1334
- const [newPassword, setNewPassword] = useState4("");
1335
- const [confirmPassword, setConfirmPassword] = useState4("");
1336
- const [saving, setSaving] = useState4(false);
1337
- const [error, setError] = useState4(null);
1338
- const [success, setSuccess] = useState4(null);
1339
- useEffect3(() => {
1459
+ const [tab, setTab] = useState5("profile");
1460
+ const [firstName, setFirstName] = useState5(user?.firstName ?? "");
1461
+ const [lastName, setLastName] = useState5(user?.lastName ?? "");
1462
+ const [imageUrl, setImageUrl] = useState5(user?.imageUrl ?? "");
1463
+ const [currentPassword, setCurrentPassword] = useState5("");
1464
+ const [newPassword, setNewPassword] = useState5("");
1465
+ const [confirmPassword, setConfirmPassword] = useState5("");
1466
+ const [saving, setSaving] = useState5(false);
1467
+ const [error, setError] = useState5(null);
1468
+ const [success, setSuccess] = useState5(null);
1469
+ useEffect4(() => {
1340
1470
  function onKey(e) {
1341
1471
  if (e.key === "Escape") onClose();
1342
1472
  }
@@ -1447,17 +1577,17 @@ function ProfileModal({ onClose }) {
1447
1577
  }
1448
1578
  function SecurityTab() {
1449
1579
  const { apiOrigin } = useVaultixContext();
1450
- const [totpEnabled, setTotpEnabled] = useState4(null);
1451
- const [backupCodesLeft, setBackupCodesLeft] = useState4(null);
1452
- const [enrollStep, setEnrollStep] = useState4("idle");
1453
- const [qrDataUrl, setQrDataUrl] = useState4("");
1454
- const [manualKey, setManualKey] = useState4("");
1455
- const [enrollCode, setEnrollCode] = useState4("");
1456
- const [disableCode, setDisableCode] = useState4("");
1457
- const [backupCodes, setBackupCodes] = useState4([]);
1458
- const [loading, setLoading] = useState4(false);
1459
- const [error, setError] = useState4(null);
1460
- const [showDisable, setShowDisable] = useState4(false);
1580
+ const [totpEnabled, setTotpEnabled] = useState5(null);
1581
+ const [backupCodesLeft, setBackupCodesLeft] = useState5(null);
1582
+ const [enrollStep, setEnrollStep] = useState5("idle");
1583
+ const [qrDataUrl, setQrDataUrl] = useState5("");
1584
+ const [manualKey, setManualKey] = useState5("");
1585
+ const [enrollCode, setEnrollCode] = useState5("");
1586
+ const [disableCode, setDisableCode] = useState5("");
1587
+ const [backupCodes, setBackupCodes] = useState5([]);
1588
+ const [loading, setLoading] = useState5(false);
1589
+ const [error, setError] = useState5(null);
1590
+ const [showDisable, setShowDisable] = useState5(false);
1461
1591
  const fetchStatus = useCallback3(async () => {
1462
1592
  const res = await fetch(`${apiOrigin}/api/v1/auth/totp/status`, { credentials: "include" });
1463
1593
  if (res.ok) {
@@ -1466,7 +1596,7 @@ function SecurityTab() {
1466
1596
  setBackupCodesLeft(d.backup_codes_remaining);
1467
1597
  }
1468
1598
  }, [apiOrigin]);
1469
- useEffect3(() => {
1599
+ useEffect4(() => {
1470
1600
  void fetchStatus();
1471
1601
  }, [fetchStatus]);
1472
1602
  async function startEnroll() {
@@ -1782,7 +1912,7 @@ function CloseIcon() {
1782
1912
 
1783
1913
  // src/components/OrganizationSwitcher.tsx
1784
1914
  import { clsx as clsx4 } from "clsx";
1785
- import { useEffect as useEffect4, useRef as useRef4, useState as useState5 } from "react";
1915
+ import { useEffect as useEffect5, useRef as useRef4, useState as useState6 } from "react";
1786
1916
  import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1787
1917
  function resolveApiOrigin4() {
1788
1918
  if (typeof document !== "undefined") {
@@ -1796,11 +1926,11 @@ function OrganizationSwitcher({
1796
1926
  className
1797
1927
  }) {
1798
1928
  const { organization, isLoaded, isSignedIn } = useVaultixContext();
1799
- const [open, setOpen] = useState5(false);
1800
- const [orgs, setOrgs] = useState5([]);
1801
- const [switching, setSwitching] = useState5(null);
1929
+ const [open, setOpen] = useState6(false);
1930
+ const [orgs, setOrgs] = useState6([]);
1931
+ const [switching, setSwitching] = useState6(null);
1802
1932
  const containerRef = useRef4(null);
1803
- useEffect4(() => {
1933
+ useEffect5(() => {
1804
1934
  function onPointerDown(e) {
1805
1935
  if (containerRef.current && !containerRef.current.contains(e.target)) {
1806
1936
  setOpen(false);
@@ -1809,7 +1939,7 @@ function OrganizationSwitcher({
1809
1939
  document.addEventListener("pointerdown", onPointerDown);
1810
1940
  return () => document.removeEventListener("pointerdown", onPointerDown);
1811
1941
  }, []);
1812
- useEffect4(() => {
1942
+ useEffect5(() => {
1813
1943
  if (!open) return;
1814
1944
  const api = resolveApiOrigin4();
1815
1945
  fetch(`${api}/v1/me/organizations`, { credentials: "include" }).then((r) => r.json()).then(
@@ -2004,6 +2134,7 @@ export {
2004
2134
  getStoredToken,
2005
2135
  useAuth,
2006
2136
  useOrganization,
2137
+ usePlatformConnect,
2007
2138
  useSession,
2008
2139
  useUser,
2009
2140
  useVaultix