Caputchin
Referências

Métodos e eventos do widget

O widget Caputchin envia dois elementos personalizados, e sua página interage com eles em duas direções: você chama métodos no elemento para conduzi-lo, e você escuta eventos que ele emite para reagir. Esta página é a referência exaustiva das duas superfícies.

Todo evento é um CustomEvent despachado com bubbles: true e composed: true, então ele escapa do shadow DOM do widget e você pode escutá-lo diretamente no elemento (ou em qualquer ancestral). O dado está sempre em event.detail.

Os dois elementos de relance

ElementoPropósitoMétodos
<caputchin-widget>Só verificação (proof-of-work / checkbox).start()
<caputchin-game>Anfitrião de jogo, com verificação opcional.pass(), fail()

A checkbox do widget tem só start(); ela não expõe pass() / fail(). O anfitrião de jogo não tem start() (sua rodada fica ativa na montagem para inline, ou na primeira abertura de diálogo para modal / fullscreen). Os dois elementos emitem start, pass, error e degraded; o anfitrião de jogo adicionalmente emite dialog-shown e dialog-hidden. A cobertura está na tabela de eventos abaixo.

Métodos

start(), só <caputchin-widget>

Começa a verificação imediatamente. Seu propósito é o gatilho manual: quando o elemento tem trigger="manual", você chama start() para disparar a resolução de proof-of-work do seu próprio gesto (por exemplo, no submit do seu formulário) em vez da checkbox embutida. Com os gatilhos padrão auto / click o elemento conecta sua própria ativação, então você não chama isto.

const widget = document.querySelector("caputchin-widget");
widget.start();

O anfitrião de jogo não tem start(). Veja modo manual para o passo a passo completo de conduzi-lo você mesmo.

pass(payload), só <caputchin-game>

Libera o portão de verificação: o visitante teve sucesso. Válido só quando trigger="manual"; chamá-lo em um jogo não manual emite um error com código invalid-call. O primeiro pass() resgata e trava o veredito; chamadas posteriores são silenciosamente ignoradas (uma rodada por sessão).

const widget = document.querySelector("caputchin-game");
widget.pass({ trace: roundRecord });
Campo de payloadTipoSignificado
tracestringO registro opaco da rodada que seu jogo produz. Numa rodada com portão o servidor o reexecuta para derivar o veredito autoritativo; numa chave sem portão ou só-jogo ele é aceito como está. Passe uma string vazia se a sua interação não tem registro para reexecutar.

Não há campo score neste método, o portão é o replay do trace pelo servidor, não uma pontuação alegada pelo cliente. (Um score aparece no evento pass, que é o widget reportando de volta a você, não você ao widget.)

Chamar pass() antes de a rodada ter começado (modal / fullscreen, diálogo ainda não aberto) emite um error com código invalid-call. Numa chave só-jogo (sem sitekey) não há portão para liberar, então pass() simplesmente emite o evento pass com token: null.

fail(payload?), só <caputchin-game>

Aborta a rodada: uma derrota definitiva. Válido só quando trigger="manual" (senão invalid-call). Opcional, uma rodada inacabada é tratada como uma não-aprovação de qualquer forma. Ele aborta a verificação em andamento (as checagens de proof-of-work e instrumentação) e expõe um evento error com código game-error-relayed.

widget.fail({ code: "out-of-moves", message: "no moves left" });
Campo de payloadTipoSignificado
codestring (opcional)Seu código de diagnóstico; exposto como o originalCode do evento error. O padrão é game-failed.
messagestring (opcional)Motivo legível por humanos.

Eventos

Escute com addEventListener(type, handler). Todo payload vive em event.detail.

EventoEmitido porevent.detailDispara quando
startambos{ gameId: string | null }A verificação começa (auto na montagem, na ativação, ou via start()). gameId é definido para uma rodada de jogo, null para o widget simples.
passambos{ token: string | null, score: number | null, durationMs: number | null }A verificação é liberada. token é o token envolvido para enviar ao seu backend; null numa chave só-jogo (sem sitekey).
errorambos{ code, message, severity, originalCode? }Qualquer coisa de um aviso de config benigno a uma falha grave. Veja o evento error.
degradedambos{ reason: "timeout" | "network" | "http" | "malformed" }O widget não conseguiu resolver a tempo o tamanho / skin / locale que você configurou, então renderizou com seus valores padrão empacotados. Não é um erro. Veja o evento degraded.
dialog-shown<caputchin-game>{ layout: "modal" | "fullscreen" }Um diálogo de jogo em sobreposição abre (programático ou primeiro clique).
dialog-hidden<caputchin-game>{ layout: "modal" | "fullscreen" }Um diálogo de jogo em sobreposição fecha (programático, Escape, ou clique no fundo).

O evento pass e o token

O evento pass é a sua deixa de que a verificação teve sucesso, mas ele não é a decisão de confiança. A decisão de confiança é o seu backend confirmando detail.token. Sempre verifique o token no seu backend; nunca conceda acesso só pelo evento de front-end. Em um formulário, o widget também injeta o token como um campo caputchin-token para que um POST de formulário normal o carregue. O score e o durationMs neste evento são análises reportadas pelo cliente e podem ser null; nunca os trate como um sinal de confiança.

O evento error

O evento error carrega um code estável, uma message humana, uma severity, e às vezes um originalCode. Cada código tem uma severidade padrão fixa para que você possa filtrar avisos de "continuou rodando" das falhas de "de fato quebrou" sem codificar à mão uma tabela de código-para-severidade, só leia detail.severity. O conjunto completo de códigos:

codeseveritySignificado
invalid-configwarnUm atributo ou combinação que o widget rejeitou; ele degrada graciosamente e continua rodando.
invalid-callwarnUm método chamado quando não era válido (ex.: pass() em um jogo não manual, ou antes de a rodada começar).
verification-failederrorA checagem de proof-of-work ou instrumentação (ou o resgate do token) falhou; nenhum token emitido.
game-load-failederrorO bundle do jogo não pôde ser resolvido, carregado ou registrado.
gate-unavailableerrorO servidor retornou uma recusa autoritativa no bootstrap (uma chave com portão não conseguiu fornecer um jogo válido).
game-error-relayederrorUm erro surgiu de dentro do jogo (repassado do iframe, ou de um fail() manual).

detail.originalCode está presente quando o code público é uma generalização de um motivo interno mais específico (por exemplo, uma falha de carregamento de iframe repassada como game-load-failed carrega o iframe-load-failed / iframe-script-blocked / game-not-registered cru em originalCode). Use code para ramificar e originalCode só para diagnósticos.

O evento degraded

Na montagem, o widget faz uma chamada curta ao Caputchin para resolver o tamanho, skin e locale que você configurou (e, para um jogo do marketplace, sua pegada preferida). Se essa chamada falhar ou for lenta demais, o widget não bloqueia nem quebra: ele renderiza com os valores assados no bundle e emite degraded, para que o fallback nunca seja silencioso. O widget continua plenamente funcional após um evento degraded, só a apresentação resolvida pode diferir do que você configurou (um jogo pode aparecer no seu tamanho padrão, ou a checkbox no seu tema padrão). O widget retenta uma resolução lenta antes de cair para o fallback, então degraded significa que as tentativas se esgotaram, não que uma única tentativa foi lenta.

detail.reason diz a você por que a resolução caiu para o fallback, para que você possa exibi-lo na sua própria telemetria:

reasonSignificado
timeoutA resolução não respondeu dentro do seu orçamento de tempo (serviço lento ou inalcançável).
networkA própria requisição falhou (offline, DNS, bloqueada, ou conexão reiniciada).
httpO serviço respondeu com um status de erro.
malformedO serviço respondeu, mas o corpo não era válido.

degraded é um aviso, não uma falha, então é deliberadamente não um evento error: uma resolução lenta não deveria disparar os handlers que você liga para falhas reais. Escute-o só se você quiser observar os renders degradados, por exemplo para alertar quando seus visitantes estão vendo a apresentação de fallback.

Escutando, na prática

const widget = document.querySelector("caputchin-game");

const onPass = (e) => {
  // send e.detail.token to your backend to verify
};
const onError = (e) => {
  if (e.detail.severity === "error") {
    console.error(e.detail.code, e.detail.message);
  }
};

widget.addEventListener("pass", onPass);
widget.addEventListener("error", onError);

// Clean up when you tear down your view:
widget.removeEventListener("pass", onPass);
widget.removeEventListener("error", onError);

Estes são CustomEvents nativos do DOM, então no React você os anexa com um ref e addEventListener (não props JSX onPass); os exemplos de frontend mostram a conexão específica de cada framework. Como todo evento borbulha e é composto, você também pode delegar de um elemento contêiner em vez de vincular cada widget individualmente.

Veja também

Nesta página