@axeptio/behavior-detection 1.0.0

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.
Files changed (76) hide show
  1. package/README.md +828 -0
  2. package/dist/behavior-detection.esm.min.js +2 -0
  3. package/dist/behavior-detection.esm.min.js.map +7 -0
  4. package/dist/behavior-detection.min.js +2 -0
  5. package/dist/behavior-detection.min.js.map +7 -0
  6. package/dist/behavior-detector.d.ts +102 -0
  7. package/dist/browser.d.ts +33 -0
  8. package/dist/cjs/behavior-detector.d.ts +102 -0
  9. package/dist/cjs/behavior-detector.js +315 -0
  10. package/dist/cjs/browser.d.ts +33 -0
  11. package/dist/cjs/browser.js +226 -0
  12. package/dist/cjs/index.d.ts +38 -0
  13. package/dist/cjs/index.js +55 -0
  14. package/dist/cjs/math-utils.d.ts +84 -0
  15. package/dist/cjs/math-utils.js +141 -0
  16. package/dist/cjs/strategies/click.d.ts +39 -0
  17. package/dist/cjs/strategies/click.js +173 -0
  18. package/dist/cjs/strategies/environment.d.ts +52 -0
  19. package/dist/cjs/strategies/environment.js +148 -0
  20. package/dist/cjs/strategies/index.d.ts +18 -0
  21. package/dist/cjs/strategies/index.js +36 -0
  22. package/dist/cjs/strategies/keyboard.d.ts +43 -0
  23. package/dist/cjs/strategies/keyboard.js +233 -0
  24. package/dist/cjs/strategies/mouse.d.ts +39 -0
  25. package/dist/cjs/strategies/mouse.js +159 -0
  26. package/dist/cjs/strategies/resize.d.ts +21 -0
  27. package/dist/cjs/strategies/resize.js +97 -0
  28. package/dist/cjs/strategies/scroll.d.ts +37 -0
  29. package/dist/cjs/strategies/scroll.js +149 -0
  30. package/dist/cjs/strategies/tap.d.ts +38 -0
  31. package/dist/cjs/strategies/tap.js +214 -0
  32. package/dist/cjs/strategy.d.ts +107 -0
  33. package/dist/cjs/strategy.js +33 -0
  34. package/dist/cjs/types.d.ts +168 -0
  35. package/dist/cjs/types.js +26 -0
  36. package/dist/esm/behavior-detector.d.ts +102 -0
  37. package/dist/esm/behavior-detector.js +311 -0
  38. package/dist/esm/browser.d.ts +33 -0
  39. package/dist/esm/browser.js +224 -0
  40. package/dist/esm/index.d.ts +38 -0
  41. package/dist/esm/index.js +36 -0
  42. package/dist/esm/math-utils.d.ts +84 -0
  43. package/dist/esm/math-utils.js +127 -0
  44. package/dist/esm/strategies/click.d.ts +39 -0
  45. package/dist/esm/strategies/click.js +169 -0
  46. package/dist/esm/strategies/environment.d.ts +52 -0
  47. package/dist/esm/strategies/environment.js +144 -0
  48. package/dist/esm/strategies/index.d.ts +18 -0
  49. package/dist/esm/strategies/index.js +19 -0
  50. package/dist/esm/strategies/keyboard.d.ts +43 -0
  51. package/dist/esm/strategies/keyboard.js +229 -0
  52. package/dist/esm/strategies/mouse.d.ts +39 -0
  53. package/dist/esm/strategies/mouse.js +155 -0
  54. package/dist/esm/strategies/resize.d.ts +21 -0
  55. package/dist/esm/strategies/resize.js +93 -0
  56. package/dist/esm/strategies/scroll.d.ts +37 -0
  57. package/dist/esm/strategies/scroll.js +145 -0
  58. package/dist/esm/strategies/tap.d.ts +38 -0
  59. package/dist/esm/strategies/tap.js +210 -0
  60. package/dist/esm/strategy.d.ts +107 -0
  61. package/dist/esm/strategy.js +29 -0
  62. package/dist/esm/types.d.ts +168 -0
  63. package/dist/esm/types.js +23 -0
  64. package/dist/index.d.ts +38 -0
  65. package/dist/math-utils.d.ts +84 -0
  66. package/dist/strategies/click.d.ts +39 -0
  67. package/dist/strategies/environment.d.ts +52 -0
  68. package/dist/strategies/index.d.ts +18 -0
  69. package/dist/strategies/keyboard.d.ts +43 -0
  70. package/dist/strategies/mouse.d.ts +39 -0
  71. package/dist/strategies/resize.d.ts +21 -0
  72. package/dist/strategies/scroll.d.ts +37 -0
  73. package/dist/strategies/tap.d.ts +38 -0
  74. package/dist/strategy.d.ts +107 -0
  75. package/dist/types.d.ts +168 -0
  76. package/package.json +60 -0
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Mouse Movement Detection Strategy
3
+ * Autonomous module that manages its own mouse event listeners and state
4
+ * Tracks distance and angle to detect unnatural jumps and sharp turns
5
+ */
6
+ import { BaseStrategy, type TimeSeriesPoint } from '../strategy';
7
+ export declare class MouseStrategy extends BaseStrategy {
8
+ readonly name = "mouse";
9
+ readonly defaultWeight = 0.3;
10
+ private distanceSeries;
11
+ private angleSeries;
12
+ private lastPosition;
13
+ private lastAngle;
14
+ private cumulativeAngle;
15
+ private rollingWindowMs;
16
+ private listener;
17
+ private leaveListener;
18
+ private isActive;
19
+ private screenDiagonal;
20
+ constructor(options?: {
21
+ rollingWindow?: number;
22
+ });
23
+ start(): void;
24
+ stop(): void;
25
+ reset(): void;
26
+ score(): number | undefined;
27
+ /**
28
+ * Mouse-specific pattern detection
29
+ * Detects bot-like patterns: constant velocity, linear paths
30
+ */
31
+ private detectMousePatterns;
32
+ getDebugInfo(): {
33
+ eventCount: number;
34
+ rollingWindow: number;
35
+ isActive: boolean;
36
+ distanceSeries: TimeSeriesPoint[];
37
+ angleSeries: TimeSeriesPoint[];
38
+ };
39
+ }
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Mouse Movement Detection Strategy
3
+ * Autonomous module that manages its own mouse event listeners and state
4
+ * Tracks distance and angle to detect unnatural jumps and sharp turns
5
+ */
6
+ import { BaseStrategy } from '../strategy';
7
+ import { calculateStatistics, gaussian } from '../math-utils';
8
+ export class MouseStrategy extends BaseStrategy {
9
+ constructor(options) {
10
+ super();
11
+ this.name = 'mouse';
12
+ this.defaultWeight = 0.30;
13
+ this.distanceSeries = [];
14
+ this.angleSeries = [];
15
+ this.lastPosition = null;
16
+ this.lastAngle = 0;
17
+ this.cumulativeAngle = 0;
18
+ this.rollingWindowMs = 5000;
19
+ this.listener = null;
20
+ this.leaveListener = null;
21
+ this.isActive = false;
22
+ this.screenDiagonal = 1;
23
+ if ((options === null || options === void 0 ? void 0 : options.rollingWindow) !== undefined)
24
+ this.rollingWindowMs = options.rollingWindow;
25
+ }
26
+ start() {
27
+ if (this.isActive)
28
+ return;
29
+ this.isActive = true;
30
+ // Calculate screen diagonal for normalization (distance relative to screen size)
31
+ const width = window.innerWidth;
32
+ const height = window.innerHeight;
33
+ this.screenDiagonal = Math.sqrt(width * width + height * height);
34
+ this.listener = (e) => {
35
+ const mouseEvent = e;
36
+ const now = Date.now();
37
+ const currentPos = { x: mouseEvent.clientX, y: mouseEvent.clientY };
38
+ // Calculate distance and angle from previous position
39
+ if (this.lastPosition) {
40
+ const dx = currentPos.x - this.lastPosition.x;
41
+ const dy = currentPos.y - this.lastPosition.y;
42
+ const pixelDistance = Math.sqrt(dx * dx + dy * dy);
43
+ // Normalize distance to screen diagonal (0-1 range)
44
+ // A full diagonal movement = 1.0, a 10px movement on 2000px screen = 0.005
45
+ const normalizedDistance = pixelDistance / this.screenDiagonal;
46
+ // Only record if movement is meaningful (> 0.001 = ~2px on 2000px screen)
47
+ if (normalizedDistance > 0.001) {
48
+ const rawAngle = Math.atan2(dy, dx); // -PI to PI
49
+ // Unwrap angle to avoid discontinuities (e.g., circles)
50
+ let angleDiff = rawAngle - this.lastAngle;
51
+ // Normalize difference to -PI to PI
52
+ while (angleDiff > Math.PI)
53
+ angleDiff -= 2 * Math.PI;
54
+ while (angleDiff < -Math.PI)
55
+ angleDiff += 2 * Math.PI;
56
+ this.cumulativeAngle += angleDiff;
57
+ this.lastAngle = rawAngle;
58
+ // Store normalized distance (not raw pixels)
59
+ this.distanceSeries.push({ value: normalizedDistance, timestamp: now });
60
+ this.angleSeries.push({ value: this.cumulativeAngle, timestamp: now });
61
+ // Notify detector for confidence tracking
62
+ this.notifyEvent(Math.min(1, normalizedDistance * 100));
63
+ }
64
+ // Apply rolling window efficiently: remove old events from start
65
+ // Since events are chronological, we only check from the beginning
66
+ const cutoff = now - this.rollingWindowMs;
67
+ while (this.distanceSeries.length > 0 && this.distanceSeries[0].timestamp < cutoff) {
68
+ this.distanceSeries.shift();
69
+ this.angleSeries.shift(); // Keep both arrays in sync
70
+ }
71
+ }
72
+ this.lastPosition = currentPos;
73
+ };
74
+ document.addEventListener('mousemove', this.listener, { passive: true });
75
+ // Clear data when mouse leaves the window (discontinuous tracking)
76
+ this.leaveListener = () => {
77
+ this.distanceSeries = [];
78
+ this.angleSeries = [];
79
+ this.lastPosition = null;
80
+ this.lastAngle = 0;
81
+ this.cumulativeAngle = 0;
82
+ };
83
+ document.addEventListener('mouseleave', this.leaveListener, { passive: true });
84
+ }
85
+ stop() {
86
+ if (!this.isActive)
87
+ return;
88
+ this.isActive = false;
89
+ if (this.listener) {
90
+ document.removeEventListener('mousemove', this.listener);
91
+ this.listener = null;
92
+ }
93
+ if (this.leaveListener) {
94
+ document.removeEventListener('mouseleave', this.leaveListener);
95
+ this.leaveListener = null;
96
+ }
97
+ }
98
+ reset() {
99
+ this.distanceSeries = [];
100
+ this.angleSeries = [];
101
+ this.lastPosition = null;
102
+ this.lastAngle = 0;
103
+ this.cumulativeAngle = 0;
104
+ }
105
+ score() {
106
+ if (this.distanceSeries.length < 10)
107
+ return undefined;
108
+ // Mouse-specific pattern detection (optimized for normalized continuous data)
109
+ // Generic smoothness detector is calibrated for discrete events, not continuous movement
110
+ return this.detectMousePatterns();
111
+ }
112
+ /**
113
+ * Mouse-specific pattern detection
114
+ * Detects bot-like patterns: constant velocity, linear paths
115
+ */
116
+ detectMousePatterns() {
117
+ if (this.distanceSeries.length < 10)
118
+ return undefined;
119
+ let score = 0;
120
+ let factors = 0;
121
+ // 1. VELOCITY CONSISTENCY - Bots often move at constant speed
122
+ const distances = this.distanceSeries.map(p => p.value);
123
+ if (distances.length >= 3) {
124
+ const stats = calculateStatistics(distances);
125
+ // Real human movement has high variation (CV ~0.8-1.2)
126
+ // page.mouse.move() with steps has lower CV (~0.4-0.6)
127
+ // Narrower gaussian to be strict
128
+ score += gaussian(stats.cv, 0.9, 0.35);
129
+ factors++;
130
+ }
131
+ // 2. DIRECTION CHANGES - Bots often have too few or too many sharp turns
132
+ const angles = this.angleSeries.map(p => p.value);
133
+ if (angles.length >= 3) {
134
+ const angleChanges = [];
135
+ for (let i = 1; i < angles.length; i++) {
136
+ angleChanges.push(Math.abs(angles[i] - angles[i - 1]));
137
+ }
138
+ const avgChange = angleChanges.reduce((a, b) => a + b, 0) / angleChanges.length;
139
+ // Real humans have moderate but varied direction changes
140
+ // page.mouse.move() linear interpolation has very small, consistent changes
141
+ score += gaussian(avgChange, 0.15, 0.12);
142
+ factors++;
143
+ }
144
+ return factors > 0 ? score / factors : undefined;
145
+ }
146
+ getDebugInfo() {
147
+ return {
148
+ eventCount: this.distanceSeries.length,
149
+ rollingWindow: this.rollingWindowMs,
150
+ isActive: this.isActive,
151
+ distanceSeries: this.distanceSeries,
152
+ angleSeries: this.angleSeries,
153
+ };
154
+ }
155
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Resize Behavior Detection Strategy
3
+ */
4
+ import { BaseStrategy } from '../strategy';
5
+ export declare class ResizeStrategy extends BaseStrategy {
6
+ readonly name = "resize";
7
+ readonly defaultWeight = 0.02;
8
+ private events;
9
+ private listener;
10
+ private isActive;
11
+ private lastMousePosition;
12
+ private mouseListener;
13
+ start(): void;
14
+ stop(): void;
15
+ reset(): void;
16
+ score(): number | undefined;
17
+ getDebugInfo(): {
18
+ eventCount: number;
19
+ withMouseData: number;
20
+ };
21
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Resize Behavior Detection Strategy
3
+ */
4
+ import { BaseStrategy } from '../strategy';
5
+ import { inverseSigmoid, sigmoid } from '../math-utils';
6
+ export class ResizeStrategy extends BaseStrategy {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.name = 'resize';
10
+ this.defaultWeight = 0.02;
11
+ this.events = [];
12
+ this.listener = null;
13
+ this.isActive = false;
14
+ this.lastMousePosition = null;
15
+ this.mouseListener = null;
16
+ }
17
+ start() {
18
+ if (this.isActive)
19
+ return;
20
+ this.isActive = true;
21
+ // Track mouse for resize detection
22
+ this.mouseListener = (e) => {
23
+ const mouseEvent = e;
24
+ this.lastMousePosition = {
25
+ x: mouseEvent.clientX,
26
+ y: mouseEvent.clientY,
27
+ };
28
+ };
29
+ document.addEventListener('mousemove', this.mouseListener, { passive: true });
30
+ // Track resizes
31
+ this.listener = () => {
32
+ var _a, _b;
33
+ const mouseX = (_a = this.lastMousePosition) === null || _a === void 0 ? void 0 : _a.x;
34
+ const mouseY = (_b = this.lastMousePosition) === null || _b === void 0 ? void 0 : _b.y;
35
+ let mouseNearEdge = false;
36
+ if (mouseX !== undefined && mouseY !== undefined) {
37
+ const edgeThreshold = 50;
38
+ mouseNearEdge = (mouseX < edgeThreshold ||
39
+ mouseX > window.innerWidth - edgeThreshold ||
40
+ mouseY < edgeThreshold ||
41
+ mouseY > window.innerHeight - edgeThreshold);
42
+ }
43
+ this.events.push({
44
+ width: window.innerWidth,
45
+ height: window.innerHeight,
46
+ mouseX,
47
+ mouseY,
48
+ mouseNearEdge,
49
+ timestamp: Date.now(),
50
+ });
51
+ };
52
+ window.addEventListener('resize', this.listener);
53
+ }
54
+ stop() {
55
+ if (!this.isActive)
56
+ return;
57
+ this.isActive = false;
58
+ if (this.listener) {
59
+ window.removeEventListener('resize', this.listener);
60
+ this.listener = null;
61
+ }
62
+ if (this.mouseListener) {
63
+ document.removeEventListener('mousemove', this.mouseListener);
64
+ this.mouseListener = null;
65
+ }
66
+ }
67
+ reset() {
68
+ this.events = [];
69
+ }
70
+ score() {
71
+ if (this.events.length === 0)
72
+ return undefined;
73
+ let score = 0;
74
+ let factors = 0;
75
+ // Frequency
76
+ score += inverseSigmoid(this.events.length, 5, 0.5);
77
+ factors++;
78
+ // Mouse near edge
79
+ const withMouse = this.events.filter(e => e.mouseX !== undefined);
80
+ if (withMouse.length > 0) {
81
+ const nearEdge = withMouse.filter(e => e.mouseNearEdge).length;
82
+ score += sigmoid(nearEdge / withMouse.length, 0.5, 8);
83
+ factors++;
84
+ }
85
+ return factors > 0 ? score / factors : undefined;
86
+ }
87
+ getDebugInfo() {
88
+ return {
89
+ eventCount: this.events.length,
90
+ withMouseData: this.events.filter(e => e.mouseX !== undefined).length,
91
+ };
92
+ }
93
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Scroll Behavior Detection Strategy
3
+ * Autonomous module managing scroll event listeners
4
+ * Tracks normalized scroll distance and velocity patterns
5
+ */
6
+ import { BaseStrategy, type TimeSeriesPoint } from '../strategy';
7
+ export declare class ScrollStrategy extends BaseStrategy {
8
+ readonly name = "scroll";
9
+ readonly defaultWeight = 0.15;
10
+ private distanceSeries;
11
+ private velocitySeries;
12
+ private lastScrollY;
13
+ private lastTimestamp;
14
+ private rollingWindowMs;
15
+ private documentHeight;
16
+ private listener;
17
+ private isActive;
18
+ constructor(options?: {
19
+ rollingWindow?: number;
20
+ });
21
+ start(): void;
22
+ stop(): void;
23
+ reset(): void;
24
+ score(): number | undefined;
25
+ /**
26
+ * Scroll-specific pattern detection
27
+ * Detects bot-like patterns: constant deltas, instant jumps, too smooth
28
+ */
29
+ private detectScrollPatterns;
30
+ getDebugInfo(): {
31
+ eventCount: number;
32
+ rollingWindow: number;
33
+ isActive: boolean;
34
+ distanceSeries: TimeSeriesPoint[];
35
+ velocitySeries: TimeSeriesPoint[];
36
+ };
37
+ }
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Scroll Behavior Detection Strategy
3
+ * Autonomous module managing scroll event listeners
4
+ * Tracks normalized scroll distance and velocity patterns
5
+ */
6
+ import { BaseStrategy } from '../strategy';
7
+ import { calculateStatistics, gaussian, inverseSigmoid } from '../math-utils';
8
+ export class ScrollStrategy extends BaseStrategy {
9
+ constructor(options) {
10
+ super();
11
+ this.name = 'scroll';
12
+ this.defaultWeight = 0.15;
13
+ this.distanceSeries = [];
14
+ this.velocitySeries = [];
15
+ this.lastScrollY = null;
16
+ this.lastTimestamp = 0;
17
+ this.rollingWindowMs = 5000;
18
+ this.documentHeight = 1;
19
+ this.listener = null;
20
+ this.isActive = false;
21
+ if ((options === null || options === void 0 ? void 0 : options.rollingWindow) !== undefined)
22
+ this.rollingWindowMs = options.rollingWindow;
23
+ }
24
+ start() {
25
+ if (this.isActive)
26
+ return;
27
+ this.isActive = true;
28
+ // Calculate document height for normalization
29
+ this.documentHeight = Math.max(document.body.scrollHeight, document.documentElement.scrollHeight, 1);
30
+ this.listener = (_e) => {
31
+ const scrollY = window.scrollY;
32
+ const now = Date.now();
33
+ // Always update last position on first event
34
+ if (this.lastScrollY === null) {
35
+ this.lastScrollY = scrollY;
36
+ this.lastTimestamp = now;
37
+ return;
38
+ }
39
+ const pixelDelta = scrollY - this.lastScrollY;
40
+ const deltaTime = now - this.lastTimestamp;
41
+ // Skip if no actual scroll happened
42
+ if (pixelDelta === 0) {
43
+ return;
44
+ }
45
+ // Normalize scroll distance to document height (0-1 range)
46
+ const normalizedDistance = Math.abs(pixelDelta) / this.documentHeight;
47
+ // Record all scroll movements (no threshold - let pattern detection decide)
48
+ if (deltaTime > 0) {
49
+ const velocity = normalizedDistance / deltaTime; // normalized units per ms
50
+ // Store as time series
51
+ this.distanceSeries.push({ value: normalizedDistance, timestamp: now });
52
+ this.velocitySeries.push({ value: velocity, timestamp: now });
53
+ // Notify detector for confidence tracking
54
+ this.notifyEvent(Math.min(1, normalizedDistance * 10));
55
+ // Apply rolling window efficiently
56
+ const cutoff = now - this.rollingWindowMs;
57
+ while (this.distanceSeries.length > 0 && this.distanceSeries[0].timestamp < cutoff) {
58
+ this.distanceSeries.shift();
59
+ this.velocitySeries.shift();
60
+ }
61
+ }
62
+ this.lastScrollY = scrollY;
63
+ this.lastTimestamp = now;
64
+ };
65
+ // Listen on window for scroll events (document scrolling)
66
+ window.addEventListener('scroll', this.listener, { passive: true });
67
+ }
68
+ stop() {
69
+ if (!this.isActive)
70
+ return;
71
+ this.isActive = false;
72
+ if (this.listener) {
73
+ window.removeEventListener('scroll', this.listener);
74
+ this.listener = null;
75
+ }
76
+ }
77
+ reset() {
78
+ this.distanceSeries = [];
79
+ this.velocitySeries = [];
80
+ this.lastScrollY = null;
81
+ this.lastTimestamp = 0;
82
+ }
83
+ score() {
84
+ if (this.distanceSeries.length < 2)
85
+ return undefined;
86
+ // Scroll-specific pattern detection
87
+ return this.detectScrollPatterns();
88
+ }
89
+ /**
90
+ * Scroll-specific pattern detection
91
+ * Detects bot-like patterns: constant deltas, instant jumps, too smooth
92
+ */
93
+ detectScrollPatterns() {
94
+ if (this.distanceSeries.length < 2)
95
+ return undefined;
96
+ let score = 0;
97
+ let factors = 0;
98
+ // 1. IDENTICAL DELTAS - Smoking gun for bots
99
+ const distances = this.distanceSeries.map(p => p.value);
100
+ if (distances.length >= 2) {
101
+ // Check if all distances are identical (tolerance for floating point)
102
+ const uniqueDistances = new Set(distances.map(d => Math.round(d * 1000))).size;
103
+ if (uniqueDistances === 1) {
104
+ // All scroll amounts identical = definite bot
105
+ return 0.05;
106
+ }
107
+ }
108
+ // 2. DISTANCE CONSISTENCY - Bots often scroll same amount repeatedly
109
+ if (distances.length >= 2) {
110
+ const stats = calculateStatistics(distances);
111
+ // Real humans have high CV (>0.8) due to natural scroll acceleration/deceleration
112
+ // Simple automation has lower CV even with varied amounts
113
+ // Gaussian centered high with narrow width - be strict
114
+ score += gaussian(stats.cv, 1.0, 0.4);
115
+ factors++;
116
+ }
117
+ // 3. VELOCITY VARIATION - Humans have highly variable scroll speeds
118
+ const velocities = this.velocitySeries.map(p => p.value);
119
+ if (velocities.length >= 2) {
120
+ const stats = calculateStatistics(velocities);
121
+ // Human velocity is very chaotic (acceleration/deceleration)
122
+ // Automation has more consistent velocity even with delays
123
+ score += gaussian(stats.cv, 1.2, 0.5);
124
+ factors++;
125
+ }
126
+ // 4. INSTANT JUMPS - Detect programmatic scrollTo
127
+ const instantJumps = distances.filter(d => d > 0.1).length; // >10% of document in one event
128
+ if (distances.length > 0) {
129
+ const jumpRatio = instantJumps / distances.length;
130
+ // Penalize high jump ratio (programmatic scrollTo)
131
+ score += inverseSigmoid(jumpRatio, 0.3, 15);
132
+ factors++;
133
+ }
134
+ return factors > 0 ? score / factors : undefined;
135
+ }
136
+ getDebugInfo() {
137
+ return {
138
+ eventCount: this.distanceSeries.length,
139
+ rollingWindow: this.rollingWindowMs,
140
+ isActive: this.isActive,
141
+ distanceSeries: this.distanceSeries,
142
+ velocitySeries: this.velocitySeries,
143
+ };
144
+ }
145
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Tap Behavior Detection Strategy (Mobile)
3
+ * Monitors touch interactions on specific elements
4
+ * Analyzes tap duration, precision, movement, and timing patterns
5
+ */
6
+ import { BaseStrategy } from '../strategy';
7
+ export declare class TapStrategy extends BaseStrategy {
8
+ readonly name = "tap";
9
+ readonly defaultWeight = 0.35;
10
+ private events;
11
+ private targetSelectors;
12
+ private touchStartListeners;
13
+ private touchEndListeners;
14
+ private activeTouches;
15
+ private isActive;
16
+ constructor(options?: {
17
+ targetSelectors?: string[];
18
+ });
19
+ start(): void;
20
+ addTarget(selector: string): void;
21
+ private attachTouchListeners;
22
+ private attachTouchListenersForSelector;
23
+ stop(): void;
24
+ reset(): void;
25
+ score(): number | undefined;
26
+ getDebugInfo(): {
27
+ eventCount: number;
28
+ positions: {
29
+ outside: number;
30
+ deadCenter: number;
31
+ overElement: number;
32
+ };
33
+ durations: number[];
34
+ movements: number[];
35
+ inViewport: number;
36
+ trackedElements: number;
37
+ };
38
+ }