# Openfort SDK events

The Openfort SDK provides an event system that allows you to monitor and respond to authentication, wallet, and UI lifecycle events in your application.

## Event system overview

The SDK uses a typed event emitter that you can access via the `openfortEvents` export. All events are strongly typed and provide detailed payload information.

```typescript
import { openfortEvents, OpenfortEvents } from '@openfort/openfort-js'

// Subscribe to an event
openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, (authResponse) => {
  console.log('User authenticated:', authResponse.user.id)
})

// Remove a specific listener
const handler = (authResponse) => console.log('Auth success')
openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, handler)
openfortEvents.off(OpenfortEvents.ON_AUTH_SUCCESS, handler)

// Remove all listeners for an event
openfortEvents.removeAllListeners(OpenfortEvents.ON_AUTH_SUCCESS)
```

## Authentication events

### `ON_AUTH_INIT`

Called when an authentication process begins, before the user completes authentication.

**Payload:**

```typescript
type AuthInitPayload = {
  method: 'email' | 'oauth' | 'siwe' | 'idToken' | 'guest' | 'phone'
  provider?: string  // OAuth provider name (for example, 'google', 'discord')
}
```

**Example:**

```typescript
openfortEvents.on(OpenfortEvents.ON_AUTH_INIT, (payload) => {
  console.log(`Authentication started with ${payload.method}`)
  if (payload.provider) {
    console.log(`Using provider: ${payload.provider}`)
  }
  // Show loading indicator, track analytics, etc.
})
```

**Use cases:**

* Display loading states
* Track authentication attempts in analytics
* Log authentication method usage

***

### `ON_AUTH_SUCCESS`

Called after the user successfully authenticates and receives a session token.

**Payload:**

```typescript
type AuthResponse = {
  token: string | null    // Session token for authentication
  user: User              // User profile information
  session?: Session       // Optional session details
}

type User = {
  id: string                   // Unique user identifier
  email?: string               // User's email address
  name?: string                // User's display name
  image?: string               // URL to user's profile image
  emailVerified?: boolean      // Whether email has been verified
  createdAt?: string           // ISO timestamp when created
  updatedAt?: string           // ISO timestamp when last updated
  isAnonymous?: boolean        // Whether user is anonymous (guest)
  phoneNumber?: string         // User's phone number
  phoneNumberVerified?: boolean // Whether phone has been verified
  linkedAccounts?: UserAccount[] // Linked authentication accounts
}
```

**Example:**

```typescript
openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, (authResponse) => {
  console.log('User authenticated successfully!')
  console.log('User ID:', authResponse.user.id)
  console.log('Email:', authResponse.user.email)

  router.push('/dashboard')
})
```

**Use cases:**

* Navigate user to authenticated area
* Store user preferences
* Initialize user-specific features
* Track successful authentication in analytics

***

### `ON_AUTH_FAILURE`

Called when authentication fails due to an error.

**Payload:**

```typescript
Error  // Standard JavaScript Error object
```

**Example:**

```typescript
openfortEvents.on(OpenfortEvents.ON_AUTH_FAILURE, (error) => {
  console.error('Authentication failed:', error.message)

  // Show error message to user
  toast.error(`Failed to authenticate: ${error.message}`)

  // Track error in monitoring
  Sentry.captureException(error)
})
```

**Use cases:**

* Display error messages to users
* Log authentication errors
* Retry authentication logic
* Error tracking and monitoring

***

### `ON_LOGOUT`

Called after the user successfully logs out.

**Payload:** None

**Example:**

```typescript
openfortEvents.on(OpenfortEvents.ON_LOGOUT, () => {
  console.log('User logged out')

  // Clear local state, navigate to login, etc.
  localStorage.clear()
  router.push('/login')
})
```

**Use cases:**

* Clear local application state
* Navigate to login page
* Reset UI components
* Clear sensitive data from memory

***

### `ON_OTP_REQUEST`

Called when an OTP (one-time passcode) is requested for email or phone authentication.

**Payload:**

```typescript
{
  method: 'email' | 'phone'
  provider?: string  // For phone OTP, this is 'phone'
}
```

**Example:**

```typescript
openfortEvents.on(OpenfortEvents.ON_OTP_REQUEST, (payload) => {
  console.log(`OTP requested via ${payload.method}`)

  // Show OTP input form
  showOtpInputForm()
})
```

**Use cases:**

* Display OTP input form
* Start countdown timer for resend
* Track OTP request attempts

***

### `ON_OTP_FAILURE`

Called when an OTP request fails.

**Payload:**

```typescript
Error  // Standard JavaScript Error object
```

**Example:**

```typescript
openfortEvents.on(OpenfortEvents.ON_OTP_FAILURE, (error) => {
  console.error('OTP request failed:', error.message)

  toast.error('Failed to send OTP. Please try again.')
})
```

**Use cases:**

* Display error messages
* Handle rate limiting
* Retry OTP request

***

## Wallet events

### `ON_EMBEDDED_WALLET_CREATED`

Called after a new embedded wallet is created for the user.

**Payload:**

```typescript
type EmbeddedAccount = {
  id: string
  address: string
  chainId?: number
  chainType: 'EVM' | 'SVM'
  accountType: 'Externally Owned Account' | 'Smart Account' | 'Delegated Account'
  ownerAddress?: string
  implementationType?: string
  implementationAddress?: string
  factoryAddress?: string
  salt?: string
  createdAt?: number
  recoveryMethod?: 'password' | 'automatic' | 'passkey'
  recoveryMethodDetails?: {
    passkeyId?: string
    passkeyEnv?: {
      name?: string
      os?: string
      osVersion?: string
      device?: string
    }
  }
}
```

**Example:**

```typescript
openfortEvents.on(OpenfortEvents.ON_EMBEDDED_WALLET_CREATED, (wallet) => {
  console.log('New wallet created!')
  console.log('Address:', wallet.address)
  console.log('Chain ID:', wallet.chainId)
  console.log('Account type:', wallet.accountType)
  console.log('Recovery method:', wallet.recoveryMethod)

  // Display wallet address to user
  setWalletAddress(wallet.address)

  // Track wallet creation
  analytics.track('wallet_created', {
    chainType: wallet.chainType,
    accountType: wallet.accountType,
  })
})
```

**Use cases:**

* Display new wallet information
* Store wallet address in UI state
* Track wallet creation metrics
* Initialize wallet-dependent features

***

### `ON_EMBEDDED_WALLET_RECOVERED`

Called when an existing embedded wallet is recovered.

**Payload:**

```typescript
type EmbeddedAccount = {
  // Same structure as ON_EMBEDDED_WALLET_CREATED
}
```

**Example:**

```typescript
openfortEvents.on(OpenfortEvents.ON_EMBEDDED_WALLET_RECOVERED, (wallet) => {
  console.log('Wallet recovered!')
  console.log('Address:', wallet.address)
  console.log('Recovery method used:', wallet.recoveryMethod)

  // Update UI with recovered wallet
  setWalletAddress(wallet.address)

  // Track recovery
  analytics.track('wallet_recovered', {
    recoveryMethod: wallet.recoveryMethod,
  })
})
```

**Use cases:**

* Display recovered wallet information
* Track successful wallet recovery
* Verify recovery method
* Resume wallet operations

***

### `ON_SWITCH_ACCOUNT`

Called when switching between different accounts or chains.

**Payload:**

```typescript
string  // The new account address
```

**Example:**

```typescript
openfortEvents.on(OpenfortEvents.ON_SWITCH_ACCOUNT, (address) => {
  console.log('Switched to account:', address)

  // Update UI with new account
  setCurrentAccount(address)

  // Refresh account balance
  fetchBalance(address)

  // Update chain-specific components
  updateChainInfo()
})
```

**Use cases:**

* Update UI when user switches accounts
* Refresh account-specific data
* Update balance displays
* Sync with blockchain state

***

### `ON_SIGNED_MESSAGE`

Called whenever the wallet signs a message. This includes:

* Personal message signing (`signMessage`)
* Typed data signing (`signTypedData` / EIP-712)
* Transaction signatures
* Session key signatures
* Internal signing operations

**Payload:**

```typescript
type SignedMessagePayload = {
  message: string | Uint8Array  // The message that was signed
  signature: string              // The resulting signature (hex string)
}
```

**Example:**

```typescript
openfortEvents.on(OpenfortEvents.ON_SIGNED_MESSAGE, (payload) => {
  console.log('Message signed!')
  console.log('Message:', payload.message)
  console.log('Signature:', payload.signature)

  // Track signing activity
  analytics.track('message_signed', {
    messageLength: typeof payload.message === 'string'
      ? payload.message.length
      : payload.message.length,
  })

  // Store signature for later use
  saveSignature(payload.signature)

  // Show success notification
  toast.success('Message signed successfully!')
})
```

**Use cases:**

* Track all signing operations
* Audit trail for signatures
* Display signing confirmations
* Monitor transaction signing
* Debug signing issues
* Implement custom signing workflows

**Note:** This event is emitted for ALL signing operations, including:

* Manual `openfort.embeddedWallet.signMessage()` calls
* EIP-712 typed data signing
* Smart account user operation signatures
* EOA transaction signatures
* Session key registration/revocation signatures

## TypeScript types

All events are fully typed. Import the types you need:

```typescript
import type {
  OpenfortEvents,
  OpenfortEventMap,
  AuthInitPayload,
  AuthResponse,
  EmbeddedAccount,
  SignedMessagePayload,
} from '@openfort/openfort-js'
```

The `OpenfortEventMap` provides the complete type mapping. It extends `Record<string, any>`, meaning the event emitter also accepts custom event names beyond those listed below:

```typescript
interface OpenfortEventMap extends Record<string, any> {
  [OpenfortEvents.ON_AUTH_INIT]: [AuthInitPayload]
  [OpenfortEvents.ON_AUTH_SUCCESS]: [AuthResponse]
  [OpenfortEvents.ON_AUTH_FAILURE]: [Error]
  [OpenfortEvents.ON_LOGOUT]: []
  [OpenfortEvents.ON_SWITCH_ACCOUNT]: [string]
  [OpenfortEvents.ON_SIGNED_MESSAGE]: [SignedMessagePayload]
  [OpenfortEvents.ON_EMBEDDED_WALLET_CREATED]: [EmbeddedAccount]
  [OpenfortEvents.ON_EMBEDDED_WALLET_RECOVERED]: [EmbeddedAccount]
}
```

:::info
`ON_OTP_REQUEST` and `ON_OTP_FAILURE` are available as event names in `OpenfortEvents` but are not typed in `OpenfortEventMap`. You can still listen to them, but payloads will be untyped.
:::

## Best practices

### 1. Always clean up listeners

Remove event listeners when components unmount to prevent memory leaks:

```typescript
useEffect(() => {
  const handler = (data) => console.log(data)
  openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, handler)

  return () => {
    openfortEvents.off(OpenfortEvents.ON_AUTH_SUCCESS, handler)
  }
}, [])
```

### 2. Handle errors gracefully

Always handle the `ON_AUTH_FAILURE` event to provide user feedback:

```typescript
openfortEvents.on(OpenfortEvents.ON_AUTH_FAILURE, (error) => {
  // Show user-friendly error message
  toast.error(getUserFriendlyError(error))

  // Log for debugging
  console.error('Auth error:', error)

  // Track in error monitoring
  Sentry.captureException(error)
})
```

### 3. Use events for analytics

Events are perfect for tracking user behavior:

```typescript
openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, (auth) => {
  analytics.track('user_authenticated', {
    user_id: auth.user.id,
    is_anonymous: auth.user.isAnonymous,
  })
})

openfortEvents.on(OpenfortEvents.ON_SIGNED_MESSAGE, () => {
  analytics.track('message_signed')
})
```

### 4. Avoid heavy operations in event handlers

Keep event handlers lightweight and asynchronous when needed:

```typescript
openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, async (auth) => {
  // Good: Non-blocking UI update
  setUser(auth.user)

  // Good: Async heavy operation doesn't block
  fetchUserData(auth.user.id).catch(console.error)
})
```

### 5. Type your event handlers

Use proper TypeScript types for type safety:

```typescript
import type { AuthResponse, EmbeddedAccount } from '@openfort/openfort-js'

const handleAuthSuccess = (auth: AuthResponse) => {
  console.log(auth.user.id) // Fully typed!
}

const handleWalletCreated = (wallet: EmbeddedAccount) => {
  console.log(wallet.address) // Fully typed!
}

openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, handleAuthSuccess)
openfortEvents.on(OpenfortEvents.ON_EMBEDDED_WALLET_CREATED, handleWalletCreated)
```

## Troubleshooting

### Events not firing

1. **Check listener registration**: Ensure listeners are registered before triggering actions
2. **Verify imports**: Make sure you're importing from `@openfort/openfort-js`
3. **Check cleanup**: Ensure you're not removing listeners prematurely

### Memory leaks

If you notice memory issues:

1. Always clean up listeners in useEffect cleanup or componentWillUnmount
2. Use `removeAllListeners` for the specific event, not globally
3. Consider using weak references for long-lived listeners
