browserclaw 0.12.2 → 0.12.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -721,12 +721,17 @@ interface PinnedHostname {
721
721
  */
722
722
  declare class CrawlPage {
723
723
  private readonly cdpUrl;
724
- private readonly targetId;
724
+ private _targetId;
725
725
  private readonly ssrfPolicy;
726
726
  /** @internal */
727
727
  constructor(cdpUrl: string, targetId: string, ssrfPolicy?: SsrfPolicy);
728
728
  /** The CDP target ID for this page. Use this to identify the page in multi-tab scenarios. */
729
729
  get id(): string;
730
+ /**
731
+ * Refresh the target ID by re-resolving the page from the browser.
732
+ * Useful after reconnection when the old target ID may be stale.
733
+ */
734
+ refreshTargetId(): Promise<string>;
730
735
  /**
731
736
  * Take an AI-readable snapshot of the page.
732
737
  *
@@ -1957,6 +1962,7 @@ declare function forceDisconnectPlaywrightConnection(opts: {
1957
1962
  targetId?: string;
1958
1963
  reason?: string;
1959
1964
  }): Promise<void>;
1965
+
1960
1966
  /** @deprecated Use `forceDisconnectPlaywrightConnection` instead. */
1961
1967
  declare const forceDisconnectPlaywrightForTarget: typeof forceDisconnectPlaywrightConnection;
1962
1968
  /**
@@ -1967,7 +1973,7 @@ declare function resolvePageByTargetIdOrThrow(opts: {
1967
1973
  targetId: string;
1968
1974
  }): Promise<Page>;
1969
1975
  /**
1970
- * Get a page for a target, ensuring page state is initialized and role refs are restored.
1976
+ * Get a page for a target, ensuring page state is initialized.
1971
1977
  */
1972
1978
  declare function getRestoredPageForTarget(opts: {
1973
1979
  cdpUrl: string;
@@ -1995,7 +2001,7 @@ declare function pressAndHoldViaCdp(opts: {
1995
2001
  * navigator.connection, console toString, headless-mode quirks,
1996
2002
  * hardwareConcurrency, and deviceMemory.
1997
2003
  */
1998
- declare const STEALTH_SCRIPT = "(function() {\n 'use strict';\n function p(fn) { try { fn(); } catch(_) {} }\n\n // \u2500\u2500 1. navigator.webdriver \u2192 undefined \u2500\u2500\n p(function() {\n Object.defineProperty(navigator, 'webdriver', { get: function() { return undefined; }, configurable: true });\n });\n\n // \u2500\u2500 2. navigator.plugins + mimeTypes (only if empty \u2014 Chrome 92+ populates them natively) \u2500\u2500\n p(function() {\n if (navigator.plugins && navigator.plugins.length > 0) return;\n\n function FakePlugin(name, fn, desc, mimes) {\n this.name = name; this.filename = fn; this.description = desc; this.length = mimes.length;\n for (var i = 0; i < mimes.length; i++) { this[i] = mimes[i]; mimes[i].enabledPlugin = this; }\n }\n FakePlugin.prototype.item = function(i) { return this[i] || null; };\n FakePlugin.prototype.namedItem = function(n) {\n for (var i = 0; i < this.length; i++) if (this[i].type === n) return this[i];\n return null;\n };\n\n function M(type, suf, desc) { this.type = type; this.suffixes = suf; this.description = desc; }\n\n var m1 = new M('application/pdf', 'pdf', 'Portable Document Format');\n var m2 = new M('application/x-google-chrome-pdf', 'pdf', 'Portable Document Format');\n var m3 = new M('application/x-nacl', '', 'Native Client Executable');\n var m4 = new M('application/x-pnacl', '', 'Portable Native Client Executable');\n\n var plugins = [\n new FakePlugin('Chrome PDF Plugin', 'internal-pdf-viewer', 'Portable Document Format', [m1]),\n new FakePlugin('Chrome PDF Viewer', 'mhjfbmdgcfjbbpaeojofohoefgiehjai', '', [m2]),\n new FakePlugin('Native Client', 'internal-nacl-plugin', '', [m3, m4]),\n ];\n\n function makeIterable(arr, items) {\n arr.length = items.length;\n for (var i = 0; i < items.length; i++) arr[i] = items[i];\n arr[Symbol.iterator] = function() {\n var idx = 0;\n return { next: function() {\n return idx < items.length ? { value: items[idx++], done: false } : { done: true };\n }};\n };\n }\n\n var pa = { item: function(i) { return plugins[i] || null; },\n namedItem: function(n) { for (var i = 0; i < plugins.length; i++) if (plugins[i].name === n) return plugins[i]; return null; },\n refresh: function() {} };\n makeIterable(pa, plugins);\n Object.defineProperty(navigator, 'plugins', { get: function() { return pa; } });\n\n var allMimes = [m1, m2, m3, m4];\n var ma = { item: function(i) { return allMimes[i] || null; },\n namedItem: function(n) { for (var i = 0; i < allMimes.length; i++) if (allMimes[i].type === n) return allMimes[i]; return null; } };\n makeIterable(ma, allMimes);\n Object.defineProperty(navigator, 'mimeTypes', { get: function() { return ma; } });\n });\n\n // \u2500\u2500 3. navigator.languages (cached + frozen so identity check passes) \u2500\u2500\n p(function() {\n if (!navigator.languages || navigator.languages.length === 0) {\n var langs = Object.freeze(['en-US', 'en']);\n Object.defineProperty(navigator, 'languages', { get: function() { return langs; } });\n }\n });\n\n // \u2500\u2500 4. window.chrome \u2500\u2500\n p(function() {\n if (window.chrome && window.chrome.runtime && window.chrome.runtime.connect) return;\n\n var chrome = window.chrome || {};\n var noop = function() {};\n var evtStub = { addListener: noop, removeListener: noop, hasListeners: function() { return false; } };\n chrome.runtime = chrome.runtime || {};\n chrome.runtime.onMessage = chrome.runtime.onMessage || evtStub;\n chrome.runtime.onConnect = chrome.runtime.onConnect || evtStub;\n chrome.runtime.sendMessage = chrome.runtime.sendMessage || noop;\n chrome.runtime.connect = chrome.runtime.connect || function() {\n return { onMessage: { addListener: noop }, postMessage: noop, disconnect: noop };\n };\n if (chrome.runtime.id === undefined) chrome.runtime.id = undefined;\n if (!chrome.loadTimes) chrome.loadTimes = function() { return {}; };\n if (!chrome.csi) chrome.csi = function() { return {}; };\n if (!chrome.app) {\n chrome.app = {\n isInstalled: false,\n InstallState: { INSTALLED: 'installed', NOT_INSTALLED: 'not_installed', DISABLED: 'disabled' },\n RunningState: { CANNOT_RUN: 'cannot_run', READY_TO_RUN: 'ready_to_run', RUNNING: 'running' },\n getDetails: function() { return null; },\n getIsInstalled: function() { return false; },\n runningState: function() { return 'cannot_run'; },\n };\n }\n\n if (!window.chrome) {\n Object.defineProperty(window, 'chrome', { value: chrome, writable: false, enumerable: true, configurable: false });\n }\n });\n\n // \u2500\u2500 5. Permissions API consistency \u2500\u2500\n p(function() {\n var orig = navigator.permissions.query.bind(navigator.permissions);\n function q(params) {\n if (params.name === 'notifications') {\n return Promise.resolve({\n state: typeof Notification !== 'undefined' ? Notification.permission : 'prompt',\n name: 'notifications', onchange: null,\n addEventListener: function(){}, removeEventListener: function(){}, dispatchEvent: function(){ return true; },\n });\n }\n return orig(params);\n }\n q.toString = function() { return 'function query() { [native code] }'; };\n navigator.permissions.query = q;\n });\n\n // \u2500\u2500 6. WebGL vendor / renderer \u2500\u2500\n p(function() {\n var h = {\n apply: function(target, self, args) {\n var param = args[0];\n if (param === 0x9245) return 'Intel Inc.';\n if (param === 0x9246) return 'Intel Iris OpenGL Engine';\n return Reflect.apply(target, self, args);\n }\n };\n if (typeof WebGLRenderingContext !== 'undefined')\n WebGLRenderingContext.prototype.getParameter = new Proxy(WebGLRenderingContext.prototype.getParameter, h);\n if (typeof WebGL2RenderingContext !== 'undefined')\n WebGL2RenderingContext.prototype.getParameter = new Proxy(WebGL2RenderingContext.prototype.getParameter, h);\n });\n\n // \u2500\u2500 7. Notification.permission \u2500\u2500\n p(function() {\n if (typeof Notification !== 'undefined' && Notification.permission === 'denied') {\n Object.defineProperty(Notification, 'permission', { get: function() { return 'default'; }, configurable: true });\n }\n });\n\n // \u2500\u2500 8. navigator.connection (cached so identity check passes) \u2500\u2500\n p(function() {\n if (navigator.connection) return;\n var conn = {\n effectiveType: '4g', rtt: 50, downlink: 10, saveData: false, onchange: null,\n addEventListener: function(){}, removeEventListener: function(){}, dispatchEvent: function(){ return true; },\n };\n Object.defineProperty(navigator, 'connection', { get: function() { return conn; } });\n });\n\n // \u2500\u2500 9. Iframe contentWindow.chrome \u2500\u2500\n // Handled by patch 4 \u2014 chrome object is now on window, propagates to iframes on same origin.\n\n // \u2500\u2500 10. console method toString \u2500\u2500\n p(function() {\n ['log','info','warn','error','debug','table','trace'].forEach(function(n) {\n if (console[n]) {\n console[n].toString = function() { return 'function ' + n + '() { [native code] }'; };\n }\n });\n });\n\n // \u2500\u2500 11. Headless-mode window / screen fixes \u2500\u2500\n p(function() {\n if (window.outerWidth === 0)\n Object.defineProperty(window, 'outerWidth', { get: function() { return window.innerWidth || 1920; } });\n if (window.outerHeight === 0)\n Object.defineProperty(window, 'outerHeight', { get: function() { return (window.innerHeight || 1080) + 85; } });\n });\n\n p(function() {\n if (screen.colorDepth === 0) {\n Object.defineProperty(screen, 'colorDepth', { get: function() { return 24; } });\n Object.defineProperty(screen, 'pixelDepth', { get: function() { return 24; } });\n }\n });\n\n // \u2500\u2500 12. navigator.hardwareConcurrency \u2500\u2500\n p(function() {\n if (!navigator.hardwareConcurrency)\n Object.defineProperty(navigator, 'hardwareConcurrency', { get: function() { return 4; } });\n });\n\n // \u2500\u2500 13. navigator.deviceMemory \u2500\u2500\n p(function() {\n if (!navigator.deviceMemory)\n Object.defineProperty(navigator, 'deviceMemory', { get: function() { return 8; } });\n });\n})()";
2004
+ declare const STEALTH_SCRIPT = "(function() {\n 'use strict';\n function p(fn) { try { fn(); } catch(_) {} }\n\n // \u2500\u2500 1. navigator.webdriver \u2192 undefined \u2500\u2500\n p(function() {\n Object.defineProperty(navigator, 'webdriver', { get: function() { return undefined; }, configurable: true });\n });\n\n // \u2500\u2500 2. navigator.plugins + mimeTypes (only if empty \u2014 Chrome 92+ populates them natively) \u2500\u2500\n p(function() {\n if (navigator.plugins && navigator.plugins.length > 0) return;\n\n function FakePlugin(name, fn, desc, mimes) {\n this.name = name; this.filename = fn; this.description = desc; this.length = mimes.length;\n for (var i = 0; i < mimes.length; i++) { this[i] = mimes[i]; mimes[i].enabledPlugin = this; }\n }\n FakePlugin.prototype.item = function(i) { return this[i] || null; };\n FakePlugin.prototype.namedItem = function(n) {\n for (var i = 0; i < this.length; i++) if (this[i].type === n) return this[i];\n return null;\n };\n\n function M(type, suf, desc) { this.type = type; this.suffixes = suf; this.description = desc; }\n\n var m1 = new M('application/pdf', 'pdf', 'Portable Document Format');\n var m2 = new M('application/x-google-chrome-pdf', 'pdf', 'Portable Document Format');\n var m3 = new M('application/x-nacl', '', 'Native Client Executable');\n var m4 = new M('application/x-pnacl', '', 'Portable Native Client Executable');\n\n var plugins = [\n new FakePlugin('Chrome PDF Plugin', 'internal-pdf-viewer', 'Portable Document Format', [m1]),\n new FakePlugin('Chrome PDF Viewer', 'mhjfbmdgcfjbbpaeojofohoefgiehjai', '', [m2]),\n new FakePlugin('Native Client', 'internal-nacl-plugin', '', [m3, m4]),\n ];\n\n function makeIterable(arr, items) {\n arr.length = items.length;\n for (var i = 0; i < items.length; i++) arr[i] = items[i];\n arr[Symbol.iterator] = function() {\n var idx = 0;\n return { next: function() {\n return idx < items.length ? { value: items[idx++], done: false } : { done: true };\n }};\n };\n }\n\n var pa = { item: function(i) { return plugins[i] || null; },\n namedItem: function(n) { for (var i = 0; i < plugins.length; i++) if (plugins[i].name === n) return plugins[i]; return null; },\n refresh: function() {} };\n makeIterable(pa, plugins);\n Object.defineProperty(navigator, 'plugins', { get: function() { return pa; } });\n\n var allMimes = [m1, m2, m3, m4];\n var ma = { item: function(i) { return allMimes[i] || null; },\n namedItem: function(n) { for (var i = 0; i < allMimes.length; i++) if (allMimes[i].type === n) return allMimes[i]; return null; } };\n makeIterable(ma, allMimes);\n Object.defineProperty(navigator, 'mimeTypes', { get: function() { return ma; } });\n });\n\n // \u2500\u2500 3. navigator.languages (cached + frozen so identity check passes) \u2500\u2500\n p(function() {\n if (!navigator.languages || navigator.languages.length === 0) {\n var langs = Object.freeze(['en-US', 'en']);\n Object.defineProperty(navigator, 'languages', { get: function() { return langs; } });\n }\n });\n\n // \u2500\u2500 4. window.chrome \u2500\u2500\n // Stub the chrome.runtime API surface that detection scripts probe for.\n // Only applied when the real chrome.runtime.connect is absent (headless/CDP mode).\n // The stubs are intentionally non-functional \u2014 they exist solely to pass presence checks.\n p(function() {\n if (window.chrome && window.chrome.runtime && window.chrome.runtime.connect) return;\n\n var chrome = window.chrome || {};\n var noop = function() {};\n var evtStub = { addListener: noop, removeListener: noop, hasListeners: function() { return false; } };\n chrome.runtime = chrome.runtime || {};\n chrome.runtime.onMessage = chrome.runtime.onMessage || evtStub;\n chrome.runtime.onConnect = chrome.runtime.onConnect || evtStub;\n chrome.runtime.sendMessage = chrome.runtime.sendMessage || noop;\n chrome.runtime.connect = chrome.runtime.connect || function() {\n return { onMessage: { addListener: noop }, postMessage: noop, disconnect: noop };\n };\n if (chrome.runtime.id === undefined) chrome.runtime.id = undefined;\n if (!chrome.loadTimes) chrome.loadTimes = function() { return {}; };\n if (!chrome.csi) chrome.csi = function() { return {}; };\n if (!chrome.app) {\n chrome.app = {\n isInstalled: false,\n InstallState: { INSTALLED: 'installed', NOT_INSTALLED: 'not_installed', DISABLED: 'disabled' },\n RunningState: { CANNOT_RUN: 'cannot_run', READY_TO_RUN: 'ready_to_run', RUNNING: 'running' },\n getDetails: function() { return null; },\n getIsInstalled: function() { return false; },\n runningState: function() { return 'cannot_run'; },\n };\n }\n\n if (!window.chrome) {\n Object.defineProperty(window, 'chrome', { value: chrome, writable: false, enumerable: true, configurable: false });\n }\n });\n\n // \u2500\u2500 5. Permissions API consistency \u2500\u2500\n p(function() {\n var orig = navigator.permissions.query.bind(navigator.permissions);\n function q(params) {\n if (params.name === 'notifications') {\n return Promise.resolve({\n state: typeof Notification !== 'undefined' ? Notification.permission : 'prompt',\n name: 'notifications', onchange: null,\n addEventListener: function(){}, removeEventListener: function(){}, dispatchEvent: function(){ return true; },\n });\n }\n return orig(params);\n }\n q.toString = function() { return 'function query() { [native code] }'; };\n navigator.permissions.query = q;\n });\n\n // \u2500\u2500 6. WebGL vendor / renderer \u2500\u2500\n // Hardcoded to Intel Iris \u2014 the most common discrete GPU on macOS. These strings\n // are fingerprinting targets; a more sophisticated approach would randomize per-session,\n // but static values are sufficient to avoid the default \"Google SwiftShader\" headless signal.\n p(function() {\n var h = {\n apply: function(target, self, args) {\n var param = args[0];\n if (param === 0x9245) return 'Intel Inc.';\n if (param === 0x9246) return 'Intel Iris OpenGL Engine';\n return Reflect.apply(target, self, args);\n }\n };\n if (typeof WebGLRenderingContext !== 'undefined')\n WebGLRenderingContext.prototype.getParameter = new Proxy(WebGLRenderingContext.prototype.getParameter, h);\n if (typeof WebGL2RenderingContext !== 'undefined')\n WebGL2RenderingContext.prototype.getParameter = new Proxy(WebGL2RenderingContext.prototype.getParameter, h);\n });\n\n // \u2500\u2500 7. Notification.permission \u2500\u2500\n p(function() {\n if (typeof Notification !== 'undefined' && Notification.permission === 'denied') {\n Object.defineProperty(Notification, 'permission', { get: function() { return 'default'; }, configurable: true });\n }\n });\n\n // \u2500\u2500 8. navigator.connection (cached so identity check passes) \u2500\u2500\n p(function() {\n if (navigator.connection) return;\n var conn = {\n effectiveType: '4g', rtt: 50, downlink: 10, saveData: false, onchange: null,\n addEventListener: function(){}, removeEventListener: function(){}, dispatchEvent: function(){ return true; },\n };\n Object.defineProperty(navigator, 'connection', { get: function() { return conn; } });\n });\n\n // \u2500\u2500 9. Iframe contentWindow.chrome \u2500\u2500\n // Handled by patch 4 \u2014 chrome object is now on window, propagates to iframes on same origin.\n\n // \u2500\u2500 10. console method toString \u2500\u2500\n p(function() {\n ['log','info','warn','error','debug','table','trace'].forEach(function(n) {\n if (console[n]) {\n console[n].toString = function() { return 'function ' + n + '() { [native code] }'; };\n }\n });\n });\n\n // \u2500\u2500 11. Headless-mode window / screen fixes \u2500\u2500\n p(function() {\n if (window.outerWidth === 0)\n Object.defineProperty(window, 'outerWidth', { get: function() { return window.innerWidth || 1920; } });\n if (window.outerHeight === 0)\n Object.defineProperty(window, 'outerHeight', { get: function() { return (window.innerHeight || 1080) + 85; } });\n });\n\n p(function() {\n if (screen.colorDepth === 0) {\n Object.defineProperty(screen, 'colorDepth', { get: function() { return 24; } });\n Object.defineProperty(screen, 'pixelDepth', { get: function() { return 24; } });\n }\n });\n\n // \u2500\u2500 12. navigator.hardwareConcurrency \u2500\u2500\n p(function() {\n if (!navigator.hardwareConcurrency)\n Object.defineProperty(navigator, 'hardwareConcurrency', { get: function() { return 4; } });\n });\n\n // \u2500\u2500 13. navigator.deviceMemory \u2500\u2500\n p(function() {\n if (!navigator.deviceMemory)\n Object.defineProperty(navigator, 'deviceMemory', { get: function() { return 8; } });\n });\n})()";
1999
2005
 
2000
2006
  /**
2001
2007
  * Detect whether the current page is showing an anti-bot challenge.
package/dist/index.d.ts CHANGED
@@ -721,12 +721,17 @@ interface PinnedHostname {
721
721
  */
722
722
  declare class CrawlPage {
723
723
  private readonly cdpUrl;
724
- private readonly targetId;
724
+ private _targetId;
725
725
  private readonly ssrfPolicy;
726
726
  /** @internal */
727
727
  constructor(cdpUrl: string, targetId: string, ssrfPolicy?: SsrfPolicy);
728
728
  /** The CDP target ID for this page. Use this to identify the page in multi-tab scenarios. */
729
729
  get id(): string;
730
+ /**
731
+ * Refresh the target ID by re-resolving the page from the browser.
732
+ * Useful after reconnection when the old target ID may be stale.
733
+ */
734
+ refreshTargetId(): Promise<string>;
730
735
  /**
731
736
  * Take an AI-readable snapshot of the page.
732
737
  *
@@ -1957,6 +1962,7 @@ declare function forceDisconnectPlaywrightConnection(opts: {
1957
1962
  targetId?: string;
1958
1963
  reason?: string;
1959
1964
  }): Promise<void>;
1965
+
1960
1966
  /** @deprecated Use `forceDisconnectPlaywrightConnection` instead. */
1961
1967
  declare const forceDisconnectPlaywrightForTarget: typeof forceDisconnectPlaywrightConnection;
1962
1968
  /**
@@ -1967,7 +1973,7 @@ declare function resolvePageByTargetIdOrThrow(opts: {
1967
1973
  targetId: string;
1968
1974
  }): Promise<Page>;
1969
1975
  /**
1970
- * Get a page for a target, ensuring page state is initialized and role refs are restored.
1976
+ * Get a page for a target, ensuring page state is initialized.
1971
1977
  */
1972
1978
  declare function getRestoredPageForTarget(opts: {
1973
1979
  cdpUrl: string;
@@ -1995,7 +2001,7 @@ declare function pressAndHoldViaCdp(opts: {
1995
2001
  * navigator.connection, console toString, headless-mode quirks,
1996
2002
  * hardwareConcurrency, and deviceMemory.
1997
2003
  */
1998
- declare const STEALTH_SCRIPT = "(function() {\n 'use strict';\n function p(fn) { try { fn(); } catch(_) {} }\n\n // \u2500\u2500 1. navigator.webdriver \u2192 undefined \u2500\u2500\n p(function() {\n Object.defineProperty(navigator, 'webdriver', { get: function() { return undefined; }, configurable: true });\n });\n\n // \u2500\u2500 2. navigator.plugins + mimeTypes (only if empty \u2014 Chrome 92+ populates them natively) \u2500\u2500\n p(function() {\n if (navigator.plugins && navigator.plugins.length > 0) return;\n\n function FakePlugin(name, fn, desc, mimes) {\n this.name = name; this.filename = fn; this.description = desc; this.length = mimes.length;\n for (var i = 0; i < mimes.length; i++) { this[i] = mimes[i]; mimes[i].enabledPlugin = this; }\n }\n FakePlugin.prototype.item = function(i) { return this[i] || null; };\n FakePlugin.prototype.namedItem = function(n) {\n for (var i = 0; i < this.length; i++) if (this[i].type === n) return this[i];\n return null;\n };\n\n function M(type, suf, desc) { this.type = type; this.suffixes = suf; this.description = desc; }\n\n var m1 = new M('application/pdf', 'pdf', 'Portable Document Format');\n var m2 = new M('application/x-google-chrome-pdf', 'pdf', 'Portable Document Format');\n var m3 = new M('application/x-nacl', '', 'Native Client Executable');\n var m4 = new M('application/x-pnacl', '', 'Portable Native Client Executable');\n\n var plugins = [\n new FakePlugin('Chrome PDF Plugin', 'internal-pdf-viewer', 'Portable Document Format', [m1]),\n new FakePlugin('Chrome PDF Viewer', 'mhjfbmdgcfjbbpaeojofohoefgiehjai', '', [m2]),\n new FakePlugin('Native Client', 'internal-nacl-plugin', '', [m3, m4]),\n ];\n\n function makeIterable(arr, items) {\n arr.length = items.length;\n for (var i = 0; i < items.length; i++) arr[i] = items[i];\n arr[Symbol.iterator] = function() {\n var idx = 0;\n return { next: function() {\n return idx < items.length ? { value: items[idx++], done: false } : { done: true };\n }};\n };\n }\n\n var pa = { item: function(i) { return plugins[i] || null; },\n namedItem: function(n) { for (var i = 0; i < plugins.length; i++) if (plugins[i].name === n) return plugins[i]; return null; },\n refresh: function() {} };\n makeIterable(pa, plugins);\n Object.defineProperty(navigator, 'plugins', { get: function() { return pa; } });\n\n var allMimes = [m1, m2, m3, m4];\n var ma = { item: function(i) { return allMimes[i] || null; },\n namedItem: function(n) { for (var i = 0; i < allMimes.length; i++) if (allMimes[i].type === n) return allMimes[i]; return null; } };\n makeIterable(ma, allMimes);\n Object.defineProperty(navigator, 'mimeTypes', { get: function() { return ma; } });\n });\n\n // \u2500\u2500 3. navigator.languages (cached + frozen so identity check passes) \u2500\u2500\n p(function() {\n if (!navigator.languages || navigator.languages.length === 0) {\n var langs = Object.freeze(['en-US', 'en']);\n Object.defineProperty(navigator, 'languages', { get: function() { return langs; } });\n }\n });\n\n // \u2500\u2500 4. window.chrome \u2500\u2500\n p(function() {\n if (window.chrome && window.chrome.runtime && window.chrome.runtime.connect) return;\n\n var chrome = window.chrome || {};\n var noop = function() {};\n var evtStub = { addListener: noop, removeListener: noop, hasListeners: function() { return false; } };\n chrome.runtime = chrome.runtime || {};\n chrome.runtime.onMessage = chrome.runtime.onMessage || evtStub;\n chrome.runtime.onConnect = chrome.runtime.onConnect || evtStub;\n chrome.runtime.sendMessage = chrome.runtime.sendMessage || noop;\n chrome.runtime.connect = chrome.runtime.connect || function() {\n return { onMessage: { addListener: noop }, postMessage: noop, disconnect: noop };\n };\n if (chrome.runtime.id === undefined) chrome.runtime.id = undefined;\n if (!chrome.loadTimes) chrome.loadTimes = function() { return {}; };\n if (!chrome.csi) chrome.csi = function() { return {}; };\n if (!chrome.app) {\n chrome.app = {\n isInstalled: false,\n InstallState: { INSTALLED: 'installed', NOT_INSTALLED: 'not_installed', DISABLED: 'disabled' },\n RunningState: { CANNOT_RUN: 'cannot_run', READY_TO_RUN: 'ready_to_run', RUNNING: 'running' },\n getDetails: function() { return null; },\n getIsInstalled: function() { return false; },\n runningState: function() { return 'cannot_run'; },\n };\n }\n\n if (!window.chrome) {\n Object.defineProperty(window, 'chrome', { value: chrome, writable: false, enumerable: true, configurable: false });\n }\n });\n\n // \u2500\u2500 5. Permissions API consistency \u2500\u2500\n p(function() {\n var orig = navigator.permissions.query.bind(navigator.permissions);\n function q(params) {\n if (params.name === 'notifications') {\n return Promise.resolve({\n state: typeof Notification !== 'undefined' ? Notification.permission : 'prompt',\n name: 'notifications', onchange: null,\n addEventListener: function(){}, removeEventListener: function(){}, dispatchEvent: function(){ return true; },\n });\n }\n return orig(params);\n }\n q.toString = function() { return 'function query() { [native code] }'; };\n navigator.permissions.query = q;\n });\n\n // \u2500\u2500 6. WebGL vendor / renderer \u2500\u2500\n p(function() {\n var h = {\n apply: function(target, self, args) {\n var param = args[0];\n if (param === 0x9245) return 'Intel Inc.';\n if (param === 0x9246) return 'Intel Iris OpenGL Engine';\n return Reflect.apply(target, self, args);\n }\n };\n if (typeof WebGLRenderingContext !== 'undefined')\n WebGLRenderingContext.prototype.getParameter = new Proxy(WebGLRenderingContext.prototype.getParameter, h);\n if (typeof WebGL2RenderingContext !== 'undefined')\n WebGL2RenderingContext.prototype.getParameter = new Proxy(WebGL2RenderingContext.prototype.getParameter, h);\n });\n\n // \u2500\u2500 7. Notification.permission \u2500\u2500\n p(function() {\n if (typeof Notification !== 'undefined' && Notification.permission === 'denied') {\n Object.defineProperty(Notification, 'permission', { get: function() { return 'default'; }, configurable: true });\n }\n });\n\n // \u2500\u2500 8. navigator.connection (cached so identity check passes) \u2500\u2500\n p(function() {\n if (navigator.connection) return;\n var conn = {\n effectiveType: '4g', rtt: 50, downlink: 10, saveData: false, onchange: null,\n addEventListener: function(){}, removeEventListener: function(){}, dispatchEvent: function(){ return true; },\n };\n Object.defineProperty(navigator, 'connection', { get: function() { return conn; } });\n });\n\n // \u2500\u2500 9. Iframe contentWindow.chrome \u2500\u2500\n // Handled by patch 4 \u2014 chrome object is now on window, propagates to iframes on same origin.\n\n // \u2500\u2500 10. console method toString \u2500\u2500\n p(function() {\n ['log','info','warn','error','debug','table','trace'].forEach(function(n) {\n if (console[n]) {\n console[n].toString = function() { return 'function ' + n + '() { [native code] }'; };\n }\n });\n });\n\n // \u2500\u2500 11. Headless-mode window / screen fixes \u2500\u2500\n p(function() {\n if (window.outerWidth === 0)\n Object.defineProperty(window, 'outerWidth', { get: function() { return window.innerWidth || 1920; } });\n if (window.outerHeight === 0)\n Object.defineProperty(window, 'outerHeight', { get: function() { return (window.innerHeight || 1080) + 85; } });\n });\n\n p(function() {\n if (screen.colorDepth === 0) {\n Object.defineProperty(screen, 'colorDepth', { get: function() { return 24; } });\n Object.defineProperty(screen, 'pixelDepth', { get: function() { return 24; } });\n }\n });\n\n // \u2500\u2500 12. navigator.hardwareConcurrency \u2500\u2500\n p(function() {\n if (!navigator.hardwareConcurrency)\n Object.defineProperty(navigator, 'hardwareConcurrency', { get: function() { return 4; } });\n });\n\n // \u2500\u2500 13. navigator.deviceMemory \u2500\u2500\n p(function() {\n if (!navigator.deviceMemory)\n Object.defineProperty(navigator, 'deviceMemory', { get: function() { return 8; } });\n });\n})()";
2004
+ declare const STEALTH_SCRIPT = "(function() {\n 'use strict';\n function p(fn) { try { fn(); } catch(_) {} }\n\n // \u2500\u2500 1. navigator.webdriver \u2192 undefined \u2500\u2500\n p(function() {\n Object.defineProperty(navigator, 'webdriver', { get: function() { return undefined; }, configurable: true });\n });\n\n // \u2500\u2500 2. navigator.plugins + mimeTypes (only if empty \u2014 Chrome 92+ populates them natively) \u2500\u2500\n p(function() {\n if (navigator.plugins && navigator.plugins.length > 0) return;\n\n function FakePlugin(name, fn, desc, mimes) {\n this.name = name; this.filename = fn; this.description = desc; this.length = mimes.length;\n for (var i = 0; i < mimes.length; i++) { this[i] = mimes[i]; mimes[i].enabledPlugin = this; }\n }\n FakePlugin.prototype.item = function(i) { return this[i] || null; };\n FakePlugin.prototype.namedItem = function(n) {\n for (var i = 0; i < this.length; i++) if (this[i].type === n) return this[i];\n return null;\n };\n\n function M(type, suf, desc) { this.type = type; this.suffixes = suf; this.description = desc; }\n\n var m1 = new M('application/pdf', 'pdf', 'Portable Document Format');\n var m2 = new M('application/x-google-chrome-pdf', 'pdf', 'Portable Document Format');\n var m3 = new M('application/x-nacl', '', 'Native Client Executable');\n var m4 = new M('application/x-pnacl', '', 'Portable Native Client Executable');\n\n var plugins = [\n new FakePlugin('Chrome PDF Plugin', 'internal-pdf-viewer', 'Portable Document Format', [m1]),\n new FakePlugin('Chrome PDF Viewer', 'mhjfbmdgcfjbbpaeojofohoefgiehjai', '', [m2]),\n new FakePlugin('Native Client', 'internal-nacl-plugin', '', [m3, m4]),\n ];\n\n function makeIterable(arr, items) {\n arr.length = items.length;\n for (var i = 0; i < items.length; i++) arr[i] = items[i];\n arr[Symbol.iterator] = function() {\n var idx = 0;\n return { next: function() {\n return idx < items.length ? { value: items[idx++], done: false } : { done: true };\n }};\n };\n }\n\n var pa = { item: function(i) { return plugins[i] || null; },\n namedItem: function(n) { for (var i = 0; i < plugins.length; i++) if (plugins[i].name === n) return plugins[i]; return null; },\n refresh: function() {} };\n makeIterable(pa, plugins);\n Object.defineProperty(navigator, 'plugins', { get: function() { return pa; } });\n\n var allMimes = [m1, m2, m3, m4];\n var ma = { item: function(i) { return allMimes[i] || null; },\n namedItem: function(n) { for (var i = 0; i < allMimes.length; i++) if (allMimes[i].type === n) return allMimes[i]; return null; } };\n makeIterable(ma, allMimes);\n Object.defineProperty(navigator, 'mimeTypes', { get: function() { return ma; } });\n });\n\n // \u2500\u2500 3. navigator.languages (cached + frozen so identity check passes) \u2500\u2500\n p(function() {\n if (!navigator.languages || navigator.languages.length === 0) {\n var langs = Object.freeze(['en-US', 'en']);\n Object.defineProperty(navigator, 'languages', { get: function() { return langs; } });\n }\n });\n\n // \u2500\u2500 4. window.chrome \u2500\u2500\n // Stub the chrome.runtime API surface that detection scripts probe for.\n // Only applied when the real chrome.runtime.connect is absent (headless/CDP mode).\n // The stubs are intentionally non-functional \u2014 they exist solely to pass presence checks.\n p(function() {\n if (window.chrome && window.chrome.runtime && window.chrome.runtime.connect) return;\n\n var chrome = window.chrome || {};\n var noop = function() {};\n var evtStub = { addListener: noop, removeListener: noop, hasListeners: function() { return false; } };\n chrome.runtime = chrome.runtime || {};\n chrome.runtime.onMessage = chrome.runtime.onMessage || evtStub;\n chrome.runtime.onConnect = chrome.runtime.onConnect || evtStub;\n chrome.runtime.sendMessage = chrome.runtime.sendMessage || noop;\n chrome.runtime.connect = chrome.runtime.connect || function() {\n return { onMessage: { addListener: noop }, postMessage: noop, disconnect: noop };\n };\n if (chrome.runtime.id === undefined) chrome.runtime.id = undefined;\n if (!chrome.loadTimes) chrome.loadTimes = function() { return {}; };\n if (!chrome.csi) chrome.csi = function() { return {}; };\n if (!chrome.app) {\n chrome.app = {\n isInstalled: false,\n InstallState: { INSTALLED: 'installed', NOT_INSTALLED: 'not_installed', DISABLED: 'disabled' },\n RunningState: { CANNOT_RUN: 'cannot_run', READY_TO_RUN: 'ready_to_run', RUNNING: 'running' },\n getDetails: function() { return null; },\n getIsInstalled: function() { return false; },\n runningState: function() { return 'cannot_run'; },\n };\n }\n\n if (!window.chrome) {\n Object.defineProperty(window, 'chrome', { value: chrome, writable: false, enumerable: true, configurable: false });\n }\n });\n\n // \u2500\u2500 5. Permissions API consistency \u2500\u2500\n p(function() {\n var orig = navigator.permissions.query.bind(navigator.permissions);\n function q(params) {\n if (params.name === 'notifications') {\n return Promise.resolve({\n state: typeof Notification !== 'undefined' ? Notification.permission : 'prompt',\n name: 'notifications', onchange: null,\n addEventListener: function(){}, removeEventListener: function(){}, dispatchEvent: function(){ return true; },\n });\n }\n return orig(params);\n }\n q.toString = function() { return 'function query() { [native code] }'; };\n navigator.permissions.query = q;\n });\n\n // \u2500\u2500 6. WebGL vendor / renderer \u2500\u2500\n // Hardcoded to Intel Iris \u2014 the most common discrete GPU on macOS. These strings\n // are fingerprinting targets; a more sophisticated approach would randomize per-session,\n // but static values are sufficient to avoid the default \"Google SwiftShader\" headless signal.\n p(function() {\n var h = {\n apply: function(target, self, args) {\n var param = args[0];\n if (param === 0x9245) return 'Intel Inc.';\n if (param === 0x9246) return 'Intel Iris OpenGL Engine';\n return Reflect.apply(target, self, args);\n }\n };\n if (typeof WebGLRenderingContext !== 'undefined')\n WebGLRenderingContext.prototype.getParameter = new Proxy(WebGLRenderingContext.prototype.getParameter, h);\n if (typeof WebGL2RenderingContext !== 'undefined')\n WebGL2RenderingContext.prototype.getParameter = new Proxy(WebGL2RenderingContext.prototype.getParameter, h);\n });\n\n // \u2500\u2500 7. Notification.permission \u2500\u2500\n p(function() {\n if (typeof Notification !== 'undefined' && Notification.permission === 'denied') {\n Object.defineProperty(Notification, 'permission', { get: function() { return 'default'; }, configurable: true });\n }\n });\n\n // \u2500\u2500 8. navigator.connection (cached so identity check passes) \u2500\u2500\n p(function() {\n if (navigator.connection) return;\n var conn = {\n effectiveType: '4g', rtt: 50, downlink: 10, saveData: false, onchange: null,\n addEventListener: function(){}, removeEventListener: function(){}, dispatchEvent: function(){ return true; },\n };\n Object.defineProperty(navigator, 'connection', { get: function() { return conn; } });\n });\n\n // \u2500\u2500 9. Iframe contentWindow.chrome \u2500\u2500\n // Handled by patch 4 \u2014 chrome object is now on window, propagates to iframes on same origin.\n\n // \u2500\u2500 10. console method toString \u2500\u2500\n p(function() {\n ['log','info','warn','error','debug','table','trace'].forEach(function(n) {\n if (console[n]) {\n console[n].toString = function() { return 'function ' + n + '() { [native code] }'; };\n }\n });\n });\n\n // \u2500\u2500 11. Headless-mode window / screen fixes \u2500\u2500\n p(function() {\n if (window.outerWidth === 0)\n Object.defineProperty(window, 'outerWidth', { get: function() { return window.innerWidth || 1920; } });\n if (window.outerHeight === 0)\n Object.defineProperty(window, 'outerHeight', { get: function() { return (window.innerHeight || 1080) + 85; } });\n });\n\n p(function() {\n if (screen.colorDepth === 0) {\n Object.defineProperty(screen, 'colorDepth', { get: function() { return 24; } });\n Object.defineProperty(screen, 'pixelDepth', { get: function() { return 24; } });\n }\n });\n\n // \u2500\u2500 12. navigator.hardwareConcurrency \u2500\u2500\n p(function() {\n if (!navigator.hardwareConcurrency)\n Object.defineProperty(navigator, 'hardwareConcurrency', { get: function() { return 4; } });\n });\n\n // \u2500\u2500 13. navigator.deviceMemory \u2500\u2500\n p(function() {\n if (!navigator.deviceMemory)\n Object.defineProperty(navigator, 'deviceMemory', { get: function() { return 8; } });\n });\n})()";
1999
2005
 
2000
2006
  /**
2001
2007
  * Detect whether the current page is showing an anti-bot challenge.