@embarkai/ui-kit 0.4.82 → 0.4.84

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.js CHANGED
@@ -7158,13 +7158,13 @@ var init_useAuthStore = __esm({
7158
7158
  step: "signin",
7159
7159
  alert: null,
7160
7160
  email: "",
7161
- expiresIn: null,
7161
+ emailChallenge: null,
7162
7162
  codeSendError: null,
7163
7163
  passkeyStatus: "idle",
7164
7164
  failedType: "general",
7165
7165
  setStep: (step) => set({ step }),
7166
7166
  setEmail: (email) => set({ email }),
7167
- setExpiresIn: (expiresIn) => set({ expiresIn }),
7167
+ setEmailChallenge: (emailChallenge) => set({ emailChallenge }),
7168
7168
  setPasskeyStatus: (status) => set({ passkeyStatus: status }),
7169
7169
  setAlert: (alert2) => set({ alert: alert2 }),
7170
7170
  setFailedType: (type) => set({ failedType: type })
@@ -7722,6 +7722,23 @@ var init_input = __esm({
7722
7722
  }
7723
7723
  });
7724
7724
 
7725
+ // src/internal/components/AuthMenu/emailChallenge.ts
7726
+ var normalizeChallengeEmail, createEmailChallenge, isEmailChallengeActive, shouldDiscardEmailChallengeForError;
7727
+ var init_emailChallenge = __esm({
7728
+ "src/internal/components/AuthMenu/emailChallenge.ts"() {
7729
+ normalizeChallengeEmail = (email) => email.trim().toLowerCase();
7730
+ createEmailChallenge = (email, expiresIn, now = Date.now()) => ({
7731
+ email: normalizeChallengeEmail(email),
7732
+ expiresAt: now + Math.max(0, expiresIn) * 1e3
7733
+ });
7734
+ isEmailChallengeActive = (challenge, email, now = Date.now()) => challenge !== null && challenge.email === normalizeChallengeEmail(email) && challenge.expiresAt > now;
7735
+ shouldDiscardEmailChallengeForError = (message) => {
7736
+ const normalizedMessage = message.toLowerCase();
7737
+ return normalizedMessage.includes("expired") || normalizedMessage.includes("429") || normalizedMessage.includes("too many") || normalizedMessage.includes("code_not_found") || normalizedMessage.includes("no verification code");
7738
+ };
7739
+ }
7740
+ });
7741
+
7725
7742
  // src/internal/components/AuthMenu/SignInStep/Email.tsx
7726
7743
  import { useMutation as useMutation3 } from "@tanstack/react-query";
7727
7744
  import { ChevronRight, Loader as Loader2, Mail as Mail2 } from "lucide-react";
@@ -7736,7 +7753,7 @@ function Email() {
7736
7753
  const isLoading = useSession((st) => st.isLoading);
7737
7754
  const setIsLoading = useSession((st) => st.setIsLoading);
7738
7755
  const isMobileView = useLayoutStore((st) => st.isMobileView);
7739
- const { email, alert: alert2, setEmail, setExpiresIn, setStep, setAlert } = useAuthStore();
7756
+ const { email, emailChallenge, alert: alert2, setEmail, setEmailChallenge, setStep, setAlert } = useAuthStore();
7740
7757
  const { mutate: onSendVerificationCode } = useMutation3({
7741
7758
  mutationFn: async (mail) => {
7742
7759
  const isEmailValid = mail.length !== 0 && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(mail);
@@ -7753,10 +7770,10 @@ function Email() {
7753
7770
  body: JSON.stringify({ email: mail, purpose: "login" })
7754
7771
  });
7755
7772
  },
7756
- onSuccess: async (response) => {
7773
+ onSuccess: async (response, requestedEmail) => {
7757
7774
  const data = await response.json();
7758
7775
  if (response.ok) {
7759
- setExpiresIn(data.expiresIn || 300);
7776
+ setEmailChallenge(createEmailChallenge(requestedEmail, data.expiresIn ?? 600));
7760
7777
  setStep("verify");
7761
7778
  } else {
7762
7779
  if (response.status === 429) {
@@ -7788,6 +7805,14 @@ function Email() {
7788
7805
  setIsLoading(false);
7789
7806
  }
7790
7807
  });
7808
+ const continueWithEmail = () => {
7809
+ if (isEmailChallengeActive(emailChallenge, email)) {
7810
+ setAlert(null);
7811
+ setStep("verify");
7812
+ return;
7813
+ }
7814
+ onSendVerificationCode(email);
7815
+ };
7791
7816
  useEffect9(() => {
7792
7817
  if (!focusRef.current || !isMobileView) return;
7793
7818
  focusRef.current?.focus();
@@ -7841,7 +7866,7 @@ function Email() {
7841
7866
  variant: "default",
7842
7867
  size: "large",
7843
7868
  disabled: !email || isLoading,
7844
- onClick: () => onSendVerificationCode(email),
7869
+ onClick: continueWithEmail,
7845
7870
  children: isLoading ? /* @__PURE__ */ jsx14(Loader2, { className: "w-4 h-4 animate-spin" }) : /* @__PURE__ */ jsx14(ChevronRight, { className: "w-4 h-4" })
7846
7871
  }
7847
7872
  )
@@ -7860,6 +7885,7 @@ var init_Email = __esm({
7860
7885
  init_projectId();
7861
7886
  init_button();
7862
7887
  init_input();
7888
+ init_emailChallenge();
7863
7889
  init_useAuthStore();
7864
7890
  }
7865
7891
  });
@@ -8695,16 +8721,10 @@ var init_VerificationCodeInput = __esm({
8695
8721
  init_useAuthStore();
8696
8722
  getRemainingSeconds = (expiresAt) => Math.max(0, Math.ceil((expiresAt - Date.now()) / 1e3));
8697
8723
  VerificationCodeInput = (props) => {
8698
- const { onVerifyCode, onResendCode, isLoading, expiresIn } = props;
8724
+ const { onVerifyCode, onResendCode, isLoading, expiresAt } = props;
8699
8725
  const { t } = useT();
8700
8726
  const setAlert = useAuthStore((st) => st.setAlert);
8701
- const [expiresAt, setExpiresAt] = useState3(() => Date.now() + Math.max(0, expiresIn) * 1e3);
8702
8727
  const [timeLeft, setTimeLeft] = useState3(() => getRemainingSeconds(expiresAt));
8703
- useEffect10(() => {
8704
- const nextExpiresAt = Date.now() + Math.max(0, expiresIn) * 1e3;
8705
- setExpiresAt(nextExpiresAt);
8706
- setTimeLeft(getRemainingSeconds(nextExpiresAt));
8707
- }, [expiresIn]);
8708
8728
  useEffect10(() => {
8709
8729
  let intervalId;
8710
8730
  const syncTimeLeft = () => {
@@ -8794,7 +8814,9 @@ var init_VerificationCodeInput = __esm({
8794
8814
  "input",
8795
8815
  {
8796
8816
  name: `verification-code-symbol-${i}`,
8797
- ref: (el) => inputsRef.current[i] = el,
8817
+ ref: (el) => {
8818
+ inputsRef.current[i] = el;
8819
+ },
8798
8820
  type: "text",
8799
8821
  autoComplete: "off",
8800
8822
  disabled: isLoading,
@@ -8856,11 +8878,11 @@ function VerifyStep(props) {
8856
8878
  const setIsLoading = useSession((st) => st.setIsLoading);
8857
8879
  const {
8858
8880
  email,
8859
- expiresIn,
8881
+ emailChallenge,
8860
8882
  setFailedType,
8861
8883
  setStep,
8862
8884
  setEmail,
8863
- setExpiresIn,
8885
+ setEmailChallenge,
8864
8886
  setAlert
8865
8887
  } = useAuthStore();
8866
8888
  const [resendCount, setResendCount] = useState4(0);
@@ -8901,6 +8923,7 @@ function VerifyStep(props) {
8901
8923
  const needsRecovery = loginResponse.hasKeyshare && !loginResponse.isNewUser && !localKeyshare;
8902
8924
  if (!recoveryUserId && !needsRecovery) {
8903
8925
  setEmail("");
8926
+ setEmailChallenge(null);
8904
8927
  setAlert(null);
8905
8928
  }
8906
8929
  await onAuthSuccess?.();
@@ -8912,11 +8935,13 @@ function VerifyStep(props) {
8912
8935
  let errorMessage = "";
8913
8936
  const rawErrorMessage = error.message || "";
8914
8937
  const normalizedErrorMessage = rawErrorMessage.toLowerCase();
8938
+ if (shouldDiscardEmailChallengeForError(rawErrorMessage)) {
8939
+ setEmailChallenge(null);
8940
+ }
8915
8941
  if (normalizedErrorMessage.includes("invalid")) {
8916
8942
  errorMessage = "Invalid verification code. Please try again.";
8917
8943
  } else if (normalizedErrorMessage.includes("expired")) {
8918
8944
  errorMessage = "Verification code expired. Please request a new one.";
8919
- setExpiresIn(0);
8920
8945
  } else if (normalizedErrorMessage.includes("429") || normalizedErrorMessage.includes("too many")) {
8921
8946
  errorMessage = "Too many attempts. Please try again later.";
8922
8947
  } else {
@@ -8948,7 +8973,7 @@ function VerifyStep(props) {
8948
8973
  onSuccess: async (response) => {
8949
8974
  const data = await response.json();
8950
8975
  if (response.ok) {
8951
- setExpiresIn(data.expiresIn || 300);
8976
+ setEmailChallenge(createEmailChallenge(email, data.expiresIn ?? 600));
8952
8977
  setResendCount((c) => c + 1);
8953
8978
  }
8954
8979
  if (!response.ok && response.status === 429) {
@@ -9006,7 +9031,7 @@ function VerifyStep(props) {
9006
9031
  onVerifyCode,
9007
9032
  onResendCode,
9008
9033
  isLoading,
9009
- expiresIn
9034
+ expiresAt: emailChallenge?.expiresAt ?? Date.now()
9010
9035
  },
9011
9036
  resendCount
9012
9037
  )
@@ -9021,6 +9046,7 @@ var init_VerifyStep = __esm({
9021
9046
  init_icons();
9022
9047
  init_projectId();
9023
9048
  init_button();
9049
+ init_emailChallenge();
9024
9050
  init_useAuthStore();
9025
9051
  init_VerificationCodeInput();
9026
9052
  }
@@ -9063,7 +9089,7 @@ var init_AuthMenu = __esm({
9063
9089
  const setTransitionPageHeight = useLayoutDataStore((st) => st.setTransitionPageHeight);
9064
9090
  const pendingWalletLogin = useLayoutDataStore((st) => st.pendingWalletLogin);
9065
9091
  const setPendingWalletLogin = useLayoutDataStore((st) => st.setPendingWalletLogin);
9066
- const { step, alert: alert2, setStep, setPasskeyStatus, setEmail, setAlert } = useAuthStore();
9092
+ const { step, alert: alert2, setStep, setPasskeyStatus, setEmail, setEmailChallenge, setAlert } = useAuthStore();
9067
9093
  const { pendingLoginResponseRef, onAuthSuccess, goBackToSignIn } = useAuthMenuHandlers();
9068
9094
  useEffect11(() => {
9069
9095
  if (!pendingWalletLogin) return;
@@ -9080,6 +9106,7 @@ var init_AuthMenu = __esm({
9080
9106
  return () => {
9081
9107
  setStep("signin");
9082
9108
  setEmail("");
9109
+ setEmailChallenge(null);
9083
9110
  setPasskeyStatus("idle");
9084
9111
  setAlert(null);
9085
9112
  };
@@ -13598,6 +13625,41 @@ var init_passkey2 = __esm({
13598
13625
  }
13599
13626
  });
13600
13627
 
13628
+ // src/internal/auth/providers/email.ts
13629
+ async function sendEmailLinkCode(email) {
13630
+ const hasValidToken = await ensureValidToken();
13631
+ if (!hasValidToken) throw new Error("No authentication token available");
13632
+ const response = await authenticatedFetch(`${getTssUrl3()}/api/auth/link/email/send-code`, {
13633
+ method: "POST",
13634
+ body: JSON.stringify({ email })
13635
+ });
13636
+ if (!response.ok) {
13637
+ const errorData = await response.json().catch(() => ({}));
13638
+ throw new Error(errorData.message || `Failed to send email verification code: ${response.statusText}`);
13639
+ }
13640
+ const data = await response.json().catch(() => ({}));
13641
+ return data.expiresIn ?? 600;
13642
+ }
13643
+ async function verifyEmailLinkCode(email, code) {
13644
+ const hasValidToken = await ensureValidToken();
13645
+ if (!hasValidToken) throw new Error("No authentication token available");
13646
+ const response = await authenticatedFetch(`${getTssUrl3()}/api/auth/link/email/verify-code`, {
13647
+ method: "POST",
13648
+ credentials: "include",
13649
+ body: JSON.stringify({ email, code })
13650
+ });
13651
+ if (!response.ok) {
13652
+ const errorData = await response.json().catch(() => ({}));
13653
+ throw new Error(errorData.message || `Failed to verify email and link provider: ${response.statusText}`);
13654
+ }
13655
+ }
13656
+ var init_email = __esm({
13657
+ "src/internal/auth/providers/email.ts"() {
13658
+ init_auth();
13659
+ init_types();
13660
+ }
13661
+ });
13662
+
13601
13663
  // src/internal/components/ManageWalletMenu/hooks/useStore.ts
13602
13664
  import { create as create8 } from "zustand";
13603
13665
  var useManageWalletStore;
@@ -13609,7 +13671,7 @@ var init_useStore = __esm({
13609
13671
  emailStep: "input",
13610
13672
  email: "",
13611
13673
  emailCode: "",
13612
- emailCodeExpiresIn: 0,
13674
+ emailCodeExpiresAt: 0,
13613
13675
  linkIsLoading: false,
13614
13676
  // linkError: null,
13615
13677
  providerType: null,
@@ -13618,7 +13680,7 @@ var init_useStore = __esm({
13618
13680
  setEmailStep: (emailStep) => set({ emailStep }),
13619
13681
  setEmail: (email) => set({ email }),
13620
13682
  setEmailCode: (emailCode) => set({ emailCode }),
13621
- setEmailCodeExpiresIn: (emailCodeExpiresIn) => set({ emailCodeExpiresIn }),
13683
+ setEmailCodeExpiresAt: (emailCodeExpiresAt) => set({ emailCodeExpiresAt }),
13622
13684
  setLinkIsLoading: (linkIsLoading) => {
13623
13685
  useLayoutStore.setState({ isDialogForced: linkIsLoading });
13624
13686
  set({ linkIsLoading });
@@ -13630,74 +13692,47 @@ var init_useStore = __esm({
13630
13692
  }
13631
13693
  });
13632
13694
 
13633
- // src/internal/components/ManageWalletMenu/EmailForm.tsx
13695
+ // src/internal/components/ManageWalletMenu/hooks/useSendVerificationCode.ts
13634
13696
  import { useMutation as useMutation8 } from "@tanstack/react-query";
13697
+ function useSendVerificationCode() {
13698
+ const setAlert = useManageWalletStore((st) => st.setAlert);
13699
+ const setLinkIsLoading = useManageWalletStore((st) => st.setLinkIsLoading);
13700
+ const setEmailCodeExpiresAt = useManageWalletStore((st) => st.setEmailCodeExpiresAt);
13701
+ return useMutation8({
13702
+ mutationFn: async (email) => {
13703
+ if (!email) {
13704
+ throw new Error("Email is required");
13705
+ }
13706
+ setAlert(null);
13707
+ setLinkIsLoading(true);
13708
+ return await sendEmailLinkCode(email);
13709
+ },
13710
+ onError: (error) => {
13711
+ console.error("Failed to send verification code", error.message);
13712
+ setAlert({ title: "Error", message: error?.message || "Failed to send verification code" });
13713
+ setLinkIsLoading(false);
13714
+ },
13715
+ onSuccess: (expiresIn) => {
13716
+ setEmailCodeExpiresAt(Date.now() + expiresIn * 1e3);
13717
+ console.log("Verification code sent");
13718
+ setLinkIsLoading(false);
13719
+ }
13720
+ });
13721
+ }
13722
+ var init_useSendVerificationCode = __esm({
13723
+ "src/internal/components/ManageWalletMenu/hooks/useSendVerificationCode.ts"() {
13724
+ init_email();
13725
+ init_useStore();
13726
+ }
13727
+ });
13728
+
13729
+ // src/internal/components/ManageWalletMenu/EmailForm.tsx
13635
13730
  import { ChevronRight as ChevronRight2, Loader as Loader8, Mail as Mail4 } from "lucide-react";
13636
13731
  import { jsx as jsx61, jsxs as jsxs54 } from "react/jsx-runtime";
13637
13732
  function EmailForm() {
13638
- const { callbacksRef } = useProviderConfig();
13639
13733
  const { t } = useT();
13640
- const isLoading = useSession((st) => st.isLoading);
13641
- const setIsLoading = useSession((st) => st.setIsLoading);
13642
- const { email, setEmail, setAlert, setEmailCodeExpiresIn, setEmailStep } = useManageWalletStore();
13643
- const { mutate: onSendVerificationCode } = useMutation8({
13644
- mutationFn: async () => {
13645
- if (!email) return;
13646
- setIsLoading(true);
13647
- setAlert(null);
13648
- try {
13649
- const response = await fetch(addProjectIdToUrl(`${getServiceUrls().tssUrl}/api/auth/email/send-code`), {
13650
- method: "POST",
13651
- headers: {
13652
- "Content-Type": "application/json"
13653
- },
13654
- credentials: "include",
13655
- body: JSON.stringify({
13656
- email,
13657
- purpose: "login"
13658
- })
13659
- });
13660
- const data = await response.json();
13661
- if (response.ok) {
13662
- setEmailCodeExpiresIn(data?.expiresIn || 300);
13663
- setEmailStep("verify");
13664
- } else {
13665
- if (response.status === 429) {
13666
- const retryAfter = data.retryAfter || 60;
13667
- setAlert({
13668
- title: "Too Many Requests",
13669
- message: `Code already sent recently. Please wait ${retryAfter} seconds before requesting another.`
13670
- });
13671
- } else if (response.status === 400) {
13672
- setAlert({
13673
- title: "Invalid Email",
13674
- message: data.message || "Invalid email address"
13675
- });
13676
- } else {
13677
- setAlert({
13678
- title: "Error",
13679
- message: data.message || "Failed to send verification code"
13680
- });
13681
- }
13682
- }
13683
- } catch (error) {
13684
- const errorMessage = "Network error. Please check your connection.";
13685
- setAlert({
13686
- title: "Network Error",
13687
- message: errorMessage
13688
- });
13689
- try {
13690
- callbacksRef.current?.onError?.({
13691
- error: error instanceof Error ? error : new Error(errorMessage),
13692
- message: errorMessage
13693
- });
13694
- } catch {
13695
- }
13696
- } finally {
13697
- setIsLoading(false);
13698
- }
13699
- }
13700
- });
13734
+ const { email, linkIsLoading, setEmail, setEmailStep } = useManageWalletStore();
13735
+ const { mutate: onSendVerificationCode } = useSendVerificationCode();
13701
13736
  return /* @__PURE__ */ jsxs54("div", { className: "w-full flex gap-[10px] items-center", children: [
13702
13737
  /* @__PURE__ */ jsx61(
13703
13738
  Input,
@@ -13718,22 +13753,19 @@ function EmailForm() {
13718
13753
  className: "w-12 h-12 flex-none",
13719
13754
  variant: "default",
13720
13755
  size: "large",
13721
- disabled: !email || isLoading,
13722
- onClick: () => onSendVerificationCode(),
13723
- children: isLoading ? /* @__PURE__ */ jsx61(Loader8, { className: "w-4 h-4 animate-spin" }) : /* @__PURE__ */ jsx61(ChevronRight2, { className: "w-4 h-4" })
13756
+ disabled: !email || linkIsLoading,
13757
+ onClick: () => onSendVerificationCode(email, { onSuccess: () => setEmailStep("verify") }),
13758
+ children: linkIsLoading ? /* @__PURE__ */ jsx61(Loader8, { className: "w-4 h-4 animate-spin" }) : /* @__PURE__ */ jsx61(ChevronRight2, { className: "w-4 h-4" })
13724
13759
  }
13725
13760
  )
13726
13761
  ] });
13727
13762
  }
13728
13763
  var init_EmailForm = __esm({
13729
13764
  "src/internal/components/ManageWalletMenu/EmailForm.tsx"() {
13730
- init_initial();
13731
- init_ProviderContext();
13732
- init_SessionContext();
13733
13765
  init_i18n();
13734
- init_projectId();
13735
13766
  init_button();
13736
13767
  init_input();
13768
+ init_useSendVerificationCode();
13737
13769
  init_useStore();
13738
13770
  }
13739
13771
  });
@@ -13760,75 +13792,8 @@ var init_useProvidersList = __esm({
13760
13792
  }
13761
13793
  });
13762
13794
 
13763
- // src/internal/auth/providers/email.ts
13764
- async function sendEmailLinkCode(email) {
13765
- const hasValidToken = await ensureValidToken();
13766
- if (!hasValidToken) throw new Error("No authentication token available");
13767
- const response = await authenticatedFetch(`${getTssUrl3()}/api/auth/link/email/send-code`, {
13768
- method: "POST",
13769
- body: JSON.stringify({ email })
13770
- });
13771
- if (!response.ok) {
13772
- const errorData = await response.json().catch(() => ({}));
13773
- throw new Error(errorData.message || `Failed to send email verification code: ${response.statusText}`);
13774
- }
13775
- }
13776
- async function verifyEmailLinkCode(email, code) {
13777
- const hasValidToken = await ensureValidToken();
13778
- if (!hasValidToken) throw new Error("No authentication token available");
13779
- const response = await authenticatedFetch(`${getTssUrl3()}/api/auth/link/email/verify-code`, {
13780
- method: "POST",
13781
- credentials: "include",
13782
- body: JSON.stringify({ email, code })
13783
- });
13784
- if (!response.ok) {
13785
- const errorData = await response.json().catch(() => ({}));
13786
- throw new Error(errorData.message || `Failed to verify email and link provider: ${response.statusText}`);
13787
- }
13788
- }
13789
- var init_email = __esm({
13790
- "src/internal/auth/providers/email.ts"() {
13791
- init_auth();
13792
- init_types();
13793
- }
13794
- });
13795
-
13796
- // src/internal/components/ManageWalletMenu/hooks/useSendVerificationCode.ts
13797
- import { useMutation as useMutation9 } from "@tanstack/react-query";
13798
- function useSendVerificationCode() {
13799
- const setAlert = useManageWalletStore((st) => st.setAlert);
13800
- const setLinkIsLoading = useManageWalletStore((st) => st.setLinkIsLoading);
13801
- const setEmailCodeExpiresIn = useManageWalletStore((st) => st.setEmailCodeExpiresIn);
13802
- return useMutation9({
13803
- mutationFn: async (email) => {
13804
- if (!email) {
13805
- throw new Error("Email is required");
13806
- }
13807
- setAlert(null);
13808
- setLinkIsLoading(true);
13809
- await sendEmailLinkCode(email);
13810
- },
13811
- onError: (error) => {
13812
- console.error("Failed to send verification code", error.message);
13813
- setAlert({ title: "Error", message: error?.message || "Failed to send verification code" });
13814
- setLinkIsLoading(false);
13815
- },
13816
- onSuccess: () => {
13817
- setEmailCodeExpiresIn(300);
13818
- console.log("Verification code sent");
13819
- setLinkIsLoading(false);
13820
- }
13821
- });
13822
- }
13823
- var init_useSendVerificationCode = __esm({
13824
- "src/internal/components/ManageWalletMenu/hooks/useSendVerificationCode.ts"() {
13825
- init_email();
13826
- init_useStore();
13827
- }
13828
- });
13829
-
13830
13795
  // src/internal/components/ManageWalletMenu/hooks/useVerifyCode.ts
13831
- import { useMutation as useMutation10, useQueryClient as useQueryClient9 } from "@tanstack/react-query";
13796
+ import { useMutation as useMutation9, useQueryClient as useQueryClient9 } from "@tanstack/react-query";
13832
13797
  function useVerifyCode() {
13833
13798
  const { callbacksRef } = useProviderConfig();
13834
13799
  const qc = useQueryClient9();
@@ -13840,12 +13805,12 @@ function useVerifyCode() {
13840
13805
  setEmail,
13841
13806
  setEmailStep,
13842
13807
  setEmailCode,
13843
- setEmailCodeExpiresIn,
13808
+ setEmailCodeExpiresAt,
13844
13809
  setProviderType,
13845
13810
  setLinkIsLoading,
13846
13811
  setAlert
13847
13812
  } = useManageWalletStore();
13848
- return useMutation10({
13813
+ return useMutation9({
13849
13814
  mutationFn: async (codeToVerify) => {
13850
13815
  const code = codeToVerify ?? emailCode;
13851
13816
  if (!code) {
@@ -13874,8 +13839,8 @@ function useVerifyCode() {
13874
13839
  },
13875
13840
  onError: (error) => {
13876
13841
  const message = error?.message || "Failed to verify and link email";
13877
- if (message.toLowerCase().includes("expired")) {
13878
- setEmailCodeExpiresIn(0);
13842
+ if (shouldDiscardEmailChallengeForError(message)) {
13843
+ setEmailCodeExpiresAt(0);
13879
13844
  }
13880
13845
  setAlert({ title: "Error", message });
13881
13846
  setIsLoading(false);
@@ -13889,6 +13854,7 @@ var init_useVerifyCode = __esm({
13889
13854
  init_SessionContext();
13890
13855
  init_linkedProfiles();
13891
13856
  init_email();
13857
+ init_emailChallenge();
13892
13858
  init_useProvidersList();
13893
13859
  init_useStore();
13894
13860
  }
@@ -13917,7 +13883,7 @@ function AddProvider() {
13917
13883
  providerType,
13918
13884
  email,
13919
13885
  emailStep,
13920
- emailCodeExpiresIn,
13886
+ emailCodeExpiresAt,
13921
13887
  setAlert,
13922
13888
  setProviderType,
13923
13889
  setLinkIsLoading
@@ -13944,7 +13910,7 @@ function AddProvider() {
13944
13910
  onVerifyCode,
13945
13911
  onResendCode: () => onResendCode(email),
13946
13912
  isLoading,
13947
- expiresIn: emailCodeExpiresIn
13913
+ expiresAt: emailCodeExpiresAt
13948
13914
  }
13949
13915
  )
13950
13916
  ] }),
@@ -14525,7 +14491,7 @@ function ManageWalletMenu() {
14525
14491
  setProviderType,
14526
14492
  setEmail,
14527
14493
  setEmailStep,
14528
- setEmailCodeExpiresIn,
14494
+ setEmailCodeExpiresAt,
14529
14495
  setEmailCode
14530
14496
  } = useManageWalletStore();
14531
14497
  const configuredProviders = getConfiguredProviders(config.current);
@@ -14573,7 +14539,7 @@ function ManageWalletMenu() {
14573
14539
  case "email":
14574
14540
  setEmail("");
14575
14541
  setEmailCode("");
14576
- setEmailCodeExpiresIn(0);
14542
+ setEmailCodeExpiresAt(0);
14577
14543
  setEmailStep("input");
14578
14544
  setProviderType(provider);
14579
14545
  break;
@@ -14636,7 +14602,7 @@ function ManageWalletMenu() {
14636
14602
  setEmail("");
14637
14603
  setEmailCode("");
14638
14604
  setEmailStep("input");
14639
- setEmailCodeExpiresIn(0);
14605
+ setEmailCodeExpiresAt(0);
14640
14606
  }
14641
14607
  if (!providerType) useLayoutDataStore.getState().setPage("settings" /* SETTINGS */);
14642
14608
  setProviderType(null);
@@ -14701,7 +14667,7 @@ var init_ManageWallet = __esm({
14701
14667
  });
14702
14668
 
14703
14669
  // src/internal/components/ManageWalletMenu/UnlinkProviderMenu.tsx
14704
- import { useMutation as useMutation11, useQueryClient as useQueryClient13 } from "@tanstack/react-query";
14670
+ import { useMutation as useMutation10, useQueryClient as useQueryClient13 } from "@tanstack/react-query";
14705
14671
  import { Key as Key4, Loader as Loader10 } from "lucide-react";
14706
14672
  import { useState as useState12 } from "react";
14707
14673
  import { useDisconnect } from "wagmi";
@@ -14716,7 +14682,7 @@ function UnlinkProviderMenu() {
14716
14682
  const setPage = useLayoutDataStore((st) => st.setPage);
14717
14683
  const { confirmUnlink, setConfirmUnlink, setAlert } = useManageWalletStore();
14718
14684
  const [confirmInput, setConfirmInput] = useState12("");
14719
- const { mutate: handleUnlinkProvider, isPending: isProviderUnlinking } = useMutation11({
14685
+ const { mutate: handleUnlinkProvider, isPending: isProviderUnlinking } = useMutation10({
14720
14686
  mutationFn: async () => {
14721
14687
  if (!confirmUnlink) {
14722
14688
  throw new Error("No provider to unlink");
@@ -14844,7 +14810,7 @@ var init_useConnectExternalWalletMenuParams = __esm({
14844
14810
  });
14845
14811
 
14846
14812
  // src/internal/components/ConnectExternalWalletMenu/ConnectExternalWalletMenu.tsx
14847
- import { useMutation as useMutation12, useQuery as useQuery8, useQueryClient as useQueryClient14 } from "@tanstack/react-query";
14813
+ import { useMutation as useMutation11, useQuery as useQuery8, useQueryClient as useQueryClient14 } from "@tanstack/react-query";
14848
14814
  import { ArrowLeft as ArrowLeft7, Loader as Loader11, Wallet2Icon as Wallet2Icon2 } from "lucide-react";
14849
14815
  import { useCallback as useCallback16, useMemo as useMemo8 } from "react";
14850
14816
  import { useConnect, useConnection, useConnectors, useDisconnect as useDisconnect2, useSignMessage } from "wagmi";
@@ -14875,7 +14841,7 @@ function ConnectExternalWalletMenu() {
14875
14841
  queryKey: [PROVIDERS_QUERY_KEY, embarkAiAddress],
14876
14842
  queryFn: async () => getLinkedProviders()
14877
14843
  });
14878
- const { mutateAsync: onLinkingComplete } = useMutation12({
14844
+ const { mutateAsync: onLinkingComplete } = useMutation11({
14879
14845
  mutationFn: async (success) => {
14880
14846
  useManageWalletStore.getState().setProviderType(null);
14881
14847
  useLayoutDataStore.getState().setPage(walletMenuOpenedFrom || "manage-wallet" /* MANAGE_WALLET */);
@@ -14886,7 +14852,7 @@ function ConnectExternalWalletMenu() {
14886
14852
  callbacksRef.current?.onAccountUpdate?.({ providers: providers2 });
14887
14853
  }
14888
14854
  });
14889
- const { mutateAsync: loginOrLinkOrConnectWallet, isPending: isLoginOrLinkOrConnectWallet } = useMutation12({
14855
+ const { mutateAsync: loginOrLinkOrConnectWallet, isPending: isLoginOrLinkOrConnectWallet } = useMutation11({
14890
14856
  mutationFn: async (payload) => {
14891
14857
  const { walletData, connectFlowType } = payload;
14892
14858
  const { walletMenuOpenedFrom: walletMenuOpenedFrom2, setPage, setPendingWalletLogin } = useLayoutDataStore.getState();
@@ -15243,7 +15209,7 @@ var init_ConnectExternalWalletMenu2 = __esm({
15243
15209
  });
15244
15210
 
15245
15211
  // src/internal/clients/devices.ts
15246
- import { useMutation as useMutation13, useQuery as useQuery9, useQueryClient as useQueryClient15 } from "@tanstack/react-query";
15212
+ import { useMutation as useMutation12, useQuery as useQuery9, useQueryClient as useQueryClient15 } from "@tanstack/react-query";
15247
15213
  async function getDevices() {
15248
15214
  const response = await tssClient.get("/api/auth/devices", true);
15249
15215
  if (!response.success || !response.data) {
@@ -15276,7 +15242,7 @@ function useDevices() {
15276
15242
  }
15277
15243
  function useLinkDevice() {
15278
15244
  const qc = useQueryClient15();
15279
- return useMutation13({
15245
+ return useMutation12({
15280
15246
  mutationFn: (code) => linkDevice(code),
15281
15247
  onSuccess: () => {
15282
15248
  qc.invalidateQueries({ queryKey: [DEVICES_QUERY_KEY] });
@@ -15285,7 +15251,7 @@ function useLinkDevice() {
15285
15251
  }
15286
15252
  function useUnlinkDevice() {
15287
15253
  const qc = useQueryClient15();
15288
- return useMutation13({
15254
+ return useMutation12({
15289
15255
  mutationFn: (deviceId) => unlinkDevice(deviceId),
15290
15256
  onSuccess: () => {
15291
15257
  qc.invalidateQueries({ queryKey: [DEVICES_QUERY_KEY] });
@@ -16838,7 +16804,7 @@ var init_cloudStorage = __esm({
16838
16804
  });
16839
16805
 
16840
16806
  // src/internal/components/KeyshareRestoreMenu/hooks/useCreateBackup.ts
16841
- import { useMutation as useMutation14, useQueryClient as useQueryClient16 } from "@tanstack/react-query";
16807
+ import { useMutation as useMutation13, useQueryClient as useQueryClient16 } from "@tanstack/react-query";
16842
16808
  import { useCallback as useCallback21, useEffect as useEffect25 } from "react";
16843
16809
  function useCreateBackup() {
16844
16810
  const qc = useQueryClient16();
@@ -16859,7 +16825,7 @@ function useCreateBackup() {
16859
16825
  const onBackupSuccess = useCallback21(() => {
16860
16826
  console.log("[EMBARKAI BACKUP] Backup created successfully");
16861
16827
  }, [hasServerVault]);
16862
- const { mutate: createPasswordBackup, isPending: isPasswordBackupCreating } = useMutation14({
16828
+ const { mutate: createPasswordBackup, isPending: isPasswordBackupCreating } = useMutation13({
16863
16829
  mutationFn: async () => {
16864
16830
  const iframeManager = getIframeManager();
16865
16831
  if (!iframeManager) {
@@ -16904,7 +16870,7 @@ function useCreateBackup() {
16904
16870
  qc.invalidateQueries({ queryKey: [CHECK_BACKUP_QUERY_KEY, address] });
16905
16871
  }
16906
16872
  });
16907
- const { mutate: createLocalBackup, isPending: isLocalBackupCreating } = useMutation14({
16873
+ const { mutate: createLocalBackup, isPending: isLocalBackupCreating } = useMutation13({
16908
16874
  mutationFn: async () => {
16909
16875
  const iframeManager = getIframeManager();
16910
16876
  if (!usePasskey && !restorePassword) {
@@ -16938,7 +16904,7 @@ function useCreateBackup() {
16938
16904
  qc.invalidateQueries({ queryKey: [CHECK_BACKUP_QUERY_KEY, address] });
16939
16905
  }
16940
16906
  });
16941
- const { mutate: createPasskey, isPending: isPasskeyCreating } = useMutation14({
16907
+ const { mutate: createPasskey, isPending: isPasskeyCreating } = useMutation13({
16942
16908
  mutationFn: async () => {
16943
16909
  useRestoreStore.getState().setIsCreatingPasskey(true);
16944
16910
  const { linkPasskeyWithWebAuthn: linkPasskeyWithWebAuthn2 } = await Promise.resolve().then(() => (init_passkey2(), passkey_exports2));
@@ -16965,7 +16931,7 @@ function useCreateBackup() {
16965
16931
  }
16966
16932
  }
16967
16933
  });
16968
- const { mutate: createCloudBackup, isPending: isCloudBackupCreating } = useMutation14({
16934
+ const { mutate: createCloudBackup, isPending: isCloudBackupCreating } = useMutation13({
16969
16935
  mutationFn: async () => {
16970
16936
  const iframeManager = getIframeManager();
16971
16937
  const encryptedData = await iframeManager.encryptBackupData(passportUserId);
@@ -17028,7 +16994,7 @@ var init_useCreateBackup = __esm({
17028
16994
  });
17029
16995
 
17030
16996
  // src/internal/components/KeyshareRestoreMenu/hooks/useRestoreAccount.ts
17031
- import { useMutation as useMutation15 } from "@tanstack/react-query";
16997
+ import { useMutation as useMutation14 } from "@tanstack/react-query";
17032
16998
  function useRestoreAccount() {
17033
16999
  const recoveryUserId = useSession((st) => st.recoveryUserId);
17034
17000
  const {
@@ -17042,7 +17008,7 @@ function useRestoreAccount() {
17042
17008
  setRestoreFile
17043
17009
  } = useRestoreStore();
17044
17010
  const { onRestoreSuccess } = useOnRestoreSuccess();
17045
- const { mutate: restoreFromServer2, isPending: isRestoringFromServer } = useMutation15({
17011
+ const { mutate: restoreFromServer2, isPending: isRestoringFromServer } = useMutation14({
17046
17012
  mutationFn: async () => {
17047
17013
  setError(null);
17048
17014
  setSuccess(null);
@@ -17081,7 +17047,7 @@ function useRestoreAccount() {
17081
17047
  setError(errorMsg);
17082
17048
  }
17083
17049
  });
17084
- const { mutate: restoreFromFile, isPending: isRestoringFromFile } = useMutation15({
17050
+ const { mutate: restoreFromFile, isPending: isRestoringFromFile } = useMutation14({
17085
17051
  mutationFn: async () => {
17086
17052
  if (!restoreFile) {
17087
17053
  throw new Error("Please select a backup file");
@@ -17115,7 +17081,7 @@ function useRestoreAccount() {
17115
17081
  setError(errorMsg);
17116
17082
  }
17117
17083
  });
17118
- const { mutate: restoreFromCloud, isPending: isRestoringFromCloud } = useMutation15({
17084
+ const { mutate: restoreFromCloud, isPending: isRestoringFromCloud } = useMutation14({
17119
17085
  mutationFn: async () => {
17120
17086
  alert("Cloud restore not implemented yet");
17121
17087
  return null;
@@ -18208,7 +18174,7 @@ var init_methods = __esm({
18208
18174
  });
18209
18175
 
18210
18176
  // src/internal/components/KeyshareRestoreMenu/KeyshareRestoreMenu.tsx
18211
- import { useMutation as useMutation16, useQuery as useQuery11, useQueryClient as useQueryClient18 } from "@tanstack/react-query";
18177
+ import { useMutation as useMutation15, useQuery as useQuery11, useQueryClient as useQueryClient18 } from "@tanstack/react-query";
18212
18178
  import { AlertCircle as AlertCircle2, CheckCircle2, CloudDownload as CloudDownload2, Loader as Loader14, UserCircle as UserCircle2 } from "lucide-react";
18213
18179
  import { useEffect as useEffect30 } from "react";
18214
18180
  import { useDisconnect as useDisconnect4 } from "wagmi";
@@ -18289,7 +18255,7 @@ var init_KeyshareRestoreMenu = __esm({
18289
18255
  useEffect30(() => {
18290
18256
  if (!!hasServerBackup) useRestoreStore.getState().setMethod("server");
18291
18257
  }, [hasServerBackup]);
18292
- const { mutate: disconnect, isPending: isDisconnecting } = useMutation16({
18258
+ const { mutate: disconnect, isPending: isDisconnecting } = useMutation15({
18293
18259
  mutationFn: async () => {
18294
18260
  const { setStatus, setIsLoading } = useSession.getState();
18295
18261
  const { setError, setMethod } = useRestoreStore.getState();
@@ -19225,7 +19191,7 @@ var init_useNicknameStore = __esm({
19225
19191
  });
19226
19192
 
19227
19193
  // src/internal/components/NicknameMenu/useNicknameAvailability.ts
19228
- import { useMutation as useMutation17 } from "@tanstack/react-query";
19194
+ import { useMutation as useMutation16 } from "@tanstack/react-query";
19229
19195
  import { debounce as debounce4 } from "lodash-es";
19230
19196
  import { useCallback as useCallback23, useEffect as useEffect35 } from "react";
19231
19197
  function useNicknameAvailability(currentNickname) {
@@ -19235,7 +19201,7 @@ function useNicknameAvailability(currentNickname) {
19235
19201
  if (!currentNickname) return;
19236
19202
  useNicknameStore.getState().setNicknameValue(currentNickname);
19237
19203
  }, [currentNickname]);
19238
- const { mutate: checkAvailability, isPending: isCheckingAvailability } = useMutation17({
19204
+ const { mutate: checkAvailability, isPending: isCheckingAvailability } = useMutation16({
19239
19205
  mutationFn: async (newNickname) => {
19240
19206
  useNicknameStore.getState().setError(null);
19241
19207
  useNicknameStore.getState().setAvailability(null);
@@ -19280,7 +19246,7 @@ var init_useNicknameAvailability = __esm({
19280
19246
  });
19281
19247
 
19282
19248
  // src/internal/components/NicknameMenu/NicknameEditForm.tsx
19283
- import { useMutation as useMutation18, useQueryClient as useQueryClient19 } from "@tanstack/react-query";
19249
+ import { useMutation as useMutation17, useQueryClient as useQueryClient19 } from "@tanstack/react-query";
19284
19250
  import { AtSignIcon, CopyIcon, LoaderIcon as LoaderIcon10, SaveIcon } from "lucide-react";
19285
19251
  import { useCallback as useCallback24, useState as useState20 } from "react";
19286
19252
  import { Fragment as Fragment30, jsx as jsx87, jsxs as jsxs80 } from "react/jsx-runtime";
@@ -19296,7 +19262,7 @@ function NicknameEditForm(props) {
19296
19262
  const nicknameAvailability = useNicknameStore((st) => st.availability);
19297
19263
  const { isCheckingAvailability } = useNicknameAvailability(nicknameInfo ? nicknameInfo.handle : "");
19298
19264
  const [isNicknameCopied, setIsNicknameCopied] = useState20(false);
19299
- const { mutate: changeNickname2, isPending: isNicknameChanging } = useMutation18({
19265
+ const { mutate: changeNickname2, isPending: isNicknameChanging } = useMutation17({
19300
19266
  mutationFn: (handle) => changeNickname(handle),
19301
19267
  onSuccess: () => {
19302
19268
  qc.invalidateQueries({ queryKey: [QUERY_KEYS.nicknameInfo] });
@@ -21051,7 +21017,7 @@ var init_ConnectedApps = __esm({
21051
21017
  });
21052
21018
 
21053
21019
  // src/internal/components/SecurityMenu/ConnectedApps/UntrustApplication.tsx
21054
- import { useMutation as useMutation19, useQueryClient as useQueryClient22 } from "@tanstack/react-query";
21020
+ import { useMutation as useMutation18, useQueryClient as useQueryClient22 } from "@tanstack/react-query";
21055
21021
  import { AppWindowMac as AppWindowMac2, Loader as Loader18 } from "lucide-react";
21056
21022
  import { jsx as jsx94, jsxs as jsxs87 } from "react/jsx-runtime";
21057
21023
  function UntrustApplication() {
@@ -21059,7 +21025,7 @@ function UntrustApplication() {
21059
21025
  const qc = useQueryClient22();
21060
21026
  const userId = useSession((st) => st?.session?.mpcUserId);
21061
21027
  const appToUntrust = useSecurityStore((st) => st.appToUntrust);
21062
- const { mutate: handleUntrustApp, isPending: isUntrustingApp } = useMutation19({
21028
+ const { mutate: handleUntrustApp, isPending: isUntrustingApp } = useMutation18({
21063
21029
  mutationFn: async () => {
21064
21030
  if (!userId || !appToUntrust) return;
21065
21031
  const iframeManager = getIframeManager();
@@ -22164,7 +22130,7 @@ var init_useOperationHashesStore = __esm({
22164
22130
  });
22165
22131
 
22166
22132
  // src/internal/components/SendMenu/hyperbridge/hooks/useBridge.ts
22167
- import { useMutation as useMutation20, useQueryClient as useQueryClient23 } from "@tanstack/react-query";
22133
+ import { useMutation as useMutation19, useQueryClient as useQueryClient23 } from "@tanstack/react-query";
22168
22134
  import { useCallback as useCallback27 } from "react";
22169
22135
  import { useSwitchChain, useWalletClient } from "wagmi";
22170
22136
  function useBridge() {
@@ -22186,7 +22152,7 @@ function useBridge() {
22186
22152
  setOriginChain(destinationChain);
22187
22153
  setDestinationChain(originChain);
22188
22154
  }, []);
22189
- const { mutate: estimateQuote } = useMutation20({
22155
+ const { mutate: estimateQuote } = useMutation19({
22190
22156
  mutationFn: async (amountToBridge) => {
22191
22157
  useFlowSelectorStore.getState().setError(null);
22192
22158
  useFlowSelectorStore.getState().setIsUiLocked(true);
@@ -22253,7 +22219,7 @@ function useBridge() {
22253
22219
  })
22254
22220
  );
22255
22221
  }, []);
22256
- const { mutate: bridgeAsset, isPending: isAssetBridging } = useMutation20({
22222
+ const { mutate: bridgeAsset, isPending: isAssetBridging } = useMutation19({
22257
22223
  mutationFn: async () => {
22258
22224
  const directWalletAddress = useExternalWalletStore.getState().externalAddress;
22259
22225
  const directWalletChainId = useExternalWalletStore.getState().externalChainId;
@@ -24734,7 +24700,7 @@ var init_InputSendStep = __esm({
24734
24700
  });
24735
24701
 
24736
24702
  // src/internal/components/SendMenu/send/sendSteps/ConfirmSendStep.tsx
24737
- import { useMutation as useMutation21 } from "@tanstack/react-query";
24703
+ import { useMutation as useMutation20 } from "@tanstack/react-query";
24738
24704
  import { AlertTriangle as AlertTriangle3, AtSign as AtSign3, Loader as Loader21, Shield, ShieldAlert as ShieldAlert2, ShieldCheck as ShieldCheck3 } from "lucide-react";
24739
24705
  import { Fragment as Fragment41, jsx as jsx114, jsxs as jsxs104 } from "react/jsx-runtime";
24740
24706
  function ConfirmSendStep(props) {
@@ -24748,7 +24714,7 @@ function ConfirmSendStep(props) {
24748
24714
  const isNft = isNftAsset3(selectedAsset);
24749
24715
  const isSecurity = isSecurityToken2(selectedAsset);
24750
24716
  const effectiveAddress = isNicknameInput ? resolvedAddress : recipient;
24751
- const { mutate: handleConfirm, isPending: isTransactionPending } = useMutation21({
24717
+ const { mutate: handleConfirm, isPending: isTransactionPending } = useMutation20({
24752
24718
  mutationFn: async () => {
24753
24719
  if (!effectiveAddress || !selectedAsset) return;
24754
24720
  setTxStep("pending");
@@ -26777,7 +26743,7 @@ var init_package = __esm({
26777
26743
  "package.json"() {
26778
26744
  package_default = {
26779
26745
  name: "@embarkai/ui-kit",
26780
- version: "0.4.82",
26746
+ version: "0.4.84",
26781
26747
  description: "React UI components and hooks for EmbarkAI authentication and Account Abstraction",
26782
26748
  type: "module",
26783
26749
  main: "./dist/index.cjs",
@@ -26877,7 +26843,7 @@ var init_package = __esm({
26877
26843
  });
26878
26844
 
26879
26845
  // src/internal/components/Footer/Footer.tsx
26880
- import { useMutation as useMutation22, useQueryClient as useQueryClient27 } from "@tanstack/react-query";
26846
+ import { useMutation as useMutation21, useQueryClient as useQueryClient27 } from "@tanstack/react-query";
26881
26847
  import { Loader as Loader29, LogOut } from "lucide-react";
26882
26848
  import { useDisconnect as useDisconnect5 } from "wagmi";
26883
26849
  import { jsx as jsx122, jsxs as jsxs111 } from "react/jsx-runtime";
@@ -26899,7 +26865,7 @@ function Footer() {
26899
26865
  }
26900
26866
  }
26901
26867
  });
26902
- const { mutate: disconnect, isPending: isDisconnecting } = useMutation22({
26868
+ const { mutate: disconnect, isPending: isDisconnecting } = useMutation21({
26903
26869
  mutationFn: async (disconnectAddress) => {
26904
26870
  if (!disconnectAddress) throw new Error("No address to disconnect");
26905
26871
  const { setError, setStatus, setIsLoading } = useSession.getState();
@@ -31815,6 +31781,7 @@ init_tokens();
31815
31781
  init_wallets();
31816
31782
 
31817
31783
  // src/index.ts
31784
+ init_Expandable2();
31818
31785
  init_i18n();
31819
31786
 
31820
31787
  // src/internal/exportedQueryKeys.ts
@@ -31841,6 +31808,7 @@ export {
31841
31808
  Address,
31842
31809
  ConnectWalletButton,
31843
31810
  ErrorCodes,
31811
+ Expandable,
31844
31812
  Hash,
31845
31813
  KeyshareBackupMenu as KeyshareBackup,
31846
31814
  LOCAL_STORAGE_I18N_KEY,