@tatchi-xyz/sdk 0.31.1 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +2 -0
  2. package/dist/cjs/core/TatchiPasskey/registration.js +40 -7
  3. package/dist/cjs/core/TatchiPasskey/registration.js.map +1 -1
  4. package/dist/cjs/core/WalletIframe/client/on-events-progress-bus.js +1 -1
  5. package/dist/cjs/core/WalletIframe/client/on-events-progress-bus.js.map +1 -1
  6. package/dist/cjs/core/types/sdkSentEvents.js +3 -2
  7. package/dist/cjs/core/types/sdkSentEvents.js.map +1 -1
  8. package/dist/cjs/react/context/useTatchiWithSdkFlow.js +1 -1
  9. package/dist/cjs/react/context/useTatchiWithSdkFlow.js.map +1 -1
  10. package/dist/cjs/react/src/core/TatchiPasskey/registration.js +40 -7
  11. package/dist/cjs/react/src/core/TatchiPasskey/registration.js.map +1 -1
  12. package/dist/cjs/react/src/core/WalletIframe/client/on-events-progress-bus.js +1 -1
  13. package/dist/cjs/react/src/core/WalletIframe/client/on-events-progress-bus.js.map +1 -1
  14. package/dist/cjs/react/src/core/types/sdkSentEvents.js +3 -2
  15. package/dist/cjs/react/src/core/types/sdkSentEvents.js.map +1 -1
  16. package/dist/esm/core/TatchiPasskey/registration.js +40 -7
  17. package/dist/esm/core/TatchiPasskey/registration.js.map +1 -1
  18. package/dist/esm/core/WalletIframe/client/on-events-progress-bus.js +1 -1
  19. package/dist/esm/core/WalletIframe/client/on-events-progress-bus.js.map +1 -1
  20. package/dist/esm/core/types/sdkSentEvents.js +3 -2
  21. package/dist/esm/core/types/sdkSentEvents.js.map +1 -1
  22. package/dist/esm/react/context/useTatchiWithSdkFlow.js +1 -1
  23. package/dist/esm/react/context/useTatchiWithSdkFlow.js.map +1 -1
  24. package/dist/esm/react/src/core/TatchiPasskey/registration.js +40 -7
  25. package/dist/esm/react/src/core/TatchiPasskey/registration.js.map +1 -1
  26. package/dist/esm/react/src/core/WalletIframe/client/on-events-progress-bus.js +1 -1
  27. package/dist/esm/react/src/core/WalletIframe/client/on-events-progress-bus.js.map +1 -1
  28. package/dist/esm/react/src/core/types/sdkSentEvents.js +3 -2
  29. package/dist/esm/react/src/core/types/sdkSentEvents.js.map +1 -1
  30. package/dist/esm/sdk/{delegateAction-DdkvFFKA.js → delegateAction-Bq5zkOvn.js} +1 -1
  31. package/dist/esm/sdk/{emailRecovery-C0LSDleV.js → emailRecovery-B1hbE_sM.js} +3 -3
  32. package/dist/esm/sdk/{linkDevice-Ds1GNIDk.js → linkDevice-CRPf5aW2.js} +3 -3
  33. package/dist/esm/sdk/{login-BKhTuGcy.js → login-DUIWZHp_.js} +2 -2
  34. package/dist/esm/sdk/offline-export-app.js +3 -2
  35. package/dist/esm/sdk/offline-export-app.js.map +1 -1
  36. package/dist/esm/sdk/{relay-Dq9D7fhG.js → relay-BCEyWFew.js} +1 -1
  37. package/dist/esm/sdk/{router-2aGn-CTp.js → router-Cj2WexK-.js} +2 -2
  38. package/dist/esm/sdk/{rpcCalls-BPI0icZG.js → rpcCalls-C1sp-Epo.js} +2 -2
  39. package/dist/esm/sdk/{rpcCalls-BW3M_q3-.js → rpcCalls-VL4loDKP.js} +1 -1
  40. package/dist/esm/sdk/{scanDevice-BBSehlMx.js → scanDevice-C0HcnZym.js} +3 -3
  41. package/dist/esm/sdk/{sdkSentEvents-CzAZBFjP.js → sdkSentEvents-BfkcI7EN.js} +3 -2
  42. package/dist/esm/sdk/{signNEP413-DsyWH_Jo.js → signNEP413-lj0swHsD.js} +1 -1
  43. package/dist/esm/sdk/{syncAccount-DEZHBiRa.js → syncAccount-DnQ9AstS.js} +3 -3
  44. package/dist/esm/sdk/{syncAccount-DHKtl-xh.js → syncAccount-xh81Vppo.js} +2 -2
  45. package/dist/esm/sdk/wallet-iframe-host.js +54 -21
  46. package/dist/esm/wasm_vrf_worker/pkg/wasm_vrf_worker_bg.wasm +0 -0
  47. package/dist/types/src/core/types/sdkSentEvents.d.ts +18 -7
  48. package/dist/types/src/core/types/sdkSentEvents.d.ts.map +1 -1
  49. package/dist/workers/offline-export-sw.js +1 -156
  50. package/dist/workers/wasm_vrf_worker_bg.wasm +0 -0
  51. package/dist/workers/web3authn-signer.worker.js +2 -1360
  52. package/dist/workers/web3authn-vrf.worker.js +2 -2857
  53. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"registration.js","names":["confirmationConfig: Partial<ConfirmationConfig>","thresholdClientVerifyingShareB64u: string | null","expectedAccessKeys: string[]","error: unknown","rollbackError: unknown"],"sources":["../../../../src/core/TatchiPasskey/registration.ts"],"sourcesContent":["import type { NearClient } from '../NearClient';\nimport { ensureEd25519Prefix, validateNearAccountId } from '../../utils/validation';\nimport type {\n RegistrationHooksOptions,\n RegistrationSSEEvent,\n} from '../types/sdkSentEvents';\nimport type { RegistrationResult, TatchiConfigs } from '../types/tatchi';\nimport type { AuthenticatorOptions } from '../types/authenticatorOptions';\nimport { RegistrationPhase, RegistrationStatus } from '../types/sdkSentEvents';\nimport {\n createAccountAndRegisterWithRelayServer\n} from './faucets/createAccountRelayServer';\nimport { PasskeyManagerContext } from './index';\nimport { WebAuthnManager } from '../WebAuthnManager';\nimport { IndexedDBManager } from '../IndexedDBManager';\nimport { VRFChallenge } from '../types/vrf-worker';\nimport { type ConfirmationConfig, type SignerMode, mergeSignerMode } from '../types/signer-worker';\nimport type { WebAuthnRegistrationCredential } from '../types/webauthn';\nimport type { AccountId } from '../types/accountIds';\nimport { getUserFriendlyErrorMessage } from '../../utils/errors';\nimport { authenticatorsToAllowCredentials } from '../WebAuthnManager/touchIdPrompt';\nimport { DEFAULT_WAIT_STATUS } from '../types/rpc';\nimport { buildThresholdEd25519Participants2pV1 } from '../../threshold/participants';\n// Registration forces a visible, clickable confirmation for cross‑origin safety\n\n/**\n * Core registration function that handles passkey registration\n *\n * VRF Registration Flow (Single VRF Keypair):\n * 1. Generate VRF keypair (ed25519) using crypto.randomUUID() + persist in worker memory\n * 2. Generate VRF proof + output using the VRF keypair\n * - VRF input with domain separator + NEAR block height + hash\n * 3. Use VRF output as WebAuthn challenge in registration ceremony\n * 4. Derive AES key from WebAuthn PRF output and encrypt the SAME VRF keypair\n * 5. Store encrypted VRF keypair in IndexedDB\n * 6. Call contract verify_registration_response with VRF proof + WebAuthn registration payload\n * 7. Contract verifies VRF proof and WebAuthn registration (challenges match!)\n * 8. Contract stores VRF pubkey + authenticator credentials on-chain for\n * future stateless authentication\n */\nexport async function registerPasskeyInternal(\n context: PasskeyManagerContext,\n nearAccountId: AccountId,\n options: RegistrationHooksOptions,\n authenticatorOptions: AuthenticatorOptions,\n confirmationConfigOverride?: Partial<ConfirmationConfig>\n): Promise<RegistrationResult> {\n\n const { onEvent, onError, afterCall } = options;\n const { webAuthnManager, configs } = context;\n\n // Track registration progress for rollback\n const registrationState = {\n accountCreated: false,\n contractRegistered: false,\n databaseStored: false,\n contractTransactionId: null as string | null,\n };\n\n console.log('⚡ Registration: Passkey registration with VRF WebAuthn');\n onEvent?.({\n step: 1,\n phase: RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION,\n status: RegistrationStatus.PROGRESS,\n message: `Starting registration for ${nearAccountId}`\n } as RegistrationSSEEvent);\n\n try {\n\n await validateRegistrationInputs(context, nearAccountId, onEvent, onError);\n\n onEvent?.({\n step: 1,\n phase: RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION,\n status: RegistrationStatus.PROGRESS,\n message: 'Generating passkey credential...'\n });\n\n const confirmationConfig: Partial<ConfirmationConfig> = {\n uiMode: 'modal',\n behavior: 'requireClick', // cross‑origin safari requirement: must requireClick\n theme: (context.configs?.walletTheme === 'light') ? 'light' : 'dark',\n ...(confirmationConfigOverride ?? options?.confirmationConfig ?? {}),\n };\n\n const registrationSession = await context.webAuthnManager.requestRegistrationCredentialConfirmation({\n nearAccountId: String(nearAccountId),\n deviceNumber: 1,\n confirmerText: options?.confirmerText,\n confirmationConfigOverride: confirmationConfig,\n });\n\n const credential = registrationSession.credential;\n const vrfChallenge = registrationSession.vrfChallenge;\n const transactionContext = registrationSession.transactionContext;\n\n onEvent?.({\n step: 1,\n phase: RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION,\n status: RegistrationStatus.SUCCESS,\n message: 'WebAuthn ceremony successful'\n });\n\n // 1) Ensure VRF keypair is derived and loaded in-memory\n // before deriving WrapKeySeed for NEAR key encryption\n const deterministicVrfKeyResult = await webAuthnManager.deriveVrfKeypair({\n credential,\n nearAccountId,\n saveInMemory: true,\n });\n if (!deterministicVrfKeyResult.success || !deterministicVrfKeyResult.vrfPublicKey) {\n throw new Error('Failed to derive deterministic VRF keypair from PRF');\n }\n\n const baseSignerMode = webAuthnManager.getUserPreferences().getSignerMode();\n const requestedSignerMode = mergeSignerMode(baseSignerMode, options?.signerMode);\n const requestedSignerModeStr = requestedSignerMode.mode;\n\n // 2) Derive/enroll the local NEAR key after VRF keypair exists.\n const nearKeyResult = await webAuthnManager.deriveNearKeypairAndEncryptFromSerialized({\n credential,\n nearAccountId,\n options: { deviceNumber: 1 },\n });\n if (!nearKeyResult.success || !nearKeyResult.publicKey) {\n const reason = nearKeyResult?.error || 'Failed to generate NEAR keypair with PRF';\n throw new Error(reason);\n }\n const nearPublicKey = nearKeyResult.publicKey;\n const wrapKeySalt = String(nearKeyResult.wrapKeySalt || '').trim();\n if (!wrapKeySalt) {\n throw new Error('Missing wrapKeySalt after local key derivation');\n }\n\n // Optional: threshold-signer enrollment during registration.\n // Derive client verifying share (public) and let the relay compute threshold group public key\n // and include it in the on-chain AddKey set during create_account_and_register_user.\n let thresholdClientVerifyingShareB64u: string | null = null;\n if (requestedSignerModeStr === 'threshold-signer') {\n const derived = await webAuthnManager.deriveThresholdEd25519ClientVerifyingShareFromCredential({\n credential,\n nearAccountId,\n wrapKeySalt,\n });\n if (!derived.success || !derived.clientVerifyingShareB64u) {\n throw new Error(derived.error || 'Failed to derive threshold client verifying share');\n }\n thresholdClientVerifyingShareB64u = derived.clientVerifyingShareB64u;\n }\n\n // Step 4-5: Create account and register with contract using the relay (atomic)\n onEvent?.({\n step: 2,\n phase: RegistrationPhase.STEP_2_KEY_GENERATION,\n status: RegistrationStatus.SUCCESS,\n message: 'Wallet derived successfully from Passkey',\n verified: true,\n nearAccountId: nearAccountId,\n nearPublicKey: nearPublicKey,\n vrfPublicKey: vrfChallenge.vrfPublicKey,\n });\n\n let accountAndRegistrationResult;\n accountAndRegistrationResult = await createAccountAndRegisterWithRelayServer(\n context,\n nearAccountId,\n nearPublicKey,\n credential,\n vrfChallenge,\n deterministicVrfKeyResult.vrfPublicKey,\n authenticatorOptions,\n onEvent,\n {\n thresholdEd25519: thresholdClientVerifyingShareB64u\n ? { clientVerifyingShareB64u: thresholdClientVerifyingShareB64u }\n : undefined,\n },\n );\n\n if (!accountAndRegistrationResult.success) {\n throw new Error(accountAndRegistrationResult.error || 'Account creation and registration failed');\n }\n\n // Update registration state based on results\n registrationState.accountCreated = true;\n registrationState.contractRegistered = true;\n registrationState.contractTransactionId = accountAndRegistrationResult.transactionId || null;\n\n // Step 6: Post-commit verification: ensure on-chain access key matches expected public key\n onEvent?.({\n step: 6,\n phase: RegistrationPhase.STEP_6_ACCOUNT_VERIFICATION,\n status: RegistrationStatus.PROGRESS,\n message: 'Verifying on-chain access key matches expected public key...'\n });\n\n const expectedAccessKeys: string[] = [nearPublicKey];\n const thresholdPublicKey = String(accountAndRegistrationResult?.thresholdEd25519?.publicKey || '').trim();\n const relayerKeyId = String(accountAndRegistrationResult?.thresholdEd25519?.relayerKeyId || '').trim();\n\n const accessKeyVerified = await verifyAccountAccessKeysPresent(\n context.nearClient,\n nearAccountId,\n expectedAccessKeys,\n { attempts: 3, delayMs: 200, finality: 'optimistic' },\n );\n\n if (!accessKeyVerified) {\n console.warn('[Registration] Access key not yet visible after atomic registration; continuing optimistically');\n onEvent?.({\n step: 6,\n phase: RegistrationPhase.STEP_6_ACCOUNT_VERIFICATION,\n status: RegistrationStatus.SUCCESS,\n message: 'Access key verification pending (optimistic); continuing...'\n });\n } else {\n onEvent?.({\n step: 6,\n phase: RegistrationPhase.STEP_6_ACCOUNT_VERIFICATION,\n status: RegistrationStatus.SUCCESS,\n message: 'Access key verified on-chain'\n });\n }\n\n // Threshold enrollment can take an extra on-chain tx + key propagation; don't block registration on it.\n activateThresholdEnrollmentPostRegistration({\n requestedSignerMode: requestedSignerModeStr,\n nearAccountId,\n nearPublicKey,\n thresholdPublicKey,\n relayerKeyId,\n clientParticipantId: accountAndRegistrationResult?.thresholdEd25519?.clientParticipantId,\n relayerParticipantId: accountAndRegistrationResult?.thresholdEd25519?.relayerParticipantId,\n thresholdClientVerifyingShareB64u,\n relayerVerifyingShareB64u: String(\n accountAndRegistrationResult?.thresholdEd25519?.relayerVerifyingShareB64u || '',\n ).trim(),\n credential,\n wrapKeySalt,\n webAuthnManager: context.webAuthnManager,\n nearClient: context.nearClient,\n onEvent,\n }).catch(() => {});\n\n // Step 7: Store user data with VRF credentials atomically\n onEvent?.({\n step: 7,\n phase: RegistrationPhase.STEP_7_DATABASE_STORAGE,\n status: RegistrationStatus.PROGRESS,\n message: 'Storing passkey wallet metadata...'\n });\n\n await webAuthnManager.atomicStoreRegistrationData({\n nearAccountId,\n credential,\n publicKey: nearPublicKey,\n encryptedVrfKeypair: deterministicVrfKeyResult.encryptedVrfKeypair,\n vrfPublicKey: deterministicVrfKeyResult.vrfPublicKey,\n serverEncryptedVrfKeypair: deterministicVrfKeyResult.serverEncryptedVrfKeypair,\n });\n\n // Mark database as stored for rollback tracking\n registrationState.databaseStored = true;\n\n onEvent?.({\n step: 7,\n phase: RegistrationPhase.STEP_7_DATABASE_STORAGE,\n status: RegistrationStatus.SUCCESS,\n message: 'Registration metadata stored successfully'\n });\n\n // Step 7: Ensure VRF session is active for auto-login\n // If VRF keypair is already in-memory (saved earlier), skip an extra Touch ID prompt.\n let vrfStatus = await webAuthnManager.checkVrfStatus().catch(() => ({ active: false }));\n if (!vrfStatus?.active) {\n // Prefer a no-prompt unlock using the existing registration credential (PRF already available).\n // Fallback to an explicit authentication ceremony only if needed.\n const unlockNoPrompt = await webAuthnManager.unlockVRFKeypair({\n nearAccountId: nearAccountId,\n encryptedVrfKeypair: deterministicVrfKeyResult.encryptedVrfKeypair,\n credential,\n }).catch((unlockError: unknown) => {\n const message = (unlockError && typeof unlockError === 'object' && 'message' in unlockError)\n ? String((unlockError as { message?: unknown }).message || '')\n : String(unlockError || '');\n return { success: false, error: message };\n });\n\n if (!unlockNoPrompt.success) {\n // Obtain an authentication credential for VRF unlock (separate from registration credential)\n // IMPORTANT: Immediately after account creation, the new access key may not be queryable yet on some RPC nodes.\n // We only need fresh block info for the VRF challenge here, so fetch the block directly to avoid AK lookup failures.\n let txBlockHash = String(transactionContext?.txBlockHash || '').trim();\n let txBlockHeight = String(transactionContext?.txBlockHeight || '').trim();\n if (!txBlockHash || !txBlockHeight) {\n const blockInfo = await context.nearClient.viewBlock({ finality: 'final' });\n txBlockHash = String(blockInfo?.header?.hash || '').trim();\n txBlockHeight = String(blockInfo?.header?.height ?? '').trim();\n }\n const vrfChallenge2 = await webAuthnManager.generateVrfChallengeOnce({\n userId: nearAccountId,\n rpId: webAuthnManager.getRpId(),\n blockHash: txBlockHash,\n blockHeight: txBlockHeight,\n });\n const allowCredentialIds = String(credential?.rawId || '').trim()\n ? [String(credential.rawId)]\n : (await webAuthnManager.getAuthenticatorsByUser(nearAccountId)).map((a) => a.credentialId);\n const authCredential = await webAuthnManager.getAuthenticationCredentialsSerializedDualPrf({\n nearAccountId,\n challenge: vrfChallenge2,\n credentialIds: allowCredentialIds,\n });\n const unlockResult = await webAuthnManager.unlockVRFKeypair({\n nearAccountId: nearAccountId,\n encryptedVrfKeypair: deterministicVrfKeyResult.encryptedVrfKeypair,\n credential: authCredential,\n }).catch((unlockError: unknown) => {\n const message = (unlockError && typeof unlockError === 'object' && 'message' in unlockError)\n ? String((unlockError as { message?: unknown }).message || '')\n : String(unlockError || '');\n return { success: false, error: message };\n });\n\n if (!unlockResult.success) {\n console.warn('VRF keypair unlock failed:', unlockResult.error);\n throw new Error(unlockResult.error);\n }\n } else {\n console.debug('Registration: VRF unlocked using registration credential; skipping extra Touch ID unlock');\n }\n } else {\n console.debug('Registration: VRF session already active; skipping extra Touch ID unlock');\n }\n\n // Initialize current user only after a successful unlock\n try {\n await webAuthnManager.initializeCurrentUser(nearAccountId);\n webAuthnManager.getNonceManager().prefetchBlockheight(context.nearClient).catch(() => {});\n } catch (initErr) {\n console.warn('Failed to initialize current user after registration:', initErr);\n }\n\n onEvent?.({\n step: 8,\n phase: RegistrationPhase.STEP_8_REGISTRATION_COMPLETE,\n status: RegistrationStatus.SUCCESS,\n message: 'Registration completed!'\n });\n\n const successResult = {\n success: true,\n nearAccountId: nearAccountId,\n clientNearPublicKey: nearPublicKey,\n transactionId: registrationState.contractTransactionId,\n vrfRegistration: {\n success: true,\n vrfPublicKey: vrfChallenge.vrfPublicKey,\n encryptedVrfKeypair: deterministicVrfKeyResult.encryptedVrfKeypair,\n contractVerified: accountAndRegistrationResult.success,\n }\n };\n\n afterCall?.(true, successResult);\n return successResult;\n\n } catch (error: unknown) {\n const message = (error && typeof error === 'object' && 'message' in error)\n ? String((error as { message?: unknown }).message || '')\n : String(error || '');\n const stack = (error && typeof error === 'object' && 'stack' in error)\n ? String((error as { stack?: unknown }).stack || '')\n : '';\n console.error('Registration failed:', message, stack);\n\n // Perform rollback based on registration state\n await performRegistrationRollback(\n registrationState,\n nearAccountId,\n webAuthnManager,\n onEvent\n );\n\n // Use centralized error handling\n const errorMessage = getUserFriendlyErrorMessage(error, 'registration', nearAccountId);\n\n const errorObject = new Error(errorMessage);\n onError?.(errorObject);\n\n onEvent?.({\n step: 0,\n phase: RegistrationPhase.REGISTRATION_ERROR,\n status: RegistrationStatus.ERROR,\n message: errorMessage,\n error: errorMessage\n } as RegistrationSSEEvent);\n\n const result = { success: false, error: errorMessage };\n afterCall?.(false);\n return result;\n }\n}\n\n// Backward-compatible wrapper without explicit confirmationConfig override\nexport async function registerPasskey(\n context: PasskeyManagerContext,\n nearAccountId: AccountId,\n options: RegistrationHooksOptions,\n authenticatorOptions: AuthenticatorOptions\n): Promise<RegistrationResult> {\n return registerPasskeyInternal(context, nearAccountId, options, authenticatorOptions, undefined);\n}\n\n//////////////////////////////////////\n// HELPER FUNCTIONS\n//////////////////////////////////////\n\n/**\n * Generate a VRF keypair + challenge in VRF wasm worker for WebAuthn registration ceremony bootstrapping\n *\n * ARCHITECTURE: This function solves the chicken-and-egg problem with a single VRF keypair:\n * 1. Generate VRF keypair + challenge (no PRF needed)\n * 2. Persist VRF keypair in worker memory (NOT encrypted yet)\n * 3. Use VRF challenge for WebAuthn ceremony → get PRF output\n * 4. Encrypt the SAME VRF keypair (still in memory) with PRF\n *\n * @param webAuthnManager - WebAuthn manager instance\n * @param nearAccountId - NEAR account ID for VRF input\n * @param blockHeight - Current NEAR block height for freshness\n * @param blockHashBytes - Current NEAR block hash bytes for entropy\n * @returns VRF challenge data (VRF keypair persisted in worker memory)\n */\nexport async function generateBootstrapVrfChallenge(\n context: PasskeyManagerContext,\n nearAccountId: AccountId,\n): Promise<VRFChallenge> {\n\n const { webAuthnManager, nearClient } = context;\n\n const blockInfo = await nearClient.viewBlock({ finality: 'final' });\n\n // Generate VRF keypair and persist in worker memory\n const vrfResult = await webAuthnManager.generateVrfKeypairBootstrap({\n vrfInputData: {\n userId: nearAccountId,\n // Keep VRF rpId consistent with WebAuthn rpId selection logic.\n rpId: webAuthnManager.getRpId(),\n blockHeight: String(blockInfo.header.height),\n blockHash: blockInfo.header.hash,\n },\n saveInMemory: true,\n // VRF keypair persists in worker memory until PRF encryption\n });\n\n if (!vrfResult.vrfChallenge) {\n throw new Error('Registration VRF keypair generation failed');\n }\n return vrfResult.vrfChallenge;\n}\n\n/**\n * Validates registration inputs and throws errors if invalid\n * @param nearAccountId - NEAR account ID to validate\n * @param onEvent - Optional callback for registration progress events\n * @param onError - Optional callback for error handling\n */\nconst validateRegistrationInputs = async (\n context: {\n configs: TatchiConfigs,\n webAuthnManager: WebAuthnManager,\n nearClient: NearClient,\n },\n nearAccountId: AccountId,\n onEvent?: (event: RegistrationSSEEvent) => void,\n onError?: (error: Error) => void,\n) => {\n\n onEvent?.({\n step: 1,\n phase: RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION,\n status: RegistrationStatus.PROGRESS,\n message: 'Validating registration inputs...'\n } as RegistrationSSEEvent);\n\n // Validation\n if (!nearAccountId) {\n const error = new Error('NEAR account ID is required for registration.');\n onError?.(error);\n throw error;\n }\n // Validate the account ID format\n const validation = validateNearAccountId(nearAccountId);\n if (!validation.valid) {\n const error = new Error(`Invalid NEAR account ID: ${validation.error}`);\n onError?.(error);\n throw error;\n }\n if (!window.isSecureContext) {\n const error = new Error('Passkey operations require a secure context (HTTPS or localhost).');\n onError?.(error);\n throw error;\n }\n\n // On-chain account existence / contract validation is performed by the relay + contract\n // during the atomic create_account_and_register_user call.\n onEvent?.({\n step: 1,\n phase: RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION,\n status: RegistrationStatus.PROGRESS,\n message: `Account format validated, preparing confirmation`\n } as RegistrationSSEEvent);\n return;\n}\n\n/**\n * Rollback registration data in case of errors\n */\nasync function performRegistrationRollback(\n registrationState: {\n accountCreated: boolean;\n contractRegistered: boolean;\n databaseStored: boolean;\n contractTransactionId: string | null;\n },\n nearAccountId: AccountId,\n webAuthnManager: WebAuthnManager,\n onEvent?: (event: RegistrationSSEEvent) => void\n): Promise<void> {\n console.debug('Starting registration rollback...', registrationState);\n\n // Rollback in reverse order\n try {\n // 1. Always clear any in-memory VRF session established during bootstrap\n await webAuthnManager.clearVrfSession();\n\n // 2. Rollback database storage\n if (registrationState.databaseStored) {\n console.debug('Rolling back database storage...');\n onEvent?.({\n step: 0,\n phase: RegistrationPhase.REGISTRATION_ERROR,\n status: RegistrationStatus.ERROR,\n message: 'Rolling back database storage...',\n error: 'Registration failed - rolling back database storage'\n } as RegistrationSSEEvent);\n\n await webAuthnManager.rollbackUserRegistration(nearAccountId);\n console.debug('Database rollback completed');\n }\n\n // 3. Contract rollback on the Web3Authn contract\n // NOT NEEDED - account creation and contract registration are atomic in the relay server flow\n if (registrationState.contractRegistered) {\n console.debug('Contract registration cannot be rolled back (immutable blockchain state)');\n onEvent?.({\n step: 0,\n phase: RegistrationPhase.REGISTRATION_ERROR,\n status: RegistrationStatus.ERROR,\n message: `Contract registration (tx: ${registrationState.contractTransactionId}) cannot be rolled back`,\n error: 'Registration failed - contract state is immutable'\n } as RegistrationSSEEvent);\n }\n console.debug('Registration rollback completed');\n\n } catch (rollbackError: unknown) {\n console.error('Rollback failed:', rollbackError);\n onEvent?.({\n step: 0,\n phase: RegistrationPhase.REGISTRATION_ERROR,\n status: RegistrationStatus.ERROR,\n message: `Rollback failed: ${\n (rollbackError && typeof rollbackError === 'object' && 'message' in rollbackError)\n ? String((rollbackError as { message?: unknown }).message || '')\n : String(rollbackError || '')\n }`,\n error: 'Both registration and rollback failed'\n } as RegistrationSSEEvent);\n }\n}\n\nasync function activateThresholdEnrollmentPostRegistration(opts: {\n requestedSignerMode: SignerMode['mode'];\n nearAccountId: AccountId;\n nearPublicKey: string;\n thresholdPublicKey: string;\n relayerKeyId: string;\n clientParticipantId?: number;\n relayerParticipantId?: number;\n thresholdClientVerifyingShareB64u: string | null;\n relayerVerifyingShareB64u: string;\n credential: WebAuthnRegistrationCredential;\n wrapKeySalt: string;\n webAuthnManager: WebAuthnManager;\n nearClient: NearClient;\n onEvent?: (event: RegistrationSSEEvent) => void;\n}): Promise<void> {\n // Optional: activate threshold enrollment post-registration by having the client\n // submit AddKey(thresholdPublicKey) signed with the local key.\n if (opts.requestedSignerMode !== 'threshold-signer') return;\n\n const thresholdPublicKey = String(opts.thresholdPublicKey || '').trim();\n const relayerKeyId = String(opts.relayerKeyId || '').trim();\n const clientVerifyingShareB64u = String(opts.thresholdClientVerifyingShareB64u || '').trim();\n const relayerVerifyingShareB64u = String(opts.relayerVerifyingShareB64u || '').trim();\n\n if (!thresholdPublicKey || !relayerKeyId || !clientVerifyingShareB64u || !relayerVerifyingShareB64u) {\n console.warn('[Registration] threshold-signer requested but threshold enrollment details are missing; continuing with local-signer only');\n return;\n }\n\n try {\n opts.onEvent?.({\n step: 6,\n phase: RegistrationPhase.STEP_6_ACCOUNT_VERIFICATION,\n status: RegistrationStatus.PROGRESS,\n message: 'Activating threshold access key onchain...'\n });\n\n // Prepare a single AddKey transaction signed with the local key (no extra TouchID prompt).\n try {\n opts.webAuthnManager.getNonceManager().initializeUser(opts.nearAccountId, opts.nearPublicKey);\n } catch {}\n const txContext = await opts.webAuthnManager.getNonceManager().getNonceBlockHashAndHeight(\n opts.nearClient,\n { force: true },\n );\n\n const signed = await opts.webAuthnManager.signAddKeyThresholdPublicKeyNoPrompt({\n nearAccountId: opts.nearAccountId,\n credential: opts.credential,\n wrapKeySalt: opts.wrapKeySalt,\n transactionContext: txContext,\n thresholdPublicKey,\n relayerVerifyingShareB64u,\n clientParticipantId: opts.clientParticipantId,\n relayerParticipantId: opts.relayerParticipantId,\n });\n\n const signedTx = signed?.signedTransaction;\n if (!signedTx) throw new Error('Failed to sign AddKey(thresholdPublicKey) transaction');\n\n await opts.nearClient.sendTransaction(signedTx, DEFAULT_WAIT_STATUS.thresholdAddKey);\n\n const thresholdKeyVerified = await verifyAccountAccessKeysPresent(\n opts.nearClient,\n opts.nearAccountId,\n [opts.nearPublicKey, thresholdPublicKey],\n { attempts: 6, delayMs: 250, finality: 'optimistic' },\n );\n if (!thresholdKeyVerified) {\n throw new Error('Threshold access key not found on-chain after AddKey');\n }\n\n await IndexedDBManager.nearKeysDB.storeKeyMaterial({\n kind: 'threshold_ed25519_2p_v1',\n nearAccountId: opts.nearAccountId,\n deviceNumber: 1,\n publicKey: thresholdPublicKey,\n wrapKeySalt: opts.wrapKeySalt,\n relayerKeyId,\n clientShareDerivation: 'prf_first_v1',\n participants: buildThresholdEd25519Participants2pV1({\n clientParticipantId: opts.clientParticipantId,\n relayerParticipantId: opts.relayerParticipantId,\n relayerKeyId,\n relayerUrl: opts.webAuthnManager.tatchiPasskeyConfigs?.relayer?.url,\n clientVerifyingShareB64u,\n relayerVerifyingShareB64u,\n clientShareDerivation: 'prf_first_v1',\n }),\n timestamp: Date.now(),\n });\n\n opts.onEvent?.({\n step: 6,\n phase: RegistrationPhase.STEP_6_ACCOUNT_VERIFICATION,\n status: RegistrationStatus.SUCCESS,\n message: 'Threshold access key activated on-chain'\n });\n } catch (e) {\n console.warn('[Registration] threshold enrollment activation failed; continuing with local-signer only:', e);\n }\n}\n\nasync function verifyAccountAccessKeysPresent(\n nearClient: NearClient,\n nearAccountId: string,\n expectedPublicKeys: string[],\n opts?: { attempts?: number; delayMs?: number; finality?: 'optimistic' | 'final' },\n): Promise<boolean> {\n const unique = Array.from(\n new Set(expectedPublicKeys.map((k) => ensureEd25519Prefix(k)).filter(Boolean)),\n );\n if (!unique.length) return false;\n\n const attempts = Math.max(1, Math.floor(opts?.attempts ?? 6));\n const delayMs = Math.max(50, Math.floor(opts?.delayMs ?? 750));\n const finality = opts?.finality ?? 'optimistic';\n\n for (let i = 0; i < attempts; i++) {\n try {\n const accessKeyList = await nearClient.viewAccessKeyList(\n nearAccountId,\n { finality } as any,\n );\n const keys = accessKeyList.keys.map((k) => ensureEd25519Prefix(k.public_key)).filter(Boolean);\n const allPresent = unique.every((expected) => keys.includes(expected));\n if (allPresent) return true;\n } catch {\n // tolerate transient view errors during propagation; retry\n }\n if (i < attempts - 1) {\n await new Promise((res) => setTimeout(res, delayMs));\n }\n }\n return false;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"registration.js","names":["confirmationConfig: Partial<ConfirmationConfig>","thresholdClientVerifyingShareB64u: string | null","expectedAccessKeys: string[]","error: unknown","rollbackError: unknown","missingEnrollmentDetails: string[]"],"sources":["../../../../src/core/TatchiPasskey/registration.ts"],"sourcesContent":["import type { NearClient } from '../NearClient';\nimport { ensureEd25519Prefix, validateNearAccountId } from '../../utils/validation';\nimport type {\n RegistrationHooksOptions,\n RegistrationSSEEvent,\n} from '../types/sdkSentEvents';\nimport type { RegistrationResult, TatchiConfigs } from '../types/tatchi';\nimport type { AuthenticatorOptions } from '../types/authenticatorOptions';\nimport { RegistrationPhase, RegistrationStatus } from '../types/sdkSentEvents';\nimport {\n createAccountAndRegisterWithRelayServer\n} from './faucets/createAccountRelayServer';\nimport { PasskeyManagerContext } from './index';\nimport { WebAuthnManager } from '../WebAuthnManager';\nimport { IndexedDBManager } from '../IndexedDBManager';\nimport { VRFChallenge } from '../types/vrf-worker';\nimport { type ConfirmationConfig, type SignerMode, mergeSignerMode } from '../types/signer-worker';\nimport type { WebAuthnRegistrationCredential } from '../types/webauthn';\nimport type { AccountId } from '../types/accountIds';\nimport { getUserFriendlyErrorMessage } from '../../utils/errors';\nimport { authenticatorsToAllowCredentials } from '../WebAuthnManager/touchIdPrompt';\nimport { DEFAULT_WAIT_STATUS } from '../types/rpc';\nimport { buildThresholdEd25519Participants2pV1 } from '../../threshold/participants';\n// Registration forces a visible, clickable confirmation for cross‑origin safety\n\n/**\n * Core registration function that handles passkey registration\n *\n * VRF Registration Flow (Single VRF Keypair):\n * 1. Generate VRF keypair (ed25519) using crypto.randomUUID() + persist in worker memory\n * 2. Generate VRF proof + output using the VRF keypair\n * - VRF input with domain separator + NEAR block height + hash\n * 3. Use VRF output as WebAuthn challenge in registration ceremony\n * 4. Derive AES key from WebAuthn PRF output and encrypt the SAME VRF keypair\n * 5. Store encrypted VRF keypair in IndexedDB\n * 6. Call contract verify_registration_response with VRF proof + WebAuthn registration payload\n * 7. Contract verifies VRF proof and WebAuthn registration (challenges match!)\n * 8. Contract stores VRF pubkey + authenticator credentials on-chain for\n * future stateless authentication\n */\nexport async function registerPasskeyInternal(\n context: PasskeyManagerContext,\n nearAccountId: AccountId,\n options: RegistrationHooksOptions,\n authenticatorOptions: AuthenticatorOptions,\n confirmationConfigOverride?: Partial<ConfirmationConfig>\n): Promise<RegistrationResult> {\n\n const { onEvent, onError, afterCall } = options;\n const { webAuthnManager, configs } = context;\n\n // Track registration progress for rollback\n const registrationState = {\n accountCreated: false,\n contractRegistered: false,\n databaseStored: false,\n contractTransactionId: null as string | null,\n };\n\n console.log('⚡ Registration: Passkey registration with VRF WebAuthn');\n onEvent?.({\n step: 1,\n phase: RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION,\n status: RegistrationStatus.PROGRESS,\n message: `Starting registration for ${nearAccountId}`\n } as RegistrationSSEEvent);\n\n try {\n\n await validateRegistrationInputs(context, nearAccountId, onEvent, onError);\n\n onEvent?.({\n step: 1,\n phase: RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION,\n status: RegistrationStatus.PROGRESS,\n message: 'Generating passkey credential...'\n });\n\n const confirmationConfig: Partial<ConfirmationConfig> = {\n uiMode: 'modal',\n behavior: 'requireClick', // cross‑origin safari requirement: must requireClick\n theme: (context.configs?.walletTheme === 'light') ? 'light' : 'dark',\n ...(confirmationConfigOverride ?? options?.confirmationConfig ?? {}),\n };\n\n const registrationSession = await context.webAuthnManager.requestRegistrationCredentialConfirmation({\n nearAccountId: String(nearAccountId),\n deviceNumber: 1,\n confirmerText: options?.confirmerText,\n confirmationConfigOverride: confirmationConfig,\n });\n\n const credential = registrationSession.credential;\n const vrfChallenge = registrationSession.vrfChallenge;\n const transactionContext = registrationSession.transactionContext;\n\n onEvent?.({\n step: 1,\n phase: RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION,\n status: RegistrationStatus.SUCCESS,\n message: 'WebAuthn ceremony successful'\n });\n\n // 1) Ensure VRF keypair is derived and loaded in-memory\n // before deriving WrapKeySeed for NEAR key encryption\n const deterministicVrfKeyResult = await webAuthnManager.deriveVrfKeypair({\n credential,\n nearAccountId,\n saveInMemory: true,\n });\n if (!deterministicVrfKeyResult.success || !deterministicVrfKeyResult.vrfPublicKey) {\n throw new Error('Failed to derive deterministic VRF keypair from PRF');\n }\n\n const baseSignerMode = webAuthnManager.getUserPreferences().getSignerMode();\n const requestedSignerMode = mergeSignerMode(baseSignerMode, options?.signerMode);\n const requestedSignerModeStr = requestedSignerMode.mode;\n\n // 2) Derive/enroll the local NEAR key after VRF keypair exists.\n const nearKeyResult = await webAuthnManager.deriveNearKeypairAndEncryptFromSerialized({\n credential,\n nearAccountId,\n options: { deviceNumber: 1 },\n });\n if (!nearKeyResult.success || !nearKeyResult.publicKey) {\n const reason = nearKeyResult?.error || 'Failed to generate NEAR keypair with PRF';\n throw new Error(reason);\n }\n const nearPublicKey = nearKeyResult.publicKey;\n const wrapKeySalt = String(nearKeyResult.wrapKeySalt || '').trim();\n if (!wrapKeySalt) {\n throw new Error('Missing wrapKeySalt after local key derivation');\n }\n\n // Optional: threshold-signer enrollment during registration.\n // Derive client verifying share (public) and let the relay compute threshold group public key\n // and include it in the on-chain AddKey set during create_account_and_register_user.\n let thresholdClientVerifyingShareB64u: string | null = null;\n if (requestedSignerModeStr === 'threshold-signer') {\n const derived = await webAuthnManager.deriveThresholdEd25519ClientVerifyingShareFromCredential({\n credential,\n nearAccountId,\n wrapKeySalt,\n });\n if (!derived.success || !derived.clientVerifyingShareB64u) {\n throw new Error(derived.error || 'Failed to derive threshold client verifying share');\n }\n thresholdClientVerifyingShareB64u = derived.clientVerifyingShareB64u;\n }\n\n // Step 4-5: Create account and register with contract using the relay (atomic)\n onEvent?.({\n step: 2,\n phase: RegistrationPhase.STEP_2_KEY_GENERATION,\n status: RegistrationStatus.SUCCESS,\n message: 'Wallet derived successfully from Passkey',\n verified: true,\n nearAccountId: nearAccountId,\n nearPublicKey: nearPublicKey,\n vrfPublicKey: vrfChallenge.vrfPublicKey,\n });\n\n let accountAndRegistrationResult;\n accountAndRegistrationResult = await createAccountAndRegisterWithRelayServer(\n context,\n nearAccountId,\n nearPublicKey,\n credential,\n vrfChallenge,\n deterministicVrfKeyResult.vrfPublicKey,\n authenticatorOptions,\n onEvent,\n {\n thresholdEd25519: thresholdClientVerifyingShareB64u\n ? { clientVerifyingShareB64u: thresholdClientVerifyingShareB64u }\n : undefined,\n },\n );\n\n if (!accountAndRegistrationResult.success) {\n throw new Error(accountAndRegistrationResult.error || 'Account creation and registration failed');\n }\n\n // Update registration state based on results\n registrationState.accountCreated = true;\n registrationState.contractRegistered = true;\n registrationState.contractTransactionId = accountAndRegistrationResult.transactionId || null;\n\n // Step 6: Post-commit verification: ensure on-chain access key matches expected public key\n onEvent?.({\n step: 6,\n phase: RegistrationPhase.STEP_6_ACCOUNT_VERIFICATION,\n status: RegistrationStatus.PROGRESS,\n message: 'Verifying on-chain access key matches expected public key...'\n });\n\n const expectedAccessKeys: string[] = [nearPublicKey];\n const thresholdPublicKey = String(accountAndRegistrationResult?.thresholdEd25519?.publicKey || '').trim();\n const relayerKeyId = String(accountAndRegistrationResult?.thresholdEd25519?.relayerKeyId || '').trim();\n\n const accessKeyVerified = await verifyAccountAccessKeysPresent(\n context.nearClient,\n nearAccountId,\n expectedAccessKeys,\n { attempts: 3, delayMs: 200, finality: 'optimistic' },\n );\n\n if (!accessKeyVerified) {\n console.warn('[Registration] Access key not yet visible after atomic registration; continuing optimistically');\n onEvent?.({\n step: 6,\n phase: RegistrationPhase.STEP_6_ACCOUNT_VERIFICATION,\n status: RegistrationStatus.SUCCESS,\n message: 'Access key verification pending (optimistic); continuing...'\n });\n } else {\n onEvent?.({\n step: 6,\n phase: RegistrationPhase.STEP_6_ACCOUNT_VERIFICATION,\n status: RegistrationStatus.SUCCESS,\n message: 'Access key verified on-chain'\n });\n }\n\n // Threshold enrollment can take an extra on-chain tx + key propagation; don't block registration on it.\n activateThresholdEnrollmentPostRegistration({\n requestedSignerMode: requestedSignerModeStr,\n nearAccountId,\n nearPublicKey,\n thresholdPublicKey,\n relayerKeyId,\n clientParticipantId: accountAndRegistrationResult?.thresholdEd25519?.clientParticipantId,\n relayerParticipantId: accountAndRegistrationResult?.thresholdEd25519?.relayerParticipantId,\n thresholdClientVerifyingShareB64u,\n relayerVerifyingShareB64u: String(\n accountAndRegistrationResult?.thresholdEd25519?.relayerVerifyingShareB64u || '',\n ).trim(),\n credential,\n wrapKeySalt,\n webAuthnManager: context.webAuthnManager,\n nearClient: context.nearClient,\n onEvent,\n }).catch(() => {});\n\n // Step 8: Store user data with VRF credentials atomically\n onEvent?.({\n step: 8,\n phase: RegistrationPhase.STEP_8_DATABASE_STORAGE,\n status: RegistrationStatus.PROGRESS,\n message: 'Storing passkey wallet metadata...'\n });\n\n await webAuthnManager.atomicStoreRegistrationData({\n nearAccountId,\n credential,\n publicKey: nearPublicKey,\n encryptedVrfKeypair: deterministicVrfKeyResult.encryptedVrfKeypair,\n vrfPublicKey: deterministicVrfKeyResult.vrfPublicKey,\n serverEncryptedVrfKeypair: deterministicVrfKeyResult.serverEncryptedVrfKeypair,\n });\n\n // Mark database as stored for rollback tracking\n registrationState.databaseStored = true;\n\n onEvent?.({\n step: 8,\n phase: RegistrationPhase.STEP_8_DATABASE_STORAGE,\n status: RegistrationStatus.SUCCESS,\n message: 'Registration metadata stored successfully'\n });\n\n // Step 8: Ensure VRF session is active for auto-login\n // If VRF keypair is already in-memory (saved earlier), skip an extra Touch ID prompt.\n let vrfStatus = await webAuthnManager.checkVrfStatus().catch(() => ({ active: false }));\n if (!vrfStatus?.active) {\n // Prefer a no-prompt unlock using the existing registration credential (PRF already available).\n // Fallback to an explicit authentication ceremony only if needed.\n const unlockNoPrompt = await webAuthnManager.unlockVRFKeypair({\n nearAccountId: nearAccountId,\n encryptedVrfKeypair: deterministicVrfKeyResult.encryptedVrfKeypair,\n credential,\n }).catch((unlockError: unknown) => {\n const message = (unlockError && typeof unlockError === 'object' && 'message' in unlockError)\n ? String((unlockError as { message?: unknown }).message || '')\n : String(unlockError || '');\n return { success: false, error: message };\n });\n\n if (!unlockNoPrompt.success) {\n // Obtain an authentication credential for VRF unlock (separate from registration credential)\n // IMPORTANT: Immediately after account creation, the new access key may not be queryable yet on some RPC nodes.\n // We only need fresh block info for the VRF challenge here, so fetch the block directly to avoid AK lookup failures.\n let txBlockHash = String(transactionContext?.txBlockHash || '').trim();\n let txBlockHeight = String(transactionContext?.txBlockHeight || '').trim();\n if (!txBlockHash || !txBlockHeight) {\n const blockInfo = await context.nearClient.viewBlock({ finality: 'final' });\n txBlockHash = String(blockInfo?.header?.hash || '').trim();\n txBlockHeight = String(blockInfo?.header?.height ?? '').trim();\n }\n const vrfChallenge2 = await webAuthnManager.generateVrfChallengeOnce({\n userId: nearAccountId,\n rpId: webAuthnManager.getRpId(),\n blockHash: txBlockHash,\n blockHeight: txBlockHeight,\n });\n const allowCredentialIds = String(credential?.rawId || '').trim()\n ? [String(credential.rawId)]\n : (await webAuthnManager.getAuthenticatorsByUser(nearAccountId)).map((a) => a.credentialId);\n const authCredential = await webAuthnManager.getAuthenticationCredentialsSerializedDualPrf({\n nearAccountId,\n challenge: vrfChallenge2,\n credentialIds: allowCredentialIds,\n });\n const unlockResult = await webAuthnManager.unlockVRFKeypair({\n nearAccountId: nearAccountId,\n encryptedVrfKeypair: deterministicVrfKeyResult.encryptedVrfKeypair,\n credential: authCredential,\n }).catch((unlockError: unknown) => {\n const message = (unlockError && typeof unlockError === 'object' && 'message' in unlockError)\n ? String((unlockError as { message?: unknown }).message || '')\n : String(unlockError || '');\n return { success: false, error: message };\n });\n\n if (!unlockResult.success) {\n console.warn('VRF keypair unlock failed:', unlockResult.error);\n throw new Error(unlockResult.error);\n }\n } else {\n console.debug('Registration: VRF unlocked using registration credential; skipping extra Touch ID unlock');\n }\n } else {\n console.debug('Registration: VRF session already active; skipping extra Touch ID unlock');\n }\n\n // Initialize current user only after a successful unlock\n try {\n await webAuthnManager.initializeCurrentUser(nearAccountId);\n webAuthnManager.getNonceManager().prefetchBlockheight(context.nearClient).catch(() => {});\n } catch (initErr) {\n console.warn('Failed to initialize current user after registration:', initErr);\n }\n\n onEvent?.({\n step: 9,\n phase: RegistrationPhase.STEP_9_REGISTRATION_COMPLETE,\n status: RegistrationStatus.SUCCESS,\n message: 'Registration completed!'\n });\n\n const successResult = {\n success: true,\n nearAccountId: nearAccountId,\n clientNearPublicKey: nearPublicKey,\n transactionId: registrationState.contractTransactionId,\n vrfRegistration: {\n success: true,\n vrfPublicKey: vrfChallenge.vrfPublicKey,\n encryptedVrfKeypair: deterministicVrfKeyResult.encryptedVrfKeypair,\n contractVerified: accountAndRegistrationResult.success,\n }\n };\n\n afterCall?.(true, successResult);\n return successResult;\n\n } catch (error: unknown) {\n const message = (error && typeof error === 'object' && 'message' in error)\n ? String((error as { message?: unknown }).message || '')\n : String(error || '');\n const stack = (error && typeof error === 'object' && 'stack' in error)\n ? String((error as { stack?: unknown }).stack || '')\n : '';\n console.error('Registration failed:', message, stack);\n\n // Perform rollback based on registration state\n await performRegistrationRollback(\n registrationState,\n nearAccountId,\n webAuthnManager,\n onEvent\n );\n\n // Use centralized error handling\n const errorMessage = getUserFriendlyErrorMessage(error, 'registration', nearAccountId);\n\n const errorObject = new Error(errorMessage);\n onError?.(errorObject);\n\n onEvent?.({\n step: 0,\n phase: RegistrationPhase.REGISTRATION_ERROR,\n status: RegistrationStatus.ERROR,\n message: errorMessage,\n error: errorMessage\n } as RegistrationSSEEvent);\n\n const result = { success: false, error: errorMessage };\n afterCall?.(false);\n return result;\n }\n}\n\n// Backward-compatible wrapper without explicit confirmationConfig override\nexport async function registerPasskey(\n context: PasskeyManagerContext,\n nearAccountId: AccountId,\n options: RegistrationHooksOptions,\n authenticatorOptions: AuthenticatorOptions\n): Promise<RegistrationResult> {\n return registerPasskeyInternal(context, nearAccountId, options, authenticatorOptions, undefined);\n}\n\n//////////////////////////////////////\n// HELPER FUNCTIONS\n//////////////////////////////////////\n\n/**\n * Generate a VRF keypair + challenge in VRF wasm worker for WebAuthn registration ceremony bootstrapping\n *\n * ARCHITECTURE: This function solves the chicken-and-egg problem with a single VRF keypair:\n * 1. Generate VRF keypair + challenge (no PRF needed)\n * 2. Persist VRF keypair in worker memory (NOT encrypted yet)\n * 3. Use VRF challenge for WebAuthn ceremony → get PRF output\n * 4. Encrypt the SAME VRF keypair (still in memory) with PRF\n *\n * @param webAuthnManager - WebAuthn manager instance\n * @param nearAccountId - NEAR account ID for VRF input\n * @param blockHeight - Current NEAR block height for freshness\n * @param blockHashBytes - Current NEAR block hash bytes for entropy\n * @returns VRF challenge data (VRF keypair persisted in worker memory)\n */\nexport async function generateBootstrapVrfChallenge(\n context: PasskeyManagerContext,\n nearAccountId: AccountId,\n): Promise<VRFChallenge> {\n\n const { webAuthnManager, nearClient } = context;\n\n const blockInfo = await nearClient.viewBlock({ finality: 'final' });\n\n // Generate VRF keypair and persist in worker memory\n const vrfResult = await webAuthnManager.generateVrfKeypairBootstrap({\n vrfInputData: {\n userId: nearAccountId,\n // Keep VRF rpId consistent with WebAuthn rpId selection logic.\n rpId: webAuthnManager.getRpId(),\n blockHeight: String(blockInfo.header.height),\n blockHash: blockInfo.header.hash,\n },\n saveInMemory: true,\n // VRF keypair persists in worker memory until PRF encryption\n });\n\n if (!vrfResult.vrfChallenge) {\n throw new Error('Registration VRF keypair generation failed');\n }\n return vrfResult.vrfChallenge;\n}\n\n/**\n * Validates registration inputs and throws errors if invalid\n * @param nearAccountId - NEAR account ID to validate\n * @param onEvent - Optional callback for registration progress events\n * @param onError - Optional callback for error handling\n */\nconst validateRegistrationInputs = async (\n context: {\n configs: TatchiConfigs,\n webAuthnManager: WebAuthnManager,\n nearClient: NearClient,\n },\n nearAccountId: AccountId,\n onEvent?: (event: RegistrationSSEEvent) => void,\n onError?: (error: Error) => void,\n) => {\n\n onEvent?.({\n step: 1,\n phase: RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION,\n status: RegistrationStatus.PROGRESS,\n message: 'Validating registration inputs...'\n } as RegistrationSSEEvent);\n\n // Validation\n if (!nearAccountId) {\n const error = new Error('NEAR account ID is required for registration.');\n onError?.(error);\n throw error;\n }\n // Validate the account ID format\n const validation = validateNearAccountId(nearAccountId);\n if (!validation.valid) {\n const error = new Error(`Invalid NEAR account ID: ${validation.error}`);\n onError?.(error);\n throw error;\n }\n if (!window.isSecureContext) {\n const error = new Error('Passkey operations require a secure context (HTTPS or localhost).');\n onError?.(error);\n throw error;\n }\n\n // On-chain account existence / contract validation is performed by the relay + contract\n // during the atomic create_account_and_register_user call.\n onEvent?.({\n step: 1,\n phase: RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION,\n status: RegistrationStatus.PROGRESS,\n message: `Account format validated, preparing confirmation`\n } as RegistrationSSEEvent);\n return;\n}\n\n/**\n * Rollback registration data in case of errors\n */\nasync function performRegistrationRollback(\n registrationState: {\n accountCreated: boolean;\n contractRegistered: boolean;\n databaseStored: boolean;\n contractTransactionId: string | null;\n },\n nearAccountId: AccountId,\n webAuthnManager: WebAuthnManager,\n onEvent?: (event: RegistrationSSEEvent) => void\n): Promise<void> {\n console.debug('Starting registration rollback...', registrationState);\n\n // Rollback in reverse order\n try {\n // 1. Always clear any in-memory VRF session established during bootstrap\n await webAuthnManager.clearVrfSession();\n\n // 2. Rollback database storage\n if (registrationState.databaseStored) {\n console.debug('Rolling back database storage...');\n onEvent?.({\n step: 0,\n phase: RegistrationPhase.REGISTRATION_ERROR,\n status: RegistrationStatus.ERROR,\n message: 'Rolling back database storage...',\n error: 'Registration failed - rolling back database storage'\n } as RegistrationSSEEvent);\n\n await webAuthnManager.rollbackUserRegistration(nearAccountId);\n console.debug('Database rollback completed');\n }\n\n // 3. Contract rollback on the Web3Authn contract\n // NOT NEEDED - account creation and contract registration are atomic in the relay server flow\n if (registrationState.contractRegistered) {\n console.debug('Contract registration cannot be rolled back (immutable blockchain state)');\n onEvent?.({\n step: 0,\n phase: RegistrationPhase.REGISTRATION_ERROR,\n status: RegistrationStatus.ERROR,\n message: `Contract registration (tx: ${registrationState.contractTransactionId}) cannot be rolled back`,\n error: 'Registration failed - contract state is immutable'\n } as RegistrationSSEEvent);\n }\n console.debug('Registration rollback completed');\n\n } catch (rollbackError: unknown) {\n console.error('Rollback failed:', rollbackError);\n onEvent?.({\n step: 0,\n phase: RegistrationPhase.REGISTRATION_ERROR,\n status: RegistrationStatus.ERROR,\n message: `Rollback failed: ${\n (rollbackError && typeof rollbackError === 'object' && 'message' in rollbackError)\n ? String((rollbackError as { message?: unknown }).message || '')\n : String(rollbackError || '')\n }`,\n error: 'Both registration and rollback failed'\n } as RegistrationSSEEvent);\n }\n}\n\nasync function activateThresholdEnrollmentPostRegistration(opts: {\n requestedSignerMode: SignerMode['mode'];\n nearAccountId: AccountId;\n nearPublicKey: string;\n thresholdPublicKey: string;\n relayerKeyId: string;\n clientParticipantId?: number;\n relayerParticipantId?: number;\n thresholdClientVerifyingShareB64u: string | null;\n relayerVerifyingShareB64u: string;\n credential: WebAuthnRegistrationCredential;\n wrapKeySalt: string;\n webAuthnManager: WebAuthnManager;\n nearClient: NearClient;\n onEvent?: (event: RegistrationSSEEvent) => void;\n}): Promise<void> {\n // Optional: activate threshold enrollment post-registration by having the client\n // submit AddKey(thresholdPublicKey) signed with the local key.\n if (opts.requestedSignerMode !== 'threshold-signer') return;\n\n const thresholdPublicKey = String(opts.thresholdPublicKey || '').trim();\n const relayerKeyId = String(opts.relayerKeyId || '').trim();\n const clientVerifyingShareB64u = String(opts.thresholdClientVerifyingShareB64u || '').trim();\n const relayerVerifyingShareB64u = String(opts.relayerVerifyingShareB64u || '').trim();\n\n const emitThresholdKeyEnrollmentResult = (input: {\n thresholdKeyReady: boolean;\n message: string;\n warning?: string;\n }) => {\n opts.onEvent?.({\n step: 7,\n phase: RegistrationPhase.STEP_7_THRESHOLD_KEY_ENROLLMENT,\n status: RegistrationStatus.SUCCESS,\n message: input.message,\n thresholdKeyReady: input.thresholdKeyReady,\n thresholdPublicKey: thresholdPublicKey || undefined,\n relayerKeyId: relayerKeyId || undefined,\n deviceNumber: 1,\n warning: input.warning,\n });\n };\n\n const missingEnrollmentDetails: string[] = [];\n if (!thresholdPublicKey) missingEnrollmentDetails.push('thresholdPublicKey');\n if (!relayerKeyId) missingEnrollmentDetails.push('relayerKeyId');\n if (!clientVerifyingShareB64u) missingEnrollmentDetails.push('clientVerifyingShareB64u');\n if (!relayerVerifyingShareB64u) missingEnrollmentDetails.push('relayerVerifyingShareB64u');\n\n if (missingEnrollmentDetails.length) {\n console.warn('[Registration] threshold-signer requested but threshold enrollment details are missing; continuing with local-signer only');\n emitThresholdKeyEnrollmentResult({\n thresholdKeyReady: false,\n message: 'Threshold key not ready; continuing with local-signer only',\n warning: `Missing threshold enrollment details: ${missingEnrollmentDetails.join(', ')}`,\n });\n return;\n }\n\n try {\n opts.onEvent?.({\n step: 6,\n phase: RegistrationPhase.STEP_6_ACCOUNT_VERIFICATION,\n status: RegistrationStatus.PROGRESS,\n message: 'Activating threshold access key onchain...'\n });\n\n // Prepare a single AddKey transaction signed with the local key (no extra TouchID prompt).\n try {\n opts.webAuthnManager.getNonceManager().initializeUser(opts.nearAccountId, opts.nearPublicKey);\n } catch {}\n const txContext = await opts.webAuthnManager.getNonceManager().getNonceBlockHashAndHeight(\n opts.nearClient,\n { force: true },\n );\n\n const signed = await opts.webAuthnManager.signAddKeyThresholdPublicKeyNoPrompt({\n nearAccountId: opts.nearAccountId,\n credential: opts.credential,\n wrapKeySalt: opts.wrapKeySalt,\n transactionContext: txContext,\n thresholdPublicKey,\n relayerVerifyingShareB64u,\n clientParticipantId: opts.clientParticipantId,\n relayerParticipantId: opts.relayerParticipantId,\n });\n\n const signedTx = signed?.signedTransaction;\n if (!signedTx) throw new Error('Failed to sign AddKey(thresholdPublicKey) transaction');\n\n await opts.nearClient.sendTransaction(signedTx, DEFAULT_WAIT_STATUS.thresholdAddKey);\n\n const thresholdKeyVerified = await verifyAccountAccessKeysPresent(\n opts.nearClient,\n opts.nearAccountId,\n [opts.nearPublicKey, thresholdPublicKey],\n { attempts: 6, delayMs: 250, finality: 'optimistic' },\n );\n if (!thresholdKeyVerified) {\n throw new Error('Threshold access key not found on-chain after AddKey');\n }\n\n await IndexedDBManager.nearKeysDB.storeKeyMaterial({\n kind: 'threshold_ed25519_2p_v1',\n nearAccountId: opts.nearAccountId,\n deviceNumber: 1,\n publicKey: thresholdPublicKey,\n wrapKeySalt: opts.wrapKeySalt,\n relayerKeyId,\n clientShareDerivation: 'prf_first_v1',\n participants: buildThresholdEd25519Participants2pV1({\n clientParticipantId: opts.clientParticipantId,\n relayerParticipantId: opts.relayerParticipantId,\n relayerKeyId,\n relayerUrl: opts.webAuthnManager.tatchiPasskeyConfigs?.relayer?.url,\n clientVerifyingShareB64u,\n relayerVerifyingShareB64u,\n clientShareDerivation: 'prf_first_v1',\n }),\n timestamp: Date.now(),\n });\n\n opts.onEvent?.({\n step: 6,\n phase: RegistrationPhase.STEP_6_ACCOUNT_VERIFICATION,\n status: RegistrationStatus.SUCCESS,\n message: 'Threshold access key activated on-chain'\n });\n\n emitThresholdKeyEnrollmentResult({\n thresholdKeyReady: true,\n message: 'Threshold key ready',\n });\n } catch (e) {\n const warning = (e && typeof e === 'object' && 'message' in e)\n ? String((e as { message?: unknown }).message || '')\n : String(e || '');\n console.warn('[Registration] threshold enrollment activation failed; continuing with local-signer only:', e);\n emitThresholdKeyEnrollmentResult({\n thresholdKeyReady: false,\n message: 'Threshold key not ready; continuing with local-signer only',\n warning,\n });\n }\n}\n\nasync function verifyAccountAccessKeysPresent(\n nearClient: NearClient,\n nearAccountId: string,\n expectedPublicKeys: string[],\n opts?: { attempts?: number; delayMs?: number; finality?: 'optimistic' | 'final' },\n): Promise<boolean> {\n const unique = Array.from(\n new Set(expectedPublicKeys.map((k) => ensureEd25519Prefix(k)).filter(Boolean)),\n );\n if (!unique.length) return false;\n\n const attempts = Math.max(1, Math.floor(opts?.attempts ?? 6));\n const delayMs = Math.max(50, Math.floor(opts?.delayMs ?? 750));\n const finality = opts?.finality ?? 'optimistic';\n\n for (let i = 0; i < attempts; i++) {\n try {\n const accessKeyList = await nearClient.viewAccessKeyList(\n nearAccountId,\n { finality } as any,\n );\n const keys = accessKeyList.keys.map((k) => ensureEd25519Prefix(k.public_key)).filter(Boolean);\n const allPresent = unique.every((expected) => keys.includes(expected));\n if (allPresent) return true;\n } catch {\n // tolerate transient view errors during propagation; retry\n }\n if (i < attempts - 1) {\n await new Promise((res) => setTimeout(res, delayMs));\n }\n }\n return false;\n}\n"],"mappings":"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"}
@@ -24,7 +24,7 @@ const HIDE_PHASES = new Set([
24
24
  DeviceLinkingPhase.LOGIN_ERROR,
25
25
  DeviceLinkingPhase.DEVICE_LINKING_ERROR,
26
26
  RegistrationPhase.STEP_5_CONTRACT_REGISTRATION,
27
- RegistrationPhase.STEP_8_REGISTRATION_COMPLETE,
27
+ RegistrationPhase.STEP_9_REGISTRATION_COMPLETE,
28
28
  RegistrationPhase.REGISTRATION_ERROR,
29
29
  LoginPhase.STEP_3_VRF_UNLOCK,
30
30
  LoginPhase.STEP_4_LOGIN_COMPLETE,
@@ -1 +1 @@
1
- {"version":3,"file":"on-events-progress-bus.js","names":["DelegateActionPhase","defaultPhaseHeuristics: PhaseHeuristics"],"sources":["../../../../../src/core/WalletIframe/client/on-events-progress-bus.ts"],"sourcesContent":["/**\n * OnEventsProgressBus - Client-Side Communication Layer\n *\n * Manages progress event routing and overlay visibility *intents* for the wallet\n * iframe. It never manipulates the iframe directly; instead it calls the\n * injected OverlayController interface (show/hide), and WalletIframeRouter\n * owns the concrete OverlayController that knows how to display the iframe.\n *\n * Key Responsibilities:\n * - Progress Routing: Dispatches typed progress payloads to per-request subscribers\n * - Overlay Intents: Applies SHOW/HIDE based on phase heuristics, leaving actual\n * DOM/CSS work to WalletIframeRouter + OverlayController\n * - Concurrent Aggregation: Tracks overlay demand per requestId and only hides\n * when no request still requires SHOW (multi-request safe)\n * - Sticky Subscriptions: Supports long-running subscriptions that persist after completion\n * - Phase Heuristics: Pluggable logic to map phases → 'show' | 'hide' | 'none'\n * - Event Statistics: Tracks counts/timestamps for debugging\n */\n\nimport type { ProgressPayload as MessageProgressPayload } from '../shared/messages';\nimport {\n ActionPhase,\n DeviceLinkingPhase,\n SyncAccountPhase,\n RegistrationPhase,\n LoginPhase,\n EmailRecoveryPhase,\n DelegateActionPhase,\n} from '../../types/sdkSentEvents';\n\n// Phases that should temporarily SHOW the overlay (to capture activation)\n// IMPORTANT: STEP_2_USER_CONFIRMATION must remain in this list. Without it,\n// modal confirmation with behavior: 'requireClick' will never be visible in\n// iframe mode, because the wallet iframe is still 0×0 when the modal mounts.\nconst SHOW_PHASES = new Set<string>([\n // Gate overlay to moments of imminent activation only.\n // Show early during user confirmation so the modal inside the wallet iframe is visible\n // and can capture the required click when behavior === 'requireClick'.\n ActionPhase.STEP_2_USER_CONFIRMATION,\n DelegateActionPhase.STEP_2_USER_CONFIRMATION,\n ActionPhase.STEP_3_WEBAUTHN_AUTHENTICATION,\n DelegateActionPhase.STEP_3_WEBAUTHN_AUTHENTICATION,\n // Registration requires a WebAuthn create() ceremony at step 1\n RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION,\n // Email recovery: TouchID registration uses WebAuthn create()\n EmailRecoveryPhase.STEP_2_TOUCH_ID_REGISTRATION,\n // Device1: TouchID authorization (host needs overlay to capture activation)\n DeviceLinkingPhase.STEP_3_AUTHORIZATION,\n // Device2: Registration inside wallet host (collects passkey via ModalTxConfirmer)\n // Show overlay so the wallet iframe is visible and focused for WebAuthn\n DeviceLinkingPhase.STEP_6_REGISTRATION,\n SyncAccountPhase.STEP_2_WEBAUTHN_AUTHENTICATION,\n LoginPhase.STEP_2_WEBAUTHN_ASSERTION,\n]);\n\n// Phases that should HIDE the overlay asap (post-activation, non-interactive)\nconst HIDE_PHASES = new Set<string>([\n ActionPhase.STEP_4_AUTHENTICATION_COMPLETE,\n ActionPhase.STEP_5_TRANSACTION_SIGNING_PROGRESS,\n ActionPhase.STEP_6_TRANSACTION_SIGNING_COMPLETE,\n ActionPhase.STEP_7_BROADCASTING,\n ActionPhase.STEP_8_ACTION_COMPLETE,\n // Device linking: hide when the flow has finished or errored\n DeviceLinkingPhase.STEP_7_LINKING_COMPLETE,\n DeviceLinkingPhase.REGISTRATION_ERROR,\n DeviceLinkingPhase.LOGIN_ERROR,\n DeviceLinkingPhase.DEVICE_LINKING_ERROR,\n // Registration: hide once contract work starts or flow completes/errors\n RegistrationPhase.STEP_5_CONTRACT_REGISTRATION,\n RegistrationPhase.STEP_8_REGISTRATION_COMPLETE,\n RegistrationPhase.REGISTRATION_ERROR,\n // Login: hide after assertion leads to VRF unlock or completion/errors\n LoginPhase.STEP_3_VRF_UNLOCK,\n LoginPhase.STEP_4_LOGIN_COMPLETE,\n LoginPhase.LOGIN_ERROR,\n // Account sync: hide after authentication completes or on completion/errors\n SyncAccountPhase.STEP_4_AUTHENTICATOR_SAVED,\n SyncAccountPhase.STEP_5_SYNC_ACCOUNT_COMPLETE,\n SyncAccountPhase.ERROR,\n // Email recovery: hide after finalization/complete or on error\n EmailRecoveryPhase.STEP_5_FINALIZING_REGISTRATION,\n EmailRecoveryPhase.STEP_6_COMPLETE,\n EmailRecoveryPhase.ERROR,\n]);\n\nexport type ProgressPayload = MessageProgressPayload;\n\n// Minimal overlay control interface used by ProgressBus.\n// Implemented by WalletIframeRouter via an adapter object that calls\n// into the concrete OverlayToggler (fullscreen/anchored) as needed.\nexport interface OverlayToggler {\n show: () => void;\n hide: () => void;\n}\n\nexport type PhaseHeuristics = (payload: ProgressPayload) => 'show' | 'hide' | 'none';\n\nexport interface ProgressSubscriber {\n onProgress?: (payload: ProgressPayload) => void;\n sticky: boolean;\n stats: { count: number; lastPhase: string | null; lastAt: number | null };\n}\n\nexport class OnEventsProgressBus {\n private subs = new Map<string, ProgressSubscriber>();\n private logger?: (msg: string, data?: Record<string, unknown>) => void;\n private overlay: OverlayToggler;\n private heuristic: PhaseHeuristics;\n // Track the most recent overlay intent per requestId so that we can\n // aggregate visibility across concurrent requests. If any request's\n // latest intent is 'show', we keep the overlay visible.\n private overlayDemands = new Map<string, 'show' | 'hide' | 'none'>();\n\n constructor(overlay: OverlayToggler, heuristic: PhaseHeuristics, logger?: (msg: string, data?: Record<string, unknown>) => void) {\n this.overlay = overlay;\n this.heuristic = heuristic;\n this.logger = logger;\n }\n\n /**\n * Register a subscriber for a requestId.\n * Initializes demand tracking to 'none' (neutral) until phases arrive.\n */\n register({ requestId, onProgress, sticky = false }: {\n requestId: string,\n sticky: boolean,\n onProgress?: (p: ProgressPayload) => void,\n }): void {\n this.subs.set(requestId, {\n onProgress,\n sticky,\n stats: { count: 0, lastPhase: null, lastAt: null }\n });\n // Initialize demand tracking for this request as neutral\n this.overlayDemands.set(requestId, 'none');\n this.log('register', { requestId, sticky });\n }\n\n /**\n * Unregister a subscriber and clear its overlay demand.\n * If no remaining requests demand 'show', the overlay is hidden.\n */\n unregister(requestId: string): void {\n if (this.subs.delete(requestId)) this.log('unregister', { requestId });\n // Remove any overlay demand for this request\n this.overlayDemands.delete(requestId);\n // If no remaining requests demand 'show', we can safely hide\n if (!this.wantsVisible()) {\n try { this.overlay.hide(); } catch {}\n }\n }\n\n /**\n * Remove all subscribers and demands; overlay demand set is cleared.\n */\n clearAll(): void {\n this.subs.clear();\n this.overlayDemands.clear();\n this.log('clearAll');\n }\n\n isSticky(requestId: string): boolean {\n const sub = this.subs.get(requestId);\n return !!sub?.sticky;\n }\n\n /**\n * Dispatch a progress payload to a request's subscriber and update\n * the aggregate overlay demand based on the phase heuristic.\n */\n dispatch({ requestId, payload }: {\n requestId: string,\n payload: ProgressPayload\n }): boolean {\n\n const phase = String((payload || {}).phase || '');\n const action = this.heuristic(payload);\n\n // Update the latest demand for this request\n this.overlayDemands.set(requestId, action);\n\n // Apply aggregated overlay visibility:\n // - If any request currently demands 'show', ensure overlay is visible\n // - Only hide when no outstanding 'show' demands remain\n if (action === 'show') {\n try { this.overlay.show(); } catch {}\n } else if (action === 'hide') {\n if (!this.wantsVisible()) {\n try { this.overlay.hide(); } catch {}\n }\n }\n\n const sub = this.subs.get(requestId);\n if (sub) {\n this.bumpStats(sub, phase);\n try { sub.onProgress?.(payload); } catch {}\n this.log('dispatch', { requestId, phase, sticky: sub.sticky });\n return true;\n }\n\n // Deliver to sticky-only subscriber if present (e.g., flow finished but status updates continue)\n const sticky = this.findSticky(requestId);\n if (sticky) {\n this.bumpStats(sticky, phase);\n try { sticky.onProgress?.(payload); } catch {}\n this.log('dispatch-sticky', { requestId, phase });\n return true;\n }\n this.log('dispatch-miss', { requestId, phase });\n return false;\n }\n\n getStats(requestId: string): {\n count: number;\n lastPhase: string | null;\n lastAt: number | null\n } | null {\n const sub = this.subs.get(requestId);\n return sub ? sub.stats : null;\n }\n\n /**\n * Returns true if any tracked request currently demands the overlay be visible.\n * Useful for higher layers (router) to avoid premature hides on completion/timeout.\n */\n wantsVisible(): boolean {\n for (const v of this.overlayDemands.values()) {\n if (v === 'show') return true;\n }\n return false;\n }\n\n private findSticky(requestId: string): ProgressSubscriber | null {\n const sub = this.subs.get(requestId);\n if (sub && sub.sticky) return sub;\n // sticky subscribers are keyed by the same requestId in this design\n return null;\n }\n\n private bumpStats(sub: ProgressSubscriber, phase: string) {\n sub.stats.count += 1;\n sub.stats.lastPhase = phase || null;\n sub.stats.lastAt = Date.now();\n }\n\n private log(msg: string, data?: Record<string, unknown>) {\n try { this.logger?.(msg, data); } catch {}\n }\n}\n\n// Default phase heuristic used by the client\n/**\n * defaultPhaseHeuristics\n *\n * Decides when to expand or contract the invisible wallet iframe overlay\n * based on incoming progress events (phases). Returning:\n * - 'show' → expands the iframe to a full-screen, invisible layer that captures\n * user activation (e.g., TouchID / WebAuthn prompts) and pointer events.\n * - 'hide' → immediately contracts the iframe back to 0×0 so it no longer blocks clicks.\n * - 'none' → no change.\n *\n * Important UX constraint: the overlay covers the entire viewport and is\n * intentionally invisible. While expanded, it will intercept clicks and can\n * block interactions with the app. Therefore, we must minimize the time it is\n * expanded and only show it during the brief windows where user activation is\n * required (e.g., when the TouchID prompt is about to appear or the modal is\n * mounting and needs focus/activation in the iframe context). As soon as\n * activation completes (e.g., authentication-complete), we hide it again.\n *\n * If new phases are introduced that require user activation, add them to\n * SHOW_PHASES; if phases become non-interactive post-activation, add them to\n * HIDE_PHASES. The goal is to keep the overlay up for the minimum possible time.\n */\nexport const defaultPhaseHeuristics: PhaseHeuristics = (payload: ProgressPayload) => {\n try {\n const phase = String((payload || {}).phase || '');\n if (!phase) return 'none';\n\n // Step 1: Check if this phase requires showing the overlay for user activation\n if (SHOW_PHASES.has(phase)) return 'show';\n\n // Step 2: Check if this phase indicates we should hide the overlay (post-activation)\n if (HIDE_PHASES.has(phase)) return 'hide';\n\n // Step 3: Handle legacy/custom completion markers\n const raw = phase.toLowerCase();\n if (raw === 'user-confirmation-complete') return 'hide';\n\n // Step 4: Extra hardening - hide overlay on explicit cancellation\n if (raw === 'cancelled') return 'hide';\n\n // Step 5: Default to no change for unknown phases\n return 'none';\n } catch { return 'none'; }\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"on-events-progress-bus.js","names":["DelegateActionPhase","defaultPhaseHeuristics: PhaseHeuristics"],"sources":["../../../../../src/core/WalletIframe/client/on-events-progress-bus.ts"],"sourcesContent":["/**\n * OnEventsProgressBus - Client-Side Communication Layer\n *\n * Manages progress event routing and overlay visibility *intents* for the wallet\n * iframe. It never manipulates the iframe directly; instead it calls the\n * injected OverlayController interface (show/hide), and WalletIframeRouter\n * owns the concrete OverlayController that knows how to display the iframe.\n *\n * Key Responsibilities:\n * - Progress Routing: Dispatches typed progress payloads to per-request subscribers\n * - Overlay Intents: Applies SHOW/HIDE based on phase heuristics, leaving actual\n * DOM/CSS work to WalletIframeRouter + OverlayController\n * - Concurrent Aggregation: Tracks overlay demand per requestId and only hides\n * when no request still requires SHOW (multi-request safe)\n * - Sticky Subscriptions: Supports long-running subscriptions that persist after completion\n * - Phase Heuristics: Pluggable logic to map phases → 'show' | 'hide' | 'none'\n * - Event Statistics: Tracks counts/timestamps for debugging\n */\n\nimport type { ProgressPayload as MessageProgressPayload } from '../shared/messages';\nimport {\n ActionPhase,\n DeviceLinkingPhase,\n SyncAccountPhase,\n RegistrationPhase,\n LoginPhase,\n EmailRecoveryPhase,\n DelegateActionPhase,\n} from '../../types/sdkSentEvents';\n\n// Phases that should temporarily SHOW the overlay (to capture activation)\n// IMPORTANT: STEP_2_USER_CONFIRMATION must remain in this list. Without it,\n// modal confirmation with behavior: 'requireClick' will never be visible in\n// iframe mode, because the wallet iframe is still 0×0 when the modal mounts.\nconst SHOW_PHASES = new Set<string>([\n // Gate overlay to moments of imminent activation only.\n // Show early during user confirmation so the modal inside the wallet iframe is visible\n // and can capture the required click when behavior === 'requireClick'.\n ActionPhase.STEP_2_USER_CONFIRMATION,\n DelegateActionPhase.STEP_2_USER_CONFIRMATION,\n ActionPhase.STEP_3_WEBAUTHN_AUTHENTICATION,\n DelegateActionPhase.STEP_3_WEBAUTHN_AUTHENTICATION,\n // Registration requires a WebAuthn create() ceremony at step 1\n RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION,\n // Email recovery: TouchID registration uses WebAuthn create()\n EmailRecoveryPhase.STEP_2_TOUCH_ID_REGISTRATION,\n // Device1: TouchID authorization (host needs overlay to capture activation)\n DeviceLinkingPhase.STEP_3_AUTHORIZATION,\n // Device2: Registration inside wallet host (collects passkey via ModalTxConfirmer)\n // Show overlay so the wallet iframe is visible and focused for WebAuthn\n DeviceLinkingPhase.STEP_6_REGISTRATION,\n SyncAccountPhase.STEP_2_WEBAUTHN_AUTHENTICATION,\n LoginPhase.STEP_2_WEBAUTHN_ASSERTION,\n]);\n\n// Phases that should HIDE the overlay asap (post-activation, non-interactive)\nconst HIDE_PHASES = new Set<string>([\n ActionPhase.STEP_4_AUTHENTICATION_COMPLETE,\n ActionPhase.STEP_5_TRANSACTION_SIGNING_PROGRESS,\n ActionPhase.STEP_6_TRANSACTION_SIGNING_COMPLETE,\n ActionPhase.STEP_7_BROADCASTING,\n ActionPhase.STEP_8_ACTION_COMPLETE,\n // Device linking: hide when the flow has finished or errored\n DeviceLinkingPhase.STEP_7_LINKING_COMPLETE,\n DeviceLinkingPhase.REGISTRATION_ERROR,\n DeviceLinkingPhase.LOGIN_ERROR,\n DeviceLinkingPhase.DEVICE_LINKING_ERROR,\n // Registration: hide once contract work starts or flow completes/errors\n RegistrationPhase.STEP_5_CONTRACT_REGISTRATION,\n RegistrationPhase.STEP_9_REGISTRATION_COMPLETE,\n RegistrationPhase.REGISTRATION_ERROR,\n // Login: hide after assertion leads to VRF unlock or completion/errors\n LoginPhase.STEP_3_VRF_UNLOCK,\n LoginPhase.STEP_4_LOGIN_COMPLETE,\n LoginPhase.LOGIN_ERROR,\n // Account sync: hide after authentication completes or on completion/errors\n SyncAccountPhase.STEP_4_AUTHENTICATOR_SAVED,\n SyncAccountPhase.STEP_5_SYNC_ACCOUNT_COMPLETE,\n SyncAccountPhase.ERROR,\n // Email recovery: hide after finalization/complete or on error\n EmailRecoveryPhase.STEP_5_FINALIZING_REGISTRATION,\n EmailRecoveryPhase.STEP_6_COMPLETE,\n EmailRecoveryPhase.ERROR,\n]);\n\nexport type ProgressPayload = MessageProgressPayload;\n\n// Minimal overlay control interface used by ProgressBus.\n// Implemented by WalletIframeRouter via an adapter object that calls\n// into the concrete OverlayToggler (fullscreen/anchored) as needed.\nexport interface OverlayToggler {\n show: () => void;\n hide: () => void;\n}\n\nexport type PhaseHeuristics = (payload: ProgressPayload) => 'show' | 'hide' | 'none';\n\nexport interface ProgressSubscriber {\n onProgress?: (payload: ProgressPayload) => void;\n sticky: boolean;\n stats: { count: number; lastPhase: string | null; lastAt: number | null };\n}\n\nexport class OnEventsProgressBus {\n private subs = new Map<string, ProgressSubscriber>();\n private logger?: (msg: string, data?: Record<string, unknown>) => void;\n private overlay: OverlayToggler;\n private heuristic: PhaseHeuristics;\n // Track the most recent overlay intent per requestId so that we can\n // aggregate visibility across concurrent requests. If any request's\n // latest intent is 'show', we keep the overlay visible.\n private overlayDemands = new Map<string, 'show' | 'hide' | 'none'>();\n\n constructor(overlay: OverlayToggler, heuristic: PhaseHeuristics, logger?: (msg: string, data?: Record<string, unknown>) => void) {\n this.overlay = overlay;\n this.heuristic = heuristic;\n this.logger = logger;\n }\n\n /**\n * Register a subscriber for a requestId.\n * Initializes demand tracking to 'none' (neutral) until phases arrive.\n */\n register({ requestId, onProgress, sticky = false }: {\n requestId: string,\n sticky: boolean,\n onProgress?: (p: ProgressPayload) => void,\n }): void {\n this.subs.set(requestId, {\n onProgress,\n sticky,\n stats: { count: 0, lastPhase: null, lastAt: null }\n });\n // Initialize demand tracking for this request as neutral\n this.overlayDemands.set(requestId, 'none');\n this.log('register', { requestId, sticky });\n }\n\n /**\n * Unregister a subscriber and clear its overlay demand.\n * If no remaining requests demand 'show', the overlay is hidden.\n */\n unregister(requestId: string): void {\n if (this.subs.delete(requestId)) this.log('unregister', { requestId });\n // Remove any overlay demand for this request\n this.overlayDemands.delete(requestId);\n // If no remaining requests demand 'show', we can safely hide\n if (!this.wantsVisible()) {\n try { this.overlay.hide(); } catch {}\n }\n }\n\n /**\n * Remove all subscribers and demands; overlay demand set is cleared.\n */\n clearAll(): void {\n this.subs.clear();\n this.overlayDemands.clear();\n this.log('clearAll');\n }\n\n isSticky(requestId: string): boolean {\n const sub = this.subs.get(requestId);\n return !!sub?.sticky;\n }\n\n /**\n * Dispatch a progress payload to a request's subscriber and update\n * the aggregate overlay demand based on the phase heuristic.\n */\n dispatch({ requestId, payload }: {\n requestId: string,\n payload: ProgressPayload\n }): boolean {\n\n const phase = String((payload || {}).phase || '');\n const action = this.heuristic(payload);\n\n // Update the latest demand for this request\n this.overlayDemands.set(requestId, action);\n\n // Apply aggregated overlay visibility:\n // - If any request currently demands 'show', ensure overlay is visible\n // - Only hide when no outstanding 'show' demands remain\n if (action === 'show') {\n try { this.overlay.show(); } catch {}\n } else if (action === 'hide') {\n if (!this.wantsVisible()) {\n try { this.overlay.hide(); } catch {}\n }\n }\n\n const sub = this.subs.get(requestId);\n if (sub) {\n this.bumpStats(sub, phase);\n try { sub.onProgress?.(payload); } catch {}\n this.log('dispatch', { requestId, phase, sticky: sub.sticky });\n return true;\n }\n\n // Deliver to sticky-only subscriber if present (e.g., flow finished but status updates continue)\n const sticky = this.findSticky(requestId);\n if (sticky) {\n this.bumpStats(sticky, phase);\n try { sticky.onProgress?.(payload); } catch {}\n this.log('dispatch-sticky', { requestId, phase });\n return true;\n }\n this.log('dispatch-miss', { requestId, phase });\n return false;\n }\n\n getStats(requestId: string): {\n count: number;\n lastPhase: string | null;\n lastAt: number | null\n } | null {\n const sub = this.subs.get(requestId);\n return sub ? sub.stats : null;\n }\n\n /**\n * Returns true if any tracked request currently demands the overlay be visible.\n * Useful for higher layers (router) to avoid premature hides on completion/timeout.\n */\n wantsVisible(): boolean {\n for (const v of this.overlayDemands.values()) {\n if (v === 'show') return true;\n }\n return false;\n }\n\n private findSticky(requestId: string): ProgressSubscriber | null {\n const sub = this.subs.get(requestId);\n if (sub && sub.sticky) return sub;\n // sticky subscribers are keyed by the same requestId in this design\n return null;\n }\n\n private bumpStats(sub: ProgressSubscriber, phase: string) {\n sub.stats.count += 1;\n sub.stats.lastPhase = phase || null;\n sub.stats.lastAt = Date.now();\n }\n\n private log(msg: string, data?: Record<string, unknown>) {\n try { this.logger?.(msg, data); } catch {}\n }\n}\n\n// Default phase heuristic used by the client\n/**\n * defaultPhaseHeuristics\n *\n * Decides when to expand or contract the invisible wallet iframe overlay\n * based on incoming progress events (phases). Returning:\n * - 'show' → expands the iframe to a full-screen, invisible layer that captures\n * user activation (e.g., TouchID / WebAuthn prompts) and pointer events.\n * - 'hide' → immediately contracts the iframe back to 0×0 so it no longer blocks clicks.\n * - 'none' → no change.\n *\n * Important UX constraint: the overlay covers the entire viewport and is\n * intentionally invisible. While expanded, it will intercept clicks and can\n * block interactions with the app. Therefore, we must minimize the time it is\n * expanded and only show it during the brief windows where user activation is\n * required (e.g., when the TouchID prompt is about to appear or the modal is\n * mounting and needs focus/activation in the iframe context). As soon as\n * activation completes (e.g., authentication-complete), we hide it again.\n *\n * If new phases are introduced that require user activation, add them to\n * SHOW_PHASES; if phases become non-interactive post-activation, add them to\n * HIDE_PHASES. The goal is to keep the overlay up for the minimum possible time.\n */\nexport const defaultPhaseHeuristics: PhaseHeuristics = (payload: ProgressPayload) => {\n try {\n const phase = String((payload || {}).phase || '');\n if (!phase) return 'none';\n\n // Step 1: Check if this phase requires showing the overlay for user activation\n if (SHOW_PHASES.has(phase)) return 'show';\n\n // Step 2: Check if this phase indicates we should hide the overlay (post-activation)\n if (HIDE_PHASES.has(phase)) return 'hide';\n\n // Step 3: Handle legacy/custom completion markers\n const raw = phase.toLowerCase();\n if (raw === 'user-confirmation-complete') return 'hide';\n\n // Step 4: Extra hardening - hide overlay on explicit cancellation\n if (raw === 'cancelled') return 'hide';\n\n // Step 5: Default to no change for unknown phases\n return 'none';\n } catch { return 'none'; }\n};\n"],"mappings":"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"}
@@ -6,8 +6,9 @@ let RegistrationPhase = /* @__PURE__ */ function(RegistrationPhase$1) {
6
6
  RegistrationPhase$1["STEP_4_ACCESS_KEY_ADDITION"] = "access-key-addition";
7
7
  RegistrationPhase$1["STEP_5_CONTRACT_REGISTRATION"] = "contract-registration";
8
8
  RegistrationPhase$1["STEP_6_ACCOUNT_VERIFICATION"] = "account-verification";
9
- RegistrationPhase$1["STEP_7_DATABASE_STORAGE"] = "database-storage";
10
- RegistrationPhase$1["STEP_8_REGISTRATION_COMPLETE"] = "registration-complete";
9
+ RegistrationPhase$1["STEP_7_THRESHOLD_KEY_ENROLLMENT"] = "threshold-key-enrollment";
10
+ RegistrationPhase$1["STEP_8_DATABASE_STORAGE"] = "database-storage";
11
+ RegistrationPhase$1["STEP_9_REGISTRATION_COMPLETE"] = "registration-complete";
11
12
  RegistrationPhase$1["REGISTRATION_ERROR"] = "error";
12
13
  return RegistrationPhase$1;
13
14
  }({});
@@ -1 +1 @@
1
- {"version":3,"file":"sdkSentEvents.js","names":[],"sources":["../../../../src/core/types/sdkSentEvents.ts"],"sourcesContent":["import type { TxExecutionStatus } from '@near-js/types';\nimport type { ConfirmationConfig, SignerMode, ThresholdBehavior } from './signer-worker';\nimport type {\n ActionResult,\n DelegateRelayResult,\n LoginAndCreateSessionResult,\n LoginResult,\n RegistrationResult,\n SignAndSendDelegateActionResult,\n SignDelegateActionResult,\n SignTransactionResult,\n} from './tatchi';\nimport type { SyncAccountResult, SignNEP413MessageResult } from '../TatchiPasskey';\n\n//////////////////////////\n// Progress Events Enums\n//////////////////////////\n\n// Registration Enums\nexport enum RegistrationPhase {\n STEP_1_WEBAUTHN_VERIFICATION = 'webauthn-verification',\n STEP_2_KEY_GENERATION = 'key-generation',\n STEP_3_CONTRACT_PRE_CHECK = 'contract-pre-check',\n STEP_4_ACCESS_KEY_ADDITION = 'access-key-addition',\n STEP_5_CONTRACT_REGISTRATION = 'contract-registration',\n STEP_6_ACCOUNT_VERIFICATION = 'account-verification',\n STEP_7_DATABASE_STORAGE = 'database-storage',\n STEP_8_REGISTRATION_COMPLETE = 'registration-complete',\n REGISTRATION_ERROR = 'error',\n}\nexport enum RegistrationStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Login Enums\nexport enum LoginPhase {\n STEP_1_PREPARATION = 'preparation',\n STEP_2_WEBAUTHN_ASSERTION = 'webauthn-assertion',\n STEP_3_VRF_UNLOCK = 'vrf-unlock',\n STEP_4_LOGIN_COMPLETE = 'login-complete',\n LOGIN_ERROR = 'login-error',\n}\nexport enum LoginStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Action Enums\nexport enum ActionPhase {\n STEP_1_PREPARATION = 'preparation', // Rust WASM worker phase: Preparation = 100\n STEP_2_USER_CONFIRMATION = 'user-confirmation', // Rust WASM worker phase: UserConfirmation = 101\n STEP_3_WEBAUTHN_AUTHENTICATION = 'webauthn-authentication', // Rust WASM worker phase: WebauthnAuthentication = 102\n STEP_4_AUTHENTICATION_COMPLETE = 'authentication-complete', // Rust WASM worker phase: AuthenticationComplete = 103\n STEP_5_TRANSACTION_SIGNING_PROGRESS = 'transaction-signing-progress', // Rust WASM worker phase: TransactionSigningProgress = 104\n STEP_6_TRANSACTION_SIGNING_COMPLETE = 'transaction-signing-complete', // Rust WASM worker phase: TransactionSigningComplete = 105\n WASM_ERROR = 'wasm-error', // Rust WASM worker phase: Error = 106\n STEP_7_BROADCASTING = 'broadcasting',\n STEP_8_ACTION_COMPLETE = 'action-complete',\n ACTION_ERROR = 'action-error',\n}\nexport enum ActionStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Delegate-specific phase alias for filtering\nexport { ActionPhase as DelegateActionPhase };\n\n// Account Sync Enums\nexport enum SyncAccountPhase {\n STEP_1_PREPARATION = 'preparation',\n STEP_2_WEBAUTHN_AUTHENTICATION = 'webauthn-authentication',\n STEP_3_SYNC_AUTHENTICATORS_ONCHAIN = 'sync-authenticators-onchain',\n STEP_4_AUTHENTICATOR_SAVED = 'authenticator-saved',\n STEP_5_SYNC_ACCOUNT_COMPLETE = 'sync-account-complete',\n ERROR = 'error',\n}\nexport enum SyncAccountStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Device Linking Enums\nexport enum DeviceLinkingPhase {\n STEP_1_QR_CODE_GENERATED = 'qr-code-generated', // Device2: QR code created and displayed\n STEP_2_SCANNING = 'scanning', // Device1: Scanning QR code\n STEP_3_AUTHORIZATION = 'authorization', // Device1: TouchID authorization\n STEP_4_POLLING = 'polling', // Device2: Polling contract for mapping\n STEP_5_ADDKEY_DETECTED = 'addkey-detected', // Device2: AddKey transaction detected\n STEP_6_REGISTRATION = 'registration', // Device2: Registration and credential storage\n STEP_7_LINKING_COMPLETE = 'linking-complete', // Final completion\n STEP_8_AUTO_LOGIN = 'auto-login', // Auto-login after registration\n IDLE = 'idle', // Idle state\n REGISTRATION_ERROR = 'registration-error', // Error during registration\n LOGIN_ERROR = 'login-error', // Error during login\n DEVICE_LINKING_ERROR = 'error', // General error state\n}\nexport enum DeviceLinkingStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Email Recovery Enums\nexport enum EmailRecoveryPhase {\n STEP_1_PREPARATION = 'email-recovery-preparation',\n STEP_2_TOUCH_ID_REGISTRATION = 'email-recovery-touch-id-registration',\n STEP_3_AWAIT_EMAIL = 'email-recovery-await-email',\n STEP_4_POLLING_ADD_KEY = 'email-recovery-polling-add-key',\n STEP_4_POLLING_VERIFICATION_RESULT = 'email-recovery-polling-add-key',\n STEP_5_FINALIZING_REGISTRATION = 'email-recovery-finalizing-registration',\n STEP_6_COMPLETE = 'email-recovery-complete',\n ERROR = 'email-recovery-error',\n RESUMED_FROM_PENDING = 'email-recovery-resumed-from-pending',\n}\nexport enum EmailRecoveryStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Base event callback type\nexport type EventCallback<T> = (event: T) => void;\n\n// Users can still supply a single implementation: (success: boolean, result?: T) => ...\nexport interface AfterCall<T> {\n (success: true, result: T): void | Promise<void>;\n (success: false): void | Promise<void>;\n}\n\n// Base SSE Event Types (unified for Registration and Actions)\nexport interface BaseSSEEvent {\n step: number;\n phase: RegistrationPhase | LoginPhase | ActionPhase | DeviceLinkingPhase | SyncAccountPhase | EmailRecoveryPhase;\n status: RegistrationStatus | LoginStatus | ActionStatus | DeviceLinkingStatus | SyncAccountStatus | EmailRecoveryStatus;\n message: string;\n}\n\n// Registration-specific events\nexport interface BaseRegistrationSSEEvent extends BaseSSEEvent {\n phase: RegistrationPhase;\n status: RegistrationStatus;\n}\n\n// Action-specific events\nexport interface BaseActionSSEEvent extends BaseSSEEvent {\n phase: ActionPhase;\n status: ActionStatus;\n}\n\n// Login-specific events\nexport interface BaseLoginSSEEvent extends BaseSSEEvent {\n phase: LoginPhase;\n status: LoginStatus;\n}\n\nexport interface BaseDeviceLinkingSSEEvent extends BaseSSEEvent {\n phase: DeviceLinkingPhase;\n status: DeviceLinkingStatus;\n}\n\n// Action-specific events\nexport interface BaseSyncAccountEvent extends BaseSSEEvent {\n phase: SyncAccountPhase;\n status: SyncAccountStatus;\n}\n\nexport interface BaseEmailRecoveryEvent extends BaseSSEEvent {\n phase: EmailRecoveryPhase;\n status: EmailRecoveryStatus;\n}\n\n// Progress Events\nexport interface onProgressEvents extends BaseActionSSEEvent {\n step: number;\n status: ActionStatus;\n message: string;\n // Generic metadata bag for progress payloads\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\n// Optional, phase-specific data shapes used where we can commit to fields\n// Intentionally keep progress payloads generic to avoid duplicating\n// worker-side data shapes. Concrete fields can be added in future PRs\n// by normalizing worker payloads in one place.\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Registration Event Types\n/////////////////////////////////////////////\n\nexport interface RegistrationEventStep1 extends BaseRegistrationSSEEvent {\n step: 1;\n phase: RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION;\n}\n\nexport interface RegistrationEventStep2 extends BaseRegistrationSSEEvent {\n step: 2;\n phase: RegistrationPhase.STEP_2_KEY_GENERATION;\n status: RegistrationStatus.SUCCESS;\n verified: boolean;\n nearAccountId: string;\n nearPublicKey: string | null | undefined;\n vrfPublicKey: string | null | undefined;\n}\n\n// Optional progress emission during step 2 (e.g., concurrent contract pre-checks)\nexport interface RegistrationEventStep2Progress extends BaseRegistrationSSEEvent {\n step: 2;\n phase: RegistrationPhase.STEP_2_KEY_GENERATION;\n status: RegistrationStatus.PROGRESS;\n}\n\nexport interface RegistrationEventStep3 extends BaseRegistrationSSEEvent {\n step: 3;\n phase: RegistrationPhase.STEP_3_CONTRACT_PRE_CHECK;\n error?: string;\n}\n\nexport interface RegistrationEventStep4 extends BaseRegistrationSSEEvent {\n step: 4;\n phase: RegistrationPhase.STEP_4_ACCESS_KEY_ADDITION;\n error?: string;\n}\n\nexport interface RegistrationEventStep5 extends BaseRegistrationSSEEvent {\n step: 5;\n phase: RegistrationPhase.STEP_5_CONTRACT_REGISTRATION;\n error?: string;\n}\n\nexport interface RegistrationEventStep6 extends BaseRegistrationSSEEvent {\n step: 6;\n phase: RegistrationPhase.STEP_6_ACCOUNT_VERIFICATION;\n error?: string;\n}\n\nexport interface RegistrationEventStep7 extends BaseRegistrationSSEEvent {\n step: 7;\n phase: RegistrationPhase.STEP_7_DATABASE_STORAGE;\n error?: string;\n}\n\nexport interface RegistrationEventStep8 extends BaseRegistrationSSEEvent {\n step: 8;\n phase: RegistrationPhase.STEP_8_REGISTRATION_COMPLETE;\n status: RegistrationStatus.SUCCESS;\n}\n\nexport interface RegistrationEventStep0 extends BaseRegistrationSSEEvent {\n step: 0;\n phase: RegistrationPhase.REGISTRATION_ERROR;\n status: RegistrationStatus.ERROR;\n error: string;\n}\n\nexport type RegistrationSSEEvent =\n | RegistrationEventStep1\n | RegistrationEventStep2Progress\n | RegistrationEventStep2\n | RegistrationEventStep3\n | RegistrationEventStep4\n | RegistrationEventStep5\n | RegistrationEventStep6\n | RegistrationEventStep7\n | RegistrationEventStep8\n | RegistrationEventStep0;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Login Event Types\n/////////////////////////////////////////////\n\nexport interface LoginSSEventStep1 extends BaseLoginSSEEvent {\n step: 1;\n phase: LoginPhase.STEP_1_PREPARATION;\n}\n\nexport interface LoginSSEventStep2 extends BaseLoginSSEEvent {\n step: 2;\n phase: LoginPhase.STEP_2_WEBAUTHN_ASSERTION;\n}\n\nexport interface LoginSSEventStep3 extends BaseLoginSSEEvent {\n step: 3;\n phase: LoginPhase.STEP_3_VRF_UNLOCK;\n}\n\nexport interface LoginSSEventStep4 extends BaseLoginSSEEvent {\n step: 4;\n phase: LoginPhase.STEP_4_LOGIN_COMPLETE;\n status: LoginStatus.SUCCESS;\n nearAccountId: string;\n clientNearPublicKey: string;\n}\n\nexport interface LoginSSEventStep0 extends BaseLoginSSEEvent {\n step: 0;\n phase: LoginPhase.LOGIN_ERROR;\n status: LoginStatus.ERROR;\n error: string;\n}\n\nexport type LoginSSEvent =\n | LoginSSEventStep1\n | LoginSSEventStep2\n | LoginSSEventStep3\n | LoginSSEventStep4\n | LoginSSEventStep0;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Action Event Types\n/////////////////////////////////////////////\n\nexport interface ActionEventStep1 extends BaseActionSSEEvent {\n step: 1;\n phase: ActionPhase.STEP_1_PREPARATION;\n}\n\nexport interface ActionEventStep2 extends BaseActionSSEEvent {\n step: 2;\n phase: ActionPhase.STEP_2_USER_CONFIRMATION;\n}\n\nexport interface ActionEventStep3 extends BaseActionSSEEvent {\n step: 3;\n phase: ActionPhase.STEP_3_WEBAUTHN_AUTHENTICATION;\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\nexport interface ActionEventStep4 extends BaseActionSSEEvent {\n step: 4;\n phase: ActionPhase.STEP_4_AUTHENTICATION_COMPLETE;\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\nexport interface ActionEventStep5 extends BaseActionSSEEvent {\n step: 5;\n phase: ActionPhase.STEP_5_TRANSACTION_SIGNING_PROGRESS;\n data?: Record<string, unknown>;\n}\n\nexport interface ActionEventStep6 extends BaseActionSSEEvent {\n step: 6;\n phase: ActionPhase.STEP_6_TRANSACTION_SIGNING_COMPLETE;\n status: ActionStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface ActionEventStep7 extends BaseActionSSEEvent {\n step: 7;\n phase: ActionPhase.STEP_7_BROADCASTING;\n}\n\nexport interface ActionEventStep8 extends BaseActionSSEEvent {\n step: 8;\n phase: ActionPhase.STEP_8_ACTION_COMPLETE;\n status: ActionStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface ActionEventError extends BaseActionSSEEvent {\n step: 0;\n phase: ActionPhase.ACTION_ERROR;\n status: ActionStatus.ERROR;\n error: string;\n}\n\nexport interface ActionEventWasmError extends BaseActionSSEEvent {\n step: 0;\n phase: ActionPhase.WASM_ERROR;\n status: ActionStatus.ERROR;\n error: string;\n}\n\nexport type ActionSSEEvent =\n | ActionEventStep1\n | ActionEventStep2\n | ActionEventStep3\n | ActionEventStep4\n | ActionEventStep5\n | ActionEventStep6\n | ActionEventStep7\n | ActionEventStep8\n | ActionEventError\n | ActionEventWasmError;\n\nexport type DelegateActionSSEEvent = ActionSSEEvent;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Device Linking Event Types\n/////////////////////////////////////////////\n\nexport interface DeviceLinkingEventStep1 extends BaseDeviceLinkingSSEEvent {\n step: 1;\n phase: DeviceLinkingPhase.STEP_1_QR_CODE_GENERATED;\n}\n\nexport interface DeviceLinkingEventStep2 extends BaseDeviceLinkingSSEEvent {\n step: 2;\n phase: DeviceLinkingPhase.STEP_2_SCANNING;\n}\n\nexport interface DeviceLinkingEventStep3 extends BaseDeviceLinkingSSEEvent {\n step: 3;\n phase: DeviceLinkingPhase.STEP_3_AUTHORIZATION;\n}\n\nexport interface DeviceLinkingEventStep4 extends BaseDeviceLinkingSSEEvent {\n step: 4;\n phase: DeviceLinkingPhase.STEP_4_POLLING;\n}\n\nexport interface DeviceLinkingEventStep5 extends BaseDeviceLinkingSSEEvent {\n step: 5;\n phase: DeviceLinkingPhase.STEP_5_ADDKEY_DETECTED;\n}\n\nexport interface DeviceLinkingEventStep6 extends BaseDeviceLinkingSSEEvent {\n step: 6;\n phase: DeviceLinkingPhase.STEP_6_REGISTRATION;\n}\n\nexport interface DeviceLinkingEventStep7 extends BaseDeviceLinkingSSEEvent {\n step: 7;\n phase: DeviceLinkingPhase.STEP_7_LINKING_COMPLETE;\n}\n\nexport interface DeviceLinkingEventStep8 extends BaseDeviceLinkingSSEEvent {\n step: 8;\n phase: DeviceLinkingPhase.STEP_8_AUTO_LOGIN;\n}\n\nexport interface DeviceLinkingErrorEvent extends BaseDeviceLinkingSSEEvent {\n step: 0;\n phase: DeviceLinkingPhase.DEVICE_LINKING_ERROR\n | DeviceLinkingPhase.LOGIN_ERROR\n | DeviceLinkingPhase.REGISTRATION_ERROR;\n status: DeviceLinkingStatus.ERROR;\n error: string;\n}\n\nexport type DeviceLinkingSSEEvent =\n | DeviceLinkingEventStep1\n | DeviceLinkingEventStep2\n | DeviceLinkingEventStep3\n | DeviceLinkingEventStep4\n | DeviceLinkingEventStep5\n | DeviceLinkingEventStep6\n | DeviceLinkingEventStep7\n | DeviceLinkingEventStep8\n | DeviceLinkingErrorEvent;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Account Sync Event Types\n/////////////////////////////////////////////\n\nexport interface SyncAccountEventStep1 extends BaseSyncAccountEvent {\n step: 1;\n phase: SyncAccountPhase.STEP_1_PREPARATION;\n}\n\nexport interface SyncAccountEventStep2 extends BaseSyncAccountEvent {\n step: 2;\n phase: SyncAccountPhase.STEP_2_WEBAUTHN_AUTHENTICATION;\n}\n\nexport interface SyncAccountEventStep3 extends BaseSyncAccountEvent {\n step: 3;\n phase: SyncAccountPhase.STEP_3_SYNC_AUTHENTICATORS_ONCHAIN;\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\nexport interface SyncAccountEventStep4 extends BaseSyncAccountEvent {\n step: 4;\n phase: SyncAccountPhase.STEP_4_AUTHENTICATOR_SAVED;\n status: SyncAccountStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface SyncAccountEventStep5 extends BaseSyncAccountEvent {\n step: 5;\n phase: SyncAccountPhase.STEP_5_SYNC_ACCOUNT_COMPLETE;\n status: SyncAccountStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface SyncAccountError extends BaseSyncAccountEvent {\n step: 0;\n phase: SyncAccountPhase.ERROR;\n status: SyncAccountStatus.ERROR;\n error: string;\n}\n\nexport type SyncAccountSSEEvent =\n | SyncAccountEventStep1\n | SyncAccountEventStep2\n | SyncAccountEventStep3\n | SyncAccountEventStep4\n | SyncAccountEventStep5\n | SyncAccountError;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Email Recovery Event Types\n/////////////////////////////////////////////\n\nexport interface EmailRecoveryEventStep1 extends BaseEmailRecoveryEvent {\n step: 1;\n phase: EmailRecoveryPhase.STEP_1_PREPARATION;\n}\n\nexport interface EmailRecoveryEventStep2 extends BaseEmailRecoveryEvent {\n step: 2;\n phase: EmailRecoveryPhase.STEP_2_TOUCH_ID_REGISTRATION;\n}\n\nexport interface EmailRecoveryEventStep3 extends BaseEmailRecoveryEvent {\n step: 3;\n phase: EmailRecoveryPhase.STEP_3_AWAIT_EMAIL;\n}\n\nexport interface EmailRecoveryEventStep4 extends BaseEmailRecoveryEvent {\n step: 4;\n phase: EmailRecoveryPhase.STEP_4_POLLING_ADD_KEY | EmailRecoveryPhase.STEP_4_POLLING_VERIFICATION_RESULT;\n data?: {\n accountId?: string;\n requestId?: string;\n nearPublicKey?: string;\n elapsedMs?: number;\n pollCount?: number;\n [key: string]: unknown;\n };\n logs?: string[];\n}\n\nexport interface EmailRecoveryEventStep5 extends BaseEmailRecoveryEvent {\n step: 5;\n phase: EmailRecoveryPhase.STEP_5_FINALIZING_REGISTRATION;\n data?: Record<string, unknown>;\n}\n\nexport interface EmailRecoveryEventStep6 extends BaseEmailRecoveryEvent {\n step: 6;\n phase: EmailRecoveryPhase.STEP_6_COMPLETE;\n status: EmailRecoveryStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface EmailRecoveryEventResumedFromPending extends BaseEmailRecoveryEvent {\n step: 0;\n phase: EmailRecoveryPhase.RESUMED_FROM_PENDING;\n status: EmailRecoveryStatus.PROGRESS;\n data?: Record<string, unknown>;\n}\n\nexport interface EmailRecoveryErrorEvent extends BaseEmailRecoveryEvent {\n step: 0;\n phase: EmailRecoveryPhase.ERROR;\n status: EmailRecoveryStatus.ERROR;\n error: string;\n}\n\nexport type EmailRecoverySSEEvent =\n | EmailRecoveryEventStep1\n | EmailRecoveryEventStep2\n | EmailRecoveryEventStep3\n | EmailRecoveryEventStep4\n | EmailRecoveryEventStep5\n | EmailRecoveryEventStep6\n | EmailRecoveryEventResumedFromPending\n | EmailRecoveryErrorEvent;\n\n//////////////////////////////////\n/// Hooks Options\n//////////////////////////////////\n\n// Function Options\nexport interface RegistrationHooksOptions {\n onEvent?: EventCallback<RegistrationSSEEvent>;\n onError?: (error: Error) => void;\n afterCall?: AfterCall<RegistrationResult>;\n /**\n * Optional: registration signing policy.\n * - `{ mode: 'local-signer' }`: derive and store an encrypted local NEAR secret key (v3 vault).\n * - `{ mode: 'threshold-signer' }`: derive the local key AND enroll a threshold Ed25519 (2-of-2) access key\n * during registration (relay adds the threshold public key on-chain and returns relayerKeyId).\n *\n * Defaults to `{ mode: 'local-signer' }` for backwards compatibility in public APIs.\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration. When provided, overrides user preferences\n // for this request only (not persisted).\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface LoginHooksOptions {\n onEvent?: EventCallback<LoginSSEvent>;\n onError?: (error: Error) => void;\n afterCall?: AfterCall<LoginAndCreateSessionResult>;\n /**\n * Optional: passkey deviceNumber hint.\n *\n * When multiple passkeys exist for the same `nearAccountId`, providing this hint lets\n * the login flow prioritize the matching `credentialId` when presenting the TouchID\n * (WebAuthn) prompt.\n */\n deviceNumber?: number;\n // Optional: request a server session (JWT in body or HttpOnly cookie)\n session?: {\n // 'jwt' returns the token in the JSON body; 'cookie' sets HttpOnly cookie\n kind: 'jwt' | 'cookie';\n // Optional: override relay URL; defaults to TatchiConfigs.relayer.url\n relayUrl?: string;\n // Optional: override route path; defaults to '/verify-authentication-response'\n route?: string;\n };\n /**\n * Optional: override the warm signing session policy minted during login.\n * Defaults come from `TatchiConfigs.signingSessionDefaults`.\n */\n signingSession?: {\n ttlMs?: number;\n remainingUses?: number;\n };\n}\n\nexport interface ActionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n afterCall?: AfterCall<ActionResult>;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration. When provided, overrides user preferences\n // for this request only (not persisted).\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport type ExecutionWaitOption =\n | { mode: 'sequential'; waitUntil?: TxExecutionStatus }\n | { mode: 'parallelStaggered'; staggerMs: number };\n\nexport interface SignAndSendTransactionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Execution control for multi-transaction broadcasts:\n * - { mode: 'sequential', waitUntil?: TxExecutionStatus }\n * - { mode: 'parallelStaggered', staggerMs: number }\n */\n executionWait?: ExecutionWaitOption;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n\n afterCall?: AfterCall<ActionResult[]>;\n // Per-call confirmation configuration. When provided, overrides user preferences\n // for this request only (not persisted).\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface SignTransactionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n\n afterCall?: AfterCall<SignTransactionResult[]>;\n waitUntil?: TxExecutionStatus;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration (non-persistent)\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface SendTransactionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n\n afterCall?: AfterCall<ActionResult>;\n waitUntil?: TxExecutionStatus;\n}\n\nexport interface DelegateActionHooksOptions {\n onEvent?: EventCallback<DelegateActionSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n afterCall?: AfterCall<SignDelegateActionResult>;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface DelegateRelayHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n afterCall?: AfterCall<DelegateRelayResult>;\n}\n\nexport type SignAndSendDelegateActionHooksOptions =\n Omit<DelegateActionHooksOptions, 'afterCall'> & {\n afterCall?: AfterCall<SignAndSendDelegateActionResult>;\n };\n\nexport interface SyncAccountHooksOptions {\n onEvent?: EventCallback<SyncAccountSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n\n afterCall?: AfterCall<SyncAccountResult>;\n}\n\nexport interface SignNEP413HooksOptions {\n onEvent?: EventCallback<RegistrationSSEEvent | LoginSSEvent | ActionSSEEvent | DeviceLinkingSSEEvent | SyncAccountSSEEvent | EmailRecoverySSEEvent>;\n onError?: (error: Error) => void;\n\n afterCall?: AfterCall<SignNEP413MessageResult>;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration (non-persistent)\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n"],"mappings":";AAmBA,IAAY,kEAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAEF,IAAY,oEAAL;AACL;AACA;AACA;;;AAIF,IAAY,oDAAL;AACL;AACA;AACA;AACA;AACA;;;AAEF,IAAY,sDAAL;AACL;AACA;AACA;;;AAIF,IAAY,sDAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAEF,IAAY,wDAAL;AACL;AACA;AACA;;;AAOF,IAAY,gEAAL;AACL;AACA;AACA;AACA;AACA;AACA;;;AAEF,IAAY,kEAAL;AACL;AACA;AACA;;;AAIF,IAAY,oEAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAEF,IAAY,sEAAL;AACL;AACA;AACA;;;AAIF,IAAY,oEAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAEF,IAAY,sEAAL;AACL;AACA;AACA"}
1
+ {"version":3,"file":"sdkSentEvents.js","names":[],"sources":["../../../../src/core/types/sdkSentEvents.ts"],"sourcesContent":["import type { TxExecutionStatus } from '@near-js/types';\nimport type { ConfirmationConfig, SignerMode, ThresholdBehavior } from './signer-worker';\nimport type {\n ActionResult,\n DelegateRelayResult,\n LoginAndCreateSessionResult,\n LoginResult,\n RegistrationResult,\n SignAndSendDelegateActionResult,\n SignDelegateActionResult,\n SignTransactionResult,\n} from './tatchi';\nimport type { SyncAccountResult, SignNEP413MessageResult } from '../TatchiPasskey';\n\n//////////////////////////\n// Progress Events Enums\n//////////////////////////\n\n// Registration Enums\nexport enum RegistrationPhase {\n STEP_1_WEBAUTHN_VERIFICATION = 'webauthn-verification',\n STEP_2_KEY_GENERATION = 'key-generation',\n STEP_3_CONTRACT_PRE_CHECK = 'contract-pre-check',\n STEP_4_ACCESS_KEY_ADDITION = 'access-key-addition',\n STEP_5_CONTRACT_REGISTRATION = 'contract-registration',\n STEP_6_ACCOUNT_VERIFICATION = 'account-verification',\n STEP_7_THRESHOLD_KEY_ENROLLMENT = 'threshold-key-enrollment',\n STEP_8_DATABASE_STORAGE = 'database-storage',\n STEP_9_REGISTRATION_COMPLETE = 'registration-complete',\n REGISTRATION_ERROR = 'error',\n}\nexport enum RegistrationStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Login Enums\nexport enum LoginPhase {\n STEP_1_PREPARATION = 'preparation',\n STEP_2_WEBAUTHN_ASSERTION = 'webauthn-assertion',\n STEP_3_VRF_UNLOCK = 'vrf-unlock',\n STEP_4_LOGIN_COMPLETE = 'login-complete',\n LOGIN_ERROR = 'login-error',\n}\nexport enum LoginStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Action Enums\nexport enum ActionPhase {\n STEP_1_PREPARATION = 'preparation', // Rust WASM worker phase: Preparation = 100\n STEP_2_USER_CONFIRMATION = 'user-confirmation', // Rust WASM worker phase: UserConfirmation = 101\n STEP_3_WEBAUTHN_AUTHENTICATION = 'webauthn-authentication', // Rust WASM worker phase: WebauthnAuthentication = 102\n STEP_4_AUTHENTICATION_COMPLETE = 'authentication-complete', // Rust WASM worker phase: AuthenticationComplete = 103\n STEP_5_TRANSACTION_SIGNING_PROGRESS = 'transaction-signing-progress', // Rust WASM worker phase: TransactionSigningProgress = 104\n STEP_6_TRANSACTION_SIGNING_COMPLETE = 'transaction-signing-complete', // Rust WASM worker phase: TransactionSigningComplete = 105\n WASM_ERROR = 'wasm-error', // Rust WASM worker phase: Error = 106\n STEP_7_BROADCASTING = 'broadcasting',\n STEP_8_ACTION_COMPLETE = 'action-complete',\n ACTION_ERROR = 'action-error',\n}\nexport enum ActionStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Delegate-specific phase alias for filtering\nexport { ActionPhase as DelegateActionPhase };\n\n// Account Sync Enums\nexport enum SyncAccountPhase {\n STEP_1_PREPARATION = 'preparation',\n STEP_2_WEBAUTHN_AUTHENTICATION = 'webauthn-authentication',\n STEP_3_SYNC_AUTHENTICATORS_ONCHAIN = 'sync-authenticators-onchain',\n STEP_4_AUTHENTICATOR_SAVED = 'authenticator-saved',\n STEP_5_SYNC_ACCOUNT_COMPLETE = 'sync-account-complete',\n ERROR = 'error',\n}\nexport enum SyncAccountStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Device Linking Enums\nexport enum DeviceLinkingPhase {\n STEP_1_QR_CODE_GENERATED = 'qr-code-generated', // Device2: QR code created and displayed\n STEP_2_SCANNING = 'scanning', // Device1: Scanning QR code\n STEP_3_AUTHORIZATION = 'authorization', // Device1: TouchID authorization\n STEP_4_POLLING = 'polling', // Device2: Polling contract for mapping\n STEP_5_ADDKEY_DETECTED = 'addkey-detected', // Device2: AddKey transaction detected\n STEP_6_REGISTRATION = 'registration', // Device2: Registration and credential storage\n STEP_7_LINKING_COMPLETE = 'linking-complete', // Final completion\n STEP_8_AUTO_LOGIN = 'auto-login', // Auto-login after registration\n IDLE = 'idle', // Idle state\n REGISTRATION_ERROR = 'registration-error', // Error during registration\n LOGIN_ERROR = 'login-error', // Error during login\n DEVICE_LINKING_ERROR = 'error', // General error state\n}\nexport enum DeviceLinkingStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Email Recovery Enums\nexport enum EmailRecoveryPhase {\n STEP_1_PREPARATION = 'email-recovery-preparation',\n STEP_2_TOUCH_ID_REGISTRATION = 'email-recovery-touch-id-registration',\n STEP_3_AWAIT_EMAIL = 'email-recovery-await-email',\n STEP_4_POLLING_ADD_KEY = 'email-recovery-polling-add-key',\n STEP_4_POLLING_VERIFICATION_RESULT = 'email-recovery-polling-add-key',\n STEP_5_FINALIZING_REGISTRATION = 'email-recovery-finalizing-registration',\n STEP_6_COMPLETE = 'email-recovery-complete',\n ERROR = 'email-recovery-error',\n RESUMED_FROM_PENDING = 'email-recovery-resumed-from-pending',\n}\nexport enum EmailRecoveryStatus {\n PROGRESS = 'progress',\n SUCCESS = 'success',\n ERROR = 'error',\n}\n\n// Base event callback type\nexport type EventCallback<T> = (event: T) => void;\n\n// Users can still supply a single implementation: (success: boolean, result?: T) => ...\nexport interface AfterCall<T> {\n (success: true, result: T): void | Promise<void>;\n (success: false): void | Promise<void>;\n}\n\n// Base SSE Event Types (unified for Registration and Actions)\nexport interface BaseSSEEvent {\n step: number;\n phase: RegistrationPhase | LoginPhase | ActionPhase | DeviceLinkingPhase | SyncAccountPhase | EmailRecoveryPhase;\n status: RegistrationStatus | LoginStatus | ActionStatus | DeviceLinkingStatus | SyncAccountStatus | EmailRecoveryStatus;\n message: string;\n}\n\n// Registration-specific events\nexport interface BaseRegistrationSSEEvent extends BaseSSEEvent {\n phase: RegistrationPhase;\n status: RegistrationStatus;\n}\n\n// Action-specific events\nexport interface BaseActionSSEEvent extends BaseSSEEvent {\n phase: ActionPhase;\n status: ActionStatus;\n}\n\n// Login-specific events\nexport interface BaseLoginSSEEvent extends BaseSSEEvent {\n phase: LoginPhase;\n status: LoginStatus;\n}\n\nexport interface BaseDeviceLinkingSSEEvent extends BaseSSEEvent {\n phase: DeviceLinkingPhase;\n status: DeviceLinkingStatus;\n}\n\n// Action-specific events\nexport interface BaseSyncAccountEvent extends BaseSSEEvent {\n phase: SyncAccountPhase;\n status: SyncAccountStatus;\n}\n\nexport interface BaseEmailRecoveryEvent extends BaseSSEEvent {\n phase: EmailRecoveryPhase;\n status: EmailRecoveryStatus;\n}\n\n// Progress Events\nexport interface onProgressEvents extends BaseActionSSEEvent {\n step: number;\n status: ActionStatus;\n message: string;\n // Generic metadata bag for progress payloads\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\n// Optional, phase-specific data shapes used where we can commit to fields\n// Intentionally keep progress payloads generic to avoid duplicating\n// worker-side data shapes. Concrete fields can be added in future PRs\n// by normalizing worker payloads in one place.\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Registration Event Types\n/////////////////////////////////////////////\n\nexport interface RegistrationEventStep1 extends BaseRegistrationSSEEvent {\n step: 1;\n phase: RegistrationPhase.STEP_1_WEBAUTHN_VERIFICATION;\n}\n\nexport interface RegistrationEventStep2 extends BaseRegistrationSSEEvent {\n step: 2;\n phase: RegistrationPhase.STEP_2_KEY_GENERATION;\n status: RegistrationStatus.SUCCESS;\n verified: boolean;\n nearAccountId: string;\n nearPublicKey: string | null | undefined;\n vrfPublicKey: string | null | undefined;\n}\n\n// Optional progress emission during step 2 (e.g., concurrent contract pre-checks)\nexport interface RegistrationEventStep2Progress extends BaseRegistrationSSEEvent {\n step: 2;\n phase: RegistrationPhase.STEP_2_KEY_GENERATION;\n status: RegistrationStatus.PROGRESS;\n}\n\nexport interface RegistrationEventStep3 extends BaseRegistrationSSEEvent {\n step: 3;\n phase: RegistrationPhase.STEP_3_CONTRACT_PRE_CHECK;\n error?: string;\n}\n\nexport interface RegistrationEventStep4 extends BaseRegistrationSSEEvent {\n step: 4;\n phase: RegistrationPhase.STEP_4_ACCESS_KEY_ADDITION;\n error?: string;\n}\n\nexport interface RegistrationEventStep5 extends BaseRegistrationSSEEvent {\n step: 5;\n phase: RegistrationPhase.STEP_5_CONTRACT_REGISTRATION;\n error?: string;\n}\n\nexport interface RegistrationEventStep6 extends BaseRegistrationSSEEvent {\n step: 6;\n phase: RegistrationPhase.STEP_6_ACCOUNT_VERIFICATION;\n error?: string;\n}\n\nexport interface RegistrationEventStep7ThresholdKeyEnrollment extends BaseRegistrationSSEEvent {\n step: 7;\n phase: RegistrationPhase.STEP_7_THRESHOLD_KEY_ENROLLMENT;\n status: RegistrationStatus.SUCCESS;\n thresholdKeyReady: boolean;\n thresholdPublicKey?: string;\n relayerKeyId?: string;\n deviceNumber?: number;\n warning?: string;\n}\n\nexport interface RegistrationEventStep8 extends BaseRegistrationSSEEvent {\n step: 8;\n phase: RegistrationPhase.STEP_8_DATABASE_STORAGE;\n error?: string;\n}\n\nexport interface RegistrationEventStep9 extends BaseRegistrationSSEEvent {\n step: 9;\n phase: RegistrationPhase.STEP_9_REGISTRATION_COMPLETE;\n status: RegistrationStatus.SUCCESS;\n}\n\nexport interface RegistrationEventStep0 extends BaseRegistrationSSEEvent {\n step: 0;\n phase: RegistrationPhase.REGISTRATION_ERROR;\n status: RegistrationStatus.ERROR;\n error: string;\n}\n\nexport type RegistrationSSEEvent =\n | RegistrationEventStep1\n | RegistrationEventStep2Progress\n | RegistrationEventStep2\n | RegistrationEventStep3\n | RegistrationEventStep4\n | RegistrationEventStep5\n | RegistrationEventStep6\n | RegistrationEventStep7ThresholdKeyEnrollment\n | RegistrationEventStep8\n | RegistrationEventStep9\n | RegistrationEventStep0;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Login Event Types\n/////////////////////////////////////////////\n\nexport interface LoginSSEventStep1 extends BaseLoginSSEEvent {\n step: 1;\n phase: LoginPhase.STEP_1_PREPARATION;\n}\n\nexport interface LoginSSEventStep2 extends BaseLoginSSEEvent {\n step: 2;\n phase: LoginPhase.STEP_2_WEBAUTHN_ASSERTION;\n}\n\nexport interface LoginSSEventStep3 extends BaseLoginSSEEvent {\n step: 3;\n phase: LoginPhase.STEP_3_VRF_UNLOCK;\n}\n\nexport interface LoginSSEventStep4 extends BaseLoginSSEEvent {\n step: 4;\n phase: LoginPhase.STEP_4_LOGIN_COMPLETE;\n status: LoginStatus.SUCCESS;\n nearAccountId: string;\n clientNearPublicKey: string;\n}\n\nexport interface LoginSSEventStep0 extends BaseLoginSSEEvent {\n step: 0;\n phase: LoginPhase.LOGIN_ERROR;\n status: LoginStatus.ERROR;\n error: string;\n}\n\nexport type LoginSSEvent =\n | LoginSSEventStep1\n | LoginSSEventStep2\n | LoginSSEventStep3\n | LoginSSEventStep4\n | LoginSSEventStep0;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Action Event Types\n/////////////////////////////////////////////\n\nexport interface ActionEventStep1 extends BaseActionSSEEvent {\n step: 1;\n phase: ActionPhase.STEP_1_PREPARATION;\n}\n\nexport interface ActionEventStep2 extends BaseActionSSEEvent {\n step: 2;\n phase: ActionPhase.STEP_2_USER_CONFIRMATION;\n}\n\nexport interface ActionEventStep3 extends BaseActionSSEEvent {\n step: 3;\n phase: ActionPhase.STEP_3_WEBAUTHN_AUTHENTICATION;\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\nexport interface ActionEventStep4 extends BaseActionSSEEvent {\n step: 4;\n phase: ActionPhase.STEP_4_AUTHENTICATION_COMPLETE;\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\nexport interface ActionEventStep5 extends BaseActionSSEEvent {\n step: 5;\n phase: ActionPhase.STEP_5_TRANSACTION_SIGNING_PROGRESS;\n data?: Record<string, unknown>;\n}\n\nexport interface ActionEventStep6 extends BaseActionSSEEvent {\n step: 6;\n phase: ActionPhase.STEP_6_TRANSACTION_SIGNING_COMPLETE;\n status: ActionStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface ActionEventStep7 extends BaseActionSSEEvent {\n step: 7;\n phase: ActionPhase.STEP_7_BROADCASTING;\n}\n\nexport interface ActionEventStep8 extends BaseActionSSEEvent {\n step: 8;\n phase: ActionPhase.STEP_8_ACTION_COMPLETE;\n status: ActionStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface ActionEventError extends BaseActionSSEEvent {\n step: 0;\n phase: ActionPhase.ACTION_ERROR;\n status: ActionStatus.ERROR;\n error: string;\n}\n\nexport interface ActionEventWasmError extends BaseActionSSEEvent {\n step: 0;\n phase: ActionPhase.WASM_ERROR;\n status: ActionStatus.ERROR;\n error: string;\n}\n\nexport type ActionSSEEvent =\n | ActionEventStep1\n | ActionEventStep2\n | ActionEventStep3\n | ActionEventStep4\n | ActionEventStep5\n | ActionEventStep6\n | ActionEventStep7\n | ActionEventStep8\n | ActionEventError\n | ActionEventWasmError;\n\nexport type DelegateActionSSEEvent = ActionSSEEvent;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Device Linking Event Types\n/////////////////////////////////////////////\n\nexport interface DeviceLinkingEventStep1 extends BaseDeviceLinkingSSEEvent {\n step: 1;\n phase: DeviceLinkingPhase.STEP_1_QR_CODE_GENERATED;\n}\n\nexport interface DeviceLinkingEventStep2 extends BaseDeviceLinkingSSEEvent {\n step: 2;\n phase: DeviceLinkingPhase.STEP_2_SCANNING;\n}\n\nexport interface DeviceLinkingEventStep3 extends BaseDeviceLinkingSSEEvent {\n step: 3;\n phase: DeviceLinkingPhase.STEP_3_AUTHORIZATION;\n}\n\nexport interface DeviceLinkingEventStep4 extends BaseDeviceLinkingSSEEvent {\n step: 4;\n phase: DeviceLinkingPhase.STEP_4_POLLING;\n}\n\nexport interface DeviceLinkingEventStep5 extends BaseDeviceLinkingSSEEvent {\n step: 5;\n phase: DeviceLinkingPhase.STEP_5_ADDKEY_DETECTED;\n}\n\nexport interface DeviceLinkingEventStep6 extends BaseDeviceLinkingSSEEvent {\n step: 6;\n phase: DeviceLinkingPhase.STEP_6_REGISTRATION;\n}\n\nexport interface DeviceLinkingEventStep7 extends BaseDeviceLinkingSSEEvent {\n step: 7;\n phase: DeviceLinkingPhase.STEP_7_LINKING_COMPLETE;\n}\n\nexport interface DeviceLinkingEventStep8 extends BaseDeviceLinkingSSEEvent {\n step: 8;\n phase: DeviceLinkingPhase.STEP_8_AUTO_LOGIN;\n}\n\nexport interface DeviceLinkingErrorEvent extends BaseDeviceLinkingSSEEvent {\n step: 0;\n phase: DeviceLinkingPhase.DEVICE_LINKING_ERROR\n | DeviceLinkingPhase.LOGIN_ERROR\n | DeviceLinkingPhase.REGISTRATION_ERROR;\n status: DeviceLinkingStatus.ERROR;\n error: string;\n}\n\nexport type DeviceLinkingSSEEvent =\n | DeviceLinkingEventStep1\n | DeviceLinkingEventStep2\n | DeviceLinkingEventStep3\n | DeviceLinkingEventStep4\n | DeviceLinkingEventStep5\n | DeviceLinkingEventStep6\n | DeviceLinkingEventStep7\n | DeviceLinkingEventStep8\n | DeviceLinkingErrorEvent;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Account Sync Event Types\n/////////////////////////////////////////////\n\nexport interface SyncAccountEventStep1 extends BaseSyncAccountEvent {\n step: 1;\n phase: SyncAccountPhase.STEP_1_PREPARATION;\n}\n\nexport interface SyncAccountEventStep2 extends BaseSyncAccountEvent {\n step: 2;\n phase: SyncAccountPhase.STEP_2_WEBAUTHN_AUTHENTICATION;\n}\n\nexport interface SyncAccountEventStep3 extends BaseSyncAccountEvent {\n step: 3;\n phase: SyncAccountPhase.STEP_3_SYNC_AUTHENTICATORS_ONCHAIN;\n data?: Record<string, unknown>;\n logs?: string[];\n}\n\nexport interface SyncAccountEventStep4 extends BaseSyncAccountEvent {\n step: 4;\n phase: SyncAccountPhase.STEP_4_AUTHENTICATOR_SAVED;\n status: SyncAccountStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface SyncAccountEventStep5 extends BaseSyncAccountEvent {\n step: 5;\n phase: SyncAccountPhase.STEP_5_SYNC_ACCOUNT_COMPLETE;\n status: SyncAccountStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface SyncAccountError extends BaseSyncAccountEvent {\n step: 0;\n phase: SyncAccountPhase.ERROR;\n status: SyncAccountStatus.ERROR;\n error: string;\n}\n\nexport type SyncAccountSSEEvent =\n | SyncAccountEventStep1\n | SyncAccountEventStep2\n | SyncAccountEventStep3\n | SyncAccountEventStep4\n | SyncAccountEventStep5\n | SyncAccountError;\n\n/////////////////////////////////////////////\n// SDK-Sent-Events: Email Recovery Event Types\n/////////////////////////////////////////////\n\nexport interface EmailRecoveryEventStep1 extends BaseEmailRecoveryEvent {\n step: 1;\n phase: EmailRecoveryPhase.STEP_1_PREPARATION;\n}\n\nexport interface EmailRecoveryEventStep2 extends BaseEmailRecoveryEvent {\n step: 2;\n phase: EmailRecoveryPhase.STEP_2_TOUCH_ID_REGISTRATION;\n}\n\nexport interface EmailRecoveryEventStep3 extends BaseEmailRecoveryEvent {\n step: 3;\n phase: EmailRecoveryPhase.STEP_3_AWAIT_EMAIL;\n}\n\nexport interface EmailRecoveryEventStep4 extends BaseEmailRecoveryEvent {\n step: 4;\n phase: EmailRecoveryPhase.STEP_4_POLLING_ADD_KEY | EmailRecoveryPhase.STEP_4_POLLING_VERIFICATION_RESULT;\n data?: {\n accountId?: string;\n requestId?: string;\n nearPublicKey?: string;\n elapsedMs?: number;\n pollCount?: number;\n [key: string]: unknown;\n };\n logs?: string[];\n}\n\nexport interface EmailRecoveryEventStep5 extends BaseEmailRecoveryEvent {\n step: 5;\n phase: EmailRecoveryPhase.STEP_5_FINALIZING_REGISTRATION;\n data?: Record<string, unknown>;\n}\n\nexport interface EmailRecoveryEventStep6 extends BaseEmailRecoveryEvent {\n step: 6;\n phase: EmailRecoveryPhase.STEP_6_COMPLETE;\n status: EmailRecoveryStatus.SUCCESS;\n data?: Record<string, unknown>;\n}\n\nexport interface EmailRecoveryEventResumedFromPending extends BaseEmailRecoveryEvent {\n step: 0;\n phase: EmailRecoveryPhase.RESUMED_FROM_PENDING;\n status: EmailRecoveryStatus.PROGRESS;\n data?: Record<string, unknown>;\n}\n\nexport interface EmailRecoveryErrorEvent extends BaseEmailRecoveryEvent {\n step: 0;\n phase: EmailRecoveryPhase.ERROR;\n status: EmailRecoveryStatus.ERROR;\n error: string;\n}\n\nexport type EmailRecoverySSEEvent =\n | EmailRecoveryEventStep1\n | EmailRecoveryEventStep2\n | EmailRecoveryEventStep3\n | EmailRecoveryEventStep4\n | EmailRecoveryEventStep5\n | EmailRecoveryEventStep6\n | EmailRecoveryEventResumedFromPending\n | EmailRecoveryErrorEvent;\n\n//////////////////////////////////\n/// Hooks Options\n//////////////////////////////////\n\n// Function Options\nexport interface RegistrationHooksOptions {\n onEvent?: EventCallback<RegistrationSSEEvent>;\n onError?: (error: Error) => void;\n afterCall?: AfterCall<RegistrationResult>;\n /**\n * Optional: registration signing policy.\n * - `{ mode: 'local-signer' }`: derive and store an encrypted local NEAR secret key (v3 vault).\n * - `{ mode: 'threshold-signer' }`: derive the local key AND enroll a threshold Ed25519 (2-of-2) access key\n * during registration (relay adds the threshold public key on-chain and returns relayerKeyId).\n *\n * Defaults to `{ mode: 'local-signer' }` for backwards compatibility in public APIs.\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration. When provided, overrides user preferences\n // for this request only (not persisted).\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface LoginHooksOptions {\n onEvent?: EventCallback<LoginSSEvent>;\n onError?: (error: Error) => void;\n afterCall?: AfterCall<LoginAndCreateSessionResult>;\n /**\n * Optional: passkey deviceNumber hint.\n *\n * When multiple passkeys exist for the same `nearAccountId`, providing this hint lets\n * the login flow prioritize the matching `credentialId` when presenting the TouchID\n * (WebAuthn) prompt.\n */\n deviceNumber?: number;\n // Optional: request a server session (JWT in body or HttpOnly cookie)\n session?: {\n // 'jwt' returns the token in the JSON body; 'cookie' sets HttpOnly cookie\n kind: 'jwt' | 'cookie';\n // Optional: override relay URL; defaults to TatchiConfigs.relayer.url\n relayUrl?: string;\n // Optional: override route path; defaults to '/verify-authentication-response'\n route?: string;\n };\n /**\n * Optional: override the warm signing session policy minted during login.\n * Defaults come from `TatchiConfigs.signingSessionDefaults`.\n */\n signingSession?: {\n ttlMs?: number;\n remainingUses?: number;\n };\n}\n\nexport interface ActionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n afterCall?: AfterCall<ActionResult>;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration. When provided, overrides user preferences\n // for this request only (not persisted).\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport type ExecutionWaitOption =\n | { mode: 'sequential'; waitUntil?: TxExecutionStatus }\n | { mode: 'parallelStaggered'; staggerMs: number };\n\nexport interface SignAndSendTransactionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Execution control for multi-transaction broadcasts:\n * - { mode: 'sequential', waitUntil?: TxExecutionStatus }\n * - { mode: 'parallelStaggered', staggerMs: number }\n */\n executionWait?: ExecutionWaitOption;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n\n afterCall?: AfterCall<ActionResult[]>;\n // Per-call confirmation configuration. When provided, overrides user preferences\n // for this request only (not persisted).\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface SignTransactionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n\n afterCall?: AfterCall<SignTransactionResult[]>;\n waitUntil?: TxExecutionStatus;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration (non-persistent)\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface SendTransactionHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n\n afterCall?: AfterCall<ActionResult>;\n waitUntil?: TxExecutionStatus;\n}\n\nexport interface DelegateActionHooksOptions {\n onEvent?: EventCallback<DelegateActionSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n afterCall?: AfterCall<SignDelegateActionResult>;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n\nexport interface DelegateRelayHooksOptions {\n onEvent?: EventCallback<ActionSSEEvent>;\n onError?: (error: Error) => void;\n afterCall?: AfterCall<DelegateRelayResult>;\n}\n\nexport type SignAndSendDelegateActionHooksOptions =\n Omit<DelegateActionHooksOptions, 'afterCall'> & {\n afterCall?: AfterCall<SignAndSendDelegateActionResult>;\n };\n\nexport interface SyncAccountHooksOptions {\n onEvent?: EventCallback<SyncAccountSSEEvent>;\n onError?: (error: Error) => void;\n waitUntil?: TxExecutionStatus;\n\n afterCall?: AfterCall<SyncAccountResult>;\n}\n\nexport interface SignNEP413HooksOptions {\n onEvent?: EventCallback<RegistrationSSEEvent | LoginSSEvent | ActionSSEEvent | DeviceLinkingSSEEvent | SyncAccountSSEEvent | EmailRecoverySSEEvent>;\n onError?: (error: Error) => void;\n\n afterCall?: AfterCall<SignNEP413MessageResult>;\n /**\n * Signing policy:\n * { mode: 'local-signer' }\n * { mode: 'threshold-signer'; behavior?: ThresholdBehavior };\n */\n signerMode?: SignerMode;\n /**\n * Preferred grouping for per-call confirmer copy.\n */\n confirmerText?: { title?: string; body?: string };\n // Per-call confirmation configuration (non-persistent)\n // Accept partial config so callers can pass minimal overrides like { uiMode: 'drawer' }\n confirmationConfig?: Partial<ConfirmationConfig>;\n}\n"],"mappings":";AAmBA,IAAY,kEAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAEF,IAAY,oEAAL;AACL;AACA;AACA;;;AAIF,IAAY,oDAAL;AACL;AACA;AACA;AACA;AACA;;;AAEF,IAAY,sDAAL;AACL;AACA;AACA;;;AAIF,IAAY,sDAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAEF,IAAY,wDAAL;AACL;AACA;AACA;;;AAOF,IAAY,gEAAL;AACL;AACA;AACA;AACA;AACA;AACA;;;AAEF,IAAY,kEAAL;AACL;AACA;AACA;;;AAIF,IAAY,oEAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAEF,IAAY,sEAAL;AACL;AACA;AACA;;;AAIF,IAAY,oEAAL;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAEF,IAAY,sEAAL;AACL;AACA;AACA"}
@@ -32,7 +32,7 @@ function useTatchiWithSdkFlow(args) {
32
32
  ...options,
33
33
  onEvent: (event) => {
34
34
  appendSdkEventMessage(seq, event.message);
35
- if (event.phase === RegistrationPhase.STEP_8_REGISTRATION_COMPLETE && event.status === RegistrationStatus.SUCCESS) endSdkFlow("register", seq, "success");
35
+ if (event.phase === RegistrationPhase.STEP_9_REGISTRATION_COMPLETE && event.status === RegistrationStatus.SUCCESS) endSdkFlow("register", seq, "success");
36
36
  else if (event.phase === RegistrationPhase.REGISTRATION_ERROR || event.status === RegistrationStatus.ERROR) {
37
37
  const error = "error" in event ? event.error : event.message;
38
38
  endSdkFlow("register", seq, "error", error || event.message);
@@ -1 +1 @@
1
- {"version":3,"file":"useTatchiWithSdkFlow.js","names":["loginAndCreateSessionWithSdkFlow: LoginAndCreateSessionFn","wrappedOptions: LoginHooksOptions","registerPasskeyWithSdkFlow: RegisterPasskeyFn","wrappedOptions: RegistrationHooksOptions","syncAccountWithSdkFlow: SyncAccountFn","args","options: SyncAccountHooksOptions | undefined","wrappedOptions: SyncAccountHooksOptions","value: unknown"],"sources":["../../../../src/react/context/useTatchiWithSdkFlow.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport type { TatchiPasskey } from '@/core/TatchiPasskey';\nimport {\n SyncAccountPhase,\n SyncAccountStatus,\n type SyncAccountHooksOptions,\n type SyncAccountSSEEvent,\n LoginPhase,\n LoginStatus,\n type LoginHooksOptions,\n type LoginSSEvent,\n RegistrationPhase,\n RegistrationStatus,\n type RegistrationHooksOptions,\n type RegistrationSSEEvent,\n} from '@/core/types/sdkSentEvents';\n\nexport function useTatchiWithSdkFlow(args: {\n tatchi: TatchiPasskey;\n beginSdkFlow: (kind: 'login' | 'register' | 'sync', accountId?: string) => number;\n appendSdkEventMessage: (seq: number, message: string) => void;\n endSdkFlow: (kind: 'login' | 'register' | 'sync', seq: number, status: 'success' | 'error', error?: string) => void;\n}): TatchiPasskey {\n const { tatchi, beginSdkFlow, appendSdkEventMessage, endSdkFlow } = args;\n\n return useMemo(() => {\n /**\n * We use a `Proxy` to instrument a few core flow entrypoints (login/register/sync)\n * while preserving the full `TatchiPasskey` API surface.\n *\n * This lets *all* callers (not just PasskeyAuthMenu) use `ctx.tatchi.*` directly and\n * still have `sdkFlow` update as events stream in.\n */\n type LoginAndCreateSessionFn = TatchiPasskey['loginAndCreateSession'];\n type RegisterPasskeyFn = TatchiPasskey['registerPasskey'];\n type SyncAccountFn = TatchiPasskey['syncAccount'];\n\n const loginAndCreateSessionWithSdkFlow: LoginAndCreateSessionFn = async (\n nearAccountId,\n options,\n ) => {\n const seq = beginSdkFlow('login', nearAccountId);\n const wrappedOptions: LoginHooksOptions = {\n ...options,\n onEvent: (event: LoginSSEvent) => {\n appendSdkEventMessage(seq, event.message);\n if (event.phase === LoginPhase.STEP_4_LOGIN_COMPLETE && event.status === LoginStatus.SUCCESS) {\n endSdkFlow('login', seq, 'success');\n } else if (event.phase === LoginPhase.LOGIN_ERROR || event.status === LoginStatus.ERROR) {\n const error = 'error' in event ? event.error : event.message;\n endSdkFlow('login', seq, 'error', error || event.message);\n }\n options?.onEvent?.(event);\n },\n onError: (error: Error) => {\n appendSdkEventMessage(seq, error.message);\n endSdkFlow('login', seq, 'error', error.message);\n options?.onError?.(error);\n },\n };\n\n return await tatchi.loginAndCreateSession(nearAccountId, wrappedOptions);\n };\n\n const registerPasskeyWithSdkFlow: RegisterPasskeyFn = async (\n nearAccountId,\n options,\n ) => {\n const seq = beginSdkFlow('register', nearAccountId);\n const wrappedOptions: RegistrationHooksOptions = {\n ...options,\n onEvent: (event: RegistrationSSEEvent) => {\n appendSdkEventMessage(seq, event.message);\n if (\n event.phase === RegistrationPhase.STEP_8_REGISTRATION_COMPLETE &&\n event.status === RegistrationStatus.SUCCESS\n ) {\n endSdkFlow('register', seq, 'success');\n } else if (event.phase === RegistrationPhase.REGISTRATION_ERROR || event.status === RegistrationStatus.ERROR) {\n const error = 'error' in event ? event.error : event.message;\n endSdkFlow('register', seq, 'error', error || event.message);\n }\n options?.onEvent?.(event);\n },\n onError: (error: Error) => {\n appendSdkEventMessage(seq, error.message);\n endSdkFlow('register', seq, 'error', error.message);\n options?.onError?.(error);\n },\n };\n\n return await tatchi.registerPasskey(nearAccountId, wrappedOptions);\n };\n\n const syncAccountWithSdkFlow: SyncAccountFn = async (args) => {\n const seq = beginSdkFlow('sync', args?.accountId);\n const options: SyncAccountHooksOptions | undefined = args?.options;\n\n const wrappedOptions: SyncAccountHooksOptions = {\n ...options,\n onEvent: (event: SyncAccountSSEEvent) => {\n appendSdkEventMessage(seq, event.message);\n if (\n event.phase === SyncAccountPhase.STEP_5_SYNC_ACCOUNT_COMPLETE &&\n event.status === SyncAccountStatus.SUCCESS\n ) {\n endSdkFlow('sync', seq, 'success');\n } else if (event.phase === SyncAccountPhase.ERROR || event.status === SyncAccountStatus.ERROR) {\n const error = 'error' in event ? event.error : event.message;\n endSdkFlow('sync', seq, 'error', error || event.message);\n }\n options?.onEvent?.(event);\n },\n onError: (error: Error) => {\n appendSdkEventMessage(seq, error.message);\n endSdkFlow('sync', seq, 'error', error.message);\n options?.onError?.(error);\n },\n };\n\n return await tatchi.syncAccount({\n ...args,\n options: wrappedOptions,\n });\n };\n\n return new Proxy(tatchi, {\n get(target, prop, receiver) {\n if (prop === 'loginAndCreateSession') {\n return loginAndCreateSessionWithSdkFlow;\n }\n\n if (prop === 'registerPasskey') {\n return registerPasskeyWithSdkFlow;\n }\n\n if (prop === 'syncAccount') {\n return syncAccountWithSdkFlow;\n }\n\n const value: unknown = Reflect.get(target as object, prop, receiver);\n // For non-wrapped methods, bind to preserve `this` on the class instance.\n if (typeof value === 'function') return (value as (...args: unknown[]) => unknown).bind(target);\n return value;\n },\n });\n }, [appendSdkEventMessage, beginSdkFlow, endSdkFlow, tatchi]);\n}\n\nexport default useTatchiWithSdkFlow;\n"],"mappings":";;;;AAiBA,SAAgB,qBAAqB,MAKnB;CAChB,MAAM,EAAE,QAAQ,cAAc,uBAAuB,eAAe;AAEpE,QAAO,cAAc;EAYnB,MAAMA,mCAA4D,OAChE,eACA,YACG;GACH,MAAM,MAAM,aAAa,SAAS;GAClC,MAAMC,iBAAoC;IACxC,GAAG;IACH,UAAU,UAAwB;AAChC,2BAAsB,KAAK,MAAM;AACjC,SAAI,MAAM,UAAU,WAAW,yBAAyB,MAAM,WAAW,YAAY,QACnF,YAAW,SAAS,KAAK;cAChB,MAAM,UAAU,WAAW,eAAe,MAAM,WAAW,YAAY,OAAO;MACvF,MAAM,QAAQ,WAAW,QAAQ,MAAM,QAAQ,MAAM;AACrD,iBAAW,SAAS,KAAK,SAAS,SAAS,MAAM;;AAEnD,cAAS,UAAU;;IAErB,UAAU,UAAiB;AACzB,2BAAsB,KAAK,MAAM;AACjC,gBAAW,SAAS,KAAK,SAAS,MAAM;AACxC,cAAS,UAAU;;;AAIvB,UAAO,MAAM,OAAO,sBAAsB,eAAe;;EAG3D,MAAMC,6BAAgD,OACpD,eACA,YACG;GACH,MAAM,MAAM,aAAa,YAAY;GACrC,MAAMC,iBAA2C;IAC/C,GAAG;IACH,UAAU,UAAgC;AACxC,2BAAsB,KAAK,MAAM;AACjC,SACE,MAAM,UAAU,kBAAkB,gCAClC,MAAM,WAAW,mBAAmB,QAEpC,YAAW,YAAY,KAAK;cACnB,MAAM,UAAU,kBAAkB,sBAAsB,MAAM,WAAW,mBAAmB,OAAO;MAC5G,MAAM,QAAQ,WAAW,QAAQ,MAAM,QAAQ,MAAM;AACrD,iBAAW,YAAY,KAAK,SAAS,SAAS,MAAM;;AAEtD,cAAS,UAAU;;IAErB,UAAU,UAAiB;AACzB,2BAAsB,KAAK,MAAM;AACjC,gBAAW,YAAY,KAAK,SAAS,MAAM;AAC3C,cAAS,UAAU;;;AAIvB,UAAO,MAAM,OAAO,gBAAgB,eAAe;;EAGrD,MAAMC,yBAAwC,OAAO,WAAS;GAC5D,MAAM,MAAM,aAAa,QAAQC,QAAM;GACvC,MAAMC,UAA+CD,QAAM;GAE3D,MAAME,iBAA0C;IAC9C,GAAG;IACH,UAAU,UAA+B;AACvC,2BAAsB,KAAK,MAAM;AACjC,SACE,MAAM,UAAU,iBAAiB,gCACjC,MAAM,WAAW,kBAAkB,QAEnC,YAAW,QAAQ,KAAK;cACf,MAAM,UAAU,iBAAiB,SAAS,MAAM,WAAW,kBAAkB,OAAO;MAC7F,MAAM,QAAQ,WAAW,QAAQ,MAAM,QAAQ,MAAM;AACrD,iBAAW,QAAQ,KAAK,SAAS,SAAS,MAAM;;AAElD,cAAS,UAAU;;IAErB,UAAU,UAAiB;AACzB,2BAAsB,KAAK,MAAM;AACjC,gBAAW,QAAQ,KAAK,SAAS,MAAM;AACvC,cAAS,UAAU;;;AAIvB,UAAO,MAAM,OAAO,YAAY;IAC9B,GAAGF;IACH,SAAS;;;AAIb,SAAO,IAAI,MAAM,QAAQ,EACvB,IAAI,QAAQ,MAAM,UAAU;AAC1B,OAAI,SAAS,wBACX,QAAO;AAGT,OAAI,SAAS,kBACX,QAAO;AAGT,OAAI,SAAS,cACX,QAAO;GAGT,MAAMG,QAAiB,QAAQ,IAAI,QAAkB,MAAM;AAE3D,OAAI,OAAO,UAAU,WAAY,QAAQ,MAA0C,KAAK;AACxF,UAAO;;IAGV;EAAC;EAAuB;EAAc;EAAY"}
1
+ {"version":3,"file":"useTatchiWithSdkFlow.js","names":["loginAndCreateSessionWithSdkFlow: LoginAndCreateSessionFn","wrappedOptions: LoginHooksOptions","registerPasskeyWithSdkFlow: RegisterPasskeyFn","wrappedOptions: RegistrationHooksOptions","syncAccountWithSdkFlow: SyncAccountFn","args","options: SyncAccountHooksOptions | undefined","wrappedOptions: SyncAccountHooksOptions","value: unknown"],"sources":["../../../../src/react/context/useTatchiWithSdkFlow.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport type { TatchiPasskey } from '@/core/TatchiPasskey';\nimport {\n SyncAccountPhase,\n SyncAccountStatus,\n type SyncAccountHooksOptions,\n type SyncAccountSSEEvent,\n LoginPhase,\n LoginStatus,\n type LoginHooksOptions,\n type LoginSSEvent,\n RegistrationPhase,\n RegistrationStatus,\n type RegistrationHooksOptions,\n type RegistrationSSEEvent,\n} from '@/core/types/sdkSentEvents';\n\nexport function useTatchiWithSdkFlow(args: {\n tatchi: TatchiPasskey;\n beginSdkFlow: (kind: 'login' | 'register' | 'sync', accountId?: string) => number;\n appendSdkEventMessage: (seq: number, message: string) => void;\n endSdkFlow: (kind: 'login' | 'register' | 'sync', seq: number, status: 'success' | 'error', error?: string) => void;\n}): TatchiPasskey {\n const { tatchi, beginSdkFlow, appendSdkEventMessage, endSdkFlow } = args;\n\n return useMemo(() => {\n /**\n * We use a `Proxy` to instrument a few core flow entrypoints (login/register/sync)\n * while preserving the full `TatchiPasskey` API surface.\n *\n * This lets *all* callers (not just PasskeyAuthMenu) use `ctx.tatchi.*` directly and\n * still have `sdkFlow` update as events stream in.\n */\n type LoginAndCreateSessionFn = TatchiPasskey['loginAndCreateSession'];\n type RegisterPasskeyFn = TatchiPasskey['registerPasskey'];\n type SyncAccountFn = TatchiPasskey['syncAccount'];\n\n const loginAndCreateSessionWithSdkFlow: LoginAndCreateSessionFn = async (\n nearAccountId,\n options,\n ) => {\n const seq = beginSdkFlow('login', nearAccountId);\n const wrappedOptions: LoginHooksOptions = {\n ...options,\n onEvent: (event: LoginSSEvent) => {\n appendSdkEventMessage(seq, event.message);\n if (event.phase === LoginPhase.STEP_4_LOGIN_COMPLETE && event.status === LoginStatus.SUCCESS) {\n endSdkFlow('login', seq, 'success');\n } else if (event.phase === LoginPhase.LOGIN_ERROR || event.status === LoginStatus.ERROR) {\n const error = 'error' in event ? event.error : event.message;\n endSdkFlow('login', seq, 'error', error || event.message);\n }\n options?.onEvent?.(event);\n },\n onError: (error: Error) => {\n appendSdkEventMessage(seq, error.message);\n endSdkFlow('login', seq, 'error', error.message);\n options?.onError?.(error);\n },\n };\n\n return await tatchi.loginAndCreateSession(nearAccountId, wrappedOptions);\n };\n\n const registerPasskeyWithSdkFlow: RegisterPasskeyFn = async (\n nearAccountId,\n options,\n ) => {\n const seq = beginSdkFlow('register', nearAccountId);\n const wrappedOptions: RegistrationHooksOptions = {\n ...options,\n onEvent: (event: RegistrationSSEEvent) => {\n appendSdkEventMessage(seq, event.message);\n if (\n event.phase === RegistrationPhase.STEP_9_REGISTRATION_COMPLETE &&\n event.status === RegistrationStatus.SUCCESS\n ) {\n endSdkFlow('register', seq, 'success');\n } else if (event.phase === RegistrationPhase.REGISTRATION_ERROR || event.status === RegistrationStatus.ERROR) {\n const error = 'error' in event ? event.error : event.message;\n endSdkFlow('register', seq, 'error', error || event.message);\n }\n options?.onEvent?.(event);\n },\n onError: (error: Error) => {\n appendSdkEventMessage(seq, error.message);\n endSdkFlow('register', seq, 'error', error.message);\n options?.onError?.(error);\n },\n };\n\n return await tatchi.registerPasskey(nearAccountId, wrappedOptions);\n };\n\n const syncAccountWithSdkFlow: SyncAccountFn = async (args) => {\n const seq = beginSdkFlow('sync', args?.accountId);\n const options: SyncAccountHooksOptions | undefined = args?.options;\n\n const wrappedOptions: SyncAccountHooksOptions = {\n ...options,\n onEvent: (event: SyncAccountSSEEvent) => {\n appendSdkEventMessage(seq, event.message);\n if (\n event.phase === SyncAccountPhase.STEP_5_SYNC_ACCOUNT_COMPLETE &&\n event.status === SyncAccountStatus.SUCCESS\n ) {\n endSdkFlow('sync', seq, 'success');\n } else if (event.phase === SyncAccountPhase.ERROR || event.status === SyncAccountStatus.ERROR) {\n const error = 'error' in event ? event.error : event.message;\n endSdkFlow('sync', seq, 'error', error || event.message);\n }\n options?.onEvent?.(event);\n },\n onError: (error: Error) => {\n appendSdkEventMessage(seq, error.message);\n endSdkFlow('sync', seq, 'error', error.message);\n options?.onError?.(error);\n },\n };\n\n return await tatchi.syncAccount({\n ...args,\n options: wrappedOptions,\n });\n };\n\n return new Proxy(tatchi, {\n get(target, prop, receiver) {\n if (prop === 'loginAndCreateSession') {\n return loginAndCreateSessionWithSdkFlow;\n }\n\n if (prop === 'registerPasskey') {\n return registerPasskeyWithSdkFlow;\n }\n\n if (prop === 'syncAccount') {\n return syncAccountWithSdkFlow;\n }\n\n const value: unknown = Reflect.get(target as object, prop, receiver);\n // For non-wrapped methods, bind to preserve `this` on the class instance.\n if (typeof value === 'function') return (value as (...args: unknown[]) => unknown).bind(target);\n return value;\n },\n });\n }, [appendSdkEventMessage, beginSdkFlow, endSdkFlow, tatchi]);\n}\n\nexport default useTatchiWithSdkFlow;\n"],"mappings":";;;;AAiBA,SAAgB,qBAAqB,MAKnB;CAChB,MAAM,EAAE,QAAQ,cAAc,uBAAuB,eAAe;AAEpE,QAAO,cAAc;EAYnB,MAAMA,mCAA4D,OAChE,eACA,YACG;GACH,MAAM,MAAM,aAAa,SAAS;GAClC,MAAMC,iBAAoC;IACxC,GAAG;IACH,UAAU,UAAwB;AAChC,2BAAsB,KAAK,MAAM;AACjC,SAAI,MAAM,UAAU,WAAW,yBAAyB,MAAM,WAAW,YAAY,QACnF,YAAW,SAAS,KAAK;cAChB,MAAM,UAAU,WAAW,eAAe,MAAM,WAAW,YAAY,OAAO;MACvF,MAAM,QAAQ,WAAW,QAAQ,MAAM,QAAQ,MAAM;AACrD,iBAAW,SAAS,KAAK,SAAS,SAAS,MAAM;;AAEnD,cAAS,UAAU;;IAErB,UAAU,UAAiB;AACzB,2BAAsB,KAAK,MAAM;AACjC,gBAAW,SAAS,KAAK,SAAS,MAAM;AACxC,cAAS,UAAU;;;AAIvB,UAAO,MAAM,OAAO,sBAAsB,eAAe;;EAG3D,MAAMC,6BAAgD,OACpD,eACA,YACG;GACH,MAAM,MAAM,aAAa,YAAY;GACrC,MAAMC,iBAA2C;IAC/C,GAAG;IACH,UAAU,UAAgC;AACxC,2BAAsB,KAAK,MAAM;AACjC,SACE,MAAM,UAAU,kBAAkB,gCAClC,MAAM,WAAW,mBAAmB,QAEpC,YAAW,YAAY,KAAK;cACnB,MAAM,UAAU,kBAAkB,sBAAsB,MAAM,WAAW,mBAAmB,OAAO;MAC5G,MAAM,QAAQ,WAAW,QAAQ,MAAM,QAAQ,MAAM;AACrD,iBAAW,YAAY,KAAK,SAAS,SAAS,MAAM;;AAEtD,cAAS,UAAU;;IAErB,UAAU,UAAiB;AACzB,2BAAsB,KAAK,MAAM;AACjC,gBAAW,YAAY,KAAK,SAAS,MAAM;AAC3C,cAAS,UAAU;;;AAIvB,UAAO,MAAM,OAAO,gBAAgB,eAAe;;EAGrD,MAAMC,yBAAwC,OAAO,WAAS;GAC5D,MAAM,MAAM,aAAa,QAAQC,QAAM;GACvC,MAAMC,UAA+CD,QAAM;GAE3D,MAAME,iBAA0C;IAC9C,GAAG;IACH,UAAU,UAA+B;AACvC,2BAAsB,KAAK,MAAM;AACjC,SACE,MAAM,UAAU,iBAAiB,gCACjC,MAAM,WAAW,kBAAkB,QAEnC,YAAW,QAAQ,KAAK;cACf,MAAM,UAAU,iBAAiB,SAAS,MAAM,WAAW,kBAAkB,OAAO;MAC7F,MAAM,QAAQ,WAAW,QAAQ,MAAM,QAAQ,MAAM;AACrD,iBAAW,QAAQ,KAAK,SAAS,SAAS,MAAM;;AAElD,cAAS,UAAU;;IAErB,UAAU,UAAiB;AACzB,2BAAsB,KAAK,MAAM;AACjC,gBAAW,QAAQ,KAAK,SAAS,MAAM;AACvC,cAAS,UAAU;;;AAIvB,UAAO,MAAM,OAAO,YAAY;IAC9B,GAAGF;IACH,SAAS;;;AAIb,SAAO,IAAI,MAAM,QAAQ,EACvB,IAAI,QAAQ,MAAM,UAAU;AAC1B,OAAI,SAAS,wBACX,QAAO;AAGT,OAAI,SAAS,kBACX,QAAO;AAGT,OAAI,SAAS,cACX,QAAO;GAGT,MAAMG,QAAiB,QAAQ,IAAI,QAAkB,MAAM;AAE3D,OAAI,OAAO,UAAU,WAAY,QAAQ,MAA0C,KAAK;AACxF,UAAO;;IAGV;EAAC;EAAuB;EAAc;EAAY"}
@@ -160,8 +160,8 @@ async function registerPasskeyInternal(context, nearAccountId, options, authenti
160
160
  onEvent
161
161
  }).catch(() => {});
162
162
  onEvent?.({
163
- step: 7,
164
- phase: RegistrationPhase.STEP_7_DATABASE_STORAGE,
163
+ step: 8,
164
+ phase: RegistrationPhase.STEP_8_DATABASE_STORAGE,
165
165
  status: RegistrationStatus.PROGRESS,
166
166
  message: "Storing passkey wallet metadata..."
167
167
  });
@@ -175,8 +175,8 @@ async function registerPasskeyInternal(context, nearAccountId, options, authenti
175
175
  });
176
176
  registrationState.databaseStored = true;
177
177
  onEvent?.({
178
- step: 7,
179
- phase: RegistrationPhase.STEP_7_DATABASE_STORAGE,
178
+ step: 8,
179
+ phase: RegistrationPhase.STEP_8_DATABASE_STORAGE,
180
180
  status: RegistrationStatus.SUCCESS,
181
181
  message: "Registration metadata stored successfully"
182
182
  });
@@ -237,8 +237,8 @@ async function registerPasskeyInternal(context, nearAccountId, options, authenti
237
237
  console.warn("Failed to initialize current user after registration:", initErr);
238
238
  }
239
239
  onEvent?.({
240
- step: 8,
241
- phase: RegistrationPhase.STEP_8_REGISTRATION_COMPLETE,
240
+ step: 9,
241
+ phase: RegistrationPhase.STEP_9_REGISTRATION_COMPLETE,
242
242
  status: RegistrationStatus.SUCCESS,
243
243
  message: "Registration completed!"
244
244
  });
@@ -365,8 +365,31 @@ async function activateThresholdEnrollmentPostRegistration(opts) {
365
365
  const relayerKeyId = String(opts.relayerKeyId || "").trim();
366
366
  const clientVerifyingShareB64u = String(opts.thresholdClientVerifyingShareB64u || "").trim();
367
367
  const relayerVerifyingShareB64u = String(opts.relayerVerifyingShareB64u || "").trim();
368
- if (!thresholdPublicKey || !relayerKeyId || !clientVerifyingShareB64u || !relayerVerifyingShareB64u) {
368
+ const emitThresholdKeyEnrollmentResult = (input) => {
369
+ opts.onEvent?.({
370
+ step: 7,
371
+ phase: RegistrationPhase.STEP_7_THRESHOLD_KEY_ENROLLMENT,
372
+ status: RegistrationStatus.SUCCESS,
373
+ message: input.message,
374
+ thresholdKeyReady: input.thresholdKeyReady,
375
+ thresholdPublicKey: thresholdPublicKey || void 0,
376
+ relayerKeyId: relayerKeyId || void 0,
377
+ deviceNumber: 1,
378
+ warning: input.warning
379
+ });
380
+ };
381
+ const missingEnrollmentDetails = [];
382
+ if (!thresholdPublicKey) missingEnrollmentDetails.push("thresholdPublicKey");
383
+ if (!relayerKeyId) missingEnrollmentDetails.push("relayerKeyId");
384
+ if (!clientVerifyingShareB64u) missingEnrollmentDetails.push("clientVerifyingShareB64u");
385
+ if (!relayerVerifyingShareB64u) missingEnrollmentDetails.push("relayerVerifyingShareB64u");
386
+ if (missingEnrollmentDetails.length) {
369
387
  console.warn("[Registration] threshold-signer requested but threshold enrollment details are missing; continuing with local-signer only");
388
+ emitThresholdKeyEnrollmentResult({
389
+ thresholdKeyReady: false,
390
+ message: "Threshold key not ready; continuing with local-signer only",
391
+ warning: `Missing threshold enrollment details: ${missingEnrollmentDetails.join(", ")}`
392
+ });
370
393
  return;
371
394
  }
372
395
  try {
@@ -424,8 +447,18 @@ async function activateThresholdEnrollmentPostRegistration(opts) {
424
447
  status: RegistrationStatus.SUCCESS,
425
448
  message: "Threshold access key activated on-chain"
426
449
  });
450
+ emitThresholdKeyEnrollmentResult({
451
+ thresholdKeyReady: true,
452
+ message: "Threshold key ready"
453
+ });
427
454
  } catch (e) {
455
+ const warning = e && typeof e === "object" && "message" in e ? String(e.message || "") : String(e || "");
428
456
  console.warn("[Registration] threshold enrollment activation failed; continuing with local-signer only:", e);
457
+ emitThresholdKeyEnrollmentResult({
458
+ thresholdKeyReady: false,
459
+ message: "Threshold key not ready; continuing with local-signer only",
460
+ warning
461
+ });
429
462
  }
430
463
  }
431
464
  async function verifyAccountAccessKeysPresent(nearClient, nearAccountId, expectedPublicKeys, opts) {