From d2b0765c5ba4c056f4d7c75a26586da6c9157841 Mon Sep 17 00:00:00 2001 From: Taois Date: Thu, 2 Oct 2025 07:29:34 +0800 Subject: [PATCH 1/9] fix: docs error --- README.md | 68 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 0131057..6cda3e2 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,12 @@ - 🎨 现代化 Web 演示界面 - 📦 支持打包成二进制文件,无需安装 Node.js +## 系统要求 + +- **Chrome 浏览器**: 系统需要安装 Chrome 浏览器(Puppeteer 依赖) +- **Node.js**: 从源码运行需要 Node.js >= 18.0.0 +- **操作系统**: 支持 Windows、Linux、macOS + ## 快速开始 ### 方式一:使用二进制文件(推荐) @@ -26,12 +32,22 @@ 3. 直接运行二进制文件: ```bash - # Windows + # Windows - 默认端口启动 ./pup-sniffer-win.exe - # Linux/macOS + # Windows - 指定端口启动 + ./pup-sniffer-win.exe -port 8080 + + # Linux/macOS - 默认端口启动 ./pup-sniffer-linux ./pup-sniffer-macos + + # Linux/macOS - 指定端口启动 + ./pup-sniffer-linux -port 8080 + ./pup-sniffer-macos -port 8080 + + # 查看帮助信息 + ./pup-sniffer-win.exe --help ``` ### 方式二:从源码运行 @@ -43,10 +59,20 @@ 2. 启动服务: ```bash + # 默认端口启动(自动查找可用端口,从57573开始) npm start + + # 或直接使用 node 命令 + node server.cjs + + # 指定端口启动 + node server.cjs -port 8080 + + # 查看帮助信息 + node server.cjs --help ``` -服务将在 http://localhost:57573 启动 +服务默认在 http://localhost:57573 启动(如果端口被占用会自动查找下一个可用端口) ## 构建二进制文件 @@ -185,10 +211,16 @@ npm run build:macos-arm ## 使用示例 +**注意**:以下示例使用默认端口 57573,如果您使用了 `-port` 参数指定了其他端口,请相应调整 URL 中的端口号。 + ### 基本嗅探 ```bash +# 默认端口 curl "http://localhost:57573/sniffer?url=https://example.com/play" + +# 自定义端口(如果使用 -port 8080 启动) +curl "http://localhost:8080/sniffer?url=https://example.com/play" ``` ### 多链接嗅探 @@ -220,19 +252,31 @@ curl "http://localhost:57573/fetCodeByWebView?url=https://example.com" ## 测试 ```bash -# 测试 Sniffer 类 +# 运行测试脚本 npm test - -# 测试服务器接口(需要先启动服务) -npm run test:server ``` +**注意**: 测试前请确保服务器已启动 (`npm start`)。 + +## 命令行参数 + +| 参数 | 说明 | 示例 | +|------|------|------| +| `-port <端口号>` | 指定服务器端口号 (1-65535) | `-port 8080` | +| `-h, --help` | 显示帮助信息 | `--help` | + +**端口说明**: +- 如果不指定端口号,程序将从 57573 开始自动查找可用端口 +- 如果指定的端口被占用,程序会报错并退出 +- 端口号必须在 1-65535 范围内 + ## 环境变量 | 变量 | 说明 | 默认值 | |------|------|--------| -| PORT | 服务端口 | 57573 | -| HOST | 服务主机 | 0.0.0.0 | +| HOST | 服务主机地址 | 0.0.0.0 | + +**注意**: 端口配置请使用 `-port` 命令行参数,不支持通过环境变量设置端口。 ## 注意事项 @@ -262,10 +306,10 @@ npm run test:server ## 开发 -项目采用 ESM 模块化开发,主要文件: +项目采用 CommonJS 模块化开发,主要文件: -- `sniffer.js`: 核心嗅探类 -- `server.js`: Fastify 服务器 +- `sniffer.cjs`: 核心嗅探类 +- `server.cjs`: Fastify 服务器 - `test.js`: 测试脚本 - `package.json`: 项目配置 From 105e7fd05d88a4ea6853c6e76ed6d29cac13a78b Mon Sep 17 00:00:00 2001 From: Taois Date: Sun, 5 Oct 2025 03:10:45 +0800 Subject: [PATCH 2/9] =?UTF-8?q?add:=20=E5=A2=9E=E5=8A=A0golang=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E7=9A=84=E6=AE=8B=E5=BA=9F=E5=93=81=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=EF=BC=8C=E6=97=A0=E6=B3=95=E5=97=85=E6=8E=A2=E5=88=B0=E8=A7=86?= =?UTF-8?q?=E9=A2=91=E7=9B=B4=E9=93=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- golang/README.md | 242 +++++++++++++++ golang/go.mod | 40 +++ golang/go.sum | 102 +++++++ golang/server.go | 582 ++++++++++++++++++++++++++++++++++++ golang/sniffer.go | 731 ++++++++++++++++++++++++++++++++++++++++++++++ test-video.html | 19 ++ 6 files changed, 1716 insertions(+) create mode 100644 golang/README.md create mode 100644 golang/go.mod create mode 100644 golang/go.sum create mode 100644 golang/server.go create mode 100644 golang/sniffer.go create mode 100644 test-video.html diff --git a/golang/README.md b/golang/README.md new file mode 100644 index 0000000..08d0f7a --- /dev/null +++ b/golang/README.md @@ -0,0 +1,242 @@ +# Pup Sniffer - Golang 版本 + +基于 [go-rod](https://github.com/go-rod/rod) 的视频资源嗅探器 Golang 实现。 + +## 功能特性 + +- 🎯 **媒体嗅探**: 自动检测和提取网页中的视频/音频资源 URL +- 🌐 **多模式支持**: 支持单个 URL 嗅探和批量 URL 收集 +- 📱 **设备模拟**: 支持 PC 和移动设备模拟 +- 🔧 **自定义脚本**: 支持页面初始化脚本和执行脚本 +- 📄 **页面源码**: 获取动态渲染后的页面 HTML 源码 +- ⚡ **高性能**: 基于 Chrome DevTools Protocol,性能优异 +- 🛡️ **反检测**: 内置反自动化检测机制 + +## 系统要求 + +- Go >= 1.21 +- Chrome 浏览器 (用于 go-rod) +- 支持 Windows、Linux、macOS + +## 快速开始 + +### 1. 安装依赖 + +```bash +cd golang +go mod tidy +``` + +### 2. 运行服务 + +```bash +# 使用默认端口 (自动查找可用端口,从 57573 开始) +go run . + +# 指定端口 +go run . -port 8080 + +# 查看帮助 +go run . -help +``` + +### 3. 编译可执行文件 + +```bash +# 编译当前平台 +go build -o pup-sniffer . + +# 交叉编译 Windows +GOOS=windows GOARCH=amd64 go build -o pup-sniffer.exe . + +# 交叉编译 Linux +GOOS=linux GOARCH=amd64 go build -o pup-sniffer-linux . +``` + +## API 接口 + +### 1. 媒体嗅探接口 + +**GET** `/sniffer` + +**参数:** +- `url` (必需): 目标页面 URL +- `mode` (可选): 嗅探模式 + - `0`: 单个 URL 模式 (找到第一个匹配的 URL 后立即返回) + - `1`: 批量 URL 模式 (收集所有匹配的 URL) +- `is_pc` (可选): 设备模式 + - `0`: 移动设备模拟 (默认) + - `1`: PC 设备模拟 +- `timeout` (可选): 超时时间,单位毫秒 (默认: 10000,最大: 60000) +- `custom_regex` (可选): 自定义正则表达式 +- `sniffer_exclude` (可选): 排除正则表达式 +- `css` (可选): CSS 选择器,等待元素出现 +- `script` (可选): 页面脚本 (Base64 编码) +- `init_script` (可选): 初始化脚本 (Base64 编码) +- `headers` (可选): 自定义请求头,格式为 "key: value" 每行一个 + +**示例:** +```bash +curl "http://localhost:57573/sniffer?url=https://example.com&mode=0&timeout=10000" +``` + +### 2. 页面源码接口 + +**GET** `/fetCodeByWebView` + +获取动态渲染后的页面 HTML 源码。 + +**参数:** 与嗅探接口相同 (除了 `mode`, `custom_regex`, `sniffer_exclude`) + +**示例:** +```bash +curl "http://localhost:57573/fetCodeByWebView?url=https://example.com&timeout=10000" +``` + +### 3. 健康检查接口 + +**GET** `/health` + +检查服务状态。 + +### 4. 活跃状态接口 + +**GET** `/active` + +检查服务和浏览器状态。 + +## 响应格式 + +所有接口都返回统一的 JSON 格式: + +```json +{ + "code": 200, + "msg": "success", + "data": { + // 具体数据 + }, + "timestamp": 1640995200000 +} +``` + +### 嗅探成功响应 (mode=0) + +```json +{ + "code": 200, + "msg": "success", + "data": { + "url": "https://example.com/video.m3u8", + "headers": { + "referer": "https://example.com", + "user-agent": "Mozilla/5.0..." + }, + "from": "https://example.com", + "cost": "2500 ms", + "total_cost": "2600 ms", + "code": 200, + "msg": "超级嗅探解析成功" + } +} +``` + +### 嗅探成功响应 (mode=1) + +```json +{ + "code": 200, + "msg": "success", + "data": { + "urls": [ + { + "url": "https://example.com/video1.m3u8", + "headers": { + "referer": "https://example.com" + } + }, + { + "url": "https://example.com/video2.mp4", + "headers": { + "referer": "https://example.com" + } + } + ], + "from": "https://example.com", + "cost": "5000 ms", + "total_cost": "5100 ms", + "code": 200, + "msg": "超级嗅探解析成功" + } +} +``` + +## 配置说明 + +### 默认配置 + +```go +config := &SnifferConfig{ + Debug: true, // 启用调试日志 + Headless: true, // 无头模式 + UseChrome: true, // 使用系统 Chrome + DeviceType: "mobile", // 默认移动设备 + Timeout: 30000, // 默认超时 30 秒 + SnifferTimeout: 10000, // 嗅探超时 10 秒 + HeadTimeout: 5000, // HEAD 请求超时 5 秒 + ConcurrencyNum: 3, // 并发数 +} +``` + +### 环境变量 + +- `HOST`: 服务器监听地址 (默认: 0.0.0.0) + +## 与 Node.js 版本的差异 + +1. **性能**: Golang 版本在并发处理和内存使用方面更优 +2. **部署**: 编译后的二进制文件更容易部署,无需 Node.js 环境 +3. **依赖**: 使用 go-rod 替代 puppeteer,功能基本一致 +4. **API**: 保持与原版 100% 兼容的 API 接口 + +## 故障排除 + +### 1. Chrome 未找到 + +确保系统已安装 Chrome 浏览器,或者设置 `UseChrome: false` 使用内置浏览器。 + +### 2. 端口被占用 + +使用 `-port` 参数指定其他端口,或让程序自动查找可用端口。 + +### 3. 超时问题 + +根据目标网站的加载速度调整 `timeout` 参数。 + +### 4. 嗅探失败 + +- 检查目标 URL 是否可访问 +- 尝试使用自定义正则表达式 +- 检查是否需要特殊的请求头或脚本 + +## 开发说明 + +### 项目结构 + +``` +golang/ +├── go.mod # Go 模块文件 +├── sniffer.go # 嗅探器核心实现 +├── server.go # HTTP 服务器实现 +└── README.md # 说明文档 +``` + +### 核心组件 + +1. **Sniffer**: 嗅探器核心,基于 go-rod 实现 +2. **Server**: HTTP 服务器,基于 Gin 框架 +3. **APIResponse**: 统一的响应格式 + +## 许可证 + +与主项目保持一致的许可证。 \ No newline at end of file diff --git a/golang/go.mod b/golang/go.mod new file mode 100644 index 0000000..78e65ce --- /dev/null +++ b/golang/go.mod @@ -0,0 +1,40 @@ +module pup-sniffer + +go 1.21 + +require ( + github.com/gin-gonic/gin v1.9.1 + github.com/go-rod/rod v0.114.5 +) + +require ( + github.com/bytedance/sonic v1.9.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + github.com/ysmood/fetchup v0.2.3 // indirect + github.com/ysmood/goob v0.4.0 // indirect + github.com/ysmood/got v0.34.1 // indirect + github.com/ysmood/gson v0.7.3 // indirect + github.com/ysmood/leakless v0.8.0 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/golang/go.sum b/golang/go.sum new file mode 100644 index 0000000..a579d5d --- /dev/null +++ b/golang/go.sum @@ -0,0 +1,102 @@ +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/go-rod/rod v0.114.5 h1:1x6oqnslwFVuXJbJifgxspJUd3O4ntaGhRLHt+4Er9c= +github.com/go-rod/rod v0.114.5/go.mod h1:aiedSEFg5DwG/fnNbUOTPMTTWX3MRj6vIs/a684Mthw= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ= +github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns= +github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ= +github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18= +github.com/ysmood/gop v0.0.2 h1:VuWweTmXK+zedLqYufJdh3PlxDNBOfFHjIZlPT2T5nw= +github.com/ysmood/gop v0.0.2/go.mod h1:rr5z2z27oGEbyB787hpEcx4ab8cCiPnKxn0SUHt6xzk= +github.com/ysmood/got v0.34.1 h1:IrV2uWLs45VXNvZqhJ6g2nIhY+pgIG1CUoOcqfXFl1s= +github.com/ysmood/got v0.34.1/go.mod h1:yddyjq/PmAf08RMLSwDjPyCvHvYed+WjHnQxpH851LM= +github.com/ysmood/gotrace v0.6.0 h1:SyI1d4jclswLhg7SWTL6os3L1WOKeNn/ZtzVQF8QmdY= +github.com/ysmood/gotrace v0.6.0/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM= +github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE= +github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg= +github.com/ysmood/leakless v0.8.0 h1:BzLrVoiwxikpgEQR0Lk8NyBN5Cit2b1z+u0mgL4ZJak= +github.com/ysmood/leakless v0.8.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/golang/server.go b/golang/server.go new file mode 100644 index 0000000..c2d6373 --- /dev/null +++ b/golang/server.go @@ -0,0 +1,582 @@ +package main + +import ( + "encoding/base64" + "encoding/json" + "flag" + "fmt" + "log" + "net" + "net/http" + "net/url" + "os" + "os/signal" + "strconv" + "strings" + "syscall" + "time" + + "github.com/gin-gonic/gin" +) + +// APIResponse 统一响应格式 +type APIResponse struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data interface{} `json:"data,omitempty"` + Timestamp int64 `json:"timestamp"` +} + +// Server HTTP 服务器 +type Server struct { + sniffer *Sniffer + engine *gin.Engine + port int + host string +} + +// NewServer 创建新的服务器实例 +func NewServer() *Server { + // 设置 Gin 模式 + gin.SetMode(gin.ReleaseMode) + + server := &Server{ + engine: gin.New(), + host: "0.0.0.0", + } + + // 添加中间件 + server.engine.Use(gin.Logger()) + server.engine.Use(gin.Recovery()) + server.engine.Use(corsMiddleware()) + + // 设置路由 + server.setupRoutes() + + return server +} + +// corsMiddleware CORS 中间件 +func corsMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + c.Header("Access-Control-Allow-Origin", "*") + c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") + c.Header("Access-Control-Allow-Headers", "Origin, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") + c.Header("Access-Control-Allow-Credentials", "true") + + if c.Request.Method == "OPTIONS" { + c.AbortWithStatus(204) + return + } + + c.Next() + } +} + +// setupRoutes 设置路由 +func (s *Server) setupRoutes() { + // 首页路由 + s.engine.GET("/", s.handleHome) + + // 健康检查接口 + s.engine.GET("/health", s.handleHealth) + + // 活跃状态接口 + s.engine.GET("/active", s.handleActive) + + // 主要的嗅探接口 + s.engine.GET("/sniffer", s.handleSniffer) + + // 获取页面源码接口 + s.engine.GET("/fetCodeByWebView", s.handleFetCodeByWebView) +} + +// createResponse 创建统一响应 +func createResponse(data interface{}, code int, msg string) *APIResponse { + return &APIResponse{ + Code: code, + Msg: msg, + Data: data, + Timestamp: time.Now().UnixMilli(), + } +} + +// createErrorResponse 创建错误响应 +func createErrorResponse(msg string, code int) *APIResponse { + return createResponse(nil, code, msg) +} + +// handleHome 首页处理器 +func (s *Server) handleHome(c *gin.Context) { + // 简单的演示页面 + html := ` + + + Pup Sniffer - Golang Version + + + + +
+

🐶 Pup Sniffer - Golang Version

+

视频资源嗅探器 - 基于 go-rod 的 Golang 实现

+ +

API 接口

+ +
+

GET /sniffer

+

媒体嗅探接口

+

参数:

+
    +
  • url - 目标页面 URL (必需)
  • +
  • mode - 嗅探模式 (0: 单个URL, 1: 批量URL)
  • +
  • is_pc - 是否使用PC模式 (0: 移动端, 1: PC端)
  • +
  • timeout - 超时时间 (毫秒)
  • +
  • custom_regex - 自定义正则表达式
  • +
  • sniffer_exclude - 排除正则表达式
  • +
  • css - CSS 选择器
  • +
  • script - 页面脚本 (Base64编码)
  • +
  • init_script - 初始化脚本 (Base64编码)
  • +
  • headers - 请求头
  • +
+
+ +
+

GET /fetCodeByWebView

+

获取页面源码接口

+

参数: 与 /sniffer 接口相同

+
+ +
+

GET /health

+

健康检查接口

+
+ +
+

GET /active

+

活跃状态检查接口

+
+ +

示例

+
curl "http://localhost:57573/sniffer?url=https://example.com&mode=0&timeout=10000"
+
+ +` + + c.Header("Content-Type", "text/html; charset=utf-8") + c.String(http.StatusOK, html) +} + +// handleHealth 健康检查处理器 +func (s *Server) handleHealth(c *gin.Context) { + data := map[string]interface{}{ + "status": "ok", + "service": "pup-sniffer-golang", + } + c.JSON(http.StatusOK, createResponse(data, 200, "success")) +} + +// handleActive 活跃状态处理器 +func (s *Server) handleActive(c *gin.Context) { + browserStatus := "not_initialized" + if s.sniffer != nil && s.sniffer.browser != nil { + browserStatus = "initialized" + } + + data := map[string]interface{}{ + "active": true, + "browser": browserStatus, + "timestamp": time.Now().Format(time.RFC3339), + } + c.JSON(http.StatusOK, createResponse(data, 200, "success")) +} + +// handleSniffer 嗅探处理器 +func (s *Server) handleSniffer(c *gin.Context) { + startTime := time.Now() + + // 获取请求参数 + targetURL := c.Query("url") + isPcStr := c.DefaultQuery("is_pc", "0") + css := c.Query("css") + script := c.Query("script") + initScript := c.Query("init_script") + headers := c.Query("headers") + timeoutStr := c.DefaultQuery("timeout", "10000") + customRegex := c.Query("custom_regex") + snifferExclude := c.Query("sniffer_exclude") + modeStr := c.DefaultQuery("mode", "0") + + // 验证必需参数 + if targetURL == "" { + c.JSON(http.StatusBadRequest, createErrorResponse("缺少必需参数: url", 400)) + return + } + + if !isValidURL(targetURL) { + c.JSON(http.StatusBadRequest, createErrorResponse("无效的 URL 格式", 400)) + return + } + + // 解析参数 + var parsedScript, parsedInitScript string + var parsedHeaders map[string]string + var parsedTimeout, parsedMode int + var parsedIsPc bool + + // 解码 Base64 脚本 + if script != "" { + if decoded, err := base64.StdEncoding.DecodeString(script); err == nil { + parsedScript = string(decoded) + } else { + log.Printf("解码 script 失败: %v", err) + parsedScript = script + } + } + + if initScript != "" { + if decoded, err := base64.StdEncoding.DecodeString(initScript); err == nil { + parsedInitScript = string(decoded) + } else { + log.Printf("解码 init_script 失败: %v", err) + parsedInitScript = initScript + } + } + + // 解析请求头 + parsedHeaders = parseHeaders(headers) + + // 解析超时时间 + if timeout, err := strconv.Atoi(timeoutStr); err == nil { + parsedTimeout = timeout + if parsedTimeout > 60000 { + parsedTimeout = 60000 // 最大 60 秒 + } + } else { + parsedTimeout = 10000 + } + + // 解析模式 + if mode, err := strconv.Atoi(modeStr); err == nil { + parsedMode = mode + } else { + parsedMode = 0 + } + + // 解析是否为 PC + parsedIsPc = isPcStr == "1" || isPcStr == "true" + + // 初始化 Sniffer + if err := s.initSniffer(); err != nil { + c.JSON(http.StatusInternalServerError, createErrorResponse(fmt.Sprintf("初始化嗅探器失败: %v", err), 500)) + return + } + + // 执行嗅探 + options := &SnifferOptions{ + Mode: parsedMode, + CustomRegex: customRegex, + SnifferExclude: snifferExclude, + Timeout: parsedTimeout, + CSS: css, + IsPc: parsedIsPc, + Headers: parsedHeaders, + Script: parsedScript, + InitScript: parsedInitScript, + } + + result, err := s.sniffer.SnifferMediaURL(targetURL, options) + if err != nil { + log.Printf("嗅探过程中发生错误: %v", err) + c.JSON(http.StatusInternalServerError, createErrorResponse(fmt.Sprintf("嗅探失败: %v", err), 500)) + return + } + + totalCost := time.Since(startTime) + if result != nil { + // 添加总耗时信息 + resultMap := make(map[string]interface{}) + resultBytes, _ := json.Marshal(result) + json.Unmarshal(resultBytes, &resultMap) + resultMap["total_cost"] = fmt.Sprintf("%d ms", totalCost.Milliseconds()) + + c.JSON(http.StatusOK, createResponse(resultMap, 200, "success")) + } else { + c.JSON(http.StatusInternalServerError, createErrorResponse("嗅探返回空结果", 500)) + } +} + +// handleFetCodeByWebView 获取页面源码处理器 +func (s *Server) handleFetCodeByWebView(c *gin.Context) { + startTime := time.Now() + + // 获取请求参数 + targetURL := c.Query("url") + isPcStr := c.DefaultQuery("is_pc", "0") + css := c.Query("css") + script := c.Query("script") + initScript := c.Query("init_script") + headers := c.Query("headers") + timeoutStr := c.DefaultQuery("timeout", "10000") + + // 验证必需参数 + if targetURL == "" { + c.JSON(http.StatusBadRequest, createErrorResponse("缺少必需参数: url", 400)) + return + } + + if !isValidURL(targetURL) { + c.JSON(http.StatusBadRequest, createErrorResponse("无效的 URL 格式", 400)) + return + } + + // 解析参数 + var parsedScript, parsedInitScript string + var parsedHeaders map[string]string + var parsedTimeout int + var parsedIsPc bool + + // 解码 Base64 脚本 + if script != "" { + if decoded, err := base64.StdEncoding.DecodeString(script); err == nil { + parsedScript = string(decoded) + } else { + log.Printf("解码 script 失败: %v", err) + parsedScript = script + } + } + + if initScript != "" { + if decoded, err := base64.StdEncoding.DecodeString(initScript); err == nil { + parsedInitScript = string(decoded) + } else { + log.Printf("解码 init_script 失败: %v", err) + parsedInitScript = initScript + } + } + + // 解析请求头 + parsedHeaders = parseHeaders(headers) + + // 解析超时时间 + if timeout, err := strconv.Atoi(timeoutStr); err == nil { + parsedTimeout = timeout + if parsedTimeout > 60000 { + parsedTimeout = 60000 // 最大 60 秒 + } + } else { + parsedTimeout = 10000 + } + + // 解析是否为 PC + parsedIsPc = isPcStr == "1" || isPcStr == "true" + + // 初始化 Sniffer + if err := s.initSniffer(); err != nil { + c.JSON(http.StatusInternalServerError, createErrorResponse(fmt.Sprintf("初始化嗅探器失败: %v", err), 500)) + return + } + + // 获取页面源码 + options := &SnifferOptions{ + Timeout: parsedTimeout, + CSS: css, + IsPc: parsedIsPc, + Headers: parsedHeaders, + Script: parsedScript, + InitScript: parsedInitScript, + } + + result, err := s.sniffer.FetCodeByWebView(targetURL, options) + if err != nil { + log.Printf("获取页面源码过程中发生错误: %v", err) + c.JSON(http.StatusInternalServerError, createErrorResponse(fmt.Sprintf("获取页面源码失败: %v", err), 500)) + return + } + + totalCost := time.Since(startTime) + if result != nil { + // 添加总耗时信息 + resultMap := make(map[string]interface{}) + resultBytes, _ := json.Marshal(result) + json.Unmarshal(resultBytes, &resultMap) + resultMap["total_cost"] = fmt.Sprintf("%d ms", totalCost.Milliseconds()) + + c.JSON(http.StatusOK, createResponse(resultMap, 200, "success")) + } else { + c.JSON(http.StatusInternalServerError, createErrorResponse("获取页面源码返回空结果", 500)) + } +} + +// initSniffer 初始化嗅探器 +func (s *Server) initSniffer() error { + if s.sniffer == nil { + log.Println("开始初始化嗅探器...") + config := &SnifferConfig{ + Debug: true, + Headless: true, + UseChrome: true, + } + s.sniffer = NewSniffer(config) + err := s.sniffer.InitBrowser() + if err != nil { + log.Printf("浏览器初始化失败: %v", err) + return err + } + log.Println("嗅探器初始化完成") + } + return nil +} + +// isValidURL 验证 URL 格式 +func isValidURL(urlStr string) bool { + _, err := url.Parse(urlStr) + return err == nil && (strings.HasPrefix(urlStr, "http://") || strings.HasPrefix(urlStr, "https://")) +} + +// parseHeaders 解析请求头字符串 +func parseHeaders(headerStr string) map[string]string { + headers := make(map[string]string) + if headerStr == "" { + return headers + } + + lines := strings.Split(headerStr, "\n") + for _, line := range lines { + colonIndex := strings.Index(line, ":") + if colonIndex > 0 { + key := strings.TrimSpace(strings.ToLower(line[:colonIndex])) + value := strings.TrimSpace(line[colonIndex+1:]) + if key != "" && value != "" { + headers[key] = value + } + } + } + + return headers +} + +// checkPortAvailable 检查端口是否可用 +func checkPortAvailable(port int) bool { + ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port)) + if err != nil { + return false + } + ln.Close() + return true +} + +// findAvailablePort 查找可用端口 +func findAvailablePort(startPort int) (int, error) { + for port := startPort; port < startPort+100; port++ { + if checkPortAvailable(port) { + return port, nil + } + } + return 0, fmt.Errorf("无法找到可用端口,已尝试从 %d 到 %d", startPort, startPort+99) +} + +// showHelp 显示帮助信息 +func showHelp() { + fmt.Println(` +Pup Sniffer - 视频资源嗅探器 (Golang版本) + +使用方法: + go run . [选项] + ./pup-sniffer [选项] + +选项: + -port <端口号> 指定服务器端口号 (1-65535) + -h, -help 显示此帮助信息 + +示例: + go run . -port 8080 + ./pup-sniffer -port 3000 + +如果不指定端口号,服务器将从57573开始自动查找可用端口。 +`) +} + +// Start 启动服务器 +func (s *Server) Start() error { + // 解析命令行参数 + var port int + var help bool + + flag.IntVar(&port, "port", 0, "指定服务器端口号") + flag.BoolVar(&help, "h", false, "显示帮助信息") + flag.BoolVar(&help, "help", false, "显示帮助信息") + flag.Parse() + + // 如果请求帮助,显示帮助信息并退出 + if help { + showHelp() + return nil + } + + // 确定使用的端口 + if port != 0 { + // 使用指定的端口 + if !checkPortAvailable(port) { + return fmt.Errorf("指定的端口 %d 已被占用", port) + } + s.port = port + fmt.Printf("使用指定端口: %d\n", port) + } else { + // 自动查找可用端口 + fmt.Println("正在查找可用端口...") + availablePort, err := findAvailablePort(57573) + if err != nil { + return err + } + s.port = availablePort + fmt.Printf("找到可用端口: %d\n", availablePort) + } + + // 设置优雅关闭 + go s.setupGracefulShutdown() + + // 启动服务器 + addr := fmt.Sprintf("%s:%d", s.host, s.port) + fmt.Printf("🚀 服务器已启动,监听地址: http://%s:%d\n", s.host, s.port) + fmt.Printf("📡 嗅探接口: http://%s:%d/sniffer\n", s.host, s.port) + fmt.Printf("📄 页面源码接口: http://%s:%d/fetCodeByWebView\n", s.host, s.port) + fmt.Printf("💚 健康检查: http://%s:%d/health\n", s.host, s.port) + fmt.Printf("🔄 活跃状态: http://%s:%d/active\n", s.host, s.port) + + return s.engine.Run(addr) +} + +// setupGracefulShutdown 设置优雅关闭 +func (s *Server) setupGracefulShutdown() { + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + + <-c + fmt.Println("\n收到关闭信号,正在关闭服务器...") + + if s.sniffer != nil { + if err := s.sniffer.Close(); err != nil { + log.Printf("关闭嗅探器时发生错误: %v", err) + } else { + fmt.Println("嗅探器已关闭") + } + } + + fmt.Println("服务器已关闭") + os.Exit(0) +} + +func main() { + server := NewServer() + if err := server.Start(); err != nil { + log.Fatalf("启动服务器失败: %v", err) + } +} \ No newline at end of file diff --git a/golang/sniffer.go b/golang/sniffer.go new file mode 100644 index 0000000..3564d89 --- /dev/null +++ b/golang/sniffer.go @@ -0,0 +1,731 @@ +package main + +import ( + "context" + "fmt" + "log" + "net/http" + "net/url" + "regexp" + "strings" + "time" + + "github.com/go-rod/rod" + "github.com/go-rod/rod/lib/devices" + "github.com/go-rod/rod/lib/launcher" + "github.com/go-rod/rod/lib/proto" +) + +// SnifferConfig 嗅探器配置 +type SnifferConfig struct { + Debug bool `json:"debug"` + Headless bool `json:"headless"` + UseChrome bool `json:"use_chrome"` + DeviceType string `json:"device_type"` + UserAgent string `json:"user_agent"` + Timeout int `json:"timeout"` + SnifferTimeout int `json:"sniffer_timeout"` + HeadTimeout int `json:"head_timeout"` + ConcurrencyNum int `json:"concurrency_num"` + CustomRegex string `json:"custom_regex"` +} + +// Sniffer 嗅探器结构体 +type Sniffer struct { + config *SnifferConfig + browser *rod.Browser + urlRegex *regexp.Regexp + urlNoHead *regexp.Regexp + excludeRegex *regexp.Regexp + blockResources []string +} + +// SnifferOptions 嗅探选项 +type SnifferOptions struct { + Mode int `json:"mode"` + CustomRegex string `json:"custom_regex"` + SnifferExclude string `json:"sniffer_exclude"` + Timeout int `json:"timeout"` + CSS string `json:"css"` + IsPc bool `json:"is_pc"` + Headers map[string]string `json:"headers"` + Script string `json:"script"` + InitScript string `json:"init_script"` +} + +// SnifferResult 嗅探结果 +type SnifferResult struct { + URL string `json:"url,omitempty"` + URLs []URLWithHeaders `json:"urls,omitempty"` + Headers map[string]string `json:"headers,omitempty"` + From string `json:"from"` + Cost string `json:"cost"` + Code int `json:"code"` + Script string `json:"script,omitempty"` + InitScript string `json:"init_script,omitempty"` + Msg string `json:"msg"` +} + +// URLWithHeaders URL和请求头 +type URLWithHeaders struct { + URL string `json:"url"` + Headers map[string]string `json:"headers"` +} + +// PageCodeResult 页面源码结果 +type PageCodeResult struct { + Code string `json:"code"` + From string `json:"from"` + Cost string `json:"cost"` + Script string `json:"script,omitempty"` + InitScript string `json:"init_script,omitempty"` + Msg string `json:"msg"` +} + +// NewSniffer 创建新的嗅探器实例 +func NewSniffer(config *SnifferConfig) *Sniffer { + if config == nil { + config = &SnifferConfig{ + Debug: true, + Headless: true, + UseChrome: true, + DeviceType: "mobile", + Timeout: 30000, + SnifferTimeout: 10000, + HeadTimeout: 5000, + ConcurrencyNum: 3, + } + } + + // 默认正则表达式 - 兼容 Go RE2 引擎(不支持负向前瞻) + // 匹配包含媒体文件扩展名的 URL + urlRegex := regexp.MustCompile(`(?i)https?://[^\s"'<>]{12,}?\.(m3u8|mp4|flv|avi|mkv|rm|wmv|mpg|m4a|mp3)(\?[^\s"'<>]*)?|https?://[^\s"'<>]*?(video|obj)/tos[^\s"'<>]*`) + urlNoHead := regexp.MustCompile(`https?://[^\s"'<>]{12,}?(ac=dm&url=)`) + + // 阻止的资源类型 + blockResources := []string{ + "image", "stylesheet", "font", "texttrack", "object", "beacon", + "csp_report", "imageset", "media", + } + + return &Sniffer{ + config: config, + urlRegex: urlRegex, + urlNoHead: urlNoHead, + blockResources: blockResources, + } +} + +// log 日志输出 +func (s *Sniffer) log(args ...interface{}) { + if s.config.Debug { + log.Println(args...) + } +} + +// InitBrowser 初始化浏览器 +func (s *Sniffer) InitBrowser() error { + var l *launcher.Launcher + + if s.config.UseChrome { + // 查找系统中的 Chrome + l = launcher.New().Headless(s.config.Headless) + } else { + // 使用内置浏览器 + l = launcher.New().Headless(s.config.Headless) + } + + // 设置启动参数 + l = l.Set("disable-blink-features", "AutomationControlled"). + Set("disable-features", "VizDisplayCompositor,TranslateUI"). + Set("disable-ipc-flooding-protection"). + Set("disable-renderer-backgrounding"). + Set("disable-backgrounding-occluded-windows"). + Set("disable-background-timer-throttling"). + Set("disable-background-networking"). + Set("disable-breakpad"). + Set("disable-client-side-phishing-detection"). + Set("disable-component-extensions-with-background-pages"). + Set("disable-default-apps"). + Set("disable-dev-shm-usage"). + Set("disable-extensions"). + Set("disable-features", "TranslateUI"). + Set("disable-hang-monitor"). + Set("disable-popup-blocking"). + Set("disable-prompt-on-repost"). + Set("disable-sync"). + Set("disable-web-security"). + Set("metrics-recording-only"). + Set("no-first-run"). + Set("no-default-browser-check"). + Set("password-store", "basic"). + Set("use-mock-keychain"). + Set("no-sandbox"). + Set("disable-setuid-sandbox") + + url, err := l.Launch() + if err != nil { + return fmt.Errorf("启动浏览器失败: %v", err) + } + + browser := rod.New().ControlURL(url) + err = browser.Connect() + if err != nil { + return fmt.Errorf("连接浏览器失败: %v", err) + } + + s.browser = browser + s.log("浏览器初始化成功") + return nil +} + +// GetPage 获取新页面 +func (s *Sniffer) GetPage(headers map[string]string) (*rod.Page, error) { + if s.browser == nil { + return nil, fmt.Errorf("浏览器未初始化") + } + + page, err := s.browser.Page(proto.TargetCreateTarget{}) + if err != nil { + return nil, fmt.Errorf("创建页面失败: %v", err) + } + + // 设置设备模拟 + if !strings.Contains(s.config.DeviceType, "pc") { + device := devices.IPhoneX + err = page.Emulate(device) + if err != nil { + s.log("设备模拟失败:", err) + } + } + + // 设置用户代理 + userAgent := s.config.UserAgent + if userAgent == "" { + if strings.Contains(s.config.DeviceType, "pc") { + userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" + } else { + userAgent = "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1" + } + } + + err = page.SetUserAgent(&proto.NetworkSetUserAgentOverride{ + UserAgent: userAgent, + }) + if err != nil { + s.log("设置用户代理失败:", err) + } + + // 设置额外的请求头 + if len(headers) > 0 { + headerList := make([]string, 0, len(headers)*2) + for k, v := range headers { + headerList = append(headerList, k, v) + } + _, err = page.SetExtraHeaders(headerList) + if err != nil { + s.log("设置额外请求头失败:", err) + } + } + + // 设置 User-Agent + if userAgent != "" { + err = page.SetUserAgent(&proto.NetworkSetUserAgentOverride{ + UserAgent: userAgent, + }) + if err != nil { + s.log("设置 User-Agent 失败:", err) + } + } + + // 注释掉资源阻止逻辑,避免与主要的嗅探拦截器冲突 + // 资源阻止将在主要的嗅探拦截器中处理 + + return page, nil +} + +// shouldBlockResource 检查是否应该阻止资源 +func (s *Sniffer) shouldBlockResource(resourceType string) bool { + for _, blockType := range s.blockResources { + if resourceType == blockType { + return true + } + } + return false +} + +// ClosePage 关闭页面 +func (s *Sniffer) ClosePage(page *rod.Page) { + if page != nil { + err := page.Close() + if err != nil { + s.log("关闭页面失败:", err) + } + } +} + +// Close 关闭浏览器 +func (s *Sniffer) Close() error { + if s.browser != nil { + err := s.browser.Close() + if err != nil { + return fmt.Errorf("关闭浏览器失败: %v", err) + } + s.log("浏览器已关闭") + } + return nil +} + +// IsValidURL 检查 URL 是否有效 +func (s *Sniffer) IsValidURL(urlStr string) bool { + _, err := url.Parse(urlStr) + return err == nil && (strings.HasPrefix(urlStr, "http://") || strings.HasPrefix(urlStr, "https://")) +} + +// IsRealURLCheck 检查是否为真实媒体 URL +func (s *Sniffer) IsRealURLCheck(urlStr string) bool { + // 排除一些明显不是媒体文件的 URL + excludePatterns := []string{ + "google", "facebook", "twitter", "analytics", "doubleclick", + ".css", ".js", ".html", ".htm", ".png", ".jpg", ".jpeg", ".gif", + } + + lowerURL := strings.ToLower(urlStr) + for _, pattern := range excludePatterns { + if strings.Contains(lowerURL, pattern) { + return false + } + } + + return true +} + +// CanHeadCheck 检查是否可以进行 HEAD 请求 +func (s *Sniffer) CanHeadCheck(urlStr string) bool { + // 简单的检查逻辑 + return !s.urlNoHead.MatchString(urlStr) +} + +// SnifferMediaURL 嗅探媒体 URL +func (s *Sniffer) SnifferMediaURL(playURL string, options *SnifferOptions) (*SnifferResult, error) { + startTime := time.Now() + + if options == nil { + options = &SnifferOptions{ + Mode: 0, + Timeout: s.config.SnifferTimeout, + } + } + + // 验证 URL + if !s.IsValidURL(playURL) { + return &SnifferResult{ + Code: 400, + Msg: "无效的 URL", + From: playURL, + Cost: fmt.Sprintf("%d ms", time.Since(startTime).Milliseconds()), + }, nil + } + + realURLs := make([]URLWithHeaders, 0) + headURLs := make(map[string]bool) + + page, err := s.GetPage(options.Headers) + if err != nil { + return &SnifferResult{ + Code: 500, + Msg: fmt.Sprintf("创建页面失败: %v", err), + From: playURL, + Cost: fmt.Sprintf("%d ms", time.Since(startTime).Milliseconds()), + }, nil + } + defer s.ClosePage(page) + + // 设置超时 + timeout := time.Duration(options.Timeout) * time.Millisecond + if options.Mode == 1 { + if options.Timeout > s.config.Timeout { + timeout = time.Duration(s.config.Timeout) * time.Millisecond + } + } else { + if options.Timeout > s.config.SnifferTimeout { + timeout = time.Duration(s.config.SnifferTimeout) * time.Millisecond + } + } + + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + // 请求拦截器 + router := page.HijackRequests() + router.MustAdd("*", func(hijack *rod.Hijack) { + reqURL := hijack.Request.URL().String() + method := hijack.Request.Method() + headers := hijack.Request.Headers() + resourceType := hijack.Request.Type() + + s.log("on_request:", reqURL, "method:", method, "type:", resourceType) + + // 检查是否需要阻止的资源类型 + if s.shouldBlockResource(string(resourceType)) { + s.log("blocking resource type:", resourceType, "for URL:", reqURL) + hijack.Response.Fail(proto.NetworkErrorReasonBlockedByClient) + return + } + + // 添加调试:检查是否匹配默认正则 + if s.urlRegex.MatchString(reqURL) { + s.log("URL matches urlRegex:", reqURL) + if s.IsRealURLCheck(reqURL) { + s.log("URL passes IsRealURLCheck:", reqURL) + } else { + s.log("URL fails IsRealURLCheck:", reqURL) + } + } + + // 检查排除正则 + if options.SnifferExclude != "" { + excludeRegex, err := regexp.Compile("(?mi)" + options.SnifferExclude) + if err == nil && excludeRegex.MatchString(reqURL) { + hijack.ContinueRequest(&proto.FetchContinueRequest{}) + return + } + } + + // 检查自定义正则 + if options.CustomRegex != "" { + customRegex, err := regexp.Compile("(?mi)" + options.CustomRegex) + if err == nil && customRegex.MatchString(reqURL) { + reqHeaders := make(map[string]string) + if referer, ok := headers["referer"]; ok && referer.String() != "" { + reqHeaders["referer"] = referer.String() + } + if userAgent, ok := headers["user-agent"]; ok && userAgent.String() != "" { + reqHeaders["user-agent"] = userAgent.String() + } + + realURLs = append(realURLs, URLWithHeaders{ + URL: reqURL, + Headers: reqHeaders, + }) + + s.log("通过custom_regex嗅探到真实地址:", reqURL) + + if options.Mode == 0 { + cancel() // 触发超时,结束嗅探 + } + hijack.ContinueRequest(&proto.FetchContinueRequest{}) + return + } + } + + // 检查默认正则 + if s.urlRegex.MatchString(reqURL) && s.IsRealURLCheck(reqURL) { + if !strings.Contains(reqURL, "url=http") && !strings.Contains(reqURL, "v=http") && + !strings.Contains(reqURL, ".css") && !strings.Contains(reqURL, ".html") { + + reqHeaders := make(map[string]string) + if referer, ok := headers["referer"]; ok && referer.String() != "" { + reqHeaders["referer"] = referer.String() + } + if userAgent, ok := headers["user-agent"]; ok && userAgent.String() != "" { + reqHeaders["user-agent"] = userAgent.String() + } + + realURLs = append(realURLs, URLWithHeaders{ + URL: reqURL, + Headers: reqHeaders, + }) + + s.log("通过默认正则嗅探到真实地址:", reqURL) + + if options.Mode == 0 { + cancel() // 触发超时,结束嗅探 + } + } + } else if strings.ToLower(method) == "get" && strings.HasPrefix(reqURL, "http") && reqURL != playURL { + // HEAD 请求检查逻辑 + parsedURL, err := url.Parse(reqURL) + if err == nil { + path := parsedURL.Path + filename := "" + if idx := strings.LastIndex(path, "/"); idx >= 0 { + filename = path[idx+1:] + } + + shouldCheck := (filename != "" && !strings.Contains(filename, ".") && !s.urlNoHead.MatchString(reqURL)) || + (strings.Contains(filename, ".") && len(filename) > 1) + + if shouldCheck && !headURLs[reqURL] && s.CanHeadCheck(reqURL) { + go func(checkURL string) { + client := &http.Client{ + Timeout: time.Duration(s.config.HeadTimeout) * time.Millisecond, + } + + req, err := http.NewRequest("HEAD", checkURL, nil) + if err != nil { + s.log("创建HEAD请求失败:", err) + return + } + + resp, err := client.Do(req) + if err != nil { + s.log("HEAD请求失败:", err) + return + } + defer resp.Body.Close() + + contentType := resp.Header.Get("content-type") + contentDisposition := resp.Header.Get("content-disposition") + + if contentType == "application/octet-stream" && + contentDisposition != "" && strings.Contains(contentDisposition, ".m3u8") { + + reqHeaders := make(map[string]string) + if referer, ok := headers["referer"]; ok && referer.String() != "" { + reqHeaders["referer"] = referer.String() + } + if userAgent, ok := headers["user-agent"]; ok && userAgent.String() != "" { + reqHeaders["user-agent"] = userAgent.String() + } + + realURLs = append(realURLs, URLWithHeaders{ + URL: checkURL, + Headers: reqHeaders, + }) + + s.log("通过head请求嗅探到真实地址:", checkURL) + + if options.Mode == 0 { + cancel() // 触发超时,结束嗅探 + } + } + }(reqURL) + + headURLs[reqURL] = true + } + } + } + + hijack.ContinueRequest(&proto.FetchContinueRequest{}) + }) + go router.Run() + + // 执行初始化脚本 + if options.InitScript != "" { + s.log("开始执行页面初始化js:", options.InitScript) + _, err = page.EvalOnNewDocument(options.InitScript) + if err != nil { + s.log("执行页面初始化js发生错误:", err) + } + } + + // 导航到页面 + err = rod.Try(func() { + page.Context(ctx).MustNavigate(playURL) + // 尝试等待页面加载,但不强制要求成功 + rod.Try(func() { + page.Context(ctx).MustWaitLoad() + }) + }) + if err != nil { + s.log("页面导航失败:", err) + // 继续执行,不要因为导航失败就停止 + } + + // 等待 CSS 选择器 + if options.CSS != "" { + err = rod.Try(func() { + page.Context(ctx).MustElement(options.CSS) + }) + if err != nil { + s.log("等待CSS选择器失败:", err) + } + } + + // 执行页面脚本 + if options.Script != "" { + s.log("开始执行网页js:", options.Script) + jsCode := fmt.Sprintf(` + var scriptTimer; + var scriptCounter = 0; + scriptTimer = setInterval(function(){ + if(location.href !== 'about:blank'){ + scriptCounter += 1; + console.log('---第' + scriptCounter + '次执行script[' + location.href + ']---'); + %s + clearInterval(scriptTimer); + scriptCounter = 0; + console.log('---执行script成功---'); + } + }, 200); + `, options.Script) + + err = rod.Try(func() { + page.Context(ctx).MustEval(jsCode) + }) + if err != nil { + s.log("执行页面脚本失败:", err) + } + } + + // 等待结果 + if options.Mode == 0 { + // 等待找到第一个 URL 或超时 + <-ctx.Done() + } else if options.Mode == 1 { + // 等待指定时间收集所有 URL + <-ctx.Done() + } + + cost := time.Since(startTime) + costStr := fmt.Sprintf("%d ms", cost.Milliseconds()) + + s.log("共计耗时", cost.Milliseconds(), "毫秒") + s.log("realURLs:", realURLs) + + // 返回结果 + if options.Mode == 0 && len(realURLs) > 0 { + return &SnifferResult{ + URL: realURLs[0].URL, + Headers: realURLs[0].Headers, + From: playURL, + Cost: costStr, + Code: 200, + Script: options.Script, + InitScript: options.InitScript, + Msg: "超级嗅探解析成功", + }, nil + } else if options.Mode == 1 && len(realURLs) > 0 { + return &SnifferResult{ + URLs: realURLs, + Code: 200, + From: playURL, + Cost: costStr, + Script: options.Script, + InitScript: options.InitScript, + Msg: "超级嗅探解析成功", + }, nil + } else { + return &SnifferResult{ + URL: "", + Headers: make(map[string]string), + From: playURL, + Cost: costStr, + Script: options.Script, + InitScript: options.InitScript, + Code: 404, + Msg: "超级嗅探解析失败", + }, nil + } +} + +// FetCodeByWebView 获取页面源码 +func (s *Sniffer) FetCodeByWebView(pageURL string, options *SnifferOptions) (*PageCodeResult, error) { + startTime := time.Now() + + if options == nil { + options = &SnifferOptions{ + Timeout: s.config.Timeout, + } + } + + // 验证 URL + if !s.IsValidURL(pageURL) { + return &PageCodeResult{ + Code: "", + From: pageURL, + Cost: fmt.Sprintf("%d ms", time.Since(startTime).Milliseconds()), + Msg: "无效的 URL", + }, nil + } + + page, err := s.GetPage(options.Headers) + if err != nil { + return &PageCodeResult{ + Code: "", + From: pageURL, + Cost: fmt.Sprintf("%d ms", time.Since(startTime).Milliseconds()), + Msg: fmt.Sprintf("创建页面失败: %v", err), + }, nil + } + defer s.ClosePage(page) + + // 设置超时 + timeout := time.Duration(options.Timeout) * time.Millisecond + ctx, cancel := context.WithTimeout(context.Background(), timeout) + defer cancel() + + // 执行初始化脚本 + if options.InitScript != "" { + s.log("开始执行页面初始化js:", options.InitScript) + _, err = page.EvalOnNewDocument(options.InitScript) + if err != nil { + s.log("执行页面初始化js发生错误:", err) + } + } + + // 导航到页面 + err = rod.Try(func() { + page.Context(ctx).MustNavigate(pageURL).MustWaitLoad() + }) + if err != nil { + s.log("页面导航失败:", err) + return &PageCodeResult{ + Code: "", + From: pageURL, + Cost: fmt.Sprintf("%d ms", time.Since(startTime).Milliseconds()), + Msg: fmt.Sprintf("页面导航失败: %v", err), + }, nil + } + + // 等待 CSS 选择器 + if options.CSS != "" { + err = rod.Try(func() { + page.Context(ctx).MustElement(options.CSS) + }) + if err != nil { + s.log("等待CSS选择器失败:", err) + } + } + + // 执行页面脚本 + if options.Script != "" { + s.log("开始执行网页js:", options.Script) + err = rod.Try(func() { + page.Context(ctx).MustEval(options.Script) + }) + if err != nil { + s.log("执行页面脚本失败:", err) + } + } + + // 获取页面源码 + var htmlContent string + err = rod.Try(func() { + htmlContent = page.Context(ctx).MustHTML() + }) + if err != nil { + s.log("获取页面源码失败:", err) + return &PageCodeResult{ + Code: "", + From: pageURL, + Cost: fmt.Sprintf("%d ms", time.Since(startTime).Milliseconds()), + Msg: fmt.Sprintf("获取页面源码失败: %v", err), + }, nil + } + + cost := time.Since(startTime) + costStr := fmt.Sprintf("%d ms", cost.Milliseconds()) + + s.log("获取页面源码成功,耗时", cost.Milliseconds(), "毫秒") + + return &PageCodeResult{ + Code: htmlContent, + From: pageURL, + Cost: costStr, + Script: options.Script, + InitScript: options.InitScript, + Msg: "获取页面源码成功", + }, nil +} \ No newline at end of file diff --git a/test-video.html b/test-video.html new file mode 100644 index 0000000..ed0f593 --- /dev/null +++ b/test-video.html @@ -0,0 +1,19 @@ + + + + Test Video Page + + +

Test Video

+ + + + \ No newline at end of file From ab6913d044e755607c6daea54e3a4a7ab52b814b Mon Sep 17 00:00:00 2001 From: Taois Date: Sun, 5 Oct 2025 08:25:06 +0800 Subject: [PATCH 3/9] =?UTF-8?q?feat:=E6=89=93=E5=8C=85=E4=BD=93=E7=A7=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pkgignore | 77 ++++++++++++++++++++++++++++ build-optimized.js | 91 +++++++++++++++++++++++++++++++++ API_DOCS.md => docs/API_DOCS.md | 0 docs/BUILD_GUIDE.md | 85 ++++++++++++++++++++++++++++++ package.json | 41 ++++++++++++--- server.cjs | 5 +- test-video.html | 19 ------- 7 files changed, 290 insertions(+), 28 deletions(-) create mode 100644 .pkgignore create mode 100644 build-optimized.js rename API_DOCS.md => docs/API_DOCS.md (100%) create mode 100644 docs/BUILD_GUIDE.md delete mode 100644 test-video.html diff --git a/.pkgignore b/.pkgignore new file mode 100644 index 0000000..a4cd824 --- /dev/null +++ b/.pkgignore @@ -0,0 +1,77 @@ +# 开发和测试文件 +test.js +quick-test.js +build.js +start.js +test-video.html + +# 文档文件 +README.md +LICENSE +API_DOCS.md + +# Git 相关 +.gitignore +.git/ + +# Node.js 相关 +node_modules/.cache/ +node_modules/*/test/ +node_modules/*/tests/ +node_modules/*/.nyc_output/ +node_modules/*/coverage/ +node_modules/*/docs/ +node_modules/*/doc/ +node_modules/*/examples/ +node_modules/*/example/ +node_modules/*/benchmark/ +node_modules/*/benchmarks/ + +# Puppeteer 相关 - 排除大部分 Chromium 文件 +node_modules/puppeteer/.local-chromium/ +node_modules/puppeteer/lib/esm/ +node_modules/puppeteer/src/ +node_modules/puppeteer/test/ +node_modules/puppeteer/docs/ + +# 开发环境专用模块 +node_modules/pino-pretty/ + +# TypeScript 定义文件 +node_modules/@types/ +*.d.ts + +# 日志文件 +*.log +logs/ + +# 临时文件 +*.tmp +*.temp +.DS_Store +Thumbs.db + +# 开发工具配置 +.vscode/ +.idea/ +*.swp +*.swo + +# 构建输出 +dist/ +build/ + +# 包管理器文件 +package-lock.json +yarn.lock +pnpm-lock.yaml + +# 其他大型依赖的非必要部分 +node_modules/*/CHANGELOG.md +node_modules/*/HISTORY.md +node_modules/*/AUTHORS +node_modules/*/CONTRIBUTORS +node_modules/*/*.md +node_modules/*/*.txt +node_modules/*/LICENSE* +node_modules/*/LICENCE* \ No newline at end of file diff --git a/build-optimized.js b/build-optimized.js new file mode 100644 index 0000000..1a7ad69 --- /dev/null +++ b/build-optimized.js @@ -0,0 +1,91 @@ +#!/usr/bin/env node + +const { execSync } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +console.log('🚀 开始优化构建...'); + +// 清理输出目录 +if (fs.existsSync('dist')) { + console.log('🧹 清理旧的构建文件...'); + try { + fs.rmSync('dist', { recursive: true, force: true }); + } catch (error) { + console.log('⚠️ 清理失败,继续构建...'); + } +} + +// 创建输出目录 +fs.mkdirSync('dist', { recursive: true }); + +// 构建配置 +const builds = [ + { + name: 'Windows (GZip)', + command: 'pkg . --targets node18-win-x64 --compress GZip --output dist/pup-sniffer-win.exe' + }, + { + name: 'Windows (Brotli - 最小体积)', + command: 'pkg . --targets node18-win-x64 --compress Brotli --no-bytecode --public-packages=* --output dist/pup-sniffer-win-mini.exe' + }, + { + name: 'Linux (GZip)', + command: 'pkg . --targets node18-linux-x64 --compress GZip --output dist/pup-sniffer-linux' + }, + { + name: 'Linux (Brotli - 最小体积)', + command: 'pkg . --targets node18-linux-x64 --compress Brotli --no-bytecode --public-packages=* --output dist/pup-sniffer-linux-mini' + }, + { + name: 'macOS Intel (GZip)', + command: 'pkg . --targets node18-macos-x64 --compress GZip --output dist/pup-sniffer-macos' + }, + { + name: 'macOS Intel (Brotli - 最小体积)', + command: 'pkg . --targets node18-macos-x64 --compress Brotli --no-bytecode --public-packages=* --output dist/pup-sniffer-macos-mini' + }, + { + name: 'macOS ARM (GZip)', + command: 'pkg . --targets node18-macos-arm64 --compress GZip --output dist/pup-sniffer-macos-arm64' + }, + { + name: 'macOS ARM (Brotli - 最小体积)', + command: 'pkg . --targets node18-macos-arm64 --compress Brotli --no-bytecode --public-packages=* --output dist/pup-sniffer-macos-arm64-mini' + } +]; + +// 执行构建 +for (const build of builds) { + console.log(`\n📦 构建: ${build.name}`); + try { + const startTime = Date.now(); + execSync(build.command, { stdio: 'inherit' }); + const endTime = Date.now(); + console.log(`✅ ${build.name} 构建完成 (${((endTime - startTime) / 1000).toFixed(1)}s)`); + } catch (error) { + console.error(`❌ ${build.name} 构建失败:`, error.message); + } +} + +// 显示文件大小统计 +console.log('\n📊 构建结果统计:'); +console.log('=' .repeat(60)); + +const distFiles = fs.readdirSync('dist').filter(file => + !file.includes('.') || file.endsWith('.exe') +); + +distFiles.forEach(file => { + const filePath = path.join('dist', file); + const stats = fs.statSync(filePath); + const sizeInMB = (stats.size / (1024 * 1024)).toFixed(2); + console.log(`${file.padEnd(35)} ${sizeInMB.padStart(8)} MB`); +}); + +console.log('=' .repeat(60)); +console.log('🎉 所有构建完成!'); +console.log('\n💡 提示:'); +console.log('- 使用 GZip 版本获得更好的兼容性'); +console.log('- 使用 Brotli mini 版本获得最小体积'); +console.log('- mini 版本可能需要更多运行时依赖'); \ No newline at end of file diff --git a/API_DOCS.md b/docs/API_DOCS.md similarity index 100% rename from API_DOCS.md rename to docs/API_DOCS.md diff --git a/docs/BUILD_GUIDE.md b/docs/BUILD_GUIDE.md new file mode 100644 index 0000000..d0d4e6b --- /dev/null +++ b/docs/BUILD_GUIDE.md @@ -0,0 +1,85 @@ +# 构建指南 + +本项目提供了多种构建选项来优化最终可执行文件的体积。 + +## 构建选项 + +### 1. 标准构建 (GZip 压缩) +```bash +npm run build:all +``` +- 使用 GZip 压缩 +- 兼容性最好 +- 体积适中 + +### 2. Brotli 压缩构建 +```bash +npm run build:brotli +``` +- 使用 Brotli 压缩 +- 比 GZip 体积更小 +- 压缩率更高 + +### 3. 轻量级构建 +```bash +npm run build:lite +``` +- 使用 Brotli 压缩 +- 禁用字节码缓存 (`--no-bytecode`) +- 公开所有包 (`--public-packages=*`) +- 体积最小 + +### 4. 迷你构建 +```bash +npm run build:mini +``` +- 最激进的压缩选项 +- 添加 `--no-warnings` 选项 +- 体积最小,但可能需要更多运行时依赖 + +### 5. 优化构建 (推荐) +```bash +npm run build:optimized +``` +- 自动构建多个版本 +- 提供详细的体积统计 +- 包含标准版和迷你版 + +## 体积优化技术 + +### 1. 压缩算法 +- **GZip**: 标准压缩,兼容性好 +- **Brotli**: 更高压缩率,体积更小 + +### 2. PKG 选项 +- `--no-bytecode`: 禁用字节码缓存,减少体积 +- `--public-packages=*`: 将所有包标记为公开,减少包装开销 +- `--no-warnings`: 禁用警告,减少输出体积 + +### 3. 资源排除 +- 使用 `.pkgignore` 文件排除不必要的文件 +- 移除了大部分 Puppeteer Chromium 文件 +- 排除开发和测试文件 + +### 4. 依赖优化 +- 只包含必要的运行时文件 +- 排除文档、测试和示例文件 +- 移除 TypeScript 定义文件 + +## 文件说明 + +- `.pkgignore`: 定义打包时要排除的文件和目录 +- `build-optimized.js`: 优化构建脚本,提供详细统计 +- `BUILD_GUIDE.md`: 本构建指南 + +## 使用建议 + +1. **开发测试**: 使用 `npm run build:win` (或对应平台) +2. **生产部署**: 使用 `npm run build:optimized` +3. **极限压缩**: 使用 `npm run build:mini` + +## 注意事项 + +- 迷你版本可能在某些环境下需要额外的运行时依赖 +- Brotli 压缩的文件启动时间可能稍长 +- 建议在目标环境中测试压缩版本的兼容性 \ No newline at end of file diff --git a/package.json b/package.json index 714df95..454e5ac 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,26 @@ "test": "node test.js", "build": "node build.js", "build:all": "npm run build:win && npm run build:linux && npm run build:macos && npm run build:macos-arm", - "build:win": "pkg . --targets node18-win-x64 --output dist/pup-sniffer-win.exe", - "build:linux": "pkg . --targets node18-linux-x64 --output dist/pup-sniffer-linux", - "build:macos": "pkg . --targets node18-macos-x64 --output dist/pup-sniffer-macos", - "build:macos-arm": "pkg . --targets node18-macos-arm64 --output dist/pup-sniffer-macos-arm64", + "build:win": "pkg . --targets node18-win-x64 --compress GZip --output dist/pup-sniffer-win.exe", + "build:linux": "pkg . --targets node18-linux-x64 --compress GZip --output dist/pup-sniffer-linux", + "build:macos": "pkg . --targets node18-macos-x64 --compress GZip --output dist/pup-sniffer-macos", + "build:macos-arm": "pkg . --targets node18-macos-arm64 --compress GZip --output dist/pup-sniffer-macos-arm64", + "build:brotli": "npm run build:win:brotli && npm run build:linux:brotli && npm run build:macos:brotli && npm run build:macos-arm:brotli", + "build:win:brotli": "pkg . --targets node18-win-x64 --compress Brotli --output dist/pup-sniffer-win-brotli.exe", + "build:linux:brotli": "pkg . --targets node18-linux-x64 --compress Brotli --output dist/pup-sniffer-linux-brotli", + "build:macos:brotli": "pkg . --targets node18-macos-x64 --compress Brotli --output dist/pup-sniffer-macos-brotli", + "build:macos-arm:brotli": "pkg . --targets node18-macos-arm64 --compress Brotli --output dist/pup-sniffer-macos-arm64-brotli", + "build:lite": "npm run build:win:lite && npm run build:linux:lite && npm run build:macos:lite && npm run build:macos-arm:lite", + "build:win:lite": "pkg . --targets node18-win-x64 --compress Brotli --no-bytecode --public-packages=* --output dist/pup-sniffer-win-lite.exe", + "build:linux:lite": "pkg . --targets node18-linux-x64 --compress Brotli --no-bytecode --public-packages=* --output dist/pup-sniffer-linux-lite", + "build:macos:lite": "pkg . --targets node18-macos-x64 --compress Brotli --no-bytecode --public-packages=* --output dist/pup-sniffer-macos-lite", + "build:macos-arm:lite": "pkg . --targets node18-macos-arm64 --compress Brotli --no-bytecode --public-packages=* --output dist/pup-sniffer-macos-arm64-lite", + "build:optimized": "node build-optimized.js", + "build:mini": "npm run build:win:mini && npm run build:linux:mini && npm run build:macos:mini && npm run build:macos-arm:mini", + "build:win:mini": "pkg . --targets node18-win-x64 --compress Brotli --no-bytecode --public-packages=* --no-warnings --output dist/pup-sniffer-win-mini.exe", + "build:linux:mini": "pkg . --targets node18-linux-x64 --compress Brotli --no-bytecode --public-packages=* --no-warnings --output dist/pup-sniffer-linux-mini", + "build:macos:mini": "pkg . --targets node18-macos-x64 --compress Brotli --no-bytecode --public-packages=* --no-warnings --output dist/pup-sniffer-macos-mini", + "build:macos-arm:mini": "pkg . --targets node18-macos-arm64 --compress Brotli --no-bytecode --public-packages=* --no-warnings --output dist/pup-sniffer-macos-arm64-mini", "clean": "rimraf dist", "prebuild": "npm run clean" }, @@ -49,9 +65,7 @@ ], "assets": [ "demo.html", - "node_modules/puppeteer/.local-chromium/**/*", - "node_modules/thread-stream/lib/worker.js", - "node_modules/pino-pretty/**/*" + "node_modules/thread-stream/lib/worker.js" ], "targets": [ "node18-win-x64", @@ -59,6 +73,17 @@ "node18-macos-x64", "node18-macos-arm64" ], - "outputPath": "dist" + "outputPath": "dist", + "options": [ + "--no-bytecode", + "--public-packages=*", + "--no-warnings" + ], + "patches": { + "puppeteer": [ + "node_modules/puppeteer/lib/cjs/puppeteer/node/BrowserFetcher.js" + ] + }, + "compress": "Brotli" } } diff --git a/server.cjs b/server.cjs index fd80c19..5ba7e9f 100644 --- a/server.cjs +++ b/server.cjs @@ -112,8 +112,11 @@ function getResourcePath(filename) { } // 创建 Fastify 实例 +const isPkg = typeof process.pkg !== 'undefined'; const fastify = Fastify({ - logger: { + logger: isPkg ? { + level: 'info' + } : { level: 'info', transport: { target: 'pino-pretty', diff --git a/test-video.html b/test-video.html deleted file mode 100644 index ed0f593..0000000 --- a/test-video.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - Test Video Page - - -

Test Video

- - - - \ No newline at end of file From 89b256182040c27a3cb15224cf8364866b4889e0 Mon Sep 17 00:00:00 2001 From: Taois Date: Sun, 5 Oct 2025 08:28:57 +0800 Subject: [PATCH 4/9] =?UTF-8?q?feat:=E5=8D=87=E7=BA=A7=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .pkgignore | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.pkgignore b/.pkgignore index a4cd824..be5353c 100644 --- a/.pkgignore +++ b/.pkgignore @@ -8,7 +8,7 @@ test-video.html # 文档文件 README.md LICENSE -API_DOCS.md +docs/ # Git 相关 .gitignore diff --git a/package.json b/package.json index 454e5ac..31dcd40 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pup-sniffer", - "version": "1.0.0", + "version": "1.0.1", "description": "Video resource sniffer using Puppeteer and Fastify", "main": "server.cjs", "bin": "server.cjs", From 2efaa0e58aaa24f857296f961ac00877fb9e0eb0 Mon Sep 17 00:00:00 2001 From: Taois Date: Sun, 5 Oct 2025 08:34:25 +0800 Subject: [PATCH 5/9] docs:update readme --- README.md | 197 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 189 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6cda3e2..f476ec0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,30 @@ # Pup Sniffer +[![Node.js Version](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)](https://nodejs.org/) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20Linux%20%7C%20macOS-lightgrey.svg)](https://github.com) + 基于 Puppeteer 和 Fastify 的视频资源嗅探器 Node.js 版本。 +> 🎯 **高性能视频资源嗅探工具**,支持多平台部署,提供完整的 API 接口和现代化 Web 界面。 + +## 📋 目录 + +- [功能特性](#功能特性) +- [系统要求](#系统要求) +- [快速开始](#快速开始) +- [构建二进制文件](#构建二进制文件) +- [API 接口](#api-接口) +- [使用示例](#使用示例) +- [测试](#测试) +- [命令行参数](#命令行参数) +- [环境变量](#环境变量) +- [注意事项](#注意事项) +- [故障排除](#故障排除) +- [文档](#文档) +- [开发](#开发) +- [许可证](#许可证) + ## 功能特性 - 🎯 视频资源嗅探(支持 m3u8、mp4 等格式) @@ -76,20 +99,38 @@ ## 构建二进制文件 -### 构建所有平台 +项目提供了多种构建选项,支持不同的压缩算法和优化级别,以满足不同的使用需求。 + +### 📦 构建选项概览 + +| 构建类型 | 压缩算法 | 体积优化 | 适用场景 | +|----------|----------|----------|----------| +| 标准版 | GZip | 中等 | 通用部署 | +| Brotli版 | Brotli | 较高 | 网络传输优化 | +| 轻量版 | Brotli | 高 | 资源受限环境 | +| 迷你版 | Brotli | 最高 | 极致体积要求 | + +### 🚀 快速构建 + ```bash +# 构建所有平台(标准版,GZip压缩) npm run build -``` -### 构建特定平台 +# 构建优化版本(推荐,包含多种压缩选项) +npm run build:optimized -[打包工具pkg安装参考](https://www.jb51.net/javascript/329845uie.htm) +# 构建迷你版本(最小体积,所有平台) +npm run build:mini +``` + +### 🎯 平台特定构建 +#### 标准版本(GZip 压缩) ```bash # Windows x64 npm run build:win -# Linux x64 +# Linux x64 npm run build:linux # macOS x64 @@ -99,6 +140,114 @@ npm run build:macos npm run build:macos-arm ``` +#### Brotli 压缩版本(更小体积) +```bash +# Windows x64 +npm run build:win:brotli + +# Linux x64 +npm run build:linux:brotli + +# macOS x64 +npm run build:macos:brotli + +# macOS ARM64 +npm run build:macos-arm:brotli +``` + +#### 轻量版本(优化选项) +```bash +# Windows x64 +npm run build:win:lite + +# Linux x64 +npm run build:linux:lite + +# macOS x64 +npm run build:macos:lite + +# macOS ARM64 +npm run build:macos-arm:lite +``` + +#### 迷你版本(最小体积) +```bash +# Windows x64 +npm run build:win:mini + +# Linux x64 +npm run build:linux:mini + +# macOS x64 +npm run build:macos:mini + +# macOS ARM64 +npm run build:macos-arm:mini +``` + +### ⚙️ 构建优化技术 + +项目采用了多种优化技术来减小打包体积: + +1. **压缩算法**: + - **GZip**:标准压缩,兼容性好 + - **Brotli**:更高压缩率,体积减少 10-15% + +2. **PKG 优化选项**: + - `--no-bytecode`:禁用字节码缓存 + - `--public-packages=*`:减少包装开销 + - `--no-warnings`:减少输出体积 + +3. **资源排除**: + - 通过 `.pkgignore` 排除开发、测试、文档文件 + - 排除大型依赖的非必要部分 + - 智能排除开发环境专用模块 + +4. **智能配置**: + - 生产环境自动禁用 `pino-pretty` 日志美化 + - 动态检测运行环境,优化资源加载 + +### 📊 体积对比 + +以 Windows x64 版本为例: + +| 版本类型 | 文件大小 | 压缩率 | 说明 | +|----------|----------|--------|------| +| 标准版 | ~46 MB | - | GZip 压缩 | +| Brotli版 | ~44 MB | -4% | Brotli 压缩 | +| 轻量版 | ~42 MB | -9% | Brotli + 优化选项 | +| 迷你版 | ~41 MB | -11% | 最大优化 | + +### 🛠️ 高级构建 + +如需更多自定义选项,可以使用优化构建脚本: + +```bash +# 运行优化构建脚本(包含所有选项) +node build-optimized.js + +# 查看详细构建指南 +cat docs/BUILD_GUIDE.md +``` + +### 📋 构建要求 + +[打包工具pkg安装参考](https://www.jb51.net/javascript/329845uie.htm) + +**系统要求**: +- Node.js >= 18.0.0 +- npm 或 yarn +- 足够的磁盘空间(构建过程需要约 200MB 临时空间) + +**依赖安装**: +```bash +# 安装构建依赖 +npm install + +# 全局安装 pkg(可选,项目已包含) +npm install -g pkg +``` + 构建完成后,二进制文件将输出到 `dist/` 目录。 ## API 接口 @@ -304,15 +453,47 @@ npm test 3. 尝试使用自定义正则表达式 4. 启用调试模式查看详细日志 -## 开发 +## 📚 文档 + +- [API 文档](docs/API_DOCS.md) - 详细的 API 接口说明 +- [构建指南](docs/BUILD_GUIDE.md) - 完整的构建配置和优化说明 + +## 🔧 开发 项目采用 CommonJS 模块化开发,主要文件: - `sniffer.cjs`: 核心嗅探类 -- `server.cjs`: Fastify 服务器 +- `server.cjs`: Fastify 服务器 - `test.js`: 测试脚本 - `package.json`: 项目配置 +- `build-optimized.js`: 优化构建脚本 +- `.pkgignore`: 打包排除文件配置 + +### 开发环境设置 + +```bash +# 克隆项目 +git clone +cd pup-sniffer + +# 安装依赖 +npm install + +# 启动开发服务器 +npm start + +# 运行测试 +npm test +``` + +### 代码贡献 + +1. Fork 项目 +2. 创建特性分支 (`git checkout -b feature/AmazingFeature`) +3. 提交更改 (`git commit -m 'Add some AmazingFeature'`) +4. 推送到分支 (`git push origin feature/AmazingFeature`) +5. 打开 Pull Request -## 许可证 +## 📄 许可证 MIT License \ No newline at end of file From 9e3518dad687686fbb204f7bb038b62b9f90d739 Mon Sep 17 00:00:00 2001 From: Taois Date: Tue, 7 Oct 2025 05:22:05 +0800 Subject: [PATCH 6/9] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8D=E5=97=85=E6=8E=A2?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E9=97=AE=E9=A2=98=E5=8F=8A=E5=97=85=E6=8E=A2?= =?UTF-8?q?=E8=BF=87=E7=A8=8B=E8=BD=AF=E4=BB=B6=E5=B4=A9=E6=BA=83=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sniffer.cjs | 121 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 103 insertions(+), 18 deletions(-) diff --git a/sniffer.cjs b/sniffer.cjs index 4b6375f..4076195 100644 --- a/sniffer.cjs +++ b/sniffer.cjs @@ -42,6 +42,33 @@ class Sniffer { } } + /** + * 安全的 page.evaluate 调用,处理执行上下文销毁的情况 + */ + async safeEvaluate(page, pageFunction, ...args) { + try { + // 检查页面是否已关闭 + if (page.isClosed()) { + this.log('页面已关闭,跳过 evaluate 调用'); + return null; + } + + return await page.evaluate(pageFunction, ...args); + } catch (error) { + // 处理执行上下文销毁错误 + if (error.message.includes('Execution context was destroyed') || + error.message.includes('Cannot find context') || + error.message.includes('Target closed')) { + this.log('执行上下文已销毁,安全跳过 evaluate 调用:', error.message); + return null; + } + + // 其他错误继续抛出 + this.log('evaluate 调用发生错误:', error.message); + throw error; + } + } + /** * 检查是否可以进行 HEAD 请求 */ @@ -363,7 +390,7 @@ class Sniffer { // 执行页面脚本 if (script) { try { - await page.evaluate(script); + await this.safeEvaluate(page, script); this.log(`网页加载完成后成功执行脚本: ${script}`); } catch (e) { this.log(`网页加载完成后执行脚本发生错误: ${e.message}`); @@ -403,6 +430,11 @@ class Sniffer { const headUrls = []; // 已经 head 请求过的链接 const page = await this.getPage(headers); + // 外部变量保存嗅探结果,避免依赖页面上下文 + let externalRealUrl = ''; + let externalRealHeaders = {}; + let sniffingSuccess = false; + let actualTimeout = timeout || this.timeout; if (mode === 1) { actualTimeout = Math.min(actualTimeout, this.timeout); @@ -412,12 +444,19 @@ class Sniffer { // 请求拦截器 const onRequest = async (request) => { - const url = request.url(); - const method = request.method(); - const requestHeaders = request.headers(); - const resourceType = request.resourceType(); - - this.log('on_request:', url, ' method:', method, ' resource_type:', resourceType); + try { + // 检查页面是否已关闭 + if (page.isClosed()) { + this.log('页面已关闭,跳过请求处理'); + return false; + } + + const url = request.url(); + const method = request.method(); + const requestHeaders = request.headers(); + const resourceType = request.resourceType(); + + this.log('on_request:', url, ' method:', method, ' resource_type:', resourceType); // 检查排除正则 if (snifferExclude && new RegExp(snifferExclude, 'mi').test(url)) { @@ -432,7 +471,13 @@ class Sniffer { realUrls.push({ url, headers: _headers }); - await page.evaluate(([url, _headers, realUrls]) => { + // 保存到外部变量 + externalRealUrl = url; + externalRealHeaders = _headers; + sniffingSuccess = true; + + // 尝试设置页面变量(可能失败但不影响结果) + await this.safeEvaluate(page, ([url, _headers, realUrls]) => { window.realUrl = url; window.realHeaders = _headers; window.realUrls = realUrls; @@ -457,7 +502,13 @@ class Sniffer { realUrls.push({ url, headers: _headers }); - await page.evaluate(([url, _headers, realUrls]) => { + // 保存到外部变量 + externalRealUrl = url; + externalRealHeaders = _headers; + sniffingSuccess = true; + + // 尝试设置页面变量(可能失败但不影响结果) + await this.safeEvaluate(page, ([url, _headers, realUrls]) => { window.realUrl = url; window.realHeaders = _headers; window.realUrls = realUrls; @@ -501,7 +552,13 @@ class Sniffer { realUrls.push({ url, headers: _headers }); - await page.evaluate(([url, _headers, realUrls]) => { + // 保存到外部变量 + externalRealUrl = url; + externalRealHeaders = _headers; + sniffingSuccess = true; + + // 尝试设置页面变量(可能失败但不影响结果) + await this.safeEvaluate(page, ([url, _headers, realUrls]) => { window.realUrl = url; window.realHeaders = _headers; window.realUrls = realUrls; @@ -526,6 +583,19 @@ class Sniffer { } return false; + } catch (error) { + // 全局错误处理 + if (error.message.includes('Execution context was destroyed') || + error.message.includes('Cannot find context') || + error.message.includes('Target closed') || + error.message.includes('Page closed')) { + this.log('请求处理过程中页面上下文已销毁,安全跳过:', error.message); + return false; + } + + this.log('请求处理过程中发生错误:', error.message); + return false; + } }; // 监听请求 @@ -539,7 +609,7 @@ class Sniffer { await page.exposeFunction('log', (...args) => console.log(...args)); // 初始化页面变量 - await page.evaluate(() => { + await this.safeEvaluate(page, () => { window.realUrl = ''; window.realHeaders = {}; window.realUrls = []; @@ -598,7 +668,7 @@ class Sniffer { `; await page.evaluateOnNewDocument(jsCode); - await page.evaluate(jsCode); + await this.safeEvaluate(page, jsCode); this.log(`网页加载完成后成功执行脚本: ${script}`); } catch (e) { this.log(`网页加载完成后执行脚本发生错误: ${e.message}`); @@ -610,10 +680,18 @@ class Sniffer { // 等待结果 if (mode === 0) { try { - await page.waitForFunction(() => window.realUrl, { timeout: actualTimeout }); + // 优先检查外部变量,如果已经有结果就不需要等待 + if (!sniffingSuccess) { + await page.waitForFunction(() => window.realUrl, { timeout: actualTimeout }); + } else { + this.log('外部变量已有嗅探结果,跳过等待'); + } } catch (e) { this.log(`page.waitForFunction window.realUrl 发生了错误: ${e.message}`); - isTimeout = true; + // 即使等待失败,也检查外部变量是否有结果 + if (!sniffingSuccess) { + isTimeout = true; + } } } else if (mode === 1) { try { @@ -624,10 +702,17 @@ class Sniffer { } } - // 获取结果 - const realUrl = await page.evaluate(() => window.realUrl); - const realHeaders = await page.evaluate(() => window.realHeaders); - const realUrlsResult = await page.evaluate(() => window.realUrls); + // 获取结果 - 优先使用外部变量 + let realUrl = externalRealUrl || ''; + let realHeaders = externalRealHeaders || {}; + let realUrlsResult = realUrls || []; + + // 如果外部变量没有结果,再尝试从页面获取 + if (!realUrl) { + realUrl = await this.safeEvaluate(page, () => window.realUrl) || ''; + realHeaders = await this.safeEvaluate(page, () => window.realHeaders) || {}; + realUrlsResult = await this.safeEvaluate(page, () => window.realUrls) || []; + } const cost = Date.now() - startTime; const costStr = `${cost} ms`; From 968e621e8a7bd0d3ea454d1e19c9af6a263b2856 Mon Sep 17 00:00:00 2001 From: Taois Date: Wed, 8 Oct 2025 17:27:39 +0800 Subject: [PATCH 7/9] =?UTF-8?q?docs:=E4=BF=AE=E6=94=B9=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8F=B7=E5=87=86=E5=A4=87=E6=89=93=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 31dcd40..e43538d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pup-sniffer", - "version": "1.0.1", + "version": "1.0.2", "description": "Video resource sniffer using Puppeteer and Fastify", "main": "server.cjs", "bin": "server.cjs", From f4aad8b871317053d0be7f37928d6c448709afc6 Mon Sep 17 00:00:00 2001 From: Taois Date: Mon, 13 Oct 2025 23:49:29 +0800 Subject: [PATCH 8/9] =?UTF-8?q?docs:=E5=A2=9E=E5=8A=A0pkg=E5=AE=89?= =?UTF-8?q?=E8=A3=85=E6=8C=87=E5=8D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 139 +- package-lock.json | 3304 --------------------------------------------- 2 files changed, 85 insertions(+), 3358 deletions(-) delete mode 100644 package-lock.json diff --git a/README.md b/README.md index f476ec0..550a285 100644 --- a/README.md +++ b/README.md @@ -46,10 +46,10 @@ ### 方式一:使用二进制文件(推荐) 1. 下载对应平台的二进制文件: - - Windows: `pup-sniffer-win.exe` - - Linux: `pup-sniffer-linux` - - macOS (Intel): `pup-sniffer-macos` - - macOS (Apple Silicon): `pup-sniffer-macos-arm64` + - Windows: `pup-sniffer-win.exe` + - Linux: `pup-sniffer-linux` + - macOS (Intel): `pup-sniffer-macos` + - macOS (Apple Silicon): `pup-sniffer-macos-arm64` 2. 将 `demo.html` 文件放在二进制文件同一目录下 @@ -103,12 +103,12 @@ ### 📦 构建选项概览 -| 构建类型 | 压缩算法 | 体积优化 | 适用场景 | -|----------|----------|----------|----------| -| 标准版 | GZip | 中等 | 通用部署 | -| Brotli版 | Brotli | 较高 | 网络传输优化 | -| 轻量版 | Brotli | 高 | 资源受限环境 | -| 迷你版 | Brotli | 最高 | 极致体积要求 | +| 构建类型 | 压缩算法 | 体积优化 | 适用场景 | +|---------|--------|------|--------| +| 标准版 | GZip | 中等 | 通用部署 | +| Brotli版 | Brotli | 较高 | 网络传输优化 | +| 轻量版 | Brotli | 高 | 资源受限环境 | +| 迷你版 | Brotli | 最高 | 极致体积要求 | ### 🚀 快速构建 @@ -126,6 +126,7 @@ npm run build:mini ### 🎯 平台特定构建 #### 标准版本(GZip 压缩) + ```bash # Windows x64 npm run build:win @@ -141,6 +142,7 @@ npm run build:macos-arm ``` #### Brotli 压缩版本(更小体积) + ```bash # Windows x64 npm run build:win:brotli @@ -156,6 +158,7 @@ npm run build:macos-arm:brotli ``` #### 轻量版本(优化选项) + ```bash # Windows x64 npm run build:win:lite @@ -171,6 +174,7 @@ npm run build:macos-arm:lite ``` #### 迷你版本(最小体积) + ```bash # Windows x64 npm run build:win:mini @@ -190,33 +194,33 @@ npm run build:macos-arm:mini 项目采用了多种优化技术来减小打包体积: 1. **压缩算法**: - - **GZip**:标准压缩,兼容性好 - - **Brotli**:更高压缩率,体积减少 10-15% + - **GZip**:标准压缩,兼容性好 + - **Brotli**:更高压缩率,体积减少 10-15% 2. **PKG 优化选项**: - - `--no-bytecode`:禁用字节码缓存 - - `--public-packages=*`:减少包装开销 - - `--no-warnings`:减少输出体积 + - `--no-bytecode`:禁用字节码缓存 + - `--public-packages=*`:减少包装开销 + - `--no-warnings`:减少输出体积 3. **资源排除**: - - 通过 `.pkgignore` 排除开发、测试、文档文件 - - 排除大型依赖的非必要部分 - - 智能排除开发环境专用模块 + - 通过 `.pkgignore` 排除开发、测试、文档文件 + - 排除大型依赖的非必要部分 + - 智能排除开发环境专用模块 4. **智能配置**: - - 生产环境自动禁用 `pino-pretty` 日志美化 - - 动态检测运行环境,优化资源加载 + - 生产环境自动禁用 `pino-pretty` 日志美化 + - 动态检测运行环境,优化资源加载 ### 📊 体积对比 以 Windows x64 版本为例: -| 版本类型 | 文件大小 | 压缩率 | 说明 | -|----------|----------|--------|------| -| 标准版 | ~46 MB | - | GZip 压缩 | -| Brotli版 | ~44 MB | -4% | Brotli 压缩 | -| 轻量版 | ~42 MB | -9% | Brotli + 优化选项 | -| 迷你版 | ~41 MB | -11% | 最大优化 | +| 版本类型 | 文件大小 | 压缩率 | 说明 | +|---------|--------|------|---------------| +| 标准版 | ~46 MB | - | GZip 压缩 | +| Brotli版 | ~44 MB | -4% | Brotli 压缩 | +| 轻量版 | ~42 MB | -9% | Brotli + 优化选项 | +| 迷你版 | ~41 MB | -11% | 最大优化 | ### 🛠️ 高级构建 @@ -234,12 +238,26 @@ cat docs/BUILD_GUIDE.md [打包工具pkg安装参考](https://www.jb51.net/javascript/329845uie.htm) +[各版本二进制下载地址](https://github.com/vercel/pkg-fetch/releases) + +linux命令安装方法 + +``` +cd /root/.pkg-cache +wget -O fetched-v18.5.0-linux-x64 https://github.catvod.com/https://github.com/vercel/pkg-fetch/releases/download/v3.4/node-v18.5.0-linux-x64 +npm run build:linux:mini +cd dist +./pup-sniffer-linux-mini +``` + **系统要求**: + - Node.js >= 18.0.0 - npm 或 yarn - 足够的磁盘空间(构建过程需要约 200MB 临时空间) **依赖安装**: + ```bash # 安装构建依赖 npm install @@ -258,18 +276,18 @@ npm install -g pkg #### 请求参数 -| 参数 | 类型 | 必需 | 说明 | -|------|------|------|------| -| url | string | ✅ | 要嗅探的页面 URL | -| mode | string | ❌ | 嗅探模式:0=单个链接,1=多个链接(默认:0) | -| is_pc | string | ❌ | 是否模拟 PC:0=移动设备,1=PC(默认:0) | -| timeout | string | ❌ | 超时时间(毫秒,默认:10000) | -| css | string | ❌ | 等待的 CSS 选择器 | -| script | string | ❌ | 页面执行脚本(Base64 编码) | -| init_script | string | ❌ | 页面初始化脚本(Base64 编码) | -| headers | string | ❌ | 自定义请求头(换行分隔) | -| custom_regex | string | ❌ | 自定义匹配正则表达式 | -| sniffer_exclude | string | ❌ | 排除匹配的正则表达式 | +| 参数 | 类型 | 必需 | 说明 | +|-----------------|--------|----|---------------------------| +| url | string | ✅ | 要嗅探的页面 URL | +| mode | string | ❌ | 嗅探模式:0=单个链接,1=多个链接(默认:0) | +| is_pc | string | ❌ | 是否模拟 PC:0=移动设备,1=PC(默认:0) | +| timeout | string | ❌ | 超时时间(毫秒,默认:10000) | +| css | string | ❌ | 等待的 CSS 选择器 | +| script | string | ❌ | 页面执行脚本(Base64 编码) | +| init_script | string | ❌ | 页面初始化脚本(Base64 编码) | +| headers | string | ❌ | 自定义请求头(换行分隔) | +| custom_regex | string | ❌ | 自定义匹配正则表达式 | +| sniffer_exclude | string | ❌ | 排除匹配的正则表达式 | #### 响应示例 @@ -298,15 +316,15 @@ npm install -g pkg #### 请求参数 -| 参数 | 类型 | 必需 | 说明 | -|------|------|------|------| -| url | string | ✅ | 要获取源码的页面 URL | -| is_pc | string | ❌ | 是否模拟 PC:0=移动设备,1=PC(默认:0) | -| timeout | string | ❌ | 超时时间(毫秒,默认:10000) | -| css | string | ❌ | 等待的 CSS 选择器 | -| script | string | ❌ | 页面执行脚本(Base64 编码) | -| init_script | string | ❌ | 页面初始化脚本(Base64 编码) | -| headers | string | ❌ | 自定义请求头(换行分隔) | +| 参数 | 类型 | 必需 | 说明 | +|-------------|--------|----|---------------------------| +| url | string | ✅ | 要获取源码的页面 URL | +| is_pc | string | ❌ | 是否模拟 PC:0=移动设备,1=PC(默认:0) | +| timeout | string | ❌ | 超时时间(毫秒,默认:10000) | +| css | string | ❌ | 等待的 CSS 选择器 | +| script | string | ❌ | 页面执行脚本(Base64 编码) | +| init_script | string | ❌ | 页面初始化脚本(Base64 编码) | +| headers | string | ❌ | 自定义请求头(换行分隔) | #### 响应示例 @@ -409,20 +427,21 @@ npm test ## 命令行参数 -| 参数 | 说明 | 示例 | -|------|------|------| +| 参数 | 说明 | 示例 | +|---------------|--------------------|--------------| | `-port <端口号>` | 指定服务器端口号 (1-65535) | `-port 8080` | -| `-h, --help` | 显示帮助信息 | `--help` | +| `-h, --help` | 显示帮助信息 | `--help` | **端口说明**: + - 如果不指定端口号,程序将从 57573 开始自动查找可用端口 - 如果指定的端口被占用,程序会报错并退出 - 端口号必须在 1-65535 范围内 ## 环境变量 -| 变量 | 说明 | 默认值 | -|------|------|--------| +| 变量 | 说明 | 默认值 | +|------|--------|---------| | HOST | 服务主机地址 | 0.0.0.0 | **注意**: 端口配置请使用 `-port` 命令行参数,不支持通过环境变量设置端口。 @@ -453,6 +472,18 @@ npm test 3. 尝试使用自定义正则表达式 4. 启用调试模式查看详细日志 +### linux使用前置条件 + +```shell +# 安装谷歌浏览器 +apt update +wget -O google-chrome-104.deb -c https://www.slimjet.com/chrome/download-chrome.php?file=files%2F104.0.5112.102%2Fgoogle-chrome-stable_current_amd64.deb +dpkg -i google-chrome-104.deb +apt install -f +dpkg -i google-chrome-104.deb +google-chrome --version +``` + ## 📚 文档 - [API 文档](docs/API_DOCS.md) - 详细的 API 接口说明 @@ -463,7 +494,7 @@ npm test 项目采用 CommonJS 模块化开发,主要文件: - `sniffer.cjs`: 核心嗅探类 -- `server.cjs`: Fastify 服务器 +- `server.cjs`: Fastify 服务器 - `test.js`: 测试脚本 - `package.json`: 项目配置 - `build-optimized.js`: 优化构建脚本 @@ -473,7 +504,7 @@ npm test ```bash # 克隆项目 -git clone +git clone https://github.com/hjdhnx/pup-sniffer.git cd pup-sniffer # 安装依赖 diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index daafeb4..0000000 --- a/package-lock.json +++ /dev/null @@ -1,3304 +0,0 @@ -{ - "name": "pup-sniffer", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "pup-sniffer", - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@fastify/cors": "^8.4.0", - "@fastify/static": "^6.12.0", - "fastify": "^4.24.3", - "pino-pretty": "^13.1.1", - "puppeteer": "^21.6.1" - }, - "devDependencies": { - "@types/node": "^20.10.0", - "pkg": "^5.8.1", - "rimraf": "^6.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.18.2", - "resolved": "https://registry.npmmirror.com/@babel/generator/-/generator-7.18.2.tgz", - "integrity": "sha512-W1lG5vUwFvfMd8HVXqdfbuG7RuaSrTCCD8cl8fP8wOivdbtbIg2Db3IWUcgvfxKbbn6ZBGYRW/Zk1MIwK49mgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.18.2", - "@jridgewell/gen-mapping": "^0.3.0", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.18.4", - "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.18.4.tgz", - "integrity": "sha512-FDge0dFazETFcxGw/EXzOkN8uJp0PC7Qbm+Pe9T+av2zlBpOgunFHkQPPn+eRuClU73JF+98D531UgayY89tow==", - "dev": true, - "license": "MIT", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@fastify/accept-negotiator": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/@fastify/ajv-compiler": { - "version": "3.6.0", - "license": "MIT", - "dependencies": { - "ajv": "^8.11.0", - "ajv-formats": "^2.1.1", - "fast-uri": "^2.0.0" - } - }, - "node_modules/@fastify/cors": { - "version": "8.5.0", - "license": "MIT", - "dependencies": { - "fastify-plugin": "^4.0.0", - "mnemonist": "0.39.6" - } - }, - "node_modules/@fastify/error": { - "version": "3.4.1", - "license": "MIT" - }, - "node_modules/@fastify/fast-json-stringify-compiler": { - "version": "4.3.0", - "license": "MIT", - "dependencies": { - "fast-json-stringify": "^5.7.0" - } - }, - "node_modules/@fastify/merge-json-schemas": { - "version": "0.1.1", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - } - }, - "node_modules/@fastify/send": { - "version": "2.1.0", - "license": "MIT", - "dependencies": { - "@lukeed/ms": "^2.0.1", - "escape-html": "~1.0.3", - "fast-decode-uri-component": "^1.0.1", - "http-errors": "2.0.0", - "mime": "^3.0.0" - } - }, - "node_modules/@fastify/static": { - "version": "6.12.0", - "license": "MIT", - "dependencies": { - "@fastify/accept-negotiator": "^1.0.0", - "@fastify/send": "^2.0.0", - "content-disposition": "^0.5.3", - "fastify-plugin": "^4.0.0", - "glob": "^8.0.1", - "p-limit": "^3.1.0" - } - }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmmirror.com/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmmirror.com/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@lukeed/ms": { - "version": "2.0.2", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@puppeteer/browsers": { - "version": "1.9.1", - "license": "Apache-2.0", - "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.3.1", - "tar-fs": "3.0.4", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.2" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=16.3.0" - } - }, - "node_modules/@tootallnate/quickjs-emscripten": { - "version": "0.23.0", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "20.19.19", - "devOptional": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "license": "MIT", - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/abstract-logging": { - "version": "2.0.1", - "license": "MIT" - }, - "node_modules/agent-base": { - "version": "7.1.4", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ajv": { - "version": "8.17.1", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "2.1.1", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/ajv/node_modules/fast-uri": { - "version": "3.1.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "license": "Python-2.0" - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ast-types": { - "version": "0.13.4", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/atomic-sleep": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/avvio": { - "version": "8.4.0", - "license": "MIT", - "dependencies": { - "@fastify/error": "^3.3.0", - "fastq": "^1.17.1" - } - }, - "node_modules/b4a": { - "version": "1.7.3", - "license": "Apache-2.0", - "peerDependencies": { - "react-native-b4a": "*" - }, - "peerDependenciesMeta": { - "react-native-b4a": { - "optional": true - } - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "license": "MIT" - }, - "node_modules/bare-events": { - "version": "2.7.0", - "license": "Apache-2.0" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/basic-ftp": { - "version": "5.0.5", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/brace-expansion": { - "version": "2.0.2", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true, - "license": "ISC" - }, - "node_modules/chromium-bidi": { - "version": "0.5.8", - "license": "Apache-2.0", - "dependencies": { - "mitt": "3.0.1", - "urlpattern-polyfill": "10.0.0" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "license": "MIT" - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmmirror.com/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.2", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cosmiconfig": { - "version": "9.0.0", - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/cross-fetch": { - "version": "4.0.0", - "license": "MIT", - "dependencies": { - "node-fetch": "^2.6.12" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/data-uri-to-buffer": { - "version": "6.0.2", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/dateformat": { - "version": "4.6.3", - "resolved": "https://registry.npmmirror.com/dateformat/-/dateformat-4.6.3.tgz", - "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmmirror.com/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/degenerator": { - "version": "5.0.1", - "license": "MIT", - "dependencies": { - "ast-types": "^0.13.4", - "escodegen": "^2.1.0", - "esprima": "^4.0.1" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/detect-libc": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.1.tgz", - "integrity": "sha512-ecqj/sy1jcK1uWrwpR67UhYrIFQ+5WlGxth34WquCbamhFA6hkkwiu37o6J5xCHdo1oixJRfVRw+ywV+Hq/0Aw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/devtools-protocol": { - "version": "0.0.1232444", - "license": "BSD-3-Clause" - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmmirror.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "license": "MIT" - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/error-ex": { - "version": "1.3.4", - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "license": "MIT" - }, - "node_modules/escodegen": { - "version": "2.1.0", - "license": "BSD-2-Clause", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/events-universal": { - "version": "1.0.1", - "license": "Apache-2.0", - "dependencies": { - "bare-events": "^2.7.0" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true, - "license": "(MIT OR WTFPL)", - "engines": { - "node": ">=6" - } - }, - "node_modules/extract-zip": { - "version": "2.0.1", - "license": "BSD-2-Clause", - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/fast-content-type-parse": { - "version": "1.1.0", - "license": "MIT" - }, - "node_modules/fast-copy": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/fast-copy/-/fast-copy-3.0.2.tgz", - "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", - "license": "MIT" - }, - "node_modules/fast-decode-uri-component": { - "version": "1.0.1", - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "license": "MIT" - }, - "node_modules/fast-fifo": { - "version": "1.3.2", - "license": "MIT" - }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-json-stringify": { - "version": "5.16.1", - "license": "MIT", - "dependencies": { - "@fastify/merge-json-schemas": "^0.1.0", - "ajv": "^8.10.0", - "ajv-formats": "^3.0.1", - "fast-deep-equal": "^3.1.3", - "fast-uri": "^2.1.0", - "json-schema-ref-resolver": "^1.0.1", - "rfdc": "^1.2.0" - } - }, - "node_modules/fast-json-stringify/node_modules/ajv-formats": { - "version": "3.0.1", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/fast-querystring": { - "version": "1.1.2", - "license": "MIT", - "dependencies": { - "fast-decode-uri-component": "^1.0.1" - } - }, - "node_modules/fast-safe-stringify": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", - "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "2.4.0", - "license": "MIT" - }, - "node_modules/fastify": { - "version": "4.29.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT", - "dependencies": { - "@fastify/ajv-compiler": "^3.5.0", - "@fastify/error": "^3.4.0", - "@fastify/fast-json-stringify-compiler": "^4.3.0", - "abstract-logging": "^2.0.1", - "avvio": "^8.3.0", - "fast-content-type-parse": "^1.1.0", - "fast-json-stringify": "^5.8.0", - "find-my-way": "^8.0.0", - "light-my-request": "^5.11.0", - "pino": "^9.0.0", - "process-warning": "^3.0.0", - "proxy-addr": "^2.0.7", - "rfdc": "^1.3.0", - "secure-json-parse": "^2.7.0", - "semver": "^7.5.4", - "toad-cache": "^3.3.0" - } - }, - "node_modules/fastify-plugin": { - "version": "4.5.1", - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.19.1", - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-my-way": { - "version": "8.2.2", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-querystring": "^1.0.0", - "safe-regex2": "^3.1.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmmirror.com/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/from2": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/from2/-/from2-2.3.0.tgz", - "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "license": "MIT" - }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "license": "ISC" - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-stream": { - "version": "5.2.0", - "license": "MIT", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-uri": { - "version": "6.0.5", - "license": "MIT", - "dependencies": { - "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^6.0.2", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmmirror.com/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "dev": true, - "license": "MIT" - }, - "node_modules/glob": { - "version": "8.1.0", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmmirror.com/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/help-me": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/help-me/-/help-me-5.0.0.tgz", - "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", - "license": "MIT" - }, - "node_modules/http-errors": { - "version": "2.0.0", - "license": "MIT", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmmirror.com/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "license": "ISC" - }, - "node_modules/into-stream": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/into-stream/-/into-stream-6.0.0.tgz", - "integrity": "sha512-XHbaOAvP+uFKUFsOgoNPRjLkwB+I22JFPFe5OjTkQ0nwgj6+pSjb4NmB6VMxaPshLiOf+zcpOCBQuLwC1KHhZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "from2": "^2.3.0", - "p-is-promise": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ip-address": { - "version": "10.0.1", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "license": "MIT" - }, - "node_modules/is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/jackspeak": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/jackspeak/-/jackspeak-4.1.1.tgz", - "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/joycon": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "license": "MIT" - }, - "node_modules/json-schema-ref-resolver": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/light-my-request": { - "version": "5.14.0", - "license": "BSD-3-Clause", - "dependencies": { - "cookie": "^0.7.0", - "process-warning": "^3.0.0", - "set-cookie-parser": "^2.4.1" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "7.18.3", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "3.0.0", - "license": "MIT", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "5.1.6", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/mitt": { - "version": "3.0.1", - "license": "MIT" - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "license": "MIT" - }, - "node_modules/mnemonist": { - "version": "0.39.6", - "license": "MIT", - "dependencies": { - "obliterator": "^2.0.1" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "license": "MIT" - }, - "node_modules/multistream": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/multistream/-/multistream-4.1.0.tgz", - "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "once": "^1.4.0", - "readable-stream": "^3.6.0" - } - }, - "node_modules/multistream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true, - "license": "MIT" - }, - "node_modules/netmask": { - "version": "2.0.2", - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/node-abi": { - "version": "3.77.0", - "resolved": "https://registry.npmmirror.com/node-abi/-/node-abi-3.77.0.tgz", - "integrity": "sha512-DSmt0OEcLoK4i3NuscSbGjOf3bqiDEutejqENSplMSFA/gmB8mkED9G4pKWnPl7MDU4rSHebKPHeitpDfyH0cQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/obliterator": { - "version": "2.0.5", - "license": "MIT" - }, - "node_modules/on-exit-leak-free": { - "version": "2.1.2", - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-is-promise": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/p-is-promise/-/p-is-promise-3.0.0.tgz", - "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pac-proxy-agent": { - "version": "7.2.0", - "license": "MIT", - "dependencies": { - "@tootallnate/quickjs-emscripten": "^0.23.0", - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "get-uri": "^6.0.1", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.6", - "pac-resolver": "^7.0.1", - "socks-proxy-agent": "^8.0.5" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/pac-resolver": { - "version": "7.0.1", - "license": "MIT", - "dependencies": { - "degenerator": "^5.0.0", - "netmask": "^2.0.2" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/path-scurry/-/path-scurry-2.0.0.tgz", - "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.2.2", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-11.2.2.tgz", - "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pino": { - "version": "9.12.0", - "license": "MIT", - "dependencies": { - "atomic-sleep": "^1.0.0", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^2.0.0", - "pino-std-serializers": "^7.0.0", - "process-warning": "^5.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.2.0", - "safe-stable-stringify": "^2.3.1", - "slow-redact": "^0.3.0", - "sonic-boom": "^4.0.1", - "thread-stream": "^3.0.0" - }, - "bin": { - "pino": "bin.js" - } - }, - "node_modules/pino-abstract-transport": { - "version": "2.0.0", - "license": "MIT", - "dependencies": { - "split2": "^4.0.0" - } - }, - "node_modules/pino-pretty": { - "version": "13.1.1", - "resolved": "https://registry.npmmirror.com/pino-pretty/-/pino-pretty-13.1.1.tgz", - "integrity": "sha512-TNNEOg0eA0u+/WuqH0MH0Xui7uqVk9D74ESOpjtebSQYbNWJk/dIxCXIxFsNfeN53JmtWqYHP2OrIZjT/CBEnA==", - "license": "MIT", - "dependencies": { - "colorette": "^2.0.7", - "dateformat": "^4.6.3", - "fast-copy": "^3.0.2", - "fast-safe-stringify": "^2.1.1", - "help-me": "^5.0.0", - "joycon": "^3.1.1", - "minimist": "^1.2.6", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^2.0.0", - "pump": "^3.0.0", - "secure-json-parse": "^4.0.0", - "sonic-boom": "^4.0.1", - "strip-json-comments": "^5.0.2" - }, - "bin": { - "pino-pretty": "bin.js" - } - }, - "node_modules/pino-pretty/node_modules/secure-json-parse": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/secure-json-parse/-/secure-json-parse-4.0.0.tgz", - "integrity": "sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/pino-std-serializers": { - "version": "7.0.0", - "license": "MIT" - }, - "node_modules/pino/node_modules/process-warning": { - "version": "5.0.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "MIT" - }, - "node_modules/pkg": { - "version": "5.8.1", - "resolved": "https://registry.npmmirror.com/pkg/-/pkg-5.8.1.tgz", - "integrity": "sha512-CjBWtFStCfIiT4Bde9QpJy0KeH19jCfwZRJqHFDFXfhUklCx8JoFmMj3wgnEYIwGmZVNkhsStPHEOnrtrQhEXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/generator": "7.18.2", - "@babel/parser": "7.18.4", - "@babel/types": "7.19.0", - "chalk": "^4.1.2", - "fs-extra": "^9.1.0", - "globby": "^11.1.0", - "into-stream": "^6.0.0", - "is-core-module": "2.9.0", - "minimist": "^1.2.6", - "multistream": "^4.1.0", - "pkg-fetch": "3.4.2", - "prebuild-install": "7.1.1", - "resolve": "^1.22.0", - "stream-meter": "^1.0.4" - }, - "bin": { - "pkg": "lib-es5/bin.js" - }, - "peerDependencies": { - "node-notifier": ">=9.0.1" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/pkg-fetch": { - "version": "3.4.2", - "resolved": "https://registry.npmmirror.com/pkg-fetch/-/pkg-fetch-3.4.2.tgz", - "integrity": "sha512-0+uijmzYcnhC0hStDjm/cl2VYdrmVVBpe7Q8k9YBojxmR5tG8mvR9/nooQq3QSXiQqORDVOTY3XqMEqJVIzkHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.1.2", - "fs-extra": "^9.1.0", - "https-proxy-agent": "^5.0.0", - "node-fetch": "^2.6.6", - "progress": "^2.0.3", - "semver": "^7.3.5", - "tar-fs": "^2.1.1", - "yargs": "^16.2.0" - }, - "bin": { - "pkg-fetch": "lib-es5/bin.js" - } - }, - "node_modules/pkg-fetch/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/pkg-fetch/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmmirror.com/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/pkg-fetch/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-fetch/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-fetch/node_modules/tar-fs": { - "version": "2.1.4", - "resolved": "https://registry.npmmirror.com/tar-fs/-/tar-fs-2.1.4.tgz", - "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/pkg-fetch/node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-fetch/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmmirror.com/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/pkg-fetch/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmmirror.com/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prebuild-install/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/prebuild-install/node_modules/tar-fs": { - "version": "2.1.4", - "resolved": "https://registry.npmmirror.com/tar-fs/-/tar-fs-2.1.4.tgz", - "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/prebuild-install/node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/process-warning": { - "version": "3.0.0", - "license": "MIT" - }, - "node_modules/progress": { - "version": "2.0.3", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-agent": { - "version": "6.3.1", - "license": "MIT", - "dependencies": { - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.0.1", - "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.2" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "license": "MIT" - }, - "node_modules/pump": { - "version": "3.0.3", - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/puppeteer": { - "version": "21.11.0", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@puppeteer/browsers": "1.9.1", - "cosmiconfig": "9.0.0", - "puppeteer-core": "21.11.0" - }, - "bin": { - "puppeteer": "lib/esm/puppeteer/node/cli.js" - }, - "engines": { - "node": ">=16.13.2" - } - }, - "node_modules/puppeteer-core": { - "version": "21.11.0", - "license": "Apache-2.0", - "dependencies": { - "@puppeteer/browsers": "1.9.1", - "chromium-bidi": "0.5.8", - "cross-fetch": "4.0.0", - "debug": "4.3.4", - "devtools-protocol": "0.0.1232444", - "ws": "8.16.0" - }, - "engines": { - "node": ">=16.13.2" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/quick-format-unescaped": { - "version": "4.0.4", - "license": "MIT" - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmmirror.com/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/real-require": { - "version": "0.2.0", - "license": "MIT", - "engines": { - "node": ">= 12.13.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve/node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/ret": { - "version": "0.4.3", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "license": "MIT" - }, - "node_modules/rimraf": { - "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-6.0.1.tgz", - "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^11.0.0", - "package-json-from-dist": "^1.0.0" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "11.0.3", - "resolved": "https://registry.npmmirror.com/glob/-/glob-11.0.3.tgz", - "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.3.1", - "jackspeak": "^4.1.1", - "minimatch": "^10.0.3", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "10.0.3", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-10.0.3.tgz", - "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", - "dev": true, - "license": "ISC", - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safe-regex2": { - "version": "3.1.0", - "license": "MIT", - "dependencies": { - "ret": "~0.4.0" - } - }, - "node_modules/safe-stable-stringify": { - "version": "2.5.0", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/secure-json-parse": { - "version": "2.7.0", - "license": "BSD-3-Clause" - }, - "node_modules/semver": { - "version": "7.7.2", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/set-cookie-parser": { - "version": "2.7.1", - "license": "MIT" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmmirror.com/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/slow-redact": { - "version": "0.3.0", - "license": "MIT" - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.7", - "license": "MIT", - "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "8.0.5", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/sonic-boom": { - "version": "4.2.0", - "license": "MIT", - "dependencies": { - "atomic-sleep": "^1.0.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "license": "BSD-3-Clause", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split2": { - "version": "4.2.0", - "license": "ISC", - "engines": { - "node": ">= 10.x" - } - }, - "node_modules/statuses": { - "version": "2.0.1", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stream-meter": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/stream-meter/-/stream-meter-1.0.4.tgz", - "integrity": "sha512-4sOEtrbgFotXwnEuzzsQBYEV1elAeFSO8rSGeTwabuX1RRn/kEq9JVH7I0MRBhKVRR0sJkr0M0QCH7yOLf9fhQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "readable-stream": "^2.1.4" - } - }, - "node_modules/streamx": { - "version": "2.23.0", - "license": "MIT", - "dependencies": { - "events-universal": "^1.0.0", - "fast-fifo": "^1.3.2", - "text-decoder": "^1.1.0" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width": { - "version": "4.2.3", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "5.0.3", - "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-5.0.3.tgz", - "integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==", - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tar-fs": { - "version": "3.0.4", - "license": "MIT", - "dependencies": { - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^3.1.5" - } - }, - "node_modules/tar-stream": { - "version": "3.1.7", - "license": "MIT", - "dependencies": { - "b4a": "^1.6.4", - "fast-fifo": "^1.2.0", - "streamx": "^2.15.0" - } - }, - "node_modules/text-decoder": { - "version": "1.2.3", - "license": "Apache-2.0", - "dependencies": { - "b4a": "^1.6.4" - } - }, - "node_modules/thread-stream": { - "version": "3.1.0", - "license": "MIT", - "dependencies": { - "real-require": "^0.2.0" - } - }, - "node_modules/through": { - "version": "2.3.8", - "license": "MIT" - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/toad-cache": { - "version": "3.7.0", - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "license": "MIT" - }, - "node_modules/tslib": { - "version": "2.8.1", - "license": "0BSD" - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmmirror.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/unbzip2-stream": { - "version": "1.4.3", - "license": "MIT", - "dependencies": { - "buffer": "^5.2.1", - "through": "^2.3.8" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "devOptional": true, - "license": "MIT" - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/urlpattern-polyfill": { - "version": "10.0.0", - "license": "MIT" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "license": "ISC" - }, - "node_modules/ws": { - "version": "8.16.0", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} From 60af836d8bc59937de046ae915dc39d55de992a9 Mon Sep 17 00:00:00 2001 From: Taois Date: Tue, 14 Oct 2025 03:13:45 +0800 Subject: [PATCH 9/9] =?UTF-8?q?fix:=E4=BF=AE=E5=A4=8D=E5=A7=8B=E7=BB=88?= =?UTF-8?q?=E6=98=AFlocalhost=E5=97=85=E6=8E=A2=E5=9C=B0=E5=9D=80=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo.html | 3 ++- package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/demo.html b/demo.html index 549ade3..0e82d13 100644 --- a/demo.html +++ b/demo.html @@ -452,7 +452,8 @@

📄 页面源码获取