├── .github
└── ISSUE_TEMPLATE
│ └── general_issue.yaml
├── .gitignore
├── Dockerfile
├── LICENSE.md
├── README.md
├── data
├── capsolver.png
└── sdo.gif
├── lib
├── cjs
│ ├── index.js
│ └── module
│ │ ├── pageController.js
│ │ └── turnstile.js
└── esm
│ ├── index.mjs
│ └── module
│ ├── pageController.mjs
│ └── turnstile.mjs
├── package-lock.json
├── package.json
├── test
├── cjs
│ └── test.js
└── esm
│ ├── package.json
│ └── test.js
└── typings.d.ts
/.github/ISSUE_TEMPLATE/general_issue.yaml:
--------------------------------------------------------------------------------
1 | name: Report Issue
2 | description: Please use this to report any issue
3 | labels: [triage]
4 | assignees:
5 | - zfcsoftware
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | Please take care to fill in all fields. Recreating the issue will speed up its resolution. Thank you for contributing to the betterment of the library by reporting issues.
11 | - type: textarea
12 | id: issue-detail
13 | attributes:
14 | label: Description
15 | description: Please describe the problem you are experiencing. You only need to provide information about the problem in this field.
16 | validations:
17 | required: true
18 | - type: textarea
19 | id: issue-recreate
20 | attributes:
21 | label: Full steps to reproduce the issue
22 | description: Please provide a full working code to reproduce the issue. Make sure that the code you provide is directly executable. This step is very important to resolve the issue.
23 | validations:
24 | required: true
25 | - type: dropdown
26 | id: issue-type
27 | attributes:
28 | label: Issue Type
29 | description: What type of issue would you like to report?
30 | multiple: true
31 | options:
32 | - Bug
33 | - Build/Install
34 | - Performance
35 | - Support
36 | - Feature Request
37 | - Documentation Request
38 | - Others
39 | - type: dropdown
40 | id: Operating-System
41 | attributes:
42 | label: Operating System
43 | description: What OS are you seeing the issue in? If you don't see your OS listed, please provide more details in the "Description" section above.
44 | multiple: true
45 | options:
46 | - Windows 10
47 | - Linux
48 | - Mac OS
49 | - Other
50 | - type: dropdown
51 | id: use-type
52 | attributes:
53 | label: Do you use Docker?
54 | description: Are you running it with Docker or on your local computer?
55 | multiple: false
56 | options:
57 | - Docker
58 | - I don't use Docker
59 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:latest
2 |
3 | RUN apt-get update && apt-get install -y \
4 | wget \
5 | gnupg \
6 | ca-certificates \
7 | apt-transport-https \
8 | chromium \
9 | chromium-driver \
10 | xvfb \
11 | && rm -rf /var/lib/apt/lists/*
12 |
13 | ENV CHROME_BIN=/usr/bin/chromium
14 |
15 | WORKDIR /app
16 |
17 | COPY package*.json ./
18 |
19 | RUN npm update
20 | RUN npm install
21 | COPY . .
22 |
23 | # Command to run the application
24 | CMD ["npm", "run","cjs_test"]
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 - 2024 @zfcsoftware
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | > [!WARNING]
2 | > This repo will no longer receive updates. Thank you to everyone who supported it.
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
Puppeteer Real Browser
11 |
12 |
13 | This package prevents Puppeteer from being detected as a bot in services like Cloudflare and allows you to pass captchas without any problems. It behaves like a real browser.
14 |
15 |
16 | If you are only interested in Cloudflare WAF, please check this repo:
https://github.com/zfcsoftware/cf-clearance-scraper
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | ## Sponsor
33 |
34 | [](https://www.capsolver.com/?utm_source=github&utm_medium=repo&utm_campaign=scraping&utm_term=puppeteer-real-browser)
35 |
36 | [](https://scrape.do/?utm_source=github&utm_medium=repo_prb)
37 |
38 | ## Installation
39 |
40 | If you are using a Linux operating system, xvfb must be installed for the library to work correctly.
41 |
42 | ```bash
43 | npm i puppeteer-real-browser
44 | ```
45 |
46 | if you are using linux:
47 |
48 | ```bash
49 | sudo apt-get install xvfb
50 | ```
51 |
52 | ## Include
53 |
54 | ### CommonJS
55 |
56 | ```js
57 | const { connect } = require("puppeteer-real-browser");
58 |
59 | const start = async () => {
60 | const { page, browser } = await connect();
61 | };
62 | ```
63 |
64 | ### Module
65 |
66 | ```js
67 | import { connect } from "puppeteer-real-browser";
68 |
69 | const { page, browser } = await connect();
70 | ```
71 |
72 | ## Usage
73 |
74 | ```js
75 | const { connect } = require("puppeteer-real-browser");
76 |
77 | async function test() {
78 | const { browser, page } = await connect({
79 | headless: false,
80 |
81 | args: [],
82 |
83 | customConfig: {},
84 |
85 | turnstile: true,
86 |
87 | connectOption: {},
88 |
89 | disableXvfb: false,
90 | ignoreAllFlags: false,
91 | // proxy:{
92 | // host:'',
93 | // port:'',
94 | // username:'',
95 | // password:''
96 | // }
97 | });
98 | await page.goto("");
99 | }
100 |
101 | test();
102 | ```
103 |
104 | **headless**: The default value is false. Values such as “new”, true, “shell” can also be sent, but it works most stable when false is used.
105 |
106 | **args:** If there is an additional flag you want to add when starting Chromium, you can send it with this string.
107 | Supported flags: https://github.com/GoogleChrome/chrome-launcher/blob/main/docs/chrome-flags-for-tools.md
108 |
109 | **customConfig:** https://github.com/GoogleChrome/chrome-launcher The browser is initialized with this library. What you send with this object is added as a direct initialization argument. You should use the initialization values in this repo. You should set the userDataDir option here and if you want to specify a custom chrome path, you should set it with the chromePath value.
110 |
111 | **turnstile:** Cloudflare Turnstile automatically clicks on Captchas if set to true
112 |
113 | **connectOption:** The variables you send when connecting to chromium created with puppeteer.connect are added
114 |
115 | **disableXvfb:** In Linux, when headless is false, a virtual screen is created and the browser is run there. You can set this value to true if you want to see the browser.
116 |
117 | **ignoreAllFlags** If true, all initialization arguments are overridden. This includes the let's get started page that appears on the first load.
118 |
119 | ## How to Install Puppeteer-extra Plugins?
120 |
121 | Some plugins, such as puppeteer-extra-plugin-anonymize-ua, may cause you to be detected. You can use the plugin installation test in the library's test file to see if it will cause you to be detected.
122 |
123 | The following is an example of installing a plugin. You can install other plugins in the same way as this example.
124 |
125 | ```bash
126 | npm i puppeteer-extra-plugin-click-and-wait
127 | ```
128 |
129 | ```js
130 | const test = require("node:test");
131 | const assert = require("node:assert");
132 | const { connect } = require("puppeteer-real-browser");
133 |
134 | test("Puppeteer Extra Plugin", async () => {
135 | const { page, browser } = await connect({
136 | args: ["--start-maximized"],
137 | turnstile: true,
138 | headless: false,
139 | // disableXvfb: true,
140 | customConfig: {},
141 | connectOption: {
142 | defaultViewport: null,
143 | },
144 | plugins: [require("puppeteer-extra-plugin-click-and-wait")()],
145 | });
146 | await page.goto("https://google.com", { waitUntil: "domcontentloaded" });
147 | await page.clickAndWaitForNavigation("body");
148 | await browser.close();
149 | });
150 | ```
151 |
152 | ## Docker
153 |
154 | You can use the Dockerfile file in the main directory to use this library with docker. It has been tested with docker on Ubuntu server operating systems.
155 |
156 | To run a test, you can follow these steps
157 |
158 | ```bash
159 | git clone https://github.com/zfcsoftware/puppeteer-real-browser
160 | ```
161 |
162 | ```bash
163 | cd puppeteer-real-browser
164 | ```
165 |
166 | ```bash
167 | docker build -t puppeteer-real-browser-project .
168 | ```
169 |
170 | ```bash
171 | docker run puppeteer-real-browser-project
172 | ```
173 |
174 | ## Support Us
175 |
176 | This library is completely open source and is constantly being updated. Please star this repo to support this project. Starring and supporting the project will ensure that it receives updates. If you want to support it further, you can consider sponsoring me (https://github.com/sponsors/zfcsoftware)
177 |
178 | ## Quick Questions and Answers
179 |
180 | ### I Cannot Access Functions in Window Object What Should I Do?
181 |
182 | This problem is probably caused by the runtime being closed by the rebrowser used.
183 | https://github.com/zfcsoftware/puppeteer-real-browser/tree/access-window
184 | I created a branch for this. You can access the value you want by adding javascript to the page source with puppeteer-intercept-and-modify-requests as done in success.js. If you know about the Chrome plugin, you can also use it.
185 |
186 | ### page.setViewport method is not working, what should I do?
187 |
188 | As with the initialization arguments in the test module, you can set the defaultViewport in connectOption. If you set null, it will take up as much space as the width of the Browser.
189 |
190 | ### Does the library have any known detection problems?
191 |
192 | using puppeteer-core patched with rebrowser. Tested with the challenging sites in the test file in headless false mode and passed with flying colors. The only known issue is that the mouse screeenX does not match the mouse position. This has been patched in the library.
193 |
194 | The ghost-cursor is included in the library. (https://github.com/zfcsoftware/puppeteer-real-browser/blob/2a5fba37a85c15625fb3c8d1f7cf8dcb109b9492/lib/cjs/module/pageController.js#L54) You can use ghost-cursor with page.realCursor. page.click It is recommended to use page.realClick instead of page.click.
195 |
196 | ### What Makes This Library Special?
197 |
198 | This library lets you launch and use Chrome in its most natural state. It tries to get the best results with minimal patching. Thanks to @nwebson who fixed the Runtime.enable issue from this point. If using rebrowser solves your problem, I don't recommend using real browser.
199 |
200 | Real browser does not give you full control over launching. It launches Chrome with Chrome launcher and connects to it with rebrowser.
201 |
202 | ### Why can't I pass Recaptcha v3?
203 |
204 | https://stackoverflow.com/questions/52546045/how-to-pass-recaptcha-v3
205 |
206 | Please see the answers in the link above. When there is no Google session, no matter how good your browser is, recaptcha identifies you as a bot. It is a common problem.
207 |
208 | ## License
209 |
210 | Distributed under the MIT License. See [LICENSE](https://github.com/zfcsoftware/puppeteer-real-browser/blob/main/LICENSE.md) for more information.
211 |
212 | ## Thank You
213 |
214 | **Contributions to the current version**
215 |
216 | - **rebrowser™** - [rebrowser™](https://github.com/rebrowser) - _Created a patch pack for Runtime, which left many traces behind. Since Runtime was not used, most problems were solved. TargetFilter, which was used in the past and caused many problems, was switched to this patch. The Puppeteer-core library was patched and added to this repo. A lot of good bot detection systems are not caught thanks to rebrowser. Please star the rebrowser repo. Thank you. (https://github.com/rebrowser/rebrowser-patches)_
217 |
218 | - **Skill Issue™** - [TheFalloutOf76](https://github.com/TheFalloutOf76) - _He realized that mouse movements could not be simulated accurately and created a solution for this. His solution is used in this library. (https://github.com/TheFalloutOf76/CDP-bug-MouseEvent-.screenX-.screenY-patcher)_
219 |
220 | ## Disclaimer of Liability
221 |
222 | No responsibility is accepted for the use of this software. This software is intended for educational and informational purposes only. Users should use this software at their own risk. The developer cannot be held liable for any damages that may result from the use of this software.
223 |
224 | This software is not intended to bypass Cloudflare Captcha or any other security measure. It must not be used for malicious purposes. Malicious use may result in legal consequences.
225 |
226 | This software is not officially endorsed or guaranteed. Users can visit the GitHub page to report bugs or contribute to the software, but they are not entitled to make any claims or request service fixes.
227 |
228 | By using this software, you agree to this disclaimer.
229 |
--------------------------------------------------------------------------------
/data/capsolver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZFC-Digital/puppeteer-real-browser/4550aeabfed280ac1977d2768a6aa65bde69c367/data/capsolver.png
--------------------------------------------------------------------------------
/data/sdo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZFC-Digital/puppeteer-real-browser/4550aeabfed280ac1977d2768a6aa65bde69c367/data/sdo.gif
--------------------------------------------------------------------------------
/lib/cjs/index.js:
--------------------------------------------------------------------------------
1 | let puppeteer = require("rebrowser-puppeteer-core");
2 | const { pageController } = require("./module/pageController.js");
3 | let Xvfb
4 | try {
5 | Xvfb = require("xvfb");
6 | } catch {
7 | // ignore
8 | }
9 |
10 | async function connect({
11 | args = [],
12 | headless = false,
13 | customConfig = {},
14 | proxy = {},
15 | turnstile = false,
16 | connectOption = {},
17 | disableXvfb = false,
18 | plugins = [],
19 | ignoreAllFlags = false,
20 | } = {}) {
21 | const { launch, Launcher } = await import("chrome-launcher");
22 |
23 | let xvfbsession = null;
24 | if (headless == "auto") headless = false;
25 |
26 | if (process.platform === "linux" && disableXvfb === false) {
27 | try {
28 | xvfbsession = new Xvfb({
29 | silent: true,
30 | xvfb_args: ["-screen", "0", "1920x1080x24", "-ac"],
31 | });
32 | xvfbsession.startSync();
33 | } catch (err) {
34 | console.log(
35 | "You are running on a Linux platform but do not have xvfb installed. The browser can be captured. Please install it with the following command\n\nsudo apt-get install xvfb\n\n" +
36 | err.message
37 | );
38 | }
39 | }
40 |
41 | let chromeFlags;
42 | if (ignoreAllFlags === true) {
43 | chromeFlags = [
44 | ...args,
45 | ...(headless !== false ? [`--headless=${headless}`] : []),
46 | ...(proxy && proxy.host && proxy.port
47 | ? [`--proxy-server=${proxy.host}:${proxy.port}`]
48 | : []),
49 | ];
50 | } else {
51 | // Default flags: https://github.com/GoogleChrome/chrome-launcher/blob/main/src/flags.ts
52 | const flags = Launcher.defaultFlags();
53 | // Add AutomationControlled to "disable-features" flag
54 | const indexDisableFeatures = flags.findIndex((flag) => flag.startsWith('--disable-features'));
55 | flags[indexDisableFeatures] = `${flags[indexDisableFeatures]},AutomationControlled`;
56 | // Remove "disable-component-update" flag
57 | const indexComponentUpdateFlag = flags.findIndex((flag) => flag.startsWith('--disable-component-update'));
58 | flags.splice(indexComponentUpdateFlag, 1);
59 | chromeFlags = [
60 | ...flags,
61 | ...args,
62 | ...(headless !== false ? [`--headless=${headless}`] : []),
63 | ...(proxy && proxy.host && proxy.port
64 | ? [`--proxy-server=${proxy.host}:${proxy.port}`]
65 | : []),
66 | "--no-sandbox",
67 | "--disable-dev-shm-usage",
68 | ];
69 | }
70 | const chrome = await launch({
71 | ignoreDefaultFlags: true,
72 | chromeFlags,
73 | ...customConfig,
74 | });
75 |
76 | if (plugins.length > 0) {
77 | const { addExtra } = await import("puppeteer-extra");
78 |
79 | puppeteer = addExtra(puppeteer);
80 |
81 | for (const item of plugins) {
82 | puppeteer.use(item);
83 | }
84 | }
85 |
86 | const browser = await puppeteer.connect({
87 | browserURL: `http://127.0.0.1:${chrome.port}`,
88 | ...connectOption,
89 | });
90 |
91 | let [page] = await browser.pages();
92 |
93 | let pageControllerConfig = {
94 | browser,
95 | page,
96 | proxy,
97 | turnstile,
98 | xvfbsession,
99 | pid: chrome.pid,
100 | plugins,
101 | };
102 |
103 | page = await pageController({
104 | ...pageControllerConfig,
105 | killProcess: true,
106 | chrome,
107 | });
108 |
109 | browser.on("targetcreated", async (target) => {
110 | if (target.type() === "page") {
111 | let newPage = await target.page();
112 | pageControllerConfig.page = newPage;
113 | newPage = await pageController(pageControllerConfig);
114 | }
115 | });
116 |
117 | return {
118 | browser,
119 | page,
120 | };
121 | }
122 |
123 | module.exports = { connect };
124 |
--------------------------------------------------------------------------------
/lib/cjs/module/pageController.js:
--------------------------------------------------------------------------------
1 | const { createCursor } = require('ghost-cursor');
2 | const { checkTurnstile } = require('./turnstile.js');
3 | const kill = require('tree-kill');
4 |
5 | function getRandomInt(min, max) {
6 | min = Math.ceil(min);
7 | max = Math.floor(max);
8 | return Math.floor(Math.random() * (max - min + 1)) + min;
9 | }
10 |
11 | async function pageController({ browser, page, proxy, turnstile, xvfbsession, pid, plugins, killProcess = false, chrome }) {
12 |
13 | let solveStatus = turnstile
14 |
15 | page.on('close', () => {
16 | solveStatus = false
17 | });
18 |
19 |
20 | browser.on('disconnected', async () => {
21 | solveStatus = false
22 | if (killProcess === true) {
23 | if (xvfbsession) try { xvfbsession.stopSync() } catch (err) { }
24 | if (chrome) try { chrome.kill() } catch (err) { console.log(err); }
25 | if (pid) try { kill(pid, 'SIGKILL', () => { }) } catch (err) { }
26 | }
27 | });
28 |
29 | async function turnstileSolver() {
30 | while (solveStatus) {
31 | await checkTurnstile({ page }).catch(() => { });
32 | await new Promise(r => setTimeout(r, 1000));
33 | }
34 | return
35 | }
36 |
37 | turnstileSolver()
38 |
39 | if (proxy.username && proxy.password) await page.authenticate({ username: proxy.username, password: proxy.password });
40 |
41 | if (plugins.length > 0) {
42 | for (const plugin of plugins) {
43 | plugin.onPageCreated(page)
44 | }
45 | }
46 |
47 | await page.evaluateOnNewDocument(() => {
48 | Object.defineProperty(MouseEvent.prototype, 'screenX', {
49 | get: function () {
50 | return this.clientX + window.screenX;
51 | }
52 | });
53 |
54 | Object.defineProperty(MouseEvent.prototype, 'screenY', {
55 | get: function () {
56 | return this.clientY + window.screenY;
57 | }
58 | });
59 |
60 | });
61 |
62 | const cursor = createCursor(page);
63 | page.realCursor = cursor
64 | page.realClick = cursor.click
65 |
66 | return page
67 | }
68 |
69 | module.exports = { pageController }
--------------------------------------------------------------------------------
/lib/cjs/module/turnstile.js:
--------------------------------------------------------------------------------
1 | const checkTurnstile = ({ page }) => {
2 | return new Promise(async (resolve, reject) => {
3 | var waitInterval = setTimeout(() => { clearInterval(waitInterval); resolve(false) }, 5000);
4 | try {
5 | const elements = await page.$$('[name="cf-turnstile-response"]');
6 | if (elements.length <= 0) {
7 |
8 | const coordinates = await page.evaluate(() => {
9 | let coordinates = [];
10 | document.querySelectorAll('div').forEach(item => {
11 | try {
12 | let itemCoordinates = item.getBoundingClientRect()
13 | let itemCss = window.getComputedStyle(item)
14 | if (itemCss.margin == "0px" && itemCss.padding == "0px" && itemCoordinates.width > 290 && itemCoordinates.width <= 310 && !item.querySelector('*')) {
15 | coordinates.push({ x: itemCoordinates.x, y: item.getBoundingClientRect().y, w: item.getBoundingClientRect().width, h: item.getBoundingClientRect().height })
16 | }
17 | } catch (err) { }
18 | });
19 |
20 | if (coordinates.length <= 0) {
21 | document.querySelectorAll('div').forEach(item => {
22 | try {
23 | let itemCoordinates = item.getBoundingClientRect()
24 | if (itemCoordinates.width > 290 && itemCoordinates.width <= 310 && !item.querySelector('*')) {
25 | coordinates.push({ x: itemCoordinates.x, y: item.getBoundingClientRect().y, w: item.getBoundingClientRect().width, h: item.getBoundingClientRect().height })
26 | }
27 | } catch (err) { }
28 | });
29 |
30 | }
31 |
32 | return coordinates
33 | })
34 |
35 | for (const item of coordinates) {
36 | try {
37 | let x = item.x + 30;
38 | let y = item.y + item.h / 2;
39 | await page.mouse.click(x, y);
40 | } catch (err) { }
41 | }
42 | return resolve(true)
43 | }
44 |
45 | for (const element of elements) {
46 | try {
47 | const parentElement = await element.evaluateHandle(el => el.parentElement);
48 | const box = await parentElement.boundingBox();
49 | let x = box.x + 30;
50 | let y = box.y + box.height / 2;
51 | await page.mouse.click(x, y);
52 | } catch (err) { }
53 | }
54 | clearInterval(waitInterval)
55 | resolve(true)
56 | } catch (err) {
57 | clearInterval(waitInterval)
58 | resolve(false)
59 | }
60 | })
61 | }
62 |
63 | module.exports = { checkTurnstile }
--------------------------------------------------------------------------------
/lib/esm/index.mjs:
--------------------------------------------------------------------------------
1 | import { launch, Launcher } from "chrome-launcher";
2 | import puppeteer from "rebrowser-puppeteer-core";
3 | import { pageController } from "./module/pageController.mjs";
4 |
5 | // process.env.REBROWSER_PATCHES_DEBUG=1
6 | export async function connect({
7 | args = [],
8 | headless = false,
9 | customConfig = {},
10 | proxy = {},
11 | turnstile = false,
12 | connectOption = {},
13 | disableXvfb = false,
14 | plugins = [],
15 | ignoreAllFlags = false,
16 | } = {}) {
17 | let xvfbsession = null;
18 | if (headless == "auto") headless = false;
19 |
20 | if (process.platform === "linux" && disableXvfb === false) {
21 | try {
22 | const { default: Xvfb } = await import("xvfb");
23 | xvfbsession = new Xvfb({
24 | silent: true,
25 | xvfb_args: ["-screen", "0", "1920x1080x24", "-ac"],
26 | });
27 | xvfbsession.startSync();
28 | } catch (err) {
29 | console.log(
30 | "You are running on a Linux platform but do not have xvfb installed. The browser can be captured. Please install it with the following command\n\nsudo apt-get install xvfb\n\n" +
31 | err.message
32 | );
33 | }
34 | }
35 |
36 | let chromeFlags;
37 | if (ignoreAllFlags === true) {
38 | chromeFlags = [
39 | ...args,
40 | ...(headless !== false ? [`--headless=${headless}`] : []),
41 | ...(proxy && proxy.host && proxy.port
42 | ? [`--proxy-server=${proxy.host}:${proxy.port}`]
43 | : []),
44 | ];
45 | } else {
46 | // Default flags: https://github.com/GoogleChrome/chrome-launcher/blob/main/src/flags.ts
47 | const flags = Launcher.defaultFlags();
48 | // Add AutomationControlled to "disable-features" flag
49 | const indexDisableFeatures = flags.findIndex((flag) => flag.startsWith('--disable-features'));
50 | flags[indexDisableFeatures] = `${flags[indexDisableFeatures]},AutomationControlled`;
51 | // Remove "disable-component-update" flag
52 | const indexComponentUpdateFlag = flags.findIndex((flag) => flag.startsWith('--disable-component-update'));
53 | flags.splice(indexComponentUpdateFlag, 1);
54 | chromeFlags = [
55 | ...flags,
56 | ...args,
57 | ...(headless !== false ? [`--headless=${headless}`] : []),
58 | ...(proxy && proxy.host && proxy.port
59 | ? [`--proxy-server=${proxy.host}:${proxy.port}`]
60 | : []),
61 | "--no-sandbox",
62 | "--disable-dev-shm-usage",
63 | ];
64 | }
65 | const chrome = await launch({
66 | ignoreDefaultFlags: true,
67 | chromeFlags,
68 | ...customConfig,
69 | });
70 | let pextra = null;
71 | if (plugins.length > 0) {
72 | const { addExtra } = await import("puppeteer-extra");
73 |
74 | pextra = addExtra(puppeteer);
75 |
76 | for (const item of plugins) {
77 | pextra.use(item);
78 | }
79 | }
80 |
81 | const browser = await (pextra ? pextra : puppeteer).connect({
82 | browserURL: `http://127.0.0.1:${chrome.port}`,
83 | ...connectOption,
84 | });
85 |
86 | let [page] = await browser.pages();
87 |
88 | let pageControllerConfig = {
89 | browser,
90 | page,
91 | proxy,
92 | turnstile,
93 | xvfbsession,
94 | pid: chrome.pid,
95 | plugins,
96 | };
97 |
98 | page = await pageController({
99 | ...pageControllerConfig,
100 | chrome,
101 | killProcess: true,
102 | });
103 |
104 | browser.on("targetcreated", async (target) => {
105 | if (target.type() === "page") {
106 | let newPage = await target.page();
107 | pageControllerConfig.page = newPage;
108 | newPage = await pageController(pageControllerConfig);
109 | }
110 | });
111 |
112 | return {
113 | browser,
114 | page,
115 | };
116 | }
117 |
--------------------------------------------------------------------------------
/lib/esm/module/pageController.mjs:
--------------------------------------------------------------------------------
1 | import { createCursor } from 'ghost-cursor';
2 | import { checkTurnstile } from './turnstile.mjs';
3 | import kill from 'tree-kill';
4 |
5 | function getRandomInt(min, max) {
6 | min = Math.ceil(min);
7 | max = Math.floor(max);
8 | return Math.floor(Math.random() * (max - min + 1)) + min;
9 | }
10 |
11 | export async function pageController({ browser, page, proxy, turnstile, xvfbsession, pid, plugins, killProcess = false, chrome }) {
12 |
13 | let solveStatus = turnstile
14 |
15 | page.on('close', () => {
16 | solveStatus = false
17 | });
18 |
19 |
20 | browser.on('disconnected', async () => {
21 | solveStatus = false
22 | if (killProcess === true) {
23 | if (xvfbsession) try { xvfbsession.stopSync() } catch (err) { }
24 | if (chrome) try { chrome.kill() } catch (err) { console.log(err); }
25 | if (pid) try { kill(pid, 'SIGKILL', () => { }) } catch (err) { }
26 | }
27 | });
28 |
29 | async function turnstileSolver() {
30 | while (solveStatus) {
31 | await checkTurnstile({ page }).catch(() => { });
32 | await new Promise(r => setTimeout(r, 1000));
33 | }
34 | return
35 | }
36 |
37 | turnstileSolver()
38 |
39 | if (proxy.username && proxy.password) await page.authenticate({ username: proxy.username, password: proxy.password });
40 |
41 | if (plugins.length > 0) {
42 | for (const plugin of plugins) {
43 | plugin.onPageCreated(page)
44 | }
45 | }
46 |
47 | await page.evaluateOnNewDocument(() => {
48 | Object.defineProperty(MouseEvent.prototype, 'screenX', {
49 | get: function () {
50 | return this.clientX + window.screenX;
51 | }
52 | });
53 |
54 | Object.defineProperty(MouseEvent.prototype, 'screenY', {
55 | get: function () {
56 | return this.clientY + window.screenY;
57 | }
58 | });
59 |
60 | });
61 |
62 | const cursor = createCursor(page);
63 | page.realCursor = cursor
64 | page.realClick = cursor.click
65 | return page
66 | }
--------------------------------------------------------------------------------
/lib/esm/module/turnstile.mjs:
--------------------------------------------------------------------------------
1 | export const checkTurnstile = ({ page }) => {
2 | return new Promise(async (resolve, reject) => {
3 | var waitInterval = setTimeout(() => { clearInterval(waitInterval); resolve(false) }, 5000);
4 |
5 | try {
6 | const elements = await page.$$('[name="cf-turnstile-response"]');
7 | if (elements.length <= 0) {
8 |
9 | const coordinates = await page.evaluate(() => {
10 | let coordinates = [];
11 | document.querySelectorAll('div').forEach(item => {
12 | try {
13 | let itemCoordinates = item.getBoundingClientRect()
14 | let itemCss = window.getComputedStyle(item)
15 | if (itemCss.margin == "0px" && itemCss.padding == "0px" && itemCoordinates.width > 290 && itemCoordinates.width <= 310 && !item.querySelector('*')) {
16 | coordinates.push({ x: itemCoordinates.x, y: item.getBoundingClientRect().y, w: item.getBoundingClientRect().width, h: item.getBoundingClientRect().height })
17 | }
18 | } catch (err) { }
19 | });
20 |
21 | if (coordinates.length <= 0) {
22 | document.querySelectorAll('div').forEach(item => {
23 | try {
24 | let itemCoordinates = item.getBoundingClientRect()
25 | if (itemCoordinates.width > 290 && itemCoordinates.width <= 310 && !item.querySelector('*')) {
26 | coordinates.push({ x: itemCoordinates.x, y: item.getBoundingClientRect().y, w: item.getBoundingClientRect().width, h: item.getBoundingClientRect().height })
27 | }
28 | } catch (err) { }
29 | });
30 |
31 | }
32 |
33 | return coordinates
34 | })
35 |
36 | for (const item of coordinates) {
37 | try {
38 | let x = item.x + 30;
39 | let y = item.y + item.h / 2;
40 | await page.mouse.click(x, y);
41 | } catch (err) { }
42 | }
43 | return resolve(true)
44 | }
45 |
46 | for (const element of elements) {
47 | try {
48 | const parentElement = await element.evaluateHandle(el => el.parentElement);
49 | const box = await parentElement.boundingBox();
50 | let x = box.x + 30;
51 | let y = box.y + box.height / 2;
52 | await page.mouse.click(x, y);
53 | } catch (err) { }
54 | }
55 | clearInterval(waitInterval)
56 | resolve(true)
57 | } catch (err) {
58 | clearInterval(waitInterval)
59 | resolve(false)
60 | }
61 | })
62 | }
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "puppeteer-real-browser",
3 | "version": "1.3.22",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "puppeteer-real-browser",
9 | "version": "1.3.22",
10 | "license": "ISC",
11 | "dependencies": {
12 | "chrome-launcher": "^1.1.2",
13 | "ghost-cursor": "^1.3.0",
14 | "puppeteer-extra": "^3.3.6",
15 | "rebrowser-puppeteer-core": "^23.3.1",
16 | "tree-kill": "^1.2.2",
17 | "xvfb": "^0.4.0"
18 | }
19 | },
20 | "node_modules/@tootallnate/quickjs-emscripten": {
21 | "version": "0.23.0",
22 | "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
23 | "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
24 | "license": "MIT"
25 | },
26 | "node_modules/@types/bezier-js": {
27 | "version": "4.1.3",
28 | "resolved": "https://registry.npmjs.org/@types/bezier-js/-/bezier-js-4.1.3.tgz",
29 | "integrity": "sha512-FNVVCu5mx/rJCWBxLTcL7oOajmGtWtBTDjq6DSUWUI12GeePivrZZXz+UgE0D6VYsLEjvExRO03z4hVtu3pTEQ==",
30 | "license": "MIT"
31 | },
32 | "node_modules/@types/debug": {
33 | "version": "4.1.12",
34 | "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
35 | "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==",
36 | "license": "MIT",
37 | "dependencies": {
38 | "@types/ms": "*"
39 | }
40 | },
41 | "node_modules/@types/ms": {
42 | "version": "0.7.34",
43 | "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz",
44 | "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==",
45 | "license": "MIT"
46 | },
47 | "node_modules/@types/node": {
48 | "version": "22.5.0",
49 | "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.0.tgz",
50 | "integrity": "sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==",
51 | "license": "MIT",
52 | "dependencies": {
53 | "undici-types": "~6.19.2"
54 | }
55 | },
56 | "node_modules/@types/yauzl": {
57 | "version": "2.10.3",
58 | "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
59 | "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
60 | "license": "MIT",
61 | "optional": true,
62 | "dependencies": {
63 | "@types/node": "*"
64 | }
65 | },
66 | "node_modules/agent-base": {
67 | "version": "7.1.1",
68 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
69 | "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
70 | "license": "MIT",
71 | "dependencies": {
72 | "debug": "^4.3.4"
73 | },
74 | "engines": {
75 | "node": ">= 14"
76 | }
77 | },
78 | "node_modules/ansi-regex": {
79 | "version": "5.0.1",
80 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
81 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
82 | "license": "MIT",
83 | "engines": {
84 | "node": ">=8"
85 | }
86 | },
87 | "node_modules/ansi-styles": {
88 | "version": "4.3.0",
89 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
90 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
91 | "license": "MIT",
92 | "dependencies": {
93 | "color-convert": "^2.0.1"
94 | },
95 | "engines": {
96 | "node": ">=8"
97 | },
98 | "funding": {
99 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
100 | }
101 | },
102 | "node_modules/ast-types": {
103 | "version": "0.13.4",
104 | "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
105 | "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
106 | "license": "MIT",
107 | "dependencies": {
108 | "tslib": "^2.0.1"
109 | },
110 | "engines": {
111 | "node": ">=4"
112 | }
113 | },
114 | "node_modules/b4a": {
115 | "version": "1.6.6",
116 | "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz",
117 | "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==",
118 | "license": "Apache-2.0"
119 | },
120 | "node_modules/bare-events": {
121 | "version": "2.4.2",
122 | "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz",
123 | "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==",
124 | "license": "Apache-2.0",
125 | "optional": true
126 | },
127 | "node_modules/bare-fs": {
128 | "version": "2.3.3",
129 | "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.3.tgz",
130 | "integrity": "sha512-7RYKL+vZVCyAsMLi5SPu7QGauGGT8avnP/HO571ndEuV4MYdGXvLhtW67FuLPeEI8EiIY7zbbRR9x7x7HU0kgw==",
131 | "license": "Apache-2.0",
132 | "optional": true,
133 | "dependencies": {
134 | "bare-events": "^2.0.0",
135 | "bare-path": "^2.0.0",
136 | "bare-stream": "^2.0.0"
137 | }
138 | },
139 | "node_modules/bare-os": {
140 | "version": "2.4.2",
141 | "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.2.tgz",
142 | "integrity": "sha512-HZoJwzC+rZ9lqEemTMiO0luOePoGYNBgsLLgegKR/cljiJvcDNhDZQkzC+NC5Oh0aHbdBNSOHpghwMuB5tqhjg==",
143 | "license": "Apache-2.0",
144 | "optional": true
145 | },
146 | "node_modules/bare-path": {
147 | "version": "2.1.3",
148 | "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz",
149 | "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==",
150 | "license": "Apache-2.0",
151 | "optional": true,
152 | "dependencies": {
153 | "bare-os": "^2.1.0"
154 | }
155 | },
156 | "node_modules/bare-stream": {
157 | "version": "2.2.1",
158 | "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.2.1.tgz",
159 | "integrity": "sha512-YTB47kHwBW9zSG8LD77MIBAAQXjU2WjAkMHeeb7hUplVs6+IoM5I7uEVQNPMB7lj9r8I76UMdoMkGnCodHOLqg==",
160 | "license": "Apache-2.0",
161 | "optional": true,
162 | "dependencies": {
163 | "b4a": "^1.6.6",
164 | "streamx": "^2.18.0"
165 | }
166 | },
167 | "node_modules/base64-js": {
168 | "version": "1.5.1",
169 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
170 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
171 | "funding": [
172 | {
173 | "type": "github",
174 | "url": "https://github.com/sponsors/feross"
175 | },
176 | {
177 | "type": "patreon",
178 | "url": "https://www.patreon.com/feross"
179 | },
180 | {
181 | "type": "consulting",
182 | "url": "https://feross.org/support"
183 | }
184 | ],
185 | "license": "MIT"
186 | },
187 | "node_modules/basic-ftp": {
188 | "version": "5.0.5",
189 | "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz",
190 | "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==",
191 | "license": "MIT",
192 | "engines": {
193 | "node": ">=10.0.0"
194 | }
195 | },
196 | "node_modules/bezier-js": {
197 | "version": "6.1.4",
198 | "resolved": "https://registry.npmjs.org/bezier-js/-/bezier-js-6.1.4.tgz",
199 | "integrity": "sha512-PA0FW9ZpcHbojUCMu28z9Vg/fNkwTj5YhusSAjHHDfHDGLxJ6YUKrAN2vk1fP2MMOxVw4Oko16FMlRGVBGqLKg==",
200 | "license": "MIT",
201 | "funding": {
202 | "type": "individual",
203 | "url": "https://github.com/Pomax/bezierjs/blob/master/FUNDING.md"
204 | }
205 | },
206 | "node_modules/buffer": {
207 | "version": "5.7.1",
208 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
209 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
210 | "funding": [
211 | {
212 | "type": "github",
213 | "url": "https://github.com/sponsors/feross"
214 | },
215 | {
216 | "type": "patreon",
217 | "url": "https://www.patreon.com/feross"
218 | },
219 | {
220 | "type": "consulting",
221 | "url": "https://feross.org/support"
222 | }
223 | ],
224 | "license": "MIT",
225 | "dependencies": {
226 | "base64-js": "^1.3.1",
227 | "ieee754": "^1.1.13"
228 | }
229 | },
230 | "node_modules/buffer-crc32": {
231 | "version": "0.2.13",
232 | "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
233 | "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
234 | "license": "MIT",
235 | "engines": {
236 | "node": "*"
237 | }
238 | },
239 | "node_modules/chrome-launcher": {
240 | "version": "1.1.2",
241 | "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.1.2.tgz",
242 | "integrity": "sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==",
243 | "license": "Apache-2.0",
244 | "dependencies": {
245 | "@types/node": "*",
246 | "escape-string-regexp": "^4.0.0",
247 | "is-wsl": "^2.2.0",
248 | "lighthouse-logger": "^2.0.1"
249 | },
250 | "bin": {
251 | "print-chrome-path": "bin/print-chrome-path.js"
252 | },
253 | "engines": {
254 | "node": ">=12.13.0"
255 | }
256 | },
257 | "node_modules/chromium-bidi": {
258 | "version": "0.6.5",
259 | "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.6.5.tgz",
260 | "integrity": "sha512-RuLrmzYrxSb0s9SgpB+QN5jJucPduZQ/9SIe76MDxYJuecPW5mxMdacJ1f4EtgiV+R0p3sCkznTMvH0MPGFqjA==",
261 | "license": "Apache-2.0",
262 | "dependencies": {
263 | "mitt": "3.0.1",
264 | "urlpattern-polyfill": "10.0.0",
265 | "zod": "3.23.8"
266 | },
267 | "peerDependencies": {
268 | "devtools-protocol": "*"
269 | }
270 | },
271 | "node_modules/cliui": {
272 | "version": "8.0.1",
273 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
274 | "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
275 | "license": "ISC",
276 | "dependencies": {
277 | "string-width": "^4.2.0",
278 | "strip-ansi": "^6.0.1",
279 | "wrap-ansi": "^7.0.0"
280 | },
281 | "engines": {
282 | "node": ">=12"
283 | }
284 | },
285 | "node_modules/color-convert": {
286 | "version": "2.0.1",
287 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
288 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
289 | "license": "MIT",
290 | "dependencies": {
291 | "color-name": "~1.1.4"
292 | },
293 | "engines": {
294 | "node": ">=7.0.0"
295 | }
296 | },
297 | "node_modules/color-name": {
298 | "version": "1.1.4",
299 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
300 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
301 | "license": "MIT"
302 | },
303 | "node_modules/data-uri-to-buffer": {
304 | "version": "6.0.2",
305 | "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
306 | "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==",
307 | "license": "MIT",
308 | "engines": {
309 | "node": ">= 14"
310 | }
311 | },
312 | "node_modules/debug": {
313 | "version": "4.3.7",
314 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
315 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
316 | "license": "MIT",
317 | "dependencies": {
318 | "ms": "^2.1.3"
319 | },
320 | "engines": {
321 | "node": ">=6.0"
322 | },
323 | "peerDependenciesMeta": {
324 | "supports-color": {
325 | "optional": true
326 | }
327 | }
328 | },
329 | "node_modules/deepmerge": {
330 | "version": "4.3.1",
331 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
332 | "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
333 | "license": "MIT",
334 | "engines": {
335 | "node": ">=0.10.0"
336 | }
337 | },
338 | "node_modules/degenerator": {
339 | "version": "5.0.1",
340 | "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
341 | "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
342 | "license": "MIT",
343 | "dependencies": {
344 | "ast-types": "^0.13.4",
345 | "escodegen": "^2.1.0",
346 | "esprima": "^4.0.1"
347 | },
348 | "engines": {
349 | "node": ">= 14"
350 | }
351 | },
352 | "node_modules/devtools-protocol": {
353 | "version": "0.0.1330662",
354 | "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1330662.tgz",
355 | "integrity": "sha512-pzh6YQ8zZfz3iKlCvgzVCu22NdpZ8hNmwU6WnQjNVquh0A9iVosPtNLWDwaWVGyrntQlltPFztTMK5Cg6lfCuw==",
356 | "license": "BSD-3-Clause"
357 | },
358 | "node_modules/emoji-regex": {
359 | "version": "8.0.0",
360 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
361 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
362 | "license": "MIT"
363 | },
364 | "node_modules/end-of-stream": {
365 | "version": "1.4.4",
366 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
367 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
368 | "license": "MIT",
369 | "dependencies": {
370 | "once": "^1.4.0"
371 | }
372 | },
373 | "node_modules/escalade": {
374 | "version": "3.2.0",
375 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
376 | "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
377 | "license": "MIT",
378 | "engines": {
379 | "node": ">=6"
380 | }
381 | },
382 | "node_modules/escape-string-regexp": {
383 | "version": "4.0.0",
384 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
385 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
386 | "license": "MIT",
387 | "engines": {
388 | "node": ">=10"
389 | },
390 | "funding": {
391 | "url": "https://github.com/sponsors/sindresorhus"
392 | }
393 | },
394 | "node_modules/escodegen": {
395 | "version": "2.1.0",
396 | "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
397 | "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
398 | "license": "BSD-2-Clause",
399 | "dependencies": {
400 | "esprima": "^4.0.1",
401 | "estraverse": "^5.2.0",
402 | "esutils": "^2.0.2"
403 | },
404 | "bin": {
405 | "escodegen": "bin/escodegen.js",
406 | "esgenerate": "bin/esgenerate.js"
407 | },
408 | "engines": {
409 | "node": ">=6.0"
410 | },
411 | "optionalDependencies": {
412 | "source-map": "~0.6.1"
413 | }
414 | },
415 | "node_modules/esprima": {
416 | "version": "4.0.1",
417 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
418 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
419 | "license": "BSD-2-Clause",
420 | "bin": {
421 | "esparse": "bin/esparse.js",
422 | "esvalidate": "bin/esvalidate.js"
423 | },
424 | "engines": {
425 | "node": ">=4"
426 | }
427 | },
428 | "node_modules/estraverse": {
429 | "version": "5.3.0",
430 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
431 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
432 | "license": "BSD-2-Clause",
433 | "engines": {
434 | "node": ">=4.0"
435 | }
436 | },
437 | "node_modules/esutils": {
438 | "version": "2.0.3",
439 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
440 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
441 | "license": "BSD-2-Clause",
442 | "engines": {
443 | "node": ">=0.10.0"
444 | }
445 | },
446 | "node_modules/extract-zip": {
447 | "version": "2.0.1",
448 | "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
449 | "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
450 | "license": "BSD-2-Clause",
451 | "dependencies": {
452 | "debug": "^4.1.1",
453 | "get-stream": "^5.1.0",
454 | "yauzl": "^2.10.0"
455 | },
456 | "bin": {
457 | "extract-zip": "cli.js"
458 | },
459 | "engines": {
460 | "node": ">= 10.17.0"
461 | },
462 | "optionalDependencies": {
463 | "@types/yauzl": "^2.9.1"
464 | }
465 | },
466 | "node_modules/fast-fifo": {
467 | "version": "1.3.2",
468 | "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
469 | "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
470 | "license": "MIT"
471 | },
472 | "node_modules/fd-slicer": {
473 | "version": "1.1.0",
474 | "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
475 | "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
476 | "license": "MIT",
477 | "dependencies": {
478 | "pend": "~1.2.0"
479 | }
480 | },
481 | "node_modules/fs-extra": {
482 | "version": "11.2.0",
483 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
484 | "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
485 | "license": "MIT",
486 | "dependencies": {
487 | "graceful-fs": "^4.2.0",
488 | "jsonfile": "^6.0.1",
489 | "universalify": "^2.0.0"
490 | },
491 | "engines": {
492 | "node": ">=14.14"
493 | }
494 | },
495 | "node_modules/get-caller-file": {
496 | "version": "2.0.5",
497 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
498 | "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
499 | "license": "ISC",
500 | "engines": {
501 | "node": "6.* || 8.* || >= 10.*"
502 | }
503 | },
504 | "node_modules/get-stream": {
505 | "version": "5.2.0",
506 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
507 | "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
508 | "license": "MIT",
509 | "dependencies": {
510 | "pump": "^3.0.0"
511 | },
512 | "engines": {
513 | "node": ">=8"
514 | },
515 | "funding": {
516 | "url": "https://github.com/sponsors/sindresorhus"
517 | }
518 | },
519 | "node_modules/get-uri": {
520 | "version": "6.0.3",
521 | "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz",
522 | "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==",
523 | "license": "MIT",
524 | "dependencies": {
525 | "basic-ftp": "^5.0.2",
526 | "data-uri-to-buffer": "^6.0.2",
527 | "debug": "^4.3.4",
528 | "fs-extra": "^11.2.0"
529 | },
530 | "engines": {
531 | "node": ">= 14"
532 | }
533 | },
534 | "node_modules/ghost-cursor": {
535 | "version": "1.3.0",
536 | "resolved": "https://registry.npmjs.org/ghost-cursor/-/ghost-cursor-1.3.0.tgz",
537 | "integrity": "sha512-niTjgH8o2EhYG0vJfGB45JrLAt5CRoXg+8zWIcXtcgUgLds+i6YyFXkYuHpno9gKi93KpQvxY/uVYMV9CeeJ0w==",
538 | "license": "ISC",
539 | "dependencies": {
540 | "@types/bezier-js": "4",
541 | "bezier-js": "^6.1.3",
542 | "debug": "^4.3.4"
543 | }
544 | },
545 | "node_modules/graceful-fs": {
546 | "version": "4.2.11",
547 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
548 | "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
549 | "license": "ISC"
550 | },
551 | "node_modules/http-proxy-agent": {
552 | "version": "7.0.2",
553 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
554 | "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
555 | "license": "MIT",
556 | "dependencies": {
557 | "agent-base": "^7.1.0",
558 | "debug": "^4.3.4"
559 | },
560 | "engines": {
561 | "node": ">= 14"
562 | }
563 | },
564 | "node_modules/https-proxy-agent": {
565 | "version": "7.0.5",
566 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
567 | "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
568 | "license": "MIT",
569 | "dependencies": {
570 | "agent-base": "^7.0.2",
571 | "debug": "4"
572 | },
573 | "engines": {
574 | "node": ">= 14"
575 | }
576 | },
577 | "node_modules/ieee754": {
578 | "version": "1.2.1",
579 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
580 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
581 | "funding": [
582 | {
583 | "type": "github",
584 | "url": "https://github.com/sponsors/feross"
585 | },
586 | {
587 | "type": "patreon",
588 | "url": "https://www.patreon.com/feross"
589 | },
590 | {
591 | "type": "consulting",
592 | "url": "https://feross.org/support"
593 | }
594 | ],
595 | "license": "BSD-3-Clause"
596 | },
597 | "node_modules/ip-address": {
598 | "version": "9.0.5",
599 | "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
600 | "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
601 | "license": "MIT",
602 | "dependencies": {
603 | "jsbn": "1.1.0",
604 | "sprintf-js": "^1.1.3"
605 | },
606 | "engines": {
607 | "node": ">= 12"
608 | }
609 | },
610 | "node_modules/is-docker": {
611 | "version": "2.2.1",
612 | "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
613 | "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
614 | "license": "MIT",
615 | "bin": {
616 | "is-docker": "cli.js"
617 | },
618 | "engines": {
619 | "node": ">=8"
620 | },
621 | "funding": {
622 | "url": "https://github.com/sponsors/sindresorhus"
623 | }
624 | },
625 | "node_modules/is-fullwidth-code-point": {
626 | "version": "3.0.0",
627 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
628 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
629 | "license": "MIT",
630 | "engines": {
631 | "node": ">=8"
632 | }
633 | },
634 | "node_modules/is-wsl": {
635 | "version": "2.2.0",
636 | "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
637 | "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
638 | "license": "MIT",
639 | "dependencies": {
640 | "is-docker": "^2.0.0"
641 | },
642 | "engines": {
643 | "node": ">=8"
644 | }
645 | },
646 | "node_modules/jsbn": {
647 | "version": "1.1.0",
648 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
649 | "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
650 | "license": "MIT"
651 | },
652 | "node_modules/jsonfile": {
653 | "version": "6.1.0",
654 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
655 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
656 | "license": "MIT",
657 | "dependencies": {
658 | "universalify": "^2.0.0"
659 | },
660 | "optionalDependencies": {
661 | "graceful-fs": "^4.1.6"
662 | }
663 | },
664 | "node_modules/lighthouse-logger": {
665 | "version": "2.0.1",
666 | "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.1.tgz",
667 | "integrity": "sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==",
668 | "license": "Apache-2.0",
669 | "dependencies": {
670 | "debug": "^2.6.9",
671 | "marky": "^1.2.2"
672 | }
673 | },
674 | "node_modules/lighthouse-logger/node_modules/debug": {
675 | "version": "2.6.9",
676 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
677 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
678 | "license": "MIT",
679 | "dependencies": {
680 | "ms": "2.0.0"
681 | }
682 | },
683 | "node_modules/lighthouse-logger/node_modules/ms": {
684 | "version": "2.0.0",
685 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
686 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
687 | "license": "MIT"
688 | },
689 | "node_modules/lru-cache": {
690 | "version": "7.18.3",
691 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
692 | "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
693 | "license": "ISC",
694 | "engines": {
695 | "node": ">=12"
696 | }
697 | },
698 | "node_modules/marky": {
699 | "version": "1.2.5",
700 | "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.5.tgz",
701 | "integrity": "sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==",
702 | "license": "Apache-2.0"
703 | },
704 | "node_modules/mitt": {
705 | "version": "3.0.1",
706 | "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
707 | "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
708 | "license": "MIT"
709 | },
710 | "node_modules/ms": {
711 | "version": "2.1.3",
712 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
713 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
714 | "license": "MIT"
715 | },
716 | "node_modules/nan": {
717 | "version": "2.20.0",
718 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz",
719 | "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==",
720 | "license": "MIT",
721 | "optional": true
722 | },
723 | "node_modules/netmask": {
724 | "version": "2.0.2",
725 | "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz",
726 | "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==",
727 | "license": "MIT",
728 | "engines": {
729 | "node": ">= 0.4.0"
730 | }
731 | },
732 | "node_modules/once": {
733 | "version": "1.4.0",
734 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
735 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
736 | "license": "ISC",
737 | "dependencies": {
738 | "wrappy": "1"
739 | }
740 | },
741 | "node_modules/pac-proxy-agent": {
742 | "version": "7.0.2",
743 | "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz",
744 | "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==",
745 | "license": "MIT",
746 | "dependencies": {
747 | "@tootallnate/quickjs-emscripten": "^0.23.0",
748 | "agent-base": "^7.0.2",
749 | "debug": "^4.3.4",
750 | "get-uri": "^6.0.1",
751 | "http-proxy-agent": "^7.0.0",
752 | "https-proxy-agent": "^7.0.5",
753 | "pac-resolver": "^7.0.1",
754 | "socks-proxy-agent": "^8.0.4"
755 | },
756 | "engines": {
757 | "node": ">= 14"
758 | }
759 | },
760 | "node_modules/pac-resolver": {
761 | "version": "7.0.1",
762 | "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
763 | "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
764 | "license": "MIT",
765 | "dependencies": {
766 | "degenerator": "^5.0.0",
767 | "netmask": "^2.0.2"
768 | },
769 | "engines": {
770 | "node": ">= 14"
771 | }
772 | },
773 | "node_modules/pend": {
774 | "version": "1.2.0",
775 | "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
776 | "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
777 | "license": "MIT"
778 | },
779 | "node_modules/progress": {
780 | "version": "2.0.3",
781 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
782 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
783 | "license": "MIT",
784 | "engines": {
785 | "node": ">=0.4.0"
786 | }
787 | },
788 | "node_modules/proxy-agent": {
789 | "version": "6.4.0",
790 | "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz",
791 | "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==",
792 | "license": "MIT",
793 | "dependencies": {
794 | "agent-base": "^7.0.2",
795 | "debug": "^4.3.4",
796 | "http-proxy-agent": "^7.0.1",
797 | "https-proxy-agent": "^7.0.3",
798 | "lru-cache": "^7.14.1",
799 | "pac-proxy-agent": "^7.0.1",
800 | "proxy-from-env": "^1.1.0",
801 | "socks-proxy-agent": "^8.0.2"
802 | },
803 | "engines": {
804 | "node": ">= 14"
805 | }
806 | },
807 | "node_modules/proxy-from-env": {
808 | "version": "1.1.0",
809 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
810 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
811 | "license": "MIT"
812 | },
813 | "node_modules/pump": {
814 | "version": "3.0.0",
815 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
816 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
817 | "license": "MIT",
818 | "dependencies": {
819 | "end-of-stream": "^1.1.0",
820 | "once": "^1.3.1"
821 | }
822 | },
823 | "node_modules/puppeteer-extra": {
824 | "version": "3.3.6",
825 | "resolved": "https://registry.npmjs.org/puppeteer-extra/-/puppeteer-extra-3.3.6.tgz",
826 | "integrity": "sha512-rsLBE/6mMxAjlLd06LuGacrukP2bqbzKCLzV1vrhHFavqQE/taQ2UXv3H5P0Ls7nsrASa+6x3bDbXHpqMwq+7A==",
827 | "license": "MIT",
828 | "dependencies": {
829 | "@types/debug": "^4.1.0",
830 | "debug": "^4.1.1",
831 | "deepmerge": "^4.2.2"
832 | },
833 | "engines": {
834 | "node": ">=8"
835 | },
836 | "peerDependencies": {
837 | "@types/puppeteer": "*",
838 | "puppeteer": "*",
839 | "puppeteer-core": "*"
840 | },
841 | "peerDependenciesMeta": {
842 | "@types/puppeteer": {
843 | "optional": true
844 | },
845 | "puppeteer": {
846 | "optional": true
847 | },
848 | "puppeteer-core": {
849 | "optional": true
850 | }
851 | }
852 | },
853 | "node_modules/queue-tick": {
854 | "version": "1.0.1",
855 | "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
856 | "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
857 | "license": "MIT"
858 | },
859 | "node_modules/rebrowser-puppeteer-core": {
860 | "version": "23.3.1",
861 | "resolved": "https://registry.npmjs.org/rebrowser-puppeteer-core/-/rebrowser-puppeteer-core-23.3.1.tgz",
862 | "integrity": "sha512-+BB6leL2aSnpR/DYc0cqcdue3PCzPzT6t0b3IUFbhfQVjfr0WHXNpEd5/AECTg42O/3YdMkLLXNyfzmd+aiFsw==",
863 | "license": "Apache-2.0",
864 | "dependencies": {
865 | "@puppeteer/browsers": "2.4.0",
866 | "chromium-bidi": "0.6.5",
867 | "debug": "^4.3.7",
868 | "devtools-protocol": "0.0.1330662",
869 | "typed-query-selector": "^2.12.0",
870 | "ws": "^8.18.0"
871 | },
872 | "engines": {
873 | "node": ">=18"
874 | }
875 | },
876 | "node_modules/rebrowser-puppeteer-core/node_modules/@puppeteer/browsers": {
877 | "version": "2.4.0",
878 | "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.4.0.tgz",
879 | "integrity": "sha512-x8J1csfIygOwf6D6qUAZ0ASk3z63zPb7wkNeHRerCMh82qWKUrOgkuP005AJC8lDL6/evtXETGEJVcwykKT4/g==",
880 | "license": "Apache-2.0",
881 | "dependencies": {
882 | "debug": "^4.3.6",
883 | "extract-zip": "^2.0.1",
884 | "progress": "^2.0.3",
885 | "proxy-agent": "^6.4.0",
886 | "semver": "^7.6.3",
887 | "tar-fs": "^3.0.6",
888 | "unbzip2-stream": "^1.4.3",
889 | "yargs": "^17.7.2"
890 | },
891 | "bin": {
892 | "browsers": "lib/cjs/main-cli.js"
893 | },
894 | "engines": {
895 | "node": ">=18"
896 | }
897 | },
898 | "node_modules/require-directory": {
899 | "version": "2.1.1",
900 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
901 | "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
902 | "license": "MIT",
903 | "engines": {
904 | "node": ">=0.10.0"
905 | }
906 | },
907 | "node_modules/semver": {
908 | "version": "7.6.3",
909 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
910 | "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
911 | "license": "ISC",
912 | "bin": {
913 | "semver": "bin/semver.js"
914 | },
915 | "engines": {
916 | "node": ">=10"
917 | }
918 | },
919 | "node_modules/sleep": {
920 | "version": "6.1.0",
921 | "resolved": "https://registry.npmjs.org/sleep/-/sleep-6.1.0.tgz",
922 | "integrity": "sha512-Z1x4JjJxsru75Tqn8F4tnOFeEu3HjtITTsumYUiuz54sGKdISgLCek9AUlXlVVrkhltRFhNUsJDJE76SFHTDIQ==",
923 | "hasInstallScript": true,
924 | "license": "MIT",
925 | "optional": true,
926 | "dependencies": {
927 | "nan": "^2.13.2"
928 | },
929 | "engines": {
930 | "node": ">=0.8.0"
931 | }
932 | },
933 | "node_modules/smart-buffer": {
934 | "version": "4.2.0",
935 | "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
936 | "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
937 | "license": "MIT",
938 | "engines": {
939 | "node": ">= 6.0.0",
940 | "npm": ">= 3.0.0"
941 | }
942 | },
943 | "node_modules/socks": {
944 | "version": "2.8.3",
945 | "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
946 | "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
947 | "license": "MIT",
948 | "dependencies": {
949 | "ip-address": "^9.0.5",
950 | "smart-buffer": "^4.2.0"
951 | },
952 | "engines": {
953 | "node": ">= 10.0.0",
954 | "npm": ">= 3.0.0"
955 | }
956 | },
957 | "node_modules/socks-proxy-agent": {
958 | "version": "8.0.4",
959 | "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz",
960 | "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==",
961 | "license": "MIT",
962 | "dependencies": {
963 | "agent-base": "^7.1.1",
964 | "debug": "^4.3.4",
965 | "socks": "^2.8.3"
966 | },
967 | "engines": {
968 | "node": ">= 14"
969 | }
970 | },
971 | "node_modules/source-map": {
972 | "version": "0.6.1",
973 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
974 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
975 | "license": "BSD-3-Clause",
976 | "optional": true,
977 | "engines": {
978 | "node": ">=0.10.0"
979 | }
980 | },
981 | "node_modules/sprintf-js": {
982 | "version": "1.1.3",
983 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
984 | "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
985 | "license": "BSD-3-Clause"
986 | },
987 | "node_modules/streamx": {
988 | "version": "2.20.0",
989 | "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.0.tgz",
990 | "integrity": "sha512-ZGd1LhDeGFucr1CUCTBOS58ZhEendd0ttpGT3usTvosS4ntIwKN9LJFp+OeCSprsCPL14BXVRZlHGRY1V9PVzQ==",
991 | "license": "MIT",
992 | "dependencies": {
993 | "fast-fifo": "^1.3.2",
994 | "queue-tick": "^1.0.1",
995 | "text-decoder": "^1.1.0"
996 | },
997 | "optionalDependencies": {
998 | "bare-events": "^2.2.0"
999 | }
1000 | },
1001 | "node_modules/string-width": {
1002 | "version": "4.2.3",
1003 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
1004 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
1005 | "license": "MIT",
1006 | "dependencies": {
1007 | "emoji-regex": "^8.0.0",
1008 | "is-fullwidth-code-point": "^3.0.0",
1009 | "strip-ansi": "^6.0.1"
1010 | },
1011 | "engines": {
1012 | "node": ">=8"
1013 | }
1014 | },
1015 | "node_modules/strip-ansi": {
1016 | "version": "6.0.1",
1017 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
1018 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
1019 | "license": "MIT",
1020 | "dependencies": {
1021 | "ansi-regex": "^5.0.1"
1022 | },
1023 | "engines": {
1024 | "node": ">=8"
1025 | }
1026 | },
1027 | "node_modules/tar-fs": {
1028 | "version": "3.0.6",
1029 | "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz",
1030 | "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==",
1031 | "license": "MIT",
1032 | "dependencies": {
1033 | "pump": "^3.0.0",
1034 | "tar-stream": "^3.1.5"
1035 | },
1036 | "optionalDependencies": {
1037 | "bare-fs": "^2.1.1",
1038 | "bare-path": "^2.1.0"
1039 | }
1040 | },
1041 | "node_modules/tar-stream": {
1042 | "version": "3.1.7",
1043 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
1044 | "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
1045 | "license": "MIT",
1046 | "dependencies": {
1047 | "b4a": "^1.6.4",
1048 | "fast-fifo": "^1.2.0",
1049 | "streamx": "^2.15.0"
1050 | }
1051 | },
1052 | "node_modules/text-decoder": {
1053 | "version": "1.1.1",
1054 | "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz",
1055 | "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==",
1056 | "license": "Apache-2.0",
1057 | "dependencies": {
1058 | "b4a": "^1.6.4"
1059 | }
1060 | },
1061 | "node_modules/through": {
1062 | "version": "2.3.8",
1063 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
1064 | "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
1065 | "license": "MIT"
1066 | },
1067 | "node_modules/tree-kill": {
1068 | "version": "1.2.2",
1069 | "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
1070 | "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
1071 | "license": "MIT",
1072 | "bin": {
1073 | "tree-kill": "cli.js"
1074 | }
1075 | },
1076 | "node_modules/tslib": {
1077 | "version": "2.7.0",
1078 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
1079 | "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
1080 | "license": "0BSD"
1081 | },
1082 | "node_modules/typed-query-selector": {
1083 | "version": "2.12.0",
1084 | "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz",
1085 | "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==",
1086 | "license": "MIT"
1087 | },
1088 | "node_modules/unbzip2-stream": {
1089 | "version": "1.4.3",
1090 | "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
1091 | "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
1092 | "license": "MIT",
1093 | "dependencies": {
1094 | "buffer": "^5.2.1",
1095 | "through": "^2.3.8"
1096 | }
1097 | },
1098 | "node_modules/undici-types": {
1099 | "version": "6.19.8",
1100 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
1101 | "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
1102 | "license": "MIT"
1103 | },
1104 | "node_modules/universalify": {
1105 | "version": "2.0.1",
1106 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
1107 | "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
1108 | "license": "MIT",
1109 | "engines": {
1110 | "node": ">= 10.0.0"
1111 | }
1112 | },
1113 | "node_modules/urlpattern-polyfill": {
1114 | "version": "10.0.0",
1115 | "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz",
1116 | "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==",
1117 | "license": "MIT"
1118 | },
1119 | "node_modules/wrap-ansi": {
1120 | "version": "7.0.0",
1121 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
1122 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
1123 | "license": "MIT",
1124 | "dependencies": {
1125 | "ansi-styles": "^4.0.0",
1126 | "string-width": "^4.1.0",
1127 | "strip-ansi": "^6.0.0"
1128 | },
1129 | "engines": {
1130 | "node": ">=10"
1131 | },
1132 | "funding": {
1133 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
1134 | }
1135 | },
1136 | "node_modules/wrappy": {
1137 | "version": "1.0.2",
1138 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1139 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
1140 | "license": "ISC"
1141 | },
1142 | "node_modules/ws": {
1143 | "version": "8.18.0",
1144 | "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
1145 | "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
1146 | "license": "MIT",
1147 | "engines": {
1148 | "node": ">=10.0.0"
1149 | },
1150 | "peerDependencies": {
1151 | "bufferutil": "^4.0.1",
1152 | "utf-8-validate": ">=5.0.2"
1153 | },
1154 | "peerDependenciesMeta": {
1155 | "bufferutil": {
1156 | "optional": true
1157 | },
1158 | "utf-8-validate": {
1159 | "optional": true
1160 | }
1161 | }
1162 | },
1163 | "node_modules/xvfb": {
1164 | "version": "0.4.0",
1165 | "resolved": "https://registry.npmjs.org/xvfb/-/xvfb-0.4.0.tgz",
1166 | "integrity": "sha512-g55AbjcBL4Bztfn7kiUrR0ne8mMUsFODDJ+HFGf5OuHJqKKccpExX2Qgn7VF2eImw1eoh6+riXHser1J4agrFA==",
1167 | "license": "MIT",
1168 | "optionalDependencies": {
1169 | "sleep": "6.1.0"
1170 | }
1171 | },
1172 | "node_modules/y18n": {
1173 | "version": "5.0.8",
1174 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
1175 | "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
1176 | "license": "ISC",
1177 | "engines": {
1178 | "node": ">=10"
1179 | }
1180 | },
1181 | "node_modules/yargs": {
1182 | "version": "17.7.2",
1183 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
1184 | "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
1185 | "license": "MIT",
1186 | "dependencies": {
1187 | "cliui": "^8.0.1",
1188 | "escalade": "^3.1.1",
1189 | "get-caller-file": "^2.0.5",
1190 | "require-directory": "^2.1.1",
1191 | "string-width": "^4.2.3",
1192 | "y18n": "^5.0.5",
1193 | "yargs-parser": "^21.1.1"
1194 | },
1195 | "engines": {
1196 | "node": ">=12"
1197 | }
1198 | },
1199 | "node_modules/yargs-parser": {
1200 | "version": "21.1.1",
1201 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
1202 | "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
1203 | "license": "ISC",
1204 | "engines": {
1205 | "node": ">=12"
1206 | }
1207 | },
1208 | "node_modules/yauzl": {
1209 | "version": "2.10.0",
1210 | "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
1211 | "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
1212 | "license": "MIT",
1213 | "dependencies": {
1214 | "buffer-crc32": "~0.2.3",
1215 | "fd-slicer": "~1.1.0"
1216 | }
1217 | },
1218 | "node_modules/zod": {
1219 | "version": "3.23.8",
1220 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
1221 | "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
1222 | "license": "MIT",
1223 | "funding": {
1224 | "url": "https://github.com/sponsors/colinhacks"
1225 | }
1226 | }
1227 | }
1228 | }
1229 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "puppeteer-real-browser",
3 | "version": "1.4.2",
4 | "description": "This package is designed to bypass puppeteer's bot-detecting captchas such as Cloudflare. It acts like a real browser and can be managed with puppeteer.",
5 | "main": "lib/cjs/index.js",
6 | "module": "lib/esm/index.mjs",
7 | "exports": {
8 | ".": {
9 | "require": "./lib/cjs/index.js",
10 | "import": "./lib/esm/index.mjs",
11 | "types": "./typings.d.ts"
12 | }
13 | },
14 | "typings": "typings.d.ts",
15 | "scripts": {
16 | "esm_test": "node ./test/esm/test.js",
17 | "cjs_test": "node ./test/cjs/test.js"
18 | },
19 | "keywords": [
20 | "cf-bypass",
21 | "cloudflare-bypass",
22 | "puppeteer-fingerprint",
23 | "puppeteer-cloudflare",
24 | "puppeteer-real-browser",
25 | "undetectable-puppeteer",
26 | "undetect",
27 | "undetectable",
28 | "puppeteer-undetectable",
29 | "puppeteer-undetect",
30 | "puppeteer-undetectable-bypass",
31 | "puppeteer-undetect-bypass",
32 | "puppeteer-undetectable-cloudflare",
33 | "puppeteer-undetect-cloudflare",
34 | "puppeteer-undetectable-cf",
35 | "puppeteer-undetect-cf",
36 | "puppeteer-undetectable-cf-bypass"
37 | ],
38 | "author": "zfc-software",
39 | "license": "ISC",
40 | "dependencies": {
41 | "chrome-launcher": "^1.1.2",
42 | "ghost-cursor": "^1.3.0",
43 | "puppeteer-extra": "^3.3.6",
44 | "rebrowser-puppeteer-core": "^23.3.1",
45 | "tree-kill": "^1.2.2",
46 | "xvfb": "^0.4.0"
47 | },
48 | "repository": {
49 | "type": "git",
50 | "url": "https://github.com/zfcsoftware/puppeteer-real-browser"
51 | },
52 | "readme": "README.md",
53 | "homepage": "https://github.com/zfcsoftware/puppeteer-real-browser"
54 | }
55 |
--------------------------------------------------------------------------------
/test/cjs/test.js:
--------------------------------------------------------------------------------
1 | const test = require('node:test');
2 | const assert = require('node:assert');
3 | const { connect } = require('../../lib/cjs/index.js');
4 |
5 |
6 | const realBrowserOption = {
7 | args: ["--start-maximized"],
8 | turnstile: true,
9 | headless: false,
10 | // disableXvfb: true,
11 | customConfig: {},
12 | connectOption: {
13 | defaultViewport: null
14 | },
15 | plugins: []
16 | }
17 |
18 | // test('Puppeteer Extra Plugin', async () => {
19 | // /*
20 | // Run with:
21 | // npm i puppeteer-extra-plugin-click-and-wait
22 | // */
23 | // realBrowserOption.plugins = [
24 | // require('puppeteer-extra-plugin-click-and-wait')()
25 | // ]
26 | // const { page, browser } = await connect(realBrowserOption)
27 | // await page.goto("https://google.com", { waitUntil: "domcontentloaded" })
28 | // await page.clickAndWaitForNavigation('body')
29 | // await browser.close()
30 | // })
31 |
32 | test('DrissionPage Detector', async () => {
33 | const { page, browser } = await connect(realBrowserOption)
34 | await page.goto("https://web.archive.org/web/20240913054632/https://drissionpage.pages.dev/");
35 | await page.realClick("#detector")
36 | let result = await page.evaluate(() => { return document.querySelector('#isBot span').textContent.includes("not") ? true : false })
37 | await browser.close()
38 | assert.strictEqual(result, true, "DrissionPage Detector test failed!")
39 | })
40 |
41 | test('Brotector, a webdriver detector', async () => {
42 | const { page, browser } = await connect(realBrowserOption)
43 | await page.goto("https://kaliiiiiiiiii.github.io/brotector/");
44 | await new Promise(r => setTimeout(r, 3000));
45 | let result = await page.evaluate(() => { return document.querySelector('#table-keys').getAttribute('bgcolor') })
46 | await browser.close()
47 | assert.strictEqual(result === "darkgreen", true, "Brotector, a webdriver detector test failed!")
48 | })
49 |
50 | test('Cloudflare WAF', async () => {
51 | const { page, browser } = await connect(realBrowserOption)
52 | await page.goto("https://nopecha.com/demo/cloudflare");
53 | let verify = null
54 | let startDate = Date.now()
55 | while (!verify && (Date.now() - startDate) < 30000) {
56 | verify = await page.evaluate(() => { return document.querySelector('.link_row') ? true : null }).catch(() => null)
57 | await new Promise(r => setTimeout(r, 1000));
58 | }
59 | await browser.close()
60 | assert.strictEqual(verify === true, true, "Cloudflare WAF test failed!")
61 | })
62 |
63 |
64 | test('Cloudflare Turnstile', async () => {
65 | const { page, browser } = await connect(realBrowserOption)
66 | await page.goto("https://turnstile.zeroclover.io/");
67 | await page.waitForSelector('[type="submit"]')
68 | let token = null
69 | let startDate = Date.now()
70 | while (!token && (Date.now() - startDate) < 30000) {
71 | token = await page.evaluate(() => {
72 | try {
73 | let item = document.querySelector('[name="cf-turnstile-response"]').value
74 | return item && item.length > 20 ? item : null
75 | } catch (e) {
76 | return null
77 | }
78 | })
79 | await new Promise(r => setTimeout(r, 1000));
80 | }
81 | await browser.close()
82 | // if (token !== null) console.log('Cloudflare Turnstile Token: ' + token);
83 | assert.strictEqual(token !== null, true, "Cloudflare turnstile test failed!")
84 | })
85 |
86 |
87 | test('Fingerprint JS Bot Detector', async () => {
88 | const { page, browser } = await connect(realBrowserOption)
89 | await page.goto("https://fingerprint.com/products/bot-detection/");
90 | await new Promise(r => setTimeout(r, 5000));
91 | const detect = await page.evaluate(() => {
92 | return document.querySelector('.HeroSection-module--botSubTitle--2711e').textContent.includes("not") ? true : false
93 | })
94 | await browser.close()
95 | assert.strictEqual(detect, true, "Fingerprint JS Bot Detector test failed!")
96 | })
97 |
98 |
99 | // If you fail this test, your ip address probably has a high spam score. Please use a mobile or clean ip address.
100 | test('Datadome Bot Detector', async (t) => {
101 | const { page, browser } = await connect(realBrowserOption)
102 | await page.goto("https://antoinevastel.com/bots/datadome");
103 | const check = await page.waitForSelector('nav #navbarCollapse').catch(() => null)
104 | await browser.close()
105 | assert.strictEqual(check ? true : false, true, "Datadome Bot Detector test failed! [This may also be because your ip address has a high spam score. Please try with a clean ip address.]")
106 | })
107 |
108 | // If this test fails, please first check if you can access https://antcpt.com/score_detector/
109 | test('Recaptcha V3 Score (hard)', async () => {
110 | const { page, browser } = await connect(realBrowserOption)
111 | await page.goto("https://antcpt.com/score_detector/");
112 | await page.realClick("button")
113 | await new Promise(r => setTimeout(r, 5000));
114 | const score = await page.evaluate(() => {
115 | return document.querySelector('big').textContent.replace(/[^0-9.]/g, '')
116 | })
117 | await browser.close()
118 | // if (Number(score) >= 0.7) console.log('Recaptcha V3 Score: ' + score);
119 | assert.strictEqual(Number(score) >= 0.7, true, "(please first check if you can access https://antcpt.com/score_detector/.) Recaptcha V3 Score (hard) should be >=0.7. Score Result: " + score)
120 | })
--------------------------------------------------------------------------------
/test/esm/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test",
3 | "type": "module",
4 | "version": "1.0.0",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "description": ""
13 | }
14 |
--------------------------------------------------------------------------------
/test/esm/test.js:
--------------------------------------------------------------------------------
1 | import test from 'node:test';
2 | import assert from 'node:assert';
3 | import { connect } from '../../lib/esm/index.mjs';
4 |
5 | const realBrowserOption = {
6 | args: ["--start-maximized"],
7 | turnstile: true,
8 | headless: false,
9 | // disableXvfb: true,
10 | // ignoreAllFlags:true,
11 | customConfig: {},
12 | connectOption: {
13 | defaultViewport: null
14 | },
15 | plugins: []
16 | }
17 |
18 |
19 | // test('Puppeteer Extra Plugin', async () => {
20 | // /*
21 | // Run with:
22 | // npm i puppeteer-extra-plugin-click-and-wait
23 | // */
24 | // const clickAndWait = await (await import('puppeteer-extra-plugin-click-and-wait')).default
25 | // realBrowserOption.plugins = [
26 | // clickAndWait()
27 | // ]
28 | // const { page, browser } = await connect(realBrowserOption)
29 | // await page.goto("https://google.com", { waitUntil: "domcontentloaded" })
30 | // await page.clickAndWaitForNavigation('body')
31 | // await browser.close()
32 | // })
33 |
34 | test('DrissionPage Detector', async () => {
35 | const { page, browser } = await connect(realBrowserOption)
36 | await page.goto("https://web.archive.org/web/20240913054632/https://drissionpage.pages.dev/");
37 | await page.realClick("#detector")
38 | let result = await page.evaluate(() => { return document.querySelector('#isBot span').textContent.includes("not") ? true : false })
39 | await browser.close()
40 | assert.strictEqual(result, true, "DrissionPage Detector test failed!")
41 | })
42 |
43 | test('Brotector, a webdriver detector', async () => {
44 | const { page, browser } = await connect(realBrowserOption)
45 | await page.goto("https://kaliiiiiiiiii.github.io/brotector/");
46 | await new Promise(r => setTimeout(r, 3000));
47 | let result = await page.evaluate(() => { return document.querySelector('#table-keys').getAttribute('bgcolor') })
48 | await browser.close()
49 | assert.strictEqual(result === "darkgreen", true, "Brotector, a webdriver detector test failed!")
50 | })
51 |
52 | test('Cloudflare WAF', async () => {
53 | const { page, browser } = await connect(realBrowserOption)
54 | await page.goto("https://nopecha.com/demo/cloudflare");
55 | let verify = null
56 | let startDate = Date.now()
57 | while (!verify && (Date.now() - startDate) < 30000) {
58 | verify = await page.evaluate(() => { return document.querySelector('.link_row') ? true : null }).catch(() => null)
59 | await new Promise(r => setTimeout(r, 1000));
60 | }
61 | await browser.close()
62 | assert.strictEqual(verify === true, true, "Cloudflare WAF test failed!")
63 | })
64 |
65 |
66 | test('Cloudflare Turnstile', async () => {
67 | const { page, browser } = await connect(realBrowserOption)
68 | await page.goto("https://turnstile.zeroclover.io/");
69 | await page.waitForSelector('[type="submit"]')
70 | let token = null
71 | let startDate = Date.now()
72 | while (!token && (Date.now() - startDate) < 30000) {
73 | token = await page.evaluate(() => {
74 | try {
75 | let item = document.querySelector('[name="cf-turnstile-response"]').value
76 | return item && item.length > 20 ? item : null
77 | } catch (e) {
78 | return null
79 | }
80 | })
81 | await new Promise(r => setTimeout(r, 1000));
82 | }
83 | await browser.close()
84 | // if (token !== null) console.log('Cloudflare Turnstile Token: ' + token);
85 | assert.strictEqual(token !== null, true, "Cloudflare turnstile test failed!")
86 | })
87 |
88 |
89 |
90 | test('Fingerprint JS Bot Detector', async () => {
91 | const { page, browser } = await connect(realBrowserOption)
92 | await page.goto("https://fingerprint.com/products/bot-detection/");
93 | await new Promise(r => setTimeout(r, 5000));
94 | const detect = await page.evaluate(() => {
95 | return document.querySelector('.HeroSection-module--botSubTitle--2711e').textContent.includes("not") ? true : false
96 | })
97 | await browser.close()
98 | assert.strictEqual(detect, true, "Fingerprint JS Bot Detector test failed!")
99 | })
100 |
101 |
102 | // If you fail this test, your ip address probably has a high spam score. Please use a mobile or clean ip address.
103 | test('Datadome Bot Detector', async (t) => {
104 | const { page, browser } = await connect(realBrowserOption)
105 | await page.goto("https://antoinevastel.com/bots/datadome");
106 | const check = await page.waitForSelector('nav #navbarCollapse').catch(() => null)
107 | await browser.close()
108 | assert.strictEqual(check ? true : false, true, "Datadome Bot Detector test failed! [This may also be because your ip address has a high spam score. Please try with a clean ip address.]")
109 | })
110 |
111 | // If this test fails, please first check if you can access https://antcpt.com/score_detector/
112 | test('Recaptcha V3 Score (hard)', async () => {
113 | const { page, browser } = await connect(realBrowserOption)
114 | await page.goto("https://antcpt.com/score_detector/");
115 | await page.realClick("button")
116 | await new Promise(r => setTimeout(r, 5000));
117 | const score = await page.evaluate(() => {
118 | return document.querySelector('big').textContent.replace(/[^0-9.]/g, '')
119 | })
120 | await browser.close()
121 | // if (Number(score) >= 0.7) console.log('Recaptcha V3 Score: ' + score);
122 | assert.strictEqual(Number(score) >= 0.7, true, "(please first check if you can access https://antcpt.com/score_detector/.) Recaptcha V3 Score (hard) should be >=0.7. Score Result: " + score)
123 | })
--------------------------------------------------------------------------------
/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare module "puppeteer-real-browser" {
2 | import type { Browser, Page } from "rebrowser-puppeteer-core";
3 | import type { GhostCursor } from "ghost-cursor";
4 |
5 | export function connect(options: Options): Promise;
6 |
7 | interface PageWithCursor extends Page {
8 | realClick: GhostCursor["click"];
9 | realCursor: GhostCursor;
10 | }
11 |
12 | type ConnectResult = {
13 | browser: Browser;
14 | page: PageWithCursor;
15 | };
16 |
17 | interface Options {
18 | args?: string[];
19 | headless?: boolean;
20 | customConfig?: import("chrome-launcher").Options;
21 | proxy?: ProxyOptions;
22 | turnstile?: boolean;
23 | connectOption?: import("rebrowser-puppeteer-core").ConnectOptions;
24 | disableXvfb?: boolean;
25 | plugins?: import("puppeteer-extra").PuppeteerExtraPlugin[];
26 | ignoreAllFlags?: boolean;
27 | }
28 |
29 | interface ProxyOptions {
30 | host: string;
31 | port: number;
32 | username?: string;
33 | password?: string;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------