Sistemas Descentralizados/03 - Nostr5 min
Kinds de Eventos e Mensagens
- Que problema isso resolve?
- Quando usar / quando NÃO usar?
- Qual o principal trade-off?
- Como isso falha em produção?
Tabelas de consulta do NIP-01. Para o conceito por trás, ver 2. Eventos e Chaves.
Conceito
As 4 faixas de kind — e por que elas existem
Este é o detalhe mais elegante do NIP-01: o número do kind não é só um rótulo, é uma instrução de armazenamento para o relay. A faixa em que ele cai determina o comportamento, sem precisar de campo extra nem de configuração.
| Faixa | Tipo | O relay deve |
|---|---|---|
1000 ≤ n < 10000, 4 ≤ n < 45, n = 1, n = 2 |
Regular | guardar todos |
10000 ≤ n < 20000, n = 0, n = 3 |
Replaceable | guardar só o mais recente por (pubkey, kind) |
20000 ≤ n < 30000 |
Ephemeral | não guardar — só repassar a quem está ouvindo |
30000 ≤ n < 40000 |
Addressable | guardar só o mais recente por (pubkey, kind, tag d) |
Repare no que isso resolve:
- Replaceable é como o perfil (
kind: 0) e a lista de seguidos (kind: 3) funcionam sem acumular lixo. Você não "edita" o perfil — publica um novo, e o relay descarta o anterior. É estado por sobrescrita, não por mutação. - Addressable adiciona uma chave secundária (a tag
d), permitindo vários documentos editáveis do mesmo tipo. É como um artigo (kind: 30023) tem um endereço estável (naddr) e continua editável. - Ephemeral é fire-and-forget: usado por autenticação (
kind: 22242) e por RPC entre apps (kind: 24133), onde persistir seria vazamento, não feature.
Empate de timestamp em replaceable? Regra do NIP-01: fica o de id menor em ordem lexicográfica. Determinístico, sem coordenação — todo relay chega ao mesmo resultado sozinho.
Kinds mais usados
| kind | O que é | NIP |
|---|---|---|
0 |
Metadados do usuário (perfil) | 01 |
1 |
Nota de texto curta | 10 |
3 |
Lista de seguidos | 02 |
5 |
Pedido de deleção | 09 |
6 / 16 |
Repost / repost genérico | 18 |
7 |
Reação (curtida) | 25 |
9 |
Mensagem de chat | C7 |
11 |
Thread de fórum | 7D |
13 |
Seal (camada interna do gift wrap) | 59 |
14 / 15 |
DM privada / arquivo em DM | 17 |
20 / 21 / 22 |
Foto / vídeo / vídeo vertical | 68, 71 |
1059 |
Gift Wrap (envelope anônimo) | 59 |
1111 |
Comentário genérico | 22 |
1984 |
Denúncia | 56 |
1985 |
Rótulo (label) | 32 |
9734 / 9735 |
Pedido de zap / recibo de zap | 57 |
10002 |
Lista de relays (outbox model) | 65 |
10050 |
Relays para receber DM | 17, 51 |
22242 |
Autenticação no relay (efêmero) | 42 |
24133 |
Nostr Connect / remote signing | 46 |
27235 |
HTTP Auth | 98 |
30023 |
Artigo longo (Markdown) | 23 |
30078 |
Dados específicos de aplicação | 78 |
31922–31925 |
Eventos de calendário e RSVP | 52 |
34550 |
Definição de comunidade | 72 ⚠️ |
A tabela oficial tem mais de 150 entradas e não é exaustiva — o registro legível por máquina fica em registry-of-kinds. Ou seja: o espaço de
kindé aberto, e a colisão é evitada por convenção social, não por autoridade.
Mensagens Cliente → Relay
| Mensagem | Para quê | NIP |
|---|---|---|
["EVENT", <evento>] |
publicar | 01 |
["REQ", <sub_id>, <filtros...>] |
pedir histórico e assinar novidades | 01 |
["CLOSE", <sub_id>] |
cancelar a inscrição | 01 |
["AUTH", <evento kind 22242>] |
responder ao desafio do relay | 42 |
["COUNT", <sub_id>, <filtros...>] |
contar sem baixar | 45 |
Mensagens Relay → Cliente
| Mensagem | Significa | NIP |
|---|---|---|
["EVENT", <sub_id>, <evento>] |
toma um evento dessa inscrição | 01 |
["OK", <id>, <bool>, <motivo>] |
aceitei / recusei seu evento | 01 |
["EOSE", <sub_id>] |
acabou o histórico — daqui pra frente é ao vivo | 01 |
["CLOSED", <sub_id>, <motivo>] |
encerrei sua inscrição, e por quê | 01 |
["NOTICE", <mensagem>] |
recado legível por humano | 01 |
["AUTH", <desafio>] |
autentique-se | 42 |
["COUNT", <sub_id>, {"count": n}] |
a contagem pedida | 45 |
O EOSE é a peça de design mais interessante do conjunto. Uma única inscrição serve histórico e tempo real no mesmo canal, e o EOSE é apenas o marcador entre os dois. Não há "endpoint de histórico" e "websocket de updates" — há um só fluxo, com uma fronteira anunciada.
Motivos padronizados de OK e CLOSED
O terceiro campo do OK e o do CLOSED começam com um prefixo legível por máquina, seguido de texto livre:
duplicate · pow · blocked · rate-limited · invalid · restricted · mute · error
["OK", "b1a649eb...", false, "rate-limited: slow down, 10 events/min"]
["CLOSED", "sub1", "auth-required: precisa autenticar para ler DMs"]
O padrão — prefixo para a máquina, resto para o humano — é o mesmo dos status codes HTTP com corpo de erro, e resolve o mesmo problema: dar ao cliente algo para decidir programaticamente sem perder a mensagem diagnóstica.
Trade-offs
A faixa do kind codificar semântica de armazenamento é econômico e irreversível. Economia: zero campos extras, zero configuração, e um relay implementa as quatro políticas com um if na faixa. Irreversibilidade: um kind publicado na faixa errada não pode ser reclassificado depois sem quebrar quem já o armazena.
O custo maior é a numeração como espaço compartilhado global. Não há registro autoritativo — dois projetos podem escolher o mesmo kind para coisas diferentes, e o conflito só aparece quando os dados se cruzam num relay. A defesa é convenção e o registro comunitário, o que é frágil por construção. É o preço de não ter autoridade, coerente com o resto do desenho.
Exemplo prático
Uma sessão completa, do primeiro byte:
→ ["REQ","feed",{"kinds":[1],"authors":["3bf0c63f..."],"limit":20}]
← ["EVENT","feed",{...}] # 20 eventos do histórico
← ["EOSE","feed"] # acabou o passado
← ["EVENT","feed",{...}] # 10 min depois: post novo, ao vivo
→ ["EVENT",{"kind":1,"content":"oi","sig":"..."}]
← ["OK","a1b2c3...",true,""]
→ ["EVENT",{"kind":1,"content":"oi","sig":"..."}] # mandei de novo
← ["OK","a1b2c3...",true,"duplicate: already have this event"]
Repare na última linha: reenviar o mesmo evento devolve true, não erro. E é correto — o id é o hash do conteúdo, então "já tenho" e "acabei de guardar" levam ao mesmo estado final.
Ou seja: publicar no Nostr é idempotente por construção, e de graça. Não precisou de chave de idempotência como no exemplo de 1. O que é um Sistema Distribuído, porque o identificador é o conteúdo. É a mesma propriedade que faz o retry seguro funcionar — obtida por endereçamento por conteúdo em vez de por protocolo.