From 34661cc879efd27760b303c26f638dae5398299d Mon Sep 17 00:00:00 2001 From: foxhui Date: Wed, 26 Nov 2025 03:27:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=BC=BA=E6=B5=8F=E8=A7=88?= =?UTF-8?q?=E5=99=A8=E7=89=B9=E5=BE=81=E4=BC=AA=E8=A3=85=20(ref=20#1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 21 ++- README.md | 61 +++++++- lib/lmarena.js | 216 ++++++++++++++------------- package.json | 3 + pnpm-lock.yaml | 387 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 575 insertions(+), 113 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1853951..6a2aba2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,31 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.1.1] - 2024-11-24 + +## [1.2.0] - 2024-11-26 + +### Added +- **浏览器特征伪装** + - 在 Windows10 官方 Chrome 环境下已通过 [antibot](https://bot.sannysoft.com/) 和 [CreepJS](https://abrahamjuliot.github.io/creepjs/) 测试(无红色警示)(但在Linux下未完全通过,需要用户配合,详情和进一步伪装请查看文档常见问题部分) + - 引入 `ghost-cursor` 优化鼠标移动轨迹伪装,不再重复造轮子 + +### Changed +- **指定模型** + - 更改模型UUID的拦截器不再使用注入Fetch脚本和Puppeteer Interception,改用CDP拦截器,减少特征 + +- **浏览器特征伪装** + - 优化浏览器启动参数,减少特征 + - 优化窗口大小计算方式 + +--- + +## [1.1.1] - 2024-11-25 ### Fixed - **指定模型** - 修复因错误的UUID映射导致的 gemini-3-pro-image-preview 模型触发HTTP500的 BUG +--- ## [1.1.0] - 2024-11-24 diff --git a/README.md b/README.md index ec0cbd1..9ab929b 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,13 @@ LMArenaImagenAutomator 是一个基于 Puppeteer 的自动化图像生成工具 ### ✨ 主要特性 -- 🎭 **拟人化操作**:使用贝塞尔曲线模拟真实鼠标移动轨迹 +- 💁‍♂️ **拟人操作**:模拟真实鼠标移动轨迹和抖动 - 🤖 **智能输入**:模拟人类打字速度和错误纠正行为 - 🖼️ **多图支持**:最多支持同时上传 5 张参考图片 - 🔐 **安全认证**:基于 Bearer Token 的 API 鉴权 - 📊 **队列管理**:智能任务队列,防止请求过载 - 🌐 **代理支持**:支持 HTTP 和 SOCKS5 代理配置 +- 🎭 **特征伪装**:尽量伪装成真实浏览器的特征(详情参考文档结尾) --- @@ -25,7 +26,7 @@ LMArenaImagenAutomator 是一个基于 Puppeteer 的自动化图像生成工具 - **Node.js**: 16.0 或更高版本 - **操作系统**: Windows、Linux 或 macOS -- **浏览器**: Google Chrome 或 Chromium (可选,Puppeteer 会自动下载) +- **浏览器**: Google Chrome 或 Chromium (Puppeteer 会自动下载,但是**更推荐**使用Google Chrome) ### 安装步骤 @@ -443,7 +444,7 @@ chrome:
-🐧 Linux 环境下非无头模式运行 +🐧 【Linux 环境下非无头模式运行】 **问题**: 需要在 Linux 服务器上显示浏览器界面(如手动过验证码) @@ -475,6 +476,60 @@ chrome:
+
+🎭 【浏览器特征伪装】 + +**问题**: 如何优化浏览器特征伪装,减少验证码弹出频率? + +**当前状态**: +- ✅ **Windows 10 官方 Chrome**: 已通过 [antibot](https://bot.sannysoft.com/) 和 [CreepJS](https://abrahamjuliot.github.io/creepjs/) 测试(无红色警示) +- ⚠️ **Linux 环境**: 未完全通过 CreepJS 测试,但基本不影响使用 + +**进一步优化建议**: + +> [!TIP] +> 完成后,可有效缓解验证码的弹出频率。 + +**1. 使用官方 Chrome(推荐)** + +不推荐使用 Chromium,因为它缺少 MP4/H.264 解码器等插件,且被大量爬虫使用,会成为明显特征。 + +**Linux 安装官方 Chrome**: +```bash +# 从 Google 官方下载 Chrome deb 安装包 +# 大陆服务器可手动下载deb安装包 https://www.google.com/chrome/?platform=linux +wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb +sudo dpkg -i google-chrome-stable_current_amd64.deb +sudo apt-get install -f # 修复可能的依赖问题 +``` + +**配置方式**: + +修改 `config.yaml`,可使用`which google-chrome`指令查询路径 +```yaml +chrome: + path: "/usr/bin/google-chrome" +``` + +使用环境变量可跳过 Puppeteer 自动下载 Chromium +```bash +export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD="true" +``` + +**2. 优化字体指纹** + +Linux 服务器通常只安装了极少量字体(甚至没有中文),这会增加指纹特征。 + +**安装常用字体**: +```bash +# 安装中文字体(必备,否则中文提示词将显示方框) +sudo apt install fonts-wqy-zenhei fonts-wqy-microhei + +# 安装微软核心字体(减少字体指纹差异) +sudo apt install ttf-mscorefonts-installer +``` + +
--- diff --git a/lib/lmarena.js b/lib/lmarena.js index ca87ef8..1083f43 100644 --- a/lib/lmarena.js +++ b/lib/lmarena.js @@ -1,14 +1,17 @@ -import puppeteer from 'puppeteer'; +import puppeteer from 'puppeteer-extra'; +import StealthPlugin from 'puppeteer-extra-plugin-stealth'; +import { createCursor } from 'ghost-cursor'; import fs from 'fs'; import path from 'path'; -import { fileURLToPath } from 'url'; import { anonymizeProxy, closeAnonymizedProxy } from 'proxy-chain'; -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); + +const stealth = StealthPlugin(); +stealth.enabledEvasions.delete('user-agent-override'); +stealth.enabledEvasions.delete('iframe.contentWindow'); +puppeteer.use(stealth); // --- 配置常量 --- -const CHROME_PATH = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'; const USER_DATA_DIR = path.join(process.cwd(), 'data', 'chromeUserData'); const TARGET_URL = 'https://lmarena.ai/c/new?mode=direct&chat-modality=image'; const TEMP_DIR = path.join(process.cwd(), 'data', 'temp'); @@ -46,48 +49,7 @@ function getMimeType(filePath) { return map[ext] || 'application/octet-stream'; } -// --- 核心拟人化算法 (贝塞尔曲线 + 物理模拟) --- -/** - * 三次贝塞尔曲线计算 - */ -function cubicBezier(t, p0, p1, p2, p3) { - const k = 1 - t; - return k * k * k * p0 + 3 * k * k * t * p1 + 3 * k * t * t * p2 + t * t * t * p3; -} - -/** - * 模拟人类鼠标移动轨迹 - * @param {object} page Puppeteer 页面对象 - * @param {number} startX 起始 X 坐标 - * @param {number} startY 起始 Y 坐标 - * @param {number} targetX 目标 X 坐标 - * @param {number} targetY 目标 Y 坐标 - */ -async function humanMove(page, startX, startY, targetX, targetY) { - const distance = Math.sqrt(Math.pow(targetX - startX, 2) + Math.pow(targetY - startY, 2)); - const steps = Math.floor(Math.max(distance / 8, 15)); - - const offset = distance * 0.4; - // 生成两个随机控制点,使轨迹弯曲 - const cp1X = startX + (targetX - startX) / 3 + random(-offset, offset); - const cp1Y = startY + (targetY - startY) / 3 + random(-offset, offset); - const cp2X = startX + 2 * (targetX - startX) / 3 + random(-offset, offset); - const cp2Y = startY + 2 * (targetY - startY) / 3 + random(-offset, offset); - - for (let i = 0; i <= steps; i++) { - const t = i / steps; - // 缓动函数:起步快,结尾慢,模拟人类肌肉运动 - const easeT = t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t; - - let x = cubicBezier(easeT, startX, cp1X, cp2X, targetX); - let y = cubicBezier(easeT, startY, cp1Y, cp2Y, targetY); - - // 添加微小的随机抖动 - if (i % 3 === 0) { x += random(-1, 1); y += random(-1, 1); } - await page.mouse.move(x, y); - } -} /** * 安全点击元素(包含拟人化移动和点击) @@ -98,24 +60,15 @@ async function safeClick(page, selector) { try { const el = await page.$(selector); if (!el) throw new Error(`未找到: ${selector}`); - const box = await el.boundingBox(); - if (!box) throw new Error(`不可见: ${selector}`); - // 先稍微移动一下当前位置 (增加真实感) - await page.mouse.move(box.x - random(50, 100), box.y - random(50, 100), { steps: 2 }); + // 使用 ghost-cursor 点击 + if (page.cursor) { + await page.cursor.click(el); + return; + } - // 目标点击位置在元素内部随机区域 - const targetX = box.x + box.width * random(0.3, 0.7); - const targetY = box.y + box.height * random(0.3, 0.7); - - // 移动鼠标到目标位置 - await humanMove(page, box.x - 50, box.y - 50, targetX, targetY); - - // 模拟点击过程:按下 -> 停顿 -> 抬起 - await sleep(100, 300); - await page.mouse.down(); - await sleep(60, 120); - await page.mouse.up(); + // 降级逻辑 + await el.click(); } catch (err) { throw err; } @@ -242,35 +195,32 @@ function extractImage(text) { /** * 初始化浏览器 * @param {object} config 配置对象 (包含 chrome 配置) - * @returns {Promise<{browser: object, page: object, client: object, width: number, height: number}>} + * @returns {Promise<{browser: object, page: object, client: object}>} */ async function initBrowser(config) { console.log('>>> [Browser] 开始初始化浏览器'); const chromeConfig = config?.chrome || {}; - const width = Math.floor(random(900, 1100)); - const height = Math.floor(random(500, 700)); // 1. 基础参数 const args = [ '--no-sandbox', '--disable-setuid-sandbox', - `--window-size=${width},${height}`, '--disable-blink-features=AutomationControlled', - '--disable-infobars', - '--test-type', - '--no-zygote', - '--disable-dev-shm-usage' + '--disable-dev-shm-usage', ]; - // 2. Headless 模式配置 + // 2. Headless 模式配置 & 窗口大小 let headlessMode = false; if (chromeConfig.headless) { headlessMode = 'new'; - args.push('--disable-gl-drawing-for-tests'); - console.log('>>> [Browser] Headless 模式: 启用'); + // 无头模式锁死分辨率 + args.push('--window-size=1280,690'); + console.log('>>> [Browser] Headless 模式: 启用 (1280x690)'); } else { - console.log('>>> [Browser] Headless 模式: 禁用'); + // 有头模式:最大化窗口以适配屏幕 + args.push('--start-maximized'); + console.log('>>> [Browser] Headless 模式: 禁用 (最大化窗口)'); } // 3. GPU 配置 @@ -323,9 +273,11 @@ async function initBrowser(config) { args: args }); - // 重用第一个标签页 - const pages = await browser.pages(); - const page = pages[0]; + // 保留第一个标签页 (about:blank),在新标签页中打开 + const page = await browser.newPage(); + + // 初始化 ghost-cursor + page.cursor = createCursor(page); // 5. 代理认证 (仅当未使用 proxy-chain 桥接时) if (chromeConfig.proxy && chromeConfig.proxy.enable && chromeConfig.proxy.user && !proxyUrlForChrome) { @@ -336,11 +288,6 @@ async function initBrowser(config) { console.log('>>> [Browser] 代理认证: 已设置 (HTTP Basic Auth)'); } - // 隐藏 WebDriver 特征 - await page.evaluateOnNewDocument(() => { - Object.defineProperty(navigator, 'webdriver', { get: () => undefined }); - }); - // 创建 CDP 会话以监听网络请求 const client = await page.target().createCDPSession(); await client.send('Network.enable'); @@ -351,12 +298,19 @@ async function initBrowser(config) { console.log('>>> [Warmup] 正在随机浏览页面以建立信任...'); - // 计算屏幕中心点 + // 计算屏幕中心点 (动态获取视口大小) + let viewport = page.viewport(); + // 如果是 null (有时候 headless 初始化慢),给个默认值 + let width = viewport ? viewport.width : 1280; + let height = viewport ? viewport.height : 690; + const centerX = width / 2; const centerY = height / 2; // 第一次移动:从左上角移动到中心附近 - await humanMove(page, 0, 0, centerX + random(-200, 200), centerY + random(-200, 200)); + if (page.cursor) { + await page.cursor.moveTo({ x: centerX + random(-200, 200), y: centerY + random(-200, 200) }); + } await sleep(500, 1000); // 模拟滚动行为 @@ -373,11 +327,14 @@ async function initBrowser(config) { // 移动鼠标到输入框 const box = await (await page.$(textareaSelector)).boundingBox(); if (box) { - await humanMove(page, centerX, centerY, box.x + box.width / 2, box.y + box.height / 2); + if (page.cursor) { + await page.cursor.moveTo({ x: box.x + box.width / 2, y: box.y + box.height / 2 }); + } await sleep(500, 1000); } console.log('>>> [Browser] 浏览器初始化完成,系统就绪'); + console.log('>>> [Browser] 当程序有任务运行时请勿随意调节窗口大小,以免鼠标轨迹错位!'); // 注册清理钩子:浏览器关闭时关闭代理服务器 if (proxyUrlForChrome) { @@ -391,21 +348,21 @@ async function initBrowser(config) { }); } - return { browser, page, client, width, height }; + return { browser, page, client }; } /** * 执行生图任务 - * @param {object} context 浏览器上下文 {page, client, width, height} + * @param {object} context 浏览器上下文 {page, client} * @param {string} prompt 提示词 * @param {string[]} imgPaths 图片路径数组 * @param {string|null} modelId 模型 UUID (可选) * @returns {Promise<{image?: string, text?: string, error?: string}>} */ async function generateImage(context, prompt, imgPaths, modelId) { - const { page, client, width, height } = context; + const { page, client } = context; const textareaSelector = 'textarea'; - let requestHandler = null; + let fetchPausedHandler = null; try { // 1. 强制开启新会话 (通过URL跳转) @@ -428,34 +385,70 @@ async function generateImage(context, prompt, imgPaths, modelId) { await humanType(page, textareaSelector, prompt); await sleep(800, 1500); - // --- 注入 Fetch 拦截器 (Puppeteer Request Interception) --- + // 注入 CDP Fetch 拦截器 if (modelId) { - await page.setRequestInterception(true); - requestHandler = async (request) => { - const url = request.url(); - if (url.includes('/nextjs-api/stream/') && request.method() === 'POST') { + // 1. 启用 Fetch 域拦截,仅拦截特定 URL + await client.send('Fetch.enable', { + patterns: [{ + urlPattern: '*nextjs-api/stream*', + requestStage: 'Request' + }] + }); + + // 2. 定义拦截处理函数 + fetchPausedHandler = async (event) => { + const { requestId, request } = event; + + if (request.method === 'POST' && request.postData) { try { - const postData = request.postData(); - if (postData) { - const data = JSON.parse(postData); - console.log(`[Browser] 正在拦截请求。原始 modelAId: ${data.modelAId}`); + // 尝试解码可能是 base64 编码的postData + let rawBody = request.postData; + // 尝试解析 JSON + let data; + try { + data = JSON.parse(rawBody); + } catch (e) { + // 尝试 Base64 解码 + try { + rawBody = Buffer.from(rawBody, 'base64').toString('utf8'); + data = JSON.parse(rawBody); + } catch (e2) { + // 无法解析,跳过 + } + } + + if (data && data.modelAId) { + console.log(`>>> [CDP] 正在拦截请求。原始 modelAId: ${data.modelAId}`); // 修改 modelAId data.modelAId = modelId; - const newPostData = JSON.stringify(data); - console.log(`[Browser] 请求已修改。新 modelAId: ${data.modelAId}`); - await request.continue({ postData: newPostData }); + // 重新序列化并转为 Base64 (Fetch.continueRequest 需要 base64) + const newBody = JSON.stringify(data); + const newBodyBase64 = Buffer.from(newBody).toString('base64'); + + console.log(`>>> [CDP] 请求已修改。新 modelAId: ${data.modelAId}`); + + await client.send('Fetch.continueRequest', { + requestId, + postData: newBodyBase64 + }); return; } } catch (e) { - console.error('[Browser] 拦截修改失败:', e); + console.error('[CDP] 拦截处理出错:', e); } } - await request.continue(); + + // 如果不匹配或出错,直接放行 + try { + await client.send('Fetch.continueRequest', { requestId }); + } catch (e) { } }; - page.on('request', requestHandler); - console.log(`>>> [Test] 已启用请求拦截,目标模型: ${modelId}`); + + // 3. 监听拦截事件 + client.on('Fetch.requestPaused', fetchPausedHandler); + console.log(`>>> [Test] 已启用 CDP Fetch 拦截,目标模型: ${modelId}`); } // 4. 发送 @@ -515,7 +508,12 @@ async function generateImage(context, prompt, imgPaths, modelId) { }); // 任务结束,像人一样把鼠标移开,防止遮挡或误触 - await humanMove(page, width / 2, height / 2, width - 100, height / 2); + if (page.cursor) { + const vp = page.viewport(); + const w = vp ? vp.width : 1280; + const h = vp ? vp.height : 690; + await page.cursor.moveTo({ x: w - 100, y: h / 2 }); + } return result; @@ -523,10 +521,10 @@ async function generateImage(context, prompt, imgPaths, modelId) { console.error('>>> [Error] 生成任务失败:', err.message); return { error: err.message }; } finally { - if (requestHandler) { - page.off('request', requestHandler); + if (fetchPausedHandler) { + client.off('Fetch.requestPaused', fetchPausedHandler); try { - await page.setRequestInterception(false); + await client.send('Fetch.disable'); } catch (e) { } } } diff --git a/package.json b/package.json index 49ee76b..21c378e 100644 --- a/package.json +++ b/package.json @@ -11,10 +11,13 @@ "genkey": "node lib/genApiKey.js" }, "dependencies": { + "ghost-cursor": "^1.4.1", "got-scraping": "^4.1.2", "js-yaml": "^4.1.1", "proxy-chain": "^2.6.0", "puppeteer": "^24.31.0", + "puppeteer-extra": "^3.3.6", + "puppeteer-extra-plugin-stealth": "^2.11.2", "sharp": "^0.34.5" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0a84a0a..c5e90e2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + ghost-cursor: + specifier: ^1.4.1 + version: 1.4.1 got-scraping: specifier: ^4.1.2 version: 4.1.2 @@ -20,6 +23,12 @@ importers: puppeteer: specifier: ^24.31.0 version: 24.31.0 + puppeteer-extra: + specifier: ^3.3.6 + version: 3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0) + puppeteer-extra-plugin-stealth: + specifier: ^2.11.2 + version: 2.11.2(puppeteer-extra@3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0)) sharp: specifier: ^0.34.5 version: 0.34.5 @@ -216,9 +225,18 @@ packages: '@tootallnate/quickjs-emscripten@0.23.0': resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@types/bezier-js@4.1.3': + resolution: {integrity: sha512-FNVVCu5mx/rJCWBxLTcL7oOajmGtWtBTDjq6DSUWUI12GeePivrZZXz+UgE0D6VYsLEjvExRO03z4hVtu3pTEQ==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + '@types/http-cache-semantics@4.0.4': resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node@24.10.1': resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} @@ -244,6 +262,10 @@ packages: argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + arr-union@3.1.0: + resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} + engines: {node: '>=0.10.0'} + ast-types@0.13.4: resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} engines: {node: '>=4'} @@ -256,6 +278,9 @@ packages: react-native-b4a: optional: true + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bare-events@2.8.2: resolution: {integrity: sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==} peerDependencies: @@ -302,6 +327,12 @@ packages: resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==} engines: {node: '>=10.0.0'} + bezier-js@6.1.4: + resolution: {integrity: sha512-PA0FW9ZpcHbojUCMu28z9Vg/fNkwTj5YhusSAjHHDfHDGLxJ6YUKrAN2vk1fP2MMOxVw4Oko16FMlRGVBGqLKg==} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + browserslist@4.28.0: resolution: {integrity: sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -342,6 +373,10 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + clone-deep@0.2.4: + resolution: {integrity: sha512-we+NuQo2DHhSl+DP6jlUiAhyAjBQrYnpOk15rN6c6JSPScjiCLh8IbSU+VTcph6YS3o7mASE8a0+gbZ7ChLpgg==} + engines: {node: '>=0.10.0'} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -349,6 +384,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + cosmiconfig@9.0.0: resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} engines: {node: '>=14'} @@ -375,6 +413,10 @@ packages: resolution: {integrity: sha512-oj7KWToJuuxlPr7VV0vabvxEIiqNMo+q0NueIiL3XhtwC6FVOX7Hr1c0C4eD0bmf7Zr+S/dSf2xvkH3Ad6sU3Q==} engines: {node: '>=20'} + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + degenerator@5.0.1: resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} engines: {node: '>= 14'} @@ -446,10 +488,29 @@ packages: fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + for-in@0.1.8: + resolution: {integrity: sha512-F0to7vbBSHP8E3l6dCjxNOLuSFAACIxFy3UehTUlG7svlXi37HHsDkyVcHo0Pq8QwrE+pXvWSVX3ZT1T9wAZ9g==} + engines: {node: '>=0.10.0'} + + for-in@1.0.2: + resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} + engines: {node: '>=0.10.0'} + + for-own@0.1.5: + resolution: {integrity: sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==} + engines: {node: '>=0.10.0'} + form-data-encoder@4.1.0: resolution: {integrity: sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw==} engines: {node: '>= 18'} + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + generative-bayesian-network@2.1.77: resolution: {integrity: sha512-viU4CRPsmgiklR94LhvdMndaY73BkCH1pGjmOjWbLR/ZwcUd06gKF3TCcsS3npRl74o33YSInSixxm16wIukcA==} @@ -469,6 +530,13 @@ packages: resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} engines: {node: '>= 14'} + ghost-cursor@1.4.1: + resolution: {integrity: sha512-K8A8/Co/Jbdqee694qrNsGWBG51DVK5UF2gGKEoZBDx9F1WmoD2SzUoDHWoY7O+TY84s1VrWwwfkVKxI2FoV2Q==} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + got-scraping@4.1.2: resolution: {integrity: sha512-LtVwPM5YLnNY7HVT/AK/yDBUg/4yOZSlAjjug2ovrHQseS43QCmO1XosKKXcXrfc6OMX8OnDbAWIauFMcaJ5TQ==} engines: {node: '>=16'} @@ -477,6 +545,9 @@ packages: resolution: {integrity: sha512-DjsLab39NUMf5iYlK9asVCkHMhaA2hEhrlmf+qXRhjEivuuBHWYbjmty9DA3OORUwZgENTB+6vSmY2ZW8gFHVw==} engines: {node: '>=20'} + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + header-generator@2.1.77: resolution: {integrity: sha512-ggSG/mfkFMu8CO7xP591G8kp1IJCBvgXu7M8oxTjC9u914JsIzE6zIfoFsXzA+pf0utWJhUsdqU0oV/DtQ4DFQ==} engines: {node: '>=16.0.0'} @@ -500,6 +571,13 @@ packages: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} + inflight@1.0.6: + resolution: {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. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ip-address@10.1.0: resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} engines: {node: '>= 12'} @@ -507,6 +585,13 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -515,10 +600,18 @@ packages: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} + is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + is-stream@4.0.1: resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} engines: {node: '>=18'} + isobject@3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -529,9 +622,28 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + keyv@5.5.4: resolution: {integrity: sha512-eohl3hKTiVyD1ilYdw9T0OiB4hnjef89e3dMYKz+mVKDzj+5IteTseASUsOB+EU9Tf6VNTCjDePcP6wkDGmLKQ==} + kind-of@2.0.1: + resolution: {integrity: sha512-0u8i1NZ/mg0b+W3MGGw5I7+6Eib2nx72S/QvXa0hYjEkjTknYmEYQJwGu3mLC0BrhtJjtQafTkyRUQ75Kx0LVg==} + engines: {node: '>=0.10.0'} + + kind-of@3.2.2: + resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} + engines: {node: '>=0.10.0'} + + lazy-cache@0.2.7: + resolution: {integrity: sha512-gkX52wvU/R8DVMMt78ATVPFMJqfW8FPz1GZ1sVHBVQHmu/WvhIWE4cE1GBzhJNFicDeYhnwp6Rl35BcAIM3YOQ==} + engines: {node: '>=0.10.0'} + + lazy-cache@1.0.4: + resolution: {integrity: sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==} + engines: {node: '>=0.10.0'} + lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -547,13 +659,24 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} + merge-deep@3.0.3: + resolution: {integrity: sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==} + engines: {node: '>=0.10.0'} + mimic-response@4.0.0: resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + mitt@3.0.1: resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + mixin-object@2.0.1: + resolution: {integrity: sha512-ALGF1Jt9ouehcaXaHhn6t1yGWRqGaHkPFndtFVHfZXOvkIZ/yoGaSi0AHVTafb3ZBGg4dr/bDwnaEKqCXzchMA==} + engines: {node: '>=0.10.0'} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -599,6 +722,10 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + pend@1.2.0: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} @@ -627,6 +754,69 @@ packages: resolution: {integrity: sha512-pnAohhSZipWQoFpXuGV7xCZfaGhqcBR9C4pVrU0QSrcMi7tQMH9J9lDBqBvyMAHQqe8HCARuREqFuVKRQOgTvg==} engines: {node: '>=18'} + puppeteer-extra-plugin-stealth@2.11.2: + resolution: {integrity: sha512-bUemM5XmTj9i2ZerBzsk2AN5is0wHMNE6K0hXBzBXOzP5m5G3Wl0RHhiqKeHToe/uIH8AoZiGhc1tCkLZQPKTQ==} + engines: {node: '>=8'} + peerDependencies: + playwright-extra: '*' + puppeteer-extra: '*' + peerDependenciesMeta: + playwright-extra: + optional: true + puppeteer-extra: + optional: true + + puppeteer-extra-plugin-user-data-dir@2.4.1: + resolution: {integrity: sha512-kH1GnCcqEDoBXO7epAse4TBPJh9tEpVEK/vkedKfjOVOhZAvLkHGc9swMs5ChrJbRnf8Hdpug6TJlEuimXNQ+g==} + engines: {node: '>=8'} + peerDependencies: + playwright-extra: '*' + puppeteer-extra: '*' + peerDependenciesMeta: + playwright-extra: + optional: true + puppeteer-extra: + optional: true + + puppeteer-extra-plugin-user-preferences@2.4.1: + resolution: {integrity: sha512-i1oAZxRbc1bk8MZufKCruCEC3CCafO9RKMkkodZltI4OqibLFXF3tj6HZ4LZ9C5vCXZjYcDWazgtY69mnmrQ9A==} + engines: {node: '>=8'} + peerDependencies: + playwright-extra: '*' + puppeteer-extra: '*' + peerDependenciesMeta: + playwright-extra: + optional: true + puppeteer-extra: + optional: true + + puppeteer-extra-plugin@3.2.3: + resolution: {integrity: sha512-6RNy0e6pH8vaS3akPIKGg28xcryKscczt4wIl0ePciZENGE2yoaQJNd17UiEbdmh5/6WW6dPcfRWT9lxBwCi2Q==} + engines: {node: '>=9.11.2'} + peerDependencies: + playwright-extra: '*' + puppeteer-extra: '*' + peerDependenciesMeta: + playwright-extra: + optional: true + puppeteer-extra: + optional: true + + puppeteer-extra@3.3.6: + resolution: {integrity: sha512-rsLBE/6mMxAjlLd06LuGacrukP2bqbzKCLzV1vrhHFavqQE/taQ2UXv3H5P0Ls7nsrASa+6x3bDbXHpqMwq+7A==} + engines: {node: '>=8'} + peerDependencies: + '@types/puppeteer': '*' + puppeteer: '*' + puppeteer-core: '*' + peerDependenciesMeta: + '@types/puppeteer': + optional: true + puppeteer: + optional: true + puppeteer-core: + optional: true + puppeteer@24.31.0: resolution: {integrity: sha512-q8y5yLxLD8xdZdzNWqdOL43NbfvUOp60SYhaLZQwHC9CdKldxQKXOyJAciOr7oUJfyAH/KgB2wKvqT2sFKoVXA==} engines: {node: '>=18'} @@ -655,11 +845,20 @@ packages: resolution: {integrity: sha512-cGk8IbWEAnaCpdAt1BHzJ3Ahz5ewDJa0KseTsE3qIRMJ3C698W8psM7byCeWVpd/Ha7FUYzuRVzXoKoM6nRUbA==} engines: {node: '>=20'} + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + semver@7.7.3: resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} hasBin: true + shallow-clone@0.1.2: + resolution: {integrity: sha512-J1zdXCky5GmNnuauESROVu31MQSnLoYvlyEn6j2Ztk6Q5EHFIhxkMhYcv6vuDzl2XEzoRr856QwzMgWM/TmZgw==} + engines: {node: '>=0.10.0'} + sharp@0.34.5: resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -717,6 +916,10 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + update-browserslist-db@1.1.4: resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} hasBin: true @@ -905,8 +1108,16 @@ snapshots: '@tootallnate/quickjs-emscripten@0.23.0': {} + '@types/bezier-js@4.1.3': {} + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + '@types/http-cache-semantics@4.0.4': {} + '@types/ms@2.1.0': {} + '@types/node@24.10.1': dependencies: undici-types: 7.16.0 @@ -929,12 +1140,16 @@ snapshots: argparse@2.0.1: {} + arr-union@3.1.0: {} + ast-types@0.13.4: dependencies: tslib: 2.8.1 b4a@1.7.3: {} + balanced-match@1.0.2: {} + bare-events@2.8.2: {} bare-fs@4.5.1: @@ -976,6 +1191,13 @@ snapshots: basic-ftp@5.0.5: {} + bezier-js@6.1.4: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + browserslist@4.28.0: dependencies: baseline-browser-mapping: 2.8.30 @@ -1018,12 +1240,22 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + clone-deep@0.2.4: + dependencies: + for-own: 0.1.5 + is-plain-object: 2.0.4 + kind-of: 3.2.2 + lazy-cache: 1.0.4 + shallow-clone: 0.1.2 + color-convert@2.0.1: dependencies: color-name: 1.1.4 color-name@1.1.4: {} + concat-map@0.0.1: {} + cosmiconfig@9.0.0: dependencies: env-paths: 2.2.1 @@ -1041,6 +1273,8 @@ snapshots: dependencies: mimic-response: 4.0.0 + deepmerge@4.3.1: {} + degenerator@5.0.1: dependencies: ast-types: 0.13.4 @@ -1111,8 +1345,24 @@ snapshots: dependencies: pend: 1.2.0 + for-in@0.1.8: {} + + for-in@1.0.2: {} + + for-own@0.1.5: + dependencies: + for-in: 1.0.2 + form-data-encoder@4.1.0: {} + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs.realpath@1.0.0: {} + generative-bayesian-network@2.1.77: dependencies: adm-zip: 0.5.16 @@ -1137,6 +1387,23 @@ snapshots: transitivePeerDependencies: - supports-color + ghost-cursor@1.4.1: + dependencies: + '@types/bezier-js': 4.1.3 + bezier-js: 6.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + got-scraping@4.1.2: dependencies: got: 14.6.4 @@ -1162,6 +1429,8 @@ snapshots: responselike: 4.0.2 type-fest: 4.41.0 + graceful-fs@4.2.11: {} + header-generator@2.1.77: dependencies: browserslist: 4.28.0 @@ -1195,16 +1464,33 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + ip-address@10.1.0: {} is-arrayish@0.2.1: {} + is-buffer@1.1.6: {} + + is-extendable@0.1.1: {} + is-fullwidth-code-point@3.0.0: {} is-obj@2.0.0: {} + is-plain-object@2.0.4: + dependencies: + isobject: 3.0.1 + is-stream@4.0.1: {} + isobject@3.0.1: {} + js-tokens@4.0.0: {} js-yaml@4.1.1: @@ -1213,10 +1499,28 @@ snapshots: json-parse-even-better-errors@2.3.1: {} + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + keyv@5.5.4: dependencies: '@keyv/serialize': 1.1.1 + kind-of@2.0.1: + dependencies: + is-buffer: 1.1.6 + + kind-of@3.2.2: + dependencies: + is-buffer: 1.1.6 + + lazy-cache@0.2.7: {} + + lazy-cache@1.0.4: {} + lines-and-columns@1.2.4: {} lodash.isequal@4.5.0: {} @@ -1225,10 +1529,25 @@ snapshots: lru-cache@7.18.3: {} + merge-deep@3.0.3: + dependencies: + arr-union: 3.1.0 + clone-deep: 0.2.4 + kind-of: 3.2.2 + mimic-response@4.0.0: {} + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + mitt@3.0.1: {} + mixin-object@2.0.1: + dependencies: + for-in: 0.1.8 + is-extendable: 0.1.1 + ms@2.1.3: {} netmask@2.0.2: {} @@ -1288,6 +1607,8 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + path-is-absolute@1.0.1: {} + pend@1.2.0: {} picocolors@1.1.1: {} @@ -1339,6 +1660,59 @@ snapshots: - supports-color - utf-8-validate + puppeteer-extra-plugin-stealth@2.11.2(puppeteer-extra@3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0)): + dependencies: + debug: 4.4.3 + puppeteer-extra-plugin: 3.2.3(puppeteer-extra@3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0)) + puppeteer-extra-plugin-user-preferences: 2.4.1(puppeteer-extra@3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0)) + optionalDependencies: + puppeteer-extra: 3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0) + transitivePeerDependencies: + - supports-color + + puppeteer-extra-plugin-user-data-dir@2.4.1(puppeteer-extra@3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0)): + dependencies: + debug: 4.4.3 + fs-extra: 10.1.0 + puppeteer-extra-plugin: 3.2.3(puppeteer-extra@3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0)) + rimraf: 3.0.2 + optionalDependencies: + puppeteer-extra: 3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0) + transitivePeerDependencies: + - supports-color + + puppeteer-extra-plugin-user-preferences@2.4.1(puppeteer-extra@3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0)): + dependencies: + debug: 4.4.3 + deepmerge: 4.3.1 + puppeteer-extra-plugin: 3.2.3(puppeteer-extra@3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0)) + puppeteer-extra-plugin-user-data-dir: 2.4.1(puppeteer-extra@3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0)) + optionalDependencies: + puppeteer-extra: 3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0) + transitivePeerDependencies: + - supports-color + + puppeteer-extra-plugin@3.2.3(puppeteer-extra@3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0)): + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3 + merge-deep: 3.0.3 + optionalDependencies: + puppeteer-extra: 3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0) + transitivePeerDependencies: + - supports-color + + puppeteer-extra@3.3.6(puppeteer-core@24.31.0)(puppeteer@24.31.0): + dependencies: + '@types/debug': 4.1.12 + debug: 4.4.3 + deepmerge: 4.3.1 + optionalDependencies: + puppeteer: 24.31.0 + puppeteer-core: 24.31.0 + transitivePeerDependencies: + - supports-color + puppeteer@24.31.0: dependencies: '@puppeteer/browsers': 2.10.13 @@ -1370,8 +1744,19 @@ snapshots: dependencies: lowercase-keys: 3.0.0 + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + semver@7.7.3: {} + shallow-clone@0.1.2: + dependencies: + is-extendable: 0.1.1 + kind-of: 2.0.1 + lazy-cache: 0.2.7 + mixin-object: 2.0.1 + sharp@0.34.5: dependencies: '@img/colour': 1.0.0 @@ -1478,6 +1863,8 @@ snapshots: undici-types@7.16.0: optional: true + universalify@2.0.1: {} + update-browserslist-db@1.1.4(browserslist@4.28.0): dependencies: browserslist: 4.28.0