@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 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 {};