@axeptio/behavior-detection 1.0.3 → 1.1.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/README.md +126 -12
- package/dist/behavior-detection.esm.min.js +1 -1
- package/dist/behavior-detection.esm.min.js.map +4 -4
- package/dist/behavior-detection.min.js +1 -1
- package/dist/behavior-detection.min.js.map +3 -3
- package/dist/cjs/index.cjs +937 -29
- package/dist/esm/browser.js +0 -2
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/strategies/click.d.ts +8 -0
- package/dist/esm/strategies/click.js +108 -9
- package/dist/esm/strategies/environment.d.ts +39 -0
- package/dist/esm/strategies/environment.js +218 -16
- package/dist/esm/strategies/index.d.ts +4 -0
- package/dist/esm/strategies/index.js +4 -0
- package/dist/esm/strategies/mouse.d.ts +53 -1
- package/dist/esm/strategies/mouse.js +198 -2
- package/dist/esm/strategies/timing.d.ts +64 -0
- package/dist/esm/strategies/timing.js +308 -0
- package/dist/esm/strategies/visibility.d.ts +64 -0
- package/dist/esm/strategies/visibility.js +295 -0
- package/dist/index.d.ts +1 -1
- package/dist/strategies/click.d.ts +8 -0
- package/dist/strategies/environment.d.ts +39 -0
- package/dist/strategies/index.d.ts +4 -0
- package/dist/strategies/mouse.d.ts +53 -1
- package/dist/strategies/timing.d.ts +64 -0
- package/dist/strategies/visibility.d.ts +64 -0
- package/package.json +1 -1
|
@@ -2,8 +2,27 @@
|
|
|
2
2
|
* Mouse Movement Detection Strategy
|
|
3
3
|
* Autonomous module that manages its own mouse event listeners and state
|
|
4
4
|
* Tracks distance and angle to detect unnatural jumps and sharp turns
|
|
5
|
+
*
|
|
6
|
+
* Enhanced detection:
|
|
7
|
+
* - Pre-click stillness (micro-movements before clicks)
|
|
8
|
+
* - Entry point analysis (where mouse enters viewport)
|
|
9
|
+
* - Velocity consistency
|
|
5
10
|
*/
|
|
6
11
|
import { BaseStrategy, type TimeSeriesPoint } from '../strategy.js';
|
|
12
|
+
interface MousePosition {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
timestamp: number;
|
|
16
|
+
}
|
|
17
|
+
interface EntryPoint {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
timestamp: number;
|
|
21
|
+
/** Distance from nearest edge (0 = at edge) */
|
|
22
|
+
edgeDistance: number;
|
|
23
|
+
/** Which edge: 'top' | 'bottom' | 'left' | 'right' | 'corner' | 'center' */
|
|
24
|
+
entryEdge: 'top' | 'bottom' | 'left' | 'right' | 'corner' | 'center';
|
|
25
|
+
}
|
|
7
26
|
export declare class MouseStrategy extends BaseStrategy {
|
|
8
27
|
readonly name = "mouse";
|
|
9
28
|
readonly defaultWeight = 0.3;
|
|
@@ -15,8 +34,15 @@ export declare class MouseStrategy extends BaseStrategy {
|
|
|
15
34
|
private rollingWindowMs;
|
|
16
35
|
private listener;
|
|
17
36
|
private leaveListener;
|
|
37
|
+
private enterListener;
|
|
18
38
|
private isActive;
|
|
19
39
|
private screenDiagonal;
|
|
40
|
+
/** Entry points tracking */
|
|
41
|
+
private entryPoints;
|
|
42
|
+
/** Micro-movements in last 500ms (for stillness detection) */
|
|
43
|
+
private microMovements;
|
|
44
|
+
/** Stillness window in ms */
|
|
45
|
+
private readonly STILLNESS_WINDOW;
|
|
20
46
|
constructor(options?: {
|
|
21
47
|
rollingWindow?: number;
|
|
22
48
|
});
|
|
@@ -26,14 +52,40 @@ export declare class MouseStrategy extends BaseStrategy {
|
|
|
26
52
|
score(): number | undefined;
|
|
27
53
|
/**
|
|
28
54
|
* Mouse-specific pattern detection
|
|
29
|
-
* Detects bot-like patterns: constant velocity, linear paths
|
|
55
|
+
* Detects bot-like patterns: constant velocity, linear paths, suspicious entry points
|
|
30
56
|
*/
|
|
31
57
|
private detectMousePatterns;
|
|
58
|
+
/**
|
|
59
|
+
* Score based on viewport entry points
|
|
60
|
+
* Humans enter from edges with momentum; bots often start at (0,0) or center
|
|
61
|
+
*/
|
|
62
|
+
private scoreEntryPoints;
|
|
63
|
+
/**
|
|
64
|
+
* Score based on micro-movements (tremor detection)
|
|
65
|
+
* Humans have natural hand tremor causing 1-5px jitter
|
|
66
|
+
* Bots have perfect stillness or no micro-movements
|
|
67
|
+
*/
|
|
68
|
+
private scoreMicroMovements;
|
|
69
|
+
/**
|
|
70
|
+
* Get micro-movement count for external use (e.g., by ClickStrategy)
|
|
71
|
+
*/
|
|
72
|
+
getMicroMovementCount(): number;
|
|
73
|
+
/**
|
|
74
|
+
* Get last position for external use
|
|
75
|
+
*/
|
|
76
|
+
getLastPosition(): {
|
|
77
|
+
x: number;
|
|
78
|
+
y: number;
|
|
79
|
+
} | null;
|
|
32
80
|
getDebugInfo(): {
|
|
33
81
|
eventCount: number;
|
|
34
82
|
rollingWindow: number;
|
|
35
83
|
isActive: boolean;
|
|
36
84
|
distanceSeries: TimeSeriesPoint[];
|
|
37
85
|
angleSeries: TimeSeriesPoint[];
|
|
86
|
+
entryPoints: EntryPoint[];
|
|
87
|
+
microMovementCount: number;
|
|
88
|
+
lastPosition: MousePosition | null;
|
|
38
89
|
};
|
|
39
90
|
}
|
|
91
|
+
export {};
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
* Mouse Movement Detection Strategy
|
|
3
3
|
* Autonomous module that manages its own mouse event listeners and state
|
|
4
4
|
* Tracks distance and angle to detect unnatural jumps and sharp turns
|
|
5
|
+
*
|
|
6
|
+
* Enhanced detection:
|
|
7
|
+
* - Pre-click stillness (micro-movements before clicks)
|
|
8
|
+
* - Entry point analysis (where mouse enters viewport)
|
|
9
|
+
* - Velocity consistency
|
|
5
10
|
*/
|
|
6
11
|
import { BaseStrategy } from '../strategy.js';
|
|
7
12
|
import { calculateStatistics, gaussian } from '../math-utils.js';
|
|
@@ -18,8 +23,15 @@ export class MouseStrategy extends BaseStrategy {
|
|
|
18
23
|
this.rollingWindowMs = 5000;
|
|
19
24
|
this.listener = null;
|
|
20
25
|
this.leaveListener = null;
|
|
26
|
+
this.enterListener = null;
|
|
21
27
|
this.isActive = false;
|
|
22
28
|
this.screenDiagonal = 1;
|
|
29
|
+
/** Entry points tracking */
|
|
30
|
+
this.entryPoints = [];
|
|
31
|
+
/** Micro-movements in last 500ms (for stillness detection) */
|
|
32
|
+
this.microMovements = [];
|
|
33
|
+
/** Stillness window in ms */
|
|
34
|
+
this.STILLNESS_WINDOW = 500;
|
|
23
35
|
if ((options === null || options === void 0 ? void 0 : options.rollingWindow) !== undefined)
|
|
24
36
|
this.rollingWindowMs = options.rollingWindow;
|
|
25
37
|
}
|
|
@@ -34,12 +46,21 @@ export class MouseStrategy extends BaseStrategy {
|
|
|
34
46
|
this.listener = (e) => {
|
|
35
47
|
const mouseEvent = e;
|
|
36
48
|
const now = Date.now();
|
|
37
|
-
const currentPos = { x: mouseEvent.clientX, y: mouseEvent.clientY };
|
|
49
|
+
const currentPos = { x: mouseEvent.clientX, y: mouseEvent.clientY, timestamp: now };
|
|
38
50
|
// Calculate distance and angle from previous position
|
|
39
51
|
if (this.lastPosition) {
|
|
40
52
|
const dx = currentPos.x - this.lastPosition.x;
|
|
41
53
|
const dy = currentPos.y - this.lastPosition.y;
|
|
42
54
|
const pixelDistance = Math.sqrt(dx * dx + dy * dy);
|
|
55
|
+
// Track micro-movements (1-5px) for stillness detection
|
|
56
|
+
if (pixelDistance >= 1 && pixelDistance <= 5) {
|
|
57
|
+
this.microMovements.push({ dx, dy, timestamp: now });
|
|
58
|
+
// Clean up old micro-movements (shift from front, more efficient than filter)
|
|
59
|
+
const cutoffMicro = now - this.STILLNESS_WINDOW;
|
|
60
|
+
while (this.microMovements.length > 0 && this.microMovements[0].timestamp < cutoffMicro) {
|
|
61
|
+
this.microMovements.shift();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
43
64
|
// Normalize distance to screen diagonal (0-1 range)
|
|
44
65
|
// A full diagonal movement = 1.0, a 10px movement on 2000px screen = 0.005
|
|
45
66
|
const normalizedDistance = pixelDistance / this.screenDiagonal;
|
|
@@ -72,6 +93,67 @@ export class MouseStrategy extends BaseStrategy {
|
|
|
72
93
|
this.lastPosition = currentPos;
|
|
73
94
|
};
|
|
74
95
|
document.addEventListener('mousemove', this.listener, { passive: true });
|
|
96
|
+
// Track mouse entry points into viewport
|
|
97
|
+
this.enterListener = (e) => {
|
|
98
|
+
const mouseEvent = e;
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
const x = mouseEvent.clientX;
|
|
101
|
+
const y = mouseEvent.clientY;
|
|
102
|
+
const width = window.innerWidth;
|
|
103
|
+
const height = window.innerHeight;
|
|
104
|
+
// Calculate edge distances
|
|
105
|
+
const distTop = y;
|
|
106
|
+
const distBottom = height - y;
|
|
107
|
+
const distLeft = x;
|
|
108
|
+
const distRight = width - x;
|
|
109
|
+
const minEdgeDist = Math.min(distTop, distBottom, distLeft, distRight);
|
|
110
|
+
// Determine entry edge
|
|
111
|
+
let entryEdge;
|
|
112
|
+
const edgeThreshold = 50; // pixels from edge to count as edge entry
|
|
113
|
+
if (minEdgeDist < edgeThreshold) {
|
|
114
|
+
if (distTop <= minEdgeDist)
|
|
115
|
+
entryEdge = 'top';
|
|
116
|
+
else if (distBottom <= minEdgeDist)
|
|
117
|
+
entryEdge = 'bottom';
|
|
118
|
+
else if (distLeft <= minEdgeDist)
|
|
119
|
+
entryEdge = 'left';
|
|
120
|
+
else
|
|
121
|
+
entryEdge = 'right';
|
|
122
|
+
}
|
|
123
|
+
else if (x > width * 0.35 && x < width * 0.65 &&
|
|
124
|
+
y > height * 0.35 && y < height * 0.65) {
|
|
125
|
+
entryEdge = 'center'; // Suspicious - bots often start at center
|
|
126
|
+
}
|
|
127
|
+
else if ((distTop < edgeThreshold * 2 && distLeft < edgeThreshold * 2) ||
|
|
128
|
+
(distTop < edgeThreshold * 2 && distRight < edgeThreshold * 2) ||
|
|
129
|
+
(distBottom < edgeThreshold * 2 && distLeft < edgeThreshold * 2) ||
|
|
130
|
+
(distBottom < edgeThreshold * 2 && distRight < edgeThreshold * 2)) {
|
|
131
|
+
entryEdge = 'corner';
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
// Entry from middle of an edge, normal
|
|
135
|
+
if (distTop < distBottom && distTop < distLeft && distTop < distRight)
|
|
136
|
+
entryEdge = 'top';
|
|
137
|
+
else if (distBottom < distLeft && distBottom < distRight)
|
|
138
|
+
entryEdge = 'bottom';
|
|
139
|
+
else if (distLeft < distRight)
|
|
140
|
+
entryEdge = 'left';
|
|
141
|
+
else
|
|
142
|
+
entryEdge = 'right';
|
|
143
|
+
}
|
|
144
|
+
this.entryPoints.push({
|
|
145
|
+
x,
|
|
146
|
+
y,
|
|
147
|
+
timestamp: now,
|
|
148
|
+
edgeDistance: minEdgeDist,
|
|
149
|
+
entryEdge,
|
|
150
|
+
});
|
|
151
|
+
// Keep only last 20 entry points (shift is more memory efficient than slice)
|
|
152
|
+
if (this.entryPoints.length > 20) {
|
|
153
|
+
this.entryPoints.shift();
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
document.addEventListener('mouseenter', this.enterListener, { passive: true });
|
|
75
157
|
// Clear data when mouse leaves the window (discontinuous tracking)
|
|
76
158
|
this.leaveListener = () => {
|
|
77
159
|
this.distanceSeries = [];
|
|
@@ -79,6 +161,7 @@ export class MouseStrategy extends BaseStrategy {
|
|
|
79
161
|
this.lastPosition = null;
|
|
80
162
|
this.lastAngle = 0;
|
|
81
163
|
this.cumulativeAngle = 0;
|
|
164
|
+
this.microMovements = [];
|
|
82
165
|
};
|
|
83
166
|
document.addEventListener('mouseleave', this.leaveListener, { passive: true });
|
|
84
167
|
}
|
|
@@ -94,6 +177,10 @@ export class MouseStrategy extends BaseStrategy {
|
|
|
94
177
|
document.removeEventListener('mouseleave', this.leaveListener);
|
|
95
178
|
this.leaveListener = null;
|
|
96
179
|
}
|
|
180
|
+
if (this.enterListener) {
|
|
181
|
+
document.removeEventListener('mouseenter', this.enterListener);
|
|
182
|
+
this.enterListener = null;
|
|
183
|
+
}
|
|
97
184
|
}
|
|
98
185
|
reset() {
|
|
99
186
|
this.distanceSeries = [];
|
|
@@ -101,6 +188,8 @@ export class MouseStrategy extends BaseStrategy {
|
|
|
101
188
|
this.lastPosition = null;
|
|
102
189
|
this.lastAngle = 0;
|
|
103
190
|
this.cumulativeAngle = 0;
|
|
191
|
+
this.entryPoints = [];
|
|
192
|
+
this.microMovements = [];
|
|
104
193
|
}
|
|
105
194
|
score() {
|
|
106
195
|
if (this.distanceSeries.length < 10)
|
|
@@ -111,7 +200,7 @@ export class MouseStrategy extends BaseStrategy {
|
|
|
111
200
|
}
|
|
112
201
|
/**
|
|
113
202
|
* Mouse-specific pattern detection
|
|
114
|
-
* Detects bot-like patterns: constant velocity, linear paths
|
|
203
|
+
* Detects bot-like patterns: constant velocity, linear paths, suspicious entry points
|
|
115
204
|
*/
|
|
116
205
|
detectMousePatterns() {
|
|
117
206
|
if (this.distanceSeries.length < 10)
|
|
@@ -141,8 +230,112 @@ export class MouseStrategy extends BaseStrategy {
|
|
|
141
230
|
score += gaussian(avgChange, 0.15, 0.12);
|
|
142
231
|
factors++;
|
|
143
232
|
}
|
|
233
|
+
// 3. ENTRY POINT ANALYSIS - Where does mouse enter the viewport?
|
|
234
|
+
const entryScore = this.scoreEntryPoints();
|
|
235
|
+
if (entryScore !== undefined) {
|
|
236
|
+
score += entryScore;
|
|
237
|
+
factors++;
|
|
238
|
+
}
|
|
239
|
+
// 4. MICRO-MOVEMENT PRESENCE - Humans have tremors, bots don't
|
|
240
|
+
const microScore = this.scoreMicroMovements();
|
|
241
|
+
if (microScore !== undefined) {
|
|
242
|
+
score += microScore;
|
|
243
|
+
factors++;
|
|
244
|
+
}
|
|
144
245
|
return factors > 0 ? score / factors : undefined;
|
|
145
246
|
}
|
|
247
|
+
/**
|
|
248
|
+
* Score based on viewport entry points
|
|
249
|
+
* Humans enter from edges with momentum; bots often start at (0,0) or center
|
|
250
|
+
*/
|
|
251
|
+
scoreEntryPoints() {
|
|
252
|
+
if (this.entryPoints.length < 2)
|
|
253
|
+
return undefined;
|
|
254
|
+
let suspiciousCount = 0;
|
|
255
|
+
let centerCount = 0;
|
|
256
|
+
let cornerCount = 0;
|
|
257
|
+
let originCount = 0;
|
|
258
|
+
for (const entry of this.entryPoints) {
|
|
259
|
+
// Check for (0,0) or near-origin entries (very suspicious)
|
|
260
|
+
if (entry.x < 5 && entry.y < 5) {
|
|
261
|
+
originCount++;
|
|
262
|
+
suspiciousCount++;
|
|
263
|
+
}
|
|
264
|
+
else if (entry.entryEdge === 'center') {
|
|
265
|
+
centerCount++;
|
|
266
|
+
suspiciousCount++;
|
|
267
|
+
}
|
|
268
|
+
else if (entry.entryEdge === 'corner') {
|
|
269
|
+
cornerCount++;
|
|
270
|
+
// Corners are slightly suspicious but not as bad as center
|
|
271
|
+
if (entry.edgeDistance < 10)
|
|
272
|
+
suspiciousCount++;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const total = this.entryPoints.length;
|
|
276
|
+
const suspiciousRatio = suspiciousCount / total;
|
|
277
|
+
// High ratio of origin entries = definitely bot
|
|
278
|
+
if (originCount >= 2 || originCount / total >= 0.5)
|
|
279
|
+
return 0.1;
|
|
280
|
+
// High ratio of center entries = likely bot
|
|
281
|
+
if (centerCount / total >= 0.5)
|
|
282
|
+
return 0.2;
|
|
283
|
+
// Mix of suspicious entries
|
|
284
|
+
if (suspiciousRatio >= 0.7)
|
|
285
|
+
return 0.3;
|
|
286
|
+
if (suspiciousRatio >= 0.5)
|
|
287
|
+
return 0.5;
|
|
288
|
+
if (suspiciousRatio >= 0.3)
|
|
289
|
+
return 0.7;
|
|
290
|
+
// Mostly edge entries = human
|
|
291
|
+
return 1.0;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Score based on micro-movements (tremor detection)
|
|
295
|
+
* Humans have natural hand tremor causing 1-5px jitter
|
|
296
|
+
* Bots have perfect stillness or no micro-movements
|
|
297
|
+
*/
|
|
298
|
+
scoreMicroMovements() {
|
|
299
|
+
// Need some movement data first
|
|
300
|
+
if (this.distanceSeries.length < 20)
|
|
301
|
+
return undefined;
|
|
302
|
+
const microCount = this.microMovements.length;
|
|
303
|
+
// Calculate expected micro-movements based on tracking duration
|
|
304
|
+
// Humans should have ~5-20 micro-movements per second when cursor is active
|
|
305
|
+
const oldestEvent = this.distanceSeries[0];
|
|
306
|
+
const newestEvent = this.distanceSeries[this.distanceSeries.length - 1];
|
|
307
|
+
const durationMs = newestEvent.timestamp - oldestEvent.timestamp;
|
|
308
|
+
if (durationMs < 1000)
|
|
309
|
+
return undefined; // Need at least 1 second of data
|
|
310
|
+
// Micro-movements per second
|
|
311
|
+
const microPerSecond = (microCount / durationMs) * 1000;
|
|
312
|
+
// No micro-movements at all = very suspicious
|
|
313
|
+
if (microCount === 0)
|
|
314
|
+
return 0.3;
|
|
315
|
+
// Very few micro-movements = somewhat suspicious
|
|
316
|
+
if (microPerSecond < 1)
|
|
317
|
+
return 0.5;
|
|
318
|
+
// Some micro-movements = more human-like
|
|
319
|
+
if (microPerSecond < 5)
|
|
320
|
+
return 0.7;
|
|
321
|
+
// Good amount of micro-movements = human
|
|
322
|
+
if (microPerSecond >= 5 && microPerSecond <= 30)
|
|
323
|
+
return 1.0;
|
|
324
|
+
// Excessive micro-movements (> 30/sec) might be artificial noise
|
|
325
|
+
return 0.8;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Get micro-movement count for external use (e.g., by ClickStrategy)
|
|
329
|
+
*/
|
|
330
|
+
getMicroMovementCount() {
|
|
331
|
+
return this.microMovements.length;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Get last position for external use
|
|
335
|
+
*/
|
|
336
|
+
getLastPosition() {
|
|
337
|
+
return this.lastPosition ? { x: this.lastPosition.x, y: this.lastPosition.y } : null;
|
|
338
|
+
}
|
|
146
339
|
getDebugInfo() {
|
|
147
340
|
return {
|
|
148
341
|
eventCount: this.distanceSeries.length,
|
|
@@ -150,6 +343,9 @@ export class MouseStrategy extends BaseStrategy {
|
|
|
150
343
|
isActive: this.isActive,
|
|
151
344
|
distanceSeries: this.distanceSeries,
|
|
152
345
|
angleSeries: this.angleSeries,
|
|
346
|
+
entryPoints: this.entryPoints,
|
|
347
|
+
microMovementCount: this.microMovements.length,
|
|
348
|
+
lastPosition: this.lastPosition,
|
|
153
349
|
};
|
|
154
350
|
}
|
|
155
351
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timing Analysis Strategy
|
|
3
|
+
* Detects bot-like timing patterns in user interactions
|
|
4
|
+
*
|
|
5
|
+
* Key detection signals:
|
|
6
|
+
* - Pre-action stillness (humans have micro-movements before clicking)
|
|
7
|
+
* - Action timing patterns (machine-precise intervals)
|
|
8
|
+
* - Inactivity patterns (bursts after long silence, no idle variance)
|
|
9
|
+
* - Actions while tab is hidden (bots ignore visibility)
|
|
10
|
+
*/
|
|
11
|
+
import { BaseStrategy } from '../strategy.js';
|
|
12
|
+
export declare class TimingStrategy extends BaseStrategy {
|
|
13
|
+
readonly name = "timing";
|
|
14
|
+
readonly defaultWeight = 0.15;
|
|
15
|
+
private actions;
|
|
16
|
+
private mouseStillness;
|
|
17
|
+
private microMovements;
|
|
18
|
+
private isActive;
|
|
19
|
+
private mouseListener;
|
|
20
|
+
private clickListener;
|
|
21
|
+
private keydownListener;
|
|
22
|
+
private scrollListener;
|
|
23
|
+
/** Time window to consider for pre-action stillness (ms) */
|
|
24
|
+
private readonly STILLNESS_WINDOW;
|
|
25
|
+
/** Minimum distance to count as meaningful movement (px) */
|
|
26
|
+
private readonly MICRO_MOVEMENT_THRESHOLD;
|
|
27
|
+
/** Maximum micro-movement to count (jitter vs intentional) (px) */
|
|
28
|
+
private readonly MAX_MICRO_MOVEMENT;
|
|
29
|
+
/** Machine-precision threshold (intervals within this are suspicious) */
|
|
30
|
+
private readonly MACHINE_PRECISION_THRESHOLD;
|
|
31
|
+
start(): void;
|
|
32
|
+
private recordAction;
|
|
33
|
+
stop(): void;
|
|
34
|
+
reset(): void;
|
|
35
|
+
score(): number | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Score based on pre-action stillness
|
|
38
|
+
* Humans have micro-movements before clicking; bots are perfectly still
|
|
39
|
+
*/
|
|
40
|
+
private scorePreActionStillness;
|
|
41
|
+
/**
|
|
42
|
+
* Score mouse-to-click delay patterns (using pre-filtered cache)
|
|
43
|
+
*/
|
|
44
|
+
private scoreMouseToClickDelayFromCache;
|
|
45
|
+
/**
|
|
46
|
+
* Score action intervals for machine-like precision
|
|
47
|
+
* Detects exact intervals: 100ms, 500ms, 1000ms
|
|
48
|
+
*/
|
|
49
|
+
private scoreActionIntervals;
|
|
50
|
+
/**
|
|
51
|
+
* Score based on actions while document was hidden (using pre-computed count)
|
|
52
|
+
*/
|
|
53
|
+
private scoreHiddenActionsFromCount;
|
|
54
|
+
getDebugInfo(): {
|
|
55
|
+
actionCount: number;
|
|
56
|
+
clickCount: number;
|
|
57
|
+
keydownCount: number;
|
|
58
|
+
scrollCount: number;
|
|
59
|
+
hiddenActionCount: number;
|
|
60
|
+
microMovementCount: number;
|
|
61
|
+
intervals: number[];
|
|
62
|
+
lastStillnessDuration: number | null;
|
|
63
|
+
};
|
|
64
|
+
}
|