Package
ubfb es el cliente oficial en TypeScript: une la API REST y el WebSocket de presencia en una sola interfaz, con una caché local para no repetir llamadas de red.
Instalación
npm install ubfbUso básico
import { UBFB } from "ubfb";
const ubfb = new UBFB({ name: "MiBot" }); // name/avatarUrl son opcionales, públicos y sin verificar
ubfb.on("sync", (ids) => console.log(`${ids.length} usuarios activos`));
ubfb.on("add", (entry) => console.log("nuevo:", entry.id, entry.reason));
ubfb.on("remove", (userId) => console.log("rehabilitado:", userId));
ubfb.on("error", (err) => console.error(err));
ubfb.connect();
// en cualquier parte, sin llamada de red:
if (ubfb.isBlacklisted(userId)) {
// ...
}Conexión (WebSocket)
Ninguno de los dos requiere red para responder — solo abren/cierran el socket.
connect(): voidreconnectDelayMs (5000ms por defecto) — no hace falta llamar a connect() otra vez.close(): voidconnect() explícitamente.Eventos
UBFB extiende EventEmitter de Node — ubfb.on(evento, callback). Solo llegan tras connect().
"open" → ()"close" → ()close() o por una caída de conexión. Si fue una caída inesperada, justo después empieza el temporizador de reconexión."error" → (error: Error)"sync" → (ids: string[])"add" → (entry: BlacklistEntry)"remove" → (userId: string)Caché local
Se mantiene al día desde dos fuentes: cada evento del WebSocket (sync/add/remove) y cada llamada REST que devuelve datos del blacklist (getBlacklistIds, getAllBlacklist,getBlacklistEntry) — no hace falta connect() para que la caché tenga algo, basta con haber pedido los datos por REST alguna vez.
await ubfb.getAllBlacklist(); // también rellena la caché
ubfb.isBlacklisted(userId); // sin red
ubfb.getCachedEntry(userId); // sin red — undefined si nunca vimos el detalle completo
ubfb.getCachedEntries(); // todo lo que hay en caché ahora mismoisBlacklisted(userId: string): booleangetCachedEntry(userId: string): BlacklistEntry | undefinedundefined aunqueisBlacklisted() devuelva true — un sync por WS solo trae IDs, no filas completas.getCachedEntries(): BlacklistEntry[]sync (WS) y getBlacklistIds() (REST) solo traen IDs, no filas completas — así que isBlacklisted() puede ser true mientrasgetCachedEntry() devuelve undefined, hasta que llegue el detalle completo (por un evento add o por getAllBlacklist()/getBlacklistEntry()).
API REST
Cada método funciona sin connect() — son llamadas independientes, y cada una que devuelve datos del blacklist también rellena la caché. Todos lanzanUBFBApiError (con .status y .body) si la API responde con un error.
getBlacklistIds(): Promise<string[]>GET /blacklist/ids — todos los IDs de Discord actualmente activos.getAllBlacklist(): Promise<BlacklistEntry[]>GET /blacklist/all — todas las entradas activas, filas completas.getBlacklistEntry(userId: string): Promise<BlacklistEntry | null>GET /blacklist/:userId — la entrada de un usuario, o null si no está en la blacklist.getReports(): Promise<Report[]>GET /reports — la cola completa de reportes pendientes, de solo lectura. No es dato de blacklist — no toca la caché.fileReport(input: ReportInput): Promise<Report>POST /reports — archiva un nuevo reporte. proofs debe traer al menos una URL de imagen. No toca la caché: archivar un reporte no blacklistea a nadie por sí solo, eso solo pasa cuando staff lo aprueba.Lanza UBFBApiError: 400 si el input es inválido, 409 si el usuario ya tiene un reporte pendiente.
exportBlacklist(format: ExportFormat): Promise<string>GET /export?format=... — la blacklist activa como texto plano, en el formato indicado ("json" | "csv" | "sql").getActiveBots(): Promise<{ count: number; bots: ActiveBot[] }>GET /bots/active — quién está conectado ahora mismo al WebSocket de presencia.Lista de razones
import { BlacklistReasons } from "ubfb";
[...BlacklistReasons]; // BlacklistReason[], las 21 razones válidas
BlacklistReasons.length; // 21
BlacklistReasons.toMarkdown(); // lista en markdown, una razón por línea ("- Raider\n- ...")BlacklistReasons es una instancia de BlacklistReasonList ya poblada con todas las razones — es iterable directamente. Para un subconjunto propio:new BlacklistReasonList([BlacklistReason.Dox, BlacklistReason.Estafa]).toMarkdown().
Opciones y tipos
Opciones del constructor
| Opción | Tipo | Descripción |
|---|---|---|
| baseUrl | string | Base de la API REST. Por defecto https://ubfb-api.theindiebrand.es. |
| wsUrl | string | URL del WebSocket de presencia. Por defecto, derivada de baseUrl. |
| name | string | Nombre público mostrado en GET /bots/active. No autenticado. |
| avatarUrl | string | Avatar público mostrado junto al nombre. No autenticado. |
| reconnectDelayMs | number | Espera antes de reconectar tras una caída inesperada. Por defecto 5000. |
También exportado
| UBFB | La clase principal — event emitter + REST + caché, todo en uno. |
| UBFBPresence | Solo el WebSocket de presencia, sin caché ni REST — para quien quiera manejarlo por separado. |
| UBFBRest | Solo las llamadas REST, sin WebSocket ni caché. |
| UBFBCache | La caché en memoria por sí sola. |
| UBFBApiError | Error lanzado por los métodos REST — trae .status y .body. |
| BlacklistReason | Enum con las 21 razones válidas — el mismo que usa la API. |
| BlacklistStatus | Enum del estado de una entrada: Activo, Inactivo, En votación. |
| BlacklistEntry | Una fila del blacklist activo. |
| Report | Un reporte pendiente, tal como lo devuelve fileReport()/getReports(). |
| ReportInput | El body que espera fileReport(). |
| ActiveBot | Un cliente conectado ahora mismo al WebSocket de presencia. |
| ExportFormat | "json" | "csv" | "sql" — el tipo del argumento de exportBlacklist(). |