@tatchi-xyz/sdk 0.20.0 → 0.21.0

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.
Files changed (217) hide show
  1. package/dist/cjs/core/TatchiPasskey/emailRecovery.js +67 -45
  2. package/dist/cjs/core/TatchiPasskey/emailRecovery.js.map +1 -1
  3. package/dist/cjs/core/TatchiPasskey/index.js +2 -1
  4. package/dist/cjs/core/TatchiPasskey/index.js.map +1 -1
  5. package/dist/cjs/core/TatchiPasskey/linkDevice.js +2 -1
  6. package/dist/cjs/core/TatchiPasskey/linkDevice.js.map +1 -1
  7. package/dist/cjs/core/TatchiPasskey/scanDevice.js +5 -3
  8. package/dist/cjs/core/TatchiPasskey/scanDevice.js.map +1 -1
  9. package/dist/cjs/core/WalletIframe/client/router.js +1 -1
  10. package/dist/cjs/core/WalletIframe/client/router.js.map +1 -1
  11. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +3 -4
  12. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  13. package/dist/cjs/core/defaultConfigs.js +3 -7
  14. package/dist/cjs/core/defaultConfigs.js.map +1 -1
  15. package/dist/cjs/core/nearCrypto.js +29 -5
  16. package/dist/cjs/core/nearCrypto.js.map +1 -1
  17. package/dist/cjs/core/rpcCalls.js +56 -26
  18. package/dist/cjs/core/rpcCalls.js.map +1 -1
  19. package/dist/cjs/react/components/AccountMenuButton/{LinkedDevicesModal-BCrFe5p3.css → LinkedDevicesModal-BRtht0XI.css} +1 -1
  20. package/dist/{esm/react/components/AccountMenuButton/LinkedDevicesModal-BCrFe5p3.css.map → cjs/react/components/AccountMenuButton/LinkedDevicesModal-BRtht0XI.css.map} +1 -1
  21. package/dist/cjs/react/components/AccountMenuButton/{ProfileDropdown-CRJrtxDb.css → ProfileDropdown-BG_6hcim.css} +1 -1
  22. package/dist/{esm/react/components/AccountMenuButton/ProfileDropdown-CRJrtxDb.css.map → cjs/react/components/AccountMenuButton/ProfileDropdown-BG_6hcim.css.map} +1 -1
  23. package/dist/cjs/react/components/AccountMenuButton/{Web3AuthProfileButton-DXFRw8ND.css → Web3AuthProfileButton-k8_FAYFq.css} +1 -1
  24. package/dist/cjs/react/components/AccountMenuButton/{Web3AuthProfileButton-DXFRw8ND.css.map → Web3AuthProfileButton-k8_FAYFq.css.map} +1 -1
  25. package/dist/cjs/react/components/AccountMenuButton/icons/{TouchIcon-DNgbAK_i.css → TouchIcon-C-RcGfr5.css} +1 -1
  26. package/dist/cjs/react/components/AccountMenuButton/icons/{TouchIcon-DNgbAK_i.css.map → TouchIcon-C-RcGfr5.css.map} +1 -1
  27. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-DRwSoF8q.css → PasskeyAuthMenu-DKMiLeT9.css} +59 -4
  28. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-DRwSoF8q.css.map → PasskeyAuthMenu-DKMiLeT9.css.map} +1 -1
  29. package/dist/cjs/react/components/PasskeyAuthMenu/adapters/tatchi.js +1 -0
  30. package/dist/cjs/react/components/PasskeyAuthMenu/adapters/tatchi.js.map +1 -1
  31. package/dist/cjs/react/components/PasskeyAuthMenu/client.js +30 -8
  32. package/dist/cjs/react/components/PasskeyAuthMenu/client.js.map +1 -1
  33. package/dist/cjs/react/components/PasskeyAuthMenu/controller/useSDKEvents.js +22 -0
  34. package/dist/cjs/react/components/PasskeyAuthMenu/controller/useSDKEvents.js.map +1 -0
  35. package/dist/cjs/react/components/PasskeyAuthMenu/ui/ContentSwitcher.js +17 -4
  36. package/dist/cjs/react/components/PasskeyAuthMenu/ui/ContentSwitcher.js.map +1 -1
  37. package/dist/cjs/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js +254 -140
  38. package/dist/cjs/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js.map +1 -1
  39. package/dist/cjs/react/components/{ShowQRCode-CL4gsszN.css → ShowQRCode-CB0UCQ_h.css} +1 -1
  40. package/dist/cjs/react/components/{ShowQRCode-CL4gsszN.css.map → ShowQRCode-CB0UCQ_h.css.map} +1 -1
  41. package/dist/cjs/react/context/useSDKFlowRuntime.js +183 -0
  42. package/dist/cjs/react/context/useSDKFlowRuntime.js.map +1 -0
  43. package/dist/cjs/react/context/useTatchiContextValue.js +24 -15
  44. package/dist/cjs/react/context/useTatchiContextValue.js.map +1 -1
  45. package/dist/cjs/react/context/useTatchiWithSdkFlow.js +96 -0
  46. package/dist/cjs/react/context/useTatchiWithSdkFlow.js.map +1 -0
  47. package/dist/cjs/react/sdk/src/core/EmailRecovery/index.js +1 -0
  48. package/dist/cjs/react/sdk/src/core/TatchiPasskey/emailRecovery.js +67 -45
  49. package/dist/cjs/react/sdk/src/core/TatchiPasskey/emailRecovery.js.map +1 -1
  50. package/dist/cjs/react/sdk/src/core/TatchiPasskey/index.js +2 -1
  51. package/dist/cjs/react/sdk/src/core/TatchiPasskey/index.js.map +1 -1
  52. package/dist/cjs/react/sdk/src/core/TatchiPasskey/linkDevice.js +2 -1
  53. package/dist/cjs/react/sdk/src/core/TatchiPasskey/linkDevice.js.map +1 -1
  54. package/dist/cjs/react/sdk/src/core/TatchiPasskey/scanDevice.js +5 -3
  55. package/dist/cjs/react/sdk/src/core/TatchiPasskey/scanDevice.js.map +1 -1
  56. package/dist/cjs/react/sdk/src/core/WalletIframe/client/router.js +1 -1
  57. package/dist/cjs/react/sdk/src/core/WalletIframe/client/router.js.map +1 -1
  58. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +3 -4
  59. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  60. package/dist/cjs/react/sdk/src/core/defaultConfigs.js +3 -7
  61. package/dist/cjs/react/sdk/src/core/defaultConfigs.js.map +1 -1
  62. package/dist/cjs/react/sdk/src/core/nearCrypto.js +29 -5
  63. package/dist/cjs/react/sdk/src/core/nearCrypto.js.map +1 -1
  64. package/dist/cjs/react/sdk/src/core/rpcCalls.js +56 -26
  65. package/dist/cjs/react/sdk/src/core/rpcCalls.js.map +1 -1
  66. package/dist/cjs/server/email-recovery/emailParsers.js +2 -1
  67. package/dist/cjs/server/email-recovery/emailParsers.js.map +1 -1
  68. package/dist/cjs/server/email-recovery/index.js +6 -6
  69. package/dist/cjs/server/email-recovery/index.js.map +1 -1
  70. package/dist/cjs/server/email-recovery/rpcCalls.js +22 -3
  71. package/dist/cjs/server/email-recovery/rpcCalls.js.map +1 -1
  72. package/dist/cjs/server/router/cloudflare.js +8 -3
  73. package/dist/cjs/server/router/cloudflare.js.map +1 -1
  74. package/dist/cjs/server/router/express.js.map +1 -1
  75. package/dist/cjs/server/sdk/src/core/defaultConfigs.js +2 -4
  76. package/dist/cjs/server/sdk/src/core/defaultConfigs.js.map +1 -1
  77. package/dist/cjs/server/sdk/src/core/nearCrypto.js +26 -7
  78. package/dist/cjs/server/sdk/src/core/nearCrypto.js.map +1 -1
  79. package/dist/esm/core/TatchiPasskey/emailRecovery.js +67 -45
  80. package/dist/esm/core/TatchiPasskey/emailRecovery.js.map +1 -1
  81. package/dist/esm/core/TatchiPasskey/index.js +2 -1
  82. package/dist/esm/core/TatchiPasskey/index.js.map +1 -1
  83. package/dist/esm/core/TatchiPasskey/linkDevice.js +2 -1
  84. package/dist/esm/core/TatchiPasskey/linkDevice.js.map +1 -1
  85. package/dist/esm/core/TatchiPasskey/scanDevice.js +5 -3
  86. package/dist/esm/core/TatchiPasskey/scanDevice.js.map +1 -1
  87. package/dist/esm/core/WalletIframe/client/router.js +1 -1
  88. package/dist/esm/core/WalletIframe/client/router.js.map +1 -1
  89. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +2 -3
  90. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  91. package/dist/esm/core/defaultConfigs.js +3 -7
  92. package/dist/esm/core/defaultConfigs.js.map +1 -1
  93. package/dist/esm/core/nearCrypto.js +24 -6
  94. package/dist/esm/core/nearCrypto.js.map +1 -1
  95. package/dist/esm/core/rpcCalls.js +56 -26
  96. package/dist/esm/core/rpcCalls.js.map +1 -1
  97. package/dist/esm/react/components/AccountMenuButton/{LinkedDevicesModal-BCrFe5p3.css → LinkedDevicesModal-BRtht0XI.css} +1 -1
  98. package/dist/{cjs/react/components/AccountMenuButton/LinkedDevicesModal-BCrFe5p3.css.map → esm/react/components/AccountMenuButton/LinkedDevicesModal-BRtht0XI.css.map} +1 -1
  99. package/dist/esm/react/components/AccountMenuButton/{ProfileDropdown-CRJrtxDb.css → ProfileDropdown-BG_6hcim.css} +1 -1
  100. package/dist/{cjs/react/components/AccountMenuButton/ProfileDropdown-CRJrtxDb.css.map → esm/react/components/AccountMenuButton/ProfileDropdown-BG_6hcim.css.map} +1 -1
  101. package/dist/esm/react/components/AccountMenuButton/{Web3AuthProfileButton-DXFRw8ND.css → Web3AuthProfileButton-k8_FAYFq.css} +1 -1
  102. package/dist/esm/react/components/AccountMenuButton/{Web3AuthProfileButton-DXFRw8ND.css.map → Web3AuthProfileButton-k8_FAYFq.css.map} +1 -1
  103. package/dist/esm/react/components/AccountMenuButton/icons/{TouchIcon-DNgbAK_i.css → TouchIcon-C-RcGfr5.css} +1 -1
  104. package/dist/esm/react/components/AccountMenuButton/icons/{TouchIcon-DNgbAK_i.css.map → TouchIcon-C-RcGfr5.css.map} +1 -1
  105. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-DRwSoF8q.css → PasskeyAuthMenu-DKMiLeT9.css} +59 -4
  106. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-DRwSoF8q.css.map → PasskeyAuthMenu-DKMiLeT9.css.map} +1 -1
  107. package/dist/esm/react/components/PasskeyAuthMenu/adapters/tatchi.js +1 -0
  108. package/dist/esm/react/components/PasskeyAuthMenu/adapters/tatchi.js.map +1 -1
  109. package/dist/esm/react/components/PasskeyAuthMenu/client.js +30 -8
  110. package/dist/esm/react/components/PasskeyAuthMenu/client.js.map +1 -1
  111. package/dist/esm/react/components/PasskeyAuthMenu/controller/useSDKEvents.js +20 -0
  112. package/dist/esm/react/components/PasskeyAuthMenu/controller/useSDKEvents.js.map +1 -0
  113. package/dist/esm/react/components/PasskeyAuthMenu/ui/ContentSwitcher.js +17 -4
  114. package/dist/esm/react/components/PasskeyAuthMenu/ui/ContentSwitcher.js.map +1 -1
  115. package/dist/esm/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js +254 -140
  116. package/dist/esm/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js.map +1 -1
  117. package/dist/esm/react/components/{ShowQRCode-CL4gsszN.css → ShowQRCode-CB0UCQ_h.css} +1 -1
  118. package/dist/esm/react/components/{ShowQRCode-CL4gsszN.css.map → ShowQRCode-CB0UCQ_h.css.map} +1 -1
  119. package/dist/esm/react/context/useSDKFlowRuntime.js +181 -0
  120. package/dist/esm/react/context/useSDKFlowRuntime.js.map +1 -0
  121. package/dist/esm/react/context/useTatchiContextValue.js +25 -16
  122. package/dist/esm/react/context/useTatchiContextValue.js.map +1 -1
  123. package/dist/esm/react/context/useTatchiWithSdkFlow.js +94 -0
  124. package/dist/esm/react/context/useTatchiWithSdkFlow.js.map +1 -0
  125. package/dist/esm/react/sdk/src/core/EmailRecovery/index.js +1 -1
  126. package/dist/esm/react/sdk/src/core/TatchiPasskey/emailRecovery.js +67 -45
  127. package/dist/esm/react/sdk/src/core/TatchiPasskey/emailRecovery.js.map +1 -1
  128. package/dist/esm/react/sdk/src/core/TatchiPasskey/index.js +2 -1
  129. package/dist/esm/react/sdk/src/core/TatchiPasskey/index.js.map +1 -1
  130. package/dist/esm/react/sdk/src/core/TatchiPasskey/linkDevice.js +2 -1
  131. package/dist/esm/react/sdk/src/core/TatchiPasskey/linkDevice.js.map +1 -1
  132. package/dist/esm/react/sdk/src/core/TatchiPasskey/scanDevice.js +5 -3
  133. package/dist/esm/react/sdk/src/core/TatchiPasskey/scanDevice.js.map +1 -1
  134. package/dist/esm/react/sdk/src/core/WalletIframe/client/router.js +1 -1
  135. package/dist/esm/react/sdk/src/core/WalletIframe/client/router.js.map +1 -1
  136. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +2 -3
  137. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  138. package/dist/esm/react/sdk/src/core/defaultConfigs.js +3 -7
  139. package/dist/esm/react/sdk/src/core/defaultConfigs.js.map +1 -1
  140. package/dist/esm/react/sdk/src/core/nearCrypto.js +24 -6
  141. package/dist/esm/react/sdk/src/core/nearCrypto.js.map +1 -1
  142. package/dist/esm/react/sdk/src/core/rpcCalls.js +56 -26
  143. package/dist/esm/react/sdk/src/core/rpcCalls.js.map +1 -1
  144. package/dist/esm/react/styles/styles.css +58 -3
  145. package/dist/esm/sdk/{defaultConfigs-DpslkAQd.js → defaultConfigs-CfQDV-ya.js} +3 -7
  146. package/dist/esm/sdk/{getDeviceNumber-fXizNGQl.js → getDeviceNumber-BpernPnM.js} +4 -8
  147. package/dist/esm/sdk/getDeviceNumber-BpernPnM.js.map +1 -0
  148. package/dist/esm/sdk/offline-export-app.js +23 -6
  149. package/dist/esm/sdk/offline-export-app.js.map +1 -1
  150. package/dist/esm/sdk/{router-DuGYOd3G.js → router-BWtacLJg.js} +1 -1
  151. package/dist/esm/sdk/{rpcCalls-BQrJMTdg.js → rpcCalls-CYGJSCgm.js} +3 -3
  152. package/dist/esm/sdk/{rpcCalls-YVeUVMk2.js → rpcCalls-DZZSa-sk.js} +57 -27
  153. package/dist/esm/sdk/{transactions-bqaAwL4k.js → transactions-Cn9xTWlK.js} +2 -2
  154. package/dist/esm/sdk/{transactions-bqaAwL4k.js.map → transactions-Cn9xTWlK.js.map} +1 -1
  155. package/dist/esm/sdk/{transactions-BalIhtJ9.js → transactions-DfdwDQCn.js} +1 -1
  156. package/dist/esm/sdk/wallet-iframe-host.js +549 -557
  157. package/dist/esm/server/email-recovery/emailParsers.js +3 -1
  158. package/dist/esm/server/email-recovery/emailParsers.js.map +1 -1
  159. package/dist/esm/server/email-recovery/index.js +6 -6
  160. package/dist/esm/server/email-recovery/index.js.map +1 -1
  161. package/dist/esm/server/email-recovery/rpcCalls.js +22 -3
  162. package/dist/esm/server/email-recovery/rpcCalls.js.map +1 -1
  163. package/dist/esm/server/router/cloudflare.js +8 -3
  164. package/dist/esm/server/router/cloudflare.js.map +1 -1
  165. package/dist/esm/server/router/express.js.map +1 -1
  166. package/dist/esm/server/sdk/src/core/defaultConfigs.js +2 -4
  167. package/dist/esm/server/sdk/src/core/defaultConfigs.js.map +1 -1
  168. package/dist/esm/server/sdk/src/core/nearCrypto.js +26 -8
  169. package/dist/esm/server/sdk/src/core/nearCrypto.js.map +1 -1
  170. package/dist/esm/wasm_vrf_worker/pkg/wasm_vrf_worker_bg.wasm +0 -0
  171. package/dist/types/src/core/TatchiPasskey/emailRecovery.d.ts +5 -4
  172. package/dist/types/src/core/TatchiPasskey/emailRecovery.d.ts.map +1 -1
  173. package/dist/types/src/core/TatchiPasskey/index.d.ts +1 -1
  174. package/dist/types/src/core/TatchiPasskey/index.d.ts.map +1 -1
  175. package/dist/types/src/core/TatchiPasskey/scanDevice.d.ts.map +1 -1
  176. package/dist/types/src/core/WalletIframe/TatchiPasskeyIframe.d.ts +1 -1
  177. package/dist/types/src/core/WalletIframe/TatchiPasskeyIframe.d.ts.map +1 -1
  178. package/dist/types/src/core/WalletIframe/client/router.d.ts +1 -1
  179. package/dist/types/src/core/WalletIframe/client/router.d.ts.map +1 -1
  180. package/dist/types/src/core/WalletIframe/shared/messages.d.ts +1 -1
  181. package/dist/types/src/core/WalletIframe/shared/messages.d.ts.map +1 -1
  182. package/dist/types/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.d.ts +2 -1
  183. package/dist/types/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.d.ts.map +1 -1
  184. package/dist/types/src/core/defaultConfigs.d.ts.map +1 -1
  185. package/dist/types/src/core/nearCrypto.d.ts +14 -0
  186. package/dist/types/src/core/nearCrypto.d.ts.map +1 -1
  187. package/dist/types/src/core/rpcCalls.d.ts +11 -8
  188. package/dist/types/src/core/rpcCalls.d.ts.map +1 -1
  189. package/dist/types/src/core/types/tatchi.d.ts +0 -4
  190. package/dist/types/src/core/types/tatchi.d.ts.map +1 -1
  191. package/dist/types/src/react/components/PasskeyAuthMenu/adapters/tatchi.d.ts +2 -0
  192. package/dist/types/src/react/components/PasskeyAuthMenu/adapters/tatchi.d.ts.map +1 -1
  193. package/dist/types/src/react/components/PasskeyAuthMenu/client.d.ts.map +1 -1
  194. package/dist/types/src/react/components/PasskeyAuthMenu/controller/useSDKEvents.d.ts +10 -0
  195. package/dist/types/src/react/components/PasskeyAuthMenu/controller/useSDKEvents.d.ts.map +1 -0
  196. package/dist/types/src/react/components/PasskeyAuthMenu/types.d.ts +8 -3
  197. package/dist/types/src/react/components/PasskeyAuthMenu/types.d.ts.map +1 -1
  198. package/dist/types/src/react/components/PasskeyAuthMenu/ui/ContentSwitcher.d.ts +2 -0
  199. package/dist/types/src/react/components/PasskeyAuthMenu/ui/ContentSwitcher.d.ts.map +1 -1
  200. package/dist/types/src/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.d.ts +1 -1
  201. package/dist/types/src/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.d.ts.map +1 -1
  202. package/dist/types/src/react/context/useSDKFlowRuntime.d.ts +10 -0
  203. package/dist/types/src/react/context/useSDKFlowRuntime.d.ts.map +1 -0
  204. package/dist/types/src/react/context/useTatchiContextValue.d.ts.map +1 -1
  205. package/dist/types/src/react/context/useTatchiWithSdkFlow.d.ts +9 -0
  206. package/dist/types/src/react/context/useTatchiWithSdkFlow.d.ts.map +1 -0
  207. package/dist/types/src/react/types.d.ts +31 -0
  208. package/dist/types/src/react/types.d.ts.map +1 -1
  209. package/dist/types/src/server/email-recovery/emailParsers.d.ts.map +1 -1
  210. package/dist/types/src/server/email-recovery/index.d.ts +5 -6
  211. package/dist/types/src/server/email-recovery/index.d.ts.map +1 -1
  212. package/dist/types/src/server/email-recovery/rpcCalls.d.ts +1 -0
  213. package/dist/types/src/server/email-recovery/rpcCalls.d.ts.map +1 -1
  214. package/dist/types/src/server/router/cloudflare-adaptor.d.ts.map +1 -1
  215. package/dist/workers/wasm_vrf_worker_bg.wasm +0 -0
  216. package/package.json +1 -1
  217. package/dist/esm/sdk/getDeviceNumber-fXizNGQl.js.map +0 -1
@@ -1,13 +1,24 @@
1
- import { init_accountIds, toAccountId } from "../../../sdk/src/core/types/accountIds.js";
2
- import { IndexedDBManager, init_IndexedDBManager } from "../../../sdk/src/core/IndexedDBManager/index.js";
1
+ import { EmailRecoveryPhase, EmailRecoveryStatus, init_sdkSentEvents } from "../../../sdk/src/core/types/sdkSentEvents.js";
2
+ import { bytesToHex, canonicalizeEmail, init_EmailRecovery } from "../../../sdk/src/core/EmailRecovery/index.js";
3
3
  import { EmailRecoveryErrorCode, init_emailRecovery } from "../../../sdk/src/core/types/emailRecovery.js";
4
4
  import React from "react";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
6
 
7
7
  //#region src/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.tsx
8
- init_IndexedDBManager();
9
- init_accountIds();
8
+ init_sdkSentEvents();
10
9
  init_emailRecovery();
10
+ init_EmailRecovery();
11
+ async function hashRecoveryEmailForAccountHex(args) {
12
+ const salt = String(args.accountId || "").trim().toLowerCase();
13
+ if (!salt) return null;
14
+ const canonical = canonicalizeEmail(String(args.recoveryEmail || ""));
15
+ if (!canonical || !canonical.includes("@")) return null;
16
+ if (typeof crypto === "undefined" || !crypto.subtle) return null;
17
+ const input = `${canonical}|${salt}`;
18
+ const bytes = new TextEncoder().encode(input);
19
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
20
+ return bytesToHex(new Uint8Array(digest));
21
+ }
11
22
  function getEmailRecoveryErrorCode(err) {
12
23
  const code = err?.code;
13
24
  if (typeof code !== "string") return null;
@@ -15,6 +26,11 @@ function getEmailRecoveryErrorCode(err) {
15
26
  }
16
27
  function getEmailRecoveryUiError(err) {
17
28
  const fallback = err instanceof Error ? err.message : String(err || "");
29
+ const normalizedFallback = fallback.trim().toLowerCase();
30
+ if (normalizedFallback.includes("recovery email is required")) return {
31
+ message: fallback || "Recovery email is required for email-based account recovery. Make sure you send the email from your configured recovery email address.",
32
+ canRestart: true
33
+ };
18
34
  const code = getEmailRecoveryErrorCode(err);
19
35
  switch (code) {
20
36
  case EmailRecoveryErrorCode.VRF_CHALLENGE_EXPIRED: return {
@@ -31,6 +47,19 @@ function getEmailRecoveryUiError(err) {
31
47
  };
32
48
  }
33
49
  }
50
+ function getEmailRecoveryErrorTxHash(err) {
51
+ const carrier = err;
52
+ const ctx = carrier?.context && typeof carrier.context === "object" ? carrier.context : null;
53
+ const details = carrier?.details && typeof carrier.details === "object" ? carrier.details : null;
54
+ const source = ctx ?? details;
55
+ if (!source) return null;
56
+ const txHash = source.transactionHash;
57
+ return typeof txHash === "string" && txHash.trim().length > 0 ? txHash.trim() : null;
58
+ }
59
+ function asRecord(value) {
60
+ if (!value || typeof value !== "object") return null;
61
+ return value;
62
+ }
34
63
  const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, emailRecoveryOptions }) => {
35
64
  const mountedRef = React.useRef(true);
36
65
  const mailtoAttemptTimerRef = React.useRef(null);
@@ -47,7 +76,6 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
47
76
  }, []);
48
77
  const [isBusy, setIsBusy] = React.useState(false);
49
78
  const [accountIdInput, setAccountIdInput] = React.useState("");
50
- const [recoveryEmailInput, setRecoveryEmailInput] = React.useState("");
51
79
  const [pendingMailtoUrl, setPendingMailtoUrl] = React.useState(null);
52
80
  const [pendingNearPublicKey, setPendingNearPublicKey] = React.useState(null);
53
81
  const [mailtoUiState, setMailtoUiState] = React.useState("ready");
@@ -59,9 +87,11 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
59
87
  const [accountInfoLoading, setAccountInfoLoading] = React.useState(false);
60
88
  const [accountInfoError, setAccountInfoError] = React.useState(null);
61
89
  const [localRecoveryEmails, setLocalRecoveryEmails] = React.useState([]);
90
+ const [recoveryEmailRecords, setRecoveryEmailRecords] = React.useState([]);
91
+ const [recoveryEmailInput, setRecoveryEmailInput] = React.useState("");
92
+ const [recoveryEmailMatchStatus, setRecoveryEmailMatchStatus] = React.useState("empty");
62
93
  const [explorerToast, setExplorerToast] = React.useState(null);
63
94
  const lastPrefilledAccountIdRef = React.useRef("");
64
- const lastPrefilledRecoveryEmailRef = React.useRef("");
65
95
  React.useEffect(() => {
66
96
  const next = (accountId || "").trim();
67
97
  if (!next) return;
@@ -82,6 +112,9 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
82
112
  setAccountInfo(null);
83
113
  setAccountInfoError(null);
84
114
  setLocalRecoveryEmails([]);
115
+ setRecoveryEmailRecords([]);
116
+ setRecoveryEmailInput("");
117
+ setRecoveryEmailMatchStatus("empty");
85
118
  setExplorerToast(null);
86
119
  if (mailtoAttemptTimerRef.current != null) {
87
120
  window.clearTimeout(mailtoAttemptTimerRef.current);
@@ -105,14 +138,16 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
105
138
  const safeSetAccountInfoLoading = React.useMemo(() => safeSet(setAccountInfoLoading), []);
106
139
  const safeSetAccountInfoError = React.useMemo(() => safeSet(setAccountInfoError), []);
107
140
  const safeSetLocalRecoveryEmails = React.useMemo(() => safeSet(setLocalRecoveryEmails), []);
141
+ const safeSetRecoveryEmailRecords = React.useMemo(() => safeSet(setRecoveryEmailRecords), []);
142
+ const safeSetRecoveryEmailMatchStatus = React.useMemo(() => safeSet(setRecoveryEmailMatchStatus), []);
108
143
  const safeSetExplorerToast = React.useMemo(() => safeSet(setExplorerToast), []);
109
144
  const safeSetMailtoUiState = React.useMemo(() => safeSet(setMailtoUiState), []);
110
145
  const onEvent = React.useCallback((ev) => {
111
146
  if (cancelRequestedRef.current) return;
112
147
  safeSetStatusText(ev?.message || null);
113
148
  emailRecoveryOptions?.onEvent?.(ev);
114
- const data = ev?.data || {};
115
- const rawTxHash = data?.transactionHash ?? data?.transaction_hash;
149
+ const data = "data" in ev ? asRecord(ev.data) : null;
150
+ const rawTxHash = data?.["transactionHash"] ?? data?.["transaction_hash"];
116
151
  const txHash = typeof rawTxHash === "string" ? rawTxHash.trim() : "";
117
152
  if (txHash) {
118
153
  const base = String(tatchiPasskey.configs?.nearExplorerUrl || "https://testnet.nearblocks.io").replace(/\/$/, "");
@@ -122,13 +157,13 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
122
157
  transactionHash: txHash
123
158
  });
124
159
  }
125
- const elapsedRaw = data?.elapsedMs ?? data?.elapsed_ms;
160
+ const elapsedRaw = data?.["elapsedMs"] ?? data?.["elapsed_ms"];
126
161
  if (elapsedRaw == null) safeSetPollingElapsedMs(null);
127
162
  const elapsed = elapsedRaw == null ? NaN : Number(elapsedRaw);
128
163
  if (!Number.isNaN(elapsed)) safeSetPollingElapsedMs(elapsed);
129
- if (ev?.phase === "email-recovery-error" || ev?.status === "error") {
130
- const raw = ev?.error || ev?.message || "Email recovery failed";
131
- safeSetErrorText(String(raw));
164
+ if (ev.phase === EmailRecoveryPhase.ERROR || ev.status === EmailRecoveryStatus.ERROR) {
165
+ const raw = "error" in ev ? ev.error : ev.message;
166
+ safeSetErrorText(raw || "Email recovery failed");
132
167
  safeSetCanRestart(false);
133
168
  }
134
169
  }, [
@@ -150,6 +185,16 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
150
185
  accountId: normalized
151
186
  });
152
187
  }, [safeSetExplorerToast, tatchiPasskey]);
188
+ const showExplorerTxToast = React.useCallback((txHash) => {
189
+ const normalized = (txHash || "").trim();
190
+ if (!normalized) return;
191
+ const base = String(tatchiPasskey.configs?.nearExplorerUrl || "https://testnet.nearblocks.io").replace(/\/$/, "");
192
+ const url = base.includes("nearblocks.io") ? `${base}/txns/${normalized}` : `${base}/transactions/${normalized}`;
193
+ safeSetExplorerToast({
194
+ url,
195
+ transactionHash: normalized
196
+ });
197
+ }, [safeSetExplorerToast, tatchiPasskey]);
153
198
  const launchMailto = React.useCallback((rawMailtoUrl) => {
154
199
  const url = String(rawMailtoUrl || "").trim();
155
200
  if (!url) return;
@@ -195,40 +240,9 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
195
240
  document.removeEventListener("visibilitychange", onVisibilityChange);
196
241
  };
197
242
  }, [mailtoUiState, safeSetMailtoUiState]);
198
- const fetchLocalRecoveryEmailsFromIndexedDB = React.useCallback(async (rawAccountId) => {
199
- const normalized = (rawAccountId || "").trim();
200
- if (!normalized) {
201
- console.log("[EmailRecoverySlide] fetchLocalRecoveryEmails: empty accountId");
202
- return [];
203
- }
204
- try {
205
- console.log("[EmailRecoverySlide] fetchLocalRecoveryEmails: loading from IndexedDB", { accountId: normalized });
206
- const records = await IndexedDBManager.getRecoveryEmails(toAccountId(normalized));
207
- console.log("[EmailRecoverySlide] fetchLocalRecoveryEmails: raw IndexedDB records", {
208
- accountId: normalized,
209
- count: Array.isArray(records) ? records.length : 0,
210
- records
211
- });
212
- if (!Array.isArray(records) || records.length === 0) return [];
213
- const sorted = [...records].sort((a, b) => (b?.addedAt || 0) - (a?.addedAt || 0));
214
- const emails = sorted.map((r) => String(r?.email || "").trim().toLowerCase()).filter((e) => !!e && e.includes("@"));
215
- const uniq = Array.from(new Set(emails));
216
- console.log("[EmailRecoverySlide] fetchLocalRecoveryEmails: parsed emails", {
217
- accountId: normalized,
218
- emails: uniq
219
- });
220
- return uniq;
221
- } catch (err) {
222
- console.log("[EmailRecoverySlide] fetchLocalRecoveryEmails: failed to read IndexedDB", {
223
- accountId: normalized,
224
- error: err instanceof Error ? err.message : String(err)
225
- });
226
- return [];
227
- }
228
- }, []);
229
243
  const deriveEmailsFromRecoveryRecords = React.useCallback((records) => {
230
- if (!Array.isArray(records) || records.length === 0) return [];
231
- const emails = records.map((r) => String(r?.email || "").trim().toLowerCase()).filter((e) => !!e && e.includes("@"));
244
+ if (records.length === 0) return [];
245
+ const emails = records.map((r) => r.email.trim().toLowerCase()).filter((e) => e.length > 0 && e.includes("@"));
232
246
  return Array.from(new Set(emails));
233
247
  }, []);
234
248
  React.useEffect(() => {
@@ -246,27 +260,11 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
246
260
  const handle = window.setTimeout(() => {
247
261
  (async () => {
248
262
  try {
249
- const isWalletIframeMode = !!tatchiPasskey.configs?.iframeWallet?.walletOrigin;
250
- let localEmails = [];
251
- if (!isWalletIframeMode) {
252
- localEmails = await fetchLocalRecoveryEmailsFromIndexedDB(normalized);
253
- if (!cancelled) console.log("[EmailRecoverySlide] local saved emails (IndexedDB)", {
254
- accountId: normalized,
255
- localEmails
256
- });
257
- }
258
263
  const records = await tatchiPasskey.getRecoveryEmails(normalized);
259
- const resolvedEmails = isWalletIframeMode ? deriveEmailsFromRecoveryRecords(records) : localEmails;
264
+ const resolvedEmails = deriveEmailsFromRecoveryRecords(records);
260
265
  if (!cancelled) {
261
266
  safeSetLocalRecoveryEmails(resolvedEmails);
262
- console.log("[EmailRecoverySlide] recovery email suggestions (state)", {
263
- accountId: normalized,
264
- emails: resolvedEmails
265
- });
266
- if (resolvedEmails.length === 1 && (recoveryEmailInput.trim() === "" || recoveryEmailInput === lastPrefilledRecoveryEmailRef.current)) {
267
- lastPrefilledRecoveryEmailRef.current = resolvedEmails[0];
268
- setRecoveryEmailInput(resolvedEmails[0]);
269
- }
267
+ safeSetRecoveryEmailRecords(records);
270
268
  }
271
269
  const info = records ? { emailsCount: Array.isArray(records) ? records.length : 0 } : null;
272
270
  if (cancelled) return;
@@ -274,7 +272,10 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
274
272
  } catch (err) {
275
273
  if (cancelled) return;
276
274
  safeSetAccountInfo(null);
277
- safeSetAccountInfoError(err?.message || "Failed to load email recovery settings for this account");
275
+ const msg = err instanceof Error ? err.message : "";
276
+ safeSetAccountInfoError(msg || "Failed to load email recovery settings for this account");
277
+ safeSetLocalRecoveryEmails([]);
278
+ safeSetRecoveryEmailRecords([]);
278
279
  } finally {
279
280
  if (!cancelled) safeSetAccountInfoLoading(false);
280
281
  }
@@ -287,25 +288,100 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
287
288
  }, [
288
289
  accountIdInput,
289
290
  deriveEmailsFromRecoveryRecords,
290
- fetchLocalRecoveryEmailsFromIndexedDB,
291
- recoveryEmailInput,
292
291
  safeSetAccountInfo,
293
292
  safeSetAccountInfoError,
294
293
  safeSetAccountInfoLoading,
295
294
  safeSetLocalRecoveryEmails,
295
+ safeSetRecoveryEmailRecords,
296
296
  tatchiPasskey
297
297
  ]);
298
+ const recoveryEmailConfirmationRequired = !accountInfoLoading && !accountInfoError && !!accountInfo && accountInfo.emailsCount > 0 && localRecoveryEmails.length === 0;
299
+ React.useEffect(() => {
300
+ const normalizedAccountId = (accountIdInput || "").trim();
301
+ const rawEmail = (recoveryEmailInput || "").trim();
302
+ if (!rawEmail || !normalizedAccountId) {
303
+ safeSetRecoveryEmailMatchStatus("empty");
304
+ return;
305
+ }
306
+ if (!Array.isArray(recoveryEmailRecords) || recoveryEmailRecords.length === 0) {
307
+ safeSetRecoveryEmailMatchStatus("checking");
308
+ return;
309
+ }
310
+ let cancelled = false;
311
+ safeSetRecoveryEmailMatchStatus("checking");
312
+ const handle = window.setTimeout(() => {
313
+ (async () => {
314
+ try {
315
+ const hashHex = await hashRecoveryEmailForAccountHex({
316
+ recoveryEmail: rawEmail,
317
+ accountId: normalizedAccountId
318
+ });
319
+ if (cancelled) return;
320
+ if (!hashHex) {
321
+ safeSetRecoveryEmailMatchStatus("invalid");
322
+ return;
323
+ }
324
+ const normalizedHashHex = hashHex.toLowerCase();
325
+ const matches = recoveryEmailRecords.some((rec) => String(rec.hashHex || "").toLowerCase() === normalizedHashHex);
326
+ safeSetRecoveryEmailMatchStatus(matches ? "match" : "mismatch");
327
+ } catch {
328
+ if (!cancelled) safeSetRecoveryEmailMatchStatus("invalid");
329
+ }
330
+ })();
331
+ }, 250);
332
+ return () => {
333
+ cancelled = true;
334
+ window.clearTimeout(handle);
335
+ };
336
+ }, [
337
+ accountIdInput,
338
+ recoveryEmailInput,
339
+ recoveryEmailRecords,
340
+ safeSetRecoveryEmailMatchStatus
341
+ ]);
298
342
  const handleStart = React.useCallback(async () => {
299
343
  const normalizedAccountId = (accountIdInput || "").trim();
300
344
  if (!normalizedAccountId) {
301
345
  safeSetErrorText("Enter an account ID.");
302
346
  return;
303
347
  }
304
- const emailCandidate = (recoveryEmailInput || "").trim().toLowerCase();
305
- if (!emailCandidate) {
306
- safeSetErrorText("Enter the recovery email to send from.");
348
+ if (accountInfoLoading) {
349
+ safeSetErrorText("Checking recovery email settings…");
307
350
  return;
308
351
  }
352
+ if (accountInfoError) {
353
+ safeSetErrorText(accountInfoError);
354
+ return;
355
+ }
356
+ if (!accountInfo) {
357
+ safeSetErrorText("Failed to load email recovery settings for this account.");
358
+ return;
359
+ }
360
+ if (accountInfo.emailsCount === 0) {
361
+ safeSetErrorText("No recovery emails are configured for this account.");
362
+ return;
363
+ }
364
+ const recoveryEmail = recoveryEmailInput.trim();
365
+ if (recoveryEmailConfirmationRequired) {
366
+ if (!recoveryEmail) {
367
+ safeSetErrorText("Enter the recovery email address you will send from.");
368
+ return;
369
+ }
370
+ const hashHex = await hashRecoveryEmailForAccountHex({
371
+ recoveryEmail,
372
+ accountId: normalizedAccountId
373
+ }).catch(() => null);
374
+ if (!hashHex) {
375
+ safeSetErrorText("Enter a valid recovery email address.");
376
+ return;
377
+ }
378
+ const normalizedHashHex = hashHex.toLowerCase();
379
+ const matches = recoveryEmailRecords.some((rec) => String(rec.hashHex || "").toLowerCase() === normalizedHashHex);
380
+ if (!matches) {
381
+ safeSetErrorText("That email is not configured for recovery on this account. Please use your configured recovery email address.");
382
+ return;
383
+ }
384
+ }
309
385
  safeSetIsBusy(true);
310
386
  cancelRequestedRef.current = false;
311
387
  safeSetErrorText(null);
@@ -319,7 +395,7 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
319
395
  try {
320
396
  const result = await tatchiPasskey.startEmailRecovery({
321
397
  accountId: normalizedAccountId,
322
- recoveryEmail: emailCandidate,
398
+ ...recoveryEmail ? { recoveryEmail } : {},
323
399
  options: {
324
400
  onEvent,
325
401
  onError: (err) => {
@@ -327,8 +403,7 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
327
403
  safeSetErrorText(err?.message || "Failed to start email recovery");
328
404
  didForwardError = true;
329
405
  emailRecoveryOptions?.onError?.(err);
330
- },
331
- afterCall: async () => {}
406
+ }
332
407
  }
333
408
  });
334
409
  safeSetPendingMailtoUrl(result.mailtoUrl);
@@ -345,10 +420,11 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
345
420
  const uiError = getEmailRecoveryUiError(err);
346
421
  safeSetErrorText(uiError.message || "Failed to finalize email recovery");
347
422
  safeSetCanRestart(uiError.canRestart);
423
+ const txHash = getEmailRecoveryErrorTxHash(err);
424
+ if (txHash) showExplorerTxToast(txHash);
348
425
  didForwardError = true;
349
426
  emailRecoveryOptions?.onError?.(err);
350
- },
351
- afterCall: async () => {}
427
+ }
352
428
  }
353
429
  });
354
430
  showExplorerToast(normalizedAccountId);
@@ -379,6 +455,8 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
379
455
  const uiError = getEmailRecoveryUiError(err);
380
456
  safeSetErrorText(uiError.message || "Failed to start email recovery");
381
457
  safeSetCanRestart(uiError.canRestart);
458
+ const txHash = getEmailRecoveryErrorTxHash(err);
459
+ if (txHash) showExplorerTxToast(txHash);
382
460
  if (!didForwardError && err instanceof Error) emailRecoveryOptions?.onError?.(err);
383
461
  } finally {
384
462
  safeSetIsBusy(false);
@@ -386,9 +464,14 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
386
464
  }, [
387
465
  accountIdInput,
388
466
  emailRecoveryOptions,
389
- recoveryEmailInput,
390
467
  onEvent,
391
468
  refreshLoginState,
469
+ accountInfo,
470
+ accountInfoError,
471
+ accountInfoLoading,
472
+ recoveryEmailConfirmationRequired,
473
+ recoveryEmailInput,
474
+ recoveryEmailRecords,
392
475
  showExplorerToast,
393
476
  safeSetErrorText,
394
477
  safeSetIsBusy,
@@ -397,6 +480,7 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
397
480
  safeSetStatusText,
398
481
  safeSetMailtoUiState,
399
482
  attemptOpenMailtoAuto,
483
+ showExplorerTxToast,
400
484
  tatchiPasskey
401
485
  ]);
402
486
  const handleRestart = React.useCallback(async () => {
@@ -433,8 +517,27 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
433
517
  safeSetStatusText,
434
518
  tatchiPasskey
435
519
  ]);
436
- const summaryLine = accountInfoLoading ? "Checking if account has recovery emails configured..." : accountInfo && !accountInfoError ? `Recovery emails configured: ${accountInfo.emailsCount}` : "\xA0";
520
+ const summaryLine = accountInfoLoading ? /* @__PURE__ */ jsxs(Fragment, { children: ["Checking if account has recovery emails configured", /* @__PURE__ */ jsxs("span", {
521
+ className: "w3a-ellipsis",
522
+ "aria-hidden": "true",
523
+ children: [
524
+ /* @__PURE__ */ jsx("span", {
525
+ className: "w3a-ellipsis-dot",
526
+ children: "."
527
+ }),
528
+ /* @__PURE__ */ jsx("span", {
529
+ className: "w3a-ellipsis-dot",
530
+ children: "."
531
+ }),
532
+ /* @__PURE__ */ jsx("span", {
533
+ className: "w3a-ellipsis-dot",
534
+ children: "."
535
+ })
536
+ ]
537
+ })] }) : accountInfo && !accountInfoError ? `Recovery emails configured: ${accountInfo.emailsCount}` : "\xA0";
437
538
  const noRecoveryEmailsConfigured = !accountInfoLoading && !accountInfoError && !!accountInfo && accountInfo.emailsCount === 0;
539
+ const disableStartForRecoveryEmailMismatch = recoveryEmailConfirmationRequired && (recoveryEmailMatchStatus === "empty" || recoveryEmailMatchStatus === "checking" || recoveryEmailMatchStatus === "invalid" || recoveryEmailMatchStatus === "mismatch");
540
+ const startDisabled = isBusy || accountInfoLoading || !!accountInfoError || !accountInfo || noRecoveryEmailsConfigured || disableStartForRecoveryEmailMismatch;
438
541
  return /* @__PURE__ */ jsxs("div", {
439
542
  className: "w3a-email-recovery-slide",
440
543
  children: [
@@ -444,73 +547,84 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
444
547
  }),
445
548
  /* @__PURE__ */ jsx("div", {
446
549
  className: "w3a-email-recovery-help",
447
- children: "Send a recovery email from your registered email address. Your account will be recovered with a new key once the email is verified."
550
+ children: "Send a special email to recover your account. This email must be sent from the designated email recovery address."
448
551
  }),
449
- /* @__PURE__ */ jsx("div", {
450
- className: "w3a-email-recovery-field",
552
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("div", {
553
+ className: "w3a-input-pill w3a-email-recovery-input-pill",
451
554
  children: /* @__PURE__ */ jsx("div", {
452
- className: "w3a-input-pill w3a-email-recovery-input-pill",
453
- children: /* @__PURE__ */ jsx("div", {
454
- className: "w3a-input-wrap",
455
- children: /* @__PURE__ */ jsx("input", {
456
- type: "text",
457
- value: accountIdInput,
458
- onChange: (e) => setAccountIdInput(e.target.value),
459
- placeholder: "NEAR account ID (e.g. alice.testnet)",
460
- className: "w3a-input",
461
- autoCapitalize: "none",
462
- autoCorrect: "off",
463
- spellCheck: false,
464
- inputMode: "text",
465
- disabled: isBusy
466
- })
555
+ className: "w3a-input-wrap",
556
+ children: /* @__PURE__ */ jsx("input", {
557
+ type: "text",
558
+ value: accountIdInput,
559
+ onChange: (e) => setAccountIdInput(e.target.value),
560
+ placeholder: "NEAR account ID (e.g. alice.testnet)",
561
+ className: "w3a-input",
562
+ autoCapitalize: "none",
563
+ autoCorrect: "off",
564
+ spellCheck: false,
565
+ inputMode: "text",
566
+ disabled: isBusy
467
567
  })
468
568
  })
469
- }),
470
- /* @__PURE__ */ jsx("div", {
569
+ }) }),
570
+ /* @__PURE__ */ jsxs("div", {
471
571
  className: "w3a-email-recovery-summary",
472
572
  "aria-live": "polite",
473
- children: /* @__PURE__ */ jsx("div", { children: summaryLine })
474
- }),
475
- /* @__PURE__ */ jsx("div", {
476
- className: "w3a-email-recovery-field",
477
- children: /* @__PURE__ */ jsx("div", {
478
- className: "w3a-input-pill w3a-email-recovery-input-pill",
479
- children: /* @__PURE__ */ jsx("div", {
480
- className: "w3a-input-wrap",
481
- children: /* @__PURE__ */ jsx("input", {
482
- type: "email",
483
- value: recoveryEmailInput,
484
- onChange: (e) => setRecoveryEmailInput(e.target.value),
485
- placeholder: "Recovery email to send from",
486
- className: "w3a-input",
487
- list: localRecoveryEmails.length > 0 ? "w3a-email-recovery-saved-emails" : void 0,
488
- autoCapitalize: "none",
489
- autoCorrect: "off",
490
- spellCheck: false,
491
- inputMode: "email",
492
- disabled: isBusy || noRecoveryEmailsConfigured
493
- })
573
+ children: [
574
+ /* @__PURE__ */ jsx("div", { children: summaryLine }),
575
+ !!accountInfoError && /* @__PURE__ */ jsx("div", {
576
+ className: "w3a-email-recovery-warning",
577
+ children: accountInfoError
578
+ }),
579
+ localRecoveryEmails.length > 0 && /* @__PURE__ */ jsx("div", {
580
+ className: "w3a-email-recovery-saved-emails",
581
+ role: "list",
582
+ "aria-label": "Recovery emails",
583
+ children: localRecoveryEmails.map((email) => /* @__PURE__ */ jsx("span", {
584
+ className: "w3a-email-recovery-email-chip w3a-email-recovery-email-chip-static",
585
+ role: "listitem",
586
+ children: email
587
+ }, email))
588
+ }),
589
+ recoveryEmailConfirmationRequired && /* @__PURE__ */ jsxs(Fragment, { children: [
590
+ /* @__PURE__ */ jsx("div", {
591
+ className: "w3a-email-recovery-warning",
592
+ children: "This device can’t display your configured recovery email address. Enter the email you will send from to confirm it matches what’s configured for this account."
593
+ }),
594
+ /* @__PURE__ */ jsx("div", {
595
+ className: "w3a-input-pill w3a-email-recovery-input-pill",
596
+ children: /* @__PURE__ */ jsx("div", {
597
+ className: "w3a-input-wrap",
598
+ children: /* @__PURE__ */ jsx("input", {
599
+ type: "email",
600
+ value: recoveryEmailInput,
601
+ onChange: (e) => setRecoveryEmailInput(e.target.value),
602
+ placeholder: "Recovery email address (sender)",
603
+ className: "w3a-input",
604
+ autoCapitalize: "none",
605
+ autoCorrect: "off",
606
+ spellCheck: false,
607
+ inputMode: "email",
608
+ disabled: isBusy
609
+ })
610
+ })
611
+ }),
612
+ recoveryEmailMatchStatus === "checking" && /* @__PURE__ */ jsx("div", { children: "Checking recovery email…" }),
613
+ recoveryEmailMatchStatus === "invalid" && /* @__PURE__ */ jsx("div", {
614
+ className: "w3a-email-recovery-warning",
615
+ children: "Enter a valid email address."
616
+ }),
617
+ recoveryEmailMatchStatus === "mismatch" && /* @__PURE__ */ jsx("div", {
618
+ className: "w3a-email-recovery-warning",
619
+ children: "That email is not configured for recovery on this account."
620
+ }),
621
+ recoveryEmailMatchStatus === "match" && /* @__PURE__ */ jsx("div", { children: "Recovery email verified for this account." })
622
+ ] }),
623
+ !!accountIdInput.trim() && !noRecoveryEmailsConfigured && /* @__PURE__ */ jsx("div", {
624
+ className: "w3a-email-recovery-from-warning",
625
+ children: recoveryEmailInput.trim() ? `Check that you are sending the recovery email from ${recoveryEmailInput.trim()}.` : "Check that you are sending the recovery email from your designated recovery email."
494
626
  })
495
- })
496
- }),
497
- localRecoveryEmails.length > 0 && /* @__PURE__ */ jsxs("div", {
498
- className: "w3a-email-recovery-summary",
499
- "aria-live": "polite",
500
- children: [/* @__PURE__ */ jsx("div", { children: "Saved on this device:" }), /* @__PURE__ */ jsx("div", {
501
- className: "w3a-email-recovery-saved-emails",
502
- children: localRecoveryEmails.map((email) => /* @__PURE__ */ jsx("button", {
503
- type: "button",
504
- className: "w3a-email-recovery-email-chip",
505
- onClick: () => setRecoveryEmailInput(email),
506
- disabled: isBusy,
507
- children: email
508
- }, email))
509
- })]
510
- }),
511
- localRecoveryEmails.length > 0 && /* @__PURE__ */ jsx("datalist", {
512
- id: "w3a-email-recovery-saved-emails",
513
- children: localRecoveryEmails.map((email) => /* @__PURE__ */ jsx("option", { value: email }, email))
627
+ ]
514
628
  }),
515
629
  /* @__PURE__ */ jsxs("div", {
516
630
  className: "w3a-email-recovery-actions",
@@ -518,8 +632,8 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
518
632
  (!pendingMailtoUrl || !isBusy) && /* @__PURE__ */ jsx("button", {
519
633
  onClick: handleStart,
520
634
  className: "w3a-link-device-btn w3a-link-device-btn-primary",
521
- disabled: isBusy || noRecoveryEmailsConfigured,
522
- children: noRecoveryEmailsConfigured ? "No recovery emails configured" : isBusy ? "Working…" : "Start Email Recovery"
635
+ disabled: startDisabled,
636
+ children: accountInfoLoading ? "Checking recovery emails…" : noRecoveryEmailsConfigured ? "No recovery emails configured" : disableStartForRecoveryEmailMismatch ? "Confirm recovery email" : isBusy ? "Working…" : "Start Email Recovery"
523
637
  }),
524
638
  pendingMailtoUrl && /* @__PURE__ */ jsxs("button", {
525
639
  type: "button",
@@ -553,13 +667,13 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
553
667
  "s)."
554
668
  ]
555
669
  }),
556
- explorerToast && /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx("a", {
670
+ explorerToast && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("br", {}), /* @__PURE__ */ jsx("a", {
557
671
  className: "w3a-email-recovery-link",
558
672
  href: explorerToast.url,
559
673
  target: "_blank",
560
674
  rel: "noopener noreferrer",
561
675
  children: "View on explorer"
562
- }) })
676
+ })] })
563
677
  ]
564
678
  })
565
679
  ]