Caputchin
Referenzen

Widget-Methoden und -Events

Das Caputchin-Widget liefert zwei Custom Elements, und deine Seite interagiert mit ihnen in zwei Richtungen: du rufst Methoden auf dem Element auf, um es zu treiben, und du lauschst auf Events, die es emittiert, um zu reagieren. Diese Seite ist die erschöpfende Referenz für beide Flächen.

Jedes Event ist ein CustomEvent, dispatcht mit bubbles: true und composed: true, sodass es dem Shadow DOM des Widgets entkommt und du direkt auf dem Element (oder auf jedem Vorfahren) darauf lauschen kannst. Die Daten sind immer auf event.detail.

Die zwei Elemente auf einen Blick

ElementZweckMethoden
<caputchin-widget>Nur Verifizierung (Proof-of-Work / Checkbox).start()
<caputchin-game>Spiel-Host, mit optionaler Verifizierung.pass(), fail()

Das Checkbox-Widget hat nur start(); es stellt pass() / fail() nicht bereit. Der Spiel-Host hat kein start() (seine Runde wird beim Mount für Inline live, oder beim ersten Dialog-Öffnen für Modal / Fullscreen). Beide Elemente emittieren start, pass, error und degraded; der Spiel-Host emittiert zusätzlich dialog-shown und dialog-hidden. Die Abdeckung ist in der Events-Tabelle unten.

Methoden

start() (nur <caputchin-widget>)

Beginnt die Verifizierung sofort. Sein Zweck ist der manuelle Auslöser: wenn das Element trigger="manual" hat, rufst du start() auf, um die Proof-of-Work-Lösung aus deiner eigenen Geste zu feuern (zum Beispiel beim Submit deines Formulars) statt der eingebauten Checkbox. Mit den Standard-auto / click-Auslösern verdrahtet das Element seine eigene Aktivierung, also rufst du dies nicht auf.

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

Der Spiel-Host hat kein start(). Sieh dir manueller Modus für die vollständige Treib-es-selbst-Anleitung an.

pass(payload) (nur <caputchin-game>)

Gibt das Verifizierungs-Gate frei: der Besucher war erfolgreich. Nur gültig, wenn trigger="manual"; es auf einem nicht-manuellen Spiel aufzurufen emittiert ein error mit Code invalid-call. Das erste pass() löst ein und sperrt das Urteil; spätere Aufrufe werden still ignoriert (eine Runde pro Session).

const widget = document.querySelector("caputchin-game");
widget.pass({ trace: roundRecord });
payload-FeldTypBedeutung
tracestringDer opake Runden-Datensatz, den dein Spiel produziert. Auf einer gegateten Runde spielt der Server ihn ab, um das maßgebliche Urteil abzuleiten; auf einem ungegateten oder nur-Spiel-Key wird er wie er ist akzeptiert. Übergib einen leeren String, wenn deine Interaktion keinen Datensatz zum Abspielen hat.

Es gibt kein score-Feld auf dieser Methode, das Gate ist das Replay des trace durch den Server, keine vom Client behauptete Punktzahl. (Ein score erscheint auf dem pass-Event, das das Widget ist, das an dich zurückmeldet, nicht du an das Widget.)

pass() aufzurufen, bevor die Runde begonnen hat (Modal / Fullscreen, Dialog noch nicht geöffnet), emittiert ein error mit Code invalid-call. Auf einem nur-Spiel-Key (kein sitekey) gibt es kein Gate freizugeben, also emittiert pass() einfach das pass-Event mit token: null.

fail(payload?) (nur <caputchin-game>)

Bricht die Runde ab: ein endgültiger Verlust. Nur gültig, wenn trigger="manual" (sonst invalid-call). Optional, eine unfertige Runde wird ohnehin als Nicht-Pass behandelt. Es bricht die laufende Verifizierung ab (die Proof-of-Work- und Instrumentierungs-Prüfungen) und bringt ein error-Event mit Code game-error-relayed zum Vorschein.

widget.fail({ code: "out-of-moves", message: "no moves left" });
payload-FeldTypBedeutung
codestring (optional)Dein Diagnose-Code; als originalCode des error-Events zum Vorschein gebracht. Standard ist game-failed.
messagestring (optional)Menschenlesbarer Grund.

Events

Lausch mit addEventListener(type, handler). Jede Payload lebt auf event.detail.

EventEmittiert vonevent.detailFeuert wenn
startbeide{ gameId: string | null }Verifizierung beginnt (auto beim Mount, bei Aktivierung oder per start()). gameId ist für eine Spiel-Runde gesetzt, null für das schlichte Widget.
passbeide{ token: string | null, score: number | null, durationMs: number | null }Verifizierung wird freigegeben. token ist das umhüllte Token, das du an dein Backend sendest; null auf einem nur-Spiel-Key (kein sitekey).
errorbeide{ code, message, severity, originalCode? }Alles von einer harmlosen Config-Warnung bis zu einem harten Versagen. Sieh dir das error-Event an.
degradedbeide{ reason: "timeout" | "network" | "http" | "malformed" }Das Widget konnte deine konfigurierte Größe / Skin / Locale nicht rechtzeitig auflösen, also rendert es mit seinen gebündelten Standardwerten. Kein Fehler. Sieh dir das degraded-Event an.
dialog-shown<caputchin-game>{ layout: "modal" | "fullscreen" }Ein Overlay-Spiel-Dialog öffnet sich (programmatisch oder erster Klick).
dialog-hidden<caputchin-game>{ layout: "modal" | "fullscreen" }Ein Overlay-Spiel-Dialog schließt sich (programmatisch, Escape oder Backdrop-Klick).

Das pass-Event und das Token

Das pass-Event ist dein Stichwort, dass die Verifizierung gelang, aber es ist nicht die Vertrauensentscheidung. Die Vertrauensentscheidung ist, dass dein Backend detail.token bestätigt. Verifizier das Token immer auf deinem Backend; gewähr nie Zugriff allein aus dem Frontend-Event. In einem Formular fügt das Widget das Token auch als caputchin-token-Feld ein, sodass ein normaler Formular-POST es trägt. Das score und durationMs auf diesem Event sind vom Client gemeldete Analysen und können null sein; behandle sie nie als Vertrauenssignal.

Das error-Event

Das error-Event trägt einen stabilen code, eine menschliche message, eine severity und manchmal einen originalCode. Jeder Code hat eine feste Standard-Severity, sodass du "lief weiter"-Warnungen von "ist wirklich kaputtgegangen"-Versagen filtern kannst, ohne eine Code-zu-Severity-Tabelle hartzucoden, lies einfach detail.severity. Der vollständige Satz Codes:

codeseverityBedeutung
invalid-configwarnEin Attribut oder eine Kombination, die das Widget ablehnte; es degradiert sanft und läuft weiter.
invalid-callwarnEine Methode aufgerufen, als sie nicht gültig war (z. B. pass() auf einem nicht-manuellen Spiel, oder bevor die Runde begann).
verification-failederrorDie Proof-of-Work- oder Instrumentierungs-Prüfung (oder das Token-Einlösen) schlug fehl; kein Token ausgegeben.
game-load-failederrorDas Spiel-Bundle konnte nicht aufgelöst, geladen oder registriert werden.
gate-unavailableerrorDer Server gab beim Bootstrap eine maßgebliche Ablehnung zurück (ein gegateter Key konnte kein gültiges Spiel liefern).
game-error-relayederrorEin Fehler kam aus dem Inneren des Spiels zum Vorschein (vom Iframe weitergereicht, oder von einem manuellen fail()).

detail.originalCode ist vorhanden, wenn der öffentliche code eine Verallgemeinerung eines spezifischeren internen Grundes ist (zum Beispiel trägt ein als game-load-failed weitergereichtes Iframe-Lade-Versagen das rohe iframe-load-failed / iframe-script-blocked / game-not-registered in originalCode). Nutz code zum Verzweigen und originalCode nur zur Diagnose.

Das degraded-Event

Beim Mount macht das Widget einen kurzen Aufruf an Caputchin, um die von dir konfigurierte Größe, Skin und Locale aufzulösen (und, bei einem Marketplace-Spiel, dessen bevorzugten Footprint). Falls dieser Aufruf fehlschlägt oder zu langsam ist, blockiert oder bricht das Widget nicht: es rendert mit den ins Bundle eingebackenen Werten und emittiert degraded, sodass der Rückfall nie stumm ist. Das Widget bleibt nach einem degraded-Event voll funktionsfähig, nur die aufgelöste Darstellung kann sich von dem unterscheiden, was du konfiguriert hast (ein Spiel erscheint vielleicht in seiner Standardgröße, oder die Checkbox in ihrem Standard-Theme). Das Widget versucht eine langsame Auflösung erneut, bevor es zurückfällt, also bedeutet degraded, dass die Versuche erschöpft waren, nicht dass ein einzelner Versuch langsam war.

detail.reason sagt dir, warum die Auflösung zurückfiel, sodass du es in deiner eigenen Telemetrie sichtbar machen kannst:

reasonBedeutung
timeoutDie Auflösung antwortete nicht innerhalb ihres Zeitbudgets (Dienst langsam oder nicht erreichbar).
networkDie Anfrage selbst scheiterte (offline, DNS, blockiert oder Verbindung zurückgesetzt).
httpDer Dienst antwortete mit einem Fehlerstatus.
malformedDer Dienst antwortete, aber der Body war nicht gültig.

degraded ist ein Hinweis, kein Versagen, also ist es absichtlich kein error-Event: eine langsame Auflösung sollte nicht die Handler auslösen, die du für echte Fehler verdrahtest. Lausch nur darauf, wenn du degradierte Renders beobachten willst, zum Beispiel um zu alarmieren, wenn deine Besucher die Fallback-Darstellung sehen.

Lauschen, in der Praxis

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);

Das sind native DOM-CustomEvents, also hängst du sie in React mit einem ref und addEventListener an (keine JSX-onPass-Props); die Frontend-Beispiele zeigen die framework-spezifische Verdrahtung. Weil jedes Event bubblet und composed ist, kannst du auch von einem Container-Element delegieren, statt jedes Widget einzeln zu binden.

Siehe auch

Auf dieser Seite