react-gamified-captcha 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CaptchaWidget.js CHANGED
@@ -1,65 +1,43 @@
1
- import React, { useEffect, useState } from 'react';
1
+ import React, { useEffect } from 'react';
2
2
 
3
3
  export const GamifiedCaptcha = ({
4
4
  siteKey = "ch_pub_demo_testkey_12345",
5
- onHumanVerified,
6
- onError,
5
+ onHumanVerified,
6
+ gameUrl = "https://conversion.business/sunny-day-maze/",
7
7
  className = "conversion-business-widget",
8
8
  style = {}
9
9
  }) => {
10
- const [hasError, setHasError] = useState(false);
11
10
  const isInvalidKey = !siteKey || siteKey === "ch_pub_demo_testkey_12345";
12
11
 
13
12
  useEffect(() => {
14
- // 1. SSR Safety Check
15
- if (typeof window === 'undefined' || typeof document === 'undefined') {
13
+ // SSR Safety Check
14
+ if (typeof window === 'undefined') {
16
15
  return;
17
16
  }
18
17
 
19
- // 2. Funnel Logic (Console Warning for missing/demo keys)
20
18
  if (isInvalidKey) {
21
19
  console.error("Conversion.Business Error: Invalid Site Key. Please register at https://conversion.business to obtain a valid API key.");
22
- setHasError(true);
23
- return;
24
- }
25
-
26
- const scriptId = 'conversion-business-sdk';
27
- let script = document.getElementById(scriptId);
28
- let isNewScript = false;
29
-
30
- // 3. Singleton Script Loading
31
- if (!script) {
32
- script = document.createElement('script');
33
- script.id = scriptId;
34
- script.src = 'https://conversion-business-widgets.web.app/sdk.js';
35
- script.async = true;
36
- isNewScript = true;
37
-
38
- // 4. CSP/Network Error Handling (Fail-Open)
39
- script.onerror = (e) => {
40
- console.error("Conversion.Business Error: Failed to load SDK. Check your Content Security Policy or AdBlocker.", e);
41
- if (onError) onError(e);
42
- };
43
-
44
- document.body.appendChild(script);
45
20
  }
46
21
 
47
- const verificationHandler = (e) => {
48
- if (onHumanVerified && e.detail?.token) {
49
- onHumanVerified(e.detail.token);
22
+ const verificationHandler = (event) => {
23
+ // Ensure we only process events from the conversion.business iframe
24
+ if (event.data && event.data.type === 'oops_captcha_solved') {
25
+ if (onHumanVerified && event.data.payload) {
26
+ onHumanVerified(event.data.payload);
27
+ }
50
28
  }
51
29
  };
52
30
 
53
- document.addEventListener('conversion.business:verified', verificationHandler);
31
+ window.addEventListener('message', verificationHandler);
54
32
 
55
33
  return () => {
56
- document.removeEventListener('conversion.business:verified', verificationHandler);
57
- // We do not remove the script tag because other instances on the page might need it.
34
+ // Memory leak cleanup when component unmounts
35
+ window.removeEventListener('message', verificationHandler);
58
36
  };
59
- }, [siteKey, onHumanVerified, onError, isInvalidKey]);
37
+ }, [siteKey, onHumanVerified, isInvalidKey]);
60
38
 
61
- // 5. Funnel Logic (Visual Fallback for missing/demo keys)
62
- if (hasError || isInvalidKey) {
39
+ // Visual Fallback for missing/demo keys (The Funnel Trap)
40
+ if (isInvalidKey) {
63
41
  return (
64
42
  <div style={{ color: '#d32f2f', border: '1px solid #d32f2f', padding: '12px', borderRadius: '4px', backgroundColor: '#fff', fontFamily: 'sans-serif', ...style }} className={className}>
65
43
  <strong>Widget Error:</strong> Valid API Key Required. <a href="https://conversion.business" target="_blank" rel="noopener noreferrer" style={{color: '#d32f2f', textDecoration: 'underline'}}>Get your free key here</a>.
@@ -67,13 +45,13 @@ export const GamifiedCaptcha = ({
67
45
  );
68
46
  }
69
47
 
70
- // 6. Prop Forwarding to the actual widget container
48
+ // Exact iframe architecture matching portal.html
71
49
  return (
72
- <div
73
- className={className}
74
- data-sitekey={siteKey}
75
- data-theme="light"
76
- style={style}
50
+ <iframe
51
+ className={className}
52
+ src={`${gameUrl}?mode=captcha&clientId=${siteKey}`}
53
+ style={{ width: "100%", height: "400px", border: "none", borderRadius: "12px", ...style }}
54
+ title="Conversion.Business Validation"
77
55
  />
78
56
  );
79
57
  };
package/README.md CHANGED
@@ -19,13 +19,8 @@ import { GamifiedCaptcha } from 'react-gamified-captcha';
19
19
 
20
20
  function App() {
21
21
  const handleVerify = (token) => {
22
- console.log("Human verified! Token:", token);
23
- // Send this token to your backend for validation
24
- };
25
-
26
- const handleError = (error) => {
27
- console.warn("Captcha failed to load or encountered an error. Failing open.", error);
28
- // Best practice: Fail-open by allowing the user to submit the form anyway
22
+ console.log("Human verified! Token payload:", token);
23
+ // Send this payload to your backend for cryptographic HMAC verification
29
24
  };
30
25
 
31
26
  return (
@@ -35,7 +30,6 @@ function App() {
35
30
  <GamifiedCaptcha
36
31
  siteKey="YOUR_CONVERSION_BUSINESS_API_KEY"
37
32
  onHumanVerified={handleVerify}
38
- onError={handleError}
39
33
  />
40
34
 
41
35
  <button type="submit">Submit</button>
@@ -46,6 +40,3 @@ function App() {
46
40
 
47
41
  ## Next.js (SSR) Support
48
42
  This component is fully SSR-safe and can be used directly in Next.js or Remix applications without requiring dynamic imports.
49
-
50
- ## Graceful Degradation (`onError`)
51
- If a user has an aggressive ad-blocker or strict Content Security Policy that prevents our script from loading, the `onError` callback will fire. We strongly recommend implementing a **fail-open** strategy in this scenario. If `onError` triggers, simply let the user bypass the captcha so you don't lose the signup.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-gamified-captcha",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "A gamified, frictionless captcha component for React. Powered by conversion.business.",
5
5
  "main": "index.js",
6
6
  "scripts": {