var __accessCheck = (obj, member, msg) => {
  if (!member.has(obj))
    throw TypeError("Cannot " + msg);
};
var __privateGet = (obj, member, getter) => {
  __accessCheck(obj, member, "read from private field");
  return getter ? getter.call(obj) : member.get(obj);
};
var __privateAdd = (obj, member, value) => {
  if (member.has(obj))
    throw TypeError("Cannot add the same private member more than once");
  member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
};
var __privateSet = (obj, member, value, setter) => {
  __accessCheck(obj, member, "write to private field");
  setter ? setter.call(obj, value) : member.set(obj, value);
  return value;
};
var __privateMethod = (obj, member, method) => {
  __accessCheck(obj, member, "access private method");
  return method;
};

// src/bridge-mode/page-browser-side.ts
import { assert as assert4 } from "@midscene_spp/shared/utils";

// src/common/ui-utils.ts
var limitOpenNewTabScript = `
if (!window.__MIDSCENE_NEW_TAB_INTERCEPTOR_INITIALIZED__) {
  window.__MIDSCENE_NEW_TAB_INTERCEPTOR_INITIALIZED__ = true;

  // Intercept the window.open method (only once)
  window.open = function(url) {
    console.log('Blocked window.open:', url);
    window.location.href = url;
    return null;
  };

  // Block all a tag clicks with target="_blank" (only once)
  document.addEventListener('click', function(e) {
    const target = e.target.closest('a');
    if (target && target.target === '_blank') {
      e.preventDefault();
      console.log('Blocked new tab:', target.href);
      window.location.href = target.href;
      target.removeAttribute('target');
    }
  }, true);
}
`;

// src/chrome-extension/page.ts
import { treeToList } from "@midscene_spp/shared/extractor";
import { assert as assert2 } from "@midscene_spp/shared/utils";

// src/chrome-extension/cdpInput.ts
import {
  _keyDefinitions
} from "@midscene_spp/shared/keyboard-layout";
import { assert } from "@midscene_spp/shared/utils";
var _pressedKeys, _client, _modifierBit, modifierBit_fn, _keyDescriptionForString, keyDescriptionForString_fn;
var CdpKeyboard = class {
  constructor(client) {
    __privateAdd(this, _modifierBit);
    __privateAdd(this, _keyDescriptionForString);
    __privateAdd(this, _pressedKeys, /* @__PURE__ */ new Set());
    __privateAdd(this, _client, void 0);
    this._modifiers = 0;
    __privateSet(this, _client, client);
  }
  updateClient(client) {
    __privateSet(this, _client, client);
  }
  async down(key, options = {
    text: void 0,
    commands: []
  }) {
    const description = __privateMethod(this, _keyDescriptionForString, keyDescriptionForString_fn).call(this, key);
    const autoRepeat = __privateGet(this, _pressedKeys).has(description.code);
    __privateGet(this, _pressedKeys).add(description.code);
    this._modifiers |= __privateMethod(this, _modifierBit, modifierBit_fn).call(this, description.key);
    const text = options.text === void 0 ? description.text : options.text;
    await __privateGet(this, _client).send("Input.dispatchKeyEvent", {
      type: text ? "keyDown" : "rawKeyDown",
      modifiers: this._modifiers,
      windowsVirtualKeyCode: description.keyCode,
      code: description.code,
      key: description.key,
      text,
      unmodifiedText: text,
      autoRepeat,
      location: description.location,
      isKeypad: description.location === 3,
      commands: options.commands
    });
  }
  async up(key) {
    const description = __privateMethod(this, _keyDescriptionForString, keyDescriptionForString_fn).call(this, key);
    this._modifiers &= ~__privateMethod(this, _modifierBit, modifierBit_fn).call(this, description.key);
    __privateGet(this, _pressedKeys).delete(description.code);
    await __privateGet(this, _client).send("Input.dispatchKeyEvent", {
      type: "keyUp",
      modifiers: this._modifiers,
      key: description.key,
      windowsVirtualKeyCode: description.keyCode,
      code: description.code,
      location: description.location
    });
  }
  async sendCharacter(char) {
    await __privateGet(this, _client).send("Input.insertText", { text: char });
  }
  charIsKey(char) {
    return !!_keyDefinitions[char];
  }
  async type(text, options = {}) {
    const delay = options.delay || void 0;
    for (const char of text) {
      if (this.charIsKey(char)) {
        await this.press(char, { delay });
      } else {
        if (delay) {
          await new Promise((f) => {
            return setTimeout(f, delay);
          });
        }
        await this.sendCharacter(char);
      }
    }
  }
  async press(key, options = {}) {
    const { delay = null } = options;
    const keys = Array.isArray(key) ? key : [key];
    for (const k of keys) {
      await this.down(k, options);
    }
    if (delay) {
      await new Promise((f) => {
        return setTimeout(f, options.delay);
      });
    }
    for (const k of [...keys].reverse()) {
      await this.up(k);
    }
  }
};
_pressedKeys = new WeakMap();
_client = new WeakMap();
_modifierBit = new WeakSet();
modifierBit_fn = function(key) {
  if (key === "Alt") {
    return 1;
  }
  if (key === "Control") {
    return 2;
  }
  if (key === "Meta") {
    return 4;
  }
  if (key === "Shift") {
    return 8;
  }
  return 0;
};
_keyDescriptionForString = new WeakSet();
keyDescriptionForString_fn = function(keyString) {
  const shift = this._modifiers & 8;
  const description = {
    key: "",
    keyCode: 0,
    code: "",
    text: "",
    location: 0
  };
  const definition = _keyDefinitions[keyString];
  assert(definition, `Unknown key: "${keyString}"`);
  if (definition.key) {
    description.key = definition.key;
  }
  if (shift && definition.shiftKey) {
    description.key = definition.shiftKey;
  }
  if (definition.keyCode) {
    description.keyCode = definition.keyCode;
  }
  if (shift && definition.shiftKeyCode) {
    description.keyCode = definition.shiftKeyCode;
  }
  if (definition.code) {
    description.code = definition.code;
  }
  if (definition.location) {
    description.location = definition.location;
  }
  if (description.key.length === 1) {
    description.text = description.key;
  }
  if (definition.text) {
    description.text = definition.text;
  }
  if (shift && definition.shiftText) {
    description.text = definition.shiftText;
  }
  if (this._modifiers & ~8) {
    description.text = "";
  }
  return description;
};

// src/chrome-extension/dynamic-scripts.ts
import fs from "fs";
import { ifInBrowser } from "@midscene_spp/shared/utils";
var scriptFileContentCache = null;
var getHtmlElementScript = async () => {
  const scriptFileToRetrieve = chrome.runtime.getURL("scripts/htmlElement.js");
  if (scriptFileContentCache)
    return scriptFileContentCache;
  if (ifInBrowser) {
    const script = await fetch(scriptFileToRetrieve);
    scriptFileContentCache = await script.text();
    return scriptFileContentCache;
  }
  return fs.readFileSync(scriptFileToRetrieve, "utf8");
};
var waterFlowScriptFileContentCache = null;
var injectWaterFlowAnimation = async () => {
  const waterFlowScriptFileToRetrieve = chrome.runtime.getURL(
    "scripts/water-flow.js"
  );
  if (waterFlowScriptFileContentCache)
    return waterFlowScriptFileContentCache;
  if (ifInBrowser) {
    const script = await fetch(waterFlowScriptFileToRetrieve);
    waterFlowScriptFileContentCache = await script.text();
    return waterFlowScriptFileContentCache;
  }
  return fs.readFileSync(waterFlowScriptFileToRetrieve, "utf8");
};
var stopWaterFlowScriptFileContentCache = null;
var injectStopWaterFlowAnimation = async () => {
  const stopWaterFlowScriptFileToRetrieve = chrome.runtime.getURL(
    "scripts/stop-water-flow.js"
  );
  if (stopWaterFlowScriptFileContentCache)
    return stopWaterFlowScriptFileContentCache;
  if (ifInBrowser) {
    const script = await fetch(stopWaterFlowScriptFileToRetrieve);
    stopWaterFlowScriptFileContentCache = await script.text();
    return stopWaterFlowScriptFileContentCache;
  }
  return fs.readFileSync(stopWaterFlowScriptFileToRetrieve, "utf8");
};

// src/chrome-extension/page.ts
function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
var ChromeExtensionProxyPage = class {
  constructor(forceSameTabNavigation) {
    this.pageType = "chrome-extension-proxy";
    this.version = "0.17.3";
    this.activeTabId = null;
    this.tabIdOfDebuggerAttached = null;
    this.attachingDebugger = null;
    this.destroyed = false;
    this.latestMouseX = 100;
    this.latestMouseY = 100;
    this.mouse = {
      click: async (x, y) => {
        await this.mouse.move(x, y);
        await this.sendCommandToDebugger("Input.dispatchMouseEvent", {
          type: "mousePressed",
          x,
          y,
          button: "left",
          clickCount: 1
        });
        await this.sendCommandToDebugger("Input.dispatchMouseEvent", {
          type: "mouseReleased",
          x,
          y,
          button: "left",
          clickCount: 1
        });
      },
      wheel: async (deltaX, deltaY, startX, startY) => {
        const finalX = startX || this.latestMouseX;
        const finalY = startY || this.latestMouseY;
        await this.showMousePointer(finalX, finalY);
        await this.sendCommandToDebugger("Input.dispatchMouseEvent", {
          type: "mouseWheel",
          x: finalX,
          y: finalY,
          deltaX,
          deltaY
        });
        this.latestMouseX = finalX;
        this.latestMouseY = finalY;
      },
      move: async (x, y) => {
        await this.showMousePointer(x, y);
        await this.sendCommandToDebugger("Input.dispatchMouseEvent", {
          type: "mouseMoved",
          x,
          y
        });
        this.latestMouseX = x;
        this.latestMouseY = y;
      },
      drag: async (from, to) => {
        await this.mouse.move(from.x, from.y);
        await this.sendCommandToDebugger("Input.dispatchMouseEvent", {
          type: "mousePressed",
          x: from.x,
          y: from.y,
          button: "left",
          clickCount: 1
        });
        await this.mouse.move(to.x, to.y);
        await this.sendCommandToDebugger("Input.dispatchMouseEvent", {
          type: "mouseReleased",
          x: to.x,
          y: to.y,
          button: "left",
          clickCount: 1
        });
      }
    };
    this.keyboard = {
      type: async (text) => {
        const cdpKeyboard = new CdpKeyboard({
          send: this.sendCommandToDebugger.bind(this)
        });
        await cdpKeyboard.type(text, { delay: 0 });
      },
      press: async (action) => {
        const cdpKeyboard = new CdpKeyboard({
          send: this.sendCommandToDebugger.bind(this)
        });
        const keys = Array.isArray(action) ? action : [action];
        for (const k of keys) {
          const commands = k.command ? [k.command] : [];
          await cdpKeyboard.down(k.key, { commands });
        }
        for (const k of [...keys].reverse()) {
          await cdpKeyboard.up(k.key);
        }
      }
    };
    this.forceSameTabNavigation = forceSameTabNavigation;
  }
  async setActiveTabId(tabId) {
    if (this.activeTabId) {
      throw new Error(
        `Active tab id is already set, which is ${this.activeTabId}, cannot set it to ${tabId}`
      );
    }
    await chrome.tabs.update(tabId, { active: true });
    this.activeTabId = tabId;
  }
  async getActiveTabId() {
    return this.activeTabId;
  }
  /**
   * Get a list of current tabs
   * @returns {Promise<Array<{id: number, title: string, url: string}>>}
   */
  async getBrowserTabList() {
    const tabs = await chrome.tabs.query({ currentWindow: true });
    return tabs.map((tab) => ({
      id: `${tab.id}`,
      title: tab.title,
      url: tab.url,
      currentActiveTab: tab.active
    })).filter((tab) => tab.id && tab.title && tab.url);
  }
  async getTabIdOrConnectToCurrentTab() {
    if (this.activeTabId) {
      return this.activeTabId;
    }
    const tabId = await chrome.tabs.query({ active: true, currentWindow: true }).then((tabs) => tabs[0]?.id);
    this.activeTabId = tabId || 0;
    return this.activeTabId;
  }
  async attachDebugger() {
    assert2(!this.destroyed, "Page is destroyed");
    if (this.attachingDebugger) {
      await this.attachingDebugger;
      return;
    }
    this.attachingDebugger = (async () => {
      const url = await this.url();
      let error = null;
      if (url.startsWith("chrome://")) {
        throw new Error(
          "Cannot attach debugger to chrome:// pages, please use Midscene in a normal page with http://, https:// or file://"
        );
      }
      try {
        const currentTabId = await this.getTabIdOrConnectToCurrentTab();
        if (this.tabIdOfDebuggerAttached === currentTabId) {
          return;
        }
        if (this.tabIdOfDebuggerAttached && this.tabIdOfDebuggerAttached !== currentTabId) {
          console.log(
            "detach the previous tab",
            this.tabIdOfDebuggerAttached,
            "->",
            currentTabId
          );
          try {
            await this.detachDebugger(this.tabIdOfDebuggerAttached);
          } catch (error2) {
            console.error("Failed to detach debugger", error2);
          }
        }
        console.log("attaching debugger", currentTabId);
        await chrome.debugger.attach({ tabId: currentTabId }, "1.3");
        await sleep(500);
        this.tabIdOfDebuggerAttached = currentTabId;
        await this.enableWaterFlowAnimation();
      } catch (e) {
        console.error("Failed to attach debugger", e);
        error = e;
      } finally {
        this.attachingDebugger = null;
      }
      if (error) {
        throw error;
      }
    })();
    await this.attachingDebugger;
  }
  async showMousePointer(x, y) {
    const pointerScript = `(() => {
      if(typeof window.midsceneWaterFlowAnimation !== 'undefined') {
        window.midsceneWaterFlowAnimation.enable();
        window.midsceneWaterFlowAnimation.showMousePointer(${x}, ${y});
      } else {
        console.log('midsceneWaterFlowAnimation is not defined');
      }
    })()`;
    await this.sendCommandToDebugger("Runtime.evaluate", {
      expression: `${pointerScript}`
    });
  }
  async hideMousePointer() {
    await this.sendCommandToDebugger("Runtime.evaluate", {
      expression: `(() => {
        if(typeof window.midsceneWaterFlowAnimation !== 'undefined') {
          window.midsceneWaterFlowAnimation.hideMousePointer();
        }
      })()`
    });
  }
  async detachDebugger(tabId) {
    const tabIdToDetach = tabId || this.tabIdOfDebuggerAttached;
    console.log("detaching debugger", tabIdToDetach);
    if (!tabIdToDetach) {
      console.warn("No tab id to detach");
      return;
    }
    try {
      await this.disableWaterFlowAnimation(tabIdToDetach);
      await sleep(200);
    } catch (error) {
      console.warn("Failed to disable water flow animation", error);
    }
    try {
      await chrome.debugger.detach({ tabId: tabIdToDetach });
    } catch (error) {
      console.warn("Failed to detach debugger", error);
    }
    this.tabIdOfDebuggerAttached = null;
  }
  async enableWaterFlowAnimation() {
    if (this.forceSameTabNavigation) {
      await chrome.debugger.sendCommand(
        { tabId: this.tabIdOfDebuggerAttached },
        "Runtime.evaluate",
        {
          expression: limitOpenNewTabScript
        }
      );
    }
    const script = await injectWaterFlowAnimation();
    await chrome.debugger.sendCommand(
      { tabId: this.tabIdOfDebuggerAttached },
      "Runtime.evaluate",
      {
        expression: script
      }
    );
  }
  async disableWaterFlowAnimation(tabId) {
    const script = await injectStopWaterFlowAnimation();
    await chrome.debugger.sendCommand({ tabId }, "Runtime.evaluate", {
      expression: script
    });
  }
  async sendCommandToDebugger(command, params) {
    await this.attachDebugger();
    assert2(this.tabIdOfDebuggerAttached, "Debugger is not attached");
    this.enableWaterFlowAnimation();
    return await chrome.debugger.sendCommand(
      { tabId: this.tabIdOfDebuggerAttached },
      command,
      params
    );
  }
  async getPageContentByCDP() {
    const script = await getHtmlElementScript();
    await this.sendCommandToDebugger("Runtime.evaluate", {
      expression: script
    });
    const expression = () => {
      window.midscene_element_inspector.setNodeHashCacheListOnWindow();
      return {
        tree: window.midscene_element_inspector.webExtractNodeTree(),
        size: {
          width: document.documentElement.clientWidth,
          height: document.documentElement.clientHeight,
          dpr: window.devicePixelRatio
        }
      };
    };
    const returnValue = await this.sendCommandToDebugger("Runtime.evaluate", {
      expression: `(${expression.toString()})()`,
      returnByValue: true
    });
    if (!returnValue.result.value) {
      const errorDescription = returnValue.exceptionDetails?.exception?.description || "";
      if (!errorDescription) {
        console.error("returnValue from cdp", returnValue);
      }
      throw new Error(
        `Failed to get page content from page, error: ${errorDescription}`
      );
    }
    return returnValue.result.value;
  }
  async evaluateJavaScript(script) {
    return this.sendCommandToDebugger("Runtime.evaluate", {
      expression: script
    });
  }
  // current implementation is wait until domReadyState is complete
  async waitUntilNetworkIdle() {
    const timeout = 1e4;
    const startTime = Date.now();
    let lastReadyState = "";
    while (Date.now() - startTime < timeout) {
      const result = await this.sendCommandToDebugger("Runtime.evaluate", {
        expression: "document.readyState"
      });
      lastReadyState = result.result.value;
      if (lastReadyState === "complete") {
        await new Promise((resolve) => setTimeout(resolve, 300));
        return;
      }
      await new Promise((resolve) => setTimeout(resolve, 300));
    }
    throw new Error(
      `Failed to wait until network idle, last readyState: ${lastReadyState}`
    );
  }
  async getElementsInfo() {
    const tree = await this.getElementsNodeTree();
    return treeToList(tree);
  }
  async getXpathsById(id) {
    const script = await getHtmlElementScript();
    await this.sendCommandToDebugger("Runtime.evaluate", {
      expression: script
    });
    const result = await this.sendCommandToDebugger("Runtime.evaluate", {
      expression: `window.midscene_element_inspector.getXpathsById('${id}')`,
      returnByValue: true
    });
    return result.result.value;
  }
  async getElementInfoByXpath(xpath) {
    const script = await getHtmlElementScript();
    await this.sendCommandToDebugger("Runtime.evaluate", {
      expression: script
    });
    const result = await this.sendCommandToDebugger("Runtime.evaluate", {
      expression: `window.midscene_element_inspector.getElementInfoByXpath('${xpath}')`,
      returnByValue: true
    });
    return result.result.value;
  }
  async getElementsNodeTree() {
    await this.hideMousePointer();
    const content = await this.getPageContentByCDP();
    if (content?.size) {
      this.viewportSize = content.size;
    }
    return content?.tree || { node: null, children: [] };
  }
  async size() {
    if (this.viewportSize)
      return this.viewportSize;
    const content = await this.getPageContentByCDP();
    return content.size;
  }
  async screenshotBase64() {
    await this.hideMousePointer();
    const base64 = await this.sendCommandToDebugger("Page.captureScreenshot", {
      format: "jpeg",
      quality: 90
    });
    return `data:image/jpeg;base64,${base64.data}`;
  }
  async url() {
    const tabId = await this.getTabIdOrConnectToCurrentTab();
    const url = await chrome.tabs.get(tabId).then((tab) => tab.url);
    return url || "";
  }
  async scrollUntilTop(startingPoint) {
    if (startingPoint) {
      await this.mouse.move(startingPoint.left, startingPoint.top);
    }
    return this.mouse.wheel(0, -9999999);
  }
  async scrollUntilBottom(startingPoint) {
    if (startingPoint) {
      await this.mouse.move(startingPoint.left, startingPoint.top);
    }
    return this.mouse.wheel(0, 9999999);
  }
  async scrollUntilLeft(startingPoint) {
    if (startingPoint) {
      await this.mouse.move(startingPoint.left, startingPoint.top);
    }
    return this.mouse.wheel(-9999999, 0);
  }
  async scrollUntilRight(startingPoint) {
    if (startingPoint) {
      await this.mouse.move(startingPoint.left, startingPoint.top);
    }
    return this.mouse.wheel(9999999, 0);
  }
  async scrollUp(distance, startingPoint) {
    const { height } = await this.size();
    const scrollDistance = distance || height * 0.7;
    return this.mouse.wheel(
      0,
      -scrollDistance,
      startingPoint?.left,
      startingPoint?.top
    );
  }
  async scrollDown(distance, startingPoint) {
    const { height } = await this.size();
    const scrollDistance = distance || height * 0.7;
    return this.mouse.wheel(
      0,
      scrollDistance,
      startingPoint?.left,
      startingPoint?.top
    );
  }
  async scrollLeft(distance, startingPoint) {
    const { width } = await this.size();
    const scrollDistance = distance || width * 0.7;
    return this.mouse.wheel(
      -scrollDistance,
      0,
      startingPoint?.left,
      startingPoint?.top
    );
  }
  async scrollRight(distance, startingPoint) {
    const { width } = await this.size();
    const scrollDistance = distance || width * 0.7;
    return this.mouse.wheel(
      scrollDistance,
      0,
      startingPoint?.left,
      startingPoint?.top
    );
  }
  async clearInput(element) {
    if (!element) {
      console.warn("No element to clear input");
      return;
    }
    await this.mouse.click(element.center[0], element.center[1]);
    await this.sendCommandToDebugger("Input.dispatchKeyEvent", {
      type: "keyDown",
      commands: ["selectAll"]
    });
    await this.sendCommandToDebugger("Input.dispatchKeyEvent", {
      type: "keyUp",
      commands: ["selectAll"]
    });
    await sleep(100);
    await this.keyboard.press({
      key: "Backspace"
    });
  }
  async destroy() {
    this.activeTabId = null;
    await this.detachDebugger();
    this.destroyed = true;
  }
};

// src/bridge-mode/common.ts
var DefaultBridgeServerPort = 3766;
var DefaultLocalEndpoint = `http://127.0.0.1:${DefaultBridgeServerPort}`;

// src/bridge-mode/io-client.ts
import { assert as assert3 } from "@midscene_spp/shared/utils";
import { io as ClientIO } from "socket.io-client";
var BridgeClient = class {
  constructor(endpoint, onBridgeCall, onDisconnect) {
    this.endpoint = endpoint;
    this.onBridgeCall = onBridgeCall;
    this.onDisconnect = onDisconnect;
    this.socket = null;
    this.serverVersion = null;
  }
  async connect() {
    return new Promise((resolve, reject) => {
      this.socket = ClientIO(this.endpoint, {
        reconnection: false,
        query: {
          version: "0.17.3"
        }
      });
      const timeout = setTimeout(() => {
        try {
          this.socket?.offAny();
          this.socket?.close();
        } catch (e) {
          console.warn("got error when offing socket", e);
        }
        this.socket = null;
        reject(new Error("failed to connect to bridge server after timeout"));
      }, 1 * 1e3);
      this.socket.on("disconnect", (reason) => {
        this.socket = null;
        this.onDisconnect?.();
      });
      this.socket.on("connect_error", (e) => {
        console.error("bridge-connect-error", e);
        reject(new Error(e || "bridge connect error"));
      });
      this.socket.on(
        "bridge-connected" /* Connected */,
        (payload) => {
          clearTimeout(timeout);
          this.serverVersion = payload?.version || "unknown";
          resolve(this.socket);
        }
      );
      this.socket.on("bridge-refused" /* Refused */, (e) => {
        console.error("bridge-refused", e);
        try {
          this.socket?.disconnect();
        } catch (e2) {
        }
        reject(new Error(e || "bridge refused"));
      });
      this.socket.on("bridge-call" /* Call */, (call) => {
        const id = call.id;
        assert3(typeof id !== "undefined", "call id is required");
        (async () => {
          let response;
          try {
            response = await this.onBridgeCall(call.method, call.args);
          } catch (e) {
            const errorContent = `Error from bridge client when calling, method: ${call.method}, args: ${call.args}, error: ${e?.message || e}
${e?.stack || ""}`;
            console.error(errorContent);
            return this.socket?.emit("bridge-call-response" /* CallResponse */, {
              id,
              error: errorContent
            });
          }
          this.socket?.emit("bridge-call-response" /* CallResponse */, {
            id,
            response
          });
        })();
      });
    });
  }
  disconnect() {
    this.socket?.disconnect();
    this.socket = null;
  }
};

// src/bridge-mode/page-browser-side.ts
var ExtensionBridgePageBrowserSide = class extends ChromeExtensionProxyPage {
  constructor(onDisconnect = () => {
  }, onLogMessage = () => {
  }, forceSameTabNavigation = true) {
    super(forceSameTabNavigation);
    this.onDisconnect = onDisconnect;
    this.onLogMessage = onLogMessage;
    this.bridgeClient = null;
    this.newlyCreatedTabIds = [];
  }
  async setupBridgeClient() {
    this.bridgeClient = new BridgeClient(
      `ws://localhost:${DefaultBridgeServerPort}`,
      async (method, args) => {
        console.log("bridge call from cli side", method, args);
        if (method === "connectNewTabWithUrl" /* ConnectNewTabWithUrl */) {
          return this.connectNewTabWithUrl.apply(
            this,
            args
          );
        }
        if (method === "getBrowserTabList" /* GetBrowserTabList */) {
          return this.getBrowserTabList.apply(this, args);
        }
        if (method === "setActiveTabId" /* SetActiveTabId */) {
          return this.setActiveTabId.apply(this, args);
        }
        if (method === "connectCurrentTab" /* ConnectCurrentTab */) {
          return this.connectCurrentTab.apply(this, args);
        }
        if (method === "bridge-update-agent-status" /* UpdateAgentStatus */) {
          return this.onLogMessage(args[0], "status");
        }
        const tabId = await this.getActiveTabId();
        if (!tabId || tabId === 0) {
          throw new Error("no tab is connected");
        }
        if (method.startsWith("mouse." /* PREFIX */)) {
          const actionName = method.split(".")[1];
          if (actionName === "drag") {
            return this.mouse[actionName].apply(this.mouse, args);
          }
          return this.mouse[actionName].apply(this.mouse, args);
        }
        if (method.startsWith("keyboard." /* PREFIX */)) {
          const actionName = method.split(".")[1];
          if (actionName === "press") {
            return this.keyboard[actionName].apply(this.keyboard, args);
          }
          return this.keyboard[actionName].apply(this.keyboard, args);
        }
        try {
          const result = await this[method](
            ...args
          );
          return result;
        } catch (e) {
          const errorMessage = e instanceof Error ? e.message : "Unknown error";
          console.error("error calling method", method, args, e);
          this.onLogMessage(
            `Error calling method: ${method}, ${errorMessage}`,
            "log"
          );
          throw new Error(errorMessage, { cause: e });
        }
      },
      // on disconnect
      () => {
        return this.destroy();
      }
    );
    await this.bridgeClient.connect();
    this.onLogMessage(
      `Bridge connected, cli-side version v${this.bridgeClient.serverVersion}, browser-side version v${"0.17.3"}`,
      "log"
    );
  }
  async connect() {
    return await this.setupBridgeClient();
  }
  async connectNewTabWithUrl(url, options = {
    forceSameTabNavigation: true
  }) {
    const tab = await chrome.tabs.create({ url });
    const tabId = tab.id;
    assert4(tabId, "failed to get tabId after creating a new tab");
    this.onLogMessage(`Creating new tab: ${url}`, "log");
    this.newlyCreatedTabIds.push(tabId);
    if (options?.forceSameTabNavigation) {
      this.forceSameTabNavigation = true;
    }
    await this.setActiveTabId(tabId);
  }
  async connectCurrentTab(options = {
    forceSameTabNavigation: true
  }) {
    const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
    const tabId = tabs[0]?.id;
    assert4(tabId, "failed to get tabId");
    this.onLogMessage(`Connected to current tab: ${tabs[0]?.url}`, "log");
    if (options?.forceSameTabNavigation) {
      this.forceSameTabNavigation = true;
    }
    await this.setActiveTabId(tabId);
  }
  async setDestroyOptions(options) {
    this.destroyOptions = options;
  }
  async destroy() {
    if (this.destroyOptions?.closeTab && this.newlyCreatedTabIds.length > 0) {
      this.onLogMessage("Closing all newly created tabs by bridge...", "log");
      for (const tabId of this.newlyCreatedTabIds) {
        await chrome.tabs.remove(tabId);
      }
      this.newlyCreatedTabIds = [];
    }
    await super.destroy();
    if (this.bridgeClient) {
      this.bridgeClient.disconnect();
      this.bridgeClient = null;
      this.onDisconnect();
    }
  }
};
export {
  ExtensionBridgePageBrowserSide
};
/**
 * @license
 * Copyright 2017 Google Inc.
 * SPDX-License-Identifier: Apache-2.0
 */

//# sourceMappingURL=bridge-mode-browser.js.map