Pular para o conteúdo
Gamerspelo Brasil
Conferindo…

OFICINA · GAMERS PELO BRASIL

Cópia pública do guia canônico. SDK de testes com API publicada. Chave e origens são fornecidas pelo operador; login Google depende da configuração do ambiente.

Edição pública gerada de backend/sdk/README.md. Revisão oficina-2026-10-23.3; SDK 0.1.0-test.3. Links internos não distribuídos são identificados.

SDK de troféus — versão de testes

Decisão de Murillo em 2026-10-17: o backend passa a centralizar conquistas de todos os jogos. Novas integrações enviam apenas conquistas, sem score ou diário de partida. Cada jogo dispõe de bronze-1, bronze-2, bronze-3, prata-1, prata-2, ouro-1 e diamante-1. São sete conquistas distintas por jogo, cada uma guardada uma vez por jogador; não são sete premiações globais para dividir entre jogadores. Os critérios de conquista são responsabilidade do jogo.

Fluxo implementado

  1. Murillo cadastra o jogo e suas origens com a CLI administrativa e entrega a chave pública ao criador. O jogo instala o módulo JavaScript.
  2. Ao ocorrer a conquista, ganhar(slot) cria um token aleatório de 256 bits e um UUID v4. Envia somente UUID, slot e SHA-256 do token à API com a chave. Nenhum jogador, score, cookie ou evento intermediário sai do jogo.
  3. A API valida jogo, origem, chave, slot e reenvios, guarda o hash no PostgreSQL e informa o prazo e a página central. O SDK monta o link com o token no fragmento: /trofeus/#token=.... O token não vai na query nem no GET.
  4. O jogador abre o link. A página central retira o fragmento do endereço e mantém uma fila em sessionStorage, inclusive durante reload. Cada resposta confirma apenas o token enviado; links que chegam durante o POST permanecem na fila. O GET não concede troféu. A confirmação envia o token em POST à API, com credentials include e CORS restrito ao hub.
  5. O backend reconhece a identidade pelo cookie HttpOnly existente, confere o hash e grava a conquista em transação. Link consumido por outro jogador é recusado. A coleção reúne os jogos, sem ranking por score.

O servidor não lê storage/cache do navegador. localStorage pertence à origem que o criou; cookies são enviados pelo navegador conforme domínio e atributos. Referências técnicas consultadas em 2026-10-17: cookies e localStorage. Desde a publicação de 2026-10-21, a central pertence a HUB_ORIGIN, no hub. O endereço antigo PUBLIC_ORIGIN/trofeus/ permanece como redirecionamento 302 sem HTML ou fragmento próprio, preservando links e SDKs existentes. O campo claim_url da API v1 permanece inalterado por compatibilidade. O cookie continua host-only na API; o hub usa credentials include. A fila antiga da origem da API não é copiada: reabra o link no jogo ou use renovarLink se venceu. Troféus já persistidos continuam na coleção.

Instalar e usar no jogo

Pacote ESM sem dependências: @gamers-pelo-brasil/trofeus, versão 0.1.0-test.3. Não publicado no npm. Instalação pela pasta do código-fonte (com package.json), para quem tem acesso:

npm install /caminho/para/backend/sdk

O ZIP público usa arquivos diretos e não requer npm. Para HTML sem bundler, comece pelo exemplo completo e copiável. Copie exemplo.html e trofeus.js para a mesma pasta, sirva por HTTPS ou localhost e preencha a API/chave entregues pelo operador. Não abra por file://. Em produção, use api: 'https://api.gamerspelobrasil.tech', sem barra final nem /api/v1. O módulo publicado fica em https://gamerspelobrasil.tech/criar/sdk/arquivos/trofeus.js; o caminho antigo https://api.gamerspelobrasil.tech/sdk/trofeus.js redireciona para ele. Prefira copiar o módulo do ZIP para o próprio jogo, como no exemplo. A central de resgate fica no hub. O link retornado pelo SDK passa pela API e redireciona para a central; use receipt.claim_url inteiro, sem remover nem enviar o fragmento ao servidor. Use somente API, chave e origens fornecidas pelo operador. Login Google depende da configuração do ambiente; o SDK não configura nem solicita credenciais de conta.

  1. Peça ao operador a origem da API, a chave pública, as origens cadastradas do jogo e a correspondência entre desafios e os sete slots. O criador não precisa acessar banco, CLI ou credenciais administrativas.
  2. Prepare o SDK antes de iniciar a partida. No exemplo, “Testar conexão” só diagnostica; “Emitir conquista real” representa um callback real e grava uma prova. Ligue cada callback a registrarConquista(slot):

js // Dentro do script do exemplo, depois de preparar o SDK: aoVencerPrimeiraFase(() => registrarConquista('bronze-1')); aoCompletarJogo(() => registrarConquista('ouro-1'));

Substitua aoVencerPrimeiraFase/aoCompletarJogo pelos eventos existentes no seu jogo; não crie regras de vitória novas. Cada slot tem sua própria linha, status, link Receber na minha coleção, Tentar novamente e Gerar novo link. 3. Falhou a rede? Use Tentar novamente. A conquista fica registrada antes do envio, mesmo se o callback ocorrer uma única vez. Após reload, prepare o SDK com a mesma API/chave: as linhas são restauradas sem precisar vencer de novo. 4. A central disse CLAIM_USED ou link vencido? Dispense o link antigo na central se for reutilizar a mesma aba. Volte à linha da conquista e use Gerar novo link. Esse ato explícito substitui a prova local daquele slot. Se a resposta da renovação se perder, use Tentar novamente, que reutiliza a prova recém-criada. Não clique de novo em renovar para repetir transporte. O novo link permite resgatar na identidade atual; não recupera a coleção antiga. 5. Teste dois slots, interrompa uma resposta e recarregue. Cada linha deve manter seu próprio botão; o retry não depende de reiniciar a partida. Abra receber, entre com Google se a central solicitar e confirme o resgate. Em ambientes com Google desativado, a central oferece uma identidade de teste.

Para integração assistida por IA: forneça o HTML completo e o mapeamento de slots; peça para ligar apenas os callbacks reais a registrarConquista, preservando as linhas/retries, API/chave pública fornecidas e credentials: 'omit'. Cadastro, banco e configuração do proxy são do operador. Não peça login no jogo ou mudanças no sandbox/CORS do conteúdo hospedado.

Chave, origem e configuração no jogo

A chave gpb_… é pública e pode ficar no JavaScript. Use a chave do próprio jogo; ela identifica o cadastro, não autentica o jogador e não comprova a vitória. Não peça a chave ao jogador. Na versão integrada, preencha api e chave no código e prepare o SDK ao carregar o jogo, antes de habilitar a partida. O formulário do exemplo serve para o autor testar a configuração.

import {criarTrofeus} from './trofeus.js';
const sdk = criarTrofeus({
  api: 'https://api.gamerspelobrasil.tech',
  chave: 'CHAVE_PUBLICA_ENTREGUE_PELO_OPERADOR'
});
// Mantenha as linhas, os botões e a recuperação do exemplo completo.
// Cada callback real chama registrarConquista(slot), que usa esta instância.

A origem é protocolo + domínio + porta, sem caminho nem barra final. https://meu-jogo.pages.dev é diferente de um subdomínio de preview, http://localhost:8091 ou http://127.0.0.1:8091. Só funcionam as origens cadastradas para aquela chave. Servir por localhost habilita Web Crypto, mas não libera a emissão real: para testar sem gravar, use testar(slot) abaixo; para emitir conquistas locais de verdade, solicite ao operador o cadastro exato. Publicar o exemplo na origem autorizada também permite testar a chave real. Não use mode: 'no-cors', não defina Origin manualmente e preserve credentials: 'omit'; o SDK cuida dos cabeçalhos e do preflight.

Se o jogo tiver Content-Security-Policy, permita a API em connect-src e o local do módulo em script-src. Isso vale para o frontend externo administrado pelo autor; não altera o isolamento dos jogos hospedados pela plataforma.

Sintoma Conferência e ação
Chave do jogo inválida ao preparar Substitua o placeholder pela chave completa gpb_ + 64 hexadecimais.
ORIGIN_NOT_ALLOWED / erro de CORS ou Failed to fetch Veja no Network o OPTIONS/POST: confira origem cadastrada, HTTPS, CSP e conectividade. O navegador pode ocultar a resposta quando CORS bloqueia.
INVALID_GAME_KEY (403) Confira se a chave está ativa e pertence ao jogo e à origem usados.
RATE_LIMITED (429) Aguarde um minuto e tente novamente com a mesma prova.
CLAIM_EXPIRED / CLAIM_USED Gere novo link por ação explícita no jogo; retry sozinho preserva o link antigo.

Testar em localhost sem gravar conquistas

A partir do SDK 0.1.0-test.3, use a mesma chave pública do jogo para verificar conexão, chave ativa e slot, mesmo sem cadastrar localhost:

const resultado = await sdk.testar('bronze-1');
// {mode: 'test', game_id: 'meu-jogo', trophy_id: 'bronze-1',
//  origin_registered: false, persisted: false}

Copie exemplo.html e trofeus.js do ZIP para a mesma pasta e sirva:

python3 -m http.server 5173 --bind 127.0.0.1

Abra http://localhost:5173/exemplo.html, preencha a API de produção e a chave, clique Preparar SDK e Testar conexão (sem gravar). Não é necessário banco, CLI, conta ou uma chave de teste separada. O operador já deve ter cadastrado a chave do jogo; chave inventada, girada ou desativada retorna erro.

O diagnóstico faz POST /api/v1/trophies/check com X-Game-Key e corpo {"trophy_id":"bronze-1"}. O servidor executa apenas leitura: não cria claim, token, sessão, troféu nem debita cotas SQL de emissão. O SDK não modifica as intenções em storage e não devolve link de resgate. origin_registered: false é esperado em localhost sem cadastro; persisted é sempre false. As defesas gerais da API continuam limitando excesso de requisições.

Aceita http://localhost:<porta>, http://127.0.0.1:<porta> e http://[::1]:<porta> (ou HTTPS), com porta válida. LAN, file:///Origin null e previews não cadastrados continuam recusados. A exceção local vale somente para /check; ganhar(slot) e Emitir conquista real continuam gravando provas e exigindo origem cadastrada. Não use emissão como teste de conexão. Se /check responder 404, a API ainda não recebeu a versão com diagnóstico; se testar não existir, atualize o módulo. Não substitua o diagnóstico por emissão.

Critérios de integração concluída

Mapeie os desafios existentes para os slots que o jogo usar; não é obrigatório atribuir os sete de uma vez. Um link pronto significa que a prova foi emitida. O troféu só entra na coleção após o jogador confirmar o resgate na central. Valide um callback natural, dois slots independentes, falha de rede/retry, reload, renovação explícita e resgate/coleção com a conta do jogador. Instalar o módulo e obter HTTP 200 não substitui esse fluxo completo.

Roteiro de validação com o criador

O retorno do criador é parte do piloto: confirme o mapeamento de eventos existentes para slots antes do aceite. Os critérios pertencem ao jogo; não há exigência de dificuldade uniforme entre jogos. Cada slot é independente por jogo, mesmo quando dois jogos usam o mesmo identificador.

Use estas três etapas e declare qual foi concluída:

Etapa Como executar O que comprova
Diagnóstico sem gravação testar(slot) com a chave pública Conexão, chave ativa, slot e se a origem está cadastrada. Não cria prova ou link.
Simulação no jogo Acionar os eventos existentes com envio interceptado no ambiente de teste do autor Callbacks, apresentação das conquistas e tratamento de falhas simuladas. Não comprova emissão ou coleção na central.
Aceite real Jogar na origem cadastrada, emitir pelo SDK, abrir o link e confirmar na central com a conta Integração do jogo com emissão, login quando solicitado, resgate e coleção. A persistência deve ser conferida com o operador.

A simulação é útil e não impede o aceite real coordenado com o operador. Uma falha de rede provocada que apresenta Tentar novamente é um resultado esperado; para validar recuperação, é preciso também concluir o reenvio. Não use emissão para diagnosticar conexão nem execute emissões em massa na API pública. Faça os cenários de falha técnica em ambiente controlado.

Antes de concluir a integração, confira:

O criador registra versão/URL do jogo, slot e evento, data/hora, aparelho, navegador, etapa testada e resultado observado. Não inclua tokens, cookies ou links pessoais. O operador confere a persistência independentemente; o criador não precisa de banco ou credenciais administrativas. Uma partida automática não substitui a conferência em aparelho físico; um ensaio sintético da equipe não substitui o callback natural do jogo.

Nomes das conquistas no jogo e na coleção

Você pode apresentar títulos e descrições próprios no jogo, associados aos slots. Na versão atual, a central exibe a categoria do troféu e o nome cadastrado do jogo; não recebe o título, a descrição ou o ícone personalizado da conquista. Por exemplo, “Escavador” associado a bronze-1 continua sendo o bronze daquele jogo na coleção. Envie somente os campos do contrato pelo SDK. A personalização da central é uma evolução opcional e não bloqueia o piloto.

API JavaScript e recuperação

ganhar(slot) registra a intenção e envia/reenvia a mesma prova; chamadas simultâneas do mesmo slot compartilham a promessa. pendentes() lista os slots com intenção local, inclusive quando o envio falhou; não indica que houve resgate. renovarLink(slot) cria outro UUID/token explicitamente, sem consultar a identidade central. A renovação em paralelo a um envio do mesmo slot falha com ISSUE_IN_PROGRESS; espere a operação e use retry se necessário.

O SDK não faz chamadas ao inicializar, polling ou login. A primeira conquista faz POST (e preflight quando necessário). Após resposta válida, reutiliza o link; falha de transporte preserva UUID/token. O prazo do servidor é 15 minutos, sem renovar em reenvio. Não há substituição automática por relógio local: se a prova venceu, a UI oferece renovação explícita. Timeout de rede: 10 segundos; sem retry automático. O cache usa API/chave/slot. Sem storage disponível, a intenção fica apenas na memória da página e não sobrevive a reload. Apagar storage, mudar origem ou chave também impede recuperar essa intenção; localStorage não é conta central.

Cadastrar, girar ou desativar a chave

Para experimentar manualmente, com DATABASE_URL de testes já definida, execute na pasta backend/ (terminal 1):

make build
HTTP_ADDR=127.0.0.1:8082 PUBLIC_ORIGIN=http://127.0.0.1:8082 HUB_ORIGIN=http://127.0.0.1:8081 ./bin/api

No terminal 2, com a mesma DATABASE_URL:

./bin/trofeus -jogo piloto -nome 'Meu jogo piloto' -origens 'http://localhost:8091'
python3 -m http.server 8091 --bind 127.0.0.1 --directory sdk

No terminal 3, na pasta hub/, inicie a central local (com Go disponível):

HTTP_ADDR=127.0.0.1:8081 API_ORIGIN=http://127.0.0.1:8082 go run .

Abra http://localhost:8091/exemplo.html, cole a chave pública retornada e clique em “Preparar SDK”, “Emitir conquista real” e “Receber na minha coleção”. O HTML abre a central em outra aba e mantém os links de cada slot no jogo. A página central oferece criar a identidade de teste somente se não houver sessão. As duas origens diferentes reproduzem a separação jogo/central. Use Ctrl+C para encerrar os processos de teste. Não é deploy nem publicação npm.

Depois de iniciar a API para aplicar migrations, a partir de backend/, use DATABASE_URL de um banco de testes já configurado, sem imprimi-la:

make build
./bin/trofeus -jogo piloto -nome 'Meu jogo piloto' -origens 'http://localhost:8091'
./bin/trofeus -acao girar-chave -jogo piloto
./bin/trofeus -acao desativar -jogo piloto

A saída contém a chave pública (gpb_ + 64 hexadecimais), não a credencial administrativa do banco. Só existe administração por CLI; nenhuma rota HTTP pública cadastra jogos ou cria chaves. O banco guarda somente o hash da chave. Cadastro duplicado falha sem substituir o jogo. Rotação invalida a chave anterior e seus resgates pendentes; desativação bloqueia novas emissões e resgates. Ambas preservam a coleção já conquistada. A CLI está incluída no Dockerfile, sem executar mudanças no build.

Cadastre de uma a dez origens exatas, separadas por vírgula, sem caminho/barra final; HTTPS obrigatório fora de loopback. Origem opaca null é recusada. Os jogos hospedados atuais abrem diretamente em nova aba, com origem opaca por cabeçalho CSP. Precisam de uma integração própria ainda não entregue; não se remove o isolamento nem se aceita Origin null para instalar o SDK.

Contrato e fronteiras

Contrato canônico: OpenAPI, tag Troféus. Implementação: HTTP (referência interna; consulte o operador), transações (referência interna; consulte o operador) e migration 004 (referência interna; consulte o operador).

Operação Identidade/autorização Efeito
POST /api/v1/trophies/claims Chave pública e origem do jogo; sem sessão Registra hash/UUID/slot e responde página e validade
GET /trofeus/ na API Redirecionamento sem corpo Leva à central do hub; não cria identidade nem grava conquista
POST /api/v1/trophies/redeem Cookie e Origin central Resgata uma vez; reenvio do dono retorna a mesma conquista
GET /api/v1/players/me/trophies Cookie central Até 1000 conquistas mais recentes, sem acesso entre jogadores

A chave no JavaScript e o cabeçalho Origin são copiáveis. Esta versão valida a autorização do cadastro e a integridade do resgate, não prova que o desafio foi vencido. O token é um comprovante ao portador: quem possuir o link pode resgatá-lo primeiro. Não há identidade do jogador vinculada na emissão; esse é o compromisso do fluxo sem login nos jogos. Não publique links pessoais como compartilhamento. Para um futuro modo verificado, o servidor do jogo poderá atestar conquistas com credencial privada; isso não está implementado na versão de browser.

Limites por janela fixa de minuto, compartilhados no PostgreSQL entre processos: 4096 bytes por pedido; 10 provas novas por jogo/solicitante, 60 provas novas por jogo (teto agregado preservado), 120 pedidos válidos por jogo/solicitante, incluindo reenvios/conflitos e novas emissões recusadas. Pedidos sem autorização ou malformados são recusados antes dessa admissão; proteção volumétrica desses pedidos cabe à borda. Retry idempotente não debita provas novas, mesmo com o teto agregado cheio; continua limitado pelos 120 pedidos. Falha transacional não deixa claim nem débito de prova nova; a admissão do pedido persiste separadamente. 429 inclui Retry-After: 60. Resgate mantém 60 tentativas autenticadas/jogador/minuto.

Solicitante é o IP da conexão (IPv4 sem porta; IPv6 agrupado por /64), nunca um ID escolhido pelo browser. Só o hash desse agrupamento entra no contador. NAT compartilha a cota; uma rede distribuída ainda pode atingir o teto agregado. Isso reduz o abuso reproduzido e limita escrita, sem constituir proteção completa contra DDoS.

Por padrão, cabeçalhos de proxy são ignorados. Atrás de proxy, o operador deve configurar TRUSTED_PROXY_CIDRS com CIDRs explícitos dos saltos controlados e validar que a borda remove ou acrescenta o IP real à direita de X-Forwarded-For. A API percorre a cadeia da direita para a esquerda até o primeiro IP não confiável; prefixos inventados à esquerda não criam novas cotas. Não use redes amplas que incluam clientes; cabeçalho ausente/inválido usa o IP do proxy e compartilha a cota. A publicação de testes foi conferida em 2026-10-19; configuração e provas operacionais pertencem ao ambiente (referência interna; consulte o operador).

Hash, UUID e corpo devem coincidir para reenvio. Claims não consumidos vencem em 15 minutos. Reenvio do dono após consumo continua idempotente mesmo depois desse prazo, enquanto jogo/chave e sessão forem válidos. Não há limpeza automática das provas nesta versão; política e operação ficam no quadro. Nenhuma concessão depende de memória do processo Go. Não recebe URL arbitrária para redirecionar nem busca URLs do jogo.

Identidade central: com Google habilitado pelo operador, o jogador entra na central e recupera a coleção pela conta. O jogo não recebe essa sessão nem solicita credenciais Google. Com Google desativado, a central oferece identidade de teste por cookie defende_brasil_session, HttpOnly, SameSite=Lax, host-only e Secure sob HTTPS. A duração de teste segue SESSION_TTL (padrão 24h, sem renovação). Perder ou expirar o cookie de teste não recupera a coleção pela UI: uma nova sessão cria outra identidade. Storage do jogo não é autenticação. A configuração de conta não é fornecida no ZIP; confira o modo oferecido pela central do ambiente disponibilizado. Não prometa migração de troféus de uma identidade de teste para uma conta.

Reproduzir os ensaios

Com Go no PATH, PostgreSQL descartável e Playwright/Chromium configurados conforme o ambiente (referência interna; consulte o operador), a partir de backend/:

make trophies-test

O alvo exige TEST_DATABASE_URL de cluster dedicado e PLAYWRIGHT_MODULE; não aceita silenciosamente pular o navegador. Cada teste cria banco/role próprios e remove-os no final. O navegador usa sandbox ativo e portas loopback; o teste inicia/encerra apenas seus processos. O fixture externo serve o HTML completo e o SDK reais, com registro pela CLI e API em processo separado. Exercita callback único, resposta perdida, vários slots, troca de cookie, renovação explícita e fila central durante respostas atrasadas. Não altera jogos publicados.

Testes: SDK (referência interna; consulte o operador), HTTP/banco (referência interna; consulte o operador), processo/CLI (referência interna; consulte o operador) e navegador (referência interna; consulte o operador). Evidências executadas pertencem ao relatório (referência interna; consulte o operador); existência dos testes não é prova de sucesso.

Distribuição pública da oficina — 2026-10-18

O módulo e o exemplo são distribuídos sob MIT. A oficina em /criar/sdk/ do hub prepara guia navegável e ZIP versionado sem exigir acesso ao repositório privado. Este README permanece dono do contrato: o gerador hub/tools/build_oficina.py copia módulo/exemplo byte a byte e adapta apenas links na edição pública do guia, identificando referências internas não distribuídas. Hashes de origem e dos arquivos do kit ficam no manifesto. Preparação local não comprova publicação do hub ou dos endpoints de troféus. Provas da distribuição pertencem ao guia do hub (referência interna; consulte o operador).

Evolução prevista

Primeira versão: transporte de conquista, sete slots fixos, cadastro por CLI, resgate e coleção central. Próxima integração: piloto escolhido e adaptado pelos criadores e abertura coordenada. Login Google está implementado separadamente e depende da configuração do ambiente; não faz parte da instalação do SDK. Nomes/descrições/ícones personalizados dos sete slots, painel de administração, paginação além de 1000 itens e atestado privado de um servidor de jogo são extensões, não requisitos já entregues. O legado de partidas/score continua disponível para compatibilidade; nenhuma partida antiga foi apagada ou convertida em troféu automaticamente.

Voltar ao início da oficina · Ir para os jogos