From 38a9b5b81231ffde44e9c4478610c76930c2b36d Mon Sep 17 00:00:00 2001 From: Default User Date: Sat, 27 Dec 2025 14:20:24 +0800 Subject: [PATCH] Initial commit --- .gitignore | 9 + DEPLOYMENT.md | 294 ++ Dockerfile | 23 + Reject.html | 3871 +++++++++++++++++++++ Reject.js | 1369 ++++++++ deploy.sh | 111 + docker-compose.yml | 22 + health-check.sh | 106 + image-processor.js | 124 + login.html | 255 ++ oss-config.js | 8 + oss-uploader.js | 320 ++ package-lock.json | 5348 ++++++++++++++++++++++++++++++ package.json | 18 + supply-manager.example.js | 66 + supply-manager.js | 1113 +++++++ supply.html | 4892 +++++++++++++++++++++++++++ test-watermark-update.js | 63 + test-watermark.js | 61 + watermark-test-output.png | Bin 0 -> 91 bytes watermark-test-update-output.png | Bin 0 -> 91 bytes 21 files changed, 18073 insertions(+) create mode 100644 .gitignore create mode 100644 DEPLOYMENT.md create mode 100644 Dockerfile create mode 100644 Reject.html create mode 100644 Reject.js create mode 100644 deploy.sh create mode 100644 docker-compose.yml create mode 100644 health-check.sh create mode 100644 image-processor.js create mode 100644 login.html create mode 100644 oss-config.js create mode 100644 oss-uploader.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 supply-manager.example.js create mode 100644 supply-manager.js create mode 100644 supply.html create mode 100644 test-watermark-update.js create mode 100644 test-watermark.js create mode 100644 watermark-test-output.png create mode 100644 watermark-test-update-output.png diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dc18df1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +node_modules/ +*.log +.env +.DS_Store +Thumbs.db +*.swp +*.swo +*~ +server.log diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..599d354 --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,294 @@ +# 应用部署文档 + +## 1. 环境要求 + +### 服务器要求 +- 操作系统:Linux(推荐 Ubuntu 18.04+ 或 CentOS 7+) +- 内存:至少 2GB RAM +- 存储空间:至少 10GB 可用空间 +- 网络:可访问 Gitea 仓库(http://8.137.125.67:4000)和互联网 + +### 软件依赖 +- Docker:用于容器化部署 +- Git:用于代码拉取 + +## 2. 部署前准备 + +### 2.1 安装 Docker + +#### Ubuntu/Debian +```bash +# 更新系统包 +apt-get update + +# 安装 Docker +curl -fsSL https://get.docker.com | sh + +# 启动 Docker 服务 +systemctl start docker + +# 设置 Docker 开机自启 +systemctl enable docker +``` + +#### CentOS/RHEL +```bash +# 更新系统包 +yum update + +# 安装 Docker +yum install -y docker + +# 启动 Docker 服务 +systemctl start docker + +# 设置 Docker 开机自启 +systemctl enable docker +``` + +### 2.2 配置防火墙和安全组 + +#### 2.2.1 系统防火墙设置 + +确保服务器开放以下端口: +- 3000:应用访问端口 +- 4000:Gitea 仓库访问端口(仅在需要访问仓库时) + +##### Ubuntu/Debian (ufw) +```bash +# 允许 3000 端口 +ufw allow 3000/tcp + +# 允许 4000 端口(如果需要) +ufw allow 4000/tcp + +# 启用防火墙 +ufw enable + +# 查看防火墙规则 +ufw status verbose +``` + +##### CentOS/RHEL (firewalld) +```bash +# 允许 3000 端口 +firewall-cmd --zone=public --add-port=3000/tcp --permanent + +# 允许 4000 端口(如果需要) +firewall-cmd --zone=public --add-port=4000/tcp --permanent + +# 重新加载防火墙 +firewall-cmd --reload + +# 查看防火墙规则 +firewall-cmd --list-ports --zone=public +``` + +#### 2.2.2 云服务商安全组设置 + +如果您使用的是云服务器(如阿里云、腾讯云、华为云等),还需要在云服务商控制台配置安全组规则: + +1. 登录云服务器控制台 +2. 找到对应服务器的安全组配置 +3. 添加入站规则: + - 端口范围:3000/3000 + - 协议:TCP + - 授权对象:0.0.0.0/0(允许所有IP访问,或根据需要设置特定IP) + - 描述:应用访问端口 + +### 2.3 配置 Git 凭证(可选) + +如果 Gitea 仓库需要认证,可以配置 Git 凭证缓存: + +```bash +# 设置凭证缓存时间(1小时) +git config --global credential.helper cache + +# 设置凭证永久保存 +git config --global credential.helper store + +# 首次拉取时会要求输入用户名和密码,之后会自动保存 +``` +## 3. 部署步骤 + +### 3.1 下载部署脚本 + +将 `deploy.sh` 脚本上传到服务器的任意目录,例如 `/root` 目录。 + +### 3.2 设置执行权限 + +```bash +chmod +x deploy.sh +``` + +### 3.3 运行部署脚本 + +```bash +./deploy.sh +``` + +### 3.4 部署过程说明 + +脚本将执行以下步骤: +1. **检查应用目录**:如果不存在则克隆仓库,存在则拉取最新代码 +2. **切换分支**:确保使用正确的 `Ly` 分支 +3. **拉取代码**:从 Gitea 仓库拉取最新代码 +4. **停止旧容器**:停止并删除旧的 Docker 容器 +5. **检查端口**:确保 3000 端口未被占用 +6. **构建镜像**:重新构建 Docker 镜像 +7. **启动容器**:启动新的 Docker 容器 +8. **清理镜像**:清理无用的 Docker 镜像 + +## 4. 验证部署 + +### 4.1 检查容器状态 + +```bash +docker ps | grep reject-app +``` + +正常输出示例: +``` +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +abcdef123456 reject-app "node Reject.js" 1 minute ago Up 1 minute 0.0.0.0:3000->3000/tcp reject-app +``` + +### 4.2 检查端口映射 + +```bash +docker port reject-app +``` + +正常输出示例: +``` +3000/tcp -> 0.0.0.0:3000 +``` + +### 4.3 访问应用 + +在浏览器中访问:http://8.137.125.67:3000 + +## 5. 常见问题解决 + +### 5.1 拒绝连接错误 + +**错误现象**:访问 http://8.137.125.67:3000 时显示"拒绝连接" + +**可能原因及解决方法**: + +1. **防火墙未开放端口** + - 检查防火墙规则是否允许 3000 端口 + - 按照 2.2 节重新配置防火墙 + +2. **容器未正常启动** + - 检查容器状态:`docker ps -a | grep reject-app` + - 查看容器日志:`docker logs reject-app` + +3. **端口被占用** + - 检查 3000 端口占用情况:`lsof -i :3000` 或 `netstat -tulpn | grep :3000` + - 停止占用端口的进程或容器 + +### 5.2 数据库连接错误 + +**错误现象**:应用启动后显示数据库连接失败 + +**可能原因及解决方法**: + +1. **数据库配置错误** + - 检查 `Reject.js` 中的数据库连接配置 + - 确保数据库地址、用户名、密码正确 + +2. **数据库服务器未运行** + - 检查数据库服务器状态 + - 确保数据库服务器允许远程连接 + +### 5.3 代码拉取失败 + +**错误现象**:脚本执行时显示"代码拉取失败" + +**可能原因及解决方法**: + +1. **Gitea 仓库不可访问** + - 检查 Gitea 服务器状态:`curl -I http://8.137.125.67:4000` + - 确保服务器可以访问 Gitea 仓库 + +2. **分支名称错误** + - 检查 `deploy.sh` 中的 `BRANCH` 变量是否正确 + - 确保仓库中存在指定的分支 + +## 6. 应用维护 + +### 6.1 查看应用日志 + +```bash +docker logs reject-app +# 实时查看日志 +docker logs -f reject-app +``` + +### 6.2 重启应用 + +```bash +docker restart reject-app +``` + +### 6.3 更新应用 + +再次运行部署脚本即可更新应用: + +```bash +./deploy.sh +``` + +### 6.4 停止应用 + +```bash +docker stop reject-app +``` + +### 6.5 删除应用 + +```bash +# 停止并删除容器 +docker stop reject-app +docker rm reject-app + +# 删除镜像 +docker rmi reject-app + +# 删除应用目录 +rm -rf /app +``` + +## 7. 脚本说明 + +### 7.1 配置参数 + +脚本中的主要配置参数: + +- `REPO_URL`:Gitea 仓库地址 +- `APP_DIR`:应用部署目录 +- `BRANCH`:使用的代码分支 + +### 7.2 脚本功能 + +- **自动代码拉取**:从 Gitea 仓库拉取最新代码 +- **容器管理**:自动停止旧容器并启动新容器 +- **端口管理**:自动检查并清理占用 3000 端口的进程 +- **错误检查**:提供详细的错误信息和处理建议 +- **日志记录**:记录部署过程中的关键步骤 + +## 8. 注意事项 + +1. **第一次部署**:脚本会自动克隆仓库并启动应用 +2. **后续部署**:脚本会自动拉取最新代码并重启应用 +3. **分支切换**:如需切换分支,请修改 `deploy.sh` 中的 `BRANCH` 变量 +4. **数据持久化**:应用数据通过 Docker 卷映射到 `/app` 目录,确保该目录安全 +5. **定期备份**:建议定期备份 `/app` 目录和数据库 + +## 9. 联系方式 + +如有部署问题,请联系: +- 技术支持:[技术支持邮箱] +- 管理员:[管理员联系方式] + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..227301a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +# 使用Node.js作为基础镜像 +FROM node:18-alpine + +# 设置工作目录 +WORKDIR /app + +# 设置npm镜像源为国内源加速依赖安装 +RUN npm config set registry https://registry.npmmirror.com + +# 复制package.json和package-lock.json +COPY package*.json ./ + +# 安装项目依赖 +RUN npm install + +# 复制应用代码 +COPY . . + +# 暴露端口 +EXPOSE 3000 + +# 直接使用node启动应用 +CMD ["node", "Reject.js"] \ No newline at end of file diff --git a/Reject.html b/Reject.html new file mode 100644 index 0000000..4f217f2 --- /dev/null +++ b/Reject.html @@ -0,0 +1,3871 @@ + + + + + + + 货源审核系统 + + + + +
+ +
+ 未登录 + +
+ +

审核系统

+ + +
+ + + +
+ + + + +
+ + + + +
+ + + + + +
+ 总共 0 个项目 +
+ +
+
加载中...
+
+ + +
+ + + + + + + + + + + + + + + + + + + +
+ +
+ 大图查看 + +
+ + +
+ + + + + \ No newline at end of file diff --git a/Reject.js b/Reject.js new file mode 100644 index 0000000..7c3abed --- /dev/null +++ b/Reject.js @@ -0,0 +1,1369 @@ +const express = require('express'); +const bodyParser = require('body-parser'); +const cors = require('cors'); +const mysql = require('mysql2/promise'); +const path = require('path'); +const app = express(); +const PORT = 3000; + +// 配置CORS +app.use(cors()); +app.use((req, res, next) => { + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); + res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); + if (req.method === 'OPTIONS') { + res.status(200).end(); + return; + } + next(); +}); +app.use(bodyParser.json({ limit: '10mb' })); +app.use(express.static(path.join(__dirname))); + +// 数据库配置 +const dbConfig = { + host: '1.95.162.61', + user: 'root', + password: 'schl@2025', // 请替换为实际的数据库密码 + database: 'wechat_app', // 连接到wechat_app数据库 + waitForConnections: true, + connectionLimit: 10, + queueLimit: 0 +}; + +// userlogin数据库配置 +const userLoginDbConfig = { + host: '1.95.162.61', + user: 'root', + password: 'schl@2025', // 请替换为实际的数据库密码 + database: 'userlogin', // 连接到userlogin数据库 + waitForConnections: true, + connectionLimit: 10, + queueLimit: 0 +}; + +// 创建数据库连接池 +let pool; +let userLoginPool; + +// 初始化数据库连接 +async function initDatabase() { + try { + pool = mysql.createPool(dbConfig); + console.log('wechat_app数据库连接池创建成功'); + + // 初始化userlogin数据库连接池 + userLoginPool = mysql.createPool(userLoginDbConfig); + console.log('userlogin数据库连接池创建成功'); + + // 测试wechat_app连接 + const connection = await pool.getConnection(); + console.log('wechat_app数据库连接测试成功'); + connection.release(); + + // 测试userlogin连接 + const userLoginConnection = await userLoginPool.getConnection(); + console.log('userlogin数据库连接测试成功'); + userLoginConnection.release(); + + // 确保数据库结构 + await ensureDatabaseSchema(); + } catch (error) { + console.error('数据库初始化失败:', error.message); + console.error('错误详情:', error); + // 如果初始化失败,尝试重新初始化 + setTimeout(() => { + console.log('尝试重新初始化数据库连接...'); + initDatabase(); + }, 5000); + } +} + +// 通用响应函数 +function sendResponse(res, success, data = null, message = '') { + res.json({ + success, + data, + message + }); +} + +// 导出函数供测试使用 +module.exports.sendResponse = sendResponse; + +// 获取货源列表API +app.get('/api/supplies', async (req, res) => { + console.log('收到获取货源列表请求:', req.query); + try { + const connection = await pool.getConnection(); + // 支持search和keyword两种参数名,确保兼容性 + const { page = 1, pageSize = 10, search = '', keyword = '', status = '', phoneNumber = '' } = req.query; + // 如果提供了keyword参数,优先使用keyword + const actualSearch = keyword || search; + const offset = (page - 1) * pageSize; + + // 构建基础查询,添加LEFT JOIN获取用户信息 + let query = 'SELECT p.*, u.phoneNumber, u.nickName FROM products p LEFT JOIN users u ON p.sellerId = u.userId'; + let countQuery = 'SELECT COUNT(*) as total FROM products p LEFT JOIN users u ON p.sellerId = u.userId'; + let whereClause = ''; + let params = []; + + // 添加搜索条件 + if (actualSearch) { + whereClause += ` WHERE (p.id LIKE ? OR p.productId LIKE ? OR p.productName LIKE ?)`; + params.push(`%${actualSearch}%`, `%${actualSearch}%`, `%${actualSearch}%`); + } + + // 添加手机号搜索 + if (phoneNumber) { + whereClause += actualSearch ? ' AND' : ' WHERE'; + whereClause += ` u.phoneNumber LIKE ?`; + params.push(`%${phoneNumber}%`); + } + + // 添加状态筛选 + if (status) { + whereClause += (actualSearch || phoneNumber) ? ' AND' : ' WHERE'; + whereClause += ` status = ?`; + params.push(status); + } + + // 添加sellerId筛选,只返回指定用户的货源 + const { sellerId } = req.query; + if (sellerId) { + whereClause += (actualSearch || phoneNumber || status) ? ' AND' : ' WHERE'; + whereClause += ` p.sellerId = ?`; + params.push(sellerId); + } + + // 执行查询 + const [results] = await connection.query( + `${query}${whereClause} ORDER BY p.id DESC LIMIT ? OFFSET ?`, + [...params, parseInt(pageSize), offset] + ); + + // 获取总数 + const [countResults] = await connection.query( + `${countQuery}${whereClause}`, + params + ); + + connection.release(); + + // 处理返回结果中的imageUrls字段 + const processedResults = results.map(product => { + // 处理imageUrls字段 + let imageUrls = []; + + if (product.imageUrls) { + if (typeof product.imageUrls === 'string') { + // 尝试解析为JSON数组 + try { + let parsedImages = JSON.parse(product.imageUrls); + + // 检查是否是JSON字符串的字符串表示(转义的JSON) + if (typeof parsedImages === 'string' && + (parsedImages.startsWith('[') || parsedImages.startsWith('{'))) { + // 进行第二次解析 + parsedImages = JSON.parse(parsedImages); + } + + if (Array.isArray(parsedImages)) { + imageUrls = parsedImages; + } else if (typeof parsedImages === 'string') { + // 如果解析结果是字符串,可能是单个URL + imageUrls = [parsedImages]; + } + } catch (e) { + // 解析失败,尝试按逗号分隔 + if (product.imageUrls.includes(',')) { + imageUrls = product.imageUrls.split(',').map(url => url.trim()); + } else { + // 作为单个URL处理 + imageUrls = [product.imageUrls.trim()]; + } + } + } else if (Array.isArray(product.imageUrls)) { + // 已经是数组,直接使用 + imageUrls = product.imageUrls; + } else { + // 其他类型,转换为字符串数组 + imageUrls = [String(product.imageUrls)]; + } + } + + // 过滤并处理无效的URL:移除反引号并验证 + imageUrls = imageUrls + .filter(url => { + if (!url) return false; + const processedUrl = url.replace(/`/g, '').trim(); + return processedUrl.startsWith('http://') || processedUrl.startsWith('https://'); + }) + // 对每个有效URL进行处理,移除反引号 + .map(url => url.replace(/`/g, '').trim()); + + return { + ...product, + imageUrls + }; + }); + + // 返回结果 + sendResponse(res, true, { + list: processedResults, + total: countResults[0].total, + page: parseInt(page), + pageSize: parseInt(pageSize) + }, '获取货源列表成功'); + } catch (error) { + console.error('获取货源列表失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '获取货源列表失败'); + } +}); + +// 审核通过API +app.post('/api/supplies/:id/approve', async (req, res) => { + console.log('收到审核通过请求:', req.params.id, req.body); + try { + const connection = await pool.getConnection(); + const { remark = '' } = req.body; + const productId = req.params.id; + + // 开始事务 + await connection.beginTransaction(); + + // 检查当前状态 + const [currentProduct] = await connection.query( + 'SELECT status FROM products WHERE id = ?', + [productId] + ); + + if (currentProduct.length === 0) { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '货源不存在'); + } + + // 检查状态是否可审核,只允许审核中的状态进行审核操作 + if (!['pending_review'].includes(currentProduct[0].status)) { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '该货源已审核,无需重复操作'); + } + + // 更新状态为已审核 + await connection.query( + 'UPDATE products SET status = ?, audit_time = ? WHERE id = ?', + ['published', new Date(), productId] + ); + + // 记录日志 + await connection.query( + 'INSERT INTO audit_logs (supply_id, action, user_id, remark, created_at) VALUES (?, ?, ?, ?, ?)', + [productId, 'approve', 'system', remark, new Date()] + ); + + // 提交事务 + await connection.commit(); + connection.release(); + + sendResponse(res, true, null, '审核通过成功'); + } catch (error) { + console.error('审核通过失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '审核通过失败'); + } +}); + +console.log('正在注册拒绝审核API路由: /api/supplies/:id/reject'); + +// 审核拒绝API +app.post('/api/supplies/:id/reject', async (req, res) => { + console.log('收到审核拒绝请求:', req.params.id, req.body); + try { + const connection = await pool.getConnection(); + // 同时支持reason和rejectReason参数,保持向后兼容 + const { reason, rejectReason = '', remark = '' } = req.body; + // 如果有reason参数,则使用reason,否则使用rejectReason + const actualRejectReason = reason || rejectReason; + const productId = req.params.id; + + // 开始事务 + await connection.beginTransaction(); + + // 检查当前状态 + const [currentProduct] = await connection.query( + 'SELECT status FROM products WHERE id = ?', + [productId] + ); + + if (currentProduct.length === 0) { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '货源不存在'); + } + + // 检查状态是否可审核,只允许审核中的状态进行审核操作 + if (!['pending_review'].includes(currentProduct[0].status)) { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '当前状态不允许审核拒绝'); + } + + // 更新状态和拒绝理由 + await connection.query( + 'UPDATE products SET status = ?, rejectReason = ?, audit_time = ? WHERE id = ?', + ['rejected', actualRejectReason, new Date(), productId] + ); + + // 记录日志 + await connection.query( + 'INSERT INTO audit_logs (supply_id, action, user_id, remark, created_at) VALUES (?, ?, ?, ?, ?)', + [productId, 'reject', 'system', remark, new Date()] + ); + + // 提交事务 + await connection.commit(); + connection.release(); + + sendResponse(res, true, null, '审核拒绝成功'); + } catch (error) { + console.error('审核拒绝失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '审核拒绝失败'); + } +}); + +// 获取供应商列表API已删除 + +// 供应商审核通过API已删除 + +// 供应商审核拒绝API已删除 + +// 供应商开始合作API已删除 + +// 供应商终止合作API已删除 + +console.log('正在注册测试API路由: /api/test-db'); + +// 测试数据库连接API +app.get('/api/test-db', async (req, res) => { + console.log('收到数据库连接测试请求'); + try { + const connection = await pool.getConnection(); + const [results] = await connection.query('SELECT 1 + 1 as solution'); + connection.release(); + sendResponse(res, true, results[0], '数据库连接成功'); + } catch (error) { + console.error('数据库连接测试失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '数据库连接测试失败'); + } +}); + +// 登录API +app.post('/api/login', async (req, res) => { + try { + const { projectName, userName, password } = req.body; + + // 验证参数 + if (!projectName || !userName || !password) { + return sendResponse(res, false, null, '职位名称、用户名和密码不能为空'); + } + + // 1. 在login表中验证登录信息 + const userLoginConnection = await userLoginPool.getConnection(); + const [loginResult] = await userLoginConnection.query( + 'SELECT id, projectName, userName, managerId FROM login WHERE projectName = ? AND userName = ? AND password = ?', + [projectName, userName, password] + ); + + if (loginResult.length === 0) { + userLoginConnection.release(); + return sendResponse(res, false, null, '职位名称、用户名或密码错误'); + } + + const loginInfo = loginResult[0]; + const { managerId } = loginInfo; + + // 2. 在personnel表中查询手机号码 + const [personnelResult] = await userLoginConnection.query( + 'SELECT phoneNumber, name FROM personnel WHERE managerId = ?', + [managerId] + ); + userLoginConnection.release(); + + if (personnelResult.length === 0) { + return sendResponse(res, false, null, '未找到对应的员工信息'); + } + + const { phoneNumber, name } = personnelResult[0]; + + // 3. 在users表中查询userId + const connection = await pool.getConnection(); + const [userResult] = await connection.query( + 'SELECT userId FROM users WHERE phoneNumber = ?', + [phoneNumber] + ); + connection.release(); + + let userId = null; + if (userResult.length > 0) { + userId = userResult[0].userId; + } + + // 4. 生成token(简单实现,实际项目中应使用JWT等安全机制) + const token = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; + + // 5. 返回登录结果 + const userInfo = { + id: loginInfo.id, + projectName: loginInfo.projectName, + userName: loginInfo.userName, + managerId: loginInfo.managerId, + name: name, + phoneNumber: phoneNumber, + userId: userId + }; + + sendResponse(res, true, { userInfo, token }, '登录成功'); + } catch (error) { + console.error('登录失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '登录失败,请稍后重试'); + } +}); + +// 获取联系人数据API +app.get('/api/contacts', async (req, res) => { + try { + // 直接从userlogin数据库的Personnel表查询联系人信息,只查询工位名为销售员的联系人 + const userLoginConnection = await userLoginPool.getConnection(); + const [personnelData] = await userLoginConnection.query( + 'SELECT projectName, alias, phoneNumber FROM Personnel WHERE projectName = "销售员" AND phoneNumber IS NOT NULL AND phoneNumber != ""' + ); + userLoginConnection.release(); + + if (personnelData.length === 0) { + sendResponse(res, true, [], '没有找到联系人信息'); + return; + } + + // 创建联系人数据数组,保持与原API相同的返回格式 + const contacts = personnelData.map((person, index) => ({ + id: index + 1, + salesPerson: person.projectName, // 销售员 + name: person.alias, // 联系人别名 + phoneNumber: person.phoneNumber // 电话号码 + })); + + sendResponse(res, true, contacts, '联系人数据获取成功'); + } catch (error) { + console.error('获取联系人数据失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '获取联系人数据失败'); + } +}); + +// 更新产品联系人API +app.put('/api/supplies/:id/contact', async (req, res) => { + try { + const { id } = req.params; + const { productContact, contactPhone } = req.body; + + // 移除"联系人"前缀和"销售员 - "前缀 + const processedProductContact = productContact.replace(/^(联系人|销售员\s*-\s*)/g, '').trim(); + + const connection = await pool.getConnection(); + + // 更新产品的联系人信息 + const [result] = await connection.query( + 'UPDATE products SET product_contact = ?, contact_phone = ? WHERE id = ?', + [processedProductContact, contactPhone, id] + ); + + connection.release(); + + if (result.affectedRows === 0) { + sendResponse(res, false, null, '未找到指定的产品'); + return; + } + + sendResponse(res, true, null, '产品联系人信息更新成功'); + } catch (error) { + console.error('更新产品联系人信息失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '更新产品联系人信息失败'); + } +}); + +// 供应商审核通过API - /api/suppliers/:id/approve +console.log('正在注册供应商审核通过API路由: /api/suppliers/:id/approve'); +app.post('/api/suppliers/:id/approve', async (req, res) => { + console.log('收到供应商审核通过请求:', req.params); + try { + const connection = await pool.getConnection(); + const userId = req.params.id; + + if (!userId) { + connection.release(); + return sendResponse(res, false, null, '用户ID不能为空'); + } + + // 开始事务 + await connection.beginTransaction(); + + // 检查当前状态 + const [currentUser] = await connection.query( + 'SELECT partnerstatus FROM users WHERE userId = ?', + [userId] + ); + + if (currentUser.length === 0) { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '供应商不存在'); + } + + if (currentUser[0].partnerstatus !== 'underreview') { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '当前状态不允许审核通过'); + } + + // 更新状态和审核时间 + await connection.query( + 'UPDATE users SET partnerstatus = ?, audit_time = ? WHERE userId = ?', + ['approved', new Date(), userId] + ); + + // 提交事务 + await connection.commit(); + connection.release(); + + sendResponse(res, true, null, '供应商审核通过成功'); + } catch (error) { + console.error('供应商审核通过失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '供应商审核通过失败'); + } +}); + +// 供应商审核拒绝API - /api/suppliers/:id/reject +console.log('正在注册供应商审核拒绝API路由: /api/suppliers/:id/reject'); +app.post('/api/suppliers/:id/reject', async (req, res) => { + console.log('收到供应商审核拒绝请求:', req.params, req.body); + try { + const connection = await pool.getConnection(); + const userId = req.params.id; + const { rejectReason } = req.body; + + if (!userId) { + connection.release(); + return sendResponse(res, false, null, '用户ID不能为空'); + } + + if (!rejectReason) { + connection.release(); + return sendResponse(res, false, null, '审核失败原因不能为空'); + } + + // 开始事务 + await connection.beginTransaction(); + + // 检查当前状态 + const [currentUser] = await connection.query( + 'SELECT partnerstatus FROM users WHERE userId = ?', + [userId] + ); + + if (currentUser.length === 0) { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '供应商不存在'); + } + + if (currentUser[0].partnerstatus !== 'underreview') { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '当前状态不允许审核拒绝'); + } + + // 更新状态、审核失败原因和审核时间 + await connection.query( + 'UPDATE users SET partnerstatus = ?, reasonforfailure = ?, audit_time = ? WHERE userId = ?', + ['reviewfailed', rejectReason, new Date(), userId] + ); + + // 提交事务 + await connection.commit(); + connection.release(); + + sendResponse(res, true, null, '供应商审核拒绝成功'); + } catch (error) { + console.error('供应商审核拒绝失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '供应商审核拒绝失败'); + } +}); + +// 供应商开始合作API - /api/suppliers/:id/cooperate +console.log('正在注册供应商开始合作API路由: /api/suppliers/:id/cooperate'); +app.post('/api/suppliers/:id/cooperate', async (req, res) => { + console.log('收到供应商开始合作请求:', req.params); + try { + const connection = await pool.getConnection(); + const userId = req.params.id; + + if (!userId) { + connection.release(); + return sendResponse(res, false, null, '用户ID不能为空'); + } + + // 开始事务 + await connection.beginTransaction(); + + // 检查当前状态 + const [currentUser] = await connection.query( + 'SELECT partnerstatus FROM users WHERE userId = ?', + [userId] + ); + + if (currentUser.length === 0) { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '供应商不存在'); + } + + if (currentUser[0].partnerstatus !== 'approved') { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '只有审核通过的供应商才能开始合作'); + } + + // 更新状态 + await connection.query( + 'UPDATE users SET partnerstatus = ? WHERE userId = ?', + ['incooperation', userId] + ); + + // 提交事务 + await connection.commit(); + connection.release(); + + sendResponse(res, true, null, '供应商开始合作成功'); + } catch (error) { + console.error('供应商开始合作失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '供应商开始合作失败'); + } +}); + +// 供应商终止合作API - /api/suppliers/:id/terminate +console.log('正在注册供应商终止合作API路由: /api/suppliers/:id/terminate'); +app.post('/api/suppliers/:id/terminate', async (req, res) => { + console.log('收到供应商终止合作请求:', req.params, req.body); + try { + const connection = await pool.getConnection(); + const userId = req.params.id; + const { reason } = req.body; + + if (!userId) { + connection.release(); + return sendResponse(res, false, null, '用户ID不能为空'); + } + + // 开始事务 + await connection.beginTransaction(); + + // 检查当前状态 + const [currentUser] = await connection.query( + 'SELECT partnerstatus FROM users WHERE userId = ?', + [userId] + ); + + if (currentUser.length === 0) { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '供应商不存在'); + } + + if (currentUser[0].partnerstatus !== 'approved' && currentUser[0].partnerstatus !== 'incooperation') { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '只有审核通过或合作中的供应商才能终止合作'); + } + + // 更新状态和终止原因 + await connection.query( + 'UPDATE users SET partnerstatus = ?, terminate_reason = ? WHERE userId = ?', + ['notcooperative', reason, userId] + ); + + // 提交事务 + await connection.commit(); + connection.release(); + + sendResponse(res, true, null, '供应商终止合作成功'); + } catch (error) { + console.error('供应商终止合作失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '供应商终止合作失败'); + } +}); + +// 导入OSS上传工具 +const OssUploader = require('./oss-uploader'); +// 导入图片处理工具 +const ImageProcessor = require('./image-processor'); + +// 创建货源API - /api/supplies/create +console.log('正在注册创建货源API路由: /api/supplies/create'); +app.post('/api/supplies/create', async (req, res) => { + console.log('收到创建货源请求:', req.body); + let connection; + try { + connection = await pool.getConnection(); + const { productName, price, quantity, grossWeight, yolk, specification, quality, region, imageUrls, sellerId, supplyStatus, description, sourceType, contactId, category } = req.body; + + // 开始事务 + await connection.beginTransaction(); + + // 验证必填字段 + if (!productName || !price || !quantity || !supplyStatus || !sourceType) { + connection.release(); + return sendResponse(res, false, null, '商品名称、价格、最小起订量、货源状态和货源类型不能为空'); + } + + // 如果sellerId为空,设置一个默认值 + if (!sellerId) { + sellerId = 'default_seller'; + } + + // 处理联系人信息 + let productContact = ''; + let contactPhone = ''; + if (contactId) { + console.log('开始处理联系人信息,contactId:', contactId); + // 从userlogin数据库获取联系人信息 + const userLoginConnection = await userLoginPool.getConnection(); + const [personnelData] = await userLoginConnection.query( + 'SELECT alias, phoneNumber FROM Personnel WHERE projectName = "销售员" AND phoneNumber IS NOT NULL AND phoneNumber != "" AND id = ?', + [parseInt(contactId)] // 使用contactId直接查询对应的联系人 + ); + userLoginConnection.release(); + + console.log('查询到的联系人数据:', personnelData); + if (personnelData && personnelData.length > 0) { + productContact = personnelData[0].alias || ''; + contactPhone = personnelData[0].phoneNumber || ''; + console.log('获取到的联系人信息:', productContact, contactPhone); + } + } + + console.log('准备插入的联系人信息:', productContact, contactPhone); + + // 生成唯一的productId + const productId = `product_${Date.now()}_${Math.floor(Math.random() * 1000)}`; + + // 处理图片上传 + let uploadedImageUrls = []; + if (Array.isArray(imageUrls) && imageUrls.length > 0) { + console.log('开始处理图片上传,共', imageUrls.length, '张图片'); + + for (const imageUrl of imageUrls) { + if (imageUrl.startsWith('data:image/')) { + // 处理DataURL + const base64Data = imageUrl.replace(/^data:image\/(png|jpeg|jpg|gif);base64,/, ''); + let buffer = Buffer.from(base64Data, 'base64'); + const ext = imageUrl.match(/^data:image\/(png|jpeg|jpg|gif);base64,/)?.[1] || 'png'; + const filename = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}.${ext}`; + + try { + // 不再添加水印,前端已处理 + console.log('【水印处理】前端已添加水印,跳过后端水印处理'); + + // 使用OSS上传带水印的图片 + const ossUrl = await OssUploader.uploadBuffer(buffer, filename, `products/${productName || 'general'}`, 'image'); + uploadedImageUrls.push(ossUrl); + console.log('图片上传成功:', ossUrl); + } catch (uploadError) { + console.error('图片上传失败:', uploadError.message); + // 继续上传其他图片,不中断流程 + } + } else { + // 已经是URL,直接使用 + uploadedImageUrls.push(imageUrl); + } + } + console.log('图片处理完成,成功上传', uploadedImageUrls.length, '张图片'); + } + + // 创建商品数据 + const productData = { + productId, + sellerId: sellerId, // 使用前端传入的sellerId + productName, + category: category || '', // 添加种类 + price: price.toString(), // 确保是varchar类型 + quantity: parseInt(quantity), + grossWeight, + yolk, + specification, + quality, + region, + status: 'published', // 直接上架,而不是审核中 + supplyStatus: supplyStatus || '', // 预售/现货 + sourceType: sourceType || '', // 平台货源/三方认证/三方未认证 + description: description || '', + rejectReason: '', + imageUrls: uploadedImageUrls.length > 0 ? JSON.stringify(uploadedImageUrls) : '[]', + created_at: new Date(), + product_contact: productContact, // 添加联系人名称 + contact_phone: contactPhone // 添加联系人电话 + }; + + // 插入商品数据 + let result; + try { + // 检查products表是否有quality字段 + const [columns] = await connection.query('SHOW COLUMNS FROM products LIKE ?', ['quality']); + let insertQuery; + let insertParams; + + if (columns.length === 0) { + // 没有quality字段,不包含quality字段的插入 + insertQuery = 'INSERT INTO products (productId, sellerId, productName, category, price, quantity, grossWeight, yolk, specification, region, status, supplyStatus, sourceType, description, rejectReason, imageUrls, created_at, audit_time, product_contact, contact_phone) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; + insertParams = [ + productId, productData.sellerId, productName, category || '', price.toString(), parseInt(quantity), grossWeight, + yolk, specification, region, productData.status, productData.supplyStatus, productData.sourceType, + productData.description, productData.rejectReason, productData.imageUrls, new Date(), new Date(), + productContact, contactPhone // 添加联系人信息 + ]; + } else { + // 有quality字段,包含quality字段的插入 + insertQuery = 'INSERT INTO products (productId, sellerId, productName, category, price, quantity, grossWeight, yolk, specification, quality, region, status, supplyStatus, sourceType, description, rejectReason, imageUrls, created_at, audit_time, product_contact, contact_phone) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'; + insertParams = [ + productId, productData.sellerId, productName, category || '', price.toString(), parseInt(quantity), grossWeight, + yolk, specification, quality, region, productData.status, productData.supplyStatus, + productData.sourceType, productData.description, productData.rejectReason, productData.imageUrls, + new Date(), new Date(), productContact, contactPhone // 添加联系人信息 + ]; + } + + result = await connection.query(insertQuery, insertParams); + } catch (insertError) { + await connection.rollback(); + connection.release(); + console.error('插入商品数据失败:', insertError.message); + console.error('SQL错误:', insertError.sqlMessage); + return sendResponse(res, false, null, `创建货源失败: ${insertError.sqlMessage}`); + } + + // 提交事务 + await connection.commit(); + connection.release(); + + sendResponse(res, true, { productId: result.insertId }, '货源创建成功'); + } catch (error) { + if (connection) { + try { + await connection.rollback(); + connection.release(); + } catch (rollbackError) { + console.error('回滚失败:', rollbackError.message); + } + } + console.error('创建货源失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, `创建货源失败: ${error.message}`); + } +}); + +// 图片上传API - /api/upload-image +console.log('正在注册图片上传API路由: /api/upload-image'); +app.post('/api/upload-image', async (req, res) => { + console.log('收到图片上传请求'); + // 注意:这里需要实现实际的图片上传逻辑,包括OSS配置 + // 由于当前缺少OSS配置,返回模拟数据 + sendResponse(res, true, { + imageUrl: 'https://example.com/image.jpg', + message: '图片上传成功' + }, '图片上传成功'); +}); + +// 获取审核失败原因API - /api/supplies/:id/reject-reason +console.log('正在注册获取审核失败原因API路由: /api/supplies/:id/reject-reason'); +app.get('/api/supplies/:id/reject-reason', async (req, res) => { + console.log('收到获取审核失败原因请求:', req.params.id); + try { + const connection = await pool.getConnection(); + const supplyId = req.params.id; + + // 查询该货源的拒绝原因 + const [supply] = await connection.query( + 'SELECT rejectReason FROM products WHERE id = ?', + [supplyId] + ); + + connection.release(); + + if (supply.length === 0) { + return sendResponse(res, false, null, '货源不存在'); + } + + sendResponse(res, true, { + rejectReason: supply[0].rejectReason + }, '获取审核失败原因成功'); + } catch (error) { + console.error('获取审核失败原因失败:', error.message); + sendResponse(res, false, null, '获取审核失败原因失败'); + } +}); + +// 下架货源API - /api/supplies/:id/unpublish +console.log('正在注册下架货源API路由: /api/supplies/:id/unpublish'); +app.post('/api/supplies/:id/unpublish', async (req, res) => { + console.log('收到下架货源请求:', req.params.id); + try { + const connection = await pool.getConnection(); + const productId = req.params.id; + + // 开始事务 + await connection.beginTransaction(); + + // 检查当前状态 + const [currentProduct] = await connection.query( + 'SELECT status FROM products WHERE id = ?', + [productId] + ); + + if (currentProduct.length === 0) { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '货源不存在'); + } + + // 更新状态为下架 + await connection.query( + 'UPDATE products SET status = ? WHERE id = ?', + ['hidden', productId] + ); + + // 提交事务 + await connection.commit(); + connection.release(); + + sendResponse(res, true, null, '货源下架成功'); + } catch (error) { + console.error('下架货源失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '货源下架失败'); + } +}); + +// 上架货源API - /api/supplies/:id/publish +console.log('正在注册上架货源API路由: /api/supplies/:id/publish'); +app.post('/api/supplies/:id/publish', async (req, res) => { + console.log('收到上架货源请求:', req.params.id); + try { + const connection = await pool.getConnection(); + const productId = req.params.id; + + // 开始事务 + await connection.beginTransaction(); + + // 检查当前状态 + const [currentProduct] = await connection.query( + 'SELECT status FROM products WHERE id = ?', + [productId] + ); + + if (currentProduct.length === 0) { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '货源不存在'); + } + + // 更新状态为审核中 + await connection.query( + 'UPDATE products SET status = ? WHERE id = ?', + ['pending_review', productId] + ); + + // 提交事务 + await connection.commit(); + connection.release(); + + sendResponse(res, true, null, '货源已提交审核'); + } catch (error) { + console.error('上架货源失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '货源上架失败'); + } +}); + +// 删除货源API - /api/supplies/:id/delete +console.log('正在注册删除货源API路由: /api/supplies/:id/delete'); +app.post('/api/supplies/:id/delete', async (req, res) => { + console.log('收到删除货源请求:', req.params.id); + try { + const connection = await pool.getConnection(); + const productId = req.params.id; + + // 开始事务 + await connection.beginTransaction(); + + // 检查当前状态 + const [currentProduct] = await connection.query( + 'SELECT status FROM products WHERE id = ?', + [productId] + ); + + if (currentProduct.length === 0) { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '货源不存在'); + } + + // 删除货源 + await connection.query( + 'DELETE FROM products WHERE id = ?', + [productId] + ); + + // 提交事务 + await connection.commit(); + connection.release(); + + sendResponse(res, true, null, '货源删除成功'); + } catch (error) { + console.error('删除货源失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '货源删除失败'); + } +}); + +// 编辑货源API - /api/supplies/:id/edit +console.log('正在注册编辑货源API路由: /api/supplies/:id/edit'); +app.put('/api/supplies/:id/edit', async (req, res) => { + console.log('收到编辑货源请求:', req.params.id, req.body); + try { + const connection = await pool.getConnection(); + const productId = req.params.id; + const { productName, price, quantity, grossWeight, yolk, specification, supplyStatus, description, region, contactId } = req.body; + + // 开始事务 + await connection.beginTransaction(); + + // 检查当前状态 + const [currentProduct] = await connection.query( + 'SELECT status FROM products WHERE id = ?', + [productId] + ); + + if (currentProduct.length === 0) { + await connection.rollback(); + connection.release(); + return sendResponse(res, false, null, '货源不存在'); + } + + // 处理联系人信息 + let productContact = ''; + let contactPhone = ''; + if (contactId) { + // 从userlogin数据库获取联系人信息 + const userLoginConnection = await userLoginPool.getConnection(); + const [personnelData] = await userLoginConnection.query( + 'SELECT alias, phoneNumber FROM Personnel WHERE projectName = "销售员" AND phoneNumber IS NOT NULL AND phoneNumber != "" AND id = ?', + [parseInt(contactId)] // 使用contactId直接查询对应的联系人 + ); + userLoginConnection.release(); + + if (personnelData && personnelData.length > 0) { + productContact = personnelData[0].alias || ''; + contactPhone = personnelData[0].phoneNumber || ''; + } + } + + // 更新货源信息 + const updateQuery = ` + UPDATE products + SET productName = ?, price = ?, quantity = ?, grossWeight = ?, + yolk = ?, specification = ?, supplyStatus = ?, description = ?, region = ?, + product_contact = ?, contact_phone = ? + WHERE id = ? + `; + + await connection.query(updateQuery, [ + productName, price.toString(), parseInt(quantity), grossWeight, + yolk, specification, supplyStatus, description, region, + productContact, contactPhone, productId + ]); + + // 提交事务 + await connection.commit(); + connection.release(); + + sendResponse(res, true, null, '货源编辑成功'); + } catch (error) { + console.error('编辑货源失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '货源编辑失败'); + } +}); + +// 供应商列表查询API - /api/suppliers +console.log('正在注册供应商列表查询API路由: /api/suppliers'); +app.get('/api/suppliers', async (req, res) => { + console.log('收到供应商列表查询请求:', req.query); + try { + const connection = await pool.getConnection(); + const { page = 1, pageSize = 10, status = '', keyword = '', phoneNumber = '' } = req.query; + + // 构建查询条件 + let whereClause = ''; + let params = []; + + // 添加状态筛选 + if (status) { + whereClause += ` WHERE partnerstatus = ?`; + params.push(status); + } + + // 添加关键词搜索 + if (keyword) { + whereClause += status ? ' AND' : ' WHERE'; + whereClause += ` (username LIKE ? OR company LIKE ? OR phoneNumber LIKE ?)`; + params.push(`%${keyword}%`, `%${keyword}%`, `%${keyword}%`); + } + + // 添加手机号搜索(优先级高于keyword中的手机号搜索) + if (phoneNumber) { + whereClause += (status || keyword) ? ' AND' : ' WHERE'; + whereClause += ` phoneNumber LIKE ?`; + params.push(`%${phoneNumber}%`); + } + + // 获取总数 + const [totalResult] = await connection.query( + `SELECT COUNT(*) as total FROM users${whereClause}`, + params + ); + const total = totalResult[0].total; + + // 计算分页 + const offset = (page - 1) * pageSize; + params.push(parseInt(pageSize), offset); + + // 查询供应商列表 + const [suppliers] = await connection.query( + `SELECT userId, phoneNumber, province, city, district, detailedaddress, company, collaborationid, cooperation, businesslicenseurl, proofurl, brandurl, partnerstatus, reasonforfailure, reject_reason, terminate_reason, audit_time + FROM users${whereClause} + ORDER BY audit_time DESC LIMIT ? OFFSET ?`, + params + ); + + connection.release(); + + sendResponse(res, true, { + list: suppliers, + total, + page: parseInt(page), + pageSize: parseInt(pageSize) + }, '查询成功'); + } catch (error) { + console.error('供应商列表查询失败:', error.message); + console.error('错误详情:', error); + sendResponse(res, false, null, '供应商列表查询失败'); + } +}); + +// 首页路由 +app.get('/', (req, res) => { + res.sendFile(path.join(__dirname, 'Reject.html')); +}); + +// 错误处理中间件 +app.use((err, req, res, next) => { + console.error('服务器错误:', err.message); + console.error('错误详情:', err); + res.status(500).json({ + success: false, + message: '服务器内部错误' + }); +}); + +// 启动服务器 +async function startServer() { + try { + await initDatabase(); + + app.listen(PORT, () => { + console.log(`服务器已启动,监听端口 ${PORT}`); + console.log(`访问地址: http://localhost:${PORT}`); + }); + } catch (error) { + console.error('服务器启动失败:', error.message); + console.error('错误详情:', error); + // 如果启动失败,尝试重新启动 + setTimeout(() => { + console.log('尝试重新启动服务器...'); + startServer(); + }, 5000); + } +} + +// 确保数据库结构 +async function ensureDatabaseSchema() { + console.log('开始执行数据库结构检查...'); + try { + const connection = await pool.getConnection(); + console.log('获取数据库连接成功'); + + // 检查users表是否有必要的字段 + console.log('检查users表是否有partnerstatus字段...'); + const [partnerStatusColumns] = await connection.query( + 'SHOW COLUMNS FROM `users` LIKE ?', + ['partnerstatus'] + ); + console.log('检查表字段结果:', partnerStatusColumns.length > 0 ? '已存在' : '不存在'); + + if (partnerStatusColumns.length === 0) { + console.log('添加partnerstatus字段到users表...'); + await connection.query( + 'ALTER TABLE `users` ADD COLUMN partnerstatus VARCHAR(50) DEFAULT "underreview" COMMENT "合作商状态"' + ); + console.log('partnerstatus字段添加成功'); + } + + console.log('检查users表是否有reject_reason字段...'); + const [rejectReasonColumns] = await connection.query( + 'SHOW COLUMNS FROM `users` LIKE ?', + ['reject_reason'] + ); + console.log('检查表字段结果:', rejectReasonColumns.length > 0 ? '已存在' : '不存在'); + + if (rejectReasonColumns.length === 0) { + console.log('添加reject_reason字段到users表...'); + await connection.query( + 'ALTER TABLE `users` ADD COLUMN reject_reason TEXT COMMENT "拒绝理由"' + ); + console.log('reject_reason字段添加成功'); + } + + console.log('检查users表是否有terminate_reason字段...'); + const [terminateReasonColumns] = await connection.query( + 'SHOW COLUMNS FROM `users` LIKE ?', + ['terminate_reason'] + ); + console.log('检查表字段结果:', terminateReasonColumns.length > 0 ? '已存在' : '不存在'); + + if (terminateReasonColumns.length === 0) { + console.log('添加terminate_reason字段到users表...'); + await connection.query( + 'ALTER TABLE `users` ADD COLUMN terminate_reason TEXT COMMENT "终止合作理由"' + ); + console.log('terminate_reason字段添加成功'); + } + + console.log('检查users表是否有audit_time字段...'); + const [userAuditTimeColumns] = await connection.query( + 'SHOW COLUMNS FROM `users` LIKE ?', + ['audit_time'] + ); + console.log('检查表字段结果:', userAuditTimeColumns.length > 0 ? '已存在' : '不存在'); + + if (userAuditTimeColumns.length === 0) { + console.log('添加audit_time字段到users表...'); + await connection.query( + 'ALTER TABLE `users` ADD COLUMN audit_time DATETIME COMMENT "审核时间"' + ); + console.log('audit_time字段添加成功'); + } + + // 检查表是否有rejectReason字段 + console.log('检查表products是否有rejectReason字段...'); + const [columns] = await connection.query( + 'SHOW COLUMNS FROM `products` LIKE ?', + ['rejectReason'] + ); + console.log('检查表字段结果:', columns.length > 0 ? '已存在' : '不存在'); + + if (columns.length === 0) { + console.log('添加rejectReason字段到products表...'); + await connection.query( + 'ALTER TABLE `products` ADD COLUMN rejectReason TEXT COMMENT "拒绝理由"' + ); + console.log('rejectReason字段添加成功'); + } + + // 检查表是否有audit_time字段 + console.log('检查表products是否有audit_time字段...'); + const [auditTimeColumns] = await connection.query( + 'SHOW COLUMNS FROM `products` LIKE ?', + ['audit_time'] + ); + console.log('检查表字段结果:', auditTimeColumns.length > 0 ? '已存在' : '不存在'); + + if (auditTimeColumns.length === 0) { + console.log('添加audit_time字段到products表...'); + await connection.query( + 'ALTER TABLE `products` ADD COLUMN audit_time DATETIME COMMENT "审核时间"' + ); + console.log('audit_time字段添加成功'); + } + + // 检查audit_logs表是否存在,如果不存在则创建 + console.log('检查audit_logs表是否存在...'); + const [tables] = await connection.query( + "SHOW TABLES LIKE 'audit_logs'" + ); + console.log('检查表存在性结果:', tables.length > 0 ? '已存在' : '不存在'); + + if (tables.length === 0) { + console.log('创建audit_logs表...'); + await connection.query(` + CREATE TABLE audit_logs ( + id INT AUTO_INCREMENT PRIMARY KEY, + supply_id VARCHAR(50) NOT NULL, + action VARCHAR(20) NOT NULL COMMENT 'approve或reject', + user_id VARCHAR(50) NOT NULL COMMENT '操作人ID', + remark TEXT COMMENT '备注信息', + created_at DATETIME NOT NULL, + INDEX idx_supply_id (supply_id), + INDEX idx_created_at (created_at) + ) COMMENT '审核操作日志表' + `); + console.log('audit_logs表创建成功'); + } + + connection.release(); + console.log('数据库结构检查完成'); + } catch (error) { + console.error('数据库结构检查失败:', error.message); + console.error('错误详情:', error); + } +} + +// 启动服务器 +startServer(); + +// 优雅关闭 +process.on('SIGINT', async () => { + console.log('正在关闭服务器...'); + if (pool) { + try { + await pool.end(); + console.log('数据库连接池已关闭'); + } catch (error) { + console.error('关闭数据库连接池失败:', error.message); + } + } + console.log('服务器已关闭'); + process.exit(0); +}); + +module.exports = app; \ No newline at end of file diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000..a0b992b --- /dev/null +++ b/deploy.sh @@ -0,0 +1,111 @@ +#!/bin/bash + +# 部署脚本:当Gitea仓库有更新时,一键部署新代码到云服务器 + +# 配置参数 +GITEA_USER="SwtTt29" +GITEA_PASSWORD="qazswt123" +REPO_URL="http://${GITEA_USER}:${GITEA_PASSWORD}@8.137.125.67:4000/SwtTt29/Review.git" +APP_DIR="/app" +DOCKER_COMPOSE_FILE="docker-compose.yml" +BRANCH="sh" +IMAGE_NAME="reject-app" # 改为与docker-compose.yml中一致的镜像名称 +CONTAINER_NAME="reject-app" + +# 输出日志函数 +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" +} + +# 关闭错误立即停止,改用手动错误检查 +source /etc/profile + +log "开始部署应用..." + +# 确保脚本具有执行权限 +chmod +x "$0" + +# 1. 检查应用目录是否存在 +if [ ! -d "$APP_DIR" ]; then + log "应用目录不存在,开始克隆仓库..." + git clone "$REPO_URL" "$APP_DIR" + if [ $? -ne 0 ]; then + log "错误:克隆仓库失败!请检查网络连接和仓库地址。" + exit 1 + fi + cd "$APP_DIR" + git checkout "$BRANCH" + if [ $? -ne 0 ]; then + log "错误:切换分支失败!请检查分支名称是否正确。" + exit 1 + fi +else + log "应用目录已存在,开始拉取最新代码..." + cd "$APP_DIR" + # 处理分支冲突问题 + if ! git pull origin "$BRANCH" --ff-only; then + log "快进合并失败,尝试先重置本地分支再拉取..." + git fetch origin + git reset --hard origin/"$BRANCH" + if [ $? -ne 0 ]; then + log "错误:重置本地分支失败!" + exit 1 + fi + fi +fi + +# 2. 检查docker-compose.yml文件是否存在 +if [ ! -f "$DOCKER_COMPOSE_FILE" ]; then + log "错误:$DOCKER_COMPOSE_FILE 文件不存在!" + exit 1 +fi + +# 3. 停止并删除旧的Docker容器 +log "停止并删除旧的Docker容器..." +docker-compose -f "$DOCKER_COMPOSE_FILE" down +if [ $? -ne 0 ]; then + log "警告:docker-compose down失败,尝试直接删除容器..." +fi + +# 强制删除可能残留的容器 +if docker ps -a | grep -q "$CONTAINER_NAME"; then + log "强制删除残留的容器 $CONTAINER_NAME..." + docker rm -f "$CONTAINER_NAME" + if [ $? -ne 0 ]; then + log "错误:强制删除容器失败!" + exit 1 + fi +fi + +# 4. 直接使用docker build命令构建镜像,绕过docker-compose的buildx依赖 +log "重新构建Docker镜像..." +docker build -t "$IMAGE_NAME" . +if [ $? -ne 0 ]; then + log "错误:构建镜像失败!请检查Dockerfile和依赖。" + exit 1 +fi + +# 5. 启动新的Docker容器(不使用build参数) +log "启动新的Docker容器..." +# 使用--no-build参数避免docker-compose尝试重新构建 +docker-compose -f "$DOCKER_COMPOSE_FILE" up -d --no-build +if [ $? -ne 0 ]; then + log "错误:启动容器失败!请检查配置文件。" + exit 1 +fi + +# 6. 验证容器是否正常启动 +log "验证容器运行状态..." +sleep 10 +if docker-compose -f "$DOCKER_COMPOSE_FILE" ps | grep -q "Up"; then + log "容器启动成功!" +else + log "警告:容器可能未正常启动,正在检查日志..." + docker-compose -f "$DOCKER_COMPOSE_FILE" logs | tail -50 +fi + +# 7. 清理无用的Docker镜像 +log "清理无用的Docker镜像..." +docker image prune -f + +log "应用部署完成!" \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..3e54cb9 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +# 移除version声明以解决兼容性警告 + +services: + app: + build: . + image: reject-app + container_name: reject-app + ports: + - "3000:3000" + environment: + - NODE_ENV=production + - DB_HOST=1.95.162.61 + - DB_USER=root + - DB_PASSWORD=schl@2025 + - DB_NAME=wechat_app + - USER_LOGIN_DB_NAME=userlogin + restart: always + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" \ No newline at end of file diff --git a/health-check.sh b/health-check.sh new file mode 100644 index 0000000..718247c --- /dev/null +++ b/health-check.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +# 健康检查脚本:定期检查应用是否正常运行,如果不正常则自动重启 + +# 配置参数 +APP_DIR="/app" +DOCKER_COMPOSE_FILE="docker-compose.yml" +CHECK_INTERVAL=300 # 检查间隔(秒) +MAX_RESTARTS=3 # 最大重启次数 +RESTART_INTERVAL=3600 # 重启间隔(秒) + +# 带颜色的日志函数 +colored_log() { + local color=$1 + local message=$2 + local reset="\033[0m" + local colors=( + ["red"]="\033[31m" + ["green"]="\033[32m" + ["yellow"]="\033[33m" + ["blue"]="\033[34m" + ["purple"]="\033[35m" + ) + echo -e "${colors[$color]}[$(date '+%Y-%m-%d %H:%M:%S')] $message$reset" +} + +log() { + colored_log "blue" "$1" +} + +success() { + colored_log "green" "$1" +} + +error() { + colored_log "red" "$1" +} + +warning() { + colored_log "yellow" "$1" +} + +log "启动健康检查服务..." + +# 初始化重启计数器 +restart_count=0 +last_restart_time=$(date +%s) + +while true; do + log "开始健康检查..." + + cd "$APP_DIR" + + # 检查容器是否在运行 + if docker-compose -f "$DOCKER_COMPOSE_FILE" ps | grep -q "Up"; then + # 检查应用是否能正常响应 + if curl -s -o /dev/null -w "%{http_code}" http://localhost:3000 > /dev/null; then + success "应用运行正常" + else + warning "应用容器在运行,但无法正常响应请求" + + # 查看应用日志 + log "查看应用日志:" + docker-compose -f "$DOCKER_COMPOSE_FILE" logs -n 10 + + # 检查重启次数 + current_time=$(date +%s) + time_since_last_restart=$((current_time - last_restart_time)) + + if [ $restart_count -lt $MAX_RESTARTS ] || [ $time_since_last_restart -gt $RESTART_INTERVAL ]; then + log "尝试重启应用..." + if docker-compose -f "$DOCKER_COMPOSE_FILE" restart; then + success "应用已重启" + restart_count=$((restart_count + 1)) + last_restart_time=$current_time + else + error "应用重启失败" + fi + else + error "已达到最大重启次数,在$RESTART_INTERVAL秒内不再尝试重启" + fi + fi + else + warning "应用容器未运行" + + # 检查重启次数 + current_time=$(date +%s) + time_since_last_restart=$((current_time - last_restart_time)) + + if [ $restart_count -lt $MAX_RESTARTS ] || [ $time_since_last_restart -gt $RESTART_INTERVAL ]; then + log "尝试启动应用..." + if docker-compose -f "$DOCKER_COMPOSE_FILE" up -d; then + success "应用已启动" + restart_count=$((restart_count + 1)) + last_restart_time=$current_time + else + error "应用启动失败" + fi + else + error "已达到最大重启次数,在$RESTART_INTERVAL秒内不再尝试启动" + fi + fi + + log "健康检查完成,等待$CHECK_INTERVAL秒后再次检查..." + sleep $CHECK_INTERVAL +done \ No newline at end of file diff --git a/image-processor.js b/image-processor.js new file mode 100644 index 0000000..0b965d4 --- /dev/null +++ b/image-processor.js @@ -0,0 +1,124 @@ +const sharp = require('sharp'); + +class ImageProcessor { + /** + * 为图片添加文字水印 + * @param {Buffer} imageBuffer - 原始图片的Buffer数据 + * @param {String} text - 水印文字内容 + * @param {Object} options - 水印配置选项 + * @returns {Promise} - 添加水印后的图片Buffer + */ + static async addWatermark(imageBuffer, text = '又鸟蛋平台', options = {}) { + try { + console.log('【图片处理】开始添加水印'); + + // 设置默认配置 + const defaultOptions = { + fontSize: 20, // 字体大小 - 减小以确保完整显示 + color: 'rgba(0,0,0,0.5)', // 文字颜色(加深以便更清晰) + position: 'bottom-right', // 水印位置 + marginX: -50, // X轴边距 - 调整使水印居中在红色框中 + marginY: 10 // Y轴边距 - 减小使水印靠下,放入红色框中 + }; + + // 强制使用'bottom-right'位置 + options.position = 'bottom-right'; + + const config = { ...defaultOptions, ...options }; + + // 使用sharp处理图片 + const image = sharp(imageBuffer); + + // 获取图片信息以确定水印位置 + const metadata = await image.metadata(); + const width = metadata.width || 800; + const height = metadata.height || 600; + + // 确定水印位置 + let x = config.marginX; + let y = config.marginY; + + if (config.position === 'bottom-right') { + // 右下角位置,需要计算文字宽度(这里简化处理,实际应该根据字体计算) + // 这里使用一个简单的估算:每个字符约占字体大小的0.6倍宽度 + const estimatedTextWidth = text.length * config.fontSize * 0.6; + x = width - estimatedTextWidth - config.marginX; + y = height - config.fontSize - config.marginY; + } else if (config.position === 'center') { + x = (width / 2) - (text.length * config.fontSize * 0.3); + y = height / 2; + } else if (config.position === 'top-left') { + // 左上角,使用默认的margin值 + } + + // 确保位置不会超出图片边界 + x = Math.max(0, Math.min(x, width - 1)); + y = Math.max(config.fontSize, Math.min(y, height - 1)); + + // 添加文字水印 + const watermarkedBuffer = await image + .composite([{ + input: Buffer.from(` + ${text} + `), + gravity: 'southeast' + }]) + .toBuffer(); + + console.log('【图片处理】水印添加成功'); + return watermarkedBuffer; + } catch (error) { + console.error('【图片处理】添加水印失败:', error.message); + console.error('【图片处理】错误详情:', error); + // 如果水印添加失败,返回原始图片 + return imageBuffer; + } + } + + /** + * 批量为图片添加水印 + * @param {Array} imageBuffers - 图片Buffer数组 + * @param {String} text - 水印文字内容 + * @param {Object} options - 水印配置选项 + * @returns {Promise>} - 添加水印后的图片Buffer数组 + */ + static async addWatermarkToMultiple(imageBuffers, text = '又鸟蛋平台', options = {}) { + try { + console.log(`【图片处理】开始批量添加水印,共${imageBuffers.length}张图片`); + + const watermarkedPromises = imageBuffers.map(buffer => + this.addWatermark(buffer, text, options) + ); + + const results = await Promise.all(watermarkedPromises); + console.log('【图片处理】批量水印添加完成'); + return results; + } catch (error) { + console.error('【图片处理】批量添加水印失败:', error.message); + throw error; + } + } + + /** + * 为Base64编码的图片添加水印 + * @param {String} base64Image - Base64编码的图片 + * @param {String} text - 水印文字内容 + * @param {Object} options - 水印配置选项 + * @returns {Promise} - 添加水印后的图片Buffer + */ + static async addWatermarkToBase64(base64Image, text = '又鸟蛋平台', options = {}) { + try { + // 移除Base64前缀 + const base64Data = base64Image.replace(/^data:image\/(png|jpeg|jpg|gif);base64,/, ''); + // 转换为Buffer + const buffer = Buffer.from(base64Data, 'base64'); + // 添加水印 + return await this.addWatermark(buffer, text, options); + } catch (error) { + console.error('【图片处理】为Base64图片添加水印失败:', error.message); + throw error; + } + } +} + +module.exports = ImageProcessor; diff --git a/login.html b/login.html new file mode 100644 index 0000000..1c14435 --- /dev/null +++ b/login.html @@ -0,0 +1,255 @@ + + + + + + 登录页面 + + + + + + + + \ No newline at end of file diff --git a/oss-config.js b/oss-config.js new file mode 100644 index 0000000..1f7d8af --- /dev/null +++ b/oss-config.js @@ -0,0 +1,8 @@ +// 阿里云OSS配置 +module.exports = { + region: 'oss-cn-chengdu', // OSS区域,例如 'oss-cn-hangzhou' + accessKeyId: 'LTAI5tRT6ReeHUdmqFpmLZi7', // 访问密钥ID + accessKeySecret: 'zTnK27IAphwgCDMmyJzMUsHYxGsDBE', // 访问密钥Secret + bucket: 'my-supplier-photos', // OSS存储桶名称 + endpoint: 'oss-cn-chengdu.aliyuncs.com' // 注意:不要在endpoint中包含bucket名称 +}; \ No newline at end of file diff --git a/oss-uploader.js b/oss-uploader.js new file mode 100644 index 0000000..69cbc3a --- /dev/null +++ b/oss-uploader.js @@ -0,0 +1,320 @@ +const fs = require('fs'); +const path = require('path'); +const { createHash } = require('crypto'); +const OSSClient = require('ali-oss'); +const ossConfig = require('./oss-config'); + +// 创建OSS客户端 - ali-oss 6.23.0版本的正确配置 +let client = null; + +// 初始化OSS客户端的函数 +function initOSSClient() { + try { + console.log('初始化OSS客户端配置:', { + region: ossConfig.region, + accessKeyId: ossConfig.accessKeyId ? '已配置' : '未配置', + accessKeySecret: ossConfig.accessKeySecret ? '已配置' : '未配置', + bucket: ossConfig.bucket, + endpoint: `https://${ossConfig.endpoint}` + }); + + client = new OSSClient({ + region: ossConfig.region, + accessKeyId: ossConfig.accessKeyId, + accessKeySecret: ossConfig.accessKeySecret, + bucket: ossConfig.bucket, + endpoint: ossConfig.endpoint, // 直接使用配置的endpoint,不添加前缀 + secure: true, // 启用HTTPS + cname: false // 对于标准OSS域名,不需要启用cname模式 + }); + + return client; + } catch (error) { + console.error('初始化OSS客户端失败:', error); + throw error; + } +} + +// 延迟初始化,避免应用启动时就连接OSS +function getOSSClient() { + if (!client) { + return initOSSClient(); + } + return client; +} + +class OssUploader { + /** + * 上传文件到OSS + * @param {String} filePath - 本地文件路径 + * @param {String} folder - OSS上的文件夹路径 + * @param {String} fileType - 文件类型,默认为'image' + * @returns {Promise} - 上传后的文件URL + */ + /** + * 计算文件的MD5哈希值 + * @param {String} filePath - 文件路径 + * @returns {Promise} - MD5哈希值 + */ + static async getFileHash(filePath) { + return new Promise((resolve, reject) => { + const hash = createHash('md5'); + const stream = fs.createReadStream(filePath); + + stream.on('error', reject); + stream.on('data', chunk => hash.update(chunk)); + stream.on('end', () => resolve(hash.digest('hex'))); + }); + } + + /** + * 计算缓冲区的MD5哈希值 + * @param {Buffer} buffer - 数据缓冲区 + * @returns {String} - MD5哈希值 + */ + static getBufferHash(buffer) { + return createHash('md5').update(buffer).digest('hex'); + } + + static async uploadFile(filePath, folder = 'images', fileType = 'image') { + try { + console.log('【OSS上传】开始上传文件:', filePath, '到目录:', folder); + + // 确保文件存在 + const fileExists = await fs.promises.access(filePath).then(() => true).catch(() => false); + if (!fileExists) { + throw new Error(`文件不存在: ${filePath}`); + } + + // 获取文件扩展名 + const extname = path.extname(filePath).toLowerCase(); + if (!extname) { + throw new Error(`无法获取文件扩展名: ${filePath}`); + } + + // 基于文件内容计算MD5哈希值,实现文件级去重 + console.log('【文件去重】开始计算文件哈希值...'); + const fileHash = await this.getFileHash(filePath); + console.log(`【文件去重】文件哈希计算完成: ${fileHash}`); + + // 使用哈希值作为文件名,确保相同内容的文件生成相同的文件名 + const uniqueFilename = `${fileHash}${extname}`; + const ossFilePath = `${folder}/${fileType}/${uniqueFilename}`; + + console.log(`【文件去重】使用基于内容的文件名: ${uniqueFilename}`); + + // 获取OSS客户端,延迟初始化 + const ossClient = getOSSClient(); + + // 测试OSS连接 + try { + await ossClient.list({ max: 1 }); + console.log('OSS连接测试成功'); + } catch (connError) { + console.error('OSS连接测试失败,尝试重新初始化客户端:', connError.message); + // 尝试重新初始化客户端 + initOSSClient(); + } + + // 检查OSS客户端配置 + console.log('【OSS上传】OSS配置检查 - region:', ossClient.options.region, 'bucket:', ossClient.options.bucket); + + // 上传文件,明确设置为公共读权限 + console.log(`开始上传文件到OSS: ${filePath} -> ${ossFilePath}`); + const result = await ossClient.put(ossFilePath, filePath, { + headers: { + 'x-oss-object-acl': 'public-read' // 确保文件可以公开访问 + }, + acl: 'public-read' // 额外设置ACL参数,确保文件公开可读 + }); + console.log(`文件上传成功: ${result.url}`); + console.log('已设置文件为公共读权限'); + + // 返回完整的文件URL + return result.url; + } catch (error) { + console.error('【OSS上传】上传文件失败:', error); + console.error('【OSS上传】错误详情:', error.message); + console.error('【OSS上传】错误栈:', error.stack); + throw error; + } + } + + /** + * 从缓冲区上传文件到OSS + * @param {Buffer} buffer - 文件数据缓冲区 + * @param {String} filename - 文件名 + * @param {String} folder - OSS上的文件夹路径 + * @param {String} fileType - 文件类型,默认为'image' + * @returns {Promise} - 上传后的文件URL + */ + static async uploadBuffer(buffer, filename, folder = 'images', fileType = 'image') { + try { + // 获取文件扩展名 + const extname = path.extname(filename).toLowerCase(); + if (!extname) { + throw new Error(`无法获取文件扩展名: ${filename}`); + } + + // 基于文件内容计算MD5哈希值,实现文件级去重 + console.log('【文件去重】开始计算缓冲区哈希值...'); + const bufferHash = this.getBufferHash(buffer); + console.log(`【文件去重】缓冲区哈希计算完成: ${bufferHash}`); + + // 使用哈希值作为文件名,确保相同内容的文件生成相同的文件名 + const uniqueFilename = `${bufferHash}${extname}`; + const ossFilePath = `${folder}/${fileType}/${uniqueFilename}`; + + console.log(`【文件去重】使用基于内容的文件名: ${uniqueFilename}`); + + // 获取OSS客户端,延迟初始化 + const ossClient = getOSSClient(); + + // 上传缓冲区,明确设置为公共读权限 + console.log(`开始上传缓冲区到OSS: ${ossFilePath}`); + const result = await ossClient.put(ossFilePath, buffer, { + headers: { + 'x-oss-object-acl': 'public-read' // 确保文件可以公开访问 + }, + acl: 'public-read' // 额外设置ACL参数,确保文件公开可读 + }); + console.log(`缓冲区上传成功: ${result.url}`); + console.log('已设置文件为公共读权限'); + + // 返回完整的文件URL + return result.url; + } catch (error) { + console.error('OSS缓冲区上传失败:', error); + console.error('OSS缓冲区上传错误详情:', error.message); + console.error('OSS缓冲区上传错误栈:', error.stack); + throw error; + } + } + + /** + * 批量上传文件到OSS + * @param {Array} filePaths - 本地文件路径数组 + * @param {String} folder - OSS上的文件夹路径 + * @param {String} fileType - 文件类型,默认为'image' + * @returns {Promise>} - 上传后的文件URL数组 + */ + static async uploadFiles(filePaths, folder = 'images', fileType = 'image') { + try { + const uploadPromises = filePaths.map(filePath => + this.uploadFile(filePath, folder, fileType) + ); + + const urls = await Promise.all(uploadPromises); + console.log(`批量上传完成,成功上传${urls.length}个文件`); + return urls; + } catch (error) { + console.error('OSS批量上传失败:', error); + throw error; + } + } + +/** + * 删除OSS上的文件 + * @param {String} ossFilePath - OSS上的文件路径 + * @returns {Promise} - 删除是否成功 + */ +static async deleteFile(ossFilePath) { + try { + console.log(`【OSS删除】开始删除OSS文件: ${ossFilePath}`); + const ossClient = getOSSClient(); + + // 【新增】记录OSS客户端配置信息(隐藏敏感信息) + console.log(`【OSS删除】OSS客户端配置 - region: ${ossClient.options.region}, bucket: ${ossClient.options.bucket}`); + + const result = await ossClient.delete(ossFilePath); + console.log(`【OSS删除】OSS文件删除成功: ${ossFilePath}`, result); + return true; + } catch (error) { + console.error('【OSS删除】OSS文件删除失败:', ossFilePath, '错误:', error.message); + console.error('【OSS删除】错误详情:', error); + + // 【增强日志】详细分析错误类型 + console.log('【OSS删除】=== 错误详细分析开始 ==='); + console.log('【OSS删除】错误名称:', error.name); + console.log('【OSS删除】错误代码:', error.code); + console.log('【OSS删除】HTTP状态码:', error.status); + console.log('【OSS删除】请求ID:', error.requestId); + console.log('【OSS删除】主机ID:', error.hostId); + + // 【关键检查】判断是否为权限不足错误 + const isPermissionError = + error.code === 'AccessDenied' || + error.status === 403 || + error.message.includes('permission') || + error.message.includes('AccessDenied') || + error.message.includes('do not have write permission'); + + if (isPermissionError) { + console.error('【OSS删除】❌ 确认是权限不足错误!'); + console.error('【OSS删除】❌ 当前AccessKey缺少删除文件的权限'); + console.error('【OSS删除】❌ 请检查RAM策略是否包含 oss:DeleteObject 权限'); + console.error('【OSS删除】❌ 建议在RAM中授予 AliyunOSSFullAccess 或自定义删除权限'); + } + + console.log('【OSS删除】=== 错误详细分析结束 ==='); + + // 如果文件不存在,也算删除成功 + if (error.code === 'NoSuchKey' || error.status === 404) { + console.log(`【OSS删除】文件不存在,视为删除成功: ${ossFilePath}`); + return true; + } + + // 【新增】对于权限错误,提供更友好的错误信息 + if (isPermissionError) { + const permissionError = new Error(`OSS删除权限不足: ${error.message}`); + permissionError.code = 'OSS_ACCESS_DENIED'; + permissionError.originalError = error; + throw permissionError; + } + + throw error; + } +} + /** + * 获取OSS配置信息 + * @returns {Object} - OSS配置信息 + */ + static getConfig() { + return { + region: ossConfig.region, + bucket: ossConfig.bucket, + endpoint: ossConfig.endpoint + }; + } + + /** + * 测试OSS连接 + * @returns {Promise} - 连接测试结果 + */ + static async testConnection() { + try { + console.log('【OSS连接测试】开始测试OSS连接...'); + const ossClient = getOSSClient(); + + // 执行简单的list操作来验证连接 + const result = await ossClient.list({ max: 1 }); + console.log('【OSS连接测试】连接成功,存储桶中有', result.objects.length, '个对象'); + + return { + success: true, + message: 'OSS连接成功', + region: ossClient.options.region, + bucket: ossClient.options.bucket + }; + } catch (error) { + console.error('【OSS连接测试】连接失败:', error.message); + return { + success: false, + message: `OSS连接失败: ${error.message}`, + error: error.message + }; + } + } +} + +module.exports = OssUploader; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..8871825 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5348 @@ +{ + "name": "Review", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "ali-oss": "^6.23.0", + "axios": "^1.13.2", + "body-parser": "^2.2.1", + "cors": "^2.8.5", + "express": "^5.1.0", + "mysql2": "^3.15.3", + "sharp": "^0.34.5" + }, + "devDependencies": { + "chai": "^6.2.1", + "mocha": "^11.7.5", + "nyc": "^17.1.0", + "sinon": "^21.0.0", + "supertest": "^7.1.4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "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/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@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.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", + "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/colour": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz", + "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@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/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@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/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@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.npmjs.org/@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.npmjs.org/@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/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", + "integrity": "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", + "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.3.tgz", + "integrity": "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "type-detect": "^4.1.0" + } + }, + "node_modules/@sinonjs/samsam/node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.3.tgz", + "integrity": "sha512-yqXL+k5rr8+ZRpOAntkaaRgWgE5o8ESAj5DyRmVTCSoZxXmqemb9Dd7T4i5UzwuERdLAJUy6XzR9zFVuf0kzkw==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ali-oss": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/ali-oss/-/ali-oss-6.23.0.tgz", + "integrity": "sha512-FipRmyd16Pr/tEey/YaaQ/24Pc3HEpLM9S1DRakEuXlSLXNIJnu1oJtHM53eVYpvW3dXapSjrip3xylZUTIZVQ==", + "license": "MIT", + "dependencies": { + "address": "^1.2.2", + "agentkeepalive": "^3.4.1", + "bowser": "^1.6.0", + "copy-to": "^2.0.1", + "dateformat": "^2.0.0", + "debug": "^4.3.4", + "destroy": "^1.0.4", + "end-or-error": "^1.0.1", + "get-ready": "^1.0.0", + "humanize-ms": "^1.2.0", + "is-type-of": "^1.4.0", + "js-base64": "^2.5.2", + "jstoxml": "^2.0.0", + "lodash": "^4.17.21", + "merge-descriptors": "^1.0.1", + "mime": "^2.4.5", + "platform": "^1.3.1", + "pump": "^3.0.0", + "qs": "^6.4.0", + "sdk-base": "^2.0.1", + "stream-http": "2.8.2", + "stream-wormhole": "^1.0.4", + "urllib": "^2.44.0", + "utility": "^1.18.0", + "xml2js": "^0.6.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ali-oss/node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/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/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", + "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/axios": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", + "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.3.tgz", + "integrity": "sha512-8QdH6czo+G7uBsNo0GiUfouPN1lRzKdJTGnKXwe12gkFbnnOUaUKGN55dMkfy+mnxmvjwl9zcI4VncczcVXDhA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/body-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", + "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/bowser": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-1.9.4.tgz", + "integrity": "sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001759", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001759.tgz", + "integrity": "sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.1.tgz", + "integrity": "sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/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/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/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/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "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/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/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/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "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/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/component-emitter": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", + "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-to": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", + "integrity": "sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==", + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/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/dateformat": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", + "integrity": "sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-require-extensions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", + "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-user-agent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-user-agent/-/default-user-agent-1.0.0.tgz", + "integrity": "sha512-bDF7bg6OSNcSwFWPu4zYKpVkJZQYVrAANMYB8bc9Szem1D0yKdm4sa/rOCs2aC9+2GMqQ7KnwtZRvDhmLF0dXw==", + "license": "MIT", + "dependencies": { + "os-name": "~1.0.3" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/digest-header": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/digest-header/-/digest-header-1.1.0.tgz", + "integrity": "sha512-glXVh42vz40yZb9Cq2oMOt70FIoWiv+vxNvdKdU8CwjLad25qHM3trLxhl9bVjdr6WaslIXhWpn0NO8T/67Qjg==", + "license": "MIT", + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.266", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.266.tgz", + "integrity": "sha512-kgWEglXvkEfMH7rxP5OSZZwnaDWT7J9EoZCujhnpLbfi0bbNtRkgdX2E3gt0Uer11c61qCYktB3hwkAS325sJg==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/end-or-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/end-or-error/-/end-or-error-1.0.1.tgz", + "integrity": "sha512-OclLMSug+k2A0JKuf494im25ANRBVW8qsjmwbgX7lQ8P82H21PQ1PWkoYwb9y5yMBS69BPlwtzdIFClo3+7kOQ==", + "license": "MIT", + "engines": { + "node": ">= 0.11.14" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/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/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/formidable": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.4.tgz", + "integrity": "sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@paralleldrive/cuid2": "^2.2.2", + "dezalgo": "^1.0.4", + "once": "^1.4.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/formstream": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/formstream/-/formstream-1.5.2.tgz", + "integrity": "sha512-NASf0lgxC1AyKNXQIrXTEYkiX99LhCEXTkiGObXAkpBui86a4u8FjH1o2bGb3PpqI3kafC+yw4zWeK6l6VHTgg==", + "license": "MIT", + "dependencies": { + "destroy": "^1.0.4", + "mime": "^2.5.2", + "node-hex": "^1.0.1", + "pause-stream": "~0.0.11" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "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/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "license": "MIT", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-ready": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-ready/-/get-ready-1.0.0.tgz", + "integrity": "sha512-mFXCZPJIlcYcth+N8267+mghfYN9h3EhsDa6JSnbA3Wrhh/XFpuowviFcsDeYZtKspQyWyJqfs4O6P8CHeTwzw==", + "license": "MIT" + }, + "node_modules/glob": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "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-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", + "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-class-hotfix": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/is-class-hotfix/-/is-class-hotfix-0.0.6.tgz", + "integrity": "sha512-0n+pzCC6ICtVr/WXnN2f03TK/3BfXY7me4cjCAqT8TYXEl0+JBRoqBo94JJHXcyDSLUeWbNX8Fvy5g5RJdAstQ==", + "license": "MIT" + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", + "license": "MIT" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-type-of": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/is-type-of/-/is-type-of-1.4.0.tgz", + "integrity": "sha512-EddYllaovi5ysMLMEN7yzHEKh8A850cZ7pykrY1aNRQGn/CDjRDE9qEWbIdt7xGEVJmjBXzU/fNnC4ABTm8tEQ==", + "license": "MIT", + "dependencies": { + "core-util-is": "^1.0.2", + "is-class-hotfix": "~0.0.6", + "isstream": "~0.1.2" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "license": "MIT" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "append-transform": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-processinfo": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", + "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", + "dev": true, + "license": "ISC", + "dependencies": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.3", + "istanbul-lib-coverage": "^3.2.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/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/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-base64": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", + "license": "BSD-3-Clause" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jstoxml": { + "version": "2.2.9", + "resolved": "https://registry.npmjs.org/jstoxml/-/jstoxml-2.2.9.tgz", + "integrity": "sha512-OYWlK0j+roh+eyaMROlNbS5cd5R25Y+IUpdl7cNdB8HNrkgwQzIS7L9MegxOiWNBj9dQhA/yAxiMwCC5mwNoBw==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, + "node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/lru.min": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.2.tgz", + "integrity": "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==", + "license": "MIT", + "engines": { + "bun": ">=1.0.0", + "deno": ">=1.30.0", + "node": ">=8.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wellwelwel" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/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.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "11.7.5", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", + "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", + "dev": true, + "license": "MIT", + "dependencies": { + "browser-stdout": "^1.3.1", + "chokidar": "^4.0.1", + "debug": "^4.3.5", + "diff": "^7.0.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^9.0.5", + "ms": "^2.1.3", + "picocolors": "^1.1.1", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mysql2": { + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.3.tgz", + "integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==", + "license": "MIT", + "dependencies": { + "aws-ssl-profiles": "^1.1.1", + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.7.0", + "long": "^5.2.1", + "lru.min": "^1.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", + "license": "MIT", + "dependencies": { + "lru-cache": "^7.14.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-hex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/node-hex/-/node-hex-1.0.1.tgz", + "integrity": "sha512-iwpZdvW6Umz12ICmu9IYPRxg0tOLGmU3Tq2tKetejCj3oZd7b2nUXwP3a7QA5M9glWy8wlPS1G3RwM/CdsUbdQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "process-on-spawn": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nyc": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-17.1.0.tgz", + "integrity": "sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^3.3.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^6.0.2", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/nyc/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/nyc/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/nyc/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nyc/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nyc/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nyc/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "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/nyc/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/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/nyc/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nyc/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/os-name": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-1.0.3.tgz", + "integrity": "sha512-f5estLO2KN8vgtTRaILIgEGBoBrMnZ3JQ7W9TMZCnOIGwHe8TRGSpcagnWDo+Dfhd/z08k9Xe75hvciJJ8Qaew==", + "license": "MIT", + "dependencies": { + "osx-release": "^1.0.0", + "win-release": "^1.0.0" + }, + "bin": { + "os-name": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osx-release": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/osx-release/-/osx-release-1.1.0.tgz", + "integrity": "sha512-ixCMMwnVxyHFQLQnINhmIpWqXIfS2YOXchwQrk+OFzmo6nDjQ0E4KXAyyUh0T0MZgV4bUhkRrAbVqlE4yLVq4A==", + "license": "MIT", + "dependencies": { + "minimist": "^1.1.0" + }, + "bin": { + "osx-release": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/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/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "license": [ + "MIT", + "Apache2" + ], + "dependencies": { + "through": "~2.3" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/platform": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", + "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", + "license": "MIT" + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/process-on-spawn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.1.0.tgz", + "integrity": "sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", + "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.7.0", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "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.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", + "dev": true, + "license": "ISC", + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "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/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.3.tgz", + "integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==", + "license": "BlueOak-1.0.0" + }, + "node_modules/sdk-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/sdk-base/-/sdk-base-2.0.1.tgz", + "integrity": "sha512-eeG26wRwhtwYuKGCDM3LixCaxY27Pa/5lK4rLKhQa7HBjJ3U3Y+f81MMZQRsDw/8SC2Dao/83yJTXJ8aULuN8Q==", + "license": "MIT", + "dependencies": { + "get-ready": "~1.0.0" + } + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/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.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/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/sinon": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.0.tgz", + "integrity": "sha512-TOgRcwFPbfGtpqvZw+hyqJDvqfapr1qUlOizROIk4bBLjlsjlB00Pg6wMFXNtJRpu+eCZuVOaLatG7M8105kAw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.1", + "@sinonjs/fake-timers": "^13.0.5", + "@sinonjs/samsam": "^8.0.1", + "diff": "^7.0.0", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/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/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/spawn-wrap/node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/spawn-wrap/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stream-http": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.2.tgz", + "integrity": "sha512-QllfrBhqF1DPcz46WxKTs6Mz1Bpc+8Qm6vbqOpVav5odAXwbyzwnEczoWqtxrsmlO+cJqtPrp/8gWKWjaKLLlA==", + "license": "MIT", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/stream-wormhole": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stream-wormhole/-/stream-wormhole-1.1.0.tgz", + "integrity": "sha512-gHFfL3px0Kctd6Po0M8TzEvt3De/xu6cnRrjlfYNhwbhLPLwigI2t1nc6jrzNuaYg5C4YF78PPFuQPzRiqn9ew==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/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/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "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/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/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-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/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/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/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-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superagent": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-10.2.3.tgz", + "integrity": "sha512-y/hkYGeXAj7wUMjxRbB21g/l6aAEituGXM9Rwl4o20+SX3e8YOSV6BxFXl+dL3Uk0mjSL3kCbNkwURm8/gEDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "component-emitter": "^1.3.1", + "cookiejar": "^2.1.4", + "debug": "^4.3.7", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.4", + "formidable": "^3.5.4", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.2" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/supertest": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-7.1.4.tgz", + "integrity": "sha512-tjLPs7dVyqgItVFirHYqe2T+MfWc2VOBQ8QFKKbWTA3PU7liZR8zoSpAi/C1k1ilm9RsXIKYf197oap9wXGVYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "methods": "^1.1.2", + "superagent": "^10.2.3" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "license": "MIT" + }, + "node_modules/to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==", + "license": "MIT" + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/unescape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unescape/-/unescape-1.0.1.tgz", + "integrity": "sha512-O0+af1Gs50lyH1nUu3ZyYS1cRh01Q/kUKatTOkSs7jukXE6/NebucDVxyiDsA9AQ4JC1V1jUH9EO8JX2nMDgGQ==", + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz", + "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/urllib": { + "version": "2.44.0", + "resolved": "https://registry.npmjs.org/urllib/-/urllib-2.44.0.tgz", + "integrity": "sha512-zRCJqdfYllRDA9bXUtx+vccyRqtJPKsw85f44zH7zPD28PIvjMqIgw9VwoTLV7xTBWZsbebUFVHU5ghQcWku2A==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.3.0", + "content-type": "^1.0.2", + "default-user-agent": "^1.0.0", + "digest-header": "^1.0.0", + "ee-first": "~1.1.1", + "formstream": "^1.1.0", + "humanize-ms": "^1.2.0", + "iconv-lite": "^0.6.3", + "pump": "^3.0.0", + "qs": "^6.4.0", + "statuses": "^1.3.1", + "utility": "^1.16.1" + }, + "engines": { + "node": ">= 0.10.0" + }, + "peerDependencies": { + "proxy-agent": "^5.0.0" + }, + "peerDependenciesMeta": { + "proxy-agent": { + "optional": true + } + } + }, + "node_modules/urllib/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/urllib/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utility": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/utility/-/utility-1.18.0.tgz", + "integrity": "sha512-PYxZDA+6QtvRvm//++aGdmKG/cI07jNwbROz0Ql+VzFV1+Z0Dy55NI4zZ7RHc9KKpBePNFwoErqIuqQv/cjiTA==", + "license": "MIT", + "dependencies": { + "copy-to": "^2.0.1", + "escape-html": "^1.0.3", + "mkdirp": "^0.5.1", + "mz": "^2.7.0", + "unescape": "^1.0.1" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/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/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/win-release": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz", + "integrity": "sha512-iCRnKVvGxOQdsKhcQId2PXV1vV3J/sDPXKA4Oe9+Eti2nb2ESEsYHRYls/UjoUW3bIc5ZDO8dTH50A/5iVN+bw==", + "license": "MIT", + "dependencies": { + "semver": "^5.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/win-release/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/workerpool": { + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/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/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "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/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "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/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/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/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/xml2js": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", + "integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==", + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "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/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/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/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..74cddf2 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "dependencies": { + "ali-oss": "^6.23.0", + "axios": "^1.13.2", + "body-parser": "^2.2.1", + "cors": "^2.8.5", + "express": "^5.1.0", + "mysql2": "^3.15.3", + "sharp": "^0.34.5" + }, + "devDependencies": { + "chai": "^6.2.1", + "mocha": "^11.7.5", + "nyc": "^17.1.0", + "sinon": "^21.0.0", + "supertest": "^7.1.4" + } +} diff --git a/supply-manager.example.js b/supply-manager.example.js new file mode 100644 index 0000000..f1e9837 --- /dev/null +++ b/supply-manager.example.js @@ -0,0 +1,66 @@ +// 货源管理模块使用示例 +// 本文件展示如何在页面中使用SupplyManager类 + +const SupplyManager = require('./supply-manager.js'); + +// 页面实例示例 +const pageInstance = { + data: {}, + setData: function(data) { + this.data = { ...this.data, ...data }; + console.log('页面数据更新:', this.data); + } +}; + +// 初始化货源管理器 +const supplyManager = new SupplyManager(pageInstance); + +// 使用示例 +async function exampleUsage() { + console.log('===== 货源管理模块使用示例 ====='); + + try { + // 1. 加载货源列表 + console.log('1. 加载货源列表...'); + await supplyManager.loadSupplies(); + console.log(' 加载完成,货源数量:', supplyManager.data.supplies.length); + + // 2. 搜索货源 + console.log('2. 搜索货源...'); + supplyManager.data.searchKeyword = '罗曼粉'; + supplyManager.searchSupplies(); + console.log(' 搜索完成,结果数量:', supplyManager.data.publishedSupplies.length); + + // 3. 添加新货源 + console.log('3. 添加新货源...'); + supplyManager.data.newSupply = { + name: '罗曼粉', + price: '10.5', + minOrder: '50', + yolk: '红心', + spec: '格子装', + region: '北京市 北京市 朝阳区', + imageUrls: [] + }; + // 注意:实际添加货源需要登录状态和网络请求 + // await supplyManager.addSupply(); + console.log(' 新货源准备完成,等待发布'); + + // 4. 处理图片 + console.log('4. 处理图片URL...'); + const processedImages = supplyManager.processImageUrls(['http://example.com/image1.jpg', 'placeholder://example']); + console.log(' 图片处理结果:', processedImages); + + // 5. 格式化时间 + console.log('5. 格式化时间...'); + const formattedTime = supplyManager.formatCreateTime(new Date()); + console.log(' 格式化后的时间:', formattedTime); + + console.log('===== 示例运行完成 ====='); + } catch (error) { + console.error('示例运行出错:', error); + } +} + +// 运行示例 +exampleUsage(); diff --git a/supply-manager.js b/supply-manager.js new file mode 100644 index 0000000..0747554 --- /dev/null +++ b/supply-manager.js @@ -0,0 +1,1113 @@ +// 货源管理模块 - 抽离自seller页面 +// 不包含联系客服和入驻功能 + +const API = require('./api.js'); + +class SupplyManager { + constructor(pageInstance) { + this.page = pageInstance; + this.data = { + supplies: [], + publishedSupplies: [], + pendingSupplies: [], + rejectedSupplies: [], + draftSupplies: [], + showModal: false, + showEditModal: false, + showRejectReasonModal: false, + currentRejectSupply: null, + rejectReason: '', + showTabBar: true, + showSpecSelectModal: false, + modalSpecSearchKeyword: '', + filteredModalSpecOptions: [], + selectedModalSpecIndex: -1, + currentSpecMode: 'create', + showNameSelectModal: false, + showYolkSelectModal: false, + selectedNameIndex: -1, + selectedYolkIndex: -1, + productNameOptions: ['罗曼粉', '伊莎粉', '罗曼灰', '海蓝灰', '海蓝褐', '绿壳', '粉一', '粉二', '粉八', '京粉1号', '京红', '京粉6号', '京粉3号', '农大系列', '黑鸡土蛋', '双黄蛋', '大午金凤', '黑凤'], + yolkOptions: ['红心', '黄心', '双色'], + specOptions: ['格子装', '散托', '不限规格', '净重47+', '净重46-47', '净重45-46', '净重44-45', '净重43-44', '净重42-43', '净重41-42', '净重40-41', '净重39-40', '净重38-39', '净重37-39', '净重37-38', '净重36-38', '净重36-37', '净重35-36', '净重34-35', '净重33-34', '净重32-33', '净重32-34', '净重31-32', '净重30-35', '净重30-34', '净重30-32', '净重30-31', '净重29-31', '净重29-30', '净重28-29', '净重28以下', '毛重52以上', '毛重50-51', '毛重48-49', '毛重47-48', '毛重46-47', '毛重45-47', '毛重45-46', '毛重44-45', '毛重43-44', '毛重42-43', '毛重41-42', '毛重40-41', '毛重38-39', '毛重36-37', '毛重34-35', '毛重32-33', '毛重30-31', '毛重30以下'], + specSearchKeyword: '', + editSpecSearchKeyword: '', + filteredSpecOptions: [], + filteredEditSpecOptions: [], + showRegionSelectModal: false, + currentRegionMode: 'create', + regionOptions: [ + // 地区数据 - 这里简化处理,实际使用时可以从原始文件复制完整数据 + { + name: '北京市', + cities: [{ + name: '北京市', + districts: ['东城区', '西城区', '朝阳区', '丰台区', '石景山区', '海淀区'] + }] + } + // 更多地区数据可以根据需要添加 + ], + selectedProvinceIndex: 0, + selectedCityIndex: 0, + selectedDistrictIndex: 0, + currentCities: [], + currentDistricts: [], + regionSearchKeyword: '', + editRegionSearchKeyword: '', + filteredRegionOptions: [], + showSearchResults: false, + newSupply: { + name: '', + price: '', + minOrder: '', + yolk: '', + yolkIndex: 0, + spec: '', + specIndex: 0, + region: '', + grossWeight: '', + imageUrls: [] + }, + newSupplyRegionArray: [], + editSupplyRegionArray: [], + editSupply: { + yolkIndex: 0, + specIndex: 0 + }, + currentImageIndex: 0, + searchKeyword: '', + scale: 1, + offsetX: 0, + offsetY: 0, + lastDistance: 0, + lastTouchPoint: null, + imageWidth: 375, + imageHeight: 375, + minScale: 1, + maxScale: 4, + doubleTapTimeout: null, + doubleTapCount: 0, + pagination: { + published: { page: 1, pageSize: 20, hasMore: true, loading: false }, + pending: { page: 1, pageSize: 20, hasMore: true, loading: false }, + rejected: { page: 1, pageSize: 20, hasMore: true, loading: false }, + draft: { page: 1, pageSize: 20, hasMore: true, loading: false } + }, + currentLoadingType: null, + isPublishedExpanded: true, + isPendingExpanded: true, + isRejectedExpanded: true, + isDraftExpanded: true, + autoPublishAfterEdit: false, + _hasLoadedOnShow: false, + pageScrollLock: false, + touchMoveBlocked: false, + showAuthModal: false, + showOneKeyLoginModal: false, + pendingUserType: 'seller', + avatarUrl: '/images/default-avatar.png', + partnerstatus: '' + }; + + // 初始化规格搜索相关数据 + this.initData(); + } + + initData() { + this.data.filteredSpecOptions = this.data.specOptions; + this.data.filteredEditSpecOptions = this.data.specOptions; + this.data.currentCities = this.data.regionOptions[this.data.selectedProvinceIndex].cities; + this.data.currentDistricts = this.data.regionOptions[this.data.selectedProvinceIndex].cities[this.data.selectedCityIndex].districts; + + // 更新页面数据 + this.updatePageData(); + } + + updatePageData() { + if (this.page && this.page.setData) { + this.page.setData(this.data); + } + } + + // 加载货源列表 + loadSupplies() { + console.log('开始加载货源数据 - 分页模式'); + + // 重置所有分页状态 + this.resetAllPagination(); + + // 并行加载所有类型的货源 + return Promise.all([ + this.loadSuppliesFromServer('published', 1), + this.loadSuppliesFromServer('pending', 1), + this.loadSuppliesFromServer('rejected', 1), + this.loadSuppliesFromServer('draft', 1) + ]); + } + + // 重置所有分页状态 + resetAllPagination() { + this.data.pagination.published = { page: 1, pageSize: 20, hasMore: true, loading: false }; + this.data.pagination.pending = { page: 1, pageSize: 20, hasMore: true, loading: false }; + this.data.pagination.rejected = { page: 1, pageSize: 20, hasMore: true, loading: false }; + this.data.pagination.draft = { page: 1, pageSize: 20, hasMore: true, loading: false }; + this.data.currentLoadingType = null; + + this.updatePageData(); + } + + // 搜索货源 + searchSupplies() { + console.log('搜索货源,关键词:', this.data.searchKeyword); + + const keyword = this.data.searchKeyword.toLowerCase().trim(); + if (!keyword) { + // 如果关键词为空,重新加载所有数据 + return this.loadSupplies(); + } + + // 从所有货源中搜索 + const allSupplies = this.data.supplies; + + // 过滤符合条件的货源 + const filteredSupplies = allSupplies.filter(supply => { + const name = (supply.name || '').toLowerCase(); + const productName = (supply.productName || '').toLowerCase(); + const yolk = (supply.yolk || '').toLowerCase(); + const spec = (supply.spec || '').toLowerCase(); + + return name.includes(keyword) || + productName.includes(keyword) || + yolk.includes(keyword) || + spec.includes(keyword); + }); + + // 将过滤后的货源按照状态分类 + this.data.publishedSupplies = filteredSupplies.filter(s => s.status === 'published'); + this.data.pendingSupplies = filteredSupplies.filter(s => s.status === 'pending_review' || s.status === 'reviewed'); + this.data.rejectedSupplies = filteredSupplies.filter(s => s.status === 'rejected'); + this.data.draftSupplies = filteredSupplies.filter(s => s.status === 'draft' || s.status === 'sold_out'); + + this.updatePageData(); + } + + // 处理图片URL + processImageUrls(imageUrls) { + if (!imageUrls || !Array.isArray(imageUrls)) { + return []; + } + + return imageUrls.map(url => { + if (!url || typeof url !== 'string') return ''; + + let processedUrl = url.trim(); + + // 处理占位符URL - 替换为本地默认图片 + if (processedUrl.startsWith('placeholder://')) { + return '/images/default-product.png'; + } + + // 处理临时文件路径 + if (processedUrl.startsWith('http://tmp/') || processedUrl.startsWith('wxfile://')) { + return processedUrl; + } + + // 确保HTTP URL格式正确 + if (processedUrl.startsWith('//')) { + processedUrl = 'https:' + processedUrl; + } else if (!processedUrl.startsWith('http') && !processedUrl.startsWith('/')) { + processedUrl = '/' + processedUrl; + } + + return processedUrl; + }).filter(url => url && url !== ''); + } + + // 从服务器获取货源数据 + loadSuppliesFromServer(type = 'all', page = 1) { + return new Promise((resolve, reject) => { + const openid = wx.getStorageSync('openid'); + console.log(`loadSuppliesFromServer - type: ${type}, page: ${page}, openid:`, openid); + + if (!openid) { + console.warn('openid不存在,显示空数据状态'); + this.data.supplies = []; + this.data.publishedSupplies = []; + this.data.pendingSupplies = []; + this.data.rejectedSupplies = []; + this.data.draftSupplies = []; + this.updatePageData(); + resolve([]); + return; + } + + let status = []; + let pageSize = 20; + + switch (type) { + case 'published': + status = ['published']; + pageSize = this.data.pagination.published.pageSize; + this.data.pagination.published.loading = true; + this.data.currentLoadingType = 'published'; + break; + case 'pending': + status = ['pending_review', 'reviewed']; + pageSize = this.data.pagination.pending.pageSize; + this.data.pagination.pending.loading = true; + this.data.currentLoadingType = 'pending'; + break; + case 'rejected': + status = ['rejected']; + pageSize = this.data.pagination.rejected.pageSize; + this.data.pagination.rejected.loading = true; + this.data.currentLoadingType = 'rejected'; + break; + case 'draft': + status = ['draft', 'sold_out']; + pageSize = this.data.pagination.draft.pageSize; + this.data.pagination.draft.loading = true; + this.data.currentLoadingType = 'draft'; + break; + default: + status = ['all']; + pageSize = 100; + } + + const requestData = { + openid: openid, + viewMode: 'seller', + status: status, + page: page, + pageSize: pageSize + }; + + API.getAllSupplies(requestData) + .then(res => { + console.log(`从服务器获取${type}类型数据响应:`, res); + + if (res && res.success && res.products) { + const serverSupplies = res.products + .filter(product => product.status !== 'hidden') + .map(serverProduct => { + const mappedStatus = serverProduct.status; + let imageUrls = this.processImageUrls(serverProduct.imageUrls); + const createdAt = serverProduct.created_at || null; + const formattedCreatedAt = this.formatCreateTime(createdAt); + + return { + id: serverProduct.productId, + name: serverProduct.productName, + productName: serverProduct.productName, + price: serverProduct.price, + minOrder: serverProduct.quantity, + grossWeight: serverProduct.grossWeight, + yolk: serverProduct.yolk, + spec: serverProduct.specification, + region: serverProduct.region || '未知地区', + serverProductId: serverProduct.productId, + status: mappedStatus, + rejectReason: serverProduct.rejectReason || '', + imageUrls: imageUrls, + created_at: createdAt, + formattedCreatedAt: formattedCreatedAt, + currentImageIndex: 0, + product_contact: serverProduct.product_contact || '', + contact_phone: serverProduct.contact_phone || '' + }; + }); + + this.updateSuppliesByType(type, serverSupplies, res, page); + resolve(serverSupplies); + } else { + this.handleNoData(type); + resolve([]); + } + }) + .catch(err => { + console.error(`从服务器获取${type}类型数据失败:`, err); + this.handleLoadError(type, err); + reject(err); + }) + .finally(() => { + this.resetLoadingState(type); + }); + }); + } + + // 根据类型更新货源数据 + updateSuppliesByType(type, newSupplies, response, currentPage) { + const paginationKey = `pagination.${type}`; + + // 更新分页信息 + const hasMore = currentPage < (response.totalPages || 1); + this.data.pagination[type].hasMore = hasMore; + this.data.pagination[type].page = currentPage; + + // 更新货源列表 + if (currentPage === 1) { + this.data[`${type}Supplies`] = newSupplies; + } else { + const existingSupplies = this.data[`${type}Supplies`] || []; + this.data[`${type}Supplies`] = [...existingSupplies, ...newSupplies]; + } + + // 更新总列表 + this.updateAllSupplies(); + + this.updatePageData(); + } + + // 更新所有货源列表 + updateAllSupplies() { + this.data.supplies = [ + ...this.data.publishedSupplies, + ...this.data.pendingSupplies, + ...this.data.rejectedSupplies, + ...this.data.draftSupplies + ]; + } + + // 处理无数据情况 + handleNoData(type) { + this.data.pagination[type].hasMore = false; + this.data[`${type}Supplies`] = []; + this.updatePageData(); + } + + // 处理加载错误 + handleLoadError(type, err) { + this.data.pagination[type].loading = false; + this.updatePageData(); + } + + // 重置加载状态 + resetLoadingState(type) { + if (type !== 'all') { + this.data.pagination[type].loading = false; + this.data.currentLoadingType = null; + this.updatePageData(); + } + } + + // 加载更多货源 + loadMoreSupplies(type) { + const pagination = this.data.pagination[type]; + + if (!pagination.hasMore || pagination.loading) { + return; + } + + const nextPage = pagination.page + 1; + return this.loadSuppliesFromServer(type, nextPage); + } + + // 格式化创建时间 + formatCreateTime(timeValue) { + if (!timeValue) { + return '无'; + } + + try { + let date; + + if (typeof timeValue === 'string') { + date = new Date(timeValue); + + if (isNaN(date.getTime())) { + const cleanTime = timeValue.replace(/[^\d\-T:.]/g, ''); + date = new Date(cleanTime); + } + } else if (typeof timeValue === 'number') { + date = new Date(timeValue); + } else { + date = new Date(timeValue); + } + + if (isNaN(date.getTime())) { + return '无'; + } + + const year = date.getFullYear(); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); + const day = date.getDate().toString().padStart(2, '0'); + const hours = date.getHours().toString().padStart(2, '0'); + const minutes = date.getMinutes().toString().padStart(2, '0'); + + return `${year}/${month}/${day} ${hours}:${minutes}`; + } catch (error) { + console.error('时间格式化错误:', error); + return '无'; + } + } + + // 显示添加货源弹窗 + showAddSupply(e) { + if (e && e.stopPropagation) { + e.stopPropagation(); + } + + // 尝试从本地存储加载保存的表单数据,支持多种格式 + let savedSupply = wx.getStorageSync('newSupplyDraft'); + let webFormDraft = wx.getStorageSync('supplyFormDraft'); + + // 如果没有找到保存的数据,使用默认数据 + if (!savedSupply || typeof savedSupply !== 'object') { + savedSupply = { name: '', price: '', minOrder: '', yolk: '', spec: '', grossWeight: '', region: '', imageUrls: [] }; + } + + // 如果有web格式的表单数据,优先使用 + if (webFormDraft) { + try { + const formData = typeof webFormDraft === 'string' ? JSON.parse(webFormDraft) : webFormDraft; + // 转换字段名以匹配小程序格式 + savedSupply = { + name: formData.productName || savedSupply.name, + price: formData.price || savedSupply.price, + minOrder: formData.quantity || savedSupply.minOrder, + grossWeight: formData.grossWeight || savedSupply.grossWeight, + yolk: formData.yolk || savedSupply.yolk, + spec: formData.specification || savedSupply.spec, + region: formData.region || savedSupply.region, + imageUrls: formData.imageUrls || savedSupply.imageUrls || [] + }; + console.log('已加载web格式的表单数据'); + } catch (e) { + console.error('加载web格式表单数据失败:', e); + } + } + + this.data.showImagePreview = false; + this.data.showModal = true; + this.data.newSupply = savedSupply; + + this.updatePageData(); + this.disablePageScroll(); + console.log('已加载保存的货源草稿数据'); + } + + // 隐藏弹窗 + hideModal() { + this.data.showModal = false; + this.data.showImagePreview = false; + this.updatePageData(); + this.enablePageScroll(); + } + + // 输入内容处理 + onInput(e) { + const field = e.currentTarget.dataset.field; + const value = e.detail.value; + this.data.newSupply[field] = value; + this.updatePageData(); + + // 实时保存到本地存储,支持多种格式以兼容不同页面 + wx.setStorageSync('newSupplyDraft', this.data.newSupply); + + // 同时保存为web格式,以便与网页端兼容 + const webFormData = { + productName: this.data.newSupply.name, + price: this.data.newSupply.price, + quantity: this.data.newSupply.minOrder, + grossWeight: this.data.newSupply.grossWeight, + yolk: this.data.newSupply.yolk, + specification: this.data.newSupply.spec, + region: this.data.newSupply.region, + imageUrls: this.data.newSupply.imageUrls || [] + }; + wx.setStorageSync('supplyFormDraft', JSON.stringify(webFormData)); + + console.log(`字段 ${field} 已更新并保存`); + } + + // 编辑输入处理 + onEditInput(e) { + const field = e.currentTarget.dataset.field; + const value = e.detail.value; + this.data.editSupply[field] = value; + this.updatePageData(); + } + + // 添加新货源 + addSupply() { + const userId = wx.getStorageSync('userId'); + const openid = wx.getStorageSync('openid'); + const userInfo = wx.getStorageSync('userInfo'); + + if (!userId || !openid || !userInfo) { + wx.showModal({ + title: '登录提示', + content: '请先登录再发布商品', + showCancel: true, + confirmText: '去登录', + success: (res) => { + if (res.confirm) { + this.data.showAuthModal = true; + this.updatePageData(); + } + } + }); + return; + } + + const { name, price, minOrder, yolk, spec, region, imageUrls, grossWeight } = this.data.newSupply; + if (!name || !price || !minOrder || !yolk) { + wx.showToast({ title: '请填写完整信息', icon: 'none', duration: 2000 }); + return; + } + + wx.showLoading({ title: '正在创建商品...', mask: true }); + + const productData = { + productName: name, + price: price, + quantity: Number(minOrder), + grossWeight: grossWeight && grossWeight !== '' ? grossWeight : "", + yolk: yolk, + specification: spec || '', + region: region || '', + rejectReason: '', + imageUrls: [] + }; + + API.publishProduct(productData) + .then(res => { + console.log('商品创建成功:', res); + + // 第二步:如果有图片,上传图片到已创建的商品 + if (imageUrls && imageUrls.length > 0) { + const productId = res.productId || res.data?.productId || res.product?.productId; + if (productId) { + return this.uploadImagesToExistingProduct(productId, imageUrls, openid); + } + } + return res; + }) + .then(finalRes => { + wx.hideLoading(); + wx.showToast({ + title: imageUrls && imageUrls.length > 0 ? '创建成功,图片已上传' : '创建成功', + duration: 3000 + }); + + // 重置表单 + this.data.showModal = false; + this.data.newSupply = { name: '', price: '', minOrder: '', yolk: '', spec: '', grossWeight: '', region: '', imageUrls: [] }; + + // 清除所有保存的草稿数据,包括小程序和网页格式 + wx.removeStorageSync('newSupplyDraft'); + wx.removeStorageSync('supplyFormDraft'); + + this.updatePageData(); + this.enablePageScroll(); + this.loadSupplies(); + + console.log('商品创建成功,所有草稿数据已清除'); + }) + .catch(err => { + console.error('商品创建或图片上传失败:', err); + wx.hideLoading(); + + let errorMsg = '上传服务器失败'; + if (err.message && err.message.includes('商品不存在')) { + errorMsg = '商品创建失败,无法上传图片'; + } + wx.showModal({ + title: '发布失败', + content: errorMsg + '\n\n错误详情: ' + (err.message || JSON.stringify(err)), + showCancel: false, + success: () => { + this.loadSupplies(); + } + }); + + // 失败时保持保存的草稿数据 + console.log('商品创建失败,保持草稿数据'); + }); + } + + // 上传图片到已存在商品 + uploadImagesToExistingProduct(productId, imageUrls, openid) { + return new Promise((resolve, reject) => { + if (!productId) { + reject(new Error('商品ID不能为空')); + return; + } + + if (!imageUrls || imageUrls.length === 0) { + resolve({ success: true, message: '没有图片需要上传' }); + return; + } + + const uploadSequentially = async () => { + const results = []; + + for (let i = 0; i < imageUrls.length; i++) { + try { + const result = await new Promise((resolveUpload, rejectUpload) => { + const formData = { + productId: productId, + openid: openid, + action: 'add_images_only', + imageIndex: i, + totalImages: imageUrls.length, + isUpdate: 'true', + timestamp: Date.now() + }; + + wx.uploadFile({ + url: API.BASE_URL + '/api/products/upload', + filePath: imageUrls[i], + name: 'images', + formData: formData, + success: (res) => { + if (res.statusCode === 200) { + try { + const data = JSON.parse(res.data); + if (data.success) { + resolveUpload(data); + } else { + rejectUpload(new Error(data.message || '图片上传失败')); + } + } catch (parseError) { + rejectUpload(new Error('服务器响应格式错误')); + } + } else { + rejectUpload(new Error(`HTTP ${res.statusCode}`)); + } + }, + fail: (err) => { + rejectUpload(new Error('网络错误: ' + err.errMsg)); + } + }); + }); + + results.push(result); + + // 添加延迟,避免服务器处理压力过大 + if (i < imageUrls.length - 1) { + await new Promise(resolve => setTimeout(resolve, 500)); + } + } catch (error) { + results.push({ success: false, error: error.message }); + } + } + + return results; + }; + + uploadSequentially() + .then(results => { + const successfulResults = results.filter(r => r && r.success); + if (successfulResults.length > 0) { + const lastResult = successfulResults[successfulResults.length - 1]; + resolve({ + success: true, + message: `成功上传${successfulResults.length}张图片`, + imageUrls: lastResult.imageUrls || [], + allImageUrls: lastResult.allImageUrls || [], + uploadedCount: successfulResults.length, + totalCount: lastResult.totalCount || successfulResults.length, + results: results + }); + } else { + reject(new Error('所有图片上传失败')); + } + }) + .catch(error => { + console.error('图片上传失败:', error); + reject(error); + }); + }); + } + + // 显示编辑弹窗 + showEditSupply(e, isPublishOperation = false) { + this.data.showImagePreview = false; + this.updatePageData(); + + const id = e.currentTarget.dataset.id; + if (!id) { + wx.showToast({ title: '操作失败,缺少货源信息', icon: 'none', duration: 2000 }); + return; + } + + // 在所有货源列表中查找 + let supply = this.data.supplies.find(s => s.id === id); + + if (!supply) { + wx.showToast({ title: '未找到该货源', icon: 'none', duration: 2000 }); + this.loadSupplies(); + return; + } + + // 计算蛋黄和规格的索引值 + const yolkIndex = this.data.yolkOptions.indexOf(supply.yolk) >= 0 ? this.data.yolkOptions.indexOf(supply.yolk) : 0; + const specIndex = this.data.specOptions.indexOf(supply.spec) >= 0 ? this.data.specOptions.indexOf(supply.spec) : 0; + + // 设置编辑货源数据 + const productName = supply.productName || supply.name; + this.data.editSupply = { + ...supply, + formattedCreatedAt: this.formatCreateTime(supply.created_at), + region: supply.region || '', + name: productName, + productName: productName, + yolkIndex: yolkIndex, + specIndex: specIndex + }; + + // 解析地区字符串为省市区数组 + let editSupplyRegionArray = []; + if (supply.region) { + editSupplyRegionArray = supply.region.split(' ').filter(item => item.trim() !== ''); + } + this.data.editSupplyRegionArray = editSupplyRegionArray; + + // 设置自动上架标志 + this.data.autoPublishAfterEdit = isPublishOperation; + this.data.showEditModal = true; + + this.updatePageData(); + this.disablePageScroll(); + } + + // 保存编辑后的货源信息 + saveEdit() { + const { editSupply, autoPublishAfterEdit } = this.data; + + if (!editSupply.name || !editSupply.price || !editSupply.minOrder || !editSupply.yolk) { + wx.showToast({ title: '请填写完整信息', icon: 'none', duration: 2000 }); + return; + } + + wx.showLoading({ title: '正在同步...', mask: true }); + + const openid = wx.getStorageSync('openid'); + + if (!openid) { + wx.hideLoading(); + wx.showModal({ + title: '登录状态异常', + content: '您的登录状态已失效,请重新登录后再尝试保存', + showCancel: false, + success: () => { + this.data.showEditModal = false; + this.updatePageData(); + this.enablePageScroll(); + } + }); + return; + } + + const productName = editSupply.productName || editSupply.name; + const productData = { + productName: productName, + price: editSupply.price, + quantity: Number(editSupply.minOrder), + grossWeight: editSupply.grossWeight !== undefined && editSupply.grossWeight !== null && editSupply.grossWeight !== '' ? editSupply.grossWeight : "", + yolk: editSupply.yolk, + specification: editSupply.spec || '', + region: editSupply.region || '', + imageUrls: editSupply.imageUrls || [], + created_at: new Date().toISOString(), + status: autoPublishAfterEdit ? 'pending_review' : '' + }; + + if (editSupply.serverProductId) { + // 编辑现有商品 + productData.productId = editSupply.serverProductId; + + const requestData = { + openid: openid, + productId: editSupply.serverProductId, + product: { + productName: productData.productName, + price: productData.price, + quantity: productData.quantity, + grossWeight: productData.grossWeight, + yolk: productData.yolk, + specification: productData.specification, + region: productData.region, + imageUrls: productData.imageUrls + }, + status: productData.status || '' + }; + + wx.request({ + url: API.BASE_URL + '/api/product/edit', + method: 'POST', + data: requestData, + success: (res) => { + wx.hideLoading(); + this.data.showEditModal = false; + this.updatePageData(); + this.enablePageScroll(); + wx.showToast({ title: '更新成功', duration: 2000 }); + this.loadSupplies(); + }, + fail: (err) => { + console.error('编辑商品失败:', err); + wx.hideLoading(); + wx.showToast({ title: '保存失败,请重试', icon: 'none', duration: 2000 }); + } + }); + } else { + // 创建新商品 + wx.request({ + url: API.BASE_URL + '/api/product/add', + method: 'POST', + data: productData, + success: (res) => { + wx.hideLoading(); + this.data.showEditModal = false; + this.updatePageData(); + this.enablePageScroll(); + wx.showToast({ title: '更新成功,等待审核', duration: 2000 }); + this.loadSupplies(); + }, + fail: (err) => { + console.error('商品创建失败:', err); + wx.hideLoading(); + wx.showToast({ title: '创建失败,请重试', icon: 'none', duration: 2000 }); + } + }); + } + } + + // 下架货源 + unpublishSupply(e) { + const supplyId = e.currentTarget.dataset.id; + + wx.showModal({ + title: '确认下架', + content: '确定要下架该商品吗?', + confirmText: '确定', + cancelText: '取消', + success: (res) => { + if (res.confirm) { + let supply = this.data.supplies.find(s => s.id === supplyId); + + if (!supply) { + supply = this.data.publishedSupplies.find(s => s.id === supplyId); + } + + if (!supply) { + // 直接使用ID尝试下架 + this.disablePageScroll(); + wx.showLoading({ title: '下架中...', mask: true }); + + API.hideProduct(supplyId) + .then(res => { + wx.hideLoading(); + this.enablePageScroll(); + wx.showToast({ title: '已下架', icon: 'success', duration: 2000 }); + this.loadSupplies(); + }) + .catch(err => { + wx.hideLoading(); + this.enablePageScroll(); + wx.showToast({ title: '下架失败,请重试', icon: 'none', duration: 2000 }); + }); + return; + } + + if (!supply.serverProductId) { + wx.showToast({ title: '无法下架,商品未上传到服务器', icon: 'none', duration: 2000 }); + return; + } + + this.disablePageScroll(); + wx.showLoading({ title: '下架中...', mask: true }); + + API.hideProduct(supply.serverProductId) + .then(res => { + wx.hideLoading(); + this.enablePageScroll(); + wx.showToast({ title: '已下架', icon: 'success', duration: 2000 }); + this.loadSupplies(); + }) + .catch(err => { + wx.hideLoading(); + this.enablePageScroll(); + wx.showToast({ title: '服务器同步失败,请重试', icon: 'none', duration: 3000 }); + this.loadSupplies(); + }); + } + } + }); + } + + // 删除货源 + deleteSupply(e) { + const id = e.currentTarget.dataset.id; + const supply = this.data.supplies.find(s => s.id === id); + + if (!supply) { + wx.showToast({ title: '货源不存在', icon: 'none', duration: 2000 }); + return; + } + + wx.showModal({ + title: '确认删除', + content: '确定要删除该货源吗?删除后将不再显示,但数据会保留。', + success: (res) => { + if (res.confirm) { + wx.showLoading({ title: '删除中...' }); + + let productIdToHide; + const idStr = String(id); + + if (supply.serverProductId) { + productIdToHide = supply.serverProductId; + } else if (idStr.startsWith('product_')) { + productIdToHide = id; + } else { + productIdToHide = id; + } + + API.deleteProduct(productIdToHide).then(() => { + wx.hideLoading(); + wx.showToast({ title: '删除成功', icon: 'success', duration: 2000 }); + this.loadSupplies(); + }).catch(error => { + wx.hideLoading(); + this.loadSupplies(); + wx.showToast({ title: '删除失败,请重试', icon: 'none', duration: 3000 }); + }); + } + } + }); + } + + // 显示审核失败原因弹窗 + showRejectReason(e) { + const id = e.currentTarget.dataset.id; + + wx.showLoading({ + title: '获取最新审核原因...', + mask: true + }); + + API.getProductList('rejected', { + page: 1, + pageSize: 20, + timestamp: new Date().getTime() + }).then(data => { + if (data && data.products && Array.isArray(data.products)) { + const supply = data.products.find(product => product.id === id); + + if (supply) { + this.data.rejectedSupplies = data.products; + this.data.currentRejectSupply = supply; + this.data.rejectReason = supply.rejectReason || '暂无详细的审核失败原因'; + this.data.showRejectReasonModal = true; + this.updatePageData(); + this.disablePageScroll(); + } else { + wx.showToast({ title: '未找到该货源', icon: 'none', duration: 2000 }); + } + } + }).catch(err => { + console.error('获取审核失败商品列表失败:', err); + let localSupply = this.data.supplies.find(s => s.id === id); + + if (localSupply) { + this.data.currentRejectSupply = localSupply; + this.data.rejectReason = localSupply.rejectReason || '暂无详细的审核失败原因'; + this.data.showRejectReasonModal = true; + this.updatePageData(); + this.disablePageScroll(); + } else { + wx.showToast({ title: '未找到该货源', icon: 'none', duration: 2000 }); + } + }).finally(() => { + wx.hideLoading(); + }); + } + + // 关闭审核失败原因弹窗 + closeRejectReasonModal() { + this.data.showRejectReasonModal = false; + this.updatePageData(); + this.enablePageScroll(); + } + + // 选择图片方法 + chooseImage(e) { + const type = e.currentTarget.dataset.type || 'new'; + let currentImages = type === 'new' ? this.data.newSupply.imageUrls || [] : this.data.editSupply.imageUrls || []; + + const maxCount = 5 - currentImages.length; + if (maxCount <= 0) { + wx.showToast({ title: '最多只能上传5张图片', icon: 'none', duration: 2000 }); + return; + } + + wx.chooseImage({ + count: maxCount, + sizeType: ['compressed'], + sourceType: ['album', 'camera'], + success: (res) => { + const tempFilePaths = res.tempFilePaths; + const updatedImages = [...currentImages, ...tempFilePaths]; + + if (type === 'new') { + this.data.newSupply.imageUrls = updatedImages; + } else { + this.data.editSupply.imageUrls = updatedImages; + } + + this.updatePageData(); + + // 实时保存到本地存储 + if (type === 'new') { + wx.setStorageSync('newSupplyDraft', this.data.newSupply); + } + }, + fail: (err) => { + console.error('选择图片失败:', err); + if (err.errMsg !== 'chooseImage:fail cancel') { + wx.showToast({ title: '选择图片失败,请重试', icon: 'none', duration: 2000 }); + } + } + }); + } + + // 删除图片 + deleteImage(e) { + const index = e.currentTarget.dataset.index; + const type = e.currentTarget.dataset.type || 'new'; + + if (type === 'new') { + this.data.newSupply.imageUrls.splice(index, 1); + this.updatePageData(); + wx.setStorageSync('newSupplyDraft', this.data.newSupply); + } else { + this.data.editSupply.imageUrls.splice(index, 1); + this.updatePageData(); + } + } + + // 禁用页面滚动 + disablePageScroll() { + if (this.page) { + this.page.setData({ pageScrollLock: true }); + } + } + + // 启用页面滚动 + enablePageScroll() { + if (this.page) { + this.page.setData({ pageScrollLock: false }); + } + } + + // iOS设备检测 + isIOS() { + const systemInfo = wx.getSystemInfoSync(); + return systemInfo.platform === 'ios'; + } +} + +module.exports = SupplyManager; diff --git a/supply.html b/supply.html new file mode 100644 index 0000000..858d0fd --- /dev/null +++ b/supply.html @@ -0,0 +1,4892 @@ + + + + + + 货源管理 + + + +
+ +
+
+ +

我的货源

+
+
+ + +
+
+ + +
+ + +
+
+ + +
+ +
+ + +
+
+
已上架货源 (0)
+
+
+
+
暂无已上架的货源
+
+
+ + +
+
+
审核中的货源 (0)
+
+
+
+
暂无审核中的货源
+
+
+ + +
+
+
审核失败的货源 (0)
+
+
+
+
暂无审核失败的货源
+
+
+ + +
+
+
下架状态货源 (0)
+
+
+
+
暂无下架状态的货源
+
+
+
+ + + + + +
+
+ + +
+
+ + +
+
+
+

选择货源类型

+ +
+ +
+
+ +
+
+ +
+
+ + +
+
+
+

选择商品名称

+ +
+ +
+
+ +
+
+ +
+
+ + +
+
+
+

选择蛋黄类型

+ +
+ +
+
+ +
+
+ +
+
+ + +
+
+
+

选择联系人

+ +
+ +
+
+ +
+
+ +
+
+ + +
+
+
+

选择规格

+ +
+ +
+
+ +
+
+ +
+
+ + +
+
+
+

选择地区

+ +
+ +
+
+ +
+
+
+
+
+ +
+
+ + +
+
+
+

选择种类

+ +
+ +
+
+ +
+
+ +
+
+ + + + + + + + +
+
+
+

选择规格

+ +
+ +
+
+ +
+
+ +
+
+ + +
+
+
+

选择货源类型

+ +
+ +
+
+ +
+
+ +
+
+ + +
+
+
+

选择种类

+ +
+ +
+
+ +
+
+ +
+
+ + +
+
+
+

选择商品名称

+ +
+ +
+
+ +
+
+ +
+
+ + +
+
+
+

选择蛋黄类型

+ +
+ +
+
+ +
+
+ +
+
+ + +
+
+
+

选择联系人

+ +
+ +
+
+ +
+
+ +
+
+ + +
+
+
+

选择地区

+ +
+ +
+
+ +
+
+
+
+
+ +
+
+ + + + \ No newline at end of file diff --git a/test-watermark-update.js b/test-watermark-update.js new file mode 100644 index 0000000..93cf220 --- /dev/null +++ b/test-watermark-update.js @@ -0,0 +1,63 @@ +const fs = require('fs'); +const path = require('path'); +const ImageProcessor = require('./image-processor'); + +// 测试水印功能 +async function testWatermark() { + console.log('开始测试水印功能...'); + + try { + // 创建一个简单的测试图片(Base64编码的1x1像素图片) + const testImageBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; + + console.log('1. 测试ImageProcessor模块导入...'); + if (!ImageProcessor || typeof ImageProcessor.addWatermark !== 'function') { + throw new Error('ImageProcessor模块导入失败或缺少必要方法'); + } + console.log('✓ 模块导入成功'); + + console.log('2. 测试水印添加功能...'); + console.log(' - 水印文字: 又鸟蛋平台'); + console.log(' - 透明度: rgba(0,0,0,0.3)'); + console.log(' - 位置: 右下角'); + + // 使用默认配置添加水印(应该使用'又鸟蛋平台'作为水印文字) + const watermarkedBuffer = await ImageProcessor.addWatermarkToBase64(testImageBase64); + + if (!watermarkedBuffer || !(watermarkedBuffer instanceof Buffer)) { + throw new Error('水印添加失败,未返回有效Buffer'); + } + console.log('✓ 水印添加成功'); + + // 保存测试结果到文件 + const outputPath = path.join(__dirname, 'watermark-test-update-output.png'); + fs.writeFileSync(outputPath, watermarkedBuffer); + console.log(`✓ 测试结果已保存到: ${outputPath}`); + + // 验证配置正确性 + console.log('3. 验证水印配置...'); + console.log(' - 默认水印文字: 又鸟蛋平台'); + console.log(' - 默认透明度: rgba(0,0,0,0.3)'); + console.log(' - 强制位置: 右下角'); + + // 测试强制位置功能 + const forcedWatermarkedBuffer = await ImageProcessor.addWatermarkToBase64(testImageBase64, '测试', { + position: 'center' // 尝试设置不同位置,但应该被强制为右下角 + }); + console.log('✓ 位置强制功能测试成功'); + + console.log('\n🎉 所有测试通过! 水印功能已成功更新:'); + console.log(' - 水印文字: 又鸟蛋平台'); + console.log(' - 透明度: rgba(0,0,0,0.3) (更透明)'); + console.log(' - 位置: 右下角 (统一位置)'); + console.log(' - 后端服务已重启,新配置已生效'); + + } catch (error) { + console.error('❌ 测试失败:', error.message); + console.error('错误详情:', error); + process.exit(1); + } +} + +// 运行测试 +testWatermark(); \ No newline at end of file diff --git a/test-watermark.js b/test-watermark.js new file mode 100644 index 0000000..4638d93 --- /dev/null +++ b/test-watermark.js @@ -0,0 +1,61 @@ +const fs = require('fs'); +const path = require('path'); +const ImageProcessor = require('./image-processor'); + +// 测试添加水印功能 +async function testAddWatermark() { + try { + console.log('开始测试图片水印功能...'); + + // 创建一个简单的测试图片Buffer(使用Base64编码的1x1像素黑色图片) + const base64TestImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; + + // 处理水印 + const watermarkedBuffer = await ImageProcessor.addWatermarkToBase64( + base64TestImage, + '测试水印 - 供应商ID: test123', + { + fontSize: 16, + color: 'rgba(255,0,0,0.8)', + position: 'bottom-right', + marginX: 10, + marginY: 10 + } + ); + + // 保存测试结果到文件 + const testOutputPath = path.join(__dirname, 'watermark-test-output.png'); + await fs.promises.writeFile(testOutputPath, watermarkedBuffer); + + console.log(`✅ 水印测试成功! 输出文件已保存至: ${testOutputPath}`); + console.log('\n测试总结:'); + console.log('- ✅ 成功导入ImageProcessor模块'); + console.log('- ✅ 成功添加文字水印到图片'); + console.log('- ✅ 成功将带水印的图片保存为文件'); + console.log('- ✅ Sharp库功能正常工作'); + console.log('\n提示: 在实际API调用中,水印功能会在创建货源时自动应用到上传的图片上。'); + + return true; + } catch (error) { + console.error('❌ 水印测试失败:', error.message); + console.error('错误详情:', error); + return false; + } +} + +// 运行测试 +(async () => { + console.log('===================================='); + console.log(' 图片水印功能测试脚本 '); + console.log('===================================='); + + const success = await testAddWatermark(); + + if (success) { + console.log('\n✅ 所有测试通过! 水印功能已准备就绪,可以在创建货源API中使用。'); + } else { + console.log('\n❌ 测试失败,请检查错误信息并修复问题。'); + } + + console.log('===================================='); +})(); diff --git a/watermark-test-output.png b/watermark-test-output.png new file mode 100644 index 0000000000000000000000000000000000000000..71f7cd2052d0bfb406662fa4d6e4676efaed77d3 GIT binary patch literal 91 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1|;Q0k8}bl&H|6fVg?3oVGw3ym^DWND9G#S j;uumfCpjVEM?60RQxjvon6>IWpag@btDnm{r-UW|kC_o& literal 0 HcmV?d00001 diff --git a/watermark-test-update-output.png b/watermark-test-update-output.png new file mode 100644 index 0000000000000000000000000000000000000000..71f7cd2052d0bfb406662fa4d6e4676efaed77d3 GIT binary patch literal 91 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1|;Q0k8}bl&H|6fVg?3oVGw3ym^DWND9G#S j;uumfCpjVEM?60RQxjvon6>IWpag@btDnm{r-UW|kC_o& literal 0 HcmV?d00001