@letsscrapedata/controller 0.0.55 → 0.0.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1982 -137
- package/dist/index.d.cts +14 -5
- package/dist/index.d.ts +14 -5
- package/dist/index.js +1982 -137
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -470,6 +470,9 @@ var PlaywrightPage = class extends import_node_events.default {
|
|
|
470
470
|
const localStorageStr = await page.evaluate(() => JSON.stringify(window.localStorage));
|
|
471
471
|
const localStorageObj = JSON.parse(localStorageStr);
|
|
472
472
|
const localStorageItems = Object.keys(localStorageObj).map((name) => ({ name, value: localStorageObj[name] }));
|
|
473
|
+
if (localStorageItems.length === 0) {
|
|
474
|
+
return [];
|
|
475
|
+
}
|
|
473
476
|
const url = new URL(page.url());
|
|
474
477
|
return [{ origin: url.origin, localStorage: localStorageItems }];
|
|
475
478
|
}
|
|
@@ -2254,6 +2257,9 @@ var PuppeteerPage = class extends import_node_events4.default {
|
|
|
2254
2257
|
const localStorageStr = await page.evaluate(() => JSON.stringify(window.localStorage));
|
|
2255
2258
|
const localStorageObj = JSON.parse(localStorageStr);
|
|
2256
2259
|
const localStorageItems = Object.keys(localStorageObj).map((name) => ({ name, value: localStorageObj[name] }));
|
|
2260
|
+
if (localStorageItems.length === 0) {
|
|
2261
|
+
return [];
|
|
2262
|
+
}
|
|
2257
2263
|
const url = new URL(page.url());
|
|
2258
2264
|
return [{ origin: url.origin, localStorage: localStorageItems }];
|
|
2259
2265
|
}
|
|
@@ -4007,6 +4013,7 @@ var import_os = __toESM(require("os"), 1);
|
|
|
4007
4013
|
var import_puppeteer = __toESM(require("puppeteer"), 1);
|
|
4008
4014
|
var import_playwright = __toESM(require("playwright"), 1);
|
|
4009
4015
|
var import_patchright = __toESM(require("patchright"), 1);
|
|
4016
|
+
var import_camoufox_js = require("camoufox-js");
|
|
4010
4017
|
|
|
4011
4018
|
// src/patchright/browser.ts
|
|
4012
4019
|
var import_node_events10 = __toESM(require("events"), 1);
|
|
@@ -4051,12 +4058,12 @@ var PatchrightElement = class _PatchrightElement {
|
|
|
4051
4058
|
return {};
|
|
4052
4059
|
}
|
|
4053
4060
|
}
|
|
4054
|
-
async evaluate(func, args) {
|
|
4061
|
+
async evaluate(func, args, isolated = true) {
|
|
4055
4062
|
try {
|
|
4056
4063
|
const frame = this.#frame;
|
|
4057
4064
|
;
|
|
4058
4065
|
if (typeof frame.parentFrame === "function") {
|
|
4059
|
-
return await frame.evaluate(func, args);
|
|
4066
|
+
return await frame.evaluate(func, args, !!isolated);
|
|
4060
4067
|
} else {
|
|
4061
4068
|
const locator = this.#frame.owner();
|
|
4062
4069
|
return await locator.evaluate(func, args);
|
|
@@ -4386,6 +4393,9 @@ var PatchrightPage = class extends import_node_events8.default {
|
|
|
4386
4393
|
const localStorageStr = await page.evaluate(() => JSON.stringify(window.localStorage));
|
|
4387
4394
|
const localStorageObj = JSON.parse(localStorageStr);
|
|
4388
4395
|
const localStorageItems = Object.keys(localStorageObj).map((name) => ({ name, value: localStorageObj[name] }));
|
|
4396
|
+
if (localStorageItems.length === 0) {
|
|
4397
|
+
return [];
|
|
4398
|
+
}
|
|
4389
4399
|
const url = new URL(page.url());
|
|
4390
4400
|
return [{ origin: url.origin, localStorage: localStorageItems }];
|
|
4391
4401
|
}
|
|
@@ -4709,18 +4719,17 @@ var PatchrightPage = class extends import_node_events8.default {
|
|
|
4709
4719
|
const height = await this.#page.evaluate(() => document.documentElement.scrollHeight);
|
|
4710
4720
|
return height;
|
|
4711
4721
|
}
|
|
4712
|
-
async evaluate(func, args) {
|
|
4722
|
+
async evaluate(func, args, isolated = true) {
|
|
4713
4723
|
if (!this.#page) {
|
|
4714
4724
|
throw new Error("No valid page");
|
|
4715
4725
|
}
|
|
4716
|
-
return this.#page.evaluate(func, args);
|
|
4726
|
+
return this.#page.evaluate(func, args, !!isolated);
|
|
4717
4727
|
}
|
|
4718
|
-
async exposeFunction(
|
|
4728
|
+
async exposeFunction(_name, _callbackFunction) {
|
|
4719
4729
|
if (!this.#page) {
|
|
4720
4730
|
throw new Error("No valid page");
|
|
4721
4731
|
}
|
|
4722
|
-
|
|
4723
|
-
return;
|
|
4732
|
+
throw new Error(`Patchright does not support page.exposeFunction to prevent detection`);
|
|
4724
4733
|
}
|
|
4725
4734
|
async findElement(selectorOrXpath, iframeOptions = []) {
|
|
4726
4735
|
if (!this.#page) {
|
|
@@ -5660,7 +5669,7 @@ var PatchrightBrowser = class _PatchrightBrowser extends import_node_events10.de
|
|
|
5660
5669
|
this.#pid = pid;
|
|
5661
5670
|
this.#createTime = (0, import_utils13.getCurrentUnixTime)();
|
|
5662
5671
|
this.#lsdBrowserContexts = [];
|
|
5663
|
-
this.#browserControllerType = "
|
|
5672
|
+
this.#browserControllerType = "patchright";
|
|
5664
5673
|
this.#browserType = browserType;
|
|
5665
5674
|
if (!_PatchrightBrowser.#supportedBrowserTypes.includes(browserType)) {
|
|
5666
5675
|
throw new Error(`Browser controller ${this.#browserControllerType} doesnot support browserType ${browserType}`);
|
|
@@ -5810,151 +5819,1956 @@ var PatchrightBrowser = class _PatchrightBrowser extends import_node_events10.de
|
|
|
5810
5819
|
};
|
|
5811
5820
|
|
|
5812
5821
|
// src/controller/controller.ts
|
|
5822
|
+
var import_utils18 = require("@letsscrapedata/utils");
|
|
5823
|
+
|
|
5824
|
+
// src/camoufox/browser.ts
|
|
5825
|
+
var import_node_events13 = __toESM(require("events"), 1);
|
|
5826
|
+
var import_utils17 = require("@letsscrapedata/utils");
|
|
5827
|
+
|
|
5828
|
+
// src/camoufox/context.ts
|
|
5829
|
+
var import_node_events12 = __toESM(require("events"), 1);
|
|
5830
|
+
var import_utils16 = require("@letsscrapedata/utils");
|
|
5831
|
+
|
|
5832
|
+
// src/camoufox/page.ts
|
|
5833
|
+
var import_node_events11 = __toESM(require("events"), 1);
|
|
5834
|
+
var import_utils15 = require("@letsscrapedata/utils");
|
|
5835
|
+
|
|
5836
|
+
// src/camoufox/element.ts
|
|
5813
5837
|
var import_utils14 = require("@letsscrapedata/utils");
|
|
5814
|
-
var
|
|
5815
|
-
|
|
5816
|
-
#
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
/**
|
|
5821
|
-
* Possible values are 'aix', 'darwin', 'freebsd','linux', 'openbsd', 'sunos', and 'win32'.
|
|
5822
|
-
*/
|
|
5823
|
-
#osPlatform;
|
|
5824
|
-
constructor() {
|
|
5825
|
-
if (_LsdBrowserController.#forbidConstructor) {
|
|
5826
|
-
throw new Error("Only one LsdBrowserController instance can be created!");
|
|
5838
|
+
var CamoufoxElement = class _CamoufoxElement {
|
|
5839
|
+
#frame;
|
|
5840
|
+
#locator;
|
|
5841
|
+
constructor(locator, frame) {
|
|
5842
|
+
if (!frame.locator || !locator.click) {
|
|
5843
|
+
throw new Error("Invalid paras in new CamoufoxElement");
|
|
5827
5844
|
}
|
|
5828
|
-
this.#
|
|
5829
|
-
this.#
|
|
5830
|
-
chromium: import_playwright.default.chromium,
|
|
5831
|
-
firefox: import_playwright.default.firefox,
|
|
5832
|
-
webkit: import_playwright.default.webkit
|
|
5833
|
-
};
|
|
5834
|
-
this.#patchrightBrowserTypes = {
|
|
5835
|
-
chromium: import_patchright.default.chromium,
|
|
5836
|
-
firefox: import_patchright.default.firefox,
|
|
5837
|
-
webkit: import_patchright.default.webkit
|
|
5838
|
-
};
|
|
5839
|
-
this.#osPlatform = import_os.default.platform();
|
|
5840
|
-
this.#nextBrowserIdx = 1;
|
|
5841
|
-
_LsdBrowserController.#forbidConstructor = true;
|
|
5845
|
+
this.#frame = frame;
|
|
5846
|
+
this.#locator = locator;
|
|
5842
5847
|
}
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
} else if (connectFlag) {
|
|
5847
|
-
throw new Error(`playwright only can connect to chromium browser, not support ${browserType} browser`);
|
|
5848
|
-
} else if (browserType === "firefox") {
|
|
5849
|
-
return this.#playwrightBrowserTypes.firefox;
|
|
5850
|
-
} else if (browserType === "webkit") {
|
|
5851
|
-
return this.#playwrightBrowserTypes.webkit;
|
|
5852
|
-
} else {
|
|
5853
|
-
throw new Error(`Invalid playwright browserType ${browserType}`);
|
|
5854
|
-
}
|
|
5848
|
+
async attribute(attributeName) {
|
|
5849
|
+
const attributeValue = await this.#locator.getAttribute(attributeName);
|
|
5850
|
+
return attributeValue ? attributeValue : "";
|
|
5855
5851
|
}
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5852
|
+
async attributeNames() {
|
|
5853
|
+
const names = await this.#locator.evaluate((node) => node.getAttributeNames());
|
|
5854
|
+
return names;
|
|
5855
|
+
}
|
|
5856
|
+
async boundingBox() {
|
|
5857
|
+
return await this.#locator.boundingBox();
|
|
5858
|
+
}
|
|
5859
|
+
async dataset() {
|
|
5860
|
+
try {
|
|
5861
|
+
const dataset = await this.#locator.evaluate((node) => node.dataset);
|
|
5862
|
+
return dataset;
|
|
5863
|
+
} catch (err) {
|
|
5864
|
+
return {};
|
|
5867
5865
|
}
|
|
5868
5866
|
}
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5867
|
+
async evaluate(func, args, isolated = true) {
|
|
5868
|
+
try {
|
|
5869
|
+
const frame = this.#frame;
|
|
5870
|
+
;
|
|
5871
|
+
if (typeof frame.parentFrame === "function") {
|
|
5872
|
+
if (typeof func === "string" && !isolated) {
|
|
5873
|
+
return await frame.evaluate(`mw:${func}`, args);
|
|
5874
|
+
} else {
|
|
5875
|
+
return await frame.evaluate(func, args);
|
|
5876
|
+
}
|
|
5877
|
+
} else {
|
|
5878
|
+
const locator = this.#frame.owner();
|
|
5879
|
+
if (typeof func === "string" && !isolated) {
|
|
5880
|
+
return await locator.evaluate(`mw:${func}`, args);
|
|
5881
|
+
} else {
|
|
5882
|
+
return await locator.evaluate(func, args);
|
|
5883
|
+
}
|
|
5884
|
+
}
|
|
5885
|
+
} catch (err) {
|
|
5886
|
+
logerr(err);
|
|
5887
|
+
return "";
|
|
5874
5888
|
}
|
|
5875
5889
|
}
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
if (!
|
|
5879
|
-
throw new Error(
|
|
5890
|
+
/*
|
|
5891
|
+
async #getChildFrame(parentFrame: Frame, iframeOption: IframeOption): Promise<Frame | null> {
|
|
5892
|
+
if (!parentFrame) {
|
|
5893
|
+
throw new Error("Invalid parent frame");
|
|
5880
5894
|
}
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
if (!
|
|
5884
|
-
throw new Error(
|
|
5895
|
+
|
|
5896
|
+
let { src = "" } = iframeOption;
|
|
5897
|
+
if (!src) {
|
|
5898
|
+
throw new Error("Invalid src in IframeOption");
|
|
5885
5899
|
}
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
(
|
|
5900
|
+
|
|
5901
|
+
// src: use childFrames()
|
|
5902
|
+
const childFrames = parentFrame.childFrames();
|
|
5903
|
+
for (const childFrame of childFrames) {
|
|
5904
|
+
const url = childFrame.url();
|
|
5905
|
+
if (typeof src === "string") {
|
|
5906
|
+
// src: string
|
|
5907
|
+
if (url.startsWith(src)) {
|
|
5908
|
+
return childFrame;
|
|
5909
|
+
} else if (url.toLowerCase().startsWith(src)) {
|
|
5910
|
+
return childFrame;
|
|
5911
|
+
}
|
|
5912
|
+
} else {
|
|
5913
|
+
// src: RegExp
|
|
5914
|
+
if (url.match(src)) {
|
|
5915
|
+
return childFrame;
|
|
5916
|
+
}
|
|
5917
|
+
}
|
|
5894
5918
|
}
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5919
|
+
|
|
5920
|
+
return null;
|
|
5921
|
+
}
|
|
5922
|
+
*/
|
|
5923
|
+
async #getChildFrameLocator(parent, iframeOption) {
|
|
5924
|
+
return parent.frameLocator(getIframeSelector(iframeOption));
|
|
5925
|
+
}
|
|
5926
|
+
async #getDescendantFrame(parent, iframeOptions) {
|
|
5927
|
+
try {
|
|
5928
|
+
if (iframeOptions.length <= 0) {
|
|
5929
|
+
return null;
|
|
5898
5930
|
}
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
5902
|
-
|
|
5903
|
-
|
|
5904
|
-
|
|
5905
|
-
default:
|
|
5906
|
-
(0, import_utils14.unreachable)(browserType);
|
|
5931
|
+
let frameLocator = parent.frameLocator(getIframeSelector(iframeOptions[0]));
|
|
5932
|
+
for (const iframeOption of iframeOptions.slice(1)) {
|
|
5933
|
+
if (!frameLocator) {
|
|
5934
|
+
return null;
|
|
5935
|
+
}
|
|
5936
|
+
frameLocator = await this.#getChildFrameLocator(frameLocator, iframeOption);
|
|
5907
5937
|
}
|
|
5908
|
-
|
|
5909
|
-
|
|
5938
|
+
return frameLocator;
|
|
5939
|
+
} catch (err) {
|
|
5940
|
+
throw new Error(`No child iframe: ${JSON.stringify(iframeOptions)}`);
|
|
5910
5941
|
}
|
|
5911
|
-
return true;
|
|
5912
5942
|
}
|
|
5913
|
-
async
|
|
5914
|
-
let
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
|
|
5918
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
5921
|
-
|
|
5922
|
-
|
|
5923
|
-
|
|
5924
|
-
maxWindowSize = true,
|
|
5925
|
-
headless = true,
|
|
5926
|
-
minBrowserContexts = 1,
|
|
5927
|
-
// incognito
|
|
5928
|
-
proxyPerBrowserContext = false,
|
|
5929
|
-
userDataDir = "",
|
|
5930
|
-
userAgent = ""
|
|
5931
|
-
} = options ? options : {};
|
|
5932
|
-
let browserPid = 0;
|
|
5933
|
-
const incognito = typeof options?.incognito === "boolean" ? options.incognito : browserControllerType === "puppeteer" ? false : true;
|
|
5934
|
-
const actOptions = { closeFreePagesIntervalSeconds, maxBrowserContextsPerBrowser, maxPagesPerBrowserContext, maxPageFreeSeconds, maxViewportOfNewPage, proxy, timeout, args, executablePath, maxWindowSize, headless, minBrowserContexts, incognito, proxyPerBrowserContext, userDataDir, userAgent };
|
|
5935
|
-
let idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--incoginto"));
|
|
5936
|
-
if (idx >= 0) {
|
|
5937
|
-
logwarn(`Please use options.incognito instead when launching new browser.`);
|
|
5938
|
-
args.splice(idx, 1);
|
|
5939
|
-
}
|
|
5940
|
-
idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--proxy-server"));
|
|
5941
|
-
if (idx >= 0) {
|
|
5942
|
-
logwarn(`Please use options.proxy instead when launching new browser.`);
|
|
5943
|
-
args.splice(idx, 1);
|
|
5943
|
+
async #findElementHandles(selector, absolute = false, iframeOptions = []) {
|
|
5944
|
+
let parent = absolute ? this.#frame : this.#locator;
|
|
5945
|
+
let frame = this.#frame;
|
|
5946
|
+
const retObj = { frame, locators: [] };
|
|
5947
|
+
if (iframeOptions.length > 0) {
|
|
5948
|
+
const childFrame = await this.#getDescendantFrame(frame, iframeOptions);
|
|
5949
|
+
if (!childFrame) {
|
|
5950
|
+
return retObj;
|
|
5951
|
+
}
|
|
5952
|
+
retObj.frame = childFrame;
|
|
5953
|
+
parent = childFrame;
|
|
5944
5954
|
}
|
|
5945
|
-
|
|
5946
|
-
|
|
5947
|
-
|
|
5948
|
-
|
|
5955
|
+
try {
|
|
5956
|
+
let locators = [];
|
|
5957
|
+
if (selector.startsWith("./") || selector.startsWith("/") || selector.startsWith("..")) {
|
|
5958
|
+
locators = await parent.locator(`xpath=${selector}`).all();
|
|
5959
|
+
} else {
|
|
5960
|
+
if (selector !== ".") {
|
|
5961
|
+
locators = await parent.locator(selector).all();
|
|
5962
|
+
} else {
|
|
5963
|
+
locators = [this.#locator];
|
|
5964
|
+
}
|
|
5965
|
+
}
|
|
5966
|
+
retObj.locators = locators;
|
|
5967
|
+
return retObj;
|
|
5968
|
+
} catch (err) {
|
|
5969
|
+
loginfo(err);
|
|
5970
|
+
return retObj;
|
|
5949
5971
|
}
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5972
|
+
}
|
|
5973
|
+
async findElement(selectorOrXpath, iframeOptions = [], absolute = false) {
|
|
5974
|
+
const selectors = typeof selectorOrXpath === "string" ? [selectorOrXpath] : selectorOrXpath;
|
|
5975
|
+
if (!Array.isArray(selectors)) {
|
|
5976
|
+
throw new Error(`Invalid selectorOrXpath ${selectorOrXpath} in findElement`);
|
|
5954
5977
|
}
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5978
|
+
for (const selector of selectors) {
|
|
5979
|
+
const { frame, locators } = await this.#findElementHandles(selector, absolute, iframeOptions);
|
|
5980
|
+
if (locators.length > 0) {
|
|
5981
|
+
const playwrightElement = new _CamoufoxElement(locators[0], frame);
|
|
5982
|
+
return playwrightElement;
|
|
5983
|
+
}
|
|
5984
|
+
}
|
|
5985
|
+
return null;
|
|
5986
|
+
}
|
|
5987
|
+
async findElements(selectorOrXpath, iframeOptions = [], absolute = false) {
|
|
5988
|
+
const selectors = typeof selectorOrXpath === "string" ? [selectorOrXpath] : selectorOrXpath;
|
|
5989
|
+
if (!Array.isArray(selectors)) {
|
|
5990
|
+
throw new Error(`Invalid selectorOrXpath ${selectorOrXpath} in findElements`);
|
|
5991
|
+
}
|
|
5992
|
+
for (const selector of selectors) {
|
|
5993
|
+
const { frame, locators } = await this.#findElementHandles(selector, absolute, iframeOptions);
|
|
5994
|
+
if (locators.length > 0) {
|
|
5995
|
+
const playwrightElements = locators.map((locator) => new _CamoufoxElement(locator, frame));
|
|
5996
|
+
return playwrightElements;
|
|
5997
|
+
}
|
|
5998
|
+
}
|
|
5999
|
+
return [];
|
|
6000
|
+
}
|
|
6001
|
+
async hasAttribute(attributeName) {
|
|
6002
|
+
const hasFlag = await this.#locator.evaluate((node, attr) => node.hasAttribute(attr), attributeName);
|
|
6003
|
+
return hasFlag;
|
|
6004
|
+
}
|
|
6005
|
+
async innerHtml() {
|
|
6006
|
+
const html = await this.#locator.innerHTML();
|
|
6007
|
+
return html;
|
|
6008
|
+
}
|
|
6009
|
+
async innerText(onlyChild = false) {
|
|
6010
|
+
let text = "";
|
|
6011
|
+
if (onlyChild) {
|
|
6012
|
+
text = await this.#locator.evaluate((node) => {
|
|
6013
|
+
let child = node.firstChild;
|
|
6014
|
+
let texts = [];
|
|
6015
|
+
while (child) {
|
|
6016
|
+
if (child.nodeType == 3) {
|
|
6017
|
+
texts.push(child.data);
|
|
6018
|
+
}
|
|
6019
|
+
child = child.nextSibling;
|
|
6020
|
+
}
|
|
6021
|
+
return texts.join(" ");
|
|
6022
|
+
});
|
|
6023
|
+
} else {
|
|
6024
|
+
text = await this.#locator.innerText();
|
|
6025
|
+
}
|
|
6026
|
+
return text;
|
|
6027
|
+
}
|
|
6028
|
+
async outerHtml() {
|
|
6029
|
+
const html = await this.#locator.evaluate((node) => node.outerHTML);
|
|
6030
|
+
return html;
|
|
6031
|
+
}
|
|
6032
|
+
async textContent() {
|
|
6033
|
+
const text = await this.#locator.textContent();
|
|
6034
|
+
return text ? text : "";
|
|
6035
|
+
}
|
|
6036
|
+
async click(options = {}) {
|
|
6037
|
+
const { button, clickCount: count, delay, position: offset, clickType = "click" } = options;
|
|
6038
|
+
const actOptions = { button, count, delay, offset };
|
|
6039
|
+
if (clickType === "click") {
|
|
6040
|
+
await this.#locator.click(actOptions);
|
|
6041
|
+
} else if (clickType === "evaluate") {
|
|
6042
|
+
await this.#locator.evaluate(async (ev) => await ev.click());
|
|
6043
|
+
} else {
|
|
6044
|
+
(0, import_utils14.unreachable)(clickType);
|
|
6045
|
+
}
|
|
6046
|
+
return true;
|
|
6047
|
+
}
|
|
6048
|
+
async focus() {
|
|
6049
|
+
await this.#locator.focus();
|
|
6050
|
+
return true;
|
|
6051
|
+
}
|
|
6052
|
+
async hover() {
|
|
6053
|
+
await this.#locator.hover();
|
|
6054
|
+
return true;
|
|
6055
|
+
}
|
|
6056
|
+
async input(value, options = {}) {
|
|
6057
|
+
const { delay = 0, replace = false, enter = false } = options;
|
|
6058
|
+
if (replace) {
|
|
6059
|
+
await this.#locator.click({ button: "left", clickCount: 3 });
|
|
6060
|
+
}
|
|
6061
|
+
if (delay > 0) {
|
|
6062
|
+
await this.#locator.fill(value);
|
|
6063
|
+
} else {
|
|
6064
|
+
await this.#locator.fill(value);
|
|
6065
|
+
}
|
|
6066
|
+
if (enter) {
|
|
6067
|
+
await this.#locator.press("Enter");
|
|
6068
|
+
}
|
|
6069
|
+
return true;
|
|
6070
|
+
}
|
|
6071
|
+
async press(key, options = {}) {
|
|
6072
|
+
await this.#locator.press(key, options);
|
|
6073
|
+
return true;
|
|
6074
|
+
}
|
|
6075
|
+
async screenshot(options) {
|
|
6076
|
+
return await this.#locator.screenshot(options);
|
|
6077
|
+
}
|
|
6078
|
+
async scrollIntoView() {
|
|
6079
|
+
await this.#locator.scrollIntoViewIfNeeded();
|
|
6080
|
+
return true;
|
|
6081
|
+
}
|
|
6082
|
+
async select(options) {
|
|
6083
|
+
const { type, values = [], labels = [], indexes = [] } = options;
|
|
6084
|
+
switch (type) {
|
|
6085
|
+
case "value":
|
|
6086
|
+
if (values.length > 0) {
|
|
6087
|
+
await this.#locator.selectOption(values);
|
|
6088
|
+
}
|
|
6089
|
+
break;
|
|
6090
|
+
case "label":
|
|
6091
|
+
if (labels.length > 0) {
|
|
6092
|
+
await this.#locator.selectOption(labels.map((label) => {
|
|
6093
|
+
return { label };
|
|
6094
|
+
}));
|
|
6095
|
+
}
|
|
6096
|
+
break;
|
|
6097
|
+
case "index":
|
|
6098
|
+
if (indexes.length > 0) {
|
|
6099
|
+
const indexValues = await this.#locator.evaluate(
|
|
6100
|
+
(node, indexes2) => {
|
|
6101
|
+
const options2 = node.options;
|
|
6102
|
+
const len = options2.length;
|
|
6103
|
+
const vals = [];
|
|
6104
|
+
for (const index of indexes2.filter((i) => i >= 0 && i < len)) {
|
|
6105
|
+
vals.push(options2[index].value);
|
|
6106
|
+
}
|
|
6107
|
+
return vals;
|
|
6108
|
+
},
|
|
6109
|
+
indexes
|
|
6110
|
+
);
|
|
6111
|
+
if (indexValues.length > 0) {
|
|
6112
|
+
await this.#locator.selectOption(indexValues);
|
|
6113
|
+
}
|
|
6114
|
+
}
|
|
6115
|
+
break;
|
|
6116
|
+
default:
|
|
6117
|
+
(0, import_utils14.unreachable)(type);
|
|
6118
|
+
}
|
|
6119
|
+
return true;
|
|
6120
|
+
}
|
|
6121
|
+
async setAttribute(attributeName, newValue) {
|
|
6122
|
+
await this.#locator.evaluate((node, argvs) => {
|
|
6123
|
+
node.setAttribute(argvs[0], argvs[1]);
|
|
6124
|
+
}, [attributeName, newValue]);
|
|
6125
|
+
return true;
|
|
6126
|
+
}
|
|
6127
|
+
_origElement() {
|
|
6128
|
+
return this.#locator;
|
|
6129
|
+
}
|
|
6130
|
+
};
|
|
6131
|
+
|
|
6132
|
+
// src/camoufox/page.ts
|
|
6133
|
+
var CamoufoxPage = class extends import_node_events11.default {
|
|
6134
|
+
#lsdBrowserContext;
|
|
6135
|
+
#page;
|
|
6136
|
+
#status;
|
|
6137
|
+
#pageId;
|
|
6138
|
+
#closeWhenFree;
|
|
6139
|
+
#resquestInterceptionOptions;
|
|
6140
|
+
#responseInterceptionOptions;
|
|
6141
|
+
#client;
|
|
6142
|
+
#responseCb;
|
|
6143
|
+
#hasValidUrl(page) {
|
|
6144
|
+
const url = page.url();
|
|
6145
|
+
return url.toLowerCase().startsWith("http");
|
|
6146
|
+
}
|
|
6147
|
+
async #clearCookies(page) {
|
|
6148
|
+
if (!this.#hasValidUrl(page)) {
|
|
6149
|
+
throw new Error("Please open related url before clearing cookies");
|
|
6150
|
+
}
|
|
6151
|
+
const browserContext = this.#lsdBrowserContext._origBrowserContext();
|
|
6152
|
+
if (!browserContext) {
|
|
6153
|
+
throw new Error(`Invalid LsdBrowserContext`);
|
|
6154
|
+
}
|
|
6155
|
+
const cookieItems = await this.#getCookies(page);
|
|
6156
|
+
const domainSet = new Set(cookieItems.map((c) => c.domain));
|
|
6157
|
+
if (domainSet.size !== 1) {
|
|
6158
|
+
logwarn(`Domains in clearCookies: ${Array.from(domainSet.values())}`);
|
|
6159
|
+
}
|
|
6160
|
+
for (const domain of domainSet.values()) {
|
|
6161
|
+
await browserContext.clearCookies({ domain });
|
|
6162
|
+
}
|
|
6163
|
+
return true;
|
|
6164
|
+
}
|
|
6165
|
+
async #getCookies(page) {
|
|
6166
|
+
if (!this.#hasValidUrl(page)) {
|
|
6167
|
+
throw new Error("Please open related url before getting cookies");
|
|
6168
|
+
}
|
|
6169
|
+
const browserContext = this.#lsdBrowserContext._origBrowserContext();
|
|
6170
|
+
if (!browserContext) {
|
|
6171
|
+
throw new Error(`Invalid LsdBrowserContext`);
|
|
6172
|
+
}
|
|
6173
|
+
const url = page.url();
|
|
6174
|
+
const origCookies = await browserContext.cookies(url);
|
|
6175
|
+
const cookies = origCookies.map((origCookie) => {
|
|
6176
|
+
const { name, value, domain, path, expires, httpOnly, secure, sameSite = "Lax" } = origCookie;
|
|
6177
|
+
return { name, value, domain, path, expires, httpOnly, secure, sameSite };
|
|
6178
|
+
});
|
|
6179
|
+
return cookies;
|
|
6180
|
+
}
|
|
6181
|
+
async #setCookies(page, cookies) {
|
|
6182
|
+
if (!page) {
|
|
6183
|
+
throw new Error("No valid page");
|
|
6184
|
+
}
|
|
6185
|
+
if (Array.isArray(cookies) && cookies.length > 0 && cookies.every((c) => typeof c.name === "string")) {
|
|
6186
|
+
const browserContext = this.#lsdBrowserContext._origBrowserContext();
|
|
6187
|
+
if (!browserContext) {
|
|
6188
|
+
throw new Error(`Invalid LsdBrowserContext`);
|
|
6189
|
+
}
|
|
6190
|
+
await browserContext.addCookies(cookies);
|
|
6191
|
+
return true;
|
|
6192
|
+
} else {
|
|
6193
|
+
return false;
|
|
6194
|
+
}
|
|
6195
|
+
}
|
|
6196
|
+
async #clearLocalStorage(page) {
|
|
6197
|
+
if (!this.#hasValidUrl(page)) {
|
|
6198
|
+
throw new Error("Please open related url before clearing localStorage");
|
|
6199
|
+
}
|
|
6200
|
+
await page.evaluate(() => window.localStorage.clear());
|
|
6201
|
+
return true;
|
|
6202
|
+
}
|
|
6203
|
+
async #getLocalStorage(page) {
|
|
6204
|
+
if (!this.#hasValidUrl(page)) {
|
|
6205
|
+
throw new Error("Please open related url before getting localStorage");
|
|
6206
|
+
}
|
|
6207
|
+
const localStorageStr = await page.evaluate(() => JSON.stringify(window.localStorage));
|
|
6208
|
+
const localStorageObj = JSON.parse(localStorageStr);
|
|
6209
|
+
const localStorageItems = Object.keys(localStorageObj).map((name) => ({ name, value: localStorageObj[name] }));
|
|
6210
|
+
if (localStorageItems.length === 0) {
|
|
6211
|
+
return [];
|
|
6212
|
+
}
|
|
6213
|
+
const url = new URL(page.url());
|
|
6214
|
+
return [{ origin: url.origin, localStorage: localStorageItems }];
|
|
6215
|
+
}
|
|
6216
|
+
async #setLocalStorage(page, localStorageItems) {
|
|
6217
|
+
if (!this.#hasValidUrl(page)) {
|
|
6218
|
+
throw new Error("Please open related url before setting localStorage");
|
|
6219
|
+
}
|
|
6220
|
+
await page.evaluate((items) => {
|
|
6221
|
+
for (const item of items) {
|
|
6222
|
+
window.localStorage.setItem(item.name, item.value);
|
|
6223
|
+
}
|
|
6224
|
+
}, localStorageItems);
|
|
6225
|
+
return true;
|
|
6226
|
+
}
|
|
6227
|
+
async #clearIndexedDB(page) {
|
|
6228
|
+
if (!this.#hasValidUrl(page)) {
|
|
6229
|
+
throw new Error("Please open related url before clearing indexedDB");
|
|
6230
|
+
}
|
|
6231
|
+
await page.evaluate(async () => {
|
|
6232
|
+
for (const db of await indexedDB.databases?.() || []) {
|
|
6233
|
+
if (db.name)
|
|
6234
|
+
indexedDB.deleteDatabase(db.name);
|
|
6235
|
+
}
|
|
6236
|
+
});
|
|
6237
|
+
return true;
|
|
6238
|
+
}
|
|
6239
|
+
/*
|
|
6240
|
+
async #getChildFrame(parentFrame: Frame, iframeOption: IframeOption): Promise<Frame | null> {
|
|
6241
|
+
if (!parentFrame) {
|
|
6242
|
+
throw new Error("Invalid parent frame");
|
|
6243
|
+
}
|
|
6244
|
+
|
|
6245
|
+
let { src = "" } = iframeOption;
|
|
6246
|
+
if (!src) {
|
|
6247
|
+
throw new Error("Invalid src in IframeOption");
|
|
6248
|
+
}
|
|
6249
|
+
|
|
6250
|
+
// src: use childFrames()
|
|
6251
|
+
const childFrames = parentFrame.childFrames();
|
|
6252
|
+
for (const childFrame of childFrames) {
|
|
6253
|
+
const url = childFrame.url();
|
|
6254
|
+
if (typeof src === "string") {
|
|
6255
|
+
// src: string
|
|
6256
|
+
if (url.startsWith(src)) {
|
|
6257
|
+
return childFrame;
|
|
6258
|
+
} else if (url.toLowerCase().startsWith(src)) {
|
|
6259
|
+
return childFrame;
|
|
6260
|
+
}
|
|
6261
|
+
} else {
|
|
6262
|
+
// src: RegExp
|
|
6263
|
+
if (url.match(src)) {
|
|
6264
|
+
return childFrame;
|
|
6265
|
+
}
|
|
6266
|
+
}
|
|
6267
|
+
}
|
|
6268
|
+
|
|
6269
|
+
return null;
|
|
6270
|
+
}
|
|
6271
|
+
*/
|
|
6272
|
+
async #findDescendantFrame(src, id) {
|
|
6273
|
+
if (!this.#page) {
|
|
6274
|
+
throw new Error("No valid page");
|
|
6275
|
+
}
|
|
6276
|
+
const frames = this.#page.frames();
|
|
6277
|
+
for (const frame of frames) {
|
|
6278
|
+
const url = frame.url();
|
|
6279
|
+
if (typeof src === "string" && src) {
|
|
6280
|
+
if (url.startsWith(src)) {
|
|
6281
|
+
return frame;
|
|
6282
|
+
} else if (url.toLowerCase().startsWith(src)) {
|
|
6283
|
+
return frame;
|
|
6284
|
+
}
|
|
6285
|
+
} else if (src instanceof RegExp) {
|
|
6286
|
+
if (url.match(src)) {
|
|
6287
|
+
return frame;
|
|
6288
|
+
}
|
|
6289
|
+
} else if (id) {
|
|
6290
|
+
const element = await frame.frameElement();
|
|
6291
|
+
if (element) {
|
|
6292
|
+
const frameId = await frame.evaluate(([ele, attr]) => ele.getAttribute(attr), [element, "id"]);
|
|
6293
|
+
if (frameId === id) {
|
|
6294
|
+
return frame;
|
|
6295
|
+
}
|
|
6296
|
+
}
|
|
6297
|
+
}
|
|
6298
|
+
}
|
|
6299
|
+
return null;
|
|
6300
|
+
}
|
|
6301
|
+
async #getChildFrameLocator(parent, iframeOption) {
|
|
6302
|
+
return parent.frameLocator(getIframeSelector(iframeOption));
|
|
6303
|
+
}
|
|
6304
|
+
async #getDescendantFrame(mainFrame, iframeOptions) {
|
|
6305
|
+
try {
|
|
6306
|
+
if (iframeOptions.length <= 0) {
|
|
6307
|
+
return null;
|
|
6308
|
+
}
|
|
6309
|
+
if (iframeOptions.length === 1 && !iframeOptions[0].selector) {
|
|
6310
|
+
const { src = "", id = "" } = iframeOptions[0];
|
|
6311
|
+
const frame = await this.#findDescendantFrame(src, id);
|
|
6312
|
+
return frame;
|
|
6313
|
+
} else {
|
|
6314
|
+
let frameLocator = mainFrame.frameLocator(getIframeSelector(iframeOptions[0]));
|
|
6315
|
+
for (const iframeOption of iframeOptions.slice(1)) {
|
|
6316
|
+
if (!frameLocator) {
|
|
6317
|
+
return null;
|
|
6318
|
+
}
|
|
6319
|
+
frameLocator = await this.#getChildFrameLocator(frameLocator, iframeOption);
|
|
6320
|
+
}
|
|
6321
|
+
return frameLocator;
|
|
6322
|
+
}
|
|
6323
|
+
} catch (err) {
|
|
6324
|
+
throw new Error(`No child iframe: ${JSON.stringify(iframeOptions)}`);
|
|
6325
|
+
}
|
|
6326
|
+
}
|
|
6327
|
+
async #findElementHandles(selector, iframeOptions = []) {
|
|
6328
|
+
if (!this.#page) {
|
|
6329
|
+
throw new Error("No valid page");
|
|
6330
|
+
}
|
|
6331
|
+
let frame = this.#page.mainFrame();
|
|
6332
|
+
const retObj = { frame, locators: [] };
|
|
6333
|
+
if (iframeOptions.length > 0) {
|
|
6334
|
+
frame = await this.#getDescendantFrame(frame, iframeOptions);
|
|
6335
|
+
if (!frame) {
|
|
6336
|
+
return retObj;
|
|
6337
|
+
}
|
|
6338
|
+
retObj.frame = frame;
|
|
6339
|
+
}
|
|
6340
|
+
try {
|
|
6341
|
+
let locators = [];
|
|
6342
|
+
if (selector.startsWith("./") || selector.startsWith("/") || selector.startsWith("..")) {
|
|
6343
|
+
locators = await frame.locator(`xpath=${selector}`).all();
|
|
6344
|
+
} else {
|
|
6345
|
+
if (selector !== ".") {
|
|
6346
|
+
locators = await frame.locator(selector).all();
|
|
6347
|
+
} else {
|
|
6348
|
+
throw new Error("Cannot use selector '.' on page");
|
|
6349
|
+
}
|
|
6350
|
+
}
|
|
6351
|
+
retObj.locators = locators;
|
|
6352
|
+
return retObj;
|
|
6353
|
+
} catch (err) {
|
|
6354
|
+
loginfo(err);
|
|
6355
|
+
return retObj;
|
|
6356
|
+
}
|
|
6357
|
+
}
|
|
6358
|
+
#addPageOn() {
|
|
6359
|
+
if (!this.#page) {
|
|
6360
|
+
throw new Error("No valid page");
|
|
6361
|
+
}
|
|
6362
|
+
const page = this.#page;
|
|
6363
|
+
const pageId = this.#pageId;
|
|
6364
|
+
page.on("close", async () => {
|
|
6365
|
+
loginfo(`##browser ${pageId} closed`);
|
|
6366
|
+
if (!page.pageInfo) {
|
|
6367
|
+
logerr(`Logic error in page.on("close")`);
|
|
6368
|
+
}
|
|
6369
|
+
this.emit("pageClose");
|
|
6370
|
+
this.#lsdBrowserContext.emit("pageClose", this);
|
|
6371
|
+
});
|
|
6372
|
+
page.on("popup", (p) => {
|
|
6373
|
+
if (p) {
|
|
6374
|
+
let evtData = null;
|
|
6375
|
+
const pageInfo = p.pageInfo;
|
|
6376
|
+
let popupPageId = "page";
|
|
6377
|
+
if (pageInfo) {
|
|
6378
|
+
const { browserIdx, browserContextIdx, pageIdx } = pageInfo;
|
|
6379
|
+
popupPageId = `page-${browserIdx}-${browserContextIdx}-${pageIdx}`;
|
|
6380
|
+
pageInfo.openType = "popup";
|
|
6381
|
+
evtData = this.browserContext().page(pageIdx);
|
|
6382
|
+
if (evtData && page.pageInfo?.taskId) {
|
|
6383
|
+
pageInfo.relatedId = page.pageInfo.taskId;
|
|
6384
|
+
}
|
|
6385
|
+
} else {
|
|
6386
|
+
logerr(`##browser ${pageId} has popup without page.pageInfo`);
|
|
6387
|
+
}
|
|
6388
|
+
loginfo(`##browser ${pageId} has popup ${popupPageId}`);
|
|
6389
|
+
this.emit("pagePopup", evtData);
|
|
6390
|
+
} else {
|
|
6391
|
+
logerr(`##browser ${pageId} has popup page with null page`);
|
|
6392
|
+
}
|
|
6393
|
+
});
|
|
6394
|
+
}
|
|
6395
|
+
constructor(browserContext, page, pageInfo) {
|
|
6396
|
+
if (!browserContext.pages || !page?.goto) {
|
|
6397
|
+
throw new Error("Invalid paras in new LsdPage");
|
|
6398
|
+
}
|
|
6399
|
+
super();
|
|
6400
|
+
this.#lsdBrowserContext = browserContext;
|
|
6401
|
+
this.#page = page;
|
|
6402
|
+
this.#status = "free";
|
|
6403
|
+
const currentTime = (0, import_utils15.getCurrentUnixTime)();
|
|
6404
|
+
const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, lastStatusUpdateTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
|
|
6405
|
+
this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, lastStatusUpdateTime, taskId, relatedId, misc };
|
|
6406
|
+
this.#pageId = `page-${browserIdx}-${browserContextIdx}-${pageIdx}`;
|
|
6407
|
+
this.#closeWhenFree = false;
|
|
6408
|
+
this.#resquestInterceptionOptions = [];
|
|
6409
|
+
this.#responseInterceptionOptions = [];
|
|
6410
|
+
this.#client = null;
|
|
6411
|
+
this.#responseCb = null;
|
|
6412
|
+
this.#addPageOn();
|
|
6413
|
+
}
|
|
6414
|
+
async addPreloadScript() {
|
|
6415
|
+
throw new Error(`Camoufox does not support page.addPreloadScript to prevent detection`);
|
|
6416
|
+
}
|
|
6417
|
+
async addScriptTag(_options) {
|
|
6418
|
+
throw new Error(`Camoufox does not support page.addPreloadScript to prevent detection`);
|
|
6419
|
+
}
|
|
6420
|
+
apiContext() {
|
|
6421
|
+
return this.browserContext().apiContext();
|
|
6422
|
+
}
|
|
6423
|
+
async bringToFront() {
|
|
6424
|
+
if (!this.#page) {
|
|
6425
|
+
throw new Error("No valid page");
|
|
6426
|
+
}
|
|
6427
|
+
await this.#page.bringToFront();
|
|
6428
|
+
return true;
|
|
6429
|
+
}
|
|
6430
|
+
browserContext() {
|
|
6431
|
+
return this.#lsdBrowserContext;
|
|
6432
|
+
}
|
|
6433
|
+
async clearCookies() {
|
|
6434
|
+
if (!this.#page) {
|
|
6435
|
+
throw new Error("No valid page");
|
|
6436
|
+
}
|
|
6437
|
+
return await this.#clearCookies(this.#page);
|
|
6438
|
+
}
|
|
6439
|
+
async clearLocalStorage() {
|
|
6440
|
+
if (!this.#page) {
|
|
6441
|
+
throw new Error("No valid page");
|
|
6442
|
+
}
|
|
6443
|
+
return await this.#clearLocalStorage(this.#page);
|
|
6444
|
+
}
|
|
6445
|
+
async clearRequestInterceptions() {
|
|
6446
|
+
if (!this.#page) {
|
|
6447
|
+
throw new Error("No valid page");
|
|
6448
|
+
}
|
|
6449
|
+
await this.#page.unrouteAll();
|
|
6450
|
+
return true;
|
|
6451
|
+
}
|
|
6452
|
+
async clearResponseInterceptions() {
|
|
6453
|
+
if (!this.#page) {
|
|
6454
|
+
throw new Error("No valid page");
|
|
6455
|
+
}
|
|
6456
|
+
try {
|
|
6457
|
+
if (this.#responseInterceptionOptions.length > 0) {
|
|
6458
|
+
if (this.#responseCb) {
|
|
6459
|
+
this.#page.removeListener("response", this.#responseCb);
|
|
6460
|
+
}
|
|
6461
|
+
this.#responseInterceptionOptions = [];
|
|
6462
|
+
}
|
|
6463
|
+
return true;
|
|
6464
|
+
} catch (err) {
|
|
6465
|
+
logerr(err);
|
|
6466
|
+
return false;
|
|
6467
|
+
}
|
|
6468
|
+
}
|
|
6469
|
+
async clearStateData() {
|
|
6470
|
+
if (!this.#page) {
|
|
6471
|
+
throw new Error("No valid page");
|
|
6472
|
+
}
|
|
6473
|
+
await this.#clearCookies(this.#page);
|
|
6474
|
+
await this.#clearIndexedDB(this.#page);
|
|
6475
|
+
return await this.#clearLocalStorage(this.#page);
|
|
6476
|
+
}
|
|
6477
|
+
async close() {
|
|
6478
|
+
if (this.#status === "closed") {
|
|
6479
|
+
logwarn(`Page ${this.#pageId} is already closed.`);
|
|
6480
|
+
return true;
|
|
6481
|
+
} else if (this.#status === "busy") {
|
|
6482
|
+
throw new Error(`Page ${this.#pageId} cannot be closed because it is busy.`);
|
|
6483
|
+
}
|
|
6484
|
+
if (!this.#page) {
|
|
6485
|
+
throw new Error("No valid page");
|
|
6486
|
+
}
|
|
6487
|
+
await this.#page.close();
|
|
6488
|
+
this.#page = null;
|
|
6489
|
+
this.#status = "closed";
|
|
6490
|
+
return true;
|
|
6491
|
+
}
|
|
6492
|
+
closeWhenFree() {
|
|
6493
|
+
return this.#closeWhenFree;
|
|
6494
|
+
}
|
|
6495
|
+
async content(iframeOptions = []) {
|
|
6496
|
+
if (!this.#page) {
|
|
6497
|
+
throw new Error("No valid page");
|
|
6498
|
+
}
|
|
6499
|
+
let content = "";
|
|
6500
|
+
if (iframeOptions.length > 0) {
|
|
6501
|
+
const frameLocator = await this.#getDescendantFrame(this.#page.mainFrame(), iframeOptions);
|
|
6502
|
+
if (frameLocator) {
|
|
6503
|
+
content = await frameLocator.locator(":root").evaluate(() => document.documentElement.outerHTML);
|
|
6504
|
+
}
|
|
6505
|
+
} else {
|
|
6506
|
+
content = await this.#page.content();
|
|
6507
|
+
}
|
|
6508
|
+
return content;
|
|
6509
|
+
}
|
|
6510
|
+
async cookies() {
|
|
6511
|
+
if (!this.#page) {
|
|
6512
|
+
throw new Error("No valid page");
|
|
6513
|
+
}
|
|
6514
|
+
return this.#getCookies(this.#page);
|
|
6515
|
+
}
|
|
6516
|
+
async documentHeight() {
|
|
6517
|
+
if (!this.#page) {
|
|
6518
|
+
throw new Error("No valid page");
|
|
6519
|
+
}
|
|
6520
|
+
const height = await this.#page.evaluate(() => document.documentElement.scrollHeight);
|
|
6521
|
+
return height;
|
|
6522
|
+
}
|
|
6523
|
+
async evaluate(func, args, isolated = true) {
|
|
6524
|
+
if (!this.#page) {
|
|
6525
|
+
throw new Error("No valid page");
|
|
6526
|
+
}
|
|
6527
|
+
if (typeof func === "string" && !isolated) {
|
|
6528
|
+
return this.#page.evaluate(`mw:${func}`, args);
|
|
6529
|
+
} else {
|
|
6530
|
+
return this.#page.evaluate(func, args);
|
|
6531
|
+
}
|
|
6532
|
+
}
|
|
6533
|
+
async exposeFunction(_name, _callbackFunction) {
|
|
6534
|
+
throw new Error(`Camoufox does not support page.exposeFunction to prevent detection`);
|
|
6535
|
+
}
|
|
6536
|
+
async findElement(selectorOrXpath, iframeOptions = []) {
|
|
6537
|
+
if (!this.#page) {
|
|
6538
|
+
throw new Error("No valid page");
|
|
6539
|
+
}
|
|
6540
|
+
const selectors = typeof selectorOrXpath === "string" ? [selectorOrXpath] : selectorOrXpath;
|
|
6541
|
+
if (!Array.isArray(selectors)) {
|
|
6542
|
+
throw new Error(`Invalid selectorOrXpath ${selectorOrXpath} in findElement`);
|
|
6543
|
+
}
|
|
6544
|
+
for (const selector of selectors) {
|
|
6545
|
+
const { frame, locators } = await this.#findElementHandles(selector, iframeOptions);
|
|
6546
|
+
if (locators.length > 0) {
|
|
6547
|
+
const playwrightElement = new CamoufoxElement(locators[0], frame);
|
|
6548
|
+
return playwrightElement;
|
|
6549
|
+
}
|
|
6550
|
+
}
|
|
6551
|
+
return null;
|
|
6552
|
+
}
|
|
6553
|
+
async findElements(selectorOrXpath, iframeOptions = []) {
|
|
6554
|
+
if (!this.#page) {
|
|
6555
|
+
throw new Error("No valid page");
|
|
6556
|
+
}
|
|
6557
|
+
const selectors = typeof selectorOrXpath === "string" ? [selectorOrXpath] : selectorOrXpath;
|
|
6558
|
+
if (!Array.isArray(selectors)) {
|
|
6559
|
+
throw new Error(`Invalid selectorOrXpath ${selectorOrXpath} in findElements`);
|
|
6560
|
+
}
|
|
6561
|
+
for (const selector of selectors) {
|
|
6562
|
+
const { frame, locators } = await this.#findElementHandles(selector, iframeOptions);
|
|
6563
|
+
if (locators.length > 0) {
|
|
6564
|
+
const playwrightElements = locators.map((locator) => new CamoufoxElement(locator, frame));
|
|
6565
|
+
return playwrightElements;
|
|
6566
|
+
}
|
|
6567
|
+
}
|
|
6568
|
+
return [];
|
|
6569
|
+
}
|
|
6570
|
+
async free() {
|
|
6571
|
+
if (this.#status === "free") {
|
|
6572
|
+
logwarn(`Page ${this.#pageId} is already free.`);
|
|
6573
|
+
}
|
|
6574
|
+
this.#status = "free";
|
|
6575
|
+
await this.clearRequestInterceptions();
|
|
6576
|
+
await this.clearResponseInterceptions();
|
|
6577
|
+
return true;
|
|
6578
|
+
}
|
|
6579
|
+
#getWaitUntil(origWaitUntil) {
|
|
6580
|
+
if (origWaitUntil === "networkidle0" || origWaitUntil === "networkidle2") {
|
|
6581
|
+
return "networkidle";
|
|
6582
|
+
} else {
|
|
6583
|
+
return origWaitUntil;
|
|
6584
|
+
}
|
|
6585
|
+
}
|
|
6586
|
+
async goto(url, options) {
|
|
6587
|
+
if (!this.#page) {
|
|
6588
|
+
throw new Error("No valid page");
|
|
6589
|
+
}
|
|
6590
|
+
if (options) {
|
|
6591
|
+
const { referer, timeout, waitUntil = "load" } = options;
|
|
6592
|
+
const newOptions = {};
|
|
6593
|
+
if (referer) {
|
|
6594
|
+
newOptions.referer = referer;
|
|
6595
|
+
}
|
|
6596
|
+
if (timeout) {
|
|
6597
|
+
newOptions.timeout = timeout;
|
|
6598
|
+
}
|
|
6599
|
+
newOptions.waitUntil = this.#getWaitUntil(waitUntil);
|
|
6600
|
+
await this.#page.goto(url, newOptions);
|
|
6601
|
+
} else {
|
|
6602
|
+
await this.#page.goto(url);
|
|
6603
|
+
}
|
|
6604
|
+
return true;
|
|
6605
|
+
}
|
|
6606
|
+
id() {
|
|
6607
|
+
return this.#pageId;
|
|
6608
|
+
}
|
|
6609
|
+
isFree() {
|
|
6610
|
+
return this.#status === "free";
|
|
6611
|
+
}
|
|
6612
|
+
async localStroage() {
|
|
6613
|
+
if (!this.#page) {
|
|
6614
|
+
throw new Error("No valid page");
|
|
6615
|
+
}
|
|
6616
|
+
return this.#getLocalStorage(this.#page);
|
|
6617
|
+
}
|
|
6618
|
+
load() {
|
|
6619
|
+
throw new Error("Not supported in CamoufoxPage.");
|
|
6620
|
+
}
|
|
6621
|
+
mainFrame() {
|
|
6622
|
+
if (!this.#page) {
|
|
6623
|
+
throw new Error("No valid page");
|
|
6624
|
+
}
|
|
6625
|
+
return this.#page.mainFrame();
|
|
6626
|
+
}
|
|
6627
|
+
async maximizeViewport() {
|
|
6628
|
+
const height = await this.pageHeight();
|
|
6629
|
+
const width = await this.pageWidth();
|
|
6630
|
+
return await this.setViewportSize({ height, width });
|
|
6631
|
+
}
|
|
6632
|
+
async mouseClick(x, y, options) {
|
|
6633
|
+
if (!this.#page) {
|
|
6634
|
+
throw new Error("No valid page");
|
|
6635
|
+
}
|
|
6636
|
+
await this.#page.mouse.click(x, y, options);
|
|
6637
|
+
return true;
|
|
6638
|
+
}
|
|
6639
|
+
async mouseDown() {
|
|
6640
|
+
if (!this.#page) {
|
|
6641
|
+
throw new Error("No valid page");
|
|
6642
|
+
}
|
|
6643
|
+
await this.#page.mouse.down();
|
|
6644
|
+
return true;
|
|
6645
|
+
}
|
|
6646
|
+
async mouseMove(x, y) {
|
|
6647
|
+
if (!this.#page) {
|
|
6648
|
+
throw new Error("No valid page");
|
|
6649
|
+
}
|
|
6650
|
+
await this.#page.mouse.move(x, y);
|
|
6651
|
+
return true;
|
|
6652
|
+
}
|
|
6653
|
+
async mouseUp() {
|
|
6654
|
+
if (!this.#page) {
|
|
6655
|
+
throw new Error("No valid page");
|
|
6656
|
+
}
|
|
6657
|
+
await this.#page.mouse.up();
|
|
6658
|
+
return true;
|
|
6659
|
+
}
|
|
6660
|
+
async mouseWheel(deltaX = 0, deltaY = 0) {
|
|
6661
|
+
if (!this.#page) {
|
|
6662
|
+
throw new Error("No valid page");
|
|
6663
|
+
}
|
|
6664
|
+
await this.#page.mouse.wheel(deltaX, deltaY);
|
|
6665
|
+
return true;
|
|
6666
|
+
}
|
|
6667
|
+
async pageHeight() {
|
|
6668
|
+
if (!this.#page) {
|
|
6669
|
+
throw new Error("No valid page");
|
|
6670
|
+
}
|
|
6671
|
+
const bodyHeight = await this.#page.evaluate(() => document.body.scrollHeight);
|
|
6672
|
+
const documentHeight = await this.#page.evaluate(() => document.documentElement.scrollHeight);
|
|
6673
|
+
const windowHeight = await this.#page.evaluate(() => window.outerHeight);
|
|
6674
|
+
const pageHeight = Math.max(bodyHeight, documentHeight, windowHeight);
|
|
6675
|
+
return pageHeight;
|
|
6676
|
+
}
|
|
6677
|
+
pageInfo() {
|
|
6678
|
+
if (!this.#page) {
|
|
6679
|
+
throw new Error("No valid page");
|
|
6680
|
+
}
|
|
6681
|
+
return Object.assign({}, this.#page.pageInfo);
|
|
6682
|
+
}
|
|
6683
|
+
async pageWidth() {
|
|
6684
|
+
if (!this.#page) {
|
|
6685
|
+
throw new Error("No valid page");
|
|
6686
|
+
}
|
|
6687
|
+
const offsetWidth = await this.#page.evaluate(() => document.documentElement.offsetWidth);
|
|
6688
|
+
const windowWidth = await this.#page.evaluate(() => window.outerWidth);
|
|
6689
|
+
const pageWidth = Math.max(offsetWidth, windowWidth);
|
|
6690
|
+
return pageWidth;
|
|
6691
|
+
}
|
|
6692
|
+
async pdf(options) {
|
|
6693
|
+
if (!this.#page) {
|
|
6694
|
+
throw new Error("No valid page");
|
|
6695
|
+
}
|
|
6696
|
+
const buffer = await this.#page.pdf(options);
|
|
6697
|
+
return buffer;
|
|
6698
|
+
}
|
|
6699
|
+
async reload() {
|
|
6700
|
+
if (!this.#page) {
|
|
6701
|
+
throw new Error("No valid page");
|
|
6702
|
+
}
|
|
6703
|
+
try {
|
|
6704
|
+
await this.#page.reload();
|
|
6705
|
+
return true;
|
|
6706
|
+
} catch (err) {
|
|
6707
|
+
loginfo(err);
|
|
6708
|
+
return false;
|
|
6709
|
+
}
|
|
6710
|
+
}
|
|
6711
|
+
async screenshot(options) {
|
|
6712
|
+
if (!this.#page) {
|
|
6713
|
+
throw new Error("No valid page");
|
|
6714
|
+
}
|
|
6715
|
+
return await this.#page.screenshot(options);
|
|
6716
|
+
}
|
|
6717
|
+
async scrollBy(x, y) {
|
|
6718
|
+
if (!this.#page) {
|
|
6719
|
+
throw new Error("No valid page");
|
|
6720
|
+
}
|
|
6721
|
+
await this.#page.evaluate(
|
|
6722
|
+
([x2, y2]) => {
|
|
6723
|
+
window.scrollBy(x2, y2);
|
|
6724
|
+
},
|
|
6725
|
+
[x, y]
|
|
6726
|
+
);
|
|
6727
|
+
return true;
|
|
6728
|
+
}
|
|
6729
|
+
async scrollTo(x, y) {
|
|
6730
|
+
if (!this.#page) {
|
|
6731
|
+
throw new Error("No valid page");
|
|
6732
|
+
}
|
|
6733
|
+
await this.#page.evaluate(
|
|
6734
|
+
([x2, y2]) => {
|
|
6735
|
+
window.scrollTo(x2, y2);
|
|
6736
|
+
},
|
|
6737
|
+
[x, y]
|
|
6738
|
+
);
|
|
6739
|
+
return true;
|
|
6740
|
+
}
|
|
6741
|
+
async sendCDPMessage(method, params = null, detach = true) {
|
|
6742
|
+
if (!this.#client) {
|
|
6743
|
+
const origContext = this.browserContext()._origBrowserContext();
|
|
6744
|
+
if (!origContext) {
|
|
6745
|
+
throw new Error(`Invalid playwright browserContext`);
|
|
6746
|
+
}
|
|
6747
|
+
this.#client = await origContext.newCDPSession(this.#page);
|
|
6748
|
+
}
|
|
6749
|
+
if (!this.#client) {
|
|
6750
|
+
throw new Error("No valid CDP session to send message");
|
|
6751
|
+
}
|
|
6752
|
+
const response = params ? await this.#client.send(method, params) : await this.#client.send(method);
|
|
6753
|
+
if (detach) {
|
|
6754
|
+
await this.#client.detach();
|
|
6755
|
+
this.#client = null;
|
|
6756
|
+
}
|
|
6757
|
+
return response;
|
|
6758
|
+
}
|
|
6759
|
+
setCloseWhenFree(closeWhenFree) {
|
|
6760
|
+
this.#closeWhenFree = closeWhenFree;
|
|
6761
|
+
return true;
|
|
6762
|
+
}
|
|
6763
|
+
async setCookies(cookies) {
|
|
6764
|
+
if (!this.#page) {
|
|
6765
|
+
throw new Error("No valid page");
|
|
6766
|
+
}
|
|
6767
|
+
return await this.#setCookies(this.#page, cookies);
|
|
6768
|
+
}
|
|
6769
|
+
async setExtraHTTPHeaders(headers) {
|
|
6770
|
+
if (!this.#page) {
|
|
6771
|
+
throw new Error("No valid page");
|
|
6772
|
+
}
|
|
6773
|
+
await this.#page.setExtraHTTPHeaders(headers);
|
|
6774
|
+
return true;
|
|
6775
|
+
}
|
|
6776
|
+
async setLocalStroage(localStorageItems) {
|
|
6777
|
+
if (!this.#page) {
|
|
6778
|
+
throw new Error("No valid page");
|
|
6779
|
+
}
|
|
6780
|
+
return await this.#setLocalStorage(this.#page, localStorageItems);
|
|
6781
|
+
}
|
|
6782
|
+
setPageInfo(pageInfo) {
|
|
6783
|
+
if (!this.#page?.pageInfo) {
|
|
6784
|
+
throw new Error("No valid page or pageInfo");
|
|
6785
|
+
}
|
|
6786
|
+
if (!pageInfo) {
|
|
6787
|
+
throw new Error("Invalid paras in setPageInfo");
|
|
6788
|
+
}
|
|
6789
|
+
const actPageInfo = this.#page.pageInfo;
|
|
6790
|
+
const { lastStatusUpdateTime, taskId, relatedId, misc } = pageInfo;
|
|
6791
|
+
if (typeof lastStatusUpdateTime === "number") {
|
|
6792
|
+
actPageInfo.lastStatusUpdateTime = lastStatusUpdateTime;
|
|
6793
|
+
}
|
|
6794
|
+
if (typeof taskId === "number") {
|
|
6795
|
+
actPageInfo.taskId = taskId;
|
|
6796
|
+
}
|
|
6797
|
+
if (typeof relatedId === "number") {
|
|
6798
|
+
actPageInfo.relatedId = relatedId;
|
|
6799
|
+
}
|
|
6800
|
+
if (misc && typeof misc === "object") {
|
|
6801
|
+
for (const key of Object.keys(misc)) {
|
|
6802
|
+
actPageInfo.misc[key] = misc[key];
|
|
6803
|
+
}
|
|
6804
|
+
}
|
|
6805
|
+
return true;
|
|
6806
|
+
}
|
|
6807
|
+
#checkRequestMatch(request, requestMatch) {
|
|
6808
|
+
try {
|
|
6809
|
+
if (!request) {
|
|
6810
|
+
return false;
|
|
6811
|
+
}
|
|
6812
|
+
const { methods, postData, resourceTypes, url } = requestMatch;
|
|
6813
|
+
if (methods && !methods.includes(request.method().toUpperCase())) {
|
|
6814
|
+
return false;
|
|
6815
|
+
}
|
|
6816
|
+
if (resourceTypes && !resourceTypes.includes(request.resourceType())) {
|
|
6817
|
+
return false;
|
|
6818
|
+
}
|
|
6819
|
+
if (url && !request.url().match(url)) {
|
|
6820
|
+
return false;
|
|
6821
|
+
}
|
|
6822
|
+
const origData = request.postData();
|
|
6823
|
+
const data = origData ? origData : "";
|
|
6824
|
+
if (postData && !data.match(postData)) {
|
|
6825
|
+
return false;
|
|
6826
|
+
}
|
|
6827
|
+
return true;
|
|
6828
|
+
} catch (err) {
|
|
6829
|
+
logerr(err);
|
|
6830
|
+
return false;
|
|
6831
|
+
}
|
|
6832
|
+
}
|
|
6833
|
+
async setRequestInterception(options) {
|
|
6834
|
+
if (!this.#page) {
|
|
6835
|
+
throw new Error("No valid page");
|
|
6836
|
+
}
|
|
6837
|
+
const actOptions = Array.isArray(options) ? options : [options];
|
|
6838
|
+
if (actOptions.length <= 0) {
|
|
6839
|
+
logwarn("Invalid paras in setRequestInterception");
|
|
6840
|
+
return false;
|
|
6841
|
+
}
|
|
6842
|
+
const firstRequestInterception = this.#resquestInterceptionOptions.length <= 0;
|
|
6843
|
+
for (const option of actOptions) {
|
|
6844
|
+
switch (option.action) {
|
|
6845
|
+
case "abort":
|
|
6846
|
+
case "fulfill":
|
|
6847
|
+
this.#resquestInterceptionOptions.push(option);
|
|
6848
|
+
break;
|
|
6849
|
+
default:
|
|
6850
|
+
(0, import_utils15.unreachable)(option.action);
|
|
6851
|
+
}
|
|
6852
|
+
}
|
|
6853
|
+
if (firstRequestInterception && this.#resquestInterceptionOptions.length > 0) {
|
|
6854
|
+
this.#page.route("**", async (route) => {
|
|
6855
|
+
try {
|
|
6856
|
+
for (const option of actOptions) {
|
|
6857
|
+
const { requestMatch, action, fulfill } = option;
|
|
6858
|
+
const request = route.request();
|
|
6859
|
+
const matchedFlag = !requestMatch || this.#checkRequestMatch(request, requestMatch);
|
|
6860
|
+
if (matchedFlag) {
|
|
6861
|
+
switch (action) {
|
|
6862
|
+
case "abort":
|
|
6863
|
+
await route.abort();
|
|
6864
|
+
break;
|
|
6865
|
+
case "fulfill":
|
|
6866
|
+
const body = fulfill ? fulfill : `<html><body><h1>${request.url()}</h1></body></html>`;
|
|
6867
|
+
route.fulfill({
|
|
6868
|
+
status: 200,
|
|
6869
|
+
// contentType: "text/html; charset=utf-8", // "text/plain",
|
|
6870
|
+
body
|
|
6871
|
+
});
|
|
6872
|
+
break;
|
|
6873
|
+
default:
|
|
6874
|
+
(0, import_utils15.unreachable)(action);
|
|
6875
|
+
}
|
|
6876
|
+
return true;
|
|
6877
|
+
} else {
|
|
6878
|
+
}
|
|
6879
|
+
}
|
|
6880
|
+
await route.continue();
|
|
6881
|
+
return true;
|
|
6882
|
+
} catch (err) {
|
|
6883
|
+
logerr(err);
|
|
6884
|
+
return false;
|
|
6885
|
+
}
|
|
6886
|
+
});
|
|
6887
|
+
}
|
|
6888
|
+
return true;
|
|
6889
|
+
}
|
|
6890
|
+
async #responseListener(response) {
|
|
6891
|
+
try {
|
|
6892
|
+
const pageUrl = this.#page ? this.#page.url() : "";
|
|
6893
|
+
if (!response.ok()) {
|
|
6894
|
+
return;
|
|
6895
|
+
}
|
|
6896
|
+
const request = response.request();
|
|
6897
|
+
if (!request) {
|
|
6898
|
+
return;
|
|
6899
|
+
}
|
|
6900
|
+
for (const option of this.#responseInterceptionOptions) {
|
|
6901
|
+
const { requestMatch, responseMatch, responseItems, handler, handlerOptions = {} } = option;
|
|
6902
|
+
let matchedFlag = !requestMatch || this.#checkRequestMatch(request, requestMatch);
|
|
6903
|
+
if (matchedFlag && responseMatch) {
|
|
6904
|
+
const { minLength, maxLength } = responseMatch;
|
|
6905
|
+
const text = await response.text();
|
|
6906
|
+
const len = text.length;
|
|
6907
|
+
if (minLength && minLength > 0 && len < minLength || maxLength && maxLength > 0 && len > maxLength) {
|
|
6908
|
+
matchedFlag = false;
|
|
6909
|
+
}
|
|
6910
|
+
}
|
|
6911
|
+
if (!matchedFlag) {
|
|
6912
|
+
continue;
|
|
6913
|
+
}
|
|
6914
|
+
if (Array.isArray(responseItems)) {
|
|
6915
|
+
const requestMethod = request.method();
|
|
6916
|
+
const requestUrl = request.url();
|
|
6917
|
+
const reqData2 = request.postData();
|
|
6918
|
+
const requestData = reqData2 ? reqData2 : "";
|
|
6919
|
+
const responseData = await response.text();
|
|
6920
|
+
responseItems.push({
|
|
6921
|
+
pageUrl,
|
|
6922
|
+
requestMethod,
|
|
6923
|
+
requestUrl,
|
|
6924
|
+
requestData,
|
|
6925
|
+
responseData
|
|
6926
|
+
});
|
|
6927
|
+
loginfo(`##browser cache matched response: ${requestUrl}`);
|
|
6928
|
+
}
|
|
6929
|
+
if (typeof handler === "function") {
|
|
6930
|
+
const pageData = { pageUrl, cookies: "" };
|
|
6931
|
+
await handler(response, handlerOptions, pageData);
|
|
6932
|
+
}
|
|
6933
|
+
}
|
|
6934
|
+
return;
|
|
6935
|
+
} catch (err) {
|
|
6936
|
+
logerr(err);
|
|
6937
|
+
return;
|
|
6938
|
+
}
|
|
6939
|
+
}
|
|
6940
|
+
async setResponseInterception(options) {
|
|
6941
|
+
if (!this.#page) {
|
|
6942
|
+
throw new Error("No valid page");
|
|
6943
|
+
}
|
|
6944
|
+
const actOptions = Array.isArray(options) ? options : [options];
|
|
6945
|
+
if (actOptions.length <= 0) {
|
|
6946
|
+
logwarn("Invalid paras in setResponseInterception");
|
|
6947
|
+
return false;
|
|
6948
|
+
}
|
|
6949
|
+
const firstResponseInterception = this.#responseInterceptionOptions.length <= 0;
|
|
6950
|
+
for (const option of actOptions) {
|
|
6951
|
+
if (option?.responseItems || option?.handler) {
|
|
6952
|
+
this.#responseInterceptionOptions.push(option);
|
|
6953
|
+
} else {
|
|
6954
|
+
throw new Error(`Invalid ResponseInterceptionOption`);
|
|
6955
|
+
}
|
|
6956
|
+
}
|
|
6957
|
+
if (firstResponseInterception && this.#responseInterceptionOptions.length > 0) {
|
|
6958
|
+
this.#responseCb = this.#responseListener.bind(this);
|
|
6959
|
+
this.#page.on("response", this.#responseCb);
|
|
6960
|
+
}
|
|
6961
|
+
return true;
|
|
6962
|
+
}
|
|
6963
|
+
async setStateData(stateData) {
|
|
6964
|
+
return await this.#lsdBrowserContext.setStateData(stateData);
|
|
6965
|
+
}
|
|
6966
|
+
async setUserAgent(userAgent) {
|
|
6967
|
+
if (userAgent) {
|
|
6968
|
+
throw new Error(`Camoufox does not support page.setUserAgent by now`);
|
|
6969
|
+
}
|
|
6970
|
+
return false;
|
|
6971
|
+
}
|
|
6972
|
+
async setViewportSize(viewPortSize) {
|
|
6973
|
+
if (!this.#page) {
|
|
6974
|
+
throw new Error("No valid page");
|
|
6975
|
+
}
|
|
6976
|
+
await this.#page.setViewportSize(viewPortSize);
|
|
6977
|
+
return true;
|
|
6978
|
+
}
|
|
6979
|
+
async stateData() {
|
|
6980
|
+
if (!this.#page) {
|
|
6981
|
+
throw new Error("No valid page");
|
|
6982
|
+
}
|
|
6983
|
+
const cookies = await this.#getCookies(this.#page);
|
|
6984
|
+
const localStorage = await this.#getLocalStorage(this.#page);
|
|
6985
|
+
return { cookies, localStorage };
|
|
6986
|
+
}
|
|
6987
|
+
status() {
|
|
6988
|
+
return this.#status;
|
|
6989
|
+
}
|
|
6990
|
+
async title() {
|
|
6991
|
+
if (!this.#page) {
|
|
6992
|
+
throw new Error("No valid page");
|
|
6993
|
+
}
|
|
6994
|
+
return await this.#page.title();
|
|
6995
|
+
}
|
|
6996
|
+
url() {
|
|
6997
|
+
if (!this.#page) {
|
|
6998
|
+
throw new Error("No valid page");
|
|
6999
|
+
}
|
|
7000
|
+
return this.#page.url();
|
|
7001
|
+
}
|
|
7002
|
+
use() {
|
|
7003
|
+
if (this.#status === "busy") {
|
|
7004
|
+
throw new Error(`Page ${this.#pageId} is already busy!!!`);
|
|
7005
|
+
}
|
|
7006
|
+
this.#status = "busy";
|
|
7007
|
+
return true;
|
|
7008
|
+
}
|
|
7009
|
+
async waitForElement(selector, options = {}) {
|
|
7010
|
+
if (!this.#page) {
|
|
7011
|
+
throw new Error("No valid page");
|
|
7012
|
+
}
|
|
7013
|
+
const locator = this.#page.locator(selector);
|
|
7014
|
+
const { timeout = 3e4, state = "visible" } = options;
|
|
7015
|
+
await locator.waitFor({ state, timeout });
|
|
7016
|
+
return true;
|
|
7017
|
+
}
|
|
7018
|
+
async waitForNavigation(options) {
|
|
7019
|
+
if (!this.#page) {
|
|
7020
|
+
throw new Error("No valid page");
|
|
7021
|
+
}
|
|
7022
|
+
const { url = "", timeout = 3e4, waitUntil = "load" } = options;
|
|
7023
|
+
const newWaitUntil = this.#getWaitUntil(waitUntil);
|
|
7024
|
+
if (url) {
|
|
7025
|
+
await this.#page.waitForURL(url, { timeout, waitUntil: newWaitUntil });
|
|
7026
|
+
} else if (newWaitUntil === "commit") {
|
|
7027
|
+
throw new Error("commit is not supported in CamoufoxPage.waitForNavigation");
|
|
7028
|
+
} else {
|
|
7029
|
+
await this.#page.waitForLoadState(newWaitUntil, { timeout });
|
|
7030
|
+
}
|
|
7031
|
+
return true;
|
|
7032
|
+
}
|
|
7033
|
+
async windowMember(keys) {
|
|
7034
|
+
if (!this.#page) {
|
|
7035
|
+
throw new Error("No valid page");
|
|
7036
|
+
}
|
|
7037
|
+
if (!this.#page || !Array.isArray(keys) || keys.length <= 0 || keys.length > 20) {
|
|
7038
|
+
return "";
|
|
7039
|
+
}
|
|
7040
|
+
const content = await this.#page.evaluate(
|
|
7041
|
+
(keys2) => {
|
|
7042
|
+
let retObj = window;
|
|
7043
|
+
for (const key of keys2) {
|
|
7044
|
+
if (!key) {
|
|
7045
|
+
break;
|
|
7046
|
+
} else if (typeof retObj !== "object" || !retObj) {
|
|
7047
|
+
return "";
|
|
7048
|
+
} else {
|
|
7049
|
+
retObj = retObj[key];
|
|
7050
|
+
}
|
|
7051
|
+
}
|
|
7052
|
+
if (typeof retObj === "string") {
|
|
7053
|
+
return retObj;
|
|
7054
|
+
} else if (typeof retObj === "number") {
|
|
7055
|
+
return String(retObj);
|
|
7056
|
+
} else if (typeof retObj === "boolean") {
|
|
7057
|
+
return String(Number(retObj));
|
|
7058
|
+
} else if (!retObj) {
|
|
7059
|
+
return "";
|
|
7060
|
+
} else if (typeof retObj === "object") {
|
|
7061
|
+
try {
|
|
7062
|
+
return JSON.stringify(retObj);
|
|
7063
|
+
} catch (err) {
|
|
7064
|
+
return "";
|
|
7065
|
+
}
|
|
7066
|
+
} else if (typeof retObj === "bigint") {
|
|
7067
|
+
return String(retObj);
|
|
7068
|
+
} else {
|
|
7069
|
+
return "";
|
|
7070
|
+
}
|
|
7071
|
+
},
|
|
7072
|
+
keys
|
|
7073
|
+
);
|
|
7074
|
+
return content;
|
|
7075
|
+
}
|
|
7076
|
+
_origPage() {
|
|
7077
|
+
return this.#page;
|
|
7078
|
+
}
|
|
7079
|
+
};
|
|
7080
|
+
|
|
7081
|
+
// src/camoufox/api.ts
|
|
7082
|
+
var CamoufoxApiContext = class {
|
|
7083
|
+
#apiRequestContext;
|
|
7084
|
+
#status;
|
|
7085
|
+
constructor(apiRequestContext) {
|
|
7086
|
+
this.#apiRequestContext = apiRequestContext;
|
|
7087
|
+
this.#status = "normal";
|
|
7088
|
+
}
|
|
7089
|
+
async fetch(url, options = {}) {
|
|
7090
|
+
if (this.#status !== "normal") {
|
|
7091
|
+
throw new Error(`ApiContext has already been destroyed`);
|
|
7092
|
+
}
|
|
7093
|
+
const apiResponse = await this.#apiRequestContext.fetch(url, options);
|
|
7094
|
+
const headers = apiResponse.headers();
|
|
7095
|
+
const status = apiResponse.status();
|
|
7096
|
+
const statusText = apiResponse.statusText();
|
|
7097
|
+
const text = await apiResponse.text();
|
|
7098
|
+
const responseUrl = apiResponse.url();
|
|
7099
|
+
return { headers, status, statusText, text, url: responseUrl };
|
|
7100
|
+
}
|
|
7101
|
+
async stateData() {
|
|
7102
|
+
if (this.#status !== "normal") {
|
|
7103
|
+
throw new Error(`ApiContext has already been destroyed`);
|
|
7104
|
+
}
|
|
7105
|
+
const storageState = await this.#apiRequestContext.storageState();
|
|
7106
|
+
const { cookies, origins: localStorage } = storageState;
|
|
7107
|
+
return { cookies, localStorage };
|
|
7108
|
+
}
|
|
7109
|
+
async destroy() {
|
|
7110
|
+
await this.#apiRequestContext.dispose();
|
|
7111
|
+
this.#status = "destroyed";
|
|
7112
|
+
return true;
|
|
7113
|
+
}
|
|
7114
|
+
};
|
|
7115
|
+
|
|
7116
|
+
// src/camoufox/context.ts
|
|
7117
|
+
var CamoufoxBrowserContext = class extends import_node_events12.default {
|
|
7118
|
+
#lsdBrowser;
|
|
7119
|
+
#browserIdx;
|
|
7120
|
+
#browserContextIdx;
|
|
7121
|
+
#browserContext;
|
|
7122
|
+
#browserContextCreationMethod;
|
|
7123
|
+
#apiContext;
|
|
7124
|
+
#createTime;
|
|
7125
|
+
#lastStatusUpdateTime;
|
|
7126
|
+
#status;
|
|
7127
|
+
#incognito;
|
|
7128
|
+
#proxy;
|
|
7129
|
+
#maxPagesPerBrowserContext;
|
|
7130
|
+
#maxPageFreeSeconds;
|
|
7131
|
+
#maxViewportOfNewPage;
|
|
7132
|
+
#lsdPages;
|
|
7133
|
+
#nextPageIdx;
|
|
7134
|
+
#gettingPage;
|
|
7135
|
+
async #initPages() {
|
|
7136
|
+
if (!this.#browserContext) {
|
|
7137
|
+
throw new Error("Invalid browserContext");
|
|
7138
|
+
}
|
|
7139
|
+
const pages = this.#browserContext.pages();
|
|
7140
|
+
const openType = this.#lsdBrowser.browserCreationMethod();
|
|
7141
|
+
const lastStatusUpdateTime = (0, import_utils16.getCurrentUnixTime)();
|
|
7142
|
+
for (const page of pages) {
|
|
7143
|
+
const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, lastStatusUpdateTime, taskId: 0, relatedId: 0, misc: {} };
|
|
7144
|
+
const lsdPage = new CamoufoxPage(this, page, pageInfo);
|
|
7145
|
+
if (this.#maxViewportOfNewPage) {
|
|
7146
|
+
await lsdPage.maximizeViewport();
|
|
7147
|
+
}
|
|
7148
|
+
this.#lsdPages.push(lsdPage);
|
|
7149
|
+
loginfo(`##browser ${lsdPage.id()} ${openType}ed`);
|
|
7150
|
+
}
|
|
7151
|
+
}
|
|
7152
|
+
constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, maxViewportOfNewPage = true) {
|
|
7153
|
+
if (!lsdBrowser || typeof lsdBrowser.browserContexts !== "function") {
|
|
7154
|
+
throw new Error(`Invalid lsdBrowser parameter`);
|
|
7155
|
+
}
|
|
7156
|
+
if (!browserContext || typeof browserContext.setOffline !== "function") {
|
|
7157
|
+
throw new Error(`Invalid playwright browserContext parameter`);
|
|
7158
|
+
}
|
|
7159
|
+
super();
|
|
7160
|
+
this.#lsdBrowser = lsdBrowser;
|
|
7161
|
+
this.#browserIdx = browserIdx;
|
|
7162
|
+
this.#browserContextIdx = browserContextIdx;
|
|
7163
|
+
this.#browserContext = browserContext;
|
|
7164
|
+
this.#browserContextCreationMethod = browserContextCreationMethod;
|
|
7165
|
+
const apiRequestContext = browserContext.request;
|
|
7166
|
+
this.#apiContext = new CamoufoxApiContext(apiRequestContext);
|
|
7167
|
+
const currentTime = (0, import_utils16.getCurrentUnixTime)();
|
|
7168
|
+
this.#createTime = currentTime;
|
|
7169
|
+
this.#lastStatusUpdateTime = currentTime;
|
|
7170
|
+
this.#status = "free";
|
|
7171
|
+
this.#incognito = incognito === false ? false : true;
|
|
7172
|
+
this.#proxy = proxy?.proxyUrl ? proxy : null;
|
|
7173
|
+
this.#maxPagesPerBrowserContext = maxPagesPerBrowserContext;
|
|
7174
|
+
this.#maxPageFreeSeconds = maxPageFreeSeconds;
|
|
7175
|
+
this.#maxViewportOfNewPage = maxViewportOfNewPage;
|
|
7176
|
+
this.#lsdPages = [];
|
|
7177
|
+
this.#nextPageIdx = 1;
|
|
7178
|
+
this.#gettingPage = false;
|
|
7179
|
+
this.#initPages();
|
|
7180
|
+
browserContext.on("page", async (page) => {
|
|
7181
|
+
const pageInfo = page.pageInfo;
|
|
7182
|
+
if (pageInfo) {
|
|
7183
|
+
const { browserIdx: browserIdx2, browserContextIdx: browserContextIdx2, pageIdx } = pageInfo;
|
|
7184
|
+
logwarn(`##browser page-${browserIdx2}-${browserContextIdx2}-${pageIdx} has been already created`);
|
|
7185
|
+
} else {
|
|
7186
|
+
const currentTime2 = (0, import_utils16.getCurrentUnixTime)();
|
|
7187
|
+
const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, lastStatusUpdateTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
|
|
7188
|
+
const lsdPage = new CamoufoxPage(this, page, pageInfo2);
|
|
7189
|
+
if (this.#maxViewportOfNewPage) {
|
|
7190
|
+
await lsdPage.maximizeViewport();
|
|
7191
|
+
}
|
|
7192
|
+
this.#lsdPages.push(lsdPage);
|
|
7193
|
+
loginfo(`##page ${lsdPage.id()} created`);
|
|
7194
|
+
}
|
|
7195
|
+
});
|
|
7196
|
+
browserContext.on("close", (bc) => {
|
|
7197
|
+
if (browserContext !== bc) {
|
|
7198
|
+
logerr(`##browser different browserContext in browserContext.on("close")`);
|
|
7199
|
+
}
|
|
7200
|
+
this.#lsdBrowser.emit("browserContextClose", this);
|
|
7201
|
+
});
|
|
7202
|
+
this.on("pageClose", (lsdPage) => {
|
|
7203
|
+
if (!(lsdPage instanceof CamoufoxPage)) {
|
|
7204
|
+
logerr(`Invalid data in LsdBrowserContext.on("pageClose)`);
|
|
7205
|
+
return;
|
|
7206
|
+
}
|
|
7207
|
+
const idx = this.#lsdPages.findIndex((p) => p === lsdPage);
|
|
7208
|
+
if (idx < 0) {
|
|
7209
|
+
logerr(`Invalid lsdPage in LsdBrowserContext.on("pageClose)`);
|
|
7210
|
+
return;
|
|
7211
|
+
}
|
|
7212
|
+
this.#lsdPages.splice(idx, 1);
|
|
7213
|
+
return;
|
|
7214
|
+
});
|
|
7215
|
+
}
|
|
7216
|
+
apiContext() {
|
|
7217
|
+
return this.#apiContext;
|
|
7218
|
+
}
|
|
7219
|
+
browser() {
|
|
7220
|
+
return this.#lsdBrowser;
|
|
7221
|
+
}
|
|
7222
|
+
async close() {
|
|
7223
|
+
if (this.#browserContext) {
|
|
7224
|
+
this.#status = "closed";
|
|
7225
|
+
this.#lastStatusUpdateTime = (0, import_utils16.getCurrentUnixTime)();
|
|
7226
|
+
loginfo(`browserContext ${this.id()} closed at ${this.#lastStatusUpdateTime}`);
|
|
7227
|
+
await this.#browserContext.close();
|
|
7228
|
+
}
|
|
7229
|
+
return true;
|
|
7230
|
+
}
|
|
7231
|
+
async #tryToGetGettingLock() {
|
|
7232
|
+
let i = 0;
|
|
7233
|
+
for (i = 0; i < 50; i++) {
|
|
7234
|
+
if (!this.#gettingPage) {
|
|
7235
|
+
this.#gettingPage = true;
|
|
7236
|
+
return true;
|
|
7237
|
+
} else {
|
|
7238
|
+
await (0, import_utils16.sleep)(200);
|
|
7239
|
+
}
|
|
7240
|
+
}
|
|
7241
|
+
logwarn(`Cannot get the gettingLock.`);
|
|
7242
|
+
return false;
|
|
7243
|
+
}
|
|
7244
|
+
#freeGettingLock() {
|
|
7245
|
+
if (!this.#gettingPage) {
|
|
7246
|
+
logwarn(`Getting lock is already free now.`);
|
|
7247
|
+
}
|
|
7248
|
+
this.#gettingPage = false;
|
|
7249
|
+
}
|
|
7250
|
+
async closeFreePages(maxPageFreeSeconds = 0) {
|
|
7251
|
+
if (maxPageFreeSeconds <= 0) {
|
|
7252
|
+
maxPageFreeSeconds = this.#maxPageFreeSeconds;
|
|
7253
|
+
}
|
|
7254
|
+
if (maxPageFreeSeconds <= 0) {
|
|
7255
|
+
logwarn(`Please set valid maxPageFreeSeconds to close free pages`);
|
|
7256
|
+
return false;
|
|
7257
|
+
}
|
|
7258
|
+
const gotLock = await this.#tryToGetGettingLock();
|
|
7259
|
+
if (!gotLock) {
|
|
7260
|
+
return false;
|
|
7261
|
+
}
|
|
7262
|
+
try {
|
|
7263
|
+
const maxUpdateTime = (0, import_utils16.getCurrentUnixTime)() - this.#maxPageFreeSeconds;
|
|
7264
|
+
let freePages = this.#lsdPages.filter((p) => p.isFree() && p.pageInfo().lastStatusUpdateTime < maxUpdateTime);
|
|
7265
|
+
if (freePages.length === this.#lsdPages.length) {
|
|
7266
|
+
freePages = freePages.slice(1);
|
|
7267
|
+
}
|
|
7268
|
+
for (const lsdPage of freePages) {
|
|
7269
|
+
await lsdPage.close();
|
|
7270
|
+
}
|
|
7271
|
+
this.#freeGettingLock();
|
|
7272
|
+
return true;
|
|
7273
|
+
} catch (err) {
|
|
7274
|
+
logerr(err);
|
|
7275
|
+
this.#freeGettingLock();
|
|
7276
|
+
return false;
|
|
7277
|
+
}
|
|
7278
|
+
}
|
|
7279
|
+
creationMethod() {
|
|
7280
|
+
return this.#browserContextCreationMethod;
|
|
7281
|
+
}
|
|
7282
|
+
doesMeetBrowserContextRequirements(browserContextRequirements) {
|
|
7283
|
+
if (!this.#lsdBrowser.doesMeetBrowserContextRequirements(browserContextRequirements)) {
|
|
7284
|
+
return false;
|
|
7285
|
+
}
|
|
7286
|
+
const { browserIncognitos: incognitos } = browserContextRequirements;
|
|
7287
|
+
return incognitos.length === 0 || incognitos.includes(this.#incognito);
|
|
7288
|
+
}
|
|
7289
|
+
async getPage(always = false) {
|
|
7290
|
+
if (!this.#browserContext) {
|
|
7291
|
+
throw new Error("Invalid browserContext");
|
|
7292
|
+
}
|
|
7293
|
+
const gotLock = await this.#tryToGetGettingLock();
|
|
7294
|
+
if (!gotLock) {
|
|
7295
|
+
return null;
|
|
7296
|
+
}
|
|
7297
|
+
try {
|
|
7298
|
+
let lsdPage = this.#lsdPages.find((p) => p.isFree());
|
|
7299
|
+
if (lsdPage) {
|
|
7300
|
+
lsdPage.use();
|
|
7301
|
+
this.#freeGettingLock();
|
|
7302
|
+
return lsdPage;
|
|
7303
|
+
}
|
|
7304
|
+
if (this.#lsdPages.length >= this.#maxPagesPerBrowserContext && !always) {
|
|
7305
|
+
this.#freeGettingLock();
|
|
7306
|
+
return null;
|
|
7307
|
+
}
|
|
7308
|
+
const page = await this.#browserContext.newPage();
|
|
7309
|
+
await (0, import_utils16.sleep)(2e3);
|
|
7310
|
+
const pageInfo = page.pageInfo;
|
|
7311
|
+
if (!pageInfo) {
|
|
7312
|
+
throw new Error(`Logic error in getPage`);
|
|
7313
|
+
} else {
|
|
7314
|
+
pageInfo.openType = "newpage";
|
|
7315
|
+
}
|
|
7316
|
+
lsdPage = this.#lsdPages.find((p) => p.isFree());
|
|
7317
|
+
if (lsdPage) {
|
|
7318
|
+
lsdPage.use();
|
|
7319
|
+
this.#freeGettingLock();
|
|
7320
|
+
return lsdPage;
|
|
7321
|
+
} else {
|
|
7322
|
+
this.#freeGettingLock();
|
|
7323
|
+
return null;
|
|
7324
|
+
}
|
|
7325
|
+
} catch (err) {
|
|
7326
|
+
logerr(err);
|
|
7327
|
+
this.#freeGettingLock();
|
|
7328
|
+
return null;
|
|
7329
|
+
}
|
|
7330
|
+
}
|
|
7331
|
+
free(clearStateData = false) {
|
|
7332
|
+
if (this.#status === "busy") {
|
|
7333
|
+
this.#status = "free";
|
|
7334
|
+
this.#lastStatusUpdateTime = (0, import_utils16.getCurrentUnixTime)();
|
|
7335
|
+
if (clearStateData) {
|
|
7336
|
+
}
|
|
7337
|
+
return true;
|
|
7338
|
+
} else {
|
|
7339
|
+
return false;
|
|
7340
|
+
}
|
|
7341
|
+
}
|
|
7342
|
+
hasFreePage(pageNum = 1) {
|
|
7343
|
+
if (this.#maxPagesPerBrowserContext - this.#lsdPages.length > pageNum) {
|
|
7344
|
+
return true;
|
|
7345
|
+
} else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isFree()).length > pageNum) {
|
|
7346
|
+
return true;
|
|
7347
|
+
} else {
|
|
7348
|
+
return false;
|
|
7349
|
+
}
|
|
7350
|
+
}
|
|
7351
|
+
id() {
|
|
7352
|
+
return `browserContext-${this.#browserIdx}-${this.#browserContextIdx}`;
|
|
7353
|
+
}
|
|
7354
|
+
isFree() {
|
|
7355
|
+
return this.#status === "free";
|
|
7356
|
+
}
|
|
7357
|
+
isIncognito() {
|
|
7358
|
+
return this.#incognito;
|
|
7359
|
+
}
|
|
7360
|
+
page(pageIdx) {
|
|
7361
|
+
const lsdPage = this.#lsdPages.find((p) => p.pageInfo().pageIdx === pageIdx);
|
|
7362
|
+
return lsdPage ? lsdPage : null;
|
|
7363
|
+
}
|
|
7364
|
+
pages() {
|
|
7365
|
+
return this.#lsdPages;
|
|
7366
|
+
}
|
|
7367
|
+
proxy() {
|
|
7368
|
+
return this.#proxy;
|
|
7369
|
+
}
|
|
7370
|
+
async setStateData(stateData) {
|
|
7371
|
+
if (!this.#browserContext) {
|
|
7372
|
+
throw new Error("No valid browserContext");
|
|
7373
|
+
}
|
|
7374
|
+
try {
|
|
7375
|
+
const { cookies, localStorage: localStorageOrigins } = stateData;
|
|
7376
|
+
const page = await this.getPage();
|
|
7377
|
+
if (!page) {
|
|
7378
|
+
return false;
|
|
7379
|
+
}
|
|
7380
|
+
const origPage = page._origPage();
|
|
7381
|
+
if (cookies.length > 0) {
|
|
7382
|
+
await this.#browserContext.addCookies(cookies);
|
|
7383
|
+
}
|
|
7384
|
+
if (localStorageOrigins.length > 0) {
|
|
7385
|
+
await origPage.route("**/*", async (route) => {
|
|
7386
|
+
const request = route.request();
|
|
7387
|
+
await route.fulfill({
|
|
7388
|
+
status: 200,
|
|
7389
|
+
// contentType: "text/html; charset=utf-8", // "text/plain",
|
|
7390
|
+
body: `<html><body><h1>${request.url()}</h1></body></html>`
|
|
7391
|
+
});
|
|
7392
|
+
});
|
|
7393
|
+
for (const localStorageOrigin of localStorageOrigins) {
|
|
7394
|
+
const { origin, localStorage } = localStorageOrigin;
|
|
7395
|
+
await origPage.goto(origin);
|
|
7396
|
+
await origPage.evaluate((localStorageItems) => {
|
|
7397
|
+
for (const item of localStorageItems) {
|
|
7398
|
+
window.localStorage.setItem(item.name, item.value);
|
|
7399
|
+
}
|
|
7400
|
+
}, localStorage);
|
|
7401
|
+
}
|
|
7402
|
+
}
|
|
7403
|
+
await (0, import_utils16.sleep)(2e3);
|
|
7404
|
+
await origPage.unrouteAll();
|
|
7405
|
+
await page.free();
|
|
7406
|
+
return true;
|
|
7407
|
+
} catch (err) {
|
|
7408
|
+
logerr(err);
|
|
7409
|
+
return false;
|
|
7410
|
+
}
|
|
7411
|
+
}
|
|
7412
|
+
status() {
|
|
7413
|
+
return this.#status;
|
|
7414
|
+
}
|
|
7415
|
+
use() {
|
|
7416
|
+
if (this.#status === "free") {
|
|
7417
|
+
this.#status = "busy";
|
|
7418
|
+
this.#lastStatusUpdateTime = (0, import_utils16.getCurrentUnixTime)();
|
|
7419
|
+
return true;
|
|
7420
|
+
} else {
|
|
7421
|
+
return false;
|
|
7422
|
+
}
|
|
7423
|
+
}
|
|
7424
|
+
_origBrowserContext() {
|
|
7425
|
+
return this.#browserContext;
|
|
7426
|
+
}
|
|
7427
|
+
};
|
|
7428
|
+
|
|
7429
|
+
// src/camoufox/browser.ts
|
|
7430
|
+
var CamoufoxBrowser = class _CamoufoxBrowser extends import_node_events13.default {
|
|
7431
|
+
static #supportedBrowserTypes = ["firefox"];
|
|
7432
|
+
static doesSupport(browserType) {
|
|
7433
|
+
return _CamoufoxBrowser.#supportedBrowserTypes.includes(browserType);
|
|
7434
|
+
}
|
|
7435
|
+
#browser;
|
|
7436
|
+
#browserIdx;
|
|
7437
|
+
#pid;
|
|
7438
|
+
#createTime;
|
|
7439
|
+
#lsdBrowserContexts;
|
|
7440
|
+
#browserControllerType;
|
|
7441
|
+
#browserType;
|
|
7442
|
+
#browserCreationMethod;
|
|
7443
|
+
#headless;
|
|
7444
|
+
#options;
|
|
7445
|
+
#proxy;
|
|
7446
|
+
/**
|
|
7447
|
+
* launch: actual path of executable app
|
|
7448
|
+
* connect: ""
|
|
7449
|
+
*/
|
|
7450
|
+
#executablePath;
|
|
7451
|
+
#nextBrowserContextIdx;
|
|
7452
|
+
#closeFreePagesIntervalId;
|
|
7453
|
+
#maxBrowserContextsPerBrowser() {
|
|
7454
|
+
return this.#options.maxBrowserContextsPerBrowser ? this.#options.maxBrowserContextsPerBrowser : 10;
|
|
7455
|
+
}
|
|
7456
|
+
#maxPagesPerBrowserContext() {
|
|
7457
|
+
return this.#options.maxPagesPerBrowserContext ? this.#options.maxPagesPerBrowserContext : 20;
|
|
7458
|
+
}
|
|
7459
|
+
#maxPageFreeSeconds() {
|
|
7460
|
+
return this.#options.maxPageFreeSeconds ? this.#options.maxPageFreeSeconds : 900;
|
|
7461
|
+
}
|
|
7462
|
+
// constructor: called only by LsdBrowserController.launch/connect
|
|
7463
|
+
constructor(browser, browserType, browserCreateMethod, options, browserIdx = 0, pid = 0) {
|
|
7464
|
+
if (!browser || typeof browser.contexts !== "function") {
|
|
7465
|
+
throw new Error(`Invalid playwright browser parameter`);
|
|
7466
|
+
}
|
|
7467
|
+
super();
|
|
7468
|
+
const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
|
|
7469
|
+
this.#browser = browser;
|
|
7470
|
+
this.#browserIdx = browserIdx;
|
|
7471
|
+
this.#pid = pid;
|
|
7472
|
+
this.#createTime = (0, import_utils17.getCurrentUnixTime)();
|
|
7473
|
+
this.#lsdBrowserContexts = [];
|
|
7474
|
+
this.#browserControllerType = "playwright";
|
|
7475
|
+
this.#browserType = browserType;
|
|
7476
|
+
if (!_CamoufoxBrowser.#supportedBrowserTypes.includes(browserType)) {
|
|
7477
|
+
throw new Error(`Browser controller ${this.#browserControllerType} doesnot support browserType ${browserType}`);
|
|
7478
|
+
}
|
|
7479
|
+
this.#browserCreationMethod = browserCreateMethod;
|
|
7480
|
+
this.#headless = headless;
|
|
7481
|
+
this.#proxy = options?.proxy ? Object.assign({}, options.proxy) : null;
|
|
7482
|
+
this.#options = Object.assign({}, options, { closeFreePagesIntervalSeconds, maxPageFreeSeconds, maxViewportOfNewPage, headless, executablePath, proxy: this.#proxy });
|
|
7483
|
+
this.#executablePath = executablePath;
|
|
7484
|
+
this.#nextBrowserContextIdx = 1;
|
|
7485
|
+
this.#closeFreePagesIntervalId = null;
|
|
7486
|
+
loginfo(`##browser ${this.id()} ${this.#browserCreationMethod}ed by ${this.#browserControllerType}`);
|
|
7487
|
+
const browserContexts = browser.contexts();
|
|
7488
|
+
if (browserContexts.length > 0) {
|
|
7489
|
+
logwarn(`There are ${browserContexts.length} new browserContexts when playwright launches new browser`);
|
|
7490
|
+
}
|
|
7491
|
+
const incognito = typeof options?.incognito === "boolean" ? options.incognito : true;
|
|
7492
|
+
for (const browserContext of browserContexts) {
|
|
7493
|
+
const lsdBrowserContext = new CamoufoxBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), maxViewportOfNewPage);
|
|
7494
|
+
this.#lsdBrowserContexts.push(lsdBrowserContext);
|
|
7495
|
+
loginfo(`##browserContext ${lsdBrowserContext.id()} ${this.#browserCreationMethod}ed`);
|
|
7496
|
+
}
|
|
7497
|
+
browser.on("disconnected", () => {
|
|
7498
|
+
loginfo(`##browser ${this.id()} disconnected`);
|
|
7499
|
+
if (this.#lsdBrowserContexts.length > 0) {
|
|
7500
|
+
logerr(`${this.id()} has browserContexts when disconnected`);
|
|
7501
|
+
}
|
|
7502
|
+
});
|
|
7503
|
+
this.on("browserContextClose", (lsdBrowserContext) => {
|
|
7504
|
+
if (!(lsdBrowserContext instanceof CamoufoxBrowserContext)) {
|
|
7505
|
+
logerr(`Invalid data in LsdBrowser.on("browserContextClose)`);
|
|
7506
|
+
return;
|
|
7507
|
+
}
|
|
7508
|
+
const idx = this.#lsdBrowserContexts.findIndex((bc) => bc === lsdBrowserContext);
|
|
7509
|
+
if (idx < 0) {
|
|
7510
|
+
logerr(`Invalid lsdBrowserContext in LsdBrowser.on("browserContextClose)`);
|
|
7511
|
+
return;
|
|
7512
|
+
}
|
|
7513
|
+
loginfo(`##browserContext ${lsdBrowserContext.id()} closed
|
|
7514
|
+
`);
|
|
7515
|
+
this.#lsdBrowserContexts.splice(idx, 1);
|
|
7516
|
+
if (this.#lsdBrowserContexts.length === 0) {
|
|
7517
|
+
loginfo(`##browser ${this.id()} has no browserContexts now`);
|
|
7518
|
+
}
|
|
7519
|
+
return;
|
|
7520
|
+
});
|
|
7521
|
+
if (closeFreePagesIntervalSeconds > 0 && maxPageFreeSeconds > 0) {
|
|
7522
|
+
this.#closeFreePagesIntervalId = setInterval(async () => {
|
|
7523
|
+
await this.#closeFreePagesHandler();
|
|
7524
|
+
}, closeFreePagesIntervalSeconds * 1e3);
|
|
7525
|
+
}
|
|
7526
|
+
}
|
|
7527
|
+
async #closeFreePagesHandler() {
|
|
7528
|
+
for (const lsdBrowserContext of this.#lsdBrowserContexts) {
|
|
7529
|
+
await lsdBrowserContext.closeFreePages();
|
|
7530
|
+
}
|
|
7531
|
+
}
|
|
7532
|
+
async newBrowserContext(options) {
|
|
7533
|
+
if (this.#lsdBrowserContexts.length >= this.#maxBrowserContextsPerBrowser()) {
|
|
7534
|
+
logwarn(`##browser ${this.id()} can not create more new browserContext`);
|
|
7535
|
+
return null;
|
|
7536
|
+
}
|
|
7537
|
+
const browserContextOptions = {};
|
|
7538
|
+
if (this.#options.maxWindowSize) {
|
|
7539
|
+
browserContextOptions.viewport = null;
|
|
7540
|
+
}
|
|
7541
|
+
const proxy = options?.proxy ? Object.assign({}, options.proxy) : this.#proxy;
|
|
7542
|
+
if (proxy) {
|
|
7543
|
+
const { proxyUrl: server, username, password } = proxy;
|
|
7544
|
+
browserContextOptions.proxy = { server, username, password };
|
|
7545
|
+
}
|
|
7546
|
+
if (options?.userAgent) {
|
|
7547
|
+
browserContextOptions.userAgent = options.userAgent;
|
|
7548
|
+
}
|
|
7549
|
+
const browserContext = await this.#browser.newContext(browserContextOptions);
|
|
7550
|
+
const { maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
|
|
7551
|
+
const lsdBrowserContext = new CamoufoxBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), maxViewportOfNewPage);
|
|
7552
|
+
this.#lsdBrowserContexts.push(lsdBrowserContext);
|
|
7553
|
+
loginfo(`##browser ${lsdBrowserContext.id()} created`);
|
|
7554
|
+
return lsdBrowserContext;
|
|
7555
|
+
}
|
|
7556
|
+
async close() {
|
|
7557
|
+
if (this.#closeFreePagesIntervalId) {
|
|
7558
|
+
clearInterval(this.#closeFreePagesIntervalId);
|
|
7559
|
+
}
|
|
7560
|
+
for (const lsdBrowserContext of this.#lsdBrowserContexts) {
|
|
7561
|
+
await lsdBrowserContext.close();
|
|
7562
|
+
}
|
|
7563
|
+
await this.#browser.close();
|
|
7564
|
+
return true;
|
|
7565
|
+
}
|
|
7566
|
+
browserContexts() {
|
|
7567
|
+
return this.#lsdBrowserContexts;
|
|
7568
|
+
}
|
|
7569
|
+
browserControllerType() {
|
|
7570
|
+
return this.#browserControllerType;
|
|
7571
|
+
}
|
|
7572
|
+
browserCreationMethod() {
|
|
7573
|
+
return this.#browserCreationMethod;
|
|
7574
|
+
}
|
|
7575
|
+
browserType() {
|
|
7576
|
+
return this.#browserType;
|
|
7577
|
+
}
|
|
7578
|
+
createTime() {
|
|
7579
|
+
return this.#createTime;
|
|
7580
|
+
}
|
|
7581
|
+
doesMeetBrowserContextRequirements(browserContextRequirements) {
|
|
7582
|
+
const { browserControllerTypes, browserTypes, browserHeadlesses } = browserContextRequirements;
|
|
7583
|
+
return (browserControllerTypes.length === 0 || browserControllerTypes.includes(this.#browserControllerType)) && (browserTypes.length === 0 || browserTypes.includes(this.#browserType)) && (browserHeadlesses.length === 0 || browserHeadlesses.includes(this.#headless));
|
|
7584
|
+
}
|
|
7585
|
+
executablePath() {
|
|
7586
|
+
return this.#executablePath;
|
|
7587
|
+
}
|
|
7588
|
+
id() {
|
|
7589
|
+
return `browser-${this.#browserType}-${this.#browserIdx}`;
|
|
7590
|
+
}
|
|
7591
|
+
isConnected() {
|
|
7592
|
+
return this.#browser.isConnected();
|
|
7593
|
+
}
|
|
7594
|
+
isHeadless() {
|
|
7595
|
+
return this.#headless;
|
|
7596
|
+
}
|
|
7597
|
+
options() {
|
|
7598
|
+
return this.#options;
|
|
7599
|
+
}
|
|
7600
|
+
pid() {
|
|
7601
|
+
return this.#pid;
|
|
7602
|
+
}
|
|
7603
|
+
async pidUsage() {
|
|
7604
|
+
if (this.#pid > 0) {
|
|
7605
|
+
const usage = await (0, import_utils17.getPerformanceOfPidTree)(this.#pid, "MB");
|
|
7606
|
+
return usage;
|
|
7607
|
+
} else {
|
|
7608
|
+
return { cpu: 0, memory: 0 };
|
|
7609
|
+
}
|
|
7610
|
+
}
|
|
7611
|
+
proxy() {
|
|
7612
|
+
return this.#proxy;
|
|
7613
|
+
}
|
|
7614
|
+
async version() {
|
|
7615
|
+
const version = await this.#browser.version();
|
|
7616
|
+
return version;
|
|
7617
|
+
}
|
|
7618
|
+
_origBrowser() {
|
|
7619
|
+
return this.#browser;
|
|
7620
|
+
}
|
|
7621
|
+
};
|
|
7622
|
+
|
|
7623
|
+
// src/controller/controller.ts
|
|
7624
|
+
var LsdBrowserController = class _LsdBrowserController {
|
|
7625
|
+
static #forbidConstructor = false;
|
|
7626
|
+
#puppeteer;
|
|
7627
|
+
#playwrightBrowserTypes;
|
|
7628
|
+
#patchrightBrowserTypes;
|
|
7629
|
+
#nextBrowserIdx;
|
|
7630
|
+
/**
|
|
7631
|
+
* Possible values are 'aix', 'darwin', 'freebsd','linux', 'openbsd', 'sunos', and 'win32'.
|
|
7632
|
+
*/
|
|
7633
|
+
#osPlatform;
|
|
7634
|
+
constructor() {
|
|
7635
|
+
if (_LsdBrowserController.#forbidConstructor) {
|
|
7636
|
+
throw new Error("Only one LsdBrowserController instance can be created!");
|
|
7637
|
+
}
|
|
7638
|
+
this.#puppeteer = import_puppeteer.default;
|
|
7639
|
+
this.#playwrightBrowserTypes = {
|
|
7640
|
+
chromium: import_playwright.default.chromium,
|
|
7641
|
+
firefox: import_playwright.default.firefox,
|
|
7642
|
+
webkit: import_playwright.default.webkit
|
|
7643
|
+
};
|
|
7644
|
+
this.#patchrightBrowserTypes = {
|
|
7645
|
+
chromium: import_patchright.default.chromium,
|
|
7646
|
+
firefox: import_patchright.default.firefox,
|
|
7647
|
+
webkit: import_patchright.default.webkit
|
|
7648
|
+
};
|
|
7649
|
+
this.#osPlatform = import_os.default.platform();
|
|
7650
|
+
this.#nextBrowserIdx = 1;
|
|
7651
|
+
_LsdBrowserController.#forbidConstructor = true;
|
|
7652
|
+
}
|
|
7653
|
+
#playwrightBrowserType(browserType, connectFlag = false) {
|
|
7654
|
+
if (browserType === "chromium") {
|
|
7655
|
+
return this.#playwrightBrowserTypes.chromium;
|
|
7656
|
+
} else if (connectFlag) {
|
|
7657
|
+
throw new Error(`playwright only can connect to chromium browser, not support ${browserType} browser`);
|
|
7658
|
+
} else if (browserType === "firefox") {
|
|
7659
|
+
return this.#playwrightBrowserTypes.firefox;
|
|
7660
|
+
} else if (browserType === "webkit") {
|
|
7661
|
+
return this.#playwrightBrowserTypes.webkit;
|
|
7662
|
+
} else {
|
|
7663
|
+
throw new Error(`Invalid playwright browserType ${browserType}`);
|
|
7664
|
+
}
|
|
7665
|
+
}
|
|
7666
|
+
#patchrightBrowserType(browserType, connectFlag = false) {
|
|
7667
|
+
if (browserType === "chromium") {
|
|
7668
|
+
return this.#patchrightBrowserTypes.chromium;
|
|
7669
|
+
} else if (connectFlag) {
|
|
7670
|
+
throw new Error(`patchright only can connect to chromium browser, not support ${browserType} browser`);
|
|
7671
|
+
} else if (browserType === "firefox") {
|
|
7672
|
+
return this.#patchrightBrowserTypes.firefox;
|
|
7673
|
+
} else if (browserType === "webkit") {
|
|
7674
|
+
return this.#patchrightBrowserTypes.webkit;
|
|
7675
|
+
} else {
|
|
7676
|
+
throw new Error(`Invalid patchright browserType ${browserType}`);
|
|
7677
|
+
}
|
|
7678
|
+
}
|
|
7679
|
+
#puppeteerProduct(browserType) {
|
|
7680
|
+
if (browserType === "chromium") {
|
|
7681
|
+
return "chrome";
|
|
7682
|
+
} else {
|
|
7683
|
+
throw new Error(`Invalid puppeteer product ${browserType}`);
|
|
7684
|
+
}
|
|
7685
|
+
}
|
|
7686
|
+
setBrowserPlugin(browserControllerType, browserType, plugin) {
|
|
7687
|
+
if (browserControllerType === "puppeteer") {
|
|
7688
|
+
if (!PuppeteerBrowser.doesSupport(browserType)) {
|
|
7689
|
+
throw new Error(`BrowserControllerType ${browserControllerType} doesnot support browserType ${browserType}`);
|
|
7690
|
+
}
|
|
7691
|
+
this.#puppeteer = plugin;
|
|
7692
|
+
} else if (browserControllerType === "playwright") {
|
|
7693
|
+
if (!PlaywrightBrowser.doesSupport(browserType)) {
|
|
7694
|
+
throw new Error(`BrowserControllerType ${browserControllerType} doesnot support browserType ${browserType}`);
|
|
7695
|
+
}
|
|
7696
|
+
switch (browserType) {
|
|
7697
|
+
case "chromium":
|
|
7698
|
+
case "firefox":
|
|
7699
|
+
case "webkit":
|
|
7700
|
+
this.#playwrightBrowserTypes[browserType] = plugin;
|
|
7701
|
+
break;
|
|
7702
|
+
default:
|
|
7703
|
+
(0, import_utils18.unreachable)(browserType);
|
|
7704
|
+
}
|
|
7705
|
+
} else if (browserControllerType === "patchright") {
|
|
7706
|
+
if (!PatchrightBrowser.doesSupport(browserType)) {
|
|
7707
|
+
throw new Error(`BrowserControllerType ${browserControllerType} doesnot support browserType ${browserType}`);
|
|
7708
|
+
}
|
|
7709
|
+
switch (browserType) {
|
|
7710
|
+
case "chromium":
|
|
7711
|
+
case "firefox":
|
|
7712
|
+
case "webkit":
|
|
7713
|
+
this.#patchrightBrowserTypes[browserType] = plugin;
|
|
7714
|
+
break;
|
|
7715
|
+
default:
|
|
7716
|
+
(0, import_utils18.unreachable)(browserType);
|
|
7717
|
+
}
|
|
7718
|
+
} else if (browserControllerType === "camoufox") {
|
|
7719
|
+
if (!CamoufoxBrowser.doesSupport(browserType)) {
|
|
7720
|
+
throw new Error(`BrowserControllerType ${browserControllerType} doesnot support browserType ${browserType}`);
|
|
7721
|
+
}
|
|
7722
|
+
} else {
|
|
7723
|
+
(0, import_utils18.unreachable)(browserControllerType);
|
|
7724
|
+
}
|
|
7725
|
+
return true;
|
|
7726
|
+
}
|
|
7727
|
+
async launch(browserControllerType, browserType, options) {
|
|
7728
|
+
let {
|
|
7729
|
+
closeFreePagesIntervalSeconds = 300,
|
|
7730
|
+
maxBrowserContextsPerBrowser = 10,
|
|
7731
|
+
maxPagesPerBrowserContext = 20,
|
|
7732
|
+
maxPageFreeSeconds = 900,
|
|
7733
|
+
maxViewportOfNewPage = true,
|
|
7734
|
+
proxy = null,
|
|
7735
|
+
timeout = 3e4,
|
|
7736
|
+
args = [],
|
|
7737
|
+
executablePath = "",
|
|
7738
|
+
maxWindowSize = true,
|
|
7739
|
+
headless = true,
|
|
7740
|
+
minBrowserContexts = 1,
|
|
7741
|
+
// incognito
|
|
7742
|
+
proxyPerBrowserContext = false,
|
|
7743
|
+
userDataDir = "",
|
|
7744
|
+
userAgent = ""
|
|
7745
|
+
} = options ? options : {};
|
|
7746
|
+
let browserPid = 0;
|
|
7747
|
+
const incognito = typeof options?.incognito === "boolean" ? options.incognito : browserControllerType === "puppeteer" ? false : true;
|
|
7748
|
+
const actOptions = { closeFreePagesIntervalSeconds, maxBrowserContextsPerBrowser, maxPagesPerBrowserContext, maxPageFreeSeconds, maxViewportOfNewPage, proxy, timeout, args, executablePath, maxWindowSize, headless, minBrowserContexts, incognito, proxyPerBrowserContext, userDataDir, userAgent };
|
|
7749
|
+
let idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--incoginto"));
|
|
7750
|
+
if (idx >= 0) {
|
|
7751
|
+
logwarn(`Please use options.incognito instead when launching new browser.`);
|
|
7752
|
+
args.splice(idx, 1);
|
|
7753
|
+
}
|
|
7754
|
+
idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--proxy-server"));
|
|
7755
|
+
if (idx >= 0) {
|
|
7756
|
+
logwarn(`Please use options.proxy instead when launching new browser.`);
|
|
7757
|
+
args.splice(idx, 1);
|
|
7758
|
+
}
|
|
7759
|
+
idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--user-data-dir"));
|
|
7760
|
+
if (idx >= 0) {
|
|
7761
|
+
logwarn(`Please use options.userDataDir instead when launching new browser.`);
|
|
7762
|
+
args.splice(idx, 1);
|
|
7763
|
+
}
|
|
7764
|
+
idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--start-maximized"));
|
|
7765
|
+
if (idx >= 0) {
|
|
7766
|
+
logwarn(`Please use options.maxWindowSize instead when launching new browser.`);
|
|
7767
|
+
args.splice(idx, 1);
|
|
7768
|
+
}
|
|
7769
|
+
let lsdBrowser;
|
|
7770
|
+
if (browserControllerType === "playwright") {
|
|
7771
|
+
const launchOptions = { headless, timeout };
|
|
5958
7772
|
if (executablePath) {
|
|
5959
7773
|
launchOptions.executablePath = executablePath;
|
|
5960
7774
|
}
|
|
@@ -6072,8 +7886,39 @@ var LsdBrowserController = class _LsdBrowserController {
|
|
|
6072
7886
|
browserPid = browserProcess.pid;
|
|
6073
7887
|
}
|
|
6074
7888
|
lsdBrowser = new PuppeteerBrowser(browser, browserType, "launch", actOptions, this.#nextBrowserIdx++, browserPid);
|
|
7889
|
+
} else if (browserControllerType === "camoufox") {
|
|
7890
|
+
const launchOptions = { headless, timeout };
|
|
7891
|
+
if (executablePath) {
|
|
7892
|
+
launchOptions.executable_path = executablePath;
|
|
7893
|
+
}
|
|
7894
|
+
if (maxWindowSize) {
|
|
7895
|
+
args.push("--start-maximized");
|
|
7896
|
+
}
|
|
7897
|
+
if (proxy?.proxyUrl && proxy.proxyUrl !== "local") {
|
|
7898
|
+
const { proxyUrl: server, username, password } = proxy;
|
|
7899
|
+
launchOptions.proxy = { server, username, password };
|
|
7900
|
+
}
|
|
7901
|
+
if (userDataDir) {
|
|
7902
|
+
launchOptions.user_data_dir = userDataDir;
|
|
7903
|
+
}
|
|
7904
|
+
if (args.length > 0) {
|
|
7905
|
+
launchOptions.args = args;
|
|
7906
|
+
}
|
|
7907
|
+
if (options.launchMethod === "launchServer") {
|
|
7908
|
+
const browserServer = await (0, import_camoufox_js.launchServer)(launchOptions);
|
|
7909
|
+
const process = browserServer.process();
|
|
7910
|
+
if (process?.pid) {
|
|
7911
|
+
browserPid = process.pid;
|
|
7912
|
+
}
|
|
7913
|
+
const wsEndpoint = browserServer.wsEndpoint();
|
|
7914
|
+
const browser = await import_playwright.default.firefox.connect(wsEndpoint);
|
|
7915
|
+
lsdBrowser = new CamoufoxBrowser(browser, browserType, "launch", actOptions, this.#nextBrowserIdx++, browserPid);
|
|
7916
|
+
} else {
|
|
7917
|
+
const browser = await (0, import_camoufox_js.Camoufox)(launchOptions);
|
|
7918
|
+
lsdBrowser = new CamoufoxBrowser(browser, browserType, "launch", actOptions, this.#nextBrowserIdx++, browserPid);
|
|
7919
|
+
}
|
|
6075
7920
|
} else {
|
|
6076
|
-
|
|
7921
|
+
(0, import_utils18.unreachable)(browserControllerType);
|
|
6077
7922
|
}
|
|
6078
7923
|
for (let i = lsdBrowser.browserContexts().length; i < minBrowserContexts; i++) {
|
|
6079
7924
|
await lsdBrowser.newBrowserContext();
|
|
@@ -6100,7 +7945,7 @@ var LsdBrowserController = class _LsdBrowserController {
|
|
|
6100
7945
|
}
|
|
6101
7946
|
const u = new URL(browserUrl);
|
|
6102
7947
|
const port = u.port ? parseInt(u.port) : 80;
|
|
6103
|
-
const pids = await (0,
|
|
7948
|
+
const pids = await (0, import_utils18.getPidsListeningOnPort)(port);
|
|
6104
7949
|
let browserPid = 0;
|
|
6105
7950
|
if (pids.length !== 1) {
|
|
6106
7951
|
logerr(`##browser pids.length ${pids.length} is not 1 when trying to connect to browserUrl ${browserUrl}`);
|