@tatchi-xyz/sdk 0.16.0 → 0.17.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 (470) hide show
  1. package/dist/cjs/core/EmailRecovery/index.js +12 -5
  2. package/dist/cjs/core/EmailRecovery/index.js.map +1 -1
  3. package/dist/cjs/core/IndexedDBManager/passkeyClientDB.js +35 -36
  4. package/dist/cjs/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  5. package/dist/cjs/core/NearClient.js +2 -1
  6. package/dist/cjs/core/NearClient.js.map +1 -1
  7. package/dist/cjs/core/TatchiPasskey/emailRecovery.js +136 -27
  8. package/dist/cjs/core/TatchiPasskey/emailRecovery.js.map +1 -1
  9. package/dist/cjs/core/TatchiPasskey/faucets/createAccountRelayServer.js +1 -0
  10. package/dist/cjs/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  11. package/dist/cjs/core/TatchiPasskey/index.js +25 -0
  12. package/dist/cjs/core/TatchiPasskey/index.js.map +1 -1
  13. package/dist/cjs/core/TatchiPasskey/linkDevice.js +2 -0
  14. package/dist/cjs/core/TatchiPasskey/linkDevice.js.map +1 -1
  15. package/dist/cjs/core/TatchiPasskey/login.js +15 -4
  16. package/dist/cjs/core/TatchiPasskey/login.js.map +1 -1
  17. package/dist/cjs/core/TatchiPasskey/recoverAccount.js +1 -0
  18. package/dist/cjs/core/TatchiPasskey/recoverAccount.js.map +1 -1
  19. package/dist/cjs/core/TatchiPasskey/scanDevice.js +1 -0
  20. package/dist/cjs/core/TatchiPasskey/scanDevice.js.map +1 -1
  21. package/dist/cjs/core/WalletIframe/client/IframeTransport.js +10 -0
  22. package/dist/cjs/core/WalletIframe/client/IframeTransport.js.map +1 -1
  23. package/dist/cjs/core/WalletIframe/client/router.js +9 -0
  24. package/dist/cjs/core/WalletIframe/client/router.js.map +1 -1
  25. package/dist/cjs/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js +1 -1
  26. package/dist/cjs/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js.map +1 -1
  27. package/dist/cjs/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js +52 -52
  28. package/dist/cjs/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js.map +1 -1
  29. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/getDeviceNumber.js +10 -1
  30. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/getDeviceNumber.js.map +1 -1
  31. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js +1 -0
  32. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js.map +1 -1
  33. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js +1 -0
  34. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js.map +1 -1
  35. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js +1 -0
  36. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js.map +1 -1
  37. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js +1 -0
  38. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js.map +1 -1
  39. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js +2 -1
  40. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js.map +1 -1
  41. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js +1 -0
  42. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js.map +1 -1
  43. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js +1 -0
  44. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js.map +1 -1
  45. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js +1 -0
  46. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js.map +1 -1
  47. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +2 -0
  48. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  49. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/index.js +1 -0
  50. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/index.js.map +1 -1
  51. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js +1 -0
  52. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js.map +1 -1
  53. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js +6 -0
  54. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js.map +1 -1
  55. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js +2 -1
  56. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js.map +1 -1
  57. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js +1 -0
  58. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js.map +1 -1
  59. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +1 -0
  60. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  61. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +4 -15
  62. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  63. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js +1 -0
  64. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js.map +1 -1
  65. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js +1 -0
  66. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js.map +1 -1
  67. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js +1 -0
  68. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js.map +1 -1
  69. package/dist/cjs/core/WebAuthnManager/WebAuthnFallbacks/index.js +17 -0
  70. package/dist/cjs/core/WebAuthnManager/WebAuthnFallbacks/index.js.map +1 -0
  71. package/dist/cjs/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js +64 -54
  72. package/dist/cjs/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js.map +1 -1
  73. package/dist/cjs/core/WebAuthnManager/credentialsHelpers.js +12 -2
  74. package/dist/cjs/core/WebAuthnManager/credentialsHelpers.js.map +1 -1
  75. package/dist/cjs/core/WebAuthnManager/index.js +6 -1
  76. package/dist/cjs/core/WebAuthnManager/index.js.map +1 -1
  77. package/dist/cjs/core/WebAuthnManager/touchIdPrompt.js +209 -201
  78. package/dist/cjs/core/WebAuthnManager/touchIdPrompt.js.map +1 -1
  79. package/dist/cjs/core/WebAuthnManager/userHandle.js +2 -1
  80. package/dist/cjs/core/WebAuthnManager/userHandle.js.map +1 -1
  81. package/dist/cjs/core/defaultConfigs.js +1 -1
  82. package/dist/cjs/core/defaultConfigs.js.map +1 -1
  83. package/dist/cjs/core/types/vrf-worker.js +10 -1
  84. package/dist/cjs/core/types/vrf-worker.js.map +1 -1
  85. package/dist/cjs/react/components/AccountMenuButton/{LinkedDevicesModal-STvIsylA.css → LinkedDevicesModal-B6api181.css} +1 -1
  86. package/dist/{esm/react/components/AccountMenuButton/LinkedDevicesModal-STvIsylA.css.map → cjs/react/components/AccountMenuButton/LinkedDevicesModal-B6api181.css.map} +1 -1
  87. package/dist/cjs/react/components/AccountMenuButton/{ProfileDropdown-iARgUwK1.css → ProfileDropdown-B-DrG_u5.css} +1 -1
  88. package/dist/{esm/react/components/AccountMenuButton/ProfileDropdown-iARgUwK1.css.map → cjs/react/components/AccountMenuButton/ProfileDropdown-B-DrG_u5.css.map} +1 -1
  89. package/dist/cjs/react/components/AccountMenuButton/{Web3AuthProfileButton-Db3NeoAC.css → Web3AuthProfileButton-BnZDUeCL.css} +1 -1
  90. package/dist/cjs/react/components/AccountMenuButton/{Web3AuthProfileButton-Db3NeoAC.css.map → Web3AuthProfileButton-BnZDUeCL.css.map} +1 -1
  91. package/dist/cjs/react/components/AccountMenuButton/icons/{TouchIcon-BXM5NR4A.css → TouchIcon-CAGCi8MY.css} +1 -1
  92. package/dist/cjs/react/components/AccountMenuButton/icons/{TouchIcon-BXM5NR4A.css.map → TouchIcon-CAGCi8MY.css.map} +1 -1
  93. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-De1qTSmU.css → PasskeyAuthMenu-CNNxVj4L.css} +14 -1
  94. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-De1qTSmU.css.map → PasskeyAuthMenu-CNNxVj4L.css.map} +1 -1
  95. package/dist/cjs/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js +122 -53
  96. package/dist/cjs/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js.map +1 -1
  97. package/dist/cjs/react/components/{ShowQRCode-DCnR__fx.css → ShowQRCode-nZhZSaba.css} +1 -1
  98. package/dist/cjs/react/components/{ShowQRCode-DCnR__fx.css.map → ShowQRCode-nZhZSaba.css.map} +1 -1
  99. package/dist/cjs/react/deviceDetection.js +75 -92
  100. package/dist/cjs/react/deviceDetection.js.map +1 -1
  101. package/dist/cjs/react/hooks/usePreconnectWalletAssets.js +32 -27
  102. package/dist/cjs/react/hooks/usePreconnectWalletAssets.js.map +1 -1
  103. package/dist/cjs/react/hooks/useQRCamera.js +1 -0
  104. package/dist/cjs/react/hooks/useQRCamera.js.map +1 -1
  105. package/dist/cjs/react/sdk/src/core/EmailRecovery/index.js +12 -5
  106. package/dist/cjs/react/sdk/src/core/EmailRecovery/index.js.map +1 -1
  107. package/dist/cjs/react/sdk/src/core/IndexedDBManager/passkeyClientDB.js +35 -36
  108. package/dist/cjs/react/sdk/src/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  109. package/dist/cjs/react/sdk/src/core/NearClient.js +2 -1
  110. package/dist/cjs/react/sdk/src/core/NearClient.js.map +1 -1
  111. package/dist/cjs/react/sdk/src/core/TatchiPasskey/emailRecovery.js +136 -27
  112. package/dist/cjs/react/sdk/src/core/TatchiPasskey/emailRecovery.js.map +1 -1
  113. package/dist/cjs/react/sdk/src/core/TatchiPasskey/faucets/createAccountRelayServer.js +1 -0
  114. package/dist/cjs/react/sdk/src/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  115. package/dist/cjs/react/sdk/src/core/TatchiPasskey/index.js +25 -0
  116. package/dist/cjs/react/sdk/src/core/TatchiPasskey/index.js.map +1 -1
  117. package/dist/cjs/react/sdk/src/core/TatchiPasskey/linkDevice.js +2 -0
  118. package/dist/cjs/react/sdk/src/core/TatchiPasskey/linkDevice.js.map +1 -1
  119. package/dist/cjs/react/sdk/src/core/TatchiPasskey/login.js +15 -4
  120. package/dist/cjs/react/sdk/src/core/TatchiPasskey/login.js.map +1 -1
  121. package/dist/cjs/react/sdk/src/core/TatchiPasskey/recoverAccount.js +1 -0
  122. package/dist/cjs/react/sdk/src/core/TatchiPasskey/recoverAccount.js.map +1 -1
  123. package/dist/cjs/react/sdk/src/core/TatchiPasskey/scanDevice.js +1 -0
  124. package/dist/cjs/react/sdk/src/core/TatchiPasskey/scanDevice.js.map +1 -1
  125. package/dist/cjs/react/sdk/src/core/WalletIframe/client/IframeTransport.js +10 -0
  126. package/dist/cjs/react/sdk/src/core/WalletIframe/client/IframeTransport.js.map +1 -1
  127. package/dist/cjs/react/sdk/src/core/WalletIframe/client/router.js +9 -0
  128. package/dist/cjs/react/sdk/src/core/WalletIframe/client/router.js.map +1 -1
  129. package/dist/cjs/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js +1 -1
  130. package/dist/cjs/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js.map +1 -1
  131. package/dist/cjs/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js +52 -52
  132. package/dist/cjs/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js.map +1 -1
  133. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/getDeviceNumber.js +10 -1
  134. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/getDeviceNumber.js.map +1 -1
  135. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js +1 -0
  136. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js.map +1 -1
  137. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js +1 -0
  138. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js.map +1 -1
  139. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js +1 -0
  140. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js.map +1 -1
  141. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js +1 -0
  142. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js.map +1 -1
  143. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js +2 -1
  144. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js.map +1 -1
  145. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js +1 -0
  146. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js.map +1 -1
  147. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js +1 -0
  148. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js.map +1 -1
  149. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js +1 -0
  150. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js.map +1 -1
  151. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +2 -0
  152. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  153. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/index.js +1 -0
  154. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/index.js.map +1 -1
  155. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js +1 -0
  156. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js.map +1 -1
  157. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js +6 -0
  158. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js.map +1 -1
  159. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js +2 -1
  160. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js.map +1 -1
  161. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js +1 -0
  162. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js.map +1 -1
  163. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +1 -0
  164. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  165. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +4 -15
  166. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  167. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js +1 -0
  168. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js.map +1 -1
  169. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js +1 -0
  170. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js.map +1 -1
  171. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js +1 -0
  172. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js.map +1 -1
  173. package/dist/cjs/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/index.js +17 -0
  174. package/dist/cjs/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/index.js.map +1 -0
  175. package/dist/cjs/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js +64 -54
  176. package/dist/cjs/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js.map +1 -1
  177. package/dist/cjs/react/sdk/src/core/WebAuthnManager/credentialsHelpers.js +12 -2
  178. package/dist/cjs/react/sdk/src/core/WebAuthnManager/credentialsHelpers.js.map +1 -1
  179. package/dist/cjs/react/sdk/src/core/WebAuthnManager/index.js +6 -1
  180. package/dist/cjs/react/sdk/src/core/WebAuthnManager/index.js.map +1 -1
  181. package/dist/cjs/react/sdk/src/core/WebAuthnManager/touchIdPrompt.js +209 -201
  182. package/dist/cjs/react/sdk/src/core/WebAuthnManager/touchIdPrompt.js.map +1 -1
  183. package/dist/cjs/react/sdk/src/core/WebAuthnManager/userHandle.js +2 -1
  184. package/dist/cjs/react/sdk/src/core/WebAuthnManager/userHandle.js.map +1 -1
  185. package/dist/cjs/react/sdk/src/core/defaultConfigs.js +1 -1
  186. package/dist/cjs/react/sdk/src/core/defaultConfigs.js.map +1 -1
  187. package/dist/cjs/react/sdk/src/core/types/vrf-worker.js +10 -1
  188. package/dist/cjs/react/sdk/src/core/types/vrf-worker.js.map +1 -1
  189. package/dist/cjs/react/sdk/src/utils/index.js +13 -3
  190. package/dist/cjs/server/email-recovery/emailEncryptor.js +11 -0
  191. package/dist/cjs/server/email-recovery/emailEncryptor.js.map +1 -1
  192. package/dist/cjs/server/email-recovery/emailParsers.js +57 -0
  193. package/dist/cjs/server/email-recovery/emailParsers.js.map +1 -1
  194. package/dist/cjs/server/email-recovery/index.js +1 -1
  195. package/dist/cjs/server/email-recovery/index.js.map +1 -1
  196. package/dist/cjs/server/email-recovery/rpcCalls.js +14 -1
  197. package/dist/cjs/server/email-recovery/rpcCalls.js.map +1 -1
  198. package/dist/cjs/server/index.js +1 -0
  199. package/dist/cjs/server/router/cloudflare.js.map +1 -1
  200. package/dist/cjs/server/router/express.js.map +1 -1
  201. package/dist/cjs/server/sdk/src/core/defaultConfigs.js +1 -1
  202. package/dist/cjs/server/sdk/src/core/defaultConfigs.js.map +1 -1
  203. package/dist/cjs/utils/index.js +13 -3
  204. package/dist/esm/core/EmailRecovery/index.js +12 -5
  205. package/dist/esm/core/EmailRecovery/index.js.map +1 -1
  206. package/dist/esm/core/IndexedDBManager/passkeyClientDB.js +35 -36
  207. package/dist/esm/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  208. package/dist/esm/core/NearClient.js +2 -1
  209. package/dist/esm/core/NearClient.js.map +1 -1
  210. package/dist/esm/core/TatchiPasskey/emailRecovery.js +136 -27
  211. package/dist/esm/core/TatchiPasskey/emailRecovery.js.map +1 -1
  212. package/dist/esm/core/TatchiPasskey/faucets/createAccountRelayServer.js +2 -1
  213. package/dist/esm/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  214. package/dist/esm/core/TatchiPasskey/index.js +26 -1
  215. package/dist/esm/core/TatchiPasskey/index.js.map +1 -1
  216. package/dist/esm/core/TatchiPasskey/linkDevice.js +4 -2
  217. package/dist/esm/core/TatchiPasskey/linkDevice.js.map +1 -1
  218. package/dist/esm/core/TatchiPasskey/login.js +13 -7
  219. package/dist/esm/core/TatchiPasskey/login.js.map +1 -1
  220. package/dist/esm/core/TatchiPasskey/recoverAccount.js +2 -1
  221. package/dist/esm/core/TatchiPasskey/recoverAccount.js.map +1 -1
  222. package/dist/esm/core/TatchiPasskey/scanDevice.js +2 -1
  223. package/dist/esm/core/TatchiPasskey/scanDevice.js.map +1 -1
  224. package/dist/esm/core/WalletIframe/client/IframeTransport.js +11 -1
  225. package/dist/esm/core/WalletIframe/client/IframeTransport.js.map +1 -1
  226. package/dist/esm/core/WalletIframe/client/router.js +9 -0
  227. package/dist/esm/core/WalletIframe/client/router.js.map +1 -1
  228. package/dist/esm/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js +1 -1
  229. package/dist/esm/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js.map +1 -1
  230. package/dist/esm/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js +52 -52
  231. package/dist/esm/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js.map +1 -1
  232. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/getDeviceNumber.js +6 -2
  233. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js +2 -1
  234. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js.map +1 -1
  235. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js +2 -1
  236. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js.map +1 -1
  237. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js +2 -1
  238. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js.map +1 -1
  239. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js +2 -1
  240. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js.map +1 -1
  241. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js +2 -1
  242. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js.map +1 -1
  243. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js +2 -1
  244. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js.map +1 -1
  245. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js +2 -1
  246. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js.map +1 -1
  247. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js +2 -1
  248. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js.map +1 -1
  249. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +4 -2
  250. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  251. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/index.js +2 -1
  252. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/index.js.map +1 -1
  253. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js +1 -0
  254. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js.map +1 -1
  255. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js +8 -2
  256. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js.map +1 -1
  257. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js +2 -1
  258. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js.map +1 -1
  259. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js +2 -1
  260. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js.map +1 -1
  261. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +2 -1
  262. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  263. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +5 -16
  264. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  265. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js +2 -1
  266. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js.map +1 -1
  267. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js +2 -1
  268. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js.map +1 -1
  269. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js +2 -1
  270. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js.map +1 -1
  271. package/dist/esm/core/WebAuthnManager/WebAuthnFallbacks/index.js +12 -0
  272. package/dist/esm/core/WebAuthnManager/WebAuthnFallbacks/index.js.map +1 -0
  273. package/dist/esm/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js +61 -55
  274. package/dist/esm/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js.map +1 -1
  275. package/dist/esm/core/WebAuthnManager/credentialsHelpers.js +8 -3
  276. package/dist/esm/core/WebAuthnManager/index.js +8 -3
  277. package/dist/esm/core/WebAuthnManager/index.js.map +1 -1
  278. package/dist/esm/core/WebAuthnManager/touchIdPrompt.js +207 -204
  279. package/dist/esm/core/WebAuthnManager/touchIdPrompt.js.map +1 -1
  280. package/dist/esm/core/WebAuthnManager/userHandle.js +2 -1
  281. package/dist/esm/core/WebAuthnManager/userHandle.js.map +1 -1
  282. package/dist/esm/core/defaultConfigs.js +1 -1
  283. package/dist/esm/core/defaultConfigs.js.map +1 -1
  284. package/dist/esm/core/types/vrf-worker.js +6 -2
  285. package/dist/esm/react/components/AccountMenuButton/{LinkedDevicesModal-STvIsylA.css → LinkedDevicesModal-B6api181.css} +1 -1
  286. package/dist/{cjs/react/components/AccountMenuButton/LinkedDevicesModal-STvIsylA.css.map → esm/react/components/AccountMenuButton/LinkedDevicesModal-B6api181.css.map} +1 -1
  287. package/dist/esm/react/components/AccountMenuButton/{ProfileDropdown-iARgUwK1.css → ProfileDropdown-B-DrG_u5.css} +1 -1
  288. package/dist/{cjs/react/components/AccountMenuButton/ProfileDropdown-iARgUwK1.css.map → esm/react/components/AccountMenuButton/ProfileDropdown-B-DrG_u5.css.map} +1 -1
  289. package/dist/esm/react/components/AccountMenuButton/{Web3AuthProfileButton-Db3NeoAC.css → Web3AuthProfileButton-BnZDUeCL.css} +1 -1
  290. package/dist/esm/react/components/AccountMenuButton/{Web3AuthProfileButton-Db3NeoAC.css.map → Web3AuthProfileButton-BnZDUeCL.css.map} +1 -1
  291. package/dist/esm/react/components/AccountMenuButton/icons/{TouchIcon-BXM5NR4A.css → TouchIcon-CAGCi8MY.css} +1 -1
  292. package/dist/esm/react/components/AccountMenuButton/icons/{TouchIcon-BXM5NR4A.css.map → TouchIcon-CAGCi8MY.css.map} +1 -1
  293. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-De1qTSmU.css → PasskeyAuthMenu-CNNxVj4L.css} +14 -1
  294. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-De1qTSmU.css.map → PasskeyAuthMenu-CNNxVj4L.css.map} +1 -1
  295. package/dist/esm/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js +123 -54
  296. package/dist/esm/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js.map +1 -1
  297. package/dist/esm/react/components/{ShowQRCode-DCnR__fx.css → ShowQRCode-nZhZSaba.css} +1 -1
  298. package/dist/esm/react/components/{ShowQRCode-DCnR__fx.css.map → ShowQRCode-nZhZSaba.css.map} +1 -1
  299. package/dist/esm/react/deviceDetection.js +72 -93
  300. package/dist/esm/react/deviceDetection.js.map +1 -1
  301. package/dist/esm/react/hooks/usePreconnectWalletAssets.js +32 -27
  302. package/dist/esm/react/hooks/usePreconnectWalletAssets.js.map +1 -1
  303. package/dist/esm/react/hooks/useQRCamera.js +2 -1
  304. package/dist/esm/react/hooks/useQRCamera.js.map +1 -1
  305. package/dist/esm/react/sdk/src/core/EmailRecovery/index.js +12 -5
  306. package/dist/esm/react/sdk/src/core/EmailRecovery/index.js.map +1 -1
  307. package/dist/esm/react/sdk/src/core/IndexedDBManager/passkeyClientDB.js +35 -36
  308. package/dist/esm/react/sdk/src/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  309. package/dist/esm/react/sdk/src/core/NearClient.js +2 -1
  310. package/dist/esm/react/sdk/src/core/NearClient.js.map +1 -1
  311. package/dist/esm/react/sdk/src/core/TatchiPasskey/emailRecovery.js +136 -27
  312. package/dist/esm/react/sdk/src/core/TatchiPasskey/emailRecovery.js.map +1 -1
  313. package/dist/esm/react/sdk/src/core/TatchiPasskey/faucets/createAccountRelayServer.js +2 -1
  314. package/dist/esm/react/sdk/src/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  315. package/dist/esm/react/sdk/src/core/TatchiPasskey/index.js +26 -1
  316. package/dist/esm/react/sdk/src/core/TatchiPasskey/index.js.map +1 -1
  317. package/dist/esm/react/sdk/src/core/TatchiPasskey/linkDevice.js +4 -2
  318. package/dist/esm/react/sdk/src/core/TatchiPasskey/linkDevice.js.map +1 -1
  319. package/dist/esm/react/sdk/src/core/TatchiPasskey/login.js +13 -7
  320. package/dist/esm/react/sdk/src/core/TatchiPasskey/login.js.map +1 -1
  321. package/dist/esm/react/sdk/src/core/TatchiPasskey/recoverAccount.js +2 -1
  322. package/dist/esm/react/sdk/src/core/TatchiPasskey/recoverAccount.js.map +1 -1
  323. package/dist/esm/react/sdk/src/core/TatchiPasskey/scanDevice.js +2 -1
  324. package/dist/esm/react/sdk/src/core/TatchiPasskey/scanDevice.js.map +1 -1
  325. package/dist/esm/react/sdk/src/core/WalletIframe/client/IframeTransport.js +11 -1
  326. package/dist/esm/react/sdk/src/core/WalletIframe/client/IframeTransport.js.map +1 -1
  327. package/dist/esm/react/sdk/src/core/WalletIframe/client/router.js +9 -0
  328. package/dist/esm/react/sdk/src/core/WalletIframe/client/router.js.map +1 -1
  329. package/dist/esm/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js +1 -1
  330. package/dist/esm/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js.map +1 -1
  331. package/dist/esm/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js +52 -52
  332. package/dist/esm/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js.map +1 -1
  333. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/getDeviceNumber.js +6 -2
  334. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js +2 -1
  335. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js.map +1 -1
  336. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js +2 -1
  337. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js.map +1 -1
  338. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js +2 -1
  339. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js.map +1 -1
  340. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js +2 -1
  341. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js.map +1 -1
  342. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js +2 -1
  343. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js.map +1 -1
  344. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js +2 -1
  345. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js.map +1 -1
  346. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js +2 -1
  347. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js.map +1 -1
  348. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js +2 -1
  349. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js.map +1 -1
  350. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +4 -2
  351. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  352. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/index.js +2 -1
  353. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/index.js.map +1 -1
  354. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js +1 -0
  355. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js.map +1 -1
  356. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js +8 -2
  357. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js.map +1 -1
  358. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js +2 -1
  359. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js.map +1 -1
  360. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js +2 -1
  361. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js.map +1 -1
  362. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +2 -1
  363. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  364. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +5 -16
  365. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  366. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js +2 -1
  367. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js.map +1 -1
  368. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js +2 -1
  369. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js.map +1 -1
  370. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js +2 -1
  371. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js.map +1 -1
  372. package/dist/esm/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/index.js +12 -0
  373. package/dist/esm/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/index.js.map +1 -0
  374. package/dist/esm/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js +61 -55
  375. package/dist/esm/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js.map +1 -1
  376. package/dist/esm/react/sdk/src/core/WebAuthnManager/credentialsHelpers.js +8 -3
  377. package/dist/esm/react/sdk/src/core/WebAuthnManager/index.js +8 -3
  378. package/dist/esm/react/sdk/src/core/WebAuthnManager/index.js.map +1 -1
  379. package/dist/esm/react/sdk/src/core/WebAuthnManager/touchIdPrompt.js +207 -204
  380. package/dist/esm/react/sdk/src/core/WebAuthnManager/touchIdPrompt.js.map +1 -1
  381. package/dist/esm/react/sdk/src/core/WebAuthnManager/userHandle.js +2 -1
  382. package/dist/esm/react/sdk/src/core/WebAuthnManager/userHandle.js.map +1 -1
  383. package/dist/esm/react/sdk/src/core/defaultConfigs.js +1 -1
  384. package/dist/esm/react/sdk/src/core/defaultConfigs.js.map +1 -1
  385. package/dist/esm/react/sdk/src/core/types/vrf-worker.js +6 -2
  386. package/dist/esm/react/sdk/src/utils/index.js +10 -4
  387. package/dist/esm/react/styles/styles.css +13 -0
  388. package/dist/esm/sdk/{safari-fallbacks-oQKu9xUs.js → WebAuthnFallbacks-Bl4BTsNt.js} +131 -135
  389. package/dist/esm/sdk/{createAdapters-pNiL2KNq.js → createAdapters-BumKM2ft.js} +59 -54
  390. package/dist/esm/sdk/createAdapters-BumKM2ft.js.map +1 -0
  391. package/dist/esm/sdk/{createAdapters-BWLe9Ddo.js → createAdapters-qVGD6i0g.js} +10 -3
  392. package/dist/esm/sdk/{defaultConfigs-VzvDejmy.js → defaultConfigs-DpslkAQd.js} +1 -1
  393. package/dist/esm/sdk/{getDeviceNumber-CkWRT17I.js → getDeviceNumber-fXizNGQl.js} +2 -2
  394. package/dist/esm/sdk/getDeviceNumber-fXizNGQl.js.map +1 -0
  395. package/dist/esm/sdk/{getDeviceNumber-CfmlgfMX.js → getDeviceNumber-zsOHT_Um.js} +6 -3
  396. package/dist/esm/sdk/{localOnly-DnpSyDaF.js → localOnly-Byi3AK7A.js} +2 -2
  397. package/dist/esm/sdk/{localOnly-DnpSyDaF.js.map → localOnly-Byi3AK7A.js.map} +1 -1
  398. package/dist/esm/sdk/{localOnly-BdumO2st.js → localOnly-pXMTqh1m.js} +5 -4
  399. package/dist/esm/sdk/offline-export-app.js +46 -44
  400. package/dist/esm/sdk/offline-export-app.js.map +1 -1
  401. package/dist/esm/sdk/{overlay-BTqPGG-o.js → overlay-ZGbucXIa.js} +2 -0
  402. package/dist/esm/sdk/{registration-C633u6x8.js → registration-CBiS4Ua_.js} +2 -2
  403. package/dist/esm/sdk/{registration-C633u6x8.js.map → registration-CBiS4Ua_.js.map} +1 -1
  404. package/dist/esm/sdk/{registration-xyYUFRqk.js → registration-DLPLsGCz.js} +5 -4
  405. package/dist/esm/sdk/{requestHelpers-DLBGBHMw.js → requestHelpers-Dh1hEYL9.js} +206 -204
  406. package/dist/esm/sdk/{router-BG6KC_p7.js → router-BLFegW7J.js} +20 -2
  407. package/dist/esm/sdk/{rpcCalls-fLObBbbz.js → rpcCalls-DEv9x5-f.js} +2 -2
  408. package/dist/esm/sdk/{rpcCalls-CAU5XYEF.js → rpcCalls-OhgEeFig.js} +1 -1
  409. package/dist/esm/sdk/{transactions-jH38BZ-Q.js → transactions-BIqKZeR0.js} +6 -18
  410. package/dist/esm/sdk/transactions-BIqKZeR0.js.map +1 -0
  411. package/dist/esm/sdk/{transactions-CzZAt1Yn.js → transactions-Bk-VavcV.js} +10 -21
  412. package/dist/esm/sdk/tx-confirm-ui.js +53 -53
  413. package/dist/esm/sdk/{tx-confirmer-wrapper-CqfVBUaA.js → tx-confirmer-wrapper-lHNgz9i4.js} +53 -53
  414. package/dist/esm/sdk/tx-confirmer.css +6 -4
  415. package/dist/esm/sdk/w3a-tx-confirmer.js +1 -1
  416. package/dist/esm/sdk/wallet-iframe-host.js +271 -89
  417. package/dist/esm/server/email-recovery/emailEncryptor.js +11 -1
  418. package/dist/esm/server/email-recovery/emailEncryptor.js.map +1 -1
  419. package/dist/esm/server/email-recovery/emailParsers.js +55 -1
  420. package/dist/esm/server/email-recovery/emailParsers.js.map +1 -1
  421. package/dist/esm/server/email-recovery/index.js +2 -2
  422. package/dist/esm/server/email-recovery/index.js.map +1 -1
  423. package/dist/esm/server/email-recovery/rpcCalls.js +14 -1
  424. package/dist/esm/server/email-recovery/rpcCalls.js.map +1 -1
  425. package/dist/esm/server/index.js +2 -2
  426. package/dist/esm/server/router/cloudflare.js.map +1 -1
  427. package/dist/esm/server/router/express.js.map +1 -1
  428. package/dist/esm/server/sdk/src/core/defaultConfigs.js +1 -1
  429. package/dist/esm/server/sdk/src/core/defaultConfigs.js.map +1 -1
  430. package/dist/esm/utils/index.js +10 -4
  431. package/dist/esm/wasm_vrf_worker/pkg/wasm_vrf_worker.js +3 -0
  432. package/dist/esm/wasm_vrf_worker/pkg/wasm_vrf_worker_bg.wasm +0 -0
  433. package/dist/types/src/core/EmailRecovery/index.d.ts.map +1 -1
  434. package/dist/types/src/core/IndexedDBManager/passkeyClientDB.d.ts +11 -21
  435. package/dist/types/src/core/IndexedDBManager/passkeyClientDB.d.ts.map +1 -1
  436. package/dist/types/src/core/TatchiPasskey/emailRecovery.d.ts +12 -1
  437. package/dist/types/src/core/TatchiPasskey/emailRecovery.d.ts.map +1 -1
  438. package/dist/types/src/core/TatchiPasskey/index.d.ts +8 -0
  439. package/dist/types/src/core/TatchiPasskey/index.d.ts.map +1 -1
  440. package/dist/types/src/core/WalletIframe/TatchiPasskeyIframe.d.ts +4 -0
  441. package/dist/types/src/core/WalletIframe/TatchiPasskeyIframe.d.ts.map +1 -1
  442. package/dist/types/src/core/WalletIframe/client/IframeTransport.d.ts.map +1 -1
  443. package/dist/types/src/core/WalletIframe/client/router.d.ts +4 -0
  444. package/dist/types/src/core/WalletIframe/client/router.d.ts.map +1 -1
  445. package/dist/types/src/core/WalletIframe/host/wallet-iframe-handlers.d.ts.map +1 -1
  446. package/dist/types/src/core/WalletIframe/shared/messages.d.ts +6 -2
  447. package/dist/types/src/core/WalletIframe/shared/messages.d.ts.map +1 -1
  448. package/dist/types/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.d.ts.map +1 -1
  449. package/dist/types/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.d.ts.map +1 -1
  450. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.d.ts.map +1 -1
  451. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.d.ts.map +1 -1
  452. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.d.ts.map +1 -1
  453. package/dist/types/src/core/WebAuthnManager/index.d.ts.map +1 -1
  454. package/dist/types/src/core/defaultConfigs.d.ts.map +1 -1
  455. package/dist/types/src/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.d.ts.map +1 -1
  456. package/dist/types/src/react/hooks/usePreconnectWalletAssets.d.ts.map +1 -1
  457. package/dist/types/src/server/email-recovery/emailEncryptor.d.ts +4 -0
  458. package/dist/types/src/server/email-recovery/emailEncryptor.d.ts.map +1 -1
  459. package/dist/types/src/server/email-recovery/emailParsers.d.ts +7 -0
  460. package/dist/types/src/server/email-recovery/emailParsers.d.ts.map +1 -1
  461. package/dist/types/src/server/email-recovery/index.d.ts +1 -1
  462. package/dist/types/src/server/email-recovery/rpcCalls.d.ts +1 -1
  463. package/dist/types/src/server/email-recovery/rpcCalls.d.ts.map +1 -1
  464. package/dist/types/src/wasm_vrf_worker/pkg/wasm_vrf_worker.d.ts.map +1 -1
  465. package/dist/workers/wasm_vrf_worker_bg.wasm +0 -0
  466. package/dist/workers/web3authn-vrf.worker.js +3 -0
  467. package/package.json +1 -1
  468. package/dist/esm/sdk/createAdapters-pNiL2KNq.js.map +0 -1
  469. package/dist/esm/sdk/getDeviceNumber-CkWRT17I.js.map +0 -1
  470. package/dist/esm/sdk/transactions-jH38BZ-Q.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"EmailRecoverySlide.js","names":["EmailRecoverySlide: React.FC<EmailRecoverySlideProps>","localEmails: string[]","info: EmailRecoveryAccountInfo | null","err: any"],"sources":["../../../../../../src/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.tsx"],"sourcesContent":["import React from 'react';\n\nimport type { EmailRecoverySSEEvent } from '@/core/types/sdkSentEvents';\nimport type { TatchiPasskey } from '@/core/TatchiPasskey';\nimport { IndexedDBManager } from '@/core/IndexedDBManager';\nimport { toAccountId } from '@/core/types/accountIds';\n\nexport interface EmailRecoverySlideProps {\n tatchiPasskey: TatchiPasskey;\n accountId: string;\n refreshLoginState?: (nearAccountId?: string) => Promise<void>;\n emailRecoveryOptions?: {\n onEvent?: (event: EmailRecoverySSEEvent) => void;\n onError?: (error: Error) => void;\n };\n}\n\ntype EmailRecoveryPolicy = {\n minRequiredEmails?: number;\n maxAgeMs?: number;\n};\n\ntype EmailRecoveryAccountInfo = {\n emailsCount: number;\n};\n\nexport const EmailRecoverySlide: React.FC<EmailRecoverySlideProps> = ({ tatchiPasskey, accountId, refreshLoginState, emailRecoveryOptions }) => {\n const mountedRef = React.useRef(true);\n const explorerToastTimerRef = React.useRef<number | null>(null);\n React.useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n if (explorerToastTimerRef.current != null) {\n window.clearTimeout(explorerToastTimerRef.current);\n explorerToastTimerRef.current = null;\n }\n };\n }, []);\n\n const [isBusy, setIsBusy] = React.useState(false);\n const [accountIdInput, setAccountIdInput] = React.useState('');\n const [recoveryEmailInput, setRecoveryEmailInput] = React.useState('');\n const [pendingMailtoUrl, setPendingMailtoUrl] = React.useState<string | null>(null);\n const [statusText, setStatusText] = React.useState<string | null>(null);\n const [pollingElapsedMs, setPollingElapsedMs] = React.useState<number | null>(null);\n const [errorText, setErrorText] = React.useState<string | null>(null);\n const [accountInfo, setAccountInfo] = React.useState<EmailRecoveryAccountInfo | null>(null);\n const [accountInfoLoading, setAccountInfoLoading] = React.useState(false);\n const [accountInfoError, setAccountInfoError] = React.useState<string | null>(null);\n const [localRecoveryEmails, setLocalRecoveryEmails] = React.useState<string[]>([]);\n const [explorerToast, setExplorerToast] = React.useState<{ url: string; accountId: string } | null>(null);\n\n const lastPrefilledAccountIdRef = React.useRef<string>('');\n const lastPrefilledRecoveryEmailRef = React.useRef<string>('');\n\n React.useEffect(() => {\n const next = (accountId || '').trim();\n if (!next) return;\n if (accountIdInput.trim() === '' || accountIdInput === lastPrefilledAccountIdRef.current) {\n lastPrefilledAccountIdRef.current = next;\n setAccountIdInput(next);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [accountId]);\n\n React.useEffect(() => {\n setPendingMailtoUrl(null);\n setStatusText(null);\n setPollingElapsedMs(null);\n setErrorText(null);\n setAccountInfo(null);\n setAccountInfoError(null);\n setLocalRecoveryEmails([]);\n setExplorerToast(null);\n if (explorerToastTimerRef.current != null) {\n window.clearTimeout(explorerToastTimerRef.current);\n explorerToastTimerRef.current = null;\n }\n }, [accountId]);\n\n const safeSet = <T,>(setter: React.Dispatch<React.SetStateAction<T>>) => {\n return (value: React.SetStateAction<T>) => {\n if (!mountedRef.current) return;\n setter(value);\n };\n };\n\n const safeSetPendingMailtoUrl = React.useMemo(() => safeSet(setPendingMailtoUrl), []);\n const safeSetStatusText = React.useMemo(() => safeSet(setStatusText), []);\n const safeSetPollingElapsedMs = React.useMemo(() => safeSet(setPollingElapsedMs), []);\n const safeSetErrorText = React.useMemo(() => safeSet(setErrorText), []);\n const safeSetIsBusy = React.useMemo(() => safeSet(setIsBusy), []);\n const safeSetAccountInfo = React.useMemo(() => safeSet(setAccountInfo), []);\n const safeSetAccountInfoLoading = React.useMemo(() => safeSet(setAccountInfoLoading), []);\n const safeSetAccountInfoError = React.useMemo(() => safeSet(setAccountInfoError), []);\n const safeSetLocalRecoveryEmails = React.useMemo(() => safeSet(setLocalRecoveryEmails), []);\n const safeSetExplorerToast = React.useMemo(() => safeSet(setExplorerToast), []);\n\n const onEvent = React.useCallback(\n (ev: EmailRecoverySSEEvent) => {\n safeSetStatusText(ev?.message || null);\n emailRecoveryOptions?.onEvent?.(ev);\n\n const data = (ev as any)?.data || {};\n const elapsedRaw = data?.elapsedMs ?? data?.elapsed_ms;\n const elapsed = elapsedRaw == null ? Number.NaN : Number(elapsedRaw);\n if (!Number.isNaN(elapsed)) safeSetPollingElapsedMs(elapsed);\n\n if (ev?.phase === 'email-recovery-error' || (ev as any)?.status === 'error') {\n const raw = (ev as any)?.error || ev?.message || 'Email recovery failed';\n safeSetErrorText(String(raw));\n }\n },\n [emailRecoveryOptions, safeSetStatusText, safeSetPollingElapsedMs, safeSetErrorText],\n );\n\n const showExplorerToast = React.useCallback(\n (rawAccountId: string) => {\n const normalized = (rawAccountId || '').trim();\n if (!normalized) return;\n const base = String(tatchiPasskey.configs?.nearExplorerUrl || 'https://testnet.nearblocks.io').replace(/\\/$/, '');\n const url = `${base}/address/${normalized}`;\n\n safeSetExplorerToast({ url, accountId: normalized });\n\n if (explorerToastTimerRef.current != null) {\n window.clearTimeout(explorerToastTimerRef.current);\n }\n explorerToastTimerRef.current = window.setTimeout(() => {\n safeSetExplorerToast(null);\n explorerToastTimerRef.current = null;\n }, 12_000);\n },\n [safeSetExplorerToast, tatchiPasskey],\n );\n\n const fetchLocalRecoveryEmailsFromIndexedDB = React.useCallback(\n async (rawAccountId: string): Promise<string[]> => {\n const normalized = (rawAccountId || '').trim();\n if (!normalized) {\n console.log('[EmailRecoverySlide] fetchLocalRecoveryEmails: empty accountId');\n return [];\n }\n\n try {\n console.log('[EmailRecoverySlide] fetchLocalRecoveryEmails: loading from IndexedDB', { accountId: normalized });\n const records = await IndexedDBManager.getRecoveryEmails(toAccountId(normalized));\n console.log('[EmailRecoverySlide] fetchLocalRecoveryEmails: raw IndexedDB records', {\n accountId: normalized,\n count: Array.isArray(records) ? records.length : 0,\n records,\n });\n if (!Array.isArray(records) || records.length === 0) return [];\n\n const sorted = [...records].sort((a, b) => (b?.addedAt || 0) - (a?.addedAt || 0));\n const emails = sorted\n .map(r => String(r?.email || '').trim().toLowerCase())\n .filter(e => !!e && e.includes('@'));\n\n const uniq = Array.from(new Set(emails));\n console.log('[EmailRecoverySlide] fetchLocalRecoveryEmails: parsed emails', {\n accountId: normalized,\n emails: uniq,\n });\n return uniq;\n } catch (err) {\n // best-effort; treat as no saved emails (e.g., IndexedDB unavailable)\n console.log('[EmailRecoverySlide] fetchLocalRecoveryEmails: failed to read IndexedDB', {\n accountId: normalized,\n error: err instanceof Error ? err.message : String(err),\n });\n return [];\n }\n },\n [],\n );\n\n const deriveEmailsFromRecoveryRecords = React.useCallback((records: unknown): string[] => {\n if (!Array.isArray(records) || records.length === 0) return [];\n const emails = records\n .map((r: any) => String(r?.email || '').trim().toLowerCase())\n .filter((e: string) => !!e && e.includes('@'));\n return Array.from(new Set(emails));\n }, []);\n\n React.useEffect(() => {\n const normalized = (accountIdInput || '').trim();\n if (!normalized) {\n setAccountInfo(null);\n setAccountInfoError(null);\n setAccountInfoLoading(false);\n safeSetLocalRecoveryEmails([]);\n return;\n }\n\n let cancelled = false;\n // Show loading state immediately (don't wait for debounce).\n safeSetAccountInfoLoading(true);\n safeSetAccountInfoError(null);\n const handle = window.setTimeout(() => {\n void (async () => {\n try {\n const isWalletIframeMode = !!tatchiPasskey.configs?.iframeWallet?.walletOrigin;\n\n // Legacy mode: suggest recovery emails from local IndexedDB mapping (best-effort).\n let localEmails: string[] = [];\n if (!isWalletIframeMode) {\n localEmails = await fetchLocalRecoveryEmailsFromIndexedDB(normalized);\n if (!cancelled) {\n console.log('[EmailRecoverySlide] local saved emails (IndexedDB)', { accountId: normalized, localEmails });\n }\n }\n\n const records = await tatchiPasskey.getRecoveryEmails(normalized);\n const resolvedEmails = isWalletIframeMode\n ? deriveEmailsFromRecoveryRecords(records)\n : localEmails;\n\n if (!cancelled) {\n safeSetLocalRecoveryEmails(resolvedEmails);\n console.log('[EmailRecoverySlide] recovery email suggestions (state)', { accountId: normalized, emails: resolvedEmails });\n\n if (\n resolvedEmails.length === 1 &&\n (recoveryEmailInput.trim() === '' || recoveryEmailInput === lastPrefilledRecoveryEmailRef.current)\n ) {\n lastPrefilledRecoveryEmailRef.current = resolvedEmails[0];\n setRecoveryEmailInput(resolvedEmails[0]);\n }\n }\n\n const info: EmailRecoveryAccountInfo | null = records\n ? { emailsCount: Array.isArray(records) ? records.length : 0 }\n : null;\n if (cancelled) return;\n safeSetAccountInfo(info);\n } catch (err: any) {\n if (cancelled) return;\n safeSetAccountInfo(null);\n safeSetAccountInfoError(err?.message || 'Failed to load email recovery settings for this account');\n } finally {\n if (!cancelled) safeSetAccountInfoLoading(false);\n }\n })();\n }, 350);\n\n return () => {\n cancelled = true;\n window.clearTimeout(handle);\n };\n }, [\n accountIdInput,\n deriveEmailsFromRecoveryRecords,\n fetchLocalRecoveryEmailsFromIndexedDB,\n recoveryEmailInput,\n safeSetAccountInfo,\n safeSetAccountInfoError,\n safeSetAccountInfoLoading,\n safeSetLocalRecoveryEmails,\n tatchiPasskey,\n ]);\n\n const handleStart = React.useCallback(async () => {\n const normalizedAccountId = (accountIdInput || '').trim();\n if (!normalizedAccountId) {\n safeSetErrorText('Enter an account ID.');\n return;\n }\n\n const emailCandidate = (recoveryEmailInput || '').trim().toLowerCase();\n if (!emailCandidate) {\n safeSetErrorText('Enter the recovery email to send from.');\n return;\n }\n\n safeSetIsBusy(true);\n safeSetErrorText(null);\n safeSetStatusText(null);\n safeSetPollingElapsedMs(null);\n safeSetPendingMailtoUrl(null);\n\n let didForwardError = false;\n try {\n const result = await tatchiPasskey.startEmailRecovery({\n accountId: normalizedAccountId,\n recoveryEmail: emailCandidate,\n options: {\n onEvent,\n onError: (err: Error) => {\n safeSetErrorText(err?.message || 'Failed to start email recovery');\n didForwardError = true;\n emailRecoveryOptions?.onError?.(err);\n },\n afterCall: async () => {},\n } as any,\n });\n\n safeSetPendingMailtoUrl(result.mailtoUrl);\n safeSetStatusText('Recovery email draft ready. Send it from your recovery address. Waiting for verification…');\n\n if (typeof window !== 'undefined' && typeof window.open === 'function') {\n window.open(result.mailtoUrl, '_blank', 'noopener,noreferrer');\n }\n\n showExplorerToast(normalizedAccountId);\n\n await tatchiPasskey.finalizeEmailRecovery({\n accountId: normalizedAccountId,\n nearPublicKey: result.nearPublicKey,\n options: {\n onEvent,\n onError: (err: Error) => {\n safeSetErrorText(err?.message || 'Failed to finalize email recovery');\n didForwardError = true;\n emailRecoveryOptions?.onError?.(err);\n },\n afterCall: async () => {},\n } as any,\n });\n\n // Best-effort auto-login: the core flow attempts it, but if it couldn't (e.g. missing Shamir\n // auto-unlock and user cancelled TouchID), try once more here.\n let loginOk = false;\n const session = await tatchiPasskey.getLoginSession(normalizedAccountId).catch(() => null);\n if (session?.login?.isLoggedIn) {\n loginOk = true;\n } else {\n safeSetStatusText('Email recovery completed. Logging you in…');\n loginOk = await tatchiPasskey.loginAndCreateSession(normalizedAccountId)\n .then(() => true)\n .catch(() => false);\n }\n\n if (refreshLoginState) {\n await refreshLoginState(normalizedAccountId).catch(() => {});\n }\n\n safeSetStatusText(loginOk ? 'Email recovery completed on this device.' : 'Email recovery completed. Please log in on this device.');\n safeSetPendingMailtoUrl(null);\n safeSetPollingElapsedMs(null);\n } catch (err: any) {\n safeSetErrorText(err?.message || 'Failed to start email recovery');\n if (!didForwardError && err instanceof Error) {\n emailRecoveryOptions?.onError?.(err);\n }\n } finally {\n safeSetIsBusy(false);\n }\n }, [\n accountIdInput,\n emailRecoveryOptions,\n recoveryEmailInput,\n onEvent,\n refreshLoginState,\n showExplorerToast,\n safeSetErrorText,\n safeSetIsBusy,\n safeSetPendingMailtoUrl,\n safeSetPollingElapsedMs,\n safeSetStatusText,\n tatchiPasskey,\n ]);\n\n const summaryLine = accountInfoLoading\n ? 'Checking if account has recovery emails configured...'\n : accountInfo && !accountInfoError\n ? `Recovery emails configured: ${accountInfo.emailsCount}`\n : '\\u00A0';\n\n const noRecoveryEmailsConfigured =\n !accountInfoLoading && !accountInfoError && !!accountInfo && accountInfo.emailsCount === 0;\n\n return (\n <div className=\"w3a-email-recovery-slide\">\n <div className=\"w3a-email-recovery-title\">Recover Account with Email</div>\n <div className=\"w3a-email-recovery-help\">\n Send a special recovery email from your recovery email address.\n Your account will be recovered with a new key once the email is verified.\n </div>\n\n <div className=\"w3a-email-recovery-field\">\n <div className=\"w3a-input-pill w3a-email-recovery-input-pill\">\n <div className=\"w3a-input-wrap\">\n <input\n type=\"text\"\n value={accountIdInput}\n onChange={(e) => setAccountIdInput(e.target.value)}\n placeholder=\"NEAR account ID (e.g. alice.testnet)\"\n className=\"w3a-input\"\n autoCapitalize=\"none\"\n autoCorrect=\"off\"\n spellCheck={false}\n inputMode=\"text\"\n disabled={isBusy}\n />\n </div>\n </div>\n </div>\n\n <div className=\"w3a-email-recovery-summary\" aria-live=\"polite\">\n <div>{summaryLine}</div>\n </div>\n\n <div className=\"w3a-email-recovery-field\">\n <div className=\"w3a-input-pill w3a-email-recovery-input-pill\">\n <div className=\"w3a-input-wrap\">\n <input\n type=\"email\"\n value={recoveryEmailInput}\n onChange={(e) => setRecoveryEmailInput(e.target.value)}\n placeholder=\"Recovery email to send from\"\n className=\"w3a-input\"\n list={localRecoveryEmails.length > 0 ? 'w3a-email-recovery-saved-emails' : undefined}\n autoCapitalize=\"none\"\n autoCorrect=\"off\"\n spellCheck={false}\n inputMode=\"email\"\n disabled={isBusy || noRecoveryEmailsConfigured}\n />\n </div>\n </div>\n </div>\n\n {localRecoveryEmails.length > 0 && (\n <div className=\"w3a-email-recovery-summary\" aria-live=\"polite\">\n <div>Saved on this device:</div>\n <div className=\"w3a-email-recovery-saved-emails\">\n {localRecoveryEmails.map((email) => (\n <button\n key={email}\n type=\"button\"\n className=\"w3a-email-recovery-email-chip\"\n onClick={() => setRecoveryEmailInput(email)}\n disabled={isBusy}\n >\n {email}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {localRecoveryEmails.length > 0 && (\n <datalist id=\"w3a-email-recovery-saved-emails\">\n {localRecoveryEmails.map((email) => (\n <option key={email} value={email} />\n ))}\n </datalist>\n )}\n\n <div className=\"w3a-email-recovery-actions\">\n <button\n onClick={handleStart}\n className=\"w3a-link-device-btn w3a-link-device-btn-primary\"\n disabled={isBusy || noRecoveryEmailsConfigured}\n >\n {noRecoveryEmailsConfigured ? 'No recovery emails configured' : (isBusy ? 'Working…' : 'Start Email Recovery')}\n </button>\n </div>\n\n {pendingMailtoUrl && (\n <a className=\"w3a-email-recovery-link\" href={pendingMailtoUrl}>\n Open recovery email draft\n </a>\n )}\n\n {explorerToast && (\n <div className=\"w3a-email-recovery-toast\" role=\"status\" aria-live=\"polite\">\n <span>View on explorer:</span>\n <a href={explorerToast.url} target=\"_blank\" rel=\"noopener noreferrer\">\n {explorerToast.accountId}\n </a>\n <button\n type=\"button\"\n className=\"w3a-email-recovery-toast-close\"\n onClick={() => safeSetExplorerToast(null)}\n aria-label=\"Dismiss\"\n >\n ✕\n </button>\n </div>\n )}\n\n {(errorText || statusText) && (\n <div className={`w3a-email-recovery-status${errorText ? ' is-error' : ''}`}>\n {errorText ? errorText : statusText}\n {pollingElapsedMs != null && !Number.isNaN(pollingElapsedMs) && pollingElapsedMs > 0 && (\n <span className=\"w3a-email-recovery-elapsed\">\n (~{Math.round(pollingElapsedMs / 1000)}s)\n </span>\n )}\n </div>\n )}\n </div>\n );\n};\n\nexport default EmailRecoverySlide;\n"],"mappings":"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"}
1
+ {"version":3,"file":"EmailRecoverySlide.js","names":["EmailRecoverySlide: React.FC<EmailRecoverySlideProps>","localEmails: string[]","info: EmailRecoveryAccountInfo | null","err: any"],"sources":["../../../../../../src/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.tsx"],"sourcesContent":["import React from 'react';\n\nimport type { EmailRecoverySSEEvent } from '@/core/types/sdkSentEvents';\nimport type { TatchiPasskey } from '@/core/TatchiPasskey';\nimport { IndexedDBManager } from '@/core/IndexedDBManager';\nimport { toAccountId } from '@/core/types/accountIds';\n\nexport interface EmailRecoverySlideProps {\n tatchiPasskey: TatchiPasskey;\n accountId: string;\n refreshLoginState?: (nearAccountId?: string) => Promise<void>;\n emailRecoveryOptions?: {\n onEvent?: (event: EmailRecoverySSEEvent) => void;\n onError?: (error: Error) => void;\n };\n}\n\ntype EmailRecoveryPolicy = {\n minRequiredEmails?: number;\n maxAgeMs?: number;\n};\n\ntype EmailRecoveryAccountInfo = {\n emailsCount: number;\n};\n\ntype MailtoUiState = 'ready' | 'opening';\n\nexport const EmailRecoverySlide: React.FC<EmailRecoverySlideProps> = ({ tatchiPasskey, accountId, refreshLoginState, emailRecoveryOptions }) => {\n const mountedRef = React.useRef(true);\n const mailtoAttemptTimerRef = React.useRef<number | null>(null);\n const cancelRequestedRef = React.useRef(false);\n React.useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n if (mailtoAttemptTimerRef.current != null) {\n window.clearTimeout(mailtoAttemptTimerRef.current);\n mailtoAttemptTimerRef.current = null;\n }\n };\n }, []);\n\n const [isBusy, setIsBusy] = React.useState(false);\n const [accountIdInput, setAccountIdInput] = React.useState('');\n const [recoveryEmailInput, setRecoveryEmailInput] = React.useState('');\n const [pendingMailtoUrl, setPendingMailtoUrl] = React.useState<string | null>(null);\n const [mailtoUiState, setMailtoUiState] = React.useState<MailtoUiState>('ready');\n const [statusText, setStatusText] = React.useState<string | null>(null);\n const [pollingElapsedMs, setPollingElapsedMs] = React.useState<number | null>(null);\n const [errorText, setErrorText] = React.useState<string | null>(null);\n const [accountInfo, setAccountInfo] = React.useState<EmailRecoveryAccountInfo | null>(null);\n const [accountInfoLoading, setAccountInfoLoading] = React.useState(false);\n const [accountInfoError, setAccountInfoError] = React.useState<string | null>(null);\n const [localRecoveryEmails, setLocalRecoveryEmails] = React.useState<string[]>([]);\n const [explorerToast, setExplorerToast] = React.useState<{ url: string; accountId?: string; transactionHash?: string } | null>(null);\n\n const lastPrefilledAccountIdRef = React.useRef<string>('');\n const lastPrefilledRecoveryEmailRef = React.useRef<string>('');\n\n React.useEffect(() => {\n const next = (accountId || '').trim();\n if (!next) return;\n if (accountIdInput.trim() === '' || accountIdInput === lastPrefilledAccountIdRef.current) {\n lastPrefilledAccountIdRef.current = next;\n setAccountIdInput(next);\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [accountId]);\n\n React.useEffect(() => {\n setPendingMailtoUrl(null);\n setMailtoUiState('ready');\n cancelRequestedRef.current = false;\n setStatusText(null);\n setPollingElapsedMs(null);\n setErrorText(null);\n setAccountInfo(null);\n setAccountInfoError(null);\n setLocalRecoveryEmails([]);\n setExplorerToast(null);\n if (mailtoAttemptTimerRef.current != null) {\n window.clearTimeout(mailtoAttemptTimerRef.current);\n mailtoAttemptTimerRef.current = null;\n }\n }, [accountId]);\n\n const safeSet = <T,>(setter: React.Dispatch<React.SetStateAction<T>>) => {\n return (value: React.SetStateAction<T>) => {\n if (!mountedRef.current) return;\n setter(value);\n };\n };\n\n const safeSetPendingMailtoUrl = React.useMemo(() => safeSet(setPendingMailtoUrl), []);\n const safeSetStatusText = React.useMemo(() => safeSet(setStatusText), []);\n const safeSetPollingElapsedMs = React.useMemo(() => safeSet(setPollingElapsedMs), []);\n const safeSetErrorText = React.useMemo(() => safeSet(setErrorText), []);\n const safeSetIsBusy = React.useMemo(() => safeSet(setIsBusy), []);\n const safeSetAccountInfo = React.useMemo(() => safeSet(setAccountInfo), []);\n const safeSetAccountInfoLoading = React.useMemo(() => safeSet(setAccountInfoLoading), []);\n const safeSetAccountInfoError = React.useMemo(() => safeSet(setAccountInfoError), []);\n const safeSetLocalRecoveryEmails = React.useMemo(() => safeSet(setLocalRecoveryEmails), []);\n const safeSetExplorerToast = React.useMemo(() => safeSet(setExplorerToast), []);\n const safeSetMailtoUiState = React.useMemo(() => safeSet(setMailtoUiState), []);\n\n const onEvent = React.useCallback(\n (ev: EmailRecoverySSEEvent) => {\n if (cancelRequestedRef.current) return;\n safeSetStatusText(ev?.message || null);\n emailRecoveryOptions?.onEvent?.(ev);\n\n const data = (ev as any)?.data || {};\n const rawTxHash = data?.transactionHash ?? data?.transaction_hash;\n const txHash = typeof rawTxHash === 'string' ? rawTxHash.trim() : '';\n if (txHash) {\n const base = String(tatchiPasskey.configs?.nearExplorerUrl || 'https://testnet.nearblocks.io').replace(/\\/$/, '');\n const url = base.includes('nearblocks.io')\n ? `${base}/txns/${txHash}`\n : `${base}/transactions/${txHash}`;\n safeSetExplorerToast({ url, transactionHash: txHash });\n }\n const elapsedRaw = data?.elapsedMs ?? data?.elapsed_ms;\n if (elapsedRaw == null) safeSetPollingElapsedMs(null);\n const elapsed = elapsedRaw == null ? Number.NaN : Number(elapsedRaw);\n if (!Number.isNaN(elapsed)) safeSetPollingElapsedMs(elapsed);\n\n if (ev?.phase === 'email-recovery-error' || (ev as any)?.status === 'error') {\n const raw = (ev as any)?.error || ev?.message || 'Email recovery failed';\n safeSetErrorText(String(raw));\n }\n },\n [emailRecoveryOptions, safeSetErrorText, safeSetExplorerToast, safeSetPollingElapsedMs, safeSetStatusText, tatchiPasskey],\n );\n\n const showExplorerToast = React.useCallback(\n (rawAccountId: string) => {\n const normalized = (rawAccountId || '').trim();\n if (!normalized) return;\n const base = String(tatchiPasskey.configs?.nearExplorerUrl || 'https://testnet.nearblocks.io').replace(/\\/$/, '');\n const url = base.includes('nearblocks.io')\n ? `${base}/address/${normalized}`\n : `${base}/accounts/${normalized}`;\n\n safeSetExplorerToast({ url, accountId: normalized });\n },\n [safeSetExplorerToast, tatchiPasskey],\n );\n\n const launchMailto = React.useCallback((rawMailtoUrl: string) => {\n const url = String(rawMailtoUrl || '').trim();\n if (!url) return;\n\n if (typeof window !== 'undefined') {\n try {\n window.location.href = url;\n } catch {}\n }\n }, []);\n\n const attemptOpenMailtoFromUserGesture = React.useCallback(\n (rawMailtoUrl: string) => {\n const url = String(rawMailtoUrl || '').trim();\n if (!url) return;\n\n safeSetMailtoUiState('opening');\n\n if (mailtoAttemptTimerRef.current != null) {\n window.clearTimeout(mailtoAttemptTimerRef.current);\n }\n\n // If the browser never blurs/hides (i.e. mailto blocked or cancelled), re-enable so users can retry.\n mailtoAttemptTimerRef.current = window.setTimeout(() => {\n safeSetMailtoUiState(prev => (prev === 'opening' ? 'ready' : prev));\n mailtoAttemptTimerRef.current = null;\n }, 2_000);\n\n launchMailto(url);\n },\n [launchMailto, safeSetMailtoUiState],\n );\n\n const attemptOpenMailtoAuto = React.useCallback(\n (rawMailtoUrl: string) => {\n const url = String(rawMailtoUrl || '').trim();\n if (!url) return;\n // Best-effort only: do not change `mailtoUiState` so users can immediately click the CTA.\n launchMailto(url);\n },\n [launchMailto],\n );\n\n React.useEffect(() => {\n if (mailtoUiState !== 'opening') return;\n if (typeof window === 'undefined' || typeof document === 'undefined') return;\n\n // Heuristic signals that the mail client likely opened. Treat as a hint only:\n // re-enable immediately so the CTA remains retryable even if this is a false-positive.\n const markMaybeOpened = () => {\n safeSetMailtoUiState('ready');\n if (mailtoAttemptTimerRef.current != null) {\n window.clearTimeout(mailtoAttemptTimerRef.current);\n mailtoAttemptTimerRef.current = null;\n }\n };\n\n const onVisibilityChange = () => {\n if (document.visibilityState === 'hidden') markMaybeOpened();\n };\n\n window.addEventListener('blur', markMaybeOpened);\n window.addEventListener('pagehide', markMaybeOpened);\n document.addEventListener('visibilitychange', onVisibilityChange);\n\n return () => {\n window.removeEventListener('blur', markMaybeOpened);\n window.removeEventListener('pagehide', markMaybeOpened);\n document.removeEventListener('visibilitychange', onVisibilityChange);\n };\n }, [mailtoUiState, safeSetMailtoUiState]);\n\n const fetchLocalRecoveryEmailsFromIndexedDB = React.useCallback(\n async (rawAccountId: string): Promise<string[]> => {\n const normalized = (rawAccountId || '').trim();\n if (!normalized) {\n console.log('[EmailRecoverySlide] fetchLocalRecoveryEmails: empty accountId');\n return [];\n }\n\n try {\n console.log('[EmailRecoverySlide] fetchLocalRecoveryEmails: loading from IndexedDB', { accountId: normalized });\n const records = await IndexedDBManager.getRecoveryEmails(toAccountId(normalized));\n console.log('[EmailRecoverySlide] fetchLocalRecoveryEmails: raw IndexedDB records', {\n accountId: normalized,\n count: Array.isArray(records) ? records.length : 0,\n records,\n });\n if (!Array.isArray(records) || records.length === 0) return [];\n\n const sorted = [...records].sort((a, b) => (b?.addedAt || 0) - (a?.addedAt || 0));\n const emails = sorted\n .map(r => String(r?.email || '').trim().toLowerCase())\n .filter(e => !!e && e.includes('@'));\n\n const uniq = Array.from(new Set(emails));\n console.log('[EmailRecoverySlide] fetchLocalRecoveryEmails: parsed emails', {\n accountId: normalized,\n emails: uniq,\n });\n return uniq;\n } catch (err) {\n // best-effort; treat as no saved emails (e.g., IndexedDB unavailable)\n console.log('[EmailRecoverySlide] fetchLocalRecoveryEmails: failed to read IndexedDB', {\n accountId: normalized,\n error: err instanceof Error ? err.message : String(err),\n });\n return [];\n }\n },\n [],\n );\n\n const deriveEmailsFromRecoveryRecords = React.useCallback((records: unknown): string[] => {\n if (!Array.isArray(records) || records.length === 0) return [];\n const emails = records\n .map((r: any) => String(r?.email || '').trim().toLowerCase())\n .filter((e: string) => !!e && e.includes('@'));\n return Array.from(new Set(emails));\n }, []);\n\n React.useEffect(() => {\n const normalized = (accountIdInput || '').trim();\n if (!normalized) {\n setAccountInfo(null);\n setAccountInfoError(null);\n setAccountInfoLoading(false);\n safeSetLocalRecoveryEmails([]);\n return;\n }\n\n let cancelled = false;\n // Show loading state immediately (don't wait for debounce).\n safeSetAccountInfoLoading(true);\n safeSetAccountInfoError(null);\n const handle = window.setTimeout(() => {\n void (async () => {\n try {\n const isWalletIframeMode = !!tatchiPasskey.configs?.iframeWallet?.walletOrigin;\n\n // Legacy mode: suggest recovery emails from local IndexedDB mapping (best-effort).\n let localEmails: string[] = [];\n if (!isWalletIframeMode) {\n localEmails = await fetchLocalRecoveryEmailsFromIndexedDB(normalized);\n if (!cancelled) {\n console.log('[EmailRecoverySlide] local saved emails (IndexedDB)', { accountId: normalized, localEmails });\n }\n }\n\n const records = await tatchiPasskey.getRecoveryEmails(normalized);\n const resolvedEmails = isWalletIframeMode\n ? deriveEmailsFromRecoveryRecords(records)\n : localEmails;\n\n if (!cancelled) {\n safeSetLocalRecoveryEmails(resolvedEmails);\n console.log('[EmailRecoverySlide] recovery email suggestions (state)', { accountId: normalized, emails: resolvedEmails });\n\n if (\n resolvedEmails.length === 1 &&\n (recoveryEmailInput.trim() === '' || recoveryEmailInput === lastPrefilledRecoveryEmailRef.current)\n ) {\n lastPrefilledRecoveryEmailRef.current = resolvedEmails[0];\n setRecoveryEmailInput(resolvedEmails[0]);\n }\n }\n\n const info: EmailRecoveryAccountInfo | null = records\n ? { emailsCount: Array.isArray(records) ? records.length : 0 }\n : null;\n if (cancelled) return;\n safeSetAccountInfo(info);\n } catch (err: any) {\n if (cancelled) return;\n safeSetAccountInfo(null);\n safeSetAccountInfoError(err?.message || 'Failed to load email recovery settings for this account');\n } finally {\n if (!cancelled) safeSetAccountInfoLoading(false);\n }\n })();\n }, 350);\n\n return () => {\n cancelled = true;\n window.clearTimeout(handle);\n };\n }, [\n accountIdInput,\n deriveEmailsFromRecoveryRecords,\n fetchLocalRecoveryEmailsFromIndexedDB,\n recoveryEmailInput,\n safeSetAccountInfo,\n safeSetAccountInfoError,\n safeSetAccountInfoLoading,\n safeSetLocalRecoveryEmails,\n tatchiPasskey,\n ]);\n\n const handleStart = React.useCallback(async () => {\n const normalizedAccountId = (accountIdInput || '').trim();\n if (!normalizedAccountId) {\n safeSetErrorText('Enter an account ID.');\n return;\n }\n\n const emailCandidate = (recoveryEmailInput || '').trim().toLowerCase();\n if (!emailCandidate) {\n safeSetErrorText('Enter the recovery email to send from.');\n return;\n }\n\n safeSetIsBusy(true);\n cancelRequestedRef.current = false;\n safeSetErrorText(null);\n safeSetStatusText(null);\n safeSetPollingElapsedMs(null);\n safeSetPendingMailtoUrl(null);\n safeSetMailtoUiState('ready');\n\n let didForwardError = false;\n try {\n const result = await tatchiPasskey.startEmailRecovery({\n accountId: normalizedAccountId,\n recoveryEmail: emailCandidate,\n options: {\n onEvent,\n onError: (err: Error) => {\n if (cancelRequestedRef.current) return;\n safeSetErrorText(err?.message || 'Failed to start email recovery');\n didForwardError = true;\n emailRecoveryOptions?.onError?.(err);\n },\n afterCall: async () => {},\n } as any,\n });\n\n safeSetPendingMailtoUrl(result.mailtoUrl);\n safeSetStatusText('Recovery email draft ready. If it didn’t open automatically, click “Open recovery email draft”. Waiting for verification…');\n\n // Best-effort open. If blocked/cancelled, the CTA remains immediately clickable for a user-gesture retry.\n attemptOpenMailtoAuto(result.mailtoUrl);\n\n // Start polling immediately after attempting to open the email prompt.\n const finalizePromise = tatchiPasskey.finalizeEmailRecovery({\n accountId: normalizedAccountId,\n nearPublicKey: result.nearPublicKey,\n options: {\n onEvent,\n onError: (err: Error) => {\n if (cancelRequestedRef.current) return;\n safeSetErrorText(err?.message || 'Failed to finalize email recovery');\n didForwardError = true;\n emailRecoveryOptions?.onError?.(err);\n },\n afterCall: async () => {},\n } as any,\n });\n\n showExplorerToast(normalizedAccountId);\n\n await finalizePromise;\n\n // Best-effort auto-login: the core flow attempts it, but if it couldn't (e.g. missing Shamir\n // auto-unlock and user cancelled TouchID), try once more here.\n let loginOk = false;\n const session = await tatchiPasskey.getLoginSession(normalizedAccountId).catch(() => null);\n if (session?.login?.isLoggedIn) {\n loginOk = true;\n } else {\n safeSetStatusText('Email recovery completed. Logging you in…');\n loginOk = await tatchiPasskey.loginAndCreateSession(normalizedAccountId)\n .then(() => true)\n .catch(() => false);\n }\n\n if (refreshLoginState) {\n await refreshLoginState(normalizedAccountId).catch(() => {});\n }\n\n safeSetStatusText(loginOk ? 'Email recovery completed on this device.' : 'Email recovery completed. Please log in on this device.');\n safeSetPendingMailtoUrl(null);\n safeSetMailtoUiState('ready');\n safeSetPollingElapsedMs(null);\n } catch (err: any) {\n if (cancelRequestedRef.current) {\n safeSetErrorText('Email recovery cancelled. Please try again.');\n safeSetStatusText(null);\n safeSetPollingElapsedMs(null);\n safeSetPendingMailtoUrl(null);\n safeSetMailtoUiState('ready');\n return;\n }\n safeSetErrorText(err?.message || 'Failed to start email recovery');\n if (!didForwardError && err instanceof Error) {\n emailRecoveryOptions?.onError?.(err);\n }\n } finally {\n safeSetIsBusy(false);\n }\n }, [\n accountIdInput,\n emailRecoveryOptions,\n recoveryEmailInput,\n onEvent,\n refreshLoginState,\n showExplorerToast,\n safeSetErrorText,\n safeSetIsBusy,\n safeSetPendingMailtoUrl,\n safeSetPollingElapsedMs,\n safeSetStatusText,\n safeSetMailtoUiState,\n attemptOpenMailtoAuto,\n tatchiPasskey,\n ]);\n\n const summaryLine = accountInfoLoading\n ? 'Checking if account has recovery emails configured...'\n : accountInfo && !accountInfoError\n ? `Recovery emails configured: ${accountInfo.emailsCount}`\n : '\\u00A0';\n\n const noRecoveryEmailsConfigured =\n !accountInfoLoading && !accountInfoError && !!accountInfo && accountInfo.emailsCount === 0;\n\n return (\n <div className=\"w3a-email-recovery-slide\">\n <div className=\"w3a-email-recovery-title\">Recover Account with Email</div>\n <div className=\"w3a-email-recovery-help\">\n Send a special recovery email from your recovery email address.\n Your account will be recovered with a new key once the email is verified.\n </div>\n\n <div className=\"w3a-email-recovery-field\">\n <div className=\"w3a-input-pill w3a-email-recovery-input-pill\">\n <div className=\"w3a-input-wrap\">\n <input\n type=\"text\"\n value={accountIdInput}\n onChange={(e) => setAccountIdInput(e.target.value)}\n placeholder=\"NEAR account ID (e.g. alice.testnet)\"\n className=\"w3a-input\"\n autoCapitalize=\"none\"\n autoCorrect=\"off\"\n spellCheck={false}\n inputMode=\"text\"\n disabled={isBusy}\n />\n </div>\n </div>\n </div>\n\n <div className=\"w3a-email-recovery-summary\" aria-live=\"polite\">\n <div>{summaryLine}</div>\n </div>\n\n <div className=\"w3a-email-recovery-field\">\n <div className=\"w3a-input-pill w3a-email-recovery-input-pill\">\n <div className=\"w3a-input-wrap\">\n <input\n type=\"email\"\n value={recoveryEmailInput}\n onChange={(e) => setRecoveryEmailInput(e.target.value)}\n placeholder=\"Recovery email to send from\"\n className=\"w3a-input\"\n list={localRecoveryEmails.length > 0 ? 'w3a-email-recovery-saved-emails' : undefined}\n autoCapitalize=\"none\"\n autoCorrect=\"off\"\n spellCheck={false}\n inputMode=\"email\"\n disabled={isBusy || noRecoveryEmailsConfigured}\n />\n </div>\n </div>\n </div>\n\n {localRecoveryEmails.length > 0 && (\n <div className=\"w3a-email-recovery-summary\" aria-live=\"polite\">\n <div>Saved on this device:</div>\n <div className=\"w3a-email-recovery-saved-emails\">\n {localRecoveryEmails.map((email) => (\n <button\n key={email}\n type=\"button\"\n className=\"w3a-email-recovery-email-chip\"\n onClick={() => setRecoveryEmailInput(email)}\n disabled={isBusy}\n >\n {email}\n </button>\n ))}\n </div>\n </div>\n )}\n\n {localRecoveryEmails.length > 0 && (\n <datalist id=\"w3a-email-recovery-saved-emails\">\n {localRecoveryEmails.map((email) => (\n <option key={email} value={email} />\n ))}\n </datalist>\n )}\n\n <div className=\"w3a-email-recovery-actions\">\n {(!pendingMailtoUrl || !isBusy) && (\n <button\n onClick={handleStart}\n className=\"w3a-link-device-btn w3a-link-device-btn-primary\"\n disabled={isBusy || noRecoveryEmailsConfigured}\n >\n {noRecoveryEmailsConfigured ? 'No recovery emails configured' : (isBusy ? 'Working…' : 'Start Email Recovery')}\n </button>\n )}\n\n {pendingMailtoUrl && (\n <button\n type=\"button\"\n onClick={() => attemptOpenMailtoFromUserGesture(pendingMailtoUrl)}\n className=\"w3a-link-device-btn w3a-link-device-btn-primary\"\n disabled={mailtoUiState === 'opening'}\n aria-busy={mailtoUiState === 'opening'}\n >\n {mailtoUiState === 'opening' && <span className=\"w3a-spinner\" aria-hidden=\"true\" />}\n {mailtoUiState === 'opening' ? 'Opening email…' : 'Open recovery email draft'}\n </button>\n )}\n </div>\n\n {(errorText || statusText || explorerToast) && (\n <div className={`w3a-email-recovery-status${errorText ? ' is-error' : ''}`}>\n {errorText ? errorText : statusText}\n {pollingElapsedMs != null && !Number.isNaN(pollingElapsedMs) && pollingElapsedMs > 0 && (\n <span className=\"w3a-email-recovery-elapsed\">\n (~{Math.round(pollingElapsedMs / 1000)}s).\n </span>\n )}\n {explorerToast && (\n <>\n <br />\n <a className=\"w3a-email-recovery-link\" href={explorerToast.url} target=\"_blank\" rel=\"noopener noreferrer\">\n View on explorer\n </a>\n </>\n )}\n </div>\n )}\n </div>\n );\n};\n\nexport default EmailRecoverySlide;\n"],"mappings":"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"}
@@ -110,4 +110,4 @@
110
110
  }
111
111
 
112
112
 
113
- /*# sourceMappingURL=ShowQRCode-DCnR__fx.css.map*/
113
+ /*# sourceMappingURL=ShowQRCode-nZhZSaba.css.map*/
@@ -1 +1 @@
1
- {"version":3,"file":"ShowQRCode-DCnR__fx.css","names":[],"sources":["../../../../src/react/components/ShowQRCode.css"],"sourcesContent":[".qr-code-container {\n padding-top: 1rem;\n}\n\n/* Modal Header */\n.qr-header {\n position: relative;\n display: grid;\n place-content: center;\n padding: 0rem;\n}\n\n.qr-title {\n font-size: 1.5rem;\n font-weight: 700;\n color: var(--w3a-colors-textPrimary, #1e293b);\n padding-top: 0rem;\n margin: 0;\n}\n\n.qr-body {\n padding: 0rem;\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n.qr-code-section {\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n/* QR Code Display */\n.qr-code-display {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 0rem;\n padding: 1rem;\n border-radius: 1.5rem;\n width: 100%;\n max-width: 300px;\n}\n\n.qr-instruction, .qr-status {\n margin: 0;\n font-size: 1rem;\n font-weight: 500;\n line-height: 1.5;\n color: var(--w3a-colors-textSecondary, #1e293b);\n text-align: center;\n}\n\n.qr-status {\n margin-bottom: 0.5rem;\n}\n\n.animated-ellipsis {\n display: inline-block;\n width: 1.2em;\n text-align: left;\n}\n\n.animated-ellipsis::after {\n content: \"...\";\n animation: ellipsis 1.5s infinite;\n}\n\n@keyframes ellipsis {\n 0% { content: \"...\"; }\n 25% { content: \"\"; }\n 50% { content: \".\"; }\n 75% { content: \"..\"; }\n 100% { content: \"...\"; }\n}\n\n.qr-code-image {\n max-width: 200px;\n height: auto;\n border-radius: var(--w3a-border-radius-md, 0.5rem);\n}\n\n.qr-loading {\n text-align: center;\n padding: 2rem;\n color: var(--w3a-colors-textSecondary, #64748b);\n}\n\n/* Responsive Design */\n@media (max-width: 768px) {\n .qr-modal-content {\n margin: 1rem;\n max-width: calc(100vw - 2rem);\n }\n\n @supports (width: 1dvw) {\n .qr-modal-content { max-width: calc(100dvw - 2rem); }\n }\n\n .qr-code-image {\n max-width: 200px;\n }\n\n .qr-code-display {\n padding: 1rem;\n }\n}\n"],"mappings":"AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA"}
1
+ {"version":3,"file":"ShowQRCode-nZhZSaba.css","names":[],"sources":["../../../../src/react/components/ShowQRCode.css"],"sourcesContent":[".qr-code-container {\n padding-top: 1rem;\n}\n\n/* Modal Header */\n.qr-header {\n position: relative;\n display: grid;\n place-content: center;\n padding: 0rem;\n}\n\n.qr-title {\n font-size: 1.5rem;\n font-weight: 700;\n color: var(--w3a-colors-textPrimary, #1e293b);\n padding-top: 0rem;\n margin: 0;\n}\n\n.qr-body {\n padding: 0rem;\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n.qr-code-section {\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n}\n\n/* QR Code Display */\n.qr-code-display {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 0rem;\n padding: 1rem;\n border-radius: 1.5rem;\n width: 100%;\n max-width: 300px;\n}\n\n.qr-instruction, .qr-status {\n margin: 0;\n font-size: 1rem;\n font-weight: 500;\n line-height: 1.5;\n color: var(--w3a-colors-textSecondary, #1e293b);\n text-align: center;\n}\n\n.qr-status {\n margin-bottom: 0.5rem;\n}\n\n.animated-ellipsis {\n display: inline-block;\n width: 1.2em;\n text-align: left;\n}\n\n.animated-ellipsis::after {\n content: \"...\";\n animation: ellipsis 1.5s infinite;\n}\n\n@keyframes ellipsis {\n 0% { content: \"...\"; }\n 25% { content: \"\"; }\n 50% { content: \".\"; }\n 75% { content: \"..\"; }\n 100% { content: \"...\"; }\n}\n\n.qr-code-image {\n max-width: 200px;\n height: auto;\n border-radius: var(--w3a-border-radius-md, 0.5rem);\n}\n\n.qr-loading {\n text-align: center;\n padding: 2rem;\n color: var(--w3a-colors-textSecondary, #64748b);\n}\n\n/* Responsive Design */\n@media (max-width: 768px) {\n .qr-modal-content {\n margin: 1rem;\n max-width: calc(100vw - 2rem);\n }\n\n @supports (width: 1dvw) {\n .qr-modal-content { max-width: calc(100dvw - 2rem); }\n }\n\n .qr-code-image {\n max-width: 200px;\n }\n\n .qr-code-display {\n padding: 1rem;\n }\n}\n"],"mappings":"AAAA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA"}
@@ -1,97 +1,76 @@
1
+ import { __esm } from "./_virtual/rolldown_runtime.js";
2
+
1
3
  //#region src/react/deviceDetection.ts
2
- /**
3
- * Detects the current device type based on multiple indicators
4
- */
5
- const detectDeviceType = () => {
6
- const userAgent = navigator.userAgent.toLowerCase();
7
- const isMobileUA = /android|iphone|ipod|blackberry|iemobile|opera mini/i.test(userAgent);
8
- const isTabletUA = /ipad|tablet|kindle|playbook|silk/i.test(userAgent);
9
- const isTouchDevice = navigator.maxTouchPoints > 0;
10
- const screenWidth = window.screen.width;
11
- const isSmallScreen = screenWidth <= 480;
12
- const isMediumScreen = screenWidth <= 1024;
13
- const hasOrientation = "orientation" in window;
14
- if (isMobileUA || isTouchDevice && isSmallScreen) return "mobile";
15
- if (isTabletUA || isTouchDevice && isMediumScreen && hasOrientation) return "tablet";
16
- return "desktop";
17
- };
18
- /**
19
- * Basic Safari detection (desktop Safari). Note: all iOS browsers use WebKit,
20
- * so use isIOS() to capture iOS Safari-like restrictions.
21
- */
22
- const isSafari = () => {
23
- try {
24
- const ua = navigator.userAgent;
25
- const isSafariEngine = /safari/i.test(ua) && !/chrome|crios|crmo|chromium|edg|edge|opr|opera|brave/i.test(ua);
26
- return isSafariEngine;
27
- } catch {
28
- return false;
29
- }
30
- };
31
- /**
32
- * Detect iOS (covers iPhone/iPad/iPod and iPadOS with desktop UA).
33
- * iOS has WebAuthn user-activation quirks that are shared by all iOS browsers.
34
- */
35
- const isIOS = () => {
36
- try {
37
- const ua = navigator.userAgent;
38
- const platform = navigator.platform || "";
39
- const maxTouch = Number(navigator.maxTouchPoints || 0);
40
- const iOSUA = /iPad|iPhone|iPod/.test(ua);
41
- const iPadOSMacLike = /Macintosh/.test(ua) && maxTouch > 1;
42
- const iOSPlatform = /iPad|iPhone|iPod/.test(platform);
43
- return iOSUA || iPadOSMacLike || iOSPlatform;
44
- } catch {
45
- return false;
46
- }
47
- };
48
- /**
49
- * Returns true when the page currently has a transient user activation
50
- * (click/tap/key within the allowed time window).
51
- */
52
- const hasActiveUserActivation = () => {
53
- try {
54
- const ua = navigator.userActivation;
55
- return !!(ua && typeof ua.isActive === "boolean" && ua.isActive);
56
- } catch {
57
- return false;
58
- }
59
- };
60
- /**
61
- * Heuristic: when on Safari/iOS or on a mobile device AND no active user
62
- * activation, we should surface a clickable UI to capture activation.
63
- */
64
- const needsExplicitActivation = () => {
65
- try {
66
- if (hasActiveUserActivation()) return false;
67
- return isIOS() || isMobileDevice() || isSafari();
68
- } catch {
69
- return false;
70
- }
71
- };
72
- /**
73
- * Determines optimal camera facing mode based on device type
74
- * - Mobile/Tablet: Back camera (environment) for QR scanning
75
- * - Desktop/Laptop: Front camera (user) for video calls/selfies
76
- */
77
- const getOptimalCameraFacingMode = () => {
78
- const deviceType = detectDeviceType();
79
- switch (deviceType) {
80
- case "mobile":
81
- case "tablet":
82
- console.log(`${deviceType} device detected - using back camera (environment)`);
83
- return "environment";
84
- case "desktop":
85
- default: return "user";
86
- }
87
- };
88
- /**
89
- * Check if the current device is likely mobile
90
- */
91
- const isMobileDevice = () => {
92
- return detectDeviceType() === "mobile";
93
- };
4
+ var detectDeviceType, isSafari, isIOS, hasActiveUserActivation, needsExplicitActivation, getOptimalCameraFacingMode, isMobileDevice;
5
+ var init_deviceDetection = __esm({ "src/react/deviceDetection.ts": (() => {
6
+ detectDeviceType = () => {
7
+ const userAgent = navigator.userAgent.toLowerCase();
8
+ const isMobileUA = /android|iphone|ipod|blackberry|iemobile|opera mini/i.test(userAgent);
9
+ const isTabletUA = /ipad|tablet|kindle|playbook|silk/i.test(userAgent);
10
+ const isTouchDevice = navigator.maxTouchPoints > 0;
11
+ const screenWidth = window.screen.width;
12
+ const isSmallScreen = screenWidth <= 480;
13
+ const isMediumScreen = screenWidth <= 1024;
14
+ const hasOrientation = "orientation" in window;
15
+ if (isMobileUA || isTouchDevice && isSmallScreen) return "mobile";
16
+ if (isTabletUA || isTouchDevice && isMediumScreen && hasOrientation) return "tablet";
17
+ return "desktop";
18
+ };
19
+ isSafari = () => {
20
+ try {
21
+ const ua = navigator.userAgent;
22
+ const isSafariEngine = /safari/i.test(ua) && !/chrome|crios|crmo|chromium|edg|edge|opr|opera|brave/i.test(ua);
23
+ return isSafariEngine;
24
+ } catch {
25
+ return false;
26
+ }
27
+ };
28
+ isIOS = () => {
29
+ try {
30
+ const ua = navigator.userAgent;
31
+ const platform = navigator.platform || "";
32
+ const maxTouch = Number(navigator.maxTouchPoints || 0);
33
+ const iOSUA = /iPad|iPhone|iPod/.test(ua);
34
+ const iPadOSMacLike = /Macintosh/.test(ua) && maxTouch > 1;
35
+ const iOSPlatform = /iPad|iPhone|iPod/.test(platform);
36
+ return iOSUA || iPadOSMacLike || iOSPlatform;
37
+ } catch {
38
+ return false;
39
+ }
40
+ };
41
+ hasActiveUserActivation = () => {
42
+ try {
43
+ const ua = navigator.userActivation;
44
+ return !!(ua && typeof ua.isActive === "boolean" && ua.isActive);
45
+ } catch {
46
+ return false;
47
+ }
48
+ };
49
+ needsExplicitActivation = () => {
50
+ try {
51
+ if (hasActiveUserActivation()) return false;
52
+ return isIOS() || isMobileDevice() || isSafari();
53
+ } catch {
54
+ return false;
55
+ }
56
+ };
57
+ getOptimalCameraFacingMode = () => {
58
+ const deviceType = detectDeviceType();
59
+ switch (deviceType) {
60
+ case "mobile":
61
+ case "tablet":
62
+ console.log(`${deviceType} device detected - using back camera (environment)`);
63
+ return "environment";
64
+ case "desktop":
65
+ default: return "user";
66
+ }
67
+ };
68
+ isMobileDevice = () => {
69
+ return detectDeviceType() === "mobile";
70
+ };
71
+ }) });
94
72
 
95
73
  //#endregion
96
- export { detectDeviceType, getOptimalCameraFacingMode, hasActiveUserActivation, isIOS, isMobileDevice, isSafari, needsExplicitActivation };
74
+ init_deviceDetection();
75
+ export { detectDeviceType, getOptimalCameraFacingMode, hasActiveUserActivation, init_deviceDetection, isIOS, isMobileDevice, isSafari, needsExplicitActivation };
97
76
  //# sourceMappingURL=deviceDetection.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"deviceDetection.js","names":[],"sources":["../../../src/react/deviceDetection.ts"],"sourcesContent":["/**\n * Device detection utilities for camera and UI optimization\n */\n\nexport type DeviceType = 'mobile' | 'tablet' | 'desktop';\nexport type CameraFacingMode = 'user' | 'environment';\n\n/**\n * Detects the current device type based on multiple indicators\n */\nexport const detectDeviceType = (): DeviceType => {\n // Method 1: User agent detection\n const userAgent = navigator.userAgent.toLowerCase();\n const isMobileUA = /android|iphone|ipod|blackberry|iemobile|opera mini/i.test(userAgent);\n const isTabletUA = /ipad|tablet|kindle|playbook|silk/i.test(userAgent);\n\n // Method 2: Touch and screen size detection\n const isTouchDevice = navigator.maxTouchPoints > 0;\n const screenWidth = window.screen.width;\n const isSmallScreen = screenWidth <= 480;\n const isMediumScreen = screenWidth <= 1024;\n\n // Method 3: Orientation support (mobile/tablet indicator)\n const hasOrientation = 'orientation' in window;\n\n // Determine device type with priority: mobile > tablet > desktop\n if (isMobileUA || (isTouchDevice && isSmallScreen)) {\n return 'mobile';\n }\n\n if (isTabletUA || (isTouchDevice && isMediumScreen && hasOrientation)) {\n return 'tablet';\n }\n\n return 'desktop';\n};\n\n/**\n * Basic Safari detection (desktop Safari). Note: all iOS browsers use WebKit,\n * so use isIOS() to capture iOS Safari-like restrictions.\n */\nexport const isSafari = (): boolean => {\n try {\n const ua = navigator.userAgent;\n const isSafariEngine = /safari/i.test(ua) && !/chrome|crios|crmo|chromium|edg|edge|opr|opera|brave/i.test(ua);\n return isSafariEngine;\n } catch {\n return false;\n }\n};\n\n/**\n * Detect iOS (covers iPhone/iPad/iPod and iPadOS with desktop UA).\n * iOS has WebAuthn user-activation quirks that are shared by all iOS browsers.\n */\nexport const isIOS = (): boolean => {\n try {\n const ua = navigator.userAgent;\n const platform = (navigator as any).platform || '';\n const maxTouch = Number(navigator.maxTouchPoints || 0);\n const iOSUA = /iPad|iPhone|iPod/.test(ua);\n const iPadOSMacLike = /Macintosh/.test(ua) && maxTouch > 1; // iPadOS masquerading as Mac\n const iOSPlatform = /iPad|iPhone|iPod/.test(platform);\n return iOSUA || iPadOSMacLike || iOSPlatform;\n } catch {\n return false;\n }\n};\n\n/**\n * Detect Mobile Safari (iOS Safari specifically). Chrome/Firefox on iOS still use WebKit,\n * so for WebAuthn activation rules, prefer checking isIOS() as well.\n */\nexport const isMobileSafari = (): boolean => {\n try {\n const ua = navigator.userAgent;\n if (!isIOS()) return false;\n // Exclude Chrome/Firefox/Edge branded iOS browsers (still WebKit underneath)\n const branded = /crios|fxios|edgios|opios|mercury/i.test(ua);\n const safariToken = /safari/i.test(ua);\n return safariToken && !branded;\n } catch {\n return false;\n }\n};\n\n/**\n * Returns true when the page currently has a transient user activation\n * (click/tap/key within the allowed time window).\n */\nexport const hasActiveUserActivation = (): boolean => {\n try {\n const ua = (navigator as any).userActivation;\n return !!(ua && typeof ua.isActive === 'boolean' && ua.isActive);\n } catch {\n return false;\n }\n};\n\n/**\n * Heuristic: when on Safari/iOS or on a mobile device AND no active user\n * activation, we should surface a clickable UI to capture activation.\n */\nexport const needsExplicitActivation = (): boolean => {\n try {\n if (hasActiveUserActivation()) return false;\n return isIOS() || isMobileDevice() || isSafari();\n } catch {\n // In non-browser or SSR/test environments, avoid forcing UI changes\n return false;\n }\n};\n\n/**\n * Determines optimal camera facing mode based on device type\n * - Mobile/Tablet: Back camera (environment) for QR scanning\n * - Desktop/Laptop: Front camera (user) for video calls/selfies\n */\nexport const getOptimalCameraFacingMode = (): CameraFacingMode => {\n const deviceType = detectDeviceType();\n\n switch (deviceType) {\n case 'mobile':\n case 'tablet':\n console.log(`${deviceType} device detected - using back camera (environment)`);\n return 'environment';\n\n case 'desktop':\n default:\n return 'user';\n }\n};\n\n/**\n * Check if the current device is likely mobile\n */\nexport const isMobileDevice = (): boolean => {\n return detectDeviceType() === 'mobile';\n};\n\n/**\n * Check if the current device supports touch\n */\nexport const isTouchDevice = (): boolean => {\n return navigator.maxTouchPoints > 0;\n};\n\n/**\n * Get device capabilities for camera constraints\n */\nexport const getDeviceCapabilities = () => {\n const deviceType = detectDeviceType();\n const isTouch = isTouchDevice();\n const facingMode = getOptimalCameraFacingMode();\n\n return {\n deviceType,\n isTouch,\n recommendedFacingMode: facingMode,\n // Recommended camera constraints based on device\n cameraConstraints: {\n video: {\n facingMode,\n width: deviceType === 'mobile' ? { ideal: 720, min: 480 } : { ideal: 1280, min: 720 },\n height: deviceType === 'mobile' ? { ideal: 720, min: 480 } : { ideal: 720, min: 480 },\n aspectRatio: deviceType === 'mobile' ? { ideal: 1.0 } : { ideal: 16/9 }\n }\n }\n };\n};\n"],"mappings":";;;;AAUA,MAAa,yBAAqC;CAEhD,MAAM,YAAY,UAAU,UAAU;CACtC,MAAM,aAAa,sDAAsD,KAAK;CAC9E,MAAM,aAAa,oCAAoC,KAAK;CAG5D,MAAM,gBAAgB,UAAU,iBAAiB;CACjD,MAAM,cAAc,OAAO,OAAO;CAClC,MAAM,gBAAgB,eAAe;CACrC,MAAM,iBAAiB,eAAe;CAGtC,MAAM,iBAAiB,iBAAiB;AAGxC,KAAI,cAAe,iBAAiB,cAClC,QAAO;AAGT,KAAI,cAAe,iBAAiB,kBAAkB,eACpD,QAAO;AAGT,QAAO;;;;;;AAOT,MAAa,iBAA0B;AACrC,KAAI;EACF,MAAM,KAAK,UAAU;EACrB,MAAM,iBAAiB,UAAU,KAAK,OAAO,CAAC,uDAAuD,KAAK;AAC1G,SAAO;SACD;AACN,SAAO;;;;;;;AAQX,MAAa,cAAuB;AAClC,KAAI;EACF,MAAM,KAAK,UAAU;EACrB,MAAM,WAAY,UAAkB,YAAY;EAChD,MAAM,WAAW,OAAO,UAAU,kBAAkB;EACpD,MAAM,QAAQ,mBAAmB,KAAK;EACtC,MAAM,gBAAgB,YAAY,KAAK,OAAO,WAAW;EACzD,MAAM,cAAc,mBAAmB,KAAK;AAC5C,SAAO,SAAS,iBAAiB;SAC3B;AACN,SAAO;;;;;;;AAyBX,MAAa,gCAAyC;AACpD,KAAI;EACF,MAAM,KAAM,UAAkB;AAC9B,SAAO,CAAC,EAAE,MAAM,OAAO,GAAG,aAAa,aAAa,GAAG;SACjD;AACN,SAAO;;;;;;;AAQX,MAAa,gCAAyC;AACpD,KAAI;AACF,MAAI,0BAA2B,QAAO;AACtC,SAAO,WAAW,oBAAoB;SAChC;AAEN,SAAO;;;;;;;;AASX,MAAa,mCAAqD;CAChE,MAAM,aAAa;AAEnB,SAAQ,YAAR;EACE,KAAK;EACL,KAAK;AACH,WAAQ,IAAI,GAAG,WAAW;AAC1B,UAAO;EAET,KAAK;EACL,QACE,QAAO;;;;;;AAOb,MAAa,uBAAgC;AAC3C,QAAO,uBAAuB"}
1
+ {"version":3,"file":"deviceDetection.js","names":[],"sources":["../../../src/react/deviceDetection.ts"],"sourcesContent":["/**\n * Device detection utilities for camera and UI optimization\n */\n\nexport type DeviceType = 'mobile' | 'tablet' | 'desktop';\nexport type CameraFacingMode = 'user' | 'environment';\n\n/**\n * Detects the current device type based on multiple indicators\n */\nexport const detectDeviceType = (): DeviceType => {\n // Method 1: User agent detection\n const userAgent = navigator.userAgent.toLowerCase();\n const isMobileUA = /android|iphone|ipod|blackberry|iemobile|opera mini/i.test(userAgent);\n const isTabletUA = /ipad|tablet|kindle|playbook|silk/i.test(userAgent);\n\n // Method 2: Touch and screen size detection\n const isTouchDevice = navigator.maxTouchPoints > 0;\n const screenWidth = window.screen.width;\n const isSmallScreen = screenWidth <= 480;\n const isMediumScreen = screenWidth <= 1024;\n\n // Method 3: Orientation support (mobile/tablet indicator)\n const hasOrientation = 'orientation' in window;\n\n // Determine device type with priority: mobile > tablet > desktop\n if (isMobileUA || (isTouchDevice && isSmallScreen)) {\n return 'mobile';\n }\n\n if (isTabletUA || (isTouchDevice && isMediumScreen && hasOrientation)) {\n return 'tablet';\n }\n\n return 'desktop';\n};\n\n/**\n * Basic Safari detection (desktop Safari). Note: all iOS browsers use WebKit,\n * so use isIOS() to capture iOS Safari-like restrictions.\n */\nexport const isSafari = (): boolean => {\n try {\n const ua = navigator.userAgent;\n const isSafariEngine = /safari/i.test(ua) && !/chrome|crios|crmo|chromium|edg|edge|opr|opera|brave/i.test(ua);\n return isSafariEngine;\n } catch {\n return false;\n }\n};\n\n/**\n * Detect iOS (covers iPhone/iPad/iPod and iPadOS with desktop UA).\n * iOS has WebAuthn user-activation quirks that are shared by all iOS browsers.\n */\nexport const isIOS = (): boolean => {\n try {\n const ua = navigator.userAgent;\n const platform = (navigator as any).platform || '';\n const maxTouch = Number(navigator.maxTouchPoints || 0);\n const iOSUA = /iPad|iPhone|iPod/.test(ua);\n const iPadOSMacLike = /Macintosh/.test(ua) && maxTouch > 1; // iPadOS masquerading as Mac\n const iOSPlatform = /iPad|iPhone|iPod/.test(platform);\n return iOSUA || iPadOSMacLike || iOSPlatform;\n } catch {\n return false;\n }\n};\n\n/**\n * Detect Mobile Safari (iOS Safari specifically). Chrome/Firefox on iOS still use WebKit,\n * so for WebAuthn activation rules, prefer checking isIOS() as well.\n */\nexport const isMobileSafari = (): boolean => {\n try {\n const ua = navigator.userAgent;\n if (!isIOS()) return false;\n // Exclude Chrome/Firefox/Edge branded iOS browsers (still WebKit underneath)\n const branded = /crios|fxios|edgios|opios|mercury/i.test(ua);\n const safariToken = /safari/i.test(ua);\n return safariToken && !branded;\n } catch {\n return false;\n }\n};\n\n/**\n * Returns true when the page currently has a transient user activation\n * (click/tap/key within the allowed time window).\n */\nexport const hasActiveUserActivation = (): boolean => {\n try {\n const ua = (navigator as any).userActivation;\n return !!(ua && typeof ua.isActive === 'boolean' && ua.isActive);\n } catch {\n return false;\n }\n};\n\n/**\n * Heuristic: when on Safari/iOS or on a mobile device AND no active user\n * activation, we should surface a clickable UI to capture activation.\n */\nexport const needsExplicitActivation = (): boolean => {\n try {\n if (hasActiveUserActivation()) return false;\n return isIOS() || isMobileDevice() || isSafari();\n } catch {\n // In non-browser or SSR/test environments, avoid forcing UI changes\n return false;\n }\n};\n\n/**\n * Determines optimal camera facing mode based on device type\n * - Mobile/Tablet: Back camera (environment) for QR scanning\n * - Desktop/Laptop: Front camera (user) for video calls/selfies\n */\nexport const getOptimalCameraFacingMode = (): CameraFacingMode => {\n const deviceType = detectDeviceType();\n\n switch (deviceType) {\n case 'mobile':\n case 'tablet':\n console.log(`${deviceType} device detected - using back camera (environment)`);\n return 'environment';\n\n case 'desktop':\n default:\n return 'user';\n }\n};\n\n/**\n * Check if the current device is likely mobile\n */\nexport const isMobileDevice = (): boolean => {\n return detectDeviceType() === 'mobile';\n};\n\n/**\n * Check if the current device supports touch\n */\nexport const isTouchDevice = (): boolean => {\n return navigator.maxTouchPoints > 0;\n};\n\n/**\n * Get device capabilities for camera constraints\n */\nexport const getDeviceCapabilities = () => {\n const deviceType = detectDeviceType();\n const isTouch = isTouchDevice();\n const facingMode = getOptimalCameraFacingMode();\n\n return {\n deviceType,\n isTouch,\n recommendedFacingMode: facingMode,\n // Recommended camera constraints based on device\n cameraConstraints: {\n video: {\n facingMode,\n width: deviceType === 'mobile' ? { ideal: 720, min: 480 } : { ideal: 1280, min: 720 },\n height: deviceType === 'mobile' ? { ideal: 720, min: 480 } : { ideal: 720, min: 480 },\n aspectRatio: deviceType === 'mobile' ? { ideal: 1.0 } : { ideal: 16/9 }\n }\n }\n };\n};\n"],"mappings":";;;;;CAUa,yBAAqC;EAEhD,MAAM,YAAY,UAAU,UAAU;EACtC,MAAM,aAAa,sDAAsD,KAAK;EAC9E,MAAM,aAAa,oCAAoC,KAAK;EAG5D,MAAM,gBAAgB,UAAU,iBAAiB;EACjD,MAAM,cAAc,OAAO,OAAO;EAClC,MAAM,gBAAgB,eAAe;EACrC,MAAM,iBAAiB,eAAe;EAGtC,MAAM,iBAAiB,iBAAiB;AAGxC,MAAI,cAAe,iBAAiB,cAClC,QAAO;AAGT,MAAI,cAAe,iBAAiB,kBAAkB,eACpD,QAAO;AAGT,SAAO;;CAOI,iBAA0B;AACrC,MAAI;GACF,MAAM,KAAK,UAAU;GACrB,MAAM,iBAAiB,UAAU,KAAK,OAAO,CAAC,uDAAuD,KAAK;AAC1G,UAAO;UACD;AACN,UAAO;;;CAQE,cAAuB;AAClC,MAAI;GACF,MAAM,KAAK,UAAU;GACrB,MAAM,WAAY,UAAkB,YAAY;GAChD,MAAM,WAAW,OAAO,UAAU,kBAAkB;GACpD,MAAM,QAAQ,mBAAmB,KAAK;GACtC,MAAM,gBAAgB,YAAY,KAAK,OAAO,WAAW;GACzD,MAAM,cAAc,mBAAmB,KAAK;AAC5C,UAAO,SAAS,iBAAiB;UAC3B;AACN,UAAO;;;CAyBE,gCAAyC;AACpD,MAAI;GACF,MAAM,KAAM,UAAkB;AAC9B,UAAO,CAAC,EAAE,MAAM,OAAO,GAAG,aAAa,aAAa,GAAG;UACjD;AACN,UAAO;;;CAQE,gCAAyC;AACpD,MAAI;AACF,OAAI,0BAA2B,QAAO;AACtC,UAAO,WAAW,oBAAoB;UAChC;AAEN,UAAO;;;CASE,mCAAqD;EAChE,MAAM,aAAa;AAEnB,UAAQ,YAAR;GACE,KAAK;GACL,KAAK;AACH,YAAQ,IAAI,GAAG,WAAW;AAC1B,WAAO;GAET,KAAK;GACL,QACE,QAAO;;;CAOA,uBAAgC;AAC3C,SAAO,uBAAuB"}
@@ -12,9 +12,12 @@ function usePreconnectWalletAssets(config) {
12
12
  if (typeof document === "undefined") return;
13
13
  let isCrossOrigin = false;
14
14
  let walletOriginOrigin = void 0;
15
+ let walletIsHttp = false;
15
16
  try {
16
17
  if (walletOrigin) {
17
- walletOriginOrigin = new URL(walletOrigin, window.location.href).origin;
18
+ const url = new URL(walletOrigin, window.location.href);
19
+ walletOriginOrigin = url.origin;
20
+ walletIsHttp = url.protocol === "http:" || url.protocol === "https:";
18
21
  const parentOrigin = window.location.origin;
19
22
  isCrossOrigin = walletOriginOrigin !== parentOrigin;
20
23
  if (isCrossOrigin) {
@@ -42,35 +45,37 @@ function usePreconnectWalletAssets(config) {
42
45
  } catch {}
43
46
  };
44
47
  if (walletOrigin) {
45
- ensureLink("dns-prefetch", walletOrigin);
46
- ensureLink("preconnect", walletOrigin, { crossorigin: "" });
47
- if (!isCrossOrigin) try {
48
- const serviceUrl = new URL(servicePath, walletOrigin).toString();
49
- ensureLink("prefetch", serviceUrl, { as: "document" });
50
- } catch {}
51
- try {
52
- const sdkPath = sdkBasePath || "/sdk";
53
- const withSlash = sdkPath.endsWith("/") ? sdkPath : sdkPath + "/";
54
- const base = new URL(withSlash, walletOrigin);
55
- const hostJs = new URL("wallet-iframe-host.js", base).toString();
56
- ensureLink("modulepreload", hostJs, { crossorigin: "" });
57
- try {
58
- const signerWasm = new URL("workers/wasm_signer_worker_bg.wasm", base).toString();
59
- ensureLink("prefetch", signerWasm, {
60
- as: "fetch",
61
- crossorigin: "",
62
- type: "application/wasm"
63
- });
48
+ if (walletIsHttp && walletOriginOrigin) {
49
+ ensureLink("dns-prefetch", walletOriginOrigin);
50
+ ensureLink("preconnect", walletOriginOrigin, { crossorigin: "" });
51
+ if (!isCrossOrigin) try {
52
+ const serviceUrl = new URL(servicePath, walletOriginOrigin).toString();
53
+ ensureLink("prefetch", serviceUrl, { as: "document" });
64
54
  } catch {}
65
55
  try {
66
- const vrfWasm = new URL("workers/wasm_vrf_worker_bg.wasm", base).toString();
67
- ensureLink("prefetch", vrfWasm, {
68
- as: "fetch",
69
- crossorigin: "",
70
- type: "application/wasm"
71
- });
56
+ const sdkPath = sdkBasePath || "/sdk";
57
+ const withSlash = sdkPath.endsWith("/") ? sdkPath : sdkPath + "/";
58
+ const base = new URL(withSlash, walletOriginOrigin);
59
+ const hostJs = new URL("wallet-iframe-host.js", base).toString();
60
+ ensureLink("modulepreload", hostJs, { crossorigin: "" });
61
+ try {
62
+ const signerWasm = new URL("workers/wasm_signer_worker_bg.wasm", base).toString();
63
+ ensureLink("prefetch", signerWasm, {
64
+ as: "fetch",
65
+ crossorigin: "",
66
+ type: "application/wasm"
67
+ });
68
+ } catch {}
69
+ try {
70
+ const vrfWasm = new URL("workers/wasm_vrf_worker_bg.wasm", base).toString();
71
+ ensureLink("prefetch", vrfWasm, {
72
+ as: "fetch",
73
+ crossorigin: "",
74
+ type: "application/wasm"
75
+ });
76
+ } catch {}
72
77
  } catch {}
73
- } catch {}
78
+ }
74
79
  }
75
80
  if (relayerUrl) {
76
81
  ensureLink("dns-prefetch", relayerUrl);
@@ -1 +1 @@
1
- {"version":3,"file":"usePreconnectWalletAssets.js","names":["walletOriginOrigin: string | undefined"],"sources":["../../../../src/react/hooks/usePreconnectWalletAssets.ts"],"sourcesContent":["import React from 'react';\nimport type { TatchiContextProviderProps } from '../types';\nimport { setEmbeddedBase } from '../../core/sdkPaths';\n\n// Internal: Add preconnect/prefetch hints for wallet service + relayer and\n// expose an absolute embedded asset base for srcdoc iframes.\n//\n// What this hook does\n// - Adds resource hints for the configured wallet origin (dns‑prefetch, preconnect, prefetch)\n// and modulepreload for the wallet host script.\n// - Sets `window.__W3A_WALLET_SDK_BASE__` to an absolute `${walletOrigin}${sdkBasePath}/` so\n// any embedded srcdoc iframes created by the SDK load ESM bundles from the wallet origin,\n// not from the host app origin.\n//\n// Requirements\n// - `config.iframeWallet.walletOrigin` points to the wallet site (e.g. https://web3authn.org)\n// - `config.iframeWallet.sdkBasePath` (default '/sdk') is served on that wallet site\n// - `config.iframeWallet.walletServicePath` (default '/wallet-service') is reachable\n//\n// Gotchas\n// - Always resolve `${sdkBasePath}/...` with a trailing slash; otherwise `new URL('file', '/sdk')`\n// becomes `/file` instead of `/sdk/file`.\n// - For cross‑origin module/worker imports, ensure the wallet site sends CORS headers for\n// `/sdk/*` and `/sdk/workers/*` (e.g. `Access-Control-Allow-Origin: *`) and `.wasm` has\n// `Content-Type: application/wasm`.\n// - `/wallet-service` may 308 → `/wallet-service/` on Pages; both are fine.\nexport function usePreconnectWalletAssets(config: TatchiContextProviderProps['config']): void {\n // Derive stable primitives to avoid re-running the effect on object identity changes.\n const walletOrigin = config?.iframeWallet?.walletOrigin as string | undefined;\n const servicePath = config?.iframeWallet?.walletServicePath || '/wallet-service';\n const sdkBasePath = config?.iframeWallet?.sdkBasePath || '/sdk';\n const relayerUrl = config?.relayer?.url as string | undefined;\n\n React.useEffect(() => {\n try {\n if (typeof document === 'undefined') return;\n // Determine cross‑origin once per effect and expose absolute embedded base\n // for srcdoc iframes ONLY when wallet is cross‑origin.\n let isCrossOrigin = false;\n let walletOriginOrigin: string | undefined = undefined;\n try {\n if (walletOrigin) {\n walletOriginOrigin = new URL(walletOrigin, window.location.href).origin;\n const parentOrigin = window.location.origin;\n isCrossOrigin = walletOriginOrigin !== parentOrigin;\n if (isCrossOrigin) {\n const sdkPath = (sdkBasePath || '/sdk') as string;\n const withSlash = sdkPath.endsWith('/') ? sdkPath : sdkPath + '/';\n const abs = new URL(withSlash, walletOriginOrigin).toString();\n setEmbeddedBase(abs);\n }\n }\n } catch {}\n const ensureLink = (rel: string, href?: string, attrs?: Record<string, string>) => {\n try {\n if (!href) return;\n const head = document.head || document.getElementsByTagName('head')[0];\n if (!head) return;\n const selector = `link[rel=\"${rel}\"][href=\"${href}\"]`;\n if (head.querySelector(selector)) return;\n const link = document.createElement('link');\n link.rel = rel;\n link.href = href;\n if (attrs) {\n for (const [k, v] of Object.entries(attrs)) {\n try { link.setAttribute(k, v); } catch {}\n }\n }\n head.appendChild(link);\n } catch {}\n };\n\n if (walletOrigin) {\n // Reduce DNS/TLS handshake and fetch delays for the wallet origin\n ensureLink('dns-prefetch', walletOrigin);\n ensureLink('preconnect', walletOrigin, { crossorigin: '' });\n\n // Prefetch the service HTML document only in same‑origin dev.\n // Cross‑origin prefetch would require ACAO on the HTML, which we purposely avoid.\n if (!isCrossOrigin) {\n try {\n const serviceUrl = new URL(servicePath, walletOrigin).toString();\n ensureLink('prefetch', serviceUrl, { as: 'document' });\n } catch {}\n }\n\n // Preload the wallet host script module so the iframe boots faster\n // Ensure the base URL ends with a trailing slash; otherwise new URL('file', base)\n // would replace the last path segment (\"/sdk\") and yield \"/wallet-iframe-host.js\".\n try {\n const sdkPath = (sdkBasePath || '/sdk') as string;\n const withSlash = sdkPath.endsWith('/') ? sdkPath : sdkPath + '/';\n const base = new URL(withSlash, walletOrigin);\n const hostJs = new URL('wallet-iframe-host.js', base).toString();\n ensureLink('modulepreload', hostJs, { crossorigin: '' });\n\n // Optionally prefetch WASM binaries to accelerate first-use while avoiding preload warnings\n // Requires CORS + correct MIME (application/wasm) on the wallet origin\n try {\n const signerWasm = new URL('workers/wasm_signer_worker_bg.wasm', base).toString();\n ensureLink('prefetch', signerWasm, { as: 'fetch', crossorigin: '', type: 'application/wasm' } as any);\n } catch {}\n try {\n const vrfWasm = new URL('workers/wasm_vrf_worker_bg.wasm', base).toString();\n ensureLink('prefetch', vrfWasm, { as: 'fetch', crossorigin: '', type: 'application/wasm' } as any);\n } catch {}\n\n // // Preload core CSS used by confirmer to reduce first-paint FOUC\n // const tokensCss = new URL('w3a-components.css', base).toString();\n // const txTreeCss = new URL('tx-tree.css', base).toString();\n // const txConfirmerCss = new URL('tx-confirmer.css', base).toString();\n // const drawerCss = new URL('drawer.css', base).toString();\n // ensureLink('preload', tokensCss, { as: 'style', crossorigin: '' });\n // ensureLink('preload', txTreeCss, { as: 'style', crossorigin: '' });\n // ensureLink('preload', modalCss, { as: 'style', crossorigin: '' });\n // ensureLink('preload', drawerCss, { as: 'style', crossorigin: '' });\n } catch {}\n }\n\n if (relayerUrl) {\n ensureLink('dns-prefetch', relayerUrl);\n ensureLink('preconnect', relayerUrl, { crossorigin: '' });\n }\n } catch {}\n }, [walletOrigin, servicePath, sdkBasePath, relayerUrl]);\n}\n\nexport default usePreconnectWalletAssets;\n"],"mappings":";;;;AA0BA,SAAgB,0BAA0B,QAAoD;CAE5F,MAAM,eAAe,QAAQ,cAAc;CAC3C,MAAM,cAAc,QAAQ,cAAc,qBAAqB;CAC/D,MAAM,cAAc,QAAQ,cAAc,eAAe;CACzD,MAAM,aAAa,QAAQ,SAAS;AAEpC,OAAM,gBAAgB;AACpB,MAAI;AACF,OAAI,OAAO,aAAa,YAAa;GAGrC,IAAI,gBAAgB;GACpB,IAAIA,qBAAyC;AAC7C,OAAI;AACF,QAAI,cAAc;AAChB,0BAAqB,IAAI,IAAI,cAAc,OAAO,SAAS,MAAM;KACjE,MAAM,eAAe,OAAO,SAAS;AACrC,qBAAgB,uBAAuB;AACvC,SAAI,eAAe;MACjB,MAAM,UAAW,eAAe;MAChC,MAAM,YAAY,QAAQ,SAAS,OAAO,UAAU,UAAU;MAC9D,MAAM,MAAM,IAAI,IAAI,WAAW,oBAAoB;AACnD,sBAAgB;;;WAGd;GACR,MAAM,cAAc,KAAa,MAAe,UAAmC;AACjF,QAAI;AACF,SAAI,CAAC,KAAM;KACX,MAAM,OAAO,SAAS,QAAQ,SAAS,qBAAqB,QAAQ;AACpE,SAAI,CAAC,KAAM;KACX,MAAM,WAAW,aAAa,IAAI,WAAW,KAAK;AAClD,SAAI,KAAK,cAAc,UAAW;KAClC,MAAM,OAAO,SAAS,cAAc;AACpC,UAAK,MAAM;AACX,UAAK,OAAO;AACZ,SAAI,MACF,MAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,OAClC,KAAI;AAAE,WAAK,aAAa,GAAG;aAAY;AAG3C,UAAK,YAAY;YACX;;AAGV,OAAI,cAAc;AAEhB,eAAW,gBAAgB;AAC3B,eAAW,cAAc,cAAc,EAAE,aAAa;AAItD,QAAI,CAAC,cACH,KAAI;KACF,MAAM,aAAa,IAAI,IAAI,aAAa,cAAc;AACtD,gBAAW,YAAY,YAAY,EAAE,IAAI;YACnC;AAMV,QAAI;KACF,MAAM,UAAW,eAAe;KAChC,MAAM,YAAY,QAAQ,SAAS,OAAO,UAAU,UAAU;KAC9D,MAAM,OAAO,IAAI,IAAI,WAAW;KAChC,MAAM,SAAS,IAAI,IAAI,yBAAyB,MAAM;AACtD,gBAAW,iBAAiB,QAAQ,EAAE,aAAa;AAInD,SAAI;MACF,MAAM,aAAa,IAAI,IAAI,sCAAsC,MAAM;AACvE,iBAAW,YAAY,YAAY;OAAE,IAAI;OAAS,aAAa;OAAI,MAAM;;aACnE;AACR,SAAI;MACF,MAAM,UAAU,IAAI,IAAI,mCAAmC,MAAM;AACjE,iBAAW,YAAY,SAAS;OAAE,IAAI;OAAS,aAAa;OAAI,MAAM;;aAChE;YAWF;;AAGV,OAAI,YAAY;AACd,eAAW,gBAAgB;AAC3B,eAAW,cAAc,YAAY,EAAE,aAAa;;UAEhD;IACP;EAAC;EAAc;EAAa;EAAa"}
1
+ {"version":3,"file":"usePreconnectWalletAssets.js","names":["walletOriginOrigin: string | undefined"],"sources":["../../../../src/react/hooks/usePreconnectWalletAssets.ts"],"sourcesContent":["import React from 'react';\nimport type { TatchiContextProviderProps } from '../types';\nimport { setEmbeddedBase } from '../../core/sdkPaths';\n\n// Internal: Add preconnect/prefetch hints for wallet service + relayer and\n// expose an absolute embedded asset base for srcdoc iframes.\n//\n// What this hook does\n// - Adds resource hints for the configured wallet origin (dns‑prefetch, preconnect, prefetch)\n// and modulepreload for the wallet host script.\n// - Sets `window.__W3A_WALLET_SDK_BASE__` to an absolute `${walletOrigin}${sdkBasePath}/` so\n// any embedded srcdoc iframes created by the SDK load ESM bundles from the wallet origin,\n// not from the host app origin.\n//\n// Requirements\n// - `config.iframeWallet.walletOrigin` points to the wallet site (e.g. https://web3authn.org)\n// - `config.iframeWallet.sdkBasePath` (default '/sdk') is served on that wallet site\n// - `config.iframeWallet.walletServicePath` (default '/wallet-service') is reachable\n//\n// Gotchas\n// - Always resolve `${sdkBasePath}/...` with a trailing slash; otherwise `new URL('file', '/sdk')`\n// becomes `/file` instead of `/sdk/file`.\n// - For cross‑origin module/worker imports, ensure the wallet site sends CORS headers for\n// `/sdk/*` and `/sdk/workers/*` (e.g. `Access-Control-Allow-Origin: *`) and `.wasm` has\n// `Content-Type: application/wasm`.\n// - `/wallet-service` may 308 → `/wallet-service/` on Pages; both are fine.\nexport function usePreconnectWalletAssets(config: TatchiContextProviderProps['config']): void {\n // Derive stable primitives to avoid re-running the effect on object identity changes.\n const walletOrigin = config?.iframeWallet?.walletOrigin as string | undefined;\n const servicePath = config?.iframeWallet?.walletServicePath || '/wallet-service';\n const sdkBasePath = config?.iframeWallet?.sdkBasePath || '/sdk';\n const relayerUrl = config?.relayer?.url as string | undefined;\n\n React.useEffect(() => {\n try {\n if (typeof document === 'undefined') return;\n // Determine cross‑origin once per effect and expose absolute embedded base\n // for srcdoc iframes ONLY when wallet is cross‑origin.\n let isCrossOrigin = false;\n let walletOriginOrigin: string | undefined = undefined;\n let walletIsHttp = false;\n try {\n if (walletOrigin) {\n const url = new URL(walletOrigin, window.location.href);\n walletOriginOrigin = url.origin;\n walletIsHttp = url.protocol === 'http:' || url.protocol === 'https:';\n const parentOrigin = window.location.origin;\n isCrossOrigin = walletOriginOrigin !== parentOrigin;\n if (isCrossOrigin) {\n const sdkPath = (sdkBasePath || '/sdk') as string;\n const withSlash = sdkPath.endsWith('/') ? sdkPath : sdkPath + '/';\n const abs = new URL(withSlash, walletOriginOrigin).toString();\n setEmbeddedBase(abs);\n }\n }\n } catch {}\n const ensureLink = (rel: string, href?: string, attrs?: Record<string, string>) => {\n try {\n if (!href) return;\n const head = document.head || document.getElementsByTagName('head')[0];\n if (!head) return;\n const selector = `link[rel=\"${rel}\"][href=\"${href}\"]`;\n if (head.querySelector(selector)) return;\n const link = document.createElement('link');\n link.rel = rel;\n link.href = href;\n if (attrs) {\n for (const [k, v] of Object.entries(attrs)) {\n try { link.setAttribute(k, v); } catch {}\n }\n }\n head.appendChild(link);\n } catch {}\n };\n\n if (walletOrigin) {\n // Resource hints only work for network origins; skip for schemes like chrome-extension://\n // (which can cause confusing console errors and does not benefit DNS/TLS preconnect).\n if (walletIsHttp && walletOriginOrigin) {\n // Reduce DNS/TLS handshake and fetch delays for the wallet origin\n ensureLink('dns-prefetch', walletOriginOrigin);\n ensureLink('preconnect', walletOriginOrigin, { crossorigin: '' });\n\n // Prefetch the service HTML document only in same‑origin dev.\n // Cross‑origin prefetch would require ACAO on the HTML, which we purposely avoid.\n if (!isCrossOrigin) {\n try {\n const serviceUrl = new URL(servicePath, walletOriginOrigin).toString();\n ensureLink('prefetch', serviceUrl, { as: 'document' });\n } catch {}\n }\n\n // Preload the wallet host script module so the iframe boots faster\n // Ensure the base URL ends with a trailing slash; otherwise new URL('file', base)\n // would replace the last path segment (\"/sdk\") and yield \"/wallet-iframe-host.js\".\n try {\n const sdkPath = (sdkBasePath || '/sdk') as string;\n const withSlash = sdkPath.endsWith('/') ? sdkPath : sdkPath + '/';\n const base = new URL(withSlash, walletOriginOrigin);\n const hostJs = new URL('wallet-iframe-host.js', base).toString();\n ensureLink('modulepreload', hostJs, { crossorigin: '' });\n\n // Optionally prefetch WASM binaries to accelerate first-use while avoiding preload warnings\n // Requires CORS + correct MIME (application/wasm) on the wallet origin\n try {\n const signerWasm = new URL('workers/wasm_signer_worker_bg.wasm', base).toString();\n ensureLink('prefetch', signerWasm, { as: 'fetch', crossorigin: '', type: 'application/wasm' } as any);\n } catch {}\n try {\n const vrfWasm = new URL('workers/wasm_vrf_worker_bg.wasm', base).toString();\n ensureLink('prefetch', vrfWasm, { as: 'fetch', crossorigin: '', type: 'application/wasm' } as any);\n } catch {}\n\n // // Preload core CSS used by confirmer to reduce first-paint FOUC\n // const tokensCss = new URL('w3a-components.css', base).toString();\n // const txTreeCss = new URL('tx-tree.css', base).toString();\n // const txConfirmerCss = new URL('tx-confirmer.css', base).toString();\n // const drawerCss = new URL('drawer.css', base).toString();\n // ensureLink('preload', tokensCss, { as: 'style', crossorigin: '' });\n // ensureLink('preload', txTreeCss, { as: 'style', crossorigin: '' });\n // ensureLink('preload', modalCss, { as: 'style', crossorigin: '' });\n // ensureLink('preload', drawerCss, { as: 'style', crossorigin: '' });\n } catch {}\n }\n }\n\n if (relayerUrl) {\n ensureLink('dns-prefetch', relayerUrl);\n ensureLink('preconnect', relayerUrl, { crossorigin: '' });\n }\n } catch {}\n }, [walletOrigin, servicePath, sdkBasePath, relayerUrl]);\n}\n\nexport default usePreconnectWalletAssets;\n"],"mappings":";;;;AA0BA,SAAgB,0BAA0B,QAAoD;CAE5F,MAAM,eAAe,QAAQ,cAAc;CAC3C,MAAM,cAAc,QAAQ,cAAc,qBAAqB;CAC/D,MAAM,cAAc,QAAQ,cAAc,eAAe;CACzD,MAAM,aAAa,QAAQ,SAAS;AAEpC,OAAM,gBAAgB;AACpB,MAAI;AACF,OAAI,OAAO,aAAa,YAAa;GAGrC,IAAI,gBAAgB;GACpB,IAAIA,qBAAyC;GAC7C,IAAI,eAAe;AACnB,OAAI;AACF,QAAI,cAAc;KAChB,MAAM,MAAM,IAAI,IAAI,cAAc,OAAO,SAAS;AAClD,0BAAqB,IAAI;AACzB,oBAAe,IAAI,aAAa,WAAW,IAAI,aAAa;KAC5D,MAAM,eAAe,OAAO,SAAS;AACrC,qBAAgB,uBAAuB;AACvC,SAAI,eAAe;MACjB,MAAM,UAAW,eAAe;MAChC,MAAM,YAAY,QAAQ,SAAS,OAAO,UAAU,UAAU;MAC9D,MAAM,MAAM,IAAI,IAAI,WAAW,oBAAoB;AACnD,sBAAgB;;;WAGd;GACR,MAAM,cAAc,KAAa,MAAe,UAAmC;AACjF,QAAI;AACF,SAAI,CAAC,KAAM;KACX,MAAM,OAAO,SAAS,QAAQ,SAAS,qBAAqB,QAAQ;AACpE,SAAI,CAAC,KAAM;KACX,MAAM,WAAW,aAAa,IAAI,WAAW,KAAK;AAClD,SAAI,KAAK,cAAc,UAAW;KAClC,MAAM,OAAO,SAAS,cAAc;AACpC,UAAK,MAAM;AACX,UAAK,OAAO;AACZ,SAAI,MACF,MAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,OAClC,KAAI;AAAE,WAAK,aAAa,GAAG;aAAY;AAG3C,UAAK,YAAY;YACX;;AAGV,OAAI,cAGF;QAAI,gBAAgB,oBAAoB;AAEtC,gBAAW,gBAAgB;AAC3B,gBAAW,cAAc,oBAAoB,EAAE,aAAa;AAI5D,SAAI,CAAC,cACH,KAAI;MACF,MAAM,aAAa,IAAI,IAAI,aAAa,oBAAoB;AAC5D,iBAAW,YAAY,YAAY,EAAE,IAAI;aACnC;AAMV,SAAI;MACF,MAAM,UAAW,eAAe;MAChC,MAAM,YAAY,QAAQ,SAAS,OAAO,UAAU,UAAU;MAC9D,MAAM,OAAO,IAAI,IAAI,WAAW;MAChC,MAAM,SAAS,IAAI,IAAI,yBAAyB,MAAM;AACtD,iBAAW,iBAAiB,QAAQ,EAAE,aAAa;AAInD,UAAI;OACF,MAAM,aAAa,IAAI,IAAI,sCAAsC,MAAM;AACvE,kBAAW,YAAY,YAAY;QAAE,IAAI;QAAS,aAAa;QAAI,MAAM;;cACnE;AACR,UAAI;OACF,MAAM,UAAU,IAAI,IAAI,mCAAmC,MAAM;AACjE,kBAAW,YAAY,SAAS;QAAE,IAAI;QAAS,aAAa;QAAI,MAAM;;cAChE;aAWF;;;AAIZ,OAAI,YAAY;AACd,eAAW,gBAAgB;AAC3B,eAAW,cAAc,YAAY,EAAE,aAAa;;UAEhD;IACP;EAAC;EAAc;EAAa;EAAa"}
@@ -1,8 +1,9 @@
1
- import { getOptimalCameraFacingMode } from "../deviceDetection.js";
1
+ import { getOptimalCameraFacingMode, init_deviceDetection } from "../deviceDetection.js";
2
2
  import { ScanQRCodeFlow, detectFrontCamera, enumerateVideoDevices } from "../sdk/src/utils/qrScanner.js";
3
3
  import { useCallback, useEffect, useRef, useState } from "react";
4
4
 
5
5
  //#region src/react/hooks/useQRCamera.ts
6
+ init_deviceDetection();
6
7
  /**
7
8
  * QR Camera Scanning Hook
8
9
  *
@@ -1 +1 @@
1
- {"version":3,"file":"useQRCamera.js","names":["error: any","error"],"sources":["../../../../src/react/hooks/useQRCamera.ts"],"sourcesContent":["import { useEffect, useRef, useState, useCallback } from 'react';\nimport { getOptimalCameraFacingMode } from '../deviceDetection';\nimport type { DeviceLinkingQRData } from '@/index';\nimport { ScanQRCodeFlow, enumerateVideoDevices, detectFrontCamera } from '../../utils/qrScanner';\n\n/**\n * QR Camera Scanning Hook\n *\n * Provides camera-based QR code scanning functionality for device linking.\n *\n * **Important:** This hook should be used with the TatchiPasskey provider.\n * Wrap your app with PasskeyProvider so useTatchi is available when needed.\n *\n * @example\n * ```tsx\n * import { PasskeyProvider } from '@tatchi-xyz/sdk/react';\n * import { useQRCamera } from '@tatchi-xyz/sdk/react';\n *\n * function QRScanner() {\n * const qrCamera = useQRCamera({\n * onQRDetected: (qrData) => console.log('QR detected:', qrData),\n * onError: (error) => console.error('Error:', error)\n * });\n *\n * return <video ref={qrCamera.videoRef} />;\n * }\n * ```\n */\nexport enum QRScanMode {\n CAMERA = 'camera',\n FILE = 'file',\n AUTO = 'auto'\n}\n\nexport interface UseQRCameraOptions {\n onQRDetected?: (qrData: DeviceLinkingQRData) => void;\n onError?: (error: Error) => void;\n isOpen?: boolean;\n cameraId?: string;\n}\n\nexport interface UseQRCameraReturn {\n // State\n isScanning: boolean;\n isProcessing: boolean;\n error: string | null;\n cameras: MediaDeviceInfo[];\n selectedCamera: string;\n scanMode: QRScanMode;\n isFrontCamera: boolean;\n scanDurationMs: number;\n\n // Refs for UI\n videoRef: React.RefObject<HTMLVideoElement | null>;\n canvasRef: React.RefObject<HTMLCanvasElement | null>;\n\n // Controls\n startScanning: () => Promise<void>;\n stopScanning: () => void;\n handleCameraChange: (deviceId: string) => void;\n setScanMode: (mode: QRScanMode) => void;\n setError: (error: string | null) => void;\n\n // Utilities\n getOptimalFacingMode: () => 'user' | 'environment';\n}\n\nexport const useQRCamera = (options: UseQRCameraOptions): UseQRCameraReturn => {\n const {\n onQRDetected,\n onError,\n isOpen = true,\n cameraId\n } = options;\n\n // Refs\n const videoRef = useRef<HTMLVideoElement>(null);\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const flowRef = useRef<ScanQRCodeFlow | null>(null);\n\n // State\n const [isScanning, setIsScanning] = useState(false);\n const [isProcessing, setIsProcessing] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [cameras, setCameras] = useState<MediaDeviceInfo[]>([]);\n const [selectedCamera, setSelectedCamera] = useState<string>(cameraId || '');\n const [scanMode, setScanMode] = useState<QRScanMode>(QRScanMode.CAMERA);\n const [isFrontCamera, setIsFrontCamera] = useState<boolean>(false);\n const [scanDurationMs, setScanDurationMs] = useState<number>(0);\n\n // Create ScanQRCodeFlow instance\n // This is the core scanning engine that handles camera access and QR detection\n useEffect(() => {\n flowRef.current = new ScanQRCodeFlow(\n {\n cameraId: selectedCamera,\n cameraConfigs: {\n facingMode: getOptimalCameraFacingMode()\n },\n timeout: 60000 // 60 seconds\n },\n {\n onQRDetected: (qrData) => {\n console.log('useQRCamera: Valid QR data detected -', {\n devicePublicKey: qrData.device2PublicKey,\n accountId: qrData.accountId,\n timestamp: new Date(qrData.timestamp || 0).toISOString()\n });\n setIsProcessing(false);\n setIsScanning(false);\n setScanDurationMs(0);\n onQRDetected?.(qrData);\n },\n onError: (err) => {\n console.error('useQRCamera: QR scan error -', err);\n setError(err.message);\n setIsProcessing(false);\n setIsScanning(false);\n setScanDurationMs(0);\n onError?.(err);\n },\n onCameraReady: (stream) => {\n // Camera stream is ready, but video element attachment is handled separately\n console.log('useQRCamera: Camera stream ready');\n },\n onScanProgress: (duration) => {\n setScanDurationMs(duration);\n }\n }\n );\n\n return () => {\n if (flowRef.current) {\n // Hook Cleanup Point 1: Stop scanning and cleanup\n flowRef.current.stop();\n flowRef.current = null;\n }\n };\n }, []); // Only initialize once\n\n // Load cameras on mount\n useEffect(() => {\n const loadCameras = async () => {\n try {\n const videoDevices = await enumerateVideoDevices();\n setCameras(videoDevices);\n\n if (videoDevices.length > 0 && !selectedCamera) {\n const firstCamera = videoDevices[0];\n setSelectedCamera(firstCamera.deviceId);\n setIsFrontCamera(detectFrontCamera(firstCamera));\n }\n } catch (error: any) {\n setError(error.message);\n }\n };\n\n loadCameras();\n }, []);\n\n // Update flow camera when selectedCamera changes\n useEffect(() => {\n if (flowRef.current && selectedCamera) {\n flowRef.current.switchCamera(selectedCamera);\n }\n }, [selectedCamera]);\n\n // Attach/detach video element when ref changes\n useEffect(() => {\n if (videoRef.current && flowRef.current) {\n flowRef.current.attachVideoElement(videoRef.current);\n }\n\n return () => {\n if (flowRef.current) {\n flowRef.current.detachVideoElement();\n }\n };\n }, [videoRef.current]);\n\n // Hook Cleanup Point 2: (when modal closes or scan mode changes from camera to file)\n useEffect(() => {\n const flow = flowRef.current;\n if (!flow) return;\n\n if (isOpen && scanMode === QRScanMode.CAMERA) {\n setError(null);\n setIsProcessing(true);\n setIsScanning(true);\n setScanDurationMs(0);\n flow.startQRScanner();\n } else {\n flow.stop();\n setIsScanning(false);\n setIsProcessing(false);\n setScanDurationMs(0);\n }\n }, [isOpen, scanMode]);\n\n // Manual controls\n const startScanning = useCallback(async () => {\n if (flowRef.current) {\n setError(null);\n setIsProcessing(true);\n setIsScanning(true);\n setScanDurationMs(0);\n await flowRef.current.startQRScanner();\n }\n }, []);\n\n // Hook Cleanup Point 3: called when user explicitly stops scanning\n const stopScanning = useCallback(() => {\n if (flowRef.current) {\n flowRef.current.stop();\n setIsScanning(false);\n setIsProcessing(false);\n setScanDurationMs(0);\n }\n }, []);\n\n // Handle camera change\n const handleCameraChange = useCallback(async (deviceId: string) => {\n setSelectedCamera(deviceId);\n\n const selectedCameraDevice = cameras.find(camera => camera.deviceId === deviceId);\n if (selectedCameraDevice) {\n setIsFrontCamera(detectFrontCamera(selectedCameraDevice));\n }\n\n // The useEffect will handle updating the flow\n }, [cameras]);\n\n const getOptimalFacingMode = useCallback(() => getOptimalCameraFacingMode(), []);\n\n return {\n // State\n isScanning,\n isProcessing,\n error,\n cameras,\n selectedCamera,\n scanMode,\n isFrontCamera,\n scanDurationMs,\n\n // Refs for UI\n videoRef,\n canvasRef,\n\n // Controls\n startScanning,\n stopScanning,\n handleCameraChange,\n setScanMode,\n setError,\n\n // Utilities\n getOptimalFacingMode\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"useQRCamera.js","names":["error: any","error"],"sources":["../../../../src/react/hooks/useQRCamera.ts"],"sourcesContent":["import { useEffect, useRef, useState, useCallback } from 'react';\nimport { getOptimalCameraFacingMode } from '../deviceDetection';\nimport type { DeviceLinkingQRData } from '@/index';\nimport { ScanQRCodeFlow, enumerateVideoDevices, detectFrontCamera } from '../../utils/qrScanner';\n\n/**\n * QR Camera Scanning Hook\n *\n * Provides camera-based QR code scanning functionality for device linking.\n *\n * **Important:** This hook should be used with the TatchiPasskey provider.\n * Wrap your app with PasskeyProvider so useTatchi is available when needed.\n *\n * @example\n * ```tsx\n * import { PasskeyProvider } from '@tatchi-xyz/sdk/react';\n * import { useQRCamera } from '@tatchi-xyz/sdk/react';\n *\n * function QRScanner() {\n * const qrCamera = useQRCamera({\n * onQRDetected: (qrData) => console.log('QR detected:', qrData),\n * onError: (error) => console.error('Error:', error)\n * });\n *\n * return <video ref={qrCamera.videoRef} />;\n * }\n * ```\n */\nexport enum QRScanMode {\n CAMERA = 'camera',\n FILE = 'file',\n AUTO = 'auto'\n}\n\nexport interface UseQRCameraOptions {\n onQRDetected?: (qrData: DeviceLinkingQRData) => void;\n onError?: (error: Error) => void;\n isOpen?: boolean;\n cameraId?: string;\n}\n\nexport interface UseQRCameraReturn {\n // State\n isScanning: boolean;\n isProcessing: boolean;\n error: string | null;\n cameras: MediaDeviceInfo[];\n selectedCamera: string;\n scanMode: QRScanMode;\n isFrontCamera: boolean;\n scanDurationMs: number;\n\n // Refs for UI\n videoRef: React.RefObject<HTMLVideoElement | null>;\n canvasRef: React.RefObject<HTMLCanvasElement | null>;\n\n // Controls\n startScanning: () => Promise<void>;\n stopScanning: () => void;\n handleCameraChange: (deviceId: string) => void;\n setScanMode: (mode: QRScanMode) => void;\n setError: (error: string | null) => void;\n\n // Utilities\n getOptimalFacingMode: () => 'user' | 'environment';\n}\n\nexport const useQRCamera = (options: UseQRCameraOptions): UseQRCameraReturn => {\n const {\n onQRDetected,\n onError,\n isOpen = true,\n cameraId\n } = options;\n\n // Refs\n const videoRef = useRef<HTMLVideoElement>(null);\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const flowRef = useRef<ScanQRCodeFlow | null>(null);\n\n // State\n const [isScanning, setIsScanning] = useState(false);\n const [isProcessing, setIsProcessing] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [cameras, setCameras] = useState<MediaDeviceInfo[]>([]);\n const [selectedCamera, setSelectedCamera] = useState<string>(cameraId || '');\n const [scanMode, setScanMode] = useState<QRScanMode>(QRScanMode.CAMERA);\n const [isFrontCamera, setIsFrontCamera] = useState<boolean>(false);\n const [scanDurationMs, setScanDurationMs] = useState<number>(0);\n\n // Create ScanQRCodeFlow instance\n // This is the core scanning engine that handles camera access and QR detection\n useEffect(() => {\n flowRef.current = new ScanQRCodeFlow(\n {\n cameraId: selectedCamera,\n cameraConfigs: {\n facingMode: getOptimalCameraFacingMode()\n },\n timeout: 60000 // 60 seconds\n },\n {\n onQRDetected: (qrData) => {\n console.log('useQRCamera: Valid QR data detected -', {\n devicePublicKey: qrData.device2PublicKey,\n accountId: qrData.accountId,\n timestamp: new Date(qrData.timestamp || 0).toISOString()\n });\n setIsProcessing(false);\n setIsScanning(false);\n setScanDurationMs(0);\n onQRDetected?.(qrData);\n },\n onError: (err) => {\n console.error('useQRCamera: QR scan error -', err);\n setError(err.message);\n setIsProcessing(false);\n setIsScanning(false);\n setScanDurationMs(0);\n onError?.(err);\n },\n onCameraReady: (stream) => {\n // Camera stream is ready, but video element attachment is handled separately\n console.log('useQRCamera: Camera stream ready');\n },\n onScanProgress: (duration) => {\n setScanDurationMs(duration);\n }\n }\n );\n\n return () => {\n if (flowRef.current) {\n // Hook Cleanup Point 1: Stop scanning and cleanup\n flowRef.current.stop();\n flowRef.current = null;\n }\n };\n }, []); // Only initialize once\n\n // Load cameras on mount\n useEffect(() => {\n const loadCameras = async () => {\n try {\n const videoDevices = await enumerateVideoDevices();\n setCameras(videoDevices);\n\n if (videoDevices.length > 0 && !selectedCamera) {\n const firstCamera = videoDevices[0];\n setSelectedCamera(firstCamera.deviceId);\n setIsFrontCamera(detectFrontCamera(firstCamera));\n }\n } catch (error: any) {\n setError(error.message);\n }\n };\n\n loadCameras();\n }, []);\n\n // Update flow camera when selectedCamera changes\n useEffect(() => {\n if (flowRef.current && selectedCamera) {\n flowRef.current.switchCamera(selectedCamera);\n }\n }, [selectedCamera]);\n\n // Attach/detach video element when ref changes\n useEffect(() => {\n if (videoRef.current && flowRef.current) {\n flowRef.current.attachVideoElement(videoRef.current);\n }\n\n return () => {\n if (flowRef.current) {\n flowRef.current.detachVideoElement();\n }\n };\n }, [videoRef.current]);\n\n // Hook Cleanup Point 2: (when modal closes or scan mode changes from camera to file)\n useEffect(() => {\n const flow = flowRef.current;\n if (!flow) return;\n\n if (isOpen && scanMode === QRScanMode.CAMERA) {\n setError(null);\n setIsProcessing(true);\n setIsScanning(true);\n setScanDurationMs(0);\n flow.startQRScanner();\n } else {\n flow.stop();\n setIsScanning(false);\n setIsProcessing(false);\n setScanDurationMs(0);\n }\n }, [isOpen, scanMode]);\n\n // Manual controls\n const startScanning = useCallback(async () => {\n if (flowRef.current) {\n setError(null);\n setIsProcessing(true);\n setIsScanning(true);\n setScanDurationMs(0);\n await flowRef.current.startQRScanner();\n }\n }, []);\n\n // Hook Cleanup Point 3: called when user explicitly stops scanning\n const stopScanning = useCallback(() => {\n if (flowRef.current) {\n flowRef.current.stop();\n setIsScanning(false);\n setIsProcessing(false);\n setScanDurationMs(0);\n }\n }, []);\n\n // Handle camera change\n const handleCameraChange = useCallback(async (deviceId: string) => {\n setSelectedCamera(deviceId);\n\n const selectedCameraDevice = cameras.find(camera => camera.deviceId === deviceId);\n if (selectedCameraDevice) {\n setIsFrontCamera(detectFrontCamera(selectedCameraDevice));\n }\n\n // The useEffect will handle updating the flow\n }, [cameras]);\n\n const getOptimalFacingMode = useCallback(() => getOptimalCameraFacingMode(), []);\n\n return {\n // State\n isScanning,\n isProcessing,\n error,\n cameras,\n selectedCamera,\n scanMode,\n isFrontCamera,\n scanDurationMs,\n\n // Refs for UI\n videoRef,\n canvasRef,\n\n // Controls\n startScanning,\n stopScanning,\n handleCameraChange,\n setScanMode,\n setError,\n\n // Utilities\n getOptimalFacingMode\n };\n};\n"],"mappings":"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"}
@@ -5,11 +5,18 @@ import { IndexedDBManager, init_IndexedDBManager } from "../IndexedDBManager/ind
5
5
  init_accountIds();
6
6
  init_IndexedDBManager();
7
7
  const canonicalizeEmail = (email) => {
8
- let addr = email;
9
- const angleStart = email.indexOf("<");
10
- const angleEnd = email.indexOf(">");
11
- if (angleStart !== -1 && angleEnd > angleStart) addr = email.slice(angleStart + 1, angleEnd);
12
- return addr.trim().toLowerCase();
8
+ const raw = String(email || "").trim();
9
+ if (!raw) return "";
10
+ const withoutHeaderName = raw.replace(/^[a-z0-9-]+\s*:\s*/i, "").trim();
11
+ const emailRegex = /([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*)/;
12
+ const angleMatch = withoutHeaderName.match(/<([^>]+)>/);
13
+ const candidates = [angleMatch?.[1], withoutHeaderName].filter((v) => typeof v === "string" && v.length > 0);
14
+ for (const candidate of candidates) {
15
+ const cleaned = candidate.replace(/^mailto:\s*/i, "");
16
+ const match = cleaned.match(emailRegex);
17
+ if (match?.[1]) return match[1].trim().toLowerCase();
18
+ }
19
+ return withoutHeaderName.toLowerCase();
13
20
  };
14
21
  const bytesToHex = (bytes) => {
15
22
  const arr = bytes instanceof Uint8Array ? bytes : Uint8Array.from(bytes);