@tatchi-xyz/sdk 0.31.1 → 0.32.1
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.
- package/README.md +2 -0
- package/dist/cjs/core/TatchiPasskey/registration.js +40 -7
- package/dist/cjs/core/TatchiPasskey/registration.js.map +1 -1
- package/dist/cjs/core/WalletIframe/client/on-events-progress-bus.js +1 -1
- package/dist/cjs/core/WalletIframe/client/on-events-progress-bus.js.map +1 -1
- package/dist/cjs/core/types/sdkSentEvents.js +3 -2
- package/dist/cjs/core/types/sdkSentEvents.js.map +1 -1
- package/dist/cjs/react/components/PasskeyAuthMenu/shell.js +2 -44
- package/dist/cjs/react/components/PasskeyAuthMenu/shell.js.map +1 -1
- package/dist/cjs/react/context/useTatchiWithSdkFlow.js +1 -1
- package/dist/cjs/react/context/useTatchiWithSdkFlow.js.map +1 -1
- package/dist/cjs/react/src/core/TatchiPasskey/registration.js +40 -7
- package/dist/cjs/react/src/core/TatchiPasskey/registration.js.map +1 -1
- package/dist/cjs/react/src/core/WalletIframe/client/on-events-progress-bus.js +1 -1
- package/dist/cjs/react/src/core/WalletIframe/client/on-events-progress-bus.js.map +1 -1
- package/dist/cjs/react/src/core/types/sdkSentEvents.js +3 -2
- package/dist/cjs/react/src/core/types/sdkSentEvents.js.map +1 -1
- package/dist/esm/core/TatchiPasskey/registration.js +40 -7
- package/dist/esm/core/TatchiPasskey/registration.js.map +1 -1
- package/dist/esm/core/WalletIframe/client/on-events-progress-bus.js +1 -1
- package/dist/esm/core/WalletIframe/client/on-events-progress-bus.js.map +1 -1
- package/dist/esm/core/types/sdkSentEvents.js +3 -2
- package/dist/esm/core/types/sdkSentEvents.js.map +1 -1
- package/dist/esm/react/components/PasskeyAuthMenu/shell.js +2 -44
- package/dist/esm/react/components/PasskeyAuthMenu/shell.js.map +1 -1
- package/dist/esm/react/context/useTatchiWithSdkFlow.js +1 -1
- package/dist/esm/react/context/useTatchiWithSdkFlow.js.map +1 -1
- package/dist/esm/react/src/core/TatchiPasskey/registration.js +40 -7
- package/dist/esm/react/src/core/TatchiPasskey/registration.js.map +1 -1
- package/dist/esm/react/src/core/WalletIframe/client/on-events-progress-bus.js +1 -1
- package/dist/esm/react/src/core/WalletIframe/client/on-events-progress-bus.js.map +1 -1
- package/dist/esm/react/src/core/types/sdkSentEvents.js +3 -2
- package/dist/esm/react/src/core/types/sdkSentEvents.js.map +1 -1
- package/dist/esm/sdk/{delegateAction-DdkvFFKA.js → delegateAction-Bq5zkOvn.js} +1 -1
- package/dist/esm/sdk/{emailRecovery-C0LSDleV.js → emailRecovery-B1hbE_sM.js} +3 -3
- package/dist/esm/sdk/{linkDevice-Ds1GNIDk.js → linkDevice-CRPf5aW2.js} +3 -3
- package/dist/esm/sdk/{login-BKhTuGcy.js → login-DUIWZHp_.js} +2 -2
- package/dist/esm/sdk/offline-export-app.js +3 -2
- package/dist/esm/sdk/offline-export-app.js.map +1 -1
- package/dist/esm/sdk/{relay-Dq9D7fhG.js → relay-BCEyWFew.js} +1 -1
- package/dist/esm/sdk/{router-2aGn-CTp.js → router-Cj2WexK-.js} +2 -2
- package/dist/esm/sdk/{rpcCalls-BPI0icZG.js → rpcCalls-C1sp-Epo.js} +2 -2
- package/dist/esm/sdk/{rpcCalls-BW3M_q3-.js → rpcCalls-VL4loDKP.js} +1 -1
- package/dist/esm/sdk/{scanDevice-BBSehlMx.js → scanDevice-C0HcnZym.js} +3 -3
- package/dist/esm/sdk/{sdkSentEvents-CzAZBFjP.js → sdkSentEvents-BfkcI7EN.js} +3 -2
- package/dist/esm/sdk/{signNEP413-DsyWH_Jo.js → signNEP413-lj0swHsD.js} +1 -1
- package/dist/esm/sdk/{syncAccount-DEZHBiRa.js → syncAccount-DnQ9AstS.js} +3 -3
- package/dist/esm/sdk/{syncAccount-DHKtl-xh.js → syncAccount-xh81Vppo.js} +2 -2
- package/dist/esm/sdk/wallet-iframe-host.js +54 -21
- package/dist/esm/wasm_vrf_worker/pkg/wasm_vrf_worker_bg.wasm +0 -0
- package/dist/types/src/core/types/sdkSentEvents.d.ts +18 -7
- package/dist/types/src/core/types/sdkSentEvents.d.ts.map +1 -1
- package/dist/types/src/react/components/PasskeyAuthMenu/shell.d.ts.map +1 -1
- package/dist/workers/offline-export-sw.js +1 -156
- package/dist/workers/wasm_vrf_worker_bg.wasm +0 -0
- package/dist/workers/web3authn-signer.worker.js +2 -1360
- package/dist/workers/web3authn-vrf.worker.js +2 -2857
- package/package.json +4 -4
|
@@ -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"}
|
|
@@ -35,61 +35,19 @@ var LazyErrorBoundary = class extends React.Component {
|
|
|
35
35
|
const PasskeyAuthMenu = (props) => {
|
|
36
36
|
const [isClient, setIsClient] = React.useState(false);
|
|
37
37
|
const [retryKey, setRetryKey] = React.useState(0);
|
|
38
|
-
const [stylesReady, setStylesReady] = React.useState(false);
|
|
39
38
|
const ClientLazy = React.useMemo(() => createClientLazy(), [retryKey]);
|
|
40
|
-
const skeletonRootRef = React.useRef(null);
|
|
41
39
|
const { theme } = useTheme();
|
|
42
40
|
React.useEffect(() => {
|
|
43
41
|
setIsClient(true);
|
|
44
42
|
preloadPasskeyAuthMenu();
|
|
45
43
|
}, []);
|
|
46
|
-
React.useEffect(() => {
|
|
47
|
-
if (!isClient) return;
|
|
48
|
-
if (stylesReady) return;
|
|
49
|
-
if (typeof window === "undefined" || typeof requestAnimationFrame !== "function") {
|
|
50
|
-
setStylesReady(true);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
let cancelled = false;
|
|
54
|
-
const start = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
55
|
-
const maxWaitMs = 1500;
|
|
56
|
-
const tick = () => {
|
|
57
|
-
if (cancelled) return;
|
|
58
|
-
const el = skeletonRootRef.current;
|
|
59
|
-
if (el) try {
|
|
60
|
-
const cs = window.getComputedStyle(el);
|
|
61
|
-
const sentinelReady = cs.getPropertyValue("--w3a-pam2-css-ready").trim() === "1";
|
|
62
|
-
const borderOk = cs.borderTopStyle !== "none" && cs.borderTopWidth !== "0px";
|
|
63
|
-
const radiusOk = cs.borderTopLeftRadius !== "0px";
|
|
64
|
-
if (sentinelReady || borderOk || radiusOk) {
|
|
65
|
-
setStylesReady(true);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
} catch {}
|
|
69
|
-
const now = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
70
|
-
if (now - start >= maxWaitMs) {
|
|
71
|
-
setStylesReady(true);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
requestAnimationFrame(tick);
|
|
75
|
-
};
|
|
76
|
-
requestAnimationFrame(tick);
|
|
77
|
-
return () => {
|
|
78
|
-
cancelled = true;
|
|
79
|
-
};
|
|
80
|
-
}, [isClient, stylesReady]);
|
|
81
|
-
const skeletonWithRef = /* @__PURE__ */ jsx(PasskeyAuthMenuSkeletonInner, {
|
|
82
|
-
ref: skeletonRootRef,
|
|
83
|
-
className: props.className,
|
|
84
|
-
style: props.style
|
|
85
|
-
});
|
|
86
44
|
const skeleton = /* @__PURE__ */ jsx(PasskeyAuthMenuSkeletonInner, {
|
|
87
45
|
className: props.className,
|
|
88
46
|
style: props.style
|
|
89
47
|
});
|
|
90
48
|
return /* @__PURE__ */ jsx(PasskeyAuthMenuThemeScope, {
|
|
91
49
|
theme,
|
|
92
|
-
children: isClient
|
|
50
|
+
children: isClient ? /* @__PURE__ */ jsx(LazyErrorBoundary, {
|
|
93
51
|
onRetry: () => setRetryKey((k) => k + 1),
|
|
94
52
|
fallback: ({ retry }) => /* @__PURE__ */ jsxs("div", { children: [skeleton, /* @__PURE__ */ jsxs("div", {
|
|
95
53
|
style: {
|
|
@@ -113,7 +71,7 @@ const PasskeyAuthMenu = (props) => {
|
|
|
113
71
|
fallback: skeleton,
|
|
114
72
|
children: /* @__PURE__ */ jsx(ClientLazy, { ...props })
|
|
115
73
|
})
|
|
116
|
-
}) :
|
|
74
|
+
}) : skeleton
|
|
117
75
|
});
|
|
118
76
|
};
|
|
119
77
|
var shell_default = PasskeyAuthMenu;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell.js","names":["PasskeyAuthMenu: React.FC<PasskeyAuthMenuProps>"],"sources":["../../../../../src/react/components/PasskeyAuthMenu/shell.tsx"],"sourcesContent":["import React from 'react';\nimport { PasskeyAuthMenuSkeletonInner } from './skeleton';\nimport { PasskeyAuthMenuThemeScope } from './themeScope';\nimport type { PasskeyAuthMenuProps } from './types';\nimport { useTheme } from '../theme';\nimport { preloadPasskeyAuthMenu } from './preload';\n\nfunction createClientLazy() {\n return React.lazy(() => import('./client').then((m) => ({ default: m.PasskeyAuthMenuClient })));\n}\n\nclass LazyErrorBoundary extends React.Component<\n {\n fallback: (args: { error: Error; retry: () => void }) => React.ReactNode;\n onRetry: () => void;\n children: React.ReactNode;\n },\n { error: Error | null }\n> {\n state: { error: Error | null } = { error: null };\n\n static getDerivedStateFromError(error: Error): { error: Error } {\n return { error };\n }\n\n retry = () => {\n this.setState({ error: null });\n this.props.onRetry();\n };\n\n render() {\n if (this.state.error) {\n return this.props.fallback({ error: this.state.error, retry: this.retry });\n }\n return this.props.children;\n }\n}\n\n/**\n * `PasskeyAuthMenu` — SSR-safe shell.\n *\n * - Server: renders a skeleton only.\n * - Client: lazy-loads the full implementation after mount.\n */\nexport const PasskeyAuthMenu: React.FC<PasskeyAuthMenuProps> = (props) => {\n const [isClient, setIsClient] = React.useState(false);\n const [retryKey, setRetryKey] = React.useState(0);\n const
|
|
1
|
+
{"version":3,"file":"shell.js","names":["PasskeyAuthMenu: React.FC<PasskeyAuthMenuProps>"],"sources":["../../../../../src/react/components/PasskeyAuthMenu/shell.tsx"],"sourcesContent":["import React from 'react';\nimport { PasskeyAuthMenuSkeletonInner } from './skeleton';\nimport { PasskeyAuthMenuThemeScope } from './themeScope';\nimport type { PasskeyAuthMenuProps } from './types';\nimport { useTheme } from '../theme';\nimport { preloadPasskeyAuthMenu } from './preload';\n\nfunction createClientLazy() {\n return React.lazy(() => import('./client').then((m) => ({ default: m.PasskeyAuthMenuClient })));\n}\n\nclass LazyErrorBoundary extends React.Component<\n {\n fallback: (args: { error: Error; retry: () => void }) => React.ReactNode;\n onRetry: () => void;\n children: React.ReactNode;\n },\n { error: Error | null }\n> {\n state: { error: Error | null } = { error: null };\n\n static getDerivedStateFromError(error: Error): { error: Error } {\n return { error };\n }\n\n retry = () => {\n this.setState({ error: null });\n this.props.onRetry();\n };\n\n render() {\n if (this.state.error) {\n return this.props.fallback({ error: this.state.error, retry: this.retry });\n }\n return this.props.children;\n }\n}\n\n/**\n * `PasskeyAuthMenu` — SSR-safe shell.\n *\n * - Server: renders a skeleton only.\n * - Client: lazy-loads the full implementation after mount.\n */\nexport const PasskeyAuthMenu: React.FC<PasskeyAuthMenuProps> = (props) => {\n const [isClient, setIsClient] = React.useState(false);\n const [retryKey, setRetryKey] = React.useState(0);\n const ClientLazy = React.useMemo(() => createClientLazy(), [retryKey]);\n\n // Align with the SDK Theme boundary when present (TatchiPasskeyProvider wraps one by default).\n // Falls back to system preference when used standalone.\n const { theme } = useTheme();\n\n React.useEffect(() => {\n setIsClient(true);\n // Start fetching the client chunk immediately; the skeleton remains as the Suspense fallback.\n preloadPasskeyAuthMenu();\n }, []);\n\n const skeleton = (\n <PasskeyAuthMenuSkeletonInner className={props.className} style={props.style} />\n );\n\n return (\n <PasskeyAuthMenuThemeScope theme={theme}>\n {isClient ? (\n <LazyErrorBoundary\n onRetry={() => setRetryKey((k) => k + 1)}\n fallback={({ retry }) => (\n <div>\n {skeleton}\n <div style={{ marginTop: 10, fontSize: 12, textAlign: 'center', opacity: 0.9 }}>\n Failed to load menu.{' '}\n <button type=\"button\" onClick={retry} style={{ textDecoration: 'underline' }}>\n Retry\n </button>\n </div>\n </div>\n )}\n >\n <React.Suspense\n fallback={skeleton}\n >\n <ClientLazy {...props} />\n </React.Suspense>\n </LazyErrorBoundary>\n ) : (\n skeleton\n )}\n </PasskeyAuthMenuThemeScope>\n );\n};\n\nexport default PasskeyAuthMenu;\n"],"mappings":";;;;;;;;AAOA,SAAS,mBAAmB;AAC1B,QAAO,MAAM,WAAW,OAAO,eAAY,MAAM,OAAO,EAAE,SAAS,EAAE;;AAGvE,IAAM,oBAAN,cAAgC,MAAM,UAOpC;CACA,QAAiC,EAAE,OAAO;CAE1C,OAAO,yBAAyB,OAAgC;AAC9D,SAAO,EAAE;;CAGX,cAAc;AACZ,OAAK,SAAS,EAAE,OAAO;AACvB,OAAK,MAAM;;CAGb,SAAS;AACP,MAAI,KAAK,MAAM,MACb,QAAO,KAAK,MAAM,SAAS;GAAE,OAAO,KAAK,MAAM;GAAO,OAAO,KAAK;;AAEpE,SAAO,KAAK,MAAM;;;;;;;;;AAUtB,MAAaA,mBAAmD,UAAU;CACxE,MAAM,CAAC,UAAU,eAAe,MAAM,SAAS;CAC/C,MAAM,CAAC,UAAU,eAAe,MAAM,SAAS;CAC/C,MAAM,aAAa,MAAM,cAAc,oBAAoB,CAAC;CAI5D,MAAM,EAAE,UAAU;AAElB,OAAM,gBAAgB;AACpB,cAAY;AAEZ;IACC;CAEH,MAAM,WACJ,oBAAC;EAA6B,WAAW,MAAM;EAAW,OAAO,MAAM;;AAGzE,QACE,oBAAC;EAAiC;YAC/B,WACC,oBAAC;GACC,eAAe,aAAa,MAAM,IAAI;GACtC,WAAW,EAAE,YACX,qBAAC,oBACE,UACD,qBAAC;IAAI,OAAO;KAAE,WAAW;KAAI,UAAU;KAAI,WAAW;KAAU,SAAS;;;KAAO;KACzD;KACrB,oBAAC;MAAO,MAAK;MAAS,SAAS;MAAO,OAAO,EAAE,gBAAgB;gBAAe;;;;aAOpF,oBAAC,MAAM;IACL,UAAU;cAEV,oBAAC,cAAW,GAAI;;OAIpB;;;AAMR,oBAAe"}
|
|
@@ -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.
|
|
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.
|
|
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:
|
|
164
|
-
phase: RegistrationPhase.
|
|
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:
|
|
179
|
-
phase: RegistrationPhase.
|
|
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:
|
|
241
|
-
phase: RegistrationPhase.
|
|
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
|
-
|
|
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) {
|
|
@@ -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.
|
|
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,
|