jumpy-lion 0.0.41 → 0.0.42

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 (119) hide show
  1. package/dist/browser-controller.d.ts.map +1 -1
  2. package/dist/browser-controller.js +102 -16
  3. package/dist/browser-controller.js.map +1 -1
  4. package/dist/browser-plugin.d.ts +20 -1
  5. package/dist/browser-plugin.d.ts.map +1 -1
  6. package/dist/browser-plugin.js +21 -1
  7. package/dist/browser-plugin.js.map +1 -1
  8. package/dist/browser-process/browser.d.ts +22 -1
  9. package/dist/browser-process/browser.d.ts.map +1 -1
  10. package/dist/browser-process/browser.js +77 -5
  11. package/dist/browser-process/browser.js.map +1 -1
  12. package/dist/browser-profiles/chrome/default.d.ts +116 -0
  13. package/dist/browser-profiles/chrome/default.d.ts.map +1 -1
  14. package/dist/browser-profiles/chrome/default.js +118 -1
  15. package/dist/browser-profiles/chrome/default.js.map +1 -1
  16. package/dist/browser-profiles/chrome/populate-profile.d.ts +76 -0
  17. package/dist/browser-profiles/chrome/populate-profile.d.ts.map +1 -0
  18. package/dist/browser-profiles/chrome/populate-profile.js +300 -0
  19. package/dist/browser-profiles/chrome/populate-profile.js.map +1 -0
  20. package/dist/browser-profiles/index.d.ts +1 -0
  21. package/dist/browser-profiles/index.d.ts.map +1 -1
  22. package/dist/browser-profiles/index.js +2 -0
  23. package/dist/browser-profiles/index.js.map +1 -1
  24. package/dist/crawler.d.ts +32 -1
  25. package/dist/crawler.d.ts.map +1 -1
  26. package/dist/crawler.js +7 -0
  27. package/dist/crawler.js.map +1 -1
  28. package/dist/fingerprinting/custom-fingerprint-injector.d.ts +87 -0
  29. package/dist/fingerprinting/custom-fingerprint-injector.d.ts.map +1 -0
  30. package/dist/fingerprinting/custom-fingerprint-injector.js +342 -0
  31. package/dist/fingerprinting/custom-fingerprint-injector.js.map +1 -0
  32. package/dist/fingerprinting/fingerprint-injector.d.ts +40 -2
  33. package/dist/fingerprinting/fingerprint-injector.d.ts.map +1 -1
  34. package/dist/fingerprinting/fingerprint-injector.js +449 -44
  35. package/dist/fingerprinting/fingerprint-injector.js.map +1 -1
  36. package/dist/fingerprinting/fingerprint-overrides/audio-spoofing.d.ts.map +1 -1
  37. package/dist/fingerprinting/fingerprint-overrides/audio-spoofing.js +11 -1
  38. package/dist/fingerprinting/fingerprint-overrides/audio-spoofing.js.map +1 -1
  39. package/dist/fingerprinting/fingerprint-overrides/canvas-protection.d.ts.map +1 -1
  40. package/dist/fingerprinting/fingerprint-overrides/canvas-protection.js +11 -1
  41. package/dist/fingerprinting/fingerprint-overrides/canvas-protection.js.map +1 -1
  42. package/dist/fingerprinting/fingerprint-overrides/cdp-detection-bypass.d.ts +14 -0
  43. package/dist/fingerprinting/fingerprint-overrides/cdp-detection-bypass.d.ts.map +1 -0
  44. package/dist/fingerprinting/fingerprint-overrides/cdp-detection-bypass.js +497 -0
  45. package/dist/fingerprinting/fingerprint-overrides/cdp-detection-bypass.js.map +1 -0
  46. package/dist/fingerprinting/fingerprint-overrides/client-rect-spoofing.d.ts.map +1 -1
  47. package/dist/fingerprinting/fingerprint-overrides/client-rect-spoofing.js +11 -1
  48. package/dist/fingerprinting/fingerprint-overrides/client-rect-spoofing.js.map +1 -1
  49. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.d.ts +14 -0
  50. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.d.ts.map +1 -0
  51. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.js +536 -0
  52. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.js.map +1 -0
  53. package/dist/fingerprinting/fingerprint-overrides/font-spoofing.d.ts.map +1 -1
  54. package/dist/fingerprinting/fingerprint-overrides/font-spoofing.js +11 -1
  55. package/dist/fingerprinting/fingerprint-overrides/font-spoofing.js.map +1 -1
  56. package/dist/fingerprinting/fingerprint-overrides/index.d.ts +16 -1
  57. package/dist/fingerprinting/fingerprint-overrides/index.d.ts.map +1 -1
  58. package/dist/fingerprinting/fingerprint-overrides/index.js +19 -1
  59. package/dist/fingerprinting/fingerprint-overrides/index.js.map +1 -1
  60. package/dist/fingerprinting/fingerprint-overrides/keyboard-humanization.d.ts +45 -0
  61. package/dist/fingerprinting/fingerprint-overrides/keyboard-humanization.d.ts.map +1 -0
  62. package/dist/fingerprinting/fingerprint-overrides/keyboard-humanization.js +291 -0
  63. package/dist/fingerprinting/fingerprint-overrides/keyboard-humanization.js.map +1 -0
  64. package/dist/fingerprinting/fingerprint-overrides/locale-spoofing.d.ts.map +1 -1
  65. package/dist/fingerprinting/fingerprint-overrides/locale-spoofing.js +54 -22
  66. package/dist/fingerprinting/fingerprint-overrides/locale-spoofing.js.map +1 -1
  67. package/dist/fingerprinting/fingerprint-overrides/mouse-humanization.d.ts.map +1 -1
  68. package/dist/fingerprinting/fingerprint-overrides/mouse-humanization.js +4 -5
  69. package/dist/fingerprinting/fingerprint-overrides/mouse-humanization.js.map +1 -1
  70. package/dist/fingerprinting/fingerprint-overrides/performance-spoofing.d.ts.map +1 -1
  71. package/dist/fingerprinting/fingerprint-overrides/performance-spoofing.js +11 -1
  72. package/dist/fingerprinting/fingerprint-overrides/performance-spoofing.js.map +1 -1
  73. package/dist/fingerprinting/fingerprint-overrides/platform-consistency.d.ts +13 -0
  74. package/dist/fingerprinting/fingerprint-overrides/platform-consistency.d.ts.map +1 -1
  75. package/dist/fingerprinting/fingerprint-overrides/platform-consistency.js +413 -70
  76. package/dist/fingerprinting/fingerprint-overrides/platform-consistency.js.map +1 -1
  77. package/dist/fingerprinting/fingerprint-overrides/runtime-enable-bypass.d.ts +10 -3
  78. package/dist/fingerprinting/fingerprint-overrides/runtime-enable-bypass.d.ts.map +1 -1
  79. package/dist/fingerprinting/fingerprint-overrides/runtime-enable-bypass.js +132 -73
  80. package/dist/fingerprinting/fingerprint-overrides/runtime-enable-bypass.js.map +1 -1
  81. package/dist/fingerprinting/fingerprint-overrides/scroll-humanization.d.ts +55 -0
  82. package/dist/fingerprinting/fingerprint-overrides/scroll-humanization.d.ts.map +1 -0
  83. package/dist/fingerprinting/fingerprint-overrides/scroll-humanization.js +380 -0
  84. package/dist/fingerprinting/fingerprint-overrides/scroll-humanization.js.map +1 -0
  85. package/dist/fingerprinting/fingerprint-overrides/stealth-script.d.ts +8 -0
  86. package/dist/fingerprinting/fingerprint-overrides/stealth-script.d.ts.map +1 -1
  87. package/dist/fingerprinting/fingerprint-overrides/stealth-script.js +417 -71
  88. package/dist/fingerprinting/fingerprint-overrides/stealth-script.js.map +1 -1
  89. package/dist/fingerprinting/fingerprint-overrides/storage-consistency.d.ts +13 -0
  90. package/dist/fingerprinting/fingerprint-overrides/storage-consistency.d.ts.map +1 -0
  91. package/dist/fingerprinting/fingerprint-overrides/storage-consistency.js +368 -0
  92. package/dist/fingerprinting/fingerprint-overrides/storage-consistency.js.map +1 -0
  93. package/dist/fingerprinting/fingerprint-overrides/timing-consistency.d.ts +13 -0
  94. package/dist/fingerprinting/fingerprint-overrides/timing-consistency.d.ts.map +1 -0
  95. package/dist/fingerprinting/fingerprint-overrides/timing-consistency.js +438 -0
  96. package/dist/fingerprinting/fingerprint-overrides/timing-consistency.js.map +1 -0
  97. package/dist/fingerprinting/fingerprint-overrides/utils.d.ts +12 -0
  98. package/dist/fingerprinting/fingerprint-overrides/utils.d.ts.map +1 -0
  99. package/dist/fingerprinting/fingerprint-overrides/utils.js +315 -0
  100. package/dist/fingerprinting/fingerprint-overrides/utils.js.map +1 -0
  101. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.d.ts.map +1 -1
  102. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.js +13 -1
  103. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.js.map +1 -1
  104. package/dist/fingerprinting/fingerprint-overrides/webgpu-spoofing.d.ts.map +1 -1
  105. package/dist/fingerprinting/fingerprint-overrides/webgpu-spoofing.js +11 -1
  106. package/dist/fingerprinting/fingerprint-overrides/webgpu-spoofing.js.map +1 -1
  107. package/dist/fingerprinting/fingerprint-overrides/webrtc-spoofing.d.ts.map +1 -1
  108. package/dist/fingerprinting/fingerprint-overrides/webrtc-spoofing.js +11 -1
  109. package/dist/fingerprinting/fingerprint-overrides/webrtc-spoofing.js.map +1 -1
  110. package/dist/page.d.ts +12 -0
  111. package/dist/page.d.ts.map +1 -1
  112. package/dist/page.js +35 -3
  113. package/dist/page.js.map +1 -1
  114. package/dist/tsconfig.build.tsbuildinfo +1 -1
  115. package/package.json +4 -4
  116. package/dist/fingerprinting/canvas-fingerprint.d.ts +0 -4
  117. package/dist/fingerprinting/canvas-fingerprint.d.ts.map +0 -1
  118. package/dist/fingerprinting/canvas-fingerprint.js +0 -60
  119. package/dist/fingerprinting/canvas-fingerprint.js.map +0 -1
@@ -1,84 +1,143 @@
1
1
  /**
2
- * Runtime.enable Bypass
3
- * Prevents CDP detection through console.log(Error) technique
2
+ * Runtime.enable Bypass Script
3
+ * Prevents CDP detection through console.log(Error) technique and stack trace analysis.
4
+ *
5
+ * IMPORTANT: This is now a SCRIPT to be injected via addScriptToEvaluateOnNewDocument,
6
+ * NOT via Runtime.evaluate (which would defeat the purpose since Runtime.evaluate IS detectable!)
4
7
  */
5
- export const setupRuntimeEnableBypass = async (client) => {
6
- // Intercept Runtime.enable calls to prevent detection
7
- await client.send('Runtime.evaluate', {
8
- expression: `
8
+ /**
9
+ * Creates the runtime enable bypass script that should be bundled with other stealth scripts.
10
+ * This script runs BEFORE page JavaScript and patches Error/console to hide CDP markers.
11
+ */
12
+ export const createRuntimeEnableBypassScript = () => `
9
13
  (() => {
10
- // Store the original CDP send method if accessible
11
- if (window.__CDP_CLIENT__) {
12
- const originalSend = window.__CDP_CLIENT__.send;
13
- window.__CDP_CLIENT__.send = function(method, params) {
14
- // Block or modify Runtime.enable calls
15
- if (method === 'Runtime.enable') {
16
- console.log('Runtime.enable blocked');
17
- return Promise.resolve({});
18
- }
19
- return originalSend.apply(this, arguments);
20
- };
21
- }
14
+ 'use strict';
15
+ const DEBUG_PREFIX = '[RUNTIME-ENABLE-BYPASS]';
22
16
 
23
- // Additional protection against CDP detection
24
- const originalError = Error;
25
- let errorCounter = 0;
26
-
27
- window.Error = new Proxy(originalError, {
28
- construct(target, args) {
29
- const error = Reflect.construct(target, args);
17
+ try {
18
+ // =============================================================================
19
+ // PART 1: Error stack trace sanitization
20
+ // CDP detection often works by examining Error.stack for automation markers
21
+ // =============================================================================
22
+
23
+ const originalError = Error;
24
+ const originalErrorToString = Error.prototype.toString;
25
+ const originalErrorStackDesc = Object.getOwnPropertyDescriptor(Error.prototype, 'stack');
26
+
27
+ // Patterns that reveal CDP/automation
28
+ const CDP_MARKERS = [
29
+ '__puppeteer_evaluation_script__',
30
+ '__playwright_evaluation_script__',
31
+ 'CDP_',
32
+ 'chrome-extension://',
33
+ 'devtools://',
34
+ 'pptr:',
35
+ 'Runtime.evaluate',
36
+ ];
37
+
38
+ const sanitizeStack = (stack) => {
39
+ if (!stack || typeof stack !== 'string') return stack;
30
40
 
31
- // Detect CDP serialization attempts
32
- const stack = new originalError().stack;
33
- if (stack && stack.includes('__puppeteer_evaluation_script__')) {
34
- // This is likely a CDP evaluation, modify behavior
35
- Object.defineProperty(error, 'stack', {
36
- get() {
37
- return 'Error\\n at <anonymous>:1:1';
38
- },
39
- configurable: false
40
- });
41
+ let sanitized = stack;
42
+ for (const marker of CDP_MARKERS) {
43
+ if (sanitized.includes(marker)) {
44
+ // Replace with generic anonymous reference
45
+ // Simple string replacement (markers don't contain regex special chars)
46
+ while (sanitized.includes(marker)) {
47
+ sanitized = sanitized.split(marker).join('anonymous');
48
+ }
49
+ }
41
50
  }
42
-
43
- return error;
51
+ return sanitized;
52
+ };
53
+
54
+ // Override Error.prepareStackTrace if it exists (V8 specific)
55
+ if (typeof Error.prepareStackTrace === 'function') {
56
+ const originalPrepareStackTrace = Error.prepareStackTrace;
57
+ Error.prepareStackTrace = function(error, structuredStackTrace) {
58
+ const stack = originalPrepareStackTrace.call(this, error, structuredStackTrace);
59
+ return sanitizeStack(stack);
60
+ };
44
61
  }
45
- });
46
-
47
- // Protect against console-based CDP detection
48
- const protectedConsole = new Proxy(console, {
49
- get(target, prop) {
50
- const original = target[prop];
62
+
63
+ // Override Error.prototype.stack getter
64
+ if (originalErrorStackDesc && originalErrorStackDesc.get) {
65
+ Object.defineProperty(Error.prototype, 'stack', {
66
+ get: function() {
67
+ const stack = originalErrorStackDesc.get.call(this);
68
+ return sanitizeStack(stack);
69
+ },
70
+ set: originalErrorStackDesc.set,
71
+ configurable: true,
72
+ enumerable: false
73
+ });
74
+ }
75
+
76
+ console.log(DEBUG_PREFIX, '✓ Error stack trace sanitization applied');
77
+
78
+ // =============================================================================
79
+ // PART 2: Console protection
80
+ // Some CDP detection works by examining how Error objects are serialized in console
81
+ // =============================================================================
82
+
83
+ const originalConsole = window.console;
84
+ const consoleMethodsToProtect = ['log', 'warn', 'error', 'info', 'debug', 'trace'];
85
+
86
+ consoleMethodsToProtect.forEach(method => {
87
+ const original = originalConsole[method];
51
88
  if (typeof original === 'function') {
52
- return new Proxy(original, {
53
- apply(fn, thisArg, args) {
54
- // Filter out Error objects that might be used for CDP detection
55
- const filteredArgs = args.map(arg => {
56
- if (arg instanceof Error && arg.stack) {
57
- // Check if this might be a CDP detection attempt
58
- const stackString = arg.stack.toString();
59
- if (stackString.includes('Error.captureStackTrace') ||
60
- stackString.includes('__puppeteer_evaluation_script__')) {
61
- return arg.toString();
62
- }
63
- }
64
- return arg;
65
- });
66
- return Reflect.apply(fn, thisArg, filteredArgs);
67
- }
68
- });
89
+ originalConsole[method] = function(...args) {
90
+ // Sanitize Error objects before logging
91
+ const sanitizedArgs = args.map(arg => {
92
+ if (arg instanceof Error) {
93
+ // Clone the error with sanitized stack
94
+ const sanitizedError = new Error(arg.message);
95
+ sanitizedError.name = arg.name;
96
+ // stack will be auto-sanitized by our getter
97
+ return sanitizedError;
98
+ }
99
+ return arg;
100
+ });
101
+ return original.apply(this, sanitizedArgs);
102
+ };
103
+ // Hide the patch
104
+ originalConsole[method].toString = () => \`function \${method}() { [native code] }\`;
69
105
  }
70
- return original;
71
- }
72
- });
73
-
74
- try {
75
- Object.defineProperty(window, 'console', {
76
- value: protectedConsole,
77
- writable: false,
78
- configurable: false
79
106
  });
80
- } catch (e) {}
81
- })();`,
82
- });
83
- };
107
+
108
+ console.log(DEBUG_PREFIX, '✓ Console protection applied');
109
+
110
+ // =============================================================================
111
+ // PART 3: Protect against CDP WebSocket detection
112
+ // Some advanced detection tries to find the CDP websocket connection
113
+ // =============================================================================
114
+
115
+ // Override WebSocket to hide CDP connections
116
+ const originalWebSocket = window.WebSocket;
117
+ window.WebSocket = function(url, protocols) {
118
+ // Check if this looks like a CDP connection
119
+ if (url && typeof url === 'string') {
120
+ const lowerUrl = url.toLowerCase();
121
+ if (lowerUrl.includes('devtools') ||
122
+ lowerUrl.includes('/json') ||
123
+ lowerUrl.includes('ws://localhost:') ||
124
+ lowerUrl.includes('ws://127.0.0.1:')) {
125
+ // This might be a CDP detection attempt, proceed but mark it
126
+ // We can't block it as that would break legitimate websockets
127
+ }
128
+ }
129
+ return new originalWebSocket(url, protocols);
130
+ };
131
+
132
+ window.WebSocket.prototype = originalWebSocket.prototype;
133
+ Object.defineProperty(window.WebSocket, 'name', { value: 'WebSocket' });
134
+ window.WebSocket.toString = () => 'function WebSocket() { [native code] }';
135
+
136
+ console.log(DEBUG_PREFIX, '✓ WebSocket protection applied');
137
+
138
+ } catch (error) {
139
+ console.error(DEBUG_PREFIX, 'Failed to apply bypass:', error.message);
140
+ }
141
+ })();
142
+ `;
84
143
  //# sourceMappingURL=runtime-enable-bypass.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-enable-bypass.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/runtime-enable-bypass.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,KAAK,EAAE,MAAW,EAAiB,EAAE;IACzE,sDAAsD;IACtD,MAAM,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE;QAClC,UAAU,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAyEd;KACD,CAAC,CAAC;AACP,CAAC,CAAC"}
1
+ {"version":3,"file":"runtime-enable-bypass.js","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/runtime-enable-bypass.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,GAAW,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkI5D,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Scroll Humanization Module
3
+ * Simulates realistic scroll behavior for 2024-2025
4
+ *
5
+ * Features:
6
+ * - Natural scroll momentum physics
7
+ * - Reading-speed based scroll patterns
8
+ * - Scroll pause at content sections
9
+ * - Touch-like vs mouse wheel differentiation
10
+ * - CDP-level scroll enhancement
11
+ */
12
+ /**
13
+ * Scroll configuration
14
+ */
15
+ interface ScrollConfig {
16
+ /** Base scroll speed in pixels per scroll event */
17
+ baseScrollAmount: number;
18
+ /** Variance in scroll amount */
19
+ scrollVariance: number;
20
+ /** Deceleration factor for momentum scrolling */
21
+ deceleration: number;
22
+ /** Minimum velocity before stopping */
23
+ minVelocity: number;
24
+ /** Reading pause probability (0-1) */
25
+ readingPauseProbability: number;
26
+ /** Reading pause duration range in ms [min, max] */
27
+ readingPauseDuration: [number, number];
28
+ /** Delay between scroll events in ms */
29
+ eventDelay: number;
30
+ }
31
+ /**
32
+ * Generate human-like scroll positions using momentum physics
33
+ */
34
+ export declare const generateScrollPath: (startY: number, targetY: number, config?: Partial<ScrollConfig>) => {
35
+ y: number;
36
+ delay: number;
37
+ }[];
38
+ /**
39
+ * Create a script that enhances scroll events in the browser
40
+ */
41
+ export declare const createScrollHumanizationScript: () => string;
42
+ /**
43
+ * CDP-level human-like scroll function
44
+ */
45
+ export declare const humanScroll: (client: unknown, targetY: number, config?: Partial<ScrollConfig>) => Promise<void>;
46
+ /**
47
+ * Scroll to element with human-like behavior
48
+ */
49
+ export declare const humanScrollToElement: (client: unknown, selector: string, config?: Partial<ScrollConfig>) => Promise<void>;
50
+ /**
51
+ * Setup scroll humanization at CDP level
52
+ */
53
+ export declare const setupScrollHumanization: (client: unknown) => Promise<void>;
54
+ export {};
55
+ //# sourceMappingURL=scroll-humanization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scroll-humanization.d.ts","sourceRoot":"","sources":["../../../src/fingerprinting/fingerprint-overrides/scroll-humanization.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;GAEG;AACH,UAAU,YAAY;IAClB,mDAAmD;IACnD,gBAAgB,EAAE,MAAM,CAAC;IACzB,gCAAgC;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,YAAY,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,uBAAuB,EAAE,MAAM,CAAC;IAChC,oDAAoD;IACpD,oBAAoB,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;CACtB;AAYD;;GAEG;AACH,eAAO,MAAM,kBAAkB,WACnB,MAAM,WACL,MAAM,WACP,OAAO,CAAC,YAAY,CAAC,KAC9B;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAyD9B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,8BAA8B,QAAO,MA0NjD,CAAC;AAOF;;GAEG;AACH,eAAO,MAAM,WAAW,WACZ,OAAO,WACN,MAAM,WACP,OAAO,CAAC,YAAY,CAAC,KAC9B,OAAO,CAAC,IAAI,CA0Dd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,WACrB,OAAO,YACL,MAAM,WACR,OAAO,CAAC,YAAY,CAAC,KAC9B,OAAO,CAAC,IAAI,CAuCd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,WAAkB,OAAO,KAAG,OAAO,CAAC,IAAI,CAY3E,CAAC"}
@@ -0,0 +1,380 @@
1
+ /**
2
+ * Scroll Humanization Module
3
+ * Simulates realistic scroll behavior for 2024-2025
4
+ *
5
+ * Features:
6
+ * - Natural scroll momentum physics
7
+ * - Reading-speed based scroll patterns
8
+ * - Scroll pause at content sections
9
+ * - Touch-like vs mouse wheel differentiation
10
+ * - CDP-level scroll enhancement
11
+ */
12
+ const DEFAULT_SCROLL_CONFIG = {
13
+ baseScrollAmount: 100,
14
+ scrollVariance: 30,
15
+ deceleration: 0.95,
16
+ minVelocity: 5,
17
+ readingPauseProbability: 0.15,
18
+ readingPauseDuration: [500, 2000],
19
+ eventDelay: 16, // ~60fps
20
+ };
21
+ /**
22
+ * Generate human-like scroll positions using momentum physics
23
+ */
24
+ export const generateScrollPath = (startY, targetY, config = {}) => {
25
+ const cfg = { ...DEFAULT_SCROLL_CONFIG, ...config };
26
+ const path = [];
27
+ const direction = targetY > startY ? 1 : -1;
28
+ const totalDistance = Math.abs(targetY - startY);
29
+ // Initial velocity based on distance
30
+ let velocity = Math.min(cfg.baseScrollAmount * 2, totalDistance / 10);
31
+ let currentY = startY;
32
+ while (Math.abs(targetY - currentY) > cfg.minVelocity) {
33
+ // Apply deceleration as we approach target
34
+ const remainingDistance = Math.abs(targetY - currentY);
35
+ const decelerationFactor = remainingDistance < 200 ?
36
+ cfg.deceleration * 0.8 : cfg.deceleration;
37
+ velocity *= decelerationFactor;
38
+ // Add variance to make it look natural
39
+ const variance = (Math.random() - 0.5) * cfg.scrollVariance;
40
+ const scrollAmount = (velocity + variance) * direction;
41
+ currentY += scrollAmount;
42
+ // Clamp to target
43
+ if (direction > 0) {
44
+ currentY = Math.min(currentY, targetY);
45
+ }
46
+ else {
47
+ currentY = Math.max(currentY, targetY);
48
+ }
49
+ // Add slight variation to timing
50
+ const delay = cfg.eventDelay + (Math.random() - 0.5) * 8;
51
+ path.push({ y: Math.round(currentY), delay: Math.round(delay) });
52
+ // Occasionally pause as if reading
53
+ if (Math.random() < cfg.readingPauseProbability && path.length > 3) {
54
+ const pauseDuration = cfg.readingPauseDuration[0] +
55
+ Math.random() * (cfg.readingPauseDuration[1] - cfg.readingPauseDuration[0]);
56
+ path.push({ y: Math.round(currentY), delay: Math.round(pauseDuration) });
57
+ // Reset velocity after pause (user starts scrolling again)
58
+ velocity = cfg.baseScrollAmount;
59
+ }
60
+ // Ensure we don't get stuck in an infinite loop
61
+ if (velocity < cfg.minVelocity) {
62
+ break;
63
+ }
64
+ }
65
+ // Final position
66
+ path.push({ y: targetY, delay: cfg.eventDelay });
67
+ return path;
68
+ };
69
+ /**
70
+ * Create a script that enhances scroll events in the browser
71
+ */
72
+ export const createScrollHumanizationScript = () => {
73
+ return `
74
+ (() => {
75
+ 'use strict';
76
+
77
+ // Scroll Humanization for 2024-2025
78
+ const humanizeScroll = () => {
79
+ console.log('[SCROLL-DEBUG] Initializing scroll humanization');
80
+
81
+ // Track scroll state
82
+ let lastScrollTime = 0;
83
+ let scrollVelocity = 0;
84
+ let isScrolling = false;
85
+ let scrollTimeout = null;
86
+
87
+ // Generate consistent scroll variations
88
+ const generateScrollId = () => {
89
+ return Math.random().toString(36).substr(2, 9);
90
+ };
91
+
92
+ // Store original wheel event constructor
93
+ const OriginalWheelEvent = WheelEvent;
94
+
95
+ // Override WheelEvent to add realistic properties
96
+ window.WheelEvent = function(type, eventInitDict = {}) {
97
+ const enhancedInit = { ...eventInitDict };
98
+
99
+ // Add realistic delta values if not set
100
+ if (enhancedInit.deltaY === undefined) {
101
+ enhancedInit.deltaY = 100 + (Math.random() - 0.5) * 30;
102
+ }
103
+
104
+ // Add variance to existing delta
105
+ if (typeof enhancedInit.deltaY === 'number') {
106
+ enhancedInit.deltaY += (Math.random() - 0.5) * 10;
107
+ }
108
+
109
+ // Ensure proper delta mode (0 = pixels, 1 = lines, 2 = pages)
110
+ if (enhancedInit.deltaMode === undefined) {
111
+ enhancedInit.deltaMode = 0; // Pixels is most common
112
+ }
113
+
114
+ return new OriginalWheelEvent(type, enhancedInit);
115
+ };
116
+
117
+ // Note: Don't assign to prototype - it may be frozen in modern Chrome
118
+ // The Proxy wrapper handles prototype access via get trap if needed
119
+ console.log('[SCROLL-DEBUG] WheelEvent override installed');
120
+
121
+ // Enhanced scroll behavior tracking
122
+ const trackScrollBehavior = () => {
123
+ console.log('[SCROLL-DEBUG] Setting up scroll behavior tracking');
124
+ const originalScrollTo = window.scrollTo;
125
+ const originalScrollBy = window.scrollBy;
126
+ const originalScrollIntoView = Element.prototype.scrollIntoView;
127
+
128
+ let scrollCallCount = 0;
129
+
130
+ // Override scrollTo to add human-like behavior
131
+ window.scrollTo = function(options) {
132
+ scrollCallCount++;
133
+ console.log('[SCROLL-DEBUG] scrollTo called', {
134
+ callCount: scrollCallCount,
135
+ options,
136
+ scrollY: window.scrollY
137
+ });
138
+ // Don't interfere with normal scrolling - just pass through
139
+ // The humanization happens at the wheel event level
140
+ return originalScrollTo.apply(this, arguments);
141
+ };
142
+
143
+ // Override scrollBy similarly
144
+ window.scrollBy = function(options) {
145
+ scrollCallCount++;
146
+ console.log('[SCROLL-DEBUG] scrollBy called', {
147
+ callCount: scrollCallCount,
148
+ options: typeof options === 'object' ? options : { x: arguments[0], y: arguments[1] },
149
+ scrollY: window.scrollY
150
+ });
151
+
152
+ // Create a copy of options to avoid modifying the original
153
+ if (typeof options === 'object' && options !== null) {
154
+ const modifiedOptions = { ...options };
155
+ // Add slight variance to scroll amount
156
+ if (modifiedOptions.top !== undefined) {
157
+ modifiedOptions.top += (Math.random() - 0.5) * 2;
158
+ }
159
+ if (modifiedOptions.left !== undefined) {
160
+ modifiedOptions.left += (Math.random() - 0.5) * 2;
161
+ }
162
+ return originalScrollBy.call(this, modifiedOptions);
163
+ }
164
+
165
+ return originalScrollBy.apply(this, arguments);
166
+ };
167
+
168
+ // Override scrollIntoView
169
+ Element.prototype.scrollIntoView = function(options) {
170
+ scrollCallCount++;
171
+ console.log('[SCROLL-DEBUG] scrollIntoView called', {
172
+ callCount: scrollCallCount,
173
+ element: this.tagName,
174
+ options
175
+ });
176
+ // Just pass through to original - don't break scrolling
177
+ return originalScrollIntoView.call(this, options);
178
+ };
179
+
180
+ console.log('[SCROLL-DEBUG] Scroll overrides installed');
181
+ };
182
+
183
+ // Simulate natural scroll momentum
184
+ const addScrollMomentum = () => {
185
+ let momentumId = null;
186
+ let currentVelocity = 0;
187
+ let wheelEventCount = 0;
188
+
189
+ console.log('[SCROLL-DEBUG] Setting up scroll momentum');
190
+
191
+ window.addEventListener('wheel', (event) => {
192
+ wheelEventCount++;
193
+ console.log('[SCROLL-DEBUG] Wheel event', {
194
+ count: wheelEventCount,
195
+ deltaY: event.deltaY,
196
+ scrollY: window.scrollY,
197
+ maxScrollY: document.documentElement.scrollHeight - window.innerHeight
198
+ });
199
+
200
+ // Calculate scroll velocity
201
+ const now = performance.now();
202
+ const timeDelta = now - lastScrollTime;
203
+
204
+ if (timeDelta > 0 && timeDelta < 500) {
205
+ currentVelocity = event.deltaY / timeDelta;
206
+ }
207
+
208
+ lastScrollTime = now;
209
+
210
+ // Cancel any existing momentum
211
+ if (momentumId) {
212
+ cancelAnimationFrame(momentumId);
213
+ }
214
+
215
+ // Start momentum scrolling
216
+ const applyMomentum = () => {
217
+ if (Math.abs(currentVelocity) < 0.1) {
218
+ console.log('[SCROLL-DEBUG] Momentum stopped (velocity too low)');
219
+ return;
220
+ }
221
+
222
+ currentVelocity *= 0.95; // Deceleration
223
+ window.scrollBy(0, currentVelocity * 16);
224
+
225
+ momentumId = requestAnimationFrame(applyMomentum);
226
+ };
227
+
228
+ // Only apply momentum on natural scroll end
229
+ // (not when user is actively scrolling)
230
+ clearTimeout(scrollTimeout);
231
+ scrollTimeout = setTimeout(() => {
232
+ if (Math.abs(currentVelocity) > 0.5) {
233
+ console.log('[SCROLL-DEBUG] Starting momentum scroll', { velocity: currentVelocity });
234
+ applyMomentum();
235
+ }
236
+ }, 100);
237
+ }, { passive: true });
238
+
239
+ console.log('[SCROLL-DEBUG] Wheel event listener attached');
240
+ };
241
+
242
+ // Track and enhance touch scroll events
243
+ const enhanceTouchScroll = () => {
244
+ let touchStartY = 0;
245
+ let touchStartTime = 0;
246
+
247
+ window.addEventListener('touchstart', (event) => {
248
+ if (event.touches.length === 1) {
249
+ touchStartY = event.touches[0].clientY;
250
+ touchStartTime = performance.now();
251
+ }
252
+ }, { passive: true });
253
+
254
+ window.addEventListener('touchend', (event) => {
255
+ const touchDuration = performance.now() - touchStartTime;
256
+ const touchEndY = event.changedTouches[0]?.clientY || touchStartY;
257
+ const distance = touchStartY - touchEndY;
258
+
259
+ // Calculate velocity for momentum
260
+ if (touchDuration > 0) {
261
+ scrollVelocity = distance / touchDuration;
262
+ }
263
+ }, { passive: true });
264
+ };
265
+
266
+ // Initialize scroll humanization
267
+ console.log('[SCROLL-DEBUG] Starting scroll humanization initialization');
268
+ trackScrollBehavior();
269
+ addScrollMomentum();
270
+ enhanceTouchScroll();
271
+ console.log('[SCROLL-DEBUG] Scroll humanization fully initialized');
272
+
273
+ // Log document ready state
274
+ console.log('[SCROLL-DEBUG] Document ready state:', document.readyState);
275
+ console.log('[SCROLL-DEBUG] Body scrollHeight:', document.body?.scrollHeight || 'N/A');
276
+ console.log('[SCROLL-DEBUG] Document scrollHeight:', document.documentElement?.scrollHeight || 'N/A');
277
+ console.log('[SCROLL-DEBUG] Window innerHeight:', window.innerHeight);
278
+ };
279
+
280
+ // Don't catch errors - let them bubble up so we can see them
281
+ humanizeScroll();
282
+
283
+ // Also log when DOM is ready
284
+ if (document.readyState === 'loading') {
285
+ document.addEventListener('DOMContentLoaded', () => {
286
+ console.log('[SCROLL-DEBUG] DOM loaded - scrollHeight:', document.documentElement?.scrollHeight || 'N/A');
287
+ });
288
+ }
289
+ })();`;
290
+ };
291
+ /**
292
+ * Helper sleep function
293
+ */
294
+ const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
295
+ /**
296
+ * CDP-level human-like scroll function
297
+ */
298
+ export const humanScroll = async (client, targetY, config = {}) => {
299
+ const inputClient = client;
300
+ // Get current scroll position
301
+ const result = await inputClient.Runtime.evaluate({
302
+ expression: 'window.scrollY',
303
+ returnByValue: true,
304
+ });
305
+ const startY = result.result.value;
306
+ // Generate scroll path
307
+ const path = generateScrollPath(startY, targetY, config);
308
+ // Get viewport dimensions for mouse position
309
+ const viewportResult = await inputClient.Runtime.evaluate({
310
+ expression: 'JSON.stringify({ width: window.innerWidth, height: window.innerHeight })',
311
+ returnByValue: true,
312
+ });
313
+ const viewport = JSON.parse(viewportResult.result.value);
314
+ // Position mouse in center of viewport
315
+ const mouseX = viewport.width / 2;
316
+ const mouseY = viewport.height / 2;
317
+ // Execute scroll path
318
+ let lastY = startY;
319
+ for (const point of path) {
320
+ const deltaY = point.y - lastY;
321
+ if (deltaY !== 0) {
322
+ // Dispatch wheel event
323
+ await inputClient.Input.dispatchMouseEvent({
324
+ type: 'mouseWheel',
325
+ x: mouseX,
326
+ y: mouseY,
327
+ deltaX: 0,
328
+ deltaY: deltaY,
329
+ });
330
+ }
331
+ lastY = point.y;
332
+ // Wait for delay
333
+ await sleep(point.delay);
334
+ }
335
+ };
336
+ /**
337
+ * Scroll to element with human-like behavior
338
+ */
339
+ export const humanScrollToElement = async (client, selector, config = {}) => {
340
+ const runtimeClient = client;
341
+ // Get element position
342
+ const result = await runtimeClient.Runtime.evaluate({
343
+ expression: `
344
+ (() => {
345
+ const element = document.querySelector('${selector.replace(/'/g, "\\'")}');
346
+ if (!element) return null;
347
+ const rect = element.getBoundingClientRect();
348
+ return {
349
+ top: rect.top + window.scrollY,
350
+ height: rect.height
351
+ };
352
+ })()
353
+ `,
354
+ returnByValue: true,
355
+ });
356
+ const elementInfo = result.result.value;
357
+ if (!elementInfo) {
358
+ throw new Error(`Element not found: ${selector}`);
359
+ }
360
+ // Calculate target scroll position (element centered in viewport)
361
+ const viewportResult = await runtimeClient.Runtime.evaluate({
362
+ expression: 'window.innerHeight',
363
+ returnByValue: true,
364
+ });
365
+ const viewportHeight = viewportResult.result.value;
366
+ const targetY = elementInfo.top - (viewportHeight / 2) + (elementInfo.height / 2);
367
+ await humanScroll(client, Math.max(0, targetY), config);
368
+ };
369
+ /**
370
+ * Setup scroll humanization at CDP level
371
+ */
372
+ export const setupScrollHumanization = async (client) => {
373
+ const runtimeClient = client;
374
+ // NOTE: Using addScriptToEvaluateOnNewDocument instead of Runtime.evaluate
375
+ // Runtime.evaluate is a CDP detection vector
376
+ await runtimeClient.Page.addScriptToEvaluateOnNewDocument({
377
+ source: createScrollHumanizationScript()
378
+ });
379
+ };
380
+ //# sourceMappingURL=scroll-humanization.js.map