@tatchi-xyz/sdk 0.31.0 → 0.32.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 (197) hide show
  1. package/README.md +2 -0
  2. package/dist/cjs/core/IndexedDBManager/passkeyClientDB.js +2 -2
  3. package/dist/cjs/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  4. package/dist/cjs/core/TatchiPasskey/faucets/createAccountRelayServer.js +9 -8
  5. package/dist/cjs/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  6. package/dist/cjs/core/TatchiPasskey/login.js +1 -1
  7. package/dist/cjs/core/TatchiPasskey/login.js.map +1 -1
  8. package/dist/cjs/core/TatchiPasskey/registration.js +107 -63
  9. package/dist/cjs/core/TatchiPasskey/registration.js.map +1 -1
  10. package/dist/cjs/core/WalletIframe/client/on-events-progress-bus.js +1 -1
  11. package/dist/cjs/core/WalletIframe/client/on-events-progress-bus.js.map +1 -1
  12. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js +1 -10
  13. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js.map +1 -1
  14. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +58 -67
  15. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  16. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +74 -75
  17. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  18. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js +17 -7
  19. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js.map +1 -1
  20. package/dist/cjs/core/WebAuthnManager/index.js +3 -3
  21. package/dist/cjs/core/WebAuthnManager/index.js.map +1 -1
  22. package/dist/cjs/core/defaultConfigs.js +3 -1
  23. package/dist/cjs/core/defaultConfigs.js.map +1 -1
  24. package/dist/cjs/core/types/sdkSentEvents.js +3 -2
  25. package/dist/cjs/core/types/sdkSentEvents.js.map +1 -1
  26. package/dist/cjs/react/components/AccountMenuButton/TransactionSettingsSection.js +3 -3
  27. package/dist/cjs/react/components/AccountMenuButton/TransactionSettingsSection.js.map +1 -1
  28. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-CRlobBrN.css → PasskeyAuthMenu-D2eRb2-S.css} +3 -1
  29. package/dist/cjs/react/components/PasskeyAuthMenu/PasskeyAuthMenu-D2eRb2-S.css.map +1 -0
  30. package/dist/cjs/react/components/PasskeyAuthMenu/preload.js +1 -1
  31. package/dist/cjs/react/components/PasskeyAuthMenu/preload.js.map +1 -1
  32. package/dist/cjs/react/components/PasskeyAuthMenu/shell.js +52 -13
  33. package/dist/cjs/react/components/PasskeyAuthMenu/shell.js.map +1 -1
  34. package/dist/cjs/react/components/PasskeyAuthMenu/skeleton.js +4 -2
  35. package/dist/cjs/react/components/PasskeyAuthMenu/skeleton.js.map +1 -1
  36. package/dist/cjs/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js +5 -1
  37. package/dist/cjs/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js.map +1 -1
  38. package/dist/cjs/react/context/useTatchiWithSdkFlow.js +1 -1
  39. package/dist/cjs/react/context/useTatchiWithSdkFlow.js.map +1 -1
  40. package/dist/cjs/react/index.js +1 -1
  41. package/dist/cjs/react/src/core/IndexedDBManager/passkeyClientDB.js +2 -2
  42. package/dist/cjs/react/src/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  43. package/dist/cjs/react/src/core/TatchiPasskey/faucets/createAccountRelayServer.js +9 -8
  44. package/dist/cjs/react/src/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  45. package/dist/cjs/react/src/core/TatchiPasskey/login.js +1 -1
  46. package/dist/cjs/react/src/core/TatchiPasskey/login.js.map +1 -1
  47. package/dist/cjs/react/src/core/TatchiPasskey/registration.js +107 -63
  48. package/dist/cjs/react/src/core/TatchiPasskey/registration.js.map +1 -1
  49. package/dist/cjs/react/src/core/WalletIframe/client/on-events-progress-bus.js +1 -1
  50. package/dist/cjs/react/src/core/WalletIframe/client/on-events-progress-bus.js.map +1 -1
  51. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js +1 -10
  52. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js.map +1 -1
  53. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +58 -67
  54. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  55. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +74 -75
  56. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  57. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js +17 -7
  58. package/dist/cjs/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js.map +1 -1
  59. package/dist/cjs/react/src/core/WebAuthnManager/index.js +3 -3
  60. package/dist/cjs/react/src/core/WebAuthnManager/index.js.map +1 -1
  61. package/dist/cjs/react/src/core/defaultConfigs.js +3 -1
  62. package/dist/cjs/react/src/core/defaultConfigs.js.map +1 -1
  63. package/dist/cjs/react/src/core/types/sdkSentEvents.js +3 -2
  64. package/dist/cjs/react/src/core/types/sdkSentEvents.js.map +1 -1
  65. package/dist/cjs/server/core/AuthService.js +49 -6
  66. package/dist/cjs/server/core/AuthService.js.map +1 -1
  67. package/dist/cjs/server/sdk/src/core/defaultConfigs.js.map +1 -1
  68. package/dist/esm/core/IndexedDBManager/passkeyClientDB.js +2 -2
  69. package/dist/esm/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  70. package/dist/esm/core/TatchiPasskey/faucets/createAccountRelayServer.js +9 -8
  71. package/dist/esm/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  72. package/dist/esm/core/TatchiPasskey/login.js +1 -1
  73. package/dist/esm/core/TatchiPasskey/login.js.map +1 -1
  74. package/dist/esm/core/TatchiPasskey/registration.js +107 -63
  75. package/dist/esm/core/TatchiPasskey/registration.js.map +1 -1
  76. package/dist/esm/core/WalletIframe/client/on-events-progress-bus.js +1 -1
  77. package/dist/esm/core/WalletIframe/client/on-events-progress-bus.js.map +1 -1
  78. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js +1 -10
  79. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js.map +1 -1
  80. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +58 -67
  81. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  82. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +74 -75
  83. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  84. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js +17 -7
  85. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js.map +1 -1
  86. package/dist/esm/core/WebAuthnManager/index.js +3 -3
  87. package/dist/esm/core/WebAuthnManager/index.js.map +1 -1
  88. package/dist/esm/core/defaultConfigs.js +3 -1
  89. package/dist/esm/core/defaultConfigs.js.map +1 -1
  90. package/dist/esm/core/types/sdkSentEvents.js +3 -2
  91. package/dist/esm/core/types/sdkSentEvents.js.map +1 -1
  92. package/dist/esm/react/components/AccountMenuButton/TransactionSettingsSection.js +3 -3
  93. package/dist/esm/react/components/AccountMenuButton/TransactionSettingsSection.js.map +1 -1
  94. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-D2VHZ04W.css → PasskeyAuthMenu-qTHAv58Z.css} +3 -1
  95. package/dist/esm/react/components/PasskeyAuthMenu/PasskeyAuthMenu-qTHAv58Z.css.map +1 -0
  96. package/dist/esm/react/components/PasskeyAuthMenu/preload.js +1 -1
  97. package/dist/esm/react/components/PasskeyAuthMenu/preload.js.map +1 -1
  98. package/dist/esm/react/components/PasskeyAuthMenu/shell.js +52 -13
  99. package/dist/esm/react/components/PasskeyAuthMenu/shell.js.map +1 -1
  100. package/dist/esm/react/components/PasskeyAuthMenu/skeleton.js +4 -2
  101. package/dist/esm/react/components/PasskeyAuthMenu/skeleton.js.map +1 -1
  102. package/dist/esm/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js +5 -1
  103. package/dist/esm/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.js.map +1 -1
  104. package/dist/esm/react/context/useTatchiWithSdkFlow.js +1 -1
  105. package/dist/esm/react/context/useTatchiWithSdkFlow.js.map +1 -1
  106. package/dist/esm/react/index.js +1 -1
  107. package/dist/esm/react/src/core/IndexedDBManager/passkeyClientDB.js +2 -2
  108. package/dist/esm/react/src/core/IndexedDBManager/passkeyClientDB.js.map +1 -1
  109. package/dist/esm/react/src/core/TatchiPasskey/faucets/createAccountRelayServer.js +9 -8
  110. package/dist/esm/react/src/core/TatchiPasskey/faucets/createAccountRelayServer.js.map +1 -1
  111. package/dist/esm/react/src/core/TatchiPasskey/login.js +1 -1
  112. package/dist/esm/react/src/core/TatchiPasskey/login.js.map +1 -1
  113. package/dist/esm/react/src/core/TatchiPasskey/registration.js +107 -63
  114. package/dist/esm/react/src/core/TatchiPasskey/registration.js.map +1 -1
  115. package/dist/esm/react/src/core/WalletIframe/client/on-events-progress-bus.js +1 -1
  116. package/dist/esm/react/src/core/WalletIframe/client/on-events-progress-bus.js.map +1 -1
  117. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js +1 -10
  118. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.js.map +1 -1
  119. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js +58 -67
  120. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.js.map +1 -1
  121. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js +74 -75
  122. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.js.map +1 -1
  123. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js +17 -7
  124. package/dist/esm/react/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.js.map +1 -1
  125. package/dist/esm/react/src/core/WebAuthnManager/index.js +3 -3
  126. package/dist/esm/react/src/core/WebAuthnManager/index.js.map +1 -1
  127. package/dist/esm/react/src/core/defaultConfigs.js +3 -1
  128. package/dist/esm/react/src/core/defaultConfigs.js.map +1 -1
  129. package/dist/esm/react/src/core/types/sdkSentEvents.js +3 -2
  130. package/dist/esm/react/src/core/types/sdkSentEvents.js.map +1 -1
  131. package/dist/esm/react/styles/styles.css +2 -0
  132. package/dist/esm/sdk/{EmailRecovery-Dl8b4ONg.js → EmailRecovery-Y7rurd4B.js} +3 -3
  133. package/dist/esm/sdk/{EmailRecovery-v9oNO2Tc.js → EmailRecovery-lsjLWApQ.js} +1 -1
  134. package/dist/esm/sdk/{IndexedDBManager-B1cUvdyY.js → IndexedDBManager-CmdN7smS.js} +3 -3
  135. package/dist/esm/sdk/{createAdapters-Dv7ZJPf1.js → createAdapters-4c8mBiD5.js} +2 -11
  136. package/dist/esm/sdk/{createAdapters-Dv7ZJPf1.js.map → createAdapters-4c8mBiD5.js.map} +1 -1
  137. package/dist/esm/sdk/{createAdapters-1Hmc1vVC.js → createAdapters-DF32SIZa.js} +1 -10
  138. package/dist/esm/sdk/{defaultConfigs-BmCU1_qI.js → defaultConfigs-BQqiXif-.js} +3 -1
  139. package/dist/esm/sdk/{delegateAction-DdkvFFKA.js → delegateAction-Bq5zkOvn.js} +1 -1
  140. package/dist/esm/sdk/{emailRecovery-4J-g9tlY.js → emailRecovery-B1hbE_sM.js} +6 -6
  141. package/dist/esm/sdk/{getDeviceNumber-f8bfPB9U.js → getDeviceNumber-WiNzKx1x.js} +4 -2
  142. package/dist/esm/sdk/{getDeviceNumber-f8bfPB9U.js.map → getDeviceNumber-WiNzKx1x.js.map} +1 -1
  143. package/dist/esm/sdk/{linkDevice-C98klpcE.js → linkDevice-CRPf5aW2.js} +5 -5
  144. package/dist/esm/sdk/{localOnly-40zxrBMm.js → localOnly-COpDBMkm.js} +2 -2
  145. package/dist/esm/sdk/{localOnly-40zxrBMm.js.map → localOnly-COpDBMkm.js.map} +1 -1
  146. package/dist/esm/sdk/{localOnly-BZPBj14l.js → localOnly-DQQuqgjJ.js} +1 -1
  147. package/dist/esm/sdk/{login-DnROv3eA.js → login-DUIWZHp_.js} +4 -4
  148. package/dist/esm/sdk/offline-export-app.js +32 -21
  149. package/dist/esm/sdk/offline-export-app.js.map +1 -1
  150. package/dist/esm/sdk/{registration-BP9M3tE1.js → registration-BR2G9tz_.js} +59 -68
  151. package/dist/esm/sdk/{registration-MrAOC8Ub.js → registration-R70lvG_o.js} +60 -69
  152. package/dist/esm/sdk/registration-R70lvG_o.js.map +1 -0
  153. package/dist/esm/sdk/{relay-Dq9D7fhG.js → relay-BCEyWFew.js} +1 -1
  154. package/dist/esm/sdk/{router-BEGGuWaB.js → router-Cj2WexK-.js} +3 -3
  155. package/dist/esm/sdk/{rpcCalls-CMzj_Va_.js → rpcCalls-C1sp-Epo.js} +3 -3
  156. package/dist/esm/sdk/{rpcCalls-B44MZora.js → rpcCalls-VL4loDKP.js} +2 -2
  157. package/dist/esm/sdk/{scanDevice-Cp-r-Z2T.js → scanDevice-C0HcnZym.js} +5 -5
  158. package/dist/esm/sdk/{sdkSentEvents-CzAZBFjP.js → sdkSentEvents-BfkcI7EN.js} +3 -2
  159. package/dist/esm/sdk/{signNEP413-DsyWH_Jo.js → signNEP413-lj0swHsD.js} +1 -1
  160. package/dist/esm/sdk/{syncAccount-CqWCmBVb.js → syncAccount-DnQ9AstS.js} +5 -5
  161. package/dist/esm/sdk/{syncAccount-Dt5jJbEB.js → syncAccount-xh81Vppo.js} +3 -3
  162. package/dist/esm/sdk/{transactions-DAZrPW-6.js → transactions-Cg1TIUyK.js} +76 -77
  163. package/dist/esm/sdk/{transactions-CrjP8yPD.js → transactions-CxsklyCK.js} +77 -78
  164. package/dist/esm/sdk/transactions-CxsklyCK.js.map +1 -0
  165. package/dist/esm/sdk/wallet-iframe-host.js +160 -105
  166. package/dist/esm/server/core/AuthService.js +49 -6
  167. package/dist/esm/server/core/AuthService.js.map +1 -1
  168. package/dist/esm/server/sdk/src/core/defaultConfigs.js.map +1 -1
  169. package/dist/esm/wasm_vrf_worker/pkg/wasm_vrf_worker_bg.wasm +0 -0
  170. package/dist/types/src/__tests__/setup/bootstrap.d.ts.map +1 -1
  171. package/dist/types/src/core/IndexedDBManager/passkeyClientDB.d.ts +1 -1
  172. package/dist/types/src/core/IndexedDBManager/passkeyClientDB.d.ts.map +1 -1
  173. package/dist/types/src/core/TatchiPasskey/faucets/createAccountRelayServer.d.ts +6 -6
  174. package/dist/types/src/core/TatchiPasskey/faucets/createAccountRelayServer.d.ts.map +1 -1
  175. package/dist/types/src/core/TatchiPasskey/registration.d.ts.map +1 -1
  176. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.d.ts +0 -5
  177. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/session.d.ts.map +1 -1
  178. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/registration.d.ts.map +1 -1
  179. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/transactions.d.ts.map +1 -1
  180. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.d.ts.map +1 -1
  181. package/dist/types/src/core/WebAuthnManager/index.d.ts +1 -1
  182. package/dist/types/src/core/WebAuthnManager/index.d.ts.map +1 -1
  183. package/dist/types/src/core/defaultConfigs.d.ts.map +1 -1
  184. package/dist/types/src/core/types/sdkSentEvents.d.ts +18 -7
  185. package/dist/types/src/core/types/sdkSentEvents.d.ts.map +1 -1
  186. package/dist/types/src/react/components/PasskeyAuthMenu/preload.d.ts.map +1 -1
  187. package/dist/types/src/react/components/PasskeyAuthMenu/shell.d.ts.map +1 -1
  188. package/dist/types/src/react/components/PasskeyAuthMenu/skeleton.d.ts +1 -1
  189. package/dist/types/src/react/components/PasskeyAuthMenu/skeleton.d.ts.map +1 -1
  190. package/dist/types/src/react/components/PasskeyAuthMenu/ui/EmailRecoverySlide.d.ts.map +1 -1
  191. package/dist/types/src/server/core/AuthService.d.ts.map +1 -1
  192. package/dist/workers/wasm_vrf_worker_bg.wasm +0 -0
  193. package/package.json +4 -4
  194. package/dist/cjs/react/components/PasskeyAuthMenu/PasskeyAuthMenu-CRlobBrN.css.map +0 -1
  195. package/dist/esm/react/components/PasskeyAuthMenu/PasskeyAuthMenu-D2VHZ04W.css.map +0 -1
  196. package/dist/esm/sdk/registration-MrAOC8Ub.js.map +0 -1
  197. package/dist/esm/sdk/transactions-CrjP8yPD.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"offline-export-app.js","names":["target","DB_CONFIG: PasskeyClientDBConfig","DB_CONFIG","err: any","entry: AppStateEntry<T>","userData: ClientUserData","lastUserState: LastUserAccountIdState","fixed: ClientUserData","updatedUser: ClientUserData","clientAuth: ClientAuthenticatorData","rec: DerivedAddressRecord","rec: RecoveryEmailRecord","ALPHABET","basex","bs58","out: number[]","out: ThresholdEd25519ParticipantV1[]","participant: ThresholdEd25519ParticipantV1","client: ThresholdEd25519ParticipantV1","relayer: ThresholdEd25519ParticipantV1","DB_CONFIG: PasskeyNearKeysDBConfig","kind","value: any","txPayload: EncodableSignedTx","lastError: unknown","err: unknown","base","params: Record<string, unknown>","fullAccessKeys: FullAccessKey[]","functionCallAccessKeys: FunctionCallAccessKey[]","isObject","err: unknown","base","error: any","serializedCredential: WebAuthnRegistrationCredential","result: CheckCanRegisterUserResult","error: unknown","wasmModule.UserVerificationPolicy.Required","wasmModule.UserVerificationPolicy.Preferred","wasmModule.UserVerificationPolicy.Discouraged","DEFAULT_AUTHENTICATOR_OPTIONS: AuthenticatorOptions","keyMaterial: LocalNearSkV3Material","error: unknown","error: unknown","base","DEFAULT_THRESHOLD_SESSION_POLICY: Pick<ThresholdEd25519SessionPolicy, 'ttlMs' | 'remainingUses'>","warnings: string[]","txSigningRequests: TransactionPayload[]","extractSigningEvidenceFromConfirmation","e: unknown","credentialForRelay: WebAuthnAuthenticationCredential | undefined","warnings: string[]","extractSigningEvidenceFromConfirmation","okResponse","okResponse: WorkerSuccessResponse<typeof WorkerRequestType.SignDelegateAction>","e: unknown","credentialForRelay: WebAuthnAuthenticationCredential | undefined","error: unknown","error: unknown","error: unknown","okResponse","okResponse: WorkerSuccessResponse<typeof WorkerRequestType.SignNep413Message>","e: unknown","error: unknown","credentialForRelay: WebAuthnAuthenticationCredential | undefined","keyMaterial: LocalNearSkV3Material","error: unknown","cfg: ConfirmationConfig","newUiMode: ConfirmationConfig['uiMode']","payload: any","request: SecureConfirmRequest","confirmationConfig: ConfirmationConfig","transactionSummary: TransactionSummary","e: unknown","_err: unknown","HANDLERS: Partial<Record<SecureConfirmationType, Handler>>","error: unknown","vrfPort: MessagePort | undefined","error: unknown","promises: Promise<void>[]","responses: WorkerResponseForRequest<T>[]","errorMessage","message: VRFWorkerMessage<WasmVrfWorkerRequestType>","message: VRFWorkerMessage<WasmClearSessionRequest>","message: VRFWorkerMessage<WasmVrfWorkerRequestType>","message: VRFWorkerMessage<WasmDevice2RegistrationSessionRequest>","intentDigest: string","request: SecureConfirmRequest<SignTransactionPayload | SignNep413Payload, TransactionSummary>","summary: TransactionSummary","txSigningRequests: TransactionInputWasm[]","message: VRFWorkerMessage<WasmConfirmAndPrepareSigningSessionRequest>","message: VRFWorkerMessage<WasmDeriveVrfKeypairFromPrfRequest>","message: VRFWorkerMessage<WasmMintSessionKeysAndSendToSignerRequest>","message: VRFWorkerMessage<WasmDispenseSessionKeyRequest>","message: VRFWorkerMessage<WasmShamir3PassClientDecryptVrfKeypairRequest>","message: VRFWorkerMessage<WasmGenerateVrfChallengeRequest>","indexedDB","message: VRFWorkerMessage<WasmGenerateVrfKeypairBootstrapRequest>","error: any","message: VRFWorkerMessage<WasmCheckSessionStatusRequest>","message: VRFWorkerMessage<any>","requestRegistrationCredentialConfirmation","request: SecureConfirmRequest<{\n nearAccountId: string;\n deviceNumber: number;\n rpcCall: { contractId: string; nearRpcUrl: string; nearAccountId: string };\n }, RegistrationSummary>","requestRegistrationCredentialConfirmationFlow","message: VRFWorkerMessage<WasmVrfWorkerRequestType>","message: VRFWorkerMessage<WasmUnlockVrfKeypairRequest>","error: any","next: ConfirmationConfig","base","envTheme: 'dark' | 'light' | null","accountId: AccountId | undefined","maybeAccessKey: unknown","maybeBlock: unknown","accessKeyError: unknown","blockError: unknown","tasks: Promise<void>[]","akErr: unknown","err: unknown","transactionContext: TransactionContext","now","planned: string[]","error: unknown","newLast: bigint | null","error: unknown","base","deleteKeyAction: ActionArgsWasm","txInputs: TransactionInputWasm[]","rpcCall: RpcCallPayload","error: unknown","UserPreferencesInstance","NonceManagerInstance","collectAuthenticationCredentialForVrfChallengeImpl","error: any","result: {\n success: boolean;\n vrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n vrfChallenge: VRFChallenge | null;\n serverEncryptedVrfKeypair: ServerEncryptedVrfKeypair | null;\n }","deviceNumber: number","deviceNumberToUse: number | null","credentialId: string","attestationB64u: string","transports: string[]","normalizedRpcCall: RpcCallPayload","error: unknown","keyMaterial: ThresholdEd25519_2p_V1Material","all: string[]","offlineConfigsInput: TatchiConfigsInput","err: any","last","e: any"],"sources":["../../../../node_modules/.pnpm/idb@8.0.3/node_modules/idb/build/index.js","../../../src/core/IndexedDBManager/passkeyClientDB.ts","../../../../node_modules/.pnpm/base-x@5.0.1/node_modules/base-x/src/esm/index.js","../../../../node_modules/.pnpm/bs58@6.0.0/node_modules/bs58/src/esm/index.js","../../../src/utils/base58.ts","../../../src/react/deviceDetection.ts","../../../src/threshold/participants.ts","../../../src/core/IndexedDBManager/passkeyNearKeysDB.ts","../../../src/core/IndexedDBManager/index.ts","../../../src/core/NearRpcError.ts","../../../src/core/types/rpc.ts","../../../src/core/NearClient.ts","../../../src/core/OfflineExport/messages.ts","../../../build-paths.ts","../../../src/config.ts","../../../src/core/sdkPaths/base.ts","../../../src/core/sdkPaths/workers.ts","../../../src/core/workerControlMessages.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/sessionMessages.ts","../../../src/core/types/sdkSentEvents.ts","../../../src/core/rpcCalls.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.ts","../../../src/core/types/authenticatorOptions.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/session.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/sessionHandshake.ts","../../../src/core/threshold/thresholdEd25519RelayerHealth.ts","../../../src/core/threshold/thresholdEd25519AuthSession.ts","../../../src/core/threshold/thresholdSessionPolicy.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/recoverKeypairFromPasskey.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/extractCosePublicKey.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionWithKeyPair.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/requestAdapter.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/secureConfirmBridge.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/deriveThresholdEd25519ClientVerifyingShare.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/index.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/checkVrfStatus.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/clearSession.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/clearVrf.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/confirmAndDeriveDevice2RegistrationSession.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/confirmAndPrepareSigningSession.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/mintSessionKeysAndSendToSigner.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/dispenseSessionKey.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/shamir3PassDecryptVrfKeypair.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/checkSessionStatus.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/prepareDecryptSession.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/requestRegistrationCredentialConfirmation.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/requestRegistrationCredentialConfirmation.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/shamir3PassEncryptCurrentVrfKeypair.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/unlockVrfKeypair.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/index.ts","../../../src/core/WebAuthnManager/userPreferences.ts","../../../src/core/nonceManager.ts","../../../src/core/WebAuthnManager/threshold/enrollThresholdEd25519Key.ts","../../../src/core/WebAuthnManager/threshold/rotateThresholdEd25519KeyPostRegistration.ts","../../../src/core/WebAuthnManager/index.ts","../../../src/core/OfflineExport/offline-export-app.ts"],"sourcesContent":["const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);\n\nlet idbProxyableTypes;\nlet cursorAdvanceMethods;\n// This is a function to prevent it throwing up in node environments.\nfunction getIdbProxyableTypes() {\n return (idbProxyableTypes ||\n (idbProxyableTypes = [\n IDBDatabase,\n IDBObjectStore,\n IDBIndex,\n IDBCursor,\n IDBTransaction,\n ]));\n}\n// This is a function to prevent it throwing up in node environments.\nfunction getCursorAdvanceMethods() {\n return (cursorAdvanceMethods ||\n (cursorAdvanceMethods = [\n IDBCursor.prototype.advance,\n IDBCursor.prototype.continue,\n IDBCursor.prototype.continuePrimaryKey,\n ]));\n}\nconst transactionDoneMap = new WeakMap();\nconst transformCache = new WeakMap();\nconst reverseTransformCache = new WeakMap();\nfunction promisifyRequest(request) {\n const promise = new Promise((resolve, reject) => {\n const unlisten = () => {\n request.removeEventListener('success', success);\n request.removeEventListener('error', error);\n };\n const success = () => {\n resolve(wrap(request.result));\n unlisten();\n };\n const error = () => {\n reject(request.error);\n unlisten();\n };\n request.addEventListener('success', success);\n request.addEventListener('error', error);\n });\n // This mapping exists in reverseTransformCache but doesn't exist in transformCache. This\n // is because we create many promises from a single IDBRequest.\n reverseTransformCache.set(promise, request);\n return promise;\n}\nfunction cacheDonePromiseForTransaction(tx) {\n // Early bail if we've already created a done promise for this transaction.\n if (transactionDoneMap.has(tx))\n return;\n const done = new Promise((resolve, reject) => {\n const unlisten = () => {\n tx.removeEventListener('complete', complete);\n tx.removeEventListener('error', error);\n tx.removeEventListener('abort', error);\n };\n const complete = () => {\n resolve();\n unlisten();\n };\n const error = () => {\n reject(tx.error || new DOMException('AbortError', 'AbortError'));\n unlisten();\n };\n tx.addEventListener('complete', complete);\n tx.addEventListener('error', error);\n tx.addEventListener('abort', error);\n });\n // Cache it for later retrieval.\n transactionDoneMap.set(tx, done);\n}\nlet idbProxyTraps = {\n get(target, prop, receiver) {\n if (target instanceof IDBTransaction) {\n // Special handling for transaction.done.\n if (prop === 'done')\n return transactionDoneMap.get(target);\n // Make tx.store return the only store in the transaction, or undefined if there are many.\n if (prop === 'store') {\n return receiver.objectStoreNames[1]\n ? undefined\n : receiver.objectStore(receiver.objectStoreNames[0]);\n }\n }\n // Else transform whatever we get back.\n return wrap(target[prop]);\n },\n set(target, prop, value) {\n target[prop] = value;\n return true;\n },\n has(target, prop) {\n if (target instanceof IDBTransaction &&\n (prop === 'done' || prop === 'store')) {\n return true;\n }\n return prop in target;\n },\n};\nfunction replaceTraps(callback) {\n idbProxyTraps = callback(idbProxyTraps);\n}\nfunction wrapFunction(func) {\n // Due to expected object equality (which is enforced by the caching in `wrap`), we\n // only create one new func per func.\n // Cursor methods are special, as the behaviour is a little more different to standard IDB. In\n // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the\n // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense\n // with real promises, so each advance methods returns a new promise for the cursor object, or\n // undefined if the end of the cursor has been reached.\n if (getCursorAdvanceMethods().includes(func)) {\n return function (...args) {\n // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n // the original object.\n func.apply(unwrap(this), args);\n return wrap(this.request);\n };\n }\n return function (...args) {\n // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n // the original object.\n return wrap(func.apply(unwrap(this), args));\n };\n}\nfunction transformCachableValue(value) {\n if (typeof value === 'function')\n return wrapFunction(value);\n // This doesn't return, it just creates a 'done' promise for the transaction,\n // which is later returned for transaction.done (see idbObjectHandler).\n if (value instanceof IDBTransaction)\n cacheDonePromiseForTransaction(value);\n if (instanceOfAny(value, getIdbProxyableTypes()))\n return new Proxy(value, idbProxyTraps);\n // Return the same value back if we're not going to transform it.\n return value;\n}\nfunction wrap(value) {\n // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because\n // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.\n if (value instanceof IDBRequest)\n return promisifyRequest(value);\n // If we've already transformed this value before, reuse the transformed value.\n // This is faster, but it also provides object equality.\n if (transformCache.has(value))\n return transformCache.get(value);\n const newValue = transformCachableValue(value);\n // Not all types are transformed.\n // These may be primitive types, so they can't be WeakMap keys.\n if (newValue !== value) {\n transformCache.set(value, newValue);\n reverseTransformCache.set(newValue, value);\n }\n return newValue;\n}\nconst unwrap = (value) => reverseTransformCache.get(value);\n\n/**\n * Open a database.\n *\n * @param name Name of the database.\n * @param version Schema version.\n * @param callbacks Additional callbacks.\n */\nfunction openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {\n const request = indexedDB.open(name, version);\n const openPromise = wrap(request);\n if (upgrade) {\n request.addEventListener('upgradeneeded', (event) => {\n upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);\n });\n }\n if (blocked) {\n request.addEventListener('blocked', (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion, event.newVersion, event));\n }\n openPromise\n .then((db) => {\n if (terminated)\n db.addEventListener('close', () => terminated());\n if (blocking) {\n db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event));\n }\n })\n .catch(() => { });\n return openPromise;\n}\n/**\n * Delete a database.\n *\n * @param name Name of the database.\n */\nfunction deleteDB(name, { blocked } = {}) {\n const request = indexedDB.deleteDatabase(name);\n if (blocked) {\n request.addEventListener('blocked', (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion, event));\n }\n return wrap(request).then(() => undefined);\n}\n\nconst readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];\nconst writeMethods = ['put', 'add', 'delete', 'clear'];\nconst cachedMethods = new Map();\nfunction getMethod(target, prop) {\n if (!(target instanceof IDBDatabase &&\n !(prop in target) &&\n typeof prop === 'string')) {\n return;\n }\n if (cachedMethods.get(prop))\n return cachedMethods.get(prop);\n const targetFuncName = prop.replace(/FromIndex$/, '');\n const useIndex = prop !== targetFuncName;\n const isWrite = writeMethods.includes(targetFuncName);\n if (\n // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.\n !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) ||\n !(isWrite || readMethods.includes(targetFuncName))) {\n return;\n }\n const method = async function (storeName, ...args) {\n // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(\n const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');\n let target = tx.store;\n if (useIndex)\n target = target.index(args.shift());\n // Must reject if op rejects.\n // If it's a write operation, must reject if tx.done rejects.\n // Must reject with op rejection first.\n // Must resolve with op value.\n // Must handle both promises (no unhandled rejections)\n return (await Promise.all([\n target[targetFuncName](...args),\n isWrite && tx.done,\n ]))[0];\n };\n cachedMethods.set(prop, method);\n return method;\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),\n has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop),\n}));\n\nconst advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];\nconst methodMap = {};\nconst advanceResults = new WeakMap();\nconst ittrProxiedCursorToOriginalProxy = new WeakMap();\nconst cursorIteratorTraps = {\n get(target, prop) {\n if (!advanceMethodProps.includes(prop))\n return target[prop];\n let cachedFunc = methodMap[prop];\n if (!cachedFunc) {\n cachedFunc = methodMap[prop] = function (...args) {\n advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));\n };\n }\n return cachedFunc;\n },\n};\nasync function* iterate(...args) {\n // tslint:disable-next-line:no-this-assignment\n let cursor = this;\n if (!(cursor instanceof IDBCursor)) {\n cursor = await cursor.openCursor(...args);\n }\n if (!cursor)\n return;\n cursor = cursor;\n const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);\n ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);\n // Map this double-proxy back to the original, so other cursor methods work.\n reverseTransformCache.set(proxiedCursor, unwrap(cursor));\n while (cursor) {\n yield proxiedCursor;\n // If one of the advancing methods was not called, call continue().\n cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());\n advanceResults.delete(proxiedCursor);\n }\n}\nfunction isIteratorProp(target, prop) {\n return ((prop === Symbol.asyncIterator &&\n instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor])) ||\n (prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore])));\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get(target, prop, receiver) {\n if (isIteratorProp(target, prop))\n return iterate;\n return oldTraps.get(target, prop, receiver);\n },\n has(target, prop) {\n return isIteratorProp(target, prop) || oldTraps.has(target, prop);\n },\n}));\n\nexport { deleteDB, openDB, unwrap, wrap };\n","import { openDB, type IDBPDatabase } from 'idb';\nimport { type ValidationResult, validateNearAccountId } from '../../utils/validation';\nimport type { AccountId } from '../types/accountIds';\nimport { toAccountId } from '../types/accountIds';\nimport {\n ConfirmationConfig,\n DEFAULT_CONFIRMATION_CONFIG,\n type SignerMode,\n DEFAULT_SIGNING_MODE,\n coerceSignerMode,\n} from '../types/signer-worker'\n\n\nexport interface ClientUserData {\n // Primary key - now uses AccountId + deviceNumber for unique identification\n nearAccountId: AccountId;\n deviceNumber: number; // Device number for multi-device support (1-indexed)\n version?: number;\n\n // User metadata\n registeredAt?: number;\n lastLogin?: number;\n lastUpdated?: number;\n\n // WebAuthn/Passkey data (merged from WebAuthnManager)\n clientNearPublicKey: string;\n passkeyCredential: {\n id: string;\n rawId: string;\n };\n\n // VRF credentials for stateless authentication\n encryptedVrfKeypair: {\n encryptedVrfDataB64u: string;\n chacha20NonceB64u: string;\n };\n // Server-assisted auto-login (VRF key session): Shamir 3-pass fields\n // Stores relayer-blinded KEK and the VRF ciphertext; server never sees plaintext VRF or KEK\n serverEncryptedVrfKeypair?: {\n ciphertextVrfB64u: string;\n kek_s_b64u: string;\n // Metadata for proactive refresh\n serverKeyId: string;\n updatedAt?: number;\n };\n\n // User preferences\n preferences?: UserPreferences;\n}\n\nexport type StoreUserDataInput = Omit<ClientUserData, 'deviceNumber' | 'lastLogin' | 'registeredAt'>\n & {\n deviceNumber?: number;\n serverEncryptedVrfKeypair?: ClientUserData['serverEncryptedVrfKeypair'];\n version?: number;\n };\n\nexport type StoreWebAuthnUserDataInput = {\n nearAccountId: AccountId;\n deviceNumber: number;\n clientNearPublicKey: string;\n lastUpdated?: number;\n version?: number;\n passkeyCredential: ClientUserData['passkeyCredential'];\n encryptedVrfKeypair: ClientUserData['encryptedVrfKeypair'];\n serverEncryptedVrfKeypair?: ClientUserData['serverEncryptedVrfKeypair'];\n};\n\nexport interface UserPreferences {\n useRelayer: boolean;\n useNetwork: 'testnet' | 'mainnet';\n confirmationConfig: ConfirmationConfig;\n signerMode?: SignerMode;\n // User preferences can be extended here as needed\n}\n\n// Authenticator cache\nexport interface ClientAuthenticatorData {\n credentialId: string;\n credentialPublicKey: Uint8Array;\n transports?: string[]; // AuthenticatorTransport[]\n name?: string;\n nearAccountId: AccountId; // FK reference using AccountId\n deviceNumber: number; // Device number for this authenticator (1-indexed)\n registered: string; // ISO date string\n syncedAt: string; // When this cache entry was last synced with contract\n vrfPublicKey: string; // Base64-encoded VRF public key (1:1 relationship on client)\n}\n\ninterface AppStateEntry<T = unknown> {\n key: string;\n value: T;\n}\n\n// Internal helper: legacy user records may be missing deviceNumber.\ntype ClientUserDataWithOptionalDevice =\n | ClientUserData\n | (Omit<ClientUserData, 'deviceNumber'> & { deviceNumber?: number });\n\n// Special type for lastUserAccountId app state entry\nexport interface LastUserAccountIdState {\n accountId: AccountId;\n deviceNumber: number;\n}\n\ninterface PasskeyClientDBConfig {\n dbName: string;\n dbVersion: number;\n userStore: string;\n appStateStore: string;\n authenticatorStore: string;\n derivedAddressStore: string;\n recoveryEmailStore: string;\n}\n\n// === CONSTANTS ===\nconst DB_CONFIG: PasskeyClientDBConfig = {\n dbName: 'PasskeyClientDB',\n dbVersion: 15, // v15: add recoveryEmails store\n userStore: 'users',\n appStateStore: 'appState',\n authenticatorStore: 'authenticators',\n derivedAddressStore: 'derivedAddresses',\n recoveryEmailStore: 'recoveryEmails'\n} as const;\n\nexport interface IndexedDBEvent {\n type: 'user-updated' | 'preferences-updated' | 'user-deleted';\n accountId: AccountId;\n data?: Record<string, unknown>;\n}\n\n// Persisted mapping of derived (e.g., EVM) addresses tied to an account\n/**\n * Persisted mapping of derived (e.g., EVM/Solana/Zcash) addresses tied to an account.\n *\n * Notes on multi-chain support:\n * - The composite primary key is [nearAccountId, contractId, path]. To support\n * different chains and chain IDs, encode them in the `path` string, e.g.:\n * - EVM: `evm:<chainId>:<derivationPath>` → `evm:84532:ethereum-1`\n * - Solana: `solana:<derivationPath>`\n * - Zcash: `zcash:<derivationPath>`\n * - Additional descriptive fields like `namespace` and `chainRef` are optional metadata\n * and are not part of the key.\n */\nexport interface DerivedAddressRecord {\n nearAccountId: AccountId;\n contractId: string; // MPC/Derivation contract on NEAR\n path: string; // Composite path (may include namespace/chainId); see docs above\n address: string; // Derived address (e.g., 0x...)\n updatedAt: number;\n // Optional metadata (not used in the key)\n namespace?: string; // e.g., 'evm', 'solana', 'zcash'\n chainRef?: string; // e.g., chainId '84532' or a named network slug\n}\n\n/**\n * Persisted mapping of recovery email hashes to canonical email addresses for an account.\n *\n * Notes:\n * - Composite primary key is [nearAccountId, hashHex].\n * - `hashHex` is the 0x-prefixed hex encoding of the 32-byte hash:\n * SHA256(canonical_email || \"|\" || account_id)\n * - `email` is the canonical form: \"local@domain\", lowercased.\n */\nexport interface RecoveryEmailRecord {\n nearAccountId: AccountId;\n hashHex: string;\n email: string;\n addedAt: number;\n}\n\nexport class PasskeyClientDBManager {\n private config: PasskeyClientDBConfig;\n private db: IDBPDatabase | null = null;\n private disabled = false;\n private eventListeners: Set<(event: IndexedDBEvent) => void> = new Set();\n\n constructor(config: PasskeyClientDBConfig = DB_CONFIG) {\n this.config = config;\n }\n\n getDbName(): string {\n return this.config.dbName;\n }\n\n setDbName(dbName: string): void {\n const next = String(dbName || '').trim();\n if (!next || next === this.config.dbName) return;\n try { (this.db as any)?.close?.(); } catch {}\n this.db = null;\n this.config = { ...this.config, dbName: next };\n }\n\n isDisabled(): boolean {\n return this.disabled;\n }\n\n setDisabled(disabled: boolean): void {\n const next = !!disabled;\n if (next === this.disabled) return;\n this.disabled = next;\n if (next) {\n try { (this.db as any)?.close?.(); } catch {}\n this.db = null;\n }\n }\n\n // === EVENT SYSTEM ===\n\n onChange(listener: (event: IndexedDBEvent) => void): () => void {\n this.eventListeners.add(listener);\n return () => {\n this.eventListeners.delete(listener);\n };\n }\n\n private emitEvent(event: IndexedDBEvent): void {\n this.eventListeners.forEach(listener => {\n try {\n listener(event);\n } catch (error) {\n console.warn('[IndexedDBManager]: Error in event listener:', error);\n }\n });\n }\n\n private async getDB(): Promise<IDBPDatabase> {\n if (this.disabled) {\n throw new Error('[PasskeyClientDBManager] IndexedDB is disabled in this environment.');\n }\n if (this.db) {\n return this.db;\n }\n\n try {\n this.db = await openDB(this.config.dbName, this.config.dbVersion, {\n upgrade: (db, oldVersion, _newVersion, _transaction): void => {\n // Create stores if they don't exist\n if (!db.objectStoreNames.contains(DB_CONFIG.userStore)) {\n // Users table: composite key of [nearAccountId, deviceNumber]\n const userStore = db.createObjectStore(DB_CONFIG.userStore, { keyPath: ['nearAccountId', 'deviceNumber'] });\n userStore.createIndex('nearAccountId', 'nearAccountId', { unique: false });\n }\n if (!db.objectStoreNames.contains(DB_CONFIG.appStateStore)) {\n db.createObjectStore(DB_CONFIG.appStateStore, { keyPath: 'key' });\n }\n if (!db.objectStoreNames.contains(DB_CONFIG.authenticatorStore)) {\n // Authenticators table: composite key of [nearAccountId, deviceNumber, credentialId]\n const authStore = db.createObjectStore(DB_CONFIG.authenticatorStore, { keyPath: ['nearAccountId', 'deviceNumber', 'credentialId'] });\n authStore.createIndex('nearAccountId', 'nearAccountId', { unique: false });\n }\n if (!db.objectStoreNames.contains(DB_CONFIG.derivedAddressStore)) {\n // Derived addresses: composite key of [nearAccountId, contractId, path]\n const dStore = db.createObjectStore(DB_CONFIG.derivedAddressStore, { keyPath: ['nearAccountId', 'contractId', 'path'] });\n try { dStore.createIndex('nearAccountId', 'nearAccountId', { unique: false }); } catch {}\n }\n if (!db.objectStoreNames.contains(DB_CONFIG.recoveryEmailStore)) {\n // Recovery emails: composite key of [nearAccountId, hashHex]\n const rStore = db.createObjectStore(DB_CONFIG.recoveryEmailStore, { keyPath: ['nearAccountId', 'hashHex'] });\n try { rStore.createIndex('nearAccountId', 'nearAccountId', { unique: false }); } catch {}\n }\n },\n blocked() {\n console.warn('PasskeyClientDB connection is blocked.');\n },\n blocking() {\n console.warn('PasskeyClientDB connection is blocking another connection.');\n },\n terminated: () => {\n console.warn('PasskeyClientDB connection has been terminated.');\n this.db = null;\n },\n });\n\n // Post-open migrations (non-blocking)\n try { await this.runMigrationsIfNeeded(this.db); } catch {}\n\n } catch (err: any) {\n const msg = String(err?.message || '');\n if (err?.name === 'VersionError' || /less than the existing version/i.test(msg)) {\n // Mixed-version contexts (host/app) — open without version to adopt existing DB\n try {\n console.warn('PasskeyClientDB: opening existing DB without version due to VersionError');\n this.db = await openDB(this.config.dbName);\n } catch (e) {\n throw err;\n }\n } else {\n throw err;\n }\n }\n\n return this.db;\n }\n\n private async runMigrationsIfNeeded(_db: IDBPDatabase): Promise<void> {\n return;\n }\n\n // === APP STATE METHODS ===\n\n async getAppState<T = unknown>(key: string): Promise<T | undefined> {\n const db = await this.getDB();\n const result = await db.get(DB_CONFIG.appStateStore, key);\n return result?.value as T | undefined;\n }\n\n async setAppState<T = unknown>(key: string, value: T): Promise<void> {\n const db = await this.getDB();\n const entry: AppStateEntry<T> = { key, value };\n await db.put(DB_CONFIG.appStateStore, entry);\n }\n\n // === ACCOUNT ID VALIDATION AND UTILITIES ===\n\n /**\n * Validate that a NEAR account ID is in the expected format\n * Supports both <username>.<relayerAccountId> and <username>.testnet formats\n */\n validateNearAccountId(nearAccountId: AccountId): ValidationResult {\n return validateNearAccountId(nearAccountId);\n }\n\n /**\n * Extract username from NEAR account ID\n */\n extractUsername(nearAccountId: AccountId): string {\n const validation = validateNearAccountId(nearAccountId);\n if (!validation.valid) {\n throw new Error(`Invalid NEAR account ID: ${validation.error}`);\n }\n return nearAccountId.split('.')[0];\n }\n\n /**\n * Generate a NEAR account ID from a username and domain\n * @param username - The username to use for the account ID\n * @param domain - The domain to use for the account ID\n * @returns The generated NEAR account ID\n */\n generateNearAccountId(username: string, domain: string): string {\n const sanitizedName = username\n .toLowerCase()\n .replace(/[^a-z0-9_\\\\-]/g, '')\n .substring(0, 32);\n return `${sanitizedName}.${domain}`;\n }\n\n // === USER MANAGEMENT METHODS ===\n\n async getUser(nearAccountId: AccountId, deviceNumber?: number): Promise<ClientUserData | null> {\n if (!nearAccountId) return null;\n\n const validation = this.validateNearAccountId(nearAccountId);\n if (!validation.valid) {\n console.warn(`Invalid account ID format: ${nearAccountId}`);\n return null;\n }\n\n const db = await this.getDB();\n const accountId = toAccountId(nearAccountId);\n\n if (typeof deviceNumber === 'number') {\n const rec = await db.get(DB_CONFIG.userStore, [accountId, deviceNumber]);\n if (!rec) return null;\n return await this.normalizeUserDeviceNumber(rec as ClientUserDataWithOptionalDevice, deviceNumber);\n }\n\n const index = db.transaction(DB_CONFIG.userStore).store.index('nearAccountId');\n const results = await index.getAll(accountId);\n if (results.length === 0) {\n return null;\n }\n\n if (results.length > 1) {\n console.warn(\n `Multiple passkeys found for account ${accountId}, deviceNumber not provided; ` +\n 'defaulting to last logged-in user.'\n );\n console.log('defaulting to last used user deviceNumber');\n const lastUserState = await this.getAppState<LastUserAccountIdState>('lastUserAccountId').catch(() => null);\n if (lastUserState && toAccountId(lastUserState.accountId) === accountId) {\n const keyed = await db.get(DB_CONFIG.userStore, [accountId, lastUserState.deviceNumber]);\n if (keyed) {\n return await this.normalizeUserDeviceNumber(\n keyed as ClientUserDataWithOptionalDevice,\n lastUserState.deviceNumber\n );\n }\n }\n }\n\n const first = results[0] as ClientUserDataWithOptionalDevice;\n if (!first) return null;\n return await this.normalizeUserDeviceNumber(first, 1);\n }\n\n /**\n * Get the current/last user\n * This is maintained via app state and updated whenever a user is stored or updated\n */\n async getLastUser(): Promise<ClientUserData | null> {\n const lastUserState = await this.getAppState<LastUserAccountIdState>('lastUserAccountId');\n if (!lastUserState) return null;\n const db = await this.getDB();\n const accountId = toAccountId(lastUserState.accountId);\n // Prefer exact device match using composite primary key\n const record = await db.get(DB_CONFIG.userStore, [accountId, lastUserState.deviceNumber]);\n if (record) return record as ClientUserData;\n // Fallback: return any user for account\n return this.getUser(accountId);\n }\n\n /** Get user record by composite key (nearAccountId, deviceNumber) */\n async getUserByDevice(nearAccountId: AccountId, deviceNumber: number): Promise<ClientUserData | null> {\n const db = await this.getDB();\n const accountId = toAccountId(nearAccountId);\n const rec = await db.get(DB_CONFIG.userStore, [accountId, deviceNumber]);\n return rec as ClientUserData || null;\n }\n\n /**\n * Get the most recently updated user record for a given account.\n * Useful when deviceNumber is unknown but we need the freshest key for the account.\n */\n /**\n * Get the most recently updated user record for a given account.\n * Useful when deviceNumber is unknown but we need the freshest key for the account.\n */\n async getLastDBUpdatedUser(nearAccountId: AccountId): Promise<ClientUserData | null> {\n const db = await this.getDB();\n try {\n const idx = db.transaction(DB_CONFIG.userStore).store.index('nearAccountId');\n const all = await idx.getAll(toAccountId(nearAccountId));\n if (Array.isArray(all) && all.length > 0) {\n const latest = (all as ClientUserData[]).reduce((a, b) =>\n (a.lastUpdated ?? 0) >= (b.lastUpdated ?? 0) ? a : b\n );\n return latest;\n }\n } catch {\n // fall through\n }\n return null;\n }\n\n async hasPasskeyCredential(nearAccountId: AccountId): Promise<boolean> {\n const authenticators = await this.getAuthenticatorsByUser(nearAccountId);\n return !!authenticators[0]?.credentialId;\n }\n\n /**\n * Ensure the current passkey selection is aligned with the last logged-in device.\n *\n * - When multiple authenticators exist for an account and no deviceNumber is specified,\n * this helper prefers authenticators whose deviceNumber matches the last logged-in user.\n * - Optionally validates that a selected credential (by rawId) also matches the last-user device.\n *\n * @param nearAccountId - Account ID for which the operation is being performed\n * @param authenticators - All authenticators stored for the account\n * @param selectedCredentialRawId - Optional rawId of the credential chosen by WebAuthn\n * @returns filtered authenticators for allowCredentials, plus optional wrongPasskeyError\n */\n async ensureCurrentPasskey(\n nearAccountId: AccountId,\n authenticators: ClientAuthenticatorData[],\n selectedCredentialRawId?: string,\n ): Promise<{\n authenticatorsForPrompt: ClientAuthenticatorData[];\n wrongPasskeyError?: string;\n }> {\n if (authenticators.length <= 1) {\n return { authenticatorsForPrompt: authenticators };\n }\n\n const accountIdNormalized = toAccountId(nearAccountId);\n const lastUser = await this.getLastUser().catch(() => null);\n if (!lastUser || lastUser.nearAccountId !== accountIdNormalized) {\n return { authenticatorsForPrompt: authenticators };\n }\n\n const expectedDeviceNumber = lastUser.deviceNumber;\n const byDeviceNumber = authenticators.filter(a => a.deviceNumber === expectedDeviceNumber);\n\n // Prefer the credentialId for the last-user deviceNumber; use the stored last-user rawId\n // only when it matches an authenticator for that device (or when we have no device match).\n let expectedCredentialId = lastUser.passkeyCredential.rawId;\n if (byDeviceNumber.length > 0 && !byDeviceNumber.some(a => a.credentialId === expectedCredentialId)) {\n expectedCredentialId = byDeviceNumber[0].credentialId;\n }\n\n // Preference: restrict allowCredentials to the last-user credentialId.\n // Fallback: if the local authenticator cache is missing that entry, prefer the last-user deviceNumber.\n const byCredentialId = authenticators.filter(a => a.credentialId === expectedCredentialId);\n const authenticatorsForPrompt =\n byCredentialId.length > 0\n ? byCredentialId\n : (byDeviceNumber.length > 0 ? byDeviceNumber : authenticators);\n\n const wrongPasskeyError =\n selectedCredentialRawId && selectedCredentialRawId !== expectedCredentialId\n ? (\n `You have multiple passkeys (deviceNumbers) for account ${accountIdNormalized}, ` +\n 'but used a different passkey than the most recently logged-in one. Please use the passkey for the most recently logged-in device.'\n )\n : undefined;\n\n return { authenticatorsForPrompt, wrongPasskeyError };\n }\n\n /**\n * Register a new user with the given NEAR account ID\n * @param nearAccountId - Full NEAR account ID (e.g., \"username.testnet\" or \"username.relayer.testnet\")\n * @param additionalData - Additional user data to store\n */\n async registerUser(storeUserData: StoreUserDataInput): Promise<ClientUserData> {\n\n const validation = this.validateNearAccountId(storeUserData.nearAccountId);\n if (!validation.valid) {\n throw new Error(`Cannot register user with invalid account ID: ${validation.error}`);\n }\n\n const now = Date.now();\n\n const userData: ClientUserData = {\n nearAccountId: toAccountId(storeUserData.nearAccountId),\n deviceNumber: storeUserData.deviceNumber || 1, // Default to device 1 (1-indexed)\n version: storeUserData.version || 2,\n registeredAt: now,\n lastLogin: now,\n lastUpdated: now,\n clientNearPublicKey: storeUserData.clientNearPublicKey,\n passkeyCredential: storeUserData.passkeyCredential,\n preferences: {\n useRelayer: false,\n useNetwork: 'testnet',\n confirmationConfig: DEFAULT_CONFIRMATION_CONFIG,\n // Default preferences can be set here\n },\n encryptedVrfKeypair: storeUserData.encryptedVrfKeypair,\n serverEncryptedVrfKeypair: storeUserData.serverEncryptedVrfKeypair,\n };\n\n await this.storeUser(userData);\n return userData;\n }\n\n async updateUser(nearAccountId: AccountId, updates: Partial<ClientUserData>): Promise<void> {\n const user = await this.getUser(nearAccountId);\n if (user) {\n const updatedUser = {\n ...user,\n ...updates,\n lastUpdated: Date.now()\n };\n await this.storeUser(updatedUser); // This will update the app state lastUserAccountId\n\n // Emit event for user updates\n this.emitEvent({\n type: 'user-updated',\n accountId: nearAccountId,\n data: { updates, updatedUser }\n });\n }\n }\n\n async updateLastLogin(nearAccountId: AccountId): Promise<void> {\n await this.updateUser(nearAccountId, { lastLogin: Date.now() });\n }\n\n /**\n * Set the last logged-in user\n * @param nearAccountId - The account ID of the user\n * @param deviceNumber - The device number (defaults to 1)\n */\n async setLastUser(nearAccountId: AccountId, deviceNumber: number = 1): Promise<void> {\n const lastUserState: LastUserAccountIdState = {\n accountId: nearAccountId,\n deviceNumber,\n };\n await this.setAppState('lastUserAccountId', lastUserState);\n }\n\n async updatePreferences(\n nearAccountId: AccountId,\n preferences: Partial<UserPreferences>\n ): Promise<void> {\n const user = await this.getUser(nearAccountId);\n if (user) {\n const updatedPreferences = {\n ...user.preferences,\n ...preferences\n } as UserPreferences;\n await this.updateUser(nearAccountId, { preferences: updatedPreferences });\n\n // Emit event for preference changes\n this.emitEvent({\n type: 'preferences-updated',\n accountId: nearAccountId,\n data: { preferences: updatedPreferences }\n });\n }\n }\n\n private async normalizeUserDeviceNumber(\n user: ClientUserDataWithOptionalDevice,\n defaultDeviceNumber: number\n ): Promise<ClientUserData> {\n const hasValidDevice =\n typeof user.deviceNumber === 'number' && Number.isFinite(user.deviceNumber);\n if (hasValidDevice) {\n return user as ClientUserData;\n }\n\n const deviceNumber = defaultDeviceNumber;\n const fixed: ClientUserData = {\n ...(user as Omit<ClientUserData, 'deviceNumber'>),\n deviceNumber,\n };\n await this.storeUser(fixed);\n return fixed;\n }\n\n private async storeUser(userData: ClientUserData): Promise<void> {\n const validation = this.validateNearAccountId(userData.nearAccountId);\n if (!validation.valid) {\n throw new Error(`Cannot store user with invalid account ID: ${validation.error}`);\n }\n\n const db = await this.getDB();\n await db.put(DB_CONFIG.userStore, userData);\n\n // Update lastUserAccountId with new format including device info\n const lastUserState: LastUserAccountIdState = {\n accountId: userData.nearAccountId,\n deviceNumber: userData.deviceNumber,\n };\n\n await this.setAppState('lastUserAccountId', lastUserState);\n }\n\n /**\n * Store WebAuthn user data (compatibility with WebAuthnManager)\n * @param userData - User data with nearAccountId as primary identifier\n */\n async storeWebAuthnUserData(userData: StoreWebAuthnUserDataInput): Promise<void> {\n const validation = this.validateNearAccountId(userData.nearAccountId);\n if (!validation.valid) {\n throw new Error(`Cannot store WebAuthn data for invalid account ID: ${validation.error}`);\n }\n\n const accountId = toAccountId(userData.nearAccountId);\n const deviceNumber = userData.deviceNumber;\n let user = await this.getUser(accountId, deviceNumber);\n\n if (!user) {\n user = await this.registerUser({\n nearAccountId: accountId,\n deviceNumber,\n clientNearPublicKey: userData.clientNearPublicKey,\n passkeyCredential: userData.passkeyCredential,\n encryptedVrfKeypair: userData.encryptedVrfKeypair,\n version: userData.version || 2,\n serverEncryptedVrfKeypair: userData.serverEncryptedVrfKeypair,\n });\n }\n\n const updatedUser: ClientUserData = {\n ...user,\n clientNearPublicKey: userData.clientNearPublicKey,\n passkeyCredential: userData.passkeyCredential,\n encryptedVrfKeypair: userData.encryptedVrfKeypair,\n serverEncryptedVrfKeypair: userData.serverEncryptedVrfKeypair ?? user.serverEncryptedVrfKeypair,\n version: userData.version ?? user.version,\n lastUpdated: userData.lastUpdated ?? Date.now(),\n };\n\n await this.storeUser(updatedUser);\n this.emitEvent({\n type: 'user-updated',\n accountId,\n data: { updatedUser }\n });\n }\n\n async getAllUsers(): Promise<ClientUserData[]> {\n const db = await this.getDB();\n return db.getAll(DB_CONFIG.userStore);\n }\n\n async deleteUser(nearAccountId: AccountId): Promise<void> {\n const db = await this.getDB();\n await db.delete(DB_CONFIG.userStore, nearAccountId);\n // Also clean up related authenticators\n await this.clearAuthenticatorsForUser(nearAccountId);\n }\n\n async clearAllUsers(): Promise<void> {\n const db = await this.getDB();\n await db.clear(DB_CONFIG.userStore);\n }\n\n async clearAllAppState(): Promise<void> {\n const db = await this.getDB();\n await db.clear(DB_CONFIG.appStateStore);\n }\n\n /**\n * Store authenticator data for a user\n */\n async storeAuthenticator(authenticatorData: ClientAuthenticatorData): Promise<void> {\n const db = await this.getDB();\n await db.put(DB_CONFIG.authenticatorStore, authenticatorData);\n }\n\n /**\n * Get all authenticators for a user (optionally for a specific device)\n */\n async getAuthenticatorsByUser(nearAccountId: AccountId): Promise<ClientAuthenticatorData[]> {\n const db = await this.getDB();\n const tx = db.transaction(DB_CONFIG.authenticatorStore, 'readonly');\n const store = tx.objectStore(DB_CONFIG.authenticatorStore);\n const accountId = toAccountId(nearAccountId);\n\n // Get all authenticators for this account across all devices\n const index = store.index('nearAccountId');\n return await index.getAll(accountId);\n }\n\n /**\n * Get a specific authenticator by credential ID\n */\n async getAuthenticatorByCredentialId(\n nearAccountId: AccountId,\n credentialId: string\n ): Promise<ClientAuthenticatorData | null> {\n const db = await this.getDB();\n const tx = db.transaction(DB_CONFIG.authenticatorStore, 'readonly');\n const store = tx.objectStore(DB_CONFIG.authenticatorStore);\n const accountId = toAccountId(nearAccountId);\n\n // Primary key is [nearAccountId, deviceNumber, credentialId], so we cannot\n // look up by [nearAccountId, credentialId] directly. Use the nearAccountId\n // index and filter by credentialId.\n const index = store.index('nearAccountId');\n const all = await index.getAll(accountId);\n const match = all.find((auth: any) => auth.credentialId === credentialId) || null;\n return match;\n }\n\n /**\n * Clear all authenticators for a user\n */\n async clearAuthenticatorsForUser(nearAccountId: AccountId): Promise<void> {\n const authenticators = await this.getAuthenticatorsByUser(nearAccountId);\n const db = await this.getDB();\n const tx = db.transaction(DB_CONFIG.authenticatorStore, 'readwrite');\n const store = tx.objectStore(DB_CONFIG.authenticatorStore);\n\n for (const auth of authenticators) {\n // Composite PK is [nearAccountId, deviceNumber, credentialId]\n await store.delete([nearAccountId, auth.deviceNumber, auth.credentialId]);\n }\n }\n\n /**\n * Sync authenticators from contract data\n */\n async syncAuthenticatorsFromContract(\n nearAccountId: AccountId,\n contractAuthenticators: Array<{\n credentialId: string;\n credentialPublicKey: Uint8Array;\n transports?: string[];\n name?: string;\n registered: string;\n vrfPublicKey: string;\n deviceNumber?: number; // Device number from contract\n }>\n ): Promise<void> {\n // Clear existing cache for this user\n await this.clearAuthenticatorsForUser(nearAccountId);\n\n // Add all contract authenticators to cache\n const syncedAt = new Date().toISOString();\n for (const auth of contractAuthenticators) {\n // Fix transport processing: filter out undefined values and provide fallback\n const rawTransports = auth.transports || [];\n const validTransports = rawTransports.filter((transport: any) =>\n transport !== undefined && transport !== null && typeof transport === 'string'\n );\n\n // If no valid transports, default to 'internal' for platform authenticators\n const transports = validTransports.length > 0 ? validTransports : ['internal'];\n\n const clientAuth: ClientAuthenticatorData = {\n credentialId: auth.credentialId,\n credentialPublicKey: auth.credentialPublicKey,\n transports,\n name: auth.name,\n nearAccountId: toAccountId(nearAccountId),\n deviceNumber: auth.deviceNumber || 1, // Default to device 1 (1-indexed)\n registered: auth.registered,\n syncedAt: syncedAt,\n vrfPublicKey: auth.vrfPublicKey,\n };\n await this.storeAuthenticator(clientAuth);\n }\n }\n\n // === ATOMIC OPERATIONS AND ROLLBACK METHODS ===\n\n /**\n * Delete all authenticators for a user\n */\n async deleteAllAuthenticatorsForUser(nearAccountId: AccountId): Promise<void> {\n const authenticators = await this.getAuthenticatorsByUser(nearAccountId);\n\n if (authenticators.length === 0) {\n console.warn(`No authenticators found for user ${nearAccountId}`);\n return;\n }\n\n const db = await this.getDB();\n const tx = db.transaction(DB_CONFIG.authenticatorStore, 'readwrite');\n const store = tx.objectStore(DB_CONFIG.authenticatorStore);\n\n for (const auth of authenticators) {\n // Composite PK is [nearAccountId, deviceNumber, credentialId]\n await store.delete([nearAccountId, auth.deviceNumber, auth.credentialId]);\n }\n\n console.debug(`Deleted ${authenticators.length} authenticators for user ${nearAccountId}`);\n }\n\n /**\n * Get user's confirmation config from IndexedDB\n * @param nearAccountId - The user's account ID\n * @returns ConfirmationConfig or undefined\n */\n async getConfirmationConfig(nearAccountId: AccountId): Promise<ConfirmationConfig> {\n const user = await this.getUser(nearAccountId);\n return user?.preferences?.confirmationConfig || DEFAULT_CONFIRMATION_CONFIG;\n }\n\n /**\n * Get user's theme preference from IndexedDB\n * @param nearAccountId - The user's account ID\n * @returns 'dark' | 'light' | null\n */\n async getTheme(nearAccountId: AccountId): Promise<'dark' | 'light' | null> {\n const user = await this.getUser(nearAccountId);\n return user?.preferences?.confirmationConfig.theme || null;\n }\n\n /**\n * Set user's theme preference in IndexedDB\n * @param nearAccountId - The user's account ID\n * @param theme - The theme to set ('dark' | 'light')\n */\n async setTheme(nearAccountId: AccountId, theme: 'dark' | 'light'): Promise<void> {\n const existingConfig = await this.getConfirmationConfig(nearAccountId);\n const confirmationConfig = { ...existingConfig, theme };\n await this.updatePreferences(nearAccountId, { confirmationConfig });\n }\n\n /**\n * Get user's theme with fallback to 'dark'\n * @param nearAccountId - The user's account ID\n * @returns 'dark' | 'light'\n */\n async getThemeOrDefault(nearAccountId: AccountId): Promise<'dark' | 'light'> {\n const theme = await this.getTheme(nearAccountId);\n return theme || 'dark';\n }\n\n /**\n * Get user's signer mode preference from IndexedDB\n */\n async getSignerMode(nearAccountId: AccountId): Promise<SignerMode> {\n const user = await this.getUser(nearAccountId);\n const raw = user?.preferences?.signerMode as SignerMode | SignerMode['mode'] | null | undefined;\n return coerceSignerMode(raw, DEFAULT_SIGNING_MODE);\n }\n\n /**\n * Set user's signer mode preference in IndexedDB\n */\n async setSignerMode(nearAccountId: AccountId, signerMode: SignerMode | SignerMode['mode']): Promise<void> {\n const next = coerceSignerMode(signerMode, DEFAULT_SIGNING_MODE);\n await this.updatePreferences(nearAccountId, { signerMode: next });\n }\n\n /**\n * Toggle between dark and light theme for a user\n * @param nearAccountId - The user's account ID\n * @returns The new theme that was set\n */\n async toggleTheme(nearAccountId: AccountId): Promise<'dark' | 'light'> {\n const currentTheme = await this.getThemeOrDefault(nearAccountId);\n const newTheme = currentTheme === 'dark' ? 'light' : 'dark';\n await this.setTheme(nearAccountId, newTheme);\n return newTheme;\n }\n\n // === DERIVED ADDRESS METHODS ===\n\n /**\n * Store a derived address for a given NEAR account + contract + path\n */\n async setDerivedAddress(nearAccountId: AccountId, args: { contractId: string; path: string; address: string }): Promise<void> {\n if (!nearAccountId || !args?.contractId || !args?.path || !args?.address) return;\n const validation = this.validateNearAccountId(nearAccountId);\n if (!validation.valid) return;\n const rec: DerivedAddressRecord = {\n nearAccountId: toAccountId(nearAccountId),\n contractId: String(args.contractId),\n path: String(args.path),\n address: String(args.address),\n updatedAt: Date.now(),\n };\n const db = await this.getDB();\n await db.put(DB_CONFIG.derivedAddressStore, rec);\n }\n\n /**\n * Fetch a derived address record; returns null if not found\n */\n async getDerivedAddressRecord(nearAccountId: AccountId, args: { contractId: string; path: string }): Promise<DerivedAddressRecord | null> {\n if (!nearAccountId || !args?.contractId || !args?.path) return null;\n const db = await this.getDB();\n const rec = await db.get(DB_CONFIG.derivedAddressStore, [toAccountId(nearAccountId), String(args.contractId), String(args.path)]);\n return (rec as DerivedAddressRecord) || null;\n }\n\n /**\n * Get only the derived address string; returns null if not set\n */\n async getDerivedAddress(nearAccountId: AccountId, args: { contractId: string; path: string }): Promise<string | null> {\n const rec = await this.getDerivedAddressRecord(nearAccountId, args);\n return rec?.address || null;\n }\n\n // === RECOVERY EMAIL METHODS ===\n\n /**\n * Upsert recovery email records for an account.\n * Merges by hashHex, preferring the most recent email.\n */\n async upsertRecoveryEmails(\n nearAccountId: AccountId,\n entries: Array<{ hashHex: string; email: string }>\n ): Promise<void> {\n if (!nearAccountId || !entries?.length) return;\n const validation = this.validateNearAccountId(nearAccountId);\n if (!validation.valid) return;\n\n const db = await this.getDB();\n const accountId = toAccountId(nearAccountId);\n const now = Date.now();\n\n for (const entry of entries) {\n const hashHex = String(entry?.hashHex || '').trim();\n const email = String(entry?.email || '').trim();\n if (!hashHex || !email) continue;\n\n const rec: RecoveryEmailRecord = {\n nearAccountId: accountId,\n hashHex,\n email,\n addedAt: now,\n };\n await db.put(DB_CONFIG.recoveryEmailStore, rec);\n }\n }\n\n /**\n * Fetch all recovery email records for an account.\n */\n async getRecoveryEmails(nearAccountId: AccountId): Promise<RecoveryEmailRecord[]> {\n if (!nearAccountId) return [];\n const db = await this.getDB();\n const accountId = toAccountId(nearAccountId);\n const tx = db.transaction(DB_CONFIG.recoveryEmailStore, 'readonly');\n const store = tx.objectStore(DB_CONFIG.recoveryEmailStore);\n const index = store.index('nearAccountId');\n const result = await index.getAll(accountId);\n return (result as RecoveryEmailRecord[]) || [];\n }\n\n /**\n * Atomic operation wrapper for multiple IndexedDB operations\n * Either all operations succeed or all are rolled back\n */\n async atomicOperation<T>(operation: (db: IDBPDatabase) => Promise<T>): Promise<T> {\n const db = await this.getDB();\n try {\n const result = await operation(db);\n return result;\n } catch (error) {\n console.error('Atomic operation failed:', error);\n throw error;\n }\n }\n\n /**\n * Complete rollback of user registration data\n * Deletes user, authenticators, and WebAuthn data atomically\n */\n async rollbackUserRegistration(nearAccountId: AccountId): Promise<void> {\n console.debug(`Rolling back registration data for ${nearAccountId}`);\n\n await this.atomicOperation(async (db) => {\n // Delete all authenticators for this user\n await this.deleteAllAuthenticatorsForUser(nearAccountId);\n\n // Delete user record\n await db.delete(DB_CONFIG.userStore, nearAccountId);\n\n // Clear from app state if this was the last user\n const lastUserAccount = await this.getAppState<string>('lastUserAccountId');\n if (lastUserAccount === nearAccountId) {\n await this.setAppState('lastUserAccountId', null);\n }\n\n console.debug(`Rolled back all registration data for ${nearAccountId}`);\n return true;\n });\n }\n}\n","// base-x encoding / decoding\n// Copyright (c) 2018 base-x contributors\n// Copyright (c) 2014-2018 The Bitcoin Core developers (base58.cpp)\n// Distributed under the MIT software license, see the accompanying\n// file LICENSE or http://www.opensource.org/licenses/mit-license.php.\nfunction base (ALPHABET) {\n if (ALPHABET.length >= 255) { throw new TypeError('Alphabet too long') }\n const BASE_MAP = new Uint8Array(256)\n for (let j = 0; j < BASE_MAP.length; j++) {\n BASE_MAP[j] = 255\n }\n for (let i = 0; i < ALPHABET.length; i++) {\n const x = ALPHABET.charAt(i)\n const xc = x.charCodeAt(0)\n if (BASE_MAP[xc] !== 255) { throw new TypeError(x + ' is ambiguous') }\n BASE_MAP[xc] = i\n }\n const BASE = ALPHABET.length\n const LEADER = ALPHABET.charAt(0)\n const FACTOR = Math.log(BASE) / Math.log(256) // log(BASE) / log(256), rounded up\n const iFACTOR = Math.log(256) / Math.log(BASE) // log(256) / log(BASE), rounded up\n function encode (source) {\n // eslint-disable-next-line no-empty\n if (source instanceof Uint8Array) { } else if (ArrayBuffer.isView(source)) {\n source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength)\n } else if (Array.isArray(source)) {\n source = Uint8Array.from(source)\n }\n if (!(source instanceof Uint8Array)) { throw new TypeError('Expected Uint8Array') }\n if (source.length === 0) { return '' }\n // Skip & count leading zeroes.\n let zeroes = 0\n let length = 0\n let pbegin = 0\n const pend = source.length\n while (pbegin !== pend && source[pbegin] === 0) {\n pbegin++\n zeroes++\n }\n // Allocate enough space in big-endian base58 representation.\n const size = ((pend - pbegin) * iFACTOR + 1) >>> 0\n const b58 = new Uint8Array(size)\n // Process the bytes.\n while (pbegin !== pend) {\n let carry = source[pbegin]\n // Apply \"b58 = b58 * 256 + ch\".\n let i = 0\n for (let it1 = size - 1; (carry !== 0 || i < length) && (it1 !== -1); it1--, i++) {\n carry += (256 * b58[it1]) >>> 0\n b58[it1] = (carry % BASE) >>> 0\n carry = (carry / BASE) >>> 0\n }\n if (carry !== 0) { throw new Error('Non-zero carry') }\n length = i\n pbegin++\n }\n // Skip leading zeroes in base58 result.\n let it2 = size - length\n while (it2 !== size && b58[it2] === 0) {\n it2++\n }\n // Translate the result into a string.\n let str = LEADER.repeat(zeroes)\n for (; it2 < size; ++it2) { str += ALPHABET.charAt(b58[it2]) }\n return str\n }\n function decodeUnsafe (source) {\n if (typeof source !== 'string') { throw new TypeError('Expected String') }\n if (source.length === 0) { return new Uint8Array() }\n let psz = 0\n // Skip and count leading '1's.\n let zeroes = 0\n let length = 0\n while (source[psz] === LEADER) {\n zeroes++\n psz++\n }\n // Allocate enough space in big-endian base256 representation.\n const size = (((source.length - psz) * FACTOR) + 1) >>> 0 // log(58) / log(256), rounded up.\n const b256 = new Uint8Array(size)\n // Process the characters.\n while (psz < source.length) {\n // Find code of next character\n const charCode = source.charCodeAt(psz)\n // Base map can not be indexed using char code\n if (charCode > 255) { return }\n // Decode character\n let carry = BASE_MAP[charCode]\n // Invalid character\n if (carry === 255) { return }\n let i = 0\n for (let it3 = size - 1; (carry !== 0 || i < length) && (it3 !== -1); it3--, i++) {\n carry += (BASE * b256[it3]) >>> 0\n b256[it3] = (carry % 256) >>> 0\n carry = (carry / 256) >>> 0\n }\n if (carry !== 0) { throw new Error('Non-zero carry') }\n length = i\n psz++\n }\n // Skip leading zeroes in b256.\n let it4 = size - length\n while (it4 !== size && b256[it4] === 0) {\n it4++\n }\n const vch = new Uint8Array(zeroes + (size - it4))\n let j = zeroes\n while (it4 !== size) {\n vch[j++] = b256[it4++]\n }\n return vch\n }\n function decode (string) {\n const buffer = decodeUnsafe(string)\n if (buffer) { return buffer }\n throw new Error('Non-base' + BASE + ' character')\n }\n return {\n encode,\n decodeUnsafe,\n decode\n }\n}\nexport default base\n","import basex from 'base-x';\nvar ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\nexport default basex(ALPHABET);\n","import bs58 from 'bs58';\n\n/**\n * Encodes binary data to base58 string using Bitcoin's base58 alphabet.\n * Used extensively in NEAR for account IDs, public keys, hashes, and signatures.\n *\n * @param data - Binary data to encode (Uint8Array, ArrayBuffer, or number[])\n * @returns Base58-encoded string\n */\nexport const base58Encode = (data: Uint8Array | ArrayBuffer | number[]): string => {\n if (data instanceof ArrayBuffer) {\n return bs58.encode(new Uint8Array(data));\n }\n if (Array.isArray(data)) {\n return bs58.encode(new Uint8Array(data));\n }\n return bs58.encode(data);\n};\n\n/**\n * Decodes a base58 string to binary data using Bitcoin's base58 alphabet.\n * Returns a Uint8Array containing the decoded bytes.\n *\n * @param base58String - Base58-encoded string to decode\n * @returns Uint8Array containing the decoded bytes\n * @throws Error if input contains invalid base58 characters\n */\nexport const base58Decode = (base58String: string): Uint8Array => {\n return bs58.decode(base58String);\n};\n\n","/**\n * Device detection utilities for camera and UI optimization\n */\n\nexport type DeviceType = 'mobile' | 'tablet' | 'desktop';\nexport type CameraFacingMode = 'user' | 'environment';\n\n/**\n * Detects the current device type based on multiple indicators\n */\nexport const detectDeviceType = (): DeviceType => {\n // Method 1: User agent detection\n const userAgent = navigator.userAgent.toLowerCase();\n const isMobileUA = /android|iphone|ipod|blackberry|iemobile|opera mini/i.test(userAgent);\n const isTabletUA = /ipad|tablet|kindle|playbook|silk/i.test(userAgent);\n\n // Method 2: Touch and screen size detection\n const isTouchDevice = navigator.maxTouchPoints > 0;\n const screenWidth = window.screen.width;\n const isSmallScreen = screenWidth <= 480;\n const isMediumScreen = screenWidth <= 1024;\n\n // Method 3: Orientation support (mobile/tablet indicator)\n const hasOrientation = 'orientation' in window;\n\n // Determine device type with priority: mobile > tablet > desktop\n if (isMobileUA || (isTouchDevice && isSmallScreen)) {\n return 'mobile';\n }\n\n if (isTabletUA || (isTouchDevice && isMediumScreen && hasOrientation)) {\n return 'tablet';\n }\n\n return 'desktop';\n};\n\n/**\n * Basic Safari detection (desktop Safari). Note: all iOS browsers use WebKit,\n * so use isIOS() to capture iOS Safari-like restrictions.\n */\nexport const isSafari = (): boolean => {\n try {\n const ua = navigator.userAgent;\n const isSafariEngine = /safari/i.test(ua) && !/chrome|crios|crmo|chromium|edg|edge|opr|opera|brave/i.test(ua);\n return isSafariEngine;\n } catch {\n return false;\n }\n};\n\n/**\n * Detect iOS (covers iPhone/iPad/iPod and iPadOS with desktop UA).\n * iOS has WebAuthn user-activation quirks that are shared by all iOS browsers.\n */\nexport const isIOS = (): boolean => {\n try {\n const ua = navigator.userAgent;\n const platform = (navigator as any).platform || '';\n const maxTouch = Number(navigator.maxTouchPoints || 0);\n const iOSUA = /iPad|iPhone|iPod/.test(ua);\n const iPadOSMacLike = /Macintosh/.test(ua) && maxTouch > 1; // iPadOS masquerading as Mac\n const iOSPlatform = /iPad|iPhone|iPod/.test(platform);\n return iOSUA || iPadOSMacLike || iOSPlatform;\n } catch {\n return false;\n }\n};\n\n/**\n * Detect Mobile Safari (iOS Safari specifically). Chrome/Firefox on iOS still use WebKit,\n * so for WebAuthn activation rules, prefer checking isIOS() as well.\n */\nexport const isMobileSafari = (): boolean => {\n try {\n const ua = navigator.userAgent;\n if (!isIOS()) return false;\n // Exclude Chrome/Firefox/Edge branded iOS browsers (still WebKit underneath)\n const branded = /crios|fxios|edgios|opios|mercury/i.test(ua);\n const safariToken = /safari/i.test(ua);\n return safariToken && !branded;\n } catch {\n return false;\n }\n};\n\n/**\n * Returns true when the page currently has a transient user activation\n * (click/tap/key within the allowed time window).\n */\nexport const hasActiveUserActivation = (): boolean => {\n try {\n const ua = (navigator as any).userActivation;\n return !!(ua && typeof ua.isActive === 'boolean' && ua.isActive);\n } catch {\n return false;\n }\n};\n\n/**\n * Heuristic: when on Safari/iOS or on a mobile device AND no active user\n * activation, we should surface a clickable UI to capture activation.\n */\nexport const needsExplicitActivation = (): boolean => {\n try {\n if (hasActiveUserActivation()) return false;\n return isIOS() || isMobileDevice() || isSafari();\n } catch {\n // In non-browser or SSR/test environments, avoid forcing UI changes\n return false;\n }\n};\n\n/**\n * Determines optimal camera facing mode based on device type\n * - Mobile/Tablet: Back camera (environment) for QR scanning\n * - Desktop/Laptop: Front camera (user) for video calls/selfies\n */\nexport const getOptimalCameraFacingMode = (): CameraFacingMode => {\n const deviceType = detectDeviceType();\n\n switch (deviceType) {\n case 'mobile':\n case 'tablet':\n console.log(`${deviceType} device detected - using back camera (environment)`);\n return 'environment';\n\n case 'desktop':\n default:\n return 'user';\n }\n};\n\n/**\n * Check if the current device is likely mobile\n */\nexport const isMobileDevice = (): boolean => {\n return detectDeviceType() === 'mobile';\n};\n\n/**\n * Check if the current device supports touch\n */\nexport const isTouchDevice = (): boolean => {\n return navigator.maxTouchPoints > 0;\n};\n\n/**\n * Get device capabilities for camera constraints\n */\nexport const getDeviceCapabilities = () => {\n const deviceType = detectDeviceType();\n const isTouch = isTouchDevice();\n const facingMode = getOptimalCameraFacingMode();\n\n return {\n deviceType,\n isTouch,\n recommendedFacingMode: facingMode,\n // Recommended camera constraints based on device\n cameraConstraints: {\n video: {\n facingMode,\n width: deviceType === 'mobile' ? { ideal: 720, min: 480 } : { ideal: 1280, min: 720 },\n height: deviceType === 'mobile' ? { ideal: 720, min: 480 } : { ideal: 720, min: 480 },\n aspectRatio: deviceType === 'mobile' ? { ideal: 1.0 } : { ideal: 16/9 }\n }\n }\n };\n};\n","export type ThresholdParticipantRole = 'client' | 'relayer';\n\nimport { toOptionalTrimmedString } from '../utils/validation';\nimport {\n THRESHOLD_ED25519_CLIENT_PARTICIPANT_ID,\n THRESHOLD_ED25519_RELAYER_PARTICIPANT_ID,\n THRESHOLD_ED25519_2P_PARTICIPANT_IDS,\n} from '../core/defaultConfigs';\n\nexport {\n THRESHOLD_ED25519_CLIENT_PARTICIPANT_ID,\n THRESHOLD_ED25519_RELAYER_PARTICIPANT_ID,\n THRESHOLD_ED25519_2P_PARTICIPANT_IDS,\n};\n\n/**\n * Metadata describing how a participant share is derived/stored.\n * This is informational in v1 and may be used for validation/policy later.\n */\nexport type ThresholdEd25519ShareDerivation =\n | 'prf_first_v1'\n | 'derived_master_secret_v1'\n | 'kv_random_v1'\n | 'unknown';\n\nexport interface ThresholdEd25519ParticipantV1 {\n /** FROST identifier (1-indexed). */\n id: number;\n role: ThresholdParticipantRole;\n /** Optional relayer endpoint for this participant (future multi-relayer support). */\n relayerUrl?: string;\n /** Key/share identifier understood by this participant (e.g. relayerKeyId). */\n relayerKeyId?: string;\n /** Base64url-encoded 32-byte verifying share (compressed EdwardsY). */\n verifyingShareB64u?: string;\n shareDerivation?: ThresholdEd25519ShareDerivation;\n}\n\nexport const THRESHOLD_ED25519_PARTICIPANT_SET_V1 = 'threshold_ed25519_participants_v1' as const;\n\nexport interface ThresholdEd25519ParticipantSetV1 {\n version: typeof THRESHOLD_ED25519_PARTICIPANT_SET_V1;\n groupPublicKey: string;\n participants: ThresholdEd25519ParticipantV1[];\n}\n\nexport function normalizeThresholdEd25519ParticipantId(id: unknown): number | null {\n const n = Number(id);\n if (!Number.isSafeInteger(n) || n < 1 || n > 65_535) return null;\n return n;\n}\n\nexport function normalizeThresholdEd25519ParticipantIds(input: unknown): number[] | null {\n if (!Array.isArray(input) || input.length === 0) return null;\n const out: number[] = [];\n const seen = new Set<number>();\n for (const v of input) {\n const id = normalizeThresholdEd25519ParticipantId(v);\n if (!id) return null;\n if (!seen.has(id)) {\n seen.add(id);\n out.push(id);\n }\n }\n out.sort((a, b) => a - b);\n return out.length ? out : null;\n}\n\nexport function areThresholdEd25519ParticipantIds2p(\n participantIds: number[] | null | undefined,\n expected: readonly number[] = THRESHOLD_ED25519_2P_PARTICIPANT_IDS,\n): boolean {\n const ids = normalizeThresholdEd25519ParticipantIds(participantIds);\n const expectedIds = normalizeThresholdEd25519ParticipantIds([...expected]);\n if (!ids || !expectedIds) return false;\n if (ids.length !== expectedIds.length) return false;\n return ids.every((id, i) => id === expectedIds[i]);\n}\n\nexport function parseThresholdEd25519ParticipantsV1(input: unknown): ThresholdEd25519ParticipantV1[] | null {\n if (!Array.isArray(input) || input.length === 0) return null;\n\n const out: ThresholdEd25519ParticipantV1[] = [];\n for (const item of input) {\n if (!item || typeof item !== 'object' || Array.isArray(item)) return null;\n const rec = item as Record<string, unknown>;\n\n const id = normalizeThresholdEd25519ParticipantId(rec.id);\n const role = toOptionalTrimmedString(rec.role);\n if (!id || (role !== 'client' && role !== 'relayer')) return null;\n\n const participant: ThresholdEd25519ParticipantV1 = {\n id,\n role: role as ThresholdParticipantRole,\n };\n\n const relayerUrl = toOptionalTrimmedString(rec.relayerUrl);\n if (relayerUrl) participant.relayerUrl = relayerUrl;\n\n const relayerKeyId = toOptionalTrimmedString(rec.relayerKeyId);\n if (relayerKeyId) participant.relayerKeyId = relayerKeyId;\n\n const verifyingShareB64u = toOptionalTrimmedString(rec.verifyingShareB64u);\n if (verifyingShareB64u) participant.verifyingShareB64u = verifyingShareB64u;\n\n const shareDerivation = toOptionalTrimmedString(rec.shareDerivation);\n if (\n shareDerivation === 'prf_first_v1'\n || shareDerivation === 'derived_master_secret_v1'\n || shareDerivation === 'kv_random_v1'\n || shareDerivation === 'unknown'\n ) {\n participant.shareDerivation = shareDerivation;\n }\n\n out.push(participant);\n }\n\n return out.length ? out : null;\n}\n\nexport function buildThresholdEd25519Participants2pV1(input: {\n clientParticipantId?: number | null;\n relayerParticipantId?: number | null;\n relayerKeyId: string;\n relayerUrl?: string | null;\n clientVerifyingShareB64u?: string | null;\n relayerVerifyingShareB64u?: string | null;\n clientShareDerivation?: ThresholdEd25519ShareDerivation | null;\n relayerShareDerivation?: ThresholdEd25519ShareDerivation | null;\n}): ThresholdEd25519ParticipantV1[] {\n const relayerKeyId = toOptionalTrimmedString(input.relayerKeyId);\n const relayerUrl = toOptionalTrimmedString(input.relayerUrl);\n const clientVerifyingShareB64u = toOptionalTrimmedString(input.clientVerifyingShareB64u);\n const relayerVerifyingShareB64u = toOptionalTrimmedString(input.relayerVerifyingShareB64u);\n const clientParticipantId =\n normalizeThresholdEd25519ParticipantId(input.clientParticipantId) ?? THRESHOLD_ED25519_CLIENT_PARTICIPANT_ID;\n const relayerParticipantId =\n normalizeThresholdEd25519ParticipantId(input.relayerParticipantId) ?? THRESHOLD_ED25519_RELAYER_PARTICIPANT_ID;\n\n const client: ThresholdEd25519ParticipantV1 = {\n id: clientParticipantId,\n role: 'client',\n ...(clientVerifyingShareB64u ? { verifyingShareB64u: clientVerifyingShareB64u } : {}),\n shareDerivation: input.clientShareDerivation || 'prf_first_v1',\n };\n\n const relayer: ThresholdEd25519ParticipantV1 = {\n id: relayerParticipantId,\n role: 'relayer',\n ...(relayerUrl ? { relayerUrl } : {}),\n ...(relayerKeyId ? { relayerKeyId } : {}),\n ...(relayerVerifyingShareB64u ? { verifyingShareB64u: relayerVerifyingShareB64u } : {}),\n ...(input.relayerShareDerivation ? { shareDerivation: input.relayerShareDerivation } : {}),\n };\n\n return [client, relayer];\n}\n","import { openDB, type IDBPDatabase } from 'idb';\nimport {\n buildThresholdEd25519Participants2pV1,\n parseThresholdEd25519ParticipantsV1,\n type ThresholdEd25519ParticipantV1,\n} from '../../threshold/participants';\n\nconst DB_CONFIG: PasskeyNearKeysDBConfig = {\n dbName: 'PasskeyNearKeys',\n // v4: allow storing multiple key materials per device (keyed by kind)\n dbVersion: 4,\n storeName: 'keyMaterial',\n keyPath: ['nearAccountId', 'deviceNumber', 'kind']\n} as const;\n\nexport type ClientShareDerivation = 'prf_first_v1';\n\nexport type PasskeyNearKeyMaterialKind =\n | 'local_near_sk_v3'\n | 'threshold_ed25519_2p_v1';\n\nexport interface BasePasskeyNearKeyMaterial {\n nearAccountId: string;\n deviceNumber: number; // 1-indexed device number\n kind: PasskeyNearKeyMaterialKind;\n /** NEAR ed25519 public key (e.g. `ed25519:...`) */\n publicKey: string;\n /** HKDF salt used alongside WrapKeySeed for KEK derivation */\n wrapKeySalt: string;\n timestamp: number;\n}\n\nexport interface LocalNearSkV3Material extends BasePasskeyNearKeyMaterial {\n kind: 'local_near_sk_v3';\n encryptedSk: string;\n /**\n * Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for `encryptedSk`.\n */\n chacha20NonceB64u: string;\n}\n\nexport interface ThresholdEd25519_2p_V1Material extends BasePasskeyNearKeyMaterial {\n kind: 'threshold_ed25519_2p_v1';\n relayerKeyId: string;\n clientShareDerivation: ClientShareDerivation;\n /**\n * Versioned participant list for future n-party support.\n * In 2P, participants are `{id:1, role:'client'}` and `{id:2, role:'relayer', ...}`.\n */\n participants: ThresholdEd25519ParticipantV1[];\n}\n\nexport type PasskeyNearKeyMaterial =\n | LocalNearSkV3Material\n | ThresholdEd25519_2p_V1Material;\n\ninterface PasskeyNearKeysDBConfig {\n dbName: string;\n dbVersion: number;\n storeName: string;\n keyPath: string | [string, string] | [string, string, string];\n}\n\nexport class PasskeyNearKeysDBManager {\n private config: PasskeyNearKeysDBConfig;\n private db: IDBPDatabase | null = null;\n private disabled = false;\n\n constructor(config: PasskeyNearKeysDBConfig = DB_CONFIG) {\n this.config = config;\n }\n\n getDbName(): string {\n return this.config.dbName;\n }\n\n setDbName(dbName: string): void {\n const next = String(dbName || '').trim();\n if (!next || next === this.config.dbName) return;\n try { (this.db as any)?.close?.(); } catch {}\n this.db = null;\n this.config = { ...this.config, dbName: next };\n }\n\n isDisabled(): boolean {\n return this.disabled;\n }\n\n setDisabled(disabled: boolean): void {\n const next = !!disabled;\n if (next === this.disabled) return;\n this.disabled = next;\n if (next) {\n try { (this.db as any)?.close?.(); } catch {}\n this.db = null;\n }\n }\n\n /**\n * Get database connection, initializing if necessary\n */\n private async getDB(): Promise<IDBPDatabase> {\n if (this.disabled) {\n throw new Error('[PasskeyNearKeysDBManager] IndexedDB is disabled in this environment.');\n }\n if (this.db) {\n return this.db;\n }\n\n this.db = await openDB(this.config.dbName, this.config.dbVersion, {\n upgrade(db): void {\n // Always recreate store with composite key; no migration.\n for (const name of ['encryptedKeys', DB_CONFIG.storeName]) {\n try { if (db.objectStoreNames.contains(name)) db.deleteObjectStore(name); } catch {}\n }\n const store = db.createObjectStore(DB_CONFIG.storeName, { keyPath: DB_CONFIG.keyPath });\n try { store.createIndex('nearAccountId', 'nearAccountId', { unique: false }); } catch {}\n try { store.createIndex('publicKey', 'publicKey', { unique: false }); } catch {}\n try { store.createIndex('kind', 'kind', { unique: false }); } catch {}\n },\n blocked() {\n console.warn('PasskeyNearKeysDB connection is blocked.');\n },\n blocking() {\n console.warn('PasskeyNearKeysDB connection is blocking another connection.');\n },\n terminated: () => {\n console.warn('PasskeyNearKeysDB connection has been terminated.');\n this.db = null;\n },\n });\n\n return this.db;\n }\n\n /**\n * Store encrypted key data\n */\n async storeKeyMaterial(data: PasskeyNearKeyMaterial): Promise<void> {\n const db = await this.getDB();\n if (!data.wrapKeySalt) {\n throw new Error('PasskeyNearKeysDB: Missing wrapKeySalt');\n }\n if (!data.publicKey) {\n throw new Error('PasskeyNearKeysDB: Missing publicKey');\n }\n\n if (data.kind === 'local_near_sk_v3') {\n if (!data.encryptedSk) {\n throw new Error('PasskeyNearKeysDB: Missing encryptedSk for local_near_sk_v3');\n }\n if (!data.chacha20NonceB64u) {\n throw new Error('PasskeyNearKeysDB: Missing chacha20NonceB64u for local_near_sk_v3');\n }\n } else if (data.kind === 'threshold_ed25519_2p_v1') {\n if (!data.relayerKeyId) {\n throw new Error('PasskeyNearKeysDB: Missing relayerKeyId for threshold_ed25519_2p_v1');\n }\n if (!data.clientShareDerivation) {\n throw new Error('PasskeyNearKeysDB: Missing clientShareDerivation for threshold_ed25519_2p_v1');\n }\n const parsed = parseThresholdEd25519ParticipantsV1(data.participants);\n data.participants = parsed || buildThresholdEd25519Participants2pV1({\n relayerKeyId: data.relayerKeyId,\n clientShareDerivation: data.clientShareDerivation,\n });\n }\n await db.put(this.config.storeName, data);\n }\n\n /**\n * Retrieve encrypted key data\n */\n async getKeyMaterial(\n nearAccountId: string,\n deviceNumber: number,\n kind: PasskeyNearKeyMaterialKind,\n ): Promise<PasskeyNearKeyMaterial | null> {\n const db = await this.getDB();\n if (!kind) {\n throw new Error('PasskeyNearKeysDB: kind is required (no fallback lookup is allowed)');\n }\n const sanitize = (rec: any): PasskeyNearKeyMaterial | null => {\n const kind = rec?.kind as PasskeyNearKeyMaterialKind | undefined;\n if (!rec?.nearAccountId || typeof rec?.deviceNumber !== 'number') return null;\n if (!kind) return null;\n if (!rec?.publicKey || !rec?.wrapKeySalt || typeof rec?.timestamp !== 'number') return null;\n\n if (kind === 'local_near_sk_v3') {\n if (!rec?.encryptedSk || !rec?.chacha20NonceB64u) return null;\n return {\n nearAccountId: rec.nearAccountId,\n deviceNumber: rec.deviceNumber,\n kind,\n publicKey: rec.publicKey,\n wrapKeySalt: rec.wrapKeySalt,\n encryptedSk: rec.encryptedSk,\n chacha20NonceB64u: rec.chacha20NonceB64u,\n timestamp: rec.timestamp,\n };\n }\n\n if (kind === 'threshold_ed25519_2p_v1') {\n if (!rec?.relayerKeyId || !rec?.clientShareDerivation) return null;\n const participants =\n parseThresholdEd25519ParticipantsV1(rec.participants)\n || buildThresholdEd25519Participants2pV1({\n relayerKeyId: rec.relayerKeyId,\n clientShareDerivation: rec.clientShareDerivation,\n });\n return {\n nearAccountId: rec.nearAccountId,\n deviceNumber: rec.deviceNumber,\n kind,\n publicKey: rec.publicKey,\n wrapKeySalt: rec.wrapKeySalt,\n relayerKeyId: rec.relayerKeyId,\n clientShareDerivation: rec.clientShareDerivation,\n participants,\n timestamp: rec.timestamp,\n };\n }\n\n return null;\n };\n\n const res = await db.get(this.config.storeName, [nearAccountId, deviceNumber, kind]);\n return sanitize(res);\n }\n\n async getLocalKeyMaterial(\n nearAccountId: string,\n deviceNumber: number\n ): Promise<LocalNearSkV3Material | null> {\n const rec = await this.getKeyMaterial(nearAccountId, deviceNumber, 'local_near_sk_v3');\n return rec?.kind === 'local_near_sk_v3' ? rec : null;\n }\n\n async getThresholdKeyMaterial(\n nearAccountId: string,\n deviceNumber: number\n ): Promise<ThresholdEd25519_2p_V1Material | null> {\n const rec = await this.getKeyMaterial(nearAccountId, deviceNumber, 'threshold_ed25519_2p_v1');\n return rec?.kind === 'threshold_ed25519_2p_v1' ? rec : null;\n }\n\n /**\n * Verify key storage by attempting retrieval\n */\n async verifyKeyStorage(\n nearAccountId: string,\n deviceNumber: number,\n kind: PasskeyNearKeyMaterialKind\n ): Promise<boolean> {\n const retrievedKey = await this.getKeyMaterial(nearAccountId, deviceNumber, kind);\n return !!retrievedKey;\n }\n\n /**\n * Delete encrypted key data for a specific account\n */\n async deleteKeyMaterial(nearAccountId: string, deviceNumber?: number, kind?: PasskeyNearKeyMaterialKind): Promise<void> {\n const db = await this.getDB();\n if (typeof deviceNumber === 'number' && kind) {\n await db.delete(this.config.storeName, [nearAccountId, deviceNumber, kind]);\n } else if (typeof deviceNumber === 'number') {\n // Delete all kinds for this deviceNumber\n const tx = db.transaction(this.config.storeName, 'readwrite');\n const idx = tx.store.index('nearAccountId');\n let cursor = await idx.openCursor(IDBKeyRange.only(nearAccountId));\n while (cursor) {\n const value: any = cursor.value;\n if (value?.deviceNumber === deviceNumber) {\n await tx.store.delete(cursor.primaryKey);\n }\n cursor = await cursor.continue();\n }\n await tx.done;\n } else {\n // Delete all keys for this account if device unspecified\n const tx = db.transaction(this.config.storeName, 'readwrite');\n const idx = tx.store.index('nearAccountId');\n let cursor = await idx.openCursor(IDBKeyRange.only(nearAccountId));\n while (cursor) {\n await tx.store.delete(cursor.primaryKey);\n cursor = await cursor.continue();\n }\n await tx.done;\n }\n console.debug('PasskeyNearKeysDB: deleteKeyMaterial - Successfully deleted');\n }\n\n /**\n * Get all encrypted keys (for migration or debugging purposes)\n */\n async getAllKeyMaterial(): Promise<PasskeyNearKeyMaterial[]> {\n const db = await this.getDB();\n const all = await db.getAll(this.config.storeName);\n return (all as any[])\n .map((rec) => {\n const kind = rec?.kind as PasskeyNearKeyMaterialKind | undefined;\n if (!kind) return null;\n\n if (kind === 'local_near_sk_v3') {\n if (!rec?.encryptedSk || !rec?.chacha20NonceB64u) return null;\n return {\n nearAccountId: rec.nearAccountId,\n deviceNumber: rec.deviceNumber,\n kind,\n publicKey: rec.publicKey,\n wrapKeySalt: rec.wrapKeySalt,\n encryptedSk: rec.encryptedSk,\n chacha20NonceB64u: rec.chacha20NonceB64u,\n timestamp: rec.timestamp,\n } as LocalNearSkV3Material;\n }\n\n if (kind === 'threshold_ed25519_2p_v1') {\n if (!rec?.relayerKeyId || !rec?.clientShareDerivation) return null;\n const participants =\n parseThresholdEd25519ParticipantsV1(rec.participants)\n || buildThresholdEd25519Participants2pV1({\n relayerKeyId: rec.relayerKeyId,\n clientShareDerivation: rec.clientShareDerivation,\n });\n return {\n nearAccountId: rec.nearAccountId,\n deviceNumber: rec.deviceNumber,\n kind,\n publicKey: rec.publicKey,\n wrapKeySalt: rec.wrapKeySalt,\n relayerKeyId: rec.relayerKeyId,\n clientShareDerivation: rec.clientShareDerivation,\n participants,\n timestamp: rec.timestamp,\n } as ThresholdEd25519_2p_V1Material;\n }\n\n return null;\n })\n .filter((rec): rec is PasskeyNearKeyMaterial => rec !== null);\n }\n\n /**\n * Check if a key exists for the given account\n */\n async hasKeyMaterial(\n nearAccountId: string,\n deviceNumber: number,\n kind: PasskeyNearKeyMaterialKind\n ): Promise<boolean> {\n const keyData = await this.getKeyMaterial(nearAccountId, deviceNumber, kind);\n return !!keyData;\n }\n}\n","export { PasskeyClientDBManager } from './passkeyClientDB';\nexport { PasskeyNearKeysDBManager } from './passkeyNearKeysDB';\n\nexport type {\n ClientUserData,\n UserPreferences,\n ClientAuthenticatorData,\n IndexedDBEvent,\n DerivedAddressRecord,\n RecoveryEmailRecord\n} from './passkeyClientDB';\n\nexport type {\n PasskeyNearKeyMaterial,\n LocalNearSkV3Material,\n ThresholdEd25519_2p_V1Material,\n PasskeyNearKeyMaterialKind,\n ClientShareDerivation,\n} from './passkeyNearKeysDB';\n\nimport { AccountId } from '../types/accountIds';\n\n// === SINGLETON INSTANCES ===\nimport { PasskeyClientDBManager, type ClientUserData } from './passkeyClientDB';\nimport { PasskeyNearKeysDBManager, type PasskeyNearKeyMaterial } from './passkeyNearKeysDB';\n\n// Export singleton instances for backward compatibility with existing code\nexport const passkeyClientDB = new PasskeyClientDBManager();\nexport const passkeyNearKeysDB = new PasskeyNearKeysDBManager();\n\nexport type IndexedDBMode = 'legacy' | 'wallet' | 'disabled';\n\nconst DB_CONFIG_BY_MODE: Record<IndexedDBMode, { clientDbName: string; nearKeysDbName: string; disabled: boolean }> = {\n legacy: { clientDbName: 'PasskeyClientDB', nearKeysDbName: 'PasskeyNearKeys', disabled: false },\n wallet: { clientDbName: 'PasskeyClientDB', nearKeysDbName: 'PasskeyNearKeys', disabled: false },\n // When running the SDK on the app origin with a wallet iframe configured, we disable IndexedDB entirely\n // to ensure no SDK tables are created and nothing can accidentally persist there.\n disabled: { clientDbName: 'PasskeyClientDB', nearKeysDbName: 'PasskeyNearKeys', disabled: true },\n};\n\nlet configured: { mode: IndexedDBMode; clientDbName: string; nearKeysDbName: string; disabled: boolean } | null = null;\n\n/**\n * Configure IndexedDB database names for the current runtime.\n *\n * Call this once, early (before any IndexedDB access).\n * - Wallet iframe host should use `mode: 'wallet'`.\n * - App origin should use `mode: 'disabled'` when wallet-iframe mode is enabled.\n * - Non-iframe apps should use `mode: 'legacy'`.\n */\nexport function configureIndexedDB(args: { mode: IndexedDBMode }): { clientDbName: string; nearKeysDbName: string } {\n const mode = args?.mode;\n const next = DB_CONFIG_BY_MODE[mode];\n if (!next) {\n throw new Error(`[IndexedDBManager] Unknown IndexedDBMode: ${String(mode)}`);\n }\n\n if (configured) {\n const isSame =\n configured.clientDbName === next.clientDbName\n && configured.nearKeysDbName === next.nearKeysDbName\n && configured.disabled === next.disabled;\n if (!isSame) {\n console.warn('[IndexedDBManager] configureIndexedDB called multiple times; ignoring subsequent configuration', {\n configured,\n requested: next,\n });\n }\n return { clientDbName: configured.clientDbName, nearKeysDbName: configured.nearKeysDbName };\n }\n\n configured = { mode, ...next };\n passkeyClientDB.setDbName(next.clientDbName);\n passkeyNearKeysDB.setDbName(next.nearKeysDbName);\n passkeyClientDB.setDisabled(next.disabled);\n passkeyNearKeysDB.setDisabled(next.disabled);\n return { clientDbName: configured.clientDbName, nearKeysDbName: configured.nearKeysDbName };\n}\n\nexport function getIndexedDBNames(): { clientDbName: string; nearKeysDbName: string } {\n return configured || {\n clientDbName: passkeyClientDB.getDbName(),\n nearKeysDbName: passkeyNearKeysDB.getDbName(),\n };\n}\n\n/**\n * Unified IndexedDB interface providing access to both databases\n * This allows centralized access while maintaining separation of concerns\n */\nexport class UnifiedIndexedDBManager {\n public readonly clientDB: PasskeyClientDBManager;\n public readonly nearKeysDB: PasskeyNearKeysDBManager;\n private _initialized = false;\n\n constructor() {\n this.clientDB = passkeyClientDB;\n this.nearKeysDB = passkeyNearKeysDB;\n }\n\n /**\n * Initialize both databases proactively\n * This ensures both databases are created and ready for use\n */\n async initialize(): Promise<void> {\n if (this._initialized) {\n return;\n }\n\n try {\n if (this.clientDB.isDisabled() || this.nearKeysDB.isDisabled()) {\n this._initialized = true;\n return;\n }\n // Initialize both databases by calling a simple operation\n // This will trigger the getDB() method in both managers and ensure databases are created\n await Promise.all([\n this.clientDB.getAppState('_init_check'),\n this.nearKeysDB.hasKeyMaterial('_init_check', 1, 'local_near_sk_v3')\n ]);\n\n this._initialized = true;\n } catch (error) {\n console.warn('Failed to initialize IndexedDB databases:', error);\n // Don't throw - allow the SDK to continue working, databases will be initialized on first use\n }\n }\n\n /**\n * Check if databases have been initialized\n */\n get isInitialized(): boolean {\n return this._initialized;\n }\n\n // === CONVENIENCE METHODS ===\n\n /**\n * Get user data and check if they have encrypted NEAR keys\n */\n async getUserWithKeys(nearAccountId: AccountId): Promise<{\n userData: ClientUserData | null;\n hasKeys: boolean;\n keyMaterial?: PasskeyNearKeyMaterial | null;\n }> {\n const last = await this.clientDB.getLastUser();\n const userData = last && last.nearAccountId === nearAccountId\n ? last\n : await this.clientDB.getUserByDevice(nearAccountId, 1);\n const deviceNumber = (last && last.nearAccountId === nearAccountId)\n ? last.deviceNumber\n : userData?.deviceNumber!;\n const [local, threshold] = await Promise.all([\n this.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber),\n this.nearKeysDB.getThresholdKeyMaterial(nearAccountId, deviceNumber),\n ]);\n const keyData = local ?? threshold;\n const hasKeys = !!keyData;\n\n return {\n userData,\n hasKeys,\n keyMaterial: hasKeys ? keyData : undefined\n };\n }\n\n // === Derived addresses convenience ===\n async setDerivedAddress(\n nearAccountId: AccountId,\n args: { contractId: string; path: string; address: string }\n ): Promise<void> {\n return this.clientDB.setDerivedAddress(nearAccountId, args);\n }\n\n async getDerivedAddressRecord(\n nearAccountId: AccountId,\n args: { contractId: string; path: string }\n ): Promise<import('./passkeyClientDB').DerivedAddressRecord | null> {\n return this.clientDB.getDerivedAddressRecord(nearAccountId, args);\n }\n\n async getDerivedAddress(\n nearAccountId: AccountId,\n args: { contractId: string; path: string }\n ): Promise<string | null> {\n return this.clientDB.getDerivedAddress(nearAccountId, args);\n }\n\n // === Recovery emails convenience ===\n async upsertRecoveryEmails(\n nearAccountId: AccountId,\n entries: Array<{ hashHex: string; email: string }>\n ): Promise<void> {\n return this.clientDB.upsertRecoveryEmails(nearAccountId, entries);\n }\n\n async getRecoveryEmails(nearAccountId: AccountId): Promise<import('./passkeyClientDB').RecoveryEmailRecord[]> {\n return this.clientDB.getRecoveryEmails(nearAccountId);\n }\n}\n\n// Export singleton instance of unified manager\nexport const IndexedDBManager = new UnifiedIndexedDBManager();\n","import { RpcResponse } from './types/rpc';\n\ntype NearRpcErrorType = 'InvalidTxError' | 'ActionError' | 'TxExecutionError' | 'RpcError' | 'Failure' | 'Unknown';\n\nfunction isObj(v: unknown): v is Record<string, unknown> {\n return !!v && typeof v === 'object' && !Array.isArray(v);\n}\n\nfunction firstKey(o: Record<string, unknown> | undefined): string | undefined {\n if (!o) return undefined;\n const keys = Object.keys(o);\n return keys.length ? keys[0] : undefined;\n}\n\nexport class NearRpcError extends Error {\n code?: number;\n type: NearRpcErrorType;\n kind?: string;\n index?: number;\n short: string;\n details?: unknown;\n operation?: string;\n\n constructor(params: {\n message: string;\n short: string;\n type?: NearRpcErrorType;\n kind?: string;\n index?: number;\n code?: number;\n name?: string;\n operation?: string;\n details?: unknown;\n }) {\n super(params.message);\n this.name = params.name || 'NearRpcError';\n this.code = params.code;\n this.type = params.type || 'Unknown';\n this.kind = params.kind;\n this.index = params.index;\n this.short = params.short;\n this.details = params.details;\n this.operation = params.operation;\n }\n\n static fromRpcResponse(operationName: string, rpc: RpcResponse): NearRpcError {\n const err = rpc.error || {};\n const details = err.data as unknown;\n\n const { message, type, kind, index, short } = describeDetails(operationName, details);\n\n return new NearRpcError({\n message: message || err.message || `${operationName} RPC error`,\n short: short || kind || 'RPC error',\n type: type || 'RpcError',\n kind,\n index,\n code: err.code,\n name: err.name || 'NearRpcError',\n operation: operationName,\n details,\n });\n }\n\n static fromOutcome(operationName: string, outcome: any, failure: any): NearRpcError {\n const { message, type, kind, index, short } = describeFailure(operationName, failure);\n return new NearRpcError({\n message: message || `${operationName} failed`,\n short: short || kind || 'TxExecutionError',\n type: type || 'Failure',\n kind,\n index,\n name: 'TxExecutionFailure',\n operation: operationName,\n details: { Failure: failure, outcome },\n });\n }\n}\n\nfunction describeDetails(operationName: string, details: unknown): {\n message: string;\n type?: NearRpcErrorType;\n kind?: string;\n index?: number;\n short?: string;\n} {\n const d = isObj(details) ? details : undefined;\n const txExec = isObj(d?.TxExecutionError) ? (d!.TxExecutionError as Record<string, unknown>) : undefined;\n if (!txExec) {\n const dataStr = d ? ` Details: ${JSON.stringify(d)}` : '';\n return { message: `${operationName} RPC error.${dataStr}` };\n }\n return describeTxExecution(operationName, txExec);\n}\n\nfunction describeFailure(operationName: string, failure: any): {\n message: string;\n type?: NearRpcErrorType;\n kind?: string;\n index?: number;\n short?: string;\n} {\n const f = isObj(failure) ? (failure as Record<string, unknown>) : undefined;\n if (!f) {\n return { message: `${operationName} failed (Unknown Failure)` };\n }\n // Reuse TxExecutionError shape if available\n return describeTxExecution(operationName, f as Record<string, unknown>);\n}\n\nfunction describeTxExecution(operationName: string, exec: Record<string, unknown>): {\n message: string;\n type?: NearRpcErrorType;\n kind?: string;\n index?: number;\n short?: string;\n} {\n // InvalidTxError\n if (isObj(exec.InvalidTxError)) {\n const inv = exec.InvalidTxError as Record<string, unknown>;\n let kind = firstKey(inv) || 'InvalidTxError';\n if (isObj(inv.ActionsValidation)) {\n kind = `ActionsValidation.${firstKey(inv.ActionsValidation as Record<string, unknown>)}`;\n }\n const short = kind.startsWith('ActionsValidation.')\n ? `InvalidTxError: ${kind.split('.')[1] || 'ActionsValidation'}`\n : `InvalidTxError: ${kind}`;\n return {\n message: `${operationName} failed (InvalidTxError: ${kind})`,\n type: 'InvalidTxError',\n kind,\n short,\n };\n }\n\n // ActionError\n if (isObj(exec.ActionError)) {\n const ae = exec.ActionError as Record<string, unknown>;\n const idx = typeof (ae.index as unknown) === 'number' ? (ae.index as number) : undefined;\n const kobj = isObj(ae.kind) ? (ae.kind as Record<string, unknown>) : undefined;\n const kind = firstKey(kobj) || 'ActionError';\n const idxStr = typeof idx === 'number' ? ` at action ${idx}` : '';\n const short = `ActionError: ${kind}`;\n return {\n message: `${operationName} failed${idxStr} (ActionError: ${kind})`,\n type: 'ActionError',\n kind,\n index: idx,\n short,\n };\n }\n\n // Fallback TxExecutionError without specifics\n return {\n message: `${operationName} failed (TxExecutionError)`,\n type: 'TxExecutionError',\n kind: 'TxExecutionError',\n short: 'TxExecutionError',\n };\n}\n","import type { AccessKeyView, TxExecutionStatus } from \"@near-js/types\";\n\nexport const DEFAULT_WAIT_STATUS = {\n executeAction: \"EXECUTED_OPTIMISTIC\" as TxExecutionStatus,\n linkDeviceAddKey: \"INCLUDED_FINAL\" as TxExecutionStatus,\n // Threshold AddKey is safe to treat optimistically; finality will converge shortly after.\n thresholdAddKey: \"EXECUTED_OPTIMISTIC\" as TxExecutionStatus,\n linkDeviceSwapKey: \"FINAL\" as TxExecutionStatus,\n linkDeviceAccountMapping: \"INCLUDED_FINAL\" as TxExecutionStatus,\n linkDeviceDeleteKey: \"INCLUDED_FINAL\" as TxExecutionStatus,\n linkDeviceRegistration: \"FINAL\" as TxExecutionStatus,\n // See default finality settings:\n // https://github.com/near/near-api-js/blob/99f34864317725467a097dc3c7a3cc5f7a5b43d4/packages/accounts/src/account.ts#L68\n}\n\n// Transaction and Signature types - defined as TypeScript interfaces since they're handled as JSON\nexport interface TransactionStruct {\n signerAccount: string;\n publicKey: {\n keyType: number;\n keyData: number[];\n };\n nonce: number;\n receiverAccount: string;\n blockHash: number[];\n actions: any[]; // Actions are complex, handled as JSON\n}\n\nexport interface SignatureStruct {\n keyType: number;\n signatureData: number[];\n}\n\nexport interface NearRpcCallParams {\n jsonrpc: string;\n id: string;\n method: string;\n params: {\n signed_tx_base64: string;\n wait_until: TxExecutionStatus;\n }\n}\n\nexport interface TransactionContext {\n nearPublicKeyStr: string;\n accessKeyInfo: AccessKeyView;\n nextNonce: string;\n txBlockHeight: string;\n txBlockHash: string;\n}\n\nexport interface BlockInfo {\n header: {\n hash: string;\n height: number;\n };\n}\nexport interface RpcErrorData {\n // NEAR error payloads vary; keep flexible but preserve common fields\n // Top-level helper message if present\n message?: string;\n // Anything else from the node (TxExecutionError, ActionError, etc.)\n [key: string]: any;\n}\n\nexport interface RpcError {\n code?: number;\n name?: string;\n data?: RpcErrorData;\n message?: string;\n}\n\nexport interface RpcResponse {\n error?: RpcError;\n result?: any;\n}\n","/**\n * Minimal NEAR RPC client that replaces @near-js/providers\n * Only includes the methods actually used by TatchiPasskey\n *\n * If needed, we can just wrap @near-js if we require more complex\n * functionality and type definitions\n */\n\nimport type {\n FinalExecutionOutcome,\n QueryResponseKind,\n TxExecutionStatus,\n AccessKeyView,\n AccessKeyInfoView,\n AccessKeyList,\n FunctionCallPermissionView,\n AccountView,\n BlockResult,\n BlockReference,\n RpcQueryRequest,\n FinalityReference,\n} from \"@near-js/types\";\nimport { base64Encode, base64Decode } from \"../utils\";\nimport { errorMessage } from \"../utils/errors\";\nimport { NearRpcError } from \"./NearRpcError\";\nimport { DEFAULT_WAIT_STATUS, RpcResponse } from \"./types/rpc\";\nimport { isFunction } from '@/utils/validation';\nimport {\n WasmTransaction,\n WasmSignature,\n} from \"../wasm_signer_worker/pkg/wasm_signer_worker.js\";\n\n// re-export near-js types\nexport type { AccessKeyList } from \"@near-js/types\";\n\nexport interface ViewAccountParams {\n account: string;\n block_id?: string;\n}\n\nexport type FullAccessKey = Omit<AccessKeyInfoView, 'access_key'>\n & { access_key: Omit<AccessKeyView, 'permission'> & { permission: 'FullAccess' } }\n\nexport type FunctionCallAccessKey = Omit<AccessKeyInfoView, 'access_key'>\n & { access_key: Omit<AccessKeyView, 'permission'> & { permission: FunctionCallPermissionView } }\n\nexport interface ContractResult<T> extends QueryResponseKind {\n result?: T | string | number;\n logs: string[];\n}\n\nexport enum RpcCallType {\n Query = \"query\",\n View = \"view\",\n Send = \"send_tx\",\n Block = \"block\",\n Call = \"call_function\",\n}\n\nexport class SignedTransaction {\n transaction: WasmTransaction;\n signature: WasmSignature;\n borsh_bytes: number[];\n\n constructor(data: {\n transaction: WasmTransaction;\n signature: WasmSignature;\n borsh_bytes: number[]\n }) {\n this.transaction = data.transaction;\n this.signature = data.signature;\n this.borsh_bytes = data.borsh_bytes;\n }\n\n static fromPlain(input: { transaction: unknown; signature: unknown; borsh_bytes: number[] }): SignedTransaction {\n return new SignedTransaction({\n transaction: input.transaction as WasmTransaction,\n signature: input.signature as WasmSignature,\n borsh_bytes: input.borsh_bytes,\n });\n }\n\n encode(): ArrayBuffer {\n // If borsh_bytes are already available, use them\n return (new Uint8Array(this.borsh_bytes)).buffer;\n }\n\n base64Encode(): string {\n return base64Encode(this.encode());\n }\n\n static decode(bytes: Uint8Array): SignedTransaction {\n // This would need borsh deserialization\n throw new Error('SignedTransaction.decode(): borsh deserialization not implemented');\n }\n}\n\n/**\n * Serialize a signed transaction-like object to base64.\n * Accepts either our SignedTransaction instance or a plain object\n * with borsh bytes (borsh_bytes | borshBytes) from cross-origin RPC.\n *\n * Implementation notes / pitfalls:\n * - We always bind `this` correctly when calling .base64Encode() / .encode()\n * so methods defined on SignedTransaction can safely call this.encode().\n * - The underlying base64Encode() helper is implemented to avoid spreading large\n * Uint8Arrays into String.fromCharCode(...), which can overflow the JS call\n * stack for big WASM binaries or large transactions.\n * - As a fallback, we accept raw borsh bytes in multiple shapes to keep the\n * serializer resilient to different runtimes (plain objects, typed arrays, etc.).\n */\nexport type EncodableSignedTx =\n | SignedTransaction\n | {\n // Borsh bytes in various shapes from different runtimes\n borsh_bytes?: unknown;\n borshBytes?: unknown;\n // Optional helper methods from some callers\n encode?: () => ArrayBuffer;\n base64Encode?: () => string;\n };\n\nexport function toArrayBufferFromUnknownBytes(\n bytes: unknown\n): ArrayBuffer | SharedArrayBuffer | null {\n if (!bytes) return null;\n\n // Plain number[]\n if (Array.isArray(bytes)) {\n return new Uint8Array(bytes as number[]).buffer;\n }\n\n // Typed arrays / DataView\n if (ArrayBuffer.isView(bytes)) {\n const view = bytes as ArrayBufferView;\n return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength);\n }\n\n // Raw ArrayBuffer\n if (bytes instanceof ArrayBuffer) {\n return bytes;\n }\n\n return null;\n}\n\nexport function encodeSignedTransactionBase64(signed: EncodableSignedTx): string {\n // Some call sites wrap the actual SignedTransaction in a { signedTransaction } envelope.\n // Normalize that here so the rest of the function always works with a concrete tx-like object.\n const maybeSigned = (signed as any)?.signedTransaction;\n const txPayload: EncodableSignedTx =\n maybeSigned && typeof maybeSigned === 'object'\n ? (maybeSigned as EncodableSignedTx)\n : signed;\n\n // 1) If the payload exposes a .base64Encode() helper (our SignedTransaction class),\n // use it directly. Bind `this` so the method can safely call this.encode().\n const maybeBase64 = (txPayload as { base64Encode?: unknown }).base64Encode;\n if (isFunction(maybeBase64)) {\n return (maybeBase64 as () => string).call(txPayload);\n }\n\n // 2) Otherwise, fall back to a generic encode() → ArrayBuffer method if present.\n const maybeEncode = (txPayload as { encode?: unknown }).encode;\n if (isFunction(maybeEncode)) {\n const buf = (maybeEncode as () => ArrayBuffer).call(txPayload);\n return base64Encode(buf);\n }\n\n // 3) Finally, accept raw borsh bytes in multiple shapes / field names.\n // This keeps the serializer resilient across runtimes that may not\n // hydrate SignedTransaction instances but still provide borsh_bytes/Bytes.\n const snakeBuf = toArrayBufferFromUnknownBytes(\n (txPayload as { borsh_bytes?: unknown }).borsh_bytes\n );\n if (snakeBuf) {\n return base64Encode(snakeBuf);\n }\n\n const camelBuf = toArrayBufferFromUnknownBytes(\n (txPayload as { borshBytes?: unknown }).borshBytes\n );\n if (camelBuf) {\n return base64Encode(camelBuf);\n }\n\n throw new Error('Invalid signed transaction payload: cannot serialize to base64');\n}\n\n/**\n * MinimalNearClient provides a simplified interface for NEAR protocol interactions\n */\nexport interface NearClient {\n viewAccessKey(accountId: string, publicKey: string, finalityQuery?: FinalityReference): Promise<AccessKeyView>;\n viewAccessKeyList(accountId: string, finalityQuery?: FinalityReference): Promise<AccessKeyList>;\n viewAccount(accountId: string): Promise<AccountView>;\n viewCode(accountId: string, finalityQuery?: FinalityReference): Promise<Uint8Array>;\n viewBlock(params: BlockReference): Promise<BlockResult>;\n sendTransaction(\n signedTransaction: SignedTransaction,\n waitUntil?: TxExecutionStatus\n ): Promise<FinalExecutionOutcome>;\n txStatus(txHash: string, senderAccountId: string): Promise<FinalExecutionOutcome>;\n query<T extends QueryResponseKind>(params: RpcQueryRequest): Promise<T>;\n callFunction<A, T>(\n contractId: string,\n method: string,\n args: A,\n blockQuery?: BlockReference\n ): Promise<T>;\n view<A, T>(params: { account: string; method: string; args: A }): Promise<T>;\n getAccessKeys(params: ViewAccountParams): Promise<{\n fullAccessKeys: FullAccessKey[];\n functionCallAccessKeys: FunctionCallAccessKey[];\n }>;\n}\n\nexport class MinimalNearClient implements NearClient {\n private readonly rpcUrls: string[];\n\n constructor(rpcUrl: string | string[]) {\n this.rpcUrls = MinimalNearClient.normalizeRpcUrls(rpcUrl);\n }\n\n private static normalizeRpcUrls(input: string | string[]): string[] {\n const urls = Array.isArray(input)\n ? input\n : input\n .split(/[\\s,]+/)\n .map(url => url.trim())\n .filter(Boolean);\n\n const normalized = urls.map(url => {\n try {\n return new URL(url).toString();\n } catch (err) {\n const message = errorMessage(err) || `Invalid NEAR RPC URL: ${url}`;\n throw new Error(message);\n }\n });\n\n if (!normalized.length) {\n throw new Error('NEAR RPC URL cannot be empty');\n }\n\n return Array.from(new Set(normalized));\n }\n\n // ===========================\n // PRIVATE HELPER FUNCTIONS\n // ===========================\n\n /** Build a JSON-RPC 2.0 POST body (stringified). */\n private buildRequestBody<P>(method: string, params: P): string {\n return JSON.stringify({\n jsonrpc: '2.0',\n id: crypto.randomUUID(),\n method,\n params\n });\n }\n\n /** Perform a single POST to one endpoint and return parsed RpcResponse. */\n private async postOnce(url: string, requestBody: string): Promise<RpcResponse> {\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: requestBody\n });\n\n if (!response.ok) {\n throw new Error(`RPC request failed: ${response.status} ${response.statusText}`);\n }\n\n const text = await response.text();\n if (!text?.trim()) {\n throw new Error('Empty response from RPC server');\n }\n\n return JSON.parse(text) as RpcResponse;\n }\n\n /** Try each configured RPC endpoint in order and return the first successful RpcResponse. */\n private async requestWithFallback(requestBody: string): Promise<RpcResponse> {\n let lastError: unknown;\n for (const [index, url] of this.rpcUrls.entries()) {\n try {\n const result = await this.postOnce(url, requestBody);\n if (index > 0) console.warn(`[NearClient] RPC succeeded via fallback: ${url}`);\n return result;\n } catch (err) {\n lastError = err;\n const remaining = index < this.rpcUrls.length - 1;\n console.warn(`[NearClient] RPC call to ${url} failed${remaining ? ', trying next' : ''}: ${errorMessage(err) || 'RPC request failed'}`);\n if (!remaining) throw err instanceof Error ? err : new Error(String(err));\n }\n }\n throw new Error(errorMessage(lastError) || 'RPC request failed');\n }\n\n /** Validate and unwrap RpcResponse into the typed result with rich error forwarding. */\n private unwrapRpcResult<T>(rpc: RpcResponse, operationName: string): T {\n if (rpc.error) {\n throw NearRpcError.fromRpcResponse(operationName, rpc);\n }\n const result = rpc.result as any;\n // Some providers return a wrapped error in `result.error`\n if (result?.error) {\n const msg = typeof result.error === 'string' ? result.error : JSON.stringify(result.error);\n throw new NearRpcError({ message: `${operationName} Error: ${msg}`, short: 'RpcError', type: 'RpcError' });\n }\n return rpc.result as T;\n }\n\n /**\n * Execute RPC call with proper error handling and result extraction\n */\n private async makeRpcCall<P, T>(\n method: string,\n params: P,\n operationName: string\n ): Promise<T> {\n const requestBody = this.buildRequestBody(method, params);\n const rpc = await this.requestWithFallback(requestBody);\n return this.unwrapRpcResult<T>(rpc, operationName);\n }\n\n // ===========================\n // PUBLIC API METHODS\n // ===========================\n\n async query<T extends QueryResponseKind>(params: RpcQueryRequest): Promise<T> {\n return this.makeRpcCall<RpcQueryRequest, T>(RpcCallType.Query, params, 'Query');\n }\n\n async viewAccessKey(accountId: string, publicKey: string, finalityQuery?: FinalityReference): Promise<AccessKeyView> {\n const publicKeyStr = publicKey;\n const finality = finalityQuery?.finality || 'final';\n const params = {\n request_type: 'view_access_key',\n finality: finality,\n account_id: accountId,\n public_key: publicKeyStr\n };\n return this.makeRpcCall<typeof params, AccessKeyView>(\n RpcCallType.Query,\n params,\n 'View Access Key'\n );\n }\n\n async viewAccessKeyList(accountId: string, finalityQuery?: FinalityReference): Promise<AccessKeyList> {\n const finality = finalityQuery?.finality || 'final';\n const params = {\n request_type: 'view_access_key_list',\n finality: finality,\n account_id: accountId\n };\n return this.makeRpcCall<typeof params, AccessKeyList>(RpcCallType.Query, params, 'View Access Key List');\n }\n\n async viewAccount(accountId: string): Promise<AccountView> {\n const params = {\n request_type: 'view_account',\n finality: 'final',\n account_id: accountId\n };\n return this.makeRpcCall<typeof params, AccountView>(RpcCallType.Query, params, 'View Account');\n }\n\n async viewCode(accountId: string, finalityQuery?: FinalityReference): Promise<Uint8Array> {\n const finality = finalityQuery?.finality || 'final';\n const params = {\n request_type: 'view_code',\n finality,\n account_id: accountId\n };\n const result = await this.makeRpcCall<typeof params, any>(\n RpcCallType.Query,\n params,\n 'View Code'\n );\n const codeBase64 = result?.code_base64;\n if (typeof codeBase64 !== 'string' || !codeBase64.length) {\n throw new Error('Invalid View Code response: missing code_base64');\n }\n return base64Decode(codeBase64);\n }\n\n async viewBlock(params: BlockReference): Promise<BlockResult> {\n return this.makeRpcCall<BlockReference, BlockResult>(RpcCallType.Block, params, 'View Block');\n }\n\n async sendTransaction(\n signedTransaction: SignedTransaction,\n waitUntil: TxExecutionStatus = DEFAULT_WAIT_STATUS.executeAction\n ): Promise<FinalExecutionOutcome> {\n const params = {\n signed_tx_base64: encodeSignedTransactionBase64(signedTransaction),\n wait_until: waitUntil\n };\n\n // Retry on transient RPC errors commonly seen with shared/public nodes\n const maxAttempts = 5;\n let lastError: unknown = null;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n const outcome = await this.makeRpcCall<typeof params, FinalExecutionOutcome>(RpcCallType.Send, params, 'Send Transaction');\n // near-api-js throws on Failure; replicate that for clearer UX\n const status = (outcome as any)?.status;\n if (status && typeof status === 'object' && 'Failure' in status) {\n const failure = (status as any).Failure;\n throw NearRpcError.fromOutcome('Send Transaction', outcome, failure);\n }\n return outcome;\n } catch (err: unknown) {\n lastError = err;\n const msg = errorMessage(err);\n const retryable = /server error|internal|temporar|timeout|too many requests|429|unavailable|bad gateway|gateway timeout/i.test(msg || '');\n if (!retryable || attempt === maxAttempts) {\n throw err;\n }\n // Exponential backoff with jitter (200–1200ms approx across attempts)\n const base = 200 * Math.pow(2, attempt - 1);\n const jitter = Math.floor(Math.random() * 150);\n await new Promise(r => setTimeout(r, base + jitter));\n }\n }\n // Should be unreachable\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n }\n\n async txStatus(txHash: string, senderAccountId: string): Promise<FinalExecutionOutcome> {\n const params = {\n tx_hash: txHash,\n sender_account_id: senderAccountId,\n };\n return this.makeRpcCall<typeof params, FinalExecutionOutcome>(\n 'EXPERIMENTAL_tx_status',\n params,\n 'Tx Status'\n );\n }\n\n // legacy helpers removed in favor of NearRpcError\n\n async callFunction<A, T>(\n contractId: string,\n method: string,\n args: A,\n blockQuery?: BlockReference\n ): Promise<T> {\n const rpcParams = {\n request_type: 'call_function',\n finality: 'final',\n account_id: contractId,\n method_name: method,\n args_base64: base64Encode(new TextEncoder().encode(JSON.stringify(args)).buffer)\n };\n const result = await this.makeRpcCall<typeof rpcParams, ContractResult<T>>(\n RpcCallType.Query,\n rpcParams,\n 'View Function'\n );\n\n // Parse result bytes to string/JSON\n const resultBytes = result.result;\n\n if (!Array.isArray(resultBytes)) {\n // If result is not bytes array, it might already be parsed\n return result as unknown as T;\n }\n\n const resultString = String.fromCharCode(...resultBytes);\n\n if (!resultString.trim()) {\n return null as T;\n }\n\n try {\n const parsed = JSON.parse(resultString);\n return parsed as T;\n } catch (parseError) {\n console.warn('Failed to parse result as JSON, returning as string:', parseError);\n console.warn('Raw result string:', resultString);\n // Return the string value if it's not valid JSON\n const cleanString = resultString.replace(/^\"|\"$/g, ''); // Remove quotes\n return cleanString as T;\n }\n }\n\n async view<A, T>(params: { account: string; method: string; args: A }): Promise<T> {\n return this.callFunction<A, T>(params.account, params.method, params.args);\n }\n\n async getAccessKeys({ account, block_id }: ViewAccountParams): Promise<{\n fullAccessKeys: FullAccessKey[];\n functionCallAccessKeys: FunctionCallAccessKey[];\n }> {\n // Build RPC parameters similar to the official implementation\n const params: Record<string, unknown> = {\n request_type: 'view_access_key_list',\n account_id: account,\n finality: 'final'\n };\n\n // Add block_id if provided (for specific block queries)\n if (block_id) {\n params.block_id = block_id;\n delete params.finality; // block_id takes precedence over finality\n }\n\n // Make the RPC call directly to match the official implementation\n const accessKeyList = await this.makeRpcCall<typeof params, AccessKeyList>(\n RpcCallType.Query,\n params,\n 'View Access Key List'\n );\n\n // Separate full access keys and function call access keys\n const fullAccessKeys: FullAccessKey[] = [];\n const functionCallAccessKeys: FunctionCallAccessKey[] = [];\n\n // Process each access key (matching the official categorization logic)\n for (const key of accessKeyList.keys) {\n if (key.access_key.permission === 'FullAccess') {\n // Full Access Keys: Keys with FullAccess permission\n fullAccessKeys.push(key as FullAccessKey);\n } else if (key.access_key.permission && typeof key.access_key.permission === 'object' && 'FunctionCall' in key.access_key.permission) {\n // Function Call Keys: Keys with limited permissions for specific contract calls\n functionCallAccessKeys.push(key as FunctionCallAccessKey);\n }\n }\n\n return {\n fullAccessKeys,\n functionCallAccessKeys\n };\n }\n}\n","export const OFFLINE_EXPORT_DONE = 'OFFLINE_EXPORT_DONE';\nexport const OFFLINE_EXPORT_ERROR = 'OFFLINE_EXPORT_ERROR';\n\n// Posted by wallet host to request parent fallback to the offline route\nexport const OFFLINE_EXPORT_FALLBACK = 'OFFLINE_EXPORT_FALLBACK';\n\n// Reused wallet-iframe close notification\nexport const WALLET_UI_CLOSED = 'WALLET_UI_CLOSED';\n\n// Export UI: user explicitly cancelled TouchID/FaceID during key export\nexport const EXPORT_NEAR_KEYPAIR_CANCELLED = 'EXPORT_NEAR_KEYPAIR_CANCELLED';\n\nexport type OfflineExportDoneMsg = { type: typeof OFFLINE_EXPORT_DONE; nearAccountId: string };\nexport type OfflineExportErrorMsg = { type: typeof OFFLINE_EXPORT_ERROR; error: string };\nexport type WalletUiClosedMsg = { type: typeof WALLET_UI_CLOSED };\n\n// No inbound handshake is required in the new-tab flow\nexport type OfflineExportInboundMsg = never;\nexport type OfflineExportOutboundMsg =\n | OfflineExportDoneMsg\n | OfflineExportErrorMsg\n | WalletUiClosedMsg;\n","// Centralized build configuration\n// This file defines all paths used across the build system\n\nexport const BUILD_PATHS = {\n // Build output directories\n BUILD: {\n ROOT: 'dist',\n WORKERS: 'dist/workers',\n ESM: 'dist/esm',\n CJS: 'dist/cjs',\n TYPES: 'dist/types'\n },\n\n // Source directories\n SOURCE: {\n ROOT: 'src',\n CORE: 'src/core',\n WASM_SIGNER: 'src/wasm_signer_worker',\n WASM_VRF: 'src/wasm_vrf_worker',\n CRITICAL_DIRS: [\n 'src/core',\n 'src/wasm_signer_worker',\n 'src/wasm_vrf_worker'\n ]\n },\n\n // Frontend deployment paths\n FRONTEND: {\n ROOT: '../examples/vite/public',\n SDK: '../examples/vite/public/sdk',\n WORKERS: '../examples/vite/public/sdk/workers'\n },\n\n // Runtime paths (used by workers and tests)\n RUNTIME: {\n SDK_BASE: '/sdk',\n WORKERS_BASE: '/sdk/workers',\n VRF_WORKER: '/sdk/workers/web3authn-vrf.worker.js',\n SIGNER_WORKER: '/sdk/workers/web3authn-signer.worker.js'\n },\n\n // Worker file names\n WORKERS: {\n VRF: 'web3authn-vrf.worker.js',\n SIGNER: 'web3authn-signer.worker.js',\n OFFLINE_SW: 'offline-export-sw.js',\n WASM_VRF_JS: 'wasm_vrf_worker.js',\n WASM_VRF_WASM: 'wasm_vrf_worker_bg.wasm',\n WASM_SIGNER_JS: 'wasm_signer_worker.js',\n WASM_SIGNER_WASM: 'wasm_signer_worker_bg.wasm'\n },\n\n // Test worker file paths (for test files)\n TEST_WORKERS: {\n VRF: '/sdk/workers/web3authn-vrf.worker.js',\n SIGNER: '/sdk/workers/web3authn-signer.worker.js',\n WASM_VRF_JS: '/sdk/workers/wasm_vrf_worker.js',\n WASM_VRF_WASM: '/sdk/workers/wasm_vrf_worker_bg.wasm',\n WASM_SIGNER_JS: '/sdk/workers/wasm_signer_worker.js',\n WASM_SIGNER_WASM: '/sdk/workers/wasm_signer_worker_bg.wasm'\n }\n} as const;\n\n// Helper functions\nexport const getWorkerPath = (workerName: string): string => `${BUILD_PATHS.BUILD.WORKERS}/${workerName}`;\nexport const getRuntimeWorkerPath = (workerName: string): string => `${BUILD_PATHS.RUNTIME.WORKERS_BASE}/${workerName}`;\nexport const getFrontendWorkerPath = (workerName: string): string => `${BUILD_PATHS.FRONTEND.WORKERS}/${workerName}`;\n\n// Default export for easier importing\nexport default BUILD_PATHS;\n","import { BUILD_PATHS } from '../build-paths.js';\n\n// === CONFIGURATION ===\nexport const SIGNER_WORKER_MANAGER_CONFIG = {\n TIMEOUTS: {\n DEFAULT: 60_000, // 60s default fallback for worker operations\n TRANSACTION: 60_000, // 60s for contract verification + signing\n REGISTRATION: 60_000, // 60s for registration operations\n },\n WORKER: {\n URL: BUILD_PATHS.RUNTIME.SIGNER_WORKER,\n TYPE: 'module' as const,\n NAME: 'Web3AuthnSignerWorker',\n },\n RETRY: {\n MAX_ATTEMPTS: 3,\n BACKOFF_MS: 1000,\n }\n} as const;\n\n// === DEVICE LINKING CONFIGURATION ===\nexport const DEVICE_LINKING_CONFIG = {\n TIMEOUTS: {\n QR_CODE_MAX_AGE_MS: 15 * 60 * 1000, // 15 minutes - QR code expiration\n SESSION_EXPIRATION_MS: 15 * 60 * 1000, // 15 minutes - Device linking session timeout\n TEMP_KEY_CLEANUP_MS: 15 * 60 * 1000, // 15 minutes - Automatic cleanup of temporary keys\n POLLING_INTERVAL_MS: 3000, // 3 seconds - AddKey polling interval\n REGISTRATION_RETRY_DELAY_MS: 2000, // 2 seconds - Delay between registration retries\n },\n RETRY: {\n MAX_REGISTRATION_ATTEMPTS: 5, // Maximum registration retry attempts\n }\n} as const;\n","/**\n * SDK Base (wallet origin)\n *\n * The wallet iframe host announces the absolute SDK base URL so that all\n * embedded assets (host script, Lit bundles) and module workers resolve from\n * the wallet origin in production. This keeps sensitive execution isolated\n * under the wallet site while allowing cross‑origin embedding.\n *\n * Writers:\n * - Wallet iframe host (service) on boot and after PM_SET_CONFIG\n * - App provider hook in dev when walletOrigin is configured\n *\n * Readers:\n * - WebAuthnManager (to set worker base origin for managers)\n * - Lit wrappers (to resolve embedded script/css URLs)\n */\nexport const W3A_WALLET_SDK_BASE_KEY = '__W3A_WALLET_SDK_BASE__'\nexport const W3A_WALLET_SDK_BASE_EVENT = 'W3A_WALLET_SDK_BASE_CHANGED'\n\n/**\n * Typed CustomEvent emitted when the wallet SDK base changes.\n * Detail contains the absolute base URL string (e.g., `${walletOrigin}/sdk/`).\n */\nexport type WalletSdkBaseChangedEvent = CustomEvent<string>\n\nexport interface WalletSDKBase {\n [W3A_WALLET_SDK_BASE_KEY]?: string\n}\n\n/**\n * @returns Absolute SDK base URL (e.g., `${walletOrigin}/sdk/`) when set, otherwise undefined.\n */\nexport function getEmbeddedBase(): string | undefined {\n if (typeof window === 'undefined') return undefined\n const w = window as unknown as WalletSDKBase\n const v = w[W3A_WALLET_SDK_BASE_KEY]\n return typeof v === 'string' && v.length > 0 ? v : undefined\n}\n\n/**\n * @param url - Absolute SDK base URL (e.g., `${walletOrigin}/sdk/`).\n * @returns void\n */\nexport function setEmbeddedBase(url: string): void {\n if (typeof window === 'undefined') return\n const w = window as unknown as WalletSDKBase\n w[W3A_WALLET_SDK_BASE_KEY] = url\n window.dispatchEvent(new CustomEvent(W3A_WALLET_SDK_BASE_EVENT as any, { detail: url }))\n}\n\n/**\n * @param cb - Callback invoked with the new absolute base URL when it changes.\n * @returns Unsubscribe function to remove the listener.\n */\nexport function onEmbeddedBaseChange(cb: (url: string) => void): () => void {\n if (typeof window === 'undefined') return () => {}\n const handler = (e: WalletSdkBaseChangedEvent) => {\n const d = e.detail\n if (typeof d === 'string' && d.length > 0) cb(d)\n }\n window.addEventListener(W3A_WALLET_SDK_BASE_EVENT, handler as EventListener, { passive: true })\n return () => window.removeEventListener(W3A_WALLET_SDK_BASE_EVENT, handler as EventListener)\n}\n","/**\n * Resolve the base origin for worker scripts.\n * Priority:\n * 1) window.__W3A_WALLET_SDK_BASE__ (absolute `${walletOrigin}${sdkBasePath}/`) → take its origin (only if same-origin)\n * 2) window.location.origin (host/app origin)\n *\n * @returns The origin (protocol + host [+ port]) used to resolve worker script URLs.\n * Prefers the wallet SDK base origin; falls back to the current window origin.\n */\nexport function resolveWorkerBaseOrigin(): string {\n const currentOrigin =\n (typeof window !== 'undefined' && window.location?.origin)\n ? window.location.origin\n : '';\n\n // Only allow worker scripts to resolve from the embedded base when it matches\n // the current origin. Cross-origin worker scripts are not reliably loadable\n // across browsers (even for module workers) and will fail with CORS errors.\n try {\n const embeddedBase = (window as any)?.__W3A_WALLET_SDK_BASE__ as string | undefined;\n if (embeddedBase) {\n const embeddedOrigin = new URL(embeddedBase, currentOrigin || 'https://invalid.local').origin;\n if (embeddedOrigin === currentOrigin) {\n return embeddedOrigin;\n }\n }\n } catch {}\n\n return currentOrigin;\n}\n\n/**\n * Build an absolute worker script URL from a path or absolute URL.\n * If `input` is a path (e.g., `/sdk/workers/foo.js`), it will be resolved\n * against the wallet origin (from `__W3A_WALLET_SDK_BASE__`) when available,\n * otherwise against the host origin.\n *\n * @param input - Absolute URL or path (e.g., `/sdk/workers/web3authn-signer.worker.js`).\n * @returns Absolute URL to the worker script, resolved against the wallet origin when available,\n * otherwise against the current window origin.\n */\nexport function resolveWorkerScriptUrl(input: string): string {\n return resolveWorkerUrl(input, { worker: detectWorkerFromPath(input) })\n}\n\nexport function resolveWorkerUrl(\n input: string | undefined,\n opts: { worker: 'signer' | 'vrf'; baseOrigin?: string }\n): string {\n const worker = opts.worker\n const baseOrigin = opts.baseOrigin || resolveWorkerBaseOrigin() || (typeof window !== 'undefined' ? window.location.origin : '') || 'https://invalid.local'\n try {\n // Prefer explicit per-worker URL override\n const ovAny = (typeof window !== 'undefined' ? (window as any) : {}) as any\n const override = worker === 'signer' ? ovAny.__W3A_SIGNER_WORKER_URL__ : ovAny.__W3A_VRF_WORKER_URL__\n const candidate = (typeof override === 'string' && override) ? override : (input || defaultWorkerPath(worker))\n if (/^https?:\\/\\//i.test(candidate)) {\n return new URL(candidate).toString()\n }\n return new URL(candidate, baseOrigin).toString()\n } catch {\n try { return new URL(input || defaultWorkerPath(worker), baseOrigin).toString() } catch {}\n return input || defaultWorkerPath(worker)\n }\n}\n\nfunction detectWorkerFromPath(p: string): 'signer' | 'vrf' {\n return /web3authn-signer\\.worker\\.js(?:$|\\?)/.test(p) ? 'signer' : 'vrf'\n}\n\nfunction defaultWorkerPath(worker: 'signer' | 'vrf'): string {\n return worker === 'signer' ? '/sdk/workers/web3authn-signer.worker.js' : '/sdk/workers/web3authn-vrf.worker.js'\n}\n","/**\n * Control messages exchanged between worker shims and the main thread.\n *\n * These messages are JS-only and do NOT go through the Rust WASM JSON request/response pipeline.\n * They are used for:\n * - MessagePort attachment handshakes (WrapKeySeed delivery)\n * - Readiness signals (worker pool health checks)\n */\nexport const WorkerControlMessage = {\n ATTACH_WRAP_KEY_SEED_PORT: 'ATTACH_WRAP_KEY_SEED_PORT',\n ATTACH_WRAP_KEY_SEED_PORT_OK: 'ATTACH_WRAP_KEY_SEED_PORT_OK',\n ATTACH_WRAP_KEY_SEED_PORT_ERROR: 'ATTACH_WRAP_KEY_SEED_PORT_ERROR',\n WORKER_READY: 'WORKER_READY',\n} as const;\n\nexport type WorkerControlMessageType =\n (typeof WorkerControlMessage)[keyof typeof WorkerControlMessage];\n","/**\n * Session Message Handling for Signer Worker\n *\n * This module provides helpers for waiting on session lifecycle messages from the signer worker.\n * Session messages are JS-only messages that never go through the Rust JSON pipeline\n * and are used for worker lifecycle management and session setup.\n */\n\nimport { WorkerControlMessage } from '../../workerControlMessages';\n\n// === SESSION MESSAGE TYPES ===\n\n/**\n * Control message sent by the signer worker after successfully attaching\n * a WrapKeySeed MessagePort for a signing session.\n */\nexport interface AttachWrapKeySeedPortOkMessage {\n type: typeof WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_OK;\n sessionId: string;\n}\n\n/**\n * Control message sent by the signer worker when attaching a WrapKeySeed\n * MessagePort fails.\n */\nexport interface AttachWrapKeySeedPortErrorMessage {\n type: typeof WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_ERROR;\n sessionId: string;\n error: string;\n}\n\n/**\n * Control message sent by the signer worker when it's ready to receive messages.\n */\nexport interface WorkerReadyMessage {\n type: typeof WorkerControlMessage.WORKER_READY;\n ready: boolean;\n}\n\n/**\n * All control messages that can be sent by the signer worker.\n */\nexport type SignerWorkerControlMessage =\n | AttachWrapKeySeedPortOkMessage\n | AttachWrapKeySeedPortErrorMessage\n | WorkerReadyMessage;\n\nexport type SessionMessage = Record<string, unknown> & {\n type: string;\n sessionId?: string;\n error?: string;\n};\n\nfunction asSessionMessage(msg: unknown): SessionMessage | null {\n if (!isObject(msg)) return null;\n if (typeof msg.type !== 'string') return null;\n if (msg.sessionId != null && typeof msg.sessionId !== 'string') return null;\n if (msg.error != null && typeof msg.error !== 'string') return null;\n return msg as SessionMessage;\n}\n\n/**\n * Type guard to check if a message is a control message.\n */\nexport function isSignerWorkerControlMessage(msg: unknown): msg is SignerWorkerControlMessage {\n if (!isObject(msg) || typeof msg.type !== 'string') {\n return false;\n }\n\n switch (msg.type) {\n case WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_OK:\n return typeof msg.sessionId === 'string';\n case WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_ERROR:\n return typeof msg.sessionId === 'string' && typeof msg.error === 'string';\n case WorkerControlMessage.WORKER_READY:\n return typeof msg.ready === 'boolean';\n default:\n return false;\n }\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n// === SESSION MESSAGE HELPERS ===\n\n/**\n * Generic helper for waiting on session messages from a worker.\n * Registers a listener, sends no message (caller handles that), and waits for a matching response.\n *\n * @param worker - The worker to listen to\n * @param options - Configuration for what to wait for\n * @returns Promise that resolves when the expected message arrives, rejects on timeout or error\n */\nexport function waitForSessionMessage(\n worker: Worker,\n options: {\n /** Message type(s) to wait for (success) */\n successType: string | string[];\n /** Optional error type to reject on */\n errorType?: string;\n /** Session ID to match (if applicable) */\n sessionId?: string;\n /** Timeout in milliseconds */\n timeoutMs?: number;\n /** Custom message validator - return true to resolve, false to ignore, throw to reject */\n validator?: (msg: SessionMessage) => boolean;\n }\n): Promise<void> {\n const {\n successType,\n errorType,\n sessionId,\n timeoutMs = 2000,\n validator,\n } = options;\n\n const successTypes = Array.isArray(successType) ? successType : [successType];\n\n return new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n cleanup();\n reject(new Error(\n `Timeout waiting for session message (${successTypes.join('|')})${sessionId ? ` for session ${sessionId}` : ''}`\n ));\n }, timeoutMs);\n\n const messageHandler = (event: MessageEvent<unknown>) => {\n const msg = asSessionMessage(event.data);\n\n // Skip if message doesn't have a type\n if (!msg) return;\n\n // Check if sessionId matches (if specified)\n if (sessionId && msg.sessionId !== sessionId) {\n return;\n }\n\n // Check for error type\n if (errorType && msg.type === errorType) {\n cleanup();\n const error = msg.error || 'Unknown error';\n reject(new Error(`Session message error: ${error}`));\n return;\n }\n\n // Check for success type\n if (successTypes.includes(msg.type)) {\n // Run custom validator if provided\n if (validator) {\n try {\n const shouldResolve = validator(msg);\n if (!shouldResolve) {\n return; // Validator said to ignore this message\n }\n } catch (err) {\n cleanup();\n reject(err);\n return;\n }\n }\n\n cleanup();\n resolve();\n }\n };\n\n const cleanup = () => {\n clearTimeout(timeout);\n worker.removeEventListener('message', messageHandler);\n };\n\n worker.addEventListener('message', messageHandler);\n });\n}\n\n/**\n * Wait for the worker to acknowledge successful attachment of the WrapKeySeed port.\n * This provides early detection of attach failures instead of only seeing late WASM errors.\n *\n * @param worker - The worker that should send the ACK\n * @param sessionId - The session ID to match\n * @param timeoutMs - How long to wait before rejecting (default: 2000ms)\n * @returns Promise that resolves on success ACK, rejects on error or timeout\n */\nexport function waitForWrapKeyPortAttach(\n worker: Worker,\n sessionId: string,\n timeoutMs: number = 2000\n): Promise<void> {\n return waitForSessionMessage(worker, {\n successType: WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_OK,\n errorType: WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_ERROR,\n sessionId,\n timeoutMs,\n });\n}\n","import type { TxExecutionStatus } from '@near-js/types';\nimport type { ConfirmationConfig, SignerMode, ThresholdBehavior } from './signer-worker';\nimport type {\n ActionResult,\n DelegateRelayResult,\n LoginAndCreateSessionResult,\n LoginResult,\n RegistrationResult,\n SignAndSendDelegateActionResult,\n SignDelegateActionResult,\n SignTransactionResult,\n} from './tatchi';\nimport type { SyncAccountResult, SignNEP413MessageResult } from '../TatchiPasskey';\n\n//////////////////////////\n// Progress Events Enums\n//////////////////////////\n\n// Registration Enums\nexport enum RegistrationPhase {\n STEP_1_WEBAUTHN_VERIFICATION = 'webauthn-verification',\n STEP_2_KEY_GENERATION = 'key-generation',\n STEP_3_CONTRACT_PRE_CHECK = 'contract-pre-check',\n STEP_4_ACCESS_KEY_ADDITION = 'access-key-addition',\n STEP_5_CONTRACT_REGISTRATION = 'contract-registration',\n STEP_6_ACCOUNT_VERIFICATION = 'account-verification',\n STEP_7_DATABASE_STORAGE = 'database-storage',\n STEP_8_REGISTRATION_COMPLETE = 'registration-complete',\n REGISTRATION_ERROR = 'error',\n}\nexport enum RegistrationStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Login Enums\nexport enum LoginPhase {\n STEP_1_PREPARATION = 'preparation',\n STEP_2_WEBAUTHN_ASSERTION = 'webauthn-assertion',\n STEP_3_VRF_UNLOCK = 'vrf-unlock',\n STEP_4_LOGIN_COMPLETE = 'login-complete',\n LOGIN_ERROR = 'login-error',\n}\nexport enum LoginStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Action Enums\nexport enum ActionPhase {\n STEP_1_PREPARATION = 'preparation', // Rust WASM worker phase: Preparation = 100\n STEP_2_USER_CONFIRMATION = 'user-confirmation', // Rust WASM worker phase: UserConfirmation = 101\n STEP_3_WEBAUTHN_AUTHENTICATION = 'webauthn-authentication', // Rust WASM worker phase: WebauthnAuthentication = 102\n STEP_4_AUTHENTICATION_COMPLETE = 'authentication-complete', // Rust WASM worker phase: AuthenticationComplete = 103\n STEP_5_TRANSACTION_SIGNING_PROGRESS = 'transaction-signing-progress', // Rust WASM worker phase: TransactionSigningProgress = 104\n STEP_6_TRANSACTION_SIGNING_COMPLETE = 'transaction-signing-complete', // Rust WASM worker phase: TransactionSigningComplete = 105\n WASM_ERROR = 'wasm-error', // Rust WASM worker phase: Error = 106\n STEP_7_BROADCASTING = 'broadcasting',\n STEP_8_ACTION_COMPLETE = 'action-complete',\n ACTION_ERROR = 'action-error',\n}\nexport enum ActionStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Delegate-specific phase alias for filtering\nexport { ActionPhase as DelegateActionPhase };\n\n// Account Sync Enums\nexport enum SyncAccountPhase {\n STEP_1_PREPARATION = 'preparation',\n STEP_2_WEBAUTHN_AUTHENTICATION = 'webauthn-authentication',\n STEP_3_SYNC_AUTHENTICATORS_ONCHAIN = 'sync-authenticators-onchain',\n STEP_4_AUTHENTICATOR_SAVED = 'authenticator-saved',\n STEP_5_SYNC_ACCOUNT_COMPLETE = 'sync-account-complete',\n ERROR = 'error',\n}\nexport enum SyncAccountStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Device Linking Enums\nexport enum DeviceLinkingPhase {\n STEP_1_QR_CODE_GENERATED = 'qr-code-generated', // Device2: QR code created and displayed\n STEP_2_SCANNING = 'scanning', // Device1: Scanning QR code\n STEP_3_AUTHORIZATION = 'authorization', // Device1: TouchID authorization\n STEP_4_POLLING = 'polling', // Device2: Polling contract for mapping\n STEP_5_ADDKEY_DETECTED = 'addkey-detected', // Device2: AddKey transaction detected\n STEP_6_REGISTRATION = 'registration', // Device2: Registration and credential storage\n STEP_7_LINKING_COMPLETE = 'linking-complete', // Final completion\n STEP_8_AUTO_LOGIN = 'auto-login', // Auto-login after registration\n IDLE = 'idle', // Idle state\n REGISTRATION_ERROR = 'registration-error', // Error during registration\n LOGIN_ERROR = 'login-error', // Error during login\n DEVICE_LINKING_ERROR = 'error', // General error state\n}\nexport enum DeviceLinkingStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Email Recovery Enums\nexport enum EmailRecoveryPhase {\n STEP_1_PREPARATION = 'email-recovery-preparation',\n STEP_2_TOUCH_ID_REGISTRATION = 'email-recovery-touch-id-registration',\n STEP_3_AWAIT_EMAIL = 'email-recovery-await-email',\n STEP_4_POLLING_ADD_KEY = 'email-recovery-polling-add-key',\n STEP_4_POLLING_VERIFICATION_RESULT = 'email-recovery-polling-add-key',\n STEP_5_FINALIZING_REGISTRATION = 'email-recovery-finalizing-registration',\n STEP_6_COMPLETE = 'email-recovery-complete',\n ERROR = 'email-recovery-error',\n RESUMED_FROM_PENDING = 'email-recovery-resumed-from-pending',\n}\nexport enum EmailRecoveryStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Base event callback type\nexport type EventCallback<T> = (event: T) => void;\n\n// Users can still supply a single implementation: (success: boolean, result?: T) => ...\nexport interface AfterCall<T> {\n (success: true, result: T): void | Promise<void>;\n (success: false): void | Promise<void>;\n}\n\n// Base SSE Event Types (unified for Registration and Actions)\nexport interface BaseSSEEvent {\n step: number;\n phase: RegistrationPhase | LoginPhase | ActionPhase | DeviceLinkingPhase | SyncAccountPhase | EmailRecoveryPhase;\n status: RegistrationStatus | LoginStatus | ActionStatus | DeviceLinkingStatus | SyncAccountStatus | EmailRecoveryStatus;\n message: string;\n}\n\n// Registration-specific events\nexport interface BaseRegistrationSSEEvent extends BaseSSEEvent {\n phase: RegistrationPhase;\n status: RegistrationStatus;\n}\n\n// Action-specific events\nexport interface BaseActionSSEEvent extends BaseSSEEvent {\n phase: ActionPhase;\n status: ActionStatus;\n}\n\n// Login-specific events\nexport interface BaseLoginSSEEvent extends BaseSSEEvent {\n phase: LoginPhase;\n status: LoginStatus;\n}\n\nexport interface BaseDeviceLinkingSSEEvent extends BaseSSEEvent {\n phase: DeviceLinkingPhase;\n status: DeviceLinkingStatus;\n}\n\n// Action-specific events\nexport interface BaseSyncAccountEvent extends BaseSSEEvent {\n phase: SyncAccountPhase;\n status: SyncAccountStatus;\n}\n\nexport interface BaseEmailRecoveryEvent extends BaseSSEEvent {\n phase: EmailRecoveryPhase;\n status: EmailRecoveryStatus;\n}\n\n// Progress Events\nexport interface onProgressEvents extends BaseActionSSEEvent {\n step: number;\n status: ActionStatus;\n message: string;\n // Generic metadata bag for progress payloads\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\n// Optional, phase-specific data shapes used where we can commit to fields\n// Intentionally keep progress payloads generic to avoid duplicating\n// worker-side data shapes. Concrete fields can be added in future PRs\n// by normalizing worker payloads in one place.\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Registration Event Types\n/////////////////////////////////////////////\n\nexport interface RegistrationEventStep1 extends BaseRegistrationSSEEvent {\n step: 1;\n phase: RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION;\n}\n\nexport interface RegistrationEventStep2 extends BaseRegistrationSSEEvent {\n step: 2;\n phase: RegistrationPhase.STEP_2_KEY_GENERATION;\n status: RegistrationStatus.SUCCESS;\n verified: boolean;\n nearAccountId: string;\n nearPublicKey: string | null | undefined;\n vrfPublicKey: string | null | undefined;\n}\n\n// Optional progress emission during step 2 (e.g., concurrent contract pre-checks)\nexport interface RegistrationEventStep2Progress extends BaseRegistrationSSEEvent {\n step: 2;\n phase: RegistrationPhase.STEP_2_KEY_GENERATION;\n status: RegistrationStatus.PROGRESS;\n}\n\nexport interface RegistrationEventStep3 extends BaseRegistrationSSEEvent {\n step: 3;\n phase: RegistrationPhase.STEP_3_CONTRACT_PRE_CHECK;\n error?: string;\n}\n\nexport interface RegistrationEventStep4 extends BaseRegistrationSSEEvent {\n step: 4;\n phase: RegistrationPhase.STEP_4_ACCESS_KEY_ADDITION;\n error?: string;\n}\n\nexport interface RegistrationEventStep5 extends BaseRegistrationSSEEvent {\n step: 5;\n phase: RegistrationPhase.STEP_5_CONTRACT_REGISTRATION;\n error?: string;\n}\n\nexport interface RegistrationEventStep6 extends BaseRegistrationSSEEvent {\n step: 6;\n phase: RegistrationPhase.STEP_6_ACCOUNT_VERIFICATION;\n error?: string;\n}\n\nexport interface RegistrationEventStep7 extends BaseRegistrationSSEEvent {\n step: 7;\n phase: RegistrationPhase.STEP_7_DATABASE_STORAGE;\n error?: string;\n}\n\nexport interface RegistrationEventStep8 extends BaseRegistrationSSEEvent {\n step: 8;\n phase: RegistrationPhase.STEP_8_REGISTRATION_COMPLETE;\n status: RegistrationStatus.SUCCESS;\n}\n\nexport interface RegistrationEventStep0 extends BaseRegistrationSSEEvent {\n step: 0;\n phase: RegistrationPhase.REGISTRATION_ERROR;\n status: RegistrationStatus.ERROR;\n error: string;\n}\n\nexport type RegistrationSSEEvent =\n | RegistrationEventStep1\n | RegistrationEventStep2Progress\n | RegistrationEventStep2\n | RegistrationEventStep3\n | RegistrationEventStep4\n | RegistrationEventStep5\n | RegistrationEventStep6\n | RegistrationEventStep7\n | RegistrationEventStep8\n | RegistrationEventStep0;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Login Event Types\n/////////////////////////////////////////////\n\nexport interface LoginSSEventStep1 extends BaseLoginSSEEvent {\n step: 1;\n phase: LoginPhase.STEP_1_PREPARATION;\n}\n\nexport interface LoginSSEventStep2 extends BaseLoginSSEEvent {\n step: 2;\n phase: LoginPhase.STEP_2_WEBAUTHN_ASSERTION;\n}\n\nexport interface LoginSSEventStep3 extends BaseLoginSSEEvent {\n step: 3;\n phase: LoginPhase.STEP_3_VRF_UNLOCK;\n}\n\nexport interface LoginSSEventStep4 extends BaseLoginSSEEvent {\n step: 4;\n phase: LoginPhase.STEP_4_LOGIN_COMPLETE;\n status: LoginStatus.SUCCESS;\n nearAccountId: string;\n clientNearPublicKey: string;\n}\n\nexport interface LoginSSEventStep0 extends BaseLoginSSEEvent {\n step: 0;\n phase: LoginPhase.LOGIN_ERROR;\n status: LoginStatus.ERROR;\n error: string;\n}\n\nexport type LoginSSEvent =\n | LoginSSEventStep1\n | LoginSSEventStep2\n | LoginSSEventStep3\n | LoginSSEventStep4\n | LoginSSEventStep0;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Action Event Types\n/////////////////////////////////////////////\n\nexport interface ActionEventStep1 extends BaseActionSSEEvent {\n step: 1;\n phase: ActionPhase.STEP_1_PREPARATION;\n}\n\nexport interface ActionEventStep2 extends BaseActionSSEEvent {\n step: 2;\n phase: ActionPhase.STEP_2_USER_CONFIRMATION;\n}\n\nexport interface ActionEventStep3 extends BaseActionSSEEvent {\n step: 3;\n phase: ActionPhase.STEP_3_WEBAUTHN_AUTHENTICATION;\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\nexport interface ActionEventStep4 extends BaseActionSSEEvent {\n step: 4;\n phase: ActionPhase.STEP_4_AUTHENTICATION_COMPLETE;\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\nexport interface ActionEventStep5 extends BaseActionSSEEvent {\n step: 5;\n phase: ActionPhase.STEP_5_TRANSACTION_SIGNING_PROGRESS;\n data?: Record<string, unknown>;\n}\n\nexport interface ActionEventStep6 extends BaseActionSSEEvent {\n step: 6;\n phase: ActionPhase.STEP_6_TRANSACTION_SIGNING_COMPLETE;\n status: ActionStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface ActionEventStep7 extends BaseActionSSEEvent {\n step: 7;\n phase: ActionPhase.STEP_7_BROADCASTING;\n}\n\nexport interface ActionEventStep8 extends BaseActionSSEEvent {\n step: 8;\n phase: ActionPhase.STEP_8_ACTION_COMPLETE;\n status: ActionStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface ActionEventError extends BaseActionSSEEvent {\n step: 0;\n phase: ActionPhase.ACTION_ERROR;\n status: ActionStatus.ERROR;\n error: string;\n}\n\nexport interface ActionEventWasmError extends BaseActionSSEEvent {\n step: 0;\n phase: ActionPhase.WASM_ERROR;\n status: ActionStatus.ERROR;\n error: string;\n}\n\nexport type ActionSSEEvent =\n | ActionEventStep1\n | ActionEventStep2\n | ActionEventStep3\n | ActionEventStep4\n | ActionEventStep5\n | ActionEventStep6\n | ActionEventStep7\n | ActionEventStep8\n | ActionEventError\n | ActionEventWasmError;\n\nexport type DelegateActionSSEEvent = ActionSSEEvent;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Device Linking Event Types\n/////////////////////////////////////////////\n\nexport interface DeviceLinkingEventStep1 extends BaseDeviceLinkingSSEEvent {\n step: 1;\n phase: DeviceLinkingPhase.STEP_1_QR_CODE_GENERATED;\n}\n\nexport interface DeviceLinkingEventStep2 extends BaseDeviceLinkingSSEEvent {\n step: 2;\n phase: DeviceLinkingPhase.STEP_2_SCANNING;\n}\n\nexport interface DeviceLinkingEventStep3 extends BaseDeviceLinkingSSEEvent {\n step: 3;\n phase: DeviceLinkingPhase.STEP_3_AUTHORIZATION;\n}\n\nexport interface DeviceLinkingEventStep4 extends BaseDeviceLinkingSSEEvent {\n step: 4;\n phase: DeviceLinkingPhase.STEP_4_POLLING;\n}\n\nexport interface DeviceLinkingEventStep5 extends BaseDeviceLinkingSSEEvent {\n step: 5;\n phase: DeviceLinkingPhase.STEP_5_ADDKEY_DETECTED;\n}\n\nexport interface DeviceLinkingEventStep6 extends BaseDeviceLinkingSSEEvent {\n step: 6;\n phase: DeviceLinkingPhase.STEP_6_REGISTRATION;\n}\n\nexport interface DeviceLinkingEventStep7 extends BaseDeviceLinkingSSEEvent {\n step: 7;\n phase: DeviceLinkingPhase.STEP_7_LINKING_COMPLETE;\n}\n\nexport interface DeviceLinkingEventStep8 extends BaseDeviceLinkingSSEEvent {\n step: 8;\n phase: DeviceLinkingPhase.STEP_8_AUTO_LOGIN;\n}\n\nexport interface DeviceLinkingErrorEvent extends BaseDeviceLinkingSSEEvent {\n step: 0;\n phase: DeviceLinkingPhase.DEVICE_LINKING_ERROR\n | DeviceLinkingPhase.LOGIN_ERROR\n | DeviceLinkingPhase.REGISTRATION_ERROR;\n status: DeviceLinkingStatus.ERROR;\n error: string;\n}\n\nexport type DeviceLinkingSSEEvent =\n | DeviceLinkingEventStep1\n | DeviceLinkingEventStep2\n | DeviceLinkingEventStep3\n | DeviceLinkingEventStep4\n | DeviceLinkingEventStep5\n | DeviceLinkingEventStep6\n | DeviceLinkingEventStep7\n | DeviceLinkingEventStep8\n | DeviceLinkingErrorEvent;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Account Sync Event Types\n/////////////////////////////////////////////\n\nexport interface SyncAccountEventStep1 extends BaseSyncAccountEvent {\n step: 1;\n phase: SyncAccountPhase.STEP_1_PREPARATION;\n}\n\nexport interface SyncAccountEventStep2 extends BaseSyncAccountEvent {\n step: 2;\n phase: SyncAccountPhase.STEP_2_WEBAUTHN_AUTHENTICATION;\n}\n\nexport interface SyncAccountEventStep3 extends BaseSyncAccountEvent {\n step: 3;\n phase: SyncAccountPhase.STEP_3_SYNC_AUTHENTICATORS_ONCHAIN;\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\nexport interface SyncAccountEventStep4 extends BaseSyncAccountEvent {\n step: 4;\n phase: SyncAccountPhase.STEP_4_AUTHENTICATOR_SAVED;\n status: SyncAccountStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface SyncAccountEventStep5 extends BaseSyncAccountEvent {\n step: 5;\n phase: SyncAccountPhase.STEP_5_SYNC_ACCOUNT_COMPLETE;\n status: SyncAccountStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface SyncAccountError extends BaseSyncAccountEvent {\n step: 0;\n phase: SyncAccountPhase.ERROR;\n status: SyncAccountStatus.ERROR;\n error: string;\n}\n\nexport type SyncAccountSSEEvent =\n | SyncAccountEventStep1\n | SyncAccountEventStep2\n | SyncAccountEventStep3\n | SyncAccountEventStep4\n | SyncAccountEventStep5\n | SyncAccountError;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Email Recovery Event Types\n/////////////////////////////////////////////\n\nexport interface EmailRecoveryEventStep1 extends BaseEmailRecoveryEvent {\n step: 1;\n phase: EmailRecoveryPhase.STEP_1_PREPARATION;\n}\n\nexport interface EmailRecoveryEventStep2 extends BaseEmailRecoveryEvent {\n step: 2;\n phase: EmailRecoveryPhase.STEP_2_TOUCH_ID_REGISTRATION;\n}\n\nexport interface EmailRecoveryEventStep3 extends BaseEmailRecoveryEvent {\n step: 3;\n phase: EmailRecoveryPhase.STEP_3_AWAIT_EMAIL;\n}\n\nexport interface EmailRecoveryEventStep4 extends BaseEmailRecoveryEvent {\n step: 4;\n phase: EmailRecoveryPhase.STEP_4_POLLING_ADD_KEY | EmailRecoveryPhase.STEP_4_POLLING_VERIFICATION_RESULT;\n data?: {\n accountId?: string;\n requestId?: string;\n nearPublicKey?: string;\n elapsedMs?: number;\n pollCount?: number;\n [key: string]: unknown;\n };\n logs?: string[];\n}\n\nexport interface EmailRecoveryEventStep5 extends BaseEmailRecoveryEvent {\n step: 5;\n phase: EmailRecoveryPhase.STEP_5_FINALIZING_REGISTRATION;\n data?: Record<string, unknown>;\n}\n\nexport interface EmailRecoveryEventStep6 extends BaseEmailRecoveryEvent {\n step: 6;\n phase: EmailRecoveryPhase.STEP_6_COMPLETE;\n status: EmailRecoveryStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface EmailRecoveryEventResumedFromPending extends BaseEmailRecoveryEvent {\n step: 0;\n phase: EmailRecoveryPhase.RESUMED_FROM_PENDING;\n status: EmailRecoveryStatus.PROGRESS;\n data?: Record<string, unknown>;\n}\n\nexport interface EmailRecoveryErrorEvent extends BaseEmailRecoveryEvent {\n step: 0;\n phase: EmailRecoveryPhase.ERROR;\n status: EmailRecoveryStatus.ERROR;\n error: string;\n}\n\nexport type EmailRecoverySSEEvent =\n | EmailRecoveryEventStep1\n | EmailRecoveryEventStep2\n | EmailRecoveryEventStep3\n | EmailRecoveryEventStep4\n | EmailRecoveryEventStep5\n | EmailRecoveryEventStep6\n | EmailRecoveryEventResumedFromPending\n | EmailRecoveryErrorEvent;\n\n//////////////////////////////////\n/// Hooks Options\n//////////////////////////////////\n\n// Function Options\nexport interface RegistrationHooksOptions {\n onEvent?: EventCallback<RegistrationSSEEvent>;\n onError?: (error: Error) => void;\n afterCall?: AfterCall<RegistrationResult>;\n /**\n * Optional: registration signing policy.\n * - `{ mode: 'local-signer' }`: derive and store an encrypted local NEAR secret key (v3 vault).\n * - `{ mode: 'threshold-signer' }`: derive the local key AND enroll a threshold Ed25519 (2-of-2) access key\n * during registration (relay adds the threshold public key on-chain and returns relayerKeyId).\n *\n * Defaults to `{ mode: 'local-signer' }` for backwards compatibility in public APIs.\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration. When provided, overrides user preferences\n // for this request only (not persisted).\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface LoginHooksOptions {\n onEvent?: EventCallback<LoginSSEvent>;\n onError?: (error: Error) => void;\n afterCall?: AfterCall<LoginAndCreateSessionResult>;\n /**\n * Optional: passkey deviceNumber hint.\n *\n * When multiple passkeys exist for the same `nearAccountId`, providing this hint lets\n * the login flow prioritize the matching `credentialId` when presenting the TouchID\n * (WebAuthn) prompt.\n */\n deviceNumber?: number;\n // Optional: request a server session (JWT in body or HttpOnly cookie)\n session?: {\n // 'jwt' returns the token in the JSON body; 'cookie' sets HttpOnly cookie\n kind: 'jwt' | 'cookie';\n // Optional: override relay URL; defaults to TatchiConfigs.relayer.url\n relayUrl?: string;\n // Optional: override route path; defaults to '/verify-authentication-response'\n route?: string;\n };\n /**\n * Optional: override the warm signing session policy minted during login.\n * Defaults come from `TatchiConfigs.signingSessionDefaults`.\n */\n signingSession?: {\n ttlMs?: number;\n remainingUses?: number;\n };\n}\n\nexport interface ActionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n afterCall?: AfterCall<ActionResult>;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration. When provided, overrides user preferences\n // for this request only (not persisted).\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport type ExecutionWaitOption =\n | { mode: 'sequential'; waitUntil?: TxExecutionStatus }\n | { mode: 'parallelStaggered'; staggerMs: number };\n\nexport interface SignAndSendTransactionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Execution control for multi-transaction broadcasts:\n * - { mode: 'sequential', waitUntil?: TxExecutionStatus }\n * - { mode: 'parallelStaggered', staggerMs: number }\n */\n executionWait?: ExecutionWaitOption;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n\n afterCall?: AfterCall<ActionResult[]>;\n // Per-call confirmation configuration. When provided, overrides user preferences\n // for this request only (not persisted).\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface SignTransactionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n\n afterCall?: AfterCall<SignTransactionResult[]>;\n waitUntil?: TxExecutionStatus;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration (non-persistent)\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface SendTransactionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n\n afterCall?: AfterCall<ActionResult>;\n waitUntil?: TxExecutionStatus;\n}\n\nexport interface DelegateActionHooksOptions {\n onEvent?: EventCallback<DelegateActionSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n afterCall?: AfterCall<SignDelegateActionResult>;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface DelegateRelayHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n afterCall?: AfterCall<DelegateRelayResult>;\n}\n\nexport type SignAndSendDelegateActionHooksOptions =\n Omit<DelegateActionHooksOptions, 'afterCall'> & {\n afterCall?: AfterCall<SignAndSendDelegateActionResult>;\n };\n\nexport interface SyncAccountHooksOptions {\n onEvent?: EventCallback<SyncAccountSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n\n afterCall?: AfterCall<SyncAccountResult>;\n}\n\nexport interface SignNEP413HooksOptions {\n onEvent?: EventCallback<RegistrationSSEEvent | LoginSSEvent | ActionSSEEvent | DeviceLinkingSSEEvent | SyncAccountSSEEvent | EmailRecoverySSEEvent>;\n onError?: (error: Error) => void;\n\n afterCall?: AfterCall<SignNEP413MessageResult>;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration (non-persistent)\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n","/**\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/syncAccount';\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 { createRandomVRFChallenge, type 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 { ensureEd25519Prefix } from '../utils/validation';\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 RecoveryAttemptStatus =\n | \"Started\"\n | \"VerifyingDkim\"\n | \"VerifyingZkEmail\"\n | \"DkimFailed\"\n | \"ZkEmailFailed\"\n | \"PolicyFailed\"\n | \"Recovering\"\n | \"AwaitingMoreEmails\"\n | \"Complete\"\n | \"Failed\";\n\nexport type RecoveryAttempt = {\n request_id: string;\n status: RecoveryAttemptStatus | string;\n created_at_ms: number;\n updated_at_ms: number;\n error?: string | null;\n /**\n * 32-byte SHA-256 hash of \"<canonical_from>|<account_id_lower>\".\n * Returned by newer EmailRecoverer contracts (replaces `from_address`).\n */\n from_address_hash?: number[] | null;\n /** Legacy field (string email address). */\n from_address?: string | null;\n email_timestamp_ms?: number | null;\n new_public_key?: string | null;\n};\n\nfunction normalizeByteArray(input: unknown): number[] | null | undefined {\n if (input == null) return input as null | undefined;\n\n if (Array.isArray(input)) {\n return input.map((v) => Number(v)).filter((v) => Number.isFinite(v));\n }\n\n if (typeof input === 'string' && input) {\n try {\n const bytes =\n typeof Buffer !== 'undefined'\n ? Buffer.from(input, 'base64')\n : Uint8Array.from(atob(input), (c) => c.charCodeAt(0));\n const arr = bytes instanceof Uint8Array ? Array.from(bytes) : Array.from(new Uint8Array(bytes));\n return arr;\n } catch {\n return undefined;\n }\n }\n\n return undefined;\n}\n\nexport async function getEmailRecoveryAttempt(\n nearClient: NearClient,\n accountId: string,\n requestId: string\n): Promise<RecoveryAttempt | null> {\n const raw = await nearClient.view<{ request_id: string }, Omit<RecoveryAttempt, 'status'> & { status: any } | null>({\n account: accountId,\n method: 'get_recovery_attempt',\n args: { request_id: requestId },\n });\n\n if (!raw) return null;\n\n // Normalization logic for status (string or object enum)\n const statusRaw = raw.status;\n const status = (() => {\n if (typeof statusRaw === 'string') return statusRaw.trim();\n if (statusRaw && typeof statusRaw === 'object') {\n const keys = Object.keys(statusRaw as Record<string, unknown>);\n if (keys.length === 1) {\n return String(keys[0] || '').trim();\n }\n }\n return '';\n })();\n\n return {\n ...raw,\n from_address_hash: normalizeByteArray((raw as any).from_address_hash) ?? (raw as any).from_address_hash,\n status: status as RecoveryAttemptStatus,\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 const signTransactions = () => context.webAuthnManager.signTransactionsWithActions({\n rpcCall: {\n contractId: context.webAuthnManager.tatchiPasskeyConfigs.contractId,\n nearRpcUrl: context.webAuthnManager.tatchiPasskeyConfigs.nearRpcUrl,\n nearAccountId: device1AccountId\n },\n // Prefer threshold signing when available; fall back to local signing if the account\n // is not enrolled with threshold key material.\n signerMode: { mode: 'threshold-signer', behavior: 'fallback' },\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 // Sign three transactions with one PRF authentication\n let signedTransactions: Array<{ signedTransaction: SignedTransaction }> = [];\n try {\n signedTransactions = await signTransactions();\n } catch (e: unknown) {\n if (!isVrfSessionPasskeyMismatchError(e)) throw e;\n\n // This happens when:\n // - the VRF worker is unlocked for a different device's VRF keypair, but\n // - IndexedDB `lastUser` (and thus allowCredentials) points at another device.\n // Fix by re-unlocking the VRF keypair for the current deviceNumber, then retry once.\n onEvent?.({\n step: 3,\n phase: DeviceLinkingPhase.STEP_3_AUTHORIZATION,\n status: DeviceLinkingStatus.PROGRESS,\n message: 'Session mismatch detected; re-authenticating with TouchID...'\n });\n\n await repairVrfSessionForCurrentDevice({\n context,\n nearAccountId: device1AccountId,\n // Needs to cover 3 txs in a single batch.\n remainingUses: 3,\n ttlMs: 2 * 60 * 1000,\n });\n\n signedTransactions = await signTransactions();\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\nfunction isVrfSessionPasskeyMismatchError(err: unknown): boolean {\n const msg = errorMessage(err) || String(err || '');\n return msg.includes('different passkey/VRF session than the current device');\n}\n\nasync function repairVrfSessionForCurrentDevice(args: {\n context: PasskeyManagerContext;\n nearAccountId: AccountId;\n ttlMs?: number;\n remainingUses?: number;\n}): Promise<void> {\n const { context, nearAccountId } = args;\n const lastUser = await context.webAuthnManager.getLastUser();\n if (!lastUser || lastUser.nearAccountId !== nearAccountId) {\n throw new Error('Cannot repair VRF session: no lastUser for this account. Please log in again.');\n }\n const deviceNumber = lastUser.deviceNumber;\n if (!Number.isFinite(deviceNumber) || deviceNumber < 1) {\n throw new Error('Cannot repair VRF session: invalid lastUser.deviceNumber');\n }\n\n const authenticators = await context.webAuthnManager.getAuthenticatorsByUser(nearAccountId);\n const credentialIdsForDevice = authenticators\n .filter((a) => a.deviceNumber === deviceNumber)\n .map((a) => a.credentialId);\n\n const credentialIds = credentialIdsForDevice.length > 0\n ? credentialIdsForDevice\n : authenticators.map((a) => a.credentialId);\n\n if (credentialIds.length === 0) {\n throw new Error(`Cannot repair VRF session: no authenticators found for ${nearAccountId}`);\n }\n\n const challenge = createRandomVRFChallenge();\n const credential = await context.webAuthnManager.getAuthenticationCredentialsSerializedDualPrf({\n nearAccountId,\n challenge: challenge as VRFChallenge,\n credentialIds,\n });\n\n const unlockResult = await context.webAuthnManager.unlockVRFKeypair({\n nearAccountId,\n encryptedVrfKeypair: lastUser.encryptedVrfKeypair,\n credential: credential as WebAuthnAuthenticationCredential,\n });\n if (!unlockResult.success) {\n throw new Error(unlockResult.error || 'Failed to re-unlock VRF keypair for current device');\n }\n\n // Restore a minimal warm signing session so the retried batch can run without a second TouchID prompt.\n await context.webAuthnManager.mintSigningSessionFromCredential({\n nearAccountId,\n credential: credential as WebAuthnAuthenticationCredential,\n ttlMs: args.ttlMs,\n remainingUses: args.remainingUses,\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, nearPublicKey?: string }>> {\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 const nearPublicKey = (() => {\n const raw = (contractAuthenticator as any).near_public_key;\n if (typeof raw !== 'string') return undefined;\n const trimmed = raw.trim();\n return trimmed ? ensureEd25519Prefix(trimmed) : 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 ...(nearPublicKey ? { nearPublicKey } : {})\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\nconst EMPTY_NEAR_CODE_HASH = '11111111111111111111111111111111';\n\nasync function hasDeployedContractCode(nearClient: NearClient, accountId: AccountId): Promise<boolean> {\n try {\n const account = await nearClient.viewAccount(accountId);\n const codeHash = (account as { code_hash?: unknown } | null)?.code_hash;\n const globalContractHash = (account as { global_contract_hash?: unknown } | null)?.global_contract_hash;\n const globalContractAccountId = (account as { global_contract_account_id?: unknown } | null)?.global_contract_account_id;\n\n const hasLocalCode = typeof codeHash === 'string' && codeHash !== EMPTY_NEAR_CODE_HASH;\n const hasGlobalCode =\n (typeof globalContractHash === 'string' && globalContractHash.trim().length > 0) ||\n (typeof globalContractAccountId === 'string' && globalContractAccountId.trim().length > 0);\n\n return hasLocalCode || hasGlobalCode;\n } catch {\n return false;\n }\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 // Prefer `view_account` over `view_code`:\n // - `view_code` is expected to fail for non-contract accounts and is noisy.\n // - `view_account` is lightweight and tells us whether the account uses local contract code\n // or a NEAR \"global contract\" (via `global_contract_*` fields).\n const hasContract = await hasDeployedContractCode(nearClient, accountId);\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 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 const hasContract = await hasDeployedContractCode(nearClient, accountId);\n\n const {\n emailRecovererGlobalContract,\n zkEmailVerifierContract,\n emailDkimVerifierContract,\n } = contracts;\n\n // If the account already has a contract (local or global), it still might not be a readable\n // EmailRecoverer instance (e.g. stale state after upgrades). In that case, `set_recovery_emails`\n // would fail while `init_email_recovery` (#[init(ignore_state)]) can safely re-initialize.\n //\n // We keep this as a best-effort probe to avoid wiping state on transient RPC issues.\n let shouldInit = !hasContract;\n if (!shouldInit) {\n try {\n await nearClient.view<Record<string, never>, unknown>({\n account: accountId,\n method: 'get_recovery_emails',\n args: {} as Record<string, never>,\n });\n } catch (err: unknown) {\n const msg = errorMessage(err);\n // Common/expected cases where we should fall back to init:\n // - account has a global contract pointer but no EmailRecoverer-compatible state yet\n // - account has stale/incompatible state after a contract upgrade\n // - account has some other contract (method missing)\n if (/Cannot deserialize the contract state/i.test(msg)\n || /CodeDoesNotExist/i.test(msg)\n || /MethodNotFound/i.test(msg)) {\n shouldInit = true;\n }\n }\n }\n\n const base: ActionArgs[] = [\n {\n type: ActionType.UseGlobalContract,\n accountId: emailRecovererGlobalContract,\n },\n ];\n\n return shouldInit\n ? [\n ...base,\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 ...base,\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\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// ACCESS KEY HELPERS\n// ===========================\n\nexport type AccessKeyWaitOptions = {\n attempts?: number;\n delayMs?: number;\n};\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((res) => setTimeout(res, ms));\n}\n\nfunction isAccessKeyNotFoundError(err: unknown): boolean {\n const msg = String(errorMessage(err) || '').toLowerCase();\n if (!msg) return false;\n\n // Common NEAR node / near-api-js phrasing for missing access keys.\n if (msg.includes('unknown access key') || msg.includes('unknown_access_key') || msg.includes('unknownaccesskey')) {\n return true;\n }\n if (msg.includes('accesskeydoesnotexist')) return true;\n if (msg.includes('access key does not exist')) return true;\n if (msg.includes(\"access key doesn't exist\")) return true;\n if (msg.includes('access key not found')) return true;\n if (msg.includes('no such access key')) return true;\n if (msg.includes('viewing access key') && msg.includes('does not exist') && !msg.includes('account')) return true;\n\n return false;\n}\n\nexport async function hasAccessKey(\n nearClient: NearClient,\n nearAccountId: string,\n publicKey: string,\n opts?: AccessKeyWaitOptions,\n): Promise<boolean> {\n const expected = ensureEd25519Prefix(publicKey);\n if (!expected) return false;\n\n const attempts = Math.max(1, Math.floor(opts?.attempts ?? 6));\n const delayMs = Math.max(50, Math.floor(opts?.delayMs ?? 750));\n\n for (let i = 0; i < attempts; i++) {\n try {\n await nearClient.viewAccessKey(nearAccountId, expected);\n return true;\n } catch {\n // tolerate transient view errors during propagation; retry\n }\n if (i < attempts - 1) {\n await sleep(delayMs);\n }\n }\n return false;\n}\n\nexport async function waitForAccessKeyAbsent(\n nearClient: NearClient,\n nearAccountId: string,\n publicKey: string,\n opts?: AccessKeyWaitOptions,\n): Promise<boolean> {\n const expected = ensureEd25519Prefix(publicKey);\n if (!expected) return true;\n\n const attempts = Math.max(1, Math.floor(opts?.attempts ?? 6));\n const delayMs = Math.max(50, Math.floor(opts?.delayMs ?? 650));\n\n for (let i = 0; i < attempts; i++) {\n try {\n await nearClient.viewAccessKey(nearAccountId, expected);\n } catch (err: unknown) {\n if (isAccessKeyNotFoundError(err)) return true;\n // tolerate transient view errors during propagation; retry\n }\n if (i < attempts - 1) {\n await sleep(delayMs);\n }\n }\n return false;\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 intent_digest_32 = Array.from(base64UrlDecode(vrfChallenge.intentDigest || ''));\n if (intent_digest_32.length !== 32) {\n throw new Error('Missing or invalid vrfChallenge.intentDigest (expected base64url-encoded 32 bytes)');\n }\n const session_policy_digest_32 = vrfChallenge.sessionPolicyDigest32\n ? Array.from(base64UrlDecode(vrfChallenge.sessionPolicyDigest32))\n : [];\n if (session_policy_digest_32.length !== 0 && session_policy_digest_32.length !== 32) {\n throw new Error('Invalid vrfChallenge.sessionPolicyDigest32 (expected base64url-encoded 32 bytes)');\n }\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 intent_digest_32,\n ...(session_policy_digest_32.length ? { session_policy_digest_32 } : {}),\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 intent_digest_32 = toBytes(vrfChallenge.intentDigest);\n if (intent_digest_32.length !== 32) {\n throw new Error('Missing or invalid vrfChallenge.intentDigest (expected base64url-encoded 32 bytes)');\n }\n const session_policy_digest_32 = toBytes(vrfChallenge.sessionPolicyDigest32);\n if (session_policy_digest_32.length !== 0 && session_policy_digest_32.length !== 32) {\n throw new Error('Invalid vrfChallenge.sessionPolicyDigest32 (expected base64url-encoded 32 bytes)');\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 intent_digest_32,\n ...(session_policy_digest_32.length ? { session_policy_digest_32 } : {}),\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\nexport async function authorizeThresholdEd25519(\n relayServerUrl: string,\n vrfChallenge: VRFChallenge,\n webauthnAuthentication: WebAuthnAuthenticationCredential,\n args: {\n relayerKeyId: string;\n clientVerifyingShareB64u: string;\n purpose: string;\n /**\n * Exact 32-byte digest that will be co-signed (tx hash / delegate hash / NEP-413 hash).\n * The relayer must bind this digest to the VRF-authorized `intent_digest_32`.\n */\n signingDigest32: number[];\n signingPayload?: unknown;\n },\n): Promise<{\n ok: boolean;\n mpcSessionId?: string;\n expiresAt?: string;\n code?: string;\n message?: string;\n error?: string;\n}> {\n try {\n const toBytes = (b64u: string | undefined): number[] => {\n if (!b64u) return [];\n return Array.from(base64UrlDecode(b64u));\n };\n const intent_digest_32 = toBytes(vrfChallenge.intentDigest);\n if (intent_digest_32.length !== 32) {\n throw new Error('Missing or invalid vrfChallenge.intentDigest (expected base64url-encoded 32 bytes)');\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 intent_digest_32,\n };\n\n const clientVerifyingShareBytes = toBytes(args.clientVerifyingShareB64u);\n if (clientVerifyingShareBytes.length !== 32) {\n throw new Error('Missing or invalid args.clientVerifyingShareB64u (expected base64url-encoded 32 bytes)');\n }\n\n // Strip extension results before sending to the relay (never send PRF outputs).\n const webauthn_authentication = {\n ...webauthnAuthentication,\n authenticatorAttachment: webauthnAuthentication.authenticatorAttachment ?? null,\n response: {\n ...webauthnAuthentication.response,\n userHandle: webauthnAuthentication.response.userHandle ?? null,\n },\n clientExtensionResults: null,\n };\n\n const url = `${relayServerUrl.replace(/\\/$/, '')}/threshold-ed25519/authorize`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n credentials: 'include',\n body: JSON.stringify({\n relayerKeyId: args.relayerKeyId,\n clientVerifyingShareB64u: args.clientVerifyingShareB64u,\n purpose: args.purpose,\n signing_digest_32: (() => {\n const d = args.signingDigest32;\n if (!Array.isArray(d) || d.length !== 32) {\n throw new Error('Missing or invalid args.signingDigest32 (expected number[32])');\n }\n return d;\n })(),\n signingPayload: args.signingPayload,\n vrf_data,\n webauthn_authentication,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n return { ok: false, error: `HTTP ${response.status}: ${errorText}` };\n }\n\n const json = await response.json();\n return {\n ok: !!json?.ok,\n mpcSessionId: json?.mpcSessionId,\n expiresAt: json?.expiresAt,\n code: json?.code,\n message: json?.message,\n };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'Failed to authorize threshold-ed25519 signing' };\n }\n}\n\nexport async function thresholdEd25519Keygen(\n relayServerUrl: string,\n vrfChallenge: VRFChallenge,\n webauthnAuthentication: WebAuthnAuthenticationCredential,\n args: {\n clientVerifyingShareB64u: string;\n nearAccountId: string;\n },\n): Promise<{\n ok: boolean;\n clientParticipantId?: number;\n relayerParticipantId?: number;\n participantIds?: number[];\n relayerKeyId?: string;\n publicKey?: string;\n relayerVerifyingShareB64u?: string;\n code?: string;\n message?: string;\n error?: string;\n}> {\n try {\n const base = String(relayServerUrl || '').trim().replace(/\\/$/, '');\n if (!base) throw new Error('Missing relayServerUrl');\n\n const clientVerifyingShareB64u = String(args.clientVerifyingShareB64u || '').trim();\n if (!clientVerifyingShareB64u) throw new Error('Missing clientVerifyingShareB64u');\n\n const nearAccountId = String(args.nearAccountId || '').trim();\n if (!nearAccountId) throw new Error('Missing nearAccountId');\n\n const toBytes = (b64u: string | undefined): number[] => {\n if (!b64u) return [];\n return Array.from(base64UrlDecode(b64u));\n };\n const intent_digest_32 = toBytes(vrfChallenge.intentDigest);\n if (intent_digest_32.length !== 32) {\n throw new Error('Missing or invalid vrfChallenge.intentDigest (expected base64url-encoded 32 bytes)');\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 intent_digest_32,\n };\n\n // Strip extension results before sending to the relay (never send PRF outputs).\n const webauthn_authentication = {\n ...webauthnAuthentication,\n authenticatorAttachment: webauthnAuthentication.authenticatorAttachment ?? null,\n response: {\n ...webauthnAuthentication.response,\n userHandle: webauthnAuthentication.response.userHandle ?? null,\n },\n clientExtensionResults: null,\n };\n\n const url = `${base}/threshold-ed25519/keygen`;\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({\n clientVerifyingShareB64u,\n nearAccountId,\n vrf_data,\n webauthn_authentication,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n return { ok: false, error: `HTTP ${response.status}: ${errorText}` };\n }\n\n const json = await response.json();\n return {\n ok: !!json?.ok,\n clientParticipantId: json?.clientParticipantId,\n relayerParticipantId: json?.relayerParticipantId,\n participantIds: json?.participantIds,\n relayerKeyId: json?.relayerKeyId,\n publicKey: json?.publicKey,\n relayerVerifyingShareB64u: json?.relayerVerifyingShareB64u,\n code: json?.code,\n message: json?.message,\n };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'Failed to keygen threshold-ed25519' };\n }\n}\n\nexport async function thresholdEd25519KeygenFromRegistrationTx(\n relayServerUrl: string,\n args: {\n clientVerifyingShareB64u: string;\n nearAccountId: string;\n registrationTxHash: string;\n },\n): Promise<{\n ok: boolean;\n clientParticipantId?: number;\n relayerParticipantId?: number;\n participantIds?: number[];\n relayerKeyId?: string;\n publicKey?: string;\n relayerVerifyingShareB64u?: string;\n code?: string;\n message?: string;\n error?: string;\n}> {\n try {\n const base = String(relayServerUrl || '').trim().replace(/\\/$/, '');\n if (!base) throw new Error('Missing relayServerUrl');\n\n const clientVerifyingShareB64u = String(args.clientVerifyingShareB64u || '').trim();\n if (!clientVerifyingShareB64u) throw new Error('Missing clientVerifyingShareB64u');\n\n const nearAccountId = String(args.nearAccountId || '').trim();\n if (!nearAccountId) throw new Error('Missing nearAccountId');\n\n const registrationTxHash = String(args.registrationTxHash || '').trim();\n if (!registrationTxHash) throw new Error('Missing registrationTxHash');\n\n const url = `${base}/threshold-ed25519/keygen`;\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({\n clientVerifyingShareB64u,\n nearAccountId,\n registrationTxHash,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n return { ok: false, error: `HTTP ${response.status}: ${errorText}` };\n }\n\n const json = await response.json();\n return {\n ok: !!json?.ok,\n clientParticipantId: json?.clientParticipantId,\n relayerParticipantId: json?.relayerParticipantId,\n participantIds: json?.participantIds,\n relayerKeyId: json?.relayerKeyId,\n publicKey: json?.publicKey,\n relayerVerifyingShareB64u: json?.relayerVerifyingShareB64u,\n code: json?.code,\n message: json?.message,\n };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'Failed to keygen threshold-ed25519 from registration tx' };\n }\n}\n","\nimport { PASSKEY_MANAGER_DEFAULT_CONFIGS } from \"../../../defaultConfigs\";\nimport type { CheckCanRegisterUserResult } from '../../../rpcCalls';\nimport { checkCanRegisterUserContractCall } from '../../../rpcCalls';\nimport { serializeRegistrationCredentialWithPRF, removePrfOutputGuard } from '../../credentialsHelpers';\nimport { VRFChallenge } from '../../../types/vrf-worker';\nimport { RegistrationPhase, RegistrationStatus, type RegistrationEventStep3 } from '../../../types/sdkSentEvents';\nimport type { AuthenticatorOptions } from '../../../types/authenticatorOptions';\nimport { SignerWorkerManagerContext } from '..';\nimport type { WebAuthnRegistrationCredential } from '../../../types/webauthn';\nimport { errorMessage } from '@/utils/errors';\nimport { isObject, isString } from '@/utils/validation';\n\n\nexport async function checkCanRegisterUser({\n ctx,\n vrfChallenge,\n credential,\n contractId,\n nearRpcUrl,\n authenticatorOptions,\n onEvent,\n}: {\n ctx: SignerWorkerManagerContext,\n vrfChallenge: VRFChallenge,\n credential: WebAuthnRegistrationCredential,\n contractId: string;\n nearRpcUrl: string;\n authenticatorOptions?: AuthenticatorOptions; // Authenticator options for registration check\n onEvent?: (update: RegistrationEventStep3) => void;\n}): Promise<{\n success: boolean;\n verified?: boolean;\n registrationInfo?: {\n credentialId: Uint8Array;\n credentialPublicKey: Uint8Array;\n userId: string;\n vrfPublicKey: Uint8Array | undefined;\n };\n logs?: string[];\n signedTransactionBorsh?: number[];\n error?: string;\n}> {\n try {\n // Accept either a real PublicKeyCredential or an already-serialized credential\n const isSerialized = (cred: unknown): cred is WebAuthnRegistrationCredential => {\n if (!isObject(cred)) return false;\n const resp = (cred as { response?: unknown }).response;\n if (!isObject(resp)) return false;\n return isString((resp as { clientDataJSON?: unknown }).clientDataJSON)\n && isString((resp as { attestationObject?: unknown }).attestationObject);\n };\n\n const serializedCredential: WebAuthnRegistrationCredential = isSerialized(credential)\n ? credential\n : serializeRegistrationCredentialWithPRF({ credential: credential });\n\n // Ensure required fields are present; avoid undefined which gets dropped by JSON.stringify in the worker\n const resolvedContractId = contractId || PASSKEY_MANAGER_DEFAULT_CONFIGS.contractId;\n\n onEvent?.({\n step: 3,\n phase: RegistrationPhase.STEP_3_CONTRACT_PRE_CHECK,\n status: RegistrationStatus.PROGRESS,\n message: 'Running webauthn contract registration checks...',\n });\n\n // PRF outputs must never be sent over the network. Strip them before\n // calling the contract while preserving the rest of the credential shape.\n const strippedCredential = removePrfOutputGuard<WebAuthnRegistrationCredential>(serializedCredential);\n\n const result: CheckCanRegisterUserResult = await checkCanRegisterUserContractCall({\n nearClient: ctx.nearClient,\n contractId: resolvedContractId,\n vrfChallenge,\n credential: strippedCredential,\n authenticatorOptions,\n });\n\n if (!result.success) {\n throw new Error(result.error || 'Registration pre-check RPC failed');\n }\n\n const wasmResult = {\n verified: result.verified,\n registrationInfo: undefined,\n logs: result.logs,\n error: result.error,\n };\n\n onEvent?.({\n step: 3,\n phase: RegistrationPhase.STEP_3_CONTRACT_PRE_CHECK,\n status: result.verified ? RegistrationStatus.SUCCESS : RegistrationStatus.ERROR,\n message: result.verified ? 'Registration pre-check succeeded' : (result.error || 'Registration pre-check failed'),\n ...(result.verified ? {} : { error: result.error || 'Registration pre-check failed' }),\n });\n\n return {\n success: true,\n verified: wasmResult.verified,\n registrationInfo: wasmResult.registrationInfo,\n logs: wasmResult.logs,\n error: wasmResult.error,\n };\n\n } catch (error: unknown) {\n // Preserve the detailed error message instead of converting to generic error\n console.error('checkCanRegisterUser failed:', error);\n return {\n success: false,\n verified: false,\n error: errorMessage(error) || 'Unknown error occurred',\n logs: [],\n };\n }\n}\n","import * as wasmModule from '../../wasm_signer_worker/pkg/wasm_signer_worker.js';\n\n/**\n * User verification policy for WebAuthn authenticators\n *\n * @example\n * ```typescript\n * // Require user verification (PIN, fingerprint, etc.)\n * UserVerificationPolicy.Required\n *\n * // Prefer user verification but don't require it\n * UserVerificationPolicy.Preferred\n *\n * // Discourage user verification (for performance)\n * UserVerificationPolicy.Discouraged\n * ```\n */\nexport enum UserVerificationPolicy {\n Required = 'required',\n Preferred = 'preferred',\n Discouraged = 'discouraged'\n}\n\n/**\n * Origin policy input for WebAuthn registration (matches WASM OriginPolicyInput struct)\n * Note: choose only one of the fields: single, all_subdomains, multiple\n */\nexport interface OriginPolicyInput {\n single: boolean | undefined;\n all_subdomains: boolean | undefined;\n multiple: string[] | undefined;\n}\n\nexport const toEnumUserVerificationPolicy = (userVerification: UserVerificationPolicy | undefined): wasmModule.UserVerificationPolicy => {\n switch (userVerification) {\n case UserVerificationPolicy.Required:\n return wasmModule.UserVerificationPolicy.Required;\n case UserVerificationPolicy.Preferred:\n return wasmModule.UserVerificationPolicy.Preferred;\n case UserVerificationPolicy.Discouraged:\n return wasmModule.UserVerificationPolicy.Discouraged;\n default:\n return wasmModule.UserVerificationPolicy.Preferred;\n }\n};\n\nexport interface AuthenticatorOptions {\n userVerification: UserVerificationPolicy;\n originPolicy: OriginPolicyInput;\n}\n\n/**\n * Default authenticator options (matches contract defaults)\n */\nexport const DEFAULT_AUTHENTICATOR_OPTIONS: AuthenticatorOptions = {\n userVerification: UserVerificationPolicy.Preferred,\n originPolicy: {\n single: undefined,\n all_subdomains: true,\n multiple: undefined\n }\n};\n","\nexport function withSessionId<T extends object>(\n sessionId: string,\n payload: T,\n): T & { sessionId: string } {\n\n if (!sessionId) {\n throw new Error('withSessionId: sessionId is required');\n }\n\n const existing = (payload as { sessionId?: unknown })?.sessionId;\n if (existing != null && typeof existing !== 'string') {\n throw new Error('withSessionId: payload.sessionId must be a string when provided');\n }\n if (existing && existing !== sessionId) {\n throw new Error(\n `withSessionId: payload.sessionId (${existing}) does not match provided sessionId (${sessionId})`,\n );\n }\n\n return { ...payload, sessionId };\n}\n","\nimport type { LocalNearSkV3Material } from '../../../IndexedDBManager/passkeyNearKeysDB';\nimport type { AuthenticatorOptions } from '../../../types/authenticatorOptions';\nimport {\n WorkerRequestType,\n isDeriveNearKeypairAndEncryptSuccess,\n} from '../../../types/signer-worker';\nimport { AccountId, toAccountId } from \"../../../types/accountIds\";\nimport { getLastLoggedInDeviceNumber } from '../getDeviceNumber';\nimport { SignerWorkerManagerContext } from '..';\nimport type { WebAuthnRegistrationCredential } from '@/core/types/webauthn';\nimport { toEnumUserVerificationPolicy } from '../../../types/authenticatorOptions';\nimport { withSessionId } from './session';\n\n/**\n * Derive NEAR keypair and encrypt it from a serialized WebAuthn registration credential\n * (shape compatible with SerializedRegistrationCredential from WASM) by extracting PRF outputs from it.\n */\nexport async function deriveNearKeypairAndEncryptFromSerialized({\n ctx,\n credential,\n nearAccountId,\n options,\n sessionId,\n}: {\n ctx: SignerWorkerManagerContext,\n credential: WebAuthnRegistrationCredential;\n nearAccountId: AccountId,\n options?: {\n authenticatorOptions?: AuthenticatorOptions;\n deviceNumber?: number;\n };\n sessionId: string;\n}): Promise<{\n success: boolean;\n nearAccountId: AccountId;\n publicKey: string;\n /**\n * Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for the encrypted private key.\n */\n chacha20NonceB64u?: string;\n wrapKeySalt?: string;\n error?: string;\n}> {\n try {\n // PRF outputs are now extracted by VRF worker and delivered to signer worker via MessagePort\n // No need to extract or send them through main thread\n if (!sessionId) throw new Error('Missing sessionId for registration WrapKeySeed delivery');\n\n const response = await ctx.sendMessage<WorkerRequestType.DeriveNearKeypairAndEncrypt>({\n sessionId,\n message: {\n type: WorkerRequestType.DeriveNearKeypairAndEncrypt,\n payload: withSessionId(sessionId, {\n nearAccountId: nearAccountId,\n credential,\n authenticatorOptions: options?.authenticatorOptions ? {\n userVerification: toEnumUserVerificationPolicy(options.authenticatorOptions.userVerification),\n originPolicy: options.authenticatorOptions.originPolicy,\n } : undefined,\n })\n },\n });\n\n if (!isDeriveNearKeypairAndEncryptSuccess(response)) {\n throw new Error('Dual PRF registration (from serialized) failed');\n }\n\n const wasmResult = response.payload;\n const wrapKeySaltPersisted = wasmResult.wrapKeySalt;\n if (!wrapKeySaltPersisted) {\n throw new Error('Missing wrapKeySalt in deriveNearKeypairAndEncrypt result');\n }\n // Prefer explicitly provided deviceNumber, else derive from IndexedDB state\n const deviceNumber = (typeof options?.deviceNumber === 'number')\n ? options!.deviceNumber!\n : await getLastLoggedInDeviceNumber(nearAccountId, ctx.indexedDB.clientDB);\n const chacha20NonceB64u = wasmResult.chacha20NonceB64u;\n if (!chacha20NonceB64u) {\n throw new Error('Missing chacha20NonceB64u in deriveNearKeypairAndEncrypt result');\n }\n const keyMaterial: LocalNearSkV3Material = {\n kind: 'local_near_sk_v3',\n nearAccountId,\n deviceNumber,\n publicKey: wasmResult.publicKey,\n encryptedSk: wasmResult.encryptedData,\n chacha20NonceB64u,\n wrapKeySalt: wrapKeySaltPersisted,\n timestamp: Date.now(),\n };\n await ctx.indexedDB.nearKeysDB.storeKeyMaterial(keyMaterial);\n\n return {\n success: true,\n nearAccountId: toAccountId(wasmResult.nearAccountId),\n publicKey: wasmResult.publicKey,\n chacha20NonceB64u,\n wrapKeySalt: wrapKeySaltPersisted,\n };\n } catch (error: unknown) {\n console.error('WebAuthnManager: deriveNearKeypairAndEncryptFromSerialized error:', error);\n const message = String((error as { message?: unknown })?.message || error || '');\n return {\n success: false,\n nearAccountId,\n publicKey: '',\n error: message\n };\n }\n}\n","\nimport { ClientAuthenticatorData } from '../../../IndexedDBManager';\nimport {\n WorkerRequestType,\n isDecryptPrivateKeyWithPrfSuccess,\n} from '../../../types/signer-worker';\nimport { AccountId, toAccountId } from \"../../../types/accountIds\";\n\nimport { SignerWorkerManagerContext } from '..';\nimport { getLastLoggedInDeviceNumber } from '../getDeviceNumber';\nimport { isObject } from '@/utils/validation';\nimport { withSessionId } from './session';\n\nexport async function decryptPrivateKeyWithPrf({\n ctx,\n nearAccountId,\n authenticators,\n sessionId,\n}: {\n ctx: SignerWorkerManagerContext,\n nearAccountId: AccountId,\n authenticators: ClientAuthenticatorData[],\n sessionId: string,\n}): Promise<{ decryptedPrivateKey: string; nearAccountId: AccountId }> {\n try {\n console.info('WebAuthnManager: Starting private key decryption with dual PRF (local operation)');\n // Retrieve encrypted key data from IndexedDB in main thread\n const deviceNumber = await getLastLoggedInDeviceNumber(nearAccountId, ctx.indexedDB.clientDB);\n const keyMaterial = await ctx.indexedDB.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber);\n if (!keyMaterial) {\n throw new Error(`No key material found for account: ${nearAccountId}`);\n }\n\n const response = await ctx.sendMessage({\n sessionId,\n message: {\n type: WorkerRequestType.DecryptPrivateKeyWithPrf,\n payload: withSessionId(sessionId, {\n nearAccountId: nearAccountId,\n encryptedPrivateKeyData: keyMaterial.encryptedSk,\n encryptedPrivateKeyChacha20NonceB64u: keyMaterial.chacha20NonceB64u,\n })\n },\n });\n\n if (!isDecryptPrivateKeyWithPrfSuccess(response)) {\n console.error('WebAuthnManager: Dual PRF private key decryption failed:', response);\n const payloadError = isObject(response?.payload) && (response as any)?.payload?.error;\n throw new Error(payloadError || 'Private key decryption failed');\n }\n return {\n decryptedPrivateKey: response.payload.privateKey,\n nearAccountId: toAccountId(response.payload.nearAccountId)\n };\n } catch (error: unknown) {\n console.error('WebAuthnManager: Dual PRF private key decryption error:', error);\n throw error;\n }\n}\n","/**\n * Session Handshake Orchestration for Signer Worker\n *\n * This module provides high-level functions for setting up and validating\n * signing sessions with the signer worker. It orchestrates the complete\n * handshake flow for port attachment so the VRF worker can deliver WrapKeySeed\n * to the signer worker over a session MessagePort.\n */\n\nimport { waitForWrapKeyPortAttach } from './sessionMessages.js';\nimport { computeUiIntentDigestFromTxs, orderActionForDigest } from '../../digests/intentDigest';\nimport type { NearClient } from '../../NearClient';\nimport type { NonceManager } from '../../nonceManager';\nimport type { TransactionContext } from '../../types/rpc';\nimport type { TransactionInputWasm } from '../../types/actions';\nimport { WorkerControlMessage } from '../../workerControlMessages';\n\ntype VrfSessionKeyDispenser = {\n dispenseSessionKey: (args: { sessionId: string; uses?: number }) => Promise<unknown>;\n};\n\n/**\n * Attach a WrapKeySeed MessagePort to the signer worker and wait for acknowledgment.\n * This ensures the port is successfully attached before proceeding.\n *\n * Flow:\n * 1. Register ACK listener (avoids race where worker responds before we listen)\n * 2. Send ATTACH_WRAP_KEY_SEED_PORT message with port transfer\n * 3. Wait for ATTACH_WRAP_KEY_SEED_PORT_OK acknowledgment\n *\n * @param worker - The signer worker to attach the port to\n * @param sessionId - The signing session ID\n * @param signerPort - The MessagePort for receiving WrapKeySeed material\n * @param timeoutMs - How long to wait for ACK (default: 2000ms)\n * @throws Error if attachment fails or times out\n */\nexport async function attachSessionPort(\n worker: Worker,\n sessionId: string,\n signerPort: MessagePort,\n timeoutMs: number = 2000\n): Promise<void> {\n // Register the ACK listener BEFORE sending the message to avoid race condition\n const waitPromise = waitForWrapKeyPortAttach(worker, sessionId, timeoutMs);\n\n // Send the attach command (transfer the port)\n worker.postMessage(\n { type: WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT, sessionId },\n [signerPort]\n );\n\n // Wait for the worker to acknowledge successful attachment\n await waitPromise;\n}\n\nexport const generateSessionId = (): string => {\n return (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function')\n ? crypto.randomUUID()\n : `sign-session-${Date.now()}-${Math.random().toString(16).slice(2)}`\n}\n\nexport function isWarmSessionUnavailableError(err: unknown): boolean {\n const msg = err instanceof Error ? err.message : String(err);\n return (\n msg.includes('SESSION_NOT_FOUND') ||\n msg.includes('SESSION_EXPIRED') ||\n msg.includes('SESSION_EXHAUSTED')\n );\n}\n\nfunction releaseNoncesBestEffort(nonceManager: NonceManager, nonces: string[]): void {\n for (const n of nonces) {\n try { nonceManager.releaseNonce(n); } catch {}\n }\n}\n\n/**\n * Warm signing helper for transaction-like operations.\n *\n * - Computes canonical `intentDigest` for UI/signer validation\n * - Reserves nonces for `txCount` to avoid collisions\n * - Attempts VRF session key dispense (WrapKeySeed + wrapKeySalt) without prompting\n *\n * Returns null when the VRF session is missing/expired/exhausted so callers can\n * fall back to full confirmTxFlow.\n */\nexport async function tryPrepareWarmSigningContext(args: {\n nearClient: NearClient;\n nonceManager: NonceManager;\n txInputsForDigest: TransactionInputWasm[];\n sessionId: string;\n vrfWorkerManager: VrfSessionKeyDispenser;\n nonceCount?: number;\n uses?: number;\n}): Promise<{ intentDigest: string; transactionContext: TransactionContext } | null> {\n const baseCtx = await args.nonceManager.getNonceBlockHashAndHeight(args.nearClient);\n const txCount = Math.max(1, args.nonceCount ?? args.txInputsForDigest.length ?? 1);\n const reservedNonces = args.nonceManager.reserveNonces(txCount);\n\n let keepReservations = false;\n try {\n const transactionContext: TransactionContext = {\n ...baseCtx,\n nextNonce: reservedNonces[0] ?? baseCtx.nextNonce,\n };\n\n const intentDigest = await computeUiIntentDigestFromTxs(\n args.txInputsForDigest.map(tx => ({\n receiverId: tx.receiverId,\n actions: tx.actions.map(orderActionForDigest),\n })) as TransactionInputWasm[]\n );\n\n const uses = Math.max(1, args.uses ?? txCount);\n try {\n await args.vrfWorkerManager.dispenseSessionKey({ sessionId: args.sessionId, uses });\n } catch (err) {\n if (isWarmSessionUnavailableError(err)) {\n return null;\n }\n throw err;\n }\n\n keepReservations = true;\n return { intentDigest, transactionContext };\n } finally {\n if (!keepReservations) {\n releaseNoncesBestEffort(args.nonceManager, reservedNonces);\n }\n }\n}\n","import type { SignerMode, ThresholdBehavior } from '../types/signer-worker';\nimport { DEFAULT_THRESHOLD_BEHAVIOR, getThresholdBehaviorFromSignerMode } from '../types/signer-worker';\nimport { stripTrailingSlashes, toTrimmedString } from '../../utils/validation';\n\nexport type ThresholdEd25519HealthzResponse =\n | { ok: true; configured: true }\n | { ok: false; configured: false; code?: string; message?: string };\n\nconst DEFAULT_CACHE_TTL_MS = 60_000;\nconst cache = new Map<string, { configured: boolean; expiresAtMs: number }>();\nconst inFlight = new Map<string, Promise<boolean>>();\nconst DEFAULT_WARN_TTL_MS = 10 * 60_000;\nconst MAX_WARN_KEYS = 1_000;\nconst warnedUnsupportedRelayerByKey = new Map<string, number>();\n\nexport async function isRelayerThresholdEd25519Configured(\n relayerUrl: string,\n opts?: { cacheTtlMs?: number },\n): Promise<boolean> {\n const base = stripTrailingSlashes(toTrimmedString(relayerUrl));\n return isRelayerThresholdEd25519ConfiguredBase(base, opts);\n}\n\nasync function isRelayerThresholdEd25519ConfiguredBase(\n base: string,\n opts?: { cacheTtlMs?: number },\n): Promise<boolean> {\n if (!base) return false;\n if (typeof fetch !== 'function') return false;\n\n const ttlMs = Math.max(0, Number(opts?.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS));\n const now = Date.now();\n const cached = cache.get(base);\n if (cached && cached.expiresAtMs > now) return cached.configured;\n\n const existing = inFlight.get(base);\n if (existing) return existing;\n\n const req = (async (): Promise<boolean> => {\n try {\n const res = await fetch(`${base}/threshold-ed25519/healthz`, { method: 'GET' });\n if (!res.ok) {\n cache.set(base, { configured: false, expiresAtMs: now + ttlMs });\n return false;\n }\n const data = (await res.json().catch(() => null)) as ThresholdEd25519HealthzResponse | null;\n const configured = data?.configured === true;\n cache.set(base, { configured, expiresAtMs: now + ttlMs });\n return configured;\n } catch {\n cache.set(base, { configured: false, expiresAtMs: now + ttlMs });\n return false;\n } finally {\n inFlight.delete(base);\n }\n })();\n\n inFlight.set(base, req);\n return req;\n}\n\nfunction coerceThresholdBehavior(input?: ThresholdBehavior): ThresholdBehavior {\n return input === 'fallback' || input === 'strict' ? input : DEFAULT_THRESHOLD_BEHAVIOR;\n}\n\nfunction pruneWarned(nowMs: number): void {\n if (warnedUnsupportedRelayerByKey.size <= MAX_WARN_KEYS) return;\n for (const [key, expiresAtMs] of warnedUnsupportedRelayerByKey.entries()) {\n if (expiresAtMs <= nowMs) warnedUnsupportedRelayerByKey.delete(key);\n }\n while (warnedUnsupportedRelayerByKey.size > MAX_WARN_KEYS) {\n const first = warnedUnsupportedRelayerByKey.keys().next().value as string | undefined;\n if (!first) break;\n warnedUnsupportedRelayerByKey.delete(first);\n }\n}\n\nfunction warnOnce(key: string, message: string, opts?: { warnTtlMs?: number; warnings?: string[] }): void {\n const nowMs = Date.now();\n const ttlMs = Math.max(0, Math.floor(opts?.warnTtlMs ?? DEFAULT_WARN_TTL_MS));\n if (ttlMs === 0) return;\n pruneWarned(nowMs);\n const existing = warnedUnsupportedRelayerByKey.get(key);\n if (existing && existing > nowMs) return;\n warnedUnsupportedRelayerByKey.set(key, nowMs + ttlMs);\n // eslint-disable-next-line no-console\n console.warn(message);\n opts?.warnings?.push(message);\n}\n\nexport async function fallbackToLocalSignerIfRelayerUnsupported(args: {\n nearAccountId: string;\n signerMode: SignerMode;\n relayerUrl: string;\n warnings?: string[];\n cacheTtlMs?: number;\n warnTtlMs?: number;\n}): Promise<SignerMode['mode']> {\n const requested = args.signerMode.mode;\n if (requested !== 'threshold-signer') return requested;\n\n const base = stripTrailingSlashes(toTrimmedString(args.relayerUrl));\n const behavior = coerceThresholdBehavior(getThresholdBehaviorFromSignerMode(args.signerMode));\n const configured = await isRelayerThresholdEd25519ConfiguredBase(base, { cacheTtlMs: args.cacheTtlMs });\n if (configured) return requested;\n\n const msg = '[WebAuthnManager] signerMode=threshold-signer requested but the relayer does not support threshold signing';\n if (behavior === 'fallback') {\n warnOnce(`${args.nearAccountId}|${base}`, `${msg}; falling back to local-signer`, {\n warnTtlMs: args.warnTtlMs,\n warnings: args.warnings,\n });\n return 'local-signer';\n }\n throw new Error(`${msg}; set signerMode={ mode: 'threshold-signer', behavior: 'fallback' } to allow local-signer fallback`);\n}\n\nexport async function resolveSignerModeForThresholdSigning(args: {\n nearAccountId: string;\n signerMode: SignerMode;\n relayerUrl: string;\n hasThresholdKeyMaterial: boolean;\n warnings?: string[];\n cacheTtlMs?: number;\n warnTtlMs?: number;\n}): Promise<SignerMode['mode']> {\n const requested = args.signerMode.mode;\n if (requested !== 'threshold-signer') return requested;\n\n const behavior = coerceThresholdBehavior(getThresholdBehaviorFromSignerMode(args.signerMode));\n\n if (!args.hasThresholdKeyMaterial) {\n const msg = '[WebAuthnManager] signerMode=threshold-signer requested but threshold key material is unavailable';\n if (behavior === 'fallback') {\n warnOnce(`${args.nearAccountId}|threshold-key-material-missing`, `${msg}; falling back to local-signer`, {\n warnTtlMs: args.warnTtlMs,\n warnings: args.warnings,\n });\n return 'local-signer';\n }\n throw new Error(`${msg}; set signerMode={ mode: 'threshold-signer', behavior: 'fallback' } to allow local-signer fallback`);\n }\n\n return fallbackToLocalSignerIfRelayerUnsupported({\n nearAccountId: args.nearAccountId,\n signerMode: args.signerMode,\n relayerUrl: args.relayerUrl,\n warnings: args.warnings,\n cacheTtlMs: args.cacheTtlMs,\n warnTtlMs: args.warnTtlMs,\n });\n}\n","import { base64UrlDecode } from '@/utils/encoders';\nimport { stripTrailingSlashes, toTrimmedString } from '@/utils/validation';\nimport { removePrfOutputGuard } from '../WebAuthnManager/credentialsHelpers';\nimport type { VRFChallenge } from '../types/vrf-worker';\nimport type { ThresholdEd25519SessionPolicy } from './thresholdSessionPolicy';\nimport type { WebAuthnAuthenticationCredential } from '../types/webauthn';\nimport { normalizeThresholdEd25519ParticipantIds } from '../../threshold/participants';\n\nexport type ThresholdEd25519SessionKind = 'jwt' | 'cookie';\n\nexport type ThresholdEd25519AuthSession = {\n sessionKind: ThresholdEd25519SessionKind;\n policy: ThresholdEd25519SessionPolicy;\n policyJson: string;\n sessionPolicyDigest32: string;\n jwt?: string;\n expiresAtMs?: number;\n};\n\ntype ThresholdEd25519AuthSessionCacheEntry = ThresholdEd25519AuthSession;\n\nconst authSessionCache = new Map<string, ThresholdEd25519AuthSessionCacheEntry>();\n\nexport function makeThresholdEd25519AuthSessionCacheKey(args: {\n nearAccountId: string;\n rpId: string;\n relayerUrl: string;\n relayerKeyId: string;\n participantIds?: number[];\n}): string {\n const relayerUrl = stripTrailingSlashes(toTrimmedString(args.relayerUrl));\n const participantIds = normalizeThresholdEd25519ParticipantIds(args.participantIds);\n return [\n String(args.nearAccountId || '').trim(),\n String(args.rpId || '').trim(),\n relayerUrl,\n String(args.relayerKeyId || '').trim(),\n ...(participantIds ? [participantIds.join(',')] : []),\n ].join('|');\n}\n\nexport function getCachedThresholdEd25519AuthSession(cacheKey: string): ThresholdEd25519AuthSession | null {\n const entry = authSessionCache.get(cacheKey);\n if (!entry) return null;\n\n if (typeof entry.expiresAtMs === 'number' && Number.isFinite(entry.expiresAtMs) && Date.now() >= entry.expiresAtMs) {\n authSessionCache.delete(cacheKey);\n return null;\n }\n\n return entry;\n}\n\nexport function putCachedThresholdEd25519AuthSession(cacheKey: string, entry: ThresholdEd25519AuthSession): void {\n authSessionCache.set(cacheKey, entry);\n}\n\nexport function clearCachedThresholdEd25519AuthSession(cacheKey: string): void {\n authSessionCache.delete(cacheKey);\n}\n\nexport function clearAllCachedThresholdEd25519AuthSessions(): void {\n authSessionCache.clear();\n}\n\nexport function getCachedThresholdEd25519AuthSessionJwt(cacheKey: string): string | undefined {\n const cached = getCachedThresholdEd25519AuthSession(cacheKey);\n const jwt = cached?.jwt;\n if (typeof jwt === 'string') {\n const trimmed = jwt.trim();\n if (trimmed) return trimmed;\n }\n if (cached) clearCachedThresholdEd25519AuthSession(cacheKey);\n return undefined;\n}\n\nexport async function mintThresholdEd25519AuthSession(args: {\n relayerUrl: string;\n sessionKind: ThresholdEd25519SessionKind;\n relayerKeyId: string;\n clientVerifyingShareB64u: string;\n sessionPolicy: ThresholdEd25519SessionPolicy;\n vrfChallenge: VRFChallenge;\n webauthnAuthentication: WebAuthnAuthenticationCredential;\n}): Promise<{\n ok: boolean;\n sessionId?: string;\n expiresAtMs?: number;\n remainingUses?: number;\n jwt?: string;\n code?: string;\n message?: string;\n}> {\n const relayerUrl = stripTrailingSlashes(toTrimmedString(args.relayerUrl));\n if (!relayerUrl) {\n return { ok: false, code: 'invalid_args', message: 'Missing relayerUrl for threshold session mint' };\n }\n\n if (typeof fetch !== 'function') {\n return { ok: false, code: 'unsupported', message: 'fetch is not available for threshold session mint' };\n }\n\n const toBytes = (b64u: string | undefined): number[] => {\n if (!b64u) return [];\n return Array.from(base64UrlDecode(b64u));\n };\n\n const intent_digest_32 = toBytes(args.vrfChallenge.intentDigest);\n if (intent_digest_32.length !== 32) {\n return { ok: false, code: 'invalid_args', message: 'Missing or invalid vrfChallenge.intentDigest (expected base64url 32 bytes)' };\n }\n\n const clientVerifyingShareBytes = toBytes(args.clientVerifyingShareB64u);\n if (clientVerifyingShareBytes.length !== 32) {\n return { ok: false, code: 'invalid_args', message: 'Missing or invalid clientVerifyingShareB64u (expected base64url 32 bytes)' };\n }\n\n const session_policy_digest_32 = toBytes(args.vrfChallenge.sessionPolicyDigest32);\n if (session_policy_digest_32.length !== 32) {\n return { ok: false, code: 'invalid_args', message: 'Missing vrfChallenge.sessionPolicyDigest32 (expected base64url 32 bytes) for threshold session mint' };\n }\n\n const vrf_data = {\n vrf_input_data: toBytes(args.vrfChallenge.vrfInput),\n vrf_output: toBytes(args.vrfChallenge.vrfOutput),\n vrf_proof: toBytes(args.vrfChallenge.vrfProof),\n public_key: toBytes(args.vrfChallenge.vrfPublicKey),\n user_id: args.vrfChallenge.userId,\n rp_id: args.vrfChallenge.rpId,\n block_height: Number(args.vrfChallenge.blockHeight || 0),\n block_hash: toBytes(args.vrfChallenge.blockHash),\n intent_digest_32,\n session_policy_digest_32,\n };\n\n // Never send PRF outputs to the relay.\n const webauthn_authentication = removePrfOutputGuard(args.webauthnAuthentication);\n\n type ThresholdEd25519SessionMintResponseBody = Partial<{\n ok: boolean;\n sessionId: string;\n expiresAt: string;\n remainingUses: number;\n jwt: string;\n code: string;\n message: string;\n }>;\n\n try {\n const url = `${relayerUrl}/threshold-ed25519/session`;\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: args.sessionKind === 'cookie' ? 'include' : 'omit',\n body: JSON.stringify({\n sessionKind: args.sessionKind,\n relayerKeyId: args.relayerKeyId,\n clientVerifyingShareB64u: args.clientVerifyingShareB64u,\n sessionPolicy: args.sessionPolicy,\n vrf_data,\n webauthn_authentication,\n }),\n });\n\n const data = (await response.json().catch(() => ({}))) as ThresholdEd25519SessionMintResponseBody;\n if (!response.ok) {\n return {\n ok: false,\n code: data.code || 'http_error',\n message: data.message || `HTTP ${response.status}`,\n };\n }\n\n const expiresAtMs = (() => {\n const raw = data.expiresAt ? Date.parse(data.expiresAt) : NaN;\n return Number.isFinite(raw) ? raw : undefined;\n })();\n\n return {\n ok: data.ok === true,\n sessionId: data.sessionId,\n expiresAtMs,\n remainingUses: data.remainingUses,\n jwt: data.jwt,\n ...(data.code ? { code: data.code } : {}),\n ...(data.message ? { message: data.message } : {}),\n };\n } catch (e: unknown) {\n const msg = String((e && typeof e === 'object' && 'message' in e) ? (e as { message?: unknown }).message : e || 'Failed to mint threshold session');\n return { ok: false, code: 'network_error', message: msg };\n }\n}\n","import { alphabetizeStringify, sha256BytesUtf8 } from '@/utils/digests';\nimport { base64UrlEncode } from '@/utils/encoders';\nimport { normalizeThresholdEd25519ParticipantIds } from '../../threshold/participants';\n\nexport const THRESHOLD_SESSION_POLICY_VERSION = 'threshold_session_v1' as const;\n\nexport type ThresholdEd25519SessionPolicy = {\n version: typeof THRESHOLD_SESSION_POLICY_VERSION;\n nearAccountId: string;\n rpId: string;\n relayerKeyId: string;\n sessionId: string;\n /**\n * Optional signer set binding (participant ids).\n *\n * When present, the relayer must bind the session token to this signer set and ensure\n * downstream signature share usage is scoped to the same set.\n */\n participantIds?: number[];\n ttlMs: number;\n remainingUses: number;\n};\n\nexport const THRESHOLD_SESSION_POLICY_MAX_TTL_MS = 10 * 60_000;\nexport const THRESHOLD_SESSION_POLICY_MAX_USES = 20;\n\n// Default policy used when callers do not specify a policy explicitly.\n// These defaults are kept conservative to limit the blast radius of a stolen token.\nexport const DEFAULT_THRESHOLD_SESSION_POLICY: Pick<ThresholdEd25519SessionPolicy, 'ttlMs' | 'remainingUses'> = {\n ttlMs: 5 * 60_000,\n remainingUses: 5,\n};\n\nexport function clampThresholdSessionPolicy(input: {\n ttlMs: number;\n remainingUses: number;\n}): { ttlMs: number; remainingUses: number } {\n const ttlMs = Math.max(0, Math.floor(Number(input.ttlMs) || 0));\n const remainingUses = Math.max(0, Math.floor(Number(input.remainingUses) || 0));\n return {\n ttlMs: Math.min(ttlMs, THRESHOLD_SESSION_POLICY_MAX_TTL_MS),\n remainingUses: Math.min(remainingUses, THRESHOLD_SESSION_POLICY_MAX_USES),\n };\n}\n\nexport function generateThresholdSessionId(): string {\n const id = (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function')\n ? crypto.randomUUID()\n : `tsess-${Date.now()}-${Math.random().toString(16).slice(2)}`;\n return `tsess-${id}`;\n}\n\nexport async function computeThresholdSessionPolicyDigest32(policy: ThresholdEd25519SessionPolicy): Promise<string> {\n const json = alphabetizeStringify(policy);\n const bytes = await sha256BytesUtf8(json);\n return base64UrlEncode(bytes);\n}\n\nexport async function buildThresholdSessionPolicy(params: {\n nearAccountId: string;\n rpId: string;\n relayerKeyId: string;\n participantIds?: number[];\n sessionId?: string;\n ttlMs?: number;\n remainingUses?: number;\n}): Promise<{\n policy: ThresholdEd25519SessionPolicy;\n policyJson: string;\n sessionPolicyDigest32: string;\n}> {\n const sessionId = params.sessionId || generateThresholdSessionId();\n const { ttlMs, remainingUses } = clampThresholdSessionPolicy({\n ttlMs: params.ttlMs ?? DEFAULT_THRESHOLD_SESSION_POLICY.ttlMs,\n remainingUses: params.remainingUses ?? DEFAULT_THRESHOLD_SESSION_POLICY.remainingUses,\n });\n const participantIds = normalizeThresholdEd25519ParticipantIds(params.participantIds);\n const policy: ThresholdEd25519SessionPolicy = {\n version: THRESHOLD_SESSION_POLICY_VERSION,\n nearAccountId: params.nearAccountId,\n rpId: params.rpId,\n relayerKeyId: params.relayerKeyId,\n sessionId,\n ...(participantIds ? { participantIds } : {}),\n ttlMs,\n remainingUses,\n };\n const sessionPolicyDigest32 = await computeThresholdSessionPolicyDigest32(policy);\n return { policy, policyJson: JSON.stringify(policy), sessionPolicyDigest32 };\n}\n\nexport function isThresholdSessionAuthUnavailableError(err: unknown): boolean {\n const msg = err instanceof Error ? err.message : String(err);\n return (\n msg.includes('no cached threshold session token') ||\n msg.includes('relayer threshold session expired') ||\n msg.includes('threshold session exhausted') ||\n msg.includes('threshold session expired') ||\n msg.includes('Missing or invalid threshold session token') ||\n msg.includes('Invalid session token kind') ||\n msg.includes('/authorize HTTP 401') ||\n msg.includes('/authorize HTTP 403')\n );\n}\n\nexport function isThresholdSignerMissingKeyError(err: unknown): boolean {\n const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();\n return (\n msg.includes('\"code\":\"missing_key\"') ||\n msg.includes('missing_key') ||\n msg.includes('unknown relayerkeyid') ||\n msg.includes('call /threshold-ed25519/keygen')\n );\n}\n","\nimport { SignedTransaction } from '../../../NearClient';\nimport { TransactionInputWasm, validateActionArgsWasm } from '../../../types/actions';\nimport { type onProgressEvents } from '../../../types/sdkSentEvents';\nimport {\n WorkerRequestType,\n TransactionPayload,\n isSignTransactionsWithActionsSuccess,\n isWorkerError,\n type ConfirmationConfig,\n type RpcCallPayload,\n type SignerMode,\n type TransactionResponse,\n type WorkerSuccessResponse,\n getThresholdBehaviorFromSignerMode,\n} from '../../../types/signer-worker';\nimport { AccountId } from '../../../types/accountIds';\nimport { SignerWorkerManagerContext } from '..';\nimport { PASSKEY_MANAGER_DEFAULT_CONFIGS } from '../../../defaultConfigs';\nimport { toAccountId } from '../../../types/accountIds';\nimport { getLastLoggedInDeviceNumber } from '../getDeviceNumber';\nimport { generateSessionId } from '../sessionHandshake.js';\nimport { WebAuthnAuthenticationCredential } from '../../../types';\nimport { removePrfOutputGuard } from '../../credentialsHelpers';\nimport { resolveSignerModeForThresholdSigning } from '../../../threshold/thresholdEd25519RelayerHealth';\nimport type { TransactionContext } from '../../../types/rpc';\nimport type { VRFChallenge } from '../../../types/vrf-worker';\nimport type {\n LocalNearSkV3Material,\n ThresholdEd25519_2p_V1Material,\n} from '../../../IndexedDBManager/passkeyNearKeysDB';\nimport {\n clearCachedThresholdEd25519AuthSession,\n getCachedThresholdEd25519AuthSessionJwt,\n makeThresholdEd25519AuthSessionCacheKey,\n} from '../../../threshold/thresholdEd25519AuthSession';\nimport {\n isThresholdSessionAuthUnavailableError,\n isThresholdSignerMissingKeyError,\n} from '../../../threshold/thresholdSessionPolicy';\nimport { normalizeThresholdEd25519ParticipantIds } from '../../../../threshold/participants';\n\n/**\n * Sign multiple transactions with shared VRF challenge and credential\n * Efficiently processes multiple transactions with one PRF authentication\n */\nexport async function signTransactionsWithActions({\n ctx,\n sessionId: providedSessionId,\n transactions,\n rpcCall,\n signerMode,\n onEvent,\n confirmationConfigOverride,\n title,\n body,\n}: {\n ctx: SignerWorkerManagerContext,\n sessionId?: string;\n transactions: TransactionInputWasm[],\n rpcCall: RpcCallPayload;\n signerMode: SignerMode;\n onEvent?: (update: onProgressEvents) => void;\n // Allow callers to pass a partial override (e.g., { uiMode: 'drawer' })\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n title?: string;\n body?: string;\n}): Promise<Array<{\n signedTransaction: SignedTransaction;\n nearAccountId: AccountId;\n logs?: string[]\n}>> {\n\n const sessionId = providedSessionId ?? generateSessionId();\n const nearAccountId = rpcCall.nearAccountId;\n const relayerUrl = ctx.relayerUrl;\n\n transactions.forEach(txPayload => {\n txPayload.actions.forEach(action => {\n validateActionArgsWasm(action);\n })\n })\n\n const deviceNumber = await getLastLoggedInDeviceNumber(nearAccountId, ctx.indexedDB.clientDB);\n\n // Retrieve encrypted key data from IndexedDB in main thread\n const [localKeyMaterial, thresholdKeyMaterial] = await Promise.all([\n ctx.indexedDB.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber),\n ctx.indexedDB.nearKeysDB.getThresholdKeyMaterial(nearAccountId, deviceNumber),\n ]);\n if (!localKeyMaterial) {\n throw new Error(`No local key material found for account: ${nearAccountId}`);\n }\n\n\t const warnings: string[] = [];\n\t const thresholdBehavior = getThresholdBehaviorFromSignerMode(signerMode);\n\t const resolvedSignerMode = await resolveSignerModeForThresholdSigning({\n\t nearAccountId,\n\t signerMode,\n\t relayerUrl,\n\t hasThresholdKeyMaterial: !!thresholdKeyMaterial,\n warnings,\n });\n console.debug('[signTransactionsWithActions] resolvedSignerMode', { nearAccountId, resolvedSignerMode, warnings });\n\n const signingContext = validateAndPrepareSigningContext({\n nearAccountId,\n resolvedSignerMode,\n relayerUrl,\n rpId: ctx.touchIdPrompt.getRpId(),\n localKeyMaterial,\n thresholdKeyMaterial,\n });\n\n // Ensure nonce/block context is fetched for the same access key that will sign.\n // Threshold signing MUST use the threshold/group public key (relayer access key) for:\n // - correct nonce reservation\n // - relayer scope checks (/authorize expects signingPayload.transactionContext.nearPublicKeyStr == relayer key)\n ctx.nonceManager.initializeUser(toAccountId(nearAccountId), signingContext.signingNearPublicKeyStr);\n\n // Normalize rpcCall to ensure required fields are present.\n const resolvedRpcCall = {\n contractId: rpcCall.contractId || PASSKEY_MANAGER_DEFAULT_CONFIGS.contractId,\n nearRpcUrl: rpcCall.nearRpcUrl || PASSKEY_MANAGER_DEFAULT_CONFIGS.nearRpcUrl,\n nearAccountId: rpcCall.nearAccountId,\n } as RpcCallPayload;\n\n // Create transaction signing requests (shared by local + threshold signing).\n // NOTE: nonce and blockHash are computed in confirmation flow, not here.\n const txSigningRequests: TransactionPayload[] = transactions.map(tx => ({\n nearAccountId: rpcCall.nearAccountId,\n receiverId: tx.receiverId,\n actions: tx.actions,\n }));\n\n // Confirm via VRF-driven flow before sending anything to the signer worker.\n // WrapKeySeed derivation is handled inside confirmTxFlow (handleTransactionSigningFlow),\n // which uses the same sessionId/requestId and delivers WrapKeySeed over the reserved port.\n if (!ctx.vrfWorkerManager) {\n throw new Error('VrfWorkerManager not available for signing');\n }\n const confirmation = await ctx.vrfWorkerManager.confirmAndPrepareSigningSession({\n ctx,\n sessionId,\n kind: 'transaction',\n ...(signingContext.threshold && !signingContext.threshold.thresholdSessionJwt ? { signingAuthMode: 'webauthn' } : {}),\n txSigningRequests: transactions,\n rpcCall: resolvedRpcCall,\n confirmationConfigOverride,\n title,\n body,\n });\n\n\t let { intentDigest, transactionContext, vrfChallenge, credential } =\n\t extractSigningEvidenceFromConfirmation(confirmation);\n\n\t // Threshold signer: authorize with relayer and pass threshold config into the signer worker.\n\t if (signingContext.threshold) {\n\t const requestPayload = {\n\t signerMode: signingContext.resolvedSignerMode,\n\t rpcCall: resolvedRpcCall,\n\t createdAt: Date.now(),\n\t decryption: {\n encryptedPrivateKeyData: '',\n encryptedPrivateKeyChacha20NonceB64u: '',\n },\n threshold: {\n relayerUrl: signingContext.threshold.relayerUrl,\n relayerKeyId: signingContext.threshold.thresholdKeyMaterial.relayerKeyId,\n clientParticipantId: signingContext.threshold.thresholdKeyMaterial.participants.find((p) => p.role === 'client')?.id,\n relayerParticipantId: signingContext.threshold.thresholdKeyMaterial.participants.find((p) => p.role === 'relayer')?.id,\n participantIds: signingContext.threshold.thresholdKeyMaterial.participants.map((p) => p.id),\n thresholdSessionKind: 'jwt' as const,\n thresholdSessionJwt: signingContext.threshold.thresholdSessionJwt,\n },\n txSigningRequests,\n intentDigest,\n transactionContext,\n\t vrfChallenge,\n\t credential,\n\t };\n\n\t for (let attempt = 0; attempt < 2; attempt++) {\n\t try {\n\t const response = await ctx.sendMessage<typeof WorkerRequestType.SignTransactionsWithActions>({\n\t sessionId,\n\t message: { type: WorkerRequestType.SignTransactionsWithActions, payload: requestPayload },\n\t onEvent,\n\t });\n\t const okResponse = requireOkSignTransactionsWithActionsResponse(response);\n\t return toSignedTransactionResults({\n\t okResponse,\n\t expectedTransactionCount: transactions.length,\n\t nearAccountId,\n\t warnings,\n\t });\n\t } catch (e: unknown) {\n\t const err = e instanceof Error ? e : new Error(String(e));\n\n\t if (thresholdBehavior === 'fallback' && isThresholdSignerMissingKeyError(err)) {\n\t const msg =\n\t '[WebAuthnManager] threshold-signer requested but the relayer is missing the signing share; falling back to local-signer';\n\t // eslint-disable-next-line no-console\n\t console.warn(msg);\n\t warnings.push(msg);\n\n\t try {\n\t clearCachedThresholdEd25519AuthSession(signingContext.threshold.thresholdSessionCacheKey);\n\t } catch {}\n\t signingContext.threshold.thresholdSessionJwt = undefined;\n\t requestPayload.threshold.thresholdSessionJwt = undefined;\n\n\t ctx.nonceManager.initializeUser(toAccountId(nearAccountId), localKeyMaterial.publicKey);\n\t if (!credential || !vrfChallenge) {\n\t const refreshed = await ctx.vrfWorkerManager.confirmAndPrepareSigningSession({\n\t ctx,\n\t sessionId,\n\t kind: 'transaction',\n\t signingAuthMode: 'webauthn',\n\t txSigningRequests: transactions,\n\t rpcCall: resolvedRpcCall,\n\t confirmationConfigOverride,\n\t title,\n\t body,\n\t });\n\t ({ intentDigest, transactionContext, vrfChallenge, credential } =\n\t extractSigningEvidenceFromConfirmation(refreshed));\n\t } else {\n\t transactionContext = await ctx.nonceManager.getNonceBlockHashAndHeight(ctx.nearClient, { force: true });\n\t }\n\n\t return await signTransactionsWithActionsLocally({\n\t ctx,\n\t sessionId,\n\t onEvent,\n\t resolvedRpcCall,\n\t localKeyMaterial,\n\t txSigningRequests,\n\t intentDigest,\n\t transactionContext,\n\t credential,\n\t expectedTransactionCount: transactions.length,\n\t warnings,\n\t });\n\t }\n\n\t if (attempt === 0 && isThresholdSessionAuthUnavailableError(err)) {\n\t clearCachedThresholdEd25519AuthSession(signingContext.threshold.thresholdSessionCacheKey);\n\t signingContext.threshold.thresholdSessionJwt = undefined;\n\t requestPayload.threshold.thresholdSessionJwt = undefined;\n\n\t if (!credential || !vrfChallenge) {\n\t const refreshed = await ctx.vrfWorkerManager.confirmAndPrepareSigningSession({\n\t ctx,\n\t sessionId,\n\t kind: 'transaction',\n\t signingAuthMode: 'webauthn',\n\t txSigningRequests: transactions,\n\t rpcCall: resolvedRpcCall,\n\t confirmationConfigOverride,\n\t title,\n\t body,\n\t });\n\n\t ({ intentDigest, transactionContext, vrfChallenge, credential } =\n\t extractSigningEvidenceFromConfirmation(refreshed));\n\n\t requestPayload.intentDigest = intentDigest;\n\t requestPayload.transactionContext = transactionContext;\n\t requestPayload.vrfChallenge = vrfChallenge;\n\t requestPayload.credential = credential;\n\t }\n\n\t continue;\n\t }\n\n\t throw err;\n\t }\n\t }\n\t }\n\n\t return await signTransactionsWithActionsLocally({\n\t ctx,\n\t sessionId,\n\t onEvent,\n\t resolvedRpcCall,\n\t localKeyMaterial,\n\t txSigningRequests,\n\t intentDigest,\n\t transactionContext,\n\t credential,\n\t expectedTransactionCount: transactions.length,\n\t warnings,\n\t });\n\n\t}\n\nasync function signTransactionsWithActionsLocally(args: {\n ctx: SignerWorkerManagerContext;\n sessionId: string;\n onEvent?: (update: onProgressEvents) => void;\n resolvedRpcCall: RpcCallPayload;\n localKeyMaterial: LocalNearSkV3Material;\n txSigningRequests: TransactionPayload[];\n intentDigest: string;\n transactionContext: TransactionContext;\n credential: string | undefined;\n expectedTransactionCount: number;\n warnings: string[];\n}): Promise<Array<{\n signedTransaction: SignedTransaction;\n nearAccountId: AccountId;\n logs?: string[];\n}>> {\n const response = await args.ctx.sendMessage<WorkerRequestType.SignTransactionsWithActions>({\n sessionId: args.sessionId,\n message: {\n type: WorkerRequestType.SignTransactionsWithActions,\n payload: {\n signerMode: 'local-signer',\n rpcCall: args.resolvedRpcCall,\n createdAt: Date.now(),\n decryption: {\n encryptedPrivateKeyData: args.localKeyMaterial.encryptedSk,\n encryptedPrivateKeyChacha20NonceB64u: args.localKeyMaterial.chacha20NonceB64u,\n },\n txSigningRequests: args.txSigningRequests,\n intentDigest: args.intentDigest,\n transactionContext: args.transactionContext,\n credential: args.credential,\n },\n },\n onEvent: args.onEvent,\n });\n\n const okResponse = requireOkSignTransactionsWithActionsResponse(response);\n return toSignedTransactionResults({\n okResponse,\n expectedTransactionCount: args.expectedTransactionCount,\n nearAccountId: args.resolvedRpcCall.nearAccountId,\n warnings: args.warnings,\n });\n}\n\nfunction toSignedTransactionResults(args: {\n okResponse: WorkerSuccessResponse<typeof WorkerRequestType.SignTransactionsWithActions>;\n expectedTransactionCount: number;\n nearAccountId: string;\n warnings: string[];\n}): Array<{\n signedTransaction: SignedTransaction;\n nearAccountId: AccountId;\n logs?: string[];\n}> {\n const signedTransactions = args.okResponse.payload.signedTransactions || [];\n if (signedTransactions.length !== args.expectedTransactionCount) {\n throw new Error(\n `Expected ${args.expectedTransactionCount} signed transactions but received ${signedTransactions.length}`\n );\n }\n\n return signedTransactions.map((signedTx, index) => {\n if (!signedTx || !signedTx.transaction || !signedTx.signature) {\n throw new Error(`Incomplete signed transaction data received for transaction ${index + 1}`);\n }\n return {\n signedTransaction: new SignedTransaction({\n transaction: signedTx.transaction,\n signature: signedTx.signature,\n borsh_bytes: Array.from(signedTx.borshBytes || []),\n }),\n nearAccountId: toAccountId(args.nearAccountId),\n logs: [...(args.okResponse.payload.logs || []), ...args.warnings],\n };\n });\n}\n\ntype ThresholdSigningContext = {\n resolvedSignerMode: 'threshold-signer';\n signingNearPublicKeyStr: string;\n threshold: {\n relayerUrl: string;\n thresholdKeyMaterial: ThresholdEd25519_2p_V1Material;\n thresholdSessionCacheKey: string;\n thresholdSessionJwt: string | undefined;\n };\n};\n\ntype LocalSigningContext = {\n resolvedSignerMode: 'local-signer';\n signingNearPublicKeyStr: string;\n threshold: null;\n};\n\ntype SigningContext = ThresholdSigningContext | LocalSigningContext;\n\nfunction validateAndPrepareSigningContext(args: {\n nearAccountId: string;\n resolvedSignerMode: SignerMode['mode'];\n relayerUrl: string;\n rpId: string | null;\n localKeyMaterial: LocalNearSkV3Material;\n thresholdKeyMaterial: ThresholdEd25519_2p_V1Material | null;\n}): SigningContext {\n const localPublicKey = String(args.localKeyMaterial.publicKey || '').trim();\n if (!localPublicKey) {\n throw new Error(`Missing local signing public key for ${args.nearAccountId}`);\n }\n\n if (args.resolvedSignerMode !== 'threshold-signer') {\n return { resolvedSignerMode: 'local-signer', signingNearPublicKeyStr: localPublicKey, threshold: null };\n }\n\n const thresholdKeyMaterial = args.thresholdKeyMaterial;\n if (!thresholdKeyMaterial) {\n throw new Error(`Missing threshold key material for ${args.nearAccountId}`);\n }\n\n const thresholdPublicKey = String(thresholdKeyMaterial.publicKey || '').trim();\n if (!thresholdPublicKey) {\n throw new Error(`Missing threshold signing public key for ${args.nearAccountId}`);\n }\n\n const relayerUrl = String(args.relayerUrl || '').trim();\n if (!relayerUrl) {\n throw new Error('Missing relayerUrl (required for threshold-signer)');\n }\n\n const rpId = String(args.rpId || '').trim();\n if (!rpId) {\n throw new Error('Missing rpId for threshold signing');\n }\n\n const participantIds = normalizeThresholdEd25519ParticipantIds(thresholdKeyMaterial.participants.map((p) => p.id));\n if (!participantIds || participantIds.length < 2) {\n throw new Error(\n `Invalid threshold signing participantIds (expected >=2 participants, got [${(participantIds || []).join(',')}])`\n );\n }\n\n const thresholdSessionCacheKey = makeThresholdEd25519AuthSessionCacheKey({\n nearAccountId: args.nearAccountId,\n rpId,\n relayerUrl,\n relayerKeyId: thresholdKeyMaterial.relayerKeyId,\n participantIds,\n });\n\n return {\n resolvedSignerMode: 'threshold-signer',\n signingNearPublicKeyStr: thresholdPublicKey,\n threshold: {\n relayerUrl,\n thresholdKeyMaterial,\n thresholdSessionCacheKey,\n thresholdSessionJwt: getCachedThresholdEd25519AuthSessionJwt(thresholdSessionCacheKey),\n },\n };\n}\n\nfunction extractSigningEvidenceFromConfirmation(confirmation: {\n intentDigest: string;\n transactionContext: TransactionContext;\n vrfChallenge?: VRFChallenge;\n credential?: unknown;\n}): {\n intentDigest: string;\n transactionContext: TransactionContext;\n vrfChallenge: VRFChallenge | undefined;\n credential: string | undefined;\n} {\n const credentialForRelay: WebAuthnAuthenticationCredential | undefined = confirmation.credential\n ? removePrfOutputGuard(confirmation.credential as WebAuthnAuthenticationCredential)\n : undefined;\n\n return {\n intentDigest: confirmation.intentDigest,\n transactionContext: confirmation.transactionContext,\n vrfChallenge: confirmation.vrfChallenge,\n credential: credentialForRelay ? JSON.stringify(credentialForRelay) : undefined,\n };\n}\n\nfunction requireOkSignTransactionsWithActionsResponse(\n response: TransactionResponse\n): WorkerSuccessResponse<typeof WorkerRequestType.SignTransactionsWithActions> {\n if (!isSignTransactionsWithActionsSuccess(response)) {\n if (isWorkerError(response)) {\n throw new Error(response.payload.error || 'Batch transaction signing failed');\n }\n throw new Error('Batch transaction signing failed');\n }\n\n if (!response.payload.success) {\n throw new Error(response.payload.error || 'Batch transaction signing failed');\n }\n return response;\n}\n","import { normalizeRegistrationCredential } from '../../credentialsHelpers';\nimport type { WebAuthnRegistrationCredential } from '../../../types/webauthn';\nimport { validateVRFChallenge, type VRFChallenge } from '../../../types/vrf-worker';\nimport type { TransactionContext } from '../../../types/rpc';\nimport { isObject, assertString } from '@/utils/validation';\nimport { DelegateActionInput } from '../../../types/delegate';\nimport { base58Encode } from '../../../../utils/base58';\n\nimport { ensureEd25519Prefix } from '../../../nearCrypto';\nexport { ensureEd25519Prefix };\n\nexport const toPublicKeyString = (pk: DelegateActionInput['publicKey']): string => {\n if (typeof pk === 'string') {\n return pk;\n }\n return ensureEd25519Prefix(base58Encode(pk.keyData));\n};\n\n// Strongly typed payload expected from the WASM → JS boundary\nexport interface RegistrationCredentialConfirmationPayload {\n confirmed: boolean;\n requestId: string;\n intentDigest: string;\n credential: WebAuthnRegistrationCredential; // serialized PublicKeyCredential (no methods)\n vrfChallenge: VRFChallenge;\n transactionContext?: TransactionContext;\n error?: string;\n}\n\nfunction validateTransactionContextMaybe(input: unknown): TransactionContext | undefined {\n if (input == null) return undefined;\n if (!isObject(input)) {\n throw new Error('Invalid transactionContext: expected object');\n }\n\n const {\n nearPublicKeyStr,\n nextNonce,\n txBlockHeight,\n txBlockHash,\n accessKeyInfo,\n } = input as {\n nearPublicKeyStr?: unknown;\n nextNonce?: unknown;\n txBlockHeight?: unknown;\n txBlockHash?: unknown;\n accessKeyInfo?: unknown;\n };\n\n // Minimal structural validation; AccessKeyView is complex. Be tolerant because the WASM struct omits it.\n const normalizedNearPublicKeyStr = assertString(\n nearPublicKeyStr,\n 'transactionContext.nearPublicKeyStr',\n );\n const normalizedNextNonce = assertString(nextNonce, 'transactionContext.nextNonce');\n const normalizedTxBlockHeight = assertString(\n txBlockHeight,\n 'transactionContext.txBlockHeight',\n );\n const normalizedTxBlockHash = assertString(txBlockHash, 'transactionContext.txBlockHash');\n\n let normalizedAccessKeyInfo = accessKeyInfo as TransactionContext['accessKeyInfo'] | undefined;\n if (normalizedAccessKeyInfo != null && !isObject(normalizedAccessKeyInfo)) {\n throw new Error('Invalid transactionContext.accessKeyInfo: expected object');\n }\n if (normalizedAccessKeyInfo == null) {\n // Synthesize a minimal placeholder; not used by registration flows consuming this payload\n normalizedAccessKeyInfo = { nonce: 0 } as unknown as TransactionContext['accessKeyInfo'];\n }\n\n return {\n nearPublicKeyStr: normalizedNearPublicKeyStr,\n nextNonce: normalizedNextNonce,\n txBlockHeight: normalizedTxBlockHeight,\n txBlockHash: normalizedTxBlockHash,\n accessKeyInfo: normalizedAccessKeyInfo,\n };\n}\n\nfunction validateCredentialMaybe(input: unknown): WebAuthnRegistrationCredential | undefined {\n if (input == null) return undefined;\n\n const cred = normalizeRegistrationCredential(input);\n if (cred.type !== 'public-key') {\n throw new Error('Invalid credential.type: expected \"public-key\"');\n }\n\n const { id, rawId, response, authenticatorAttachment } = cred as {\n id?: unknown;\n rawId?: unknown;\n response?: unknown;\n authenticatorAttachment?: unknown;\n };\n\n // Core field/type validation (serialized shapes should be base64url strings)\n assertString(id, 'credential.id');\n assertString(rawId, 'credential.rawId');\n\n if (!isObject(response)) {\n throw new Error('Invalid credential.response: expected object');\n }\n\n const {\n clientDataJSON,\n attestationObject,\n transports,\n } = response as {\n clientDataJSON?: unknown;\n attestationObject?: unknown;\n transports?: unknown;\n };\n\n assertString(clientDataJSON, 'credential.response.clientDataJSON');\n assertString(attestationObject, 'credential.response.attestationObject');\n\n if (!Array.isArray(transports)) {\n throw new Error('Invalid credential.response.transports: expected string[]');\n }\n for (const t of transports) {\n if (typeof t !== 'string') {\n throw new Error('Invalid credential.response.transports item: expected string');\n }\n }\n\n if (authenticatorAttachment != null && typeof authenticatorAttachment !== 'string') {\n throw new Error('Invalid credential.authenticatorAttachment: expected string | undefined');\n }\n\n // Note: prf.results may be undefined/null here. We intentionally do NOT\n // require them at the boundary; internal callers that need PRF (e.g. key\n // derivation) will extract/compute them separately. Contract payloads must\n // not include PRF values.\n return cred;\n}\n\nfunction validateVrfChallengeMaybe(input: unknown): VRFChallenge | undefined {\n if (input == null) return undefined;\n return validateVRFChallenge(input as Parameters<typeof validateVRFChallenge>[0]);\n}\n\nexport function parseAndValidateRegistrationCredentialConfirmationPayload(\n payload: unknown,\n): RegistrationCredentialConfirmationPayload {\n\n if (!isObject(payload)) {\n throw new Error('Invalid response payload: expected object');\n }\n\n const {\n confirmed,\n requestId,\n intentDigest,\n credential,\n vrfChallenge,\n transactionContext,\n error,\n } = payload as {\n confirmed?: unknown;\n requestId?: unknown;\n intentDigest?: unknown;\n credential?: unknown;\n vrfChallenge?: unknown;\n transactionContext?: unknown;\n error?: unknown;\n };\n\n const normalizedRequestId = assertString(requestId, 'requestId');\n\n // intentDigest is only used for TX signing requests, not registration or link device requests\n const normalizedIntentDigest =\n intentDigest == null ? '' : assertString(intentDigest, 'intentDigest');\n\n const normalizedCredential =\n credential != null ? validateCredentialMaybe(credential) : undefined;\n\n if (!normalizedCredential) {\n throw new Error('Missing registration credential');\n }\n\n const normalizedVrfChallenge =\n vrfChallenge != null ? validateVrfChallengeMaybe(vrfChallenge) : undefined;\n\n if (!normalizedVrfChallenge) {\n throw new Error('Missing VRF Challenge');\n }\n\n const normalizedTransactionContext =\n transactionContext != null ? validateTransactionContextMaybe(transactionContext) : undefined;\n\n const normalizedError =\n error == null ? undefined : assertString(error, 'error');\n\n return {\n confirmed: !!confirmed,\n requestId: normalizedRequestId,\n intentDigest: normalizedIntentDigest,\n credential: normalizedCredential,\n vrfChallenge: normalizedVrfChallenge,\n transactionContext: normalizedTransactionContext,\n error: normalizedError,\n };\n}","import { PASSKEY_MANAGER_DEFAULT_CONFIGS } from '../../../defaultConfigs';\nimport { AccountId, toAccountId } from '../../../types/accountIds';\nimport { toActionArgsWasm, validateActionArgsWasm } from '../../../types/actions';\nimport { DelegateActionInput } from '../../../types/delegate';\nimport { type onProgressEvents } from '../../../types/sdkSentEvents';\nimport {\n ConfirmationConfig,\n RpcCallPayload,\n type SignerMode,\n WorkerRequestType,\n type DelegateSignResponse,\n isWorkerError,\n isSignDelegateActionSuccess,\n type WorkerSuccessResponse,\n WasmSignedDelegate,\n} from '../../../types/signer-worker';\nimport type { WebAuthnAuthenticationCredential } from '../../../types';\nimport { removePrfOutputGuard } from '../../credentialsHelpers';\nimport { resolveSignerModeForThresholdSigning } from '../../../threshold/thresholdEd25519RelayerHealth';\nimport type {\n LocalNearSkV3Material,\n ThresholdEd25519_2p_V1Material,\n} from '../../../IndexedDBManager/passkeyNearKeysDB';\nimport type { TransactionContext } from '../../../types/rpc';\nimport type { VRFChallenge } from '../../../types/vrf-worker';\nimport {\n clearCachedThresholdEd25519AuthSession,\n getCachedThresholdEd25519AuthSessionJwt,\n makeThresholdEd25519AuthSessionCacheKey,\n} from '../../../threshold/thresholdEd25519AuthSession';\nimport { isThresholdSessionAuthUnavailableError } from '../../../threshold/thresholdSessionPolicy';\nimport { normalizeThresholdEd25519ParticipantIds } from '../../../../threshold/participants';\nimport { SignerWorkerManagerContext } from '..';\nimport { getLastLoggedInDeviceNumber } from '../getDeviceNumber';\nimport { generateSessionId } from '../sessionHandshake.js';\nimport { ensureEd25519Prefix, toPublicKeyString } from './validation';\n\nexport async function signDelegateAction({\n ctx,\n delegate,\n rpcCall,\n signerMode,\n onEvent,\n confirmationConfigOverride,\n title,\n body,\n sessionId: providedSessionId,\n}: {\n ctx: SignerWorkerManagerContext;\n delegate: DelegateActionInput;\n rpcCall: RpcCallPayload;\n signerMode: SignerMode;\n onEvent?: (update: onProgressEvents) => void;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n title?: string;\n body?: string;\n sessionId?: string;\n}): Promise<{\n signedDelegate: WasmSignedDelegate;\n hash: string;\n nearAccountId: AccountId;\n logs?: string[];\n}> {\n const sessionId = providedSessionId ?? generateSessionId();\n const nearAccountId = rpcCall.nearAccountId || delegate.senderId;\n const relayerUrl = ctx.relayerUrl;\n\n const resolvedRpcCall = {\n contractId: rpcCall.contractId || PASSKEY_MANAGER_DEFAULT_CONFIGS.contractId,\n nearRpcUrl: rpcCall.nearRpcUrl || (PASSKEY_MANAGER_DEFAULT_CONFIGS.nearRpcUrl.split(',')[0] || PASSKEY_MANAGER_DEFAULT_CONFIGS.nearRpcUrl),\n nearAccountId,\n } as RpcCallPayload;\n\n const actionsWasm = delegate.actions.map(toActionArgsWasm);\n actionsWasm.forEach((action, actionIndex) => {\n try {\n validateActionArgsWasm(action);\n } catch (error) {\n throw new Error(\n `Delegate action ${actionIndex} validation failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n });\n\n const deviceNumber = await getLastLoggedInDeviceNumber(nearAccountId, ctx.indexedDB.clientDB);\n const [localKeyMaterial, thresholdKeyMaterial] = await Promise.all([\n ctx.indexedDB.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber),\n ctx.indexedDB.nearKeysDB.getThresholdKeyMaterial(nearAccountId, deviceNumber),\n ]);\n if (!localKeyMaterial) {\n throw new Error(`No local key material found for account: ${nearAccountId}`);\n }\n\n const warnings: string[] = [];\n const vrfWorkerManager = ctx.vrfWorkerManager;\n if (!vrfWorkerManager) {\n throw new Error('VrfWorkerManager not available for delegate signing');\n }\n\n const resolvedSignerMode = await resolveSignerModeForThresholdSigning({\n nearAccountId,\n signerMode,\n relayerUrl,\n hasThresholdKeyMaterial: !!thresholdKeyMaterial,\n warnings,\n });\n\n const signingContext = validateAndPrepareDelegateSigningContext({\n nearAccountId,\n resolvedSignerMode,\n relayerUrl,\n rpId: ctx.touchIdPrompt.getRpId(),\n localKeyMaterial,\n thresholdKeyMaterial,\n providedDelegatePublicKey: delegate.publicKey,\n warnings,\n });\n\n // Ensure nonce/block context is fetched for the same access key that will sign.\n // Threshold signing MUST use the threshold/group public key (relayer access key) for:\n // - correct nonce reservation\n // - relayer scope checks (/authorize expects signingPayload.delegate.publicKey == relayer key)\n ctx.nonceManager.initializeUser(toAccountId(nearAccountId), signingContext.signingNearPublicKeyStr);\n\n const confirmation = await vrfWorkerManager.confirmAndPrepareSigningSession({\n ctx,\n sessionId,\n kind: 'delegate',\n ...(signingContext.threshold && !signingContext.threshold.thresholdSessionJwt ? { signingAuthMode: 'webauthn' } : {}),\n nearAccountId,\n delegate: {\n senderId: delegate.senderId || nearAccountId,\n receiverId: delegate.receiverId,\n actions: actionsWasm,\n nonce: delegate.nonce,\n maxBlockHeight: delegate.maxBlockHeight,\n },\n rpcCall: resolvedRpcCall,\n confirmationConfigOverride,\n title,\n body,\n });\n\n let { intentDigest, transactionContext, vrfChallenge, credential } =\n extractSigningEvidenceFromConfirmation(confirmation);\n\n const delegatePayload = {\n senderId: delegate.senderId || nearAccountId,\n receiverId: delegate.receiverId,\n actions: actionsWasm,\n nonce: delegate.nonce.toString(),\n maxBlockHeight: delegate.maxBlockHeight.toString(),\n publicKey: signingContext.delegatePublicKeyStr,\n };\n\n if (!signingContext.threshold) {\n const response = await ctx.sendMessage<WorkerRequestType.SignDelegateAction>({\n sessionId,\n message: {\n type: WorkerRequestType.SignDelegateAction,\n payload: {\n signerMode: signingContext.resolvedSignerMode,\n rpcCall: resolvedRpcCall,\n createdAt: Date.now(),\n decryption: {\n encryptedPrivateKeyData: localKeyMaterial.encryptedSk,\n encryptedPrivateKeyChacha20NonceB64u: localKeyMaterial.chacha20NonceB64u,\n },\n delegate: delegatePayload,\n intentDigest,\n transactionContext,\n credential,\n },\n },\n onEvent,\n });\n\n const okResponse = requireOkSignDelegateActionResponse(response);\n return {\n signedDelegate: okResponse.payload.signedDelegate!,\n hash: okResponse.payload.hash!,\n nearAccountId: toAccountId(nearAccountId),\n logs: [...(okResponse.payload.logs || []), ...warnings],\n };\n }\n\n const requestPayload = {\n signerMode: signingContext.resolvedSignerMode,\n rpcCall: resolvedRpcCall,\n createdAt: Date.now(),\n decryption: {\n encryptedPrivateKeyData: '',\n encryptedPrivateKeyChacha20NonceB64u: '',\n },\n threshold: {\n relayerUrl: signingContext.threshold.relayerUrl,\n relayerKeyId: signingContext.threshold.thresholdKeyMaterial.relayerKeyId,\n clientParticipantId: signingContext.threshold.thresholdKeyMaterial.participants.find((p) => p.role === 'client')?.id,\n relayerParticipantId: signingContext.threshold.thresholdKeyMaterial.participants.find((p) => p.role === 'relayer')?.id,\n participantIds: signingContext.threshold.thresholdKeyMaterial.participants.map((p) => p.id),\n thresholdSessionKind: 'jwt' as const,\n thresholdSessionJwt: signingContext.threshold.thresholdSessionJwt,\n },\n delegate: delegatePayload,\n intentDigest,\n transactionContext,\n vrfChallenge,\n credential,\n };\n\n let okResponse: WorkerSuccessResponse<typeof WorkerRequestType.SignDelegateAction>;\n try {\n const resp = await ctx.sendMessage<typeof WorkerRequestType.SignDelegateAction>({\n sessionId,\n message: { type: WorkerRequestType.SignDelegateAction, payload: requestPayload },\n onEvent,\n });\n okResponse = requireOkSignDelegateActionResponse(resp);\n } catch (e: unknown) {\n const err = e instanceof Error ? e : new Error(String(e));\n if (!isThresholdSessionAuthUnavailableError(err)) throw err;\n\n clearCachedThresholdEd25519AuthSession(signingContext.threshold.thresholdSessionCacheKey);\n signingContext.threshold.thresholdSessionJwt = undefined;\n requestPayload.threshold.thresholdSessionJwt = undefined;\n\n if (!credential || !vrfChallenge) {\n const refreshed = await vrfWorkerManager.confirmAndPrepareSigningSession({\n ctx,\n sessionId,\n kind: 'delegate',\n signingAuthMode: 'webauthn',\n nearAccountId,\n delegate: {\n senderId: delegate.senderId || nearAccountId,\n receiverId: delegate.receiverId,\n actions: actionsWasm,\n nonce: delegate.nonce,\n maxBlockHeight: delegate.maxBlockHeight,\n },\n rpcCall: resolvedRpcCall,\n confirmationConfigOverride,\n title,\n body,\n });\n\n ({ intentDigest, transactionContext, vrfChallenge, credential } =\n extractSigningEvidenceFromConfirmation(refreshed));\n\n requestPayload.intentDigest = intentDigest;\n requestPayload.transactionContext = transactionContext;\n requestPayload.vrfChallenge = vrfChallenge;\n requestPayload.credential = credential;\n }\n\n const resp = await ctx.sendMessage<typeof WorkerRequestType.SignDelegateAction>({\n sessionId,\n message: { type: WorkerRequestType.SignDelegateAction, payload: requestPayload },\n onEvent,\n });\n okResponse = requireOkSignDelegateActionResponse(resp);\n }\n\n return {\n signedDelegate: okResponse.payload.signedDelegate!,\n hash: okResponse.payload.hash!,\n nearAccountId: toAccountId(nearAccountId),\n logs: [...(okResponse.payload.logs || []), ...warnings],\n };\n}\n\ntype ThresholdDelegateSigningContext = {\n resolvedSignerMode: 'threshold-signer';\n signingNearPublicKeyStr: string;\n delegatePublicKeyStr: string;\n threshold: {\n relayerUrl: string;\n thresholdKeyMaterial: ThresholdEd25519_2p_V1Material;\n thresholdSessionCacheKey: string;\n thresholdSessionJwt: string | undefined;\n };\n};\n\ntype LocalDelegateSigningContext = {\n resolvedSignerMode: 'local-signer';\n signingNearPublicKeyStr: string;\n delegatePublicKeyStr: string;\n threshold: null;\n};\n\ntype DelegateSigningContext = ThresholdDelegateSigningContext | LocalDelegateSigningContext;\n\nfunction validateAndPrepareDelegateSigningContext(args: {\n nearAccountId: string;\n resolvedSignerMode: SignerMode['mode'];\n relayerUrl: string;\n rpId: string | null;\n localKeyMaterial: LocalNearSkV3Material;\n thresholdKeyMaterial: ThresholdEd25519_2p_V1Material | null;\n providedDelegatePublicKey: DelegateActionInput['publicKey'];\n warnings: string[];\n}): DelegateSigningContext {\n const localPublicKey = ensureEd25519Prefix(args.localKeyMaterial.publicKey);\n if (!localPublicKey) {\n throw new Error(`Missing local signing public key for ${args.nearAccountId}`);\n }\n\n const providedDelegatePublicKeyStr = ensureEd25519Prefix(toPublicKeyString(args.providedDelegatePublicKey));\n\n if (args.resolvedSignerMode !== 'threshold-signer') {\n if (providedDelegatePublicKeyStr && providedDelegatePublicKeyStr !== localPublicKey) {\n args.warnings.push(\n `Delegate public key ${providedDelegatePublicKeyStr} does not match local signer key; using ${localPublicKey}`\n );\n }\n return {\n resolvedSignerMode: 'local-signer',\n signingNearPublicKeyStr: localPublicKey,\n delegatePublicKeyStr: localPublicKey,\n threshold: null,\n };\n }\n\n const thresholdKeyMaterial = args.thresholdKeyMaterial;\n if (!thresholdKeyMaterial) {\n throw new Error(`Missing threshold key material for ${args.nearAccountId}`);\n }\n\n const thresholdPublicKey = ensureEd25519Prefix(thresholdKeyMaterial.publicKey);\n if (!thresholdPublicKey) {\n throw new Error(`Missing threshold signing public key for ${args.nearAccountId}`);\n }\n\n if (providedDelegatePublicKeyStr && providedDelegatePublicKeyStr !== thresholdPublicKey) {\n args.warnings.push(\n `Delegate public key ${providedDelegatePublicKeyStr} does not match threshold signer key; using ${thresholdPublicKey}`\n );\n }\n\n const relayerUrl = String(args.relayerUrl || '').trim();\n if (!relayerUrl) {\n throw new Error('Missing relayerUrl (required for threshold-signer)');\n }\n\n const rpId = String(args.rpId || '').trim();\n if (!rpId) {\n throw new Error('Missing rpId for threshold signing');\n }\n\n const participantIds = normalizeThresholdEd25519ParticipantIds(thresholdKeyMaterial.participants.map((p) => p.id));\n if (!participantIds || participantIds.length < 2) {\n throw new Error(\n `Invalid threshold signing participantIds (expected >=2 participants, got [${(participantIds || []).join(',')}])`\n );\n }\n\n const thresholdSessionCacheKey = makeThresholdEd25519AuthSessionCacheKey({\n nearAccountId: args.nearAccountId,\n rpId,\n relayerUrl,\n relayerKeyId: thresholdKeyMaterial.relayerKeyId,\n participantIds,\n });\n\n return {\n resolvedSignerMode: 'threshold-signer',\n signingNearPublicKeyStr: thresholdPublicKey,\n delegatePublicKeyStr: thresholdPublicKey,\n threshold: {\n relayerUrl,\n thresholdKeyMaterial,\n thresholdSessionCacheKey,\n thresholdSessionJwt: getCachedThresholdEd25519AuthSessionJwt(thresholdSessionCacheKey),\n },\n };\n}\n\nfunction extractSigningEvidenceFromConfirmation(confirmation: {\n intentDigest: string;\n transactionContext: TransactionContext;\n vrfChallenge?: VRFChallenge;\n credential?: unknown;\n}): {\n intentDigest: string;\n transactionContext: TransactionContext;\n vrfChallenge: VRFChallenge | undefined;\n credential: string | undefined;\n} {\n const credentialForRelay: WebAuthnAuthenticationCredential | undefined = confirmation.credential\n ? removePrfOutputGuard(confirmation.credential as WebAuthnAuthenticationCredential)\n : undefined;\n\n return {\n intentDigest: confirmation.intentDigest,\n transactionContext: confirmation.transactionContext,\n vrfChallenge: confirmation.vrfChallenge,\n credential: credentialForRelay ? JSON.stringify(credentialForRelay) : undefined,\n };\n}\n\nfunction requireOkSignDelegateActionResponse(\n response: DelegateSignResponse\n): WorkerSuccessResponse<typeof WorkerRequestType.SignDelegateAction> {\n if (!isSignDelegateActionSuccess(response)) {\n if (isWorkerError(response)) {\n throw new Error(response.payload.error || 'Delegate action signing failed');\n }\n throw new Error('Delegate action signing failed');\n }\n\n if (!response.payload.success || !response.payload.signedDelegate || !response.payload.hash) {\n throw new Error(response.payload.error || 'Delegate action signing failed');\n }\n return response;\n}\n","import {\n WorkerRequestType, // from wasm worker\n isRecoverKeypairFromPasskeySuccess,\n} from '../../../types/signer-worker';\nimport type { WebAuthnAuthenticationCredential } from '../../../types/webauthn';\nimport { SignerWorkerManagerContext } from '..';\nimport { withSessionId } from './session';\n\n/**\n * Recover keypair from authentication credential for account recovery\n * Uses dual PRF-based Ed25519 key derivation with account-specific HKDF and AES encryption\n */\nexport async function recoverKeypairFromPasskey({\n ctx,\n credential,\n accountIdHint,\n sessionId,\n}: {\n ctx: SignerWorkerManagerContext;\n credential: WebAuthnAuthenticationCredential;\n accountIdHint?: string;\n sessionId: string;\n}): Promise<{\n publicKey: string;\n encryptedPrivateKey: string;\n /**\n * Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for the encrypted private key.\n */\n chacha20NonceB64u: string;\n accountIdHint?: string;\n wrapKeySalt: string;\n}> {\n try {\n console.info('SignerWorkerManager: Starting dual PRF-based keypair recovery from authentication credential');\n // Accept either live PublicKeyCredential or already-serialized auth credential\n\n // Verify dual PRF outputs are available\n if (\n !credential.clientExtensionResults?.prf?.results?.first ||\n !credential.clientExtensionResults?.prf?.results?.second\n ) {\n throw new Error('Dual PRF outputs required for account recovery - both ChaCha20 and Ed25519 PRF outputs must be available');\n }\n\n if (!sessionId) throw new Error('Missing sessionId for recovery WrapKeySeed delivery');\n\n // Use generic sendMessage with specific request type for better type safety\n const response = await ctx.sendMessage<WorkerRequestType.RecoverKeypairFromPasskey>({\n sessionId,\n message: {\n type: WorkerRequestType.RecoverKeypairFromPasskey,\n payload: withSessionId(sessionId, {\n credential,\n accountIdHint,\n })\n },\n });\n\n // response is RecoverKeypairSuccessResponse | RecoverKeypairFailureResponse\n if (!isRecoverKeypairFromPasskeySuccess(response)) {\n throw new Error('Dual PRF keypair recovery failed in WASM worker');\n }\n\n const chacha20NonceB64u = response.payload.chacha20NonceB64u;\n if (!chacha20NonceB64u) {\n throw new Error('Missing chacha20NonceB64u in recovery result');\n }\n return {\n publicKey: response.payload.publicKey,\n encryptedPrivateKey: response.payload.encryptedData,\n chacha20NonceB64u,\n accountIdHint: response.payload.accountIdHint,\n wrapKeySalt: response.payload.wrapKeySalt,\n };\n\n } catch (error: unknown) {\n console.error('SignerWorkerManager: Dual PRF keypair recovery error:', error);\n throw error;\n }\n}\n","\nimport { WorkerRequestType, isExtractCosePublicKeySuccess } from '../../../types/signer-worker';\nimport { SignerWorkerManagerContext } from '..';\n\n\n/**\n * Extract COSE public key from WebAuthn attestation object\n * Simple operation that doesn't require TouchID or progress updates\n */\nexport async function extractCosePublicKey({ ctx, attestationObjectBase64url }: {\n ctx: SignerWorkerManagerContext;\n attestationObjectBase64url: string;\n}): Promise<Uint8Array> {\n try {\n const response = await ctx.sendMessage<WorkerRequestType.ExtractCosePublicKey>({\n message: {\n type: WorkerRequestType.ExtractCosePublicKey,\n payload: {\n attestationObjectBase64url\n }\n }\n });\n\n if (isExtractCosePublicKeySuccess(response)) {\n return response.payload.cosePublicKeyBytes;\n } else {\n throw new Error('COSE public key extraction failed in WASM worker');\n }\n } catch (error: unknown) {\n throw error;\n }\n}\n","\nimport { SignedTransaction } from '../../../NearClient';\nimport { type ActionArgsWasm, validateActionArgsWasm } from '../../../types/actions';\nimport {\n WorkerRequestType,\n WorkerResponseType,\n WasmTransactionSignResult,\n} from '../../../types/signer-worker';\nimport { SignerWorkerManagerContext } from '..';\n\n/**\n * Sign transaction with raw private key (for key replacement in Option D device linking)\n * No TouchID/PRF required - uses provided private key directly\n */\nexport async function signTransactionWithKeyPair({\n ctx,\n nearPrivateKey,\n signerAccountId,\n receiverId,\n nonce,\n blockHash,\n actions\n}: {\n ctx: SignerWorkerManagerContext;\n nearPrivateKey: string;\n signerAccountId: string;\n receiverId: string;\n nonce: string;\n blockHash: string;\n actions: ActionArgsWasm[];\n}): Promise<{\n signedTransaction: SignedTransaction;\n logs?: string[];\n}> {\n try {\n console.info('SignerWorkerManager: Starting transaction signing with provided private key');\n // Validate actions\n actions.forEach(action => {\n validateActionArgsWasm(action);\n });\n\n const response = await ctx.sendMessage<WorkerRequestType.SignTransactionWithKeyPair>({\n message: {\n type: WorkerRequestType.SignTransactionWithKeyPair,\n payload: {\n nearPrivateKey,\n signerAccountId,\n receiverId,\n nonce,\n blockHash: blockHash,\n actions: actions\n }\n }\n });\n\n if (response.type !== WorkerResponseType.SignTransactionWithKeyPairSuccess) {\n console.error('SignerWorkerManager: Transaction signing with private key failed:', response);\n throw new Error('Transaction signing with private key failed');\n }\n\n const wasmResult = response.payload as WasmTransactionSignResult;\n if (!wasmResult.success) {\n throw new Error(wasmResult.error || 'Transaction signing failed');\n }\n // Extract the signed transaction\n const signedTransactions = wasmResult.signedTransactions || [];\n if (signedTransactions.length !== 1) {\n throw new Error(`Expected 1 signed transaction but received ${signedTransactions.length}`);\n }\n const signedTx = signedTransactions[0];\n if (!signedTx || !signedTx.transaction || !signedTx.signature) {\n throw new Error('Incomplete signed transaction data received');\n }\n\n const result = {\n signedTransaction: new SignedTransaction({\n transaction: signedTx.transaction,\n signature: signedTx.signature,\n borsh_bytes: Array.from(signedTx.borshBytes || [])\n }),\n logs: wasmResult.logs\n };\n\n console.debug('SignerWorkerManager: Transaction signing with private key successful');\n return result;\n\n } catch (error: unknown) {\n console.error('SignerWorkerManager: Transaction signing with private key error:', error);\n throw error;\n }\n}\n","import {\n WorkerRequestType,\n isSignNep413MessageSuccess,\n isWorkerError,\n type ConfirmationConfig,\n type Nep413SigningResponse,\n type SignerMode,\n type WorkerSuccessResponse,\n} from '../../../types/signer-worker';\nimport type { WebAuthnAuthenticationCredential } from '../../../types';\nimport { removePrfOutputGuard } from '../../credentialsHelpers';\nimport { resolveSignerModeForThresholdSigning } from '../../../threshold/thresholdEd25519RelayerHealth';\nimport type {\n LocalNearSkV3Material,\n ThresholdEd25519_2p_V1Material,\n} from '../../../IndexedDBManager/passkeyNearKeysDB';\nimport type { VRFChallenge } from '../../../types/vrf-worker';\nimport {\n clearCachedThresholdEd25519AuthSession,\n getCachedThresholdEd25519AuthSessionJwt,\n makeThresholdEd25519AuthSessionCacheKey,\n} from '../../../threshold/thresholdEd25519AuthSession';\nimport { isThresholdSessionAuthUnavailableError } from '../../../threshold/thresholdSessionPolicy';\nimport { normalizeThresholdEd25519ParticipantIds } from '../../../../threshold/participants';\nimport { getLastLoggedInDeviceNumber } from '../getDeviceNumber';\nimport { generateSessionId } from '../sessionHandshake.js';\nimport { SignerWorkerManagerContext } from '..';\n\n/**\n * Sign a NEP-413 message using the user's passkey-derived private key\n *\n * @param payload - NEP-413 signing parameters including message, recipient, nonce, and state\n * @returns Promise resolving to signing result with account ID, public key, and signature\n */\nexport async function signNep413Message({ ctx, payload }: {\n ctx: SignerWorkerManagerContext;\n payload: {\n message: string;\n recipient: string;\n nonce: string;\n state: string | null;\n accountId: string;\n signerMode: SignerMode;\n title?: string;\n body?: string;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n sessionId?: string;\n contractId?: string;\n nearRpcUrl?: string;\n };\n}): Promise<{\n success: boolean;\n accountId: string;\n publicKey: string;\n signature: string;\n state?: string;\n error?: string;\n}> {\n try {\n const sessionId = payload.sessionId ?? generateSessionId();\n const relayerUrl = ctx.relayerUrl;\n const nearAccountId = payload.accountId;\n\n const deviceNumber = await getLastLoggedInDeviceNumber(nearAccountId, ctx.indexedDB.clientDB);\n const [localKeyMaterial, thresholdKeyMaterial] = await Promise.all([\n ctx.indexedDB.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber),\n ctx.indexedDB.nearKeysDB.getThresholdKeyMaterial(nearAccountId, deviceNumber),\n ]);\n if (!localKeyMaterial) {\n throw new Error(`No local key material found for account: ${nearAccountId}`);\n }\n\n const resolvedSignerMode = await resolveSignerModeForThresholdSigning({\n nearAccountId,\n signerMode: payload.signerMode,\n relayerUrl,\n hasThresholdKeyMaterial: !!thresholdKeyMaterial,\n });\n\n const vrfWorkerManager = ctx.vrfWorkerManager;\n if (!vrfWorkerManager) {\n throw new Error('VrfWorkerManager not available for NEP-413 signing');\n }\n\n const signingContext = validateAndPrepareNep413SigningContext({\n nearAccountId,\n resolvedSignerMode,\n relayerUrl,\n rpId: ctx.touchIdPrompt.getRpId(),\n localKeyMaterial,\n thresholdKeyMaterial,\n });\n\n const confirmation = await vrfWorkerManager.confirmAndPrepareSigningSession({\n ctx,\n sessionId,\n kind: 'nep413',\n ...(signingContext.threshold && !signingContext.threshold.thresholdSessionJwt\n ? { signingAuthMode: 'webauthn' }\n : {}),\n nearAccountId,\n message: payload.message,\n recipient: payload.recipient,\n title: payload.title,\n body: payload.body,\n confirmationConfigOverride: payload.confirmationConfigOverride,\n contractId: payload.contractId,\n nearRpcUrl: payload.nearRpcUrl,\n });\n\n let { vrfChallenge, credential } = extractSigningEvidenceFromConfirmation(confirmation);\n\n const requestPayload = {\n signerMode: signingContext.resolvedSignerMode,\n message: payload.message,\n recipient: payload.recipient,\n nonce: payload.nonce,\n state: payload.state || undefined,\n accountId: nearAccountId,\n nearPublicKey: signingContext.nearPublicKey,\n decryption: signingContext.decryption,\n threshold: signingContext.threshold\n ? {\n relayerUrl: signingContext.threshold.relayerUrl,\n relayerKeyId: signingContext.threshold.thresholdKeyMaterial.relayerKeyId,\n clientParticipantId: signingContext.threshold.thresholdKeyMaterial.participants.find((p) => p.role === 'client')?.id,\n relayerParticipantId: signingContext.threshold.thresholdKeyMaterial.participants.find((p) => p.role === 'relayer')?.id,\n participantIds: signingContext.threshold.thresholdKeyMaterial.participants.map((p) => p.id),\n thresholdSessionKind: 'jwt' as const,\n thresholdSessionJwt: signingContext.threshold.thresholdSessionJwt,\n }\n : undefined,\n vrfChallenge,\n credential,\n };\n\n if (!signingContext.threshold) {\n const response = await ctx.sendMessage<typeof WorkerRequestType.SignNep413Message>({\n sessionId,\n message: { type: WorkerRequestType.SignNep413Message, payload: requestPayload },\n });\n const okResponse = requireOkSignNep413MessageResponse(response);\n\n return {\n success: true,\n accountId: okResponse.payload.accountId,\n publicKey: okResponse.payload.publicKey,\n signature: okResponse.payload.signature,\n state: okResponse.payload.state || undefined,\n };\n }\n\n let okResponse: WorkerSuccessResponse<typeof WorkerRequestType.SignNep413Message>;\n try {\n const response = await ctx.sendMessage<typeof WorkerRequestType.SignNep413Message>({\n sessionId,\n message: { type: WorkerRequestType.SignNep413Message, payload: requestPayload },\n });\n okResponse = requireOkSignNep413MessageResponse(response);\n } catch (e: unknown) {\n const err = e instanceof Error ? e : new Error(String(e));\n if (!isThresholdSessionAuthUnavailableError(err)) throw err;\n\n clearCachedThresholdEd25519AuthSession(signingContext.threshold.thresholdSessionCacheKey);\n signingContext.threshold.thresholdSessionJwt = undefined;\n requestPayload.threshold!.thresholdSessionJwt = undefined;\n\n if (!credential || !vrfChallenge) {\n const refreshed = await vrfWorkerManager.confirmAndPrepareSigningSession({\n ctx,\n sessionId,\n kind: 'nep413',\n signingAuthMode: 'webauthn',\n nearAccountId,\n message: payload.message,\n recipient: payload.recipient,\n title: payload.title,\n body: payload.body,\n confirmationConfigOverride: payload.confirmationConfigOverride,\n contractId: payload.contractId,\n nearRpcUrl: payload.nearRpcUrl,\n });\n\n ({ vrfChallenge, credential } = extractSigningEvidenceFromConfirmation(refreshed));\n\n requestPayload.vrfChallenge = vrfChallenge;\n requestPayload.credential = credential;\n }\n\n const response = await ctx.sendMessage<typeof WorkerRequestType.SignNep413Message>({\n sessionId,\n message: { type: WorkerRequestType.SignNep413Message, payload: requestPayload },\n });\n okResponse = requireOkSignNep413MessageResponse(response);\n }\n\n return {\n success: true,\n accountId: okResponse.payload.accountId,\n publicKey: okResponse.payload.publicKey,\n signature: okResponse.payload.signature,\n state: okResponse.payload.state || undefined,\n };\n } catch (error: unknown) {\n // eslint-disable-next-line no-console\n console.error('SignerWorkerManager: NEP-413 signing error:', error);\n return {\n success: false,\n accountId: '',\n publicKey: '',\n signature: '',\n error: (error && typeof (error as { message?: unknown }).message === 'string')\n ? (error as { message: string }).message\n : 'Unknown error'\n };\n }\n}\n\ntype ThresholdNep413SigningContext = {\n resolvedSignerMode: 'threshold-signer';\n nearPublicKey: string;\n decryption: { encryptedPrivateKeyData: string; encryptedPrivateKeyChacha20NonceB64u: string };\n threshold: {\n relayerUrl: string;\n thresholdKeyMaterial: ThresholdEd25519_2p_V1Material;\n thresholdSessionCacheKey: string;\n thresholdSessionJwt: string | undefined;\n };\n};\n\ntype LocalNep413SigningContext = {\n resolvedSignerMode: 'local-signer';\n nearPublicKey: string;\n decryption: { encryptedPrivateKeyData: string; encryptedPrivateKeyChacha20NonceB64u: string };\n threshold: null;\n};\n\ntype Nep413SigningContext = ThresholdNep413SigningContext | LocalNep413SigningContext;\n\nfunction validateAndPrepareNep413SigningContext(args: {\n nearAccountId: string;\n resolvedSignerMode: SignerMode['mode'];\n relayerUrl: string;\n rpId: string | null;\n localKeyMaterial: LocalNearSkV3Material;\n thresholdKeyMaterial: ThresholdEd25519_2p_V1Material | null;\n}): Nep413SigningContext {\n const localPublicKey = String(args.localKeyMaterial.publicKey || '').trim();\n if (!localPublicKey) {\n throw new Error(`Missing local signing public key for ${args.nearAccountId}`);\n }\n\n if (args.resolvedSignerMode !== 'threshold-signer') {\n return {\n resolvedSignerMode: 'local-signer',\n nearPublicKey: localPublicKey,\n decryption: {\n encryptedPrivateKeyData: args.localKeyMaterial.encryptedSk,\n encryptedPrivateKeyChacha20NonceB64u: args.localKeyMaterial.chacha20NonceB64u,\n },\n threshold: null,\n };\n }\n\n const thresholdKeyMaterial = args.thresholdKeyMaterial;\n if (!thresholdKeyMaterial) {\n throw new Error(`Missing threshold key material for ${args.nearAccountId}`);\n }\n\n const thresholdPublicKey = String(thresholdKeyMaterial.publicKey || '').trim();\n if (!thresholdPublicKey) {\n throw new Error(`Missing threshold signing public key for ${args.nearAccountId}`);\n }\n\n const relayerUrl = String(args.relayerUrl || '').trim();\n if (!relayerUrl) {\n throw new Error('Missing relayerUrl (required for threshold-signer)');\n }\n\n const rpId = String(args.rpId || '').trim();\n if (!rpId) {\n throw new Error('Missing rpId for threshold signing');\n }\n\n const participantIds = normalizeThresholdEd25519ParticipantIds(thresholdKeyMaterial.participants.map((p) => p.id));\n if (!participantIds || participantIds.length < 2) {\n throw new Error(\n `Invalid threshold signing participantIds (expected >=2 participants, got [${(participantIds || []).join(',')}])`\n );\n }\n\n const thresholdSessionCacheKey = makeThresholdEd25519AuthSessionCacheKey({\n nearAccountId: args.nearAccountId,\n rpId,\n relayerUrl,\n relayerKeyId: thresholdKeyMaterial.relayerKeyId,\n participantIds,\n });\n\n return {\n resolvedSignerMode: 'threshold-signer',\n nearPublicKey: thresholdPublicKey,\n decryption: {\n encryptedPrivateKeyData: '',\n encryptedPrivateKeyChacha20NonceB64u: '',\n },\n threshold: {\n relayerUrl,\n thresholdKeyMaterial,\n thresholdSessionCacheKey,\n thresholdSessionJwt: getCachedThresholdEd25519AuthSessionJwt(thresholdSessionCacheKey),\n },\n };\n}\n\nfunction extractSigningEvidenceFromConfirmation(confirmation: {\n vrfChallenge?: VRFChallenge;\n credential?: unknown;\n}): {\n vrfChallenge: VRFChallenge | undefined;\n credential: string | undefined;\n} {\n const credentialForRelay: WebAuthnAuthenticationCredential | undefined = confirmation.credential\n ? removePrfOutputGuard(confirmation.credential as WebAuthnAuthenticationCredential)\n : undefined;\n\n return {\n vrfChallenge: confirmation.vrfChallenge,\n credential: credentialForRelay ? JSON.stringify(credentialForRelay) : undefined,\n };\n}\n\nfunction requireOkSignNep413MessageResponse(\n response: Nep413SigningResponse,\n): WorkerSuccessResponse<typeof WorkerRequestType.SignNep413Message> {\n if (!isSignNep413MessageSuccess(response)) {\n if (isWorkerError(response)) {\n throw new Error(response.payload.error || 'NEP-413 signing failed');\n }\n throw new Error('NEP-413 signing failed');\n }\n return response;\n}\n","import { base64UrlDecode } from '../../../../utils';\nimport type { LocalNearSkV3Material } from '../../../IndexedDBManager/passkeyNearKeysDB';\nimport {\n WorkerRequestType,\n isRegisterDevice2WithDerivedKeySuccess,\n type WasmSignedTransaction,\n} from '../../../types/signer-worker';\nimport { AccountId, toAccountId } from \"../../../types/accountIds\";\nimport { SignerWorkerManagerContext } from '..';\nimport type { WebAuthnRegistrationCredential } from '@/core/types/webauthn';\nimport type { VRFChallenge } from '../../../types/vrf-worker';\nimport type { TransactionContext } from '../../../types/rpc';\nimport { withSessionId } from './session';\nimport { UserVerificationPolicy, toEnumUserVerificationPolicy } from '../../../types/authenticatorOptions';\n\n/**\n * Combined Device2 registration flow: derive NEAR keypair + sign registration transaction\n * in a single operation without requiring a separate authentication prompt.\n *\n * This handler orchestrates:\n * 1. Retrieving PRF.second and WrapKeySeed from session storage (delivered via MessagePort)\n * 2. Deriving NEAR ed25519 keypair from PRF.second\n * 3. Encrypting the NEAR private key with KEK (derived from WrapKeySeed + wrapKeySalt)\n * 4. Building the Device2 registration transaction (`link_device_register_user`)\n * 5. Signing the transaction with the derived NEAR keypair\n * 6. Storing encrypted key data in IndexedDB\n *\n * Security: PRF.second and WrapKeySeed never traverse the main thread - they're delivered\n * directly from VRF worker to Signer worker via MessagePort.\n */\nexport async function registerDevice2WithDerivedKey({\n ctx,\n sessionId,\n nearAccountId,\n credential,\n vrfChallenge,\n transactionContext,\n contractId,\n wrapKeySalt,\n deviceNumber,\n deterministicVrfPublicKey,\n}: {\n ctx: SignerWorkerManagerContext;\n sessionId: string;\n nearAccountId: AccountId;\n credential: WebAuthnRegistrationCredential;\n vrfChallenge: VRFChallenge;\n transactionContext: TransactionContext;\n contractId: string;\n wrapKeySalt: string;\n deviceNumber?: number;\n deterministicVrfPublicKey?: string;\n}): Promise<\n | {\n success: true;\n publicKey: string;\n signedTransaction: WasmSignedTransaction;\n wrapKeySalt: string;\n encryptedData: string;\n /**\n * Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for the encrypted private key.\n */\n chacha20NonceB64u: string;\n }\n | {\n success: false;\n publicKey: '';\n signedTransaction: null;\n wrapKeySalt: '';\n error: string;\n }\n> {\n try {\n if (!sessionId) {\n throw new Error('Missing sessionId for Device2 registration');\n }\n\n console.debug('[SignerWorkerManager] Starting Device2 combined registration', {\n nearAccountId,\n sessionId,\n deviceNumber,\n });\n\n // Helper to convert base64url string to byte array (number[])\n const b64ToBytes = (s: string | undefined): number[] => {\n if (!s) return [];\n return Array.from(base64UrlDecode(s));\n };\n const intentDigest32 = b64ToBytes(vrfChallenge.intentDigest);\n if (intentDigest32.length !== 32) {\n throw new Error('Missing or invalid vrfChallenge.intentDigest (expected base64url-encoded 32 bytes)');\n }\n // Construct contractArgs in TypeScript and use JSON.stringify() here.\n // This is native to JS, extremely fast, and means the Rust worker just receives a \"dumb\" string that it can blindly convert to bytes\n const finalContractArgs = {\n vrf_data: {\n vrf_input_data: b64ToBytes(vrfChallenge.vrfInput),\n vrf_output: b64ToBytes(vrfChallenge.vrfOutput),\n vrf_proof: b64ToBytes(vrfChallenge.vrfProof),\n public_key: b64ToBytes(vrfChallenge.vrfPublicKey),\n user_id: vrfChallenge.userId,\n rp_id: vrfChallenge.rpId,\n block_height: Number(vrfChallenge.blockHeight),\n block_hash: b64ToBytes(vrfChallenge.blockHash),\n intent_digest_32: intentDigest32,\n },\n webauthn_registration: credential,\n deterministic_vrf_public_key: b64ToBytes(deterministicVrfPublicKey),\n authenticator_options: {\n userVerification: toEnumUserVerificationPolicy(UserVerificationPolicy.Preferred),\n originPolicy: {\n single: undefined,\n all_subdomains: true,\n multiple: undefined,\n },\n },\n };\n\n // Build request payload for combined Device2 registration\n const response = await ctx.sendMessage<WorkerRequestType.RegisterDevice2WithDerivedKey>({\n sessionId,\n message: {\n type: WorkerRequestType.RegisterDevice2WithDerivedKey,\n payload: withSessionId(sessionId, {\n credential,\n nearAccountId,\n transactionContext: {\n txBlockHash: transactionContext.txBlockHash,\n txBlockHeight: transactionContext.txBlockHeight,\n baseNonce: transactionContext.nextNonce,\n },\n contractId,\n contractArgsJson: JSON.stringify(finalContractArgs),\n }),\n },\n });\n\n if (!isRegisterDevice2WithDerivedKeySuccess(response)) {\n throw new Error('Device2 combined registration failed');\n }\n\n const wasmResult = response.payload;\n\n console.debug('[SignerWorkerManager] Device2 registration complete, storing encrypted key');\n\n // Store encrypted NEAR key in IndexedDB\n const chacha20NonceB64u = wasmResult.chacha20NonceB64u;\n if (!chacha20NonceB64u) {\n throw new Error('Missing chacha20NonceB64u in Device2 registration result');\n }\n const wrapKeySaltPersisted = wasmResult.wrapKeySalt;\n if (!wrapKeySaltPersisted) {\n throw new Error('Missing wrapKeySalt in Device2 registration result');\n }\n\n const keyMaterial: LocalNearSkV3Material = {\n kind: 'local_near_sk_v3',\n nearAccountId,\n deviceNumber: deviceNumber ?? 2, // Default to device 2\n publicKey: wasmResult.publicKey,\n encryptedSk: wasmResult.encryptedData,\n chacha20NonceB64u,\n wrapKeySalt: wrapKeySaltPersisted,\n timestamp: Date.now(),\n };\n await ctx.indexedDB.nearKeysDB.storeKeyMaterial(keyMaterial);\n\n console.debug('[SignerWorkerManager] Device2 encrypted key stored successfully');\n\n return {\n success: true,\n publicKey: wasmResult.publicKey,\n signedTransaction: wasmResult.signedTransaction,\n wrapKeySalt: wrapKeySaltPersisted,\n encryptedData: wasmResult.encryptedData,\n chacha20NonceB64u,\n };\n } catch (error: unknown) {\n console.error('[SignerWorkerManager] registerDevice2WithDerivedKey error:', error);\n const message = String((error as { message?: unknown })?.message || error || '');\n return {\n success: false,\n publicKey: '',\n signedTransaction: null,\n wrapKeySalt: '',\n error: message,\n };\n }\n}\n","import type { ConfirmationConfig } from '../../../types/signer-worker';\nimport type { VrfWorkerManagerContext } from '../';\nimport type { SecureConfirmRequest } from './types';\nimport { SecureConfirmationType } from './types';\nimport { needsExplicitActivation } from '@/utils';\n\n/**\n * determineConfirmationConfig\n *\n * Computes the effective confirmation UI behavior used by the secure‑confirmation\n * flow by merging inputs and applying safe runtime rules.\n *\n * Order of precedence (highest → lowest):\n * 1) Request‑level override (request.confirmationConfig), when explicitly set.\n * 2) User preferences stored in the wallet host (from IndexedDB via ctx.userPreferencesManager).\n * 3) Runtime safety rules (wallet‑iframe registration/link flows) that may clamp behavior.\n *\n * Wallet‑iframe registration/link safety rule:\n * - When running inside the wallet-iframe host context, always clamp registration/link flows to\n * `{ uiMode: 'modal', behavior: 'requireClick' }` so the user activation happens inside the iframe.\n * This intentionally overrides both user preferences and request-level overrides.\n *\n * Notes\n * - The function is pure (does not mutate the input object) and safe to call multiple times.\n * - Theme and unrelated visual options are preserved in all cases.\n */\nexport function determineConfirmationConfig(\n ctx: VrfWorkerManagerContext,\n request: SecureConfirmRequest | undefined,\n): ConfirmationConfig {\n\n // Merge request‑level override over user preferences\n // Important: drop undefined/null fields from the override so they don't clobber\n // persisted preferences (e.g., behavior) with an undefined value.\n const configBase = ctx.userPreferencesManager.getConfirmationConfig();\n const rawOverride = (request?.confirmationConfig || {}) as Partial<ConfirmationConfig>;\n const cleanedOverride = Object.fromEntries(\n Object.entries(rawOverride).filter(([, v]) => v !== undefined && v !== null)\n ) as Partial<ConfirmationConfig>;\n let cfg: ConfirmationConfig = { ...configBase, ...cleanedOverride } as ConfirmationConfig;\n\n // Normalize theme default\n cfg = { ...cfg, theme: cfg.theme || 'dark' } as ConfirmationConfig;\n // Default decrypt-private-key confirmations to 'skip' UI. The flow collects\n // WebAuthn credentials silently and the worker may follow up with a\n // SHOW_SECURE_PRIVATE_KEY_UI request to display the key.\n if (request?.type === SecureConfirmationType.DECRYPT_PRIVATE_KEY_WITH_PRF) {\n return {\n uiMode: 'skip',\n behavior: cfg.behavior,\n autoProceedDelay: cfg.autoProceedDelay,\n theme: cfg.theme || 'dark',\n // container selection handled by uiMode only\n } as ConfirmationConfig;\n }\n // Detect if running inside an iframe (wallet host context)\n const inIframe = (() => window.self !== window.top)();\n\n // On Safari/iOS or mobile devices without a fresh user activation,\n // clamp to a clickable UI to reliably satisfy WebAuthn requirements.\n // - If caller/user set uiMode: 'skip', promote to 'modal' + requireClick\n // - If behavior is 'autoProceed', upgrade to 'requireClick'\n // Use shared heuristic to decide if explicit activation is necessary\n if (needsExplicitActivation()) {\n const newUiMode: ConfirmationConfig['uiMode'] = (cfg.uiMode === 'skip') ? 'drawer' : cfg.uiMode;\n cfg = {\n ...cfg,\n uiMode: newUiMode,\n behavior: 'requireClick',\n } as ConfirmationConfig;\n }\n\n // In wallet‑iframe host context: registration/link flows default to an explicit click.\n // However, if the effective config explicitly opts into auto‑proceed (or skip), honor it.\n if (\n inIframe &&\n request?.type &&\n (request.type === SecureConfirmationType.REGISTER_ACCOUNT || request.type === SecureConfirmationType.LINK_DEVICE)\n ) {\n // Cross‑origin registration/link flows: always require a visible, clickable confirmation\n // so the click lands inside the wallet iframe and satisfies WebAuthn activation.\n return {\n uiMode: 'modal',\n behavior: 'requireClick',\n autoProceedDelay: cfg.autoProceedDelay,\n theme: cfg.theme || 'dark',\n } as ConfirmationConfig;\n }\n\n // Otherwise honor caller/user configuration\n return cfg;\n}\n","import type { SecureConfirmRequest } from '../types';\nimport { SecureConfirmationType } from '../types';\nimport { isObject, isString } from '@/utils/validation';\n\n/**\n * Validates secure-confirm requests (V2 only).\n * This deliberately does not accept JSON strings or shorthand/legacy shapes.\n */\nexport function validateSecureConfirmRequest(input: unknown): SecureConfirmRequest {\n if (typeof input === 'string') {\n throw new Error('Invalid secure confirm request: expected an object (JSON strings are not supported)');\n }\n if (!isObject(input)) throw new Error('parsed is not an object');\n const p = input as {\n requestId?: unknown;\n type?: unknown;\n summary?: unknown;\n payload?: unknown;\n };\n if (!isString(p.requestId) || !p.requestId) throw new Error('missing requestId');\n if (!isString(p.type) || !p.type) throw new Error('missing type');\n if (p.summary === undefined || p.summary === null) throw new Error('missing summary');\n if (p.payload === undefined || p.payload === null) throw new Error('missing payload');\n return input as unknown as SecureConfirmRequest;\n}\n\nexport function assertNoForbiddenMainThreadSigningSecrets(request: SecureConfirmRequest): void {\n if (\n request.type !== SecureConfirmationType.SIGN_TRANSACTION\n && request.type !== SecureConfirmationType.SIGN_NEP413_MESSAGE\n ) {\n return;\n }\n\n const payload: any = (request as any).payload || {};\n if (payload.prfOutput !== undefined) {\n throw new Error('Invalid secure confirm request: forbidden signing payload field prfOutput');\n }\n if (payload.wrapKeySeed !== undefined) {\n throw new Error('Invalid secure confirm request: forbidden signing payload field wrapKeySeed');\n }\n if (payload.wrapKeySalt !== undefined) {\n throw new Error('Invalid secure confirm request: forbidden signing payload field wrapKeySalt');\n }\n if (payload.vrf_sk !== undefined) {\n throw new Error('Invalid secure confirm request: forbidden signing payload field vrf_sk');\n }\n}\n","import type { VrfWorkerManagerContext } from '../';\nimport type { ConfirmationConfig } from '../../../types/signer-worker';\nimport { determineConfirmationConfig } from './determineConfirmationConfig';\nimport {\n TransactionSummary,\n SecureConfirmMessageType,\n SecureConfirmRequest,\n SecureConfirmationType,\n} from './types';\nimport { errorMessage, toError } from '../../../../utils/errors';\nimport {\n parseTransactionSummary,\n getIntentDigest,\n sendConfirmResponse,\n sanitizeForPostMessage,\n} from './flows';\nimport {\n assertNoForbiddenMainThreadSigningSecrets,\n validateSecureConfirmRequest,\n} from './adapters/requestAdapter';\nimport type {\n LocalOnlySecureConfirmRequest,\n RegistrationSecureConfirmRequest,\n SigningSecureConfirmRequest,\n} from './types';\n\n/**\n * Handles secure confirmation requests from the worker with robust error handling\n * => SecureConfirmMessageType.PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD\n * and proper data validation. Supports both transaction and registration confirmation flows.\n */\nexport async function handlePromptUserConfirmInJsMainThread(\n ctx: VrfWorkerManagerContext,\n message: {\n type: SecureConfirmMessageType.PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD,\n data: SecureConfirmRequest,\n },\n worker: Worker\n): Promise<void> {\n\n // 1. Validate and parse request\n let request: SecureConfirmRequest;\n let confirmationConfig: ConfirmationConfig;\n let transactionSummary: TransactionSummary;\n\n try {\n\n request = validateSecureConfirmRequest(message.data);\n assertNoForbiddenMainThreadSigningSecrets(request);\n confirmationConfig = determineConfirmationConfig(ctx, request);\n\n const parsedSummary = parseTransactionSummary(request.summary);\n const intentDigest = getIntentDigest(request);\n\n transactionSummary = sanitizeForPostMessage({\n ...parsedSummary,\n ...(intentDigest ? { intentDigest } : {}),\n }) as TransactionSummary;\n\n } catch (e: unknown) {\n\n console.error('[SecureConfirm][Host] validateAndParseRequest failed', e);\n // Attempt to send a structured error back to the worker to avoid hard failure\n try {\n const rid = (message?.data as any)?.requestId;\n if (typeof rid === 'string' && rid) {\n sendConfirmResponse(worker, {\n requestId: rid,\n confirmed: false,\n error: errorMessage(e) || 'Invalid secure confirm request',\n });\n return;\n }\n } catch (_err: unknown) {\n throw toError(e);\n }\n throw toError(e);\n }\n\n const handler = HANDLERS[request.type];\n if (!handler) {\n // Unsupported type fallback: return structured error to worker.\n sendConfirmResponse(worker, {\n requestId: request.requestId,\n confirmed: false,\n error: 'Unsupported secure confirmation type'\n });\n return;\n }\n\n await handler({ ctx, request, worker, confirmationConfig, transactionSummary });\n}\n\ntype HandlerArgs = {\n ctx: VrfWorkerManagerContext;\n request: SecureConfirmRequest;\n worker: Worker;\n confirmationConfig: ConfirmationConfig;\n transactionSummary: TransactionSummary;\n};\n\ntype Handler = (args: HandlerArgs) => Promise<void>;\n\nasync function importFlow<T>(label: string, loader: () => Promise<T>): Promise<T> {\n try {\n return await loader();\n } catch (e) {\n console.error(`[SecureConfirm][Host] failed to import ${label} flow module`, e);\n throw e;\n }\n}\n\nconst HANDLERS: Partial<Record<SecureConfirmationType, Handler>> = {\n [SecureConfirmationType.DECRYPT_PRIVATE_KEY_WITH_PRF]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleLocalOnlyFlow } = await importFlow('localOnly', () => import('./flows/localOnly'));\n await handleLocalOnlyFlow(ctx, request as LocalOnlySecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.SHOW_SECURE_PRIVATE_KEY_UI]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleLocalOnlyFlow } = await importFlow('localOnly', () => import('./flows/localOnly'));\n await handleLocalOnlyFlow(ctx, request as LocalOnlySecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.REGISTER_ACCOUNT]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleRegistrationFlow } = await importFlow('registration', () => import('./flows/registration'));\n await handleRegistrationFlow(ctx, request as RegistrationSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.LINK_DEVICE]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleRegistrationFlow } = await importFlow('registration', () => import('./flows/registration'));\n await handleRegistrationFlow(ctx, request as RegistrationSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.SIGN_TRANSACTION]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleTransactionSigningFlow } = await importFlow('transactions', () => import('./flows/transactions'));\n await handleTransactionSigningFlow(ctx, request as SigningSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.SIGN_NEP413_MESSAGE]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleTransactionSigningFlow } = await importFlow('transactions', () => import('./flows/transactions'));\n await handleTransactionSigningFlow(ctx, request as SigningSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n};\n","import {\n SecureConfirmMessageType,\n SecureConfirmRequest,\n SecureConfirmDecision,\n} from './confirmTxFlow/types';\nimport { handlePromptUserConfirmInJsMainThread } from './confirmTxFlow';\nimport type { VrfWorkerManagerContext } from '.';\n\n/**\n * VRF-side helper to run confirmTxFlow directly from JS without going through a worker.\n * Useful while VRF-driven flows migrate off the signer worker.\n *\n * Returns the USER_PASSKEY_CONFIRM_RESPONSE data once the flow completes.\n */\nexport async function runSecureConfirm(\n ctx: VrfWorkerManagerContext,\n request: SecureConfirmRequest\n): Promise<SecureConfirmDecision> {\n return new Promise<SecureConfirmDecision>((resolve, reject) => {\n // Minimal Worker-like object to capture the response\n const worker = {\n postMessage: (msg: any) => {\n if (msg?.type === SecureConfirmMessageType.USER_PASSKEY_CONFIRM_RESPONSE) {\n resolve(msg.data as SecureConfirmDecision);\n }\n }\n } as unknown as Worker;\n\n handlePromptUserConfirmInJsMainThread(\n ctx,\n { type: SecureConfirmMessageType.PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD, data: request },\n worker\n ).catch(reject);\n });\n}\n","import { isObject } from '@/utils/validation';\nimport { AccountId, toAccountId } from '../../../types/accountIds';\nimport {\n WorkerRequestType,\n isDecryptPrivateKeyWithPrfSuccess,\n} from '../../../types/signer-worker';\nimport { runSecureConfirm } from '../../VrfWorkerManager/secureConfirmBridge';\nimport { SecureConfirmationType } from '../../VrfWorkerManager/confirmTxFlow/types';\nimport { SignerWorkerManagerContext } from '..';\nimport { getLastLoggedInDeviceNumber } from '../getDeviceNumber';\n\n/**\n * Two-phase export (worker-driven):\n * - Phase 1: collect PRF (uiMode: 'skip') and derive WrapKeySeed in VRF worker\n * - Decrypt inside signer worker (session-bound)\n * - Phase 2: show export UI with decrypted key (kept open until user closes)\n */\nexport async function exportNearKeypairUi({\n ctx,\n nearAccountId,\n variant,\n theme,\n sessionId,\n}: {\n ctx: SignerWorkerManagerContext;\n nearAccountId: AccountId;\n variant?: 'drawer' | 'modal';\n theme?: 'dark' | 'light';\n sessionId: string;\n}): Promise<void> {\n const accountId = toAccountId(nearAccountId);\n\n // Gather encrypted key + ChaCha20 nonce and public key from IndexedDB\n const deviceNumber = await getLastLoggedInDeviceNumber(accountId, ctx.indexedDB.clientDB);\n const [keyData, user] = await Promise.all([\n ctx.indexedDB.nearKeysDB.getLocalKeyMaterial(accountId, deviceNumber),\n ctx.indexedDB.clientDB.getUserByDevice(accountId, deviceNumber),\n ]);\n const publicKey = user?.clientNearPublicKey || '';\n if (!keyData || !publicKey) {\n throw new Error('Missing local key material for export. Re-register to upgrade vault.');\n }\n\n // Decrypt inside signer worker using the reserved session\n const response = await ctx.sendMessage<WorkerRequestType.DecryptPrivateKeyWithPrf>({\n sessionId,\n message: {\n type: WorkerRequestType.DecryptPrivateKeyWithPrf,\n payload: {\n nearAccountId: accountId,\n encryptedPrivateKeyData: keyData.encryptedSk,\n encryptedPrivateKeyChacha20NonceB64u: keyData.chacha20NonceB64u,\n },\n },\n });\n\n if (!isDecryptPrivateKeyWithPrfSuccess(response)) {\n console.error('WebAuthnManager: Export decrypt failed:', response);\n const payloadError = isObject(response?.payload) && response?.payload?.error;\n const msg = String(payloadError || 'Export decrypt failed');\n throw new Error(msg);\n }\n\n const privateKey = response.payload.privateKey;\n\n // Phase 2: show secure UI (VRF-driven viewer)\n const showReq = {\n requestId: sessionId,\n type: SecureConfirmationType.SHOW_SECURE_PRIVATE_KEY_UI,\n summary: {\n operation: 'Export Private Key' as const,\n accountId,\n publicKey,\n warning: 'Anyone with your private key can fully control your account. Never share it.',\n },\n payload: {\n nearAccountId: accountId,\n publicKey,\n privateKey,\n variant,\n theme,\n },\n };\n await runSecureConfirm(ctx, showReq);\n}\n","import type { SignerWorkerManagerContext } from '..';\nimport {\n WorkerRequestType,\n WorkerResponseType,\n type WasmDeriveThresholdEd25519ClientVerifyingShareResult,\n} from '../../../types/signer-worker';\n\nexport async function deriveThresholdEd25519ClientVerifyingShare(args: {\n ctx: SignerWorkerManagerContext;\n sessionId: string;\n nearAccountId: string;\n}): Promise<{\n success: boolean;\n nearAccountId: string;\n clientVerifyingShareB64u: string;\n wrapKeySalt: string;\n error?: string;\n}> {\n const { ctx } = args;\n const sessionId = args.sessionId;\n const nearAccountId = args.nearAccountId;\n\n try {\n if (!sessionId) throw new Error('Missing sessionId');\n if (!nearAccountId) throw new Error('Missing nearAccountId');\n\n const response = await ctx.sendMessage<WorkerRequestType.DeriveThresholdEd25519ClientVerifyingShare>({\n sessionId,\n message: {\n type: WorkerRequestType.DeriveThresholdEd25519ClientVerifyingShare,\n payload: { nearAccountId },\n },\n });\n\n if (response.type !== WorkerResponseType.DeriveThresholdEd25519ClientVerifyingShareSuccess) {\n throw new Error('DeriveThresholdEd25519ClientVerifyingShare failed');\n }\n\n const wasmResult = response.payload as WasmDeriveThresholdEd25519ClientVerifyingShareResult;\n const clientVerifyingShareB64u = wasmResult?.clientVerifyingShareB64u;\n const wrapKeySalt = wasmResult?.wrapKeySalt;\n\n if (!clientVerifyingShareB64u) throw new Error('Missing clientVerifyingShareB64u in worker response');\n if (!wrapKeySalt) throw new Error('Missing wrapKeySalt in worker response');\n\n return {\n success: true,\n nearAccountId,\n clientVerifyingShareB64u,\n wrapKeySalt\n };\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return {\n success: false,\n nearAccountId,\n clientVerifyingShareB64u: '',\n wrapKeySalt: '',\n error: message\n };\n }\n}\n","import { SIGNER_WORKER_MANAGER_CONFIG } from \"../../../config\";\nimport { ClientAuthenticatorData, UnifiedIndexedDBManager } from '../../IndexedDBManager';\nimport { IndexedDBManager } from '../../IndexedDBManager';\nimport { SignedTransaction, type NearClient } from '../../NearClient';\nimport { isObject } from '@/utils/validation';\nimport { resolveWorkerUrl } from '../../sdkPaths';\nimport {\n WorkerRequestType,\n WorkerResponseForRequest,\n isWorkerProgress,\n isWorkerError,\n isWorkerSuccess,\n WorkerProgressResponse,\n WorkerErrorResponse,\n WorkerRequestTypeMap,\n} from '../../types/signer-worker';\nimport { VrfWorkerManager } from '../VrfWorkerManager';\nimport { VRFChallenge } from '../../types/vrf-worker';\nimport type { ActionArgsWasm, TransactionInputWasm } from '../../types/actions';\nimport type { DelegateActionInput } from '../../types/delegate';\nimport type { onProgressEvents, RegistrationEventStep3 } from '../../types/sdkSentEvents';\nimport type { AuthenticatorOptions } from '../../types/authenticatorOptions';\nimport { AccountId } from \"../../types/accountIds\";\nimport { TransactionContext } from '../../types/rpc';\nimport {\n ConfirmationConfig,\n type SignerMode,\n WasmSignedDelegate,\n} from '../../types/signer-worker';\nimport type { ThresholdBehavior } from '../../types/signer-worker';\nimport { TouchIdPrompt } from \"../touchIdPrompt\";\nimport { isSignerWorkerControlMessage } from './sessionMessages';\nimport { WorkerControlMessage } from '../../workerControlMessages';\n\nimport {\n decryptPrivateKeyWithPrf,\n checkCanRegisterUser,\n signTransactionsWithActions,\n recoverKeypairFromPasskey,\n extractCosePublicKey,\n signTransactionWithKeyPair,\n signNep413Message,\n deriveNearKeypairAndEncryptFromSerialized,\n signDelegateAction,\n registerDevice2WithDerivedKey,\n exportNearKeypairUi,\n deriveThresholdEd25519ClientVerifyingShare,\n} from './handlers';\nimport { RpcCallPayload } from '../../types/signer-worker';\nimport { UserPreferencesManager } from '../userPreferences';\nimport { NonceManager } from '../../nonceManager';\nimport { WebAuthnAuthenticationCredential, WebAuthnRegistrationCredential } from '../../types';\nimport { toError } from '@/utils/errors';\nimport { withSessionId } from './handlers/session';\nimport { attachSessionPort } from './sessionHandshake.js';\n\ntype WithOptionalSessionId<T> = T extends { sessionId: string }\n ? Omit<T, 'sessionId'> & { sessionId?: string }\n : T;\n\ntype SigningSessionEntry = {\n worker: Worker;\n wrapKeySeedPort?: MessagePort;\n createdAt: number;\n};\n\nexport interface SignerWorkerManagerContext {\n touchIdPrompt: TouchIdPrompt;\n nearClient: NearClient;\n indexedDB: UnifiedIndexedDBManager;\n userPreferencesManager: UserPreferencesManager;\n nonceManager: NonceManager;\n relayerUrl: string;\n rpIdOverride?: string;\n nearExplorerUrl?: string;\n vrfWorkerManager?: VrfWorkerManager;\n sendMessage: <T extends keyof WorkerRequestTypeMap>(args: {\n message: {\n type: T;\n payload: WithOptionalSessionId<WorkerRequestTypeMap[T]['request']>;\n };\n onEvent?: (update: onProgressEvents) => void;\n timeoutMs?: number;\n sessionId?: string;\n }) => Promise<WorkerResponseForRequest<T>>;\n};\n\n/**\n * WebAuthnWorkers handles PRF, workers, and COSE operations\n *\n * Note: Challenge store removed as VRF provides cryptographic freshness\n * without needing centralized challenge management\n */\nexport class SignerWorkerManager {\n\n private indexedDB: UnifiedIndexedDBManager;\n private touchIdPrompt: TouchIdPrompt;\n private vrfWorkerManager: VrfWorkerManager;\n private nearClient: NearClient;\n private userPreferencesManager: UserPreferencesManager;\n private nonceManager: NonceManager;\n private relayerUrl: string;\n private workerBaseOrigin: string | undefined;\n private nearExplorerUrl?: string;\n\n constructor(\n vrfWorkerManager: VrfWorkerManager,\n nearClient: NearClient,\n userPreferencesManager: UserPreferencesManager,\n nonceManager: NonceManager,\n relayerUrl: string,\n rpIdOverride?: string,\n enableSafariGetWebauthnRegistrationFallback: boolean = true,\n nearExplorerUrl?: string,\n ) {\n this.indexedDB = IndexedDBManager;\n this.touchIdPrompt = new TouchIdPrompt(rpIdOverride, enableSafariGetWebauthnRegistrationFallback);\n this.vrfWorkerManager = vrfWorkerManager;\n this.nearClient = nearClient;\n this.userPreferencesManager = userPreferencesManager;\n this.nonceManager = nonceManager;\n this.relayerUrl = relayerUrl;\n this.nearExplorerUrl = nearExplorerUrl;\n }\n\n setWorkerBaseOrigin(origin: string | undefined): void {\n this.workerBaseOrigin = origin;\n }\n\n getContext(): SignerWorkerManagerContext {\n return {\n sendMessage: this.sendMessage.bind(this), // bind to access this.createSecureWorker\n indexedDB: this.indexedDB,\n touchIdPrompt: this.touchIdPrompt,\n vrfWorkerManager: this.vrfWorkerManager,\n nearClient: this.nearClient,\n userPreferencesManager: this.userPreferencesManager,\n nonceManager: this.nonceManager,\n rpIdOverride: this.touchIdPrompt.getRpId(),\n nearExplorerUrl: this.nearExplorerUrl,\n relayerUrl: this.relayerUrl,\n };\n }\n\n createSecureWorker(): Worker {\n const workerUrlStr = resolveWorkerUrl(\n SIGNER_WORKER_MANAGER_CONFIG.WORKER.URL,\n { worker: 'signer', baseOrigin: this.workerBaseOrigin }\n )\n try {\n const worker = new Worker(workerUrlStr, {\n type: SIGNER_WORKER_MANAGER_CONFIG.WORKER.TYPE,\n name: SIGNER_WORKER_MANAGER_CONFIG.WORKER.NAME\n });\n // minimal error handler in tests; avoid noisy logs\n worker.onerror = () => {};\n return worker;\n } catch (error) {\n // Do not silently downgrade to same‑origin. Cross‑origin workers must be\n // resolvable under the configured wallet origin with proper headers.\n // Surface a precise error so tests assert the real path.\n const msg = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to create secure worker: ${msg}`);\n }\n }\n\n /**\n * Executes a worker operation by sending a message to the secure worker.\n * Handles progress updates via onEvent callback, supports both single and multiple response patterns.\n * Intercepts secure confirmation handshake messages for pluggable UI.\n * Resolves with the final worker response or rejects on error/timeout.\n *\n * @template T - Worker request type.\n * @param params.message - The message to send to the worker.\n * @param params.onEvent - Optional callback for progress events.\n * @param params.timeoutMs - Optional timeout in milliseconds.\n * @returns Promise resolving to the worker response for the request.\n */\n private workerPool: Worker[] = [];\n private readonly MAX_WORKER_POOL_SIZE = 3; // Increased for security model\n // Map of active signing sessions to reserved workers and optional WrapKeySeed ports\n private signingSessions: Map<string, SigningSessionEntry> = new Map();\n private readonly SIGNING_SESSION_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\n\n private getWorkerFromPool(): Worker {\n if (this.workerPool.length > 0) {\n return this.workerPool.pop()!;\n }\n return this.createSecureWorker();\n }\n\n private terminateAndReplaceWorker(worker: Worker): void {\n // Always terminate workers to clear memory\n worker.terminate();\n // Asynchronously create a replacement worker for the pool\n this.createReplacementWorker();\n }\n\n /**\n * Reserve a signer worker \"session\"\n *\n * What this does:\n * - Reserves a specific `Worker` instance from the pool and pins it to `sessionId`.\n * - Ensures the signer worker has a dedicated `MessagePort` attached for receiving `WrapKeySeed`\n * from the VRF worker (VRF → Signer channel).\n *\n * Port wiring:\n * - The VRF worker retains one end of a `MessageChannel` and the signer worker receives the other.\n * - This method attaches the signer-facing port via a control message (`ATTACH_WRAP_KEY_SEED_PORT`)\n * and waits for an ACK (`ATTACH_WRAP_KEY_SEED_PORT_OK`) before exposing the session.\n *\n * @param sessionId - Session identifier used to correlate MessagePorts + ready signals.\n * @param opts.signerPort - Optional signer-facing `MessagePort` created/owned by the caller (VRF-created channel).\n * If omitted, this method creates a fresh `MessageChannel` and returns `vrfPort` so the\n * caller can transfer it to the VRF worker.\n * @returns `{ worker, signerPort, vrfPort }` where `vrfPort` is only present when we created the channel here.\n */\n async reserveSignerWorkerSession(sessionId: string, opts?: { signerPort?: MessagePort }): Promise<{ worker: Worker; signerPort?: MessagePort; vrfPort?: MessagePort }> {\n if (this.signingSessions.has(sessionId)) {\n throw new Error(`Signing session already exists for id: ${sessionId}`);\n }\n // Reserve a worker from the pool for this sessionId.\n const worker = this.getWorkerFromPool();\n let signerPort = opts?.signerPort;\n let vrfPort: MessagePort | undefined;\n if (!signerPort) {\n // If caller did not provide a signer-facing port, create a channel.\n // - port1 => signer worker (receiver)\n // - port2 => VRF worker (sender) returned to caller\n const channel = new MessageChannel();\n signerPort = channel.port1;\n vrfPort = channel.port2;\n }\n\n // Attach the signerPort to the worker and wait for ACK before adding to signingSessions\n try {\n if (!signerPort) {\n throw new Error('Missing signerPort for signing session');\n }\n\n // Use centralized handshake logic (registers listener, sends message, waits for ACK)\n await attachSessionPort(worker, sessionId, signerPort);\n\n // Only add to signingSessions after successful attachment\n // (prevents callers from observing a session that can't receive WrapKeySeed yet).\n this.signingSessions.set(sessionId, {\n worker,\n wrapKeySeedPort: signerPort,\n createdAt: Date.now(),\n });\n\n } catch (err) {\n console.error('[SignerWorkerManager]: Failed to attach WrapKeySeed port to signer worker', err);\n // Best-effort cleanup\n try { signerPort?.close(); } catch {}\n try { vrfPort?.close(); } catch {}\n this.terminateAndReplaceWorker(worker);\n this.signingSessions.delete(sessionId);\n throw err;\n }\n return { worker, signerPort, vrfPort };\n }\n\n /**\n * Release a signing session: close ports and terminate/replace the worker to zeroize state.\n */\n releaseSigningSession(sessionId: string): void {\n const entry = this.signingSessions.get(sessionId);\n if (!entry) return;\n try { entry.wrapKeySeedPort?.close() } catch {}\n try { this.terminateAndReplaceWorker(entry.worker) } catch {}\n this.signingSessions.delete(sessionId);\n }\n\n /**\n * Sweep expired signing sessions based on createdAt and timeout.\n */\n sweepExpiredSigningSessions(): void {\n const now = Date.now();\n for (const [sessionId, entry] of this.signingSessions.entries()) {\n if (now - entry.createdAt > this.SIGNING_SESSION_TIMEOUT_MS) {\n this.releaseSigningSession(sessionId);\n }\n }\n }\n\n private async createReplacementWorker(): Promise<void> {\n try {\n const worker = this.createSecureWorker();\n\n // Simple health check\n const healthPromise = new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => reject(new Error('Health check timeout')), 5000);\n\n const onMessage = (event: MessageEvent) => {\n if (event.data?.type === WorkerControlMessage.WORKER_READY || event.data?.ready) {\n worker.removeEventListener('message', onMessage);\n clearTimeout(timeout);\n resolve();\n }\n };\n\n worker.addEventListener('message', onMessage);\n worker.onerror = () => {\n worker.removeEventListener('message', onMessage);\n clearTimeout(timeout);\n reject(new Error('Worker error during health check'));\n };\n });\n\n await healthPromise;\n\n if (this.workerPool.length < this.MAX_WORKER_POOL_SIZE) {\n this.workerPool.push(worker);\n } else {\n worker.terminate();\n }\n } catch (error: unknown) {\n console.warn('SignerWorkerManager: Failed to create replacement worker:', error);\n }\n }\n\n /**\n * Pre-warm worker pool by creating and initializing workers in advance\n * This reduces latency for the first transaction by having workers ready\n */\n async preWarmWorkerPool(): Promise<void> {\n const promises: Promise<void>[] = [];\n\n for (let i = 0; i < this.MAX_WORKER_POOL_SIZE; i++) {\n promises.push(\n new Promise<void>((resolve, reject) => {\n try {\n const worker = this.createSecureWorker();\n\n // Set up one-time ready handler\n const onReady = (event: MessageEvent) => {\n if (event.data?.type === WorkerControlMessage.WORKER_READY || event.data?.ready) {\n worker.removeEventListener('message', onReady);\n this.terminateAndReplaceWorker(worker);\n resolve();\n }\n };\n\n worker.addEventListener('message', onReady);\n\n // Set up error handler\n worker.onerror = (error) => {\n worker.removeEventListener('message', onReady);\n console.error(`WebAuthnManager: Worker ${i + 1} pre-warm failed:`, error);\n reject(error);\n };\n\n // Timeout after 5 seconds\n setTimeout(() => {\n worker.removeEventListener('message', onReady);\n // Pre-warm timeouts are benign; workers will be created on-demand later.\n // console.debug(`WebAuthnManager: Worker ${i + 1} pre-warm timeout`);\n reject(new Error('Pre-warm timeout'));\n }, 5000);\n\n } catch (error: unknown) {\n console.error(`WebAuthnManager: Failed to create worker ${i + 1}:`, error);\n reject(toError(error));\n }\n })\n );\n }\n\n try {\n await Promise.allSettled(promises);\n } catch (error: unknown) {\n console.warn('WebAuthnManager: Some workers failed to pre-warm:', error);\n }\n }\n\n private async sendMessage<T extends keyof WorkerRequestTypeMap>({\n sessionId,\n message,\n onEvent,\n timeoutMs = SIGNER_WORKER_MANAGER_CONFIG.TIMEOUTS.DEFAULT, // 60s\n }: {\n sessionId?: string;\n message: { type: T; payload: WithOptionalSessionId<WorkerRequestTypeMap[T]['request']> };\n onEvent?: (update: onProgressEvents) => void;\n timeoutMs?: number;\n }): Promise<WorkerResponseForRequest<T>> {\n\n // Clean up any expired signing sessions before allocating a worker\n this.sweepExpiredSigningSessions();\n\n const payloadSessionId = (message.payload as any)?.sessionId as string | undefined;\n if (sessionId && payloadSessionId && payloadSessionId !== sessionId) {\n throw new Error(\n `sendMessage: payload.sessionId (${payloadSessionId}) does not match provided sessionId (${sessionId})`\n );\n }\n\n const effectiveSessionId = sessionId || payloadSessionId;\n const sessionEntry = effectiveSessionId ? this.signingSessions.get(effectiveSessionId) : undefined;\n if (effectiveSessionId && !sessionEntry) {\n throw new Error(`Signing session not found for id: ${effectiveSessionId}`);\n }\n\n // Normalize/inject sessionId into payload once to avoid duplication at call sites.\n const finalPayload = effectiveSessionId\n ? withSessionId(effectiveSessionId, message.payload)\n : (message.payload);\n\n const worker = sessionEntry ? sessionEntry.worker : this.getWorkerFromPool();\n const isSessionWorker = !!sessionEntry;\n\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n try {\n if (isSessionWorker && effectiveSessionId) {\n // Release reserved session to avoid leaking worker/port\n this.releaseSigningSession(effectiveSessionId);\n } else {\n this.terminateAndReplaceWorker(worker);\n }\n } catch {}\n // Notify any open modal host to transition to error state\n try {\n const seconds = Math.round(timeoutMs / 1000);\n window.postMessage({ type: 'MODAL_TIMEOUT', payload: `Timed out after ${seconds}s, try again` }, '*');\n } catch {}\n reject(new Error(`Worker operation timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n\n const responses: WorkerResponseForRequest<T>[] = [];\n\n worker.onmessage = async (event) => {\n try {\n // Ignore control messages (lifecycle/session setup) – they are handled elsewhere.\n if (isSignerWorkerControlMessage(event?.data)) {\n return;\n }\n // Ignore readiness pings that can arrive if a worker was just spawned\n if (event?.data?.type === WorkerControlMessage.WORKER_READY || event?.data?.ready) {\n return; // not a response to an operation\n }\n // Use strong typing from WASM-generated types\n const response = event.data as WorkerResponseForRequest<T>;\n responses.push(response);\n\n // Handle progress updates using WASM-generated numeric enum values\n if (isWorkerProgress(response)) {\n const progressResponse = response as WorkerProgressResponse;\n onEvent?.(progressResponse.payload as onProgressEvents);\n return; // Continue listening for more messages\n }\n\n // Handle errors using WASM-generated enum\n if (isWorkerError(response)) {\n clearTimeout(timeoutId);\n if (!isSessionWorker) this.terminateAndReplaceWorker(worker);\n const errorResponse = response as WorkerErrorResponse;\n console.error('Worker error response:', errorResponse);\n reject(new Error(errorResponse.payload.error));\n return;\n }\n\n // Handle successful completion types using strong typing\n if (isWorkerSuccess(response)) {\n clearTimeout(timeoutId);\n if (!isSessionWorker) this.terminateAndReplaceWorker(worker);\n resolve(response as WorkerResponseForRequest<T>);\n return;\n }\n\n // If we reach here, the response doesn't match any expected type\n console.error('Unexpected worker response format:', {\n response,\n });\n\n // Check if it's a generic Error object\n if (isObject(response) && 'message' in response && 'stack' in response) {\n clearTimeout(timeoutId);\n if (!isSessionWorker) this.terminateAndReplaceWorker(worker);\n console.error('Worker sent generic Error object:', response);\n reject(new Error(`Worker sent generic error: ${(response as Error).message}`));\n return;\n }\n\n // Unknown response format\n clearTimeout(timeoutId);\n if (!isSessionWorker) this.terminateAndReplaceWorker(worker);\n reject(new Error(`Unknown worker response format: ${JSON.stringify(response)}`));\n } catch (error: unknown) {\n clearTimeout(timeoutId);\n if (!isSessionWorker) this.terminateAndReplaceWorker(worker);\n console.error('Error processing worker message:', error);\n const err = toError(error);\n reject(new Error(`Worker message processing error: ${err.message}`));\n }\n };\n\n worker.onerror = (event) => {\n clearTimeout(timeoutId);\n if (!isSessionWorker) this.terminateAndReplaceWorker(worker);\n const errorMessage = event.error?.message || event.message || 'Unknown worker error';\n console.error('Worker error details (progress):', {\n message: errorMessage,\n filename: event.filename,\n lineno: event.lineno,\n colno: event.colno,\n error: event.error\n });\n reject(new Error(`Worker error: ${errorMessage}`));\n };\n\n // Format message for Rust SignerWorkerMessage structure using WASM types\n const formattedMessage = {\n type: message.type, // Numeric enum value from WorkerRequestType\n payload: finalPayload,\n };\n\n worker.postMessage(formattedMessage);\n });\n }\n\n /**\n * Derive NEAR keypair from a serialized WebAuthn registration credential\n */\n async deriveNearKeypairAndEncryptFromSerialized(args: {\n credential: WebAuthnRegistrationCredential;\n nearAccountId: AccountId;\n options?: {\n authenticatorOptions?: AuthenticatorOptions;\n deviceNumber?: number;\n };\n sessionId: string;\n }): Promise<{\n success: boolean;\n nearAccountId: AccountId;\n publicKey: string;\n /**\n * Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for the encrypted private key.\n */\n chacha20NonceB64u?: string;\n wrapKeySalt?: string;\n }> {\n return deriveNearKeypairAndEncryptFromSerialized({ ctx: this.getContext(), ...args });\n }\n\n async deriveThresholdEd25519ClientVerifyingShare(args: {\n sessionId: string;\n nearAccountId: AccountId;\n }): Promise<{\n success: boolean;\n nearAccountId: string;\n clientVerifyingShareB64u: string;\n wrapKeySalt: string;\n error?: string;\n }> {\n return deriveThresholdEd25519ClientVerifyingShare({\n ctx: this.getContext(),\n sessionId: args.sessionId,\n nearAccountId: String(args.nearAccountId),\n });\n }\n\n /**\n * Secure private key decryption with dual PRF\n */\n async decryptPrivateKeyWithPrf(args: {\n nearAccountId: AccountId,\n authenticators: ClientAuthenticatorData[],\n sessionId: string,\n }): Promise<{\n decryptedPrivateKey: string;\n nearAccountId: AccountId\n }> {\n return decryptPrivateKeyWithPrf({ ctx: this.getContext(), ...args });\n }\n\n async checkCanRegisterUser(args: {\n vrfChallenge: VRFChallenge,\n credential: WebAuthnRegistrationCredential,\n contractId: string;\n nearRpcUrl: string;\n authenticatorOptions?: AuthenticatorOptions; // Authenticator options for registration check\n onEvent?: (update: RegistrationEventStep3) => void;\n }): Promise<{\n success: boolean;\n verified?: boolean;\n registrationInfo?: unknown;\n logs?: string[];\n signedTransactionBorsh?: number[];\n error?: string;\n }> {\n return checkCanRegisterUser({ ctx: this.getContext(), ...args });\n }\n\n /**\n * Combined Device2 registration: derive NEAR keypair + sign registration transaction\n * in a single operation without requiring a separate authentication prompt.\n *\n * This replaces the old two-step flow (register → authenticate → sign).\n * PRF.second and WrapKeySeed are already in the signer worker via MessagePort.\n */\n async registerDevice2WithDerivedKey(args: {\n sessionId: string;\n nearAccountId: AccountId;\n credential: WebAuthnRegistrationCredential;\n vrfChallenge: VRFChallenge;\n transactionContext: TransactionContext;\n contractId: string;\n wrapKeySalt: string;\n deviceNumber?: number;\n deterministicVrfPublicKey: string;\n }): Promise<{\n success: boolean;\n publicKey: string;\n signedTransaction: any;\n wrapKeySalt: string;\n encryptedData?: string;\n /**\n * Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for the encrypted private key.\n */\n chacha20NonceB64u?: string;\n error?: string;\n }> {\n return registerDevice2WithDerivedKey({ ctx: this.getContext(), ...args });\n }\n\n // === ACTION-BASED SIGNING METHODS ===\n\n /**\n * Sign multiple transactions with shared VRF challenge and credential\n * Efficiently processes multiple transactions with one PRF authentication\n */\n async signTransactionsWithActions(args: {\n transactions: TransactionInputWasm[],\n rpcCall: RpcCallPayload,\n signerMode: SignerMode,\n onEvent?: (update: onProgressEvents) => void,\n confirmationConfigOverride?: Partial<ConfirmationConfig>,\n title?: string;\n body?: string;\n sessionId: string,\n }): Promise<Array<{\n signedTransaction: SignedTransaction;\n nearAccountId: AccountId;\n logs?: string[]\n }>> {\n return signTransactionsWithActions({\n ctx: this.getContext(),\n ...args\n });\n }\n\n async signDelegateAction(args: {\n delegate: DelegateActionInput;\n rpcCall: RpcCallPayload;\n signerMode: SignerMode;\n onEvent?: (update: onProgressEvents) => void;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n title?: string;\n body?: string;\n sessionId: string;\n }): Promise<{\n signedDelegate: WasmSignedDelegate;\n hash: string;\n nearAccountId: AccountId;\n logs?: string[];\n }> {\n return signDelegateAction({ ctx: this.getContext(), ...args });\n }\n\n /**\n * Recover keypair from authentication credential for account recovery\n * Uses dual PRF-based Ed25519 key derivation with account-specific HKDF and AES encryption\n */\n async recoverKeypairFromPasskey(args: {\n credential: WebAuthnAuthenticationCredential;\n accountIdHint?: string;\n sessionId: string,\n }): Promise<{\n publicKey: string;\n encryptedPrivateKey: string;\n /** Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for encrypted key */\n chacha20NonceB64u: string;\n accountIdHint?: string;\n wrapKeySalt: string;\n }> {\n return recoverKeypairFromPasskey({ ctx: this.getContext(), ...args });\n }\n\n /**\n * Extract COSE public key from WebAuthn attestation object\n * Simple operation that doesn't require TouchID or progress updates\n */\n async extractCosePublicKey(attestationObjectBase64url: string): Promise<Uint8Array> {\n return extractCosePublicKey({ ctx: this.getContext(), attestationObjectBase64url });\n }\n\n /**\n * Sign transaction with raw private key (for key replacement in Option D device linking)\n * No TouchID/PRF required - uses provided private key directly\n */\n async signTransactionWithKeyPair(args: {\n nearPrivateKey: string;\n signerAccountId: string;\n receiverId: string;\n nonce: string;\n blockHash: string;\n actions: ActionArgsWasm[];\n }): Promise<{\n signedTransaction: SignedTransaction;\n logs?: string[];\n }> {\n return signTransactionWithKeyPair({ ctx: this.getContext(), ...args });\n }\n\n /**\n * Sign a NEP-413 message using the user's passkey-derived private key\n *\n * @param payload - NEP-413 signing parameters including message, recipient, nonce, and state\n * @returns Promise resolving to signing result with account ID, public key, and signature\n */\n async signNep413Message(payload: {\n message: string;\n recipient: string;\n nonce: string;\n state: string | null;\n accountId: string;\n signerMode: SignerMode;\n title?: string;\n body?: string;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n sessionId: string;\n contractId?: string;\n nearRpcUrl?: string;\n }): Promise<{\n success: boolean;\n accountId: string;\n publicKey: string;\n signature: string;\n state?: string;\n error?: string;\n }> {\n return signNep413Message({\n ctx: this.getContext(),\n payload\n });\n }\n\n /**\n * Two-phase export (worker-driven):\n * - Phase 1: collect PRF (uiMode: 'skip')\n * - Decrypt inside worker\n * - Phase 2: show export UI with decrypted key (kept open until user closes)\n */\n async exportNearKeypairUi(args: {\n nearAccountId: AccountId,\n variant?: 'drawer'|'modal',\n theme?: 'dark'|'light',\n sessionId: string,\n }): Promise<void> {\n return exportNearKeypairUi({ ctx: this.getContext(), ...args });\n }\n\n}\n","import type { VRFWorkerMessage, VRFWorkerStatus, WasmVrfWorkerRequestType } from '../../../types/vrf-worker';\nimport { toAccountId } from '../../../types/accountIds';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * \"Global\" VRF status: is the VRF keypair currently unlocked/active inside the VRF worker?\n *\n * This is NOT the same as a signing session status (WrapKeySeed session gating).\n * For per-`sessionId` signing-session status, use `checkSessionStatus`.\n */\nexport async function checkVrfStatus(ctx: VrfWorkerManagerHandlerContext): Promise<VRFWorkerStatus> {\n try {\n await ctx.ensureWorkerReady();\n } catch {\n // If initialization fails, return inactive status\n return { active: false, nearAccountId: null, vrfPublicKey: null };\n }\n\n try {\n const message: VRFWorkerMessage<WasmVrfWorkerRequestType> = {\n type: 'CHECK_VRF_STATUS',\n id: ctx.generateMessageId(),\n payload: {} as WasmVrfWorkerRequestType\n };\n\n const response = await ctx.sendMessage(message);\n\n if (response.success && response.data) {\n const data = response.data as { active: boolean; sessionDuration?: number; vrfPublicKey?: string };\n const current = ctx.getCurrentVrfAccountId();\n return {\n active: data.active,\n nearAccountId: current ? toAccountId(current) : null,\n sessionDuration: data.sessionDuration,\n vrfPublicKey: data.vrfPublicKey ?? null,\n };\n }\n\n return { active: false, nearAccountId: null, vrfPublicKey: null };\n } catch (error) {\n console.warn('VRF Manager: Failed to get VRF status:', error);\n return { active: false, nearAccountId: null, vrfPublicKey: null };\n }\n}\n","import type { VRFWorkerMessage, WasmClearSessionRequest } from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Best-effort cleanup for a single VRF-owned signing session.\n *\n * Clears any VRF worker state bound to `sessionId`:\n * - cached WrapKeySeed session material (TTL/uses),\n * - cached VRF challenge (used for contract verification),\n * - and any attached WrapKeySeed MessagePort.\n *\n * Used by UI \"Lock\" actions and as a safety valve for session lifecycle cleanup.\n */\nexport async function clearSession(\n ctx: VrfWorkerManagerHandlerContext,\n args: { sessionId: string }\n): Promise<{\n sessionId: string;\n clearedSession: boolean;\n clearedChallenge: boolean;\n clearedPort: boolean;\n}> {\n await ctx.ensureWorkerReady(true);\n const message: VRFWorkerMessage<WasmClearSessionRequest> = {\n type: 'CLEAR_SESSION',\n id: ctx.generateMessageId(),\n payload: {\n sessionId: args.sessionId,\n } as any,\n };\n const response = await ctx.sendMessage<WasmClearSessionRequest>(message);\n if (!response.success) {\n throw new Error(`clearSession failed: ${response.error}`);\n }\n return (response.data as any) || {\n sessionId: args.sessionId,\n clearedSession: false,\n clearedChallenge: false,\n clearedPort: false,\n };\n}\n","import type { VRFWorkerMessage, WasmVrfWorkerRequestType } from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Full VRF logout: zeroize the in-memory VRF keypair and clear all VRF worker caches.\n *\n * This differs from `clearSession`, which only clears a single signing session (`sessionId`).\n * Use this when the user explicitly logs out / locks the VRF keypair.\n */\nexport async function clearVrfSession(ctx: VrfWorkerManagerHandlerContext): Promise<void> {\n console.debug('VRF Manager: Clearing VRF session...');\n\n await ctx.ensureWorkerReady();\n\n try {\n const message: VRFWorkerMessage<WasmVrfWorkerRequestType> = {\n type: 'CLEAR_VRF',\n id: ctx.generateMessageId(),\n payload: {} as WasmVrfWorkerRequestType\n };\n\n const response = await ctx.sendMessage(message);\n\n if (response.success) {\n // Clear the TypeScript-tracked account ID\n ctx.setCurrentVrfAccountId(null);\n console.debug('VRF Manager: VRF session cleared (key material zeroized)');\n } else {\n console.warn('️VRF Manager: Clear VRF failed:', response.error);\n }\n } catch (error) {\n console.warn('VRF Manager: Clear VRF error:', error);\n }\n}\n","import type { AccountId } from '../../../types/accountIds';\nimport type { EncryptedVRFKeypair, VRFWorkerMessage, WasmDevice2RegistrationSessionRequest } from '../../../types/vrf-worker';\nimport type { TransactionContext } from '../../../types/rpc';\nimport type { VRFChallenge } from '../../../types/vrf-worker';\nimport type { WebAuthnRegistrationCredential } from '../../../types/webauthn';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Kick off the SecureConfirm flow for Device2 registration (\"link device\") and return the confirmed result.\n *\n * This is a bundled orchestration that can:\n * - collect a registration credential (PRF-capable),\n * - derive a deterministic VRF keypair for the new device,\n * - and return the data needed for storage + subsequent signing steps (tx context, VRF challenge, etc.).\n */\nexport async function confirmAndDeriveDevice2RegistrationSession(\n ctx: VrfWorkerManagerHandlerContext,\n params: {\n sessionId: string;\n nearAccountId: AccountId;\n deviceNumber: number;\n contractId: string;\n nearRpcUrl: string;\n authenticatorOptions?: object;\n wrapKeySalt?: string;\n }\n): Promise<{\n confirmed: boolean;\n sessionId: string;\n credential: WebAuthnRegistrationCredential;\n vrfChallenge: VRFChallenge;\n transactionContext: TransactionContext;\n wrapKeySalt: string;\n requestId: string;\n intentDigest: string;\n deterministicVrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n error?: string;\n}> {\n await ctx.ensureWorkerReady(true);\n\n const message: VRFWorkerMessage<WasmDevice2RegistrationSessionRequest> = {\n type: 'DEVICE2_REGISTRATION_SESSION',\n id: ctx.generateMessageId(),\n payload: {\n sessionId: params.sessionId,\n nearAccountId: params.nearAccountId,\n deviceNumber: params.deviceNumber,\n contractId: params.contractId,\n nearRpcUrl: params.nearRpcUrl,\n wrapKeySalt: params.wrapKeySalt || '',\n // No confirmationConfig override for now; can add later if needed\n }\n };\n\n const response = await ctx.sendMessage<WasmDevice2RegistrationSessionRequest>(message);\n\n if (!response.success) {\n throw new Error(`Device2 registration session failed: ${response.error}`);\n }\n\n const data = response.data as any;\n\n if (!data.confirmed) {\n throw new Error(data.error || 'User rejected Device2 registration');\n }\n\n if (!data.credential) {\n throw new Error('Missing credential from Device2 registration session');\n }\n if (!data.vrfChallenge) {\n throw new Error('Missing vrfChallenge from Device2 registration session');\n }\n if (!data.transactionContext) {\n throw new Error('Missing transactionContext from Device2 registration session');\n }\n if (!data.wrapKeySalt) {\n throw new Error('Missing wrapKeySalt from Device2 registration session');\n }\n\n return {\n confirmed: true,\n sessionId: data.sessionId,\n credential: data.credential,\n vrfChallenge: data.vrfChallenge,\n transactionContext: data.transactionContext,\n wrapKeySalt: data.wrapKeySalt,\n requestId: data.requestId,\n intentDigest: data.intentDigest,\n deterministicVrfPublicKey: data.deterministicVrfPublicKey,\n encryptedVrfKeypair: data.encryptedVrfKeypair,\n };\n}\n","import type { TransactionInputWasm } from '../../../types/actions';\nimport { ActionType } from '../../../types/actions';\nimport type { RpcCallPayload, ConfirmationConfig } from '../../../types/signer-worker';\nimport type { TransactionContext } from '../../../types/rpc';\nimport { computeUiIntentDigestFromTxs, orderActionForDigest } from '../../../digests/intentDigest';\nimport {\n SecureConfirmationType,\n type SecureConfirmRequest,\n type SignTransactionPayload,\n type SigningAuthMode,\n type TransactionSummary,\n type SerializableCredential,\n} from '../confirmTxFlow/types';\nimport type { SignNep413Payload } from '../confirmTxFlow/types';\nimport type { VrfWorkerManagerContext } from '..';\nimport type { VrfWorkerManagerHandlerContext } from './types';\nimport type { VRFChallenge, VRFWorkerMessage, WasmConfirmAndPrepareSigningSessionRequest } from '../../../types/vrf-worker';\n\nexport interface ConfirmAndPrepareSigningSessionBaseParams {\n ctx: VrfWorkerManagerContext;\n sessionId: string;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n /**\n * Optional override for signing auth mode.\n * When omitted, the VRF worker may auto-select `warmSession` when a session is available.\n *\n * Threshold signing should force `webauthn` to ensure a fresh VRF challenge + WebAuthn assertion\n * is available for relayer authorization.\n */\n signingAuthMode?: SigningAuthMode;\n /**\n * Optional base64url-encoded 32-byte digest to bind a relayer session policy into the VRF input hash (v4+ only).\n * When provided, it is forwarded to the VRF worker for inclusion in VRF input derivation.\n */\n sessionPolicyDigest32?: string;\n}\n\nexport interface ConfirmAndPrepareSigningSessionTransactionParams extends ConfirmAndPrepareSigningSessionBaseParams {\n kind: 'transaction';\n txSigningRequests: TransactionInputWasm[];\n rpcCall: RpcCallPayload;\n title?: string;\n body?: string;\n}\n\nexport interface ConfirmAndPrepareSigningSessionDelegateParams extends ConfirmAndPrepareSigningSessionBaseParams {\n kind: 'delegate';\n nearAccountId: string;\n title?: string;\n body?: string;\n delegate: {\n senderId: string;\n receiverId: string;\n actions: TransactionInputWasm['actions'];\n nonce: string | number | bigint;\n maxBlockHeight: string | number | bigint;\n };\n rpcCall: RpcCallPayload;\n}\n\nexport interface ConfirmAndPrepareSigningSessionNep413Params extends ConfirmAndPrepareSigningSessionBaseParams {\n kind: 'nep413';\n nearAccountId: string;\n message: string;\n recipient: string;\n title?: string;\n body?: string;\n contractId?: string;\n nearRpcUrl?: string;\n}\n\nexport type ConfirmAndPrepareSigningSessionParams =\n | ConfirmAndPrepareSigningSessionTransactionParams\n | ConfirmAndPrepareSigningSessionDelegateParams\n | ConfirmAndPrepareSigningSessionNep413Params;\n\nexport interface ConfirmAndPrepareSigningSessionResult {\n sessionId: string;\n transactionContext: TransactionContext;\n intentDigest: string;\n credential?: SerializableCredential;\n vrfChallenge?: VRFChallenge;\n}\n\n/**\n * Kick off the SecureConfirm signing flow inside the VRF worker.\n *\n * This creates a `SecureConfirmRequest` (tx / delegate / NEP-413) and sends it to the\n * VRF worker, which will render UI, collect a WebAuthn credential when needed, and return the\n * `transactionContext` (reserved nonces, block hash/height) needed by the signer worker.\n */\nexport async function confirmAndPrepareSigningSession(\n handlerCtx: VrfWorkerManagerHandlerContext,\n params: ConfirmAndPrepareSigningSessionParams\n): Promise<ConfirmAndPrepareSigningSessionResult> {\n const { sessionId } = params;\n\n let intentDigest: string;\n let request: SecureConfirmRequest<SignTransactionPayload | SignNep413Payload, TransactionSummary>;\n\n switch (params.kind) {\n case 'transaction': {\n const txSigningRequests = params.txSigningRequests;\n intentDigest = await computeUiIntentDigestFromTxs(\n txSigningRequests.map(tx => ({\n receiverId: tx.receiverId,\n actions: tx.actions.map(orderActionForDigest),\n })) as TransactionInputWasm[]\n );\n\n const summary: TransactionSummary = {\n intentDigest,\n receiverId: txSigningRequests[0]?.receiverId,\n totalAmount: computeTotalAmountYocto(txSigningRequests),\n type: 'transaction',\n ...(params.title != null ? { title: params.title } : {}),\n ...(params.body != null ? { body: params.body } : {}),\n };\n\n request = {\n requestId: sessionId,\n type: SecureConfirmationType.SIGN_TRANSACTION,\n summary,\n payload: {\n txSigningRequests,\n intentDigest,\n rpcCall: params.rpcCall,\n ...(params.sessionPolicyDigest32 ? { sessionPolicyDigest32: params.sessionPolicyDigest32 } : {}),\n ...(params.signingAuthMode ? { signingAuthMode: params.signingAuthMode } : {}),\n },\n confirmationConfig: params.confirmationConfigOverride,\n intentDigest,\n };\n break;\n }\n case 'delegate': {\n const txSigningRequests: TransactionInputWasm[] = [{\n receiverId: params.delegate.receiverId,\n actions: params.delegate.actions,\n }];\n\n intentDigest = await computeUiIntentDigestFromTxs(\n txSigningRequests.map(tx => ({\n receiverId: tx.receiverId,\n actions: tx.actions.map(orderActionForDigest),\n }))\n );\n\n const summary: TransactionSummary = {\n intentDigest,\n receiverId: txSigningRequests[0]?.receiverId,\n totalAmount: computeTotalAmountYocto(txSigningRequests),\n type: 'delegateAction',\n ...(params.title != null ? { title: params.title } : {}),\n ...(params.body != null ? { body: params.body } : {}),\n delegate: {\n senderId: params.delegate.senderId,\n receiverId: params.delegate.receiverId,\n nonce: String(params.delegate.nonce),\n maxBlockHeight: String(params.delegate.maxBlockHeight),\n },\n };\n\n request = {\n requestId: sessionId,\n type: SecureConfirmationType.SIGN_TRANSACTION,\n summary,\n payload: {\n txSigningRequests,\n intentDigest,\n rpcCall: params.rpcCall,\n ...(params.sessionPolicyDigest32 ? { sessionPolicyDigest32: params.sessionPolicyDigest32 } : {}),\n ...(params.signingAuthMode ? { signingAuthMode: params.signingAuthMode } : {}),\n },\n confirmationConfig: params.confirmationConfigOverride,\n intentDigest,\n };\n break;\n }\n case 'nep413': {\n intentDigest = `${params.nearAccountId}:${params.recipient}:${params.message}`;\n const summary: TransactionSummary = {\n intentDigest,\n method: 'NEP-413',\n receiverId: params.recipient,\n ...(params.title != null ? { title: params.title } : {}),\n ...(params.body != null ? { body: params.body } : {}),\n };\n\n request = {\n requestId: sessionId,\n type: SecureConfirmationType.SIGN_NEP413_MESSAGE,\n summary,\n payload: {\n nearAccountId: params.nearAccountId,\n message: params.message,\n recipient: params.recipient,\n ...(params.sessionPolicyDigest32 ? { sessionPolicyDigest32: params.sessionPolicyDigest32 } : {}),\n ...(params.contractId ? { contractId: params.contractId } : {}),\n ...(params.nearRpcUrl ? { nearRpcUrl: params.nearRpcUrl } : {}),\n ...(params.signingAuthMode ? { signingAuthMode: params.signingAuthMode } : {}),\n },\n confirmationConfig: params.confirmationConfigOverride,\n intentDigest,\n };\n break;\n }\n default: {\n // Exhaustiveness guard\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const _exhaustive: never = params;\n throw new Error('Unsupported signing session kind');\n }\n }\n\n await handlerCtx.ensureWorkerReady(true);\n const message: VRFWorkerMessage<WasmConfirmAndPrepareSigningSessionRequest> = {\n type: 'CONFIRM_AND_PREPARE_SIGNING_SESSION',\n id: handlerCtx.generateMessageId(),\n payload: {\n request,\n },\n };\n const response = await handlerCtx.sendMessage<WasmConfirmAndPrepareSigningSessionRequest>(message);\n if (!response.success) {\n throw new Error(`confirmAndPrepareSigningSession failed: ${response.error}`);\n }\n\n const decision = response.data as {\n confirmed?: boolean;\n error?: string;\n intent_digest?: string;\n transaction_context?: TransactionContext;\n credential?: SerializableCredential;\n vrf_challenge?: VRFChallenge;\n };\n\n if (!decision?.confirmed) {\n throw new Error(decision?.error || 'User rejected signing request');\n }\n if (!decision.transaction_context) {\n throw new Error('Missing transactionContext from confirmation flow');\n }\n\n return {\n sessionId,\n transactionContext: decision.transaction_context,\n intentDigest: decision.intent_digest || intentDigest,\n credential: decision.credential,\n vrfChallenge: decision.vrf_challenge,\n };\n}\n\nfunction computeTotalAmountYocto(txSigningRequests: TransactionInputWasm[]): string | undefined {\n try {\n let total = BigInt(0);\n for (const tx of txSigningRequests) {\n for (const action of tx.actions) {\n switch (action.action_type) {\n case ActionType.Transfer:\n total += BigInt(action.deposit || '0');\n break;\n case ActionType.FunctionCall:\n total += BigInt(action.deposit || '0');\n break;\n case ActionType.Stake:\n total += BigInt(action.stake || '0');\n break;\n default:\n break;\n }\n }\n }\n return total > BigInt(0) ? total.toString() : undefined;\n } catch {\n return undefined;\n }\n}\n","import type { AccountId } from '../../../types/accountIds';\nimport type {\n EncryptedVRFKeypair,\n ServerEncryptedVrfKeypair,\n VRFInputData,\n VRFWorkerMessage,\n WasmDeriveVrfKeypairFromPrfRequest,\n} from '../../../types/vrf-worker';\nimport { validateVRFChallenge, type VRFChallenge } from '../../../types/vrf-worker';\nimport type { WebAuthnAuthenticationCredential, WebAuthnRegistrationCredential } from '../../../types/webauthn';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Derive deterministic VRF keypair from PRF output embedded in a WebAuthn credential.\n */\nexport async function deriveVrfKeypairFromPrf(\n ctx: VrfWorkerManagerHandlerContext,\n args: {\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n nearAccountId: AccountId;\n vrfInputData?: VRFInputData;\n saveInMemory?: boolean;\n }\n): Promise<{\n vrfPublicKey: string;\n vrfChallenge: VRFChallenge | null;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n serverEncryptedVrfKeypair: ServerEncryptedVrfKeypair | null;\n}> {\n const saveInMemory = args.saveInMemory ?? true;\n await ctx.ensureWorkerReady();\n\n const vrfInputData = args.vrfInputData;\n const hasVrfInputData = vrfInputData?.blockHash\n && vrfInputData?.blockHeight\n && vrfInputData?.userId\n && vrfInputData?.rpId;\n\n const message: VRFWorkerMessage<WasmDeriveVrfKeypairFromPrfRequest> = {\n type: 'DERIVE_VRF_KEYPAIR_FROM_PRF',\n id: ctx.generateMessageId(),\n payload: {\n credential: args.credential,\n nearAccountId: args.nearAccountId,\n\t saveInMemory,\n\t vrfInputData: hasVrfInputData ? {\n\t userId: vrfInputData.userId,\n\t rpId: vrfInputData.rpId,\n\t blockHeight: String(vrfInputData.blockHeight),\n\t blockHash: vrfInputData.blockHash,\n\t intentDigest: vrfInputData.intentDigest,\n sessionPolicyDigest32: vrfInputData.sessionPolicyDigest32,\n\t } : undefined,\n\t }\n\t };\n\n const response = await ctx.sendMessage(message);\n\n if (!response.success || !response.data) {\n throw new Error(`VRF keypair derivation failed: ${response.error}`);\n }\n const data = response.data as {\n vrfPublicKey?: string;\n vrfChallengeData?: VRFChallenge;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n serverEncryptedVrfKeypair?: ServerEncryptedVrfKeypair | null;\n };\n\n const vrfPublicKey = data.vrfPublicKey || data.vrfChallengeData?.vrfPublicKey;\n if (!vrfPublicKey) {\n throw new Error('VRF public key not found in response');\n }\n if (!data.encryptedVrfKeypair) {\n throw new Error('Encrypted VRF keypair not found in response');\n }\n\n const vrfChallenge = data.vrfChallengeData\n ? validateVRFChallenge({\n vrfInput: data.vrfChallengeData.vrfInput,\n vrfOutput: data.vrfChallengeData.vrfOutput,\n vrfProof: data.vrfChallengeData.vrfProof,\n vrfPublicKey: data.vrfChallengeData.vrfPublicKey,\n userId: data.vrfChallengeData.userId,\n rpId: data.vrfChallengeData.rpId,\n blockHeight: data.vrfChallengeData.blockHeight,\n blockHash: data.vrfChallengeData.blockHash,\n ...(data.vrfChallengeData.intentDigest ? { intentDigest: data.vrfChallengeData.intentDigest } : {}),\n ...(data.vrfChallengeData.sessionPolicyDigest32 ? { sessionPolicyDigest32: data.vrfChallengeData.sessionPolicyDigest32 } : {}),\n })\n : null;\n\n if (saveInMemory) {\n ctx.setCurrentVrfAccountId(args.nearAccountId);\n console.debug(`VRF Manager: VRF keypair loaded in memory for ${args.nearAccountId}`);\n }\n\n return {\n vrfPublicKey,\n vrfChallenge,\n encryptedVrfKeypair: data.encryptedVrfKeypair,\n serverEncryptedVrfKeypair: data.serverEncryptedVrfKeypair || null,\n };\n}\n","import type {\n VRFWorkerMessage,\n WasmMintSessionKeysAndSendToSignerRequest,\n} from '../../../types/vrf-worker';\nimport type { WebAuthnAuthenticationCredential, WebAuthnRegistrationCredential } from '../../../types/webauthn';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Mint/refresh a VRF-owned signing session and deliver WrapKey material to the signer worker.\n *\n * VRF WASM will:\n * - (optionally) gate on `verify_authentication_response` when `contractId` + `nearRpcUrl` are provided,\n * - derive WrapKeySeed from PRF.first_auth + the in-memory VRF secret key,\n * - choose/generate `wrapKeySalt` (when omitted/empty),\n * - upsert session metadata (TTL + remaining uses),\n * - and send `{ wrap_key_seed, wrapKeySalt, prfSecond? }` to the signer worker over the attached MessagePort.\n *\n * The main thread never receives WrapKeySeed; it only receives `wrapKeySalt` metadata.\n * This expects `createSigningSessionChannel` + signer port attachment to have happened for `sessionId`.\n */\nexport async function mintSessionKeysAndSendToSigner(\n ctx: VrfWorkerManagerHandlerContext,\n args: {\n sessionId: string;\n wrapKeySalt?: string;\n contractId?: string;\n nearRpcUrl?: string;\n ttlMs?: number;\n remainingUses?: number;\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n }\n): Promise<{ sessionId: string; wrapKeySalt: string }> {\n await ctx.ensureWorkerReady(true);\n\n const message: VRFWorkerMessage<WasmMintSessionKeysAndSendToSignerRequest> = {\n type: 'MINT_SESSION_KEYS_AND_SEND_TO_SIGNER',\n id: ctx.generateMessageId(),\n payload: {\n sessionId: args.sessionId,\n // Use empty string as a sentinel to tell the VRF worker to generate wrapKeySalt when none is provided.\n wrapKeySalt: args.wrapKeySalt ?? '',\n contractId: args.contractId,\n nearRpcUrl: args.nearRpcUrl,\n ttlMs: args.ttlMs,\n remainingUses: args.remainingUses,\n credential: args.credential,\n }\n };\n const response = await ctx.sendMessage<WasmMintSessionKeysAndSendToSignerRequest>(message);\n if (!response.success) {\n throw new Error(`mintSessionKeysAndSendToSigner failed: ${response.error}`);\n }\n // VRF WASM now delivers WrapKeySeed + wrapKeySalt directly to the signer worker via the\n // attached MessagePort; TS only needs to know that the session is prepared and\n // what wrapKeySalt was actually used (for new vault entries).\n const data = (response.data as unknown) as { sessionId: string; wrapKeySalt?: string } | undefined;\n const wrapKeySalt = data?.wrapKeySalt ?? args.wrapKeySalt ?? '';\n if (!wrapKeySalt) {\n throw new Error('mintSessionKeysAndSendToSigner: VRF worker did not return wrapKeySalt');\n }\n return { sessionId: data?.sessionId ?? args.sessionId, wrapKeySalt };\n}\n","import type { VRFWorkerMessage, WasmDispenseSessionKeyRequest } from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * \"Warm session\" path: dispense an existing VRF-owned session key to the signer worker.\n *\n * VRF WASM enforces TTL/usage limits for `sessionId`, then sends `{ wrap_key_seed, wrapKeySalt }`\n * over the attached MessagePort to the signer worker. This does not prompt for WebAuthn.\n */\nexport async function dispenseSessionKey(\n ctx: VrfWorkerManagerHandlerContext,\n args: { sessionId: string; uses?: number }\n): Promise<{\n sessionId: string;\n remainingUses?: number;\n expiresAtMs?: number;\n}> {\n await ctx.ensureWorkerReady(true);\n const message: VRFWorkerMessage<WasmDispenseSessionKeyRequest> = {\n type: 'DISPENSE_SESSION_KEY',\n id: ctx.generateMessageId(),\n payload: {\n sessionId: args.sessionId,\n uses: args.uses,\n } as any,\n };\n const response = await ctx.sendMessage<WasmDispenseSessionKeyRequest>(message);\n if (!response.success) {\n throw new Error(`dispenseSessionKey failed: ${response.error}`);\n }\n return (response.data as any) || { sessionId: args.sessionId };\n}\n","import type { AccountId } from '../../../types/accountIds';\nimport type {\n VRFWorkerMessage,\n VRFWorkerResponse,\n WasmShamir3PassClientDecryptVrfKeypairRequest\n} from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Shamir 3-pass (client): decrypt/unlock a VRF keypair using a server-protected envelope.\n *\n * On success, the VRF keypair becomes active in the VRF worker and is bound (in TS state) to `nearAccountId`.\n */\nexport async function shamir3PassDecryptVrfKeypair(\n ctx: VrfWorkerManagerHandlerContext,\n args: {\n nearAccountId: AccountId;\n kek_s_b64u: string;\n ciphertextVrfB64u: string;\n serverKeyId: string;\n }\n): Promise<VRFWorkerResponse> {\n await ctx.ensureWorkerReady(true);\n const message: VRFWorkerMessage<WasmShamir3PassClientDecryptVrfKeypairRequest> = {\n type: 'SHAMIR3PASS_CLIENT_DECRYPT_VRF_KEYPAIR',\n id: ctx.generateMessageId(),\n payload: {\n nearAccountId: args.nearAccountId,\n kek_s_b64u: args.kek_s_b64u,\n ciphertextVrfB64u: args.ciphertextVrfB64u,\n // Required key for server selection\n keyId: args.serverKeyId,\n },\n };\n const response = await ctx.sendMessage(message);\n if (response.success) {\n ctx.setCurrentVrfAccountId(args.nearAccountId);\n }\n return response;\n}\n","import type {\n VRFInputData,\n VRFWorkerMessage,\n WasmGenerateVrfChallengeRequest,\n} from '../../../types/vrf-worker';\nimport { validateVRFChallenge, type VRFChallenge } from '../../../types/vrf-worker';\nimport { toAccountId } from '../../../types/accountIds';\nimport type { VrfWorkerManagerHandlerContext } from './types';\nimport { checkVrfStatus } from './checkVrfStatus';\nimport { shamir3PassDecryptVrfKeypair } from './shamir3PassDecryptVrfKeypair';\nimport { toTrimmedString } from '@/utils';\n\n/**\n * Generate a VRF challenge and cache it under `sessionId` inside the VRF worker.\n *\n * This is used by SecureConfirm flows so later steps (e.g. contract verification) can rely on\n * worker-owned challenge data instead of JS-provided state.\n */\nexport async function generateVrfChallengeForSession(\n ctx: VrfWorkerManagerHandlerContext,\n inputData: VRFInputData,\n sessionId: string\n): Promise<VRFChallenge> {\n return generateVrfChallengeInternal(ctx, inputData, sessionId);\n}\n\n/**\n * Generate a one-off VRF challenge without caching it in the VRF worker.\n *\n * Used for standalone WebAuthn prompts where we don't need to later look up the challenge by `sessionId`.\n */\nexport async function generateVrfChallengeOnce(\n ctx: VrfWorkerManagerHandlerContext,\n inputData: VRFInputData\n): Promise<VRFChallenge> {\n return generateVrfChallengeInternal(ctx, inputData);\n}\n\nasync function generateVrfChallengeInternal(\n ctx: VrfWorkerManagerHandlerContext,\n inputData: VRFInputData,\n sessionId?: string\n): Promise<VRFChallenge> {\n await ctx.ensureWorkerReady(true);\n\n // Root-cause fix: ensure the VRF worker's active VRF keypair matches the IndexedDB \"lastUser\" device.\n // Otherwise, multi-device accounts can drift such that:\n // - WebAuthn allowCredentials selects the lastUser passkey, but\n // - VRF challenges are generated from a different device's vrf_sk,\n // causing contract verification failures.\n await ensureVrfKeypairBoundToLastUser(ctx, inputData.userId);\n\n const message: VRFWorkerMessage<WasmGenerateVrfChallengeRequest> = {\n type: 'GENERATE_VRF_CHALLENGE',\n id: ctx.generateMessageId(),\n payload: {\n sessionId,\n\t vrfInputData: {\n\t userId: inputData.userId,\n\t rpId: inputData.rpId,\n\t blockHeight: String(inputData.blockHeight),\n\t blockHash: inputData.blockHash,\n\t intentDigest: inputData.intentDigest,\n sessionPolicyDigest32: inputData.sessionPolicyDigest32,\n\t },\n\t },\n\t };\n\n const response = await ctx.sendMessage(message);\n\n if (!response.success || !response.data) {\n throw new Error(`VRF challenge generation failed: ${response.error}`);\n }\n\n const data = response.data as unknown as VRFChallenge;\n return validateVRFChallenge(data);\n}\n\nasync function ensureVrfKeypairBoundToLastUser(\n ctx: VrfWorkerManagerHandlerContext,\n nearAccountId: string,\n): Promise<void> {\n const accountId = toAccountId(nearAccountId);\n const { indexedDB } = ctx.getContext();\n\n const lastUser = await indexedDB.clientDB.getLastUser().catch(() => null);\n if (!lastUser || toAccountId(lastUser.nearAccountId) !== accountId) {\n return;\n }\n\n const lastUserDeviceNumber = Number(lastUser.deviceNumber);\n if (!Number.isFinite(lastUserDeviceNumber) || lastUserDeviceNumber < 1) {\n return;\n }\n\n const status = await checkVrfStatus(ctx);\n const currentVrfPublicKey = toTrimmedString(status.vrfPublicKey);\n\n // Best-effort: find the expected VRF public key for the last-user device from the authenticator cache.\n const authenticators = await indexedDB.clientDB.getAuthenticatorsByUser(accountId).catch(() => []);\n const expectedVrfPublicKey = toTrimmedString(\n authenticators.find(a => a.credentialId === lastUser.passkeyCredential.rawId)?.vrfPublicKey\n ?? authenticators.find(a => a.deviceNumber === lastUserDeviceNumber)?.vrfPublicKey\n );\n\n const needsRebind = !status.active\n || (expectedVrfPublicKey && currentVrfPublicKey !== expectedVrfPublicKey);\n\n if (!needsRebind) {\n return;\n }\n\n const shamir = lastUser.serverEncryptedVrfKeypair;\n if (!shamir?.ciphertextVrfB64u || !shamir?.kek_s_b64u || !shamir?.serverKeyId) {\n // If we can't rebind automatically, fail early instead of silently generating a challenge from the wrong vrf_sk.\n throw new Error(\n 'VRF session is not bound to the last logged-in passkey device. Please log in again on this device.',\n );\n }\n\n const unlock = await shamir3PassDecryptVrfKeypair(ctx, {\n nearAccountId: accountId,\n ciphertextVrfB64u: shamir.ciphertextVrfB64u,\n kek_s_b64u: shamir.kek_s_b64u,\n serverKeyId: shamir.serverKeyId,\n });\n if (!unlock.success) {\n throw new Error(unlock.error || 'Failed to rebind VRF keypair to the last logged-in device');\n }\n\n // If we know the expected VRF pk, confirm the rebind succeeded.\n if (expectedVrfPublicKey) {\n const rebound = await checkVrfStatus(ctx);\n const reboundPk = toTrimmedString(rebound.vrfPublicKey);\n if (!rebound.active || reboundPk !== expectedVrfPublicKey) {\n throw new Error(\n 'VRF session mismatch: VRF keypair did not match the last logged-in device after rebind. Please log in again.',\n );\n }\n }\n}\n","import type { VRFInputData } from '../../../types/vrf-worker';\nimport { validateVRFChallenge, type VRFChallenge } from '../../../types/vrf-worker';\nimport type { VRFWorkerMessage, WasmGenerateVrfKeypairBootstrapRequest } from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Registration bootstrap: generate a fresh random VRF keypair in the VRF worker and (optionally)\n * generate a VRF challenge from it.\n *\n * This solves the \"chicken-and-egg\" problem during registration where you need a VRF challenge\n * before you have PRF outputs to encrypt the VRF keypair. The generated VRF keypair lives in\n * VRF worker memory until it is later encrypted with PRF output.\n */\nexport async function generateVrfKeypairBootstrap(\n ctx: VrfWorkerManagerHandlerContext,\n args: {\n vrfInputData: VRFInputData;\n saveInMemory: boolean;\n sessionId?: string;\n }\n): Promise<{\n vrfPublicKey: string;\n vrfChallenge: VRFChallenge;\n}> {\n await ctx.ensureWorkerReady();\n try {\n const message: VRFWorkerMessage<WasmGenerateVrfKeypairBootstrapRequest> = {\n type: 'GENERATE_VRF_KEYPAIR_BOOTSTRAP',\n id: ctx.generateMessageId(),\n\t payload: {\n\t // Include VRF input data if provided for challenge generation\n\t sessionId: args.sessionId,\n\t vrfInputData: args.vrfInputData\n\t ? {\n\t userId: args.vrfInputData.userId,\n\t rpId: args.vrfInputData.rpId,\n\t blockHeight: String(args.vrfInputData.blockHeight),\n\t blockHash: args.vrfInputData.blockHash,\n\t intentDigest: args.vrfInputData.intentDigest,\n sessionPolicyDigest32: args.vrfInputData.sessionPolicyDigest32,\n\t }\n\t : undefined,\n\t },\n\t };\n\n const response = await ctx.sendMessage(message);\n\n if (!response.success || !response.data) {\n throw new Error(`VRF bootstrap keypair generation failed: ${response.error}`);\n }\n const data = response.data as { vrf_challenge_data?: VRFChallenge; vrfPublicKey?: string };\n const challengeData = data.vrf_challenge_data as VRFChallenge | undefined;\n if (!challengeData) {\n throw new Error('VRF challenge data failed to be generated');\n }\n const vrfPublicKey = data.vrfPublicKey || challengeData.vrfPublicKey;\n if (!vrfPublicKey) {\n throw new Error('VRF public key missing in bootstrap response');\n }\n if (args.vrfInputData && args.saveInMemory) {\n // Track the account ID for this VRF session if saving in memory\n ctx.setCurrentVrfAccountId(args.vrfInputData.userId);\n }\n\n // TODO: strong types generated by Rust wasm-bindgen\n return {\n vrfPublicKey,\n vrfChallenge: validateVRFChallenge({\n vrfInput: challengeData.vrfInput,\n vrfOutput: challengeData.vrfOutput,\n vrfProof: challengeData.vrfProof,\n vrfPublicKey: challengeData.vrfPublicKey,\n userId: challengeData.userId,\n rpId: challengeData.rpId,\n blockHeight: challengeData.blockHeight,\n blockHash: challengeData.blockHash,\n ...(challengeData.intentDigest ? { intentDigest: challengeData.intentDigest } : {}),\n ...(challengeData.sessionPolicyDigest32 ? { sessionPolicyDigest32: challengeData.sessionPolicyDigest32 } : {}),\n })\n }\n\n } catch (error: any) {\n console.error('VRF Manager: Bootstrap VRF keypair generation failed:', error);\n throw new Error(`Failed to generate bootstrap VRF keypair: ${error.message}`);\n }\n}\n","import type { VRFWorkerMessage, WasmCheckSessionStatusRequest } from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Per-`sessionId` signing-session status (WrapKeySeed session gating).\n *\n * This is NOT the same as the \"global\" VRF unlock status (whether the VRF keypair is active).\n * For VRF keypair unlock status, use `checkVrfStatus`.\n */\nexport async function checkSessionStatus(\n ctx: VrfWorkerManagerHandlerContext,\n args: { sessionId: string }\n): Promise<{\n sessionId: string;\n status: 'active' | 'exhausted' | 'expired' | 'not_found';\n remainingUses?: number;\n expiresAtMs?: number;\n createdAtMs?: number;\n}> {\n await ctx.ensureWorkerReady(true);\n const message: VRFWorkerMessage<WasmCheckSessionStatusRequest> = {\n type: 'CHECK_SESSION_STATUS',\n id: ctx.generateMessageId(),\n payload: {\n sessionId: args.sessionId,\n } as any,\n };\n const response = await ctx.sendMessage<WasmCheckSessionStatusRequest>(message);\n if (!response.success) {\n throw new Error(`checkSessionStatus failed: ${response.error}`);\n }\n return (\n (response.data as any) || {\n sessionId: args.sessionId,\n status: 'not_found',\n }\n );\n}\n","import type { AccountId } from '../../../types/accountIds';\nimport type { EncryptedVRFKeypair, VRFWorkerMessage } from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Prepare an export/decrypt session by having the VRF worker derive and deliver WrapKeySeed\n * to the signer worker, using the VRF-owned confirmation flow.\n *\n * This is used by \"offline export\" / decrypt flows where secrets must not touch the main thread.\n */\nexport async function prepareDecryptSession(\n ctx: VrfWorkerManagerHandlerContext,\n args: {\n sessionId: string;\n nearAccountId: AccountId;\n wrapKeySalt: string;\n /**\n * Optional: local encrypted VRF keypair for this account/device.\n * Supplying this lets the VRF worker unlock the correct VRF secret in offline mode.\n */\n encryptedVrfKeypair?: EncryptedVRFKeypair;\n /**\n * Optional: expected VRF public key (base64url) for sanity checking/fallback derivation.\n */\n expectedVrfPublicKey?: string;\n }\n): Promise<void> {\n if (!args.wrapKeySalt) {\n throw new Error('wrapKeySalt is required for decrypt session');\n }\n await ctx.ensureWorkerReady(true);\n const message: VRFWorkerMessage<any> = {\n type: 'DECRYPT_SESSION',\n id: ctx.generateMessageId(),\n payload: {\n sessionId: args.sessionId,\n nearAccountId: String(args.nearAccountId),\n wrapKeySalt: args.wrapKeySalt,\n encryptedVrfKeypair: args.encryptedVrfKeypair,\n expectedVrfPublicKey: args.expectedVrfPublicKey,\n },\n };\n try {\n console.debug('[VRF] prepareDecryptSession: start', {\n sessionId: args.sessionId,\n nearAccountId: String(args.nearAccountId),\n });\n const response = await ctx.sendMessage(message);\n if (!response.success) {\n console.error('[VRF] prepareDecryptSession: worker reported failure', {\n sessionId: args.sessionId,\n nearAccountId: String(args.nearAccountId),\n error: response.error,\n });\n throw new Error(`prepareDecryptSession failed: ${response.error}`);\n }\n console.debug('[VRF] prepareDecryptSession: success', {\n sessionId: args.sessionId,\n nearAccountId: String(args.nearAccountId),\n });\n } catch (error) {\n console.error('[VRF] prepareDecryptSession: error', {\n sessionId: args.sessionId,\n nearAccountId: String(args.nearAccountId),\n error,\n });\n throw error;\n }\n}\n","import type { ConfirmationConfig } from '../../../../types/signer-worker';\nimport { PASSKEY_MANAGER_DEFAULT_CONFIGS } from '../../../../defaultConfigs';\nimport type { VrfWorkerManagerContext } from '../../';\nimport { runSecureConfirm } from '../../secureConfirmBridge';\nimport {\n SecureConfirmationType,\n type RegistrationSummary,\n type SecureConfirmRequest,\n} from '../types';\nimport {\n parseAndValidateRegistrationCredentialConfirmationPayload,\n type RegistrationCredentialConfirmationPayload,\n} from '../../../SignerWorkerManager/handlers/validation';\n\nexport async function requestRegistrationCredentialConfirmation({\n ctx,\n nearAccountId,\n deviceNumber,\n confirmerText,\n contractId,\n nearRpcUrl,\n confirmationConfig,\n}: {\n ctx: VrfWorkerManagerContext,\n nearAccountId: string,\n deviceNumber: number,\n confirmerText?: { title?: string; body?: string };\n contractId: string,\n nearRpcUrl: string,\n confirmationConfig?: Partial<ConfirmationConfig>,\n}): Promise<RegistrationCredentialConfirmationPayload> {\n\n // Ensure required fields are present; JSON.stringify drops undefined causing Rust parse failure\n const resolvedContractId = contractId || PASSKEY_MANAGER_DEFAULT_CONFIGS.contractId;\n // Use the first URL if defaults include a failover list\n const resolvedNearRpcUrl = nearRpcUrl\n || (PASSKEY_MANAGER_DEFAULT_CONFIGS.nearRpcUrl.split(',')[0] || PASSKEY_MANAGER_DEFAULT_CONFIGS.nearRpcUrl);\n\n const requestId = (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function')\n ? crypto.randomUUID()\n : `register-${Date.now()}-${Math.random().toString(16).slice(2)}`;\n\n const title = confirmerText?.title;\n const body = confirmerText?.body;\n const request: SecureConfirmRequest<{\n nearAccountId: string;\n deviceNumber: number;\n rpcCall: { contractId: string; nearRpcUrl: string; nearAccountId: string };\n }, RegistrationSummary> = {\n requestId,\n type: SecureConfirmationType.REGISTER_ACCOUNT,\n summary: {\n nearAccountId,\n deviceNumber,\n contractId: resolvedContractId,\n ...(title != null ? { title } : {}),\n ...(body != null ? { body } : {}),\n },\n payload: {\n nearAccountId,\n deviceNumber,\n rpcCall: {\n contractId: resolvedContractId,\n nearRpcUrl: resolvedNearRpcUrl,\n nearAccountId,\n },\n },\n confirmationConfig,\n intentDigest: `register:${nearAccountId}:${deviceNumber}`,\n };\n\n const decision = await runSecureConfirm(ctx, request);\n\n return parseAndValidateRegistrationCredentialConfirmationPayload({\n confirmed: decision.confirmed,\n requestId,\n intentDigest: decision.intentDigest || '',\n credential: decision.credential,\n vrfChallenge: decision.vrfChallenge,\n transactionContext: decision.transactionContext,\n error: decision.error,\n });\n}\n","import type { ConfirmationConfig } from '../../../types/signer-worker';\nimport type { RegistrationCredentialConfirmationPayload } from '../../SignerWorkerManager/handlers/validation';\nimport { requestRegistrationCredentialConfirmation as requestRegistrationCredentialConfirmationFlow } from '../confirmTxFlow/flows/requestRegistrationCredentialConfirmation';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Kick off the SecureConfirm UI flow for account registration and return the confirmed decision.\n *\n * This is used when the host (main thread) needs a registration credential + VRF challenge + NEAR context,\n * but the UI/confirmation orchestration lives in the VRF worker confirmation flow.\n */\nexport async function requestRegistrationCredentialConfirmation(\n ctx: VrfWorkerManagerHandlerContext,\n params: {\n nearAccountId: string;\n deviceNumber: number;\n confirmerText?: { title?: string; body?: string };\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n contractId: string;\n nearRpcUrl: string;\n }\n): Promise<RegistrationCredentialConfirmationPayload> {\n const hostCtx = ctx.getContext();\n const decision = await requestRegistrationCredentialConfirmationFlow({\n ctx: hostCtx,\n nearAccountId: params.nearAccountId,\n deviceNumber: params.deviceNumber,\n confirmerText: params.confirmerText,\n contractId: params.contractId,\n nearRpcUrl: params.nearRpcUrl,\n // Flow expects `confirmationConfig` on the request envelope; forward the override.\n confirmationConfig: params.confirmationConfigOverride,\n });\n\n if (!decision.confirmed) {\n throw new Error(decision.error || 'User rejected registration request');\n }\n if (!decision.credential) {\n throw new Error('Missing credential from registration confirmation');\n }\n if (!decision.vrfChallenge) {\n throw new Error('Missing vrfChallenge from registration confirmation');\n }\n if (!decision.transactionContext) {\n throw new Error('Missing transactionContext from registration confirmation');\n }\n\n return decision;\n}\n","import type { VRFWorkerMessage, WasmVrfWorkerRequestType } from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Shamir 3-pass (client): encrypt the currently-unlocked VRF keypair for server lock flows.\n *\n * Returns ciphertext + client key share (`kek_s_b64u`) + server key id for subsequent unlock.\n */\nexport async function shamir3PassEncryptCurrentVrfKeypair(\n ctx: VrfWorkerManagerHandlerContext,\n): Promise<{\n ciphertextVrfB64u: string;\n kek_s_b64u: string;\n serverKeyId: string;\n}> {\n await ctx.ensureWorkerReady(true);\n const message: VRFWorkerMessage<WasmVrfWorkerRequestType> = {\n type: 'SHAMIR3PASS_CLIENT_ENCRYPT_CURRENT_VRF_KEYPAIR',\n id: ctx.generateMessageId(),\n payload: {} as WasmVrfWorkerRequestType,\n };\n const response = await ctx.sendMessage(message);\n if (!response.success || !response.data) {\n throw new Error(`VRF encrypt-current failed: ${response.error}`);\n }\n const { ciphertextVrfB64u, kek_s_b64u, serverKeyId } = response.data as {\n ciphertextVrfB64u: string;\n kek_s_b64u: string;\n serverKeyId: string;\n };\n if (!ciphertextVrfB64u || !kek_s_b64u) {\n throw new Error('Invalid encrypt-current response');\n }\n if (!serverKeyId) {\n throw new Error('Server did not return keyId from apply-server-lock');\n }\n return { ciphertextVrfB64u, kek_s_b64u, serverKeyId };\n}\n","import type { AccountId } from '../../../types/accountIds';\nimport type {\n EncryptedVRFKeypair,\n VRFWorkerMessage,\n VRFWorkerResponse,\n WasmUnlockVrfKeypairRequest,\n} from '../../../types/vrf-worker';\nimport type { WebAuthnAuthenticationCredential, WebAuthnRegistrationCredential } from '../../../types/webauthn';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Unlock/load the VRF keypair into VRF worker memory using a WebAuthn authentication credential.\n *\n * This is the \"login\" / \"unlock\" path: the VRF worker decrypts the stored encrypted VRF keypair\n * using PRF output, and keeps it active in-memory for subsequent operations (challenge gen, sessions, etc.).\n */\nexport async function unlockVrfKeypair(\n ctx: VrfWorkerManagerHandlerContext,\n args: {\n credential: WebAuthnAuthenticationCredential | WebAuthnRegistrationCredential;\n nearAccountId: AccountId;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n onEvent?: (event: { type: string; data: { step: string; message: string } }) => void;\n }\n): Promise<VRFWorkerResponse> {\n await ctx.ensureWorkerReady(true);\n\n args.onEvent?.({\n type: 'loginProgress',\n data: {\n step: 'verifying-server',\n message: 'TouchId success! Unlocking VRF keypair...'\n }\n });\n\n const message: VRFWorkerMessage<WasmUnlockVrfKeypairRequest> = {\n type: 'UNLOCK_VRF_KEYPAIR',\n id: ctx.generateMessageId(),\n payload: {\n nearAccountId: args.nearAccountId,\n encryptedVrfKeypair: args.encryptedVrfKeypair,\n credential: args.credential,\n }\n };\n\n const response = await ctx.sendMessage(message);\n if (response.success) {\n // Track the current VRF session account at TypeScript level\n ctx.setCurrentVrfAccountId(args.nearAccountId);\n console.debug(`VRF Manager: VRF keypair unlocked for ${args.nearAccountId}`);\n } else {\n console.error('VRF Manager: Failed to unlock VRF keypair:', response.error);\n console.error('VRF Manager: Full response:', JSON.stringify(response, null, 2));\n console.error('VRF Manager: Message that was sent:', JSON.stringify(message, null, 2));\n }\n\n return response;\n}\n","/**\n * VRF Manager\n * Uses Web Workers for VRF keypair management with client-hosted worker files.\n */\n\nimport type {\n VRFWorkerStatus,\n VrfWorkerManagerConfig,\n EncryptedVRFKeypair,\n VRFInputData,\n VRFWorkerMessage,\n VRFWorkerResponse,\n ServerEncryptedVrfKeypair,\n WasmVrfWorkerRequestType,\n WasmShamir3PassConfigPRequest,\n WasmShamir3PassConfigServerUrlsRequest,\n} from '../../types/vrf-worker';\nimport type { VRFChallenge } from '../../types/vrf-worker';\nimport { BUILD_PATHS } from '../../../../build-paths.js';\nimport { resolveWorkerUrl } from '../../sdkPaths';\nimport type { AccountId } from '../../types/accountIds';\nimport type { TouchIdPrompt } from '../touchIdPrompt';\nimport type { NearClient } from '../../NearClient';\nimport type { UnifiedIndexedDBManager } from '../../IndexedDBManager';\nimport type { UserPreferencesManager } from '../userPreferences';\nimport type { NonceManager } from '../../nonceManager';\nimport {\n SecureConfirmMessageType,\n type SecureConfirmRequest,\n type SerializableCredential,\n type SigningAuthMode,\n} from './confirmTxFlow/types';\nimport type { TransactionInputWasm } from '../../types/actions';\nimport type { RpcCallPayload, ConfirmationConfig } from '../../types/signer-worker';\nimport type { TransactionContext } from '../../types/rpc';\nimport type { RegistrationCredentialConfirmationPayload } from '../SignerWorkerManager/handlers/validation';\nimport type { WebAuthnAuthenticationCredential, WebAuthnRegistrationCredential } from '../../types/webauthn';\nimport { handlePromptUserConfirmInJsMainThread } from './confirmTxFlow';\nimport type { VrfWorkerManagerHandlerContext } from './handlers/types';\nimport { WorkerControlMessage } from '../../workerControlMessages';\nimport {\n checkVrfStatus,\n clearSession,\n clearVrfSession,\n confirmAndDeriveDevice2RegistrationSession,\n confirmAndPrepareSigningSession,\n deriveVrfKeypairFromPrf,\n mintSessionKeysAndSendToSigner,\n dispenseSessionKey,\n generateVrfChallengeForSession,\n generateVrfChallengeOnce,\n generateVrfKeypairBootstrap,\n checkSessionStatus,\n prepareDecryptSession,\n requestRegistrationCredentialConfirmation,\n shamir3PassDecryptVrfKeypair,\n shamir3PassEncryptCurrentVrfKeypair,\n unlockVrfKeypair,\n} from './handlers';\n\n/**\n * VRF-owned host context passed into confirmTxFlow.\n */\nexport interface VrfWorkerManagerContext {\n touchIdPrompt: TouchIdPrompt;\n nearClient: NearClient;\n indexedDB: UnifiedIndexedDBManager;\n userPreferencesManager: UserPreferencesManager;\n nonceManager: NonceManager;\n rpIdOverride?: string;\n nearExplorerUrl?: string;\n vrfWorkerManager?: SessionVrfWorkerManager;\n}\n\n/**\n * Narrow VRF manager surface used by confirmTxFlow. This interface only exposes\n * session-bound operations so confirm flows cannot accidentally call the\n * low-level helpers that take an optional sessionId.\n */\nexport interface SessionVrfWorkerManager {\n generateVrfKeypairBootstrap(args: {\n vrfInputData: VRFInputData;\n saveInMemory: boolean;\n sessionId: string;\n }): Promise<{\n vrfPublicKey: string;\n vrfChallenge: VRFChallenge;\n }>;\n\n generateVrfChallengeForSession(inputData: VRFInputData, sessionId: string): Promise<VRFChallenge>;\n\n mintSessionKeysAndSendToSigner(args: {\n sessionId: string;\n wrapKeySalt?: string;\n contractId?: string;\n nearRpcUrl?: string;\n ttlMs?: number;\n remainingUses?: number;\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n }): Promise<{ sessionId: string; wrapKeySalt: string }>;\n\n dispenseSessionKey(args: {\n sessionId: string;\n uses?: number;\n }): Promise<{\n sessionId: string;\n remainingUses?: number;\n expiresAtMs?: number;\n }>;\n\n prepareDecryptSession(args: {\n sessionId: string;\n nearAccountId: AccountId;\n wrapKeySalt: string;\n encryptedVrfKeypair?: EncryptedVRFKeypair;\n expectedVrfPublicKey?: string;\n }): Promise<void>;\n\n requestRegistrationCredentialConfirmation(params: {\n nearAccountId: string;\n deviceNumber: number;\n confirmerText?: { title?: string; body?: string };\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n contractId: string;\n nearRpcUrl: string;\n }): Promise<RegistrationCredentialConfirmationPayload>;\n\n confirmAndDeriveDevice2RegistrationSession(params: {\n sessionId: string;\n nearAccountId: AccountId;\n deviceNumber: number;\n contractId: string;\n nearRpcUrl: string;\n authenticatorOptions?: object;\n wrapKeySalt?: string;\n }): Promise<{\n confirmed: boolean;\n sessionId: string;\n credential: WebAuthnRegistrationCredential;\n vrfChallenge: VRFChallenge;\n transactionContext: TransactionContext;\n wrapKeySalt: string;\n requestId: string;\n intentDigest: string;\n deterministicVrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n error?: string;\n }>;\n\n checkVrfStatus(): Promise<VRFWorkerStatus>;\n}\n\n/**\n * VRF Worker Manager\n *\n * This class manages VRF operations using Web Workers for:\n * - VRF keypair unlocking (login)\n * - VRF challenge generation (authentication)\n * - Session management (browser session only)\n * - Client-hosted worker files\n */\nexport class VrfWorkerManager {\n private vrfWorker: Worker | null = null;\n private initializationPromise: Promise<void> | null = null;\n private messageId = 0;\n private config: VrfWorkerManagerConfig;\n private currentVrfAccountId: string | null = null;\n private workerBaseOrigin: string | undefined;\n private context: VrfWorkerManagerContext;\n\n constructor(config: VrfWorkerManagerConfig, context: VrfWorkerManagerContext) {\n this.config = {\n // Default to client-hosted worker file using centralized config\n vrfWorkerUrl: BUILD_PATHS.RUNTIME.VRF_WORKER,\n workerTimeout: 60_000,\n debug: false,\n ...config\n };\n // Attach a self-reference so confirmTxFlow helpers can call back into VRF APIs.\n this.context = {\n ...context,\n vrfWorkerManager: this,\n };\n }\n\n /**\n * Context used by confirmTxFlow for VRF-driven flows.\n */\n getContext(): VrfWorkerManagerContext {\n return this.context;\n }\n\n private getHandlerContext(): VrfWorkerManagerHandlerContext {\n return {\n ensureWorkerReady: this.ensureWorkerReady.bind(this),\n sendMessage: this.sendMessage.bind(this),\n generateMessageId: this.generateMessageId.bind(this),\n getContext: this.getContext.bind(this),\n postToWorker: (message: unknown, transfer?: Transferable[]) => {\n if (!this.vrfWorker) {\n throw new Error('VRF Web Worker not available');\n }\n this.vrfWorker.postMessage(message, transfer as any);\n },\n getCurrentVrfAccountId: () => this.currentVrfAccountId,\n setCurrentVrfAccountId: (next: string | null) => {\n this.currentVrfAccountId = next;\n },\n };\n }\n\n /**\n * Create a VRF-owned MessageChannel for signing and return the signer-facing port.\n * VRF retains the sibling port for WrapKeySeed delivery.\n */\n async createSigningSessionChannel(sessionId: string): Promise<MessagePort> {\n await this.ensureWorkerReady(true);\n if (!this.vrfWorker) {\n throw new Error('VRF Web Worker not available');\n }\n\n const channel = new MessageChannel();\n\n // Wait for VRF worker ACK to avoid a race where MintSessionKeys runs before\n // the VRF worker has stored the port (WrapKeySeed delivery would silently no-op).\n const ackPromise = new Promise<void>((resolve, reject) => {\n const worker = this.vrfWorker!;\n const timeout = setTimeout(() => {\n cleanup();\n reject(new Error(`Timeout waiting for VRF WrapKeySeed port attach for session ${sessionId}`));\n }, 2000);\n\n const onMessage = (event: MessageEvent) => {\n const msg = (event as any)?.data as any;\n if (!msg || typeof msg.type !== 'string') return;\n if (msg.sessionId !== sessionId) return;\n\n if (msg.type === WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_ERROR) {\n cleanup();\n reject(new Error(String(msg.error || 'VRF worker failed to attach WrapKeySeed port')));\n return;\n }\n if (msg.type === WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_OK) {\n cleanup();\n resolve();\n }\n };\n\n const cleanup = () => {\n clearTimeout(timeout);\n worker.removeEventListener('message', onMessage);\n };\n\n worker.addEventListener('message', onMessage);\n });\n\n this.vrfWorker.postMessage(\n { type: WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT, sessionId },\n [channel.port1],\n );\n\n await ackPromise;\n return channel.port2;\n }\n\n /**\n * Derive WrapKeySeed in the VRF worker and deliver it (along with PRF.second if credential provided)\n * to the signer worker via the registered port.\n */\n async mintSessionKeysAndSendToSigner(args: {\n sessionId: string;\n // Optional vault wrapKeySalt. When omitted or empty, VRF worker will generate a fresh wrapKeySalt.\n wrapKeySalt?: string;\n // Optional contract verification context; when provided, VRF Rust will call\n // verify_authentication_response before deriving WrapKeySeed.\n contractId?: string;\n nearRpcUrl?: string;\n // Optional signing-session config. When omitted, VRF worker uses defaults.\n ttlMs?: number;\n remainingUses?: number;\n // Optional credential for PRF.second extraction (registration or authentication)\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n }): Promise<{ sessionId: string; wrapKeySalt: string }> {\n return mintSessionKeysAndSendToSigner(this.getHandlerContext(), args);\n }\n\n /**\n * Dispense an existing VRF-owned session key (WrapKeySeed + wrapKeySalt) over the\n * attached MessagePort for `sessionId`, enforcing TTL/usage in the VRF worker.\n *\n * This is the primitive needed for \"warm\" signing sessions: 1 VRF worker → N one-shot signer workers.\n */\n async dispenseSessionKey(args: {\n sessionId: string;\n uses?: number;\n }): Promise<{\n sessionId: string;\n remainingUses?: number;\n expiresAtMs?: number;\n }> {\n return dispenseSessionKey(this.getHandlerContext(), args);\n }\n\n /**\n * Query VRF-owned signing session status for UI introspection.\n * This does not prompt and does not reveal secrets; it only returns metadata.\n */\n async checkSessionStatus(args: {\n sessionId: string;\n }): Promise<{\n sessionId: string;\n status: 'active' | 'exhausted' | 'expired' | 'not_found';\n remainingUses?: number;\n expiresAtMs?: number;\n createdAtMs?: number;\n }> {\n return checkSessionStatus(this.getHandlerContext(), args);\n }\n\n /**\n * Clear VRF-owned signing session material for a given `sessionId`.\n * Intended for explicit \"Lock\" actions or lifecycle cleanup.\n */\n async clearSession(args: {\n sessionId: string;\n }): Promise<{\n sessionId: string;\n clearedSession: boolean;\n clearedChallenge: boolean;\n clearedPort: boolean;\n }> {\n return clearSession(this.getHandlerContext(), args);\n }\n\n /**\n * VRF-driven decrypt session for export flows.\n * Kicks off a LocalOnly DECRYPT_PRIVATE_KEY_WITH_PRF confirm via VRF Rust and derives\n * WrapKeySeed using the vault-provided wrapKeySalt. WrapKeySeed + wrapKeySalt are sent to the signer over\n * the dedicated MessagePort for the given sessionId.\n */\n async prepareDecryptSession(args: {\n sessionId: string;\n nearAccountId: AccountId;\n wrapKeySalt: string;\n encryptedVrfKeypair?: EncryptedVRFKeypair;\n expectedVrfPublicKey?: string;\n }): Promise<void> {\n return prepareDecryptSession(this.getHandlerContext(), args);\n }\n\n /**\n * VRF-driven confirmation + WrapKeySeed derivation for signing flows.\n * Runs confirmTxFlow on the main thread, derives WrapKeySeed in the VRF worker, and returns\n * the session metadata needed by the signer worker. WrapKeySeed itself travels only over the\n * reserved MessagePort registered via registerSignerWrapKeySeedPort.\n */\n async confirmAndPrepareSigningSession(params: {\n ctx: VrfWorkerManagerContext;\n sessionId: string;\n signingAuthMode?: SigningAuthMode;\n sessionPolicyDigest32?: string;\n kind: 'transaction';\n txSigningRequests: TransactionInputWasm[];\n rpcCall: RpcCallPayload;\n title?: string;\n body?: string;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n } | {\n ctx: VrfWorkerManagerContext;\n sessionId: string;\n signingAuthMode?: SigningAuthMode;\n sessionPolicyDigest32?: string;\n kind: 'delegate';\n nearAccountId: string;\n title?: string;\n body?: string;\n delegate: {\n senderId: string;\n receiverId: string;\n actions: TransactionInputWasm['actions'];\n nonce: string | number | bigint;\n maxBlockHeight: string | number | bigint;\n };\n rpcCall: RpcCallPayload;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n } | {\n ctx: VrfWorkerManagerContext;\n sessionId: string;\n signingAuthMode?: SigningAuthMode;\n sessionPolicyDigest32?: string;\n kind: 'nep413';\n nearAccountId: string;\n message: string;\n recipient: string;\n title?: string;\n body?: string;\n contractId?: string;\n nearRpcUrl?: string;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n }): Promise<{\n sessionId: string;\n transactionContext: TransactionContext;\n intentDigest: string;\n credential?: SerializableCredential;\n vrfChallenge?: VRFChallenge;\n }> {\n return confirmAndPrepareSigningSession(this.getHandlerContext(), params);\n }\n\n /**\n * VRF-driven helper for registration confirmation.\n * Runs confirmTxFlow on the main thread and returns registration artifacts.\n * WrapKeySeed derivation is handled later when we call into signing/derivation\n * flows with PRF + withSigningSession.\n */\n async requestRegistrationCredentialConfirmation(params: {\n nearAccountId: string;\n deviceNumber: number;\n confirmerText?: { title?: string; body?: string };\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n contractId: string;\n nearRpcUrl: string;\n }): Promise<RegistrationCredentialConfirmationPayload> {\n return requestRegistrationCredentialConfirmation(this.getHandlerContext(), params);\n }\n\n /**\n * Combined Device2 registration session: single WebAuthn ceremony for credential + WrapKeySeed derivation.\n *\n * This method orchestrates the complete Device2 registration flow:\n * 1. Runs a VRF-driven registration confirmation (single TouchID prompt)\n * 2. Extracts PRF.first from the credential and derives WrapKeySeed\n * 3. Sends WrapKeySeed to signer worker via MessagePort (never exposed to JS)\n * 4. Returns credential (with PRF.second embedded), vrfChallenge, transactionContext, wrapKeySalt\n *\n * The signer worker can then use PRF.second for NEAR key derivation and WrapKeySeed for encryption.\n */\n async confirmAndDeriveDevice2RegistrationSession(params: {\n sessionId: string;\n nearAccountId: AccountId;\n deviceNumber: number;\n contractId: string;\n nearRpcUrl: string;\n authenticatorOptions?: object;\n wrapKeySalt?: string;\n }): Promise<{\n confirmed: boolean;\n sessionId: string;\n credential: WebAuthnRegistrationCredential;\n vrfChallenge: VRFChallenge;\n transactionContext: TransactionContext;\n wrapKeySalt: string;\n requestId: string;\n intentDigest: string;\n deterministicVrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n error?: string;\n }> {\n return confirmAndDeriveDevice2RegistrationSession(this.getHandlerContext(), params);\n }\n\n setWorkerBaseOrigin(origin: string | undefined): void {\n this.workerBaseOrigin = origin;\n }\n\n /**\n * Ensure VRF worker is ready for operations\n * @param requireHealthCheck - Whether to perform health check after initialization\n */\n private async ensureWorkerReady(requireHealthCheck = false): Promise<void> {\n if (this.initializationPromise) {\n await this.initializationPromise;\n } else if (!this.vrfWorker) {\n await this.initialize();\n }\n if (!this.vrfWorker) {\n throw new Error('VRF Worker failed to initialize');\n }\n // Optional health check for critical operations\n if (requireHealthCheck) {\n try {\n const healthResponse = await this.sendMessage({\n type: 'PING',\n id: this.generateMessageId(),\n payload: {} as WasmVrfWorkerRequestType\n }, 3000);\n\n if (!healthResponse.success) {\n throw new Error('VRF Worker failed health check');\n }\n } catch (error) {\n console.error('VRF Manager: Health check failed:', error);\n throw new Error('VRF Worker failed health check');\n }\n }\n }\n\n /**\n * Initialize VRF functionality using Web Workers\n */\n async initialize(): Promise<void> {\n if (this.initializationPromise) {\n return this.initializationPromise;\n }\n // =============================================================\n // This improved error handling ensures that:\n // 1. Initialization failures are properly logged with full details\n // 2. Errors are re-thrown to callers (no silent swallowing)\n // 3. Failed initialization promise is reset for retry\n // 4. Debug logs actually appear in test output\n this.initializationPromise = this.createVrfWorker().catch(error => {\n console.error('VRF Manager: Initialization failed:', error);\n console.error('VRF Manager: Error details:', {\n message: error.message,\n stack: error.stack,\n name: error.name\n });\n // Reset promise so initialization can be retried\n this.initializationPromise = null;\n throw error; // Re-throw so callers know it failed\n });\n\n const result = await this.initializationPromise;\n return result;\n }\n\n /**\n * Initialize Web Worker with client-hosted VRF worker\n */\n private async createVrfWorker(): Promise<void> {\n try {\n const relativePath = this.config.vrfWorkerUrl || BUILD_PATHS.RUNTIME.VRF_WORKER;\n const vrfUrlStr = resolveWorkerUrl(relativePath, { worker: 'vrf', baseOrigin: this.workerBaseOrigin })\n console.debug('VRF Manager: Worker URL:', vrfUrlStr);\n // Create Web Worker from resolved URL\n this.vrfWorker = new Worker(vrfUrlStr, {\n type: 'module',\n name: 'Web3AuthnVRFWorker'\n });\n // Set up error handling\n this.vrfWorker.onerror = (error) => {\n console.error('VRF Manager: Web Worker error:', error);\n };\n // Test communication with the Web Worker\n await this.testWebWorkerCommunication();\n\n // Configure Shamir P if provided\n if (this.config.shamirPB64u) {\n const resp = await this.sendMessage<WasmShamir3PassConfigPRequest>({\n type: 'SHAMIR3PASS_CONFIG_P',\n id: this.generateMessageId(),\n payload: { p_b64u: this.config.shamirPB64u }\n });\n if (!resp.success) {\n throw new Error(`Failed to configure Shamir P: ${resp.error}`);\n }\n }\n\n // Configure relay server URLs if provided\n if (this.config.relayServerUrl && this.config.applyServerLockRoute && this.config.removeServerLockRoute) {\n const resp2 = await this.sendMessage<WasmShamir3PassConfigServerUrlsRequest>({\n type: 'SHAMIR3PASS_CONFIG_SERVER_URLS',\n id: this.generateMessageId(),\n payload: {\n relayServerUrl: this.config.relayServerUrl,\n applyLockRoute: this.config.applyServerLockRoute,\n removeLockRoute: this.config.removeServerLockRoute,\n }\n });\n if (!resp2.success) {\n throw new Error(`Failed to configure Shamir server URLs: ${resp2.error}`);\n }\n }\n\n } catch (error: any) {\n throw new Error(`VRF Web Worker initialization failed: ${error.message}`);\n }\n }\n\n /**\n * Send message to Web Worker and wait for response\n */\n private async sendMessage<T extends WasmVrfWorkerRequestType>(\n message: VRFWorkerMessage<T>,\n customTimeout?: number\n ): Promise<VRFWorkerResponse> {\n return new Promise((resolve, reject) => {\n if (!this.vrfWorker) {\n reject(new Error('VRF Web Worker not available'));\n return;\n }\n\n const timeoutMs = (customTimeout ?? this.config.workerTimeout ?? 60_000);\n const timeout = setTimeout(() => {\n reject(new Error(`VRF Web Worker communication timeout (${timeoutMs}ms) for message type: ${message.type}`));\n }, timeoutMs);\n\n const handleMessage = (event: MessageEvent) => {\n const payload = event.data as VRFWorkerResponse | {\n type?: unknown;\n data?: unknown;\n };\n\n // Intercept SecureConfirm handshake messages from the VRF worker and\n // dispatch them through confirmTxFlow on the main thread. The decision\n // is sent back to the worker as USER_PASSKEY_CONFIRM_RESPONSE and\n // consumed by awaitSecureConfirmationV2; this should not resolve the\n // original VRF request promise.\n if ((payload as any)?.type === SecureConfirmMessageType.PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD) {\n const env = payload as {\n type: SecureConfirmMessageType.PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD;\n data: SecureConfirmRequest;\n };\n const ctx = this.getContext();\n if (!this.vrfWorker) {\n console.error('[VRF] SecureConfirm: vrfWorker missing for PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD');\n return;\n }\n void handlePromptUserConfirmInJsMainThread(ctx, env, this.vrfWorker);\n return;\n }\n\n const response = payload as VRFWorkerResponse;\n if (response.id === message.id) {\n clearTimeout(timeout);\n this.vrfWorker!.removeEventListener('message', handleMessage);\n resolve(response);\n }\n };\n\n this.vrfWorker.addEventListener('message', handleMessage);\n this.vrfWorker.postMessage(message);\n });\n }\n\n /**\n * Generate unique message ID\n */\n private generateMessageId(): string {\n return `vrf_${Date.now()}_${++this.messageId}`;\n }\n\n /**\n * Unlock VRF keypair in Web Worker memory using PRF output\n * This is called during login to decrypt and load the VRF keypair in-memory\n */\n async unlockVrfKeypair(args: {\n credential: WebAuthnAuthenticationCredential | WebAuthnRegistrationCredential;\n nearAccountId: AccountId;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n onEvent?: (event: { type: string; data: { step: string; message: string } }) => void;\n }): Promise<VRFWorkerResponse> {\n return unlockVrfKeypair(this.getHandlerContext(), args);\n }\n\n async generateVrfChallengeForSession(inputData: VRFInputData, sessionId: string): Promise<VRFChallenge> {\n return generateVrfChallengeForSession(this.getHandlerContext(), inputData, sessionId);\n }\n\n async generateVrfChallengeOnce(inputData: VRFInputData): Promise<VRFChallenge> {\n return generateVrfChallengeOnce(this.getHandlerContext(), inputData);\n }\n\n /**\n * Get current VRF session status\n */\n async checkVrfStatus(): Promise<VRFWorkerStatus> {\n return checkVrfStatus(this.getHandlerContext());\n }\n\n /**\n * Logout and clear VRF session\n */\n async clearVrfSession(): Promise<void> {\n return clearVrfSession(this.getHandlerContext());\n }\n\n /**\n * Set the current VRF account ID at the TypeScript level\n * Used after VRF keypair is loaded in WASM memory (e.g., after deriveVrfKeypairFromPrf)\n * to track which account has an active VRF session\n */\n setCurrentVrfAccountId(nearAccountId: AccountId): void {\n this.currentVrfAccountId = nearAccountId;\n console.debug(`VRF Manager: Current VRF account ID set to ${nearAccountId}`);\n }\n\n /**\n * Generate VRF keypair for bootstrapping - stores in memory unencrypted temporarily\n * This is used during registration to generate a VRF keypair that will be used for\n * WebAuthn ceremony and later encrypted with the real PRF output\n *\n * @param saveInMemory - Always true for bootstrap (VRF keypair stored in memory)\n * @param vrfInputParams - Optional parameters to generate VRF challenge/proof in same call\n * @returns VRF public key and optionally VRF challenge data\n */\n async generateVrfKeypairBootstrap(args: {\n vrfInputData: VRFInputData;\n saveInMemory: boolean;\n sessionId?: string;\n }): Promise<{\n vrfPublicKey: string;\n vrfChallenge: VRFChallenge;\n }> {\n return generateVrfKeypairBootstrap(this.getHandlerContext(), args);\n }\n\n /**\n * Derive deterministic VRF keypair from PRF output embedded in a WebAuthn credential.\n * Optionally generates VRF challenge if input parameters are provided\n * This enables deterministic VRF key derivation without needing stored VRF keypairs\n *\n * @param credential - WebAuthn credential containing PRF outputs\n * @param nearAccountId - NEAR account ID for key derivation salt\n * @param vrfInputParams - Optional VRF input parameters for challenge generation\n * @returns Deterministic VRF public key, optional VRF challenge, and encrypted VRF keypair for storage\n */\n async deriveVrfKeypairFromPrf(args: {\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n nearAccountId: AccountId;\n vrfInputData?: VRFInputData; // optional, for challenge generation\n saveInMemory?: boolean; // optional, whether to save in worker memory\n }): Promise<{\n vrfPublicKey: string;\n vrfChallenge: VRFChallenge | null;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n serverEncryptedVrfKeypair: ServerEncryptedVrfKeypair | null;\n }> {\n return deriveVrfKeypairFromPrf(this.getHandlerContext(), args);\n }\n\n /**\n * This securely decrypts the shamir3Pass encrypted VRF keypair and loads it into memory\n * It performs Shamir-3-Pass commutative decryption within WASM worker with the relay-server\n */\n async shamir3PassDecryptVrfKeypair(args: {\n nearAccountId: AccountId;\n kek_s_b64u: string;\n ciphertextVrfB64u: string;\n serverKeyId: string;\n }): Promise<VRFWorkerResponse> {\n return shamir3PassDecryptVrfKeypair(this.getHandlerContext(), args);\n }\n\n /**\n * Shamir 3-pass: encrypt the currently unlocked VRF keypair under the server key\n * Returns a fresh serverEncryptedVrfKeypair blob for IndexedDB.\n * Requires: current VRF keypair is unlocked and present in worker memory.\n */\n async shamir3PassEncryptCurrentVrfKeypair(): Promise<{\n ciphertextVrfB64u: string;\n kek_s_b64u: string;\n serverKeyId: string;\n }> {\n return shamir3PassEncryptCurrentVrfKeypair(this.getHandlerContext());\n }\n\n /**\n * Test Web Worker communication\n */\n private async testWebWorkerCommunication(): Promise<void> {\n try {\n const timeoutMs = 2000;\n const pingResponse = await this.sendMessage({\n type: 'PING',\n id: this.generateMessageId(),\n payload: {} as WasmVrfWorkerRequestType\n }, timeoutMs);\n if (!pingResponse.success) {\n throw new Error(`VRF Web Worker PING failed: ${pingResponse.error}`);\n }\n return;\n } catch (error: any) {\n console.warn(`️VRF Manager: testWebWorkerCommunication failed:`, error.message);\n }\n }\n}\n","import {\n ConfirmationConfig,\n DEFAULT_CONFIRMATION_CONFIG,\n type SignerMode,\n DEFAULT_SIGNING_MODE,\n coerceSignerMode,\n mergeSignerMode,\n} from '../types/signer-worker';\nimport type { AccountId } from '../types/accountIds';\nimport { IndexedDBManager, type IndexedDBEvent } from '../IndexedDBManager';\n\n\nexport class UserPreferencesManager {\n\n private themeChangeListeners: Set<(theme: 'dark' | 'light') => void> = new Set();\n private confirmationConfigChangeListeners: Set<(config: ConfirmationConfig) => void> = new Set();\n private signerModeChangeListeners: Set<(mode: SignerMode) => void> = new Set();\n\n private currentUserAccountId: AccountId | undefined;\n private confirmationConfig: ConfirmationConfig = DEFAULT_CONFIRMATION_CONFIG;\n private signerMode: SignerMode = DEFAULT_SIGNING_MODE;\n\n // Optional app-provided default theme (e.g., configs.walletTheme). This is NOT a per-user preference.\n private walletThemeOverride: 'dark' | 'light' | null = null;\n // Optional app-provided default signer mode (e.g., configs.signerMode). This is NOT a per-user preference.\n private signerModeOverride: SignerMode | null = null;\n // Wallet-iframe app-origin: delegate signerMode persistence to the wallet host.\n private walletIframeSignerModeWriter: ((signerMode: SignerMode) => Promise<void>) | null = null;\n // Prevent multiple one-time environment syncs per session\n private envThemeSyncedForSession = false;\n\n constructor() {\n // Subscribe to IndexedDB change events for automatic sync\n this.subscribeToIndexedDBChanges();\n }\n\n /**\n * Apply an app-provided default theme (e.g., `configs.walletTheme`) without\n * persisting it as a per-user preference in IndexedDB.\n *\n * This also disables the one-time environment theme sync so host appearance\n * (e.g., VitePress `html.dark`) cannot override an explicit config.\n */\n configureWalletTheme(theme?: 'dark' | 'light'): void {\n if (theme !== 'dark' && theme !== 'light') return;\n this.walletThemeOverride = theme;\n // If integrator explicitly configured a theme, do not auto-sync from environment.\n this.envThemeSyncedForSession = true;\n if (this.confirmationConfig.theme !== theme) {\n this.confirmationConfig = {\n ...this.confirmationConfig,\n theme,\n };\n this.notifyConfirmationConfigChange(this.confirmationConfig);\n this.notifyThemeChange(theme);\n }\n }\n\n /**\n * Apply an app-provided default signer mode (e.g., `configs.signerMode`) without\n * persisting it as a per-user preference in IndexedDB.\n */\n configureDefaultSignerMode(signerMode?: SignerMode | SignerMode['mode'] | null): void {\n const next = coerceSignerMode(signerMode, DEFAULT_SIGNING_MODE);\n this.signerModeOverride = next;\n // When no user is active, keep in-memory default aligned to config.\n if (!this.currentUserAccountId) {\n this.setSignerModeInternal(next, { persist: false, notify: true });\n }\n }\n\n /**\n * In wallet-iframe mode on the app origin, user preferences must be persisted by the wallet host\n * (not the app origin). This configures a best-effort writer used by `setSignerMode(...)` when\n * IndexedDB is disabled.\n */\n configureWalletIframeSignerModeWriter(writer: ((signerMode: SignerMode) => Promise<void>) | null): void {\n this.walletIframeSignerModeWriter = writer;\n }\n\n /**\n * Register a callback for theme change events\n */\n onThemeChange(callback: (theme: 'dark' | 'light') => void): () => void {\n this.themeChangeListeners.add(callback);\n return () => {\n this.themeChangeListeners.delete(callback);\n };\n }\n\n /**\n * Register a callback for confirmation config changes.\n * Used to keep app UI in sync with the wallet host in wallet-iframe mode.\n */\n onConfirmationConfigChange(callback: (config: ConfirmationConfig) => void): () => void {\n this.confirmationConfigChangeListeners.add(callback);\n return () => {\n this.confirmationConfigChangeListeners.delete(callback);\n };\n }\n\n /**\n * Register a callback for signer mode changes.\n */\n onSignerModeChange(callback: (mode: SignerMode) => void): () => void {\n this.signerModeChangeListeners.add(callback);\n return () => {\n this.signerModeChangeListeners.delete(callback);\n };\n }\n\n /**\n * Notify all registered listeners of theme changes\n */\n private notifyThemeChange(theme: 'dark' | 'light'): void {\n if (this.themeChangeListeners.size === 0) {\n // In many environments (e.g., wallet iframe host), there may be no UI subscribers.\n // Use debug to avoid noisy warnings while still being helpful during development.\n console.debug(`[UserPreferencesManager]: No listeners registered, theme change will not propagate.`);\n return;\n }\n\n for (const listener of this.themeChangeListeners) {\n listener(theme);\n }\n }\n\n private notifyConfirmationConfigChange(config: ConfirmationConfig): void {\n if (this.confirmationConfigChangeListeners.size === 0) return;\n for (const listener of this.confirmationConfigChangeListeners) {\n listener(config);\n }\n }\n\n private notifySignerModeChange(mode: SignerMode): void {\n if (this.signerModeChangeListeners.size === 0) return;\n for (const listener of this.signerModeChangeListeners) {\n listener(mode);\n }\n }\n\n /**\n * Best-effort async initialization from IndexedDB.\n *\n * Callers decide when to invoke this so environments that must avoid\n * app-origin IndexedDB (wallet-iframe mode) can skip it entirely.\n */\n async initFromIndexedDB(): Promise<void> {\n await this.loadUserSettings().catch((error) => {\n console.warn('[WebAuthnManager]: Failed to initialize user settings:', error);\n });\n }\n\n /**\n * Subscribe to IndexedDB change events for automatic synchronization\n */\n private subscribeToIndexedDBChanges(): void {\n // Subscribe to IndexedDB change events\n this.unsubscribeFromIndexedDB = IndexedDBManager.clientDB.onChange((event) => {\n void this.handleIndexedDBEvent(event).catch((error) => {\n console.warn('[WebAuthnManager]: Error handling IndexedDB event:', error);\n });\n });\n }\n\n /**\n * Handle IndexedDB change events.\n * @param event - The IndexedDBEvent: `user-updated`, `preferences-updated`, `user-deleted` to handle.\n */\n private async handleIndexedDBEvent(event: IndexedDBEvent): Promise<void> {\n switch (event.type) {\n case 'preferences-updated':\n // Check if this affects the current user\n if (event.accountId === this.currentUserAccountId) {\n await this.reloadUserSettings();\n }\n break;\n\n case 'user-updated':\n // Check if this affects the current user\n if (event.accountId === this.currentUserAccountId) {\n await this.reloadUserSettings();\n }\n break;\n\n case 'user-deleted':\n // Check if the deleted user was the current user\n if (event.accountId === this.currentUserAccountId) {\n this.currentUserAccountId = undefined;\n this.confirmationConfig = DEFAULT_CONFIRMATION_CONFIG;\n }\n break;\n }\n }\n\n /**\n * Unsubscribe function for IndexedDB events\n */\n private unsubscribeFromIndexedDB?: () => void;\n\n /**\n * Clean up resources and unsubscribe from events\n */\n destroy(): void {\n if (this.unsubscribeFromIndexedDB) {\n this.unsubscribeFromIndexedDB();\n this.unsubscribeFromIndexedDB = undefined;\n }\n this.walletIframeSignerModeWriter = null;\n // Clear all theme change listeners\n this.themeChangeListeners.clear();\n this.confirmationConfigChangeListeners.clear();\n this.signerModeChangeListeners.clear();\n }\n\n getCurrentUserAccountId(): AccountId {\n if (!this.currentUserAccountId) {\n console.debug('[UserPreferencesManager]: getCurrentUserAccountId called with no current user; returning empty id');\n // Return an empty string to keep callers defensive; most consumers\n // already treat falsy accountIds as \"no-op\"/logged‑out.\n return '' as AccountId;\n }\n return this.currentUserAccountId;\n }\n\n getConfirmationConfig(): ConfirmationConfig {\n return this.confirmationConfig;\n }\n\n getSignerMode(): SignerMode {\n return this.signerMode;\n }\n\n /**\n * Apply an authoritative confirmation config snapshot from the wallet-iframe host.\n * This updates in-memory state only; persistence remains owned by the wallet origin.\n */\n applyWalletHostConfirmationConfig(args: {\n nearAccountId?: AccountId | null;\n confirmationConfig: ConfirmationConfig;\n }): void {\n const { nearAccountId, confirmationConfig } = args || ({} as any);\n const prevTheme = this.confirmationConfig.theme;\n const next: ConfirmationConfig = {\n ...DEFAULT_CONFIRMATION_CONFIG,\n ...(confirmationConfig || {}),\n } as ConfirmationConfig;\n\n if (nearAccountId) {\n this.currentUserAccountId = nearAccountId;\n }\n\n // Prevent environment heuristics on the app origin from overriding wallet-host state.\n this.envThemeSyncedForSession = true;\n\n this.confirmationConfig = next;\n this.notifyConfirmationConfigChange(this.confirmationConfig);\n if (this.confirmationConfig.theme !== prevTheme) {\n this.notifyThemeChange(this.confirmationConfig.theme);\n }\n }\n\n /**\n * Apply an authoritative signer mode snapshot from the wallet-iframe host.\n * This updates in-memory state only; persistence remains owned by the wallet origin.\n */\n applyWalletHostSignerMode(args: {\n nearAccountId?: AccountId | null;\n signerMode: SignerMode;\n }): void {\n const { nearAccountId, signerMode } = args || ({} as any);\n if (nearAccountId) {\n this.currentUserAccountId = nearAccountId;\n }\n const base = this.signerModeOverride ?? DEFAULT_SIGNING_MODE;\n const next = coerceSignerMode(signerMode, base);\n this.setSignerModeInternal(next, { persist: false, notify: true });\n }\n\n setCurrentUser(nearAccountId: AccountId): void {\n this.currentUserAccountId = nearAccountId;\n // Load settings for the new user (best-effort). In wallet-iframe mode on the app origin,\n // IndexedDB is intentionally disabled to avoid creating any tables.\n if (!IndexedDBManager.clientDB.isDisabled()) {\n void this.loadSettingsForUser(nearAccountId).catch(() => undefined);\n }\n\n // One-time: align user theme to current host appearance (e.g., VitePress html.dark)\n // In wallet-iframe mode (app origin), the wallet host owns preferences; do not override.\n if (!IndexedDBManager.clientDB.isDisabled() && !this.envThemeSyncedForSession && !this.walletThemeOverride) {\n let envTheme: 'dark' | 'light' | null = null;\n const isDark = (globalThis as any)?.document?.documentElement?.classList?.contains?.('dark');\n if (typeof isDark === 'boolean') envTheme = isDark ? 'dark' : 'light';\n if (!envTheme) {\n try {\n const stored = (globalThis as any)?.localStorage?.getItem?.('vitepress-theme-appearance');\n if (stored === 'dark' || stored === 'light') envTheme = stored;\n } catch {\n // Storage may be blocked by the environment (e.g., third-party iframes)\n }\n }\n if (envTheme && envTheme !== this.confirmationConfig.theme) {\n // Fire-and-forget; listeners will propagate the change\n void this.setUserTheme(envTheme);\n }\n this.envThemeSyncedForSession = true;\n }\n }\n\n /**\n * Load settings for a specific user\n */\n private async loadSettingsForUser(nearAccountId: AccountId): Promise<void> {\n if (IndexedDBManager.clientDB.isDisabled()) return;\n const user = await IndexedDBManager.clientDB.getLastUser().catch(() => null);\n if (!user || user.nearAccountId !== nearAccountId) return;\n if (user?.preferences?.confirmationConfig) {\n const prevTheme = this.confirmationConfig.theme;\n this.confirmationConfig = {\n ...this.confirmationConfig,\n ...user.preferences.confirmationConfig\n };\n this.notifyConfirmationConfigChange(this.confirmationConfig);\n if (this.confirmationConfig.theme !== prevTheme) {\n this.notifyThemeChange(this.confirmationConfig.theme);\n }\n }\n\n // Signer mode: stored per-user preference (optional).\n const base = this.signerModeOverride ?? DEFAULT_SIGNING_MODE;\n const stored = user?.preferences?.signerMode as SignerMode | SignerMode['mode'] | null | undefined;\n const nextSignerMode = stored != null ? coerceSignerMode(stored, base) : base;\n this.setSignerModeInternal(nextSignerMode, { persist: false, notify: true });\n }\n\n /**\n * Reload current user settings from IndexedDB\n */\n async reloadUserSettings(): Promise<void> {\n await this.loadSettingsForUser(this.getCurrentUserAccountId());\n }\n\n /**\n * Set confirmation behavior\n */\n setConfirmBehavior(behavior: 'requireClick' | 'autoProceed'): void {\n this.confirmationConfig = {\n ...this.confirmationConfig,\n behavior\n };\n this.notifyConfirmationConfigChange(this.confirmationConfig);\n this.saveUserSettings();\n }\n\n /**\n * Set confirmation configuration\n */\n setConfirmationConfig(config: ConfirmationConfig): void {\n const prevTheme = this.confirmationConfig.theme;\n this.confirmationConfig = {\n ...this.confirmationConfig,\n ...config\n };\n this.notifyConfirmationConfigChange(this.confirmationConfig);\n if (this.confirmationConfig.theme !== prevTheme) {\n this.notifyThemeChange(this.confirmationConfig.theme);\n }\n this.saveUserSettings();\n }\n\n /**\n * Load user confirmation settings from IndexedDB\n */\n async loadUserSettings(): Promise<void> {\n if (IndexedDBManager.clientDB.isDisabled()) return;\n const user = await IndexedDBManager.clientDB.getLastUser().catch(() => null);\n if (user) {\n const prevTheme = this.confirmationConfig.theme;\n this.currentUserAccountId = user.nearAccountId;\n // Load user's confirmation config if it exists, otherwise keep existing settings/defaults\n if (user.preferences?.confirmationConfig) {\n this.confirmationConfig = {\n ...this.confirmationConfig,\n ...user.preferences.confirmationConfig\n };\n this.notifyConfirmationConfigChange(this.confirmationConfig);\n if (this.confirmationConfig.theme !== prevTheme) {\n this.notifyThemeChange(this.confirmationConfig.theme);\n }\n } else {\n console.debug('[WebAuthnManager]: No user preferences found, using defaults');\n }\n\n // Load signer mode preference if available; otherwise use app default (configs.signerMode).\n const base = this.signerModeOverride ?? DEFAULT_SIGNING_MODE;\n const stored = user?.preferences?.signerMode as SignerMode | SignerMode['mode'] | null | undefined;\n const nextSignerMode = stored != null ? coerceSignerMode(stored, base) : base;\n this.setSignerModeInternal(nextSignerMode, { persist: false, notify: true });\n } else {\n console.debug('[WebAuthnManager]: No last user found, using default settings');\n }\n }\n\n /**\n * Save current confirmation settings to IndexedDB\n */\n async saveUserSettings(): Promise<void> {\n try {\n let accountId: AccountId | undefined = this.currentUserAccountId ?? undefined;\n if (!accountId) {\n const last = await IndexedDBManager.clientDB.getLastUser().catch(() => undefined as any);\n accountId = (last as any)?.nearAccountId;\n }\n\n if (!accountId) {\n console.warn('[UserPreferences]: No current user set; keeping confirmation config in memory only');\n return;\n }\n\n // Save confirmation config (which includes theme)\n await IndexedDBManager.clientDB.updatePreferences(accountId, {\n confirmationConfig: this.confirmationConfig,\n });\n } catch (error) {\n console.warn('[WebAuthnManager]: Failed to save user settings:', error);\n }\n }\n\n /**\n * Get user theme preference from IndexedDB\n */\n async getCurrentUserAccountIdTheme(): Promise<'dark' | 'light' | null> {\n const id = this.currentUserAccountId;\n if (!id) return null;\n try {\n return await IndexedDBManager.clientDB.getTheme(id);\n } catch (error) {\n console.debug('[WebAuthnManager]: getCurrentUserAccountIdTheme:', error);\n return null;\n }\n }\n\n getUserTheme(): 'dark' | 'light' {\n return this.confirmationConfig.theme;\n }\n\n /**\n * Set user theme preference in IndexedDB\n */\n async setUserTheme(theme: 'dark' | 'light'): Promise<void> {\n const id = this.currentUserAccountId;\n if (!id) return; // No-op when no user is set (logged-out state)\n // Always update local UI state immediately; persistence is best-effort.\n this.confirmationConfig = {\n ...this.confirmationConfig,\n theme\n };\n // Notify all listeners of theme change\n this.notifyConfirmationConfigChange(this.confirmationConfig);\n this.notifyThemeChange(theme);\n try {\n await IndexedDBManager.clientDB.setTheme(id, theme);\n } catch (error) {\n console.warn('[UserPreferencesManager]: Failed to save user theme:', error);\n }\n }\n\n /**\n * Set signer mode preference (in-memory immediately; IndexedDB persistence is best-effort).\n */\n setSignerMode(signerMode: SignerMode | SignerMode['mode']): void {\n const next = mergeSignerMode(this.signerMode, signerMode);\n // In wallet-iframe mode on the app origin, persistence is owned by the wallet host.\n // Forward to the host and rely on PREFERENCES_CHANGED mirroring for local state updates.\n if (this.walletIframeSignerModeWriter && IndexedDBManager.clientDB.isDisabled()) {\n void this.walletIframeSignerModeWriter(next).catch(() => undefined);\n return;\n }\n this.setSignerModeInternal(next, { persist: true, notify: true });\n }\n\n private isSignerModeEqual(a: SignerMode, b: SignerMode): boolean {\n if (a.mode !== b.mode) return false;\n if (a.mode !== 'threshold-signer' || b.mode !== 'threshold-signer') return true;\n return (a.behavior ?? null) === (b.behavior ?? null);\n }\n\n private setSignerModeInternal(next: SignerMode, opts: { persist: boolean; notify: boolean }): void {\n const prev = this.signerMode;\n this.signerMode = next;\n if (opts.notify && !this.isSignerModeEqual(prev, next)) {\n this.notifySignerModeChange(next);\n }\n if (opts.persist) {\n // Best-effort persistence: only write when we have a current user context.\n const id = this.currentUserAccountId;\n if (!id || IndexedDBManager.clientDB.isDisabled()) return;\n void IndexedDBManager.clientDB.setSignerMode(id, next).catch(() => undefined);\n }\n }\n}\n\n// Create and export singleton instance\nconst UserPreferencesInstance = new UserPreferencesManager();\nexport default UserPreferencesInstance;\n","import type { NearClient } from './NearClient';\nimport type { AccountId } from './types/accountIds';\nimport type { TransactionContext } from './types/rpc';\nimport type { AccessKeyView, BlockResult } from '@near-js/types';\nimport { isObject, isNumber, isString } from '@/utils/validation';\nimport { errorMessage } from '../utils/errors';\n\n/**\n * NonceManager - Singleton for managing NEAR transaction context\n *\n * This class pre-fetches nonce and block height asynchronously at the start\n * of executeAction calls to avoid blocking renderUserConfirmUI().\n *\n * The manager is cleared on logout and instantiated with new user on login.\n */\nexport class NonceManager {\n private static instance: NonceManager | null = null;\n\n public lastNonceUpdate: number | null = null;\n public lastBlockHeightUpdate: number | null = null;\n public nearAccountId: AccountId | null = null;\n public nearPublicKeyStr: string | null = null;\n public transactionContext: TransactionContext | null = null;\n private inflightFetch: Promise<TransactionContext> | null = null;\n // Monotonic identifier to disambiguate concurrent fetches and prevent stale commits/clears\n private inflightId: number = 0;\n private refreshTimer: ReturnType<typeof setTimeout> | null = null;\n private prefetchTimer: ReturnType<typeof setTimeout> | null = null;\n\n // Nonce reservation system for batch transactions\n private reservedNonces: Set<string> = new Set();\n private lastReservedNonce: string | null = null;\n\n // Freshness thresholds (ms)\n // Treat context older than 5s as stale enough to refetch\n private readonly NONCE_FRESHNESS_THRESHOLD = 5 * 1000; // 5 seconds\n private readonly BLOCK_FRESHNESS_THRESHOLD = 20 * 1000; // 20 seconds (less frequent block refreshes)\n private readonly PREFETCH_DEBOUNCE_MS = 400; // less aggressive prefetch debounce to reduce churn\n\n // Private constructor for singleton pattern\n private constructor() {}\n\n /**\n * Get singleton instance\n */\n public static getInstance(): NonceManager {\n if (!NonceManager.instance) {\n NonceManager.instance = new NonceManager();\n }\n return NonceManager.instance;\n }\n\n /**\n * Prefetch block height/hash (and nonce if missing) in the background.\n * - If block info is stale or context missing, triggers a non-blocking refresh.\n * - Safe to call frequently (coalesces concurrent fetches).\n */\n public async prefetchBlockheight(nearClient: NearClient): Promise<void> {\n if (!this.nearAccountId || !this.nearPublicKeyStr) return;\n // Debounce prefetch to avoid repeated calls on quick hover/focus toggles\n this.clearPrefetchTimer();\n this.prefetchTimer = setTimeout(async () => {\n this.prefetchTimer = null;\n if (this.inflightFetch) return; // already fetching\n\n const now = Date.now();\n const isBlockStale = !this.lastBlockHeightUpdate || (now - this.lastBlockHeightUpdate) >= this.BLOCK_FRESHNESS_THRESHOLD;\n const missingContext = !this.transactionContext;\n if (!isBlockStale && !missingContext) return;\n\n try {\n await this.fetchFreshData(nearClient);\n } catch (e) {\n // Swallow errors during prefetch; runtime path will retry as needed\n console.debug('[NonceManager]: prefetchBlockheight ignored error:', e);\n }\n }, this.PREFETCH_DEBOUNCE_MS);\n }\n\n /**\n * Initialize or update the manager with user information\n */\n public initializeUser(nearAccountId: AccountId, nearPublicKeyStr: string): void {\n this.nearAccountId = nearAccountId;\n this.nearPublicKeyStr = nearPublicKeyStr;\n this.clearTransactionContext();\n }\n\n /**\n * Clear all data when user logs out\n */\n public clear(): void {\n this.lastNonceUpdate = null;\n this.lastBlockHeightUpdate = null;\n this.nearAccountId = null;\n this.nearPublicKeyStr = null;\n this.transactionContext = null;\n this.clearRefreshTimer();\n this.clearPrefetchTimer();\n this.inflightFetch = null;\n this.reservedNonces.clear();\n this.lastReservedNonce = null;\n }\n\n /**\n * Smart caching method for nonce and block height data\n * Returns cached data if fresh, otherwise fetches synchronously\n */\n public async getNonceBlockHashAndHeight(nearClient: NearClient, opts?: { force?: boolean }): Promise<TransactionContext> {\n // Always prefer a fresh fetch for critical paths; coalesced by fetchFreshData.\n // This minimizes subtle cache bugs after key rotations/linking and across devices.\n if (!this.nearAccountId || !this.nearPublicKeyStr) {\n throw new Error('NonceManager not initialized with user data');\n }\n // Respect caller's intent to force or use freshness thresholds\n const force = opts?.force === true;\n return await this.fetchFreshData(nearClient, force);\n }\n\n /**\n * Schedule an asynchronous refresh of the transaction context\n */\n private maybeScheduleBackgroundRefresh(nearClient: NearClient): void {\n if (!this.lastNonceUpdate || !this.lastBlockHeightUpdate) return;\n if (this.inflightFetch) return; // already fetching\n\n const now = Date.now();\n const nonceAge = now - this.lastNonceUpdate;\n const blockAge = now - this.lastBlockHeightUpdate;\n\n const halfNonceTtl = this.NONCE_FRESHNESS_THRESHOLD / 2;\n const halfBlockTtl = this.BLOCK_FRESHNESS_THRESHOLD / 2;\n\n // If we're past the half-life for either value, refresh NOW in background\n if (nonceAge >= halfNonceTtl || blockAge >= halfBlockTtl) {\n this.clearRefreshTimer();\n // Fire-and-forget refresh to keep cache warm\n void this.fetchFreshData(nearClient)\n .catch((error) => console.warn('[NonceManager]: Background refresh failed:', error));\n return;\n }\n\n // Otherwise, schedule a refresh for when the earliest metric hits half-life\n const delayToHalfNonce = Math.max(0, halfNonceTtl - nonceAge);\n const delayToHalfBlock = Math.max(0, halfBlockTtl - blockAge);\n const delay = Math.min(delayToHalfNonce, delayToHalfBlock);\n\n // Avoid multiple timers\n this.clearRefreshTimer();\n this.refreshTimer = setTimeout(() => {\n this.refreshTimer = null;\n if (this.inflightFetch) return;\n void this.fetchFreshData(nearClient)\n .catch((error) => console.warn('[NonceManager]: Background refresh failed:', error));\n }, delay);\n }\n\n /**\n * Fetch fresh transaction context data from NEAR RPC\n */\n private async fetchFreshData(nearClient: NearClient, force: boolean = false): Promise<TransactionContext> {\n // Coalesce concurrent refreshes when not forced to reduce redundant network calls.\n // Force=true is used by latency-critical paths (e.g., JIT VRF refresh) to guarantee a fresh block height.\n if (this.inflightFetch && !force) {\n return this.inflightFetch;\n }\n\n const capturedAccountId = this.nearAccountId;\n const capturedPublicKey = this.nearPublicKeyStr;\n // Start a new fetch; assign a unique id to guard commit and cleanup\n const requestId = (++this.inflightId);\n const fetchPromise = (async () => {\n try {\n // Determine what is actually stale so we only fetch what we need\n const now = Date.now();\n const isNonceStale = force || !this.lastNonceUpdate || (now - this.lastNonceUpdate) >= this.NONCE_FRESHNESS_THRESHOLD;\n const isBlockStale = force || !this.lastBlockHeightUpdate || (now - this.lastBlockHeightUpdate) >= this.BLOCK_FRESHNESS_THRESHOLD;\n\n let accessKeyInfo = this.transactionContext?.accessKeyInfo;\n let txBlockHeight = this.transactionContext?.txBlockHeight;\n let txBlockHash = this.transactionContext?.txBlockHash;\n\n const fetchAccessKey = isNonceStale || !accessKeyInfo;\n const fetchBlock = isBlockStale || !txBlockHeight || !txBlockHash;\n\n // Fetch required parts with tolerance for missing access key just after creation\n let maybeAccessKey: unknown = accessKeyInfo ?? null;\n let maybeBlock: unknown = null;\n\n // Run RPC calls in parallel where applicable, while preserving tolerant error handling\n let accessKeyError: unknown = null;\n let blockError: unknown = null;\n const tasks: Promise<void>[] = [];\n\n if (fetchAccessKey) {\n tasks.push((async () => {\n try {\n maybeAccessKey = await nearClient.viewAccessKey(capturedAccountId!, capturedPublicKey!);\n } catch (akErr: unknown) {\n const msg = errorMessage(akErr);\n const missingAk = msg.includes('does not exist while viewing')\n || msg.includes('Access key not found')\n || msg.includes('unknown public key')\n || msg.includes('does not exist');\n if (missingAk) {\n // Non-fatal: proceed without live AK; compute nextNonce conservatively\n maybeAccessKey = null;\n } else {\n accessKeyError = akErr;\n }\n }\n })());\n }\n\n if (fetchBlock) {\n tasks.push((async () => {\n try {\n maybeBlock = await nearClient.viewBlock({ finality: 'final' });\n } catch (err: unknown) {\n // Block info is required\n blockError = err;\n }\n })());\n }\n\n if (tasks.length > 0) {\n await Promise.all(tasks);\n }\n\n if (accessKeyError) {\n throw accessKeyError;\n }\n if (blockError) {\n throw blockError;\n }\n\n // Commit results\n if (fetchAccessKey) {\n if (isAccessKeyView(maybeAccessKey)) {\n accessKeyInfo = maybeAccessKey;\n } else {\n // Keep previous accessKeyInfo if present; else set minimal placeholder\n accessKeyInfo = this.transactionContext?.accessKeyInfo || makePlaceholderAccessKey();\n }\n }\n\n if (fetchBlock) {\n if (!isBlockResult(maybeBlock)) {\n throw new Error('Failed to fetch Block Info');\n }\n txBlockHeight = String(maybeBlock.header.height);\n txBlockHash = maybeBlock.header.hash;\n }\n\n // Derive nextNonce from access key info + current context + reservations\n let nextCandidate = this.maxBigInt(\n accessKeyInfo?.nonce !== undefined ? (BigInt(accessKeyInfo.nonce) + 1n) : 0n,\n this.transactionContext?.nextNonce ? BigInt(this.transactionContext.nextNonce) : 0n,\n this.lastReservedNonce ? BigInt(this.lastReservedNonce) + 1n : 0n\n );\n if (nextCandidate <= 0n) nextCandidate = 1n; // never use 0\n const nextNonce = nextCandidate.toString();\n\n const transactionContext: TransactionContext = {\n nearPublicKeyStr: capturedPublicKey!,\n accessKeyInfo: accessKeyInfo!,\n nextNonce,\n txBlockHeight: txBlockHeight!,\n txBlockHash: txBlockHash!,\n };\n\n // Only commit if identity did not change AND this fetch is still the latest.\n // This guards against stale commits from races when a forced refresh overtakes a cached one.\n if (\n capturedAccountId === this.nearAccountId &&\n capturedPublicKey === this.nearPublicKeyStr &&\n requestId === this.inflightId\n ) {\n this.transactionContext = transactionContext;\n const now = Date.now();\n if (fetchAccessKey) this.lastNonceUpdate = now;\n if (fetchBlock) this.lastBlockHeightUpdate = now;\n } else {\n // Discard results from outdated or identity-mismatched fetches; a newer fetch has already committed.\n }\n\n return transactionContext;\n } catch (error) {\n console.error('[NonceManager]: Failed to fetch fresh transaction context:', error);\n throw error;\n } finally {\n // Only clear inflight if this promise is still the latest.\n if (requestId === this.inflightId) {\n this.inflightFetch = null;\n }\n }\n })();\n\n this.inflightFetch = fetchPromise;\n return fetchPromise;\n }\n\n /**\n * Get the current transaction context\n * Throws if data is not available or stale\n */\n public getTransactionContext(): TransactionContext {\n if (!this.transactionContext) {\n throw new Error('Transaction context not available - call getNonceBlockHashAndHeight() first');\n }\n\n // Check if data is stale (more than 30 seconds old)\n const now = Date.now();\n const maxAge = 30 * 1000; // 30 seconds\n\n if (this.lastNonceUpdate && (now - this.lastNonceUpdate) > maxAge) {\n console.warn('[NonceManager]: Transaction context is stale, consider refreshing');\n }\n\n return this.transactionContext;\n }\n\n /**\n * Check if transaction context is available and not stale\n */\n public isTransactionContextAvailable(maxAgeMs: number = 30000): boolean {\n if (!this.transactionContext || !this.lastNonceUpdate) {\n return false;\n }\n\n const now = Date.now();\n return (now - this.lastNonceUpdate) <= maxAgeMs;\n }\n\n /**\n * Clear transaction context (useful when nonce might be invalidated)\n */\n public clearTransactionContext(): void {\n this.transactionContext = null;\n this.lastNonceUpdate = null;\n this.lastBlockHeightUpdate = null;\n this.clearRefreshTimer();\n this.clearPrefetchTimer();\n this.inflightFetch = null;\n this.reservedNonces.clear();\n this.lastReservedNonce = null;\n }\n\n /**\n * Force a synchronous refresh of nonce + block context.\n * Useful after key rotations (e.g., link-device) or when encountering INVALID_NONCE.\n * Optionally clears any locally reserved nonces to avoid collisions.\n */\n public async refreshNow(nearClient: NearClient, opts?: { clearReservations?: boolean }): Promise<TransactionContext> {\n if (opts?.clearReservations) {\n try { this.releaseAllNonces(); } catch {}\n }\n return await this.fetchFreshData(nearClient, true);\n }\n\n /**\n * Reserve a nonce for batch transactions\n * This increments the nonce locally to prevent conflicts in batch operations\n * @param count - Number of nonces to reserve (default: 1)\n * @returns Array of reserved nonces\n */\n public reserveNonces(count: number = 1): string[] {\n if (!this.transactionContext) {\n throw new Error('Transaction context not available - call getNonceBlockHashAndHeight() first');\n }\n\n if (count <= 0) return [];\n\n const start = this.lastReservedNonce\n ? BigInt(this.lastReservedNonce) + 1n\n : BigInt(this.transactionContext.nextNonce);\n\n // Plan reservations first (pure), then commit atomically\n const planned: string[] = [];\n for (let i = 0; i < count; i++) {\n const candidate = (start + BigInt(i)).toString();\n if (this.reservedNonces.has(candidate)) {\n throw new Error(`Nonce ${candidate} is already reserved`);\n }\n planned.push(candidate);\n }\n\n // Commit: extend set and bump lastReservedNonce\n const newSet = new Set(this.reservedNonces);\n for (const n of planned) newSet.add(n);\n this.reservedNonces = newSet;\n this.lastReservedNonce = planned[planned.length - 1];\n\n return planned;\n }\n\n /**\n * Release a reserved nonce (call when transaction is completed or failed)\n * @param nonce - The nonce to release\n */\n public releaseNonce(nonce: string): void {\n if (this.reservedNonces.has(nonce)) {\n this.reservedNonces.delete(nonce);\n }\n }\n\n /**\n * Release all reserved nonces\n */\n public releaseAllNonces(): void {\n const count = this.reservedNonces.size;\n this.reservedNonces.clear();\n this.lastReservedNonce = null;\n }\n\n /**\n * Update nonce from blockchain after transaction completion\n * This should be called after a transaction is successfully broadcasted\n * @param nearClient - NEAR client for RPC calls\n * @param actualNonce - The actual nonce used in the completed transaction\n */\n public async updateNonceFromBlockchain(nearClient: NearClient, actualNonce: string): Promise<void> {\n if (!this.nearAccountId || !this.nearPublicKeyStr) {\n throw new Error('NonceManager not initialized with user data');\n }\n\n try {\n // Fetch fresh access key info to get the latest nonce\n const accessKeyInfo = await nearClient.viewAccessKey(this.nearAccountId, this.nearPublicKeyStr);\n\n if (!accessKeyInfo || accessKeyInfo.nonce === undefined) {\n throw new Error(`Access key not found or invalid for account ${this.nearAccountId}`);\n }\n\n const chainNonceBigInt = BigInt(accessKeyInfo.nonce);\n const actualNonceBigInt = BigInt(actualNonce);\n\n // Tolerate both pre- and post-final states:\n // - pre-final: chainNonce == actualNonce - 1\n // - post-final: chainNonce >= actualNonce\n if (chainNonceBigInt < actualNonceBigInt - BigInt(1)) {\n console.warn(\n `[NonceManager]: Chain nonce (${chainNonceBigInt}) behind expected (${actualNonceBigInt - BigInt(1)}). Updating...`\n );\n }\n\n // Compute next usable nonce using maxBigInt for clarity\n // Include (actualNonce + 1) to immediately advance locally after broadcast,\n // even if chain finality has not reflected the new nonce yet.\n const candidateNext = this.maxBigInt(\n chainNonceBigInt + 1n,\n actualNonceBigInt + 1n,\n this.transactionContext?.nextNonce ? BigInt(this.transactionContext.nextNonce) : 0n,\n this.lastReservedNonce ? BigInt(this.lastReservedNonce) + 1n : 0n,\n );\n\n // Update cached context with fresh access key info and computed next nonce\n if (this.transactionContext) {\n this.transactionContext.accessKeyInfo = accessKeyInfo;\n this.transactionContext.nextNonce = candidateNext.toString();\n } else {\n // If no context exists (should be rare here), construct a minimal one\n this.transactionContext = {\n nearPublicKeyStr: this.nearPublicKeyStr!,\n accessKeyInfo: accessKeyInfo,\n nextNonce: candidateNext.toString(),\n // Block values are unknown here; leave stale ones to be refreshed later\n txBlockHeight: '0',\n txBlockHash: '',\n } as TransactionContext; // We'll refresh these via fetchFreshData when needed\n }\n this.lastNonceUpdate = Date.now();\n\n // Release the used nonce (idempotent)\n this.releaseNonce(actualNonce);\n\n // Prune any reserved nonces that are now <= chain nonce (already used or invalid)\n if (this.reservedNonces.size > 0) {\n const { set: prunedSet, lastReserved } = this.pruneReserved(chainNonceBigInt, this.reservedNonces);\n this.reservedNonces = prunedSet;\n this.lastReservedNonce = lastReserved;\n }\n\n console.debug(\n `[NonceManager]: Updated from chain nonce=${chainNonceBigInt} actual=${actualNonceBigInt} next=${this.transactionContext!.nextNonce}`\n );\n\n } catch (error: unknown) {\n const msg = errorMessage(error);\n // Tolerate missing/rotated keys: avoid noisy error and advance nextNonce optimistically\n if (msg.includes('does not exist while viewing') || msg.includes('Access key not found')) {\n try {\n const actualNonceBigInt = BigInt(actualNonce);\n const candidateNext = this.maxBigInt(\n actualNonceBigInt + 1n,\n this.transactionContext?.nextNonce ? BigInt(this.transactionContext.nextNonce) : 0n,\n this.lastReservedNonce ? BigInt(this.lastReservedNonce) + 1n : 0n,\n );\n if (this.transactionContext) {\n this.transactionContext.nextNonce = candidateNext.toString();\n } else {\n this.transactionContext = {\n nearPublicKeyStr: this.nearPublicKeyStr!,\n accessKeyInfo: makePlaceholderAccessKey(),\n nextNonce: candidateNext.toString(),\n txBlockHeight: '0',\n txBlockHash: '',\n } as TransactionContext;\n }\n this.lastNonceUpdate = Date.now();\n console.debug('[NonceManager]: Access key missing; advanced nextNonce optimistically to', this.transactionContext?.nextNonce);\n return;\n } catch {}\n }\n console.warn('[NonceManager]: Failed to update nonce from blockchain:', error);\n // Don't throw - this is a best-effort update\n }\n }\n\n /**\n * Get the next available nonce for a single transaction\n * This is a convenience method that reserves exactly one nonce\n * @returns The next nonce to use\n */\n public getNextNonce(): string {\n const nonces = this.reserveNonces(1);\n return nonces[0];\n }\n\n private clearRefreshTimer(): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n }\n private clearPrefetchTimer(): void {\n if (this.prefetchTimer) {\n clearTimeout(this.prefetchTimer);\n this.prefetchTimer = null;\n }\n }\n\n // Small helper to get max of BigInt values elegantly\n private maxBigInt(...values: bigint[]): bigint {\n if (values.length === 0) return 0n;\n return values.reduce((a, b) => (a > b ? a : b));\n }\n\n // Return a new reserved set that excludes entries <= chain nonce, and compute new lastReserved\n private pruneReserved(chainNonceBigInt: bigint, reserved: Set<string>): { set: Set<string>, lastReserved: string | null } {\n const newSet = new Set<string>();\n let newLast: bigint | null = null;\n for (const r of reserved) {\n try {\n const rb = BigInt(r);\n if (rb > chainNonceBigInt) {\n newSet.add(r);\n if (newLast === null || rb > newLast) newLast = rb;\n }\n } catch {\n // skip malformed entries\n }\n }\n return {\n set: newSet,\n lastReserved: newLast ? newLast.toString() : null\n };\n }\n\n}\n\n// ===== Type guards for NEAR RPC return shapes =====\nfunction isAccessKeyView(x: unknown): x is AccessKeyView {\n if (!isObject(x)) return false;\n // Only validate the fields we actually use\n return isNumber((x as { nonce?: unknown }).nonce);\n}\n\nfunction isBlockResult(x: unknown): x is BlockResult {\n if (!isObject(x)) return false;\n const h = (x as { header?: unknown }).header;\n if (!isObject(h)) return false;\n const height = (h as { height?: unknown }).height;\n const hash = (h as { hash?: unknown }).hash;\n return isNumber(height) && isString(hash);\n}\n\nfunction makePlaceholderAccessKey(): AccessKeyView {\n return {\n nonce: BigInt(0),\n permission: 'FullAccess',\n block_hash: '',\n block_height: 0\n }\n}\n\n// Create and export singleton instance\nconst NonceManagerInstance = NonceManager.getInstance();\nexport default NonceManagerInstance;\n","import type { NearClient } from '../../NearClient';\nimport { IndexedDBManager } from '../../IndexedDBManager';\nimport { toAccountId, type AccountId } from '../../types/accountIds';\nimport type { VRFChallenge, VRFInputData } from '../../types/vrf-worker';\nimport { thresholdEd25519Keygen } from '../../rpcCalls';\nimport { computeThresholdEd25519KeygenIntentDigest } from '../../digests/intentDigest';\nimport { ensureEd25519Prefix } from '../../../utils/validation';\nimport type { TouchIdPrompt } from '../touchIdPrompt';\nimport { collectAuthenticationCredentialForVrfChallenge } from '../collectAuthenticationCredentialForVrfChallenge';\n\ntype DeriveThresholdClientShareResult = {\n success: boolean;\n clientVerifyingShareB64u: string;\n wrapKeySalt: string;\n error?: string;\n};\n\nexport type EnrollThresholdEd25519KeyHandlerContext = {\n nearClient: NearClient;\n vrfWorkerManager: {\n generateVrfChallengeOnce: (inputData: VRFInputData) => Promise<VRFChallenge>;\n };\n signerWorkerManager: {\n deriveThresholdEd25519ClientVerifyingShare: (args: {\n sessionId: string;\n nearAccountId: AccountId;\n }) => Promise<DeriveThresholdClientShareResult>;\n };\n touchIdPrompt: Pick<\n TouchIdPrompt,\n 'getRpId' | 'getAuthenticationCredentialsSerialized' | 'getAuthenticationCredentialsSerializedDualPrf'\n >;\n relayerUrl: string;\n};\n\n/**\n * Threshold keygen helper (2-of-2):\n * - derive deterministic client verifying share from WrapKeySeed (via signer worker session)\n * - run `/threshold-ed25519/keygen` to fetch relayer share + group public key\n */\nexport async function enrollThresholdEd25519KeyHandler(\n ctx: EnrollThresholdEd25519KeyHandlerContext,\n args: {\n sessionId: string;\n nearAccountId: AccountId | string;\n }\n): Promise<{\n success: boolean;\n publicKey: string;\n clientParticipantId?: number;\n relayerParticipantId?: number;\n participantIds?: number[];\n clientVerifyingShareB64u: string;\n relayerKeyId: string;\n relayerVerifyingShareB64u: string;\n wrapKeySalt: string;\n error?: string;\n}> {\n const nearAccountId = toAccountId(args.nearAccountId);\n const sessionId = String(args.sessionId || '').trim();\n const relayerUrl = String(ctx.relayerUrl || '').trim();\n\n try {\n if (!sessionId) throw new Error('Missing sessionId');\n if (!relayerUrl) throw new Error('Missing relayer url (configs.relayer.url)');\n\n const derived = await ctx.signerWorkerManager.deriveThresholdEd25519ClientVerifyingShare({\n sessionId,\n nearAccountId,\n });\n if (!derived.success) {\n throw new Error(derived.error || 'Failed to derive threshold client verifying share');\n }\n\n const rpId = ctx.touchIdPrompt.getRpId();\n if (!rpId) throw new Error('Missing rpId for WebAuthn VRF challenge');\n\n // Keygen intent digest must bind the client verifying share; compute it before generating the VRF challenge.\n const keygenIntentDigestB64u = await computeThresholdEd25519KeygenIntentDigest({\n nearAccountId,\n rpId,\n clientVerifyingShareB64u: derived.clientVerifyingShareB64u,\n });\n\n // Fetch a fresh block height/hash for VRF freshness validation.\n const block = await ctx.nearClient.viewBlock({ finality: 'final' } as any);\n const blockHeight = String((block as any)?.header?.height ?? '');\n const blockHash = String((block as any)?.header?.hash ?? '');\n if (!blockHeight || !blockHash) throw new Error('Failed to fetch NEAR block context for keygen VRF challenge');\n\n const vrfChallenge = await ctx.vrfWorkerManager.generateVrfChallengeOnce({\n userId: nearAccountId,\n rpId,\n blockHeight,\n blockHash,\n intentDigest: keygenIntentDigestB64u,\n });\n\n // Collect a WebAuthn authentication credential with the VRF output as challenge.\n const webauthnAuthentication = await collectAuthenticationCredentialForVrfChallenge({\n indexedDB: IndexedDBManager,\n touchIdPrompt: ctx.touchIdPrompt,\n nearAccountId,\n vrfChallenge,\n });\n\n const keygen = await thresholdEd25519Keygen(relayerUrl, vrfChallenge, webauthnAuthentication, {\n clientVerifyingShareB64u: derived.clientVerifyingShareB64u,\n nearAccountId,\n });\n if (!keygen.ok) {\n throw new Error(keygen.error || keygen.message || keygen.code || 'Threshold keygen failed');\n }\n\n const publicKeyRaw = keygen.publicKey;\n const relayerKeyId = keygen.relayerKeyId;\n const relayerVerifyingShareB64u = keygen.relayerVerifyingShareB64u;\n if (!publicKeyRaw) throw new Error('Threshold keygen returned empty publicKey');\n if (!relayerKeyId) throw new Error('Threshold keygen returned empty relayerKeyId');\n if (!relayerVerifyingShareB64u) throw new Error('Threshold keygen returned empty relayerVerifyingShareB64u');\n\n const publicKey = ensureEd25519Prefix(publicKeyRaw);\n if (!publicKey) throw new Error('Threshold keygen returned empty publicKey');\n\n const clientParticipantId = typeof keygen.clientParticipantId === 'number' ? keygen.clientParticipantId : undefined;\n const relayerParticipantId = typeof keygen.relayerParticipantId === 'number' ? keygen.relayerParticipantId : undefined;\n\n return {\n success: true,\n publicKey,\n clientParticipantId,\n relayerParticipantId,\n participantIds: Array.isArray(keygen.participantIds) ? keygen.participantIds : undefined,\n clientVerifyingShareB64u: derived.clientVerifyingShareB64u,\n relayerKeyId,\n relayerVerifyingShareB64u,\n wrapKeySalt: derived.wrapKeySalt,\n };\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return { success: false, publicKey: '', clientVerifyingShareB64u: '', relayerKeyId: '', relayerVerifyingShareB64u: '', wrapKeySalt: '', error: message };\n }\n}\n","import type { NearClient } from '../../NearClient';\nimport { IndexedDBManager } from '../../IndexedDBManager';\nimport { hasAccessKey, waitForAccessKeyAbsent } from '../../rpcCalls';\nimport { ensureEd25519Prefix } from '../../../utils/validation';\nimport { ActionType, type ActionArgsWasm, type TransactionInputWasm } from '../../types/actions';\nimport { toAccountId, type AccountId } from '../../types/accountIds';\nimport { DEFAULT_WAIT_STATUS } from '../../types/rpc';\nimport type {\n ConfirmationConfig,\n RpcCallPayload,\n SignerMode,\n} from '../../types/signer-worker';\nimport type { SignTransactionResult } from '../../types/tatchi';\n\nexport type RotateThresholdEd25519KeyPostRegistrationHandlerContext = {\n nearClient: NearClient;\n contractId: string;\n nearRpcUrl: string;\n signTransactionsWithActions: (args: {\n transactions: TransactionInputWasm[];\n rpcCall: RpcCallPayload;\n signerMode: SignerMode;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n title?: string;\n body?: string;\n }) => Promise<SignTransactionResult[]>;\n};\n\n/**\n * Threshold key rotation (post-registration):\n * - keygen (new relayerKeyId + publicKey)\n * - AddKey(new threshold publicKey)\n * - DeleteKey(old threshold publicKey)\n *\n * Uses the local signer key for AddKey/DeleteKey, and requires the account to already\n * have a stored `threshold_ed25519_2p_v1` key material entry for the target device.\n */\nexport async function rotateThresholdEd25519KeyPostRegistrationHandler(\n ctx: RotateThresholdEd25519KeyPostRegistrationHandlerContext,\n args: {\n nearAccountId: AccountId | string;\n deviceNumber: number;\n oldPublicKey: string;\n oldRelayerKeyId: string;\n newPublicKey: string;\n newRelayerKeyId: string;\n wrapKeySalt: string;\n }\n): Promise<{\n success: boolean;\n oldPublicKey: string;\n oldRelayerKeyId: string;\n publicKey: string;\n relayerKeyId: string;\n wrapKeySalt: string;\n deleteOldKeyAttempted: boolean;\n deleteOldKeySuccess: boolean;\n warning?: string;\n error?: string;\n}> {\n const nearAccountId = toAccountId(args.nearAccountId);\n\n const oldPublicKey = String(args.oldPublicKey || '');\n const oldRelayerKeyId = String(args.oldRelayerKeyId || '');\n const newPublicKey = String(args.newPublicKey || '');\n const newRelayerKeyId = String(args.newRelayerKeyId || '');\n const wrapKeySalt = String(args.wrapKeySalt || '');\n\n const base = {\n oldPublicKey,\n oldRelayerKeyId,\n publicKey: newPublicKey,\n relayerKeyId: newRelayerKeyId,\n wrapKeySalt,\n };\n\n const ok = (params: { deleteOldKeyAttempted: boolean; deleteOldKeySuccess: boolean; warning?: string }) => {\n const { warning, ...rest } = params;\n return {\n success: true,\n ...base,\n ...rest,\n ...(warning ? { warning } : {}),\n };\n };\n\n try {\n const deviceNumber = Number(args.deviceNumber);\n const resolvedDeviceNumber = Number.isSafeInteger(deviceNumber) && deviceNumber >= 1 ? deviceNumber : NaN;\n if (!Number.isSafeInteger(resolvedDeviceNumber) || resolvedDeviceNumber < 1) {\n throw new Error('Invalid deviceNumber');\n }\n\n const oldNormalized = ensureEd25519Prefix(oldPublicKey);\n const newNormalized = ensureEd25519Prefix(newPublicKey);\n\n if (!oldNormalized) {\n return ok({\n deleteOldKeyAttempted: false,\n deleteOldKeySuccess: false,\n warning: 'Rotation completed but old threshold key material had an invalid publicKey; skipped DeleteKey.',\n });\n }\n\n if (oldNormalized === newNormalized) {\n return ok({\n deleteOldKeyAttempted: false,\n deleteOldKeySuccess: true,\n warning: 'Rotation returned the same threshold public key; skipped DeleteKey(old).',\n });\n }\n\n const localKeyMaterial = await IndexedDBManager.nearKeysDB.getLocalKeyMaterial(nearAccountId, resolvedDeviceNumber);\n if (!localKeyMaterial) {\n return ok({\n deleteOldKeyAttempted: false,\n deleteOldKeySuccess: false,\n warning: `Rotation completed but could not load local key material for DeleteKey(old) (account ${nearAccountId} device ${resolvedDeviceNumber}).`,\n });\n }\n\n const localPk = ensureEd25519Prefix(localKeyMaterial.publicKey);\n if (localPk && localPk === oldNormalized) {\n return ok({\n deleteOldKeyAttempted: false,\n deleteOldKeySuccess: false,\n warning: 'Refusing to DeleteKey(old) because it matches the local signer public key.',\n });\n }\n\n const oldOnChain = await hasAccessKey(ctx.nearClient, nearAccountId, oldPublicKey, { attempts: 1, delayMs: 0 });\n if (!oldOnChain) {\n return ok({ deleteOldKeyAttempted: false, deleteOldKeySuccess: true });\n }\n\n const deleteKeyAction: ActionArgsWasm = {\n action_type: ActionType.DeleteKey,\n public_key: oldNormalized,\n };\n\n const txInputs: TransactionInputWasm[] = [\n {\n receiverId: nearAccountId,\n actions: [deleteKeyAction],\n },\n ];\n\n let deleteOldKeyAttempted = false;\n try {\n const rpcCall: RpcCallPayload = {\n contractId: ctx.contractId,\n nearRpcUrl: ctx.nearRpcUrl,\n nearAccountId,\n };\n\n const signed = await ctx.signTransactionsWithActions({\n transactions: txInputs,\n rpcCall,\n signerMode: { mode: 'local-signer' },\n confirmationConfigOverride: {\n uiMode: 'skip',\n behavior: 'autoProceed',\n autoProceedDelay: 0,\n },\n title: 'Rotate threshold key',\n body: 'Confirm deletion of the old threshold access key.',\n });\n\n const signedTx = signed?.[0]?.signedTransaction;\n if (!signedTx) throw new Error('Failed to sign DeleteKey(oldThresholdPublicKey) transaction');\n deleteOldKeyAttempted = true;\n\n await ctx.nearClient.sendTransaction(signedTx, DEFAULT_WAIT_STATUS.linkDeviceDeleteKey);\n\n const deleted = await waitForAccessKeyAbsent(ctx.nearClient, nearAccountId, oldPublicKey);\n if (!deleted) {\n return ok({\n deleteOldKeyAttempted,\n deleteOldKeySuccess: false,\n warning: 'DeleteKey(old) submitted but old access key is still present on-chain.',\n });\n }\n\n return ok({ deleteOldKeyAttempted, deleteOldKeySuccess: true });\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return ok({\n deleteOldKeyAttempted,\n deleteOldKeySuccess: false,\n warning: `Rotation completed but failed to DeleteKey(old): ${message}`,\n });\n }\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return {\n success: false,\n oldPublicKey,\n oldRelayerKeyId,\n publicKey: '',\n relayerKeyId: '',\n wrapKeySalt: '',\n deleteOldKeyAttempted: false,\n deleteOldKeySuccess: false,\n error: message,\n };\n }\n}\n","import {\n IndexedDBManager,\n type ClientUserData,\n type ClientAuthenticatorData,\n type UnifiedIndexedDBManager,\n} from '../IndexedDBManager';\nimport { StoreUserDataInput } from '../IndexedDBManager/passkeyClientDB';\nimport type { ThresholdEd25519_2p_V1Material } from '../IndexedDBManager/passkeyNearKeysDB';\nimport { buildThresholdEd25519Participants2pV1 } from '../../threshold/participants';\nimport { type NearClient, SignedTransaction } from '../NearClient';\nimport { SignerWorkerManager } from './SignerWorkerManager';\nimport { VrfWorkerManager } from './VrfWorkerManager';\nimport { AllowCredential, TouchIdPrompt } from './touchIdPrompt';\nimport { toAccountId } from '../types/accountIds';\nimport { UserPreferencesManager } from './userPreferences';\nimport UserPreferencesInstance from './userPreferences';\nimport { NonceManager } from '../nonceManager';\nimport NonceManagerInstance from '../nonceManager';\nimport {\n EncryptedVRFKeypair,\n ServerEncryptedVrfKeypair,\n VRFInputData,\n VRFChallenge\n} from '../types/vrf-worker';\nimport { ActionType, type ActionArgsWasm, type TransactionInputWasm } from '../types/actions';\nimport type { RegistrationEventStep3, RegistrationHooksOptions, RegistrationSSEEvent, onProgressEvents } from '../types/sdkSentEvents';\nimport type { SignTransactionResult, TatchiConfigs } from '../types/tatchi';\nimport type { AccountId } from '../types/accountIds';\nimport type { AuthenticatorOptions } from '../types/authenticatorOptions';\nimport type { DelegateActionInput } from '../types/delegate';\nimport {\n INTERNAL_WORKER_REQUEST_TYPE_SIGN_ADD_KEY_THRESHOLD_PUBLIC_KEY_NO_PROMPT,\n isSignAddKeyThresholdPublicKeyNoPromptSuccess,\n type ConfirmationConfig,\n type RpcCallPayload,\n type SignerMode,\n type ThresholdBehavior,\n type WasmSignedDelegate,\n} from '../types/signer-worker';\nimport { WebAuthnRegistrationCredential, WebAuthnAuthenticationCredential } from '../types';\nimport { RegistrationCredentialConfirmationPayload } from './SignerWorkerManager/handlers/validation';\nimport { resolveWorkerBaseOrigin, onEmbeddedBaseChange } from '../sdkPaths';\nimport { DEFAULT_WAIT_STATUS, type TransactionContext } from '../types/rpc';\nimport { getLastLoggedInDeviceNumber } from './SignerWorkerManager/getDeviceNumber';\nimport { __isWalletIframeHostMode } from '../WalletIframe/host-mode';\nimport { hasAccessKey } from '../rpcCalls';\nimport { ensureEd25519Prefix } from '../../utils/validation';\nimport { enrollThresholdEd25519KeyHandler } from './threshold/enrollThresholdEd25519Key';\nimport { rotateThresholdEd25519KeyPostRegistrationHandler } from './threshold/rotateThresholdEd25519KeyPostRegistration';\nimport { collectAuthenticationCredentialForVrfChallenge as collectAuthenticationCredentialForVrfChallengeImpl } from './collectAuthenticationCredentialForVrfChallenge';\n\ntype SigningSessionOptions = {\n /** PRF-bearing credential; VRF worker extracts PRF outputs internally */\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n /**\n * Optional wrapKeySalt for WrapKeySeed delivery.\n * When provided, VRF worker will reuse this salt instead of generating a new one.\n */\n wrapKeySalt?: string;\n};\n\n/**\n * WebAuthnManager - Main orchestrator for WebAuthn operations\n *\n * Architecture:\n * - index.ts (this file): Main class orchestrating everything\n * - signerWorkerManager: NEAR transaction signing, and VRF Web3Authn verification RPC calls\n * - vrfWorkerManager: VRF keypair generation, challenge generation\n * - touchIdPrompt: TouchID prompt for biometric authentication\n */\nexport class WebAuthnManager {\n private readonly vrfWorkerManager: VrfWorkerManager;\n private readonly signerWorkerManager: SignerWorkerManager;\n private readonly touchIdPrompt: TouchIdPrompt;\n private readonly userPreferencesManager: UserPreferencesManager;\n private readonly nearClient: NearClient;\n private readonly nonceManager: NonceManager;\n private workerBaseOrigin: string = '';\n // VRF-owned signing session id per account (warm session reuse).\n private activeSigningSessionIds: Map<string, string> = new Map();\n\n readonly tatchiPasskeyConfigs: TatchiConfigs;\n\n constructor(tatchiPasskeyConfigs: TatchiConfigs, nearClient: NearClient) {\n this.tatchiPasskeyConfigs = tatchiPasskeyConfigs;\n this.nearClient = nearClient;\n // Respect rpIdOverride. Safari get() bridge fallback is always enabled.\n this.touchIdPrompt = new TouchIdPrompt(\n tatchiPasskeyConfigs.iframeWallet?.rpIdOverride,\n true,\n );\n this.userPreferencesManager = UserPreferencesInstance;\n // Apply integrator-provided default UI theme (in-memory only; user preferences may override later).\n this.userPreferencesManager.configureWalletTheme?.(tatchiPasskeyConfigs.walletTheme);\n // Apply integrator-provided default signer mode (in-memory only; user preferences may override later).\n this.userPreferencesManager.configureDefaultSignerMode?.(tatchiPasskeyConfigs.signerMode);\n this.nonceManager = NonceManagerInstance;\n const { vrfWorkerConfigs } = tatchiPasskeyConfigs;\n // Group VRF worker configuration and pass context\n this.vrfWorkerManager = new VrfWorkerManager(\n {\n shamirPB64u: vrfWorkerConfigs?.shamir3pass?.p,\n relayServerUrl: vrfWorkerConfigs?.shamir3pass?.relayServerUrl,\n applyServerLockRoute: vrfWorkerConfigs?.shamir3pass?.applyServerLockRoute,\n removeServerLockRoute: vrfWorkerConfigs?.shamir3pass?.removeServerLockRoute,\n },\n {\n touchIdPrompt: this.touchIdPrompt,\n nearClient: this.nearClient,\n indexedDB: IndexedDBManager,\n userPreferencesManager: this.userPreferencesManager,\n nonceManager: this.nonceManager,\n rpIdOverride: this.touchIdPrompt.getRpId(),\n nearExplorerUrl: tatchiPasskeyConfigs.nearExplorerUrl,\n }\n );\n this.signerWorkerManager = new SignerWorkerManager(\n this.vrfWorkerManager,\n nearClient,\n this.userPreferencesManager,\n this.nonceManager,\n this.tatchiPasskeyConfigs.relayer.url,\n tatchiPasskeyConfigs.iframeWallet?.rpIdOverride,\n true,\n tatchiPasskeyConfigs.nearExplorerUrl,\n );\n // VRF worker initializes on-demand with proper error propagation\n\n // Compute initial worker base origin once\n this.workerBaseOrigin = resolveWorkerBaseOrigin() || (typeof window !== 'undefined' ? window.location.origin : '');\n this.signerWorkerManager.setWorkerBaseOrigin(this.workerBaseOrigin);\n this.vrfWorkerManager.setWorkerBaseOrigin?.(this.workerBaseOrigin as any);\n\n // Keep base origin updated if the wallet sets a new embedded base\n if (typeof window !== 'undefined') {\n onEmbeddedBaseChange((url) => {\n const origin = new URL(url, window.location.origin).origin;\n if (origin && origin !== this.workerBaseOrigin) {\n this.workerBaseOrigin = origin;\n this.signerWorkerManager.setWorkerBaseOrigin(origin);\n this.vrfWorkerManager.setWorkerBaseOrigin?.(origin as any);\n }\n });\n }\n\n // Best-effort: load persisted preferences unless we are in app-origin iframe mode,\n // where the wallet origin owns persistence and the app should avoid IndexedDB.\n const shouldAvoidAppOriginIndexedDB =\n !!tatchiPasskeyConfigs.iframeWallet?.walletOrigin && !__isWalletIframeHostMode();\n if (!shouldAvoidAppOriginIndexedDB) {\n void this.userPreferencesManager.initFromIndexedDB().catch(() => undefined);\n }\n }\n\n /**\n * Public pre-warm hook to initialize signer workers ahead of time.\n * Safe to call multiple times; errors are non-fatal.\n */\n prewarmSignerWorkers(): void {\n if (typeof window === 'undefined' || typeof (window as any).Worker === 'undefined') return;\n // Avoid noisy SecurityError in cross‑origin dev: only prewarm when same‑origin\n if (this.workerBaseOrigin && this.workerBaseOrigin !== window.location.origin) return;\n this.signerWorkerManager.preWarmWorkerPool().catch(() => { });\n }\n\n /**\n * Warm critical resources to reduce first-action latency.\n * - Initialize current user (sets up NonceManager and local state)\n * - Prefetch latest block context (and nonce if missing)\n * - Pre-open IndexedDB and warm encrypted key for the active account (best-effort)\n * - Pre-warm signer workers in the background\n */\n async warmCriticalResources(nearAccountId?: string): Promise<void> {\n // Initialize current user first (best-effort)\n if (nearAccountId) {\n await this.initializeCurrentUser(toAccountId(nearAccountId), this.nearClient).catch(() => null);\n }\n // Prefetch latest block/nonce context (best-effort)\n await this.nonceManager.prefetchBlockheight(this.nearClient).catch(() => null);\n // Best-effort: open IndexedDB and warm key data for the account\n if (nearAccountId) {\n await IndexedDBManager.getUserWithKeys(toAccountId(nearAccountId)).catch(() => null);\n }\n // Warm signer workers in background\n this.prewarmSignerWorkers();\n }\n\n /**\n * Resolve the effective rpId used for WebAuthn operations.\n * Delegates to TouchIdPrompt to centralize rpId selection logic.\n */\n getRpId(): string {\n return this.touchIdPrompt.getRpId();\n }\n\n /** Getter for NonceManager instance */\n getNonceManager(): NonceManager {\n return this.nonceManager;\n }\n\n /**\n * WebAuthnManager-level orchestrator for VRF-owned signing sessions.\n * Creates sessionId, wires MessagePort between VRF and signer workers, and ensures cleanup.\n *\n * Overload 1: plain signing session (no WrapKeySeed derivation).\n * Overload 2: signing session with WrapKeySeed derivation, when `SigningSessionOptions`\n * (PRF.first_auth) are provided. wrapKeySalt is generated inside the VRF worker\n * when a new vault entry is being created.\n */\n private generateSessionId(prefix: string): string {\n return (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function')\n ? crypto.randomUUID()\n : `${prefix}-${Date.now()}-${Math.random().toString(16).slice(2)}`;\n }\n\n private toNonNegativeInt(value: unknown): number | undefined {\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) return undefined;\n return Math.floor(value);\n }\n\n private resolveSigningSessionPolicy(args: {\n ttlMs?: number;\n remainingUses?: number;\n }): {\n ttlMs: number;\n remainingUses: number;\n } {\n const ttlMs = this.toNonNegativeInt(args.ttlMs)\n ?? this.tatchiPasskeyConfigs.signingSessionDefaults.ttlMs;\n const remainingUses = this.toNonNegativeInt(args.remainingUses)\n ?? this.tatchiPasskeyConfigs.signingSessionDefaults.remainingUses;\n return { ttlMs, remainingUses };\n }\n\n private getOrCreateActiveSigningSessionId(nearAccountId: AccountId): string {\n const key = String(toAccountId(nearAccountId));\n const existing = this.activeSigningSessionIds.get(key);\n if (existing) return existing;\n const sessionId = this.generateSessionId('signing-session');\n this.activeSigningSessionIds.set(key, sessionId);\n return sessionId;\n }\n\n private async withSigningSession<T>(args: {\n sessionId?: string;\n prefix?: string;\n options?: SigningSessionOptions;\n handler: (sessionId: string) => Promise<T>;\n }): Promise<T> {\n if (typeof args.handler !== 'function') {\n throw new Error('withSigningSession requires a handler function');\n }\n const sessionId = args.sessionId || (args.prefix ? this.generateSessionId(args.prefix) : '');\n if (!sessionId) {\n throw new Error('withSigningSession requires a sessionId or prefix');\n }\n return await this.withSigningSessionInternal({ sessionId, options: args.options, handler: args.handler });\n }\n\n private async withSigningSessionInternal<T>(args: {\n sessionId: string;\n options?: SigningSessionOptions;\n handler: (sessionId: string) => Promise<T>;\n }): Promise<T> {\n const signerPort = await this.vrfWorkerManager.createSigningSessionChannel(args.sessionId);\n await this.signerWorkerManager.reserveSignerWorkerSession(args.sessionId, { signerPort });\n try {\n // If PRF is provided, derive WrapKeySeed in VRF worker and deliver it\n // (along with PRF.second if credential is provided) to the signer worker\n // via the reserved MessagePort before invoking the handler.\n if (args.options) {\n await this.vrfWorkerManager.mintSessionKeysAndSendToSigner({\n sessionId: args.sessionId,\n wrapKeySalt: args.options.wrapKeySalt,\n credential: args.options.credential,\n });\n }\n return await args.handler(args.sessionId);\n } finally {\n this.signerWorkerManager.releaseSigningSession(args.sessionId);\n }\n }\n\n /**\n * VRF-driven registration confirmation helper.\n * Runs confirmTxFlow and returns registration artifacts.\n *\n * SecureConfirm wrapper for link-device / registration: prompts user in-iframe to create a\n * new passkey (device N), returning artifacts for subsequent derivation.\n */\n async requestRegistrationCredentialConfirmation(params: {\n nearAccountId: string;\n deviceNumber: number;\n confirmerText?: { title?: string; body?: string };\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n }): Promise<RegistrationCredentialConfirmationPayload> {\n return this.vrfWorkerManager.requestRegistrationCredentialConfirmation({\n nearAccountId: params.nearAccountId,\n deviceNumber: params.deviceNumber,\n confirmerText: params.confirmerText,\n confirmationConfigOverride: params.confirmationConfigOverride,\n contractId: this.tatchiPasskeyConfigs.contractId,\n nearRpcUrl: this.tatchiPasskeyConfigs.nearRpcUrl,\n });\n }\n\n /**\n * Helper for export/decrypt flows:\n * - Read vault wrapKeySalt\n * - Ask VRF worker to run LocalOnly(DECRYPT_PRIVATE_KEY_WITH_PRF) + derive WrapKeySeed\n * - WrapKeySeed travels only over the VRF→Signer MessagePort\n */\n private async confirmDecryptAndDeriveWrapKeySeed(args: {\n nearAccountId: AccountId;\n sessionId: string;\n }): Promise<void> {\n const nearAccountId = toAccountId(args.nearAccountId);\n // Resolve deviceNumber consistently with signer paths so both VRF and signer\n // operate on the same vault entry. Prefer the last logged-in device for this\n // account; if unavailable, fall back to the most recently updated user row.\n const [last, latest] = await Promise.all([\n IndexedDBManager.clientDB.getLastUser().catch(() => null),\n IndexedDBManager.clientDB.getLastDBUpdatedUser(nearAccountId).catch(() => null)\n ]);\n\n const deviceNumber =\n (last && last.nearAccountId === nearAccountId && typeof last.deviceNumber === 'number')\n ? last.deviceNumber\n : (latest && typeof latest.deviceNumber === 'number')\n ? latest.deviceNumber\n : null;\n\n if (deviceNumber === null) {\n throw new Error(`No deviceNumber found for account ${nearAccountId} (decrypt session)`);\n }\n\n // Load VRF material for this device so the VRF worker can unlock the correct\n // VRF keypair in a fresh/offline worker instance.\n const userForDevice = await IndexedDBManager.clientDB.getUserByDevice(nearAccountId, deviceNumber).catch(() => null);\n const encryptedVrfKeypair = userForDevice?.encryptedVrfKeypair;\n\n // Gather encrypted key + wrapKeySalt and public key from IndexedDB for this device\n const keyMaterial = await IndexedDBManager.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber);\n if (!keyMaterial) {\n console.error('WebAuthnManager: No encrypted key found for decrypt session', {\n nearAccountId: String(nearAccountId),\n deviceNumber,\n });\n throw new Error(`No key material found for account: ${nearAccountId}`);\n }\n const wrapKeySalt = keyMaterial.wrapKeySalt;\n if (!wrapKeySalt) {\n console.error('WebAuthnManager: Missing wrapKeySalt in vault for decrypt session', {\n nearAccountId: String(nearAccountId),\n deviceNumber,\n });\n throw new Error('Missing wrapKeySalt in vault; re-register to upgrade vault format.');\n }\n\n try {\n await this.vrfWorkerManager.prepareDecryptSession({\n sessionId: args.sessionId,\n nearAccountId,\n wrapKeySalt,\n encryptedVrfKeypair,\n });\n } catch (error) {\n console.error('WebAuthnManager: VRF decrypt session failed', {\n nearAccountId: String(nearAccountId),\n sessionId: args.sessionId,\n error,\n });\n throw error;\n }\n }\n\n getAuthenticationCredentialsSerialized({\n nearAccountId,\n challenge,\n allowCredentials\n }: {\n nearAccountId: AccountId;\n challenge: VRFChallenge;\n allowCredentials: AllowCredential[];\n }): Promise<WebAuthnAuthenticationCredential> {\n return this.touchIdPrompt.getAuthenticationCredentialsSerialized({\n nearAccountId,\n challenge,\n allowCredentials\n });\n }\n\n async collectAuthenticationCredentialForVrfChallenge(args: {\n nearAccountId: AccountId | string;\n vrfChallenge: VRFChallenge;\n onBeforePrompt?: (info: {\n authenticators: ClientAuthenticatorData[];\n authenticatorsForPrompt: ClientAuthenticatorData[];\n vrfChallenge: VRFChallenge;\n }) => void;\n /**\n * When true, include PRF.second in the serialized credential.\n * Use only for explicit recovery/export flows (higher-friction paths).\n */\n includeSecondPrfOutput?: boolean;\n }): Promise<WebAuthnAuthenticationCredential> {\n return collectAuthenticationCredentialForVrfChallengeImpl({\n indexedDB: IndexedDBManager,\n touchIdPrompt: this.touchIdPrompt,\n nearAccountId: args.nearAccountId,\n vrfChallenge: args.vrfChallenge,\n includeSecondPrfOutput: args.includeSecondPrfOutput,\n onBeforePrompt: args.onBeforePrompt,\n });\n }\n\n ///////////////////////////////////////\n // VRF MANAGER FUNCTIONS\n ///////////////////////////////////////\n\n /**\n * Generate a VRF challenge bound to a specific signing/confirm session.\n * The challenge will be cached in the VRF worker under this sessionId so\n * later contract verification (MINT_SESSION_KEYS_AND_SEND_TO_SIGNER) can look it up.\n */\n async generateVrfChallengeForSession(\n sessionId: string,\n vrfInputData: VRFInputData,\n ): Promise<VRFChallenge> {\n return this.vrfWorkerManager.generateVrfChallengeForSession(vrfInputData, sessionId);\n }\n\n /**\n * Generate a one-off VRF challenge without caching it in the VRF worker.\n * Use this for flows that don't perform contract verification or derive\n * wrap keys via MINT_SESSION_KEYS_AND_SEND_TO_SIGNER.\n */\n async generateVrfChallengeOnce(vrfInputData: VRFInputData): Promise<VRFChallenge> {\n return this.vrfWorkerManager.generateVrfChallengeOnce(vrfInputData);\n }\n\n /**\n * Generate VRF keypair for bootstrapping - stores in memory unencrypted temporarily\n * This is used during registration to generate a VRF keypair that will be used for\n * WebAuthn ceremony and later encrypted with the real PRF output\n *\n * @param saveInMemory - Whether to persist the generated VRF keypair in WASM worker memory\n * @param vrfInputParams - Optional parameters to generate VRF challenge/proof in same call\n * @returns VRF public key and optionally VRF challenge data\n */\n async generateVrfKeypairBootstrap(args: {\n saveInMemory: boolean;\n vrfInputData: VRFInputData;\n sessionId?: string;\n }): Promise<{\n vrfPublicKey: string;\n vrfChallenge: VRFChallenge;\n }> {\n return this.vrfWorkerManager.generateVrfKeypairBootstrap({\n vrfInputData: args.vrfInputData,\n saveInMemory: args.saveInMemory,\n sessionId: args.sessionId,\n });\n }\n\n /**\n * Derive NEAR keypair directly from a serialized WebAuthn registration credential\n */\n async deriveNearKeypairAndEncryptFromSerialized({\n credential,\n nearAccountId,\n options,\n }: {\n credential: WebAuthnRegistrationCredential;\n nearAccountId: string;\n options?: {\n authenticatorOptions?: AuthenticatorOptions;\n deviceNumber?: number;\n };\n }): Promise<{\n success: boolean;\n nearAccountId: string;\n publicKey: string;\n chacha20NonceB64u?: string;\n wrapKeySalt?: string;\n error?: string;\n }> {\n return this.withSigningSession({\n prefix: 'reg',\n options: { credential },\n handler: (sessionId) =>\n this.signerWorkerManager.deriveNearKeypairAndEncryptFromSerialized({\n credential,\n nearAccountId: toAccountId(nearAccountId),\n options,\n sessionId,\n }),\n });\n }\n\n /**\n * **Sign Device2 registration transaction with already-stored key (no prompt)**\n *\n * Used by linkDevice flow after key swap to sign the registration transaction\n * without prompting the user again. Reuses the credential collected earlier.\n *\n * Flow:\n * 1. Extract PRF.first from the provided credential\n * 2. Create new MessagePort session for WrapKeySeed delivery\n * 3. VRF worker re-derives WrapKeySeed and sends to signer (with PRF.second)\n * 4. Signer worker retrieves encrypted key from IndexedDB\n * 5. Signer worker decrypts key and signs registration transaction\n *\n * @param nearAccountId - NEAR account ID for Device2\n * @param credential - WebAuthn registration credential from earlier prompt\n * @param vrfChallenge - VRF challenge from earlier prompt\n * @param deviceNumber - Device number for Device2\n * @returns Signed registration transaction ready for submission\n */\n async signDevice2RegistrationWithStoredKey(args: {\n nearAccountId: AccountId;\n credential: WebAuthnRegistrationCredential;\n vrfChallenge: VRFChallenge;\n deviceNumber: number;\n deterministicVrfPublicKey: string;\n }): Promise<{\n success: boolean;\n publicKey?: string;\n signedTransaction?: any;\n error?: string;\n }> {\n const { nearAccountId, credential, vrfChallenge, deviceNumber, deterministicVrfPublicKey } = args;\n const contractId = this.tatchiPasskeyConfigs.contractId;\n\n try {\n // Generate new session ID for this signing operation\n const sessionId = `device2-sign-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n\n // Retrieve encrypted key data and wrapKeySalt from IndexedDB\n const keyMaterial = await IndexedDBManager.nearKeysDB.getLocalKeyMaterial(\n nearAccountId,\n deviceNumber\n );\n if (!keyMaterial) {\n throw new Error(`No key material found for account ${nearAccountId} device ${deviceNumber}`);\n }\n\n const wrapKeySalt = keyMaterial.wrapKeySalt;\n if (!wrapKeySalt) {\n throw new Error(`Missing wrapKeySalt for account ${nearAccountId} device ${deviceNumber}`);\n }\n\n // === STEP 1: Create MessagePort session for WrapKeySeed delivery ===\n const signerPort = await this.vrfWorkerManager.createSigningSessionChannel(sessionId);\n await this.signerWorkerManager.reserveSignerWorkerSession(sessionId, { signerPort });\n\n // === STEP 2: VRF worker re-derives WrapKeySeed and sends to signer ===\n // This extracts PRF.second from the credential and delivers both WrapKeySeed + PRF.second\n // to the signer worker via MessagePort\n await this.vrfWorkerManager.mintSessionKeysAndSendToSigner({\n sessionId,\n wrapKeySalt,\n credential, // VRF will extract PRF.second from this\n });\n\n // === STEP 4: Get transaction context for registration ===\n const transactionContext = await this.nonceManager.getNonceBlockHashAndHeight(this.nearClient);\n\n // === STEP 5: Determine deterministic VRF public key ===\n // Try: provided parameter → authenticator table → fallback to ephemeral VRF from challenge\n let vrfPublicKey = deterministicVrfPublicKey;\n // Fallback to ephemeral VRF public key from challenge if still not found\n const finalVrfPublicKey = vrfPublicKey || vrfChallenge.vrfPublicKey;\n\n // === STEP 6: Signer worker signs registration transaction ===\n // WrapKeySeed and PRF.second are already in signer worker via MessagePort\n const signerResult = await this.signerWorkerManager.registerDevice2WithDerivedKey({\n sessionId,\n nearAccountId,\n credential,\n vrfChallenge,\n transactionContext,\n contractId,\n wrapKeySalt,\n deviceNumber,\n deterministicVrfPublicKey: finalVrfPublicKey,\n });\n\n return {\n success: true,\n publicKey: signerResult.publicKey,\n signedTransaction: signerResult.signedTransaction,\n };\n\n } catch (error: any) {\n console.error('[WebAuthnManager] Failed to sign Device2 registration with stored key:', error);\n return {\n success: false,\n error: error.message || String(error),\n };\n }\n }\n\n /**\n * Derive deterministic VRF keypair from PRF output for recovery\n * Optionally generates VRF challenge if input parameters are provided\n * This enables deterministic VRF key derivation from WebAuthn credentials\n *\n * @param credential - WebAuthn credential containing PRF outputs\n * @param nearAccountId - NEAR account ID for key derivation salt\n * @param vrfInputParams - Optional VRF inputs, if provided will generate a challenge\n * @param saveInMemory - Whether to save the derived VRF keypair in worker memory for immediate use\n * @returns Deterministic VRF public key, optional VRF challenge, and encrypted VRF keypair for storage\n */\n async deriveVrfKeypair({\n credential,\n nearAccountId,\n vrfInputData,\n saveInMemory = true,\n }: {\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n nearAccountId: AccountId;\n vrfInputData?: VRFInputData; // optional, for challenge generation\n saveInMemory?: boolean; // optional, whether to save in worker memory\n }): Promise<{\n success: boolean;\n vrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n vrfChallenge: VRFChallenge | null;\n serverEncryptedVrfKeypair: ServerEncryptedVrfKeypair | null;\n }> {\n try {\n const vrfResult = await this.vrfWorkerManager.deriveVrfKeypairFromPrf({\n credential,\n nearAccountId,\n vrfInputData,\n saveInMemory,\n });\n\n const result: {\n success: boolean;\n vrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n vrfChallenge: VRFChallenge | null;\n serverEncryptedVrfKeypair: ServerEncryptedVrfKeypair | null;\n } = {\n success: true,\n vrfPublicKey: vrfResult.vrfPublicKey,\n encryptedVrfKeypair: vrfResult.encryptedVrfKeypair,\n vrfChallenge: vrfResult.vrfChallenge,\n serverEncryptedVrfKeypair: vrfResult.serverEncryptedVrfKeypair,\n };\n\n return result;\n\n } catch (error: any) {\n console.error('WebAuthnManager: VRF keypair derivation error:', error);\n throw new Error(`VRF keypair derivation failed ${error.message}`);\n }\n }\n\n /**\n * Unlock VRF keypair in memory using PRF output\n * This is called during login to decrypt and load the VRF keypair in-memory\n */\n async unlockVRFKeypair({\n nearAccountId,\n encryptedVrfKeypair,\n credential,\n }: {\n nearAccountId: AccountId;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n credential: WebAuthnAuthenticationCredential | WebAuthnRegistrationCredential;\n }): Promise<{ success: boolean; error?: string }> {\n try {\n const unlockResult = await this.vrfWorkerManager.unlockVrfKeypair({\n credential,\n nearAccountId,\n encryptedVrfKeypair,\n });\n\n if (!unlockResult.success) {\n console.error('WebAuthnManager: VRF keypair unlock failed');\n return { success: false, error: 'VRF keypair unlock failed' };\n }\n\n // Warm up signer workers after a successful unlock to minimize first-use latency\n this.signerWorkerManager.preWarmWorkerPool().catch(() => { });\n\n return { success: true };\n\n } catch (error: any) {\n console.error('WebAuthnManager: VRF keypair unlock failed:', error.message);\n return { success: false, error: error.message };\n }\n }\n\n /**\n * Perform Shamir 3-pass commutative decryption within WASM worker\n * This securely decrypts a server-encrypted KEK (key encryption key)\n * which the wasm worker uses to unlock a key to decrypt the VRF keypair and loads it into memory\n * The server never knows the real value of the KEK, nor the VRF keypair\n */\n async shamir3PassDecryptVrfKeypair({\n nearAccountId,\n kek_s_b64u,\n ciphertextVrfB64u,\n serverKeyId,\n }: {\n nearAccountId: AccountId;\n kek_s_b64u: string;\n ciphertextVrfB64u: string;\n serverKeyId: string;\n }): Promise<{ success: boolean; error?: string }> {\n const result = await this.vrfWorkerManager.shamir3PassDecryptVrfKeypair({\n nearAccountId,\n kek_s_b64u,\n ciphertextVrfB64u,\n serverKeyId,\n });\n\n return {\n success: result.success,\n error: result.error\n };\n }\n\n /**\n * Shamir 3-pass: encrypt the unlocked VRF keypair under the server key\n * Returns a fresh blob to store in IndexedDB for future auto-login.\n */\n async shamir3PassEncryptCurrentVrfKeypair(): Promise<ServerEncryptedVrfKeypair> {\n const res = await this.vrfWorkerManager.shamir3PassEncryptCurrentVrfKeypair();\n return {\n ciphertextVrfB64u: res.ciphertextVrfB64u,\n kek_s_b64u: res.kek_s_b64u,\n serverKeyId: res.serverKeyId,\n };\n }\n\n /**\n * Persist refreshed server-encrypted VRF keypair in IndexedDB.\n */\n async updateServerEncryptedVrfKeypair(\n nearAccountId: AccountId,\n serverEncrypted: ServerEncryptedVrfKeypair\n ): Promise<void> {\n await IndexedDBManager.clientDB.updateUser(nearAccountId, {\n serverEncryptedVrfKeypair: {\n ciphertextVrfB64u: serverEncrypted.ciphertextVrfB64u,\n kek_s_b64u: serverEncrypted.kek_s_b64u,\n serverKeyId: serverEncrypted.serverKeyId,\n updatedAt: Date.now(),\n }\n });\n }\n\n async clearVrfSession(): Promise<void> {\n // In cross-origin dev, skip local worker init; wallet iframe handles PM_LOGOUT\n if (typeof window !== 'undefined' && this.workerBaseOrigin !== window.location.origin) {\n return;\n }\n return await this.vrfWorkerManager.clearVrfSession();\n }\n\n /**\n * Check VRF worker status\n */\n async checkVrfStatus(): Promise<{\n active: boolean;\n nearAccountId: AccountId | null;\n sessionDuration?: number\n }> {\n return this.vrfWorkerManager.checkVrfStatus();\n }\n\n /**\n * Mint/refresh a VRF-owned warm signing session using an already-collected WebAuthn credential.\n *\n * This is used to avoid a second TouchID prompt during login flows when we already\n * performed an authentication ceremony (e.g., to unlock the VRF keypair).\n *\n * Notes:\n * - This method does not initiate a WebAuthn prompt.\n * - Contract verification is optional and only performed when `contractId` + `nearRpcUrl` are provided.\n */\n\t async mintSigningSessionFromCredential(args: {\n\t nearAccountId: AccountId;\n\t credential: WebAuthnAuthenticationCredential;\n\t remainingUses?: number;\n\t ttlMs?: number;\n\t contractId?: string;\n\t nearRpcUrl?: string;\n\t }): Promise<{\n\t sessionId: string;\n\t status: 'active' | 'exhausted' | 'expired' | 'not_found';\n\t remainingUses?: number;\n\t expiresAtMs?: number;\n\t createdAtMs?: number;\n\t }> {\n\t const nearAccountId = toAccountId(args.nearAccountId);\n\t const sessionId = this.getOrCreateActiveSigningSessionId(nearAccountId);\n\n\t // Ensure VRF keypair is active and bound to the same account.\n\t const vrfStatus = await this.vrfWorkerManager.checkVrfStatus();\n\t if (!vrfStatus.active) {\n\t throw new Error('VRF keypair not active in memory. Please log in again.');\n\t }\n\t if (!vrfStatus.nearAccountId || String(vrfStatus.nearAccountId) !== String(nearAccountId)) {\n\t throw new Error('VRF keypair active but bound to a different account. Please log in again.');\n\t }\n\n\t const credentialRawId = String(args.credential?.rawId || '').trim();\n\t const authenticators = await this.getAuthenticatorsByUser(nearAccountId).catch(() => []);\n\n\t // Fetch wrapKeySalt from vault so the derived WrapKeySeed can decrypt the stored NEAR keys.\n\t let deviceNumber: number;\n\t try {\n\t deviceNumber = await getLastLoggedInDeviceNumber(nearAccountId, IndexedDBManager.clientDB);\n\t } catch (err) {\n\t // Fallback: if lastUser was not set (e.g., cross-origin flows), infer the deviceNumber\n\t // from the credential rawId so we can still mint a session for the selected passkey.\n\t if (credentialRawId) {\n\t const matched = authenticators.find((a) => a.credentialId === credentialRawId);\n\t const inferred =\n\t matched && typeof matched.deviceNumber === 'number' && Number.isFinite(matched.deviceNumber)\n\t ? matched.deviceNumber\n\t : null;\n\t if (inferred !== null) {\n\t deviceNumber = inferred;\n\t // Best-effort: align lastUser to the passkey that was actually used.\n\t await this.setLastUser(nearAccountId, inferred).catch(() => undefined);\n\t } else {\n\t throw err;\n\t }\n\t } else {\n\t throw err;\n\t }\n\t }\n\n\t // If multiple passkeys exist, ensure the credential used for session minting matches\n\t // the currently selected/last-user device. This avoids deriving a WrapKeySeed that\n\t // cannot decrypt the expected vault entry.\n\t if (credentialRawId && authenticators.length > 1) {\n\t const { wrongPasskeyError } = await IndexedDBManager.clientDB.ensureCurrentPasskey(\n\t nearAccountId,\n\t authenticators,\n\t credentialRawId,\n\t );\n\t if (wrongPasskeyError) {\n\t throw new Error(wrongPasskeyError);\n\t }\n\t }\n\n\t const keyMaterial = await IndexedDBManager.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber);\n\t if (!keyMaterial) {\n\t throw new Error(`No key material found for account ${nearAccountId} device ${deviceNumber}`);\n\t }\n\t const wrapKeySalt = keyMaterial.wrapKeySalt;\n if (!wrapKeySalt) {\n throw new Error('Missing wrapKeySalt in vault; re-register to upgrade vault format.');\n }\n\n // Extract PRF.first_auth from the already-collected credential.\n const { ttlMs, remainingUses } = this.resolveSigningSessionPolicy(args);\n\n await this.vrfWorkerManager.mintSessionKeysAndSendToSigner({\n sessionId,\n wrapKeySalt,\n contractId: args.contractId,\n nearRpcUrl: args.nearRpcUrl,\n ttlMs,\n remainingUses,\n credential: args.credential,\n });\n\n return await this.vrfWorkerManager.checkSessionStatus({ sessionId });\n }\n\n /**\n * Introspect the VRF-owned signing session for UI (no prompt, metadata only).\n * Session usage (`remainingUses`) is decremented on `DISPENSE_SESSION_KEY` calls.\n */\n async getWarmSigningSessionStatus(nearAccountId: AccountId): Promise<{\n sessionId: string;\n status: 'active' | 'exhausted' | 'expired' | 'not_found';\n remainingUses?: number;\n expiresAtMs?: number;\n createdAtMs?: number;\n }> {\n const sessionId = this.getOrCreateActiveSigningSessionId(nearAccountId);\n return await this.vrfWorkerManager.checkSessionStatus({ sessionId });\n }\n\n /**\n * Fetch Shamir server key info to support proactive refresh.\n */\n async getShamirKeyInfo(): Promise<{\n currentKeyId: string | null;\n p_b64u: string | null;\n graceKeyIds?: string[]\n } | null> {\n try {\n const relayUrl = this.tatchiPasskeyConfigs?.vrfWorkerConfigs?.shamir3pass?.relayServerUrl;\n if (!relayUrl) return null;\n const res = await fetch(`${relayUrl}/shamir/key-info`, { method: 'GET' });\n if (!res.ok) return null;\n const data = await res.json();\n return {\n currentKeyId: data?.currentKeyId ?? null,\n p_b64u: data?.p_b64u ?? null,\n graceKeyIds: Array.isArray(data?.graceKeyIds) ? data.graceKeyIds : undefined,\n };\n } catch {\n return null;\n }\n }\n\n /**\n * If server key changed and VRF is unlocked in memory, re-encrypt under the new server key.\n * Returns true if refreshed, false otherwise.\n */\n async maybeProactiveShamirRefresh(nearAccountId: AccountId): Promise<boolean> {\n try {\n const relayUrl = this.tatchiPasskeyConfigs?.vrfWorkerConfigs?.shamir3pass?.relayServerUrl;\n if (!relayUrl) return false;\n const userData = await this.getLastUser();\n const stored = userData?.serverEncryptedVrfKeypair;\n if (!stored || !stored.kek_s_b64u || !stored.ciphertextVrfB64u || !stored.serverKeyId) return false;\n\n const keyInfo = await this.getShamirKeyInfo();\n const currentKeyId = keyInfo?.currentKeyId;\n if (!currentKeyId || currentKeyId === stored.serverKeyId) return false;\n\n const status = await this.checkVrfStatus();\n const active = status.active && status.nearAccountId === nearAccountId;\n if (!active) return false;\n\n const refreshed = await this.shamir3PassEncryptCurrentVrfKeypair();\n await this.updateServerEncryptedVrfKeypair(nearAccountId, refreshed);\n return true;\n } catch {\n return false;\n }\n }\n\n ///////////////////////////////////////\n // INDEXEDDB OPERATIONS\n ///////////////////////////////////////\n\n async storeUserData(userData: StoreUserDataInput): Promise<void> {\n await IndexedDBManager.clientDB.storeWebAuthnUserData({\n ...userData,\n deviceNumber: userData.deviceNumber ?? 1,\n version: userData.version || 2,\n });\n }\n\n async getAllUsers(): Promise<ClientUserData[]> {\n return await IndexedDBManager.clientDB.getAllUsers();\n }\n\n async getUserByDevice(nearAccountId: AccountId, deviceNumber: number): Promise<ClientUserData | null> {\n return await IndexedDBManager.clientDB.getUserByDevice(nearAccountId, deviceNumber);\n }\n\n async getLastUser(): Promise<ClientUserData | null> {\n return await IndexedDBManager.clientDB.getLastUser();\n }\n\n async getAuthenticatorsByUser(nearAccountId: AccountId): Promise<ClientAuthenticatorData[]> {\n return await IndexedDBManager.clientDB.getAuthenticatorsByUser(nearAccountId);\n }\n\n async updateLastLogin(nearAccountId: AccountId): Promise<void> {\n return await IndexedDBManager.clientDB.updateLastLogin(nearAccountId);\n }\n\n /**\n * Set the last logged-in user\n * @param nearAccountId - The account ID of the user\n * @param deviceNumber - The device number (defaults to 1)\n */\n async setLastUser(nearAccountId: AccountId, deviceNumber: number = 1): Promise<void> {\n return await IndexedDBManager.clientDB.setLastUser(nearAccountId, deviceNumber);\n }\n\n\n /**\n * Initialize current user authentication state\n * This should be called after VRF keypair is successfully unlocked in memory\n * to ensure the user is properly logged in and can perform transactions\n *\n * @param nearAccountId - The NEAR account ID to initialize\n * @param nearClient - The NEAR client for nonce prefetching\n */\n async initializeCurrentUser(\n nearAccountId: AccountId,\n nearClient?: NearClient,\n ): Promise<void> {\n const accountId = toAccountId(nearAccountId);\n\n // Set as last user for future sessions, preserving the current deviceNumber\n // when it is already known for this account.\n let deviceNumberToUse: number | null = null;\n const lastUser = await IndexedDBManager.clientDB.getLastUser().catch(() => null);\n if (\n lastUser &&\n toAccountId(lastUser.nearAccountId) === accountId &&\n Number.isFinite(lastUser.deviceNumber)\n ) {\n deviceNumberToUse = lastUser.deviceNumber;\n }\n\n if (deviceNumberToUse === null) {\n const userForAccount = await IndexedDBManager.clientDB\n .getUserByDevice(accountId, 1)\n .catch(() => null);\n if (userForAccount && Number.isFinite(userForAccount.deviceNumber)) {\n deviceNumberToUse = userForAccount.deviceNumber;\n }\n }\n\n if (deviceNumberToUse === null) {\n deviceNumberToUse = 1;\n }\n\n await this.setLastUser(accountId, deviceNumberToUse);\n\n // Set as current user for immediate use\n this.userPreferencesManager.setCurrentUser(accountId);\n // Ensure confirmation preferences are loaded before callers read them (best-effort)\n await this.userPreferencesManager.reloadUserSettings().catch(() => undefined);\n\n // Initialize NonceManager with the selected user's public key (best-effort)\n const userData = await IndexedDBManager.clientDB\n .getUserByDevice(accountId, deviceNumberToUse)\n .catch(() => null);\n if (userData && userData.clientNearPublicKey) {\n this.nonceManager.initializeUser(accountId, userData.clientNearPublicKey);\n }\n\n // Prefetch block height for better UX (non-fatal if it fails and nearClient is provided)\n if (nearClient) {\n await this.nonceManager\n .prefetchBlockheight(nearClient)\n .catch((prefetchErr) => console.debug('Nonce prefetch after authentication state initialization failed (non-fatal):', prefetchErr));\n }\n }\n\n async registerUser(storeUserData: StoreUserDataInput): Promise<ClientUserData> {\n return await IndexedDBManager.clientDB.registerUser(storeUserData);\n }\n\n async storeAuthenticator(authenticatorData: {\n credentialId: string;\n credentialPublicKey: Uint8Array;\n transports?: string[];\n name?: string;\n nearAccountId: AccountId;\n registered: string;\n syncedAt: string;\n vrfPublicKey: string;\n deviceNumber?: number;\n }): Promise<void> {\n const deviceNumber = Number(authenticatorData.deviceNumber);\n const normalizedDeviceNumber = Number.isSafeInteger(deviceNumber) && deviceNumber >= 1 ? deviceNumber : 1;\n const authData = {\n ...authenticatorData,\n nearAccountId: toAccountId(authenticatorData.nearAccountId),\n deviceNumber: normalizedDeviceNumber, // Default to device 1 (1-indexed)\n };\n return await IndexedDBManager.clientDB.storeAuthenticator(authData);\n }\n\n extractUsername(nearAccountId: AccountId): string {\n return IndexedDBManager.clientDB.extractUsername(nearAccountId);\n }\n\n async atomicOperation<T>(callback: (db: any) => Promise<T>): Promise<T> {\n return await IndexedDBManager.clientDB.atomicOperation(callback);\n }\n\n async rollbackUserRegistration(nearAccountId: AccountId): Promise<void> {\n return await IndexedDBManager.clientDB.rollbackUserRegistration(nearAccountId);\n }\n\n async hasPasskeyCredential(nearAccountId: AccountId): Promise<boolean> {\n return await IndexedDBManager.clientDB.hasPasskeyCredential(nearAccountId);\n }\n\n /**\n * Atomically store all registration data (user, authenticator, VRF credentials)\n */\n async atomicStoreRegistrationData({\n nearAccountId,\n credential,\n publicKey,\n encryptedVrfKeypair,\n vrfPublicKey,\n serverEncryptedVrfKeypair,\n }: {\n nearAccountId: AccountId;\n credential: WebAuthnRegistrationCredential;\n publicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n vrfPublicKey: string;\n serverEncryptedVrfKeypair: ServerEncryptedVrfKeypair | null;\n }): Promise<void> {\n await this.atomicOperation(async (db) => {\n // Store credential for authentication\n const credentialId: string = credential.rawId;\n const attestationB64u: string = credential.response.attestationObject;\n const transports: string[] = credential.response?.transports;\n\n await this.storeAuthenticator({\n nearAccountId: nearAccountId,\n credentialId: credentialId,\n credentialPublicKey: await this.extractCosePublicKey(attestationB64u),\n transports,\n name: `VRF Passkey for ${this.extractUsername(nearAccountId)}`,\n registered: new Date().toISOString(),\n syncedAt: new Date().toISOString(),\n vrfPublicKey: vrfPublicKey,\n });\n\n // Store WebAuthn user data with encrypted VRF credentials\n await this.storeUserData({\n nearAccountId,\n deviceNumber: 1,\n clientNearPublicKey: publicKey,\n lastUpdated: Date.now(),\n passkeyCredential: {\n id: credential.id,\n rawId: credentialId\n },\n encryptedVrfKeypair: {\n encryptedVrfDataB64u: encryptedVrfKeypair.encryptedVrfDataB64u,\n chacha20NonceB64u: encryptedVrfKeypair.chacha20NonceB64u,\n },\n version: 2,\n serverEncryptedVrfKeypair: serverEncryptedVrfKeypair ? {\n ciphertextVrfB64u: serverEncryptedVrfKeypair?.ciphertextVrfB64u,\n kek_s_b64u: serverEncryptedVrfKeypair?.kek_s_b64u,\n serverKeyId: serverEncryptedVrfKeypair?.serverKeyId,\n updatedAt: Date.now(),\n } : undefined,\n });\n\n return true;\n });\n }\n\n ///////////////////////////////////////\n // SIGNER WASM WORKER OPERATIONS\n ///////////////////////////////////////\n\n /**\n * Transaction signing with contract verification and progress updates.\n * Demonstrates the \"streaming\" worker pattern similar to SSE.\n *\n * Requires a successful TouchID/biometric prompt before transaction signing in wasm worker\n * Automatically verifies the authentication with the web3authn contract.\n *\n * @param transactions - Transaction payload containing:\n * - receiverId: NEAR account ID receiving the transaction\n * - actions: Array of NEAR actions to execute\n * @param rpcCall: RpcCallPayload containing:\n * - contractId: Web3Authn contract ID for verification\n * - nearRpcUrl: NEAR RPC endpoint URL\n * - nearAccountId: NEAR account ID performing the transaction\n * @param confirmationConfigOverride: Optional confirmation configuration override\n * @param onEvent: Optional callback for progress updates during signing\n * @param onEvent - Optional callback for progress updates during signing\n */\n async signTransactionsWithActions({\n transactions,\n rpcCall,\n signerMode,\n confirmationConfigOverride,\n title,\n body,\n onEvent,\n }: {\n transactions: TransactionInputWasm[],\n rpcCall: RpcCallPayload,\n signerMode: SignerMode;\n // Accept partial override; merging happens in handlers layer\n confirmationConfigOverride?: Partial<ConfirmationConfig>,\n title?: string;\n body?: string;\n onEvent?: (update: onProgressEvents) => void,\n }): Promise<SignTransactionResult[]> {\n return this.withSigningSession({\n sessionId: this.getOrCreateActiveSigningSessionId(toAccountId(rpcCall.nearAccountId)),\n handler: (sessionId) =>\n this.signerWorkerManager.signTransactionsWithActions({\n transactions,\n rpcCall,\n signerMode,\n confirmationConfigOverride,\n title,\n body,\n onEvent,\n sessionId,\n }),\n });\n }\n\n /**\n * Sign AddKey(thresholdPublicKey) for `receiverId === nearAccountId` without running confirmTxFlow.\n *\n * This is a narrowly-scoped, internal-only helper for post-registration activation flows where\n * the caller already has a PRF-bearing credential in memory (e.g., immediately after registration)\n * and wants to avoid an extra TouchID/WebAuthn prompt.\n */\n async signAddKeyThresholdPublicKeyNoPrompt(args: {\n nearAccountId: AccountId | string;\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n wrapKeySalt: string;\n transactionContext: TransactionContext;\n thresholdPublicKey: string;\n relayerVerifyingShareB64u: string;\n clientParticipantId?: number;\n relayerParticipantId?: number;\n deviceNumber?: number;\n onEvent?: (update: onProgressEvents) => void;\n }): Promise<SignTransactionResult> {\n const nearAccountId = toAccountId(args.nearAccountId);\n const wrapKeySalt = args.wrapKeySalt;\n if (!wrapKeySalt) throw new Error('Missing wrapKeySalt for AddKey(thresholdPublicKey) signing');\n if (!args.credential) throw new Error('Missing credential for AddKey(thresholdPublicKey) signing');\n if (!args.transactionContext) throw new Error('Missing transactionContext for no-prompt signing');\n const thresholdPublicKey = ensureEd25519Prefix(args.thresholdPublicKey);\n if (!thresholdPublicKey) throw new Error('Missing thresholdPublicKey for AddKey(thresholdPublicKey) signing');\n const relayerVerifyingShareB64u = args.relayerVerifyingShareB64u;\n if (!relayerVerifyingShareB64u) throw new Error('Missing relayerVerifyingShareB64u for AddKey(thresholdPublicKey) signing');\n\n const deviceNumber = Number(args.deviceNumber);\n const resolvedDeviceNumber = Number.isSafeInteger(deviceNumber) && deviceNumber >= 1\n ? deviceNumber\n : await getLastLoggedInDeviceNumber(nearAccountId, IndexedDBManager.clientDB).catch(() => 1);\n\n const localKeyMaterial = await IndexedDBManager.nearKeysDB.getLocalKeyMaterial(\n nearAccountId,\n resolvedDeviceNumber,\n );\n if (!localKeyMaterial) {\n throw new Error(`No local key material found for account ${nearAccountId} device ${resolvedDeviceNumber}`);\n }\n\n if (localKeyMaterial.wrapKeySalt !== wrapKeySalt) {\n throw new Error('wrapKeySalt mismatch for AddKey(thresholdPublicKey) signing');\n }\n\n return await this.withSigningSession({\n prefix: 'no-prompt-add-threshold-key',\n options: { credential: args.credential, wrapKeySalt },\n handler: async (sessionId) => {\n const response = await this.signerWorkerManager.getContext().sendMessage({\n sessionId,\n message: {\n type: INTERNAL_WORKER_REQUEST_TYPE_SIGN_ADD_KEY_THRESHOLD_PUBLIC_KEY_NO_PROMPT,\n payload: {\n createdAt: Date.now(),\n decryption: {\n encryptedPrivateKeyData: localKeyMaterial.encryptedSk,\n encryptedPrivateKeyChacha20NonceB64u: localKeyMaterial.chacha20NonceB64u,\n },\n transactionContext: args.transactionContext,\n nearAccountId,\n thresholdPublicKey,\n relayerVerifyingShareB64u,\n clientParticipantId: typeof args.clientParticipantId === 'number' ? args.clientParticipantId : undefined,\n relayerParticipantId: typeof args.relayerParticipantId === 'number' ? args.relayerParticipantId : undefined,\n },\n },\n onEvent: args.onEvent,\n });\n\n if (!isSignAddKeyThresholdPublicKeyNoPromptSuccess(response)) {\n throw new Error('AddKey(thresholdPublicKey) signing failed');\n }\n if (!response.payload.success) {\n throw new Error(response.payload.error || 'AddKey(thresholdPublicKey) signing failed');\n }\n\n const signedTransactions = response.payload.signedTransactions || [];\n if (signedTransactions.length !== 1) {\n throw new Error(`Expected 1 signed transaction but received ${signedTransactions.length}`);\n }\n\n const signedTx = signedTransactions[0];\n if (!signedTx || !(signedTx as any).transaction || !(signedTx as any).signature) {\n throw new Error('Incomplete signed transaction data received for AddKey(thresholdPublicKey)');\n }\n return {\n signedTransaction: new SignedTransaction({\n transaction: (signedTx as any).transaction,\n signature: (signedTx as any).signature,\n borsh_bytes: Array.from((signedTx as any).borshBytes || []),\n }),\n nearAccountId: String(nearAccountId),\n logs: response.payload.logs || [],\n };\n },\n });\n }\n\n async signDelegateAction({\n delegate,\n rpcCall,\n signerMode,\n confirmationConfigOverride,\n title,\n body,\n onEvent,\n }: {\n delegate: DelegateActionInput;\n rpcCall: RpcCallPayload;\n signerMode: SignerMode;\n // Accept partial override; merging happens in handlers layer\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n title?: string;\n body?: string;\n onEvent?: (update: onProgressEvents) => void;\n }): Promise<{\n signedDelegate: WasmSignedDelegate;\n hash: string;\n nearAccountId: AccountId;\n logs?: string[];\n }> {\n const nearAccountId = toAccountId(rpcCall.nearAccountId || delegate.senderId);\n const normalizedRpcCall: RpcCallPayload = {\n contractId: rpcCall.contractId || this.tatchiPasskeyConfigs.contractId,\n nearRpcUrl: rpcCall.nearRpcUrl || this.tatchiPasskeyConfigs.nearRpcUrl,\n nearAccountId,\n };\n\n try {\n const activeSessionId = this.getOrCreateActiveSigningSessionId(nearAccountId);\n return await this.withSigningSession({\n sessionId: activeSessionId,\n handler: (sessionId) => {\n console.debug('[WebAuthnManager][delegate] session created', { sessionId });\n return this.signerWorkerManager.signDelegateAction({\n delegate,\n rpcCall: normalizedRpcCall,\n signerMode,\n confirmationConfigOverride,\n title,\n body,\n onEvent,\n sessionId,\n });\n }\n });\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('[WebAuthnManager][delegate] failed', err);\n throw err;\n }\n }\n\n async signNEP413Message(payload: {\n message: string;\n recipient: string;\n nonce: string;\n state: string | null;\n accountId: AccountId;\n signerMode: SignerMode;\n title?: string;\n body?: string;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n }): Promise<{\n success: boolean;\n accountId: string;\n publicKey: string;\n signature: string;\n state?: string;\n error?: string;\n }> {\n try {\n const activeSessionId = this.getOrCreateActiveSigningSessionId(payload.accountId);\n const contractId = this.tatchiPasskeyConfigs.contractId;\n const nearRpcUrl = (this.tatchiPasskeyConfigs.nearRpcUrl.split(',')[0] || this.tatchiPasskeyConfigs.nearRpcUrl);\n const result = await this.withSigningSession({\n sessionId: activeSessionId,\n handler: (sessionId) =>\n this.signerWorkerManager.signNep413Message({ ...payload, sessionId, contractId, nearRpcUrl }),\n });\n if (result.success) {\n return result;\n } else {\n throw new Error(`NEP-413 signing failed: ${result.error || 'Unknown error'}`);\n }\n } catch (error: any) {\n console.error('WebAuthnManager: NEP-413 signing error:', error);\n return {\n success: false,\n accountId: '',\n publicKey: '',\n signature: '',\n error: error.message || 'Unknown error'\n };\n }\n }\n\n // === COSE OPERATIONS ===\n\n /**\n * Extract COSE public key from WebAuthn attestation object using WASM worker\n */\n async extractCosePublicKey(attestationObjectBase64url: string): Promise<Uint8Array> {\n return await this.signerWorkerManager.extractCosePublicKey(attestationObjectBase64url);\n }\n\n ///////////////////////////////////////\n // PRIVATE KEY EXPORT (Drawer/Modal in sandboxed iframe)\n ///////////////////////////////////////\n\n /** Worker-driven export: two-phase V2 (collect PRF → decrypt → show UI) */\n async exportNearKeypairWithUIWorkerDriven(\n nearAccountId: AccountId,\n options?: { variant?: 'drawer' | 'modal', theme?: 'dark' | 'light' }\n ): Promise<void> {\n await this.withSigningSession({\n prefix: 'export-session', handler: async (sessionId) => {\n // Phase 1: collect PRF via LocalOnly(DECRYPT_PRIVATE_KEY_WITH_PRF) inside VRF worker\n // and derive WrapKeySeed with the vault-provided wrapKeySalt.\n await this.confirmDecryptAndDeriveWrapKeySeed({ nearAccountId, sessionId });\n\n // Phase 2 + 3: decrypt inside signer worker using the reserved session,\n // then show the export viewer UI.\n return this.signerWorkerManager.exportNearKeypairUi({\n nearAccountId,\n variant: options?.variant,\n theme: options?.theme,\n sessionId,\n });\n }\n });\n }\n\n async exportNearKeypairWithUI(\n nearAccountId: AccountId,\n options?: {\n variant?: 'drawer' | 'modal';\n theme?: 'dark' | 'light'\n }\n ): Promise<{ accountId: string; publicKey: string; privateKey: string }> {\n // Route to worker-driven two-phase flow. UI is shown inside the wallet host; no secrets are returned.\n await this.exportNearKeypairWithUIWorkerDriven(nearAccountId, options);\n // Surface the freshest device key for this account to the caller.\n // Prefer last user when it matches the account, else pick the most recently\n // updated user record for this account.\n let userData = await this.getLastUser();\n if (!userData || userData.nearAccountId !== nearAccountId) {\n userData = await IndexedDBManager.clientDB.getLastDBUpdatedUser(nearAccountId);\n }\n return {\n accountId: String(nearAccountId),\n publicKey: userData?.clientNearPublicKey ?? '',\n privateKey: '',\n };\n }\n\n ///////////////////////////////////////\n // REGISTRATION\n ///////////////////////////////////////\n\n async checkCanRegisterUser({\n contractId,\n credential,\n vrfChallenge,\n authenticatorOptions,\n onEvent,\n }: {\n contractId: string,\n credential: WebAuthnRegistrationCredential,\n vrfChallenge: VRFChallenge,\n authenticatorOptions?: AuthenticatorOptions;\n onEvent?: (update: RegistrationEventStep3) => void\n }): Promise<{\n success: boolean;\n verified?: boolean;\n registrationInfo?: any;\n logs?: string[];\n signedTransactionBorsh?: number[];\n error?: string;\n }> {\n return await this.signerWorkerManager.checkCanRegisterUser({\n contractId,\n credential,\n vrfChallenge,\n authenticatorOptions,\n onEvent,\n nearRpcUrl: this.tatchiPasskeyConfigs.nearRpcUrl,\n });\n }\n\n ///////////////////////////////////////\n // ACCOUNT RECOVERY\n ///////////////////////////////////////\n\n /**\n * Recover keypair from authentication credential for account recovery\n * Uses dual PRF outputs to re-derive the same NEAR keypair and re-encrypt it\n * @param challenge - Random challenge for WebAuthn authentication ceremony\n * @param authenticationCredential - The authentication credential with dual PRF outputs\n * @param accountIdHint - Optional account ID hint for recovery\n * @returns Public key and encrypted private key for secure storage\n */\n async recoverKeypairFromPasskey(\n authenticationCredential: WebAuthnAuthenticationCredential,\n accountIdHint?: string,\n ): Promise<{\n publicKey: string;\n encryptedPrivateKey: string;\n /**\n * Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for the encrypted private key.\n */\n chacha20NonceB64u: string;\n accountIdHint?: string;\n wrapKeySalt: string;\n stored?: boolean;\n }> {\n try {\n // Verify we have an authentication credential (not registration)\n if (!authenticationCredential) {\n throw new Error(\n 'Authentication credential required for account recovery. ' +\n 'Use an existing credential with dual PRF outputs to re-derive the same NEAR keypair.'\n );\n }\n\n // Verify dual PRF outputs are available\n const prfResults = authenticationCredential.clientExtensionResults?.prf?.results;\n if (!prfResults?.first || !prfResults?.second) {\n throw new Error('Dual PRF outputs required for account recovery - both AES and Ed25519 PRF outputs must be available');\n }\n\n // Extract PRF.first for WrapKeySeed derivation\n // Orchestrate a VRF-owned signing session with WrapKeySeed derivation, then ask\n // the signer to recover and re-encrypt the NEAR keypair.\n const result = await this.withSigningSession({\n prefix: 'recover',\n options: { credential: authenticationCredential },\n handler: (sessionId) =>\n this.signerWorkerManager.recoverKeypairFromPasskey({\n credential: authenticationCredential,\n accountIdHint,\n sessionId,\n }),\n });\n return result;\n\n } catch (error: any) {\n console.error('WebAuthnManager: Deterministic keypair derivation error:', error);\n throw new Error(`Deterministic keypair derivation failed: ${error.message}`);\n }\n }\n\n async getAuthenticationCredentialsSerializedDualPrf({\n nearAccountId,\n challenge,\n credentialIds,\n }: {\n nearAccountId: AccountId;\n challenge: VRFChallenge,\n credentialIds: string[];\n }): Promise<WebAuthnAuthenticationCredential> {\n // Same as getAuthenticationCredentialsSerialized but returns both PRF outputs (PRF.first + PRF.second).\n return this.touchIdPrompt.getAuthenticationCredentialsSerializedDualPrf({\n nearAccountId,\n challenge,\n allowCredentials: credentialIds.map(id => ({\n id: id,\n type: 'public-key',\n transports: ['internal', 'hybrid', 'usb', 'ble'] as AuthenticatorTransport[]\n })),\n });\n }\n\n /**\n * Sign transaction with raw private key\n * for key replacement in device linking\n * No TouchID/PRF required - uses provided private key directly\n */\n async signTransactionWithKeyPair({\n nearPrivateKey,\n signerAccountId,\n receiverId,\n nonce,\n blockHash,\n actions\n }: {\n nearPrivateKey: string;\n signerAccountId: string;\n receiverId: string;\n nonce: string;\n blockHash: string;\n actions: ActionArgsWasm[];\n }): Promise<{\n signedTransaction: SignedTransaction;\n logs?: string[];\n }> {\n return await this.signerWorkerManager.signTransactionWithKeyPair({\n nearPrivateKey,\n signerAccountId,\n receiverId,\n nonce,\n blockHash,\n actions\n });\n }\n\n // ==============================\n // Threshold Signing\n // ==============================\n\n /**\n * Derive the deterministic threshold client verifying share (2-of-2 ed25519) from WrapKeySeed.\n * This is safe to call during registration because it only requires the PRF-bearing credential\n * (no on-chain verification needed) and returns public material only.\n */\n async deriveThresholdEd25519ClientVerifyingShareFromCredential(args: {\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n nearAccountId: AccountId | string;\n wrapKeySalt?: string;\n }): Promise<{\n success: boolean;\n nearAccountId: string;\n clientVerifyingShareB64u: string;\n wrapKeySalt: string;\n error?: string;\n }> {\n const nearAccountId = toAccountId(args.nearAccountId);\n try {\n return await this.withSigningSession({\n prefix: 'threshold-client-share',\n options: { credential: args.credential, wrapKeySalt: args.wrapKeySalt },\n handler: (sessionId) =>\n this.signerWorkerManager.deriveThresholdEd25519ClientVerifyingShare({\n sessionId,\n nearAccountId,\n }),\n });\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return {\n success: false,\n nearAccountId,\n clientVerifyingShareB64u: '',\n wrapKeySalt: '',\n error: message,\n };\n }\n }\n\n /**\n * Threshold key enrollment (post-registration):\n * prompts for a dual-PRF WebAuthn authentication to obtain PRF.first/second,\n * then runs the `/threshold-ed25519/keygen` enrollment flow.\n *\n * This is intended to be called only after the passkey is registered on-chain.\n */\n async enrollThresholdEd25519KeyPostRegistration(args: {\n nearAccountId: AccountId | string;\n deviceNumber?: number;\n }): Promise<{\n success: boolean;\n publicKey: string;\n relayerKeyId: string;\n wrapKeySalt: string;\n error?: string;\n }> {\n const nearAccountId = toAccountId(args.nearAccountId);\n\n try {\n const rpId = this.touchIdPrompt.getRpId();\n if (!rpId) throw new Error('Missing rpId for WebAuthn VRF challenge');\n\n // Generate a fresh VRF challenge for a dual-PRF authentication prompt (PRF.first + PRF.second).\n const block = await this.nearClient.viewBlock({ finality: 'final' } as any);\n const blockHeight = String((block as any)?.header?.height ?? '');\n const blockHash = String((block as any)?.header?.hash ?? '');\n if (!blockHeight || !blockHash) throw new Error('Failed to fetch NEAR block context for VRF challenge');\n\n const vrfChallenge = await this.vrfWorkerManager.generateVrfChallengeOnce({\n userId: nearAccountId,\n rpId,\n blockHeight,\n blockHash,\n });\n\n const authenticators = await this.getAuthenticatorsByUser(nearAccountId);\n if (!authenticators.length) {\n throw new Error(`No passkey authenticators found for account ${nearAccountId}`);\n }\n\n const authCredential = await this.collectAuthenticationCredentialForVrfChallenge({\n nearAccountId,\n vrfChallenge,\n includeSecondPrfOutput: true,\n });\n\n return await this.enrollThresholdEd25519Key({\n credential: authCredential,\n nearAccountId,\n deviceNumber: args.deviceNumber,\n });\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return { success: false, publicKey: '', relayerKeyId: '', wrapKeySalt: '', error: message };\n }\n }\n\n /**\n * Threshold key rotation (post-registration):\n * - keygen (new relayerKeyId + publicKey)\n * - AddKey(new threshold publicKey)\n * - DeleteKey(old threshold publicKey)\n *\n * Uses the local signer key for AddKey/DeleteKey, and requires the account to already\n * have a stored `threshold_ed25519_2p_v1` key material entry for the target device.\n */\n async rotateThresholdEd25519KeyPostRegistration(args: {\n nearAccountId: AccountId | string;\n deviceNumber?: number;\n }): Promise<{\n success: boolean;\n oldPublicKey: string;\n oldRelayerKeyId: string;\n publicKey: string;\n relayerKeyId: string;\n wrapKeySalt: string;\n deleteOldKeyAttempted: boolean;\n deleteOldKeySuccess: boolean;\n warning?: string;\n error?: string;\n }> {\n const nearAccountId = toAccountId(args.nearAccountId);\n\n let oldPublicKey = '';\n let oldRelayerKeyId = '';\n\n try {\n const deviceNumber = Number(args.deviceNumber);\n const resolvedDeviceNumber = Number.isSafeInteger(deviceNumber) && deviceNumber >= 1\n ? deviceNumber\n : await getLastLoggedInDeviceNumber(nearAccountId, IndexedDBManager.clientDB).catch(() => 1);\n\n const existing = await IndexedDBManager.nearKeysDB.getThresholdKeyMaterial(nearAccountId, resolvedDeviceNumber);\n if (!existing) {\n throw new Error(\n `No threshold key material found for account ${nearAccountId} device ${resolvedDeviceNumber}. Call enrollThresholdEd25519Key() first.`,\n );\n }\n oldPublicKey = existing.publicKey;\n oldRelayerKeyId = existing.relayerKeyId;\n\n const enrollment = await this.enrollThresholdEd25519KeyPostRegistration({\n nearAccountId,\n deviceNumber: resolvedDeviceNumber,\n });\n if (!enrollment.success) {\n throw new Error(enrollment.error || 'Threshold keygen/enrollment failed');\n }\n\n return await rotateThresholdEd25519KeyPostRegistrationHandler(\n {\n nearClient: this.nearClient,\n contractId: this.tatchiPasskeyConfigs.contractId,\n nearRpcUrl: this.tatchiPasskeyConfigs.nearRpcUrl,\n signTransactionsWithActions: (params) => this.signTransactionsWithActions(params),\n },\n {\n nearAccountId,\n deviceNumber: resolvedDeviceNumber,\n oldPublicKey,\n oldRelayerKeyId,\n newPublicKey: enrollment.publicKey,\n newRelayerKeyId: enrollment.relayerKeyId,\n wrapKeySalt: enrollment.wrapKeySalt,\n },\n );\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return {\n success: false,\n oldPublicKey,\n oldRelayerKeyId,\n publicKey: '',\n relayerKeyId: '',\n wrapKeySalt: '',\n deleteOldKeyAttempted: false,\n deleteOldKeySuccess: false,\n error: message,\n };\n }\n }\n\n /**\n * Threshold key enrollment (2-of-2): deterministically derive the client verifying share\n * from WrapKeySeed and register the corresponding relayer share via `/threshold-ed25519/keygen`.\n *\n * Stores a v3 vault entry of kind `threshold_ed25519_2p_v1` (breaking; no migration).\n */\n async enrollThresholdEd25519Key(args: {\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n nearAccountId: AccountId | string;\n deviceNumber?: number;\n }): Promise<{\n success: boolean;\n publicKey: string;\n relayerKeyId: string;\n wrapKeySalt: string;\n error?: string;\n }> {\n const nearAccountId = toAccountId(args.nearAccountId);\n const relayerUrl = this.tatchiPasskeyConfigs.relayer.url;\n\n try {\n if (!relayerUrl) throw new Error('Missing relayer url (configs.relayer.url)');\n if (!args.credential) throw new Error('Missing credential');\n\n const deviceNumber = Number(args.deviceNumber);\n const resolvedDeviceNumber = Number.isSafeInteger(deviceNumber) && deviceNumber >= 1\n ? deviceNumber\n : await getLastLoggedInDeviceNumber(nearAccountId, IndexedDBManager.clientDB).catch(() => 1);\n\n const keygen = await this.withSigningSession({\n prefix: 'threshold-keygen',\n options: { credential: args.credential },\n handler: (sessionId) =>\n enrollThresholdEd25519KeyHandler(\n {\n nearClient: this.nearClient,\n vrfWorkerManager: this.vrfWorkerManager,\n signerWorkerManager: this.signerWorkerManager,\n touchIdPrompt: this.touchIdPrompt,\n relayerUrl,\n },\n { sessionId, nearAccountId },\n ),\n });\n\n if (!keygen.success) {\n throw new Error(keygen.error || 'Threshold keygen failed');\n }\n\n const publicKey = keygen.publicKey;\n const clientVerifyingShareB64u = keygen.clientVerifyingShareB64u;\n const relayerKeyId = keygen.relayerKeyId;\n const relayerVerifyingShareB64u = keygen.relayerVerifyingShareB64u;\n if (!clientVerifyingShareB64u) throw new Error('Threshold keygen returned empty clientVerifyingShareB64u');\n\n // Activate threshold enrollment on-chain by submitting AddKey(publicKey) signed with the local key.\n const localKeyMaterial = await IndexedDBManager.nearKeysDB.getLocalKeyMaterial(nearAccountId, resolvedDeviceNumber);\n if (!localKeyMaterial) {\n throw new Error(`No local key material found for account ${nearAccountId} device ${resolvedDeviceNumber}`);\n }\n\n // If the key is already present, skip AddKey and just persist local threshold metadata.\n const alreadyActive = await hasAccessKey(this.nearClient, nearAccountId, publicKey, { attempts: 1, delayMs: 0 });\n if (!alreadyActive) {\n this.nonceManager.initializeUser(nearAccountId, localKeyMaterial.publicKey);\n const txContext = await this.nonceManager.getNonceBlockHashAndHeight(this.nearClient, { force: true });\n\n const signed = await this.signAddKeyThresholdPublicKeyNoPrompt({\n nearAccountId,\n credential: args.credential,\n wrapKeySalt: localKeyMaterial.wrapKeySalt,\n transactionContext: txContext,\n thresholdPublicKey: publicKey,\n relayerVerifyingShareB64u,\n clientParticipantId: keygen.clientParticipantId,\n relayerParticipantId: keygen.relayerParticipantId,\n deviceNumber: resolvedDeviceNumber,\n });\n\n const signedTx = signed?.signedTransaction;\n if (!signedTx) throw new Error('Failed to sign AddKey(thresholdPublicKey) transaction');\n\n await this.nearClient.sendTransaction(signedTx, DEFAULT_WAIT_STATUS.thresholdAddKey);\n\n const activated = await hasAccessKey(this.nearClient, nearAccountId, publicKey);\n if (!activated) throw new Error('Threshold access key not found on-chain after AddKey');\n }\n\n const keyMaterial: ThresholdEd25519_2p_V1Material = {\n kind: 'threshold_ed25519_2p_v1',\n nearAccountId,\n deviceNumber: resolvedDeviceNumber,\n publicKey,\n wrapKeySalt: keygen.wrapKeySalt,\n relayerKeyId,\n clientShareDerivation: 'prf_first_v1',\n participants: buildThresholdEd25519Participants2pV1({\n clientParticipantId: keygen.clientParticipantId,\n relayerParticipantId: keygen.relayerParticipantId,\n relayerKeyId,\n relayerUrl,\n clientVerifyingShareB64u,\n relayerVerifyingShareB64u,\n clientShareDerivation: 'prf_first_v1',\n }),\n timestamp: Date.now(),\n };\n await IndexedDBManager.nearKeysDB.storeKeyMaterial(keyMaterial);\n\n return {\n success: true,\n publicKey,\n relayerKeyId,\n wrapKeySalt: keygen.wrapKeySalt,\n };\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return { success: false, publicKey: '', relayerKeyId: '', wrapKeySalt: '', error: message };\n }\n }\n\n // ==============================\n // USER SETTINGS\n // ==============================\n\n /** * Get user preferences manager */\n getUserPreferences(): UserPreferencesManager {\n return this.userPreferencesManager;\n }\n\n /** * Clean up resources */\n destroy(): void {\n if (this.userPreferencesManager) {\n this.userPreferencesManager.destroy();\n }\n if (this.nonceManager) {\n this.nonceManager.clear();\n }\n this.activeSigningSessionIds.clear();\n }\n\n}\n","/**\n * Offline Export App (minimal, zero-config)\n *\n * Runs under `/offline-export/` on the wallet origin and reuses the\n * WebAuthnManager.exportNearKeypairWithUI() VRF-driven flow to decrypt and\n * display the private key export viewer. No network requests are made.\n *\n * See `docs/vrf2-refactor-export-keys.md` for the canonical export flow design.\n */\nimport { IndexedDBManager } from '../IndexedDBManager';\nimport { MinimalNearClient } from '../NearClient';\nimport { toAccountId } from '../types/accountIds';\nimport { OFFLINE_EXPORT_DONE, OFFLINE_EXPORT_ERROR } from './messages';\nimport type { TatchiConfigsInput } from '../types/tatchi';\nimport { WebAuthnManager } from '../WebAuthnManager';\nimport { TouchIdPrompt } from '../WebAuthnManager/touchIdPrompt';\nimport { createRandomVRFChallenge, type VRFChallenge } from '../types/vrf-worker';\nimport { buildConfigsFromEnv } from '../defaultConfigs';\n\nasync function registerServiceWorker(): Promise<void> {\n if (!('serviceWorker' in navigator)) return;\n // Register and await ready() only in this route; SW is in-scope here\n await navigator.serviceWorker\n .register('/offline-export/sw.js', { scope: '/offline-export/' })\n .catch(() => {});\n await navigator.serviceWorker.ready.catch(() => {});\n}\n\nasync function prewarmSdkAssets(): Promise<void> {\n // Only attempt network warm-up when online; SW will cache responses\n if (!navigator.onLine) return\n try {\n const resp = await fetch('/offline-export/precache.manifest.json', { cache: 'no-cache' })\n const all: string[] = resp.ok ? (await resp.json()) : []\n const priority = new Set<string>([\n '/offline-export/offline-export-app.js',\n '/sdk/offline-export-app.js',\n '/sdk/offline-export.css',\n '/sdk/export-private-key-viewer.js',\n '/sdk/iframe-export-bootstrap.js',\n '/sdk/export-viewer.css',\n '/sdk/export-iframe.css',\n '/offline-export/workers/web3authn-signer.worker.js',\n '/offline-export/workers/web3authn-vrf.worker.js',\n '/offline-export/workers/wasm_signer_worker_bg.wasm',\n '/offline-export/workers/wasm_vrf_worker_bg.wasm',\n '/sdk/workers/web3authn-signer.worker.js',\n '/sdk/workers/web3authn-vrf.worker.js',\n '/sdk/workers/wasm_signer_worker_bg.wasm',\n '/sdk/workers/wasm_vrf_worker_bg.wasm',\n ])\n const pri = Array.from(priority)\n const rest = all.filter((u) => !priority.has(u))\n await Promise.allSettled(pri.map((u) => fetch(u).then(() => void 0)))\n // Warm the remaining entries opportunistically\n const schedule = () => void Promise.allSettled(rest.map((u) => fetch(u).then(() => void 0)))\n try { (window as any).requestIdleCallback ? (window as any).requestIdleCallback(schedule, { timeout: 8000 }) : setTimeout(schedule, 800) } catch { setTimeout(schedule, 800) }\n } catch {}\n\n // Fallback: proactively cache any /sdk/* scripts that the offline page\n // already loaded as part of its initial bundle (e.g. common-*.js vendor chunks).\n // These are requested before the SW takes control, so we re-fetch them once\n // the SW is ready to ensure they are present in the offline cache.\n try {\n const origin = window.location.origin;\n const scriptPaths = Array.from(document.querySelectorAll('script[src]'))\n .map((el) => (el as HTMLScriptElement).src)\n .filter((src) => typeof src === 'string' && src.startsWith(origin + '/sdk/'))\n .map((src) => new URL(src).pathname);\n if (scriptPaths.length > 0) {\n await Promise.allSettled(\n scriptPaths.map((p) => fetch(p).then(() => void 0))\n );\n }\n } catch {}\n}\n\nfunction autoStartIfSingleUser(users: any[], selectedAccount: string, startExport: (acc: string) => Promise<void>): void {\n if (Array.isArray(users) && users.length === 1 && typeof selectedAccount === 'string' && selectedAccount) {\n setTimeout(() => { void startExport(selectedAccount) }, 0)\n }\n}\n\nfunction renderShell(message: string, canExport = false): HTMLButtonElement | null {\n document.documentElement.classList.add('w3a-transparent');\n document.body.classList.add('w3a-transparent');\n const root = document.createElement('div');\n root.className = 'offline-root'\n const h = document.createElement('h1');\n h.textContent = 'Offline Export';\n h.className = 'offline-title'\n const p = document.createElement('p');\n p.textContent = message;\n p.className = 'offline-desc'\n const info = document.createElement('div');\n info.className = 'offline-info';\n try {\n const tick = document.createElement('span');\n tick.className = 'offline-info-tick';\n tick.textContent = '✓';\n const label = document.createElement('span');\n label.textContent = ' Wallet origin: ';\n const url = document.createElement('a');\n url.className = 'offline-info-url';\n const origin = window.location.origin;\n url.href = origin;\n url.textContent = origin;\n url.target = '_blank';\n url.rel = 'noopener noreferrer';\n info.appendChild(tick);\n info.appendChild(label);\n info.appendChild(url);\n } catch {\n info.textContent = '✓ Wallet origin: (unknown)';\n }\n const btn = document.createElement('button');\n btn.textContent = 'Export My Key';\n btn.className = 'offline-btn'\n btn.disabled = !canExport;\n root.appendChild(h);\n root.appendChild(p);\n root.appendChild(info);\n root.appendChild(btn);\n document.body.appendChild(root);\n return canExport ? btn : null;\n}\n\nasync function main(): Promise<void> {\n await registerServiceWorker();\n // Best-effort: warm critical SDK assets so offline flow is reliable.\n // Do not block first paint — fire-and-forget.\n void prewarmSdkAssets();\n try {\n // Ensure worker scripts resolve under SW scope so their subresource fetches (WASM) are controlled\n (window as any).__W3A_SIGNER_WORKER_URL__ = '/offline-export/workers/web3authn-signer.worker.js'\n ;(window as any).__W3A_VRF_WORKER_URL__ = '/offline-export/workers/web3authn-vrf.worker.js'\n const rpOverrideFromMeta = (() => {\n const m = document.querySelector('meta[name=\"tatchi-rpid-base\"]') as HTMLMetaElement | null;\n const v = (m?.content || '').trim();\n return v || undefined;\n })();\n const deriveBaseDomain = (host: string): string | undefined => {\n const parts = (host || '').split('.');\n // Heuristic: use registrable suffix for dev hosts like wallet.example.localhost\n return parts.length >= 3 ? parts.slice(1).join('.') : undefined;\n };\n const inferredBase = deriveBaseDomain(window.location.hostname);\n const effectiveRpIdOverride = rpOverrideFromMeta || inferredBase;\n // Detect last user (same origin IndexedDB)\n const last = await IndexedDBManager.clientDB.getLastUser();\n const users = await IndexedDBManager.clientDB.getAllUsers().catch(() => []);\n\n // Optional preselected account via query string\n const qs = new URLSearchParams((window.location && window.location.search) || '')\n const qsAccountRaw = (qs.get('accountId') || '').trim()\n const qsAccount = qsAccountRaw ? String(toAccountId(qsAccountRaw)) : ''\n\n // Container: message + optional account selector + button + status line\n const defaultAccount = qsAccount || (last?.nearAccountId || '')\n if (!defaultAccount) {\n renderShell('No local account found on this device. Open the wallet once online on this device to prime offline export.');\n return;\n }\n const btn = renderShell('Authenticate with Touch ID/biometrics to export keys offline.', true);\n if (!btn) return;\n const container = btn.parentElement as HTMLDivElement;\n\n // Optional account selector when multiple local users exist\n let selectedAccount = defaultAccount as string;\n if (Array.isArray(users) && users.length > 1) {\n const label = document.createElement('label');\n label.textContent = 'Choose account:';\n label.className = 'offline-label'\n const sel = document.createElement('select');\n sel.className = 'offline-select'\n for (const u of users) {\n const opt = document.createElement('option');\n opt.value = (u as any).nearAccountId;\n opt.textContent = (u as any).nearAccountId;\n if ((u as any).nearAccountId === selectedAccount) opt.selected = true;\n sel.appendChild(opt);\n }\n sel.addEventListener('change', () => { selectedAccount = sel.value; statusEl.textContent = ''; });\n container.insertBefore(sel, btn);\n container.insertBefore(label, sel);\n }\n\n // Status line for inline errors/info\n const statusEl = document.createElement('div');\n statusEl.className = 'offline-status'\n container.appendChild(statusEl);\n\n // Pre-flight: soft-check for local authenticators (do not block)\n async function ensureLocalAuthenticators(acc: string): Promise<any[]> {\n try {\n const authenticators = await IndexedDBManager.clientDB.getAuthenticatorsByUser(acc as any);\n if (!Array.isArray(authenticators) || authenticators.length === 0) {\n console.warn('[offline-export] No local passkeys in IndexedDB; proceeding (resident credentials may still be available)');\n statusEl.textContent = 'Tip: open the wallet on this device once online to prime offline export. If a passkey exists on this device, you can still proceed.';\n return [];\n }\n return authenticators;\n } catch (e) {\n console.warn('[offline-export] Failed to read authenticators; proceeding anyway', e);\n return [];\n }\n }\n\n let started = false;\n const defaultBtnLabel = btn.textContent || 'Export My Key';\n const startExport = async (account: string) => {\n if (started) return;\n started = true;\n btn.disabled = true;\n btn.classList.add('loading');\n try { btn.textContent = 'Exporting…'; btn.setAttribute('aria-busy', 'true'); } catch {}\n statusEl.textContent = '';\n try {\n // Soft-check (non-blocking) — we may still have resident credentials\n const authenticators = await ensureLocalAuthenticators(account);\n\n // Instantiate WebAuthnManager with minimal offline configs. No network RPC is used in export flow.\n const near = new MinimalNearClient('https://rpc.invalid.local');\n const offlineConfigsInput: TatchiConfigsInput = {\n nearRpcUrl: 'https://rpc.invalid.local',\n nearNetwork: 'testnet',\n contractId: 'w3a-v1.testnet',\n walletTheme: 'dark',\n iframeWallet: effectiveRpIdOverride ? { rpIdOverride: effectiveRpIdOverride } : undefined,\n relayer: {\n url: 'https://rpc.invalid.local',\n },\n };\n const offlineConfigs = buildConfigsFromEnv(offlineConfigsInput);\n const webAuthnManager = new WebAuthnManager(offlineConfigs, near);\n console.debug('[offline-export] rpId (hostname):', window.location.hostname);\n if (effectiveRpIdOverride) {\n console.debug('[offline-export] rpIdOverride:', effectiveRpIdOverride);\n }\n try {\n // Attempt direct export using WebAuthnManager's worker-driven flow\n await webAuthnManager.exportNearKeypairWithUI(toAccountId(account), {\n variant: 'drawer',\n theme: 'dark',\n });\n } catch (err: any) {\n const msg = String(err?.message || err || '');\n const isMissingLocalKeyMaterial = msg.includes('Missing local key material for export');\n const isAeadDecryptMismatch =\n msg.includes('Decryption failed: Decryption error: aead::Error') || msg.includes('aead::Error');\n\n if (isMissingLocalKeyMaterial || isAeadDecryptMismatch) {\n // Attempt local recovery of key material from passkey, then retry\n statusEl.textContent = isAeadDecryptMismatch\n ? 'Decryption failed. Attempting recovery with your passkey…'\n : 'Missing local key material. Attempting recovery with your passkey…';\n const tip = new TouchIdPrompt(effectiveRpIdOverride);\n const challenge = createRandomVRFChallenge() as VRFChallenge;\n const allowCredentials = Array.isArray(authenticators) && authenticators.length > 0\n ? authenticators.map((a: any) => ({ id: a.credentialId, type: 'public-key', transports: a.transports as any }))\n : [];\n const authCred = await tip.getAuthenticationCredentialsSerializedDualPrf({\n nearAccountId: account,\n challenge,\n allowCredentials,\n });\n // Recover NEAR keypair using WebAuthnManager's recovery flow\n const rec = await webAuthnManager.recoverKeypairFromPasskey(authCred, account);\n if (!rec.wrapKeySalt) {\n throw new Error('Missing wrapKeySalt in recovered key material; re-register to upgrade vault format.');\n }\n // Store encrypted key locally for this device. Prefer the last logged-in\n // device for this account; fall back to device 1 for legacy cases.\n const accountId = toAccountId(account);\n const [last, latest] = await Promise.all([\n IndexedDBManager.clientDB.getLastUser().catch(() => null),\n IndexedDBManager.clientDB.getLastDBUpdatedUser(accountId).catch(() => null),\n ]);\n const deviceNumber =\n (last && last.nearAccountId === accountId && typeof last.deviceNumber === 'number')\n ? last.deviceNumber\n : (latest && latest.nearAccountId === accountId && typeof latest.deviceNumber === 'number')\n ? latest.deviceNumber\n : 1;\n\n // Safety check: only overwrite local vault material if the recovered public key\n // matches what we already have for this account/device.\n const existing = await IndexedDBManager.clientDB.getUserByDevice(accountId, deviceNumber).catch(() => null);\n if (isAeadDecryptMismatch && !existing) {\n throw new Error(\n `Decryption failed and no local user record was found for '${account}'. ` +\n 'Open the wallet once online on this device to restore local vault state, then retry offline export.'\n );\n }\n const expectedPublicKey = String(existing?.clientNearPublicKey || '');\n if (expectedPublicKey && expectedPublicKey !== rec.publicKey) {\n throw new Error(\n `Selected passkey does not match the existing key for '${account}'. ` +\n 'Please select the correct passkey for this account and try again.'\n );\n }\n\n await IndexedDBManager.nearKeysDB.storeKeyMaterial({\n kind: 'local_near_sk_v3',\n nearAccountId: account,\n deviceNumber,\n publicKey: rec.publicKey,\n encryptedSk: rec.encryptedPrivateKey,\n chacha20NonceB64u: rec.chacha20NonceB64u,\n wrapKeySalt: rec.wrapKeySalt,\n timestamp: Date.now(),\n });\n // Upsert public key if missing for this device\n if (!existing?.clientNearPublicKey) {\n try { await IndexedDBManager.clientDB.updateUser(accountId, { clientNearPublicKey: rec.publicKey }); } catch {}\n }\n statusEl.textContent = 'Recovered local key material. Opening export viewer…';\n await webAuthnManager.exportNearKeypairWithUI(toAccountId(account), {\n variant: 'drawer',\n theme: 'dark',\n });\n } else {\n throw err;\n }\n }\n // Notify parent (overlay controllers) that the export UI has been shown\n window.parent?.postMessage?.({ type: OFFLINE_EXPORT_DONE, nearAccountId: account }, '*');\n } catch (e: any) {\n console.error('[offline-export] export failed', e);\n const msg = String(e?.message || e || '');\n if (msg.includes('User cancelled secure confirm request')) {\n // Differentiate common NotAllowedError path vs explicit cancel\n statusEl.textContent = `No matching passkeys for this origin or the prompt was cancelled. Ensure this device has a passkey for '${account}' on ${window.location.hostname}, then try again.`;\n } else if (msg.includes('NotAllowedError')) {\n statusEl.textContent = `No matching passkeys available for '${account}' on this device.`;\n } else if (msg.includes('Missing local key material')) {\n statusEl.textContent = 'Missing local key material for export. Open the wallet on this device once online to prime offline export.';\n } else {\n statusEl.textContent = 'Export failed: ' + msg;\n }\n window.parent?.postMessage?.({ type: OFFLINE_EXPORT_ERROR, error: msg }, '*');\n } finally {\n btn.disabled = false;\n btn.classList.remove('loading');\n try { btn.textContent = defaultBtnLabel; btn.removeAttribute('aria-busy'); } catch {}\n started = false;\n }\n };\n\n // Click handler uses current selected account\n btn.addEventListener('click', async () => { await startExport(selectedAccount); });\n } catch (e) {\n console.error('[offline-export] bootstrap failed', e);\n renderShell('Failed to initialize offline export on this device.');\n }\n}\n\nif (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => void main());\n} else {\n void main();\n}\n\nexport {}\n"],"x_google_ignoreList":[0,2,3],"mappings":"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"}
1
+ {"version":3,"file":"offline-export-app.js","names":["target","DB_CONFIG: PasskeyClientDBConfig","DB_CONFIG","err: any","entry: AppStateEntry<T>","userData: ClientUserData","lastUserState: LastUserAccountIdState","fixed: ClientUserData","updatedUser: ClientUserData","clientAuth: ClientAuthenticatorData","rec: DerivedAddressRecord","rec: RecoveryEmailRecord","ALPHABET","basex","bs58","out: number[]","out: ThresholdEd25519ParticipantV1[]","participant: ThresholdEd25519ParticipantV1","client: ThresholdEd25519ParticipantV1","relayer: ThresholdEd25519ParticipantV1","DB_CONFIG: PasskeyNearKeysDBConfig","kind","value: any","txPayload: EncodableSignedTx","lastError: unknown","err: unknown","base","params: Record<string, unknown>","fullAccessKeys: FullAccessKey[]","functionCallAccessKeys: FunctionCallAccessKey[]","isObject","err: unknown","base","error: any","serializedCredential: WebAuthnRegistrationCredential","result: CheckCanRegisterUserResult","error: unknown","wasmModule.UserVerificationPolicy.Required","wasmModule.UserVerificationPolicy.Preferred","wasmModule.UserVerificationPolicy.Discouraged","DEFAULT_AUTHENTICATOR_OPTIONS: AuthenticatorOptions","keyMaterial: LocalNearSkV3Material","error: unknown","error: unknown","base","DEFAULT_THRESHOLD_SESSION_POLICY: Pick<ThresholdEd25519SessionPolicy, 'ttlMs' | 'remainingUses'>","warnings: string[]","txSigningRequests: TransactionPayload[]","extractSigningEvidenceFromConfirmation","e: unknown","credentialForRelay: WebAuthnAuthenticationCredential | undefined","warnings: string[]","extractSigningEvidenceFromConfirmation","okResponse","okResponse: WorkerSuccessResponse<typeof WorkerRequestType.SignDelegateAction>","e: unknown","credentialForRelay: WebAuthnAuthenticationCredential | undefined","error: unknown","error: unknown","error: unknown","okResponse","okResponse: WorkerSuccessResponse<typeof WorkerRequestType.SignNep413Message>","e: unknown","error: unknown","credentialForRelay: WebAuthnAuthenticationCredential | undefined","keyMaterial: LocalNearSkV3Material","error: unknown","cfg: ConfirmationConfig","newUiMode: ConfirmationConfig['uiMode']","payload: any","request: SecureConfirmRequest","confirmationConfig: ConfirmationConfig","transactionSummary: TransactionSummary","e: unknown","_err: unknown","HANDLERS: Partial<Record<SecureConfirmationType, Handler>>","error: unknown","vrfPort: MessagePort | undefined","error: unknown","promises: Promise<void>[]","responses: WorkerResponseForRequest<T>[]","errorMessage","message: VRFWorkerMessage<WasmVrfWorkerRequestType>","message: VRFWorkerMessage<WasmClearSessionRequest>","message: VRFWorkerMessage<WasmVrfWorkerRequestType>","message: VRFWorkerMessage<WasmDevice2RegistrationSessionRequest>","intentDigest: string","request: SecureConfirmRequest<SignTransactionPayload | SignNep413Payload, TransactionSummary>","summary: TransactionSummary","txSigningRequests: TransactionInputWasm[]","message: VRFWorkerMessage<WasmConfirmAndPrepareSigningSessionRequest>","message: VRFWorkerMessage<WasmDeriveVrfKeypairFromPrfRequest>","message: VRFWorkerMessage<WasmMintSessionKeysAndSendToSignerRequest>","message: VRFWorkerMessage<WasmDispenseSessionKeyRequest>","message: VRFWorkerMessage<WasmShamir3PassClientDecryptVrfKeypairRequest>","message: VRFWorkerMessage<WasmGenerateVrfChallengeRequest>","indexedDB","message: VRFWorkerMessage<WasmGenerateVrfKeypairBootstrapRequest>","error: any","message: VRFWorkerMessage<WasmCheckSessionStatusRequest>","message: VRFWorkerMessage<any>","requestRegistrationCredentialConfirmation","request: SecureConfirmRequest<{\n nearAccountId: string;\n deviceNumber: number;\n rpcCall: { contractId: string; nearRpcUrl: string; nearAccountId: string };\n }, RegistrationSummary>","requestRegistrationCredentialConfirmationFlow","message: VRFWorkerMessage<WasmVrfWorkerRequestType>","message: VRFWorkerMessage<WasmUnlockVrfKeypairRequest>","error: any","next: ConfirmationConfig","base","envTheme: 'dark' | 'light' | null","accountId: AccountId | undefined","maybeAccessKey: unknown","maybeBlock: unknown","accessKeyError: unknown","blockError: unknown","tasks: Promise<void>[]","akErr: unknown","err: unknown","transactionContext: TransactionContext","now","planned: string[]","error: unknown","newLast: bigint | null","error: unknown","base","deleteKeyAction: ActionArgsWasm","txInputs: TransactionInputWasm[]","rpcCall: RpcCallPayload","error: unknown","UserPreferencesInstance","NonceManagerInstance","collectAuthenticationCredentialForVrfChallengeImpl","error: any","result: {\n success: boolean;\n vrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n vrfChallenge: VRFChallenge | null;\n serverEncryptedVrfKeypair: ServerEncryptedVrfKeypair | null;\n }","deviceNumber: number","deviceNumberToUse: number | null","credentialId: string","attestationB64u: string","transports: string[]","normalizedRpcCall: RpcCallPayload","error: unknown","keyMaterial: ThresholdEd25519_2p_V1Material","all: string[]","offlineConfigsInput: TatchiConfigsInput","err: any","last","e: any"],"sources":["../../../../node_modules/.pnpm/idb@8.0.3/node_modules/idb/build/index.js","../../../src/core/IndexedDBManager/passkeyClientDB.ts","../../../../node_modules/.pnpm/base-x@5.0.1/node_modules/base-x/src/esm/index.js","../../../../node_modules/.pnpm/bs58@6.0.0/node_modules/bs58/src/esm/index.js","../../../src/utils/base58.ts","../../../src/react/deviceDetection.ts","../../../src/threshold/participants.ts","../../../src/core/IndexedDBManager/passkeyNearKeysDB.ts","../../../src/core/IndexedDBManager/index.ts","../../../src/core/NearRpcError.ts","../../../src/core/types/rpc.ts","../../../src/core/NearClient.ts","../../../src/core/OfflineExport/messages.ts","../../../build-paths.ts","../../../src/config.ts","../../../src/core/sdkPaths/base.ts","../../../src/core/sdkPaths/workers.ts","../../../src/core/workerControlMessages.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/sessionMessages.ts","../../../src/core/types/sdkSentEvents.ts","../../../src/core/rpcCalls.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/checkCanRegisterUser.ts","../../../src/core/types/authenticatorOptions.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/session.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/deriveNearKeypairAndEncryptFromSerialized.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/decryptPrivateKeyWithPrf.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/sessionHandshake.ts","../../../src/core/threshold/thresholdEd25519RelayerHealth.ts","../../../src/core/threshold/thresholdEd25519AuthSession.ts","../../../src/core/threshold/thresholdSessionPolicy.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionsWithActions.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/validation.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/signDelegateAction.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/recoverKeypairFromPasskey.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/extractCosePublicKey.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/signTransactionWithKeyPair.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/signNep413Message.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/registerDevice2WithDerivedKey.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/determineConfirmationConfig.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/requestAdapter.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/handleSecureConfirmRequest.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/secureConfirmBridge.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/exportNearKeypairUi.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/handlers/deriveThresholdEd25519ClientVerifyingShare.ts","../../../src/core/WebAuthnManager/SignerWorkerManager/index.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/checkVrfStatus.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/clearSession.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/clearVrf.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/confirmAndDeriveDevice2RegistrationSession.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/confirmAndPrepareSigningSession.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/deriveVrfKeypairFromPrf.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/mintSessionKeysAndSendToSigner.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/dispenseSessionKey.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/shamir3PassDecryptVrfKeypair.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfChallenge.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/generateVrfKeypairBootstrap.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/checkSessionStatus.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/prepareDecryptSession.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/requestRegistrationCredentialConfirmation.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/requestRegistrationCredentialConfirmation.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/shamir3PassEncryptCurrentVrfKeypair.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/handlers/unlockVrfKeypair.ts","../../../src/core/WebAuthnManager/VrfWorkerManager/index.ts","../../../src/core/WebAuthnManager/userPreferences.ts","../../../src/core/nonceManager.ts","../../../src/core/WebAuthnManager/threshold/enrollThresholdEd25519Key.ts","../../../src/core/WebAuthnManager/threshold/rotateThresholdEd25519KeyPostRegistration.ts","../../../src/core/WebAuthnManager/index.ts","../../../src/core/OfflineExport/offline-export-app.ts"],"sourcesContent":["const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);\n\nlet idbProxyableTypes;\nlet cursorAdvanceMethods;\n// This is a function to prevent it throwing up in node environments.\nfunction getIdbProxyableTypes() {\n return (idbProxyableTypes ||\n (idbProxyableTypes = [\n IDBDatabase,\n IDBObjectStore,\n IDBIndex,\n IDBCursor,\n IDBTransaction,\n ]));\n}\n// This is a function to prevent it throwing up in node environments.\nfunction getCursorAdvanceMethods() {\n return (cursorAdvanceMethods ||\n (cursorAdvanceMethods = [\n IDBCursor.prototype.advance,\n IDBCursor.prototype.continue,\n IDBCursor.prototype.continuePrimaryKey,\n ]));\n}\nconst transactionDoneMap = new WeakMap();\nconst transformCache = new WeakMap();\nconst reverseTransformCache = new WeakMap();\nfunction promisifyRequest(request) {\n const promise = new Promise((resolve, reject) => {\n const unlisten = () => {\n request.removeEventListener('success', success);\n request.removeEventListener('error', error);\n };\n const success = () => {\n resolve(wrap(request.result));\n unlisten();\n };\n const error = () => {\n reject(request.error);\n unlisten();\n };\n request.addEventListener('success', success);\n request.addEventListener('error', error);\n });\n // This mapping exists in reverseTransformCache but doesn't exist in transformCache. This\n // is because we create many promises from a single IDBRequest.\n reverseTransformCache.set(promise, request);\n return promise;\n}\nfunction cacheDonePromiseForTransaction(tx) {\n // Early bail if we've already created a done promise for this transaction.\n if (transactionDoneMap.has(tx))\n return;\n const done = new Promise((resolve, reject) => {\n const unlisten = () => {\n tx.removeEventListener('complete', complete);\n tx.removeEventListener('error', error);\n tx.removeEventListener('abort', error);\n };\n const complete = () => {\n resolve();\n unlisten();\n };\n const error = () => {\n reject(tx.error || new DOMException('AbortError', 'AbortError'));\n unlisten();\n };\n tx.addEventListener('complete', complete);\n tx.addEventListener('error', error);\n tx.addEventListener('abort', error);\n });\n // Cache it for later retrieval.\n transactionDoneMap.set(tx, done);\n}\nlet idbProxyTraps = {\n get(target, prop, receiver) {\n if (target instanceof IDBTransaction) {\n // Special handling for transaction.done.\n if (prop === 'done')\n return transactionDoneMap.get(target);\n // Make tx.store return the only store in the transaction, or undefined if there are many.\n if (prop === 'store') {\n return receiver.objectStoreNames[1]\n ? undefined\n : receiver.objectStore(receiver.objectStoreNames[0]);\n }\n }\n // Else transform whatever we get back.\n return wrap(target[prop]);\n },\n set(target, prop, value) {\n target[prop] = value;\n return true;\n },\n has(target, prop) {\n if (target instanceof IDBTransaction &&\n (prop === 'done' || prop === 'store')) {\n return true;\n }\n return prop in target;\n },\n};\nfunction replaceTraps(callback) {\n idbProxyTraps = callback(idbProxyTraps);\n}\nfunction wrapFunction(func) {\n // Due to expected object equality (which is enforced by the caching in `wrap`), we\n // only create one new func per func.\n // Cursor methods are special, as the behaviour is a little more different to standard IDB. In\n // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the\n // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense\n // with real promises, so each advance methods returns a new promise for the cursor object, or\n // undefined if the end of the cursor has been reached.\n if (getCursorAdvanceMethods().includes(func)) {\n return function (...args) {\n // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n // the original object.\n func.apply(unwrap(this), args);\n return wrap(this.request);\n };\n }\n return function (...args) {\n // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n // the original object.\n return wrap(func.apply(unwrap(this), args));\n };\n}\nfunction transformCachableValue(value) {\n if (typeof value === 'function')\n return wrapFunction(value);\n // This doesn't return, it just creates a 'done' promise for the transaction,\n // which is later returned for transaction.done (see idbObjectHandler).\n if (value instanceof IDBTransaction)\n cacheDonePromiseForTransaction(value);\n if (instanceOfAny(value, getIdbProxyableTypes()))\n return new Proxy(value, idbProxyTraps);\n // Return the same value back if we're not going to transform it.\n return value;\n}\nfunction wrap(value) {\n // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because\n // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.\n if (value instanceof IDBRequest)\n return promisifyRequest(value);\n // If we've already transformed this value before, reuse the transformed value.\n // This is faster, but it also provides object equality.\n if (transformCache.has(value))\n return transformCache.get(value);\n const newValue = transformCachableValue(value);\n // Not all types are transformed.\n // These may be primitive types, so they can't be WeakMap keys.\n if (newValue !== value) {\n transformCache.set(value, newValue);\n reverseTransformCache.set(newValue, value);\n }\n return newValue;\n}\nconst unwrap = (value) => reverseTransformCache.get(value);\n\n/**\n * Open a database.\n *\n * @param name Name of the database.\n * @param version Schema version.\n * @param callbacks Additional callbacks.\n */\nfunction openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {\n const request = indexedDB.open(name, version);\n const openPromise = wrap(request);\n if (upgrade) {\n request.addEventListener('upgradeneeded', (event) => {\n upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);\n });\n }\n if (blocked) {\n request.addEventListener('blocked', (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion, event.newVersion, event));\n }\n openPromise\n .then((db) => {\n if (terminated)\n db.addEventListener('close', () => terminated());\n if (blocking) {\n db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event));\n }\n })\n .catch(() => { });\n return openPromise;\n}\n/**\n * Delete a database.\n *\n * @param name Name of the database.\n */\nfunction deleteDB(name, { blocked } = {}) {\n const request = indexedDB.deleteDatabase(name);\n if (blocked) {\n request.addEventListener('blocked', (event) => blocked(\n // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n event.oldVersion, event));\n }\n return wrap(request).then(() => undefined);\n}\n\nconst readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];\nconst writeMethods = ['put', 'add', 'delete', 'clear'];\nconst cachedMethods = new Map();\nfunction getMethod(target, prop) {\n if (!(target instanceof IDBDatabase &&\n !(prop in target) &&\n typeof prop === 'string')) {\n return;\n }\n if (cachedMethods.get(prop))\n return cachedMethods.get(prop);\n const targetFuncName = prop.replace(/FromIndex$/, '');\n const useIndex = prop !== targetFuncName;\n const isWrite = writeMethods.includes(targetFuncName);\n if (\n // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.\n !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) ||\n !(isWrite || readMethods.includes(targetFuncName))) {\n return;\n }\n const method = async function (storeName, ...args) {\n // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(\n const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');\n let target = tx.store;\n if (useIndex)\n target = target.index(args.shift());\n // Must reject if op rejects.\n // If it's a write operation, must reject if tx.done rejects.\n // Must reject with op rejection first.\n // Must resolve with op value.\n // Must handle both promises (no unhandled rejections)\n return (await Promise.all([\n target[targetFuncName](...args),\n isWrite && tx.done,\n ]))[0];\n };\n cachedMethods.set(prop, method);\n return method;\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),\n has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop),\n}));\n\nconst advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];\nconst methodMap = {};\nconst advanceResults = new WeakMap();\nconst ittrProxiedCursorToOriginalProxy = new WeakMap();\nconst cursorIteratorTraps = {\n get(target, prop) {\n if (!advanceMethodProps.includes(prop))\n return target[prop];\n let cachedFunc = methodMap[prop];\n if (!cachedFunc) {\n cachedFunc = methodMap[prop] = function (...args) {\n advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));\n };\n }\n return cachedFunc;\n },\n};\nasync function* iterate(...args) {\n // tslint:disable-next-line:no-this-assignment\n let cursor = this;\n if (!(cursor instanceof IDBCursor)) {\n cursor = await cursor.openCursor(...args);\n }\n if (!cursor)\n return;\n cursor = cursor;\n const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);\n ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);\n // Map this double-proxy back to the original, so other cursor methods work.\n reverseTransformCache.set(proxiedCursor, unwrap(cursor));\n while (cursor) {\n yield proxiedCursor;\n // If one of the advancing methods was not called, call continue().\n cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());\n advanceResults.delete(proxiedCursor);\n }\n}\nfunction isIteratorProp(target, prop) {\n return ((prop === Symbol.asyncIterator &&\n instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor])) ||\n (prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore])));\n}\nreplaceTraps((oldTraps) => ({\n ...oldTraps,\n get(target, prop, receiver) {\n if (isIteratorProp(target, prop))\n return iterate;\n return oldTraps.get(target, prop, receiver);\n },\n has(target, prop) {\n return isIteratorProp(target, prop) || oldTraps.has(target, prop);\n },\n}));\n\nexport { deleteDB, openDB, unwrap, wrap };\n","import { openDB, type IDBPDatabase } from 'idb';\nimport { type ValidationResult, validateNearAccountId } from '../../utils/validation';\nimport type { AccountId } from '../types/accountIds';\nimport { toAccountId } from '../types/accountIds';\nimport {\n ConfirmationConfig,\n DEFAULT_CONFIRMATION_CONFIG,\n type SignerMode,\n DEFAULT_SIGNING_MODE,\n coerceSignerMode,\n} from '../types/signer-worker'\n\n\nexport interface ClientUserData {\n // Primary key - now uses AccountId + deviceNumber for unique identification\n nearAccountId: AccountId;\n deviceNumber: number; // Device number for multi-device support (1-indexed)\n version?: number;\n\n // User metadata\n registeredAt?: number;\n lastLogin?: number;\n lastUpdated?: number;\n\n // WebAuthn/Passkey data (merged from WebAuthnManager)\n clientNearPublicKey: string;\n passkeyCredential: {\n id: string;\n rawId: string;\n };\n\n // VRF credentials for stateless authentication\n encryptedVrfKeypair: {\n encryptedVrfDataB64u: string;\n chacha20NonceB64u: string;\n };\n // Server-assisted auto-login (VRF key session): Shamir 3-pass fields\n // Stores relayer-blinded KEK and the VRF ciphertext; server never sees plaintext VRF or KEK\n serverEncryptedVrfKeypair?: {\n ciphertextVrfB64u: string;\n kek_s_b64u: string;\n // Metadata for proactive refresh\n serverKeyId: string;\n updatedAt?: number;\n };\n\n // User preferences\n preferences?: UserPreferences;\n}\n\nexport type StoreUserDataInput = Omit<ClientUserData, 'deviceNumber' | 'lastLogin' | 'registeredAt'>\n & {\n deviceNumber?: number;\n serverEncryptedVrfKeypair?: ClientUserData['serverEncryptedVrfKeypair'];\n version?: number;\n };\n\nexport type StoreWebAuthnUserDataInput = {\n nearAccountId: AccountId;\n deviceNumber: number;\n clientNearPublicKey: string;\n lastUpdated?: number;\n version?: number;\n passkeyCredential: ClientUserData['passkeyCredential'];\n encryptedVrfKeypair: ClientUserData['encryptedVrfKeypair'];\n serverEncryptedVrfKeypair?: ClientUserData['serverEncryptedVrfKeypair'];\n};\n\nexport interface UserPreferences {\n useRelayer: boolean;\n useNetwork: 'testnet' | 'mainnet';\n confirmationConfig: ConfirmationConfig;\n signerMode?: SignerMode;\n // User preferences can be extended here as needed\n}\n\n// Authenticator cache\nexport interface ClientAuthenticatorData {\n credentialId: string;\n credentialPublicKey: Uint8Array;\n transports?: string[]; // AuthenticatorTransport[]\n name?: string;\n nearAccountId: AccountId; // FK reference using AccountId\n deviceNumber: number; // Device number for this authenticator (1-indexed)\n registered: string; // ISO date string\n syncedAt: string; // When this cache entry was last synced with contract\n vrfPublicKey: string; // Base64-encoded VRF public key (1:1 relationship on client)\n}\n\ninterface AppStateEntry<T = unknown> {\n key: string;\n value: T;\n}\n\n// Internal helper: legacy user records may be missing deviceNumber.\ntype ClientUserDataWithOptionalDevice =\n | ClientUserData\n | (Omit<ClientUserData, 'deviceNumber'> & { deviceNumber?: number });\n\n// Special type for lastUserAccountId app state entry\nexport interface LastUserAccountIdState {\n accountId: AccountId;\n deviceNumber: number;\n}\n\ninterface PasskeyClientDBConfig {\n dbName: string;\n dbVersion: number;\n userStore: string;\n appStateStore: string;\n authenticatorStore: string;\n derivedAddressStore: string;\n recoveryEmailStore: string;\n}\n\n// === CONSTANTS ===\nconst DB_CONFIG: PasskeyClientDBConfig = {\n dbName: 'PasskeyClientDB',\n dbVersion: 15, // v15: add recoveryEmails store\n userStore: 'users',\n appStateStore: 'appState',\n authenticatorStore: 'authenticators',\n derivedAddressStore: 'derivedAddresses',\n recoveryEmailStore: 'recoveryEmails'\n} as const;\n\nexport interface IndexedDBEvent {\n type: 'user-updated' | 'preferences-updated' | 'user-deleted';\n accountId: AccountId;\n data?: Record<string, unknown>;\n}\n\n// Persisted mapping of derived (e.g., EVM) addresses tied to an account\n/**\n * Persisted mapping of derived (e.g., EVM/Solana/Zcash) addresses tied to an account.\n *\n * Notes on multi-chain support:\n * - The composite primary key is [nearAccountId, contractId, path]. To support\n * different chains and chain IDs, encode them in the `path` string, e.g.:\n * - EVM: `evm:<chainId>:<derivationPath>` → `evm:84532:ethereum-1`\n * - Solana: `solana:<derivationPath>`\n * - Zcash: `zcash:<derivationPath>`\n * - Additional descriptive fields like `namespace` and `chainRef` are optional metadata\n * and are not part of the key.\n */\nexport interface DerivedAddressRecord {\n nearAccountId: AccountId;\n contractId: string; // MPC/Derivation contract on NEAR\n path: string; // Composite path (may include namespace/chainId); see docs above\n address: string; // Derived address (e.g., 0x...)\n updatedAt: number;\n // Optional metadata (not used in the key)\n namespace?: string; // e.g., 'evm', 'solana', 'zcash'\n chainRef?: string; // e.g., chainId '84532' or a named network slug\n}\n\n/**\n * Persisted mapping of recovery email hashes to canonical email addresses for an account.\n *\n * Notes:\n * - Composite primary key is [nearAccountId, hashHex].\n * - `hashHex` is the 0x-prefixed hex encoding of the 32-byte hash:\n * SHA256(canonical_email || \"|\" || account_id)\n * - `email` is the canonical form: \"local@domain\", lowercased.\n */\nexport interface RecoveryEmailRecord {\n nearAccountId: AccountId;\n hashHex: string;\n email: string;\n addedAt: number;\n}\n\nexport class PasskeyClientDBManager {\n private config: PasskeyClientDBConfig;\n private db: IDBPDatabase | null = null;\n private disabled = false;\n private eventListeners: Set<(event: IndexedDBEvent) => void> = new Set();\n\n constructor(config: PasskeyClientDBConfig = DB_CONFIG) {\n this.config = config;\n }\n\n getDbName(): string {\n return this.config.dbName;\n }\n\n setDbName(dbName: string): void {\n const next = String(dbName || '').trim();\n if (!next || next === this.config.dbName) return;\n try { (this.db as any)?.close?.(); } catch {}\n this.db = null;\n this.config = { ...this.config, dbName: next };\n }\n\n isDisabled(): boolean {\n return this.disabled;\n }\n\n setDisabled(disabled: boolean): void {\n const next = !!disabled;\n if (next === this.disabled) return;\n this.disabled = next;\n if (next) {\n try { (this.db as any)?.close?.(); } catch {}\n this.db = null;\n }\n }\n\n // === EVENT SYSTEM ===\n\n onChange(listener: (event: IndexedDBEvent) => void): () => void {\n this.eventListeners.add(listener);\n return () => {\n this.eventListeners.delete(listener);\n };\n }\n\n private emitEvent(event: IndexedDBEvent): void {\n this.eventListeners.forEach(listener => {\n try {\n listener(event);\n } catch (error) {\n console.warn('[IndexedDBManager]: Error in event listener:', error);\n }\n });\n }\n\n private async getDB(): Promise<IDBPDatabase> {\n if (this.disabled) {\n throw new Error('[PasskeyClientDBManager] IndexedDB is disabled in this environment.');\n }\n if (this.db) {\n return this.db;\n }\n\n try {\n this.db = await openDB(this.config.dbName, this.config.dbVersion, {\n upgrade: (db, oldVersion, _newVersion, _transaction): void => {\n // Create stores if they don't exist\n if (!db.objectStoreNames.contains(DB_CONFIG.userStore)) {\n // Users table: composite key of [nearAccountId, deviceNumber]\n const userStore = db.createObjectStore(DB_CONFIG.userStore, { keyPath: ['nearAccountId', 'deviceNumber'] });\n userStore.createIndex('nearAccountId', 'nearAccountId', { unique: false });\n }\n if (!db.objectStoreNames.contains(DB_CONFIG.appStateStore)) {\n db.createObjectStore(DB_CONFIG.appStateStore, { keyPath: 'key' });\n }\n if (!db.objectStoreNames.contains(DB_CONFIG.authenticatorStore)) {\n // Authenticators table: composite key of [nearAccountId, deviceNumber, credentialId]\n const authStore = db.createObjectStore(DB_CONFIG.authenticatorStore, { keyPath: ['nearAccountId', 'deviceNumber', 'credentialId'] });\n authStore.createIndex('nearAccountId', 'nearAccountId', { unique: false });\n }\n if (!db.objectStoreNames.contains(DB_CONFIG.derivedAddressStore)) {\n // Derived addresses: composite key of [nearAccountId, contractId, path]\n const dStore = db.createObjectStore(DB_CONFIG.derivedAddressStore, { keyPath: ['nearAccountId', 'contractId', 'path'] });\n try { dStore.createIndex('nearAccountId', 'nearAccountId', { unique: false }); } catch {}\n }\n if (!db.objectStoreNames.contains(DB_CONFIG.recoveryEmailStore)) {\n // Recovery emails: composite key of [nearAccountId, hashHex]\n const rStore = db.createObjectStore(DB_CONFIG.recoveryEmailStore, { keyPath: ['nearAccountId', 'hashHex'] });\n try { rStore.createIndex('nearAccountId', 'nearAccountId', { unique: false }); } catch {}\n }\n },\n blocked() {\n console.warn('PasskeyClientDB connection is blocked.');\n },\n blocking() {\n console.warn('PasskeyClientDB connection is blocking another connection.');\n },\n terminated: () => {\n console.warn('PasskeyClientDB connection has been terminated.');\n this.db = null;\n },\n });\n\n // Post-open migrations (non-blocking)\n try { await this.runMigrationsIfNeeded(this.db); } catch {}\n\n } catch (err: any) {\n const msg = String(err?.message || '');\n if (err?.name === 'VersionError' || /less than the existing version/i.test(msg)) {\n // Mixed-version contexts (host/app) — open without version to adopt existing DB\n try {\n console.warn('PasskeyClientDB: opening existing DB without version due to VersionError');\n this.db = await openDB(this.config.dbName);\n } catch (e) {\n throw err;\n }\n } else {\n throw err;\n }\n }\n\n return this.db;\n }\n\n private async runMigrationsIfNeeded(_db: IDBPDatabase): Promise<void> {\n return;\n }\n\n // === APP STATE METHODS ===\n\n async getAppState<T = unknown>(key: string): Promise<T | undefined> {\n const db = await this.getDB();\n const result = await db.get(DB_CONFIG.appStateStore, key);\n return result?.value as T | undefined;\n }\n\n async setAppState<T = unknown>(key: string, value: T): Promise<void> {\n const db = await this.getDB();\n const entry: AppStateEntry<T> = { key, value };\n await db.put(DB_CONFIG.appStateStore, entry);\n }\n\n // === ACCOUNT ID VALIDATION AND UTILITIES ===\n\n /**\n * Validate that a NEAR account ID is in the expected format\n * Supports both <username>.<relayerAccountId> and <username>.testnet formats\n */\n validateNearAccountId(nearAccountId: AccountId): ValidationResult {\n return validateNearAccountId(nearAccountId);\n }\n\n /**\n * Extract username from NEAR account ID\n */\n extractUsername(nearAccountId: AccountId): string {\n const validation = validateNearAccountId(nearAccountId);\n if (!validation.valid) {\n throw new Error(`Invalid NEAR account ID: ${validation.error}`);\n }\n return nearAccountId.split('.')[0];\n }\n\n /**\n * Generate a NEAR account ID from a username and domain\n * @param username - The username to use for the account ID\n * @param domain - The domain to use for the account ID\n * @returns The generated NEAR account ID\n */\n generateNearAccountId(username: string, domain: string): string {\n const sanitizedName = username\n .toLowerCase()\n .replace(/[^a-z0-9_\\\\-]/g, '')\n .substring(0, 32);\n return `${sanitizedName}.${domain}`;\n }\n\n // === USER MANAGEMENT METHODS ===\n\n async getUser(nearAccountId: AccountId, deviceNumber?: number): Promise<ClientUserData | null> {\n if (!nearAccountId) return null;\n\n const validation = this.validateNearAccountId(nearAccountId);\n if (!validation.valid) {\n console.warn(`Invalid account ID format: ${nearAccountId}`);\n return null;\n }\n\n const db = await this.getDB();\n const accountId = toAccountId(nearAccountId);\n\n if (typeof deviceNumber === 'number') {\n const rec = await db.get(DB_CONFIG.userStore, [accountId, deviceNumber]);\n if (!rec) return null;\n return await this.normalizeUserDeviceNumber(rec as ClientUserDataWithOptionalDevice, deviceNumber);\n }\n\n const index = db.transaction(DB_CONFIG.userStore).store.index('nearAccountId');\n const results = await index.getAll(accountId);\n if (results.length === 0) {\n return null;\n }\n\n if (results.length > 1) {\n console.warn(\n `Multiple passkeys found for account ${accountId}, deviceNumber not provided; ` +\n 'defaulting to last logged-in user.'\n );\n console.log('defaulting to last used user deviceNumber');\n const lastUserState = await this.getAppState<LastUserAccountIdState>('lastUserAccountId').catch(() => null);\n if (lastUserState && toAccountId(lastUserState.accountId) === accountId) {\n const keyed = await db.get(DB_CONFIG.userStore, [accountId, lastUserState.deviceNumber]);\n if (keyed) {\n return await this.normalizeUserDeviceNumber(\n keyed as ClientUserDataWithOptionalDevice,\n lastUserState.deviceNumber\n );\n }\n }\n }\n\n const first = results[0] as ClientUserDataWithOptionalDevice;\n if (!first) return null;\n return await this.normalizeUserDeviceNumber(first, 1);\n }\n\n /**\n * Get the current/last user\n * This is maintained via app state and updated whenever a user is stored or updated\n */\n async getLastUser(): Promise<ClientUserData | null> {\n const lastUserState = await this.getAppState<LastUserAccountIdState>('lastUserAccountId');\n if (!lastUserState) return null;\n const db = await this.getDB();\n const accountId = toAccountId(lastUserState.accountId);\n // Prefer exact device match using composite primary key\n const record = await db.get(DB_CONFIG.userStore, [accountId, lastUserState.deviceNumber]);\n if (record) return record as ClientUserData;\n // Fallback: return any user for account\n return this.getUser(accountId);\n }\n\n /** Get user record by composite key (nearAccountId, deviceNumber) */\n async getUserByDevice(nearAccountId: AccountId, deviceNumber: number): Promise<ClientUserData | null> {\n const db = await this.getDB();\n const accountId = toAccountId(nearAccountId);\n const rec = await db.get(DB_CONFIG.userStore, [accountId, deviceNumber]);\n return rec as ClientUserData || null;\n }\n\n /**\n * Get the most recently updated user record for a given account.\n * Useful when deviceNumber is unknown but we need the freshest key for the account.\n */\n /**\n * Get the most recently updated user record for a given account.\n * Useful when deviceNumber is unknown but we need the freshest key for the account.\n */\n async getLastDBUpdatedUser(nearAccountId: AccountId): Promise<ClientUserData | null> {\n const db = await this.getDB();\n try {\n const idx = db.transaction(DB_CONFIG.userStore).store.index('nearAccountId');\n const all = await idx.getAll(toAccountId(nearAccountId));\n if (Array.isArray(all) && all.length > 0) {\n const latest = (all as ClientUserData[]).reduce((a, b) =>\n (a.lastUpdated ?? 0) >= (b.lastUpdated ?? 0) ? a : b\n );\n return latest;\n }\n } catch {\n // fall through\n }\n return null;\n }\n\n async hasPasskeyCredential(nearAccountId: AccountId): Promise<boolean> {\n const authenticators = await this.getAuthenticatorsByUser(nearAccountId);\n return !!authenticators[0]?.credentialId;\n }\n\n /**\n * Ensure the current passkey selection is aligned with the last logged-in device.\n *\n * - When multiple authenticators exist for an account and no deviceNumber is specified,\n * this helper prefers authenticators whose deviceNumber matches the last logged-in user.\n * - Optionally validates that a selected credential (by rawId) also matches the last-user device.\n *\n * @param nearAccountId - Account ID for which the operation is being performed\n * @param authenticators - All authenticators stored for the account\n * @param selectedCredentialRawId - Optional rawId of the credential chosen by WebAuthn\n * @returns filtered authenticators for allowCredentials, plus optional wrongPasskeyError\n */\n async ensureCurrentPasskey(\n nearAccountId: AccountId,\n authenticators: ClientAuthenticatorData[],\n selectedCredentialRawId?: string,\n ): Promise<{\n authenticatorsForPrompt: ClientAuthenticatorData[];\n wrongPasskeyError?: string;\n }> {\n if (authenticators.length <= 1) {\n return { authenticatorsForPrompt: authenticators };\n }\n\n const accountIdNormalized = toAccountId(nearAccountId);\n const lastUser = await this.getLastUser().catch(() => null);\n if (!lastUser || lastUser.nearAccountId !== accountIdNormalized) {\n return { authenticatorsForPrompt: authenticators };\n }\n\n const expectedDeviceNumber = lastUser.deviceNumber;\n const byDeviceNumber = authenticators.filter(a => a.deviceNumber === expectedDeviceNumber);\n\n // Prefer the credentialId for the last-user deviceNumber; use the stored last-user rawId\n // only when it matches an authenticator for that device (or when we have no device match).\n let expectedCredentialId = lastUser.passkeyCredential.rawId;\n if (byDeviceNumber.length > 0 && !byDeviceNumber.some(a => a.credentialId === expectedCredentialId)) {\n expectedCredentialId = byDeviceNumber[0].credentialId;\n }\n\n // Preference: restrict allowCredentials to the last-user credentialId.\n // Fallback: if the local authenticator cache is missing that entry, prefer the last-user deviceNumber.\n const byCredentialId = authenticators.filter(a => a.credentialId === expectedCredentialId);\n const authenticatorsForPrompt =\n byCredentialId.length > 0\n ? byCredentialId\n : (byDeviceNumber.length > 0 ? byDeviceNumber : authenticators);\n\n const wrongPasskeyError =\n selectedCredentialRawId && selectedCredentialRawId !== expectedCredentialId\n ? (\n `You have multiple passkeys (deviceNumbers) for account ${accountIdNormalized}, ` +\n 'but used a different passkey than the most recently logged-in one. Please use the passkey for the most recently logged-in device.'\n )\n : undefined;\n\n return { authenticatorsForPrompt, wrongPasskeyError };\n }\n\n /**\n * Register a new user with the given NEAR account ID\n * @param nearAccountId - Full NEAR account ID (e.g., \"username.testnet\" or \"username.relayer.testnet\")\n * @param additionalData - Additional user data to store\n */\n async registerUser(storeUserData: StoreUserDataInput): Promise<ClientUserData> {\n\n const validation = this.validateNearAccountId(storeUserData.nearAccountId);\n if (!validation.valid) {\n throw new Error(`Cannot register user with invalid account ID: ${validation.error}`);\n }\n\n const now = Date.now();\n\n const userData: ClientUserData = {\n nearAccountId: toAccountId(storeUserData.nearAccountId),\n deviceNumber: storeUserData.deviceNumber || 1, // Default to device 1 (1-indexed)\n version: storeUserData.version || 2,\n registeredAt: now,\n lastLogin: now,\n lastUpdated: now,\n clientNearPublicKey: storeUserData.clientNearPublicKey,\n passkeyCredential: storeUserData.passkeyCredential,\n preferences: {\n useRelayer: false,\n useNetwork: 'testnet',\n confirmationConfig: DEFAULT_CONFIRMATION_CONFIG,\n // Default preferences can be set here\n },\n encryptedVrfKeypair: storeUserData.encryptedVrfKeypair,\n serverEncryptedVrfKeypair: storeUserData.serverEncryptedVrfKeypair,\n };\n\n await this.storeUser(userData);\n return userData;\n }\n\n async updateUser(nearAccountId: AccountId, updates: Partial<ClientUserData>, deviceNumber?: number): Promise<void> {\n const user = await this.getUser(nearAccountId, deviceNumber);\n if (user) {\n const updatedUser = {\n ...user,\n ...updates,\n lastUpdated: Date.now()\n };\n await this.storeUser(updatedUser); // This will update the app state lastUserAccountId\n\n // Emit event for user updates\n this.emitEvent({\n type: 'user-updated',\n accountId: nearAccountId,\n data: { updates, updatedUser }\n });\n }\n }\n\n async updateLastLogin(nearAccountId: AccountId): Promise<void> {\n await this.updateUser(nearAccountId, { lastLogin: Date.now() });\n }\n\n /**\n * Set the last logged-in user\n * @param nearAccountId - The account ID of the user\n * @param deviceNumber - The device number (defaults to 1)\n */\n async setLastUser(nearAccountId: AccountId, deviceNumber: number = 1): Promise<void> {\n const lastUserState: LastUserAccountIdState = {\n accountId: nearAccountId,\n deviceNumber,\n };\n await this.setAppState('lastUserAccountId', lastUserState);\n }\n\n async updatePreferences(\n nearAccountId: AccountId,\n preferences: Partial<UserPreferences>\n ): Promise<void> {\n const user = await this.getUser(nearAccountId);\n if (user) {\n const updatedPreferences = {\n ...user.preferences,\n ...preferences\n } as UserPreferences;\n await this.updateUser(nearAccountId, { preferences: updatedPreferences });\n\n // Emit event for preference changes\n this.emitEvent({\n type: 'preferences-updated',\n accountId: nearAccountId,\n data: { preferences: updatedPreferences }\n });\n }\n }\n\n private async normalizeUserDeviceNumber(\n user: ClientUserDataWithOptionalDevice,\n defaultDeviceNumber: number\n ): Promise<ClientUserData> {\n const hasValidDevice =\n typeof user.deviceNumber === 'number' && Number.isFinite(user.deviceNumber);\n if (hasValidDevice) {\n return user as ClientUserData;\n }\n\n const deviceNumber = defaultDeviceNumber;\n const fixed: ClientUserData = {\n ...(user as Omit<ClientUserData, 'deviceNumber'>),\n deviceNumber,\n };\n await this.storeUser(fixed);\n return fixed;\n }\n\n private async storeUser(userData: ClientUserData): Promise<void> {\n const validation = this.validateNearAccountId(userData.nearAccountId);\n if (!validation.valid) {\n throw new Error(`Cannot store user with invalid account ID: ${validation.error}`);\n }\n\n const db = await this.getDB();\n await db.put(DB_CONFIG.userStore, userData);\n\n // Update lastUserAccountId with new format including device info\n const lastUserState: LastUserAccountIdState = {\n accountId: userData.nearAccountId,\n deviceNumber: userData.deviceNumber,\n };\n\n await this.setAppState('lastUserAccountId', lastUserState);\n }\n\n /**\n * Store WebAuthn user data (compatibility with WebAuthnManager)\n * @param userData - User data with nearAccountId as primary identifier\n */\n async storeWebAuthnUserData(userData: StoreWebAuthnUserDataInput): Promise<void> {\n const validation = this.validateNearAccountId(userData.nearAccountId);\n if (!validation.valid) {\n throw new Error(`Cannot store WebAuthn data for invalid account ID: ${validation.error}`);\n }\n\n const accountId = toAccountId(userData.nearAccountId);\n const deviceNumber = userData.deviceNumber;\n let user = await this.getUser(accountId, deviceNumber);\n\n if (!user) {\n user = await this.registerUser({\n nearAccountId: accountId,\n deviceNumber,\n clientNearPublicKey: userData.clientNearPublicKey,\n passkeyCredential: userData.passkeyCredential,\n encryptedVrfKeypair: userData.encryptedVrfKeypair,\n version: userData.version || 2,\n serverEncryptedVrfKeypair: userData.serverEncryptedVrfKeypair,\n });\n }\n\n const updatedUser: ClientUserData = {\n ...user,\n clientNearPublicKey: userData.clientNearPublicKey,\n passkeyCredential: userData.passkeyCredential,\n encryptedVrfKeypair: userData.encryptedVrfKeypair,\n serverEncryptedVrfKeypair: userData.serverEncryptedVrfKeypair ?? user.serverEncryptedVrfKeypair,\n version: userData.version ?? user.version,\n lastUpdated: userData.lastUpdated ?? Date.now(),\n };\n\n await this.storeUser(updatedUser);\n this.emitEvent({\n type: 'user-updated',\n accountId,\n data: { updatedUser }\n });\n }\n\n async getAllUsers(): Promise<ClientUserData[]> {\n const db = await this.getDB();\n return db.getAll(DB_CONFIG.userStore);\n }\n\n async deleteUser(nearAccountId: AccountId): Promise<void> {\n const db = await this.getDB();\n await db.delete(DB_CONFIG.userStore, nearAccountId);\n // Also clean up related authenticators\n await this.clearAuthenticatorsForUser(nearAccountId);\n }\n\n async clearAllUsers(): Promise<void> {\n const db = await this.getDB();\n await db.clear(DB_CONFIG.userStore);\n }\n\n async clearAllAppState(): Promise<void> {\n const db = await this.getDB();\n await db.clear(DB_CONFIG.appStateStore);\n }\n\n /**\n * Store authenticator data for a user\n */\n async storeAuthenticator(authenticatorData: ClientAuthenticatorData): Promise<void> {\n const db = await this.getDB();\n await db.put(DB_CONFIG.authenticatorStore, authenticatorData);\n }\n\n /**\n * Get all authenticators for a user (optionally for a specific device)\n */\n async getAuthenticatorsByUser(nearAccountId: AccountId): Promise<ClientAuthenticatorData[]> {\n const db = await this.getDB();\n const tx = db.transaction(DB_CONFIG.authenticatorStore, 'readonly');\n const store = tx.objectStore(DB_CONFIG.authenticatorStore);\n const accountId = toAccountId(nearAccountId);\n\n // Get all authenticators for this account across all devices\n const index = store.index('nearAccountId');\n return await index.getAll(accountId);\n }\n\n /**\n * Get a specific authenticator by credential ID\n */\n async getAuthenticatorByCredentialId(\n nearAccountId: AccountId,\n credentialId: string\n ): Promise<ClientAuthenticatorData | null> {\n const db = await this.getDB();\n const tx = db.transaction(DB_CONFIG.authenticatorStore, 'readonly');\n const store = tx.objectStore(DB_CONFIG.authenticatorStore);\n const accountId = toAccountId(nearAccountId);\n\n // Primary key is [nearAccountId, deviceNumber, credentialId], so we cannot\n // look up by [nearAccountId, credentialId] directly. Use the nearAccountId\n // index and filter by credentialId.\n const index = store.index('nearAccountId');\n const all = await index.getAll(accountId);\n const match = all.find((auth: any) => auth.credentialId === credentialId) || null;\n return match;\n }\n\n /**\n * Clear all authenticators for a user\n */\n async clearAuthenticatorsForUser(nearAccountId: AccountId): Promise<void> {\n const authenticators = await this.getAuthenticatorsByUser(nearAccountId);\n const db = await this.getDB();\n const tx = db.transaction(DB_CONFIG.authenticatorStore, 'readwrite');\n const store = tx.objectStore(DB_CONFIG.authenticatorStore);\n\n for (const auth of authenticators) {\n // Composite PK is [nearAccountId, deviceNumber, credentialId]\n await store.delete([nearAccountId, auth.deviceNumber, auth.credentialId]);\n }\n }\n\n /**\n * Sync authenticators from contract data\n */\n async syncAuthenticatorsFromContract(\n nearAccountId: AccountId,\n contractAuthenticators: Array<{\n credentialId: string;\n credentialPublicKey: Uint8Array;\n transports?: string[];\n name?: string;\n registered: string;\n vrfPublicKey: string;\n deviceNumber?: number; // Device number from contract\n }>\n ): Promise<void> {\n // Clear existing cache for this user\n await this.clearAuthenticatorsForUser(nearAccountId);\n\n // Add all contract authenticators to cache\n const syncedAt = new Date().toISOString();\n for (const auth of contractAuthenticators) {\n // Fix transport processing: filter out undefined values and provide fallback\n const rawTransports = auth.transports || [];\n const validTransports = rawTransports.filter((transport: any) =>\n transport !== undefined && transport !== null && typeof transport === 'string'\n );\n\n // If no valid transports, default to 'internal' for platform authenticators\n const transports = validTransports.length > 0 ? validTransports : ['internal'];\n\n const clientAuth: ClientAuthenticatorData = {\n credentialId: auth.credentialId,\n credentialPublicKey: auth.credentialPublicKey,\n transports,\n name: auth.name,\n nearAccountId: toAccountId(nearAccountId),\n deviceNumber: auth.deviceNumber || 1, // Default to device 1 (1-indexed)\n registered: auth.registered,\n syncedAt: syncedAt,\n vrfPublicKey: auth.vrfPublicKey,\n };\n await this.storeAuthenticator(clientAuth);\n }\n }\n\n // === ATOMIC OPERATIONS AND ROLLBACK METHODS ===\n\n /**\n * Delete all authenticators for a user\n */\n async deleteAllAuthenticatorsForUser(nearAccountId: AccountId): Promise<void> {\n const authenticators = await this.getAuthenticatorsByUser(nearAccountId);\n\n if (authenticators.length === 0) {\n console.warn(`No authenticators found for user ${nearAccountId}`);\n return;\n }\n\n const db = await this.getDB();\n const tx = db.transaction(DB_CONFIG.authenticatorStore, 'readwrite');\n const store = tx.objectStore(DB_CONFIG.authenticatorStore);\n\n for (const auth of authenticators) {\n // Composite PK is [nearAccountId, deviceNumber, credentialId]\n await store.delete([nearAccountId, auth.deviceNumber, auth.credentialId]);\n }\n\n console.debug(`Deleted ${authenticators.length} authenticators for user ${nearAccountId}`);\n }\n\n /**\n * Get user's confirmation config from IndexedDB\n * @param nearAccountId - The user's account ID\n * @returns ConfirmationConfig or undefined\n */\n async getConfirmationConfig(nearAccountId: AccountId): Promise<ConfirmationConfig> {\n const user = await this.getUser(nearAccountId);\n return user?.preferences?.confirmationConfig || DEFAULT_CONFIRMATION_CONFIG;\n }\n\n /**\n * Get user's theme preference from IndexedDB\n * @param nearAccountId - The user's account ID\n * @returns 'dark' | 'light' | null\n */\n async getTheme(nearAccountId: AccountId): Promise<'dark' | 'light' | null> {\n const user = await this.getUser(nearAccountId);\n return user?.preferences?.confirmationConfig.theme || null;\n }\n\n /**\n * Set user's theme preference in IndexedDB\n * @param nearAccountId - The user's account ID\n * @param theme - The theme to set ('dark' | 'light')\n */\n async setTheme(nearAccountId: AccountId, theme: 'dark' | 'light'): Promise<void> {\n const existingConfig = await this.getConfirmationConfig(nearAccountId);\n const confirmationConfig = { ...existingConfig, theme };\n await this.updatePreferences(nearAccountId, { confirmationConfig });\n }\n\n /**\n * Get user's theme with fallback to 'dark'\n * @param nearAccountId - The user's account ID\n * @returns 'dark' | 'light'\n */\n async getThemeOrDefault(nearAccountId: AccountId): Promise<'dark' | 'light'> {\n const theme = await this.getTheme(nearAccountId);\n return theme || 'dark';\n }\n\n /**\n * Get user's signer mode preference from IndexedDB\n */\n async getSignerMode(nearAccountId: AccountId): Promise<SignerMode> {\n const user = await this.getUser(nearAccountId);\n const raw = user?.preferences?.signerMode as SignerMode | SignerMode['mode'] | null | undefined;\n return coerceSignerMode(raw, DEFAULT_SIGNING_MODE);\n }\n\n /**\n * Set user's signer mode preference in IndexedDB\n */\n async setSignerMode(nearAccountId: AccountId, signerMode: SignerMode | SignerMode['mode']): Promise<void> {\n const next = coerceSignerMode(signerMode, DEFAULT_SIGNING_MODE);\n await this.updatePreferences(nearAccountId, { signerMode: next });\n }\n\n /**\n * Toggle between dark and light theme for a user\n * @param nearAccountId - The user's account ID\n * @returns The new theme that was set\n */\n async toggleTheme(nearAccountId: AccountId): Promise<'dark' | 'light'> {\n const currentTheme = await this.getThemeOrDefault(nearAccountId);\n const newTheme = currentTheme === 'dark' ? 'light' : 'dark';\n await this.setTheme(nearAccountId, newTheme);\n return newTheme;\n }\n\n // === DERIVED ADDRESS METHODS ===\n\n /**\n * Store a derived address for a given NEAR account + contract + path\n */\n async setDerivedAddress(nearAccountId: AccountId, args: { contractId: string; path: string; address: string }): Promise<void> {\n if (!nearAccountId || !args?.contractId || !args?.path || !args?.address) return;\n const validation = this.validateNearAccountId(nearAccountId);\n if (!validation.valid) return;\n const rec: DerivedAddressRecord = {\n nearAccountId: toAccountId(nearAccountId),\n contractId: String(args.contractId),\n path: String(args.path),\n address: String(args.address),\n updatedAt: Date.now(),\n };\n const db = await this.getDB();\n await db.put(DB_CONFIG.derivedAddressStore, rec);\n }\n\n /**\n * Fetch a derived address record; returns null if not found\n */\n async getDerivedAddressRecord(nearAccountId: AccountId, args: { contractId: string; path: string }): Promise<DerivedAddressRecord | null> {\n if (!nearAccountId || !args?.contractId || !args?.path) return null;\n const db = await this.getDB();\n const rec = await db.get(DB_CONFIG.derivedAddressStore, [toAccountId(nearAccountId), String(args.contractId), String(args.path)]);\n return (rec as DerivedAddressRecord) || null;\n }\n\n /**\n * Get only the derived address string; returns null if not set\n */\n async getDerivedAddress(nearAccountId: AccountId, args: { contractId: string; path: string }): Promise<string | null> {\n const rec = await this.getDerivedAddressRecord(nearAccountId, args);\n return rec?.address || null;\n }\n\n // === RECOVERY EMAIL METHODS ===\n\n /**\n * Upsert recovery email records for an account.\n * Merges by hashHex, preferring the most recent email.\n */\n async upsertRecoveryEmails(\n nearAccountId: AccountId,\n entries: Array<{ hashHex: string; email: string }>\n ): Promise<void> {\n if (!nearAccountId || !entries?.length) return;\n const validation = this.validateNearAccountId(nearAccountId);\n if (!validation.valid) return;\n\n const db = await this.getDB();\n const accountId = toAccountId(nearAccountId);\n const now = Date.now();\n\n for (const entry of entries) {\n const hashHex = String(entry?.hashHex || '').trim();\n const email = String(entry?.email || '').trim();\n if (!hashHex || !email) continue;\n\n const rec: RecoveryEmailRecord = {\n nearAccountId: accountId,\n hashHex,\n email,\n addedAt: now,\n };\n await db.put(DB_CONFIG.recoveryEmailStore, rec);\n }\n }\n\n /**\n * Fetch all recovery email records for an account.\n */\n async getRecoveryEmails(nearAccountId: AccountId): Promise<RecoveryEmailRecord[]> {\n if (!nearAccountId) return [];\n const db = await this.getDB();\n const accountId = toAccountId(nearAccountId);\n const tx = db.transaction(DB_CONFIG.recoveryEmailStore, 'readonly');\n const store = tx.objectStore(DB_CONFIG.recoveryEmailStore);\n const index = store.index('nearAccountId');\n const result = await index.getAll(accountId);\n return (result as RecoveryEmailRecord[]) || [];\n }\n\n /**\n * Atomic operation wrapper for multiple IndexedDB operations\n * Either all operations succeed or all are rolled back\n */\n async atomicOperation<T>(operation: (db: IDBPDatabase) => Promise<T>): Promise<T> {\n const db = await this.getDB();\n try {\n const result = await operation(db);\n return result;\n } catch (error) {\n console.error('Atomic operation failed:', error);\n throw error;\n }\n }\n\n /**\n * Complete rollback of user registration data\n * Deletes user, authenticators, and WebAuthn data atomically\n */\n async rollbackUserRegistration(nearAccountId: AccountId): Promise<void> {\n console.debug(`Rolling back registration data for ${nearAccountId}`);\n\n await this.atomicOperation(async (db) => {\n // Delete all authenticators for this user\n await this.deleteAllAuthenticatorsForUser(nearAccountId);\n\n // Delete user record\n await db.delete(DB_CONFIG.userStore, nearAccountId);\n\n // Clear from app state if this was the last user\n const lastUserAccount = await this.getAppState<string>('lastUserAccountId');\n if (lastUserAccount === nearAccountId) {\n await this.setAppState('lastUserAccountId', null);\n }\n\n console.debug(`Rolled back all registration data for ${nearAccountId}`);\n return true;\n });\n }\n}\n","// base-x encoding / decoding\n// Copyright (c) 2018 base-x contributors\n// Copyright (c) 2014-2018 The Bitcoin Core developers (base58.cpp)\n// Distributed under the MIT software license, see the accompanying\n// file LICENSE or http://www.opensource.org/licenses/mit-license.php.\nfunction base (ALPHABET) {\n if (ALPHABET.length >= 255) { throw new TypeError('Alphabet too long') }\n const BASE_MAP = new Uint8Array(256)\n for (let j = 0; j < BASE_MAP.length; j++) {\n BASE_MAP[j] = 255\n }\n for (let i = 0; i < ALPHABET.length; i++) {\n const x = ALPHABET.charAt(i)\n const xc = x.charCodeAt(0)\n if (BASE_MAP[xc] !== 255) { throw new TypeError(x + ' is ambiguous') }\n BASE_MAP[xc] = i\n }\n const BASE = ALPHABET.length\n const LEADER = ALPHABET.charAt(0)\n const FACTOR = Math.log(BASE) / Math.log(256) // log(BASE) / log(256), rounded up\n const iFACTOR = Math.log(256) / Math.log(BASE) // log(256) / log(BASE), rounded up\n function encode (source) {\n // eslint-disable-next-line no-empty\n if (source instanceof Uint8Array) { } else if (ArrayBuffer.isView(source)) {\n source = new Uint8Array(source.buffer, source.byteOffset, source.byteLength)\n } else if (Array.isArray(source)) {\n source = Uint8Array.from(source)\n }\n if (!(source instanceof Uint8Array)) { throw new TypeError('Expected Uint8Array') }\n if (source.length === 0) { return '' }\n // Skip & count leading zeroes.\n let zeroes = 0\n let length = 0\n let pbegin = 0\n const pend = source.length\n while (pbegin !== pend && source[pbegin] === 0) {\n pbegin++\n zeroes++\n }\n // Allocate enough space in big-endian base58 representation.\n const size = ((pend - pbegin) * iFACTOR + 1) >>> 0\n const b58 = new Uint8Array(size)\n // Process the bytes.\n while (pbegin !== pend) {\n let carry = source[pbegin]\n // Apply \"b58 = b58 * 256 + ch\".\n let i = 0\n for (let it1 = size - 1; (carry !== 0 || i < length) && (it1 !== -1); it1--, i++) {\n carry += (256 * b58[it1]) >>> 0\n b58[it1] = (carry % BASE) >>> 0\n carry = (carry / BASE) >>> 0\n }\n if (carry !== 0) { throw new Error('Non-zero carry') }\n length = i\n pbegin++\n }\n // Skip leading zeroes in base58 result.\n let it2 = size - length\n while (it2 !== size && b58[it2] === 0) {\n it2++\n }\n // Translate the result into a string.\n let str = LEADER.repeat(zeroes)\n for (; it2 < size; ++it2) { str += ALPHABET.charAt(b58[it2]) }\n return str\n }\n function decodeUnsafe (source) {\n if (typeof source !== 'string') { throw new TypeError('Expected String') }\n if (source.length === 0) { return new Uint8Array() }\n let psz = 0\n // Skip and count leading '1's.\n let zeroes = 0\n let length = 0\n while (source[psz] === LEADER) {\n zeroes++\n psz++\n }\n // Allocate enough space in big-endian base256 representation.\n const size = (((source.length - psz) * FACTOR) + 1) >>> 0 // log(58) / log(256), rounded up.\n const b256 = new Uint8Array(size)\n // Process the characters.\n while (psz < source.length) {\n // Find code of next character\n const charCode = source.charCodeAt(psz)\n // Base map can not be indexed using char code\n if (charCode > 255) { return }\n // Decode character\n let carry = BASE_MAP[charCode]\n // Invalid character\n if (carry === 255) { return }\n let i = 0\n for (let it3 = size - 1; (carry !== 0 || i < length) && (it3 !== -1); it3--, i++) {\n carry += (BASE * b256[it3]) >>> 0\n b256[it3] = (carry % 256) >>> 0\n carry = (carry / 256) >>> 0\n }\n if (carry !== 0) { throw new Error('Non-zero carry') }\n length = i\n psz++\n }\n // Skip leading zeroes in b256.\n let it4 = size - length\n while (it4 !== size && b256[it4] === 0) {\n it4++\n }\n const vch = new Uint8Array(zeroes + (size - it4))\n let j = zeroes\n while (it4 !== size) {\n vch[j++] = b256[it4++]\n }\n return vch\n }\n function decode (string) {\n const buffer = decodeUnsafe(string)\n if (buffer) { return buffer }\n throw new Error('Non-base' + BASE + ' character')\n }\n return {\n encode,\n decodeUnsafe,\n decode\n }\n}\nexport default base\n","import basex from 'base-x';\nvar ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';\nexport default basex(ALPHABET);\n","import bs58 from 'bs58';\n\n/**\n * Encodes binary data to base58 string using Bitcoin's base58 alphabet.\n * Used extensively in NEAR for account IDs, public keys, hashes, and signatures.\n *\n * @param data - Binary data to encode (Uint8Array, ArrayBuffer, or number[])\n * @returns Base58-encoded string\n */\nexport const base58Encode = (data: Uint8Array | ArrayBuffer | number[]): string => {\n if (data instanceof ArrayBuffer) {\n return bs58.encode(new Uint8Array(data));\n }\n if (Array.isArray(data)) {\n return bs58.encode(new Uint8Array(data));\n }\n return bs58.encode(data);\n};\n\n/**\n * Decodes a base58 string to binary data using Bitcoin's base58 alphabet.\n * Returns a Uint8Array containing the decoded bytes.\n *\n * @param base58String - Base58-encoded string to decode\n * @returns Uint8Array containing the decoded bytes\n * @throws Error if input contains invalid base58 characters\n */\nexport const base58Decode = (base58String: string): Uint8Array => {\n return bs58.decode(base58String);\n};\n\n","/**\n * Device detection utilities for camera and UI optimization\n */\n\nexport type DeviceType = 'mobile' | 'tablet' | 'desktop';\nexport type CameraFacingMode = 'user' | 'environment';\n\n/**\n * Detects the current device type based on multiple indicators\n */\nexport const detectDeviceType = (): DeviceType => {\n // Method 1: User agent detection\n const userAgent = navigator.userAgent.toLowerCase();\n const isMobileUA = /android|iphone|ipod|blackberry|iemobile|opera mini/i.test(userAgent);\n const isTabletUA = /ipad|tablet|kindle|playbook|silk/i.test(userAgent);\n\n // Method 2: Touch and screen size detection\n const isTouchDevice = navigator.maxTouchPoints > 0;\n const screenWidth = window.screen.width;\n const isSmallScreen = screenWidth <= 480;\n const isMediumScreen = screenWidth <= 1024;\n\n // Method 3: Orientation support (mobile/tablet indicator)\n const hasOrientation = 'orientation' in window;\n\n // Determine device type with priority: mobile > tablet > desktop\n if (isMobileUA || (isTouchDevice && isSmallScreen)) {\n return 'mobile';\n }\n\n if (isTabletUA || (isTouchDevice && isMediumScreen && hasOrientation)) {\n return 'tablet';\n }\n\n return 'desktop';\n};\n\n/**\n * Basic Safari detection (desktop Safari). Note: all iOS browsers use WebKit,\n * so use isIOS() to capture iOS Safari-like restrictions.\n */\nexport const isSafari = (): boolean => {\n try {\n const ua = navigator.userAgent;\n const isSafariEngine = /safari/i.test(ua) && !/chrome|crios|crmo|chromium|edg|edge|opr|opera|brave/i.test(ua);\n return isSafariEngine;\n } catch {\n return false;\n }\n};\n\n/**\n * Detect iOS (covers iPhone/iPad/iPod and iPadOS with desktop UA).\n * iOS has WebAuthn user-activation quirks that are shared by all iOS browsers.\n */\nexport const isIOS = (): boolean => {\n try {\n const ua = navigator.userAgent;\n const platform = (navigator as any).platform || '';\n const maxTouch = Number(navigator.maxTouchPoints || 0);\n const iOSUA = /iPad|iPhone|iPod/.test(ua);\n const iPadOSMacLike = /Macintosh/.test(ua) && maxTouch > 1; // iPadOS masquerading as Mac\n const iOSPlatform = /iPad|iPhone|iPod/.test(platform);\n return iOSUA || iPadOSMacLike || iOSPlatform;\n } catch {\n return false;\n }\n};\n\n/**\n * Detect Mobile Safari (iOS Safari specifically). Chrome/Firefox on iOS still use WebKit,\n * so for WebAuthn activation rules, prefer checking isIOS() as well.\n */\nexport const isMobileSafari = (): boolean => {\n try {\n const ua = navigator.userAgent;\n if (!isIOS()) return false;\n // Exclude Chrome/Firefox/Edge branded iOS browsers (still WebKit underneath)\n const branded = /crios|fxios|edgios|opios|mercury/i.test(ua);\n const safariToken = /safari/i.test(ua);\n return safariToken && !branded;\n } catch {\n return false;\n }\n};\n\n/**\n * Returns true when the page currently has a transient user activation\n * (click/tap/key within the allowed time window).\n */\nexport const hasActiveUserActivation = (): boolean => {\n try {\n const ua = (navigator as any).userActivation;\n return !!(ua && typeof ua.isActive === 'boolean' && ua.isActive);\n } catch {\n return false;\n }\n};\n\n/**\n * Heuristic: when on Safari/iOS or on a mobile device AND no active user\n * activation, we should surface a clickable UI to capture activation.\n */\nexport const needsExplicitActivation = (): boolean => {\n try {\n if (hasActiveUserActivation()) return false;\n return isIOS() || isMobileDevice() || isSafari();\n } catch {\n // In non-browser or SSR/test environments, avoid forcing UI changes\n return false;\n }\n};\n\n/**\n * Determines optimal camera facing mode based on device type\n * - Mobile/Tablet: Back camera (environment) for QR scanning\n * - Desktop/Laptop: Front camera (user) for video calls/selfies\n */\nexport const getOptimalCameraFacingMode = (): CameraFacingMode => {\n const deviceType = detectDeviceType();\n\n switch (deviceType) {\n case 'mobile':\n case 'tablet':\n console.log(`${deviceType} device detected - using back camera (environment)`);\n return 'environment';\n\n case 'desktop':\n default:\n return 'user';\n }\n};\n\n/**\n * Check if the current device is likely mobile\n */\nexport const isMobileDevice = (): boolean => {\n return detectDeviceType() === 'mobile';\n};\n\n/**\n * Check if the current device supports touch\n */\nexport const isTouchDevice = (): boolean => {\n return navigator.maxTouchPoints > 0;\n};\n\n/**\n * Get device capabilities for camera constraints\n */\nexport const getDeviceCapabilities = () => {\n const deviceType = detectDeviceType();\n const isTouch = isTouchDevice();\n const facingMode = getOptimalCameraFacingMode();\n\n return {\n deviceType,\n isTouch,\n recommendedFacingMode: facingMode,\n // Recommended camera constraints based on device\n cameraConstraints: {\n video: {\n facingMode,\n width: deviceType === 'mobile' ? { ideal: 720, min: 480 } : { ideal: 1280, min: 720 },\n height: deviceType === 'mobile' ? { ideal: 720, min: 480 } : { ideal: 720, min: 480 },\n aspectRatio: deviceType === 'mobile' ? { ideal: 1.0 } : { ideal: 16/9 }\n }\n }\n };\n};\n","export type ThresholdParticipantRole = 'client' | 'relayer';\n\nimport { toOptionalTrimmedString } from '../utils/validation';\nimport {\n THRESHOLD_ED25519_CLIENT_PARTICIPANT_ID,\n THRESHOLD_ED25519_RELAYER_PARTICIPANT_ID,\n THRESHOLD_ED25519_2P_PARTICIPANT_IDS,\n} from '../core/defaultConfigs';\n\nexport {\n THRESHOLD_ED25519_CLIENT_PARTICIPANT_ID,\n THRESHOLD_ED25519_RELAYER_PARTICIPANT_ID,\n THRESHOLD_ED25519_2P_PARTICIPANT_IDS,\n};\n\n/**\n * Metadata describing how a participant share is derived/stored.\n * This is informational in v1 and may be used for validation/policy later.\n */\nexport type ThresholdEd25519ShareDerivation =\n | 'prf_first_v1'\n | 'derived_master_secret_v1'\n | 'kv_random_v1'\n | 'unknown';\n\nexport interface ThresholdEd25519ParticipantV1 {\n /** FROST identifier (1-indexed). */\n id: number;\n role: ThresholdParticipantRole;\n /** Optional relayer endpoint for this participant (future multi-relayer support). */\n relayerUrl?: string;\n /** Key/share identifier understood by this participant (e.g. relayerKeyId). */\n relayerKeyId?: string;\n /** Base64url-encoded 32-byte verifying share (compressed EdwardsY). */\n verifyingShareB64u?: string;\n shareDerivation?: ThresholdEd25519ShareDerivation;\n}\n\nexport const THRESHOLD_ED25519_PARTICIPANT_SET_V1 = 'threshold_ed25519_participants_v1' as const;\n\nexport interface ThresholdEd25519ParticipantSetV1 {\n version: typeof THRESHOLD_ED25519_PARTICIPANT_SET_V1;\n groupPublicKey: string;\n participants: ThresholdEd25519ParticipantV1[];\n}\n\nexport function normalizeThresholdEd25519ParticipantId(id: unknown): number | null {\n const n = Number(id);\n if (!Number.isSafeInteger(n) || n < 1 || n > 65_535) return null;\n return n;\n}\n\nexport function normalizeThresholdEd25519ParticipantIds(input: unknown): number[] | null {\n if (!Array.isArray(input) || input.length === 0) return null;\n const out: number[] = [];\n const seen = new Set<number>();\n for (const v of input) {\n const id = normalizeThresholdEd25519ParticipantId(v);\n if (!id) return null;\n if (!seen.has(id)) {\n seen.add(id);\n out.push(id);\n }\n }\n out.sort((a, b) => a - b);\n return out.length ? out : null;\n}\n\nexport function areThresholdEd25519ParticipantIds2p(\n participantIds: number[] | null | undefined,\n expected: readonly number[] = THRESHOLD_ED25519_2P_PARTICIPANT_IDS,\n): boolean {\n const ids = normalizeThresholdEd25519ParticipantIds(participantIds);\n const expectedIds = normalizeThresholdEd25519ParticipantIds([...expected]);\n if (!ids || !expectedIds) return false;\n if (ids.length !== expectedIds.length) return false;\n return ids.every((id, i) => id === expectedIds[i]);\n}\n\nexport function parseThresholdEd25519ParticipantsV1(input: unknown): ThresholdEd25519ParticipantV1[] | null {\n if (!Array.isArray(input) || input.length === 0) return null;\n\n const out: ThresholdEd25519ParticipantV1[] = [];\n for (const item of input) {\n if (!item || typeof item !== 'object' || Array.isArray(item)) return null;\n const rec = item as Record<string, unknown>;\n\n const id = normalizeThresholdEd25519ParticipantId(rec.id);\n const role = toOptionalTrimmedString(rec.role);\n if (!id || (role !== 'client' && role !== 'relayer')) return null;\n\n const participant: ThresholdEd25519ParticipantV1 = {\n id,\n role: role as ThresholdParticipantRole,\n };\n\n const relayerUrl = toOptionalTrimmedString(rec.relayerUrl);\n if (relayerUrl) participant.relayerUrl = relayerUrl;\n\n const relayerKeyId = toOptionalTrimmedString(rec.relayerKeyId);\n if (relayerKeyId) participant.relayerKeyId = relayerKeyId;\n\n const verifyingShareB64u = toOptionalTrimmedString(rec.verifyingShareB64u);\n if (verifyingShareB64u) participant.verifyingShareB64u = verifyingShareB64u;\n\n const shareDerivation = toOptionalTrimmedString(rec.shareDerivation);\n if (\n shareDerivation === 'prf_first_v1'\n || shareDerivation === 'derived_master_secret_v1'\n || shareDerivation === 'kv_random_v1'\n || shareDerivation === 'unknown'\n ) {\n participant.shareDerivation = shareDerivation;\n }\n\n out.push(participant);\n }\n\n return out.length ? out : null;\n}\n\nexport function buildThresholdEd25519Participants2pV1(input: {\n clientParticipantId?: number | null;\n relayerParticipantId?: number | null;\n relayerKeyId: string;\n relayerUrl?: string | null;\n clientVerifyingShareB64u?: string | null;\n relayerVerifyingShareB64u?: string | null;\n clientShareDerivation?: ThresholdEd25519ShareDerivation | null;\n relayerShareDerivation?: ThresholdEd25519ShareDerivation | null;\n}): ThresholdEd25519ParticipantV1[] {\n const relayerKeyId = toOptionalTrimmedString(input.relayerKeyId);\n const relayerUrl = toOptionalTrimmedString(input.relayerUrl);\n const clientVerifyingShareB64u = toOptionalTrimmedString(input.clientVerifyingShareB64u);\n const relayerVerifyingShareB64u = toOptionalTrimmedString(input.relayerVerifyingShareB64u);\n const clientParticipantId =\n normalizeThresholdEd25519ParticipantId(input.clientParticipantId) ?? THRESHOLD_ED25519_CLIENT_PARTICIPANT_ID;\n const relayerParticipantId =\n normalizeThresholdEd25519ParticipantId(input.relayerParticipantId) ?? THRESHOLD_ED25519_RELAYER_PARTICIPANT_ID;\n\n const client: ThresholdEd25519ParticipantV1 = {\n id: clientParticipantId,\n role: 'client',\n ...(clientVerifyingShareB64u ? { verifyingShareB64u: clientVerifyingShareB64u } : {}),\n shareDerivation: input.clientShareDerivation || 'prf_first_v1',\n };\n\n const relayer: ThresholdEd25519ParticipantV1 = {\n id: relayerParticipantId,\n role: 'relayer',\n ...(relayerUrl ? { relayerUrl } : {}),\n ...(relayerKeyId ? { relayerKeyId } : {}),\n ...(relayerVerifyingShareB64u ? { verifyingShareB64u: relayerVerifyingShareB64u } : {}),\n ...(input.relayerShareDerivation ? { shareDerivation: input.relayerShareDerivation } : {}),\n };\n\n return [client, relayer];\n}\n","import { openDB, type IDBPDatabase } from 'idb';\nimport {\n buildThresholdEd25519Participants2pV1,\n parseThresholdEd25519ParticipantsV1,\n type ThresholdEd25519ParticipantV1,\n} from '../../threshold/participants';\n\nconst DB_CONFIG: PasskeyNearKeysDBConfig = {\n dbName: 'PasskeyNearKeys',\n // v4: allow storing multiple key materials per device (keyed by kind)\n dbVersion: 4,\n storeName: 'keyMaterial',\n keyPath: ['nearAccountId', 'deviceNumber', 'kind']\n} as const;\n\nexport type ClientShareDerivation = 'prf_first_v1';\n\nexport type PasskeyNearKeyMaterialKind =\n | 'local_near_sk_v3'\n | 'threshold_ed25519_2p_v1';\n\nexport interface BasePasskeyNearKeyMaterial {\n nearAccountId: string;\n deviceNumber: number; // 1-indexed device number\n kind: PasskeyNearKeyMaterialKind;\n /** NEAR ed25519 public key (e.g. `ed25519:...`) */\n publicKey: string;\n /** HKDF salt used alongside WrapKeySeed for KEK derivation */\n wrapKeySalt: string;\n timestamp: number;\n}\n\nexport interface LocalNearSkV3Material extends BasePasskeyNearKeyMaterial {\n kind: 'local_near_sk_v3';\n encryptedSk: string;\n /**\n * Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for `encryptedSk`.\n */\n chacha20NonceB64u: string;\n}\n\nexport interface ThresholdEd25519_2p_V1Material extends BasePasskeyNearKeyMaterial {\n kind: 'threshold_ed25519_2p_v1';\n relayerKeyId: string;\n clientShareDerivation: ClientShareDerivation;\n /**\n * Versioned participant list for future n-party support.\n * In 2P, participants are `{id:1, role:'client'}` and `{id:2, role:'relayer', ...}`.\n */\n participants: ThresholdEd25519ParticipantV1[];\n}\n\nexport type PasskeyNearKeyMaterial =\n | LocalNearSkV3Material\n | ThresholdEd25519_2p_V1Material;\n\ninterface PasskeyNearKeysDBConfig {\n dbName: string;\n dbVersion: number;\n storeName: string;\n keyPath: string | [string, string] | [string, string, string];\n}\n\nexport class PasskeyNearKeysDBManager {\n private config: PasskeyNearKeysDBConfig;\n private db: IDBPDatabase | null = null;\n private disabled = false;\n\n constructor(config: PasskeyNearKeysDBConfig = DB_CONFIG) {\n this.config = config;\n }\n\n getDbName(): string {\n return this.config.dbName;\n }\n\n setDbName(dbName: string): void {\n const next = String(dbName || '').trim();\n if (!next || next === this.config.dbName) return;\n try { (this.db as any)?.close?.(); } catch {}\n this.db = null;\n this.config = { ...this.config, dbName: next };\n }\n\n isDisabled(): boolean {\n return this.disabled;\n }\n\n setDisabled(disabled: boolean): void {\n const next = !!disabled;\n if (next === this.disabled) return;\n this.disabled = next;\n if (next) {\n try { (this.db as any)?.close?.(); } catch {}\n this.db = null;\n }\n }\n\n /**\n * Get database connection, initializing if necessary\n */\n private async getDB(): Promise<IDBPDatabase> {\n if (this.disabled) {\n throw new Error('[PasskeyNearKeysDBManager] IndexedDB is disabled in this environment.');\n }\n if (this.db) {\n return this.db;\n }\n\n this.db = await openDB(this.config.dbName, this.config.dbVersion, {\n upgrade(db): void {\n // Always recreate store with composite key; no migration.\n for (const name of ['encryptedKeys', DB_CONFIG.storeName]) {\n try { if (db.objectStoreNames.contains(name)) db.deleteObjectStore(name); } catch {}\n }\n const store = db.createObjectStore(DB_CONFIG.storeName, { keyPath: DB_CONFIG.keyPath });\n try { store.createIndex('nearAccountId', 'nearAccountId', { unique: false }); } catch {}\n try { store.createIndex('publicKey', 'publicKey', { unique: false }); } catch {}\n try { store.createIndex('kind', 'kind', { unique: false }); } catch {}\n },\n blocked() {\n console.warn('PasskeyNearKeysDB connection is blocked.');\n },\n blocking() {\n console.warn('PasskeyNearKeysDB connection is blocking another connection.');\n },\n terminated: () => {\n console.warn('PasskeyNearKeysDB connection has been terminated.');\n this.db = null;\n },\n });\n\n return this.db;\n }\n\n /**\n * Store encrypted key data\n */\n async storeKeyMaterial(data: PasskeyNearKeyMaterial): Promise<void> {\n const db = await this.getDB();\n if (!data.wrapKeySalt) {\n throw new Error('PasskeyNearKeysDB: Missing wrapKeySalt');\n }\n if (!data.publicKey) {\n throw new Error('PasskeyNearKeysDB: Missing publicKey');\n }\n\n if (data.kind === 'local_near_sk_v3') {\n if (!data.encryptedSk) {\n throw new Error('PasskeyNearKeysDB: Missing encryptedSk for local_near_sk_v3');\n }\n if (!data.chacha20NonceB64u) {\n throw new Error('PasskeyNearKeysDB: Missing chacha20NonceB64u for local_near_sk_v3');\n }\n } else if (data.kind === 'threshold_ed25519_2p_v1') {\n if (!data.relayerKeyId) {\n throw new Error('PasskeyNearKeysDB: Missing relayerKeyId for threshold_ed25519_2p_v1');\n }\n if (!data.clientShareDerivation) {\n throw new Error('PasskeyNearKeysDB: Missing clientShareDerivation for threshold_ed25519_2p_v1');\n }\n const parsed = parseThresholdEd25519ParticipantsV1(data.participants);\n data.participants = parsed || buildThresholdEd25519Participants2pV1({\n relayerKeyId: data.relayerKeyId,\n clientShareDerivation: data.clientShareDerivation,\n });\n }\n await db.put(this.config.storeName, data);\n }\n\n /**\n * Retrieve encrypted key data\n */\n async getKeyMaterial(\n nearAccountId: string,\n deviceNumber: number,\n kind: PasskeyNearKeyMaterialKind,\n ): Promise<PasskeyNearKeyMaterial | null> {\n const db = await this.getDB();\n if (!kind) {\n throw new Error('PasskeyNearKeysDB: kind is required (no fallback lookup is allowed)');\n }\n const sanitize = (rec: any): PasskeyNearKeyMaterial | null => {\n const kind = rec?.kind as PasskeyNearKeyMaterialKind | undefined;\n if (!rec?.nearAccountId || typeof rec?.deviceNumber !== 'number') return null;\n if (!kind) return null;\n if (!rec?.publicKey || !rec?.wrapKeySalt || typeof rec?.timestamp !== 'number') return null;\n\n if (kind === 'local_near_sk_v3') {\n if (!rec?.encryptedSk || !rec?.chacha20NonceB64u) return null;\n return {\n nearAccountId: rec.nearAccountId,\n deviceNumber: rec.deviceNumber,\n kind,\n publicKey: rec.publicKey,\n wrapKeySalt: rec.wrapKeySalt,\n encryptedSk: rec.encryptedSk,\n chacha20NonceB64u: rec.chacha20NonceB64u,\n timestamp: rec.timestamp,\n };\n }\n\n if (kind === 'threshold_ed25519_2p_v1') {\n if (!rec?.relayerKeyId || !rec?.clientShareDerivation) return null;\n const participants =\n parseThresholdEd25519ParticipantsV1(rec.participants)\n || buildThresholdEd25519Participants2pV1({\n relayerKeyId: rec.relayerKeyId,\n clientShareDerivation: rec.clientShareDerivation,\n });\n return {\n nearAccountId: rec.nearAccountId,\n deviceNumber: rec.deviceNumber,\n kind,\n publicKey: rec.publicKey,\n wrapKeySalt: rec.wrapKeySalt,\n relayerKeyId: rec.relayerKeyId,\n clientShareDerivation: rec.clientShareDerivation,\n participants,\n timestamp: rec.timestamp,\n };\n }\n\n return null;\n };\n\n const res = await db.get(this.config.storeName, [nearAccountId, deviceNumber, kind]);\n return sanitize(res);\n }\n\n async getLocalKeyMaterial(\n nearAccountId: string,\n deviceNumber: number\n ): Promise<LocalNearSkV3Material | null> {\n const rec = await this.getKeyMaterial(nearAccountId, deviceNumber, 'local_near_sk_v3');\n return rec?.kind === 'local_near_sk_v3' ? rec : null;\n }\n\n async getThresholdKeyMaterial(\n nearAccountId: string,\n deviceNumber: number\n ): Promise<ThresholdEd25519_2p_V1Material | null> {\n const rec = await this.getKeyMaterial(nearAccountId, deviceNumber, 'threshold_ed25519_2p_v1');\n return rec?.kind === 'threshold_ed25519_2p_v1' ? rec : null;\n }\n\n /**\n * Verify key storage by attempting retrieval\n */\n async verifyKeyStorage(\n nearAccountId: string,\n deviceNumber: number,\n kind: PasskeyNearKeyMaterialKind\n ): Promise<boolean> {\n const retrievedKey = await this.getKeyMaterial(nearAccountId, deviceNumber, kind);\n return !!retrievedKey;\n }\n\n /**\n * Delete encrypted key data for a specific account\n */\n async deleteKeyMaterial(nearAccountId: string, deviceNumber?: number, kind?: PasskeyNearKeyMaterialKind): Promise<void> {\n const db = await this.getDB();\n if (typeof deviceNumber === 'number' && kind) {\n await db.delete(this.config.storeName, [nearAccountId, deviceNumber, kind]);\n } else if (typeof deviceNumber === 'number') {\n // Delete all kinds for this deviceNumber\n const tx = db.transaction(this.config.storeName, 'readwrite');\n const idx = tx.store.index('nearAccountId');\n let cursor = await idx.openCursor(IDBKeyRange.only(nearAccountId));\n while (cursor) {\n const value: any = cursor.value;\n if (value?.deviceNumber === deviceNumber) {\n await tx.store.delete(cursor.primaryKey);\n }\n cursor = await cursor.continue();\n }\n await tx.done;\n } else {\n // Delete all keys for this account if device unspecified\n const tx = db.transaction(this.config.storeName, 'readwrite');\n const idx = tx.store.index('nearAccountId');\n let cursor = await idx.openCursor(IDBKeyRange.only(nearAccountId));\n while (cursor) {\n await tx.store.delete(cursor.primaryKey);\n cursor = await cursor.continue();\n }\n await tx.done;\n }\n console.debug('PasskeyNearKeysDB: deleteKeyMaterial - Successfully deleted');\n }\n\n /**\n * Get all encrypted keys (for migration or debugging purposes)\n */\n async getAllKeyMaterial(): Promise<PasskeyNearKeyMaterial[]> {\n const db = await this.getDB();\n const all = await db.getAll(this.config.storeName);\n return (all as any[])\n .map((rec) => {\n const kind = rec?.kind as PasskeyNearKeyMaterialKind | undefined;\n if (!kind) return null;\n\n if (kind === 'local_near_sk_v3') {\n if (!rec?.encryptedSk || !rec?.chacha20NonceB64u) return null;\n return {\n nearAccountId: rec.nearAccountId,\n deviceNumber: rec.deviceNumber,\n kind,\n publicKey: rec.publicKey,\n wrapKeySalt: rec.wrapKeySalt,\n encryptedSk: rec.encryptedSk,\n chacha20NonceB64u: rec.chacha20NonceB64u,\n timestamp: rec.timestamp,\n } as LocalNearSkV3Material;\n }\n\n if (kind === 'threshold_ed25519_2p_v1') {\n if (!rec?.relayerKeyId || !rec?.clientShareDerivation) return null;\n const participants =\n parseThresholdEd25519ParticipantsV1(rec.participants)\n || buildThresholdEd25519Participants2pV1({\n relayerKeyId: rec.relayerKeyId,\n clientShareDerivation: rec.clientShareDerivation,\n });\n return {\n nearAccountId: rec.nearAccountId,\n deviceNumber: rec.deviceNumber,\n kind,\n publicKey: rec.publicKey,\n wrapKeySalt: rec.wrapKeySalt,\n relayerKeyId: rec.relayerKeyId,\n clientShareDerivation: rec.clientShareDerivation,\n participants,\n timestamp: rec.timestamp,\n } as ThresholdEd25519_2p_V1Material;\n }\n\n return null;\n })\n .filter((rec): rec is PasskeyNearKeyMaterial => rec !== null);\n }\n\n /**\n * Check if a key exists for the given account\n */\n async hasKeyMaterial(\n nearAccountId: string,\n deviceNumber: number,\n kind: PasskeyNearKeyMaterialKind\n ): Promise<boolean> {\n const keyData = await this.getKeyMaterial(nearAccountId, deviceNumber, kind);\n return !!keyData;\n }\n}\n","export { PasskeyClientDBManager } from './passkeyClientDB';\nexport { PasskeyNearKeysDBManager } from './passkeyNearKeysDB';\n\nexport type {\n ClientUserData,\n UserPreferences,\n ClientAuthenticatorData,\n IndexedDBEvent,\n DerivedAddressRecord,\n RecoveryEmailRecord\n} from './passkeyClientDB';\n\nexport type {\n PasskeyNearKeyMaterial,\n LocalNearSkV3Material,\n ThresholdEd25519_2p_V1Material,\n PasskeyNearKeyMaterialKind,\n ClientShareDerivation,\n} from './passkeyNearKeysDB';\n\nimport { AccountId } from '../types/accountIds';\n\n// === SINGLETON INSTANCES ===\nimport { PasskeyClientDBManager, type ClientUserData } from './passkeyClientDB';\nimport { PasskeyNearKeysDBManager, type PasskeyNearKeyMaterial } from './passkeyNearKeysDB';\n\n// Export singleton instances for backward compatibility with existing code\nexport const passkeyClientDB = new PasskeyClientDBManager();\nexport const passkeyNearKeysDB = new PasskeyNearKeysDBManager();\n\nexport type IndexedDBMode = 'legacy' | 'wallet' | 'disabled';\n\nconst DB_CONFIG_BY_MODE: Record<IndexedDBMode, { clientDbName: string; nearKeysDbName: string; disabled: boolean }> = {\n legacy: { clientDbName: 'PasskeyClientDB', nearKeysDbName: 'PasskeyNearKeys', disabled: false },\n wallet: { clientDbName: 'PasskeyClientDB', nearKeysDbName: 'PasskeyNearKeys', disabled: false },\n // When running the SDK on the app origin with a wallet iframe configured, we disable IndexedDB entirely\n // to ensure no SDK tables are created and nothing can accidentally persist there.\n disabled: { clientDbName: 'PasskeyClientDB', nearKeysDbName: 'PasskeyNearKeys', disabled: true },\n};\n\nlet configured: { mode: IndexedDBMode; clientDbName: string; nearKeysDbName: string; disabled: boolean } | null = null;\n\n/**\n * Configure IndexedDB database names for the current runtime.\n *\n * Call this once, early (before any IndexedDB access).\n * - Wallet iframe host should use `mode: 'wallet'`.\n * - App origin should use `mode: 'disabled'` when wallet-iframe mode is enabled.\n * - Non-iframe apps should use `mode: 'legacy'`.\n */\nexport function configureIndexedDB(args: { mode: IndexedDBMode }): { clientDbName: string; nearKeysDbName: string } {\n const mode = args?.mode;\n const next = DB_CONFIG_BY_MODE[mode];\n if (!next) {\n throw new Error(`[IndexedDBManager] Unknown IndexedDBMode: ${String(mode)}`);\n }\n\n if (configured) {\n const isSame =\n configured.clientDbName === next.clientDbName\n && configured.nearKeysDbName === next.nearKeysDbName\n && configured.disabled === next.disabled;\n if (!isSame) {\n console.warn('[IndexedDBManager] configureIndexedDB called multiple times; ignoring subsequent configuration', {\n configured,\n requested: next,\n });\n }\n return { clientDbName: configured.clientDbName, nearKeysDbName: configured.nearKeysDbName };\n }\n\n configured = { mode, ...next };\n passkeyClientDB.setDbName(next.clientDbName);\n passkeyNearKeysDB.setDbName(next.nearKeysDbName);\n passkeyClientDB.setDisabled(next.disabled);\n passkeyNearKeysDB.setDisabled(next.disabled);\n return { clientDbName: configured.clientDbName, nearKeysDbName: configured.nearKeysDbName };\n}\n\nexport function getIndexedDBNames(): { clientDbName: string; nearKeysDbName: string } {\n return configured || {\n clientDbName: passkeyClientDB.getDbName(),\n nearKeysDbName: passkeyNearKeysDB.getDbName(),\n };\n}\n\n/**\n * Unified IndexedDB interface providing access to both databases\n * This allows centralized access while maintaining separation of concerns\n */\nexport class UnifiedIndexedDBManager {\n public readonly clientDB: PasskeyClientDBManager;\n public readonly nearKeysDB: PasskeyNearKeysDBManager;\n private _initialized = false;\n\n constructor() {\n this.clientDB = passkeyClientDB;\n this.nearKeysDB = passkeyNearKeysDB;\n }\n\n /**\n * Initialize both databases proactively\n * This ensures both databases are created and ready for use\n */\n async initialize(): Promise<void> {\n if (this._initialized) {\n return;\n }\n\n try {\n if (this.clientDB.isDisabled() || this.nearKeysDB.isDisabled()) {\n this._initialized = true;\n return;\n }\n // Initialize both databases by calling a simple operation\n // This will trigger the getDB() method in both managers and ensure databases are created\n await Promise.all([\n this.clientDB.getAppState('_init_check'),\n this.nearKeysDB.hasKeyMaterial('_init_check', 1, 'local_near_sk_v3')\n ]);\n\n this._initialized = true;\n } catch (error) {\n console.warn('Failed to initialize IndexedDB databases:', error);\n // Don't throw - allow the SDK to continue working, databases will be initialized on first use\n }\n }\n\n /**\n * Check if databases have been initialized\n */\n get isInitialized(): boolean {\n return this._initialized;\n }\n\n // === CONVENIENCE METHODS ===\n\n /**\n * Get user data and check if they have encrypted NEAR keys\n */\n async getUserWithKeys(nearAccountId: AccountId): Promise<{\n userData: ClientUserData | null;\n hasKeys: boolean;\n keyMaterial?: PasskeyNearKeyMaterial | null;\n }> {\n const last = await this.clientDB.getLastUser();\n const userData = last && last.nearAccountId === nearAccountId\n ? last\n : await this.clientDB.getUserByDevice(nearAccountId, 1);\n const deviceNumber = (last && last.nearAccountId === nearAccountId)\n ? last.deviceNumber\n : userData?.deviceNumber!;\n const [local, threshold] = await Promise.all([\n this.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber),\n this.nearKeysDB.getThresholdKeyMaterial(nearAccountId, deviceNumber),\n ]);\n const keyData = local ?? threshold;\n const hasKeys = !!keyData;\n\n return {\n userData,\n hasKeys,\n keyMaterial: hasKeys ? keyData : undefined\n };\n }\n\n // === Derived addresses convenience ===\n async setDerivedAddress(\n nearAccountId: AccountId,\n args: { contractId: string; path: string; address: string }\n ): Promise<void> {\n return this.clientDB.setDerivedAddress(nearAccountId, args);\n }\n\n async getDerivedAddressRecord(\n nearAccountId: AccountId,\n args: { contractId: string; path: string }\n ): Promise<import('./passkeyClientDB').DerivedAddressRecord | null> {\n return this.clientDB.getDerivedAddressRecord(nearAccountId, args);\n }\n\n async getDerivedAddress(\n nearAccountId: AccountId,\n args: { contractId: string; path: string }\n ): Promise<string | null> {\n return this.clientDB.getDerivedAddress(nearAccountId, args);\n }\n\n // === Recovery emails convenience ===\n async upsertRecoveryEmails(\n nearAccountId: AccountId,\n entries: Array<{ hashHex: string; email: string }>\n ): Promise<void> {\n return this.clientDB.upsertRecoveryEmails(nearAccountId, entries);\n }\n\n async getRecoveryEmails(nearAccountId: AccountId): Promise<import('./passkeyClientDB').RecoveryEmailRecord[]> {\n return this.clientDB.getRecoveryEmails(nearAccountId);\n }\n}\n\n// Export singleton instance of unified manager\nexport const IndexedDBManager = new UnifiedIndexedDBManager();\n","import { RpcResponse } from './types/rpc';\n\ntype NearRpcErrorType = 'InvalidTxError' | 'ActionError' | 'TxExecutionError' | 'RpcError' | 'Failure' | 'Unknown';\n\nfunction isObj(v: unknown): v is Record<string, unknown> {\n return !!v && typeof v === 'object' && !Array.isArray(v);\n}\n\nfunction firstKey(o: Record<string, unknown> | undefined): string | undefined {\n if (!o) return undefined;\n const keys = Object.keys(o);\n return keys.length ? keys[0] : undefined;\n}\n\nexport class NearRpcError extends Error {\n code?: number;\n type: NearRpcErrorType;\n kind?: string;\n index?: number;\n short: string;\n details?: unknown;\n operation?: string;\n\n constructor(params: {\n message: string;\n short: string;\n type?: NearRpcErrorType;\n kind?: string;\n index?: number;\n code?: number;\n name?: string;\n operation?: string;\n details?: unknown;\n }) {\n super(params.message);\n this.name = params.name || 'NearRpcError';\n this.code = params.code;\n this.type = params.type || 'Unknown';\n this.kind = params.kind;\n this.index = params.index;\n this.short = params.short;\n this.details = params.details;\n this.operation = params.operation;\n }\n\n static fromRpcResponse(operationName: string, rpc: RpcResponse): NearRpcError {\n const err = rpc.error || {};\n const details = err.data as unknown;\n\n const { message, type, kind, index, short } = describeDetails(operationName, details);\n\n return new NearRpcError({\n message: message || err.message || `${operationName} RPC error`,\n short: short || kind || 'RPC error',\n type: type || 'RpcError',\n kind,\n index,\n code: err.code,\n name: err.name || 'NearRpcError',\n operation: operationName,\n details,\n });\n }\n\n static fromOutcome(operationName: string, outcome: any, failure: any): NearRpcError {\n const { message, type, kind, index, short } = describeFailure(operationName, failure);\n return new NearRpcError({\n message: message || `${operationName} failed`,\n short: short || kind || 'TxExecutionError',\n type: type || 'Failure',\n kind,\n index,\n name: 'TxExecutionFailure',\n operation: operationName,\n details: { Failure: failure, outcome },\n });\n }\n}\n\nfunction describeDetails(operationName: string, details: unknown): {\n message: string;\n type?: NearRpcErrorType;\n kind?: string;\n index?: number;\n short?: string;\n} {\n const d = isObj(details) ? details : undefined;\n const txExec = isObj(d?.TxExecutionError) ? (d!.TxExecutionError as Record<string, unknown>) : undefined;\n if (!txExec) {\n const dataStr = d ? ` Details: ${JSON.stringify(d)}` : '';\n return { message: `${operationName} RPC error.${dataStr}` };\n }\n return describeTxExecution(operationName, txExec);\n}\n\nfunction describeFailure(operationName: string, failure: any): {\n message: string;\n type?: NearRpcErrorType;\n kind?: string;\n index?: number;\n short?: string;\n} {\n const f = isObj(failure) ? (failure as Record<string, unknown>) : undefined;\n if (!f) {\n return { message: `${operationName} failed (Unknown Failure)` };\n }\n // Reuse TxExecutionError shape if available\n return describeTxExecution(operationName, f as Record<string, unknown>);\n}\n\nfunction describeTxExecution(operationName: string, exec: Record<string, unknown>): {\n message: string;\n type?: NearRpcErrorType;\n kind?: string;\n index?: number;\n short?: string;\n} {\n // InvalidTxError\n if (isObj(exec.InvalidTxError)) {\n const inv = exec.InvalidTxError as Record<string, unknown>;\n let kind = firstKey(inv) || 'InvalidTxError';\n if (isObj(inv.ActionsValidation)) {\n kind = `ActionsValidation.${firstKey(inv.ActionsValidation as Record<string, unknown>)}`;\n }\n const short = kind.startsWith('ActionsValidation.')\n ? `InvalidTxError: ${kind.split('.')[1] || 'ActionsValidation'}`\n : `InvalidTxError: ${kind}`;\n return {\n message: `${operationName} failed (InvalidTxError: ${kind})`,\n type: 'InvalidTxError',\n kind,\n short,\n };\n }\n\n // ActionError\n if (isObj(exec.ActionError)) {\n const ae = exec.ActionError as Record<string, unknown>;\n const idx = typeof (ae.index as unknown) === 'number' ? (ae.index as number) : undefined;\n const kobj = isObj(ae.kind) ? (ae.kind as Record<string, unknown>) : undefined;\n const kind = firstKey(kobj) || 'ActionError';\n const idxStr = typeof idx === 'number' ? ` at action ${idx}` : '';\n const short = `ActionError: ${kind}`;\n return {\n message: `${operationName} failed${idxStr} (ActionError: ${kind})`,\n type: 'ActionError',\n kind,\n index: idx,\n short,\n };\n }\n\n // Fallback TxExecutionError without specifics\n return {\n message: `${operationName} failed (TxExecutionError)`,\n type: 'TxExecutionError',\n kind: 'TxExecutionError',\n short: 'TxExecutionError',\n };\n}\n","import type { AccessKeyView, TxExecutionStatus } from \"@near-js/types\";\n\nexport const DEFAULT_WAIT_STATUS = {\n executeAction: \"EXECUTED_OPTIMISTIC\" as TxExecutionStatus,\n linkDeviceAddKey: \"INCLUDED_FINAL\" as TxExecutionStatus,\n // Threshold AddKey is safe to treat optimistically; finality will converge shortly after.\n thresholdAddKey: \"EXECUTED_OPTIMISTIC\" as TxExecutionStatus,\n linkDeviceSwapKey: \"FINAL\" as TxExecutionStatus,\n linkDeviceAccountMapping: \"INCLUDED_FINAL\" as TxExecutionStatus,\n linkDeviceDeleteKey: \"INCLUDED_FINAL\" as TxExecutionStatus,\n linkDeviceRegistration: \"FINAL\" as TxExecutionStatus,\n // See default finality settings:\n // https://github.com/near/near-api-js/blob/99f34864317725467a097dc3c7a3cc5f7a5b43d4/packages/accounts/src/account.ts#L68\n}\n\n// Transaction and Signature types - defined as TypeScript interfaces since they're handled as JSON\nexport interface TransactionStruct {\n signerAccount: string;\n publicKey: {\n keyType: number;\n keyData: number[];\n };\n nonce: number;\n receiverAccount: string;\n blockHash: number[];\n actions: any[]; // Actions are complex, handled as JSON\n}\n\nexport interface SignatureStruct {\n keyType: number;\n signatureData: number[];\n}\n\nexport interface NearRpcCallParams {\n jsonrpc: string;\n id: string;\n method: string;\n params: {\n signed_tx_base64: string;\n wait_until: TxExecutionStatus;\n }\n}\n\nexport interface TransactionContext {\n nearPublicKeyStr: string;\n accessKeyInfo: AccessKeyView;\n nextNonce: string;\n txBlockHeight: string;\n txBlockHash: string;\n}\n\nexport interface BlockInfo {\n header: {\n hash: string;\n height: number;\n };\n}\nexport interface RpcErrorData {\n // NEAR error payloads vary; keep flexible but preserve common fields\n // Top-level helper message if present\n message?: string;\n // Anything else from the node (TxExecutionError, ActionError, etc.)\n [key: string]: any;\n}\n\nexport interface RpcError {\n code?: number;\n name?: string;\n data?: RpcErrorData;\n message?: string;\n}\n\nexport interface RpcResponse {\n error?: RpcError;\n result?: any;\n}\n","/**\n * Minimal NEAR RPC client that replaces @near-js/providers\n * Only includes the methods actually used by TatchiPasskey\n *\n * If needed, we can just wrap @near-js if we require more complex\n * functionality and type definitions\n */\n\nimport type {\n FinalExecutionOutcome,\n QueryResponseKind,\n TxExecutionStatus,\n AccessKeyView,\n AccessKeyInfoView,\n AccessKeyList,\n FunctionCallPermissionView,\n AccountView,\n BlockResult,\n BlockReference,\n RpcQueryRequest,\n FinalityReference,\n} from \"@near-js/types\";\nimport { base64Encode, base64Decode } from \"../utils\";\nimport { errorMessage } from \"../utils/errors\";\nimport { NearRpcError } from \"./NearRpcError\";\nimport { DEFAULT_WAIT_STATUS, RpcResponse } from \"./types/rpc\";\nimport { isFunction } from '@/utils/validation';\nimport {\n WasmTransaction,\n WasmSignature,\n} from \"../wasm_signer_worker/pkg/wasm_signer_worker.js\";\n\n// re-export near-js types\nexport type { AccessKeyList } from \"@near-js/types\";\n\nexport interface ViewAccountParams {\n account: string;\n block_id?: string;\n}\n\nexport type FullAccessKey = Omit<AccessKeyInfoView, 'access_key'>\n & { access_key: Omit<AccessKeyView, 'permission'> & { permission: 'FullAccess' } }\n\nexport type FunctionCallAccessKey = Omit<AccessKeyInfoView, 'access_key'>\n & { access_key: Omit<AccessKeyView, 'permission'> & { permission: FunctionCallPermissionView } }\n\nexport interface ContractResult<T> extends QueryResponseKind {\n result?: T | string | number;\n logs: string[];\n}\n\nexport enum RpcCallType {\n Query = \"query\",\n View = \"view\",\n Send = \"send_tx\",\n Block = \"block\",\n Call = \"call_function\",\n}\n\nexport class SignedTransaction {\n transaction: WasmTransaction;\n signature: WasmSignature;\n borsh_bytes: number[];\n\n constructor(data: {\n transaction: WasmTransaction;\n signature: WasmSignature;\n borsh_bytes: number[]\n }) {\n this.transaction = data.transaction;\n this.signature = data.signature;\n this.borsh_bytes = data.borsh_bytes;\n }\n\n static fromPlain(input: { transaction: unknown; signature: unknown; borsh_bytes: number[] }): SignedTransaction {\n return new SignedTransaction({\n transaction: input.transaction as WasmTransaction,\n signature: input.signature as WasmSignature,\n borsh_bytes: input.borsh_bytes,\n });\n }\n\n encode(): ArrayBuffer {\n // If borsh_bytes are already available, use them\n return (new Uint8Array(this.borsh_bytes)).buffer;\n }\n\n base64Encode(): string {\n return base64Encode(this.encode());\n }\n\n static decode(bytes: Uint8Array): SignedTransaction {\n // This would need borsh deserialization\n throw new Error('SignedTransaction.decode(): borsh deserialization not implemented');\n }\n}\n\n/**\n * Serialize a signed transaction-like object to base64.\n * Accepts either our SignedTransaction instance or a plain object\n * with borsh bytes (borsh_bytes | borshBytes) from cross-origin RPC.\n *\n * Implementation notes / pitfalls:\n * - We always bind `this` correctly when calling .base64Encode() / .encode()\n * so methods defined on SignedTransaction can safely call this.encode().\n * - The underlying base64Encode() helper is implemented to avoid spreading large\n * Uint8Arrays into String.fromCharCode(...), which can overflow the JS call\n * stack for big WASM binaries or large transactions.\n * - As a fallback, we accept raw borsh bytes in multiple shapes to keep the\n * serializer resilient to different runtimes (plain objects, typed arrays, etc.).\n */\nexport type EncodableSignedTx =\n | SignedTransaction\n | {\n // Borsh bytes in various shapes from different runtimes\n borsh_bytes?: unknown;\n borshBytes?: unknown;\n // Optional helper methods from some callers\n encode?: () => ArrayBuffer;\n base64Encode?: () => string;\n };\n\nexport function toArrayBufferFromUnknownBytes(\n bytes: unknown\n): ArrayBuffer | SharedArrayBuffer | null {\n if (!bytes) return null;\n\n // Plain number[]\n if (Array.isArray(bytes)) {\n return new Uint8Array(bytes as number[]).buffer;\n }\n\n // Typed arrays / DataView\n if (ArrayBuffer.isView(bytes)) {\n const view = bytes as ArrayBufferView;\n return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength);\n }\n\n // Raw ArrayBuffer\n if (bytes instanceof ArrayBuffer) {\n return bytes;\n }\n\n return null;\n}\n\nexport function encodeSignedTransactionBase64(signed: EncodableSignedTx): string {\n // Some call sites wrap the actual SignedTransaction in a { signedTransaction } envelope.\n // Normalize that here so the rest of the function always works with a concrete tx-like object.\n const maybeSigned = (signed as any)?.signedTransaction;\n const txPayload: EncodableSignedTx =\n maybeSigned && typeof maybeSigned === 'object'\n ? (maybeSigned as EncodableSignedTx)\n : signed;\n\n // 1) If the payload exposes a .base64Encode() helper (our SignedTransaction class),\n // use it directly. Bind `this` so the method can safely call this.encode().\n const maybeBase64 = (txPayload as { base64Encode?: unknown }).base64Encode;\n if (isFunction(maybeBase64)) {\n return (maybeBase64 as () => string).call(txPayload);\n }\n\n // 2) Otherwise, fall back to a generic encode() → ArrayBuffer method if present.\n const maybeEncode = (txPayload as { encode?: unknown }).encode;\n if (isFunction(maybeEncode)) {\n const buf = (maybeEncode as () => ArrayBuffer).call(txPayload);\n return base64Encode(buf);\n }\n\n // 3) Finally, accept raw borsh bytes in multiple shapes / field names.\n // This keeps the serializer resilient across runtimes that may not\n // hydrate SignedTransaction instances but still provide borsh_bytes/Bytes.\n const snakeBuf = toArrayBufferFromUnknownBytes(\n (txPayload as { borsh_bytes?: unknown }).borsh_bytes\n );\n if (snakeBuf) {\n return base64Encode(snakeBuf);\n }\n\n const camelBuf = toArrayBufferFromUnknownBytes(\n (txPayload as { borshBytes?: unknown }).borshBytes\n );\n if (camelBuf) {\n return base64Encode(camelBuf);\n }\n\n throw new Error('Invalid signed transaction payload: cannot serialize to base64');\n}\n\n/**\n * MinimalNearClient provides a simplified interface for NEAR protocol interactions\n */\nexport interface NearClient {\n viewAccessKey(accountId: string, publicKey: string, finalityQuery?: FinalityReference): Promise<AccessKeyView>;\n viewAccessKeyList(accountId: string, finalityQuery?: FinalityReference): Promise<AccessKeyList>;\n viewAccount(accountId: string): Promise<AccountView>;\n viewCode(accountId: string, finalityQuery?: FinalityReference): Promise<Uint8Array>;\n viewBlock(params: BlockReference): Promise<BlockResult>;\n sendTransaction(\n signedTransaction: SignedTransaction,\n waitUntil?: TxExecutionStatus\n ): Promise<FinalExecutionOutcome>;\n txStatus(txHash: string, senderAccountId: string): Promise<FinalExecutionOutcome>;\n query<T extends QueryResponseKind>(params: RpcQueryRequest): Promise<T>;\n callFunction<A, T>(\n contractId: string,\n method: string,\n args: A,\n blockQuery?: BlockReference\n ): Promise<T>;\n view<A, T>(params: { account: string; method: string; args: A }): Promise<T>;\n getAccessKeys(params: ViewAccountParams): Promise<{\n fullAccessKeys: FullAccessKey[];\n functionCallAccessKeys: FunctionCallAccessKey[];\n }>;\n}\n\nexport class MinimalNearClient implements NearClient {\n private readonly rpcUrls: string[];\n\n constructor(rpcUrl: string | string[]) {\n this.rpcUrls = MinimalNearClient.normalizeRpcUrls(rpcUrl);\n }\n\n private static normalizeRpcUrls(input: string | string[]): string[] {\n const urls = Array.isArray(input)\n ? input\n : input\n .split(/[\\s,]+/)\n .map(url => url.trim())\n .filter(Boolean);\n\n const normalized = urls.map(url => {\n try {\n return new URL(url).toString();\n } catch (err) {\n const message = errorMessage(err) || `Invalid NEAR RPC URL: ${url}`;\n throw new Error(message);\n }\n });\n\n if (!normalized.length) {\n throw new Error('NEAR RPC URL cannot be empty');\n }\n\n return Array.from(new Set(normalized));\n }\n\n // ===========================\n // PRIVATE HELPER FUNCTIONS\n // ===========================\n\n /** Build a JSON-RPC 2.0 POST body (stringified). */\n private buildRequestBody<P>(method: string, params: P): string {\n return JSON.stringify({\n jsonrpc: '2.0',\n id: crypto.randomUUID(),\n method,\n params\n });\n }\n\n /** Perform a single POST to one endpoint and return parsed RpcResponse. */\n private async postOnce(url: string, requestBody: string): Promise<RpcResponse> {\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: requestBody\n });\n\n if (!response.ok) {\n throw new Error(`RPC request failed: ${response.status} ${response.statusText}`);\n }\n\n const text = await response.text();\n if (!text?.trim()) {\n throw new Error('Empty response from RPC server');\n }\n\n return JSON.parse(text) as RpcResponse;\n }\n\n /** Try each configured RPC endpoint in order and return the first successful RpcResponse. */\n private async requestWithFallback(requestBody: string): Promise<RpcResponse> {\n let lastError: unknown;\n for (const [index, url] of this.rpcUrls.entries()) {\n try {\n const result = await this.postOnce(url, requestBody);\n if (index > 0) console.warn(`[NearClient] RPC succeeded via fallback: ${url}`);\n return result;\n } catch (err) {\n lastError = err;\n const remaining = index < this.rpcUrls.length - 1;\n console.warn(`[NearClient] RPC call to ${url} failed${remaining ? ', trying next' : ''}: ${errorMessage(err) || 'RPC request failed'}`);\n if (!remaining) throw err instanceof Error ? err : new Error(String(err));\n }\n }\n throw new Error(errorMessage(lastError) || 'RPC request failed');\n }\n\n /** Validate and unwrap RpcResponse into the typed result with rich error forwarding. */\n private unwrapRpcResult<T>(rpc: RpcResponse, operationName: string): T {\n if (rpc.error) {\n throw NearRpcError.fromRpcResponse(operationName, rpc);\n }\n const result = rpc.result as any;\n // Some providers return a wrapped error in `result.error`\n if (result?.error) {\n const msg = typeof result.error === 'string' ? result.error : JSON.stringify(result.error);\n throw new NearRpcError({ message: `${operationName} Error: ${msg}`, short: 'RpcError', type: 'RpcError' });\n }\n return rpc.result as T;\n }\n\n /**\n * Execute RPC call with proper error handling and result extraction\n */\n private async makeRpcCall<P, T>(\n method: string,\n params: P,\n operationName: string\n ): Promise<T> {\n const requestBody = this.buildRequestBody(method, params);\n const rpc = await this.requestWithFallback(requestBody);\n return this.unwrapRpcResult<T>(rpc, operationName);\n }\n\n // ===========================\n // PUBLIC API METHODS\n // ===========================\n\n async query<T extends QueryResponseKind>(params: RpcQueryRequest): Promise<T> {\n return this.makeRpcCall<RpcQueryRequest, T>(RpcCallType.Query, params, 'Query');\n }\n\n async viewAccessKey(accountId: string, publicKey: string, finalityQuery?: FinalityReference): Promise<AccessKeyView> {\n const publicKeyStr = publicKey;\n const finality = finalityQuery?.finality || 'final';\n const params = {\n request_type: 'view_access_key',\n finality: finality,\n account_id: accountId,\n public_key: publicKeyStr\n };\n return this.makeRpcCall<typeof params, AccessKeyView>(\n RpcCallType.Query,\n params,\n 'View Access Key'\n );\n }\n\n async viewAccessKeyList(accountId: string, finalityQuery?: FinalityReference): Promise<AccessKeyList> {\n const finality = finalityQuery?.finality || 'final';\n const params = {\n request_type: 'view_access_key_list',\n finality: finality,\n account_id: accountId\n };\n return this.makeRpcCall<typeof params, AccessKeyList>(RpcCallType.Query, params, 'View Access Key List');\n }\n\n async viewAccount(accountId: string): Promise<AccountView> {\n const params = {\n request_type: 'view_account',\n finality: 'final',\n account_id: accountId\n };\n return this.makeRpcCall<typeof params, AccountView>(RpcCallType.Query, params, 'View Account');\n }\n\n async viewCode(accountId: string, finalityQuery?: FinalityReference): Promise<Uint8Array> {\n const finality = finalityQuery?.finality || 'final';\n const params = {\n request_type: 'view_code',\n finality,\n account_id: accountId\n };\n const result = await this.makeRpcCall<typeof params, any>(\n RpcCallType.Query,\n params,\n 'View Code'\n );\n const codeBase64 = result?.code_base64;\n if (typeof codeBase64 !== 'string' || !codeBase64.length) {\n throw new Error('Invalid View Code response: missing code_base64');\n }\n return base64Decode(codeBase64);\n }\n\n async viewBlock(params: BlockReference): Promise<BlockResult> {\n return this.makeRpcCall<BlockReference, BlockResult>(RpcCallType.Block, params, 'View Block');\n }\n\n async sendTransaction(\n signedTransaction: SignedTransaction,\n waitUntil: TxExecutionStatus = DEFAULT_WAIT_STATUS.executeAction\n ): Promise<FinalExecutionOutcome> {\n const params = {\n signed_tx_base64: encodeSignedTransactionBase64(signedTransaction),\n wait_until: waitUntil\n };\n\n // Retry on transient RPC errors commonly seen with shared/public nodes\n const maxAttempts = 5;\n let lastError: unknown = null;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n const outcome = await this.makeRpcCall<typeof params, FinalExecutionOutcome>(RpcCallType.Send, params, 'Send Transaction');\n // near-api-js throws on Failure; replicate that for clearer UX\n const status = (outcome as any)?.status;\n if (status && typeof status === 'object' && 'Failure' in status) {\n const failure = (status as any).Failure;\n throw NearRpcError.fromOutcome('Send Transaction', outcome, failure);\n }\n return outcome;\n } catch (err: unknown) {\n lastError = err;\n const msg = errorMessage(err);\n const retryable = /server error|internal|temporar|timeout|too many requests|429|unavailable|bad gateway|gateway timeout/i.test(msg || '');\n if (!retryable || attempt === maxAttempts) {\n throw err;\n }\n // Exponential backoff with jitter (200–1200ms approx across attempts)\n const base = 200 * Math.pow(2, attempt - 1);\n const jitter = Math.floor(Math.random() * 150);\n await new Promise(r => setTimeout(r, base + jitter));\n }\n }\n // Should be unreachable\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n }\n\n async txStatus(txHash: string, senderAccountId: string): Promise<FinalExecutionOutcome> {\n const params = {\n tx_hash: txHash,\n sender_account_id: senderAccountId,\n };\n return this.makeRpcCall<typeof params, FinalExecutionOutcome>(\n 'EXPERIMENTAL_tx_status',\n params,\n 'Tx Status'\n );\n }\n\n // legacy helpers removed in favor of NearRpcError\n\n async callFunction<A, T>(\n contractId: string,\n method: string,\n args: A,\n blockQuery?: BlockReference\n ): Promise<T> {\n const rpcParams = {\n request_type: 'call_function',\n finality: 'final',\n account_id: contractId,\n method_name: method,\n args_base64: base64Encode(new TextEncoder().encode(JSON.stringify(args)).buffer)\n };\n const result = await this.makeRpcCall<typeof rpcParams, ContractResult<T>>(\n RpcCallType.Query,\n rpcParams,\n 'View Function'\n );\n\n // Parse result bytes to string/JSON\n const resultBytes = result.result;\n\n if (!Array.isArray(resultBytes)) {\n // If result is not bytes array, it might already be parsed\n return result as unknown as T;\n }\n\n const resultString = String.fromCharCode(...resultBytes);\n\n if (!resultString.trim()) {\n return null as T;\n }\n\n try {\n const parsed = JSON.parse(resultString);\n return parsed as T;\n } catch (parseError) {\n console.warn('Failed to parse result as JSON, returning as string:', parseError);\n console.warn('Raw result string:', resultString);\n // Return the string value if it's not valid JSON\n const cleanString = resultString.replace(/^\"|\"$/g, ''); // Remove quotes\n return cleanString as T;\n }\n }\n\n async view<A, T>(params: { account: string; method: string; args: A }): Promise<T> {\n return this.callFunction<A, T>(params.account, params.method, params.args);\n }\n\n async getAccessKeys({ account, block_id }: ViewAccountParams): Promise<{\n fullAccessKeys: FullAccessKey[];\n functionCallAccessKeys: FunctionCallAccessKey[];\n }> {\n // Build RPC parameters similar to the official implementation\n const params: Record<string, unknown> = {\n request_type: 'view_access_key_list',\n account_id: account,\n finality: 'final'\n };\n\n // Add block_id if provided (for specific block queries)\n if (block_id) {\n params.block_id = block_id;\n delete params.finality; // block_id takes precedence over finality\n }\n\n // Make the RPC call directly to match the official implementation\n const accessKeyList = await this.makeRpcCall<typeof params, AccessKeyList>(\n RpcCallType.Query,\n params,\n 'View Access Key List'\n );\n\n // Separate full access keys and function call access keys\n const fullAccessKeys: FullAccessKey[] = [];\n const functionCallAccessKeys: FunctionCallAccessKey[] = [];\n\n // Process each access key (matching the official categorization logic)\n for (const key of accessKeyList.keys) {\n if (key.access_key.permission === 'FullAccess') {\n // Full Access Keys: Keys with FullAccess permission\n fullAccessKeys.push(key as FullAccessKey);\n } else if (key.access_key.permission && typeof key.access_key.permission === 'object' && 'FunctionCall' in key.access_key.permission) {\n // Function Call Keys: Keys with limited permissions for specific contract calls\n functionCallAccessKeys.push(key as FunctionCallAccessKey);\n }\n }\n\n return {\n fullAccessKeys,\n functionCallAccessKeys\n };\n }\n}\n","export const OFFLINE_EXPORT_DONE = 'OFFLINE_EXPORT_DONE';\nexport const OFFLINE_EXPORT_ERROR = 'OFFLINE_EXPORT_ERROR';\n\n// Posted by wallet host to request parent fallback to the offline route\nexport const OFFLINE_EXPORT_FALLBACK = 'OFFLINE_EXPORT_FALLBACK';\n\n// Reused wallet-iframe close notification\nexport const WALLET_UI_CLOSED = 'WALLET_UI_CLOSED';\n\n// Export UI: user explicitly cancelled TouchID/FaceID during key export\nexport const EXPORT_NEAR_KEYPAIR_CANCELLED = 'EXPORT_NEAR_KEYPAIR_CANCELLED';\n\nexport type OfflineExportDoneMsg = { type: typeof OFFLINE_EXPORT_DONE; nearAccountId: string };\nexport type OfflineExportErrorMsg = { type: typeof OFFLINE_EXPORT_ERROR; error: string };\nexport type WalletUiClosedMsg = { type: typeof WALLET_UI_CLOSED };\n\n// No inbound handshake is required in the new-tab flow\nexport type OfflineExportInboundMsg = never;\nexport type OfflineExportOutboundMsg =\n | OfflineExportDoneMsg\n | OfflineExportErrorMsg\n | WalletUiClosedMsg;\n","// Centralized build configuration\n// This file defines all paths used across the build system\n\nexport const BUILD_PATHS = {\n // Build output directories\n BUILD: {\n ROOT: 'dist',\n WORKERS: 'dist/workers',\n ESM: 'dist/esm',\n CJS: 'dist/cjs',\n TYPES: 'dist/types'\n },\n\n // Source directories\n SOURCE: {\n ROOT: 'src',\n CORE: 'src/core',\n WASM_SIGNER: 'src/wasm_signer_worker',\n WASM_VRF: 'src/wasm_vrf_worker',\n CRITICAL_DIRS: [\n 'src/core',\n 'src/wasm_signer_worker',\n 'src/wasm_vrf_worker'\n ]\n },\n\n // Frontend deployment paths\n FRONTEND: {\n ROOT: '../examples/vite/public',\n SDK: '../examples/vite/public/sdk',\n WORKERS: '../examples/vite/public/sdk/workers'\n },\n\n // Runtime paths (used by workers and tests)\n RUNTIME: {\n SDK_BASE: '/sdk',\n WORKERS_BASE: '/sdk/workers',\n VRF_WORKER: '/sdk/workers/web3authn-vrf.worker.js',\n SIGNER_WORKER: '/sdk/workers/web3authn-signer.worker.js'\n },\n\n // Worker file names\n WORKERS: {\n VRF: 'web3authn-vrf.worker.js',\n SIGNER: 'web3authn-signer.worker.js',\n OFFLINE_SW: 'offline-export-sw.js',\n WASM_VRF_JS: 'wasm_vrf_worker.js',\n WASM_VRF_WASM: 'wasm_vrf_worker_bg.wasm',\n WASM_SIGNER_JS: 'wasm_signer_worker.js',\n WASM_SIGNER_WASM: 'wasm_signer_worker_bg.wasm'\n },\n\n // Test worker file paths (for test files)\n TEST_WORKERS: {\n VRF: '/sdk/workers/web3authn-vrf.worker.js',\n SIGNER: '/sdk/workers/web3authn-signer.worker.js',\n WASM_VRF_JS: '/sdk/workers/wasm_vrf_worker.js',\n WASM_VRF_WASM: '/sdk/workers/wasm_vrf_worker_bg.wasm',\n WASM_SIGNER_JS: '/sdk/workers/wasm_signer_worker.js',\n WASM_SIGNER_WASM: '/sdk/workers/wasm_signer_worker_bg.wasm'\n }\n} as const;\n\n// Helper functions\nexport const getWorkerPath = (workerName: string): string => `${BUILD_PATHS.BUILD.WORKERS}/${workerName}`;\nexport const getRuntimeWorkerPath = (workerName: string): string => `${BUILD_PATHS.RUNTIME.WORKERS_BASE}/${workerName}`;\nexport const getFrontendWorkerPath = (workerName: string): string => `${BUILD_PATHS.FRONTEND.WORKERS}/${workerName}`;\n\n// Default export for easier importing\nexport default BUILD_PATHS;\n","import { BUILD_PATHS } from '../build-paths.js';\n\n// === CONFIGURATION ===\nexport const SIGNER_WORKER_MANAGER_CONFIG = {\n TIMEOUTS: {\n DEFAULT: 60_000, // 60s default fallback for worker operations\n TRANSACTION: 60_000, // 60s for contract verification + signing\n REGISTRATION: 60_000, // 60s for registration operations\n },\n WORKER: {\n URL: BUILD_PATHS.RUNTIME.SIGNER_WORKER,\n TYPE: 'module' as const,\n NAME: 'Web3AuthnSignerWorker',\n },\n RETRY: {\n MAX_ATTEMPTS: 3,\n BACKOFF_MS: 1000,\n }\n} as const;\n\n// === DEVICE LINKING CONFIGURATION ===\nexport const DEVICE_LINKING_CONFIG = {\n TIMEOUTS: {\n QR_CODE_MAX_AGE_MS: 15 * 60 * 1000, // 15 minutes - QR code expiration\n SESSION_EXPIRATION_MS: 15 * 60 * 1000, // 15 minutes - Device linking session timeout\n TEMP_KEY_CLEANUP_MS: 15 * 60 * 1000, // 15 minutes - Automatic cleanup of temporary keys\n POLLING_INTERVAL_MS: 3000, // 3 seconds - AddKey polling interval\n REGISTRATION_RETRY_DELAY_MS: 2000, // 2 seconds - Delay between registration retries\n },\n RETRY: {\n MAX_REGISTRATION_ATTEMPTS: 5, // Maximum registration retry attempts\n }\n} as const;\n","/**\n * SDK Base (wallet origin)\n *\n * The wallet iframe host announces the absolute SDK base URL so that all\n * embedded assets (host script, Lit bundles) and module workers resolve from\n * the wallet origin in production. This keeps sensitive execution isolated\n * under the wallet site while allowing cross‑origin embedding.\n *\n * Writers:\n * - Wallet iframe host (service) on boot and after PM_SET_CONFIG\n * - App provider hook in dev when walletOrigin is configured\n *\n * Readers:\n * - WebAuthnManager (to set worker base origin for managers)\n * - Lit wrappers (to resolve embedded script/css URLs)\n */\nexport const W3A_WALLET_SDK_BASE_KEY = '__W3A_WALLET_SDK_BASE__'\nexport const W3A_WALLET_SDK_BASE_EVENT = 'W3A_WALLET_SDK_BASE_CHANGED'\n\n/**\n * Typed CustomEvent emitted when the wallet SDK base changes.\n * Detail contains the absolute base URL string (e.g., `${walletOrigin}/sdk/`).\n */\nexport type WalletSdkBaseChangedEvent = CustomEvent<string>\n\nexport interface WalletSDKBase {\n [W3A_WALLET_SDK_BASE_KEY]?: string\n}\n\n/**\n * @returns Absolute SDK base URL (e.g., `${walletOrigin}/sdk/`) when set, otherwise undefined.\n */\nexport function getEmbeddedBase(): string | undefined {\n if (typeof window === 'undefined') return undefined\n const w = window as unknown as WalletSDKBase\n const v = w[W3A_WALLET_SDK_BASE_KEY]\n return typeof v === 'string' && v.length > 0 ? v : undefined\n}\n\n/**\n * @param url - Absolute SDK base URL (e.g., `${walletOrigin}/sdk/`).\n * @returns void\n */\nexport function setEmbeddedBase(url: string): void {\n if (typeof window === 'undefined') return\n const w = window as unknown as WalletSDKBase\n w[W3A_WALLET_SDK_BASE_KEY] = url\n window.dispatchEvent(new CustomEvent(W3A_WALLET_SDK_BASE_EVENT as any, { detail: url }))\n}\n\n/**\n * @param cb - Callback invoked with the new absolute base URL when it changes.\n * @returns Unsubscribe function to remove the listener.\n */\nexport function onEmbeddedBaseChange(cb: (url: string) => void): () => void {\n if (typeof window === 'undefined') return () => {}\n const handler = (e: WalletSdkBaseChangedEvent) => {\n const d = e.detail\n if (typeof d === 'string' && d.length > 0) cb(d)\n }\n window.addEventListener(W3A_WALLET_SDK_BASE_EVENT, handler as EventListener, { passive: true })\n return () => window.removeEventListener(W3A_WALLET_SDK_BASE_EVENT, handler as EventListener)\n}\n","/**\n * Resolve the base origin for worker scripts.\n * Priority:\n * 1) window.__W3A_WALLET_SDK_BASE__ (absolute `${walletOrigin}${sdkBasePath}/`) → take its origin (only if same-origin)\n * 2) window.location.origin (host/app origin)\n *\n * @returns The origin (protocol + host [+ port]) used to resolve worker script URLs.\n * Prefers the wallet SDK base origin; falls back to the current window origin.\n */\nexport function resolveWorkerBaseOrigin(): string {\n const currentOrigin =\n (typeof window !== 'undefined' && window.location?.origin)\n ? window.location.origin\n : '';\n\n // Only allow worker scripts to resolve from the embedded base when it matches\n // the current origin. Cross-origin worker scripts are not reliably loadable\n // across browsers (even for module workers) and will fail with CORS errors.\n try {\n const embeddedBase = (window as any)?.__W3A_WALLET_SDK_BASE__ as string | undefined;\n if (embeddedBase) {\n const embeddedOrigin = new URL(embeddedBase, currentOrigin || 'https://invalid.local').origin;\n if (embeddedOrigin === currentOrigin) {\n return embeddedOrigin;\n }\n }\n } catch {}\n\n return currentOrigin;\n}\n\n/**\n * Build an absolute worker script URL from a path or absolute URL.\n * If `input` is a path (e.g., `/sdk/workers/foo.js`), it will be resolved\n * against the wallet origin (from `__W3A_WALLET_SDK_BASE__`) when available,\n * otherwise against the host origin.\n *\n * @param input - Absolute URL or path (e.g., `/sdk/workers/web3authn-signer.worker.js`).\n * @returns Absolute URL to the worker script, resolved against the wallet origin when available,\n * otherwise against the current window origin.\n */\nexport function resolveWorkerScriptUrl(input: string): string {\n return resolveWorkerUrl(input, { worker: detectWorkerFromPath(input) })\n}\n\nexport function resolveWorkerUrl(\n input: string | undefined,\n opts: { worker: 'signer' | 'vrf'; baseOrigin?: string }\n): string {\n const worker = opts.worker\n const baseOrigin = opts.baseOrigin || resolveWorkerBaseOrigin() || (typeof window !== 'undefined' ? window.location.origin : '') || 'https://invalid.local'\n try {\n // Prefer explicit per-worker URL override\n const ovAny = (typeof window !== 'undefined' ? (window as any) : {}) as any\n const override = worker === 'signer' ? ovAny.__W3A_SIGNER_WORKER_URL__ : ovAny.__W3A_VRF_WORKER_URL__\n const candidate = (typeof override === 'string' && override) ? override : (input || defaultWorkerPath(worker))\n if (/^https?:\\/\\//i.test(candidate)) {\n return new URL(candidate).toString()\n }\n return new URL(candidate, baseOrigin).toString()\n } catch {\n try { return new URL(input || defaultWorkerPath(worker), baseOrigin).toString() } catch {}\n return input || defaultWorkerPath(worker)\n }\n}\n\nfunction detectWorkerFromPath(p: string): 'signer' | 'vrf' {\n return /web3authn-signer\\.worker\\.js(?:$|\\?)/.test(p) ? 'signer' : 'vrf'\n}\n\nfunction defaultWorkerPath(worker: 'signer' | 'vrf'): string {\n return worker === 'signer' ? '/sdk/workers/web3authn-signer.worker.js' : '/sdk/workers/web3authn-vrf.worker.js'\n}\n","/**\n * Control messages exchanged between worker shims and the main thread.\n *\n * These messages are JS-only and do NOT go through the Rust WASM JSON request/response pipeline.\n * They are used for:\n * - MessagePort attachment handshakes (WrapKeySeed delivery)\n * - Readiness signals (worker pool health checks)\n */\nexport const WorkerControlMessage = {\n ATTACH_WRAP_KEY_SEED_PORT: 'ATTACH_WRAP_KEY_SEED_PORT',\n ATTACH_WRAP_KEY_SEED_PORT_OK: 'ATTACH_WRAP_KEY_SEED_PORT_OK',\n ATTACH_WRAP_KEY_SEED_PORT_ERROR: 'ATTACH_WRAP_KEY_SEED_PORT_ERROR',\n WORKER_READY: 'WORKER_READY',\n} as const;\n\nexport type WorkerControlMessageType =\n (typeof WorkerControlMessage)[keyof typeof WorkerControlMessage];\n","/**\n * Session Message Handling for Signer Worker\n *\n * This module provides helpers for waiting on session lifecycle messages from the signer worker.\n * Session messages are JS-only messages that never go through the Rust JSON pipeline\n * and are used for worker lifecycle management and session setup.\n */\n\nimport { WorkerControlMessage } from '../../workerControlMessages';\n\n// === SESSION MESSAGE TYPES ===\n\n/**\n * Control message sent by the signer worker after successfully attaching\n * a WrapKeySeed MessagePort for a signing session.\n */\nexport interface AttachWrapKeySeedPortOkMessage {\n type: typeof WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_OK;\n sessionId: string;\n}\n\n/**\n * Control message sent by the signer worker when attaching a WrapKeySeed\n * MessagePort fails.\n */\nexport interface AttachWrapKeySeedPortErrorMessage {\n type: typeof WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_ERROR;\n sessionId: string;\n error: string;\n}\n\n/**\n * Control message sent by the signer worker when it's ready to receive messages.\n */\nexport interface WorkerReadyMessage {\n type: typeof WorkerControlMessage.WORKER_READY;\n ready: boolean;\n}\n\n/**\n * All control messages that can be sent by the signer worker.\n */\nexport type SignerWorkerControlMessage =\n | AttachWrapKeySeedPortOkMessage\n | AttachWrapKeySeedPortErrorMessage\n | WorkerReadyMessage;\n\nexport type SessionMessage = Record<string, unknown> & {\n type: string;\n sessionId?: string;\n error?: string;\n};\n\nfunction asSessionMessage(msg: unknown): SessionMessage | null {\n if (!isObject(msg)) return null;\n if (typeof msg.type !== 'string') return null;\n if (msg.sessionId != null && typeof msg.sessionId !== 'string') return null;\n if (msg.error != null && typeof msg.error !== 'string') return null;\n return msg as SessionMessage;\n}\n\n/**\n * Type guard to check if a message is a control message.\n */\nexport function isSignerWorkerControlMessage(msg: unknown): msg is SignerWorkerControlMessage {\n if (!isObject(msg) || typeof msg.type !== 'string') {\n return false;\n }\n\n switch (msg.type) {\n case WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_OK:\n return typeof msg.sessionId === 'string';\n case WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_ERROR:\n return typeof msg.sessionId === 'string' && typeof msg.error === 'string';\n case WorkerControlMessage.WORKER_READY:\n return typeof msg.ready === 'boolean';\n default:\n return false;\n }\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\n// === SESSION MESSAGE HELPERS ===\n\n/**\n * Generic helper for waiting on session messages from a worker.\n * Registers a listener, sends no message (caller handles that), and waits for a matching response.\n *\n * @param worker - The worker to listen to\n * @param options - Configuration for what to wait for\n * @returns Promise that resolves when the expected message arrives, rejects on timeout or error\n */\nexport function waitForSessionMessage(\n worker: Worker,\n options: {\n /** Message type(s) to wait for (success) */\n successType: string | string[];\n /** Optional error type to reject on */\n errorType?: string;\n /** Session ID to match (if applicable) */\n sessionId?: string;\n /** Timeout in milliseconds */\n timeoutMs?: number;\n /** Custom message validator - return true to resolve, false to ignore, throw to reject */\n validator?: (msg: SessionMessage) => boolean;\n }\n): Promise<void> {\n const {\n successType,\n errorType,\n sessionId,\n timeoutMs = 2000,\n validator,\n } = options;\n\n const successTypes = Array.isArray(successType) ? successType : [successType];\n\n return new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n cleanup();\n reject(new Error(\n `Timeout waiting for session message (${successTypes.join('|')})${sessionId ? ` for session ${sessionId}` : ''}`\n ));\n }, timeoutMs);\n\n const messageHandler = (event: MessageEvent<unknown>) => {\n const msg = asSessionMessage(event.data);\n\n // Skip if message doesn't have a type\n if (!msg) return;\n\n // Check if sessionId matches (if specified)\n if (sessionId && msg.sessionId !== sessionId) {\n return;\n }\n\n // Check for error type\n if (errorType && msg.type === errorType) {\n cleanup();\n const error = msg.error || 'Unknown error';\n reject(new Error(`Session message error: ${error}`));\n return;\n }\n\n // Check for success type\n if (successTypes.includes(msg.type)) {\n // Run custom validator if provided\n if (validator) {\n try {\n const shouldResolve = validator(msg);\n if (!shouldResolve) {\n return; // Validator said to ignore this message\n }\n } catch (err) {\n cleanup();\n reject(err);\n return;\n }\n }\n\n cleanup();\n resolve();\n }\n };\n\n const cleanup = () => {\n clearTimeout(timeout);\n worker.removeEventListener('message', messageHandler);\n };\n\n worker.addEventListener('message', messageHandler);\n });\n}\n\n/**\n * Wait for the worker to acknowledge successful attachment of the WrapKeySeed port.\n * This provides early detection of attach failures instead of only seeing late WASM errors.\n *\n * @param worker - The worker that should send the ACK\n * @param sessionId - The session ID to match\n * @param timeoutMs - How long to wait before rejecting (default: 2000ms)\n * @returns Promise that resolves on success ACK, rejects on error or timeout\n */\nexport function waitForWrapKeyPortAttach(\n worker: Worker,\n sessionId: string,\n timeoutMs: number = 2000\n): Promise<void> {\n return waitForSessionMessage(worker, {\n successType: WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_OK,\n errorType: WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_ERROR,\n sessionId,\n timeoutMs,\n });\n}\n","import type { TxExecutionStatus } from '@near-js/types';\nimport type { ConfirmationConfig, SignerMode, ThresholdBehavior } from './signer-worker';\nimport type {\n ActionResult,\n DelegateRelayResult,\n LoginAndCreateSessionResult,\n LoginResult,\n RegistrationResult,\n SignAndSendDelegateActionResult,\n SignDelegateActionResult,\n SignTransactionResult,\n} from './tatchi';\nimport type { SyncAccountResult, SignNEP413MessageResult } from '../TatchiPasskey';\n\n//////////////////////////\n// Progress Events Enums\n//////////////////////////\n\n// Registration Enums\nexport enum RegistrationPhase {\n STEP_1_WEBAUTHN_VERIFICATION = 'webauthn-verification',\n STEP_2_KEY_GENERATION = 'key-generation',\n STEP_3_CONTRACT_PRE_CHECK = 'contract-pre-check',\n STEP_4_ACCESS_KEY_ADDITION = 'access-key-addition',\n STEP_5_CONTRACT_REGISTRATION = 'contract-registration',\n STEP_6_ACCOUNT_VERIFICATION = 'account-verification',\n STEP_7_THRESHOLD_KEY_ENROLLMENT = 'threshold-key-enrollment',\n STEP_8_DATABASE_STORAGE = 'database-storage',\n STEP_9_REGISTRATION_COMPLETE = 'registration-complete',\n REGISTRATION_ERROR = 'error',\n}\nexport enum RegistrationStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Login Enums\nexport enum LoginPhase {\n STEP_1_PREPARATION = 'preparation',\n STEP_2_WEBAUTHN_ASSERTION = 'webauthn-assertion',\n STEP_3_VRF_UNLOCK = 'vrf-unlock',\n STEP_4_LOGIN_COMPLETE = 'login-complete',\n LOGIN_ERROR = 'login-error',\n}\nexport enum LoginStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Action Enums\nexport enum ActionPhase {\n STEP_1_PREPARATION = 'preparation', // Rust WASM worker phase: Preparation = 100\n STEP_2_USER_CONFIRMATION = 'user-confirmation', // Rust WASM worker phase: UserConfirmation = 101\n STEP_3_WEBAUTHN_AUTHENTICATION = 'webauthn-authentication', // Rust WASM worker phase: WebauthnAuthentication = 102\n STEP_4_AUTHENTICATION_COMPLETE = 'authentication-complete', // Rust WASM worker phase: AuthenticationComplete = 103\n STEP_5_TRANSACTION_SIGNING_PROGRESS = 'transaction-signing-progress', // Rust WASM worker phase: TransactionSigningProgress = 104\n STEP_6_TRANSACTION_SIGNING_COMPLETE = 'transaction-signing-complete', // Rust WASM worker phase: TransactionSigningComplete = 105\n WASM_ERROR = 'wasm-error', // Rust WASM worker phase: Error = 106\n STEP_7_BROADCASTING = 'broadcasting',\n STEP_8_ACTION_COMPLETE = 'action-complete',\n ACTION_ERROR = 'action-error',\n}\nexport enum ActionStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Delegate-specific phase alias for filtering\nexport { ActionPhase as DelegateActionPhase };\n\n// Account Sync Enums\nexport enum SyncAccountPhase {\n STEP_1_PREPARATION = 'preparation',\n STEP_2_WEBAUTHN_AUTHENTICATION = 'webauthn-authentication',\n STEP_3_SYNC_AUTHENTICATORS_ONCHAIN = 'sync-authenticators-onchain',\n STEP_4_AUTHENTICATOR_SAVED = 'authenticator-saved',\n STEP_5_SYNC_ACCOUNT_COMPLETE = 'sync-account-complete',\n ERROR = 'error',\n}\nexport enum SyncAccountStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Device Linking Enums\nexport enum DeviceLinkingPhase {\n STEP_1_QR_CODE_GENERATED = 'qr-code-generated', // Device2: QR code created and displayed\n STEP_2_SCANNING = 'scanning', // Device1: Scanning QR code\n STEP_3_AUTHORIZATION = 'authorization', // Device1: TouchID authorization\n STEP_4_POLLING = 'polling', // Device2: Polling contract for mapping\n STEP_5_ADDKEY_DETECTED = 'addkey-detected', // Device2: AddKey transaction detected\n STEP_6_REGISTRATION = 'registration', // Device2: Registration and credential storage\n STEP_7_LINKING_COMPLETE = 'linking-complete', // Final completion\n STEP_8_AUTO_LOGIN = 'auto-login', // Auto-login after registration\n IDLE = 'idle', // Idle state\n REGISTRATION_ERROR = 'registration-error', // Error during registration\n LOGIN_ERROR = 'login-error', // Error during login\n DEVICE_LINKING_ERROR = 'error', // General error state\n}\nexport enum DeviceLinkingStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Email Recovery Enums\nexport enum EmailRecoveryPhase {\n STEP_1_PREPARATION = 'email-recovery-preparation',\n STEP_2_TOUCH_ID_REGISTRATION = 'email-recovery-touch-id-registration',\n STEP_3_AWAIT_EMAIL = 'email-recovery-await-email',\n STEP_4_POLLING_ADD_KEY = 'email-recovery-polling-add-key',\n STEP_4_POLLING_VERIFICATION_RESULT = 'email-recovery-polling-add-key',\n STEP_5_FINALIZING_REGISTRATION = 'email-recovery-finalizing-registration',\n STEP_6_COMPLETE = 'email-recovery-complete',\n ERROR = 'email-recovery-error',\n RESUMED_FROM_PENDING = 'email-recovery-resumed-from-pending',\n}\nexport enum EmailRecoveryStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Base event callback type\nexport type EventCallback<T> = (event: T) => void;\n\n// Users can still supply a single implementation: (success: boolean, result?: T) => ...\nexport interface AfterCall<T> {\n (success: true, result: T): void | Promise<void>;\n (success: false): void | Promise<void>;\n}\n\n// Base SSE Event Types (unified for Registration and Actions)\nexport interface BaseSSEEvent {\n step: number;\n phase: RegistrationPhase | LoginPhase | ActionPhase | DeviceLinkingPhase | SyncAccountPhase | EmailRecoveryPhase;\n status: RegistrationStatus | LoginStatus | ActionStatus | DeviceLinkingStatus | SyncAccountStatus | EmailRecoveryStatus;\n message: string;\n}\n\n// Registration-specific events\nexport interface BaseRegistrationSSEEvent extends BaseSSEEvent {\n phase: RegistrationPhase;\n status: RegistrationStatus;\n}\n\n// Action-specific events\nexport interface BaseActionSSEEvent extends BaseSSEEvent {\n phase: ActionPhase;\n status: ActionStatus;\n}\n\n// Login-specific events\nexport interface BaseLoginSSEEvent extends BaseSSEEvent {\n phase: LoginPhase;\n status: LoginStatus;\n}\n\nexport interface BaseDeviceLinkingSSEEvent extends BaseSSEEvent {\n phase: DeviceLinkingPhase;\n status: DeviceLinkingStatus;\n}\n\n// Action-specific events\nexport interface BaseSyncAccountEvent extends BaseSSEEvent {\n phase: SyncAccountPhase;\n status: SyncAccountStatus;\n}\n\nexport interface BaseEmailRecoveryEvent extends BaseSSEEvent {\n phase: EmailRecoveryPhase;\n status: EmailRecoveryStatus;\n}\n\n// Progress Events\nexport interface onProgressEvents extends BaseActionSSEEvent {\n step: number;\n status: ActionStatus;\n message: string;\n // Generic metadata bag for progress payloads\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\n// Optional, phase-specific data shapes used where we can commit to fields\n// Intentionally keep progress payloads generic to avoid duplicating\n// worker-side data shapes. Concrete fields can be added in future PRs\n// by normalizing worker payloads in one place.\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Registration Event Types\n/////////////////////////////////////////////\n\nexport interface RegistrationEventStep1 extends BaseRegistrationSSEEvent {\n step: 1;\n phase: RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION;\n}\n\nexport interface RegistrationEventStep2 extends BaseRegistrationSSEEvent {\n step: 2;\n phase: RegistrationPhase.STEP_2_KEY_GENERATION;\n status: RegistrationStatus.SUCCESS;\n verified: boolean;\n nearAccountId: string;\n nearPublicKey: string | null | undefined;\n vrfPublicKey: string | null | undefined;\n}\n\n// Optional progress emission during step 2 (e.g., concurrent contract pre-checks)\nexport interface RegistrationEventStep2Progress extends BaseRegistrationSSEEvent {\n step: 2;\n phase: RegistrationPhase.STEP_2_KEY_GENERATION;\n status: RegistrationStatus.PROGRESS;\n}\n\nexport interface RegistrationEventStep3 extends BaseRegistrationSSEEvent {\n step: 3;\n phase: RegistrationPhase.STEP_3_CONTRACT_PRE_CHECK;\n error?: string;\n}\n\nexport interface RegistrationEventStep4 extends BaseRegistrationSSEEvent {\n step: 4;\n phase: RegistrationPhase.STEP_4_ACCESS_KEY_ADDITION;\n error?: string;\n}\n\nexport interface RegistrationEventStep5 extends BaseRegistrationSSEEvent {\n step: 5;\n phase: RegistrationPhase.STEP_5_CONTRACT_REGISTRATION;\n error?: string;\n}\n\nexport interface RegistrationEventStep6 extends BaseRegistrationSSEEvent {\n step: 6;\n phase: RegistrationPhase.STEP_6_ACCOUNT_VERIFICATION;\n error?: string;\n}\n\nexport interface RegistrationEventStep7ThresholdKeyEnrollment extends BaseRegistrationSSEEvent {\n step: 7;\n phase: RegistrationPhase.STEP_7_THRESHOLD_KEY_ENROLLMENT;\n status: RegistrationStatus.SUCCESS;\n thresholdKeyReady: boolean;\n thresholdPublicKey?: string;\n relayerKeyId?: string;\n deviceNumber?: number;\n warning?: string;\n}\n\nexport interface RegistrationEventStep8 extends BaseRegistrationSSEEvent {\n step: 8;\n phase: RegistrationPhase.STEP_8_DATABASE_STORAGE;\n error?: string;\n}\n\nexport interface RegistrationEventStep9 extends BaseRegistrationSSEEvent {\n step: 9;\n phase: RegistrationPhase.STEP_9_REGISTRATION_COMPLETE;\n status: RegistrationStatus.SUCCESS;\n}\n\nexport interface RegistrationEventStep0 extends BaseRegistrationSSEEvent {\n step: 0;\n phase: RegistrationPhase.REGISTRATION_ERROR;\n status: RegistrationStatus.ERROR;\n error: string;\n}\n\nexport type RegistrationSSEEvent =\n | RegistrationEventStep1\n | RegistrationEventStep2Progress\n | RegistrationEventStep2\n | RegistrationEventStep3\n | RegistrationEventStep4\n | RegistrationEventStep5\n | RegistrationEventStep6\n | RegistrationEventStep7ThresholdKeyEnrollment\n | RegistrationEventStep8\n | RegistrationEventStep9\n | RegistrationEventStep0;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Login Event Types\n/////////////////////////////////////////////\n\nexport interface LoginSSEventStep1 extends BaseLoginSSEEvent {\n step: 1;\n phase: LoginPhase.STEP_1_PREPARATION;\n}\n\nexport interface LoginSSEventStep2 extends BaseLoginSSEEvent {\n step: 2;\n phase: LoginPhase.STEP_2_WEBAUTHN_ASSERTION;\n}\n\nexport interface LoginSSEventStep3 extends BaseLoginSSEEvent {\n step: 3;\n phase: LoginPhase.STEP_3_VRF_UNLOCK;\n}\n\nexport interface LoginSSEventStep4 extends BaseLoginSSEEvent {\n step: 4;\n phase: LoginPhase.STEP_4_LOGIN_COMPLETE;\n status: LoginStatus.SUCCESS;\n nearAccountId: string;\n clientNearPublicKey: string;\n}\n\nexport interface LoginSSEventStep0 extends BaseLoginSSEEvent {\n step: 0;\n phase: LoginPhase.LOGIN_ERROR;\n status: LoginStatus.ERROR;\n error: string;\n}\n\nexport type LoginSSEvent =\n | LoginSSEventStep1\n | LoginSSEventStep2\n | LoginSSEventStep3\n | LoginSSEventStep4\n | LoginSSEventStep0;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Action Event Types\n/////////////////////////////////////////////\n\nexport interface ActionEventStep1 extends BaseActionSSEEvent {\n step: 1;\n phase: ActionPhase.STEP_1_PREPARATION;\n}\n\nexport interface ActionEventStep2 extends BaseActionSSEEvent {\n step: 2;\n phase: ActionPhase.STEP_2_USER_CONFIRMATION;\n}\n\nexport interface ActionEventStep3 extends BaseActionSSEEvent {\n step: 3;\n phase: ActionPhase.STEP_3_WEBAUTHN_AUTHENTICATION;\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\nexport interface ActionEventStep4 extends BaseActionSSEEvent {\n step: 4;\n phase: ActionPhase.STEP_4_AUTHENTICATION_COMPLETE;\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\nexport interface ActionEventStep5 extends BaseActionSSEEvent {\n step: 5;\n phase: ActionPhase.STEP_5_TRANSACTION_SIGNING_PROGRESS;\n data?: Record<string, unknown>;\n}\n\nexport interface ActionEventStep6 extends BaseActionSSEEvent {\n step: 6;\n phase: ActionPhase.STEP_6_TRANSACTION_SIGNING_COMPLETE;\n status: ActionStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface ActionEventStep7 extends BaseActionSSEEvent {\n step: 7;\n phase: ActionPhase.STEP_7_BROADCASTING;\n}\n\nexport interface ActionEventStep8 extends BaseActionSSEEvent {\n step: 8;\n phase: ActionPhase.STEP_8_ACTION_COMPLETE;\n status: ActionStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface ActionEventError extends BaseActionSSEEvent {\n step: 0;\n phase: ActionPhase.ACTION_ERROR;\n status: ActionStatus.ERROR;\n error: string;\n}\n\nexport interface ActionEventWasmError extends BaseActionSSEEvent {\n step: 0;\n phase: ActionPhase.WASM_ERROR;\n status: ActionStatus.ERROR;\n error: string;\n}\n\nexport type ActionSSEEvent =\n | ActionEventStep1\n | ActionEventStep2\n | ActionEventStep3\n | ActionEventStep4\n | ActionEventStep5\n | ActionEventStep6\n | ActionEventStep7\n | ActionEventStep8\n | ActionEventError\n | ActionEventWasmError;\n\nexport type DelegateActionSSEEvent = ActionSSEEvent;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Device Linking Event Types\n/////////////////////////////////////////////\n\nexport interface DeviceLinkingEventStep1 extends BaseDeviceLinkingSSEEvent {\n step: 1;\n phase: DeviceLinkingPhase.STEP_1_QR_CODE_GENERATED;\n}\n\nexport interface DeviceLinkingEventStep2 extends BaseDeviceLinkingSSEEvent {\n step: 2;\n phase: DeviceLinkingPhase.STEP_2_SCANNING;\n}\n\nexport interface DeviceLinkingEventStep3 extends BaseDeviceLinkingSSEEvent {\n step: 3;\n phase: DeviceLinkingPhase.STEP_3_AUTHORIZATION;\n}\n\nexport interface DeviceLinkingEventStep4 extends BaseDeviceLinkingSSEEvent {\n step: 4;\n phase: DeviceLinkingPhase.STEP_4_POLLING;\n}\n\nexport interface DeviceLinkingEventStep5 extends BaseDeviceLinkingSSEEvent {\n step: 5;\n phase: DeviceLinkingPhase.STEP_5_ADDKEY_DETECTED;\n}\n\nexport interface DeviceLinkingEventStep6 extends BaseDeviceLinkingSSEEvent {\n step: 6;\n phase: DeviceLinkingPhase.STEP_6_REGISTRATION;\n}\n\nexport interface DeviceLinkingEventStep7 extends BaseDeviceLinkingSSEEvent {\n step: 7;\n phase: DeviceLinkingPhase.STEP_7_LINKING_COMPLETE;\n}\n\nexport interface DeviceLinkingEventStep8 extends BaseDeviceLinkingSSEEvent {\n step: 8;\n phase: DeviceLinkingPhase.STEP_8_AUTO_LOGIN;\n}\n\nexport interface DeviceLinkingErrorEvent extends BaseDeviceLinkingSSEEvent {\n step: 0;\n phase: DeviceLinkingPhase.DEVICE_LINKING_ERROR\n | DeviceLinkingPhase.LOGIN_ERROR\n | DeviceLinkingPhase.REGISTRATION_ERROR;\n status: DeviceLinkingStatus.ERROR;\n error: string;\n}\n\nexport type DeviceLinkingSSEEvent =\n | DeviceLinkingEventStep1\n | DeviceLinkingEventStep2\n | DeviceLinkingEventStep3\n | DeviceLinkingEventStep4\n | DeviceLinkingEventStep5\n | DeviceLinkingEventStep6\n | DeviceLinkingEventStep7\n | DeviceLinkingEventStep8\n | DeviceLinkingErrorEvent;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Account Sync Event Types\n/////////////////////////////////////////////\n\nexport interface SyncAccountEventStep1 extends BaseSyncAccountEvent {\n step: 1;\n phase: SyncAccountPhase.STEP_1_PREPARATION;\n}\n\nexport interface SyncAccountEventStep2 extends BaseSyncAccountEvent {\n step: 2;\n phase: SyncAccountPhase.STEP_2_WEBAUTHN_AUTHENTICATION;\n}\n\nexport interface SyncAccountEventStep3 extends BaseSyncAccountEvent {\n step: 3;\n phase: SyncAccountPhase.STEP_3_SYNC_AUTHENTICATORS_ONCHAIN;\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\nexport interface SyncAccountEventStep4 extends BaseSyncAccountEvent {\n step: 4;\n phase: SyncAccountPhase.STEP_4_AUTHENTICATOR_SAVED;\n status: SyncAccountStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface SyncAccountEventStep5 extends BaseSyncAccountEvent {\n step: 5;\n phase: SyncAccountPhase.STEP_5_SYNC_ACCOUNT_COMPLETE;\n status: SyncAccountStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface SyncAccountError extends BaseSyncAccountEvent {\n step: 0;\n phase: SyncAccountPhase.ERROR;\n status: SyncAccountStatus.ERROR;\n error: string;\n}\n\nexport type SyncAccountSSEEvent =\n | SyncAccountEventStep1\n | SyncAccountEventStep2\n | SyncAccountEventStep3\n | SyncAccountEventStep4\n | SyncAccountEventStep5\n | SyncAccountError;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Email Recovery Event Types\n/////////////////////////////////////////////\n\nexport interface EmailRecoveryEventStep1 extends BaseEmailRecoveryEvent {\n step: 1;\n phase: EmailRecoveryPhase.STEP_1_PREPARATION;\n}\n\nexport interface EmailRecoveryEventStep2 extends BaseEmailRecoveryEvent {\n step: 2;\n phase: EmailRecoveryPhase.STEP_2_TOUCH_ID_REGISTRATION;\n}\n\nexport interface EmailRecoveryEventStep3 extends BaseEmailRecoveryEvent {\n step: 3;\n phase: EmailRecoveryPhase.STEP_3_AWAIT_EMAIL;\n}\n\nexport interface EmailRecoveryEventStep4 extends BaseEmailRecoveryEvent {\n step: 4;\n phase: EmailRecoveryPhase.STEP_4_POLLING_ADD_KEY | EmailRecoveryPhase.STEP_4_POLLING_VERIFICATION_RESULT;\n data?: {\n accountId?: string;\n requestId?: string;\n nearPublicKey?: string;\n elapsedMs?: number;\n pollCount?: number;\n [key: string]: unknown;\n };\n logs?: string[];\n}\n\nexport interface EmailRecoveryEventStep5 extends BaseEmailRecoveryEvent {\n step: 5;\n phase: EmailRecoveryPhase.STEP_5_FINALIZING_REGISTRATION;\n data?: Record<string, unknown>;\n}\n\nexport interface EmailRecoveryEventStep6 extends BaseEmailRecoveryEvent {\n step: 6;\n phase: EmailRecoveryPhase.STEP_6_COMPLETE;\n status: EmailRecoveryStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface EmailRecoveryEventResumedFromPending extends BaseEmailRecoveryEvent {\n step: 0;\n phase: EmailRecoveryPhase.RESUMED_FROM_PENDING;\n status: EmailRecoveryStatus.PROGRESS;\n data?: Record<string, unknown>;\n}\n\nexport interface EmailRecoveryErrorEvent extends BaseEmailRecoveryEvent {\n step: 0;\n phase: EmailRecoveryPhase.ERROR;\n status: EmailRecoveryStatus.ERROR;\n error: string;\n}\n\nexport type EmailRecoverySSEEvent =\n | EmailRecoveryEventStep1\n | EmailRecoveryEventStep2\n | EmailRecoveryEventStep3\n | EmailRecoveryEventStep4\n | EmailRecoveryEventStep5\n | EmailRecoveryEventStep6\n | EmailRecoveryEventResumedFromPending\n | EmailRecoveryErrorEvent;\n\n//////////////////////////////////\n/// Hooks Options\n//////////////////////////////////\n\n// Function Options\nexport interface RegistrationHooksOptions {\n onEvent?: EventCallback<RegistrationSSEEvent>;\n onError?: (error: Error) => void;\n afterCall?: AfterCall<RegistrationResult>;\n /**\n * Optional: registration signing policy.\n * - `{ mode: 'local-signer' }`: derive and store an encrypted local NEAR secret key (v3 vault).\n * - `{ mode: 'threshold-signer' }`: derive the local key AND enroll a threshold Ed25519 (2-of-2) access key\n * during registration (relay adds the threshold public key on-chain and returns relayerKeyId).\n *\n * Defaults to `{ mode: 'local-signer' }` for backwards compatibility in public APIs.\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration. When provided, overrides user preferences\n // for this request only (not persisted).\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface LoginHooksOptions {\n onEvent?: EventCallback<LoginSSEvent>;\n onError?: (error: Error) => void;\n afterCall?: AfterCall<LoginAndCreateSessionResult>;\n /**\n * Optional: passkey deviceNumber hint.\n *\n * When multiple passkeys exist for the same `nearAccountId`, providing this hint lets\n * the login flow prioritize the matching `credentialId` when presenting the TouchID\n * (WebAuthn) prompt.\n */\n deviceNumber?: number;\n // Optional: request a server session (JWT in body or HttpOnly cookie)\n session?: {\n // 'jwt' returns the token in the JSON body; 'cookie' sets HttpOnly cookie\n kind: 'jwt' | 'cookie';\n // Optional: override relay URL; defaults to TatchiConfigs.relayer.url\n relayUrl?: string;\n // Optional: override route path; defaults to '/verify-authentication-response'\n route?: string;\n };\n /**\n * Optional: override the warm signing session policy minted during login.\n * Defaults come from `TatchiConfigs.signingSessionDefaults`.\n */\n signingSession?: {\n ttlMs?: number;\n remainingUses?: number;\n };\n}\n\nexport interface ActionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n afterCall?: AfterCall<ActionResult>;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration. When provided, overrides user preferences\n // for this request only (not persisted).\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport type ExecutionWaitOption =\n | { mode: 'sequential'; waitUntil?: TxExecutionStatus }\n | { mode: 'parallelStaggered'; staggerMs: number };\n\nexport interface SignAndSendTransactionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Execution control for multi-transaction broadcasts:\n * - { mode: 'sequential', waitUntil?: TxExecutionStatus }\n * - { mode: 'parallelStaggered', staggerMs: number }\n */\n executionWait?: ExecutionWaitOption;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n\n afterCall?: AfterCall<ActionResult[]>;\n // Per-call confirmation configuration. When provided, overrides user preferences\n // for this request only (not persisted).\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface SignTransactionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n\n afterCall?: AfterCall<SignTransactionResult[]>;\n waitUntil?: TxExecutionStatus;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration (non-persistent)\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface SendTransactionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n\n afterCall?: AfterCall<ActionResult>;\n waitUntil?: TxExecutionStatus;\n}\n\nexport interface DelegateActionHooksOptions {\n onEvent?: EventCallback<DelegateActionSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n afterCall?: AfterCall<SignDelegateActionResult>;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface DelegateRelayHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n afterCall?: AfterCall<DelegateRelayResult>;\n}\n\nexport type SignAndSendDelegateActionHooksOptions =\n Omit<DelegateActionHooksOptions, 'afterCall'> & {\n afterCall?: AfterCall<SignAndSendDelegateActionResult>;\n };\n\nexport interface SyncAccountHooksOptions {\n onEvent?: EventCallback<SyncAccountSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n\n afterCall?: AfterCall<SyncAccountResult>;\n}\n\nexport interface SignNEP413HooksOptions {\n onEvent?: EventCallback<RegistrationSSEEvent | LoginSSEvent | ActionSSEEvent | DeviceLinkingSSEEvent | SyncAccountSSEEvent | EmailRecoverySSEEvent>;\n onError?: (error: Error) => void;\n\n afterCall?: AfterCall<SignNEP413MessageResult>;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration (non-persistent)\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n","/**\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/syncAccount';\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 { createRandomVRFChallenge, type 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 { ensureEd25519Prefix } from '../utils/validation';\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 RecoveryAttemptStatus =\n | \"Started\"\n | \"VerifyingDkim\"\n | \"VerifyingZkEmail\"\n | \"DkimFailed\"\n | \"ZkEmailFailed\"\n | \"PolicyFailed\"\n | \"Recovering\"\n | \"AwaitingMoreEmails\"\n | \"Complete\"\n | \"Failed\";\n\nexport type RecoveryAttempt = {\n request_id: string;\n status: RecoveryAttemptStatus | string;\n created_at_ms: number;\n updated_at_ms: number;\n error?: string | null;\n /**\n * 32-byte SHA-256 hash of \"<canonical_from>|<account_id_lower>\".\n * Returned by newer EmailRecoverer contracts (replaces `from_address`).\n */\n from_address_hash?: number[] | null;\n /** Legacy field (string email address). */\n from_address?: string | null;\n email_timestamp_ms?: number | null;\n new_public_key?: string | null;\n};\n\nfunction normalizeByteArray(input: unknown): number[] | null | undefined {\n if (input == null) return input as null | undefined;\n\n if (Array.isArray(input)) {\n return input.map((v) => Number(v)).filter((v) => Number.isFinite(v));\n }\n\n if (typeof input === 'string' && input) {\n try {\n const bytes =\n typeof Buffer !== 'undefined'\n ? Buffer.from(input, 'base64')\n : Uint8Array.from(atob(input), (c) => c.charCodeAt(0));\n const arr = bytes instanceof Uint8Array ? Array.from(bytes) : Array.from(new Uint8Array(bytes));\n return arr;\n } catch {\n return undefined;\n }\n }\n\n return undefined;\n}\n\nexport async function getEmailRecoveryAttempt(\n nearClient: NearClient,\n accountId: string,\n requestId: string\n): Promise<RecoveryAttempt | null> {\n const raw = await nearClient.view<{ request_id: string }, Omit<RecoveryAttempt, 'status'> & { status: any } | null>({\n account: accountId,\n method: 'get_recovery_attempt',\n args: { request_id: requestId },\n });\n\n if (!raw) return null;\n\n // Normalization logic for status (string or object enum)\n const statusRaw = raw.status;\n const status = (() => {\n if (typeof statusRaw === 'string') return statusRaw.trim();\n if (statusRaw && typeof statusRaw === 'object') {\n const keys = Object.keys(statusRaw as Record<string, unknown>);\n if (keys.length === 1) {\n return String(keys[0] || '').trim();\n }\n }\n return '';\n })();\n\n return {\n ...raw,\n from_address_hash: normalizeByteArray((raw as any).from_address_hash) ?? (raw as any).from_address_hash,\n status: status as RecoveryAttemptStatus,\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 const signTransactions = () => context.webAuthnManager.signTransactionsWithActions({\n rpcCall: {\n contractId: context.webAuthnManager.tatchiPasskeyConfigs.contractId,\n nearRpcUrl: context.webAuthnManager.tatchiPasskeyConfigs.nearRpcUrl,\n nearAccountId: device1AccountId\n },\n // Prefer threshold signing when available; fall back to local signing if the account\n // is not enrolled with threshold key material.\n signerMode: { mode: 'threshold-signer', behavior: 'fallback' },\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 // Sign three transactions with one PRF authentication\n let signedTransactions: Array<{ signedTransaction: SignedTransaction }> = [];\n try {\n signedTransactions = await signTransactions();\n } catch (e: unknown) {\n if (!isVrfSessionPasskeyMismatchError(e)) throw e;\n\n // This happens when:\n // - the VRF worker is unlocked for a different device's VRF keypair, but\n // - IndexedDB `lastUser` (and thus allowCredentials) points at another device.\n // Fix by re-unlocking the VRF keypair for the current deviceNumber, then retry once.\n onEvent?.({\n step: 3,\n phase: DeviceLinkingPhase.STEP_3_AUTHORIZATION,\n status: DeviceLinkingStatus.PROGRESS,\n message: 'Session mismatch detected; re-authenticating with TouchID...'\n });\n\n await repairVrfSessionForCurrentDevice({\n context,\n nearAccountId: device1AccountId,\n // Needs to cover 3 txs in a single batch.\n remainingUses: 3,\n ttlMs: 2 * 60 * 1000,\n });\n\n signedTransactions = await signTransactions();\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\nfunction isVrfSessionPasskeyMismatchError(err: unknown): boolean {\n const msg = errorMessage(err) || String(err || '');\n return msg.includes('different passkey/VRF session than the current device');\n}\n\nasync function repairVrfSessionForCurrentDevice(args: {\n context: PasskeyManagerContext;\n nearAccountId: AccountId;\n ttlMs?: number;\n remainingUses?: number;\n}): Promise<void> {\n const { context, nearAccountId } = args;\n const lastUser = await context.webAuthnManager.getLastUser();\n if (!lastUser || lastUser.nearAccountId !== nearAccountId) {\n throw new Error('Cannot repair VRF session: no lastUser for this account. Please log in again.');\n }\n const deviceNumber = lastUser.deviceNumber;\n if (!Number.isFinite(deviceNumber) || deviceNumber < 1) {\n throw new Error('Cannot repair VRF session: invalid lastUser.deviceNumber');\n }\n\n const authenticators = await context.webAuthnManager.getAuthenticatorsByUser(nearAccountId);\n const credentialIdsForDevice = authenticators\n .filter((a) => a.deviceNumber === deviceNumber)\n .map((a) => a.credentialId);\n\n const credentialIds = credentialIdsForDevice.length > 0\n ? credentialIdsForDevice\n : authenticators.map((a) => a.credentialId);\n\n if (credentialIds.length === 0) {\n throw new Error(`Cannot repair VRF session: no authenticators found for ${nearAccountId}`);\n }\n\n const challenge = createRandomVRFChallenge();\n const credential = await context.webAuthnManager.getAuthenticationCredentialsSerializedDualPrf({\n nearAccountId,\n challenge: challenge as VRFChallenge,\n credentialIds,\n });\n\n const unlockResult = await context.webAuthnManager.unlockVRFKeypair({\n nearAccountId,\n encryptedVrfKeypair: lastUser.encryptedVrfKeypair,\n credential: credential as WebAuthnAuthenticationCredential,\n });\n if (!unlockResult.success) {\n throw new Error(unlockResult.error || 'Failed to re-unlock VRF keypair for current device');\n }\n\n // Restore a minimal warm signing session so the retried batch can run without a second TouchID prompt.\n await context.webAuthnManager.mintSigningSessionFromCredential({\n nearAccountId,\n credential: credential as WebAuthnAuthenticationCredential,\n ttlMs: args.ttlMs,\n remainingUses: args.remainingUses,\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, nearPublicKey?: string }>> {\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 const nearPublicKey = (() => {\n const raw = (contractAuthenticator as any).near_public_key;\n if (typeof raw !== 'string') return undefined;\n const trimmed = raw.trim();\n return trimmed ? ensureEd25519Prefix(trimmed) : 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 ...(nearPublicKey ? { nearPublicKey } : {})\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\nconst EMPTY_NEAR_CODE_HASH = '11111111111111111111111111111111';\n\nasync function hasDeployedContractCode(nearClient: NearClient, accountId: AccountId): Promise<boolean> {\n try {\n const account = await nearClient.viewAccount(accountId);\n const codeHash = (account as { code_hash?: unknown } | null)?.code_hash;\n const globalContractHash = (account as { global_contract_hash?: unknown } | null)?.global_contract_hash;\n const globalContractAccountId = (account as { global_contract_account_id?: unknown } | null)?.global_contract_account_id;\n\n const hasLocalCode = typeof codeHash === 'string' && codeHash !== EMPTY_NEAR_CODE_HASH;\n const hasGlobalCode =\n (typeof globalContractHash === 'string' && globalContractHash.trim().length > 0) ||\n (typeof globalContractAccountId === 'string' && globalContractAccountId.trim().length > 0);\n\n return hasLocalCode || hasGlobalCode;\n } catch {\n return false;\n }\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 // Prefer `view_account` over `view_code`:\n // - `view_code` is expected to fail for non-contract accounts and is noisy.\n // - `view_account` is lightweight and tells us whether the account uses local contract code\n // or a NEAR \"global contract\" (via `global_contract_*` fields).\n const hasContract = await hasDeployedContractCode(nearClient, accountId);\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 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 const hasContract = await hasDeployedContractCode(nearClient, accountId);\n\n const {\n emailRecovererGlobalContract,\n zkEmailVerifierContract,\n emailDkimVerifierContract,\n } = contracts;\n\n // If the account already has a contract (local or global), it still might not be a readable\n // EmailRecoverer instance (e.g. stale state after upgrades). In that case, `set_recovery_emails`\n // would fail while `init_email_recovery` (#[init(ignore_state)]) can safely re-initialize.\n //\n // We keep this as a best-effort probe to avoid wiping state on transient RPC issues.\n let shouldInit = !hasContract;\n if (!shouldInit) {\n try {\n await nearClient.view<Record<string, never>, unknown>({\n account: accountId,\n method: 'get_recovery_emails',\n args: {} as Record<string, never>,\n });\n } catch (err: unknown) {\n const msg = errorMessage(err);\n // Common/expected cases where we should fall back to init:\n // - account has a global contract pointer but no EmailRecoverer-compatible state yet\n // - account has stale/incompatible state after a contract upgrade\n // - account has some other contract (method missing)\n if (/Cannot deserialize the contract state/i.test(msg)\n || /CodeDoesNotExist/i.test(msg)\n || /MethodNotFound/i.test(msg)) {\n shouldInit = true;\n }\n }\n }\n\n const base: ActionArgs[] = [\n {\n type: ActionType.UseGlobalContract,\n accountId: emailRecovererGlobalContract,\n },\n ];\n\n return shouldInit\n ? [\n ...base,\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 ...base,\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\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// ACCESS KEY HELPERS\n// ===========================\n\nexport type AccessKeyWaitOptions = {\n attempts?: number;\n delayMs?: number;\n};\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((res) => setTimeout(res, ms));\n}\n\nfunction isAccessKeyNotFoundError(err: unknown): boolean {\n const msg = String(errorMessage(err) || '').toLowerCase();\n if (!msg) return false;\n\n // Common NEAR node / near-api-js phrasing for missing access keys.\n if (msg.includes('unknown access key') || msg.includes('unknown_access_key') || msg.includes('unknownaccesskey')) {\n return true;\n }\n if (msg.includes('accesskeydoesnotexist')) return true;\n if (msg.includes('access key does not exist')) return true;\n if (msg.includes(\"access key doesn't exist\")) return true;\n if (msg.includes('access key not found')) return true;\n if (msg.includes('no such access key')) return true;\n if (msg.includes('viewing access key') && msg.includes('does not exist') && !msg.includes('account')) return true;\n\n return false;\n}\n\nexport async function hasAccessKey(\n nearClient: NearClient,\n nearAccountId: string,\n publicKey: string,\n opts?: AccessKeyWaitOptions,\n): Promise<boolean> {\n const expected = ensureEd25519Prefix(publicKey);\n if (!expected) return false;\n\n const attempts = Math.max(1, Math.floor(opts?.attempts ?? 6));\n const delayMs = Math.max(50, Math.floor(opts?.delayMs ?? 750));\n\n for (let i = 0; i < attempts; i++) {\n try {\n await nearClient.viewAccessKey(nearAccountId, expected);\n return true;\n } catch {\n // tolerate transient view errors during propagation; retry\n }\n if (i < attempts - 1) {\n await sleep(delayMs);\n }\n }\n return false;\n}\n\nexport async function waitForAccessKeyAbsent(\n nearClient: NearClient,\n nearAccountId: string,\n publicKey: string,\n opts?: AccessKeyWaitOptions,\n): Promise<boolean> {\n const expected = ensureEd25519Prefix(publicKey);\n if (!expected) return true;\n\n const attempts = Math.max(1, Math.floor(opts?.attempts ?? 6));\n const delayMs = Math.max(50, Math.floor(opts?.delayMs ?? 650));\n\n for (let i = 0; i < attempts; i++) {\n try {\n await nearClient.viewAccessKey(nearAccountId, expected);\n } catch (err: unknown) {\n if (isAccessKeyNotFoundError(err)) return true;\n // tolerate transient view errors during propagation; retry\n }\n if (i < attempts - 1) {\n await sleep(delayMs);\n }\n }\n return false;\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 intent_digest_32 = Array.from(base64UrlDecode(vrfChallenge.intentDigest || ''));\n if (intent_digest_32.length !== 32) {\n throw new Error('Missing or invalid vrfChallenge.intentDigest (expected base64url-encoded 32 bytes)');\n }\n const session_policy_digest_32 = vrfChallenge.sessionPolicyDigest32\n ? Array.from(base64UrlDecode(vrfChallenge.sessionPolicyDigest32))\n : [];\n if (session_policy_digest_32.length !== 0 && session_policy_digest_32.length !== 32) {\n throw new Error('Invalid vrfChallenge.sessionPolicyDigest32 (expected base64url-encoded 32 bytes)');\n }\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 intent_digest_32,\n ...(session_policy_digest_32.length ? { session_policy_digest_32 } : {}),\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 intent_digest_32 = toBytes(vrfChallenge.intentDigest);\n if (intent_digest_32.length !== 32) {\n throw new Error('Missing or invalid vrfChallenge.intentDigest (expected base64url-encoded 32 bytes)');\n }\n const session_policy_digest_32 = toBytes(vrfChallenge.sessionPolicyDigest32);\n if (session_policy_digest_32.length !== 0 && session_policy_digest_32.length !== 32) {\n throw new Error('Invalid vrfChallenge.sessionPolicyDigest32 (expected base64url-encoded 32 bytes)');\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 intent_digest_32,\n ...(session_policy_digest_32.length ? { session_policy_digest_32 } : {}),\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\nexport async function authorizeThresholdEd25519(\n relayServerUrl: string,\n vrfChallenge: VRFChallenge,\n webauthnAuthentication: WebAuthnAuthenticationCredential,\n args: {\n relayerKeyId: string;\n clientVerifyingShareB64u: string;\n purpose: string;\n /**\n * Exact 32-byte digest that will be co-signed (tx hash / delegate hash / NEP-413 hash).\n * The relayer must bind this digest to the VRF-authorized `intent_digest_32`.\n */\n signingDigest32: number[];\n signingPayload?: unknown;\n },\n): Promise<{\n ok: boolean;\n mpcSessionId?: string;\n expiresAt?: string;\n code?: string;\n message?: string;\n error?: string;\n}> {\n try {\n const toBytes = (b64u: string | undefined): number[] => {\n if (!b64u) return [];\n return Array.from(base64UrlDecode(b64u));\n };\n const intent_digest_32 = toBytes(vrfChallenge.intentDigest);\n if (intent_digest_32.length !== 32) {\n throw new Error('Missing or invalid vrfChallenge.intentDigest (expected base64url-encoded 32 bytes)');\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 intent_digest_32,\n };\n\n const clientVerifyingShareBytes = toBytes(args.clientVerifyingShareB64u);\n if (clientVerifyingShareBytes.length !== 32) {\n throw new Error('Missing or invalid args.clientVerifyingShareB64u (expected base64url-encoded 32 bytes)');\n }\n\n // Strip extension results before sending to the relay (never send PRF outputs).\n const webauthn_authentication = {\n ...webauthnAuthentication,\n authenticatorAttachment: webauthnAuthentication.authenticatorAttachment ?? null,\n response: {\n ...webauthnAuthentication.response,\n userHandle: webauthnAuthentication.response.userHandle ?? null,\n },\n clientExtensionResults: null,\n };\n\n const url = `${relayServerUrl.replace(/\\/$/, '')}/threshold-ed25519/authorize`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n credentials: 'include',\n body: JSON.stringify({\n relayerKeyId: args.relayerKeyId,\n clientVerifyingShareB64u: args.clientVerifyingShareB64u,\n purpose: args.purpose,\n signing_digest_32: (() => {\n const d = args.signingDigest32;\n if (!Array.isArray(d) || d.length !== 32) {\n throw new Error('Missing or invalid args.signingDigest32 (expected number[32])');\n }\n return d;\n })(),\n signingPayload: args.signingPayload,\n vrf_data,\n webauthn_authentication,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n return { ok: false, error: `HTTP ${response.status}: ${errorText}` };\n }\n\n const json = await response.json();\n return {\n ok: !!json?.ok,\n mpcSessionId: json?.mpcSessionId,\n expiresAt: json?.expiresAt,\n code: json?.code,\n message: json?.message,\n };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'Failed to authorize threshold-ed25519 signing' };\n }\n}\n\nexport async function thresholdEd25519Keygen(\n relayServerUrl: string,\n vrfChallenge: VRFChallenge,\n webauthnAuthentication: WebAuthnAuthenticationCredential,\n args: {\n clientVerifyingShareB64u: string;\n nearAccountId: string;\n },\n): Promise<{\n ok: boolean;\n clientParticipantId?: number;\n relayerParticipantId?: number;\n participantIds?: number[];\n relayerKeyId?: string;\n publicKey?: string;\n relayerVerifyingShareB64u?: string;\n code?: string;\n message?: string;\n error?: string;\n}> {\n try {\n const base = String(relayServerUrl || '').trim().replace(/\\/$/, '');\n if (!base) throw new Error('Missing relayServerUrl');\n\n const clientVerifyingShareB64u = String(args.clientVerifyingShareB64u || '').trim();\n if (!clientVerifyingShareB64u) throw new Error('Missing clientVerifyingShareB64u');\n\n const nearAccountId = String(args.nearAccountId || '').trim();\n if (!nearAccountId) throw new Error('Missing nearAccountId');\n\n const toBytes = (b64u: string | undefined): number[] => {\n if (!b64u) return [];\n return Array.from(base64UrlDecode(b64u));\n };\n const intent_digest_32 = toBytes(vrfChallenge.intentDigest);\n if (intent_digest_32.length !== 32) {\n throw new Error('Missing or invalid vrfChallenge.intentDigest (expected base64url-encoded 32 bytes)');\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 intent_digest_32,\n };\n\n // Strip extension results before sending to the relay (never send PRF outputs).\n const webauthn_authentication = {\n ...webauthnAuthentication,\n authenticatorAttachment: webauthnAuthentication.authenticatorAttachment ?? null,\n response: {\n ...webauthnAuthentication.response,\n userHandle: webauthnAuthentication.response.userHandle ?? null,\n },\n clientExtensionResults: null,\n };\n\n const url = `${base}/threshold-ed25519/keygen`;\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({\n clientVerifyingShareB64u,\n nearAccountId,\n vrf_data,\n webauthn_authentication,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n return { ok: false, error: `HTTP ${response.status}: ${errorText}` };\n }\n\n const json = await response.json();\n return {\n ok: !!json?.ok,\n clientParticipantId: json?.clientParticipantId,\n relayerParticipantId: json?.relayerParticipantId,\n participantIds: json?.participantIds,\n relayerKeyId: json?.relayerKeyId,\n publicKey: json?.publicKey,\n relayerVerifyingShareB64u: json?.relayerVerifyingShareB64u,\n code: json?.code,\n message: json?.message,\n };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'Failed to keygen threshold-ed25519' };\n }\n}\n\nexport async function thresholdEd25519KeygenFromRegistrationTx(\n relayServerUrl: string,\n args: {\n clientVerifyingShareB64u: string;\n nearAccountId: string;\n registrationTxHash: string;\n },\n): Promise<{\n ok: boolean;\n clientParticipantId?: number;\n relayerParticipantId?: number;\n participantIds?: number[];\n relayerKeyId?: string;\n publicKey?: string;\n relayerVerifyingShareB64u?: string;\n code?: string;\n message?: string;\n error?: string;\n}> {\n try {\n const base = String(relayServerUrl || '').trim().replace(/\\/$/, '');\n if (!base) throw new Error('Missing relayServerUrl');\n\n const clientVerifyingShareB64u = String(args.clientVerifyingShareB64u || '').trim();\n if (!clientVerifyingShareB64u) throw new Error('Missing clientVerifyingShareB64u');\n\n const nearAccountId = String(args.nearAccountId || '').trim();\n if (!nearAccountId) throw new Error('Missing nearAccountId');\n\n const registrationTxHash = String(args.registrationTxHash || '').trim();\n if (!registrationTxHash) throw new Error('Missing registrationTxHash');\n\n const url = `${base}/threshold-ed25519/keygen`;\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: 'include',\n body: JSON.stringify({\n clientVerifyingShareB64u,\n nearAccountId,\n registrationTxHash,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n return { ok: false, error: `HTTP ${response.status}: ${errorText}` };\n }\n\n const json = await response.json();\n return {\n ok: !!json?.ok,\n clientParticipantId: json?.clientParticipantId,\n relayerParticipantId: json?.relayerParticipantId,\n participantIds: json?.participantIds,\n relayerKeyId: json?.relayerKeyId,\n publicKey: json?.publicKey,\n relayerVerifyingShareB64u: json?.relayerVerifyingShareB64u,\n code: json?.code,\n message: json?.message,\n };\n } catch (error: any) {\n return { ok: false, error: error?.message || 'Failed to keygen threshold-ed25519 from registration tx' };\n }\n}\n","\nimport { PASSKEY_MANAGER_DEFAULT_CONFIGS } from \"../../../defaultConfigs\";\nimport type { CheckCanRegisterUserResult } from '../../../rpcCalls';\nimport { checkCanRegisterUserContractCall } from '../../../rpcCalls';\nimport { serializeRegistrationCredentialWithPRF, removePrfOutputGuard } from '../../credentialsHelpers';\nimport { VRFChallenge } from '../../../types/vrf-worker';\nimport { RegistrationPhase, RegistrationStatus, type RegistrationEventStep3 } from '../../../types/sdkSentEvents';\nimport type { AuthenticatorOptions } from '../../../types/authenticatorOptions';\nimport { SignerWorkerManagerContext } from '..';\nimport type { WebAuthnRegistrationCredential } from '../../../types/webauthn';\nimport { errorMessage } from '@/utils/errors';\nimport { isObject, isString } from '@/utils/validation';\n\n\nexport async function checkCanRegisterUser({\n ctx,\n vrfChallenge,\n credential,\n contractId,\n nearRpcUrl,\n authenticatorOptions,\n onEvent,\n}: {\n ctx: SignerWorkerManagerContext,\n vrfChallenge: VRFChallenge,\n credential: WebAuthnRegistrationCredential,\n contractId: string;\n nearRpcUrl: string;\n authenticatorOptions?: AuthenticatorOptions; // Authenticator options for registration check\n onEvent?: (update: RegistrationEventStep3) => void;\n}): Promise<{\n success: boolean;\n verified?: boolean;\n registrationInfo?: {\n credentialId: Uint8Array;\n credentialPublicKey: Uint8Array;\n userId: string;\n vrfPublicKey: Uint8Array | undefined;\n };\n logs?: string[];\n signedTransactionBorsh?: number[];\n error?: string;\n}> {\n try {\n // Accept either a real PublicKeyCredential or an already-serialized credential\n const isSerialized = (cred: unknown): cred is WebAuthnRegistrationCredential => {\n if (!isObject(cred)) return false;\n const resp = (cred as { response?: unknown }).response;\n if (!isObject(resp)) return false;\n return isString((resp as { clientDataJSON?: unknown }).clientDataJSON)\n && isString((resp as { attestationObject?: unknown }).attestationObject);\n };\n\n const serializedCredential: WebAuthnRegistrationCredential = isSerialized(credential)\n ? credential\n : serializeRegistrationCredentialWithPRF({ credential: credential });\n\n // Ensure required fields are present; avoid undefined which gets dropped by JSON.stringify in the worker\n const resolvedContractId = contractId || PASSKEY_MANAGER_DEFAULT_CONFIGS.contractId;\n\n onEvent?.({\n step: 3,\n phase: RegistrationPhase.STEP_3_CONTRACT_PRE_CHECK,\n status: RegistrationStatus.PROGRESS,\n message: 'Running webauthn contract registration checks...',\n });\n\n // PRF outputs must never be sent over the network. Strip them before\n // calling the contract while preserving the rest of the credential shape.\n const strippedCredential = removePrfOutputGuard<WebAuthnRegistrationCredential>(serializedCredential);\n\n const result: CheckCanRegisterUserResult = await checkCanRegisterUserContractCall({\n nearClient: ctx.nearClient,\n contractId: resolvedContractId,\n vrfChallenge,\n credential: strippedCredential,\n authenticatorOptions,\n });\n\n if (!result.success) {\n throw new Error(result.error || 'Registration pre-check RPC failed');\n }\n\n const wasmResult = {\n verified: result.verified,\n registrationInfo: undefined,\n logs: result.logs,\n error: result.error,\n };\n\n onEvent?.({\n step: 3,\n phase: RegistrationPhase.STEP_3_CONTRACT_PRE_CHECK,\n status: result.verified ? RegistrationStatus.SUCCESS : RegistrationStatus.ERROR,\n message: result.verified ? 'Registration pre-check succeeded' : (result.error || 'Registration pre-check failed'),\n ...(result.verified ? {} : { error: result.error || 'Registration pre-check failed' }),\n });\n\n return {\n success: true,\n verified: wasmResult.verified,\n registrationInfo: wasmResult.registrationInfo,\n logs: wasmResult.logs,\n error: wasmResult.error,\n };\n\n } catch (error: unknown) {\n // Preserve the detailed error message instead of converting to generic error\n console.error('checkCanRegisterUser failed:', error);\n return {\n success: false,\n verified: false,\n error: errorMessage(error) || 'Unknown error occurred',\n logs: [],\n };\n }\n}\n","import * as wasmModule from '../../wasm_signer_worker/pkg/wasm_signer_worker.js';\n\n/**\n * User verification policy for WebAuthn authenticators\n *\n * @example\n * ```typescript\n * // Require user verification (PIN, fingerprint, etc.)\n * UserVerificationPolicy.Required\n *\n * // Prefer user verification but don't require it\n * UserVerificationPolicy.Preferred\n *\n * // Discourage user verification (for performance)\n * UserVerificationPolicy.Discouraged\n * ```\n */\nexport enum UserVerificationPolicy {\n Required = 'required',\n Preferred = 'preferred',\n Discouraged = 'discouraged'\n}\n\n/**\n * Origin policy input for WebAuthn registration (matches WASM OriginPolicyInput struct)\n * Note: choose only one of the fields: single, all_subdomains, multiple\n */\nexport interface OriginPolicyInput {\n single: boolean | undefined;\n all_subdomains: boolean | undefined;\n multiple: string[] | undefined;\n}\n\nexport const toEnumUserVerificationPolicy = (userVerification: UserVerificationPolicy | undefined): wasmModule.UserVerificationPolicy => {\n switch (userVerification) {\n case UserVerificationPolicy.Required:\n return wasmModule.UserVerificationPolicy.Required;\n case UserVerificationPolicy.Preferred:\n return wasmModule.UserVerificationPolicy.Preferred;\n case UserVerificationPolicy.Discouraged:\n return wasmModule.UserVerificationPolicy.Discouraged;\n default:\n return wasmModule.UserVerificationPolicy.Preferred;\n }\n};\n\nexport interface AuthenticatorOptions {\n userVerification: UserVerificationPolicy;\n originPolicy: OriginPolicyInput;\n}\n\n/**\n * Default authenticator options (matches contract defaults)\n */\nexport const DEFAULT_AUTHENTICATOR_OPTIONS: AuthenticatorOptions = {\n userVerification: UserVerificationPolicy.Preferred,\n originPolicy: {\n single: undefined,\n all_subdomains: true,\n multiple: undefined\n }\n};\n","\nexport function withSessionId<T extends object>(\n sessionId: string,\n payload: T,\n): T & { sessionId: string } {\n\n if (!sessionId) {\n throw new Error('withSessionId: sessionId is required');\n }\n\n const existing = (payload as { sessionId?: unknown })?.sessionId;\n if (existing != null && typeof existing !== 'string') {\n throw new Error('withSessionId: payload.sessionId must be a string when provided');\n }\n if (existing && existing !== sessionId) {\n throw new Error(\n `withSessionId: payload.sessionId (${existing}) does not match provided sessionId (${sessionId})`,\n );\n }\n\n return { ...payload, sessionId };\n}\n","\nimport type { LocalNearSkV3Material } from '../../../IndexedDBManager/passkeyNearKeysDB';\nimport type { AuthenticatorOptions } from '../../../types/authenticatorOptions';\nimport {\n WorkerRequestType,\n isDeriveNearKeypairAndEncryptSuccess,\n} from '../../../types/signer-worker';\nimport { AccountId, toAccountId } from \"../../../types/accountIds\";\nimport { getLastLoggedInDeviceNumber } from '../getDeviceNumber';\nimport { SignerWorkerManagerContext } from '..';\nimport type { WebAuthnRegistrationCredential } from '@/core/types/webauthn';\nimport { toEnumUserVerificationPolicy } from '../../../types/authenticatorOptions';\nimport { withSessionId } from './session';\n\n/**\n * Derive NEAR keypair and encrypt it from a serialized WebAuthn registration credential\n * (shape compatible with SerializedRegistrationCredential from WASM) by extracting PRF outputs from it.\n */\nexport async function deriveNearKeypairAndEncryptFromSerialized({\n ctx,\n credential,\n nearAccountId,\n options,\n sessionId,\n}: {\n ctx: SignerWorkerManagerContext,\n credential: WebAuthnRegistrationCredential;\n nearAccountId: AccountId,\n options?: {\n authenticatorOptions?: AuthenticatorOptions;\n deviceNumber?: number;\n };\n sessionId: string;\n}): Promise<{\n success: boolean;\n nearAccountId: AccountId;\n publicKey: string;\n /**\n * Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for the encrypted private key.\n */\n chacha20NonceB64u?: string;\n wrapKeySalt?: string;\n error?: string;\n}> {\n try {\n // PRF outputs are now extracted by VRF worker and delivered to signer worker via MessagePort\n // No need to extract or send them through main thread\n if (!sessionId) throw new Error('Missing sessionId for registration WrapKeySeed delivery');\n\n const response = await ctx.sendMessage<WorkerRequestType.DeriveNearKeypairAndEncrypt>({\n sessionId,\n message: {\n type: WorkerRequestType.DeriveNearKeypairAndEncrypt,\n payload: withSessionId(sessionId, {\n nearAccountId: nearAccountId,\n credential,\n authenticatorOptions: options?.authenticatorOptions ? {\n userVerification: toEnumUserVerificationPolicy(options.authenticatorOptions.userVerification),\n originPolicy: options.authenticatorOptions.originPolicy,\n } : undefined,\n })\n },\n });\n\n if (!isDeriveNearKeypairAndEncryptSuccess(response)) {\n throw new Error('Dual PRF registration (from serialized) failed');\n }\n\n const wasmResult = response.payload;\n const wrapKeySaltPersisted = wasmResult.wrapKeySalt;\n if (!wrapKeySaltPersisted) {\n throw new Error('Missing wrapKeySalt in deriveNearKeypairAndEncrypt result');\n }\n // Prefer explicitly provided deviceNumber, else derive from IndexedDB state\n const deviceNumber = (typeof options?.deviceNumber === 'number')\n ? options!.deviceNumber!\n : await getLastLoggedInDeviceNumber(nearAccountId, ctx.indexedDB.clientDB);\n const chacha20NonceB64u = wasmResult.chacha20NonceB64u;\n if (!chacha20NonceB64u) {\n throw new Error('Missing chacha20NonceB64u in deriveNearKeypairAndEncrypt result');\n }\n const keyMaterial: LocalNearSkV3Material = {\n kind: 'local_near_sk_v3',\n nearAccountId,\n deviceNumber,\n publicKey: wasmResult.publicKey,\n encryptedSk: wasmResult.encryptedData,\n chacha20NonceB64u,\n wrapKeySalt: wrapKeySaltPersisted,\n timestamp: Date.now(),\n };\n await ctx.indexedDB.nearKeysDB.storeKeyMaterial(keyMaterial);\n\n return {\n success: true,\n nearAccountId: toAccountId(wasmResult.nearAccountId),\n publicKey: wasmResult.publicKey,\n chacha20NonceB64u,\n wrapKeySalt: wrapKeySaltPersisted,\n };\n } catch (error: unknown) {\n console.error('WebAuthnManager: deriveNearKeypairAndEncryptFromSerialized error:', error);\n const message = String((error as { message?: unknown })?.message || error || '');\n return {\n success: false,\n nearAccountId,\n publicKey: '',\n error: message\n };\n }\n}\n","\nimport { ClientAuthenticatorData } from '../../../IndexedDBManager';\nimport {\n WorkerRequestType,\n isDecryptPrivateKeyWithPrfSuccess,\n} from '../../../types/signer-worker';\nimport { AccountId, toAccountId } from \"../../../types/accountIds\";\n\nimport { SignerWorkerManagerContext } from '..';\nimport { getLastLoggedInDeviceNumber } from '../getDeviceNumber';\nimport { isObject } from '@/utils/validation';\nimport { withSessionId } from './session';\n\nexport async function decryptPrivateKeyWithPrf({\n ctx,\n nearAccountId,\n authenticators,\n sessionId,\n}: {\n ctx: SignerWorkerManagerContext,\n nearAccountId: AccountId,\n authenticators: ClientAuthenticatorData[],\n sessionId: string,\n}): Promise<{ decryptedPrivateKey: string; nearAccountId: AccountId }> {\n try {\n console.info('WebAuthnManager: Starting private key decryption with dual PRF (local operation)');\n // Retrieve encrypted key data from IndexedDB in main thread\n const deviceNumber = await getLastLoggedInDeviceNumber(nearAccountId, ctx.indexedDB.clientDB);\n const keyMaterial = await ctx.indexedDB.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber);\n if (!keyMaterial) {\n throw new Error(`No key material found for account: ${nearAccountId}`);\n }\n\n const response = await ctx.sendMessage({\n sessionId,\n message: {\n type: WorkerRequestType.DecryptPrivateKeyWithPrf,\n payload: withSessionId(sessionId, {\n nearAccountId: nearAccountId,\n encryptedPrivateKeyData: keyMaterial.encryptedSk,\n encryptedPrivateKeyChacha20NonceB64u: keyMaterial.chacha20NonceB64u,\n })\n },\n });\n\n if (!isDecryptPrivateKeyWithPrfSuccess(response)) {\n console.error('WebAuthnManager: Dual PRF private key decryption failed:', response);\n const payloadError = isObject(response?.payload) && (response as any)?.payload?.error;\n throw new Error(payloadError || 'Private key decryption failed');\n }\n return {\n decryptedPrivateKey: response.payload.privateKey,\n nearAccountId: toAccountId(response.payload.nearAccountId)\n };\n } catch (error: unknown) {\n console.error('WebAuthnManager: Dual PRF private key decryption error:', error);\n throw error;\n }\n}\n","/**\n * Session Handshake Orchestration for Signer Worker\n *\n * This module provides high-level functions for setting up and validating\n * signing sessions with the signer worker. It orchestrates the complete\n * handshake flow for port attachment so the VRF worker can deliver WrapKeySeed\n * to the signer worker over a session MessagePort.\n */\n\nimport { waitForWrapKeyPortAttach } from './sessionMessages.js';\nimport { computeUiIntentDigestFromTxs, orderActionForDigest } from '../../digests/intentDigest';\nimport type { NearClient } from '../../NearClient';\nimport type { NonceManager } from '../../nonceManager';\nimport type { TransactionContext } from '../../types/rpc';\nimport type { TransactionInputWasm } from '../../types/actions';\nimport { WorkerControlMessage } from '../../workerControlMessages';\n\ntype VrfSessionKeyDispenser = {\n dispenseSessionKey: (args: { sessionId: string; uses?: number }) => Promise<unknown>;\n};\n\n/**\n * Attach a WrapKeySeed MessagePort to the signer worker and wait for acknowledgment.\n * This ensures the port is successfully attached before proceeding.\n *\n * Flow:\n * 1. Register ACK listener (avoids race where worker responds before we listen)\n * 2. Send ATTACH_WRAP_KEY_SEED_PORT message with port transfer\n * 3. Wait for ATTACH_WRAP_KEY_SEED_PORT_OK acknowledgment\n *\n * @param worker - The signer worker to attach the port to\n * @param sessionId - The signing session ID\n * @param signerPort - The MessagePort for receiving WrapKeySeed material\n * @param timeoutMs - How long to wait for ACK (default: 2000ms)\n * @throws Error if attachment fails or times out\n */\nexport async function attachSessionPort(\n worker: Worker,\n sessionId: string,\n signerPort: MessagePort,\n timeoutMs: number = 2000\n): Promise<void> {\n // Register the ACK listener BEFORE sending the message to avoid race condition\n const waitPromise = waitForWrapKeyPortAttach(worker, sessionId, timeoutMs);\n\n // Send the attach command (transfer the port)\n worker.postMessage(\n { type: WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT, sessionId },\n [signerPort]\n );\n\n // Wait for the worker to acknowledge successful attachment\n await waitPromise;\n}\n\nexport const generateSessionId = (): string => {\n return (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function')\n ? crypto.randomUUID()\n : `sign-session-${Date.now()}-${Math.random().toString(16).slice(2)}`\n}\n\nexport function isWarmSessionUnavailableError(err: unknown): boolean {\n const msg = err instanceof Error ? err.message : String(err);\n return (\n msg.includes('SESSION_NOT_FOUND') ||\n msg.includes('SESSION_EXPIRED') ||\n msg.includes('SESSION_EXHAUSTED')\n );\n}\n\nfunction releaseNoncesBestEffort(nonceManager: NonceManager, nonces: string[]): void {\n for (const n of nonces) {\n try { nonceManager.releaseNonce(n); } catch {}\n }\n}\n\n/**\n * Warm signing helper for transaction-like operations.\n *\n * - Computes canonical `intentDigest` for UI/signer validation\n * - Reserves nonces for `txCount` to avoid collisions\n * - Attempts VRF session key dispense (WrapKeySeed + wrapKeySalt) without prompting\n *\n * Returns null when the VRF session is missing/expired/exhausted so callers can\n * fall back to full confirmTxFlow.\n */\nexport async function tryPrepareWarmSigningContext(args: {\n nearClient: NearClient;\n nonceManager: NonceManager;\n txInputsForDigest: TransactionInputWasm[];\n sessionId: string;\n vrfWorkerManager: VrfSessionKeyDispenser;\n nonceCount?: number;\n uses?: number;\n}): Promise<{ intentDigest: string; transactionContext: TransactionContext } | null> {\n const baseCtx = await args.nonceManager.getNonceBlockHashAndHeight(args.nearClient);\n const txCount = Math.max(1, args.nonceCount ?? args.txInputsForDigest.length ?? 1);\n const reservedNonces = args.nonceManager.reserveNonces(txCount);\n\n let keepReservations = false;\n try {\n const transactionContext: TransactionContext = {\n ...baseCtx,\n nextNonce: reservedNonces[0] ?? baseCtx.nextNonce,\n };\n\n const intentDigest = await computeUiIntentDigestFromTxs(\n args.txInputsForDigest.map(tx => ({\n receiverId: tx.receiverId,\n actions: tx.actions.map(orderActionForDigest),\n })) as TransactionInputWasm[]\n );\n\n const uses = Math.max(1, args.uses ?? txCount);\n try {\n await args.vrfWorkerManager.dispenseSessionKey({ sessionId: args.sessionId, uses });\n } catch (err) {\n if (isWarmSessionUnavailableError(err)) {\n return null;\n }\n throw err;\n }\n\n keepReservations = true;\n return { intentDigest, transactionContext };\n } finally {\n if (!keepReservations) {\n releaseNoncesBestEffort(args.nonceManager, reservedNonces);\n }\n }\n}\n","import type { SignerMode, ThresholdBehavior } from '../types/signer-worker';\nimport { DEFAULT_THRESHOLD_BEHAVIOR, getThresholdBehaviorFromSignerMode } from '../types/signer-worker';\nimport { stripTrailingSlashes, toTrimmedString } from '../../utils/validation';\n\nexport type ThresholdEd25519HealthzResponse =\n | { ok: true; configured: true }\n | { ok: false; configured: false; code?: string; message?: string };\n\nconst DEFAULT_CACHE_TTL_MS = 60_000;\nconst cache = new Map<string, { configured: boolean; expiresAtMs: number }>();\nconst inFlight = new Map<string, Promise<boolean>>();\nconst DEFAULT_WARN_TTL_MS = 10 * 60_000;\nconst MAX_WARN_KEYS = 1_000;\nconst warnedUnsupportedRelayerByKey = new Map<string, number>();\n\nexport async function isRelayerThresholdEd25519Configured(\n relayerUrl: string,\n opts?: { cacheTtlMs?: number },\n): Promise<boolean> {\n const base = stripTrailingSlashes(toTrimmedString(relayerUrl));\n return isRelayerThresholdEd25519ConfiguredBase(base, opts);\n}\n\nasync function isRelayerThresholdEd25519ConfiguredBase(\n base: string,\n opts?: { cacheTtlMs?: number },\n): Promise<boolean> {\n if (!base) return false;\n if (typeof fetch !== 'function') return false;\n\n const ttlMs = Math.max(0, Number(opts?.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS));\n const now = Date.now();\n const cached = cache.get(base);\n if (cached && cached.expiresAtMs > now) return cached.configured;\n\n const existing = inFlight.get(base);\n if (existing) return existing;\n\n const req = (async (): Promise<boolean> => {\n try {\n const res = await fetch(`${base}/threshold-ed25519/healthz`, { method: 'GET' });\n if (!res.ok) {\n cache.set(base, { configured: false, expiresAtMs: now + ttlMs });\n return false;\n }\n const data = (await res.json().catch(() => null)) as ThresholdEd25519HealthzResponse | null;\n const configured = data?.configured === true;\n cache.set(base, { configured, expiresAtMs: now + ttlMs });\n return configured;\n } catch {\n cache.set(base, { configured: false, expiresAtMs: now + ttlMs });\n return false;\n } finally {\n inFlight.delete(base);\n }\n })();\n\n inFlight.set(base, req);\n return req;\n}\n\nfunction coerceThresholdBehavior(input?: ThresholdBehavior): ThresholdBehavior {\n return input === 'fallback' || input === 'strict' ? input : DEFAULT_THRESHOLD_BEHAVIOR;\n}\n\nfunction pruneWarned(nowMs: number): void {\n if (warnedUnsupportedRelayerByKey.size <= MAX_WARN_KEYS) return;\n for (const [key, expiresAtMs] of warnedUnsupportedRelayerByKey.entries()) {\n if (expiresAtMs <= nowMs) warnedUnsupportedRelayerByKey.delete(key);\n }\n while (warnedUnsupportedRelayerByKey.size > MAX_WARN_KEYS) {\n const first = warnedUnsupportedRelayerByKey.keys().next().value as string | undefined;\n if (!first) break;\n warnedUnsupportedRelayerByKey.delete(first);\n }\n}\n\nfunction warnOnce(key: string, message: string, opts?: { warnTtlMs?: number; warnings?: string[] }): void {\n const nowMs = Date.now();\n const ttlMs = Math.max(0, Math.floor(opts?.warnTtlMs ?? DEFAULT_WARN_TTL_MS));\n if (ttlMs === 0) return;\n pruneWarned(nowMs);\n const existing = warnedUnsupportedRelayerByKey.get(key);\n if (existing && existing > nowMs) return;\n warnedUnsupportedRelayerByKey.set(key, nowMs + ttlMs);\n // eslint-disable-next-line no-console\n console.warn(message);\n opts?.warnings?.push(message);\n}\n\nexport async function fallbackToLocalSignerIfRelayerUnsupported(args: {\n nearAccountId: string;\n signerMode: SignerMode;\n relayerUrl: string;\n warnings?: string[];\n cacheTtlMs?: number;\n warnTtlMs?: number;\n}): Promise<SignerMode['mode']> {\n const requested = args.signerMode.mode;\n if (requested !== 'threshold-signer') return requested;\n\n const base = stripTrailingSlashes(toTrimmedString(args.relayerUrl));\n const behavior = coerceThresholdBehavior(getThresholdBehaviorFromSignerMode(args.signerMode));\n const configured = await isRelayerThresholdEd25519ConfiguredBase(base, { cacheTtlMs: args.cacheTtlMs });\n if (configured) return requested;\n\n const msg = '[WebAuthnManager] signerMode=threshold-signer requested but the relayer does not support threshold signing';\n if (behavior === 'fallback') {\n warnOnce(`${args.nearAccountId}|${base}`, `${msg}; falling back to local-signer`, {\n warnTtlMs: args.warnTtlMs,\n warnings: args.warnings,\n });\n return 'local-signer';\n }\n throw new Error(`${msg}; set signerMode={ mode: 'threshold-signer', behavior: 'fallback' } to allow local-signer fallback`);\n}\n\nexport async function resolveSignerModeForThresholdSigning(args: {\n nearAccountId: string;\n signerMode: SignerMode;\n relayerUrl: string;\n hasThresholdKeyMaterial: boolean;\n warnings?: string[];\n cacheTtlMs?: number;\n warnTtlMs?: number;\n}): Promise<SignerMode['mode']> {\n const requested = args.signerMode.mode;\n if (requested !== 'threshold-signer') return requested;\n\n const behavior = coerceThresholdBehavior(getThresholdBehaviorFromSignerMode(args.signerMode));\n\n if (!args.hasThresholdKeyMaterial) {\n const msg = '[WebAuthnManager] signerMode=threshold-signer requested but threshold key material is unavailable';\n if (behavior === 'fallback') {\n warnOnce(`${args.nearAccountId}|threshold-key-material-missing`, `${msg}; falling back to local-signer`, {\n warnTtlMs: args.warnTtlMs,\n warnings: args.warnings,\n });\n return 'local-signer';\n }\n throw new Error(`${msg}; set signerMode={ mode: 'threshold-signer', behavior: 'fallback' } to allow local-signer fallback`);\n }\n\n return fallbackToLocalSignerIfRelayerUnsupported({\n nearAccountId: args.nearAccountId,\n signerMode: args.signerMode,\n relayerUrl: args.relayerUrl,\n warnings: args.warnings,\n cacheTtlMs: args.cacheTtlMs,\n warnTtlMs: args.warnTtlMs,\n });\n}\n","import { base64UrlDecode } from '@/utils/encoders';\nimport { stripTrailingSlashes, toTrimmedString } from '@/utils/validation';\nimport { removePrfOutputGuard } from '../WebAuthnManager/credentialsHelpers';\nimport type { VRFChallenge } from '../types/vrf-worker';\nimport type { ThresholdEd25519SessionPolicy } from './thresholdSessionPolicy';\nimport type { WebAuthnAuthenticationCredential } from '../types/webauthn';\nimport { normalizeThresholdEd25519ParticipantIds } from '../../threshold/participants';\n\nexport type ThresholdEd25519SessionKind = 'jwt' | 'cookie';\n\nexport type ThresholdEd25519AuthSession = {\n sessionKind: ThresholdEd25519SessionKind;\n policy: ThresholdEd25519SessionPolicy;\n policyJson: string;\n sessionPolicyDigest32: string;\n jwt?: string;\n expiresAtMs?: number;\n};\n\ntype ThresholdEd25519AuthSessionCacheEntry = ThresholdEd25519AuthSession;\n\nconst authSessionCache = new Map<string, ThresholdEd25519AuthSessionCacheEntry>();\n\nexport function makeThresholdEd25519AuthSessionCacheKey(args: {\n nearAccountId: string;\n rpId: string;\n relayerUrl: string;\n relayerKeyId: string;\n participantIds?: number[];\n}): string {\n const relayerUrl = stripTrailingSlashes(toTrimmedString(args.relayerUrl));\n const participantIds = normalizeThresholdEd25519ParticipantIds(args.participantIds);\n return [\n String(args.nearAccountId || '').trim(),\n String(args.rpId || '').trim(),\n relayerUrl,\n String(args.relayerKeyId || '').trim(),\n ...(participantIds ? [participantIds.join(',')] : []),\n ].join('|');\n}\n\nexport function getCachedThresholdEd25519AuthSession(cacheKey: string): ThresholdEd25519AuthSession | null {\n const entry = authSessionCache.get(cacheKey);\n if (!entry) return null;\n\n if (typeof entry.expiresAtMs === 'number' && Number.isFinite(entry.expiresAtMs) && Date.now() >= entry.expiresAtMs) {\n authSessionCache.delete(cacheKey);\n return null;\n }\n\n return entry;\n}\n\nexport function putCachedThresholdEd25519AuthSession(cacheKey: string, entry: ThresholdEd25519AuthSession): void {\n authSessionCache.set(cacheKey, entry);\n}\n\nexport function clearCachedThresholdEd25519AuthSession(cacheKey: string): void {\n authSessionCache.delete(cacheKey);\n}\n\nexport function clearAllCachedThresholdEd25519AuthSessions(): void {\n authSessionCache.clear();\n}\n\nexport function getCachedThresholdEd25519AuthSessionJwt(cacheKey: string): string | undefined {\n const cached = getCachedThresholdEd25519AuthSession(cacheKey);\n const jwt = cached?.jwt;\n if (typeof jwt === 'string') {\n const trimmed = jwt.trim();\n if (trimmed) return trimmed;\n }\n if (cached) clearCachedThresholdEd25519AuthSession(cacheKey);\n return undefined;\n}\n\nexport async function mintThresholdEd25519AuthSession(args: {\n relayerUrl: string;\n sessionKind: ThresholdEd25519SessionKind;\n relayerKeyId: string;\n clientVerifyingShareB64u: string;\n sessionPolicy: ThresholdEd25519SessionPolicy;\n vrfChallenge: VRFChallenge;\n webauthnAuthentication: WebAuthnAuthenticationCredential;\n}): Promise<{\n ok: boolean;\n sessionId?: string;\n expiresAtMs?: number;\n remainingUses?: number;\n jwt?: string;\n code?: string;\n message?: string;\n}> {\n const relayerUrl = stripTrailingSlashes(toTrimmedString(args.relayerUrl));\n if (!relayerUrl) {\n return { ok: false, code: 'invalid_args', message: 'Missing relayerUrl for threshold session mint' };\n }\n\n if (typeof fetch !== 'function') {\n return { ok: false, code: 'unsupported', message: 'fetch is not available for threshold session mint' };\n }\n\n const toBytes = (b64u: string | undefined): number[] => {\n if (!b64u) return [];\n return Array.from(base64UrlDecode(b64u));\n };\n\n const intent_digest_32 = toBytes(args.vrfChallenge.intentDigest);\n if (intent_digest_32.length !== 32) {\n return { ok: false, code: 'invalid_args', message: 'Missing or invalid vrfChallenge.intentDigest (expected base64url 32 bytes)' };\n }\n\n const clientVerifyingShareBytes = toBytes(args.clientVerifyingShareB64u);\n if (clientVerifyingShareBytes.length !== 32) {\n return { ok: false, code: 'invalid_args', message: 'Missing or invalid clientVerifyingShareB64u (expected base64url 32 bytes)' };\n }\n\n const session_policy_digest_32 = toBytes(args.vrfChallenge.sessionPolicyDigest32);\n if (session_policy_digest_32.length !== 32) {\n return { ok: false, code: 'invalid_args', message: 'Missing vrfChallenge.sessionPolicyDigest32 (expected base64url 32 bytes) for threshold session mint' };\n }\n\n const vrf_data = {\n vrf_input_data: toBytes(args.vrfChallenge.vrfInput),\n vrf_output: toBytes(args.vrfChallenge.vrfOutput),\n vrf_proof: toBytes(args.vrfChallenge.vrfProof),\n public_key: toBytes(args.vrfChallenge.vrfPublicKey),\n user_id: args.vrfChallenge.userId,\n rp_id: args.vrfChallenge.rpId,\n block_height: Number(args.vrfChallenge.blockHeight || 0),\n block_hash: toBytes(args.vrfChallenge.blockHash),\n intent_digest_32,\n session_policy_digest_32,\n };\n\n // Never send PRF outputs to the relay.\n const webauthn_authentication = removePrfOutputGuard(args.webauthnAuthentication);\n\n type ThresholdEd25519SessionMintResponseBody = Partial<{\n ok: boolean;\n sessionId: string;\n expiresAt: string;\n remainingUses: number;\n jwt: string;\n code: string;\n message: string;\n }>;\n\n try {\n const url = `${relayerUrl}/threshold-ed25519/session`;\n const response = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n credentials: args.sessionKind === 'cookie' ? 'include' : 'omit',\n body: JSON.stringify({\n sessionKind: args.sessionKind,\n relayerKeyId: args.relayerKeyId,\n clientVerifyingShareB64u: args.clientVerifyingShareB64u,\n sessionPolicy: args.sessionPolicy,\n vrf_data,\n webauthn_authentication,\n }),\n });\n\n const data = (await response.json().catch(() => ({}))) as ThresholdEd25519SessionMintResponseBody;\n if (!response.ok) {\n return {\n ok: false,\n code: data.code || 'http_error',\n message: data.message || `HTTP ${response.status}`,\n };\n }\n\n const expiresAtMs = (() => {\n const raw = data.expiresAt ? Date.parse(data.expiresAt) : NaN;\n return Number.isFinite(raw) ? raw : undefined;\n })();\n\n return {\n ok: data.ok === true,\n sessionId: data.sessionId,\n expiresAtMs,\n remainingUses: data.remainingUses,\n jwt: data.jwt,\n ...(data.code ? { code: data.code } : {}),\n ...(data.message ? { message: data.message } : {}),\n };\n } catch (e: unknown) {\n const msg = String((e && typeof e === 'object' && 'message' in e) ? (e as { message?: unknown }).message : e || 'Failed to mint threshold session');\n return { ok: false, code: 'network_error', message: msg };\n }\n}\n","import { alphabetizeStringify, sha256BytesUtf8 } from '@/utils/digests';\nimport { base64UrlEncode } from '@/utils/encoders';\nimport { normalizeThresholdEd25519ParticipantIds } from '../../threshold/participants';\n\nexport const THRESHOLD_SESSION_POLICY_VERSION = 'threshold_session_v1' as const;\n\nexport type ThresholdEd25519SessionPolicy = {\n version: typeof THRESHOLD_SESSION_POLICY_VERSION;\n nearAccountId: string;\n rpId: string;\n relayerKeyId: string;\n sessionId: string;\n /**\n * Optional signer set binding (participant ids).\n *\n * When present, the relayer must bind the session token to this signer set and ensure\n * downstream signature share usage is scoped to the same set.\n */\n participantIds?: number[];\n ttlMs: number;\n remainingUses: number;\n};\n\nexport const THRESHOLD_SESSION_POLICY_MAX_TTL_MS = 10 * 60_000;\nexport const THRESHOLD_SESSION_POLICY_MAX_USES = 20;\n\n// Default policy used when callers do not specify a policy explicitly.\n// These defaults are kept conservative to limit the blast radius of a stolen token.\nexport const DEFAULT_THRESHOLD_SESSION_POLICY: Pick<ThresholdEd25519SessionPolicy, 'ttlMs' | 'remainingUses'> = {\n ttlMs: 5 * 60_000,\n remainingUses: 5,\n};\n\nexport function clampThresholdSessionPolicy(input: {\n ttlMs: number;\n remainingUses: number;\n}): { ttlMs: number; remainingUses: number } {\n const ttlMs = Math.max(0, Math.floor(Number(input.ttlMs) || 0));\n const remainingUses = Math.max(0, Math.floor(Number(input.remainingUses) || 0));\n return {\n ttlMs: Math.min(ttlMs, THRESHOLD_SESSION_POLICY_MAX_TTL_MS),\n remainingUses: Math.min(remainingUses, THRESHOLD_SESSION_POLICY_MAX_USES),\n };\n}\n\nexport function generateThresholdSessionId(): string {\n const id = (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function')\n ? crypto.randomUUID()\n : `tsess-${Date.now()}-${Math.random().toString(16).slice(2)}`;\n return `tsess-${id}`;\n}\n\nexport async function computeThresholdSessionPolicyDigest32(policy: ThresholdEd25519SessionPolicy): Promise<string> {\n const json = alphabetizeStringify(policy);\n const bytes = await sha256BytesUtf8(json);\n return base64UrlEncode(bytes);\n}\n\nexport async function buildThresholdSessionPolicy(params: {\n nearAccountId: string;\n rpId: string;\n relayerKeyId: string;\n participantIds?: number[];\n sessionId?: string;\n ttlMs?: number;\n remainingUses?: number;\n}): Promise<{\n policy: ThresholdEd25519SessionPolicy;\n policyJson: string;\n sessionPolicyDigest32: string;\n}> {\n const sessionId = params.sessionId || generateThresholdSessionId();\n const { ttlMs, remainingUses } = clampThresholdSessionPolicy({\n ttlMs: params.ttlMs ?? DEFAULT_THRESHOLD_SESSION_POLICY.ttlMs,\n remainingUses: params.remainingUses ?? DEFAULT_THRESHOLD_SESSION_POLICY.remainingUses,\n });\n const participantIds = normalizeThresholdEd25519ParticipantIds(params.participantIds);\n const policy: ThresholdEd25519SessionPolicy = {\n version: THRESHOLD_SESSION_POLICY_VERSION,\n nearAccountId: params.nearAccountId,\n rpId: params.rpId,\n relayerKeyId: params.relayerKeyId,\n sessionId,\n ...(participantIds ? { participantIds } : {}),\n ttlMs,\n remainingUses,\n };\n const sessionPolicyDigest32 = await computeThresholdSessionPolicyDigest32(policy);\n return { policy, policyJson: JSON.stringify(policy), sessionPolicyDigest32 };\n}\n\nexport function isThresholdSessionAuthUnavailableError(err: unknown): boolean {\n const msg = err instanceof Error ? err.message : String(err);\n return (\n msg.includes('no cached threshold session token') ||\n msg.includes('relayer threshold session expired') ||\n msg.includes('threshold session exhausted') ||\n msg.includes('threshold session expired') ||\n msg.includes('Missing or invalid threshold session token') ||\n msg.includes('Invalid session token kind') ||\n msg.includes('/authorize HTTP 401') ||\n msg.includes('/authorize HTTP 403')\n );\n}\n\nexport function isThresholdSignerMissingKeyError(err: unknown): boolean {\n const msg = (err instanceof Error ? err.message : String(err)).toLowerCase();\n return (\n msg.includes('\"code\":\"missing_key\"') ||\n msg.includes('missing_key') ||\n msg.includes('unknown relayerkeyid') ||\n msg.includes('call /threshold-ed25519/keygen')\n );\n}\n","\nimport { SignedTransaction } from '../../../NearClient';\nimport { TransactionInputWasm, validateActionArgsWasm } from '../../../types/actions';\nimport { type onProgressEvents } from '../../../types/sdkSentEvents';\nimport {\n WorkerRequestType,\n TransactionPayload,\n isSignTransactionsWithActionsSuccess,\n isWorkerError,\n type ConfirmationConfig,\n type RpcCallPayload,\n type SignerMode,\n type TransactionResponse,\n type WorkerSuccessResponse,\n getThresholdBehaviorFromSignerMode,\n} from '../../../types/signer-worker';\nimport { AccountId } from '../../../types/accountIds';\nimport { SignerWorkerManagerContext } from '..';\nimport { PASSKEY_MANAGER_DEFAULT_CONFIGS } from '../../../defaultConfigs';\nimport { toAccountId } from '../../../types/accountIds';\nimport { getLastLoggedInDeviceNumber } from '../getDeviceNumber';\nimport { generateSessionId } from '../sessionHandshake.js';\nimport { WebAuthnAuthenticationCredential } from '../../../types';\nimport { removePrfOutputGuard } from '../../credentialsHelpers';\nimport { resolveSignerModeForThresholdSigning } from '../../../threshold/thresholdEd25519RelayerHealth';\nimport type { TransactionContext } from '../../../types/rpc';\nimport type { VRFChallenge } from '../../../types/vrf-worker';\nimport type {\n LocalNearSkV3Material,\n ThresholdEd25519_2p_V1Material,\n} from '../../../IndexedDBManager/passkeyNearKeysDB';\nimport {\n clearCachedThresholdEd25519AuthSession,\n getCachedThresholdEd25519AuthSessionJwt,\n makeThresholdEd25519AuthSessionCacheKey,\n} from '../../../threshold/thresholdEd25519AuthSession';\nimport {\n isThresholdSessionAuthUnavailableError,\n isThresholdSignerMissingKeyError,\n} from '../../../threshold/thresholdSessionPolicy';\nimport { normalizeThresholdEd25519ParticipantIds } from '../../../../threshold/participants';\n\n/**\n * Sign multiple transactions with shared VRF challenge and credential\n * Efficiently processes multiple transactions with one PRF authentication\n */\nexport async function signTransactionsWithActions({\n ctx,\n sessionId: providedSessionId,\n transactions,\n rpcCall,\n signerMode,\n onEvent,\n confirmationConfigOverride,\n title,\n body,\n}: {\n ctx: SignerWorkerManagerContext,\n sessionId?: string;\n transactions: TransactionInputWasm[],\n rpcCall: RpcCallPayload;\n signerMode: SignerMode;\n onEvent?: (update: onProgressEvents) => void;\n // Allow callers to pass a partial override (e.g., { uiMode: 'drawer' })\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n title?: string;\n body?: string;\n}): Promise<Array<{\n signedTransaction: SignedTransaction;\n nearAccountId: AccountId;\n logs?: string[]\n}>> {\n\n const sessionId = providedSessionId ?? generateSessionId();\n const nearAccountId = rpcCall.nearAccountId;\n const relayerUrl = ctx.relayerUrl;\n\n transactions.forEach(txPayload => {\n txPayload.actions.forEach(action => {\n validateActionArgsWasm(action);\n })\n })\n\n const deviceNumber = await getLastLoggedInDeviceNumber(nearAccountId, ctx.indexedDB.clientDB);\n\n // Retrieve encrypted key data from IndexedDB in main thread\n const [localKeyMaterial, thresholdKeyMaterial] = await Promise.all([\n ctx.indexedDB.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber),\n ctx.indexedDB.nearKeysDB.getThresholdKeyMaterial(nearAccountId, deviceNumber),\n ]);\n if (!localKeyMaterial) {\n throw new Error(`No local key material found for account: ${nearAccountId}`);\n }\n\n\t const warnings: string[] = [];\n\t const thresholdBehavior = getThresholdBehaviorFromSignerMode(signerMode);\n\t const resolvedSignerMode = await resolveSignerModeForThresholdSigning({\n\t nearAccountId,\n\t signerMode,\n\t relayerUrl,\n\t hasThresholdKeyMaterial: !!thresholdKeyMaterial,\n warnings,\n });\n console.debug('[signTransactionsWithActions] resolvedSignerMode', { nearAccountId, resolvedSignerMode, warnings });\n\n const signingContext = validateAndPrepareSigningContext({\n nearAccountId,\n resolvedSignerMode,\n relayerUrl,\n rpId: ctx.touchIdPrompt.getRpId(),\n localKeyMaterial,\n thresholdKeyMaterial,\n });\n\n // Ensure nonce/block context is fetched for the same access key that will sign.\n // Threshold signing MUST use the threshold/group public key (relayer access key) for:\n // - correct nonce reservation\n // - relayer scope checks (/authorize expects signingPayload.transactionContext.nearPublicKeyStr == relayer key)\n ctx.nonceManager.initializeUser(toAccountId(nearAccountId), signingContext.signingNearPublicKeyStr);\n\n // Normalize rpcCall to ensure required fields are present.\n const resolvedRpcCall = {\n contractId: rpcCall.contractId || PASSKEY_MANAGER_DEFAULT_CONFIGS.contractId,\n nearRpcUrl: rpcCall.nearRpcUrl || PASSKEY_MANAGER_DEFAULT_CONFIGS.nearRpcUrl,\n nearAccountId: rpcCall.nearAccountId,\n } as RpcCallPayload;\n\n // Create transaction signing requests (shared by local + threshold signing).\n // NOTE: nonce and blockHash are computed in confirmation flow, not here.\n const txSigningRequests: TransactionPayload[] = transactions.map(tx => ({\n nearAccountId: rpcCall.nearAccountId,\n receiverId: tx.receiverId,\n actions: tx.actions,\n }));\n\n // Confirm via VRF-driven flow before sending anything to the signer worker.\n // WrapKeySeed derivation is handled inside confirmTxFlow (handleTransactionSigningFlow),\n // which uses the same sessionId/requestId and delivers WrapKeySeed over the reserved port.\n if (!ctx.vrfWorkerManager) {\n throw new Error('VrfWorkerManager not available for signing');\n }\n const confirmation = await ctx.vrfWorkerManager.confirmAndPrepareSigningSession({\n ctx,\n sessionId,\n kind: 'transaction',\n ...(signingContext.threshold && !signingContext.threshold.thresholdSessionJwt ? { signingAuthMode: 'webauthn' } : {}),\n txSigningRequests: transactions,\n rpcCall: resolvedRpcCall,\n confirmationConfigOverride,\n title,\n body,\n });\n\n\t let { intentDigest, transactionContext, vrfChallenge, credential } =\n\t extractSigningEvidenceFromConfirmation(confirmation);\n\n\t // Threshold signer: authorize with relayer and pass threshold config into the signer worker.\n\t if (signingContext.threshold) {\n\t const requestPayload = {\n\t signerMode: signingContext.resolvedSignerMode,\n\t rpcCall: resolvedRpcCall,\n\t createdAt: Date.now(),\n\t decryption: {\n encryptedPrivateKeyData: '',\n encryptedPrivateKeyChacha20NonceB64u: '',\n },\n threshold: {\n relayerUrl: signingContext.threshold.relayerUrl,\n relayerKeyId: signingContext.threshold.thresholdKeyMaterial.relayerKeyId,\n clientParticipantId: signingContext.threshold.thresholdKeyMaterial.participants.find((p) => p.role === 'client')?.id,\n relayerParticipantId: signingContext.threshold.thresholdKeyMaterial.participants.find((p) => p.role === 'relayer')?.id,\n participantIds: signingContext.threshold.thresholdKeyMaterial.participants.map((p) => p.id),\n thresholdSessionKind: 'jwt' as const,\n thresholdSessionJwt: signingContext.threshold.thresholdSessionJwt,\n },\n txSigningRequests,\n intentDigest,\n transactionContext,\n\t vrfChallenge,\n\t credential,\n\t };\n\n\t for (let attempt = 0; attempt < 2; attempt++) {\n\t try {\n\t const response = await ctx.sendMessage<typeof WorkerRequestType.SignTransactionsWithActions>({\n\t sessionId,\n\t message: { type: WorkerRequestType.SignTransactionsWithActions, payload: requestPayload },\n\t onEvent,\n\t });\n\t const okResponse = requireOkSignTransactionsWithActionsResponse(response);\n\t return toSignedTransactionResults({\n\t okResponse,\n\t expectedTransactionCount: transactions.length,\n\t nearAccountId,\n\t warnings,\n\t });\n\t } catch (e: unknown) {\n\t const err = e instanceof Error ? e : new Error(String(e));\n\n\t if (thresholdBehavior === 'fallback' && isThresholdSignerMissingKeyError(err)) {\n\t const msg =\n\t '[WebAuthnManager] threshold-signer requested but the relayer is missing the signing share; falling back to local-signer';\n\t // eslint-disable-next-line no-console\n\t console.warn(msg);\n\t warnings.push(msg);\n\n\t try {\n\t clearCachedThresholdEd25519AuthSession(signingContext.threshold.thresholdSessionCacheKey);\n\t } catch {}\n\t signingContext.threshold.thresholdSessionJwt = undefined;\n\t requestPayload.threshold.thresholdSessionJwt = undefined;\n\n\t ctx.nonceManager.initializeUser(toAccountId(nearAccountId), localKeyMaterial.publicKey);\n\t if (!credential || !vrfChallenge) {\n\t const refreshed = await ctx.vrfWorkerManager.confirmAndPrepareSigningSession({\n\t ctx,\n\t sessionId,\n\t kind: 'transaction',\n\t signingAuthMode: 'webauthn',\n\t txSigningRequests: transactions,\n\t rpcCall: resolvedRpcCall,\n\t confirmationConfigOverride,\n\t title,\n\t body,\n\t });\n\t ({ intentDigest, transactionContext, vrfChallenge, credential } =\n\t extractSigningEvidenceFromConfirmation(refreshed));\n\t } else {\n\t transactionContext = await ctx.nonceManager.getNonceBlockHashAndHeight(ctx.nearClient, { force: true });\n\t }\n\n\t return await signTransactionsWithActionsLocally({\n\t ctx,\n\t sessionId,\n\t onEvent,\n\t resolvedRpcCall,\n\t localKeyMaterial,\n\t txSigningRequests,\n\t intentDigest,\n\t transactionContext,\n\t credential,\n\t expectedTransactionCount: transactions.length,\n\t warnings,\n\t });\n\t }\n\n\t if (attempt === 0 && isThresholdSessionAuthUnavailableError(err)) {\n\t clearCachedThresholdEd25519AuthSession(signingContext.threshold.thresholdSessionCacheKey);\n\t signingContext.threshold.thresholdSessionJwt = undefined;\n\t requestPayload.threshold.thresholdSessionJwt = undefined;\n\n\t if (!credential || !vrfChallenge) {\n\t const refreshed = await ctx.vrfWorkerManager.confirmAndPrepareSigningSession({\n\t ctx,\n\t sessionId,\n\t kind: 'transaction',\n\t signingAuthMode: 'webauthn',\n\t txSigningRequests: transactions,\n\t rpcCall: resolvedRpcCall,\n\t confirmationConfigOverride,\n\t title,\n\t body,\n\t });\n\n\t ({ intentDigest, transactionContext, vrfChallenge, credential } =\n\t extractSigningEvidenceFromConfirmation(refreshed));\n\n\t requestPayload.intentDigest = intentDigest;\n\t requestPayload.transactionContext = transactionContext;\n\t requestPayload.vrfChallenge = vrfChallenge;\n\t requestPayload.credential = credential;\n\t }\n\n\t continue;\n\t }\n\n\t throw err;\n\t }\n\t }\n\t }\n\n\t return await signTransactionsWithActionsLocally({\n\t ctx,\n\t sessionId,\n\t onEvent,\n\t resolvedRpcCall,\n\t localKeyMaterial,\n\t txSigningRequests,\n\t intentDigest,\n\t transactionContext,\n\t credential,\n\t expectedTransactionCount: transactions.length,\n\t warnings,\n\t });\n\n\t}\n\nasync function signTransactionsWithActionsLocally(args: {\n ctx: SignerWorkerManagerContext;\n sessionId: string;\n onEvent?: (update: onProgressEvents) => void;\n resolvedRpcCall: RpcCallPayload;\n localKeyMaterial: LocalNearSkV3Material;\n txSigningRequests: TransactionPayload[];\n intentDigest: string;\n transactionContext: TransactionContext;\n credential: string | undefined;\n expectedTransactionCount: number;\n warnings: string[];\n}): Promise<Array<{\n signedTransaction: SignedTransaction;\n nearAccountId: AccountId;\n logs?: string[];\n}>> {\n const response = await args.ctx.sendMessage<WorkerRequestType.SignTransactionsWithActions>({\n sessionId: args.sessionId,\n message: {\n type: WorkerRequestType.SignTransactionsWithActions,\n payload: {\n signerMode: 'local-signer',\n rpcCall: args.resolvedRpcCall,\n createdAt: Date.now(),\n decryption: {\n encryptedPrivateKeyData: args.localKeyMaterial.encryptedSk,\n encryptedPrivateKeyChacha20NonceB64u: args.localKeyMaterial.chacha20NonceB64u,\n },\n txSigningRequests: args.txSigningRequests,\n intentDigest: args.intentDigest,\n transactionContext: args.transactionContext,\n credential: args.credential,\n },\n },\n onEvent: args.onEvent,\n });\n\n const okResponse = requireOkSignTransactionsWithActionsResponse(response);\n return toSignedTransactionResults({\n okResponse,\n expectedTransactionCount: args.expectedTransactionCount,\n nearAccountId: args.resolvedRpcCall.nearAccountId,\n warnings: args.warnings,\n });\n}\n\nfunction toSignedTransactionResults(args: {\n okResponse: WorkerSuccessResponse<typeof WorkerRequestType.SignTransactionsWithActions>;\n expectedTransactionCount: number;\n nearAccountId: string;\n warnings: string[];\n}): Array<{\n signedTransaction: SignedTransaction;\n nearAccountId: AccountId;\n logs?: string[];\n}> {\n const signedTransactions = args.okResponse.payload.signedTransactions || [];\n if (signedTransactions.length !== args.expectedTransactionCount) {\n throw new Error(\n `Expected ${args.expectedTransactionCount} signed transactions but received ${signedTransactions.length}`\n );\n }\n\n return signedTransactions.map((signedTx, index) => {\n if (!signedTx || !signedTx.transaction || !signedTx.signature) {\n throw new Error(`Incomplete signed transaction data received for transaction ${index + 1}`);\n }\n return {\n signedTransaction: new SignedTransaction({\n transaction: signedTx.transaction,\n signature: signedTx.signature,\n borsh_bytes: Array.from(signedTx.borshBytes || []),\n }),\n nearAccountId: toAccountId(args.nearAccountId),\n logs: [...(args.okResponse.payload.logs || []), ...args.warnings],\n };\n });\n}\n\ntype ThresholdSigningContext = {\n resolvedSignerMode: 'threshold-signer';\n signingNearPublicKeyStr: string;\n threshold: {\n relayerUrl: string;\n thresholdKeyMaterial: ThresholdEd25519_2p_V1Material;\n thresholdSessionCacheKey: string;\n thresholdSessionJwt: string | undefined;\n };\n};\n\ntype LocalSigningContext = {\n resolvedSignerMode: 'local-signer';\n signingNearPublicKeyStr: string;\n threshold: null;\n};\n\ntype SigningContext = ThresholdSigningContext | LocalSigningContext;\n\nfunction validateAndPrepareSigningContext(args: {\n nearAccountId: string;\n resolvedSignerMode: SignerMode['mode'];\n relayerUrl: string;\n rpId: string | null;\n localKeyMaterial: LocalNearSkV3Material;\n thresholdKeyMaterial: ThresholdEd25519_2p_V1Material | null;\n}): SigningContext {\n const localPublicKey = String(args.localKeyMaterial.publicKey || '').trim();\n if (!localPublicKey) {\n throw new Error(`Missing local signing public key for ${args.nearAccountId}`);\n }\n\n if (args.resolvedSignerMode !== 'threshold-signer') {\n return { resolvedSignerMode: 'local-signer', signingNearPublicKeyStr: localPublicKey, threshold: null };\n }\n\n const thresholdKeyMaterial = args.thresholdKeyMaterial;\n if (!thresholdKeyMaterial) {\n throw new Error(`Missing threshold key material for ${args.nearAccountId}`);\n }\n\n const thresholdPublicKey = String(thresholdKeyMaterial.publicKey || '').trim();\n if (!thresholdPublicKey) {\n throw new Error(`Missing threshold signing public key for ${args.nearAccountId}`);\n }\n\n const relayerUrl = String(args.relayerUrl || '').trim();\n if (!relayerUrl) {\n throw new Error('Missing relayerUrl (required for threshold-signer)');\n }\n\n const rpId = String(args.rpId || '').trim();\n if (!rpId) {\n throw new Error('Missing rpId for threshold signing');\n }\n\n const participantIds = normalizeThresholdEd25519ParticipantIds(thresholdKeyMaterial.participants.map((p) => p.id));\n if (!participantIds || participantIds.length < 2) {\n throw new Error(\n `Invalid threshold signing participantIds (expected >=2 participants, got [${(participantIds || []).join(',')}])`\n );\n }\n\n const thresholdSessionCacheKey = makeThresholdEd25519AuthSessionCacheKey({\n nearAccountId: args.nearAccountId,\n rpId,\n relayerUrl,\n relayerKeyId: thresholdKeyMaterial.relayerKeyId,\n participantIds,\n });\n\n return {\n resolvedSignerMode: 'threshold-signer',\n signingNearPublicKeyStr: thresholdPublicKey,\n threshold: {\n relayerUrl,\n thresholdKeyMaterial,\n thresholdSessionCacheKey,\n thresholdSessionJwt: getCachedThresholdEd25519AuthSessionJwt(thresholdSessionCacheKey),\n },\n };\n}\n\nfunction extractSigningEvidenceFromConfirmation(confirmation: {\n intentDigest: string;\n transactionContext: TransactionContext;\n vrfChallenge?: VRFChallenge;\n credential?: unknown;\n}): {\n intentDigest: string;\n transactionContext: TransactionContext;\n vrfChallenge: VRFChallenge | undefined;\n credential: string | undefined;\n} {\n const credentialForRelay: WebAuthnAuthenticationCredential | undefined = confirmation.credential\n ? removePrfOutputGuard(confirmation.credential as WebAuthnAuthenticationCredential)\n : undefined;\n\n return {\n intentDigest: confirmation.intentDigest,\n transactionContext: confirmation.transactionContext,\n vrfChallenge: confirmation.vrfChallenge,\n credential: credentialForRelay ? JSON.stringify(credentialForRelay) : undefined,\n };\n}\n\nfunction requireOkSignTransactionsWithActionsResponse(\n response: TransactionResponse\n): WorkerSuccessResponse<typeof WorkerRequestType.SignTransactionsWithActions> {\n if (!isSignTransactionsWithActionsSuccess(response)) {\n if (isWorkerError(response)) {\n throw new Error(response.payload.error || 'Batch transaction signing failed');\n }\n throw new Error('Batch transaction signing failed');\n }\n\n if (!response.payload.success) {\n throw new Error(response.payload.error || 'Batch transaction signing failed');\n }\n return response;\n}\n","import { normalizeRegistrationCredential } from '../../credentialsHelpers';\nimport type { WebAuthnRegistrationCredential } from '../../../types/webauthn';\nimport { validateVRFChallenge, type VRFChallenge } from '../../../types/vrf-worker';\nimport type { TransactionContext } from '../../../types/rpc';\nimport { isObject, assertString } from '@/utils/validation';\nimport { DelegateActionInput } from '../../../types/delegate';\nimport { base58Encode } from '../../../../utils/base58';\n\nimport { ensureEd25519Prefix } from '../../../nearCrypto';\nexport { ensureEd25519Prefix };\n\nexport const toPublicKeyString = (pk: DelegateActionInput['publicKey']): string => {\n if (typeof pk === 'string') {\n return pk;\n }\n return ensureEd25519Prefix(base58Encode(pk.keyData));\n};\n\n// Strongly typed payload expected from the WASM → JS boundary\nexport interface RegistrationCredentialConfirmationPayload {\n confirmed: boolean;\n requestId: string;\n intentDigest: string;\n credential: WebAuthnRegistrationCredential; // serialized PublicKeyCredential (no methods)\n vrfChallenge: VRFChallenge;\n transactionContext?: TransactionContext;\n error?: string;\n}\n\nfunction validateTransactionContextMaybe(input: unknown): TransactionContext | undefined {\n if (input == null) return undefined;\n if (!isObject(input)) {\n throw new Error('Invalid transactionContext: expected object');\n }\n\n const {\n nearPublicKeyStr,\n nextNonce,\n txBlockHeight,\n txBlockHash,\n accessKeyInfo,\n } = input as {\n nearPublicKeyStr?: unknown;\n nextNonce?: unknown;\n txBlockHeight?: unknown;\n txBlockHash?: unknown;\n accessKeyInfo?: unknown;\n };\n\n // Minimal structural validation; AccessKeyView is complex. Be tolerant because the WASM struct omits it.\n const normalizedNearPublicKeyStr = assertString(\n nearPublicKeyStr,\n 'transactionContext.nearPublicKeyStr',\n );\n const normalizedNextNonce = assertString(nextNonce, 'transactionContext.nextNonce');\n const normalizedTxBlockHeight = assertString(\n txBlockHeight,\n 'transactionContext.txBlockHeight',\n );\n const normalizedTxBlockHash = assertString(txBlockHash, 'transactionContext.txBlockHash');\n\n let normalizedAccessKeyInfo = accessKeyInfo as TransactionContext['accessKeyInfo'] | undefined;\n if (normalizedAccessKeyInfo != null && !isObject(normalizedAccessKeyInfo)) {\n throw new Error('Invalid transactionContext.accessKeyInfo: expected object');\n }\n if (normalizedAccessKeyInfo == null) {\n // Synthesize a minimal placeholder; not used by registration flows consuming this payload\n normalizedAccessKeyInfo = { nonce: 0 } as unknown as TransactionContext['accessKeyInfo'];\n }\n\n return {\n nearPublicKeyStr: normalizedNearPublicKeyStr,\n nextNonce: normalizedNextNonce,\n txBlockHeight: normalizedTxBlockHeight,\n txBlockHash: normalizedTxBlockHash,\n accessKeyInfo: normalizedAccessKeyInfo,\n };\n}\n\nfunction validateCredentialMaybe(input: unknown): WebAuthnRegistrationCredential | undefined {\n if (input == null) return undefined;\n\n const cred = normalizeRegistrationCredential(input);\n if (cred.type !== 'public-key') {\n throw new Error('Invalid credential.type: expected \"public-key\"');\n }\n\n const { id, rawId, response, authenticatorAttachment } = cred as {\n id?: unknown;\n rawId?: unknown;\n response?: unknown;\n authenticatorAttachment?: unknown;\n };\n\n // Core field/type validation (serialized shapes should be base64url strings)\n assertString(id, 'credential.id');\n assertString(rawId, 'credential.rawId');\n\n if (!isObject(response)) {\n throw new Error('Invalid credential.response: expected object');\n }\n\n const {\n clientDataJSON,\n attestationObject,\n transports,\n } = response as {\n clientDataJSON?: unknown;\n attestationObject?: unknown;\n transports?: unknown;\n };\n\n assertString(clientDataJSON, 'credential.response.clientDataJSON');\n assertString(attestationObject, 'credential.response.attestationObject');\n\n if (!Array.isArray(transports)) {\n throw new Error('Invalid credential.response.transports: expected string[]');\n }\n for (const t of transports) {\n if (typeof t !== 'string') {\n throw new Error('Invalid credential.response.transports item: expected string');\n }\n }\n\n if (authenticatorAttachment != null && typeof authenticatorAttachment !== 'string') {\n throw new Error('Invalid credential.authenticatorAttachment: expected string | undefined');\n }\n\n // Note: prf.results may be undefined/null here. We intentionally do NOT\n // require them at the boundary; internal callers that need PRF (e.g. key\n // derivation) will extract/compute them separately. Contract payloads must\n // not include PRF values.\n return cred;\n}\n\nfunction validateVrfChallengeMaybe(input: unknown): VRFChallenge | undefined {\n if (input == null) return undefined;\n return validateVRFChallenge(input as Parameters<typeof validateVRFChallenge>[0]);\n}\n\nexport function parseAndValidateRegistrationCredentialConfirmationPayload(\n payload: unknown,\n): RegistrationCredentialConfirmationPayload {\n\n if (!isObject(payload)) {\n throw new Error('Invalid response payload: expected object');\n }\n\n const {\n confirmed,\n requestId,\n intentDigest,\n credential,\n vrfChallenge,\n transactionContext,\n error,\n } = payload as {\n confirmed?: unknown;\n requestId?: unknown;\n intentDigest?: unknown;\n credential?: unknown;\n vrfChallenge?: unknown;\n transactionContext?: unknown;\n error?: unknown;\n };\n\n const normalizedRequestId = assertString(requestId, 'requestId');\n\n // intentDigest is only used for TX signing requests, not registration or link device requests\n const normalizedIntentDigest =\n intentDigest == null ? '' : assertString(intentDigest, 'intentDigest');\n\n const normalizedCredential =\n credential != null ? validateCredentialMaybe(credential) : undefined;\n\n if (!normalizedCredential) {\n throw new Error('Missing registration credential');\n }\n\n const normalizedVrfChallenge =\n vrfChallenge != null ? validateVrfChallengeMaybe(vrfChallenge) : undefined;\n\n if (!normalizedVrfChallenge) {\n throw new Error('Missing VRF Challenge');\n }\n\n const normalizedTransactionContext =\n transactionContext != null ? validateTransactionContextMaybe(transactionContext) : undefined;\n\n const normalizedError =\n error == null ? undefined : assertString(error, 'error');\n\n return {\n confirmed: !!confirmed,\n requestId: normalizedRequestId,\n intentDigest: normalizedIntentDigest,\n credential: normalizedCredential,\n vrfChallenge: normalizedVrfChallenge,\n transactionContext: normalizedTransactionContext,\n error: normalizedError,\n };\n}","import { PASSKEY_MANAGER_DEFAULT_CONFIGS } from '../../../defaultConfigs';\nimport { AccountId, toAccountId } from '../../../types/accountIds';\nimport { toActionArgsWasm, validateActionArgsWasm } from '../../../types/actions';\nimport { DelegateActionInput } from '../../../types/delegate';\nimport { type onProgressEvents } from '../../../types/sdkSentEvents';\nimport {\n ConfirmationConfig,\n RpcCallPayload,\n type SignerMode,\n WorkerRequestType,\n type DelegateSignResponse,\n isWorkerError,\n isSignDelegateActionSuccess,\n type WorkerSuccessResponse,\n WasmSignedDelegate,\n} from '../../../types/signer-worker';\nimport type { WebAuthnAuthenticationCredential } from '../../../types';\nimport { removePrfOutputGuard } from '../../credentialsHelpers';\nimport { resolveSignerModeForThresholdSigning } from '../../../threshold/thresholdEd25519RelayerHealth';\nimport type {\n LocalNearSkV3Material,\n ThresholdEd25519_2p_V1Material,\n} from '../../../IndexedDBManager/passkeyNearKeysDB';\nimport type { TransactionContext } from '../../../types/rpc';\nimport type { VRFChallenge } from '../../../types/vrf-worker';\nimport {\n clearCachedThresholdEd25519AuthSession,\n getCachedThresholdEd25519AuthSessionJwt,\n makeThresholdEd25519AuthSessionCacheKey,\n} from '../../../threshold/thresholdEd25519AuthSession';\nimport { isThresholdSessionAuthUnavailableError } from '../../../threshold/thresholdSessionPolicy';\nimport { normalizeThresholdEd25519ParticipantIds } from '../../../../threshold/participants';\nimport { SignerWorkerManagerContext } from '..';\nimport { getLastLoggedInDeviceNumber } from '../getDeviceNumber';\nimport { generateSessionId } from '../sessionHandshake.js';\nimport { ensureEd25519Prefix, toPublicKeyString } from './validation';\n\nexport async function signDelegateAction({\n ctx,\n delegate,\n rpcCall,\n signerMode,\n onEvent,\n confirmationConfigOverride,\n title,\n body,\n sessionId: providedSessionId,\n}: {\n ctx: SignerWorkerManagerContext;\n delegate: DelegateActionInput;\n rpcCall: RpcCallPayload;\n signerMode: SignerMode;\n onEvent?: (update: onProgressEvents) => void;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n title?: string;\n body?: string;\n sessionId?: string;\n}): Promise<{\n signedDelegate: WasmSignedDelegate;\n hash: string;\n nearAccountId: AccountId;\n logs?: string[];\n}> {\n const sessionId = providedSessionId ?? generateSessionId();\n const nearAccountId = rpcCall.nearAccountId || delegate.senderId;\n const relayerUrl = ctx.relayerUrl;\n\n const resolvedRpcCall = {\n contractId: rpcCall.contractId || PASSKEY_MANAGER_DEFAULT_CONFIGS.contractId,\n nearRpcUrl: rpcCall.nearRpcUrl || (PASSKEY_MANAGER_DEFAULT_CONFIGS.nearRpcUrl.split(',')[0] || PASSKEY_MANAGER_DEFAULT_CONFIGS.nearRpcUrl),\n nearAccountId,\n } as RpcCallPayload;\n\n const actionsWasm = delegate.actions.map(toActionArgsWasm);\n actionsWasm.forEach((action, actionIndex) => {\n try {\n validateActionArgsWasm(action);\n } catch (error) {\n throw new Error(\n `Delegate action ${actionIndex} validation failed: ${error instanceof Error ? error.message : String(error)}`\n );\n }\n });\n\n const deviceNumber = await getLastLoggedInDeviceNumber(nearAccountId, ctx.indexedDB.clientDB);\n const [localKeyMaterial, thresholdKeyMaterial] = await Promise.all([\n ctx.indexedDB.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber),\n ctx.indexedDB.nearKeysDB.getThresholdKeyMaterial(nearAccountId, deviceNumber),\n ]);\n if (!localKeyMaterial) {\n throw new Error(`No local key material found for account: ${nearAccountId}`);\n }\n\n const warnings: string[] = [];\n const vrfWorkerManager = ctx.vrfWorkerManager;\n if (!vrfWorkerManager) {\n throw new Error('VrfWorkerManager not available for delegate signing');\n }\n\n const resolvedSignerMode = await resolveSignerModeForThresholdSigning({\n nearAccountId,\n signerMode,\n relayerUrl,\n hasThresholdKeyMaterial: !!thresholdKeyMaterial,\n warnings,\n });\n\n const signingContext = validateAndPrepareDelegateSigningContext({\n nearAccountId,\n resolvedSignerMode,\n relayerUrl,\n rpId: ctx.touchIdPrompt.getRpId(),\n localKeyMaterial,\n thresholdKeyMaterial,\n providedDelegatePublicKey: delegate.publicKey,\n warnings,\n });\n\n // Ensure nonce/block context is fetched for the same access key that will sign.\n // Threshold signing MUST use the threshold/group public key (relayer access key) for:\n // - correct nonce reservation\n // - relayer scope checks (/authorize expects signingPayload.delegate.publicKey == relayer key)\n ctx.nonceManager.initializeUser(toAccountId(nearAccountId), signingContext.signingNearPublicKeyStr);\n\n const confirmation = await vrfWorkerManager.confirmAndPrepareSigningSession({\n ctx,\n sessionId,\n kind: 'delegate',\n ...(signingContext.threshold && !signingContext.threshold.thresholdSessionJwt ? { signingAuthMode: 'webauthn' } : {}),\n nearAccountId,\n delegate: {\n senderId: delegate.senderId || nearAccountId,\n receiverId: delegate.receiverId,\n actions: actionsWasm,\n nonce: delegate.nonce,\n maxBlockHeight: delegate.maxBlockHeight,\n },\n rpcCall: resolvedRpcCall,\n confirmationConfigOverride,\n title,\n body,\n });\n\n let { intentDigest, transactionContext, vrfChallenge, credential } =\n extractSigningEvidenceFromConfirmation(confirmation);\n\n const delegatePayload = {\n senderId: delegate.senderId || nearAccountId,\n receiverId: delegate.receiverId,\n actions: actionsWasm,\n nonce: delegate.nonce.toString(),\n maxBlockHeight: delegate.maxBlockHeight.toString(),\n publicKey: signingContext.delegatePublicKeyStr,\n };\n\n if (!signingContext.threshold) {\n const response = await ctx.sendMessage<WorkerRequestType.SignDelegateAction>({\n sessionId,\n message: {\n type: WorkerRequestType.SignDelegateAction,\n payload: {\n signerMode: signingContext.resolvedSignerMode,\n rpcCall: resolvedRpcCall,\n createdAt: Date.now(),\n decryption: {\n encryptedPrivateKeyData: localKeyMaterial.encryptedSk,\n encryptedPrivateKeyChacha20NonceB64u: localKeyMaterial.chacha20NonceB64u,\n },\n delegate: delegatePayload,\n intentDigest,\n transactionContext,\n credential,\n },\n },\n onEvent,\n });\n\n const okResponse = requireOkSignDelegateActionResponse(response);\n return {\n signedDelegate: okResponse.payload.signedDelegate!,\n hash: okResponse.payload.hash!,\n nearAccountId: toAccountId(nearAccountId),\n logs: [...(okResponse.payload.logs || []), ...warnings],\n };\n }\n\n const requestPayload = {\n signerMode: signingContext.resolvedSignerMode,\n rpcCall: resolvedRpcCall,\n createdAt: Date.now(),\n decryption: {\n encryptedPrivateKeyData: '',\n encryptedPrivateKeyChacha20NonceB64u: '',\n },\n threshold: {\n relayerUrl: signingContext.threshold.relayerUrl,\n relayerKeyId: signingContext.threshold.thresholdKeyMaterial.relayerKeyId,\n clientParticipantId: signingContext.threshold.thresholdKeyMaterial.participants.find((p) => p.role === 'client')?.id,\n relayerParticipantId: signingContext.threshold.thresholdKeyMaterial.participants.find((p) => p.role === 'relayer')?.id,\n participantIds: signingContext.threshold.thresholdKeyMaterial.participants.map((p) => p.id),\n thresholdSessionKind: 'jwt' as const,\n thresholdSessionJwt: signingContext.threshold.thresholdSessionJwt,\n },\n delegate: delegatePayload,\n intentDigest,\n transactionContext,\n vrfChallenge,\n credential,\n };\n\n let okResponse: WorkerSuccessResponse<typeof WorkerRequestType.SignDelegateAction>;\n try {\n const resp = await ctx.sendMessage<typeof WorkerRequestType.SignDelegateAction>({\n sessionId,\n message: { type: WorkerRequestType.SignDelegateAction, payload: requestPayload },\n onEvent,\n });\n okResponse = requireOkSignDelegateActionResponse(resp);\n } catch (e: unknown) {\n const err = e instanceof Error ? e : new Error(String(e));\n if (!isThresholdSessionAuthUnavailableError(err)) throw err;\n\n clearCachedThresholdEd25519AuthSession(signingContext.threshold.thresholdSessionCacheKey);\n signingContext.threshold.thresholdSessionJwt = undefined;\n requestPayload.threshold.thresholdSessionJwt = undefined;\n\n if (!credential || !vrfChallenge) {\n const refreshed = await vrfWorkerManager.confirmAndPrepareSigningSession({\n ctx,\n sessionId,\n kind: 'delegate',\n signingAuthMode: 'webauthn',\n nearAccountId,\n delegate: {\n senderId: delegate.senderId || nearAccountId,\n receiverId: delegate.receiverId,\n actions: actionsWasm,\n nonce: delegate.nonce,\n maxBlockHeight: delegate.maxBlockHeight,\n },\n rpcCall: resolvedRpcCall,\n confirmationConfigOverride,\n title,\n body,\n });\n\n ({ intentDigest, transactionContext, vrfChallenge, credential } =\n extractSigningEvidenceFromConfirmation(refreshed));\n\n requestPayload.intentDigest = intentDigest;\n requestPayload.transactionContext = transactionContext;\n requestPayload.vrfChallenge = vrfChallenge;\n requestPayload.credential = credential;\n }\n\n const resp = await ctx.sendMessage<typeof WorkerRequestType.SignDelegateAction>({\n sessionId,\n message: { type: WorkerRequestType.SignDelegateAction, payload: requestPayload },\n onEvent,\n });\n okResponse = requireOkSignDelegateActionResponse(resp);\n }\n\n return {\n signedDelegate: okResponse.payload.signedDelegate!,\n hash: okResponse.payload.hash!,\n nearAccountId: toAccountId(nearAccountId),\n logs: [...(okResponse.payload.logs || []), ...warnings],\n };\n}\n\ntype ThresholdDelegateSigningContext = {\n resolvedSignerMode: 'threshold-signer';\n signingNearPublicKeyStr: string;\n delegatePublicKeyStr: string;\n threshold: {\n relayerUrl: string;\n thresholdKeyMaterial: ThresholdEd25519_2p_V1Material;\n thresholdSessionCacheKey: string;\n thresholdSessionJwt: string | undefined;\n };\n};\n\ntype LocalDelegateSigningContext = {\n resolvedSignerMode: 'local-signer';\n signingNearPublicKeyStr: string;\n delegatePublicKeyStr: string;\n threshold: null;\n};\n\ntype DelegateSigningContext = ThresholdDelegateSigningContext | LocalDelegateSigningContext;\n\nfunction validateAndPrepareDelegateSigningContext(args: {\n nearAccountId: string;\n resolvedSignerMode: SignerMode['mode'];\n relayerUrl: string;\n rpId: string | null;\n localKeyMaterial: LocalNearSkV3Material;\n thresholdKeyMaterial: ThresholdEd25519_2p_V1Material | null;\n providedDelegatePublicKey: DelegateActionInput['publicKey'];\n warnings: string[];\n}): DelegateSigningContext {\n const localPublicKey = ensureEd25519Prefix(args.localKeyMaterial.publicKey);\n if (!localPublicKey) {\n throw new Error(`Missing local signing public key for ${args.nearAccountId}`);\n }\n\n const providedDelegatePublicKeyStr = ensureEd25519Prefix(toPublicKeyString(args.providedDelegatePublicKey));\n\n if (args.resolvedSignerMode !== 'threshold-signer') {\n if (providedDelegatePublicKeyStr && providedDelegatePublicKeyStr !== localPublicKey) {\n args.warnings.push(\n `Delegate public key ${providedDelegatePublicKeyStr} does not match local signer key; using ${localPublicKey}`\n );\n }\n return {\n resolvedSignerMode: 'local-signer',\n signingNearPublicKeyStr: localPublicKey,\n delegatePublicKeyStr: localPublicKey,\n threshold: null,\n };\n }\n\n const thresholdKeyMaterial = args.thresholdKeyMaterial;\n if (!thresholdKeyMaterial) {\n throw new Error(`Missing threshold key material for ${args.nearAccountId}`);\n }\n\n const thresholdPublicKey = ensureEd25519Prefix(thresholdKeyMaterial.publicKey);\n if (!thresholdPublicKey) {\n throw new Error(`Missing threshold signing public key for ${args.nearAccountId}`);\n }\n\n if (providedDelegatePublicKeyStr && providedDelegatePublicKeyStr !== thresholdPublicKey) {\n args.warnings.push(\n `Delegate public key ${providedDelegatePublicKeyStr} does not match threshold signer key; using ${thresholdPublicKey}`\n );\n }\n\n const relayerUrl = String(args.relayerUrl || '').trim();\n if (!relayerUrl) {\n throw new Error('Missing relayerUrl (required for threshold-signer)');\n }\n\n const rpId = String(args.rpId || '').trim();\n if (!rpId) {\n throw new Error('Missing rpId for threshold signing');\n }\n\n const participantIds = normalizeThresholdEd25519ParticipantIds(thresholdKeyMaterial.participants.map((p) => p.id));\n if (!participantIds || participantIds.length < 2) {\n throw new Error(\n `Invalid threshold signing participantIds (expected >=2 participants, got [${(participantIds || []).join(',')}])`\n );\n }\n\n const thresholdSessionCacheKey = makeThresholdEd25519AuthSessionCacheKey({\n nearAccountId: args.nearAccountId,\n rpId,\n relayerUrl,\n relayerKeyId: thresholdKeyMaterial.relayerKeyId,\n participantIds,\n });\n\n return {\n resolvedSignerMode: 'threshold-signer',\n signingNearPublicKeyStr: thresholdPublicKey,\n delegatePublicKeyStr: thresholdPublicKey,\n threshold: {\n relayerUrl,\n thresholdKeyMaterial,\n thresholdSessionCacheKey,\n thresholdSessionJwt: getCachedThresholdEd25519AuthSessionJwt(thresholdSessionCacheKey),\n },\n };\n}\n\nfunction extractSigningEvidenceFromConfirmation(confirmation: {\n intentDigest: string;\n transactionContext: TransactionContext;\n vrfChallenge?: VRFChallenge;\n credential?: unknown;\n}): {\n intentDigest: string;\n transactionContext: TransactionContext;\n vrfChallenge: VRFChallenge | undefined;\n credential: string | undefined;\n} {\n const credentialForRelay: WebAuthnAuthenticationCredential | undefined = confirmation.credential\n ? removePrfOutputGuard(confirmation.credential as WebAuthnAuthenticationCredential)\n : undefined;\n\n return {\n intentDigest: confirmation.intentDigest,\n transactionContext: confirmation.transactionContext,\n vrfChallenge: confirmation.vrfChallenge,\n credential: credentialForRelay ? JSON.stringify(credentialForRelay) : undefined,\n };\n}\n\nfunction requireOkSignDelegateActionResponse(\n response: DelegateSignResponse\n): WorkerSuccessResponse<typeof WorkerRequestType.SignDelegateAction> {\n if (!isSignDelegateActionSuccess(response)) {\n if (isWorkerError(response)) {\n throw new Error(response.payload.error || 'Delegate action signing failed');\n }\n throw new Error('Delegate action signing failed');\n }\n\n if (!response.payload.success || !response.payload.signedDelegate || !response.payload.hash) {\n throw new Error(response.payload.error || 'Delegate action signing failed');\n }\n return response;\n}\n","import {\n WorkerRequestType, // from wasm worker\n isRecoverKeypairFromPasskeySuccess,\n} from '../../../types/signer-worker';\nimport type { WebAuthnAuthenticationCredential } from '../../../types/webauthn';\nimport { SignerWorkerManagerContext } from '..';\nimport { withSessionId } from './session';\n\n/**\n * Recover keypair from authentication credential for account recovery\n * Uses dual PRF-based Ed25519 key derivation with account-specific HKDF and AES encryption\n */\nexport async function recoverKeypairFromPasskey({\n ctx,\n credential,\n accountIdHint,\n sessionId,\n}: {\n ctx: SignerWorkerManagerContext;\n credential: WebAuthnAuthenticationCredential;\n accountIdHint?: string;\n sessionId: string;\n}): Promise<{\n publicKey: string;\n encryptedPrivateKey: string;\n /**\n * Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for the encrypted private key.\n */\n chacha20NonceB64u: string;\n accountIdHint?: string;\n wrapKeySalt: string;\n}> {\n try {\n console.info('SignerWorkerManager: Starting dual PRF-based keypair recovery from authentication credential');\n // Accept either live PublicKeyCredential or already-serialized auth credential\n\n // Verify dual PRF outputs are available\n if (\n !credential.clientExtensionResults?.prf?.results?.first ||\n !credential.clientExtensionResults?.prf?.results?.second\n ) {\n throw new Error('Dual PRF outputs required for account recovery - both ChaCha20 and Ed25519 PRF outputs must be available');\n }\n\n if (!sessionId) throw new Error('Missing sessionId for recovery WrapKeySeed delivery');\n\n // Use generic sendMessage with specific request type for better type safety\n const response = await ctx.sendMessage<WorkerRequestType.RecoverKeypairFromPasskey>({\n sessionId,\n message: {\n type: WorkerRequestType.RecoverKeypairFromPasskey,\n payload: withSessionId(sessionId, {\n credential,\n accountIdHint,\n })\n },\n });\n\n // response is RecoverKeypairSuccessResponse | RecoverKeypairFailureResponse\n if (!isRecoverKeypairFromPasskeySuccess(response)) {\n throw new Error('Dual PRF keypair recovery failed in WASM worker');\n }\n\n const chacha20NonceB64u = response.payload.chacha20NonceB64u;\n if (!chacha20NonceB64u) {\n throw new Error('Missing chacha20NonceB64u in recovery result');\n }\n return {\n publicKey: response.payload.publicKey,\n encryptedPrivateKey: response.payload.encryptedData,\n chacha20NonceB64u,\n accountIdHint: response.payload.accountIdHint,\n wrapKeySalt: response.payload.wrapKeySalt,\n };\n\n } catch (error: unknown) {\n console.error('SignerWorkerManager: Dual PRF keypair recovery error:', error);\n throw error;\n }\n}\n","\nimport { WorkerRequestType, isExtractCosePublicKeySuccess } from '../../../types/signer-worker';\nimport { SignerWorkerManagerContext } from '..';\n\n\n/**\n * Extract COSE public key from WebAuthn attestation object\n * Simple operation that doesn't require TouchID or progress updates\n */\nexport async function extractCosePublicKey({ ctx, attestationObjectBase64url }: {\n ctx: SignerWorkerManagerContext;\n attestationObjectBase64url: string;\n}): Promise<Uint8Array> {\n try {\n const response = await ctx.sendMessage<WorkerRequestType.ExtractCosePublicKey>({\n message: {\n type: WorkerRequestType.ExtractCosePublicKey,\n payload: {\n attestationObjectBase64url\n }\n }\n });\n\n if (isExtractCosePublicKeySuccess(response)) {\n return response.payload.cosePublicKeyBytes;\n } else {\n throw new Error('COSE public key extraction failed in WASM worker');\n }\n } catch (error: unknown) {\n throw error;\n }\n}\n","\nimport { SignedTransaction } from '../../../NearClient';\nimport { type ActionArgsWasm, validateActionArgsWasm } from '../../../types/actions';\nimport {\n WorkerRequestType,\n WorkerResponseType,\n WasmTransactionSignResult,\n} from '../../../types/signer-worker';\nimport { SignerWorkerManagerContext } from '..';\n\n/**\n * Sign transaction with raw private key (for key replacement in Option D device linking)\n * No TouchID/PRF required - uses provided private key directly\n */\nexport async function signTransactionWithKeyPair({\n ctx,\n nearPrivateKey,\n signerAccountId,\n receiverId,\n nonce,\n blockHash,\n actions\n}: {\n ctx: SignerWorkerManagerContext;\n nearPrivateKey: string;\n signerAccountId: string;\n receiverId: string;\n nonce: string;\n blockHash: string;\n actions: ActionArgsWasm[];\n}): Promise<{\n signedTransaction: SignedTransaction;\n logs?: string[];\n}> {\n try {\n console.info('SignerWorkerManager: Starting transaction signing with provided private key');\n // Validate actions\n actions.forEach(action => {\n validateActionArgsWasm(action);\n });\n\n const response = await ctx.sendMessage<WorkerRequestType.SignTransactionWithKeyPair>({\n message: {\n type: WorkerRequestType.SignTransactionWithKeyPair,\n payload: {\n nearPrivateKey,\n signerAccountId,\n receiverId,\n nonce,\n blockHash: blockHash,\n actions: actions\n }\n }\n });\n\n if (response.type !== WorkerResponseType.SignTransactionWithKeyPairSuccess) {\n console.error('SignerWorkerManager: Transaction signing with private key failed:', response);\n throw new Error('Transaction signing with private key failed');\n }\n\n const wasmResult = response.payload as WasmTransactionSignResult;\n if (!wasmResult.success) {\n throw new Error(wasmResult.error || 'Transaction signing failed');\n }\n // Extract the signed transaction\n const signedTransactions = wasmResult.signedTransactions || [];\n if (signedTransactions.length !== 1) {\n throw new Error(`Expected 1 signed transaction but received ${signedTransactions.length}`);\n }\n const signedTx = signedTransactions[0];\n if (!signedTx || !signedTx.transaction || !signedTx.signature) {\n throw new Error('Incomplete signed transaction data received');\n }\n\n const result = {\n signedTransaction: new SignedTransaction({\n transaction: signedTx.transaction,\n signature: signedTx.signature,\n borsh_bytes: Array.from(signedTx.borshBytes || [])\n }),\n logs: wasmResult.logs\n };\n\n console.debug('SignerWorkerManager: Transaction signing with private key successful');\n return result;\n\n } catch (error: unknown) {\n console.error('SignerWorkerManager: Transaction signing with private key error:', error);\n throw error;\n }\n}\n","import {\n WorkerRequestType,\n isSignNep413MessageSuccess,\n isWorkerError,\n type ConfirmationConfig,\n type Nep413SigningResponse,\n type SignerMode,\n type WorkerSuccessResponse,\n} from '../../../types/signer-worker';\nimport type { WebAuthnAuthenticationCredential } from '../../../types';\nimport { removePrfOutputGuard } from '../../credentialsHelpers';\nimport { resolveSignerModeForThresholdSigning } from '../../../threshold/thresholdEd25519RelayerHealth';\nimport type {\n LocalNearSkV3Material,\n ThresholdEd25519_2p_V1Material,\n} from '../../../IndexedDBManager/passkeyNearKeysDB';\nimport type { VRFChallenge } from '../../../types/vrf-worker';\nimport {\n clearCachedThresholdEd25519AuthSession,\n getCachedThresholdEd25519AuthSessionJwt,\n makeThresholdEd25519AuthSessionCacheKey,\n} from '../../../threshold/thresholdEd25519AuthSession';\nimport { isThresholdSessionAuthUnavailableError } from '../../../threshold/thresholdSessionPolicy';\nimport { normalizeThresholdEd25519ParticipantIds } from '../../../../threshold/participants';\nimport { getLastLoggedInDeviceNumber } from '../getDeviceNumber';\nimport { generateSessionId } from '../sessionHandshake.js';\nimport { SignerWorkerManagerContext } from '..';\n\n/**\n * Sign a NEP-413 message using the user's passkey-derived private key\n *\n * @param payload - NEP-413 signing parameters including message, recipient, nonce, and state\n * @returns Promise resolving to signing result with account ID, public key, and signature\n */\nexport async function signNep413Message({ ctx, payload }: {\n ctx: SignerWorkerManagerContext;\n payload: {\n message: string;\n recipient: string;\n nonce: string;\n state: string | null;\n accountId: string;\n signerMode: SignerMode;\n title?: string;\n body?: string;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n sessionId?: string;\n contractId?: string;\n nearRpcUrl?: string;\n };\n}): Promise<{\n success: boolean;\n accountId: string;\n publicKey: string;\n signature: string;\n state?: string;\n error?: string;\n}> {\n try {\n const sessionId = payload.sessionId ?? generateSessionId();\n const relayerUrl = ctx.relayerUrl;\n const nearAccountId = payload.accountId;\n\n const deviceNumber = await getLastLoggedInDeviceNumber(nearAccountId, ctx.indexedDB.clientDB);\n const [localKeyMaterial, thresholdKeyMaterial] = await Promise.all([\n ctx.indexedDB.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber),\n ctx.indexedDB.nearKeysDB.getThresholdKeyMaterial(nearAccountId, deviceNumber),\n ]);\n if (!localKeyMaterial) {\n throw new Error(`No local key material found for account: ${nearAccountId}`);\n }\n\n const resolvedSignerMode = await resolveSignerModeForThresholdSigning({\n nearAccountId,\n signerMode: payload.signerMode,\n relayerUrl,\n hasThresholdKeyMaterial: !!thresholdKeyMaterial,\n });\n\n const vrfWorkerManager = ctx.vrfWorkerManager;\n if (!vrfWorkerManager) {\n throw new Error('VrfWorkerManager not available for NEP-413 signing');\n }\n\n const signingContext = validateAndPrepareNep413SigningContext({\n nearAccountId,\n resolvedSignerMode,\n relayerUrl,\n rpId: ctx.touchIdPrompt.getRpId(),\n localKeyMaterial,\n thresholdKeyMaterial,\n });\n\n const confirmation = await vrfWorkerManager.confirmAndPrepareSigningSession({\n ctx,\n sessionId,\n kind: 'nep413',\n ...(signingContext.threshold && !signingContext.threshold.thresholdSessionJwt\n ? { signingAuthMode: 'webauthn' }\n : {}),\n nearAccountId,\n message: payload.message,\n recipient: payload.recipient,\n title: payload.title,\n body: payload.body,\n confirmationConfigOverride: payload.confirmationConfigOverride,\n contractId: payload.contractId,\n nearRpcUrl: payload.nearRpcUrl,\n });\n\n let { vrfChallenge, credential } = extractSigningEvidenceFromConfirmation(confirmation);\n\n const requestPayload = {\n signerMode: signingContext.resolvedSignerMode,\n message: payload.message,\n recipient: payload.recipient,\n nonce: payload.nonce,\n state: payload.state || undefined,\n accountId: nearAccountId,\n nearPublicKey: signingContext.nearPublicKey,\n decryption: signingContext.decryption,\n threshold: signingContext.threshold\n ? {\n relayerUrl: signingContext.threshold.relayerUrl,\n relayerKeyId: signingContext.threshold.thresholdKeyMaterial.relayerKeyId,\n clientParticipantId: signingContext.threshold.thresholdKeyMaterial.participants.find((p) => p.role === 'client')?.id,\n relayerParticipantId: signingContext.threshold.thresholdKeyMaterial.participants.find((p) => p.role === 'relayer')?.id,\n participantIds: signingContext.threshold.thresholdKeyMaterial.participants.map((p) => p.id),\n thresholdSessionKind: 'jwt' as const,\n thresholdSessionJwt: signingContext.threshold.thresholdSessionJwt,\n }\n : undefined,\n vrfChallenge,\n credential,\n };\n\n if (!signingContext.threshold) {\n const response = await ctx.sendMessage<typeof WorkerRequestType.SignNep413Message>({\n sessionId,\n message: { type: WorkerRequestType.SignNep413Message, payload: requestPayload },\n });\n const okResponse = requireOkSignNep413MessageResponse(response);\n\n return {\n success: true,\n accountId: okResponse.payload.accountId,\n publicKey: okResponse.payload.publicKey,\n signature: okResponse.payload.signature,\n state: okResponse.payload.state || undefined,\n };\n }\n\n let okResponse: WorkerSuccessResponse<typeof WorkerRequestType.SignNep413Message>;\n try {\n const response = await ctx.sendMessage<typeof WorkerRequestType.SignNep413Message>({\n sessionId,\n message: { type: WorkerRequestType.SignNep413Message, payload: requestPayload },\n });\n okResponse = requireOkSignNep413MessageResponse(response);\n } catch (e: unknown) {\n const err = e instanceof Error ? e : new Error(String(e));\n if (!isThresholdSessionAuthUnavailableError(err)) throw err;\n\n clearCachedThresholdEd25519AuthSession(signingContext.threshold.thresholdSessionCacheKey);\n signingContext.threshold.thresholdSessionJwt = undefined;\n requestPayload.threshold!.thresholdSessionJwt = undefined;\n\n if (!credential || !vrfChallenge) {\n const refreshed = await vrfWorkerManager.confirmAndPrepareSigningSession({\n ctx,\n sessionId,\n kind: 'nep413',\n signingAuthMode: 'webauthn',\n nearAccountId,\n message: payload.message,\n recipient: payload.recipient,\n title: payload.title,\n body: payload.body,\n confirmationConfigOverride: payload.confirmationConfigOverride,\n contractId: payload.contractId,\n nearRpcUrl: payload.nearRpcUrl,\n });\n\n ({ vrfChallenge, credential } = extractSigningEvidenceFromConfirmation(refreshed));\n\n requestPayload.vrfChallenge = vrfChallenge;\n requestPayload.credential = credential;\n }\n\n const response = await ctx.sendMessage<typeof WorkerRequestType.SignNep413Message>({\n sessionId,\n message: { type: WorkerRequestType.SignNep413Message, payload: requestPayload },\n });\n okResponse = requireOkSignNep413MessageResponse(response);\n }\n\n return {\n success: true,\n accountId: okResponse.payload.accountId,\n publicKey: okResponse.payload.publicKey,\n signature: okResponse.payload.signature,\n state: okResponse.payload.state || undefined,\n };\n } catch (error: unknown) {\n // eslint-disable-next-line no-console\n console.error('SignerWorkerManager: NEP-413 signing error:', error);\n return {\n success: false,\n accountId: '',\n publicKey: '',\n signature: '',\n error: (error && typeof (error as { message?: unknown }).message === 'string')\n ? (error as { message: string }).message\n : 'Unknown error'\n };\n }\n}\n\ntype ThresholdNep413SigningContext = {\n resolvedSignerMode: 'threshold-signer';\n nearPublicKey: string;\n decryption: { encryptedPrivateKeyData: string; encryptedPrivateKeyChacha20NonceB64u: string };\n threshold: {\n relayerUrl: string;\n thresholdKeyMaterial: ThresholdEd25519_2p_V1Material;\n thresholdSessionCacheKey: string;\n thresholdSessionJwt: string | undefined;\n };\n};\n\ntype LocalNep413SigningContext = {\n resolvedSignerMode: 'local-signer';\n nearPublicKey: string;\n decryption: { encryptedPrivateKeyData: string; encryptedPrivateKeyChacha20NonceB64u: string };\n threshold: null;\n};\n\ntype Nep413SigningContext = ThresholdNep413SigningContext | LocalNep413SigningContext;\n\nfunction validateAndPrepareNep413SigningContext(args: {\n nearAccountId: string;\n resolvedSignerMode: SignerMode['mode'];\n relayerUrl: string;\n rpId: string | null;\n localKeyMaterial: LocalNearSkV3Material;\n thresholdKeyMaterial: ThresholdEd25519_2p_V1Material | null;\n}): Nep413SigningContext {\n const localPublicKey = String(args.localKeyMaterial.publicKey || '').trim();\n if (!localPublicKey) {\n throw new Error(`Missing local signing public key for ${args.nearAccountId}`);\n }\n\n if (args.resolvedSignerMode !== 'threshold-signer') {\n return {\n resolvedSignerMode: 'local-signer',\n nearPublicKey: localPublicKey,\n decryption: {\n encryptedPrivateKeyData: args.localKeyMaterial.encryptedSk,\n encryptedPrivateKeyChacha20NonceB64u: args.localKeyMaterial.chacha20NonceB64u,\n },\n threshold: null,\n };\n }\n\n const thresholdKeyMaterial = args.thresholdKeyMaterial;\n if (!thresholdKeyMaterial) {\n throw new Error(`Missing threshold key material for ${args.nearAccountId}`);\n }\n\n const thresholdPublicKey = String(thresholdKeyMaterial.publicKey || '').trim();\n if (!thresholdPublicKey) {\n throw new Error(`Missing threshold signing public key for ${args.nearAccountId}`);\n }\n\n const relayerUrl = String(args.relayerUrl || '').trim();\n if (!relayerUrl) {\n throw new Error('Missing relayerUrl (required for threshold-signer)');\n }\n\n const rpId = String(args.rpId || '').trim();\n if (!rpId) {\n throw new Error('Missing rpId for threshold signing');\n }\n\n const participantIds = normalizeThresholdEd25519ParticipantIds(thresholdKeyMaterial.participants.map((p) => p.id));\n if (!participantIds || participantIds.length < 2) {\n throw new Error(\n `Invalid threshold signing participantIds (expected >=2 participants, got [${(participantIds || []).join(',')}])`\n );\n }\n\n const thresholdSessionCacheKey = makeThresholdEd25519AuthSessionCacheKey({\n nearAccountId: args.nearAccountId,\n rpId,\n relayerUrl,\n relayerKeyId: thresholdKeyMaterial.relayerKeyId,\n participantIds,\n });\n\n return {\n resolvedSignerMode: 'threshold-signer',\n nearPublicKey: thresholdPublicKey,\n decryption: {\n encryptedPrivateKeyData: '',\n encryptedPrivateKeyChacha20NonceB64u: '',\n },\n threshold: {\n relayerUrl,\n thresholdKeyMaterial,\n thresholdSessionCacheKey,\n thresholdSessionJwt: getCachedThresholdEd25519AuthSessionJwt(thresholdSessionCacheKey),\n },\n };\n}\n\nfunction extractSigningEvidenceFromConfirmation(confirmation: {\n vrfChallenge?: VRFChallenge;\n credential?: unknown;\n}): {\n vrfChallenge: VRFChallenge | undefined;\n credential: string | undefined;\n} {\n const credentialForRelay: WebAuthnAuthenticationCredential | undefined = confirmation.credential\n ? removePrfOutputGuard(confirmation.credential as WebAuthnAuthenticationCredential)\n : undefined;\n\n return {\n vrfChallenge: confirmation.vrfChallenge,\n credential: credentialForRelay ? JSON.stringify(credentialForRelay) : undefined,\n };\n}\n\nfunction requireOkSignNep413MessageResponse(\n response: Nep413SigningResponse,\n): WorkerSuccessResponse<typeof WorkerRequestType.SignNep413Message> {\n if (!isSignNep413MessageSuccess(response)) {\n if (isWorkerError(response)) {\n throw new Error(response.payload.error || 'NEP-413 signing failed');\n }\n throw new Error('NEP-413 signing failed');\n }\n return response;\n}\n","import { base64UrlDecode } from '../../../../utils';\nimport type { LocalNearSkV3Material } from '../../../IndexedDBManager/passkeyNearKeysDB';\nimport {\n WorkerRequestType,\n isRegisterDevice2WithDerivedKeySuccess,\n type WasmSignedTransaction,\n} from '../../../types/signer-worker';\nimport { AccountId, toAccountId } from \"../../../types/accountIds\";\nimport { SignerWorkerManagerContext } from '..';\nimport type { WebAuthnRegistrationCredential } from '@/core/types/webauthn';\nimport type { VRFChallenge } from '../../../types/vrf-worker';\nimport type { TransactionContext } from '../../../types/rpc';\nimport { withSessionId } from './session';\nimport { UserVerificationPolicy, toEnumUserVerificationPolicy } from '../../../types/authenticatorOptions';\n\n/**\n * Combined Device2 registration flow: derive NEAR keypair + sign registration transaction\n * in a single operation without requiring a separate authentication prompt.\n *\n * This handler orchestrates:\n * 1. Retrieving PRF.second and WrapKeySeed from session storage (delivered via MessagePort)\n * 2. Deriving NEAR ed25519 keypair from PRF.second\n * 3. Encrypting the NEAR private key with KEK (derived from WrapKeySeed + wrapKeySalt)\n * 4. Building the Device2 registration transaction (`link_device_register_user`)\n * 5. Signing the transaction with the derived NEAR keypair\n * 6. Storing encrypted key data in IndexedDB\n *\n * Security: PRF.second and WrapKeySeed never traverse the main thread - they're delivered\n * directly from VRF worker to Signer worker via MessagePort.\n */\nexport async function registerDevice2WithDerivedKey({\n ctx,\n sessionId,\n nearAccountId,\n credential,\n vrfChallenge,\n transactionContext,\n contractId,\n wrapKeySalt,\n deviceNumber,\n deterministicVrfPublicKey,\n}: {\n ctx: SignerWorkerManagerContext;\n sessionId: string;\n nearAccountId: AccountId;\n credential: WebAuthnRegistrationCredential;\n vrfChallenge: VRFChallenge;\n transactionContext: TransactionContext;\n contractId: string;\n wrapKeySalt: string;\n deviceNumber?: number;\n deterministicVrfPublicKey?: string;\n}): Promise<\n | {\n success: true;\n publicKey: string;\n signedTransaction: WasmSignedTransaction;\n wrapKeySalt: string;\n encryptedData: string;\n /**\n * Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for the encrypted private key.\n */\n chacha20NonceB64u: string;\n }\n | {\n success: false;\n publicKey: '';\n signedTransaction: null;\n wrapKeySalt: '';\n error: string;\n }\n> {\n try {\n if (!sessionId) {\n throw new Error('Missing sessionId for Device2 registration');\n }\n\n console.debug('[SignerWorkerManager] Starting Device2 combined registration', {\n nearAccountId,\n sessionId,\n deviceNumber,\n });\n\n // Helper to convert base64url string to byte array (number[])\n const b64ToBytes = (s: string | undefined): number[] => {\n if (!s) return [];\n return Array.from(base64UrlDecode(s));\n };\n const intentDigest32 = b64ToBytes(vrfChallenge.intentDigest);\n if (intentDigest32.length !== 32) {\n throw new Error('Missing or invalid vrfChallenge.intentDigest (expected base64url-encoded 32 bytes)');\n }\n // Construct contractArgs in TypeScript and use JSON.stringify() here.\n // This is native to JS, extremely fast, and means the Rust worker just receives a \"dumb\" string that it can blindly convert to bytes\n const finalContractArgs = {\n vrf_data: {\n vrf_input_data: b64ToBytes(vrfChallenge.vrfInput),\n vrf_output: b64ToBytes(vrfChallenge.vrfOutput),\n vrf_proof: b64ToBytes(vrfChallenge.vrfProof),\n public_key: b64ToBytes(vrfChallenge.vrfPublicKey),\n user_id: vrfChallenge.userId,\n rp_id: vrfChallenge.rpId,\n block_height: Number(vrfChallenge.blockHeight),\n block_hash: b64ToBytes(vrfChallenge.blockHash),\n intent_digest_32: intentDigest32,\n },\n webauthn_registration: credential,\n deterministic_vrf_public_key: b64ToBytes(deterministicVrfPublicKey),\n authenticator_options: {\n userVerification: toEnumUserVerificationPolicy(UserVerificationPolicy.Preferred),\n originPolicy: {\n single: undefined,\n all_subdomains: true,\n multiple: undefined,\n },\n },\n };\n\n // Build request payload for combined Device2 registration\n const response = await ctx.sendMessage<WorkerRequestType.RegisterDevice2WithDerivedKey>({\n sessionId,\n message: {\n type: WorkerRequestType.RegisterDevice2WithDerivedKey,\n payload: withSessionId(sessionId, {\n credential,\n nearAccountId,\n transactionContext: {\n txBlockHash: transactionContext.txBlockHash,\n txBlockHeight: transactionContext.txBlockHeight,\n baseNonce: transactionContext.nextNonce,\n },\n contractId,\n contractArgsJson: JSON.stringify(finalContractArgs),\n }),\n },\n });\n\n if (!isRegisterDevice2WithDerivedKeySuccess(response)) {\n throw new Error('Device2 combined registration failed');\n }\n\n const wasmResult = response.payload;\n\n console.debug('[SignerWorkerManager] Device2 registration complete, storing encrypted key');\n\n // Store encrypted NEAR key in IndexedDB\n const chacha20NonceB64u = wasmResult.chacha20NonceB64u;\n if (!chacha20NonceB64u) {\n throw new Error('Missing chacha20NonceB64u in Device2 registration result');\n }\n const wrapKeySaltPersisted = wasmResult.wrapKeySalt;\n if (!wrapKeySaltPersisted) {\n throw new Error('Missing wrapKeySalt in Device2 registration result');\n }\n\n const keyMaterial: LocalNearSkV3Material = {\n kind: 'local_near_sk_v3',\n nearAccountId,\n deviceNumber: deviceNumber ?? 2, // Default to device 2\n publicKey: wasmResult.publicKey,\n encryptedSk: wasmResult.encryptedData,\n chacha20NonceB64u,\n wrapKeySalt: wrapKeySaltPersisted,\n timestamp: Date.now(),\n };\n await ctx.indexedDB.nearKeysDB.storeKeyMaterial(keyMaterial);\n\n console.debug('[SignerWorkerManager] Device2 encrypted key stored successfully');\n\n return {\n success: true,\n publicKey: wasmResult.publicKey,\n signedTransaction: wasmResult.signedTransaction,\n wrapKeySalt: wrapKeySaltPersisted,\n encryptedData: wasmResult.encryptedData,\n chacha20NonceB64u,\n };\n } catch (error: unknown) {\n console.error('[SignerWorkerManager] registerDevice2WithDerivedKey error:', error);\n const message = String((error as { message?: unknown })?.message || error || '');\n return {\n success: false,\n publicKey: '',\n signedTransaction: null,\n wrapKeySalt: '',\n error: message,\n };\n }\n}\n","import type { ConfirmationConfig } from '../../../types/signer-worker';\nimport type { VrfWorkerManagerContext } from '../';\nimport type { SecureConfirmRequest } from './types';\nimport { SecureConfirmationType } from './types';\nimport { needsExplicitActivation } from '@/utils';\n\n/**\n * determineConfirmationConfig\n *\n * Computes the effective confirmation UI behavior used by the secure‑confirmation\n * flow by merging inputs and applying safe runtime rules.\n *\n * Order of precedence (highest → lowest):\n * 1) Request‑level override (request.confirmationConfig), when explicitly set.\n * 2) User preferences stored in the wallet host (from IndexedDB via ctx.userPreferencesManager).\n * 3) Runtime safety rules (wallet‑iframe registration/link flows) that may clamp behavior.\n *\n * Wallet‑iframe registration/link safety rule:\n * - When running inside the wallet-iframe host context, always clamp registration/link flows to\n * `{ uiMode: 'modal', behavior: 'requireClick' }` so the user activation happens inside the iframe.\n * This intentionally overrides both user preferences and request-level overrides.\n *\n * Notes\n * - The function is pure (does not mutate the input object) and safe to call multiple times.\n * - Theme and unrelated visual options are preserved in all cases.\n */\nexport function determineConfirmationConfig(\n ctx: VrfWorkerManagerContext,\n request: SecureConfirmRequest | undefined,\n): ConfirmationConfig {\n\n // Merge request‑level override over user preferences\n // Important: drop undefined/null fields from the override so they don't clobber\n // persisted preferences (e.g., behavior) with an undefined value.\n const configBase = ctx.userPreferencesManager.getConfirmationConfig();\n const rawOverride = (request?.confirmationConfig || {}) as Partial<ConfirmationConfig>;\n const cleanedOverride = Object.fromEntries(\n Object.entries(rawOverride).filter(([, v]) => v !== undefined && v !== null)\n ) as Partial<ConfirmationConfig>;\n let cfg: ConfirmationConfig = { ...configBase, ...cleanedOverride } as ConfirmationConfig;\n\n // Normalize theme default\n cfg = { ...cfg, theme: cfg.theme || 'dark' } as ConfirmationConfig;\n // Default decrypt-private-key confirmations to 'skip' UI. The flow collects\n // WebAuthn credentials silently and the worker may follow up with a\n // SHOW_SECURE_PRIVATE_KEY_UI request to display the key.\n if (request?.type === SecureConfirmationType.DECRYPT_PRIVATE_KEY_WITH_PRF) {\n return {\n uiMode: 'skip',\n behavior: cfg.behavior,\n autoProceedDelay: cfg.autoProceedDelay,\n theme: cfg.theme || 'dark',\n // container selection handled by uiMode only\n } as ConfirmationConfig;\n }\n // Detect if running inside an iframe (wallet host context)\n const inIframe = (() => window.self !== window.top)();\n\n // On Safari/iOS or mobile devices without a fresh user activation,\n // clamp to a clickable UI to reliably satisfy WebAuthn requirements.\n // - If caller/user set uiMode: 'skip', promote to 'modal' + requireClick\n // - If behavior is 'autoProceed', upgrade to 'requireClick'\n // Use shared heuristic to decide if explicit activation is necessary\n if (needsExplicitActivation()) {\n const newUiMode: ConfirmationConfig['uiMode'] = (cfg.uiMode === 'skip') ? 'drawer' : cfg.uiMode;\n cfg = {\n ...cfg,\n uiMode: newUiMode,\n behavior: 'requireClick',\n } as ConfirmationConfig;\n }\n\n // In wallet‑iframe host context: registration/link flows default to an explicit click.\n // However, if the effective config explicitly opts into auto‑proceed (or skip), honor it.\n if (\n inIframe &&\n request?.type &&\n (request.type === SecureConfirmationType.REGISTER_ACCOUNT || request.type === SecureConfirmationType.LINK_DEVICE)\n ) {\n // Cross‑origin registration/link flows: always require a visible, clickable confirmation\n // so the click lands inside the wallet iframe and satisfies WebAuthn activation.\n return {\n uiMode: 'modal',\n behavior: 'requireClick',\n autoProceedDelay: cfg.autoProceedDelay,\n theme: cfg.theme || 'dark',\n } as ConfirmationConfig;\n }\n\n // Otherwise honor caller/user configuration\n return cfg;\n}\n","import type { SecureConfirmRequest } from '../types';\nimport { SecureConfirmationType } from '../types';\nimport { isObject, isString } from '@/utils/validation';\n\n/**\n * Validates secure-confirm requests (V2 only).\n * This deliberately does not accept JSON strings or shorthand/legacy shapes.\n */\nexport function validateSecureConfirmRequest(input: unknown): SecureConfirmRequest {\n if (typeof input === 'string') {\n throw new Error('Invalid secure confirm request: expected an object (JSON strings are not supported)');\n }\n if (!isObject(input)) throw new Error('parsed is not an object');\n const p = input as {\n requestId?: unknown;\n type?: unknown;\n summary?: unknown;\n payload?: unknown;\n };\n if (!isString(p.requestId) || !p.requestId) throw new Error('missing requestId');\n if (!isString(p.type) || !p.type) throw new Error('missing type');\n if (p.summary === undefined || p.summary === null) throw new Error('missing summary');\n if (p.payload === undefined || p.payload === null) throw new Error('missing payload');\n return input as unknown as SecureConfirmRequest;\n}\n\nexport function assertNoForbiddenMainThreadSigningSecrets(request: SecureConfirmRequest): void {\n if (\n request.type !== SecureConfirmationType.SIGN_TRANSACTION\n && request.type !== SecureConfirmationType.SIGN_NEP413_MESSAGE\n ) {\n return;\n }\n\n const payload: any = (request as any).payload || {};\n if (payload.prfOutput !== undefined) {\n throw new Error('Invalid secure confirm request: forbidden signing payload field prfOutput');\n }\n if (payload.wrapKeySeed !== undefined) {\n throw new Error('Invalid secure confirm request: forbidden signing payload field wrapKeySeed');\n }\n if (payload.wrapKeySalt !== undefined) {\n throw new Error('Invalid secure confirm request: forbidden signing payload field wrapKeySalt');\n }\n if (payload.vrf_sk !== undefined) {\n throw new Error('Invalid secure confirm request: forbidden signing payload field vrf_sk');\n }\n}\n","import type { VrfWorkerManagerContext } from '../';\nimport type { ConfirmationConfig } from '../../../types/signer-worker';\nimport { determineConfirmationConfig } from './determineConfirmationConfig';\nimport {\n TransactionSummary,\n SecureConfirmMessageType,\n SecureConfirmRequest,\n SecureConfirmationType,\n} from './types';\nimport { errorMessage, toError } from '../../../../utils/errors';\nimport {\n parseTransactionSummary,\n getIntentDigest,\n sendConfirmResponse,\n sanitizeForPostMessage,\n} from './flows';\nimport {\n assertNoForbiddenMainThreadSigningSecrets,\n validateSecureConfirmRequest,\n} from './adapters/requestAdapter';\nimport type {\n LocalOnlySecureConfirmRequest,\n RegistrationSecureConfirmRequest,\n SigningSecureConfirmRequest,\n} from './types';\n\n/**\n * Handles secure confirmation requests from the worker with robust error handling\n * => SecureConfirmMessageType.PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD\n * and proper data validation. Supports both transaction and registration confirmation flows.\n */\nexport async function handlePromptUserConfirmInJsMainThread(\n ctx: VrfWorkerManagerContext,\n message: {\n type: SecureConfirmMessageType.PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD,\n data: SecureConfirmRequest,\n },\n worker: Worker\n): Promise<void> {\n\n // 1. Validate and parse request\n let request: SecureConfirmRequest;\n let confirmationConfig: ConfirmationConfig;\n let transactionSummary: TransactionSummary;\n\n try {\n\n request = validateSecureConfirmRequest(message.data);\n assertNoForbiddenMainThreadSigningSecrets(request);\n confirmationConfig = determineConfirmationConfig(ctx, request);\n\n const parsedSummary = parseTransactionSummary(request.summary);\n const intentDigest = getIntentDigest(request);\n\n transactionSummary = sanitizeForPostMessage({\n ...parsedSummary,\n ...(intentDigest ? { intentDigest } : {}),\n }) as TransactionSummary;\n\n } catch (e: unknown) {\n\n console.error('[SecureConfirm][Host] validateAndParseRequest failed', e);\n // Attempt to send a structured error back to the worker to avoid hard failure\n try {\n const rid = (message?.data as any)?.requestId;\n if (typeof rid === 'string' && rid) {\n sendConfirmResponse(worker, {\n requestId: rid,\n confirmed: false,\n error: errorMessage(e) || 'Invalid secure confirm request',\n });\n return;\n }\n } catch (_err: unknown) {\n throw toError(e);\n }\n throw toError(e);\n }\n\n const handler = HANDLERS[request.type];\n if (!handler) {\n // Unsupported type fallback: return structured error to worker.\n sendConfirmResponse(worker, {\n requestId: request.requestId,\n confirmed: false,\n error: 'Unsupported secure confirmation type'\n });\n return;\n }\n\n try {\n await handler({ ctx, request, worker, confirmationConfig, transactionSummary });\n } catch (e: unknown) {\n console.error('[SecureConfirm][Host] handler failed', e);\n // Best-effort: always respond to the worker so VRF-side requests don't hang indefinitely.\n sendConfirmResponse(worker, {\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: errorMessage(e) || 'Secure confirmation failed',\n });\n }\n}\n\ntype HandlerArgs = {\n ctx: VrfWorkerManagerContext;\n request: SecureConfirmRequest;\n worker: Worker;\n confirmationConfig: ConfirmationConfig;\n transactionSummary: TransactionSummary;\n};\n\ntype Handler = (args: HandlerArgs) => Promise<void>;\n\nasync function importFlow<T>(label: string, loader: () => Promise<T>): Promise<T> {\n try {\n return await loader();\n } catch (e) {\n console.error(`[SecureConfirm][Host] failed to import ${label} flow module`, e);\n throw e;\n }\n}\n\nconst HANDLERS: Partial<Record<SecureConfirmationType, Handler>> = {\n [SecureConfirmationType.DECRYPT_PRIVATE_KEY_WITH_PRF]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleLocalOnlyFlow } = await importFlow('localOnly', () => import('./flows/localOnly'));\n await handleLocalOnlyFlow(ctx, request as LocalOnlySecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.SHOW_SECURE_PRIVATE_KEY_UI]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleLocalOnlyFlow } = await importFlow('localOnly', () => import('./flows/localOnly'));\n await handleLocalOnlyFlow(ctx, request as LocalOnlySecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.REGISTER_ACCOUNT]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleRegistrationFlow } = await importFlow('registration', () => import('./flows/registration'));\n await handleRegistrationFlow(ctx, request as RegistrationSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.LINK_DEVICE]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleRegistrationFlow } = await importFlow('registration', () => import('./flows/registration'));\n await handleRegistrationFlow(ctx, request as RegistrationSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.SIGN_TRANSACTION]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleTransactionSigningFlow } = await importFlow('transactions', () => import('./flows/transactions'));\n await handleTransactionSigningFlow(ctx, request as SigningSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n [SecureConfirmationType.SIGN_NEP413_MESSAGE]: async ({ ctx, request, worker, confirmationConfig, transactionSummary }) => {\n const { handleTransactionSigningFlow } = await importFlow('transactions', () => import('./flows/transactions'));\n await handleTransactionSigningFlow(ctx, request as SigningSecureConfirmRequest, worker, { confirmationConfig, transactionSummary });\n },\n};\n","import {\n SecureConfirmMessageType,\n SecureConfirmRequest,\n SecureConfirmDecision,\n} from './confirmTxFlow/types';\nimport { handlePromptUserConfirmInJsMainThread } from './confirmTxFlow';\nimport type { VrfWorkerManagerContext } from '.';\n\n/**\n * VRF-side helper to run confirmTxFlow directly from JS without going through a worker.\n * Useful while VRF-driven flows migrate off the signer worker.\n *\n * Returns the USER_PASSKEY_CONFIRM_RESPONSE data once the flow completes.\n */\nexport async function runSecureConfirm(\n ctx: VrfWorkerManagerContext,\n request: SecureConfirmRequest\n): Promise<SecureConfirmDecision> {\n return new Promise<SecureConfirmDecision>((resolve, reject) => {\n // Minimal Worker-like object to capture the response\n const worker = {\n postMessage: (msg: any) => {\n if (msg?.type === SecureConfirmMessageType.USER_PASSKEY_CONFIRM_RESPONSE) {\n resolve(msg.data as SecureConfirmDecision);\n }\n }\n } as unknown as Worker;\n\n handlePromptUserConfirmInJsMainThread(\n ctx,\n { type: SecureConfirmMessageType.PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD, data: request },\n worker\n ).catch(reject);\n });\n}\n","import { isObject } from '@/utils/validation';\nimport { AccountId, toAccountId } from '../../../types/accountIds';\nimport {\n WorkerRequestType,\n isDecryptPrivateKeyWithPrfSuccess,\n} from '../../../types/signer-worker';\nimport { runSecureConfirm } from '../../VrfWorkerManager/secureConfirmBridge';\nimport { SecureConfirmationType } from '../../VrfWorkerManager/confirmTxFlow/types';\nimport { SignerWorkerManagerContext } from '..';\nimport { getLastLoggedInDeviceNumber } from '../getDeviceNumber';\n\n/**\n * Two-phase export (worker-driven):\n * - Phase 1: collect PRF (uiMode: 'skip') and derive WrapKeySeed in VRF worker\n * - Decrypt inside signer worker (session-bound)\n * - Phase 2: show export UI with decrypted key (kept open until user closes)\n */\nexport async function exportNearKeypairUi({\n ctx,\n nearAccountId,\n variant,\n theme,\n sessionId,\n}: {\n ctx: SignerWorkerManagerContext;\n nearAccountId: AccountId;\n variant?: 'drawer' | 'modal';\n theme?: 'dark' | 'light';\n sessionId: string;\n}): Promise<void> {\n const accountId = toAccountId(nearAccountId);\n\n // Gather encrypted key + ChaCha20 nonce and public key from IndexedDB\n const deviceNumber = await getLastLoggedInDeviceNumber(accountId, ctx.indexedDB.clientDB);\n const [keyData, user] = await Promise.all([\n ctx.indexedDB.nearKeysDB.getLocalKeyMaterial(accountId, deviceNumber),\n ctx.indexedDB.clientDB.getUserByDevice(accountId, deviceNumber),\n ]);\n const publicKey = user?.clientNearPublicKey || '';\n if (!keyData || !publicKey) {\n throw new Error('Missing local key material for export. Re-register to upgrade vault.');\n }\n\n // Decrypt inside signer worker using the reserved session\n const response = await ctx.sendMessage<WorkerRequestType.DecryptPrivateKeyWithPrf>({\n sessionId,\n message: {\n type: WorkerRequestType.DecryptPrivateKeyWithPrf,\n payload: {\n nearAccountId: accountId,\n encryptedPrivateKeyData: keyData.encryptedSk,\n encryptedPrivateKeyChacha20NonceB64u: keyData.chacha20NonceB64u,\n },\n },\n });\n\n if (!isDecryptPrivateKeyWithPrfSuccess(response)) {\n console.error('WebAuthnManager: Export decrypt failed:', response);\n const payloadError = isObject(response?.payload) && response?.payload?.error;\n const msg = String(payloadError || 'Export decrypt failed');\n throw new Error(msg);\n }\n\n const privateKey = response.payload.privateKey;\n\n // Phase 2: show secure UI (VRF-driven viewer)\n const showReq = {\n requestId: sessionId,\n type: SecureConfirmationType.SHOW_SECURE_PRIVATE_KEY_UI,\n summary: {\n operation: 'Export Private Key' as const,\n accountId,\n publicKey,\n warning: 'Anyone with your private key can fully control your account. Never share it.',\n },\n payload: {\n nearAccountId: accountId,\n publicKey,\n privateKey,\n variant,\n theme,\n },\n };\n await runSecureConfirm(ctx, showReq);\n}\n","import type { SignerWorkerManagerContext } from '..';\nimport {\n WorkerRequestType,\n WorkerResponseType,\n type WasmDeriveThresholdEd25519ClientVerifyingShareResult,\n} from '../../../types/signer-worker';\n\nexport async function deriveThresholdEd25519ClientVerifyingShare(args: {\n ctx: SignerWorkerManagerContext;\n sessionId: string;\n nearAccountId: string;\n}): Promise<{\n success: boolean;\n nearAccountId: string;\n clientVerifyingShareB64u: string;\n wrapKeySalt: string;\n error?: string;\n}> {\n const { ctx } = args;\n const sessionId = args.sessionId;\n const nearAccountId = args.nearAccountId;\n\n try {\n if (!sessionId) throw new Error('Missing sessionId');\n if (!nearAccountId) throw new Error('Missing nearAccountId');\n\n const response = await ctx.sendMessage<WorkerRequestType.DeriveThresholdEd25519ClientVerifyingShare>({\n sessionId,\n message: {\n type: WorkerRequestType.DeriveThresholdEd25519ClientVerifyingShare,\n payload: { nearAccountId },\n },\n });\n\n if (response.type !== WorkerResponseType.DeriveThresholdEd25519ClientVerifyingShareSuccess) {\n throw new Error('DeriveThresholdEd25519ClientVerifyingShare failed');\n }\n\n const wasmResult = response.payload as WasmDeriveThresholdEd25519ClientVerifyingShareResult;\n const clientVerifyingShareB64u = wasmResult?.clientVerifyingShareB64u;\n const wrapKeySalt = wasmResult?.wrapKeySalt;\n\n if (!clientVerifyingShareB64u) throw new Error('Missing clientVerifyingShareB64u in worker response');\n if (!wrapKeySalt) throw new Error('Missing wrapKeySalt in worker response');\n\n return {\n success: true,\n nearAccountId,\n clientVerifyingShareB64u,\n wrapKeySalt\n };\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return {\n success: false,\n nearAccountId,\n clientVerifyingShareB64u: '',\n wrapKeySalt: '',\n error: message\n };\n }\n}\n","import { SIGNER_WORKER_MANAGER_CONFIG } from \"../../../config\";\nimport { ClientAuthenticatorData, UnifiedIndexedDBManager } from '../../IndexedDBManager';\nimport { IndexedDBManager } from '../../IndexedDBManager';\nimport { SignedTransaction, type NearClient } from '../../NearClient';\nimport { isObject } from '@/utils/validation';\nimport { resolveWorkerUrl } from '../../sdkPaths';\nimport {\n WorkerRequestType,\n WorkerResponseForRequest,\n isWorkerProgress,\n isWorkerError,\n isWorkerSuccess,\n WorkerProgressResponse,\n WorkerErrorResponse,\n WorkerRequestTypeMap,\n} from '../../types/signer-worker';\nimport { VrfWorkerManager } from '../VrfWorkerManager';\nimport { VRFChallenge } from '../../types/vrf-worker';\nimport type { ActionArgsWasm, TransactionInputWasm } from '../../types/actions';\nimport type { DelegateActionInput } from '../../types/delegate';\nimport type { onProgressEvents, RegistrationEventStep3 } from '../../types/sdkSentEvents';\nimport type { AuthenticatorOptions } from '../../types/authenticatorOptions';\nimport { AccountId } from \"../../types/accountIds\";\nimport { TransactionContext } from '../../types/rpc';\nimport {\n ConfirmationConfig,\n type SignerMode,\n WasmSignedDelegate,\n} from '../../types/signer-worker';\nimport type { ThresholdBehavior } from '../../types/signer-worker';\nimport { TouchIdPrompt } from \"../touchIdPrompt\";\nimport { isSignerWorkerControlMessage } from './sessionMessages';\nimport { WorkerControlMessage } from '../../workerControlMessages';\n\nimport {\n decryptPrivateKeyWithPrf,\n checkCanRegisterUser,\n signTransactionsWithActions,\n recoverKeypairFromPasskey,\n extractCosePublicKey,\n signTransactionWithKeyPair,\n signNep413Message,\n deriveNearKeypairAndEncryptFromSerialized,\n signDelegateAction,\n registerDevice2WithDerivedKey,\n exportNearKeypairUi,\n deriveThresholdEd25519ClientVerifyingShare,\n} from './handlers';\nimport { RpcCallPayload } from '../../types/signer-worker';\nimport { UserPreferencesManager } from '../userPreferences';\nimport { NonceManager } from '../../nonceManager';\nimport { WebAuthnAuthenticationCredential, WebAuthnRegistrationCredential } from '../../types';\nimport { toError } from '@/utils/errors';\nimport { withSessionId } from './handlers/session';\nimport { attachSessionPort } from './sessionHandshake.js';\n\ntype WithOptionalSessionId<T> = T extends { sessionId: string }\n ? Omit<T, 'sessionId'> & { sessionId?: string }\n : T;\n\ntype SigningSessionEntry = {\n worker: Worker;\n wrapKeySeedPort?: MessagePort;\n createdAt: number;\n};\n\nexport interface SignerWorkerManagerContext {\n touchIdPrompt: TouchIdPrompt;\n nearClient: NearClient;\n indexedDB: UnifiedIndexedDBManager;\n userPreferencesManager: UserPreferencesManager;\n nonceManager: NonceManager;\n relayerUrl: string;\n rpIdOverride?: string;\n nearExplorerUrl?: string;\n vrfWorkerManager?: VrfWorkerManager;\n sendMessage: <T extends keyof WorkerRequestTypeMap>(args: {\n message: {\n type: T;\n payload: WithOptionalSessionId<WorkerRequestTypeMap[T]['request']>;\n };\n onEvent?: (update: onProgressEvents) => void;\n timeoutMs?: number;\n sessionId?: string;\n }) => Promise<WorkerResponseForRequest<T>>;\n};\n\n/**\n * WebAuthnWorkers handles PRF, workers, and COSE operations\n *\n * Note: Challenge store removed as VRF provides cryptographic freshness\n * without needing centralized challenge management\n */\nexport class SignerWorkerManager {\n\n private indexedDB: UnifiedIndexedDBManager;\n private touchIdPrompt: TouchIdPrompt;\n private vrfWorkerManager: VrfWorkerManager;\n private nearClient: NearClient;\n private userPreferencesManager: UserPreferencesManager;\n private nonceManager: NonceManager;\n private relayerUrl: string;\n private workerBaseOrigin: string | undefined;\n private nearExplorerUrl?: string;\n\n constructor(\n vrfWorkerManager: VrfWorkerManager,\n nearClient: NearClient,\n userPreferencesManager: UserPreferencesManager,\n nonceManager: NonceManager,\n relayerUrl: string,\n rpIdOverride?: string,\n enableSafariGetWebauthnRegistrationFallback: boolean = true,\n nearExplorerUrl?: string,\n ) {\n this.indexedDB = IndexedDBManager;\n this.touchIdPrompt = new TouchIdPrompt(rpIdOverride, enableSafariGetWebauthnRegistrationFallback);\n this.vrfWorkerManager = vrfWorkerManager;\n this.nearClient = nearClient;\n this.userPreferencesManager = userPreferencesManager;\n this.nonceManager = nonceManager;\n this.relayerUrl = relayerUrl;\n this.nearExplorerUrl = nearExplorerUrl;\n }\n\n setWorkerBaseOrigin(origin: string | undefined): void {\n this.workerBaseOrigin = origin;\n }\n\n getContext(): SignerWorkerManagerContext {\n return {\n sendMessage: this.sendMessage.bind(this), // bind to access this.createSecureWorker\n indexedDB: this.indexedDB,\n touchIdPrompt: this.touchIdPrompt,\n vrfWorkerManager: this.vrfWorkerManager,\n nearClient: this.nearClient,\n userPreferencesManager: this.userPreferencesManager,\n nonceManager: this.nonceManager,\n rpIdOverride: this.touchIdPrompt.getRpId(),\n nearExplorerUrl: this.nearExplorerUrl,\n relayerUrl: this.relayerUrl,\n };\n }\n\n createSecureWorker(): Worker {\n const workerUrlStr = resolveWorkerUrl(\n SIGNER_WORKER_MANAGER_CONFIG.WORKER.URL,\n { worker: 'signer', baseOrigin: this.workerBaseOrigin }\n )\n try {\n const worker = new Worker(workerUrlStr, {\n type: SIGNER_WORKER_MANAGER_CONFIG.WORKER.TYPE,\n name: SIGNER_WORKER_MANAGER_CONFIG.WORKER.NAME\n });\n // minimal error handler in tests; avoid noisy logs\n worker.onerror = () => {};\n return worker;\n } catch (error) {\n // Do not silently downgrade to same‑origin. Cross‑origin workers must be\n // resolvable under the configured wallet origin with proper headers.\n // Surface a precise error so tests assert the real path.\n const msg = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to create secure worker: ${msg}`);\n }\n }\n\n /**\n * Executes a worker operation by sending a message to the secure worker.\n * Handles progress updates via onEvent callback, supports both single and multiple response patterns.\n * Intercepts secure confirmation handshake messages for pluggable UI.\n * Resolves with the final worker response or rejects on error/timeout.\n *\n * @template T - Worker request type.\n * @param params.message - The message to send to the worker.\n * @param params.onEvent - Optional callback for progress events.\n * @param params.timeoutMs - Optional timeout in milliseconds.\n * @returns Promise resolving to the worker response for the request.\n */\n private workerPool: Worker[] = [];\n private readonly MAX_WORKER_POOL_SIZE = 3; // Increased for security model\n // Map of active signing sessions to reserved workers and optional WrapKeySeed ports\n private signingSessions: Map<string, SigningSessionEntry> = new Map();\n private readonly SIGNING_SESSION_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes\n\n private getWorkerFromPool(): Worker {\n if (this.workerPool.length > 0) {\n return this.workerPool.pop()!;\n }\n return this.createSecureWorker();\n }\n\n private terminateAndReplaceWorker(worker: Worker): void {\n // Always terminate workers to clear memory\n worker.terminate();\n // Asynchronously create a replacement worker for the pool\n this.createReplacementWorker();\n }\n\n /**\n * Reserve a signer worker \"session\"\n *\n * What this does:\n * - Reserves a specific `Worker` instance from the pool and pins it to `sessionId`.\n * - Ensures the signer worker has a dedicated `MessagePort` attached for receiving `WrapKeySeed`\n * from the VRF worker (VRF → Signer channel).\n *\n * Port wiring:\n * - The VRF worker retains one end of a `MessageChannel` and the signer worker receives the other.\n * - This method attaches the signer-facing port via a control message (`ATTACH_WRAP_KEY_SEED_PORT`)\n * and waits for an ACK (`ATTACH_WRAP_KEY_SEED_PORT_OK`) before exposing the session.\n *\n * @param sessionId - Session identifier used to correlate MessagePorts + ready signals.\n * @param opts.signerPort - Optional signer-facing `MessagePort` created/owned by the caller (VRF-created channel).\n * If omitted, this method creates a fresh `MessageChannel` and returns `vrfPort` so the\n * caller can transfer it to the VRF worker.\n * @returns `{ worker, signerPort, vrfPort }` where `vrfPort` is only present when we created the channel here.\n */\n async reserveSignerWorkerSession(sessionId: string, opts?: { signerPort?: MessagePort }): Promise<{ worker: Worker; signerPort?: MessagePort; vrfPort?: MessagePort }> {\n if (this.signingSessions.has(sessionId)) {\n throw new Error(`Signing session already exists for id: ${sessionId}`);\n }\n // Reserve a worker from the pool for this sessionId.\n const worker = this.getWorkerFromPool();\n let signerPort = opts?.signerPort;\n let vrfPort: MessagePort | undefined;\n if (!signerPort) {\n // If caller did not provide a signer-facing port, create a channel.\n // - port1 => signer worker (receiver)\n // - port2 => VRF worker (sender) returned to caller\n const channel = new MessageChannel();\n signerPort = channel.port1;\n vrfPort = channel.port2;\n }\n\n // Attach the signerPort to the worker and wait for ACK before adding to signingSessions\n try {\n if (!signerPort) {\n throw new Error('Missing signerPort for signing session');\n }\n\n // Use centralized handshake logic (registers listener, sends message, waits for ACK)\n await attachSessionPort(worker, sessionId, signerPort);\n\n // Only add to signingSessions after successful attachment\n // (prevents callers from observing a session that can't receive WrapKeySeed yet).\n this.signingSessions.set(sessionId, {\n worker,\n wrapKeySeedPort: signerPort,\n createdAt: Date.now(),\n });\n\n } catch (err) {\n console.error('[SignerWorkerManager]: Failed to attach WrapKeySeed port to signer worker', err);\n // Best-effort cleanup\n try { signerPort?.close(); } catch {}\n try { vrfPort?.close(); } catch {}\n this.terminateAndReplaceWorker(worker);\n this.signingSessions.delete(sessionId);\n throw err;\n }\n return { worker, signerPort, vrfPort };\n }\n\n /**\n * Release a signing session: close ports and terminate/replace the worker to zeroize state.\n */\n releaseSigningSession(sessionId: string): void {\n const entry = this.signingSessions.get(sessionId);\n if (!entry) return;\n try { entry.wrapKeySeedPort?.close() } catch {}\n try { this.terminateAndReplaceWorker(entry.worker) } catch {}\n this.signingSessions.delete(sessionId);\n }\n\n /**\n * Sweep expired signing sessions based on createdAt and timeout.\n */\n sweepExpiredSigningSessions(): void {\n const now = Date.now();\n for (const [sessionId, entry] of this.signingSessions.entries()) {\n if (now - entry.createdAt > this.SIGNING_SESSION_TIMEOUT_MS) {\n this.releaseSigningSession(sessionId);\n }\n }\n }\n\n private async createReplacementWorker(): Promise<void> {\n try {\n const worker = this.createSecureWorker();\n\n // Simple health check\n const healthPromise = new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => reject(new Error('Health check timeout')), 5000);\n\n const onMessage = (event: MessageEvent) => {\n if (event.data?.type === WorkerControlMessage.WORKER_READY || event.data?.ready) {\n worker.removeEventListener('message', onMessage);\n clearTimeout(timeout);\n resolve();\n }\n };\n\n worker.addEventListener('message', onMessage);\n worker.onerror = () => {\n worker.removeEventListener('message', onMessage);\n clearTimeout(timeout);\n reject(new Error('Worker error during health check'));\n };\n });\n\n await healthPromise;\n\n if (this.workerPool.length < this.MAX_WORKER_POOL_SIZE) {\n this.workerPool.push(worker);\n } else {\n worker.terminate();\n }\n } catch (error: unknown) {\n console.warn('SignerWorkerManager: Failed to create replacement worker:', error);\n }\n }\n\n /**\n * Pre-warm worker pool by creating and initializing workers in advance\n * This reduces latency for the first transaction by having workers ready\n */\n async preWarmWorkerPool(): Promise<void> {\n const promises: Promise<void>[] = [];\n\n for (let i = 0; i < this.MAX_WORKER_POOL_SIZE; i++) {\n promises.push(\n new Promise<void>((resolve, reject) => {\n try {\n const worker = this.createSecureWorker();\n\n // Set up one-time ready handler\n const onReady = (event: MessageEvent) => {\n if (event.data?.type === WorkerControlMessage.WORKER_READY || event.data?.ready) {\n worker.removeEventListener('message', onReady);\n this.terminateAndReplaceWorker(worker);\n resolve();\n }\n };\n\n worker.addEventListener('message', onReady);\n\n // Set up error handler\n worker.onerror = (error) => {\n worker.removeEventListener('message', onReady);\n console.error(`WebAuthnManager: Worker ${i + 1} pre-warm failed:`, error);\n reject(error);\n };\n\n // Timeout after 5 seconds\n setTimeout(() => {\n worker.removeEventListener('message', onReady);\n // Pre-warm timeouts are benign; workers will be created on-demand later.\n // console.debug(`WebAuthnManager: Worker ${i + 1} pre-warm timeout`);\n reject(new Error('Pre-warm timeout'));\n }, 5000);\n\n } catch (error: unknown) {\n console.error(`WebAuthnManager: Failed to create worker ${i + 1}:`, error);\n reject(toError(error));\n }\n })\n );\n }\n\n try {\n await Promise.allSettled(promises);\n } catch (error: unknown) {\n console.warn('WebAuthnManager: Some workers failed to pre-warm:', error);\n }\n }\n\n private async sendMessage<T extends keyof WorkerRequestTypeMap>({\n sessionId,\n message,\n onEvent,\n timeoutMs = SIGNER_WORKER_MANAGER_CONFIG.TIMEOUTS.DEFAULT, // 60s\n }: {\n sessionId?: string;\n message: { type: T; payload: WithOptionalSessionId<WorkerRequestTypeMap[T]['request']> };\n onEvent?: (update: onProgressEvents) => void;\n timeoutMs?: number;\n }): Promise<WorkerResponseForRequest<T>> {\n\n // Clean up any expired signing sessions before allocating a worker\n this.sweepExpiredSigningSessions();\n\n const payloadSessionId = (message.payload as any)?.sessionId as string | undefined;\n if (sessionId && payloadSessionId && payloadSessionId !== sessionId) {\n throw new Error(\n `sendMessage: payload.sessionId (${payloadSessionId}) does not match provided sessionId (${sessionId})`\n );\n }\n\n const effectiveSessionId = sessionId || payloadSessionId;\n const sessionEntry = effectiveSessionId ? this.signingSessions.get(effectiveSessionId) : undefined;\n if (effectiveSessionId && !sessionEntry) {\n throw new Error(`Signing session not found for id: ${effectiveSessionId}`);\n }\n\n // Normalize/inject sessionId into payload once to avoid duplication at call sites.\n const finalPayload = effectiveSessionId\n ? withSessionId(effectiveSessionId, message.payload)\n : (message.payload);\n\n const worker = sessionEntry ? sessionEntry.worker : this.getWorkerFromPool();\n const isSessionWorker = !!sessionEntry;\n\n return new Promise((resolve, reject) => {\n const timeoutId = setTimeout(() => {\n try {\n if (isSessionWorker && effectiveSessionId) {\n // Release reserved session to avoid leaking worker/port\n this.releaseSigningSession(effectiveSessionId);\n } else {\n this.terminateAndReplaceWorker(worker);\n }\n } catch {}\n // Notify any open modal host to transition to error state\n try {\n const seconds = Math.round(timeoutMs / 1000);\n window.postMessage({ type: 'MODAL_TIMEOUT', payload: `Timed out after ${seconds}s, try again` }, '*');\n } catch {}\n reject(new Error(`Worker operation timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n\n const responses: WorkerResponseForRequest<T>[] = [];\n\n worker.onmessage = async (event) => {\n try {\n // Ignore control messages (lifecycle/session setup) – they are handled elsewhere.\n if (isSignerWorkerControlMessage(event?.data)) {\n return;\n }\n // Ignore readiness pings that can arrive if a worker was just spawned\n if (event?.data?.type === WorkerControlMessage.WORKER_READY || event?.data?.ready) {\n return; // not a response to an operation\n }\n // Use strong typing from WASM-generated types\n const response = event.data as WorkerResponseForRequest<T>;\n responses.push(response);\n\n // Handle progress updates using WASM-generated numeric enum values\n if (isWorkerProgress(response)) {\n const progressResponse = response as WorkerProgressResponse;\n onEvent?.(progressResponse.payload as onProgressEvents);\n return; // Continue listening for more messages\n }\n\n // Handle errors using WASM-generated enum\n if (isWorkerError(response)) {\n clearTimeout(timeoutId);\n if (!isSessionWorker) this.terminateAndReplaceWorker(worker);\n const errorResponse = response as WorkerErrorResponse;\n console.error('Worker error response:', errorResponse);\n reject(new Error(errorResponse.payload.error));\n return;\n }\n\n // Handle successful completion types using strong typing\n if (isWorkerSuccess(response)) {\n clearTimeout(timeoutId);\n if (!isSessionWorker) this.terminateAndReplaceWorker(worker);\n resolve(response as WorkerResponseForRequest<T>);\n return;\n }\n\n // If we reach here, the response doesn't match any expected type\n console.error('Unexpected worker response format:', {\n response,\n });\n\n // Check if it's a generic Error object\n if (isObject(response) && 'message' in response && 'stack' in response) {\n clearTimeout(timeoutId);\n if (!isSessionWorker) this.terminateAndReplaceWorker(worker);\n console.error('Worker sent generic Error object:', response);\n reject(new Error(`Worker sent generic error: ${(response as Error).message}`));\n return;\n }\n\n // Unknown response format\n clearTimeout(timeoutId);\n if (!isSessionWorker) this.terminateAndReplaceWorker(worker);\n reject(new Error(`Unknown worker response format: ${JSON.stringify(response)}`));\n } catch (error: unknown) {\n clearTimeout(timeoutId);\n if (!isSessionWorker) this.terminateAndReplaceWorker(worker);\n console.error('Error processing worker message:', error);\n const err = toError(error);\n reject(new Error(`Worker message processing error: ${err.message}`));\n }\n };\n\n worker.onerror = (event) => {\n clearTimeout(timeoutId);\n if (!isSessionWorker) this.terminateAndReplaceWorker(worker);\n const errorMessage = event.error?.message || event.message || 'Unknown worker error';\n console.error('Worker error details (progress):', {\n message: errorMessage,\n filename: event.filename,\n lineno: event.lineno,\n colno: event.colno,\n error: event.error\n });\n reject(new Error(`Worker error: ${errorMessage}`));\n };\n\n // Format message for Rust SignerWorkerMessage structure using WASM types\n const formattedMessage = {\n type: message.type, // Numeric enum value from WorkerRequestType\n payload: finalPayload,\n };\n\n worker.postMessage(formattedMessage);\n });\n }\n\n /**\n * Derive NEAR keypair from a serialized WebAuthn registration credential\n */\n async deriveNearKeypairAndEncryptFromSerialized(args: {\n credential: WebAuthnRegistrationCredential;\n nearAccountId: AccountId;\n options?: {\n authenticatorOptions?: AuthenticatorOptions;\n deviceNumber?: number;\n };\n sessionId: string;\n }): Promise<{\n success: boolean;\n nearAccountId: AccountId;\n publicKey: string;\n /**\n * Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for the encrypted private key.\n */\n chacha20NonceB64u?: string;\n wrapKeySalt?: string;\n }> {\n return deriveNearKeypairAndEncryptFromSerialized({ ctx: this.getContext(), ...args });\n }\n\n async deriveThresholdEd25519ClientVerifyingShare(args: {\n sessionId: string;\n nearAccountId: AccountId;\n }): Promise<{\n success: boolean;\n nearAccountId: string;\n clientVerifyingShareB64u: string;\n wrapKeySalt: string;\n error?: string;\n }> {\n return deriveThresholdEd25519ClientVerifyingShare({\n ctx: this.getContext(),\n sessionId: args.sessionId,\n nearAccountId: String(args.nearAccountId),\n });\n }\n\n /**\n * Secure private key decryption with dual PRF\n */\n async decryptPrivateKeyWithPrf(args: {\n nearAccountId: AccountId,\n authenticators: ClientAuthenticatorData[],\n sessionId: string,\n }): Promise<{\n decryptedPrivateKey: string;\n nearAccountId: AccountId\n }> {\n return decryptPrivateKeyWithPrf({ ctx: this.getContext(), ...args });\n }\n\n async checkCanRegisterUser(args: {\n vrfChallenge: VRFChallenge,\n credential: WebAuthnRegistrationCredential,\n contractId: string;\n nearRpcUrl: string;\n authenticatorOptions?: AuthenticatorOptions; // Authenticator options for registration check\n onEvent?: (update: RegistrationEventStep3) => void;\n }): Promise<{\n success: boolean;\n verified?: boolean;\n registrationInfo?: unknown;\n logs?: string[];\n signedTransactionBorsh?: number[];\n error?: string;\n }> {\n return checkCanRegisterUser({ ctx: this.getContext(), ...args });\n }\n\n /**\n * Combined Device2 registration: derive NEAR keypair + sign registration transaction\n * in a single operation without requiring a separate authentication prompt.\n *\n * This replaces the old two-step flow (register → authenticate → sign).\n * PRF.second and WrapKeySeed are already in the signer worker via MessagePort.\n */\n async registerDevice2WithDerivedKey(args: {\n sessionId: string;\n nearAccountId: AccountId;\n credential: WebAuthnRegistrationCredential;\n vrfChallenge: VRFChallenge;\n transactionContext: TransactionContext;\n contractId: string;\n wrapKeySalt: string;\n deviceNumber?: number;\n deterministicVrfPublicKey: string;\n }): Promise<{\n success: boolean;\n publicKey: string;\n signedTransaction: any;\n wrapKeySalt: string;\n encryptedData?: string;\n /**\n * Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for the encrypted private key.\n */\n chacha20NonceB64u?: string;\n error?: string;\n }> {\n return registerDevice2WithDerivedKey({ ctx: this.getContext(), ...args });\n }\n\n // === ACTION-BASED SIGNING METHODS ===\n\n /**\n * Sign multiple transactions with shared VRF challenge and credential\n * Efficiently processes multiple transactions with one PRF authentication\n */\n async signTransactionsWithActions(args: {\n transactions: TransactionInputWasm[],\n rpcCall: RpcCallPayload,\n signerMode: SignerMode,\n onEvent?: (update: onProgressEvents) => void,\n confirmationConfigOverride?: Partial<ConfirmationConfig>,\n title?: string;\n body?: string;\n sessionId: string,\n }): Promise<Array<{\n signedTransaction: SignedTransaction;\n nearAccountId: AccountId;\n logs?: string[]\n }>> {\n return signTransactionsWithActions({\n ctx: this.getContext(),\n ...args\n });\n }\n\n async signDelegateAction(args: {\n delegate: DelegateActionInput;\n rpcCall: RpcCallPayload;\n signerMode: SignerMode;\n onEvent?: (update: onProgressEvents) => void;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n title?: string;\n body?: string;\n sessionId: string;\n }): Promise<{\n signedDelegate: WasmSignedDelegate;\n hash: string;\n nearAccountId: AccountId;\n logs?: string[];\n }> {\n return signDelegateAction({ ctx: this.getContext(), ...args });\n }\n\n /**\n * Recover keypair from authentication credential for account recovery\n * Uses dual PRF-based Ed25519 key derivation with account-specific HKDF and AES encryption\n */\n async recoverKeypairFromPasskey(args: {\n credential: WebAuthnAuthenticationCredential;\n accountIdHint?: string;\n sessionId: string,\n }): Promise<{\n publicKey: string;\n encryptedPrivateKey: string;\n /** Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for encrypted key */\n chacha20NonceB64u: string;\n accountIdHint?: string;\n wrapKeySalt: string;\n }> {\n return recoverKeypairFromPasskey({ ctx: this.getContext(), ...args });\n }\n\n /**\n * Extract COSE public key from WebAuthn attestation object\n * Simple operation that doesn't require TouchID or progress updates\n */\n async extractCosePublicKey(attestationObjectBase64url: string): Promise<Uint8Array> {\n return extractCosePublicKey({ ctx: this.getContext(), attestationObjectBase64url });\n }\n\n /**\n * Sign transaction with raw private key (for key replacement in Option D device linking)\n * No TouchID/PRF required - uses provided private key directly\n */\n async signTransactionWithKeyPair(args: {\n nearPrivateKey: string;\n signerAccountId: string;\n receiverId: string;\n nonce: string;\n blockHash: string;\n actions: ActionArgsWasm[];\n }): Promise<{\n signedTransaction: SignedTransaction;\n logs?: string[];\n }> {\n return signTransactionWithKeyPair({ ctx: this.getContext(), ...args });\n }\n\n /**\n * Sign a NEP-413 message using the user's passkey-derived private key\n *\n * @param payload - NEP-413 signing parameters including message, recipient, nonce, and state\n * @returns Promise resolving to signing result with account ID, public key, and signature\n */\n async signNep413Message(payload: {\n message: string;\n recipient: string;\n nonce: string;\n state: string | null;\n accountId: string;\n signerMode: SignerMode;\n title?: string;\n body?: string;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n sessionId: string;\n contractId?: string;\n nearRpcUrl?: string;\n }): Promise<{\n success: boolean;\n accountId: string;\n publicKey: string;\n signature: string;\n state?: string;\n error?: string;\n }> {\n return signNep413Message({\n ctx: this.getContext(),\n payload\n });\n }\n\n /**\n * Two-phase export (worker-driven):\n * - Phase 1: collect PRF (uiMode: 'skip')\n * - Decrypt inside worker\n * - Phase 2: show export UI with decrypted key (kept open until user closes)\n */\n async exportNearKeypairUi(args: {\n nearAccountId: AccountId,\n variant?: 'drawer'|'modal',\n theme?: 'dark'|'light',\n sessionId: string,\n }): Promise<void> {\n return exportNearKeypairUi({ ctx: this.getContext(), ...args });\n }\n\n}\n","import type { VRFWorkerMessage, VRFWorkerStatus, WasmVrfWorkerRequestType } from '../../../types/vrf-worker';\nimport { toAccountId } from '../../../types/accountIds';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * \"Global\" VRF status: is the VRF keypair currently unlocked/active inside the VRF worker?\n *\n * This is NOT the same as a signing session status (WrapKeySeed session gating).\n * For per-`sessionId` signing-session status, use `checkSessionStatus`.\n */\nexport async function checkVrfStatus(ctx: VrfWorkerManagerHandlerContext): Promise<VRFWorkerStatus> {\n try {\n await ctx.ensureWorkerReady();\n } catch {\n // If initialization fails, return inactive status\n return { active: false, nearAccountId: null, vrfPublicKey: null };\n }\n\n try {\n const message: VRFWorkerMessage<WasmVrfWorkerRequestType> = {\n type: 'CHECK_VRF_STATUS',\n id: ctx.generateMessageId(),\n payload: {} as WasmVrfWorkerRequestType\n };\n\n const response = await ctx.sendMessage(message);\n\n if (response.success && response.data) {\n const data = response.data as { active: boolean; sessionDuration?: number; vrfPublicKey?: string };\n const current = ctx.getCurrentVrfAccountId();\n return {\n active: data.active,\n nearAccountId: current ? toAccountId(current) : null,\n sessionDuration: data.sessionDuration,\n vrfPublicKey: data.vrfPublicKey ?? null,\n };\n }\n\n return { active: false, nearAccountId: null, vrfPublicKey: null };\n } catch (error) {\n console.warn('VRF Manager: Failed to get VRF status:', error);\n return { active: false, nearAccountId: null, vrfPublicKey: null };\n }\n}\n","import type { VRFWorkerMessage, WasmClearSessionRequest } from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Best-effort cleanup for a single VRF-owned signing session.\n *\n * Clears any VRF worker state bound to `sessionId`:\n * - cached WrapKeySeed session material (TTL/uses),\n * - cached VRF challenge (used for contract verification),\n * - and any attached WrapKeySeed MessagePort.\n *\n * Used by UI \"Lock\" actions and as a safety valve for session lifecycle cleanup.\n */\nexport async function clearSession(\n ctx: VrfWorkerManagerHandlerContext,\n args: { sessionId: string }\n): Promise<{\n sessionId: string;\n clearedSession: boolean;\n clearedChallenge: boolean;\n clearedPort: boolean;\n}> {\n await ctx.ensureWorkerReady(true);\n const message: VRFWorkerMessage<WasmClearSessionRequest> = {\n type: 'CLEAR_SESSION',\n id: ctx.generateMessageId(),\n payload: {\n sessionId: args.sessionId,\n } as any,\n };\n const response = await ctx.sendMessage<WasmClearSessionRequest>(message);\n if (!response.success) {\n throw new Error(`clearSession failed: ${response.error}`);\n }\n return (response.data as any) || {\n sessionId: args.sessionId,\n clearedSession: false,\n clearedChallenge: false,\n clearedPort: false,\n };\n}\n","import type { VRFWorkerMessage, WasmVrfWorkerRequestType } from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Full VRF logout: zeroize the in-memory VRF keypair and clear all VRF worker caches.\n *\n * This differs from `clearSession`, which only clears a single signing session (`sessionId`).\n * Use this when the user explicitly logs out / locks the VRF keypair.\n */\nexport async function clearVrfSession(ctx: VrfWorkerManagerHandlerContext): Promise<void> {\n console.debug('VRF Manager: Clearing VRF session...');\n\n await ctx.ensureWorkerReady();\n\n try {\n const message: VRFWorkerMessage<WasmVrfWorkerRequestType> = {\n type: 'CLEAR_VRF',\n id: ctx.generateMessageId(),\n payload: {} as WasmVrfWorkerRequestType\n };\n\n const response = await ctx.sendMessage(message);\n\n if (response.success) {\n // Clear the TypeScript-tracked account ID\n ctx.setCurrentVrfAccountId(null);\n console.debug('VRF Manager: VRF session cleared (key material zeroized)');\n } else {\n console.warn('️VRF Manager: Clear VRF failed:', response.error);\n }\n } catch (error) {\n console.warn('VRF Manager: Clear VRF error:', error);\n }\n}\n","import type { AccountId } from '../../../types/accountIds';\nimport type { EncryptedVRFKeypair, VRFWorkerMessage, WasmDevice2RegistrationSessionRequest } from '../../../types/vrf-worker';\nimport type { TransactionContext } from '../../../types/rpc';\nimport type { VRFChallenge } from '../../../types/vrf-worker';\nimport type { WebAuthnRegistrationCredential } from '../../../types/webauthn';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Kick off the SecureConfirm flow for Device2 registration (\"link device\") and return the confirmed result.\n *\n * This is a bundled orchestration that can:\n * - collect a registration credential (PRF-capable),\n * - derive a deterministic VRF keypair for the new device,\n * - and return the data needed for storage + subsequent signing steps (tx context, VRF challenge, etc.).\n */\nexport async function confirmAndDeriveDevice2RegistrationSession(\n ctx: VrfWorkerManagerHandlerContext,\n params: {\n sessionId: string;\n nearAccountId: AccountId;\n deviceNumber: number;\n contractId: string;\n nearRpcUrl: string;\n authenticatorOptions?: object;\n wrapKeySalt?: string;\n }\n): Promise<{\n confirmed: boolean;\n sessionId: string;\n credential: WebAuthnRegistrationCredential;\n vrfChallenge: VRFChallenge;\n transactionContext: TransactionContext;\n wrapKeySalt: string;\n requestId: string;\n intentDigest: string;\n deterministicVrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n error?: string;\n}> {\n await ctx.ensureWorkerReady(true);\n\n const message: VRFWorkerMessage<WasmDevice2RegistrationSessionRequest> = {\n type: 'DEVICE2_REGISTRATION_SESSION',\n id: ctx.generateMessageId(),\n payload: {\n sessionId: params.sessionId,\n nearAccountId: params.nearAccountId,\n deviceNumber: params.deviceNumber,\n contractId: params.contractId,\n nearRpcUrl: params.nearRpcUrl,\n wrapKeySalt: params.wrapKeySalt || '',\n // No confirmationConfig override for now; can add later if needed\n }\n };\n\n const response = await ctx.sendMessage<WasmDevice2RegistrationSessionRequest>(message);\n\n if (!response.success) {\n throw new Error(`Device2 registration session failed: ${response.error}`);\n }\n\n const data = response.data as any;\n\n if (!data.confirmed) {\n throw new Error(data.error || 'User rejected Device2 registration');\n }\n\n if (!data.credential) {\n throw new Error('Missing credential from Device2 registration session');\n }\n if (!data.vrfChallenge) {\n throw new Error('Missing vrfChallenge from Device2 registration session');\n }\n if (!data.transactionContext) {\n throw new Error('Missing transactionContext from Device2 registration session');\n }\n if (!data.wrapKeySalt) {\n throw new Error('Missing wrapKeySalt from Device2 registration session');\n }\n\n return {\n confirmed: true,\n sessionId: data.sessionId,\n credential: data.credential,\n vrfChallenge: data.vrfChallenge,\n transactionContext: data.transactionContext,\n wrapKeySalt: data.wrapKeySalt,\n requestId: data.requestId,\n intentDigest: data.intentDigest,\n deterministicVrfPublicKey: data.deterministicVrfPublicKey,\n encryptedVrfKeypair: data.encryptedVrfKeypair,\n };\n}\n","import type { TransactionInputWasm } from '../../../types/actions';\nimport { ActionType } from '../../../types/actions';\nimport type { RpcCallPayload, ConfirmationConfig } from '../../../types/signer-worker';\nimport type { TransactionContext } from '../../../types/rpc';\nimport { computeUiIntentDigestFromTxs, orderActionForDigest } from '../../../digests/intentDigest';\nimport {\n SecureConfirmationType,\n type SecureConfirmRequest,\n type SignTransactionPayload,\n type SigningAuthMode,\n type TransactionSummary,\n type SerializableCredential,\n} from '../confirmTxFlow/types';\nimport type { SignNep413Payload } from '../confirmTxFlow/types';\nimport type { VrfWorkerManagerContext } from '..';\nimport type { VrfWorkerManagerHandlerContext } from './types';\nimport type { VRFChallenge, VRFWorkerMessage, WasmConfirmAndPrepareSigningSessionRequest } from '../../../types/vrf-worker';\n\nexport interface ConfirmAndPrepareSigningSessionBaseParams {\n ctx: VrfWorkerManagerContext;\n sessionId: string;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n /**\n * Optional override for signing auth mode.\n * When omitted, the VRF worker may auto-select `warmSession` when a session is available.\n *\n * Threshold signing should force `webauthn` to ensure a fresh VRF challenge + WebAuthn assertion\n * is available for relayer authorization.\n */\n signingAuthMode?: SigningAuthMode;\n /**\n * Optional base64url-encoded 32-byte digest to bind a relayer session policy into the VRF input hash (v4+ only).\n * When provided, it is forwarded to the VRF worker for inclusion in VRF input derivation.\n */\n sessionPolicyDigest32?: string;\n}\n\nexport interface ConfirmAndPrepareSigningSessionTransactionParams extends ConfirmAndPrepareSigningSessionBaseParams {\n kind: 'transaction';\n txSigningRequests: TransactionInputWasm[];\n rpcCall: RpcCallPayload;\n title?: string;\n body?: string;\n}\n\nexport interface ConfirmAndPrepareSigningSessionDelegateParams extends ConfirmAndPrepareSigningSessionBaseParams {\n kind: 'delegate';\n nearAccountId: string;\n title?: string;\n body?: string;\n delegate: {\n senderId: string;\n receiverId: string;\n actions: TransactionInputWasm['actions'];\n nonce: string | number | bigint;\n maxBlockHeight: string | number | bigint;\n };\n rpcCall: RpcCallPayload;\n}\n\nexport interface ConfirmAndPrepareSigningSessionNep413Params extends ConfirmAndPrepareSigningSessionBaseParams {\n kind: 'nep413';\n nearAccountId: string;\n message: string;\n recipient: string;\n title?: string;\n body?: string;\n contractId?: string;\n nearRpcUrl?: string;\n}\n\nexport type ConfirmAndPrepareSigningSessionParams =\n | ConfirmAndPrepareSigningSessionTransactionParams\n | ConfirmAndPrepareSigningSessionDelegateParams\n | ConfirmAndPrepareSigningSessionNep413Params;\n\nexport interface ConfirmAndPrepareSigningSessionResult {\n sessionId: string;\n transactionContext: TransactionContext;\n intentDigest: string;\n credential?: SerializableCredential;\n vrfChallenge?: VRFChallenge;\n}\n\n/**\n * Kick off the SecureConfirm signing flow inside the VRF worker.\n *\n * This creates a `SecureConfirmRequest` (tx / delegate / NEP-413) and sends it to the\n * VRF worker, which will render UI, collect a WebAuthn credential when needed, and return the\n * `transactionContext` (reserved nonces, block hash/height) needed by the signer worker.\n */\nexport async function confirmAndPrepareSigningSession(\n handlerCtx: VrfWorkerManagerHandlerContext,\n params: ConfirmAndPrepareSigningSessionParams\n): Promise<ConfirmAndPrepareSigningSessionResult> {\n const { sessionId } = params;\n\n let intentDigest: string;\n let request: SecureConfirmRequest<SignTransactionPayload | SignNep413Payload, TransactionSummary>;\n\n switch (params.kind) {\n case 'transaction': {\n const txSigningRequests = params.txSigningRequests;\n intentDigest = await computeUiIntentDigestFromTxs(\n txSigningRequests.map(tx => ({\n receiverId: tx.receiverId,\n actions: tx.actions.map(orderActionForDigest),\n })) as TransactionInputWasm[]\n );\n\n const summary: TransactionSummary = {\n intentDigest,\n receiverId: txSigningRequests[0]?.receiverId,\n totalAmount: computeTotalAmountYocto(txSigningRequests),\n type: 'transaction',\n ...(params.title != null ? { title: params.title } : {}),\n ...(params.body != null ? { body: params.body } : {}),\n };\n\n request = {\n requestId: sessionId,\n type: SecureConfirmationType.SIGN_TRANSACTION,\n summary,\n payload: {\n txSigningRequests,\n intentDigest,\n rpcCall: params.rpcCall,\n ...(params.sessionPolicyDigest32 ? { sessionPolicyDigest32: params.sessionPolicyDigest32 } : {}),\n ...(params.signingAuthMode ? { signingAuthMode: params.signingAuthMode } : {}),\n },\n confirmationConfig: params.confirmationConfigOverride,\n intentDigest,\n };\n break;\n }\n case 'delegate': {\n const txSigningRequests: TransactionInputWasm[] = [{\n receiverId: params.delegate.receiverId,\n actions: params.delegate.actions,\n }];\n\n intentDigest = await computeUiIntentDigestFromTxs(\n txSigningRequests.map(tx => ({\n receiverId: tx.receiverId,\n actions: tx.actions.map(orderActionForDigest),\n }))\n );\n\n const summary: TransactionSummary = {\n intentDigest,\n receiverId: txSigningRequests[0]?.receiverId,\n totalAmount: computeTotalAmountYocto(txSigningRequests),\n type: 'delegateAction',\n ...(params.title != null ? { title: params.title } : {}),\n ...(params.body != null ? { body: params.body } : {}),\n delegate: {\n senderId: params.delegate.senderId,\n receiverId: params.delegate.receiverId,\n nonce: String(params.delegate.nonce),\n maxBlockHeight: String(params.delegate.maxBlockHeight),\n },\n };\n\n request = {\n requestId: sessionId,\n type: SecureConfirmationType.SIGN_TRANSACTION,\n summary,\n payload: {\n txSigningRequests,\n intentDigest,\n rpcCall: params.rpcCall,\n ...(params.sessionPolicyDigest32 ? { sessionPolicyDigest32: params.sessionPolicyDigest32 } : {}),\n ...(params.signingAuthMode ? { signingAuthMode: params.signingAuthMode } : {}),\n },\n confirmationConfig: params.confirmationConfigOverride,\n intentDigest,\n };\n break;\n }\n case 'nep413': {\n intentDigest = `${params.nearAccountId}:${params.recipient}:${params.message}`;\n const summary: TransactionSummary = {\n intentDigest,\n method: 'NEP-413',\n receiverId: params.recipient,\n ...(params.title != null ? { title: params.title } : {}),\n ...(params.body != null ? { body: params.body } : {}),\n };\n\n request = {\n requestId: sessionId,\n type: SecureConfirmationType.SIGN_NEP413_MESSAGE,\n summary,\n payload: {\n nearAccountId: params.nearAccountId,\n message: params.message,\n recipient: params.recipient,\n ...(params.sessionPolicyDigest32 ? { sessionPolicyDigest32: params.sessionPolicyDigest32 } : {}),\n ...(params.contractId ? { contractId: params.contractId } : {}),\n ...(params.nearRpcUrl ? { nearRpcUrl: params.nearRpcUrl } : {}),\n ...(params.signingAuthMode ? { signingAuthMode: params.signingAuthMode } : {}),\n },\n confirmationConfig: params.confirmationConfigOverride,\n intentDigest,\n };\n break;\n }\n default: {\n // Exhaustiveness guard\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const _exhaustive: never = params;\n throw new Error('Unsupported signing session kind');\n }\n }\n\n await handlerCtx.ensureWorkerReady(true);\n const message: VRFWorkerMessage<WasmConfirmAndPrepareSigningSessionRequest> = {\n type: 'CONFIRM_AND_PREPARE_SIGNING_SESSION',\n id: handlerCtx.generateMessageId(),\n payload: {\n request,\n },\n };\n const response = await handlerCtx.sendMessage<WasmConfirmAndPrepareSigningSessionRequest>(message);\n if (!response.success) {\n throw new Error(`confirmAndPrepareSigningSession failed: ${response.error}`);\n }\n\n const decision = response.data as {\n confirmed?: boolean;\n error?: string;\n intent_digest?: string;\n transaction_context?: TransactionContext;\n credential?: SerializableCredential;\n vrf_challenge?: VRFChallenge;\n };\n\n if (!decision?.confirmed) {\n throw new Error(decision?.error || 'User rejected signing request');\n }\n if (!decision.transaction_context) {\n throw new Error('Missing transactionContext from confirmation flow');\n }\n\n return {\n sessionId,\n transactionContext: decision.transaction_context,\n intentDigest: decision.intent_digest || intentDigest,\n credential: decision.credential,\n vrfChallenge: decision.vrf_challenge,\n };\n}\n\nfunction computeTotalAmountYocto(txSigningRequests: TransactionInputWasm[]): string | undefined {\n try {\n let total = BigInt(0);\n for (const tx of txSigningRequests) {\n for (const action of tx.actions) {\n switch (action.action_type) {\n case ActionType.Transfer:\n total += BigInt(action.deposit || '0');\n break;\n case ActionType.FunctionCall:\n total += BigInt(action.deposit || '0');\n break;\n case ActionType.Stake:\n total += BigInt(action.stake || '0');\n break;\n default:\n break;\n }\n }\n }\n return total > BigInt(0) ? total.toString() : undefined;\n } catch {\n return undefined;\n }\n}\n","import type { AccountId } from '../../../types/accountIds';\nimport type {\n EncryptedVRFKeypair,\n ServerEncryptedVrfKeypair,\n VRFInputData,\n VRFWorkerMessage,\n WasmDeriveVrfKeypairFromPrfRequest,\n} from '../../../types/vrf-worker';\nimport { validateVRFChallenge, type VRFChallenge } from '../../../types/vrf-worker';\nimport type { WebAuthnAuthenticationCredential, WebAuthnRegistrationCredential } from '../../../types/webauthn';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Derive deterministic VRF keypair from PRF output embedded in a WebAuthn credential.\n */\nexport async function deriveVrfKeypairFromPrf(\n ctx: VrfWorkerManagerHandlerContext,\n args: {\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n nearAccountId: AccountId;\n vrfInputData?: VRFInputData;\n saveInMemory?: boolean;\n }\n): Promise<{\n vrfPublicKey: string;\n vrfChallenge: VRFChallenge | null;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n serverEncryptedVrfKeypair: ServerEncryptedVrfKeypair | null;\n}> {\n const saveInMemory = args.saveInMemory ?? true;\n await ctx.ensureWorkerReady();\n\n const vrfInputData = args.vrfInputData;\n const hasVrfInputData = vrfInputData?.blockHash\n && vrfInputData?.blockHeight\n && vrfInputData?.userId\n && vrfInputData?.rpId;\n\n const message: VRFWorkerMessage<WasmDeriveVrfKeypairFromPrfRequest> = {\n type: 'DERIVE_VRF_KEYPAIR_FROM_PRF',\n id: ctx.generateMessageId(),\n payload: {\n credential: args.credential,\n nearAccountId: args.nearAccountId,\n\t saveInMemory,\n\t vrfInputData: hasVrfInputData ? {\n\t userId: vrfInputData.userId,\n\t rpId: vrfInputData.rpId,\n\t blockHeight: String(vrfInputData.blockHeight),\n\t blockHash: vrfInputData.blockHash,\n\t intentDigest: vrfInputData.intentDigest,\n sessionPolicyDigest32: vrfInputData.sessionPolicyDigest32,\n\t } : undefined,\n\t }\n\t };\n\n const response = await ctx.sendMessage(message);\n\n if (!response.success || !response.data) {\n throw new Error(`VRF keypair derivation failed: ${response.error}`);\n }\n const data = response.data as {\n vrfPublicKey?: string;\n vrfChallengeData?: VRFChallenge;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n serverEncryptedVrfKeypair?: ServerEncryptedVrfKeypair | null;\n };\n\n const vrfPublicKey = data.vrfPublicKey || data.vrfChallengeData?.vrfPublicKey;\n if (!vrfPublicKey) {\n throw new Error('VRF public key not found in response');\n }\n if (!data.encryptedVrfKeypair) {\n throw new Error('Encrypted VRF keypair not found in response');\n }\n\n const vrfChallenge = data.vrfChallengeData\n ? validateVRFChallenge({\n vrfInput: data.vrfChallengeData.vrfInput,\n vrfOutput: data.vrfChallengeData.vrfOutput,\n vrfProof: data.vrfChallengeData.vrfProof,\n vrfPublicKey: data.vrfChallengeData.vrfPublicKey,\n userId: data.vrfChallengeData.userId,\n rpId: data.vrfChallengeData.rpId,\n blockHeight: data.vrfChallengeData.blockHeight,\n blockHash: data.vrfChallengeData.blockHash,\n ...(data.vrfChallengeData.intentDigest ? { intentDigest: data.vrfChallengeData.intentDigest } : {}),\n ...(data.vrfChallengeData.sessionPolicyDigest32 ? { sessionPolicyDigest32: data.vrfChallengeData.sessionPolicyDigest32 } : {}),\n })\n : null;\n\n if (saveInMemory) {\n ctx.setCurrentVrfAccountId(args.nearAccountId);\n console.debug(`VRF Manager: VRF keypair loaded in memory for ${args.nearAccountId}`);\n }\n\n return {\n vrfPublicKey,\n vrfChallenge,\n encryptedVrfKeypair: data.encryptedVrfKeypair,\n serverEncryptedVrfKeypair: data.serverEncryptedVrfKeypair || null,\n };\n}\n","import type {\n VRFWorkerMessage,\n WasmMintSessionKeysAndSendToSignerRequest,\n} from '../../../types/vrf-worker';\nimport type { WebAuthnAuthenticationCredential, WebAuthnRegistrationCredential } from '../../../types/webauthn';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Mint/refresh a VRF-owned signing session and deliver WrapKey material to the signer worker.\n *\n * VRF WASM will:\n * - (optionally) gate on `verify_authentication_response` when `contractId` + `nearRpcUrl` are provided,\n * - derive WrapKeySeed from PRF.first_auth + the in-memory VRF secret key,\n * - choose/generate `wrapKeySalt` (when omitted/empty),\n * - upsert session metadata (TTL + remaining uses),\n * - and send `{ wrap_key_seed, wrapKeySalt, prfSecond? }` to the signer worker over the attached MessagePort.\n *\n * The main thread never receives WrapKeySeed; it only receives `wrapKeySalt` metadata.\n * This expects `createSigningSessionChannel` + signer port attachment to have happened for `sessionId`.\n */\nexport async function mintSessionKeysAndSendToSigner(\n ctx: VrfWorkerManagerHandlerContext,\n args: {\n sessionId: string;\n wrapKeySalt?: string;\n contractId?: string;\n nearRpcUrl?: string;\n ttlMs?: number;\n remainingUses?: number;\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n }\n): Promise<{ sessionId: string; wrapKeySalt: string }> {\n await ctx.ensureWorkerReady(true);\n\n const message: VRFWorkerMessage<WasmMintSessionKeysAndSendToSignerRequest> = {\n type: 'MINT_SESSION_KEYS_AND_SEND_TO_SIGNER',\n id: ctx.generateMessageId(),\n payload: {\n sessionId: args.sessionId,\n // Use empty string as a sentinel to tell the VRF worker to generate wrapKeySalt when none is provided.\n wrapKeySalt: args.wrapKeySalt ?? '',\n contractId: args.contractId,\n nearRpcUrl: args.nearRpcUrl,\n ttlMs: args.ttlMs,\n remainingUses: args.remainingUses,\n credential: args.credential,\n }\n };\n const response = await ctx.sendMessage<WasmMintSessionKeysAndSendToSignerRequest>(message);\n if (!response.success) {\n throw new Error(`mintSessionKeysAndSendToSigner failed: ${response.error}`);\n }\n // VRF WASM now delivers WrapKeySeed + wrapKeySalt directly to the signer worker via the\n // attached MessagePort; TS only needs to know that the session is prepared and\n // what wrapKeySalt was actually used (for new vault entries).\n const data = (response.data as unknown) as { sessionId: string; wrapKeySalt?: string } | undefined;\n const wrapKeySalt = data?.wrapKeySalt ?? args.wrapKeySalt ?? '';\n if (!wrapKeySalt) {\n throw new Error('mintSessionKeysAndSendToSigner: VRF worker did not return wrapKeySalt');\n }\n return { sessionId: data?.sessionId ?? args.sessionId, wrapKeySalt };\n}\n","import type { VRFWorkerMessage, WasmDispenseSessionKeyRequest } from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * \"Warm session\" path: dispense an existing VRF-owned session key to the signer worker.\n *\n * VRF WASM enforces TTL/usage limits for `sessionId`, then sends `{ wrap_key_seed, wrapKeySalt }`\n * over the attached MessagePort to the signer worker. This does not prompt for WebAuthn.\n */\nexport async function dispenseSessionKey(\n ctx: VrfWorkerManagerHandlerContext,\n args: { sessionId: string; uses?: number }\n): Promise<{\n sessionId: string;\n remainingUses?: number;\n expiresAtMs?: number;\n}> {\n await ctx.ensureWorkerReady(true);\n const message: VRFWorkerMessage<WasmDispenseSessionKeyRequest> = {\n type: 'DISPENSE_SESSION_KEY',\n id: ctx.generateMessageId(),\n payload: {\n sessionId: args.sessionId,\n uses: args.uses,\n } as any,\n };\n const response = await ctx.sendMessage<WasmDispenseSessionKeyRequest>(message);\n if (!response.success) {\n throw new Error(`dispenseSessionKey failed: ${response.error}`);\n }\n return (response.data as any) || { sessionId: args.sessionId };\n}\n","import type { AccountId } from '../../../types/accountIds';\nimport type {\n VRFWorkerMessage,\n VRFWorkerResponse,\n WasmShamir3PassClientDecryptVrfKeypairRequest\n} from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Shamir 3-pass (client): decrypt/unlock a VRF keypair using a server-protected envelope.\n *\n * On success, the VRF keypair becomes active in the VRF worker and is bound (in TS state) to `nearAccountId`.\n */\nexport async function shamir3PassDecryptVrfKeypair(\n ctx: VrfWorkerManagerHandlerContext,\n args: {\n nearAccountId: AccountId;\n kek_s_b64u: string;\n ciphertextVrfB64u: string;\n serverKeyId: string;\n }\n): Promise<VRFWorkerResponse> {\n await ctx.ensureWorkerReady(true);\n const message: VRFWorkerMessage<WasmShamir3PassClientDecryptVrfKeypairRequest> = {\n type: 'SHAMIR3PASS_CLIENT_DECRYPT_VRF_KEYPAIR',\n id: ctx.generateMessageId(),\n payload: {\n nearAccountId: args.nearAccountId,\n kek_s_b64u: args.kek_s_b64u,\n ciphertextVrfB64u: args.ciphertextVrfB64u,\n // Required key for server selection\n keyId: args.serverKeyId,\n },\n };\n const response = await ctx.sendMessage(message);\n if (response.success) {\n ctx.setCurrentVrfAccountId(args.nearAccountId);\n }\n return response;\n}\n","import type {\n VRFInputData,\n VRFWorkerMessage,\n WasmGenerateVrfChallengeRequest,\n} from '../../../types/vrf-worker';\nimport { validateVRFChallenge, type VRFChallenge } from '../../../types/vrf-worker';\nimport { toAccountId } from '../../../types/accountIds';\nimport type { VrfWorkerManagerHandlerContext } from './types';\nimport { checkVrfStatus } from './checkVrfStatus';\nimport { shamir3PassDecryptVrfKeypair } from './shamir3PassDecryptVrfKeypair';\nimport { toTrimmedString } from '@/utils';\n\n/**\n * Generate a VRF challenge and cache it under `sessionId` inside the VRF worker.\n *\n * This is used by SecureConfirm flows so later steps (e.g. contract verification) can rely on\n * worker-owned challenge data instead of JS-provided state.\n */\nexport async function generateVrfChallengeForSession(\n ctx: VrfWorkerManagerHandlerContext,\n inputData: VRFInputData,\n sessionId: string\n): Promise<VRFChallenge> {\n return generateVrfChallengeInternal(ctx, inputData, sessionId);\n}\n\n/**\n * Generate a one-off VRF challenge without caching it in the VRF worker.\n *\n * Used for standalone WebAuthn prompts where we don't need to later look up the challenge by `sessionId`.\n */\nexport async function generateVrfChallengeOnce(\n ctx: VrfWorkerManagerHandlerContext,\n inputData: VRFInputData\n): Promise<VRFChallenge> {\n return generateVrfChallengeInternal(ctx, inputData);\n}\n\nasync function generateVrfChallengeInternal(\n ctx: VrfWorkerManagerHandlerContext,\n inputData: VRFInputData,\n sessionId?: string\n): Promise<VRFChallenge> {\n await ctx.ensureWorkerReady(true);\n\n // Root-cause fix: ensure the VRF worker's active VRF keypair matches the IndexedDB \"lastUser\" device.\n // Otherwise, multi-device accounts can drift such that:\n // - WebAuthn allowCredentials selects the lastUser passkey, but\n // - VRF challenges are generated from a different device's vrf_sk,\n // causing contract verification failures.\n await ensureVrfKeypairBoundToLastUser(ctx, inputData.userId);\n\n const message: VRFWorkerMessage<WasmGenerateVrfChallengeRequest> = {\n type: 'GENERATE_VRF_CHALLENGE',\n id: ctx.generateMessageId(),\n payload: {\n sessionId,\n\t vrfInputData: {\n\t userId: inputData.userId,\n\t rpId: inputData.rpId,\n\t blockHeight: String(inputData.blockHeight),\n\t blockHash: inputData.blockHash,\n\t intentDigest: inputData.intentDigest,\n sessionPolicyDigest32: inputData.sessionPolicyDigest32,\n\t },\n\t },\n\t };\n\n const response = await ctx.sendMessage(message);\n\n if (!response.success || !response.data) {\n throw new Error(`VRF challenge generation failed: ${response.error}`);\n }\n\n const data = response.data as unknown as VRFChallenge;\n return validateVRFChallenge(data);\n}\n\nasync function ensureVrfKeypairBoundToLastUser(\n ctx: VrfWorkerManagerHandlerContext,\n nearAccountId: string,\n): Promise<void> {\n const accountId = toAccountId(nearAccountId);\n const { indexedDB } = ctx.getContext();\n\n const lastUser = await indexedDB.clientDB.getLastUser().catch(() => null);\n if (!lastUser || toAccountId(lastUser.nearAccountId) !== accountId) {\n return;\n }\n\n const lastUserDeviceNumber = Number(lastUser.deviceNumber);\n if (!Number.isFinite(lastUserDeviceNumber) || lastUserDeviceNumber < 1) {\n return;\n }\n\n const status = await checkVrfStatus(ctx);\n const currentVrfPublicKey = toTrimmedString(status.vrfPublicKey);\n\n // Best-effort: find the expected VRF public key for the last-user device from the authenticator cache.\n const authenticators = await indexedDB.clientDB.getAuthenticatorsByUser(accountId).catch(() => []);\n const expectedVrfPublicKey = toTrimmedString(\n authenticators.find(a => a.credentialId === lastUser.passkeyCredential.rawId)?.vrfPublicKey\n ?? authenticators.find(a => a.deviceNumber === lastUserDeviceNumber)?.vrfPublicKey\n );\n\n const needsRebind = !status.active\n || (expectedVrfPublicKey && currentVrfPublicKey !== expectedVrfPublicKey);\n\n if (!needsRebind) {\n return;\n }\n\n const shamir = lastUser.serverEncryptedVrfKeypair;\n if (!shamir?.ciphertextVrfB64u || !shamir?.kek_s_b64u || !shamir?.serverKeyId) {\n // If we can't rebind automatically, fail early instead of silently generating a challenge from the wrong vrf_sk.\n throw new Error(\n 'VRF session is not bound to the last logged-in passkey device. Please log in again on this device.',\n );\n }\n\n const unlock = await shamir3PassDecryptVrfKeypair(ctx, {\n nearAccountId: accountId,\n ciphertextVrfB64u: shamir.ciphertextVrfB64u,\n kek_s_b64u: shamir.kek_s_b64u,\n serverKeyId: shamir.serverKeyId,\n });\n if (!unlock.success) {\n throw new Error(unlock.error || 'Failed to rebind VRF keypair to the last logged-in device');\n }\n\n // If we know the expected VRF pk, confirm the rebind succeeded.\n if (expectedVrfPublicKey) {\n const rebound = await checkVrfStatus(ctx);\n const reboundPk = toTrimmedString(rebound.vrfPublicKey);\n if (!rebound.active || reboundPk !== expectedVrfPublicKey) {\n throw new Error(\n 'VRF session mismatch: VRF keypair did not match the last logged-in device after rebind. Please log in again.',\n );\n }\n }\n}\n","import type { VRFInputData } from '../../../types/vrf-worker';\nimport { validateVRFChallenge, type VRFChallenge } from '../../../types/vrf-worker';\nimport type { VRFWorkerMessage, WasmGenerateVrfKeypairBootstrapRequest } from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Registration bootstrap: generate a fresh random VRF keypair in the VRF worker and (optionally)\n * generate a VRF challenge from it.\n *\n * This solves the \"chicken-and-egg\" problem during registration where you need a VRF challenge\n * before you have PRF outputs to encrypt the VRF keypair. The generated VRF keypair lives in\n * VRF worker memory until it is later encrypted with PRF output.\n */\nexport async function generateVrfKeypairBootstrap(\n ctx: VrfWorkerManagerHandlerContext,\n args: {\n vrfInputData: VRFInputData;\n saveInMemory: boolean;\n sessionId?: string;\n }\n): Promise<{\n vrfPublicKey: string;\n vrfChallenge: VRFChallenge;\n}> {\n await ctx.ensureWorkerReady();\n try {\n const message: VRFWorkerMessage<WasmGenerateVrfKeypairBootstrapRequest> = {\n type: 'GENERATE_VRF_KEYPAIR_BOOTSTRAP',\n id: ctx.generateMessageId(),\n\t payload: {\n\t // Include VRF input data if provided for challenge generation\n\t sessionId: args.sessionId,\n\t vrfInputData: args.vrfInputData\n\t ? {\n\t userId: args.vrfInputData.userId,\n\t rpId: args.vrfInputData.rpId,\n\t blockHeight: String(args.vrfInputData.blockHeight),\n\t blockHash: args.vrfInputData.blockHash,\n\t intentDigest: args.vrfInputData.intentDigest,\n sessionPolicyDigest32: args.vrfInputData.sessionPolicyDigest32,\n\t }\n\t : undefined,\n\t },\n\t };\n\n const response = await ctx.sendMessage(message);\n\n if (!response.success || !response.data) {\n throw new Error(`VRF bootstrap keypair generation failed: ${response.error}`);\n }\n const data = response.data as { vrf_challenge_data?: VRFChallenge; vrfPublicKey?: string };\n const challengeData = data.vrf_challenge_data as VRFChallenge | undefined;\n if (!challengeData) {\n throw new Error('VRF challenge data failed to be generated');\n }\n const vrfPublicKey = data.vrfPublicKey || challengeData.vrfPublicKey;\n if (!vrfPublicKey) {\n throw new Error('VRF public key missing in bootstrap response');\n }\n if (args.vrfInputData && args.saveInMemory) {\n // Track the account ID for this VRF session if saving in memory\n ctx.setCurrentVrfAccountId(args.vrfInputData.userId);\n }\n\n // TODO: strong types generated by Rust wasm-bindgen\n return {\n vrfPublicKey,\n vrfChallenge: validateVRFChallenge({\n vrfInput: challengeData.vrfInput,\n vrfOutput: challengeData.vrfOutput,\n vrfProof: challengeData.vrfProof,\n vrfPublicKey: challengeData.vrfPublicKey,\n userId: challengeData.userId,\n rpId: challengeData.rpId,\n blockHeight: challengeData.blockHeight,\n blockHash: challengeData.blockHash,\n ...(challengeData.intentDigest ? { intentDigest: challengeData.intentDigest } : {}),\n ...(challengeData.sessionPolicyDigest32 ? { sessionPolicyDigest32: challengeData.sessionPolicyDigest32 } : {}),\n })\n }\n\n } catch (error: any) {\n console.error('VRF Manager: Bootstrap VRF keypair generation failed:', error);\n throw new Error(`Failed to generate bootstrap VRF keypair: ${error.message}`);\n }\n}\n","import type { VRFWorkerMessage, WasmCheckSessionStatusRequest } from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Per-`sessionId` signing-session status (WrapKeySeed session gating).\n *\n * This is NOT the same as the \"global\" VRF unlock status (whether the VRF keypair is active).\n * For VRF keypair unlock status, use `checkVrfStatus`.\n */\nexport async function checkSessionStatus(\n ctx: VrfWorkerManagerHandlerContext,\n args: { sessionId: string }\n): Promise<{\n sessionId: string;\n status: 'active' | 'exhausted' | 'expired' | 'not_found';\n remainingUses?: number;\n expiresAtMs?: number;\n createdAtMs?: number;\n}> {\n await ctx.ensureWorkerReady(true);\n const message: VRFWorkerMessage<WasmCheckSessionStatusRequest> = {\n type: 'CHECK_SESSION_STATUS',\n id: ctx.generateMessageId(),\n payload: {\n sessionId: args.sessionId,\n } as any,\n };\n const response = await ctx.sendMessage<WasmCheckSessionStatusRequest>(message);\n if (!response.success) {\n throw new Error(`checkSessionStatus failed: ${response.error}`);\n }\n return (\n (response.data as any) || {\n sessionId: args.sessionId,\n status: 'not_found',\n }\n );\n}\n","import type { AccountId } from '../../../types/accountIds';\nimport type { EncryptedVRFKeypair, VRFWorkerMessage } from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Prepare an export/decrypt session by having the VRF worker derive and deliver WrapKeySeed\n * to the signer worker, using the VRF-owned confirmation flow.\n *\n * This is used by \"offline export\" / decrypt flows where secrets must not touch the main thread.\n */\nexport async function prepareDecryptSession(\n ctx: VrfWorkerManagerHandlerContext,\n args: {\n sessionId: string;\n nearAccountId: AccountId;\n wrapKeySalt: string;\n /**\n * Optional: local encrypted VRF keypair for this account/device.\n * Supplying this lets the VRF worker unlock the correct VRF secret in offline mode.\n */\n encryptedVrfKeypair?: EncryptedVRFKeypair;\n /**\n * Optional: expected VRF public key (base64url) for sanity checking/fallback derivation.\n */\n expectedVrfPublicKey?: string;\n }\n): Promise<void> {\n if (!args.wrapKeySalt) {\n throw new Error('wrapKeySalt is required for decrypt session');\n }\n await ctx.ensureWorkerReady(true);\n const message: VRFWorkerMessage<any> = {\n type: 'DECRYPT_SESSION',\n id: ctx.generateMessageId(),\n payload: {\n sessionId: args.sessionId,\n nearAccountId: String(args.nearAccountId),\n wrapKeySalt: args.wrapKeySalt,\n encryptedVrfKeypair: args.encryptedVrfKeypair,\n expectedVrfPublicKey: args.expectedVrfPublicKey,\n },\n };\n try {\n console.debug('[VRF] prepareDecryptSession: start', {\n sessionId: args.sessionId,\n nearAccountId: String(args.nearAccountId),\n });\n const response = await ctx.sendMessage(message);\n if (!response.success) {\n console.error('[VRF] prepareDecryptSession: worker reported failure', {\n sessionId: args.sessionId,\n nearAccountId: String(args.nearAccountId),\n error: response.error,\n });\n throw new Error(`prepareDecryptSession failed: ${response.error}`);\n }\n console.debug('[VRF] prepareDecryptSession: success', {\n sessionId: args.sessionId,\n nearAccountId: String(args.nearAccountId),\n });\n } catch (error) {\n console.error('[VRF] prepareDecryptSession: error', {\n sessionId: args.sessionId,\n nearAccountId: String(args.nearAccountId),\n error,\n });\n throw error;\n }\n}\n","import type { ConfirmationConfig } from '../../../../types/signer-worker';\nimport { PASSKEY_MANAGER_DEFAULT_CONFIGS } from '../../../../defaultConfigs';\nimport type { VrfWorkerManagerContext } from '../../';\nimport { runSecureConfirm } from '../../secureConfirmBridge';\nimport {\n SecureConfirmationType,\n type RegistrationSummary,\n type SecureConfirmRequest,\n} from '../types';\nimport {\n parseAndValidateRegistrationCredentialConfirmationPayload,\n type RegistrationCredentialConfirmationPayload,\n} from '../../../SignerWorkerManager/handlers/validation';\n\nexport async function requestRegistrationCredentialConfirmation({\n ctx,\n nearAccountId,\n deviceNumber,\n confirmerText,\n contractId,\n nearRpcUrl,\n confirmationConfig,\n}: {\n ctx: VrfWorkerManagerContext,\n nearAccountId: string,\n deviceNumber: number,\n confirmerText?: { title?: string; body?: string };\n contractId: string,\n nearRpcUrl: string,\n confirmationConfig?: Partial<ConfirmationConfig>,\n}): Promise<RegistrationCredentialConfirmationPayload> {\n\n // Ensure required fields are present; JSON.stringify drops undefined causing Rust parse failure\n const resolvedContractId = contractId || PASSKEY_MANAGER_DEFAULT_CONFIGS.contractId;\n // Use the first URL if defaults include a failover list\n const resolvedNearRpcUrl = nearRpcUrl\n || (PASSKEY_MANAGER_DEFAULT_CONFIGS.nearRpcUrl.split(',')[0] || PASSKEY_MANAGER_DEFAULT_CONFIGS.nearRpcUrl);\n\n const requestId = (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function')\n ? crypto.randomUUID()\n : `register-${Date.now()}-${Math.random().toString(16).slice(2)}`;\n\n const title = confirmerText?.title;\n const body = confirmerText?.body;\n const request: SecureConfirmRequest<{\n nearAccountId: string;\n deviceNumber: number;\n rpcCall: { contractId: string; nearRpcUrl: string; nearAccountId: string };\n }, RegistrationSummary> = {\n requestId,\n type: SecureConfirmationType.REGISTER_ACCOUNT,\n summary: {\n nearAccountId,\n deviceNumber,\n contractId: resolvedContractId,\n ...(title != null ? { title } : {}),\n ...(body != null ? { body } : {}),\n },\n payload: {\n nearAccountId,\n deviceNumber,\n rpcCall: {\n contractId: resolvedContractId,\n nearRpcUrl: resolvedNearRpcUrl,\n nearAccountId,\n },\n },\n confirmationConfig,\n intentDigest: `register:${nearAccountId}:${deviceNumber}`,\n };\n\n const decision = await runSecureConfirm(ctx, request);\n\n return parseAndValidateRegistrationCredentialConfirmationPayload({\n confirmed: decision.confirmed,\n requestId,\n intentDigest: decision.intentDigest || '',\n credential: decision.credential,\n vrfChallenge: decision.vrfChallenge,\n transactionContext: decision.transactionContext,\n error: decision.error,\n });\n}\n","import type { ConfirmationConfig } from '../../../types/signer-worker';\nimport type { RegistrationCredentialConfirmationPayload } from '../../SignerWorkerManager/handlers/validation';\nimport { requestRegistrationCredentialConfirmation as requestRegistrationCredentialConfirmationFlow } from '../confirmTxFlow/flows/requestRegistrationCredentialConfirmation';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Kick off the SecureConfirm UI flow for account registration and return the confirmed decision.\n *\n * This is used when the host (main thread) needs a registration credential + VRF challenge + NEAR context,\n * but the UI/confirmation orchestration lives in the VRF worker confirmation flow.\n */\nexport async function requestRegistrationCredentialConfirmation(\n ctx: VrfWorkerManagerHandlerContext,\n params: {\n nearAccountId: string;\n deviceNumber: number;\n confirmerText?: { title?: string; body?: string };\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n contractId: string;\n nearRpcUrl: string;\n }\n): Promise<RegistrationCredentialConfirmationPayload> {\n const hostCtx = ctx.getContext();\n const decision = await requestRegistrationCredentialConfirmationFlow({\n ctx: hostCtx,\n nearAccountId: params.nearAccountId,\n deviceNumber: params.deviceNumber,\n confirmerText: params.confirmerText,\n contractId: params.contractId,\n nearRpcUrl: params.nearRpcUrl,\n // Flow expects `confirmationConfig` on the request envelope; forward the override.\n confirmationConfig: params.confirmationConfigOverride,\n });\n\n if (!decision.confirmed) {\n throw new Error(decision.error || 'User rejected registration request');\n }\n if (!decision.credential) {\n throw new Error('Missing credential from registration confirmation');\n }\n if (!decision.vrfChallenge) {\n throw new Error('Missing vrfChallenge from registration confirmation');\n }\n if (!decision.transactionContext) {\n throw new Error('Missing transactionContext from registration confirmation');\n }\n\n return decision;\n}\n","import type { VRFWorkerMessage, WasmVrfWorkerRequestType } from '../../../types/vrf-worker';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Shamir 3-pass (client): encrypt the currently-unlocked VRF keypair for server lock flows.\n *\n * Returns ciphertext + client key share (`kek_s_b64u`) + server key id for subsequent unlock.\n */\nexport async function shamir3PassEncryptCurrentVrfKeypair(\n ctx: VrfWorkerManagerHandlerContext,\n): Promise<{\n ciphertextVrfB64u: string;\n kek_s_b64u: string;\n serverKeyId: string;\n}> {\n await ctx.ensureWorkerReady(true);\n const message: VRFWorkerMessage<WasmVrfWorkerRequestType> = {\n type: 'SHAMIR3PASS_CLIENT_ENCRYPT_CURRENT_VRF_KEYPAIR',\n id: ctx.generateMessageId(),\n payload: {} as WasmVrfWorkerRequestType,\n };\n const response = await ctx.sendMessage(message);\n if (!response.success || !response.data) {\n throw new Error(`VRF encrypt-current failed: ${response.error}`);\n }\n const { ciphertextVrfB64u, kek_s_b64u, serverKeyId } = response.data as {\n ciphertextVrfB64u: string;\n kek_s_b64u: string;\n serverKeyId: string;\n };\n if (!ciphertextVrfB64u || !kek_s_b64u) {\n throw new Error('Invalid encrypt-current response');\n }\n if (!serverKeyId) {\n throw new Error('Server did not return keyId from apply-server-lock');\n }\n return { ciphertextVrfB64u, kek_s_b64u, serverKeyId };\n}\n","import type { AccountId } from '../../../types/accountIds';\nimport type {\n EncryptedVRFKeypair,\n VRFWorkerMessage,\n VRFWorkerResponse,\n WasmUnlockVrfKeypairRequest,\n} from '../../../types/vrf-worker';\nimport type { WebAuthnAuthenticationCredential, WebAuthnRegistrationCredential } from '../../../types/webauthn';\nimport type { VrfWorkerManagerHandlerContext } from './types';\n\n/**\n * Unlock/load the VRF keypair into VRF worker memory using a WebAuthn authentication credential.\n *\n * This is the \"login\" / \"unlock\" path: the VRF worker decrypts the stored encrypted VRF keypair\n * using PRF output, and keeps it active in-memory for subsequent operations (challenge gen, sessions, etc.).\n */\nexport async function unlockVrfKeypair(\n ctx: VrfWorkerManagerHandlerContext,\n args: {\n credential: WebAuthnAuthenticationCredential | WebAuthnRegistrationCredential;\n nearAccountId: AccountId;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n onEvent?: (event: { type: string; data: { step: string; message: string } }) => void;\n }\n): Promise<VRFWorkerResponse> {\n await ctx.ensureWorkerReady(true);\n\n args.onEvent?.({\n type: 'loginProgress',\n data: {\n step: 'verifying-server',\n message: 'TouchId success! Unlocking VRF keypair...'\n }\n });\n\n const message: VRFWorkerMessage<WasmUnlockVrfKeypairRequest> = {\n type: 'UNLOCK_VRF_KEYPAIR',\n id: ctx.generateMessageId(),\n payload: {\n nearAccountId: args.nearAccountId,\n encryptedVrfKeypair: args.encryptedVrfKeypair,\n credential: args.credential,\n }\n };\n\n const response = await ctx.sendMessage(message);\n if (response.success) {\n // Track the current VRF session account at TypeScript level\n ctx.setCurrentVrfAccountId(args.nearAccountId);\n console.debug(`VRF Manager: VRF keypair unlocked for ${args.nearAccountId}`);\n } else {\n console.error('VRF Manager: Failed to unlock VRF keypair:', response.error);\n console.error('VRF Manager: Full response:', JSON.stringify(response, null, 2));\n console.error('VRF Manager: Message that was sent:', JSON.stringify(message, null, 2));\n }\n\n return response;\n}\n","/**\n * VRF Manager\n * Uses Web Workers for VRF keypair management with client-hosted worker files.\n */\n\nimport type {\n VRFWorkerStatus,\n VrfWorkerManagerConfig,\n EncryptedVRFKeypair,\n VRFInputData,\n VRFWorkerMessage,\n VRFWorkerResponse,\n ServerEncryptedVrfKeypair,\n WasmVrfWorkerRequestType,\n WasmShamir3PassConfigPRequest,\n WasmShamir3PassConfigServerUrlsRequest,\n} from '../../types/vrf-worker';\nimport type { VRFChallenge } from '../../types/vrf-worker';\nimport { BUILD_PATHS } from '../../../../build-paths.js';\nimport { resolveWorkerUrl } from '../../sdkPaths';\nimport type { AccountId } from '../../types/accountIds';\nimport type { TouchIdPrompt } from '../touchIdPrompt';\nimport type { NearClient } from '../../NearClient';\nimport type { UnifiedIndexedDBManager } from '../../IndexedDBManager';\nimport type { UserPreferencesManager } from '../userPreferences';\nimport type { NonceManager } from '../../nonceManager';\nimport {\n SecureConfirmMessageType,\n type SecureConfirmRequest,\n type SerializableCredential,\n type SigningAuthMode,\n} from './confirmTxFlow/types';\nimport type { TransactionInputWasm } from '../../types/actions';\nimport type { RpcCallPayload, ConfirmationConfig } from '../../types/signer-worker';\nimport type { TransactionContext } from '../../types/rpc';\nimport type { RegistrationCredentialConfirmationPayload } from '../SignerWorkerManager/handlers/validation';\nimport type { WebAuthnAuthenticationCredential, WebAuthnRegistrationCredential } from '../../types/webauthn';\nimport { handlePromptUserConfirmInJsMainThread } from './confirmTxFlow';\nimport type { VrfWorkerManagerHandlerContext } from './handlers/types';\nimport { WorkerControlMessage } from '../../workerControlMessages';\nimport {\n checkVrfStatus,\n clearSession,\n clearVrfSession,\n confirmAndDeriveDevice2RegistrationSession,\n confirmAndPrepareSigningSession,\n deriveVrfKeypairFromPrf,\n mintSessionKeysAndSendToSigner,\n dispenseSessionKey,\n generateVrfChallengeForSession,\n generateVrfChallengeOnce,\n generateVrfKeypairBootstrap,\n checkSessionStatus,\n prepareDecryptSession,\n requestRegistrationCredentialConfirmation,\n shamir3PassDecryptVrfKeypair,\n shamir3PassEncryptCurrentVrfKeypair,\n unlockVrfKeypair,\n} from './handlers';\n\n/**\n * VRF-owned host context passed into confirmTxFlow.\n */\nexport interface VrfWorkerManagerContext {\n touchIdPrompt: TouchIdPrompt;\n nearClient: NearClient;\n indexedDB: UnifiedIndexedDBManager;\n userPreferencesManager: UserPreferencesManager;\n nonceManager: NonceManager;\n rpIdOverride?: string;\n nearExplorerUrl?: string;\n vrfWorkerManager?: SessionVrfWorkerManager;\n}\n\n/**\n * Narrow VRF manager surface used by confirmTxFlow. This interface only exposes\n * session-bound operations so confirm flows cannot accidentally call the\n * low-level helpers that take an optional sessionId.\n */\nexport interface SessionVrfWorkerManager {\n generateVrfKeypairBootstrap(args: {\n vrfInputData: VRFInputData;\n saveInMemory: boolean;\n sessionId: string;\n }): Promise<{\n vrfPublicKey: string;\n vrfChallenge: VRFChallenge;\n }>;\n\n generateVrfChallengeForSession(inputData: VRFInputData, sessionId: string): Promise<VRFChallenge>;\n\n mintSessionKeysAndSendToSigner(args: {\n sessionId: string;\n wrapKeySalt?: string;\n contractId?: string;\n nearRpcUrl?: string;\n ttlMs?: number;\n remainingUses?: number;\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n }): Promise<{ sessionId: string; wrapKeySalt: string }>;\n\n dispenseSessionKey(args: {\n sessionId: string;\n uses?: number;\n }): Promise<{\n sessionId: string;\n remainingUses?: number;\n expiresAtMs?: number;\n }>;\n\n prepareDecryptSession(args: {\n sessionId: string;\n nearAccountId: AccountId;\n wrapKeySalt: string;\n encryptedVrfKeypair?: EncryptedVRFKeypair;\n expectedVrfPublicKey?: string;\n }): Promise<void>;\n\n requestRegistrationCredentialConfirmation(params: {\n nearAccountId: string;\n deviceNumber: number;\n confirmerText?: { title?: string; body?: string };\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n contractId: string;\n nearRpcUrl: string;\n }): Promise<RegistrationCredentialConfirmationPayload>;\n\n confirmAndDeriveDevice2RegistrationSession(params: {\n sessionId: string;\n nearAccountId: AccountId;\n deviceNumber: number;\n contractId: string;\n nearRpcUrl: string;\n authenticatorOptions?: object;\n wrapKeySalt?: string;\n }): Promise<{\n confirmed: boolean;\n sessionId: string;\n credential: WebAuthnRegistrationCredential;\n vrfChallenge: VRFChallenge;\n transactionContext: TransactionContext;\n wrapKeySalt: string;\n requestId: string;\n intentDigest: string;\n deterministicVrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n error?: string;\n }>;\n\n checkVrfStatus(): Promise<VRFWorkerStatus>;\n}\n\n/**\n * VRF Worker Manager\n *\n * This class manages VRF operations using Web Workers for:\n * - VRF keypair unlocking (login)\n * - VRF challenge generation (authentication)\n * - Session management (browser session only)\n * - Client-hosted worker files\n */\nexport class VrfWorkerManager {\n private vrfWorker: Worker | null = null;\n private initializationPromise: Promise<void> | null = null;\n private messageId = 0;\n private config: VrfWorkerManagerConfig;\n private currentVrfAccountId: string | null = null;\n private workerBaseOrigin: string | undefined;\n private context: VrfWorkerManagerContext;\n\n constructor(config: VrfWorkerManagerConfig, context: VrfWorkerManagerContext) {\n this.config = {\n // Default to client-hosted worker file using centralized config\n vrfWorkerUrl: BUILD_PATHS.RUNTIME.VRF_WORKER,\n workerTimeout: 60_000,\n debug: false,\n ...config\n };\n // Attach a self-reference so confirmTxFlow helpers can call back into VRF APIs.\n this.context = {\n ...context,\n vrfWorkerManager: this,\n };\n }\n\n /**\n * Context used by confirmTxFlow for VRF-driven flows.\n */\n getContext(): VrfWorkerManagerContext {\n return this.context;\n }\n\n private getHandlerContext(): VrfWorkerManagerHandlerContext {\n return {\n ensureWorkerReady: this.ensureWorkerReady.bind(this),\n sendMessage: this.sendMessage.bind(this),\n generateMessageId: this.generateMessageId.bind(this),\n getContext: this.getContext.bind(this),\n postToWorker: (message: unknown, transfer?: Transferable[]) => {\n if (!this.vrfWorker) {\n throw new Error('VRF Web Worker not available');\n }\n this.vrfWorker.postMessage(message, transfer as any);\n },\n getCurrentVrfAccountId: () => this.currentVrfAccountId,\n setCurrentVrfAccountId: (next: string | null) => {\n this.currentVrfAccountId = next;\n },\n };\n }\n\n /**\n * Create a VRF-owned MessageChannel for signing and return the signer-facing port.\n * VRF retains the sibling port for WrapKeySeed delivery.\n */\n async createSigningSessionChannel(sessionId: string): Promise<MessagePort> {\n await this.ensureWorkerReady(true);\n if (!this.vrfWorker) {\n throw new Error('VRF Web Worker not available');\n }\n\n const channel = new MessageChannel();\n\n // Wait for VRF worker ACK to avoid a race where MintSessionKeys runs before\n // the VRF worker has stored the port (WrapKeySeed delivery would silently no-op).\n const ackPromise = new Promise<void>((resolve, reject) => {\n const worker = this.vrfWorker!;\n const timeout = setTimeout(() => {\n cleanup();\n reject(new Error(`Timeout waiting for VRF WrapKeySeed port attach for session ${sessionId}`));\n }, 2000);\n\n const onMessage = (event: MessageEvent) => {\n const msg = (event as any)?.data as any;\n if (!msg || typeof msg.type !== 'string') return;\n if (msg.sessionId !== sessionId) return;\n\n if (msg.type === WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_ERROR) {\n cleanup();\n reject(new Error(String(msg.error || 'VRF worker failed to attach WrapKeySeed port')));\n return;\n }\n if (msg.type === WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT_OK) {\n cleanup();\n resolve();\n }\n };\n\n const cleanup = () => {\n clearTimeout(timeout);\n worker.removeEventListener('message', onMessage);\n };\n\n worker.addEventListener('message', onMessage);\n });\n\n this.vrfWorker.postMessage(\n { type: WorkerControlMessage.ATTACH_WRAP_KEY_SEED_PORT, sessionId },\n [channel.port1],\n );\n\n await ackPromise;\n return channel.port2;\n }\n\n /**\n * Derive WrapKeySeed in the VRF worker and deliver it (along with PRF.second if credential provided)\n * to the signer worker via the registered port.\n */\n async mintSessionKeysAndSendToSigner(args: {\n sessionId: string;\n // Optional vault wrapKeySalt. When omitted or empty, VRF worker will generate a fresh wrapKeySalt.\n wrapKeySalt?: string;\n // Optional contract verification context; when provided, VRF Rust will call\n // verify_authentication_response before deriving WrapKeySeed.\n contractId?: string;\n nearRpcUrl?: string;\n // Optional signing-session config. When omitted, VRF worker uses defaults.\n ttlMs?: number;\n remainingUses?: number;\n // Optional credential for PRF.second extraction (registration or authentication)\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n }): Promise<{ sessionId: string; wrapKeySalt: string }> {\n return mintSessionKeysAndSendToSigner(this.getHandlerContext(), args);\n }\n\n /**\n * Dispense an existing VRF-owned session key (WrapKeySeed + wrapKeySalt) over the\n * attached MessagePort for `sessionId`, enforcing TTL/usage in the VRF worker.\n *\n * This is the primitive needed for \"warm\" signing sessions: 1 VRF worker → N one-shot signer workers.\n */\n async dispenseSessionKey(args: {\n sessionId: string;\n uses?: number;\n }): Promise<{\n sessionId: string;\n remainingUses?: number;\n expiresAtMs?: number;\n }> {\n return dispenseSessionKey(this.getHandlerContext(), args);\n }\n\n /**\n * Query VRF-owned signing session status for UI introspection.\n * This does not prompt and does not reveal secrets; it only returns metadata.\n */\n async checkSessionStatus(args: {\n sessionId: string;\n }): Promise<{\n sessionId: string;\n status: 'active' | 'exhausted' | 'expired' | 'not_found';\n remainingUses?: number;\n expiresAtMs?: number;\n createdAtMs?: number;\n }> {\n return checkSessionStatus(this.getHandlerContext(), args);\n }\n\n /**\n * Clear VRF-owned signing session material for a given `sessionId`.\n * Intended for explicit \"Lock\" actions or lifecycle cleanup.\n */\n async clearSession(args: {\n sessionId: string;\n }): Promise<{\n sessionId: string;\n clearedSession: boolean;\n clearedChallenge: boolean;\n clearedPort: boolean;\n }> {\n return clearSession(this.getHandlerContext(), args);\n }\n\n /**\n * VRF-driven decrypt session for export flows.\n * Kicks off a LocalOnly DECRYPT_PRIVATE_KEY_WITH_PRF confirm via VRF Rust and derives\n * WrapKeySeed using the vault-provided wrapKeySalt. WrapKeySeed + wrapKeySalt are sent to the signer over\n * the dedicated MessagePort for the given sessionId.\n */\n async prepareDecryptSession(args: {\n sessionId: string;\n nearAccountId: AccountId;\n wrapKeySalt: string;\n encryptedVrfKeypair?: EncryptedVRFKeypair;\n expectedVrfPublicKey?: string;\n }): Promise<void> {\n return prepareDecryptSession(this.getHandlerContext(), args);\n }\n\n /**\n * VRF-driven confirmation + WrapKeySeed derivation for signing flows.\n * Runs confirmTxFlow on the main thread, derives WrapKeySeed in the VRF worker, and returns\n * the session metadata needed by the signer worker. WrapKeySeed itself travels only over the\n * reserved MessagePort registered via registerSignerWrapKeySeedPort.\n */\n async confirmAndPrepareSigningSession(params: {\n ctx: VrfWorkerManagerContext;\n sessionId: string;\n signingAuthMode?: SigningAuthMode;\n sessionPolicyDigest32?: string;\n kind: 'transaction';\n txSigningRequests: TransactionInputWasm[];\n rpcCall: RpcCallPayload;\n title?: string;\n body?: string;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n } | {\n ctx: VrfWorkerManagerContext;\n sessionId: string;\n signingAuthMode?: SigningAuthMode;\n sessionPolicyDigest32?: string;\n kind: 'delegate';\n nearAccountId: string;\n title?: string;\n body?: string;\n delegate: {\n senderId: string;\n receiverId: string;\n actions: TransactionInputWasm['actions'];\n nonce: string | number | bigint;\n maxBlockHeight: string | number | bigint;\n };\n rpcCall: RpcCallPayload;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n } | {\n ctx: VrfWorkerManagerContext;\n sessionId: string;\n signingAuthMode?: SigningAuthMode;\n sessionPolicyDigest32?: string;\n kind: 'nep413';\n nearAccountId: string;\n message: string;\n recipient: string;\n title?: string;\n body?: string;\n contractId?: string;\n nearRpcUrl?: string;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n }): Promise<{\n sessionId: string;\n transactionContext: TransactionContext;\n intentDigest: string;\n credential?: SerializableCredential;\n vrfChallenge?: VRFChallenge;\n }> {\n return confirmAndPrepareSigningSession(this.getHandlerContext(), params);\n }\n\n /**\n * VRF-driven helper for registration confirmation.\n * Runs confirmTxFlow on the main thread and returns registration artifacts.\n * WrapKeySeed derivation is handled later when we call into signing/derivation\n * flows with PRF + withSigningSession.\n */\n async requestRegistrationCredentialConfirmation(params: {\n nearAccountId: string;\n deviceNumber: number;\n confirmerText?: { title?: string; body?: string };\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n contractId: string;\n nearRpcUrl: string;\n }): Promise<RegistrationCredentialConfirmationPayload> {\n return requestRegistrationCredentialConfirmation(this.getHandlerContext(), params);\n }\n\n /**\n * Combined Device2 registration session: single WebAuthn ceremony for credential + WrapKeySeed derivation.\n *\n * This method orchestrates the complete Device2 registration flow:\n * 1. Runs a VRF-driven registration confirmation (single TouchID prompt)\n * 2. Extracts PRF.first from the credential and derives WrapKeySeed\n * 3. Sends WrapKeySeed to signer worker via MessagePort (never exposed to JS)\n * 4. Returns credential (with PRF.second embedded), vrfChallenge, transactionContext, wrapKeySalt\n *\n * The signer worker can then use PRF.second for NEAR key derivation and WrapKeySeed for encryption.\n */\n async confirmAndDeriveDevice2RegistrationSession(params: {\n sessionId: string;\n nearAccountId: AccountId;\n deviceNumber: number;\n contractId: string;\n nearRpcUrl: string;\n authenticatorOptions?: object;\n wrapKeySalt?: string;\n }): Promise<{\n confirmed: boolean;\n sessionId: string;\n credential: WebAuthnRegistrationCredential;\n vrfChallenge: VRFChallenge;\n transactionContext: TransactionContext;\n wrapKeySalt: string;\n requestId: string;\n intentDigest: string;\n deterministicVrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n error?: string;\n }> {\n return confirmAndDeriveDevice2RegistrationSession(this.getHandlerContext(), params);\n }\n\n setWorkerBaseOrigin(origin: string | undefined): void {\n this.workerBaseOrigin = origin;\n }\n\n /**\n * Ensure VRF worker is ready for operations\n * @param requireHealthCheck - Whether to perform health check after initialization\n */\n private async ensureWorkerReady(requireHealthCheck = false): Promise<void> {\n if (this.initializationPromise) {\n await this.initializationPromise;\n } else if (!this.vrfWorker) {\n await this.initialize();\n }\n if (!this.vrfWorker) {\n throw new Error('VRF Worker failed to initialize');\n }\n // Optional health check for critical operations\n if (requireHealthCheck) {\n try {\n const healthResponse = await this.sendMessage({\n type: 'PING',\n id: this.generateMessageId(),\n payload: {} as WasmVrfWorkerRequestType\n }, 3000);\n\n if (!healthResponse.success) {\n throw new Error('VRF Worker failed health check');\n }\n } catch (error) {\n console.error('VRF Manager: Health check failed:', error);\n throw new Error('VRF Worker failed health check');\n }\n }\n }\n\n /**\n * Initialize VRF functionality using Web Workers\n */\n async initialize(): Promise<void> {\n if (this.initializationPromise) {\n return this.initializationPromise;\n }\n // =============================================================\n // This improved error handling ensures that:\n // 1. Initialization failures are properly logged with full details\n // 2. Errors are re-thrown to callers (no silent swallowing)\n // 3. Failed initialization promise is reset for retry\n // 4. Debug logs actually appear in test output\n this.initializationPromise = this.createVrfWorker().catch(error => {\n console.error('VRF Manager: Initialization failed:', error);\n console.error('VRF Manager: Error details:', {\n message: error.message,\n stack: error.stack,\n name: error.name\n });\n // Reset promise so initialization can be retried\n this.initializationPromise = null;\n throw error; // Re-throw so callers know it failed\n });\n\n const result = await this.initializationPromise;\n return result;\n }\n\n /**\n * Initialize Web Worker with client-hosted VRF worker\n */\n private async createVrfWorker(): Promise<void> {\n try {\n const relativePath = this.config.vrfWorkerUrl || BUILD_PATHS.RUNTIME.VRF_WORKER;\n const vrfUrlStr = resolveWorkerUrl(relativePath, { worker: 'vrf', baseOrigin: this.workerBaseOrigin })\n console.debug('VRF Manager: Worker URL:', vrfUrlStr);\n // Create Web Worker from resolved URL\n this.vrfWorker = new Worker(vrfUrlStr, {\n type: 'module',\n name: 'Web3AuthnVRFWorker'\n });\n // Set up error handling\n this.vrfWorker.onerror = (error) => {\n console.error('VRF Manager: Web Worker error:', error);\n };\n // Test communication with the Web Worker\n await this.testWebWorkerCommunication();\n\n // Configure Shamir P if provided\n if (this.config.shamirPB64u) {\n const resp = await this.sendMessage<WasmShamir3PassConfigPRequest>({\n type: 'SHAMIR3PASS_CONFIG_P',\n id: this.generateMessageId(),\n payload: { p_b64u: this.config.shamirPB64u }\n });\n if (!resp.success) {\n throw new Error(`Failed to configure Shamir P: ${resp.error}`);\n }\n }\n\n // Configure relay server URLs if provided\n if (this.config.relayServerUrl && this.config.applyServerLockRoute && this.config.removeServerLockRoute) {\n const resp2 = await this.sendMessage<WasmShamir3PassConfigServerUrlsRequest>({\n type: 'SHAMIR3PASS_CONFIG_SERVER_URLS',\n id: this.generateMessageId(),\n payload: {\n relayServerUrl: this.config.relayServerUrl,\n applyLockRoute: this.config.applyServerLockRoute,\n removeLockRoute: this.config.removeServerLockRoute,\n }\n });\n if (!resp2.success) {\n throw new Error(`Failed to configure Shamir server URLs: ${resp2.error}`);\n }\n }\n\n } catch (error: any) {\n throw new Error(`VRF Web Worker initialization failed: ${error.message}`);\n }\n }\n\n /**\n * Send message to Web Worker and wait for response\n */\n private async sendMessage<T extends WasmVrfWorkerRequestType>(\n message: VRFWorkerMessage<T>,\n customTimeout?: number\n ): Promise<VRFWorkerResponse> {\n return new Promise((resolve, reject) => {\n if (!this.vrfWorker) {\n reject(new Error('VRF Web Worker not available'));\n return;\n }\n\n const timeoutMs = (customTimeout ?? this.config.workerTimeout ?? 60_000);\n const timeout = setTimeout(() => {\n reject(new Error(`VRF Web Worker communication timeout (${timeoutMs}ms) for message type: ${message.type}`));\n }, timeoutMs);\n\n const handleMessage = (event: MessageEvent) => {\n const payload = event.data as VRFWorkerResponse | {\n type?: unknown;\n data?: unknown;\n };\n\n // Intercept SecureConfirm handshake messages from the VRF worker and\n // dispatch them through confirmTxFlow on the main thread. The decision\n // is sent back to the worker as USER_PASSKEY_CONFIRM_RESPONSE and\n // consumed by awaitSecureConfirmationV2; this should not resolve the\n // original VRF request promise.\n if ((payload as any)?.type === SecureConfirmMessageType.PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD) {\n const env = payload as {\n type: SecureConfirmMessageType.PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD;\n data: SecureConfirmRequest;\n };\n const ctx = this.getContext();\n if (!this.vrfWorker) {\n console.error('[VRF] SecureConfirm: vrfWorker missing for PROMPT_USER_CONFIRM_IN_JS_MAIN_THREAD');\n return;\n }\n void handlePromptUserConfirmInJsMainThread(ctx, env, this.vrfWorker);\n return;\n }\n\n const response = payload as VRFWorkerResponse;\n if (response.id === message.id) {\n clearTimeout(timeout);\n this.vrfWorker!.removeEventListener('message', handleMessage);\n resolve(response);\n }\n };\n\n this.vrfWorker.addEventListener('message', handleMessage);\n this.vrfWorker.postMessage(message);\n });\n }\n\n /**\n * Generate unique message ID\n */\n private generateMessageId(): string {\n return `vrf_${Date.now()}_${++this.messageId}`;\n }\n\n /**\n * Unlock VRF keypair in Web Worker memory using PRF output\n * This is called during login to decrypt and load the VRF keypair in-memory\n */\n async unlockVrfKeypair(args: {\n credential: WebAuthnAuthenticationCredential | WebAuthnRegistrationCredential;\n nearAccountId: AccountId;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n onEvent?: (event: { type: string; data: { step: string; message: string } }) => void;\n }): Promise<VRFWorkerResponse> {\n return unlockVrfKeypair(this.getHandlerContext(), args);\n }\n\n async generateVrfChallengeForSession(inputData: VRFInputData, sessionId: string): Promise<VRFChallenge> {\n return generateVrfChallengeForSession(this.getHandlerContext(), inputData, sessionId);\n }\n\n async generateVrfChallengeOnce(inputData: VRFInputData): Promise<VRFChallenge> {\n return generateVrfChallengeOnce(this.getHandlerContext(), inputData);\n }\n\n /**\n * Get current VRF session status\n */\n async checkVrfStatus(): Promise<VRFWorkerStatus> {\n return checkVrfStatus(this.getHandlerContext());\n }\n\n /**\n * Logout and clear VRF session\n */\n async clearVrfSession(): Promise<void> {\n return clearVrfSession(this.getHandlerContext());\n }\n\n /**\n * Set the current VRF account ID at the TypeScript level\n * Used after VRF keypair is loaded in WASM memory (e.g., after deriveVrfKeypairFromPrf)\n * to track which account has an active VRF session\n */\n setCurrentVrfAccountId(nearAccountId: AccountId): void {\n this.currentVrfAccountId = nearAccountId;\n console.debug(`VRF Manager: Current VRF account ID set to ${nearAccountId}`);\n }\n\n /**\n * Generate VRF keypair for bootstrapping - stores in memory unencrypted temporarily\n * This is used during registration to generate a VRF keypair that will be used for\n * WebAuthn ceremony and later encrypted with the real PRF output\n *\n * @param saveInMemory - Always true for bootstrap (VRF keypair stored in memory)\n * @param vrfInputParams - Optional parameters to generate VRF challenge/proof in same call\n * @returns VRF public key and optionally VRF challenge data\n */\n async generateVrfKeypairBootstrap(args: {\n vrfInputData: VRFInputData;\n saveInMemory: boolean;\n sessionId?: string;\n }): Promise<{\n vrfPublicKey: string;\n vrfChallenge: VRFChallenge;\n }> {\n return generateVrfKeypairBootstrap(this.getHandlerContext(), args);\n }\n\n /**\n * Derive deterministic VRF keypair from PRF output embedded in a WebAuthn credential.\n * Optionally generates VRF challenge if input parameters are provided\n * This enables deterministic VRF key derivation without needing stored VRF keypairs\n *\n * @param credential - WebAuthn credential containing PRF outputs\n * @param nearAccountId - NEAR account ID for key derivation salt\n * @param vrfInputParams - Optional VRF input parameters for challenge generation\n * @returns Deterministic VRF public key, optional VRF challenge, and encrypted VRF keypair for storage\n */\n async deriveVrfKeypairFromPrf(args: {\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n nearAccountId: AccountId;\n vrfInputData?: VRFInputData; // optional, for challenge generation\n saveInMemory?: boolean; // optional, whether to save in worker memory\n }): Promise<{\n vrfPublicKey: string;\n vrfChallenge: VRFChallenge | null;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n serverEncryptedVrfKeypair: ServerEncryptedVrfKeypair | null;\n }> {\n return deriveVrfKeypairFromPrf(this.getHandlerContext(), args);\n }\n\n /**\n * This securely decrypts the shamir3Pass encrypted VRF keypair and loads it into memory\n * It performs Shamir-3-Pass commutative decryption within WASM worker with the relay-server\n */\n async shamir3PassDecryptVrfKeypair(args: {\n nearAccountId: AccountId;\n kek_s_b64u: string;\n ciphertextVrfB64u: string;\n serverKeyId: string;\n }): Promise<VRFWorkerResponse> {\n return shamir3PassDecryptVrfKeypair(this.getHandlerContext(), args);\n }\n\n /**\n * Shamir 3-pass: encrypt the currently unlocked VRF keypair under the server key\n * Returns a fresh serverEncryptedVrfKeypair blob for IndexedDB.\n * Requires: current VRF keypair is unlocked and present in worker memory.\n */\n async shamir3PassEncryptCurrentVrfKeypair(): Promise<{\n ciphertextVrfB64u: string;\n kek_s_b64u: string;\n serverKeyId: string;\n }> {\n return shamir3PassEncryptCurrentVrfKeypair(this.getHandlerContext());\n }\n\n /**\n * Test Web Worker communication\n */\n private async testWebWorkerCommunication(): Promise<void> {\n try {\n const timeoutMs = 2000;\n const pingResponse = await this.sendMessage({\n type: 'PING',\n id: this.generateMessageId(),\n payload: {} as WasmVrfWorkerRequestType\n }, timeoutMs);\n if (!pingResponse.success) {\n throw new Error(`VRF Web Worker PING failed: ${pingResponse.error}`);\n }\n return;\n } catch (error: any) {\n console.warn(`️VRF Manager: testWebWorkerCommunication failed:`, error.message);\n }\n }\n}\n","import {\n ConfirmationConfig,\n DEFAULT_CONFIRMATION_CONFIG,\n type SignerMode,\n DEFAULT_SIGNING_MODE,\n coerceSignerMode,\n mergeSignerMode,\n} from '../types/signer-worker';\nimport type { AccountId } from '../types/accountIds';\nimport { IndexedDBManager, type IndexedDBEvent } from '../IndexedDBManager';\n\n\nexport class UserPreferencesManager {\n\n private themeChangeListeners: Set<(theme: 'dark' | 'light') => void> = new Set();\n private confirmationConfigChangeListeners: Set<(config: ConfirmationConfig) => void> = new Set();\n private signerModeChangeListeners: Set<(mode: SignerMode) => void> = new Set();\n\n private currentUserAccountId: AccountId | undefined;\n private confirmationConfig: ConfirmationConfig = DEFAULT_CONFIRMATION_CONFIG;\n private signerMode: SignerMode = DEFAULT_SIGNING_MODE;\n\n // Optional app-provided default theme (e.g., configs.walletTheme). This is NOT a per-user preference.\n private walletThemeOverride: 'dark' | 'light' | null = null;\n // Optional app-provided default signer mode (e.g., configs.signerMode). This is NOT a per-user preference.\n private signerModeOverride: SignerMode | null = null;\n // Wallet-iframe app-origin: delegate signerMode persistence to the wallet host.\n private walletIframeSignerModeWriter: ((signerMode: SignerMode) => Promise<void>) | null = null;\n // Prevent multiple one-time environment syncs per session\n private envThemeSyncedForSession = false;\n\n constructor() {\n // Subscribe to IndexedDB change events for automatic sync\n this.subscribeToIndexedDBChanges();\n }\n\n /**\n * Apply an app-provided default theme (e.g., `configs.walletTheme`) without\n * persisting it as a per-user preference in IndexedDB.\n *\n * This also disables the one-time environment theme sync so host appearance\n * (e.g., VitePress `html.dark`) cannot override an explicit config.\n */\n configureWalletTheme(theme?: 'dark' | 'light'): void {\n if (theme !== 'dark' && theme !== 'light') return;\n this.walletThemeOverride = theme;\n // If integrator explicitly configured a theme, do not auto-sync from environment.\n this.envThemeSyncedForSession = true;\n if (this.confirmationConfig.theme !== theme) {\n this.confirmationConfig = {\n ...this.confirmationConfig,\n theme,\n };\n this.notifyConfirmationConfigChange(this.confirmationConfig);\n this.notifyThemeChange(theme);\n }\n }\n\n /**\n * Apply an app-provided default signer mode (e.g., `configs.signerMode`) without\n * persisting it as a per-user preference in IndexedDB.\n */\n configureDefaultSignerMode(signerMode?: SignerMode | SignerMode['mode'] | null): void {\n const next = coerceSignerMode(signerMode, DEFAULT_SIGNING_MODE);\n this.signerModeOverride = next;\n // When no user is active, keep in-memory default aligned to config.\n if (!this.currentUserAccountId) {\n this.setSignerModeInternal(next, { persist: false, notify: true });\n }\n }\n\n /**\n * In wallet-iframe mode on the app origin, user preferences must be persisted by the wallet host\n * (not the app origin). This configures a best-effort writer used by `setSignerMode(...)` when\n * IndexedDB is disabled.\n */\n configureWalletIframeSignerModeWriter(writer: ((signerMode: SignerMode) => Promise<void>) | null): void {\n this.walletIframeSignerModeWriter = writer;\n }\n\n /**\n * Register a callback for theme change events\n */\n onThemeChange(callback: (theme: 'dark' | 'light') => void): () => void {\n this.themeChangeListeners.add(callback);\n return () => {\n this.themeChangeListeners.delete(callback);\n };\n }\n\n /**\n * Register a callback for confirmation config changes.\n * Used to keep app UI in sync with the wallet host in wallet-iframe mode.\n */\n onConfirmationConfigChange(callback: (config: ConfirmationConfig) => void): () => void {\n this.confirmationConfigChangeListeners.add(callback);\n return () => {\n this.confirmationConfigChangeListeners.delete(callback);\n };\n }\n\n /**\n * Register a callback for signer mode changes.\n */\n onSignerModeChange(callback: (mode: SignerMode) => void): () => void {\n this.signerModeChangeListeners.add(callback);\n return () => {\n this.signerModeChangeListeners.delete(callback);\n };\n }\n\n /**\n * Notify all registered listeners of theme changes\n */\n private notifyThemeChange(theme: 'dark' | 'light'): void {\n if (this.themeChangeListeners.size === 0) {\n // In many environments (e.g., wallet iframe host), there may be no UI subscribers.\n // Use debug to avoid noisy warnings while still being helpful during development.\n console.debug(`[UserPreferencesManager]: No listeners registered, theme change will not propagate.`);\n return;\n }\n\n for (const listener of this.themeChangeListeners) {\n listener(theme);\n }\n }\n\n private notifyConfirmationConfigChange(config: ConfirmationConfig): void {\n if (this.confirmationConfigChangeListeners.size === 0) return;\n for (const listener of this.confirmationConfigChangeListeners) {\n listener(config);\n }\n }\n\n private notifySignerModeChange(mode: SignerMode): void {\n if (this.signerModeChangeListeners.size === 0) return;\n for (const listener of this.signerModeChangeListeners) {\n listener(mode);\n }\n }\n\n /**\n * Best-effort async initialization from IndexedDB.\n *\n * Callers decide when to invoke this so environments that must avoid\n * app-origin IndexedDB (wallet-iframe mode) can skip it entirely.\n */\n async initFromIndexedDB(): Promise<void> {\n await this.loadUserSettings().catch((error) => {\n console.warn('[WebAuthnManager]: Failed to initialize user settings:', error);\n });\n }\n\n /**\n * Subscribe to IndexedDB change events for automatic synchronization\n */\n private subscribeToIndexedDBChanges(): void {\n // Subscribe to IndexedDB change events\n this.unsubscribeFromIndexedDB = IndexedDBManager.clientDB.onChange((event) => {\n void this.handleIndexedDBEvent(event).catch((error) => {\n console.warn('[WebAuthnManager]: Error handling IndexedDB event:', error);\n });\n });\n }\n\n /**\n * Handle IndexedDB change events.\n * @param event - The IndexedDBEvent: `user-updated`, `preferences-updated`, `user-deleted` to handle.\n */\n private async handleIndexedDBEvent(event: IndexedDBEvent): Promise<void> {\n switch (event.type) {\n case 'preferences-updated':\n // Check if this affects the current user\n if (event.accountId === this.currentUserAccountId) {\n await this.reloadUserSettings();\n }\n break;\n\n case 'user-updated':\n // Check if this affects the current user\n if (event.accountId === this.currentUserAccountId) {\n await this.reloadUserSettings();\n }\n break;\n\n case 'user-deleted':\n // Check if the deleted user was the current user\n if (event.accountId === this.currentUserAccountId) {\n this.currentUserAccountId = undefined;\n this.confirmationConfig = DEFAULT_CONFIRMATION_CONFIG;\n }\n break;\n }\n }\n\n /**\n * Unsubscribe function for IndexedDB events\n */\n private unsubscribeFromIndexedDB?: () => void;\n\n /**\n * Clean up resources and unsubscribe from events\n */\n destroy(): void {\n if (this.unsubscribeFromIndexedDB) {\n this.unsubscribeFromIndexedDB();\n this.unsubscribeFromIndexedDB = undefined;\n }\n this.walletIframeSignerModeWriter = null;\n // Clear all theme change listeners\n this.themeChangeListeners.clear();\n this.confirmationConfigChangeListeners.clear();\n this.signerModeChangeListeners.clear();\n }\n\n getCurrentUserAccountId(): AccountId {\n if (!this.currentUserAccountId) {\n console.debug('[UserPreferencesManager]: getCurrentUserAccountId called with no current user; returning empty id');\n // Return an empty string to keep callers defensive; most consumers\n // already treat falsy accountIds as \"no-op\"/logged‑out.\n return '' as AccountId;\n }\n return this.currentUserAccountId;\n }\n\n getConfirmationConfig(): ConfirmationConfig {\n return this.confirmationConfig;\n }\n\n getSignerMode(): SignerMode {\n return this.signerMode;\n }\n\n /**\n * Apply an authoritative confirmation config snapshot from the wallet-iframe host.\n * This updates in-memory state only; persistence remains owned by the wallet origin.\n */\n applyWalletHostConfirmationConfig(args: {\n nearAccountId?: AccountId | null;\n confirmationConfig: ConfirmationConfig;\n }): void {\n const { nearAccountId, confirmationConfig } = args || ({} as any);\n const prevTheme = this.confirmationConfig.theme;\n const next: ConfirmationConfig = {\n ...DEFAULT_CONFIRMATION_CONFIG,\n ...(confirmationConfig || {}),\n } as ConfirmationConfig;\n\n if (nearAccountId) {\n this.currentUserAccountId = nearAccountId;\n }\n\n // Prevent environment heuristics on the app origin from overriding wallet-host state.\n this.envThemeSyncedForSession = true;\n\n this.confirmationConfig = next;\n this.notifyConfirmationConfigChange(this.confirmationConfig);\n if (this.confirmationConfig.theme !== prevTheme) {\n this.notifyThemeChange(this.confirmationConfig.theme);\n }\n }\n\n /**\n * Apply an authoritative signer mode snapshot from the wallet-iframe host.\n * This updates in-memory state only; persistence remains owned by the wallet origin.\n */\n applyWalletHostSignerMode(args: {\n nearAccountId?: AccountId | null;\n signerMode: SignerMode;\n }): void {\n const { nearAccountId, signerMode } = args || ({} as any);\n if (nearAccountId) {\n this.currentUserAccountId = nearAccountId;\n }\n const base = this.signerModeOverride ?? DEFAULT_SIGNING_MODE;\n const next = coerceSignerMode(signerMode, base);\n this.setSignerModeInternal(next, { persist: false, notify: true });\n }\n\n setCurrentUser(nearAccountId: AccountId): void {\n this.currentUserAccountId = nearAccountId;\n // Load settings for the new user (best-effort). In wallet-iframe mode on the app origin,\n // IndexedDB is intentionally disabled to avoid creating any tables.\n if (!IndexedDBManager.clientDB.isDisabled()) {\n void this.loadSettingsForUser(nearAccountId).catch(() => undefined);\n }\n\n // One-time: align user theme to current host appearance (e.g., VitePress html.dark)\n // In wallet-iframe mode (app origin), the wallet host owns preferences; do not override.\n if (!IndexedDBManager.clientDB.isDisabled() && !this.envThemeSyncedForSession && !this.walletThemeOverride) {\n let envTheme: 'dark' | 'light' | null = null;\n const isDark = (globalThis as any)?.document?.documentElement?.classList?.contains?.('dark');\n if (typeof isDark === 'boolean') envTheme = isDark ? 'dark' : 'light';\n if (!envTheme) {\n try {\n const stored = (globalThis as any)?.localStorage?.getItem?.('vitepress-theme-appearance');\n if (stored === 'dark' || stored === 'light') envTheme = stored;\n } catch {\n // Storage may be blocked by the environment (e.g., third-party iframes)\n }\n }\n if (envTheme && envTheme !== this.confirmationConfig.theme) {\n // Fire-and-forget; listeners will propagate the change\n void this.setUserTheme(envTheme);\n }\n this.envThemeSyncedForSession = true;\n }\n }\n\n /**\n * Load settings for a specific user\n */\n private async loadSettingsForUser(nearAccountId: AccountId): Promise<void> {\n if (IndexedDBManager.clientDB.isDisabled()) return;\n const user = await IndexedDBManager.clientDB.getLastUser().catch(() => null);\n if (!user || user.nearAccountId !== nearAccountId) return;\n if (user?.preferences?.confirmationConfig) {\n const prevTheme = this.confirmationConfig.theme;\n this.confirmationConfig = {\n ...this.confirmationConfig,\n ...user.preferences.confirmationConfig\n };\n this.notifyConfirmationConfigChange(this.confirmationConfig);\n if (this.confirmationConfig.theme !== prevTheme) {\n this.notifyThemeChange(this.confirmationConfig.theme);\n }\n }\n\n // Signer mode: stored per-user preference (optional).\n const base = this.signerModeOverride ?? DEFAULT_SIGNING_MODE;\n const stored = user?.preferences?.signerMode as SignerMode | SignerMode['mode'] | null | undefined;\n const nextSignerMode = stored != null ? coerceSignerMode(stored, base) : base;\n this.setSignerModeInternal(nextSignerMode, { persist: false, notify: true });\n }\n\n /**\n * Reload current user settings from IndexedDB\n */\n async reloadUserSettings(): Promise<void> {\n await this.loadSettingsForUser(this.getCurrentUserAccountId());\n }\n\n /**\n * Set confirmation behavior\n */\n setConfirmBehavior(behavior: 'requireClick' | 'autoProceed'): void {\n this.confirmationConfig = {\n ...this.confirmationConfig,\n behavior\n };\n this.notifyConfirmationConfigChange(this.confirmationConfig);\n this.saveUserSettings();\n }\n\n /**\n * Set confirmation configuration\n */\n setConfirmationConfig(config: ConfirmationConfig): void {\n const prevTheme = this.confirmationConfig.theme;\n this.confirmationConfig = {\n ...this.confirmationConfig,\n ...config\n };\n this.notifyConfirmationConfigChange(this.confirmationConfig);\n if (this.confirmationConfig.theme !== prevTheme) {\n this.notifyThemeChange(this.confirmationConfig.theme);\n }\n this.saveUserSettings();\n }\n\n /**\n * Load user confirmation settings from IndexedDB\n */\n async loadUserSettings(): Promise<void> {\n if (IndexedDBManager.clientDB.isDisabled()) return;\n const user = await IndexedDBManager.clientDB.getLastUser().catch(() => null);\n if (user) {\n const prevTheme = this.confirmationConfig.theme;\n this.currentUserAccountId = user.nearAccountId;\n // Load user's confirmation config if it exists, otherwise keep existing settings/defaults\n if (user.preferences?.confirmationConfig) {\n this.confirmationConfig = {\n ...this.confirmationConfig,\n ...user.preferences.confirmationConfig\n };\n this.notifyConfirmationConfigChange(this.confirmationConfig);\n if (this.confirmationConfig.theme !== prevTheme) {\n this.notifyThemeChange(this.confirmationConfig.theme);\n }\n } else {\n console.debug('[WebAuthnManager]: No user preferences found, using defaults');\n }\n\n // Load signer mode preference if available; otherwise use app default (configs.signerMode).\n const base = this.signerModeOverride ?? DEFAULT_SIGNING_MODE;\n const stored = user?.preferences?.signerMode as SignerMode | SignerMode['mode'] | null | undefined;\n const nextSignerMode = stored != null ? coerceSignerMode(stored, base) : base;\n this.setSignerModeInternal(nextSignerMode, { persist: false, notify: true });\n } else {\n console.debug('[WebAuthnManager]: No last user found, using default settings');\n }\n }\n\n /**\n * Save current confirmation settings to IndexedDB\n */\n async saveUserSettings(): Promise<void> {\n try {\n let accountId: AccountId | undefined = this.currentUserAccountId ?? undefined;\n if (!accountId) {\n const last = await IndexedDBManager.clientDB.getLastUser().catch(() => undefined as any);\n accountId = (last as any)?.nearAccountId;\n }\n\n if (!accountId) {\n console.warn('[UserPreferences]: No current user set; keeping confirmation config in memory only');\n return;\n }\n\n // Save confirmation config (which includes theme)\n await IndexedDBManager.clientDB.updatePreferences(accountId, {\n confirmationConfig: this.confirmationConfig,\n });\n } catch (error) {\n console.warn('[WebAuthnManager]: Failed to save user settings:', error);\n }\n }\n\n /**\n * Get user theme preference from IndexedDB\n */\n async getCurrentUserAccountIdTheme(): Promise<'dark' | 'light' | null> {\n const id = this.currentUserAccountId;\n if (!id) return null;\n try {\n return await IndexedDBManager.clientDB.getTheme(id);\n } catch (error) {\n console.debug('[WebAuthnManager]: getCurrentUserAccountIdTheme:', error);\n return null;\n }\n }\n\n getUserTheme(): 'dark' | 'light' {\n return this.confirmationConfig.theme;\n }\n\n /**\n * Set user theme preference in IndexedDB\n */\n async setUserTheme(theme: 'dark' | 'light'): Promise<void> {\n const id = this.currentUserAccountId;\n if (!id) return; // No-op when no user is set (logged-out state)\n // Always update local UI state immediately; persistence is best-effort.\n this.confirmationConfig = {\n ...this.confirmationConfig,\n theme\n };\n // Notify all listeners of theme change\n this.notifyConfirmationConfigChange(this.confirmationConfig);\n this.notifyThemeChange(theme);\n try {\n await IndexedDBManager.clientDB.setTheme(id, theme);\n } catch (error) {\n console.warn('[UserPreferencesManager]: Failed to save user theme:', error);\n }\n }\n\n /**\n * Set signer mode preference (in-memory immediately; IndexedDB persistence is best-effort).\n */\n setSignerMode(signerMode: SignerMode | SignerMode['mode']): void {\n const next = mergeSignerMode(this.signerMode, signerMode);\n // In wallet-iframe mode on the app origin, persistence is owned by the wallet host.\n // Forward to the host and rely on PREFERENCES_CHANGED mirroring for local state updates.\n if (this.walletIframeSignerModeWriter && IndexedDBManager.clientDB.isDisabled()) {\n void this.walletIframeSignerModeWriter(next).catch(() => undefined);\n return;\n }\n this.setSignerModeInternal(next, { persist: true, notify: true });\n }\n\n private isSignerModeEqual(a: SignerMode, b: SignerMode): boolean {\n if (a.mode !== b.mode) return false;\n if (a.mode !== 'threshold-signer' || b.mode !== 'threshold-signer') return true;\n return (a.behavior ?? null) === (b.behavior ?? null);\n }\n\n private setSignerModeInternal(next: SignerMode, opts: { persist: boolean; notify: boolean }): void {\n const prev = this.signerMode;\n this.signerMode = next;\n if (opts.notify && !this.isSignerModeEqual(prev, next)) {\n this.notifySignerModeChange(next);\n }\n if (opts.persist) {\n // Best-effort persistence: only write when we have a current user context.\n const id = this.currentUserAccountId;\n if (!id || IndexedDBManager.clientDB.isDisabled()) return;\n void IndexedDBManager.clientDB.setSignerMode(id, next).catch(() => undefined);\n }\n }\n}\n\n// Create and export singleton instance\nconst UserPreferencesInstance = new UserPreferencesManager();\nexport default UserPreferencesInstance;\n","import type { NearClient } from './NearClient';\nimport type { AccountId } from './types/accountIds';\nimport type { TransactionContext } from './types/rpc';\nimport type { AccessKeyView, BlockResult } from '@near-js/types';\nimport { isObject, isNumber, isString } from '@/utils/validation';\nimport { errorMessage } from '../utils/errors';\n\n/**\n * NonceManager - Singleton for managing NEAR transaction context\n *\n * This class pre-fetches nonce and block height asynchronously at the start\n * of executeAction calls to avoid blocking renderUserConfirmUI().\n *\n * The manager is cleared on logout and instantiated with new user on login.\n */\nexport class NonceManager {\n private static instance: NonceManager | null = null;\n\n public lastNonceUpdate: number | null = null;\n public lastBlockHeightUpdate: number | null = null;\n public nearAccountId: AccountId | null = null;\n public nearPublicKeyStr: string | null = null;\n public transactionContext: TransactionContext | null = null;\n private inflightFetch: Promise<TransactionContext> | null = null;\n // Monotonic identifier to disambiguate concurrent fetches and prevent stale commits/clears\n private inflightId: number = 0;\n private refreshTimer: ReturnType<typeof setTimeout> | null = null;\n private prefetchTimer: ReturnType<typeof setTimeout> | null = null;\n\n // Nonce reservation system for batch transactions\n private reservedNonces: Set<string> = new Set();\n private lastReservedNonce: string | null = null;\n\n // Freshness thresholds (ms)\n // Treat context older than 5s as stale enough to refetch\n private readonly NONCE_FRESHNESS_THRESHOLD = 5 * 1000; // 5 seconds\n private readonly BLOCK_FRESHNESS_THRESHOLD = 20 * 1000; // 20 seconds (less frequent block refreshes)\n private readonly PREFETCH_DEBOUNCE_MS = 400; // less aggressive prefetch debounce to reduce churn\n\n // Private constructor for singleton pattern\n private constructor() {}\n\n /**\n * Get singleton instance\n */\n public static getInstance(): NonceManager {\n if (!NonceManager.instance) {\n NonceManager.instance = new NonceManager();\n }\n return NonceManager.instance;\n }\n\n /**\n * Prefetch block height/hash (and nonce if missing) in the background.\n * - If block info is stale or context missing, triggers a non-blocking refresh.\n * - Safe to call frequently (coalesces concurrent fetches).\n */\n public async prefetchBlockheight(nearClient: NearClient): Promise<void> {\n if (!this.nearAccountId || !this.nearPublicKeyStr) return;\n // Debounce prefetch to avoid repeated calls on quick hover/focus toggles\n this.clearPrefetchTimer();\n this.prefetchTimer = setTimeout(async () => {\n this.prefetchTimer = null;\n if (this.inflightFetch) return; // already fetching\n\n const now = Date.now();\n const isBlockStale = !this.lastBlockHeightUpdate || (now - this.lastBlockHeightUpdate) >= this.BLOCK_FRESHNESS_THRESHOLD;\n const missingContext = !this.transactionContext;\n if (!isBlockStale && !missingContext) return;\n\n try {\n await this.fetchFreshData(nearClient);\n } catch (e) {\n // Swallow errors during prefetch; runtime path will retry as needed\n console.debug('[NonceManager]: prefetchBlockheight ignored error:', e);\n }\n }, this.PREFETCH_DEBOUNCE_MS);\n }\n\n /**\n * Initialize or update the manager with user information\n */\n public initializeUser(nearAccountId: AccountId, nearPublicKeyStr: string): void {\n this.nearAccountId = nearAccountId;\n this.nearPublicKeyStr = nearPublicKeyStr;\n this.clearTransactionContext();\n }\n\n /**\n * Clear all data when user logs out\n */\n public clear(): void {\n this.lastNonceUpdate = null;\n this.lastBlockHeightUpdate = null;\n this.nearAccountId = null;\n this.nearPublicKeyStr = null;\n this.transactionContext = null;\n this.clearRefreshTimer();\n this.clearPrefetchTimer();\n this.inflightFetch = null;\n this.reservedNonces.clear();\n this.lastReservedNonce = null;\n }\n\n /**\n * Smart caching method for nonce and block height data\n * Returns cached data if fresh, otherwise fetches synchronously\n */\n public async getNonceBlockHashAndHeight(nearClient: NearClient, opts?: { force?: boolean }): Promise<TransactionContext> {\n // Always prefer a fresh fetch for critical paths; coalesced by fetchFreshData.\n // This minimizes subtle cache bugs after key rotations/linking and across devices.\n if (!this.nearAccountId || !this.nearPublicKeyStr) {\n throw new Error('NonceManager not initialized with user data');\n }\n // Respect caller's intent to force or use freshness thresholds\n const force = opts?.force === true;\n return await this.fetchFreshData(nearClient, force);\n }\n\n /**\n * Schedule an asynchronous refresh of the transaction context\n */\n private maybeScheduleBackgroundRefresh(nearClient: NearClient): void {\n if (!this.lastNonceUpdate || !this.lastBlockHeightUpdate) return;\n if (this.inflightFetch) return; // already fetching\n\n const now = Date.now();\n const nonceAge = now - this.lastNonceUpdate;\n const blockAge = now - this.lastBlockHeightUpdate;\n\n const halfNonceTtl = this.NONCE_FRESHNESS_THRESHOLD / 2;\n const halfBlockTtl = this.BLOCK_FRESHNESS_THRESHOLD / 2;\n\n // If we're past the half-life for either value, refresh NOW in background\n if (nonceAge >= halfNonceTtl || blockAge >= halfBlockTtl) {\n this.clearRefreshTimer();\n // Fire-and-forget refresh to keep cache warm\n void this.fetchFreshData(nearClient)\n .catch((error) => console.warn('[NonceManager]: Background refresh failed:', error));\n return;\n }\n\n // Otherwise, schedule a refresh for when the earliest metric hits half-life\n const delayToHalfNonce = Math.max(0, halfNonceTtl - nonceAge);\n const delayToHalfBlock = Math.max(0, halfBlockTtl - blockAge);\n const delay = Math.min(delayToHalfNonce, delayToHalfBlock);\n\n // Avoid multiple timers\n this.clearRefreshTimer();\n this.refreshTimer = setTimeout(() => {\n this.refreshTimer = null;\n if (this.inflightFetch) return;\n void this.fetchFreshData(nearClient)\n .catch((error) => console.warn('[NonceManager]: Background refresh failed:', error));\n }, delay);\n }\n\n /**\n * Fetch fresh transaction context data from NEAR RPC\n */\n private async fetchFreshData(nearClient: NearClient, force: boolean = false): Promise<TransactionContext> {\n // Coalesce concurrent refreshes when not forced to reduce redundant network calls.\n // Force=true is used by latency-critical paths (e.g., JIT VRF refresh) to guarantee a fresh block height.\n if (this.inflightFetch && !force) {\n return this.inflightFetch;\n }\n\n const capturedAccountId = this.nearAccountId;\n const capturedPublicKey = this.nearPublicKeyStr;\n // Start a new fetch; assign a unique id to guard commit and cleanup\n const requestId = (++this.inflightId);\n const fetchPromise = (async () => {\n try {\n // Determine what is actually stale so we only fetch what we need\n const now = Date.now();\n const isNonceStale = force || !this.lastNonceUpdate || (now - this.lastNonceUpdate) >= this.NONCE_FRESHNESS_THRESHOLD;\n const isBlockStale = force || !this.lastBlockHeightUpdate || (now - this.lastBlockHeightUpdate) >= this.BLOCK_FRESHNESS_THRESHOLD;\n\n let accessKeyInfo = this.transactionContext?.accessKeyInfo;\n let txBlockHeight = this.transactionContext?.txBlockHeight;\n let txBlockHash = this.transactionContext?.txBlockHash;\n\n const fetchAccessKey = isNonceStale || !accessKeyInfo;\n const fetchBlock = isBlockStale || !txBlockHeight || !txBlockHash;\n\n // Fetch required parts with tolerance for missing access key just after creation\n let maybeAccessKey: unknown = accessKeyInfo ?? null;\n let maybeBlock: unknown = null;\n\n // Run RPC calls in parallel where applicable, while preserving tolerant error handling\n let accessKeyError: unknown = null;\n let blockError: unknown = null;\n const tasks: Promise<void>[] = [];\n\n if (fetchAccessKey) {\n tasks.push((async () => {\n try {\n maybeAccessKey = await nearClient.viewAccessKey(capturedAccountId!, capturedPublicKey!);\n } catch (akErr: unknown) {\n const msg = errorMessage(akErr);\n const missingAk = msg.includes('does not exist while viewing')\n || msg.includes('Access key not found')\n || msg.includes('unknown public key')\n || msg.includes('does not exist');\n if (missingAk) {\n // Non-fatal: proceed without live AK; compute nextNonce conservatively\n maybeAccessKey = null;\n } else {\n accessKeyError = akErr;\n }\n }\n })());\n }\n\n if (fetchBlock) {\n tasks.push((async () => {\n try {\n maybeBlock = await nearClient.viewBlock({ finality: 'final' });\n } catch (err: unknown) {\n // Block info is required\n blockError = err;\n }\n })());\n }\n\n if (tasks.length > 0) {\n await Promise.all(tasks);\n }\n\n if (accessKeyError) {\n throw accessKeyError;\n }\n if (blockError) {\n throw blockError;\n }\n\n // Commit results\n if (fetchAccessKey) {\n if (isAccessKeyView(maybeAccessKey)) {\n accessKeyInfo = maybeAccessKey;\n } else {\n // Keep previous accessKeyInfo if present; else set minimal placeholder\n accessKeyInfo = this.transactionContext?.accessKeyInfo || makePlaceholderAccessKey();\n }\n }\n\n if (fetchBlock) {\n if (!isBlockResult(maybeBlock)) {\n throw new Error('Failed to fetch Block Info');\n }\n txBlockHeight = String(maybeBlock.header.height);\n txBlockHash = maybeBlock.header.hash;\n }\n\n // Derive nextNonce from access key info + current context + reservations\n let nextCandidate = this.maxBigInt(\n accessKeyInfo?.nonce !== undefined ? (BigInt(accessKeyInfo.nonce) + 1n) : 0n,\n this.transactionContext?.nextNonce ? BigInt(this.transactionContext.nextNonce) : 0n,\n this.lastReservedNonce ? BigInt(this.lastReservedNonce) + 1n : 0n\n );\n if (nextCandidate <= 0n) nextCandidate = 1n; // never use 0\n const nextNonce = nextCandidate.toString();\n\n const transactionContext: TransactionContext = {\n nearPublicKeyStr: capturedPublicKey!,\n accessKeyInfo: accessKeyInfo!,\n nextNonce,\n txBlockHeight: txBlockHeight!,\n txBlockHash: txBlockHash!,\n };\n\n // Only commit if identity did not change AND this fetch is still the latest.\n // This guards against stale commits from races when a forced refresh overtakes a cached one.\n if (\n capturedAccountId === this.nearAccountId &&\n capturedPublicKey === this.nearPublicKeyStr &&\n requestId === this.inflightId\n ) {\n this.transactionContext = transactionContext;\n const now = Date.now();\n if (fetchAccessKey) this.lastNonceUpdate = now;\n if (fetchBlock) this.lastBlockHeightUpdate = now;\n } else {\n // Discard results from outdated or identity-mismatched fetches; a newer fetch has already committed.\n }\n\n return transactionContext;\n } catch (error) {\n console.error('[NonceManager]: Failed to fetch fresh transaction context:', error);\n throw error;\n } finally {\n // Only clear inflight if this promise is still the latest.\n if (requestId === this.inflightId) {\n this.inflightFetch = null;\n }\n }\n })();\n\n this.inflightFetch = fetchPromise;\n return fetchPromise;\n }\n\n /**\n * Get the current transaction context\n * Throws if data is not available or stale\n */\n public getTransactionContext(): TransactionContext {\n if (!this.transactionContext) {\n throw new Error('Transaction context not available - call getNonceBlockHashAndHeight() first');\n }\n\n // Check if data is stale (more than 30 seconds old)\n const now = Date.now();\n const maxAge = 30 * 1000; // 30 seconds\n\n if (this.lastNonceUpdate && (now - this.lastNonceUpdate) > maxAge) {\n console.warn('[NonceManager]: Transaction context is stale, consider refreshing');\n }\n\n return this.transactionContext;\n }\n\n /**\n * Check if transaction context is available and not stale\n */\n public isTransactionContextAvailable(maxAgeMs: number = 30000): boolean {\n if (!this.transactionContext || !this.lastNonceUpdate) {\n return false;\n }\n\n const now = Date.now();\n return (now - this.lastNonceUpdate) <= maxAgeMs;\n }\n\n /**\n * Clear transaction context (useful when nonce might be invalidated)\n */\n public clearTransactionContext(): void {\n this.transactionContext = null;\n this.lastNonceUpdate = null;\n this.lastBlockHeightUpdate = null;\n this.clearRefreshTimer();\n this.clearPrefetchTimer();\n this.inflightFetch = null;\n this.reservedNonces.clear();\n this.lastReservedNonce = null;\n }\n\n /**\n * Force a synchronous refresh of nonce + block context.\n * Useful after key rotations (e.g., link-device) or when encountering INVALID_NONCE.\n * Optionally clears any locally reserved nonces to avoid collisions.\n */\n public async refreshNow(nearClient: NearClient, opts?: { clearReservations?: boolean }): Promise<TransactionContext> {\n if (opts?.clearReservations) {\n try { this.releaseAllNonces(); } catch {}\n }\n return await this.fetchFreshData(nearClient, true);\n }\n\n /**\n * Reserve a nonce for batch transactions\n * This increments the nonce locally to prevent conflicts in batch operations\n * @param count - Number of nonces to reserve (default: 1)\n * @returns Array of reserved nonces\n */\n public reserveNonces(count: number = 1): string[] {\n if (!this.transactionContext) {\n throw new Error('Transaction context not available - call getNonceBlockHashAndHeight() first');\n }\n\n if (count <= 0) return [];\n\n const start = this.lastReservedNonce\n ? BigInt(this.lastReservedNonce) + 1n\n : BigInt(this.transactionContext.nextNonce);\n\n // Plan reservations first (pure), then commit atomically\n const planned: string[] = [];\n for (let i = 0; i < count; i++) {\n const candidate = (start + BigInt(i)).toString();\n if (this.reservedNonces.has(candidate)) {\n throw new Error(`Nonce ${candidate} is already reserved`);\n }\n planned.push(candidate);\n }\n\n // Commit: extend set and bump lastReservedNonce\n const newSet = new Set(this.reservedNonces);\n for (const n of planned) newSet.add(n);\n this.reservedNonces = newSet;\n this.lastReservedNonce = planned[planned.length - 1];\n\n return planned;\n }\n\n /**\n * Release a reserved nonce (call when transaction is completed or failed)\n * @param nonce - The nonce to release\n */\n public releaseNonce(nonce: string): void {\n if (this.reservedNonces.has(nonce)) {\n this.reservedNonces.delete(nonce);\n }\n }\n\n /**\n * Release all reserved nonces\n */\n public releaseAllNonces(): void {\n const count = this.reservedNonces.size;\n this.reservedNonces.clear();\n this.lastReservedNonce = null;\n }\n\n /**\n * Update nonce from blockchain after transaction completion\n * This should be called after a transaction is successfully broadcasted\n * @param nearClient - NEAR client for RPC calls\n * @param actualNonce - The actual nonce used in the completed transaction\n */\n public async updateNonceFromBlockchain(nearClient: NearClient, actualNonce: string): Promise<void> {\n if (!this.nearAccountId || !this.nearPublicKeyStr) {\n throw new Error('NonceManager not initialized with user data');\n }\n\n try {\n // Fetch fresh access key info to get the latest nonce\n const accessKeyInfo = await nearClient.viewAccessKey(this.nearAccountId, this.nearPublicKeyStr);\n\n if (!accessKeyInfo || accessKeyInfo.nonce === undefined) {\n throw new Error(`Access key not found or invalid for account ${this.nearAccountId}`);\n }\n\n const chainNonceBigInt = BigInt(accessKeyInfo.nonce);\n const actualNonceBigInt = BigInt(actualNonce);\n\n // Tolerate both pre- and post-final states:\n // - pre-final: chainNonce == actualNonce - 1\n // - post-final: chainNonce >= actualNonce\n if (chainNonceBigInt < actualNonceBigInt - BigInt(1)) {\n console.warn(\n `[NonceManager]: Chain nonce (${chainNonceBigInt}) behind expected (${actualNonceBigInt - BigInt(1)}). Updating...`\n );\n }\n\n // Compute next usable nonce using maxBigInt for clarity\n // Include (actualNonce + 1) to immediately advance locally after broadcast,\n // even if chain finality has not reflected the new nonce yet.\n const candidateNext = this.maxBigInt(\n chainNonceBigInt + 1n,\n actualNonceBigInt + 1n,\n this.transactionContext?.nextNonce ? BigInt(this.transactionContext.nextNonce) : 0n,\n this.lastReservedNonce ? BigInt(this.lastReservedNonce) + 1n : 0n,\n );\n\n // Update cached context with fresh access key info and computed next nonce\n if (this.transactionContext) {\n this.transactionContext.accessKeyInfo = accessKeyInfo;\n this.transactionContext.nextNonce = candidateNext.toString();\n } else {\n // If no context exists (should be rare here), construct a minimal one\n this.transactionContext = {\n nearPublicKeyStr: this.nearPublicKeyStr!,\n accessKeyInfo: accessKeyInfo,\n nextNonce: candidateNext.toString(),\n // Block values are unknown here; leave stale ones to be refreshed later\n txBlockHeight: '0',\n txBlockHash: '',\n } as TransactionContext; // We'll refresh these via fetchFreshData when needed\n }\n this.lastNonceUpdate = Date.now();\n\n // Release the used nonce (idempotent)\n this.releaseNonce(actualNonce);\n\n // Prune any reserved nonces that are now <= chain nonce (already used or invalid)\n if (this.reservedNonces.size > 0) {\n const { set: prunedSet, lastReserved } = this.pruneReserved(chainNonceBigInt, this.reservedNonces);\n this.reservedNonces = prunedSet;\n this.lastReservedNonce = lastReserved;\n }\n\n console.debug(\n `[NonceManager]: Updated from chain nonce=${chainNonceBigInt} actual=${actualNonceBigInt} next=${this.transactionContext!.nextNonce}`\n );\n\n } catch (error: unknown) {\n const msg = errorMessage(error);\n // Tolerate missing/rotated keys: avoid noisy error and advance nextNonce optimistically\n if (msg.includes('does not exist while viewing') || msg.includes('Access key not found')) {\n try {\n const actualNonceBigInt = BigInt(actualNonce);\n const candidateNext = this.maxBigInt(\n actualNonceBigInt + 1n,\n this.transactionContext?.nextNonce ? BigInt(this.transactionContext.nextNonce) : 0n,\n this.lastReservedNonce ? BigInt(this.lastReservedNonce) + 1n : 0n,\n );\n if (this.transactionContext) {\n this.transactionContext.nextNonce = candidateNext.toString();\n } else {\n this.transactionContext = {\n nearPublicKeyStr: this.nearPublicKeyStr!,\n accessKeyInfo: makePlaceholderAccessKey(),\n nextNonce: candidateNext.toString(),\n txBlockHeight: '0',\n txBlockHash: '',\n } as TransactionContext;\n }\n this.lastNonceUpdate = Date.now();\n console.debug('[NonceManager]: Access key missing; advanced nextNonce optimistically to', this.transactionContext?.nextNonce);\n return;\n } catch {}\n }\n console.warn('[NonceManager]: Failed to update nonce from blockchain:', error);\n // Don't throw - this is a best-effort update\n }\n }\n\n /**\n * Get the next available nonce for a single transaction\n * This is a convenience method that reserves exactly one nonce\n * @returns The next nonce to use\n */\n public getNextNonce(): string {\n const nonces = this.reserveNonces(1);\n return nonces[0];\n }\n\n private clearRefreshTimer(): void {\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n }\n private clearPrefetchTimer(): void {\n if (this.prefetchTimer) {\n clearTimeout(this.prefetchTimer);\n this.prefetchTimer = null;\n }\n }\n\n // Small helper to get max of BigInt values elegantly\n private maxBigInt(...values: bigint[]): bigint {\n if (values.length === 0) return 0n;\n return values.reduce((a, b) => (a > b ? a : b));\n }\n\n // Return a new reserved set that excludes entries <= chain nonce, and compute new lastReserved\n private pruneReserved(chainNonceBigInt: bigint, reserved: Set<string>): { set: Set<string>, lastReserved: string | null } {\n const newSet = new Set<string>();\n let newLast: bigint | null = null;\n for (const r of reserved) {\n try {\n const rb = BigInt(r);\n if (rb > chainNonceBigInt) {\n newSet.add(r);\n if (newLast === null || rb > newLast) newLast = rb;\n }\n } catch {\n // skip malformed entries\n }\n }\n return {\n set: newSet,\n lastReserved: newLast ? newLast.toString() : null\n };\n }\n\n}\n\n// ===== Type guards for NEAR RPC return shapes =====\nfunction isAccessKeyView(x: unknown): x is AccessKeyView {\n if (!isObject(x)) return false;\n // Only validate the fields we actually use\n return isNumber((x as { nonce?: unknown }).nonce);\n}\n\nfunction isBlockResult(x: unknown): x is BlockResult {\n if (!isObject(x)) return false;\n const h = (x as { header?: unknown }).header;\n if (!isObject(h)) return false;\n const height = (h as { height?: unknown }).height;\n const hash = (h as { hash?: unknown }).hash;\n return isNumber(height) && isString(hash);\n}\n\nfunction makePlaceholderAccessKey(): AccessKeyView {\n return {\n nonce: BigInt(0),\n permission: 'FullAccess',\n block_hash: '',\n block_height: 0\n }\n}\n\n// Create and export singleton instance\nconst NonceManagerInstance = NonceManager.getInstance();\nexport default NonceManagerInstance;\n","import type { NearClient } from '../../NearClient';\nimport { IndexedDBManager } from '../../IndexedDBManager';\nimport { toAccountId, type AccountId } from '../../types/accountIds';\nimport type { VRFChallenge, VRFInputData } from '../../types/vrf-worker';\nimport { thresholdEd25519Keygen } from '../../rpcCalls';\nimport { computeThresholdEd25519KeygenIntentDigest } from '../../digests/intentDigest';\nimport { ensureEd25519Prefix } from '../../../utils/validation';\nimport type { TouchIdPrompt } from '../touchIdPrompt';\nimport { collectAuthenticationCredentialForVrfChallenge } from '../collectAuthenticationCredentialForVrfChallenge';\n\ntype DeriveThresholdClientShareResult = {\n success: boolean;\n clientVerifyingShareB64u: string;\n wrapKeySalt: string;\n error?: string;\n};\n\nexport type EnrollThresholdEd25519KeyHandlerContext = {\n nearClient: NearClient;\n vrfWorkerManager: {\n generateVrfChallengeOnce: (inputData: VRFInputData) => Promise<VRFChallenge>;\n };\n signerWorkerManager: {\n deriveThresholdEd25519ClientVerifyingShare: (args: {\n sessionId: string;\n nearAccountId: AccountId;\n }) => Promise<DeriveThresholdClientShareResult>;\n };\n touchIdPrompt: Pick<\n TouchIdPrompt,\n 'getRpId' | 'getAuthenticationCredentialsSerialized' | 'getAuthenticationCredentialsSerializedDualPrf'\n >;\n relayerUrl: string;\n};\n\n/**\n * Threshold keygen helper (2-of-2):\n * - derive deterministic client verifying share from WrapKeySeed (via signer worker session)\n * - run `/threshold-ed25519/keygen` to fetch relayer share + group public key\n */\nexport async function enrollThresholdEd25519KeyHandler(\n ctx: EnrollThresholdEd25519KeyHandlerContext,\n args: {\n sessionId: string;\n nearAccountId: AccountId | string;\n }\n): Promise<{\n success: boolean;\n publicKey: string;\n clientParticipantId?: number;\n relayerParticipantId?: number;\n participantIds?: number[];\n clientVerifyingShareB64u: string;\n relayerKeyId: string;\n relayerVerifyingShareB64u: string;\n wrapKeySalt: string;\n error?: string;\n}> {\n const nearAccountId = toAccountId(args.nearAccountId);\n const sessionId = String(args.sessionId || '').trim();\n const relayerUrl = String(ctx.relayerUrl || '').trim();\n\n try {\n if (!sessionId) throw new Error('Missing sessionId');\n if (!relayerUrl) throw new Error('Missing relayer url (configs.relayer.url)');\n\n const derived = await ctx.signerWorkerManager.deriveThresholdEd25519ClientVerifyingShare({\n sessionId,\n nearAccountId,\n });\n if (!derived.success) {\n throw new Error(derived.error || 'Failed to derive threshold client verifying share');\n }\n\n const rpId = ctx.touchIdPrompt.getRpId();\n if (!rpId) throw new Error('Missing rpId for WebAuthn VRF challenge');\n\n // Keygen intent digest must bind the client verifying share; compute it before generating the VRF challenge.\n const keygenIntentDigestB64u = await computeThresholdEd25519KeygenIntentDigest({\n nearAccountId,\n rpId,\n clientVerifyingShareB64u: derived.clientVerifyingShareB64u,\n });\n\n // Fetch a fresh block height/hash for VRF freshness validation.\n const block = await ctx.nearClient.viewBlock({ finality: 'final' } as any);\n const blockHeight = String((block as any)?.header?.height ?? '');\n const blockHash = String((block as any)?.header?.hash ?? '');\n if (!blockHeight || !blockHash) throw new Error('Failed to fetch NEAR block context for keygen VRF challenge');\n\n const vrfChallenge = await ctx.vrfWorkerManager.generateVrfChallengeOnce({\n userId: nearAccountId,\n rpId,\n blockHeight,\n blockHash,\n intentDigest: keygenIntentDigestB64u,\n });\n\n // Collect a WebAuthn authentication credential with the VRF output as challenge.\n const webauthnAuthentication = await collectAuthenticationCredentialForVrfChallenge({\n indexedDB: IndexedDBManager,\n touchIdPrompt: ctx.touchIdPrompt,\n nearAccountId,\n vrfChallenge,\n });\n\n const keygen = await thresholdEd25519Keygen(relayerUrl, vrfChallenge, webauthnAuthentication, {\n clientVerifyingShareB64u: derived.clientVerifyingShareB64u,\n nearAccountId,\n });\n if (!keygen.ok) {\n throw new Error(keygen.error || keygen.message || keygen.code || 'Threshold keygen failed');\n }\n\n const publicKeyRaw = keygen.publicKey;\n const relayerKeyId = keygen.relayerKeyId;\n const relayerVerifyingShareB64u = keygen.relayerVerifyingShareB64u;\n if (!publicKeyRaw) throw new Error('Threshold keygen returned empty publicKey');\n if (!relayerKeyId) throw new Error('Threshold keygen returned empty relayerKeyId');\n if (!relayerVerifyingShareB64u) throw new Error('Threshold keygen returned empty relayerVerifyingShareB64u');\n\n const publicKey = ensureEd25519Prefix(publicKeyRaw);\n if (!publicKey) throw new Error('Threshold keygen returned empty publicKey');\n\n const clientParticipantId = typeof keygen.clientParticipantId === 'number' ? keygen.clientParticipantId : undefined;\n const relayerParticipantId = typeof keygen.relayerParticipantId === 'number' ? keygen.relayerParticipantId : undefined;\n\n return {\n success: true,\n publicKey,\n clientParticipantId,\n relayerParticipantId,\n participantIds: Array.isArray(keygen.participantIds) ? keygen.participantIds : undefined,\n clientVerifyingShareB64u: derived.clientVerifyingShareB64u,\n relayerKeyId,\n relayerVerifyingShareB64u,\n wrapKeySalt: derived.wrapKeySalt,\n };\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return { success: false, publicKey: '', clientVerifyingShareB64u: '', relayerKeyId: '', relayerVerifyingShareB64u: '', wrapKeySalt: '', error: message };\n }\n}\n","import type { NearClient } from '../../NearClient';\nimport { IndexedDBManager } from '../../IndexedDBManager';\nimport { hasAccessKey, waitForAccessKeyAbsent } from '../../rpcCalls';\nimport { ensureEd25519Prefix } from '../../../utils/validation';\nimport { ActionType, type ActionArgsWasm, type TransactionInputWasm } from '../../types/actions';\nimport { toAccountId, type AccountId } from '../../types/accountIds';\nimport { DEFAULT_WAIT_STATUS } from '../../types/rpc';\nimport type {\n ConfirmationConfig,\n RpcCallPayload,\n SignerMode,\n} from '../../types/signer-worker';\nimport type { SignTransactionResult } from '../../types/tatchi';\n\nexport type RotateThresholdEd25519KeyPostRegistrationHandlerContext = {\n nearClient: NearClient;\n contractId: string;\n nearRpcUrl: string;\n signTransactionsWithActions: (args: {\n transactions: TransactionInputWasm[];\n rpcCall: RpcCallPayload;\n signerMode: SignerMode;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n title?: string;\n body?: string;\n }) => Promise<SignTransactionResult[]>;\n};\n\n/**\n * Threshold key rotation (post-registration):\n * - keygen (new relayerKeyId + publicKey)\n * - AddKey(new threshold publicKey)\n * - DeleteKey(old threshold publicKey)\n *\n * Uses the local signer key for AddKey/DeleteKey, and requires the account to already\n * have a stored `threshold_ed25519_2p_v1` key material entry for the target device.\n */\nexport async function rotateThresholdEd25519KeyPostRegistrationHandler(\n ctx: RotateThresholdEd25519KeyPostRegistrationHandlerContext,\n args: {\n nearAccountId: AccountId | string;\n deviceNumber: number;\n oldPublicKey: string;\n oldRelayerKeyId: string;\n newPublicKey: string;\n newRelayerKeyId: string;\n wrapKeySalt: string;\n }\n): Promise<{\n success: boolean;\n oldPublicKey: string;\n oldRelayerKeyId: string;\n publicKey: string;\n relayerKeyId: string;\n wrapKeySalt: string;\n deleteOldKeyAttempted: boolean;\n deleteOldKeySuccess: boolean;\n warning?: string;\n error?: string;\n}> {\n const nearAccountId = toAccountId(args.nearAccountId);\n\n const oldPublicKey = String(args.oldPublicKey || '');\n const oldRelayerKeyId = String(args.oldRelayerKeyId || '');\n const newPublicKey = String(args.newPublicKey || '');\n const newRelayerKeyId = String(args.newRelayerKeyId || '');\n const wrapKeySalt = String(args.wrapKeySalt || '');\n\n const base = {\n oldPublicKey,\n oldRelayerKeyId,\n publicKey: newPublicKey,\n relayerKeyId: newRelayerKeyId,\n wrapKeySalt,\n };\n\n const ok = (params: { deleteOldKeyAttempted: boolean; deleteOldKeySuccess: boolean; warning?: string }) => {\n const { warning, ...rest } = params;\n return {\n success: true,\n ...base,\n ...rest,\n ...(warning ? { warning } : {}),\n };\n };\n\n try {\n const deviceNumber = Number(args.deviceNumber);\n const resolvedDeviceNumber = Number.isSafeInteger(deviceNumber) && deviceNumber >= 1 ? deviceNumber : NaN;\n if (!Number.isSafeInteger(resolvedDeviceNumber) || resolvedDeviceNumber < 1) {\n throw new Error('Invalid deviceNumber');\n }\n\n const oldNormalized = ensureEd25519Prefix(oldPublicKey);\n const newNormalized = ensureEd25519Prefix(newPublicKey);\n\n if (!oldNormalized) {\n return ok({\n deleteOldKeyAttempted: false,\n deleteOldKeySuccess: false,\n warning: 'Rotation completed but old threshold key material had an invalid publicKey; skipped DeleteKey.',\n });\n }\n\n if (oldNormalized === newNormalized) {\n return ok({\n deleteOldKeyAttempted: false,\n deleteOldKeySuccess: true,\n warning: 'Rotation returned the same threshold public key; skipped DeleteKey(old).',\n });\n }\n\n const localKeyMaterial = await IndexedDBManager.nearKeysDB.getLocalKeyMaterial(nearAccountId, resolvedDeviceNumber);\n if (!localKeyMaterial) {\n return ok({\n deleteOldKeyAttempted: false,\n deleteOldKeySuccess: false,\n warning: `Rotation completed but could not load local key material for DeleteKey(old) (account ${nearAccountId} device ${resolvedDeviceNumber}).`,\n });\n }\n\n const localPk = ensureEd25519Prefix(localKeyMaterial.publicKey);\n if (localPk && localPk === oldNormalized) {\n return ok({\n deleteOldKeyAttempted: false,\n deleteOldKeySuccess: false,\n warning: 'Refusing to DeleteKey(old) because it matches the local signer public key.',\n });\n }\n\n const oldOnChain = await hasAccessKey(ctx.nearClient, nearAccountId, oldPublicKey, { attempts: 1, delayMs: 0 });\n if (!oldOnChain) {\n return ok({ deleteOldKeyAttempted: false, deleteOldKeySuccess: true });\n }\n\n const deleteKeyAction: ActionArgsWasm = {\n action_type: ActionType.DeleteKey,\n public_key: oldNormalized,\n };\n\n const txInputs: TransactionInputWasm[] = [\n {\n receiverId: nearAccountId,\n actions: [deleteKeyAction],\n },\n ];\n\n let deleteOldKeyAttempted = false;\n try {\n const rpcCall: RpcCallPayload = {\n contractId: ctx.contractId,\n nearRpcUrl: ctx.nearRpcUrl,\n nearAccountId,\n };\n\n const signed = await ctx.signTransactionsWithActions({\n transactions: txInputs,\n rpcCall,\n signerMode: { mode: 'local-signer' },\n confirmationConfigOverride: {\n uiMode: 'skip',\n behavior: 'autoProceed',\n autoProceedDelay: 0,\n },\n title: 'Rotate threshold key',\n body: 'Confirm deletion of the old threshold access key.',\n });\n\n const signedTx = signed?.[0]?.signedTransaction;\n if (!signedTx) throw new Error('Failed to sign DeleteKey(oldThresholdPublicKey) transaction');\n deleteOldKeyAttempted = true;\n\n await ctx.nearClient.sendTransaction(signedTx, DEFAULT_WAIT_STATUS.linkDeviceDeleteKey);\n\n const deleted = await waitForAccessKeyAbsent(ctx.nearClient, nearAccountId, oldPublicKey);\n if (!deleted) {\n return ok({\n deleteOldKeyAttempted,\n deleteOldKeySuccess: false,\n warning: 'DeleteKey(old) submitted but old access key is still present on-chain.',\n });\n }\n\n return ok({ deleteOldKeyAttempted, deleteOldKeySuccess: true });\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return ok({\n deleteOldKeyAttempted,\n deleteOldKeySuccess: false,\n warning: `Rotation completed but failed to DeleteKey(old): ${message}`,\n });\n }\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return {\n success: false,\n oldPublicKey,\n oldRelayerKeyId,\n publicKey: '',\n relayerKeyId: '',\n wrapKeySalt: '',\n deleteOldKeyAttempted: false,\n deleteOldKeySuccess: false,\n error: message,\n };\n }\n}\n","import {\n IndexedDBManager,\n type ClientUserData,\n type ClientAuthenticatorData,\n type UnifiedIndexedDBManager,\n} from '../IndexedDBManager';\nimport { StoreUserDataInput } from '../IndexedDBManager/passkeyClientDB';\nimport type { ThresholdEd25519_2p_V1Material } from '../IndexedDBManager/passkeyNearKeysDB';\nimport { buildThresholdEd25519Participants2pV1 } from '../../threshold/participants';\nimport { type NearClient, SignedTransaction } from '../NearClient';\nimport { SignerWorkerManager } from './SignerWorkerManager';\nimport { VrfWorkerManager } from './VrfWorkerManager';\nimport { AllowCredential, TouchIdPrompt } from './touchIdPrompt';\nimport { toAccountId } from '../types/accountIds';\nimport { UserPreferencesManager } from './userPreferences';\nimport UserPreferencesInstance from './userPreferences';\nimport { NonceManager } from '../nonceManager';\nimport NonceManagerInstance from '../nonceManager';\nimport {\n EncryptedVRFKeypair,\n ServerEncryptedVrfKeypair,\n VRFInputData,\n VRFChallenge\n} from '../types/vrf-worker';\nimport { ActionType, type ActionArgsWasm, type TransactionInputWasm } from '../types/actions';\nimport type { RegistrationEventStep3, RegistrationHooksOptions, RegistrationSSEEvent, onProgressEvents } from '../types/sdkSentEvents';\nimport type { SignTransactionResult, TatchiConfigs } from '../types/tatchi';\nimport type { AccountId } from '../types/accountIds';\nimport type { AuthenticatorOptions } from '../types/authenticatorOptions';\nimport type { DelegateActionInput } from '../types/delegate';\nimport {\n INTERNAL_WORKER_REQUEST_TYPE_SIGN_ADD_KEY_THRESHOLD_PUBLIC_KEY_NO_PROMPT,\n isSignAddKeyThresholdPublicKeyNoPromptSuccess,\n type ConfirmationConfig,\n type RpcCallPayload,\n type SignerMode,\n type ThresholdBehavior,\n type WasmSignedDelegate,\n} from '../types/signer-worker';\nimport { WebAuthnRegistrationCredential, WebAuthnAuthenticationCredential } from '../types';\nimport { RegistrationCredentialConfirmationPayload } from './SignerWorkerManager/handlers/validation';\nimport { resolveWorkerBaseOrigin, onEmbeddedBaseChange } from '../sdkPaths';\nimport { DEFAULT_WAIT_STATUS, type TransactionContext } from '../types/rpc';\nimport { getLastLoggedInDeviceNumber } from './SignerWorkerManager/getDeviceNumber';\nimport { __isWalletIframeHostMode } from '../WalletIframe/host-mode';\nimport { hasAccessKey } from '../rpcCalls';\nimport { ensureEd25519Prefix } from '../../utils/validation';\nimport { enrollThresholdEd25519KeyHandler } from './threshold/enrollThresholdEd25519Key';\nimport { rotateThresholdEd25519KeyPostRegistrationHandler } from './threshold/rotateThresholdEd25519KeyPostRegistration';\nimport { collectAuthenticationCredentialForVrfChallenge as collectAuthenticationCredentialForVrfChallengeImpl } from './collectAuthenticationCredentialForVrfChallenge';\n\ntype SigningSessionOptions = {\n /** PRF-bearing credential; VRF worker extracts PRF outputs internally */\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n /**\n * Optional wrapKeySalt for WrapKeySeed delivery.\n * When provided, VRF worker will reuse this salt instead of generating a new one.\n */\n wrapKeySalt?: string;\n};\n\n/**\n * WebAuthnManager - Main orchestrator for WebAuthn operations\n *\n * Architecture:\n * - index.ts (this file): Main class orchestrating everything\n * - signerWorkerManager: NEAR transaction signing, and VRF Web3Authn verification RPC calls\n * - vrfWorkerManager: VRF keypair generation, challenge generation\n * - touchIdPrompt: TouchID prompt for biometric authentication\n */\nexport class WebAuthnManager {\n private readonly vrfWorkerManager: VrfWorkerManager;\n private readonly signerWorkerManager: SignerWorkerManager;\n private readonly touchIdPrompt: TouchIdPrompt;\n private readonly userPreferencesManager: UserPreferencesManager;\n private readonly nearClient: NearClient;\n private readonly nonceManager: NonceManager;\n private workerBaseOrigin: string = '';\n // VRF-owned signing session id per account (warm session reuse).\n private activeSigningSessionIds: Map<string, string> = new Map();\n\n readonly tatchiPasskeyConfigs: TatchiConfigs;\n\n constructor(tatchiPasskeyConfigs: TatchiConfigs, nearClient: NearClient) {\n this.tatchiPasskeyConfigs = tatchiPasskeyConfigs;\n this.nearClient = nearClient;\n // Respect rpIdOverride. Safari get() bridge fallback is always enabled.\n this.touchIdPrompt = new TouchIdPrompt(\n tatchiPasskeyConfigs.iframeWallet?.rpIdOverride,\n true,\n );\n this.userPreferencesManager = UserPreferencesInstance;\n // Apply integrator-provided default UI theme (in-memory only; user preferences may override later).\n this.userPreferencesManager.configureWalletTheme?.(tatchiPasskeyConfigs.walletTheme);\n // Apply integrator-provided default signer mode (in-memory only; user preferences may override later).\n this.userPreferencesManager.configureDefaultSignerMode?.(tatchiPasskeyConfigs.signerMode);\n this.nonceManager = NonceManagerInstance;\n const { vrfWorkerConfigs } = tatchiPasskeyConfigs;\n // Group VRF worker configuration and pass context\n this.vrfWorkerManager = new VrfWorkerManager(\n {\n shamirPB64u: vrfWorkerConfigs?.shamir3pass?.p,\n relayServerUrl: vrfWorkerConfigs?.shamir3pass?.relayServerUrl,\n applyServerLockRoute: vrfWorkerConfigs?.shamir3pass?.applyServerLockRoute,\n removeServerLockRoute: vrfWorkerConfigs?.shamir3pass?.removeServerLockRoute,\n },\n {\n touchIdPrompt: this.touchIdPrompt,\n nearClient: this.nearClient,\n indexedDB: IndexedDBManager,\n userPreferencesManager: this.userPreferencesManager,\n nonceManager: this.nonceManager,\n rpIdOverride: this.touchIdPrompt.getRpId(),\n nearExplorerUrl: tatchiPasskeyConfigs.nearExplorerUrl,\n }\n );\n this.signerWorkerManager = new SignerWorkerManager(\n this.vrfWorkerManager,\n nearClient,\n this.userPreferencesManager,\n this.nonceManager,\n this.tatchiPasskeyConfigs.relayer.url,\n tatchiPasskeyConfigs.iframeWallet?.rpIdOverride,\n true,\n tatchiPasskeyConfigs.nearExplorerUrl,\n );\n // VRF worker initializes on-demand with proper error propagation\n\n // Compute initial worker base origin once\n this.workerBaseOrigin = resolveWorkerBaseOrigin() || (typeof window !== 'undefined' ? window.location.origin : '');\n this.signerWorkerManager.setWorkerBaseOrigin(this.workerBaseOrigin);\n this.vrfWorkerManager.setWorkerBaseOrigin?.(this.workerBaseOrigin as any);\n\n // Keep base origin updated if the wallet sets a new embedded base\n if (typeof window !== 'undefined') {\n onEmbeddedBaseChange((url) => {\n const origin = new URL(url, window.location.origin).origin;\n if (origin && origin !== this.workerBaseOrigin) {\n this.workerBaseOrigin = origin;\n this.signerWorkerManager.setWorkerBaseOrigin(origin);\n this.vrfWorkerManager.setWorkerBaseOrigin?.(origin as any);\n }\n });\n }\n\n // Best-effort: load persisted preferences unless we are in app-origin iframe mode,\n // where the wallet origin owns persistence and the app should avoid IndexedDB.\n const shouldAvoidAppOriginIndexedDB =\n !!tatchiPasskeyConfigs.iframeWallet?.walletOrigin && !__isWalletIframeHostMode();\n if (!shouldAvoidAppOriginIndexedDB) {\n void this.userPreferencesManager.initFromIndexedDB().catch(() => undefined);\n }\n }\n\n /**\n * Public pre-warm hook to initialize signer workers ahead of time.\n * Safe to call multiple times; errors are non-fatal.\n */\n prewarmSignerWorkers(): void {\n if (typeof window === 'undefined' || typeof (window as any).Worker === 'undefined') return;\n // Avoid noisy SecurityError in cross‑origin dev: only prewarm when same‑origin\n if (this.workerBaseOrigin && this.workerBaseOrigin !== window.location.origin) return;\n this.signerWorkerManager.preWarmWorkerPool().catch(() => { });\n }\n\n /**\n * Warm critical resources to reduce first-action latency.\n * - Initialize current user (sets up NonceManager and local state)\n * - Prefetch latest block context (and nonce if missing)\n * - Pre-open IndexedDB and warm encrypted key for the active account (best-effort)\n * - Pre-warm signer workers in the background\n */\n async warmCriticalResources(nearAccountId?: string): Promise<void> {\n // Initialize current user first (best-effort)\n if (nearAccountId) {\n await this.initializeCurrentUser(toAccountId(nearAccountId), this.nearClient).catch(() => null);\n }\n // Prefetch latest block/nonce context (best-effort)\n await this.nonceManager.prefetchBlockheight(this.nearClient).catch(() => null);\n // Best-effort: open IndexedDB and warm key data for the account\n if (nearAccountId) {\n await IndexedDBManager.getUserWithKeys(toAccountId(nearAccountId)).catch(() => null);\n }\n // Warm signer workers in background\n this.prewarmSignerWorkers();\n }\n\n /**\n * Resolve the effective rpId used for WebAuthn operations.\n * Delegates to TouchIdPrompt to centralize rpId selection logic.\n */\n getRpId(): string {\n return this.touchIdPrompt.getRpId();\n }\n\n /** Getter for NonceManager instance */\n getNonceManager(): NonceManager {\n return this.nonceManager;\n }\n\n /**\n * WebAuthnManager-level orchestrator for VRF-owned signing sessions.\n * Creates sessionId, wires MessagePort between VRF and signer workers, and ensures cleanup.\n *\n * Overload 1: plain signing session (no WrapKeySeed derivation).\n * Overload 2: signing session with WrapKeySeed derivation, when `SigningSessionOptions`\n * (PRF.first_auth) are provided. wrapKeySalt is generated inside the VRF worker\n * when a new vault entry is being created.\n */\n private generateSessionId(prefix: string): string {\n return (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function')\n ? crypto.randomUUID()\n : `${prefix}-${Date.now()}-${Math.random().toString(16).slice(2)}`;\n }\n\n private toNonNegativeInt(value: unknown): number | undefined {\n if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) return undefined;\n return Math.floor(value);\n }\n\n private resolveSigningSessionPolicy(args: {\n ttlMs?: number;\n remainingUses?: number;\n }): {\n ttlMs: number;\n remainingUses: number;\n } {\n const ttlMs = this.toNonNegativeInt(args.ttlMs)\n ?? this.tatchiPasskeyConfigs.signingSessionDefaults.ttlMs;\n const remainingUses = this.toNonNegativeInt(args.remainingUses)\n ?? this.tatchiPasskeyConfigs.signingSessionDefaults.remainingUses;\n return { ttlMs, remainingUses };\n }\n\n private getOrCreateActiveSigningSessionId(nearAccountId: AccountId): string {\n const key = String(toAccountId(nearAccountId));\n const existing = this.activeSigningSessionIds.get(key);\n if (existing) return existing;\n const sessionId = this.generateSessionId('signing-session');\n this.activeSigningSessionIds.set(key, sessionId);\n return sessionId;\n }\n\n private async withSigningSession<T>(args: {\n sessionId?: string;\n prefix?: string;\n options?: SigningSessionOptions;\n handler: (sessionId: string) => Promise<T>;\n }): Promise<T> {\n if (typeof args.handler !== 'function') {\n throw new Error('withSigningSession requires a handler function');\n }\n const sessionId = args.sessionId || (args.prefix ? this.generateSessionId(args.prefix) : '');\n if (!sessionId) {\n throw new Error('withSigningSession requires a sessionId or prefix');\n }\n return await this.withSigningSessionInternal({ sessionId, options: args.options, handler: args.handler });\n }\n\n private async withSigningSessionInternal<T>(args: {\n sessionId: string;\n options?: SigningSessionOptions;\n handler: (sessionId: string) => Promise<T>;\n }): Promise<T> {\n const signerPort = await this.vrfWorkerManager.createSigningSessionChannel(args.sessionId);\n await this.signerWorkerManager.reserveSignerWorkerSession(args.sessionId, { signerPort });\n try {\n // If PRF is provided, derive WrapKeySeed in VRF worker and deliver it\n // (along with PRF.second if credential is provided) to the signer worker\n // via the reserved MessagePort before invoking the handler.\n if (args.options) {\n await this.vrfWorkerManager.mintSessionKeysAndSendToSigner({\n sessionId: args.sessionId,\n wrapKeySalt: args.options.wrapKeySalt,\n credential: args.options.credential,\n });\n }\n return await args.handler(args.sessionId);\n } finally {\n this.signerWorkerManager.releaseSigningSession(args.sessionId);\n }\n }\n\n /**\n * VRF-driven registration confirmation helper.\n * Runs confirmTxFlow and returns registration artifacts.\n *\n * SecureConfirm wrapper for link-device / registration: prompts user in-iframe to create a\n * new passkey (device N), returning artifacts for subsequent derivation.\n */\n async requestRegistrationCredentialConfirmation(params: {\n nearAccountId: string;\n deviceNumber: number;\n confirmerText?: { title?: string; body?: string };\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n }): Promise<RegistrationCredentialConfirmationPayload> {\n return this.vrfWorkerManager.requestRegistrationCredentialConfirmation({\n nearAccountId: params.nearAccountId,\n deviceNumber: params.deviceNumber,\n confirmerText: params.confirmerText,\n confirmationConfigOverride: params.confirmationConfigOverride,\n contractId: this.tatchiPasskeyConfigs.contractId,\n nearRpcUrl: this.tatchiPasskeyConfigs.nearRpcUrl,\n });\n }\n\n /**\n * Helper for export/decrypt flows:\n * - Read vault wrapKeySalt\n * - Ask VRF worker to run LocalOnly(DECRYPT_PRIVATE_KEY_WITH_PRF) + derive WrapKeySeed\n * - WrapKeySeed travels only over the VRF→Signer MessagePort\n */\n private async confirmDecryptAndDeriveWrapKeySeed(args: {\n nearAccountId: AccountId;\n sessionId: string;\n }): Promise<void> {\n const nearAccountId = toAccountId(args.nearAccountId);\n // Resolve deviceNumber consistently with signer paths so both VRF and signer\n // operate on the same vault entry. Prefer the last logged-in device for this\n // account; if unavailable, fall back to the most recently updated user row.\n const [last, latest] = await Promise.all([\n IndexedDBManager.clientDB.getLastUser().catch(() => null),\n IndexedDBManager.clientDB.getLastDBUpdatedUser(nearAccountId).catch(() => null)\n ]);\n\n const deviceNumber =\n (last && last.nearAccountId === nearAccountId && typeof last.deviceNumber === 'number')\n ? last.deviceNumber\n : (latest && typeof latest.deviceNumber === 'number')\n ? latest.deviceNumber\n : null;\n\n if (deviceNumber === null) {\n throw new Error(`No deviceNumber found for account ${nearAccountId} (decrypt session)`);\n }\n\n // Load VRF material for this device so the VRF worker can unlock the correct\n // VRF keypair in a fresh/offline worker instance.\n const userForDevice = await IndexedDBManager.clientDB.getUserByDevice(nearAccountId, deviceNumber).catch(() => null);\n const encryptedVrfKeypair = userForDevice?.encryptedVrfKeypair;\n\n // Gather encrypted key + wrapKeySalt and public key from IndexedDB for this device\n const keyMaterial = await IndexedDBManager.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber);\n if (!keyMaterial) {\n console.error('WebAuthnManager: No encrypted key found for decrypt session', {\n nearAccountId: String(nearAccountId),\n deviceNumber,\n });\n throw new Error(`No key material found for account: ${nearAccountId}`);\n }\n const wrapKeySalt = keyMaterial.wrapKeySalt;\n if (!wrapKeySalt) {\n console.error('WebAuthnManager: Missing wrapKeySalt in vault for decrypt session', {\n nearAccountId: String(nearAccountId),\n deviceNumber,\n });\n throw new Error('Missing wrapKeySalt in vault; re-register to upgrade vault format.');\n }\n\n try {\n await this.vrfWorkerManager.prepareDecryptSession({\n sessionId: args.sessionId,\n nearAccountId,\n wrapKeySalt,\n encryptedVrfKeypair,\n });\n } catch (error) {\n console.error('WebAuthnManager: VRF decrypt session failed', {\n nearAccountId: String(nearAccountId),\n sessionId: args.sessionId,\n error,\n });\n throw error;\n }\n }\n\n getAuthenticationCredentialsSerialized({\n nearAccountId,\n challenge,\n allowCredentials\n }: {\n nearAccountId: AccountId;\n challenge: VRFChallenge;\n allowCredentials: AllowCredential[];\n }): Promise<WebAuthnAuthenticationCredential> {\n return this.touchIdPrompt.getAuthenticationCredentialsSerialized({\n nearAccountId,\n challenge,\n allowCredentials\n });\n }\n\n async collectAuthenticationCredentialForVrfChallenge(args: {\n nearAccountId: AccountId | string;\n vrfChallenge: VRFChallenge;\n onBeforePrompt?: (info: {\n authenticators: ClientAuthenticatorData[];\n authenticatorsForPrompt: ClientAuthenticatorData[];\n vrfChallenge: VRFChallenge;\n }) => void;\n /**\n * When true, include PRF.second in the serialized credential.\n * Use only for explicit recovery/export flows (higher-friction paths).\n */\n includeSecondPrfOutput?: boolean;\n }): Promise<WebAuthnAuthenticationCredential> {\n return collectAuthenticationCredentialForVrfChallengeImpl({\n indexedDB: IndexedDBManager,\n touchIdPrompt: this.touchIdPrompt,\n nearAccountId: args.nearAccountId,\n vrfChallenge: args.vrfChallenge,\n includeSecondPrfOutput: args.includeSecondPrfOutput,\n onBeforePrompt: args.onBeforePrompt,\n });\n }\n\n ///////////////////////////////////////\n // VRF MANAGER FUNCTIONS\n ///////////////////////////////////////\n\n /**\n * Generate a VRF challenge bound to a specific signing/confirm session.\n * The challenge will be cached in the VRF worker under this sessionId so\n * later contract verification (MINT_SESSION_KEYS_AND_SEND_TO_SIGNER) can look it up.\n */\n async generateVrfChallengeForSession(\n sessionId: string,\n vrfInputData: VRFInputData,\n ): Promise<VRFChallenge> {\n return this.vrfWorkerManager.generateVrfChallengeForSession(vrfInputData, sessionId);\n }\n\n /**\n * Generate a one-off VRF challenge without caching it in the VRF worker.\n * Use this for flows that don't perform contract verification or derive\n * wrap keys via MINT_SESSION_KEYS_AND_SEND_TO_SIGNER.\n */\n async generateVrfChallengeOnce(vrfInputData: VRFInputData): Promise<VRFChallenge> {\n return this.vrfWorkerManager.generateVrfChallengeOnce(vrfInputData);\n }\n\n /**\n * Generate VRF keypair for bootstrapping - stores in memory unencrypted temporarily\n * This is used during registration to generate a VRF keypair that will be used for\n * WebAuthn ceremony and later encrypted with the real PRF output\n *\n * @param saveInMemory - Whether to persist the generated VRF keypair in WASM worker memory\n * @param vrfInputParams - Optional parameters to generate VRF challenge/proof in same call\n * @returns VRF public key and optionally VRF challenge data\n */\n async generateVrfKeypairBootstrap(args: {\n saveInMemory: boolean;\n vrfInputData: VRFInputData;\n sessionId?: string;\n }): Promise<{\n vrfPublicKey: string;\n vrfChallenge: VRFChallenge;\n }> {\n return this.vrfWorkerManager.generateVrfKeypairBootstrap({\n vrfInputData: args.vrfInputData,\n saveInMemory: args.saveInMemory,\n sessionId: args.sessionId,\n });\n }\n\n /**\n * Derive NEAR keypair directly from a serialized WebAuthn registration credential\n */\n async deriveNearKeypairAndEncryptFromSerialized({\n credential,\n nearAccountId,\n options,\n }: {\n credential: WebAuthnRegistrationCredential;\n nearAccountId: string;\n options?: {\n authenticatorOptions?: AuthenticatorOptions;\n deviceNumber?: number;\n };\n }): Promise<{\n success: boolean;\n nearAccountId: string;\n publicKey: string;\n chacha20NonceB64u?: string;\n wrapKeySalt?: string;\n error?: string;\n }> {\n return this.withSigningSession({\n prefix: 'reg',\n options: { credential },\n handler: (sessionId) =>\n this.signerWorkerManager.deriveNearKeypairAndEncryptFromSerialized({\n credential,\n nearAccountId: toAccountId(nearAccountId),\n options,\n sessionId,\n }),\n });\n }\n\n /**\n * **Sign Device2 registration transaction with already-stored key (no prompt)**\n *\n * Used by linkDevice flow after key swap to sign the registration transaction\n * without prompting the user again. Reuses the credential collected earlier.\n *\n * Flow:\n * 1. Extract PRF.first from the provided credential\n * 2. Create new MessagePort session for WrapKeySeed delivery\n * 3. VRF worker re-derives WrapKeySeed and sends to signer (with PRF.second)\n * 4. Signer worker retrieves encrypted key from IndexedDB\n * 5. Signer worker decrypts key and signs registration transaction\n *\n * @param nearAccountId - NEAR account ID for Device2\n * @param credential - WebAuthn registration credential from earlier prompt\n * @param vrfChallenge - VRF challenge from earlier prompt\n * @param deviceNumber - Device number for Device2\n * @returns Signed registration transaction ready for submission\n */\n async signDevice2RegistrationWithStoredKey(args: {\n nearAccountId: AccountId;\n credential: WebAuthnRegistrationCredential;\n vrfChallenge: VRFChallenge;\n deviceNumber: number;\n deterministicVrfPublicKey: string;\n }): Promise<{\n success: boolean;\n publicKey?: string;\n signedTransaction?: any;\n error?: string;\n }> {\n const { nearAccountId, credential, vrfChallenge, deviceNumber, deterministicVrfPublicKey } = args;\n const contractId = this.tatchiPasskeyConfigs.contractId;\n\n try {\n // Generate new session ID for this signing operation\n const sessionId = `device2-sign-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;\n\n // Retrieve encrypted key data and wrapKeySalt from IndexedDB\n const keyMaterial = await IndexedDBManager.nearKeysDB.getLocalKeyMaterial(\n nearAccountId,\n deviceNumber\n );\n if (!keyMaterial) {\n throw new Error(`No key material found for account ${nearAccountId} device ${deviceNumber}`);\n }\n\n const wrapKeySalt = keyMaterial.wrapKeySalt;\n if (!wrapKeySalt) {\n throw new Error(`Missing wrapKeySalt for account ${nearAccountId} device ${deviceNumber}`);\n }\n\n // === STEP 1: Create MessagePort session for WrapKeySeed delivery ===\n const signerPort = await this.vrfWorkerManager.createSigningSessionChannel(sessionId);\n await this.signerWorkerManager.reserveSignerWorkerSession(sessionId, { signerPort });\n\n // === STEP 2: VRF worker re-derives WrapKeySeed and sends to signer ===\n // This extracts PRF.second from the credential and delivers both WrapKeySeed + PRF.second\n // to the signer worker via MessagePort\n await this.vrfWorkerManager.mintSessionKeysAndSendToSigner({\n sessionId,\n wrapKeySalt,\n credential, // VRF will extract PRF.second from this\n });\n\n // === STEP 4: Get transaction context for registration ===\n const transactionContext = await this.nonceManager.getNonceBlockHashAndHeight(this.nearClient);\n\n // === STEP 5: Determine deterministic VRF public key ===\n // Try: provided parameter → authenticator table → fallback to ephemeral VRF from challenge\n let vrfPublicKey = deterministicVrfPublicKey;\n // Fallback to ephemeral VRF public key from challenge if still not found\n const finalVrfPublicKey = vrfPublicKey || vrfChallenge.vrfPublicKey;\n\n // === STEP 6: Signer worker signs registration transaction ===\n // WrapKeySeed and PRF.second are already in signer worker via MessagePort\n const signerResult = await this.signerWorkerManager.registerDevice2WithDerivedKey({\n sessionId,\n nearAccountId,\n credential,\n vrfChallenge,\n transactionContext,\n contractId,\n wrapKeySalt,\n deviceNumber,\n deterministicVrfPublicKey: finalVrfPublicKey,\n });\n\n return {\n success: true,\n publicKey: signerResult.publicKey,\n signedTransaction: signerResult.signedTransaction,\n };\n\n } catch (error: any) {\n console.error('[WebAuthnManager] Failed to sign Device2 registration with stored key:', error);\n return {\n success: false,\n error: error.message || String(error),\n };\n }\n }\n\n /**\n * Derive deterministic VRF keypair from PRF output for recovery\n * Optionally generates VRF challenge if input parameters are provided\n * This enables deterministic VRF key derivation from WebAuthn credentials\n *\n * @param credential - WebAuthn credential containing PRF outputs\n * @param nearAccountId - NEAR account ID for key derivation salt\n * @param vrfInputParams - Optional VRF inputs, if provided will generate a challenge\n * @param saveInMemory - Whether to save the derived VRF keypair in worker memory for immediate use\n * @returns Deterministic VRF public key, optional VRF challenge, and encrypted VRF keypair for storage\n */\n async deriveVrfKeypair({\n credential,\n nearAccountId,\n vrfInputData,\n saveInMemory = true,\n }: {\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n nearAccountId: AccountId;\n vrfInputData?: VRFInputData; // optional, for challenge generation\n saveInMemory?: boolean; // optional, whether to save in worker memory\n }): Promise<{\n success: boolean;\n vrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n vrfChallenge: VRFChallenge | null;\n serverEncryptedVrfKeypair: ServerEncryptedVrfKeypair | null;\n }> {\n try {\n const vrfResult = await this.vrfWorkerManager.deriveVrfKeypairFromPrf({\n credential,\n nearAccountId,\n vrfInputData,\n saveInMemory,\n });\n\n const result: {\n success: boolean;\n vrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n vrfChallenge: VRFChallenge | null;\n serverEncryptedVrfKeypair: ServerEncryptedVrfKeypair | null;\n } = {\n success: true,\n vrfPublicKey: vrfResult.vrfPublicKey,\n encryptedVrfKeypair: vrfResult.encryptedVrfKeypair,\n vrfChallenge: vrfResult.vrfChallenge,\n serverEncryptedVrfKeypair: vrfResult.serverEncryptedVrfKeypair,\n };\n\n return result;\n\n } catch (error: any) {\n console.error('WebAuthnManager: VRF keypair derivation error:', error);\n throw new Error(`VRF keypair derivation failed ${error.message}`);\n }\n }\n\n /**\n * Unlock VRF keypair in memory using PRF output\n * This is called during login to decrypt and load the VRF keypair in-memory\n */\n async unlockVRFKeypair({\n nearAccountId,\n encryptedVrfKeypair,\n credential,\n }: {\n nearAccountId: AccountId;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n credential: WebAuthnAuthenticationCredential | WebAuthnRegistrationCredential;\n }): Promise<{ success: boolean; error?: string }> {\n try {\n const unlockResult = await this.vrfWorkerManager.unlockVrfKeypair({\n credential,\n nearAccountId,\n encryptedVrfKeypair,\n });\n\n if (!unlockResult.success) {\n console.error('WebAuthnManager: VRF keypair unlock failed');\n return { success: false, error: 'VRF keypair unlock failed' };\n }\n\n // Warm up signer workers after a successful unlock to minimize first-use latency\n this.signerWorkerManager.preWarmWorkerPool().catch(() => { });\n\n return { success: true };\n\n } catch (error: any) {\n console.error('WebAuthnManager: VRF keypair unlock failed:', error.message);\n return { success: false, error: error.message };\n }\n }\n\n /**\n * Perform Shamir 3-pass commutative decryption within WASM worker\n * This securely decrypts a server-encrypted KEK (key encryption key)\n * which the wasm worker uses to unlock a key to decrypt the VRF keypair and loads it into memory\n * The server never knows the real value of the KEK, nor the VRF keypair\n */\n async shamir3PassDecryptVrfKeypair({\n nearAccountId,\n kek_s_b64u,\n ciphertextVrfB64u,\n serverKeyId,\n }: {\n nearAccountId: AccountId;\n kek_s_b64u: string;\n ciphertextVrfB64u: string;\n serverKeyId: string;\n }): Promise<{ success: boolean; error?: string }> {\n const result = await this.vrfWorkerManager.shamir3PassDecryptVrfKeypair({\n nearAccountId,\n kek_s_b64u,\n ciphertextVrfB64u,\n serverKeyId,\n });\n\n return {\n success: result.success,\n error: result.error\n };\n }\n\n /**\n * Shamir 3-pass: encrypt the unlocked VRF keypair under the server key\n * Returns a fresh blob to store in IndexedDB for future auto-login.\n */\n async shamir3PassEncryptCurrentVrfKeypair(): Promise<ServerEncryptedVrfKeypair> {\n const res = await this.vrfWorkerManager.shamir3PassEncryptCurrentVrfKeypair();\n return {\n ciphertextVrfB64u: res.ciphertextVrfB64u,\n kek_s_b64u: res.kek_s_b64u,\n serverKeyId: res.serverKeyId,\n };\n }\n\n /**\n * Persist refreshed server-encrypted VRF keypair in IndexedDB.\n */\n async updateServerEncryptedVrfKeypair(\n nearAccountId: AccountId,\n serverEncrypted: ServerEncryptedVrfKeypair,\n deviceNumber?: number\n ): Promise<void> {\n await IndexedDBManager.clientDB.updateUser(nearAccountId, {\n serverEncryptedVrfKeypair: {\n ciphertextVrfB64u: serverEncrypted.ciphertextVrfB64u,\n kek_s_b64u: serverEncrypted.kek_s_b64u,\n serverKeyId: serverEncrypted.serverKeyId,\n updatedAt: Date.now(),\n }\n }, deviceNumber);\n }\n\n async clearVrfSession(): Promise<void> {\n // In cross-origin dev, skip local worker init; wallet iframe handles PM_LOGOUT\n if (typeof window !== 'undefined' && this.workerBaseOrigin !== window.location.origin) {\n return;\n }\n return await this.vrfWorkerManager.clearVrfSession();\n }\n\n /**\n * Check VRF worker status\n */\n async checkVrfStatus(): Promise<{\n active: boolean;\n nearAccountId: AccountId | null;\n sessionDuration?: number\n }> {\n return this.vrfWorkerManager.checkVrfStatus();\n }\n\n /**\n * Mint/refresh a VRF-owned warm signing session using an already-collected WebAuthn credential.\n *\n * This is used to avoid a second TouchID prompt during login flows when we already\n * performed an authentication ceremony (e.g., to unlock the VRF keypair).\n *\n * Notes:\n * - This method does not initiate a WebAuthn prompt.\n * - Contract verification is optional and only performed when `contractId` + `nearRpcUrl` are provided.\n */\n\t async mintSigningSessionFromCredential(args: {\n\t nearAccountId: AccountId;\n\t credential: WebAuthnAuthenticationCredential;\n\t remainingUses?: number;\n\t ttlMs?: number;\n\t contractId?: string;\n\t nearRpcUrl?: string;\n\t }): Promise<{\n\t sessionId: string;\n\t status: 'active' | 'exhausted' | 'expired' | 'not_found';\n\t remainingUses?: number;\n\t expiresAtMs?: number;\n\t createdAtMs?: number;\n\t }> {\n\t const nearAccountId = toAccountId(args.nearAccountId);\n\t const sessionId = this.getOrCreateActiveSigningSessionId(nearAccountId);\n\n\t // Ensure VRF keypair is active and bound to the same account.\n\t const vrfStatus = await this.vrfWorkerManager.checkVrfStatus();\n\t if (!vrfStatus.active) {\n\t throw new Error('VRF keypair not active in memory. Please log in again.');\n\t }\n\t if (!vrfStatus.nearAccountId || String(vrfStatus.nearAccountId) !== String(nearAccountId)) {\n\t throw new Error('VRF keypair active but bound to a different account. Please log in again.');\n\t }\n\n\t const credentialRawId = String(args.credential?.rawId || '').trim();\n\t const authenticators = await this.getAuthenticatorsByUser(nearAccountId).catch(() => []);\n\n\t // Fetch wrapKeySalt from vault so the derived WrapKeySeed can decrypt the stored NEAR keys.\n\t let deviceNumber: number;\n\t try {\n\t deviceNumber = await getLastLoggedInDeviceNumber(nearAccountId, IndexedDBManager.clientDB);\n\t } catch (err) {\n\t // Fallback: if lastUser was not set (e.g., cross-origin flows), infer the deviceNumber\n\t // from the credential rawId so we can still mint a session for the selected passkey.\n\t if (credentialRawId) {\n\t const matched = authenticators.find((a) => a.credentialId === credentialRawId);\n\t const inferred =\n\t matched && typeof matched.deviceNumber === 'number' && Number.isFinite(matched.deviceNumber)\n\t ? matched.deviceNumber\n\t : null;\n\t if (inferred !== null) {\n\t deviceNumber = inferred;\n\t // Best-effort: align lastUser to the passkey that was actually used.\n\t await this.setLastUser(nearAccountId, inferred).catch(() => undefined);\n\t } else {\n\t throw err;\n\t }\n\t } else {\n\t throw err;\n\t }\n\t }\n\n\t // If multiple passkeys exist, ensure the credential used for session minting matches\n\t // the currently selected/last-user device. This avoids deriving a WrapKeySeed that\n\t // cannot decrypt the expected vault entry.\n\t if (credentialRawId && authenticators.length > 1) {\n\t const { wrongPasskeyError } = await IndexedDBManager.clientDB.ensureCurrentPasskey(\n\t nearAccountId,\n\t authenticators,\n\t credentialRawId,\n\t );\n\t if (wrongPasskeyError) {\n\t throw new Error(wrongPasskeyError);\n\t }\n\t }\n\n\t const keyMaterial = await IndexedDBManager.nearKeysDB.getLocalKeyMaterial(nearAccountId, deviceNumber);\n\t if (!keyMaterial) {\n\t throw new Error(`No key material found for account ${nearAccountId} device ${deviceNumber}`);\n\t }\n\t const wrapKeySalt = keyMaterial.wrapKeySalt;\n if (!wrapKeySalt) {\n throw new Error('Missing wrapKeySalt in vault; re-register to upgrade vault format.');\n }\n\n // Extract PRF.first_auth from the already-collected credential.\n const { ttlMs, remainingUses } = this.resolveSigningSessionPolicy(args);\n\n await this.vrfWorkerManager.mintSessionKeysAndSendToSigner({\n sessionId,\n wrapKeySalt,\n contractId: args.contractId,\n nearRpcUrl: args.nearRpcUrl,\n ttlMs,\n remainingUses,\n credential: args.credential,\n });\n\n return await this.vrfWorkerManager.checkSessionStatus({ sessionId });\n }\n\n /**\n * Introspect the VRF-owned signing session for UI (no prompt, metadata only).\n * Session usage (`remainingUses`) is decremented on `DISPENSE_SESSION_KEY` calls.\n */\n async getWarmSigningSessionStatus(nearAccountId: AccountId): Promise<{\n sessionId: string;\n status: 'active' | 'exhausted' | 'expired' | 'not_found';\n remainingUses?: number;\n expiresAtMs?: number;\n createdAtMs?: number;\n }> {\n const sessionId = this.getOrCreateActiveSigningSessionId(nearAccountId);\n return await this.vrfWorkerManager.checkSessionStatus({ sessionId });\n }\n\n /**\n * Fetch Shamir server key info to support proactive refresh.\n */\n async getShamirKeyInfo(): Promise<{\n currentKeyId: string | null;\n p_b64u: string | null;\n graceKeyIds?: string[]\n } | null> {\n try {\n const relayUrl = this.tatchiPasskeyConfigs?.vrfWorkerConfigs?.shamir3pass?.relayServerUrl;\n if (!relayUrl) return null;\n const res = await fetch(`${relayUrl}/shamir/key-info`, { method: 'GET' });\n if (!res.ok) return null;\n const data = await res.json();\n return {\n currentKeyId: data?.currentKeyId ?? null,\n p_b64u: data?.p_b64u ?? null,\n graceKeyIds: Array.isArray(data?.graceKeyIds) ? data.graceKeyIds : undefined,\n };\n } catch {\n return null;\n }\n }\n\n /**\n * If server key changed and VRF is unlocked in memory, re-encrypt under the new server key.\n * Returns true if refreshed, false otherwise.\n */\n async maybeProactiveShamirRefresh(nearAccountId: AccountId): Promise<boolean> {\n try {\n const relayUrl = this.tatchiPasskeyConfigs?.vrfWorkerConfigs?.shamir3pass?.relayServerUrl;\n if (!relayUrl) return false;\n const userData = await this.getLastUser();\n const stored = userData?.serverEncryptedVrfKeypair;\n if (!stored || !stored.kek_s_b64u || !stored.ciphertextVrfB64u || !stored.serverKeyId) return false;\n\n const keyInfo = await this.getShamirKeyInfo();\n const currentKeyId = keyInfo?.currentKeyId;\n if (!currentKeyId || currentKeyId === stored.serverKeyId) return false;\n\n const status = await this.checkVrfStatus();\n const active = status.active && status.nearAccountId === nearAccountId;\n if (!active) return false;\n\n const refreshed = await this.shamir3PassEncryptCurrentVrfKeypair();\n await this.updateServerEncryptedVrfKeypair(nearAccountId, refreshed, userData?.deviceNumber);\n return true;\n } catch {\n return false;\n }\n }\n\n ///////////////////////////////////////\n // INDEXEDDB OPERATIONS\n ///////////////////////////////////////\n\n async storeUserData(userData: StoreUserDataInput): Promise<void> {\n await IndexedDBManager.clientDB.storeWebAuthnUserData({\n ...userData,\n deviceNumber: userData.deviceNumber ?? 1,\n version: userData.version || 2,\n });\n }\n\n async getAllUsers(): Promise<ClientUserData[]> {\n return await IndexedDBManager.clientDB.getAllUsers();\n }\n\n async getUserByDevice(nearAccountId: AccountId, deviceNumber: number): Promise<ClientUserData | null> {\n return await IndexedDBManager.clientDB.getUserByDevice(nearAccountId, deviceNumber);\n }\n\n async getLastUser(): Promise<ClientUserData | null> {\n return await IndexedDBManager.clientDB.getLastUser();\n }\n\n async getAuthenticatorsByUser(nearAccountId: AccountId): Promise<ClientAuthenticatorData[]> {\n return await IndexedDBManager.clientDB.getAuthenticatorsByUser(nearAccountId);\n }\n\n async updateLastLogin(nearAccountId: AccountId): Promise<void> {\n return await IndexedDBManager.clientDB.updateLastLogin(nearAccountId);\n }\n\n /**\n * Set the last logged-in user\n * @param nearAccountId - The account ID of the user\n * @param deviceNumber - The device number (defaults to 1)\n */\n async setLastUser(nearAccountId: AccountId, deviceNumber: number = 1): Promise<void> {\n return await IndexedDBManager.clientDB.setLastUser(nearAccountId, deviceNumber);\n }\n\n\n /**\n * Initialize current user authentication state\n * This should be called after VRF keypair is successfully unlocked in memory\n * to ensure the user is properly logged in and can perform transactions\n *\n * @param nearAccountId - The NEAR account ID to initialize\n * @param nearClient - The NEAR client for nonce prefetching\n */\n async initializeCurrentUser(\n nearAccountId: AccountId,\n nearClient?: NearClient,\n ): Promise<void> {\n const accountId = toAccountId(nearAccountId);\n\n // Set as last user for future sessions, preserving the current deviceNumber\n // when it is already known for this account.\n let deviceNumberToUse: number | null = null;\n const lastUser = await IndexedDBManager.clientDB.getLastUser().catch(() => null);\n if (\n lastUser &&\n toAccountId(lastUser.nearAccountId) === accountId &&\n Number.isFinite(lastUser.deviceNumber)\n ) {\n deviceNumberToUse = lastUser.deviceNumber;\n }\n\n if (deviceNumberToUse === null) {\n const userForAccount = await IndexedDBManager.clientDB\n .getUserByDevice(accountId, 1)\n .catch(() => null);\n if (userForAccount && Number.isFinite(userForAccount.deviceNumber)) {\n deviceNumberToUse = userForAccount.deviceNumber;\n }\n }\n\n if (deviceNumberToUse === null) {\n deviceNumberToUse = 1;\n }\n\n await this.setLastUser(accountId, deviceNumberToUse);\n\n // Set as current user for immediate use\n this.userPreferencesManager.setCurrentUser(accountId);\n // Ensure confirmation preferences are loaded before callers read them (best-effort)\n await this.userPreferencesManager.reloadUserSettings().catch(() => undefined);\n\n // Initialize NonceManager with the selected user's public key (best-effort)\n const userData = await IndexedDBManager.clientDB\n .getUserByDevice(accountId, deviceNumberToUse)\n .catch(() => null);\n if (userData && userData.clientNearPublicKey) {\n this.nonceManager.initializeUser(accountId, userData.clientNearPublicKey);\n }\n\n // Prefetch block height for better UX (non-fatal if it fails and nearClient is provided)\n if (nearClient) {\n await this.nonceManager\n .prefetchBlockheight(nearClient)\n .catch((prefetchErr) => console.debug('Nonce prefetch after authentication state initialization failed (non-fatal):', prefetchErr));\n }\n }\n\n async registerUser(storeUserData: StoreUserDataInput): Promise<ClientUserData> {\n return await IndexedDBManager.clientDB.registerUser(storeUserData);\n }\n\n async storeAuthenticator(authenticatorData: {\n credentialId: string;\n credentialPublicKey: Uint8Array;\n transports?: string[];\n name?: string;\n nearAccountId: AccountId;\n registered: string;\n syncedAt: string;\n vrfPublicKey: string;\n deviceNumber?: number;\n }): Promise<void> {\n const deviceNumber = Number(authenticatorData.deviceNumber);\n const normalizedDeviceNumber = Number.isSafeInteger(deviceNumber) && deviceNumber >= 1 ? deviceNumber : 1;\n const authData = {\n ...authenticatorData,\n nearAccountId: toAccountId(authenticatorData.nearAccountId),\n deviceNumber: normalizedDeviceNumber, // Default to device 1 (1-indexed)\n };\n return await IndexedDBManager.clientDB.storeAuthenticator(authData);\n }\n\n extractUsername(nearAccountId: AccountId): string {\n return IndexedDBManager.clientDB.extractUsername(nearAccountId);\n }\n\n async atomicOperation<T>(callback: (db: any) => Promise<T>): Promise<T> {\n return await IndexedDBManager.clientDB.atomicOperation(callback);\n }\n\n async rollbackUserRegistration(nearAccountId: AccountId): Promise<void> {\n return await IndexedDBManager.clientDB.rollbackUserRegistration(nearAccountId);\n }\n\n async hasPasskeyCredential(nearAccountId: AccountId): Promise<boolean> {\n return await IndexedDBManager.clientDB.hasPasskeyCredential(nearAccountId);\n }\n\n /**\n * Atomically store all registration data (user, authenticator, VRF credentials)\n */\n async atomicStoreRegistrationData({\n nearAccountId,\n credential,\n publicKey,\n encryptedVrfKeypair,\n vrfPublicKey,\n serverEncryptedVrfKeypair,\n }: {\n nearAccountId: AccountId;\n credential: WebAuthnRegistrationCredential;\n publicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n vrfPublicKey: string;\n serverEncryptedVrfKeypair: ServerEncryptedVrfKeypair | null;\n }): Promise<void> {\n await this.atomicOperation(async (db) => {\n // Store credential for authentication\n const credentialId: string = credential.rawId;\n const attestationB64u: string = credential.response.attestationObject;\n const transports: string[] = credential.response?.transports;\n\n await this.storeAuthenticator({\n nearAccountId: nearAccountId,\n credentialId: credentialId,\n credentialPublicKey: await this.extractCosePublicKey(attestationB64u),\n transports,\n name: `VRF Passkey for ${this.extractUsername(nearAccountId)}`,\n registered: new Date().toISOString(),\n syncedAt: new Date().toISOString(),\n vrfPublicKey: vrfPublicKey,\n });\n\n // Store WebAuthn user data with encrypted VRF credentials\n await this.storeUserData({\n nearAccountId,\n deviceNumber: 1,\n clientNearPublicKey: publicKey,\n lastUpdated: Date.now(),\n passkeyCredential: {\n id: credential.id,\n rawId: credentialId\n },\n encryptedVrfKeypair: {\n encryptedVrfDataB64u: encryptedVrfKeypair.encryptedVrfDataB64u,\n chacha20NonceB64u: encryptedVrfKeypair.chacha20NonceB64u,\n },\n version: 2,\n serverEncryptedVrfKeypair: serverEncryptedVrfKeypair ? {\n ciphertextVrfB64u: serverEncryptedVrfKeypair?.ciphertextVrfB64u,\n kek_s_b64u: serverEncryptedVrfKeypair?.kek_s_b64u,\n serverKeyId: serverEncryptedVrfKeypair?.serverKeyId,\n updatedAt: Date.now(),\n } : undefined,\n });\n\n return true;\n });\n }\n\n ///////////////////////////////////////\n // SIGNER WASM WORKER OPERATIONS\n ///////////////////////////////////////\n\n /**\n * Transaction signing with contract verification and progress updates.\n * Demonstrates the \"streaming\" worker pattern similar to SSE.\n *\n * Requires a successful TouchID/biometric prompt before transaction signing in wasm worker\n * Automatically verifies the authentication with the web3authn contract.\n *\n * @param transactions - Transaction payload containing:\n * - receiverId: NEAR account ID receiving the transaction\n * - actions: Array of NEAR actions to execute\n * @param rpcCall: RpcCallPayload containing:\n * - contractId: Web3Authn contract ID for verification\n * - nearRpcUrl: NEAR RPC endpoint URL\n * - nearAccountId: NEAR account ID performing the transaction\n * @param confirmationConfigOverride: Optional confirmation configuration override\n * @param onEvent: Optional callback for progress updates during signing\n * @param onEvent - Optional callback for progress updates during signing\n */\n async signTransactionsWithActions({\n transactions,\n rpcCall,\n signerMode,\n confirmationConfigOverride,\n title,\n body,\n onEvent,\n }: {\n transactions: TransactionInputWasm[],\n rpcCall: RpcCallPayload,\n signerMode: SignerMode;\n // Accept partial override; merging happens in handlers layer\n confirmationConfigOverride?: Partial<ConfirmationConfig>,\n title?: string;\n body?: string;\n onEvent?: (update: onProgressEvents) => void,\n }): Promise<SignTransactionResult[]> {\n return this.withSigningSession({\n sessionId: this.getOrCreateActiveSigningSessionId(toAccountId(rpcCall.nearAccountId)),\n handler: (sessionId) =>\n this.signerWorkerManager.signTransactionsWithActions({\n transactions,\n rpcCall,\n signerMode,\n confirmationConfigOverride,\n title,\n body,\n onEvent,\n sessionId,\n }),\n });\n }\n\n /**\n * Sign AddKey(thresholdPublicKey) for `receiverId === nearAccountId` without running confirmTxFlow.\n *\n * This is a narrowly-scoped, internal-only helper for post-registration activation flows where\n * the caller already has a PRF-bearing credential in memory (e.g., immediately after registration)\n * and wants to avoid an extra TouchID/WebAuthn prompt.\n */\n async signAddKeyThresholdPublicKeyNoPrompt(args: {\n nearAccountId: AccountId | string;\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n wrapKeySalt: string;\n transactionContext: TransactionContext;\n thresholdPublicKey: string;\n relayerVerifyingShareB64u: string;\n clientParticipantId?: number;\n relayerParticipantId?: number;\n deviceNumber?: number;\n onEvent?: (update: onProgressEvents) => void;\n }): Promise<SignTransactionResult> {\n const nearAccountId = toAccountId(args.nearAccountId);\n const wrapKeySalt = args.wrapKeySalt;\n if (!wrapKeySalt) throw new Error('Missing wrapKeySalt for AddKey(thresholdPublicKey) signing');\n if (!args.credential) throw new Error('Missing credential for AddKey(thresholdPublicKey) signing');\n if (!args.transactionContext) throw new Error('Missing transactionContext for no-prompt signing');\n const thresholdPublicKey = ensureEd25519Prefix(args.thresholdPublicKey);\n if (!thresholdPublicKey) throw new Error('Missing thresholdPublicKey for AddKey(thresholdPublicKey) signing');\n const relayerVerifyingShareB64u = args.relayerVerifyingShareB64u;\n if (!relayerVerifyingShareB64u) throw new Error('Missing relayerVerifyingShareB64u for AddKey(thresholdPublicKey) signing');\n\n const deviceNumber = Number(args.deviceNumber);\n const resolvedDeviceNumber = Number.isSafeInteger(deviceNumber) && deviceNumber >= 1\n ? deviceNumber\n : await getLastLoggedInDeviceNumber(nearAccountId, IndexedDBManager.clientDB).catch(() => 1);\n\n const localKeyMaterial = await IndexedDBManager.nearKeysDB.getLocalKeyMaterial(\n nearAccountId,\n resolvedDeviceNumber,\n );\n if (!localKeyMaterial) {\n throw new Error(`No local key material found for account ${nearAccountId} device ${resolvedDeviceNumber}`);\n }\n\n if (localKeyMaterial.wrapKeySalt !== wrapKeySalt) {\n throw new Error('wrapKeySalt mismatch for AddKey(thresholdPublicKey) signing');\n }\n\n return await this.withSigningSession({\n prefix: 'no-prompt-add-threshold-key',\n options: { credential: args.credential, wrapKeySalt },\n handler: async (sessionId) => {\n const response = await this.signerWorkerManager.getContext().sendMessage({\n sessionId,\n message: {\n type: INTERNAL_WORKER_REQUEST_TYPE_SIGN_ADD_KEY_THRESHOLD_PUBLIC_KEY_NO_PROMPT,\n payload: {\n createdAt: Date.now(),\n decryption: {\n encryptedPrivateKeyData: localKeyMaterial.encryptedSk,\n encryptedPrivateKeyChacha20NonceB64u: localKeyMaterial.chacha20NonceB64u,\n },\n transactionContext: args.transactionContext,\n nearAccountId,\n thresholdPublicKey,\n relayerVerifyingShareB64u,\n clientParticipantId: typeof args.clientParticipantId === 'number' ? args.clientParticipantId : undefined,\n relayerParticipantId: typeof args.relayerParticipantId === 'number' ? args.relayerParticipantId : undefined,\n },\n },\n onEvent: args.onEvent,\n });\n\n if (!isSignAddKeyThresholdPublicKeyNoPromptSuccess(response)) {\n throw new Error('AddKey(thresholdPublicKey) signing failed');\n }\n if (!response.payload.success) {\n throw new Error(response.payload.error || 'AddKey(thresholdPublicKey) signing failed');\n }\n\n const signedTransactions = response.payload.signedTransactions || [];\n if (signedTransactions.length !== 1) {\n throw new Error(`Expected 1 signed transaction but received ${signedTransactions.length}`);\n }\n\n const signedTx = signedTransactions[0];\n if (!signedTx || !(signedTx as any).transaction || !(signedTx as any).signature) {\n throw new Error('Incomplete signed transaction data received for AddKey(thresholdPublicKey)');\n }\n return {\n signedTransaction: new SignedTransaction({\n transaction: (signedTx as any).transaction,\n signature: (signedTx as any).signature,\n borsh_bytes: Array.from((signedTx as any).borshBytes || []),\n }),\n nearAccountId: String(nearAccountId),\n logs: response.payload.logs || [],\n };\n },\n });\n }\n\n async signDelegateAction({\n delegate,\n rpcCall,\n signerMode,\n confirmationConfigOverride,\n title,\n body,\n onEvent,\n }: {\n delegate: DelegateActionInput;\n rpcCall: RpcCallPayload;\n signerMode: SignerMode;\n // Accept partial override; merging happens in handlers layer\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n title?: string;\n body?: string;\n onEvent?: (update: onProgressEvents) => void;\n }): Promise<{\n signedDelegate: WasmSignedDelegate;\n hash: string;\n nearAccountId: AccountId;\n logs?: string[];\n }> {\n const nearAccountId = toAccountId(rpcCall.nearAccountId || delegate.senderId);\n const normalizedRpcCall: RpcCallPayload = {\n contractId: rpcCall.contractId || this.tatchiPasskeyConfigs.contractId,\n nearRpcUrl: rpcCall.nearRpcUrl || this.tatchiPasskeyConfigs.nearRpcUrl,\n nearAccountId,\n };\n\n try {\n const activeSessionId = this.getOrCreateActiveSigningSessionId(nearAccountId);\n return await this.withSigningSession({\n sessionId: activeSessionId,\n handler: (sessionId) => {\n console.debug('[WebAuthnManager][delegate] session created', { sessionId });\n return this.signerWorkerManager.signDelegateAction({\n delegate,\n rpcCall: normalizedRpcCall,\n signerMode,\n confirmationConfigOverride,\n title,\n body,\n onEvent,\n sessionId,\n });\n }\n });\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error('[WebAuthnManager][delegate] failed', err);\n throw err;\n }\n }\n\n async signNEP413Message(payload: {\n message: string;\n recipient: string;\n nonce: string;\n state: string | null;\n accountId: AccountId;\n signerMode: SignerMode;\n title?: string;\n body?: string;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n }): Promise<{\n success: boolean;\n accountId: string;\n publicKey: string;\n signature: string;\n state?: string;\n error?: string;\n }> {\n try {\n const activeSessionId = this.getOrCreateActiveSigningSessionId(payload.accountId);\n const contractId = this.tatchiPasskeyConfigs.contractId;\n const nearRpcUrl = (this.tatchiPasskeyConfigs.nearRpcUrl.split(',')[0] || this.tatchiPasskeyConfigs.nearRpcUrl);\n const result = await this.withSigningSession({\n sessionId: activeSessionId,\n handler: (sessionId) =>\n this.signerWorkerManager.signNep413Message({ ...payload, sessionId, contractId, nearRpcUrl }),\n });\n if (result.success) {\n return result;\n } else {\n throw new Error(`NEP-413 signing failed: ${result.error || 'Unknown error'}`);\n }\n } catch (error: any) {\n console.error('WebAuthnManager: NEP-413 signing error:', error);\n return {\n success: false,\n accountId: '',\n publicKey: '',\n signature: '',\n error: error.message || 'Unknown error'\n };\n }\n }\n\n // === COSE OPERATIONS ===\n\n /**\n * Extract COSE public key from WebAuthn attestation object using WASM worker\n */\n async extractCosePublicKey(attestationObjectBase64url: string): Promise<Uint8Array> {\n return await this.signerWorkerManager.extractCosePublicKey(attestationObjectBase64url);\n }\n\n ///////////////////////////////////////\n // PRIVATE KEY EXPORT (Drawer/Modal in sandboxed iframe)\n ///////////////////////////////////////\n\n /** Worker-driven export: two-phase V2 (collect PRF → decrypt → show UI) */\n async exportNearKeypairWithUIWorkerDriven(\n nearAccountId: AccountId,\n options?: { variant?: 'drawer' | 'modal', theme?: 'dark' | 'light' }\n ): Promise<void> {\n await this.withSigningSession({\n prefix: 'export-session', handler: async (sessionId) => {\n // Phase 1: collect PRF via LocalOnly(DECRYPT_PRIVATE_KEY_WITH_PRF) inside VRF worker\n // and derive WrapKeySeed with the vault-provided wrapKeySalt.\n await this.confirmDecryptAndDeriveWrapKeySeed({ nearAccountId, sessionId });\n\n // Phase 2 + 3: decrypt inside signer worker using the reserved session,\n // then show the export viewer UI.\n return this.signerWorkerManager.exportNearKeypairUi({\n nearAccountId,\n variant: options?.variant,\n theme: options?.theme,\n sessionId,\n });\n }\n });\n }\n\n async exportNearKeypairWithUI(\n nearAccountId: AccountId,\n options?: {\n variant?: 'drawer' | 'modal';\n theme?: 'dark' | 'light'\n }\n ): Promise<{ accountId: string; publicKey: string; privateKey: string }> {\n // Route to worker-driven two-phase flow. UI is shown inside the wallet host; no secrets are returned.\n await this.exportNearKeypairWithUIWorkerDriven(nearAccountId, options);\n // Surface the freshest device key for this account to the caller.\n // Prefer last user when it matches the account, else pick the most recently\n // updated user record for this account.\n let userData = await this.getLastUser();\n if (!userData || userData.nearAccountId !== nearAccountId) {\n userData = await IndexedDBManager.clientDB.getLastDBUpdatedUser(nearAccountId);\n }\n return {\n accountId: String(nearAccountId),\n publicKey: userData?.clientNearPublicKey ?? '',\n privateKey: '',\n };\n }\n\n ///////////////////////////////////////\n // REGISTRATION\n ///////////////////////////////////////\n\n async checkCanRegisterUser({\n contractId,\n credential,\n vrfChallenge,\n authenticatorOptions,\n onEvent,\n }: {\n contractId: string,\n credential: WebAuthnRegistrationCredential,\n vrfChallenge: VRFChallenge,\n authenticatorOptions?: AuthenticatorOptions;\n onEvent?: (update: RegistrationEventStep3) => void\n }): Promise<{\n success: boolean;\n verified?: boolean;\n registrationInfo?: any;\n logs?: string[];\n signedTransactionBorsh?: number[];\n error?: string;\n }> {\n return await this.signerWorkerManager.checkCanRegisterUser({\n contractId,\n credential,\n vrfChallenge,\n authenticatorOptions,\n onEvent,\n nearRpcUrl: this.tatchiPasskeyConfigs.nearRpcUrl,\n });\n }\n\n ///////////////////////////////////////\n // ACCOUNT RECOVERY\n ///////////////////////////////////////\n\n /**\n * Recover keypair from authentication credential for account recovery\n * Uses dual PRF outputs to re-derive the same NEAR keypair and re-encrypt it\n * @param challenge - Random challenge for WebAuthn authentication ceremony\n * @param authenticationCredential - The authentication credential with dual PRF outputs\n * @param accountIdHint - Optional account ID hint for recovery\n * @returns Public key and encrypted private key for secure storage\n */\n async recoverKeypairFromPasskey(\n authenticationCredential: WebAuthnAuthenticationCredential,\n accountIdHint?: string,\n ): Promise<{\n publicKey: string;\n encryptedPrivateKey: string;\n /**\n * Base64url-encoded AEAD nonce (ChaCha20-Poly1305) for the encrypted private key.\n */\n chacha20NonceB64u: string;\n accountIdHint?: string;\n wrapKeySalt: string;\n stored?: boolean;\n }> {\n try {\n // Verify we have an authentication credential (not registration)\n if (!authenticationCredential) {\n throw new Error(\n 'Authentication credential required for account recovery. ' +\n 'Use an existing credential with dual PRF outputs to re-derive the same NEAR keypair.'\n );\n }\n\n // Verify dual PRF outputs are available\n const prfResults = authenticationCredential.clientExtensionResults?.prf?.results;\n if (!prfResults?.first || !prfResults?.second) {\n throw new Error('Dual PRF outputs required for account recovery - both AES and Ed25519 PRF outputs must be available');\n }\n\n // Extract PRF.first for WrapKeySeed derivation\n // Orchestrate a VRF-owned signing session with WrapKeySeed derivation, then ask\n // the signer to recover and re-encrypt the NEAR keypair.\n const result = await this.withSigningSession({\n prefix: 'recover',\n options: { credential: authenticationCredential },\n handler: (sessionId) =>\n this.signerWorkerManager.recoverKeypairFromPasskey({\n credential: authenticationCredential,\n accountIdHint,\n sessionId,\n }),\n });\n return result;\n\n } catch (error: any) {\n console.error('WebAuthnManager: Deterministic keypair derivation error:', error);\n throw new Error(`Deterministic keypair derivation failed: ${error.message}`);\n }\n }\n\n async getAuthenticationCredentialsSerializedDualPrf({\n nearAccountId,\n challenge,\n credentialIds,\n }: {\n nearAccountId: AccountId;\n challenge: VRFChallenge,\n credentialIds: string[];\n }): Promise<WebAuthnAuthenticationCredential> {\n // Same as getAuthenticationCredentialsSerialized but returns both PRF outputs (PRF.first + PRF.second).\n return this.touchIdPrompt.getAuthenticationCredentialsSerializedDualPrf({\n nearAccountId,\n challenge,\n allowCredentials: credentialIds.map(id => ({\n id: id,\n type: 'public-key',\n transports: ['internal', 'hybrid', 'usb', 'ble'] as AuthenticatorTransport[]\n })),\n });\n }\n\n /**\n * Sign transaction with raw private key\n * for key replacement in device linking\n * No TouchID/PRF required - uses provided private key directly\n */\n async signTransactionWithKeyPair({\n nearPrivateKey,\n signerAccountId,\n receiverId,\n nonce,\n blockHash,\n actions\n }: {\n nearPrivateKey: string;\n signerAccountId: string;\n receiverId: string;\n nonce: string;\n blockHash: string;\n actions: ActionArgsWasm[];\n }): Promise<{\n signedTransaction: SignedTransaction;\n logs?: string[];\n }> {\n return await this.signerWorkerManager.signTransactionWithKeyPair({\n nearPrivateKey,\n signerAccountId,\n receiverId,\n nonce,\n blockHash,\n actions\n });\n }\n\n // ==============================\n // Threshold Signing\n // ==============================\n\n /**\n * Derive the deterministic threshold client verifying share (2-of-2 ed25519) from WrapKeySeed.\n * This is safe to call during registration because it only requires the PRF-bearing credential\n * (no on-chain verification needed) and returns public material only.\n */\n async deriveThresholdEd25519ClientVerifyingShareFromCredential(args: {\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n nearAccountId: AccountId | string;\n wrapKeySalt?: string;\n }): Promise<{\n success: boolean;\n nearAccountId: string;\n clientVerifyingShareB64u: string;\n wrapKeySalt: string;\n error?: string;\n }> {\n const nearAccountId = toAccountId(args.nearAccountId);\n try {\n return await this.withSigningSession({\n prefix: 'threshold-client-share',\n options: { credential: args.credential, wrapKeySalt: args.wrapKeySalt },\n handler: (sessionId) =>\n this.signerWorkerManager.deriveThresholdEd25519ClientVerifyingShare({\n sessionId,\n nearAccountId,\n }),\n });\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return {\n success: false,\n nearAccountId,\n clientVerifyingShareB64u: '',\n wrapKeySalt: '',\n error: message,\n };\n }\n }\n\n /**\n * Threshold key enrollment (post-registration):\n * prompts for a dual-PRF WebAuthn authentication to obtain PRF.first/second,\n * then runs the `/threshold-ed25519/keygen` enrollment flow.\n *\n * This is intended to be called only after the passkey is registered on-chain.\n */\n async enrollThresholdEd25519KeyPostRegistration(args: {\n nearAccountId: AccountId | string;\n deviceNumber?: number;\n }): Promise<{\n success: boolean;\n publicKey: string;\n relayerKeyId: string;\n wrapKeySalt: string;\n error?: string;\n }> {\n const nearAccountId = toAccountId(args.nearAccountId);\n\n try {\n const rpId = this.touchIdPrompt.getRpId();\n if (!rpId) throw new Error('Missing rpId for WebAuthn VRF challenge');\n\n // Generate a fresh VRF challenge for a dual-PRF authentication prompt (PRF.first + PRF.second).\n const block = await this.nearClient.viewBlock({ finality: 'final' } as any);\n const blockHeight = String((block as any)?.header?.height ?? '');\n const blockHash = String((block as any)?.header?.hash ?? '');\n if (!blockHeight || !blockHash) throw new Error('Failed to fetch NEAR block context for VRF challenge');\n\n const vrfChallenge = await this.vrfWorkerManager.generateVrfChallengeOnce({\n userId: nearAccountId,\n rpId,\n blockHeight,\n blockHash,\n });\n\n const authenticators = await this.getAuthenticatorsByUser(nearAccountId);\n if (!authenticators.length) {\n throw new Error(`No passkey authenticators found for account ${nearAccountId}`);\n }\n\n const authCredential = await this.collectAuthenticationCredentialForVrfChallenge({\n nearAccountId,\n vrfChallenge,\n includeSecondPrfOutput: true,\n });\n\n return await this.enrollThresholdEd25519Key({\n credential: authCredential,\n nearAccountId,\n deviceNumber: args.deviceNumber,\n });\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return { success: false, publicKey: '', relayerKeyId: '', wrapKeySalt: '', error: message };\n }\n }\n\n /**\n * Threshold key rotation (post-registration):\n * - keygen (new relayerKeyId + publicKey)\n * - AddKey(new threshold publicKey)\n * - DeleteKey(old threshold publicKey)\n *\n * Uses the local signer key for AddKey/DeleteKey, and requires the account to already\n * have a stored `threshold_ed25519_2p_v1` key material entry for the target device.\n */\n async rotateThresholdEd25519KeyPostRegistration(args: {\n nearAccountId: AccountId | string;\n deviceNumber?: number;\n }): Promise<{\n success: boolean;\n oldPublicKey: string;\n oldRelayerKeyId: string;\n publicKey: string;\n relayerKeyId: string;\n wrapKeySalt: string;\n deleteOldKeyAttempted: boolean;\n deleteOldKeySuccess: boolean;\n warning?: string;\n error?: string;\n }> {\n const nearAccountId = toAccountId(args.nearAccountId);\n\n let oldPublicKey = '';\n let oldRelayerKeyId = '';\n\n try {\n const deviceNumber = Number(args.deviceNumber);\n const resolvedDeviceNumber = Number.isSafeInteger(deviceNumber) && deviceNumber >= 1\n ? deviceNumber\n : await getLastLoggedInDeviceNumber(nearAccountId, IndexedDBManager.clientDB).catch(() => 1);\n\n const existing = await IndexedDBManager.nearKeysDB.getThresholdKeyMaterial(nearAccountId, resolvedDeviceNumber);\n if (!existing) {\n throw new Error(\n `No threshold key material found for account ${nearAccountId} device ${resolvedDeviceNumber}. Call enrollThresholdEd25519Key() first.`,\n );\n }\n oldPublicKey = existing.publicKey;\n oldRelayerKeyId = existing.relayerKeyId;\n\n const enrollment = await this.enrollThresholdEd25519KeyPostRegistration({\n nearAccountId,\n deviceNumber: resolvedDeviceNumber,\n });\n if (!enrollment.success) {\n throw new Error(enrollment.error || 'Threshold keygen/enrollment failed');\n }\n\n return await rotateThresholdEd25519KeyPostRegistrationHandler(\n {\n nearClient: this.nearClient,\n contractId: this.tatchiPasskeyConfigs.contractId,\n nearRpcUrl: this.tatchiPasskeyConfigs.nearRpcUrl,\n signTransactionsWithActions: (params) => this.signTransactionsWithActions(params),\n },\n {\n nearAccountId,\n deviceNumber: resolvedDeviceNumber,\n oldPublicKey,\n oldRelayerKeyId,\n newPublicKey: enrollment.publicKey,\n newRelayerKeyId: enrollment.relayerKeyId,\n wrapKeySalt: enrollment.wrapKeySalt,\n },\n );\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return {\n success: false,\n oldPublicKey,\n oldRelayerKeyId,\n publicKey: '',\n relayerKeyId: '',\n wrapKeySalt: '',\n deleteOldKeyAttempted: false,\n deleteOldKeySuccess: false,\n error: message,\n };\n }\n }\n\n /**\n * Threshold key enrollment (2-of-2): deterministically derive the client verifying share\n * from WrapKeySeed and register the corresponding relayer share via `/threshold-ed25519/keygen`.\n *\n * Stores a v3 vault entry of kind `threshold_ed25519_2p_v1` (breaking; no migration).\n */\n async enrollThresholdEd25519Key(args: {\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\n nearAccountId: AccountId | string;\n deviceNumber?: number;\n }): Promise<{\n success: boolean;\n publicKey: string;\n relayerKeyId: string;\n wrapKeySalt: string;\n error?: string;\n }> {\n const nearAccountId = toAccountId(args.nearAccountId);\n const relayerUrl = this.tatchiPasskeyConfigs.relayer.url;\n\n try {\n if (!relayerUrl) throw new Error('Missing relayer url (configs.relayer.url)');\n if (!args.credential) throw new Error('Missing credential');\n\n const deviceNumber = Number(args.deviceNumber);\n const resolvedDeviceNumber = Number.isSafeInteger(deviceNumber) && deviceNumber >= 1\n ? deviceNumber\n : await getLastLoggedInDeviceNumber(nearAccountId, IndexedDBManager.clientDB).catch(() => 1);\n\n const keygen = await this.withSigningSession({\n prefix: 'threshold-keygen',\n options: { credential: args.credential },\n handler: (sessionId) =>\n enrollThresholdEd25519KeyHandler(\n {\n nearClient: this.nearClient,\n vrfWorkerManager: this.vrfWorkerManager,\n signerWorkerManager: this.signerWorkerManager,\n touchIdPrompt: this.touchIdPrompt,\n relayerUrl,\n },\n { sessionId, nearAccountId },\n ),\n });\n\n if (!keygen.success) {\n throw new Error(keygen.error || 'Threshold keygen failed');\n }\n\n const publicKey = keygen.publicKey;\n const clientVerifyingShareB64u = keygen.clientVerifyingShareB64u;\n const relayerKeyId = keygen.relayerKeyId;\n const relayerVerifyingShareB64u = keygen.relayerVerifyingShareB64u;\n if (!clientVerifyingShareB64u) throw new Error('Threshold keygen returned empty clientVerifyingShareB64u');\n\n // Activate threshold enrollment on-chain by submitting AddKey(publicKey) signed with the local key.\n const localKeyMaterial = await IndexedDBManager.nearKeysDB.getLocalKeyMaterial(nearAccountId, resolvedDeviceNumber);\n if (!localKeyMaterial) {\n throw new Error(`No local key material found for account ${nearAccountId} device ${resolvedDeviceNumber}`);\n }\n\n // If the key is already present, skip AddKey and just persist local threshold metadata.\n const alreadyActive = await hasAccessKey(this.nearClient, nearAccountId, publicKey, { attempts: 1, delayMs: 0 });\n if (!alreadyActive) {\n this.nonceManager.initializeUser(nearAccountId, localKeyMaterial.publicKey);\n const txContext = await this.nonceManager.getNonceBlockHashAndHeight(this.nearClient, { force: true });\n\n const signed = await this.signAddKeyThresholdPublicKeyNoPrompt({\n nearAccountId,\n credential: args.credential,\n wrapKeySalt: localKeyMaterial.wrapKeySalt,\n transactionContext: txContext,\n thresholdPublicKey: publicKey,\n relayerVerifyingShareB64u,\n clientParticipantId: keygen.clientParticipantId,\n relayerParticipantId: keygen.relayerParticipantId,\n deviceNumber: resolvedDeviceNumber,\n });\n\n const signedTx = signed?.signedTransaction;\n if (!signedTx) throw new Error('Failed to sign AddKey(thresholdPublicKey) transaction');\n\n await this.nearClient.sendTransaction(signedTx, DEFAULT_WAIT_STATUS.thresholdAddKey);\n\n const activated = await hasAccessKey(this.nearClient, nearAccountId, publicKey);\n if (!activated) throw new Error('Threshold access key not found on-chain after AddKey');\n }\n\n const keyMaterial: ThresholdEd25519_2p_V1Material = {\n kind: 'threshold_ed25519_2p_v1',\n nearAccountId,\n deviceNumber: resolvedDeviceNumber,\n publicKey,\n wrapKeySalt: keygen.wrapKeySalt,\n relayerKeyId,\n clientShareDerivation: 'prf_first_v1',\n participants: buildThresholdEd25519Participants2pV1({\n clientParticipantId: keygen.clientParticipantId,\n relayerParticipantId: keygen.relayerParticipantId,\n relayerKeyId,\n relayerUrl,\n clientVerifyingShareB64u,\n relayerVerifyingShareB64u,\n clientShareDerivation: 'prf_first_v1',\n }),\n timestamp: Date.now(),\n };\n await IndexedDBManager.nearKeysDB.storeKeyMaterial(keyMaterial);\n\n return {\n success: true,\n publicKey,\n relayerKeyId,\n wrapKeySalt: keygen.wrapKeySalt,\n };\n } catch (error: unknown) {\n const message = String((error as { message?: unknown })?.message ?? error);\n return { success: false, publicKey: '', relayerKeyId: '', wrapKeySalt: '', error: message };\n }\n }\n\n // ==============================\n // USER SETTINGS\n // ==============================\n\n /** * Get user preferences manager */\n getUserPreferences(): UserPreferencesManager {\n return this.userPreferencesManager;\n }\n\n /** * Clean up resources */\n destroy(): void {\n if (this.userPreferencesManager) {\n this.userPreferencesManager.destroy();\n }\n if (this.nonceManager) {\n this.nonceManager.clear();\n }\n this.activeSigningSessionIds.clear();\n }\n\n}\n","/**\n * Offline Export App (minimal, zero-config)\n *\n * Runs under `/offline-export/` on the wallet origin and reuses the\n * WebAuthnManager.exportNearKeypairWithUI() VRF-driven flow to decrypt and\n * display the private key export viewer. No network requests are made.\n *\n * See `docs/vrf2-refactor-export-keys.md` for the canonical export flow design.\n */\nimport { IndexedDBManager } from '../IndexedDBManager';\nimport { MinimalNearClient } from '../NearClient';\nimport { toAccountId } from '../types/accountIds';\nimport { OFFLINE_EXPORT_DONE, OFFLINE_EXPORT_ERROR } from './messages';\nimport type { TatchiConfigsInput } from '../types/tatchi';\nimport { WebAuthnManager } from '../WebAuthnManager';\nimport { TouchIdPrompt } from '../WebAuthnManager/touchIdPrompt';\nimport { createRandomVRFChallenge, type VRFChallenge } from '../types/vrf-worker';\nimport { buildConfigsFromEnv } from '../defaultConfigs';\n\nasync function registerServiceWorker(): Promise<void> {\n if (!('serviceWorker' in navigator)) return;\n // Register and await ready() only in this route; SW is in-scope here\n await navigator.serviceWorker\n .register('/offline-export/sw.js', { scope: '/offline-export/' })\n .catch(() => {});\n await navigator.serviceWorker.ready.catch(() => {});\n}\n\nasync function prewarmSdkAssets(): Promise<void> {\n // Only attempt network warm-up when online; SW will cache responses\n if (!navigator.onLine) return\n try {\n const resp = await fetch('/offline-export/precache.manifest.json', { cache: 'no-cache' })\n const all: string[] = resp.ok ? (await resp.json()) : []\n const priority = new Set<string>([\n '/offline-export/offline-export-app.js',\n '/sdk/offline-export-app.js',\n '/sdk/offline-export.css',\n '/sdk/export-private-key-viewer.js',\n '/sdk/iframe-export-bootstrap.js',\n '/sdk/export-viewer.css',\n '/sdk/export-iframe.css',\n '/offline-export/workers/web3authn-signer.worker.js',\n '/offline-export/workers/web3authn-vrf.worker.js',\n '/offline-export/workers/wasm_signer_worker_bg.wasm',\n '/offline-export/workers/wasm_vrf_worker_bg.wasm',\n '/sdk/workers/web3authn-signer.worker.js',\n '/sdk/workers/web3authn-vrf.worker.js',\n '/sdk/workers/wasm_signer_worker_bg.wasm',\n '/sdk/workers/wasm_vrf_worker_bg.wasm',\n ])\n const pri = Array.from(priority)\n const rest = all.filter((u) => !priority.has(u))\n await Promise.allSettled(pri.map((u) => fetch(u).then(() => void 0)))\n // Warm the remaining entries opportunistically\n const schedule = () => void Promise.allSettled(rest.map((u) => fetch(u).then(() => void 0)))\n try { (window as any).requestIdleCallback ? (window as any).requestIdleCallback(schedule, { timeout: 8000 }) : setTimeout(schedule, 800) } catch { setTimeout(schedule, 800) }\n } catch {}\n\n // Fallback: proactively cache any /sdk/* scripts that the offline page\n // already loaded as part of its initial bundle (e.g. common-*.js vendor chunks).\n // These are requested before the SW takes control, so we re-fetch them once\n // the SW is ready to ensure they are present in the offline cache.\n try {\n const origin = window.location.origin;\n const scriptPaths = Array.from(document.querySelectorAll('script[src]'))\n .map((el) => (el as HTMLScriptElement).src)\n .filter((src) => typeof src === 'string' && src.startsWith(origin + '/sdk/'))\n .map((src) => new URL(src).pathname);\n if (scriptPaths.length > 0) {\n await Promise.allSettled(\n scriptPaths.map((p) => fetch(p).then(() => void 0))\n );\n }\n } catch {}\n}\n\nfunction autoStartIfSingleUser(users: any[], selectedAccount: string, startExport: (acc: string) => Promise<void>): void {\n if (Array.isArray(users) && users.length === 1 && typeof selectedAccount === 'string' && selectedAccount) {\n setTimeout(() => { void startExport(selectedAccount) }, 0)\n }\n}\n\nfunction renderShell(message: string, canExport = false): HTMLButtonElement | null {\n document.documentElement.classList.add('w3a-transparent');\n document.body.classList.add('w3a-transparent');\n const root = document.createElement('div');\n root.className = 'offline-root'\n const h = document.createElement('h1');\n h.textContent = 'Offline Export';\n h.className = 'offline-title'\n const p = document.createElement('p');\n p.textContent = message;\n p.className = 'offline-desc'\n const info = document.createElement('div');\n info.className = 'offline-info';\n try {\n const tick = document.createElement('span');\n tick.className = 'offline-info-tick';\n tick.textContent = '✓';\n const label = document.createElement('span');\n label.textContent = ' Wallet origin: ';\n const url = document.createElement('a');\n url.className = 'offline-info-url';\n const origin = window.location.origin;\n url.href = origin;\n url.textContent = origin;\n url.target = '_blank';\n url.rel = 'noopener noreferrer';\n info.appendChild(tick);\n info.appendChild(label);\n info.appendChild(url);\n } catch {\n info.textContent = '✓ Wallet origin: (unknown)';\n }\n const btn = document.createElement('button');\n btn.textContent = 'Export My Key';\n btn.className = 'offline-btn'\n btn.disabled = !canExport;\n root.appendChild(h);\n root.appendChild(p);\n root.appendChild(info);\n root.appendChild(btn);\n document.body.appendChild(root);\n return canExport ? btn : null;\n}\n\nasync function main(): Promise<void> {\n await registerServiceWorker();\n // Best-effort: warm critical SDK assets so offline flow is reliable.\n // Do not block first paint — fire-and-forget.\n void prewarmSdkAssets();\n try {\n // Ensure worker scripts resolve under SW scope so their subresource fetches (WASM) are controlled\n (window as any).__W3A_SIGNER_WORKER_URL__ = '/offline-export/workers/web3authn-signer.worker.js'\n ;(window as any).__W3A_VRF_WORKER_URL__ = '/offline-export/workers/web3authn-vrf.worker.js'\n const rpOverrideFromMeta = (() => {\n const m = document.querySelector('meta[name=\"tatchi-rpid-base\"]') as HTMLMetaElement | null;\n const v = (m?.content || '').trim();\n return v || undefined;\n })();\n const deriveBaseDomain = (host: string): string | undefined => {\n const parts = (host || '').split('.');\n // Heuristic: use registrable suffix for dev hosts like wallet.example.localhost\n return parts.length >= 3 ? parts.slice(1).join('.') : undefined;\n };\n const inferredBase = deriveBaseDomain(window.location.hostname);\n const effectiveRpIdOverride = rpOverrideFromMeta || inferredBase;\n // Detect last user (same origin IndexedDB)\n const last = await IndexedDBManager.clientDB.getLastUser();\n const users = await IndexedDBManager.clientDB.getAllUsers().catch(() => []);\n\n // Optional preselected account via query string\n const qs = new URLSearchParams((window.location && window.location.search) || '')\n const qsAccountRaw = (qs.get('accountId') || '').trim()\n const qsAccount = qsAccountRaw ? String(toAccountId(qsAccountRaw)) : ''\n\n // Container: message + optional account selector + button + status line\n const defaultAccount = qsAccount || (last?.nearAccountId || '')\n if (!defaultAccount) {\n renderShell('No local account found on this device. Open the wallet once online on this device to prime offline export.');\n return;\n }\n const btn = renderShell('Authenticate with Touch ID/biometrics to export keys offline.', true);\n if (!btn) return;\n const container = btn.parentElement as HTMLDivElement;\n\n // Optional account selector when multiple local users exist\n let selectedAccount = defaultAccount as string;\n if (Array.isArray(users) && users.length > 1) {\n const label = document.createElement('label');\n label.textContent = 'Choose account:';\n label.className = 'offline-label'\n const sel = document.createElement('select');\n sel.className = 'offline-select'\n for (const u of users) {\n const opt = document.createElement('option');\n opt.value = (u as any).nearAccountId;\n opt.textContent = (u as any).nearAccountId;\n if ((u as any).nearAccountId === selectedAccount) opt.selected = true;\n sel.appendChild(opt);\n }\n sel.addEventListener('change', () => { selectedAccount = sel.value; statusEl.textContent = ''; });\n container.insertBefore(sel, btn);\n container.insertBefore(label, sel);\n }\n\n // Status line for inline errors/info\n const statusEl = document.createElement('div');\n statusEl.className = 'offline-status'\n container.appendChild(statusEl);\n\n // Pre-flight: soft-check for local authenticators (do not block)\n async function ensureLocalAuthenticators(acc: string): Promise<any[]> {\n try {\n const authenticators = await IndexedDBManager.clientDB.getAuthenticatorsByUser(acc as any);\n if (!Array.isArray(authenticators) || authenticators.length === 0) {\n console.warn('[offline-export] No local passkeys in IndexedDB; proceeding (resident credentials may still be available)');\n statusEl.textContent = 'Tip: open the wallet on this device once online to prime offline export. If a passkey exists on this device, you can still proceed.';\n return [];\n }\n return authenticators;\n } catch (e) {\n console.warn('[offline-export] Failed to read authenticators; proceeding anyway', e);\n return [];\n }\n }\n\n let started = false;\n const defaultBtnLabel = btn.textContent || 'Export My Key';\n const startExport = async (account: string) => {\n if (started) return;\n started = true;\n btn.disabled = true;\n btn.classList.add('loading');\n try { btn.textContent = 'Exporting…'; btn.setAttribute('aria-busy', 'true'); } catch {}\n statusEl.textContent = '';\n try {\n // Soft-check (non-blocking) — we may still have resident credentials\n const authenticators = await ensureLocalAuthenticators(account);\n\n // Instantiate WebAuthnManager with minimal offline configs. No network RPC is used in export flow.\n const near = new MinimalNearClient('https://rpc.invalid.local');\n const offlineConfigsInput: TatchiConfigsInput = {\n nearRpcUrl: 'https://rpc.invalid.local',\n nearNetwork: 'testnet',\n contractId: 'w3a-v1.testnet',\n walletTheme: 'dark',\n iframeWallet: effectiveRpIdOverride ? { rpIdOverride: effectiveRpIdOverride } : undefined,\n relayer: {\n url: 'https://rpc.invalid.local',\n },\n };\n const offlineConfigs = buildConfigsFromEnv(offlineConfigsInput);\n const webAuthnManager = new WebAuthnManager(offlineConfigs, near);\n console.debug('[offline-export] rpId (hostname):', window.location.hostname);\n if (effectiveRpIdOverride) {\n console.debug('[offline-export] rpIdOverride:', effectiveRpIdOverride);\n }\n try {\n // Attempt direct export using WebAuthnManager's worker-driven flow\n await webAuthnManager.exportNearKeypairWithUI(toAccountId(account), {\n variant: 'drawer',\n theme: 'dark',\n });\n } catch (err: any) {\n const msg = String(err?.message || err || '');\n const isMissingLocalKeyMaterial = msg.includes('Missing local key material for export');\n const isAeadDecryptMismatch =\n msg.includes('Decryption failed: Decryption error: aead::Error') || msg.includes('aead::Error');\n\n if (isMissingLocalKeyMaterial || isAeadDecryptMismatch) {\n // Attempt local recovery of key material from passkey, then retry\n statusEl.textContent = isAeadDecryptMismatch\n ? 'Decryption failed. Attempting recovery with your passkey…'\n : 'Missing local key material. Attempting recovery with your passkey…';\n const tip = new TouchIdPrompt(effectiveRpIdOverride);\n const challenge = createRandomVRFChallenge() as VRFChallenge;\n const allowCredentials = Array.isArray(authenticators) && authenticators.length > 0\n ? authenticators.map((a: any) => ({ id: a.credentialId, type: 'public-key', transports: a.transports as any }))\n : [];\n const authCred = await tip.getAuthenticationCredentialsSerializedDualPrf({\n nearAccountId: account,\n challenge,\n allowCredentials,\n });\n // Recover NEAR keypair using WebAuthnManager's recovery flow\n const rec = await webAuthnManager.recoverKeypairFromPasskey(authCred, account);\n if (!rec.wrapKeySalt) {\n throw new Error('Missing wrapKeySalt in recovered key material; re-register to upgrade vault format.');\n }\n // Store encrypted key locally for this device. Prefer the last logged-in\n // device for this account; fall back to device 1 for legacy cases.\n const accountId = toAccountId(account);\n const [last, latest] = await Promise.all([\n IndexedDBManager.clientDB.getLastUser().catch(() => null),\n IndexedDBManager.clientDB.getLastDBUpdatedUser(accountId).catch(() => null),\n ]);\n const deviceNumber =\n (last && last.nearAccountId === accountId && typeof last.deviceNumber === 'number')\n ? last.deviceNumber\n : (latest && latest.nearAccountId === accountId && typeof latest.deviceNumber === 'number')\n ? latest.deviceNumber\n : 1;\n\n // Safety check: only overwrite local vault material if the recovered public key\n // matches what we already have for this account/device.\n const existing = await IndexedDBManager.clientDB.getUserByDevice(accountId, deviceNumber).catch(() => null);\n if (isAeadDecryptMismatch && !existing) {\n throw new Error(\n `Decryption failed and no local user record was found for '${account}'. ` +\n 'Open the wallet once online on this device to restore local vault state, then retry offline export.'\n );\n }\n const expectedPublicKey = String(existing?.clientNearPublicKey || '');\n if (expectedPublicKey && expectedPublicKey !== rec.publicKey) {\n throw new Error(\n `Selected passkey does not match the existing key for '${account}'. ` +\n 'Please select the correct passkey for this account and try again.'\n );\n }\n\n await IndexedDBManager.nearKeysDB.storeKeyMaterial({\n kind: 'local_near_sk_v3',\n nearAccountId: account,\n deviceNumber,\n publicKey: rec.publicKey,\n encryptedSk: rec.encryptedPrivateKey,\n chacha20NonceB64u: rec.chacha20NonceB64u,\n wrapKeySalt: rec.wrapKeySalt,\n timestamp: Date.now(),\n });\n // Upsert public key if missing for this device\n if (!existing?.clientNearPublicKey) {\n try { await IndexedDBManager.clientDB.updateUser(accountId, { clientNearPublicKey: rec.publicKey }); } catch {}\n }\n statusEl.textContent = 'Recovered local key material. Opening export viewer…';\n await webAuthnManager.exportNearKeypairWithUI(toAccountId(account), {\n variant: 'drawer',\n theme: 'dark',\n });\n } else {\n throw err;\n }\n }\n // Notify parent (overlay controllers) that the export UI has been shown\n window.parent?.postMessage?.({ type: OFFLINE_EXPORT_DONE, nearAccountId: account }, '*');\n } catch (e: any) {\n console.error('[offline-export] export failed', e);\n const msg = String(e?.message || e || '');\n if (msg.includes('User cancelled secure confirm request')) {\n // Differentiate common NotAllowedError path vs explicit cancel\n statusEl.textContent = `No matching passkeys for this origin or the prompt was cancelled. Ensure this device has a passkey for '${account}' on ${window.location.hostname}, then try again.`;\n } else if (msg.includes('NotAllowedError')) {\n statusEl.textContent = `No matching passkeys available for '${account}' on this device.`;\n } else if (msg.includes('Missing local key material')) {\n statusEl.textContent = 'Missing local key material for export. Open the wallet on this device once online to prime offline export.';\n } else {\n statusEl.textContent = 'Export failed: ' + msg;\n }\n window.parent?.postMessage?.({ type: OFFLINE_EXPORT_ERROR, error: msg }, '*');\n } finally {\n btn.disabled = false;\n btn.classList.remove('loading');\n try { btn.textContent = defaultBtnLabel; btn.removeAttribute('aria-busy'); } catch {}\n started = false;\n }\n };\n\n // Click handler uses current selected account\n btn.addEventListener('click', async () => { await startExport(selectedAccount); });\n } catch (e) {\n console.error('[offline-export] bootstrap failed', e);\n renderShell('Failed to initialize offline export on this device.');\n }\n}\n\nif (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => void main());\n} else {\n void main();\n}\n\nexport {}\n"],"x_google_ignoreList":[0,2,3],"mappings":"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"}