Documentação

Lua 5.5 · API v0.1

Visão geral

Scripts são pequenos programas em Lua que ampliam seu servidor. Eles rodam em um processo sandbox isolado de Lua 5.5, totalmente separado do bot. Um script nunca acessa o banco de dados, o sistema de arquivos ou outros servidores. Toda capacidade passa por uma API do host em lista de permissões, que devolve o controle ao bot via IPC.

Uma sandbox por script

Sem script carregado, não existe processo.

Chamadas ao host com limite de taxa

As chamadas bot:* e msg:* têm as permissões verificadas pelo bot, não pelo Lua.

Recursos nativos têm prioridade

AutoMod, boas-vindas e tickets sempre rodam. Scripts complementam, não substituem.

Erros ficam contidos

Um script que trava é descarregado ou colocado em quarentena, e o bot continua funcionando.

Não há editor no navegador. Escreva o .lua em um editor de verdade e envie na página Scripts do seu servidor.

Primeiros passos

  1. 1

    Escreva um arquivo .lua localmente

    VS Code, Neovim ou qualquer editor.
  2. 2

    Verifique localmente (opcional)

    script_runner --check file.lua imprime check: ok.
  3. 3

    Envie

    Abra a página Scripts do seu servidor e cole o código ou envie o arquivo .lua (até 64 KiB).
  4. 4

    Teste

    Valida tamanho, codificação, bytecode e APIs proibidas sem executar nada.
  5. 5

    Ative

    Aguarde a aprovação da versão pela equipe e depois clique em Ativar. O bot carrega o script em segundos.
  6. 6

    Defina um canal de log

    Receba ali a saída de bot:log e as notificações de erro.

CLI local

O runner é o mesmo binário que o bot usa.

  • script_runner --check file.lua

    Verificação estática de sintaxe/APIs proibidas sem executar. Imprime 'check: ok'.

  • script_runner --eval 'code'

    Executa um trecho na sandbox localmente. Erros imprimem tipo + mensagem.

  • script_runner --self-test

    Executa os autotestes da sandbox, do protocolo e do socket.

Ciclo de vida e revisão

Os scripts têm versões. Uma versão é congelada quando você a envia e é identificada pelo seu SHA-256. Apenas versões aprovadas podem ser ativadas, e apenas versões ativas são carregadas pelo bot.

  1. 1

    Escrever

    Crie o arquivo .lua localmente no VS Code, Neovim ou qualquer editor. Não há editor no navegador, por decisão de projeto.
  2. 2

    Testar / enviar

    Cole o código ou envie o arquivo .lua na página Scripts do servidor (≤ 64 KiB, sem binário). O teste valida tamanho, codificação, bytecode e APIs proibidas sem executar nada.
  3. 3

    Revisão

    Todo novo script e toda nova versão começam como pendentes. A equipe aprova ou rejeita a revisão exata do código antes que ela possa rodar.
  4. 4

    Ativar

    Você ativa uma versão aprovada. A ativação de uma versão pendente ou rejeitada é recusada. Apenas versões ativas são carregadas pelo bot.
  5. 5

    Executar

    O bot carrega a versão (código + SHA-256, verificado pelo runner) em uma sandbox isolada de Lua 5.5. Os eventos são distribuídos apenas aos handlers registrados com bot:on.
  6. 6

    Atualizar / reverter

    Envie uma nova versão (pendente de novo) ou ative uma versão aprovada mais antiga para reverter. O armazenamento KV permanece.
  7. 7

    Desativar / excluir

    Desativar interrompe o carregamento imediatamente; 'Desativar todos' afeta todos os scripts ativos do servidor. Excluir remove o script, suas versões, o KV e os erros.

Status do script

Exibido como selo em cada script.

  • rascunho

    Criado, ainda sem versão ativa.

  • pendente

    Aguardando algo (ex.: a primeira aprovação); nunca roda como rascunho.

  • ativo

    Uma versão aprovada está ativada e carregada pelo bot.

  • rejeitado

    A equipe rejeitou; o script não será carregado.

  • desativado

    Desativado manualmente (por você, pela equipe, por 'Desativar todos' ou por redução de cota): descarregado.

  • em quarentena

    Desligamento automático após abuso de limites (inundação de taxa, inundação da fila, falhas repetidas). Descarregado e precisa da atenção da equipe.

Revisão de versões

Toda revisão de código passa pela revisão da equipe.

  • pendente

    A equipe ainda não decidiu. Não pode ser ativada.

  • aprovada

    Pode ser ativada. Novos envios de scripts instalados da loja pulam a fila (a versão da listagem já foi aprovada).

  • rejeitada

    A equipe recusou esta revisão do código. Envie uma nova versão.

Cota: 2 scripts ativos por servidor no plano gratuito, 10 com premium. Se a cota diminuir, os scripts ativos mais antigos acima dela são desativados automaticamente e você é avisado pelo canal de log do script.

Handlers e eventos

Registre handlers com bot:on(event, fn). O script informa seus eventos registrados ao carregar, e apenas esses eventos são entregues a ele. Nomes de eventos desconhecidos fazem o carregamento falhar, e um script pode registrar no máximo 8 handlers por evento.

luaLua
bot:on("message_create", function(msg)
  if msg.content == "!ping" then
    msg:reply("pong")
  end
end)

Eventos do tipo mensagem (message_*, automod_check) recebem um objeto de mensagem com métodos, veja Objeto de mensagem.

Chamadas ao host cedem a execução: enquanto um handler espera por bot:kv_get e chamadas parecidas, nenhum segundo evento roda no mesmo script. Novos eventos esperam em uma fila de 32; no estouro, o evento mais antigo é descartado, e uma inundação contínua coloca o script em quarentena.

guild_id é sempre injetado no payload. Os eventos só são entregues a handlers registrados com bot:on. Nomes de eventos desconhecidos fazem o carregamento falhar com um erro de policy. Não existe evento voice_state.

Payloads de eventos

Todo payload traz guild_id. Os campos são tabelas em snake_case minúsculo.

  • message_create

    id, guild_id, channel_id, author_id, author, content, attachments, referenced_id

    Disparado antes de tags/respostas automáticas. Anexos: até 8 entradas { id, filename, size }. referenced_id é 0 quando não há referência de resposta.

  • message_update

    same as message_create

  • message_delete

    channel_id, id

  • message_delete_bulk

    channel_id, ids

    ids é um array com os ids das mensagens excluídas.

  • guild_member_add

    user_id

    Contas de bots são ignoradas.

  • guild_member_remove

    user_id

  • guild_member_update

    user_id

  • reaction_add

    channel_id, id, author_id, user_id, emoji, emoji_id

    Reações de bots são ignoradas. emoji é o nome; emoji_id é 0 para emojis unicode.

  • reaction_remove

    channel_id, id, author_id, user_id, emoji, emoji_id

  • channel_create

    id, name, type

  • channel_update

    id, name, type

  • channel_delete

    id, name

  • role_create

    id, name

  • role_update

    id, name

  • role_delete

    id, name

  • thread_create

    id, name

  • thread_update

    id, name

  • thread_delete

    id

  • invite_create

    code, uses

  • invite_delete

    code

  • guild_ban_add

    user_id

  • guild_ban_remove

    user_id

  • welcome_before

    user_id, username

    Disparado antes da mensagem nativa de boas-vindas. Apenas entradas que não são bots.

  • goodbye_before

    user_id

    Disparado antes da mensagem nativa de despedida.

  • ticket_created

    ticket_id, user_id, channel_id

  • automod_check

    content, channel_id, author_id, id

    Disparado antes do AutoMod nativo. msg:escalate() exclui a mensagem em andamento; a negação nativa sempre prevalece; msg:allow() não faz nada.

  • webhooks_update

    channel_id

  • emoji_update

    count, ids

    ids limitado a 8.

  • tick

    unix

    A cada 60 segundos, entregue apenas a scripts que registraram bot:on("tick"). unix é o horário unix.

APIs do host

Estas chamadas cedem a execução ao bot via IPC. Limites de taxa por script: 30 chamadas ao host / 10 s, mais 5 envios ao Discord / 10 s (reply, channel_send, react, edit, delete, pin, escalate, http_get). Leituras de cache como member_get e guild_get nunca acessam o Discord diretamente.

  • bot:log(msg)

    Escreve no canal de log do script e no log de erros. Conta para o limite de 30 chamadas / 10 s.

  • bot:kv_get(key)

    Retorna o valor JSON armazenado ou nil. Chaves: 1–64 caracteres [A-Za-z0-9_-].

  • bot:kv_set(key, value)

    Armazena até 8 KiB de JSON. 256 chaves por script, 1 MiB por script (8 MiB no premium), 8 MiB por servidor.

  • bot:kv_del(key)

    Exclui uma chave.

  • bot:kv_keys()

    Retorna até 256 chaves, ordenadas.

  • bot:kv_incr(key, delta?)

    Incrementa um número JSON armazenado; delta padrão 1, limitado a ±1.000.000.000.

  • bot:db_exec(sql, binds?)

    Executa uma instrução de escrita ou de esquema (CREATE TABLE/INDEX, INSERT, UPDATE, DELETE, DROP) no banco de dados de scripts do servidor. Binds opcionais: um array de nil, boolean, number ou string, até 8. Retorna { changes, last_insert_rowid }. Problemas de cota, ocupação ou limite retornam { error, kind } em vez de lançar erro; instruções proibidas lançam um erro de policy.

  • bot:db_query(sql, binds?)

    Executa um SELECT com binds opcionais e retorna até 50 linhas, cada uma uma tabela indexada pelo nome da coluna. Sempre use LIMIT. Em caso de falha, retorna { error, kind }, então verifique rows.error.

  • bot:http_get(url)

    Apenas HTTPS GET. O host precisa estar na lista de permissões do servidor. Retorna { status, body, truncated }; body limitado a 16 KiB. A espera não conta para os 100 ms de tempo real do Lua.

  • bot:channel_send(channel_id, text, embed?)

    Envia para qualquer canal do próprio servidor em que o bot possa escrever. Mesmas regras de conteúdo de msg:reply.

  • bot:channel_get(channel_id)

    Leitura de cache: { id, name, type, parent_id }. Apenas o próprio servidor.

  • bot:member_get(user_id)

    Leitura de cache: { id, nick, bot, roles (até 20) }.

  • bot:role_get(role_id)

    Leitura de cache: { id, name, position, color }.

  • bot:guild_get()

    Cache do próprio servidor: { id, name, owner_id, member_count }.

  • bot:self()

    O usuário do bot: { id, username, bot }.

  • bot:has_role(user_id, role_id)

    Leitura de cache, retorna { has: true|false }.

  • bot:channels()

    Lista em cache dos canais do servidor (máx. 50).

  • bot:roles()

    Lista em cache dos cargos do servidor (máx. 50).

  • bot:now()

    Horário unix em segundos.

  • bot:id()

    O UUID deste script. Não cede a execução e não conta para os limites de taxa.

  • bot:message_get(channel_id, message_id)

    Leitura do cache de mensagens do bot (sem busca na rede).

  • bot:can_send(channel_id)

    Retorna { ok: true|false } indicando se o bot pode enviar naquele canal.

O que bot:http_get aceita

  • Somente HTTPS

    URLs http:// são negadas. Sem userinfo (user:pass@host).

  • Lista de permissões do servidor

    O host precisa estar na lista de permissões HTTP do servidor (página Scripts, até 32 hosts). Você mesmo a gerencia.

  • Sem hosts de infraestrutura

    IPs literais, localhost, *.local e *.internal são sempre negados.

  • Resposta

    { status, body, truncated }, body limitado a 16 KiB. Tempo limite de 3 s. Compartilha o limite de 5 por 10 s dos envios ao Discord.

Objeto de mensagem

Eventos de mensagem recebem uma tabela msg mais os campos do payload. Os métodos agem apenas sobre a mensagem do evento em andamento; não é possível buscar e editar mensagens arbitrárias.

Regras de conteúdo em todo lugar: texto de 1 a 2000 bytes, no máximo um embed { title, description, color }, menções resolvem apenas para o autor do evento, @everyone e @here são removidos. Sem arquivos, sem figurinhas.

  • msg:reply(text, embed?)

    Responde no canal do evento. Menções resolvem apenas para o autor do evento; @everyone / @here são removidos. Texto de 1–2000 bytes, no máximo um embed.

  • msg:react(emoji)

    Adiciona uma reação à mensagem do evento.

  • msg:unreact(emoji)

    Remove a própria reação do script.

  • msg:edit(text, embed?)

    Edita a mensagem em andamento. Mesmas regras de conteúdo do reply.

  • msg:delete()

    Exclui a mensagem em andamento.

  • msg:pin() / msg:unpin()

    Fixa/desafixa a mensagem em andamento.

  • msg:escalate()

    Somente automod_check: exclui a mensagem em andamento (ação extra, com limite de taxa). As decisões do AutoMod nativo sempre prevalecem.

  • msg:allow()

    Somente automod_check: marca a mensagem como permitida. Isso não desfaz uma negação nativa; na prática, é um marcador sem efeito.

Limites e cotas

Todos os limites ficam em um único arquivo de configuração compartilhado pelo bot e pelo runner. Eles são aplicados em tempo de execução, não apenas documentados aqui. Os números são os padrões atuais.

  • Linguagem

    Lua 5.5, apenas trechos de texto (bytecode é rejeitado). Sem io/os.file/require/load/debug/coroutine.

  • Processamento

    ~100 ms de tempo real por handler, 10.000.000 de instruções (count hook).

  • Memória

    2 MB por script no gratuito, 8 MB no premium.

  • Tamanho do código

    64 KiB de .lua em UTF-8, sem bytes NUL, sem bytecode.

  • Chamadas ao host

    30 por 10 s por script (bot:log incluído).

  • Envios ao Discord

    5 por 10 s por script (reply, channel_send, react/unreact, edit, delete, pin/unpin, escalate, http_get). 8 negações em 10 s → quarentena.

  • Handlers

    Máx. 8 por evento por script. Nomes de eventos desconhecidos são rejeitados ao carregar.

  • Fila de eventos

    Profundidade 32 por script, descarta o mais antigo no estouro. 8+ descartes em 10 s → quarentena.

  • HTTP

    HTTPS + lista de permissões do servidor, tempo limite de 3 s, body de 16 KiB, sem hosts IP/localhost/internos, sem userinfo.

  • KV

    Chaves 1–64 [A-Za-z0-9_-], valores ≤ 8 KiB de JSON, 256 chaves/script, 1 MiB/script (8 MiB no premium), 8 MiB/servidor.

  • Banco de dados

    Um arquivo SQLite por servidor, compartilhado por todos os seus scripts: 1 MiB (8 MiB no premium), uma instrução por chamada, SQL ≤ 2 KiB, ≤ 8 binds, ≤ 50 linhas, 20 ms por instrução, 64 tabelas e índices. Sem ATTACH, PRAGMA, transações, triggers, views ou WITH. Todo script do servidor pode ler e excluir todas as tabelas.

  • Scripts ativos

    2 por servidor no gratuito, 10 no premium. Os scripts ativos mais antigos que excederem são desativados automaticamente.

  • Versões

    Quantidade ilimitada por script; toda nova versão fica pendente até a equipe aprovar.

  • Menções

    Apenas o autor do evento. @everyone / @here removidos. Sem arquivos, sem figurinhas.

  • Isolamento

    3 falhas (timeout/memory/policy/runtime) → worker isolado próprio (máx. 4), senão quarentena + descarregamento.

  • Log de erros

    Últimas 24 h visíveis no painel, entradas apagadas após 7 dias.

  • Proibido

    Sem voice_state, sem APIs mod_* (ban/kick/timeout), sem acesso entre servidores, sem banco de dados/sistema de arquivos, sem monetização.

  • AutoMod

    O AutoMod nativo roda primeiro e sempre prevalece sobre os scripts.

Validação

Antes de uma versão ser armazenada, o backend executa verificações estáticas. O teste faz o mesmo sem salvar. A própria sandbox é a segunda linha de defesa: globais proibidas simplesmente não existem em tempo de execução.

  • Tamanho / codificação

    Não vazio, ≤ 64 KiB, UTF-8 sem bytes NUL.

  • Bytecode

    Qualquer coisa que comece com a assinatura de bytecode do Lua é rejeitada.

  • APIs proibidas

    A verificação estática rejeita: load(, loadfile, dofile, require(, os.execute, io.open, debug., string.dump, loadstring, getfenv, setfenv, package., coroutine., ffi., jit.

  • Sandbox em tempo de execução

    Mesmo que algo passe pela verificação estática, a sandbox simplesmente não expõe essas globais: a chamada falha com um erro de policy.

Built-ins disponíveis: a biblioteca padrão de Lua sem acesso a arquivos. string, table, math, tostring, tonumber, type, pairs, ipairs, os.time, os.clock, os.difftime e bot.

Erros e quarentena

Todo erro de handler é registrado com um tipo e exibido na página de detalhes do script (últimas 24 h). As entradas são apagadas após 7 dias.

  • runtime

    Um erro de Lua no seu handler (acesso a nil, argumentos inválidos, …). A mensagem inclui o texto do erro de Lua.

  • timeout

    O handler excedeu os 100 ms de tempo real ou uma chamada IPC expirou (1 s).

  • memory

    O script excedeu seu limite de memória.

  • policy

    O script tentou algo não permitido: evento desconhecido, handlers demais, API não permitida, payload grande demais.

Abusos repetidos escalam automaticamente: 3 falhas (timeout, memory, policy, runtime) movem o script para um worker isolado próprio. Se o mau comportamento continuar, ou se não houver vaga isolada livre (máx. 4), o script é colocado em quarentena: descarregado e marcado no painel. Inundações de taxa (8 envios ao Discord negados ou 8 descartes na fila em 10 s) causam quarentena imediata. Você é avisado pelo canal de log do script ou por DM.

Lado operacional: o bot pode ser pausado globalmente por um kill switch sem reinício, e um sinal scripts:updated recarrega versões alteradas em segundos. Ambos são ações da equipe.

Loja

A loja permite compartilhar scripts publicamente e instalar scripts de outros servidores. Publicar e instalar criam cópias. Instalar uma listagem cria um script independente no seu servidor, sem vínculo com o código do autor.

  • Publicar

    Exige um script ativo com uma versão aprovada, uma descrição (10–512 caracteres) e 1–8 tags ([a-z0-9-], 1–24 caracteres). Você precisa aceitar os termos da loja uma vez antes da primeira publicação.

  • Instalar

    Instalar copia a listagem para o seu servidor como um script próprio (rascunho, versão pré-aprovada, nome próprio com sufixo se já estiver em uso). O KV não é copiado. O contador de instalações da listagem aumenta.

  • Despublicar

    Remove a listagem da loja. As cópias existentes permanecem e continuam rodando; apenas não recebem mais atualizações.

  • Sem dinheiro

    Vendas, paywalls, links de doação/cripto e monetizações parecidas na descrição ou no código são rejeitados na publicação e podem fazer o script ser banido.

  • Denúncias

    Qualquer pessoa com acesso ao servidor pode denunciar uma listagem informando um motivo. A equipe vê uma fila de denúncias abertas e as fecha após a revisão.

  • Limites

    A lista da loja mostra até 50 listagens por consulta (pesquisa, tag, ordenação por instalações ou mais recentes). A cota normal de scripts do servidor vale para instalações.

Exemplos

Selecione um exemplo para ver o código.