REFERÊNCIA
Redeye Script
Linguagem dinâmica e tipada-em-runtime para criar comandos personalizados, cronjobs e webhooks no Discord. Sintaxe semelhante a Kotlin/JavaScript, sandbox isolado por servidor, sem build step.
01 · Sintaxe
Sintaxe básica
Scripts são executados em um sandbox isolado a cada invocação. Variáveis declaradas dentro do script só vivem durante aquela execução; pra persistir use storage.
Variáveis
var · constvar nome = "Redeye" // mutável
const pi = 3.14 // constante
nome = "Outro" // ok
pi = 3 // erro em runtime
Apenas as palavras-chave var e const existem; val e let não são reconhecidos.
Condicionais
if · elseif user.name == "Victor" {
reply "Olá, criador!"
} else if user.isBot {
reply "Você é um bot."
} else {
reply "Olá, {user.name}!"
}
Funções definidas pelo usuário
funfun dobro(n) {
return n * 2
}
reply "O dobro de 5 é {dobro(5)}"
Limites profundidade máxima de chamada é 64 e o total de passos por execução é 50.000.
Null coalescing
??var target = args[0] ?? user
reply "Alvo: {target.name}"
O operador ?? retorna o lado direito se o esquerdo for null.
Atalho de chamada
bare-callFunções de efeito colateral como reply aceitam sintaxe sem parênteses no nível do statement:
reply "Olá, mundo" // bare-call
reply("Olá, mundo") // chamada explícita - equivalente
02 · Tipos
Tipos primitivos
Seis tipos exposto à linguagem. typeof() também pode retornar "function" para funções definidas pelo usuário e "proxy" para handlers nativos como storage.
| Tipo | Exemplo | Descrição |
|---|---|---|
number |
42, 3.14, -1.5 |
Inteiros e decimais (IEEE 754) |
string |
"texto" |
Texto Unicode entre aspas duplas |
boolean |
true, false |
Verdadeiro ou falso |
null |
null |
Ausência de valor |
list |
list(1, 2, 3) |
Lista ordenada (criar com a função list) |
object |
{ nome: "x", n: 20 } |
Objeto com chaves string e valores arbitrários |
String interpolation
{expr}var nome = "Victor"
reply "Olá, {nome}!" // Olá, Victor!
reply "1 + 2 = {1 + 2}" // 1 + 2 = 3
Use {expressão} dentro de strings pra interpolar valores. Pra um literal {, escape com \{.
Objetos
literalvar perfil = {
nome: "Victor",
nivel: 10,
vip: true
}
reply "{perfil.nome} é nível {perfil.nivel}"
perfil["nivel"] = 11 // index assignment também funciona
Sintaxe o separador é : (não =). Não existe literal de array com [] - use list(...).
03 · Operadores
Operadores
| Operador | Descrição | Exemplo |
|---|---|---|
+ |
Soma ou concatenação |
1 + 2, "a" + "b" |
- |
Subtração |
10 - 3 |
* |
Multiplicação |
4 * 5 |
/ |
Divisão |
10 / 3 |
% |
Resto |
10 % 3 |
== |
Igualdade |
x == 5 |
!= |
Diferença |
x != 5 |
< > <= >= |
Comparação |
x > 10 |
&& |
E lógico (curto-circuito) |
x > 0 && x < 10 |
|| |
Ou lógico (curto-circuito) |
x == 0 || x == 1 |
! |
Negação |
!flag |
?? |
Null coalescing |
valor ?? "padrão" |
Atenção operadores & e | sozinhos são erro de lexer. Use sempre && / ||.
04 · Strings
Métodos de string
Acessíveis via dot/call em qualquer valor string.
| Método | Tipo | Descrição |
|---|---|---|
.length |
number |
Quantidade de caracteres |
.upper() |
string |
Caixa alta |
.lower() |
string |
Caixa baixa |
.trim() |
string |
Remove espaços nas pontas |
.contains(s) |
boolean |
Se contém a substring |
.startsWith(s) |
boolean |
Se começa com |
.endsWith(s) |
boolean |
Se termina com |
.replace(de, pra) |
string |
Substitui todas as ocorrências |
.substring(ini) |
string |
Recorte do índice até o fim |
.substring(ini, fim) |
string |
Recorte de ini (incl) a fim (excl) |
.split(sep) |
list |
Divide em lista de strings |
.split(sep, limit) |
list |
Divide com limite de partes |
Limite strings são limitadas a 1 MB de tamanho durante a execução.
05 · Listas
Métodos de lista
| Método | Tipo | Descrição |
|---|---|---|
.length |
number |
Quantidade de itens |
.isEmpty |
boolean |
Se está vazia |
.first |
any |
Primeiro item (null se vazia) |
.last |
any |
Último item (null se vazia) |
.push(item) |
void |
Adiciona ao final |
.pop() |
any |
Remove e retorna o último |
Acesso e atribuição por índice
var nums = list(10, 20, 30)
reply nums[0] // 10
nums[1] = 99 // index assignment
reply nums.length // 3
Limite listas são limitadas a 10.000 elementos.
06 · Built-ins
Funções built-in
Saída
| Função | Descrição |
|---|---|
reply(msg) |
Envia uma mensagem (string ou embed). Limite 5 por execução. |
Matemática
| Função | Descrição |
|---|---|
random() |
Decimal aleatório no intervalo [0.0, 1.0) |
random(max) |
Inteiro aleatório no intervalo [0, max) - max é exclusivo |
random(min, max) |
Inteiro aleatório no intervalo [min, max] - ambos inclusivos |
floor(n) |
Arredonda pra baixo |
ceil(n) |
Arredonda pra cima |
round(n) |
Arredonda pro mais próximo |
abs(n) |
Valor absoluto |
min(a, b, ...) |
Menor valor (variádica) |
max(a, b, ...) |
Maior valor (variádica) |
Conversão e utilidades
| Função | Descrição |
|---|---|
number(val) |
Converte para number |
string(val) |
Converte para string |
typeof(val) |
Retorna o tipo como string |
len(val) |
Tamanho de string, lista ou objeto |
list(a, b, ...) |
Cria uma lista (variádica) |
now() |
Timestamp atual em milissegundos (epoch) |
07 · Contexto
Objetos de contexto
Esses objetos estão disponíveis automaticamente em qualquer script invocado por comando.
user
quem executou| Propriedade | Tipo | Descrição |
|---|---|---|
user.name |
string |
Nome de exibição |
user.id |
string |
ID do usuário |
user.asMention |
string |
Menção (@user) |
user.avatar |
string |
URL do avatar |
user.isBot |
boolean |
Se é um bot |
user.balance |
number |
Saldo de iris |
user.aboutMe |
string |
Texto do about me |
user.hasRole(nome) |
boolean |
Se tem o cargo (busca por nome) |
guild
servidor atual| Propriedade | Tipo | Descrição |
|---|---|---|
guild.name |
string |
Nome do servidor |
guild.id |
string |
ID do servidor |
guild.memberCount |
number |
Quantidade de membros |
guild.getMemberById(id) |
user / null |
Busca um membro pelo ID |
guild.getRoleById(id) |
role / null |
Busca um cargo pelo ID |
guild.addRoleToMember(uid, rid) |
void |
Adiciona o cargo (conta no limite de Discord calls) |
guild.removeRoleFromMember(uid, rid) |
void |
Remove o cargo (conta no limite de Discord calls) |
channel
canal atual| Propriedade | Tipo | Descrição |
|---|---|---|
channel.name |
string |
Nome do canal |
channel.id |
string |
ID do canal |
channel.asMention |
string |
Menção (#canal) |
role
objeto retornado por getRoleById| Propriedade | Tipo | Descrição |
|---|---|---|
role.id |
string |
ID do cargo |
role.name |
string |
Nome |
role.asMention |
string |
Menção (@cargo) |
role.color |
string |
Cor hexadecimal |
08 · Args
Argumentos do comando
Os argumentos são acessados via args, uma lista posicional. Tipagem é definida nas opções do script (no painel) - user, number, string... - e o bot já entrega o valor já resolvido.
// Comando configurado com 2 opções: target (user) e amount (number)
var alvo = args[0] ?? user // padrão: quem executou
var qtd = args[1] ?? 1
reply "{alvo.asMention} recebeu {qtd} pontos!"
09 · Storage
Storage persistente
Key-value persistente compartilhado entre todos os scripts do mesmo servidor. Aceita string, number, boolean, list e object como valor.
| Método | Descrição |
|---|---|
storage.get(key) |
Lê um valor (null se não existir) |
storage.set(key, value) |
Salva um valor |
storage.delete(key) |
Remove um valor |
Exemplo - perfil persistente
var dados = storage.get(user.id)
if dados == null {
storage.set(user.id, { pontos: 0, nivel: 1 })
reply "Conta criada!"
} else {
dados.pontos = dados.pontos + 1
storage.set(user.id, dados)
reply "Você tem {dados.pontos} pontos!"
}
Limites plano free: até 500 chaves por servidor; cada valor pode ter no máximo 4 KB serializado. Tiers Premium aumentam ambos.
10 · Secrets
Secrets (chaves de API)
Valores criptografados configurados no painel e injetados na execução. Apenas leitura - scripts não podem sobrescrever.
var apiKey = secrets.get("MINHA_API_KEY")
var res = fetch("https://api.exemplo.com/dados?key={apiKey}")
reply "Resposta: {res.status}"
11 · Embeds
Embeds
Mensagens ricas com layout do Discord. O bloco embed { ... } é uma builder call - pode ser passado direto pra reply.
reply embed {
title "Título do embed"
description "Uma descrição legal"
color "#dc2626"
thumbnail user.avatar
field("Campo 1", "Valor 1", true)
field("Campo 2", "Valor 2", true)
footer "Redeye Bot"
footerIcon user.avatar
}
| Propriedade | Descrição |
|---|---|
title |
Título do embed |
description |
Descrição |
color |
Cor em hex (#RRGGBB) |
url |
Link no título |
thumbnail |
URL de imagem pequena |
image |
URL de imagem grande |
footer |
Texto do rodapé |
footerIcon |
URL do ícone do rodapé |
author |
Nome do autor |
authorIcon |
URL do ícone do autor |
authorUrl |
Link do autor |
field(nome, valor, inline?) |
Adiciona um campo |
12 · HTTP
HTTP (fetch)
Requisições GET para APIs externas. Apenas HTTPS. JSON é parseado automaticamente; resposta não-JSON volta como string.
var res = fetch("https://api.exemplo.com/dados")
// res já vem parseado se for JSON
reply "Resultado: {res.campo}"
| Restrição | Valor |
|---|---|
Método |
GET (somente) |
Protocolo |
HTTPS (somente) |
Hosts bloqueados |
localhost, IPs privados, link-local |
Timeout de conexão |
3 segundos |
Timeout total |
5 segundos |
Tamanho máximo da resposta |
256 KB |
Requests por execução |
3 |
13 · Cargos
Manipulação de cargos
Adicionar e remover cargos é uma chamada à API do Discord, contabilizada num contador compartilhado de 10 chamadas por execução.
var role = guild.getRoleById("123456789")
if role != null && !user.hasRole(role.name) {
guild.addRoleToMember(user.id, role.id)
reply "{role.asMention} adicionado a {user.asMention}"
}
Permissões o bot precisa ter cargo acima do alvo e a permissão Manage Roles pra que a operação funcione.
14 · Cronjobs
Cronjobs (premium)
Scripts que rodam automaticamente em intervalos definidos. Disponível em servidores com tier Macula (10), Retina (50) ou Sclera (200 cronjobs por servidor).
Aceita dois formatos de schedule:
| Formato | Exemplo | Descrição |
|---|---|---|
Intervalo simples |
5m, 1h, 1d |
Roda a cada N minutos, horas ou dias |
Cron parcial |
*/15 * * * * |
Sintaxe cron - aqui, a cada 15 minutos |
Sandbox cronjobs não têm user, channel nem args disponíveis. Pra postar mensagens, você configura um canal-alvo ou usa um webhook.
15 · Limites
Limites de execução
Aplicados por execução pra manter o sandbox justo. Atingir qualquer limite aborta o script com erro.
| Recurso | Limite |
|---|---|
Replies por execução |
5 |
Fetch requests por execução |
3 |
Discord API calls por execução |
10 |
Profundidade de chamada de função |
64 |
Passos de execução |
50.000 |
Tamanho máximo de string |
1 MB |
Tamanho máximo de lista |
10.000 elementos |
Resposta HTTP máxima |
256 KB |
Timeout de conexão (fetch) |
3 segundos |
Timeout total (fetch) |
5 segundos |
Storage: chaves (free) |
500 |
Storage: tamanho por valor |
4 KB |
16 · Exemplos
Exemplos completos
Cara ou coroa
if random(2) == 0 {
reply "Cara!"
} else {
reply "Coroa!"
}
Contador persistente
var target = args[0] ?? user
var dados = storage.get(target.id) ?? { count: 0 }
dados.count = dados.count + 1
storage.set(target.id, dados)
reply "{target.name} agora tem {dados.count} pontos."
API externa
var piada = fetch("https://v2.jokeapi.dev/joke/Any?type=single&lang=pt")
reply piada.joke
Embed com dados do usuário
var target = args[0] ?? user
reply embed {
title target.name
description target.aboutMe ?? "Sem about me"
color "#dc2626"
thumbnail target.avatar
field("Saldo", "{target.balance} iris", true)
field("Bot?", "{target.isBot}", true)
}
Sistema de nível simples
var perfil = storage.get("nivel_{user.id}") ?? { xp: 0, nivel: 1 }
perfil.xp = perfil.xp + random(5, 15)
if perfil.xp >= perfil.nivel * 100 {
perfil.nivel = perfil.nivel + 1
perfil.xp = 0
reply "Subiu para nível {perfil.nivel}!"
} else {
reply "XP: {perfil.xp}/{perfil.nivel * 100}"
}
storage.set("nivel_{user.id}", perfil)
Configure scripts, cronjobs, secrets e webhooks no painel web. Pra contexto sobre os sistemas do bot que os scripts podem orquestrar (economia, broker, empresas), veja o guia.