diff --git a/.github/workflows/publish-to-npm-on-tag.yml b/.github/workflows/publish-to-npm-on-tag.yml index 41220ee3d..eba37fb94 100644 --- a/.github/workflows/publish-to-npm-on-tag.yml +++ b/.github/workflows/publish-to-npm-on-tag.yml @@ -3,20 +3,15 @@ name: publish-on-tag on: push: tags: - - 'chrome-devtools-mcp-v*' + - 'v*' workflow_dispatch: inputs: npm-publish: description: 'Try to publish to NPM' default: false type: boolean - mcp-publish: - description: 'Try to publish to MCP registry' - default: true - type: boolean permissions: - id-token: write # Required for OIDC contents: read jobs: @@ -49,45 +44,6 @@ jobs: NODE_ENV: 'production' - name: Publish - run: | - npm publish --provenance --access public - - publish-to-mcp-registry: - runs-on: ubuntu-latest - needs: publish-to-npm - if: ${{ (github.event_name != 'workflow_dispatch' && needs.publish-to-npm.result == 'success') || (inputs.mcp-publish && always()) }} - steps: - - name: Check out repository - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1 - with: - fetch-depth: 2 - - - name: Set up Node.js - uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0 - with: - cache: npm - node-version-file: '.nvmrc' - registry-url: 'https://registry.npmjs.org' - - # Ensure npm 11.5.1 or later is installed - - name: Update npm - run: npm install -g npm@latest - - - name: Install dependencies - run: npm ci - - - name: Build and bundle - run: npm run bundle + run: npm publish --access public env: - NODE_ENV: 'production' - - - name: Install MCP Publisher - run: | - export OS=$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') - curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_${OS}.tar.gz" | tar xz mcp-publisher - - - name: Login to MCP Registry - run: ./mcp-publisher login github-oidc - - - name: Publish to MCP Registry - run: ./mcp-publisher publish + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml.disabled similarity index 100% rename from .github/workflows/release-please.yml rename to .github/workflows/release-please.yml.disabled diff --git a/.gitignore b/.gitignore index 6043309f0..8d734fd2c 100644 --- a/.gitignore +++ b/.gitignore @@ -145,4 +145,6 @@ build/ log.txt -.DS_Store \ No newline at end of file +.DS_Store +.bin +.reports \ No newline at end of file diff --git a/README.md b/README.md index ea6ada5f6..257d23137 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,18 @@ -# Chrome DevTools MCP +# Chrome DevTools MCP - Enhanced by NIMBUS21 -[![npm chrome-devtools-mcp package](https://img.shields.io/npm/v/chrome-devtools-mcp.svg)](https://npmjs.org/package/chrome-devtools-mcp) +[![npm @nimbus21.ai/chrome-devtools-mcp package](https://img.shields.io/npm/v/@nimbus21.ai/chrome-devtools-mcp.svg)](https://npmjs.org/package/@nimbus21.ai/chrome-devtools-mcp) -`chrome-devtools-mcp` lets your coding agent (such as Gemini, Claude, Cursor or Copilot) +> **Note:** This is an **unofficial community-maintained fork** of the original Chrome DevTools MCP server, enhanced and modified by the **NIMBUS21 Team**. This package is not affiliated with or endorsed by Google or the Chrome DevTools team. + +## 🚀 Powered by NIMBUS21 + +This enhanced version is brought to you by **[NIMBUS21](https://nimbus21.com)** - a leading technology innovation company specializing in AI-powered automation, browser automation solutions, and enterprise software development. Visit [nimbus21.ai](https://nimbus21.ai) to explore our cutting-edge AI tools, automation platforms, and developer services. + +**NIMBUS21** delivers advanced browser automation frameworks, intelligent testing solutions, and AI-driven development tools for modern web applications. Our expertise in Chrome automation, DevTools integration, and Model Context Protocol (MCP) implementations helps developers and enterprises build more reliable, performant, and intelligent software solutions. + +--- + +`@nimbus21.ai/chrome-devtools-mcp` lets your coding agent (such as Gemini, Claude, Cursor or Copilot) control and inspect a live Chrome browser. It acts as a Model-Context-Protocol (MCP) server, giving your AI coding assistant access to the full power of Chrome DevTools for reliable automation, in-depth debugging, and performance analysis. @@ -42,14 +52,14 @@ Add the following config to your MCP client: "mcpServers": { "chrome-devtools": { "command": "npx", - "args": ["-y", "chrome-devtools-mcp@latest"] + "args": ["-y", "@nimbus21.ai/chrome-devtools-mcp@latest"] } } } ``` -> [!NOTE] -> Using `chrome-devtools-mcp@latest` ensures that your MCP client will always use the latest version of the Chrome DevTools MCP server. +> [!NOTE] +> Using `@nimbus21.ai/chrome-devtools-mcp@latest` ensures that your MCP client will always use the latest version of the NIMBUS21-enhanced Chrome DevTools MCP server. ### MCP Client configuration @@ -94,7 +104,7 @@ Chrome DevTools MCP will not start the browser instance automatically using this Use the Claude Code CLI to add the Chrome DevTools MCP server (guide): ```bash -claude mcp add chrome-devtools npx chrome-devtools-mcp@latest +claude mcp add chrome-devtools npx @nimbus21.ai/chrome-devtools-mcp@latest ``` @@ -110,7 +120,7 @@ claude mcp add chrome-devtools npx chrome-devtools-mcp@latest using the standard config from above. You can also install the Chrome DevTools MCP server using the Codex CLI: ```bash -codex mcp add chrome-devtools -- npx chrome-devtools-mcp@latest +codex mcp add chrome-devtools -- npx @nimbus21.ai/chrome-devtools-mcp@latest ``` **On Windows 11** @@ -124,7 +134,7 @@ args = [ "/c", "npx", "-y", - "chrome-devtools-mcp@latest", + "@nimbus21.ai/chrome-devtools-mcp@latest", ] env = { SystemRoot="C:\\Windows", PROGRAMFILES="C:\\Program Files" } startup_timeout_ms = 20_000 @@ -151,26 +161,19 @@ Configure the following fields and press `CTRL+S` to save the configuration: - **Server name:** `chrome-devtools` - **Server Type:** `[1] Local` -- **Command:** `npx -y chrome-devtools-mcp@latest` +- **Command:** `npx` +- **Arguments:** `-y, @nimbus21.ai/chrome-devtools-mcp@latest`
Copilot / VS Code -**Click the button to install:** - -[Install in VS Code](https://vscode.dev/redirect/mcp/install?name=io.github.ChromeDevTools%2Fchrome-devtools-mcp&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22chrome-devtools-mcp%22%5D%2C%22env%22%3A%7B%7D%7D) - -[Install in VS Code Insiders](https://insiders.vscode.dev/redirect?url=vscode-insiders%3Amcp%2Finstall%3F%257B%2522name%2522%253A%2522io.github.ChromeDevTools%252Fchrome-devtools-mcp%2522%252C%2522config%2522%253A%257B%2522command%2522%253A%2522npx%2522%252C%2522args%2522%253A%255B%2522-y%2522%252C%2522chrome-devtools-mcp%2522%255D%252C%2522env%2522%253A%257B%257D%257D%257D) - -**Or install manually:** - Follow the MCP install guide, with the standard config from above. You can also install the Chrome DevTools MCP server using the VS Code CLI: ```bash -code --add-mcp '{"name":"io.github.ChromeDevTools/chrome-devtools-mcp","command":"npx","args":["-y","chrome-devtools-mcp"],"env":{}}' +code --add-mcp '{"name":"chrome-devtools","command":"npx","args":["@nimbus21.ai/chrome-devtools-mcp@latest"]}' ```
@@ -180,7 +183,7 @@ code --add-mcp '{"name":"io.github.ChromeDevTools/chrome-devtools-mcp","command" **Click the button to install:** -[Install in Cursor](https://cursor.com/en/install-mcp?name=chrome-devtools&config=eyJjb21tYW5kIjoibnB4IC15IGNocm9tZS1kZXZ0b29scy1tY3BAbGF0ZXN0In0%3D) +[Install in Cursor](https://cursor.com/en/install-mcp?name=chrome-devtools&config=eyJjb21tYW5kIjoibnB4IC15IEBuaW1idXMyMS5haS9jaHJvbWUtZGV2dG9vbHMtbWNwQGxhdGVzdCJ9) **Or install manually:** @@ -205,13 +208,13 @@ Install the Chrome DevTools MCP server using the Gemini CLI. **Project wide:** ```bash -gemini mcp add chrome-devtools npx chrome-devtools-mcp@latest +gemini mcp add chrome-devtools npx @nimbus21.ai/chrome-devtools-mcp@latest ``` **Globally:** ```bash -gemini mcp add -s user chrome-devtools npx chrome-devtools-mcp@latest +gemini mcp add -s user chrome-devtools npx @nimbus21.ai/chrome-devtools-mcp@latest ``` Alternatively, follow the MCP guide and use the standard config from above. @@ -274,7 +277,7 @@ qodercli mcp add -s user chrome-devtools -- npx chrome-devtools-mcp@latest **Click the button to install:** - [Install in Visual Studio](https://vs-open.link/mcp-install?%7B%22name%22%3A%22chrome-devtools%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22chrome-devtools-mcp%40latest%22%5D%7D) + [Install in Visual Studio](https://vs-open.link/mcp-install?%7B%22name%22%3A%22chrome-devtools%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22@nimbus21.ai/chrome-devtools-mcp%40latest%22%5D%7D)
@@ -434,7 +437,7 @@ Pass them via the `args` property in the JSON configuration. For example: "chrome-devtools": { "command": "npx", "args": [ - "chrome-devtools-mcp@latest", + "@nimbus21.ai/chrome-devtools-mcp@latest", "--channel=canary", "--headless=true", "--isolated=true" @@ -454,7 +457,7 @@ You can connect directly to a Chrome WebSocket endpoint and include custom heade "chrome-devtools": { "command": "npx", "args": [ - "chrome-devtools-mcp@latest", + "@nimbus21.ai/chrome-devtools-mcp@latest", "--wsEndpoint=ws://127.0.0.1:9222/devtools/browser/", "--wsHeaders={\"Authorization\":\"Bearer YOUR_TOKEN\"}" ] @@ -465,7 +468,7 @@ You can connect directly to a Chrome WebSocket endpoint and include custom heade To get the WebSocket endpoint from a running Chrome instance, visit `http://127.0.0.1:9222/json/version` and look for the `webSocketDebuggerUrl` field. -You can also run `npx chrome-devtools-mcp@latest --help` to see all available configuration options. +You can also run `npx @nimbus21.ai/chrome-devtools-mcp@latest --help` to see all available configuration options. ## Concepts diff --git a/STEALTH_FEATURES.md b/STEALTH_FEATURES.md new file mode 100644 index 000000000..bb79c6aa8 --- /dev/null +++ b/STEALTH_FEATURES.md @@ -0,0 +1,153 @@ +# Stealth Mode Features + +This fork of Chrome DevTools MCP adds **stealth mode** capabilities to bypass bot detection on websites. + +## New Features + +### 1. **Stealth Mode** (`--stealth`) +Enables puppeteer-extra-plugin-stealth and adds anti-detection Chrome arguments to make browser automation undetectable. + +**What it does:** +- Uses `puppeteer-extra` with `puppeteer-extra-plugin-stealth` plugin +- Removes automation-related Chrome arguments +- Adds anti-detection Chrome flags: + - `--disable-blink-features=AutomationControlled` + - `--disable-features=IsolateOrigins,site-per-process` + - `--no-first-run` + - `--no-service-autorun` + - `--password-store=basic` +- Removes `--enable-automation` flag + +### 2. **Custom Chrome Arguments** (`--chromeArgs`) +Pass any additional Chrome command-line arguments (comma-separated). + +## Usage + +### Basic Stealth Mode +```bash +npx chrome-devtools-mcp@latest --stealth +``` + +### Stealth Mode with Custom Chrome Arguments +```bash +npx chrome-devtools-mcp@latest --stealth --chromeArgs="--window-size=1920,1080,--user-agent=CustomAgent" +``` + +### Only Custom Arguments (without stealth plugin) +```bash +npx chrome-devtools-mcp@latest --chromeArgs="--disable-gpu,--no-sandbox" +``` + +## MCP Configuration + +### Claude Code +```bash +claude mcp add chrome-stealth npx chrome-devtools-mcp@latest -- --stealth +``` + +Or manually edit `.claude/config.json`: +```json +{ + "mcpServers": { + "chrome-stealth": { + "command": "npx", + "args": [ + "chrome-devtools-mcp@latest", + "--stealth" + ] + } + } +} +``` + +### With Custom Chrome Args +```json +{ + "mcpServers": { + "chrome-stealth": { + "command": "npx", + "args": [ + "chrome-devtools-mcp@latest", + "--stealth", + "--chromeArgs=--window-size=1920,1080" + ] + } + } +} +``` + +### With Chromium Path +```json +{ + "mcpServers": { + "chrome-stealth": { + "command": "npx", + "args": [ + "chrome-devtools-mcp@latest", + "--stealth", + "--executablePath", + "/usr/bin/chromium" + ] + } + } +} +``` + +## Technical Details + +### Modified Files +- `package.json` - Added `puppeteer-extra` and `puppeteer-extra-plugin-stealth` dependencies +- `src/browser.ts` - Added stealth mode logic and custom Chrome args support +- `src/cli.ts` - Added `--stealth` and `--chromeArgs` CLI options +- `src/main.ts` - Pass stealth options to browser launcher + +### How Stealth Mode Works +1. **Puppeteer-Extra Plugin**: Uses `puppeteer-extra-plugin-stealth` which applies dozens of evasion techniques: + - Removes `navigator.webdriver` flag + - Masks Chrome headless detection + - Fixes `navigator.plugins` and `navigator.languages` + - Spoofs WebGL vendor/renderer + - And many more... + +2. **Chrome Flags**: Adds critical anti-detection flags: + - `--disable-blink-features=AutomationControlled` - Removes automation indicators + - `ignoreDefaultArgs: ['--enable-automation']` - Prevents automation flag + +3. **Conditional**: Only uses puppeteer-extra when stealth is enabled, otherwise uses standard puppeteer-core for better performance + +## Testing + +Test stealth mode on bot-protected sites: +```bash +# Navigate to bot-protected site +npx chrome-devtools-mcp@latest --stealth + +# Then use the MCP tools to navigate to sites like: +# - https://2nabiji.ge +# - https://bot.sannysoft.com +# - https://arh.antoinevastel.com/bots/areyouheadless +``` + +## Comparison with Standard Chrome DevTools MCP + +| Feature | Standard | With Stealth | +|---------|----------|--------------| +| Bot Detection | ❌ Detected | ✅ Bypassed | +| Performance | Fast | Slightly slower | +| Dependencies | puppeteer-core | + puppeteer-extra | +| Use Case | Development/Testing | Bot-protected sites | + +## Use Cases + +- **E-commerce scraping**: Access sites with Cloudflare or similar protection +- **Price monitoring**: Automated price checking without detection +- **Testing**: Test how your site appears to real users vs bots +- **Research**: Access data from protected sources + +## Credits + +Stealth implementation based on: +- [puppeteer-extra](https://github.com/berstend/puppeteer-extra) +- [puppeteer-extra-plugin-stealth](https://github.com/berstend/puppeteer-extra/tree/master/packages/puppeteer-extra-plugin-stealth) + +Original Chrome DevTools MCP by Google LLC / Chrome DevTools team. diff --git a/eslint.config.mjs b/eslint.config.mjs index 04882b055..fb0093acd 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -14,7 +14,7 @@ import tseslint from 'typescript-eslint'; import localPlugin from './scripts/eslint_rules/local-plugin.js'; export default defineConfig([ - globalIgnores(['**/node_modules', '**/build/']), + globalIgnores(['**/node_modules', '**/build/', 'scripts/prepare.js', 'scripts/post-build.js']), importPlugin.flatConfigs.typescript, { languageOptions: { diff --git a/package-lock.json b/package-lock.json index 3c158d688..b1ec0224b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,17 @@ { - "name": "chrome-devtools-mcp", + "name": "@nimbus21.ai/chrome-devtools-mcp", "version": "0.12.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "chrome-devtools-mcp", + "name": "@nimbus21.ai/chrome-devtools-mcp", "version": "0.12.1", "license": "Apache-2.0", + "dependencies": { + "puppeteer-extra": "^3.3.6", + "puppeteer-extra-plugin-stealth": "^2.11.2" + }, "bin": { "chrome-devtools-mcp": "build/src/index.js" }, @@ -50,7 +54,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", @@ -65,7 +69,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -458,7 +462,7 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.11.0.tgz", "integrity": "sha512-n6oQX6mYkG8TRPuPXmbPidkUbsSRalhmaaVAQxvH1IkQy63cwsH+kOjB3e4cpCDHg0aSvsiX9bQ4s2VB6mGWUQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "debug": "^4.4.3", @@ -480,7 +484,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -490,7 +494,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -505,14 +509,14 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@puppeteer/browsers/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -527,7 +531,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -540,7 +544,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -558,7 +562,7 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "cliui": "^8.0.1", @@ -577,7 +581,7 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, + "devOptional": true, "license": "ISC", "engines": { "node": ">=12" @@ -1060,7 +1064,7 @@ "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tybys/wasm-util": { @@ -1078,7 +1082,6 @@ "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/ms": "*" @@ -1126,7 +1129,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "dev": true, "license": "MIT" }, "node_modules/@types/node": { @@ -1226,7 +1228,6 @@ "integrity": "sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.49.0", "@typescript-eslint/types": "8.49.0", @@ -1701,7 +1702,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1723,7 +1723,7 @@ "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 14" @@ -1805,7 +1805,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -1821,9 +1821,18 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, + "devOptional": true, "license": "Python-2.0" }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/array-buffer-byte-length": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", @@ -1960,7 +1969,7 @@ "version": "0.13.4", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "tslib": "^2.0.1" @@ -1999,7 +2008,7 @@ "version": "1.7.3", "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.3.tgz", "integrity": "sha512-5Q2mfq2WfGuFp3uS//0s6baOJLMoVduPYVeNmDYxu5OUA1/cBfvr2RIS7vi62LdNj/urk1hfmj867I3qt6uZ7Q==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "peerDependencies": { "react-native-b4a": "*" @@ -2014,14 +2023,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, "license": "MIT" }, "node_modules/bare-events": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz", "integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "peerDependencies": { "bare-abort-controller": "*" @@ -2118,7 +2126,7 @@ "version": "5.0.5", "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -2163,7 +2171,7 @@ "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": "*" @@ -2233,7 +2241,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -2267,7 +2275,7 @@ "version": "11.0.0", "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-11.0.0.tgz", "integrity": "sha512-cM3DI+OOb89T3wO8cpPSro80Q9eKYJ7hGVXoGS3GkDPxnYSqiv+6xwpIf6XERyJ9Tdsl09hmNmY94BkgZdVekw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "mitt": "^3.0.1", @@ -2292,11 +2300,27 @@ "node": ">=20" } }, + "node_modules/clone-deep": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", + "integrity": "sha512-we+NuQo2DHhSl+DP6jlUiAhyAjBQrYnpOk15rN6c6JSPScjiCLh8IbSU+VTcph6YS3o7mASE8a0+gbZ7ChLpgg==", + "license": "MIT", + "dependencies": { + "for-own": "^0.1.3", + "is-plain-object": "^2.0.1", + "kind-of": "^3.0.2", + "lazy-cache": "^1.0.3", + "shallow-clone": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -2309,7 +2333,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/commenting": { @@ -2330,7 +2354,6 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, "license": "MIT" }, "node_modules/content-disposition": { @@ -2406,7 +2429,7 @@ "version": "9.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "env-paths": "^2.2.1", @@ -2448,7 +2471,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 14" @@ -2512,7 +2535,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -2537,7 +2559,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2583,7 +2604,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ast-types": "^0.13.4", @@ -2608,9 +2629,8 @@ "version": "0.0.1534754", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1534754.tgz", "integrity": "sha512-26T91cV5dbOYnXdJi5qQHoTtUoNEqwkHcAyu/IKtjIAxiEqPMrDiRkDOPWVsGfNZGmlQVHQbZRSjD8sxagWVsQ==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true + "devOptional": true, + "license": "BSD-3-Clause" }, "node_modules/diff": { "version": "7.0.0", @@ -2678,7 +2698,7 @@ "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "once": "^1.4.0" @@ -2688,7 +2708,7 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -2698,7 +2718,7 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" @@ -2857,7 +2877,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -2887,7 +2907,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", @@ -2911,7 +2931,6 @@ "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -3082,7 +3101,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -3241,7 +3259,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -3281,7 +3299,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -3298,7 +3316,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -3318,7 +3336,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "bare-events": "^2.7.0" @@ -3353,7 +3371,6 @@ "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -3412,7 +3429,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, + "devOptional": true, "license": "BSD-2-Clause", "dependencies": { "debug": "^4.1.1", @@ -3440,7 +3457,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/fast-json-stable-stringify": { @@ -3478,7 +3495,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "pend": "~1.2.0" @@ -3587,6 +3604,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==", + "license": "MIT", + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -3607,6 +3645,26 @@ "node": ">= 0.8" } }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3677,7 +3735,7 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, + "devOptional": true, "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -3739,7 +3797,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "pump": "^3.0.0" @@ -3786,7 +3844,7 @@ "version": "6.0.5", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "basic-ftp": "^5.0.2", @@ -3797,6 +3855,27 @@ "node": ">= 14" } }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -3810,6 +3889,28 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/globals": { "version": "16.5.0", "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", @@ -3853,6 +3954,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, "node_modules/has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", @@ -3968,7 +4075,7 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.0", @@ -3982,7 +4089,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -4023,7 +4130,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -4046,11 +4153,21 @@ "node": ">=0.8.19" } }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, "license": "ISC" }, "node_modules/internal-slot": { @@ -4072,7 +4189,7 @@ "version": "10.1.0", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 12" @@ -4110,7 +4227,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/is-async-function": { @@ -4166,6 +4283,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT" + }, "node_modules/is-bun-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", @@ -4240,6 +4363,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4270,7 +4402,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=8" @@ -4359,6 +4491,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -4535,6 +4679,15 @@ "dev": true, "license": "ISC" }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jose": { "version": "6.1.3", "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz", @@ -4574,14 +4727,14 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -4601,7 +4754,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/json-schema-traverse": { @@ -4631,6 +4784,18 @@ "json5": "lib/cli.js" } }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4641,6 +4806,27 @@ "json-buffer": "3.0.1" } }, + "node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4659,7 +4845,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/locate-path": { @@ -4696,7 +4882,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, + "devOptional": true, "license": "ISC", "engines": { "node": ">=12" @@ -4732,6 +4918,20 @@ "node": ">= 0.8" } }, + "node_modules/merge-deep": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.3.tgz", + "integrity": "sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==", + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "clone-deep": "^0.2.4", + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/merge-descriptors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", @@ -4798,9 +4998,31 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "dev": true, + "devOptional": true, "license": "MIT" }, + "node_modules/mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha512-ALGF1Jt9ouehcaXaHhn6t1yGWRqGaHkPFndtFVHfZXOvkIZ/yoGaSi0AHVTafb3ZBGg4dr/bDwnaEKqCXzchMA==", + "license": "MIT", + "dependencies": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-object/node_modules/for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha512-F0to7vbBSHP8E3l6dCjxNOLuSFAACIxFy3UehTUlG7svlXi37HHsDkyVcHo0Pq8QwrE+pXvWSVX3ZT1T9wAZ9g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -4815,7 +5037,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/napi-postinstall": { @@ -4855,7 +5076,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.4.0" @@ -4985,7 +5206,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -5063,7 +5283,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", @@ -5083,7 +5303,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "degenerator": "^5.0.0", @@ -5110,7 +5330,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -5123,7 +5343,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", @@ -5158,6 +5378,15 @@ "node": ">=8" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -5190,7 +5419,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/perf-regexes": { @@ -5207,7 +5436,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/picomatch": { @@ -5273,7 +5502,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -5297,7 +5526,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -5317,14 +5546,14 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/pump": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -5345,7 +5574,7 @@ "version": "24.33.0", "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.33.0.tgz", "integrity": "sha512-nl3wsAztq5F8zybn4Tk41OCnYIzFIzGC6AN0WcF2KCUnWenajvRRPgBmS6LvNUV2HEeIzT2zRZHH0TgVxLDKew==", - "dev": true, + "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -5367,7 +5596,7 @@ "version": "24.33.0", "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.33.0.tgz", "integrity": "sha512-tPTxVg+Qdj/8av4cy6szv3GlhxeOoNhiiMZ955fjxQyvPQE/6DjCa6ZyF/x0WJrlgBZtaLSP8TQgJb7FdLDXXA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "@puppeteer/browsers": "2.11.0", @@ -5382,6 +5611,142 @@ "node": ">=18" } }, + "node_modules/puppeteer-extra": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/puppeteer-extra/-/puppeteer-extra-3.3.6.tgz", + "integrity": "sha512-rsLBE/6mMxAjlLd06LuGacrukP2bqbzKCLzV1vrhHFavqQE/taQ2UXv3H5P0Ls7nsrASa+6x3bDbXHpqMwq+7A==", + "license": "MIT", + "dependencies": { + "@types/debug": "^4.1.0", + "debug": "^4.1.1", + "deepmerge": "^4.2.2" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "@types/puppeteer": "*", + "puppeteer": "*", + "puppeteer-core": "*" + }, + "peerDependenciesMeta": { + "@types/puppeteer": { + "optional": true + }, + "puppeteer": { + "optional": true + }, + "puppeteer-core": { + "optional": true + } + } + }, + "node_modules/puppeteer-extra-plugin": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin/-/puppeteer-extra-plugin-3.2.3.tgz", + "integrity": "sha512-6RNy0e6pH8vaS3akPIKGg28xcryKscczt4wIl0ePciZENGE2yoaQJNd17UiEbdmh5/6WW6dPcfRWT9lxBwCi2Q==", + "license": "MIT", + "dependencies": { + "@types/debug": "^4.1.0", + "debug": "^4.1.1", + "merge-deep": "^3.0.1" + }, + "engines": { + "node": ">=9.11.2" + }, + "peerDependencies": { + "playwright-extra": "*", + "puppeteer-extra": "*" + }, + "peerDependenciesMeta": { + "playwright-extra": { + "optional": true + }, + "puppeteer-extra": { + "optional": true + } + } + }, + "node_modules/puppeteer-extra-plugin-stealth": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-stealth/-/puppeteer-extra-plugin-stealth-2.11.2.tgz", + "integrity": "sha512-bUemM5XmTj9i2ZerBzsk2AN5is0wHMNE6K0hXBzBXOzP5m5G3Wl0RHhiqKeHToe/uIH8AoZiGhc1tCkLZQPKTQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "puppeteer-extra-plugin": "^3.2.3", + "puppeteer-extra-plugin-user-preferences": "^2.4.1" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "playwright-extra": "*", + "puppeteer-extra": "*" + }, + "peerDependenciesMeta": { + "playwright-extra": { + "optional": true + }, + "puppeteer-extra": { + "optional": true + } + } + }, + "node_modules/puppeteer-extra-plugin-user-data-dir": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-user-data-dir/-/puppeteer-extra-plugin-user-data-dir-2.4.1.tgz", + "integrity": "sha512-kH1GnCcqEDoBXO7epAse4TBPJh9tEpVEK/vkedKfjOVOhZAvLkHGc9swMs5ChrJbRnf8Hdpug6TJlEuimXNQ+g==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^10.0.0", + "puppeteer-extra-plugin": "^3.2.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "playwright-extra": "*", + "puppeteer-extra": "*" + }, + "peerDependenciesMeta": { + "playwright-extra": { + "optional": true + }, + "puppeteer-extra": { + "optional": true + } + } + }, + "node_modules/puppeteer-extra-plugin-user-preferences": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/puppeteer-extra-plugin-user-preferences/-/puppeteer-extra-plugin-user-preferences-2.4.1.tgz", + "integrity": "sha512-i1oAZxRbc1bk8MZufKCruCEC3CCafO9RKMkkodZltI4OqibLFXF3tj6HZ4LZ9C5vCXZjYcDWazgtY69mnmrQ9A==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "deepmerge": "^4.2.2", + "puppeteer-extra-plugin": "^3.2.3", + "puppeteer-extra-plugin-user-data-dir": "^2.4.1" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "playwright-extra": "*", + "puppeteer-extra": "*" + }, + "peerDependenciesMeta": { + "playwright-extra": { + "optional": true + }, + "puppeteer-extra": { + "optional": true + } + } + }, "node_modules/qs": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", @@ -5472,7 +5837,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5513,7 +5878,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=4" @@ -5529,13 +5894,28 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rollup": { "version": "4.53.3", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz", "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -5733,7 +6113,7 @@ "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, + "devOptional": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -5837,6 +6217,42 @@ "dev": true, "license": "ISC" }, + "node_modules/shallow-clone": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", + "integrity": "sha512-J1zdXCky5GmNnuauESROVu31MQSnLoYvlyEn6j2Ztk6Q5EHFIhxkMhYcv6vuDzl2XEzoRr856QwzMgWM/TmZgw==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.1", + "kind-of": "^2.0.1", + "lazy-cache": "^0.2.3", + "mixin-object": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shallow-clone/node_modules/kind-of": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "integrity": "sha512-0u8i1NZ/mg0b+W3MGGw5I7+6Eib2nx72S/QvXa0hYjEkjTknYmEYQJwGu3mLC0BrhtJjtQafTkyRUQ75Kx0LVg==", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shallow-clone/node_modules/lazy-cache": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", + "integrity": "sha512-gkX52wvU/R8DVMMt78ATVPFMJqfW8FPz1GZ1sVHBVQHmu/WvhIWE4cE1GBzhJNFicDeYhnwp6Rl35BcAIM3YOQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -5968,7 +6384,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 6.0.0", @@ -5979,7 +6395,7 @@ "version": "2.8.7", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "ip-address": "^10.0.1", @@ -5994,7 +6410,7 @@ "version": "8.0.5", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -6128,7 +6544,7 @@ "version": "2.23.0", "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "events-universal": "^1.0.0", @@ -6282,7 +6698,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz", "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "pump": "^3.0.0", @@ -6297,7 +6713,7 @@ "version": "3.1.7", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "b4a": "^1.6.4", @@ -6309,7 +6725,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "dependencies": { "b4a": "^1.6.4" @@ -6372,7 +6788,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, + "devOptional": true, "license": "0BSD" }, "node_modules/type-check": { @@ -6495,7 +6911,7 @@ "version": "2.12.0", "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/typescript": { @@ -6504,7 +6920,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6563,6 +6978,15 @@ "dev": true, "license": "MIT" }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -6580,7 +7004,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "napi-postinstall": "^0.3.0" }, @@ -6633,7 +7056,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.3.9.tgz", "integrity": "sha512-uIYvlRQ0PwtZR1EzHlTMol1G0lAlmOe6wPykF9a77AK3bkpvZHzIVxRE2ThOx5vjy2zISe0zhwf5rzuUfbo1PQ==", - "dev": true, + "devOptional": true, "license": "Apache-2.0" }, "node_modules/which": { @@ -6786,14 +7209,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, "license": "ISC" }, "node_modules/ws": { "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -6815,7 +7237,7 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, + "devOptional": true, "license": "ISC", "engines": { "node": ">=10" @@ -6853,7 +7275,7 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", @@ -6877,9 +7299,8 @@ "version": "3.25.76", "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "dev": true, + "devOptional": true, "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index d4176f794..8869f3e3a 100644 --- a/package.json +++ b/package.json @@ -1,29 +1,29 @@ { - "name": "chrome-devtools-mcp", + "name": "@nimbus21.ai/chrome-devtools-mcp", "version": "0.12.1", - "description": "MCP server for Chrome DevTools", + "description": "MCP server for Chrome DevTools with stealth mode support", "type": "module", "bin": "./build/src/index.js", "main": "index.js", "scripts": { "clean": "node -e \"require('fs').rmSync('build', {recursive: true, force: true})\"", "bundle": "npm run clean && npm run build && rollup -c rollup.config.mjs && node -e \"require('fs').rmSync('build/node_modules', {recursive: true, force: true})\"", - "build": "tsc && node --experimental-strip-types --no-warnings=ExperimentalWarning scripts/post-build.ts", + "build": "tsc && node build/scripts/post-build.js", "typecheck": "tsc --noEmit", "format": "eslint --cache --fix . && prettier --write --cache .", "check-format": "eslint --cache . && prettier --check --cache .;", "docs": "npm run build && npm run docs:generate && npm run format", - "docs:generate": "node --experimental-strip-types scripts/generate-docs.ts", + "docs:generate": "node build/scripts/generate-docs.js", "start": "npm run build && node build/src/index.js", "start-debug": "DEBUG=mcp:* DEBUG_COLORS=false npm run build && node build/src/index.js", "test:node20": "node --import ./build/tests/setup.js --test-reporter spec --test-force-exit --test build/tests", - "test:no-build": "node --import ./build/tests/setup.js --no-warnings=ExperimentalWarning --experimental-print-required-tla --test-reporter spec --test-force-exit --test \"build/tests/**/*.test.js\"", + "test:no-build": "node --import ./build/tests/setup.js --no-warnings=ExperimentalWarning --test-reporter spec --test-force-exit --test \"build/tests/**/*.test.js\"", "test": "npm run build && npm run test:no-build", "test:only": "npm run build && npm run test:only:no-build", "test:only:no-build": "node --import ./build/tests/setup.js --no-warnings=ExperimentalWarning --test-reporter spec --test-force-exit --test --test-only \"build/tests/**/*.test.js\"", "test:update-snapshots": "npm run build && node --import ./build/tests/setup.js --no-warnings=ExperimentalWarning --test-force-exit --test --test-update-snapshots \"build/tests/**/*.test.js\"", - "prepare": "node --experimental-strip-types scripts/prepare.ts", - "verify-server-json-version": "node --experimental-strip-types scripts/verify-server-json-version.ts" + "prepare": "node scripts/prepare.js", + "verify-server-json-version": "node build/scripts/verify-server-json-version.js" }, "files": [ "build/src", @@ -31,14 +31,18 @@ "LICENSE", "!*.tsbuildinfo" ], - "repository": "ChromeDevTools/chrome-devtools-mcp", - "author": "Google LLC", + "repository": "nimbus21/chrome-devtools-mcp", + "author": "NIMBUS21 (forked from Google LLC)", "license": "Apache-2.0", "bugs": { - "url": "https://github.com/ChromeDevTools/chrome-devtools-mcp/issues" + "url": "https://github.com/nimbus21/chrome-devtools-mcp/issues" + }, + "homepage": "https://github.com/nimbus21/chrome-devtools-mcp#readme", + "mcpName": "io.github.nimbus21/chrome-devtools-mcp", + "dependencies": { + "puppeteer-extra": "^3.3.6", + "puppeteer-extra-plugin-stealth": "^2.11.2" }, - "homepage": "https://github.com/ChromeDevTools/chrome-devtools-mcp#readme", - "mcpName": "io.github.ChromeDevTools/chrome-devtools-mcp", "devDependencies": { "@eslint/js": "^9.35.0", "@modelcontextprotocol/sdk": "1.24.3", diff --git a/scripts/post-build.js b/scripts/post-build.js new file mode 100644 index 000000000..fae22655f --- /dev/null +++ b/scripts/post-build.js @@ -0,0 +1,172 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import tsConfig from '../tsconfig.json' with {type: 'json'}; +const BUILD_DIR = path.join(process.cwd(), 'build'); +/** + * Writes content to a file. + * @param filePath The path to the file. + * @param content The content to write. + */ +function writeFile(filePath, content) { + fs.writeFileSync(filePath, content, 'utf-8'); +} +/** + * Replaces content in a file. + * @param filePath The path to the file. + * @param find The regex to find. + * @param replace The string to replace with. + */ +function sed(filePath, find, replace) { + if (!fs.existsSync(filePath)) { + console.warn(`File not found for sed operation: ${filePath}`); + return; + } + const content = fs.readFileSync(filePath, 'utf-8'); + const newContent = content.replace(find, replace); + fs.writeFileSync(filePath, newContent, 'utf-8'); +} +/** + * Ensures that licenses for third party files we use gets copied into the build/ dir. + */ +function copyThirdPartyLicenseFiles() { + const thirdPartyDirectories = tsConfig.include.filter(location => { + return location.includes( + 'node_modules/chrome-devtools-frontend/front_end/third_party', + ); + }); + for (const thirdPartyDir of thirdPartyDirectories) { + const fullPath = path.join(process.cwd(), thirdPartyDir); + const licenseFile = path.join(fullPath, 'LICENSE'); + if (!fs.existsSync(licenseFile)) { + console.error('No LICENSE for', path.basename(thirdPartyDir)); + } + const destinationDir = path.join(BUILD_DIR, thirdPartyDir); + const destinationFile = path.join(destinationDir, 'LICENSE'); + fs.copyFileSync(licenseFile, destinationFile); + } +} +function main() { + const devtoolsThirdPartyPath = + 'node_modules/chrome-devtools-frontend/front_end/third_party'; + const devtoolsFrontEndCorePath = + 'node_modules/chrome-devtools-frontend/front_end/core'; + // Create i18n mock + const i18nDir = path.join(BUILD_DIR, devtoolsFrontEndCorePath, 'i18n'); + fs.mkdirSync(i18nDir, {recursive: true}); + const i18nFile = path.join(i18nDir, 'i18n.js'); + const i18nContent = ` +export const i18n = { + registerUIStrings: () => {}, + getLocalizedString: (_, str) => { + // So that the string passed in gets output verbatim. + return str; + }, + lockedLazyString: () => {}, + getLazilyComputedLocalizedString: () => {}, +}; + +// TODO(jacktfranklin): once the DocumentLatency insight does not depend on +// this method, we can remove this stub. +export const TimeUtilities = { + millisToString(x) { + const separator = '\xA0'; + const formatter = new Intl.NumberFormat('en-US', { + style: 'unit', + unitDisplay: 'narrow', + minimumFractionDigits: 0, + maximumFractionDigits: 1, + unit: 'millisecond', + }); + + const parts = formatter.formatToParts(x); + for (const part of parts) { + if (part.type === 'literal') { + if (part.value === ' ') { + part.value = separator; + } + } + } + + return parts.map(part => part.value).join(''); + } +}; + +// TODO(jacktfranklin): once the ImageDelivery insight does not depend on this method, we can remove this stub. +export const ByteUtilities = { + bytesToString(x) { + const separator = '\xA0'; + const formatter = new Intl.NumberFormat('en-US', { + style: 'unit', + unit: 'kilobyte', + unitDisplay: 'narrow', + minimumFractionDigits: 1, + maximumFractionDigits: 1, + }); + const parts = formatter.formatToParts(x / 1000); + for (const part of parts) { + if (part.type === 'literal') { + if (part.value === ' ') { + part.value = separator; + } + } + } + + return parts.map(part => part.value).join(''); + } +};`; + writeFile(i18nFile, i18nContent); + // Create codemirror.next mock. + const codeMirrorDir = path.join( + BUILD_DIR, + devtoolsThirdPartyPath, + 'codemirror.next', + ); + fs.mkdirSync(codeMirrorDir, {recursive: true}); + const codeMirrorFile = path.join(codeMirrorDir, 'codemirror.next.js'); + const codeMirrorContent = `export default {}`; + writeFile(codeMirrorFile, codeMirrorContent); + // Create root mock + const rootDir = path.join(BUILD_DIR, devtoolsFrontEndCorePath, 'root'); + fs.mkdirSync(rootDir, {recursive: true}); + const runtimeFile = path.join(rootDir, 'Runtime.js'); + const runtimeContent = ` +export function getChromeVersion() { return ''; }; +export const hostConfig = {}; + `; + writeFile(runtimeFile, runtimeContent); + // Update protocol_client to remove: + // 1. self.Protocol assignment + // 2. Call to register backend commands. + const protocolClientDir = path.join( + BUILD_DIR, + devtoolsFrontEndCorePath, + 'protocol_client', + ); + const clientFile = path.join(protocolClientDir, 'protocol_client.js'); + const globalAssignment = /self\.Protocol = self\.Protocol \|\| \{\};/; + const registerCommands = + /InspectorBackendCommands\.registerCommands\(InspectorBackend\.inspectorBackend\);/; + sed(clientFile, globalAssignment, ''); + sed(clientFile, registerCommands, ''); + const devtoolsLicensePath = path.join( + 'node_modules', + 'chrome-devtools-frontend', + 'LICENSE', + ); + const devtoolsLicenseFileSource = path.join( + process.cwd(), + devtoolsLicensePath, + ); + const devtoolsLicenseFileDestination = path.join( + BUILD_DIR, + devtoolsLicensePath, + ); + fs.copyFileSync(devtoolsLicenseFileSource, devtoolsLicenseFileDestination); + copyThirdPartyLicenseFiles(); +} +main(); diff --git a/scripts/post-build.ts b/scripts/post-build.ts index db702801b..c3869aa61 100644 --- a/scripts/post-build.ts +++ b/scripts/post-build.ts @@ -7,7 +7,7 @@ import * as fs from 'node:fs'; import * as path from 'node:path'; -import {sed} from './sed.ts'; +import {sed} from './sed.js'; const BUILD_DIR = path.join(process.cwd(), 'build'); diff --git a/scripts/prepare.js b/scripts/prepare.js new file mode 100644 index 000000000..dc7756dea --- /dev/null +++ b/scripts/prepare.js @@ -0,0 +1,33 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {rm} from 'node:fs/promises'; +import {resolve} from 'node:path'; + +const projectRoot = process.cwd(); + +const filesToRemove = [ + 'node_modules/chrome-devtools-frontend/package.json', + 'node_modules/chrome-devtools-frontend/front_end/models/trace/lantern/testing', + 'node_modules/chrome-devtools-frontend/front_end/third_party/intl-messageformat/package/package.json', +]; + +async function main() { + console.log('Running prepare script to clean up chrome-devtools-frontend...'); + for (const file of filesToRemove) { + const fullPath = resolve(projectRoot, file); + console.log(`Removing: ${file}`); + try { + await rm(fullPath, {recursive: true, force: true}); + } catch (error) { + console.error(`Failed to remove ${file}:`, error); + process.exit(1); + } + } + console.log('Clean up of chrome-devtools-frontend complete.'); +} + +void main(); diff --git a/src/browser.ts b/src/browser.ts index 74ad6ee43..924325b4c 100644 --- a/src/browser.ts +++ b/src/browser.ts @@ -16,6 +16,11 @@ import type { Target, } from './third_party/index.js'; import {puppeteer} from './third_party/index.js'; +import puppeteerExtra from 'puppeteer-extra'; +import StealthPlugin from 'puppeteer-extra-plugin-stealth'; + +// Add stealth plugin +puppeteerExtra.use(StealthPlugin()); let browser: Browser | undefined; @@ -144,6 +149,8 @@ interface McpLaunchOptions { }; args?: string[]; devtools: boolean; + stealth?: boolean; + chromeArgs?: string[]; } export async function launch(options: McpLaunchOptions): Promise { @@ -170,9 +177,27 @@ export async function launch(options: McpLaunchOptions): Promise { ...(options.args ?? []), '--hide-crash-restore-bubble', ]; + + // Add custom Chrome arguments if provided + if (options.chromeArgs) { + args.push(...options.chromeArgs); + } + + // Add stealth-enhancing arguments if stealth mode is enabled + if (options.stealth) { + args.push( + '--disable-blink-features=AutomationControlled', + '--disable-features=IsolateOrigins,site-per-process', + '--no-first-run', + '--no-service-autorun', + '--password-store=basic', + ); + } + if (headless) { args.push('--screen-info={3840x2160}'); } + let puppeteerChannel: ChromeReleaseChannel | undefined; if (options.devtools) { args.push('--auto-open-devtools-for-tabs'); @@ -185,7 +210,10 @@ export async function launch(options: McpLaunchOptions): Promise { } try { - const browser = await puppeteer.launch({ + // Use puppeteer-extra with stealth plugin if stealth mode is enabled + const puppeteerInstance = options.stealth ? puppeteerExtra : puppeteer; + + const launchOptions: LaunchOptions = { channel: puppeteerChannel, targetFilter: makeTargetFilter(), executablePath, @@ -196,7 +224,15 @@ export async function launch(options: McpLaunchOptions): Promise { args, acceptInsecureCerts: options.acceptInsecureCerts, handleDevToolsAsPage: true, - }); + }; + + // Add ignoreDefaultArgs when stealth is enabled to remove automation flags + if (options.stealth) { + launchOptions.ignoreDefaultArgs = ['--enable-automation']; + } + + const browser = await puppeteerInstance.launch(launchOptions); + if (options.logFile) { // FIXME: we are probably subscribing too late to catch startup logs. We // should expose the process earlier or expose the getRecentLogs() getter. diff --git a/src/cli.ts b/src/cli.ts index db2680587..e71cfb7b4 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -147,6 +147,21 @@ export const cliOptions = { type: 'boolean', description: `If enabled, ignores errors relative to self-signed and expired certificates. Use with caution.`, }, + stealth: { + type: 'boolean', + description: `Enable stealth mode to avoid bot detection. Uses puppeteer-extra-plugin-stealth and adds anti-detection Chrome arguments.`, + default: false, + }, + chromeArgs: { + type: 'string', + description: `Additional Chrome arguments to pass to the browser (comma-separated). Example: --chromeArgs="--disable-gpu,--no-sandbox"`, + coerce: (arg: string | undefined) => { + if (!arg) { + return undefined; + } + return arg.split(',').map(a => a.trim()); + }, + }, experimentalDevtools: { type: 'boolean', describe: 'Whether to enable automation over DevTools targets', @@ -220,6 +235,15 @@ export function parseArguments(version: string, argv = process.argv) { '$0 --viewport 1280x720', 'Launch Chrome with the initial viewport size of 1280x720px', ], + ['$0 --stealth', 'Enable stealth mode to bypass bot detection'], + [ + '$0 --chromeArgs="--disable-gpu,--no-sandbox"', + 'Pass custom Chrome arguments', + ], + [ + '$0 --stealth --chromeArgs="--window-size=1920,1080"', + 'Use stealth mode with custom window size', + ], [ `$0 --chrome-arg='--no-sandbox' --chrome-arg='--disable-setuid-sandbox'`, 'Launch Chrome without sandboxes. Use with caution.', diff --git a/src/main.ts b/src/main.ts index 84bb6d9b5..0a2f043fe 100644 --- a/src/main.ts +++ b/src/main.ts @@ -81,6 +81,8 @@ async function getContext(): Promise { args: extraArgs, acceptInsecureCerts: args.acceptInsecureCerts, devtools, + stealth: args.stealth, + chromeArgs: args.chromeArgs as string[] | undefined, }); if (context?.browser !== browser) { diff --git a/tsconfig.json b/tsconfig.json index 3d9ded397..df7889702 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,6 +26,10 @@ "include": [ "src/**/*.ts", "tests/**/*.ts", + "scripts/post-build.ts", + "scripts/sed.ts", + "scripts/prepare.ts", + "scripts/verify-server-json-version.ts", "node_modules/chrome-devtools-frontend/front_end/core/common", "node_modules/chrome-devtools-frontend/front_end/core/host", "node_modules/chrome-devtools-frontend/front_end/core/i18n", @@ -67,5 +71,8 @@ "node_modules/chrome-devtools-frontend/front_end/third_party/third-party-web", "node_modules/chrome-devtools-frontend/mcp" ], - "exclude": ["node_modules/chrome-devtools-frontend/**/*.test.ts"] + "exclude": [ + "node_modules/chrome-devtools-frontend/**/*.test.ts", + "node_modules/chrome-devtools-frontend/**/testing/**" + ] }