Interface Third-Party

Crie uma ferramenta que o BakoshApp possa controlar: exponha quatro endpoints HTTP em uma porta local, e seu programa reage a presentes, curtidas, seguidores e chat do TikTok e do Kick.

O BakoshApp pode executar ações dentro do seu programa. Sua ferramenta expõe uma pequena API HTTP em uma porta local; o BakoshApp lê a sua lista de ações e chama uma sempre que um evento do TikTok ou do Kick corresponde ao acionador do usuário. Qualquer coisa que você possa controlar por código — luzes inteligentes, um microcontrolador, uma soundboard, outro jogo, seu próprio bot — pode reagir a uma live sem um mod do BakoshApp.

Como tudo se encaixa

  1. Sua ferramenta escuta em http://127.0.0.1:8833.
  2. O usuário a conecta em Configurações → Third-Party (host e porta) e a verifica com Testar conexão.
  3. Na aba Ações de um mod, o usuário clica em Adicionar novo, escolhe um acionador e, em Todas as ações → Externos, configura uma Third-Party Action: o BakoshApp preenche duas listas com suas categorias e ações.
  4. A cada evento correspondente, o BakoshApp chama sua ferramenta, e o seu código faz o trabalho.

A conexão é de mão única: o BakoshApp chama você, nunca o contrário.

Porta e endereço

  • 8833 é o padrão. O usuário pode alterá-la em Configurações → Third-Party; avise seus usuários de qual porta digitar se você usar outra.
  • A porta 8832 não pode ser usada: é nela que o próprio BakoshApp escuta (é assim que o TikFinity encontra o BakoshApp), e a configuração a recusa.
  • Não há autenticação. Escute em 127.0.0.1, não em 0.0.0.0, para que a API não fique acessível pela rede.
  • O BakoshApp sempre usa HTTP simples.

Endpoints

Sua ferramenta deve expor os quatro. Toda resposta é um JSON com um membro data.

1. Informações do app

Identifica sua ferramenta. O BakoshApp a mostra como "Connected with Mock Tool 1.0 by Bakosh" em Configurações e no configurador de ações.

GET /api/app/info
{ "data": { "name": "Mock Tool", "version": "1.0", "author": "Bakosh" } }

2. Categorias

A primeira lista no configurador.

GET /api/features/categories
{
  "data": [
    { "categoryId": "smart_device_control", "categoryName": "Control Smart Devices" },
    { "categoryId": "serial_port_control",  "categoryName": "Control Serial Port" }
  ]
}

3. Ações

A segunda lista: as ações de uma categoria. O categoryId é codificado para URL.

GET /api/features/actions?categoryId=smart_device_control
{
  "data": [
    { "actionId": "turn_lights_on",  "actionName": "Turn Lights On" },
    { "actionId": "turn_lights_off", "actionName": "Turn Lights Off" }
  ]
}

As listas mostram seus itens na ordem em que você os retorna. Uma ação que o usuário já salvou, mas que você não retorna mais, permanece no topo da lista, para que ela não mude silenciosamente.

Aviso

categoryId e actionId são tudo o que o BakoshApp armazena de uma ação configurada. Mantenha-os estáveis: renomear um id quebra configurações existentes. Os nomes são só para exibição e podem mudar a qualquer momento.

4. Executar

Chamado toda vez que um evento correspondente executa a ação.

POST /api/features/actions/exec
{
  "categoryId": "smart_device_control",
  "actionId": "turn_lights_on",
  "context": {
    "triggerTypeId": 4,
    "eventType": "gift",
    "source": "eulerstream",
    "platform": "tiktok",
    "userId": "123456789",
    "username": "testuser",
    "nickname": "Test User",
    "giftName": "Rose",
    "giftId": 5655,
    "repeatCount": 3,
    "diamondCount": 1,
    "coins": 1,
    "profilePictureUrl": "https://…"
  }
}

Responda com um array data vazio assim que aceitar a requisição:

{ "data": [] }

Tempos de resposta

  • O BakoshApp espera até 5 segundos pelos três endpoints GET e 10 segundos pelo exec. Uma requisição que falha ou expira não é repetida.
  • Se a ação tiver Quantidade acima de 1, o BakoshApp chama o exec esse número de vezes, uma após a outra: ele espera sua resposta, depois o Intervalo da linha, e chama de novo.
  • As chamadas da mesma linha vêm uma de cada vez; linhas diferentes podem chamar você em paralelo.

Por isso, responda rápido e faça o trabalho demorado em segundo plano — os espectadores podem enviar presentes mais rápido do que uma porta serial consegue processar.

O objeto context

O context descreve o evento que executou a ação. Só estão presentes os campos que existem para aquele evento — verifique antes de ler.

CampoTipoPresente
triggerTypeIdnumbersempre — veja abaixo
eventTypestringsempre — gift, like, chat, follow, share, joined, subscribe, tikfinity ou test
sourcestringsempre — eulerstream (TikTok), kick, tikfinity ou test
platformstringeventos do TikTok e do Kick — tiktok ou kick
usernamestringsempre — o nome de usuário do espectador
nicknamestringeventos do TikTok e do Kick — o nome de exibição
userIdstringeventos do TikTok e do Kick
profilePictureUrlstringgeralmente (os links de avatar do TikTok expiram)
commentstringmensagens de chat; no Kick, também a mensagem anexada a um presente
giftNamestringpresentes
giftIdnumberpresentes do TikTok
repeatCountnumberpresentes do TikTok — presentes na sequência (streak); assinaturas presenteadas no Kick — número de destinatários
diamondCountnumberpresentes — valor em Diamonds (TikTok) ou preço em Kicks (Kick)
coinsnumbero mesmo que diamondCount
likeCountnumbercurtidas
subMonthnumberassinaturas

Eventos retransmitidos pelo TikFinity trazem apenas triggerTypeId (sempre 0), source, eventType e username.

Tipos de acionador

O triggerTypeId é o tipo do acionador que o usuário configurou, então um presente escolhido pelo nome e um presente identificado pelo valor são diferenciados:

IdAcionador
1Compartilhar
3Mín-Máx (faixa de valor do presente)
4Presente
6Entrou
7Like
9Seguir
10Subscribe / Super Fan
11Chat
0TikFinity, ou qualquer outra coisa

Trate ids desconhecidos como 0; mais podem ser adicionados.

O botão Testar

Testar na linha da ação (e sua tecla de atalho) chama o exec com dados de exemplo: source e eventType são test, o triggerTypeId vem do acionador da linha, o espectador é bakosh_app, e o presente é uma Rose (giftId 5655). Não há platform.

Relatando problemas

Retorne uma message para descrever o que deu errado:

{ "message": "Serial port COM3 is not available" }
  • Nos endpoints GET, qualquer message faz o BakoshApp tratar a resposta como um erro, mesmo com HTTP 200.
  • No exec, a message é gravada no console e no arquivo de log do BakoshApp como um aviso. O usuário não recebe um pop-up.

Status de erro HTTP também são respeitados; sem uma message, o log mostra apenas o código de status.

Funcionando com o TikFinity também

A interface é igual à interface de terceiros do TikFinity — os mesmos quatro caminhos e nomes de campo — então uma ferramenta pode atender aos dois. As portas são diferentes: o TikFinity procura ferramentas na 8832, que o BakoshApp ocupa enquanto está em execução, então dê ao BakoshApp outra porta.

O TikFinity é um app web e precisa de cabeçalhos CORS (Access-Control-Allow-Origin: * e afins) além de respostas às requisições de preflight OPTIONS. O BakoshApp não precisa deles, mas enviá-los não causa nenhum problema. O BakoshApp envia mais campos de context do que o TikFinity — ignore os que você não usar.

Uma ferramenta completa e funcional

Sem dependências — salve como tool.mjs e execute node tool.mjs:

import http from 'node:http';
 
const PORT = 8833;
 
const APP_INFO = { name: 'Mock Tool', version: '1.0', author: 'Bakosh' };
 
const CATALOG = [
  {
    categoryId: 'smart_device_control',
    categoryName: 'Control Smart Devices',
    actions: [
      { actionId: 'turn_lights_on', actionName: 'Turn Lights On' },
      { actionId: 'turn_lights_off', actionName: 'Turn Lights Off' },
    ],
  },
];
 
// Wildcard CORS keeps the same tool usable from TikFinity as well.
const CORS = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Headers': '*',
  'Access-Control-Allow-Methods': '*',
};
 
const send = (res, status, body) => {
  res.writeHead(status, { 'Content-Type': 'application/json', ...CORS });
  res.end(JSON.stringify(body));
};
 
const readBody = (req) =>
  new Promise((resolve) => {
    let raw = '';
    req.on('data', (c) => { raw += c; });
    req.on('end', () => { try { resolve(JSON.parse(raw || '{}')); } catch { resolve({}); } });
  });
 
// Your actual work goes here. Return a string to report a problem.
function runAction(categoryId, actionId, context) {
  console.log(`${categoryId}/${actionId} fired by ${context.username ?? 'someone'} on ${context.platform ?? context.source}`);
  // turnLightsOn() …
  return null;
}
 
http.createServer(async (req, res) => {
  const url = new URL(req.url, `http://127.0.0.1:${PORT}`);
 
  if (req.method === 'OPTIONS') {           // preflight (TikFinity only)
    res.writeHead(204, CORS);
    return res.end();
  }
 
  if (req.method === 'GET' && url.pathname === '/api/app/info') {
    return send(res, 200, { data: APP_INFO });
  }
 
  if (req.method === 'GET' && url.pathname === '/api/features/categories') {
    return send(res, 200, {
      data: CATALOG.map(({ categoryId, categoryName }) => ({ categoryId, categoryName })),
    });
  }
 
  if (req.method === 'GET' && url.pathname === '/api/features/actions') {
    const cat = CATALOG.find((c) => c.categoryId === url.searchParams.get('categoryId'));
    return send(res, 200, { data: cat ? cat.actions : [] });
  }
 
  if (req.method === 'POST' && url.pathname === '/api/features/actions/exec') {
    const body = await readBody(req);
    const problem = runAction(body.categoryId ?? '', body.actionId ?? '', body.context ?? {});
    return problem ? send(res, 200, { message: problem }) : send(res, 200, { data: [] });
  }
 
  send(res, 404, { message: `No such endpoint: ${url.pathname}` });
}).listen(PORT, '127.0.0.1', () => console.log(`Listening on http://127.0.0.1:${PORT}`));

Testando sua ferramenta

  1. Inicie sua ferramenta.
  2. No BakoshApp, abra Configurações → Third-Party, confira o host e a porta, e clique em Testar conexão. Você deve ver o nome, a versão e o autor da sua ferramenta.
  3. Na aba Ações de um mod, clique em Adicionar novo, escolha um acionador e clique em Próximo. Em Todas as ações → Externos, clique em Configure ao lado de Third-Party Action, escolha sua categoria e ação, e salve.
  4. Clique em Testar na nova linha — sua ferramenta recebe um exec com eventType: "test".
  5. Entre ao vivo e verifique se eventos reais chegam.

Se o configurador disser "Não foi possível conectar! Verifique sua integração.", verifique se a ferramenta escuta em 127.0.0.1, se a porta corresponde às Configurações, e se GET /api/app/info retorna sua resposta dentro de data.