@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.
@@ -35,7 +35,11 @@ __export(index_exports, {
35
35
  Scroll: () => ScrollStrategy,
36
36
  ScrollStrategy: () => ScrollStrategy,
37
37
  Tap: () => TapStrategy,
38
- TapStrategy: () => TapStrategy
38
+ TapStrategy: () => TapStrategy,
39
+ Timing: () => TimingStrategy,
40
+ TimingStrategy: () => TimingStrategy,
41
+ Visibility: () => VisibilityStrategy,
42
+ VisibilityStrategy: () => VisibilityStrategy
39
43
  });
40
44
  module.exports = __toCommonJS(index_exports);
41
45
 
@@ -397,8 +401,12 @@ var MouseStrategy = class extends BaseStrategy {
397
401
  this.rollingWindowMs = 5e3;
398
402
  this.listener = null;
399
403
  this.leaveListener = null;
404
+ this.enterListener = null;
400
405
  this.isActive = false;
401
406
  this.screenDiagonal = 1;
407
+ this.entryPoints = [];
408
+ this.microMovements = [];
409
+ this.STILLNESS_WINDOW = 500;
402
410
  if ((options === null || options === void 0 ? void 0 : options.rollingWindow) !== void 0)
403
411
  this.rollingWindowMs = options.rollingWindow;
404
412
  }
@@ -412,11 +420,18 @@ var MouseStrategy = class extends BaseStrategy {
412
420
  this.listener = (e) => {
413
421
  const mouseEvent = e;
414
422
  const now = Date.now();
415
- const currentPos = { x: mouseEvent.clientX, y: mouseEvent.clientY };
423
+ const currentPos = { x: mouseEvent.clientX, y: mouseEvent.clientY, timestamp: now };
416
424
  if (this.lastPosition) {
417
425
  const dx = currentPos.x - this.lastPosition.x;
418
426
  const dy = currentPos.y - this.lastPosition.y;
419
427
  const pixelDistance = Math.sqrt(dx * dx + dy * dy);
428
+ if (pixelDistance >= 1 && pixelDistance <= 5) {
429
+ this.microMovements.push({ dx, dy, timestamp: now });
430
+ const cutoffMicro = now - this.STILLNESS_WINDOW;
431
+ while (this.microMovements.length > 0 && this.microMovements[0].timestamp < cutoffMicro) {
432
+ this.microMovements.shift();
433
+ }
434
+ }
420
435
  const normalizedDistance = pixelDistance / this.screenDiagonal;
421
436
  if (normalizedDistance > 1e-3) {
422
437
  const rawAngle = Math.atan2(dy, dx);
@@ -440,12 +455,62 @@ var MouseStrategy = class extends BaseStrategy {
440
455
  this.lastPosition = currentPos;
441
456
  };
442
457
  document.addEventListener("mousemove", this.listener, { passive: true });
458
+ this.enterListener = (e) => {
459
+ const mouseEvent = e;
460
+ const now = Date.now();
461
+ const x = mouseEvent.clientX;
462
+ const y = mouseEvent.clientY;
463
+ const width2 = window.innerWidth;
464
+ const height2 = window.innerHeight;
465
+ const distTop = y;
466
+ const distBottom = height2 - y;
467
+ const distLeft = x;
468
+ const distRight = width2 - x;
469
+ const minEdgeDist = Math.min(distTop, distBottom, distLeft, distRight);
470
+ let entryEdge;
471
+ const edgeThreshold = 50;
472
+ if (minEdgeDist < edgeThreshold) {
473
+ if (distTop <= minEdgeDist)
474
+ entryEdge = "top";
475
+ else if (distBottom <= minEdgeDist)
476
+ entryEdge = "bottom";
477
+ else if (distLeft <= minEdgeDist)
478
+ entryEdge = "left";
479
+ else
480
+ entryEdge = "right";
481
+ } else if (x > width2 * 0.35 && x < width2 * 0.65 && y > height2 * 0.35 && y < height2 * 0.65) {
482
+ entryEdge = "center";
483
+ } else if (distTop < edgeThreshold * 2 && distLeft < edgeThreshold * 2 || distTop < edgeThreshold * 2 && distRight < edgeThreshold * 2 || distBottom < edgeThreshold * 2 && distLeft < edgeThreshold * 2 || distBottom < edgeThreshold * 2 && distRight < edgeThreshold * 2) {
484
+ entryEdge = "corner";
485
+ } else {
486
+ if (distTop < distBottom && distTop < distLeft && distTop < distRight)
487
+ entryEdge = "top";
488
+ else if (distBottom < distLeft && distBottom < distRight)
489
+ entryEdge = "bottom";
490
+ else if (distLeft < distRight)
491
+ entryEdge = "left";
492
+ else
493
+ entryEdge = "right";
494
+ }
495
+ this.entryPoints.push({
496
+ x,
497
+ y,
498
+ timestamp: now,
499
+ edgeDistance: minEdgeDist,
500
+ entryEdge
501
+ });
502
+ if (this.entryPoints.length > 20) {
503
+ this.entryPoints.shift();
504
+ }
505
+ };
506
+ document.addEventListener("mouseenter", this.enterListener, { passive: true });
443
507
  this.leaveListener = () => {
444
508
  this.distanceSeries = [];
445
509
  this.angleSeries = [];
446
510
  this.lastPosition = null;
447
511
  this.lastAngle = 0;
448
512
  this.cumulativeAngle = 0;
513
+ this.microMovements = [];
449
514
  };
450
515
  document.addEventListener("mouseleave", this.leaveListener, { passive: true });
451
516
  }
@@ -461,6 +526,10 @@ var MouseStrategy = class extends BaseStrategy {
461
526
  document.removeEventListener("mouseleave", this.leaveListener);
462
527
  this.leaveListener = null;
463
528
  }
529
+ if (this.enterListener) {
530
+ document.removeEventListener("mouseenter", this.enterListener);
531
+ this.enterListener = null;
532
+ }
464
533
  }
465
534
  reset() {
466
535
  this.distanceSeries = [];
@@ -468,6 +537,8 @@ var MouseStrategy = class extends BaseStrategy {
468
537
  this.lastPosition = null;
469
538
  this.lastAngle = 0;
470
539
  this.cumulativeAngle = 0;
540
+ this.entryPoints = [];
541
+ this.microMovements = [];
471
542
  }
472
543
  score() {
473
544
  if (this.distanceSeries.length < 10)
@@ -476,7 +547,7 @@ var MouseStrategy = class extends BaseStrategy {
476
547
  }
477
548
  /**
478
549
  * Mouse-specific pattern detection
479
- * Detects bot-like patterns: constant velocity, linear paths
550
+ * Detects bot-like patterns: constant velocity, linear paths, suspicious entry points
480
551
  */
481
552
  detectMousePatterns() {
482
553
  if (this.distanceSeries.length < 10)
@@ -499,15 +570,103 @@ var MouseStrategy = class extends BaseStrategy {
499
570
  score += gaussian(avgChange, 0.15, 0.12);
500
571
  factors++;
501
572
  }
573
+ const entryScore = this.scoreEntryPoints();
574
+ if (entryScore !== void 0) {
575
+ score += entryScore;
576
+ factors++;
577
+ }
578
+ const microScore = this.scoreMicroMovements();
579
+ if (microScore !== void 0) {
580
+ score += microScore;
581
+ factors++;
582
+ }
502
583
  return factors > 0 ? score / factors : void 0;
503
584
  }
585
+ /**
586
+ * Score based on viewport entry points
587
+ * Humans enter from edges with momentum; bots often start at (0,0) or center
588
+ */
589
+ scoreEntryPoints() {
590
+ if (this.entryPoints.length < 2)
591
+ return void 0;
592
+ let suspiciousCount = 0;
593
+ let centerCount = 0;
594
+ let cornerCount = 0;
595
+ let originCount = 0;
596
+ for (const entry of this.entryPoints) {
597
+ if (entry.x < 5 && entry.y < 5) {
598
+ originCount++;
599
+ suspiciousCount++;
600
+ } else if (entry.entryEdge === "center") {
601
+ centerCount++;
602
+ suspiciousCount++;
603
+ } else if (entry.entryEdge === "corner") {
604
+ cornerCount++;
605
+ if (entry.edgeDistance < 10)
606
+ suspiciousCount++;
607
+ }
608
+ }
609
+ const total = this.entryPoints.length;
610
+ const suspiciousRatio = suspiciousCount / total;
611
+ if (originCount >= 2 || originCount / total >= 0.5)
612
+ return 0.1;
613
+ if (centerCount / total >= 0.5)
614
+ return 0.2;
615
+ if (suspiciousRatio >= 0.7)
616
+ return 0.3;
617
+ if (suspiciousRatio >= 0.5)
618
+ return 0.5;
619
+ if (suspiciousRatio >= 0.3)
620
+ return 0.7;
621
+ return 1;
622
+ }
623
+ /**
624
+ * Score based on micro-movements (tremor detection)
625
+ * Humans have natural hand tremor causing 1-5px jitter
626
+ * Bots have perfect stillness or no micro-movements
627
+ */
628
+ scoreMicroMovements() {
629
+ if (this.distanceSeries.length < 20)
630
+ return void 0;
631
+ const microCount = this.microMovements.length;
632
+ const oldestEvent = this.distanceSeries[0];
633
+ const newestEvent = this.distanceSeries[this.distanceSeries.length - 1];
634
+ const durationMs = newestEvent.timestamp - oldestEvent.timestamp;
635
+ if (durationMs < 1e3)
636
+ return void 0;
637
+ const microPerSecond = microCount / durationMs * 1e3;
638
+ if (microCount === 0)
639
+ return 0.3;
640
+ if (microPerSecond < 1)
641
+ return 0.5;
642
+ if (microPerSecond < 5)
643
+ return 0.7;
644
+ if (microPerSecond >= 5 && microPerSecond <= 30)
645
+ return 1;
646
+ return 0.8;
647
+ }
648
+ /**
649
+ * Get micro-movement count for external use (e.g., by ClickStrategy)
650
+ */
651
+ getMicroMovementCount() {
652
+ return this.microMovements.length;
653
+ }
654
+ /**
655
+ * Get last position for external use
656
+ */
657
+ getLastPosition() {
658
+ return this.lastPosition ? { x: this.lastPosition.x, y: this.lastPosition.y } : null;
659
+ }
504
660
  getDebugInfo() {
505
661
  return {
506
662
  eventCount: this.distanceSeries.length,
507
663
  rollingWindow: this.rollingWindowMs,
508
664
  isActive: this.isActive,
509
665
  distanceSeries: this.distanceSeries,
510
- angleSeries: this.angleSeries
666
+ angleSeries: this.angleSeries,
667
+ entryPoints: this.entryPoints,
668
+ microMovementCount: this.microMovements.length,
669
+ lastPosition: this.lastPosition
511
670
  };
512
671
  }
513
672
  };
@@ -654,7 +813,8 @@ var ClickStrategy = class extends BaseStrategy {
654
813
  const mouseEvent = e;
655
814
  this.lastMousePosition = {
656
815
  x: mouseEvent.clientX,
657
- y: mouseEvent.clientY
816
+ y: mouseEvent.clientY,
817
+ timestamp: Date.now()
658
818
  };
659
819
  };
660
820
  document.addEventListener("mousemove", this.mouseListener, { passive: true });
@@ -684,8 +844,17 @@ var ClickStrategy = class extends BaseStrategy {
684
844
  const listener = (e) => {
685
845
  var _a, _b;
686
846
  const clickEvent = e;
847
+ const now = Date.now();
687
848
  const rect = element.getBoundingClientRect();
688
849
  const inViewport = rect.top >= 0 && rect.left >= 0 && rect.bottom <= window.innerHeight && rect.right <= window.innerWidth;
850
+ let mouseClickDelta = 0;
851
+ let timeSinceMouseMove = -1;
852
+ if (this.lastMousePosition) {
853
+ const dx = clickEvent.clientX - this.lastMousePosition.x;
854
+ const dy = clickEvent.clientY - this.lastMousePosition.y;
855
+ mouseClickDelta = Math.sqrt(dx * dx + dy * dy);
856
+ timeSinceMouseMove = now - this.lastMousePosition.timestamp;
857
+ }
689
858
  let position;
690
859
  if (!this.lastMousePosition) {
691
860
  position = "no-mouse-data";
@@ -714,7 +883,10 @@ var ClickStrategy = class extends BaseStrategy {
714
883
  rect,
715
884
  inViewport,
716
885
  position,
717
- timestamp: Date.now()
886
+ timestamp: now,
887
+ mouseClickDelta,
888
+ timeSinceMouseMove,
889
+ isTrusted: clickEvent.isTrusted
718
890
  });
719
891
  this.notifyEvent(1);
720
892
  };
@@ -740,26 +912,93 @@ var ClickStrategy = class extends BaseStrategy {
740
912
  this.lastMousePosition = null;
741
913
  }
742
914
  score() {
743
- if (this.events.length === 0)
915
+ const eventCount = this.events.length;
916
+ if (eventCount === 0)
744
917
  return void 0;
745
- let totalScore = 0;
918
+ let positionScore = 0;
919
+ let clicksWithDelta = 0;
920
+ let mismatchCount = 0;
921
+ let clicksWithTiming = 0;
922
+ let suspiciousTimingCount = 0;
923
+ let untrustedCount = 0;
746
924
  for (const click of this.events) {
747
925
  switch (click.position) {
748
926
  case "no-mouse-data":
749
- totalScore += 0;
927
+ positionScore += 0;
750
928
  break;
751
929
  case "outside":
752
- totalScore += 0;
930
+ positionScore += 0;
753
931
  break;
754
932
  case "dead-center":
755
- totalScore += 0.5;
933
+ positionScore += 0.5;
756
934
  break;
757
935
  case "over-element":
758
- totalScore += 1;
936
+ positionScore += 1;
759
937
  break;
760
938
  }
939
+ if (click.mouseClickDelta >= 0) {
940
+ clicksWithDelta++;
941
+ if (click.mouseClickDelta > 5)
942
+ mismatchCount++;
943
+ }
944
+ if (click.timeSinceMouseMove >= 0) {
945
+ clicksWithTiming++;
946
+ if (click.timeSinceMouseMove < 10 || click.timeSinceMouseMove > 2e3) {
947
+ suspiciousTimingCount++;
948
+ }
949
+ }
950
+ if (!click.isTrusted)
951
+ untrustedCount++;
952
+ }
953
+ let score = 0;
954
+ let factors = 0;
955
+ score += positionScore / eventCount;
956
+ factors++;
957
+ if (clicksWithDelta >= 2) {
958
+ const mismatchRatio = mismatchCount / clicksWithDelta;
959
+ let deltaScore;
960
+ if (mismatchRatio >= 0.8)
961
+ deltaScore = 0.1;
962
+ else if (mismatchRatio >= 0.5)
963
+ deltaScore = 0.3;
964
+ else if (mismatchRatio >= 0.3)
965
+ deltaScore = 0.5;
966
+ else if (mismatchRatio > 0)
967
+ deltaScore = 0.7;
968
+ else
969
+ deltaScore = 1;
970
+ score += deltaScore;
971
+ factors++;
761
972
  }
762
- return totalScore / this.events.length;
973
+ if (clicksWithTiming >= 2) {
974
+ const suspiciousRatio = suspiciousTimingCount / clicksWithTiming;
975
+ let timingScore;
976
+ if (suspiciousRatio >= 0.8)
977
+ timingScore = 0.2;
978
+ else if (suspiciousRatio >= 0.5)
979
+ timingScore = 0.4;
980
+ else if (suspiciousRatio >= 0.3)
981
+ timingScore = 0.6;
982
+ else if (suspiciousRatio > 0)
983
+ timingScore = 0.8;
984
+ else
985
+ timingScore = 1;
986
+ score += timingScore;
987
+ factors++;
988
+ }
989
+ if (eventCount >= 2) {
990
+ const untrustedRatio = untrustedCount / eventCount;
991
+ let trustedScore;
992
+ if (untrustedRatio >= 0.5)
993
+ trustedScore = 0.1;
994
+ else if (untrustedRatio > 0)
995
+ trustedScore = 0.3;
996
+ else
997
+ trustedScore = 1;
998
+ score += trustedScore;
999
+ factors++;
1000
+ }
1001
+ return factors > 0 ? score / factors : void 0;
763
1002
  }
764
1003
  getDebugInfo() {
765
1004
  return {
@@ -771,7 +1010,10 @@ var ClickStrategy = class extends BaseStrategy {
771
1010
  overElement: this.events.filter((e) => e.position === "over-element").length
772
1011
  },
773
1012
  inViewport: this.events.filter((e) => e.inViewport).length,
774
- trackedElements: this.clickListeners.size
1013
+ trackedElements: this.clickListeners.size,
1014
+ mouseClickDeltas: this.events.map((e) => e.mouseClickDelta),
1015
+ timeSinceMouseMoves: this.events.map((e) => e.timeSinceMouseMove),
1016
+ untrustedClicks: this.events.filter((e) => !e.isTrusted).length
775
1017
  };
776
1018
  }
777
1019
  };
@@ -1168,6 +1410,54 @@ var KeyboardStrategy = class extends BaseStrategy {
1168
1410
  };
1169
1411
 
1170
1412
  // dist/esm/strategies/environment.js
1413
+ var AUTOMATION_GLOBALS = [
1414
+ "__nightmare",
1415
+ "_phantom",
1416
+ "callPhantom",
1417
+ "__selenium_evaluate",
1418
+ "__webdriver_evaluate",
1419
+ "__driver_evaluate",
1420
+ "__webdriver_script_function",
1421
+ "__lastWatirAlert",
1422
+ "__lastWatirConfirm",
1423
+ "__lastWatirPrompt",
1424
+ "_Selenium_IDE_Recorder",
1425
+ "domAutomation",
1426
+ "domAutomationController",
1427
+ "webdriver",
1428
+ "_webdriver_script_fn",
1429
+ "__webdriver_script_func",
1430
+ "__fxdriver_evaluate",
1431
+ "__fxdriver_unwrapped",
1432
+ "__selenium_unwrapped"
1433
+ ];
1434
+ function getWebGLRenderer(gl) {
1435
+ const renderer = gl.getParameter(gl.RENDERER);
1436
+ if (renderer && !/^(WebKit WebGL|Mozilla|Google Inc\.)$/i.test(renderer)) {
1437
+ return renderer;
1438
+ }
1439
+ const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
1440
+ if (debugInfo) {
1441
+ return gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
1442
+ }
1443
+ return renderer !== null && renderer !== void 0 ? renderer : void 0;
1444
+ }
1445
+ function withWebGLContext(fn) {
1446
+ try {
1447
+ const canvas = document.createElement("canvas");
1448
+ const gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
1449
+ if (!gl)
1450
+ return { hasWebGL: false, result: void 0 };
1451
+ try {
1452
+ return { hasWebGL: true, result: fn(gl) };
1453
+ } finally {
1454
+ const loseCtx = gl.getExtension("WEBGL_lose_context");
1455
+ loseCtx === null || loseCtx === void 0 ? void 0 : loseCtx.loseContext();
1456
+ }
1457
+ } catch (_a) {
1458
+ return { hasWebGL: false, result: void 0 };
1459
+ }
1460
+ }
1171
1461
  var EnvironmentStrategy = class extends BaseStrategy {
1172
1462
  constructor() {
1173
1463
  super(...arguments);
@@ -1184,12 +1474,35 @@ var EnvironmentStrategy = class extends BaseStrategy {
1184
1474
  this.data = null;
1185
1475
  }
1186
1476
  onTick(_timestamp) {
1187
- this.captureEnvironment();
1477
+ if (!this.data) {
1478
+ this.captureEnvironment();
1479
+ }
1188
1480
  }
1189
1481
  score() {
1190
1482
  if (!this.data)
1191
1483
  return void 0;
1192
1484
  const env = this.data;
1485
+ const auto = env.automation;
1486
+ if (auto.isWebdriver) {
1487
+ return 0.05;
1488
+ }
1489
+ if (auto.hasAutomationGlobals) {
1490
+ return 0.1;
1491
+ }
1492
+ if (auto.hasCDPInjection) {
1493
+ return 0.1;
1494
+ }
1495
+ const headlessIndicatorCount = [
1496
+ auto.hasHeadlessUA,
1497
+ auto.hasChromelessRuntime,
1498
+ auto.hasSoftwareRenderer
1499
+ ].filter(Boolean).length;
1500
+ if (headlessIndicatorCount >= 2) {
1501
+ return 0.15;
1502
+ }
1503
+ if (auto.hasHeadlessUA) {
1504
+ return 0.2;
1505
+ }
1193
1506
  let score = 0;
1194
1507
  let factors = 0;
1195
1508
  score += env.suspiciousDimensions ? 0.1 : 1;
@@ -1204,9 +1517,23 @@ var EnvironmentStrategy = class extends BaseStrategy {
1204
1517
  ].filter(Boolean).length;
1205
1518
  score += featureCount / 4;
1206
1519
  factors++;
1207
- score += inverseSigmoid(env.plugins, -2, -0.5);
1208
- score += env.plugins > 0 ? 1 : 0.1;
1209
- factors += 2;
1520
+ if (!env.isMobile) {
1521
+ score += inverseSigmoid(env.plugins, -2, -0.5);
1522
+ score += env.plugins > 0 ? 1 : 0.1;
1523
+ factors += 2;
1524
+ if (auto.hasNoPlugins && env.vendor.includes("Google")) {
1525
+ score += 0.3;
1526
+ factors++;
1527
+ }
1528
+ }
1529
+ if (auto.hasChromelessRuntime) {
1530
+ score += 0.3;
1531
+ factors++;
1532
+ }
1533
+ if (auto.hasSoftwareRenderer) {
1534
+ score += 0.4;
1535
+ factors++;
1536
+ }
1210
1537
  score += gaussian(env.devicePixelRatio, 2, 1.5);
1211
1538
  score += env.colorDepth === 24 || env.colorDepth === 32 ? 1 : 0.4;
1212
1539
  factors += 2;
@@ -1218,15 +1545,58 @@ var EnvironmentStrategy = class extends BaseStrategy {
1218
1545
  const smallScreen = window.innerWidth < 768 && window.innerHeight < 1024;
1219
1546
  return hasTouchScreen && smallScreen || mobileUA;
1220
1547
  }
1221
- captureEnvironment() {
1548
+ /**
1549
+ * Detect automation indicators
1550
+ */
1551
+ detectAutomation() {
1552
+ const isMobile = this.isMobileDevice();
1553
+ const isWebdriver = navigator.webdriver === true;
1554
+ const ua = navigator.userAgent;
1555
+ const hasHeadlessUA = /HeadlessChrome|Headless/i.test(ua);
1556
+ const win = window;
1557
+ const hasChromelessRuntime = !!(win.chrome && typeof win.chrome === "object" && !win.chrome.runtime);
1558
+ const detectedGlobals = [];
1559
+ for (const global of AUTOMATION_GLOBALS) {
1560
+ if (global in win) {
1561
+ detectedGlobals.push(global);
1562
+ }
1563
+ }
1564
+ const hasAutomationGlobals = detectedGlobals.length > 0;
1565
+ const detectedCDPKeys = [];
1222
1566
  try {
1223
- let hasWebGL = false;
1224
- try {
1225
- const canvas = document.createElement("canvas");
1226
- hasWebGL = !!(canvas.getContext("webgl") || canvas.getContext("experimental-webgl"));
1227
- } catch (e) {
1228
- hasWebGL = false;
1567
+ for (const key of Object.keys(win)) {
1568
+ if (/^cdc_|^__cdc_/.test(key)) {
1569
+ detectedCDPKeys.push(key);
1570
+ }
1229
1571
  }
1572
+ } catch (_a) {
1573
+ }
1574
+ const hasCDPInjection = detectedCDPKeys.length > 0;
1575
+ const hasNoPlugins = !isMobile && navigator.plugins.length === 0;
1576
+ let hasSoftwareRenderer = false;
1577
+ const webglResult = withWebGLContext((gl) => getWebGLRenderer(gl));
1578
+ if (webglResult.hasWebGL && webglResult.result) {
1579
+ const renderer = webglResult.result;
1580
+ hasSoftwareRenderer = /SwiftShader|Software|LLVMpipe/i.test(renderer);
1581
+ this._webglRenderer = renderer;
1582
+ }
1583
+ return {
1584
+ isWebdriver,
1585
+ hasHeadlessUA,
1586
+ hasChromelessRuntime,
1587
+ hasSoftwareRenderer,
1588
+ hasNoPlugins,
1589
+ hasAutomationGlobals,
1590
+ detectedGlobals,
1591
+ hasCDPInjection,
1592
+ detectedCDPKeys
1593
+ };
1594
+ }
1595
+ captureEnvironment() {
1596
+ try {
1597
+ const webgl = withWebGLContext((gl) => getWebGLRenderer(gl));
1598
+ const hasWebGL = webgl.hasWebGL;
1599
+ const webglRenderer = webgl.result;
1230
1600
  const hasWebRTC = !!(window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection);
1231
1601
  const isMobile = this.isMobileDevice();
1232
1602
  const windowWidth = window.innerWidth;
@@ -1238,6 +1608,7 @@ var EnvironmentStrategy = class extends BaseStrategy {
1238
1608
  const suspiciousRatio = windowScreenRatio === 1 || windowScreenRatio < 0.1 || windowScreenRatio > 1;
1239
1609
  const hasStorage = typeof localStorage !== "undefined" && typeof sessionStorage !== "undefined";
1240
1610
  const featureInconsistency = navigator.plugins.length === 0 && navigator.mimeTypes.length === 0 || !hasWebGL || !hasStorage;
1611
+ const automation = this.detectAutomation();
1241
1612
  this.data = {
1242
1613
  screenWidth,
1243
1614
  screenHeight,
@@ -1263,10 +1634,11 @@ var EnvironmentStrategy = class extends BaseStrategy {
1263
1634
  suspiciousDimensions,
1264
1635
  featureInconsistency,
1265
1636
  isMobile,
1266
- timestamp: Date.now()
1637
+ timestamp: Date.now(),
1638
+ automation,
1639
+ webglRenderer
1267
1640
  };
1268
- } catch (error) {
1269
- console.warn("Failed to capture environment:", error);
1641
+ } catch (_a) {
1270
1642
  }
1271
1643
  }
1272
1644
  getDebugInfo() {
@@ -1281,6 +1653,24 @@ var EnvironmentStrategy = class extends BaseStrategy {
1281
1653
  var _a, _b;
1282
1654
  return (_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a.isMobile) !== null && _b !== void 0 ? _b : null;
1283
1655
  }
1656
+ /**
1657
+ * Get automation detection results
1658
+ * Returns null if environment hasn't been captured yet
1659
+ */
1660
+ getAutomationIndicators() {
1661
+ var _a, _b;
1662
+ return (_b = (_a = this.data) === null || _a === void 0 ? void 0 : _a.automation) !== null && _b !== void 0 ? _b : null;
1663
+ }
1664
+ /**
1665
+ * Quick check if any strong automation indicator is present
1666
+ * Returns true if likely a bot, false if likely human, null if not checked yet
1667
+ */
1668
+ isLikelyBot() {
1669
+ if (!this.data)
1670
+ return null;
1671
+ const auto = this.data.automation;
1672
+ return auto.isWebdriver || auto.hasAutomationGlobals || auto.hasCDPInjection || auto.hasHeadlessUA;
1673
+ }
1284
1674
  };
1285
1675
 
1286
1676
  // dist/esm/strategies/resize.js
@@ -1366,6 +1756,520 @@ var ResizeStrategy = class extends BaseStrategy {
1366
1756
  }
1367
1757
  };
1368
1758
 
1759
+ // dist/esm/strategies/timing.js
1760
+ var TimingStrategy = class extends BaseStrategy {
1761
+ constructor() {
1762
+ super(...arguments);
1763
+ this.name = "timing";
1764
+ this.defaultWeight = 0.15;
1765
+ this.actions = [];
1766
+ this.mouseStillness = {
1767
+ position: null,
1768
+ lastMoveTime: 0,
1769
+ microMovementCount: 0
1770
+ };
1771
+ this.microMovements = [];
1772
+ this.isActive = false;
1773
+ this.mouseListener = null;
1774
+ this.clickListener = null;
1775
+ this.keydownListener = null;
1776
+ this.scrollListener = null;
1777
+ this.STILLNESS_WINDOW = 500;
1778
+ this.MICRO_MOVEMENT_THRESHOLD = 1;
1779
+ this.MAX_MICRO_MOVEMENT = 5;
1780
+ this.MACHINE_PRECISION_THRESHOLD = 5;
1781
+ }
1782
+ start() {
1783
+ if (this.isActive)
1784
+ return;
1785
+ this.isActive = true;
1786
+ this.mouseListener = (e) => {
1787
+ const mouseEvent = e;
1788
+ const now = Date.now();
1789
+ const currentPos = { x: mouseEvent.clientX, y: mouseEvent.clientY };
1790
+ if (this.mouseStillness.position) {
1791
+ const dx = currentPos.x - this.mouseStillness.position.x;
1792
+ const dy = currentPos.y - this.mouseStillness.position.y;
1793
+ const distance = Math.sqrt(dx * dx + dy * dy);
1794
+ if (distance >= this.MICRO_MOVEMENT_THRESHOLD && distance <= this.MAX_MICRO_MOVEMENT) {
1795
+ this.microMovements.push({ timestamp: now, distance });
1796
+ }
1797
+ if (distance >= this.MICRO_MOVEMENT_THRESHOLD) {
1798
+ this.mouseStillness.lastMoveTime = now;
1799
+ }
1800
+ }
1801
+ this.mouseStillness.position = currentPos;
1802
+ const cutoff = now - this.STILLNESS_WINDOW;
1803
+ this.microMovements = this.microMovements.filter((m) => m.timestamp >= cutoff);
1804
+ };
1805
+ this.clickListener = (e) => {
1806
+ this.recordAction("click", e);
1807
+ };
1808
+ this.keydownListener = () => {
1809
+ this.recordAction("keydown");
1810
+ };
1811
+ this.scrollListener = () => {
1812
+ this.recordAction("scroll");
1813
+ };
1814
+ document.addEventListener("mousemove", this.mouseListener, { passive: true });
1815
+ document.addEventListener("click", this.clickListener, { passive: true });
1816
+ document.addEventListener("keydown", this.keydownListener, { passive: true });
1817
+ document.addEventListener("scroll", this.scrollListener, { passive: true });
1818
+ }
1819
+ recordAction(type, _event) {
1820
+ const now = Date.now();
1821
+ const timeSinceMouseMove = this.mouseStillness.lastMoveTime > 0 ? now - this.mouseStillness.lastMoveTime : -1;
1822
+ this.mouseStillness.microMovementCount = this.microMovements.length;
1823
+ this.actions.push({
1824
+ type,
1825
+ timestamp: now,
1826
+ timeSinceMouseMove,
1827
+ wasHidden: document.hidden
1828
+ });
1829
+ this.notifyEvent(0.7);
1830
+ if (this.actions.length > 100) {
1831
+ this.actions.shift();
1832
+ }
1833
+ }
1834
+ stop() {
1835
+ if (!this.isActive)
1836
+ return;
1837
+ this.isActive = false;
1838
+ if (this.mouseListener) {
1839
+ document.removeEventListener("mousemove", this.mouseListener);
1840
+ this.mouseListener = null;
1841
+ }
1842
+ if (this.clickListener) {
1843
+ document.removeEventListener("click", this.clickListener);
1844
+ this.clickListener = null;
1845
+ }
1846
+ if (this.keydownListener) {
1847
+ document.removeEventListener("keydown", this.keydownListener);
1848
+ this.keydownListener = null;
1849
+ }
1850
+ if (this.scrollListener) {
1851
+ document.removeEventListener("scroll", this.scrollListener);
1852
+ this.scrollListener = null;
1853
+ }
1854
+ }
1855
+ reset() {
1856
+ this.actions = [];
1857
+ this.microMovements = [];
1858
+ this.mouseStillness = {
1859
+ position: null,
1860
+ lastMoveTime: 0,
1861
+ microMovementCount: 0
1862
+ };
1863
+ }
1864
+ score() {
1865
+ const actionCount = this.actions.length;
1866
+ if (actionCount < 3)
1867
+ return void 0;
1868
+ let score = 0;
1869
+ let factors = 0;
1870
+ const clicks = [];
1871
+ const clicksWithMouse = [];
1872
+ let hiddenCount = 0;
1873
+ for (const action of this.actions) {
1874
+ if (action.type === "click") {
1875
+ clicks.push(action);
1876
+ if (action.timeSinceMouseMove >= 0) {
1877
+ clicksWithMouse.push(action);
1878
+ }
1879
+ }
1880
+ if (action.wasHidden)
1881
+ hiddenCount++;
1882
+ }
1883
+ if (clicks.length >= 2) {
1884
+ const stillnessScore = this.scorePreActionStillness(clicks);
1885
+ if (stillnessScore !== void 0) {
1886
+ score += stillnessScore;
1887
+ factors++;
1888
+ }
1889
+ }
1890
+ if (clicksWithMouse.length >= 3) {
1891
+ const mouseToClickScore = this.scoreMouseToClickDelayFromCache(clicksWithMouse);
1892
+ if (mouseToClickScore !== void 0) {
1893
+ score += mouseToClickScore;
1894
+ factors++;
1895
+ }
1896
+ }
1897
+ if (actionCount >= 5) {
1898
+ const intervalScore = this.scoreActionIntervals();
1899
+ if (intervalScore !== void 0) {
1900
+ score += intervalScore;
1901
+ factors++;
1902
+ }
1903
+ }
1904
+ const hiddenScore = this.scoreHiddenActionsFromCount(hiddenCount, actionCount);
1905
+ score += hiddenScore;
1906
+ factors++;
1907
+ return factors > 0 ? score / factors : void 0;
1908
+ }
1909
+ /**
1910
+ * Score based on pre-action stillness
1911
+ * Humans have micro-movements before clicking; bots are perfectly still
1912
+ */
1913
+ scorePreActionStillness(clicks) {
1914
+ const clicksWithMouseData = clicks.filter((c) => c.timeSinceMouseMove >= 0);
1915
+ if (clicksWithMouseData.length < 2)
1916
+ return void 0;
1917
+ const perfectlyStillClicks = clicksWithMouseData.filter((c) => {
1918
+ return c.timeSinceMouseMove >= 100 && c.timeSinceMouseMove <= 500 && this.mouseStillness.microMovementCount === 0;
1919
+ }).length;
1920
+ const stillRatio = perfectlyStillClicks / clicksWithMouseData.length;
1921
+ if (stillRatio >= 0.9)
1922
+ return 0.1;
1923
+ if (stillRatio >= 0.7)
1924
+ return 0.3;
1925
+ if (stillRatio >= 0.5)
1926
+ return 0.5;
1927
+ if (stillRatio >= 0.3)
1928
+ return 0.7;
1929
+ return 1;
1930
+ }
1931
+ /**
1932
+ * Score mouse-to-click delay patterns (using pre-filtered cache)
1933
+ */
1934
+ scoreMouseToClickDelayFromCache(clicksWithMouse) {
1935
+ const delays = clicksWithMouse.map((c) => c.timeSinceMouseMove);
1936
+ const stats = calculateStatistics(delays);
1937
+ if (stats.mean < 10)
1938
+ return 0.1;
1939
+ if (stats.cv < 0.2 && clicksWithMouse.length >= 5)
1940
+ return 0.2;
1941
+ if (stats.mean >= 50 && stats.mean <= 300 && stats.cv >= 0.3)
1942
+ return 1;
1943
+ if (stats.cv < 0.4)
1944
+ return 0.6;
1945
+ return 0.8;
1946
+ }
1947
+ /**
1948
+ * Score action intervals for machine-like precision
1949
+ * Detects exact intervals: 100ms, 500ms, 1000ms
1950
+ */
1951
+ scoreActionIntervals() {
1952
+ if (this.actions.length < 5)
1953
+ return void 0;
1954
+ const intervals = [];
1955
+ for (let i = 1; i < this.actions.length; i++) {
1956
+ intervals.push(this.actions[i].timestamp - this.actions[i - 1].timestamp);
1957
+ }
1958
+ const machineIntervals = [100, 200, 250, 500, 1e3];
1959
+ let preciseCount = 0;
1960
+ for (const interval of intervals) {
1961
+ for (const machineInterval of machineIntervals) {
1962
+ const remainder = interval % machineInterval;
1963
+ if (remainder < this.MACHINE_PRECISION_THRESHOLD || machineInterval - remainder < this.MACHINE_PRECISION_THRESHOLD) {
1964
+ preciseCount++;
1965
+ break;
1966
+ }
1967
+ }
1968
+ }
1969
+ const preciseRatio = preciseCount / intervals.length;
1970
+ if (preciseRatio >= 0.8)
1971
+ return 0.1;
1972
+ if (preciseRatio >= 0.6)
1973
+ return 0.3;
1974
+ if (preciseRatio >= 0.4)
1975
+ return 0.5;
1976
+ const stats = calculateStatistics(intervals);
1977
+ if (stats.cv < 0.15)
1978
+ return 0.2;
1979
+ return 1;
1980
+ }
1981
+ /**
1982
+ * Score based on actions while document was hidden (using pre-computed count)
1983
+ */
1984
+ scoreHiddenActionsFromCount(hiddenCount, totalCount) {
1985
+ if (hiddenCount === 0)
1986
+ return 1;
1987
+ const hiddenRatio = hiddenCount / totalCount;
1988
+ if (hiddenRatio > 0.5)
1989
+ return 0.1;
1990
+ if (hiddenRatio > 0.2)
1991
+ return 0.3;
1992
+ if (hiddenRatio > 0)
1993
+ return 0.5;
1994
+ return 1;
1995
+ }
1996
+ getDebugInfo() {
1997
+ const clicks = this.actions.filter((a) => a.type === "click");
1998
+ const intervals = [];
1999
+ for (let i = 1; i < this.actions.length; i++) {
2000
+ intervals.push(this.actions[i].timestamp - this.actions[i - 1].timestamp);
2001
+ }
2002
+ return {
2003
+ actionCount: this.actions.length,
2004
+ clickCount: clicks.length,
2005
+ keydownCount: this.actions.filter((a) => a.type === "keydown").length,
2006
+ scrollCount: this.actions.filter((a) => a.type === "scroll").length,
2007
+ hiddenActionCount: this.actions.filter((a) => a.wasHidden).length,
2008
+ microMovementCount: this.microMovements.length,
2009
+ intervals: intervals.slice(-20),
2010
+ // Last 20 intervals
2011
+ lastStillnessDuration: this.mouseStillness.lastMoveTime > 0 ? Date.now() - this.mouseStillness.lastMoveTime : null
2012
+ };
2013
+ }
2014
+ };
2015
+
2016
+ // dist/esm/strategies/visibility.js
2017
+ var VisibilityStrategy = class extends BaseStrategy {
2018
+ constructor() {
2019
+ super(...arguments);
2020
+ this.name = "visibility";
2021
+ this.defaultWeight = 0.1;
2022
+ this.events = [];
2023
+ this.focusTypingPairs = [];
2024
+ this.actionsWhileHidden = 0;
2025
+ this.lastVisibilityChange = null;
2026
+ this.resumeDelays = [];
2027
+ this.isActive = false;
2028
+ this.visibilityListener = null;
2029
+ this.focusListener = null;
2030
+ this.blurListener = null;
2031
+ this.clickListener = null;
2032
+ this.keydownListener = null;
2033
+ this.inputFocusListener = null;
2034
+ this.lastFocusedInput = null;
2035
+ this.hasTypedInFocusedInput = false;
2036
+ this.lastActionTime = 0;
2037
+ this.preHideActionTime = 0;
2038
+ }
2039
+ start() {
2040
+ if (this.isActive)
2041
+ return;
2042
+ this.isActive = true;
2043
+ this.visibilityListener = () => {
2044
+ const now = Date.now();
2045
+ const wasHidden = document.hidden;
2046
+ if (this.lastVisibilityChange && !wasHidden) {
2047
+ if (this.lastActionTime > 0 && this.preHideActionTime > 0) {
2048
+ const timeSinceLastAction = now - this.lastActionTime;
2049
+ if (timeSinceLastAction < 50) {
2050
+ this.actionsWhileHidden++;
2051
+ }
2052
+ }
2053
+ this.lastVisibilityChange = { hidden: false, timestamp: now };
2054
+ } else if (wasHidden) {
2055
+ this.preHideActionTime = this.lastActionTime;
2056
+ this.lastVisibilityChange = { hidden: true, timestamp: now };
2057
+ }
2058
+ this.events.push({
2059
+ type: "visibility_change",
2060
+ timestamp: now,
2061
+ wasHidden
2062
+ });
2063
+ };
2064
+ this.focusListener = () => {
2065
+ this.events.push({
2066
+ type: "focus_change",
2067
+ timestamp: Date.now(),
2068
+ wasHidden: document.hidden,
2069
+ wasFocused: true
2070
+ });
2071
+ };
2072
+ this.blurListener = () => {
2073
+ this.events.push({
2074
+ type: "focus_change",
2075
+ timestamp: Date.now(),
2076
+ wasHidden: document.hidden,
2077
+ wasFocused: false
2078
+ });
2079
+ };
2080
+ this.clickListener = (e) => {
2081
+ this.recordAction("click", e);
2082
+ };
2083
+ this.keydownListener = (e) => {
2084
+ this.recordAction("keydown", e);
2085
+ if (this.lastFocusedInput && !this.hasTypedInFocusedInput) {
2086
+ const now = Date.now();
2087
+ const delay = now - this.lastFocusedInput.timestamp;
2088
+ this.focusTypingPairs.push({
2089
+ focusTime: this.lastFocusedInput.timestamp,
2090
+ firstKeypressTime: now,
2091
+ delay,
2092
+ element: this.lastFocusedInput.element
2093
+ });
2094
+ this.hasTypedInFocusedInput = true;
2095
+ }
2096
+ };
2097
+ this.inputFocusListener = (e) => {
2098
+ const target = e.target;
2099
+ if (target && (target.tagName === "INPUT" || target.tagName === "TEXTAREA")) {
2100
+ this.lastFocusedInput = {
2101
+ element: target.tagName.toLowerCase(),
2102
+ timestamp: Date.now()
2103
+ };
2104
+ this.hasTypedInFocusedInput = false;
2105
+ }
2106
+ };
2107
+ document.addEventListener("visibilitychange", this.visibilityListener);
2108
+ window.addEventListener("focus", this.focusListener);
2109
+ window.addEventListener("blur", this.blurListener);
2110
+ document.addEventListener("click", this.clickListener, { passive: true });
2111
+ document.addEventListener("keydown", this.keydownListener, { passive: true });
2112
+ document.addEventListener("focusin", this.inputFocusListener, { passive: true });
2113
+ }
2114
+ recordAction(_type, _event) {
2115
+ const now = Date.now();
2116
+ this.lastActionTime = now;
2117
+ if (document.hidden) {
2118
+ this.actionsWhileHidden++;
2119
+ this.events.push({
2120
+ type: "action_while_hidden",
2121
+ timestamp: now,
2122
+ wasHidden: true
2123
+ });
2124
+ this.notifyEvent(1);
2125
+ }
2126
+ if (this.lastVisibilityChange && !this.lastVisibilityChange.hidden) {
2127
+ const resumeDelay = now - this.lastVisibilityChange.timestamp;
2128
+ if (resumeDelay > 0 && resumeDelay < 1e4 && this.resumeDelays.length < 20) {
2129
+ const lastRecordedDelay = this.resumeDelays[this.resumeDelays.length - 1];
2130
+ if (lastRecordedDelay === void 0 || Math.abs(resumeDelay - lastRecordedDelay) > 100) {
2131
+ this.resumeDelays.push(resumeDelay);
2132
+ }
2133
+ }
2134
+ }
2135
+ }
2136
+ stop() {
2137
+ if (!this.isActive)
2138
+ return;
2139
+ this.isActive = false;
2140
+ if (this.visibilityListener) {
2141
+ document.removeEventListener("visibilitychange", this.visibilityListener);
2142
+ this.visibilityListener = null;
2143
+ }
2144
+ if (this.focusListener) {
2145
+ window.removeEventListener("focus", this.focusListener);
2146
+ this.focusListener = null;
2147
+ }
2148
+ if (this.blurListener) {
2149
+ window.removeEventListener("blur", this.blurListener);
2150
+ this.blurListener = null;
2151
+ }
2152
+ if (this.clickListener) {
2153
+ document.removeEventListener("click", this.clickListener);
2154
+ this.clickListener = null;
2155
+ }
2156
+ if (this.keydownListener) {
2157
+ document.removeEventListener("keydown", this.keydownListener);
2158
+ this.keydownListener = null;
2159
+ }
2160
+ if (this.inputFocusListener) {
2161
+ document.removeEventListener("focusin", this.inputFocusListener);
2162
+ this.inputFocusListener = null;
2163
+ }
2164
+ }
2165
+ reset() {
2166
+ this.events = [];
2167
+ this.focusTypingPairs = [];
2168
+ this.actionsWhileHidden = 0;
2169
+ this.lastVisibilityChange = null;
2170
+ this.resumeDelays = [];
2171
+ this.lastFocusedInput = null;
2172
+ this.hasTypedInFocusedInput = false;
2173
+ this.lastActionTime = 0;
2174
+ this.preHideActionTime = 0;
2175
+ }
2176
+ score() {
2177
+ if (this.events.length < 2)
2178
+ return void 0;
2179
+ let score = 0;
2180
+ let factors = 0;
2181
+ const hiddenActionScore = this.scoreHiddenActions();
2182
+ if (hiddenActionScore !== void 0) {
2183
+ score += hiddenActionScore;
2184
+ factors++;
2185
+ }
2186
+ const resumeScore = this.scoreResumeDelays();
2187
+ if (resumeScore !== void 0) {
2188
+ score += resumeScore;
2189
+ factors++;
2190
+ }
2191
+ const focusTypingScore = this.scoreFocusTyping();
2192
+ if (focusTypingScore !== void 0) {
2193
+ score += focusTypingScore;
2194
+ factors++;
2195
+ }
2196
+ return factors > 0 ? score / factors : void 0;
2197
+ }
2198
+ /**
2199
+ * Score based on actions while document was hidden
2200
+ * Humans can't interact with hidden tabs; bots can
2201
+ */
2202
+ scoreHiddenActions() {
2203
+ if (this.actionsWhileHidden === 0)
2204
+ return 1;
2205
+ if (this.actionsWhileHidden >= 5)
2206
+ return 0.1;
2207
+ if (this.actionsWhileHidden >= 3)
2208
+ return 0.2;
2209
+ if (this.actionsWhileHidden >= 1)
2210
+ return 0.3;
2211
+ return 1;
2212
+ }
2213
+ /**
2214
+ * Score based on how quickly activity resumes after tab becomes visible
2215
+ * Humans need time to refocus (100-500ms minimum)
2216
+ * Bots often resume instantly (< 50ms)
2217
+ */
2218
+ scoreResumeDelays() {
2219
+ if (this.resumeDelays.length < 2)
2220
+ return void 0;
2221
+ const fastResumeCount = this.resumeDelays.filter((d) => d < 50).length;
2222
+ const fastResumeRatio = fastResumeCount / this.resumeDelays.length;
2223
+ if (fastResumeRatio >= 0.8)
2224
+ return 0.1;
2225
+ if (fastResumeRatio >= 0.5)
2226
+ return 0.3;
2227
+ if (fastResumeRatio >= 0.3)
2228
+ return 0.5;
2229
+ if (fastResumeRatio > 0)
2230
+ return 0.7;
2231
+ return 1;
2232
+ }
2233
+ /**
2234
+ * Score based on focus-to-keypress timing
2235
+ * Humans focus inputs before typing (natural delay 100-500ms)
2236
+ * Bots often type without focusing or with instant delay
2237
+ */
2238
+ scoreFocusTyping() {
2239
+ if (this.focusTypingPairs.length < 2)
2240
+ return void 0;
2241
+ let suspiciousCount = 0;
2242
+ for (const pair of this.focusTypingPairs) {
2243
+ if (pair.delay < 20) {
2244
+ suspiciousCount++;
2245
+ }
2246
+ }
2247
+ const suspiciousRatio = suspiciousCount / this.focusTypingPairs.length;
2248
+ if (suspiciousRatio >= 0.8)
2249
+ return 0.2;
2250
+ if (suspiciousRatio >= 0.5)
2251
+ return 0.4;
2252
+ if (suspiciousRatio >= 0.3)
2253
+ return 0.6;
2254
+ if (suspiciousRatio > 0)
2255
+ return 0.8;
2256
+ return 1;
2257
+ }
2258
+ getDebugInfo() {
2259
+ return {
2260
+ eventCount: this.events.length,
2261
+ actionsWhileHidden: this.actionsWhileHidden,
2262
+ visibilityChanges: this.events.filter((e) => e.type === "visibility_change").length,
2263
+ focusChanges: this.events.filter((e) => e.type === "focus_change").length,
2264
+ resumeDelays: this.resumeDelays,
2265
+ focusTypingPairs: this.focusTypingPairs.map((p) => ({
2266
+ delay: p.delay,
2267
+ element: p.element
2268
+ }))
2269
+ };
2270
+ }
2271
+ };
2272
+
1369
2273
  // dist/esm/types.js
1370
2274
  var DEFAULT_SETTINGS = {
1371
2275
  sampleRates: {
@@ -1418,5 +2322,9 @@ var DEFAULT_SETTINGS = {
1418
2322
  Scroll,
1419
2323
  ScrollStrategy,
1420
2324
  Tap,
1421
- TapStrategy
2325
+ TapStrategy,
2326
+ Timing,
2327
+ TimingStrategy,
2328
+ Visibility,
2329
+ VisibilityStrategy
1422
2330
  });