Méthodes et événements du widget
Le widget Caputchin livre deux éléments personnalisés, et ta page interagit avec eux dans deux directions : tu appelles des méthodes sur l'élément pour le piloter, et tu écoutes les événements qu'il émet pour réagir. Cette page est la référence exhaustive des deux surfaces.
Chaque événement est un CustomEvent dépêché avec bubbles: true et composed: true, donc il échappe au shadow DOM du widget et tu peux l'écouter directement sur l'élément (ou sur n'importe quel ancêtre). Les données sont toujours sur event.detail.
Les deux éléments d'un coup d'œil
| Élément | But | Méthodes |
|---|---|---|
<caputchin-widget> | Vérification seulement (proof of work / case à cocher). | start() |
<caputchin-game> | Hôte de jeu, avec vérification optionnelle. | pass(), fail() |
Le widget à case à cocher n'a que start() ; il n'expose pas pass() / fail(). L'hôte de jeu n'a pas de start() (sa manche devient active au montage pour inline, ou à la première ouverture de dialogue pour modal / fullscreen). Les deux éléments émettent start, pass, error et degraded ; l'hôte de jeu émet en plus dialog-shown et dialog-hidden. La couverture est dans la table des événements ci-dessous.
Méthodes
start() (<caputchin-widget> uniquement)
Commence la vérification immédiatement. Son but est le déclencheur manuel : quand l'élément a trigger="manual", tu appelles start() pour lancer la résolution du proof of work depuis ton propre geste (par exemple, à l'envoi de ton formulaire) au lieu de la case à cocher intégrée. Avec les déclencheurs auto / click par défaut, l'élément câble sa propre activation, donc tu n'appelles pas ceci.
const widget = document.querySelector("caputchin-widget");
widget.start();L'hôte de jeu n'a pas de start(). Vois mode manuel pour la marche à suivre complète du pilote-le-toi-même.
pass(payload) (<caputchin-game> uniquement)
Libère le gate de vérification : le visiteur a réussi. Valide seulement quand trigger="manual" ; l'appeler sur un jeu non manuel émet une error avec le code invalid-call. Le premier pass() échange et verrouille le verdict ; les appels ultérieurs sont silencieusement ignorés (une manche par session).
const widget = document.querySelector("caputchin-game");
widget.pass({ trace: roundRecord });Champ de payload | Type | Signification |
|---|---|---|
trace | string | L'enregistrement opaque de manche que ton jeu produit. Sur une manche gatée, le serveur la rejoue pour dériver le verdict faisant autorité ; sur une clé non gatée ou jeu-seul, elle est acceptée telle quelle. Passe une chaîne vide si ton interaction n'a pas d'enregistrement à rejouer. |
Il n'y a pas de champ score sur cette méthode, le gate est le rejeu de la trace par le serveur, pas un score revendiqué par le client. (Un score apparaît bien sur l'événement pass, qui est le widget qui te rapporte, pas toi qui rapportes au widget.)
Appeler pass() avant que la manche n'ait commencé (modal / fullscreen, dialogue pas encore ouvert) émet une error avec le code invalid-call. Sur une clé jeu-seul (pas de sitekey), il n'y a pas de gate à libérer, donc pass() émet simplement l'événement pass avec token: null.
fail(payload?) (<caputchin-game> uniquement)
Abandonne la manche : une défaite définitive. Valide seulement quand trigger="manual" (sinon invalid-call). Optionnel, une manche inachevée est de toute façon traitée comme un non-pass. Il abandonne la vérification en cours (les vérifications de proof of work et d'instrumentation) et fait surgir un événement error avec le code game-error-relayed.
widget.fail({ code: "out-of-moves", message: "no moves left" });Champ de payload | Type | Signification |
|---|---|---|
code | string (optionnel) | Ton code de diagnostic ; remonté comme l'originalCode de l'événement error. Par défaut game-failed. |
message | string (optionnel) | Raison lisible par un humain. |
Événements
Écoute avec addEventListener(type, handler). Chaque charge vit sur event.detail.
| Événement | Émis par | event.detail | Se déclenche quand |
|---|---|---|---|
start | les deux | { gameId: string | null } | La vérification commence (auto au montage, à l'activation, ou via start()). gameId est réglé pour une manche de jeu, null pour le widget simple. |
pass | les deux | { token: string | null, score: number | null, durationMs: number | null } | La vérification est libérée. token est le token enveloppé à envoyer à ton backend ; null sur une clé jeu-seul (pas de sitekey). |
error | les deux | { code, message, severity, originalCode? } | N'importe quoi d'un avertissement de config bénin à un échec dur. Vois l'événement error. |
degraded | les deux | { reason: "timeout" | "network" | "http" | "malformed" } | Le widget n'a pas pu résoudre à temps la taille / le skin / la locale que tu as configurés, alors il a rendu avec ses valeurs par défaut empaquetées. Pas une erreur. Vois l'événement degraded. |
dialog-shown | <caputchin-game> | { layout: "modal" | "fullscreen" } | Un dialogue de jeu en surcouche s'ouvre (programmatique ou premier clic). |
dialog-hidden | <caputchin-game> | { layout: "modal" | "fullscreen" } | Un dialogue de jeu en surcouche se ferme (programmatique, Échap, ou clic sur le fond). |
L'événement pass et le token
L'événement pass est ton signal que la vérification a réussi, mais ce n'est pas la décision de confiance. La décision de confiance est ton backend confirmant detail.token. Vérifie toujours le token sur ton backend ; n'accorde jamais l'accès à partir du seul événement front-end. Dans un formulaire, le widget injecte aussi le token comme champ caputchin-token pour qu'un POST de formulaire normal le porte. Les score et durationMs sur cet événement sont des analytiques rapportées par le client et peuvent être null ; ne les traite jamais comme un signal de confiance.
L'événement error
L'événement error porte un code stable, un message humain, une severity, et parfois un originalCode. Chaque code a une sévérité par défaut fixe pour que tu puisses filtrer les avertissements « a continué de tourner » des échecs « a réellement cassé » sans coder en dur une table code-vers-sévérité, lis juste detail.severity. L'ensemble complet des codes :
code | severity | Signification |
|---|---|---|
invalid-config | warn | Un attribut ou une combinaison que le widget a rejeté ; il se dégrade gracieusement et continue de tourner. |
invalid-call | warn | Une méthode appelée quand elle n'était pas valide (par ex. pass() sur un jeu non manuel, ou avant que la manche ne commence). |
verification-failed | error | La vérification de proof of work ou d'instrumentation (ou l'échange du token) a échoué ; aucun token émis. |
game-load-failed | error | Le bundle du jeu n'a pas pu être résolu, chargé ou enregistré. |
gate-unavailable | error | Le serveur a renvoyé un refus faisant autorité au bootstrap (une clé gatée n'a pas pu fournir un jeu valide). |
game-error-relayed | error | Une erreur a surgi de l'intérieur du jeu (relayée depuis l'iframe, ou depuis un fail() manuel). |
detail.originalCode est présent quand le code public est une généralisation d'une raison interne plus précise (par exemple, un échec de chargement d'iframe relayé comme game-load-failed porte le iframe-load-failed / iframe-script-blocked / game-not-registered brut dans originalCode). Utilise code pour brancher et originalCode seulement pour le diagnostic.
L'événement degraded
Au montage, le widget fait un court appel à Caputchin pour résoudre la taille, le skin et la locale que tu as configurés (et, pour un jeu du marketplace, son empreinte préférée). Si cet appel échoue ou est trop lent, le widget ne bloque ni ne casse : il rend avec les valeurs cuites dans le bundle et émet degraded, pour que le repli ne soit jamais silencieux. Le widget reste pleinement fonctionnel après un événement degraded, seule la présentation résolue peut différer de ce que tu as configuré (un jeu peut apparaître à sa taille par défaut, ou la case à cocher dans son thème par défaut). Le widget réessaie une résolution lente avant de se replier, donc degraded veut dire que les tentatives ont été épuisées, pas qu'une seule tentative était lente.
detail.reason te dit pourquoi la résolution s'est repliée, pour que tu puisses le faire remonter dans ta propre télémétrie :
reason | Signification |
|---|---|
timeout | La résolution n'a pas répondu dans son budget de temps (service lent ou injoignable). |
network | La requête elle-même a échoué (hors ligne, DNS, bloquée, ou connexion réinitialisée). |
http | Le service a répondu avec un statut d'erreur. |
malformed | Le service a répondu, mais le corps n'était pas valide. |
degraded est un avis, pas un échec, donc c'est délibérément pas un événement error : une résolution lente ne devrait pas déclencher les handlers que tu câbles pour de vraies pannes. Écoute-le seulement si tu veux observer les rendus dégradés, par exemple pour alerter quand tes visiteurs voient la présentation de repli.
Écouter, en pratique
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);Ce sont des CustomEvents DOM natifs, donc en React tu les attaches avec un ref et addEventListener (pas des props JSX onPass) ; les exemples frontend montrent le câblage spécifique au framework. Parce que chaque événement bubble et est composé, tu peux aussi déléguer depuis un élément conteneur plutôt que de lier chaque widget individuellement.
Voir aussi
- Ajouter le widget : les attributs de configuration que tu règles dans le balisage (le côté entrée de ce côté sortie).
- Pilote la vérification toi-même avec le mode manuel : le tutoriel qui utilise
start()/pass()/fail(). - Vérifier sur ton backend : quoi faire avec le token de l'événement
pass. - Exemples frontend : câbler ces événements en React, Vue et JS pur.