# Referencia de la API para desarrolladores

Verité expone una API pública de Java estable bajo el paquete `teacommontea.api`. Cada subsistema es una fachada de métodos estáticos sobre tipos públicos estables, así que puedes hacer todo lo que hace el plugin sin referenciar nunca una clase de implementación interna.

Esta página es la superficie completa, organizada para su consulta. Dos temas tienen sus propias guías dedicadas y aquí solo se enlazan de forma cruzada:

- El filtro de chat: [Integración de chat personalizado](page:developers/wiring).
- Aplicación de mutes, modo lento y congelación: [Aplicación de moderación personalizada](page:developers/moderation-enforcement).

## Primeros pasos

### Añade Verité como dependencia opcional

Añade Verité a tu `plugin.yml` para que se cargue antes que tu plugin cuando esté instalado, sin volverse obligatorio:

```yaml
softdepend:
  - Verite
```

### Protege ante la disponibilidad

Si Verité es opcional, comprueba una clase antes de tocar la API:

```java
private static final boolean VERITE_AVAILABLE;

static {
    boolean available;
    try {
        Class.forName("teacommontea.api.VeriteAPI");
        available = true;
    } catch (ClassNotFoundException ignored) {
        available = false;
    }
    VERITE_AVAILABLE = available;
}
```

Cada subsistema también se degrada por su cuenta: cuando el módulo de respaldo está desactivado, los métodos de consulta devuelven `null`, `false` o una colección vacía, las llamadas de mutación se convierten en no-ops, y las llamadas de emisión devuelven un resultado fallido. Rara vez tienes que tratar como caso especial un módulo desactivado.

## VeriteAPI

`VeriteAPI` es el punto de entrada paraguas único. Informa la versión de la API, informa qué módulos están activados y devuelve la clase de cada subsistema para su descubrimiento.

| Miembro | Devuelve | Significado |
| --- | --- | --- |
| `VeriteAPI.VERSION` | `String` | La cadena de versión de la API. |
| `moderationEnabled()` | `boolean` | Si el módulo de moderación está cargado. |
| `vanishEnabled()` | `boolean` | Si el módulo de vanish está cargado. |
| `captchaEnabled()` | `boolean` | Si el módulo de captcha está cargado. |
| `moderation()` | `Class<VeriteModeration>` | La clase del subsistema de moderación. |
| `playerData()` | `Class<VeritePlayerData>` | La clase del subsistema de datos de jugador. |
| `store()` | `Class<VeriteStore>` | La clase del subsistema de almacenamiento. |
| `vanish()` | `Class<VeriteVanish>` | La clase del subsistema de vanish. |
| `captcha()` | `Class<VeriteCaptcha>` | La clase del subsistema de captcha. |
| `filter()` | `Class<VeriteFilter>` | La clase del subsistema del filtro de chat. |
| `text()` | `Class<VeriteText>` | La clase del subsistema de formato de texto. |

Todos los subsistemas son fachadas estáticas, así que los llamas directamente (por ejemplo `VeriteModeration.isBanned(uuid)`). Los métodos de acceso existen para el descubrimiento y las comprobaciones centralizadas de activación.

## VeriteModeration

El punto de entrada completo para emitir, consultar y levantar castigos. `durationMillis` usa `Punishment.PERMANENT` para un castigo permanente. Los métodos de puerta devuelven `true` cuando detuvieron al jugador. Consulta [Aplicación de moderación personalizada](page:developers/moderation-enforcement) para conocer en profundidad el flujo de trabajo de puertas y listeners.

### Estado y consultas

| Método | Devuelve | Significado |
| --- | --- | --- |
| `enabled()` | `boolean` | Si el módulo de moderación está cargado. |
| `isBanned(UUID player)` | `boolean` | Si el jugador tiene un baneo activo. |
| `isMuted(UUID player)` | `boolean` | Si el jugador tiene un muteo activo. |
| `activeBan(UUID player)` | `Punishment` | El baneo activo, o `null`. |
| `activeMute(UUID player)` | `Punishment` | El muteo activo, o `null`. |
| `history(UUID player, int limit)` | `List<Punishment>` | Historial de castigos reciente del jugador. |
| `byIp(String ip, int limit)` | `List<Punishment>` | Castigos registrados contra una ip. |
| `byStaff(UUID staff, int limit)` | `List<Punishment>` | Castigos emitidos por un miembro del personal. |
| `activeWarnings(UUID player)` | `List<Punishment>` | Advertencias actualmente activas del jugador. |
| `activePunishments()` | `List<ActivePunishment>` | Punteros ligeros a cada castigo activo. |
| `activeOfType(PunishmentType type, long now)` | `List<Punishment>` | Castigos activos de un tipo en un momento dado. |
| `loadPunishment(long id)` | `Punishment` | El registro completo de un id numérico, o `null`. |
| `altsOf(UUID player)` | `List<UUID>` | Cuentas que comparten la primera ip conocida del jugador. |
| `pruneHistory(UUID player, long cutoff, long now)` | `int` | Elimina el historial más antiguo que el corte, devuelve la cantidad eliminada. |
| `warningExpire()` | `long` | La ventana de caducidad de advertencias en milisegundos. |

### Emisión de castigos

| Método | Devuelve |
| --- | --- |
| `ban(UUID target, String targetName, String reason, UUID executor, String executorName, long durationMillis, boolean silent)` | `PunishmentResult` |
| `mute(UUID target, String targetName, String reason, UUID executor, String executorName, long durationMillis, boolean silent)` | `PunishmentResult` |
| `ipban(UUID target, String ip, String targetName, String reason, UUID executor, String executorName, long durationMillis, boolean silent)` | `PunishmentResult` |
| `ipmute(UUID target, String ip, String targetName, String reason, UUID executor, String executorName, long durationMillis, boolean silent)` | `PunishmentResult` |
| `warn(UUID target, String targetName, String reason, UUID executor, String executorName, boolean silent)` | `PunishmentResult` |
| `kick(UUID target, String targetName, String reason, UUID executor, String executorName, boolean silent)` | `PunishmentResult` |

### Levantamiento de castigos

| Método | Devuelve | Significado |
| --- | --- | --- |
| `unban(UUID target, String targetName, UUID remover, String removerName, String reason)` | `boolean` | Levanta el baneo activo, `true` si tiene éxito. |
| `unmute(UUID target, String targetName, UUID remover, String removerName, String reason)` | `boolean` | Levanta el muteo activo, `true` si tiene éxito. |
| `unwarn(UUID target, String targetName, UUID removedBy, String removedByName, String reason)` | `PunishmentResult` | Elimina una advertencia. |

### Renderizado y avisos

| Método | Devuelve | Significado |
| --- | --- | --- |
| `banScreen(Punishment ban)` | `String` | La pantalla de baneo completa de un registro de baneo. |
| `muteLine(Punishment mute)` | `String` | El resumen de muteo de una línea. |
| `muteNotice(Punishment mute)` | `String` | El aviso de muteo enviado a un jugador muteado. |

### Puertas de chat

Cada puerta devuelve `true` cuando el jugador debe ser detenido y le envía el motivo como efecto secundario. Úsalas donde tengas intención de aplicar la norma.

| Método | Devuelve | Significado |
| --- | --- | --- |
| `muteGate(Player p)` | `boolean` | El jugador está muteado; envía el aviso de muteo. |
| `chatMuteGate(Player p)` | `boolean` | La congelación global del chat está activa; envía el aviso de congelación. |
| `slowmodeGate(Player p)` | `boolean` | El jugador está retenido por el modo lento; envía la espera restante. |

### Comandos de chat

Estos accionan los propios comandos de chat del plugin para un `CommandSender`.

| Método | Significado |
| --- | --- |
| `broadcast(CommandSender sender, String[] args)` | Envía una difusión. |
| `chatClear(CommandSender sender)` | Limpia el chat. |
| `chatMute(CommandSender sender)` | Alterna la congelación global del chat. |
| `slowmode(CommandSender sender, String[] args)` | Establece el modo lento. |

### Listener

| Método | Significado |
| --- | --- |
| `registerListener(ModerationListener listener)` | Suscribirse a la actividad de castigos. |
| `unregisterListener(ModerationListener listener)` | Dejar de recibir eventos. |

## VeritePlayerData

Lee y registra los datos de cuenta, sesión e identidad que almacena el sistema de moderación. Las marcas de tiempo son milisegundos epoch. Cuando el módulo está desactivado, las consultas devuelven `null` o vacío y las llamadas de registro son no-ops.

| Método | Devuelve | Significado |
| --- | --- | --- |
| `enabled()` | `boolean` | Si el almacén de datos está abierto. |
| `hasProfile(UUID player)` | `boolean` | Si existe un perfil. |
| `profile(UUID player)` | `PlayerProfile` | El perfil completo, o `null`. |
| `uuidByName(String name)` | `UUID` | Resuelve un uuid a partir de un nombre. |
| `nameOf(UUID player)` | `String` | Resuelve el nombre actual a partir de un uuid. |
| `knownNames()` | `List<String>` | Todos los nombres conocidos en el almacén. |
| `namesOf(UUID player)` | `List<String>` | Todos los nombres que ha usado un jugador. |
| `ipsOf(UUID player)` | `List<String>` | Todas las ips desde las que se ha conectado un jugador. |
| `usersOfIp(String ip)` | `List<UUID>` | Todos los usuarios que compartieron una ip. |
| `clientsOf(UUID player)` | `List<String>` | Todos los clientes que ha usado un jugador. |
| `recordLogin(UUID player, String name, String ip, long now)` | `void` | Registra un inicio de sesión. |
| `recordClient(UUID player, String brand, int protocol, String referrer, long now)` | `void` | Registra la marca y el protocolo de un cliente. |
| `flushSession(UUID player, long now)` | `void` | Vuelca la sesión del jugador. |
| `recordLogout(UUID player, long now)` | `void` | Registra un cierre de sesión. |

## VeriteStore y VeriteScope

`VeriteStore` abre ámbitos de datos con nombre en el almacén persistente compartido de clave-valor del plugin, para que tu plugin pueda persistir datos junto a Verité sin una base de datos propia. Usa un espacio de nombres en los nombres de tus ámbitos para evitar colisiones con los datos del plugin.

| Método de `VeriteStore` | Devuelve | Significado |
| --- | --- | --- |
| `available()` | `boolean` | Si el almacén está abierto. |
| `scope(String name)` | `VeriteScope` | Abre un ámbito con nombre, o `null` si no está disponible. |

Un `VeriteScope` es un área con nombre que lees y escribes libremente. Las escrituras persisten a través del ciclo de volcado normal del plugin.

| Método de `VeriteScope` | Devuelve | Significado |
| --- | --- | --- |
| `set(String key, Object value)` | `void` | Almacena un valor bajo una clave. |
| `delete(String key)` | `void` | Elimina una clave. |
| `has(String key)` | `boolean` | Comprueba la presencia de una clave. |
| `get(String key)` | `Object` | El valor almacenado en bruto. |
| `getString(String key, String def)` | `String` | Lectura tipada con un valor por defecto. |
| `getLong(String key, long def)` | `long` | Lectura tipada con un valor por defecto. |
| `getInt(String key, int def)` | `int` | Lectura tipada con un valor por defecto. |
| `getBoolean(String key, boolean def)` | `boolean` | Lectura tipada con un valor por defecto. |
| `getBigDecimal(String key)` | `BigDecimal` | Lectura tipada. |
| `entries()` | `List<ScopeEntry>` | Cada par clave-valor del ámbito. |

```java
VeriteScope scope = VeriteStore.scope("myplugin");
if (scope != null) {
    scope.set("greeting", "hello");
    String greeting = scope.getString("greeting", "");
}
```

## VeriteVanish

Estado y control del vanish del personal. `vanish`, `unvanish` y `toggle` devuelven `true` cuando el estado cambió realmente. Cuando el módulo está desactivado, las consultas devuelven `false` o vacío y las llamadas de mutación son no-ops.

| Método | Devuelve | Significado |
| --- | --- | --- |
| `enabled()` | `boolean` | Si el módulo de vanish está cargado. |
| `isVanished(UUID player)` | `boolean` | Si un jugador está en vanish. |
| `isVanished(Player player)` | `boolean` | Sobrecarga de conveniencia para un jugador conectado. |
| `getVanished()` | `Set<UUID>` | Todos los jugadores actualmente en vanish. |
| `vanish(Player p)` | `boolean` | Poner a un jugador en vanish. |
| `unvanish(Player p)` | `boolean` | Sacar a un jugador de vanish. |
| `toggle(Player p)` | `boolean` | Alternar el estado de vanish de un jugador. |
| `registerPlaceholders()` | `void` | Registrar la expansión de PlaceholderAPI del vanish. |
| `registerListener(VanishListener listener)` | `void` | Suscribirse a los cambios de vanish. |
| `unregisterListener(VanishListener listener)` | `void` | Dejar de recibir eventos de vanish. |

## VeriteCaptcha

Emite y hace seguimiento de los desafíos de captcha. Los métodos `challenge` devuelven `true` cuando realmente se inició un desafío. La etiqueta `source` registra por qué se abrió el desafío y viaja hasta los eventos de finalización y de solicitud de castigo. Cuando el módulo está desactivado, todas las llamadas devuelven `false`.

| Miembro | Devuelve | Significado |
| --- | --- | --- |
| `VeriteCaptcha.BYPASS_PERMISSION` | `String` | El nodo de permiso que se salta el captcha. |
| `VeriteCaptcha.NOTIFY_PERMISSION` | `String` | El nodo de permiso de notificación de captcha. |
| `enabled()` | `boolean` | Si el módulo de captcha está cargado. |
| `isActive(UUID player)` | `boolean` | Si hay un desafío activo para el jugador. |
| `challengeStandard(Player player, String source)` | `boolean` | Abrir un desafío estándar. |
| `challengeDetailed(Player player, String source)` | `boolean` | Abrir un desafío detallado. |
| `challenge(Player player, CaptchaType type, String source)` | `boolean` | Abrir un desafío de un tipo explícito. |

## VeriteFilter

El filtro de chat consciente de la evasión. El flujo de trabajo completo, incluidas las comprobaciones anónimas, las comprobaciones con detección de repeticiones y las ayudas del mensaje de bloqueo, está documentado en [Integración de chat personalizado](page:developers/wiring). La superficie:

| Miembro | Devuelve | Significado |
| --- | --- | --- |
| `VeriteFilter.ANONYMOUS` | `UUID` | Pásalo como el jugador cuando no hay ningún infractor contra el que registrar. |
| `check(UUID player, String message)` | `FilterResult` | Clasifica un mensaje y registra el acierto contra el jugador. |
| `check(UUID player, String message, boolean repeatAware)` | `FilterOutcome` | Clasificación con detección de repeticiones. |
| `count(UUID player)` | `int` | Cuántas veces ha sido marcado un jugador. |
| `blockMessage()` | `String` | El mensaje de bloqueo configurado. |
| `repeatMessage()` | `String` | El aviso de mensaje repetido configurado. |
| `selfHarmMessage()` | `String` | El aviso de autolesión configurado. |
| `blockNotice(FilterResult result, String message)` | `BaseComponent[]` | El componente de aviso renderizado para un resultado. |
| `foldAccents(String s)` | `String` | Ayuda de normalización: elimina los acentos. |
| `stripDeletes(String s)` | `String` | Ayuda de normalización: elimina los caracteres de ancho cero y de borrado. |
| `stripEntities(String s)` | `String` | Ayuda de normalización: elimina las entidades tipo html. |
| `reduceRuns(String s, int max)` | `String` | Ayuda de normalización: colapsa las letras repetidas. |
| `fingerprint(String word)` | `String` | Firma de letras independiente del orden para la coincidencia de transposiciones. |
| `trimEdges(String word)` | `String` | Recorta los bordes que no son letras de una palabra. |

Las ayudas de normalización son funciones puras y es seguro llamarlas fuera del hilo principal.

## VeriteText

Analiza texto con etiquetas de Verite y aplica el prefijo del plugin tal como lo hace el plugin, para que tu salida tenga un estilo idéntico.

| Método | Devuelve | Significado |
| --- | --- | --- |
| `parse(String tagged)` | `BaseComponent[]` | Analiza etiquetas de Verite a un array de componentes. |
| `prefixed(String tagged)` | `BaseComponent[]` | Analiza y antepone el prefijo del plugin. |
| `prefix()` | `String` | El prefijo actual. |
| `setPrefix(String prefix)` | `void` | Cambia el prefijo. |

## Utilidades

### VeriteGeoIp

Consulta el país de una ip y comprueba el estado de la base de datos de GeoIP.

| Método | Devuelve | Significado |
| --- | --- | --- |
| `country(String ip)` | `String` | Nombre del país de una ip, o `null` si no se puede resolver. |
| `available()` | `boolean` | Si la base de datos de GeoIP se cargó. |
| `isPrivate(String ip)` | `boolean` | Si una ip está en un rango privado o reservado. |
| `attempted()` | `boolean` | Si se ha intentado cargar una base de datos. |

### VeriteDuration

Analiza y formatea duraciones de castigo legibles para humanos, con constantes de unidad en milisegundos: `SECOND`, `MINUTE`, `HOUR`, `DAY`, `WEEK`, `MONTH`, `YEAR`.

| Método | Devuelve | Significado |
| --- | --- | --- |
| `suggestions()` | `List<String>` | Tokens de duración sugeridos. |
| `parse(String token)` | `long` | Analiza un token como `7d` a milisegundos. |
| `parseTwoToken(String number, String unitWord)` | `long` | Analiza un número y una palabra de unidad separados a milisegundos. |
| `format(long millis)` | `String` | Formatea milisegundos a una cadena legible para humanos. |

### VeriteFormat

Formatea tiempos, pluraliza sustantivos y nombra las versiones de protocolo de cliente.

| Método | Devuelve | Significado |
| --- | --- | --- |
| `fancyTime(long millis)` | `String` | Un lapso de milisegundos como una cadena legible para humanos. |
| `plural(long count, String noun)` | `String` | Un recuento con el sustantivo singular o plural correcto. |
| `pluralize(long count, String noun)` | `String` | Un recuento con el sustantivo singular o plural correcto. |
| `versionName(int protocol)` | `String` | El nombre de la versión de Minecraft de un número de protocolo de cliente. |

### VeriteLimits

Aplica los mismos límites de duración y tiempos de espera por emisor que aplica el plugin.

| Método | Devuelve | Significado |
| --- | --- | --- |
| `capDuration(CommandSender issuer, PunishmentType type, long requested)` | `DurationCheck` | Valida una duración solicitada y devuelve el valor limitado. |
| `cooldownRemaining(CommandSender issuer, PunishmentType type, long now)` | `long` | Milisegundos hasta que el emisor pueda actuar de nuevo. |
| `markUsed(CommandSender issuer, PunishmentType type, long now)` | `void` | Registra que un emisor usó su cupo. |

### VeriteMojang

Resuelve un nombre de usuario de Minecraft contra Mojang, usando la misma ruta y caché que usa el plugin.

| Método | Devuelve | Significado |
| --- | --- | --- |
| `lookup(String name)` | `MojangProfile` | Resuelve un nombre a un uuid, nombre canónico y estado. |

### VeriteExempt

Comprueba si a un emisor se le impide castigar a un objetivo.

| Método | Devuelve | Significado |
| --- | --- | --- |
| `blockReason(CommandSender issuer, UUID target, PunishmentType type)` | `String` | El motivo por el que no se permite el castigo, o `null` cuando está permitido. |

### VeriteLockdown

Consulta y controla el estado de bloqueo del servidor. Se cubre en su contexto en [Aplicación de moderación personalizada](page:developers/moderation-enforcement).

| Método | Devuelve | Significado |
| --- | --- | --- |
| `active()` | `boolean` | Si hay un bloqueo en efecto. |
| `reason()` | `String` | El motivo actual del bloqueo. |
| `begin(String why)` | `void` | Iniciar un bloqueo con un motivo. |
| `end()` | `void` | Levantar el bloqueo. |

### VeriteConfig

Lee la configuración efectiva del módulo de moderación.

| Método | Devuelve | Significado |
| --- | --- | --- |
| `banAlts()` | `boolean` | Si las cuentas alternativas se banean. |
| `muteCommandBlacklist()` | `List<String>` | Comandos bloqueados mientras se está muteado. |
| `warningExpire()` | `long` | La ventana de caducidad de advertencias en milisegundos. |
| `useGroupWeights()` | `boolean` | Si se usan los pesos de grupo. |
| `permitSameWeight()` | `boolean` | Si se permiten las acciones sobre el mismo peso. |
| `reduceToLimit()` | `boolean` | Si las duraciones se reducen al límite del emisor. |
| `dupeipScanLimit()` | `int` | El límite del escaneo de dupeip. |
| `yaml()` | `YamlConfiguration` | La configuración de respaldo en bruto. |

## Tipos

### Punishment

Un registro de moderación inmutable. `PERMANENT` es la marca de tiempo final centinela para un castigo permanente (`-1L`). `GLOBAL_SCOPE` es el ámbito comodín (`"*"`). Las marcas de tiempo son milisegundos epoch. Una ip de objetivo `null` significa que el castigo tiene ámbito de uuid en lugar de ámbito de ip.

Accesores: `id()`, `randomId()`, `type()`, `uuid()`, `ip()`, `reason()`, `executorUuid()`, `executorName()`, `removedByUuid()`, `removedByName()`, `removalReason()`, `dateStart()`, `dateEnd()`, `serverScope()`, `serverOrigin()`, `template()`, `silent()`, `ipban()`, `active()`.

Ayudas derivadas:

| Método | Devuelve | Significado |
| --- | --- | --- |
| `permanent()` | `boolean` | Si `dateEnd` es `PERMANENT`. |
| `expired(long now)` | `boolean` | Si un castigo temporal ha pasado su fin. |
| `inForce(long now)` | `boolean` | Si el registro está activo y no ha caducado. |
| `duration()` | `long` | Duración total, o `PERMANENT`. |
| `remaining(long now)` | `long` | Milisegundos restantes, o `PERMANENT`. |
| `hasTemplate()` | `boolean` | Si el registro lleva una plantilla. |

### PunishmentType

Enum: `BAN`, `MUTE`, `WARNING`, `KICK`.

| Método | Devuelve | Significado |
| --- | --- | --- |
| `id()` | `String` | El nombre en minúsculas de la locale raíz. |
| `PunishmentType.of(String s)` | `PunishmentType` | Analiza la forma en minúsculas de vuelta, sin distinguir mayúsculas. |

### PunishmentResult

Record: `PunishmentResult(boolean ok, Punishment entry, String error)`. En caso de éxito `ok` es `true`, `entry` contiene el castigo resultante y `error` es `null`. En caso de fallo `entry` es `null` y `error` contiene el motivo.

### ActivePunishment

Record: `ActivePunishment(PunishmentType type, UUID uuid, long entryId)`. Un puntero ligero; carga el registro completo con `VeriteModeration.loadPunishment(entryId)`.

### FilterResult

Enum: `CLEAN`, `BLOCK`, `SELF_HARM`, `ABUSE`, `PROFANITY`. `blocks()` devuelve `true` para cualquier cosa que no sea `CLEAN`. Un mensaje detenido por repetir uno reciente se reporta como `BLOCK` aquí; usa la sobrecarga de `check` con detección de repeticiones para distinguirlos. `SELF_HARM` y `ABUSE` marcan a un hablante que puede estar en crisis; no los trates como infracciones normales de las reglas.

### FilterOutcome

El valor de `VeriteFilter.check(player, message, true)`.

| Método | Devuelve | Significado |
| --- | --- | --- |
| `category()` | `FilterResult` | La categoría normal del filtro, nunca `null`. |
| `repeat()` | `boolean` | Si el bloqueo fue una repetición (solo es `true` cuando `category()` es `BLOCK`). |
| `blocks()` | `boolean` | Si el mensaje debe descartarse. |

### PlayerProfile

Record con campos: `uuid`, `name`, `names`, `ips`, `lastIp`, `clients`, `lastClient`, `protocol`, `referrer`, `firstJoin`, `lastSeen`, `joinCount`, `playtimeMs`, `online`, `punishments`. Las marcas de tiempo son milisegundos epoch. Los campos de lista nunca son `null` pero pueden estar vacíos.

### MojangProfile y MojangStatus

`MojangProfile(UUID uuid, String name, MojangStatus status)`. Cuando `status` no es `FOUND`, `uuid` y `name` son `null`.

`MojangStatus`: `FOUND` (resuelto), `NOT_FOUND` (Mojang confirmó que no existe tal cuenta), `UNKNOWN` (la consulta no pudo completarse, por ejemplo un error de red).

### DurationCheck

Record: `DurationCheck(boolean ok, long durationMillis, String error)`. Cuando `ok`, `durationMillis` contiene la duración posiblemente limitada a aplicar y `error` es `null`. Cuando no `ok`, `error` explica el rechazo.

### ScopeEntry

Record: `ScopeEntry(String key, Object value)`. Un par clave-valor de un ámbito del almacén.

### CaptchaType y CaptchaOutcomeType

`CaptchaType`: `STANDARD` (un desafío rápido de baja fricción), `DETAILED` (un desafío más estricto de varios pasos).

`CaptchaOutcomeType`: `PASS`, `FAIL`, `TIMEOUT`.

## Listeners

### ModerationListener

Implementa y registra a través de `VeriteModeration.registerListener`. Todos los métodos son no-ops por defecto, así que sobrescribe solo lo que necesites. Los callbacks pueden ejecutarse en el hilo principal del servidor; no bloquees.

| Método | Se dispara cuando |
| --- | --- |
| `entryAdded(Punishment punishment)` | Se emite un castigo. |
| `entryRemoved(Punishment punishment)` | Se levanta, indulta o caduca un castigo. |
| `broadcastSent(String message, String target)` | El sistema de moderación envía una difusión. |

### VanishListener

Implementa y registra a través de `VeriteVanish.registerListener`. No-ops por defecto; no bloquees en los callbacks.

| Método | Se dispara cuando |
| --- | --- |
| `vanished(UUID player)` | Un jugador entra en vanish. |
| `unvanished(UUID player)` | Un jugador sale de vanish. |
