jumpy-lion 0.1.6-beta.7 → 1.0.0-beta.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 (232) hide show
  1. package/README.md +1 -607
  2. package/browser/fonts/macos-bundle/40-macos-aliases.conf +515 -0
  3. package/browser/fonts/macos-bundle/README.md +24 -0
  4. package/browser/fonts/macos-bundle/install.sh +83 -0
  5. package/dist/browser-controller.d.ts +47 -4
  6. package/dist/browser-controller.d.ts.map +1 -1
  7. package/dist/browser-controller.js +219 -278
  8. package/dist/browser-controller.js.map +1 -1
  9. package/dist/browser-plugin.d.ts +82 -110
  10. package/dist/browser-plugin.d.ts.map +1 -1
  11. package/dist/browser-plugin.js +376 -379
  12. package/dist/browser-plugin.js.map +1 -1
  13. package/dist/browser-process/align-fingerprint-config.d.ts +36 -0
  14. package/dist/browser-process/align-fingerprint-config.d.ts.map +1 -0
  15. package/dist/browser-process/align-fingerprint-config.js +74 -0
  16. package/dist/browser-process/align-fingerprint-config.js.map +1 -0
  17. package/dist/browser-process/anti-detect-browser.d.ts +2 -2
  18. package/dist/browser-process/anti-detect-browser.js +7 -7
  19. package/dist/browser-process/anti-detect-config.d.ts +131 -2
  20. package/dist/browser-process/anti-detect-config.d.ts.map +1 -1
  21. package/dist/browser-process/anti-detect-config.js +337 -127
  22. package/dist/browser-process/anti-detect-config.js.map +1 -1
  23. package/dist/browser-process/browser.d.ts +25 -92
  24. package/dist/browser-process/browser.d.ts.map +1 -1
  25. package/dist/browser-process/browser.js +429 -73
  26. package/dist/browser-process/browser.js.map +1 -1
  27. package/dist/browser-process/fingerprint-config.d.ts +146 -0
  28. package/dist/browser-process/fingerprint-config.d.ts.map +1 -0
  29. package/dist/browser-process/fingerprint-config.js +308 -0
  30. package/dist/browser-process/fingerprint-config.js.map +1 -0
  31. package/dist/browser-process/get-chrome-executable.d.ts +6 -0
  32. package/dist/browser-process/get-chrome-executable.d.ts.map +1 -1
  33. package/dist/browser-process/get-chrome-executable.js +79 -4
  34. package/dist/browser-process/get-chrome-executable.js.map +1 -1
  35. package/dist/browser-process/gpu-family-profiles.d.ts +58 -0
  36. package/dist/browser-process/gpu-family-profiles.d.ts.map +1 -0
  37. package/dist/browser-process/gpu-family-profiles.js +480 -0
  38. package/dist/browser-process/gpu-family-profiles.js.map +1 -0
  39. package/dist/browser-process/launch-options.d.ts +301 -0
  40. package/dist/browser-process/launch-options.d.ts.map +1 -0
  41. package/dist/browser-process/launch-options.js +2 -0
  42. package/dist/browser-process/launch-options.js.map +1 -0
  43. package/dist/browser-process/port-allocator.d.ts +64 -0
  44. package/dist/browser-process/port-allocator.d.ts.map +1 -0
  45. package/dist/browser-process/port-allocator.js +198 -0
  46. package/dist/browser-process/port-allocator.js.map +1 -0
  47. package/dist/browser-process/process.d.ts +85 -0
  48. package/dist/browser-process/process.d.ts.map +1 -1
  49. package/dist/browser-process/process.js +235 -19
  50. package/dist/browser-process/process.js.map +1 -1
  51. package/dist/browser-process/signal-cleanup.d.ts +40 -0
  52. package/dist/browser-process/signal-cleanup.d.ts.map +1 -0
  53. package/dist/browser-process/signal-cleanup.js +105 -0
  54. package/dist/browser-process/signal-cleanup.js.map +1 -0
  55. package/dist/browser-process/widevine-cdm.d.ts +144 -0
  56. package/dist/browser-process/widevine-cdm.d.ts.map +1 -0
  57. package/dist/browser-process/widevine-cdm.js +298 -0
  58. package/dist/browser-process/widevine-cdm.js.map +1 -0
  59. package/dist/browser-profiles/chrome/populate-profile.d.ts.map +1 -1
  60. package/dist/browser-profiles/chrome/populate-profile.js +21 -22
  61. package/dist/browser-profiles/chrome/populate-profile.js.map +1 -1
  62. package/dist/connection/cdp-reconnection.d.ts +50 -0
  63. package/dist/connection/cdp-reconnection.d.ts.map +1 -0
  64. package/dist/connection/cdp-reconnection.js +75 -0
  65. package/dist/connection/cdp-reconnection.js.map +1 -0
  66. package/dist/connection/page-session.d.ts +114 -0
  67. package/dist/connection/page-session.d.ts.map +1 -0
  68. package/dist/connection/page-session.js +237 -0
  69. package/dist/connection/page-session.js.map +1 -0
  70. package/dist/connection/session-client.d.ts +34 -0
  71. package/dist/connection/session-client.d.ts.map +1 -0
  72. package/dist/connection/session-client.js +129 -0
  73. package/dist/connection/session-client.js.map +1 -0
  74. package/dist/crawler.d.ts +9 -88
  75. package/dist/crawler.d.ts.map +1 -1
  76. package/dist/crawler.js +157 -8
  77. package/dist/crawler.js.map +1 -1
  78. package/dist/fingerprinting/fingerprint-injector.d.ts +24 -114
  79. package/dist/fingerprinting/fingerprint-injector.d.ts.map +1 -1
  80. package/dist/fingerprinting/fingerprint-injector.js +305 -611
  81. package/dist/fingerprinting/fingerprint-injector.js.map +1 -1
  82. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.d.ts +1 -1
  83. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.d.ts.map +1 -1
  84. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.js +16 -14
  85. package/dist/fingerprinting/fingerprint-overrides/datadome-bypass.js.map +1 -1
  86. package/dist/fingerprinting/fingerprint-overrides/index.d.ts +6 -2
  87. package/dist/fingerprinting/fingerprint-overrides/index.d.ts.map +1 -1
  88. package/dist/fingerprinting/fingerprint-overrides/index.js +6 -2
  89. package/dist/fingerprinting/fingerprint-overrides/index.js.map +1 -1
  90. package/dist/fingerprinting/fingerprint-overrides/keyboard-humanization.d.ts +1 -1
  91. package/dist/fingerprinting/fingerprint-overrides/keyboard-humanization.js +4 -4
  92. package/dist/fingerprinting/fingerprint-overrides/keyboard-humanization.js.map +1 -1
  93. package/dist/fingerprinting/fingerprint-overrides/locale-spoofing.js +4 -4
  94. package/dist/fingerprinting/fingerprint-overrides/navigator-override.d.ts +18 -0
  95. package/dist/fingerprinting/fingerprint-overrides/navigator-override.d.ts.map +1 -0
  96. package/dist/fingerprinting/fingerprint-overrides/navigator-override.js +136 -0
  97. package/dist/fingerprinting/fingerprint-overrides/navigator-override.js.map +1 -0
  98. package/dist/fingerprinting/fingerprint-overrides/override.d.ts +151 -0
  99. package/dist/fingerprinting/fingerprint-overrides/override.d.ts.map +1 -0
  100. package/dist/fingerprinting/fingerprint-overrides/override.js +14 -0
  101. package/dist/fingerprinting/fingerprint-overrides/override.js.map +1 -0
  102. package/dist/fingerprinting/fingerprint-overrides/platform-consistency.d.ts.map +1 -1
  103. package/dist/fingerprinting/fingerprint-overrides/platform-consistency.js +46 -15
  104. package/dist/fingerprinting/fingerprint-overrides/platform-consistency.js.map +1 -1
  105. package/dist/fingerprinting/fingerprint-overrides/registry.d.ts +43 -0
  106. package/dist/fingerprinting/fingerprint-overrides/registry.d.ts.map +1 -0
  107. package/dist/fingerprinting/fingerprint-overrides/registry.js +342 -0
  108. package/dist/fingerprinting/fingerprint-overrides/registry.js.map +1 -0
  109. package/dist/fingerprinting/fingerprint-overrides/screen-override.d.ts +16 -0
  110. package/dist/fingerprinting/fingerprint-overrides/screen-override.d.ts.map +1 -0
  111. package/dist/fingerprinting/fingerprint-overrides/screen-override.js +175 -0
  112. package/dist/fingerprinting/fingerprint-overrides/screen-override.js.map +1 -0
  113. package/dist/fingerprinting/fingerprint-overrides/scroll-humanization.d.ts +1 -1
  114. package/dist/fingerprinting/fingerprint-overrides/scroll-humanization.js +4 -4
  115. package/dist/fingerprinting/fingerprint-overrides/scroll-humanization.js.map +1 -1
  116. package/dist/fingerprinting/fingerprint-overrides/stealth-script.d.ts.map +1 -1
  117. package/dist/fingerprinting/fingerprint-overrides/stealth-script.js +75 -9
  118. package/dist/fingerprinting/fingerprint-overrides/stealth-script.js.map +1 -1
  119. package/dist/fingerprinting/fingerprint-overrides/ua-ch.d.ts +1 -1
  120. package/dist/fingerprinting/fingerprint-overrides/ua-ch.d.ts.map +1 -1
  121. package/dist/fingerprinting/fingerprint-overrides/ua-ch.js +34 -20
  122. package/dist/fingerprinting/fingerprint-overrides/ua-ch.js.map +1 -1
  123. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.d.ts.map +1 -1
  124. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.js +25 -6
  125. package/dist/fingerprinting/fingerprint-overrides/webgl-spoofing.js.map +1 -1
  126. package/dist/fingerprinting/fingerprint-overrides/webrtc-spoofing.js +1 -1
  127. package/dist/fingerprinting/hardware-realism.d.ts +83 -0
  128. package/dist/fingerprinting/hardware-realism.d.ts.map +1 -0
  129. package/dist/fingerprinting/hardware-realism.js +156 -0
  130. package/dist/fingerprinting/hardware-realism.js.map +1 -0
  131. package/dist/fingerprinting/injection-planner.d.ts +133 -0
  132. package/dist/fingerprinting/injection-planner.d.ts.map +1 -0
  133. package/dist/fingerprinting/injection-planner.js +497 -0
  134. package/dist/fingerprinting/injection-planner.js.map +1 -0
  135. package/dist/fingerprinting/locale-resolver.d.ts +8 -1
  136. package/dist/fingerprinting/locale-resolver.d.ts.map +1 -1
  137. package/dist/fingerprinting/locale-resolver.js +26 -3
  138. package/dist/fingerprinting/locale-resolver.js.map +1 -1
  139. package/dist/fingerprinting/non-apify-fingerprint-generator.d.ts +4 -4
  140. package/dist/fingerprinting/non-apify-fingerprint-generator.d.ts.map +1 -1
  141. package/dist/fingerprinting/non-apify-fingerprint-generator.js +24 -58
  142. package/dist/fingerprinting/non-apify-fingerprint-generator.js.map +1 -1
  143. package/dist/fingerprinting/non-apify-profiles.json +10515 -8494
  144. package/dist/fingerprinting/os-consistency.d.ts +28 -0
  145. package/dist/fingerprinting/os-consistency.d.ts.map +1 -0
  146. package/dist/fingerprinting/os-consistency.js +45 -0
  147. package/dist/fingerprinting/os-consistency.js.map +1 -0
  148. package/dist/fingerprinting/profile-quality.d.ts +25 -0
  149. package/dist/fingerprinting/profile-quality.d.ts.map +1 -0
  150. package/dist/fingerprinting/profile-quality.js +310 -0
  151. package/dist/fingerprinting/profile-quality.js.map +1 -0
  152. package/dist/fingerprinting/profile-selector.d.ts +102 -0
  153. package/dist/fingerprinting/profile-selector.d.ts.map +1 -0
  154. package/dist/fingerprinting/profile-selector.js +168 -0
  155. package/dist/fingerprinting/profile-selector.js.map +1 -0
  156. package/dist/fingerprinting/ua-alignment.d.ts +83 -0
  157. package/dist/fingerprinting/ua-alignment.d.ts.map +1 -0
  158. package/dist/fingerprinting/ua-alignment.js +197 -0
  159. package/dist/fingerprinting/ua-alignment.js.map +1 -0
  160. package/dist/fingerprinting/ua-ch-brands.d.ts +88 -0
  161. package/dist/fingerprinting/ua-ch-brands.d.ts.map +1 -0
  162. package/dist/fingerprinting/ua-ch-brands.js +174 -0
  163. package/dist/fingerprinting/ua-ch-brands.js.map +1 -0
  164. package/dist/index.d.ts +5 -0
  165. package/dist/index.d.ts.map +1 -1
  166. package/dist/index.js +6 -0
  167. package/dist/index.js.map +1 -1
  168. package/dist/input/dropdown-selector.d.ts +90 -0
  169. package/dist/input/dropdown-selector.d.ts.map +1 -0
  170. package/dist/input/dropdown-selector.js +394 -0
  171. package/dist/input/dropdown-selector.js.map +1 -0
  172. package/dist/input/element-target.d.ts +152 -0
  173. package/dist/input/element-target.d.ts.map +1 -0
  174. package/dist/input/element-target.js +461 -0
  175. package/dist/input/element-target.js.map +1 -0
  176. package/dist/input/input-emulator.d.ts +85 -0
  177. package/dist/input/input-emulator.d.ts.map +1 -0
  178. package/dist/input/input-emulator.js +325 -0
  179. package/dist/input/input-emulator.js.map +1 -0
  180. package/dist/input/input-transport.d.ts +60 -0
  181. package/dist/input/input-transport.d.ts.map +1 -0
  182. package/dist/input/input-transport.js +28 -0
  183. package/dist/input/input-transport.js.map +1 -0
  184. package/dist/input/recording-transport.d.ts +32 -0
  185. package/dist/input/recording-transport.d.ts.map +1 -0
  186. package/dist/input/recording-transport.js +43 -0
  187. package/dist/input/recording-transport.js.map +1 -0
  188. package/dist/keyboard-layout.d.ts +2 -2
  189. package/dist/keyboard-layout.js +2 -2
  190. package/dist/navigation/page-navigation.d.ts +67 -0
  191. package/dist/navigation/page-navigation.d.ts.map +1 -0
  192. package/dist/navigation/page-navigation.js +122 -0
  193. package/dist/navigation/page-navigation.js.map +1 -0
  194. package/dist/network/network-watch.d.ts +110 -0
  195. package/dist/network/network-watch.d.ts.map +1 -0
  196. package/dist/network/network-watch.js +223 -0
  197. package/dist/network/network-watch.js.map +1 -0
  198. package/dist/page.d.ts +118 -104
  199. package/dist/page.d.ts.map +1 -1
  200. package/dist/page.js +311 -1130
  201. package/dist/page.js.map +1 -1
  202. package/dist/session/inject-hook.d.ts +24 -0
  203. package/dist/session/inject-hook.d.ts.map +1 -0
  204. package/dist/session/inject-hook.js +80 -0
  205. package/dist/session/inject-hook.js.map +1 -0
  206. package/dist/session/save.d.ts +21 -0
  207. package/dist/session/save.d.ts.map +1 -0
  208. package/dist/session/save.js +163 -0
  209. package/dist/session/save.js.map +1 -0
  210. package/dist/session/tar-data-dir.d.ts +18 -0
  211. package/dist/session/tar-data-dir.d.ts.map +1 -0
  212. package/dist/session/tar-data-dir.js +105 -0
  213. package/dist/session/tar-data-dir.js.map +1 -0
  214. package/dist/session/types.d.ts +80 -0
  215. package/dist/session/types.d.ts.map +1 -0
  216. package/dist/session/types.js +29 -0
  217. package/dist/session/types.js.map +1 -0
  218. package/dist/session-profile.d.ts +102 -0
  219. package/dist/session-profile.d.ts.map +1 -0
  220. package/dist/session-profile.js +163 -0
  221. package/dist/session-profile.js.map +1 -0
  222. package/dist/tsconfig.build.tsbuildinfo +1 -1
  223. package/package.json +17 -6
  224. package/scripts/postinstall.cjs +58 -0
  225. package/dist/fingerprinting/custom-fingerprint-injector.d.ts +0 -87
  226. package/dist/fingerprinting/custom-fingerprint-injector.d.ts.map +0 -1
  227. package/dist/fingerprinting/custom-fingerprint-injector.js +0 -342
  228. package/dist/fingerprinting/custom-fingerprint-injector.js.map +0 -1
  229. package/dist/launcher-wrap.d.ts +0 -10
  230. package/dist/launcher-wrap.d.ts.map +0 -1
  231. package/dist/launcher-wrap.js +0 -11
  232. package/dist/launcher-wrap.js.map +0 -1
@@ -0,0 +1,301 @@
1
+ import type { FingerprintConfigJson } from './anti-detect-config.js';
2
+ import type { ResolvedLocale } from '../fingerprinting/locale-resolver.js';
3
+ /**
4
+ * Fingerprint-GENERATION inputs - mirrors the subset of Crawlee's
5
+ * `browserPoolOptions.fingerprintOptions.fingerprintGeneratorOptions`
6
+ * (from `fingerprint-generator`) that cdp-crawler forwards. This selects
7
+ * *which* fingerprint identity to synthesize; it is a wholly separate concept
8
+ * from `FingerprintOptions` below (which spoof surfaces to enforce and how).
9
+ * See issue #80 - the two must not be conflated.
10
+ */
11
+ export interface FingerprintGeneratorOptions {
12
+ /** Operating systems to generate fingerprints for (e.g., ["windows"], ["macos"], ["linux"]) */
13
+ operatingSystems?: string[];
14
+ /** Devices to generate fingerprints for (e.g., ["desktop"], ["mobile"]) */
15
+ devices?: string[];
16
+ /** Browsers to generate fingerprints for (e.g., ["chrome"], ["firefox"]) */
17
+ browsers?: string[];
18
+ /** Locales to generate fingerprints for (e.g., ["en-US"], ["it-IT"]) */
19
+ locales?: string[];
20
+ }
21
+ /**
22
+ * Humanization options for simulating realistic user behavior.
23
+ * All options are disabled by default for performance.
24
+ */
25
+ export interface HumanizationOptions {
26
+ /** Enable mouse movement humanization. Default: false */
27
+ mouse?: boolean;
28
+ /** Enable keyboard humanization. Default: false */
29
+ keyboard?: boolean;
30
+ /** Enable scroll humanization. Default: false */
31
+ scroll?: boolean;
32
+ }
33
+ /**
34
+ * Fingerprint-spoofing options shared by the JS override pipeline
35
+ * (CdpFingerprintInjector) and the native-stealth (C++) launch path.
36
+ */
37
+ export interface FingerprintOptions {
38
+ /**
39
+ * Legacy nested location for the top-level `useNativeStealth` flag.
40
+ * Normalized to `launchOptions.useNativeStealth` by resolveUseNativeStealth()
41
+ * in session-profile.ts before launch; prefer the top-level field.
42
+ */
43
+ useNativeStealth?: boolean;
44
+ enableAdvancedStealth?: boolean;
45
+ bypassRuntimeEnable?: boolean;
46
+ spoofWebGL?: boolean;
47
+ spoofAudioContext?: boolean;
48
+ spoofClientRects?: boolean;
49
+ maskAutomationFlags?: boolean;
50
+ useFingerprintDefaults?: boolean;
51
+ platform?: 'Win32' | 'MacIntel' | 'Linux x86_64';
52
+ spoofFonts?: boolean;
53
+ spoofPerformance?: boolean;
54
+ spoofLocale?: boolean;
55
+ detectTimezone?: boolean;
56
+ useExperimentalFingerprints?: boolean;
57
+ /**
58
+ * BCP-47 locale tag (e.g. 'ko-KR', 'de-DE'). One flag that coherently drives
59
+ * navigator.language(s), Accept-Language header, Intl defaults, currency
60
+ * symbol, date/number formatting, and timezone (derived from region).
61
+ * When unset, falls back to proxy-country lookup → fingerprint language → 'en-US'.
62
+ */
63
+ locale?: string;
64
+ /** Explicit IANA timezone (e.g. 'Asia/Seoul'). Overrides locale-derived timezone. */
65
+ timezone?: string;
66
+ /** Explicit Accept-Language header (e.g. 'ko-KR,ko;q=0.9'). Overrides locale-derived list. */
67
+ languages?: string;
68
+ bypassCDPDetection?: boolean;
69
+ spoofStorage?: boolean;
70
+ spoofTiming?: boolean;
71
+ enableDataDomeBypass?: boolean;
72
+ /** WebRTC policy inside page scripts. Default: 'spoof'. */
73
+ webRtcPolicy?: 'spoof' | 'disable';
74
+ /** Humanization options (all disabled by default) */
75
+ humanization?: HumanizationOptions;
76
+ /** Enable debug logging in browser console. Default: true for debugging */
77
+ debug?: boolean;
78
+ /**
79
+ * Use real Chrome device profiles (Camoufox-inspired) instead of the
80
+ * Apify fingerprint-generator statistical model. Profiles are sampled from
81
+ * a bundled database of real devices where every property - navigator,
82
+ * screen, GPU, UA-CH - was measured on the same physical hardware,
83
+ * guaranteeing cross-property consistency. If the `camoufox` Python package
84
+ * is installed and `preferCamoufox` is true, Firefox device-level data is
85
+ * extracted and mapped to Chrome values.
86
+ * Default: false
87
+ */
88
+ useNonApifyFingerprints?: boolean;
89
+ /**
90
+ * Explicit fingerprint seed key for tests / A-B harvest comparisons.
91
+ * Production derives the seed from the proxy URL's `session-X` token;
92
+ * this field lets harvest runs on different hosts (Mac vs Linux Docker)
93
+ * hit the SAME bundled profile without needing a fake proxy.
94
+ */
95
+ seedKey?: string;
96
+ /**
97
+ * Force WebGL to render through the in-process emulated WebGraphics
98
+ * Context3DProvider instead of relying on a real GPU. Default: false.
99
+ *
100
+ * Why this matters on Apify-linux Docker containers:
101
+ * The Docker image has no GPU. The Chromium GPU process therefore
102
+ * crashes during init (vkCreateInstance: no drivers, no compositor
103
+ * adapter, "Exiting GPU process due to errors during initialization"),
104
+ * which transitively kills WebGL context creation in the renderer:
105
+ *
106
+ * [...]ERROR:gpu/command_buffer/.../gles2_cmd_decoder_passthrough.cc:1073]
107
+ * Automatic fallback to software WebGL has been deprecated.
108
+ * Please use the --enable-unsafe-swiftshader flag to opt in to
109
+ * lower security guarantees for trusted content.
110
+ *
111
+ * Chrome ≥126 removed the implicit fall-back-to-SwiftShader behaviour
112
+ * that used to mask a missing GPU. Without an explicit switch,
113
+ * `canvas.getContext('webgl')` returns null on a GPU-less container.
114
+ * Real Chrome on a real desktop ALWAYS exposes WebGL, so a missing
115
+ * WebGL context is itself a strong bot tell.
116
+ *
117
+ * What setting this to true does:
118
+ * Pushes the anti-detect binary's bespoke `--force-webgl-emulation`
119
+ * Chromium command-line switch. The switch is declared in
120
+ * chrome/common/chrome_switches.{h,cc} and propagated to renderer/
121
+ * GPU child processes via the kCommonSwitchNames list in
122
+ * chrome/browser/chrome_content_browser_client.cc. The renderer-side
123
+ * factory hook at third_party/blink/renderer/modules/webgl/
124
+ * webgl_rendering_context_base.cc::CreateContextProviderInternal
125
+ * reads the switch + FingerprintConfig::IsLoaded() and, when both
126
+ * are true, instantiates the in-process
127
+ * EmulatedWebGraphicsContext3DProvider instead of asking the GPU
128
+ * process for a command buffer. The provider returns a non-null
129
+ * WebGLRenderingContext whose getParameter values come from
130
+ * FingerprintConfig (vendor/renderer/max texture size) and a
131
+ * bundled Mac M1 baseline (other queryable params), and whose
132
+ * readPixels output is a deterministic xoshiro256** noise pattern
133
+ * seeded from FingerprintConfig.seed (plus a recorded baseline
134
+ * pixel buffer for known fingerprint probe shaders).
135
+ *
136
+ * The C++ provider ALSO acts as a fallback (without this switch)
137
+ * when the upstream real-GL / SwiftShader path returns null - set
138
+ * this flag to TRUE only when you want to skip real-GL entirely on
139
+ * hosts where it might otherwise succeed but degrade unpredictably
140
+ * (e.g. Apify Linux containers).
141
+ */
142
+ forceEmulateWebgl?: boolean;
143
+ }
144
+ /**
145
+ * Advanced options for the JS fingerprint-override pipeline (issue #80).
146
+ *
147
+ * These configure the JS injector's per-surface override modules. They belong
148
+ * under `stealth.overrides` when the `js` engine is selected - see
149
+ * {@link StealthOptions}. They are meaningless on the native engine (the C++
150
+ * binary owns every surface), which is why the discriminated union makes them
151
+ * settable ONLY under `engine: 'js'`.
152
+ *
153
+ * Keys are the community-canonical fingerprint-surface names (canvas/webgl/audio/
154
+ * clientRects/fonts/webrtc/… - the vocabulary used by fingerprintjs, CreepJS,
155
+ * puppeteer-extra) rather than ad-hoc `spoofX`/`maskX`/`bypassX` verbs. Each maps
156
+ * 1:1 onto an entry in the internal override registry. All spoof surfaces default
157
+ * to ON (opt-out); `webrtc` defaults to `'spoof'`; `dataDomeBypass` defaults OFF.
158
+ *
159
+ * Identity/locale/routing knobs (`platform`, `locale`, `useNonApifyFingerprints`,
160
+ * …) are intentionally NOT part of this group. The legacy per-surface toggles on
161
+ * `fingerprintOptions` (`spoofWebGL`, `maskAutomationFlags`, …) remain honoured as
162
+ * a deprecated alias.
163
+ */
164
+ export interface JsOverrideOptions {
165
+ /** Master gate for the advanced spoof set. Default: true. */
166
+ advancedStealth?: boolean;
167
+ /** WebGL `getParameter` / debug-renderer spoofing. Default: true. */
168
+ webgl?: boolean;
169
+ /** AudioContext fingerprint noise. Default: true. */
170
+ audio?: boolean;
171
+ /** `getBoundingClientRect` sub-pixel jitter. Default: true. */
172
+ clientRects?: boolean;
173
+ /** Font-enumeration spoofing. Default: true. */
174
+ fonts?: boolean;
175
+ /** `performance.now` shaping. Default: true. */
176
+ performance?: boolean;
177
+ /** `Intl` / locale formatting consistency. Default: true. */
178
+ locale?: boolean;
179
+ /** Storage-quota consistency. Default: true. */
180
+ storage?: boolean;
181
+ /** `Date.now` alignment. Default: true. */
182
+ timing?: boolean;
183
+ /** CDP-detection bypass (iframe/eval/sourceURL hiding). Default: true. */
184
+ cdpDetection?: boolean;
185
+ /** navigator.webdriver removal + automation-artifact masking. Default: true. */
186
+ automation?: boolean;
187
+ /** WebRTC handling. Default: `'spoof'`. */
188
+ webrtc?: 'spoof' | 'disable';
189
+ /** DataDome-specific bypass (JS challenges, proof-of-work). Default: false. */
190
+ dataDomeBypass?: boolean;
191
+ /** Human-like input behavior (mouse/keyboard/scroll). All off by default. */
192
+ humanization?: HumanizationOptions;
193
+ /**
194
+ * Use the generated fingerprint's values instead of hardcoded defaults for
195
+ * navigator/WebGL/UA-CH. Default: true for synthetic profiles.
196
+ */
197
+ useFingerprintDefaults?: boolean;
198
+ /** Verbose in-page debug logging. Default: false. */
199
+ debug?: boolean;
200
+ }
201
+ /**
202
+ * The fingerprint-enforcement engine - a mutually-exclusive choice (issue #80).
203
+ *
204
+ * Native stealth (the C++ anti-detect binary) and the JS override pipeline are
205
+ * two engines that cannot both run: under native stealth the JS bundle is
206
+ * skipped entirely, so JS spoof toggles are silently inert. Modelling the choice
207
+ * as a discriminated union makes that exclusivity explicit - `overrides` is only
208
+ * settable under `engine: 'js'`, so it is a *type error* to configure JS spoof
209
+ * toggles while the native engine is selected.
210
+ *
211
+ * Canonical selector for `launchOptions.stealth`. The legacy `useNativeStealth`
212
+ * boolean (+ its nested/root mirrors) and the JS toggles on `fingerprintOptions`
213
+ * are still honoured as deprecated aliases; `stealth` wins when set.
214
+ */
215
+ export type StealthOptions = {
216
+ /** C++ anti-detect binary owns every fingerprint surface; no JS overrides apply. */
217
+ engine: 'native';
218
+ } | {
219
+ /** JS fingerprint-override injection pipeline (stock Chrome). */
220
+ engine: 'js';
221
+ /** Advanced spoof/humanization toggles - only meaningful on this engine. */
222
+ overrides?: JsOverrideOptions;
223
+ };
224
+ /**
225
+ * Launch options shared by the plugin layer (CDPBrowserPlugin) and the
226
+ * process layer (browser-process/browser.ts). Each layer extends this with
227
+ * its own fields - the plugin adds Crawlee-facing fields (browserType,
228
+ * proxyUrl, sessionBundle, …); the process layer adds spawn-time fields
229
+ * (anonymizedProxyUrl, debuggingPort, …).
230
+ */
231
+ export interface BaseLaunchBrowserOptions {
232
+ /**
233
+ * The fingerprint-enforcement engine and its config (issue #80). Selecting
234
+ * `{ engine: 'js', overrides: { … } }` is the canonical, discoverable home
235
+ * for the JS spoof/humanization toggles; `{ engine: 'native' }` selects the
236
+ * C++ binary and makes those toggles a type error. Wins over the deprecated
237
+ * `useNativeStealth` boolean and the JS toggles on `fingerprintOptions`.
238
+ */
239
+ stealth?: StealthOptions;
240
+ ignoreHttpsErrors?: boolean;
241
+ headless?: boolean;
242
+ executablePath?: string;
243
+ useExperimentalFingerprints?: boolean;
244
+ /**
245
+ * Use the C++ anti-detect browser patches (Cromite-based custom binary)
246
+ * instead of the JS fingerprint override pipeline. When true, the plugin
247
+ * auto-resolves the binary installed by postinstall.js unless an explicit
248
+ * `executablePath` (or ANTI_DETECT_CHROME_PATH) pins one, and the entire
249
+ * JS injection bundle is skipped - C++ patches handle all fingerprinting.
250
+ * If the binary is not an anti-detect build, the process layer falls back
251
+ * to plain stealth args for system Chrome.
252
+ * Default: false
253
+ */
254
+ useNativeStealth?: boolean;
255
+ /** Whether to start the browser maximized and fullscreen. Default: true */
256
+ maximizeWindow?: boolean;
257
+ /** Window width in pixels. Default: 1920 */
258
+ windowWidth?: number;
259
+ /** Window height in pixels. Default: 1080 */
260
+ windowHeight?: number;
261
+ /**
262
+ * Reuse a specific Chrome user data directory across runs.
263
+ * When provided, this directory is preserved by default.
264
+ */
265
+ userDataDir?: string;
266
+ /**
267
+ * Force keeping or cleaning the profile directory on close.
268
+ * Defaults to true for temporary profiles and false for custom userDataDir.
269
+ */
270
+ keepUserDataDir?: boolean;
271
+ /**
272
+ * DNS-over-HTTPS endpoint template, for example:
273
+ * https://cloudflare-dns.com/dns-query
274
+ */
275
+ dnsOverHttpsServer?: string;
276
+ /** Chromium secure DNS mode. Default: 'secure' when dnsOverHttpsServer is set. */
277
+ secureDnsMode?: 'off' | 'automatic' | 'secure';
278
+ /**
279
+ * WebRTC IP handling policy. Recommended stealth value:
280
+ * disable_non_proxied_udp
281
+ */
282
+ webrtcIpHandlingPolicy?: 'default' | 'default_public_interface_only' | 'default_public_and_private_interfaces' | 'disable_non_proxied_udp';
283
+ fingerprintOptions?: FingerprintOptions;
284
+ /**
285
+ * Pre-generated platform-overrides JSON to pass via --blink-platform-overrides-file
286
+ * to the anti-detect browser. When provided, this overrides the static
287
+ * default_fingerprint.json so that each browser instance gets unique C++-level
288
+ * platform values (GPU, screen, CPU count, device memory) derived from the real
289
+ * device profile.
290
+ */
291
+ fingerprintConfig?: FingerprintConfigJson;
292
+ /**
293
+ * Pre-resolved locale triple from `resolveLocale()`. Populated in browser-plugin
294
+ * before launch so the native-stealth launch args (`--lang`,
295
+ * `--fingerprint-accept-language`, LANG/LC_ALL env vars) and the CDP-path
296
+ * injector read the same values and stay coherent. Consumers should prefer
297
+ * this over re-deriving from fingerprintOptions.
298
+ */
299
+ resolvedLocale?: ResolvedLocale;
300
+ }
301
+ //# sourceMappingURL=launch-options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launch-options.d.ts","sourceRoot":"","sources":["../../src/browser-process/launch-options.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=launch-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launch-options.js","sourceRoot":"","sources":["../../src/browser-process/launch-options.ts"],"names":[],"mappings":""}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * PortAllocator - owns the Chrome debugging-port pool.
3
+ *
4
+ * Interface is two methods: `acquire()` / `release(port)`. The implementation
5
+ * owns the range, acquisition serialization, the wraparound scan, the
6
+ * probe-busy quarantine, and the stale-port sweep. The OS socket probe sits
7
+ * behind the narrow `PortProbe` seam: real socket adapter in production,
8
+ * scripted adapter in tests.
9
+ */
10
+ export interface PortProbe {
11
+ /** True when the port can be bound on 127.0.0.1 right now. */
12
+ isFree(port: number): Promise<boolean>;
13
+ }
14
+ /**
15
+ * Production adapter: try to bind a throwaway server on 127.0.0.1.
16
+ * Resolves false on bind error or after a 2 s safety timeout.
17
+ */
18
+ export declare const socketPortProbe: PortProbe;
19
+ export interface PortAllocatorOptions {
20
+ min?: number;
21
+ max?: number;
22
+ probe?: PortProbe;
23
+ /** How long a probe-busy port stays quarantined before it may be retried. */
24
+ quarantineMs?: number;
25
+ /**
26
+ * Grace period after `acquire()` during which the stale sweep will NOT
27
+ * reclaim a reserved port, even though the probe reports it free. Covers the
28
+ * window between handing a port out and Chrome actually binding it.
29
+ */
30
+ launchGraceMs?: number;
31
+ /** Injectable clock (tests drive it); defaults to `Date.now`. */
32
+ now?: () => number;
33
+ }
34
+ export declare class PortAllocator {
35
+ private readonly min;
36
+ private readonly max;
37
+ private readonly probe;
38
+ private readonly quarantineMs;
39
+ private readonly launchGraceMs;
40
+ private readonly now;
41
+ private readonly usedPorts;
42
+ private lastAssignedPort;
43
+ /** Serializes acquire() calls - concurrent launches never race the scan. */
44
+ private acquireChain;
45
+ constructor(options?: PortAllocatorOptions);
46
+ acquire(): Promise<number>;
47
+ release(port: number): void;
48
+ private _acquireSerialized;
49
+ /**
50
+ * Drop tracked ports whose owner has since exited (probe binds OK).
51
+ * A crash path that never called release() would otherwise leak the slot
52
+ * forever.
53
+ *
54
+ * Reserved ports are protected for `launchGraceMs` after acquisition: a
55
+ * port is handed out BEFORE Chrome starts, so between `acquire()` and the
56
+ * browser binding its debug socket the probe legitimately reports the port
57
+ * free. Sweeping there un-tracked a port whose browser was still launching
58
+ * and handed the same port to a second browser - one of the two then failed
59
+ * to bind. Quarantine entries carry no such window (they were never ours),
60
+ * so they stay immediately reclaimable.
61
+ */
62
+ private _sweepStalePorts;
63
+ }
64
+ //# sourceMappingURL=port-allocator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"port-allocator.d.ts","sourceRoot":"","sources":["../../src/browser-process/port-allocator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,WAAW,SAAS;IACtB,8DAA8D;IAC9D,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1C;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,SA+B7B,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB;AAcD,qBAAa,aAAa;IACtB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IAEnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgC;IAC1D,OAAO,CAAC,gBAAgB,CAAS;IACjC,4EAA4E;IAC5E,OAAO,CAAC,YAAY,CAAuC;gBAE/C,OAAO,GAAE,oBAAyB;IAUxC,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAShC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;YAWb,kBAAkB;IAgDhC;;;;;;;;;;;;OAYG;YACW,gBAAgB;CAcjC"}
@@ -0,0 +1,198 @@
1
+ /**
2
+ * PortAllocator - owns the Chrome debugging-port pool.
3
+ *
4
+ * Interface is two methods: `acquire()` / `release(port)`. The implementation
5
+ * owns the range, acquisition serialization, the wraparound scan, the
6
+ * probe-busy quarantine, and the stale-port sweep. The OS socket probe sits
7
+ * behind the narrow `PortProbe` seam: real socket adapter in production,
8
+ * scripted adapter in tests.
9
+ */
10
+ import net from 'node:net';
11
+ import { log } from 'crawlee';
12
+ /**
13
+ * Production adapter: try to bind a throwaway server on 127.0.0.1.
14
+ * Resolves false on bind error or after a 2 s safety timeout.
15
+ */
16
+ export const socketPortProbe = {
17
+ async isFree(port) {
18
+ return new Promise((resolve) => {
19
+ const server = net.createServer();
20
+ let resolved = false;
21
+ const finish = (result) => {
22
+ if (resolved)
23
+ return;
24
+ resolved = true;
25
+ try {
26
+ server.close();
27
+ }
28
+ catch {
29
+ // Ignore errors during cleanup
30
+ }
31
+ resolve(result);
32
+ };
33
+ server.once('error', () => finish(false));
34
+ server.once('listening', () => finish(true));
35
+ // Safety timeout to prevent hanging
36
+ const timer = setTimeout(() => finish(false), 2000);
37
+ timer.unref?.();
38
+ try {
39
+ server.listen(port, '127.0.0.1');
40
+ }
41
+ catch {
42
+ finish(false);
43
+ }
44
+ });
45
+ },
46
+ };
47
+ export class PortAllocator {
48
+ constructor(options = {}) {
49
+ Object.defineProperty(this, "min", {
50
+ enumerable: true,
51
+ configurable: true,
52
+ writable: true,
53
+ value: void 0
54
+ });
55
+ Object.defineProperty(this, "max", {
56
+ enumerable: true,
57
+ configurable: true,
58
+ writable: true,
59
+ value: void 0
60
+ });
61
+ Object.defineProperty(this, "probe", {
62
+ enumerable: true,
63
+ configurable: true,
64
+ writable: true,
65
+ value: void 0
66
+ });
67
+ Object.defineProperty(this, "quarantineMs", {
68
+ enumerable: true,
69
+ configurable: true,
70
+ writable: true,
71
+ value: void 0
72
+ });
73
+ Object.defineProperty(this, "launchGraceMs", {
74
+ enumerable: true,
75
+ configurable: true,
76
+ writable: true,
77
+ value: void 0
78
+ });
79
+ Object.defineProperty(this, "now", {
80
+ enumerable: true,
81
+ configurable: true,
82
+ writable: true,
83
+ value: void 0
84
+ });
85
+ Object.defineProperty(this, "usedPorts", {
86
+ enumerable: true,
87
+ configurable: true,
88
+ writable: true,
89
+ value: new Map()
90
+ });
91
+ Object.defineProperty(this, "lastAssignedPort", {
92
+ enumerable: true,
93
+ configurable: true,
94
+ writable: true,
95
+ value: void 0
96
+ });
97
+ /** Serializes acquire() calls - concurrent launches never race the scan. */
98
+ Object.defineProperty(this, "acquireChain", {
99
+ enumerable: true,
100
+ configurable: true,
101
+ writable: true,
102
+ value: Promise.resolve()
103
+ });
104
+ this.min = options.min ?? 9200;
105
+ this.max = options.max ?? 9600;
106
+ this.probe = options.probe ?? socketPortProbe;
107
+ this.quarantineMs = options.quarantineMs ?? 5000;
108
+ this.launchGraceMs = options.launchGraceMs ?? 15000;
109
+ this.now = options.now ?? Date.now;
110
+ this.lastAssignedPort = this.min - 1;
111
+ }
112
+ async acquire() {
113
+ // Chain onto the previous acquire so the scan below never interleaves
114
+ // with another caller's - the replacement for the old static spin-lock.
115
+ const result = this.acquireChain.then(async () => this._acquireSerialized());
116
+ // Keep the chain alive even when an acquire rejects (pool exhausted).
117
+ this.acquireChain = result.catch(() => { });
118
+ return result;
119
+ }
120
+ release(port) {
121
+ // Idempotent: the browser close/error/disconnect handlers can all fire
122
+ // for one instance.
123
+ if (this.usedPorts.has(port)) {
124
+ this.usedPorts.delete(port);
125
+ log.debug(`Released port ${port} back to pool. Used ports: ${this.usedPorts.size}/${this.max - this.min + 1}`);
126
+ }
127
+ else {
128
+ log.debug(`Attempted to release port ${port} that was not in use`);
129
+ }
130
+ }
131
+ async _acquireSerialized() {
132
+ const maxAttempts = this.max - this.min + 1;
133
+ for (let attempts = 0; attempts < maxAttempts; attempts++) {
134
+ // Increment the last assigned port, wrapping around if necessary
135
+ this.lastAssignedPort++;
136
+ if (this.lastAssignedPort > this.max) {
137
+ this.lastAssignedPort = this.min;
138
+ log.debug('Port range wrapped around, starting from beginning');
139
+ }
140
+ const candidatePort = this.lastAssignedPort;
141
+ // Skip if port is already tracked as in use
142
+ if (this.usedPorts.has(candidatePort)) {
143
+ continue;
144
+ }
145
+ if (await this.probe.isFree(candidatePort)) {
146
+ this.usedPorts.set(candidatePort, { at: this.now(), quarantined: false });
147
+ log.debug(`Reserved port ${candidatePort} for browser instance (attempt ${attempts + 1})`);
148
+ return candidatePort;
149
+ }
150
+ // Probe says busy (something outside the pool holds it) -
151
+ // quarantine so the scan doesn't retry it immediately.
152
+ this.usedPorts.set(candidatePort, { at: this.now(), quarantined: true });
153
+ const timer = setTimeout(() => {
154
+ this.usedPorts.delete(candidatePort);
155
+ }, this.quarantineMs);
156
+ timer.unref?.();
157
+ }
158
+ // Every port is tracked or probe-busy: sweep stale entries and rescan.
159
+ log.warning(`All ports in range ${this.min}-${this.max} are in use. Attempting cleanup.`);
160
+ await this._sweepStalePorts();
161
+ for (let port = this.min; port <= this.max; port++) {
162
+ if (!this.usedPorts.has(port) && await this.probe.isFree(port)) {
163
+ this.usedPorts.set(port, { at: this.now(), quarantined: false });
164
+ log.debug(`Reserved port ${port} after cleanup`);
165
+ return port;
166
+ }
167
+ }
168
+ throw new Error(`No available ports found in the configured range ${this.min}-${this.max} after maximum attempts and cleanup`);
169
+ }
170
+ /**
171
+ * Drop tracked ports whose owner has since exited (probe binds OK).
172
+ * A crash path that never called release() would otherwise leak the slot
173
+ * forever.
174
+ *
175
+ * Reserved ports are protected for `launchGraceMs` after acquisition: a
176
+ * port is handed out BEFORE Chrome starts, so between `acquire()` and the
177
+ * browser binding its debug socket the probe legitimately reports the port
178
+ * free. Sweeping there un-tracked a port whose browser was still launching
179
+ * and handed the same port to a second browser - one of the two then failed
180
+ * to bind. Quarantine entries carry no such window (they were never ours),
181
+ * so they stay immediately reclaimable.
182
+ */
183
+ async _sweepStalePorts() {
184
+ log.debug('Cleaning up stale ports');
185
+ const now = this.now();
186
+ for (const [port, lease] of Array.from(this.usedPorts)) {
187
+ if (!lease.quarantined && now - lease.at < this.launchGraceMs) {
188
+ log.debug(`Skipping port ${port} - still inside the ${this.launchGraceMs}ms launch grace window`);
189
+ continue;
190
+ }
191
+ if (await this.probe.isFree(port)) {
192
+ this.usedPorts.delete(port);
193
+ log.debug(`Cleaned up stale port ${port}`);
194
+ }
195
+ }
196
+ }
197
+ }
198
+ //# sourceMappingURL=port-allocator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"port-allocator.js","sourceRoot":"","sources":["../../src/browser-process/port-allocator.ts"],"names":[],"mappings":"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"}