> ## Documentation Index
> Fetch the complete documentation index at: https://docs-platform.services-valid.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting

> Tratamento de erros e boas práticas para o Valid Liveness SDK

## Tipos de Erro

O SDK categoriza erros em tipos específicos para facilitar o tratamento:

```typescript theme={"theme":"catppuccin-latte"}
enum LivenessErrorType {
  INITIALIZATION_FAILED = 'INITIALIZATION_FAILED',       // Falha na inicialização
  SESSION_FAILED = 'SESSION_FAILED',                     // Falha ao criar sessão ou sessão expirada
  CAPTURE_FAILED = 'CAPTURE_FAILED',                     // Falha na captura
  LIVENESS_VALIDATION_FAILED = 'LIVENESS_VALIDATION_FAILED', // Reprovado na validação de vivacidade
  SUBMISSION_FAILED = 'SUBMISSION_FAILED',               // Falha no envio ao backend
  CAMERA_PERMISSION_DENIED = 'CAMERA_PERMISSION_DENIED', // Permissão de câmera negada
  CAMERA_INJECTION_DETECTED = 'CAMERA_INJECTION_DETECTED', // Injeção de câmera virtual detectada
  USER_CANCELLED = 'USER_CANCELLED',                     // Usuário cancelou
  NETWORK_ERROR = 'NETWORK_ERROR',                       // Erro de rede
  UNKNOWN_ERROR = 'UNKNOWN_ERROR',                       // Erro desconhecido
}
```

### Estrutura do Erro

```typescript theme={"theme":"catppuccin-latte"}
interface LivenessFailureError {
  type: LivenessErrorType; // Tipo do erro
  failureReason?: string;  // Descrição detalhada (opcional)
}
```

## Tratamento de Erros

### Usando Callback

```javascript theme={"theme":"catppuccin-latte"}
const config = {
  // ... outras configurações

  onFailure: (error) => {
    switch (error.type) {
      case 'CAMERA_PERMISSION_DENIED':
        mostrarMensagem(
          'Por favor, permita o acesso à câmera nas configurações do navegador.'
        );
        break;

      case 'CAMERA_INJECTION_DETECTED':
        mostrarMensagem(
          'Detectamos um problema com a câmera. Por favor, desative softwares de câmera virtual.'
        );
        break;

      case 'NETWORK_ERROR':
        mostrarMensagem(
          'Erro de conexão. Verifique sua internet e tente novamente.'
        );
        break;

      case 'SESSION_FAILED':
        mostrarMensagem(
          'Não foi possível iniciar a sessão. Tente novamente em alguns instantes.'
        );
        break;

      case 'LIVENESS_VALIDATION_FAILED':
        mostrarMensagem(
          'A verificação de vivacidade não foi aprovada. Tente novamente seguindo as instruções.'
        );
        break;

      case 'CAPTURE_FAILED':
        mostrarMensagem(
          'Falha na captura: ' + (error.failureReason || 'Tente novamente')
        );
        break;

      case 'USER_CANCELLED':
        mostrarMensagem('Verificação cancelada pelo usuário.');
        break;

      default:
        mostrarMensagem('Ocorreu um erro inesperado. Tente novamente.');
        console.error('Erro:', error);
    }
  },
};
```

### Usando try/catch

```javascript theme={"theme":"catppuccin-latte"}
try {
  const result = await hub.run(config);
  processarResultado(result);
} catch (error) {
  if (error.type) {
    // Erro tipado do SDK
    tratarErroLiveness(error);
  } else {
    // Erro genérico
    console.error('Erro inesperado:', error);
  }
}
```

## Mensagens Amigáveis

Converta erros técnicos em mensagens compreensíveis para o usuário:

```javascript theme={"theme":"catppuccin-latte"}
function getMensagemAmigavel(error) {
  const mensagens = {
    CAMERA_PERMISSION_DENIED: {
      titulo: 'Acesso à Câmera Necessário',
      mensagem:
        'Para continuar, permita o acesso à câmera nas configurações do seu navegador.',
      acao: 'Verificar Permissões',
    },
    CAMERA_INJECTION_DETECTED: {
      titulo: 'Câmera Virtual Detectada',
      mensagem:
        'Detectamos um software de câmera virtual. Por favor, desative-o e use sua câmera real.',
      acao: 'Tentar Novamente',
    },
    NETWORK_ERROR: {
      titulo: 'Problema de Conexão',
      mensagem:
        'Não foi possível conectar ao servidor. Verifique sua internet.',
      acao: 'Tentar Novamente',
    },
    SESSION_FAILED: {
      titulo: 'Falha na Sessão',
      mensagem: 'A sessão expirou ou não pôde ser criada. Por favor, inicie novamente.',
      acao: 'Reiniciar',
    },
    LIVENESS_VALIDATION_FAILED: {
      titulo: 'Verificação Não Aprovada',
      mensagem:
        'A verificação de vivacidade não foi aprovada. Siga as instruções na tela e tente novamente.',
      acao: 'Tentar Novamente',
    },
    CAPTURE_FAILED: {
      titulo: 'Falha na Captura',
      mensagem:
        'Não conseguimos capturar sua biometria. Tente novamente com boa iluminação.',
      acao: 'Tentar Novamente',
    },
    SUBMISSION_FAILED: {
      titulo: 'Falha no Envio',
      mensagem:
        'Não foi possível enviar os dados. Verifique sua conexão e tente novamente.',
      acao: 'Tentar Novamente',
    },
    USER_CANCELLED: {
      titulo: 'Verificação Cancelada',
      mensagem: 'Você cancelou a verificação.',
      acao: 'Reiniciar',
    },
  };

  return (
    mensagens[error.type] || {
      titulo: 'Erro Inesperado',
      mensagem: 'Ocorreu um problema. Por favor, tente novamente.',
      acao: 'Tentar Novamente',
    }
  );
}
```

## Content Security Policy (CSP)

Se a sua aplicação utiliza Content Security Policy, você precisará permitir as seguintes origens para que o SDK funcione corretamente:

```text theme={"theme":"catppuccin-latte"}
script-src 'self' https://storage.googleapis.com/hub-sdk-cdn/;
connect-src 'self' https://hub-liveness-service.app https://*.facetec.com;
img-src 'self' blob: data:;
media-src 'self' blob:;
worker-src 'self' blob:;
```

| Diretiva      | Origem                                                                        | Motivo                                                        |
| ------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------- |
| `script-src`  | `https://storage.googleapis.com/hub-sdk-cdn/`                                 | CDN do SDK                                                    |
| `connect-src` | `https://hub-liveness-service.app` `https://hml-api.hub-liveness-service.app` | Comunicação com a API de liveness (URLs gerenciadas pelo SDK) |
| `connect-src` | `https://*.facetec.com`                                                       | Recursos do motor FaceTec (quando utilizado)                  |
| `img-src`     | `blob:` `data:`                                                               | Imagens capturadas pela câmera e assets em base64             |
| `media-src`   | `blob:`                                                                       | Stream de vídeo da câmera                                     |
| `worker-src`  | `blob:`                                                                       | Web Workers usados internamente pelo SDK                      |

<Warning>
  As origens exatas podem variar dependendo do motor biométrico selecionado (FaceSDK,
  FaceTec ou Innovatrics). Em caso de erros de CSP no console, adicione as origens
  bloqueadas à sua política.
</Warning>

## Boas Práticas

### Segurança

<CardGroup cols={2}>
  <Card title="API Key" icon="key">
    Nunca exponha a API Key no código frontend em produção. Use variáveis de
    ambiente ou carregue de um endpoint seguro.
  </Card>

  <Card title="Arquivo CEK" icon="file-shield">
    Mantenha o CEK em um endpoint com autenticação. Considere carregá-lo
    dinamicamente quando necessário.
  </Card>

  <Card title="HTTPS" icon="lock">
    O SDK requer conexão segura em produção. A API `getUserMedia` só funciona em
    contextos seguros (HTTPS ou `localhost`).
  </Card>

  <Card title="Validação" icon="shield-check">
    Valide os resultados no seu backend antes de confiar neles.
  </Card>
</CardGroup>

### Performance

<Steps>
  <Step title="Pré-carregue o CEK">
    Carregue o CEK antes do usuário iniciar a verificação para evitar delays.
  </Step>

  <Step title="Container com dimensões fixas">
    Defina dimensões fixas no container para evitar reflows durante a
    renderização.
  </Step>

  <Step title="Cleanup na API Avançada">
    Se estiver usando a API Avançada (`init` / `startLivenessCheck` / `teardown`),
    sempre chame `teardown()` em um bloco `finally`. Na API Simples (`run()`),
    o cleanup é automático.
  </Step>
</Steps>

<CodeGroup>
  ```javascript API Simples theme={"theme":"catppuccin-latte"}
  // Cleanup automático, sem necessidade de teardown
  const hub = ValidHub.createHub();

  try {
    const result = await hub.run(config);
    // processar resultado
  } catch (error) {
    // tratar erro
  }
  ```

  ```javascript API Avançada theme={"theme":"catppuccin-latte"}
  // Teardown obrigatório
  const hub = ValidHub.createHub();

  try {
    await hub.init(config);
    const result = await hub.startLivenessCheck();
    // processar resultado
  } finally {
    await hub.teardown();
  }
  ```
</CodeGroup>

### Experiência do Usuário

<CardGroup cols={2}>
  <Card title="Feedback Visual" icon="spinner">
    Use os callbacks `onProgress` para mostrar feedback ao usuário durante cada
    etapa.
  </Card>

  <Card title="Mensagens Claras" icon="comment">
    Traduza os erros técnicos em mensagens compreensíveis para o usuário final.
  </Card>

  <Card title="Instruções Claras" icon="info">
    Personalize as instruções para seu público-alvo usando `hubOptions.strings`.
  </Card>

  <Card title="Ambiente Adequado" icon="lightbulb">
    Oriente o usuário sobre iluminação e posicionamento antes de iniciar a
    verificação.
  </Card>
</CardGroup>

## Integração com Frameworks

### Serviço Reutilizável

```javascript theme={"theme":"catppuccin-latte"}
// livenessService.js
class LivenessService {
  constructor(config) {
    this.config = config;
    this.hub = null;
  }

  async carregarCEK(cekUrl) {
    const response = await fetch(cekUrl);
    if (!response.ok) {
      throw new Error('Falha ao carregar CEK');
    }
    return await response.json();
  }

  async verificar(options = {}) {
    if (typeof ValidHub === 'undefined') {
      throw new Error('SDK não carregado');
    }

    const cekData = await this.carregarCEK(this.config.cekUrl);
    this.hub = ValidHub.createHub();

    const hubConfig = {
      apiKey: this.config.apiKey,
      cek: cekData,
      mount: options.container || this.config.defaultContainer,
      env: this.config.env,
      appName: this.config.appName,
      risk: options.risk || 'LIVENESS_RISK_HIGH',
      hubOptions: options.hubOptions,
      onProgress: options.onProgress,
      onSuccess: options.onSuccess,
      onFailure: options.onFailure,
    };

    try {
      const result = await this.hub.run(hubConfig);
      return result;
    } finally {
      this.hub = null;
    }
  }

  async cancelar() {
    if (this.hub) {
      await this.hub.teardown();
      this.hub = null;
    }
  }
}

// Uso
const livenessService = new LivenessService({
  apiKey: 'sua-api-key',
  cekUrl: '/config/production.cek.json',
  env: 'production',
  appName: 'minha-aplicacao',
  defaultContainer: '#camera-container',
});

async function handleVerificacao() {
  try {
    const result = await livenessService.verificar({
      risk: 'LIVENESS_RISK_HIGH',
      hubOptions: {
        locale: 'pt-BR',
        colorTheme: { primaryColor: '#0066cc' },
      },
      onProgress: (state) => atualizarUI(state),
    });

    await enviarResultadoParaBackend(result);
  } catch (error) {
    tratarErro(error);
  }
}
```

## Checklist de Verificação

Antes de reportar um problema, verifique os itens abaixo:

<Steps>
  <Step title="SDK Carregado">
    Confirme que o script do SDK foi carregado corretamente (`ValidHub` está
    disponível globalmente).
  </Step>

  <Step title="HTTPS">
    A página está sendo servida via HTTPS (obrigatório para acesso à câmera).
    Em desenvolvimento, `localhost` é aceito.
  </Step>

  <Step title="Navegador Compatível">
    Verifique se o navegador suporta WebCrypto API e `getUserMedia`
    (Chrome 60+, Firefox 55+, Safari 14.1+, Edge 79+).
  </Step>

  <Step title="CEK Válido">O CEK está acessível e não expirou.</Step>
  <Step title="Credenciais">API Key está correta e o ambiente (`env`) está configurado corretamente.</Step>

  <Step title="Container">
    O elemento container existe no DOM antes de chamar `hub.run()`.
  </Step>

  <Step title="Permissões">
    O navegador tem permissão para acessar a câmera.
  </Step>

  <Step title="CSP">
    Se a sua aplicação usa Content Security Policy, verifique se as origens
    necessárias estão permitidas (veja seção CSP acima).
  </Step>
</Steps>

## Referências

<CardGroup cols={2}>
  <Card title="Instalação" icon="download" href="/plataforma/liveness/hub/sdk/web/installation">
    Revise os requisitos e configurações
  </Card>

  <Card title="Implementação" icon="code" href="/plataforma/liveness/hub/sdk/web/implementation">
    Veja exemplos de código
  </Card>
</CardGroup>
