Caputchin
المراجع

طرائق الأداة وأحداثها

تشحن أداة Caputchin عنصرين مخصّصين، وتتفاعل صفحتك معهما باتّجاهين: تنادي طرائق على العنصر لتقوده، وتنصت لأحداث يبثّها لتتفاعل. هذه الصفحة المرجع الشامل لكلا السطحين.

كل حدث CustomEvent مُرسَل بـ bubbles: true وcomposed: true، فيفلت من DOM الظلّ للأداة وتستطيع الإنصات له مباشرةً على العنصر (أو على أي سلف). البيانات دائمًا على event.detail.

العنصران في لمحة

العنصرالغرضالطرائق
<caputchin-widget>التحقّق فقط (proof-of-work / خانة اختيار).start()
<caputchin-game>مضيف لعبة، بتحقّق اختياري.pass()، وfail()

أداة خانة الاختيار لها start() فقط؛ لا تكشف pass() / fail(). مضيف اللعبة لا start() له (جولته تصير حيّةً عند التركيب لـ inline، أو عند أول فتح حوار لـ modal / fullscreen). كلا العنصرين يبثّان start، وpass، وerror، وdegraded؛ ويبثّ مضيف اللعبة إضافةً dialog-shown وdialog-hidden. التغطية في جدول الأحداث أدناه.

الطرائق

start() (<caputchin-widget> فقط)

يبدأ التحقّق فورًا. غرضه المُطلِق اليدوي: حين يحمل العنصر trigger="manual"، تنادي start() لإطلاق حلّ proof-of-work من إيماءتك الخاصة (مثلًا، عند إرسال نموذجك) بدل خانة الاختيار المدمجة. مع المُطلِقَين الافتراضيين auto / click يوصّل العنصر تفعيله الخاص، فلا تناديه.

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

مضيف اللعبة لا start() له. انظر الوضع اليدوي للشرح الكامل لقيادته بنفسك.

pass(payload) (<caputchin-game> فقط)

يطلق بوّابة التحقّق: نجح الزائر. يصحّ فقط حين trigger="manual"؛ ونداؤه على لعبة غير يدوية يبثّ error برمز invalid-call. أول pass() يصرف ويقفل الحُكم؛ والنداءات اللاحقة تُتجاهَل بصمت (جولة واحدة لكل جلسة).

const widget = document.querySelector("caputchin-game");
widget.pass({ trace: roundRecord });
حقل payloadالنوعالمعنى
tracestringسجلّ الجولة المعتم الذي تنتجه لعبتك. على جولة محكومة يعيد الخادم تشغيله لاشتقاق الحُكم الموثوق؛ وعلى مفتاح غير محكوم أو لعبة-فقط يُقبَل كما هو. مرّر سلسلة فارغة إن لم يكن لتفاعلك سجلّ لإعادة تشغيله.

لا حقل score على هذه الطريقة، البوّابة هي إعادة تشغيل الخادم لـ trace، لا نتيجة يدّعيها العميل. (score يظهر فعلًا على حدث pass، وهو الأداة تبلّغك، لا أنت تبلّغ الأداة.)

نداء pass() قبل أن تبدأ الجولة (modal / fullscreen، الحوار لم يُفتَح بعد) يبثّ error برمز invalid-call. على مفتاح لعبة-فقط (لا sitekey) لا بوّابة لتطلقها، فـ pass() ببساطة يبثّ حدث pass بـ token: null.

fail(payload?) (<caputchin-game> فقط)

يجهض الجولة: خسارة قاطعة. يصحّ فقط حين trigger="manual" (وإلا invalid-call). اختياري، جولة غير منتهية تُعامَل كغير ناجحة على أي حال. يجهض التحقّق الجاري (فحصا proof-of-work والرصد) ويُظهر حدث error برمز game-error-relayed.

widget.fail({ code: "out-of-moves", message: "no moves left" });
حقل payloadالنوعالمعنى
codestring (اختياري)رمزك التشخيصي؛ يُظهَر كـ originalCode لحدث error. الافتراضي game-failed.
messagestring (اختياري)سبب مقروء للبشر.

الأحداث

أنصِت بـ addEventListener(type, handler). كل حمولة تقيم على event.detail.

الحدثيبثّهevent.detailيطلق حين
startكلاهما{ gameId: string | null }يبدأ التحقّق (تلقائيًّا عند التركيب، أو عند التفعيل، أو عبر start()). gameId مضبوط لجولة لعبة، وnull للأداة العادية.
passكلاهما{ token: string | null, score: number | null, durationMs: number | null }يُطلَق التحقّق. token هو الرمز المغلَّف لإرساله إلى خادمك الخلفي؛ null على مفتاح لعبة-فقط (لا sitekey).
errorكلاهما{ code, message, severity, originalCode? }أي شيء من تنبيه إعداد حميد إلى فشل صلب. انظر حدث error.
degradedكلاهما{ reason: "timeout" | "network" | "http" | "malformed" }تعذّر على الأداة حلّ المقاس / المظهر / اللغة الذين أعددتهم في الوقت المناسب، فعرضت بقيمها الافتراضية المضمَّنة. ليس خطأً. انظر حدث degraded.
dialog-shown<caputchin-game>{ layout: "modal" | "fullscreen" }يُفتَح حوار لعبة تراكبيّ (برمجيًّا أو بأول نقرة).
dialog-hidden<caputchin-game>{ layout: "modal" | "fullscreen" }يُغلَق حوار لعبة تراكبيّ (برمجيًّا، أو بـ Escape، أو بنقرة الخلفية).

حدث pass والرمز

حدث pass إشارتك إلى أن التحقّق نجح، لكنه ليس قرار الثقة. قرار الثقة هو تأكيد خادمك الخلفي لـ detail.token. تحقّق دائمًا من الرمز على خادمك الخلفي؛ لا تمنح وصولًا عن حدث الواجهة وحده أبدًا. في نموذج، تحقن الأداة أيضًا الرمز كحقل caputchin-token كي يحمله POST نموذج عاديّ. score وdurationMs على هذا الحدث تحليلات يبلّغها العميل وقد تكون null؛ لا تعاملها كإشارة ثقة أبدًا.

حدث error

يحمل حدث error رمز code ثابتًا، وmessage بشريًّا، وseverity، وأحيانًا originalCode. لكل رمز خطورة افتراضية ثابتة كي ترشّح تنبيهات "بقي يعمل" من فشل "انكسر فعلًا" دون ترميز جدول رمز-إلى-خطورة، اقرأ detail.severity فقط. مجموعة الرموز الكاملة:

codeseverityالمعنى
invalid-configwarnسمة أو تركيبة رفضتها الأداة؛ تتدهور برشاقة وتبقى تعمل.
invalid-callwarnطريقة نوديت حين لم تصحّ (مثلًا pass() على لعبة غير يدوية، أو قبل بدء الجولة).
verification-failederrorفشل فحص proof-of-work أو الرصد (أو صرف الرمز)؛ لا رمز صدر.
game-load-failederrorتعذّر حلّ حزمة اللعبة، أو تحميلها، أو تسجيلها.
gate-unavailableerrorأعاد الخادم رفضًا موثوقًا عند الإقلاع (مفتاح محكوم تعذّر عليه تقديم لعبة صالحة).
game-error-relayederrorخطأ ظهر من داخل اللعبة (مُرحَّلًا من الإطار، أو من fail() يدويّ).

detail.originalCode موجود حين يكون code العام تعميمًا لسبب داخليّ أخصّ (مثلًا، فشل تحميل إطار مُرحَّل كـ game-load-failed يحمل iframe-load-failed / iframe-script-blocked / game-not-registered الخام في originalCode). استخدم code للتفرّع وoriginalCode للتشخيص فقط.

حدث degraded

عند التركيب تجري الأداة نداءً قصيرًا واحدًا إلى Caputchin كي تحلّ المقاس والمظهر واللغة الذين أعددتهم (ولـ لعبة سوق، بصمتها المفضّلة). إن فشل ذلك النداء أو تأخّر كثيرًا، لا تتوقّف الأداة ولا تنكسر: تعرض بالقيم المخبوزة في الحزمة وتبثّ degraded كي لا يكون الرجوع إلى الافتراضي صامتًا أبدًا. تبقى الأداة عاملةً بالكامل بعد حدث degraded، فقط العرض المحلول قد يختلف عمّا أعددته (قد تظهر لعبة بمقاسها الافتراضي، أو خانة الاختيار بمظهرها الافتراضي). تعيد الأداة محاولة الحلّ البطيء قبل أن ترجع إلى الافتراضي، فـdegraded يعني أن المحاولات استُنفدت، لا أن محاولةً واحدةً كانت بطيئة.

detail.reason يخبرك لماذا رجع الحلّ إلى الافتراضي، كي تظهره في قياساتك الخاصّة:

reasonالمعنى
timeoutلم يجب الحلّ ضمن ميزانيّته الزمنيّة (الخدمة بطيئة أو غير قابلة للوصول).
networkفشل الطلب نفسه (دون اتّصال، أو DNS، أو محجوب، أو إعادة تعيين الاتّصال).
httpأجابت الخدمة بحالة خطأ.
malformedأجابت الخدمة، لكن الجسم لم يكن صالحًا.

degraded إشعار، لا فشل، فهو عمدًا ليس حدث error: حلّ بطيء لا ينبغي أن يطلق المعالِجات التي تصلها لأعطال حقيقيّة. أنصت له فقط إن أردت أن ترصد العروض المتدهورة، مثلًا لتنبّه حين يرى زوّارك عرضًا افتراضيًّا.

الإنصات، عمليًّا

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

هذه CustomEvent أصيلة من DOM، ففي React تربطها بـ ref وaddEventListener (لا خصائص JSX‏ onPassأمثلة الواجهة تعرض التوصيل الخاص بكل إطار عمل. ولأن كل حدث يطفو ومركَّب، تستطيع أيضًا التفويض من عنصر حاوية بدل ربط كل أداة منفردةً.

انظر أيضًا

في هذه الصفحة