From 67c85dfb916fb388a07c5b8fd0ac3858ca50b321 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B2=A1=E5=A4=8D=E4=B9=A0?= <2353956224@qq.com> Date: Fri, 23 Jan 2026 21:56:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .htaccess | 1 + ...Q2oHEhWk4lfJu4mJyLtTUHZehr9t9WRTyMj5El9w0w | 1 + README.md | 64 + __MACOSX/._.htaccess | Bin 0 -> 176 bytes __MACOSX/._.well-known | Bin 0 -> 176 bytes __MACOSX/._README.md | Bin 0 -> 176 bytes __MACOSX/._package.json | Bin 0 -> 176 bytes __MACOSX/._public | Bin 0 -> 176 bytes __MACOSX/._run.log | Bin 0 -> 176 bytes __MACOSX/._server.js | Bin 0 -> 176 bytes __MACOSX/.well-known/._acme-challenge | Bin 0 -> 176 bytes ...Q2oHEhWk4lfJu4mJyLtTUHZehr9t9WRTyMj5El9w0w | Bin 0 -> 176 bytes __MACOSX/public/._admin.html | Bin 0 -> 176 bytes __MACOSX/public/._index.html | Bin 0 -> 176 bytes __MACOSX/public/._staff.html | Bin 0 -> 176 bytes data.sqlite | Bin 0 -> 53248 bytes package-lock.json | 2435 +++++++++++++++++ package.json | 17 + public/admin.html | 2406 ++++++++++++++++ public/index.html | 750 +++++ public/leader.html | 1566 +++++++++++ public/staff.html | 1768 ++++++++++++ run.log | 2 + server.js | 1044 +++++++ 25 files changed, 10055 insertions(+) create mode 100644 .gitignore create mode 100644 .htaccess create mode 100644 .well-known/acme-challenge/PQ2oHEhWk4lfJu4mJyLtTUHZehr9t9WRTyMj5El9w0w create mode 100644 README.md create mode 100644 __MACOSX/._.htaccess create mode 100644 __MACOSX/._.well-known create mode 100644 __MACOSX/._README.md create mode 100644 __MACOSX/._package.json create mode 100644 __MACOSX/._public create mode 100644 __MACOSX/._run.log create mode 100644 __MACOSX/._server.js create mode 100644 __MACOSX/.well-known/._acme-challenge create mode 100644 __MACOSX/.well-known/acme-challenge/._PQ2oHEhWk4lfJu4mJyLtTUHZehr9t9WRTyMj5El9w0w create mode 100644 __MACOSX/public/._admin.html create mode 100644 __MACOSX/public/._index.html create mode 100644 __MACOSX/public/._staff.html create mode 100644 data.sqlite create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/admin.html create mode 100644 public/index.html create mode 100644 public/leader.html create mode 100644 public/staff.html create mode 100644 run.log create mode 100644 server.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b512c09 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..0c54fb9 --- /dev/null +++ b/.htaccess @@ -0,0 +1 @@ +# 请将伪静态规则或自定义Apache配置填写到此处 diff --git a/.well-known/acme-challenge/PQ2oHEhWk4lfJu4mJyLtTUHZehr9t9WRTyMj5El9w0w b/.well-known/acme-challenge/PQ2oHEhWk4lfJu4mJyLtTUHZehr9t9WRTyMj5El9w0w new file mode 100644 index 0000000..a642418 --- /dev/null +++ b/.well-known/acme-challenge/PQ2oHEhWk4lfJu4mJyLtTUHZehr9t9WRTyMj5El9w0w @@ -0,0 +1 @@ +PQ2oHEhWk4lfJu4mJyLtTUHZehr9t9WRTyMj5El9w0w.zcR77pvvtV00LcqCRWPQnkBuH0F6FaFaWKI0_uGwnn0 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..a668831 --- /dev/null +++ b/README.md @@ -0,0 +1,64 @@ +# CRM Customer Management System + +基于 Node.js + SQLite 的轻量级客户管理系统。 + +## 📋 功能特性 +- **多角色管理**:超级管理员、组长 (Leader)、员工。 +- **客户管理**:录入、查询、编辑、删除客户信息,支持服务类型和金额统计。 +- **过期提醒**:自动标记过期和即将过期的客户。 +- **数据统计**: + - 管理员:查看全公司数据、各小组(组长)业绩对比。 + - 组长:查看本组员工数据及业绩。 + - 员工:仅查看个人业绩。 +- **权限控制**: + - 组长只能管理自己创建的员工。 + - 严格的数据隔离。 + - 账号封禁/启用功能。 + +## 🛠️ 技术栈 +- **后端**:Node.js (Express) +- **数据库**:SQLite3 +- **加密**:bcryptjs (密码), JWT (Token认证) +- **前端**:HTML5, CSS3, Vanilla JS (无构建步骤,开箱即用) + +## 🚀 快速开始 + +### 1. 环境准备 +确保已安装 Node.js (v14+)。 + +### 2. 安装依赖 +```bash +npm install +``` + +### 3. 启动应用 +此命令会自动初始化数据库(如果不存在)并启动服务器。 +```bash +npm start +``` +服务器运行在: `http://localhost:3000` + +### 4. 默认账号 +系统初始化时会自动创建以下默认账号(如果未修改 server.js): + +| 角色 | 账号 | 密码 | 说明 | +|------|------|------|------| +| **超级管理员** | `admin` | `admin123456` | 拥有所有权限 | +| **员工示例** | `staff1` | `staff123456` | 默认普通员工 | + +## 📂 项目结构 +``` +├── public/ # 前端静态资源 (HTML/CSS/JS) +│ ├── admin.html # 管理员后台 +│ ├── leader.html # 组长后台 +│ ├── staff.html # 员工后台 +│ ├── index.html # 登录页 +│ └── css/ # 样式文件 +├── server.js # 后端入口 & API 逻辑 & 数据库初始化 +├── database.sqlite # SQLite 数据库文件 (自动生成) +└── package.json # 项目配置 +``` + +## 🔧 常见维护 +- **重置数据库**:删除 `database.sqlite` 文件重启即可(数据会丢失)。 +- **修改端口**:编辑 `server.js` 中的 `PORT` 变量。 diff --git a/__MACOSX/._.htaccess b/__MACOSX/._.htaccess new file mode 100644 index 0000000000000000000000000000000000000000..6def0942b298a148ae080e26f168a52e04f2a921 GIT binary patch literal 176 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}aUBqY_#1$j2;dkJ5(HHS(lG;wCD61n zBE&_L^K9H A;{X5v literal 0 HcmV?d00001 diff --git a/__MACOSX/._.well-known b/__MACOSX/._.well-known new file mode 100644 index 0000000000000000000000000000000000000000..6def0942b298a148ae080e26f168a52e04f2a921 GIT binary patch literal 176 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}aUBqY_#1$j2;dkJ5(HHS(lG;wCD61n zBE&_L^K9H A;{X5v literal 0 HcmV?d00001 diff --git a/__MACOSX/._README.md b/__MACOSX/._README.md new file mode 100644 index 0000000000000000000000000000000000000000..6def0942b298a148ae080e26f168a52e04f2a921 GIT binary patch literal 176 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}aUBqY_#1$j2;dkJ5(HHS(lG;wCD61n zBE&_L^K9H A;{X5v literal 0 HcmV?d00001 diff --git a/__MACOSX/._package.json b/__MACOSX/._package.json new file mode 100644 index 0000000000000000000000000000000000000000..6def0942b298a148ae080e26f168a52e04f2a921 GIT binary patch literal 176 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}aUBqY_#1$j2;dkJ5(HHS(lG;wCD61n zBE&_L^K9H A;{X5v literal 0 HcmV?d00001 diff --git a/__MACOSX/._public b/__MACOSX/._public new file mode 100644 index 0000000000000000000000000000000000000000..6def0942b298a148ae080e26f168a52e04f2a921 GIT binary patch literal 176 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}aUBqY_#1$j2;dkJ5(HHS(lG;wCD61n zBE&_L^K9H A;{X5v literal 0 HcmV?d00001 diff --git a/__MACOSX/._run.log b/__MACOSX/._run.log new file mode 100644 index 0000000000000000000000000000000000000000..6def0942b298a148ae080e26f168a52e04f2a921 GIT binary patch literal 176 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}aUBqY_#1$j2;dkJ5(HHS(lG;wCD61n zBE&_L^K9H A;{X5v literal 0 HcmV?d00001 diff --git a/__MACOSX/._server.js b/__MACOSX/._server.js new file mode 100644 index 0000000000000000000000000000000000000000..6def0942b298a148ae080e26f168a52e04f2a921 GIT binary patch literal 176 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}aUBqY_#1$j2;dkJ5(HHS(lG;wCD61n zBE&_L^K9H A;{X5v literal 0 HcmV?d00001 diff --git a/__MACOSX/.well-known/._acme-challenge b/__MACOSX/.well-known/._acme-challenge new file mode 100644 index 0000000000000000000000000000000000000000..6def0942b298a148ae080e26f168a52e04f2a921 GIT binary patch literal 176 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}aUBqY_#1$j2;dkJ5(HHS(lG;wCD61n zBE&_L^K9H A;{X5v literal 0 HcmV?d00001 diff --git a/__MACOSX/.well-known/acme-challenge/._PQ2oHEhWk4lfJu4mJyLtTUHZehr9t9WRTyMj5El9w0w b/__MACOSX/.well-known/acme-challenge/._PQ2oHEhWk4lfJu4mJyLtTUHZehr9t9WRTyMj5El9w0w new file mode 100644 index 0000000000000000000000000000000000000000..6def0942b298a148ae080e26f168a52e04f2a921 GIT binary patch literal 176 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}aUBqY_#1$j2;dkJ5(HHS(lG;wCD61n zBE&_L^K9H A;{X5v literal 0 HcmV?d00001 diff --git a/__MACOSX/public/._admin.html b/__MACOSX/public/._admin.html new file mode 100644 index 0000000000000000000000000000000000000000..6def0942b298a148ae080e26f168a52e04f2a921 GIT binary patch literal 176 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}aUBqY_#1$j2;dkJ5(HHS(lG;wCD61n zBE&_L^K9H A;{X5v literal 0 HcmV?d00001 diff --git a/__MACOSX/public/._index.html b/__MACOSX/public/._index.html new file mode 100644 index 0000000000000000000000000000000000000000..6def0942b298a148ae080e26f168a52e04f2a921 GIT binary patch literal 176 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}aUBqY_#1$j2;dkJ5(HHS(lG;wCD61n zBE&_L^K9H A;{X5v literal 0 HcmV?d00001 diff --git a/__MACOSX/public/._staff.html b/__MACOSX/public/._staff.html new file mode 100644 index 0000000000000000000000000000000000000000..6def0942b298a148ae080e26f168a52e04f2a921 GIT binary patch literal 176 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDI}aUBqY_#1$j2;dkJ5(HHS(lG;wCD61n zBE&_L^K9H A;{X5v literal 0 HcmV?d00001 diff --git a/data.sqlite b/data.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..e3547fa3919b70fa794cd6959e118c56fad6702f GIT binary patch literal 53248 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" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC", + "optional": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/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", + "optional": true + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.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==", + "license": "MIT", + "optional": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/aproba": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "license": "ISC", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "optional": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", + "license": "MIT" + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "optional": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "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/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "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/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "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==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT", + "optional": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC", + "optional": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "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/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.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "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/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", + "optional": true + }, + "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/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/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "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/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==", + "license": "MIT", + "optional": true + }, + "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/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/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", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "license": "MIT", + "optional": true + }, + "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/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/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/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, + "node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC", + "optional": true + }, + "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/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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-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/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "optional": true, + "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/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==", + "license": "ISC", + "optional": true + }, + "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-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC", + "optional": true + }, + "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/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "license": "BSD-2-Clause", + "optional": true + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/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", + "optional": true + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/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", + "optional": true + }, + "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", + "optional": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "optional": true, + "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==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "license": "ISC", + "optional": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "optional": true, + "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/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 12" + } + }, + "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-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==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "license": "MIT", + "optional": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC", + "optional": true + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/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/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "license": "ISC", + "optional": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "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": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "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/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/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "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": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-abi": { + "version": "3.85.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.85.0.tgz", + "integrity": "sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT" + }, + "node_modules/node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "license": "MIT", + "optional": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "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/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "license": "ISC", + "optional": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "license": "MIT", + "optional": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "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/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.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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/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": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/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/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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==", + "license": "ISC", + "optional": true + }, + "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/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": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC", + "optional": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "license": "MIT", + "optional": true, + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/socks-proxy-agent/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socks-proxy-agent/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", + "optional": true + }, + "node_modules/sqlite3": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.7.tgz", + "integrity": "sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "bindings": "^1.5.0", + "node-addon-api": "^7.0.0", + "prebuild-install": "^7.1.1", + "tar": "^6.1.11" + }, + "optionalDependencies": { + "node-gyp": "8.x" + }, + "peerDependencies": { + "node-gyp": "8.x" + }, + "peerDependenciesMeta": { + "node-gyp": { + "optional": true + } + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "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/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "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==", + "license": "MIT", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "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/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "license": "ISC", + "optional": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "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/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/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "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==", + "license": "ISC", + "optional": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "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/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..832c416 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "crm-system", + "version": "1.0.0", + "main": "server.js", + "type": "commonjs", + "scripts": { + "start": "node server.js", + "initdb": "node server.js --initdb" + }, + "dependencies": { + "bcryptjs": "^2.4.3", + "cors": "^2.8.5", + "express": "^4.19.2", + "jsonwebtoken": "^9.0.2", + "sqlite3": "^5.1.7" + } +} \ No newline at end of file diff --git a/public/admin.html b/public/admin.html new file mode 100644 index 0000000..be5cb8a --- /dev/null +++ b/public/admin.html @@ -0,0 +1,2406 @@ + + + + + + + 客户管理系统 - 总后台 + + + + +
+ + + + +
+
+

数据总览

+
+
+ + +
+
+
+
¥ 0
+
总金额
+
+
+
+
0
+
客户总数
+
+
+
+
0
+
即将到期
+
+
+
+
0
+
已过期
+
+
+ + +
+
+

员工数据

+
点击员工查看详细统计
+
+ +
+ +
+
+ + +
+
+ + +
+ +
+ + +
+ +
+ + + + +
+ + + +
+ + +
+ + + + + + + + + + + + + + + + + + +
员工客户姓名联系电话服务类型登记日期到期时间金额状态操作备注
+
+
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..e1fbbcb --- /dev/null +++ b/public/index.html @@ -0,0 +1,750 @@ + + + + + + 客户管理系统 - 登录 + + + + + + + + + + + + + diff --git a/public/leader.html b/public/leader.html new file mode 100644 index 0000000..382cd17 --- /dev/null +++ b/public/leader.html @@ -0,0 +1,1566 @@ + + + + + + + 客户管理系统 - 组长管理 + + + + +
+ + + + +
+
+

员工管理

+
创建和管理我的员工账号
+
+ + +
+
+
+
+

¥ 0

+

总金额

+
+
+
+
+
+

0

+

员工总数

+
+
+
+
+
+

0

+

客户总数

+
+
+
+
+
+

0

+

即将到期

+
+
+
+
+
+

0

+

已到期

+
+
+
+ +
+
+

员工列表

+
+ +
+
+ +
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + diff --git a/public/staff.html b/public/staff.html new file mode 100644 index 0000000..31e5c3c --- /dev/null +++ b/public/staff.html @@ -0,0 +1,1768 @@ + + + + + + + 客户登记管理系统 - 员工端 + + + + + + +
+
正在验证登录状态...
+
+
+ + + + + + + +
+
+
客户续费
+ +
+
+
+ + +
+
+ + +
+
+ 更新后,该客户的到期时间和金额将被修改 +
+
+ +
+ + +
+
+
+
到期详情
+ +
+
+
+
+ + + + + + + + + + + + +
客户姓名联系电话服务类型登记日期到期时间金额
+
+
+
+
+ + + + + + + + \ No newline at end of file diff --git a/run.log b/run.log new file mode 100644 index 0000000..c897089 --- /dev/null +++ b/run.log @@ -0,0 +1,2 @@ +nohup: ignoring input +🚀 CRM running on http://0.0.0.0:3000 diff --git a/server.js b/server.js new file mode 100644 index 0000000..f2aa8da --- /dev/null +++ b/server.js @@ -0,0 +1,1044 @@ +const path = require('path'); +const express = require('express'); +const cors = require('cors'); +const bcrypt = require('bcryptjs'); +const jwt = require('jsonwebtoken'); +const sqlite3 = require('sqlite3').verbose(); + +const PORT = process.env.PORT || 3000; +const JWT_SECRET = process.env.JWT_SECRET || 'CHANGE_ME_TO_A_RANDOM_SECRET'; +const DB_PATH = process.env.DB_PATH || path.join(__dirname, 'data.sqlite'); + +const app = express(); +app.use(cors()); +app.use(express.json()); + +// ===== DB ===== +const db = new sqlite3.Database(DB_PATH); + +function run(sql, params = []) { + return new Promise((resolve, reject) => { + db.run(sql, params, function (err) { + if (err) return reject(err); + resolve({ lastID: this.lastID, changes: this.changes }); + }); + }); +} + +function get(sql, params = []) { + return new Promise((resolve, reject) => { + db.get(sql, params, (err, row) => { + if (err) return reject(err); + resolve(row); + }); + }); +} + +function all(sql, params = []) { + return new Promise((resolve, reject) => { + db.all(sql, params, (err, rows) => { + if (err) return reject(err); + resolve(rows); + }); + }); +} + +async function initDb() { + await run('PRAGMA foreign_keys = ON;'); + + await run(` + CREATE TABLE IF NOT EXISTS users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + username TEXT UNIQUE NOT NULL, + name TEXT, + password_hash TEXT NOT NULL, + role TEXT NOT NULL CHECK(role IN ('admin','leader','staff')), + phone TEXT, + email TEXT, + status TEXT NOT NULL DEFAULT 'active', + creator_id INTEGER, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + FOREIGN KEY(creator_id) REFERENCES users(id) + ); + `); + + await run(` + CREATE TABLE IF NOT EXISTS clients ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + staff_id INTEGER NOT NULL, + regDate TEXT, -- YYYY-MM-DD + customerName TEXT NOT NULL, + phone TEXT, + expireDate TEXT, -- YYYY-MM-DD + amount REAL NOT NULL DEFAULT 0, + serviceType TEXT, + remark TEXT, + lastRenewAt TEXT, + created_at TEXT NOT NULL DEFAULT (datetime('now')), + updated_at TEXT NOT NULL DEFAULT (datetime('now')), + FOREIGN KEY(staff_id) REFERENCES users(id) + ); + `); + + const admin = await get('SELECT * FROM users WHERE username = ?', ['admin']); + if (!admin) { + const hash = await bcrypt.hash('admin123456', 10); + await run( + 'INSERT INTO users(username, name, password_hash, role, status) VALUES(?,?,?,?,?)', + ['admin', '老板', hash, 'admin', 'active'] + ); + console.log('已创建默认管理员账号:xs / xs123456...'); + } + + const staff = await get('SELECT * FROM users WHERE username = ?', ['staff1']); + if (!staff) { + const hash = await bcrypt.hash('staff123456', 10); + await run( + 'INSERT INTO users(username, name, password_hash, role, status) VALUES(?,?,?,?,?)', + ['staff1', '员工1', hash, 'staff', 'active'] + ); + console.log('已创建默认员工账号:staff1 / staff123456'); + } + + // 创建默认组长账号 + const leader = await get('SELECT * FROM users WHERE username = ?', ['leader1']); + if (!leader) { + const hash = await bcrypt.hash('leader123456', 10); + await run( + 'INSERT INTO users(username, name, password_hash, role, status) VALUES(?,?,?,?,?)', + ['leader1', '组长1', hash, 'leader', 'active'] + ); + console.log('已创建默认组长账号:leader1 / leader123456'); + } +} + +function asyncHandler(fn) { + return (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next); +} + +// ===== Auth middleware ===== +function authRequired(req, res, next) { + const auth = req.headers.authorization || ''; + const token = auth.startsWith('Bearer ') ? auth.slice(7) : ''; + if (!token) return res.status(401).json({ message: '未登录' }); + try { + const payload = jwt.verify(token, JWT_SECRET); + req.user = payload; // {id, username, role, name} + next(); + } catch (e) { + return res.status(401).json({ message: '登录已失效,请重新登录' }); + } +} + +function roleRequired(roles) { + return (req, res, next) => { + if (!req.user) return res.status(401).json({ message: '未登录' }); + if (!roles.includes(req.user.role)) return res.status(403).json({ message: '无权限' }); + next(); + }; +} + +// ===== date helpers ===== +function parseDateValue(value) { + if (!value) return null; + const d = new Date(value); + if (Number.isNaN(d.getTime())) return null; + return d; +} +function isExpired(expireDate) { + const d = parseDateValue(expireDate); + if (!d) return false; + return d.getTime() < Date.now(); +} +function isExpiringSoon(expireDate, days = 7) { + const d = parseDateValue(expireDate); + if (!d) return false; + const diff = d.getTime() - Date.now(); + return diff >= 0 && diff <= days * 24 * 60 * 60 * 1000; +} + +// ===== Common: build client status (for response) ===== +function getClientStatus(expireDate, days = 7) { + if (isExpired(expireDate)) return 'expired'; + if (isExpiringSoon(expireDate, days)) return 'expiring'; + return 'active'; +} + +// ===== API: Auth ===== +app.post('/api/auth/login', asyncHandler(async (req, res) => { + const { username, password } = req.body || {}; + if (!username || !password) return res.status(400).json({ message: '缺少账号或密码' }); + + const user = await get('SELECT * FROM users WHERE username = ?', [username]); + if (!user) return res.status(401).json({ message: '账号或密码错误' }); + + if (user.status === 'inactive') return res.status(403).json({ message: '该账号已被禁用,请联系管理员' }); + + const ok = await bcrypt.compare(password, user.password_hash); + if (!ok) return res.status(401).json({ message: '账号或密码错误' }); + + const token = jwt.sign( + { id: user.id, username: user.username, role: user.role, name: user.name }, + JWT_SECRET, + { expiresIn: '7d' } + ); + + res.json({ + token, + user: { id: user.id, username: user.username, name: user.name, role: user.role } + }); +})); + +app.get('/api/auth/me', authRequired, asyncHandler(async (req, res) => { + const u = await get( + 'SELECT id, username, name, role, phone, email, status FROM users WHERE id=?', + [req.user.id] + ); + res.json({ user: u }); +})); + +// ====================================================================== +// ✅ 新增:Dashboard Summary(总览卡片 + 员工统计) +// - admin:返回全局 stats + staffStats 列表 +// - staff:返回自己的 stats(不返回全部员工) +// ====================================================================== +app.get('/api/dashboard/summary', authRequired, asyncHandler(async (req, res) => { + const days = Number(req.query.days || 7); + + // 取所有客户(admin) or 取自己的客户(staff) + let rows; + if (req.user.role === 'admin') { + rows = await all(`SELECT staff_id, expireDate, amount FROM clients`); + } else { + rows = await all(`SELECT staff_id, expireDate, amount FROM clients WHERE staff_id = ?`, [req.user.id]); + } + + let totalAmount = 0; + let totalClients = rows.length; + let expiringCount = 0; + let expiredCount = 0; + + for (const r of rows) { + totalAmount += Number(r.amount || 0); + if (isExpired(r.expireDate)) expiredCount += 1; + else if (isExpiringSoon(r.expireDate, days)) expiringCount += 1; + } + + const stats = { totalAmount, totalClients, expiringCount, expiredCount }; + + if (req.user.role !== 'admin') { + return res.json({ stats }); + } + + // admin:补员工统计 + const staffRows = await all(` + SELECT u.id, u.username, u.name, u.phone, u.email, u.status, u.created_at, u.creator_id, c.name as creator_name, c.username as creator_username + FROM users u + LEFT JOIN users c ON u.creator_id = c.id + WHERE u.role='staff' + ORDER BY u.id ASC + `); + + const map = new Map(); + staffRows.forEach(s => { + map.set(s.id, { + id: s.id, + username: s.username, + name: s.name, + phone: s.phone, + email: s.email, + status: s.status, + created_at: s.created_at, + creator_id: s.creator_id, + creator_name: s.creator_name || s.creator_username || 'Admin', + clients: 0, + total: 0, + expired: 0, + expiring: 0 + }); + }); + + rows.forEach(c => { + const t = map.get(c.staff_id); + if (!t) return; + t.clients += 1; + t.total += Number(c.amount || 0); + if (isExpired(c.expireDate)) t.expired += 1; + else if (isExpiringSoon(c.expireDate, days)) t.expiring += 1; + }); + + res.json({ stats, staffStats: Array.from(map.values()) }); +})); + +// ====================================================================== +// ✅ 新增:Staff 通用接口(更贴近前端) +// - GET /api/staff admin:员工列表(含聚合) leader:员工列表(不含聚合) staff:返回自己 +// - POST /api/staff admin/leader:新增员工 +// - PUT /api/staff/:id admin/leader:编辑员工 +// - DELETE /api/staff/:id admin/leader:禁用员工 +// ====================================================================== +app.get('/api/staff', authRequired, asyncHandler(async (req, res) => { + // staff 只能看自己 + if (req.user.role === 'staff') { + const me = await get(` + SELECT id, username, name, phone, email, status, created_at + FROM users + WHERE id=? AND status != 'inactive' + `, [req.user.id]); + + if (!me) { + return res.json({ staff: [] }); + } + + return res.json({ staff: [me] }); + } + + // admin 和 leader 都可以查看员工列表 + // admin 可以看到所有 staff 和 leader,leader 只能看自己创建的 staff + const includeInactive = req.query.includeInactive === 'true'; + const statusFilter = includeInactive ? '' : "AND u.status != 'inactive'"; + + let staffRows; + if (req.user.role === 'admin') { + staffRows = await all(` + SELECT u.id, u.username, u.name, u.phone, u.email, u.status, u.role, u.creator_id, u.created_at + FROM users u + WHERE u.role IN ('staff', 'leader') ${statusFilter} + ORDER BY u.status ASC, u.id ASC + `); + } else { + // leader 只能看自己创建的 staff + staffRows = await all(` + SELECT u.id, u.username, u.name, u.phone, u.email, u.status, u.role, u.creator_id, u.created_at + FROM users u + WHERE u.role = 'staff' AND u.creator_id = ? ${statusFilter} + ORDER BY u.status ASC, u.id ASC + `, [req.user.id]); + } + + // leader 也返回员工的客户统计数据 + if (req.user.role === 'leader') { + const staffIds = staffRows.map(s => s.id); + if (staffIds.length === 0) { + return res.json({ staff: [] }); + } + const clientRows = await all(`SELECT staff_id, expireDate, amount FROM clients WHERE staff_id IN (${staffIds.join(',')})`); + const byStaff = new Map(); + staffRows.forEach((s) => { + byStaff.set(s.id, { + ...s, + clientsCount: 0, + totalAmount: 0, + expiredCount: 0, + expiringCount: 0 + }); + }); + const now = new Date(); + const expireThreshold = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); + clientRows.forEach((c) => { + const staff = byStaff.get(c.staff_id); + if (!staff) return; + staff.clientsCount++; + staff.totalAmount += c.amount || 0; + if (c.expireDate) { + const exp = new Date(c.expireDate); + if (exp < now) staff.expiredCount++; + else if (exp <= expireThreshold) staff.expiringCount++; + } + }); + return res.json({ staff: Array.from(byStaff.values()) }); + } + + // admin 返回完整统计数据 + const clientRows = await all('SELECT staff_id, expireDate, amount FROM clients'); + const byStaff = new Map(); + staffRows.forEach((s) => { + byStaff.set(s.id, { + ...s, + clientsCount: 0, + totalAmount: 0, + expiredCount: 0, + expiringCount: 0 + }); + }); + + clientRows.forEach((c) => { + const target = byStaff.get(c.staff_id); + if (!target) return; + target.clientsCount += 1; + target.totalAmount += Number(c.amount || 0); + if (isExpired(c.expireDate)) target.expiredCount += 1; + if (isExpiringSoon(c.expireDate)) target.expiringCount += 1; + }); + + res.json({ staff: Array.from(byStaff.values()) }); +})); + + +app.post('/api/staff', authRequired, roleRequired(['admin', 'leader']), asyncHandler(async (req, res) => { + const b = req.body || {}; + if (!b.username || !b.password || !b.name) { + return res.status(400).json({ message: '用户名、姓名和密码不能为空' }); + } + const existing = await get('SELECT id FROM users WHERE username = ?', [b.username]); + if (existing) return res.status(400).json({ message: '用户名已存在' }); + + // 只有 admin 可以创建 leader,leader 只能创建 staff + let role = 'staff'; + if (b.role === 'leader' && req.user.role === 'admin') { + role = 'leader'; + } + + // 记录创建者 ID + const creatorId = req.user.id; + + const hash = await bcrypt.hash(b.password, 10); + const r = await run( + 'INSERT INTO users(username, name, password_hash, role, phone, email, status, creator_id) VALUES(?,?,?,?,?,?,?,?)', + [b.username, b.name, hash, role, b.phone || null, b.email || null, b.status || 'active', creatorId] + ); + const row = await get('SELECT id, username, name, phone, email, status, role, creator_id, created_at FROM users WHERE id=?', [r.lastID]); + res.json({ staff: row }); +})); + +app.put('/api/staff/:id', authRequired, roleRequired(['admin', 'leader']), asyncHandler(async (req, res) => { + const id = Number(req.params.id); + if (!id) return res.status(400).json({ message: '参数错误' }); + + const existing = await get('SELECT * FROM users WHERE id=?', [id]); + if (!existing) return res.status(404).json({ message: '用户不存在' }); + + // 权限检查 + if (existing.role === 'admin') return res.status(403).json({ message: '不能操作管理员账号' }); + if (existing.role === 'leader' && req.user.role !== 'admin') return res.status(403).json({ message: '无权操作组长' }); + // 组长只能操作自己创建的员工 + if (req.user.role === 'leader' && existing.creator_id !== req.user.id) { + return res.status(403).json({ message: '无权操作此员工' }); + } + + const b = req.body || {}; + const updates = []; + const params = []; + const fields = ['name', 'phone', 'email', 'username']; // 允许修改用户名 + + for (const f of fields) { + if (Object.prototype.hasOwnProperty.call(b, f)) { + // 如果修改用户名,检查唯一性 + if (f === 'username' && b.username !== existing.username) { + const uCheck = await get('SELECT id FROM users WHERE username = ?', [b.username]); + if (uCheck) return res.status(400).json({ message: '用户名已存在' }); + } + updates.push(`${f} = ?`); + params.push(b[f]); + } + } + + // 只有 admin 可以修改角色 + if (req.user.role === 'admin' && b.role && ['leader', 'staff'].includes(b.role)) { + updates.push('role = ?'); + params.push(b.role); + } + + // 只有 admin 可以修改所属组长 (creator_id) + // 传入 id 为 leader id,如果为 'admin' 或空则设为当前 admin id + if (req.user.role === 'admin' && Object.prototype.hasOwnProperty.call(b, 'creator_id')) { + let newCreatorId = Number(b.creator_id); + if (!newCreatorId) newCreatorId = req.user.id; // 默认为当前操作者(admin) + + // 验证一下是否存在且是 leader/admin + if (newCreatorId !== req.user.id) { + const leaderCheck = await get('SELECT id, role FROM users WHERE id=?', [newCreatorId]); + if (!leaderCheck) return res.status(400).json({ message: '指定的组长不存在' }); + } + + updates.push('creator_id = ?'); + params.push(newCreatorId); + } + + if (b.password) { + const hash = await bcrypt.hash(b.password, 10); + updates.push('password_hash = ?'); + params.push(hash); + } + + if (updates.length > 0) { + params.push(id); + await run(`UPDATE users SET ${updates.join(', ')} WHERE id = ?`, params); + } + + const row = await get('SELECT id, username, name, phone, email, status, role, creator_id, created_at FROM users WHERE id=?', [id]); + res.json({ staff: row }); +})); + +app.post('/api/staff/:id/reset_password', authRequired, roleRequired(['admin', 'leader']), asyncHandler(async (req, res) => { + const id = Number(req.params.id); + if (!id) return res.status(400).json({ message: '参数错误' }); + + const b = req.body || {}; + if (!b.password) return res.status(400).json({ message: '新密码不能为空' }); + + const existing = await get('SELECT id, role, creator_id FROM users WHERE id=?', [id]); + if (!existing) return res.status(404).json({ message: '用户不存在' }); + if (existing.role === 'admin') return res.status(403).json({ message: '不能操作管理员账号' }); + if (existing.role === 'leader' && req.user.role !== 'admin') return res.status(403).json({ message: '无权操作组长' }); + // 组长只能操作自己创建的员工 + if (req.user.role === 'leader' && existing.creator_id !== req.user.id) { + return res.status(403).json({ message: '无权操作此员工' }); + } + + const hash = await bcrypt.hash(b.password, 10); + await run('UPDATE users SET password_hash = ? WHERE id = ?', [hash, id]); + res.json({ success: true }); +})); + +app.delete('/api/staff/:id', authRequired, roleRequired(['admin', 'leader']), asyncHandler(async (req, res) => { + const id = Number(req.params.id); + if (!id) return res.status(400).json({ message: '参数错误' }); + + const existing = await get('SELECT * FROM users WHERE id=?', [id]); + if (!existing) return res.status(404).json({ message: '用户不存在' }); + if (existing.role === 'admin') return res.status(403).json({ message: '不能操作管理员账号' }); + if (existing.role === 'leader' && req.user.role !== 'admin') return res.status(403).json({ message: '无权操作组长' }); + // 组长只能操作自己创建的员工 + if (req.user.role === 'leader' && existing.creator_id !== req.user.id) { + return res.status(403).json({ message: '无权操作此员工' }); + } + + await run('UPDATE users SET status = \'inactive\' WHERE id = ?', [id]); + res.json({ success: true }); +})); + +// 启用/禁用用户状态切换 +app.post('/api/staff/:id/toggle_status', authRequired, roleRequired(['admin', 'leader']), asyncHandler(async (req, res) => { + const id = Number(req.params.id); + if (!id) return res.status(400).json({ message: '参数错误' }); + + const existing = await get('SELECT * FROM users WHERE id=?', [id]); + if (!existing) return res.status(404).json({ message: '用户不存在' }); + if (existing.role === 'admin') return res.status(403).json({ message: '不能操作管理员账号' }); + if (existing.role === 'leader' && req.user.role !== 'admin') return res.status(403).json({ message: '无权操作组长' }); + // 组长只能操作自己创建的员工 + if (req.user.role === 'leader' && existing.creator_id !== req.user.id) { + return res.status(403).json({ message: '无权操作此员工' }); + } + + const newStatus = existing.status === 'active' ? 'inactive' : 'active'; + await run('UPDATE users SET status = ? WHERE id = ?', [newStatus, id]); + res.json({ success: true, status: newStatus }); +})); + +// ====================================================================== +// ✅ 改造:Clients 列表支持筛选/搜索/分页(你前端筛选栏 & 客户页需要) +// GET /api/clients +// query: +// staffId / staffName(可选) / status(active|expiring|expired) / serviceType / q +// dateFrom / dateTo (按 regDate) / page / pageSize / days(默认7,expiring阈值) +// ====================================================================== +app.get('/api/clients', authRequired, asyncHandler(async (req, res) => { + const { + staffId, + status = 'all', + serviceType = 'all', + q = '', + dateFrom, + dateTo, + page = 1, + pageSize = 20, + days = 7 + } = req.query; + + const p = Math.max(1, Number(page || 1)); + const ps = Math.min(200, Math.max(1, Number(pageSize || 20))); + const expDays = Number(days || 7); + + const where = []; + const params = []; + + // 权限限制 + if (req.user.role === 'staff') { + // 员工只能看自己的客户 + where.push('c.staff_id = ?'); + params.push(req.user.id); + } else if (req.user.role === 'leader') { + // 组长只能看自己创建的员工的客户 + if (staffId && staffId !== 'all') { + // 验证该员工是否属于此组长 + const staffUser = await get('SELECT id, creator_id FROM users WHERE id = ?', [Number(staffId)]); + if (!staffUser || staffUser.creator_id !== req.user.id) { + return res.status(403).json({ message: '无权查看此员工客户' }); + } + where.push('c.staff_id = ?'); + params.push(Number(staffId)); + } else { + // 获取此组长创建的所有员工 ID + const ownStaff = await all('SELECT id FROM users WHERE creator_id = ? AND role = ?', [req.user.id, 'staff']); + const staffIds = ownStaff.map(s => s.id); + if (staffIds.length === 0) { + return res.json({ clients: [], pagination: { page: 1, pageSize: ps, total: 0, totalPages: 0 } }); + } + where.push(`c.staff_id IN (${staffIds.join(',')})`); + } + } else if (staffId && staffId !== 'all') { + // admin 可以看任何员工 + where.push('c.staff_id = ?'); + params.push(Number(staffId)); + } + + if (serviceType && serviceType !== 'all') { + where.push('c.serviceType = ?'); + params.push(serviceType); + } + + if (q && String(q).trim()) { + const like = `%${String(q).trim()}%`; + where.push('(c.customerName LIKE ? OR c.phone LIKE ? OR c.remark LIKE ?)'); + params.push(like, like, like); + } + + // regDate 范围筛选 + if (dateFrom) { + where.push('date(c.regDate) >= date(?)'); + params.push(dateFrom); + } + if (dateTo) { + where.push('date(c.regDate) <= date(?)'); + params.push(dateTo); + } + + // 状态筛选(expireDate) + // 注意:expireDate 允许为空,空则默认当 active + if (status === 'expired') { + where.push("c.expireDate IS NOT NULL AND date(c.expireDate) < date('now')"); + } else if (status === 'expiring') { + where.push(`c.expireDate IS NOT NULL AND date(c.expireDate) >= date('now') AND date(c.expireDate) <= date('now', ?)`); + params.push(`+${expDays} day`); + } else if (status === 'active') { + // active: expireDate 为空 或 expireDate > now+days 或 expireDate 在未来但>days + // 简化:not expired and not expiring + where.push(`( + c.expireDate IS NULL + OR date(c.expireDate) > date('now', ?) + )`); + params.push(`+${expDays} day`); + } + + const whereSql = where.length ? `WHERE ${where.join(' AND ')}` : ''; + + // 总数 + const totalRow = await get(`SELECT COUNT(1) AS cnt FROM clients c ${whereSql}`, params); + const total = totalRow ? totalRow.cnt : 0; + + // 分页数据 + const offset = (p - 1) * ps; + const list = await all( + ` + SELECT c.*, u.name AS staff_name, u.username AS staff_username + FROM clients c + LEFT JOIN users u ON u.id = c.staff_id + ${whereSql} + ORDER BY c.id DESC + LIMIT ? OFFSET ? + `, + [...params, ps, offset] + ); + + // 补一个计算出来的 status 字段,前端更好用 + const clients = list.map(row => ({ + ...row, + status: getClientStatus(row.expireDate, expDays) + })); + + res.json({ + page: p, + pageSize: ps, + total, + clients + }); +})); + +// ====================================================================== +// Staff clients endpoints (for staff page) +// ====================================================================== +app.get('/api/staff/clients', authRequired, roleRequired(['staff', 'admin']), asyncHandler(async (req, res) => { + const days = Number(req.query.days || 7); + const rows = await all( + `SELECT c.* + FROM clients c + WHERE c.staff_id = ? + ORDER BY c.id DESC`, + [req.user.id] + ); + const clients = rows.map(row => ({ ...row, status: getClientStatus(row.expireDate, days) })); + res.json({ clients }); +})); + +app.post('/api/staff/clients', authRequired, roleRequired(['staff', 'admin']), asyncHandler(async (req, res) => { + const b = req.body || {}; + if (!b.customerName) return res.status(400).json({ message: '客户姓名不能为空' }); + + const amount = Number(b.amount || 0); + const now = new Date().toISOString(); + + const r = await run(` + INSERT INTO clients(staff_id, regDate, customerName, phone, expireDate, amount, serviceType, remark, lastRenewAt, created_at, updated_at) + VALUES(?,?,?,?,?,?,?,?,?,?,?) + `, [ + req.user.id, + b.regDate || null, + b.customerName, + b.phone || null, + b.expireDate || null, + amount, + b.serviceType || null, + b.remark || '', + b.lastRenewAt || null, + now, + now + ]); + + const row = await get('SELECT * FROM clients WHERE id=?', [r.lastID]); + res.json({ client: { ...row, status: getClientStatus(row.expireDate) } }); +})); + +app.put('/api/staff/clients/:id', authRequired, roleRequired(['staff', 'admin']), asyncHandler(async (req, res) => { + const id = Number(req.params.id); + if (!id) return res.status(400).json({ message: '参数错误' }); + + const existing = await get('SELECT * FROM clients WHERE id=?', [id]); + if (!existing) return res.status(404).json({ message: '客户不存在' }); + + if (req.user.role !== 'admin' && existing.staff_id !== req.user.id) { + return res.status(403).json({ message: '无权限修改该客户' }); + } + + const b = req.body || {}; + const fields = ['regDate', 'customerName', 'phone', 'expireDate', 'amount', 'serviceType', 'remark', 'lastRenewAt']; + const updates = []; + const params = []; + + for (const f of fields) { + if (!Object.prototype.hasOwnProperty.call(b, f)) continue; + updates.push(`${f} = ?`); + if (f === 'amount') params.push(Number(b[f] || 0)); + else params.push(b[f]); + } + + if (updates.length === 0) { + const row = await get('SELECT * FROM clients WHERE id=?', [id]); + return res.json({ client: { ...row, status: getClientStatus(row.expireDate) } }); + } + + updates.push('updated_at = ?'); + params.push(new Date().toISOString()); + params.push(id); + + await run(`UPDATE clients SET ${updates.join(', ')} WHERE id = ?`, params); + + const row = await get('SELECT * FROM clients WHERE id=?', [id]); + res.json({ client: { ...row, status: getClientStatus(row.expireDate) } }); +})); + +// New client +app.post('/api/clients', authRequired, roleRequired(['staff', 'admin']), asyncHandler(async (req, res) => { + const b = req.body || {}; + const staffId = (req.user.role === 'admin' && b.staff_id) ? Number(b.staff_id) : req.user.id; + + if (!b.customerName) return res.status(400).json({ message: '客户姓名不能为空' }); + + const amount = Number(b.amount || 0); + const now = new Date().toISOString(); + + const r = await run(` + INSERT INTO clients(staff_id, regDate, customerName, phone, expireDate, amount, serviceType, remark, lastRenewAt, created_at, updated_at) + VALUES(?,?,?,?,?,?,?,?,?,?,?) + `, [ + staffId, + b.regDate || null, + b.customerName, + b.phone || null, + b.expireDate || null, + amount, + b.serviceType || null, + b.remark || '', + b.lastRenewAt || null, + now, + now + ]); + + const row = await get('SELECT * FROM clients WHERE id=?', [r.lastID]); + res.json({ client: { ...row, status: getClientStatus(row.expireDate) } }); +})); + +// 更新客户 +app.put('/api/clients/:id', authRequired, asyncHandler(async (req, res) => { + const id = Number(req.params.id); + if (!id) return res.status(400).json({ message: '参数错误' }); + + const existing = await get('SELECT * FROM clients WHERE id=?', [id]); + if (!existing) return res.status(404).json({ message: '客户不存在' }); + + if (req.user.role !== 'admin' && existing.staff_id !== req.user.id) { + return res.status(403).json({ message: '无权限修改该客户' }); + } + + const b = req.body || {}; + const fields = ['regDate', 'customerName', 'phone', 'expireDate', 'amount', 'serviceType', 'remark', 'lastRenewAt', 'staff_id']; + const updates = []; + const params = []; + + for (const f of fields) { + if (!Object.prototype.hasOwnProperty.call(b, f)) continue; + + // staff_id 只有 admin 能改 + if (f === 'staff_id' && req.user.role !== 'admin') continue; + + updates.push(`${f} = ?`); + if (f === 'amount') params.push(Number(b[f] || 0)); + else if (f === 'staff_id') params.push(Number(b[f])); + else params.push(b[f]); + } + + if (updates.length === 0) return res.json({ client: { ...existing, status: getClientStatus(existing.expireDate) } }); + + updates.push('updated_at = ?'); + params.push(new Date().toISOString()); + params.push(id); + + await run(`UPDATE clients SET ${updates.join(', ')} WHERE id = ?`, params); + + const row = await get('SELECT * FROM clients WHERE id=?', [id]); + res.json({ client: { ...row, status: getClientStatus(row.expireDate) } }); +})); + +// ✅ 新增:删除客户(单个) +app.delete('/api/clients/:id', authRequired, asyncHandler(async (req, res) => { + const id = Number(req.params.id); + if (!id) return res.status(400).json({ message: '参数错误' }); + + const existing = await get('SELECT * FROM clients WHERE id=?', [id]); + if (!existing) return res.status(404).json({ message: '客户不存在' }); + + if (req.user.role !== 'admin' && existing.staff_id !== req.user.id) { + return res.status(403).json({ message: '无权限删除该客户' }); + } + + await run('DELETE FROM clients WHERE id=?', [id]); + res.json({ success: true }); +})); + +// ====================================================================== +// ✅ 新增:到期提醒列表(你左侧“到期提醒”页会用到) +// GET /api/reminders?type=expiring|expired&days=7&staffId=xxx +// ====================================================================== +app.get('/api/reminders', authRequired, asyncHandler(async (req, res) => { + const type = req.query.type || 'expiring'; + const days = Number(req.query.days || 7); + const staffId = req.query.staffId; + + const where = []; + const params = []; + + if (req.user.role !== 'admin') { + where.push('c.staff_id = ?'); + params.push(req.user.id); + } else if (staffId && staffId !== 'all') { + where.push('c.staff_id = ?'); + params.push(Number(staffId)); + } + + if (type === 'expired') { + where.push("c.expireDate IS NOT NULL AND date(c.expireDate) < date('now')"); + } else { + where.push(`c.expireDate IS NOT NULL AND date(c.expireDate) >= date('now') AND date(c.expireDate) <= date('now', ?)`); + params.push(`+${days} day`); + } + + const whereSql = where.length ? `WHERE ${where.join(' AND ')}` : ''; + const rows = await all(` + SELECT c.*, u.name AS staff_name, u.username AS staff_username + FROM clients c + LEFT JOIN users u ON u.id = c.staff_id + ${whereSql} + ORDER BY date(c.expireDate) ASC, c.id DESC + `, params); + + res.json({ + type, + days, + clients: rows.map(r => ({ ...r, status: getClientStatus(r.expireDate, days) })) + }); +})); + +// ====================================================================== +// ✅ 新增:导出客户 CSV(简单实用,Excel 也能打开) +// GET /api/export/clients?...(同 /api/clients 的筛选参数) +// ====================================================================== +app.get('/api/export/clients', authRequired, asyncHandler(async (req, res) => { + // 复用 /api/clients 的筛选逻辑,但这里直接查全部,不分页 + const { + staffId, + status = 'all', + serviceType = 'all', + q = '', + dateFrom, + dateTo, + days = 7 + } = req.query; + + const expDays = Number(days || 7); + + const where = []; + const params = []; + + if (req.user.role !== 'admin') { + where.push('c.staff_id = ?'); + params.push(req.user.id); + } else if (staffId && staffId !== 'all') { + where.push('c.staff_id = ?'); + params.push(Number(staffId)); + } + + if (serviceType && serviceType !== 'all') { + where.push('c.serviceType = ?'); + params.push(serviceType); + } + + if (q && String(q).trim()) { + const like = `%${String(q).trim()}%`; + where.push('(c.customerName LIKE ? OR c.phone LIKE ? OR c.remark LIKE ?)'); + params.push(like, like, like); + } + + if (dateFrom) { + where.push('date(c.regDate) >= date(?)'); + params.push(dateFrom); + } + if (dateTo) { + where.push('date(c.regDate) <= date(?)'); + params.push(dateTo); + } + + if (status === 'expired') { + where.push("c.expireDate IS NOT NULL AND date(c.expireDate) < date('now')"); + } else if (status === 'expiring') { + where.push(`c.expireDate IS NOT NULL AND date(c.expireDate) >= date('now') AND date(c.expireDate) <= date('now', ?)`); + params.push(`+${expDays} day`); + } else if (status === 'active') { + where.push(`( + c.expireDate IS NULL + OR date(c.expireDate) > date('now', ?) + )`); + params.push(`+${expDays} day`); + } + + const whereSql = where.length ? `WHERE ${where.join(' AND ')}` : ''; + + const rows = await all(` + SELECT c.*, u.name AS staff_name, u.username AS staff_username + FROM clients c + LEFT JOIN users u ON u.id = c.staff_id + ${whereSql} + ORDER BY c.id DESC + `, params); + + // CSV + const headers = [ + 'id', 'staff_name', 'staff_username', 'customerName', 'phone', 'serviceType', 'regDate', 'expireDate', 'amount', 'status', 'remark' + ]; + const escapeCsv = (v) => { + if (v === null || v === undefined) return ''; + const s = String(v); + if (/[",\n]/.test(s)) return `"${s.replace(/"/g, '""')}"`; + return s; + }; + + const lines = []; + lines.push(headers.join(',')); + for (const r of rows) { + const statusText = getClientStatus(r.expireDate, expDays); + const line = [ + r.id, + r.staff_name || '', + r.staff_username || '', + r.customerName || '', + r.phone || '', + r.serviceType || '', + r.regDate || '', + r.expireDate || '', + r.amount ?? 0, + statusText, + r.remark || '' + ].map(escapeCsv).join(','); + lines.push(line); + } + + const csv = '\ufeff' + lines.join('\n'); // 带 BOM,Excel 打开中文不乱码 + res.setHeader('Content-Type', 'text/csv; charset=utf-8'); + res.setHeader('Content-Disposition', `attachment; filename="clients_${Date.now()}.csv"`); + res.send(csv); +})); + +// ====================================================================== +// 兼容保留:你原来的 admin 接口(不想改前端也能用) +// ====================================================================== +app.get('/api/admin/staff', authRequired, roleRequired(['admin']), asyncHandler(async (req, res) => { + // 直接代理到 /api/staff + req.user.role = 'admin'; + return app._router.handle(req, res, () => { }, 'get', '/api/staff'); +})); + +app.post('/api/admin/staff', authRequired, roleRequired(['admin']), asyncHandler(async (req, res) => { + return app._router.handle(req, res, () => { }, 'post', '/api/staff'); +})); + +app.put('/api/admin/staff/:id', authRequired, roleRequired(['admin']), asyncHandler(async (req, res) => { + return app._router.handle(req, res, () => { }, 'put', `/api/staff/${req.params.id}`); +})); + +app.delete('/api/admin/staff/:id', authRequired, roleRequired(['admin']), asyncHandler(async (req, res) => { + return app._router.handle(req, res, () => { }, 'delete', `/api/staff/${req.params.id}`); +})); + +app.get('/api/admin/stats', authRequired, roleRequired(['admin']), asyncHandler(async (req, res) => { + // 兼容:用新 summary 的 stats + const fakeReq = { ...req, query: { ...req.query } }; + // 直接再算一次(避免 hack router) + const rows = await all('SELECT expireDate, amount FROM clients'); + let totalAmount = 0; + let totalClients = rows.length; + let activeClients = 0; + let expiringSoonClients = 0; + for (const r of rows) { + totalAmount += Number(r.amount || 0); + if (!isExpired(r.expireDate)) activeClients += 1; + if (isExpiringSoon(r.expireDate)) expiringSoonClients += 1; + } + res.json({ stats: { totalAmount, totalClients, activeClients, expiringSoonClients } }); +})); + +// ===== 静态前端文件 ===== +const publicDir = path.join(__dirname, 'public'); +app.use(express.static(publicDir)); +app.get('/', (req, res) => res.redirect('/index.html')); + +// ===== error handler ===== +app.use((err, req, res, next) => { + console.error(err); + res.status(500).json({ message: '服务器错误' }); +}); + +async function main() { + if (process.argv.includes('--initdb')) { + await initDb(); + process.exit(0); + } + await initDb(); + app.listen(PORT, () => { + console.log(`CRM running on http://0.0.0.0:${PORT}`); + }); +} + +main().catch(err => { + console.error(err); + process.exit(1); +});