@midscene/web 1.3.8 → 1.3.9

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.
@@ -17,7 +17,7 @@ class BridgeClient {
17
17
  this.socket = io(this.endpoint, {
18
18
  reconnection: false,
19
19
  query: {
20
- version: "1.3.8"
20
+ version: "1.3.9"
21
21
  }
22
22
  });
23
23
  const timeout = setTimeout(()=>{
@@ -75,7 +75,7 @@ class BridgeServer {
75
75
  logMsg('one client connected');
76
76
  this.socket = socket;
77
77
  const clientVersion = socket.handshake.query.version;
78
- logMsg(`Bridge connected, cli-side version v1.3.8, browser-side version v${clientVersion}`);
78
+ logMsg(`Bridge connected, cli-side version v1.3.9, browser-side version v${clientVersion}`);
79
79
  socket.on(BridgeEvent.CallResponse, (params)=>{
80
80
  const id = params.id;
81
81
  const response = params.response;
@@ -100,7 +100,7 @@ class BridgeServer {
100
100
  setTimeout(()=>{
101
101
  this.onConnect?.();
102
102
  const payload = {
103
- version: "1.3.8"
103
+ version: "1.3.9"
104
104
  };
105
105
  socket.emit(BridgeEvent.Connected, payload);
106
106
  Promise.resolve().then(()=>{
@@ -46,7 +46,7 @@ class ExtensionBridgePageBrowserSide extends page {
46
46
  }
47
47
  }, ()=>this.destroy());
48
48
  await this.bridgeClient.connect();
49
- this.onLogMessage(`Bridge connected, cli-side version v${this.bridgeClient.serverVersion}, browser-side version v1.3.8`, 'log');
49
+ this.onLogMessage(`Bridge connected, cli-side version v${this.bridgeClient.serverVersion}, browser-side version v1.3.9`, 'log');
50
50
  }
51
51
  async connect() {
52
52
  return await this.setupBridgeClient();
@@ -1,7 +1,9 @@
1
1
  import { WebPageContextParser, limitOpenNewTabScript } from "../web-element.mjs";
2
2
  import { treeToList } from "@midscene/shared/extractor";
3
3
  import { createImgBase64ByFormat } from "@midscene/shared/img";
4
+ import { getDebug } from "@midscene/shared/logger";
4
5
  import { assert } from "@midscene/shared/utils";
6
+ import { buildRectFromElementInfo, judgeOrderSensitive, sanitizeXpaths } from "../common/cache-helper.mjs";
5
7
  import { commonWebActionsForWebPage } from "../web-page.mjs";
6
8
  import { CdpKeyboard } from "./cdpInput.mjs";
7
9
  import { getHtmlElementScript, injectStopWaterFlowAnimation, injectWaterFlowAnimation } from "./dynamic-scripts.mjs";
@@ -15,6 +17,7 @@ function _define_property(obj, key, value) {
15
17
  else obj[key] = value;
16
18
  return obj;
17
19
  }
20
+ const debug = getDebug('web:chrome-extension:page');
18
21
  function sleep(ms) {
19
22
  return new Promise((resolve)=>setTimeout(resolve, ms));
20
23
  }
@@ -233,6 +236,34 @@ class ChromeExtensionProxyPage {
233
236
  });
234
237
  return result.result.value;
235
238
  }
239
+ async cacheFeatureForPoint(center, options) {
240
+ const point = {
241
+ left: center[0],
242
+ top: center[1]
243
+ };
244
+ try {
245
+ const isOrderSensitive = await judgeOrderSensitive(options, debug);
246
+ const xpaths = await this.getXpathsByPoint(point, isOrderSensitive);
247
+ return {
248
+ xpaths: sanitizeXpaths(xpaths)
249
+ };
250
+ } catch (error) {
251
+ debug('cacheFeatureForPoint failed: %O', error);
252
+ return {
253
+ xpaths: []
254
+ };
255
+ }
256
+ }
257
+ async rectMatchesCacheFeature(feature) {
258
+ const xpaths = sanitizeXpaths(feature.xpaths);
259
+ for (const xpath of xpaths)try {
260
+ const elementInfo = await this.getElementInfoByXpath(xpath);
261
+ if (elementInfo?.rect) return buildRectFromElementInfo(elementInfo, this.viewportSize?.dpr);
262
+ } catch (error) {
263
+ debug('rectMatchesCacheFeature failed for xpath %s: %O', xpath, error);
264
+ }
265
+ throw new Error(`No matching element rect found for cache feature (tried ${xpaths.length} xpath(s))`);
266
+ }
236
267
  async getElementsNodeTree() {
237
268
  await this.hideMousePointer();
238
269
  const content = await this.getPageContentByCDP();
@@ -1 +1 @@
1
- {"version":3,"file":"chrome-extension/page.mjs","sources":["../../../src/chrome-extension/page.ts"],"sourcesContent":["/// <reference types=\"chrome\" />\n\n/*\n It is used to interact with the page tab from the chrome extension.\n The page must be active when interacting with it.\n*/\n\nimport { limitOpenNewTabScript } from '@/web-element';\nimport type { ElementTreeNode, Point, Size, UIContext } from '@midscene/core';\nimport type { AbstractInterface, DeviceAction } from '@midscene/core/device';\nimport type { ElementInfo } from '@midscene/shared/extractor';\nimport { treeToList } from '@midscene/shared/extractor';\nimport { createImgBase64ByFormat } from '@midscene/shared/img';\nimport { assert } from '@midscene/shared/utils';\nimport type { Protocol as CDPTypes } from 'devtools-protocol';\nimport { WebPageContextParser } from '../web-element';\nimport {\n type KeyInput,\n type MouseButton,\n commonWebActionsForWebPage,\n} from '../web-page';\nimport { CdpKeyboard } from './cdpInput';\nimport {\n getHtmlElementScript,\n injectStopWaterFlowAnimation,\n injectWaterFlowAnimation,\n} from './dynamic-scripts';\n\nfunction sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport default class ChromeExtensionProxyPage implements AbstractInterface {\n interfaceType = 'chrome-extension-proxy';\n\n public forceSameTabNavigation: boolean;\n\n private viewportSize?: Size;\n\n private activeTabId: number | null = null;\n\n private destroyed = false;\n\n private isMobileEmulation: boolean | null = null;\n\n public _continueWhenFailedToAttachDebugger = false;\n\n constructor(forceSameTabNavigation: boolean) {\n this.forceSameTabNavigation = forceSameTabNavigation;\n }\n\n actionSpace(): DeviceAction[] {\n return commonWebActionsForWebPage(this);\n }\n\n public async setActiveTabId(tabId: number) {\n if (this.activeTabId) {\n throw new Error(\n `Active tab id is already set, which is ${this.activeTabId}, cannot set it to ${tabId}`,\n );\n }\n await chrome.tabs.update(tabId, { active: true });\n this.activeTabId = tabId;\n }\n\n public async getActiveTabId() {\n return this.activeTabId;\n }\n\n /**\n * Get a list of current tabs\n * @returns {Promise<Array<{id: number, title: string, url: string}>>}\n */\n public async getBrowserTabList(): Promise<\n { id: string; title: string; url: string; currentActiveTab: boolean }[]\n > {\n const tabs = await chrome.tabs.query({ currentWindow: true });\n return tabs\n .map((tab) => ({\n id: `${tab.id}`,\n title: tab.title,\n url: tab.url,\n currentActiveTab: tab.active,\n }))\n .filter((tab) => tab.id && tab.title && tab.url) as {\n id: string;\n title: string;\n url: string;\n currentActiveTab: boolean;\n }[];\n }\n\n public async getTabIdOrConnectToCurrentTab() {\n if (this.activeTabId) {\n // alway keep on the connected tab\n return this.activeTabId;\n }\n const tabId = await chrome.tabs\n .query({ active: true, currentWindow: true })\n .then((tabs) => tabs[0]?.id);\n this.activeTabId = tabId || 0;\n return this.activeTabId;\n }\n\n /**\n * Ensure debugger is attached to the current tab.\n * Uses lazy attach pattern - only attaches when needed.\n */\n private async ensureDebuggerAttached() {\n assert(!this.destroyed, 'Page is destroyed');\n\n const url = await this.url();\n if (url.startsWith('chrome://')) {\n throw new Error(\n 'Cannot attach debugger to chrome:// pages, please use Midscene in a normal page with http://, https:// or file://',\n );\n }\n\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n\n try {\n await chrome.debugger.attach({ tabId }, '1.3');\n console.log('Debugger attached to tab:', tabId);\n } catch (error) {\n const errorMsg = (error as Error)?.message || '';\n // Already attached is OK, we can continue\n if (errorMsg.includes('Another debugger is already attached')) {\n console.log('Debugger already attached to tab:', tabId);\n return;\n }\n\n if (this._continueWhenFailedToAttachDebugger) {\n console.warn(\n 'Failed to attach debugger, but continuing due to _continueWhenFailedToAttachDebugger flag',\n error,\n );\n return;\n }\n\n throw error;\n }\n\n // Wait for debugger banner in Chrome to appear\n await sleep(500);\n\n // Enable water flow animation\n await this.enableWaterFlowAnimation();\n }\n\n private async showMousePointer(x: number, y: number) {\n // update mouse pointer while redirecting\n const pointerScript = `(() => {\n if(typeof window.midsceneWaterFlowAnimation !== 'undefined') {\n window.midsceneWaterFlowAnimation.enable();\n window.midsceneWaterFlowAnimation.showMousePointer(${x}, ${y});\n } else {\n console.log('midsceneWaterFlowAnimation is not defined');\n }\n })()`;\n\n await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `${pointerScript}`,\n });\n }\n\n private async hideMousePointer() {\n await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n if(typeof window.midsceneWaterFlowAnimation !== 'undefined') {\n window.midsceneWaterFlowAnimation.hideMousePointer();\n }\n })()`,\n });\n }\n\n /**\n * Public method to detach debugger without destroying the page instance.\n * Useful for error recovery scenarios where we want to remove the debugger banner\n * without completely destroying the page.\n */\n public async detachDebugger(tabId?: number) {\n const tabIdToDetach = tabId || (await this.getTabIdOrConnectToCurrentTab());\n console.log('detaching debugger from tab:', tabIdToDetach);\n\n try {\n await this.disableWaterFlowAnimation(tabIdToDetach);\n await sleep(200); // wait for the animation to stop\n } catch (error) {\n console.warn('Failed to disable water flow animation', error);\n }\n\n try {\n await chrome.debugger.detach({ tabId: tabIdToDetach });\n console.log('Debugger detached successfully from tab:', tabIdToDetach);\n } catch (error) {\n // Tab might be closed or debugger already detached - this is OK\n console.warn(\n 'Failed to detach debugger (may already be detached):',\n error,\n );\n }\n }\n\n private async enableWaterFlowAnimation() {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n\n // limit open page in new tab\n if (this.forceSameTabNavigation) {\n await chrome.debugger.sendCommand({ tabId }, 'Runtime.evaluate', {\n expression: limitOpenNewTabScript,\n });\n }\n\n const script = await injectWaterFlowAnimation();\n // we will call this function in sendCommandToDebugger, so we have to use the chrome.debugger.sendCommand\n await chrome.debugger.sendCommand({ tabId }, 'Runtime.evaluate', {\n expression: script,\n });\n }\n\n private async disableWaterFlowAnimation(tabId: number) {\n const script = await injectStopWaterFlowAnimation();\n\n await chrome.debugger.sendCommand({ tabId }, 'Runtime.evaluate', {\n expression: script,\n });\n }\n\n /**\n * Send a command to the debugger with automatic attach and retry on detachment.\n * Uses lazy attach pattern - will automatically attach if not already attached.\n */\n private async sendCommandToDebugger<ResponseType = any, RequestType = any>(\n command: string,\n params: RequestType,\n retryCount = 0,\n ): Promise<ResponseType> {\n const MAX_RETRIES = 2;\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n\n try {\n // Try to send command directly first\n const result = (await chrome.debugger.sendCommand(\n { tabId },\n command,\n params as any,\n )) as ResponseType;\n\n // Enable water flow animation after successful command (don't await)\n this.enableWaterFlowAnimation().catch((err) => {\n console.warn('Failed to enable water flow animation:', err);\n });\n\n return result;\n } catch (error) {\n // If command failed, check if it's because debugger is not attached\n const errorMsg = (error as Error)?.message || '';\n const isDetachError =\n errorMsg.includes('Debugger is not attached') ||\n errorMsg.includes('Cannot access a Target') ||\n errorMsg.includes('No target with given id');\n\n if (isDetachError && retryCount < MAX_RETRIES) {\n console.log(\n `Debugger not attached for command \"${command}\", attempting to attach (retry ${retryCount + 1}/${MAX_RETRIES})`,\n );\n\n // Try to attach and retry\n await this.ensureDebuggerAttached();\n\n return this.sendCommandToDebugger<ResponseType, RequestType>(\n command,\n params,\n retryCount + 1,\n );\n }\n\n // Not a detach error or out of retries\n throw error;\n }\n }\n\n private async getPageContentByCDP() {\n const script = await getHtmlElementScript();\n\n // check tab url\n await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: script,\n });\n\n const expression = () => {\n const tree = (\n window as any\n ).midscene_element_inspector.webExtractNodeTree();\n\n return {\n tree,\n size: {\n width: document.documentElement.clientWidth,\n height: document.documentElement.clientHeight,\n dpr: window.devicePixelRatio,\n },\n };\n };\n const returnValue = await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: `(${expression.toString()})()`,\n returnByValue: true,\n });\n\n if (!returnValue.result.value) {\n const errorDescription =\n returnValue.exceptionDetails?.exception?.description || '';\n if (!errorDescription) {\n console.error('returnValue from cdp', returnValue);\n }\n throw new Error(\n `Failed to get page content from page, error: ${errorDescription}`,\n );\n }\n\n return returnValue.result.value as {\n tree: ElementTreeNode<ElementInfo>;\n size: Size;\n };\n }\n\n public async evaluateJavaScript(script: string) {\n return this.sendCommandToDebugger('Runtime.evaluate', {\n expression: script,\n awaitPromise: true,\n });\n }\n\n async beforeInvokeAction(): Promise<void> {\n // current implementation is wait until domReadyState is complete\n try {\n await this.waitUntilNetworkIdle();\n } catch (error) {\n // console.warn('Failed to wait until network idle', error);\n }\n }\n\n private async waitUntilNetworkIdle() {\n const timeout = 10000;\n const startTime = Date.now();\n let lastReadyState = '';\n while (Date.now() - startTime < timeout) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: 'document.readyState',\n });\n lastReadyState = result.result.value;\n if (lastReadyState === 'complete') {\n await new Promise((resolve) => setTimeout(resolve, 300));\n return;\n }\n await new Promise((resolve) => setTimeout(resolve, 300));\n }\n throw new Error(\n `Failed to wait until network idle, last readyState: ${lastReadyState}`,\n );\n }\n\n // @deprecated\n async getElementsInfo() {\n const tree = await this.getElementsNodeTree();\n return treeToList(tree);\n }\n\n async getXpathsByPoint(point: Point, isOrderSensitive = false) {\n const script = await getHtmlElementScript();\n\n await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: script,\n });\n\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `window.midscene_element_inspector.getXpathsByPoint({left: ${point.left}, top: ${point.top}}, ${isOrderSensitive})`,\n returnByValue: true,\n });\n return result.result.value;\n }\n\n async getElementInfoByXpath(xpath: string) {\n const script = await getHtmlElementScript();\n\n // check tab url\n await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: script,\n });\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `window.midscene_element_inspector.getElementInfoByXpath(${JSON.stringify(xpath)})`,\n returnByValue: true,\n });\n return result.result.value;\n }\n\n async getElementsNodeTree() {\n await this.hideMousePointer();\n const content = await this.getPageContentByCDP();\n if (content?.size) {\n this.viewportSize = content.size;\n }\n\n return content?.tree || { node: null, children: [] };\n }\n\n async getContext(): Promise<UIContext> {\n return await WebPageContextParser(this, {});\n }\n\n async size() {\n if (this.viewportSize) return this.viewportSize;\n\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression:\n '({width: document.documentElement.clientWidth, height: document.documentElement.clientHeight, dpr: window.devicePixelRatio})',\n returnByValue: true,\n });\n\n const sizeInfo: Size = result.result.value;\n console.log('sizeInfo', sizeInfo);\n\n this.viewportSize = sizeInfo;\n return sizeInfo;\n }\n\n async screenshotBase64() {\n // screenshot by cdp\n await this.hideMousePointer();\n const format = 'jpeg';\n const base64 = await this.sendCommandToDebugger('Page.captureScreenshot', {\n format,\n quality: 90,\n });\n return createImgBase64ByFormat(format, base64.data);\n }\n\n async url() {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n const url = await chrome.tabs.get(tabId).then((tab) => tab.url);\n return url || '';\n }\n\n async navigate(url: string): Promise<void> {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n await chrome.tabs.update(tabId, { url });\n // Wait for navigation to complete\n // Note: debugger will auto-reattach on next command if detached during navigation\n await this.waitUntilNetworkIdle();\n }\n\n async reload(): Promise<void> {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n await chrome.tabs.reload(tabId);\n // Wait for reload to complete\n await this.waitUntilNetworkIdle();\n }\n\n async goBack(): Promise<void> {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n await chrome.tabs.goBack(tabId);\n // Wait for navigation to complete\n await this.waitUntilNetworkIdle();\n }\n\n async scrollUntilTop(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(0, -9999999);\n }\n\n async scrollUntilBottom(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(0, 9999999);\n }\n\n async scrollUntilLeft(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(-9999999, 0);\n }\n\n async scrollUntilRight(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(9999999, 0);\n }\n\n async scrollUp(distance?: number, startingPoint?: Point) {\n const { height } = await this.size();\n const scrollDistance = distance || height * 0.7;\n return this.mouse.wheel(\n 0,\n -scrollDistance,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async scrollDown(distance?: number, startingPoint?: Point) {\n const { height } = await this.size();\n const scrollDistance = distance || height * 0.7;\n return this.mouse.wheel(\n 0,\n scrollDistance,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async scrollLeft(distance?: number, startingPoint?: Point) {\n const { width } = await this.size();\n const scrollDistance = distance || width * 0.7;\n return this.mouse.wheel(\n -scrollDistance,\n 0,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async scrollRight(distance?: number, startingPoint?: Point) {\n const { width } = await this.size();\n const scrollDistance = distance || width * 0.7;\n return this.mouse.wheel(\n scrollDistance,\n 0,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async clearInput(element: ElementInfo) {\n if (!element) {\n console.warn('No element to clear input');\n return;\n }\n\n await this.mouse.click(element.center[0], element.center[1]);\n\n await this.sendCommandToDebugger('Input.dispatchKeyEvent', {\n type: 'keyDown',\n commands: ['selectAll'],\n });\n\n await this.sendCommandToDebugger('Input.dispatchKeyEvent', {\n type: 'keyUp',\n commands: ['selectAll'],\n });\n\n await sleep(100);\n\n await this.keyboard.press({\n key: 'Backspace',\n });\n }\n\n private latestMouseX = 100;\n private latestMouseY = 100;\n\n mouse = {\n click: async (\n x: number,\n y: number,\n options?: { button?: MouseButton; count?: number },\n ) => {\n const { button = 'left', count = 1 } = options || {};\n await this.mouse.move(x, y);\n // detect if the page is in mobile emulation mode\n if (this.isMobileEmulation === null) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);\n })()`,\n returnByValue: true,\n });\n this.isMobileEmulation = result?.result?.value;\n }\n\n if (this.isMobileEmulation && button === 'left') {\n // in mobile emulation mode, directly inject click event\n const touchPoints = [{ x: Math.round(x), y: Math.round(y) }];\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchStart',\n touchPoints,\n modifiers: 0,\n });\n\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchEnd',\n touchPoints: [],\n modifiers: 0,\n });\n } else {\n // standard mousePressed + mouseReleased\n for (let i = 0; i < count; i++) {\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x,\n y,\n button,\n clickCount: 1,\n });\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x,\n y,\n button,\n clickCount: 1,\n });\n await sleep(50);\n }\n }\n },\n wheel: async (\n deltaX: number,\n deltaY: number,\n startX?: number,\n startY?: number,\n ) => {\n const finalX = startX || this.latestMouseX;\n const finalY = startY || this.latestMouseY;\n await this.showMousePointer(finalX, finalY);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseWheel',\n x: finalX,\n y: finalY,\n deltaX,\n deltaY,\n });\n this.latestMouseX = finalX;\n this.latestMouseY = finalY;\n },\n move: async (x: number, y: number) => {\n await this.showMousePointer(x, y);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseMoved',\n x,\n y,\n });\n this.latestMouseX = x;\n this.latestMouseY = y;\n },\n drag: async (\n from: { x: number; y: number },\n to: { x: number; y: number },\n ) => {\n await this.mouse.move(from.x, from.y);\n\n await sleep(200);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x: from.x,\n y: from.y,\n button: 'left',\n clickCount: 1,\n });\n\n await sleep(300);\n\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseMoved',\n x: to.x,\n y: to.y,\n });\n\n await sleep(500);\n\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x: to.x,\n y: to.y,\n button: 'left',\n clickCount: 1,\n });\n\n await sleep(200);\n\n await this.mouse.move(to.x, to.y);\n },\n };\n\n keyboard = {\n type: async (text: string) => {\n const cdpKeyboard = new CdpKeyboard({\n send: this.sendCommandToDebugger.bind(this),\n });\n await cdpKeyboard.type(text, { delay: 0 });\n },\n press: async (\n action:\n | { key: KeyInput; command?: string }\n | { key: KeyInput; command?: string }[],\n ) => {\n const cdpKeyboard = new CdpKeyboard({\n send: this.sendCommandToDebugger.bind(this),\n });\n const keys = Array.isArray(action) ? action : [action];\n for (const k of keys) {\n const commands = k.command ? [k.command] : [];\n await cdpKeyboard.down(k.key, { commands });\n }\n for (const k of [...keys].reverse()) {\n await cdpKeyboard.up(k.key);\n }\n },\n };\n\n async destroy(): Promise<void> {\n this.destroyed = true;\n this.activeTabId = null;\n await this.detachDebugger();\n }\n\n async longPress(x: number, y: number, duration?: number) {\n duration = duration || 500;\n const LONG_PRESS_THRESHOLD = 600;\n const MIN_PRESS_THRESHOLD = 300;\n if (duration > LONG_PRESS_THRESHOLD) {\n duration = LONG_PRESS_THRESHOLD;\n }\n if (duration < MIN_PRESS_THRESHOLD) {\n duration = MIN_PRESS_THRESHOLD;\n }\n await this.mouse.move(x, y);\n\n if (this.isMobileEmulation === null) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);\n })()`,\n returnByValue: true,\n });\n this.isMobileEmulation = result?.result?.value;\n }\n\n if (this.isMobileEmulation) {\n const touchPoints = [{ x: Math.round(x), y: Math.round(y) }];\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchStart',\n touchPoints,\n modifiers: 0,\n });\n await new Promise((res) => setTimeout(res, duration));\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchEnd',\n touchPoints: [],\n modifiers: 0,\n });\n } else {\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x,\n y,\n button: 'left',\n clickCount: 1,\n });\n await new Promise((res) => setTimeout(res, duration));\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x,\n y,\n button: 'left',\n clickCount: 1,\n });\n }\n this.latestMouseX = x;\n this.latestMouseY = y;\n }\n\n async swipe(\n from: { x: number; y: number },\n to: { x: number; y: number },\n duration?: number,\n ) {\n const LONG_PRESS_THRESHOLD = 500;\n const MIN_PRESS_THRESHOLD = 150;\n duration = duration || 300;\n if (duration < MIN_PRESS_THRESHOLD) {\n duration = MIN_PRESS_THRESHOLD;\n }\n if (duration > LONG_PRESS_THRESHOLD) {\n duration = LONG_PRESS_THRESHOLD;\n }\n\n if (this.isMobileEmulation === null) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);\n })()`,\n returnByValue: true,\n });\n this.isMobileEmulation = result?.result?.value;\n }\n\n const steps = 30;\n const delay = duration / steps;\n\n if (this.isMobileEmulation) {\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchStart',\n touchPoints: [{ x: Math.round(from.x), y: Math.round(from.y) }],\n modifiers: 0,\n });\n\n for (let i = 1; i <= steps; i++) {\n const x = from.x + (to.x - from.x) * (i / steps);\n const y = from.y + (to.y - from.y) * (i / steps);\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchMove',\n touchPoints: [{ x: Math.round(x), y: Math.round(y) }],\n modifiers: 0,\n });\n await new Promise((res) => setTimeout(res, delay));\n }\n\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchEnd',\n touchPoints: [],\n modifiers: 0,\n });\n } else {\n await this.mouse.move(from.x, from.y);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x: from.x,\n y: from.y,\n button: 'left',\n clickCount: 1,\n });\n\n for (let i = 1; i <= steps; i++) {\n const x = from.x + (to.x - from.x) * (i / steps);\n const y = from.y + (to.y - from.y) * (i / steps);\n await this.mouse.move(x, y);\n await new Promise((res) => setTimeout(res, delay));\n }\n\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x: to.x,\n y: to.y,\n button: 'left',\n clickCount: 1,\n });\n }\n\n this.latestMouseX = to.x;\n this.latestMouseY = to.y;\n }\n}\n"],"names":["sleep","ms","Promise","resolve","setTimeout","ChromeExtensionProxyPage","commonWebActionsForWebPage","tabId","Error","chrome","tabs","tab","assert","url","console","error","errorMsg","x","y","pointerScript","tabIdToDetach","limitOpenNewTabScript","script","injectWaterFlowAnimation","injectStopWaterFlowAnimation","command","params","retryCount","MAX_RETRIES","result","err","isDetachError","getHtmlElementScript","expression","tree","window","document","returnValue","errorDescription","timeout","startTime","Date","lastReadyState","treeToList","point","isOrderSensitive","xpath","JSON","content","WebPageContextParser","sizeInfo","format","base64","createImgBase64ByFormat","startingPoint","distance","height","scrollDistance","width","element","duration","LONG_PRESS_THRESHOLD","MIN_PRESS_THRESHOLD","touchPoints","Math","res","from","to","steps","delay","i","forceSameTabNavigation","options","button","count","deltaX","deltaY","startX","startY","finalX","finalY","text","cdpKeyboard","CdpKeyboard","action","keys","Array","k","commands"],"mappings":";;;;;;;AAKA;;;;;;;;;;AAuBA,SAASA,MAAMC,EAAU;IACvB,OAAO,IAAIC,QAAQ,CAACC,UAAYC,WAAWD,SAASF;AACtD;AAEe,MAAMI;IAmBnB,cAA8B;QAC5B,OAAOC,2BAA2B,IAAI;IACxC;IAEA,MAAa,eAAeC,KAAa,EAAE;QACzC,IAAI,IAAI,CAAC,WAAW,EAClB,MAAM,IAAIC,MACR,CAAC,uCAAuC,EAAE,IAAI,CAAC,WAAW,CAAC,mBAAmB,EAAED,OAAO;QAG3F,MAAME,OAAO,IAAI,CAAC,MAAM,CAACF,OAAO;YAAE,QAAQ;QAAK;QAC/C,IAAI,CAAC,WAAW,GAAGA;IACrB;IAEA,MAAa,iBAAiB;QAC5B,OAAO,IAAI,CAAC,WAAW;IACzB;IAMA,MAAa,oBAEX;QACA,MAAMG,OAAO,MAAMD,OAAO,IAAI,CAAC,KAAK,CAAC;YAAE,eAAe;QAAK;QAC3D,OAAOC,KACJ,GAAG,CAAC,CAACC,MAAS;gBACb,IAAI,GAAGA,IAAI,EAAE,EAAE;gBACf,OAAOA,IAAI,KAAK;gBAChB,KAAKA,IAAI,GAAG;gBACZ,kBAAkBA,IAAI,MAAM;YAC9B,IACC,MAAM,CAAC,CAACA,MAAQA,IAAI,EAAE,IAAIA,IAAI,KAAK,IAAIA,IAAI,GAAG;IAMnD;IAEA,MAAa,gCAAgC;QAC3C,IAAI,IAAI,CAAC,WAAW,EAElB,OAAO,IAAI,CAAC,WAAW;QAEzB,MAAMJ,QAAQ,MAAME,OAAO,IAAI,CAC5B,KAAK,CAAC;YAAE,QAAQ;YAAM,eAAe;QAAK,GAC1C,IAAI,CAAC,CAACC,OAASA,IAAI,CAAC,EAAE,EAAE;QAC3B,IAAI,CAAC,WAAW,GAAGH,SAAS;QAC5B,OAAO,IAAI,CAAC,WAAW;IACzB;IAMA,MAAc,yBAAyB;QACrCK,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE;QAExB,MAAMC,MAAM,MAAM,IAAI,CAAC,GAAG;QAC1B,IAAIA,IAAI,UAAU,CAAC,cACjB,MAAM,IAAIL,MACR;QAIJ,MAAMD,QAAQ,MAAM,IAAI,CAAC,6BAA6B;QAEtD,IAAI;YACF,MAAME,OAAO,QAAQ,CAAC,MAAM,CAAC;gBAAEF;YAAM,GAAG;YACxCO,QAAQ,GAAG,CAAC,6BAA6BP;QAC3C,EAAE,OAAOQ,OAAO;YACd,MAAMC,WAAYD,OAAiB,WAAW;YAE9C,IAAIC,SAAS,QAAQ,CAAC,yCAAyC,YAC7DF,QAAQ,GAAG,CAAC,qCAAqCP;YAInD,IAAI,IAAI,CAAC,mCAAmC,EAAE,YAC5CO,QAAQ,IAAI,CACV,6FACAC;YAKJ,MAAMA;QACR;QAGA,MAAMf,MAAM;QAGZ,MAAM,IAAI,CAAC,wBAAwB;IACrC;IAEA,MAAc,iBAAiBiB,CAAS,EAAEC,CAAS,EAAE;QAEnD,MAAMC,gBAAgB,CAAC;;;2DAGgC,EAAEF,EAAE,EAAE,EAAEC,EAAE;;;;QAI7D,CAAC;QAEL,MAAM,IAAI,CAAC,qBAAqB,CAAC,oBAAoB;YACnD,YAAY,GAAGC,eAAe;QAChC;IACF;IAEA,MAAc,mBAAmB;QAC/B,MAAM,IAAI,CAAC,qBAAqB,CAAC,oBAAoB;YACnD,YAAY,CAAC;;;;UAIT,CAAC;QACP;IACF;IAOA,MAAa,eAAeZ,KAAc,EAAE;QAC1C,MAAMa,gBAAgBb,SAAU,MAAM,IAAI,CAAC,6BAA6B;QACxEO,QAAQ,GAAG,CAAC,gCAAgCM;QAE5C,IAAI;YACF,MAAM,IAAI,CAAC,yBAAyB,CAACA;YACrC,MAAMpB,MAAM;QACd,EAAE,OAAOe,OAAO;YACdD,QAAQ,IAAI,CAAC,0CAA0CC;QACzD;QAEA,IAAI;YACF,MAAMN,OAAO,QAAQ,CAAC,MAAM,CAAC;gBAAE,OAAOW;YAAc;YACpDN,QAAQ,GAAG,CAAC,4CAA4CM;QAC1D,EAAE,OAAOL,OAAO;YAEdD,QAAQ,IAAI,CACV,wDACAC;QAEJ;IACF;IAEA,MAAc,2BAA2B;QACvC,MAAMR,QAAQ,MAAM,IAAI,CAAC,6BAA6B;QAGtD,IAAI,IAAI,CAAC,sBAAsB,EAC7B,MAAME,OAAO,QAAQ,CAAC,WAAW,CAAC;YAAEF;QAAM,GAAG,oBAAoB;YAC/D,YAAYc;QACd;QAGF,MAAMC,SAAS,MAAMC;QAErB,MAAMd,OAAO,QAAQ,CAAC,WAAW,CAAC;YAAEF;QAAM,GAAG,oBAAoB;YAC/D,YAAYe;QACd;IACF;IAEA,MAAc,0BAA0Bf,KAAa,EAAE;QACrD,MAAMe,SAAS,MAAME;QAErB,MAAMf,OAAO,QAAQ,CAAC,WAAW,CAAC;YAAEF;QAAM,GAAG,oBAAoB;YAC/D,YAAYe;QACd;IACF;IAMA,MAAc,sBACZG,OAAe,EACfC,MAAmB,EACnBC,aAAa,CAAC,EACS;QACvB,MAAMC,cAAc;QACpB,MAAMrB,QAAQ,MAAM,IAAI,CAAC,6BAA6B;QAEtD,IAAI;YAEF,MAAMsB,SAAU,MAAMpB,OAAO,QAAQ,CAAC,WAAW,CAC/C;gBAAEF;YAAM,GACRkB,SACAC;YAIF,IAAI,CAAC,wBAAwB,GAAG,KAAK,CAAC,CAACI;gBACrChB,QAAQ,IAAI,CAAC,0CAA0CgB;YACzD;YAEA,OAAOD;QACT,EAAE,OAAOd,OAAO;YAEd,MAAMC,WAAYD,OAAiB,WAAW;YAC9C,MAAMgB,gBACJf,SAAS,QAAQ,CAAC,+BAClBA,SAAS,QAAQ,CAAC,6BAClBA,SAAS,QAAQ,CAAC;YAEpB,IAAIe,iBAAiBJ,aAAaC,aAAa;gBAC7Cd,QAAQ,GAAG,CACT,CAAC,mCAAmC,EAAEW,QAAQ,+BAA+B,EAAEE,aAAa,EAAE,CAAC,EAAEC,YAAY,CAAC,CAAC;gBAIjH,MAAM,IAAI,CAAC,sBAAsB;gBAEjC,OAAO,IAAI,CAAC,qBAAqB,CAC/BH,SACAC,QACAC,aAAa;YAEjB;YAGA,MAAMZ;QACR;IACF;IAEA,MAAc,sBAAsB;QAClC,MAAMO,SAAS,MAAMU;QAGrB,MAAM,IAAI,CAAC,qBAAqB,CAG9B,oBAAoB;YACpB,YAAYV;QACd;QAEA,MAAMW,aAAa;YACjB,MAAMC,OACJC,OACA,0BAA0B,CAAC,kBAAkB;YAE/C,OAAO;gBACLD;gBACA,MAAM;oBACJ,OAAOE,SAAS,eAAe,CAAC,WAAW;oBAC3C,QAAQA,SAAS,eAAe,CAAC,YAAY;oBAC7C,KAAKD,OAAO,gBAAgB;gBAC9B;YACF;QACF;QACA,MAAME,cAAc,MAAM,IAAI,CAAC,qBAAqB,CAGlD,oBAAoB;YACpB,YAAY,CAAC,CAAC,EAAEJ,WAAW,QAAQ,GAAG,GAAG,CAAC;YAC1C,eAAe;QACjB;QAEA,IAAI,CAACI,YAAY,MAAM,CAAC,KAAK,EAAE;YAC7B,MAAMC,mBACJD,YAAY,gBAAgB,EAAE,WAAW,eAAe;YAC1D,IAAI,CAACC,kBACHxB,QAAQ,KAAK,CAAC,wBAAwBuB;YAExC,MAAM,IAAI7B,MACR,CAAC,6CAA6C,EAAE8B,kBAAkB;QAEtE;QAEA,OAAOD,YAAY,MAAM,CAAC,KAAK;IAIjC;IAEA,MAAa,mBAAmBf,MAAc,EAAE;QAC9C,OAAO,IAAI,CAAC,qBAAqB,CAAC,oBAAoB;YACpD,YAAYA;YACZ,cAAc;QAChB;IACF;IAEA,MAAM,qBAAoC;QAExC,IAAI;YACF,MAAM,IAAI,CAAC,oBAAoB;QACjC,EAAE,OAAOP,OAAO,CAEhB;IACF;IAEA,MAAc,uBAAuB;QACnC,MAAMwB,UAAU;QAChB,MAAMC,YAAYC,KAAK,GAAG;QAC1B,IAAIC,iBAAiB;QACrB,MAAOD,KAAK,GAAG,KAAKD,YAAYD,QAAS;YACvC,MAAMV,SAAS,MAAM,IAAI,CAAC,qBAAqB,CAAC,oBAAoB;gBAClE,YAAY;YACd;YACAa,iBAAiBb,OAAO,MAAM,CAAC,KAAK;YACpC,IAAIa,AAAmB,eAAnBA,gBAA+B,YACjC,MAAM,IAAIxC,QAAQ,CAACC,UAAYC,WAAWD,SAAS;YAGrD,MAAM,IAAID,QAAQ,CAACC,UAAYC,WAAWD,SAAS;QACrD;QACA,MAAM,IAAIK,MACR,CAAC,oDAAoD,EAAEkC,gBAAgB;IAE3E;IAGA,MAAM,kBAAkB;QACtB,MAAMR,OAAO,MAAM,IAAI,CAAC,mBAAmB;QAC3C,OAAOS,WAAWT;IACpB;IAEA,MAAM,iBAAiBU,KAAY,EAAEC,mBAAmB,KAAK,EAAE;QAC7D,MAAMvB,SAAS,MAAMU;QAErB,MAAM,IAAI,CAAC,qBAAqB,CAG9B,oBAAoB;YACpB,YAAYV;QACd;QAEA,MAAMO,SAAS,MAAM,IAAI,CAAC,qBAAqB,CAAC,oBAAoB;YAClE,YAAY,CAAC,0DAA0D,EAAEe,MAAM,IAAI,CAAC,OAAO,EAAEA,MAAM,GAAG,CAAC,GAAG,EAAEC,iBAAiB,CAAC,CAAC;YAC/H,eAAe;QACjB;QACA,OAAOhB,OAAO,MAAM,CAAC,KAAK;IAC5B;IAEA,MAAM,sBAAsBiB,KAAa,EAAE;QACzC,MAAMxB,SAAS,MAAMU;QAGrB,MAAM,IAAI,CAAC,qBAAqB,CAG9B,oBAAoB;YACpB,YAAYV;QACd;QACA,MAAMO,SAAS,MAAM,IAAI,CAAC,qBAAqB,CAAC,oBAAoB;YAClE,YAAY,CAAC,wDAAwD,EAAEkB,KAAK,SAAS,CAACD,OAAO,CAAC,CAAC;YAC/F,eAAe;QACjB;QACA,OAAOjB,OAAO,MAAM,CAAC,KAAK;IAC5B;IAEA,MAAM,sBAAsB;QAC1B,MAAM,IAAI,CAAC,gBAAgB;QAC3B,MAAMmB,UAAU,MAAM,IAAI,CAAC,mBAAmB;QAC9C,IAAIA,SAAS,MACX,IAAI,CAAC,YAAY,GAAGA,QAAQ,IAAI;QAGlC,OAAOA,SAAS,QAAQ;YAAE,MAAM;YAAM,UAAU,EAAE;QAAC;IACrD;IAEA,MAAM,aAAiC;QACrC,OAAO,MAAMC,qBAAqB,IAAI,EAAE,CAAC;IAC3C;IAEA,MAAM,OAAO;QACX,IAAI,IAAI,CAAC,YAAY,EAAE,OAAO,IAAI,CAAC,YAAY;QAE/C,MAAMpB,SAAS,MAAM,IAAI,CAAC,qBAAqB,CAAC,oBAAoB;YAClE,YACE;YACF,eAAe;QACjB;QAEA,MAAMqB,WAAiBrB,OAAO,MAAM,CAAC,KAAK;QAC1Cf,QAAQ,GAAG,CAAC,YAAYoC;QAExB,IAAI,CAAC,YAAY,GAAGA;QACpB,OAAOA;IACT;IAEA,MAAM,mBAAmB;QAEvB,MAAM,IAAI,CAAC,gBAAgB;QAC3B,MAAMC,SAAS;QACf,MAAMC,SAAS,MAAM,IAAI,CAAC,qBAAqB,CAAC,0BAA0B;YACxED;YACA,SAAS;QACX;QACA,OAAOE,wBAAwBF,QAAQC,OAAO,IAAI;IACpD;IAEA,MAAM,MAAM;QACV,MAAM7C,QAAQ,MAAM,IAAI,CAAC,6BAA6B;QACtD,MAAMM,MAAM,MAAMJ,OAAO,IAAI,CAAC,GAAG,CAACF,OAAO,IAAI,CAAC,CAACI,MAAQA,IAAI,GAAG;QAC9D,OAAOE,OAAO;IAChB;IAEA,MAAM,SAASA,GAAW,EAAiB;QACzC,MAAMN,QAAQ,MAAM,IAAI,CAAC,6BAA6B;QACtD,MAAME,OAAO,IAAI,CAAC,MAAM,CAACF,OAAO;YAAEM;QAAI;QAGtC,MAAM,IAAI,CAAC,oBAAoB;IACjC;IAEA,MAAM,SAAwB;QAC5B,MAAMN,QAAQ,MAAM,IAAI,CAAC,6BAA6B;QACtD,MAAME,OAAO,IAAI,CAAC,MAAM,CAACF;QAEzB,MAAM,IAAI,CAAC,oBAAoB;IACjC;IAEA,MAAM,SAAwB;QAC5B,MAAMA,QAAQ,MAAM,IAAI,CAAC,6BAA6B;QACtD,MAAME,OAAO,IAAI,CAAC,MAAM,CAACF;QAEzB,MAAM,IAAI,CAAC,oBAAoB;IACjC;IAEA,MAAM,eAAe+C,aAAqB,EAAE;QAC1C,IAAIA,eACF,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAACA,cAAc,IAAI,EAAEA,cAAc,GAAG;QAE7D,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG;IAC7B;IAEA,MAAM,kBAAkBA,aAAqB,EAAE;QAC7C,IAAIA,eACF,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAACA,cAAc,IAAI,EAAEA,cAAc,GAAG;QAE7D,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG;IAC7B;IAEA,MAAM,gBAAgBA,aAAqB,EAAE;QAC3C,IAAIA,eACF,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAACA,cAAc,IAAI,EAAEA,cAAc,GAAG;QAE7D,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU;IACpC;IAEA,MAAM,iBAAiBA,aAAqB,EAAE;QAC5C,IAAIA,eACF,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAACA,cAAc,IAAI,EAAEA,cAAc,GAAG;QAE7D,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS;IACnC;IAEA,MAAM,SAASC,QAAiB,EAAED,aAAqB,EAAE;QACvD,MAAM,EAAEE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI;QAClC,MAAMC,iBAAiBF,YAAYC,AAAS,MAATA;QACnC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CACrB,GACA,CAACC,gBACDH,eAAe,MACfA,eAAe;IAEnB;IAEA,MAAM,WAAWC,QAAiB,EAAED,aAAqB,EAAE;QACzD,MAAM,EAAEE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI;QAClC,MAAMC,iBAAiBF,YAAYC,AAAS,MAATA;QACnC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CACrB,GACAC,gBACAH,eAAe,MACfA,eAAe;IAEnB;IAEA,MAAM,WAAWC,QAAiB,EAAED,aAAqB,EAAE;QACzD,MAAM,EAAEI,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI;QACjC,MAAMD,iBAAiBF,YAAYG,AAAQ,MAARA;QACnC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CACrB,CAACD,gBACD,GACAH,eAAe,MACfA,eAAe;IAEnB;IAEA,MAAM,YAAYC,QAAiB,EAAED,aAAqB,EAAE;QAC1D,MAAM,EAAEI,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI;QACjC,MAAMD,iBAAiBF,YAAYG,AAAQ,MAARA;QACnC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CACrBD,gBACA,GACAH,eAAe,MACfA,eAAe;IAEnB;IAEA,MAAM,WAAWK,OAAoB,EAAE;QACrC,IAAI,CAACA,SAAS,YACZ7C,QAAQ,IAAI,CAAC;QAIf,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC6C,QAAQ,MAAM,CAAC,EAAE,EAAEA,QAAQ,MAAM,CAAC,EAAE;QAE3D,MAAM,IAAI,CAAC,qBAAqB,CAAC,0BAA0B;YACzD,MAAM;YACN,UAAU;gBAAC;aAAY;QACzB;QAEA,MAAM,IAAI,CAAC,qBAAqB,CAAC,0BAA0B;YACzD,MAAM;YACN,UAAU;gBAAC;aAAY;QACzB;QAEA,MAAM3D,MAAM;QAEZ,MAAM,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YACxB,KAAK;QACP;IACF;IAyJA,MAAM,UAAyB;QAC7B,IAAI,CAAC,SAAS,GAAG;QACjB,IAAI,CAAC,WAAW,GAAG;QACnB,MAAM,IAAI,CAAC,cAAc;IAC3B;IAEA,MAAM,UAAUiB,CAAS,EAAEC,CAAS,EAAE0C,QAAiB,EAAE;QACvDA,WAAWA,YAAY;QACvB,MAAMC,uBAAuB;QAC7B,MAAMC,sBAAsB;QAC5B,IAAIF,WAAWC,sBACbD,WAAWC;QAEb,IAAID,WAAWE,qBACbF,WAAWE;QAEb,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC7C,GAAGC;QAEzB,IAAI,AAA2B,SAA3B,IAAI,CAAC,iBAAiB,EAAW;YACnC,MAAMW,SAAS,MAAM,IAAI,CAAC,qBAAqB,CAAC,oBAAoB;gBAClE,YAAY,CAAC;;YAET,CAAC;gBACL,eAAe;YACjB;YACA,IAAI,CAAC,iBAAiB,GAAGA,QAAQ,QAAQ;QAC3C;QAEA,IAAI,IAAI,CAAC,iBAAiB,EAAE;YAC1B,MAAMkC,cAAc;gBAAC;oBAAE,GAAGC,KAAK,KAAK,CAAC/C;oBAAI,GAAG+C,KAAK,KAAK,CAAC9C;gBAAG;aAAE;YAC5D,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;gBAC3D,MAAM;gBACN6C;gBACA,WAAW;YACb;YACA,MAAM,IAAI7D,QAAQ,CAAC+D,MAAQ7D,WAAW6D,KAAKL;YAC3C,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;gBAC3D,MAAM;gBACN,aAAa,EAAE;gBACf,WAAW;YACb;QACF,OAAO;YACL,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;gBAC3D,MAAM;gBACN3C;gBACAC;gBACA,QAAQ;gBACR,YAAY;YACd;YACA,MAAM,IAAIhB,QAAQ,CAAC+D,MAAQ7D,WAAW6D,KAAKL;YAC3C,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;gBAC3D,MAAM;gBACN3C;gBACAC;gBACA,QAAQ;gBACR,YAAY;YACd;QACF;QACA,IAAI,CAAC,YAAY,GAAGD;QACpB,IAAI,CAAC,YAAY,GAAGC;IACtB;IAEA,MAAM,MACJgD,IAA8B,EAC9BC,EAA4B,EAC5BP,QAAiB,EACjB;QACA,MAAMC,uBAAuB;QAC7B,MAAMC,sBAAsB;QAC5BF,WAAWA,YAAY;QACvB,IAAIA,WAAWE,qBACbF,WAAWE;QAEb,IAAIF,WAAWC,sBACbD,WAAWC;QAGb,IAAI,AAA2B,SAA3B,IAAI,CAAC,iBAAiB,EAAW;YACnC,MAAMhC,SAAS,MAAM,IAAI,CAAC,qBAAqB,CAAC,oBAAoB;gBAClE,YAAY,CAAC;;YAET,CAAC;gBACL,eAAe;YACjB;YACA,IAAI,CAAC,iBAAiB,GAAGA,QAAQ,QAAQ;QAC3C;QAEA,MAAMuC,QAAQ;QACd,MAAMC,QAAQT,WAAWQ;QAEzB,IAAI,IAAI,CAAC,iBAAiB,EAAE;YAC1B,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;gBAC3D,MAAM;gBACN,aAAa;oBAAC;wBAAE,GAAGJ,KAAK,KAAK,CAACE,KAAK,CAAC;wBAAG,GAAGF,KAAK,KAAK,CAACE,KAAK,CAAC;oBAAE;iBAAE;gBAC/D,WAAW;YACb;YAEA,IAAK,IAAII,IAAI,GAAGA,KAAKF,OAAOE,IAAK;gBAC/B,MAAMrD,IAAIiD,KAAK,CAAC,GAAIC,AAAAA,CAAAA,GAAG,CAAC,GAAGD,KAAK,CAAC,AAAD,IAAMI,CAAAA,IAAIF,KAAI;gBAC9C,MAAMlD,IAAIgD,KAAK,CAAC,GAAIC,AAAAA,CAAAA,GAAG,CAAC,GAAGD,KAAK,CAAC,AAAD,IAAMI,CAAAA,IAAIF,KAAI;gBAC9C,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;oBAC3D,MAAM;oBACN,aAAa;wBAAC;4BAAE,GAAGJ,KAAK,KAAK,CAAC/C;4BAAI,GAAG+C,KAAK,KAAK,CAAC9C;wBAAG;qBAAE;oBACrD,WAAW;gBACb;gBACA,MAAM,IAAIhB,QAAQ,CAAC+D,MAAQ7D,WAAW6D,KAAKI;YAC7C;YAEA,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;gBAC3D,MAAM;gBACN,aAAa,EAAE;gBACf,WAAW;YACb;QACF,OAAO;YACL,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAACH,KAAK,CAAC,EAAEA,KAAK,CAAC;YACpC,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;gBAC3D,MAAM;gBACN,GAAGA,KAAK,CAAC;gBACT,GAAGA,KAAK,CAAC;gBACT,QAAQ;gBACR,YAAY;YACd;YAEA,IAAK,IAAII,IAAI,GAAGA,KAAKF,OAAOE,IAAK;gBAC/B,MAAMrD,IAAIiD,KAAK,CAAC,GAAIC,AAAAA,CAAAA,GAAG,CAAC,GAAGD,KAAK,CAAC,AAAD,IAAMI,CAAAA,IAAIF,KAAI;gBAC9C,MAAMlD,IAAIgD,KAAK,CAAC,GAAIC,AAAAA,CAAAA,GAAG,CAAC,GAAGD,KAAK,CAAC,AAAD,IAAMI,CAAAA,IAAIF,KAAI;gBAC9C,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAACnD,GAAGC;gBACzB,MAAM,IAAIhB,QAAQ,CAAC+D,MAAQ7D,WAAW6D,KAAKI;YAC7C;YAEA,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;gBAC3D,MAAM;gBACN,GAAGF,GAAG,CAAC;gBACP,GAAGA,GAAG,CAAC;gBACP,QAAQ;gBACR,YAAY;YACd;QACF;QAEA,IAAI,CAAC,YAAY,GAAGA,GAAG,CAAC;QACxB,IAAI,CAAC,YAAY,GAAGA,GAAG,CAAC;IAC1B;IAnzBA,YAAYI,sBAA+B,CAAE;QAd7C,wCAAgB;QAEhB,uBAAO,0BAAP;QAEA,uBAAQ,gBAAR;QAEA,uBAAQ,eAA6B;QAErC,uBAAQ,aAAY;QAEpB,uBAAQ,qBAAoC;QAE5C,uBAAO,uCAAsC;QAihB7C,uBAAQ,gBAAe;QACvB,uBAAQ,gBAAe;QAEvB,gCAAQ;YACN,OAAO,OACLtD,GACAC,GACAsD;gBAEA,MAAM,EAAEC,SAAS,MAAM,EAAEC,QAAQ,CAAC,EAAE,GAAGF,WAAW,CAAC;gBACnD,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAACvD,GAAGC;gBAEzB,IAAI,AAA2B,SAA3B,IAAI,CAAC,iBAAiB,EAAW;oBACnC,MAAMW,SAAS,MAAM,IAAI,CAAC,qBAAqB,CAAC,oBAAoB;wBAClE,YAAY,CAAC;;cAET,CAAC;wBACL,eAAe;oBACjB;oBACA,IAAI,CAAC,iBAAiB,GAAGA,QAAQ,QAAQ;gBAC3C;gBAEA,IAAI,IAAI,CAAC,iBAAiB,IAAI4C,AAAW,WAAXA,QAAmB;oBAE/C,MAAMV,cAAc;wBAAC;4BAAE,GAAGC,KAAK,KAAK,CAAC/C;4BAAI,GAAG+C,KAAK,KAAK,CAAC9C;wBAAG;qBAAE;oBAC5D,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;wBAC3D,MAAM;wBACN6C;wBACA,WAAW;oBACb;oBAEA,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;wBAC3D,MAAM;wBACN,aAAa,EAAE;wBACf,WAAW;oBACb;gBACF,OAEE,IAAK,IAAIO,IAAI,GAAGA,IAAII,OAAOJ,IAAK;oBAC9B,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;wBAC3D,MAAM;wBACNrD;wBACAC;wBACAuD;wBACA,YAAY;oBACd;oBACA,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;wBAC3D,MAAM;wBACNxD;wBACAC;wBACAuD;wBACA,YAAY;oBACd;oBACA,MAAMzE,MAAM;gBACd;YAEJ;YACA,OAAO,OACL2E,QACAC,QACAC,QACAC;gBAEA,MAAMC,SAASF,UAAU,IAAI,CAAC,YAAY;gBAC1C,MAAMG,SAASF,UAAU,IAAI,CAAC,YAAY;gBAC1C,MAAM,IAAI,CAAC,gBAAgB,CAACC,QAAQC;gBACpC,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;oBAC3D,MAAM;oBACN,GAAGD;oBACH,GAAGC;oBACHL;oBACAC;gBACF;gBACA,IAAI,CAAC,YAAY,GAAGG;gBACpB,IAAI,CAAC,YAAY,GAAGC;YACtB;YACA,MAAM,OAAO/D,GAAWC;gBACtB,MAAM,IAAI,CAAC,gBAAgB,CAACD,GAAGC;gBAC/B,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;oBAC3D,MAAM;oBACND;oBACAC;gBACF;gBACA,IAAI,CAAC,YAAY,GAAGD;gBACpB,IAAI,CAAC,YAAY,GAAGC;YACtB;YACA,MAAM,OACJgD,MACAC;gBAEA,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAACD,KAAK,CAAC,EAAEA,KAAK,CAAC;gBAEpC,MAAMlE,MAAM;gBACZ,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;oBAC3D,MAAM;oBACN,GAAGkE,KAAK,CAAC;oBACT,GAAGA,KAAK,CAAC;oBACT,QAAQ;oBACR,YAAY;gBACd;gBAEA,MAAMlE,MAAM;gBAEZ,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;oBAC3D,MAAM;oBACN,GAAGmE,GAAG,CAAC;oBACP,GAAGA,GAAG,CAAC;gBACT;gBAEA,MAAMnE,MAAM;gBAEZ,MAAM,IAAI,CAAC,qBAAqB,CAAC,4BAA4B;oBAC3D,MAAM;oBACN,GAAGmE,GAAG,CAAC;oBACP,GAAGA,GAAG,CAAC;oBACP,QAAQ;oBACR,YAAY;gBACd;gBAEA,MAAMnE,MAAM;gBAEZ,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAACmE,GAAG,CAAC,EAAEA,GAAG,CAAC;YAClC;QACF;QAEA,mCAAW;YACT,MAAM,OAAOc;gBACX,MAAMC,cAAc,IAAIC,YAAY;oBAClC,MAAM,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI;gBAC5C;gBACA,MAAMD,YAAY,IAAI,CAACD,MAAM;oBAAE,OAAO;gBAAE;YAC1C;YACA,OAAO,OACLG;gBAIA,MAAMF,cAAc,IAAIC,YAAY;oBAClC,MAAM,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,IAAI;gBAC5C;gBACA,MAAME,OAAOC,MAAM,OAAO,CAACF,UAAUA,SAAS;oBAACA;iBAAO;gBACtD,KAAK,MAAMG,KAAKF,KAAM;oBACpB,MAAMG,WAAWD,EAAE,OAAO,GAAG;wBAACA,EAAE,OAAO;qBAAC,GAAG,EAAE;oBAC7C,MAAML,YAAY,IAAI,CAACK,EAAE,GAAG,EAAE;wBAAEC;oBAAS;gBAC3C;gBACA,KAAK,MAAMD,KAAK;uBAAIF;iBAAK,CAAC,OAAO,GAC/B,MAAMH,YAAY,EAAE,CAACK,EAAE,GAAG;YAE9B;QACF;QAnqBE,IAAI,CAAC,sBAAsB,GAAGhB;IAChC;AAkzBF"}
1
+ {"version":3,"file":"chrome-extension/page.mjs","sources":["../../../src/chrome-extension/page.ts"],"sourcesContent":["/// <reference types=\"chrome\" />\n\n/*\n It is used to interact with the page tab from the chrome extension.\n The page must be active when interacting with it.\n*/\n\nimport { limitOpenNewTabScript } from '@/web-element';\nimport type {\n ElementCacheFeature,\n ElementTreeNode,\n Point,\n Rect,\n Size,\n UIContext,\n} from '@midscene/core';\nimport type { AbstractInterface, DeviceAction } from '@midscene/core/device';\nimport type { ElementInfo } from '@midscene/shared/extractor';\nimport { treeToList } from '@midscene/shared/extractor';\nimport { createImgBase64ByFormat } from '@midscene/shared/img';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert } from '@midscene/shared/utils';\nimport type { Protocol as CDPTypes } from 'devtools-protocol';\nimport {\n type CacheFeatureOptions,\n type WebElementCacheFeature,\n buildRectFromElementInfo,\n judgeOrderSensitive,\n sanitizeXpaths,\n} from '../common/cache-helper';\nimport { WebPageContextParser } from '../web-element';\nimport {\n type KeyInput,\n type MouseButton,\n commonWebActionsForWebPage,\n} from '../web-page';\nimport { CdpKeyboard } from './cdpInput';\nimport {\n getHtmlElementScript,\n injectStopWaterFlowAnimation,\n injectWaterFlowAnimation,\n} from './dynamic-scripts';\n\nconst debug = getDebug('web:chrome-extension:page');\n\nfunction sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport default class ChromeExtensionProxyPage implements AbstractInterface {\n interfaceType = 'chrome-extension-proxy';\n\n public forceSameTabNavigation: boolean;\n\n private viewportSize?: Size;\n\n private activeTabId: number | null = null;\n\n private destroyed = false;\n\n private isMobileEmulation: boolean | null = null;\n\n public _continueWhenFailedToAttachDebugger = false;\n\n constructor(forceSameTabNavigation: boolean) {\n this.forceSameTabNavigation = forceSameTabNavigation;\n }\n\n actionSpace(): DeviceAction[] {\n return commonWebActionsForWebPage(this);\n }\n\n public async setActiveTabId(tabId: number) {\n if (this.activeTabId) {\n throw new Error(\n `Active tab id is already set, which is ${this.activeTabId}, cannot set it to ${tabId}`,\n );\n }\n await chrome.tabs.update(tabId, { active: true });\n this.activeTabId = tabId;\n }\n\n public async getActiveTabId() {\n return this.activeTabId;\n }\n\n /**\n * Get a list of current tabs\n * @returns {Promise<Array<{id: number, title: string, url: string}>>}\n */\n public async getBrowserTabList(): Promise<\n { id: string; title: string; url: string; currentActiveTab: boolean }[]\n > {\n const tabs = await chrome.tabs.query({ currentWindow: true });\n return tabs\n .map((tab) => ({\n id: `${tab.id}`,\n title: tab.title,\n url: tab.url,\n currentActiveTab: tab.active,\n }))\n .filter((tab) => tab.id && tab.title && tab.url) as {\n id: string;\n title: string;\n url: string;\n currentActiveTab: boolean;\n }[];\n }\n\n public async getTabIdOrConnectToCurrentTab() {\n if (this.activeTabId) {\n // alway keep on the connected tab\n return this.activeTabId;\n }\n const tabId = await chrome.tabs\n .query({ active: true, currentWindow: true })\n .then((tabs) => tabs[0]?.id);\n this.activeTabId = tabId || 0;\n return this.activeTabId;\n }\n\n /**\n * Ensure debugger is attached to the current tab.\n * Uses lazy attach pattern - only attaches when needed.\n */\n private async ensureDebuggerAttached() {\n assert(!this.destroyed, 'Page is destroyed');\n\n const url = await this.url();\n if (url.startsWith('chrome://')) {\n throw new Error(\n 'Cannot attach debugger to chrome:// pages, please use Midscene in a normal page with http://, https:// or file://',\n );\n }\n\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n\n try {\n await chrome.debugger.attach({ tabId }, '1.3');\n console.log('Debugger attached to tab:', tabId);\n } catch (error) {\n const errorMsg = (error as Error)?.message || '';\n // Already attached is OK, we can continue\n if (errorMsg.includes('Another debugger is already attached')) {\n console.log('Debugger already attached to tab:', tabId);\n return;\n }\n\n if (this._continueWhenFailedToAttachDebugger) {\n console.warn(\n 'Failed to attach debugger, but continuing due to _continueWhenFailedToAttachDebugger flag',\n error,\n );\n return;\n }\n\n throw error;\n }\n\n // Wait for debugger banner in Chrome to appear\n await sleep(500);\n\n // Enable water flow animation\n await this.enableWaterFlowAnimation();\n }\n\n private async showMousePointer(x: number, y: number) {\n // update mouse pointer while redirecting\n const pointerScript = `(() => {\n if(typeof window.midsceneWaterFlowAnimation !== 'undefined') {\n window.midsceneWaterFlowAnimation.enable();\n window.midsceneWaterFlowAnimation.showMousePointer(${x}, ${y});\n } else {\n console.log('midsceneWaterFlowAnimation is not defined');\n }\n })()`;\n\n await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `${pointerScript}`,\n });\n }\n\n private async hideMousePointer() {\n await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n if(typeof window.midsceneWaterFlowAnimation !== 'undefined') {\n window.midsceneWaterFlowAnimation.hideMousePointer();\n }\n })()`,\n });\n }\n\n /**\n * Public method to detach debugger without destroying the page instance.\n * Useful for error recovery scenarios where we want to remove the debugger banner\n * without completely destroying the page.\n */\n public async detachDebugger(tabId?: number) {\n const tabIdToDetach = tabId || (await this.getTabIdOrConnectToCurrentTab());\n console.log('detaching debugger from tab:', tabIdToDetach);\n\n try {\n await this.disableWaterFlowAnimation(tabIdToDetach);\n await sleep(200); // wait for the animation to stop\n } catch (error) {\n console.warn('Failed to disable water flow animation', error);\n }\n\n try {\n await chrome.debugger.detach({ tabId: tabIdToDetach });\n console.log('Debugger detached successfully from tab:', tabIdToDetach);\n } catch (error) {\n // Tab might be closed or debugger already detached - this is OK\n console.warn(\n 'Failed to detach debugger (may already be detached):',\n error,\n );\n }\n }\n\n private async enableWaterFlowAnimation() {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n\n // limit open page in new tab\n if (this.forceSameTabNavigation) {\n await chrome.debugger.sendCommand({ tabId }, 'Runtime.evaluate', {\n expression: limitOpenNewTabScript,\n });\n }\n\n const script = await injectWaterFlowAnimation();\n // we will call this function in sendCommandToDebugger, so we have to use the chrome.debugger.sendCommand\n await chrome.debugger.sendCommand({ tabId }, 'Runtime.evaluate', {\n expression: script,\n });\n }\n\n private async disableWaterFlowAnimation(tabId: number) {\n const script = await injectStopWaterFlowAnimation();\n\n await chrome.debugger.sendCommand({ tabId }, 'Runtime.evaluate', {\n expression: script,\n });\n }\n\n /**\n * Send a command to the debugger with automatic attach and retry on detachment.\n * Uses lazy attach pattern - will automatically attach if not already attached.\n */\n private async sendCommandToDebugger<ResponseType = any, RequestType = any>(\n command: string,\n params: RequestType,\n retryCount = 0,\n ): Promise<ResponseType> {\n const MAX_RETRIES = 2;\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n\n try {\n // Try to send command directly first\n const result = (await chrome.debugger.sendCommand(\n { tabId },\n command,\n params as any,\n )) as ResponseType;\n\n // Enable water flow animation after successful command (don't await)\n this.enableWaterFlowAnimation().catch((err) => {\n console.warn('Failed to enable water flow animation:', err);\n });\n\n return result;\n } catch (error) {\n // If command failed, check if it's because debugger is not attached\n const errorMsg = (error as Error)?.message || '';\n const isDetachError =\n errorMsg.includes('Debugger is not attached') ||\n errorMsg.includes('Cannot access a Target') ||\n errorMsg.includes('No target with given id');\n\n if (isDetachError && retryCount < MAX_RETRIES) {\n console.log(\n `Debugger not attached for command \"${command}\", attempting to attach (retry ${retryCount + 1}/${MAX_RETRIES})`,\n );\n\n // Try to attach and retry\n await this.ensureDebuggerAttached();\n\n return this.sendCommandToDebugger<ResponseType, RequestType>(\n command,\n params,\n retryCount + 1,\n );\n }\n\n // Not a detach error or out of retries\n throw error;\n }\n }\n\n private async getPageContentByCDP() {\n const script = await getHtmlElementScript();\n\n // check tab url\n await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: script,\n });\n\n const expression = () => {\n const tree = (\n window as any\n ).midscene_element_inspector.webExtractNodeTree();\n\n return {\n tree,\n size: {\n width: document.documentElement.clientWidth,\n height: document.documentElement.clientHeight,\n dpr: window.devicePixelRatio,\n },\n };\n };\n const returnValue = await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: `(${expression.toString()})()`,\n returnByValue: true,\n });\n\n if (!returnValue.result.value) {\n const errorDescription =\n returnValue.exceptionDetails?.exception?.description || '';\n if (!errorDescription) {\n console.error('returnValue from cdp', returnValue);\n }\n throw new Error(\n `Failed to get page content from page, error: ${errorDescription}`,\n );\n }\n\n return returnValue.result.value as {\n tree: ElementTreeNode<ElementInfo>;\n size: Size;\n };\n }\n\n public async evaluateJavaScript(script: string) {\n return this.sendCommandToDebugger('Runtime.evaluate', {\n expression: script,\n awaitPromise: true,\n });\n }\n\n async beforeInvokeAction(): Promise<void> {\n // current implementation is wait until domReadyState is complete\n try {\n await this.waitUntilNetworkIdle();\n } catch (error) {\n // console.warn('Failed to wait until network idle', error);\n }\n }\n\n private async waitUntilNetworkIdle() {\n const timeout = 10000;\n const startTime = Date.now();\n let lastReadyState = '';\n while (Date.now() - startTime < timeout) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: 'document.readyState',\n });\n lastReadyState = result.result.value;\n if (lastReadyState === 'complete') {\n await new Promise((resolve) => setTimeout(resolve, 300));\n return;\n }\n await new Promise((resolve) => setTimeout(resolve, 300));\n }\n throw new Error(\n `Failed to wait until network idle, last readyState: ${lastReadyState}`,\n );\n }\n\n // @deprecated\n async getElementsInfo() {\n const tree = await this.getElementsNodeTree();\n return treeToList(tree);\n }\n\n async getXpathsByPoint(point: Point, isOrderSensitive = false) {\n const script = await getHtmlElementScript();\n\n await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: script,\n });\n\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `window.midscene_element_inspector.getXpathsByPoint({left: ${point.left}, top: ${point.top}}, ${isOrderSensitive})`,\n returnByValue: true,\n });\n return result.result.value;\n }\n\n async getElementInfoByXpath(xpath: string) {\n const script = await getHtmlElementScript();\n\n // check tab url\n await this.sendCommandToDebugger<\n CDPTypes.Runtime.EvaluateResponse,\n CDPTypes.Runtime.EvaluateRequest\n >('Runtime.evaluate', {\n expression: script,\n });\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `window.midscene_element_inspector.getElementInfoByXpath(${JSON.stringify(xpath)})`,\n returnByValue: true,\n });\n return result.result.value;\n }\n\n async cacheFeatureForPoint(\n center: [number, number],\n options?: CacheFeatureOptions,\n ): Promise<ElementCacheFeature> {\n const point: Point = { left: center[0], top: center[1] };\n\n try {\n const isOrderSensitive = await judgeOrderSensitive(options, debug);\n const xpaths = await this.getXpathsByPoint(point, isOrderSensitive);\n return { xpaths: sanitizeXpaths(xpaths) };\n } catch (error) {\n debug('cacheFeatureForPoint failed: %O', error);\n return { xpaths: [] };\n }\n }\n\n async rectMatchesCacheFeature(feature: ElementCacheFeature): Promise<Rect> {\n const xpaths = sanitizeXpaths((feature as WebElementCacheFeature).xpaths);\n\n for (const xpath of xpaths) {\n try {\n const elementInfo = await this.getElementInfoByXpath(xpath);\n if (elementInfo?.rect) {\n return buildRectFromElementInfo(elementInfo, this.viewportSize?.dpr);\n }\n } catch (error) {\n debug('rectMatchesCacheFeature failed for xpath %s: %O', xpath, error);\n }\n }\n\n throw new Error(\n `No matching element rect found for cache feature (tried ${xpaths.length} xpath(s))`,\n );\n }\n\n async getElementsNodeTree() {\n await this.hideMousePointer();\n const content = await this.getPageContentByCDP();\n if (content?.size) {\n this.viewportSize = content.size;\n }\n\n return content?.tree || { node: null, children: [] };\n }\n\n async getContext(): Promise<UIContext> {\n return await WebPageContextParser(this, {});\n }\n\n async size() {\n if (this.viewportSize) return this.viewportSize;\n\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression:\n '({width: document.documentElement.clientWidth, height: document.documentElement.clientHeight, dpr: window.devicePixelRatio})',\n returnByValue: true,\n });\n\n const sizeInfo: Size = result.result.value;\n console.log('sizeInfo', sizeInfo);\n\n this.viewportSize = sizeInfo;\n return sizeInfo;\n }\n\n async screenshotBase64() {\n // screenshot by cdp\n await this.hideMousePointer();\n const format = 'jpeg';\n const base64 = await this.sendCommandToDebugger('Page.captureScreenshot', {\n format,\n quality: 90,\n });\n return createImgBase64ByFormat(format, base64.data);\n }\n\n async url() {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n const url = await chrome.tabs.get(tabId).then((tab) => tab.url);\n return url || '';\n }\n\n async navigate(url: string): Promise<void> {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n await chrome.tabs.update(tabId, { url });\n // Wait for navigation to complete\n // Note: debugger will auto-reattach on next command if detached during navigation\n await this.waitUntilNetworkIdle();\n }\n\n async reload(): Promise<void> {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n await chrome.tabs.reload(tabId);\n // Wait for reload to complete\n await this.waitUntilNetworkIdle();\n }\n\n async goBack(): Promise<void> {\n const tabId = await this.getTabIdOrConnectToCurrentTab();\n await chrome.tabs.goBack(tabId);\n // Wait for navigation to complete\n await this.waitUntilNetworkIdle();\n }\n\n async scrollUntilTop(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(0, -9999999);\n }\n\n async scrollUntilBottom(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(0, 9999999);\n }\n\n async scrollUntilLeft(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(-9999999, 0);\n }\n\n async scrollUntilRight(startingPoint?: Point) {\n if (startingPoint) {\n await this.mouse.move(startingPoint.left, startingPoint.top);\n }\n return this.mouse.wheel(9999999, 0);\n }\n\n async scrollUp(distance?: number, startingPoint?: Point) {\n const { height } = await this.size();\n const scrollDistance = distance || height * 0.7;\n return this.mouse.wheel(\n 0,\n -scrollDistance,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async scrollDown(distance?: number, startingPoint?: Point) {\n const { height } = await this.size();\n const scrollDistance = distance || height * 0.7;\n return this.mouse.wheel(\n 0,\n scrollDistance,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async scrollLeft(distance?: number, startingPoint?: Point) {\n const { width } = await this.size();\n const scrollDistance = distance || width * 0.7;\n return this.mouse.wheel(\n -scrollDistance,\n 0,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async scrollRight(distance?: number, startingPoint?: Point) {\n const { width } = await this.size();\n const scrollDistance = distance || width * 0.7;\n return this.mouse.wheel(\n scrollDistance,\n 0,\n startingPoint?.left,\n startingPoint?.top,\n );\n }\n\n async clearInput(element: ElementInfo) {\n if (!element) {\n console.warn('No element to clear input');\n return;\n }\n\n await this.mouse.click(element.center[0], element.center[1]);\n\n await this.sendCommandToDebugger('Input.dispatchKeyEvent', {\n type: 'keyDown',\n commands: ['selectAll'],\n });\n\n await this.sendCommandToDebugger('Input.dispatchKeyEvent', {\n type: 'keyUp',\n commands: ['selectAll'],\n });\n\n await sleep(100);\n\n await this.keyboard.press({\n key: 'Backspace',\n });\n }\n\n private latestMouseX = 100;\n private latestMouseY = 100;\n\n mouse = {\n click: async (\n x: number,\n y: number,\n options?: { button?: MouseButton; count?: number },\n ) => {\n const { button = 'left', count = 1 } = options || {};\n await this.mouse.move(x, y);\n // detect if the page is in mobile emulation mode\n if (this.isMobileEmulation === null) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);\n })()`,\n returnByValue: true,\n });\n this.isMobileEmulation = result?.result?.value;\n }\n\n if (this.isMobileEmulation && button === 'left') {\n // in mobile emulation mode, directly inject click event\n const touchPoints = [{ x: Math.round(x), y: Math.round(y) }];\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchStart',\n touchPoints,\n modifiers: 0,\n });\n\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchEnd',\n touchPoints: [],\n modifiers: 0,\n });\n } else {\n // standard mousePressed + mouseReleased\n for (let i = 0; i < count; i++) {\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x,\n y,\n button,\n clickCount: 1,\n });\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x,\n y,\n button,\n clickCount: 1,\n });\n await sleep(50);\n }\n }\n },\n wheel: async (\n deltaX: number,\n deltaY: number,\n startX?: number,\n startY?: number,\n ) => {\n const finalX = startX || this.latestMouseX;\n const finalY = startY || this.latestMouseY;\n await this.showMousePointer(finalX, finalY);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseWheel',\n x: finalX,\n y: finalY,\n deltaX,\n deltaY,\n });\n this.latestMouseX = finalX;\n this.latestMouseY = finalY;\n },\n move: async (x: number, y: number) => {\n await this.showMousePointer(x, y);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseMoved',\n x,\n y,\n });\n this.latestMouseX = x;\n this.latestMouseY = y;\n },\n drag: async (\n from: { x: number; y: number },\n to: { x: number; y: number },\n ) => {\n await this.mouse.move(from.x, from.y);\n\n await sleep(200);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x: from.x,\n y: from.y,\n button: 'left',\n clickCount: 1,\n });\n\n await sleep(300);\n\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseMoved',\n x: to.x,\n y: to.y,\n });\n\n await sleep(500);\n\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x: to.x,\n y: to.y,\n button: 'left',\n clickCount: 1,\n });\n\n await sleep(200);\n\n await this.mouse.move(to.x, to.y);\n },\n };\n\n keyboard = {\n type: async (text: string) => {\n const cdpKeyboard = new CdpKeyboard({\n send: this.sendCommandToDebugger.bind(this),\n });\n await cdpKeyboard.type(text, { delay: 0 });\n },\n press: async (\n action:\n | { key: KeyInput; command?: string }\n | { key: KeyInput; command?: string }[],\n ) => {\n const cdpKeyboard = new CdpKeyboard({\n send: this.sendCommandToDebugger.bind(this),\n });\n const keys = Array.isArray(action) ? action : [action];\n for (const k of keys) {\n const commands = k.command ? [k.command] : [];\n await cdpKeyboard.down(k.key, { commands });\n }\n for (const k of [...keys].reverse()) {\n await cdpKeyboard.up(k.key);\n }\n },\n };\n\n async destroy(): Promise<void> {\n this.destroyed = true;\n this.activeTabId = null;\n await this.detachDebugger();\n }\n\n async longPress(x: number, y: number, duration?: number) {\n duration = duration || 500;\n const LONG_PRESS_THRESHOLD = 600;\n const MIN_PRESS_THRESHOLD = 300;\n if (duration > LONG_PRESS_THRESHOLD) {\n duration = LONG_PRESS_THRESHOLD;\n }\n if (duration < MIN_PRESS_THRESHOLD) {\n duration = MIN_PRESS_THRESHOLD;\n }\n await this.mouse.move(x, y);\n\n if (this.isMobileEmulation === null) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);\n })()`,\n returnByValue: true,\n });\n this.isMobileEmulation = result?.result?.value;\n }\n\n if (this.isMobileEmulation) {\n const touchPoints = [{ x: Math.round(x), y: Math.round(y) }];\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchStart',\n touchPoints,\n modifiers: 0,\n });\n await new Promise((res) => setTimeout(res, duration));\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchEnd',\n touchPoints: [],\n modifiers: 0,\n });\n } else {\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x,\n y,\n button: 'left',\n clickCount: 1,\n });\n await new Promise((res) => setTimeout(res, duration));\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x,\n y,\n button: 'left',\n clickCount: 1,\n });\n }\n this.latestMouseX = x;\n this.latestMouseY = y;\n }\n\n async swipe(\n from: { x: number; y: number },\n to: { x: number; y: number },\n duration?: number,\n ) {\n const LONG_PRESS_THRESHOLD = 500;\n const MIN_PRESS_THRESHOLD = 150;\n duration = duration || 300;\n if (duration < MIN_PRESS_THRESHOLD) {\n duration = MIN_PRESS_THRESHOLD;\n }\n if (duration > LONG_PRESS_THRESHOLD) {\n duration = LONG_PRESS_THRESHOLD;\n }\n\n if (this.isMobileEmulation === null) {\n const result = await this.sendCommandToDebugger('Runtime.evaluate', {\n expression: `(() => {\n return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent);\n })()`,\n returnByValue: true,\n });\n this.isMobileEmulation = result?.result?.value;\n }\n\n const steps = 30;\n const delay = duration / steps;\n\n if (this.isMobileEmulation) {\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchStart',\n touchPoints: [{ x: Math.round(from.x), y: Math.round(from.y) }],\n modifiers: 0,\n });\n\n for (let i = 1; i <= steps; i++) {\n const x = from.x + (to.x - from.x) * (i / steps);\n const y = from.y + (to.y - from.y) * (i / steps);\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchMove',\n touchPoints: [{ x: Math.round(x), y: Math.round(y) }],\n modifiers: 0,\n });\n await new Promise((res) => setTimeout(res, delay));\n }\n\n await this.sendCommandToDebugger('Input.dispatchTouchEvent', {\n type: 'touchEnd',\n touchPoints: [],\n modifiers: 0,\n });\n } else {\n await this.mouse.move(from.x, from.y);\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mousePressed',\n x: from.x,\n y: from.y,\n button: 'left',\n clickCount: 1,\n });\n\n for (let i = 1; i <= steps; i++) {\n const x = from.x + (to.x - from.x) * (i / steps);\n const y = from.y + (to.y - from.y) * (i / steps);\n await this.mouse.move(x, y);\n await new Promise((res) => setTimeout(res, delay));\n }\n\n await this.sendCommandToDebugger('Input.dispatchMouseEvent', {\n type: 'mouseReleased',\n x: to.x,\n y: to.y,\n button: 'left',\n clickCount: 1,\n });\n }\n\n this.latestMouseX = to.x;\n this.latestMouseY = to.y;\n }\n}\n"],"names":["debug","getDebug","sleep","ms","Promise","resolve","setTimeout","ChromeExtensionProxyPage","commonWebActionsForWebPage","tabId","Error","chrome","tabs","tab","assert","url","console","error","errorMsg","x","y","pointerScript","tabIdToDetach","limitOpenNewTabScript","script","injectWaterFlowAnimation","injectStopWaterFlowAnimation","command","params","retryCount","MAX_RETRIES","result","err","isDetachError","getHtmlElementScript","expression","tree","window","document","returnValue","errorDescription","timeout","startTime","Date","lastReadyState","treeToList","point","isOrderSensitive","xpath","JSON","center","options","judgeOrderSensitive","xpaths","sanitizeXpaths","feature","elementInfo","buildRectFromElementInfo","content","WebPageContextParser","sizeInfo","format","base64","createImgBase64ByFormat","startingPoint","distance","height","scrollDistance","width","element","duration","LONG_PRESS_THRESHOLD","MIN_PRESS_THRESHOLD","touchPoints","Math","res","from","to","steps","delay","i","forceSameTabNavigation","button","count","deltaX","deltaY","startX","startY","finalX","finalY","text","cdpKeyboard","CdpKeyboard","action","keys","Array","k","commands"],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { AiJudgeOrderSensitive, callAIWithObjectResponse } from "@midscene/core/ai-model";
2
+ const sanitizeXpaths = (xpaths)=>{
3
+ if (!Array.isArray(xpaths)) return [];
4
+ return xpaths.filter((xpath)=>'string' == typeof xpath && xpath.length > 0);
5
+ };
6
+ async function judgeOrderSensitive(options, debug) {
7
+ if (!options?.targetDescription || !options?.modelConfig) return false;
8
+ try {
9
+ const judgeResult = await AiJudgeOrderSensitive(options.targetDescription, callAIWithObjectResponse, options.modelConfig);
10
+ debug("judged isOrderSensitive=%s for description: %s", judgeResult.isOrderSensitive, options.targetDescription);
11
+ return judgeResult.isOrderSensitive;
12
+ } catch (error) {
13
+ debug('Failed to judge isOrderSensitive: %O', error);
14
+ return false;
15
+ }
16
+ }
17
+ function buildRectFromElementInfo(elementInfo, dpr) {
18
+ const matchedRect = {
19
+ left: elementInfo.rect.left,
20
+ top: elementInfo.rect.top,
21
+ width: elementInfo.rect.width,
22
+ height: elementInfo.rect.height
23
+ };
24
+ if (dpr) matchedRect.dpr = dpr;
25
+ return matchedRect;
26
+ }
27
+ export { buildRectFromElementInfo, judgeOrderSensitive, sanitizeXpaths };
28
+
29
+ //# sourceMappingURL=cache-helper.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common/cache-helper.mjs","sources":["../../../src/common/cache-helper.ts"],"sourcesContent":["import type { ElementCacheFeature, Point, Rect } from '@midscene/core';\nimport {\n AiJudgeOrderSensitive,\n callAIWithObjectResponse,\n} from '@midscene/core/ai-model';\nimport type { IModelConfig } from '@midscene/shared/env';\nimport type { DebugFunction } from '@midscene/shared/logger';\n\n// Shared type for web element cache feature\nexport type WebElementCacheFeature = ElementCacheFeature & {\n xpaths?: string[];\n};\n\n// Shared function to sanitize xpaths\nexport const sanitizeXpaths = (xpaths: unknown): string[] => {\n if (!Array.isArray(xpaths)) {\n return [];\n }\n\n return xpaths.filter(\n (xpath): xpath is string => typeof xpath === 'string' && xpath.length > 0,\n );\n};\n\n// Cache feature extraction options interface\nexport interface CacheFeatureOptions {\n targetDescription?: string;\n modelConfig?: IModelConfig;\n}\n\n// Shared logic for judging isOrderSensitive\nexport async function judgeOrderSensitive(\n options: CacheFeatureOptions | undefined,\n debug: DebugFunction,\n): Promise<boolean> {\n if (!options?.targetDescription || !options?.modelConfig) {\n return false;\n }\n try {\n const judgeResult = await AiJudgeOrderSensitive(\n options.targetDescription,\n callAIWithObjectResponse,\n options.modelConfig,\n );\n debug(\n 'judged isOrderSensitive=%s for description: %s',\n judgeResult.isOrderSensitive,\n options.targetDescription,\n );\n return judgeResult.isOrderSensitive;\n } catch (error) {\n debug('Failed to judge isOrderSensitive: %O', error);\n return false;\n }\n}\n\n// Shared logic to build Rect from elementInfo\nexport function buildRectFromElementInfo(\n elementInfo: {\n rect: { left: number; top: number; width: number; height: number };\n },\n dpr?: number,\n): Rect {\n const matchedRect: Rect = {\n left: elementInfo.rect.left,\n top: elementInfo.rect.top,\n width: elementInfo.rect.width,\n height: elementInfo.rect.height,\n };\n if (dpr) {\n matchedRect.dpr = dpr;\n }\n return matchedRect;\n}\n"],"names":["sanitizeXpaths","xpaths","Array","xpath","judgeOrderSensitive","options","debug","judgeResult","AiJudgeOrderSensitive","callAIWithObjectResponse","error","buildRectFromElementInfo","elementInfo","dpr","matchedRect"],"mappings":";AAcO,MAAMA,iBAAiB,CAACC;IAC7B,IAAI,CAACC,MAAM,OAAO,CAACD,SACjB,OAAO,EAAE;IAGX,OAAOA,OAAO,MAAM,CAClB,CAACE,QAA2B,AAAiB,YAAjB,OAAOA,SAAsBA,MAAM,MAAM,GAAG;AAE5E;AASO,eAAeC,oBACpBC,OAAwC,EACxCC,KAAoB;IAEpB,IAAI,CAACD,SAAS,qBAAqB,CAACA,SAAS,aAC3C,OAAO;IAET,IAAI;QACF,MAAME,cAAc,MAAMC,sBACxBH,QAAQ,iBAAiB,EACzBI,0BACAJ,QAAQ,WAAW;QAErBC,MACE,kDACAC,YAAY,gBAAgB,EAC5BF,QAAQ,iBAAiB;QAE3B,OAAOE,YAAY,gBAAgB;IACrC,EAAE,OAAOG,OAAO;QACdJ,MAAM,wCAAwCI;QAC9C,OAAO;IACT;AACF;AAGO,SAASC,yBACdC,WAEC,EACDC,GAAY;IAEZ,MAAMC,cAAoB;QACxB,MAAMF,YAAY,IAAI,CAAC,IAAI;QAC3B,KAAKA,YAAY,IAAI,CAAC,GAAG;QACzB,OAAOA,YAAY,IAAI,CAAC,KAAK;QAC7B,QAAQA,YAAY,IAAI,CAAC,MAAM;IACjC;IACA,IAAIC,KACFC,YAAY,GAAG,GAAGD;IAEpB,OAAOC;AACT"}
@@ -7,7 +7,7 @@ class WebMCPServer extends BaseMCPServer {
7
7
  constructor(toolsManager){
8
8
  super({
9
9
  name: '@midscene/web-bridge-mcp',
10
- version: "1.3.8",
10
+ version: "1.3.9",
11
11
  description: 'Control the browser using natural language commands'
12
12
  }, toolsManager);
13
13
  }
@@ -1,5 +1,4 @@
1
1
  import { WebPageContextParser } from "../web-element.mjs";
2
- import { AiJudgeOrderSensitive, callAIWithObjectResponse } from "@midscene/core/ai-model";
3
2
  import { sleep } from "@midscene/core/utils";
4
3
  import { DEFAULT_WAIT_FOR_NAVIGATION_TIMEOUT, DEFAULT_WAIT_FOR_NETWORK_IDLE_CONCURRENCY, DEFAULT_WAIT_FOR_NETWORK_IDLE_TIMEOUT } from "@midscene/shared/constants";
5
4
  import { treeToList } from "@midscene/shared/extractor";
@@ -7,6 +6,7 @@ import { createImgBase64ByFormat } from "@midscene/shared/img";
7
6
  import { getDebug } from "@midscene/shared/logger";
8
7
  import { getElementInfosScriptContent, getExtraReturnLogic } from "@midscene/shared/node";
9
8
  import { assert } from "@midscene/shared/utils";
9
+ import { buildRectFromElementInfo, judgeOrderSensitive, sanitizeXpaths } from "../common/cache-helper.mjs";
10
10
  import { commonWebActionsForWebPage } from "../web-page.mjs";
11
11
  function _define_property(obj, key, value) {
12
12
  if (key in obj) Object.defineProperty(obj, key, {
@@ -19,10 +19,6 @@ function _define_property(obj, key, value) {
19
19
  return obj;
20
20
  }
21
21
  const debugPage = getDebug('web:page');
22
- const sanitizeXpaths = (xpaths)=>{
23
- if (!Array.isArray(xpaths)) return [];
24
- return xpaths.filter((xpath)=>'string' == typeof xpath && xpath.length > 0);
25
- };
26
22
  class Page {
27
23
  actionSpace() {
28
24
  const defaultActions = commonWebActionsForWebPage(this, this.enableTouchEventsInActionSpace);
@@ -92,14 +88,7 @@ class Page {
92
88
  top: center[1]
93
89
  };
94
90
  try {
95
- let isOrderSensitive = false;
96
- if (options?.targetDescription && options?.modelConfig) try {
97
- const judgeResult = await AiJudgeOrderSensitive(options.targetDescription, callAIWithObjectResponse, options.modelConfig);
98
- isOrderSensitive = judgeResult.isOrderSensitive;
99
- debugPage("judged isOrderSensitive=%s for description: %s", isOrderSensitive, options.targetDescription);
100
- } catch (error) {
101
- debugPage('Failed to judge isOrderSensitive: %s', error);
102
- }
91
+ const isOrderSensitive = await judgeOrderSensitive(options, debugPage);
103
92
  const xpaths = await this.getXpathsByPoint(point, isOrderSensitive);
104
93
  const sanitized = sanitizeXpaths(xpaths);
105
94
  if (!sanitized.length) debugPage('cacheFeatureForPoint: no xpath found at point %o', center);
@@ -114,22 +103,14 @@ class Page {
114
103
  }
115
104
  }
116
105
  async rectMatchesCacheFeature(feature) {
117
- const webFeature = feature;
118
- const xpaths = sanitizeXpaths(webFeature.xpaths);
106
+ const xpaths = sanitizeXpaths(feature.xpaths);
119
107
  debugPage('rectMatchesCacheFeature: trying %d xpath(s)', xpaths.length);
120
108
  for (const xpath of xpaths)try {
121
109
  debugPage('rectMatchesCacheFeature: evaluating xpath: %s', xpath);
122
110
  const elementInfo = await this.getElementInfoByXpath(xpath);
123
111
  if (elementInfo?.rect) {
124
112
  debugPage('rectMatchesCacheFeature: found element, rect: %o', elementInfo.rect);
125
- const matchedRect = {
126
- left: elementInfo.rect.left,
127
- top: elementInfo.rect.top,
128
- width: elementInfo.rect.width,
129
- height: elementInfo.rect.height
130
- };
131
- if (this.viewportSize?.dpr) matchedRect.dpr = this.viewportSize.dpr;
132
- return matchedRect;
113
+ return buildRectFromElementInfo(elementInfo, this.viewportSize?.dpr);
133
114
  }
134
115
  debugPage('rectMatchesCacheFeature: element found but no rect (elementInfo: %o)', elementInfo);
135
116
  } catch (error) {