# Event System

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

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/react'

// Subscribe to an event
openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, (authResponse) => {
  console.log('User authenticated:', authResponse.player.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' | 'phone' | 'oauth' | 'siwe' | 'idToken' | 'guest'
  provider?: string  // OAuth provider name (e.g., '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 access tokens.

**Payload:**

```typescript
type AuthResponse = {
  player: AuthPlayerResponse
  token: string
  refreshToken: string
}

type AuthPlayerResponse = {
  id: string
  object: 'player'
  createdAt: number
  linkedAccounts: LinkedAccountResponse[]
  player?: {
    id: string
    name: string
    description?: string
    metadata?: Record<string, any>
    accounts?: Array<{
      id: string
      address: string
      chainId: number
      // ... more account fields
    }>
  }
}
```

**Example:**

```typescript
openfortEvents.on(OpenfortEvents.ON_AUTH_SUCCESS, (authResponse) => {
  console.log('User authenticated successfully!')
  console.log('Player ID:', authResponse.player.id)
  console.log('Linked accounts:', authResponse.player.linkedAccounts)

  // Navigate to dashboard, update UI, etc.
  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 password) is requested for login.

**Payload:**

```typescript
{
  method: 'email' | 'phone'
  provider?: string
}
```

**Example:**

```typescript
openfortEvents.on(OpenfortEvents.ON_OTP_REQUEST, (payload) => {
  console.log(`OTP requested via ${payload.method}`)
  // Show OTP input screen, start countdown timer, etc.
})
```

**Use Cases:**

* Show OTP input UI at the right moment
* Start a countdown timer for resend
* Track OTP request analytics

***

### `ON_OTP_FAILURE`

Called when an OTP request fails to send.

**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 verification code. Please try again.')
})
```

**Use Cases:**

* Display error message when OTP delivery fails
* Offer retry option
* Track delivery failures

***

## Wallet Events

### `ON_EMBEDDED_WALLET_CREATED`

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

**Payload:**

```typescript
type EmbeddedAccount = {
  id: string
  user: string
  address: string
  chainId?: number        // EVM only
  cluster?: string        // SVM only ('devnet')
  chainType: 'EVM' | 'SVM'
  accountType: 'Externally Owned Account' | 'Smart Account'
  ownerAddress?: string
  implementationType?: 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 type:', wallet.chainType)
  if (wallet.chainType === 'EVM') {
    console.log('Chain ID:', wallet.chainId)
  } else {
    console.log('Cluster:', wallet.cluster)
  }
  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.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/react'
```

The `OpenfortEventMap` provides the complete type mapping:

```typescript
interface OpenfortEventMap {
  [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]
  [OpenfortEvents.ON_OTP_REQUEST]: [{ method: 'email' | 'phone'; provider?: string }]
  [OpenfortEvents.ON_OTP_FAILURE]: [Error]
}
```

## 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', {
    player_id: auth.player.id,
    linked_accounts: auth.player.linkedAccounts.length,
  })
})

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.player)

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

### 5. Type Your Event Handlers

Use proper TypeScript types for type safety:

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

const handleAuthSuccess = (auth: AuthResponse) => {
  console.log(auth.player.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/react`
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
