@tatchi-xyz/sdk 0.16.0 → 0.18.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 (501) hide show
  1. package/dist/cjs/core/EmailRecovery/emailRecoveryPendingStore.js +69 -0
  2. package/dist/cjs/core/EmailRecovery/emailRecoveryPendingStore.js.map +1 -0
  3. package/dist/cjs/core/EmailRecovery/index.js +32 -13
  4. package/dist/cjs/core/EmailRecovery/index.js.map +1 -1
  5. package/dist/cjs/core/IndexedDBManager/passkeyClientDB.js +35 -36
  6. package/dist/cjs/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  7. package/dist/cjs/core/NearClient.js +2 -1
  8. package/dist/cjs/core/NearClient.js.map +1 -1
  9. package/dist/cjs/core/TatchiPasskey/emailRecovery.js +557 -377
  10. package/dist/cjs/core/TatchiPasskey/emailRecovery.js.map +1 -1
  11. package/dist/cjs/core/TatchiPasskey/faucets/createAccountRelayServer.js +1 -0
  12. package/dist/cjs/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  13. package/dist/cjs/core/TatchiPasskey/index.js +26 -0
  14. package/dist/cjs/core/TatchiPasskey/index.js.map +1 -1
  15. package/dist/cjs/core/TatchiPasskey/linkDevice.js +2 -0
  16. package/dist/cjs/core/TatchiPasskey/linkDevice.js.map +1 -1
  17. package/dist/cjs/core/TatchiPasskey/login.js +15 -4
  18. package/dist/cjs/core/TatchiPasskey/login.js.map +1 -1
  19. package/dist/cjs/core/TatchiPasskey/recoverAccount.js +1 -0
  20. package/dist/cjs/core/TatchiPasskey/recoverAccount.js.map +1 -1
  21. package/dist/cjs/core/TatchiPasskey/relay.js +23 -1
  22. package/dist/cjs/core/TatchiPasskey/relay.js.map +1 -1
  23. package/dist/cjs/core/TatchiPasskey/scanDevice.js +1 -0
  24. package/dist/cjs/core/TatchiPasskey/scanDevice.js.map +1 -1
  25. package/dist/cjs/core/WalletIframe/client/IframeTransport.js +3 -0
  26. package/dist/cjs/core/WalletIframe/client/IframeTransport.js.map +1 -1
  27. package/dist/cjs/core/WalletIframe/client/router.js +15 -2
  28. package/dist/cjs/core/WalletIframe/client/router.js.map +1 -1
  29. package/dist/cjs/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js +1 -1
  30. package/dist/cjs/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js.map +1 -1
  31. package/dist/cjs/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js +52 -52
  32. package/dist/cjs/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js.map +1 -1
  33. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/getDeviceNumber.js +10 -1
  34. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/getDeviceNumber.js.map +1 -1
  35. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js +1 -0
  36. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js.map +1 -1
  37. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js +1 -0
  38. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js.map +1 -1
  39. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js +1 -0
  40. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js.map +1 -1
  41. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js +1 -0
  42. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js.map +1 -1
  43. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js +2 -1
  44. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js.map +1 -1
  45. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js +1 -0
  46. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js.map +1 -1
  47. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js +1 -0
  48. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js.map +1 -1
  49. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js +1 -0
  50. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js.map +1 -1
  51. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +2 -0
  52. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  53. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/index.js +1 -0
  54. package/dist/cjs/core/WebAuthnManager/SignerWorkerManager/index.js.map +1 -1
  55. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js +1 -0
  56. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js.map +1 -1
  57. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js +6 -0
  58. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js.map +1 -1
  59. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js +2 -1
  60. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js.map +1 -1
  61. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js +1 -0
  62. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js.map +1 -1
  63. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +1 -0
  64. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  65. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +4 -15
  66. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  67. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js +1 -0
  68. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js.map +1 -1
  69. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js +1 -0
  70. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js.map +1 -1
  71. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js +1 -0
  72. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js.map +1 -1
  73. package/dist/cjs/core/WebAuthnManager/WebAuthnFallbacks/index.js +17 -0
  74. package/dist/cjs/core/WebAuthnManager/WebAuthnFallbacks/index.js.map +1 -0
  75. package/dist/cjs/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js +64 -54
  76. package/dist/cjs/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js.map +1 -1
  77. package/dist/cjs/core/WebAuthnManager/credentialsHelpers.js +12 -2
  78. package/dist/cjs/core/WebAuthnManager/credentialsHelpers.js.map +1 -1
  79. package/dist/cjs/core/WebAuthnManager/index.js +6 -1
  80. package/dist/cjs/core/WebAuthnManager/index.js.map +1 -1
  81. package/dist/cjs/core/WebAuthnManager/touchIdPrompt.js +209 -201
  82. package/dist/cjs/core/WebAuthnManager/touchIdPrompt.js.map +1 -1
  83. package/dist/cjs/core/WebAuthnManager/userHandle.js +2 -1
  84. package/dist/cjs/core/WebAuthnManager/userHandle.js.map +1 -1
  85. package/dist/cjs/core/defaultConfigs.js +1 -1
  86. package/dist/cjs/core/defaultConfigs.js.map +1 -1
  87. package/dist/cjs/core/rpcCalls.js +8 -0
  88. package/dist/cjs/core/rpcCalls.js.map +1 -1
  89. package/dist/cjs/core/types/vrf-worker.js +10 -1
  90. package/dist/cjs/core/types/vrf-worker.js.map +1 -1
  91. package/dist/cjs/index.js +6 -2
  92. package/dist/cjs/index.js.map +1 -1
  93. package/dist/cjs/react/components/AccountMenuButton/{LinkedDevicesModal-STvIsylA.css → LinkedDevicesModal-CSSowiHP.css} +1 -1
  94. package/dist/{esm/react/components/AccountMenuButton/LinkedDevicesModal-STvIsylA.css.map → cjs/react/components/AccountMenuButton/LinkedDevicesModal-CSSowiHP.css.map} +1 -1
  95. package/dist/cjs/react/components/AccountMenuButton/{ProfileDropdown-iARgUwK1.css → ProfileDropdown-CEPMZ1gY.css} +1 -1
  96. package/dist/{esm/react/components/AccountMenuButton/ProfileDropdown-iARgUwK1.css.map → cjs/react/components/AccountMenuButton/ProfileDropdown-CEPMZ1gY.css.map} +1 -1
  97. package/dist/cjs/react/components/AccountMenuButton/{Web3AuthProfileButton-Db3NeoAC.css → Web3AuthProfileButton-DopOg7Xc.css} +1 -1
  98. package/dist/cjs/react/components/AccountMenuButton/{Web3AuthProfileButton-Db3NeoAC.css.map → Web3AuthProfileButton-DopOg7Xc.css.map} +1 -1
  99. package/dist/cjs/react/components/AccountMenuButton/icons/{TouchIcon-BXM5NR4A.css → TouchIcon-BQWentvJ.css} +1 -1
  100. package/dist/cjs/react/components/AccountMenuButton/icons/{TouchIcon-BXM5NR4A.css.map → TouchIcon-BQWentvJ.css.map} +1 -1
  101. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-De1qTSmU.css → PasskeyAuthMenu-DwrzWMYx.css} +14 -1
  102. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-De1qTSmU.css.map → PasskeyAuthMenu-DwrzWMYx.css.map} +1 -1
  103. package/dist/cjs/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js +122 -53
  104. package/dist/cjs/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js.map +1 -1
  105. package/dist/cjs/react/components/{ShowQRCode-DCnR__fx.css → ShowQRCode-CCN4h6Uv.css} +1 -1
  106. package/dist/cjs/react/components/{ShowQRCode-DCnR__fx.css.map → ShowQRCode-CCN4h6Uv.css.map} +1 -1
  107. package/dist/cjs/react/deviceDetection.js +75 -92
  108. package/dist/cjs/react/deviceDetection.js.map +1 -1
  109. package/dist/cjs/react/hooks/useQRCamera.js +1 -0
  110. package/dist/cjs/react/hooks/useQRCamera.js.map +1 -1
  111. package/dist/cjs/react/sdk/src/core/EmailRecovery/emailRecoveryPendingStore.js +69 -0
  112. package/dist/cjs/react/sdk/src/core/EmailRecovery/emailRecoveryPendingStore.js.map +1 -0
  113. package/dist/cjs/react/sdk/src/core/EmailRecovery/index.js +32 -13
  114. package/dist/cjs/react/sdk/src/core/EmailRecovery/index.js.map +1 -1
  115. package/dist/cjs/react/sdk/src/core/IndexedDBManager/passkeyClientDB.js +35 -36
  116. package/dist/cjs/react/sdk/src/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  117. package/dist/cjs/react/sdk/src/core/NearClient.js +2 -1
  118. package/dist/cjs/react/sdk/src/core/NearClient.js.map +1 -1
  119. package/dist/cjs/react/sdk/src/core/TatchiPasskey/emailRecovery.js +557 -377
  120. package/dist/cjs/react/sdk/src/core/TatchiPasskey/emailRecovery.js.map +1 -1
  121. package/dist/cjs/react/sdk/src/core/TatchiPasskey/faucets/createAccountRelayServer.js +1 -0
  122. package/dist/cjs/react/sdk/src/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  123. package/dist/cjs/react/sdk/src/core/TatchiPasskey/index.js +26 -0
  124. package/dist/cjs/react/sdk/src/core/TatchiPasskey/index.js.map +1 -1
  125. package/dist/cjs/react/sdk/src/core/TatchiPasskey/linkDevice.js +2 -0
  126. package/dist/cjs/react/sdk/src/core/TatchiPasskey/linkDevice.js.map +1 -1
  127. package/dist/cjs/react/sdk/src/core/TatchiPasskey/login.js +15 -4
  128. package/dist/cjs/react/sdk/src/core/TatchiPasskey/login.js.map +1 -1
  129. package/dist/cjs/react/sdk/src/core/TatchiPasskey/recoverAccount.js +1 -0
  130. package/dist/cjs/react/sdk/src/core/TatchiPasskey/recoverAccount.js.map +1 -1
  131. package/dist/cjs/react/sdk/src/core/TatchiPasskey/relay.js +23 -1
  132. package/dist/cjs/react/sdk/src/core/TatchiPasskey/relay.js.map +1 -1
  133. package/dist/cjs/react/sdk/src/core/TatchiPasskey/scanDevice.js +1 -0
  134. package/dist/cjs/react/sdk/src/core/TatchiPasskey/scanDevice.js.map +1 -1
  135. package/dist/cjs/react/sdk/src/core/WalletIframe/client/IframeTransport.js +3 -0
  136. package/dist/cjs/react/sdk/src/core/WalletIframe/client/IframeTransport.js.map +1 -1
  137. package/dist/cjs/react/sdk/src/core/WalletIframe/client/router.js +15 -2
  138. package/dist/cjs/react/sdk/src/core/WalletIframe/client/router.js.map +1 -1
  139. package/dist/cjs/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js +1 -1
  140. package/dist/cjs/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js.map +1 -1
  141. package/dist/cjs/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js +52 -52
  142. package/dist/cjs/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js.map +1 -1
  143. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/getDeviceNumber.js +10 -1
  144. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/getDeviceNumber.js.map +1 -1
  145. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js +1 -0
  146. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js.map +1 -1
  147. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js +1 -0
  148. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js.map +1 -1
  149. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js +1 -0
  150. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js.map +1 -1
  151. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js +1 -0
  152. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js.map +1 -1
  153. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js +2 -1
  154. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js.map +1 -1
  155. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js +1 -0
  156. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js.map +1 -1
  157. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js +1 -0
  158. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js.map +1 -1
  159. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js +1 -0
  160. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js.map +1 -1
  161. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +2 -0
  162. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  163. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/index.js +1 -0
  164. package/dist/cjs/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/index.js.map +1 -1
  165. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js +1 -0
  166. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js.map +1 -1
  167. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js +6 -0
  168. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js.map +1 -1
  169. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js +2 -1
  170. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js.map +1 -1
  171. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js +1 -0
  172. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js.map +1 -1
  173. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +1 -0
  174. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  175. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +4 -15
  176. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  177. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js +1 -0
  178. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js.map +1 -1
  179. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js +1 -0
  180. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js.map +1 -1
  181. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js +1 -0
  182. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js.map +1 -1
  183. package/dist/cjs/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/index.js +17 -0
  184. package/dist/cjs/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/index.js.map +1 -0
  185. package/dist/cjs/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js +64 -54
  186. package/dist/cjs/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js.map +1 -1
  187. package/dist/cjs/react/sdk/src/core/WebAuthnManager/credentialsHelpers.js +12 -2
  188. package/dist/cjs/react/sdk/src/core/WebAuthnManager/credentialsHelpers.js.map +1 -1
  189. package/dist/cjs/react/sdk/src/core/WebAuthnManager/index.js +6 -1
  190. package/dist/cjs/react/sdk/src/core/WebAuthnManager/index.js.map +1 -1
  191. package/dist/cjs/react/sdk/src/core/WebAuthnManager/touchIdPrompt.js +209 -201
  192. package/dist/cjs/react/sdk/src/core/WebAuthnManager/touchIdPrompt.js.map +1 -1
  193. package/dist/cjs/react/sdk/src/core/WebAuthnManager/userHandle.js +2 -1
  194. package/dist/cjs/react/sdk/src/core/WebAuthnManager/userHandle.js.map +1 -1
  195. package/dist/cjs/react/sdk/src/core/defaultConfigs.js +1 -1
  196. package/dist/cjs/react/sdk/src/core/defaultConfigs.js.map +1 -1
  197. package/dist/cjs/react/sdk/src/core/rpcCalls.js +8 -0
  198. package/dist/cjs/react/sdk/src/core/rpcCalls.js.map +1 -1
  199. package/dist/cjs/react/sdk/src/core/types/vrf-worker.js +10 -1
  200. package/dist/cjs/react/sdk/src/core/types/vrf-worker.js.map +1 -1
  201. package/dist/cjs/react/sdk/src/utils/index.js +13 -3
  202. package/dist/cjs/server/email-recovery/emailEncryptor.js +11 -0
  203. package/dist/cjs/server/email-recovery/emailEncryptor.js.map +1 -1
  204. package/dist/cjs/server/email-recovery/emailParsers.js +57 -0
  205. package/dist/cjs/server/email-recovery/emailParsers.js.map +1 -1
  206. package/dist/cjs/server/email-recovery/index.js +1 -1
  207. package/dist/cjs/server/email-recovery/index.js.map +1 -1
  208. package/dist/cjs/server/email-recovery/rpcCalls.js +14 -1
  209. package/dist/cjs/server/email-recovery/rpcCalls.js.map +1 -1
  210. package/dist/cjs/server/index.js +1 -0
  211. package/dist/cjs/server/router/cloudflare.js.map +1 -1
  212. package/dist/cjs/server/router/express.js.map +1 -1
  213. package/dist/cjs/server/sdk/src/core/defaultConfigs.js +1 -1
  214. package/dist/cjs/server/sdk/src/core/defaultConfigs.js.map +1 -1
  215. package/dist/cjs/utils/index.js +13 -3
  216. package/dist/esm/core/EmailRecovery/emailRecoveryPendingStore.js +63 -0
  217. package/dist/esm/core/EmailRecovery/emailRecoveryPendingStore.js.map +1 -0
  218. package/dist/esm/core/EmailRecovery/index.js +28 -14
  219. package/dist/esm/core/EmailRecovery/index.js.map +1 -1
  220. package/dist/esm/core/IndexedDBManager/passkeyClientDB.js +35 -36
  221. package/dist/esm/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  222. package/dist/esm/core/NearClient.js +2 -1
  223. package/dist/esm/core/NearClient.js.map +1 -1
  224. package/dist/esm/core/TatchiPasskey/emailRecovery.js +557 -377
  225. package/dist/esm/core/TatchiPasskey/emailRecovery.js.map +1 -1
  226. package/dist/esm/core/TatchiPasskey/faucets/createAccountRelayServer.js +2 -1
  227. package/dist/esm/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  228. package/dist/esm/core/TatchiPasskey/index.js +28 -2
  229. package/dist/esm/core/TatchiPasskey/index.js.map +1 -1
  230. package/dist/esm/core/TatchiPasskey/linkDevice.js +4 -2
  231. package/dist/esm/core/TatchiPasskey/linkDevice.js.map +1 -1
  232. package/dist/esm/core/TatchiPasskey/login.js +13 -7
  233. package/dist/esm/core/TatchiPasskey/login.js.map +1 -1
  234. package/dist/esm/core/TatchiPasskey/recoverAccount.js +2 -1
  235. package/dist/esm/core/TatchiPasskey/recoverAccount.js.map +1 -1
  236. package/dist/esm/core/TatchiPasskey/relay.js +23 -1
  237. package/dist/esm/core/TatchiPasskey/relay.js.map +1 -1
  238. package/dist/esm/core/TatchiPasskey/scanDevice.js +2 -1
  239. package/dist/esm/core/TatchiPasskey/scanDevice.js.map +1 -1
  240. package/dist/esm/core/WalletIframe/client/IframeTransport.js +4 -1
  241. package/dist/esm/core/WalletIframe/client/IframeTransport.js.map +1 -1
  242. package/dist/esm/core/WalletIframe/client/router.js +16 -3
  243. package/dist/esm/core/WalletIframe/client/router.js.map +1 -1
  244. package/dist/esm/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js +1 -1
  245. package/dist/esm/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js.map +1 -1
  246. package/dist/esm/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js +52 -52
  247. package/dist/esm/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js.map +1 -1
  248. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/getDeviceNumber.js +6 -2
  249. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js +2 -1
  250. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js.map +1 -1
  251. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js +2 -1
  252. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js.map +1 -1
  253. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js +2 -1
  254. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js.map +1 -1
  255. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js +2 -1
  256. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js.map +1 -1
  257. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js +2 -1
  258. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js.map +1 -1
  259. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js +2 -1
  260. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js.map +1 -1
  261. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js +2 -1
  262. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js.map +1 -1
  263. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js +2 -1
  264. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js.map +1 -1
  265. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +4 -2
  266. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  267. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/index.js +2 -1
  268. package/dist/esm/core/WebAuthnManager/SignerWorkerManager/index.js.map +1 -1
  269. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js +1 -0
  270. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js.map +1 -1
  271. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js +8 -2
  272. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js.map +1 -1
  273. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js +2 -1
  274. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js.map +1 -1
  275. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js +2 -1
  276. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js.map +1 -1
  277. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +2 -1
  278. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  279. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +5 -16
  280. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  281. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js +2 -1
  282. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js.map +1 -1
  283. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js +2 -1
  284. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js.map +1 -1
  285. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js +2 -1
  286. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js.map +1 -1
  287. package/dist/esm/core/WebAuthnManager/WebAuthnFallbacks/index.js +12 -0
  288. package/dist/esm/core/WebAuthnManager/WebAuthnFallbacks/index.js.map +1 -0
  289. package/dist/esm/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js +61 -55
  290. package/dist/esm/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js.map +1 -1
  291. package/dist/esm/core/WebAuthnManager/credentialsHelpers.js +8 -3
  292. package/dist/esm/core/WebAuthnManager/index.js +8 -3
  293. package/dist/esm/core/WebAuthnManager/index.js.map +1 -1
  294. package/dist/esm/core/WebAuthnManager/touchIdPrompt.js +207 -204
  295. package/dist/esm/core/WebAuthnManager/touchIdPrompt.js.map +1 -1
  296. package/dist/esm/core/WebAuthnManager/userHandle.js +2 -1
  297. package/dist/esm/core/WebAuthnManager/userHandle.js.map +1 -1
  298. package/dist/esm/core/defaultConfigs.js +1 -1
  299. package/dist/esm/core/defaultConfigs.js.map +1 -1
  300. package/dist/esm/core/rpcCalls.js +8 -1
  301. package/dist/esm/core/rpcCalls.js.map +1 -1
  302. package/dist/esm/core/types/vrf-worker.js +6 -2
  303. package/dist/esm/index.js +4 -1
  304. package/dist/esm/index.js.map +1 -1
  305. package/dist/esm/react/components/AccountMenuButton/{LinkedDevicesModal-STvIsylA.css → LinkedDevicesModal-CSSowiHP.css} +1 -1
  306. package/dist/{cjs/react/components/AccountMenuButton/LinkedDevicesModal-STvIsylA.css.map → esm/react/components/AccountMenuButton/LinkedDevicesModal-CSSowiHP.css.map} +1 -1
  307. package/dist/esm/react/components/AccountMenuButton/{ProfileDropdown-iARgUwK1.css → ProfileDropdown-CEPMZ1gY.css} +1 -1
  308. package/dist/{cjs/react/components/AccountMenuButton/ProfileDropdown-iARgUwK1.css.map → esm/react/components/AccountMenuButton/ProfileDropdown-CEPMZ1gY.css.map} +1 -1
  309. package/dist/esm/react/components/AccountMenuButton/{Web3AuthProfileButton-Db3NeoAC.css → Web3AuthProfileButton-DopOg7Xc.css} +1 -1
  310. package/dist/esm/react/components/AccountMenuButton/{Web3AuthProfileButton-Db3NeoAC.css.map → Web3AuthProfileButton-DopOg7Xc.css.map} +1 -1
  311. package/dist/esm/react/components/AccountMenuButton/icons/{TouchIcon-BXM5NR4A.css → TouchIcon-BQWentvJ.css} +1 -1
  312. package/dist/esm/react/components/AccountMenuButton/icons/{TouchIcon-BXM5NR4A.css.map → TouchIcon-BQWentvJ.css.map} +1 -1
  313. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-De1qTSmU.css → PasskeyAuthMenu-DwrzWMYx.css} +14 -1
  314. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-De1qTSmU.css.map → PasskeyAuthMenu-DwrzWMYx.css.map} +1 -1
  315. package/dist/esm/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js +123 -54
  316. package/dist/esm/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js.map +1 -1
  317. package/dist/esm/react/components/{ShowQRCode-DCnR__fx.css → ShowQRCode-CCN4h6Uv.css} +1 -1
  318. package/dist/esm/react/components/{ShowQRCode-DCnR__fx.css.map → ShowQRCode-CCN4h6Uv.css.map} +1 -1
  319. package/dist/esm/react/deviceDetection.js +72 -93
  320. package/dist/esm/react/deviceDetection.js.map +1 -1
  321. package/dist/esm/react/hooks/useQRCamera.js +2 -1
  322. package/dist/esm/react/hooks/useQRCamera.js.map +1 -1
  323. package/dist/esm/react/sdk/src/core/EmailRecovery/emailRecoveryPendingStore.js +63 -0
  324. package/dist/esm/react/sdk/src/core/EmailRecovery/emailRecoveryPendingStore.js.map +1 -0
  325. package/dist/esm/react/sdk/src/core/EmailRecovery/index.js +28 -14
  326. package/dist/esm/react/sdk/src/core/EmailRecovery/index.js.map +1 -1
  327. package/dist/esm/react/sdk/src/core/IndexedDBManager/passkeyClientDB.js +35 -36
  328. package/dist/esm/react/sdk/src/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  329. package/dist/esm/react/sdk/src/core/NearClient.js +2 -1
  330. package/dist/esm/react/sdk/src/core/NearClient.js.map +1 -1
  331. package/dist/esm/react/sdk/src/core/TatchiPasskey/emailRecovery.js +557 -377
  332. package/dist/esm/react/sdk/src/core/TatchiPasskey/emailRecovery.js.map +1 -1
  333. package/dist/esm/react/sdk/src/core/TatchiPasskey/faucets/createAccountRelayServer.js +2 -1
  334. package/dist/esm/react/sdk/src/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  335. package/dist/esm/react/sdk/src/core/TatchiPasskey/index.js +28 -2
  336. package/dist/esm/react/sdk/src/core/TatchiPasskey/index.js.map +1 -1
  337. package/dist/esm/react/sdk/src/core/TatchiPasskey/linkDevice.js +4 -2
  338. package/dist/esm/react/sdk/src/core/TatchiPasskey/linkDevice.js.map +1 -1
  339. package/dist/esm/react/sdk/src/core/TatchiPasskey/login.js +13 -7
  340. package/dist/esm/react/sdk/src/core/TatchiPasskey/login.js.map +1 -1
  341. package/dist/esm/react/sdk/src/core/TatchiPasskey/recoverAccount.js +2 -1
  342. package/dist/esm/react/sdk/src/core/TatchiPasskey/recoverAccount.js.map +1 -1
  343. package/dist/esm/react/sdk/src/core/TatchiPasskey/relay.js +23 -1
  344. package/dist/esm/react/sdk/src/core/TatchiPasskey/relay.js.map +1 -1
  345. package/dist/esm/react/sdk/src/core/TatchiPasskey/scanDevice.js +2 -1
  346. package/dist/esm/react/sdk/src/core/TatchiPasskey/scanDevice.js.map +1 -1
  347. package/dist/esm/react/sdk/src/core/WalletIframe/client/IframeTransport.js +4 -1
  348. package/dist/esm/react/sdk/src/core/WalletIframe/client/IframeTransport.js.map +1 -1
  349. package/dist/esm/react/sdk/src/core/WalletIframe/client/router.js +16 -3
  350. package/dist/esm/react/sdk/src/core/WalletIframe/client/router.js.map +1 -1
  351. package/dist/esm/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js +1 -1
  352. package/dist/esm/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.js.map +1 -1
  353. package/dist/esm/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js +52 -52
  354. package/dist/esm/react/sdk/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.js.map +1 -1
  355. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/getDeviceNumber.js +6 -2
  356. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js +2 -1
  357. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.js.map +1 -1
  358. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js +2 -1
  359. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.js.map +1 -1
  360. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js +2 -1
  361. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.js.map +1 -1
  362. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js +2 -1
  363. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.js.map +1 -1
  364. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js +2 -1
  365. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.js.map +1 -1
  366. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js +2 -1
  367. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.js.map +1 -1
  368. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js +2 -1
  369. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.js.map +1 -1
  370. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js +2 -1
  371. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.js.map +1 -1
  372. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js +4 -2
  373. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.js.map +1 -1
  374. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/index.js +2 -1
  375. package/dist/esm/react/sdk/src/core/WebAuthnManager/SignerWorkerManager/index.js.map +1 -1
  376. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js +1 -0
  377. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.js.map +1 -1
  378. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js +8 -2
  379. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js.map +1 -1
  380. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js +2 -1
  381. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.js.map +1 -1
  382. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js +2 -1
  383. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js.map +1 -1
  384. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +2 -1
  385. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  386. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +5 -16
  387. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  388. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js +2 -1
  389. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.js.map +1 -1
  390. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js +2 -1
  391. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.js.map +1 -1
  392. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js +2 -1
  393. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.js.map +1 -1
  394. package/dist/esm/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/index.js +12 -0
  395. package/dist/esm/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/index.js.map +1 -0
  396. package/dist/esm/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js +61 -55
  397. package/dist/esm/react/sdk/src/core/WebAuthnManager/WebAuthnFallbacks/safari-fallbacks.js.map +1 -1
  398. package/dist/esm/react/sdk/src/core/WebAuthnManager/credentialsHelpers.js +8 -3
  399. package/dist/esm/react/sdk/src/core/WebAuthnManager/index.js +8 -3
  400. package/dist/esm/react/sdk/src/core/WebAuthnManager/index.js.map +1 -1
  401. package/dist/esm/react/sdk/src/core/WebAuthnManager/touchIdPrompt.js +207 -204
  402. package/dist/esm/react/sdk/src/core/WebAuthnManager/touchIdPrompt.js.map +1 -1
  403. package/dist/esm/react/sdk/src/core/WebAuthnManager/userHandle.js +2 -1
  404. package/dist/esm/react/sdk/src/core/WebAuthnManager/userHandle.js.map +1 -1
  405. package/dist/esm/react/sdk/src/core/defaultConfigs.js +1 -1
  406. package/dist/esm/react/sdk/src/core/defaultConfigs.js.map +1 -1
  407. package/dist/esm/react/sdk/src/core/rpcCalls.js +8 -1
  408. package/dist/esm/react/sdk/src/core/rpcCalls.js.map +1 -1
  409. package/dist/esm/react/sdk/src/core/types/vrf-worker.js +6 -2
  410. package/dist/esm/react/sdk/src/utils/index.js +10 -4
  411. package/dist/esm/react/styles/styles.css +13 -0
  412. package/dist/esm/sdk/{safari-fallbacks-oQKu9xUs.js → WebAuthnFallbacks-Bl4BTsNt.js} +131 -135
  413. package/dist/esm/sdk/{createAdapters-pNiL2KNq.js → createAdapters-BumKM2ft.js} +59 -54
  414. package/dist/esm/sdk/createAdapters-BumKM2ft.js.map +1 -0
  415. package/dist/esm/sdk/{createAdapters-BWLe9Ddo.js → createAdapters-qVGD6i0g.js} +10 -3
  416. package/dist/esm/sdk/{defaultConfigs-VzvDejmy.js → defaultConfigs-DpslkAQd.js} +1 -1
  417. package/dist/esm/sdk/{getDeviceNumber-CkWRT17I.js → getDeviceNumber-fXizNGQl.js} +2 -2
  418. package/dist/esm/sdk/getDeviceNumber-fXizNGQl.js.map +1 -0
  419. package/dist/esm/sdk/{getDeviceNumber-CfmlgfMX.js → getDeviceNumber-zsOHT_Um.js} +6 -3
  420. package/dist/esm/sdk/{localOnly-DnpSyDaF.js → localOnly-Byi3AK7A.js} +2 -2
  421. package/dist/esm/sdk/{localOnly-DnpSyDaF.js.map → localOnly-Byi3AK7A.js.map} +1 -1
  422. package/dist/esm/sdk/{localOnly-BdumO2st.js → localOnly-pXMTqh1m.js} +5 -4
  423. package/dist/esm/sdk/offline-export-app.js +46 -44
  424. package/dist/esm/sdk/offline-export-app.js.map +1 -1
  425. package/dist/esm/sdk/{overlay-BTqPGG-o.js → overlay-ZGbucXIa.js} +2 -0
  426. package/dist/esm/sdk/{registration-C633u6x8.js → registration-CBiS4Ua_.js} +2 -2
  427. package/dist/esm/sdk/{registration-C633u6x8.js.map → registration-CBiS4Ua_.js.map} +1 -1
  428. package/dist/esm/sdk/{registration-xyYUFRqk.js → registration-DLPLsGCz.js} +5 -4
  429. package/dist/esm/sdk/{requestHelpers-DLBGBHMw.js → requestHelpers-Dh1hEYL9.js} +206 -204
  430. package/dist/esm/sdk/{router-BG6KC_p7.js → router-DuGYOd3G.js} +19 -4
  431. package/dist/esm/sdk/{rpcCalls-fLObBbbz.js → rpcCalls-BQrJMTdg.js} +3 -3
  432. package/dist/esm/sdk/{rpcCalls-CAU5XYEF.js → rpcCalls-YVeUVMk2.js} +9 -2
  433. package/dist/esm/sdk/{transactions-jH38BZ-Q.js → transactions-BIqKZeR0.js} +6 -18
  434. package/dist/esm/sdk/transactions-BIqKZeR0.js.map +1 -0
  435. package/dist/esm/sdk/{transactions-CzZAt1Yn.js → transactions-Bk-VavcV.js} +10 -21
  436. package/dist/esm/sdk/tx-confirm-ui.js +53 -53
  437. package/dist/esm/sdk/{tx-confirmer-wrapper-CqfVBUaA.js → tx-confirmer-wrapper-lHNgz9i4.js} +53 -53
  438. package/dist/esm/sdk/tx-confirmer.css +6 -4
  439. package/dist/esm/sdk/w3a-tx-confirmer.js +1 -1
  440. package/dist/esm/sdk/wallet-iframe-host.js +782 -447
  441. package/dist/esm/server/email-recovery/emailEncryptor.js +11 -1
  442. package/dist/esm/server/email-recovery/emailEncryptor.js.map +1 -1
  443. package/dist/esm/server/email-recovery/emailParsers.js +55 -1
  444. package/dist/esm/server/email-recovery/emailParsers.js.map +1 -1
  445. package/dist/esm/server/email-recovery/index.js +2 -2
  446. package/dist/esm/server/email-recovery/index.js.map +1 -1
  447. package/dist/esm/server/email-recovery/rpcCalls.js +14 -1
  448. package/dist/esm/server/email-recovery/rpcCalls.js.map +1 -1
  449. package/dist/esm/server/index.js +2 -2
  450. package/dist/esm/server/router/cloudflare.js.map +1 -1
  451. package/dist/esm/server/router/express.js.map +1 -1
  452. package/dist/esm/server/sdk/src/core/defaultConfigs.js +1 -1
  453. package/dist/esm/server/sdk/src/core/defaultConfigs.js.map +1 -1
  454. package/dist/esm/utils/index.js +10 -4
  455. package/dist/esm/wasm_vrf_worker/pkg/wasm_vrf_worker.js +3 -0
  456. package/dist/esm/wasm_vrf_worker/pkg/wasm_vrf_worker_bg.wasm +0 -0
  457. package/dist/types/src/core/EmailRecovery/emailRecoveryPendingStore.d.ts +25 -0
  458. package/dist/types/src/core/EmailRecovery/emailRecoveryPendingStore.d.ts.map +1 -0
  459. package/dist/types/src/core/EmailRecovery/index.d.ts +1 -0
  460. package/dist/types/src/core/EmailRecovery/index.d.ts.map +1 -1
  461. package/dist/types/src/core/IndexedDBManager/passkeyClientDB.d.ts +11 -21
  462. package/dist/types/src/core/IndexedDBManager/passkeyClientDB.d.ts.map +1 -1
  463. package/dist/types/src/core/TatchiPasskey/emailRecovery.d.ts +45 -5
  464. package/dist/types/src/core/TatchiPasskey/emailRecovery.d.ts.map +1 -1
  465. package/dist/types/src/core/TatchiPasskey/index.d.ts +10 -2
  466. package/dist/types/src/core/TatchiPasskey/index.d.ts.map +1 -1
  467. package/dist/types/src/core/TatchiPasskey/relay.d.ts +2 -1
  468. package/dist/types/src/core/TatchiPasskey/relay.d.ts.map +1 -1
  469. package/dist/types/src/core/WalletIframe/TatchiPasskeyIframe.d.ts +4 -0
  470. package/dist/types/src/core/WalletIframe/TatchiPasskeyIframe.d.ts.map +1 -1
  471. package/dist/types/src/core/WalletIframe/client/router.d.ts +7 -3
  472. package/dist/types/src/core/WalletIframe/client/router.d.ts.map +1 -1
  473. package/dist/types/src/core/WalletIframe/host/wallet-iframe-handlers.d.ts.map +1 -1
  474. package/dist/types/src/core/WalletIframe/shared/messages.d.ts +6 -2
  475. package/dist/types/src/core/WalletIframe/shared/messages.d.ts.map +1 -1
  476. package/dist/types/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-drawer.d.ts.map +1 -1
  477. package/dist/types/src/core/WebAuthnManager/LitComponents/IframeTxConfirmer/viewer-modal.d.ts.map +1 -1
  478. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/vrf.d.ts.map +1 -1
  479. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.d.ts.map +1 -1
  480. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.d.ts.map +1 -1
  481. package/dist/types/src/core/WebAuthnManager/index.d.ts.map +1 -1
  482. package/dist/types/src/core/defaultConfigs.d.ts.map +1 -1
  483. package/dist/types/src/core/rpcCalls.d.ts +9 -0
  484. package/dist/types/src/core/rpcCalls.d.ts.map +1 -1
  485. package/dist/types/src/index.d.ts +1 -0
  486. package/dist/types/src/index.d.ts.map +1 -1
  487. package/dist/types/src/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.d.ts.map +1 -1
  488. package/dist/types/src/server/email-recovery/emailEncryptor.d.ts +4 -0
  489. package/dist/types/src/server/email-recovery/emailEncryptor.d.ts.map +1 -1
  490. package/dist/types/src/server/email-recovery/emailParsers.d.ts +7 -0
  491. package/dist/types/src/server/email-recovery/emailParsers.d.ts.map +1 -1
  492. package/dist/types/src/server/email-recovery/index.d.ts +1 -1
  493. package/dist/types/src/server/email-recovery/rpcCalls.d.ts +1 -1
  494. package/dist/types/src/server/email-recovery/rpcCalls.d.ts.map +1 -1
  495. package/dist/types/src/wasm_vrf_worker/pkg/wasm_vrf_worker.d.ts.map +1 -1
  496. package/dist/workers/wasm_vrf_worker_bg.wasm +0 -0
  497. package/dist/workers/web3authn-vrf.worker.js +3 -0
  498. package/package.json +1 -1
  499. package/dist/esm/sdk/createAdapters-pNiL2KNq.js.map +0 -1
  500. package/dist/esm/sdk/getDeviceNumber-CkWRT17I.js.map +0 -1
  501. package/dist/esm/sdk/transactions-jH38BZ-Q.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"rpcCalls.js","names":["error: any","ActionType","ActionPhase","DeviceLinkingPhase","DeviceLinkingStatus","addKeyTxResult: FinalExecutionOutcome","storeDeviceLinkingTxResult: FinalExecutionOutcome","DEFAULT_WAIT_STATUS","txError: any","base64UrlEncode","DEFAULT_EMAIL_RECOVERY_CONTRACTS","base64UrlDecode","err: unknown","errorMessage"],"sources":["../../../../../../src/core/rpcCalls.ts"],"sourcesContent":["/**\n * Consolidated NEAR Contract Calls\n *\n * This file contains all the NEAR contract calls made to the web3authn contract\n * throughout the passkey SDK. It provides a centralized location for all\n * contract interactions and makes it easier to maintain and update contract\n * call patterns.\n */\n\nimport type { FinalExecutionOutcome } from '@near-js/types';\nimport type { NearClient, SignedTransaction } from './NearClient';\nimport type { ContractStoredAuthenticator } from './TatchiPasskey/recoverAccount';\nimport type { PasskeyManagerContext } from './TatchiPasskey';\nimport type { AccountId } from './types/accountIds';\nimport type { DeviceLinkingSSEEvent } from './types/sdkSentEvents';\nimport type {\n StoredAuthenticator,\n WebAuthnRegistrationCredential,\n WebAuthnAuthenticationCredential\n} from './types/webauthn';\n\nimport { ActionPhase, DeviceLinkingPhase, DeviceLinkingStatus } from './types/sdkSentEvents';\nimport { ActionType, type ActionArgs } from './types/actions';\nimport { VRFChallenge } from './types/vrf-worker';\nimport { DEFAULT_WAIT_STATUS, TransactionContext } from './types/rpc';\nimport type { AuthenticatorOptions } from './types/authenticatorOptions';\nimport type { ConfirmationConfig } from './types/signer-worker';\nimport { base64UrlDecode, base64UrlEncode } from '../utils/encoders';\nimport { errorMessage } from '../utils/errors';\nimport type { EmailRecoveryContracts } from './types/tatchi';\nimport { DEFAULT_EMAIL_RECOVERY_CONTRACTS } from './defaultConfigs';\n\n// ===========================\n// CONTRACT CALL RESPONSES\n// ===========================\n\nexport interface DeviceLinkingResult {\n linkedAccountId: string;\n deviceNumber: number;\n}\n\nexport interface CredentialIdsResult {\n credentialIds: string[];\n}\n\nexport interface AuthenticatorsResult {\n authenticators: Array<[string, ContractStoredAuthenticator]>;\n}\n\n// ===========================\n// DEVICE LINKING CONTRACT CALLS\n// ===========================\n\n/**\n * Query the contract to get the account linked to a device public key\n * Used in device linking flow to check if a device key has been added\n *\n * NEAR does not provide a way to lookup the AccountID an access key has access to.\n * So we store a temporary mapping in the contract to lookup pubkey -> account ID.\n */\nexport async function getDeviceLinkingAccountContractCall(\n nearClient: NearClient,\n contractId: string,\n devicePublicKey: string\n): Promise<DeviceLinkingResult | null> {\n try {\n const result = await nearClient.callFunction<\n { device_public_key: string },\n [string, number | string]\n >(\n contractId,\n 'get_device_linking_account',\n { device_public_key: devicePublicKey }\n );\n\n // Handle different result formats\n if (result && Array.isArray(result) && result.length >= 2) {\n const [linkedAccountId, deviceNumberRaw] = result;\n const deviceNumber = Number(deviceNumberRaw);\n if (!Number.isSafeInteger(deviceNumber) || deviceNumber < 0) {\n console.warn(\n 'Invalid deviceNumber returned from get_device_linking_account:',\n deviceNumberRaw\n );\n return null;\n }\n return {\n linkedAccountId,\n deviceNumber\n };\n }\n\n return null;\n } catch (error: any) {\n console.warn('Failed to get device linking account:', error.message);\n return null;\n }\n}\n\n// ===========================\n// DEVICE LINKING TRANSACTION CALLS\n// ===========================\n\n/**\n * Execute device1's linking transactions (AddKey + Contract mapping)\n * This function signs and broadcasts both transactions required for device linking\n */\nexport async function executeDeviceLinkingContractCalls({\n context,\n device1AccountId,\n device2PublicKey,\n nextNonce,\n nextNextNonce,\n nextNextNextNonce,\n txBlockHash,\n vrfChallenge,\n onEvent,\n confirmationConfigOverride,\n confirmerText,\n}: {\n context: PasskeyManagerContext,\n device1AccountId: AccountId,\n device2PublicKey: string,\n nextNonce: string,\n nextNextNonce: string,\n nextNextNextNonce: string,\n txBlockHash: string,\n vrfChallenge: VRFChallenge,\n onEvent?: (event: DeviceLinkingSSEEvent) => void;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n confirmerText?: { title?: string; body?: string };\n}): Promise<{\n addKeyTxResult: FinalExecutionOutcome;\n storeDeviceLinkingTxResult: FinalExecutionOutcome;\n signedDeleteKeyTransaction: SignedTransaction\n}> {\n\n // Sign three transactions with one PRF authentication\n const signedTransactions = await context.webAuthnManager.signTransactionsWithActions({\n rpcCall: {\n contractId: context.webAuthnManager.tatchiPasskeyConfigs.contractId,\n nearRpcUrl: context.webAuthnManager.tatchiPasskeyConfigs.nearRpcUrl,\n nearAccountId: device1AccountId\n },\n confirmationConfigOverride,\n title: confirmerText?.title,\n body: confirmerText?.body,\n transactions: [\n // Transaction 1: AddKey - Add Device2's key to Device1's account\n {\n receiverId: device1AccountId,\n actions: [{\n action_type: ActionType.AddKey,\n public_key: device2PublicKey,\n access_key: JSON.stringify({\n // NEAR-style AccessKey JSON shape, matching near-api-js:\n // { nonce: number, permission: { FullAccess: {} } }\n nonce: 0,\n permission: { FullAccess: {} },\n }),\n }],\n nonce: nextNonce,\n },\n // Transaction 2: Store temporary mapping in contract so Device2 can lookup Device1's accountID.\n {\n receiverId: context.webAuthnManager.tatchiPasskeyConfigs.contractId,\n actions: [{\n action_type: ActionType.FunctionCall,\n method_name: 'store_device_linking_mapping',\n args: JSON.stringify({\n device_public_key: device2PublicKey,\n target_account_id: device1AccountId,\n }),\n gas: '30000000000000', // 30 TGas for device linking with yield promise automatic cleanup\n deposit: '0'\n }],\n nonce: nextNextNonce,\n },\n // Transaction 3: Remove Device2's temporary key if it fails to complete linking after a timeout\n {\n receiverId: device1AccountId,\n actions: [{\n action_type: ActionType.DeleteKey,\n public_key: device2PublicKey\n }],\n nonce: nextNextNextNonce,\n }\n ],\n onEvent: (progress) => {\n // Bridge all action progress events to the parent so the wallet iframe overlay\n // can expand during user confirmation in wallet-iframe mode.\n try { onEvent?.(progress as any); } catch { }\n // Keep existing mapping for device linking semantics; surface signing as a loading state\n if (progress.phase == ActionPhase.STEP_6_TRANSACTION_SIGNING_COMPLETE) {\n onEvent?.({\n step: 3,\n phase: DeviceLinkingPhase.STEP_3_AUTHORIZATION,\n status: DeviceLinkingStatus.PROGRESS,\n message: progress.message || 'Transaction signing in progress...'\n })\n }\n }\n });\n\n if (!signedTransactions[0].signedTransaction) {\n throw new Error('AddKey transaction signing failed');\n }\n if (!signedTransactions[1].signedTransaction) {\n throw new Error('Contract mapping transaction signing failed');\n }\n if (!signedTransactions[2].signedTransaction) {\n throw new Error('DeleteKey transaction signing failed');\n }\n\n // Broadcast just the first 2 transactions: addKey and store device linking mapping\n let addKeyTxResult: FinalExecutionOutcome;\n let storeDeviceLinkingTxResult: FinalExecutionOutcome;\n try {\n console.debug('LinkDeviceFlow: AddKey transaction details:', {\n receiverId: signedTransactions[0].signedTransaction.transaction.receiverId,\n actions: signedTransactions[0].signedTransaction.transaction.actions || [],\n transactionKeys: Object.keys(signedTransactions[0].signedTransaction.transaction),\n });\n\n addKeyTxResult = await context.nearClient.sendTransaction(\n signedTransactions[0].signedTransaction,\n DEFAULT_WAIT_STATUS.linkDeviceAddKey\n );\n console.log('LinkDeviceFlow: AddKey transaction result:', addKeyTxResult?.transaction?.hash);\n\n // Send success events immediately after AddKey succeeds\n onEvent?.({\n step: 3,\n phase: DeviceLinkingPhase.STEP_3_AUTHORIZATION,\n status: DeviceLinkingStatus.SUCCESS,\n message: `AddKey transaction completed successfully!`\n });\n\n // Check if contract mapping transaction is valid before attempting to broadcast\n const contractTx = signedTransactions[1].signedTransaction;\n console.log('LinkDeviceFlow: Contract mapping transaction details:', {\n receiverId: contractTx.transaction.receiverId,\n actions: (contractTx.transaction.actions || []).length\n });\n\n // Standard timeout since nonce conflict should be resolved by the 2s delay\n storeDeviceLinkingTxResult = await context.nearClient.sendTransaction(\n contractTx,\n DEFAULT_WAIT_STATUS.linkDeviceAccountMapping\n );\n\n } catch (txError: any) {\n console.error('LinkDeviceFlow: Transaction broadcasting failed:', txError);\n throw new Error(`Transaction broadcasting failed: ${txError.message}`);\n }\n\n onEvent?.({\n step: 6,\n phase: DeviceLinkingPhase.STEP_6_REGISTRATION,\n status: DeviceLinkingStatus.SUCCESS,\n message: `Device linking completed successfully!`\n });\n\n return {\n addKeyTxResult,\n storeDeviceLinkingTxResult,\n signedDeleteKeyTransaction: signedTransactions[2].signedTransaction\n };\n}\n\n// ===========================\n// ACCOUNT RECOVERY CONTRACT CALLS\n// ===========================\n\n/**\n * Get credential IDs associated with an account from the contract\n * Used in account recovery to discover available credentials\n */\nexport async function getCredentialIdsContractCall(\n nearClient: NearClient,\n contractId: string,\n accountId: AccountId\n): Promise<string[]> {\n try {\n const credentialIds = await nearClient.callFunction<{ account_id: AccountId }, string[]>(\n contractId,\n 'get_credential_ids_by_account',\n { account_id: accountId }\n );\n return credentialIds || [];\n } catch (error: any) {\n console.warn('Failed to fetch credential IDs from contract:', error.message);\n return [];\n }\n}\n\n/**\n * Get all authenticators stored for a user from the contract\n * Used in account recovery to sync authenticator data\n */\nexport async function getAuthenticatorsByUser(\n nearClient: NearClient,\n contractId: string,\n accountId: AccountId\n): Promise<[string, ContractStoredAuthenticator][]> {\n try {\n const authenticatorsResult = await nearClient.view<{ user_id: AccountId }, [string, ContractStoredAuthenticator][]>({\n account: contractId,\n method: 'get_authenticators_by_user',\n args: { user_id: accountId }\n });\n\n if (authenticatorsResult && Array.isArray(authenticatorsResult)) {\n return authenticatorsResult;\n }\n return [];\n } catch (error: any) {\n console.warn('Failed to fetch authenticators from contract:', error.message);\n return [];\n }\n}\n\nexport async function syncAuthenticatorsContractCall(\n nearClient: NearClient,\n contractId: string,\n accountId: AccountId\n): Promise<Array<{ credentialId: string, authenticator: StoredAuthenticator }>> {\n try {\n const authenticatorsResult = await getAuthenticatorsByUser(nearClient, contractId, accountId);\n if (authenticatorsResult && Array.isArray(authenticatorsResult)) {\n return authenticatorsResult.map(([credentialId, contractAuthenticator]) => {\n console.log(`Contract authenticator device_number for ${credentialId}:`, contractAuthenticator.device_number);\n\n const transports = Array.isArray(contractAuthenticator.transports)\n ? contractAuthenticator.transports\n : [];\n\n const registered = (() => {\n const raw = String((contractAuthenticator as any).registered ?? '');\n if (!raw) return new Date(0);\n if (/^\\d+$/.test(raw)) {\n const ts = Number(raw);\n return Number.isFinite(ts) ? new Date(ts) : new Date(0);\n }\n const d = new Date(raw);\n return Number.isFinite(d.getTime()) ? d : new Date(0);\n })();\n\n const vrfPublicKeys = (() => {\n const raw = (contractAuthenticator as any).vrf_public_keys;\n if (!raw) return undefined;\n if (Array.isArray(raw) && raw.length > 0 && typeof raw[0] === 'string') {\n return raw as string[];\n }\n if (Array.isArray(raw)) {\n return raw\n .map((entry: unknown) => {\n if (!entry) return null;\n if (entry instanceof Uint8Array) return base64UrlEncode(entry);\n if (Array.isArray(entry)) return base64UrlEncode(new Uint8Array(entry));\n return null;\n })\n .filter((x): x is string => typeof x === 'string' && x.length > 0);\n }\n return undefined;\n })();\n\n return {\n credentialId,\n authenticator: {\n credentialId,\n credentialPublicKey: new Uint8Array(contractAuthenticator.credential_public_key),\n transports,\n userId: accountId,\n name: `Device ${contractAuthenticator.device_number} Authenticator`,\n registered,\n // Store the actual device number from contract (no fallback)\n deviceNumber: contractAuthenticator.device_number,\n vrfPublicKeys\n }\n };\n });\n }\n return [];\n } catch (error: any) {\n console.warn('Failed to fetch authenticators from contract:', error.message);\n return [];\n }\n}\n\n// ===========================\n// RECOVERY EMAIL CONTRACT CALLS\n// ===========================\n\n/**\n * Fetch on-chain recovery email hashes from the per-account contract.\n * Returns [] when no contract is deployed or on failure.\n */\nexport async function getRecoveryEmailHashesContractCall(\n nearClient: NearClient,\n accountId: AccountId\n): Promise<number[][]> {\n try {\n const code = await nearClient.viewCode(accountId);\n const hasContract = !!code && code.byteLength > 0;\n if (!hasContract) return [];\n\n const hashes = await nearClient.view<Record<string, never>, number[][]>({\n account: accountId,\n method: 'get_recovery_emails',\n args: {} as Record<string, never>,\n });\n\n return Array.isArray(hashes) ? (hashes as number[][]) : [];\n } catch (error) {\n console.error('[rpcCalls] Failed to fetch recovery email hashes', error);\n return [];\n }\n}\n\n/**\n * Build action args to update on-chain recovery emails for an account.\n * If the per-account contract is missing, deploy/attach the global recoverer via `init_email_recovery`.\n */\nexport async function buildSetRecoveryEmailsActions(\n nearClient: NearClient,\n accountId: AccountId,\n recoveryEmailHashes: number[][],\n contracts: EmailRecoveryContracts = DEFAULT_EMAIL_RECOVERY_CONTRACTS\n): Promise<ActionArgs[]> {\n let hasContract = false;\n try {\n const code = await nearClient.viewCode(accountId);\n hasContract = !!code && code.byteLength > 0;\n } catch {\n hasContract = false;\n }\n\n const {\n emailRecovererGlobalContract,\n zkEmailVerifierContract,\n emailDkimVerifierContract,\n } = contracts;\n\n return hasContract\n ? [\n {\n type: ActionType.UseGlobalContract,\n accountId: emailRecovererGlobalContract,\n },\n {\n type: ActionType.FunctionCall,\n methodName: 'set_recovery_emails',\n args: {\n recovery_emails: recoveryEmailHashes,\n },\n gas: '80000000000000',\n deposit: '0',\n },\n ]\n : [\n {\n type: ActionType.UseGlobalContract,\n accountId: emailRecovererGlobalContract,\n },\n {\n type: ActionType.FunctionCall,\n methodName: 'init_email_recovery',\n args: {\n zk_email_verifier: zkEmailVerifierContract,\n email_dkim_verifier: emailDkimVerifierContract,\n policy: null,\n recovery_emails: recoveryEmailHashes,\n },\n gas: '80000000000000',\n deposit: '0',\n },\n ];\n}\n\nexport async function fetchNonceBlockHashAndHeight({ nearClient, nearPublicKeyStr, nearAccountId }: {\n nearClient: NearClient,\n nearPublicKeyStr: string,\n nearAccountId: AccountId\n}): Promise<TransactionContext> {\n // Get access key and transaction block info concurrently\n const [accessKeyInfo, txBlockInfo] = await Promise.all([\n nearClient.viewAccessKey(nearAccountId, nearPublicKeyStr)\n .catch(e => { throw new Error(`Failed to fetch Access Key`) }),\n nearClient.viewBlock({ finality: 'final' })\n .catch(e => { throw new Error(`Failed to fetch Block Info`) })\n ]);\n if (!accessKeyInfo || accessKeyInfo.nonce === undefined) {\n throw new Error(`Access key not found or invalid for account ${nearAccountId} with public key ${nearPublicKeyStr}. Response: ${JSON.stringify(accessKeyInfo)}`);\n }\n const nextNonce = (BigInt(accessKeyInfo.nonce) + BigInt(1)).toString();\n const txBlockHeight = String(txBlockInfo.header.height);\n const txBlockHash = txBlockInfo.header.hash; // Keep original base58 string\n\n return {\n nearPublicKeyStr,\n accessKeyInfo,\n nextNonce,\n txBlockHeight,\n txBlockHash,\n };\n}\n\n// ===========================\n// REGISTRATION PRE-CHECK CALL\n// ===========================\n\nexport interface CheckCanRegisterUserResult {\n success: boolean;\n verified: boolean;\n logs: string[];\n error?: string;\n}\n\n/**\n * View-only registration pre-check.\n *\n * Calls the contract's `check_can_register_user` view method with VRF data\n * derived from the provided VRF challenge and a serialized WebAuthn\n * registration credential (typically with PRF outputs embedded).\n */\nexport async function checkCanRegisterUserContractCall({\n nearClient,\n contractId,\n vrfChallenge,\n credential,\n authenticatorOptions,\n}: {\n nearClient: NearClient;\n contractId: string;\n vrfChallenge: VRFChallenge;\n credential: WebAuthnRegistrationCredential;\n authenticatorOptions?: AuthenticatorOptions;\n}): Promise<CheckCanRegisterUserResult> {\n try {\n const vrfData = {\n vrf_input_data: Array.from(base64UrlDecode(vrfChallenge.vrfInput)),\n vrf_output: Array.from(base64UrlDecode(vrfChallenge.vrfOutput)),\n vrf_proof: Array.from(base64UrlDecode(vrfChallenge.vrfProof)),\n public_key: Array.from(base64UrlDecode(vrfChallenge.vrfPublicKey)),\n user_id: vrfChallenge.userId,\n rp_id: vrfChallenge.rpId,\n block_height: Number(vrfChallenge.blockHeight),\n block_hash: Array.from(base64UrlDecode(vrfChallenge.blockHash)),\n };\n\n const args = {\n vrf_data: vrfData,\n webauthn_registration: credential,\n authenticator_options: authenticatorOptions,\n };\n\n const response = await nearClient.callFunction<typeof args, any>(\n contractId,\n 'check_can_register_user',\n args,\n );\n\n const verified = !!response?.verified;\n return {\n success: true,\n verified,\n logs: [],\n error: verified ? undefined : 'Contract registration check failed',\n };\n } catch (err: unknown) {\n return {\n success: false,\n verified: false,\n logs: [],\n error: errorMessage(err) || 'Failed to call check_can_register_user',\n };\n }\n}\n\n\n/**\n * Verify authentication response through relay server\n * Routes the request to relay server which calls the web3authn contract for verification\n * and issues a JWT or session credential\n */\nexport async function verifyAuthenticationResponse(\n relayServerUrl: string,\n routePath: string,\n sessionKind: 'jwt' | 'cookie',\n vrfChallenge: VRFChallenge,\n webauthnAuthentication: WebAuthnAuthenticationCredential\n): Promise<{\n success: boolean;\n verified?: boolean;\n jwt?: string;\n sessionCredential?: any;\n error?: string;\n contractResponse?: any;\n}> {\n try {\n // Map VRFChallenge into server ContractVrfData shape (number arrays)\n const toBytes = (b64u: string | undefined): number[] => {\n if (!b64u) return [];\n return Array.from(base64UrlDecode(b64u));\n };\n const vrf_data = {\n vrf_input_data: toBytes(vrfChallenge.vrfInput),\n vrf_output: toBytes(vrfChallenge.vrfOutput),\n vrf_proof: toBytes(vrfChallenge.vrfProof),\n public_key: toBytes(vrfChallenge.vrfPublicKey),\n user_id: vrfChallenge.userId,\n rp_id: vrfChallenge.rpId,\n block_height: Number(vrfChallenge.blockHeight || 0),\n block_hash: toBytes(vrfChallenge.blockHash),\n };\n\n // Normalize authenticatorAttachment and userHandle to null for server schema\n const webauthn_authentication = {\n ...webauthnAuthentication,\n authenticatorAttachment: webauthnAuthentication.authenticatorAttachment ?? null,\n response: {\n ...webauthnAuthentication.response,\n userHandle: webauthnAuthentication.response.userHandle ?? null,\n }\n };\n\n const url = `${relayServerUrl.replace(/\\/$/, '')}${routePath.startsWith('/') ? routePath : `/${routePath}`}`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n credentials: sessionKind === 'cookie' ? 'include' : 'omit',\n body: JSON.stringify({\n sessionKind: sessionKind,\n vrf_data,\n webauthn_authentication,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n return {\n success: false,\n error: `HTTP ${response.status}: ${errorText}`,\n };\n }\n\n const result = await response.json();\n return {\n success: true,\n verified: result.verified,\n jwt: result.jwt,\n sessionCredential: result.sessionCredential,\n contractResponse: result.contractResponse,\n };\n } catch (error: any) {\n return {\n success: false,\n error: error.message || 'Failed to verify authentication response',\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rpcCalls.js","names":["error: any","ActionType","ActionPhase","DeviceLinkingPhase","DeviceLinkingStatus","addKeyTxResult: FinalExecutionOutcome","storeDeviceLinkingTxResult: FinalExecutionOutcome","DEFAULT_WAIT_STATUS","txError: any","base64UrlEncode","DEFAULT_EMAIL_RECOVERY_CONTRACTS","base64UrlDecode","err: unknown","errorMessage"],"sources":["../../../../../../src/core/rpcCalls.ts"],"sourcesContent":["/**\n * Consolidated NEAR Contract Calls\n *\n * This file contains all the NEAR contract calls made to the web3authn contract\n * throughout the passkey SDK. It provides a centralized location for all\n * contract interactions and makes it easier to maintain and update contract\n * call patterns.\n */\n\nimport type { FinalExecutionOutcome } from '@near-js/types';\nimport type { NearClient, SignedTransaction } from './NearClient';\nimport type { ContractStoredAuthenticator } from './TatchiPasskey/recoverAccount';\nimport type { PasskeyManagerContext } from './TatchiPasskey';\nimport type { AccountId } from './types/accountIds';\nimport type { DeviceLinkingSSEEvent } from './types/sdkSentEvents';\nimport type {\n StoredAuthenticator,\n WebAuthnRegistrationCredential,\n WebAuthnAuthenticationCredential\n} from './types/webauthn';\n\nimport { ActionPhase, DeviceLinkingPhase, DeviceLinkingStatus } from './types/sdkSentEvents';\nimport { ActionType, type ActionArgs } from './types/actions';\nimport { VRFChallenge } from './types/vrf-worker';\nimport { DEFAULT_WAIT_STATUS, TransactionContext } from './types/rpc';\nimport type { AuthenticatorOptions } from './types/authenticatorOptions';\nimport type { ConfirmationConfig } from './types/signer-worker';\nimport { base64UrlDecode, base64UrlEncode } from '../utils/encoders';\nimport { errorMessage } from '../utils/errors';\nimport type { EmailRecoveryContracts } from './types/tatchi';\nimport { DEFAULT_EMAIL_RECOVERY_CONTRACTS } from './defaultConfigs';\n\n// ===========================\n// CONTRACT CALL RESPONSES\n// ===========================\n\nexport interface DeviceLinkingResult {\n linkedAccountId: string;\n deviceNumber: number;\n}\n\nexport interface CredentialIdsResult {\n credentialIds: string[];\n}\n\nexport interface AuthenticatorsResult {\n authenticators: Array<[string, ContractStoredAuthenticator]>;\n}\n\nexport type EmailRecoveryVerificationResult = {\n verified: boolean;\n account_id?: string;\n new_public_key?: string;\n transaction_hash?: string;\n error_code?: string;\n error_message?: string;\n};\n\nexport async function getEmailRecoveryVerificationResult(\n nearClient: NearClient,\n dkimVerifierAccountId: string,\n verificationViewMethod: string,\n requestId: string\n): Promise<EmailRecoveryVerificationResult | null> {\n return await nearClient.view<{ request_id: string }, EmailRecoveryVerificationResult | null>({\n account: dkimVerifierAccountId,\n method: verificationViewMethod,\n args: { request_id: requestId },\n });\n}\n\n// ===========================\n// DEVICE LINKING CONTRACT CALLS\n// ===========================\n\n/**\n * Query the contract to get the account linked to a device public key\n * Used in device linking flow to check if a device key has been added\n *\n * NEAR does not provide a way to lookup the AccountID an access key has access to.\n * So we store a temporary mapping in the contract to lookup pubkey -> account ID.\n */\nexport async function getDeviceLinkingAccountContractCall(\n nearClient: NearClient,\n contractId: string,\n devicePublicKey: string\n): Promise<DeviceLinkingResult | null> {\n try {\n const result = await nearClient.callFunction<\n { device_public_key: string },\n [string, number | string]\n >(\n contractId,\n 'get_device_linking_account',\n { device_public_key: devicePublicKey }\n );\n\n // Handle different result formats\n if (result && Array.isArray(result) && result.length >= 2) {\n const [linkedAccountId, deviceNumberRaw] = result;\n const deviceNumber = Number(deviceNumberRaw);\n if (!Number.isSafeInteger(deviceNumber) || deviceNumber < 0) {\n console.warn(\n 'Invalid deviceNumber returned from get_device_linking_account:',\n deviceNumberRaw\n );\n return null;\n }\n return {\n linkedAccountId,\n deviceNumber\n };\n }\n\n return null;\n } catch (error: any) {\n console.warn('Failed to get device linking account:', error.message);\n return null;\n }\n}\n\n// ===========================\n// DEVICE LINKING TRANSACTION CALLS\n// ===========================\n\n/**\n * Execute device1's linking transactions (AddKey + Contract mapping)\n * This function signs and broadcasts both transactions required for device linking\n */\nexport async function executeDeviceLinkingContractCalls({\n context,\n device1AccountId,\n device2PublicKey,\n nextNonce,\n nextNextNonce,\n nextNextNextNonce,\n txBlockHash,\n vrfChallenge,\n onEvent,\n confirmationConfigOverride,\n confirmerText,\n}: {\n context: PasskeyManagerContext,\n device1AccountId: AccountId,\n device2PublicKey: string,\n nextNonce: string,\n nextNextNonce: string,\n nextNextNextNonce: string,\n txBlockHash: string,\n vrfChallenge: VRFChallenge,\n onEvent?: (event: DeviceLinkingSSEEvent) => void;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n confirmerText?: { title?: string; body?: string };\n}): Promise<{\n addKeyTxResult: FinalExecutionOutcome;\n storeDeviceLinkingTxResult: FinalExecutionOutcome;\n signedDeleteKeyTransaction: SignedTransaction\n}> {\n\n // Sign three transactions with one PRF authentication\n const signedTransactions = await context.webAuthnManager.signTransactionsWithActions({\n rpcCall: {\n contractId: context.webAuthnManager.tatchiPasskeyConfigs.contractId,\n nearRpcUrl: context.webAuthnManager.tatchiPasskeyConfigs.nearRpcUrl,\n nearAccountId: device1AccountId\n },\n confirmationConfigOverride,\n title: confirmerText?.title,\n body: confirmerText?.body,\n transactions: [\n // Transaction 1: AddKey - Add Device2's key to Device1's account\n {\n receiverId: device1AccountId,\n actions: [{\n action_type: ActionType.AddKey,\n public_key: device2PublicKey,\n access_key: JSON.stringify({\n // NEAR-style AccessKey JSON shape, matching near-api-js:\n // { nonce: number, permission: { FullAccess: {} } }\n nonce: 0,\n permission: { FullAccess: {} },\n }),\n }],\n nonce: nextNonce,\n },\n // Transaction 2: Store temporary mapping in contract so Device2 can lookup Device1's accountID.\n {\n receiverId: context.webAuthnManager.tatchiPasskeyConfigs.contractId,\n actions: [{\n action_type: ActionType.FunctionCall,\n method_name: 'store_device_linking_mapping',\n args: JSON.stringify({\n device_public_key: device2PublicKey,\n target_account_id: device1AccountId,\n }),\n gas: '30000000000000', // 30 TGas for device linking with yield promise automatic cleanup\n deposit: '0'\n }],\n nonce: nextNextNonce,\n },\n // Transaction 3: Remove Device2's temporary key if it fails to complete linking after a timeout\n {\n receiverId: device1AccountId,\n actions: [{\n action_type: ActionType.DeleteKey,\n public_key: device2PublicKey\n }],\n nonce: nextNextNextNonce,\n }\n ],\n onEvent: (progress) => {\n // Bridge all action progress events to the parent so the wallet iframe overlay\n // can expand during user confirmation in wallet-iframe mode.\n try { onEvent?.(progress as any); } catch { }\n // Keep existing mapping for device linking semantics; surface signing as a loading state\n if (progress.phase == ActionPhase.STEP_6_TRANSACTION_SIGNING_COMPLETE) {\n onEvent?.({\n step: 3,\n phase: DeviceLinkingPhase.STEP_3_AUTHORIZATION,\n status: DeviceLinkingStatus.PROGRESS,\n message: progress.message || 'Transaction signing in progress...'\n })\n }\n }\n });\n\n if (!signedTransactions[0].signedTransaction) {\n throw new Error('AddKey transaction signing failed');\n }\n if (!signedTransactions[1].signedTransaction) {\n throw new Error('Contract mapping transaction signing failed');\n }\n if (!signedTransactions[2].signedTransaction) {\n throw new Error('DeleteKey transaction signing failed');\n }\n\n // Broadcast just the first 2 transactions: addKey and store device linking mapping\n let addKeyTxResult: FinalExecutionOutcome;\n let storeDeviceLinkingTxResult: FinalExecutionOutcome;\n try {\n console.debug('LinkDeviceFlow: AddKey transaction details:', {\n receiverId: signedTransactions[0].signedTransaction.transaction.receiverId,\n actions: signedTransactions[0].signedTransaction.transaction.actions || [],\n transactionKeys: Object.keys(signedTransactions[0].signedTransaction.transaction),\n });\n\n addKeyTxResult = await context.nearClient.sendTransaction(\n signedTransactions[0].signedTransaction,\n DEFAULT_WAIT_STATUS.linkDeviceAddKey\n );\n console.log('LinkDeviceFlow: AddKey transaction result:', addKeyTxResult?.transaction?.hash);\n\n // Send success events immediately after AddKey succeeds\n onEvent?.({\n step: 3,\n phase: DeviceLinkingPhase.STEP_3_AUTHORIZATION,\n status: DeviceLinkingStatus.SUCCESS,\n message: `AddKey transaction completed successfully!`\n });\n\n // Check if contract mapping transaction is valid before attempting to broadcast\n const contractTx = signedTransactions[1].signedTransaction;\n console.log('LinkDeviceFlow: Contract mapping transaction details:', {\n receiverId: contractTx.transaction.receiverId,\n actions: (contractTx.transaction.actions || []).length\n });\n\n // Standard timeout since nonce conflict should be resolved by the 2s delay\n storeDeviceLinkingTxResult = await context.nearClient.sendTransaction(\n contractTx,\n DEFAULT_WAIT_STATUS.linkDeviceAccountMapping\n );\n\n } catch (txError: any) {\n console.error('LinkDeviceFlow: Transaction broadcasting failed:', txError);\n throw new Error(`Transaction broadcasting failed: ${txError.message}`);\n }\n\n onEvent?.({\n step: 6,\n phase: DeviceLinkingPhase.STEP_6_REGISTRATION,\n status: DeviceLinkingStatus.SUCCESS,\n message: `Device linking completed successfully!`\n });\n\n return {\n addKeyTxResult,\n storeDeviceLinkingTxResult,\n signedDeleteKeyTransaction: signedTransactions[2].signedTransaction\n };\n}\n\n// ===========================\n// ACCOUNT RECOVERY CONTRACT CALLS\n// ===========================\n\n/**\n * Get credential IDs associated with an account from the contract\n * Used in account recovery to discover available credentials\n */\nexport async function getCredentialIdsContractCall(\n nearClient: NearClient,\n contractId: string,\n accountId: AccountId\n): Promise<string[]> {\n try {\n const credentialIds = await nearClient.callFunction<{ account_id: AccountId }, string[]>(\n contractId,\n 'get_credential_ids_by_account',\n { account_id: accountId }\n );\n return credentialIds || [];\n } catch (error: any) {\n console.warn('Failed to fetch credential IDs from contract:', error.message);\n return [];\n }\n}\n\n/**\n * Get all authenticators stored for a user from the contract\n * Used in account recovery to sync authenticator data\n */\nexport async function getAuthenticatorsByUser(\n nearClient: NearClient,\n contractId: string,\n accountId: AccountId\n): Promise<[string, ContractStoredAuthenticator][]> {\n try {\n const authenticatorsResult = await nearClient.view<{ user_id: AccountId }, [string, ContractStoredAuthenticator][]>({\n account: contractId,\n method: 'get_authenticators_by_user',\n args: { user_id: accountId }\n });\n\n if (authenticatorsResult && Array.isArray(authenticatorsResult)) {\n return authenticatorsResult;\n }\n return [];\n } catch (error: any) {\n console.warn('Failed to fetch authenticators from contract:', error.message);\n return [];\n }\n}\n\nexport async function syncAuthenticatorsContractCall(\n nearClient: NearClient,\n contractId: string,\n accountId: AccountId\n): Promise<Array<{ credentialId: string, authenticator: StoredAuthenticator }>> {\n try {\n const authenticatorsResult = await getAuthenticatorsByUser(nearClient, contractId, accountId);\n if (authenticatorsResult && Array.isArray(authenticatorsResult)) {\n return authenticatorsResult.map(([credentialId, contractAuthenticator]) => {\n console.log(`Contract authenticator device_number for ${credentialId}:`, contractAuthenticator.device_number);\n\n const transports = Array.isArray(contractAuthenticator.transports)\n ? contractAuthenticator.transports\n : [];\n\n const registered = (() => {\n const raw = String((contractAuthenticator as any).registered ?? '');\n if (!raw) return new Date(0);\n if (/^\\d+$/.test(raw)) {\n const ts = Number(raw);\n return Number.isFinite(ts) ? new Date(ts) : new Date(0);\n }\n const d = new Date(raw);\n return Number.isFinite(d.getTime()) ? d : new Date(0);\n })();\n\n const vrfPublicKeys = (() => {\n const raw = (contractAuthenticator as any).vrf_public_keys;\n if (!raw) return undefined;\n if (Array.isArray(raw) && raw.length > 0 && typeof raw[0] === 'string') {\n return raw as string[];\n }\n if (Array.isArray(raw)) {\n return raw\n .map((entry: unknown) => {\n if (!entry) return null;\n if (entry instanceof Uint8Array) return base64UrlEncode(entry);\n if (Array.isArray(entry)) return base64UrlEncode(new Uint8Array(entry));\n return null;\n })\n .filter((x): x is string => typeof x === 'string' && x.length > 0);\n }\n return undefined;\n })();\n\n return {\n credentialId,\n authenticator: {\n credentialId,\n credentialPublicKey: new Uint8Array(contractAuthenticator.credential_public_key),\n transports,\n userId: accountId,\n name: `Device ${contractAuthenticator.device_number} Authenticator`,\n registered,\n // Store the actual device number from contract (no fallback)\n deviceNumber: contractAuthenticator.device_number,\n vrfPublicKeys\n }\n };\n });\n }\n return [];\n } catch (error: any) {\n console.warn('Failed to fetch authenticators from contract:', error.message);\n return [];\n }\n}\n\n// ===========================\n// RECOVERY EMAIL CONTRACT CALLS\n// ===========================\n\n/**\n * Fetch on-chain recovery email hashes from the per-account contract.\n * Returns [] when no contract is deployed or on failure.\n */\nexport async function getRecoveryEmailHashesContractCall(\n nearClient: NearClient,\n accountId: AccountId\n): Promise<number[][]> {\n try {\n const code = await nearClient.viewCode(accountId);\n const hasContract = !!code && code.byteLength > 0;\n if (!hasContract) return [];\n\n const hashes = await nearClient.view<Record<string, never>, number[][]>({\n account: accountId,\n method: 'get_recovery_emails',\n args: {} as Record<string, never>,\n });\n\n return Array.isArray(hashes) ? (hashes as number[][]) : [];\n } catch (error) {\n console.error('[rpcCalls] Failed to fetch recovery email hashes', error);\n return [];\n }\n}\n\n/**\n * Build action args to update on-chain recovery emails for an account.\n * If the per-account contract is missing, deploy/attach the global recoverer via `init_email_recovery`.\n */\nexport async function buildSetRecoveryEmailsActions(\n nearClient: NearClient,\n accountId: AccountId,\n recoveryEmailHashes: number[][],\n contracts: EmailRecoveryContracts = DEFAULT_EMAIL_RECOVERY_CONTRACTS\n): Promise<ActionArgs[]> {\n let hasContract = false;\n try {\n const code = await nearClient.viewCode(accountId);\n hasContract = !!code && code.byteLength > 0;\n } catch {\n hasContract = false;\n }\n\n const {\n emailRecovererGlobalContract,\n zkEmailVerifierContract,\n emailDkimVerifierContract,\n } = contracts;\n\n return hasContract\n ? [\n {\n type: ActionType.UseGlobalContract,\n accountId: emailRecovererGlobalContract,\n },\n {\n type: ActionType.FunctionCall,\n methodName: 'set_recovery_emails',\n args: {\n recovery_emails: recoveryEmailHashes,\n },\n gas: '80000000000000',\n deposit: '0',\n },\n ]\n : [\n {\n type: ActionType.UseGlobalContract,\n accountId: emailRecovererGlobalContract,\n },\n {\n type: ActionType.FunctionCall,\n methodName: 'init_email_recovery',\n args: {\n zk_email_verifier: zkEmailVerifierContract,\n email_dkim_verifier: emailDkimVerifierContract,\n policy: null,\n recovery_emails: recoveryEmailHashes,\n },\n gas: '80000000000000',\n deposit: '0',\n },\n ];\n}\n\nexport async function fetchNonceBlockHashAndHeight({ nearClient, nearPublicKeyStr, nearAccountId }: {\n nearClient: NearClient,\n nearPublicKeyStr: string,\n nearAccountId: AccountId\n}): Promise<TransactionContext> {\n // Get access key and transaction block info concurrently\n const [accessKeyInfo, txBlockInfo] = await Promise.all([\n nearClient.viewAccessKey(nearAccountId, nearPublicKeyStr)\n .catch(e => { throw new Error(`Failed to fetch Access Key`) }),\n nearClient.viewBlock({ finality: 'final' })\n .catch(e => { throw new Error(`Failed to fetch Block Info`) })\n ]);\n if (!accessKeyInfo || accessKeyInfo.nonce === undefined) {\n throw new Error(`Access key not found or invalid for account ${nearAccountId} with public key ${nearPublicKeyStr}. Response: ${JSON.stringify(accessKeyInfo)}`);\n }\n const nextNonce = (BigInt(accessKeyInfo.nonce) + BigInt(1)).toString();\n const txBlockHeight = String(txBlockInfo.header.height);\n const txBlockHash = txBlockInfo.header.hash; // Keep original base58 string\n\n return {\n nearPublicKeyStr,\n accessKeyInfo,\n nextNonce,\n txBlockHeight,\n txBlockHash,\n };\n}\n\n// ===========================\n// REGISTRATION PRE-CHECK CALL\n// ===========================\n\nexport interface CheckCanRegisterUserResult {\n success: boolean;\n verified: boolean;\n logs: string[];\n error?: string;\n}\n\n/**\n * View-only registration pre-check.\n *\n * Calls the contract's `check_can_register_user` view method with VRF data\n * derived from the provided VRF challenge and a serialized WebAuthn\n * registration credential (typically with PRF outputs embedded).\n */\nexport async function checkCanRegisterUserContractCall({\n nearClient,\n contractId,\n vrfChallenge,\n credential,\n authenticatorOptions,\n}: {\n nearClient: NearClient;\n contractId: string;\n vrfChallenge: VRFChallenge;\n credential: WebAuthnRegistrationCredential;\n authenticatorOptions?: AuthenticatorOptions;\n}): Promise<CheckCanRegisterUserResult> {\n try {\n const vrfData = {\n vrf_input_data: Array.from(base64UrlDecode(vrfChallenge.vrfInput)),\n vrf_output: Array.from(base64UrlDecode(vrfChallenge.vrfOutput)),\n vrf_proof: Array.from(base64UrlDecode(vrfChallenge.vrfProof)),\n public_key: Array.from(base64UrlDecode(vrfChallenge.vrfPublicKey)),\n user_id: vrfChallenge.userId,\n rp_id: vrfChallenge.rpId,\n block_height: Number(vrfChallenge.blockHeight),\n block_hash: Array.from(base64UrlDecode(vrfChallenge.blockHash)),\n };\n\n const args = {\n vrf_data: vrfData,\n webauthn_registration: credential,\n authenticator_options: authenticatorOptions,\n };\n\n const response = await nearClient.callFunction<typeof args, any>(\n contractId,\n 'check_can_register_user',\n args,\n );\n\n const verified = !!response?.verified;\n return {\n success: true,\n verified,\n logs: [],\n error: verified ? undefined : 'Contract registration check failed',\n };\n } catch (err: unknown) {\n return {\n success: false,\n verified: false,\n logs: [],\n error: errorMessage(err) || 'Failed to call check_can_register_user',\n };\n }\n}\n\n\n/**\n * Verify authentication response through relay server\n * Routes the request to relay server which calls the web3authn contract for verification\n * and issues a JWT or session credential\n */\nexport async function verifyAuthenticationResponse(\n relayServerUrl: string,\n routePath: string,\n sessionKind: 'jwt' | 'cookie',\n vrfChallenge: VRFChallenge,\n webauthnAuthentication: WebAuthnAuthenticationCredential\n): Promise<{\n success: boolean;\n verified?: boolean;\n jwt?: string;\n sessionCredential?: any;\n error?: string;\n contractResponse?: any;\n}> {\n try {\n // Map VRFChallenge into server ContractVrfData shape (number arrays)\n const toBytes = (b64u: string | undefined): number[] => {\n if (!b64u) return [];\n return Array.from(base64UrlDecode(b64u));\n };\n const vrf_data = {\n vrf_input_data: toBytes(vrfChallenge.vrfInput),\n vrf_output: toBytes(vrfChallenge.vrfOutput),\n vrf_proof: toBytes(vrfChallenge.vrfProof),\n public_key: toBytes(vrfChallenge.vrfPublicKey),\n user_id: vrfChallenge.userId,\n rp_id: vrfChallenge.rpId,\n block_height: Number(vrfChallenge.blockHeight || 0),\n block_hash: toBytes(vrfChallenge.blockHash),\n };\n\n // Normalize authenticatorAttachment and userHandle to null for server schema\n const webauthn_authentication = {\n ...webauthnAuthentication,\n authenticatorAttachment: webauthnAuthentication.authenticatorAttachment ?? null,\n response: {\n ...webauthnAuthentication.response,\n userHandle: webauthnAuthentication.response.userHandle ?? null,\n }\n };\n\n const url = `${relayServerUrl.replace(/\\/$/, '')}${routePath.startsWith('/') ? routePath : `/${routePath}`}`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n credentials: sessionKind === 'cookie' ? 'include' : 'omit',\n body: JSON.stringify({\n sessionKind: sessionKind,\n vrf_data,\n webauthn_authentication,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n return {\n success: false,\n error: `HTTP ${response.status}: ${errorText}`,\n };\n }\n\n const result = await response.json();\n return {\n success: true,\n verified: result.verified,\n jwt: result.jwt,\n sessionCredential: result.sessionCredential,\n contractResponse: result.contractResponse,\n };\n } catch (error: any) {\n return {\n success: false,\n error: error.message || 'Failed to verify authentication response',\n };\n }\n}\n"],"mappings":"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"}
@@ -3,7 +3,6 @@ const require_base64 = require('../../utils/base64.js');
3
3
  const require_encoders = require('../../utils/encoders.js');
4
4
 
5
5
  //#region src/core/types/vrf-worker.ts
6
- require_encoders.init_encoders();
7
6
  /**
8
7
  * Decode VRF output and use first 32 bytes as WebAuthn challenge
9
8
  * @param vrfChallenge - VRF challenge object
@@ -57,9 +56,19 @@ function createRandomVRFChallenge() {
57
56
  blockHash: void 0
58
57
  };
59
58
  }
59
+ var init_vrf_worker = require_rolldown_runtime.__esm({ "src/core/types/vrf-worker.ts": (() => {
60
+ require_encoders.init_encoders();
61
+ }) });
60
62
 
61
63
  //#endregion
64
+ init_vrf_worker();
62
65
  exports.createRandomVRFChallenge = createRandomVRFChallenge;
66
+ Object.defineProperty(exports, 'init_vrf_worker', {
67
+ enumerable: true,
68
+ get: function () {
69
+ return init_vrf_worker;
70
+ }
71
+ });
63
72
  exports.outputAs32Bytes = outputAs32Bytes;
64
73
  exports.validateVRFChallenge = validateVRFChallenge;
65
74
  //# sourceMappingURL=vrf-worker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"vrf-worker.js","names":["base64UrlDecode","base64UrlEncode"],"sources":["../../../../../../../src/core/types/vrf-worker.ts"],"sourcesContent":["/**\n * VRF Types for Web Worker Communication\n */\nimport * as wasmModule from '../../wasm_vrf_worker/pkg/wasm_vrf_worker.js';\nimport { StripFree } from \"./index.js\";\n\nimport { WebAuthnAuthenticationCredential, WebAuthnRegistrationCredential } from \"./webauthn\";\nimport { ConfirmationConfig } from './signer-worker';\nimport { AccountId } from \"./accountIds.js\";\nimport { base64UrlDecode, base64UrlEncode } from \"../../utils/encoders.js\";\nimport type { SecureConfirmRequest } from \"../WebAuthnManager/VrfWorkerManager/confirmTxFlow/types\";\n\nexport type WasmGenerateVrfKeypairBootstrapRequest = StripFree<wasmModule.GenerateVrfKeypairBootstrapRequest>;\nexport type WasmGenerateVrfChallengeRequest = StripFree<wasmModule.GenerateVrfChallengeRequest>;\nexport type WasmUnlockVrfKeypairRequest = Omit<StripFree<wasmModule.UnlockVrfKeypairRequest>, 'prfKey'> & {\n // Prefer forwarding the full serialized WebAuthn credential so PRF outputs do not need\n // to be extracted into separate main-thread strings.\n credential: WebAuthnAuthenticationCredential;\n};\nexport type WasmDeriveVrfKeypairFromPrfRequest = Omit<\n StripFree<wasmModule.DeriveVrfKeypairFromPrfRequest>,\n 'credential' | 'prfOutput'\n> & {\n // Forward the WebAuthn credential so PRF outputs do not need to be extracted in main-thread JS.\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n};\nexport type WasmMintSessionKeysAndSendToSignerRequest =\n Omit<\n StripFree<wasmModule.MintSessionKeysAndSendToSignerRequest>,\n 'contractId' | 'nearRpcUrl' | 'ttlMs' | 'remainingUses'\n > & {\n contractId?: string;\n nearRpcUrl?: string;\n // Optional signing-session config. When omitted, VRF worker uses defaults.\n ttlMs?: number;\n remainingUses?: number;\n // Forward the WebAuthn credential so PRF outputs do not need to be extracted in main-thread JS.\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n };\nexport type WasmDispenseSessionKeyRequest = StripFree<wasmModule.DispenseSessionKeyRequest>;\nexport type WasmCheckSessionStatusRequest = StripFree<wasmModule.CheckSessionStatusRequest>;\nexport type WasmClearSessionRequest = StripFree<wasmModule.ClearSessionRequest>;\nexport type WasmConfirmAndPrepareSigningSessionRequest = {\n request: SecureConfirmRequest;\n};\nexport type WasmDecryptSessionRequest = StripFree<wasmModule.DecryptSessionRequest>;\nexport type WasmRegistrationCredentialConfirmationRequest = StripFree<wasmModule.RegistrationCredentialConfirmationRequest> & {\n confirmationConfig?: ConfirmationConfig;\n};\nexport type WasmDevice2RegistrationSessionRequest = StripFree<wasmModule.Device2RegistrationSessionRequest> & {\n confirmationConfig?: ConfirmationConfig;\n};\n\nexport type WasmShamir3PassConfigPRequest = StripFree<wasmModule.Shamir3PassConfigPRequest>;\nexport type WasmShamir3PassConfigServerUrlsRequest = StripFree<wasmModule.Shamir3PassConfigServerUrlsRequest>;\nexport type WasmShamir3PassClientEncryptCurrentVrfKeypairRequest = StripFree<wasmModule.Shamir3PassClientEncryptCurrentVrfKeypairRequest>;\nexport type WasmShamir3PassClientDecryptVrfKeypairRequest = StripFree<wasmModule.Shamir3PassClientDecryptVrfKeypairRequest>;\n\nexport type WasmVrfWorkerRequestType = WasmGenerateVrfKeypairBootstrapRequest\n | WasmGenerateVrfChallengeRequest\n | WasmUnlockVrfKeypairRequest\n | WasmDeriveVrfKeypairFromPrfRequest\n | WasmMintSessionKeysAndSendToSignerRequest\n | WasmDispenseSessionKeyRequest\n | WasmCheckSessionStatusRequest\n | WasmClearSessionRequest\n | WasmConfirmAndPrepareSigningSessionRequest\n | WasmDecryptSessionRequest\n | WasmRegistrationCredentialConfirmationRequest\n | WasmDevice2RegistrationSessionRequest\n | WasmShamir3PassConfigPRequest\n | WasmShamir3PassConfigServerUrlsRequest\n | WasmShamir3PassClientEncryptCurrentVrfKeypairRequest\n | WasmShamir3PassClientDecryptVrfKeypairRequest;\n\nexport interface VRFChallenge {\n vrfInput: string;\n vrfOutput: string;\n vrfProof: string;\n vrfPublicKey: string;\n userId: string;\n rpId: string;\n blockHeight: string;\n blockHash: string;\n}\n\n/**\n * Decode VRF output and use first 32 bytes as WebAuthn challenge\n * @param vrfChallenge - VRF challenge object\n * @returns 32-byte Uint8Array\n */\nexport function outputAs32Bytes(vrfChallenge: VRFChallenge): Uint8Array {\n let vrfOutputBytes = base64UrlDecode(vrfChallenge.vrfOutput);\n return vrfOutputBytes.slice(0, 32);\n}\n\n/**\n * Validate and create a VRFChallenge object\n * @param vrfChallengeData - The challenge data to validate\n * @returns VRFChallenge object\n */\nexport function validateVRFChallenge(vrfChallengeData: {\n vrfInput: string;\n vrfOutput: string;\n vrfProof: string;\n vrfPublicKey: string;\n userId: string;\n rpId: string;\n blockHeight: string;\n blockHash: string;\n}): VRFChallenge {\n if (!vrfChallengeData.vrfInput || typeof vrfChallengeData.vrfInput !== 'string') {\n throw new Error('vrfInput must be a non-empty string');\n }\n if (!vrfChallengeData.vrfOutput || typeof vrfChallengeData.vrfOutput !== 'string') {\n throw new Error('vrfOutput must be a non-empty string');\n }\n if (!vrfChallengeData.vrfProof || typeof vrfChallengeData.vrfProof !== 'string') {\n throw new Error('vrfProof must be a non-empty string');\n }\n if (!vrfChallengeData.vrfPublicKey || typeof vrfChallengeData.vrfPublicKey !== 'string') {\n throw new Error('vrfPublicKey must be a non-empty string');\n }\n if (!vrfChallengeData.userId || typeof vrfChallengeData.userId !== 'string') {\n throw new Error('userId must be a non-empty string');\n }\n if (!vrfChallengeData.rpId || typeof vrfChallengeData.rpId !== 'string') {\n throw new Error('rpId must be a non-empty string');\n }\n if (!vrfChallengeData.blockHeight || typeof vrfChallengeData.blockHeight !== 'string') {\n throw new Error('blockHeight must be a non-empty string');\n }\n if (!vrfChallengeData.blockHash || typeof vrfChallengeData.blockHash !== 'string') {\n throw new Error('blockHash must be a non-empty string');\n }\n\n return {\n vrfInput: vrfChallengeData.vrfInput,\n vrfOutput: vrfChallengeData.vrfOutput,\n vrfProof: vrfChallengeData.vrfProof,\n vrfPublicKey: vrfChallengeData.vrfPublicKey,\n userId: vrfChallengeData.userId,\n rpId: vrfChallengeData.rpId,\n blockHeight: vrfChallengeData.blockHeight,\n blockHash: vrfChallengeData.blockHash,\n };\n}\n\n/**\n * Create a random VRF challenge\n * @returns Partial<VRFChallenge> with vrfOutput set, but other fields are undefined\n * This is used for local operations that don't require a VRF verification\n */\nexport function createRandomVRFChallenge(): Partial<VRFChallenge> {\n const challenge = crypto.getRandomValues(new Uint8Array(32));\n const vrfOutput = base64UrlEncode(challenge.buffer);\n return {\n vrfOutput: vrfOutput,\n vrfInput: undefined,\n vrfProof: undefined,\n vrfPublicKey: undefined,\n userId: undefined,\n rpId: undefined,\n blockHeight: undefined,\n blockHash: undefined,\n };\n}\n\nexport interface VrfWorkerManagerConfig {\n vrfWorkerUrl?: string;\n workerTimeout?: number;\n debug?: boolean;\n // Optional Shamir 3-pass configuration passed to the VRF WASM worker at init\n shamirPB64u?: string; // base64url prime p\n relayServerUrl?: string;\n applyServerLockRoute?: string;\n removeServerLockRoute?: string;\n}\n\n// Define interfaces that are missing\nexport interface VRFWorkerStatus {\n active: boolean;\n nearAccountId: AccountId | null;\n sessionDuration?: number;\n}\n\nexport interface EncryptedVRFKeypair {\n encryptedVrfDataB64u: string;\n chacha20NonceB64u: string;\n}\n\nexport interface VRFInputData {\n userId: string;\n rpId: string;\n blockHeight: string;\n blockHash: string;\n}\n\nexport interface VRFWorkerMessage<T extends WasmVrfWorkerRequestType> {\n // type: wasmModule.WorkerRequestType\n type: 'PING'\n | 'GENERATE_VRF_CHALLENGE'\n | 'GENERATE_VRF_KEYPAIR_BOOTSTRAP'\n | 'UNLOCK_VRF_KEYPAIR'\n | 'CHECK_VRF_STATUS'\n | 'CLEAR_VRF'\n | 'DERIVE_VRF_KEYPAIR_FROM_PRF'\n | 'MINT_SESSION_KEYS_AND_SEND_TO_SIGNER'\n | 'DISPENSE_SESSION_KEY'\n | 'CHECK_SESSION_STATUS'\n | 'CLEAR_SESSION'\n | 'CONFIRM_AND_PREPARE_SIGNING_SESSION'\n | 'DECRYPT_SESSION'\n | 'REGISTRATION_CREDENTIAL_CONFIRMATION'\n | 'DEVICE2_REGISTRATION_SESSION'\n | 'SHAMIR3PASS_CLIENT_ENCRYPT_CURRENT_VRF_KEYPAIR' // client only\n | 'SHAMIR3PASS_CLIENT_DECRYPT_VRF_KEYPAIR' // client only\n | 'SHAMIR3PASS_APPLY_SERVER_LOCK_KEK' // server only\n | 'SHAMIR3PASS_REMOVE_SERVER_LOCK_KEK' // server only\n | 'SHAMIR3PASS_CONFIG_P'\n | 'SHAMIR3PASS_CONFIG_SERVER_URLS'\n id?: string;\n payload?: T;\n}\n\nexport interface VRFWorkerResponse<TData = Record<string, unknown>> {\n id?: string;\n success: boolean;\n data?: TData;\n error?: string;\n}\n\nexport interface VRFKeypairBootstrapResponse {\n vrfPublicKey: string;\n vrfChallengeData?: VRFChallenge;\n}\n\nexport interface EncryptedVRFKeypairResponse {\n vrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n}\n\n/**\n * Server-encrypted VRF keypair for commutative encryption scheme\n * This allows server-assisted VRF key recovery without the server seeing the plaintext\n */\nexport interface ServerEncryptedVrfKeypair {\n /** Base64url-encoded VRF ciphertext (AEAD over VRF keypair bytes) */\n ciphertextVrfB64u: string;\n /** Base64url-encoded KEK with server lock applied (KEK_s) */\n kek_s_b64u: string;\n /** Server key identifier for proactive refresh/versioning */\n serverKeyId: string;\n}\n\n/**\n * Plaintext VRF keypair data structure\n * Used for loading decrypted VRF keypairs directly into memory\n */\nexport interface VRFKeypairData {\n /** Bincode-serialized ECVRFKeyPair bytes (includes both private and public key) */\n keypairBytes: number[];\n /** Base64url-encoded public key for convenience and verification */\n publicKeyBase64: string;\n}\n\n// Shamir 3-pass registration wrap result\nexport interface Shamir3PassRegisterWrapResult {\n ciphertextVrfB64u: string;\n enc_s_k_b64u: string;\n vrfPublicKey: string;\n}\n"],"mappings":";;;;;;;;;;;AA2FA,SAAgB,gBAAgB,cAAwC;CACtE,IAAI,iBAAiBA,+BAAgB,aAAa;AAClD,QAAO,eAAe,MAAM,GAAG;;;;;;;AAQjC,SAAgB,qBAAqB,kBASpB;AACf,KAAI,CAAC,iBAAiB,YAAY,OAAO,iBAAiB,aAAa,SACrE,OAAM,IAAI,MAAM;AAElB,KAAI,CAAC,iBAAiB,aAAa,OAAO,iBAAiB,cAAc,SACvE,OAAM,IAAI,MAAM;AAElB,KAAI,CAAC,iBAAiB,YAAY,OAAO,iBAAiB,aAAa,SACrE,OAAM,IAAI,MAAM;AAElB,KAAI,CAAC,iBAAiB,gBAAgB,OAAO,iBAAiB,iBAAiB,SAC7E,OAAM,IAAI,MAAM;AAElB,KAAI,CAAC,iBAAiB,UAAU,OAAO,iBAAiB,WAAW,SACjE,OAAM,IAAI,MAAM;AAElB,KAAI,CAAC,iBAAiB,QAAQ,OAAO,iBAAiB,SAAS,SAC7D,OAAM,IAAI,MAAM;AAElB,KAAI,CAAC,iBAAiB,eAAe,OAAO,iBAAiB,gBAAgB,SAC3E,OAAM,IAAI,MAAM;AAElB,KAAI,CAAC,iBAAiB,aAAa,OAAO,iBAAiB,cAAc,SACvE,OAAM,IAAI,MAAM;AAGlB,QAAO;EACL,UAAU,iBAAiB;EAC3B,WAAW,iBAAiB;EAC5B,UAAU,iBAAiB;EAC3B,cAAc,iBAAiB;EAC/B,QAAQ,iBAAiB;EACzB,MAAM,iBAAiB;EACvB,aAAa,iBAAiB;EAC9B,WAAW,iBAAiB;;;;;;;;AAShC,SAAgB,2BAAkD;CAChE,MAAM,YAAY,OAAO,gBAAgB,IAAI,WAAW;CACxD,MAAM,YAAYC,+BAAgB,UAAU;AAC5C,QAAO;EACM;EACX,UAAU;EACV,UAAU;EACV,cAAc;EACd,QAAQ;EACR,MAAM;EACN,aAAa;EACb,WAAW"}
1
+ {"version":3,"file":"vrf-worker.js","names":["base64UrlDecode","base64UrlEncode"],"sources":["../../../../../../../src/core/types/vrf-worker.ts"],"sourcesContent":["/**\n * VRF Types for Web Worker Communication\n */\nimport * as wasmModule from '../../wasm_vrf_worker/pkg/wasm_vrf_worker.js';\nimport { StripFree } from \"./index.js\";\n\nimport { WebAuthnAuthenticationCredential, WebAuthnRegistrationCredential } from \"./webauthn\";\nimport { ConfirmationConfig } from './signer-worker';\nimport { AccountId } from \"./accountIds.js\";\nimport { base64UrlDecode, base64UrlEncode } from \"../../utils/encoders.js\";\nimport type { SecureConfirmRequest } from \"../WebAuthnManager/VrfWorkerManager/confirmTxFlow/types\";\n\nexport type WasmGenerateVrfKeypairBootstrapRequest = StripFree<wasmModule.GenerateVrfKeypairBootstrapRequest>;\nexport type WasmGenerateVrfChallengeRequest = StripFree<wasmModule.GenerateVrfChallengeRequest>;\nexport type WasmUnlockVrfKeypairRequest = Omit<StripFree<wasmModule.UnlockVrfKeypairRequest>, 'prfKey'> & {\n // Prefer forwarding the full serialized WebAuthn credential so PRF outputs do not need\n // to be extracted into separate main-thread strings.\n credential: WebAuthnAuthenticationCredential;\n};\nexport type WasmDeriveVrfKeypairFromPrfRequest = Omit<\n StripFree<wasmModule.DeriveVrfKeypairFromPrfRequest>,\n 'credential' | 'prfOutput'\n> & {\n // Forward the WebAuthn credential so PRF outputs do not need to be extracted in main-thread JS.\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n};\nexport type WasmMintSessionKeysAndSendToSignerRequest =\n Omit<\n StripFree<wasmModule.MintSessionKeysAndSendToSignerRequest>,\n 'contractId' | 'nearRpcUrl' | 'ttlMs' | 'remainingUses'\n > & {\n contractId?: string;\n nearRpcUrl?: string;\n // Optional signing-session config. When omitted, VRF worker uses defaults.\n ttlMs?: number;\n remainingUses?: number;\n // Forward the WebAuthn credential so PRF outputs do not need to be extracted in main-thread JS.\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n };\nexport type WasmDispenseSessionKeyRequest = StripFree<wasmModule.DispenseSessionKeyRequest>;\nexport type WasmCheckSessionStatusRequest = StripFree<wasmModule.CheckSessionStatusRequest>;\nexport type WasmClearSessionRequest = StripFree<wasmModule.ClearSessionRequest>;\nexport type WasmConfirmAndPrepareSigningSessionRequest = {\n request: SecureConfirmRequest;\n};\nexport type WasmDecryptSessionRequest = StripFree<wasmModule.DecryptSessionRequest>;\nexport type WasmRegistrationCredentialConfirmationRequest = StripFree<wasmModule.RegistrationCredentialConfirmationRequest> & {\n confirmationConfig?: ConfirmationConfig;\n};\nexport type WasmDevice2RegistrationSessionRequest = StripFree<wasmModule.Device2RegistrationSessionRequest> & {\n confirmationConfig?: ConfirmationConfig;\n};\n\nexport type WasmShamir3PassConfigPRequest = StripFree<wasmModule.Shamir3PassConfigPRequest>;\nexport type WasmShamir3PassConfigServerUrlsRequest = StripFree<wasmModule.Shamir3PassConfigServerUrlsRequest>;\nexport type WasmShamir3PassClientEncryptCurrentVrfKeypairRequest = StripFree<wasmModule.Shamir3PassClientEncryptCurrentVrfKeypairRequest>;\nexport type WasmShamir3PassClientDecryptVrfKeypairRequest = StripFree<wasmModule.Shamir3PassClientDecryptVrfKeypairRequest>;\n\nexport type WasmVrfWorkerRequestType = WasmGenerateVrfKeypairBootstrapRequest\n | WasmGenerateVrfChallengeRequest\n | WasmUnlockVrfKeypairRequest\n | WasmDeriveVrfKeypairFromPrfRequest\n | WasmMintSessionKeysAndSendToSignerRequest\n | WasmDispenseSessionKeyRequest\n | WasmCheckSessionStatusRequest\n | WasmClearSessionRequest\n | WasmConfirmAndPrepareSigningSessionRequest\n | WasmDecryptSessionRequest\n | WasmRegistrationCredentialConfirmationRequest\n | WasmDevice2RegistrationSessionRequest\n | WasmShamir3PassConfigPRequest\n | WasmShamir3PassConfigServerUrlsRequest\n | WasmShamir3PassClientEncryptCurrentVrfKeypairRequest\n | WasmShamir3PassClientDecryptVrfKeypairRequest;\n\nexport interface VRFChallenge {\n vrfInput: string;\n vrfOutput: string;\n vrfProof: string;\n vrfPublicKey: string;\n userId: string;\n rpId: string;\n blockHeight: string;\n blockHash: string;\n}\n\n/**\n * Decode VRF output and use first 32 bytes as WebAuthn challenge\n * @param vrfChallenge - VRF challenge object\n * @returns 32-byte Uint8Array\n */\nexport function outputAs32Bytes(vrfChallenge: VRFChallenge): Uint8Array {\n let vrfOutputBytes = base64UrlDecode(vrfChallenge.vrfOutput);\n return vrfOutputBytes.slice(0, 32);\n}\n\n/**\n * Validate and create a VRFChallenge object\n * @param vrfChallengeData - The challenge data to validate\n * @returns VRFChallenge object\n */\nexport function validateVRFChallenge(vrfChallengeData: {\n vrfInput: string;\n vrfOutput: string;\n vrfProof: string;\n vrfPublicKey: string;\n userId: string;\n rpId: string;\n blockHeight: string;\n blockHash: string;\n}): VRFChallenge {\n if (!vrfChallengeData.vrfInput || typeof vrfChallengeData.vrfInput !== 'string') {\n throw new Error('vrfInput must be a non-empty string');\n }\n if (!vrfChallengeData.vrfOutput || typeof vrfChallengeData.vrfOutput !== 'string') {\n throw new Error('vrfOutput must be a non-empty string');\n }\n if (!vrfChallengeData.vrfProof || typeof vrfChallengeData.vrfProof !== 'string') {\n throw new Error('vrfProof must be a non-empty string');\n }\n if (!vrfChallengeData.vrfPublicKey || typeof vrfChallengeData.vrfPublicKey !== 'string') {\n throw new Error('vrfPublicKey must be a non-empty string');\n }\n if (!vrfChallengeData.userId || typeof vrfChallengeData.userId !== 'string') {\n throw new Error('userId must be a non-empty string');\n }\n if (!vrfChallengeData.rpId || typeof vrfChallengeData.rpId !== 'string') {\n throw new Error('rpId must be a non-empty string');\n }\n if (!vrfChallengeData.blockHeight || typeof vrfChallengeData.blockHeight !== 'string') {\n throw new Error('blockHeight must be a non-empty string');\n }\n if (!vrfChallengeData.blockHash || typeof vrfChallengeData.blockHash !== 'string') {\n throw new Error('blockHash must be a non-empty string');\n }\n\n return {\n vrfInput: vrfChallengeData.vrfInput,\n vrfOutput: vrfChallengeData.vrfOutput,\n vrfProof: vrfChallengeData.vrfProof,\n vrfPublicKey: vrfChallengeData.vrfPublicKey,\n userId: vrfChallengeData.userId,\n rpId: vrfChallengeData.rpId,\n blockHeight: vrfChallengeData.blockHeight,\n blockHash: vrfChallengeData.blockHash,\n };\n}\n\n/**\n * Create a random VRF challenge\n * @returns Partial<VRFChallenge> with vrfOutput set, but other fields are undefined\n * This is used for local operations that don't require a VRF verification\n */\nexport function createRandomVRFChallenge(): Partial<VRFChallenge> {\n const challenge = crypto.getRandomValues(new Uint8Array(32));\n const vrfOutput = base64UrlEncode(challenge.buffer);\n return {\n vrfOutput: vrfOutput,\n vrfInput: undefined,\n vrfProof: undefined,\n vrfPublicKey: undefined,\n userId: undefined,\n rpId: undefined,\n blockHeight: undefined,\n blockHash: undefined,\n };\n}\n\nexport interface VrfWorkerManagerConfig {\n vrfWorkerUrl?: string;\n workerTimeout?: number;\n debug?: boolean;\n // Optional Shamir 3-pass configuration passed to the VRF WASM worker at init\n shamirPB64u?: string; // base64url prime p\n relayServerUrl?: string;\n applyServerLockRoute?: string;\n removeServerLockRoute?: string;\n}\n\n// Define interfaces that are missing\nexport interface VRFWorkerStatus {\n active: boolean;\n nearAccountId: AccountId | null;\n sessionDuration?: number;\n}\n\nexport interface EncryptedVRFKeypair {\n encryptedVrfDataB64u: string;\n chacha20NonceB64u: string;\n}\n\nexport interface VRFInputData {\n userId: string;\n rpId: string;\n blockHeight: string;\n blockHash: string;\n}\n\nexport interface VRFWorkerMessage<T extends WasmVrfWorkerRequestType> {\n // type: wasmModule.WorkerRequestType\n type: 'PING'\n | 'GENERATE_VRF_CHALLENGE'\n | 'GENERATE_VRF_KEYPAIR_BOOTSTRAP'\n | 'UNLOCK_VRF_KEYPAIR'\n | 'CHECK_VRF_STATUS'\n | 'CLEAR_VRF'\n | 'DERIVE_VRF_KEYPAIR_FROM_PRF'\n | 'MINT_SESSION_KEYS_AND_SEND_TO_SIGNER'\n | 'DISPENSE_SESSION_KEY'\n | 'CHECK_SESSION_STATUS'\n | 'CLEAR_SESSION'\n | 'CONFIRM_AND_PREPARE_SIGNING_SESSION'\n | 'DECRYPT_SESSION'\n | 'REGISTRATION_CREDENTIAL_CONFIRMATION'\n | 'DEVICE2_REGISTRATION_SESSION'\n | 'SHAMIR3PASS_CLIENT_ENCRYPT_CURRENT_VRF_KEYPAIR' // client only\n | 'SHAMIR3PASS_CLIENT_DECRYPT_VRF_KEYPAIR' // client only\n | 'SHAMIR3PASS_APPLY_SERVER_LOCK_KEK' // server only\n | 'SHAMIR3PASS_REMOVE_SERVER_LOCK_KEK' // server only\n | 'SHAMIR3PASS_CONFIG_P'\n | 'SHAMIR3PASS_CONFIG_SERVER_URLS'\n id?: string;\n payload?: T;\n}\n\nexport interface VRFWorkerResponse<TData = Record<string, unknown>> {\n id?: string;\n success: boolean;\n data?: TData;\n error?: string;\n}\n\nexport interface VRFKeypairBootstrapResponse {\n vrfPublicKey: string;\n vrfChallengeData?: VRFChallenge;\n}\n\nexport interface EncryptedVRFKeypairResponse {\n vrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n}\n\n/**\n * Server-encrypted VRF keypair for commutative encryption scheme\n * This allows server-assisted VRF key recovery without the server seeing the plaintext\n */\nexport interface ServerEncryptedVrfKeypair {\n /** Base64url-encoded VRF ciphertext (AEAD over VRF keypair bytes) */\n ciphertextVrfB64u: string;\n /** Base64url-encoded KEK with server lock applied (KEK_s) */\n kek_s_b64u: string;\n /** Server key identifier for proactive refresh/versioning */\n serverKeyId: string;\n}\n\n/**\n * Plaintext VRF keypair data structure\n * Used for loading decrypted VRF keypairs directly into memory\n */\nexport interface VRFKeypairData {\n /** Bincode-serialized ECVRFKeyPair bytes (includes both private and public key) */\n keypairBytes: number[];\n /** Base64url-encoded public key for convenience and verification */\n publicKeyBase64: string;\n}\n\n// Shamir 3-pass registration wrap result\nexport interface Shamir3PassRegisterWrapResult {\n ciphertextVrfB64u: string;\n enc_s_k_b64u: string;\n vrfPublicKey: string;\n}\n"],"mappings":";;;;;;;;;;AA2FA,SAAgB,gBAAgB,cAAwC;CACtE,IAAI,iBAAiBA,+BAAgB,aAAa;AAClD,QAAO,eAAe,MAAM,GAAG;;;;;;;AAQjC,SAAgB,qBAAqB,kBASpB;AACf,KAAI,CAAC,iBAAiB,YAAY,OAAO,iBAAiB,aAAa,SACrE,OAAM,IAAI,MAAM;AAElB,KAAI,CAAC,iBAAiB,aAAa,OAAO,iBAAiB,cAAc,SACvE,OAAM,IAAI,MAAM;AAElB,KAAI,CAAC,iBAAiB,YAAY,OAAO,iBAAiB,aAAa,SACrE,OAAM,IAAI,MAAM;AAElB,KAAI,CAAC,iBAAiB,gBAAgB,OAAO,iBAAiB,iBAAiB,SAC7E,OAAM,IAAI,MAAM;AAElB,KAAI,CAAC,iBAAiB,UAAU,OAAO,iBAAiB,WAAW,SACjE,OAAM,IAAI,MAAM;AAElB,KAAI,CAAC,iBAAiB,QAAQ,OAAO,iBAAiB,SAAS,SAC7D,OAAM,IAAI,MAAM;AAElB,KAAI,CAAC,iBAAiB,eAAe,OAAO,iBAAiB,gBAAgB,SAC3E,OAAM,IAAI,MAAM;AAElB,KAAI,CAAC,iBAAiB,aAAa,OAAO,iBAAiB,cAAc,SACvE,OAAM,IAAI,MAAM;AAGlB,QAAO;EACL,UAAU,iBAAiB;EAC3B,WAAW,iBAAiB;EAC5B,UAAU,iBAAiB;EAC3B,cAAc,iBAAiB;EAC/B,QAAQ,iBAAiB;EACzB,MAAM,iBAAiB;EACvB,aAAa,iBAAiB;EAC9B,WAAW,iBAAiB;;;;;;;;AAShC,SAAgB,2BAAkD;CAChE,MAAM,YAAY,OAAO,gBAAgB,IAAI,WAAW;CACxD,MAAM,YAAYC,+BAAgB,UAAU;AAC5C,QAAO;EACM;EACX,UAAU;EACV,UAAU;EACV,cAAc;EACd,QAAQ;EACR,MAAM;EACN,aAAa;EACb,WAAW"}
@@ -7,9 +7,19 @@ const require_errors = require('./errors.js');
7
7
  const require_deviceDetection = require('../../../deviceDetection.js');
8
8
 
9
9
  //#region src/utils/index.ts
10
- init_encoders();
11
- init_validation();
12
- init_errors();
10
+ var init_utils = require_rolldown_runtime.__esm({ "src/utils/index.ts": (() => {
11
+ init_encoders();
12
+ init_validation();
13
+ init_errors();
14
+ init_deviceDetection();
15
+ }) });
13
16
 
14
17
  //#endregion
18
+ init_utils();
19
+ Object.defineProperty(exports, 'init_utils', {
20
+ enumerable: true,
21
+ get: function () {
22
+ return init_utils;
23
+ }
24
+ });
15
25
  //# sourceMappingURL=index.js.map
@@ -1,3 +1,4 @@
1
+ const require_emailParsers = require('./emailParsers.js');
1
2
  const require_sha2 = require('../node_modules/.pnpm/@noble_hashes@2.0.1/node_modules/@noble/hashes/sha2.js');
2
3
  const require_ed25519 = require('../node_modules/.pnpm/@noble_curves@2.0.1/node_modules/@noble/curves/ed25519.js');
3
4
  const require_hkdf = require('../node_modules/.pnpm/@noble_hashes@2.0.1/node_modules/@noble/hashes/hkdf.js');
@@ -71,8 +72,18 @@ async function encryptEmailForOutlayer(input) {
71
72
  aeadContext
72
73
  };
73
74
  }
75
+ function hashRecoveryEmailForAccount(args) {
76
+ const salt = (args.accountId || "").trim().toLowerCase();
77
+ const canonical = require_emailParsers.canonicalizeEmail(String(args.recoveryEmail || ""));
78
+ if (!canonical) throw new Error("Missing From email address for encrypted email recovery");
79
+ const input = `${canonical}|${salt}`;
80
+ const bytes = new TextEncoder().encode(input);
81
+ const digest = require_sha2.sha256(bytes);
82
+ return Array.from(digest);
83
+ }
74
84
 
75
85
  //#endregion
76
86
  exports.deriveOutlayerStaticKeyFromSeedHex = deriveOutlayerStaticKeyFromSeedHex;
77
87
  exports.encryptEmailForOutlayer = encryptEmailForOutlayer;
88
+ exports.hashRecoveryEmailForAccount = hashRecoveryEmailForAccount;
78
89
  //# sourceMappingURL=emailEncryptor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"emailEncryptor.js","names":["hkdf","sha256","x25519","ephemeralSk: Uint8Array","ephemeralPk: Uint8Array","nonce: Uint8Array","chacha20poly1305","envelope: EncryptedEmailEnvelope"],"sources":["../../../../src/server/email-recovery/emailEncryptor.ts"],"sourcesContent":["import { x25519 } from '@noble/curves/ed25519.js';\nimport { hkdf } from '@noble/hashes/hkdf.js';\nimport { sha256 } from '@noble/hashes/sha2.js';\nimport { chacha20poly1305 } from '@noble/ciphers/chacha.js';\n\nexport interface EncryptedEmailEnvelope {\n version: number;\n ephemeral_pub: string;\n nonce: string;\n ciphertext: string;\n}\n\nexport interface EmailEncryptionContext {\n account_id: string;\n payer_account_id: string;\n network_id: string;\n // Allow relayers to include additional metadata bound into AAD\n [key: string]: unknown;\n}\n\nexport interface EncryptEmailForOutlayerInput {\n emailRaw: string;\n aeadContext: EmailEncryptionContext;\n recipientPk: Uint8Array;\n /**\n * Test-only overrides to make encryption deterministic for round-trip tests.\n */\n testOverrides?: {\n ephemeralSecretKey?: Uint8Array;\n nonce?: Uint8Array;\n };\n}\n\nexport interface EncryptEmailForOutlayerResult {\n envelope: EncryptedEmailEnvelope;\n aeadContext: EmailEncryptionContext;\n}\n\n// IMPORTANT: The exact JSON byte sequence here is used as AEAD AAD and must\n// match what the AEAD context being passed into decrypt_encrypted_email().\n// see: https://github.com/web3-authn/email-dkim-verifier-contract/blob/f06cf33b484cd9750661bf418812f259f0674b69/src/api.rs#L175\n//\n// The contract serializes `args` with serde_json, which orders keys\n// lexicographically, so we must mirror that here. Changing this logic or\n// adding/removing keys requires updating the Outlayer compat tests and\n// verifying decryption end-to-end.\n//\n// Canonical form (alphabetical by key):\n// ```\n// {\n// \"account_id\": \"...\",\n// \"network_id\": \"...\",\n// \"payer_account_id\": \"...\"\n// }\n// ```\nfunction serializeContextForAad(context: EmailEncryptionContext): string {\n const entries = Object.entries(context).sort(([a], [b]) => a.localeCompare(b));\n return JSON.stringify(Object.fromEntries(entries));\n}\n\nexport function deriveOutlayerStaticKeyFromSeedHex(seedHex: string): { secretKey: Uint8Array; publicKey: Uint8Array } {\n const cleaned = seedHex.trim();\n if (cleaned.length !== 64) {\n throw new Error('OUTLAYER_WORKER_SK_SEED_HEX32 must be a 64-char hex string');\n }\n const seed = new Uint8Array(32);\n for (let i = 0; i < 32; i++) {\n const byteHex = cleaned.slice(i * 2, i * 2 + 2);\n const value = Number.parseInt(byteHex, 16);\n if (Number.isNaN(value)) {\n throw new Error('OUTLAYER_WORKER_SK_SEED_HEX32 contains non-hex characters');\n }\n seed[i] = value;\n }\n const encoder = new TextEncoder();\n const okm = hkdf(sha256, seed, undefined, encoder.encode('outlayer-email-dkim-x25519'), 32);\n const secretKey = okm instanceof Uint8Array ? okm : new Uint8Array(okm);\n const publicKey = x25519.getPublicKey(secretKey);\n return { secretKey, publicKey };\n}\n\nexport async function encryptEmailForOutlayer(\n input: EncryptEmailForOutlayerInput\n): Promise<EncryptEmailForOutlayerResult> {\n const { emailRaw, aeadContext, recipientPk, testOverrides } = input;\n\n if (!(recipientPk instanceof Uint8Array) || recipientPk.length !== 32) {\n throw new Error('recipientPk must be a 32-byte X25519 public key');\n }\n\n const encoder = new TextEncoder();\n\n // 1. Generate ephemeral X25519 keypair\n let ephemeralSk: Uint8Array;\n let ephemeralPk: Uint8Array;\n if (testOverrides?.ephemeralSecretKey) {\n if (!(testOverrides.ephemeralSecretKey instanceof Uint8Array) || testOverrides.ephemeralSecretKey.length !== 32) {\n throw new Error('testOverrides.ephemeralSecretKey must be a 32-byte Uint8Array');\n }\n ephemeralSk = testOverrides.ephemeralSecretKey;\n ephemeralPk = x25519.getPublicKey(ephemeralSk);\n } else {\n const { secretKey, publicKey } = x25519.keygen();\n ephemeralSk = secretKey;\n ephemeralPk = publicKey;\n }\n\n // 2. Derive shared secret via X25519 ECDH\n const sharedSecret = x25519.getSharedSecret(ephemeralSk, recipientPk); // 32 bytes\n\n // 3. Derive symmetric key via HKDF-SHA256 (info=\"email-dkim-encryption-key\")\n const info = encoder.encode('email-dkim-encryption-key');\n const symmetricKey = hkdf(sha256, sharedSecret, undefined, info, 32);\n\n // 4. Encrypt using ChaCha20-Poly1305 with JSON(context) as AAD\n let nonce: Uint8Array;\n if (testOverrides?.nonce) {\n if (!(testOverrides.nonce instanceof Uint8Array) || testOverrides.nonce.length !== 12) {\n throw new Error('testOverrides.nonce must be a 12-byte Uint8Array');\n }\n nonce = testOverrides.nonce;\n } else {\n nonce = crypto.getRandomValues(new Uint8Array(12));\n }\n const aad = encoder.encode(serializeContextForAad(aeadContext));\n const plaintext = encoder.encode(emailRaw);\n\n const cipher = chacha20poly1305(symmetricKey, nonce, aad);\n const ciphertext = cipher.encrypt(plaintext);\n\n // 5. Serialize fields as base64 strings\n const b64 = (bytes: Uint8Array): string => {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(bytes).toString('base64');\n }\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n };\n\n const envelope: EncryptedEmailEnvelope = {\n version: 1,\n ephemeral_pub: b64(ephemeralPk),\n nonce: b64(nonce),\n ciphertext: b64(ciphertext),\n };\n\n return { envelope, aeadContext };\n}\n"],"mappings":";;;;;;AAuDA,SAAS,uBAAuB,SAAyC;CACvE,MAAM,UAAU,OAAO,QAAQ,SAAS,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc;AAC3E,QAAO,KAAK,UAAU,OAAO,YAAY;;AAG3C,SAAgB,mCAAmC,SAAmE;CACpH,MAAM,UAAU,QAAQ;AACxB,KAAI,QAAQ,WAAW,GACrB,OAAM,IAAI,MAAM;CAElB,MAAM,OAAO,IAAI,WAAW;AAC5B,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,MAAM,UAAU,QAAQ,MAAM,IAAI,GAAG,IAAI,IAAI;EAC7C,MAAM,QAAQ,OAAO,SAAS,SAAS;AACvC,MAAI,OAAO,MAAM,OACf,OAAM,IAAI,MAAM;AAElB,OAAK,KAAK;;CAEZ,MAAM,UAAU,IAAI;CACpB,MAAM,MAAMA,kBAAKC,qBAAQ,MAAM,QAAW,QAAQ,OAAO,+BAA+B;CACxF,MAAM,YAAY,eAAe,aAAa,MAAM,IAAI,WAAW;CACnE,MAAM,YAAYC,uBAAO,aAAa;AACtC,QAAO;EAAE;EAAW;;;AAGtB,eAAsB,wBACpB,OACwC;CACxC,MAAM,EAAE,UAAU,aAAa,aAAa,kBAAkB;AAE9D,KAAI,EAAE,uBAAuB,eAAe,YAAY,WAAW,GACjE,OAAM,IAAI,MAAM;CAGlB,MAAM,UAAU,IAAI;CAGpB,IAAIC;CACJ,IAAIC;AACJ,KAAI,eAAe,oBAAoB;AACrC,MAAI,EAAE,cAAc,8BAA8B,eAAe,cAAc,mBAAmB,WAAW,GAC3G,OAAM,IAAI,MAAM;AAElB,gBAAc,cAAc;AAC5B,gBAAcF,uBAAO,aAAa;QAC7B;EACL,MAAM,EAAE,WAAW,cAAcA,uBAAO;AACxC,gBAAc;AACd,gBAAc;;CAIhB,MAAM,eAAeA,uBAAO,gBAAgB,aAAa;CAGzD,MAAM,OAAO,QAAQ,OAAO;CAC5B,MAAM,eAAeF,kBAAKC,qBAAQ,cAAc,QAAW,MAAM;CAGjE,IAAII;AACJ,KAAI,eAAe,OAAO;AACxB,MAAI,EAAE,cAAc,iBAAiB,eAAe,cAAc,MAAM,WAAW,GACjF,OAAM,IAAI,MAAM;AAElB,UAAQ,cAAc;OAEtB,SAAQ,OAAO,gBAAgB,IAAI,WAAW;CAEhD,MAAM,MAAM,QAAQ,OAAO,uBAAuB;CAClD,MAAM,YAAY,QAAQ,OAAO;CAEjC,MAAM,SAASC,gCAAiB,cAAc,OAAO;CACrD,MAAM,aAAa,OAAO,QAAQ;CAGlC,MAAM,OAAO,UAA8B;AACzC,MAAI,OAAO,WAAW,YACpB,QAAO,OAAO,KAAK,OAAO,SAAS;EAErC,IAAI,SAAS;AACb,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,IAChC,WAAU,OAAO,aAAa,MAAM;AAEtC,SAAO,KAAK;;CAGd,MAAMC,WAAmC;EACvC,SAAS;EACT,eAAe,IAAI;EACnB,OAAO,IAAI;EACX,YAAY,IAAI;;AAGlB,QAAO;EAAE;EAAU"}
1
+ {"version":3,"file":"emailEncryptor.js","names":["hkdf","sha256","x25519","ephemeralSk: Uint8Array","ephemeralPk: Uint8Array","nonce: Uint8Array","chacha20poly1305","envelope: EncryptedEmailEnvelope","canonicalizeEmail"],"sources":["../../../../src/server/email-recovery/emailEncryptor.ts"],"sourcesContent":["import { x25519 } from '@noble/curves/ed25519.js';\nimport { hkdf } from '@noble/hashes/hkdf.js';\nimport { sha256 } from '@noble/hashes/sha2.js';\nimport { chacha20poly1305 } from '@noble/ciphers/chacha.js';\nimport { canonicalizeEmail } from './emailParsers';\n\nexport interface EncryptedEmailEnvelope {\n version: number;\n ephemeral_pub: string;\n nonce: string;\n ciphertext: string;\n}\n\nexport interface EmailEncryptionContext {\n account_id: string;\n payer_account_id: string;\n network_id: string;\n // Allow relayers to include additional metadata bound into AAD\n [key: string]: unknown;\n}\n\nexport interface EncryptEmailForOutlayerInput {\n emailRaw: string;\n aeadContext: EmailEncryptionContext;\n recipientPk: Uint8Array;\n /**\n * Test-only overrides to make encryption deterministic for round-trip tests.\n */\n testOverrides?: {\n ephemeralSecretKey?: Uint8Array;\n nonce?: Uint8Array;\n };\n}\n\nexport interface EncryptEmailForOutlayerResult {\n envelope: EncryptedEmailEnvelope;\n aeadContext: EmailEncryptionContext;\n}\n\n// IMPORTANT: The exact JSON byte sequence here is used as AEAD AAD and must\n// match what the AEAD context being passed into decrypt_encrypted_email().\n// see: https://github.com/web3-authn/email-dkim-verifier-contract/blob/f06cf33b484cd9750661bf418812f259f0674b69/src/api.rs#L175\n//\n// The contract serializes `args` with serde_json, which orders keys\n// lexicographically, so we must mirror that here. Changing this logic or\n// adding/removing keys requires updating the Outlayer compat tests and\n// verifying decryption end-to-end.\n//\n// Canonical form (alphabetical by key):\n// ```\n// {\n// \"account_id\": \"...\",\n// \"network_id\": \"...\",\n// \"payer_account_id\": \"...\"\n// }\n// ```\nfunction serializeContextForAad(context: EmailEncryptionContext): string {\n const entries = Object.entries(context).sort(([a], [b]) => a.localeCompare(b));\n return JSON.stringify(Object.fromEntries(entries));\n}\n\nexport function deriveOutlayerStaticKeyFromSeedHex(seedHex: string): { secretKey: Uint8Array; publicKey: Uint8Array } {\n const cleaned = seedHex.trim();\n if (cleaned.length !== 64) {\n throw new Error('OUTLAYER_WORKER_SK_SEED_HEX32 must be a 64-char hex string');\n }\n const seed = new Uint8Array(32);\n for (let i = 0; i < 32; i++) {\n const byteHex = cleaned.slice(i * 2, i * 2 + 2);\n const value = Number.parseInt(byteHex, 16);\n if (Number.isNaN(value)) {\n throw new Error('OUTLAYER_WORKER_SK_SEED_HEX32 contains non-hex characters');\n }\n seed[i] = value;\n }\n const encoder = new TextEncoder();\n const okm = hkdf(sha256, seed, undefined, encoder.encode('outlayer-email-dkim-x25519'), 32);\n const secretKey = okm instanceof Uint8Array ? okm : new Uint8Array(okm);\n const publicKey = x25519.getPublicKey(secretKey);\n return { secretKey, publicKey };\n}\n\nexport async function encryptEmailForOutlayer(\n input: EncryptEmailForOutlayerInput\n): Promise<EncryptEmailForOutlayerResult> {\n const { emailRaw, aeadContext, recipientPk, testOverrides } = input;\n\n if (!(recipientPk instanceof Uint8Array) || recipientPk.length !== 32) {\n throw new Error('recipientPk must be a 32-byte X25519 public key');\n }\n\n const encoder = new TextEncoder();\n\n // 1. Generate ephemeral X25519 keypair\n let ephemeralSk: Uint8Array;\n let ephemeralPk: Uint8Array;\n if (testOverrides?.ephemeralSecretKey) {\n if (!(testOverrides.ephemeralSecretKey instanceof Uint8Array) || testOverrides.ephemeralSecretKey.length !== 32) {\n throw new Error('testOverrides.ephemeralSecretKey must be a 32-byte Uint8Array');\n }\n ephemeralSk = testOverrides.ephemeralSecretKey;\n ephemeralPk = x25519.getPublicKey(ephemeralSk);\n } else {\n const { secretKey, publicKey } = x25519.keygen();\n ephemeralSk = secretKey;\n ephemeralPk = publicKey;\n }\n\n // 2. Derive shared secret via X25519 ECDH\n const sharedSecret = x25519.getSharedSecret(ephemeralSk, recipientPk); // 32 bytes\n\n // 3. Derive symmetric key via HKDF-SHA256 (info=\"email-dkim-encryption-key\")\n const info = encoder.encode('email-dkim-encryption-key');\n const symmetricKey = hkdf(sha256, sharedSecret, undefined, info, 32);\n\n // 4. Encrypt using ChaCha20-Poly1305 with JSON(context) as AAD\n let nonce: Uint8Array;\n if (testOverrides?.nonce) {\n if (!(testOverrides.nonce instanceof Uint8Array) || testOverrides.nonce.length !== 12) {\n throw new Error('testOverrides.nonce must be a 12-byte Uint8Array');\n }\n nonce = testOverrides.nonce;\n } else {\n nonce = crypto.getRandomValues(new Uint8Array(12));\n }\n const aad = encoder.encode(serializeContextForAad(aeadContext));\n const plaintext = encoder.encode(emailRaw);\n\n const cipher = chacha20poly1305(symmetricKey, nonce, aad);\n const ciphertext = cipher.encrypt(plaintext);\n\n // 5. Serialize fields as base64 strings\n const b64 = (bytes: Uint8Array): string => {\n if (typeof Buffer !== 'undefined') {\n return Buffer.from(bytes).toString('base64');\n }\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n };\n\n const envelope: EncryptedEmailEnvelope = {\n version: 1,\n ephemeral_pub: b64(ephemeralPk),\n nonce: b64(nonce),\n ciphertext: b64(ciphertext),\n };\n\n return { envelope, aeadContext };\n}\n\nexport function hashRecoveryEmailForAccount(args: { recoveryEmail: string; accountId: string }): number[] {\n const salt = (args.accountId || '').trim().toLowerCase();\n const canonical = canonicalizeEmail(String(args.recoveryEmail || ''));\n if (!canonical) {\n throw new Error('Missing From email address for encrypted email recovery');\n }\n const input = `${canonical}|${salt}`;\n const bytes = new TextEncoder().encode(input);\n const digest = sha256(bytes);\n return Array.from(digest);\n}\n"],"mappings":";;;;;;;AAwDA,SAAS,uBAAuB,SAAyC;CACvE,MAAM,UAAU,OAAO,QAAQ,SAAS,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc;AAC3E,QAAO,KAAK,UAAU,OAAO,YAAY;;AAG3C,SAAgB,mCAAmC,SAAmE;CACpH,MAAM,UAAU,QAAQ;AACxB,KAAI,QAAQ,WAAW,GACrB,OAAM,IAAI,MAAM;CAElB,MAAM,OAAO,IAAI,WAAW;AAC5B,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,MAAM,UAAU,QAAQ,MAAM,IAAI,GAAG,IAAI,IAAI;EAC7C,MAAM,QAAQ,OAAO,SAAS,SAAS;AACvC,MAAI,OAAO,MAAM,OACf,OAAM,IAAI,MAAM;AAElB,OAAK,KAAK;;CAEZ,MAAM,UAAU,IAAI;CACpB,MAAM,MAAMA,kBAAKC,qBAAQ,MAAM,QAAW,QAAQ,OAAO,+BAA+B;CACxF,MAAM,YAAY,eAAe,aAAa,MAAM,IAAI,WAAW;CACnE,MAAM,YAAYC,uBAAO,aAAa;AACtC,QAAO;EAAE;EAAW;;;AAGtB,eAAsB,wBACpB,OACwC;CACxC,MAAM,EAAE,UAAU,aAAa,aAAa,kBAAkB;AAE9D,KAAI,EAAE,uBAAuB,eAAe,YAAY,WAAW,GACjE,OAAM,IAAI,MAAM;CAGlB,MAAM,UAAU,IAAI;CAGpB,IAAIC;CACJ,IAAIC;AACJ,KAAI,eAAe,oBAAoB;AACrC,MAAI,EAAE,cAAc,8BAA8B,eAAe,cAAc,mBAAmB,WAAW,GAC3G,OAAM,IAAI,MAAM;AAElB,gBAAc,cAAc;AAC5B,gBAAcF,uBAAO,aAAa;QAC7B;EACL,MAAM,EAAE,WAAW,cAAcA,uBAAO;AACxC,gBAAc;AACd,gBAAc;;CAIhB,MAAM,eAAeA,uBAAO,gBAAgB,aAAa;CAGzD,MAAM,OAAO,QAAQ,OAAO;CAC5B,MAAM,eAAeF,kBAAKC,qBAAQ,cAAc,QAAW,MAAM;CAGjE,IAAII;AACJ,KAAI,eAAe,OAAO;AACxB,MAAI,EAAE,cAAc,iBAAiB,eAAe,cAAc,MAAM,WAAW,GACjF,OAAM,IAAI,MAAM;AAElB,UAAQ,cAAc;OAEtB,SAAQ,OAAO,gBAAgB,IAAI,WAAW;CAEhD,MAAM,MAAM,QAAQ,OAAO,uBAAuB;CAClD,MAAM,YAAY,QAAQ,OAAO;CAEjC,MAAM,SAASC,gCAAiB,cAAc,OAAO;CACrD,MAAM,aAAa,OAAO,QAAQ;CAGlC,MAAM,OAAO,UAA8B;AACzC,MAAI,OAAO,WAAW,YACpB,QAAO,OAAO,KAAK,OAAO,SAAS;EAErC,IAAI,SAAS;AACb,OAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,IAChC,WAAU,OAAO,aAAa,MAAM;AAEtC,SAAO,KAAK;;CAGd,MAAMC,WAAmC;EACvC,SAAS;EACT,eAAe,IAAI;EACnB,OAAO,IAAI;EACX,YAAY,IAAI;;AAGlB,QAAO;EAAE;EAAU;;;AAGrB,SAAgB,4BAA4B,MAA8D;CACxG,MAAM,QAAQ,KAAK,aAAa,IAAI,OAAO;CAC3C,MAAM,YAAYC,uCAAkB,OAAO,KAAK,iBAAiB;AACjE,KAAI,CAAC,UACH,OAAM,IAAI,MAAM;CAElB,MAAM,QAAQ,GAAG,UAAU,GAAG;CAC9B,MAAM,QAAQ,IAAI,cAAc,OAAO;CACvC,MAAM,SAASP,oBAAO;AACtB,QAAO,MAAM,KAAK"}
@@ -31,8 +31,65 @@ function extractRecoveryModeFromBody(emailBlob) {
31
31
  if (lower.includes(EmailRecoveryModeHint.OnchainPublic)) return "onchain-public";
32
32
  return null;
33
33
  }
34
+ const EMAIL_ADDRESS_REGEX = /([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*)/;
35
+ function canonicalizeEmail(input) {
36
+ const raw = String(input || "").trim();
37
+ if (!raw) return "";
38
+ const withoutHeaderName = raw.replace(/^[a-z0-9-]+\s*:\s*/i, "").trim();
39
+ const angleMatch = withoutHeaderName.match(/<([^>]+)>/);
40
+ const candidates = [angleMatch?.[1], withoutHeaderName].filter((v) => typeof v === "string" && v.length > 0);
41
+ for (const candidate of candidates) {
42
+ const cleaned = candidate.replace(/^mailto:\s*/i, "");
43
+ const match = cleaned.match(EMAIL_ADDRESS_REGEX);
44
+ if (match?.[1]) return match[1].trim().toLowerCase();
45
+ }
46
+ return withoutHeaderName.toLowerCase();
47
+ }
48
+ function parseHeaderValue(rawEmail, name) {
49
+ try {
50
+ const raw = String(rawEmail || "");
51
+ if (!raw) return void 0;
52
+ const lines = raw.split(/\r?\n/);
53
+ const headerLines = [];
54
+ for (const line of lines) {
55
+ if (line.trim() === "") break;
56
+ if (/^\s/.test(line) && headerLines.length > 0) {
57
+ headerLines[headerLines.length - 1] += ` ${line.trim()}`;
58
+ continue;
59
+ }
60
+ headerLines.push(line);
61
+ }
62
+ const headerName = name.trim();
63
+ if (!headerName) return void 0;
64
+ const re = new RegExp(`^${headerName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*:`, "i");
65
+ const found = headerLines.find((l) => re.test(l));
66
+ if (!found) return void 0;
67
+ const idx = found.indexOf(":");
68
+ const value = idx >= 0 ? found.slice(idx + 1).trim() : "";
69
+ return value || void 0;
70
+ } catch {
71
+ return void 0;
72
+ }
73
+ }
74
+ function parseRecoverSubjectBindings(rawEmail) {
75
+ let subjectText = (parseHeaderValue(rawEmail, "subject") || String(rawEmail || "")).trim();
76
+ if (!subjectText) return null;
77
+ subjectText = subjectText.replace(/^(re|fwd):\s*/i, "").trim();
78
+ if (!subjectText) return null;
79
+ const match = subjectText.match(/^recover-([A-Za-z0-9]{6})\s+([^\s]+)\s+ed25519:([^\s]+)\s*$/i);
80
+ if (!match) return null;
81
+ const [, requestId, accountId, newPublicKey] = match;
82
+ return {
83
+ requestId,
84
+ accountId,
85
+ newPublicKey
86
+ };
87
+ }
34
88
 
35
89
  //#endregion
90
+ exports.canonicalizeEmail = canonicalizeEmail;
36
91
  exports.extractRecoveryModeFromBody = extractRecoveryModeFromBody;
37
92
  exports.normalizeRecoveryMode = normalizeRecoveryMode;
93
+ exports.parseHeaderValue = parseHeaderValue;
94
+ exports.parseRecoverSubjectBindings = parseRecoverSubjectBindings;
38
95
  //# sourceMappingURL=emailParsers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"emailParsers.js","names":[],"sources":["../../../../src/server/email-recovery/emailParsers.ts"],"sourcesContent":["import type { EmailRecoveryMode } from './types';\nimport { normalizeForwardableEmailPayload, parseAccountIdFromSubject } from './zkEmail';\n\nexport enum EmailRecoveryModeHint {\n ZkEmail = 'zk-email',\n TeeEncrypted = 'tee-encrypted',\n OnchainPublic = 'onchain-public',\n}\n\nexport function normalizeRecoveryMode(raw: string | undefined | null): EmailRecoveryMode | null {\n if (!raw) return null;\n const value = raw.trim().toLowerCase();\n if (value === EmailRecoveryModeHint.ZkEmail) return 'zk-email';\n if (value === EmailRecoveryModeHint.TeeEncrypted) return 'tee-encrypted';\n if (value === EmailRecoveryModeHint.OnchainPublic) return 'onchain-public';\n return null;\n}\n\nexport function extractRecoveryModeFromBody(emailBlob?: string): EmailRecoveryMode | null {\n if (!emailBlob) return null;\n\n const lines = emailBlob.split(/\\r?\\n/);\n const bodyStartIndex = lines.findIndex(line => line.trim() === '');\n if (bodyStartIndex === -1) return null;\n\n const bodyLines = lines.slice(bodyStartIndex + 1);\n const firstNonEmptyBodyLine = bodyLines.find(line => line.trim() !== '');\n if (!firstNonEmptyBodyLine) return null;\n\n const candidate = firstNonEmptyBodyLine.trim();\n const normalized = normalizeRecoveryMode(candidate);\n if (normalized) return normalized;\n\n const lower = candidate.toLowerCase();\n if (lower.includes(EmailRecoveryModeHint.ZkEmail)) return 'zk-email';\n if (lower.includes(EmailRecoveryModeHint.TeeEncrypted)) return 'tee-encrypted';\n if (lower.includes(EmailRecoveryModeHint.OnchainPublic)) return 'onchain-public';\n\n return null;\n}\n\ntype HeaderValue = string | string[] | undefined;\ntype HeadersLike = Headers | Record<string, HeaderValue> | undefined;\n\nexport type RecoverEmailParseResult =\n | { ok: true; accountId: string; emailBlob: string; explicitMode?: string }\n | { ok: false; status: number; code: string; message: string };\n\nfunction getHeader(headers: HeadersLike, name: string): string | undefined {\n if (!headers) return undefined;\n\n const maybeHeaders = headers as any;\n if (typeof maybeHeaders.get === 'function') {\n const v = maybeHeaders.get(name);\n return (typeof v === 'string') ? v : undefined;\n }\n\n const record = headers as Record<string, HeaderValue>;\n const v = record[name.toLowerCase()] ?? record[name];\n if (Array.isArray(v)) return (typeof v[0] === 'string') ? v[0] : undefined;\n return (typeof v === 'string') ? v : undefined;\n}\n\nfunction parseExplicitMode(body: unknown, headers?: HeadersLike): string | undefined {\n const modeFromBody =\n (typeof (body as any)?.explicitMode === 'string' ? String((body as any).explicitMode) : '') ||\n (typeof (body as any)?.explicit_mode === 'string' ? String((body as any).explicit_mode) : '');\n const modeFromHeader = getHeader(headers, 'x-email-recovery-mode') || getHeader(headers, 'x-recovery-mode') || '';\n const raw = (modeFromBody || modeFromHeader).trim();\n return raw ? raw : undefined;\n}\n\nexport function parseRecoverEmailRequest(body: unknown, opts: { headers?: HeadersLike } = {}): RecoverEmailParseResult {\n const explicitMode = parseExplicitMode(body, opts.headers);\n\n const normalized = normalizeForwardableEmailPayload(body);\n if (!normalized.ok) {\n return { ok: false, status: 400, code: normalized.code, message: normalized.message };\n }\n\n const payload = normalized.payload;\n const emailBlob = payload.raw || '';\n const emailHeaders = payload.headers || {};\n\n const subjectHeader = emailHeaders['subject'];\n const parsedAccountId = parseAccountIdFromSubject(subjectHeader || emailBlob);\n const headerAccountId = String(emailHeaders['x-near-account-id'] || emailHeaders['x-account-id'] || '').trim();\n const accountId = (parsedAccountId || headerAccountId || '').trim();\n\n if (!accountId) {\n return { ok: false, status: 400, code: 'missing_account', message: 'x-near-account-id header is required' };\n }\n if (!emailBlob) {\n return { ok: false, status: 400, code: 'missing_email', message: 'raw email blob is required' };\n }\n\n return { ok: true, accountId, emailBlob, explicitMode };\n}\n"],"mappings":";;AAGA,IAAY,0EAAL;AACL;AACA;AACA;;;AAGF,SAAgB,sBAAsB,KAA0D;AAC9F,KAAI,CAAC,IAAK,QAAO;CACjB,MAAM,QAAQ,IAAI,OAAO;AACzB,KAAI,UAAU,sBAAsB,QAAS,QAAO;AACpD,KAAI,UAAU,sBAAsB,aAAc,QAAO;AACzD,KAAI,UAAU,sBAAsB,cAAe,QAAO;AAC1D,QAAO;;AAGT,SAAgB,4BAA4B,WAA8C;AACxF,KAAI,CAAC,UAAW,QAAO;CAEvB,MAAM,QAAQ,UAAU,MAAM;CAC9B,MAAM,iBAAiB,MAAM,WAAU,SAAQ,KAAK,WAAW;AAC/D,KAAI,mBAAmB,GAAI,QAAO;CAElC,MAAM,YAAY,MAAM,MAAM,iBAAiB;CAC/C,MAAM,wBAAwB,UAAU,MAAK,SAAQ,KAAK,WAAW;AACrE,KAAI,CAAC,sBAAuB,QAAO;CAEnC,MAAM,YAAY,sBAAsB;CACxC,MAAM,aAAa,sBAAsB;AACzC,KAAI,WAAY,QAAO;CAEvB,MAAM,QAAQ,UAAU;AACxB,KAAI,MAAM,SAAS,sBAAsB,SAAU,QAAO;AAC1D,KAAI,MAAM,SAAS,sBAAsB,cAAe,QAAO;AAC/D,KAAI,MAAM,SAAS,sBAAsB,eAAgB,QAAO;AAEhE,QAAO"}
1
+ {"version":3,"file":"emailParsers.js","names":["headerLines: string[]"],"sources":["../../../../src/server/email-recovery/emailParsers.ts"],"sourcesContent":["import type { EmailRecoveryMode } from './types';\nimport { normalizeForwardableEmailPayload, parseAccountIdFromSubject } from './zkEmail';\n\nexport enum EmailRecoveryModeHint {\n ZkEmail = 'zk-email',\n TeeEncrypted = 'tee-encrypted',\n OnchainPublic = 'onchain-public',\n}\n\nexport function normalizeRecoveryMode(raw: string | undefined | null): EmailRecoveryMode | null {\n if (!raw) return null;\n const value = raw.trim().toLowerCase();\n if (value === EmailRecoveryModeHint.ZkEmail) return 'zk-email';\n if (value === EmailRecoveryModeHint.TeeEncrypted) return 'tee-encrypted';\n if (value === EmailRecoveryModeHint.OnchainPublic) return 'onchain-public';\n return null;\n}\n\nexport function extractRecoveryModeFromBody(emailBlob?: string): EmailRecoveryMode | null {\n if (!emailBlob) return null;\n\n const lines = emailBlob.split(/\\r?\\n/);\n const bodyStartIndex = lines.findIndex(line => line.trim() === '');\n if (bodyStartIndex === -1) return null;\n\n const bodyLines = lines.slice(bodyStartIndex + 1);\n const firstNonEmptyBodyLine = bodyLines.find(line => line.trim() !== '');\n if (!firstNonEmptyBodyLine) return null;\n\n const candidate = firstNonEmptyBodyLine.trim();\n const normalized = normalizeRecoveryMode(candidate);\n if (normalized) return normalized;\n\n const lower = candidate.toLowerCase();\n if (lower.includes(EmailRecoveryModeHint.ZkEmail)) return 'zk-email';\n if (lower.includes(EmailRecoveryModeHint.TeeEncrypted)) return 'tee-encrypted';\n if (lower.includes(EmailRecoveryModeHint.OnchainPublic)) return 'onchain-public';\n\n return null;\n}\n\ntype HeaderValue = string | string[] | undefined;\ntype HeadersLike = Headers | Record<string, HeaderValue> | undefined;\n\nexport type RecoverEmailParseResult =\n | { ok: true; accountId: string; emailBlob: string; explicitMode?: string }\n | { ok: false; status: number; code: string; message: string };\n\nfunction getHeader(headers: HeadersLike, name: string): string | undefined {\n if (!headers) return undefined;\n\n const maybeHeaders = headers as any;\n if (typeof maybeHeaders.get === 'function') {\n const v = maybeHeaders.get(name);\n return (typeof v === 'string') ? v : undefined;\n }\n\n const record = headers as Record<string, HeaderValue>;\n const v = record[name.toLowerCase()] ?? record[name];\n if (Array.isArray(v)) return (typeof v[0] === 'string') ? v[0] : undefined;\n return (typeof v === 'string') ? v : undefined;\n}\n\nfunction parseExplicitMode(body: unknown, headers?: HeadersLike): string | undefined {\n const modeFromBody =\n (typeof (body as any)?.explicitMode === 'string' ? String((body as any).explicitMode) : '') ||\n (typeof (body as any)?.explicit_mode === 'string' ? String((body as any).explicit_mode) : '');\n const modeFromHeader = getHeader(headers, 'x-email-recovery-mode') || getHeader(headers, 'x-recovery-mode') || '';\n const raw = (modeFromBody || modeFromHeader).trim();\n return raw ? raw : undefined;\n}\n\nexport function parseRecoverEmailRequest(body: unknown, opts: { headers?: HeadersLike } = {}): RecoverEmailParseResult {\n const explicitMode = parseExplicitMode(body, opts.headers);\n\n const normalized = normalizeForwardableEmailPayload(body);\n if (!normalized.ok) {\n return { ok: false, status: 400, code: normalized.code, message: normalized.message };\n }\n\n const payload = normalized.payload;\n const emailBlob = payload.raw || '';\n const emailHeaders = payload.headers || {};\n\n const subjectHeader = emailHeaders['subject'];\n const parsedAccountId = parseAccountIdFromSubject(subjectHeader || emailBlob);\n const headerAccountId = String(emailHeaders['x-near-account-id'] || emailHeaders['x-account-id'] || '').trim();\n const accountId = (parsedAccountId || headerAccountId || '').trim();\n\n if (!accountId) {\n return { ok: false, status: 400, code: 'missing_account', message: 'x-near-account-id header is required' };\n }\n if (!emailBlob) {\n return { ok: false, status: 400, code: 'missing_email', message: 'raw email blob is required' };\n }\n\n return { ok: true, accountId, emailBlob, explicitMode };\n}\n\nconst EMAIL_ADDRESS_REGEX =\n /([a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*)/;\n\nexport function canonicalizeEmail(input: string): string {\n const raw = String(input || '').trim();\n if (!raw) return '';\n\n // Handle cases where a full header line is passed in (e.g. \"From: ...\").\n const withoutHeaderName = raw.replace(/^[a-z0-9-]+\\s*:\\s*/i, '').trim();\n\n // Prefer the common \"Name <email@domain>\" format when present, but still\n // validate/extract the actual address via regex.\n const angleMatch = withoutHeaderName.match(/<([^>]+)>/);\n const candidates = [\n angleMatch?.[1],\n withoutHeaderName,\n ].filter((v): v is string => typeof v === 'string' && v.length > 0);\n\n for (const candidate of candidates) {\n const cleaned = candidate.replace(/^mailto:\\s*/i, '');\n const match = cleaned.match(EMAIL_ADDRESS_REGEX);\n if (match?.[1]) {\n return match[1].trim().toLowerCase();\n }\n }\n\n return withoutHeaderName.toLowerCase();\n}\n\nexport function parseHeaderValue(rawEmail: string, name: string): string | undefined {\n try {\n const raw = String(rawEmail || '');\n if (!raw) return undefined;\n\n const lines = raw.split(/\\r?\\n/);\n const headerLines: string[] = [];\n\n // Only consider the header section (until the first blank line).\n for (const line of lines) {\n if (line.trim() === '') break;\n\n // RFC822 header folding: lines starting with whitespace continue previous header.\n if (/^\\s/.test(line) && headerLines.length > 0) {\n headerLines[headerLines.length - 1] += ` ${line.trim()}`;\n continue;\n }\n\n headerLines.push(line);\n }\n\n const headerName = name.trim();\n if (!headerName) return undefined;\n\n const re = new RegExp(`^${headerName.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\s*:`, 'i');\n const found = headerLines.find((l) => re.test(l));\n if (!found) return undefined;\n\n const idx = found.indexOf(':');\n const value = idx >= 0 ? found.slice(idx + 1).trim() : '';\n return value || undefined;\n } catch {\n return undefined;\n }\n}\n\nexport function parseRecoverSubjectBindings(\n rawEmail: string\n): { requestId: string; accountId: string; newPublicKey: string } | null {\n // Accept either a full RFC822 email or a bare Subject value.\n let subjectText = (parseHeaderValue(rawEmail, 'subject') || String(rawEmail || '')).trim();\n if (!subjectText) return null;\n\n // Strip common reply/forward prefixes.\n subjectText = subjectText.replace(/^(re|fwd):\\s*/i, '').trim();\n if (!subjectText) return null;\n\n // Strict format:\n // \"recover-<request_id> <accountId> ed25519:<pk>\"\n const match = subjectText.match(\n /^recover-([A-Za-z0-9]{6})\\s+([^\\s]+)\\s+ed25519:([^\\s]+)\\s*$/i\n );\n if (!match) return null;\n\n const [, requestId, accountId, newPublicKey] = match;\n return { requestId, accountId, newPublicKey };\n}\n"],"mappings":";;AAGA,IAAY,0EAAL;AACL;AACA;AACA;;;AAGF,SAAgB,sBAAsB,KAA0D;AAC9F,KAAI,CAAC,IAAK,QAAO;CACjB,MAAM,QAAQ,IAAI,OAAO;AACzB,KAAI,UAAU,sBAAsB,QAAS,QAAO;AACpD,KAAI,UAAU,sBAAsB,aAAc,QAAO;AACzD,KAAI,UAAU,sBAAsB,cAAe,QAAO;AAC1D,QAAO;;AAGT,SAAgB,4BAA4B,WAA8C;AACxF,KAAI,CAAC,UAAW,QAAO;CAEvB,MAAM,QAAQ,UAAU,MAAM;CAC9B,MAAM,iBAAiB,MAAM,WAAU,SAAQ,KAAK,WAAW;AAC/D,KAAI,mBAAmB,GAAI,QAAO;CAElC,MAAM,YAAY,MAAM,MAAM,iBAAiB;CAC/C,MAAM,wBAAwB,UAAU,MAAK,SAAQ,KAAK,WAAW;AACrE,KAAI,CAAC,sBAAuB,QAAO;CAEnC,MAAM,YAAY,sBAAsB;CACxC,MAAM,aAAa,sBAAsB;AACzC,KAAI,WAAY,QAAO;CAEvB,MAAM,QAAQ,UAAU;AACxB,KAAI,MAAM,SAAS,sBAAsB,SAAU,QAAO;AAC1D,KAAI,MAAM,SAAS,sBAAsB,cAAe,QAAO;AAC/D,KAAI,MAAM,SAAS,sBAAsB,eAAgB,QAAO;AAEhE,QAAO;;AA6DT,MAAM,sBACJ;AAEF,SAAgB,kBAAkB,OAAuB;CACvD,MAAM,MAAM,OAAO,SAAS,IAAI;AAChC,KAAI,CAAC,IAAK,QAAO;CAGjB,MAAM,oBAAoB,IAAI,QAAQ,uBAAuB,IAAI;CAIjE,MAAM,aAAa,kBAAkB,MAAM;CAC3C,MAAM,aAAa,CACjB,aAAa,IACb,mBACA,QAAQ,MAAmB,OAAO,MAAM,YAAY,EAAE,SAAS;AAEjE,MAAK,MAAM,aAAa,YAAY;EAClC,MAAM,UAAU,UAAU,QAAQ,gBAAgB;EAClD,MAAM,QAAQ,QAAQ,MAAM;AAC5B,MAAI,QAAQ,GACV,QAAO,MAAM,GAAG,OAAO;;AAI3B,QAAO,kBAAkB;;AAG3B,SAAgB,iBAAiB,UAAkB,MAAkC;AACnF,KAAI;EACF,MAAM,MAAM,OAAO,YAAY;AAC/B,MAAI,CAAC,IAAK,QAAO;EAEjB,MAAM,QAAQ,IAAI,MAAM;EACxB,MAAMA,cAAwB;AAG9B,OAAK,MAAM,QAAQ,OAAO;AACxB,OAAI,KAAK,WAAW,GAAI;AAGxB,OAAI,MAAM,KAAK,SAAS,YAAY,SAAS,GAAG;AAC9C,gBAAY,YAAY,SAAS,MAAM,IAAI,KAAK;AAChD;;AAGF,eAAY,KAAK;;EAGnB,MAAM,aAAa,KAAK;AACxB,MAAI,CAAC,WAAY,QAAO;EAExB,MAAM,KAAK,IAAI,OAAO,IAAI,WAAW,QAAQ,uBAAuB,QAAQ,QAAQ;EACpF,MAAM,QAAQ,YAAY,MAAM,MAAM,GAAG,KAAK;AAC9C,MAAI,CAAC,MAAO,QAAO;EAEnB,MAAM,MAAM,MAAM,QAAQ;EAC1B,MAAM,QAAQ,OAAO,IAAI,MAAM,MAAM,MAAM,GAAG,SAAS;AACvD,SAAO,SAAS;SACV;AACN,SAAO;;;AAIX,SAAgB,4BACd,UACuE;CAEvE,IAAI,eAAe,iBAAiB,UAAU,cAAc,OAAO,YAAY,KAAK;AACpF,KAAI,CAAC,YAAa,QAAO;AAGzB,eAAc,YAAY,QAAQ,kBAAkB,IAAI;AACxD,KAAI,CAAC,YAAa,QAAO;CAIzB,MAAM,QAAQ,YAAY,MACxB;AAEF,KAAI,CAAC,MAAO,QAAO;CAEnB,MAAM,GAAG,WAAW,WAAW,gBAAgB;AAC/C,QAAO;EAAE;EAAW;EAAW"}
@@ -16,7 +16,7 @@ const require_testHelpers = require('./testHelpers.js');
16
16
  * - Encrypting raw RFC822 emails with encryptEmailForOutlayer, binding an AEAD context
17
17
  * `{ account_id, network_id, payer_account_id }`,
18
18
  * - Calling the per-account EmailRecoverer contract with:
19
- * - `verify_encrypted_email_and_recover(encrypted_email_blob, aead_context)` for DKIM/TEE,
19
+ * - `verify_encrypted_email_and_recover(encrypted_email_blob, aead_context, expected_hashed_email, expected_new_public_key)` for DKIM/TEE,
20
20
  * - `verify_zkemail_and_recover` for zk-email recovery,
21
21
  * - Performing legacy plaintext on-chain verification via `verify_email_onchain_and_recover`
22
22
  * for backwards compatibility only.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["normalizeLogger","e: unknown","mapZkEmailRecoveryError","ZkEmailProverClient","getOutlayerEncryptionPublicKey","normalizeRecoveryMode","extractRecoveryModeFromBody","e: any","buildEncryptedEmailRecoveryActions","encryptEmailForOutlayer","sendEmailRecoveryTransaction","buildOnchainEmailRecoveryActions","prepareZkEmailRecovery","generateZkEmailProofFromPayload","buildZkEmailRecoveryActions","error: any"],"sources":["../../../../src/server/email-recovery/index.ts"],"sourcesContent":["import type { ActionArgsWasm } from '../../core/types/actions';\nimport { ActionType, validateActionArgsWasm } from '../../core/types/actions';\nimport { parseContractExecutionError } from '../core/errors';\nimport { generateZkEmailProofFromPayload, type ZkEmailProverClientOptions } from './zkEmail';\nimport { extractRecoveryModeFromBody, normalizeRecoveryMode } from './emailParsers';\nimport { encryptEmailForOutlayer } from './emailEncryptor';\nimport { buildEncryptedEmailRecoveryActions, buildOnchainEmailRecoveryActions, buildZkEmailRecoveryActions, sendEmailRecoveryTransaction, getOutlayerEncryptionPublicKey } from './rpcCalls';\nimport { ZkEmailProverClient } from './zkEmail/proverClient';\nimport { mapZkEmailRecoveryError, prepareZkEmailRecovery } from './zkEmail/recovery';\nimport { normalizeLogger, type NormalizedLogger } from '../core/logger';\nimport type {\n EmailRecoveryDispatchRequest,\n EmailRecoveryMode,\n EmailRecoveryRequest,\n EmailRecoveryResult,\n EmailRecoveryServiceDeps,\n} from './types';\n\nexport * from './emailEncryptor';\nexport * from './zkEmail';\nexport * from './zkEmail/recovery';\nexport * from './testHelpers';\nexport * from './types';\n\n/**\n * EmailRecoveryService encapsulates email recovery logic for the relayer.\n *\n * It currently orchestrates:\n * - Fetching and caching the Outlayer X25519 public key from the global EmailDKIMVerifier,\n * - Encrypting raw RFC822 emails with encryptEmailForOutlayer, binding an AEAD context\n * `{ account_id, network_id, payer_account_id }`,\n * - Calling the per-account EmailRecoverer contract with:\n * - `verify_encrypted_email_and_recover(encrypted_email_blob, aead_context)` for DKIM/TEE,\n * - `verify_zkemail_and_recover` for zk-email recovery,\n * - Performing legacy plaintext on-chain verification via `verify_email_onchain_and_recover`\n * for backwards compatibility only.\n */\nexport class EmailRecoveryService {\n private readonly deps: EmailRecoveryServiceDeps;\n private readonly logger: NormalizedLogger;\n private cachedOutlayerPk: Uint8Array | null = null;\n private zkEmailProverClient: ZkEmailProverClient | null = null;\n private zkEmailProverClientKey: string | null = null;\n\n constructor(deps: EmailRecoveryServiceDeps) {\n this.deps = deps;\n this.logger = normalizeLogger(deps.logger);\n }\n\n /**\n * Lightweight view of zk-email prover wiring for health/readiness endpoints.\n * This does not perform any network calls.\n */\n getZkEmailProverBaseUrl(): string | null {\n const baseUrl = String(this.deps.zkEmailProver?.baseUrl || '').trim().replace(/\\/+$/, '');\n return baseUrl ? baseUrl : null;\n }\n\n /**\n * Readiness check for zk-email prover.\n *\n * Returns `healthy: null` when zk-email prover is not configured.\n * Does not log; callers (routers) may decide how/when to log.\n */\n async checkZkEmailProverHealth(): Promise<{\n configured: boolean;\n baseUrl: string | null;\n healthy: boolean | null;\n errorCode?: string;\n message?: string;\n proverCauseCode?: string;\n proverCauseMessage?: string;\n }> {\n const baseUrl = this.getZkEmailProverBaseUrl();\n const opts = this.deps.zkEmailProver;\n if (!baseUrl || !opts) {\n return { configured: false, baseUrl: null, healthy: null };\n }\n\n try {\n const client = this.getZkEmailProverClient({ ...opts, baseUrl });\n await client.healthz();\n return { configured: true, baseUrl, healthy: true };\n } catch (e: unknown) {\n const mapped = mapZkEmailRecoveryError(e);\n return {\n configured: true,\n baseUrl,\n healthy: false,\n errorCode: mapped.errorCode,\n message: mapped.message,\n proverCauseCode: mapped.proverCauseCode,\n proverCauseMessage: mapped.proverCauseMessage,\n };\n }\n }\n\n private getZkEmailProverClient(opts: ZkEmailProverClientOptions): ZkEmailProverClient {\n const baseUrl = String(opts.baseUrl || '').replace(/\\/+$/, '');\n const timeoutMs = opts.timeoutMs ?? 60_000;\n const healthCheck = opts.healthCheck;\n const key = `${baseUrl}|${timeoutMs}|${healthCheck?.enabled ?? 'default'}|${healthCheck?.ttlMs ?? 'default'}|${healthCheck?.timeoutMs ?? 'default'}`;\n\n if (this.zkEmailProverClient && this.zkEmailProverClientKey === key) {\n return this.zkEmailProverClient;\n }\n\n const client = new ZkEmailProverClient(opts);\n this.zkEmailProverClient = client;\n this.zkEmailProverClientKey = key;\n return client;\n }\n\n private async getOutlayerEmailDkimPublicKey(): Promise<Uint8Array> {\n if (this.cachedOutlayerPk) {\n return this.cachedOutlayerPk;\n }\n const pk = await getOutlayerEncryptionPublicKey(this.deps);\n this.cachedOutlayerPk = pk;\n return pk;\n }\n\n /**\n * Determine recovery mode (zk-email | encrypted | onchain-public) from:\n * - explicit override (for programmatic callers),\n * - body markers inside the raw email,\n * falling back to tee-private for backwards compatibility.\n */\n private determineRecoveryMode(input: {\n explicitMode?: string;\n emailBlob?: string;\n }): EmailRecoveryMode {\n return (\n normalizeRecoveryMode(input.explicitMode) ??\n extractRecoveryModeFromBody(input.emailBlob) ??\n 'tee-encrypted'\n );\n }\n\n /**\n * Top-level dispatcher for email recovery modes.\n *\n * Usage from HTTP routes:\n * - Pass the full raw RFC822 email as `emailBlob` (including headers + body).\n * - Optionally include an explicit `explicitMode` override (`'zk-email' | 'tee-encrypted' | 'onchain-public'`).\n * - Otherwise, the first non-empty body line is parsed as a mode hint:\n * - `\"zk-email\"` → zk-email prover + per-account `verify_zkemail_and_recover`.\n * - `\"tee-encrypted\"` (or legacy `\"encrypted\"`) → per-account EmailRecoverer encrypted path (`verify_encrypted_email_and_recover`).\n * - `\"onchain-public\"` → currently routed to the same per-account encrypted path for backwards compatibility.\n * - If no hint is found, the mode defaults to `'tee-encrypted'`.\n */\n async requestEmailRecovery(request: EmailRecoveryDispatchRequest): Promise<EmailRecoveryResult> {\n const mode = this.determineRecoveryMode({\n explicitMode: request.explicitMode,\n emailBlob: request.emailBlob,\n });\n this.logger.debug('[email-recovery] requestEmailRecovery mode selected', {\n mode,\n accountId: request.accountId,\n });\n\n switch (mode) {\n case 'tee-encrypted':\n return this.verifyEncryptedEmailAndRecover({\n accountId: request.accountId,\n emailBlob: request.emailBlob,\n });\n case 'zk-email':\n return this.verifyZkemailAndRecover({\n accountId: request.accountId,\n emailBlob: request.emailBlob,\n });\n case 'onchain-public':\n // Use the same encrypted/TEE path via per-account EmailRecoverer.\n return this.verifyEncryptedEmailAndRecover({\n accountId: request.accountId,\n emailBlob: request.emailBlob,\n });\n default:\n // Fallback to the TEE-encrypted path for forwards compatibility.\n return this.verifyEncryptedEmailAndRecover({\n accountId: request.accountId,\n emailBlob: request.emailBlob,\n });\n }\n }\n\n /**\n * Helper for encrypted DKIM-based email recovery:\n * - Encrypts the raw email blob for the Outlayer worker.\n * - Calls the per-account EmailRecoverer contract's\n * `verify_encrypted_email_and_recover` entrypoint on the user's account.\n *\n * The per-account EmailRecoverer then delegates to the global\n * EmailDKIMVerifier (TEE path), which stores a VerificationResult keyed by\n * request_id. The frontend polls EmailDKIMVerifier::get_verification_result(request_id)\n * to observe success/failure.\n */\n\t async verifyEncryptedEmailAndRecover(request: EmailRecoveryRequest): Promise<EmailRecoveryResult> {\n\t const accountId = (request.accountId || '').trim();\n\t const emailBlob = request.emailBlob;\n\n\t if (!accountId) {\n\t const errMsg = 'accountId is required';\n\t return { success: false, error: errMsg, message: errMsg };\n\t }\n\t if (!emailBlob || typeof emailBlob !== 'string') {\n\t const errMsg = 'emailBlob (raw email) is required';\n\t return { success: false, error: errMsg, message: errMsg };\n\t }\n\n\t const { ensureSignerAndRelayerAccount } = this.deps;\n\n\t try {\n\t await ensureSignerAndRelayerAccount();\n\t } catch (e: any) {\n\t const msg = e?.message || 'Failed to initialize relayer account';\n\t return { success: false, error: msg, message: msg };\n\t }\n\n\t\t const recipientPk = await this.getOutlayerEmailDkimPublicKey();\n\t\t this.logger.debug('[email-recovery] encrypted using Outlayer public key', {\n\t\t accountId,\n\t\t outlayerPkLen: recipientPk.length,\n\t\t });\n\n\t const { actions, receiverId } = await buildEncryptedEmailRecoveryActions(this.deps, {\n\t accountId,\n\t emailBlob,\n\t recipientPk,\n\t encrypt: async ({ emailRaw, aeadContext, recipientPk: pk }) => {\n\t const { envelope } = await encryptEmailForOutlayer({\n\t emailRaw,\n\t aeadContext,\n\t recipientPk: pk,\n\t });\n\n\t\t this.logger.debug('[email-recovery] encrypted email envelope metadata', {\n\t\t accountId,\n\t\t aeadContextLen: aeadContext.length,\n\t\t envelope: {\n\t\t version: envelope.version,\n\t\t ephemeral_pub_len: envelope.ephemeral_pub?.length ?? 0,\n\t\t nonce_len: envelope.nonce?.length ?? 0,\n\t\t ciphertext_len: envelope.ciphertext?.length ?? 0,\n\t\t },\n\t\t });\n\n\t return { envelope };\n\t },\n\t });\n\n\t return sendEmailRecoveryTransaction(this.deps, {\n\t receiverId,\n\t actions,\n\t label: `Encrypted email verification requested for ${accountId}`,\n\t });\n\t }\n\n /**\n * Legacy helper for plaintext/on-chain DKIM email verification + account recovery.\n * This path is deprecated in favor of the encrypted TEE path via\n * `verifyEncryptedEmailAndRecover` and is no longer used by\n * `requestEmailRecovery`.\n */\n\t async verifyEmailOnchainAndRecover(request: EmailRecoveryRequest): Promise<EmailRecoveryResult> {\n const accountId = (request.accountId || '').trim();\n const emailBlob = request.emailBlob;\n\n if (!accountId) {\n let errMsg = 'accountId is required';\n return { success: false, error: errMsg, message: errMsg };\n }\n if (!emailBlob || typeof emailBlob !== 'string') {\n let errMsg = 'emailBlob (raw email) is required';\n return { success: false, error: errMsg, message: errMsg };\n }\n\n\t const { ensureSignerAndRelayerAccount } = this.deps;\n\n try {\n await ensureSignerAndRelayerAccount();\n } catch (e: any) {\n const msg = e?.message || 'Failed to initialize relayer account';\n return { success: false, error: msg, message: msg };\n }\n\n\t const { actions, receiverId } = await buildOnchainEmailRecoveryActions(this.deps, {\n\t accountId,\n\t emailBlob,\n\t });\n\n\t return sendEmailRecoveryTransaction(this.deps, {\n\t receiverId,\n\t actions,\n\t label: `On-chain email verification requested for ${accountId}`,\n\t });\n }\n\n /**\n * Helper for zk-email recovery:\n * - Calls external zk-email prover with the raw email blob to obtain (proof, publicInputs).\n * - Extracts subject/header bindings (account_id, new_public_key, from_email, timestamp).\n * - Calls the per-account EmailRecoverer contract with verify_zkemail_and_recover.\n */\n\t async verifyZkemailAndRecover(request: EmailRecoveryRequest): Promise<EmailRecoveryResult> {\n\t const accountId = (request.accountId || '').trim();\n\t const emailBlob = request.emailBlob;\n\n if (!accountId) {\n return {\n success: false,\n error: 'zkemail_missing_account_id',\n message: 'accountId is required',\n };\n }\n if (!emailBlob || typeof emailBlob !== 'string') {\n return {\n success: false,\n error: 'zkemail_missing_email_blob',\n message: 'emailBlob (raw email) is required',\n };\n }\n\n\t const { ensureSignerAndRelayerAccount, zkEmailProver } = this.deps;\n\n if (!zkEmailProver || !zkEmailProver.baseUrl) {\n this.logger.warn('[email-recovery] zk-email missing prover configuration', { accountId });\n return {\n success: false,\n error: 'zkemail_prover_not_configured',\n message: 'zk-email prover configuration is missing',\n };\n }\n\n const prepared = prepareZkEmailRecovery(emailBlob, accountId);\n if (!prepared.ok) {\n const log = {\n accountId,\n requestId: prepared.requestId,\n proverBaseUrl: zkEmailProver.baseUrl,\n errorCode: prepared.errorCode,\n errorMessage: prepared.message,\n accountIdSubject: prepared.subjectAccountId,\n };\n if (prepared.errorCode === 'zkemail_account_mismatch') {\n this.logger.warn('[email-recovery] zk-email account mismatch', log);\n } else {\n this.logger.warn('[email-recovery] zk-email recovery rejected', log);\n }\n return { success: false, error: prepared.errorCode, message: prepared.message };\n }\n\n const { payload, bindings } = prepared.prepared;\n\n try {\n await ensureSignerAndRelayerAccount();\n } catch (e: any) {\n const msg = e?.message || 'Failed to initialize relayer account';\n this.logger.error('[email-recovery] zk-email ensureSignerAndRelayerAccount failed', {\n accountId,\n requestId: bindings.requestId,\n error: msg,\n });\n return { success: false, error: 'zkemail_relayer_init_failed', message: msg };\n }\n\n\t try {\n\t const proverClient = this.getZkEmailProverClient(zkEmailProver);\n\t const proofResult = await generateZkEmailProofFromPayload(payload, proverClient);\n\n\t const contractArgs = {\n\t proof: proofResult.proof,\n\t public_inputs: proofResult.publicInputs,\n\t account_id: bindings.accountId,\n\t new_public_key: bindings.newPublicKey,\n\t from_email: bindings.fromEmail,\n\t timestamp: bindings.timestamp,\n\t };\n\n\t const { actions, receiverId } = await buildZkEmailRecoveryActions(this.deps, {\n\t accountId,\n\t contractArgs,\n\t });\n\n\t return sendEmailRecoveryTransaction(this.deps, {\n\t receiverId,\n\t actions,\n\t label: `ZK-email recovery requested for ${accountId}`,\n\t });\n\t\t } catch (error: any) {\n const mapped = mapZkEmailRecoveryError(error);\n\n\t\t this.logger.error('[email-recovery] zk-email recovery error', {\n\t\t accountId,\n\t requestId: bindings.requestId,\n\t\t errorCode: mapped.errorCode,\n\t\t errorMessage: mapped.message,\n\t proverBaseUrl: zkEmailProver.baseUrl,\n\t proverCauseCode: mapped.proverCauseCode,\n\t proverCauseMessage: mapped.proverCauseMessage,\n\t\t });\n\n\t return {\n\t success: false,\n\t error: mapped.errorCode,\n\t message: mapped.message,\n\t };\n\t }\n\t }\n\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["normalizeLogger","e: unknown","mapZkEmailRecoveryError","ZkEmailProverClient","getOutlayerEncryptionPublicKey","normalizeRecoveryMode","extractRecoveryModeFromBody","e: any","buildEncryptedEmailRecoveryActions","encryptEmailForOutlayer","sendEmailRecoveryTransaction","buildOnchainEmailRecoveryActions","prepareZkEmailRecovery","generateZkEmailProofFromPayload","buildZkEmailRecoveryActions","error: any"],"sources":["../../../../src/server/email-recovery/index.ts"],"sourcesContent":["import type { ActionArgsWasm } from '../../core/types/actions';\nimport { ActionType, validateActionArgsWasm } from '../../core/types/actions';\nimport { parseContractExecutionError } from '../core/errors';\nimport { generateZkEmailProofFromPayload, type ZkEmailProverClientOptions } from './zkEmail';\nimport { extractRecoveryModeFromBody, normalizeRecoveryMode } from './emailParsers';\nimport { encryptEmailForOutlayer } from './emailEncryptor';\nimport { buildEncryptedEmailRecoveryActions, buildOnchainEmailRecoveryActions, buildZkEmailRecoveryActions, sendEmailRecoveryTransaction, getOutlayerEncryptionPublicKey } from './rpcCalls';\nimport { ZkEmailProverClient } from './zkEmail/proverClient';\nimport { mapZkEmailRecoveryError, prepareZkEmailRecovery } from './zkEmail/recovery';\nimport { normalizeLogger, type NormalizedLogger } from '../core/logger';\nimport type {\n EmailRecoveryDispatchRequest,\n EmailRecoveryMode,\n EmailRecoveryRequest,\n EmailRecoveryResult,\n EmailRecoveryServiceDeps,\n} from './types';\n\nexport * from './emailEncryptor';\nexport * from './zkEmail';\nexport * from './zkEmail/recovery';\nexport * from './testHelpers';\nexport * from './types';\n\n/**\n * EmailRecoveryService encapsulates email recovery logic for the relayer.\n *\n * It currently orchestrates:\n * - Fetching and caching the Outlayer X25519 public key from the global EmailDKIMVerifier,\n * - Encrypting raw RFC822 emails with encryptEmailForOutlayer, binding an AEAD context\n * `{ account_id, network_id, payer_account_id }`,\n * - Calling the per-account EmailRecoverer contract with:\n * - `verify_encrypted_email_and_recover(encrypted_email_blob, aead_context, expected_hashed_email, expected_new_public_key)` for DKIM/TEE,\n * - `verify_zkemail_and_recover` for zk-email recovery,\n * - Performing legacy plaintext on-chain verification via `verify_email_onchain_and_recover`\n * for backwards compatibility only.\n */\nexport class EmailRecoveryService {\n private readonly deps: EmailRecoveryServiceDeps;\n private readonly logger: NormalizedLogger;\n private cachedOutlayerPk: Uint8Array | null = null;\n private zkEmailProverClient: ZkEmailProverClient | null = null;\n private zkEmailProverClientKey: string | null = null;\n\n constructor(deps: EmailRecoveryServiceDeps) {\n this.deps = deps;\n this.logger = normalizeLogger(deps.logger);\n }\n\n /**\n * Lightweight view of zk-email prover wiring for health/readiness endpoints.\n * This does not perform any network calls.\n */\n getZkEmailProverBaseUrl(): string | null {\n const baseUrl = String(this.deps.zkEmailProver?.baseUrl || '').trim().replace(/\\/+$/, '');\n return baseUrl ? baseUrl : null;\n }\n\n /**\n * Readiness check for zk-email prover.\n *\n * Returns `healthy: null` when zk-email prover is not configured.\n * Does not log; callers (routers) may decide how/when to log.\n */\n async checkZkEmailProverHealth(): Promise<{\n configured: boolean;\n baseUrl: string | null;\n healthy: boolean | null;\n errorCode?: string;\n message?: string;\n proverCauseCode?: string;\n proverCauseMessage?: string;\n }> {\n const baseUrl = this.getZkEmailProverBaseUrl();\n const opts = this.deps.zkEmailProver;\n if (!baseUrl || !opts) {\n return { configured: false, baseUrl: null, healthy: null };\n }\n\n try {\n const client = this.getZkEmailProverClient({ ...opts, baseUrl });\n await client.healthz();\n return { configured: true, baseUrl, healthy: true };\n } catch (e: unknown) {\n const mapped = mapZkEmailRecoveryError(e);\n return {\n configured: true,\n baseUrl,\n healthy: false,\n errorCode: mapped.errorCode,\n message: mapped.message,\n proverCauseCode: mapped.proverCauseCode,\n proverCauseMessage: mapped.proverCauseMessage,\n };\n }\n }\n\n private getZkEmailProverClient(opts: ZkEmailProverClientOptions): ZkEmailProverClient {\n const baseUrl = String(opts.baseUrl || '').replace(/\\/+$/, '');\n const timeoutMs = opts.timeoutMs ?? 60_000;\n const healthCheck = opts.healthCheck;\n const key = `${baseUrl}|${timeoutMs}|${healthCheck?.enabled ?? 'default'}|${healthCheck?.ttlMs ?? 'default'}|${healthCheck?.timeoutMs ?? 'default'}`;\n\n if (this.zkEmailProverClient && this.zkEmailProverClientKey === key) {\n return this.zkEmailProverClient;\n }\n\n const client = new ZkEmailProverClient(opts);\n this.zkEmailProverClient = client;\n this.zkEmailProverClientKey = key;\n return client;\n }\n\n private async getOutlayerEmailDkimPublicKey(): Promise<Uint8Array> {\n if (this.cachedOutlayerPk) {\n return this.cachedOutlayerPk;\n }\n const pk = await getOutlayerEncryptionPublicKey(this.deps);\n this.cachedOutlayerPk = pk;\n return pk;\n }\n\n /**\n * Determine recovery mode (zk-email | encrypted | onchain-public) from:\n * - explicit override (for programmatic callers),\n * - body markers inside the raw email,\n * falling back to tee-private for backwards compatibility.\n */\n private determineRecoveryMode(input: {\n explicitMode?: string;\n emailBlob?: string;\n }): EmailRecoveryMode {\n return (\n normalizeRecoveryMode(input.explicitMode) ??\n extractRecoveryModeFromBody(input.emailBlob) ??\n 'tee-encrypted'\n );\n }\n\n /**\n * Top-level dispatcher for email recovery modes.\n *\n * Usage from HTTP routes:\n * - Pass the full raw RFC822 email as `emailBlob` (including headers + body).\n * - Optionally include an explicit `explicitMode` override (`'zk-email' | 'tee-encrypted' | 'onchain-public'`).\n * - Otherwise, the first non-empty body line is parsed as a mode hint:\n * - `\"zk-email\"` → zk-email prover + per-account `verify_zkemail_and_recover`.\n * - `\"tee-encrypted\"` (or legacy `\"encrypted\"`) → per-account EmailRecoverer encrypted path (`verify_encrypted_email_and_recover`).\n * - `\"onchain-public\"` → currently routed to the same per-account encrypted path for backwards compatibility.\n * - If no hint is found, the mode defaults to `'tee-encrypted'`.\n */\n async requestEmailRecovery(request: EmailRecoveryDispatchRequest): Promise<EmailRecoveryResult> {\n const mode = this.determineRecoveryMode({\n explicitMode: request.explicitMode,\n emailBlob: request.emailBlob,\n });\n this.logger.debug('[email-recovery] requestEmailRecovery mode selected', {\n mode,\n accountId: request.accountId,\n });\n\n switch (mode) {\n case 'tee-encrypted':\n return this.verifyEncryptedEmailAndRecover({\n accountId: request.accountId,\n emailBlob: request.emailBlob,\n });\n case 'zk-email':\n return this.verifyZkemailAndRecover({\n accountId: request.accountId,\n emailBlob: request.emailBlob,\n });\n case 'onchain-public':\n // Use the same encrypted/TEE path via per-account EmailRecoverer.\n return this.verifyEncryptedEmailAndRecover({\n accountId: request.accountId,\n emailBlob: request.emailBlob,\n });\n default:\n // Fallback to the TEE-encrypted path for forwards compatibility.\n return this.verifyEncryptedEmailAndRecover({\n accountId: request.accountId,\n emailBlob: request.emailBlob,\n });\n }\n }\n\n /**\n * Helper for encrypted DKIM-based email recovery:\n * - Encrypts the raw email blob for the Outlayer worker.\n * - Calls the per-account EmailRecoverer contract's\n * `verify_encrypted_email_and_recover` entrypoint on the user's account.\n *\n * The per-account EmailRecoverer then delegates to the global\n * EmailDKIMVerifier (TEE path), which stores a VerificationResult keyed by\n * request_id. The frontend polls EmailDKIMVerifier::get_verification_result(request_id)\n * to observe success/failure.\n */\n\t async verifyEncryptedEmailAndRecover(request: EmailRecoveryRequest): Promise<EmailRecoveryResult> {\n\t const accountId = (request.accountId || '').trim();\n\t const emailBlob = request.emailBlob;\n\n\t if (!accountId) {\n\t const errMsg = 'accountId is required';\n\t return { success: false, error: errMsg, message: errMsg };\n\t }\n\t if (!emailBlob || typeof emailBlob !== 'string') {\n\t const errMsg = 'emailBlob (raw email) is required';\n\t return { success: false, error: errMsg, message: errMsg };\n\t }\n\n\t const { ensureSignerAndRelayerAccount } = this.deps;\n\n\t try {\n\t await ensureSignerAndRelayerAccount();\n\t } catch (e: any) {\n\t const msg = e?.message || 'Failed to initialize relayer account';\n\t return { success: false, error: msg, message: msg };\n\t }\n\n\t\t const recipientPk = await this.getOutlayerEmailDkimPublicKey();\n\t\t this.logger.debug('[email-recovery] encrypted using Outlayer public key', {\n\t\t accountId,\n\t\t outlayerPkLen: recipientPk.length,\n\t\t });\n\n\t const { actions, receiverId } = await buildEncryptedEmailRecoveryActions(this.deps, {\n\t accountId,\n\t emailBlob,\n\t recipientPk,\n\t encrypt: async ({ emailRaw, aeadContext, recipientPk: pk }) => {\n\t const { envelope } = await encryptEmailForOutlayer({\n\t emailRaw,\n\t aeadContext,\n\t recipientPk: pk,\n\t });\n\n\t\t this.logger.debug('[email-recovery] encrypted email envelope metadata', {\n\t\t accountId,\n\t\t aeadContextLen: aeadContext.length,\n\t\t envelope: {\n\t\t version: envelope.version,\n\t\t ephemeral_pub_len: envelope.ephemeral_pub?.length ?? 0,\n\t\t nonce_len: envelope.nonce?.length ?? 0,\n\t\t ciphertext_len: envelope.ciphertext?.length ?? 0,\n\t\t },\n\t\t });\n\n\t return { envelope };\n\t },\n\t });\n\n\t return sendEmailRecoveryTransaction(this.deps, {\n\t receiverId,\n\t actions,\n\t label: `Encrypted email verification requested for ${accountId}`,\n\t });\n\t }\n\n /**\n * Legacy helper for plaintext/on-chain DKIM email verification + account recovery.\n * This path is deprecated in favor of the encrypted TEE path via\n * `verifyEncryptedEmailAndRecover` and is no longer used by\n * `requestEmailRecovery`.\n */\n\t async verifyEmailOnchainAndRecover(request: EmailRecoveryRequest): Promise<EmailRecoveryResult> {\n const accountId = (request.accountId || '').trim();\n const emailBlob = request.emailBlob;\n\n if (!accountId) {\n let errMsg = 'accountId is required';\n return { success: false, error: errMsg, message: errMsg };\n }\n if (!emailBlob || typeof emailBlob !== 'string') {\n let errMsg = 'emailBlob (raw email) is required';\n return { success: false, error: errMsg, message: errMsg };\n }\n\n\t const { ensureSignerAndRelayerAccount } = this.deps;\n\n try {\n await ensureSignerAndRelayerAccount();\n } catch (e: any) {\n const msg = e?.message || 'Failed to initialize relayer account';\n return { success: false, error: msg, message: msg };\n }\n\n\t const { actions, receiverId } = await buildOnchainEmailRecoveryActions(this.deps, {\n\t accountId,\n\t emailBlob,\n\t });\n\n\t return sendEmailRecoveryTransaction(this.deps, {\n\t receiverId,\n\t actions,\n\t label: `On-chain email verification requested for ${accountId}`,\n\t });\n }\n\n /**\n * Helper for zk-email recovery:\n * - Calls external zk-email prover with the raw email blob to obtain (proof, publicInputs).\n * - Extracts subject/header bindings (account_id, new_public_key, from_email, timestamp).\n * - Calls the per-account EmailRecoverer contract with verify_zkemail_and_recover.\n */\n\t async verifyZkemailAndRecover(request: EmailRecoveryRequest): Promise<EmailRecoveryResult> {\n\t const accountId = (request.accountId || '').trim();\n\t const emailBlob = request.emailBlob;\n\n if (!accountId) {\n return {\n success: false,\n error: 'zkemail_missing_account_id',\n message: 'accountId is required',\n };\n }\n if (!emailBlob || typeof emailBlob !== 'string') {\n return {\n success: false,\n error: 'zkemail_missing_email_blob',\n message: 'emailBlob (raw email) is required',\n };\n }\n\n\t const { ensureSignerAndRelayerAccount, zkEmailProver } = this.deps;\n\n if (!zkEmailProver || !zkEmailProver.baseUrl) {\n this.logger.warn('[email-recovery] zk-email missing prover configuration', { accountId });\n return {\n success: false,\n error: 'zkemail_prover_not_configured',\n message: 'zk-email prover configuration is missing',\n };\n }\n\n const prepared = prepareZkEmailRecovery(emailBlob, accountId);\n if (!prepared.ok) {\n const log = {\n accountId,\n requestId: prepared.requestId,\n proverBaseUrl: zkEmailProver.baseUrl,\n errorCode: prepared.errorCode,\n errorMessage: prepared.message,\n accountIdSubject: prepared.subjectAccountId,\n };\n if (prepared.errorCode === 'zkemail_account_mismatch') {\n this.logger.warn('[email-recovery] zk-email account mismatch', log);\n } else {\n this.logger.warn('[email-recovery] zk-email recovery rejected', log);\n }\n return { success: false, error: prepared.errorCode, message: prepared.message };\n }\n\n const { payload, bindings } = prepared.prepared;\n\n try {\n await ensureSignerAndRelayerAccount();\n } catch (e: any) {\n const msg = e?.message || 'Failed to initialize relayer account';\n this.logger.error('[email-recovery] zk-email ensureSignerAndRelayerAccount failed', {\n accountId,\n requestId: bindings.requestId,\n error: msg,\n });\n return { success: false, error: 'zkemail_relayer_init_failed', message: msg };\n }\n\n\t try {\n\t const proverClient = this.getZkEmailProverClient(zkEmailProver);\n\t const proofResult = await generateZkEmailProofFromPayload(payload, proverClient);\n\n\t const contractArgs = {\n\t proof: proofResult.proof,\n\t public_inputs: proofResult.publicInputs,\n\t account_id: bindings.accountId,\n\t new_public_key: bindings.newPublicKey,\n\t from_email: bindings.fromEmail,\n\t timestamp: bindings.timestamp,\n\t };\n\n\t const { actions, receiverId } = await buildZkEmailRecoveryActions(this.deps, {\n\t accountId,\n\t contractArgs,\n\t });\n\n\t return sendEmailRecoveryTransaction(this.deps, {\n\t receiverId,\n\t actions,\n\t label: `ZK-email recovery requested for ${accountId}`,\n\t });\n\t\t } catch (error: any) {\n const mapped = mapZkEmailRecoveryError(error);\n\n\t\t this.logger.error('[email-recovery] zk-email recovery error', {\n\t\t accountId,\n\t requestId: bindings.requestId,\n\t\t errorCode: mapped.errorCode,\n\t\t errorMessage: mapped.message,\n\t proverBaseUrl: zkEmailProver.baseUrl,\n\t proverCauseCode: mapped.proverCauseCode,\n\t proverCauseMessage: mapped.proverCauseMessage,\n\t\t });\n\n\t return {\n\t success: false,\n\t error: mapped.errorCode,\n\t message: mapped.message,\n\t };\n\t }\n\t }\n\n}\n"],"mappings":"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"}
@@ -1,5 +1,7 @@
1
1
  const require_actions = require('../sdk/src/core/types/actions.js');
2
2
  const require_errors = require('../core/errors.js');
3
+ const require_emailParsers = require('./emailParsers.js');
4
+ const require_emailEncryptor = require('./emailEncryptor.js');
3
5
 
4
6
  //#region src/server/email-recovery/rpcCalls.ts
5
7
  async function getOutlayerEncryptionPublicKey(deps) {
@@ -33,9 +35,20 @@ async function buildEncryptedEmailRecoveryActions(deps, input) {
33
35
  aeadContext,
34
36
  recipientPk
35
37
  });
38
+ const bindings = require_emailParsers.parseRecoverSubjectBindings(emailBlob);
39
+ if (!bindings) throw new Error("Encrypted email recovery requires Subject: recover-<request_id> <accountId> ed25519:<new_public_key>");
40
+ if (bindings.accountId !== accountId) throw new Error(`Encrypted email recovery subject accountId mismatch (expected "${accountId}", got "${bindings.accountId}")`);
41
+ const fromHeader = require_emailParsers.parseHeaderValue(emailBlob, "from");
42
+ if (!fromHeader) throw new Error("Encrypted email recovery requires a From: header");
43
+ const expectedHashedEmail = require_emailEncryptor.hashRecoveryEmailForAccount({
44
+ recoveryEmail: fromHeader,
45
+ accountId
46
+ });
36
47
  const contractArgs = {
37
48
  encrypted_email_blob: envelope,
38
- aead_context: aeadContext
49
+ aead_context: aeadContext,
50
+ expected_hashed_email: expectedHashedEmail,
51
+ expected_new_public_key: bindings.newPublicKey
39
52
  };
40
53
  const actions = [{
41
54
  action_type: require_actions.ActionType.FunctionCall,