Automatiza bonk.io sin abrir un navegador.

bonktools es una biblioteca TypeScript que habla directamente el protocolo del juego. Crea salas, controla equipos, detecta jugadores AFK y mantén una sala funcionando las 24 horas.

npm install bonktools

EmpezarLeer la documentación

Versión 0.1.4 · MIT · Node.js 20.18 o superior

bot.ts
import { createRoom } from 'bonktools';

const room = await createRoom({
  auth: { type: 'registered', username, password },
  desiredState: {
    roomName: 'Mi Sala', password: '',
    maxPlayers: 6, mode: 'b', rounds: 3,
  },
});

room.lockTeams();       // solo el host mueve jugadores
room.enableAntiAfk();   // 12 s quieto = AFK

room.on('player-afk', (id) => room.kickPlayer(id));
room.on('chat-message', ({ message }) => {
  if (message === '!ping') room.chat('Pong!');
});

console.log(room.shareLink); // https://bonk.io/123456abcde

Características

  • Conexión directa al protocolo. Socket.IO v2 y la cadena TLS de bonk.io ya están resueltos. Sin Puppeteer, sin pantalla virtual, sin automatización frágil de la interfaz. Protocolo
  • Salas 24/7 que se recuperan. BonkSession recrea las salas que caen, con backoff exponencial, throttle de creación y un reconcile cada 60 s. Sesiones 24/7
  • Eventos tipados. Más de 30 eventos con payloads tipados y el estado de la sala siempre disponible en room.state. Eventos
  • Control de equipos. lockTeams() impide que los jugadores cambien de equipo por su cuenta: solo el host mueve jugadores. Quien entra después ya ve la sala bloqueada. Equipos y bloqueo
  • Anti-AFK. Detecta 12 s sin moverse y sin hablar, leyendo el movimiento de los frames de input por WebRTC. Anti-AFK
  • Los espectadores ven la partida. Quien entra mientras hay una partida en curso recibe el estado de la partida al instante, sin reiniciarla para todos. Partidas

Cómo funciona

Tú eliges el nivel de abstracción: un socket crudo, una sala con estado y eventos, o un pool de salas que se mantiene vivo solo. Cada sala es una conexión ligera; no hace falta renderizar el juego para alojar una sala.

Tu código
    │
BonkSession     pool de salas · login compartido · throttle · reconcile de 60 s
BonkRoom        estado · eventos tipados · equipos · bloqueo · anti-AFK · reconexión
BonkTransport   Socket.IO v2 (EIO=3) · TLS · timesync
    │
bonk.io         + PeerJS/WebRTC para los frames de input de los jugadores
  • Fallos bajo control. Las caídas transitorias se recrean. Los baneos, salas llenas y reintentos agotados son terminales y te avisan.
  • Protocolo documentado. La ingeniería inversa está registrada al detalle, con formatos de paquetes y trampas. Ver el protocolo

Ejemplos

Crear y entrar en salas

typescript
import { createRoom, joinRoom } from 'bonktools';

// Crear una sala (el bot se convierte en host)
const room = await createRoom({
  auth: { type: 'registered', username, password },
  desiredState: { roomName: 'HERMES', password: '', maxPlayers: 6, mode: 'b', rounds: 3 },
  hidden: false,
});
console.log('Link:', room.shareLink);

// Entrar en una sala existente
const guest = await joinRoom('https://bonk.io/123456abcde', {
  auth: { type: 'guest', guestName: 'BonkBot' },
  role: 'spectator',
});

Eventos y estado

typescript
room.on('player-join', (p) => room.chat(`Bienvenido, ${p.userName}!`));
room.on('team-change', (p) => console.log(`jugador ${p.id} → equipo ${p.team}`));

room.on('game-start', () => console.log('partida iniciada'));
room.on('game-end',   () => console.log('partida terminada'));

room.on('room-dead',    (reason) => console.error('la sala cayó:', reason.kind));
room.on('room-rebuilt', (link)   => console.log('sala recreada:', link));

// el estado siempre a mano
room.state.players.forEach((p) => console.log(p.userName, p.team));

Equipos y anti-AFK

typescript
room.lockTeams();                              // nadie cambia de equipo por su cuenta
room.enableAntiAfk({ thresholdMs: 12_000 });   // 12 s sin moverse ni hablar

room.on('player-afk', (id) => {
  room.chat(`${room.state.players.get(id)?.userName} está AFK!`);
  room.kickPlayer(id);
});
room.on('player-back', () => room.chat('¡ha vuelto!'));

room.setTeam(id, 3);    // el host sigue moviendo jugadores (3 = azul)
room.isAfk(id);         // consulta puntual

Sesión 24/7

typescript
import { BonkSession } from 'bonktools';

const session = new BonkSession({
  auth: { type: 'registered', username, password },
  throttle: { capacity: 1, refillPerSec: 0.3 },
});
await session.getToken();

session.on('room-added', (localId) => {
  const { room } = session.rooms.get(localId)!;
  console.log('sala activa:', room.shareLink);
});
session.on('room-dead-terminal', ({ localId, reason }) => console.error(localId, reason));

// declarativo: recrea la sala solo si se cae
await session.startFromConfig({
  rooms: [{ id: 'main', name: 'ATLAS', maxPlayers: 6, mode: 'b', rounds: 3 }],
  throttle: { maxConcurrentRooms: 1, roomCreationDelayMs: 3000, roomCreationJitterMs: 2000 },
});

Ejemplo: una sala de fútbol 24/7

El repositorio incluye un bot de referencia completo construido solo con la biblioteca. Monta los equipos, elige capitanes, rota al campeón y gestiona a los jugadores AFK. Úsalo como base para el tuyo.

  • Equipos siempre iguales. Basado en maxTeamSize: nunca 2v1, 3v1 ni 3v4.
  • Los capitanes eligen. Cuando los espectadores pueden completar los equipos, el capitán escribe el número del jugador que quiere; el último jugador entra solo.
  • El ganador se queda en azul. El perdedor va al final de la cola y el primero de la cola se convierte en capitán del rojo.
  • AFK sin complicaciones. !afk alterna, los AFK nunca son elegidos, y quien está jugando no puede declararse AFK.
  • Equipos bloqueados. Solo el bot mueve jugadores.

Cómo funciona la elección

Azul

  • Ana capitán

Rojo

vacío

Espectadores (cola)

vacío

1. Ana entra

El primer jugador va al azul y se convierte en capitán. La partida en solitario empieza al instante.

1 / 8 · maxTeamSize = 2

Comandos

ComandoQuién lo usaQué hace
!afkcualquier jugadorAlterna AFK: pasa a espectador y no puede ser elegido. Durante una partida, quien juega no puede ponerse AFK.
2 (solo el número)capitán con el turnoElige al jugador número 2 de la lista, sin comando (30 s; sin respuesta, se elige al primero).
!win blue · !win redjugador en el campoInforma del ganador y dispara la rotación de equipos.
!start · !stopjugador en el campoInicia o detiene la partida (!stop retiene el reinicio hasta el siguiente !start).

Documentación de la sala · Reglas de elección

Calidad

Las salas de juego muestran errores que las pruebas unitarias no ven, así que cada función pasa por tres capas de validación:

  • 123 pruebas en la biblioteca. Sala, equipos, bloqueo, anti-AFK, códec y reconexión.
  • 32 pruebas en la sala 24/7, con fuzzing. Más de 600 secuencias aleatorias de entradas, salidas, AFK y elecciones, comprobando la proporción de equipos en cada partida.
  • Jugadores reales. Navegadores reales jugando; incluso medimos si el disco realmente se mueve en pantalla.

Versiones

  1. 0.1.0 Base: transporte, sala con estado y eventos, sesión 24/7.
  2. 0.1.1 Balance por jugador (BALANCE_SET) reflejado en el estado.
  3. 0.1.2 Un espectador que entra con una partida en curso ahora ve el juego.
  4. 0.1.3 Anti-AFK y el handshake WebRTC, con el evento peer-input.
  5. 0.1.4 lockTeams() y unlockTeams(), además de las correcciones de gs.tl y de los colores de equipo.

Empieza en 3 pasos

Requiere Node.js 20.18 o superior y una cuenta de bonk.io.

  1. Instala.
    bash
    npm install bonktools
  2. Escribe el bot.
    bot.ts
    import { createRoom } from 'bonktools';
    
    const room = await createRoom({
      auth: { type: 'registered', username: process.env.BONK_USER!, password: process.env.BONK_PASS! },
      desiredState: { roomName: '¡Hola, bonk!', password: '', maxPlayers: 6, mode: 'b', rounds: 3 },
    });
    console.log(room.shareLink);
  3. Ejecútalo.
    bash
    BONK_USER=tu_usuario BONK_PASS=tu_contraseña npx tsx bot.ts
    # → https://bonk.io/123456abcde

Leer la guía completa