@tsdevstack/react-bot-detection 0.1.4
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/LICENSE +21 -0
- package/README.md +314 -0
- package/dist/components/bot-protected-form.d.ts +42 -0
- package/dist/components/bot-protected-form.js +114 -0
- package/dist/components/bot-protected-form.test.d.ts +1 -0
- package/dist/components/bot-protected-form.test.js +366 -0
- package/dist/components/honeypot.d.ts +30 -0
- package/dist/components/honeypot.js +40 -0
- package/dist/components/honeypot.test.d.ts +1 -0
- package/dist/components/honeypot.test.js +186 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +3 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/use-bot-detection.d.ts +31 -0
- package/dist/hooks/use-bot-detection.js +140 -0
- package/dist/hooks/use-bot-detection.test.d.ts +1 -0
- package/dist/hooks/use-bot-detection.test.js +384 -0
- package/dist/hooks/use-honeypot.d.ts +32 -0
- package/dist/hooks/use-honeypot.js +29 -0
- package/dist/hooks/use-honeypot.test.d.ts +1 -0
- package/dist/hooks/use-honeypot.test.js +78 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +3 -0
- package/dist/types/bot-detection.d.ts +33 -0
- package/dist/types/bot-detection.js +0 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +0 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 tsdevstack
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
# @tsdevstack/react-bot-detection
|
|
2
|
+
|
|
3
|
+
React hooks and components for client-side bot detection using behavioral analysis and honeypot fields.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Behavioral Analysis** - Tracks mouse movements, typing patterns, and form interactions
|
|
8
|
+
- **Honeypot Fields** - Hidden fields that bots typically fill out
|
|
9
|
+
- **Zero Dependencies** - Only requires React as a peer dependency
|
|
10
|
+
- **TypeScript** - Full type definitions included
|
|
11
|
+
- **SSR Safe** - Works with Next.js and other SSR frameworks
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @tsdevstack/react-bot-detection
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
The simplest way to add bot protection to your forms:
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { BotProtectedForm } from '@tsdevstack/react-bot-detection';
|
|
25
|
+
|
|
26
|
+
function ContactForm() {
|
|
27
|
+
const handleSubmit = async (formData: FormData, botResult) => {
|
|
28
|
+
// botResult contains detection info you can send to your backend
|
|
29
|
+
const response = await fetch('/api/contact', {
|
|
30
|
+
method: 'POST',
|
|
31
|
+
body: JSON.stringify({
|
|
32
|
+
email: formData.get('email'),
|
|
33
|
+
message: formData.get('message'),
|
|
34
|
+
botScore: botResult.score,
|
|
35
|
+
isBot: botResult.isBot,
|
|
36
|
+
}),
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<BotProtectedForm onSubmit={handleSubmit}>
|
|
42
|
+
<input name="email" type="email" placeholder="Email" />
|
|
43
|
+
<textarea name="message" placeholder="Message" />
|
|
44
|
+
</BotProtectedForm>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## API Reference
|
|
50
|
+
|
|
51
|
+
### `<BotProtectedForm>`
|
|
52
|
+
|
|
53
|
+
A form wrapper that combines behavioral analysis and honeypot detection.
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
import { BotProtectedForm } from '@tsdevstack/react-bot-detection';
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
#### Props
|
|
60
|
+
|
|
61
|
+
| Prop | Type | Default | Description |
|
|
62
|
+
|------|------|---------|-------------|
|
|
63
|
+
| `children` | `ReactNode` | required | Form content (inputs, labels, etc.) |
|
|
64
|
+
| `onSubmit` | `(data: FormData, result: BotDetectionResult) => Promise<void>` | required | Called on valid submission |
|
|
65
|
+
| `onBotDetected` | `(result: BotDetectionResult) => void` | - | Called when bot is detected |
|
|
66
|
+
| `submitButtonText` | `string` | `"Submit"` | Button text |
|
|
67
|
+
| `loadingButtonText` | `string` | `"Processing"` | Button text while submitting |
|
|
68
|
+
| `className` | `string` | - | CSS class for form element |
|
|
69
|
+
| `ButtonComponent` | `ComponentType<ButtonComponentProps>` | - | Custom button component |
|
|
70
|
+
| `showDebugPanel` | `boolean` | `false` | Show debug info (dev only) |
|
|
71
|
+
|
|
72
|
+
#### Custom Button Component
|
|
73
|
+
|
|
74
|
+
Integrate with your design system:
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
import { BotProtectedForm } from '@tsdevstack/react-bot-detection';
|
|
78
|
+
import { Button } from '@/components/ui/button';
|
|
79
|
+
|
|
80
|
+
<BotProtectedForm
|
|
81
|
+
onSubmit={handleSubmit}
|
|
82
|
+
ButtonComponent={({ children, disabled, type }) => (
|
|
83
|
+
<Button type={type} disabled={disabled}>
|
|
84
|
+
{children}
|
|
85
|
+
</Button>
|
|
86
|
+
)}
|
|
87
|
+
>
|
|
88
|
+
{/* form fields */}
|
|
89
|
+
</BotProtectedForm>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### `useBotDetection()`
|
|
95
|
+
|
|
96
|
+
Hook for behavioral analysis. Use this for custom form implementations.
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
import { useBotDetection } from '@tsdevstack/react-bot-detection';
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### Returns
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
interface UseBotDetectionReturn {
|
|
106
|
+
botScore: number; // Current score (0-100+)
|
|
107
|
+
detectionReasons: string[]; // Human-readable reasons
|
|
108
|
+
isBot: boolean; // true if score >= 50
|
|
109
|
+
handleFieldFocus: () => void; // Call on field focus
|
|
110
|
+
handleFormSubmit: () => BotDetectionResult; // Call before submit
|
|
111
|
+
stats: BotDetectionStats; // Raw statistics
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### Example
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
import { useBotDetection } from '@tsdevstack/react-bot-detection';
|
|
119
|
+
|
|
120
|
+
function CustomForm() {
|
|
121
|
+
const { handleFieldFocus, handleFormSubmit, isBot } = useBotDetection();
|
|
122
|
+
|
|
123
|
+
const onSubmit = (e: FormEvent) => {
|
|
124
|
+
e.preventDefault();
|
|
125
|
+
|
|
126
|
+
const result = handleFormSubmit();
|
|
127
|
+
if (result.isBot) {
|
|
128
|
+
console.log('Bot detected:', result.reasons);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Proceed with form submission
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
<form onSubmit={onSubmit}>
|
|
137
|
+
<input onFocus={handleFieldFocus} name="email" />
|
|
138
|
+
<button type="submit" disabled={isBot}>Submit</button>
|
|
139
|
+
</form>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### `useHoneypot()`
|
|
147
|
+
|
|
148
|
+
Hook for honeypot-based detection. Use alongside `useBotDetection` for custom forms.
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
import { useHoneypot } from '@tsdevstack/react-bot-detection';
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### Returns
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
interface UseHoneypotReturn {
|
|
158
|
+
isBotDetected: boolean; // true if honeypot was filled
|
|
159
|
+
botScore: number; // Score contribution (50 if triggered)
|
|
160
|
+
handleBotDetected: () => void; // Manual trigger
|
|
161
|
+
resetDetection: () => void; // Reset state
|
|
162
|
+
HoneypotComponent: () => ReactElement; // Pre-configured component
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### Example
|
|
167
|
+
|
|
168
|
+
```tsx
|
|
169
|
+
import { useHoneypot, useBotDetection } from '@tsdevstack/react-bot-detection';
|
|
170
|
+
|
|
171
|
+
function CustomForm() {
|
|
172
|
+
const { HoneypotComponent, isBotDetected } = useHoneypot();
|
|
173
|
+
const { handleFormSubmit } = useBotDetection();
|
|
174
|
+
|
|
175
|
+
const onSubmit = (e: FormEvent) => {
|
|
176
|
+
e.preventDefault();
|
|
177
|
+
|
|
178
|
+
if (isBotDetected) {
|
|
179
|
+
return; // Silently reject
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const result = handleFormSubmit();
|
|
183
|
+
// Combine honeypot + behavioral results
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
return (
|
|
187
|
+
<form onSubmit={onSubmit}>
|
|
188
|
+
<HoneypotComponent />
|
|
189
|
+
<input name="email" />
|
|
190
|
+
<button type="submit">Submit</button>
|
|
191
|
+
</form>
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
### `<Honeypot>`
|
|
199
|
+
|
|
200
|
+
Standalone honeypot component for full control.
|
|
201
|
+
|
|
202
|
+
```tsx
|
|
203
|
+
import { Honeypot } from '@tsdevstack/react-bot-detection';
|
|
204
|
+
|
|
205
|
+
<Honeypot onBotDetected={() => setIsBot(true)} />
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Types
|
|
211
|
+
|
|
212
|
+
### `BotDetectionResult`
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
interface BotDetectionResult {
|
|
216
|
+
score: number; // Combined score (0-100+)
|
|
217
|
+
reasons: string[]; // Detection reasons
|
|
218
|
+
isBot: boolean; // true if score >= 50
|
|
219
|
+
stats: BotDetectionStats; // Raw statistics
|
|
220
|
+
honeypotTriggered: boolean; // true if honeypot filled
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### `BotDetectionStats`
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
interface BotDetectionStats {
|
|
228
|
+
mouseMovements: number; // Mouse events tracked
|
|
229
|
+
typingEvents: number; // Keystrokes tracked
|
|
230
|
+
focusEvents: number; // Focus events tracked
|
|
231
|
+
timeSpent: number; // Time on form (ms)
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### `ButtonComponentProps`
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
interface ButtonComponentProps {
|
|
239
|
+
type: 'submit';
|
|
240
|
+
disabled: boolean;
|
|
241
|
+
className?: string;
|
|
242
|
+
children: React.ReactNode;
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## How Detection Works
|
|
249
|
+
|
|
250
|
+
### Behavioral Analysis
|
|
251
|
+
|
|
252
|
+
The `useBotDetection` hook tracks:
|
|
253
|
+
|
|
254
|
+
| Signal | Score | Description |
|
|
255
|
+
|--------|-------|-------------|
|
|
256
|
+
| No mouse movement | +30 | Bots often don't move the mouse |
|
|
257
|
+
| Unnatural mouse patterns | +20 | Perfectly straight lines, no variation |
|
|
258
|
+
| Consistent typing speed | +15 | Humans have variable typing rhythm |
|
|
259
|
+
| Superhuman typing | +20 | < 50ms between keystrokes |
|
|
260
|
+
| Fast form completion | +40 | < 2 seconds total time |
|
|
261
|
+
| Few focus events | +15 | < 2 field interactions |
|
|
262
|
+
| WebDriver detected | +25 | `navigator.webdriver === true` |
|
|
263
|
+
| Headless browser | +35 | Window size is 0 |
|
|
264
|
+
|
|
265
|
+
**Threshold:** Score >= 50 is considered a bot.
|
|
266
|
+
|
|
267
|
+
### Honeypot Detection
|
|
268
|
+
|
|
269
|
+
Hidden fields styled to be invisible to humans but visible to bots that parse HTML. When filled, adds +100 to score.
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Best Practices
|
|
274
|
+
|
|
275
|
+
### 1. Always Validate Server-Side
|
|
276
|
+
|
|
277
|
+
Client-side detection can be bypassed. Always validate the `botScore` on your backend:
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
// API route
|
|
281
|
+
export async function POST(req: Request) {
|
|
282
|
+
const { botScore, isBot, ...formData } = await req.json();
|
|
283
|
+
|
|
284
|
+
if (isBot || botScore >= 50) {
|
|
285
|
+
// Log for analysis, but don't reveal detection
|
|
286
|
+
return new Response('OK', { status: 200 });
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Process legitimate submission
|
|
290
|
+
}
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### 2. Don't Block Immediately
|
|
294
|
+
|
|
295
|
+
Silently accept bot submissions but don't process them. This prevents bots from learning your detection methods.
|
|
296
|
+
|
|
297
|
+
### 3. Use Debug Panel in Development
|
|
298
|
+
|
|
299
|
+
```tsx
|
|
300
|
+
<BotProtectedForm onSubmit={handleSubmit} showDebugPanel={process.env.NODE_ENV === 'development'}>
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### 4. Combine with Rate Limiting
|
|
304
|
+
|
|
305
|
+
Bot detection is one layer. Also implement:
|
|
306
|
+
- Rate limiting per IP
|
|
307
|
+
- CAPTCHA for suspicious scores (30-49)
|
|
308
|
+
- Email verification for signups
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## License
|
|
313
|
+
|
|
314
|
+
MIT
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { BotDetectionResult, ButtonComponentProps } from '../types';
|
|
3
|
+
export interface BotProtectedFormProps {
|
|
4
|
+
/** Form content (input fields, etc.) */
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
/** Called on form submission with FormData and bot detection result */
|
|
7
|
+
onSubmit: (data: FormData, botDetection: BotDetectionResult) => Promise<void>;
|
|
8
|
+
/** Called when bot is detected (optional) */
|
|
9
|
+
onBotDetected?: (result: BotDetectionResult) => void;
|
|
10
|
+
/** Text for submit button (default: "Submit") */
|
|
11
|
+
submitButtonText?: string;
|
|
12
|
+
/** Text while submitting (default: "Processing") */
|
|
13
|
+
loadingButtonText?: string;
|
|
14
|
+
/** CSS class for the form element */
|
|
15
|
+
className?: string;
|
|
16
|
+
/** Custom button component to match your design system */
|
|
17
|
+
ButtonComponent?: React.ComponentType<ButtonComponentProps>;
|
|
18
|
+
/** Show debug panel with detection stats (default: false) */
|
|
19
|
+
showDebugPanel?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Form wrapper with integrated bot detection.
|
|
23
|
+
*
|
|
24
|
+
* Combines behavioral analysis and honeypot detection to protect forms
|
|
25
|
+
* from automated submissions.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```tsx
|
|
29
|
+
* import { BotProtectedForm } from '@tsdevstack/react-bot-detection';
|
|
30
|
+
* import { Button } from '@/components/ui/button';
|
|
31
|
+
*
|
|
32
|
+
* <BotProtectedForm
|
|
33
|
+
* onSubmit={async (formData, botResult) => {
|
|
34
|
+
* // Send formData and botResult to your API
|
|
35
|
+
* }}
|
|
36
|
+
* ButtonComponent={Button}
|
|
37
|
+
* >
|
|
38
|
+
* <input name="email" type="email" />
|
|
39
|
+
* </BotProtectedForm>
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function BotProtectedForm({ children, onSubmit, onBotDetected, submitButtonText, loadingButtonText, className, ButtonComponent, showDebugPanel, }: BotProtectedFormProps): React.ReactElement;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useEffect, useState } from "react";
|
|
4
|
+
import { useBotDetection } from "../hooks/use-bot-detection.js";
|
|
5
|
+
import { useHoneypot } from "../hooks/use-honeypot.js";
|
|
6
|
+
function DefaultButton({ children, disabled, className, type }) {
|
|
7
|
+
return /*#__PURE__*/ jsx("button", {
|
|
8
|
+
type: type,
|
|
9
|
+
disabled: disabled,
|
|
10
|
+
className: className,
|
|
11
|
+
style: {
|
|
12
|
+
padding: '0.5rem 1rem',
|
|
13
|
+
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
14
|
+
opacity: disabled ? 0.5 : 1
|
|
15
|
+
},
|
|
16
|
+
children: children
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function BotProtectedForm({ children, onSubmit, onBotDetected, submitButtonText = 'Submit', loadingButtonText = 'Processing', className = '', ButtonComponent = DefaultButton, showDebugPanel = false }) {
|
|
20
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
21
|
+
const [isClient, setIsClient] = useState(false);
|
|
22
|
+
const { botScore, detectionReasons, isBot, handleFieldFocus, handleFormSubmit, stats } = useBotDetection();
|
|
23
|
+
const { isBotDetected: honeypotTriggered, HoneypotComponent } = useHoneypot();
|
|
24
|
+
useEffect(()=>{
|
|
25
|
+
setIsClient(true);
|
|
26
|
+
}, []);
|
|
27
|
+
const handleSubmit = useCallback(async (e)=>{
|
|
28
|
+
e.preventDefault();
|
|
29
|
+
setIsSubmitting(true);
|
|
30
|
+
try {
|
|
31
|
+
const behaviorResult = handleFormSubmit();
|
|
32
|
+
const finalBotScore = behaviorResult.score + (honeypotTriggered ? 100 : 0);
|
|
33
|
+
const allReasons = [
|
|
34
|
+
...behaviorResult.reasons,
|
|
35
|
+
...honeypotTriggered ? [
|
|
36
|
+
'Honeypot field filled'
|
|
37
|
+
] : []
|
|
38
|
+
];
|
|
39
|
+
const botDetectionResult = {
|
|
40
|
+
score: finalBotScore,
|
|
41
|
+
reasons: allReasons,
|
|
42
|
+
isBot: finalBotScore >= 50 || honeypotTriggered,
|
|
43
|
+
stats,
|
|
44
|
+
honeypotTriggered
|
|
45
|
+
};
|
|
46
|
+
if (botDetectionResult.isBot) {
|
|
47
|
+
onBotDetected?.(botDetectionResult);
|
|
48
|
+
setIsSubmitting(false);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const formData = new FormData(e.currentTarget);
|
|
52
|
+
await onSubmit(formData, botDetectionResult);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error('Form submission error:', error);
|
|
55
|
+
} finally{
|
|
56
|
+
setIsSubmitting(false);
|
|
57
|
+
}
|
|
58
|
+
}, [
|
|
59
|
+
handleFormSubmit,
|
|
60
|
+
honeypotTriggered,
|
|
61
|
+
onBotDetected,
|
|
62
|
+
onSubmit,
|
|
63
|
+
stats
|
|
64
|
+
]);
|
|
65
|
+
return /*#__PURE__*/ jsxs("form", {
|
|
66
|
+
onSubmit: handleSubmit,
|
|
67
|
+
className: className,
|
|
68
|
+
children: [
|
|
69
|
+
/*#__PURE__*/ jsx(HoneypotComponent, {}),
|
|
70
|
+
/*#__PURE__*/ jsx("div", {
|
|
71
|
+
onFocus: handleFieldFocus,
|
|
72
|
+
children: children
|
|
73
|
+
}),
|
|
74
|
+
/*#__PURE__*/ jsx(ButtonComponent, {
|
|
75
|
+
type: "submit",
|
|
76
|
+
disabled: isSubmitting,
|
|
77
|
+
className: "w-full",
|
|
78
|
+
children: isSubmitting ? loadingButtonText : submitButtonText
|
|
79
|
+
}),
|
|
80
|
+
showDebugPanel && isClient && /*#__PURE__*/ jsx("div", {
|
|
81
|
+
style: {
|
|
82
|
+
marginTop: '1rem',
|
|
83
|
+
fontSize: '0.75rem',
|
|
84
|
+
color: '#666'
|
|
85
|
+
},
|
|
86
|
+
children: /*#__PURE__*/ jsxs("details", {
|
|
87
|
+
children: [
|
|
88
|
+
/*#__PURE__*/ jsx("summary", {
|
|
89
|
+
style: {
|
|
90
|
+
cursor: 'pointer'
|
|
91
|
+
},
|
|
92
|
+
children: "Bot Detection Debug"
|
|
93
|
+
}),
|
|
94
|
+
/*#__PURE__*/ jsx("pre", {
|
|
95
|
+
style: {
|
|
96
|
+
marginTop: '0.5rem',
|
|
97
|
+
fontSize: '0.75rem',
|
|
98
|
+
whiteSpace: 'pre-wrap'
|
|
99
|
+
},
|
|
100
|
+
children: JSON.stringify({
|
|
101
|
+
botScore,
|
|
102
|
+
detectionReasons,
|
|
103
|
+
isBot,
|
|
104
|
+
honeypotTriggered,
|
|
105
|
+
stats
|
|
106
|
+
}, null, 2)
|
|
107
|
+
})
|
|
108
|
+
]
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
]
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
export { BotProtectedForm };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|