@tatchi-xyz/sdk 0.19.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 (243) hide show
  1. package/dist/cjs/core/EmailRecovery/index.js +25 -0
  2. package/dist/cjs/core/EmailRecovery/index.js.map +1 -1
  3. package/dist/cjs/core/TatchiPasskey/emailRecovery.js +135 -77
  4. package/dist/cjs/core/TatchiPasskey/emailRecovery.js.map +1 -1
  5. package/dist/cjs/core/TatchiPasskey/index.js +2 -1
  6. package/dist/cjs/core/TatchiPasskey/index.js.map +1 -1
  7. package/dist/cjs/core/TatchiPasskey/linkDevice.js +2 -1
  8. package/dist/cjs/core/TatchiPasskey/linkDevice.js.map +1 -1
  9. package/dist/cjs/core/TatchiPasskey/scanDevice.js +5 -3
  10. package/dist/cjs/core/TatchiPasskey/scanDevice.js.map +1 -1
  11. package/dist/cjs/core/WalletIframe/client/router.js +1 -1
  12. package/dist/cjs/core/WalletIframe/client/router.js.map +1 -1
  13. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +3 -4
  14. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  15. package/dist/cjs/core/defaultConfigs.js +3 -7
  16. package/dist/cjs/core/defaultConfigs.js.map +1 -1
  17. package/dist/cjs/core/nearCrypto.js +29 -5
  18. package/dist/cjs/core/nearCrypto.js.map +1 -1
  19. package/dist/cjs/core/rpcCalls.js +56 -26
  20. package/dist/cjs/core/rpcCalls.js.map +1 -1
  21. package/dist/cjs/core/types/emailRecovery.js +33 -0
  22. package/dist/cjs/core/types/emailRecovery.js.map +1 -0
  23. package/dist/cjs/index.js +4 -0
  24. package/dist/cjs/index.js.map +1 -1
  25. package/dist/cjs/react/components/AccountMenuButton/{LinkedDevicesModal-CSSowiHP.css → LinkedDevicesModal-BRtht0XI.css} +1 -1
  26. package/dist/{esm/react/components/AccountMenuButton/LinkedDevicesModal-CSSowiHP.css.map → cjs/react/components/AccountMenuButton/LinkedDevicesModal-BRtht0XI.css.map} +1 -1
  27. package/dist/cjs/react/components/AccountMenuButton/{ProfileDropdown-CEPMZ1gY.css → ProfileDropdown-BG_6hcim.css} +1 -1
  28. package/dist/{esm/react/components/AccountMenuButton/ProfileDropdown-CEPMZ1gY.css.map → cjs/react/components/AccountMenuButton/ProfileDropdown-BG_6hcim.css.map} +1 -1
  29. package/dist/cjs/react/components/AccountMenuButton/{Web3AuthProfileButton-DopOg7Xc.css → Web3AuthProfileButton-k8_FAYFq.css} +1 -1
  30. package/dist/cjs/react/components/AccountMenuButton/{Web3AuthProfileButton-DopOg7Xc.css.map → Web3AuthProfileButton-k8_FAYFq.css.map} +1 -1
  31. package/dist/cjs/react/components/AccountMenuButton/icons/{TouchIcon-BQWentvJ.css → TouchIcon-C-RcGfr5.css} +1 -1
  32. package/dist/cjs/react/components/AccountMenuButton/icons/{TouchIcon-BQWentvJ.css.map → TouchIcon-C-RcGfr5.css.map} +1 -1
  33. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-DwrzWMYx.css → PasskeyAuthMenu-DKMiLeT9.css} +59 -4
  34. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-DwrzWMYx.css.map → PasskeyAuthMenu-DKMiLeT9.css.map} +1 -1
  35. package/dist/cjs/react/components/PasskeyAuthMenu/adapters/tatchi.js +1 -0
  36. package/dist/cjs/react/components/PasskeyAuthMenu/adapters/tatchi.js.map +1 -1
  37. package/dist/cjs/react/components/PasskeyAuthMenu/client.js +30 -8
  38. package/dist/cjs/react/components/PasskeyAuthMenu/client.js.map +1 -1
  39. package/dist/cjs/react/components/PasskeyAuthMenu/controller/useSDKEvents.js +22 -0
  40. package/dist/cjs/react/components/PasskeyAuthMenu/controller/useSDKEvents.js.map +1 -0
  41. package/dist/cjs/react/components/PasskeyAuthMenu/ui/ContentSwitcher.js +17 -4
  42. package/dist/cjs/react/components/PasskeyAuthMenu/ui/ContentSwitcher.js.map +1 -1
  43. package/dist/cjs/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js +354 -154
  44. package/dist/cjs/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js.map +1 -1
  45. package/dist/cjs/react/components/{ShowQRCode-CCN4h6Uv.css → ShowQRCode-CB0UCQ_h.css} +1 -1
  46. package/dist/cjs/react/components/{ShowQRCode-CCN4h6Uv.css.map → ShowQRCode-CB0UCQ_h.css.map} +1 -1
  47. package/dist/cjs/react/context/useSDKFlowRuntime.js +183 -0
  48. package/dist/cjs/react/context/useSDKFlowRuntime.js.map +1 -0
  49. package/dist/cjs/react/context/useTatchiContextValue.js +24 -15
  50. package/dist/cjs/react/context/useTatchiContextValue.js.map +1 -1
  51. package/dist/cjs/react/context/useTatchiWithSdkFlow.js +96 -0
  52. package/dist/cjs/react/context/useTatchiWithSdkFlow.js.map +1 -0
  53. package/dist/cjs/react/sdk/src/core/EmailRecovery/index.js +26 -0
  54. package/dist/cjs/react/sdk/src/core/EmailRecovery/index.js.map +1 -1
  55. package/dist/cjs/react/sdk/src/core/TatchiPasskey/emailRecovery.js +135 -77
  56. package/dist/cjs/react/sdk/src/core/TatchiPasskey/emailRecovery.js.map +1 -1
  57. package/dist/cjs/react/sdk/src/core/TatchiPasskey/index.js +2 -1
  58. package/dist/cjs/react/sdk/src/core/TatchiPasskey/index.js.map +1 -1
  59. package/dist/cjs/react/sdk/src/core/TatchiPasskey/linkDevice.js +2 -1
  60. package/dist/cjs/react/sdk/src/core/TatchiPasskey/linkDevice.js.map +1 -1
  61. package/dist/cjs/react/sdk/src/core/TatchiPasskey/scanDevice.js +5 -3
  62. package/dist/cjs/react/sdk/src/core/TatchiPasskey/scanDevice.js.map +1 -1
  63. package/dist/cjs/react/sdk/src/core/WalletIframe/client/router.js +1 -1
  64. package/dist/cjs/react/sdk/src/core/WalletIframe/client/router.js.map +1 -1
  65. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +3 -4
  66. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  67. package/dist/cjs/react/sdk/src/core/defaultConfigs.js +3 -7
  68. package/dist/cjs/react/sdk/src/core/defaultConfigs.js.map +1 -1
  69. package/dist/cjs/react/sdk/src/core/nearCrypto.js +29 -5
  70. package/dist/cjs/react/sdk/src/core/nearCrypto.js.map +1 -1
  71. package/dist/cjs/react/sdk/src/core/rpcCalls.js +56 -26
  72. package/dist/cjs/react/sdk/src/core/rpcCalls.js.map +1 -1
  73. package/dist/cjs/react/sdk/src/core/types/emailRecovery.js +33 -0
  74. package/dist/cjs/react/sdk/src/core/types/emailRecovery.js.map +1 -0
  75. package/dist/cjs/server/email-recovery/emailParsers.js +2 -1
  76. package/dist/cjs/server/email-recovery/emailParsers.js.map +1 -1
  77. package/dist/cjs/server/email-recovery/index.js +6 -6
  78. package/dist/cjs/server/email-recovery/index.js.map +1 -1
  79. package/dist/cjs/server/email-recovery/rpcCalls.js +22 -3
  80. package/dist/cjs/server/email-recovery/rpcCalls.js.map +1 -1
  81. package/dist/cjs/server/router/cloudflare.js +8 -3
  82. package/dist/cjs/server/router/cloudflare.js.map +1 -1
  83. package/dist/cjs/server/router/express.js.map +1 -1
  84. package/dist/cjs/server/sdk/src/core/defaultConfigs.js +2 -4
  85. package/dist/cjs/server/sdk/src/core/defaultConfigs.js.map +1 -1
  86. package/dist/cjs/server/sdk/src/core/nearCrypto.js +26 -7
  87. package/dist/cjs/server/sdk/src/core/nearCrypto.js.map +1 -1
  88. package/dist/esm/core/EmailRecovery/index.js +25 -1
  89. package/dist/esm/core/EmailRecovery/index.js.map +1 -1
  90. package/dist/esm/core/TatchiPasskey/emailRecovery.js +136 -78
  91. package/dist/esm/core/TatchiPasskey/emailRecovery.js.map +1 -1
  92. package/dist/esm/core/TatchiPasskey/index.js +2 -1
  93. package/dist/esm/core/TatchiPasskey/index.js.map +1 -1
  94. package/dist/esm/core/TatchiPasskey/linkDevice.js +2 -1
  95. package/dist/esm/core/TatchiPasskey/linkDevice.js.map +1 -1
  96. package/dist/esm/core/TatchiPasskey/scanDevice.js +5 -3
  97. package/dist/esm/core/TatchiPasskey/scanDevice.js.map +1 -1
  98. package/dist/esm/core/WalletIframe/client/router.js +1 -1
  99. package/dist/esm/core/WalletIframe/client/router.js.map +1 -1
  100. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +2 -3
  101. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  102. package/dist/esm/core/defaultConfigs.js +3 -7
  103. package/dist/esm/core/defaultConfigs.js.map +1 -1
  104. package/dist/esm/core/nearCrypto.js +24 -6
  105. package/dist/esm/core/nearCrypto.js.map +1 -1
  106. package/dist/esm/core/rpcCalls.js +56 -26
  107. package/dist/esm/core/rpcCalls.js.map +1 -1
  108. package/dist/esm/core/types/emailRecovery.js +26 -0
  109. package/dist/esm/core/types/emailRecovery.js.map +1 -0
  110. package/dist/esm/index.js +3 -1
  111. package/dist/esm/index.js.map +1 -1
  112. package/dist/esm/react/components/AccountMenuButton/{LinkedDevicesModal-CSSowiHP.css → LinkedDevicesModal-BRtht0XI.css} +1 -1
  113. package/dist/{cjs/react/components/AccountMenuButton/LinkedDevicesModal-CSSowiHP.css.map → esm/react/components/AccountMenuButton/LinkedDevicesModal-BRtht0XI.css.map} +1 -1
  114. package/dist/esm/react/components/AccountMenuButton/{ProfileDropdown-CEPMZ1gY.css → ProfileDropdown-BG_6hcim.css} +1 -1
  115. package/dist/{cjs/react/components/AccountMenuButton/ProfileDropdown-CEPMZ1gY.css.map → esm/react/components/AccountMenuButton/ProfileDropdown-BG_6hcim.css.map} +1 -1
  116. package/dist/esm/react/components/AccountMenuButton/{Web3AuthProfileButton-DopOg7Xc.css → Web3AuthProfileButton-k8_FAYFq.css} +1 -1
  117. package/dist/esm/react/components/AccountMenuButton/{Web3AuthProfileButton-DopOg7Xc.css.map → Web3AuthProfileButton-k8_FAYFq.css.map} +1 -1
  118. package/dist/esm/react/components/AccountMenuButton/icons/{TouchIcon-BQWentvJ.css → TouchIcon-C-RcGfr5.css} +1 -1
  119. package/dist/esm/react/components/AccountMenuButton/icons/{TouchIcon-BQWentvJ.css.map → TouchIcon-C-RcGfr5.css.map} +1 -1
  120. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-DwrzWMYx.css → PasskeyAuthMenu-DKMiLeT9.css} +59 -4
  121. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-DwrzWMYx.css.map → PasskeyAuthMenu-DKMiLeT9.css.map} +1 -1
  122. package/dist/esm/react/components/PasskeyAuthMenu/adapters/tatchi.js +1 -0
  123. package/dist/esm/react/components/PasskeyAuthMenu/adapters/tatchi.js.map +1 -1
  124. package/dist/esm/react/components/PasskeyAuthMenu/client.js +30 -8
  125. package/dist/esm/react/components/PasskeyAuthMenu/client.js.map +1 -1
  126. package/dist/esm/react/components/PasskeyAuthMenu/controller/useSDKEvents.js +20 -0
  127. package/dist/esm/react/components/PasskeyAuthMenu/controller/useSDKEvents.js.map +1 -0
  128. package/dist/esm/react/components/PasskeyAuthMenu/ui/ContentSwitcher.js +17 -4
  129. package/dist/esm/react/components/PasskeyAuthMenu/ui/ContentSwitcher.js.map +1 -1
  130. package/dist/esm/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js +354 -154
  131. package/dist/esm/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js.map +1 -1
  132. package/dist/esm/react/components/{ShowQRCode-CCN4h6Uv.css → ShowQRCode-CB0UCQ_h.css} +1 -1
  133. package/dist/esm/react/components/{ShowQRCode-CCN4h6Uv.css.map → ShowQRCode-CB0UCQ_h.css.map} +1 -1
  134. package/dist/esm/react/context/useSDKFlowRuntime.js +181 -0
  135. package/dist/esm/react/context/useSDKFlowRuntime.js.map +1 -0
  136. package/dist/esm/react/context/useTatchiContextValue.js +25 -16
  137. package/dist/esm/react/context/useTatchiContextValue.js.map +1 -1
  138. package/dist/esm/react/context/useTatchiWithSdkFlow.js +94 -0
  139. package/dist/esm/react/context/useTatchiWithSdkFlow.js.map +1 -0
  140. package/dist/esm/react/sdk/src/core/EmailRecovery/index.js +25 -1
  141. package/dist/esm/react/sdk/src/core/EmailRecovery/index.js.map +1 -1
  142. package/dist/esm/react/sdk/src/core/TatchiPasskey/emailRecovery.js +136 -78
  143. package/dist/esm/react/sdk/src/core/TatchiPasskey/emailRecovery.js.map +1 -1
  144. package/dist/esm/react/sdk/src/core/TatchiPasskey/index.js +2 -1
  145. package/dist/esm/react/sdk/src/core/TatchiPasskey/index.js.map +1 -1
  146. package/dist/esm/react/sdk/src/core/TatchiPasskey/linkDevice.js +2 -1
  147. package/dist/esm/react/sdk/src/core/TatchiPasskey/linkDevice.js.map +1 -1
  148. package/dist/esm/react/sdk/src/core/TatchiPasskey/scanDevice.js +5 -3
  149. package/dist/esm/react/sdk/src/core/TatchiPasskey/scanDevice.js.map +1 -1
  150. package/dist/esm/react/sdk/src/core/WalletIframe/client/router.js +1 -1
  151. package/dist/esm/react/sdk/src/core/WalletIframe/client/router.js.map +1 -1
  152. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +2 -3
  153. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  154. package/dist/esm/react/sdk/src/core/defaultConfigs.js +3 -7
  155. package/dist/esm/react/sdk/src/core/defaultConfigs.js.map +1 -1
  156. package/dist/esm/react/sdk/src/core/nearCrypto.js +24 -6
  157. package/dist/esm/react/sdk/src/core/nearCrypto.js.map +1 -1
  158. package/dist/esm/react/sdk/src/core/rpcCalls.js +56 -26
  159. package/dist/esm/react/sdk/src/core/rpcCalls.js.map +1 -1
  160. package/dist/esm/react/sdk/src/core/types/emailRecovery.js +26 -0
  161. package/dist/esm/react/sdk/src/core/types/emailRecovery.js.map +1 -0
  162. package/dist/esm/react/styles/styles.css +58 -3
  163. package/dist/esm/sdk/{defaultConfigs-DpslkAQd.js → defaultConfigs-CfQDV-ya.js} +3 -7
  164. package/dist/esm/sdk/{getDeviceNumber-fXizNGQl.js → getDeviceNumber-BpernPnM.js} +4 -8
  165. package/dist/esm/sdk/getDeviceNumber-BpernPnM.js.map +1 -0
  166. package/dist/esm/sdk/offline-export-app.js +23 -6
  167. package/dist/esm/sdk/offline-export-app.js.map +1 -1
  168. package/dist/esm/sdk/{router-DuGYOd3G.js → router-BWtacLJg.js} +1 -1
  169. package/dist/esm/sdk/{rpcCalls-BQrJMTdg.js → rpcCalls-CYGJSCgm.js} +3 -3
  170. package/dist/esm/sdk/{rpcCalls-YVeUVMk2.js → rpcCalls-DZZSa-sk.js} +57 -27
  171. package/dist/esm/sdk/{transactions-bqaAwL4k.js → transactions-Cn9xTWlK.js} +2 -2
  172. package/dist/esm/sdk/{transactions-bqaAwL4k.js.map → transactions-Cn9xTWlK.js.map} +1 -1
  173. package/dist/esm/sdk/{transactions-BalIhtJ9.js → transactions-DfdwDQCn.js} +1 -1
  174. package/dist/esm/sdk/wallet-iframe-host.js +660 -590
  175. package/dist/esm/server/email-recovery/emailParsers.js +3 -1
  176. package/dist/esm/server/email-recovery/emailParsers.js.map +1 -1
  177. package/dist/esm/server/email-recovery/index.js +6 -6
  178. package/dist/esm/server/email-recovery/index.js.map +1 -1
  179. package/dist/esm/server/email-recovery/rpcCalls.js +22 -3
  180. package/dist/esm/server/email-recovery/rpcCalls.js.map +1 -1
  181. package/dist/esm/server/router/cloudflare.js +8 -3
  182. package/dist/esm/server/router/cloudflare.js.map +1 -1
  183. package/dist/esm/server/router/express.js.map +1 -1
  184. package/dist/esm/server/sdk/src/core/defaultConfigs.js +2 -4
  185. package/dist/esm/server/sdk/src/core/defaultConfigs.js.map +1 -1
  186. package/dist/esm/server/sdk/src/core/nearCrypto.js +26 -8
  187. package/dist/esm/server/sdk/src/core/nearCrypto.js.map +1 -1
  188. package/dist/esm/wasm_vrf_worker/pkg/wasm_vrf_worker_bg.wasm +0 -0
  189. package/dist/types/src/core/EmailRecovery/index.d.ts +8 -0
  190. package/dist/types/src/core/EmailRecovery/index.d.ts.map +1 -1
  191. package/dist/types/src/core/TatchiPasskey/emailRecovery.d.ts +8 -5
  192. package/dist/types/src/core/TatchiPasskey/emailRecovery.d.ts.map +1 -1
  193. package/dist/types/src/core/TatchiPasskey/index.d.ts +1 -1
  194. package/dist/types/src/core/TatchiPasskey/index.d.ts.map +1 -1
  195. package/dist/types/src/core/TatchiPasskey/scanDevice.d.ts.map +1 -1
  196. package/dist/types/src/core/WalletIframe/TatchiPasskeyIframe.d.ts +1 -1
  197. package/dist/types/src/core/WalletIframe/TatchiPasskeyIframe.d.ts.map +1 -1
  198. package/dist/types/src/core/WalletIframe/client/router.d.ts +1 -1
  199. package/dist/types/src/core/WalletIframe/client/router.d.ts.map +1 -1
  200. package/dist/types/src/core/WalletIframe/shared/messages.d.ts +1 -1
  201. package/dist/types/src/core/WalletIframe/shared/messages.d.ts.map +1 -1
  202. package/dist/types/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.d.ts +2 -1
  203. package/dist/types/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.d.ts.map +1 -1
  204. package/dist/types/src/core/defaultConfigs.d.ts.map +1 -1
  205. package/dist/types/src/core/nearCrypto.d.ts +14 -0
  206. package/dist/types/src/core/nearCrypto.d.ts.map +1 -1
  207. package/dist/types/src/core/rpcCalls.d.ts +11 -8
  208. package/dist/types/src/core/rpcCalls.d.ts.map +1 -1
  209. package/dist/types/src/core/types/emailRecovery.d.ts +10 -0
  210. package/dist/types/src/core/types/emailRecovery.d.ts.map +1 -0
  211. package/dist/types/src/core/types/index.d.ts +1 -0
  212. package/dist/types/src/core/types/index.d.ts.map +1 -1
  213. package/dist/types/src/core/types/tatchi.d.ts +0 -4
  214. package/dist/types/src/core/types/tatchi.d.ts.map +1 -1
  215. package/dist/types/src/index.d.ts +1 -0
  216. package/dist/types/src/index.d.ts.map +1 -1
  217. package/dist/types/src/react/components/PasskeyAuthMenu/adapters/tatchi.d.ts +2 -0
  218. package/dist/types/src/react/components/PasskeyAuthMenu/adapters/tatchi.d.ts.map +1 -1
  219. package/dist/types/src/react/components/PasskeyAuthMenu/client.d.ts.map +1 -1
  220. package/dist/types/src/react/components/PasskeyAuthMenu/controller/useSDKEvents.d.ts +10 -0
  221. package/dist/types/src/react/components/PasskeyAuthMenu/controller/useSDKEvents.d.ts.map +1 -0
  222. package/dist/types/src/react/components/PasskeyAuthMenu/types.d.ts +8 -3
  223. package/dist/types/src/react/components/PasskeyAuthMenu/types.d.ts.map +1 -1
  224. package/dist/types/src/react/components/PasskeyAuthMenu/ui/ContentSwitcher.d.ts +2 -0
  225. package/dist/types/src/react/components/PasskeyAuthMenu/ui/ContentSwitcher.d.ts.map +1 -1
  226. package/dist/types/src/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.d.ts +1 -1
  227. package/dist/types/src/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.d.ts.map +1 -1
  228. package/dist/types/src/react/context/useSDKFlowRuntime.d.ts +10 -0
  229. package/dist/types/src/react/context/useSDKFlowRuntime.d.ts.map +1 -0
  230. package/dist/types/src/react/context/useTatchiContextValue.d.ts.map +1 -1
  231. package/dist/types/src/react/context/useTatchiWithSdkFlow.d.ts +9 -0
  232. package/dist/types/src/react/context/useTatchiWithSdkFlow.d.ts.map +1 -0
  233. package/dist/types/src/react/types.d.ts +31 -0
  234. package/dist/types/src/react/types.d.ts.map +1 -1
  235. package/dist/types/src/server/email-recovery/emailParsers.d.ts.map +1 -1
  236. package/dist/types/src/server/email-recovery/index.d.ts +5 -6
  237. package/dist/types/src/server/email-recovery/index.d.ts.map +1 -1
  238. package/dist/types/src/server/email-recovery/rpcCalls.d.ts +1 -0
  239. package/dist/types/src/server/email-recovery/rpcCalls.d.ts.map +1 -1
  240. package/dist/types/src/server/router/cloudflare-adaptor.d.ts.map +1 -1
  241. package/dist/workers/wasm_vrf_worker_bg.wasm +0 -0
  242. package/package.json +1 -1
  243. package/dist/esm/sdk/getDeviceNumber-fXizNGQl.js.map +0 -1
@@ -1,11 +1,65 @@
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
+ import { EmailRecoveryErrorCode, init_emailRecovery } from "../../../sdk/src/core/types/emailRecovery.js";
3
4
  import React from "react";
4
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
6
 
6
7
  //#region src/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.tsx
7
- init_IndexedDBManager();
8
- init_accountIds();
8
+ init_sdkSentEvents();
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
+ }
22
+ function getEmailRecoveryErrorCode(err) {
23
+ const code = err?.code;
24
+ if (typeof code !== "string") return null;
25
+ return Object.values(EmailRecoveryErrorCode).includes(code) ? code : null;
26
+ }
27
+ function getEmailRecoveryUiError(err) {
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
+ };
34
+ const code = getEmailRecoveryErrorCode(err);
35
+ switch (code) {
36
+ case EmailRecoveryErrorCode.VRF_CHALLENGE_EXPIRED: return {
37
+ message: fallback || "Timed out finalizing registration (VRF challenge expired). Please restart email recovery and try again.",
38
+ canRestart: true
39
+ };
40
+ case EmailRecoveryErrorCode.REGISTRATION_NOT_VERIFIED: return {
41
+ message: fallback || "Registration did not verify on-chain. Please restart email recovery and try again.",
42
+ canRestart: true
43
+ };
44
+ default: return {
45
+ message: fallback || "Email recovery failed",
46
+ canRestart: false
47
+ };
48
+ }
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
+ }
9
63
  const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, emailRecoveryOptions }) => {
10
64
  const mountedRef = React.useRef(true);
11
65
  const mailtoAttemptTimerRef = React.useRef(null);
@@ -22,19 +76,22 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
22
76
  }, []);
23
77
  const [isBusy, setIsBusy] = React.useState(false);
24
78
  const [accountIdInput, setAccountIdInput] = React.useState("");
25
- const [recoveryEmailInput, setRecoveryEmailInput] = React.useState("");
26
79
  const [pendingMailtoUrl, setPendingMailtoUrl] = React.useState(null);
80
+ const [pendingNearPublicKey, setPendingNearPublicKey] = React.useState(null);
27
81
  const [mailtoUiState, setMailtoUiState] = React.useState("ready");
28
82
  const [statusText, setStatusText] = React.useState(null);
29
83
  const [pollingElapsedMs, setPollingElapsedMs] = React.useState(null);
30
84
  const [errorText, setErrorText] = React.useState(null);
85
+ const [canRestart, setCanRestart] = React.useState(false);
31
86
  const [accountInfo, setAccountInfo] = React.useState(null);
32
87
  const [accountInfoLoading, setAccountInfoLoading] = React.useState(false);
33
88
  const [accountInfoError, setAccountInfoError] = React.useState(null);
34
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");
35
93
  const [explorerToast, setExplorerToast] = React.useState(null);
36
94
  const lastPrefilledAccountIdRef = React.useRef("");
37
- const lastPrefilledRecoveryEmailRef = React.useRef("");
38
95
  React.useEffect(() => {
39
96
  const next = (accountId || "").trim();
40
97
  if (!next) return;
@@ -45,14 +102,19 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
45
102
  }, [accountId]);
46
103
  React.useEffect(() => {
47
104
  setPendingMailtoUrl(null);
105
+ setPendingNearPublicKey(null);
48
106
  setMailtoUiState("ready");
49
107
  cancelRequestedRef.current = false;
50
108
  setStatusText(null);
51
109
  setPollingElapsedMs(null);
52
110
  setErrorText(null);
111
+ setCanRestart(false);
53
112
  setAccountInfo(null);
54
113
  setAccountInfoError(null);
55
114
  setLocalRecoveryEmails([]);
115
+ setRecoveryEmailRecords([]);
116
+ setRecoveryEmailInput("");
117
+ setRecoveryEmailMatchStatus("empty");
56
118
  setExplorerToast(null);
57
119
  if (mailtoAttemptTimerRef.current != null) {
58
120
  window.clearTimeout(mailtoAttemptTimerRef.current);
@@ -66,22 +128,26 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
66
128
  };
67
129
  };
68
130
  const safeSetPendingMailtoUrl = React.useMemo(() => safeSet(setPendingMailtoUrl), []);
131
+ const safeSetPendingNearPublicKey = React.useMemo(() => safeSet(setPendingNearPublicKey), []);
69
132
  const safeSetStatusText = React.useMemo(() => safeSet(setStatusText), []);
70
133
  const safeSetPollingElapsedMs = React.useMemo(() => safeSet(setPollingElapsedMs), []);
71
134
  const safeSetErrorText = React.useMemo(() => safeSet(setErrorText), []);
72
135
  const safeSetIsBusy = React.useMemo(() => safeSet(setIsBusy), []);
136
+ const safeSetCanRestart = React.useMemo(() => safeSet(setCanRestart), []);
73
137
  const safeSetAccountInfo = React.useMemo(() => safeSet(setAccountInfo), []);
74
138
  const safeSetAccountInfoLoading = React.useMemo(() => safeSet(setAccountInfoLoading), []);
75
139
  const safeSetAccountInfoError = React.useMemo(() => safeSet(setAccountInfoError), []);
76
140
  const safeSetLocalRecoveryEmails = React.useMemo(() => safeSet(setLocalRecoveryEmails), []);
141
+ const safeSetRecoveryEmailRecords = React.useMemo(() => safeSet(setRecoveryEmailRecords), []);
142
+ const safeSetRecoveryEmailMatchStatus = React.useMemo(() => safeSet(setRecoveryEmailMatchStatus), []);
77
143
  const safeSetExplorerToast = React.useMemo(() => safeSet(setExplorerToast), []);
78
144
  const safeSetMailtoUiState = React.useMemo(() => safeSet(setMailtoUiState), []);
79
145
  const onEvent = React.useCallback((ev) => {
80
146
  if (cancelRequestedRef.current) return;
81
147
  safeSetStatusText(ev?.message || null);
82
148
  emailRecoveryOptions?.onEvent?.(ev);
83
- const data = ev?.data || {};
84
- 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"];
85
151
  const txHash = typeof rawTxHash === "string" ? rawTxHash.trim() : "";
86
152
  if (txHash) {
87
153
  const base = String(tatchiPasskey.configs?.nearExplorerUrl || "https://testnet.nearblocks.io").replace(/\/$/, "");
@@ -91,16 +157,18 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
91
157
  transactionHash: txHash
92
158
  });
93
159
  }
94
- const elapsedRaw = data?.elapsedMs ?? data?.elapsed_ms;
160
+ const elapsedRaw = data?.["elapsedMs"] ?? data?.["elapsed_ms"];
95
161
  if (elapsedRaw == null) safeSetPollingElapsedMs(null);
96
162
  const elapsed = elapsedRaw == null ? NaN : Number(elapsedRaw);
97
163
  if (!Number.isNaN(elapsed)) safeSetPollingElapsedMs(elapsed);
98
- if (ev?.phase === "email-recovery-error" || ev?.status === "error") {
99
- const raw = ev?.error || ev?.message || "Email recovery failed";
100
- 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");
167
+ safeSetCanRestart(false);
101
168
  }
102
169
  }, [
103
170
  emailRecoveryOptions,
171
+ safeSetCanRestart,
104
172
  safeSetErrorText,
105
173
  safeSetExplorerToast,
106
174
  safeSetPollingElapsedMs,
@@ -117,6 +185,16 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
117
185
  accountId: normalized
118
186
  });
119
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]);
120
198
  const launchMailto = React.useCallback((rawMailtoUrl) => {
121
199
  const url = String(rawMailtoUrl || "").trim();
122
200
  if (!url) return;
@@ -162,40 +240,9 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
162
240
  document.removeEventListener("visibilitychange", onVisibilityChange);
163
241
  };
164
242
  }, [mailtoUiState, safeSetMailtoUiState]);
165
- const fetchLocalRecoveryEmailsFromIndexedDB = React.useCallback(async (rawAccountId) => {
166
- const normalized = (rawAccountId || "").trim();
167
- if (!normalized) {
168
- console.log("[EmailRecoverySlide] fetchLocalRecoveryEmails: empty accountId");
169
- return [];
170
- }
171
- try {
172
- console.log("[EmailRecoverySlide] fetchLocalRecoveryEmails: loading from IndexedDB", { accountId: normalized });
173
- const records = await IndexedDBManager.getRecoveryEmails(toAccountId(normalized));
174
- console.log("[EmailRecoverySlide] fetchLocalRecoveryEmails: raw IndexedDB records", {
175
- accountId: normalized,
176
- count: Array.isArray(records) ? records.length : 0,
177
- records
178
- });
179
- if (!Array.isArray(records) || records.length === 0) return [];
180
- const sorted = [...records].sort((a, b) => (b?.addedAt || 0) - (a?.addedAt || 0));
181
- const emails = sorted.map((r) => String(r?.email || "").trim().toLowerCase()).filter((e) => !!e && e.includes("@"));
182
- const uniq = Array.from(new Set(emails));
183
- console.log("[EmailRecoverySlide] fetchLocalRecoveryEmails: parsed emails", {
184
- accountId: normalized,
185
- emails: uniq
186
- });
187
- return uniq;
188
- } catch (err) {
189
- console.log("[EmailRecoverySlide] fetchLocalRecoveryEmails: failed to read IndexedDB", {
190
- accountId: normalized,
191
- error: err instanceof Error ? err.message : String(err)
192
- });
193
- return [];
194
- }
195
- }, []);
196
243
  const deriveEmailsFromRecoveryRecords = React.useCallback((records) => {
197
- if (!Array.isArray(records) || records.length === 0) return [];
198
- 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("@"));
199
246
  return Array.from(new Set(emails));
200
247
  }, []);
201
248
  React.useEffect(() => {
@@ -213,27 +260,11 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
213
260
  const handle = window.setTimeout(() => {
214
261
  (async () => {
215
262
  try {
216
- const isWalletIframeMode = !!tatchiPasskey.configs?.iframeWallet?.walletOrigin;
217
- let localEmails = [];
218
- if (!isWalletIframeMode) {
219
- localEmails = await fetchLocalRecoveryEmailsFromIndexedDB(normalized);
220
- if (!cancelled) console.log("[EmailRecoverySlide] local saved emails (IndexedDB)", {
221
- accountId: normalized,
222
- localEmails
223
- });
224
- }
225
263
  const records = await tatchiPasskey.getRecoveryEmails(normalized);
226
- const resolvedEmails = isWalletIframeMode ? deriveEmailsFromRecoveryRecords(records) : localEmails;
264
+ const resolvedEmails = deriveEmailsFromRecoveryRecords(records);
227
265
  if (!cancelled) {
228
266
  safeSetLocalRecoveryEmails(resolvedEmails);
229
- console.log("[EmailRecoverySlide] recovery email suggestions (state)", {
230
- accountId: normalized,
231
- emails: resolvedEmails
232
- });
233
- if (resolvedEmails.length === 1 && (recoveryEmailInput.trim() === "" || recoveryEmailInput === lastPrefilledRecoveryEmailRef.current)) {
234
- lastPrefilledRecoveryEmailRef.current = resolvedEmails[0];
235
- setRecoveryEmailInput(resolvedEmails[0]);
236
- }
267
+ safeSetRecoveryEmailRecords(records);
237
268
  }
238
269
  const info = records ? { emailsCount: Array.isArray(records) ? records.length : 0 } : null;
239
270
  if (cancelled) return;
@@ -241,7 +272,10 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
241
272
  } catch (err) {
242
273
  if (cancelled) return;
243
274
  safeSetAccountInfo(null);
244
- 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([]);
245
279
  } finally {
246
280
  if (!cancelled) safeSetAccountInfoLoading(false);
247
281
  }
@@ -254,37 +288,114 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
254
288
  }, [
255
289
  accountIdInput,
256
290
  deriveEmailsFromRecoveryRecords,
257
- fetchLocalRecoveryEmailsFromIndexedDB,
258
- recoveryEmailInput,
259
291
  safeSetAccountInfo,
260
292
  safeSetAccountInfoError,
261
293
  safeSetAccountInfoLoading,
262
294
  safeSetLocalRecoveryEmails,
295
+ safeSetRecoveryEmailRecords,
263
296
  tatchiPasskey
264
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
+ ]);
265
342
  const handleStart = React.useCallback(async () => {
266
343
  const normalizedAccountId = (accountIdInput || "").trim();
267
344
  if (!normalizedAccountId) {
268
345
  safeSetErrorText("Enter an account ID.");
269
346
  return;
270
347
  }
271
- const emailCandidate = (recoveryEmailInput || "").trim().toLowerCase();
272
- if (!emailCandidate) {
273
- safeSetErrorText("Enter the recovery email to send from.");
348
+ if (accountInfoLoading) {
349
+ safeSetErrorText("Checking recovery email settings…");
350
+ return;
351
+ }
352
+ if (accountInfoError) {
353
+ safeSetErrorText(accountInfoError);
354
+ return;
355
+ }
356
+ if (!accountInfo) {
357
+ safeSetErrorText("Failed to load email recovery settings for this account.");
274
358
  return;
275
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
+ }
276
385
  safeSetIsBusy(true);
277
386
  cancelRequestedRef.current = false;
278
387
  safeSetErrorText(null);
388
+ safeSetCanRestart(false);
279
389
  safeSetStatusText(null);
280
390
  safeSetPollingElapsedMs(null);
281
391
  safeSetPendingMailtoUrl(null);
392
+ safeSetPendingNearPublicKey(null);
282
393
  safeSetMailtoUiState("ready");
283
394
  let didForwardError = false;
284
395
  try {
285
396
  const result = await tatchiPasskey.startEmailRecovery({
286
397
  accountId: normalizedAccountId,
287
- recoveryEmail: emailCandidate,
398
+ ...recoveryEmail ? { recoveryEmail } : {},
288
399
  options: {
289
400
  onEvent,
290
401
  onError: (err) => {
@@ -292,11 +403,11 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
292
403
  safeSetErrorText(err?.message || "Failed to start email recovery");
293
404
  didForwardError = true;
294
405
  emailRecoveryOptions?.onError?.(err);
295
- },
296
- afterCall: async () => {}
406
+ }
297
407
  }
298
408
  });
299
409
  safeSetPendingMailtoUrl(result.mailtoUrl);
410
+ safeSetPendingNearPublicKey(result.nearPublicKey);
300
411
  safeSetStatusText("Recovery email draft ready. If it didn’t open automatically, click “Open recovery email draft”. Waiting for verification…");
301
412
  attemptOpenMailtoAuto(result.mailtoUrl);
302
413
  const finalizePromise = tatchiPasskey.finalizeEmailRecovery({
@@ -306,11 +417,14 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
306
417
  onEvent,
307
418
  onError: (err) => {
308
419
  if (cancelRequestedRef.current) return;
309
- safeSetErrorText(err?.message || "Failed to finalize email recovery");
420
+ const uiError = getEmailRecoveryUiError(err);
421
+ safeSetErrorText(uiError.message || "Failed to finalize email recovery");
422
+ safeSetCanRestart(uiError.canRestart);
423
+ const txHash = getEmailRecoveryErrorTxHash(err);
424
+ if (txHash) showExplorerTxToast(txHash);
310
425
  didForwardError = true;
311
426
  emailRecoveryOptions?.onError?.(err);
312
- },
313
- afterCall: async () => {}
427
+ }
314
428
  }
315
429
  });
316
430
  showExplorerToast(normalizedAccountId);
@@ -333,10 +447,16 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
333
447
  safeSetStatusText(null);
334
448
  safeSetPollingElapsedMs(null);
335
449
  safeSetPendingMailtoUrl(null);
450
+ safeSetPendingNearPublicKey(null);
336
451
  safeSetMailtoUiState("ready");
452
+ safeSetCanRestart(false);
337
453
  return;
338
454
  }
339
- safeSetErrorText(err?.message || "Failed to start email recovery");
455
+ const uiError = getEmailRecoveryUiError(err);
456
+ safeSetErrorText(uiError.message || "Failed to start email recovery");
457
+ safeSetCanRestart(uiError.canRestart);
458
+ const txHash = getEmailRecoveryErrorTxHash(err);
459
+ if (txHash) showExplorerTxToast(txHash);
340
460
  if (!didForwardError && err instanceof Error) emailRecoveryOptions?.onError?.(err);
341
461
  } finally {
342
462
  safeSetIsBusy(false);
@@ -344,9 +464,14 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
344
464
  }, [
345
465
  accountIdInput,
346
466
  emailRecoveryOptions,
347
- recoveryEmailInput,
348
467
  onEvent,
349
468
  refreshLoginState,
469
+ accountInfo,
470
+ accountInfoError,
471
+ accountInfoLoading,
472
+ recoveryEmailConfirmationRequired,
473
+ recoveryEmailInput,
474
+ recoveryEmailRecords,
350
475
  showExplorerToast,
351
476
  safeSetErrorText,
352
477
  safeSetIsBusy,
@@ -355,10 +480,64 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
355
480
  safeSetStatusText,
356
481
  safeSetMailtoUiState,
357
482
  attemptOpenMailtoAuto,
483
+ showExplorerTxToast,
358
484
  tatchiPasskey
359
485
  ]);
360
- const summaryLine = accountInfoLoading ? "Checking if account has recovery emails configured..." : accountInfo && !accountInfoError ? `Recovery emails configured: ${accountInfo.emailsCount}` : "\xA0";
486
+ const handleRestart = React.useCallback(async () => {
487
+ const normalizedAccountId = (accountIdInput || "").trim();
488
+ if (!normalizedAccountId) return;
489
+ safeSetIsBusy(true);
490
+ try {
491
+ cancelRequestedRef.current = true;
492
+ await tatchiPasskey.cancelEmailRecovery({
493
+ accountId: normalizedAccountId,
494
+ nearPublicKey: pendingNearPublicKey || void 0
495
+ }).catch(() => {});
496
+ safeSetErrorText(null);
497
+ safeSetStatusText(null);
498
+ safeSetPollingElapsedMs(null);
499
+ safeSetPendingMailtoUrl(null);
500
+ safeSetPendingNearPublicKey(null);
501
+ safeSetMailtoUiState("ready");
502
+ safeSetCanRestart(false);
503
+ } finally {
504
+ cancelRequestedRef.current = false;
505
+ safeSetIsBusy(false);
506
+ }
507
+ }, [
508
+ accountIdInput,
509
+ pendingNearPublicKey,
510
+ safeSetCanRestart,
511
+ safeSetErrorText,
512
+ safeSetIsBusy,
513
+ safeSetMailtoUiState,
514
+ safeSetPendingMailtoUrl,
515
+ safeSetPendingNearPublicKey,
516
+ safeSetPollingElapsedMs,
517
+ safeSetStatusText,
518
+ tatchiPasskey
519
+ ]);
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";
361
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;
362
541
  return /* @__PURE__ */ jsxs("div", {
363
542
  className: "w3a-email-recovery-slide",
364
543
  children: [
@@ -368,92 +547,113 @@ const EmailRecoverySlide = ({ tatchiPasskey, accountId, refreshLoginState, email
368
547
  }),
369
548
  /* @__PURE__ */ jsx("div", {
370
549
  className: "w3a-email-recovery-help",
371
- children: "Send a special recovery email from your recovery 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."
372
551
  }),
373
- /* @__PURE__ */ jsx("div", {
374
- className: "w3a-email-recovery-field",
552
+ /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx("div", {
553
+ className: "w3a-input-pill w3a-email-recovery-input-pill",
375
554
  children: /* @__PURE__ */ jsx("div", {
376
- className: "w3a-input-pill w3a-email-recovery-input-pill",
377
- children: /* @__PURE__ */ jsx("div", {
378
- className: "w3a-input-wrap",
379
- children: /* @__PURE__ */ jsx("input", {
380
- type: "text",
381
- value: accountIdInput,
382
- onChange: (e) => setAccountIdInput(e.target.value),
383
- placeholder: "NEAR account ID (e.g. alice.testnet)",
384
- className: "w3a-input",
385
- autoCapitalize: "none",
386
- autoCorrect: "off",
387
- spellCheck: false,
388
- inputMode: "text",
389
- disabled: isBusy
390
- })
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
391
567
  })
392
568
  })
393
- }),
394
- /* @__PURE__ */ jsx("div", {
569
+ }) }),
570
+ /* @__PURE__ */ jsxs("div", {
395
571
  className: "w3a-email-recovery-summary",
396
572
  "aria-live": "polite",
397
- children: /* @__PURE__ */ jsx("div", { children: summaryLine })
398
- }),
399
- /* @__PURE__ */ jsx("div", {
400
- className: "w3a-email-recovery-field",
401
- children: /* @__PURE__ */ jsx("div", {
402
- className: "w3a-input-pill w3a-email-recovery-input-pill",
403
- children: /* @__PURE__ */ jsx("div", {
404
- className: "w3a-input-wrap",
405
- children: /* @__PURE__ */ jsx("input", {
406
- type: "email",
407
- value: recoveryEmailInput,
408
- onChange: (e) => setRecoveryEmailInput(e.target.value),
409
- placeholder: "Recovery email to send from",
410
- className: "w3a-input",
411
- list: localRecoveryEmails.length > 0 ? "w3a-email-recovery-saved-emails" : void 0,
412
- autoCapitalize: "none",
413
- autoCorrect: "off",
414
- spellCheck: false,
415
- inputMode: "email",
416
- disabled: isBusy || noRecoveryEmailsConfigured
417
- })
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."
418
626
  })
419
- })
420
- }),
421
- localRecoveryEmails.length > 0 && /* @__PURE__ */ jsxs("div", {
422
- className: "w3a-email-recovery-summary",
423
- "aria-live": "polite",
424
- children: [/* @__PURE__ */ jsx("div", { children: "Saved on this device:" }), /* @__PURE__ */ jsx("div", {
425
- className: "w3a-email-recovery-saved-emails",
426
- children: localRecoveryEmails.map((email) => /* @__PURE__ */ jsx("button", {
427
- type: "button",
428
- className: "w3a-email-recovery-email-chip",
429
- onClick: () => setRecoveryEmailInput(email),
430
- disabled: isBusy,
431
- children: email
432
- }, email))
433
- })]
434
- }),
435
- localRecoveryEmails.length > 0 && /* @__PURE__ */ jsx("datalist", {
436
- id: "w3a-email-recovery-saved-emails",
437
- children: localRecoveryEmails.map((email) => /* @__PURE__ */ jsx("option", { value: email }, email))
627
+ ]
438
628
  }),
439
629
  /* @__PURE__ */ jsxs("div", {
440
630
  className: "w3a-email-recovery-actions",
441
- children: [(!pendingMailtoUrl || !isBusy) && /* @__PURE__ */ jsx("button", {
442
- onClick: handleStart,
443
- className: "w3a-link-device-btn w3a-link-device-btn-primary",
444
- disabled: isBusy || noRecoveryEmailsConfigured,
445
- children: noRecoveryEmailsConfigured ? "No recovery emails configured" : isBusy ? "Working…" : "Start Email Recovery"
446
- }), pendingMailtoUrl && /* @__PURE__ */ jsxs("button", {
447
- type: "button",
448
- onClick: () => attemptOpenMailtoFromUserGesture(pendingMailtoUrl),
449
- className: "w3a-link-device-btn w3a-link-device-btn-primary",
450
- disabled: mailtoUiState === "opening",
451
- "aria-busy": mailtoUiState === "opening",
452
- children: [mailtoUiState === "opening" && /* @__PURE__ */ jsx("span", {
453
- className: "w3a-spinner",
454
- "aria-hidden": "true"
455
- }), mailtoUiState === "opening" ? "Opening email…" : "Open recovery email draft"]
456
- })]
631
+ children: [
632
+ (!pendingMailtoUrl || !isBusy) && /* @__PURE__ */ jsx("button", {
633
+ onClick: handleStart,
634
+ className: "w3a-link-device-btn w3a-link-device-btn-primary",
635
+ disabled: startDisabled,
636
+ children: accountInfoLoading ? "Checking recovery emails…" : noRecoveryEmailsConfigured ? "No recovery emails configured" : disableStartForRecoveryEmailMismatch ? "Confirm recovery email" : isBusy ? "Working…" : "Start Email Recovery"
637
+ }),
638
+ pendingMailtoUrl && /* @__PURE__ */ jsxs("button", {
639
+ type: "button",
640
+ onClick: () => attemptOpenMailtoFromUserGesture(pendingMailtoUrl),
641
+ className: "w3a-link-device-btn w3a-link-device-btn-primary",
642
+ disabled: mailtoUiState === "opening",
643
+ "aria-busy": mailtoUiState === "opening",
644
+ children: [mailtoUiState === "opening" && /* @__PURE__ */ jsx("span", {
645
+ className: "w3a-spinner",
646
+ "aria-hidden": "true"
647
+ }), mailtoUiState === "opening" ? "Opening email…" : "Open recovery email draft"]
648
+ }),
649
+ errorText && canRestart && /* @__PURE__ */ jsx("button", {
650
+ type: "button",
651
+ onClick: handleRestart,
652
+ className: "w3a-link-device-btn",
653
+ disabled: isBusy,
654
+ children: "Restart email recovery"
655
+ })
656
+ ]
457
657
  }),
458
658
  (errorText || statusText || explorerToast) && /* @__PURE__ */ jsxs("div", {
459
659
  className: `w3a-email-recovery-status${errorText ? " is-error" : ""}`,