Pular para o conteúdo

REST

Tudo o que o App escreve passa por app.rest — as mesmas rotas do produto, com uma moldura que aceita credencial de App. Não existe um /v1 paralelo: duas rotas para o mesmo recurso seriam duas verdades de autorização.

O objeto que faz tudo

await app.rest.whoAmI();                                // o smoke da credencial
await app.rest.getServer({ serverId });                 // retrato + revision
await app.rest.listMembers({ serverId });
await app.rest.listMessages({ serverId, channelId, beforeId });
await app.rest.sendMessage({ serverId, channelId, content, clientRef });
await app.rest.editMessage({ serverId, channelId, messageId, content });
await app.rest.deleteMessage({ serverId, channelId, messageId });
await app.rest.toggleReaction({ serverId, channelId, messageId, emoji: "👍" });
await app.rest.createChannel({ serverId, name, type: "text", revision });
await app.rest.updateChannel({ serverId, channelId, revision, name });
await app.rest.moveChannel({ serverId, channelId, revision, categoryId });
await app.rest.archiveChannel({ serverId, channelId, revision });
await app.rest.createRole({ serverId, name, permissions, revision });
await app.rest.updateRole({ serverId, roleId, revision, permissions });
await app.rest.deleteRole({ serverId, roleId, revision });
await app.rest.addMemberRole({ serverId, userId, roleId, revision });
await app.rest.removeMemberRole({ serverId, userId, roleId, revision });
await app.rest.addAppRole({ serverId, appId, roleId, revision });
await app.rest.removeAppRole({ serverId, appId, roleId, revision });
await app.rest.getSigningKeys();

Cada um deles já carrega a credencial, a versão da API, a retentativa e o respeito ao Retry-After — os tetos, e o que o 429 traz no corpo, estão em Limites e ritmo. Precisa de algo que ainda não virou método? app.rest.request() fala com qualquer rota com o mesmo tratamento de 429 e o mesmo erro — e continua sendo o SDK, não um caminho paralelo.

Fora desta lista há mais quatro métodos, os de registrar comando: eles têm página própria em Comandos, porque o que decide o que você escreve ali não é a rota, é a árvore de opções.

  • Identificadores públicos são snowflakes em string. Não os converta para número.
  • Toda recusa vira TrivoError, com code de vocabulário fechado. Ramifique no code, nunca na frase.

Ler o servidor, e o que o retrato responde

can é o que o ator desta chamada alcança neste servidor, para desenhar interface. Quem decide de verdade continua sendo o servidor, a cada mutação. Para um App, o que ele pode é a interseção dos cargos que ele recebeu com os escopos que a instalação autorizou.

myRank é o posto do ator, e para um App ele é o do cargo mais alto que ele tiver — como o de qualquer membro, e não um valor fixo. Quem impede a escalada não é a posição, é o teto: sem o escopo autorizado, cargo nenhum, por mais alto, produz capacidade. Os dois eixos estão em Permissões e escopos.

O que vem no retrato

  • channels é o que o ator — é esta lista que desenha uma barra lateral, e um canal que o App não alcança simplesmente não está nela.
  • managedChannels só aparece com gerenciar_canais, e traz os canais que existem, restritos inclusive. Ausente é diferente de vazio: vazio seria "você administra e não há canal nenhum". É existência, nunca conteúdo — um canal aqui e não em channels é um canal que o seu App pode mudar e não pode ler.
  • categories, roles e revision: a revisão é a que toda mutação administrativa precisa devolver.
  • can, myRank e isOwner descrevem o ator. E server.notificationDefault é o aviso que a casa sugere a quem nunca escolheu nada — vale para o App instalado como vale para gente, e não é decisão de moderação.

Mensagens

Paginação

Página fixa de 50, sem limit e sem cursor. Para subir o histórico, mande em antesDe o publicId da mensagem mais antiga que você já tem.

Reações

const { count, reacted } = await app.rest.toggleReaction({
  serverId,
  channelId,
  messageId,
  emoji: "👍",
});

É um toggle, e não um par de métodos: a identidade de uma reação é mensagem mais emoji mais quem reagiu, e o App só alcança a linha dele. Chamar de novo com o mesmo emoji tira a reação, e o que volta é o agregado — count e reacted.

O emoji pode ser qualquer um do conjunto RGI do Unicode — o mesmo que um teclado produz: sequências de família, tons de pele e bandeiras inclusive. O que não for emoji volta como INVALID_INPUT.

Mande a grafia totalmente qualificada (❤️, e não ). O servidor conserta as variantes que reconhece e guarda sempre a canônica — duas grafias do mesmo emoji seriam dois chips na mesma mensagem —, mas o que volta na listagem é a canônica, e é por ela que se compara.

Os seis do seletor rápido, para quem quiser começar por eles:

👍 ❤️ 😂 😮 😢 🎉

Referência de transporte

As rotas, e o que cada uma responde

O que viaja no fio, para transparência, depuração e compatibilidade — não é um segundo jeito de construir App. Se você está escrevendo um App, o SDK já faz isto.

Corpo e resposta em application/json; credencial em Authorization: Bearer, nunca em query string. É o que app.rest chama por baixo.

Servidor

RotaResposta
GET /api/servidores/{servidor}server, channels, categories, roles, revision, can, myRank, isOwner.
GET /api/servidores/{servidor}/membrosmembers, roles (sem permissions), truncated. Até 500 pessoas, sem paginação; os Apps instalados vêm na mesma lista, com isApp: true.

Mensagens

RotaCorpoResposta
GET /api/servidores/{servidor}/canais/{canal}/mensagensQuery antesDe (opcional).messages (50 por página, cronológico crescente) e reactions, um mapa pelo publicId da mensagem.
POST /api/servidores/{servidor}/canais/{canal}/mensagenscontent; opcionais clientRef e attachments. attachments reaproveita a chave de um anexo que já existe: o App não sobe arquivo, porque a rota de anexo não aceita Bearer.201 com message, e moderationWarning quando houver.
PATCH /api/servidores/{servidor}/canais/{canal}/mensagens/{mensagem}content.message. Só alcança mensagem do próprio App.
DELETE /api/servidores/{servidor}/canais/{canal}/mensagens/{mensagem}Nenhum.{ "ok": true }. A própria sempre; a dos outros exige gerenciar_mensagens.

Canais e cargos

Toda mutação administrativa exige revision, e responde com a coleção inteira mais a revisão nova. categoryId é mutuamente exclusivo com os outros campos de edição de canal: mandar os dois juntos é INVALID_INPUT. E dar cargo a alguém exige posto maior que o da pessoa — para um App, o do cargo mais alto que ele tiver.

RotaCorpoResposta
POST /api/servidores/{servidor}/canaisname, type, revision; opcional voiceLimit.201 com channels e revision.
PATCH /api/servidores/{servidor}/canais/{canal}revision; e name / voiceLimit / ageRestricted ou categoryId.channels e revision; com categoryId, também categories.
DELETE /api/servidores/{servidor}/canais/{canal}revision.channels e revision. Arquiva: a linha fica no banco para a moderação, e some do produto.
POST /api/servidores/{servidor}/cargosname, permissions, revision; opcionais color e displaySeparately.201 com roles e revision.
PATCH /api/servidores/{servidor}/cargos/{cargo}revision; opcionais name, color, permissions, displaySeparately.roles e revision.
DELETE /api/servidores/{servidor}/cargos/{cargo}revision.roles e revision.

Cargos de membros e de Apps

RotaResposta
PUT /api/servidores/{servidor}/membros/{conta}/cargos/{cargo}roles e revision.
DELETE /api/servidores/{servidor}/membros/{conta}/cargos/{cargo}roles e revision.
PUT /api/servidores/{servidor}/apps/{app}/cargos/{cargo}apps e revision. Repare: apps, não roles.
DELETE /api/servidores/{servidor}/apps/{app}/cargos/{cargo}apps e revision.

A revisão e o conflito

revision é controle de concorrência otimista. Você lê o retrato do servidor, mexe, e devolve a revisão que leu. Se outra pessoa mudou nesse meio-tempo:

import { TrivoError } from "@trivo/sdk";

try {
  await app.rest.createChannel({ serverId, name: "geral", type: "text", revision });
} catch (erro) {
  if (erro instanceof TrivoError && erro.is("STALE_REVISION")) {
    // erro.currentRevision é a revisão de agora. QUEM decide reenviar é você:
    // repetir cegamente sobrescreve a mudança de outra pessoa, que é
    // exatamente o que a revisão existe para impedir.
  }
}

O SDK não decide por você aqui, de propósito: releia o retrato, decida, e só então reenvie.

O que esta credencial não abre

Algumas rotas existem e recusam Bearer com 401: conversa privada, moderação sobre pessoas, categorias, ordenação, subir anexo e a configuração do próprio App, entre outras. A lista inteira, com o motivo de cada corte, está em O que um App nunca alcança.