@tatchi-xyz/sdk 0.17.0 → 0.19.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 (162) hide show
  1. package/dist/cjs/core/EmailRecovery/emailRecoveryPendingStore.js +69 -0
  2. package/dist/cjs/core/EmailRecovery/emailRecoveryPendingStore.js.map +1 -0
  3. package/dist/cjs/core/EmailRecovery/index.js +32 -20
  4. package/dist/cjs/core/EmailRecovery/index.js.map +1 -1
  5. package/dist/cjs/core/TatchiPasskey/emailRecovery.js +507 -452
  6. package/dist/cjs/core/TatchiPasskey/emailRecovery.js.map +1 -1
  7. package/dist/cjs/core/TatchiPasskey/index.js +1 -0
  8. package/dist/cjs/core/TatchiPasskey/index.js.map +1 -1
  9. package/dist/cjs/core/TatchiPasskey/relay.js +23 -1
  10. package/dist/cjs/core/TatchiPasskey/relay.js.map +1 -1
  11. package/dist/cjs/core/WalletIframe/client/IframeTransport.js +0 -7
  12. package/dist/cjs/core/WalletIframe/client/IframeTransport.js.map +1 -1
  13. package/dist/cjs/core/WalletIframe/client/router.js +6 -2
  14. package/dist/cjs/core/WalletIframe/client/router.js.map +1 -1
  15. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js +1 -1
  16. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js.map +1 -1
  17. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js +1 -1
  18. package/dist/cjs/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js.map +1 -1
  19. package/dist/cjs/core/WebAuthnManager/index.js +23 -0
  20. package/dist/cjs/core/WebAuthnManager/index.js.map +1 -1
  21. package/dist/cjs/core/rpcCalls.js +8 -0
  22. package/dist/cjs/core/rpcCalls.js.map +1 -1
  23. package/dist/cjs/index.js +6 -2
  24. package/dist/cjs/index.js.map +1 -1
  25. package/dist/cjs/react/components/AccountMenuButton/{LinkedDevicesModal-B6api181.css → LinkedDevicesModal-CSSowiHP.css} +1 -1
  26. package/dist/{esm/react/components/AccountMenuButton/LinkedDevicesModal-B6api181.css.map → cjs/react/components/AccountMenuButton/LinkedDevicesModal-CSSowiHP.css.map} +1 -1
  27. package/dist/cjs/react/components/AccountMenuButton/{ProfileDropdown-B-DrG_u5.css → ProfileDropdown-CEPMZ1gY.css} +1 -1
  28. package/dist/{esm/react/components/AccountMenuButton/ProfileDropdown-B-DrG_u5.css.map → cjs/react/components/AccountMenuButton/ProfileDropdown-CEPMZ1gY.css.map} +1 -1
  29. package/dist/cjs/react/components/AccountMenuButton/{Web3AuthProfileButton-BnZDUeCL.css → Web3AuthProfileButton-DopOg7Xc.css} +1 -1
  30. package/dist/cjs/react/components/AccountMenuButton/{Web3AuthProfileButton-BnZDUeCL.css.map → Web3AuthProfileButton-DopOg7Xc.css.map} +1 -1
  31. package/dist/cjs/react/components/AccountMenuButton/icons/{TouchIcon-CAGCi8MY.css → TouchIcon-BQWentvJ.css} +1 -1
  32. package/dist/cjs/react/components/AccountMenuButton/icons/{TouchIcon-CAGCi8MY.css.map → TouchIcon-BQWentvJ.css.map} +1 -1
  33. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-CNNxVj4L.css → PasskeyAuthMenu-DwrzWMYx.css} +1 -1
  34. package/dist/cjs/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-CNNxVj4L.css.map → PasskeyAuthMenu-DwrzWMYx.css.map} +1 -1
  35. package/dist/cjs/react/components/{ShowQRCode-nZhZSaba.css → ShowQRCode-CCN4h6Uv.css} +1 -1
  36. package/dist/cjs/react/components/{ShowQRCode-nZhZSaba.css.map → ShowQRCode-CCN4h6Uv.css.map} +1 -1
  37. package/dist/cjs/react/hooks/usePreconnectWalletAssets.js +27 -32
  38. package/dist/cjs/react/hooks/usePreconnectWalletAssets.js.map +1 -1
  39. package/dist/cjs/react/sdk/src/core/EmailRecovery/emailRecoveryPendingStore.js +69 -0
  40. package/dist/cjs/react/sdk/src/core/EmailRecovery/emailRecoveryPendingStore.js.map +1 -0
  41. package/dist/cjs/react/sdk/src/core/EmailRecovery/index.js +32 -20
  42. package/dist/cjs/react/sdk/src/core/EmailRecovery/index.js.map +1 -1
  43. package/dist/cjs/react/sdk/src/core/TatchiPasskey/emailRecovery.js +507 -452
  44. package/dist/cjs/react/sdk/src/core/TatchiPasskey/emailRecovery.js.map +1 -1
  45. package/dist/cjs/react/sdk/src/core/TatchiPasskey/index.js +1 -0
  46. package/dist/cjs/react/sdk/src/core/TatchiPasskey/index.js.map +1 -1
  47. package/dist/cjs/react/sdk/src/core/TatchiPasskey/relay.js +23 -1
  48. package/dist/cjs/react/sdk/src/core/TatchiPasskey/relay.js.map +1 -1
  49. package/dist/cjs/react/sdk/src/core/WalletIframe/client/IframeTransport.js +0 -7
  50. package/dist/cjs/react/sdk/src/core/WalletIframe/client/IframeTransport.js.map +1 -1
  51. package/dist/cjs/react/sdk/src/core/WalletIframe/client/router.js +6 -2
  52. package/dist/cjs/react/sdk/src/core/WalletIframe/client/router.js.map +1 -1
  53. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js +1 -1
  54. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js.map +1 -1
  55. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js +1 -1
  56. package/dist/cjs/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js.map +1 -1
  57. package/dist/cjs/react/sdk/src/core/WebAuthnManager/index.js +23 -0
  58. package/dist/cjs/react/sdk/src/core/WebAuthnManager/index.js.map +1 -1
  59. package/dist/cjs/react/sdk/src/core/rpcCalls.js +8 -0
  60. package/dist/cjs/react/sdk/src/core/rpcCalls.js.map +1 -1
  61. package/dist/esm/core/EmailRecovery/emailRecoveryPendingStore.js +63 -0
  62. package/dist/esm/core/EmailRecovery/emailRecoveryPendingStore.js.map +1 -0
  63. package/dist/esm/core/EmailRecovery/index.js +28 -21
  64. package/dist/esm/core/EmailRecovery/index.js.map +1 -1
  65. package/dist/esm/core/TatchiPasskey/emailRecovery.js +507 -452
  66. package/dist/esm/core/TatchiPasskey/emailRecovery.js.map +1 -1
  67. package/dist/esm/core/TatchiPasskey/index.js +2 -1
  68. package/dist/esm/core/TatchiPasskey/index.js.map +1 -1
  69. package/dist/esm/core/TatchiPasskey/relay.js +23 -1
  70. package/dist/esm/core/TatchiPasskey/relay.js.map +1 -1
  71. package/dist/esm/core/WalletIframe/client/IframeTransport.js +0 -7
  72. package/dist/esm/core/WalletIframe/client/IframeTransport.js.map +1 -1
  73. package/dist/esm/core/WalletIframe/client/router.js +7 -3
  74. package/dist/esm/core/WalletIframe/client/router.js.map +1 -1
  75. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js +1 -1
  76. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js.map +1 -1
  77. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js +1 -1
  78. package/dist/esm/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js.map +1 -1
  79. package/dist/esm/core/WebAuthnManager/index.js +23 -0
  80. package/dist/esm/core/WebAuthnManager/index.js.map +1 -1
  81. package/dist/esm/core/rpcCalls.js +8 -1
  82. package/dist/esm/core/rpcCalls.js.map +1 -1
  83. package/dist/esm/index.js +4 -1
  84. package/dist/esm/index.js.map +1 -1
  85. package/dist/esm/react/components/AccountMenuButton/{LinkedDevicesModal-B6api181.css → LinkedDevicesModal-CSSowiHP.css} +1 -1
  86. package/dist/{cjs/react/components/AccountMenuButton/LinkedDevicesModal-B6api181.css.map → esm/react/components/AccountMenuButton/LinkedDevicesModal-CSSowiHP.css.map} +1 -1
  87. package/dist/esm/react/components/AccountMenuButton/{ProfileDropdown-B-DrG_u5.css → ProfileDropdown-CEPMZ1gY.css} +1 -1
  88. package/dist/{cjs/react/components/AccountMenuButton/ProfileDropdown-B-DrG_u5.css.map → esm/react/components/AccountMenuButton/ProfileDropdown-CEPMZ1gY.css.map} +1 -1
  89. package/dist/esm/react/components/AccountMenuButton/{Web3AuthProfileButton-BnZDUeCL.css → Web3AuthProfileButton-DopOg7Xc.css} +1 -1
  90. package/dist/esm/react/components/AccountMenuButton/{Web3AuthProfileButton-BnZDUeCL.css.map → Web3AuthProfileButton-DopOg7Xc.css.map} +1 -1
  91. package/dist/esm/react/components/AccountMenuButton/icons/{TouchIcon-CAGCi8MY.css → TouchIcon-BQWentvJ.css} +1 -1
  92. package/dist/esm/react/components/AccountMenuButton/icons/{TouchIcon-CAGCi8MY.css.map → TouchIcon-BQWentvJ.css.map} +1 -1
  93. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-CNNxVj4L.css → PasskeyAuthMenu-DwrzWMYx.css} +1 -1
  94. package/dist/esm/react/components/PasskeyAuthMenu/{PasskeyAuthMenu-CNNxVj4L.css.map → PasskeyAuthMenu-DwrzWMYx.css.map} +1 -1
  95. package/dist/esm/react/components/{ShowQRCode-nZhZSaba.css → ShowQRCode-CCN4h6Uv.css} +1 -1
  96. package/dist/esm/react/components/{ShowQRCode-nZhZSaba.css.map → ShowQRCode-CCN4h6Uv.css.map} +1 -1
  97. package/dist/esm/react/hooks/usePreconnectWalletAssets.js +27 -32
  98. package/dist/esm/react/hooks/usePreconnectWalletAssets.js.map +1 -1
  99. package/dist/esm/react/sdk/src/core/EmailRecovery/emailRecoveryPendingStore.js +63 -0
  100. package/dist/esm/react/sdk/src/core/EmailRecovery/emailRecoveryPendingStore.js.map +1 -0
  101. package/dist/esm/react/sdk/src/core/EmailRecovery/index.js +28 -21
  102. package/dist/esm/react/sdk/src/core/EmailRecovery/index.js.map +1 -1
  103. package/dist/esm/react/sdk/src/core/TatchiPasskey/emailRecovery.js +507 -452
  104. package/dist/esm/react/sdk/src/core/TatchiPasskey/emailRecovery.js.map +1 -1
  105. package/dist/esm/react/sdk/src/core/TatchiPasskey/index.js +2 -1
  106. package/dist/esm/react/sdk/src/core/TatchiPasskey/index.js.map +1 -1
  107. package/dist/esm/react/sdk/src/core/TatchiPasskey/relay.js +23 -1
  108. package/dist/esm/react/sdk/src/core/TatchiPasskey/relay.js.map +1 -1
  109. package/dist/esm/react/sdk/src/core/WalletIframe/client/IframeTransport.js +0 -7
  110. package/dist/esm/react/sdk/src/core/WalletIframe/client/IframeTransport.js.map +1 -1
  111. package/dist/esm/react/sdk/src/core/WalletIframe/client/router.js +7 -3
  112. package/dist/esm/react/sdk/src/core/WalletIframe/client/router.js.map +1 -1
  113. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js +1 -1
  114. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.js.map +1 -1
  115. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js +1 -1
  116. package/dist/esm/react/sdk/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.js.map +1 -1
  117. package/dist/esm/react/sdk/src/core/WebAuthnManager/index.js +23 -0
  118. package/dist/esm/react/sdk/src/core/WebAuthnManager/index.js.map +1 -1
  119. package/dist/esm/react/sdk/src/core/rpcCalls.js +8 -1
  120. package/dist/esm/react/sdk/src/core/rpcCalls.js.map +1 -1
  121. package/dist/esm/sdk/{createAdapters-qVGD6i0g.js → createAdapters-DIRR8_Z9.js} +1 -1
  122. package/dist/esm/sdk/{createAdapters-BumKM2ft.js → createAdapters-Yga6W0en.js} +2 -2
  123. package/dist/esm/sdk/{createAdapters-BumKM2ft.js.map → createAdapters-Yga6W0en.js.map} +1 -1
  124. package/dist/esm/sdk/{localOnly-pXMTqh1m.js → localOnly-BHScJasw.js} +2 -2
  125. package/dist/esm/sdk/{localOnly-Byi3AK7A.js → localOnly-VevCI7H0.js} +3 -3
  126. package/dist/esm/sdk/{localOnly-Byi3AK7A.js.map → localOnly-VevCI7H0.js.map} +1 -1
  127. package/dist/esm/sdk/offline-export-app.js +29 -6
  128. package/dist/esm/sdk/offline-export-app.js.map +1 -1
  129. package/dist/esm/sdk/{registration-CBiS4Ua_.js → registration-bKEg9Zr2.js} +2 -2
  130. package/dist/esm/sdk/{registration-CBiS4Ua_.js.map → registration-bKEg9Zr2.js.map} +1 -1
  131. package/dist/esm/sdk/{registration-DLPLsGCz.js → registration-lDD60Ytt.js} +1 -1
  132. package/dist/esm/sdk/{router-BLFegW7J.js → router-DuGYOd3G.js} +6 -9
  133. package/dist/esm/sdk/{rpcCalls-DEv9x5-f.js → rpcCalls-BQrJMTdg.js} +2 -2
  134. package/dist/esm/sdk/{rpcCalls-OhgEeFig.js → rpcCalls-YVeUVMk2.js} +8 -1
  135. package/dist/esm/sdk/{transactions-Bk-VavcV.js → transactions-BalIhtJ9.js} +1 -1
  136. package/dist/esm/sdk/{transactions-BIqKZeR0.js → transactions-bqaAwL4k.js} +2 -2
  137. package/dist/esm/sdk/{transactions-BIqKZeR0.js.map → transactions-bqaAwL4k.js.map} +1 -1
  138. package/dist/esm/sdk/wallet-iframe-host.js +641 -481
  139. package/dist/esm/wasm_vrf_worker/pkg/wasm_vrf_worker_bg.wasm +0 -0
  140. package/dist/types/src/core/EmailRecovery/emailRecoveryPendingStore.d.ts +25 -0
  141. package/dist/types/src/core/EmailRecovery/emailRecoveryPendingStore.d.ts.map +1 -0
  142. package/dist/types/src/core/EmailRecovery/index.d.ts +1 -0
  143. package/dist/types/src/core/EmailRecovery/index.d.ts.map +1 -1
  144. package/dist/types/src/core/TatchiPasskey/emailRecovery.d.ts +38 -6
  145. package/dist/types/src/core/TatchiPasskey/emailRecovery.d.ts.map +1 -1
  146. package/dist/types/src/core/TatchiPasskey/index.d.ts +2 -2
  147. package/dist/types/src/core/TatchiPasskey/index.d.ts.map +1 -1
  148. package/dist/types/src/core/TatchiPasskey/relay.d.ts +2 -1
  149. package/dist/types/src/core/TatchiPasskey/relay.d.ts.map +1 -1
  150. package/dist/types/src/core/WalletIframe/client/IframeTransport.d.ts.map +1 -1
  151. package/dist/types/src/core/WalletIframe/client/router.d.ts +3 -3
  152. package/dist/types/src/core/WalletIframe/client/router.d.ts.map +1 -1
  153. package/dist/types/src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/adapters/webauthn.d.ts.map +1 -1
  154. package/dist/types/src/core/WebAuthnManager/index.d.ts +7 -0
  155. package/dist/types/src/core/WebAuthnManager/index.d.ts.map +1 -1
  156. package/dist/types/src/core/rpcCalls.d.ts +9 -0
  157. package/dist/types/src/core/rpcCalls.d.ts.map +1 -1
  158. package/dist/types/src/index.d.ts +1 -0
  159. package/dist/types/src/index.d.ts.map +1 -1
  160. package/dist/types/src/react/hooks/usePreconnectWalletAssets.d.ts.map +1 -1
  161. package/dist/workers/wasm_vrf_worker_bg.wasm +0 -0
  162. package/package.json +1 -1
@@ -78,7 +78,7 @@ async function handleLocalOnlyFlow(ctx, request, worker, opts) {
78
78
  requestId: request.requestId,
79
79
  intentDigest: getIntentDigest(request),
80
80
  confirmed: false,
81
- error: cancelled ? ERROR_MESSAGES.cancelled : ERROR_MESSAGES.collectCredentialsFailed
81
+ error: cancelled ? ERROR_MESSAGES.cancelled : errorMessage(err) || ERROR_MESSAGES.collectCredentialsFailed
82
82
  });
83
83
  }
84
84
  }
@@ -1 +1 @@
1
- {"version":3,"file":"localOnly.js","names":["removeCancelListener: (() => void) | undefined","err: unknown"],"sources":["../../../../../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.ts"],"sourcesContent":["import type { VrfWorkerManagerContext } from '../../';\nimport type { ConfirmationConfig } from '../../../../types/signer-worker';\nimport {\n SecureConfirmationType,\n TransactionSummary,\n LocalOnlySecureConfirmRequest,\n type ShowSecurePrivateKeyUiPayload,\n} from '../types';\nimport { VRFChallenge } from '../../../../types';\nimport { createRandomVRFChallenge } from '../../../../types/vrf-worker';\nimport { addLitCancelListener } from '../../../LitComponents/lit-events';\nimport { ensureDefined } from '../../../LitComponents/ensure-defined';\nimport { W3A_EXPORT_VIEWER_IFRAME_ID } from '../../../LitComponents/tags';\nimport type { ExportViewerIframeElement } from '../../../LitComponents/ExportPrivateKey/iframe-host';\nimport {\n getNearAccountId,\n getIntentDigest,\n isUserCancelledSecureConfirm,\n ERROR_MESSAGES,\n} from './index';\nimport { errorMessage } from '../../../../../utils/errors';\nimport { createConfirmSession } from '../adapters/session';\nimport { createConfirmTxFlowAdapters } from '../adapters/createAdapters';\n\nasync function mountExportViewer(\n payload: ShowSecurePrivateKeyUiPayload,\n confirmationConfig: ConfirmationConfig,\n): Promise<void> {\n await ensureDefined(W3A_EXPORT_VIEWER_IFRAME_ID, () => import('../../../LitComponents/ExportPrivateKey/iframe-host'));\n const host = document.createElement(W3A_EXPORT_VIEWER_IFRAME_ID) as ExportViewerIframeElement;\n host.theme = payload.theme || confirmationConfig.theme || 'dark';\n host.variant = payload.variant || ((confirmationConfig.uiMode === 'drawer') ? 'drawer' : 'modal');\n host.accountId = payload.nearAccountId;\n host.publicKey = payload.publicKey;\n host.privateKey = payload.privateKey;\n host.loading = false;\n\n window.parent?.postMessage({ type: 'WALLET_UI_OPENED' }, '*');\n document.body.appendChild(host);\n\n let removeCancelListener: (() => void) | undefined;\n removeCancelListener = addLitCancelListener(host, () => {\n window.parent?.postMessage({ type: 'WALLET_UI_CLOSED' }, '*');\n removeCancelListener?.();\n host.remove();\n }, { once: true });\n}\n\nexport async function handleLocalOnlyFlow(\n ctx: VrfWorkerManagerContext,\n request: LocalOnlySecureConfirmRequest,\n worker: Worker,\n opts: { confirmationConfig: ConfirmationConfig; transactionSummary: TransactionSummary },\n): Promise<void> {\n\n const { confirmationConfig, transactionSummary } = opts;\n const adapters = createConfirmTxFlowAdapters(ctx);\n const session = createConfirmSession({\n adapters,\n worker,\n request,\n confirmationConfig,\n transactionSummary,\n });\n const nearAccountId = getNearAccountId(request);\n\n // SHOW_SECURE_PRIVATE_KEY_UI: purely visual; keep UI open and return confirmed immediately\n if (request.type === SecureConfirmationType.SHOW_SECURE_PRIVATE_KEY_UI) {\n try {\n await mountExportViewer(request.payload as ShowSecurePrivateKeyUiPayload, confirmationConfig);\n // Keep viewer open; do not close here.\n session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: true,\n });\n return;\n } catch (err: unknown) {\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: errorMessage(err) || 'Failed to render export UI',\n });\n }\n }\n\n // DECRYPT_PRIVATE_KEY_WITH_PRF: collect an authentication credential (with PRF extension results)\n // and return it to the VRF worker; VRF worker extracts PRF outputs internally.\n if (request.type === SecureConfirmationType.DECRYPT_PRIVATE_KEY_WITH_PRF) {\n const vrfChallenge = createRandomVRFChallenge() as VRFChallenge;\n try {\n const credential = await adapters.webauthn.collectAuthenticationCredentialWithPRF({\n nearAccountId,\n vrfChallenge,\n // Offline export / local decrypt needs both PRF outputs so the VRF worker can\n // recover/derive key material without requiring a pre-existing VRF session.\n includeSecondPrfOutput: true,\n });\n // No modal to keep open; export viewer will be shown by a subsequent request.\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: true,\n credential,\n });\n\n } catch (err: unknown) {\n const cancelled = isUserCancelledSecureConfirm(err);\n if (cancelled) {\n window.parent?.postMessage({ type: 'WALLET_UI_CLOSED' }, '*');\n }\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: cancelled ? ERROR_MESSAGES.cancelled : ERROR_MESSAGES.collectCredentialsFailed,\n });\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAwBA,eAAe,kBACb,SACA,oBACe;AACf,OAAM,cAAc,mCAAmC,OAAO;CAC9D,MAAM,OAAO,SAAS,cAAc;AACpC,MAAK,QAAQ,QAAQ,SAAS,mBAAmB,SAAS;AAC1D,MAAK,UAAU,QAAQ,YAAa,mBAAmB,WAAW,WAAY,WAAW;AACzF,MAAK,YAAY,QAAQ;AACzB,MAAK,YAAY,QAAQ;AACzB,MAAK,aAAa,QAAQ;AAC1B,MAAK,UAAU;AAEf,QAAO,QAAQ,YAAY,EAAE,MAAM,sBAAsB;AACzD,UAAS,KAAK,YAAY;CAE1B,IAAIA;AACJ,wBAAuB,qBAAqB,YAAY;AACtD,SAAO,QAAQ,YAAY,EAAE,MAAM,sBAAsB;AACzD;AACA,OAAK;IACJ,EAAE,MAAM;;AAGb,eAAsB,oBACpB,KACA,SACA,QACA,MACe;CAEf,MAAM,EAAE,oBAAoB,uBAAuB;CACnD,MAAM,WAAW,4BAA4B;CAC7C,MAAM,UAAU,qBAAqB;EACnC;EACA;EACA;EACA;EACA;;CAEF,MAAM,gBAAgB,iBAAiB;AAGvC,KAAI,QAAQ,SAAS,uBAAuB,2BAC1C,KAAI;AACF,QAAM,kBAAkB,QAAQ,SAA0C;AAE1E,UAAQ,qBAAqB;GAC3B,WAAW,QAAQ;GACnB,cAAc,gBAAgB;GAC9B,WAAW;;AAEb;UACOC,KAAc;AACrB,SAAO,QAAQ,qBAAqB;GAClC,WAAW,QAAQ;GACnB,cAAc,gBAAgB;GAC9B,WAAW;GACX,OAAO,aAAa,QAAQ;;;AAOlC,KAAI,QAAQ,SAAS,uBAAuB,8BAA8B;EACxE,MAAM,eAAe;AACrB,MAAI;GACF,MAAM,aAAa,MAAM,SAAS,SAAS,uCAAuC;IAChF;IACA;IAGA,wBAAwB;;AAG1B,UAAO,QAAQ,qBAAqB;IAClC,WAAW,QAAQ;IACnB,cAAc,gBAAgB;IAC9B,WAAW;IACX;;WAGKA,KAAc;GACrB,MAAM,YAAY,6BAA6B;AAC/C,OAAI,UACF,QAAO,QAAQ,YAAY,EAAE,MAAM,sBAAsB;AAE3D,UAAO,QAAQ,qBAAqB;IAClC,WAAW,QAAQ;IACnB,cAAc,gBAAgB;IAC9B,WAAW;IACX,OAAO,YAAY,eAAe,YAAY,eAAe"}
1
+ {"version":3,"file":"localOnly.js","names":["removeCancelListener: (() => void) | undefined","err: unknown"],"sources":["../../../../../../../src/core/WebAuthnManager/VrfWorkerManager/confirmTxFlow/flows/localOnly.ts"],"sourcesContent":["import type { VrfWorkerManagerContext } from '../../';\nimport type { ConfirmationConfig } from '../../../../types/signer-worker';\nimport {\n SecureConfirmationType,\n TransactionSummary,\n LocalOnlySecureConfirmRequest,\n type ShowSecurePrivateKeyUiPayload,\n} from '../types';\nimport { VRFChallenge } from '../../../../types';\nimport { createRandomVRFChallenge } from '../../../../types/vrf-worker';\nimport { addLitCancelListener } from '../../../LitComponents/lit-events';\nimport { ensureDefined } from '../../../LitComponents/ensure-defined';\nimport { W3A_EXPORT_VIEWER_IFRAME_ID } from '../../../LitComponents/tags';\nimport type { ExportViewerIframeElement } from '../../../LitComponents/ExportPrivateKey/iframe-host';\nimport {\n getNearAccountId,\n getIntentDigest,\n isUserCancelledSecureConfirm,\n ERROR_MESSAGES,\n} from './index';\nimport { errorMessage } from '../../../../../utils/errors';\nimport { createConfirmSession } from '../adapters/session';\nimport { createConfirmTxFlowAdapters } from '../adapters/createAdapters';\n\nasync function mountExportViewer(\n payload: ShowSecurePrivateKeyUiPayload,\n confirmationConfig: ConfirmationConfig,\n): Promise<void> {\n await ensureDefined(W3A_EXPORT_VIEWER_IFRAME_ID, () => import('../../../LitComponents/ExportPrivateKey/iframe-host'));\n const host = document.createElement(W3A_EXPORT_VIEWER_IFRAME_ID) as ExportViewerIframeElement;\n host.theme = payload.theme || confirmationConfig.theme || 'dark';\n host.variant = payload.variant || ((confirmationConfig.uiMode === 'drawer') ? 'drawer' : 'modal');\n host.accountId = payload.nearAccountId;\n host.publicKey = payload.publicKey;\n host.privateKey = payload.privateKey;\n host.loading = false;\n\n window.parent?.postMessage({ type: 'WALLET_UI_OPENED' }, '*');\n document.body.appendChild(host);\n\n let removeCancelListener: (() => void) | undefined;\n removeCancelListener = addLitCancelListener(host, () => {\n window.parent?.postMessage({ type: 'WALLET_UI_CLOSED' }, '*');\n removeCancelListener?.();\n host.remove();\n }, { once: true });\n}\n\nexport async function handleLocalOnlyFlow(\n ctx: VrfWorkerManagerContext,\n request: LocalOnlySecureConfirmRequest,\n worker: Worker,\n opts: { confirmationConfig: ConfirmationConfig; transactionSummary: TransactionSummary },\n): Promise<void> {\n\n const { confirmationConfig, transactionSummary } = opts;\n const adapters = createConfirmTxFlowAdapters(ctx);\n const session = createConfirmSession({\n adapters,\n worker,\n request,\n confirmationConfig,\n transactionSummary,\n });\n const nearAccountId = getNearAccountId(request);\n\n // SHOW_SECURE_PRIVATE_KEY_UI: purely visual; keep UI open and return confirmed immediately\n if (request.type === SecureConfirmationType.SHOW_SECURE_PRIVATE_KEY_UI) {\n try {\n await mountExportViewer(request.payload as ShowSecurePrivateKeyUiPayload, confirmationConfig);\n // Keep viewer open; do not close here.\n session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: true,\n });\n return;\n } catch (err: unknown) {\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: errorMessage(err) || 'Failed to render export UI',\n });\n }\n }\n\n // DECRYPT_PRIVATE_KEY_WITH_PRF: collect an authentication credential (with PRF extension results)\n // and return it to the VRF worker; VRF worker extracts PRF outputs internally.\n if (request.type === SecureConfirmationType.DECRYPT_PRIVATE_KEY_WITH_PRF) {\n const vrfChallenge = createRandomVRFChallenge() as VRFChallenge;\n try {\n const credential = await adapters.webauthn.collectAuthenticationCredentialWithPRF({\n nearAccountId,\n vrfChallenge,\n // Offline export / local decrypt needs both PRF outputs so the VRF worker can\n // recover/derive key material without requiring a pre-existing VRF session.\n includeSecondPrfOutput: true,\n });\n // No modal to keep open; export viewer will be shown by a subsequent request.\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: true,\n credential,\n });\n\n } catch (err: unknown) {\n const cancelled = isUserCancelledSecureConfirm(err);\n if (cancelled) {\n window.parent?.postMessage({ type: 'WALLET_UI_CLOSED' }, '*');\n }\n return session.confirmAndCloseModal({\n requestId: request.requestId,\n intentDigest: getIntentDigest(request),\n confirmed: false,\n error: cancelled ? ERROR_MESSAGES.cancelled : (errorMessage(err) || ERROR_MESSAGES.collectCredentialsFailed),\n });\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAwBA,eAAe,kBACb,SACA,oBACe;AACf,OAAM,cAAc,mCAAmC,OAAO;CAC9D,MAAM,OAAO,SAAS,cAAc;AACpC,MAAK,QAAQ,QAAQ,SAAS,mBAAmB,SAAS;AAC1D,MAAK,UAAU,QAAQ,YAAa,mBAAmB,WAAW,WAAY,WAAW;AACzF,MAAK,YAAY,QAAQ;AACzB,MAAK,YAAY,QAAQ;AACzB,MAAK,aAAa,QAAQ;AAC1B,MAAK,UAAU;AAEf,QAAO,QAAQ,YAAY,EAAE,MAAM,sBAAsB;AACzD,UAAS,KAAK,YAAY;CAE1B,IAAIA;AACJ,wBAAuB,qBAAqB,YAAY;AACtD,SAAO,QAAQ,YAAY,EAAE,MAAM,sBAAsB;AACzD;AACA,OAAK;IACJ,EAAE,MAAM;;AAGb,eAAsB,oBACpB,KACA,SACA,QACA,MACe;CAEf,MAAM,EAAE,oBAAoB,uBAAuB;CACnD,MAAM,WAAW,4BAA4B;CAC7C,MAAM,UAAU,qBAAqB;EACnC;EACA;EACA;EACA;EACA;;CAEF,MAAM,gBAAgB,iBAAiB;AAGvC,KAAI,QAAQ,SAAS,uBAAuB,2BAC1C,KAAI;AACF,QAAM,kBAAkB,QAAQ,SAA0C;AAE1E,UAAQ,qBAAqB;GAC3B,WAAW,QAAQ;GACnB,cAAc,gBAAgB;GAC9B,WAAW;;AAEb;UACOC,KAAc;AACrB,SAAO,QAAQ,qBAAqB;GAClC,WAAW,QAAQ;GACnB,cAAc,gBAAgB;GAC9B,WAAW;GACX,OAAO,aAAa,QAAQ;;;AAOlC,KAAI,QAAQ,SAAS,uBAAuB,8BAA8B;EACxE,MAAM,eAAe;AACrB,MAAI;GACF,MAAM,aAAa,MAAM,SAAS,SAAS,uCAAuC;IAChF;IACA;IAGA,wBAAwB;;AAG1B,UAAO,QAAQ,qBAAqB;IAClC,WAAW,QAAQ;IACnB,cAAc,gBAAgB;IAC9B,WAAW;IACX;;WAGKA,KAAc;GACrB,MAAM,YAAY,6BAA6B;AAC/C,OAAI,UACF,QAAO,QAAQ,YAAY,EAAE,MAAM,sBAAsB;AAE3D,UAAO,QAAQ,qBAAqB;IAClC,WAAW,QAAQ;IACnB,cAAc,gBAAgB;IAC9B,WAAW;IACX,OAAO,YAAY,eAAe,YAAa,aAAa,QAAQ,eAAe"}
@@ -752,6 +752,29 @@ var WebAuthnManager = class {
752
752
  async extractCosePublicKey(attestationObjectBase64url) {
753
753
  return await this.signerWorkerManager.extractCosePublicKey(attestationObjectBase64url);
754
754
  }
755
+ /**
756
+ * Helper to ensure the local `lastUser` pointer is consistent with the latest DB updates.
757
+ * This fixes issues where a recovery or registration might have updated the user record
758
+ * but failed to update the `lastUser` pointer (e.g. due to previous bugs or interruptions),
759
+ * preventing the strict `ensureCurrentPasskey` check from passing.
760
+ */
761
+ async autoHealLastUserPointer(nearAccountId) {
762
+ try {
763
+ const lastUser = await this.getLastUser();
764
+ if (lastUser && lastUser.nearAccountId === nearAccountId) {
765
+ const freshest = await IndexedDBManager.clientDB.getLastDBUpdatedUser(nearAccountId);
766
+ if (freshest && freshest.deviceNumber !== lastUser.deviceNumber) {
767
+ console.log(`[WebAuthnManager] Auto-healing lastUser pointer from device ${lastUser.deviceNumber} to ${freshest.deviceNumber}`);
768
+ await this.setLastUser(nearAccountId, freshest.deviceNumber);
769
+ }
770
+ } else {
771
+ const freshest = await IndexedDBManager.clientDB.getLastDBUpdatedUser(nearAccountId);
772
+ if (freshest) await this.setLastUser(nearAccountId, freshest.deviceNumber);
773
+ }
774
+ } catch (e) {
775
+ console.warn("[WebAuthnManager] Auto-heal pointer failed (non-fatal):", e);
776
+ }
777
+ }
755
778
  /** Worker-driven export: two-phase V2 (collect PRF → decrypt → show UI) */
756
779
  async exportNearKeypairWithUIWorkerDriven(nearAccountId, options) {
757
780
  await this.withSigningSession({
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["UserPreferencesInstance","NonceManagerInstance","error: any","result: {\n success: boolean;\n vrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n vrfChallenge: VRFChallenge | null;\n serverEncryptedVrfKeypair: ServerEncryptedVrfKeypair | null;\n }","deviceNumberToUse: number | null","credentialId: string","attestationB64u: string","transports: string[]","normalizedRpcCall: RpcCallPayload"],"sources":["../../../../src/core/WebAuthnManager/index.ts"],"sourcesContent":["import {\n IndexedDBManager,\n type ClientUserData,\n type ClientAuthenticatorData,\n type UnifiedIndexedDBManager,\n} from '../IndexedDBManager';\nimport { StoreUserDataInput } from '../IndexedDBManager/passkeyClientDB';\nimport { type NearClient, SignedTransaction } from '../NearClient';\nimport { SignerWorkerManager } from './SignerWorkerManager';\nimport { VrfWorkerManager } from './VrfWorkerManager';\nimport { AllowCredential, TouchIdPrompt, authenticatorsToAllowCredentials } 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 type { ActionArgsWasm, TransactionInputWasm } from '../types/actions';\nimport type { 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 type { ConfirmationConfig, RpcCallPayload, WasmSignedDelegate } from '../types/signer-worker';\nimport { WebAuthnRegistrationCredential, WebAuthnAuthenticationCredential } from '../types';\nimport { RegistrationCredentialConfirmationPayload } from './SignerWorkerManager/handlers/validation';\nimport { resolveWorkerBaseOrigin, onEmbeddedBaseChange } from '../sdkPaths';\nimport { DEFAULT_WAIT_STATUS } from '../types/rpc';\nimport { getLastLoggedInDeviceNumber } from './SignerWorkerManager/getDeviceNumber';\nimport { __isWalletIframeHostMode } from '../WalletIframe/host-mode';\n\ntype SigningSessionOptions = {\n /** PRF-bearing credential; VRF worker extracts PRF outputs internally */\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\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 try {\n this.userPreferencesManager.configureWalletTheme?.(tatchiPasskeyConfigs.walletTheme);\n } catch {}\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 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 || '').trim() || (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 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 encryptedKeyData = await IndexedDBManager.nearKeysDB.getEncryptedKey(nearAccountId, deviceNumber);\n if (!encryptedKeyData) {\n console.error('WebAuthnManager: No encrypted key found for decrypt session', {\n nearAccountId: String(nearAccountId),\n deviceNumber,\n });\n throw new Error(`No encrypted key found for account: ${nearAccountId}`);\n }\n // For v2+ vaults, wrapKeySalt is the canonical salt.\n const wrapKeySalt = encryptedKeyData.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 ///////////////////////////////////////\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 /**\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 encryptedKeyData = await IndexedDBManager.nearKeysDB.getEncryptedKey(\n nearAccountId,\n deviceNumber\n );\n if (!encryptedKeyData) {\n throw new Error(`No encrypted key found for account ${nearAccountId} device ${deviceNumber}`);\n }\n\n const wrapKeySalt = encryptedKeyData.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;\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 async mintSigningSessionFromCredential(args: {\n nearAccountId: AccountId;\n credential: WebAuthnAuthenticationCredential;\n remainingUses?: number;\n ttlMs?: number;\n contractId?: string;\n nearRpcUrl?: string;\n }): Promise<{\n sessionId: string;\n status: 'active' | 'exhausted' | 'expired' | 'not_found';\n remainingUses?: number;\n expiresAtMs?: number;\n createdAtMs?: number;\n }> {\n const nearAccountId = toAccountId(args.nearAccountId);\n const sessionId = this.getOrCreateActiveSigningSessionId(nearAccountId);\n\n // Ensure VRF keypair is active and bound to the same account.\n const vrfStatus = await this.vrfWorkerManager.checkVrfStatus();\n if (!vrfStatus.active) {\n throw new Error('VRF keypair not active in memory. Please log in again.');\n }\n if (!vrfStatus.nearAccountId || String(vrfStatus.nearAccountId) !== String(nearAccountId)) {\n throw new Error('VRF keypair active but bound to a different account. Please log in again.');\n }\n\n // Fetch wrapKeySalt from vault so the derived WrapKeySeed can decrypt the stored NEAR keys.\n const deviceNumber = await getLastLoggedInDeviceNumber(nearAccountId, IndexedDBManager.clientDB);\n const encryptedKeyData = await IndexedDBManager.nearKeysDB.getEncryptedKey(nearAccountId, deviceNumber);\n if (!encryptedKeyData) {\n throw new Error(`No encrypted key found for account ${nearAccountId} device ${deviceNumber}`);\n }\n const wrapKeySalt = encryptedKeyData.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 confirmationConfigOverride,\n title,\n body,\n onEvent,\n }: {\n transactions: TransactionInputWasm[],\n rpcCall: RpcCallPayload,\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\n\t if (transactions.length === 0) {\n\t throw new Error('No payloads provided for signing');\n\t }\n\t const activeSessionId = this.getOrCreateActiveSigningSessionId(toAccountId(rpcCall.nearAccountId));\n\t return this.withSigningSession({\n\t sessionId: activeSessionId,\n\t handler: (sessionId) =>\n\t this.signerWorkerManager.signTransactionsWithActions({\n\t transactions,\n\t rpcCall,\n\t confirmationConfigOverride,\n\t title,\n\t body,\n\t onEvent,\n\t sessionId,\n\t }),\n\t });\n\t }\n\n async signDelegateAction({\n delegate,\n rpcCall,\n confirmationConfigOverride,\n title,\n body,\n onEvent,\n }: {\n delegate: DelegateActionInput;\n rpcCall: RpcCallPayload;\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\t try {\n\t const activeSessionId = this.getOrCreateActiveSigningSessionId(nearAccountId);\n\t return await this.withSigningSession({ sessionId: activeSessionId, handler: (sessionId) => {\n\t // eslint-disable-next-line no-console\n\t console.debug('[WebAuthnManager][delegate] session created', { sessionId });\n\t return this.signerWorkerManager.signDelegateAction({\n\t delegate,\n\t rpcCall: normalizedRpcCall,\n\t confirmationConfigOverride,\n\t title,\n\t body,\n\t onEvent,\n\t sessionId,\n\t });\n\t }});\n\t } catch (err) {\n\t // eslint-disable-next-line no-console\n\t console.error('[WebAuthnManager][delegate] failed', err);\n\t throw err;\n\t }\n }\n\n async signNEP413Message(payload: {\n message: string;\n recipient: string;\n nonce: string;\n state: string | null;\n accountId: AccountId;\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\t try {\n\t const activeSessionId = this.getOrCreateActiveSigningSessionId(payload.accountId);\n\t const contractId = this.tatchiPasskeyConfigs.contractId;\n\t const nearRpcUrl = (this.tatchiPasskeyConfigs.nearRpcUrl.split(',')[0] || this.tatchiPasskeyConfigs.nearRpcUrl);\n\t const result = await this.withSigningSession({\n\t sessionId: activeSessionId,\n handler: (sessionId) =>\n this.signerWorkerManager.signNep413Message({ ...payload, sessionId, contractId, nearRpcUrl }),\n });\n\t if (result.success) {\n\t return result;\n\t } 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\t async exportNearKeypairWithUIWorkerDriven(\n\t nearAccountId: AccountId,\n\t options?: { variant?: 'drawer'|'modal', theme?: 'dark'|'light' }\n\t ): Promise<void> {\n\t await this.withSigningSession({ prefix: 'export-session', handler: async (sessionId) => {\n\t // Phase 1: collect PRF via LocalOnly(DECRYPT_PRIVATE_KEY_WITH_PRF) inside VRF worker\n\t // and derive WrapKeySeed with the vault-provided wrapKeySalt.\n\t 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\t return this.signerWorkerManager.exportNearKeypairUi({\n\t nearAccountId,\n\t variant: options?.variant,\n\t theme: options?.theme,\n\t sessionId,\n\t });\n\t }});\n\t }\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: String(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: onProgressEvents) => 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\t // Extract PRF.first for WrapKeySeed derivation\n\t // Orchestrate a VRF-owned signing session with WrapKeySeed derivation, then ask\n\t // the signer to recover and re-encrypt the NEAR keypair.\n\t const result = await this.withSigningSession({\n\t prefix: 'recover',\n\t options: { credential: authenticationCredential },\n\t handler: (sessionId) =>\n\t this.signerWorkerManager.recoverKeypairFromPasskey({\n\t credential: authenticationCredential,\n\t accountIdHint,\n\t sessionId,\n\t }),\n\t });\n\t 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 // 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"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["UserPreferencesInstance","NonceManagerInstance","error: any","result: {\n success: boolean;\n vrfPublicKey: string;\n encryptedVrfKeypair: EncryptedVRFKeypair;\n vrfChallenge: VRFChallenge | null;\n serverEncryptedVrfKeypair: ServerEncryptedVrfKeypair | null;\n }","deviceNumberToUse: number | null","credentialId: string","attestationB64u: string","transports: string[]","normalizedRpcCall: RpcCallPayload"],"sources":["../../../../src/core/WebAuthnManager/index.ts"],"sourcesContent":["import {\n IndexedDBManager,\n type ClientUserData,\n type ClientAuthenticatorData,\n type UnifiedIndexedDBManager,\n} from '../IndexedDBManager';\nimport { StoreUserDataInput } from '../IndexedDBManager/passkeyClientDB';\nimport { type NearClient, SignedTransaction } from '../NearClient';\nimport { SignerWorkerManager } from './SignerWorkerManager';\nimport { VrfWorkerManager } from './VrfWorkerManager';\nimport { AllowCredential, TouchIdPrompt, authenticatorsToAllowCredentials } 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 type { ActionArgsWasm, TransactionInputWasm } from '../types/actions';\nimport type { 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 type { ConfirmationConfig, RpcCallPayload, WasmSignedDelegate } from '../types/signer-worker';\nimport { WebAuthnRegistrationCredential, WebAuthnAuthenticationCredential } from '../types';\nimport { RegistrationCredentialConfirmationPayload } from './SignerWorkerManager/handlers/validation';\nimport { resolveWorkerBaseOrigin, onEmbeddedBaseChange } from '../sdkPaths';\nimport { DEFAULT_WAIT_STATUS } from '../types/rpc';\nimport { getLastLoggedInDeviceNumber } from './SignerWorkerManager/getDeviceNumber';\nimport { __isWalletIframeHostMode } from '../WalletIframe/host-mode';\n\ntype SigningSessionOptions = {\n /** PRF-bearing credential; VRF worker extracts PRF outputs internally */\n credential: WebAuthnRegistrationCredential | WebAuthnAuthenticationCredential;\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 try {\n this.userPreferencesManager.configureWalletTheme?.(tatchiPasskeyConfigs.walletTheme);\n } catch { }\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 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 || '').trim() || (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 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 encryptedKeyData = await IndexedDBManager.nearKeysDB.getEncryptedKey(nearAccountId, deviceNumber);\n if (!encryptedKeyData) {\n console.error('WebAuthnManager: No encrypted key found for decrypt session', {\n nearAccountId: String(nearAccountId),\n deviceNumber,\n });\n throw new Error(`No encrypted key found for account: ${nearAccountId}`);\n }\n // For v2+ vaults, wrapKeySalt is the canonical salt.\n const wrapKeySalt = encryptedKeyData.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 ///////////////////////////////////////\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 /**\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 encryptedKeyData = await IndexedDBManager.nearKeysDB.getEncryptedKey(\n nearAccountId,\n deviceNumber\n );\n if (!encryptedKeyData) {\n throw new Error(`No encrypted key found for account ${nearAccountId} device ${deviceNumber}`);\n }\n\n const wrapKeySalt = encryptedKeyData.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;\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 async mintSigningSessionFromCredential(args: {\n nearAccountId: AccountId;\n credential: WebAuthnAuthenticationCredential;\n remainingUses?: number;\n ttlMs?: number;\n contractId?: string;\n nearRpcUrl?: string;\n }): Promise<{\n sessionId: string;\n status: 'active' | 'exhausted' | 'expired' | 'not_found';\n remainingUses?: number;\n expiresAtMs?: number;\n createdAtMs?: number;\n }> {\n const nearAccountId = toAccountId(args.nearAccountId);\n const sessionId = this.getOrCreateActiveSigningSessionId(nearAccountId);\n\n // Ensure VRF keypair is active and bound to the same account.\n const vrfStatus = await this.vrfWorkerManager.checkVrfStatus();\n if (!vrfStatus.active) {\n throw new Error('VRF keypair not active in memory. Please log in again.');\n }\n if (!vrfStatus.nearAccountId || String(vrfStatus.nearAccountId) !== String(nearAccountId)) {\n throw new Error('VRF keypair active but bound to a different account. Please log in again.');\n }\n\n // Fetch wrapKeySalt from vault so the derived WrapKeySeed can decrypt the stored NEAR keys.\n const deviceNumber = await getLastLoggedInDeviceNumber(nearAccountId, IndexedDBManager.clientDB);\n const encryptedKeyData = await IndexedDBManager.nearKeysDB.getEncryptedKey(nearAccountId, deviceNumber);\n if (!encryptedKeyData) {\n throw new Error(`No encrypted key found for account ${nearAccountId} device ${deviceNumber}`);\n }\n const wrapKeySalt = encryptedKeyData.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 confirmationConfigOverride,\n title,\n body,\n onEvent,\n }: {\n transactions: TransactionInputWasm[],\n rpcCall: RpcCallPayload,\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\n if (transactions.length === 0) {\n throw new Error('No payloads provided for signing');\n }\n const activeSessionId = this.getOrCreateActiveSigningSessionId(toAccountId(rpcCall.nearAccountId));\n return this.withSigningSession({\n sessionId: activeSessionId,\n handler: (sessionId) =>\n this.signerWorkerManager.signTransactionsWithActions({\n transactions,\n rpcCall,\n confirmationConfigOverride,\n title,\n body,\n onEvent,\n sessionId,\n }),\n });\n }\n\n async signDelegateAction({\n delegate,\n rpcCall,\n confirmationConfigOverride,\n title,\n body,\n onEvent,\n }: {\n delegate: DelegateActionInput;\n rpcCall: RpcCallPayload;\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 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 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 /**\n * Helper to ensure the local `lastUser` pointer is consistent with the latest DB updates.\n * This fixes issues where a recovery or registration might have updated the user record\n * but failed to update the `lastUser` pointer (e.g. due to previous bugs or interruptions),\n * preventing the strict `ensureCurrentPasskey` check from passing.\n */\n private async autoHealLastUserPointer(nearAccountId: AccountId): Promise<void> {\n try {\n const lastUser = await this.getLastUser();\n\n // If we are already pointing to the correct account, check if there's a fresher device.\n if (lastUser && lastUser.nearAccountId === nearAccountId) {\n const freshest = await IndexedDBManager.clientDB.getLastDBUpdatedUser(nearAccountId);\n if (freshest && freshest.deviceNumber !== lastUser.deviceNumber) {\n // We found a fresher record for this account (e.g. newly recovered device).\n // Auto-heal the pointer to respect the user's latest intent.\n console.log(`[WebAuthnManager] Auto-healing lastUser pointer from device ${lastUser.deviceNumber} to ${freshest.deviceNumber}`);\n await this.setLastUser(nearAccountId, freshest.deviceNumber);\n }\n } else {\n // If lastUser is not set or points to another account, try to set it to something valid for this account.\n const freshest = await IndexedDBManager.clientDB.getLastDBUpdatedUser(nearAccountId);\n if (freshest) {\n await this.setLastUser(nearAccountId, freshest.deviceNumber);\n }\n }\n } catch (e) {\n console.warn('[WebAuthnManager] Auto-heal pointer failed (non-fatal):', e);\n }\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: String(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: onProgressEvents) => 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 // 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"],"mappings":"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"}
@@ -8,6 +8,13 @@ import { ActionType, init_actions } from "./types/actions.js";
8
8
  import { DEFAULT_WAIT_STATUS, init_rpc } from "./types/rpc.js";
9
9
 
10
10
  //#region src/core/rpcCalls.ts
11
+ async function getEmailRecoveryVerificationResult(nearClient, dkimVerifierAccountId, verificationViewMethod, requestId) {
12
+ return await nearClient.view({
13
+ account: dkimVerifierAccountId,
14
+ method: verificationViewMethod,
15
+ args: { request_id: requestId }
16
+ });
17
+ }
11
18
  /**
12
19
  * Query the contract to get the account linked to a device public key
13
20
  * Used in device linking flow to check if a device key has been added
@@ -390,5 +397,5 @@ var init_rpcCalls = __esm({ "src/core/rpcCalls.ts": (() => {
390
397
 
391
398
  //#endregion
392
399
  init_rpcCalls();
393
- export { buildSetRecoveryEmailsActions, checkCanRegisterUserContractCall, executeDeviceLinkingContractCalls, getCredentialIdsContractCall, getDeviceLinkingAccountContractCall, getRecoveryEmailHashesContractCall, init_rpcCalls, syncAuthenticatorsContractCall, verifyAuthenticationResponse };
400
+ export { buildSetRecoveryEmailsActions, checkCanRegisterUserContractCall, executeDeviceLinkingContractCalls, getCredentialIdsContractCall, getDeviceLinkingAccountContractCall, getEmailRecoveryVerificationResult, getRecoveryEmailHashesContractCall, init_rpcCalls, syncAuthenticatorsContractCall, verifyAuthenticationResponse };
394
401
  //# sourceMappingURL=rpcCalls.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rpcCalls.js","names":["error: any","addKeyTxResult: FinalExecutionOutcome","storeDeviceLinkingTxResult: FinalExecutionOutcome","txError: any","err: unknown"],"sources":["../../../src/core/rpcCalls.ts"],"sourcesContent":["/**\n * Consolidated NEAR Contract Calls\n *\n * This file contains all the NEAR contract calls made to the web3authn contract\n * throughout the passkey SDK. It provides a centralized location for all\n * contract interactions and makes it easier to maintain and update contract\n * call patterns.\n */\n\nimport type { FinalExecutionOutcome } from '@near-js/types';\nimport type { NearClient, SignedTransaction } from './NearClient';\nimport type { ContractStoredAuthenticator } from './TatchiPasskey/recoverAccount';\nimport type { PasskeyManagerContext } from './TatchiPasskey';\nimport type { AccountId } from './types/accountIds';\nimport type { DeviceLinkingSSEEvent } from './types/sdkSentEvents';\nimport type {\n StoredAuthenticator,\n WebAuthnRegistrationCredential,\n WebAuthnAuthenticationCredential\n} from './types/webauthn';\n\nimport { ActionPhase, DeviceLinkingPhase, DeviceLinkingStatus } from './types/sdkSentEvents';\nimport { ActionType, type ActionArgs } from './types/actions';\nimport { VRFChallenge } from './types/vrf-worker';\nimport { DEFAULT_WAIT_STATUS, TransactionContext } from './types/rpc';\nimport type { AuthenticatorOptions } from './types/authenticatorOptions';\nimport type { ConfirmationConfig } from './types/signer-worker';\nimport { base64UrlDecode, base64UrlEncode } from '../utils/encoders';\nimport { errorMessage } from '../utils/errors';\nimport type { EmailRecoveryContracts } from './types/tatchi';\nimport { DEFAULT_EMAIL_RECOVERY_CONTRACTS } from './defaultConfigs';\n\n// ===========================\n// CONTRACT CALL RESPONSES\n// ===========================\n\nexport interface DeviceLinkingResult {\n linkedAccountId: string;\n deviceNumber: number;\n}\n\nexport interface CredentialIdsResult {\n credentialIds: string[];\n}\n\nexport interface AuthenticatorsResult {\n authenticators: Array<[string, ContractStoredAuthenticator]>;\n}\n\n// ===========================\n// DEVICE LINKING CONTRACT CALLS\n// ===========================\n\n/**\n * Query the contract to get the account linked to a device public key\n * Used in device linking flow to check if a device key has been added\n *\n * NEAR does not provide a way to lookup the AccountID an access key has access to.\n * So we store a temporary mapping in the contract to lookup pubkey -> account ID.\n */\nexport async function getDeviceLinkingAccountContractCall(\n nearClient: NearClient,\n contractId: string,\n devicePublicKey: string\n): Promise<DeviceLinkingResult | null> {\n try {\n const result = await nearClient.callFunction<\n { device_public_key: string },\n [string, number | string]\n >(\n contractId,\n 'get_device_linking_account',\n { device_public_key: devicePublicKey }\n );\n\n // Handle different result formats\n if (result && Array.isArray(result) && result.length >= 2) {\n const [linkedAccountId, deviceNumberRaw] = result;\n const deviceNumber = Number(deviceNumberRaw);\n if (!Number.isSafeInteger(deviceNumber) || deviceNumber < 0) {\n console.warn(\n 'Invalid deviceNumber returned from get_device_linking_account:',\n deviceNumberRaw\n );\n return null;\n }\n return {\n linkedAccountId,\n deviceNumber\n };\n }\n\n return null;\n } catch (error: any) {\n console.warn('Failed to get device linking account:', error.message);\n return null;\n }\n}\n\n// ===========================\n// DEVICE LINKING TRANSACTION CALLS\n// ===========================\n\n/**\n * Execute device1's linking transactions (AddKey + Contract mapping)\n * This function signs and broadcasts both transactions required for device linking\n */\nexport async function executeDeviceLinkingContractCalls({\n context,\n device1AccountId,\n device2PublicKey,\n nextNonce,\n nextNextNonce,\n nextNextNextNonce,\n txBlockHash,\n vrfChallenge,\n onEvent,\n confirmationConfigOverride,\n confirmerText,\n}: {\n context: PasskeyManagerContext,\n device1AccountId: AccountId,\n device2PublicKey: string,\n nextNonce: string,\n nextNextNonce: string,\n nextNextNextNonce: string,\n txBlockHash: string,\n vrfChallenge: VRFChallenge,\n onEvent?: (event: DeviceLinkingSSEEvent) => void;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n confirmerText?: { title?: string; body?: string };\n}): Promise<{\n addKeyTxResult: FinalExecutionOutcome;\n storeDeviceLinkingTxResult: FinalExecutionOutcome;\n signedDeleteKeyTransaction: SignedTransaction\n}> {\n\n // Sign three transactions with one PRF authentication\n const signedTransactions = await context.webAuthnManager.signTransactionsWithActions({\n rpcCall: {\n contractId: context.webAuthnManager.tatchiPasskeyConfigs.contractId,\n nearRpcUrl: context.webAuthnManager.tatchiPasskeyConfigs.nearRpcUrl,\n nearAccountId: device1AccountId\n },\n confirmationConfigOverride,\n title: confirmerText?.title,\n body: confirmerText?.body,\n transactions: [\n // Transaction 1: AddKey - Add Device2's key to Device1's account\n {\n receiverId: device1AccountId,\n actions: [{\n action_type: ActionType.AddKey,\n public_key: device2PublicKey,\n access_key: JSON.stringify({\n // NEAR-style AccessKey JSON shape, matching near-api-js:\n // { nonce: number, permission: { FullAccess: {} } }\n nonce: 0,\n permission: { FullAccess: {} },\n }),\n }],\n nonce: nextNonce,\n },\n // Transaction 2: Store temporary mapping in contract so Device2 can lookup Device1's accountID.\n {\n receiverId: context.webAuthnManager.tatchiPasskeyConfigs.contractId,\n actions: [{\n action_type: ActionType.FunctionCall,\n method_name: 'store_device_linking_mapping',\n args: JSON.stringify({\n device_public_key: device2PublicKey,\n target_account_id: device1AccountId,\n }),\n gas: '30000000000000', // 30 TGas for device linking with yield promise automatic cleanup\n deposit: '0'\n }],\n nonce: nextNextNonce,\n },\n // Transaction 3: Remove Device2's temporary key if it fails to complete linking after a timeout\n {\n receiverId: device1AccountId,\n actions: [{\n action_type: ActionType.DeleteKey,\n public_key: device2PublicKey\n }],\n nonce: nextNextNextNonce,\n }\n ],\n onEvent: (progress) => {\n // Bridge all action progress events to the parent so the wallet iframe overlay\n // can expand during user confirmation in wallet-iframe mode.\n try { onEvent?.(progress as any); } catch { }\n // Keep existing mapping for device linking semantics; surface signing as a loading state\n if (progress.phase == ActionPhase.STEP_6_TRANSACTION_SIGNING_COMPLETE) {\n onEvent?.({\n step: 3,\n phase: DeviceLinkingPhase.STEP_3_AUTHORIZATION,\n status: DeviceLinkingStatus.PROGRESS,\n message: progress.message || 'Transaction signing in progress...'\n })\n }\n }\n });\n\n if (!signedTransactions[0].signedTransaction) {\n throw new Error('AddKey transaction signing failed');\n }\n if (!signedTransactions[1].signedTransaction) {\n throw new Error('Contract mapping transaction signing failed');\n }\n if (!signedTransactions[2].signedTransaction) {\n throw new Error('DeleteKey transaction signing failed');\n }\n\n // Broadcast just the first 2 transactions: addKey and store device linking mapping\n let addKeyTxResult: FinalExecutionOutcome;\n let storeDeviceLinkingTxResult: FinalExecutionOutcome;\n try {\n console.debug('LinkDeviceFlow: AddKey transaction details:', {\n receiverId: signedTransactions[0].signedTransaction.transaction.receiverId,\n actions: signedTransactions[0].signedTransaction.transaction.actions || [],\n transactionKeys: Object.keys(signedTransactions[0].signedTransaction.transaction),\n });\n\n addKeyTxResult = await context.nearClient.sendTransaction(\n signedTransactions[0].signedTransaction,\n DEFAULT_WAIT_STATUS.linkDeviceAddKey\n );\n console.log('LinkDeviceFlow: AddKey transaction result:', addKeyTxResult?.transaction?.hash);\n\n // Send success events immediately after AddKey succeeds\n onEvent?.({\n step: 3,\n phase: DeviceLinkingPhase.STEP_3_AUTHORIZATION,\n status: DeviceLinkingStatus.SUCCESS,\n message: `AddKey transaction completed successfully!`\n });\n\n // Check if contract mapping transaction is valid before attempting to broadcast\n const contractTx = signedTransactions[1].signedTransaction;\n console.log('LinkDeviceFlow: Contract mapping transaction details:', {\n receiverId: contractTx.transaction.receiverId,\n actions: (contractTx.transaction.actions || []).length\n });\n\n // Standard timeout since nonce conflict should be resolved by the 2s delay\n storeDeviceLinkingTxResult = await context.nearClient.sendTransaction(\n contractTx,\n DEFAULT_WAIT_STATUS.linkDeviceAccountMapping\n );\n\n } catch (txError: any) {\n console.error('LinkDeviceFlow: Transaction broadcasting failed:', txError);\n throw new Error(`Transaction broadcasting failed: ${txError.message}`);\n }\n\n onEvent?.({\n step: 6,\n phase: DeviceLinkingPhase.STEP_6_REGISTRATION,\n status: DeviceLinkingStatus.SUCCESS,\n message: `Device linking completed successfully!`\n });\n\n return {\n addKeyTxResult,\n storeDeviceLinkingTxResult,\n signedDeleteKeyTransaction: signedTransactions[2].signedTransaction\n };\n}\n\n// ===========================\n// ACCOUNT RECOVERY CONTRACT CALLS\n// ===========================\n\n/**\n * Get credential IDs associated with an account from the contract\n * Used in account recovery to discover available credentials\n */\nexport async function getCredentialIdsContractCall(\n nearClient: NearClient,\n contractId: string,\n accountId: AccountId\n): Promise<string[]> {\n try {\n const credentialIds = await nearClient.callFunction<{ account_id: AccountId }, string[]>(\n contractId,\n 'get_credential_ids_by_account',\n { account_id: accountId }\n );\n return credentialIds || [];\n } catch (error: any) {\n console.warn('Failed to fetch credential IDs from contract:', error.message);\n return [];\n }\n}\n\n/**\n * Get all authenticators stored for a user from the contract\n * Used in account recovery to sync authenticator data\n */\nexport async function getAuthenticatorsByUser(\n nearClient: NearClient,\n contractId: string,\n accountId: AccountId\n): Promise<[string, ContractStoredAuthenticator][]> {\n try {\n const authenticatorsResult = await nearClient.view<{ user_id: AccountId }, [string, ContractStoredAuthenticator][]>({\n account: contractId,\n method: 'get_authenticators_by_user',\n args: { user_id: accountId }\n });\n\n if (authenticatorsResult && Array.isArray(authenticatorsResult)) {\n return authenticatorsResult;\n }\n return [];\n } catch (error: any) {\n console.warn('Failed to fetch authenticators from contract:', error.message);\n return [];\n }\n}\n\nexport async function syncAuthenticatorsContractCall(\n nearClient: NearClient,\n contractId: string,\n accountId: AccountId\n): Promise<Array<{ credentialId: string, authenticator: StoredAuthenticator }>> {\n try {\n const authenticatorsResult = await getAuthenticatorsByUser(nearClient, contractId, accountId);\n if (authenticatorsResult && Array.isArray(authenticatorsResult)) {\n return authenticatorsResult.map(([credentialId, contractAuthenticator]) => {\n console.log(`Contract authenticator device_number for ${credentialId}:`, contractAuthenticator.device_number);\n\n const transports = Array.isArray(contractAuthenticator.transports)\n ? contractAuthenticator.transports\n : [];\n\n const registered = (() => {\n const raw = String((contractAuthenticator as any).registered ?? '');\n if (!raw) return new Date(0);\n if (/^\\d+$/.test(raw)) {\n const ts = Number(raw);\n return Number.isFinite(ts) ? new Date(ts) : new Date(0);\n }\n const d = new Date(raw);\n return Number.isFinite(d.getTime()) ? d : new Date(0);\n })();\n\n const vrfPublicKeys = (() => {\n const raw = (contractAuthenticator as any).vrf_public_keys;\n if (!raw) return undefined;\n if (Array.isArray(raw) && raw.length > 0 && typeof raw[0] === 'string') {\n return raw as string[];\n }\n if (Array.isArray(raw)) {\n return raw\n .map((entry: unknown) => {\n if (!entry) return null;\n if (entry instanceof Uint8Array) return base64UrlEncode(entry);\n if (Array.isArray(entry)) return base64UrlEncode(new Uint8Array(entry));\n return null;\n })\n .filter((x): x is string => typeof x === 'string' && x.length > 0);\n }\n return undefined;\n })();\n\n return {\n credentialId,\n authenticator: {\n credentialId,\n credentialPublicKey: new Uint8Array(contractAuthenticator.credential_public_key),\n transports,\n userId: accountId,\n name: `Device ${contractAuthenticator.device_number} Authenticator`,\n registered,\n // Store the actual device number from contract (no fallback)\n deviceNumber: contractAuthenticator.device_number,\n vrfPublicKeys\n }\n };\n });\n }\n return [];\n } catch (error: any) {\n console.warn('Failed to fetch authenticators from contract:', error.message);\n return [];\n }\n}\n\n// ===========================\n// RECOVERY EMAIL CONTRACT CALLS\n// ===========================\n\n/**\n * Fetch on-chain recovery email hashes from the per-account contract.\n * Returns [] when no contract is deployed or on failure.\n */\nexport async function getRecoveryEmailHashesContractCall(\n nearClient: NearClient,\n accountId: AccountId\n): Promise<number[][]> {\n try {\n const code = await nearClient.viewCode(accountId);\n const hasContract = !!code && code.byteLength > 0;\n if (!hasContract) return [];\n\n const hashes = await nearClient.view<Record<string, never>, number[][]>({\n account: accountId,\n method: 'get_recovery_emails',\n args: {} as Record<string, never>,\n });\n\n return Array.isArray(hashes) ? (hashes as number[][]) : [];\n } catch (error) {\n console.error('[rpcCalls] Failed to fetch recovery email hashes', error);\n return [];\n }\n}\n\n/**\n * Build action args to update on-chain recovery emails for an account.\n * If the per-account contract is missing, deploy/attach the global recoverer via `init_email_recovery`.\n */\nexport async function buildSetRecoveryEmailsActions(\n nearClient: NearClient,\n accountId: AccountId,\n recoveryEmailHashes: number[][],\n contracts: EmailRecoveryContracts = DEFAULT_EMAIL_RECOVERY_CONTRACTS\n): Promise<ActionArgs[]> {\n let hasContract = false;\n try {\n const code = await nearClient.viewCode(accountId);\n hasContract = !!code && code.byteLength > 0;\n } catch {\n hasContract = false;\n }\n\n const {\n emailRecovererGlobalContract,\n zkEmailVerifierContract,\n emailDkimVerifierContract,\n } = contracts;\n\n return hasContract\n ? [\n {\n type: ActionType.UseGlobalContract,\n accountId: emailRecovererGlobalContract,\n },\n {\n type: ActionType.FunctionCall,\n methodName: 'set_recovery_emails',\n args: {\n recovery_emails: recoveryEmailHashes,\n },\n gas: '80000000000000',\n deposit: '0',\n },\n ]\n : [\n {\n type: ActionType.UseGlobalContract,\n accountId: emailRecovererGlobalContract,\n },\n {\n type: ActionType.FunctionCall,\n methodName: 'init_email_recovery',\n args: {\n zk_email_verifier: zkEmailVerifierContract,\n email_dkim_verifier: emailDkimVerifierContract,\n policy: null,\n recovery_emails: recoveryEmailHashes,\n },\n gas: '80000000000000',\n deposit: '0',\n },\n ];\n}\n\nexport async function fetchNonceBlockHashAndHeight({ nearClient, nearPublicKeyStr, nearAccountId }: {\n nearClient: NearClient,\n nearPublicKeyStr: string,\n nearAccountId: AccountId\n}): Promise<TransactionContext> {\n // Get access key and transaction block info concurrently\n const [accessKeyInfo, txBlockInfo] = await Promise.all([\n nearClient.viewAccessKey(nearAccountId, nearPublicKeyStr)\n .catch(e => { throw new Error(`Failed to fetch Access Key`) }),\n nearClient.viewBlock({ finality: 'final' })\n .catch(e => { throw new Error(`Failed to fetch Block Info`) })\n ]);\n if (!accessKeyInfo || accessKeyInfo.nonce === undefined) {\n throw new Error(`Access key not found or invalid for account ${nearAccountId} with public key ${nearPublicKeyStr}. Response: ${JSON.stringify(accessKeyInfo)}`);\n }\n const nextNonce = (BigInt(accessKeyInfo.nonce) + BigInt(1)).toString();\n const txBlockHeight = String(txBlockInfo.header.height);\n const txBlockHash = txBlockInfo.header.hash; // Keep original base58 string\n\n return {\n nearPublicKeyStr,\n accessKeyInfo,\n nextNonce,\n txBlockHeight,\n txBlockHash,\n };\n}\n\n// ===========================\n// REGISTRATION PRE-CHECK CALL\n// ===========================\n\nexport interface CheckCanRegisterUserResult {\n success: boolean;\n verified: boolean;\n logs: string[];\n error?: string;\n}\n\n/**\n * View-only registration pre-check.\n *\n * Calls the contract's `check_can_register_user` view method with VRF data\n * derived from the provided VRF challenge and a serialized WebAuthn\n * registration credential (typically with PRF outputs embedded).\n */\nexport async function checkCanRegisterUserContractCall({\n nearClient,\n contractId,\n vrfChallenge,\n credential,\n authenticatorOptions,\n}: {\n nearClient: NearClient;\n contractId: string;\n vrfChallenge: VRFChallenge;\n credential: WebAuthnRegistrationCredential;\n authenticatorOptions?: AuthenticatorOptions;\n}): Promise<CheckCanRegisterUserResult> {\n try {\n const vrfData = {\n vrf_input_data: Array.from(base64UrlDecode(vrfChallenge.vrfInput)),\n vrf_output: Array.from(base64UrlDecode(vrfChallenge.vrfOutput)),\n vrf_proof: Array.from(base64UrlDecode(vrfChallenge.vrfProof)),\n public_key: Array.from(base64UrlDecode(vrfChallenge.vrfPublicKey)),\n user_id: vrfChallenge.userId,\n rp_id: vrfChallenge.rpId,\n block_height: Number(vrfChallenge.blockHeight),\n block_hash: Array.from(base64UrlDecode(vrfChallenge.blockHash)),\n };\n\n const args = {\n vrf_data: vrfData,\n webauthn_registration: credential,\n authenticator_options: authenticatorOptions,\n };\n\n const response = await nearClient.callFunction<typeof args, any>(\n contractId,\n 'check_can_register_user',\n args,\n );\n\n const verified = !!response?.verified;\n return {\n success: true,\n verified,\n logs: [],\n error: verified ? undefined : 'Contract registration check failed',\n };\n } catch (err: unknown) {\n return {\n success: false,\n verified: false,\n logs: [],\n error: errorMessage(err) || 'Failed to call check_can_register_user',\n };\n }\n}\n\n\n/**\n * Verify authentication response through relay server\n * Routes the request to relay server which calls the web3authn contract for verification\n * and issues a JWT or session credential\n */\nexport async function verifyAuthenticationResponse(\n relayServerUrl: string,\n routePath: string,\n sessionKind: 'jwt' | 'cookie',\n vrfChallenge: VRFChallenge,\n webauthnAuthentication: WebAuthnAuthenticationCredential\n): Promise<{\n success: boolean;\n verified?: boolean;\n jwt?: string;\n sessionCredential?: any;\n error?: string;\n contractResponse?: any;\n}> {\n try {\n // Map VRFChallenge into server ContractVrfData shape (number arrays)\n const toBytes = (b64u: string | undefined): number[] => {\n if (!b64u) return [];\n return Array.from(base64UrlDecode(b64u));\n };\n const vrf_data = {\n vrf_input_data: toBytes(vrfChallenge.vrfInput),\n vrf_output: toBytes(vrfChallenge.vrfOutput),\n vrf_proof: toBytes(vrfChallenge.vrfProof),\n public_key: toBytes(vrfChallenge.vrfPublicKey),\n user_id: vrfChallenge.userId,\n rp_id: vrfChallenge.rpId,\n block_height: Number(vrfChallenge.blockHeight || 0),\n block_hash: toBytes(vrfChallenge.blockHash),\n };\n\n // Normalize authenticatorAttachment and userHandle to null for server schema\n const webauthn_authentication = {\n ...webauthnAuthentication,\n authenticatorAttachment: webauthnAuthentication.authenticatorAttachment ?? null,\n response: {\n ...webauthnAuthentication.response,\n userHandle: webauthnAuthentication.response.userHandle ?? null,\n }\n };\n\n const url = `${relayServerUrl.replace(/\\/$/, '')}${routePath.startsWith('/') ? routePath : `/${routePath}`}`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n credentials: sessionKind === 'cookie' ? 'include' : 'omit',\n body: JSON.stringify({\n sessionKind: sessionKind,\n vrf_data,\n webauthn_authentication,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n return {\n success: false,\n error: `HTTP ${response.status}: ${errorText}`,\n };\n }\n\n const result = await response.json();\n return {\n success: true,\n verified: result.verified,\n jwt: result.jwt,\n sessionCredential: result.sessionCredential,\n contractResponse: result.contractResponse,\n };\n } catch (error: any) {\n return {\n success: false,\n error: error.message || 'Failed to verify authentication response',\n };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rpcCalls.js","names":["error: any","addKeyTxResult: FinalExecutionOutcome","storeDeviceLinkingTxResult: FinalExecutionOutcome","txError: any","err: unknown"],"sources":["../../../src/core/rpcCalls.ts"],"sourcesContent":["/**\n * Consolidated NEAR Contract Calls\n *\n * This file contains all the NEAR contract calls made to the web3authn contract\n * throughout the passkey SDK. It provides a centralized location for all\n * contract interactions and makes it easier to maintain and update contract\n * call patterns.\n */\n\nimport type { FinalExecutionOutcome } from '@near-js/types';\nimport type { NearClient, SignedTransaction } from './NearClient';\nimport type { ContractStoredAuthenticator } from './TatchiPasskey/recoverAccount';\nimport type { PasskeyManagerContext } from './TatchiPasskey';\nimport type { AccountId } from './types/accountIds';\nimport type { DeviceLinkingSSEEvent } from './types/sdkSentEvents';\nimport type {\n StoredAuthenticator,\n WebAuthnRegistrationCredential,\n WebAuthnAuthenticationCredential\n} from './types/webauthn';\n\nimport { ActionPhase, DeviceLinkingPhase, DeviceLinkingStatus } from './types/sdkSentEvents';\nimport { ActionType, type ActionArgs } from './types/actions';\nimport { VRFChallenge } from './types/vrf-worker';\nimport { DEFAULT_WAIT_STATUS, TransactionContext } from './types/rpc';\nimport type { AuthenticatorOptions } from './types/authenticatorOptions';\nimport type { ConfirmationConfig } from './types/signer-worker';\nimport { base64UrlDecode, base64UrlEncode } from '../utils/encoders';\nimport { errorMessage } from '../utils/errors';\nimport type { EmailRecoveryContracts } from './types/tatchi';\nimport { DEFAULT_EMAIL_RECOVERY_CONTRACTS } from './defaultConfigs';\n\n// ===========================\n// CONTRACT CALL RESPONSES\n// ===========================\n\nexport interface DeviceLinkingResult {\n linkedAccountId: string;\n deviceNumber: number;\n}\n\nexport interface CredentialIdsResult {\n credentialIds: string[];\n}\n\nexport interface AuthenticatorsResult {\n authenticators: Array<[string, ContractStoredAuthenticator]>;\n}\n\nexport type EmailRecoveryVerificationResult = {\n verified: boolean;\n account_id?: string;\n new_public_key?: string;\n transaction_hash?: string;\n error_code?: string;\n error_message?: string;\n};\n\nexport async function getEmailRecoveryVerificationResult(\n nearClient: NearClient,\n dkimVerifierAccountId: string,\n verificationViewMethod: string,\n requestId: string\n): Promise<EmailRecoveryVerificationResult | null> {\n return await nearClient.view<{ request_id: string }, EmailRecoveryVerificationResult | null>({\n account: dkimVerifierAccountId,\n method: verificationViewMethod,\n args: { request_id: requestId },\n });\n}\n\n// ===========================\n// DEVICE LINKING CONTRACT CALLS\n// ===========================\n\n/**\n * Query the contract to get the account linked to a device public key\n * Used in device linking flow to check if a device key has been added\n *\n * NEAR does not provide a way to lookup the AccountID an access key has access to.\n * So we store a temporary mapping in the contract to lookup pubkey -> account ID.\n */\nexport async function getDeviceLinkingAccountContractCall(\n nearClient: NearClient,\n contractId: string,\n devicePublicKey: string\n): Promise<DeviceLinkingResult | null> {\n try {\n const result = await nearClient.callFunction<\n { device_public_key: string },\n [string, number | string]\n >(\n contractId,\n 'get_device_linking_account',\n { device_public_key: devicePublicKey }\n );\n\n // Handle different result formats\n if (result && Array.isArray(result) && result.length >= 2) {\n const [linkedAccountId, deviceNumberRaw] = result;\n const deviceNumber = Number(deviceNumberRaw);\n if (!Number.isSafeInteger(deviceNumber) || deviceNumber < 0) {\n console.warn(\n 'Invalid deviceNumber returned from get_device_linking_account:',\n deviceNumberRaw\n );\n return null;\n }\n return {\n linkedAccountId,\n deviceNumber\n };\n }\n\n return null;\n } catch (error: any) {\n console.warn('Failed to get device linking account:', error.message);\n return null;\n }\n}\n\n// ===========================\n// DEVICE LINKING TRANSACTION CALLS\n// ===========================\n\n/**\n * Execute device1's linking transactions (AddKey + Contract mapping)\n * This function signs and broadcasts both transactions required for device linking\n */\nexport async function executeDeviceLinkingContractCalls({\n context,\n device1AccountId,\n device2PublicKey,\n nextNonce,\n nextNextNonce,\n nextNextNextNonce,\n txBlockHash,\n vrfChallenge,\n onEvent,\n confirmationConfigOverride,\n confirmerText,\n}: {\n context: PasskeyManagerContext,\n device1AccountId: AccountId,\n device2PublicKey: string,\n nextNonce: string,\n nextNextNonce: string,\n nextNextNextNonce: string,\n txBlockHash: string,\n vrfChallenge: VRFChallenge,\n onEvent?: (event: DeviceLinkingSSEEvent) => void;\n confirmationConfigOverride?: Partial<ConfirmationConfig>;\n confirmerText?: { title?: string; body?: string };\n}): Promise<{\n addKeyTxResult: FinalExecutionOutcome;\n storeDeviceLinkingTxResult: FinalExecutionOutcome;\n signedDeleteKeyTransaction: SignedTransaction\n}> {\n\n // Sign three transactions with one PRF authentication\n const signedTransactions = await context.webAuthnManager.signTransactionsWithActions({\n rpcCall: {\n contractId: context.webAuthnManager.tatchiPasskeyConfigs.contractId,\n nearRpcUrl: context.webAuthnManager.tatchiPasskeyConfigs.nearRpcUrl,\n nearAccountId: device1AccountId\n },\n confirmationConfigOverride,\n title: confirmerText?.title,\n body: confirmerText?.body,\n transactions: [\n // Transaction 1: AddKey - Add Device2's key to Device1's account\n {\n receiverId: device1AccountId,\n actions: [{\n action_type: ActionType.AddKey,\n public_key: device2PublicKey,\n access_key: JSON.stringify({\n // NEAR-style AccessKey JSON shape, matching near-api-js:\n // { nonce: number, permission: { FullAccess: {} } }\n nonce: 0,\n permission: { FullAccess: {} },\n }),\n }],\n nonce: nextNonce,\n },\n // Transaction 2: Store temporary mapping in contract so Device2 can lookup Device1's accountID.\n {\n receiverId: context.webAuthnManager.tatchiPasskeyConfigs.contractId,\n actions: [{\n action_type: ActionType.FunctionCall,\n method_name: 'store_device_linking_mapping',\n args: JSON.stringify({\n device_public_key: device2PublicKey,\n target_account_id: device1AccountId,\n }),\n gas: '30000000000000', // 30 TGas for device linking with yield promise automatic cleanup\n deposit: '0'\n }],\n nonce: nextNextNonce,\n },\n // Transaction 3: Remove Device2's temporary key if it fails to complete linking after a timeout\n {\n receiverId: device1AccountId,\n actions: [{\n action_type: ActionType.DeleteKey,\n public_key: device2PublicKey\n }],\n nonce: nextNextNextNonce,\n }\n ],\n onEvent: (progress) => {\n // Bridge all action progress events to the parent so the wallet iframe overlay\n // can expand during user confirmation in wallet-iframe mode.\n try { onEvent?.(progress as any); } catch { }\n // Keep existing mapping for device linking semantics; surface signing as a loading state\n if (progress.phase == ActionPhase.STEP_6_TRANSACTION_SIGNING_COMPLETE) {\n onEvent?.({\n step: 3,\n phase: DeviceLinkingPhase.STEP_3_AUTHORIZATION,\n status: DeviceLinkingStatus.PROGRESS,\n message: progress.message || 'Transaction signing in progress...'\n })\n }\n }\n });\n\n if (!signedTransactions[0].signedTransaction) {\n throw new Error('AddKey transaction signing failed');\n }\n if (!signedTransactions[1].signedTransaction) {\n throw new Error('Contract mapping transaction signing failed');\n }\n if (!signedTransactions[2].signedTransaction) {\n throw new Error('DeleteKey transaction signing failed');\n }\n\n // Broadcast just the first 2 transactions: addKey and store device linking mapping\n let addKeyTxResult: FinalExecutionOutcome;\n let storeDeviceLinkingTxResult: FinalExecutionOutcome;\n try {\n console.debug('LinkDeviceFlow: AddKey transaction details:', {\n receiverId: signedTransactions[0].signedTransaction.transaction.receiverId,\n actions: signedTransactions[0].signedTransaction.transaction.actions || [],\n transactionKeys: Object.keys(signedTransactions[0].signedTransaction.transaction),\n });\n\n addKeyTxResult = await context.nearClient.sendTransaction(\n signedTransactions[0].signedTransaction,\n DEFAULT_WAIT_STATUS.linkDeviceAddKey\n );\n console.log('LinkDeviceFlow: AddKey transaction result:', addKeyTxResult?.transaction?.hash);\n\n // Send success events immediately after AddKey succeeds\n onEvent?.({\n step: 3,\n phase: DeviceLinkingPhase.STEP_3_AUTHORIZATION,\n status: DeviceLinkingStatus.SUCCESS,\n message: `AddKey transaction completed successfully!`\n });\n\n // Check if contract mapping transaction is valid before attempting to broadcast\n const contractTx = signedTransactions[1].signedTransaction;\n console.log('LinkDeviceFlow: Contract mapping transaction details:', {\n receiverId: contractTx.transaction.receiverId,\n actions: (contractTx.transaction.actions || []).length\n });\n\n // Standard timeout since nonce conflict should be resolved by the 2s delay\n storeDeviceLinkingTxResult = await context.nearClient.sendTransaction(\n contractTx,\n DEFAULT_WAIT_STATUS.linkDeviceAccountMapping\n );\n\n } catch (txError: any) {\n console.error('LinkDeviceFlow: Transaction broadcasting failed:', txError);\n throw new Error(`Transaction broadcasting failed: ${txError.message}`);\n }\n\n onEvent?.({\n step: 6,\n phase: DeviceLinkingPhase.STEP_6_REGISTRATION,\n status: DeviceLinkingStatus.SUCCESS,\n message: `Device linking completed successfully!`\n });\n\n return {\n addKeyTxResult,\n storeDeviceLinkingTxResult,\n signedDeleteKeyTransaction: signedTransactions[2].signedTransaction\n };\n}\n\n// ===========================\n// ACCOUNT RECOVERY CONTRACT CALLS\n// ===========================\n\n/**\n * Get credential IDs associated with an account from the contract\n * Used in account recovery to discover available credentials\n */\nexport async function getCredentialIdsContractCall(\n nearClient: NearClient,\n contractId: string,\n accountId: AccountId\n): Promise<string[]> {\n try {\n const credentialIds = await nearClient.callFunction<{ account_id: AccountId }, string[]>(\n contractId,\n 'get_credential_ids_by_account',\n { account_id: accountId }\n );\n return credentialIds || [];\n } catch (error: any) {\n console.warn('Failed to fetch credential IDs from contract:', error.message);\n return [];\n }\n}\n\n/**\n * Get all authenticators stored for a user from the contract\n * Used in account recovery to sync authenticator data\n */\nexport async function getAuthenticatorsByUser(\n nearClient: NearClient,\n contractId: string,\n accountId: AccountId\n): Promise<[string, ContractStoredAuthenticator][]> {\n try {\n const authenticatorsResult = await nearClient.view<{ user_id: AccountId }, [string, ContractStoredAuthenticator][]>({\n account: contractId,\n method: 'get_authenticators_by_user',\n args: { user_id: accountId }\n });\n\n if (authenticatorsResult && Array.isArray(authenticatorsResult)) {\n return authenticatorsResult;\n }\n return [];\n } catch (error: any) {\n console.warn('Failed to fetch authenticators from contract:', error.message);\n return [];\n }\n}\n\nexport async function syncAuthenticatorsContractCall(\n nearClient: NearClient,\n contractId: string,\n accountId: AccountId\n): Promise<Array<{ credentialId: string, authenticator: StoredAuthenticator }>> {\n try {\n const authenticatorsResult = await getAuthenticatorsByUser(nearClient, contractId, accountId);\n if (authenticatorsResult && Array.isArray(authenticatorsResult)) {\n return authenticatorsResult.map(([credentialId, contractAuthenticator]) => {\n console.log(`Contract authenticator device_number for ${credentialId}:`, contractAuthenticator.device_number);\n\n const transports = Array.isArray(contractAuthenticator.transports)\n ? contractAuthenticator.transports\n : [];\n\n const registered = (() => {\n const raw = String((contractAuthenticator as any).registered ?? '');\n if (!raw) return new Date(0);\n if (/^\\d+$/.test(raw)) {\n const ts = Number(raw);\n return Number.isFinite(ts) ? new Date(ts) : new Date(0);\n }\n const d = new Date(raw);\n return Number.isFinite(d.getTime()) ? d : new Date(0);\n })();\n\n const vrfPublicKeys = (() => {\n const raw = (contractAuthenticator as any).vrf_public_keys;\n if (!raw) return undefined;\n if (Array.isArray(raw) && raw.length > 0 && typeof raw[0] === 'string') {\n return raw as string[];\n }\n if (Array.isArray(raw)) {\n return raw\n .map((entry: unknown) => {\n if (!entry) return null;\n if (entry instanceof Uint8Array) return base64UrlEncode(entry);\n if (Array.isArray(entry)) return base64UrlEncode(new Uint8Array(entry));\n return null;\n })\n .filter((x): x is string => typeof x === 'string' && x.length > 0);\n }\n return undefined;\n })();\n\n return {\n credentialId,\n authenticator: {\n credentialId,\n credentialPublicKey: new Uint8Array(contractAuthenticator.credential_public_key),\n transports,\n userId: accountId,\n name: `Device ${contractAuthenticator.device_number} Authenticator`,\n registered,\n // Store the actual device number from contract (no fallback)\n deviceNumber: contractAuthenticator.device_number,\n vrfPublicKeys\n }\n };\n });\n }\n return [];\n } catch (error: any) {\n console.warn('Failed to fetch authenticators from contract:', error.message);\n return [];\n }\n}\n\n// ===========================\n// RECOVERY EMAIL CONTRACT CALLS\n// ===========================\n\n/**\n * Fetch on-chain recovery email hashes from the per-account contract.\n * Returns [] when no contract is deployed or on failure.\n */\nexport async function getRecoveryEmailHashesContractCall(\n nearClient: NearClient,\n accountId: AccountId\n): Promise<number[][]> {\n try {\n const code = await nearClient.viewCode(accountId);\n const hasContract = !!code && code.byteLength > 0;\n if (!hasContract) return [];\n\n const hashes = await nearClient.view<Record<string, never>, number[][]>({\n account: accountId,\n method: 'get_recovery_emails',\n args: {} as Record<string, never>,\n });\n\n return Array.isArray(hashes) ? (hashes as number[][]) : [];\n } catch (error) {\n console.error('[rpcCalls] Failed to fetch recovery email hashes', error);\n return [];\n }\n}\n\n/**\n * Build action args to update on-chain recovery emails for an account.\n * If the per-account contract is missing, deploy/attach the global recoverer via `init_email_recovery`.\n */\nexport async function buildSetRecoveryEmailsActions(\n nearClient: NearClient,\n accountId: AccountId,\n recoveryEmailHashes: number[][],\n contracts: EmailRecoveryContracts = DEFAULT_EMAIL_RECOVERY_CONTRACTS\n): Promise<ActionArgs[]> {\n let hasContract = false;\n try {\n const code = await nearClient.viewCode(accountId);\n hasContract = !!code && code.byteLength > 0;\n } catch {\n hasContract = false;\n }\n\n const {\n emailRecovererGlobalContract,\n zkEmailVerifierContract,\n emailDkimVerifierContract,\n } = contracts;\n\n return hasContract\n ? [\n {\n type: ActionType.UseGlobalContract,\n accountId: emailRecovererGlobalContract,\n },\n {\n type: ActionType.FunctionCall,\n methodName: 'set_recovery_emails',\n args: {\n recovery_emails: recoveryEmailHashes,\n },\n gas: '80000000000000',\n deposit: '0',\n },\n ]\n : [\n {\n type: ActionType.UseGlobalContract,\n accountId: emailRecovererGlobalContract,\n },\n {\n type: ActionType.FunctionCall,\n methodName: 'init_email_recovery',\n args: {\n zk_email_verifier: zkEmailVerifierContract,\n email_dkim_verifier: emailDkimVerifierContract,\n policy: null,\n recovery_emails: recoveryEmailHashes,\n },\n gas: '80000000000000',\n deposit: '0',\n },\n ];\n}\n\nexport async function fetchNonceBlockHashAndHeight({ nearClient, nearPublicKeyStr, nearAccountId }: {\n nearClient: NearClient,\n nearPublicKeyStr: string,\n nearAccountId: AccountId\n}): Promise<TransactionContext> {\n // Get access key and transaction block info concurrently\n const [accessKeyInfo, txBlockInfo] = await Promise.all([\n nearClient.viewAccessKey(nearAccountId, nearPublicKeyStr)\n .catch(e => { throw new Error(`Failed to fetch Access Key`) }),\n nearClient.viewBlock({ finality: 'final' })\n .catch(e => { throw new Error(`Failed to fetch Block Info`) })\n ]);\n if (!accessKeyInfo || accessKeyInfo.nonce === undefined) {\n throw new Error(`Access key not found or invalid for account ${nearAccountId} with public key ${nearPublicKeyStr}. Response: ${JSON.stringify(accessKeyInfo)}`);\n }\n const nextNonce = (BigInt(accessKeyInfo.nonce) + BigInt(1)).toString();\n const txBlockHeight = String(txBlockInfo.header.height);\n const txBlockHash = txBlockInfo.header.hash; // Keep original base58 string\n\n return {\n nearPublicKeyStr,\n accessKeyInfo,\n nextNonce,\n txBlockHeight,\n txBlockHash,\n };\n}\n\n// ===========================\n// REGISTRATION PRE-CHECK CALL\n// ===========================\n\nexport interface CheckCanRegisterUserResult {\n success: boolean;\n verified: boolean;\n logs: string[];\n error?: string;\n}\n\n/**\n * View-only registration pre-check.\n *\n * Calls the contract's `check_can_register_user` view method with VRF data\n * derived from the provided VRF challenge and a serialized WebAuthn\n * registration credential (typically with PRF outputs embedded).\n */\nexport async function checkCanRegisterUserContractCall({\n nearClient,\n contractId,\n vrfChallenge,\n credential,\n authenticatorOptions,\n}: {\n nearClient: NearClient;\n contractId: string;\n vrfChallenge: VRFChallenge;\n credential: WebAuthnRegistrationCredential;\n authenticatorOptions?: AuthenticatorOptions;\n}): Promise<CheckCanRegisterUserResult> {\n try {\n const vrfData = {\n vrf_input_data: Array.from(base64UrlDecode(vrfChallenge.vrfInput)),\n vrf_output: Array.from(base64UrlDecode(vrfChallenge.vrfOutput)),\n vrf_proof: Array.from(base64UrlDecode(vrfChallenge.vrfProof)),\n public_key: Array.from(base64UrlDecode(vrfChallenge.vrfPublicKey)),\n user_id: vrfChallenge.userId,\n rp_id: vrfChallenge.rpId,\n block_height: Number(vrfChallenge.blockHeight),\n block_hash: Array.from(base64UrlDecode(vrfChallenge.blockHash)),\n };\n\n const args = {\n vrf_data: vrfData,\n webauthn_registration: credential,\n authenticator_options: authenticatorOptions,\n };\n\n const response = await nearClient.callFunction<typeof args, any>(\n contractId,\n 'check_can_register_user',\n args,\n );\n\n const verified = !!response?.verified;\n return {\n success: true,\n verified,\n logs: [],\n error: verified ? undefined : 'Contract registration check failed',\n };\n } catch (err: unknown) {\n return {\n success: false,\n verified: false,\n logs: [],\n error: errorMessage(err) || 'Failed to call check_can_register_user',\n };\n }\n}\n\n\n/**\n * Verify authentication response through relay server\n * Routes the request to relay server which calls the web3authn contract for verification\n * and issues a JWT or session credential\n */\nexport async function verifyAuthenticationResponse(\n relayServerUrl: string,\n routePath: string,\n sessionKind: 'jwt' | 'cookie',\n vrfChallenge: VRFChallenge,\n webauthnAuthentication: WebAuthnAuthenticationCredential\n): Promise<{\n success: boolean;\n verified?: boolean;\n jwt?: string;\n sessionCredential?: any;\n error?: string;\n contractResponse?: any;\n}> {\n try {\n // Map VRFChallenge into server ContractVrfData shape (number arrays)\n const toBytes = (b64u: string | undefined): number[] => {\n if (!b64u) return [];\n return Array.from(base64UrlDecode(b64u));\n };\n const vrf_data = {\n vrf_input_data: toBytes(vrfChallenge.vrfInput),\n vrf_output: toBytes(vrfChallenge.vrfOutput),\n vrf_proof: toBytes(vrfChallenge.vrfProof),\n public_key: toBytes(vrfChallenge.vrfPublicKey),\n user_id: vrfChallenge.userId,\n rp_id: vrfChallenge.rpId,\n block_height: Number(vrfChallenge.blockHeight || 0),\n block_hash: toBytes(vrfChallenge.blockHash),\n };\n\n // Normalize authenticatorAttachment and userHandle to null for server schema\n const webauthn_authentication = {\n ...webauthnAuthentication,\n authenticatorAttachment: webauthnAuthentication.authenticatorAttachment ?? null,\n response: {\n ...webauthnAuthentication.response,\n userHandle: webauthnAuthentication.response.userHandle ?? null,\n }\n };\n\n const url = `${relayServerUrl.replace(/\\/$/, '')}${routePath.startsWith('/') ? routePath : `/${routePath}`}`;\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n credentials: sessionKind === 'cookie' ? 'include' : 'omit',\n body: JSON.stringify({\n sessionKind: sessionKind,\n vrf_data,\n webauthn_authentication,\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n return {\n success: false,\n error: `HTTP ${response.status}: ${errorText}`,\n };\n }\n\n const result = await response.json();\n return {\n success: true,\n verified: result.verified,\n jwt: result.jwt,\n sessionCredential: result.sessionCredential,\n contractResponse: result.contractResponse,\n };\n } catch (error: any) {\n return {\n success: false,\n error: error.message || 'Failed to verify authentication response',\n };\n }\n}\n"],"mappings":"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"}